yt-dlp 2026.1.25.233128.dev0__py3-none-any.whl → 2026.1.27.233257.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. yt_dlp/extractor/_extractors.py +9 -2
  2. yt_dlp/extractor/boosty.py +45 -16
  3. yt_dlp/extractor/dailymotion.py +45 -5
  4. yt_dlp/extractor/err.py +68 -0
  5. yt_dlp/extractor/facebook.py +57 -1
  6. yt_dlp/extractor/francetv.py +21 -5
  7. yt_dlp/extractor/frontro.py +4 -4
  8. yt_dlp/extractor/lazy_extractors.py +39 -7
  9. yt_dlp/extractor/lbry.py +1 -0
  10. yt_dlp/extractor/neteasemusic.py +32 -7
  11. yt_dlp/extractor/patreon.py +118 -33
  12. yt_dlp/extractor/pbs.py +18 -0
  13. yt_dlp/extractor/rumble.py +1 -1
  14. yt_dlp/extractor/volejtv.py +149 -22
  15. yt_dlp/extractor/wat.py +1 -1
  16. yt_dlp/version.py +3 -3
  17. {yt_dlp-2026.1.25.233128.dev0.dist-info → yt_dlp-2026.1.27.233257.dev0.dist-info}/METADATA +1 -1
  18. {yt_dlp-2026.1.25.233128.dev0.dist-info → yt_dlp-2026.1.27.233257.dev0.dist-info}/RECORD +26 -26
  19. {yt_dlp-2026.1.25.233128.dev0.data → yt_dlp-2026.1.27.233257.dev0.data}/data/share/bash-completion/completions/yt-dlp +0 -0
  20. {yt_dlp-2026.1.25.233128.dev0.data → yt_dlp-2026.1.27.233257.dev0.data}/data/share/doc/yt_dlp/README.txt +0 -0
  21. {yt_dlp-2026.1.25.233128.dev0.data → yt_dlp-2026.1.27.233257.dev0.data}/data/share/fish/vendor_completions.d/yt-dlp.fish +0 -0
  22. {yt_dlp-2026.1.25.233128.dev0.data → yt_dlp-2026.1.27.233257.dev0.data}/data/share/man/man1/yt-dlp.1 +0 -0
  23. {yt_dlp-2026.1.25.233128.dev0.data → yt_dlp-2026.1.27.233257.dev0.data}/data/share/zsh/site-functions/_yt-dlp +0 -0
  24. {yt_dlp-2026.1.25.233128.dev0.dist-info → yt_dlp-2026.1.27.233257.dev0.dist-info}/WHEEL +0 -0
  25. {yt_dlp-2026.1.25.233128.dev0.dist-info → yt_dlp-2026.1.27.233257.dev0.dist-info}/entry_points.txt +0 -0
  26. {yt_dlp-2026.1.25.233128.dev0.dist-info → yt_dlp-2026.1.27.233257.dev0.dist-info}/licenses/LICENSE +0 -0
@@ -564,7 +564,10 @@ from .eroprofile import (
564
564
  EroProfileAlbumIE,
565
565
  EroProfileIE,
566
566
  )
