Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package streamlink for openSUSE:Factory 
checked in at 2026-01-22 15:13:52
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/streamlink (Old)
 and      /work/SRC/openSUSE:Factory/.streamlink.new.1928 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "streamlink"

Thu Jan 22 15:13:52 2026 rev:29 rq:1328446 version:8.1.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/streamlink/streamlink.changes    2025-12-18 
18:32:29.580236866 +0100
+++ /work/SRC/openSUSE:Factory/.streamlink.new.1928/streamlink.changes  
2026-01-22 15:15:47.886282625 +0100
@@ -1,0 +2,17 @@
+Tue Jan 20 23:19:02 UTC 2026 - Richard Rahl <[email protected]>
+
+- Update to version 8.1.2:
+  * Fixed: warnings when parsing HLS playlists with private-use language
+    subtags
+  * youtube: fixed live streams
+- Update to version 8.1.1:
+  * Fixed: --stream-segmented-queue-deadline not being applied correctly to the
+    Streamlink session options
+  * Changed: --hls-segment-ignore-names to not hardcode .ts HLS segment file
+    name extensions
+  * dailymotion: fixed 403 HLS playlist responses
+  * pluto: fixed url matchers and ad detection
+  * soop: fixed CDN mapping for ld_cdn based regions
+  * Build: removed unneeded wheel dependency
+
+-------------------------------------------------------------------

Old:
----
  streamlink-8.1.0.tar.gz
  streamlink-8.1.0.tar.gz.asc

New:
----
  streamlink-8.1.2.tar.gz
  streamlink-8.1.2.tar.gz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ streamlink.spec ++++++
--- /var/tmp/diff_new_pack.VI98JY/_old  2026-01-22 15:15:48.714317062 +0100
+++ /var/tmp/diff_new_pack.VI98JY/_new  2026-01-22 15:15:48.714317062 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package streamlink
 #
-# Copyright (c) 2025 SUSE LLC and contributors
+# 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
@@ -24,7 +24,7 @@
 %endif
 %{?sle15_python_module_pythons}%{!?sle15_python_module_pythons:%define pythons 
python3}
 Name:           streamlink%{psuffix}
-Version:        8.1.0
+Version:        8.1.2
 Release:        0
 Summary:        Program to pipe streams from services into a video player
 License:        Apache-2.0 AND BSD-2-Clause
@@ -49,7 +49,6 @@
 BuildRequires:  %{python_module urllib3 >= 2.0.0}
 BuildRequires:  %{python_module versioningit >= 2.0.0}
 BuildRequires:  %{python_module websocket-client >= 1.2.1}
-BuildRequires:  %{python_module wheel}
 BuildRequires:  fdupes
 
 %if "%{flavor}" == "test"

++++++ streamlink-8.1.0.tar.gz -> streamlink-8.1.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/CHANGELOG.md 
new/streamlink-8.1.2/CHANGELOG.md
--- old/streamlink-8.1.0/CHANGELOG.md   2025-12-14 19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/CHANGELOG.md   2026-01-18 13:20:38.000000000 +0100
@@ -1,5 +1,27 @@
 # Changelog
 
