openvibers/openvibe.live Commits

Live Now is newest first, never by crowd, and says so (market outcome) (#506)

OP OpenVibers committed 12 days ago · 5305107a06 · 3 files, +30 −2

The home's Live Now grid drew /api/streams in its viewer-count order, so the biggest stream stayed
on top and a channel that just went live sat at the bottom. The home now sorts what it draws by
when each stream started, newest first, and the section's kicker says 'newest first, never by
crowd'. The server's order stays as it is for its other readers.

Changes

ddiff --git a/public/fragments/home.html b/public/fragments/home.html
iindex 1dac1092..08084ab6 100644
---- a/public/fragments/home.html
++++ b/public/fragments/home.html
@@@ -76,7 +76,7 @@
<div class="home-featured" id="home-featured" hidden></div>
<!-- Live Streams -->
<div class="section-header" style="--sc:#ef4444">
-- <h2><i class="fa-solid fa-circle live-dot"></i> Live Now<small class="section-kicker">on air</small></h2>
++ <h2><i class="fa-solid fa-circle live-dot"></i> Live Now<small class="section-kicker" title="Sorted by when each stream started, so a channel that just went live is seen">newest first, never by crowd</small></h2>
<span id="live-count" class="badge">0</span>
<button type="button" class="home-featured-toggle" id="home-featured-toggle" hidden><i class="fa-solid fa-satellite-dish"></i> Show featured stream</button>
</div>
ddiff --git a/public/js/app-home.js b/public/js/app-home.js
iindex c31ffce7..3b50292f 100644
---- a/public/js/app-home.js
++++ b/public/js/app-home.js
@@@ -1388,7 +1388,9 @@ async function loadHome() {
// copy is at most 20 seconds old; anything older falls through to a normal load and the
// placeholders cover the gap.
await apiSWR('/streams', (liveData) => {
-- const streams = liveData.streams || [];
++ // Newest first, never by crowd (market research, Live outcome: a channel that just went live is seen,
++ // instead of the biggest staying on top). The server's own order stays for its other readers.
++ const streams = (liveData.streams || []).slice().sort((a, b) => (Date.parse(b.started_at) || 0) - (Date.parse(a.started_at) || 0));
document.getElementById('live-count').textContent = streams.length;
const noLiveEl = document.getElementById('no-live-streams');
if (noLiveEl) noLiveEl.style.display = streams.length ? 'none' : '';
ddiff --git a/test/home-live-order.test.js b/test/home-live-order.test.js
nnew file mode 100644
iindex 00000000..bae0ba0f
---- /dev/null
++++ b/test/home-live-order.test.js
@@@ -0,0 +1,26 @@
++'use strict';
++/**
++ * The home's Live Now grid is newest first, never by crowd (market research, Live's outcome: a channel that just went
++ * live is seen instead of the biggest staying on top), and the section says so. The server's /api/streams keeps its
++ * own order for its other readers; the home sorts what it draws.
++ */
++const assert = require('assert');
++const fs = require('fs');
++const path = require('path');
++
++const fragment = fs.readFileSync(path.join(__dirname, '..', 'public', 'fragments', 'home.html'), 'utf8');
++const js = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'app-home.js'), 'utf8');
++
++assert.match(fragment, /Live Now<small class="section-kicker"[^>]*>newest first, never by crowd<\/small>/, 'the section says how it is sorted');
++const sorter = /const streams = \(liveData\.streams \|\| \[\]\)\.slice\(\)\.sort\(\(a, b\) => (.+?)\);\n/.exec(js);
++assert.ok(sorter, 'the home sorts the live streams it draws');
++// The comparator the home uses, run on three streams: the one that started last comes first, whatever its crowd.
++const cmp = new Function('a', 'b', `return ${sorter[1]};`);
++const list = [
++ { username: 'big', viewer_count: 900, started_at: '2026-11-01T08:00:00Z' },
++ { username: 'new', viewer_count: 1, started_at: '2026-11-01T10:30:00Z' },
++ { username: 'mid', viewer_count: 40, started_at: '2026-11-01T09:00:00Z' },
++].sort(cmp);
++assert.deepStrictEqual(list.map((s) => s.username), ['new', 'mid', 'big']);
++assert.ok(js.indexOf(sorter[0]) < js.indexOf("renderStreamGrid('stream-grid-live', streams, true)"), 'sorted before it is drawn');
++console.log('home-live-order: ok');