567
- from .err import ERRJupiterIE
567
+ from .err import (
568
+ ERRArhiivIE,
569
+ ERRJupiterIE,
570
+ )
568
571
  from .ertgr import (
569
572
  ERTFlixCodenameIE,
570
573
  ERTFlixIE,
@@ -2360,7 +2363,11 @@ from .voicy import (
2360
2363
  VoicyChannelIE,
2361
2364
  VoicyIE,
2362
2365
  )
2363
- from .volejtv import VolejTVIE
2366
+ from .volejtv import (
2367
+ VolejTVCategoryPlaylistIE,
2368
+ VolejTVClubPlaylistIE,
2369
+ VolejTVIE,
2370
+ )
2364
2371
  from .voxmedia import (
2365
2372
  VoxMediaIE,
2366
2373
  VoxMediaVolumeIE,
@@ -21,21 +21,44 @@ class BoostyIE(InfoExtractor):
21
21
  'url': 'https://boosty.to/kuplinov/posts/e55d050c-e3bb-4873-a7db-ac7a49b40c38',
22
22
  'info_dict': {
23
23
  'id': 'd7473824-352e-48e2-ae53-d4aa39459968',
24
- 'title': 'phasma_3',
24
+ 'title': 'Бан? А! Бан! (Phasmophobia)',
25
+ 'alt_title': 'Бан? А! Бан! (Phasmophobia)',
25
26
  'channel': 'Kuplinov',
26
27
  'channel_id': '7958701',
27
28
  'timestamp': 1655031975,
28
29
  'upload_date': '20220612',
29
30
  'release_timestamp': 1655049000,
30
31
  'release_date': '20220612',
31
- 'modified_timestamp': 1668680993,
32
- 'modified_date': '20221117',
32
+ 'modified_timestamp': 1743328648,
33
+ 'modified_date': '20250330',
33
34
  'tags': ['куплинов', 'phasmophobia'],
34
35
  'like_count': int,
35
36
  'ext': 'mp4',
36
37
  'duration': 105,
37
38
  'view_count': int,
38
- 'thumbnail': r're:^https://i\.mycdn\.me/videoPreview\?',
39
+ 'thumbnail': r're:^https://iv\.okcdn\.ru/videoPreview\?',
40
+ },
41
+ }, {
42
+ # single ok_video with truncated title
43
+ 'url': 'https://boosty.to/kuplinov/posts/cc09b7f9-121e-40b8-9392-4a075ef2ce53',
44
+ 'info_dict': {
45
+ 'id': 'fb5ea762-6303-4557-9a17-157947326810',
46
+ 'title': 'Какая там активность была? Не слышу! Повтори еще пару раз! (Phas',
47
+ 'alt_title': 'Какая там активность была? Не слышу! Повтори еще пару раз! (Phasmophobia)',
48
+ 'channel': 'Kuplinov',
49
+ 'channel_id': '7958701',
50
+ 'timestamp': 1655031930,
51
+ 'upload_date': '20220612',
52
+ 'release_timestamp': 1655048400,
53
+ 'release_date': '20220612',
54
+ 'modified_timestamp': 1743328616,
55
+ 'modified_date': '20250330',
56
+ 'tags': ['куплинов', 'phasmophobia'],
57
+ 'like_count': int,
58
+ 'ext': 'mp4',
59
+ 'duration': 39,
60
+ 'view_count': int,
61
+ 'thumbnail': r're:^https://iv\.okcdn\.ru/videoPreview\?',
39
62
  },
40
63
  }, {
41
64
  # multiple ok_video
@@ -109,36 +132,41 @@ class BoostyIE(InfoExtractor):
109
132
  'thumbnail': r're:^https://i\.mycdn\.me/videoPreview\?',
110
133
  },
111
134
  }],
135
+ 'skip': 'post has been deleted',
112
136
  }, {
113
137
  # single external video (youtube)
114
- 'url': 'https://boosty.to/denischuzhoy/posts/6094a487-bcec-4cf8-a453-43313b463c38',
138
+ 'url': 'https://boosty.to/futuremusicproduction/posts/32a8cae2-3252-49da-b285-0e014bc6e565',
115
139
  'info_dict': {
116
- 'id': 'EXelTnve5lY',
117
- 'title': 'Послание Президента Федеральному Собранию | Класс народа',
118
- 'upload_date': '20210425',
119
- 'channel': 'Денис Чужой',
120
- 'tags': 'count:10',
140
+ 'id': '-37FW_YQ3B4',
141
+ 'title': 'Afro | Deep House FREE FLP',
142
+ 'media_type': 'video',
143
+ 'upload_date': '20250829',
144
+ 'timestamp': 1756466005,
145
+ 'channel': 'Future Music Production',
146
+ 'tags': 'count:0',
121
147
  'like_count': int,
122
- 'ext': 'mp4',
123
- 'duration': 816,
148
+ 'ext': 'm4a',
149
+ 'duration': 170,
124
150
  'view_count': int,
125
151
  'thumbnail': r're:^https://i\.ytimg\.com/',
126
152
  'age_limit': 0,
127
153
  'availability': 'public',
128
154
  'categories': list,
129
155
  'channel_follower_count': int,
130
- 'channel_id': 'UCCzVNbWZfYpBfyofCCUD_0w',
131
- 'channel_is_verified': bool,
156
+ 'channel_id': 'UCKVYrFBYmci1e-T8NeHw2qg',
132
157
  'channel_url': r're:^https://www\.youtube\.com/',
133
158
  'comment_count': int,
134
159
  'description': str,
135
- 'heatmap': 'count:100',
136
160
  'live_status': str,
137
161
  'playable_in_embed': bool,
138
162
  'uploader': str,
139
163
  'uploader_id': str,
140
164
  'uploader_url': r're:^https://www\.youtube\.com/',
141
165
  },
166
+ 'expected_warnings': [
167
+ 'Remote components challenge solver script',
168
+ 'n challenge solving failed',
169
+ ],
142
170
  }]
