Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package yt-dlp for openSUSE:Factory checked 
in at 2026-02-01 22:05:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/yt-dlp (Old)
 and      /work/SRC/openSUSE:Factory/.yt-dlp.new.1995 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "yt-dlp"

Sun Feb  1 22:05:46 2026 rev:85 rq:1330251 version:2026.01.31

Changes:
--------
--- /work/SRC/openSUSE:Factory/yt-dlp/yt-dlp.changes    2026-01-31 
16:17:41.129378418 +0100
+++ /work/SRC/openSUSE:Factory/.yt-dlp.new.1995/yt-dlp.changes  2026-02-01 
22:07:08.844951490 +0100
@@ -1,0 +2,8 @@
+Sun Feb  1 09:43:09 UTC 2026 - Jan Engelhardt <[email protected]>
+
+- Update to release 2026.01.31
+  * yt: Add `web_embedded` fallback for `android_vr` client
+  * yt: Remove broken `ios_downgraded` and `tv_embedded` player
+    clients
+
+-------------------------------------------------------------------

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

Other differences:
------------------
++++++ yt-dlp.spec ++++++
--- /var/tmp/diff_new_pack.s2gNEm/_old  2026-02-01 22:07:11.249051890 +0100
+++ /var/tmp/diff_new_pack.s2gNEm/_new  2026-02-01 22:07:11.249051890 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package yt-dlp
 #
-# 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
@@ -27,7 +27,7 @@
 %endif
 
 Name:           yt-dlp
-Version:        2026.01.29
+Version:        2026.01.31
 %define ejsver  0.4.0
 Release:        0
 Summary:        Enhanced fork of youtube-dl, a video site downloader for 
offline watching
@@ -42,8 +42,8 @@
 BuildRequires:  fdupes
 BuildRequires:  make >= 4
 BuildRequires:  python-rpm-macros
-BuildRequires:  zip
 BuildRequires:  unzip
+BuildRequires:  zip
 BuildArch:      noarch
 Obsoletes:      yt-dlp-bash-completion < %version-%release
 Provides:       yt-dlp-bash-completion = %version-%release

++++++ _scmsync.obsinfo ++++++
--- /var/tmp/diff_new_pack.s2gNEm/_old  2026-02-01 22:07:11.289053561 +0100
+++ /var/tmp/diff_new_pack.s2gNEm/_new  2026-02-01 22:07:11.293053728 +0100
@@ -1,5 +1,5 @@
-mtime: 1769795804
-commit: 05dfd3096119342778e353e360063d3c4da18d5fc3b1098aaeb5a4195a0baac8
+mtime: 1769939036
+commit: 9e1bdc6b836ccf67fa5c8414ac201018e108100fff4efb5de7353c2aaa744ca5
 url: https://src.opensuse.org/jengelh/yt-dlp
 revision: master
 

++++++ build.specials.obscpio ++++++

++++++ build.specials.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.gitignore new/.gitignore
--- old/.gitignore      1970-01-01 01:00:00.000000000 +0100
+++ new/.gitignore      2026-02-01 10:44:12.000000000 +0100
@@ -0,0 +1 @@
+.osc

++++++ yt-dlp.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/AUTHORS new/yt-dlp/AUTHORS
--- old/yt-dlp/AUTHORS  2026-01-29 18:00:51.000000000 +0100
+++ new/yt-dlp/AUTHORS  2026-02-01 00:55:31.000000000 +0100
@@ -1171,6 +1171,7 @@
 aviperes
 axelerometer
 [email protected]
+azdlonky
 azeem
 barsnick
 bashonly
@@ -1613,6 +1614,7 @@
 theGeekPirate
 thedenv
 thegymguy
+thematuu
 theychx
 thomasmllt
 tiktok
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/CONTRIBUTORS new/yt-dlp/CONTRIBUTORS
--- old/yt-dlp/CONTRIBUTORS     2026-01-29 18:00:50.000000000 +0100
+++ new/yt-dlp/CONTRIBUTORS     2026-02-01 00:55:31.000000000 +0100
@@ -862,3 +862,5 @@
 romainreignier
 Sytm
 zahlman
+azdlonky
+thematuu
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/Changelog.md new/yt-dlp/Changelog.md
--- old/yt-dlp/Changelog.md     2026-01-29 18:00:45.000000000 +0100
+++ new/yt-dlp/Changelog.md     2026-02-01 00:55:25.000000000 +0100
@@ -4,6 +4,20 @@
 # To create a release, dispatch the 
https://github.com/yt-dlp/yt-dlp/actions/workflows/release.yml workflow on 
master
 -->
 
