openvibers/openvibe.live Commits
Arena: a live cam's frame is awaited (it was an un-awaited lookup, serialized as {}, so /arena asked for /[object Object] and showed a broken image) (#156)
Changes
@@@ -176,7 +176,7 @@ function _aRenderCams(live) {<div class="arena-cam-grid">${live.map(f => {const lock = f.ears && f.ears.focus;return `<div class="arena-cam ${f.transcribed ? '' : 'is-quiet'} ${lock ? 'is-locked' : ''}" style="--fc:${_aEsc(f.user.profile_color || '#8b5cf6')}">-- ${_aA(_aChannelLink(f.user, f.stream.slug || f.stream.managed_stream_id), `${f.thumbnail_url ? `<img class="arena-live-thumb" src="${_aEsc(f.thumbnail_url)}" alt="" onerror="this.hidden=true">` : ''}${_aPortrait(f, 'md')}<span class="arena-cam-rec"><span class="arena-live-dot arena-live-dot-sm"></span> LIVE · <i class="fa-solid fa-eye"></i> ${_aNum(f.stream.viewer_count)}</span>`, 'arena-cam-thumb')}++ ${_aA(_aChannelLink(f.user, f.stream.slug || f.stream.managed_stream_id), `${typeof f.thumbnail_url === 'string' && f.thumbnail_url ? `<img class="arena-live-thumb" src="${_aEsc(f.thumbnail_url)}" alt="" onerror="this.hidden=true">` : ''}${_aPortrait(f, 'md')}<span class="arena-cam-rec"><span class="arena-live-dot arena-live-dot-sm"></span> LIVE · <i class="fa-solid fa-eye"></i> ${_aNum(f.stream.viewer_count)}</span>`, 'arena-cam-thumb')}<div class="arena-cam-body"><div class="arena-mic-head">${_aA(_aFighterLink(f.user), `<strong>${_aEsc(f.user.display_name || f.user.username)}</strong>`)}@@@ -470,7 +470,7 @@ async function liveFighters() {user: c.user, rank: c.rank, ratings: c.ratings, record: c.record, image_url: c.image_url, level: c.level.level,persona: { fighter_name: c.persona.fighter_name, title: c.persona.title, class: c.persona.class, taunt: c.persona.taunt },stream: { id: s.id, title: s.title, category: s.category, viewer_count: s.viewer_count || 0, started_at: s.started_at, slug: s.managed_stream_slug || null, managed_stream_id: s.managed_stream_id || null },-- thumbnail_url: thumbs ? (thumbs.getCurrentLiveThumbnailUrl(s.id) || null) : null,++ thumbnail_url: thumbs ? ((await thumbs.getCurrentLiveThumbnailUrl(s.id)) || null) : null,hot_mic: hotMic, transcribed, ears, last_moment: lastMoment, open_beefs: (await beef.openBeefsFor(s.user_id)).length,};}))).sort((x, y) => y.ratings.power - x.ratings.power);@@@ -113,6 +113,8 @@ console.log('✅ roster + ratings are pure mic');const cs = await listener.consoleState(u3);assert.ok(cs.listening && cs.last_mic_judgement && cs.last_mic_judgement.is_trash_talk && cs.focus === null, 'console shows the mic judgement, no lock');assert.strictEqual((await arena.liveFighters())[0].user.id, u3);++ const camThumb = (await arena.liveFighters())[0].thumbnail_url;++ assert.ok(camThumb === null || typeof camThumb === 'string', `a live cam's frame is a URL or null, never ${JSON.stringify(camThumb)} (an un-awaited lookup made it {}, and the page asked for /[object Object])`);assert.ok((await arena.liveFighters())[0].last_moment && (await arena.liveFighters())[0].last_moment.aimed_at === 'chat', 'live cam carries the last judged line');// Name-drop → focus lock → beef.await db.run(`UPDATE streams SET started_at = datetime('now', '-700 seconds') WHERE id = ?`, [liveId]);
@@ -176,7 +176,7 @@ function _aRenderCams(live) {
@@ -176,7 +176,7 @@ function _aRenderCams(live) {
<div class="arena-cam-grid">${live.map(f => {
<div class="arena-cam-grid">${live.map(f => {
const lock = f.ears && f.ears.focus;
const lock = f.ears && f.ears.focus;
return `<div class="arena-cam ${f.transcribed ? '' : 'is-quiet'} ${lock ? 'is-locked' : ''}" style="--fc:${_aEsc(f.user.profile_color || '#8b5cf6')}">
return `<div class="arena-cam ${f.transcribed ? '' : 'is-quiet'} ${lock ? 'is-locked' : ''}" style="--fc:${_aEsc(f.user.profile_color || '#8b5cf6')}">
- ${_aA(_aChannelLink(f.user, f.stream.slug || f.stream.managed_stream_id), `${f.thumbnail_url ? `<img class="arena-live-thumb" src="${_aEsc(f.thumbnail_url)}" alt="" onerror="this.hidden=true">` : ''}${_aPortrait(f, 'md')}<span class="arena-cam-rec"><span class="arena-live-dot arena-live-dot-sm"></span> LIVE · <i class="fa-solid fa-eye"></i> ${_aNum(f.stream.viewer_count)}</span>`, 'arena-cam-thumb')}
+ ${_aA(_aChannelLink(f.user, f.stream.slug || f.stream.managed_stream_id), `${typeof f.thumbnail_url === 'string' && f.thumbnail_url ? `<img class="arena-live-thumb" src="${_aEsc(f.thumbnail_url)}" alt="" onerror="this.hidden=true">` : ''}${_aPortrait(f, 'md')}<span class="arena-cam-rec"><span class="arena-live-dot arena-live-dot-sm"></span> LIVE · <i class="fa-solid fa-eye"></i> ${_aNum(f.stream.viewer_count)}</span>`, 'arena-cam-thumb')}
<div class="arena-cam-body">
<div class="arena-cam-body">
<div class="arena-mic-head">
<div class="arena-mic-head">
${_aA(_aFighterLink(f.user), `<strong>${_aEsc(f.user.display_name || f.user.username)}</strong>`)}
${_aA(_aFighterLink(f.user), `<strong>${_aEsc(f.user.display_name || f.user.username)}</strong>`)}
@@ -470,7 +470,7 @@ async function liveFighters() {
@@ -470,7 +470,7 @@ async function liveFighters() {
user: c.user, rank: c.rank, ratings: c.ratings, record: c.record, image_url: c.image_url, level: c.level.level,
user: c.user, rank: c.rank, ratings: c.ratings, record: c.record, image_url: c.image_url, level: c.level.level,
persona: { fighter_name: c.persona.fighter_name, title: c.persona.title, class: c.persona.class, taunt: c.persona.taunt },
persona: { fighter_name: c.persona.fighter_name, title: c.persona.title, class: c.persona.class, taunt: c.persona.taunt },
stream: { id: s.id, title: s.title, category: s.category, viewer_count: s.viewer_count || 0, started_at: s.started_at, slug: s.managed_stream_slug || null, managed_stream_id: s.managed_stream_id || null },
stream: { id: s.id, title: s.title, category: s.category, viewer_count: s.viewer_count || 0, started_at: s.started_at, slug: s.managed_stream_slug || null, managed_stream_id: s.managed_stream_id || null },
- thumbnail_url: thumbs ? (thumbs.getCurrentLiveThumbnailUrl(s.id) || null) : null,
+ thumbnail_url: thumbs ? ((await thumbs.getCurrentLiveThumbnailUrl(s.id)) || null) : null,
hot_mic: hotMic, transcribed, ears, last_moment: lastMoment, open_beefs: (await beef.openBeefsFor(s.user_id)).length,
hot_mic: hotMic, transcribed, ears, last_moment: lastMoment, open_beefs: (await beef.openBeefsFor(s.user_id)).length,
};
};
}))).sort((x, y) => y.ratings.power - x.ratings.power);
}))).sort((x, y) => y.ratings.power - x.ratings.power);
@@ -113,6 +113,8 @@ console.log('✅ roster + ratings are pure mic');
@@ -113,6 +113,8 @@ console.log('✅ roster + ratings are pure mic');
const cs = await listener.consoleState(u3);
const cs = await listener.consoleState(u3);
assert.ok(cs.listening && cs.last_mic_judgement && cs.last_mic_judgement.is_trash_talk && cs.focus === null, 'console shows the mic judgement, no lock');
assert.ok(cs.listening && cs.last_mic_judgement && cs.last_mic_judgement.is_trash_talk && cs.focus === null, 'console shows the mic judgement, no lock');
assert.strictEqual((await arena.liveFighters())[0].user.id, u3);
assert.strictEqual((await arena.liveFighters())[0].user.id, u3);
+ const camThumb = (await arena.liveFighters())[0].thumbnail_url;
+ assert.ok(camThumb === null || typeof camThumb === 'string', `a live cam's frame is a URL or null, never ${JSON.stringify(camThumb)} (an un-awaited lookup made it {}, and the page asked for /[object Object])`);
assert.ok((await arena.liveFighters())[0].last_moment && (await arena.liveFighters())[0].last_moment.aimed_at === 'chat', 'live cam carries the last judged line');
assert.ok((await arena.liveFighters())[0].last_moment && (await arena.liveFighters())[0].last_moment.aimed_at === 'chat', 'live cam carries the last judged line');
// Name-drop → focus lock → beef.
// Name-drop → focus lock → beef.
await db.run(`UPDATE streams SET started_at = datetime('now', '-700 seconds') WHERE id = ?`, [liveId]);
await db.run(`UPDATE streams SET started_at = datetime('now', '-700 seconds') WHERE id = ?`, [liveId]);