143
171
 
144
172
  _MP4_TYPES = ('tiny', 'lowest', 'low', 'medium', 'high', 'full_hd', 'quad_hd', 'ultra_hd')
@@ -207,13 +235,14 @@ class BoostyIE(InfoExtractor):
207
235
  video_id = item.get('id') or post_id
208
236
  entries.append({
209
237
  'id': video_id,
238
+ 'alt_title': post_title,
210
239
  'formats': self._extract_formats(item.get('playerUrls'), video_id),
211
240
  **common_metadata,
212
241
  **traverse_obj(item, {
213
242
  'title': ('title', {str}),
214
243
  'duration': ('duration', {int_or_none}),
215
244
  'view_count': ('viewsCounter', {int_or_none}),
216
- 'thumbnail': (('previewUrl', 'defaultPreview'), {url_or_none}),
245
+ 'thumbnail': (('preview', 'defaultPreview'), {url_or_none}),
217
246
  }, get_all=False)})
218
247
 
219
248
  if not entries and not post.get('hasAccess'):
@@ -366,8 +366,7 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
366
366
 
367
367
  @staticmethod
368
368
  def _generate_blockbuster_headers():
369
- # Randomize our HTTP header fingerprint to bust the HTTP Error 403 block
370
- # See https://github.com/yt-dlp/yt-dlp/issues/15526
369
+ """Randomize our HTTP header fingerprint to bust the HTTP Error 403 block"""
371
370
 
372
371
  def random_letters(minimum, maximum):
373
372
  # Omit vowels so we don't generate valid header names like 'authorization', etc
@@ -378,6 +377,43 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
378
377
  for _ in range(random.randint(2, 8))
379
378
  }
380
379
 
380
+ def _extract_dailymotion_m3u8_formats_and_subtitles(self, media_url, video_id, live=False):
381
+ """See https://github.com/yt-dlp/yt-dlp/issues/15526"""
382
+
383
+ ERROR_NOTE = 'Unable to download m3u8 information'
384
+ last_error = None
385
+
386
+ for note, kwargs in (
387
+ ('Downloading m3u8 information', {}),
388
+ ('Retrying m3u8 download with randomized headers', {
389
+ 'headers': self._generate_blockbuster_headers(),
390
+ }),
391
+ ('Retrying m3u8 download with Chrome impersonation', {
392
+ 'impersonate': 'chrome',
393
+ 'require_impersonation': True,
394
+ }),
395
+ ('Retrying m3u8 download with Firefox impersonation', {
396
+ 'impersonate': 'firefox',
397
+ 'require_impersonation': True,
398
+ }),
399
+ ):
400
+ try:
401
+ m3u8_doc = self._download_webpage(media_url, video_id, note, ERROR_NOTE, **kwargs)
402
+ break
403
+ except ExtractorError as e:
404
+ last_error = e.orig_msg
405
+ self.write_debug(f'{video_id}: {last_error}')
406
+ else:
407
+ if 'impersonation' not in last_error:
408
+ self.report_warning(last_error, video_id=video_id)
409
+ last_error = None
410
+ return [], {}, last_error
411
+
412
+ formats, subtitles = self._parse_m3u8_formats_and_subtitles(
413
+ m3u8_doc, media_url, 'mp4', m3u8_id='hls', live=live, fatal=False)
414
+
415
+ return formats, subtitles, last_error
416
+
381
417
  def _real_extract(self, url):