+### 2026.01.31
+
+#### Extractor changes
+- **soop**: [Support subscription-only 
VODs](https://github.com/yt-dlp/yt-dlp/commit/d0bf3d0fc3455d411ae44c0a5dc974dd1481e3aa)
 ([#15523](https://github.com/yt-dlp/yt-dlp/issues/15523)) by 
[thematuu](https://github.com/thematuu)
+- **unsupported**: [Update unsupported 
URLs](https://github.com/yt-dlp/yt-dlp/commit/bf5d8c2a663ac690711262aebc733c1b06a54b26)
 ([#15410](https://github.com/yt-dlp/yt-dlp/issues/15410)) by 
[bashonly](https://github.com/bashonly)
+- **whyp**: [Extract more 
metadata](https://github.com/yt-dlp/yt-dlp/commit/0d8ee637e83d62edaf22aa85833a51c70d560389)
 ([#15757](https://github.com/yt-dlp/yt-dlp/issues/15757)) by 
[azdlonky](https://github.com/azdlonky)
+- **youtube**
+    - [Add `web_embedded` fallback for `android_vr` 
client](https://github.com/yt-dlp/yt-dlp/commit/bb1c05752c288a81e0e281f1caf5395411936376)
 ([#15785](https://github.com/yt-dlp/yt-dlp/issues/15785)) by 
[bashonly](https://github.com/bashonly)
+    - [Remove broken `ios_downgraded` player 
client](https://github.com/yt-dlp/yt-dlp/commit/c3674575faa23b20e97be8b73f68b9f7b4cea9ab)
 ([#15786](https://github.com/yt-dlp/yt-dlp/issues/15786)) by 
[bashonly](https://github.com/bashonly)
+    - [Remove broken `tv_embedded` player 
client](https://github.com/yt-dlp/yt-dlp/commit/8eb794366eb69e7377ff88eed7929c00195c8d74)
 ([#15787](https://github.com/yt-dlp/yt-dlp/issues/15787)) by 
[bashonly](https://github.com/bashonly)
+
+#### Misc. changes
+- **cleanup**: Miscellaneous: 
[9a9a6b6](https://github.com/yt-dlp/yt-dlp/commit/9a9a6b6fe44a30458c1754ef064f354f04a84004)
 by [bashonly](https://github.com/bashonly)
+
 ### 2026.01.29
 
 #### Core changes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/README.md new/yt-dlp/README.md
--- old/yt-dlp/README.md        2026-01-29 18:00:50.000000000 +0100
+++ new/yt-dlp/README.md        2026-02-01 00:55:30.000000000 +0100
@@ -1860,7 +1860,7 @@
 #### youtube
 * `lang`: Prefer translated metadata (`title`, `description` etc) of this 
language code (case-sensitive). By default, the video primary language metadata 
is preferred, with a fallback to `en` translated. See 
[youtube/_base.py](https://github.com/yt-dlp/yt-dlp/blob/415b4c9f955b1a0391204bd24a7132590e7b3bdb/yt_dlp/extractor/youtube/_base.py#L402-L409)
 for the list of supported content language codes
 * `skip`: One or more of `hls`, `dash` or `translated_subs` to skip extraction 
of the m3u8 manifests, dash manifests and [auto-translated 
subtitles](https://github.com/yt-dlp/yt-dlp/issues/4090#issuecomment-1158102032)
 respectively
-* `player_client`: Clients to extract video data from. The currently available 
clients are `web`, `web_safari`, `web_embedded`, `web_music`, `web_creator`, 
`mweb`, `ios`, `ios_downgraded`, `android`, `android_vr`, `tv`, `tv_simply`, 
`tv_downgraded`, and `tv_embedded`. By default, 
`android_vr,ios_downgraded,web,web_safari` is used. If no JavaScript 
runtime/engine is available, then `android_vr,ios_downgraded` is used. If 
logged-in cookies are passed to yt-dlp, then `tv_downgraded,web,web_safari` is 
used for free accounts and `tv_downgraded,web_creator,web` is used for premium 
accounts. The `web_music` client is added for `music.youtube.com` URLs when 
logged-in cookies are used. The `web_embedded` client is added for 
age-restricted videos but only works if the video is embeddable. The 
`tv_embedded` and `web_creator` clients are added for age-restricted videos if 
account age-verification is required. Some clients, such as `web` and 
`web_music`, require a `po_token` for their formats to
  be downloadable. Some clients, such as `web_creator`, will only work with 
authentication. Not all clients support authentication via cookies. You can use 
`default` for the default clients, or you can use `all` for all clients (not 
recommended). You can prefix a client with `-` to exclude it, e.g. 
`youtube:player_client=default,-ios`
+* `player_client`: Clients to extract video data from. The currently available 
clients are `web`, `web_safari`, `web_embedded`, `web_music`, `web_creator`, 
`mweb`, `ios`, `android`, `android_vr`, `tv`, `tv_downgraded`, and `tv_simply`. 
By default, `android_vr,web,web_safari` is used. If no JavaScript 
runtime/engine is available, then only `android_vr` is used. If logged-in 
cookies are passed to yt-dlp, then `tv_downgraded,web,web_safari` is used for 
free accounts and `tv_downgraded,web_creator,web` is used for premium accounts. 
The `web_music` client is added for `music.youtube.com` URLs when logged-in 
cookies are used. The `web_embedded` client is added for age-restricted videos 
but only successfully works around the age-restriction sometimes (e.g. if the 
video is embeddable), and may be added as a fallback if `android_vr` is unable 
to access a video. The `web_creator` client is added for age-restricted videos 
if account age-verification is required. Some clients, such as `web_crea
 tor` and `web_music`, require a `po_token` for their formats to be 
downloadable. Some clients, such as `web_creator`, will only work with 
authentication. Not all clients support authentication via cookies. You can use 
`default` for the default clients, or you can use `all` for all clients (not 
recommended). You can prefix a client with `-` to exclude it, e.g. 
`youtube:player_client=default,-web`
 * `player_skip`: Skip some network requests that are generally needed for 
robust extraction. One or more of `configs` (skip client configs), `webpage` 
(skip initial webpage), `js` (skip js player), `initial_data` (skip initial 
data/next ep request). While these options can help reduce the number of 
requests needed or avoid some rate-limiting, they could cause issues such as 
missing formats or metadata.  See 
[#860](https://github.com/yt-dlp/yt-dlp/pull/860) and 
[#12826](https://github.com/yt-dlp/yt-dlp/issues/12826) for more details
 * `webpage_skip`: Skip extraction of embedded webpage data. One or both of 
`player_response`, `initial_data`. These options are for testing purposes and 
don't skip any network requests
 * `player_params`: YouTube player parameters to use for player requests. Will 
overwrite any default ones set by yt-dlp.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/README.txt new/yt-dlp/README.txt
--- old/yt-dlp/README.txt       2026-01-29 18:00:51.000000000 +0100
+++ new/yt-dlp/README.txt       2026-02-01 00:55:32.000000000 +0100
@@ -2312,24 +2312,25 @@
     respectively
 -   player_client: Clients to extract video data from. The currently
     available clients are web, web_safari, web_embedded, web_music,
-    web_creator, mweb, ios, ios_downgraded, android, android_vr, tv,
-    tv_simply, tv_downgraded, and tv_embedded. By default,
-    android_vr,ios_downgraded,web,web_safari is used. If no JavaScript
-    runtime/engine is available, then android_vr,ios_downgraded is used.
-    If logged-in cookies are passed to yt-dlp, then
+    web_creator, mweb, ios, android, android_vr, tv, tv_downgraded, and
+    tv_simply. By default, android_vr,web,web_safari is used. If no
+    JavaScript runtime/engine is available, then only android_vr is
+    used. If logged-in cookies are passed to yt-dlp, then
     tv_downgraded,web,web_safari is used for free accounts and
     tv_downgraded,web_creator,web is used for premium accounts. The
     web_music client is added for music.youtube.com URLs when logged-in
     cookies are used. The web_embedded client is added for
-    age-restricted videos but only works if the video is embeddable. The
-    tv_embedded and web_creator clients are added for age-restricted
-    videos if account age-verification is required. Some clients, such
-    as web and web_music, require a po_token for their formats to be
-    downloadable. Some clients, such as web_creator, will only work with
+    age-restricted videos but only successfully works around the
+    age-restriction sometimes (e.g. if the video is embeddable), and may
+    be added as a fallback if android_vr is unable to access a video.
+    The web_creator client is added for age-restricted videos if account
+    age-verification is required. Some clients, such as web_creator and
+    web_music, require a po_token for their formats to be downloadable.
+    Some clients, such as web_creator, will only work with
     authentication. Not all clients support authentication via cookies.
     You can use default for the default clients, or you can use all for
     all clients (not recommended). You can prefix a client with - to
-    exclude it, e.g. youtube:player_client=default,-ios
+    exclude it, e.g. youtube:player_client=default,-web
 -   player_skip: Skip some network requests that are generally needed
     for robust extraction. One or more of configs (skip client configs),
     webpage (skip initial webpage), js (skip js player), initial_data
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/test/test_jsc/test_ejs_integration.py 
new/yt-dlp/test/test_jsc/test_ejs_integration.py
--- old/yt-dlp/test/test_jsc/test_ejs_integration.py    2026-01-29 
18:00:40.000000000 +0100
+++ new/yt-dlp/test/test_jsc/test_ejs_integration.py    2026-02-01 
00:55:18.000000000 +0100
@@ -36,7 +36,6 @@
     tv = 'tv-player-ias.vflset/tv-player-ias.js'
     tv_es6 = 'tv-player-es6.vflset/tv-player-es6.js'
     phone = 'player-plasma-ias-phone-en_US.vflset/base.js'
-    tablet = 'player-plasma-ias-tablet-en_US.vflset/base.js'
 
 
 @dataclasses.dataclass
Binary files old/yt-dlp/yt-dlp and new/yt-dlp/yt-dlp differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt-dlp.1 new/yt-dlp/yt-dlp.1
--- old/yt-dlp/yt-dlp.1 2026-01-29 18:00:52.000000000 +0100
+++ new/yt-dlp/yt-dlp.1 2026-02-01 00:55:32.000000000 +0100
@@ -2713,30 +2713,31 @@
 \f[V]player_client\f[R]: Clients to extract video data from.
 The currently available clients are \f[V]web\f[R], \f[V]web_safari\f[R],
 \f[V]web_embedded\f[R], \f[V]web_music\f[R], \f[V]web_creator\f[R],
-\f[V]mweb\f[R], \f[V]ios\f[R], \f[V]ios_downgraded\f[R],
-\f[V]android\f[R], \f[V]android_vr\f[R], \f[V]tv\f[R],
-\f[V]tv_simply\f[R], \f[V]tv_downgraded\f[R], and \f[V]tv_embedded\f[R].
-By default, \f[V]android_vr,ios_downgraded,web,web_safari\f[R] is used.
-If no JavaScript runtime/engine is available, then
-\f[V]android_vr,ios_downgraded\f[R] is used.
+\f[V]mweb\f[R], \f[V]ios\f[R], \f[V]android\f[R], \f[V]android_vr\f[R],
+\f[V]tv\f[R], \f[V]tv_downgraded\f[R], and \f[V]tv_simply\f[R].
+By default, \f[V]android_vr,web,web_safari\f[R] is used.
+If no JavaScript runtime/engine is available, then only
+\f[V]android_vr\f[R] is used.
 If logged-in cookies are passed to yt-dlp, then
 \f[V]tv_downgraded,web,web_safari\f[R] is used for free accounts and
 \f[V]tv_downgraded,web_creator,web\f[R] is used for premium accounts.
 The \f[V]web_music\f[R] client is added for \f[V]music.youtube.com\f[R]
 URLs when logged-in cookies are used.
 The \f[V]web_embedded\f[R] client is added for age-restricted videos but
-only works if the video is embeddable.
-The \f[V]tv_embedded\f[R] and \f[V]web_creator\f[R] clients are added
-for age-restricted videos if account age-verification is required.
-Some clients, such as \f[V]web\f[R] and \f[V]web_music\f[R], require a
-\f[V]po_token\f[R] for their formats to be downloadable.
+only successfully works around the age-restriction sometimes (e.g.
+if the video is embeddable), and may be added as a fallback if
+\f[V]android_vr\f[R] is unable to access a video.
+The \f[V]web_creator\f[R] client is added for age-restricted videos if
+account age-verification is required.
+Some clients, such as \f[V]web_creator\f[R] and \f[V]web_music\f[R],
+require a \f[V]po_token\f[R] for their formats to be downloadable.
 Some clients, such as \f[V]web_creator\f[R], will only work with
 authentication.
 Not all clients support authentication via cookies.
 You can use \f[V]default\f[R] for the default clients, or you can use
 \f[V]all\f[R] for all clients (not recommended).
 You can prefix a client with \f[V]-\f[R] to exclude it, e.g.
-\f[V]youtube:player_client=default,-ios\f[R]
+\f[V]youtube:player_client=default,-web\f[R]
 .IP \[bu] 2
 \f[V]player_skip\f[R]: Skip some network requests that are generally
 needed for robust extraction.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/downloader/__init__.py 
new/yt-dlp/yt_dlp/downloader/__init__.py
--- old/yt-dlp/yt_dlp/downloader/__init__.py    2026-01-29 18:00:40.000000000 
+0100
+++ new/yt-dlp/yt_dlp/downloader/__init__.py    2026-02-01 00:55:18.000000000 
+0100
@@ -36,6 +36,7 @@
 from .websocket import WebSocketFragmentFD
 from .youtube_live_chat import YoutubeLiveChatFD
 from .bunnycdn import BunnyCdnFD
+from .soop import SoopVodFD
 
 PROTOCOL_MAP = {
     'rtmp': RtmpFD,
@@ -56,6 +57,7 @@
     'youtube_live_chat': YoutubeLiveChatFD,
     'youtube_live_chat_replay': YoutubeLiveChatFD,
     'bunnycdn': BunnyCdnFD,
+    'soopvod': SoopVodFD,
 }
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/downloader/soop.py 
new/yt-dlp/yt_dlp/downloader/soop.py
--- old/yt-dlp/yt_dlp/downloader/soop.py        1970-01-01 01:00:00.000000000 
+0100
+++ new/yt-dlp/yt_dlp/downloader/soop.py        2026-02-01 00:55:18.000000000 
+0100
@@ -0,0 +1,61 @@
+import threading
+import time
+
+from .common import FileDownloader
+from . import HlsFD
+from ..extractor.afreecatv import _cloudfront_auth_request
+from ..networking.exceptions import network_exceptions
+
+
+class SoopVodFD(FileDownloader):
+    """
+    Downloads Soop subscription VODs with required cookie refresh requests
+    Note, this is not a part of public API, and will be removed without notice.
+    DO NOT USE
+    """
+
+    def real_download(self, filename, info_dict):
+        self.to_screen(f'[{self.FD_NAME}] Downloading Soop subscription VOD 
HLS')
+        fd = HlsFD(self.ydl, self.params)
+        refresh_params = info_dict['_cookie_refresh_params']
+        referer_url = info_dict['webpage_url']
+
+        stop_event = threading.Event()
+        refresh_thread = threading.Thread(
+            target=self._cookie_refresh_thread,
+            args=(stop_event, refresh_params, referer_url),
+        )
+        refresh_thread.start()
+
+        try:
+            return fd.real_download(filename, info_dict)
+        finally:
+            stop_event.set()
+
+    def _cookie_refresh_thread(self, stop_event, refresh_params, referer_url):
+        m3u8_url = refresh_params['m3u8_url']
+        strm_id = refresh_params['strm_id']
+        video_id = refresh_params['video_id']
+
+        def _get_cloudfront_cookie_expiration(m3u8_url):
+            cookies = self.ydl.cookiejar.get_cookies_for_url(m3u8_url)
+            return min((cookie.expires for cookie in cookies if 'CloudFront' 
in cookie.name and cookie.expires), default=0)
+
+        while not stop_event.wait(5):
+            current_time = time.time()
+            expiration_time = _get_cloudfront_cookie_expiration(m3u8_url)
+            last_refresh_check = refresh_params.get('_last_refresh', 0)
+
+            # Cookie TTL is 90 seconds, but let's give ourselves a 15-second 
cushion
+            should_refresh = (
+                (expiration_time and current_time >= expiration_time - 15)
+                or (not expiration_time and current_time - last_refresh_check 
>= 75)
+            )
+
+            if should_refresh:
+                try:
+                    self.ydl.urlopen(_cloudfront_auth_request(
+                        m3u8_url, strm_id, video_id, referer_url)).read()
+                    refresh_params['_last_refresh'] = current_time
+                except network_exceptions as e:
+                    self.to_screen(f'[{self.FD_NAME}] Cookie refresh attempt 
failed: {e}')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/afreecatv.py 
new/yt-dlp/yt_dlp/extractor/afreecatv.py
--- old/yt-dlp/yt_dlp/extractor/afreecatv.py    2026-01-29 18:00:40.000000000 
+0100
+++ new/yt-dlp/yt_dlp/extractor/afreecatv.py    2026-02-01 00:55:18.000000000 
+0100
@@ -1,5 +1,6 @@
 import datetime as dt
 import functools
+import time
 
 from .common import InfoExtractor
 from ..networking import Request
@@ -16,7 +17,23 @@
     urlencode_postdata,
     urljoin,
 )
-from ..utils.traversal import traverse_obj
+from ..utils.traversal import require, traverse_obj
+
+
+def _cloudfront_auth_request(m3u8_url, strm_id, video_id, referer_url):
+    return Request(
+        'https://live.sooplive.co.kr/api/private_auth.php',
+        method='POST',
+        headers={
+            'Referer': referer_url,
+            'Origin': 'https://vod.sooplive.co.kr',
+        },
+        data=urlencode_postdata({
+            'type': 'vod',
+            'strm_id': strm_id,
+            'title_no': video_id,
+            'url': m3u8_url,
+        }))
 
 
 class AfreecaTVBaseIE(InfoExtractor):
@@ -153,6 +170,13 @@
                 'nApiLevel': 10,
             }))['data']
 
+        initial_refresh_time = 0
+        strm_id = None
+        # For subscriber-only VODs, we need to call private_auth.php to get 
CloudFront cookies
+        needs_private_auth = traverse_obj(data, ('sub_upload_type', {str}))
+        if needs_private_auth:
+            strm_id = traverse_obj(data, ('bj_id', {str}, {require('stream 
ID')}))
+
         error_code = traverse_obj(data, ('code', {int}))
         if error_code == -6221:
             raise ExtractorError('The VOD does not exist', expected=True)
@@ -172,9 +196,23 @@
                 traverse_obj(data, ('files', lambda _, v: 
url_or_none(v['file']))), start=1):
             file_url = file_element['file']
             if determine_ext(file_url) == 'm3u8':
+                if needs_private_auth:
+                    self._request_webpage(
+                        _cloudfront_auth_request(file_url, strm_id, video_id, 
url),
+                        video_id, 'Requesting CloudFront cookies', 'Failed to 
get CloudFront cookies')
+                    initial_refresh_time = time.time()
                 formats = self._extract_m3u8_formats(
                     file_url, video_id, 'mp4', m3u8_id='hls',
                     note=f'Downloading part {file_num} m3u8 information')
+                if needs_private_auth:
+                    for fmt in formats:
+                        fmt['protocol'] = 'soopvod'
+                        fmt['_cookie_refresh_params'] = {
+                            'm3u8_url': file_url,
+                            'strm_id': strm_id,
+                            'video_id': video_id,
+                            '_last_refresh': initial_refresh_time,
+                        }
             else:
                 formats = [{
                     'url': file_url,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/lazy_extractors.py 
new/yt-dlp/yt_dlp/extractor/lazy_extractors.py
--- old/yt-dlp/yt_dlp/extractor/lazy_extractors.py      2026-01-29 
18:00:48.000000000 +0100
+++ new/yt-dlp/yt_dlp/extractor/lazy_extractors.py      2026-02-01 
00:55:28.000000000 +0100
@@ -5862,7 +5862,7 @@
 class KnownDRMIE(UnsupportedInfoExtractor):
     _module = 'yt_dlp.extractor.unsupported'
     IE_NAME = 'DRM'
-    _VALID_URL = 
'https?://(?:www\\.)?(?:play\\.hbomax\\.com|channel(?:4|5)\\.com|peacocktv\\.com|(?:[\\w.]+\\.)?disneyplus\\.com|open\\.spotify\\.com|tvnz\\.co\\.nz|oneplus\\.ch|artstation\\.com/learning/courses|philo\\.com|(?:[\\w.]+\\.)?mech-plus\\.com|aha\\.video|mubi\\.com|vootkids\\.com|nowtv\\.it/watch|tv\\.apple\\.com|primevideo\\.com|hulu\\.com|resource\\.inkryptvideos\\.com|joyn\\.de|amazon\\.(?:\\w{2}\\.)?\\w+/gp/video|music\\.amazon\\.(?:\\w{2}\\.)?\\w+|(?:watch|front)\\.njpwworld\\.com|qub\\.ca/vrai|(?:beta\\.)?crunchyroll\\.com|viki\\.com|deezer\\.com|b-ch\\.com|ctv\\.ca|noovo\\.ca|tsn\\.ca|paramountplus\\.com|(?:m\\.)?(?:sony)?crackle\\.com|cw(?:tv(?:pr)?|seed)\\.com|6play\\.fr|rtlplay\\.be|play\\.rtl\\.hr|rtlmost\\.hu|plus\\.rtl\\.de(?!/podcast/)|mediasetinfinity\\.es)'
+    _VALID_URL = 
'https?://(?:www\\.)?(?:play\\.hbomax\\.com|channel(?:4|5)\\.com|peacocktv\\.com|(?:[\\w.]+\\.)?disneyplus\\.com|open\\.spotify\\.com|tvnz\\.co\\.nz|oneplus\\.ch|artstation\\.com/learning/courses|philo\\.com|(?:[\\w.]+\\.)?mech-plus\\.com|aha\\.video|mubi\\.com|vootkids\\.com|nowtv\\.it/watch|tv\\.apple\\.com|primevideo\\.com|hulu\\.com|resource\\.inkryptvideos\\.com|joyn\\.de|amazon\\.(?:\\w{2}\\.)?\\w+/gp/video|music\\.amazon\\.(?:\\w{2}\\.)?\\w+|(?:watch|front)\\.njpwworld\\.com|qub\\.ca/vrai|(?:beta\\.)?crunchyroll\\.com|viki\\.com|deezer\\.com|b-ch\\.com|ctv\\.ca|noovo\\.ca|tsn\\.ca|paramountplus\\.com|(?:m\\.)?(?:sony)?crackle\\.com|cw(?:tv(?:pr)?|seed)\\.com|6play\\.fr|rtlplay\\.be|play\\.rtl\\.hr|rtlmost\\.hu|plus\\.rtl\\.de(?!/podcast/)|mediasetinfinity\\.es|tv5mondeplus\\.com)'
     IE_DESC = False
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/unsupported.py 
new/yt-dlp/yt_dlp/extractor/unsupported.py
--- old/yt-dlp/yt_dlp/extractor/unsupported.py  2026-01-29 18:00:40.000000000 
+0100
+++ new/yt-dlp/yt_dlp/extractor/unsupported.py  2026-02-01 00:55:18.000000000 
+0100
@@ -66,6 +66,7 @@
         r'rtlmost\.hu',
         r'plus\.rtl\.de(?!/podcast/)',
         r'mediasetinfinity\.es',
+        r'tv5mondeplus\.com',
     )
 
     _TESTS = [{
@@ -226,6 +227,10 @@
     }, {
         'url': 'https://www.mediasetinfinity.es/',
         'only_matching': True,
+    }, {
+        # https://github.com/yt-dlp/yt-dlp/issues/14743
+        'url': 'https://www.tv5mondeplus.com/',
+        'only_matching': True,
     }]
 
     def _real_extract(self, url):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/whyp.py 
new/yt-dlp/yt_dlp/extractor/whyp.py
--- old/yt-dlp/yt_dlp/extractor/whyp.py 2026-01-29 18:00:40.000000000 +0100
+++ new/yt-dlp/yt_dlp/extractor/whyp.py 2026-02-01 00:55:18.000000000 +0100
@@ -2,6 +2,7 @@
 from ..utils import (
     float_or_none,
     int_or_none,
+    parse_iso8601,
     str_or_none,
     traverse_obj,
     url_or_none,
@@ -16,9 +17,12 @@
         'info_dict': {
             'id': '18337',
             'title': 'Example Track',
+            'display_id': 'example-track',
             'description': 'md5:e0b1bcf1d267dc1a0f15efff09c8f297',
             'ext': 'flac',
             'duration': 135.63,
+            'timestamp': 1643216583,
+            'upload_date': '20220126',
             'uploader': 'Brad',
             'uploader_id': '1',
             'thumbnail': 
'https://cdn.whyp.it/6ad0bbd9-577d-42bb-9b61-2a4f57f647eb.jpg',
@@ -44,10 +48,12 @@
                 'http_headers': {'Referer': 'https://whyp.it/'},
             } for prefix in ('audio', 'lossy', 'lossless') if 
url_or_none(data.get(f'{prefix}_url'))],
             **traverse_obj(data, {
-                'title': 'title',
+                'title': ('title', {str}),
+                'display_id': ('slug', {str}),
                 'description': 'description',
                 'duration': ('duration', {float_or_none}),
-                'uploader': ('user', 'username'),
+                'timestamp': ('created_at', {parse_iso8601}),
+                'uploader': ('user', 'username', {str}),
                 'uploader_id': ('user', 'id', {str_or_none}),
                 'thumbnail': ('artwork_url', {url_or_none}),
             }),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/youtube/_base.py 
new/yt-dlp/yt_dlp/extractor/youtube/_base.py
--- old/yt-dlp/yt_dlp/extractor/youtube/_base.py        2026-01-29 
18:00:40.000000000 +0100
+++ new/yt-dlp/yt_dlp/extractor/youtube/_base.py        2026-02-01 
00:55:18.000000000 +0100
@@ -271,34 +271,6 @@
         'PLAYER_PO_TOKEN_POLICY': PlayerPoTokenPolicy(required=False, 
recommended=True),
         'REQUIRE_JS_PLAYER': False,
     },
-    'ios_downgraded': {
-        'INNERTUBE_CONTEXT': {
-            'client': {
-                'clientName': 'IOS',
-                'clientVersion': '19.49.7',
-                'deviceMake': 'Apple',
-                'deviceModel': 'iPhone16,2',
-                'userAgent': 'com.google.ios.youtube/19.49.7 (iPhone16,2; U; 
CPU iOS 17_5_1 like Mac OS X;)',
-                'osName': 'iPhone',
-                'osVersion': '17.5.1.21F90',
-            },
-        },
-        'INNERTUBE_CONTEXT_CLIENT_NAME': 5,
-        'GVS_PO_TOKEN_POLICY': {
-            StreamingProtocol.HTTPS: GvsPoTokenPolicy(
-                required=True,
-                recommended=True,
-                not_required_with_player_token=True,
-            ),
-            StreamingProtocol.HLS: GvsPoTokenPolicy(
-                required=False,
-                recommended=True,
-                not_required_with_player_token=True,
-            ),
-        },
-        'PLAYER_PO_TOKEN_POLICY': PlayerPoTokenPolicy(required=False, 
recommended=True),
-        'REQUIRE_JS_PLAYER': False,
-    },
     # mweb has 'ultralow' formats
     # See: https://github.com/yt-dlp/yt-dlp/pull/557
     'mweb': {
@@ -379,20 +351,6 @@
         },
         'INNERTUBE_CONTEXT_CLIENT_NAME': 75,
     },
-    # This client now requires sign-in for every video
-    # It was previously an age-gate workaround for videos that were 
`playable_in_embed`
-    # It may still be useful if signed into an EU account that is not 
age-verified
-    'tv_embedded': {
-        'INNERTUBE_CONTEXT': {
-            'client': {
-                'clientName': 'TVHTML5_SIMPLY_EMBEDDED_PLAYER',
-                'clientVersion': '2.0',
-            },
-        },
-        'INNERTUBE_CONTEXT_CLIENT_NAME': 85,
-        'REQUIRE_AUTH': True,
-        'SUPPORTS_COOKIES': True,
-    },
 }
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/youtube/_video.py 
new/yt-dlp/yt_dlp/extractor/youtube/_video.py
--- old/yt-dlp/yt_dlp/extractor/youtube/_video.py       2026-01-29 
18:00:40.000000000 +0100
+++ new/yt-dlp/yt_dlp/extractor/youtube/_video.py       2026-02-01 
00:55:18.000000000 +0100
@@ -145,8 +145,8 @@
         r'\b(?P<id>vfl[a-zA-Z0-9_-]+)\b.*?\.js$',
     )
     _SUBTITLE_FORMATS = ('json3', 'srv1', 'srv2', 'srv3', 'ttml', 'srt', 'vtt')
-    _DEFAULT_CLIENTS = ('android_vr', 'ios_downgraded', 'web', 'web_safari')
-    _DEFAULT_JSLESS_CLIENTS = ('android_vr', 'ios_downgraded')
+    _DEFAULT_CLIENTS = ('android_vr', 'web', 'web_safari')
+    _DEFAULT_JSLESS_CLIENTS = ('android_vr',)
     _DEFAULT_AUTHED_CLIENTS = ('tv_downgraded', 'web', 'web_safari')
     # Premium does not require POT (except for subtitles)
     _DEFAULT_PREMIUM_CLIENTS = ('tv_downgraded', 'web_creator', 'web')
@@ -1443,7 +1443,6 @@
             'view_count': int,
         },
         'params': {
-            'extractor_args': {'youtube': {'player_client': ['tv_embedded']}},
             'format': '251-drc',
             'skip_download': True,
         },
@@ -3118,6 +3117,15 @@
                 else:
                     prs.append(pr)
 
+            if (
+                # Is this a "made for kids" video that can't be downloaded 
with android_vr?
+                client == 'android_vr' and self._is_unplayable(pr)
+                and webpage and 'made for kids' in webpage
+                # ...and is a JS runtime is available?
+                and any(p.is_available() for p in 
self._jsc_director.providers.values())
+            ):
+                append_client('web_embedded')
+
             # web_embedded can work around age-gate and age-verification for 
some embeddable videos
             if self._is_agegated(pr) and variant != 'web_embedded':
                 append_client(f'web_embedded.{base_client}')
@@ -3134,9 +3142,8 @@
                 self.to_screen(
                     f'{video_id}: This video is age-restricted and YouTube is 
requiring '
                     'account age-verification; some formats may be missing', 
only_once=True)
-                # tv_embedded can work around the age-verification requirement 
for embeddable videos
                 # web_creator may work around age-verification for all videos 
but requires PO token
-                append_client('tv_embedded', 'web_creator')
+                append_client('web_creator')
 
             status = traverse_obj(pr, ('playabilityStatus', 'status', {str}))
             if status not in ('OK', 'LIVE_STREAM_OFFLINE', 
'AGE_CHECK_REQUIRED', 'AGE_VERIFICATION_REQUIRED'):
@@ -3595,10 +3602,6 @@
                 if client_name == 'web_safari' and proto == 'hls' and 
live_status != 'is_live':
                     f['source_preference'] -= 1
 
-                # Safeguard against inevitable ios_downgraded client breakage
-                if client_name == 'ios_downgraded' and proto == 'hls' and 
live_status != 'is_live':
-                    f['__needs_testing'] = True
-
                 if missing_pot:
                     f['format_note'] = join_nonempty(f.get('format_note'), 
'MISSING POT', delim=' ')
                     f['source_preference'] -= 20
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/version.py new/yt-dlp/yt_dlp/version.py
--- old/yt-dlp/yt_dlp/version.py        2026-01-29 18:00:45.000000000 +0100
+++ new/yt-dlp/yt_dlp/version.py        2026-02-01 00:55:24.000000000 +0100
@@ -1,8 +1,8 @@
 # Autogenerated by devscripts/update-version.py
 
-__version__ = '2026.01.29'
+__version__ = '2026.01.31'
 
-RELEASE_GIT_HEAD = '8b275536d945c4b3d07b6c520677922c67a7c10f'
+RELEASE_GIT_HEAD = '9a9a6b6fe44a30458c1754ef064f354f04a84004'
 
 VARIANT = None
 
@@ -12,4 +12,4 @@
 
 ORIGIN = 'yt-dlp/yt-dlp'
 
-_pkg_version = '2026.01.29'
+_pkg_version = '2026.01.31'

Reply via email to