Commit Graph
49 Commits
Author SHA1 Message Date
yonlu 3642cbe0d5 feat(16-02): add go-flac dependencies and implement FLAC tag writer
- Add go-flac/go-flac/v2, flacvorbis/v2, flacpicture/v2 dependencies
- Create tagwriter.go with TagChanges type, field constants, format detection, MIME detection
- Create flac.go with writeFlacTags using Vorbis Comments + PICTURE blocks + AtomicWrite
- Implement replaceVorbisComment helper for case-insensitive field replacement
- Handle cover art add/replace/clear via PICTURE metadata blocks
2026-03-17 10:32:28 -04:00
yonlu 56cd7e38a5 test(15-01): add FTS5 row deletion and update cycle tests
- TestDeleteSearchIndex: table-driven test for delete existing/non-existent rowid
- TestSearchIndexUpdateCycle: verifies delete+reinsert produces no ghost entries
- TestClearSearchIndexPreservesSchema: verifies drop/recreate preserves contentless_delete=1
- Update TestInsertAndDeleteSearchIndex to expect successful delete
2026-03-16 18:12:06 -04:00
yonlu cb5155b890 feat(15-01): migrate FTS5 search_index to contentless_delete=1
- Add contentless_delete=1 to search_index.sql schema file
- Update ClearSearchIndex CREATE statement to match schema
- Replace DeleteSearchIndex no-op with real DELETE WHERE rowid
- Add migration 8: drop/recreate/repopulate FTS5 table
- Update library.go comment about FTS entry lifecycle
2026-03-16 18:10:57 -04:00
yonlu 93262b9ae0 fix(13-02): auto-resolve phantom playlist tracks after library scan
- Add phantom_file_path column to playlist_tracks (migration 7)
- Store original file_path during RemoveLibrary phantom metadata population
- After each successful scan, UPDATE phantom tracks whose phantom_file_path
  now matches an audio_files row, re-linking them and clearing phantom metadata
- Update schema file, sqlc generated code, and database test for new column
2026-03-16 12:29:06 -04:00
yonlu 5f7de5060a feat(13-01): add library-filtered Go query methods and FTS search
- GetAllTracksByLibrary, GetAllAlbumsByLibrary, GetAllArtistsByLibrary
- GetAlbumsByArtistByLibrary, GetAllGenresWithCountsByLibrary
- GetTracksByGenreByLibrary, GetAlbumTracksByLibrary
- SearchTracksByLibrary wraps SearchFTSTracksByLibrary on DB
- SearchFTSTracksByLibrary filters FTS results by library_id
2026-03-16 09:29:08 -04:00
yonlu 5cc58ce66a feat(13-01): add library-filtered sqlc queries for all browse views
- GetAllTracksWithFullMetadataByLibrary for tracks filtered by library
- GetAudioFilesByReleaseGroupByLibrary for album tracks in a library
- GetAllAlbumsWithDetailsByLibrary for albums with tracks in a library
- GetAlbumsByArtistByLibrary for artist albums in a library
- GetAlbumArtistsByLibrary for artists with albums in a library
- GetAllGenresWithCountsByLibrary for genre counts within a library
- GetTracksByGenreByLibrary for genre tracks within a library
2026-03-16 09:26:42 -04:00
yonlu 943db1cf27 feat(11-01): per-library scan pipeline with queue coordinator
Task 1: Schema, events, and progress types
- Add library_id to CreateAudioFile SQL INSERT and regenerate sqlc code
- Add LibraryScanQueued and LibraryScanQueueDrained event constants
- Regenerate TypeScript events via genevents
- Add LibraryID, LibraryName, QueuedCount to ScanProgress
- Add LibraryID, LibraryName to ScanMetrics
- Add libraryID field to importResult for threading through pipeline

