Ejemplo n.º 1
0
 def _get_auto_playlists(self):
     try:
         logger.debug("YTMusic loading auto playlists")
         response = self.api._send_request("browse", {})
         tab = nav(response, SINGLE_COLUMN_TAB)
         browse = parse_auto_playlists(nav(tab, SECTION_LIST))
         if "continuations" in tab["sectionListRenderer"]:
             request_func = lambda additionalParams: self.api._send_request(
                 "browse", {}, additionalParams)
             parse_func = lambda contents: parse_auto_playlists(contents)
             browse.extend(
                 get_continuations(
                     tab["sectionListRenderer"],
                     "sectionListContinuation",
                     100,
                     request_func,
                     parse_func,
                 ))
         # Delete empty sections
         for i in range(len(browse) - 1, 0, -1):
             if len(browse[i]["items"]) == 0:
                 browse.pop(i)
         logger.info("YTMusic loaded %d auto playlists sections",
                     len(browse))
         self.library.ytbrowse = browse
     except Exception:
         logger.exception("YTMusic failed to load auto playlists")
     return None
Ejemplo n.º 2
0
 def _get_auto_playlists(self):
     try:
         logger.debug('YoutubeMusic loading auto playlists')
         response = self.api._send_request('browse', {})
         tab = nav(response, SINGLE_COLUMN_TAB)
         browse = parse_auto_playlists(nav(tab, SECTION_LIST))
         if 'continuations' in tab['sectionListRenderer']:
             request_func = lambda additionalParams: self.api._send_request(
                 'browse', {}, additionalParams)
             parse_func = lambda contents: parse_auto_playlists(contents)
             browse.extend(
                 get_continuations(tab['sectionListRenderer'],
                                   'sectionListContinuation', 100,
                                   request_func, parse_func))
         # Delete empty sections
         for i in range(len(browse) - 1, 0, -1):
             if len(browse[i]['items']) == 0:
                 browse.pop(i)
         logger.debug('YoutubeMusic loaded %d auto playlists sections',
                      len(browse))
         self.library.ytbrowse = browse
     except Exception:
         logger.exception('YoutubeMusic failed to load auto playlists')
     return (None)
Ejemplo n.º 3
0
def parse_auto_playlists(res):
    browse = []
    for sect in res:
        car = []
        if "musicImmersiveCarouselShelfRenderer" in sect:
            car = nav(sect, ["musicImmersiveCarouselShelfRenderer"])
        elif "musicCarouselShelfRenderer" in sect:
            car = nav(sect, ["musicCarouselShelfRenderer"])
        else:
            continue
        stitle = nav(car, CAROUSEL_TITLE + ["text"]).strip()
        browse.append({
            "name":
            stitle,
            "uri":
            "ytmusic:auto:" + hashlib.md5(stitle.encode("utf-8")).hexdigest(),
            "items": [],
        })
        for item in nav(car, ["contents"]):
            brId = nav(
                item,
                ["musicTwoRowItemRenderer"] + TITLE + NAVIGATION_BROWSE_ID,
                True,
            )
            if brId is None or brId == "VLLM":
                continue
            pagetype = nav(
                item,
                [
                    "musicTwoRowItemRenderer",
                    "navigationEndpoint",
                    "browseEndpoint",
                    "browseEndpointContextSupportedConfigs",
                    "browseEndpointContextMusicConfig",
                    "pageType",
                ],
                True,
            )
            ititle = nav(item,
                         ["musicTwoRowItemRenderer"] + TITLE_TEXT).strip()
            if pagetype == "MUSIC_PAGE_TYPE_PLAYLIST":
                if "subtitle" in item["musicTwoRowItemRenderer"]:
                    ititle += " ("
                    for st in item["musicTwoRowItemRenderer"]["subtitle"][
                            "runs"]:
                        ititle += st["text"]
                    ititle += ")"
                browse[-1]["items"].append({
                    "type": "playlist",
                    "uri": f"ytmusic:playlist:{brId}",
                    "name": ititle,
                })
            elif pagetype == "MUSIC_PAGE_TYPE_ARTIST":
                browse[-1]["items"].append({
                    "type": "artist",
                    "uri": f"ytmusic:artist:{brId}",
                    "name": ititle + " (Artist)",
                })
            elif pagetype == "MUSIC_PAGE_TYPE_ALBUM":
                artist = nav(
                    item,
                    [
                        "musicTwoRowItemRenderer", "subtitle", "runs", -1,
                        "text"
                    ],
                    True,
                )
                ctype = nav(
                    item,
                    ["musicTwoRowItemRenderer", "subtitle", "runs", 0, "text"],
                    True,
                )
                if artist is not None:
                    browse[-1]["items"].append({
                        "type":
                        "album",
                        "uri":
                        f"ytmusic:album:{brId}",
                        "name":
                        artist + " - " + ititle + " (" + ctype + ")",
                    })
                else:
                    browse[-1]["items"].append({
                        "type":
                        "album",
                        "uri":
                        f"ytmusic:album:{brId}",
                        "name":
                        ititle + " (" + ctype + ")",
                    })
    return browse