+## streamlink 8.1.2 (2026-01-18)
+
+- Fixed: warnings when parsing HLS playlists with private-use language subtags 
([#6780](https://github.com/streamlink/streamlink/pull/6780))
+- Updated plugins:
+  - youtube: fixed live streams 
([#6777](https://github.com/streamlink/streamlink/pull/6777))
+
+[Full 
changelog](https://github.com/streamlink/streamlink/compare/8.1.1...8.1.2)
+
+
+## streamlink 8.1.1 (2026-01-17)
+
+- Fixed: `--stream-segmented-queue-deadline` not being applied correctly to 
the Streamlink session options 
([#6758](https://github.com/streamlink/streamlink/pull/6758))
+- Changed: `--hls-segment-ignore-names` to not hardcode `.ts` HLS segment file 
name extensions ([#6747](https://github.com/streamlink/streamlink/pull/6747))
+- Updated plugins:
+  - dailymotion: fixed 403 HLS playlist responses 
([#6773](https://github.com/streamlink/streamlink/pull/6773))
+  - pluto: fixed url matchers and ad detection 
([#6767](https://github.com/streamlink/streamlink/pull/6767))
+  - soop: fixed CDN mapping for `ld_cdn` based regions 
([#6749](https://github.com/streamlink/streamlink/pull/6749))
+- Build: removed unneeded `wheel` dependency from `build-system.requires` and 
the `build` dependency group 
([#6754](https://github.com/streamlink/streamlink/pull/6754))
+
+[Full 
changelog](https://github.com/streamlink/streamlink/compare/8.1.0...8.1.1)
+
+
 ## streamlink 8.1.0 (2025-12-14)
 
 - Deprecated: `--hls-segment-queue-threshold` in favor of 
`--stream-segmented-queue-deadline` 
([#6734](https://github.com/streamlink/streamlink/pull/6734))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/LICENSE new/streamlink-8.1.2/LICENSE
--- old/streamlink-8.1.0/LICENSE        2025-12-14 19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/LICENSE        2026-01-18 13:20:38.000000000 +0100
@@ -1,5 +1,5 @@
 Copyright (c) 2011-2016, Christopher Rosell
-Copyright (c) 2016-2025, Streamlink Team
+Copyright (c) 2016-2026, Streamlink Team
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/PKG-INFO 
new/streamlink-8.1.2/PKG-INFO
--- old/streamlink-8.1.0/PKG-INFO       2025-12-14 19:07:27.963754200 +0100
+++ new/streamlink-8.1.2/PKG-INFO       2026-01-18 13:21:06.754069000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: streamlink
-Version: 8.1.0
+Version: 8.1.2
 Summary: Streamlink is a command-line utility that extracts streams from 
various services and pipes them into a video player of choice.
 Author: Streamlink
 Author-email: [email protected]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/docs/_build/man/streamlink.1 
new/streamlink-8.1.2/docs/_build/man/streamlink.1
--- old/streamlink-8.1.0/docs/_build/man/streamlink.1   2025-12-14 
19:07:23.000000000 +0100
+++ new/streamlink-8.1.2/docs/_build/man/streamlink.1   2026-01-18 
13:21:01.000000000 +0100
@@ -27,7 +27,7 @@
 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
 ..
-.TH "STREAMLINK" "1" "Dec 14, 2025" "8.1.0" "Streamlink"
+.TH "STREAMLINK" "1" "Jan 18, 2026" "8.1.2" "Streamlink"
 .SH NAME
 streamlink \- extracts streams from various services and pipes them into a 
video player of choice
 .SH SYNOPSIS
@@ -1529,6 +1529,6 @@
 .SH AUTHOR
 Streamlink Contributors
 .SH COPYRIGHT
-2025, Streamlink
+2026, Streamlink
 .\" Generated by docutils manpage writer.
 .
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/docs/changelog.md 
new/streamlink-8.1.2/docs/changelog.md
--- old/streamlink-8.1.0/docs/changelog.md      2025-12-14 19:07:02.000000000 
+0100
+++ new/streamlink-8.1.2/docs/changelog.md      2026-01-18 13:20:38.000000000 
+0100
@@ -1,5 +1,27 @@
 # Changelog
 
+## streamlink 8.1.2 (2026-01-18)
+
+- Fixed: warnings when parsing HLS playlists with private-use language subtags 
([#6780](https://github.com/streamlink/streamlink/pull/6780))
+- Updated plugins:
+  - youtube: fixed live streams 
([#6777](https://github.com/streamlink/streamlink/pull/6777))
+
+[Full 
changelog](https://github.com/streamlink/streamlink/compare/8.1.1...8.1.2)
+
+
+## streamlink 8.1.1 (2026-01-17)
+
+- Fixed: `--stream-segmented-queue-deadline` not being applied correctly to 
the Streamlink session options 
([#6758](https://github.com/streamlink/streamlink/pull/6758))
+- Changed: `--hls-segment-ignore-names` to not hardcode `.ts` HLS segment file 
name extensions ([#6747](https://github.com/streamlink/streamlink/pull/6747))
+- Updated plugins:
+  - dailymotion: fixed 403 HLS playlist responses 
([#6773](https://github.com/streamlink/streamlink/pull/6773))
+  - pluto: fixed url matchers and ad detection 
([#6767](https://github.com/streamlink/streamlink/pull/6767))
+  - soop: fixed CDN mapping for `ld_cdn` based regions 
([#6749](https://github.com/streamlink/streamlink/pull/6749))
+- Build: removed unneeded `wheel` dependency from `build-system.requires` and 
the `build` dependency group 
([#6754](https://github.com/streamlink/streamlink/pull/6754))
+
+[Full 
changelog](https://github.com/streamlink/streamlink/compare/8.1.0...8.1.1)
+
+
 ## streamlink 8.1.0 (2025-12-14)
 
 - Deprecated: `--hls-segment-queue-threshold` in favor of 
`--stream-segmented-queue-deadline` 
([#6734](https://github.com/streamlink/streamlink/pull/6734))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/docs/conf.py 
new/streamlink-8.1.2/docs/conf.py
--- old/streamlink-8.1.0/docs/conf.py   2025-12-14 19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/docs/conf.py   2026-01-18 13:20:38.000000000 +0100
@@ -16,7 +16,7 @@
 # 
https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
 
 project = "Streamlink"
-project_copyright = "2025, Streamlink"
+project_copyright = "2026, Streamlink"
 author = "Streamlink"
 version = streamlink_version.split("+")[0]
 release = streamlink_version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/pyproject.toml 
new/streamlink-8.1.2/pyproject.toml
--- old/streamlink-8.1.0/pyproject.toml 2025-12-14 19:07:27.966754200 +0100
+++ new/streamlink-8.1.2/pyproject.toml 2026-01-18 13:21:06.757069000 +0100
@@ -1,7 +1,6 @@
 [build-system]
 requires = [
   "setuptools >=77",
-  "wheel",
   # The versioningit build-requirement gets removed from the source 
distribution,
   # as the version string is already built into it (see the onbuild 
versioningit hook):
   # "versioningit >=2.0.0,<4",
@@ -106,12 +105,12 @@
   "freezegun >=1.5.0",
 ]
 lint = [
-  "ruff ==0.14.7",
+  "ruff ==0.14.11",
 ]
 typing = [
   { include-group = "test" },
   { include-group = "docs" },
-  "mypy[faster-cache] ==1.19.0",
+  "mypy[faster-cache] ==1.19.1",
   "typing-extensions >=4.0.0",
   "lxml-stubs",
   "trio-typing",
@@ -132,7 +131,6 @@
   { include-group = "dev" },
   "shtab",
   "build",
-  "wheel",
 ]
 script = [
   "inflection",
@@ -311,6 +309,7 @@
   "A003",  # builtin-attribute-shadowing
   "A005",  # stdlib-module-shadowing
   "ASYNC109",  # async-function-with-timeout
+  "B901",  # return-in-generator
   "C408",  # unnecessary-collection-call
   "ISC003",  # explicit-string-concatenation
   "PLC1901",  # compare-to-empty-string
@@ -324,15 +323,17 @@
 
 [tool.ruff.lint.per-file-ignores]
 "__init__.py" = ["F401"]
+"build_backend/__init__.py" = ["RUF067"]
 "docs/**" = ["INP"]
 "script/**" = ["INP"]
-"src/streamlink/__init__.py" = ["I"]
+"src/streamlink/__init__.py" = ["I", "RUF067"]
 "src/streamlink/_version.py" = ["I"]
 "src/streamlink/plugins/*" = ["RUF012"]
 "src/streamlink/session/http_useragents.py" = ["E501"]
 "src/streamlink/webbrowser/cdp/devtools/*" = ["E303", "E501", "F401", "TC"]
 "src/streamlink_cli/main.py" = ["PLW0603"]
 "tests/**" = ["RUF012"]
+"tests/**/__init__.py" = ["RUF067"]
 
 [tool.ruff.lint.isort]
 known-first-party = ["streamlink", "streamlink_cli"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/setup.py 
new/streamlink-8.1.2/setup.py
--- old/streamlink-8.1.0/setup.py       2025-12-14 19:07:27.966754200 +0100
+++ new/streamlink-8.1.2/setup.py       2026-01-18 13:21:06.757069000 +0100
@@ -27,6 +27,11 @@
 
 
 from pathlib import Path  # noqa: E402
+from typing import TYPE_CHECKING  # noqa: E402
+
+
+if TYPE_CHECKING:
+    from collections.abc import Sequence
 
 
 def is_wheel_for_windows(argv):
@@ -50,7 +55,7 @@
 
 
 # optional data files
-data_files = [
+data_files: "list[tuple[str, Sequence[str]]]" = [
     # shell completions:
     #  requires pre-built completion files via shtab ("build" dependency group)
     #  `./script/build-shell-completions.sh`
@@ -85,5 +90,5 @@
         cmdclass=get_cmdclasses(cmdclass),
         entry_points=entry_points,
         data_files=data_files,
-        version="8.1.0",
+        version="8.1.2",
     )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/src/streamlink/__init__.py 
new/streamlink-8.1.2/src/streamlink/__init__.py
--- old/streamlink-8.1.0/src/streamlink/__init__.py     2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink/__init__.py     2026-01-18 
13:20:38.000000000 +0100
@@ -1,22 +1,22 @@
-"""Streamlink extracts streams from various services.
+"""
+Streamlink extracts streams from various services.
 
 The main compontent of Streamlink is a command-line utility that
 launches the streams in a video player.
 
 An API is also provided that allows direct access to stream data.
 
-Full documentation is available at https://streamlink.github.io.
-
+Full documentation is available at https://streamlink.github.io/
 """
 
 from streamlink._version import __version__
+from streamlink.api import streams
+from streamlink.exceptions import StreamlinkError, PluginError, 
NoStreamsError, NoPluginError, StreamError
+from streamlink.session import Streamlink
+
 
 __title__ = "streamlink"
 __license__ = "Simplified BSD"
 __author__ = "Streamlink"
-__copyright__ = "Copyright 2025 Streamlink"
+__copyright__ = "Copyright 2026 Streamlink"
 __credits__ = ["https://github.com/streamlink/streamlink/blob/master/AUTHORS";]
-
-from streamlink.api import streams
-from streamlink.exceptions import StreamlinkError, PluginError, 
NoStreamsError, NoPluginError, StreamError
-from streamlink.session import Streamlink
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/src/streamlink/_version.py 
new/streamlink-8.1.2/src/streamlink/_version.py
--- old/streamlink-8.1.0/src/streamlink/_version.py     2025-12-14 
19:07:27.967754100 +0100
+++ new/streamlink-8.1.2/src/streamlink/_version.py     2026-01-18 
13:21:06.757069000 +0100
@@ -1 +1 @@
-__version__ = "8.1.0"
+__version__ = "8.1.2"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/streamlink-8.1.0/src/streamlink/plugins/dailymotion.py 
new/streamlink-8.1.2/src/streamlink/plugins/dailymotion.py
--- old/streamlink-8.1.0/src/streamlink/plugins/dailymotion.py  2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink/plugins/dailymotion.py  2026-01-18 
13:20:38.000000000 +0100
@@ -83,6 +83,11 @@
         self.author = media["owner"]["username"]
         self.title = media["title"]
 
+        # required for preventing 403 responses when using a French IP address
+        self.session.http.headers.update({
+            "priority": "u=1, i",
+        })
+
         for quality, streams in media["qualities"].items():
             for stream in streams:
                 if stream["type"] == "application/x-mpegURL":
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/src/streamlink/plugins/pluto.py 
new/streamlink-8.1.2/src/streamlink/plugins/pluto.py
--- old/streamlink-8.1.0/src/streamlink/plugins/pluto.py        2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink/plugins/pluto.py        2026-01-18 
13:20:38.000000000 +0100
@@ -10,24 +10,53 @@
 
 import logging
 import re
-from urllib.parse import parse_qsl, urljoin
+from dataclasses import dataclass
+from typing import ClassVar
+from urllib.parse import parse_qsl, urljoin, urlparse
 from uuid import uuid4
 
 from streamlink.exceptions import PluginError
 from streamlink.plugin import Plugin, pluginmatcher
 from streamlink.plugin.api import useragents, validate
-from streamlink.stream.hls import HLSStream, HLSStreamReader, HLSStreamWriter
+from streamlink.stream.hls import HLSSegment, HLSStream, HLSStreamReader, 
HLSStreamWriter, M3U8Parser
 from streamlink.utils.url import update_qsd
 
 
 log = logging.getLogger(__name__)
 
 
-class PlutoHLSStreamWriter(HLSStreamWriter):
-    ad_re = 
re.compile(r"_ad/creative/|creative/\d+_ad/|dai\.google\.com|Pluto_TV_OandO/.*(Bumper|plutotv_filler)")
+@dataclass
+class PlutoHLSSegment(HLSSegment):
+    ad: bool = False
+
+    _RE_AD: ClassVar[re.Pattern[str]] = re.compile(
+        r"""
+            _ad(?:/|%2F|_bumper)
+            |
+            plutotv_filler
+        """,
+        re.VERBOSE | re.IGNORECASE,
+    )
+
+    def __post_init__(self):
+        self.ad = self._is_ad()
+
+    def _is_ad(self) -> bool:
+        parsed = urlparse(self.uri)
+
+        if parsed.hostname and parsed.hostname.endswith("dai.google.com"):
+            return True
 
-    def should_filter_segment(self, segment):
-        return self.ad_re.search(segment.uri) is not None or 
super().should_filter_segment(segment)
+        return re.search(self._RE_AD, parsed.path or "") is not None
+
+
+class PlutoM3U8Parser(M3U8Parser):
+    __segment__ = PlutoHLSSegment
+
+
+class PlutoHLSStreamWriter(HLSStreamWriter):
+    def should_filter_segment(self, segment: PlutoHLSSegment):  # type: 
ignore[override]
+        return segment.ad or super().should_filter_segment(segment)
 
 
 class PlutoHLSStreamReader(HLSStreamReader):
@@ -37,24 +66,25 @@
 class PlutoHLSStream(HLSStream):
     __shortname__ = "hls-pluto"
     __reader__ = PlutoHLSStreamReader
+    __parser__ = PlutoM3U8Parser
 
 
 @pluginmatcher(
     name="live",
     pattern=re.compile(
-        r"https?://(?:www\.)?pluto\.tv/(?:\w{2}/)?live-tv/(?P<id>[^/]+)/?$",
+        r"https?://(?:www\.)?pluto\.tv/(?:\w{2,}/)?live-tv/(?P<id>[^/?]+)",
     ),
 )
 @pluginmatcher(
     name="series",
     pattern=re.compile(
-        
r"https?://(?:www\.)?pluto\.tv/(?:\w{2}/)?on-demand/series/(?P<id_s>[^/]+)(?:/season/\d+)?/episode/(?P<id_e>[^/]+)/?$",
+        
r"https?://(?:www\.)?pluto\.tv/(?:\w{2,}/)?on-demand/series/(?P<id_s>[^/]+)(?:/season/\d+)?/episode/(?P<id_e>[^/?]+)",
     ),
 )
 @pluginmatcher(
     name="movies",
     pattern=re.compile(
-        
r"https?://(?:www\.)?pluto\.tv/(?:\w{2}/)?on-demand/movies/(?P<id>[^/]+)/?$",
+        
r"https?://(?:www\.)?pluto\.tv/(?:\w{2,}/)?on-demand/movies/(?P<id>[^/?]+)",
     ),
 )
 class Pluto(Plugin):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/src/streamlink/plugins/soop.py 
new/streamlink-8.1.2/src/streamlink/plugins/soop.py
--- old/streamlink-8.1.0/src/streamlink/plugins/soop.py 2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink/plugins/soop.py 2026-01-18 
13:20:38.000000000 +0100
@@ -95,6 +95,7 @@
 
     CDN_TYPE_MAPPING = {
         "gs_cdn": "gs_cdn_pc_web",
+        "lg_cdn": "lg_cdn_pc_web",
     }
 
     CHANNEL_RESULT_OK = 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/src/streamlink/plugins/youtube.py 
new/streamlink-8.1.2/src/streamlink/plugins/youtube.py
--- old/streamlink-8.1.0/src/streamlink/plugins/youtube.py      2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink/plugins/youtube.py      2026-01-18 
13:20:38.000000000 +0100
@@ -10,7 +10,6 @@
 $notes VOD content and protected videos are not supported
 """
 
-import json
 import logging
 import re
 from urllib.parse import urlparse, urlunparse
@@ -327,28 +326,23 @@
             except (PluginError, TypeError):
                 return
 
-        try:
-            api_key = re.search(r'"INNERTUBE_API_KEY":\s*"([^"]+)"', 
res.text).group(1)
-        except AttributeError:
+        if m := 
re.search(r"""(?P<q1>["'])INNERTUBE_API_KEY(?P=q1)\s*:\s*(?P<q2>["'])(?P<data>.+?)(?P=q2)""",
 res.text):
+            api_key = m.group("data")
+        else:
             api_key = "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8"
 
-        try:
-            client_version = 
re.search(r'"INNERTUBE_CLIENT_VERSION":\s*"([\d\.]+)"', res.text).group(1)
-        except AttributeError:
-            client_version = "1.20210616.1.0"
-
-        res = self.session.http.post(
+        return self.session.http.post(
             "https://www.youtube.com/youtubei/v1/player";,
             headers={"Content-Type": "application/json"},
             params={"key": api_key},
-            data=json.dumps({
+            json={
                 "videoId": video_id,
                 "contentCheckOk": True,
                 "racyCheckOk": True,
                 "context": {
                     "client": {
-                        "clientName": "WEB",
-                        "clientVersion": client_version,
+                        "clientName": "ANDROID",
+                        "clientVersion": "19.45.36",
                         "platform": "DESKTOP",
                         "clientScreen": "EMBED",
                         "clientFormFactor": "UNKNOWN_FORM_FACTOR",
@@ -357,9 +351,11 @@
                     "user": {"lockedSafetyMode": "false"},
                     "request": {"useSsl": "true"},
                 },
-            }),
+            },
+            schema=validate.Schema(
+                validate.parse_json(),
+            ),
         )
-        return parse_json(res.text)
 
     @staticmethod
     def _data_video_id(data):
@@ -371,17 +367,6 @@
                 if videoId is not None:
                     return videoId
 
-    def _data_status(self, data, errorlog=False):
-        if not data:
-            return False
-        status, reason = self._schema_playabilitystatus(data)
-        # assume that there's an error if reason is set (status will still be 
"OK" for some reason)
-        if status != "OK" or reason:
-            if errorlog:
-                log.error(f"Could not get video info - {status}: {reason}")
-            return False
-        return True
-
     def _get_streams(self):
         res = self._get_res(self.url)
 
@@ -394,18 +379,25 @@
             self.url = self._url_canonical.format(video_id=video_id)
             res = self._get_res(self.url)
 
-        data = self._get_data_from_regex(res, 
self._re_ytInitialPlayerResponse, "initial player response")
-        if not self._data_status(data):
-            data = self._get_data_from_api(res)
-            if not self._data_status(data, True):
-                return
+        # TODO: clean up the validation schemas and how they're applied
+
+        if not (data := self._get_data_from_api(res)):
+            return
+        status, reason = self._schema_playabilitystatus(data)
+        # assume that there's an error if reason is set (status will still be 
"OK" for some reason)
+        if status != "OK" or reason:
+            log.error(f"Could not get video info - {status}: {reason}")
+            return
 
-        self.id, self.author, self.category, self.title, is_live = 
self._schema_videodetails(data)
+        # the initial player response contains the category data, which the 
API response does not
+        init_player_response = self._get_data_from_regex(res, 
self._re_ytInitialPlayerResponse, "initial player response")
+        self.id, self.author, self.category, self.title, is_live = 
self._schema_videodetails(init_player_response)
         log.debug(f"Using video ID: {self.id}")
 
         if is_live:
             log.debug("This video is live.")
 
+        # TODO: remove parsing of non-HLS stuff, as we don't support this
         streams = {}
         hls_manifest, formats, adaptive_formats = 
self._schema_streamingdata(data)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/streamlink-8.1.0/src/streamlink/session/http_useragents.py 
new/streamlink-8.1.2/src/streamlink/session/http_useragents.py
--- old/streamlink-8.1.0/src/streamlink/session/http_useragents.py      
2025-12-14 19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink/session/http_useragents.py      
2026-01-18 13:20:38.000000000 +0100
@@ -1,11 +1,11 @@
-ANDROID = "Mozilla/5.0 (Linux; Android 16) AppleWebKit/537.36 (KHTML, like 
Gecko) Chrome/142.0.7444.172 Mobile Safari/537.36"
-CHROME = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, 
like Gecko) Chrome/142.0.0.0 Safari/537.36"
+ANDROID = "Mozilla/5.0 (Linux; Android 16) AppleWebKit/537.36 (KHTML, like 
Gecko) Chrome/143.0.7499.110 Mobile Safari/537.36"
+CHROME = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, 
like Gecko) Chrome/143.0.0.0 Safari/537.36"
 CHROME_OS = "Mozilla/5.0 (X11; CrOS x86_64 16181.61.0) AppleWebKit/537.36 
(KHTML, like Gecko) Chrome/134.0.6998.198 Safari/537.36"
-FIREFOX = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:145.0) Gecko/20100101 
Firefox/145.0"
+FIREFOX = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:146.0) Gecko/20100101 
Firefox/146.0"
 IE_11 = "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
-IPHONE = "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7_2 like Mac OS X) 
AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 
Safari/604.1"
-OPERA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, 
like Gecko) Chrome/142.0.0.0 Safari/537.36 OPR/124.0.0.0"
-SAFARI = "Mozilla/5.0 (Macintosh; Intel Mac OS X 15_7_2) AppleWebKit/605.1.15 
(KHTML, like Gecko) Version/26.0 Safari/605.1.15"
+IPHONE = "Mozilla/5.0 (iPhone; CPU iPhone OS 18_7_3 like Mac OS X) 
AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Mobile/15E148 
Safari/604.1"
+OPERA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, 
like Gecko) Chrome/143.0.0.0 Safari/537.36 OPR/124.0.0.0"
+SAFARI = "Mozilla/5.0 (Macintosh; Intel Mac OS X 15_7_3) AppleWebKit/605.1.15 
(KHTML, like Gecko) Version/26.0 Safari/605.1.15"
 
 # Backwards compatibility
 EDGE = CHROME
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/src/streamlink/stream/dash/dash.py 
new/streamlink-8.1.2/src/streamlink/stream/dash/dash.py
--- old/streamlink-8.1.0/src/streamlink/stream/dash/dash.py     2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink/stream/dash/dash.py     2026-01-18 
13:20:38.000000000 +0100
@@ -33,6 +33,8 @@
 
 
 class DASHStreamWriter(SegmentedStreamWriter[DASHSegment, Response]):
+    WRITE_CHUNK_SIZE: int = 8192
+
     reader: DASHStreamReader
     stream: DASHStream
 
@@ -69,8 +71,8 @@
         except StreamError as err:
             log.error(f"{self.reader.mime_type} segment {name}: failed 
({err})")
 
-    def write(self, segment, res, chunk_size=8192):
-        for chunk in res.iter_content(chunk_size):
+    def write(self, segment: DASHSegment, result: Response, *data):
+        for chunk in result.iter_content(self.WRITE_CHUNK_SIZE):
             if self.closed:
                 log.warning(f"{self.reader.mime_type} segment {segment.name}: 
aborted")
                 return
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/src/streamlink/stream/hls/hls.py 
new/streamlink-8.1.2/src/streamlink/stream/hls/hls.py
--- old/streamlink-8.1.0/src/streamlink/stream/hls/hls.py       2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink/stream/hls/hls.py       2026-01-18 
13:20:38.000000000 +0100
@@ -96,8 +96,7 @@
         ignore_names = {*options.get("hls-segment-ignore-names")}
         if ignore_names:
             segments = "|".join(map(re.escape, ignore_names))
-            # noinspection RegExpUnnecessaryNonCapturingGroup
-            self.ignore_names = re.compile(rf"(?:{segments})\.ts", 
re.IGNORECASE)
+            self.ignore_names = re.compile(segments, re.IGNORECASE)
 
     @staticmethod
     def num_to_iv(n: int) -> bytes:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/streamlink-8.1.0/src/streamlink/stream/hls/segment.py 
new/streamlink-8.1.2/src/streamlink/stream/hls/segment.py
--- old/streamlink-8.1.0/src/streamlink/stream/hls/segment.py   2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink/stream/hls/segment.py   2026-01-18 
13:20:38.000000000 +0100
@@ -18,6 +18,7 @@
 
 
 _MEDIA_LANGUAGE_CODES_RESERVED_LOCAL = re.compile(r"^q[a-t][a-z]$")
+_MEDIA_LANGUAGE_CODES_PRIVATE_USE_SUBTAGS = re.compile(r"^[a-z]{2,3}-x-\S+$")
 
 
 class Resolution(NamedTuple):
@@ -88,7 +89,11 @@
         self._parse_language()
 
     def _parse_language(self):
-        if self.language is None or 
_MEDIA_LANGUAGE_CODES_RESERVED_LOCAL.match(self.language):
+        if (
+            self.language is None
+            or _MEDIA_LANGUAGE_CODES_RESERVED_LOCAL.match(self.language)
+            or _MEDIA_LANGUAGE_CODES_PRIVATE_USE_SUBTAGS.match(self.language)
+        ):
             return
 
         try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/streamlink-8.1.0/src/streamlink/validate/_validate.py 
new/streamlink-8.1.2/src/streamlink/validate/_validate.py
--- old/streamlink-8.1.0/src/streamlink/validate/_validate.py   2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink/validate/_validate.py   2026-01-18 
13:20:38.000000000 +0100
@@ -131,7 +131,7 @@
     if not schema(value):
         raise ValidationError(
             "{callable} is not true",
-            callable=f"{schema.__name__}({value!r})",
+            callable=f"{getattr(schema, '__name__', 
schema.__class__.__name__)}({value!r})",
             schema=abc.Callable,
         )
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/streamlink-8.1.0/src/streamlink/validate/_validators.py 
new/streamlink-8.1.2/src/streamlink/validate/_validators.py
--- old/streamlink-8.1.0/src/streamlink/validate/_validators.py 2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink/validate/_validators.py 2026-01-18 
13:20:38.000000000 +0100
@@ -21,10 +21,12 @@
 if TYPE_CHECKING:
     from collections.abc import Callable, Mapping
 
+    from _typeshed import SupportsLen
+
 
 # String related validators
 
-_validator_length_ops: Mapping[str, tuple[Callable, str]] = {
+_validator_length_ops: Mapping[Literal["lt", "le", "eq", "ge", "gt"], 
tuple[Callable[[int, int], bool], str]] = {
     "lt": (operator.lt, "Length must be <{number}, but value is {value}"),
     "le": (operator.le, "Length must be <={number}, but value is {value}"),
     "eq": (operator.eq, "Length must be =={number}, but value is {value}"),
@@ -62,8 +64,8 @@
         schema.validate([1, 2, 3])  # raises ValidationError
     """
 
-    def length(value):
-        func, msg = _validator_length_ops.get(op, "ge")
+    def length(value: SupportsLen):
+        func, msg = _validator_length_ops.get(op) or 
_validator_length_ops["ge"]
         if not func(len(value), number):
             raise ValidationError(
                 msg,
@@ -608,7 +610,9 @@
     :raise ValidationError: On parsing error
     """
 
-    return TransformSchema(_parse_json, *args, **kwargs, 
exception=ValidationError, schema=None)
+    kwargs.update(exception=ValidationError, schema=None)
+
+    return TransformSchema(_parse_json, *args, **kwargs)
 
 
 def validator_parse_html(*args, **kwargs) -> TransformSchema:
@@ -628,7 +632,9 @@
     :raise ValidationError: On parsing error
     """
 
-    return TransformSchema(_parse_html, *args, **kwargs, 
exception=ValidationError, schema=None)
+    kwargs.update(exception=ValidationError, schema=None)
+
+    return TransformSchema(_parse_html, *args, **kwargs)
 
 
 def validator_parse_xml(*args, **kwargs) -> TransformSchema:
@@ -648,7 +654,9 @@
     :raise ValidationError: On parsing error
     """
 
-    return TransformSchema(_parse_xml, *args, **kwargs, 
exception=ValidationError, schema=None)
+    kwargs.update(exception=ValidationError, schema=None)
+
+    return TransformSchema(_parse_xml, *args, **kwargs)
 
 
 def validator_parse_qsd(*args, **kwargs) -> TransformSchema:
@@ -670,6 +678,9 @@
 
     def parser(*_args, **_kwargs):
         validate(AnySchema(str, bytes), _args[0])
-        return _parse_qsd(*_args, **_kwargs, exception=ValidationError, 
schema=None)
+
+        _kwargs.update(exception=ValidationError, schema=None)
+
+        return _parse_qsd(*_args, **_kwargs)
 
     return TransformSchema(parser, *args, **kwargs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/src/streamlink.egg-info/PKG-INFO 
new/streamlink-8.1.2/src/streamlink.egg-info/PKG-INFO
--- old/streamlink-8.1.0/src/streamlink.egg-info/PKG-INFO       2025-12-14 
19:07:27.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink.egg-info/PKG-INFO       2026-01-18 
13:21:06.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: streamlink
-Version: 8.1.0
+Version: 8.1.2
 Summary: Streamlink is a command-line utility that extracts streams from 
various services and pipes them into a video player of choice.
 Author: Streamlink
 Author-email: [email protected]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/src/streamlink_cli/__init__.py 
new/streamlink-8.1.2/src/streamlink_cli/__init__.py
--- old/streamlink-8.1.0/src/streamlink_cli/__init__.py 2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink_cli/__init__.py 2026-01-18 
13:20:38.000000000 +0100
@@ -1,3 +1,5 @@
+# ruff: noqa: RUF067
+
 from signal import SIGINT, SIGTERM, signal
 from sys import exit  # noqa: A004
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/src/streamlink_cli/argparser.py 
new/streamlink-8.1.2/src/streamlink_cli/argparser.py
--- old/streamlink-8.1.0/src/streamlink_cli/argparser.py        2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink_cli/argparser.py        2026-01-18 
13:20:38.000000000 +0100
@@ -1533,19 +1533,20 @@
     ("http_timeout", "http-timeout", None),
     # stream transport arguments
     ("hls_duration", "hls-duration", None),  # deprecated options must come 
first
+    ("hls_segment_queue_threshold", "hls-segment-queue-threshold", None),  # 
deprecated options must come first
     ("ringbuffer_size", "ringbuffer-size", None),
     ("mux_subtitles", "mux-subtitles", None),
     ("stream_segment_attempts", "stream-segment-attempts", None),
     ("stream_segment_threads", "stream-segment-threads", None),
     ("stream_segment_timeout", "stream-segment-timeout", None),
     ("stream_segmented_duration", "stream-segmented-duration", None),
+    ("stream_segmented_queue_deadline", "stream-segmented-queue-deadline", 
None),
     ("stream_timeout", "stream-timeout", None),
     ("hls_live_edge", "hls-live-edge", None),
     ("hls_live_restart", "hls-live-restart", None),
     ("hls_start_offset", "hls-start-offset", None),
     ("hls_playlist_reload_attempts", "hls-playlist-reload-attempts", None),
     ("hls_playlist_reload_time", "hls-playlist-reload-time", None),
-    ("hls_segment_queue_threshold", "hls-segment-queue-threshold", None),
     ("hls_segment_stream_data", "hls-segment-stream-data", None),
     ("hls_segment_ignore_names", "hls-segment-ignore-names", None),
     ("hls_segment_key_uri", "hls-segment-key-uri", None),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/streamlink-8.1.0/src/streamlink_cli/utils/__init__.py 
new/streamlink-8.1.2/src/streamlink_cli/utils/__init__.py
--- old/streamlink-8.1.0/src/streamlink_cli/utils/__init__.py   2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/src/streamlink_cli/utils/__init__.py   2026-01-18 
13:20:38.000000000 +0100
@@ -1,3 +1,5 @@
+# ruff: noqa: RUF067
+
 import json
 from datetime import datetime as _datetime
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/tests/cli/test_argparser.py 
new/streamlink-8.1.2/tests/cli/test_argparser.py
--- old/streamlink-8.1.0/tests/cli/test_argparser.py    2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/tests/cli/test_argparser.py    2026-01-18 
13:20:38.000000000 +0100
@@ -297,6 +297,50 @@
     assert session.options.get_explicit("option") == expected
 
 
[email protected](
+    ("argv", "option", "value", "deprecations"),
+    [
+        pytest.param(
+            [
+                "--stream-segmented-duration=123",
+                "--hls-duration=321",
+            ],
+            "stream-segmented-duration",
+            123,
+            ["`hls-duration` has been deprecated in favor of the 
`stream-segmented-duration` option"],
+            id="hls-duration",
+        ),
+        pytest.param(
+            [
+                "--stream-segmented-queue-deadline=0.0",
+                "--hls-segment-queue-threshold=5.0",
+            ],
+            "stream-segmented-queue-deadline",
+            0.0,
+            ["`hls-segment-queue-threshold` has been deprecated in favor of 
the `stream-segmented-queue-deadline` option"],
+            id="hls-segment-queue-threshold",
+        ),
+    ],
+)
+def test_setup_session_options_deprecations(
+    parser: ArgumentParser,
+    session: Streamlink,
+    argv: list[str],
+    option: str,
+    value: Any,
+    deprecations: list[str],
+):
+    """
+    Test all deprecated ArgumentParser arguments that are mapped to Streamlink 
session options
+    and test whether the order is correct, so deprecated arguments are always 
overridden.
+    """
+    args = parser.parse_args(argv)
+    with pytest.warns(SDW) as warnings:
+        setup_session_options(session, args)
+    assert [str(dep.message) for dep in warnings.list] == deprecations
+    assert session.options.get_explicit(option) == value
+
+
 def test_cli_main_setup_session_options(monkeypatch: pytest.MonkeyPatch, 
parser: ArgumentParser, session: Streamlink):
     class StopTest(Exception):
         pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/tests/plugins/test_pluto.py 
new/streamlink-8.1.2/tests/plugins/test_pluto.py
--- old/streamlink-8.1.0/tests/plugins/test_pluto.py    2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/tests/plugins/test_pluto.py    2026-01-18 
13:20:38.000000000 +0100
@@ -38,7 +38,4 @@
 
     should_not_match = [
         "https://pluto.tv/live-tv";,
-        "https://pluto.tv/en/live-tv/61409f8d6feb30000766b675/details";,
-        
"https://pluto.tv/en/on-demand/series/5e00cd538e67b0dcb2cf3bcd/details/season/1";,
-        
"https://pluto.tv/en/on-demand/movies/600545d1813b2d001b686fa9/details";,
     ]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/streamlink-8.1.0/tests/resources/hls/test_media_language_special.m3u8 
new/streamlink-8.1.2/tests/resources/hls/test_media_language_special.m3u8
--- old/streamlink-8.1.0/tests/resources/hls/test_media_language_special.m3u8   
2025-12-14 19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/tests/resources/hls/test_media_language_special.m3u8   
2026-01-18 13:20:38.000000000 +0100
@@ -2,6 +2,7 @@
 #EXT-X-INDEPENDENT-SEGMENTS
 
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",LANGUAGE="en",NAME="English",AUTOSELECT=YES,DEFAULT=YES
 
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Reserved",LANGUAGE="qaa",AUTOSELECT=NO,URI="qaa.m3u8"
+#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Private 
use",LANGUAGE="en-x-foo",AUTOSELECT=NO,URI="en-x-foo.m3u8"
 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Does not 
exist",LANGUAGE="INVALID",AUTOSELECT=NO,URI="invalid.m3u8"
 
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Undetermined",LANGUAGE="und",AUTOSELECT=NO,URI="und.m3u8"
 #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Not 
selected",LANGUAGE="qqq",AUTOSELECT=NO,URI="qqq.m3u8"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/tests/stream/hls/test_hls.py 
new/streamlink-8.1.2/tests/stream/hls/test_hls.py
--- old/streamlink-8.1.0/tests/stream/hls/test_hls.py   2025-12-14 
19:07:02.000000000 +0100
+++ new/streamlink-8.1.2/tests/stream/hls/test_hls.py   2026-01-18 
13:20:38.000000000 +0100
@@ -1398,29 +1398,58 @@
         ]
 
     @pytest.mark.parametrize(
-        ("session", "_playlist"),
+        ("session", "_playlist", "expected"),
         [
             pytest.param(
-                {"hls-audio-select": ["und", "qaa", "invalid"]},
+                {"hls-audio-select": ["und", "qaa", "en-x-foo", "invalid"]},
                 {"playlist": "hls/test_media_language_special.m3u8"},
-                id="special-reserved-invalid",
+                [
+                    "http://mocked/path/playlist.m3u8";,
+                    "http://mocked/path/qaa.m3u8";,
+                    "http://mocked/path/en-x-foo.m3u8";,
+                    "http://mocked/path/invalid.m3u8";,
+                    "http://mocked/path/und.m3u8";,
+                ],
+                id="special-reserved-private-invalid",
             ),
             pytest.param(
-                {"hls-audio-select": ["Undetermined", "Reserved", "does NOT 
exist"]},
+                {"hls-audio-select": ["Undetermined", "Reserved", "Private 
use", "does NOT exist"]},
                 {"playlist": "hls/test_media_language_special.m3u8"},
+                [
+                    "http://mocked/path/playlist.m3u8";,
+                    "http://mocked/path/qaa.m3u8";,
+                    "http://mocked/path/en-x-foo.m3u8";,
+                    "http://mocked/path/invalid.m3u8";,
+                    "http://mocked/path/und.m3u8";,
+                ],
                 id="name-attribute",
             ),
+            pytest.param(
+                {"hls-audio-select": ["*"]},
+                {"playlist": "hls/test_media_language_special.m3u8"},
+                [
+                    "http://mocked/path/playlist.m3u8";,
+                    "http://mocked/path/qaa.m3u8";,
+                    "http://mocked/path/en-x-foo.m3u8";,
+                    "http://mocked/path/invalid.m3u8";,
+                    "http://mocked/path/und.m3u8";,
+                    "http://mocked/path/qqq.m3u8";,
+                ],
+                id="all",
+            ),
         ],
         indirect=["session", "_playlist"],
     )
-    def test_parse_media_language(self, caplog: pytest.LogCaptureFixture, 
session: Streamlink, stream: MuxedHLSStream):
+    def test_parse_media_language(
+        self,
+        caplog: pytest.LogCaptureFixture,
+        session: Streamlink,
+        stream: MuxedHLSStream,
+        _playlist: None,
+        expected: list[str],
+    ):
         assert isinstance(stream, MuxedHLSStream)
-        assert [substream.url for substream in stream.substreams] == [
-            "http://mocked/path/playlist.m3u8";,
-            "http://mocked/path/qaa.m3u8";,
-            "http://mocked/path/invalid.m3u8";,
-            "http://mocked/path/und.m3u8";,
-        ]
+        assert [substream.url for substream in stream.substreams] == expected
         assert [
             record.message
             for record in caplog.get_records(when="setup")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/streamlink-8.1.0/tests/test_validate.py 
new/streamlink-8.1.2/tests/test_validate.py
--- old/streamlink-8.1.0/tests/test_validate.py 2025-12-14 19:07:02.000000000 
+0100
+++ new/streamlink-8.1.2/tests/test_validate.py 2026-01-18 13:20:38.000000000 
+0100
@@ -295,9 +295,14 @@
     def subject(v):
         return v is not None
 
+    class Subject:
+        def __call__(self, v):
+            return v is not None
+
     def test_success(self):
         value = object()
         assert validate.validate(self.subject, value) is value
+        assert validate.validate(self.Subject(), value) is value
 
     def test_failure(self):
         with pytest.raises(ValidationError) as cm:
@@ -310,6 +315,16 @@
             """,
         )
 
+        with pytest.raises(ValidationError) as cm:
+            validate.validate(self.Subject(), None)
+        assert_validationerror(
+            cm.value,
+            """
+                ValidationError(Callable):
+                  Subject(None) is not true
+            """,
+        )
+
 
 class TestPattern:
     @pytest.mark.parametrize(
@@ -626,7 +641,7 @@
         with pytest.raises(ValidationError) as cm:
             # noinspection PyTypeChecker
             validate.validate(
-                validate.transform("not a callable"),
+                validate.transform("not a callable"),  # type: ignore
                 "foo",
             )
         assert_validationerror(
@@ -986,6 +1001,10 @@
             ((3,), [1, 2, 3]),
             ((3,), "abcd"),
             ((3,), [1, 2, 3, 4]),
+            ((3, "invalid"), "abc"),
+            ((3, "invalid"), [1, 2, 3]),
+            ((3, "invalid"), "abcd"),
+            ((3, "invalid"), [1, 2, 3, 4]),
             ((3, "lt"), "ab"),
             ((3, "lt"), [1, 2]),
             ((3, "le"), "ab"),
@@ -1010,6 +1029,8 @@
         [
             ((3,), "ab", "Length must be >=3, but value is 2"),
             ((3,), [1, 2], "Length must be >=3, but value is 2"),
+            ((3, "invalid"), "ab", "Length must be >=3, but value is 2"),
+            ((3, "invalid"), [1, 2], "Length must be >=3, but value is 2"),
             ((3, "lt"), "abc", "Length must be <3, but value is 3"),
             ((3, "lt"), [1, 2, 3], "Length must be <3, but value is 3"),
             ((3, "le"), "abcd", "Length must be <=3, but value is 4"),

Reply via email to