openvibers/openvibe.live Commits

The Rundown announces an episode once: a re-read writes it again without a second THE RUNDOWN line in global chat, and a stream that keeps nothing when read again loses its old write-up (#263)

OP OpenVibers committed 25 days ago · 3580ceebe9 · 2 files, +26 −2

Changes

ddiff --git a/server/rundown/desk.js b/server/rundown/desk.js
iindex bb6a092e..2480102d 100644
---- a/server/rundown/desk.js
++++ b/server/rundown/desk.js
@@@ -287,7 +287,13 @@ async function readStretch(stream, user) {
// ── Episodes ─────────────────────────────────────────────────
async function writeEpisode(stream, user) {
const segs = await db.all("SELECT id, start_sec, title, what, take, quotes_json, vod_id, topic_id FROM rundown_segments WHERE stream_id = ? AND status = 'live' ORDER BY start_sec ASC LIMIT 40", [stream.id]);
-- if (!segs.length) { await setProgress(stream.id, stream.read_to_sec, 1); return { called: false }; }
++ if (!segs.length) {
++ // Read again (after a desk fix) and nothing was kept: the old write-up goes too (one staff took down stays down).
++ await db.run("DELETE FROM rundown_reactions WHERE item_type = 'episode' AND item_id = ? AND EXISTS (SELECT 1 FROM rundown_episodes WHERE stream_id = ? AND status = 'live')", [stream.id, stream.id]);
++ await db.run("DELETE FROM rundown_episodes WHERE stream_id = ? AND status = 'live'", [stream.id]);
++ await setProgress(stream.id, stream.read_to_sec, 1);
++ return { called: false };
++ }
const topics = new Map((await db.all('SELECT id, title FROM rundown_topics WHERE id = ANY(?)', [[...new Set(segs.map((s) => s.topic_id).filter(Boolean))]])).map((t) => [t.id, t.title]));
let chat = null;
const minutes = Math.max(0, Math.round((Number(stream.duration_seconds) || ((toMs(stream.ended_at) || Date.now()) - (toMs(stream.started_at) || Date.now())) / 1000) / 60));
@@@ -303,12 +309,13 @@ async function writeEpisode(stream, user) {
if (!title || filters.addsAccusation(`${out.title} ${out.logline || ''}`, source) || filters.privateDetail(`${out.title} ${out.logline || ''}`)) { await setProgress(stream.id, stream.read_to_sec, 1); return { called: true, failed: true }; }
const chapters = (out.chapters || []).map((c) => segs[c.index] ? { sec: Math.round(Number(segs[c.index].start_sec)), title: clean(c.title, 60), segment_id: segs[c.index].id } : null).filter((c) => c && c.title);
const vod = (segs.find((s) => s.vod_id) || {}).vod_id || null;
++ const rewrite = !!await db.get('SELECT 1 FROM rundown_episodes WHERE stream_id = ?', [stream.id]);
await db.run(`INSERT INTO rundown_episodes (stream_id, user_id, title, logline, recap, chapters_json, vod_id, minutes, aired_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (stream_id) DO UPDATE SET title = excluded.title, logline = excluded.logline, recap = excluded.recap,
chapters_json = excluded.chapters_json, vod_id = excluded.vod_id, minutes = excluded.minutes`,
[stream.id, user.id, title, clean(out.logline, 220), recap ? recap.replace(/ ¶ /g, '\n\n') : null, JSON.stringify(chapters), vod, minutes, stream.started_at || sqlTime(Date.now())]);
await setProgress(stream.id, stream.read_to_sec, 1);
-- await announce(stream, user, title).catch(() => {});
++ if (!rewrite) await announce(stream, user, title).catch(() => {}); // written again (a re-read): announced once already
return { called: true, episode: true };
}
ddiff --git a/test/rundown.test.js b/test/rundown.test.js
iindex d7b2d864..e9ee6814 100644
---- a/test/rundown.test.js
++++ b/test/rundown.test.js
@@@ -310,6 +310,23 @@ console.log('✅ API: front page, topic, reactions as a signed-out reader; old /
console.log('✅ limits: lines per stretch, refused stretches skipped after three tries');
}
++// ── A re-read: the episode is written again but not announced again; a stream left with nothing has no episode ──
++{
++ const st1 = { ...await db.get('SELECT * FROM streams WHERE id = ?', [s1]), read_to_sec: (await db.get('SELECT read_to_sec FROM rundown_progress WHERE stream_id = ?', [s1])).read_to_sec };
++ const was = announced.length;
++ await desk.writeEpisode(st1, await db.get('SELECT id, username, display_name FROM users WHERE id = ?', [goose]));
++ assert.ok(await db.get('SELECT 1 FROM rundown_episodes WHERE stream_id = ?', [s1]));
++ assert.strictEqual(announced.length, was, 'written again: not announced again');
++ const quiet = await mk('quietone');
++ const sq = await stream(quiet, { startedAgoMin: 900, endedAgoMin: 800, title: 'Quiet' });
++ await db.run("INSERT INTO rundown_episodes (stream_id, user_id, title, recap, chapters_json, aired_at) VALUES (?, ?, 'Old write-up', 'x', '[]', ov_now())", [sq, quiet]);
++ await db.run("INSERT INTO rundown_reactions (item_type, item_id, voter, reaction) VALUES ('episode', ?, 'anon:q', 'lol')", [sq]);
++ await desk.writeEpisode({ ...await db.get('SELECT * FROM streams WHERE id = ?', [sq]), read_to_sec: 0 }, await db.get('SELECT id, username, display_name FROM users WHERE id = ?', [quiet]));
++ assert.ok(!await db.get('SELECT 1 FROM rundown_episodes WHERE stream_id = ?', [sq]), 'read again with nothing kept: the old write-up goes');
++ assert.ok(!await db.get("SELECT 1 FROM rundown_reactions WHERE item_type = 'episode' AND item_id = ?", [sq]), 'and its reactions');
++ console.log('✅ a re-read never announces twice and leaves no stale episode');
++}
++
// ── Play-by-play: a stream keeps its best 2 takes on a topic (and 2 with no topic) ──
{
const gamer = await mk('leaguenight');