// Round fourteen: the server's room list filtered by name and extended on // demand (it was capped at 80 with no way to the rest). const fs = require('fs'); const root = 'F:/Coding/SoulStream/'; let p, s; const load = (file) => { p = file; s = fs.readFileSync(root + p, 'utf8'); }; const save = () => fs.writeFileSync(root + p, s); const once = (a) => { const i = s.indexOf(a); if (i < 0) throw new Error('missing in ' + p + ': ' + a.slice(0, 90)); if (s.indexOf(a, i + 1) >= 0) throw new Error('ambiguous in ' + p + ': ' + a.slice(0, 90)); return i; }; const rep = (a, b) => { once(a); s = s.replace(a, () => b); }; load('src/mobile/screens/Community.svelte'); rep(` const otherRooms = $derived(slsk.rooms.filter((r) => !slsk.joined[r.name]).slice(0, 80));`, ` /* the server's rooms: filtered by name, the biggest first, 80 at a time with a way to the rest */ let roomQ = $state(""); let roomCap = $state(80); const roomsMatching = $derived.by(() => { const k = roomQ.trim().toLowerCase(); const list = slsk.rooms.filter((r) => !slsk.joined[r.name]); return k ? list.filter((r) => r.name.toLowerCase().includes(k)) : list; }); const otherRooms = $derived(roomsMatching.slice(0, roomCap)); $effect(() => { void roomQ; roomCap = 80; });`); rep(`

Rooms · {slsk.rooms.length} on the server

{#if !slsk.rooms.length}
Asking the server for its rooms…
{/if}`, `

Rooms · {slsk.rooms.length} on the server

{#if !slsk.rooms.length}
Asking the server for its rooms…
{:else if slsk.rooms.length > 8}
(roomQ = e.currentTarget.value)} type="search" placeholder="Find a room" autocomplete="off" autocapitalize="off" spellcheck="false" aria-label="Find a room" /> {#if roomQ}{/if}
{#if roomQ}
{roomsMatching.length} of {slsk.rooms.length} rooms
{/if} {/if}`); { // the "+ N more" after the room rows: the {/each} that closes otherRooms const a = ` {#each otherRooms as r (r.name)} {/each}`; once(a); s = s.replace(a, () => a + ` {#if roomsMatching.length > roomCap}
{/if}`); } save(); load('src/lib/mockLibrary.js'); rep(`const ROOMS = [["Lounge", 412], ["Electronic", 98], ["Vinyl Rips", 37], ["Jazz", 61], ["Lossless Only", 23]];`, `const ROOMS = [["Lounge", 412], ["Electronic", 98], ["Vinyl Rips", 37], ["Jazz", 61], ["Lossless Only", 23], ...Array.from({ length: 90 }, (_, i) => ["Room " + (i + 1), 90 - i])];`); save(); load('tests/mobile/smoke.mjs'); rep(` qfirst: (document.querySelector('.q-face .row .t') || {}).textContent || '',`, ` qfirst: (document.querySelector('.q-face .row .t') || {}).textContent || '', rooms: document.querySelectorAll('.screen button.row .art.hash').length,`); rep(` /* the fake network: a room with a few lines in it */ { do: \`__click('.screen button.row', 'Lounge')\`, name: "room", wait: 2400 },`, ` /* the room list: filtered by name, the rest on demand */ { do: \`(function () { var i = document.querySelector('.roomfilter input'); i.value = 'vin'; i.dispatchEvent(new Event('input', { bubbles: true })); })()\`, name: "rooms-filtered", wait: 500 }, { do: \`(function () { var i = document.querySelector('.roomfilter input'); i.value = ''; i.dispatchEvent(new Event('input', { bubbles: true })); })()\`, wait: 400 }, { do: \`__click('.screen .btn', 'more rooms')\`, name: "rooms-more", wait: 500 }, /* the fake network: a room with a few lines in it */ { do: \`__click('.screen button.row', 'Lounge')\`, name: "room", wait: 2400 },`); rep(` room: (i) => i.screen.includes("tr-push") && i.msgs >= 2,`, ` room: (i) => i.screen.includes("tr-push") && i.msgs >= 2, "rooms-filtered": (i) => i.rooms === 1, "rooms-more": (i) => i.rooms >= 95,`); save(); load('src/mobile/shell.css'); s = s.replace(/\s*$/, String.fromCharCode(10)) + ` /* Community: the room filter sits with the section, not the page's own field */ .sfield.roomfilter { margin-top: 2px; } `; save(); load('ANDROID.md'); rep(`## A peer, and their shares`, `The server's room list on Community is filtered by name and shows 80 at a time with a way to the rest (Soulseek lists hundreds). ## A peer, and their shares`); save(); console.log('round fourteen wired');