openvibers/openvibe.live Commits
Home 'Right now': the AI note alone, never the raw speech-to-text after ' — heard:' (a Greek stream's 500-character transcript filled the featured card, owner 2026-10-17); static, so it applies before the server half (#236) can deploy (#237)
Changes
@@@ -116,6 +116,9 @@function render(d) {const s = d.stream;const m = d.moment;++ // The note alone: the raw speech-to-text after " — heard:" is the AI's context, not something to show (it can be++ // 500 characters of another language; the server strips it too, server/db/database.js publicMemoryText).++ const now = m && m.description ? String(m.description).replace(/\s+—\s+heard:[\s\S]*$/, '').trim() : '';const chan = typeof channelPath === 'function' ? channelPath(s.username, s.managed_stream_slug || s.managed_stream_id || null) : `/@${s.username}`;const viewers = Number(s.total_viewer_count || s.viewer_count || 0);const up = (typeof formatUptime === 'function' && s.started_at) ? formatUptime(s.started_at) : '';@@@ -138,7 +141,7 @@${s.category ? `<span class="hf-tag"${s.ai_category && s.ai_category === s.category ? ' title="Category inferred by OpenVibe's AI from the stream"' : ''}>${escText(s.category)}${s.ai_category && s.ai_category === s.category ? '<span class="cat-inferred"> · inferred</span>' : ''}</span>` : ''}${up ? `<span class="muted"><i class="fa-solid fa-clock"></i> ${escText(up)}</span>` : ''}</a>-- ${m && m.description ? `<div class="hf-now"><div class="hf-now-head"><i class="fa-solid fa-wand-magic-sparkles"></i> Right now <span>${m.captured_at ? escText(typeof timeAgo === 'function' ? timeAgo(m.captured_at) : '') : ''}</span></div>${escText(m.description)}</div>` : ''}++ ${now ? `<div class="hf-now"><div class="hf-now-head"><i class="fa-solid fa-wand-magic-sparkles"></i> Right now <span>${m.captured_at ? escText(typeof timeAgo === 'function' ? timeAgo(m.captured_at) : '') : ''}</span></div>${escText(now)}</div>` : ''}${s.ai_overview_short || s.ai_overview ? `<div class="hf-overview">${escText(s.ai_overview_short || s.ai_overview)}</div>` : ''}<div class="hf-actions"><a class="hf-watch" href="${escText(chan)}" onclick="return handleLinkClick(event, '${escText(chan)}')"><i class="fa-solid fa-play"></i> Watch & chat</a>nnew file mode 100644@@@ -0,0 +1,19 @@++'use strict';++// The home page's Featured live card shows the AI note alone in "Right now": the raw speech-to-text after " — heard:"++// (up to 500 characters, often another language) is never shown (owner, 2026-10-17: a Greek stream's transcript++// filled the card).++//++// node test/home-featured-note.test.js++const assert = require('assert');++const fs = require('fs');++const path = require('path');++++const src = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'home-featured.js'), 'utf8');++const m = /const now = m && m\.description \? String\(m\.description\)\.replace\((\/[^\n]*?\/), ''\)\.trim\(\) : '';/.exec(src);++assert.ok(m, 'the card cuts the heard clause before showing the note');++// eslint-disable-next-line no-eval++const re = eval(m[1]);++assert.strictEqual('The main screen is black. — heard: "Δεν θα πούμε άλλο."'.replace(re, '').trim(), 'The main screen is black.');++assert.strictEqual('A quiet desk, chat is busy.'.replace(re, '').trim(), 'A quiet desk, chat is busy.', 'a note without one stays whole');++assert.ok(/\$\{escText\(now\)\}/.test(src) && !/\$\{escText\(m\.description\)\}/.test(src), 'what is shown is the cut note');++console.log('home featured note: all checks passed');
@@ -116,6 +116,9 @@
@@ -116,6 +116,9 @@
function render(d) {
function render(d) {
const s = d.stream;
const s = d.stream;
const m = d.moment;
const m = d.moment;
+ // The note alone: the raw speech-to-text after " — heard:" is the AI's context, not something to show (it can be
+ // 500 characters of another language; the server strips it too, server/db/database.js publicMemoryText).
+ const now = m && m.description ? String(m.description).replace(/\s+—\s+heard:[\s\S]*$/, '').trim() : '';
const chan = typeof channelPath === 'function' ? channelPath(s.username, s.managed_stream_slug || s.managed_stream_id || null) : `/@${s.username}`;
const chan = typeof channelPath === 'function' ? channelPath(s.username, s.managed_stream_slug || s.managed_stream_id || null) : `/@${s.username}`;
const viewers = Number(s.total_viewer_count || s.viewer_count || 0);
const viewers = Number(s.total_viewer_count || s.viewer_count || 0);
const up = (typeof formatUptime === 'function' && s.started_at) ? formatUptime(s.started_at) : '';
const up = (typeof formatUptime === 'function' && s.started_at) ? formatUptime(s.started_at) : '';
@@ -138,7 +141,7 @@
@@ -138,7 +141,7 @@
${s.category ? `<span class="hf-tag"${s.ai_category && s.ai_category === s.category ? ' title="Category inferred by OpenVibe's AI from the stream"' : ''}>${escText(s.category)}${s.ai_category && s.ai_category === s.category ? '<span class="cat-inferred"> · inferred</span>' : ''}</span>` : ''}
${s.category ? `<span class="hf-tag"${s.ai_category && s.ai_category === s.category ? ' title="Category inferred by OpenVibe's AI from the stream"' : ''}>${escText(s.category)}${s.ai_category && s.ai_category === s.category ? '<span class="cat-inferred"> · inferred</span>' : ''}</span>` : ''}
${up ? `<span class="muted"><i class="fa-solid fa-clock"></i> ${escText(up)}</span>` : ''}
${up ? `<span class="muted"><i class="fa-solid fa-clock"></i> ${escText(up)}</span>` : ''}
</a>
</a>
- ${m && m.description ? `<div class="hf-now"><div class="hf-now-head"><i class="fa-solid fa-wand-magic-sparkles"></i> Right now <span>${m.captured_at ? escText(typeof timeAgo === 'function' ? timeAgo(m.captured_at) : '') : ''}</span></div>${escText(m.description)}</div>` : ''}
+ ${now ? `<div class="hf-now"><div class="hf-now-head"><i class="fa-solid fa-wand-magic-sparkles"></i> Right now <span>${m.captured_at ? escText(typeof timeAgo === 'function' ? timeAgo(m.captured_at) : '') : ''}</span></div>${escText(now)}</div>` : ''}
${s.ai_overview_short || s.ai_overview ? `<div class="hf-overview">${escText(s.ai_overview_short || s.ai_overview)}</div>` : ''}
${s.ai_overview_short || s.ai_overview ? `<div class="hf-overview">${escText(s.ai_overview_short || s.ai_overview)}</div>` : ''}
<div class="hf-actions">
<div class="hf-actions">
<a class="hf-watch" href="${escText(chan)}" onclick="return handleLinkClick(event, '${escText(chan)}')"><i class="fa-solid fa-play"></i> Watch & chat</a>
<a class="hf-watch" href="${escText(chan)}" onclick="return handleLinkClick(event, '${escText(chan)}')"><i class="fa-solid fa-play"></i> Watch & chat</a>
new file mode 100644
new file mode 100644
@@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
+'use strict';
+// The home page's Featured live card shows the AI note alone in "Right now": the raw speech-to-text after " — heard:"
+// (up to 500 characters, often another language) is never shown (owner, 2026-10-17: a Greek stream's transcript
+// filled the card).
+//
+// node test/home-featured-note.test.js
+const assert = require('assert');
+const fs = require('fs');
+const path = require('path');
+
+const src = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'home-featured.js'), 'utf8');
+const m = /const now = m && m\.description \? String\(m\.description\)\.replace\((\/[^\n]*?\/), ''\)\.trim\(\) : '';/.exec(src);
+assert.ok(m, 'the card cuts the heard clause before showing the note');
+// eslint-disable-next-line no-eval
+const re = eval(m[1]);
+assert.strictEqual('The main screen is black. — heard: "Δεν θα πούμε άλλο."'.replace(re, '').trim(), 'The main screen is black.');
+assert.strictEqual('A quiet desk, chat is busy.'.replace(re, '').trim(), 'A quiet desk, chat is busy.', 'a note without one stays whole');
+assert.ok(/\$\{escText\(now\)\}/.test(src) && !/\$\{escText\(m\.description\)\}/.test(src), 'what is shown is the cut note');
+console.log('home featured note: all checks passed');