Task 2: Scan queue coordinator and per-library scanning
- Create scan_queue.go with ScanLibrary(id), ScanAllLibraries()
- Add CancelCurrentScan(), CancelAllScans() for queue-aware cancellation
- FIFO scan queue with silent dedup (same library already scanning or queued)
- Refactor Scan() -> scanInternal(libraryID, libraryName, libraryPath)
- Replace GetAllAudioFiles with GetAudioFilesByLibrary for per-library loading
- Thread libraryID through DB writer to set CreateAudioFileParams.LibraryID
- drainQueue auto-starts next queued library or emits LibraryScanQueueDrained
- Pause freezes current scan AND queue
- Add GetScanQueueLength() and QueuedLibraryNames() for UI
- Mark CancelScan() and Scan() as deprecated
2026-03-09 16:02:54 -04:00
yonlu 75b2a349eb fix(10-01): move library_id index to migration 6 to fix existing DB startup
On existing databases, CREATE TABLE IF NOT EXISTS audio_files is a no-op
but the standalone CREATE INDEX on library_id would fail because the
column doesn't exist until migration 6 runs. The migration already
creates this index, so removing it from the schema file is correct.
2026-03-09 10:48:11 -04:00
yonlu bc151891b5 feat(10-02): add migration 6 integration tests and NewTestDBWithLibrary helper
- Add NewTestDBWithLibrary helper for tests needing a pre-created library
- TestMigration6FreshDB: verify all tables, columns, phantom cols, VIEW, and user_version
- TestMigration6LibraryQueries: verify CRUD operations and unique path constraint
- TestMigration6PhantomPlaylistTracks: verify SET NULL FK preserves phantom metadata
- TestMigration6AudioFilesLibraryFK: verify FK enforcement on library_id
- TestMigration6TrackMetadataViewHasLibraryID: verify VIEW includes library_id
2026-03-09 09:50:14 -04:00
yonlu 02548dd55e feat(10-02): add sqlc queries for libraries and update playlist queries for phantom support
- Create libraries.sql with 7 CRUD queries (create, get, get-by-path, list, update, delete, count)
- Update playlists.sql: AddPlaylistTrack now accepts 9 params including phantom metadata
- Update playlist queries to use LEFT JOIN for nullable audio_file_id
- Add GetTrackPhantomMetadata helper query for eager phantom population
- Add is_phantom computed column to metadata queries
- Add GetAudioFilesByLibrary and CountAudioFilesByLibrary queries
- Regenerate all sqlc code
2026-03-09 09:47:30 -04:00
yonlu 1179f56c36 feat(10-01): implement migration 6 and pre-migration backup
- Add backupDatabase() for timestamped .db file backup before migration
- Add migration6MultiLibrary() with all 14 steps: FK OFF, create libraries table,
  insert default library from TOML config, add library_id to audio_files, rebuild
  playlist_tracks with SET NULL FK and 6 phantom columns, backfill phantom metadata,
  recreate track_metadata VIEW with library_id, FK ON, clean TOML config
