feat(tagging): write release identity tags

This commit is contained in:
zarzet
2026-08-18 19:04:26 +07:00
parent 48883d51d4
commit 290923e88f
21 changed files with 400 additions and 11 deletions
+7
View File
@@ -35,6 +35,7 @@ class Track {
final String? audioQuality;
final String? audioModes;
final bool? explicit;
final String? upc;
const Track({
required this.id,
@@ -66,6 +67,7 @@ class Track {
this.audioQuality,
this.audioModes,
this.explicit,
this.upc,
});
bool get isSingle {
@@ -145,6 +147,9 @@ class Track {
audioModes: data['audio_modes']?.toString(),
previewUrl: data['preview_url']?.toString(),
explicit: parseExplicitFlag(data['explicit']),
upc: normalizeOptionalString(
(data['upc'] ?? data['barcode'])?.toString(),
),
);
}
@@ -178,6 +183,7 @@ class Track {
String? audioQuality,
String? audioModes,
bool? explicit,
String? upc,
}) {
return Track(
id: id ?? this.id,
@@ -209,6 +215,7 @@ class Track {
audioQuality: audioQuality ?? this.audioQuality,
audioModes: audioModes ?? this.audioModes,
explicit: explicit ?? this.explicit,
upc: upc ?? this.upc,
);
}
+2
View File
@@ -40,6 +40,7 @@ Track _$TrackFromJson(Map<String, dynamic> json) => Track(
audioQuality: json['audioQuality'] as String?,
audioModes: json['audioModes'] as String?,
explicit: json['explicit'] as bool?,
upc: json['upc'] as String?,
);
Map<String, dynamic> _$TrackToJson(Track instance) => <String, dynamic>{
@@ -72,6 +73,7 @@ Map<String, dynamic> _$TrackToJson(Track instance) => <String, dynamic>{
'audioQuality': instance.audioQuality,
'audioModes': instance.audioModes,
'explicit': instance.explicit,
'upc': instance.upc,
};
ServiceAvailability _$ServiceAvailabilityFromJson(Map<String, dynamic> json) =>
@@ -726,6 +726,9 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
copyright: copyright ?? track.copyright ?? '',
composer: track.composer ?? '',
comment: track.comment ?? '',
explicit: track.explicit == true,
albumType: track.albumType ?? '',
upc: track.upc ?? '',
qobuzId: payloadQobuzId,
tidalId: payloadTidalId,
deezerId: deezerTrackId ?? '',
@@ -510,6 +510,12 @@ extension _DownloadQueueEmbedding on DownloadQueueNotifier {
final sourceIsrc = normalizeOptionalString(baseTrack.isrc);
final sourceReleaseDate = normalizeOptionalString(baseTrack.releaseDate);
final sourceComposer = normalizeOptionalString(baseTrack.composer);
final sourceAlbumType = normalizeOptionalString(baseTrack.albumType);
final sourceGenre = normalizeOptionalString(baseTrack.genre);
final sourceLabel = normalizeOptionalString(baseTrack.label);
final sourceCopyright = normalizeOptionalString(baseTrack.copyright);
final sourceComment = normalizeOptionalString(baseTrack.comment);
final sourceUpc = normalizeOptionalString(baseTrack.upc);
final backendGenre = normalizeOptionalString(
backendResult['genre']?.toString(),
);
@@ -522,6 +528,13 @@ extension _DownloadQueueEmbedding on DownloadQueueNotifier {
final backendComment = normalizeOptionalString(
backendResult['comment']?.toString(),
);
final backendAlbumType = normalizeOptionalString(
backendResult['album_type']?.toString(),
);
final backendUpc = normalizeOptionalString(
(backendResult['upc'] ?? backendResult['barcode'])?.toString(),
);
final backendExplicit = backendResult['explicit'] == true;
final resolvedTotalTracks = _resolvePositiveMetadataInt(
baseTrack.totalTracks,
backendTotalTracks,
@@ -554,7 +567,14 @@ extension _DownloadQueueEmbedding on DownloadQueueNotifier {
(sourceAlbumArtist == null &&
resolvedAlbumArtist == null &&
backendAlbumArtist != null) ||
(sourceComposer == null && backendComposer != null);
(sourceComposer == null && backendComposer != null) ||
(sourceAlbumType == null && backendAlbumType != null) ||
(sourceGenre == null && backendGenre != null) ||
(sourceLabel == null && backendLabel != null) ||
(sourceCopyright == null && backendCopyright != null) ||
(sourceComment == null && backendComment != null) ||
(baseTrack.explicit != true && backendExplicit) ||
(sourceUpc == null && backendUpc != null);
if (!hasOverrides) {
return baseTrack;
@@ -578,18 +598,21 @@ extension _DownloadQueueEmbedding on DownloadQueueNotifier {
releaseDate: sourceReleaseDate ?? backendYear,
deezerId: baseTrack.deezerId,
availability: baseTrack.availability,
albumType: baseTrack.albumType,
albumType: sourceAlbumType ?? backendAlbumType,
totalTracks: resolvedTotalTracks,
composer: sourceComposer ?? backendComposer,
genre: baseTrack.genre ?? backendGenre,
label: baseTrack.label ?? backendLabel,
copyright: baseTrack.copyright ?? backendCopyright,
comment: baseTrack.comment ?? backendComment,
genre: sourceGenre ?? backendGenre,
label: sourceLabel ?? backendLabel,
copyright: sourceCopyright ?? backendCopyright,
comment: sourceComment ?? backendComment,
source: baseTrack.source,
itemType: baseTrack.itemType,
audioQuality: baseTrack.audioQuality,
audioModes: baseTrack.audioModes,
explicit: baseTrack.explicit,
explicit: baseTrack.explicit == true || backendExplicit
? true
: baseTrack.explicit,
upc: sourceUpc ?? backendUpc,
);
}
@@ -690,6 +713,19 @@ extension _DownloadQueueEmbedding on DownloadQueueNotifier {
if (track.composer != null && track.composer!.isNotEmpty) {
metadata['COMPOSER'] = track.composer!;
}
if (track.isExplicit) {
metadata['ITUNESADVISORY'] = '1';
}
final resolvedAlbumType = track.albumType;
if (resolvedAlbumType != null && resolvedAlbumType.isNotEmpty) {
metadata['RELEASETYPE'] = resolvedAlbumType.toLowerCase();
if (resolvedAlbumType.toLowerCase() == 'compilation') {
metadata['COMPILATION'] = '1';
}
}
if (track.upc != null && track.upc!.isNotEmpty) {
metadata['BARCODE'] = track.upc!;
}
final lyricsMode = settings.lyricsMode;
final extensionState = ref.read(extensionProvider);
@@ -857,6 +893,12 @@ extension _DownloadQueueEmbedding on DownloadQueueNotifier {
'disc_number': track.discNumber!.toString(),
if (track.totalDiscs != null && track.totalDiscs! > 0)
'disc_total': track.totalDiscs!.toString(),
if (track.isExplicit) 'explicit': '1',
if (track.albumType != null && track.albumType!.isNotEmpty)
'album_type': track.albumType!,
if (track.upc != null && track.upc!.isNotEmpty) 'upc': track.upc!,
if (track.albumType?.toLowerCase() == 'compilation')
'compilation': '1',
'cover_path': ?validCover,
if (shouldEmbedLyrics && lrcContent != null) ...{
'lyrics': lrcContent,
@@ -362,7 +362,12 @@ class _DownloadRun {
itemType: trackToDownload.itemType,
audioQuality: trackToDownload.audioQuality,
audioModes: trackToDownload.audioModes,
explicit: trackToDownload.explicit,
explicit:
parseExplicitFlag(data['explicit']) ??
trackToDownload.explicit,
upc:
(data['upc'] ?? data['barcode'])?.toString() ??
trackToDownload.upc,
);
_log.d(
'Metadata enriched: Track ${trackToDownload.trackNumber}, Disc ${trackToDownload.discNumber}, ISRC ${trackToDownload.isrc}, AlbumType ${trackToDownload.albumType}',
@@ -39,6 +39,9 @@ class DownloadRequestPayload {
final String copyright;
final String composer;
final String comment;
final bool explicit;
final String albumType;
final String upc;
final String tidalId;
final String qobuzId;
final String deezerId;
@@ -98,6 +101,9 @@ class DownloadRequestPayload {
this.copyright = '',
this.composer = '',
this.comment = '',
this.explicit = false,
this.albumType = '',
this.upc = '',
this.tidalId = '',
this.qobuzId = '',
this.deezerId = '',
@@ -159,6 +165,9 @@ class DownloadRequestPayload {
'copyright': copyright,
'composer': composer,
'comment': comment,
'explicit': explicit,
'album_type': albumType,
'upc': upc,
'tidal_id': tidalId,
'qobuz_id': qobuzId,
'deezer_id': deezerId,
@@ -224,6 +233,9 @@ class DownloadRequestPayload {
copyright: copyright,
composer: composer,
comment: comment,
explicit: explicit,
albumType: albumType,
upc: upc,
tidalId: tidalId,
qobuzId: qobuzId,
deezerId: deezerId,