Ejemplo n.º 1
0
    def run(self, args, config):
        from ytmusicapi.ytmusic import YTMusic

        filepath = input(
            "Enter the path where you want to save auth.json [default=current dir]: "
        )
        if not filepath:
            filepath = os.getcwd()
        path = Path(filepath + '/auth.json')
        print('Using "' + str(path) + '"')
        if (path.exists()):
            print("File already exists!")
            return 1
        print(
            "Open Youtube Music, open developer tools (F12), go to Network tab,"
        )
        print(
            "right click on a POST request and choose \"Copy request headers\"."
        )
        print("Then paste (CTRL+SHIFT+V) them here and press CTRL+D.")
        try:
            print(YTMusic.setup(filepath=str(path)))
        except Exception:
            logger.exception("YoutubeMusic setup failed")
            return 1
        print("Authentication JSON data saved to {}".format(str(path)))
        print('')
        print('Update your mopidy.conf to reflect the new auth file:')
        print('   [youtubemusic]')
        print('   enabled=true')
        print('   auth_json=' + str(path))
        return 0
Ejemplo n.º 2
0
 def delete(self, uri):
     logger.debug("YoutubeMusic deleting playlist \"%s\"", uri)
     bId = parse_uri(uri)
     try:
         self.backend.api.delete_playlist(bId)
         return True
     except Exception:
         logger.exception("YoutubeMusic failed to delete playlist")
         return False
Ejemplo n.º 3
0
 def get_items(self, uri):
     bId = parse_uri(uri)
     logger.debug("YoutubeMusic getting playlist items for \"%s\"", bId)
     try:
         pls = self.backend.api.get_playlist(bId, limit=self.backend.playlist_item_limit)
     except Exception:
         logger.exception("YoutubeMusic failed getting playlist items")
         pls = None
     if pls:
         tracks = self.backend.library.playlistToTracks(pls)
         return [Ref.track(uri=t.uri, name=t.name) for t in tracks]
     return None
Ejemplo n.º 4
0
 def as_list(self):
     logger.debug("YoutubeMusic getting user playlists")
     refs = []
     try:
         playlists = self.backend.api.get_library_playlists(limit=100)
     except Exception:
         logger.exception("YoutubeMusic failed getting a list of playlists")
         playlists = []
     for pls in playlists:
         refs.append(Ref.playlist(
             uri=f"youtubemusic:playlist:{pls['playlistId']}", name=pls["title"],
         ))
     return refs
Ejemplo n.º 5
0
 def save(self, playlist):
     bId = parse_uri(playlist.uri)
     logger.debug("YoutubeMusic saving playlist \"%s\" \"%s\"", playlist.name, bId)
     try:
         pls = self.backend.api.get_playlist(bId, limit=self.backend.playlist_item_limit)
     except Exception:
         logger.exception("YoutubeMusic saving playlist failed")
         return None
     oldIds = set([t["videoId"] for t in pls["tracks"]])
     newIds = set([parse_uri(p.uri)[0] for p in playlist.tracks])
     common = oldIds & newIds
     remove = oldIds ^ common
     add = newIds ^ common
     if len(remove):
         logger.debug("YoutubeMusic removing items \"%s\" from playlist", remove)
         try:
             videos = [t for t in pls["tracks"] if t["videoId"] in remove]
             self.backend.api.remove_playlist_items(bId, videos)
         except Exception:
             logger.exception("YoutubeMusic failed removing items from playlist")
     if len(add):
         logger.debug("YoutubeMusic adding items \"%s\" to playlist", add)
         try:
             self.backend.api.add_playlist_items(bId, list(add))
         except Exception:
             logger.exception("YoutubeMusic failed adding items to playlist")
     if pls["title"] != playlist.name:
         logger.debug("Renaming playlist to \"%s\"", playlist.name)
         try:
             self.backend.api.edit_playlist(bId, title=playlist.name)
         except Exception:
             logger.exception("YoutubeMusic failed renaming playlist")
     return playlist
