/* Broadcast lyrics rendered through the existing presenter relay. */ (function(root) { 'use strict'; function cuePair(lines, index) { const current = lines[index]?.kind === 'line' ? lines[index] : null; const next = lines.slice(Math.max(0, index + 1)).find(l => l.kind === 'line') || null; return { current, next }; } function url(origin, code) { const u = new URL('/', origin); u.searchParams.set('overlay', 'lowerthird'); u.searchParams.set('code', String(code)); return u.href; } const active = () => new URLSearchParams(root.location?.search).get('overlay') === 'lowerthird'; let box, signature = ''; function paint(lines, index) { if (!box) { box = root.document.createElement('div'); box.id = 'obsLowerThird'; box.setAttribute('aria-live', 'polite'); root.document.body.append(box); } const pair = cuePair(lines, index), key = JSON.stringify(pair); if (key === signature) return; signature = key; box.replaceChildren(); for (const [role, cue] of Object.entries(pair)) { const p = root.document.createElement('div'); p.className = `obs-line obs-${role}`; const parts = root.LyricsCore.display(cue); p.textContent = parts.text; if (parts.secondary || parts.phonetic) { const secondary = root.document.createElement('small'); secondary.textContent = [parts.secondary, parts.phonetic].filter(Boolean).join(' · '); p.append(secondary); } box.append(p); } } function register(open) { root.SettingsSections.register({ id: 'broadcast', title: 'Presenter & broadcast', cluster: 'Live & worship', summary: () => 'Projector · OBS lower third', render(container) { const doc = container.ownerDocument, p = doc.createElement('p'); p.textContent = 'Start a remote-controlled screen, then copy its OBS browser-source URL. Set the browser source to 1920 × 1080. The output follows the host and remains transparent. Pairing codes expire; an already paired source reconnects until you unpair it.'; const b = doc.createElement('button'); b.type = 'button'; b.className = 'settings-back'; b.textContent = 'Open presenter & remote controls'; b.onclick = open; container.append(p, b); } }); } const api = { active, paint, cuePair, url, register }; if (typeof module !== 'undefined') module.exports = api; else { root.LowerThird = api; if (active()) root.document.documentElement.classList.add('obs-overlay'); } })(typeof window !== 'undefined' ? window : globalThis);