Commit Graph
62 Commits
Author SHA1 Message Date
yonlu 8096b28d17 feat: MBIDs in library models + local-first search + explore cache
Backend:
- Added mbid column to sqlc schemas for artists and release_groups
- Regenerated sqlc queries to SELECT mbid in artist/album queries
- Added MBID field to library.Artist and library.Album Go structs
- All GetAllArtists/GetAllAlbums variants now populate MBID

Frontend:
- Updated Wails models.ts with MBID fields on Artist and Album
- Added cachedArtists/cachedAlbums getters to LibraryStore
- searchLibraryCache now includes MBIDs and local cover art URLs
  so library results can navigate to explore detail pages
- Added mergeWithLibrary() — when full MB results arrive, library
  entries are enriched with local images and 'In Library' flags
  rather than being replaced by MB-only versions
- Created ExploreCache store for cross-page data sharing: search
  results populate the cache, detail pages can read from it to
  avoid redundant API calls for already-fetched data
2026-03-29 18:54:22 -04:00
yonlu 19a803d1fc feat: multi-source artist images with thumbnails + grid integration
Complete rewrite of the artist image pipeline:

STORAGE:
- Migration 16: artist_images table tracking source, URL, path,
  primary flag, dimensions per image (up to 10 per artist)
- Directory structure: artist-images/{mbid[:2]}/{mbid}/ with
  primary.jpg + primary_sm.jpg/_md.jpg/_lg.jpg thumbnails
- Miss marker (.miss file) prevents re-fetching artists with no image

SOURCES (priority order):
1. MusicBrainz direct image relations (Wikimedia Commons)
2. Wikidata P18 property (Wikimedia Commons)
3. Wikipedia lead image (NEW — via Wikidata sitelinks → Wikipedia API)

Each source is checked, deduplicated, and the first available
image becomes the primary with sm/md/lg thumbnail generation
(100px/200px/400px, matching cover art tier sizes).

ASSET SERVING:
- /artist-images/ path registered with Wails asset handler
- Serves files via http.FileServer from the artist-images directory
- Same pattern as /covers/ for cover art

ARTIST MODEL:
- Artist struct gains ImageSmall/ImageMedium/ImageLarge fields
- resolveArtistImages does bulk MBID lookup → disk stat for each
- Populated in GetAllArtists and GetAllArtistsByLibrary

GRID VIEW:
- artists-view uses model URLs directly (no more base64 data URLs)
- Size selection based on imageSize * devicePixelRatio (like cover-grid)
- Removed batch GetArtistImages call and in-memory cache — no longer needed
2026-03-29 08:33:32 -04:00
yonlu 7f0c6d362a feat: personalized search ranking — library > similar > neither
Migration 15: add in_library and is_similar INTEGER columns to
explore_index. Backfills in_library from existing library MBIDs.

Search index FTS5 query now includes personalization in scoring:
  ORDER BY bm25(...) - (ln(pop+1) * 1.5)
           - (in_library * 3.0) - (is_similar * 1.5)

For equal text+popularity scores:
  - Library artist beats unrelated by 3.0 points
  - Similar artist beats unrelated by 1.5 points
  - Library > Similar > Neither

Tier 3 (library) entries get in_library=1 via markInLibrary.
Tier 4 (similar) entries get is_similar=1 via markSimilar.

MB result reranking (boostWithIndexPopularity) adds a 10M
popularity bonus for library artists, ensuring they always
rank above non-library artists with equal text relevance.
2026-03-28 12:50:57 -04:00
yonlu 54b074eae7 feat: artist aliases in FTS5 index + BM25 blended scoring
Migration 14: add aliases TEXT column to explore_index, rebuild FTS5
with 3 columns (title, artist_name, aliases), recreate sync triggers.
Clears index build timestamps to force alias population on next build.

Artist image provider fetches inc=url-rels+aliases (single call, no
extra cost). GetAliases() extracts alias names from cached MB rels.
indexOneArtist stores aliases as space-separated text after image
resolution populates the cache.

Search query now uses BM25 blended scoring:
  ORDER BY bm25(fts, 3.0, 1.0, 0.5) - (ln(popularity+1) * 0.5)

Column weights: title=3.0, artist_name=1.0, aliases=0.5
- Title matches score 3x higher than artist name matches
- Alias matches are helpful but don't dominate
- Popularity is a log-scaled boost, not an override
- Exact title match on niche entity beats weak match on mega-popular

Enables: 'rhcp' → Red Hot Chili Peppers, 'gnr' → Guns N' Roses,
'sabbath' → Black Sabbath (once index build runs with aliases).
2026-03-28 09:46:54 -04:00
yonlu 8f6a4c6a8e feat: 'In Library' badges, artist images on local pages, MBID-based Tier 3
Three features wired together:

