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-03-07 20:10:29
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/yt-dlp (Old)
 and      /work/SRC/openSUSE:Factory/.yt-dlp.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "yt-dlp"

Sat Mar  7 20:10:29 2026 rev:88 rq:1337443 version:2026.03.03

Changes:
--------
--- /work/SRC/openSUSE:Factory/yt-dlp/yt-dlp.changes    2026-02-23 
16:12:32.813334740 +0100
+++ /work/SRC/openSUSE:Factory/.yt-dlp.new.8177/yt-dlp.changes  2026-03-07 
20:15:21.981359849 +0100
@@ -1,0 +2,11 @@
+Wed Mar  4 10:03:21 UTC 2026 - Luigi Baldoni <[email protected]>
+
+- Update to version 2026.03.03
+  * Extractor changes:
+  * aenetworks: Fix extraction
+  * patreon: Fix extractors
+  * thechosen: Rework extractor
+  * yt: Skip webpage player response by default
+  * zapiks: Improve extraction
+
+-------------------------------------------------------------------

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

Other differences:
------------------
++++++ yt-dlp.spec ++++++
--- /var/tmp/diff_new_pack.uDtNQT/_old  2026-03-07 20:15:23.221411146 +0100
+++ /var/tmp/diff_new_pack.uDtNQT/_new  2026-03-07 20:15:23.225411312 +0100
@@ -27,7 +27,7 @@
 %endif
 
 Name:           yt-dlp
-Version:        2026.02.21
+Version:        2026.03.03
 %define ejsver  0.5.0
 Release:        0
 Summary:        Enhanced fork of youtube-dl, a video site downloader for 
offline watching

++++++ _scmsync.obsinfo ++++++
--- /var/tmp/diff_new_pack.uDtNQT/_old  2026-03-07 20:15:23.353416607 +0100
+++ /var/tmp/diff_new_pack.uDtNQT/_new  2026-03-07 20:15:23.361416937 +0100
@@ -1,5 +1,5 @@
-mtime: 1771719307
-commit: e4f319d809018843c24aecdea617a010b3d19b3b3e0a38a5f136450ae06cbe92
+mtime: 1772648117
+commit: ffb0e8fa4812abe13422a4a47afd3325fdddc1ac324dbbaa88d69cc060b69dc9
 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-03-04 19:16:21.000000000 +0100
@@ -0,0 +1 @@
+.osc

++++++ yt-dlp.tar.gz ++++++
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-02-21 21:22:55.000000000 +0100
+++ new/yt-dlp/Changelog.md     2026-03-03 17:37:33.000000000 +0100
@@ -4,6 +4,17 @@
 # To create a release, dispatch the 
https://github.com/yt-dlp/yt-dlp/actions/workflows/release.yml workflow on 
master
 -->
 