- Add readLibraryDirFromTOML() and removeLibraryDirFromTOML() helpers
- Update runMigrations signature to accept dbPath for backup
- Add sentinel library row in NewTestDB for FK constraint satisfaction
2026-03-09 09:41:08 -04:00
yonlu 535855b383 feat(10-01): update SQL schema files for multi-library fresh installs
- Create _libraries.sql with libraries table (name, path, created_at)
- Add library_id FK column and index to audio_files.sql
- Update playlist_tracks.sql with nullable audio_file_id, SET NULL FK, and 6 phantom columns
- Add af.library_id to track_metadata VIEW
- Regenerate sqlc code for updated schemas
- Fix playlist.go to use sql.NullInt64 for nullable audio_file_id
2026-03-09 09:36:47 -04:00
yonlu e1a95e65a9 fix(quick-13): resolve lint issues in main source files
- Fix errcheck for db.Close() in testhelper.go
- Fix errcheck, nlreturn, wsl, gofumpt issues in genevents/main.go
- Fix gofumpt and wsl issues in library.go
2026-03-05 14:07:50 -05:00
yonlu 97f256d67f fix: include full track metadata in GetAudioFilesByReleaseGroup query
The GetAudioFilesByReleaseGroup SQL query only selected 6 columns,
missing audio properties (sample_rate, bit_depth, channels, bitrate,
file_size) and metadata (album, genre, year, composer, file_type).
This caused track details opened from the album view to show dashes
instead of actual values. Expanded the query to match
GetAllTracksWithFullMetadata and updated GetAlbumTracks to use the
shared mapTrackRow helper.
2026-03-05 13:34:03 -05:00
yonlu 8e9a616037 fix: drop+recreate contentless FTS5 index instead of DELETE
The search_index is a contentless FTS5 table (content=''), which
SQLite does not support DELETE on. ClearSearchIndex now drops and
recreates the virtual table. Single-row DeleteSearchIndex becomes
a no-op since contentless FTS5 also cannot delete individual rows;
stale entries are harmless (search JOINs filter them out) and the
index is fully rebuilt during FullRescan.
2026-03-05 10:41:55 -05:00
yonlu d43ba7bd0c fix(quick-10): add migration 5 and fix entity cache for composite album key
- Migration 5 rebuilds release_groups with UNIQUE(name, album_artist_credit_id)
- Drops and recreates track_metadata VIEW during table rebuild
- Temporarily disables FK checks for safe table rebuild
- Entity cache now keys by album name + artist credit ID
- Update tests to use composite cache keys
2026-03-05 10:25:53 -05:00
yonlu 999ab967be fix(quick-10): update release_groups schema and queries for composite uniqueness
- Change UNIQUE(name) to UNIQUE(name, album_artist_credit_id) in schema
- Update UpsertReleaseGroup ON CONFLICT to match composite key
- Rename GetReleaseGroupByName to GetReleaseGroupByNameAndArtist with two params
- Regenerate sqlc code
2026-03-05 10:23:25 -05:00
yonlu 7dfe003e63 docs(06-03): add SAFETY comments to all 12 hand-crafted SQL statements
- 7 SAFETY comments in search.go (FTS5 MATCH/INSERT/DELETE operations)
- 3 SAFETY comments in library.go (FTS5 INSERT/DELETE in commitNewAudioFile, updateAudioFileMetadata)
- 1 SAFETY comment in rescan.go (FTS5 DELETE in clearAllLibraryData)
- 1 SAFETY comment in persistence.go (variable-count multi-row INSERT)
- Cross-references link library.go/rescan.go back to search.go
- Two-part format: why sqlc can't handle it + what makes it safe
2026-03-04 19:33:55 -05:00
yonlu 2221a68459 feat(06-03): migrate lookupChunk to sqlc-generated LookupTrackMetaByPaths query
- Add LookupTrackMetaByPaths sqlc query using track_metadata VIEW with sqlc.slice()
- Replace hand-crafted fmt.Sprintf IN clause in lookupChunk with sqlc-generated call
- Preserve lookupTrackMetaBatch chunking at maxSQLiteVars (900)
- All queue tests pass with -race
2026-03-04 19:31:52 -05:00
yonlu 9159b409dc refactor(06-01): consolidate search queries to use track_metadata VIEW
- SearchFTS uses JOIN track_metadata instead of 5-table inline JOIN
- SearchFTSByFilename uses JOIN track_metadata instead of 5-table inline JOIN
- SearchFTSTracks uses JOIN track_metadata instead of 6-table inline JOIN
- RebuildSearchIndex selects from track_metadata instead of inline JOIN
- All 15 database tests pass with -race
2026-03-04 19:23:11 -05:00
yonlu 9c7e5a9634 feat(06-01): create track_metadata VIEW schema and migration 4
- Add track_metadata_view.sql for sqlc VIEW awareness
- Add migration4TrackMetadataView for existing databases
- sqlc generate produces TrackMetadatum model from VIEW
- migration2 inline JOIN preserved (runs before VIEW exists)
2026-03-04 19:21:58 -05:00
yonlu dd34569ac0 test(05-01): add FTS5 search tests for database package
- seedSearchData helper creates full entity graph (7 tracks, 4 artists, 7 albums)
- Pure helper tests: tokeniseForFTS, buildFTSQuery, stripExtForSearch
- FTS5 search tests: basic term, empty query, special characters (AC/DC),
  multi-word, diacritics (Beyonce→Beyoncé), ranking, filename search
