openvibers/openvibe.community Commits

Keep current Live item when older VOD is nearby (#373)

OP OpenVibers committed 2 days ago · 69f415cf3f · 2 files, +10 −6

Changes

ddiff --git a/server/pulse/sources.js b/server/pulse/sources.js
iindex 7ce44ff..94e7b82 100644
---- a/server/pulse/sources.js
++++ b/server/pulse/sources.js
@@@ -288,7 +288,7 @@ function createPulseSources({ db, config = {}, fetchImpl = globalThis.fetch, now
const id = Number(s && s.id), channel = clean(s && s.username, 64);
const started = sqlFrom(s && s.started_at, null);
if (!Number.isSafeInteger(id) || id < 1 || !/^[A-Za-z0-9_.-]{1,64}$/.test(channel) || !started) continue;
-- onAir.set(channel.toLowerCase(), Date.parse(`${started.replace(' ', 'T')}Z`));
++ onAir.set(channel.toLowerCase(), { id: String(id), started: Date.parse(`${started.replace(' ', 'T')}Z`) });
const name = clean(s.display_name || channel, 80);
const r = await store.upsertItem(db, { source_service: 'live', source_type: 'stream', source_id: String(id),
title: `${name} went live: ${clean(s.title, 160) || 'a stream'}`, url: `${liveApi}/@${encodeURIComponent(channel)}`,
@@@ -311,15 +311,15 @@ function createPulseSources({ db, config = {}, fetchImpl = globalThis.fetch, now
const at = sqlFrom(v.created_at, null);
if (!at) continue;
const channel = clean(v.channel && v.channel.username, 64);
-- const currentStart = onAir.get(channel.toLowerCase());
-- if (type === 'recording' && Number.isFinite(currentStart)
-- && Math.abs(Date.parse(`${at.replace(' ', 'T')}Z`) - currentStart) <= 10 * MINUTE) continue;
++ const current = onAir.get(channel.toLowerCase());
++ if (type === 'recording' && current && Number.isFinite(current.started)
++ && Math.abs(Date.parse(`${at.replace(' ', 'T')}Z`) - current.started) <= 10 * MINUTE) continue;
seen.add(`${type}:${id}`);
let prior = null;
if (type === 'recording' && channel) {
prior = await db.prepare(`SELECT actor_subject, source_id FROM pulse_items WHERE source_service = 'live' AND source_type = 'stream'
-- AND lower(url) = lower(?) AND occurred_at BETWEEN ? AND ? ORDER BY occurred_at DESC LIMIT 1`)
-- .get(`${liveApi}/@${encodeURIComponent(channel)}`, sqlTime(Date.parse(`${at.replace(' ', 'T')}Z`) - 60 * MINUTE), sqlTime(Date.parse(`${at.replace(' ', 'T')}Z`) + 60 * MINUTE));
++ AND lower(url) = lower(?) AND source_id <> ? AND occurred_at BETWEEN ? AND ? ORDER BY occurred_at DESC LIMIT 1`)
++ .get(`${liveApi}/@${encodeURIComponent(channel)}`, current && current.id || '', sqlTime(Date.parse(`${at.replace(' ', 'T')}Z`) - 60 * MINUTE), sqlTime(Date.parse(`${at.replace(' ', 'T')}Z`) + 60 * MINUTE));
}
const r = await store.upsertItem(db, { source_service: 'live', source_type: type, source_id: id,
title: `${type === 'recording' ? 'Recording: ' : ''}${clean(v.title, 150) || (type === 'recording' ? 'A stream' : 'A clip')}`,
ddiff --git a/test/pulse-sources.test.js b/test/pulse-sources.test.js
iindex 1d944c2..fddd185 100644
---- a/test/pulse-sources.test.js
++++ b/test/pulse-sources.test.js
@@@ -15,6 +15,7 @@ const day = (ms) => new Date(ms).toISOString().slice(0, 10);
const badgeAt = iso(Date.now() - 3_600_000);
const calls = [];
let liveStreams = [];
++ let extraContent = [];
let galleryRows = [
{ id: 'pic_01JAB2C3D4E5F6G7H8J9K0MNPQ', title: 'First photo', author: 'Alex', listed: true, published_at: badgeAt,
links: { page: 'https://openvibe.pics/i/firstpic', thumb: 'https://openvibe.pics/i/firstpic/thumb.webp' }, width: 800, height: 600 },
@@@ -42,6 +43,7 @@ const day = (ms) => new Date(ms).toISOString().slice(0, 10);
if (u.includes('/api/content/feed')) return { ok: true, json: async () => ({ items: [
{ id: 123, kind: 'vod', title: 'Night stream', href: 'https://openvibe.video/watch?v=night', thumbnail_url: 'https://openvibe.media/night.webp', created_at: badgeAt, channel: { username: 'alex', display_name: 'Alex' }, duration_seconds: 500 },
{ id: 124, kind: 'clip', title: 'Night clip', href: 'https://openvibe.video/clip/night', thumbnail_url: 'https://openvibe.media/clip.webp', created_at: badgeAt, channel: { username: 'alex', display_name: 'Alex' }, duration_seconds: 25 },
++ ...extraContent,
], next: null, sources: { vods: 'ok', clips: 'ok' }, partial: false }) };
if (u.includes('/api/v1/apps/gallery')) return { ok: true, json: async () => ({ spaces: [{
id: 'spc_01JAB2C3D4E5F6G7H8J9K0MNPQ', name: 'A shared map', description: 'A map of places',
@@@ -155,6 +157,8 @@ const day = (ms) => new Date(ms).toISOString().slice(0, 10);
const db = t.app.locals.db;
const item = (type, id) => db.prepare('SELECT title FROM pulse_items WHERE source_service = ? AND source_type = ? AND source_id = ?').get('live', type, String(id));
liveStreams = [{ id: 999, username: 'alex', display_name: 'Alex', title: 'Night stream', started_at: badgeAt }];
++ extraContent = [{ id: 125, kind: 'vod', title: 'Earlier broadcast', href: 'https://openvibe.video/watch?v=earlier',
++ created_at: iso(Date.parse(badgeAt) - 20 * 60_000), channel: { username: 'alex', display_name: 'Alex' } }];
await t.app.locals.pulseSources.runOnce({ force: true });
assert.ok(await item('stream', 999));
assert.ok(!(await item('recording', 123)), 'a recording for the broadcast is suppressed while it is live');