Skip to content

Commit

Permalink
fix #656: attempt to find runs in subtitle if not in title (#657)
Browse files Browse the repository at this point in the history
* fix #656: attempt to find runs in subtitle if not in title

* refactor

* remove fix by gotofritz

---------

Co-authored-by: sigma67 <[email protected]>
  • Loading branch information
gotofritz and sigma67 authored Oct 8, 2024
1 parent 2c6c6b6 commit 2b5d19a
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 56 deletions.
6 changes: 0 additions & 6 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,6 @@ def fixture_sample_video() -> str:
return "hpSrLjc5SMs"


@pytest.fixture(name="sample_playlist")
def fixture_sample_playlist() -> str:
"""very large playlist"""
return "PL6bPxvf5dW5clc3y9wAoslzqUrmkZ5c-u"


@pytest.fixture(name="browser_filepath")
def fixture_browser_filepath(config) -> str:
return get_resource(config["auth"]["browser_file"])
Expand Down
37 changes: 19 additions & 18 deletions tests/mixins/test_playlists.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,32 +42,33 @@ def test_get_playlist_2024(self, yt, test_file, owned):
if track["videoType"] == "MUSIC_VIDEO_TYPE_ATV":
assert isinstance(track["album"]["name"], str) and track["album"]["name"]

def test_get_playlist_foreign(self, yt_empty, yt_oauth, sample_playlist):
with pytest.raises(Exception):
yt_empty.get_playlist("PLABC")
playlist = yt_empty.get_playlist(
"RDCLAK5uy_nfjzC9YC1NVPPZHvdoAtKVBOILMDOuxOs", limit=300, suggestions_limit=7
)
@pytest.mark.parametrize(
"playlist_id, tracks_len, related_len",
[
("RDCLAK5uy_nfjzC9YC1NVPPZHvdoAtKVBOILMDOuxOs", 200, 10),
("PLj4BSJLnVpNyIjbCWXWNAmybc97FXLlTk", 200, 0), # no related tracks
("PL6bPxvf5dW5clc3y9wAoslzqUrmkZ5c-u", 1000, 10), # very large
("PLZ6Ih9wLHQ2Hm2d3Cb0iV48Z2hQjGRyNz", 300, 10), # runs in subtitle, not title
],
)
def test_get_playlist_foreign(self, yt_oauth, playlist_id, tracks_len, related_len):
playlist = yt_oauth.get_playlist(playlist_id, limit=None, related=True)
assert len(playlist["duration"]) > 5
assert playlist["trackCount"] > 200
assert len(playlist["tracks"]) > 200
assert playlist["trackCount"] > tracks_len
assert len(playlist["tracks"]) > tracks_len
assert len(playlist["related"]) == related_len
assert "suggestions" not in playlist
assert playlist["owned"] is False

def test_get_playlist_empty(self, yt_empty):
with pytest.raises(Exception):
yt_empty.get_playlist("PLABC")

def test_get_playlist_no_track_count(self, yt_oauth):
playlist = yt_oauth.get_playlist("RDATgXd-")
assert playlist["trackCount"] is None # playlist has no trackCount
assert len(playlist["tracks"]) >= 100

playlist = yt_oauth.get_playlist("PLj4BSJLnVpNyIjbCWXWNAmybc97FXLlTk", limit=None, related=True)
assert playlist["trackCount"] > 200
assert len(playlist["tracks"]) > 200
assert len(playlist["related"]) == 0

playlist = yt_oauth.get_playlist(sample_playlist, limit=1100)
assert playlist["trackCount"] > 1000
assert len(playlist["tracks"]) > 1000
assert len(playlist["related"]) == 0

@pytest.mark.parametrize("language", SUPPORTED_LANGUAGES)
def test_get_playlist_languages(self, language):
yt = YTMusic(language=language)
Expand Down
22 changes: 2 additions & 20 deletions ytmusicapi/mixins/playlists.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,28 +134,10 @@ def get_playlist(
if description_shelf
else None
)
playlist["thumbnails"] = nav(header, THUMBNAILS)
playlist["title"] = nav(header, TITLE_TEXT)
playlist.update(parse_song_runs(nav(header, SUBTITLE_RUNS)[2 + playlist["owned"] * 2 :]))

