Skip to content

Commit 90d172b

Browse files
authored
podcasts features ✨ (sigma67#559)
1 parent c412d7c commit 90d172b

File tree

46 files changed

+802
-318
lines changed

Some content is hidden

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

46 files changed

+802
-318
lines changed

README.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ Features
4747

4848
| **Library management**:
4949
50-
* get library contents: playlists, songs, artists, albums and subscriptions
50+
* get library contents: playlists, songs, artists, albums and subscriptions, podcasts, channels
5151
* add/remove library content: rate songs, albums and playlists, subscribe/unsubscribe artists
5252
* get and modify play history
5353

@@ -62,6 +62,7 @@ Features
6262
6363
* get podcasts
6464
* get episodes
65+
* get channels
6566

6667
| **Uploads**:
6768

docs/source/reference.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ Library
5252
.. automethod:: YTMusic.get_library_albums
5353
.. automethod:: YTMusic.get_library_artists
5454
.. automethod:: YTMusic.get_library_subscriptions
55+
.. automethod:: YTMusic.get_library_podcasts
56+
.. automethod:: YTMusic.get_library_channels
5557
.. automethod:: YTMusic.get_liked_songs
58+
.. automethod:: YTMusic.get_saved_episodes
5659
.. automethod:: YTMusic.get_history
5760
.. automethod:: YTMusic.add_history_item
5861
.. automethod:: YTMusic.remove_history_items
@@ -74,6 +77,8 @@ Playlists
7477

7578
Podcasts
7679
--------
80+
.. automethod:: YTMusic.get_channel
81+
.. automethod:: YTMusic.get_channel_episodes
7782
.. automethod:: YTMusic.get_podcast
7883
.. automethod:: YTMusic.get_episode
7984

pdm.lock

Lines changed: 26 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,5 @@ dev = [
7777
"mypy>=1.8.0",
7878
"pytest>=7.4.4",
7979
"pytest-cov>=4.1.0",
80+
"types-requests>=2.31.0.20240218",
8081
]

tests/mixins/test_library.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,20 @@ def test_get_library_subscriptions(self, config, yt_brand, yt_empty):
6060
artists = yt_empty.get_library_subscriptions()
6161
assert len(artists) == 0
6262

63+
def test_get_library_podcasts(self, yt_brand, yt_empty):
64+
podcasts = yt_brand.get_library_podcasts(limit=50, order="a_to_z")
65+
assert len(podcasts) > 25
66+
67+
empty = yt_empty.get_library_podcasts()
68+
assert len(empty) == 1 # saved episodes playlist is always there
69+
70+
def test_get_library_channels(self, yt_brand, yt_empty):
71+
channels = yt_brand.get_library_channels(limit=50, order="recently_added")
72+
assert len(channels) > 25
73+
74+
empty = yt_empty.get_library_channels()
75+
assert len(empty) == 0
76+
6377
def test_get_liked_songs(self, yt_brand, yt_empty):
6478
songs = yt_brand.get_liked_songs(200)
6579
assert len(songs["tracks"]) > 100

tests/mixins/test_podcasts.py

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
class TestPodcasts:
2+
def test_get_channel(self, config, yt):
3+
podcast_id = config["podcasts"]["channel_id"]
4+
channel = yt.get_channel(podcast_id)
5+
assert len(channel["episodes"]["results"]) == 10
6+
assert len(channel["podcasts"]["results"]) > 5
7+
8+
def test_get_channel_episodes(self, config, yt_oauth):
9+
channel_id = config["podcasts"]["channel_id"]
10+
channel = yt_oauth.get_channel(channel_id)
11+
channel_episodes = yt_oauth.get_channel_episodes(channel_id, channel["episodes"]["params"])
12+
assert len(channel_episodes) >= 150
13+
assert len(channel_episodes[0]) == 9
14+
215
def test_get_podcast(self, config, yt, yt_brand):
316
podcast_id = config["podcasts"]["podcast_id"]
4-
results = yt.get_podcast(podcast_id)
5-
assert len(results["episodes"]) == 100
6-
assert not results["saved"]
17+
podcast = yt.get_podcast(podcast_id)
18+
assert len(podcast["episodes"]) == 100
19+
assert not podcast["saved"]
720

8-
results = yt_brand.get_podcast(podcast_id, limit=None)
9-
assert len(results["episodes"]) > 100
10-
assert results["saved"]
21+
podcast = yt_brand.get_podcast(podcast_id, limit=None)
22+
assert len(podcast["episodes"]) > 100
23+
assert podcast["saved"]
1124

1225
def test_many_podcasts(self, yt):
1326
results = yt.search("podcast", filter="podcasts")
@@ -17,13 +30,13 @@ def test_many_podcasts(self, yt):
1730

1831
def test_get_episode(self, config, yt, yt_brand):
1932
episode_id = config["podcasts"]["episode_id"]
20-
result = yt.get_episode(episode_id)
21-
assert len(result["description"]) >= 20
22-
assert not result["saved"]
23-
assert result["playlistId"] is not None
33+
episode = yt.get_episode(episode_id)
34+
assert len(episode["description"]) >= 20
35+
assert not episode["saved"]
36+
assert episode["playlistId"] is not None
2437

25-
result = yt_brand.get_episode(episode_id)
26-
assert result["saved"]
38+
episode = yt_brand.get_episode(episode_id)
39+
assert episode["saved"]
2740

2841
def test_many_episodes(self, yt):
2942
results = yt.search("episode", filter="episodes")

tests/setup/setup_account.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
yt_brand = YTMusic(Path(__file__).parent.joinpath("oauth.json").as_posix(), brand_account)
1616

1717

18-
def populate_account():
18+
def populate_music():
1919
"""idempotent requests to populate an account"""
2020
# library
2121
playlist_id = "RDCLAK5uy_l9ex2d91-Qb1i-W7d0MLCEl_ZjRXss0Dk" # fixed playlist with many artists
@@ -53,10 +53,18 @@ def populate_account():
5353
)
5454
print(f"Created playlist {playlistId}, don't forget to set this in test.cfg playlists/own")
5555