- SearchFTSTracks verifies all 16 columns populated
- Index ops: insert, delete (documents contentless FTS5 limitation),
  rebuild, clear (documents contentless limitation)
- Migration test: user_version >= 3, UNIQUE index enforcement
- 15 tests, all passing with -race
2026-03-04 16:43:06 -05:00
yonlu bae9d70d23 feat(03-01): create NewTestDB helper for in-memory SQLite test databases
- Add testhelper.go with exported NewTestDB(t *testing.T) *DB
- Opens :memory: SQLite with same connection params as production
- Shares applyPRAGMAs, schema application loop, and runMigrations
- Registers t.Cleanup for automatic DB close
- No orphan cleanup, no functional options, no error return
2026-03-02 22:05:39 -05:00
yonlu d34881530a feat(03-01): extract shared applyPRAGMAs and add production PRAGMAs to NewDB
- Extract inline foreign_keys PRAGMA into shared applyPRAGMAs function
- Add synchronous=NORMAL, cache_size=-8000, mmap_size=67108864 PRAGMAs
- NewDB now calls applyPRAGMAs instead of inline PRAGMA exec
- applyPRAGMAs will be reused by NewTestDB for production-mirroring tests
2026-03-02 22:04:49 -05:00
yonlu 2a86408201 fix(02-01): eliminate package-level startupErr and fix config file permissions
- Move startupErr from package-level var to YellowJacketApp struct field
- Update OnStartup and OnDomReady to reference yj.startupErr
- Change config.Save() file permissions from 0o666 to 0o644
- Fix nlreturn lint in database/errors.go (pre-existing, blocking commit hook)
2026-03-02 18:39:15 -05:00
yonlu 04b2088b28 feat(quick-002): add CountPlaylistsByName SQL query and regenerate sqlc
- Add CountPlaylistsByName :one query to playlists.sql
- Regenerate sqlc to produce Go function
2026-02-28 13:52:21 -05:00
yonlu d01f5e5d14 added "default playlist"/ favorites system 2026-02-25 22:53:57 -05:00
yonlu d5010e6fa8 default user volume is 50 now 2026-02-25 19:32:44 -05:00
yonlu e192d4625e playlist phantom track matching added, updated search queries for efficiency 2026-02-24 21:23:25 -05:00
yonlu 16060023bb audio file info added, fixed right click selecting. 2026-02-23 19:05:57 -05:00
yonlu 9dabfb81c5 beginnings of artist grid and artist details view 2026-02-22 19:17:27 -05:00
yonlu 9cb1c6674a changed genre scanning to parse multiple genres, updated db to accommodate. 2026-02-22 13:59:28 -05:00
yonlu b5e70a8ce6 user can configure visible columns in track-list 2026-02-22 11:24:19 -05:00
yonlu 9d84a11543 drag and drop enhancements, fixed playlist creation using old db entries, added icons-only sidebar when small width 2026-02-21 14:16:37 -05:00
logan 2a3a79652c add dev-only profiling with pprof, runtime/trace, and operation timing
Wire up Go's standard profiling toolkit so it's automatically available
in dev builds and completely absent from production. The profiling
package uses build tags (dev/!dev) to eliminate all pprof, trace, and
timing code from release binaries with zero new dependencies.

- backend/profiling: pprof HTTP server on :6060, /debug/trace endpoint,
  block/mutex profiling, and TimeOp helper for structured operation timing
- scripts/profile.sh: interactive menu-driven script that auto-selects
  free ports (8080-8089) so multiple profiles can be open simultaneously
- Instrumented key operations: app init, database init, player load/restore,
  queue set/restore
