New Features
- crash: Show persistent crash reports on Home
- about: Link the lyrics website and service status
- player: Search lyrics online for files without them
- lyrics: Add lrc.red and BetterLyrics, split SpotiFLAC-Mobile Lyrics
- home: Greet in the header and gather listening shortcuts
- onboarding: Introduce the 5.2 release tour
- library: Add adaptive icons to collection tabs
- home: Localize greetings and address profile names
- home: Expose extension country settings and isolate regional caches
- lyrics: Refresh quote sharing and load lyrics on demand
- android: Refresh launcher widgets with adaptive expressive layouts
- player: Add configurable full-screen cover art
- player: Synchronize music haptics with local playback
- lyrics: Share lyric cards and refine timed vocal transitions
- player: Show audio source processing and output details
- equalizer: Add multiband EQ and per-player native audio processing
- autoplay: Enable personalization by default and confirm learning resets
- a11y: Label controls and improve settings contrast and targets
- i18n: Add player feature text and clarify built-in playback
- loading: Align skeletons with collection and extension layouts
- player: Share volume controls across Material and Mornye
- rewind: Add yearly highlights and seasonal library banners
- forms: Adopt expressive inputs with consistent form state
- ui: Add themed menus and adaptive checkbox rows
- ui: Unify content cards and preserve press behavior
- layout: Adapt tablet navigation and center wide content
- listening: Show a skeleton while statistics load
- listening: Add Rewind highlights and refresh statistics
- player: Refine mini-player and queue feedback
- library: Add sectioned browsing and adaptive fast scrolling
- material: Unify progress and surface transitions
- material: Animate header action groups and collapse
- settings: Connect custom Material settings rows
- settings: Connect standard Material settings rows
- ui: Add Material Expressive spring motion
- lyrics: Add SpotiFLAC fallback for Apple Music outages
- ui: Extend Material Expressive surfaces and playback controls
- theme: Show a check on selected expressive switches
- theme: Adopt Material Symbols and expressive components
- metadata: Add per-field download tag separators
Bug Fixes
- crash: Match the Home crash card to the error card style
- library: Recover interrupted scans and stale notifications
- downloads: Offer folder recovery for permission failures
- equalizer: Keep headroom and limiter choices when applying a preset
- lyrics: Restore QQ Music search after the desktop CGI broke
- player: Restore the lighter full-screen cover scrim
- storage: Retain legacy Android cipher migration support
- library: Recover missing local album artwork from audio
- library: Restore bit depth as the default quality badge
- haptics: Analyze document audio across skips and AutoMix
- player: Report Android output failures without skipping tracks
- network: Request Android 17 local network access before NAS connections
- theme: Retain dominant cover colors in player backgrounds
- automix: Align effect handoffs and render sufficient source audio
- downloads: Recover native queues when their service dies
- verification: Bound browser handoffs and release expired dialogs
- player: Size volume slider handle proportionally
- settings: Use shared sheet for log level selection
- headers: Fit artwork and unify toolbar controls
- metadata: Align separator picker with Settings components
- settings: Unify adaptive sheet layout and drag behavior
- player: Expose favorites and shuffle in Material notifications
- audio: Preserve FLAC precision in Android bit-perfect playback
- extensions: Use adaptive icons for installed extension avatars
- library: Align filter and sort sheet sizing and dismissal
- player: Prevent overlapping titles during rapid skips
- storage: Preserve audio MIME when publishing SAF downloads
- lyrics: Refresh LRC sidecars in their actual SAF folder
- download: Probe M4A streams before preserving requested FLAC
- automix: Wait for advancing audio before starting fades
Performance
- lyrics: Compile credit regexes once
- library: Build DateFormat and RegExp once instead of per row
- history: Suppress unchanged membership notifications
- history: Reuse unchanged download lookup indexes
- releases: Narrow weekly release provider dependencies
- lyrics: Cache timed lyric segment geometry
- player: Cache adjacent track titles during swipes
Refactoring
- android: Share the SAF scan percent and CUE helpers
- android: Move SAF batch exists and modtime queries out of MainActivitySafScan.kt
- android: Move SAF tree listing and executors out of MainActivitySafScan.kt
- android: Move SAF CUE helpers out of MainActivitySafScan.kt
- android: Move SAF scan checkpointing out of MainActivitySafScan.kt
- android: Move SAF file inspection out of MainActivitySafScan.kt
- android: Put the SAF IO helpers on Context receivers
- android: Share the foreground wake lock and start helper between the two services
- providers: Share one Coalescer for single-flight request coalescing
- android: Move the lifecycle backend calls into MainActivityLifecycleCalls.kt
- android: Move the download service and worker backend calls into MainActivityServiceCalls.kt
- android: Move the library scan backend calls into MainActivityLibraryScanCalls.kt
- android: Move the metadata and tag backend calls into MainActivityMetadataCalls.kt
- android: Move the SAF backend calls into MainActivitySafCalls.kt
- android: Move install state, extension intents, SAF leases and small channels out of MainActivity.kt
- library: Split local_library_provider.dart into source, scan and cover parts
- library: Share the scan completion tail as _finishScan
- library: Remove the unreachable snapshot sub-branch of the incremental scan
- convert: Route single-track conversion through the shared pipeline
- queue: Move the completion bridge into CompletionBridgeTracker
- queue: Move library paging state into QueueLibraryPager
- bridge: Share one generic cache entry and put/prune helper
- collections: Move playlist cover file I/O into PlaylistCoverStore
- cache: Move directory scanning and clearing into CacheMaintenanceService
- analysis: Move the FFmpeg runner out of the widget
- analysis: Move the analysis disk cache into audio_analysis_cache.dart
- analysis: Move the pure FFmpeg builders and parsers to a service
- setup: Move SharedPreferences access behind SetupProgressStore and SafMigrationPromptStore
- providers: Move UI-declared providers to lib/providers
- rust: Rename mod.rs modules to the foo.rs + foo/ layout
- concerts: Move the calendar channel into a service
- repo: Prepare install paths in the repo notifier
- share: Share the widget capture helper
- extensions: Share the extension health color and icon helpers
- playlists: Share the playlist name prompt and dispose its controller
- artist: Move the discography download into a part
- home: Use downloadSingleTrack for search results
- storage: Share the SAF download tree pick
- layout: Share responsiveScale and effectiveTextScale
- layering: Move logic files out of screens
- layering: Move model files to models and fix inverted imports
- layering: Move UI action helpers from services and utils to controllers
- core: Add fs::write_atomic and use it for the atomic file writes
- rust: Consolidate small duplicate helpers
- core: Move the lenient Go-style JSON decoder to core::json
- metadata: Share the sidecar publish path between save-cover and save-lyrics
- android: Move RustCoreBackend.invokeApplication into its own file
- android: Move Impeller helpers, the SAF tree picker and progress streams out of MainActivity.kt
- utils: Share the FNV-1a 32-bit hash
- notifications: Reuse formatMegabytes
- io: Use isContentUri instead of inline content:// checks
- io: Use deleteFileQuietly for exists-then-delete
- android: Move finalizer history into NativeFinalizerHistory.kt
- android: Move finalizer post-processing into NativeFinalizerPostProcess.kt
- android: Move finalizer metadata into NativeFinalizerMetadata.kt
- android: Move finalizer container into NativeFinalizerContainer.kt
- android: Move finalizer decrypt into NativeFinalizerDecrypt.kt
- network: Split client.rs into pool, stream, headers and tests, and factor execute_stream
- extensions: Split manager.rs into install, lifecycle, info and tests modules
- player: Move restorePlaybackSession to playback_session_restore.dart
- player: Move PlayableMedia to playable_media.dart
- player: Port tests to musicPlayerRuntime and delete the test-only wrappers
- settings: Move log_screen widgets into a part
- settings: Move extensions_page widgets into a part
- settings: Move appearance_settings_page widgets into a part
- settings: Move files_settings_page widgets into a part
- settings: Move download_settings_page widgets into a part
- settings: Move library_settings_page widgets into a part
- settings: Move extension_detail_page widgets into a part
- extensions: Split backend/downloads.rs helpers into submodules and move its sibling tests
- extensions: Split runtime.rs into control, vm and tests modules
- library: Extract the ingestion store from library_database.dart
- history: Move the history schema and row mapper into their own files
- downloads: Move pure queue policy helpers into download_queue_policy.dart
- lyrics: Split native_lyrics into text, lrc, ttml, credits and tests modules
- rust: Move inline tests and the test-only hires decoder into submodules
- native: Share errorJson and retire Go-era names in native comments
- android: Drop SDK checks below minSdk 24
- android: Drop unreachable dispatch cases and dead channel handlers
- android: Remove backend switches that became constants
- shell: Move nav icons to a widget file and startup prompts into a part
- setup: Move the setup step builders into a part
- equalizer: Split the equalizer screen into widgets and curve parts
- rewind: Split the listening rewind screen and move its providers
- lyrics: Split player_lyrics.dart into line-style and word-sweep parts
- metadata: Move editor form primitives into a widgets file
- metadata: Split the edit sheet into cover and auto-fill parts
- metadata: One option picker for provider and cover size
- home: Split the home tab build into sliver-group builders
- home: Move extension collection screens into their own library
- library: Build the filter sheet from the sort-mode table
- library: Move queue download labels, dialogs and sliver grid out of queue_tab.dart
- bridge: Move platform_bridge helpers into part files
- providers: Remove the unused Deezer catalogue search
- rust: Restrict test-only functions
- network: Drop the ignored insecure_tls parameter inside Rust
- services: Clarify misleading names and drop a no-op rethrow
- logging: Rename Go-era log names to native
- services: Mark test-only members and privatize file-local ones
- services: Remove members with no caller
- library: Drop unread QueueTab page parameters and fast-scroller callbacks
- settings: Migrate remaining sheet choices
- explore: Centralize persistent cache storage
- downloads: Centralize failed session accounting
- downloads: Update queue items and indexes together
- ios: Share locked backend manager snapshots
- playback: Share lost route pause transitions
- android: Scope Rust download state handles consistently
- extensions: Share priority settings links
- library: Share selection action grid layout
- settings: Share selectable bottom sheet options
- android: Share native album artist resolution
- ios: Simplify supported OAuth session handling
- android: Remove unreachable backend dispatch fallbacks
- metadata: Reuse the platform tag mapper
- ui: Use shared loading indicators
- ui: Unify expressive actions and modal transitions
Documentation
- contributing: Add the codebase map and architecture guide
- test: Describe test layout, contracts and host tools
- theme: Explain the Material and Mornye theme layer
- third-party: Complete the vendored plugin patch notes
- rust: Describe the backend workspace, builds and bindings
- integration-test: Index the device suites and their defines
- android: Document the native channel contract
- rust: Add module docs to large modules without one
- selection: Correct the SelectionModeMixin doc
- rust: Mark the Unicode case table as frozen and generated
- rust: Say that Go is the retired backend in crate docs
- contributing: Name every third_party fork and scope the ffmpeg override
- contributing: Match the repository (l10n, gradle, ffmpeg, test layers)
- readme: Describe the lyrics providers and online search
- readme: Redesign banner, sections and showcase
- readme: Show the redesigned Home screen
- readme: Refresh screenshots, badges and feature table
- l10n: Describe network storage messages
Styling
- material: Align tonal surfaces and control shapes
Testing
- player: Split music_player_automix_test.dart by group
- queue: Remove real waits from the startup flush test
- player: Drive AutoMix transport and haptics with fake time
- bridge: Inject the lookup cache persist debounce
- android: Pin the extension and MIME tables
- android: Assert the backend routing set matches the dispatch cases
- Share one FixedSettingsNotifier across tests
- Skip the automix renderer test when ffmpeg is missing
- Poll for cover eviction instead of asserting after one event-loop turn
- Split models_and_utils_test by domain and isolate source contracts
- Declare the path provider interface dependency
- library: Share re-enrichment settings fixtures
Chores
- Update AltStore source to v5.1.1 by @github-actions[bot]
- lyrics: Rename first-party provider to Zarz-LRC
- analysis: Analyze hand-written l10n files and correct the lint comment
- Retire Go-era config and rename SMB fixture servers
- Run the Android Rust build once and cache Cargo
- Add a dart format gate and fix the one drifted test file
- settings: Clarify beta features and playback information
- Include integration tests in Dart change detection
- Ignore local release assets
- release: Bump app to 5.2.0 build 162
Build
- rust: Drop unused direct dependencies and centralize pins
Full Changelog: v5.1.1...v5.2.0
Downloads
Android
- arm64:
SpotiFLAC-v5.2.0-arm64.apk(recommended for modern devices) - arm32:
SpotiFLAC-v5.2.0-arm32.apk(older devices) *.apk.idsig: V4 signatures foradb install --incrementalonly; normal installs do not need them
iOS
- iOS:
SpotiFLAC-v5.2.0-ios-unsigned.ipa(sideload required)
Installation
Android: Enable "Install from unknown sources" and install the APK
iOS: Use AltStore, Sideloadly, or similar tools to sideload the IPA