mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-08-26 12:52:40 +02:00
fix(playlist): ignore container title during album verification #519
This commit is contained in:
+15
-2
@@ -82,7 +82,11 @@ class Track {
|
||||
Map<String, dynamic> toJson() => _$TrackToJson(this);
|
||||
|
||||
/// Builds a [Track] from a backend/extension search payload map.
|
||||
factory Track.fromBackendMap(Map<String, dynamic> data, {String? source}) {
|
||||
factory Track.fromBackendMap(
|
||||
Map<String, dynamic> data, {
|
||||
String? source,
|
||||
String? playlistName,
|
||||
}) {
|
||||
final durationMs = extractDurationMs(data);
|
||||
|
||||
final itemType = data['item_type']?.toString();
|
||||
@@ -93,12 +97,21 @@ class Track {
|
||||
final preferredId = effectiveSource != null && effectiveSource.isNotEmpty
|
||||
? (nativeId.isNotEmpty ? nativeId : spotifyId)
|
||||
: (spotifyId.isNotEmpty ? spotifyId : nativeId);
|
||||
final rawAlbumName = (data['album_name'] ?? data['album'] ?? '').toString();
|
||||
final normalizedAlbumName = normalizeOptionalString(rawAlbumName);
|
||||
final normalizedPlaylistName = normalizeOptionalString(playlistName);
|
||||
final albumName =
|
||||
normalizedPlaylistName != null &&
|
||||
normalizedAlbumName?.toLowerCase() ==
|
||||
normalizedPlaylistName.toLowerCase()
|
||||
? ''
|
||||
: rawAlbumName;
|
||||
|
||||
return Track(
|
||||
id: preferredId,
|
||||
name: (data['name'] ?? '').toString(),
|
||||
artistName: (data['artists'] ?? data['artist'] ?? '').toString(),
|
||||
albumName: (data['album_name'] ?? data['album'] ?? '').toString(),
|
||||
albumName: albumName,
|
||||
albumArtist: data['album_artist']?.toString(),
|
||||
artistId: (data['artist_id'] ?? data['artistId'])?.toString(),
|
||||
albumId: data['album_id']?.toString(),
|
||||
|
||||
@@ -224,11 +224,13 @@ class TrackNotifier extends Notifier<TrackState> {
|
||||
} else if ((type == 'album' || type == 'playlist') &&
|
||||
result['tracks'] != null) {
|
||||
final trackList = result['tracks'] as List<dynamic>;
|
||||
final collectionName = result['name'] as String?;
|
||||
final tracks = trackList
|
||||
.map(
|
||||
(t) => Track.fromBackendMap(
|
||||
t as Map<String, dynamic>,
|
||||
source: extensionId,
|
||||
playlistName: type == 'playlist' ? collectionName : null,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
@@ -238,9 +240,9 @@ class TrackNotifier extends Notifier<TrackState> {
|
||||
albumId:
|
||||
(result['album'] as Map<String, dynamic>?)?['id'] as String?,
|
||||
albumName:
|
||||
result['name'] as String? ??
|
||||
collectionName ??
|
||||
(result['album'] as Map<String, dynamic>?)?['name'] as String?,
|
||||
playlistName: type == 'playlist' ? result['name'] as String? : null,
|
||||
playlistName: type == 'playlist' ? collectionName : null,
|
||||
coverUrl: normalizeCoverReference(result['cover_url']?.toString()),
|
||||
headerVideoUrl: normalizeRemoteHttpUrl(
|
||||
result['header_video']?.toString(),
|
||||
|
||||
@@ -1155,12 +1155,16 @@ class _ExtensionPlaylistScreenState
|
||||
}
|
||||
|
||||
Track _parseTrack(Map<String, dynamic> data) {
|
||||
final base = Track.fromBackendMap(data, source: widget.extensionId);
|
||||
final base = Track.fromBackendMap(
|
||||
data,
|
||||
source: widget.extensionId,
|
||||
playlistName: widget.playlistName,
|
||||
);
|
||||
return Track(
|
||||
id: (data['id'] ?? '').toString(),
|
||||
name: base.name,
|
||||
artistName: base.artistName,
|
||||
albumName: (data['album_name'] ?? '').toString(),
|
||||
albumName: base.albumName,
|
||||
artistId: base.artistId,
|
||||
albumId: base.albumId,
|
||||
coverUrl: _resolveTrackCoverUrl(
|
||||
|
||||
@@ -207,18 +207,25 @@ class _PlaylistScreenState extends ConsumerState<PlaylistScreen>
|
||||
|
||||
final playlistInfo = result['playlist_info'] as Map<String, dynamic>?;
|
||||
final owner = playlistInfo?['owner'] as Map<String, dynamic>?;
|
||||
final resolvedPlaylistName =
|
||||
(playlistInfo?['name'] ?? owner?['name'])?.toString() ??
|
||||
_playlistName;
|
||||
|
||||
final trackList = result['track_list'] as List<dynamic>? ?? [];
|
||||
final tracks = trackList
|
||||
.map((t) => Track.fromBackendMap(t as Map<String, dynamic>))
|
||||
.map(
|
||||
(t) => Track.fromBackendMap(
|
||||
t as Map<String, dynamic>,
|
||||
playlistName: resolvedPlaylistName,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
final headerVideo = playlistInfo?['header_video']?.toString();
|
||||
|
||||
setState(() {
|
||||
_fetchedTracks = tracks;
|
||||
_resolvedPlaylistName = (playlistInfo?['name'] ?? owner?['name'])
|
||||
?.toString();
|
||||
_resolvedPlaylistName = resolvedPlaylistName;
|
||||
_resolvedCoverUrl = (playlistInfo?['images'] ?? owner?['images'])
|
||||
?.toString();
|
||||
_resolvedHeaderVideoUrl =
|
||||
|
||||
@@ -443,6 +443,26 @@ void main() {
|
||||
expect(track.isExplicit, isTrue);
|
||||
});
|
||||
|
||||
test('does not treat a playlist container name as a track album', () {
|
||||
final playlistTrack = Track.fromBackendMap({
|
||||
'id': 'playlist-track-1',
|
||||
'name': 'Song',
|
||||
'artists': 'Artist',
|
||||
'album_name': ' Road Trip ',
|
||||
'duration_ms': 180000,
|
||||
}, playlistName: 'road trip');
|
||||
final releaseTrack = Track.fromBackendMap({
|
||||
'id': 'playlist-track-2',
|
||||
'name': 'Song',
|
||||
'artists': 'Artist',
|
||||
'album_name': 'Real Album',
|
||||
'duration_ms': 180000,
|
||||
}, playlistName: 'Road Trip');
|
||||
|
||||
expect(playlistTrack.albumName, isEmpty);
|
||||
expect(releaseTrack.albumName, 'Real Album');
|
||||
});
|
||||
|
||||
test('exposes collection, source, and quality flags', () {
|
||||
const album = Track(
|
||||
id: 'album-1',
|
||||
|
||||
Reference in New Issue
Block a user