# Changelog

## [3.4.0] - 2026-02-03

### Highlights

- **Local Library Scanning** ([#117](https://github.com/zarzet/SpotiFLAC-Mobile/issues/117)): Scan existing music collection to detect duplicates (FLAC, M4A, MP3, Opus, OGG)
- **Duplicate Detection** ([#117](https://github.com/zarzet/SpotiFLAC-Mobile/issues/117)): "In Library" badge on tracks matching by ISRC or track name + artist
- **Unified Library Tab**: History renamed to Library, shows Downloaded + Local Library tracks with source badges

### Added

- Local Album Screen with cover art, disc grouping, and selection mode
- Albums tab shows local library albums with folder icon badge
- Singles filter includes local library singles
- Advanced library filters: Source, Quality, Format, Date
- Cover art extraction from embedded tags (FLAC, MP3, Opus/Ogg)
- "Already in Library" notification when downloading existing tracks
- Spotify secrets now stored in secure storage (`flutter_secure_storage`)
- **Multi-Service Link Support**: Share links from Deezer, Tidal, and YouTube Music (in addition to Spotify)
  - Deezer: Full support for track, album, playlist, artist links
  - Tidal: Track links converted via SongLink to Spotify/Deezer for metadata
  - YouTube Music: Handled via ytmusic extension URL handler
- Local library tracks now open metadata screen on tap

### Changed

- Extension HTTP sandbox enforces HTTPS and blocks private IPs
- Extension file sandbox validates paths with boundary-safe checks

### Fixed

- Search filter bar now only appears after results load, not during loading
- MP3/Ogg metadata parsing (ID3v2 extended headers, Ogg packet reassembly)
- Library scan metadata (ISRC, disc number, release date)
- Cover cache robustness (size + mtime cache key)
- Local library selection and delete in list/grid views
- Albums/Singles count includes local library items

---

## [3.3.6] - 2026-02-02

### Added

- **WiFi-Only Download Mode**: Pause downloads on mobile data, auto-resume on WiFi (Settings > Download > Download Network)
- Added `connectivity_plus: ^6.0.3` dependency

---

## [3.3.5] - 2026-02-01

Same as 3.3.1 but fixes crash issues caused by FFmpeg.

### Added

- **Export Failed Downloads**: Export failed downloads to TXT file for easy lookup on other platforms
- **Auto-Export Setting**: Option to automatically export failed downloads when queue finishes

### Fixed

- **FFmpeg Crash**: Fixed crash issues during M4A to MP3/Opus conversion
- **Service Selection Ignored**: Fixed bug where selecting Qobuz/Amazon from service picker was ignored and always used Tidal instead
- **iOS iCloud Drive Permission Error**: Block iCloud Drive folder selection on iOS (Go backend cannot access iCloud due to sandboxing)

### Changed

- **Amazon Fallback Only**: Amazon Music is now grayed out in service picker and can only be used as fallback provider

---

## [3.3.1] - 2026-02-01

### Added

- **Clear All Queue Button**: Cancel all queued downloads with one tap ([#96](https://github.com/zarzet/SpotiFLAC-Mobile/issues/96))
- **IDHS Fallback**: Fallback link resolver when SongLink fails (rate limited 8 req/min)
- **Lossy Bitrate Options**: MP3 (320/256/192/128kbps), Opus (128/96/64kbps)
- **Search Filters**: Filter results by type (Tracks, Artists, Albums, Playlists)
- **Album/Playlist Search**: Deezer search now includes albums and playlists
- **New Languages**: Turkish (Kaan, BedirhanGltkn), Japanese (Re*Index.(ot_inc))
- **Optional All Files Access**: Android 13+ no longer requires full storage access; enable in Settings if needed
- **Improved VPN Compatibility**: Better HTTP/2 support for users behind VPN or restricted networks

### Changed

- **Amazon Download API**: Switched to AfkarXYZ API
- **Qobuz Download API**: Added Jumo API as fallback
- **Search Results**: Reduced artist limit from 5 to 2

### Fixed

- **MP3 Download Error 403**: Fixed 403 Forbidden error when downloading MP3 files ([#108](https://github.com/zarzet/SpotiFLAC-Mobile/issues/108))
- **Opus Cover Art**: Implemented METADATA_BLOCK_PICTURE for proper cover embedding
- **Deezer Pagination**: Fixed >25 tracks only showing first 25 ([#112](https://github.com/zarzet/SpotiFLAC-Mobile/issues/112))
- **Duplicate Embed Lyrics Setting**: Removed from Options page ([#110](https://github.com/zarzet/SpotiFLAC-Mobile/issues/110))

---

## [3.2.1] - 2026-01-22

### Added

- **Artist/Album + Singles Folder Structure**: Singles go inside artist folder (`Artist/Album/`, `Artist/Singles/`)
- **Embed Lyrics Button**: Manually embed online lyrics into tracks from Track Info screen (preserves synced timestamps)
- **Pause/Resume Button**: Added pause and resume controls next to "Downloading" header in History screen
- **Instrumental Detection**: Tracks marked as instrumental on lrclib.net now show "Instrumental track" instead of "Lyrics not available"

### Fixed

- **Lyrics**: Multi-artist tracks now search by primary artist first, then full string
- **Lyrics**: Metadata tags (`[ti:...]`, `[ar:...]`, `[by:...]`) no longer shown in display
- **Lyrics**: Embed button now correctly appears for tracks with online lyrics
- **Lyrics**: Manual embed preserves original timestamps instead of plain text
- **iOS**: Fixed "File not found" after 3.1.x → 3.2.0 update (container UUID migration)
- **Home Feed**: Greeting now uses device local time
- **Deezer**: Track position fallback to index+1 when API returns 0
- **Localization**: Fixed 16 ICU plural syntax warnings in Spanish & Portuguese

### Performance

- **Home Feed**: Precomputed Quick Picks section flag and reduced per-page allocations; explore state now watched by field to cut rebuilds
- **Home Recent**: Cached recent-access aggregation and limited list allocations for recent downloads
- **Settings/Theme/Recent**: Cached SharedPreferences instance to avoid repeated `getInstance()` calls
- **History/DB**: Batched iOS path migration updates to reduce write overhead
- **Download Queue**: Reduced polling allocations and avoided double-load scheduling for history
- **Misc**: Precompiled regex in share intent, update dialog, extensions error parsing, log analysis, and LRC cleanup; faster palette cache hits and log filtering

---

## [3.2.0] - 2026-01-22

> **Note:** Starting from v3.2.0, changelogs will be concise.

### Highlights

- **Discography Download** (Highly Requested): Download entire artist discography with album selection mode
- **Home Feed / Explore**: Personalized sections from spotify-web and ytmusic extensions
- **SQLite History Database**: O(1) lookups, non-blocking writes

### Added

- Discography download with options: All, Albums Only, Singles Only, or Select Albums
- Artist navigation from album screen (tap artist name)
- Home feed sections with pull-to-refresh
- YT Music Quick Picks swipeable UI
- `gobackend.getLocalTime()` API for extensions
- Track duration in home feed items
- Release date badge in album info card

### Improved

- Album track list shows track number instead of cover image
- Download buttons with more rounded corners
- Downloaded songs in Recent show primary-colored subtitle

### Fixed

- Home feed timezone detection
- Track duration 0:00 when downloading from home feed

### Extensions

- spotify-web v1.8.1: Home feed, artist_id support
- ytmusic v1.6.1: Home feed, artist_id support

---

## [3.1.3] - 2026-01-19

### Added

- **External LRC Lyrics File Support**: Option to save lyrics as separate .lrc files for compatibility with external music players
  - New "Lyrics Mode" setting in Settings > Download > Lyrics section
  - Three modes available:
    - **Embed in file** (default): Lyrics stored inside FLAC metadata
    - **External .lrc file**: Save lyrics as separate .lrc file next to audio file
    - **Both**: Embed and save external .lrc file
  - Perfect for players like Samsung Music that prefer external .lrc files
  - LRC files include metadata headers (title, artist, by:SpotiFLAC-Mobile)
  - Works with all download services (Tidal, Qobuz, Amazon)
- **CSV Import Quality Selection**: Choose audio quality when importing CSV playlists
  - Quality picker now appears before adding CSV tracks to download queue
  - Select between FLAC qualities (Lossless, Hi-Res, Hi-Res Max) or MP3
  - Respects "Ask quality before download" setting - uses default quality if disabled
  - **Persistent Cover Image Cache**: Album/track cover images now cached to persistent storage instead of temporary directory
  - Cover images no longer disappear when app is closed or device restarts
  - Cache stored in `app_flutter/cover_cache/` directory (not cleared by system)
  - Maximum 1000 images cached for up to 365 days
  - Covers are cached when displayed in History, Home, Album, Artist, or any other screen
  - New `CoverCacheManager` service with `clearCache()` and `getStats()` methods for future cache management
- **Extended Metadata from Deezer Enrichment**: Track downloads now include label, copyright, and genre metadata from Deezer
  - New fields in `ExtTrackMetadata`: `label`, `copyright`, `genre`
  - Metadata fetched during `enrichTrack()` via Deezer album API
  - Embedded as FLAC Vorbis comments: `GENRE`, `ORGANIZATION` (label), `COPYRIGHT`
  - Works for both extension downloads and built-in provider downloads (Tidal, Qobuz, Amazon)
- **Track Metadata Screen Extended Info**: Genre, label, and copyright now displayed in track metadata screen
  - Added `genre`, `label`, `copyright` fields to `DownloadHistoryItem` model
  - Metadata is stored in download history and persists across app restarts
  - New localization strings: `trackGenre`, `trackLabel`, `trackCopyright`
- `**utils.randomUserAgent()` for Extensions**: New utility function for extensions to get random browser User-Agent strings
  - Returns modern Chrome User-Agent format: `Chrome/{120-145}.0.{6000-7499}.{100-299}` with `Windows NT 10.0`
  - Useful for extensions that need to rotate User-Agents to avoid detection

### Fixed

- **Portuguese Language Bug**: Fixed locale parsing for languages with country codes (e.g., pt_PT, es_ES)
  - App now correctly loads Portuguese and Spanish translations
  - Updated Portuguese label to "Português (Brasil)"
- **VM Race Condition Panic**: Fixed `panic during execution: runtime error: index out of range [-2]` crash when switching search providers
  - Root cause: Goja VM was being accessed concurrently by multiple goroutines without synchronization
  - Added `VMMu sync.Mutex` to `LoadedExtension` struct
  - Added mutex lock/unlock to ALL `ExtensionProviderWrapper` methods:
    - `SearchTracks`, `GetTrack`, `GetAlbum`, `GetArtist`
    - `EnrichTrack`, `CheckAvailability`, `GetDownloadURL`, `Download`
    - `CustomSearch`, `HandleURL`, `MatchTrack`, `PostProcess`
  - Prevents race conditions when rapidly switching between extension search providers
- **Tidal Release Date Fallback**: Fixed missing release date in FLAC metadata when downloading from Tidal
  - Now uses Tidal API's release date when `req.ReleaseDate` is empty
  - Ensures release date is always embedded in downloaded files
- **Extended Metadata for M4A→FLAC Conversion**: Fixed genre, label, and copyright not being embedded when converting Amazon M4A to FLAC
  - Flutter now extracts extended metadata from Go backend response
  - Passes `genre`, `label`, `copyright` parameters to `_embedMetadataAndCover()`
  - Tags correctly embedded during FFmpeg conversion
- **Extended Metadata for MP3 Conversion**: Genre, label, and copyright now embedded in MP3 files when converting from FLAC
  - Added `genre`, `label`, `copyright` parameters to `_embedMetadataToMp3()`
  - Tags embedded as ID3v2: `GENRE`, `ORGANIZATION` (label), `COPYRIGHT`

### Extensions

- **spotify-web Extension**: Updated to v1.7.0
  - Added `getMetadataFromDeezer()` function to fetch extended metadata:
    - ISRC from track
    - Label from album
    - Copyright (generated as "YEAR LABEL")
    - Genre from album genres
    - Release date
  - `enrichTrack()` now returns all extended metadata to Go backend
  - Replaced all hardcoded User-Agent strings with `utils.randomUserAgent()`

### Performance

- **Faster App Startup**: Notification, Share Intent, and Cover Cache Manager initialization now run in parallel
- **Download Queue Polling**: Batched progress updates reduce rebuilds and list allocations during active downloads
- **Queue Item Updates**: Status/progress updates now skip no-op changes and update by index for fewer allocations
- **Directory Creation**: Download output folders are created once per path, reducing repeated I/O for albums/singles
- **Search Results Rendering**: Single-pass filtering avoids repeated `indexOf` calls for large result sets
- **Queue Lookups in UI**: O(1) lookup for queue status in Home/Album/Playlist/Artist track lists
- **History Filtering**: Album/single counts and grouping are computed once per build
- **Downloaded Album View**: Tracks are grouped by disc in one pass to reduce filtering overhead
- **Track Metadata Screen**:
  - Palette extraction deferred until after transition; reduced sample size for smoother navigation
  - File stat uses a single syscall and only triggers state updates on change
  - Static regex/month table avoids repeated allocations
  - Cover precached before opening metadata from history/queue/recents
- **Flutter Provider Optimizations**:
  - Cache `SharedPreferences` instance in `DownloadHistoryNotifier` and `DownloadQueueNotifier` to avoid repeated `getInstance()` calls
  - Precompile regex for folder name sanitization and year extraction (top-level `final`)
  - Use `indexWhere` instead of `firstWhere` with placeholder object to reduce allocations in queue processing
- **Flutter UI Optimizations**:
  - Selective `ref.watch()` for `downloadQueueProvider` (watch only `queuedCount` or `items` instead of entire state)
  - Pass `Track` directly to `_buildTrackTile()` instead of index lookup inside builder
  - Pass `historyItems` as parameter to `_buildRecentAccess()` to avoid `ref.read()` inside method
- **M4A Metadata Embedding**: Streaming implementation reduces memory usage for large files
  - Uses `os.Open()` + `ReadAt` instead of `os.ReadFile()` (no full file load into memory)
  - Atomic file replacement via temp file + rename for safer writes
  - New helper functions: `findAtomInRange()`, `readAtomHeaderAt()`, `copyRange()`

### Backend

- **Deezer ISRC Fetching**: Uses ISRCs already present in payloads and caches them, cutting extra API calls
- **SearchAll Allocation**: Preallocated slices to reduce allocations during Deezer search
- **HTTP Client Helper**: Refactored HTTP client creation to use `NewHTTPClientWithTimeout()` helper function across `lyrics.go`, `qobuz.go`, `tidal.go`

### Technical

- **Go Backend Changes**:
  - `go_backend/extension_providers.go`: Added `Label`, `Copyright`, `Genre` fields to `ExtTrackMetadata`; added mutex locks to all provider methods
  - `go_backend/extension_manager.go`: Added `VMMu sync.Mutex` to `LoadedExtension` struct
  - `go_backend/extension_runtime.go`: Added `utils.randomUserAgent` function
  - `go_backend/extension_runtime_utils.go`: Added `randomUserAgent()` implementation
  - `go_backend/httputil.go`: Updated `getRandomUserAgent()` to use modern Chrome versions
  - `go_backend/tidal.go`: Added release date fallback logic
  - `go_backend/exports.go`: Added `Genre`, `Label`, `Copyright` fields to `DownloadResponse`
- **Flutter Changes**:
  - `lib/services/cover_cache_manager.dart`: New persistent cache manager for cover images (365 days, 1000 images max)
  - `lib/widgets/cached_cover_image.dart`: Wrapper widget for CachedNetworkImage with persistent cache
  - `lib/main.dart`: Added `CoverCacheManager.initialize()` to app startup
  - `lib/screens/*.dart`: All 11 screens updated to use persistent cache manager for CachedNetworkImage
  - `lib/providers/download_queue_provider.dart`: Updated `_embedMetadataAndCover()` to accept and embed genre, label, copyright; added `genre`, `label`, `copyright` fields to `DownloadHistoryItem`
  - `lib/screens/track_metadata_screen.dart`: Display genre, label, copyright in metadata grid
  - `lib/l10n/arb/app_en.arb`: Added `trackGenre`, `trackLabel`, `trackCopyright` localization strings

### Dependencies

- Added `flutter_cache_manager: ^3.4.1` (explicit dependency for persistent cache)
- Added `path: ^1.9.0` (for cache directory path handling)

---

## [3.1.2] - 2026-01-19

### Added

- **New Languages**: Added Spanish (es) and Portuguese (pt) translations
  - Spanish: Credits 125 ([@credits125](https://crowdin.com/profile/credits125))
  - Portuguese: Pedro Marcondes ([@justapedro](https://crowdin.com/profile/justapedro))
  - Russian: Владислав ([@odinokiy_kot](https://crowdin.com/profile/odinokiy_kot))
- **Quick Search Provider Switcher** ([#76](https://github.com/zarzet/SpotiFLAC-Mobile/issues/76)): Dropdown menu in search bar for instant provider switching
  - Tap the search icon to reveal a dropdown menu with all available search providers
  - Shows default provider (Deezer based on metadata source setting) at the top
  - Lists all enabled extensions with custom search capability
  - Displays extension icons when available
  - Checkmark indicates currently selected provider
  - Search hint text updates immediately when switching providers
  - Re-triggers search automatically if there's existing text in the search bar
  - Eliminates need to navigate to Settings > Extensions > Search Provider
- **Extension Button Setting Type** ([#74](https://github.com/zarzet/SpotiFLAC-Mobile/issues/74)): New setting type for extension actions
  - Extensions can define `button` type in manifest settings
  - Triggers JavaScript function when tapped (e.g., start OAuth flow)
  - Useful for authentication, manual sync, or any custom action
- **Genre & Label Metadata** ([#75](https://github.com/zarzet/SpotiFLAC-Mobile/issues/75)): Downloaded tracks now include genre and record label information
  - Fetches genre and label from Deezer album API for each track
  - Embeds GENRE, ORGANIZATION (label), and COPYRIGHT tags into FLAC files
  - Works automatically when Deezer track ID is available (via ISRC matching)
  - Supports all download services (Tidal, Qobuz, Amazon) and extension downloads
- **MP3 Quality Option** ([#69](https://github.com/zarzet/SpotiFLAC-Mobile/issues/69)): Optional MP3 download format with FLAC-to-MP3 conversion
  - New "Enable MP3 Option" toggle in Settings > Download > Audio Quality
  - When enabled, MP3 (320kbps) appears as a quality option alongside FLAC options
  - Available in both the quality picker dialog and default quality settings
  - Works with all services (Tidal, Qobuz, Amazon) and extensions
- **MP3 Metadata Embedding**: Full metadata support for MP3 files
  - Cover art embedded using ID3v2 tags
  - Synced lyrics embedded (fetched from lrclib.net)
  - All metadata preserved: title, artist, album, album artist, track/disc number, date, ISRC
  - Automatic tag conversion from Vorbis comments (FLAC) to ID3v2 (MP3)
- **Dominant Color Header**: Album, Playlist, Downloaded Album, and Track Metadata screens now feature dynamic header backgrounds
  - Extracts dominant color from cover art using `palette_generator`
  - Creates a gradient from dominant color to theme surface color
  - Smooth 500ms color transition animation
- **Larger Cover Art**: Cover images on detail screens are now 50% of screen width (previously 140px fixed)
  - More prominent album artwork display
  - Larger shadow and rounded corners (20px radius)
  - Higher resolution cover caching
- **Sticky Title**: Title appears in AppBar when scrolling past the info card
  - Smooth fade-in animation (200ms) when scrolling down
  - Title hidden when header is expanded (shows in info card instead)
  - AppBar uses theme color (surface) for clean, native look
  - Works on Album, Playlist, Downloaded Album, Track Metadata, and Artist screens
- **Artist Name in Album Screen**: Album info card now displays artist name below album title
  - Extracted from first track's artist metadata
  - Styled with `onSurfaceVariant` color for visual hierarchy
- **Disc Separation for Multi-Disc Albums** ([#70](https://github.com/zarzet/SpotiFLAC-Mobile/issues/70)): Downloaded albums with multiple discs now display tracks grouped by disc
  - Visual disc separator header showing "Disc 1", "Disc 2", etc.
  - Tracks sorted by disc number first, then by track number
  - Single-disc albums display normally without separators
  - Fixes confusion when albums have duplicate track numbers across discs
- **Album Grouping in Recents** ([#70](https://github.com/zarzet/SpotiFLAC-Mobile/issues/70)): Downloads now show as albums instead of individual tracks in the Recent section
  - Prevents flooding the recents list when downloading full albums
  - Groups tracks by album name and artist
  - Tapping navigates directly to the downloaded album screen
  - Shows the most recent download time for each album

### Changed

- **FFmpeg FLAC-to-MP3 Conversion**: Improved conversion process
  - MP3 files now saved in the same folder as FLAC (no separate MP3 subfolder)
  - Original FLAC file automatically deleted after successful conversion
  - New `embedMetadataToMp3()` method for MP3-specific tag embedding
- **Sticky Header Theme Integration**: AppBar background uses `colorScheme.surface` instead of dominant color when collapsed
  - Dark theme: Black background with white text
  - Light theme: White background with black text
  - Matches modern app behavior for better readability

### Fixed

- **MP3 Quality Display in Track Metadata**: Fixed incorrect quality display for MP3 files
  - MP3 files now show "320kbps" instead of FLAC's bit depth/sample rate
  - History no longer stores FLAC audio specs for converted MP3 files
  - Both File Info badges and metadata grid show correct MP3 quality
- **Empty Catch Blocks**: Fixed analyzer warnings for empty catch blocks
  - `download_queue_provider.dart`: Added comments explaining why polling errors are silently ignored
  - `track_provider.dart`: Added comments explaining why availability check errors are silently ignored
  - `ffmpeg_service.dart`: Added proper error logging for temp file cleanup failures
- **Russian Plural Forms**: Fixed ICU syntax warnings in Russian localization
  - Removed redundant `=1` clauses that were overriding `one` plural category
  - Affected 10 plural strings including track counts and delete confirmations
  - Plurals now correctly handle Russian grammar (1 трек, 2 трека, 5 треков)

### Dependencies

- Added `palette_generator: ^0.3.3+4` for cover art color extraction

---

## [3.1.1] - 2026-01-17

### Added

- **Lyrics Caching**: Lyrics are now cached for 24 hours to reduce API calls and improve performance
  - Thread-safe cache with automatic expiration
  - Cache key based on artist, track, and duration
  - Log indicator shows "(cached)" when lyrics are served from cache
- **Lyrics Duration Matching**: Improved lyrics accuracy with duration-based matching
  - Compares track duration with lrclib.net results
  - 10-second tolerance to handle version differences (radio edit, remaster, etc.)
  - Prioritizes synced lyrics over plain text when duration matches
  - Falls back gracefully if no duration match found
- **Deezer Cover Art Upgrade**: Cover art from Deezer CDN now automatically upgraded to maximum quality
  - Detects Deezer CDN URLs (`cdn-images.dzcdn.net`)
  - Upgrades cover resolution to 1800x1800 (max available)
  - Works alongside existing cover upgrade
- **Live Search for Extensions**: Search-as-you-type functionality for extension search
  - 800ms debounce delay to prevent excessive API calls
  - Minimum 3 characters required before searching
  - Concurrency control to prevent race conditions in extension runtime
  - Queues pending searches if a search is already in progress
- **Russian Language Support**: Added Russian (Русский) translation - 99% complete
  - Translated via Crowdin community contributions
  - Covers all UI elements, settings, and error messages

### Fixed

- **ISRC Index Race Condition**: Fixed repeated index rebuilding during parallel downloads
  - Added per-directory build lock using `sync.Map` and `sync.Mutex`
  - Double-check locking pattern ensures index is built only once
  - Significantly improves performance during CSV import with many tracks
- **Queue Tab Scroll Exception**: Fixed Flutter rendering exception with NestedScrollView
  - Disabled Material 3 stretch overscroll indicator that caused `_StretchController` assertion
  - Wrapped NestedScrollView with ScrollConfiguration to prevent `setState during build` errors
  - Issue was especially noticeable during rapid queue updates (CSV import)
- **CSV Import**: Fixed CSV export not being parsed correctly
  - Added support for `Artist Name(s)` header (with parentheses)
  - Added support for `Track URI` header for track IDs
  - Added `artists` and `track_id` as alternative header names
  - Now correctly parses "Liked Songs" and playlist exports

---

## [3.1.0] - 2026-01-16

### Added

- **Recent Access History**: Quick access to recently visited content when tapping the search bar
- **Artist Screen Redesign**: Full-width header, monthly listeners, top tracks section
- **Extension Store Update Badge**: Badge indicator showing available extension updates
- **Extension Compatibility Warning**: Warning for extensions requiring newer app version
- **Year in Album Folder Name**: New folder structure options with release year
- **Extension Album/Playlist/Artist Support**: Extensions can now return collections in search
- **Odesli Integration**: YouTube Music extension can now match tracks to Deezer/Tidal/Qobuz
- **Download Cancel**: Properly stops in-flight downloads

### Changed

- Search bar behavior improved with recent access history

### Fixed

- Multiple extension-related fixes for artist, album, and playlist handling
- UI fixes for search, settings, and navigation

---

## [3.0.0] - 2026-01-14

### Extension System (Major Feature)

SpotiFLAC 3.0 introduces a powerful extension system that allows third-party integrations for metadata, downloads, and more.

- **Extension Store**: Browse and install extensions directly from the app
- **Web Extension**: Metadata provider for personalized playlists
- **Extension Capabilities**: Custom search, URL handlers, thumbnail ratios, post-processing
- **Extension APIs**: Full HTTP, storage, file, and crypto support
- **Security**: Sandboxed JavaScript runtime with permission-based access

### Added

- Album folder structure settings
- Separate singles folder option
- Year in album folder name
- Parallel API calls for faster downloads
- Swipeable history filters

### Fixed

- Tab edge overscroll
- Extension duplicate load error
- Settings item highlight on swipe
- Back gesture freeze on Android 13+
- Bottom overflow in dialogs
- Japanese artist name matching
- Multi-artist matching
- Max resolution cover download
- Various extension-related fixes

---

*For older versions, see [GitHub Releases*](https://github.com/zarzet/SpotiFLAC-Mobile/releases)