openvibers/openvibe.live Commits

Home streamer cards: an account-key stream is listed next to slots only while it is live or the newest; a months-old one under them read as a slot Go Live does not have (#388)

OP OpenVibers committed 17 days ago · 4fc7aa57bf · 2 files, +19 −3

Changes

ddiff --git a/server/streaming/routes.js b/server/streaming/routes.js
iindex 6e98b78a..7a6ad6e1 100644
---- a/server/streaming/routes.js
++++ b/server/streaming/routes.js
@@@ -1200,9 +1200,12 @@ router.get('/recently-online', async (req, res) => {
try {
const parsed = JSON.parse(s.managed_streams_json || '[]');
// A stream that never had a slot is listed as the channel itself, so someone who streamed is never
-- // "No streams" (Dreezy's first browser stream had no slot, 2026-10-18).
++ // "No streams" (Dreezy's first browser stream had no slot, 2026-10-18). Next to slots it is listed only
++ // while it is live or what they streamed last (the account key, finditfixit): Go Live lists slots, and
++ // a months-old account-key stream under them read as a slot nobody could find (owner, 2026-10-27).
const loose = s.loose_stream_json ? JSON.parse(s.loose_stream_json) : null;
-- if (loose) parsed.push({ managed_stream_id: null, stream_id: loose.stream_id || null, slug: null, title: loose.title || null, protocol: null, last_live_at: loose.last_live_at || null, vod_thumbnail: null });
++ const looseCurrent = loose && (!loose.last_live_at || !parsed.some(p => p.last_live_at && p.last_live_at >= loose.last_live_at));
++ if (looseCurrent) parsed.push({ managed_stream_id: null, stream_id: loose.stream_id || null, slug: null, title: loose.title || null, protocol: null, last_live_at: loose.last_live_at || null, vod_thumbnail: null });
// Sort by most recently live first; put null last
s.managed_streams = parsed.sort((a, b) => {
if (!a.last_live_at && !b.last_live_at) return 0;
ddiff --git a/test/recently-online-live.test.js b/test/recently-online-live.test.js
iindex e7b71e84..54e976c7 100644
---- a/test/recently-online-live.test.js
++++ b/test/recently-online-live.test.js
@@@ -18,8 +18,10 @@ const db = require('../server/db/database');
await db.initDb();
const mk = async (username) => { await db.createUser({ username, email: `${username}@x`, password_hash: 'x', display_name: username, stream_key: username.padEnd(32, '0') }); const id = (await db.get('SELECT id FROM users WHERE username = ?', [username])).id; await db.ensureChannel(id); return id; };
const izor = await mk('izor'), quiet1 = await mk('quietone'), first = await mk('firsttimer'), loose = await mk('dreezy');
++ const owner = await mk('goosely'), keyUser = await mk('finditfixit');
const slot = async (uid, slug) => Number((await db.run('INSERT INTO managed_streams (user_id, slug, title, protocol, stream_key, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ov_now(), ov_now()) RETURNING id', [uid, slug, `${slug} title`, 'webrtc', `${slug}-key-${uid}`])).lastInsertRowid);
const ranked = await slot(izor, 'ranked'), chill = await slot(izor, 'chill'), q = await slot(quiet1, 'main');
++ const irl = await slot(owner, 'irl'), bench = await slot(keyUser, 'bench');
const stream = async (uid, ms, { live = false, startedAgo, endedAgo = null, viewers = 0 }) => await db.run(
`INSERT INTO streams (user_id, managed_stream_id, title, protocol, is_live, viewer_count, started_at, ended_at, thumbnail_url, created_at)
VALUES (?, ?, ?, 'webrtc', ?, ?, to_char(now() - make_interval(mins => ?), 'YYYY-MM-DD HH24:MI:SS'), ${live ? 'NULL' : "to_char(now() - make_interval(mins => ?), 'YYYY-MM-DD HH24:MI:SS')"}, ?, ov_now())`,
@@@ -31,6 +33,11 @@ const db = require('../server/db/database');
// A first stream, live now and on no slot; and a streamer whose only (ended) stream never had a slot.
await stream(first, null, { live: true, startedAgo: 3, viewers: 1 });
await stream(loose, null, { startedAgo: 300, endedAgo: 298 });
++ // Streamers with slots and an account-key stream: one from months before their slots, one from after.
++ await stream(owner, null, { startedAgo: 130000, endedAgo: 129900 });
++ await stream(owner, irl, { startedAgo: 420, endedAgo: 400 });
++ await stream(keyUser, bench, { startedAgo: 5000, endedAgo: 4900 });
++ await stream(keyUser, null, { startedAgo: 700, endedAgo: 650 });
// Media's answer for a slot-less stream's public recording (lookups asks Media by stream id).
require('../server/media-proxy/lookups').publicVodsForStreams = async (ids) => new Map(ids.map((id) => [Number(id), { id: 9, thumbnail_url: '/t/dreezy-part-2.jpg' }]));
@@@ -56,7 +63,13 @@ const db = require('../server/db/database');
const dz = body.streamers.find((s) => s.username === 'dreezy');
assert.deepStrictEqual(dz.managed_streams.map((m) => [m.slug, m.title, !!m.last_live_at]), [[null, 'old', true]]);
assert.ok(String(dz.managed_streams[0].vod_thumbnail).endsWith('/t/dreezy-part-2.jpg'), "with its recording's picture");
-- assert.strictEqual(body.total, 4);
++ // Next to slots, an account-key stream is listed only while it is what they streamed last: Go Live lists slots,
++ // and a months-old one under them read as a slot nobody could find (owner, 2026-10-27).
++ const go = body.streamers.find((s) => s.username === 'goosely');
++ assert.deepStrictEqual(go.managed_streams.map((m) => m.slug), ['irl'], 'an old account-key stream is left out');
++ const fx = body.streamers.find((s) => s.username === 'finditfixit');
++ assert.deepStrictEqual(fx.managed_streams.map((m) => m.slug), [null, 'bench'], 'the newest one is listed, first');
++ assert.strictEqual(body.total, 6);
console.log('recently-online live: all checks passed');
} finally { server.close(); }
process.exit(0);