- Add SearchAll() for Tidal and Qobuz in Go backend (tracks, artists, albums)
- Add searchTidalAll/searchQobuzAll platform routing for Android and iOS
- Add Tidal/Qobuz options to search provider dropdown in home tab
- Show (Recommended) label and auto-select service in download picker
Add FFmpegService.embedMetadataToM4a() for writing tags and cover art
into M4A files via FFmpeg. Fix two bugs in the same function:
- Remove '-disposition:v:0 attached_pic' which is only valid for
Matroska/WebM containers and causes FFmpeg to error on MP4/M4A
- Apply same fix to _convertToAlac which had the identical issue
Add M4A handling (isM4A branch) to all four embed call-sites:
track_metadata_screen (lyrics embed, re-enrich, edit metadata sheet,
format conversion), queue_tab, local_album_screen, and
downloaded_album_screen.
Add 'LYRICS'/'UNSYNCEDLYRICS' to _mapMetadataForTagEmbed so existing
lyrics survive a re-enrich cycle on M4A/MP3/Opus files.
Preserve existing lyrics before overwriting tags in the edit metadata
sheet (best-effort readFileMetadata before FFmpeg pass).
Extract mergePlatformMetadataForTagEmbed() into lyrics_metadata_helper
to deduplicate the identical metadata-mapping loops that existed in
queue_tab, local_album_screen, downloaded_album_screen, and
track_metadata_screen.
Wire ensureLyricsMetadataForConversion into the format conversion path
in track_metadata_screen so lyrics are carried through conversions.
Add ISRC and LABEL/ORGANIZATION mappings to _convertToM4aTags.
Exclude same-format and lossy-to-lossless targets from the batch
convert sheet so users cannot pick pointless conversions like
FLAC→FLAC. Also clean up redundant inline comments.
- Use -map_metadata 0 instead of -map_metadata -1 so FFmpeg copies and
auto-remaps source tags (M4A/ID3 → Vorbis comments) as a base
- Add _normalizeToVorbisComments() to filter technical fields (BIT_DEPTH,
SAMPLE_RATE, DURATION) and normalize key variations to standard Vorbis
comment names before applying overrides
- Switch cover art embedding from METADATA_BLOCK_PICTURE base64 (unreliable
on Android due to command-line length limits) to -i cover -map 1:v
-disposition attached_pic (same proven approach as embedMetadata and
_convertToAlac)
- Drop zero-value track/disc numbers from override map to prevent
clobbering source metadata with '0' from Go readFileMetadata
- Add _convertToAlac() and _convertToFlac() in ffmpeg_service with
single-pass FFmpeg encoding, metadata tags, and cover art embedding
- Wire lossless formats (ALAC, FLAC) into single-track convert sheet
with dynamic format list based on source format, hidden bitrate for
lossless targets, and lossless hint text
- Add lossless conversion to batch convert UI in downloaded_album,
local_album, and queue_tab screens with lossy-source filtering
- Fix M4A quality probe in Go backend: increase audio sample entry
buffer from 24 to 32 bytes, read sample rate from correct offset
(bytes 28-29) and bit depth from samplesize field (bytes 22-23)
- Add l10n keys for lossless confirm dialogs and hints (en, id)
Add LocalTrackRedownloadService with confidence-scored metadata matching
(ISRC, title, artist, album, duration, track/disc number, year) to find
reliable online matches for locally-stored tracks.
Wire up 'Queue FLAC' selection action in both local_album_screen and
queue_tab (library tab). Shows progress snackbar during resolution,
skips ambiguous or low-confidence matches, and reports results.
Add Indonesian (id) translations for all queueFlac l10n keys.
- Reduce polling interval from 800ms to 1200ms across download progress, library scan, and Android native stream
- Add dirty-flag caching to Go GetMultiProgress() to skip redundant JSON marshaling
- Replace eager provider initialization with staggered Timer-based warmup (400/900/1600ms)
- Add snapshot-based incremental library scan to avoid large MethodChannel payloads
- Move history stats and grouped album filtering to Riverpod providers for better cache invalidation
- Cap home tab history preview to 48 items with deep equality wrapper to reduce rebuilds
- Throttle foreground service notification updates to 2% progress buckets
- Migrate PageView to PageView.builder with AutomaticKeepAliveClientMixin
- Add comparison table to README
Add set/get/clear store registry URL method channel handlers on Android,
iOS, and Go backend so users can configure a custom extension repository.
Store tab now shows a setup screen when no registry URL is configured,
with a cleaner layout (removed redundant description and helper text)
and visible TextField borders for dark theme.
Minor comment and formatting cleanups across several files.
Parse .cue files in library scanner (Go + SAF) to display individual
tracks instead of one large audio file. Add FFmpeg-based CUE splitting
to extract tracks into separate FLAC files with embedded metadata and
cover art.
- Go: CUE parser, two-pass scan (CUE first, skip referenced audio),
virtual paths (cue#trackNN) for DB UNIQUE constraint, audioDir
override for SAF temp-file scenarios
- Android: SAF scanner recognizes .cue in both full and incremental
scan, copies .cue+audio to temp for Go parsing, unchanged-CUE audio
sibling dedup, parseCueSheet handler resolves SAF audio siblings
- Dart: FFmpegService.splitCueToTracks, CUE split UI in track metadata
screen, persistent output dir for SAF splits with write-back
- CUE virtual path normalization across fileExists/fileStat/deleteFile/
openFile; play/share/open blocked for virtual tracks with guidance to
split first; delete only removes DB entry, not shared .cue file
- iOS: parseCueSheet handler
- Localization: 12 new CUE-related strings
Requested by @Seerafimm
Closes#201
Version rolled back from v4.x to v3.7.0. After extensive work on v4's
internal streaming engine, smart queue, DASH pipeline, and media controls,
we realized v3 was already feature-complete. Adding more big features
only made maintenance increasingly difficult and the developer's life
miserable. Stripped back to what works: external player only, cleaner
codebase, sustainable long-term.
- Remove just_audio, audio_service, audio_session and entire internal
playback engine (smart queue, notification, shuffle/repeat, prefetch)
- Remove PlaybackItem model, MiniPlayerBar widget, notification drawables
- Remove playerMode setting (external-only now)
- Migrate MainActivity from AudioServiceFragmentActivity to
FlutterFragmentActivity
- Migrate Qobuz to MusicDL API
- Update changelog with v3.7.0 rollback explanation
- Add configurable SongLink region (userCountry) setting with picker UI
- Pass songLinkRegion through download request payload to Go backend
- Go backend: thread-safe global SongLink region with per-request override
- Fix downloaded track not recognized in collection tap: add findByTrackAndArtist
fallback in download history lookup chain (Spotify ID → ISRC → name+artist)
- Apply same name+artist fallback to isDownloaded check in track options sheet
- Add missing library_database.dart import for LocalLibraryItem
- Add multi-select support to library_tracks_folder_screen (wishlist, loved,
playlist) with long-press to enter selection mode, animated bottom bar with
batch remove/download/add-to-playlist actions, and PopScope exit handling
- Create batch showAddTracksToPlaylistSheet in playlist_picker_sheet with
playlist thumbnail widget and cover image support
- Add playlist grid selection tint overlay in queue_tab
- Optimize collection lookups with pre-built _allPlaylistTrackKeys index and
isTrackInAnyPlaylist/hasPlaylistTracks accessors
- Eagerly initialize localLibraryProvider and libraryCollectionsProvider
- Enable SQLite WAL mode and PRAGMA synchronous=NORMAL across all databases
- Go backend: duplicate SAF output FDs before provider attempts to prevent
fdsan abort on fallback retries; close detached FDs after download completes
- Go backend: rewrite compatibilityTransport to try HTTPS first and only
fallback to HTTP on transport-level failures, preventing redirect loops
- Go backend: enforce HTTPS-only for extension sandbox HTTP clients
- Replace SharedPreferences with SQLite (AppStateDatabase, LibraryCollectionsDatabase) for download queue, library collections, and recent access history
- Add Set-based O(1) track containment checks for wishlist, loved, and playlist tracks
- Add batch addTracksToPlaylist with PlaylistAddBatchResult
- Go backend: strict mode locks download to selected provider when auto fallback is off
- Go backend: fix extension progress normalization (percent/100) and lifecycle tracking
- Go backend: case-insensitive provider ID matching throughout fallback chain
- Lyrics embedding now respects lyricsMode setting (embed/both/off)
- Debounced queue persistence to reduce write frequency
- Fix shouldUseFallback logic to not be gated by useExtensions
- Add configurable YouTube Opus (96-256kbps) and MP3 (96-320kbps) bitrates
- Improve title matching with loose normalization for symbol-heavy tracks
- Add SpotubeDL engine v2 fallback for MP3 requests
- Improve filename sanitization in track metadata screen
- Bump version to 3.6.9+82
- Add getLyricsLRCWithSource to return lyrics with source metadata
- Display lyrics source in track metadata screen
- Improve LRC parsing to preserve background vocal tags
- Add dedicated LyricsProviderPriorityPage for provider configuration
- Add Paxsenix as lyrics proxy partner for Apple Music/QQ Music
- Handle inline timestamps and speaker prefixes in LRC display
- 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
- New YouTube download provider with Opus 256kbps and MP3 320kbps options
- SongLink/Odesli integration for Spotify/Deezer ID to YouTube URL conversion
- YouTube video ID detection for YT Music extension compatibility
- Parallel cover art and lyrics fetching during download
- Queue progress shows bytes (X.X MB) for streaming downloads
- Full metadata embedding: cover, lyrics, title, artist, album, track#, disc#, year, ISRC
- Removed Tidal HIGH (lossy AAC) option - use YouTube for lossy instead
- Bumped version to 3.6.0
- Add responsive scaling across album, artist, playlist, downloaded album, local album, queue, setup, and tutorial screens to prevent overflow on smaller devices
- Add new Storage & Cache management page (Settings > Storage & Cache) with per-category clear and cleanup actions
- Extract normalizedHeaderTopPadding utility for consistent app bar padding
- Improve home search Recent Access behavior: show when focused with empty input, hide stale results during active recent mode
- Add excluded-downloaded-count tracking to local library scan stats
- Add recentEmpty and recentShowAllDownloads l10n keys (EN + ID)
- Add full cache management l10n keys (EN + ID)
- Fix about_page indentation and formatting consistency
- Fix appearance_settings_page formatting
- Fix downloaded_album_screen and local_album_screen formatting and responsive sizing