Commit Graph

20 Commits

Author SHA1 Message Date
zarzet b8b670642c feat(audio): add WAV and AIFF support + settings-style metadata menu
WAV/AIFF: library scan, quality probe, native tag read/write via embedded ID3 chunk (RIFF id3 / AIFF ID3), cover art, ReadFileMetadata, ExtractLyrics, and FLAC<->WAV/AIFF conversion (PCM, bit-depth preserved via ffprobe). Treat WAV/AIFF as lossless across all convert sheets (no bitrate picker, Lossless labels) via isLosslessConversionTarget. Native MIME maps for SAF. Redesign the track metadata three-dot menu to a settings-style grouped card with a single divider above Share.
2026-06-12 21:10:37 +07:00
zarzet ce4be0ba97 feat: enrich composer and track totals metadata 2026-04-13 23:32:17 +07:00
zarzet f37e4704a6 feat: add ReplayGain scanning, APEv2 tag support, and fix metadata bugs
ReplayGain (track + album):
- Scan track loudness via FFmpeg ebur128 filter (-18 LUFS reference)
- Duration-weighted power-mean for album gain computation
- Support for FLAC (native Vorbis), MP3 (ID3v2 TXXX), Opus, M4A
- Album RG auto-finalizes when all album tracks complete
- Retryable gate: blocks finalization while failed/skipped items exist
- SAF support: lossy album RG writes via temp file + writeTempToSaf
- New embedReplayGain setting (off by default) with UI toggle

APEv2 tag support:
- Full APEv2 reader/writer with header+items+footer format
- Merge-based editing with override keys for explicit deletions
- Binary cover art embedding (Cover Art (Front) item)
- Library scanner support for .ape/.wv/.mpc files
- ReplayGain fields in APE read/write/edit pipeline

