'use strict';
// ---- Verse By Verse Ministry (Podcast -> Verse By Verse): free verse-by-verse Bible studies from versebyverseministry.org. Pick a study, play a lesson (the rest of the
// study follows), open its handout. Where you got to in each lesson is kept on the server, so it follows you between devices.
const vbApi = (p, opts) => jfetch('/api/vbv' + p, opts);
const vbOpt = (m, o) => ({ method: m, headers: { 'content-type': 'application/json' }, body: JSON.stringify(o) });
let vbProg = {}, vbQueued = {}, vbLast = 0;
const vbPlaying = () => { const t = cur(), m = t && /^vbv:([\w-]+):(\d+)$/.exec(String(t.key)); return m ? { slug: m[1], n: +m[2], key: t.key } : null; };
const vbLoadProg = async () => { try { for (const [k, p] of Object.entries(await vbApi('/progress') || {})) if (!vbProg[k] || p.t > vbProg[k].t) vbProg[k] = p; } catch {} };
const vbPush = keepalive => {
if (!Object.keys(vbQueued).length) return;
const body = JSON.stringify(vbQueued); vbQueued = {};
fetch('/api/vbv/progress', { method: 'POST', headers: { 'content-type': 'application/json' }, body, keepalive: !!keepalive }).then(r => { if (!r.ok) throw 0; }).catch(() => { vbQueued = { ...JSON.parse(body), ...vbQueued }; });
};
const vbSave = keepalive => { const n = vbPlaying(), d = pl.a.duration; if (!n || !isFinite(d) || d <= 0) return; vbProg[n.key] = vbQueued[n.key] = { pos: pl.a.currentTime, dur: d, t: Date.now() }; vbPush(keepalive); };
pl.a.addEventListener('timeupdate', () => { if (Date.now() - vbLast > 8000) { vbLast = Date.now(); vbSave(); } });
pl.a.addEventListener('pause', () => vbSave()); pl.a.addEventListener('ended', () => vbSave()); addEventListener('pagehide', () => vbSave(true));
const vbLeft = key => { const p = vbProg[key]; return p && p.pos > 10 && p.dur && p.pos < p.dur - 30 ? p : null; };
const vbDone = key => { const p = vbProg[key]; return !!(p && p.dur && p.pos >= p.dur - 30); };
const vbDate = d => { const t = Date.parse(d); return t > 0 ? new Date(t).toLocaleDateString([], { month: 'short', day: 'numeric', year: 'numeric' }) : ''; };
const vbCover = (s, big) => ``;
async function viewVbv(args = []) {
const v = $('#view'); v.innerHTML = '
Loading…
Free verse-by-verse Bible teaching from Verse By Verse Ministry International. Each study plays lesson after lesson, and most lessons have a handout.
${recent.length ? `No studies match.
'; }; $('#vbq').oninput = e => { S.q = e.target.value.trim(); draw(); }; $('#vbchips').querySelectorAll('a').forEach(a => a.onclick = e => { e.preventDefault(); S.cat = a.dataset.c; $('#vbchips').querySelectorAll('a').forEach(x => x.classList.toggle('on', x === a)); draw(); }); draw(); } async function vbStudy(slug) { const s = await vbApi('/study/' + encodeURIComponent(slug)); if (!location.hash.startsWith('#/podcast/vbv')) return; const key = l => `vbv:${slug}:${l.n}`, partial = s.lessons.filter(l => vbLeft(key(l))).sort((a, b) => vbProg[key(b)].t - vbProg[key(a)].t)[0], started = s.lessons.some(l => vbProg[key(l)]); const nextUp = () => partial || s.lessons.find(l => !vbDone(key(l))) || s.lessons[0]; const row = l => { const p = vbLeft(key(l)), done = vbDone(key(l)); return `${esc(s.teacher)} · ${s.lessons.length} lessons
Teaching and handouts © Verse By Verse Ministry International, shared freely at versebyverseministry.org.