diff --git a/.gitignore b/.gitignore index 210086e..083fed6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ .vscode **.json docs/build -**.cfg +test.cfg **.mp3 .coverage **/__pycache__/ diff --git a/tests/mixins/__init__.py b/tests/mixins/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/mixins/test_browsing.py b/tests/mixins/test_browsing.py index 817622f..8dea6d7 100644 --- a/tests/mixins/test_browsing.py +++ b/tests/mixins/test_browsing.py @@ -6,7 +6,7 @@ class TestBrowsing: def test_get_home(self, yt, yt_auth): result = yt.get_home() - assert len(result) == 2 + assert len(result) >= 2 result = yt_auth.get_home(limit=15) assert len(result) >= 15 diff --git a/tests/mixins/test_library.py b/tests/mixins/test_library.py index eda645a..ef79eac 100644 --- a/tests/mixins/test_library.py +++ b/tests/mixins/test_library.py @@ -107,5 +107,5 @@ def test_rate_playlist(self, yt_auth): assert "actions" in response def test_subscribe_artists(self, yt_auth): - yt_auth.subscribe_artists(["UCUDVBtnOQi4c7E8jebpjc9Q", "UCiMhD4jzUqG-IgPzUmmytRQ"]) - yt_auth.unsubscribe_artists(["UCUDVBtnOQi4c7E8jebpjc9Q", "UCiMhD4jzUqG-IgPzUmmytRQ"]) + yt_auth.subscribe_artists(["UCUDVBtnOQi4c7E8jebpjc9Q"]) + yt_auth.unsubscribe_artists(["UCUDVBtnOQi4c7E8jebpjc9Q"]) diff --git a/tests/mixins/test_search.py b/tests/mixins/test_search.py index 1587399..c145323 100644 --- a/tests/mixins/test_search.py +++ b/tests/mixins/test_search.py @@ -60,7 +60,7 @@ def test_search_top_result(self, yt): results = yt.search("fdsfsfsd") # issue 524 assert results[0]["category"] == "Top result" assert results[0]["resultType"] == "playlist" - assert results[0]["playlistId"] == "PLK3q5XTYSK60QH3gDypSu3n9OBz6H9HfV" + assert results[0]["playlistId"].startswith("PL") assert len(results[0]["author"]) > 0 def test_search_uploads(self, config, yt, yt_oauth): diff --git a/tests/test.example.cfg b/tests/test.example.cfg new file mode 100644 index 0000000..c593ea8 --- /dev/null +++ b/tests/test.example.cfg @@ -0,0 +1,38 @@ +[auth] +brand_account = 101234229123420379537 +brand_account_empty = 1123456629123420379537 +headers = headers_auth_json_as_string +headers_empty = headers_account_with_empty_library_as_json_as_string +browser_file = ./browser.json +oauth_file = ./oauth.json +headers_raw = raw_headers_pasted_from_browser + +[queries] +uploads_songs = query_gives_gt_20_songs +library_any = query_gives_gt_5_results +library_songs = query_gives_gt_10_songs +library_albums = query_gives_gte_5_albums +library_artists = query_gives_gte_1_artist +library_playlists = query_gives_gte_1_playlist + +[playlists] +own = owned_playlist_id +own_length = number_of_tracks_in_playlist + +[albums] +album_browse_id = sample_id_of_regionally_available_album +album_track_length = available_album_length + +[uploads] +file = song_in_tests_directory.mp3 +private_album_id = sample_id_of_private_album +private_artist_id = sample_id_of_private_artist +private_upload_id = sample_video_id_of_private_upload + +[limits] +library_playlists = 100 +library_songs = 200 +library_artists = 300 +library_subscriptions = 50 +library_upload_albums = 200 +library_upload_artists = 250 diff --git a/ytmusicapi/mixins/browsing.py b/ytmusicapi/mixins/browsing.py index b7386a3..390802a 100644 --- a/ytmusicapi/mixins/browsing.py +++ b/ytmusicapi/mixins/browsing.py @@ -424,7 +424,9 @@ def get_album_browse_id(self, audioPlaylistId: str) -> Optional[str]: params = {"list": audioPlaylistId} response = self._send_get_request(YTM_DOMAIN + "/playlist", params) - with warnings.catch_warnings(action="ignore", category=DeprecationWarning): + with warnings.catch_warnings(): + # merge this with statement with catch_warnings on Python>=3.11 + warnings.simplefilter(action="ignore", category=DeprecationWarning) decoded = response.text.encode("utf8").decode("unicode_escape") matches = re.search(r"\"MPRE.+?\"", decoded) diff --git a/ytmusicapi/parsers/explore.py b/ytmusicapi/parsers/explore.py index 7284bec..4b366a3 100644 --- a/ytmusicapi/parsers/explore.py +++ b/ytmusicapi/parsers/explore.py @@ -24,6 +24,22 @@ def parse_chart_artist(data): return parsed +def parse_chart_trending(data): + flex_0 = get_flex_column_item(data, 0) + artists = parse_song_artists(data, 1) + index = get_dot_separator_index(artists) + # last item is views for some reason + views = None if index == len(artists) else artists.pop()["name"].split(" ")[0] + return { + "title": nav(flex_0, TEXT_RUN_TEXT), + "videoId": nav(flex_0, TEXT_RUN + NAVIGATION_VIDEO_ID, True), + "playlistId": nav(flex_0, TEXT_RUN + NAVIGATION_PLAYLIST_ID, True), + "artists": artists, + "thumbnails": nav(data, THUMBNAILS), + "views": views, + } + + def parse_ranking(data): return { "rank": nav(data, ["customIndexColumn", "musicCustomIndexColumnRenderer", *TEXT_RUN_TEXT]), diff --git a/ytmusicapi/parsers/podcasts.py b/ytmusicapi/parsers/podcasts.py index 0df885c..388b87d 100644 --- a/ytmusicapi/parsers/podcasts.py +++ b/ytmusicapi/parsers/podcasts.py @@ -87,7 +87,7 @@ def parse_podcast_header(header: Dict) -> Dict: def parse_episode_header(header: Dict) -> Dict: metadata = _parse_base_header(header) metadata["date"] = nav(header, [*SUBTITLE2]) - metadata["duration"] = nav(header, [*SUBTITLE3]) + metadata["duration"] = nav(header, [*SUBTITLE3], True) metadata["saved"] = nav(header, ["buttons", 0, *TOGGLED_BUTTON], True) metadata["playlistId"] = None