- Makefile targets: profile, profile-cpu, profile-heap, profile-trace
- .gitignore: exclude trace-*.out and *.pprof artifacts
2026-02-20 18:27:25 -06:00
yonlu 81793975b4 improved library scan speeds, added library manager component
-libraries tab now opens a library manager
-choose library directory, manually soft scan and rescan
-batched db queues
-mp3 header-based duration extraction
2026-02-19 10:17:09 -05:00
yonlu be6f4e9764 virtualization in queue list, queue db queries optimized for large queue requests 2026-02-17 19:54:24 -05:00
yonlu 50718fd633 added db query optimizations to playlists view, added caching 2026-02-17 11:39:17 -05:00
yonlu 176b32fb0d frontend fixes
album artist gets populated with artist as fallback (frontend also uses
this as display name fallback for albums). added scroll position
persistence when switching main views. also added frontend cache for
faster switching.
2026-02-16 14:38:09 -05:00
yonlu 95e1b32e86 view tracks in playlist view and play playlists 2026-02-16 02:18:45 -05:00
yonlu 4c09e7abee playlist creation, viewing, integration with other views. still wip for full playlist functionality 2026-02-16 00:27:36 -05:00
yonlu 67cea5cfb0 fixed player behavior after final queue track completes, added click to play from queue window 2026-02-15 16:20:56 -05:00
yonlu 7579a768be fix: virtual list and cover grid (#63)
* very basic slow buggy queue

* cover grid can now add albums to queue

* added virtualized lists to track list and cover grid components
2026-02-14 14:07:25 -06:00
logan 30b2480df4 fix: resolve all lint errors and make linting a required CI check (#62)
- Fix 10 err113 violations: extract dynamic errors to package-level sentinels
- Fix 12 errcheck violations: handle unchecked error returns in player,
  metadata, and config packages
- Fix 4 revive stutter warnings: rename player.PlayerState to player.State,
  player.PlayerVolume to player.Volume, queue.QueueTrack to queue.Track,
  queue.QueueState to queue.State
- Fix 2 staticcheck SA4001: simplify *&x to x in assets handler
- Fix 5 unused constants: remove dead AudioFileType iota block in models
- Fix gci/gofumpt/wsl formatting issues across multiple files
- Add gofumpt module-path setting to .golangci.yml for correct import grouping
- Fix player test: gate integration test behind YELLOWJACKET_INTEGRATION env var
  instead of only skipping in CI, and replace t.Errorf+t.Failed with t.Fatalf
- Remove continue-on-error from golangci-lint CI step so linting is now required
2026-02-14 01:52:27 -06:00
loganandonion-4-dinner f521045540 chore(deps): update go dependencies (non-major) (#40)
* chore(deps): update go dependencies (non-major)

* fix: regenerate code and add postUpgradeTasks for Renovate

Regenerate templ and sqlc output to match bumped tool versions.
Configure Renovate postUpgradeTasks to run 'go generate ./...' after
Go dependency updates, preventing stale generated files in future PRs.

---------

Co-authored-by: onion-4-dinner <15676555+onion-4-dinner@users.noreply.github.com>
2026-02-14 01:17:59 -06:00
logan 672fe24ee9 fix: use path.Join for embed.FS paths to fix Windows build
filepath.Join uses OS-specific separators (backslash on Windows), but
embed.FS always uses forward slashes. This caused schema file lookups
to fail during Wails binding generation on Windows.
2026-02-13 23:16:57 -06:00
logan d78c0584e2 Squash merge audio-player-component into main 2026-02-13 20:39:23 -06:00
logan b24e734ae3 Database basic CRUD (#27)
* started schema

* db schemas beginning

* first db schema gen

* added sqlc generation with go generate and sqlite driver

* i think these dependencies are needed

* added IF NOT EXISTS to create and CRUD for each table

* fixed missing columns

* added missing field

* fixed code generation with sqlc
2025-04-16 13:45:44 -05:00
logan 4e374fab54 added db pkg and sqlc config 2025-04-10 18:11:08 -05:00