scan progress: core API + UI poller (extracted from #558)#571
Merged
IrosTheBeggar merged 3 commits intomasterfrom Apr 25, 2026
Merged
scan progress: core API + UI poller (extracted from #558)#571IrosTheBeggar merged 3 commits intomasterfrom
IrosTheBeggar merged 3 commits intomasterfrom
Conversation
(cherry picked from commit b25b40d)
Three small modernizations from PR #558 (the syncthing/electron PR), pulled out so they can land independent of the Electron Desktop Player work. * src/api/scrobbler.js — POST /api/v1/lastfm/test-login was the last caller of axios. Switched to native fetch (Node ≥22), drop the dep. * src/logger.js — was using winston-daily-rotate-file for log rotation. Replaced with a small in-process rotator that opens a fresh file every hour and prunes anything older than 14 days. * src/api/file-explorer.js — `makeDirectorySync` from `make-dir` was the only caller; native `fs.mkdirSync(p, { recursive: true })` covers the same use. Also tightened the playlist-resolver loop and added a `skipped` count to the response so clients can see when entries were filtered for traversal.
Lifts the scan-progress refactor out of PR #558 (syncthing/electron) so the player UI can show live scan progress on a default-UI install today, without waiting for the Desktop Player feature to ship. Three problems with the old flow: 1. The scan_progress table was readable only via /api/v1/admin/db/scan/ progress, mounted in velvet-stubs.js and gated under /admin/. On a default-UI install the endpoint didn't exist (velvet-stubs only loaded when ui='velvet'), and even on velvet, non-admin users couldn't reach it. 2. The default UI's player polled /api/v1/db/status (coarse boolean lock + total file count) and only set up its 2s interval AFTER seeing locked=true once. A scan triggered after page-load went invisible until the next refresh. 3. The renderer only knew how to write 'Scan In Progress' + a count to a pair of divs. No per-vpath progress, no current-file display. Changes: * src/api/scan.js (NEW) — GET /api/v1/scan/progress. Authenticated but not admin-only. Filters rows to vpaths the caller can see; admins also see pre-vpath 'counting' rows where the scanner hasn't assigned a library yet. currentFile is stripped to basename so absolute server paths don't leak. * src/api/velvet-stubs.js — drop the old /api/v1/admin/db/scan/progress; one comment in its place pointing at the new endpoint. * src/server.js — mount scanApi alongside the other core APIs (always loaded, regardless of ui setting). * webapp/alpha/scan-progress.js (NEW) — polls every 3s unconditionally. Empty response → empty wrap → no visible UI when idle. Renders a per-vpath card with vpath name, progress bar, percent, scanned/expected counts, and current-file as the title attribute. * webapp/alpha/spa.css — .spc-* rules for the cards (palette adapted to the main UI's colors; the velvet variables aren't defined here). * webapp/index.html — replaces the legacy <div id='scan-status'> + <div id='scan-status-files'> with <div id='scan-progress-wrap'>; loads the new scan-progress.js script. * webapp/alpha/m.js — removes the old async dbStatus() + its caller + the unused startInterval. The function wrote to the now-removed scan-status DOM ids and would have thrown on every page load. MSTREAMAPI.dbStatus and the GET /api/v1/db/status endpoint are left in place — both are public surface and may have external callers.
ec8ae11 to
c5eb2f2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extracts the scan-progress refactor and a few small modernizations out of PR #558 (Syncthing + Electron Desktop Player), so they can land independent of the Desktop Player work. The Syncthing/Electron features stay on #558.
Three commits, each independently revertable:
update actionsWorkflow version bumps that hadn't already been merged to master. Honors master's deletion of
test-ffmpeg-bootstrap.yml.drop unused deps: axios, winston-daily-rotate-file, make-diraxios—POST /api/v1/lastfm/test-loginwas the last caller; swapped for nativefetch(Node ≥22).winston-daily-rotate-file— replaced with a small in-process rotator insrc/logger.js(opens a fresh file every hour, prunes anything older than 14 days).make-dir—makeDirectorySyncwas the only caller; nativefs.mkdirSync(p, { recursive: true })covers it. Also tightens the playlist-resolver loop insrc/api/file-explorer.jsand adds askippedcount to the response.scan progress: core API + UI pollerThe actual feature this PR is about. Three problems with the current scan-status flow:
scan_progresstable was readable only viaGET /api/v1/admin/db/scan/progress, mounted invelvet-stubs.js. On default-UI installs the endpoint didn't exist (velvet-stubsonly loaded whenui='velvet'), and it was admin-gated everywhere./api/v1/db/status(coarselockedboolean + total file count) and only set up its 2s interval after seeinglocked: trueonce. A scan triggered after page load went invisible until refresh.Server
src/api/scan.js(NEW) —GET /api/v1/scan/progress. Authenticated but not admin-only. Filters rows to vpaths the caller can see; admins also see pre-vpath 'counting' rows.currentFileis stripped to basename so absolute server paths don't leak.src/api/velvet-stubs.js— drops the old/api/v1/admin/db/scan/progress; one comment in its place.src/server.js— mountsscanApialongside the other core APIs (always loaded).Webapp
webapp/alpha/scan-progress.js(NEW) — polls every 3s unconditionally. Empty response → empty wrap → no visible UI when idle. Renders a per-vpath card with vpath name, progress bar, percent, scanned/expected counts, current-file as the title attribute.webapp/alpha/spa.css—.spc-*rules for the cards (palette adapted to the main UI's colors).webapp/index.html— replaces<div id='scan-status'>+<div id='scan-status-files'>with<div id='scan-progress-wrap'>; loads the new script.webapp/alpha/m.js— removes the oldasync dbStatus()+ its caller + the unusedstartInterval. The function wrote to the now-removed scan-status DOM ids and would have thrown on every page load.MSTREAMAPI.dbStatusandGET /api/v1/db/statusare left in place — both are public surface and may have external callers.Verification
prefer-const/no-useless-assignmentissues insrc/logger.jsalong the way.node --checkpasses on every changed.jsfile.fetch-based test-login. Logs rotate correctly withoutwinston-daily-rotate-file.Compatibility
/api/v1/scan/progress— does not collide with any existing route.getScanStatushandler is unchanged.MSTREAMAPI.dbStatusandGET /api/v1/db/statusare unchanged.Test plan
/admin. Within ~3s, a per-vpath card should appear in the navbar with progress.scan_progressis cleared bytask-queue.js:onScanClose./api/v1/scan/progressdirectly as a non-admin user — should return rows for that user's vpaths only, withcurrentFilecontaining only basenames./api/v1/lastfm/test-login— should round-trip without axios installed.writeLogs: true, run for an hour, confirm a newmstream-YYYY-MM-DD-HH.logfile rolls over.🤖 Generated with Claude Code