382
418
  url, smuggled_data = unsmuggle_url(url)
383
419
  video_id, is_playlist, playlist_id = self._match_valid_url(url).group('id', 'is_playlist', 'playlist_id')
@@ -431,6 +467,7 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
431
467
  is_live = media.get('isOnAir')
432
468
  formats = []
433
469
  subtitles = {}
470
+ expected_error = None
434
471
 
435
472
  for quality, media_list in metadata['qualities'].items():
436
473
  for m in media_list:
@@ -439,9 +476,8 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
439
476
  if not media_url or media_type == 'application/vnd.lumberjack.manifest':
440
477
  continue
441
478
  if media_type == 'application/x-mpegURL':
442
- fmt, subs = self._extract_m3u8_formats_and_subtitles(
443
- media_url, video_id, 'mp4', live=is_live, m3u8_id='hls',
444
- fatal=False, headers=self._generate_blockbuster_headers())
479
+ fmt, subs, expected_error = self._extract_dailymotion_m3u8_formats_and_subtitles(
480
+ media_url, video_id, live=is_live)
445
481
  formats.extend(fmt)
446
482
  self._merge_subtitles(subs, target=subtitles)
447
483
  else:
@@ -458,6 +494,10 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
458
494
  'width': width,
459
495
  })
460
496
  formats.append(f)
497
+
498
+ if not formats and expected_error:
499
+ self.raise_no_formats(expected_error, expected=True)
500
+
461
501
  for f in formats:
462
502
  f['url'] = f['url'].split('#')[0]
463
503
  if not f.get('fps') and f['format_id'].endswith('@60'):
yt_dlp/extractor/err.py CHANGED
@@ -2,6 +2,7 @@ from .common import InfoExtractor
2
2
  from ..utils import (
3
3
  clean_html,
4
4
  int_or_none,
5
+ parse_iso8601,
5
6
  str_or_none,
6
7
  url_or_none,
7
8
  )
@@ -222,3 +223,70 @@ class ERRJupiterIE(InfoExtractor):
222
223
  'episode_id': ('id', {str_or_none}),
223
224
  }) if data.get('type') == 'episode' else {}),
224
225
  }
226
+
227
+
228
+ class ERRArhiivIE(InfoExtractor):
229
+ _VALID_URL = r'https://arhiiv\.err\.ee/video/(?:vaata/)?(?P<id>[^/?#]+)'
230
+ _TESTS = [{
231
+ 'url': 'https://arhiiv.err.ee/video/kontsertpalad',
232
+ 'info_dict': {
233
+ 'id': 'kontsertpalad',
234
+ 'ext': 'mp4',
235
+ 'title': 'Kontsertpalad: 255 | L. Beethoveni sonaat c-moll, "Pateetiline"',
236
+ 'description': 'md5:a70f4ff23c3618f3be63f704bccef063',
237
+ 'series': 'Kontsertpalad',
238
+ 'episode_id': 255,
239
+ 'timestamp': 1666152162,
240
+ 'upload_date': '20221019',
241
+ 'release_year': 1970,
242
+ 'modified_timestamp': 1718620982,
243
+ 'modified_date': '20240617',
244
+ },
245
+ 'params': {'skip_download': 'm3u8'},
246
+ }, {
247
+ 'url': 'https://arhiiv.err.ee/video/vaata/koalitsioonileppe-allkirjastamine',
248
+ 'info_dict': {
249
+ 'id': 'koalitsioonileppe-allkirjastamine',
250
+ 'ext': 'mp4',
251
+ 'title': 'Koalitsioonileppe allkirjastamine',
252
+ 'timestamp': 1710728222,
253
+ 'upload_date': '20240318',
254
+ 'release_timestamp': 1611532800,
255
+ 'release_date': '20210125',
256
+ },
257
+ 'params': {'skip_download': 'm3u8'},
258
+ }]
259
+
260
+ def _real_extract(self, url):
261
+ video_id = self._match_id(url)
262
+ data = self._download_json(
263
+ f'https://arhiiv.err.ee/api/v1/content/video/{video_id}', video_id)
264
+
265
+ formats, subtitles = [], {}
266
+ if hls_url := traverse_obj(data, ('media', 'src', 'hls', {url_or_none})):
267
+ fmts, subs = self._extract_m3u8_formats_and_subtitles(
268
+ hls_url, video_id, 'mp4', m3u8_id='hls', fatal=False)
269
+ formats.extend(fmts)
270
+ self._merge_subtitles(subs, target=subtitles)
271
+ if dash_url := traverse_obj(data, ('media', 'src', 'dash', {url_or_none})):
272
+ fmts, subs = self._extract_mpd_formats_and_subtitles(
273
+ dash_url, video_id, mpd_id='dash', fatal=False)
274
+ formats.extend(fmts)
275
+ self._merge_subtitles(subs, target=subtitles)
276
+
277
+ return {
278
+ 'id': video_id,
279
+ 'formats': formats,
280
+ 'subtitles': subtitles,
281
+ **traverse_obj(data, ('info', {
282
+ 'title': ('title', {str}),
283
+ 'series': ('seriesTitle', {str}, filter),
284
+ 'series_id': ('seriesId', {str}, filter),
285
+ 'episode_id': ('episode', {int_or_none}),
286
+ 'description': ('synopsis', {str}, filter),
287
+ 'timestamp': ('uploadDate', {parse_iso8601}),
288
+ 'modified_timestamp': ('dateModified', {parse_iso8601}),
289
+ 'release_timestamp': ('date', {parse_iso8601}),
290
+ 'release_year': ('year', {int_or_none}),
291
+ })),
292
+ }
@@ -4,6 +4,7 @@ import urllib.parse
4
4
 
