Add transparent OBS lyrics output through presenter pairing
This commit is contained in:
16
frontend/lower-third.js
Normal file
16
frontend/lower-third.js
Normal file
@@ -0,0 +1,16 @@
|
||||
/* 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}`; p.textContent = cue?.text || ''; if (cue?.secondary || cue?.phonetic) { const secondary = root.document.createElement('small'); secondary.textContent = [cue.secondary, cue.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);
|
||||
Reference in New Issue
Block a user