playlist["views"] = None
playlist["duration"] = None
if "runs" in header["secondSubtitle"]:
second_subtitle_runs = header["secondSubtitle"]["runs"]
has_views = (len(second_subtitle_runs) > 3) * 2
playlist["views"] = None if not has_views else to_int(second_subtitle_runs[0]["text"])
has_duration = (len(second_subtitle_runs) > 1) * 2
playlist["duration"] = (
None if not has_duration else second_subtitle_runs[has_views + has_duration]["text"]
)
song_count_text = second_subtitle_runs[has_views + 0]["text"]
song_count_search = re.findall(r"\d+", song_count_text)
# extract the digits from the text, return 0 if no match
song_count = to_int("".join(song_count_search)) if song_count_search is not None else None
else:
song_count = None
playlist.update(parse_playlist_header_meta(header))

playlist["trackCount"] = song_count
playlist.update(parse_song_runs(nav(header, SUBTITLE_RUNS)[2 + playlist["owned"] * 2 :]))

request_func = lambda additionalParams: self._send_request(endpoint, body, additionalParams)

Expand Down
32 changes: 20 additions & 12 deletions ytmusicapi/parsers/playlists.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ def parse_playlist_header(response: dict) -> dict[str, Any]:
response, [*TWO_COLUMN_RENDERER, *TAB_CONTENT, *SECTION_LIST_ITEM, *RESPONSIVE_HEADER]
)

playlist["title"] = nav(header, TITLE_TEXT)
playlist["thumbnails"] = nav(header, THUMBNAIL_CROPPED, True)
playlist.update(parse_playlist_header_meta(header))
if playlist["thumbnails"] is None:
playlist["thumbnails"] = nav(header, THUMBNAILS)
playlist["thumbnails"] = nav(header, THUMBNAIL_CROPPED, True)
playlist["description"] = nav(header, DESCRIPTION, True)
run_count = len(nav(header, SUBTITLE_RUNS))
if run_count > 1:
Expand All @@ -33,24 +32,33 @@ def parse_playlist_header(response: dict) -> dict[str, Any]:
if run_count == 5:
playlist["year"] = nav(header, SUBTITLE3)

playlist["views"] = None
playlist["duration"] = None
playlist["trackCount"] = None
return playlist


def parse_playlist_header_meta(header: dict[str, Any]) -> dict[str, Any]:
playlist_meta = {
"views": None,
"duration": None,
"trackCount": None,
"title": nav(header, TITLE_TEXT, none_if_absent=True),
"thumbnails": nav(header, THUMBNAILS),
}
if "runs" in header["secondSubtitle"]:
second_subtitle_runs = header["secondSubtitle"]["runs"]
has_views = (len(second_subtitle_runs) > 3) * 2
playlist["views"] = None if not has_views else to_int(second_subtitle_runs[0]["text"])
playlist_meta["views"] = None if not has_views else to_int(second_subtitle_runs[0]["text"])
has_duration = (len(second_subtitle_runs) > 1) * 2
playlist["duration"] = (
playlist_meta["duration"] = (
None if not has_duration else second_subtitle_runs[has_views + has_duration]["text"]
)
song_count_text = second_subtitle_runs[has_views + 0]["text"]
song_count_search = re.search(r"\d+", song_count_text)
song_count_search = re.findall(r"\d+", song_count_text)
# extract the digits from the text, return 0 if no match
song_count = to_int(song_count_search.group()) if song_count_search is not None else 0
playlist["trackCount"] = song_count
playlist_meta["trackCount"] = (
to_int("".join(song_count_search)) if song_count_search is not None else None
)

return playlist
return playlist_meta


def parse_playlist_items(results, menu_entries: Optional[list[list]] = None, is_album=False):
Expand Down

0 comments on commit 2b5d19a

Please sign in to comment.