Something went wrong. Try again.
Fetches and returns current activity on Xbox Live, Steam, and Jellyfin.
Something went wrong. Try again.
4.8 kB · 151 lines · Created 3mo ago
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151// Expects STEAM_API_KEY, STEAM_ID, XBL_TOKEN, JELLYFIN_URL, JELLYFIN_API_KEY, and JELLYFIN_USER_ID.// Uses the OpenXBL API, official Steam API, and the Jellyfin API.
export default { async fetch(request, env) { if (request.method === "OPTIONS") { return new Response(null, { headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, OPTIONS", "Access-Control-Allow-Headers": "Content-Type", "Access-Control-Max-Age": "86400", }, }); }
const safeFetchJson = async (url, options = {}) => { try { const res = await fetch(url, options); if (!res.ok) { console.error(`API Error (${url}): ${res.status} ${res.statusText}`); return null; } return await res.json(); } catch (error) { console.error(`Fetch Error (${url}):`, error.message); return null; } };
try { const steamUrl = `https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/?key=${env.STEAM_API_KEY}&steamids=${env.STEAM_ID}`; const xblUrl = "https://api.xbl.io/v2/presence"; const jellyfinBase = env.JELLYFIN_URL?.replace(/\/$/, ""); const jellyfinUrl = `${jellyfinBase}/Sessions?controllableByUserId=${env.JELLYFIN_USER_ID}`;
const [xboxData, steamData, jellyfinData] = await Promise.all([ safeFetchJson(xblUrl, { headers: { "X-Authorization": env.XBL_TOKEN } }), safeFetchJson(steamUrl), safeFetchJson(jellyfinUrl, { headers: { "X-MediaBrowser-Token": env.JELLYFIN_API_KEY } }), ]);
// Parse Xbox let xboxOnline = false, xboxState = "Offline"; let xboxActiveTitle = null; let xboxLastSeen = null;
if (xboxData?.content) { xboxState = xboxData.content.state; xboxOnline = xboxState === "Online";
const activeDevice = (xboxData.content.devices || []).find((d) => (d.titles || []).some((t) => t.placement === "Full" && t.name !== "Home"));
if (activeDevice) { const activeTitle = activeDevice.titles.find((t) => t.placement === "Full" && t.name !== "Home"); xboxActiveTitle = { name: activeTitle.name, deviceType: activeDevice.type, state: activeTitle.state || null, // Shows if you are actively playing (e.g., "Active") lastModified: activeTitle.lastModified || null, richPresence: activeTitle.activity?.richPresence || null, }; }
if (xboxData.content.lastSeen) { xboxLastSeen = { titleName: xboxData.content.lastSeen.titleName || null, deviceType: xboxData.content.lastSeen.deviceType || null, timestamp: xboxData.content.lastSeen.timestamp || null, }; } }
// Parse Steam let steamOnline = false, steamSlug = "offline", steamGame = null;
if (steamData?.response?.players?.[0]) { const player = steamData.response.players[0]; const personaState = player.personastate; const steamSlugs = ["offline", "online", "busy", "away", "snooze", "looking_trade", "looking_play"];
steamSlug = steamSlugs[personaState] || "unknown"; steamOnline = [1, 5, 6].includes(personaState); steamGame = player.gameextrainfo || null; }
// Parse Jellyfin let jellyfinActive = false, jellyfinMedia = null;
if (Array.isArray(jellyfinData)) { const activeSession = jellyfinData.find((session) => { const type = session.NowPlayingItem?.Type?.toLowerCase(); return type === "episode" || type === "movie"; });
if (activeSession) { jellyfinActive = true; const item = activeSession.NowPlayingItem; const isEpisode = item.Type.toLowerCase() === "episode";
jellyfinMedia = isEpisode ? { type: "tv", show: item.SeriesName || null, season: item.ParentIndexNumber ?? null, episode: item.IndexNumber ?? null, episodeName: item.Name || null, } : { type: "movie", title: item.Name || null, year: item.ProductionYear || null, }; } }
const presenceData = { xbox: { online: xboxOnline, state: xboxState, activeTitle: xboxActiveTitle, lastSeen: xboxLastSeen, }, steam: { online: steamOnline, slug: steamSlug, game: steamGame }, jellyfin: { active: jellyfinActive, media: jellyfinMedia }, updatedAt: new Date().toISOString(), };
return new Response(JSON.stringify(presenceData), { headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", "Cache-Control": "no-store", }, }); } catch (error) { console.error("Catastrophic Worker Error:", error.stack); return new Response(JSON.stringify({ error: "Failed to assemble presence data" }), { status: 500, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", }, }); } },};
I deploy this as a Cloudflare Worker. I explain my use of the script here: https://vale.rocks/posts/the-implementation-of-this-site#current-media-display
Example API response: