'use strict';
// ---- Audiobooks: embedded site. Sign-in details saved in Settings (this browser only) can be copied with one tap,
// because a page can't type into another site's login form.
const abCreds = () => store.get('ab_creds', { u: '', p: '' });
// Podcast Admin (Verse by Verse): the site refuses to be framed (X-Frame-Options), so this is a launcher.
function viewVerse() {
const url = cfg.verse, host = new URL(url).host;
$('#view').innerHTML = `
Podcast Admin
${esc(host + new URL(url).pathname)}
This site doesn't allow being shown inside another app, so it opens in its own tab.
`;
}
// Frames that must keep running (audio) live outside #view: created once, then only shown or hidden.
function showFrame(key, url, title, allow) {
const wrap = $('#audiowrap');
let f = wrap.querySelector(`iframe[data-k="${key}"]`);
if (!f) { f = document.createElement('iframe'); f.dataset.k = key; f.src = url; f.title = title; f.allow = allow; wrap.appendChild(f); }
wrap.querySelectorAll('iframe').forEach(x => x.classList.toggle('act', x === f));
wrap.className = 'on'; document.body.classList.add('onaudio');
}
// Podcast: opens in a frame when it has a secure (https) address; a plain-http address cannot be framed by a secure page.
// Podcast: a plain-http address on the home network. A secure page cannot frame http content, and the address is
// private to the LAN, so this opens it directly in the browser (which works on the home network or over a VPN).
function viewPodcast() {
const url = cfg.podcast, u = new URL(url), canFrame = u.protocol === 'https:';
$('#view').innerHTML = `
If the page below stays blank, the app does not allow being shown inside another app. Use Open in new tab.
'
: '
This is a plain http address, which a secure page cannot show inside itself. It opens in its own tab, and works at home or on your VPN.
'}
`;
if (canFrame) showFrame('podcast', url, 'Podcast', 'autoplay; fullscreen; picture-in-picture; clipboard-write');
}
// The frame is created once and kept alive, so playback carries on while you use other tabs.
// It loads /api/audiobooks/enter, where the server adds the site's secret sign-in link itself (the key never reaches this page).
const ENTER = '/api/audiobooks/enter';
function viewAudio() {
const c = abCreds(), old = $('#audiowrap iframe[data-k="audio"]');
$('#view').innerHTML = `
`;
const setSt = t => { const e = $('#abst'); if (e) e.textContent = t; };
const open = fresh => {
setSt('Opening…');
let f = $('#audiowrap iframe[data-k="audio"]'); if (f) f.remove();
showFrame('audio', ENTER + (fresh ? '?t=' + Date.now() : ''), 'Audiobooks', 'autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media');
f = $('#audiowrap iframe[data-k="audio"]'); f.referrerPolicy = 'no-referrer';
let done = false;
f.addEventListener('load', () => { done = true; setSt(''); });
setTimeout(() => { if (!done) setSt('Still loading… if it stays blank, tap the arrow to open it in its own tab'); }, 10000);
};
if (!old) open(false); else { showFrame('audio', '', 'Audiobooks', ''); setSt(''); }
$('#ar').onclick = () => open(true);
$('#af').onclick = () => { const f = $('#audiowrap iframe[data-k="audio"]'); if (f && f.requestFullscreen) f.requestFullscreen().catch(() => toast('Full screen is not available here')); else toast('Full screen is not available here'); };
const cu = $('#cu'); if (cu) cu.onclick = async () => { try { await navigator.clipboard.writeText(c.u); toast('Username copied. Password is in Settings.'); } catch { toast('Could not copy'); } };
}