Ejemplo n.º 6
0
 def lookup(self, uri):
     bId = parse_uri(uri)
     logger.debug("YoutubeMusic looking up playlist \"%s\"", bId)
     try:
         pls = self.backend.api.get_playlist(bId, limit=self.backend.playlist_item_limit)
     except Exception:
         logger.exception("YoutubeMusic playlist lookup failed")
         pls = None
     if pls:
         tracks = self.backend.library.playlistToTracks(pls)
         return Playlist(
             uri=f"youtubemusic:playlist:{pls['id']}",
             name=pls["title"],
             tracks=tracks,
             last_modified=None,
         )
Ejemplo n.º 7
0
 def search(self, query=None, uris=None, exact=False):
     results = []
     logger.debug("YoutubeMusic searching for %s", query)
     if "any" in query:
         try:
             res = self.backend.api.search(" ".join(query["any"]),
                                           filter=None)
             results = self.parseSearch(res)
         except Exception:
             logger.exception(
                 "YoutubeMusic search failed for query \"any\"=\"%s\"",
                 " ".join(query["any"]))
     elif "track_name" in query:
         try:
             res = self.backend.api.search(" ".join(query["track_name"]),
                                           filter="songs")
             if exact:
                 results = self.parseSearch(res, "track",
                                            query["track_name"])
             else:
                 results = self.parseSearch(res)
         except Exception:
             logger.exception(
                 "YoutubeMusic search failed for query \"title\"=\"%s\"",
                 " ".join(query["track_name"]))
     elif "albumartist" in query or "artist" in query:
         q1 = ("albumartist" in query and query["albumartist"]) or []
         q2 = ("artist" in query and query["artist"]) or []
         try:
             res = self.backend.api.search(" ".join(q1 + q2),
                                           filter="artists")
             if exact:
                 results = self.parseSearch(res, "artist", q1 + q2)
             else:
                 results = self.parseSearch(res)
         except Exception:
             logger.exception(
                 "YoutubeMusic search failed for query \"artist\"=\"%s\"",
                 " ".join(q1 + q2))
     elif "album" in query:
         try:
             res = self.backend.api.search(" ".join(query["album"]),
                                           filter="albums")
             if exact:
                 results = self.parseSearch(res, "album", query["album"])
             else:
                 results = self.parseSearch(res)
         except Exception:
             logger.exception(
                 "YoutubeMusic search failed for query \"album\"=\"%s\"",
                 " ".join(query["album"]))
     else:
         logger.debug(
             "YoutubeMusic skipping search, unsupported field types \"%s\"",
             " ".join(query.keys()))
         return None
     return results
Ejemplo n.º 8
0
 def create(self, name):
     logger.debug("YoutubeMusic creating playlist \"%s\"", name)
     try:
         bId = self.backend.api.create_playlist(name, "")
     except Exception:
         logger.exception("YoutubeMusic playlist creation failed")
         bId = None
     if bId:
         uri = f"youtubemusic:playlist:{bId}"
         logger.debug("YoutubeMusic created playlist \"%s\"", uri)
         return Playlist(
             uri=uri,
             name=name,
             tracks=[],
             last_modified=None,
         )
     return None
Ejemplo n.º 9
0
 def lookup(self, uri):
     bId, _ = parse_uri(uri)
     if (uri.startswith("youtubemusic:album:")):
         try:
             res = self.backend.api.get_album(bId)
             tracks = self.albumToTracks(res, bId)
             return (tracks)
         except Exception:
             logger.exception(
                 "YoutubeMusic failed getting tracks for album \"%s\"", bId)
     elif (uri.startswith("youtubemusic:artist:")):
         try:
             res = self.backend.api.get_artist(bId)
             tracks = self.artistToTracks(res)
             return (tracks)
         except Exception:
             logger.exception(
                 "YoutubeMusic failed getting tracks for artist \"%s\"",
                 bId)
     elif (uri.startswith("youtubemusic:playlist:")):
         try:
             res = self.backend.api.get_playlist(
                 bId, limit=self.backend.playlist_item_limit)
             tracks = self.playlistToTracks(res)
             return (tracks)
         except Exception:
             logger.exception(
                 "YoutubeMusic failed getting tracks for playlist \"%s\"",
                 bId)
     elif (bId) in self.TRACKS:
         return [self.TRACKS[bId]]
     return []
