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

Reply via email to