import { getLibraries, getRecentItems } from '../embyApi.js';
import { connectLobby, joinParty, createParty } from '../party.js';
import { navigate } from '../router.js';
import { tileHtml, wireTileButtons, escapeHtml } from '../tiles.js';
export function renderHome(root) {
root.innerHTML = `
Accueil
Watch parties en cours
`;
// Live, not a one-shot fetch: the list (and each card's host/member count)
// updates the moment anything changes anywhere - see
// server/src/socketHandler.js's "lobby" room. The elapsed-time label is
// the one piece that ticks purely client-side (from createdUtc) - no
// point re-pushing from the server once a second just for a clock.
const lobby = connectLobby((parties) => renderParties(root, parties));
const elapsedTimer = setInterval(() => updateElapsedLabels(root), 1000);
loadRecentSections(root);
// Called by router.js before rendering whatever comes next - stops the
// lobby socket and the ticking clock from running after you've navigated
// away (see docs/architecture.md's memory-leak writeup).
return function cleanup() {
lobby.disconnect();
clearInterval(elapsedTimer);
};
}
function renderParties(root, parties) {
const section = root.querySelector('#partiesSection');
const list = root.querySelector('#partiesCarousel');
if (!section || !list) return; // navigated away mid-flight
if (!parties.length) {
section.hidden = true;
list.innerHTML = '';
return;
}
section.hidden = false;
list.innerHTML = parties.map((p) => `
`).join('');
list.querySelectorAll('.joinPartyBtn').forEach((btn) => {
btn.addEventListener('click', async () => {
btn.disabled = true;
try {
// Actually register as a member before navigating - the player's
// realtime "join" is rejected server-side otherwise (you'd load the
// video but never get added to the members list or sync).
await joinParty(btn.dataset.partyId);
navigate(`/party/${btn.dataset.partyId}`);
} catch (err) {
alert(err.message);
btn.disabled = false;
}
});
});
updateElapsedLabels(root);
}
function updateElapsedLabels(root) {
const now = Date.now();
root.querySelectorAll('.elapsed').forEach((el) => {
const created = Number(el.dataset.created);
if (!created) return;
el.textContent = formatElapsed(now - created);
});
}
function formatElapsed(ms) {
const totalSeconds = Math.max(0, Math.floor(ms / 1000));
const h = Math.floor(totalSeconds / 3600);
const m = Math.floor((totalSeconds % 3600) / 60);
const s = totalSeconds % 60;
const pad = (n) => String(n).padStart(2, '0');
return h > 0 ? `${h}:${pad(m)}:${pad(s)}` : `${m}:${pad(s)}`;
}
async function loadRecentSections(root) {
const container = root.querySelector('#recentSections');
let libraries;
try {
libraries = await getLibraries();
} catch (err) {
container.innerHTML = '
Impossible de charger les bibliothèques Emby.
';
return;
}
for (const lib of libraries) {
if (lib.collectionType === 'music') continue; // music gets its own experience later, not a poster row
const section = document.createElement('section');
section.className = 'section';
section.innerHTML = `