Music: use Plex as another person in your Plex Home (list, PIN, switch back), shown as Playing as <name>
build-container / build (push) Successful in 19m30s

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-22 09:31:47 -04:00
1 parent cedd6845ce
commit dae19176cd
6 files changed
+132 -10

No files matched your search

+39
View File
@@ -62,3 +62,42 @@ function sleepSheet() {
if (sleepT.end || sleepT.eot) opts.push({ label: 'Turn off the timer', icon: 'x', run: () => sleepSet(0) });
actionSheet('Sleep timer', sleepLabel() === 'Sleep' ? 'Fades the music out and pauses' : sleepLabel(), opts);
}
// ---- Plex Home: use Music as someone else in your Plex Home (their PIN if they have one)
const plexHome = { t: 0, data: null };
async function plexHomeUsers() {
if (plexHome.data && Date.now() - plexHome.t < 5 * 60e3) return plexHome.data;
plexHome.data = await jfetch('/api/plex/users'); plexHome.t = Date.now(); return plexHome.data;
}
/** After the Music header is drawn: "Playing as Nate" with a switch link, but only when the Plex Home has more than one person. */
async function plexHomeBadge(st) {
try {
const d = await plexHomeUsers(), el = document.getElementById('phu');
if (!el || !d.users || d.users.length < 2) return;
const me = d.users.find(x => x.current) || d.users.find(x => x.admin) || d.users[0];
el.innerHTML = ` · <a href="#" id="pswitch" style="color:var(--accent)">Playing as ${esc(me.title)} ▾</a>`;
document.getElementById('pswitch').onclick = e => { e.preventDefault(); plexSwitchSheet(d.users); };
} catch { /* no Plex Home: nothing to switch */ }
}
function plexSwitchSheet(users) {
const el = openSheet('Who is listening?', 'People in your Plex Home. Playlists, ratings and what you have played follow the person you pick.',
`<div class="list">${users.map((u, i) => `<button class="row" data-u="${i}"><span class="ic" style="background:var(--panel2);overflow:hidden;color:var(--text)">${u.thumb ? `<img src="${esc(u.thumb)}" alt="" referrerpolicy="no-referrer" style="width:100%;height:100%;object-fit:cover" onerror="this.remove()">` : esc([...u.title][0].toUpperCase())}</span>
<span class="grow"><b>${esc(u.title)}${u.current ? ' ✓' : ''}</b><small>${[u.admin ? 'Admin' : '', u.restricted ? 'Restricted' : '', u.protected && !u.admin ? 'PIN' : ''].filter(Boolean).join(' · ') || ' '}</small></span>${u.current ? '' : icon('chev', 'chev')}</button>`).join('')}</div>
<div class="bar"><button class="btn ghost" id="sx" style="flex:1;justify-content:center">Close</button></div>`);
el.querySelector('#sx').onclick = closeSheet;
el.querySelectorAll('[data-u]').forEach(b => b.onclick = () => { const u = users[+b.dataset.u]; if (u.current) return closeSheet(); if (u.protected && !u.admin) plexPinSheet(u); else plexSwitchTo(u, ''); });
}
function plexPinSheet(u) {
const el = openSheet('PIN for ' + u.title, '', `<form id="ppf"><label for="ppi">PIN</label><input type="password" id="ppi" inputmode="numeric" autocomplete="off" maxlength="8" required>
<div class="bar"><button class="btn ghost" type="button" id="sx" style="flex:1;justify-content:center">Cancel</button><button class="btn" id="ppb" style="flex:1;justify-content:center">Switch</button></div><div class="err" id="ppe" role="alert"></div></form>`);
el.querySelector('#sx').onclick = closeSheet;
el.querySelector('#ppf').onsubmit = e => { e.preventDefault(); plexSwitchTo(u, el.querySelector('#ppi').value, msg => { el.querySelector('#ppe').textContent = msg; el.querySelector('#ppi').select(); }); };
setTimeout(() => el.querySelector('#ppi').focus(), 60);
}
async function plexSwitchTo(u, pin, onError) {
try {
await jfetch('/api/plex/switch', { method: 'POST', body: JSON.stringify({ id: u.id, pin }) });
closeSheet(); plexHome.data = null; px.secs = null;
toast('Now using Plex as ' + u.title); route();
} catch (e) { if (onError) onError(e.message); else toast(e.message); }
}