5
5
  from .common import InfoExtractor
6
6
  from ..compat import compat_etree_fromstring
7
+ from ..networking.exceptions import HTTPError
7
8
  from ..utils import (
8
9
  ExtractorError,
9
10
  clean_html,
@@ -1017,6 +1018,7 @@ class FacebookAdsIE(InfoExtractor):
1017
1018
  'upload_date': '20240812',
1018
1019
  'like_count': int,
1019
1020
  },
1021
+ 'skip': 'Invalid URL',
1020
1022
  }, {
1021
1023
  'url': 'https://www.facebook.com/ads/library/?id=893637265423481',
1022
1024
  'info_dict': {
@@ -1031,6 +1033,33 @@ class FacebookAdsIE(InfoExtractor):
1031
1033
  },
1032
1034
  'playlist_count': 3,
1033
1035
  'skip': 'Invalid URL',
1036
+ }, {
1037
+ 'url': 'https://www.facebook.com/ads/library/?id=312304267031140',
1038
+ 'info_dict': {
1039
+ 'id': '312304267031140',
1040
+ 'title': 'Casper Wave Hybrid Mattress',
1041
+ 'uploader': 'Casper',
1042
+ 'uploader_id': '224110981099062',
1043
+ 'uploader_url': 'https://www.facebook.com/Casper/',
1044
+ 'timestamp': 1766299837,
1045
+ 'upload_date': '20251221',
1046
+ 'like_count': int,
1047
+ },
1048
+ 'playlist_count': 2,
1049
+ }, {
1050
+ 'url': 'https://www.facebook.com/ads/library/?id=874812092000430',
1051
+ 'info_dict': {
1052
+ 'id': '874812092000430',
1053
+ 'title': 'TikTok',
1054
+ 'uploader': 'Case \u00e0 Chocs',
1055
+ 'uploader_id': '112960472096793',
1056
+ 'uploader_url': 'https://www.facebook.com/Caseachocs/',
1057
+ 'timestamp': 1768498293,
1058
+ 'upload_date': '20260115',
1059
+ 'like_count': int,
1060
+ 'description': 'md5:f02a255fcf7dce6ed40e9494cf4bc49a',
1061
+ },
1062
+ 'playlist_count': 3,
1034
1063
  }, {
1035
1064
  'url': 'https://es-la.facebook.com/ads/library/?id=901230958115569',
1036
1065
  'only_matching': True,
@@ -1060,9 +1089,36 @@ class FacebookAdsIE(InfoExtractor):
1060
1089
  })
1061
1090
  return formats
1062
1091
 