1. 'In Library' badges on explore search results:
   CheckLibraryMBIDs Wails binding batch-checks which search result
   MBIDs exist in the local library. Green badges render on matching
   artist cards and album cards.

2. Artist images on local artist-details page:
   Local artist pages now call GetArtistMBID(name) to resolve the
   MBID from tags, then GetArtistImageURL(mbid) to fetch the cached
   Wikimedia photo. Falls back to initial-letter avatar.

3. Tier 3 search index uses direct MBIDs from tags:
   buildTier3Library now reads artists.mbid column (from audio tags)
   for direct MBID matching, falling back to name matching for
   untagged artists. Eliminates false matches and catches artists
   that name matching misses.
2026-03-26 09:34:57 -04:00
yonlu 806de8fd45 feat: migration 13 — add MBID columns to artists, release_groups, recordings
Add nullable TEXT mbid column to artists, release_groups, and
recordings tables. Partial indexes on each (WHERE mbid IS NOT NULL)
for fast MBID lookups without bloating the index for rows without
MBIDs.

Enables linking local library entities to MusicBrainz/ListenBrainz
explore data, artist image sharing, and 'In Library' badges.
2026-03-26 09:17:55 -04:00
yonlu 57a07e96cb feat: migration 12 — explore_index + FTS5 search index schema
Add explore_index table (entity_type, mbid, title, artist_name,
artist_mbid, popularity, extra_json) with a unique index on
(entity_type, mbid). FTS5 virtual table explore_index_fts backed
by the content table with auto-sync triggers for insert/update/delete.
explore_index_meta table tracks build timestamps.
2026-03-25 09:35:35 -04:00
yonlu 8fc075c24a perf(S01/T01): Add token-bucket rate limiter (1 req/sec), SQLite respon…
- backend/explore/ratelimiter.go
- backend/explore/cache.go
- backend/database/sql/schemas/explore_cache.sql
- backend/database/database.go
2026-03-23 07:55:25 -04:00
yonlu c5b293d410 chore: update sqlcgen models with play_count/last_played fields
Auto-generated by sqlc from updated schema. Adds PlayCount/LastPlayed
to AudioFile and TrackMetadatum structs, and PlayHistory model.
2026-03-22 10:48:35 -04:00
yonlu 2db6e09aa3 fix: use sql.NullTime for last_played to handle NULL scan
COALESCE(last_played, '') returned empty string which can't scan into
time.Time. Removed COALESCE, use sql.NullTime instead. Format to string
only when Valid.
2026-03-21 15:40:34 -04:00
yonlu 2ee157a376 feat(M003/S03): play count column + data pipeline
Backend:
- GetAllTracksWithFullMetadata queries now select play_count and last_played
- mapTrackRow accepts and passes through PlayCount/LastPlayed
- PlayCount + LastPlayed added to library.Track struct
- sqlcgen Row types updated with new fields

Frontend:
- PlayCount + LastPlayed added to library.Track TypeScript model
- 'Plays' column added to track-list column definitions (60px, right-aligned, sortable)

Queries without play data (search, genre, album) pass 0/empty defaults.
2026-03-21 15:33:08 -04:00
yonlu 9bf2bbab2e feat(M003/S01): play history tracking — schema, migration, recording hook
Migration 10:
- play_history table (audio_file_id FK, played_at DATETIME, CASCADE delete)
- play_count + last_played columns on audio_files (denormalized)
- Recreated track_metadata VIEW with play_count and last_played columns

Play recording:
- queue.recordPlay() inserts play_history row + updates denormalized columns
- Called from OnPlaybackFinished after queue advance completes
- Mutex released before DB write to avoid MaxOpenConns(1) deadlock
- Natural finish only — skip/stop does not count

Tests:
- TestMigration10PlayHistory: schema, columns, VIEW, round-trip verification
- All 49 smart playlist + 15 service + existing DB tests still pass
2026-03-21 15:23:18 -04:00
yonlu 477b7ff6a2 feat(M002): smart playlists — rule engine, editor UI, sidebar integration
Recovered from orphaned worktree commits (complete-milestone failed to merge).

Backend:
- Migration 9: is_smart + smart_rules columns on playlists table
- smartplaylist package: parameterized WHERE clause builder, field whitelist, genre subquery
- playlist.Service: Create/Update/Evaluate/Preview/GetRules smart playlist methods
- 65 tests (49 rule engine + 15 service + 1 migration)

Frontend:
- yj-combobox: reusable typeable dropdown with keyboard nav, ARIA, blur-race fix
- smart-playlist-editor: row-based rule builder with live preview
- smart-playlist-details: evaluate, refresh, play, shuffle, edit rules
- Sidebar: filter icon, Smart badge, create button, routing
- Queue snapshot on play/shuffle
2026-03-21 12:53:00 -04:00
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