diff --git a/lib/models/track.dart b/lib/models/track.dart index 244a7a65..e4d850c2 100644 --- a/lib/models/track.dart +++ b/lib/models/track.dart @@ -21,6 +21,7 @@ class Track { final ServiceAvailability? availability; final String? source; final String? albumType; + final int? totalTracks; final String? itemType; const Track({ @@ -41,10 +42,21 @@ class Track { this.availability, this.source, this.albumType, + this.totalTracks, this.itemType, }); - bool get isSingle => albumType == 'single' || albumType == 'ep'; + bool get isSingle { + switch (albumType?.toLowerCase()) { + case 'single': + return true; + case 'ep': + final count = totalTracks; + return count == null || count <= 1; + default: + return false; + } + } bool get isAlbumItem => itemType == 'album'; diff --git a/lib/models/track.g.dart b/lib/models/track.g.dart index f640cfe7..5e361ab6 100644 --- a/lib/models/track.g.dart +++ b/lib/models/track.g.dart @@ -28,6 +28,7 @@ Track _$TrackFromJson(Map json) => Track( ), source: json['source'] as String?, albumType: json['albumType'] as String?, + totalTracks: (json['totalTracks'] as num?)?.toInt(), itemType: json['itemType'] as String?, ); @@ -49,6 +50,7 @@ Map _$TrackToJson(Track instance) => { 'availability': instance.availability, 'source': instance.source, 'albumType': instance.albumType, + 'totalTracks': instance.totalTracks, 'itemType': instance.itemType, }; diff --git a/lib/providers/download_queue_provider.dart b/lib/providers/download_queue_provider.dart index afb2e81c..18348f96 100644 --- a/lib/providers/download_queue_provider.dart +++ b/lib/providers/download_queue_provider.dart @@ -2362,6 +2362,7 @@ class DownloadQueueNotifier extends Notifier { deezerId: baseTrack.deezerId, availability: baseTrack.availability, albumType: baseTrack.albumType, + totalTracks: baseTrack.totalTracks, source: baseTrack.source, ); } @@ -3274,6 +3275,8 @@ class DownloadQueueNotifier extends Notifier { albumType: (data['album_type'] as String?) ?? trackToDownload.albumType, + totalTracks: + data['total_tracks'] as int? ?? trackToDownload.totalTracks, source: trackToDownload.source, ); _log.d( @@ -3488,6 +3491,7 @@ class DownloadQueueNotifier extends Notifier { deezerId: deezerTrackId, availability: trackToDownload.availability, albumType: trackToDownload.albumType, + totalTracks: trackToDownload.totalTracks, source: trackToDownload.source, ); _log.d( diff --git a/lib/providers/track_provider.dart b/lib/providers/track_provider.dart index 5adae7d0..1c3974c2 100644 --- a/lib/providers/track_provider.dart +++ b/lib/providers/track_provider.dart @@ -816,6 +816,7 @@ class TrackNotifier extends Notifier { discNumber: track.discNumber, releaseDate: track.releaseDate, albumType: track.albumType, + totalTracks: track.totalTracks, source: track.source, availability: ServiceAvailability( tidal: availability['tidal'] as bool? ?? false, @@ -897,6 +898,8 @@ class TrackNotifier extends Notifier { trackNumber: data['track_number'] as int?, discNumber: data['disc_number'] as int?, releaseDate: data['release_date'] as String?, + albumType: data['album_type'] as String?, + totalTracks: data['total_tracks'] as int?, ); } @@ -919,6 +922,7 @@ class TrackNotifier extends Notifier { trackNumber: data['track_number'] as int?, discNumber: data['disc_number'] as int?, releaseDate: data['release_date']?.toString(), + totalTracks: data['total_tracks'] as int?, source: source ?? data['source']?.toString() ?? diff --git a/lib/screens/album_screen.dart b/lib/screens/album_screen.dart index ba8d9d1d..f3f22790 100644 --- a/lib/screens/album_screen.dart +++ b/lib/screens/album_screen.dart @@ -224,6 +224,8 @@ class _AlbumScreenState extends ConsumerState { trackNumber: data['track_number'] as int?, discNumber: data['disc_number'] as int?, releaseDate: data['release_date'] as String?, + albumType: data['album_type'] as String?, + totalTracks: data['total_tracks'] as int?, ); } diff --git a/lib/screens/artist_screen.dart b/lib/screens/artist_screen.dart index 8ad6bf03..06fc5063 100644 --- a/lib/screens/artist_screen.dart +++ b/lib/screens/artist_screen.dart @@ -294,7 +294,7 @@ class _ArtistScreenState extends ConsumerState { } } - Track _parseTrack(Map data) { + Track _parseTrack(Map data, {ArtistAlbum? album}) { int durationMs = 0; final durationValue = data['duration_ms']; if (durationValue is int) { @@ -307,18 +307,22 @@ class _ArtistScreenState extends ConsumerState { id: (data['spotify_id'] ?? data['id'] ?? '').toString(), name: (data['name'] ?? '').toString(), artistName: (data['artists'] ?? data['artist'] ?? '').toString(), - albumName: (data['album_name'] ?? data['album'] ?? '').toString(), - albumArtist: data['album_artist']?.toString(), + albumName: (data['album_name'] ?? data['album'] ?? album?.name ?? '') + .toString(), + albumArtist: data['album_artist']?.toString() ?? widget.artistName, artistId: (data['artist_id'] ?? data['artistId'])?.toString() ?? widget.artistId, - albumId: data['album_id']?.toString(), - coverUrl: (data['cover_url'] ?? data['images'])?.toString(), + albumId: data['album_id']?.toString() ?? album?.id, + coverUrl: (data['cover_url'] ?? data['images'] ?? album?.coverUrl) + ?.toString(), isrc: data['isrc']?.toString(), duration: (durationMs / 1000).round(), trackNumber: data['track_number'] as int?, discNumber: data['disc_number'] as int?, releaseDate: data['release_date']?.toString(), + albumType: data['album_type']?.toString() ?? album?.albumType, + totalTracks: data['total_tracks'] as int? ?? album?.totalTracks, source: data['provider_id']?.toString(), ); } @@ -669,7 +673,9 @@ class _ArtistScreenState extends ConsumerState { List albums, ) { final albumsOnly = albums.where((a) => a.albumType == 'album').toList(); - final singles = albums.where((a) => a.albumType == 'single').toList(); + final singles = albums + .where((a) => a.albumType == 'single' || a.albumType == 'ep') + .toList(); final totalTracks = albums.fold(0, (sum, a) => sum + a.totalTracks); final albumTracks = albumsOnly.fold( @@ -940,7 +946,7 @@ class _ArtistScreenState extends ConsumerState { if (result != null && result['tracks'] != null) { final tracksList = result['tracks'] as List; return tracksList - .map((t) => _parseTrack(t as Map)) + .map((t) => _parseTrack(t as Map, album: album)) .toList(); } } else if (album.id.startsWith('deezer:')) { @@ -961,7 +967,7 @@ class _ArtistScreenState extends ConsumerState { if (result != null && result['tracks'] != null) { final tracksList = result['tracks'] as List; return tracksList - .map((t) => _parseTrack(t as Map)) + .map((t) => _parseTrack(t as Map, album: album)) .toList(); } @@ -970,7 +976,7 @@ class _ArtistScreenState extends ConsumerState { if (metadata['tracks'] != null) { final tracksList = metadata['tracks'] as List; return tracksList - .map((t) => _parseTrack(t as Map)) + .map((t) => _parseTrack(t as Map, album: album)) .toList(); } } @@ -1004,6 +1010,7 @@ class _ArtistScreenState extends ConsumerState { discNumber: data['disk_number'] as int? ?? data['disc_number'] as int?, releaseDate: album.releaseDate, albumType: album.albumType, + totalTracks: album.totalTracks, ); }