diff --git a/mopidy_ytmusic/backend.py b/mopidy_ytmusic/backend.py index cab38c9..0311f57 100644 --- a/mopidy_ytmusic/backend.py +++ b/mopidy_ytmusic/backend.py @@ -75,7 +75,7 @@ def __init__(self, config, audio): self.playback = YTMusicPlaybackProvider(audio=audio, backend=self) self.library = YTMusicLibraryProvider(backend=self) - if self.auth: + if self.auth or self.oauth: self.playlists = YTMusicPlaylistsProvider(backend=self) def on_start(self): diff --git a/mopidy_ytmusic/library.py b/mopidy_ytmusic/library.py index fe926c0..1c66490 100644 --- a/mopidy_ytmusic/library.py +++ b/mopidy_ytmusic/library.py @@ -469,7 +469,7 @@ def lookup(self, uri): ) if (bId) in self.TRACKS: return [self.TRACKS[bId]] - else: + elif bId: return [self.getTrack(bId)] return [] @@ -904,20 +904,18 @@ def albumToTracks(self, album, bId): date = "0000" artists = [] artistname = "" + def artistList(artists): + return list(map(lambda artist: Artist(name=artist["name"], sortname=artist["name"], uri=f"ytmusic:artist:{artist['id']}"), artists)) + if "artists" in album: if type(album["artists"]) is list: - artist = album["artists"][0] + al = album["artists"] else: - artist = album["artists"] - # if artist["id"] not in self.ARTISTS: - self.ARTISTS[artist["id"]] = Artist( - uri=f"ytmusic:artist:{artist['id']}", - name=artist["name"], - sortname=artist["name"], - musicbrainz_id="", - ) - artists.append(self.ARTISTS[artist["id"]]) - artistname = artist["name"] + al = [album["artists"]] + if any(al): + artistname = al[0]["name"] + artists = artistList(al) + # if bId not in self.ALBUMS: self.ALBUMS[bId] = Album( uri=f"ytmusic:album:{bId}", @@ -934,7 +932,7 @@ def albumToTracks(self, album, bId): # if song["videoId"] not in self.TRACKS: try: length = [int(i) for i in song["duration"].split(":")] - except ValueError: + except (ValueError, KeyError): length = [0, 0] # Annoying workaround for Various Artists if ( @@ -944,7 +942,8 @@ def albumToTracks(self, album, bId): ): songartists = artists else: - songartists = [Artist(name=artistname)] + songartists = artistList(song["artists"]) + self.TRACKS[song["videoId"]] = Track( uri=f"ytmusic:track:{song['videoId']}", name=song["title"], @@ -995,6 +994,10 @@ def parseSearch(self, results, field=None, queries=[]): sartists = set() for result in results: if result["resultType"] == "song": + if result["category"] != "Songs": + logger.debug("Found a funny album playlist thing, skipping: " + repr(result)) + continue + if field == "track" and not any( q.casefold() == result["title"].casefold() for q in queries ): @@ -1087,109 +1090,118 @@ def parseSearch(self, results, field=None, queries=[]): 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"ytmusic: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"], + artists = [] + if "category" in result and result["category"] == "Top result": + artists += list(map(lambda x: x["id"], result["artists"])) + else: + artists.append(result["browseId"]) + + for artistid in artists: + try: + artistq = self.backend.api.get_artist(artistid) + if artistid not in self.ARTISTS: + self.ARTISTS[artistid] = Artist( + uri=f"ytmusic:artist:{artistid}", + name=artistq["name"], + sortname=artistq["name"], + musicbrainz_id="", ) - for album in albums: - if album["browseId"] not in self.ALBUMS: - self.ALBUMS[album["browseId"]] = Album( - uri=f"ytmusic: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"ytmusic:album:{album['browseId']}", - name=album["title"], - artists=[ - self.ARTISTS[result["browseId"]] - ], - date=album["year"], + sartists.add(self.ARTISTS[artistid]) + if "albums" in artistq and artistq["albums"]: + if "params" in artistq["albums"]: + albums = self.backend.api.get_artist_albums( + artistq["albums"]["browseId"], + artistq["albums"]["params"], + ) + if "results" in albums: + albums = albums["results"] + for album in albums: + if album["browseId"] not in self.ALBUMS: + self.ALBUMS[album["browseId"]] = Album( + uri=f"ytmusic:album:{album['browseId']}", + name=album["title"], + artists=[ + self.ARTISTS[artistid] + ], + 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"ytmusic:album:{album['browseId']}", + name=album["title"], + artists=[ + self.ARTISTS[artistid] + ], + 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"ytmusic:album:{single['browseId']}", + name=single["title"], + artists=[self.ARTISTS[artistid]], + date=single["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"ytmusic: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[ + 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 and song["album"]: + if ( song["album"]["id"] - ] = Album( - uri=f"ytmusic:album:{song['album']['id']}", - name=song["album"]["name"], + not in self.ALBUMS + ): + self.ALBUMS[ + song["album"]["id"] + ] = Album( + uri=f"ytmusic:album:{song['album']['id']}", + name=song["album"]["name"], + artists=[ + self.ARTISTS[ + artistid + ] + ], + date="1999", + musicbrainz_id="", + ) + album = self.ALBUMS[song["album"]["id"]] + if song["videoId"] not in self.TRACKS: + self.TRACKS[song["videoId"]] = Track( + uri=f"ytmusic:track:{song['videoId']}", + name=song["title"], artists=[ - self.ARTISTS[ - result["browseId"] - ] + self.ARTISTS[artistid] ], - date="1999", + album=album, + composers=[], + performers=[], + genre="", + track_no=None, + disc_no=None, + date="0000", + length=None, + bitrate=0, + comment="", musicbrainz_id="", + last_modified=None, ) - album = self.ALBUMS[song["album"]["id"]] - if song["videoId"] not in self.TRACKS: - self.TRACKS[song["videoId"]] = Track( - uri=f"ytmusic: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( - "YTMusic failed parsing artist %s", result["artist"] - ) + tracks.add(self.TRACKS[song["videoId"]]) + except Exception: + logger.exception( + "YTMusic failed parsing artist %s", artistid + ) tracks = list(tracks) for track in tracks: bId, _ = parse_uri(track.uri) diff --git a/mopidy_ytmusic/playback.py b/mopidy_ytmusic/playback.py index f4c4bb9..93b6160 100644 --- a/mopidy_ytmusic/playback.py +++ b/mopidy_ytmusic/playback.py @@ -20,9 +20,9 @@ def update_cipher(self, playerurl): self.Youtube_Player_URL = playerurl response = requests.get("https://music.youtube.com" + playerurl) m = re.search(r"signatureTimestamp[:=](\d+)", response.text) + self.PyTubeCipher = Cipher(js=response.text) if m: self.signatureTimestamp = m.group(1) - self.PyTubeCipher = Cipher(js=response.text) logger.debug( "YTMusic updated signatureTimestamp to %s", self.signatureTimestamp, diff --git a/pyproject.toml b/pyproject.toml index b2a121b..7981d9a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ license = "Apache-2.0" python = "^3.7" Mopidy = "^3" pytube = "^12.1.0" -ytmusicapi = ">=0.22.0, <0.30.0" +ytmusicapi = ">=1.5.4" [tool.poetry.dev-dependencies] flake8 = "^3.8.4" diff --git a/requirements.txt b/requirements.txt index 0321ae2..1f98b83 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,9 +16,7 @@ mopidy==3.4.0 ; python_version >= "3.7" and python_version < "4.0" \ pykka==3.1.1 ; python_version >= "3.7" and python_version < "4.0" \ --hash=sha256:14ce223a55e6d62de6657f9b2b129e6ac785f731eccc5e26059e5254beca3cfb \ --hash=sha256:d00de35f719afeedf8d362854d99cee6ed257663bbf7e4789344b77b73d55f28 -pytube==12.1.0 ; python_version >= "3.7" and python_version < "4.0" \ - --hash=sha256:6de1f3a4cb125dd6ff912598c7e88a866325a63cc91755cae616f53c40ae5503 \ - --hash=sha256:c2e4b1ffdf9eca4c287f881557a6b4f98dd287ecfa06e2e5d5936d39c5f4d8da +pytube==15.0.0 ; python_version >= "3.7" and python_version < "4.0" \ requests==2.28.1 ; python_version >= "3.7" and python_version < "4" \ --hash=sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983 \ --hash=sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349 @@ -43,9 +41,7 @@ typing-extensions==4.4.0 ; python_version >= "3.7" and python_version < "3.8" \ urllib3==1.26.13 ; python_version >= "3.7" and python_version < "4" \ --hash=sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc \ --hash=sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8 -ytmusicapi==0.23.0 ; python_version >= "3.7" and python_version < "4.0" \ - --hash=sha256:d182c8ba03fd3a73c25447f37fb36e5761ce05df92e3757517e5f99f84b312d4 \ - --hash=sha256:def49b1406e0c7fb8b1cdd48a1eab5b55dff6877def68c8b1712a2ef8f9b5e7f +ytmusicapi>=1.5.4 ; python_version >= "3.7" and python_version < "4.0" \ zipp==3.11.0 ; python_version >= "3.7" and python_version < "3.8" \ --hash=sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa \ --hash=sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766 diff --git a/setup.py b/setup.py index 2c75924..c7d1b66 100644 --- a/setup.py +++ b/setup.py @@ -7,8 +7,8 @@ install_requires = [ "Mopidy>=3,<4", - "pytube>=12.1.0", - "ytmusicapi>=0.22.0,<2.0.0", + "pytube==15.0.0", + "ytmusicapi>=1.5.4", ] entry_points = {"mopidy.ext": ["ytmusic = mopidy_ytmusic:Extension"]}