Ejemplo n.º 4
0
 def browse(self, uri):
     if not uri:
         return []
     logger.debug("YoutubeMusic browsing uri \"%s\"", uri)
     if uri == "youtubemusic:root":
         dirs = []
         if self.backend.auth:
             dirs += [
                 Ref.directory(uri="youtubemusic:artist", name="Artists"),
                 Ref.directory(uri="youtubemusic:album", name="Albums"),
             ]
             if self.backend.liked_songs:
                 dirs.append(
                     Ref.directory(uri="youtubemusic:liked",
                                   name="Liked Songs"))
             if self.backend.history:
                 dirs.append(
                     Ref.directory(uri="youtubemusic:history",
                                   name="Recently Played"))
             if self.backend.subscribed_artist_limit:
                 dirs.append(
                     Ref.directory(uri="youtubemusic:subscriptions",
                                   name="Subscriptions"))
         dirs.append(
             Ref.directory(uri="youtubemusic:watch",
                           name="Similar to last played"))
         if self.backend.mood_genre:
             dirs.append(
                 Ref.directory(uri="youtubemusic:mood",
                               name="Mood and Genre Playlists"))
         if self.backend._auto_playlist_refresh_rate:
             dirs.append(
                 Ref.directory(uri="youtubemusic:auto",
                               name="Auto Playlists"))
         return (dirs)
     elif uri == "youtubemusic:subscriptions" and self.backend.subscribed_artist_limit:
         try:
             subs = self.backend.api.get_library_subscriptions(
                 limit=self.backend.subscribed_artist_limit)
             logger.debug("YoutubeMusic found %d artists in subscriptions",
                          len(subs))
             return [
                 Ref.artist(uri=f"youtubemusic:artist:{a['browseId']}",
                            name=a["artist"]) for a in subs
             ]
         except Exception:
             logger.exception(
                 "YoutubeMusic failed getting artists from subscriptions")
     elif uri == "youtubemusic:artist":
         try:
             library_artists = [
                 Ref.artist(uri=f"youtubemusic:artist:{a['browseId']}",
                            name=a["artist"])
                 for a in self.backend.api.get_library_artists(limit=100)
             ]
             logger.debug("YoutubeMusic found %d artists in library",
                          len(library_artists))
         except Exception:
             logger.exception(
                 "YoutubeMusic failed getting artists from library")
             library_artists = []
         if self.backend.auth:
             try:
                 upload_artists = [
                     Ref.artist(
                         uri=f"youtubemusic:artist:{a['browseId']}:upload",
                         name=a["artist"])
                     for a in self.backend.api.get_library_upload_artists(
                         limit=100)
                 ]
                 logger.debug("YoutubeMusic found %d uploaded artists",
                              len(upload_artists))
             except Exception:
                 logger.exception(
                     "YoutubeMusic failed getting uploaded artists")
                 upload_artists = []
         else:
             upload_artists = []
         return library_artists + upload_artists
     elif uri == "youtubemusic:album":
         try:
             library_albums = [
                 Ref.album(uri=f"youtubemusic:album:{a['browseId']}",
                           name=a["title"])
                 for a in self.backend.api.get_library_albums(limit=100)
             ]
             logger.debug("YoutubeMusic found %d albums in library",
                          len(library_albums))
         except Exception:
             logger.exception(
                 "YoutubeMusic failed getting albums from library")
             library_albums = []
         if self.backend.auth:
             try:
                 upload_albums = [
                     Ref.album(
                         uri=f"youtubemusic:album:{a['browseId']}:upload",
                         name=a["title"])
                     for a in self.backend.api.get_library_upload_albums(
                         limit=100)
                 ]
                 logger.debug("YoutubeMusic found %d uploaded albums",
                              len(upload_albums))
             except Exception:
                 logger.exception(
                     "YoutubeMusic failed getting uploaded albums")
                 upload_albums = []
         else:
             upload_albums = []
         return library_albums + upload_albums
     elif uri == "youtubemusic:liked":
         try:
             res = self.backend.api.get_liked_songs(
                 limit=self.backend.playlist_item_limit)
             tracks = self.playlistToTracks(res)
             logger.debug("YoutubeMusic found %d liked songs",
                          len(res["tracks"]))
             return [Ref.track(uri=t.uri, name=t.name) for t in tracks]
         except Exception:
             logger.exception("YoutubeMusic failed getting liked songs")
     elif uri == "youtubemusic:history":
         try:
             res = self.backend.api.get_history()
             tracks = self.playlistToTracks({'tracks': res})
             logger.debug("YoutubeMusic found %d songs from recent history",
                          len(res))
             return [Ref.track(uri=t.uri, name=t.name) for t in tracks]
         except Exception:
             logger.exception(
                 "YoutubeMusic failed getting listening history")
     elif uri == "youtubemusic:watch":
         try:
             playback = self.backend.playback
             if playback.last_id is not None:
                 track_id = playback.last_id
             elif self.backend.auth:
                 hist = self.backend.api.get_history()
                 track_id = hist[0]['videoId']
             if track_id:
                 res = self.backend.api.get_watch_playlist(
                     track_id, limit=self.backend.playlist_item_limit)
                 if 'tracks' in res:
                     logger.debug(
                         "YoutubeMusic found %d watch songs for \"%s\"",
                         len(res["tracks"]), track_id)
                     res['tracks'].pop(0)
                     tracks = self.playlistToTracks(res)
                     return [
                         Ref.track(uri=t.uri, name=t.name) for t in tracks
                     ]
         except Exception:
             logger.exception("YoutubeMusic failed getting watch songs")
     elif uri == "youtubemusic:mood":
         try:
             logger.debug('YoutubeMusic loading mood/genre playlists')
             moods = {}
             response = self.backend.api._send_request(
                 'browse', {"browseId": "FEmusic_moods_and_genres"})
             for sect in nav(response, SINGLE_COLUMN_TAB + SECTION_LIST):
                 for cat in nav(sect, ['gridRenderer', 'items']):
                     title = nav(cat, [
                         'musicNavigationButtonRenderer', 'buttonText',
                         'runs', 0, 'text'
                     ]).strip()
                     endpnt = nav(cat, [
                         'musicNavigationButtonRenderer', 'clickCommand',
                         'browseEndpoint', 'browseId'
                     ])
                     params = nav(cat, [
                         'musicNavigationButtonRenderer', 'clickCommand',
                         'browseEndpoint', 'params'
                     ])
                     moods[title] = {
                         'name': title,
                         'uri': 'youtubemusic:mood:' + params + ':' + endpnt
                     }
             return [
                 Ref.directory(uri=moods[a]['uri'], name=moods[a]['name'])
                 for a in sorted(moods.keys())
             ]
         except Exception:
             logger.exception(
                 'YoutubeMusic failed to load mood/genre playlists')
     elif uri.startswith("youtubemusic:mood:"):
         try:
             ret = []
             _, _, params, endpnt = uri.split(':')
             response = self.backend.api._send_request(
                 'browse', {
                     "browseId": endpnt,
                     "params": params
                 })
             for sect in nav(response, SINGLE_COLUMN_TAB + SECTION_LIST):
                 key = []
                 if 'gridRenderer' in sect:
                     key = ['gridRenderer', 'items']
                 elif 'musicCarouselShelfRenderer' in sect:
                     key = ['musicCarouselShelfRenderer', 'contents']
                 elif 'musicImmersiveCarouselShelfRenderer' in sect:
                     key = [
                         'musicImmersiveCarouselShelfRenderer', 'contents'
                     ]
                 if len(key):
                     for item in nav(sect, key):
                         title = nav(item, ['musicTwoRowItemRenderer'] +
                                     TITLE_TEXT).strip()
                         #                           if 'subtitle' in item['musicTwoRowItemRenderer']:
                         #                               title += ' ('
                         #                               for st in item['musicTwoRowItemRenderer']['subtitle']['runs']:
                         #                                   title += st['text']
                         #                               title += ')'
                         brId = nav(item, ['musicTwoRowItemRenderer'] +
                                    NAVIGATION_BROWSE_ID)
                         ret.append(
                             Ref.playlist(
                                 uri=f"youtubemusic:playlist:{brId}",
                                 name=title))
             return (ret)
         except Exception:
             logger.exception(
                 'YoutubeMusic failed getting mood/genre playlist "%s"',
                 uri)
     elif uri == "youtubemusic:auto" and self.backend._auto_playlist_refresh_rate:
         try:
             return [
                 Ref.directory(uri=a['uri'], name=a['name'])
                 for a in self.ytbrowse
             ]
         except Exception:
             logger.exception('YoutubeMusic failed getting auto playlists')
     elif uri.startswith("youtubemusic:auto:"
                         ) and self.backend._auto_playlist_refresh_rate:
         try:
             for a in self.ytbrowse:
                 if a['uri'] == uri:
                     ret = []
                     for i in a['items']:
                         if i['type'] == 'playlist':
                             ret.append(
                                 Ref.playlist(uri=i['uri'], name=i['name']))
                             logger.debug("playlist: %s - %s", i['name'],
                                          i['uri'])
                         elif i['type'] == 'artist':
                             ret.append(
                                 Ref.artist(uri=i['uri'], name=i['name']))
                             logger.debug("artist: %s - %s", i['name'],
                                          i['uri'])
                         elif i['type'] == 'album':
                             ret.append(
                                 Ref.album(uri=i['uri'], name=i['name']))
                             logger.debug("album: %s - %s", i['name'],
                                          i['uri'])
                     return (ret)
         except Exception:
             logger.exception(
                 'YoutubeMusic failed getting auto playlist "%s"', uri)
     elif uri.startswith("youtubemusic:artist:"):
         bId, upload = parse_uri(uri)
         if upload:
             try:
                 res = self.backend.api.get_library_upload_artist(bId)
                 tracks = self.uploadArtistToTracks(res)
                 logger.debug(
                     "YoutubeMusic found %d songs for uploaded artist \"%s\"",
                     len(res), res[0]["artist"]["name"])
                 return [Ref.track(uri=t.uri, name=t.name) for t in tracks]
             except Exception:
                 logger.exception(
                     "YoutubeMusic failed getting tracks for uploaded artist \"%s\"",
                     bId)
         else:
             try:
                 res = self.backend.api.get_artist(bId)
                 tracks = self.artistToTracks(res)
                 logger.debug(
                     "YoutubeMusic found %d songs for artist \"%s\" in library",
                     len(res["songs"]), res["name"])
                 return [Ref.track(uri=t.uri, name=t.name) for t in tracks]
             except Exception:
                 logger.exception(
                     "YoutubeMusic failed getting tracks for artist \"%s\"",
                     bId)
     elif uri.startswith("youtubemusic:album:"):
         bId, upload = parse_uri(uri)
         if upload:
             try:
                 res = self.backend.api.get_library_upload_album(bId)
                 tracks = self.uploadAlbumToTracks(res, bId)
                 logger.debug(
                     "YoutubeMusic found %d songs for uploaded album \"%s\"",
                     len(res["tracks"]), res["title"])
                 return [Ref.track(uri=t.uri, name=t.name) for t in tracks]
             except Exception:
                 logger.exception(
                     "YoutubeMusic failed getting tracks for uploaded album \"%s\"",
                     bId)
         else:
             try:
                 res = self.backend.api.get_album(bId)
                 tracks = self.albumToTracks(res, bId)
                 logger.debug(
                     "YoutubeMusic found %d songs for album \"%s\" in library",
                     len(res["tracks"]), res["title"])
                 return [Ref.track(uri=t.uri, name=t.name) for t in tracks]
             except Exception:
                 logger.exception(
                     "YoutubeMusic failed getting tracks for album \"%s\"",
                     bId)
     elif uri.startswith("youtubemusic:playlist:"):
         bId, upload = parse_uri(uri)
         try:
             res = self.backend.api.get_playlist(
                 bId, limit=self.backend.playlist_item_limit)
             tracks = self.playlistToTracks(res)
             return [Ref.track(uri=t.uri, name=t.name) for t in tracks]
         except Exception:
             logger.exception(
                 "YoutubeMusic failed to get tracks from playlist '%s'",
                 bId)
     return []