+### 2026.03.03
+
+#### Extractor changes
+- **aenetworks**: [Fix 
extraction](https://github.com/yt-dlp/yt-dlp/commit/338dbebdb8627a95bd8f72ed86fdc2d50c8e2d14)
 ([#16036](https://github.com/yt-dlp/yt-dlp/issues/16036)) by 
[bashonly](https://github.com/bashonly)
+- **patreon**: [Fix 
extractors](https://github.com/yt-dlp/yt-dlp/commit/bf4dfffe0164385c29a2dcb0367110babe4d4f27)
 ([#16112](https://github.com/yt-dlp/yt-dlp/issues/16112)) by 
[bashonly](https://github.com/bashonly)
+- **thechosen**: [Rework 
extractor](https://github.com/yt-dlp/yt-dlp/commit/e3118604aa99a5514342d6a002c9b4a3fe1235b4)
 ([#16021](https://github.com/yt-dlp/yt-dlp/issues/16021)) by 
[0xvd](https://github.com/0xvd)
+- **youtube**
+    - [Force player 
`9f4cc5e4`](https://github.com/yt-dlp/yt-dlp/commit/d3165e83ffc0088eef5e594927ea9ac99a6e2ce6)
 ([#16123](https://github.com/yt-dlp/yt-dlp/issues/16123)) by 
[bashonly](https://github.com/bashonly)
+    - [Skip webpage player response by 
default](https://github.com/yt-dlp/yt-dlp/commit/2ecc4c3bc300701d85e2cbaeb2b28a921a68f0f0)
 ([#16126](https://github.com/yt-dlp/yt-dlp/issues/16126)) by 
[bashonly](https://github.com/bashonly)
+- **zapiks**: [Improve 
extraction](https://github.com/yt-dlp/yt-dlp/commit/6f796a2bff332f72c3f250207cdf10db852f6016)
 ([#16030](https://github.com/yt-dlp/yt-dlp/issues/16030)) by 
[doe1080](https://github.com/doe1080)
+
 ### 2026.02.21
 
 #### Important 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-02-21 21:23:01.000000000 +0100
+++ new/yt-dlp/README.md        2026-03-03 17:37:39.000000000 +0100
@@ -1862,10 +1862,10 @@
 * `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`, `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
+* `webpage_skip`: Skip extraction of embedded webpage data. One or both of 
`player_response`, `initial_data`. Using these will not skip any network 
requests, and in some cases will result in additional network requests. 
Currently, the default is `player_response`; however, typically these are for 
testing purposes only
 * `player_params`: YouTube player parameters to use for player requests. Will 
overwrite any default ones set by yt-dlp.
 * `player_js_variant`: The player javascript variant to use for n/sig 
deciphering. The known variants are: `main`, `tcc`, `tce`, `es5`, `es6`, 
`es6_tcc`, `es6_tce`, `tv`, `tv_es6`, `phone`, `house`. The default is `tv`, 
and the others are for debugging purposes. You can use `actual` to go with what 
is prescribed by the site
-* `player_js_version`: The player javascript version to use for n/sig 
deciphering, in the format of `signature_timestamp@hash` (e.g. 
`20348@0004de42`). The default is to use what is prescribed by the site, and 
can be selected with `actual`
+* `player_js_version`: The player javascript version to use for n/sig 
deciphering, in the format of `signature_timestamp@hash` (e.g. 
`20348@0004de42`). Currently, the default is to force `20514@9f4cc5e4`. You can 
use `actual` to go with what is prescribed by the site
 * `comment_sort`: `top` or `new` (default) - choose comment sorting mode (on 
YouTube's side)
 * `max_comments`: Limit the amount of comments to gather. Comma-separated list 
of integers representing 
`max-comments,max-parents,max-replies,max-replies-per-thread,max-depth`. 
Default is `all,all,all,all,all`
     * A `max-depth` value of `1` will discard all replies, regardless of the 
`max-replies` or `max-replies-per-thread` values given
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-02-21 21:23:02.000000000 +0100
+++ new/yt-dlp/README.txt       2026-03-03 17:37:40.000000000 +0100
@@ -2339,8 +2339,10 @@
     they could cause issues such as missing formats or metadata. See
     #860 and #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
+    of player_response, initial_data. Using these will not skip any
+    network requests, and in some cases will result in additional
+    network requests. Currently, the default is player_response;
+    however, typically these are for testing purposes only
 -   player_params: YouTube player parameters to use for player requests.
     Will overwrite any default ones set by yt-dlp.
 -   player_js_variant: The player javascript variant to use for n/sig
@@ -2350,8 +2352,8 @@
     what is prescribed by the site
 -   player_js_version: The player javascript version to use for n/sig
     deciphering, in the format of signature_timestamp@hash (e.g.
-    20348@0004de42). The default is to use what is prescribed by the
-    site, and can be selected with actual
+    20348@0004de42). Currently, the default is to force 20514@9f4cc5e4.
+    You can use actual to go with what is prescribed by the site
 -   comment_sort: top or new (default) - choose comment sorting mode (on
     YouTube's side)
 -   max_comments: Limit the amount of comments to gather.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/supportedsites.md new/yt-dlp/supportedsites.md
--- old/yt-dlp/supportedsites.md        2026-02-21 21:23:01.000000000 +0100
+++ new/yt-dlp/supportedsites.md        2026-03-03 17:37:39.000000000 +0100
@@ -1473,7 +1473,7 @@
  - **theatercomplextown:ppv**: [*theatercomplextown*](## "netrc machine")
  - **theatercomplextown:vod**: [*theatercomplextown*](## "netrc machine")
  - **TheChosen**
- - **TheChosenGroup**
+ - **TheChosenGroup**: (**Currently broken**)
  - **TheGuardianPodcast**
  - **TheGuardianPodcastPlaylist**
  - **TheHighWire**
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-02-21 21:23:03.000000000 +0100
+++ new/yt-dlp/yt-dlp.1 2026-03-03 17:37:41.000000000 +0100
@@ -2752,8 +2752,10 @@
 .IP \[bu] 2
 \f[V]webpage_skip\f[R]: Skip extraction of embedded webpage data.
 One or both of \f[V]player_response\f[R], \f[V]initial_data\f[R].
-These options are for testing purposes and don\[aq]t skip any network
-requests
+Using these will not skip any network requests, and in some cases will
+result in additional network requests.
+Currently, the default is \f[V]player_response\f[R]; however, typically
+these are for testing purposes only
 .IP \[bu] 2
 \f[V]player_params\f[R]: YouTube player parameters to use for player
 requests.
@@ -2771,8 +2773,8 @@
 n/sig deciphering, in the format of
 \f[V]signature_timestamp\[at]hash\f[R] (e.g.
 \f[V]20348\[at]0004de42\f[R]).
-The default is to use what is prescribed by the site, and can be
-selected with \f[V]actual\f[R]
+Currently, the default is to force \f[V]20514\[at]9f4cc5e4\f[R].
+You can use \f[V]actual\f[R] to go with what is prescribed by the site
 .IP \[bu] 2
 \f[V]comment_sort\f[R]: \f[V]top\f[R] or \f[V]new\f[R] (default) -
 choose comment sorting mode (on YouTube\[aq]s side)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/_extractors.py 
new/yt-dlp/yt_dlp/extractor/_extractors.py
--- old/yt-dlp/yt_dlp/extractor/_extractors.py  2026-02-21 21:22:46.000000000 
+0100
+++ new/yt-dlp/yt_dlp/extractor/_extractors.py  2026-03-03 17:37:22.000000000 
+0100
@@ -672,10 +672,6 @@
     FrontendMastersIE,
     FrontendMastersLessonIE,
 )
-from .frontro import (
-    TheChosenGroupIE,
-    TheChosenIE,
-)
 from .fujitv import FujiTVFODPlus7IE
 from .funk import FunkIE
 from .funker530 import Funker530IE
@@ -2063,6 +2059,10 @@
 from .testurl import TestURLIE
 from .tf1 import TF1IE
 from .tfo import TFOIE
+from .thechosen import (
+    TheChosenGroupIE,
+    TheChosenIE,
+)
 from .theguardian import (
     TheGuardianPodcastIE,
     TheGuardianPodcastPlaylistIE,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/aenetworks.py 
new/yt-dlp/yt_dlp/extractor/aenetworks.py
--- old/yt-dlp/yt_dlp/extractor/aenetworks.py   2026-02-21 21:22:46.000000000 
+0100
+++ new/yt-dlp/yt_dlp/extractor/aenetworks.py   2026-03-03 17:37:22.000000000 
+0100
@@ -91,8 +91,8 @@
         if filter_key == 'canonical':
             webpage = self._download_webpage(url, filter_value)
             graphql_video_id = self._search_regex(
-                r'<meta\b[^>]+\bcontent="[^"]*\btpid/(\d+)"', webpage,
-                'id') or self._html_search_meta('videoId', webpage, 'GraphQL 
video ID', fatal=True)
+                r'<meta\b[^>]+\bcontent="[^"]*\btpid/(\d+)"', webpage, 'id',
+                default=None) or self._html_search_meta('videoId', webpage, 
'GraphQL video ID', fatal=True)
         else:
             graphql_video_id = filter_value
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/frontro.py 
new/yt-dlp/yt_dlp/extractor/frontro.py
--- old/yt-dlp/yt_dlp/extractor/frontro.py      2026-02-21 21:22:47.000000000 
+0100
+++ new/yt-dlp/yt_dlp/extractor/frontro.py      2026-03-03 17:37:22.000000000 
+0100
@@ -99,66 +99,3 @@
                 'modified_timestamp': ('updatedAt', {parse_iso8601}),
             }),
         }
-
-
-class TheChosenIE(FrontroVideoBaseIE):
-    _CHANNEL_ID = '12884901895'
-
-    _VALID_URL = 
r'https?://(?:www\.)?watch\.thechosen\.tv/watch/(?P<id>[0-9]+)'
-    _TESTS = [{
-        'url': 'https://watch.thechosen.tv/watch/184683594325',
-        'md5': '3f878b689588c71b38ec9943c54ff5b0',
-        'info_dict': {
-            'id': '184683594325',
-            'ext': 'mp4',
-            'title': 'Season 3 Episode 2: Two by Two',
-            'description': 'md5:174c373756ecc8df46b403f4fcfbaf8c',
-            'comment_count': int,
-            'view_count': int,
-            'like_count': int,
-            'duration': 4212,
-            'thumbnail': 
r're:https://fastly\.frontrowcdn\.com/channels/12884901895/VIDEO_THUMBNAIL/184683594325/',
-            'timestamp': 1698954546,
-            'upload_date': '20231102',
-            'modified_timestamp': int,
-            'modified_date': str,
-        },
-    }, {
-        'url': 'https://watch.thechosen.tv/watch/184683596189',
-        'md5': 'd581562f9d29ce82f5b7770415334151',
-        'info_dict': {
-            'id': '184683596189',
-            'ext': 'mp4',
-            'title': 'Season 4 Episode 8: Humble',
-            'description': 'md5:20a57bead43da1cf77cd5b0fe29bbc76',
-            'comment_count': int,
-            'view_count': int,
-            'like_count': int,
-            'duration': 5092,
-            'thumbnail': 
r're:https://fastly\.frontrowcdn\.com/channels/12884901895/VIDEO_THUMBNAIL/184683596189/',
-            'timestamp': 1715019474,
-            'upload_date': '20240506',
-            'modified_timestamp': int,
-            'modified_date': str,
-        },
-    }]
-
-
-class TheChosenGroupIE(FrontroGroupBaseIE):
-    _CHANNEL_ID = '12884901895'
-    _VIDEO_EXTRACTOR = TheChosenIE
-    _VIDEO_URL_TMPL = 'https://watch.thechosen.tv/watch/%s'
-
-    _VALID_URL = 
r'https?://(?:www\.)?watch\.thechosen\.tv/group/(?P<id>[0-9]+)'
-    _TESTS = [{
-        'url': 'https://watch.thechosen.tv/group/309237658592',
-        'info_dict': {
-            'id': '309237658592',
-            'title': 'Season 3',
-            'timestamp': 1746203969,
-            'upload_date': '20250502',
-            'modified_timestamp': int,
-            'modified_date': str,
-        },
-        'playlist_count': 8,
-    }]
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-02-21 
21:22:58.000000000 +0100
+++ new/yt-dlp/yt_dlp/extractor/lazy_extractors.py      2026-03-03 
17:37:35.000000000 +0100
@@ -12948,21 +12948,17 @@
 
 
 class TheChosenGroupIE(FrontroGroupBaseIE):
-    _module = 'yt_dlp.extractor.frontro'
+    _module = 'yt_dlp.extractor.thechosen'
     IE_NAME = 'TheChosenGroup'
     _VALID_URL = 
'https?://(?:www\\.)?watch\\.thechosen\\.tv/group/(?P<id>[0-9]+)'
+    _WORKING = False
     _RETURN_TYPE = 'playlist'
 
 
-class FrontroVideoBaseIE(FrontoBaseIE):
-    _module = 'yt_dlp.extractor.frontro'
-    IE_NAME = 'FrontroVideoBase'
-
-
-class TheChosenIE(FrontroVideoBaseIE):
-    _module = 'yt_dlp.extractor.frontro'
+class TheChosenIE(LazyLoadExtractor):
+    _module = 'yt_dlp.extractor.thechosen'
     IE_NAME = 'TheChosen'
-    _VALID_URL = 
'https?://(?:www\\.)?watch\\.thechosen\\.tv/watch/(?P<id>[0-9]+)'
+    _VALID_URL = 
'https?://(?:www\\.)?watch\\.thechosen\\.tv/(?:video|watch)/(?P<id>[0-9]+)'
     _RETURN_TYPE = 'video'
 
 
@@ -15701,7 +15697,7 @@
 class ZapiksIE(LazyLoadExtractor):
     _module = 'yt_dlp.extractor.zapiks'
     IE_NAME = 'Zapiks'
-    _VALID_URL = 
'https?://(?:www\\.)?zapiks\\.(?:fr|com)/(?:(?:[a-z]{2}/)?(?P<display_id>.+?)\\.html|index\\.php\\?.*\\bmedia_id=(?P<id>\\d+))'
+    _VALID_URL = 
['https?://(?:www\\.)?zapiks\\.(?:com|fr)/(?P<id>[\\w-]+)\\.html', 
'https?://(?:www\\.)?zapiks\\.fr/index\\.php\\?(?:[^#]+&)?media_id=(?P<id>\\d+)']
     _RETURN_TYPE = 'video'
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/patreon.py 
new/yt-dlp/yt_dlp/extractor/patreon.py
--- old/yt-dlp/yt_dlp/extractor/patreon.py      2026-02-21 21:22:47.000000000 
+0100
+++ new/yt-dlp/yt_dlp/extractor/patreon.py      2026-03-03 17:37:22.000000000 
+0100
@@ -25,6 +25,7 @@
     find_elements,
     require,
     traverse_obj,
+    trim_str,
     value,
 )
 
@@ -32,16 +33,15 @@
 class PatreonBaseIE(InfoExtractor):
     @functools.cached_property
     def patreon_user_agent(self):
-        # Patreon mobile UA is needed to avoid triggering Cloudflare anti-bot 
protection.
-        # Newer UA yields higher res m3u8 formats for locked posts, but gives 
401 if not logged-in
+        # Patreon mobile UA yields higher res m3u8 for locked posts, but gives 
401 if not logged-in
         if self._get_cookies('https://www.patreon.com/').get('session_id'):
-            return 'Patreon/72.2.28 (Android; Android 14; Scale/2.10)'
-        return 'Patreon/7.6.28 (Android; Android 11; Scale/2.10)'
+            return 'Patreon/126.9.0.15 (Android; Android 14; Scale/2.10)'
+        return None
 
     def _call_api(self, ep, item_id, query=None, headers=None, fatal=True, 
note=None):
         if headers is None:
             headers = {}
-        if 'User-Agent' not in headers:
+        if 'User-Agent' not in headers and self.patreon_user_agent:
             headers['User-Agent'] = self.patreon_user_agent
         if query:
             query.update({'json-api-version': 1.0})
@@ -50,7 +50,9 @@
             return self._download_json(
                 f'https://www.patreon.com/api/{ep}',
                 item_id, note=note if note else 'Downloading API JSON',
-                query=query, fatal=fatal, headers=headers)
+                query=query, fatal=fatal, headers=headers,
+                # If not using Patreon mobile UA, we need impersonation due to 
Cloudflare
+                impersonate=not self.patreon_user_agent)
         except ExtractorError as e:
             if not isinstance(e.cause, HTTPError) or 
mimetype2ext(e.cause.response.headers.get('Content-Type')) != 'json':
                 raise
@@ -623,14 +625,13 @@
         'info_dict': {
             'id': '9631148',
             'title': 'Anything Else?',
-            'description': 'md5:2ee1db4aed2f9460c2b295825a24aa08',
+            'description': 'md5:b2f20eec4cb5520d9a4be4971f28add5',
             'uploader': 'dan ',
             'uploader_id': '13852412',
             'uploader_url': 'https://www.patreon.com/anythingelse',
             'channel': 'Anything Else?',
             'channel_id': '9631148',
             'channel_url': 'https://www.patreon.com/anythingelse',
-            'channel_follower_count': int,
             'age_limit': 0,
             'thumbnail': r're:https?://.+/.+',
         },
@@ -675,16 +676,15 @@
                 break
 
     def _real_extract(self, url):
-
         campaign_id, vanity = self._match_valid_url(url).group('campaign_id', 
'vanity')
         if campaign_id is None:
-            webpage = self._download_webpage(url, vanity, 
headers={'User-Agent': self.patreon_user_agent})
-            campaign_id = traverse_obj(self._search_nextjs_data(webpage, 
vanity, default=None), (
-                'props', 'pageProps', 'bootstrapEnvelope', 'pageBootstrap', 
'campaign', 'data', 'id', {str}))
-            if not campaign_id:
-                campaign_id = 
traverse_obj(self._search_nextjs_v13_data(webpage, vanity), (
-                    ((..., 'value', 'campaign', 'data'), lambda _, v: 
v['type'] == 'campaign'),
-                    'id', {str}, any, {require('campaign ID')}))
+            results = self._call_api('search', vanity, query={
+                'q': vanity,
+                'page[size]': '5',
+            })['data']
+            campaign_id = traverse_obj(results, (
+                lambda _, v: v['type'] == 'campaign-document' and 
v['attributes']['url'].lower().endswith(f'/{vanity.lower()}'),
+                'id', {trim_str(start='campaign_')}, filter, any, 
{require('campaign ID')}))
 
         params = {
             'json-api-use-default-includes': 'false',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/thechosen.py 
new/yt-dlp/yt_dlp/extractor/thechosen.py
--- old/yt-dlp/yt_dlp/extractor/thechosen.py    1970-01-01 01:00:00.000000000 
+0100
+++ new/yt-dlp/yt_dlp/extractor/thechosen.py    2026-03-03 17:37:22.000000000 
+0100
@@ -0,0 +1,118 @@
+from .common import InfoExtractor
+from .frontro import FrontroGroupBaseIE
+from ..utils import (
+    determine_ext,
+    int_or_none,
+    url_or_none,
+)
+from ..utils.traversal import traverse_obj
+
+
+class TheChosenIE(InfoExtractor):
+    _VALID_URL = 
r'https?://(?:www\.)?watch\.thechosen\.tv/(?:video|watch)/(?P<id>[0-9]+)'
+    _TESTS = [{
+        'url': 'https://watch.thechosen.tv/video/184683594325',
+        'md5': '3f878b689588c71b38ec9943c54ff5b0',
+        'info_dict': {
+            'id': '184683594325',
+            'ext': 'mp4',
+            'title': 'Season 3 Episode 2: Two by Two',
+            'description': 'md5:174c373756ecc8df46b403f4fcfbaf8c',
+            'duration': 4212,
+            'thumbnail': 
'https://cas.global.ssl.fastly.net/hls-10-4/184683594325/thumbnail.png',
+        },
+        'params': {'skip_download': 'm3u8'},
+    }, {
+        'url': 'https://watch.thechosen.tv/video/184683596189',
+        'md5': 'd581562f9d29ce82f5b7770415334151',
+        'info_dict': {
+            'id': '184683596189',
+            'ext': 'mp4',
+            'title': 'Season 4 Episode 8: Humble',
+            'description': 'md5:20a57bead43da1cf77cd5b0fe29bbc76',
+            'duration': 5092,
+            'thumbnail': 
'https://cdn.thechosen.media/videos/cmkvu7nn500nhfm0wpgmm6180/thumbnail.jpg',
+        },
+        'params': {'skip_download': 'm3u8'},
+    }, {
+        'url': 'https://watch.thechosen.tv/video/184683621748',
+        'info_dict': {
+            'id': '184683621748',
+            'ext': 'mp4',
+            'title': 'Season 5 Episode 2: House of Cards',
+            'description': 'md5:55b389cbb4b7a01d8c2d837102905617',
+            'duration': 3086,
+            'thumbnail': 
'https://cdn.thechosen.media/videos/cmkolt4el000afd5zd6x0aeph/thumbnail.jpg',
+        },
+        'params': {'skip_download': 'm3u8'},
+    }, {
+        'url': 'https://watch.thechosen.tv/video/184683621750',
+        'info_dict': {
+            'id': '184683621750',
+            'ext': 'mp4',
+            'title': 'Season 5 Episode 3:  Woes',
+            'description': 'md5:90ca3cc41316a965fd1cd3d5b3458784',
+            'duration': 3519,
+            'thumbnail': 
'https://cdn.thechosen.media/videos/cmkoltsl8000dfd5z3luid3mg/thumbnail.jpg',
+        },
+        'params': {'skip_download': 'm3u8'},
+    }]
+
+    def _real_extract(self, url):
+        video_id = self._match_id(url)
+        metadata = 
self._download_json(f'https://api.watch.thechosen.tv/v1/videos/{video_id}', 
video_id)
+
+        formats, subtitles = [], {}
+        for fmt_url in traverse_obj(metadata, ('details', 'video', ..., 'url', 
{url_or_none})):
+            ext = determine_ext(fmt_url)
+            if ext == 'm3u8':
+                fmts, subs = self._extract_m3u8_formats_and_subtitles(fmt_url, 
video_id, 'mp4', fatal=False)
+            elif ext == 'mpd':
+                fmts, subs = self._extract_mpd_formats_and_subtitles(fmt_url, 
video_id, fatal=False)
+            else:
+                self.report_warning(f'Skipping unsupported format extension 
"{ext}"', video_id=video_id)
+                continue
+            formats.extend(fmts)
+            self._merge_subtitles(subs, target=subtitles)
+
+        thumbnails = []
+        for thumb_id, thumb_url in traverse_obj(metadata, (
+            ('thumbs', 'thumbnails'), {dict.items}, lambda _, v: 
url_or_none(v[1]),
+        )):
+            thumbnails.append({
+                'id': thumb_id,
+                'url': thumb_url,
+            })
+
+        return {
+            'id': video_id,
+            **traverse_obj(metadata, ({
+                'title': ('title', {str}),
+                'description': ('description', {str}),
+                'duration': ('duration', {int_or_none}),
+            })),
+            'thumbnails': thumbnails,
+            'formats': formats,
+            'subtitles': subtitles,
+        }
+
+
+class TheChosenGroupIE(FrontroGroupBaseIE):
+    _WORKING = False
+    _CHANNEL_ID = '12884901895'
+    _VIDEO_EXTRACTOR = TheChosenIE
+    _VIDEO_URL_TMPL = 'https://watch.thechosen.tv/watch/%s'
+
+    _VALID_URL = 
r'https?://(?:www\.)?watch\.thechosen\.tv/group/(?P<id>[0-9]+)'
+    _TESTS = [{
+        'url': 'https://watch.thechosen.tv/group/309237658592',
+        'info_dict': {
+            'id': '309237658592',
+            'title': 'Season 3',
+            'timestamp': 1746203969,
+            'upload_date': '20250502',
+            'modified_timestamp': int,
+            'modified_date': str,
+        },
+        'playlist_count': 8,
+    }]
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-02-21 
21:22:47.000000000 +0100
+++ new/yt-dlp/yt_dlp/extractor/youtube/_video.py       2026-03-03 
17:37:22.000000000 +0100
@@ -1873,7 +1873,12 @@
         'params': {'skip_download': True},
     }]
 
-    _DEFAULT_PLAYER_JS_VERSION = 'actual'
+    @property
+    def _skipped_webpage_data(self):
+        # XXX: player_response as a default is a TEMPORARY workaround for 
pinning _DEFAULT_PLAYER_JS_VERSION
+        return self._configuration_arg('webpage_skip', 
default=['player_response'])
+
+    _DEFAULT_PLAYER_JS_VERSION = '20514@9f4cc5e4'
     _DEFAULT_PLAYER_JS_VARIANT = 'tv'
     _PLAYER_JS_VARIANT_MAP = {
         'main': 'player_ias.vflset/en_US/base.js',
@@ -3044,7 +3049,7 @@
                 tried_iframe_fallback = True
 
             pr = None
-            if client == webpage_client and 'player_response' not in 
self._configuration_arg('webpage_skip'):
+            if client == webpage_client and 'player_response' not in 
self._skipped_webpage_data:
                 pr = initial_pr
 
             visitor_data = visitor_data or 
self._extract_visitor_data(webpage_ytcfg, initial_pr, player_ytcfg)
@@ -3827,7 +3832,7 @@
 
     def _download_initial_data(self, video_id, webpage, webpage_client, 
webpage_ytcfg):
         initial_data = None
-        if webpage and 'initial_data' not in 
self._configuration_arg('webpage_skip'):
+        if webpage and 'initial_data' not in self._skipped_webpage_data:
             initial_data = self.extract_yt_initial_data(video_id, webpage, 
fatal=False)
             if not traverse_obj(initial_data, 'contents'):
                 self.report_warning('Incomplete data received in embedded 
initial data; re-fetching using API.')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yt-dlp/yt_dlp/extractor/zapiks.py 
new/yt-dlp/yt_dlp/extractor/zapiks.py
--- old/yt-dlp/yt_dlp/extractor/zapiks.py       2026-02-21 21:22:47.000000000 
+0100
+++ new/yt-dlp/yt_dlp/extractor/zapiks.py       2026-03-03 17:37:22.000000000 
+0100
@@ -1,110 +1,205 @@
+import json
 import re
+import urllib.parse
 
 from .common import InfoExtractor
 from ..utils import (
+    clean_html,
+    extract_attributes,
     int_or_none,
     parse_duration,
-    parse_iso8601,
-    xpath_text,
-    xpath_with_ns,
+    parse_resolution,
+    str_or_none,
+    unified_timestamp,
+    url_or_none,
+)
+from ..utils.traversal import (
+    find_element,
+    find_elements,
+    traverse_obj,
 )
 
 
 class ZapiksIE(InfoExtractor):
-    _VALID_URL = 
r'https?://(?:www\.)?zapiks\.(?:fr|com)/(?:(?:[a-z]{2}/)?(?P<display_id>.+?)\.html|index\.php\?.*\bmedia_id=(?P<id>\d+))'
-    _EMBED_REGEX = 
[r'<iframe[^>]+src="(?P<url>https?://(?:www\.)?zapiks\.fr/index\.php\?.+?)"']
+    _VALID_URL = [
+        r'https?://(?:www\.)?zapiks\.(?:com|fr)/(?P<id>[\w-]+)\.html',
+        
r'https?://(?:www\.)?zapiks\.fr/index\.php\?(?:[^#]+&)?media_id=(?P<id>\d+)',
+    ]
+    _EMBED_REGEX = 
[r'<iframe\b[^>]+\bsrc=["\'](?P<url>(?:https?:)?//(?:www\.)?zapiks\.fr/index\.php\?(?:[^#"\']+&(?:amp;)?)?media_id=\d+)']
     _TESTS = [{
-        'url': 'http://www.zapiks.fr/ep2s3-bon-appetit-eh-be-viva.html',
+        'url': 'https://www.zapiks.fr/ep2s3-bon-appetit-eh-be-viva.html',
         'md5': 'aeb3c473b2d564b2d46d664d28d5f050',
         'info_dict': {
             'id': '80798',
             'ext': 'mp4',
             'title': 'EP2S3 - Bon Appétit - Eh bé viva les pyrénées con!',
-            'description': 'md5:7054d6f6f620c6519be1fe710d4da847',
-            'thumbnail': r're:https?://zpks\.com/.+\.jpg',
+            'description': 'md5:db07a553c1550e2905bceafa923000fd',
+            'display_id': 'ep2s3-bon-appetit-eh-be-viva',
             'duration': 528,
+            'tags': 'count:5',
+            'thumbnail': r're:https?://zpks\.com/.+',
             'timestamp': 1359044972,
             'upload_date': '20130124',
+            'uploader': 'BonAppetit',
+            'uploader_id': 'bonappetit',
             'view_count': int,
         },
     }, {
-        'url': 'http://www.zapiks.com/ep3s5-bon-appetit-baqueira-m-1.html',
-        'only_matching': True,
+        'url': 'https://www.zapiks.com/ep3s5-bon-appetit-baqueira-m-1.html',
+        'md5': '196fe42901639d868956b1dcaa48de15',
+        'info_dict': {
+            'id': '118046',
+            'ext': 'mp4',
+            'title': 'EP3S5 - Bon Appétit - Baqueira Mi Corazon !',
+            'display_id': 'ep3s5-bon-appetit-baqueira-m-1',
+            'duration': 642,
+            'tags': 'count:8',
+            'thumbnail': r're:https?://zpks\.com/.+',
+            'timestamp': 1424370543,
+            'upload_date': '20150219',
+            'uploader': 'BonAppetit',
+            'uploader_id': 'bonappetit',
+            'view_count': int,
+        },
     }, {
-        'url': 'http://www.zapiks.com/nl/ep3s5-bon-appetit-baqueira-m-1.html',
-        'only_matching': True,
+        'url': 
'https://www.zapiks.fr/index.php?action=playerIframe&media_id=164049',
+        'md5': 'fb81a7c9b7b84c00ba111028aee593b8',
+        'info_dict': {
+            'id': '164049',
+            'ext': 'mp4',
+            'title': 'Courchevel Hiver 2025/2026',
+            'display_id': 'courchevel-hiver-2025-2026',
+            'duration': 38,
+            'tags': 'count:1',
+            'thumbnail': r're:https?://zpks\.com/.+',
+            'timestamp': 1769019147,
+            'upload_date': '20260121',
+            'uploader': 'jamrek',
+            'uploader_id': 'jamrek',
+            'view_count': int,
+        },
     }, {
-        'url': 
'http://www.zapiks.fr/index.php?action=playerIframe&amp;media_id=118046&amp;width=640&amp;height=360&amp;autoStart=false&amp;language=fr',
-        'only_matching': True,
+        # https://www.youtube.com/watch?v=UBAABvegu2M
+        'url': 'https://www.zapiks.com/live-fwt18-vallnord-arcalis-.html',
+        'info_dict': {
+            'id': 'UBAABvegu2M',
+            'ext': 'mp4',
+            'title': 'Replay Live - FWT18 Vallnord-Arcalís Andorra - Freeride 
World Tour 2018',
+            'age_limit': 0,
+            'availability': 'public',
+            'categories': ['Sports'],
+            'channel': 'FIS Freeride World Tour by Peak Performance',
+            'channel_follower_count': int,
+            'channel_id': 'UCraJ3GNFfw6LXFuCV6McByg',
+            'channel_url': 
'https://www.youtube.com/channel/UCraJ3GNFfw6LXFuCV6McByg',
+            'comment_count': int,
+            'description': 'md5:2d9fefef758d5ad0d5a987d46aff7572',
+            'duration': 11328,
+            'heatmap': 'count:100',
+            'like_count': int,
+            'live_status': 'was_live',
+            'media_type': 'livestream',
+            'playable_in_embed': True,
+            'release_date': '20180306',
+            'release_timestamp': 1520321809,
+            'tags': 'count:27',
+            'thumbnail': r're:https?://i\.ytimg\.com/.+',
+            'timestamp': 1520336958,
+            'upload_date': '20180306',
+            'uploader': 'FIS Freeride World Tour by Peak Performance',
+            'uploader_id': '@FISFreerideWorldTour',
+            'uploader_url': 'https://www.youtube.com/@FISFreerideWorldTour',
+            'view_count': int,
+        },
+        'add_ie': ['Youtube'],
+    }, {
+        # https://vimeo.com/235746460
+        'url': 'https://www.zapiks.fr/waking-dream-2017-full-movie.html',
+        'info_dict': {
+            'id': '235746460',
+            'ext': 'mp4',
+            'title': '"WAKING DREAM" (2017) Full Movie by Sam Favret & Julien 
Herry',
+            'duration': 1649,
+            'thumbnail': r're:https?://i\.vimeocdn\.com/video/.+',
+            'uploader': 'Favret Sam',
+            'uploader_id': 'samfavret',
+            'uploader_url': 'https://vimeo.com/samfavret',
+        },
+        'add_ie': ['Vimeo'],
+        'expected_warnings': ['Failed to parse XML: not well-formed'],
     }]
     _WEBPAGE_TESTS = [{
+        # https://www.zapiks.fr/ep3s5-bon-appetit-baqueira-m-1.html
+        # https://www.zapiks.fr/index.php?action=playerIframe&media_id=118046
         'url': 
'https://www.skipass.com/news/116090-bon-appetit-s5ep3-baqueira-mi-cor.html',
+        'md5': '196fe42901639d868956b1dcaa48de15',
         'info_dict': {
             'id': '118046',
             'ext': 'mp4',
             'title': 'EP3S5 - Bon Appétit - Baqueira Mi Corazon !',
-            'thumbnail': r're:https?://zpks\.com/.+\.jpg',
+            'description': 'md5:b45295c3897c4c01d7c04e8484c26aaf',
+            'display_id': 'ep3s5-bon-appetit-baqueira-m-1',
+            'duration': 642,
+            'tags': 'count:8',
+            'thumbnail': r're:https?://zpks\.com/.+',
+            'timestamp': 1424370543,
+            'upload_date': '20150219',
+            'uploader': 'BonAppetit',
+            'uploader_id': 'bonappetit',
+            'view_count': int,
         },
     }]
+    _UPLOADER_ID_RE = re.compile(r'/pro(?:fil)?/(?P<id>[^/?#]+)/?')
 
     def _real_extract(self, url):
-        mobj = self._match_valid_url(url)
-        video_id = mobj.group('id')
-        display_id = mobj.group('display_id') or video_id
-
+        display_id = self._match_id(url)
         webpage = self._download_webpage(url, display_id)
+        if embed_url := traverse_obj(webpage, (
+            {find_element(cls='embed-container')}, {find_element(tag='iframe', 
html=True)},
+            {extract_attributes}, 'src', {self._proto_relative_url}, 
{url_or_none},
+        )):
+            if not self.suitable(embed_url):
+                return self.url_result(embed_url)
+
+        video_responsive = traverse_obj(webpage, (
+            {find_element(cls='video-responsive', html=True)}, 
{extract_attributes}, {dict}))
+        data_media_url = traverse_obj(video_responsive, ('data-media-url', 
{url_or_none}))
+        if data_media_url and urllib.parse.urlparse(url).path == '/index.php':
+            return self.url_result(data_media_url, ZapiksIE)
 
-        if not video_id:
-            video_id = self._search_regex(
-                r'data-media-id="(\d+)"', webpage, 'video id')
-
-        playlist = self._download_xml(
-            
f'http://www.zapiks.fr/view/index.php?action=playlist&media_id={video_id}&lang=en',
-            display_id)
-
-        NS_MAP = {
-            'jwplayer': 'http://rss.jwpcdn.com/',
-        }
-
-        def ns(path):
-            return xpath_with_ns(path, NS_MAP)
-
-        item = playlist.find('./channel/item')
-
-        title = xpath_text(item, 'title', 'title') or 
self._og_search_title(webpage)
-        description = self._og_search_description(webpage, default=None)
-        thumbnail = xpath_text(
-            item, ns('./jwplayer:image'), 'thumbnail') or 
self._og_search_thumbnail(webpage, default=None)
-        duration = parse_duration(self._html_search_meta(
-            'duration', webpage, 'duration', default=None))
-        timestamp = parse_iso8601(self._html_search_meta(
-            'uploadDate', webpage, 'upload date', default=None), ' ')
-
-        view_count = int_or_none(self._search_regex(
-            r'UserPlays:(\d+)', webpage, 'view count', default=None))
-        comment_count = int_or_none(self._search_regex(
-            r'UserComments:(\d+)', webpage, 'comment count', default=None))
-
+        data_playlist = traverse_obj(video_responsive, ('data-playlist', 
{json.loads}, ..., any))
         formats = []
-        for source in item.findall(ns('./jwplayer:source')):
-            format_id = source.attrib['label']
-            f = {
-                'url': source.attrib['file'],
+        for source in traverse_obj(data_playlist, (
+            'sources', lambda _, v: url_or_none(v['file']),
+        )):
+            format_id = traverse_obj(source, ('label', {str_or_none}))
+            formats.append({
                 'format_id': format_id,
-            }
-            m = re.search(r'^(?P<height>\d+)[pP]', format_id)
-            if m:
-                f['height'] = int(m.group('height'))
-            formats.append(f)
+                'url': source['file'],
+                **parse_resolution(format_id),
+            })
 
         return {
-            'id': video_id,
-            'title': title,
-            'description': description,
-            'thumbnail': thumbnail,
-            'duration': duration,
-            'timestamp': timestamp,
-            'view_count': view_count,
-            'comment_count': comment_count,
+            'display_id': display_id,
+            'duration': parse_duration(self._html_search_meta('duration', 
webpage, default=None)),
             'formats': formats,
+            'timestamp': 
unified_timestamp(self._html_search_meta('uploadDate', webpage, default=None)),
+            **traverse_obj(webpage, {
+                'description': ({find_element(cls='description-text')}, 
{clean_html}, filter),
+                'tags': (
+                    {find_elements(cls='bs-label', html=True)},
+                    ..., {extract_attributes}, 'title', {clean_html}, filter),
+                'view_count': (
+                    {find_element(cls='video-content-view-counter')}, 
{clean_html},
+                    {lambda x: re.sub(r'(?:vues|views|\s+)', '', x)}, 
{int_or_none}),
+            }),
+            **traverse_obj(webpage, 
({find_element(cls='video-content-user-link', html=True)}, {
+                'uploader': ({clean_html}, filter),
+                'uploader_id': ({extract_attributes}, 'href', 
{self._UPLOADER_ID_RE.fullmatch}, 'id'),
+            })),
+            **traverse_obj(data_playlist, {
+                'id': ('mediaid', {str_or_none}),
+                'title': ('title', {clean_html}, filter),
+                'thumbnail': ('image', {url_or_none}),
+            }),
         }
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-02-21 21:22:55.000000000 +0100
+++ new/yt-dlp/yt_dlp/version.py        2026-03-03 17:37:32.000000000 +0100
@@ -1,8 +1,8 @@
 # Autogenerated by devscripts/update-version.py
 
-__version__ = '2026.02.21'
+__version__ = '2026.03.03'
 
-RELEASE_GIT_HEAD = '646bb31f39614e6c2f7ba687c53e7496394cbadb'
+RELEASE_GIT_HEAD = '2ecc4c3bc300701d85e2cbaeb2b28a921a68f0f0'
 
 VARIANT = None
 
@@ -12,4 +12,4 @@
 
 ORIGIN = 'yt-dlp/yt-dlp'
 
-_pkg_version = '2026.02.21'
+_pkg_version = '2026.03.03'

Reply via email to