diff --git a/lib/models/album.dart b/lib/models/album.dart index aa4625b8..83af0b2a 100644 --- a/lib/models/album.dart +++ b/lib/models/album.dart @@ -24,11 +24,13 @@ class Album { required this.browseId, required this.artists, this.year, + this.description, this.audioPlaylistId, required this.thumbnailUrl}); final String browseId; final String? audioPlaylistId; final String title; + final String? description; final List>? artists; final String? year; final String thumbnailUrl; @@ -40,6 +42,7 @@ class Album { artists:json["artists"]!=null? List>.from(json["artists"]):[{'name':''}], year: json['year'], audioPlaylistId: json['audioPlaylistId'], + description: json['description'] ?? json["type"] ?? "Album", thumbnailUrl: Thumbnail(json["thumbnails"][0]["url"]).medium); Map toJson()=>{ @@ -48,6 +51,7 @@ class Album { 'artists':artists, 'year':year, 'audioPlaylistId':audioPlaylistId, + 'description':description, 'thumbnails':[{'url':thumbnailUrl}] }; } diff --git a/lib/models/playlist.dart b/lib/models/playlist.dart index 88d8c9b2..3524e112 100644 --- a/lib/models/playlist.dart +++ b/lib/models/playlist.dart @@ -39,7 +39,7 @@ class Playlist { title: json["title"], playlistId: json["playlistId"] ?? json["browseId"], thumbnailUrl: Thumbnail(json["thumbnails"][0]["url"]).medium, - description: json["description"], + description: json["description"] ?? "Playlist", songCount: json['itemCount'], isPipedPlaylist: json["isPipedPlaylist"] ?? false, isCloudPlaylist: json["isCloudPlaylist"] ?? true); diff --git a/lib/services/music_service.dart b/lib/services/music_service.dart index 68d4e644..d99de092 100644 --- a/lib/services/music_service.dart +++ b/lib/services/music_service.dart @@ -331,32 +331,55 @@ class MusicServices extends getx.GetxService { data['browseId'] = browseId; Map response = (await _sendRequest('browse', data)).data; if (playlistId != null) { - Map header = nav(response, [ - 'contents', - "twoColumnBrowseResultsRenderer", - 'tabs', - 0, - "tabRenderer", - "content", - "sectionListRenderer", - "contents", - 0, - "musicResponsiveHeaderRenderer" - ]); - - Map results = nav(response, [ - "contents", - "twoColumnBrowseResultsRenderer", - "secondaryContents", - "sectionListRenderer", - "contents", - 0, - "musicPlaylistShelfRenderer", - ]); + Map header = + nav(response, ['header', "musicDetailHeaderRenderer"]) ?? + nav(response, [ + 'contents', + "twoColumnBrowseResultsRenderer", + 'tabs', + 0, + "tabRenderer", + "content", + "sectionListRenderer", + "contents", + 0, + "musicResponsiveHeaderRenderer" + ]); + + Map results = nav( + response, + [ + 'contents', + "singleColumnBrowseResultsRenderer", + "tabs", + 0, + "tabRenderer", + "content", + 'sectionListRenderer', + 'contents', + 0, + "musicPlaylistShelfRenderer" + ], + ) ?? + nav(response, [ + "contents", + "twoColumnBrowseResultsRenderer", + "secondaryContents", + "sectionListRenderer", + "contents", + 0, + "musicPlaylistShelfRenderer", + ]); Map playlist = {'id': results['playlistId']}; playlist['title'] = nav(header, title_text); - playlist['thumbnails'] = nav(header, thumnail_cropped); + playlist['thumbnails'] = nav(header, thumnail_cropped) ?? + nav(header, [ + "thumbnail", + "musicThumbnailRenderer", + "thumbnail", + "thumbnails" + ]); playlist["description"] = nav(header, description); int runCount = header['subtitle']['runs'].length; if (runCount > 1) { @@ -408,17 +431,32 @@ class MusicServices extends getx.GetxService { //album content final album = parseAlbumHeader(response); dynamic results = nav( - response, - [ - 'contents', - "twoColumnBrowseResultsRenderer", - "secondaryContents", - 'sectionListRenderer', - 'contents', - 0, - 'musicShelfRenderer' - ], - ); + response, + [ + 'contents', + "twoColumnBrowseResultsRenderer", + "secondaryContents", + 'sectionListRenderer', + 'contents', + 0, + 'musicShelfRenderer' + ], + ) ?? + nav( + response, + [ + 'contents', + "singleColumnBrowseResultsRenderer", + "tabs", + 0, + "tabRenderer", + "content", + 'sectionListRenderer', + 'contents', + 0, + 'musicShelfRenderer' + ], + ); album['tracks'] = parsePlaylistItems(results['contents'], artistsM: album['artists'], diff --git a/lib/services/nav_parser.dart b/lib/services/nav_parser.dart index 9ff6e57c..a62b054d 100644 --- a/lib/services/nav_parser.dart +++ b/lib/services/nav_parser.dart @@ -202,15 +202,23 @@ dynamic parseVideo(dynamic result) { } dynamic parseSingle(dynamic result) { + dynamic year; + try { + year = int.parse(nav(result, subtitle)); + } catch (e) { + year = nav(result, ["subtitle", "runs", 2, "text"]); + } return Album.fromJson({ 'title': nav(result, title_text), 'artists': [ {'name': 'Single'} ], 'audioPlaylistId': nav(result, audio_watch_playlist_id), - 'year': nav(result, subtitle), + 'year': "${year ?? ""}", 'browseId': nav(result, ['title', 'runs', 0, ...navigation_browse_id]), - 'thumbnails': nav(result, thumbnail_renderer) + 'thumbnails': nav(result, thumbnail_renderer), + 'description': + (nav(result, ["subtitle", "runs"])).map((run) => run['text']).join('') }); } @@ -256,7 +264,6 @@ Map parseSongRuns(List runs) { parsed['artists'].add(item); } } else { - // note: YT uses non-breaking space \xa0 to separate number and magnitude RegExp regExp = RegExp(r"^\d([^ ])* [^ ]*$"); if (regExp.hasMatch(text) && i > 0) { parsed['views'] = text.split(' ')[0]; @@ -281,7 +288,9 @@ Album parseAlbum(Map result, {bool reqAlbumObj = true}) { 'title': nav(result, title_text), 'browseId': nav(result, n_title + navigation_browse_id), 'thumbnails': nav(result, thumbnail_renderer), - 'audioPlaylistId': nav(result, audio_watch_playlist_id) + 'audioPlaylistId': nav(result, audio_watch_playlist_id), + 'description': + (nav(result, ["subtitle", "runs"])).map((run) => run['text']).join('') //'isExplicit': nav(result, subtitle_badge_label, noneIfAbsent: true) != null, }; albumMap.addAll(artistInfo); @@ -696,6 +705,11 @@ dynamic parseSearchResult(Map data, } else if (resultType == 'album') { searchResult['type'] = getItemText(data, 1); searchResult['audioPlaylistId'] = nav(data, audio_watch_playlist_id); + try { + final list = data['flexColumns'][1] + ['musicResponsiveListItemFlexColumnRenderer']['text']['runs']; + searchResult['description'] = list.map((run) => run['text']).join(''); + } catch (e) {} } else if (resultType.contains('playlist')) { List flexItem = getFlexColumnItem(data, 1)['text']['runs']; bool hasAuthor = (flexItem.length == defaultOffset + 3); @@ -794,37 +808,44 @@ dynamic parseSearchResult(Map data, //parse album Header Map parseAlbumHeader(Map response) { Map header = nav(response, [ - 'contents', - "twoColumnBrowseResultsRenderer", - 'tabs', - 0, - "tabRenderer", - "content", - "sectionListRenderer", - "contents", - 0, - "musicResponsiveHeaderRenderer" - ]); + 'contents', + "twoColumnBrowseResultsRenderer", + 'tabs', + 0, + "tabRenderer", + "content", + "sectionListRenderer", + "contents", + 0, + "musicResponsiveHeaderRenderer" + ]) ?? + nav(response, ["header", "musicDetailHeaderRenderer"]); Map album = { 'title': nav(header, title_text), 'type': nav(header, subtitle), - 'thumbnails': nav(header, - ["thumbnail", "musicThumbnailRenderer", "thumbnail", "thumbnails"]) + 'thumbnails': nav(header, thumnail_cropped) ?? + nav(header, + ["thumbnail", "musicThumbnailRenderer", "thumbnail", "thumbnails"]) }; - if (header.containsKey("description")) { - album["description"] = nav(header, [ - "description", - "musicDescriptionShelfRenderer", - "description", - "runs", - 0, - "text" - ]); - } + album["description"] = nav(header, [ + "description", + "musicDescriptionShelfRenderer", + "description", + "runs", + 0, + "text" + ]) ?? + (nav(header, ["subtitle", "runs"])) + .map((item) => item.values.first) + .toList() + .join(" "); Map albumInfo = parseSongRuns(header['subtitle']['runs'].sublist(2)); + try { + albumInfo.addAll(parseSongRuns(header["straplineTextOne"]['runs'])); + } catch (e) {} album.addAll(albumInfo); if (header['secondSubtitle']['runs'].length > 1) { diff --git a/lib/ui/screens/PlaylistNAlbum/playlistnalbum_screen.dart b/lib/ui/screens/PlaylistNAlbum/playlistnalbum_screen.dart index 502d096f..13c86e3b 100644 --- a/lib/ui/screens/PlaylistNAlbum/playlistnalbum_screen.dart +++ b/lib/ui/screens/PlaylistNAlbum/playlistnalbum_screen.dart @@ -579,9 +579,7 @@ class PlaylistNAlbumScreen extends StatelessWidget { (!playListNAlbumScreenController.isAlbum && content.isCloudPlaylist)) ? Text( - playListNAlbumScreenController.isAlbum - ? content.artists[0]['name'] ?? "" - : content.description ?? "", + content.description, style: Theme.of(context).textTheme.titleSmall, ) : Obx( diff --git a/lib/ui/screens/PlaylistNAlbum/playlistnalbum_screen_controller.dart b/lib/ui/screens/PlaylistNAlbum/playlistnalbum_screen_controller.dart index 0a424081..c265e3dc 100644 --- a/lib/ui/screens/PlaylistNAlbum/playlistnalbum_screen_controller.dart +++ b/lib/ui/screens/PlaylistNAlbum/playlistnalbum_screen_controller.dart @@ -10,7 +10,6 @@ import '/services/piped_service.dart'; import '../../../utils/helper.dart'; import '/models/playlist.dart'; import '/models/album.dart'; -import '/models/thumbnail.dart'; import '../../../models/media_Item_builder.dart'; import '../../../services/music_service.dart'; import '../Library/library_controller.dart'; @@ -142,22 +141,12 @@ class PlayListNAlbumScreenController extends GetxController { if (isIdOnly) { if (isAlbum) { - final album = Album( - browseId: id, - artists: List>.from(content['artists']), - thumbnailUrl: Thumbnail(content['thumbnails'][0]['url']).high, - title: content['title'], - audioPlaylistId: content['audioPlaylistId'], - year: content['year']); + content['browseId'] = id; + final album =Album.fromJson(content); contentRenderer = album; } else { - final playlist = Playlist( - title: content['title'], - playlistId: id, - thumbnailUrl: Thumbnail(content['thumbnails'][0]['url']).high, - description: content['description'], - isCloudPlaylist: true, - songCount: (content['trackCount']).toString()); + content['playlistId'] = id; + final playlist = Playlist.fromJson(content); contentRenderer = playlist; } }