Ejemplo n.º 5
0
def parse_auto_playlists(res):
    browse = []
    for sect in res:
        car = []
        if 'musicImmersiveCarouselShelfRenderer' in sect:
            car = nav(sect, ['musicImmersiveCarouselShelfRenderer'])
        elif 'musicCarouselShelfRenderer' in sect:
            car = nav(sect, ['musicCarouselShelfRenderer'])
        else:
            continue
        stitle = nav(car, CAROUSEL_TITLE + ['text']).strip()
        browse.append({
            'name':
            stitle,
            'uri':
            'youtubemusic: auto: ' +
            hashlib.md5(stitle.encode('utf-8')).hexdigest(),
            'items': []
        })
        for item in nav(car, ['contents']):
            brId = nav(item, ['musicTwoRowItemRenderer'] + TITLE +
                       NAVIGATION_BROWSE_ID, True)
            if brId is None or brId == 'VLLM':
                continue
            pagetype = nav(item, [
                'musicTwoRowItemRenderer', 'navigationEndpoint',
                'browseEndpoint', 'browseEndpointContextSupportedConfigs',
                'browseEndpointContextMusicConfig', 'pageType'
            ], True)
            ititle = nav(item,
                         ['musicTwoRowItemRenderer'] + TITLE_TEXT).strip()
            if pagetype == 'MUSIC_PAGE_TYPE_PLAYLIST':
                if 'subtitle' in item['musicTwoRowItemRenderer']:
                    ititle += ' ('
                    for st in item['musicTwoRowItemRenderer']['subtitle'][
                            'runs']:
                        ititle += st['text']
                    ititle += ')'
                browse[-1]['items'].append({
                    'type': 'playlist',
                    'uri': f"youtubemusic: playlist: {brId}",
                    'name': ititle
                })
            elif pagetype == 'MUSIC_PAGE_TYPE_ARTIST':
                browse[-1]['items'].append({
                    'type': 'artist',
                    'uri': f"youtubemusic: artist: {brId}",
                    'name': ititle + ' (Artist)'
                })
            elif pagetype == 'MUSIC_PAGE_TYPE_ALBUM':
                artist = nav(item, [
                    'musicTwoRowItemRenderer', 'subtitle', 'runs', -1, 'text'
                ], True)
                ctype = nav(
                    item,
                    ['musicTwoRowItemRenderer', 'subtitle', 'runs', 0, 'text'],
                    True)
                if artist is not None:
                    browse[-1]['items'].append({
                        'type':
                        'album',
                        'uri':
                        f"youtubemusic: album: {brId}",
                        'name':
                        artist + ' - ' + ititle + ' (' + ctype + ')'
                    })
                else:
                    browse[-1]['items'].append({
                        'type':
                        'album',
                        'uri':
                        f"youtubemusic: album: {brId}",
                        'name':
                        ititle + ' (' + ctype + ')'
                    })
    return (browse)