'use strict';
// Home: "Pick up where you left off" (Continue watching and Continue listening), shown above the day's agenda in the evening and below it in the morning.
async function homeResume(el) {
if (!el) return;
const bits = await Promise.allSettled([
allowed('video') ? (async () => {
const st = await jfetch('/api/plex/status'); if (!st.signedIn || !st.server) return '';
px.serverKey = st.server;
const items = ((await px.get('/library/onDeck?X-Plex-Container-Start=0&X-Plex-Container-Size=8')).Metadata || []).filter(m => m.type === 'movie' || m.type === 'episode').slice(0, 6);
return items.length ? `
Continue watching
${items.map(m => vdCard(m, true)).join('')}
` : '';
})() : '',
allowed('audio') ? (async () => {
const [data] = await Promise.all([abApi('/books'), abLoadProg()]), books = Array.isArray(data) ? data : (data.books || Object.values(data));
const cont = books.filter(b => { const p = abProg[abId(b)]; return p && p.pos > 10 && p.dur && p.pos < p.dur - 30; }).sort((a, b) => abProg[abId(b)].t - abProg[abId(a)].t).slice(0, 6);
today.books = cont;
return cont.length ? `Continue listening
` : '';
})() : '',
allowed('read') ? (async () => {
const list = await jfetch('/api/read/list');
const cont = list.filter(b => b.pct > 0.01 && b.pct < 0.98).sort((a, b) => b.read - a.read).slice(0, 6);
return cont.length ? `Continue reading
` : '';
})() : '',
]);
const html = bits.map(b => b.status === 'fulfilled' ? b.value : '').join('');
if (!html || !el.isConnected) return;
el.innerHTML = `Pick up where you left off
${html}`;
el.querySelectorAll('a[data-book]').forEach(a => a.onclick = e => { e.preventDefault(); const b = (today.books || []).find(x => abId(x) === a.dataset.book); if (b) abSheet(b); });
}
const today = { books: [] };
// Home: how much you listened this week (podcasts and audiobooks), the day streak, and a yearly goal for audiobooks finished. The goal is kept in your synced settings.
const lsTime = sec => { const m = Math.round(sec / 60); return m < 60 ? m + ' min' : Math.floor(m / 60) + ' h' + (m % 60 ? ' ' + (m % 60) + ' min' : ''); };
async function homeListening(after) {
if (!after || !(allowed('podcast') || allowed('audio'))) return;
let s; try { s = await jfetch('/api/listening/stats'); } catch { return; }
const goal = +store.get('read_goal', 0) || 0; if (!after.isConnected) return;
const max = Math.max(60, ...s.last14.map(d => d.s)), card = document.createElement('div'); card.id = 'listening';
card.innerHTML = `Listening
${lsTime(s.week)}this week${s.streak}day${s.streak === 1 ? '' : 's'} in a row${s.finishedYear}${goal ? ' / ' + goal : ''}books finished this year
${s.last14.map(d => ``).join('')}
${goal ? `
` : ''}
`;
after.insertAdjacentElement('afterend', card);
jfetch('/api/listening/family').then(f => { const box = card.querySelector('#lsfam'); if (!box) return; if (!f.goal && !f.finished) { box.innerHTML = ``; } else box.innerHTML = `${f.finished}${f.goal ? ' of ' + f.goal : ''}family books finished in ${f.year}${f.people.length ? ' ยท ' + esc(f.people.map(p => p.name + ' ' + p.n).join(', ')) : ''}
${f.goal ? `
` : ''}`;
const b = box.querySelector('#lsfg'); if (b) b.onclick = () => { const el = openSheet('Family reading challenge', 'One goal for everyone: how many books the family finishes this year (audiobooks and e-books together).', ``); el.querySelector('#lsff').onsubmit = async e => { e.preventDefault(); try { await jfetch('/api/listening/family', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ goal: +el.querySelector('#lsfn').value || 0 }) }); closeSheet(); card.remove(); homeListening(after); } catch (er) { toast(er.message); } }; };
}).catch(() => {});
card.querySelector('#lsgoal').onclick = () => { const el = openSheet('Audiobooks to finish this year', '', ``); el.querySelector('#lsf').onsubmit = e => { e.preventDefault(); const n = Math.max(0, Math.min(500, Math.round(+el.querySelector('#lsn').value) || 0)); if (n) store.set('read_goal', n); else store.del('read_goal'); closeSheet(); card.remove(); homeListening(after); }; };
}