openvibers/openvibe.live Commits
A private VOD or clip is transcribed and analysed too (roadmap WS-O task 2; Media 9aac60f signed playback URLs). The recording source for AI work is now a signed URL from Media (media-client signedMediaUrl, six hours), which works whatever the visibility. So OpenVibe.AI, which holds no key, reads a private recording window by window, and Live's own frame capture reads it as well. Before, the public URL 404'd for the 34 private VODs. It falls back to the public URL if Media does not sign. npm test passes.
Changes
@@@ -139,6 +139,12 @@ async function _mediaSource(row, kind = 'vod') {const media = require('../media-client');const id = row && row.id;if (!id) return null;++ // A signed URL reads the recording whatever its visibility: a private VOD is transcribed too (by OpenVibe.AI,++ // which holds no key) and its frames captured. Six hours covers a long transcript pass, window by window.++ try {++ const signed = await media.signedMediaUrl(kind, id, 6 * 3600);++ if (signed && signed.url) return signed.url;++ } catch { /* fall back to the public URL */ }const meta = kind === 'clip' ? await media.getClip(id) : await media.getVod(id);if (meta && meta.playback_url) return media.publicUrl(meta.playback_url);return kind === 'clip' ? media.clipUrl(id) : media.vodPlaybackUrl(id);@@@ -177,6 +177,14 @@ function getVod(vodId, opts = {}) {return request('GET', `/vods/${vodId}`, opts);}++/**++ * GET /vods/:id/signed-url or /clips/:id/signed-url → { url, expires_at }: a short-lived URL of the recording's bytes++ * that works whatever its visibility, for a reader with no key (OpenVibe.AI transcribing it). ttl in seconds (≤ 6 h).++ */++function signedMediaUrl(kind, id, ttlS = 3600, opts = {}) {++ return request('GET', `/${kind === 'clip' ? 'clips' : 'vods'}/${id}/signed-url`, { query: { ttl: ttlS }, ...opts });++}++/** GET /vods?limit&offset (+ pass-through filters like username/user_id/stream_id) */function listVods(query = {}, opts = {}) {return request('GET', '/vods', { query, ...opts });@@@ -398,6 +406,7 @@ function actingUserFrom(req) {}module.exports = {++ signedMediaUrl,MEDIA_URL, MEDIA_PUBLIC_URL, MEDIA_APP_ID,MediaApiError,request, proxy, actingUserFrom, _formData,
@@ -139,6 +139,12 @@ async function _mediaSource(row, kind = 'vod') {
@@ -139,6 +139,12 @@ async function _mediaSource(row, kind = 'vod') {
const media = require('../media-client');
const media = require('../media-client');
const id = row && row.id;
const id = row && row.id;
if (!id) return null;
if (!id) return null;
+ // A signed URL reads the recording whatever its visibility: a private VOD is transcribed too (by OpenVibe.AI,
+ // which holds no key) and its frames captured. Six hours covers a long transcript pass, window by window.
+ try {
+ const signed = await media.signedMediaUrl(kind, id, 6 * 3600);
+ if (signed && signed.url) return signed.url;
+ } catch { /* fall back to the public URL */ }
const meta = kind === 'clip' ? await media.getClip(id) : await media.getVod(id);
const meta = kind === 'clip' ? await media.getClip(id) : await media.getVod(id);
if (meta && meta.playback_url) return media.publicUrl(meta.playback_url);
if (meta && meta.playback_url) return media.publicUrl(meta.playback_url);
return kind === 'clip' ? media.clipUrl(id) : media.vodPlaybackUrl(id);
return kind === 'clip' ? media.clipUrl(id) : media.vodPlaybackUrl(id);
@@ -177,6 +177,14 @@ function getVod(vodId, opts = {}) {
@@ -177,6 +177,14 @@ function getVod(vodId, opts = {}) {
return request('GET', `/vods/${vodId}`, opts);
return request('GET', `/vods/${vodId}`, opts);
}
}
+/**
+ * GET /vods/:id/signed-url or /clips/:id/signed-url → { url, expires_at }: a short-lived URL of the recording's bytes
+ * that works whatever its visibility, for a reader with no key (OpenVibe.AI transcribing it). ttl in seconds (≤ 6 h).
+ */
+function signedMediaUrl(kind, id, ttlS = 3600, opts = {}) {
+ return request('GET', `/${kind === 'clip' ? 'clips' : 'vods'}/${id}/signed-url`, { query: { ttl: ttlS }, ...opts });
+}
+
/** GET /vods?limit&offset (+ pass-through filters like username/user_id/stream_id) */
/** GET /vods?limit&offset (+ pass-through filters like username/user_id/stream_id) */
function listVods(query = {}, opts = {}) {
function listVods(query = {}, opts = {}) {
return request('GET', '/vods', { query, ...opts });
return request('GET', '/vods', { query, ...opts });
@@ -398,6 +406,7 @@ function actingUserFrom(req) {
@@ -398,6 +406,7 @@ function actingUserFrom(req) {
}
}
module.exports = {
module.exports = {
+ signedMediaUrl,
MEDIA_URL, MEDIA_PUBLIC_URL, MEDIA_APP_ID,
MEDIA_URL, MEDIA_PUBLIC_URL, MEDIA_APP_ID,
MediaApiError,
MediaApiError,
request, proxy, actingUserFrom, _formData,
request, proxy, actingUserFrom, _formData,