Ejemplo n.º 10
0
 def get_distinct(self, field, query=None):
     ret = set()
     if field == "artist" or field == "albumartist":
         # try:
         #     uploads = self.backend.api.get_library_upload_artists(limit=100)
         # except Exception:
         #     logger.exception("YoutubeMusic failed getting uploaded artists")
         #     uploads = []
         #     pass
         try:
             library = self.backend.api.get_library_artists(
                 limit=self.backend.playlist_item_limit)
         except Exception:
             logger.exception(
                 "YoutubeMusic failed getting artists from library")
             library = []
             pass
         # for a in uploads:
         #     ret.add(a["artist"])
         for a in library:
             ret.add(a["artist"])
     # elif field == "album":
     #     try:
     #         uploads = self.backend.api.get_library_upload_albums(limit=self.backend.playlist_item_limit)
     #     except Exception:
     #         logger.exception("YoutubeMusic failed getting uploaded albums")
     #         uploads = []
     #         pass
     #     try:
     #         library = self.backend.api.get_library_albums(limit=self.backend.playlist_item_limit)
     #     except Exception:
     #         logger.exception("YoutubeMusic failed getting albums from library")
     #         library = []
     #         pass
     #     for a in uploads:
     #         ret.add(a["title"])
     #     for a in library:
     #         ret.add(a["title"])
     return ret
