diff options
Diffstat (limited to 'src/features')
| -rw-r--r-- | src/features/messages.js | 34 |
1 files changed, 26 insertions, 8 deletions
diff --git a/src/features/messages.js b/src/features/messages.js index 4820baa..c82670b 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -8975,7 +8975,20 @@ export function messagesFeature(ctx) { b.ws = ws; bcRecord(b); b.reconnecting = false; - if (info.id !== b.id) toast(t('goLiveRestarted')); + // The server couldn't take us back (it restarted, or we were gone + // too long): this is a new stream at a new address. The old one is + // over — said so, with no recording (there's next to nothing in + // it) — and the new one is announced as soon as it plays. + if (info.id !== b.id) { + toast(t('goLiveRestarted')); + const old = { ...b, recording: null }; + Object.assign(b, { id: info.id, liveUrl: info.live, recording: info.recording, a: LIVE_KIND + ':' + b.pk + ':' + info.id }); + bcAnnounce(old, 'ended').catch(() => {}); + bcPlaying(b).then(() => (bc === b && b.phase === 'live' ? bcAnnounce(b, 'live') : null)).then(() => { + // the streamer's own view of it follows to the new address + if (bc === b && b.ev && ui.liveStream && ui.liveStream.a === old.a) { ui.liveStream = { a: b.a, seed: b.ev }; render(); } + }).catch(() => {}); + } render(); return; } catch {} @@ -8994,14 +9007,23 @@ export function messagesFeature(ctx) { ['p', id.pubkey, '', 'Host'], ['relays', ...relays.slice(0, 6)], CLIENT_TAG]; if (me.picture) tags.push(['image', me.picture]); if (status === 'live' && b.viewers != null) tags.push(['current_participants', String(b.viewers)]); - if (status === 'ended') tags.push(['ends', String(Math.floor(Date.now() / 1000))], ['recording', b.recording]); + if (status === 'ended') tags.push(['ends', String(Math.floor(Date.now() / 1000))]); + if (status === 'ended' && b.recording) tags.push(['recording', b.recording]); const partial = { kind: LIVE_KIND, content: '', created_at: Math.floor(Date.now() / 1000), tags }; const evt = id.signer instanceof Uint8Array ? finalizeEvent(partial, id.signer) : await id.signer.signEvent(partial); takeLive([evt]); - b.ev = evt; + if (bc === b) b.ev = evt; scheduleRepaint(); return publishOn(relays, evt); } + async function bcPlaying(b) { + const url = b.liveUrl; + for (let i = 0; i < 40 && bc === b && b.phase === 'live' && b.liveUrl === url; i++) { + await new Promise((r) => setTimeout(r, 500)); + const pl = await fetch(url, { cache: 'no-store' }).then((r) => r.text()).catch(() => ''); + if ((pl.match(/\.ts\s*$/gm) || []).length >= 3) break; + } + } async function startBroadcast() { const b = bc; if (!b || b.phase !== 'setup' || !b.media) return; @@ -9019,11 +9041,7 @@ export function messagesFeature(ctx) { // three segments — Chrome's own player won't start a live playlist with // fewer (it fails to parse it), so a viewer who comes at once would get // an error, not the stream - for (let i = 0; i < 40 && bc === b && b.phase === 'live'; i++) { - await new Promise((r) => setTimeout(r, 500)); - const pl = await fetch(b.liveUrl, { cache: 'no-store' }).then((r) => r.text()).catch(() => ''); - if ((pl.match(/\.ts\s*$/gm) || []).length >= 3) break; - } + await bcPlaying(b); if (bc !== b || b.phase !== 'live') return; await bcAnnounce(b, 'live'); b.tick = setInterval(() => bcTick(b), 60_000); |
