// Everything that talks to OUR OWN backend: party REST endpoints, and the // realtime WebSocket. Same origin as this page, so no CORS concerns here - // contrast with embyApi.js. import { session } from './embyApi.js'; async function apiFetch(path, options = {}) { const res = await fetch(path, { ...options, headers: { 'Content-Type': 'application/json', 'X-Emby-Token': session.token, 'X-Emby-UserId': session.userId, ...(options.headers || {}) } }); if (!res.ok) { const body = await res.json().catch(() => ({})); throw new Error(body.error || `Request failed: ${res.status}`); } return res.json(); } export function createParty(itemId) { return apiFetch('/api/parties', { method: 'POST', body: JSON.stringify({ itemId }) }); } export function joinParty(joinCode) { return apiFetch(`/api/parties/${encodeURIComponent(joinCode)}/join`, { method: 'POST' }); } export function leaveParty(partyId) { return apiFetch(`/api/parties/${partyId}/leave`, { method: 'POST' }); } export function getParty(partyId) { return apiFetch(`/api/parties/${partyId}`); } /** * Opens the realtime connection for a party. The Emby token is sent as the * FIRST WebSocket message, not a query string - tokens don't belong in URLs * (they'd end up in server logs, browser history, etc.). */ export function connectParty(partyId, { onMembers, onPlaystate, onError, onClose } = {}) { const proto = location.protocol === 'https:' ? 'wss://' : 'ws://'; const ws = new WebSocket(proto + location.host + '/ws'); ws.addEventListener('open', () => { ws.send(JSON.stringify({ type: 'auth', token: session.token, userId: session.userId, partyId })); }); ws.addEventListener('message', (evt) => { let msg; try { msg = JSON.parse(evt.data); } catch (err) { return; } if (msg.type === 'members' && onMembers) onMembers(msg.members); if (msg.type === 'playstate' && onPlaystate) onPlaystate(msg); if (msg.type === 'error' && onError) onError(msg.message); }); ws.addEventListener('close', () => { if (onClose) onClose(); }); return { sendPlaystate(isPaused, positionTicks) { if (ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: 'playstate', isPaused, positionTicks })); } }, leave() { if (ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: 'leave' })); } ws.close(); } }; }