mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-04 09:10:48 +02:00
fix: stricter metadata matching, respect embedLyrics setting, improve Apple Music lyrics
- Re-enrich: reject candidates that don't match title/artist/album unless exact ISRC match - Respect settings.embedLyrics instead of hardcoding true in re-enrich flows - Skip lyrics resolution in NativeDownloadFinalizer when not needed - Apple Music lyrics: use direct catalog API with token scraping instead of Paxsenix search - Support ELRC/ELRCMultiPerson/Plain formats in Apple Music lyrics response - Add confidence check in metadata auto-fill to prevent applying wrong metadata - Add tests for stricter re-enrich matching logic
This commit is contained in:
@@ -883,12 +883,13 @@ class _LocalAlbumScreenState extends ConsumerState<LocalAlbumScreen> {
|
||||
List<String>? updateFields,
|
||||
}) async {
|
||||
final durationMs = (item.duration ?? 0) * 1000;
|
||||
final artistTagMode = ref.read(settingsProvider).artistTagMode;
|
||||
final settings = ref.read(settingsProvider);
|
||||
final artistTagMode = settings.artistTagMode;
|
||||
final request = <String, dynamic>{
|
||||
'file_path': item.filePath,
|
||||
'cover_url': '',
|
||||
'max_quality': true,
|
||||
'embed_lyrics': true,
|
||||
'embed_lyrics': settings.embedLyrics,
|
||||
'artist_tag_mode': artistTagMode,
|
||||
'spotify_id': '',
|
||||
'track_name': item.trackName,
|
||||
|
||||
@@ -4408,12 +4408,13 @@ class _QueueTabState extends ConsumerState<QueueTab> {
|
||||
List<String>? updateFields,
|
||||
}) async {
|
||||
final durationMs = (item.duration ?? 0) * 1000;
|
||||
final artistTagMode = ref.read(settingsProvider).artistTagMode;
|
||||
final settings = ref.read(settingsProvider);
|
||||
final artistTagMode = settings.artistTagMode;
|
||||
final request = <String, dynamic>{
|
||||
'file_path': item.filePath,
|
||||
'cover_url': '',
|
||||
'max_quality': true,
|
||||
'embed_lyrics': true,
|
||||
'embed_lyrics': settings.embedLyrics,
|
||||
'artist_tag_mode': artistTagMode,
|
||||
'spotify_id': '',
|
||||
'track_name': item.trackName,
|
||||
|
||||
@@ -599,6 +599,54 @@ class _EditMetadataSheetState extends State<_EditMetadataSheet> {
|
||||
return score;
|
||||
}
|
||||
|
||||
bool _metadataTextMatches(String current, String candidate) {
|
||||
if (current.isEmpty || candidate.isEmpty) return false;
|
||||
return current == candidate ||
|
||||
candidate.contains(current) ||
|
||||
current.contains(candidate);
|
||||
}
|
||||
|
||||
bool _metadataMatchIsConfident(
|
||||
Map<String, dynamic> track, {
|
||||
required String currentTitle,
|
||||
required String currentArtist,
|
||||
required String currentAlbum,
|
||||
required String currentIsrc,
|
||||
}) {
|
||||
final candidateIsrc = (track['isrc']?.toString() ?? '')
|
||||
.trim()
|
||||
.toUpperCase();
|
||||
if (currentIsrc.isNotEmpty && candidateIsrc == currentIsrc) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final candidateTitle = _normalizeMetadataText(
|
||||
(track['name'] ?? track['title'] ?? '').toString(),
|
||||
);
|
||||
final candidateArtist = _normalizeMetadataText(
|
||||
(track['artists'] ?? track['artist'] ?? '').toString(),
|
||||
);
|
||||
final candidateAlbum = _normalizeMetadataText(
|
||||
(track['album_name'] ?? track['album'] ?? '').toString(),
|
||||
);
|
||||
|
||||
final titleMatches = _metadataTextMatches(currentTitle, candidateTitle);
|
||||
final artistMatches = _metadataTextMatches(currentArtist, candidateArtist);
|
||||
final albumMatches = _metadataTextMatches(currentAlbum, candidateAlbum);
|
||||
|
||||
if (currentTitle.isNotEmpty && currentArtist.isNotEmpty) {
|
||||
return titleMatches && artistMatches;
|
||||
}
|
||||
if (currentTitle.isNotEmpty && currentAlbum.isNotEmpty) {
|
||||
return titleMatches && albumMatches;
|
||||
}
|
||||
if (currentTitle.isNotEmpty) {
|
||||
return titleMatches;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<void> _fetchAndFill() async {
|
||||
if (_autoFillFields.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
@@ -683,6 +731,24 @@ class _EditMetadataSheetState extends State<_EditMetadataSheet> {
|
||||
best = result;
|
||||
}
|
||||
}
|
||||
|
||||
if (best != null &&
|
||||
!_metadataMatchIsConfident(
|
||||
best,
|
||||
currentTitle: normalizedTitle,
|
||||
currentArtist: normalizedArtist,
|
||||
currentAlbum: normalizedAlbum,
|
||||
currentIsrc: currentIsrc,
|
||||
)) {
|
||||
best = null;
|
||||
}
|
||||
|
||||
if (best == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(context.l10n.editMetadataAutoFillNoResults)),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final selectedBest = best;
|
||||
|
||||
@@ -2921,7 +2921,8 @@ class _TrackMetadataScreenState extends ConsumerState<TrackMetadataScreen> {
|
||||
if (!_fileExists) return;
|
||||
|
||||
try {
|
||||
final artistTagMode = ref.read(settingsProvider).artistTagMode;
|
||||
final settings = ref.read(settingsProvider);
|
||||
final artistTagMode = settings.artistTagMode;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(context.l10n.trackReEnrichSearching)),
|
||||
);
|
||||
@@ -2931,7 +2932,7 @@ class _TrackMetadataScreenState extends ConsumerState<TrackMetadataScreen> {
|
||||
'file_path': cleanFilePath,
|
||||
'cover_url': _coverUrl ?? '',
|
||||
'max_quality': true,
|
||||
'embed_lyrics': true,
|
||||
'embed_lyrics': settings.embedLyrics,
|
||||
'artist_tag_mode': artistTagMode,
|
||||
'spotify_id': _spotifyId ?? '',
|
||||
'track_name': trackName,
|
||||
|
||||
Reference in New Issue
Block a user