1092
+ def _download_fb_webpage_and_verify(self, url, video_id):
1093
+ # See https://github.com/yt-dlp/yt-dlp/issues/15577
1094
+
1095
+ try:
1096
+ return self._download_webpage(url, video_id)
1097
+ except ExtractorError as e:
1098
+ if (
1099
+ not isinstance(e.cause, HTTPError)
1100
+ or e.cause.status != 403
1101
+ or e.cause.reason != 'Client challenge'
1102
+ ):
1103
+ raise
1104
+ error_page = self._webpage_read_content(e.cause.response, url, video_id)
1105
+
1106
+ self.write_debug('Received a client challenge response')
1107
+
1108
+ challenge_path = self._search_regex(
1109
+ r'fetch\s*\(\s*["\'](/__rd_verify[^"\']+)["\']',
1110
+ error_page, 'challenge path')
1111
+
1112
+ # Successful response will set the necessary cookie
1113
+ self._request_webpage(
1114
+ urljoin(url, challenge_path), video_id, 'Requesting verification cookie',
1115
+ 'Unable to get verification cookie', data=b'')
1116
+
1117
+ return self._download_webpage(url, video_id)
1118
+
1063
1119
  def _real_extract(self, url):
1064
1120
  video_id = self._match_id(url)
1065
- webpage = self._download_webpage(url, video_id)
1121
+ webpage = self._download_fb_webpage_and_verify(url, video_id)
1066
1122
 
1067
1123
  post_data = traverse_obj(
1068
1124
  re.findall(r'data-sjs>({.*?ScheduledServerJS.*?})</script>', webpage), (..., {json.loads}))
@@ -371,15 +371,16 @@ class FranceTVSiteIE(FranceTVBaseInfoExtractor):
371
371
 
372
372
 
373
373
  class FranceTVInfoIE(FranceTVBaseInfoExtractor):
374
- IE_NAME = 'francetvinfo.fr'
375
- _VALID_URL = r'https?://(?:www|mobile|france3-regions)\.francetvinfo\.fr/(?:[^/]+/)*(?P<id>[^/?#&.]+)'
374
+ IE_NAME = 'franceinfo'
375
+ IE_DESC = 'franceinfo.fr (formerly francetvinfo.fr)'
376
+ _VALID_URL = r'https?://(?:www|mobile|france3-regions)\.france(?:tv)?info.fr/(?:[^/?#]+/)*(?P<id>[^/?#&.]+)'
376
377
 
