openvibers/openvibe.live Commits

Arena: a meltdown's quote is the heated line nearest the shouting, not the longest line said around it (#152)

OP OpenVibers committed 28 days ago · c2d0c23eba · 2 files, +24 −3

Changes

ddiff --git a/server/arena/drama.js b/server/arena/drama.js
iindex f30928f2..19af2f84 100644
---- a/server/arena/drama.js
++++ b/server/arena/drama.js
@@@ -230,8 +230,8 @@ async function detectSounds(streams, sinceTxt) {
if (n >= 3 && (!best || n > best.n)) best = { n, from: hits[i], to: hits[j] };
}
if (!best) continue;
-- const lines = await db.all(`SELECT text FROM stream_timeline_events WHERE stream_id = ? AND kind = 'speech' AND start_sec BETWEEN ? AND ? ORDER BY start_sec`, [s.id, best.from.start_sec - 20, best.to.start_sec + 20]);
-- const quote = lines.map((l) => String(l.text || '')).filter((t) => t && !arena()._isBannedText(t)).sort((a, b) => b.length - a.length)[0] || null;
++ const lines = await db.all(`SELECT text, start_sec FROM stream_timeline_events WHERE stream_id = ? AND kind = 'speech' AND start_sec BETWEEN ? AND ? ORDER BY start_sec`, [s.id, best.from.start_sec - 20, best.to.start_sec + 20]);
++ const quote = pickQuote(lines, best.from.start_sec, best.to.start_sec);
const counts = {};
for (const h of hits.slice(hits.indexOf(best.from), hits.indexOf(best.to) + 1)) counts[h.label] = (counts[h.label] || 0) + 1;
out.push({ kind, userId: s.user_id, streamId: s.id, vodId: best.from.vod_id || null, sec: best.from.start_sec, dedupeKey: `${kind}:${s.id}:${Math.floor(best.from.start_sec / 600)}`,
@@@ -241,6 +241,18 @@ async function detectSounds(streams, sinceTxt) {
return out;
}
++// The line said around a meltdown that sounds like one: heat (swearing, exclamations, "why", "I can't") counts most,
++// then how close it was to the shouting, then length; a mundane line far from it only when nothing else was said.
++const HEAT = /\b(fuck\w*|shit\w*|damn\w*|bro|dude|wtf|why|what the|i can'?t|i'?m done|i swear|stop|rigged|trash|garbage|hate|kill me|are you (kidding|serious))\b|!/i;
++function pickQuote(lines, fromSec, toSec) {
++ const mid = (Number(fromSec) + Number(toSec)) / 2;
++ const scored = lines.map((l) => ({ t: String(l.text || '').trim(), at: Number(l.start_sec) }))
++ .filter((l) => l.t.split(/\s+/).length >= 4 && !arena()._isBannedText(l.t))
++ .map((l) => ({ ...l, score: (HEAT.test(l.t) ? 10 : 0) - Math.abs(l.at - mid) / 6 + Math.min(l.t.length, 160) / 80 }));
++ scored.sort((a, b) => b.score - a.score);
++ return scored.length ? scored[0].t : null;
++}
++
/** Once a day: who fell off, who has not missed a day, and the quote of the day. */
async function detectDaily(now) {
const out = [];
@@@ -430,4 +442,4 @@ async function setOptOut(userId, out) {
async function hide(id) { await db.run("UPDATE arena_drama SET status = 'hidden' WHERE id = ?", [Number(id)]); }
--module.exports = { detect, beefStory, createStory, announce, feed, story, react, lolcowIndex, cloutRankings, rapSheet, setOptOut, optedOut, hide, REACTIONS, TEMPLATES: T, _test: { detectStreams, detectSnapshots, detectSounds, detectDaily, weekStart, toMs, fmt } };
++module.exports = { detect, beefStory, createStory, announce, feed, story, react, lolcowIndex, cloutRankings, rapSheet, setOptOut, optedOut, hide, REACTIONS, TEMPLATES: T, _test: { detectStreams, detectSnapshots, detectSounds, detectDaily, weekStart, toMs, fmt, pickQuote } };
ddiff --git a/test/arena-drama.test.js b/test/arena-drama.test.js
iindex d031d2d9..d970bcbd 100644
---- a/test/arena-drama.test.js
++++ b/test/arena-drama.test.js
@@@ -132,6 +132,15 @@ const db = require('../server/db/database');
await new Promise((r) => setTimeout(r, 50));
assert.deepStrictEqual(await db.get('SELECT headline, ai FROM arena_drama WHERE id = ?', [g2]), { headline: '👻 ghost STREAMED 90 MINUTES TO AN EMPTY ROOM', ai: 0 }, 'a misspelled name keeps the template');
++ // The meltdown quote: the heated line near the shouting beats a longer mundane one.
++ const { pickQuote } = drama._test;
++ assert.strictEqual(pickQuote([
++ { text: 'so the charge on each capacitor of the panel decides what you see on the screen today', start_sec: 95 },
++ { text: 'bro why does this keep happening to me', start_sec: 128 },
++ { text: 'ok', start_sec: 130 },
++ ], 100, 160), 'bro why does this keep happening to me');
++ assert.strictEqual(pickQuote([{ text: 'ok', start_sec: 1 }], 0, 10), null, 'too short to quote');
++
console.log('arena-drama: all checks passed');
process.exit(0);
})().catch((e) => { console.error(e); process.exit(1); });