When an extension's preferred output isn't .m4a, downloaded M4A streams
are now automatically converted to FLAC via FFmpeg instead of being
preserved. This applies to both SAF and non-SAF download paths.
- Add monochrome.tf and samidy.com Tidal API mirrors
- Guarantee resolvedProvider is never null by defaulting to 'tidal'
- Replace stale 'Deezer' default label with 'Tidal' (Deezer moved to extension)
- Show dynamic provider target in auto label for search dropdown
- Bump app version to 4.3.0 (build 125)
- Extract createOrReuseDocumentFile() to handle SAF auto-rename races
between findFile() and createFile(), preferring the exact-named sibling
and discarding duplicate documents
- Bind cancel context to all extension HTTP calls (fetch, httpGet, httpPost,
httpRequest, fileDownload, authExchangeCodeWithPKCE) so in-flight requests
are aborted when user cancels a download
- Make initDownloadCancel idempotent: return existing context if entry already
exists and preserve pre-cancelled state
- Force SAF output filename to match actual file extension when extension
returns a different format than requested (e.g. FLAC requested but M4A produced)
- Map ALAC/AAC quality to .m4a instead of falling through to default .flac
- Embed DownloadQueueLookup into DownloadQueueState; add updatedForIndices() for O(changed) incremental updates during frequent progress ticks instead of full O(n) rebuild
- downloadQueueLookupProvider now reads pre-computed lookup from state directly
- Replace sync file deletion in DownloadedEmbeddedCoverResolver with unawaited async cleanup to avoid blocking the main thread
- Parse JSON payloads on iOS native side (parseJsonPayload) so event sinks and method channel responses return native objects, avoiding redundant Dart-side JSON decode
- Use .cast<String, dynamic>() instead of Map.from() in _decodeMapResult for zero-copy map handling
- Move explore JSON decode/encode to compute() isolate to avoid blocking main thread
- Memoize search sort results (artists/albums/playlists/tracks) in HomeTab; invalidate on new query
- Extract _DownloadedOrRemoteCover StatefulWidget with proper embedded-cover lifecycle management
- Replace O(playlists x tracks) in-memory playlist picker check with SQL loadPlaylistPickerSummaries query
- Add FutureProvider.family (libraryPlaylistPickerSummariesProvider) invalidated on all playlist mutations
- Memoize _buildQueueHistoryStats, localPathMatchKeys, and localSingleItems in QueueTab
- Add coverCacheWidthForViewport util; apply memCacheWidth/cacheWidth based on real DPR across all album/playlist/track screens
- Convert sync file ops in TrackMetadataScreen to async; use mtime+size as validation token
- Fetch Deezer album nb_tracks in parallel via fetchAlbumTrackCounts