56-
# podcasts
56+
57+
def populate_podcasts():
5758
yt_brand.rate_playlist(config["podcasts"]["podcast_id"], rating="LIKE")
5859
yt_brand.add_playlist_items("SE", [config["podcasts"]["episode_id"]])
60+
podcasts = yt_brand.search("podcast", filter="podcasts", limit=40)
61+
for podcast in podcasts:
62+
playlist_id = podcast["browseId"][4:]
63+
yt_brand.rate_playlist(playlist_id, rating="LIKE")
64+
podcast = yt_brand.get_podcast(playlist_id)
65+
yt_brand.subscribe_artists([podcast["author"]["id"]])
5966

6067

6168
if __name__ == "__main__":
62-
populate_account()
69+
populate_music()
70+
populate_podcasts()

tests/test.example.cfg

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ private_album_id = sample_id_of_private_album
3131
private_artist_id = sample_id_of_private_artist
3232
private_upload_id = sample_video_id_of_private_upload
3333

34+
[podcasts]
35+
channel_id = UCGwuxdEeCf0TIA2RbPOj-8g
36+
podcast_id = PLxq_lXOUlvQDgCVFj9L79kqJybW0k6OaB
37+
episode_id = KNkyHCLOr1o
38+
3439
[limits]
3540
library_playlists = 100
3641
library_songs = 200
105 Bytes
Binary file not shown.

ytmusicapi/locales/ar/LC_MESSAGES/base.po

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ msgid ""
77
msgstr ""
88
"Project-Id-Version: \n"
99
"Report-Msgid-Bugs-To: \n"
10-
"POT-Creation-Date: 2023-11-11 16:22+0100\n"
10+
"POT-Creation-Date: 2024-03-05 20:13+0100\n"
1111
"PO-Revision-Date: 2023-01-02 22:14+0530\n"
1212
"Last-Translator: \n"
1313
"Language-Team: \n"
@@ -17,54 +17,62 @@ msgstr ""
1717
"Content-Transfer-Encoding: 8bit\n"
1818
"X-Generator: Poedit 3.2.2\n"
1919

20-
#: parsers/i18n.py:16
20+
#: parsers/i18n.py:22
2121
msgid "artist"
2222
msgstr "فنان"
2323

24-
#: parsers/i18n.py:16
24+
#: parsers/i18n.py:23
2525
msgid "playlist"
2626
msgstr "قائمةالتشغيل"
2727

28-
#: parsers/i18n.py:16
28+
#: parsers/i18n.py:24
2929
msgid "song"
3030
msgstr "أغنية"
3131

32-
#: parsers/i18n.py:16
32+
#: parsers/i18n.py:25
3333
msgid "video"
3434
msgstr "فيديو"
3535

36-
#: parsers/i18n.py:16
36+
#: parsers/i18n.py:26
3737
msgid "station"
3838
msgstr "محطة"
3939

40-
#: parsers/i18n.py:16
40+
#: parsers/i18n.py:27
4141
msgid "profile"
4242
msgstr "الملف الشخصي"
4343

44-
#: parsers/i18n.py:16
44+
#: parsers/i18n.py:28
4545
msgid "podcast"
4646
msgstr "بودكاست"
4747

48-
#: parsers/i18n.py:16
48+
#: parsers/i18n.py:29
4949
msgid "episode"
5050
msgstr "حلقة"
5151

52-
#: parsers/i18n.py:21
52+
#: parsers/i18n.py:35
5353
msgid "albums"
5454
msgstr "ألبومات"
5555

56-
#: parsers/i18n.py:21
56+
#: parsers/i18n.py:35
5757
msgid "singles"
5858
msgstr "الفردي"
5959

60-
#: parsers/i18n.py:21
60+
#: parsers/i18n.py:35
6161
msgid "videos"
6262
msgstr "أشرطة فيديو"
6363

64-
#: parsers/i18n.py:21
64+
#: parsers/i18n.py:35
6565
msgid "playlists"
6666
msgstr "قوائم التشغيل"
6767

68-
#: parsers/i18n.py:21
68+
#: parsers/i18n.py:35
6969
msgid "related"
7070
msgstr "ذات صلة"
71+
72+
#: parsers/i18n.py:35
73+
msgid "episodes"
74+
msgstr "أحدث الحلقات"
75+
76+
#: parsers/i18n.py:35
77+
msgid "podcasts"
78+
msgstr "بودكاست"

0 commit comments

Comments
 (0)