377
378
  _TESTS = [{
378
379
  'url': 'https://www.francetvinfo.fr/replay-jt/france-3/soir-3/jt-grand-soir-3-jeudi-22-aout-2019_3561461.html',
379
380
  'info_dict': {
380
381
  'id': 'd12458ee-5062-48fe-bfdd-a30d6a01b793',
381
382
  'ext': 'mp4',
382
- 'title': 'Soir 3',
383
+ 'title': 'Soir 3 - Émission du jeudi 22 août 2019',
383
384
  'upload_date': '20190822',
384
385
  'timestamp': 1566510730,
385
386
  'thumbnail': r're:^https?://.*\.jpe?g$',
@@ -398,7 +399,7 @@ class FranceTVInfoIE(FranceTVBaseInfoExtractor):
398
399
  'info_dict': {
399
400
  'id': '7d204c9e-a2d3-11eb-9e4c-000d3a23d482',
400
401
  'ext': 'mp4',
401
- 'title': 'Covid-19 : une situation catastrophique à New Dehli - Édition du mercredi 21 avril 2021',
402
+ 'title': 'Journal 20h00 - Covid-19 : une situation catastrophique à New Dehli',
402
403
  'thumbnail': r're:^https?://.*\.jpe?g$',
403
404
  'duration': 76,
404
405
  'timestamp': 1619028518,
@@ -438,6 +439,18 @@ class FranceTVInfoIE(FranceTVBaseInfoExtractor):
438
439
  'thumbnail': r're:https://[^/?#]+/v/[^/?#]+/x1080',
439
440
  },
440
441
  'add_ie': ['Dailymotion'],
442
+ 'skip': 'Broken Dailymotion link',
443
+ }, {
444
+ 'url': 'https://www.franceinfo.fr/monde/usa/presidentielle/donald-trump/etats-unis-un-risque-d-embrasement-apres-la-mort-d-un-manifestant_7764542.html',
445
+ 'info_dict': {
446
+ 'id': 'f920fcc2-fa20-11f0-ac98-57a09c50f7ce',
447
+ 'ext': 'mp4',
448
+ 'title': 'Affaires sensibles - Manifestant tué Le risque d\'embrasement',
449
+ 'duration': 118,
450
+ 'thumbnail': r're:https?://.+/.+\.jpg',
451
+ 'timestamp': 1769367756,
452
+ 'upload_date': '20260125',
453
+ },
441
454
  }, {
442
455
  'url': 'http://france3-regions.francetvinfo.fr/limousin/emissions/jt-1213-limousin',
443
456
  'only_matching': True,
@@ -445,6 +458,9 @@ class FranceTVInfoIE(FranceTVBaseInfoExtractor):
445
458
  # "<figure id=" pattern (#28792)
446
459
  'url': 'https://www.francetvinfo.fr/culture/patrimoine/incendie-de-notre-dame-de-paris/notre-dame-de-paris-de-l-incendie-de-la-cathedrale-a-sa-reconstruction_4372291.html',
447
460
  'only_matching': True,
461
+ }, {
462
+ 'url': 'https://www.franceinfo.fr/replay-jt/france-2/20-heures/robert-de-niro-portrait-d-un-monument-du-cinema_7245456.html',
463
+ 'only_matching': True,
448
464
  }]
449
465
 
450
466
  def _real_extract(self, url):
@@ -460,7 +476,7 @@ class FranceTVInfoIE(FranceTVBaseInfoExtractor):
460
476
 
461
477
  video_id = (
462
478
  traverse_obj(webpage, (
463
- {find_element(tag='button', attr='data-cy', value='francetv-player-wrapper', html=True)},
479
+ {find_element(tag='(button|div)', attr='data-cy', value='francetv-player-wrapper', html=True, regex=True)},
464
480
  {extract_attributes}, 'id'))
465
481
  or self._search_regex(
466
482
  (r'player\.load[^;]+src:\s*["\']([^"\']+)',
@@ -104,9 +104,9 @@ class FrontroGroupBaseIE(FrontoBaseIE):
104
104
  class TheChosenIE(FrontroVideoBaseIE):
105
105
  _CHANNEL_ID = '12884901895'
106
106
 
107
- _VALID_URL = r'https?://(?:www\.)?watch\.thechosen\.tv/video/(?P<id>[0-9]+)'
107
+ _VALID_URL = r'https?://(?:www\.)?watch\.thechosen\.tv/watch/(?P<id>[0-9]+)'
108
108
  _TESTS = [{
109
- 'url': 'https://watch.thechosen.tv/video/184683594325',
109
+ 'url': 'https://watch.thechosen.tv/watch/184683594325',
110
110
  'md5': '3f878b689588c71b38ec9943c54ff5b0',
111
111
  'info_dict': {
112
112
  'id': '184683594325',
@@ -124,7 +124,7 @@ class TheChosenIE(FrontroVideoBaseIE):
124
124
  'modified_date': str,
125
125
  },
126
126
  }, {
127
- 'url': 'https://watch.thechosen.tv/video/184683596189',
127
+ 'url': 'https://watch.thechosen.tv/watch/184683596189',
128
128
  'md5': 'd581562f9d29ce82f5b7770415334151',
129
129
  'info_dict': {
130
130
  'id': '184683596189',
@@ -147,7 +147,7 @@ class TheChosenIE(FrontroVideoBaseIE):
147
147
  class TheChosenGroupIE(FrontroGroupBaseIE):
148
148
  _CHANNEL_ID = '12884901895'
149
149
  _VIDEO_EXTRACTOR = TheChosenIE
150
- _VIDEO_URL_TMPL = 'https://watch.thechosen.tv/video/%s'
150
+ _VIDEO_URL_TMPL = 'https://watch.thechosen.tv/watch/%s'
151
151
 
152
152
  _VALID_URL = r'https?://(?:www\.)?watch\.thechosen\.tv/group/(?P<id>[0-9]+)'
153
153
  _TESTS = [{