Ejemplo n.º 11
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.º 12
0
 def parseSearch(self, results, field=None, queries=[]):
     tracks = set()
     salbums = set()
     sartists = set()
     for result in results:
         if result["resultType"] == "song":
             if field == "track" and not any(
                     q.casefold() == result["title"].casefold()
                     for q in queries):
                 continue
             if result['videoId'] in self.TRACKS:
                 tracks.add(self.TRACKS[result['videoId']])
             else:
                 try:
                     length = [
                         int(i) for i in result["duration"].split(":")
                     ]
                 except ValueError:
                     length = [0, 0]
                 if result['videoId'] is None:
                     continue
                 if result['videoId'] not in self.TRACKS:
                     artists = []
                     for a in result['artists']:
                         if a['id'] not in self.ARTISTS:
                             self.ARTISTS[a['id']] = Artist(
                                 uri=f"youtubemusic:artist:{a['id']}",
                                 name=a["name"],
                                 sortname=a["name"],
                                 musicbrainz_id="",
                             )
                         artists.append(self.ARTISTS[a['id']])
                     album = None
                     if 'album' in result:
                         if result['album']['id'] not in self.ALBUMS:
                             self.ALBUMS[result['album']['id']] = Album(
                                 uri=
                                 f"youtubemusic:album:{result['album']['id']}",
                                 name=result["album"]["name"],
                                 artists=artists,
                                 num_tracks=None,
                                 num_discs=None,
                                 date="0000",
                                 musicbrainz_id="",
                             )
                             album = self.ALBUMS[result['album']['id']]
                     self.TRACKS[result['videoId']] = Track(
                         uri=f"youtubemusic:track:{result['videoId']}",
                         name=result["title"],
                         artists=artists,
                         album=album,
                         composers=[],
                         performers=[],
                         genre="",
                         track_no=None,
                         disc_no=None,
                         date="0000",
                         length=(length[0] * 60 * 1000) +
                         (length[1] * 1000),
                         bitrate=0,
                         comment="",
                         musicbrainz_id="",
                         last_modified=None,
                     )
                 tracks.add(self.TRACKS[result['videoId']])
         elif result["resultType"] == "album":
             if field == "album" and not any(
                     q.casefold() == result["title"].casefold()
                     for q in queries):
                 continue
             try:
                 album = self.backend.api.get_album(result["browseId"])
                 if result["browseId"] not in self.ALBUMS:
                     date = result['year']
                     self.ALBUMS[result['browseId']] = Album(
                         uri=f"youtubemusic:album:{result['browseId']}",
                         name=album["title"],
                         artists=[
                             Artist(
                                 uri="",
                                 name=result["artist"],
                                 sortname=result["artist"],
                                 musicbrainz_id="",
                             )
                         ],
                         num_tracks=int(album["trackCount"])
                         if str(album["trackCount"]).isnumeric() else None,
                         num_discs=None,
                         date=date,
                         musicbrainz_id="",
                     )
                 salbums.add(self.ALBUMS[result['browseId']])
             except Exception:
                 logger.exception("YoutubeMusic failed parsing album %s",
                                  result["title"])
         elif result["resultType"] == "artist":
             if field == "artist" and not any(
                     q.casefold() == result["artist"].casefold()
                     for q in queries):
                 continue
             try:
                 artistq = self.backend.api.get_artist(result["browseId"])
                 if result['browseId'] not in self.ARTISTS:
                     self.ARTISTS[result['browseId']] = Artist(
                         uri=f"youtubemusic:artist:{result['browseId']}",
                         name=artistq["name"],
                         sortname=artistq["name"],
                         musicbrainz_id="",
                     )
                 sartists.add(self.ARTISTS[result['browseId']])
                 if 'albums' in artistq:
                     if 'params' in artistq['albums']:
                         albums = self.backend.api.get_artist_albums(
                             artistq["channelId"],
                             artistq["albums"]["params"])
                         for album in albums:
                             if album['browseId'] not in self.ALBUMS:
                                 self.ALBUMS[album['browseId']] = Album(
                                     uri=
                                     f"youtubemusic:album:{album['browseId']}",
                                     name=album["title"],
                                     artists=[
                                         self.ARTISTS[result['browseId']]
                                     ],
                                     date=album['year'],
                                     musicbrainz_id="",
                                 )
                             salbums.add(self.ALBUMS[album['browseId']])
                     elif 'results' in artistq['albums']:
                         for album in artistq["albums"]["results"]:
                             if album['browseId'] not in self.ALBUMS:
                                 self.ALBUMS[album['browseId']] = Album(
                                     uri=
                                     f"youtubemusic:album:{album['browseId']}",
                                     name=album["title"],
                                     artists=[
                                         self.ARTISTS[result['browseId']]
                                     ],
                                     date=album['year'],
                                     musicbrainz_id="",
                                 )
                             salbums.add(self.ALBUMS[album['browseId']])
                 if 'singles' in artistq and 'results' in artistq['singles']:
                     for single in artistq['singles']['results']:
                         if single['browseId'] not in self.ALBUMS:
                             self.ALBUMS[single['browseId']] = Album(
                                 uri=
                                 f"youtubemusic:album:{single['browseId']}",
                                 name=single['title'],
                                 artists=[self.ARTISTS[result['browseId']]],
                                 date=single['year'],
                                 musicbrainz_id="",
                             )
                         salbums.add(self.ALBUMS[single['browseId']])
                 if 'songs' in artistq:
                     if 'results' in artistq['songs']:
                         for song in artistq['songs']['results']:
                             if song['videoId'] in self.TRACKS:
                                 tracks.add(self.TRACKS[song['videoId']])
                             else:
                                 album = None
                                 if 'album' in song:
                                     if song['album'][
                                             'id'] not in self.ALBUMS:
                                         self.ALBUMS[
                                             song['album']['id']] = Album(
                                                 uri=
                                                 f"youtubemusic:album:{song['album']['id']}",
                                                 name=song['album']['name'],
                                                 artists=[
                                                     self.ARTISTS[
                                                         result['browseId']]
                                                 ],
                                                 date='1999',
                                                 musicbrainz_id="",
                                             )
                                     album = self.ALBUMS[song['album']
                                                         ['id']]
                                 if song['videoId'] not in self.TRACKS:
                                     self.TRACKS[song['videoId']] = Track(
                                         uri=
                                         f"youtubemusic:track:{song['videoId']}",
                                         name=song['title'],
                                         artists=[
                                             self.ARTISTS[
                                                 result['browseId']]
                                         ],
                                         album=album,
                                         composers=[],
                                         performers=[],
                                         genre="",
                                         track_no=None,
                                         disc_no=None,
                                         date="0000",
                                         length=None,
                                         bitrate=0,
                                         comment="",
                                         musicbrainz_id="",
                                         last_modified=None,
                                     )
                                 tracks.add(self.TRACKS[song['videoId']])
             except Exception:
                 logger.exception("YoutubeMusic failed parsing artist %s",
                                  result["artist"])
     tracks = list(tracks)
     for track in tracks:
         bId, _ = parse_uri(track.uri)
         self.TRACKS[bId] = track
     logger.debug("YoutubeMusic search returned %d results",
                  len(tracks) + len(sartists) + len(salbums))
     return SearchResult(
         uri="youtubemusic:search",
         tracks=tracks,
         artists=list(sartists),
         albums=list(salbums),
     )
Ejemplo n.º 13
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 []