mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-04 17:16:50 +02:00
feat(metadata): limit embedded cover resolution
This commit is contained in:
@@ -8223,6 +8223,24 @@ abstract class AppLocalizations {
|
||||
/// In en, this message translates to:
|
||||
/// **'Copy all metadata'**
|
||||
String get metadataCopyAll;
|
||||
|
||||
/// Metadata setting that limits downloaded artwork resolution before it is embedded
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Embedded Cover Size'**
|
||||
String get optionsEmbeddedCoverSize;
|
||||
|
||||
/// Description shown in the embedded cover size picker
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Downscale remotely downloaded cover art before embedding it. Images already within the limit are kept unchanged.'**
|
||||
String get optionsEmbeddedCoverSizeDescription;
|
||||
|
||||
/// Option that preserves the provider artwork at its original resolution
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Original resolution'**
|
||||
String get optionsEmbeddedCoverSizeOriginal;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
||||
@@ -5047,4 +5047,14 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get metadataCopyAll => 'Copy all metadata';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSize => 'Embedded Cover Size';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeDescription =>
|
||||
'Downscale remotely downloaded cover art before embedding it. Images already within the limit are kept unchanged.';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeOriginal => 'Original resolution';
|
||||
}
|
||||
|
||||
@@ -5002,4 +5002,14 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get metadataCopyAll => 'Copy all metadata';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSize => 'Embedded Cover Size';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeDescription =>
|
||||
'Downscale remotely downloaded cover art before embedding it. Images already within the limit are kept unchanged.';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeOriginal => 'Original resolution';
|
||||
}
|
||||
|
||||
@@ -4997,6 +4997,16 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get metadataCopyAll => 'Copy all metadata';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSize => 'Embedded Cover Size';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeDescription =>
|
||||
'Downscale remotely downloaded cover art before embedding it. Images already within the limit are kept unchanged.';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeOriginal => 'Original resolution';
|
||||
}
|
||||
|
||||
/// The translations for Spanish Castilian, as used in Spain (`es_ES`).
|
||||
|
||||
@@ -5117,4 +5117,14 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get metadataCopyAll => 'Copy all metadata';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSize => 'Embedded Cover Size';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeDescription =>
|
||||
'Downscale remotely downloaded cover art before embedding it. Images already within the limit are kept unchanged.';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeOriginal => 'Original resolution';
|
||||
}
|
||||
|
||||
@@ -5000,4 +5000,14 @@ class AppLocalizationsId extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get metadataCopyAll => 'Salin semua metadata';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSize => 'Ukuran Cover Tertanam';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeDescription =>
|
||||
'Perkecil cover yang diunduh dari internet sebelum ditanamkan. Gambar yang sudah berada dalam batas tidak akan diubah.';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeOriginal => 'Resolusi asli';
|
||||
}
|
||||
|
||||
@@ -4990,4 +4990,14 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get metadataCopyAll => 'Copy all metadata';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSize => 'Embedded Cover Size';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeDescription =>
|
||||
'Downscale remotely downloaded cover art before embedding it. Images already within the limit are kept unchanged.';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeOriginal => 'Original resolution';
|
||||
}
|
||||
|
||||
@@ -4871,4 +4871,14 @@ class AppLocalizationsKo extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get metadataCopyAll => 'Copy all metadata';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSize => 'Embedded Cover Size';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeDescription =>
|
||||
'Downscale remotely downloaded cover art before embedding it. Images already within the limit are kept unchanged.';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeOriginal => 'Original resolution';
|
||||
}
|
||||
|
||||
@@ -4996,6 +4996,16 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get metadataCopyAll => 'Copy all metadata';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSize => 'Embedded Cover Size';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeDescription =>
|
||||
'Downscale remotely downloaded cover art before embedding it. Images already within the limit are kept unchanged.';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeOriginal => 'Original resolution';
|
||||
}
|
||||
|
||||
/// The translations for Portuguese, as used in Portugal (`pt_PT`).
|
||||
|
||||
@@ -5033,4 +5033,14 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get metadataCopyAll => 'Copy all metadata';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSize => 'Embedded Cover Size';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeDescription =>
|
||||
'Downscale remotely downloaded cover art before embedding it. Images already within the limit are kept unchanged.';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeOriginal => 'Original resolution';
|
||||
}
|
||||
|
||||
@@ -5032,4 +5032,14 @@ class AppLocalizationsTr extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get metadataCopyAll => 'Copy all metadata';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSize => 'Embedded Cover Size';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeDescription =>
|
||||
'Downscale remotely downloaded cover art before embedding it. Images already within the limit are kept unchanged.';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeOriginal => 'Original resolution';
|
||||
}
|
||||
|
||||
@@ -5050,4 +5050,14 @@ class AppLocalizationsUk extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get metadataCopyAll => 'Copy all metadata';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSize => 'Embedded Cover Size';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeDescription =>
|
||||
'Downscale remotely downloaded cover art before embedding it. Images already within the limit are kept unchanged.';
|
||||
|
||||
@override
|
||||
String get optionsEmbeddedCoverSizeOriginal => 'Original resolution';
|
||||
}
|
||||
|
||||
@@ -6475,5 +6475,17 @@
|
||||
"metadataCopyAll": "Copy all metadata",
|
||||
"@metadataCopyAll": {
|
||||
"description": "Metadata menu action that copies every visible key and value"
|
||||
},
|
||||
"optionsEmbeddedCoverSize": "Embedded Cover Size",
|
||||
"@optionsEmbeddedCoverSize": {
|
||||
"description": "Metadata setting that limits downloaded artwork resolution before it is embedded"
|
||||
},
|
||||
"optionsEmbeddedCoverSizeDescription": "Downscale remotely downloaded cover art before embedding it. Images already within the limit are kept unchanged.",
|
||||
"@optionsEmbeddedCoverSizeDescription": {
|
||||
"description": "Description shown in the embedded cover size picker"
|
||||
},
|
||||
"optionsEmbeddedCoverSizeOriginal": "Original resolution",
|
||||
"@optionsEmbeddedCoverSizeOriginal": {
|
||||
"description": "Option that preserves the provider artwork at its original resolution"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6153,5 +6153,8 @@
|
||||
"trackOptionCopyTrackAndArtist": "Salin judul dan artis",
|
||||
"metadataCopyValue": "Salin nilai",
|
||||
"metadataCopyField": "Salin field dan nilai",
|
||||
"metadataCopyAll": "Salin semua metadata"
|
||||
"metadataCopyAll": "Salin semua metadata",
|
||||
"optionsEmbeddedCoverSize": "Ukuran Cover Tertanam",
|
||||
"optionsEmbeddedCoverSizeDescription": "Perkecil cover yang diunduh dari internet sebelum ditanamkan. Gambar yang sudah berada dalam batas tidak akan diubah.",
|
||||
"optionsEmbeddedCoverSizeOriginal": "Resolusi asli"
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ class AppSettings {
|
||||
final String downloadTreeUri; // SAF persistable tree URI
|
||||
final bool autoFallback;
|
||||
final bool embedMetadata;
|
||||
|
||||
/// Maximum width or height of remotely fetched artwork before embedding.
|
||||
/// Zero preserves the provider's original image.
|
||||
final int embeddedCoverMaxDimension;
|
||||
final String
|
||||
artistTagMode; // 'joined' or 'split_vorbis' for Vorbis-based formats
|
||||
final bool embedLyrics;
|
||||
@@ -131,6 +135,7 @@ class AppSettings {
|
||||
this.downloadTreeUri = '',
|
||||
this.autoFallback = true,
|
||||
this.embedMetadata = true,
|
||||
this.embeddedCoverMaxDimension = 0,
|
||||
this.artistTagMode = artistTagModeJoined,
|
||||
this.embedLyrics = true,
|
||||
this.embedReplayGain = false,
|
||||
@@ -205,6 +210,7 @@ class AppSettings {
|
||||
String? downloadTreeUri,
|
||||
bool? autoFallback,
|
||||
bool? embedMetadata,
|
||||
int? embeddedCoverMaxDimension,
|
||||
String? artistTagMode,
|
||||
bool? embedLyrics,
|
||||
bool? embedReplayGain,
|
||||
@@ -282,6 +288,8 @@ class AppSettings {
|
||||
downloadTreeUri: downloadTreeUri ?? this.downloadTreeUri,
|
||||
autoFallback: autoFallback ?? this.autoFallback,
|
||||
embedMetadata: embedMetadata ?? this.embedMetadata,
|
||||
embeddedCoverMaxDimension:
|
||||
embeddedCoverMaxDimension ?? this.embeddedCoverMaxDimension,
|
||||
artistTagMode: artistTagMode ?? this.artistTagMode,
|
||||
embedLyrics: embedLyrics ?? this.embedLyrics,
|
||||
embedReplayGain: embedReplayGain ?? this.embedReplayGain,
|
||||
|
||||
@@ -16,6 +16,8 @@ AppSettings _$AppSettingsFromJson(Map<String, dynamic> json) => AppSettings(
|
||||
downloadTreeUri: json['downloadTreeUri'] as String? ?? '',
|
||||
autoFallback: json['autoFallback'] as bool? ?? true,
|
||||
embedMetadata: json['embedMetadata'] as bool? ?? true,
|
||||
embeddedCoverMaxDimension:
|
||||
(json['embeddedCoverMaxDimension'] as num?)?.toInt() ?? 0,
|
||||
artistTagMode: json['artistTagMode'] as String? ?? artistTagModeJoined,
|
||||
embedLyrics: json['embedLyrics'] as bool? ?? true,
|
||||
embedReplayGain: json['embedReplayGain'] as bool? ?? false,
|
||||
@@ -111,6 +113,7 @@ Map<String, dynamic> _$AppSettingsToJson(
|
||||
'downloadTreeUri': instance.downloadTreeUri,
|
||||
'autoFallback': instance.autoFallback,
|
||||
'embedMetadata': instance.embedMetadata,
|
||||
'embeddedCoverMaxDimension': instance.embeddedCoverMaxDimension,
|
||||
'artistTagMode': instance.artistTagMode,
|
||||
'embedLyrics': instance.embedLyrics,
|
||||
'embedReplayGain': instance.embedReplayGain,
|
||||
|
||||
@@ -849,6 +849,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
albumName: track.albumName,
|
||||
albumArtist: resolvedAlbumArtist ?? '',
|
||||
coverUrl: settings.embedMetadata ? (track.coverUrl ?? '') : '',
|
||||
coverMaxDimension: settings.embeddedCoverMaxDimension,
|
||||
outputDir: outputDir,
|
||||
filenameFormat: filenameFormat,
|
||||
quality: quality,
|
||||
|
||||
@@ -657,7 +657,10 @@ extension _DownloadQueueEmbedding on DownloadQueueNotifier {
|
||||
// Started here, awaited only after the lyrics fetch below so the two
|
||||
// network round trips overlap. Errors are handled inside the fetch
|
||||
// (it resolves to null), never as an unhandled rejection.
|
||||
coverFuture = _sharedEmbedCover(coverUrl);
|
||||
coverFuture = _sharedEmbedCover(
|
||||
coverUrl,
|
||||
settings.embeddedCoverMaxDimension,
|
||||
);
|
||||
}
|
||||
|
||||
String? lrcContent;
|
||||
@@ -1019,24 +1022,25 @@ extension _DownloadQueueEmbedding on DownloadQueueNotifier {
|
||||
static const _embedCoverCacheMax = 8;
|
||||
|
||||
/// One cover fetch per URL, shared by every track in the batch.
|
||||
Future<String?> _sharedEmbedCover(String coverUrl) {
|
||||
final existing = _embedCoverCache.remove(coverUrl);
|
||||
Future<String?> _sharedEmbedCover(String coverUrl, int maxDimension) {
|
||||
final cacheKey = '$maxDimension\u0000$coverUrl';
|
||||
final existing = _embedCoverCache.remove(cacheKey);
|
||||
if (existing != null) {
|
||||
_embedCoverCache[coverUrl] = existing; // LRU touch
|
||||
_embedCoverCache[cacheKey] = existing; // LRU touch
|
||||
return existing;
|
||||
}
|
||||
final fetch = _downloadEmbedCover(coverUrl).then((path) {
|
||||
if (path == null) _embedCoverCache.remove(coverUrl); // allow retry
|
||||
final fetch = _downloadEmbedCover(coverUrl, maxDimension).then((path) {
|
||||
if (path == null) _embedCoverCache.remove(cacheKey); // allow retry
|
||||
return path;
|
||||
});
|
||||
_embedCoverCache[coverUrl] = fetch;
|
||||
_embedCoverCache[cacheKey] = fetch;
|
||||
while (_embedCoverCache.length > _embedCoverCacheMax) {
|
||||
_evictEmbedCover(_embedCoverCache.keys.first);
|
||||
}
|
||||
return fetch;
|
||||
}
|
||||
|
||||
Future<String?> _downloadEmbedCover(String coverUrl) async {
|
||||
Future<String?> _downloadEmbedCover(String coverUrl, int maxDimension) async {
|
||||
try {
|
||||
final tempDir = await getTemporaryDirectory();
|
||||
final uniqueId =
|
||||
@@ -1047,6 +1051,7 @@ extension _DownloadQueueEmbedding on DownloadQueueNotifier {
|
||||
final result = await PlatformBridge.downloadCoverToFile(
|
||||
coverUrl,
|
||||
coverPath,
|
||||
maxDimension: maxDimension,
|
||||
);
|
||||
if (result['error'] != null) {
|
||||
_log.w('Failed to download cover: ${result['error']}');
|
||||
|
||||
@@ -108,6 +108,13 @@ class SettingsNotifier extends Notifier<AppSettings> {
|
||||
'external_first',
|
||||
'in_app_first',
|
||||
};
|
||||
static const Set<int> _embeddedCoverMaxDimensionValues = {
|
||||
0,
|
||||
500,
|
||||
1000,
|
||||
1500,
|
||||
2000,
|
||||
};
|
||||
|
||||
final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
|
||||
final FlutterSecureStorage _secureStorage = const FlutterSecureStorage();
|
||||
@@ -169,6 +176,9 @@ class SettingsNotifier extends Notifier<AppSettings> {
|
||||
autoConvertBitrate: normalizeAutoConvertBitrate(
|
||||
loaded.autoConvertBitrate,
|
||||
),
|
||||
embeddedCoverMaxDimension: _normalizeEmbeddedCoverMaxDimension(
|
||||
loaded.embeddedCoverMaxDimension,
|
||||
),
|
||||
defaultService: loaded.defaultService,
|
||||
searchProvider: loaded.searchProvider,
|
||||
extensionVerificationBrowserMode:
|
||||
@@ -327,6 +337,9 @@ class SettingsNotifier extends Notifier<AppSettings> {
|
||||
downloadDirectoryBookmark: current.downloadDirectoryBookmark,
|
||||
storageMode: current.storageMode,
|
||||
downloadTreeUri: current.downloadTreeUri,
|
||||
embeddedCoverMaxDimension: _normalizeEmbeddedCoverMaxDimension(
|
||||
restored.embeddedCoverMaxDimension,
|
||||
),
|
||||
);
|
||||
|
||||
await _saveSettings();
|
||||
@@ -401,6 +414,10 @@ class SettingsNotifier extends Notifier<AppSettings> {
|
||||
return 'in_app_first';
|
||||
}
|
||||
|
||||
int _normalizeEmbeddedCoverMaxDimension(int value) {
|
||||
return _embeddedCoverMaxDimensionValues.contains(value) ? value : 0;
|
||||
}
|
||||
|
||||
String? _sanitizeRetiredBuiltInProviderId(String? providerId) {
|
||||
final normalized = providerId?.trim().toLowerCase();
|
||||
if (normalized == null || normalized.isEmpty) return providerId;
|
||||
@@ -528,6 +545,15 @@ class SettingsNotifier extends Notifier<AppSettings> {
|
||||
_saveSettings();
|
||||
}
|
||||
|
||||
void setEmbeddedCoverMaxDimension(int maxDimension) {
|
||||
state = state.copyWith(
|
||||
embeddedCoverMaxDimension: _normalizeEmbeddedCoverMaxDimension(
|
||||
maxDimension,
|
||||
),
|
||||
);
|
||||
_saveSettings();
|
||||
}
|
||||
|
||||
void setArtistTagMode(String mode) {
|
||||
if (mode == artistTagModeJoined || mode == artistTagModeSplitVorbis) {
|
||||
state = state.copyWith(artistTagMode: mode);
|
||||
|
||||
@@ -52,6 +52,19 @@ class MetadataSettingsPage extends ConsumerWidget {
|
||||
settings.artistTagMode,
|
||||
),
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.photo_size_select_large_outlined,
|
||||
title: context.l10n.optionsEmbeddedCoverSize,
|
||||
subtitle: _getEmbeddedCoverSizeLabel(
|
||||
context,
|
||||
settings.embeddedCoverMaxDimension,
|
||||
),
|
||||
onTap: () => _showEmbeddedCoverSizePicker(
|
||||
context,
|
||||
ref,
|
||||
settings.embeddedCoverMaxDimension,
|
||||
),
|
||||
),
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.graphic_eq,
|
||||
title: context.l10n.optionsReplayGain,
|
||||
@@ -146,6 +159,77 @@ class MetadataSettingsPage extends ConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
String _getEmbeddedCoverSizeLabel(BuildContext context, int maxDimension) {
|
||||
if (maxDimension <= 0) {
|
||||
return context.l10n.optionsEmbeddedCoverSizeOriginal;
|
||||
}
|
||||
return '$maxDimension × $maxDimension px';
|
||||
}
|
||||
|
||||
void _showEmbeddedCoverSizePicker(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
int currentMaxDimension,
|
||||
) {
|
||||
const options = [0, 500, 1000, 1500, 2000];
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: colorScheme.surfaceContainerHigh,
|
||||
builder: (context) => SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 24, 24, 8),
|
||||
child: Text(
|
||||
context.l10n.optionsEmbeddedCoverSize,
|
||||
style: Theme.of(
|
||||
context,
|
||||
).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 0, 24, 12),
|
||||
child: Text(
|
||||
context.l10n.optionsEmbeddedCoverSizeDescription,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
for (final maxDimension in options)
|
||||
ListTile(
|
||||
leading: Icon(
|
||||
maxDimension == 0
|
||||
? Icons.image_outlined
|
||||
: Icons.compress_outlined,
|
||||
),
|
||||
title: Text(
|
||||
_getEmbeddedCoverSizeLabel(context, maxDimension),
|
||||
),
|
||||
trailing: currentMaxDimension == maxDimension
|
||||
? const Icon(Icons.check)
|
||||
: null,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setEmbeddedCoverMaxDimension(maxDimension);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showArtistTagModePicker(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
|
||||
@@ -242,6 +242,12 @@ class SettingsSearchCatalog {
|
||||
title: l10n.optionsArtistTagMode,
|
||||
keywords: const ['artist separator', 'multiple artists'],
|
||||
),
|
||||
SettingsSearchEntry(
|
||||
icon: Icons.photo_size_select_large_outlined,
|
||||
title: l10n.optionsEmbeddedCoverSize,
|
||||
subtitle: l10n.optionsEmbeddedCoverSizeDescription,
|
||||
keywords: const ['cover size', 'artwork resolution', 'resize image'],
|
||||
),
|
||||
SettingsSearchEntry(
|
||||
icon: Icons.graphic_eq,
|
||||
title: l10n.optionsReplayGain,
|
||||
|
||||
@@ -992,6 +992,7 @@ extension _TrackMetadataLyricsAndSaving on _TrackMetadataScreenState {
|
||||
final request = <String, dynamic>{
|
||||
'file_path': cleanFilePath,
|
||||
'cover_url': _coverUrl ?? '',
|
||||
'cover_max_dimension': settings.embeddedCoverMaxDimension,
|
||||
'embed_lyrics': settings.embedLyrics,
|
||||
'lyrics_mode': settings.lyricsMode,
|
||||
'artist_tag_mode': artistTagMode,
|
||||
|
||||
@@ -81,6 +81,7 @@ Map<String, dynamic> buildBatchReEnrichRequest({
|
||||
final request = <String, dynamic>{
|
||||
'file_path': item.filePath,
|
||||
'cover_url': '',
|
||||
'cover_max_dimension': settings.embeddedCoverMaxDimension,
|
||||
'embed_lyrics': settings.embedLyrics,
|
||||
'lyrics_mode': settings.lyricsMode,
|
||||
'artist_tag_mode': settings.artistTagMode,
|
||||
|
||||
@@ -12,6 +12,7 @@ class DownloadRequestPayload {
|
||||
final String albumName;
|
||||
final String albumArtist;
|
||||
final String coverUrl;
|
||||
final int coverMaxDimension;
|
||||
final String outputDir;
|
||||
final String filenameFormat;
|
||||
final String quality;
|
||||
@@ -74,6 +75,7 @@ class DownloadRequestPayload {
|
||||
required this.albumName,
|
||||
this.albumArtist = '',
|
||||
this.coverUrl = '',
|
||||
this.coverMaxDimension = 0,
|
||||
required this.outputDir,
|
||||
required this.filenameFormat,
|
||||
this.quality = 'LOSSLESS',
|
||||
@@ -138,6 +140,7 @@ class DownloadRequestPayload {
|
||||
'album_name': albumName,
|
||||
'album_artist': albumArtist,
|
||||
'cover_url': coverUrl,
|
||||
'cover_max_dimension': coverMaxDimension,
|
||||
'output_dir': outputDir,
|
||||
'filename_format': filenameFormat,
|
||||
'quality': quality,
|
||||
@@ -206,6 +209,7 @@ class DownloadRequestPayload {
|
||||
albumName: albumName,
|
||||
albumArtist: albumArtist,
|
||||
coverUrl: coverUrl,
|
||||
coverMaxDimension: coverMaxDimension,
|
||||
outputDir: outputDir,
|
||||
filenameFormat: filenameFormat,
|
||||
quality: quality,
|
||||
|
||||
@@ -956,11 +956,13 @@ class PlatformBridge {
|
||||
|
||||
static Future<Map<String, dynamic>> downloadCoverToFile(
|
||||
String coverUrl,
|
||||
String outputPath,
|
||||
) {
|
||||
String outputPath, {
|
||||
int maxDimension = 0,
|
||||
}) {
|
||||
return _invokeMap('downloadCoverToFile', {
|
||||
'cover_url': coverUrl,
|
||||
'output_path': outputPath,
|
||||
'max_dimension': maxDimension,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user