Bug fixes (26):
- setArtistComments wiping fields on empty string value
- APEv2 rewrite corrupting files with ID3v1 trailer
- APE edit replacing entire tag instead of merging
- ReplayGain lost on manual MP3/Opus/M4A metadata edit
- Editor metadata save losing custom tags (preserveMetadata)
- Album RG accumulator not cleaned on queue mutation
- Album gain using unweighted mean instead of power-mean
- writeAlbumReplayGainTags return value silently ignored
- SAF album RG writing to deleted temp path
- Cancelled tracks polluting album gain computation
- APE ReplayGain not wired end-to-end
- APE field deletion not working in merge
- APE cover edit was a no-op
- Album RG duplicate entries on retry
- APE apeKeysFromFields missing track/disc/lyrics mappings
- Album RG entries purged by removeItem before computation
- FFmpeg converters discarding empty metadata values
- _appendVorbisArtistEntries skipping empty value (null vs empty)
- Album RG write-back fails for SAF lossy files
- Album RG partial finalization on failed tracks
- FLAC ClearEmpty flag destroying tags on partial callers
- clearCompleted not retriggering album RG checks
- ReadFileMetadata MP3/Ogg missing label and copyright
- Cover embed on CUE split destroying split artist tags
- Album RG gain format inconsistent (missing + prefix)
- FLAC reader/editor missing tag aliases (ALBUMARTIST, LABEL, etc.)
- dart:math log shadowed by logger.dart export
2026-04-13 23:32:14 +07:00
zarzet d034144e9c feat: add resolve API with SongLink fallback, fix multi-artist tags (#288), and cleanup
Resolve API (api.zarz.moe):
- Refactor songlink.go: Spotify URLs use resolve API, non-Spotify uses SongLink API
- Add SongLink fallback when resolve API fails for Spotify (two-layer resilience)
- Remove dead code: page parser, XOR-obfuscated keys, legacy helpers

Multi-artist tag fix (#288):
- Add RewriteSplitArtistTags() in Go to rewrite ARTIST/ALBUMARTIST as split Vorbis comments
- Wire method channel handler in Android (MainActivity.kt) and iOS (AppDelegate.swift)
- Add PlatformBridge.rewriteSplitArtistTags() in Dart
- Call native FLAC rewriter after FFmpeg embed when split_vorbis mode is active
- Extract deezerTrackArtistDisplay() helper to use Contributors in album/playlist tracks

Code cleanup:
- Remove unused imports, dead code, and redundant comments across Go and Dart
- Fix build: remove stale getQobuzDebugKey() reference in deezer_download.go
2026-04-13 23:32:14 +07:00
zarzet 120ecaa0e5 feat: add artist tag mode setting with split Vorbis support and improve library scan progress
- Add artist_tag_mode setting (joined / split_vorbis) for FLAC/Opus multi-artist tags
- Split 'Artist A, Artist B' into separate ARTIST= Vorbis comments when split mode is enabled
- Join repeated ARTIST/ALBUMARTIST Vorbis comments when reading metadata
- Propagate artistTagMode through download pipeline, re-enrich, and metadata editor
- Improve library scan progress: separate polling intervals, finalizing state, indeterminate progress
- Add initial progress snapshot on library scan stream connect
- Use req.ArtistName consistently for Qobuz downloads instead of track.Performer.Name
- Add l10n keys for artist tag mode, library files unit, and scan finalizing status
2026-04-13 23:32:12 +07:00
zarzet fd3a34303e feat: add stable cover cache keys, Qobuz album-search fallback, metadata filters and extended sort options
- Introduce coverCacheKey parameter through Go backend and Kotlin bridge for stable SAF cover caching
- Add MetadataFromFilename flag to skip filename-only metadata and retry via temp-file copy
- Add Qobuz album-search fallback between API search and store scraping
- Extract buildReEnrichFFmpegMetadata to skip empty metadata fields
- Add metadata completeness filter (complete, missing year/genre/album artist)
- Add sort modes: artist, album, release date, genre (asc/desc)
- Prune stale library cover cache files after full scan
- Skip empty values and zero track/disc numbers in FFmpeg metadata
- Add new l10n keys for metadata filter and sort options
2026-04-13 23:32:12 +07:00
zarzet 091e3fadd9 feat: add audio quality analysis widget and fix USLT lyrics detection 2026-03-26 01:11:29 +07:00
zarzet c57c8a4267 feat: implement full M4A tag read engine with atom path fallback and freeform fix
Add ReadM4ATags() that parses all standard iTunes atoms (title, artist,
album, album artist, date, genre, composer, comment, copyright, lyrics,
track/disc number) and freeform '----' atoms (ISRC, label, lyrics).

Fix two pre-existing bugs in the M4A atom traversal:
- findM4AIlstAtom: now tries moov>udta>meta>ilst first, then falls back
  to moov>meta>ilst so files from Tidal/Qobuz/Apple Music are handled
- readM4AFreeformValue: 'name' atom payload is raw UTF-8 after 4-byte
  flags, not a nested 'data' atom; fix reads it directly so ISRC/label
  freeform tags are no longer silently dropped

Refactor extractLyricsFromM4A and extractCoverFromM4A to reuse the new
helpers (findM4AIlstAtom, readM4ADataAtomPayload) instead of duplicating
the atom traversal logic. Add extractAnyCoverArtWithHint M4A case that
previously returned a hardcoded 'not yet supported' error.
2026-03-22 23:00:42 +07:00
zarzet f1eef47600 refactor: optimize SAF metadata reading, CUE sibling resolution, and startup initialization
- Add fast-path SAF metadata reading via /proc/self/fd with displayNameHint support, falling back to temp copy
- Replace repeated findFile() CUE audio sibling lookups with cached case-insensitive directory listing
- Cache parsed CUE sheets to avoid redundant parsing during library scans
- Optimize incremental scan CUE modTime lookup from O(N*M) to O(N+M)
- Defer local library provider loading until localLibraryEnabled setting is true
- Replace O(n) track+artist history lookup with O(1) map-based lookup
- Delay startup maintenance tasks by 2s to reduce launch-time contention
2026-03-12 03:36:48 +07:00
zarzet 7d5cb574c6 feat: move Amazon Music to extension, fix Deezer download timeout 2026-03-08 04:15:28 +07:00
zarzet 4df96db809 feat: batch re-enrich for local tracks, SAF FD refactor, Ogg quality fix
- Replace batch Share action with batch Re-enrich in local album selection bar
  - Full native/FFmpeg re-enrich flow with SAF write-back support
  - Triggers incremental local library scan after completion to refresh metadata
- Queue tab: switch first selection action to Re-enrich when all selected items are local-only
- Refactor SAF FD handoff in MainActivity: drop detachFd/dup pattern, pass procfs
  path to Go and let Go re-open it to avoid fdsan double-close race conditions
- Handle /proc/self/fd/ path in output_fd.go: re-open via O_WRONLY|O_TRUNC instead
  of taking raw FD ownership
- Fix Ogg duration/bitrate calculation in audio_metadata.go:
  - Use float64 arithmetic and math.Round for accurate duration
  - Compute bitrate from file size / float duration at the source
  - Validate Ogg page header fields (version, headerType, segment table) to avoid
    false positives from payload bytes during backward scan
  - Guard against corrupted granule values (>24h duration, <8kbps bitrate)
- Rename trackReEnrich label from 'Re-enrich Metadata' to 'Re-enrich' across all
  13 locales and ARB files
- Update CHANGELOG.md with 3.7.0 entry
2026-02-18 19:29:59 +07:00
zarzet a1d1ab1f0f fix: preserve extended metadata during fallback, accurate lossy quality display, SAF improvements
- Add Genre/Label/Copyright fields to DownloadResult struct
- buildDownloadSuccessResponse now prefers service result metadata over request
- enrichRequestExtendedMetadata fetches Deezer metadata by ISRC before download
- Flutter sends copyright in download request payload
- History merge preserves existing genre/label/copyright on re-download
- Accurate MP3 duration via Xing/VBRI VBR headers, MPEG2/2.5 bitrate tables
- Accurate Opus/Vorbis duration via last Ogg page granule position
- Bitrate field added to LibraryScanResult, LocalLibraryItem, DB v4 migration
- Lossy formats display format+bitrate instead of fake 16-bit quality
- Local library file date uses fileModTime instead of scannedAt
- SAF URI recovery for transient FD paths after download
- Improved SAF repair and download history path matching in library scan
- Extract quality probe logic into reusable enrichResultQualityFromFile
2026-02-12 00:19:02 +07:00
zarzet 68e6c8be35 ui: improve cover preview in edit metadata sheet and user changes
- Cover preview enlarged from 120x120 to 160x160 with shadow and better styling
- Layout changed from Wrap to Row with Expanded for side-by-side covers
- Label moved below image with labelMedium typography
- Cover editor section moved to top of edit form
- Added embedded cover preview cache with LRU eviction in metadata screen
- Added current cover extraction and preview in edit metadata sheet
- Added metadata sync to download history after edits
- Added embedded cover extraction cache in queue tab for downloaded items
- Added SAF mod-time tracking for cover refresh after metadata changes
2026-02-11 01:13:24 +07:00
zarzet fe1c96ea12 v3.6.5: audio format conversion, PC v7.0.8 backend merge, Amazon re-enabled 2026-02-10 23:35:41 +07:00
zarzet df39d61ed4 feat: save cover art, save lyrics, re-enrich metadata with full SAF support + YouTube Cobalt provider with SpotubeDL fallback + metadata summary logging 2026-02-09 23:07:18 +07:00
zarzet c6ee9cda35 fix: resolve Go staticcheck warnings in audio_metadata.go and qobuz.go 2026-02-07 11:58:46 +07:00
zarzet 7c08321ce3 refactor: continue code cleanup 2026-02-04 10:42:51 +07:00
zarzet e20becdca7 refactor: remove more redundant comments 2026-02-04 10:20:04 +07:00
zarzet 24897e25e2 refactor: clean up redundant comments and code 2026-02-04 10:05:32 +07:00
zarzet 72d45746a5 feat: add local library albums to Albums tab with unified grid and LocalAlbumScreen
- Add local library albums as clickable cards in Albums filter
- Merge downloaded and local albums into single unified grid (fix layout gaps)
- Create LocalAlbumScreen for viewing local album details with:
  - Cover art display with dominant color extraction
  - Album info card with Local badge and quality info
  - Track list with disc grouping support
  - Selection mode with delete functionality
  - UI consistent with DownloadedAlbumScreen (Card + ListTile layout)
- Add singles filter support for local library singles
- Add extractDominantColorFromFile to PaletteService
- Add delete(id) method to LibraryDatabase
- Add removeItem(id) method to LocalLibraryNotifier
- Update CHANGELOG.md for v3.4.0
2026-02-03 21:51:40 +07:00