Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-ytmusicapi for
openSUSE:Factory checked in at 2026-01-31 16:17:34
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-ytmusicapi (Old)
and /work/SRC/openSUSE:Factory/.python-ytmusicapi.new.1995 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-ytmusicapi"
Sat Jan 31 16:17:34 2026 rev:13 rq:1330141 version:1.11.5
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-ytmusicapi/python-ytmusicapi.changes
2025-12-22 22:50:33.540285054 +0100
+++
/work/SRC/openSUSE:Factory/.python-ytmusicapi.new.1995/python-ytmusicapi.changes
2026-01-31 16:17:38.709277869 +0100
@@ -1,0 +2,8 @@
+Sat Jan 31 10:27:59 UTC 2026 - Christophe Marin <[email protected]>
+
+- Update to 1.11.5
+ * feat(artists): add new monthly audience feature to get_artist
+ * get_explore: fix missing duration for top episodes
+ * get_playlist: compute trackCount after following continuations
+
+-------------------------------------------------------------------
Old:
----
ytmusicapi-1.11.4.tar.gz
New:
----
ytmusicapi-1.11.5.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-ytmusicapi.spec ++++++
--- /var/tmp/diff_new_pack.uZFF2r/_old 2026-01-31 16:17:39.489310277 +0100
+++ /var/tmp/diff_new_pack.uZFF2r/_new 2026-01-31 16:17:39.493310444 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-ytmusicapi
#
-# Copyright (c) 2024 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-ytmusicapi
-Version: 1.11.4
+Version: 1.11.5
Release: 0
Summary: Unofficial API for YouTube Music
License: MIT
++++++ ytmusicapi-1.11.4.tar.gz -> ytmusicapi-1.11.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/.github/workflows/lint.yml
new/ytmusicapi-1.11.5/.github/workflows/lint.yml
--- old/ytmusicapi-1.11.4/.github/workflows/lint.yml 2025-12-19
17:51:31.000000000 +0100
+++ new/ytmusicapi-1.11.5/.github/workflows/lint.yml 2026-01-31
10:51:08.000000000 +0100
@@ -15,10 +15,10 @@
- uses: actions/checkout@v6
- uses: chartboost/ruff-action@v1
with:
- version: 0.11.5
+ version: 0.14.10
- uses: chartboost/ruff-action@v1
with:
- version: 0.11.5
+ version: 0.14.10
args: format --check
mypy:
runs-on: ubuntu-latest
@@ -27,5 +27,5 @@
- uses: actions/setup-python@v6
with:
python-version: "3.10"
- - run: pip install mypy==1.15.0
+ - run: pip install mypy==1.19.1
- run: mypy --install-types --non-interactive
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/.pre-commit-config.yaml
new/ytmusicapi-1.11.5/.pre-commit-config.yaml
--- old/ytmusicapi-1.11.4/.pre-commit-config.yaml 2025-12-19
17:51:31.000000000 +0100
+++ new/ytmusicapi-1.11.5/.pre-commit-config.yaml 2026-01-31
10:51:08.000000000 +0100
@@ -1,7 +1,7 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
- rev: v0.11.5
+ rev: v0.14.10
hooks:
# Run the linter.
- id: ruff
@@ -10,7 +10,7 @@
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
- rev: v1.15.0
+ rev: v1.19.1
hooks:
- id: mypy
verbose: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/PKG-INFO
new/ytmusicapi-1.11.5/PKG-INFO
--- old/ytmusicapi-1.11.4/PKG-INFO 2025-12-19 17:51:35.548997600 +0100
+++ new/ytmusicapi-1.11.5/PKG-INFO 2026-01-31 10:51:13.482156800 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: ytmusicapi
-Version: 1.11.4
+Version: 1.11.5
Summary: Unofficial API for YouTube Music
Author-email: sigma67 <[email protected]>
License: MIT License
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/pyproject.toml
new/ytmusicapi-1.11.5/pyproject.toml
--- old/ytmusicapi-1.11.4/pyproject.toml 2025-12-19 17:51:31.000000000
+0100
+++ new/ytmusicapi-1.11.5/pyproject.toml 2026-01-31 10:51:08.000000000
+0100
@@ -54,6 +54,7 @@
[tool.ruff]
line-length = 110
include = ["ytmusicapi/**/*.py", "tests/**/*.py"]
+exclude = ["docs/**"]
[tool.ruff.lint]
ignore = [ "F403", "F405", "F821", "E731", "PTH123" ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/tests/mixins/test_browsing.py
new/ytmusicapi-1.11.5/tests/mixins/test_browsing.py
--- old/ytmusicapi-1.11.4/tests/mixins/test_browsing.py 2025-12-19
17:51:31.000000000 +0100
+++ new/ytmusicapi-1.11.5/tests/mixins/test_browsing.py 2026-01-31
10:51:08.000000000 +0100
@@ -33,7 +33,7 @@
def test_get_artist(self, yt):
results = yt.get_artist("MPLAUCmMUZbaYdNH0bEd1PAlAqsA")
- assert len(results) == 16
+ assert len(results) == 17
assert results["shuffleId"] is not None
assert results["radioId"] is not None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/tests/mixins/test_explore.py
new/ytmusicapi-1.11.5/tests/mixins/test_explore.py
--- old/ytmusicapi-1.11.4/tests/mixins/test_explore.py 2025-12-19
17:51:31.000000000 +0100
+++ new/ytmusicapi-1.11.5/tests/mixins/test_explore.py 2026-01-31
10:51:08.000000000 +0100
@@ -1,8 +1,3 @@
-import json
-from pathlib import Path
-from unittest import mock
-
-
class TestExplore:
def test_get_mood_playlists(self, yt):
categories = yt.get_mood_categories()
@@ -45,14 +40,3 @@
and item["podcast"]["name"]
for item in explore["top_episodes"]
)
-
- def test_get_explore_2025(self, yt):
- data_dir = Path(__file__).parent.parent / "data"
- test_file = "2025_11_get_explore.json"
- with open(data_dir / test_file, encoding="utf8") as f:
- mock_response = json.load(f)
- with mock.patch("ytmusicapi.YTMusic._send_request",
return_value=mock_response):
- result = yt.get_explore()
- with open(data_dir / "expected_output" / test_file, encoding="utf8")
as f:
- expected_output = json.load(f)
- assert result == expected_output
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/tests/mixins/test_playlists.py
new/ytmusicapi-1.11.5/tests/mixins/test_playlists.py
--- old/ytmusicapi-1.11.4/tests/mixins/test_playlists.py 2025-12-19
17:51:31.000000000 +0100
+++ new/ytmusicapi-1.11.5/tests/mixins/test_playlists.py 2026-01-31
10:51:08.000000000 +0100
@@ -70,6 +70,7 @@
def test_get_large_audio_playlist(self, yt_oauth):
album =
yt_oauth.get_playlist("OLAK5uy_noLNRtYnrcRVVO9rOyGMx64XyjVSCz1YU", limit=500)
assert len(album["tracks"]) == 456
+ assert album["trackCount"] == 456
@pytest.mark.parametrize(
"playlist_id",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/tests/mixins/test_search.py
new/ytmusicapi-1.11.5/tests/mixins/test_search.py
--- old/ytmusicapi-1.11.4/tests/mixins/test_search.py 2025-12-19
17:51:31.000000000 +0100
+++ new/ytmusicapi-1.11.5/tests/mixins/test_search.py 2026-01-31
10:51:08.000000000 +0100
@@ -210,10 +210,10 @@
assert any(item.get("fromHistory") for item in results), "No
suggestions from history found"
suggestion_to_remove = [99]
- with pytest.raises(YTMusicUserError, match="Index out of range."):
+ with pytest.raises(YTMusicUserError, match="Index out of range"):
yt_auth.remove_search_suggestions(results, suggestion_to_remove)
suggestion_to_remove = [0]
- with pytest.raises(YTMusicUserError, match="No search result from
history provided."):
+ with pytest.raises(YTMusicUserError, match="No search result from
history provided"):
results = yt.get_search_suggestions("a", detailed_runs=True)
yt.remove_search_suggestions(results, suggestion_to_remove)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/tests/mixins/test_uploads.py
new/ytmusicapi-1.11.5/tests/mixins/test_uploads.py
--- old/ytmusicapi-1.11.4/tests/mixins/test_uploads.py 2025-12-19
17:51:31.000000000 +0100
+++ new/ytmusicapi-1.11.5/tests/mixins/test_uploads.py 2026-01-31
10:51:08.000000000 +0100
@@ -41,7 +41,7 @@
assert len(results) == 0
def test_upload_song_exceptions(self, config, yt_auth, yt_oauth):
- with pytest.raises(Exception, match="The provided file does not
exist."):
+ with pytest.raises(Exception, match="The provided file does not
exist"):
yt_auth.upload_song("song.wav")
with (
tempfile.NamedTemporaryFile(suffix="wav") as temp,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/ytmusicapi/mixins/browsing.py
new/ytmusicapi-1.11.5/ytmusicapi/mixins/browsing.py
--- old/ytmusicapi-1.11.4/ytmusicapi/mixins/browsing.py 2025-12-19
17:51:31.000000000 +0100
+++ new/ytmusicapi-1.11.5/ytmusicapi/mixins/browsing.py 2026-01-31
10:51:08.000000000 +0100
@@ -1,6 +1,6 @@
import re
import warnings
-from typing import Literal, cast, overload
+from typing import Any, Literal, overload
from ytmusicapi.continuations import (
get_continuations,
@@ -177,6 +177,7 @@
"shuffleId": "RDAOkjHYJjL1a3xspEyVkhHAsg",
"radioId": "RDEMkjHYJjL1a3xspEyVkhHAsg",
"subscribers": "3.86M",
+ "monthlyListeners": "29.1M",
"subscribed": false,
"thumbnails": [...],
"songs": {
@@ -267,6 +268,12 @@
artist["shuffleId"] = nav(header, ["playButton", "buttonRenderer",
*NAVIGATION_PLAYLIST_ID], True)
artist["radioId"] = nav(header, ["startRadioButton", "buttonRenderer",
*NAVIGATION_PLAYLIST_ID], True)
artist["subscribers"] = nav(subscription_button,
["subscriberCountText", "runs", 0, "text"], True)
+ artist["monthlyListeners"] = nav(header, ["monthlyListenerCount",
"runs", 0, "text"], True)
+ artist["monthlyListeners"] = (
+ artist["monthlyListeners"].replace(" monthly audience", "")
+ if artist["monthlyListeners"]
+ else None
+ )
artist["subscribed"] = subscription_button["subscribed"]
artist["thumbnails"] = nav(header, THUMBNAILS, True)
artist["songs"] = {"browseId": None}
@@ -344,7 +351,7 @@
{"continuations": [continuation["continuation"]]}
)
response = request_func(additionalParams)
- results = nav(response, SECTION_LIST_CONTINUATION + CONTENT)
+ results: dict[str, Any] = nav(response,
SECTION_LIST_CONTINUATION + CONTENT)
else:
raise ValueError(f"Invalid order parameter {order}")
@@ -355,7 +362,7 @@
contents = nav(results, GRID_ITEMS, True) or nav(results,
CAROUSEL_CONTENTS)
albums = parse_albums(contents)
- results = nav(results, GRID, True)
+ results = nav(results, GRID, True) # type: ignore[assignment]
if "continuations" in results:
remaining_limit = None if limit is None else (limit - len(albums))
albums.extend(
@@ -944,7 +951,7 @@
hasTimestamps=False,
)
- return cast(Lyrics | TimedLyrics, lyrics)
+ return lyrics
def get_basejs_url(self) -> str:
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/ytmusicapi/mixins/charts.py
new/ytmusicapi-1.11.5/ytmusicapi/mixins/charts.py
--- old/ytmusicapi-1.11.4/ytmusicapi/mixins/charts.py 2025-12-19
17:51:31.000000000 +0100
+++ new/ytmusicapi-1.11.5/ytmusicapi/mixins/charts.py 2026-01-31
10:51:08.000000000 +0100
@@ -95,7 +95,8 @@
charts_categories = [
("daily", parse_chart_playlist, MTRIR),
("weekly", parse_chart_playlist, MTRIR),
- ] + charts_categories[1:]
+ *charts_categories[1:],
+ ]
for i, (name, parse_func, key) in enumerate(charts_categories):
charts[name] = parse_content_list(nav(results[1 + i],
CAROUSEL_CONTENTS), parse_func, key)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/ytmusicapi/navigation.py
new/ytmusicapi-1.11.5/ytmusicapi/navigation.py
--- old/ytmusicapi-1.11.4/ytmusicapi/navigation.py 2025-12-19
17:51:31.000000000 +0100
+++ new/ytmusicapi-1.11.5/ytmusicapi/navigation.py 2026-01-31
10:51:08.000000000 +0100
@@ -119,7 +119,7 @@
return None
try:
for k in items:
- root = root[k] # type: ignore[index]
+ root = root[k]
except (KeyError, IndexError) as e:
if none_if_absent:
return None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/ytmusicapi/parsers/explore.py
new/ytmusicapi-1.11.5/ytmusicapi/parsers/explore.py
--- old/ytmusicapi-1.11.4/ytmusicapi/parsers/explore.py 2025-12-19
17:51:31.000000000 +0100
+++ new/ytmusicapi-1.11.5/ytmusicapi/parsers/explore.py 2026-01-31
10:51:08.000000000 +0100
@@ -34,7 +34,7 @@
episode = parse_episode(data)
del episode["index"]
episode["podcast"] = parse_id_name(nav(data, ["secondTitle", "runs", 0]))
- episode["duration"] = nav(data, SUBTITLE2, True)
+ episode["duration"] = nav(data, ["playbackProgress", *PROGRESS_RENDERER,
*DURATION_TEXT], True)
return episode
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/ytmusicapi/parsers/playlists.py
new/ytmusicapi-1.11.5/ytmusicapi/parsers/playlists.py
--- old/ytmusicapi-1.11.4/ytmusicapi/parsers/playlists.py 2025-12-19
17:51:31.000000000 +0100
+++ new/ytmusicapi-1.11.5/ytmusicapi/parsers/playlists.py 2026-01-31
10:51:08.000000000 +0100
@@ -110,7 +110,6 @@
content_data = nav(section_list, [*CONTENT, "musicPlaylistShelfRenderer"])
playlist["id"] = nav(content_data, ["targetId"])
- playlist["trackCount"] = nav(content_data, ["collapsedItemCount"])
playlist["tracks"] = []
if "contents" in content_data:
@@ -119,6 +118,8 @@
parse_func: ParseFuncType = lambda contents:
parse_playlist_items(contents)
playlist["tracks"].extend(get_continuations_2025(content_data, limit,
request_func, parse_func))
+ playlist["trackCount"] = len(playlist["tracks"])
+
playlist["title"] = playlist["tracks"][0]["album"]["name"]
playlist["duration_seconds"] = sum_total_duration(playlist)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/ytmusicapi/parsers/search.py
new/ytmusicapi-1.11.5/ytmusicapi/parsers/search.py
--- old/ytmusicapi-1.11.4/ytmusicapi/parsers/search.py 2025-12-19
17:51:31.000000000 +0100
+++ new/ytmusicapi-1.11.5/ytmusicapi/parsers/search.py 2026-01-31
10:51:08.000000000 +0100
@@ -184,6 +184,8 @@
search_result["duration"] = None
search_result["year"] = None
flex_item = get_flex_column_item(data, 1)
+ if not flex_item:
+ raise ValueError("Expected flex column item at index 1")
runs = flex_item["text"]["runs"]
if flex_item2 := get_flex_column_item(data, 2):
runs.extend([{"text": ""}, *flex_item2["text"]["runs"]]) # first
item is a dummy separator
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/ytmusicapi/ytmusic.py
new/ytmusicapi-1.11.5/ytmusicapi/ytmusic.py
--- old/ytmusicapi-1.11.4/ytmusicapi/ytmusic.py 2025-12-19 17:51:31.000000000
+0100
+++ new/ytmusicapi-1.11.5/ytmusicapi/ytmusic.py 2026-01-31 10:51:08.000000000
+0100
@@ -112,7 +112,9 @@
)
#: OAuth credential handler
self._token = RefreshingToken(
- credentials=oauth_credentials, _local_cache=auth_path,
**self._auth_headers
+ credentials=oauth_credentials,
+ _local_cache=auth_path,
+ **self._auth_headers, # type: ignore[arg-type]
)
# prepare context
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ytmusicapi-1.11.4/ytmusicapi.egg-info/PKG-INFO
new/ytmusicapi-1.11.5/ytmusicapi.egg-info/PKG-INFO
--- old/ytmusicapi-1.11.4/ytmusicapi.egg-info/PKG-INFO 2025-12-19
17:51:35.000000000 +0100
+++ new/ytmusicapi-1.11.5/ytmusicapi.egg-info/PKG-INFO 2026-01-31
10:51:13.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: ytmusicapi
-Version: 1.11.4
+Version: 1.11.5
Summary: Unofficial API for YouTube Music
Author-email: sigma67 <[email protected]>
License: MIT License