mirror of
https://github.com/spotiflacapp/SpotiFLAC-Mobile.git
synced 2026-06-01 03:15:17 +07:00
feat: add skipLyrics manifest field for extensions to opt out of lyrics fetching
This commit is contained in:
parent
59f2fe880a
commit
ac711efadc
4 changed files with 81 additions and 5 deletions
|
|
@ -908,6 +908,7 @@ func (m *ExtensionManager) GetInstalledExtensionsJSON() (string, error) {
|
|||
HasDownloadProvider bool `json:"has_download_provider"`
|
||||
HasLyricsProvider bool `json:"has_lyrics_provider"`
|
||||
SkipMetadataEnrichment bool `json:"skip_metadata_enrichment"`
|
||||
SkipLyrics bool `json:"skip_lyrics"`
|
||||
SearchBehavior *SearchBehaviorConfig `json:"search_behavior,omitempty"`
|
||||
TrackMatching *TrackMatchingConfig `json:"track_matching,omitempty"`
|
||||
PostProcessing *PostProcessingConfig `json:"post_processing,omitempty"`
|
||||
|
|
@ -965,6 +966,7 @@ func (m *ExtensionManager) GetInstalledExtensionsJSON() (string, error) {
|
|||
HasDownloadProvider: ext.Manifest.IsDownloadProvider(),
|
||||
HasLyricsProvider: ext.Manifest.IsLyricsProvider(),
|
||||
SkipMetadataEnrichment: ext.Manifest.SkipMetadataEnrichment,
|
||||
SkipLyrics: ext.Manifest.SkipLyrics,
|
||||
SearchBehavior: ext.Manifest.SearchBehavior,
|
||||
TrackMatching: ext.Manifest.TrackMatching,
|
||||
PostProcessing: ext.Manifest.PostProcessing,
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ type ExtensionManifest struct {
|
|||
QualityOptions []QualityOption `json:"qualityOptions,omitempty"`
|
||||
MinAppVersion string `json:"minAppVersion,omitempty"`
|
||||
SkipMetadataEnrichment bool `json:"skipMetadataEnrichment,omitempty"`
|
||||
SkipLyrics bool `json:"skipLyrics,omitempty"`
|
||||
SkipBuiltInFallback bool `json:"skipBuiltInFallback,omitempty"`
|
||||
SearchBehavior *SearchBehaviorConfig `json:"searchBehavior,omitempty"`
|
||||
URLHandler *URLHandlerConfig `json:"urlHandler,omitempty"`
|
||||
|
|
|
|||
|
|
@ -2215,6 +2215,27 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
return _isrcRegex.hasMatch(value.toUpperCase());
|
||||
}
|
||||
|
||||
/// Returns true if any enabled extension matching [source] or [service]
|
||||
/// declares `skipLyrics: true` in its manifest.
|
||||
bool _shouldSkipLyrics(
|
||||
ExtensionState extensionState,
|
||||
String? source,
|
||||
String? service,
|
||||
) {
|
||||
final candidates = <String>{};
|
||||
if (source != null && source.isNotEmpty) {
|
||||
candidates.add(source.trim().toLowerCase());
|
||||
}
|
||||
if (service != null && service.isNotEmpty) {
|
||||
candidates.add(service.trim().toLowerCase());
|
||||
}
|
||||
if (candidates.isEmpty) return false;
|
||||
return extensionState.extensions.any(
|
||||
(e) =>
|
||||
e.enabled && e.skipLyrics && candidates.contains(e.id.toLowerCase()),
|
||||
);
|
||||
}
|
||||
|
||||
String _newQueueItemId(Track track, {Set<String>? takenIds}) {
|
||||
final trimmedIsrc = track.isrc?.trim();
|
||||
final trimmedTrackId = track.id.trim();
|
||||
|
|
@ -3227,6 +3248,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
String? genre,
|
||||
String? label,
|
||||
String? copyright,
|
||||
String? downloadService,
|
||||
bool writeExternalLrc = true,
|
||||
}) async {
|
||||
final settings = ref.read(settingsProvider);
|
||||
|
|
@ -3314,11 +3336,19 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
_log.d('Metadata map content: $metadata');
|
||||
|
||||
final lyricsMode = settings.lyricsMode;
|
||||
final extensionState = ref.read(extensionProvider);
|
||||
final skipLyrics = _shouldSkipLyrics(
|
||||
extensionState,
|
||||
track.source,
|
||||
downloadService,
|
||||
);
|
||||
final shouldEmbedLyrics =
|
||||
settings.embedLyrics &&
|
||||
!skipLyrics &&
|
||||
(lyricsMode == 'embed' || lyricsMode == 'both');
|
||||
final shouldSaveExternalLyrics =
|
||||
settings.embedLyrics &&
|
||||
!skipLyrics &&
|
||||
(lyricsMode == 'external' || lyricsMode == 'both');
|
||||
final shouldFetchLyrics = shouldEmbedLyrics || shouldSaveExternalLyrics;
|
||||
String? lrcContent;
|
||||
|
|
@ -3453,6 +3483,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
String? genre,
|
||||
String? label,
|
||||
String? copyright,
|
||||
String? downloadService,
|
||||
}) async {
|
||||
final settings = ref.read(settingsProvider);
|
||||
if (!settings.embedMetadata) {
|
||||
|
|
@ -3541,9 +3572,16 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
_log.d('MP3 Metadata map content: $metadata');
|
||||
|
||||
final lyricsMode = settings.lyricsMode;
|
||||
final shouldEmbed = lyricsMode == 'embed' || lyricsMode == 'both';
|
||||
final mp3ExtState = ref.read(extensionProvider);
|
||||
final mp3SkipLyrics = _shouldSkipLyrics(
|
||||
mp3ExtState,
|
||||
track.source,
|
||||
downloadService,
|
||||
);
|
||||
final shouldEmbed =
|
||||
!mp3SkipLyrics && (lyricsMode == 'embed' || lyricsMode == 'both');
|
||||
final shouldSaveExternal =
|
||||
lyricsMode == 'external' || lyricsMode == 'both';
|
||||
!mp3SkipLyrics && (lyricsMode == 'external' || lyricsMode == 'both');
|
||||
|
||||
if (settings.embedLyrics && (shouldEmbed || shouldSaveExternal)) {
|
||||
try {
|
||||
|
|
@ -3639,6 +3677,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
String? genre,
|
||||
String? label,
|
||||
String? copyright,
|
||||
String? downloadService,
|
||||
}) async {
|
||||
final settings = ref.read(settingsProvider);
|
||||
if (!settings.embedMetadata) {
|
||||
|
|
@ -3724,9 +3763,16 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
_log.d('Opus Metadata map content: $metadata');
|
||||
|
||||
final lyricsMode = settings.lyricsMode;
|
||||
final shouldEmbed = lyricsMode == 'embed' || lyricsMode == 'both';
|
||||
final opusExtState = ref.read(extensionProvider);
|
||||
final opusSkipLyrics = _shouldSkipLyrics(
|
||||
opusExtState,
|
||||
track.source,
|
||||
downloadService,
|
||||
);
|
||||
final shouldEmbed =
|
||||
!opusSkipLyrics && (lyricsMode == 'embed' || lyricsMode == 'both');
|
||||
final shouldSaveExternal =
|
||||
lyricsMode == 'external' || lyricsMode == 'both';
|
||||
!opusSkipLyrics && (lyricsMode == 'external' || lyricsMode == 'both');
|
||||
|
||||
if (settings.embedLyrics && (shouldEmbed || shouldSaveExternal)) {
|
||||
try {
|
||||
|
|
@ -4685,7 +4731,14 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
quality: quality,
|
||||
embedMetadata: metadataEmbeddingEnabled,
|
||||
artistTagMode: settings.artistTagMode,
|
||||
embedLyrics: metadataEmbeddingEnabled && settings.embedLyrics,
|
||||
embedLyrics:
|
||||
metadataEmbeddingEnabled &&
|
||||
settings.embedLyrics &&
|
||||
!_shouldSkipLyrics(
|
||||
extensionState,
|
||||
trackToDownload.source,
|
||||
item.service,
|
||||
),
|
||||
embedMaxQualityCover:
|
||||
metadataEmbeddingEnabled && settings.maxQualityCover,
|
||||
trackNumber: normalizedTrackNumber,
|
||||
|
|
@ -5010,6 +5063,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
genre: backendGenre ?? genre,
|
||||
label: backendLabel ?? label,
|
||||
copyright: backendCopyright,
|
||||
downloadService: item.service,
|
||||
);
|
||||
} else {
|
||||
await _embedMetadataToOpus(
|
||||
|
|
@ -5018,6 +5072,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
genre: backendGenre ?? genre,
|
||||
label: backendLabel ?? label,
|
||||
copyright: backendCopyright,
|
||||
downloadService: item.service,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -5104,6 +5159,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
genre: backendGenre ?? genre,
|
||||
label: backendLabel ?? label,
|
||||
copyright: backendCopyright,
|
||||
downloadService: item.service,
|
||||
writeExternalLrc: false,
|
||||
);
|
||||
|
||||
|
|
@ -5197,6 +5253,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
genre: backendGenre ?? genre,
|
||||
label: backendLabel ?? label,
|
||||
copyright: backendCopyright,
|
||||
downloadService: item.service,
|
||||
);
|
||||
} else {
|
||||
await _embedMetadataToOpus(
|
||||
|
|
@ -5205,6 +5262,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
genre: backendGenre ?? genre,
|
||||
label: backendLabel ?? label,
|
||||
copyright: backendCopyright,
|
||||
downloadService: item.service,
|
||||
);
|
||||
}
|
||||
_log.d('Metadata embedded successfully');
|
||||
|
|
@ -5275,6 +5333,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
genre: backendGenre ?? genre,
|
||||
label: backendLabel ?? label,
|
||||
copyright: backendCopyright,
|
||||
downloadService: item.service,
|
||||
);
|
||||
_log.d('Metadata and cover embedded successfully');
|
||||
} catch (e) {
|
||||
|
|
@ -5340,6 +5399,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
genre: backendGenre ?? genre,
|
||||
label: backendLabel ?? label,
|
||||
copyright: backendCopyright,
|
||||
downloadService: item.service,
|
||||
);
|
||||
} else if (isOpusFile) {
|
||||
await _embedMetadataToOpus(
|
||||
|
|
@ -5348,6 +5408,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
genre: backendGenre ?? genre,
|
||||
label: backendLabel ?? label,
|
||||
copyright: backendCopyright,
|
||||
downloadService: item.service,
|
||||
);
|
||||
} else {
|
||||
await _embedMetadataAndCover(
|
||||
|
|
@ -5356,6 +5417,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
genre: backendGenre ?? genre,
|
||||
label: backendLabel ?? label,
|
||||
copyright: backendCopyright,
|
||||
downloadService: item.service,
|
||||
writeExternalLrc: false,
|
||||
);
|
||||
}
|
||||
|
|
@ -5420,6 +5482,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
genre: backendGenre ?? genre,
|
||||
label: backendLabel ?? label,
|
||||
copyright: backendCopyright,
|
||||
downloadService: item.service,
|
||||
);
|
||||
_log.d('Local FLAC metadata embedding completed');
|
||||
} catch (e) {
|
||||
|
|
@ -5500,6 +5563,11 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
|||
final shouldSaveExternalLrc =
|
||||
metadataEmbeddingEnabled &&
|
||||
settings.embedLyrics &&
|
||||
!_shouldSkipLyrics(
|
||||
extensionState,
|
||||
trackToDownload.source,
|
||||
item.service,
|
||||
) &&
|
||||
(lyricsMode == 'external' || lyricsMode == 'both');
|
||||
if (shouldSaveExternalLrc &&
|
||||
effectiveSafMode &&
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ class Extension {
|
|||
final bool hasDownloadProvider;
|
||||
final bool hasLyricsProvider;
|
||||
final bool skipMetadataEnrichment;
|
||||
final bool skipLyrics;
|
||||
final SearchBehavior? searchBehavior;
|
||||
final URLHandler? urlHandler;
|
||||
final TrackMatching? trackMatching;
|
||||
|
|
@ -57,6 +58,7 @@ class Extension {
|
|||
this.hasDownloadProvider = false,
|
||||
this.hasLyricsProvider = false,
|
||||
this.skipMetadataEnrichment = false,
|
||||
this.skipLyrics = false,
|
||||
this.searchBehavior,
|
||||
this.urlHandler,
|
||||
this.trackMatching,
|
||||
|
|
@ -94,6 +96,7 @@ class Extension {
|
|||
hasLyricsProvider: json['has_lyrics_provider'] as bool? ?? false,
|
||||
skipMetadataEnrichment:
|
||||
json['skip_metadata_enrichment'] as bool? ?? false,
|
||||
skipLyrics: json['skip_lyrics'] as bool? ?? false,
|
||||
searchBehavior: json['search_behavior'] != null
|
||||
? SearchBehavior.fromJson(
|
||||
json['search_behavior'] as Map<String, dynamic>,
|
||||
|
|
@ -134,6 +137,7 @@ class Extension {
|
|||
bool? hasDownloadProvider,
|
||||
bool? hasLyricsProvider,
|
||||
bool? skipMetadataEnrichment,
|
||||
bool? skipLyrics,
|
||||
SearchBehavior? searchBehavior,
|
||||
URLHandler? urlHandler,
|
||||
TrackMatching? trackMatching,
|
||||
|
|
@ -159,6 +163,7 @@ class Extension {
|
|||
hasLyricsProvider: hasLyricsProvider ?? this.hasLyricsProvider,
|
||||
skipMetadataEnrichment:
|
||||
skipMetadataEnrichment ?? this.skipMetadataEnrichment,
|
||||
skipLyrics: skipLyrics ?? this.skipLyrics,
|
||||
searchBehavior: searchBehavior ?? this.searchBehavior,
|
||||
urlHandler: urlHandler ?? this.urlHandler,
|
||||
trackMatching: trackMatching ?? this.trackMatching,
|
||||
|
|
|
|||
Loading…
Reference in a new issue