fix: resolve all flutter analyze warnings and improve auto-fill enrichment chain

- Fix use_build_context_synchronously in _embedLyrics by capturing l10n
  strings before async gaps (snackbarFailedToWriteStorage,
  snackbarFailedToEmbedLyrics, snackbarUnsupportedAudioFormat)
- Improve auto-fill metadata enrichment to use proper API chain:
  search providers -> convertSpotifyToDeezer (SongLink) for Deezer ID
  -> getDeezerMetadata for ISRC -> getDeezerExtendedMetadata for
  genre/label/copyright. Falls back to ISRC-based Deezer lookup when
  SongLink conversion unavailable.
- flutter analyze now reports 0 issues
This commit is contained in:
zarzet
2026-03-15 20:42:22 +07:00
parent 1665e4cd57
commit f36096e0ac
+103 -32
View File
@@ -1757,6 +1757,11 @@ class _TrackMetadataScreenState extends ConsumerState<TrackMetadataScreen> {
setState(() => _isEmbedding = true);
// Capture l10n strings before async gaps to avoid use_build_context_synchronously
final l10nFailedToWriteStorage = context.l10n.snackbarFailedToWriteStorage;
final l10nFailedToEmbedLyrics = context.l10n.snackbarFailedToEmbedLyrics;
final l10nUnsupportedFormat = context.l10n.snackbarUnsupportedAudioFormat;
String? safTempPath;
String? coverPath;
@@ -1793,13 +1798,13 @@ class _TrackMetadataScreenState extends ConsumerState<TrackMetadataScreen> {
);
success = ok;
if (!ok) {
error = context.l10n.snackbarFailedToWriteStorage;
error = l10nFailedToWriteStorage;
}
} else {
success = true;
}
} else {
error = result['error']?.toString() ?? context.l10n.snackbarFailedToEmbedLyrics;
error = result['error']?.toString() ?? l10nFailedToEmbedLyrics;
}
} else if (isMp3 || isOpus) {
final metadata = _buildFallbackMetadata();
@@ -1845,7 +1850,7 @@ class _TrackMetadataScreenState extends ConsumerState<TrackMetadataScreen> {
}
if (ffmpegResult == null) {
error = context.l10n.snackbarFailedToEmbedLyrics;
error = l10nFailedToEmbedLyrics;
} else if (_isSafFile) {
final ok = await PlatformBridge.writeTempToSaf(
ffmpegResult,
@@ -1853,13 +1858,13 @@ class _TrackMetadataScreenState extends ConsumerState<TrackMetadataScreen> {
);
success = ok;
if (!ok) {
error = context.l10n.snackbarFailedToWriteStorage;
error = l10nFailedToWriteStorage;
}
} else {
success = true;
}
} else {
error = context.l10n.snackbarUnsupportedAudioFormat;
error = l10nUnsupportedFormat;
}
if (mounted) {
@@ -4299,7 +4304,7 @@ class _EditMetadataSheetState extends State<_EditMetadataSheet> {
}
best ??= results.first;
// Extract metadata from best match
// Extract basic metadata from search result
final enriched = <String, String>{
'title': (best['name'] ?? '').toString(),
'artist': (best['artists'] ?? best['artist'] ?? '').toString(),
@@ -4311,39 +4316,82 @@ class _EditMetadataSheetState extends State<_EditMetadataSheet> {
'isrc': (best['isrc'] ?? '').toString(),
};
// Try to get extended metadata (genre, label, copyright) from Deezer
final needsIsrc = _autoFillFields.contains('isrc') &&
enriched['isrc']!.isEmpty;
final needsExtended = _autoFillFields.contains('genre') ||
_autoFillFields.contains('label') ||
_autoFillFields.contains('copyright');
final trackId =
(best['spotify_id'] ?? best['id'] ?? '').toString();
final source = (best['source'] ?? best['provider_id'] ?? '').toString();
final source =
(best['source'] ?? best['provider_id'] ?? '').toString();
final isDeezerSource = source.toLowerCase().contains('deezer');
if ((_autoFillFields.contains('genre') ||
_autoFillFields.contains('label') ||
_autoFillFields.contains('copyright')) &&
trackId.isNotEmpty) {
// Resolve Deezer track ID for extended metadata + ISRC
String? deezerId;
if ((needsIsrc || needsExtended) && trackId.isNotEmpty) {
try {
// If source is Deezer, fetch extended metadata directly
Map<String, String>? extended;
if (source.toLowerCase().contains('deezer')) {
extended = await PlatformBridge.getDeezerExtendedMetadata(trackId);
if (isDeezerSource) {
// Source is Deezer — trackId is already a Deezer ID
deezerId = trackId;
} else {
// Try ISRC lookup via Deezer for genre/label/copyright
final isrcForLookup = enriched['isrc'] ?? '';
if (isrcForLookup.isNotEmpty) {
try {
final deezerResult = await PlatformBridge.searchDeezerByISRC(
isrcForLookup,
);
final deezerTrackId =
(deezerResult['id'] ?? deezerResult['track_id'] ?? '')
.toString();
if (deezerTrackId.isNotEmpty) {
extended = await PlatformBridge.getDeezerExtendedMetadata(
deezerTrackId,
);
}
} catch (_) {}
// Source is Spotify/extension — convert to Deezer via SongLink
final deezerData = await PlatformBridge.convertSpotifyToDeezer(
'track',
trackId,
);
final trackData = deezerData['track'];
if (trackData is Map<String, dynamic>) {
final rawId = trackData['spotify_id'] as String?;
if (rawId != null && rawId.startsWith('deezer:')) {
deezerId = rawId.split(':')[1];
}
// Also grab ISRC and release_date from the conversion response
final convIsrc = (trackData['isrc'] ?? '').toString().trim();
if (convIsrc.isNotEmpty && enriched['isrc']!.isEmpty) {
enriched['isrc'] = convIsrc;
}
final convDate =
(trackData['release_date'] ?? '').toString().trim();
if (convDate.isNotEmpty && enriched['date']!.isEmpty) {
enriched['date'] = convDate;
}
}
// Fallback: legacy ID format
deezerId ??= (deezerData['id'] ?? '').toString();
if (deezerId.isEmpty) deezerId = null;
}
} catch (_) {
// SongLink conversion is best-effort
}
}
if (!mounted) return;
// Fetch ISRC from Deezer track metadata if still missing
if (needsIsrc && enriched['isrc']!.isEmpty && deezerId != null) {
try {
final deezerMeta = await PlatformBridge.getDeezerMetadata(
'track',
deezerId,
);
final deezerIsrc = (deezerMeta['isrc'] ?? '').toString().trim();
if (deezerIsrc.isNotEmpty) {
enriched['isrc'] = deezerIsrc;
}
} catch (_) {}
}
if (!mounted) return;
// Fetch genre/label/copyright from Deezer extended metadata
if (needsExtended && deezerId != null) {
try {
final extended = await PlatformBridge.getDeezerExtendedMetadata(
deezerId,
);
if (extended != null) {
enriched['genre'] = extended['genre'] ?? '';
enriched['label'] = extended['label'] ?? '';
@@ -4354,6 +4402,29 @@ class _EditMetadataSheetState extends State<_EditMetadataSheet> {
}
}
// Fallback: if still no Deezer ID but we have ISRC, try ISRC lookup
if (needsExtended &&
deezerId == null &&
enriched['isrc']!.isNotEmpty) {
try {
final deezerResult = await PlatformBridge.searchDeezerByISRC(
enriched['isrc']!,
);
final fallbackId =
(deezerResult['id'] ?? deezerResult['track_id'] ?? '')
.toString();
if (fallbackId.isNotEmpty) {
final extended =
await PlatformBridge.getDeezerExtendedMetadata(fallbackId);
if (extended != null) {
enriched['genre'] = extended['genre'] ?? '';
enriched['label'] = extended['label'] ?? '';
enriched['copyright'] = extended['copyright'] ?? '';
}
}
} catch (_) {}
}
if (!mounted) return;
// Apply selected fields to controllers