505 Commits

Author SHA1 Message Date
zarzet
43469a7ef2 feat: add configurable extension download fallback 2026-04-06 03:00:17 +07:00
zarzet
355f2eba2a fix: resolve missing track/disc numbers from search downloads and suppress FFmpeg log noise
- Tidal: use actual API track_number/disc_number when request values are 0
  (fixes search/popular downloads having no track position in metadata)
- Extension enrichment: copy TrackNumber/DiscNumber back from enriched results
- Extension fallback download: add request metadata fallback for non-source
  extensions (Album, AlbumArtist, ReleaseDate, ISRC, TrackNumber, DiscNumber)
- FFmpeg: add -v error -hide_banner to all commands (embed, convert, CUE split)
  to eliminate banner, build config, and full metadata/lyrics dump in logcat
- ebur128: add framelog=quiet to suppress per-frame loudness measurements
  while keeping the summary needed for ReplayGain parsing
- Track metadata screen: separate embedded lyrics check from online fetch,
  show file-only state with manual online fetch button
2026-04-03 00:56:09 +07:00
zarzet
26f26f792a 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-02 03:15:01 +07:00
zarzet
a1aa1319ce feat: add separate filename format for singles and EPs (#271)
Add singleFilenameFormat setting so singles/EPs can use a different filename template than albums. The format editor is reused with custom title/description. Dart selects the correct format based on track.isSingle before passing to Go, so no backend changes needed. Also fix isSingle getter to include all EPs regardless of totalTracks. Closes #271
2026-03-31 18:55:48 +07:00
zarzet
3a60ea2f4e feat: add field selection dialog for bulk re-enrich metadata
Add a bottom sheet dialog that lets users choose which metadata field
groups to update during bulk re-enrich (cover, lyrics, album/album
artist, track/disc number, date/ISRC, genre/label/copyright).

Backend (Go):
- Filter FLAC Metadata struct and FFmpeg metadata map by selected
  update_fields so non-selected groups preserve existing file values
- Guard Deezer extended metadata fetch with shouldUpdateField(extra)
- Title/Artist are never overwritten by re-enrich (search keys only)
- enrichedMeta response only includes selected field groups

Frontend (Dart):
- New re_enrich_field_dialog.dart bottom sheet with checkboxes
- FFmpegService embed methods gain preserveMetadata param that uses
  -map_metadata 0 instead of -1 to preserve non-selected tags
- Hide selection overlay/bar before showing dialog, restore on cancel
- Fix setState-after-dispose guard in cancel branches

Cleanup:
- Remove dead code in library_tracks_folder_screen.dart
- Fix use_build_context_synchronously in main_shell.dart
- Suppress false-positive use_null_aware_elements lints
- Update l10n label from 'Title, Artist, Album' to 'Album, Album Artist'
2026-03-31 18:21:45 +07:00
zarzet
93e77aeb84 refactor: remove legacy API clients, Yoinkify fallback, and unused lyrics provider
- Delete dead metadata client and extract shared types to metadata_types.go
- Remove Yoinkify download fallback from Deezer, use MusicDL only
- Clean up retired settings fields and metadataSource
- Remove dead l10n keys for retired provider
- Add migration to strip retired provider from existing users' lyrics config
2026-03-30 23:26:37 +07:00
zarzet
67daefdf60 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-03-30 12:38:42 +07:00
zarzet
fabaf0a3ff 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-03-30 11:41:11 +07:00
zarzet
48eef0853d i18n: extract hardcoded strings into l10n keys
Move hardcoded UI strings across multiple screens and the notification
service into ARB-backed l10n keys so they can be translated via Crowdin.
Adds 62 new keys covering sort labels, dialog copy, metadata error
snackbars, folder-picker errors, home-tab error states, extensions home
feed selector, and all notification titles/bodies. NotificationService
now caches an AppLocalizations instance (injected from MainShell via
didChangeDependencies) and falls back to English literals when no locale
is available.
2026-03-29 17:02:12 +07:00
zarzet
fc70a912bf refactor: route spotify URLs through extensions 2026-03-29 16:35:16 +07:00
zarzet
0f327cd1f6 feat: add flat singles folder option (Artist/song.flac without Singles subfolder) 2026-03-26 18:15:37 +07:00
zarzet
5e1cc3ecb5 refactor: extract YouTube download to ytmusic extension and fix UI issues
Remove built-in YouTube/Cobalt download pipeline from Go backend and
Dart frontend. YouTube downloading now requires the ytmusic-spotiflac
extension (with download_provider capability).

Go backend:
- Delete youtube.go (745 lines) and youtube_quality_test.go
- Remove DownloadFromYouTube, IsYouTubeURLExport,
  ExtractYouTubeVideoIDExport from exports.go
- Remove YouTube routing from DownloadTrack and DownloadByStrategy

Dart frontend:
- Remove YouTube from built-in services, bitrate settings, quality UI
- Remove youtubeOpusBitrate/youtubeMp3Bitrate from settings model
- Add migration 7: default service youtube -> tidal
- Remove YouTube l10n keys from all 14 arb files and regenerate
- Update _determineOutputExt to handle opus_/mp3_ quality strings
- Add SAF opus/mp3 metadata embedding in unified branch
- Fix TweenSequence assertion crash (t outside 0.0-1.0)
- Fix store URL TextField styling consistency

Extension changes (gitignored, in extension/YT-Music-SpotiFLAC/):
- Add download_provider type, qualityOptions, network permissions
- Implement checkAvailability and download via SpotubeDL/Cobalt
2026-03-26 16:17:57 +07:00
zarzet
091e3fadd9 feat: add audio quality analysis widget and fix USLT lyrics detection 2026-03-26 01:11:29 +07:00
zarzet
e487817f21 feat: add sorting options for search results 2026-03-25 21:40:36 +07:00
zarzet
c8d605fdee fix: add ValueListenableBuilder for embedded cover refresh and localize hardcoded queue strings 2026-03-25 20:05:24 +07:00
zarzet
4974284760 fix(l10n): consolidate Crowdin locale files and fix ICU plural warnings
- Replace app_es-ES.arb, app_pt-PT.arb, app_tr-TR.arb (hyphen format)
  with properly named app_es_ES.arb, app_pt_PT.arb, app_tr.arb
- Fix @@locale values to match Flutter filename convention (underscore)
- Fix ICU plural syntax: remove redundant 'one {}' before '=1{...}'
  in es_ES, pt_PT, tr translations
- Regenerate l10n output files
2026-03-25 16:12:37 +07:00
zarzet
ea7e594c68 Merge remote-tracking branch 'origin/dev' into l10n_dev
# Conflicts:
#	lib/l10n/arb/app_es-ES.arb
#	lib/l10n/arb/app_id.arb
#	lib/l10n/arb/app_pt-PT.arb
#	lib/l10n/arb/app_tr-TR.arb
2026-03-25 16:08:10 +07:00
Zarz Eleutherius
d00a84f1b9 New translations app_en.arb (Indonesian) 2026-03-25 16:02:56 +07:00
Zarz Eleutherius
58b6203681 New translations app_en.arb (Chinese Simplified) 2026-03-25 16:02:54 +07:00
Zarz Eleutherius
d299144c47 New translations app_en.arb (Russian) 2026-03-25 16:02:53 +07:00
Zarz Eleutherius
40b224e5a1 New translations app_en.arb (Dutch) 2026-03-25 16:02:51 +07:00
Zarz Eleutherius
7021e5493f New translations app_en.arb (Japanese) 2026-03-25 16:02:49 +07:00
Zarz Eleutherius
68bbc8a259 New translations app_en.arb (German) 2026-03-25 16:02:47 +07:00
zarzet
c91154ea3e feat: add built-in search provider in settings, fix bottom sheet overflow 2026-03-25 15:46:12 +07:00
zarzet
98fdc0ed7c feat: restore Tidal HIGH (AAC 320kbps) lossy quality option (closes #242)
Requested by @okinaau in issue #242 — brings back the ability to
download tracks in lossy format for users on low storage devices.

HIGH quality fetches the AAC M4A stream directly from the Tidal server
(no lossless download + re-encode), then converts to MP3 or Opus via
FFmpeg based on the tidalHighFormat setting (mp3_320, opus_256, or
opus_128).

- go_backend/tidal.go: restore outputExt .m4a, filename logic,
  duplicate-check guard, HIGH M4A lyrics/LRC handling, and
  bitDepth=0/sampleRate=44100 for HIGH quality result
- settings.dart + settings.g.dart: re-add tidalHighFormat field
  (default mp3_320) with JSON serialization
- settings_provider.dart: re-add setTidalHighFormat(), remove
  migration that force-migrated HIGH to LOSSLESS
- download_queue_provider.dart: restore HIGH conversion logic for
  both SAF and non-SAF paths using FFmpegService.convertM4aToLossy
- download_settings_page.dart: restore Lossy 320kbps quality tile,
  format sub-picker tile, _getTidalHighFormatLabel helper, and
  _showTidalHighFormatPicker bottom sheet
- l10n: add 10 keys (downloadLossy320, downloadLossyFormat,
  downloadLossy320Format, downloadLossy320FormatDesc, downloadLossyMp3,
  downloadLossyMp3Subtitle, downloadLossyOpus256/Subtitle,
  downloadLossyOpus128/Subtitle) to ARB and all 13 generated files
2026-03-22 23:33:32 +07:00
zarzet
497ba342c0 feat: add createPlaylistFolder setting for playlist source folder prefix
When enabled, playlist downloads are placed inside a subfolder named
after the playlist before the normal folder organization structure
(e.g. Playlist/<artist>/<album>/). The setting is a no-op when folder
organization is already set to 'By Playlist'. Includes model field,
JSON serialization, settings notifier, download queue path logic,
UI toggle in download settings, and localizations for all 13 languages.
2026-03-22 22:43:03 +07:00
zarzet
feff985439 feat: add auto-scan option for local library
Add a new 'Auto Scan' setting under Local Library with four modes:
off, every app open (10min cooldown), daily, and weekly. The app
uses WidgetsBindingObserver to trigger incremental scans on launch
and when resuming from background, respecting the configured
cooldown based on the last scan timestamp.
2026-03-16 20:28:45 +07:00
zarzet
b8af75bf6e feat: add FLAC/ALAC bidirectional lossless conversion support
- 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)
2026-03-16 02:13:45 +07:00
zarzet
1665e4cd57 feat: selective auto-fill from online in Edit Metadata sheet
Add 'Auto-fill from online' expandable section to the metadata editor
that lets users choose exactly which fields to populate from online
metadata search. Users can select individual fields via filter chips,
use 'All' or 'Empty only' quick-select buttons, then tap 'Fetch & Fill'
to search metadata providers and fill only the selected controllers.

The search uses existing searchTracksWithMetadataProviders API with
ISRC-preferring best-match selection. Extended metadata (genre, label,
copyright) is fetched via Deezer extended metadata API when available.
Cover art is downloaded from the match's cover_url. All results are
previewed in the editor before saving — nothing is written to the file
until the user taps Save.

Add 21 new l10n keys (editMetadata* namespace) for all UI strings.
2026-03-15 20:35:42 +07:00
zarzet
42f0267277 feat: queue FLAC redownloads for local library tracks
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.
2026-03-15 20:18:58 +07:00
zarzet
941347b007 feat: add Opus 320kbps quality, remove Tidal HIGH tier
- Add YouTubeQualityOpus320 constant and opus_320 parser case in Go backend
- Expand opus supported bitrates to [128, 256, 320] across Go, Dart settings, and UI
- Update default YouTube Opus option from 256 to 320kbps
- Remove Tidal HIGH (lossy 320kbps) quality from Go backend, settings model,
  settings provider, download queue provider (both SAF and non-SAF paths),
  settings UI (quality option, format picker, helper methods), and l10n keys
- Add settings migration v6: auto-migrate users with audioQuality=HIGH to LOSSLESS
- Update and add Go test cases for opus_320 and adjusted max bitrate
- Regenerate l10n files, remove 10 unused downloadLossy* l10n keys
2026-03-15 20:16:44 +07:00
zarzet
20f789f8e0 fix(i18n): localize hardcoded strings in bulk playlist download and fix trailing newlines 2026-03-15 19:01:45 +07:00
zarzet
48f614359e feat(i18n): replace all hardcoded strings with l10n keys across 13 screens
- Added 80+ new keys to app_en.arb covering lyrics, SAF, download settings,
  snackbars, dialogs, home, cache, and store screens
- Replaced hardcoded strings in main_shell, album_screen, playlist_screen,
  library_tracks_folder_screen, home_tab, settings_tab, download_settings_page,
  lyrics_provider_priority_page, track_metadata_screen, extension_detail_page,
  cache_management_page, local_album_screen, downloaded_album_screen, search_screen
- Fixed structural bug in track_metadata_screen (duplicate closing brace)
- Added missing l10n.dart import to search_screen.dart
- Regenerated all app_localizations*.dart files via flutter gen-l10n
2026-03-13 15:12:12 +07:00
Zarz Eleutherius
cbfa147a12 New translations app_en.arb (Turkish) 2026-03-11 23:43:01 +07:00
Zarz Eleutherius
5b8c953ae6 New translations app_en.arb (Hindi) 2026-03-11 23:43:00 +07:00
Zarz Eleutherius
37a4dc096b New translations app_en.arb (Indonesian) 2026-03-11 23:42:58 +07:00
Zarz Eleutherius
b3808645fb New translations app_en.arb (Chinese Traditional) 2026-03-11 23:42:57 +07:00
Zarz Eleutherius
24aa804bf2 New translations app_en.arb (Chinese Simplified) 2026-03-11 23:42:56 +07:00
Zarz Eleutherius
941ffb2bb7 New translations app_en.arb (Russian) 2026-03-11 23:42:54 +07:00
Zarz Eleutherius
59737d6f2b New translations app_en.arb (Portuguese) 2026-03-11 23:42:53 +07:00
Zarz Eleutherius
c8ad93ee9b New translations app_en.arb (Dutch) 2026-03-11 23:42:52 +07:00
Zarz Eleutherius
8cb0c037c2 New translations app_en.arb (Korean) 2026-03-11 23:42:50 +07:00
Zarz Eleutherius
e30b69397b New translations app_en.arb (Japanese) 2026-03-11 23:42:49 +07:00
Zarz Eleutherius
d6e837fd61 New translations app_en.arb (German) 2026-03-11 23:42:47 +07:00
Zarz Eleutherius
5c97d202b9 New translations app_en.arb (Spanish) 2026-03-11 23:42:46 +07:00
Zarz Eleutherius
0f6cfa75bb New translations app_en.arb (French) 2026-03-11 23:42:44 +07:00
Zarz Eleutherius
91bd6d1572 Update source file app_en.arb 2026-03-11 23:42:42 +07:00
zarzet
f2ae1398db feat: add 'By Playlist' folder organization option (#111) 2026-03-11 01:07:14 +07:00
zarzet
76fe8dbc69 feat: add CUE sheet support for local library scanning and splitting (#201)
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
2026-03-11 00:31:20 +07:00
Zarz Eleutherius
dd05061829 New translations app_en.arb (Turkish) 2026-03-10 23:26:30 +07:00