Multi-value genres for FLAC/Ogg/MP4, readable tinted and error text, no missing-track seeds #143
Merged
bvandeusen
merged 5 commits from 2026-10-07 23:53:09 -04:00
dev into main
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
37d3a5bcd3 |
fix(library): read every genre of FLAC, Ogg, Opus and MP4 files (#2500)
release / govulncheck (push) Successful in 50s
release / web (push) Successful in 2m3s
release / go (push) Successful in 2m18s
release / integration (push) Successful in 5m42s
release / android (push) Successful in 6m30s
release / Build signed APK (releases and dev) (push) Successful in 6m0s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m20s
release / Verify release artifacts (tag releases only) (push) Skipped
Vorbis comments repeat a field to give it several values (GENRE=Boom Bap, GENRE=Downtempo, ...). dhowden/tag keeps comments in a map keyed by field name, so each repeat overwrote the previous one and only the last genre was stored. MP4 has the same gap: several data atoms in one ©gen atom, or repeated ©gen atoms, collapse to one value. On the operator's library 3,658 of 4,092 FLACs declare more than one genre. Kupla's Life Forms carries eight and was stored as "Instrumental Hip Hop" alone, so browse and the taste profile never saw the other seven. - vorbisgenre.go reads the comment block directly: FLAC's metadata block (including FLACs behind an ID3v2 tag), and the comment packet of Ogg Vorbis and Opus, reassembled across pages when cover art makes it span several. - mp4genre.go walks moov > udta > meta > ilst and returns every ©gen text value. It handles ISO and QuickTime meta layouts and a moov placed after mdat. A file with only the numeric gnre atom still falls back to dhowden, which resolves it. - extractGenres routes VORBIS and MP4 through them, as #2499 did for ID3v2. - tagReadVersion 3 -> 4, so the next scan re-reads the tags of files already indexed. Unchanged files keep their duration and fingerprint, so the pass costs tag reads only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
efa3bf54ce |
fix(playlists): a missing track never seeds For You or Songs-like (#2701)
release / govulncheck (push) Successful in 14s
release / web (push) Successful in 1m11s
release / go (push) Successful in 1m29s
release / integration (push) Successful in 4m27s
release / android (push) Successful in 5m2s
release / Build signed APK (releases and dev) (push) Successful in 5m17s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m15s
release / Verify release artifacts (tag releases only) (push) Skipped
PickTopPlayedTracksForUser's liked tier read general_likes without joining tracks. With no plays to seed from, For You could pick a liked track whose file is gone. The play tiers were already safe: their play_events join filters missing_since. The same gap was in PickTopPlayedTrackForArtistByUser's fallback, which seeds Songs-like from the artist's newest album when there are no recent plays. It could pick a missing track, and since #5296 a missing track is never fetched for similarity, so that seed has no edges either. The caller already skips an empty seed, so an artist whose tracks are all missing gets no Songs-like mix instead of one aimed at nothing. Integration tests cover both cases: a liked-but-missing track is not a seed, and the Songs-like fallback moves to the next album once the newest one's track goes missing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
743b6f5eac |
fix(web): error text uses error-fg on every surface, not only on tints (#3150)
release / govulncheck (push) Successful in 17s
release / web (push) Successful in 1m6s
release / go (push) Successful in 1m29s
release / integration (push) Successful in 4m30s
release / android (push) Successful in 5m18s
release / Build signed APK (releases and dev) (push) Successful in 5m32s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
Raw error red fails AA as text even with no tint behind it: in dark mode it measures 3.63:1 on obsidian, 3.23 on iron and 2.64 on slate, against 4.5. error-fg (the house formula, 50% toward parchment) measures 5.30 at worst across both modes. - All 19 text-error uses become text-error-fg: the "Couldn't load" messages on the admin pages, the integrations form errors, the flag popover, and the error toast's text. The toast keeps its error border, since a border is a graphic with a 3:1 floor. - check-tint-contrast flags raw error text anywhere (text-error, class:text-error, color: var(--fs-error)) and leaves borders and outlines alone. Run against the files before the swap, it finds all 19. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
fdee77eaec |
fix(web): text on a tint of its own hue uses the house -fg tokens (#3150)
release / govulncheck (push) Successful in 38s
release / integration (push) Successful in 5m1s
release / Build + push container image (push) Successful in 1m17s
release / Verify release artifacts (tag releases only) (push) Skipped
release / web (push) Successful in 1m22s
release / go (push) Successful in 1m48s
release / android (push) Successful in 5m41s
release / Build signed APK (releases and dev) (push) Successful in 5m11s
release / Attach APK to the Release (tag releases only) (push) Skipped
A hue painted as text on a color-mix tint of itself sits close to the surface under it. On Minstrel's surfaces the raw accent on its 15% tint measures 1.97:1 at worst (dark mode, hover surface), against AA's 4.5. - tokens.json gains colors.fg: the five FabledSword -fg formulas (accent 45%, success 45%, warning, error and info 50%), each mixed toward parchment so one declaration serves both modes. Success is Minstrel's moss. tokens-to-css emits them in :root. - Tailwind exposes them as text-accent-fg, text-warning-fg, text-error-fg and text-info-fg. - 23 sites swapped: 14 Tailwind class strings (PlayerBar and the admin count pills) and 9 CSS rules (StatusPill's four tones and five accent chips). Worst case after: accent-fg 5.03, error-fg 4.75, warning-fg 4.92, success-fg 4.85. - scripts/check-tint-contrast.js finds the pair in either spelling. Its test scans src in the web Vitest lane and fails on any new site, with fixture cases showing it can fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c17f4273c6 |
test(web): stub SvelteKit app modules suite-wide so no test loads the client runtime (#3943)
release / govulncheck (push) Successful in 32s
release / web (push) Successful in 1m25s
release / go (push) Successful in 1m41s
release / integration (push) Successful in 4m55s
release / android (push) Successful in 6m15s
release / Build signed APK (releases and dev) (push) Successful in 6m42s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 2m4s
The home page reaches the real $app/navigation through AlbumCard and AlbumMenu. That loads SvelteKit's client runtime, whose $app/paths reads __SVELTEKIT_PAYLOAD__ at module load. The global is only there when the kit plugin's define reaches the module, and under vitest that is not reliable: page.test.ts failed to load on CI run 6576 and passed on its re-run. #374 was the same class of failure. vitest.setup.ts now mocks $app/navigation, $app/state and $app/paths for every test. Per-file mocks still win. A small guard test fails if the suite-wide mocks are removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |