openvibers/openvibe.live Commits

VOD and clip API: their independent lookups (names, stream, AI state, Media's clip list, view count, Community's comment count) run together instead of one after another (#214)

OP OpenVibers committed 27 days ago · f675c1b108 · 2 files, +27 −23

Changes

ddiff --git a/server/media-proxy/clips.js b/server/media-proxy/clips.js
iindex 3291977d..40152ca9 100644
---- a/server/media-proxy/clips.js
++++ b/server/media-proxy/clips.js
@@@ -232,20 +232,25 @@ router.get('/:id', optionalAuth, async (req, res) => {
}
if (!clip || !await access.canView(req.user, clip)) return clipNotFound(res);
if (access.isPrivate(clip)) res.set('Cache-Control', cache.htmlHeaders({ private: true }));
-- await withUserFields(clip);
++ // Independent lookups, run together (one after another before, Community's comment count included).
++ const ip = req.headers['cf-connecting-ip'] || req.headers['x-forwarded-for']?.split(',')[0]?.trim() || req.ip || 'unknown';
++ const [, inserted, stream, st, comments] = await Promise.all([
++ withUserFields(clip),
++ // Unique-view tracking (content_views stays in live.db).
++ db.run('INSERT INTO content_views (content_type, content_id, ip) VALUES (?, ?, ?) ON CONFLICT DO NOTHING', ['clip', clip.id, ip]).catch(() => null),
++ clip.stream_id ? db.getStreamById(clip.stream_id).catch(() => null) : null,
++ db.getClipAiState(clip.id).catch(() => null),
++ commentCount('clip', clip.id, clip.title, req.ip).catch(() => null), // null when Community is unreachable
++ ]);
-- // Unique-view tracking (content_views stays in live.db).
try {
-- const ip = req.headers['cf-connecting-ip'] || req.headers['x-forwarded-for']?.split(',')[0]?.trim() || req.ip || 'unknown';
-- const inserted = await db.run('INSERT INTO content_views (content_type, content_id, ip) VALUES (?, ?, ?) ON CONFLICT DO NOTHING', ['clip', clip.id, ip]);
-- if (inserted.changes > 0) {
++ if (inserted && inserted.changes > 0) {
const count = await db.get('SELECT COUNT(*) as c FROM content_views WHERE content_type = ? AND content_id = ?', ['clip', clip.id]);
clip.view_count = Math.max(Number(clip.view_count) || 0, count.c);
}
} catch { /* */ }
if (clip.stream_id) {
-- const stream = await db.getStreamById(clip.stream_id);
if (stream) {
clip.stream_started_at = stream.started_at;
clip.stream_ended_at = stream.ended_at;
@@@ -261,7 +266,6 @@ router.get('/:id', optionalAuth, async (req, res) => {
// Overlay Live-owned AI state (overview + transcript live in clip_ai_state).
try {
-- const st = await db.getClipAiState(clip.id);
if (st) {
if (st.ai_overview_short) { clip.ai_overview_short = st.ai_overview_short; clip.ai_overview = st.ai_overview || clip.ai_overview || st.ai_overview_short; }
if (st.ai_transcript_json) {
@@@ -272,7 +276,7 @@ router.get('/:id', optionalAuth, async (req, res) => {
}
} catch { /* */ }
-- clip.comment_count = await commentCount('clip', clip.id, clip.title, req.ip); // null when Community is unreachable
++ clip.comment_count = comments;
clip.can_delete = await canActorDeleteClip(req.user, clip);
clip.can_edit = await canActorModerateClip(req.user, clip);
ddiff --git a/server/media-proxy/vods.js b/server/media-proxy/vods.js
iindex 5bbf1979..b8fd5428 100644
---- a/server/media-proxy/vods.js
++++ b/server/media-proxy/vods.js
@@@ -479,11 +479,21 @@ router.get('/:id', optionalAuth, async (req, res) => {
const vod = await loadVisibleVod(req, res, req.params.id);
if (!vod) return;
if (access.isPrivate(vod)) res.set('Cache-Control', cache.htmlHeaders({ private: true }));
-- await withUserFields(vod);
++ // The lookups below do not depend on each other: they run together (they ran one after another, Media's clip
++ // list and Community's comment count included).
++ const ip = requesterIp(req);
++ const [, stream, st, co, inserted, comments] = await Promise.all([
++ withUserFields(vod),
++ vod.stream_id ? db.getStreamById(vod.stream_id).catch(() => null) : null,
++ db.getVodAiState(vod.id).catch(() => null),
++ media.listClips(vod.stream_id ? { stream_id: vod.stream_id } : { vod_id: vod.id }).catch(() => null),
++ // Unique-view tracking stays local (content_views is a Live table).
++ db.run('INSERT INTO content_views (content_type, content_id, ip) VALUES (?, ?, ?) ON CONFLICT DO NOTHING', ['vod', vod.id, ip]).catch(() => null),
++ commentCount('vod', vod.id, vod.title, req.ip).catch(() => null), // null when Community is unreachable
++ ]);
// Enrich with local stream details for chat replay.
if (vod.stream_id) {
-- const stream = await db.getStreamById(vod.stream_id);
if (stream) {
vod.stream_started_at = stream.started_at;
vod.stream_ended_at = stream.ended_at;
@@@ -496,7 +506,6 @@ router.get('/:id', optionalAuth, async (req, res) => {
// Overlay Live-owned AI state (overview + transcript live in vod_ai_state).
try {
-- const st = await db.getVodAiState(vod.id);
if (st) {
if (st.ai_overview_short) { vod.ai_overview_short = st.ai_overview_short; vod.ai_overview = st.ai_overview || vod.ai_overview || st.ai_overview_short; }
if (st.ai_transcript_json) {
@@@ -507,24 +516,15 @@ router.get('/:id', optionalAuth, async (req, res) => {
}
} catch { /* */ }
-- let clips = [];
-- try {
-- const q = vod.stream_id ? { stream_id: vod.stream_id } : { vod_id: vod.id };
-- const co = await media.listClips(q);
-- clips = co?.clips || (Array.isArray(co) ? co : []);
-- } catch { /* */ }
--
-- // Unique-view tracking stays local (content_views is a Live table).
++ const clips = co?.clips || (Array.isArray(co) ? co : []);
try {
-- const ip = requesterIp(req);
-- const inserted = await db.run('INSERT INTO content_views (content_type, content_id, ip) VALUES (?, ?, ?) ON CONFLICT DO NOTHING', ['vod', vod.id, ip]);
-- if (inserted.changes > 0) {
++ if (inserted && inserted.changes > 0) {
const count = await db.get('SELECT COUNT(*) as c FROM content_views WHERE content_type = ? AND content_id = ?', ['vod', vod.id]);
vod.view_count = Math.max(Number(vod.view_count) || 0, count.c);
}
} catch { /* */ }
-- vod.comment_count = await commentCount('vod', vod.id, vod.title, req.ip); // null when Community is unreachable
++ vod.comment_count = comments;
res.json({ vod, clips });
} catch {
res.status(500).json({ error: 'Failed to get VOD' });