Add a ?pi=1 profile, and stop re-deriving search keys per keystroke
Two separate costs, both measured on musicdolphin (Pi 4, 1920x1080 kiosk), where the app was burning ~70% of a core with nothing happening on screen. Per-frame work. The ambient canvas repaints a full-screen gradient plus a particle field every frame, and `usePlaybackClock` pushes a React setState per animation frame into both PlayView and PlayerBar for the whole length of a track. `?pi=1` (lib/ lowPower.ts) makes those cheaper rather than switching them off: the canvas paints a quarter of the pixels at 30fps with a bubble cap, and the clock renders ten times a second - a progress bar advances one pixel every few hundred ms and its label has one-second resolution, so nothing on screen can tell. Only the effects with no cheap version actually go: the backdrop-filter glass blur and the decorative CSS loops. Also drops a redundant full-canvas clearRect that the opaque gradient always covered. Search. normalize() runs a Unicode NFD decomposition, and albumMatches/songMatches called it on every album title and every track title on every keystroke - 4969 of them for a track search, whose answer cannot change until the library does. buildSearchIndex does it once per library payload; a keystroke is now String.includes over strings that already exist. On the real library that is 33ms -> 3.4ms for an eight-letter track query on a laptop, and this runs on a Pi. The same index partitions albums by shelf and pre-sorts each shelf's categories, which App and BrowseView were deriving separately from the same data. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,7 +34,7 @@ import { browseBackActions, GROUP_ORDER, handleKey, initialUiState, isRootShelf
|
||||
import { playPop } from "./lib/pop";
|
||||
import { targetForAlbum } from "./lib/remote";
|
||||
import type { Group, Results, SongHit } from "./lib/search";
|
||||
import { categoryMatches, groupOf, results as computeResults } from "./lib/search";
|
||||
import { buildSearchIndex, categoryMatches, groupOf, results as computeResults } from "./lib/search";
|
||||
import { SHOW_AMBIENCE, SHOW_GLASS_BLUR } from "./lib/theme";
|
||||
|
||||
/** How long an armed "A" waits for the digit that completes the shortcut. */
|
||||
@@ -92,33 +92,38 @@ export function App() {
|
||||
setUi((previous) => (previous.cols === columns ? previous : { ...previous, cols: columns }));
|
||||
}, [columns]);
|
||||
|
||||
// Normalized search keys, group partitions and each shelf's category list, derived
|
||||
// once per library payload instead of per keystroke - see lib/search.ts. The library
|
||||
// only reloads when the backend says a rescan finished, so this is genuinely rare.
|
||||
const index = useMemo(() => buildSearchIndex(library.albums), [library.albums]);
|
||||
|
||||
const results: Results = useMemo(
|
||||
() =>
|
||||
computeResults({
|
||||
albums: library.albums,
|
||||
index,
|
||||
search: ui.search,
|
||||
mode: ui.mode,
|
||||
group: ui.group,
|
||||
category: ui.category,
|
||||
}),
|
||||
[library.albums, ui.search, ui.mode, ui.group, ui.category],
|
||||
[index, ui.search, ui.mode, ui.group, ui.category],
|
||||
);
|
||||
|
||||
// The bare root's three shelves each compute their own categories independently
|
||||
// (see BrowseView) - the keyboard handler needs the same lists, by key only, to know
|
||||
// how far Ctrl+hjkl can move within a row and which category ENTER opens.
|
||||
// The bare root's three shelves, by category key only: the keyboard handler needs
|
||||
// these to know how far Ctrl+hjkl can move within a row and which category ENTER
|
||||
// opens. BrowseView renders the same shelves from the same precomputed lists.
|
||||
const rootShelves = useMemo(
|
||||
() =>
|
||||
GROUP_ORDER.map((group) =>
|
||||
categoryMatches({
|
||||
albums: library.albums,
|
||||
index,
|
||||
search: "",
|
||||
mode: "albums",
|
||||
category: null,
|
||||
group,
|
||||
}).map((entry) => entry.key),
|
||||
),
|
||||
[library.albums],
|
||||
[index],
|
||||
);
|
||||
|
||||
const byId = useMemo(
|
||||
@@ -432,7 +437,7 @@ export function App() {
|
||||
<BrowseView
|
||||
results={results}
|
||||
group={ui.group}
|
||||
albums={library.albums}
|
||||
index={index}
|
||||
mode={ui.mode}
|
||||
search={ui.search}
|
||||
category={ui.category}
|
||||
|
||||
Reference in New Issue
Block a user