Skip to content

Commit 6ac7901

Browse files
committed
Merge branch 'main' into async
2 parents 390b21b + 33098ba commit 6ac7901

File tree

60 files changed

+976
-762
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+976
-762
lines changed

.github/workflows/lint.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@ jobs:
1414
steps:
1515
- uses: actions/checkout@v4
1616
- uses: chartboost/ruff-action@v1
17+
with:
18+
version: 0.4.3
1719
- uses: chartboost/ruff-action@v1
1820
with:
21+
version: 0.4.3
1922
args: format --check
2023
mypy:
2124
runs-on: ubuntu-latest
@@ -24,5 +27,5 @@ jobs:
2427
- uses: actions/setup-python@v5
2528
with:
2629
python-version: "3.8"
27-
- run: pip install mypy==1.8.0
30+
- run: pip install mypy==1.10.0
2831
- run: mypy --install-types --non-interactive

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
.idea
22
.vscode
3-
**.json
3+
tests/*.json
4+
tests/setup/*.json
45
docs/build
56
test.cfg
67
**.mp3

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
repos:
22
- repo: https://github.com/astral-sh/ruff-pre-commit
33
# Ruff version.
4-
rev: v0.3.0
4+
rev: v0.4.3
55
hooks:
66
# Run the linter.
77
- id: ruff
88
# Run the formatter.
99
- id: ruff-format
1010

1111
- repo: https://github.com/pre-commit/mirrors-mypy
12-
rev: v1.8.0
12+
rev: v1.10.0
1313
hooks:
1414
- id: mypy
1515
verbose: true

README.rst

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
11
ytmusicapi: Unofficial API for YouTube Music
22
############################################
33

4-
.. image:: https://img.shields.io/pypi/dm/ytmusicapi?style=flat-square
4+
.. |pypi-downloads| image:: https://img.shields.io/pypi/dm/ytmusicapi?style=flat-square
55
:alt: PyPI Downloads
66
:target: https://pypi.org/project/ytmusicapi/
77

8-
.. image:: https://badges.gitter.im/sigma67/ytmusicapi.svg
8+
.. |gitter| image:: https://badges.gitter.im/sigma67/ytmusicapi.svg
99
:alt: Ask questions at https://gitter.im/sigma67/ytmusicapi
1010
:target: https://gitter.im/sigma67/ytmusicapi
1111

12-
.. image:: https://img.shields.io/codecov/c/github/sigma67/ytmusicapi?style=flat-square
12+
.. |code-coverage| image:: https://img.shields.io/codecov/c/github/sigma67/ytmusicapi?style=flat-square
1313
:alt: Code coverage
1414
:target: https://codecov.io/gh/sigma67/ytmusicapi
1515

16-
.. image:: https://img.shields.io/github/v/release/sigma67/ytmusicapi?style=flat-square
16+
.. |latest-release| image:: https://img.shields.io/github/v/release/sigma67/ytmusicapi?style=flat-square
1717
:alt: Latest release
1818
:target: https://github.com/sigma67/ytmusicapi/releases/latest
1919

20-
.. image:: https://img.shields.io/github/commits-since/sigma67/ytmusicapi/latest?style=flat-square
20+
.. |commits-since-latest| image:: https://img.shields.io/github/commits-since/sigma67/ytmusicapi/latest?style=flat-square
2121
:alt: Commits since latest release
2222
:target: https://github.com/sigma67/ytmusicapi/commits
2323

2424

25+
|pypi-downloads| |gitter| |code-coverage| |latest-release| |commits-since-latest|
26+
2527
ytmusicapi is a Python 3 library to send requests to the YouTube Music API.
2628
It emulates YouTube Music web client requests using the user's cookie data for authentication.
2729

pdm.lock

Lines changed: 187 additions & 380 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/data/2024_03_get_album.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

tests/data/2024_03_get_playlist.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

tests/data/2024_03_get_playlist_public.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

tests/mixins/test_browsing.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import json
12
import warnings
3+
from pathlib import Path
4+
from unittest import mock
25

36
import pytest
47

@@ -23,6 +26,14 @@ def test_get_artist(self, yt):
2326
results = yt.get_artist("UCLZ7tlKC06ResyDmEStSrOw") # no album year
2427
assert len(results) >= 11
2528

29+
def test_get_artist_shows(self, yt_oauth):
30+
# with audiobooks - only with authentication
31+
results = yt_oauth.get_artist("UCyiY-0Af0O6emoI3YvCEDaA")
32+
assert len(results["shows"]["results"]) == 10
33+
34+
results = yt_oauth.get_artist_albums(results["shows"]["browseId"], results["shows"]["params"])
35+
assert len(results) == 100
36+
2637
def test_get_artist_albums(self, yt):
2738
artist = yt.get_artist("UCAeLFBCQS7FvI8PvBrWvSBg")
2839
results = yt.get_artist_albums(artist["albums"]["browseId"], artist["albums"]["params"])
@@ -66,6 +77,15 @@ def test_get_album_browse_id_issue_470(self, yt):
6677
escaped_browse_id = yt.get_album_browse_id("OLAK5uy_nbMYyrfeg5ZgknoOsOGBL268hGxtcbnDM")
6778
assert escaped_browse_id == "MPREb_scJdtUCpPE2"
6879

80+
def test_get_album_2024(self, yt):
81+
with open(Path(__file__).parent.parent / "data" / "2024_03_get_album.json", encoding="utf8") as f:
82+
mock_response = json.load(f)
83+
with mock.patch("ytmusicapi.YTMusic._send_request", return_value=mock_response):
84+
album = yt.get_album("MPREabc")
85+
assert len(album["tracks"]) == 19
86+
assert len(album["artists"]) == 1
87+
assert len(album) == 13
88+
6989
def test_get_album(self, yt, yt_auth, sample_album):
7090
album = yt_auth.get_album(sample_album)
7191
assert len(album) >= 9

tests/mixins/test_playlists.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,30 @@
1+
import json
12
import time
3+
from pathlib import Path
4+
from unittest import mock
25

36
import pytest
47

58

69
class TestPlaylists:
10+
@pytest.mark.parametrize(
11+
("test_file", "owned"),
12+
[
13+
("2024_03_get_playlist.json", True),
14+
("2024_03_get_playlist_public.json", False),
15+
],
16+
)
17+
def test_get_playlist_2024(self, yt, test_file, owned):
18+
with open(Path(__file__).parent.parent / "data" / test_file, encoding="utf8") as f:
19+
mock_response = json.load(f)
20+
with mock.patch("ytmusicapi.YTMusic._send_request", return_value=mock_response):
21+
playlist = yt.get_playlist("MPREabc")
22+
assert playlist["year"] == "2024"
23+
assert playlist["owned"] == owned
24+
assert "hours" in playlist["duration"]
25+
assert playlist["id"]
26+
assert isinstance(playlist["description"], str)
27+
728
def test_get_playlist_foreign(self, yt, yt_auth, yt_oauth):
829
with pytest.raises(Exception):
930
yt.get_playlist("PLABC")
@@ -20,6 +41,22 @@ def test_get_playlist_foreign(self, yt, yt_auth, yt_oauth):
2041
assert len(playlist["tracks"]) > 200
2142
assert len(playlist["related"]) == 0
2243

44+
def test_get_playlist_foreign_new_format(self, yt_empty):
45+
with pytest.raises(Exception):
46+
yt_empty.get_playlist("PLABC")
47+
playlist = yt_empty.get_playlist("PLk5BdzXBUiUe8Q5I13ZSCD8HbxMqJUUQA", limit=300, suggestions_limit=7)
48+
assert len(playlist["duration"]) > 5
49+
assert len(playlist["tracks"]) > 200
50+
assert "suggestions" not in playlist
51+
assert playlist["owned"] is False
52+
53+
playlist = yt_empty.get_playlist("RDATgXd-")
54+
assert len(playlist["tracks"]) >= 100
55+
56+
playlist = yt_empty.get_playlist("PLj4BSJLnVpNyIjbCWXWNAmybc97FXLlTk", limit=None, related=True)
57+
assert len(playlist["tracks"]) > 200
58+
assert len(playlist["related"]) == 0
59+
2360
def test_get_playlist_owned(self, config, yt_brand):
2461
playlist = yt_brand.get_playlist(config["playlists"]["own"], related=True, suggestions_limit=21)
2562
assert len(playlist["tracks"]) < 100
@@ -52,7 +89,7 @@ def test_edit_playlist(self, config, yt_brand):
5289
)
5390
assert response == "STATUS_SUCCEEDED", "Playlist edit failed"
5491

55-
def test_end2end(self, config, yt_brand, sample_video):
92+
def test_end2end(self, yt_brand, sample_video):
5693
playlist_id = yt_brand.create_playlist(
5794
"test",
5895
"test description",
@@ -70,6 +107,7 @@ def test_end2end(self, config, yt_brand, sample_video):
70107
assert len(response["playlistEditResults"]) > 0, "Adding playlist item failed"
71108
time.sleep(3)
72109
yt_brand.edit_playlist(playlist_id, addToTop=False)
110+
time.sleep(3)
73111
playlist = yt_brand.get_playlist(playlist_id, related=True)
74112
assert len(playlist["tracks"]) == 46, "Getting playlist items failed"
75113
response = yt_brand.remove_playlist_items(playlist_id, playlist["tracks"])

0 commit comments

Comments
 (0)