const TEN_MINUTES_MS = 10 * 60 * 1000; /** * Build the data object expected by the stub module. * * @param {object} metadata Raw MPRIS Metadata dict * @param {string} playbackStatus "Playing" | "Paused" | "Stopped" * @param {number} positionUs Current position in microseconds * @param {string} playedTime ISO timestamp of when the track was first seen * @returns {object|null} Formatted data, or null if metadata is missing */ export function formatTrackData(metadata, playbackStatus, positionUs, playedTime) { const title = metaString(metadata, "xesam:title"); if (!title) return null; const artistList = metaStringArray(metadata, "xesam:artist"); const album = metaString(metadata, "xesam:album") ?? ""; const artUrl = metaString(metadata, "mpris:artUrl") ?? ""; const lengthUs = metaInt(metadata, "mpris:length") ?? 0; const now = Date.now(); const positionMs = Math.floor(positionUs / 1000); const lengthMs = Math.floor(lengthUs / 1000); let expiry; if (playbackStatus === "Paused") { expiry = new Date(now + TEN_MINUTES_MS).toISOString(); } else { const remainingMs = Math.max(0, lengthMs - positionMs); expiry = new Date(now + remainingMs).toISOString(); } return { artists: artistList.map((name) => ({ artistName: name })), trackName: title, playbackStatus, playedTime, releaseName: album, artUrl, duration: Math.round(lengthMs / 1000), expiry, }; } // --- helpers for reading dbus-next Variant values ---- function metaString(metadata, key) { const v = metadata[key]; if (!v) return undefined; return typeof v.value === "string" ? v.value : String(v.value); } function metaStringArray(metadata, key) { const v = metadata[key]; if (!v) return []; const arr = v.value; return Array.isArray(arr) ? arr.map(String) : [String(arr)]; } function metaInt(metadata, key) { const v = metadata[key]; if (!v) return undefined; const n = Number(v.value); return Number.isFinite(n) ? n : undefined; }