yt-dlp 2026.1.19.233146.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.
- yt_dlp/extractor/_extractors.py +9 -2
- yt_dlp/extractor/boosty.py +45 -16
- yt_dlp/extractor/dailymotion.py +58 -2
- yt_dlp/extractor/err.py +68 -0
- yt_dlp/extractor/facebook.py +57 -1
- yt_dlp/extractor/francetv.py +21 -5
- yt_dlp/extractor/frontro.py +4 -4
- yt_dlp/extractor/lazy_extractors.py +39 -7
- yt_dlp/extractor/lbry.py +1 -0
- yt_dlp/extractor/neteasemusic.py +32 -7
- yt_dlp/extractor/patreon.py +118 -33
- yt_dlp/extractor/pbs.py +18 -0
- yt_dlp/extractor/rumble.py +1 -1
- yt_dlp/extractor/tiktok.py +83 -24
- yt_dlp/extractor/volejtv.py +149 -22
- yt_dlp/extractor/wat.py +1 -1
- yt_dlp/version.py +3 -3
- {yt_dlp-2026.1.19.233146.dev0.dist-info → yt_dlp-2026.1.27.233257.dev0.dist-info}/METADATA +1 -1
- {yt_dlp-2026.1.19.233146.dev0.dist-info → yt_dlp-2026.1.27.233257.dev0.dist-info}/RECORD +27 -27
- {yt_dlp-2026.1.19.233146.dev0.data → yt_dlp-2026.1.27.233257.dev0.data}/data/share/bash-completion/completions/yt-dlp +0 -0
- {yt_dlp-2026.1.19.233146.dev0.data → yt_dlp-2026.1.27.233257.dev0.data}/data/share/doc/yt_dlp/README.txt +0 -0
- {yt_dlp-2026.1.19.233146.dev0.data → yt_dlp-2026.1.27.233257.dev0.data}/data/share/fish/vendor_completions.d/yt-dlp.fish +0 -0
- {yt_dlp-2026.1.19.233146.dev0.data → yt_dlp-2026.1.27.233257.dev0.data}/data/share/man/man1/yt-dlp.1 +0 -0
- {yt_dlp-2026.1.19.233146.dev0.data → yt_dlp-2026.1.27.233257.dev0.data}/data/share/zsh/site-functions/_yt-dlp +0 -0
- {yt_dlp-2026.1.19.233146.dev0.dist-info → yt_dlp-2026.1.27.233257.dev0.dist-info}/WHEEL +0 -0
- {yt_dlp-2026.1.19.233146.dev0.dist-info → yt_dlp-2026.1.27.233257.dev0.dist-info}/entry_points.txt +0 -0
- {yt_dlp-2026.1.19.233146.dev0.dist-info → yt_dlp-2026.1.27.233257.dev0.dist-info}/licenses/LICENSE +0 -0
yt_dlp/extractor/_extractors.py
CHANGED
|
@@ -564,7 +564,10 @@ from .eroprofile import (
|
|
|
564
564
|
EroProfileAlbumIE,
|
|
565
565
|
EroProfileIE,
|
|
566
566
|
)
|
|
567
|
-
from .err import
|
|
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
|
|
2366
|
+
from .volejtv import (
|
|
2367
|
+
VolejTVCategoryPlaylistIE,
|
|
2368
|
+
VolejTVClubPlaylistIE,
|
|
2369
|
+
VolejTVIE,
|
|
2370
|
+
)
|
|
2364
2371
|
from .voxmedia import (
|
|
2365
2372
|
VoxMediaIE,
|
|
2366
2373
|
VoxMediaVolumeIE,
|
yt_dlp/extractor/boosty.py
CHANGED
|
@@ -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': '
|
|
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':
|
|
32
|
-
'modified_date': '
|
|
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://
|
|
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/
|
|
138
|
+
'url': 'https://boosty.to/futuremusicproduction/posts/32a8cae2-3252-49da-b285-0e014bc6e565',
|
|
115
139
|
'info_dict': {
|
|
116
|
-
'id': '
|
|
117
|
-
'title': '
|
|
118
|
-
'
|
|
119
|
-
'
|
|
120
|
-
'
|
|
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': '
|
|
123
|
-
'duration':
|
|
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': '
|
|
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': (('
|
|
245
|
+
'thumbnail': (('preview', 'defaultPreview'), {url_or_none}),
|
|
217
246
|
}, get_all=False)})
|
|
218
247
|
|
|
219
248
|
if not entries and not post.get('hasAccess'):
|
yt_dlp/extractor/dailymotion.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
import json
|
|
3
|
+
import random
|
|
3
4
|
import re
|
|
4
5
|
import urllib.parse
|
|
5
6
|
|
|
@@ -363,6 +364,56 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
|
|
|
363
364
|
continue
|
|
364
365
|
yield update_url(player_url, query=query_string)
|
|
365
366
|
|
|
367
|
+
@staticmethod
|
|
368
|
+
def _generate_blockbuster_headers():
|
|
369
|
+
"""Randomize our HTTP header fingerprint to bust the HTTP Error 403 block"""
|
|
370
|
+
|
|
371
|
+
def random_letters(minimum, maximum):
|
|
372
|
+
# Omit vowels so we don't generate valid header names like 'authorization', etc
|
|
373
|
+
return ''.join(random.choices('bcdfghjklmnpqrstvwxz', k=random.randint(minimum, maximum)))
|
|
374
|
+
|
|
375
|
+
return {
|
|
376
|
+
random_letters(8, 24): random_letters(16, 32)
|
|
377
|
+
for _ in range(random.randint(2, 8))
|
|
378
|
+
}
|
|
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
|
+
|
|
366
417
|
def _real_extract(self, url):
|
|
367
418
|
url, smuggled_data = unsmuggle_url(url)
|
|
368
419
|
video_id, is_playlist, playlist_id = self._match_valid_url(url).group('id', 'is_playlist', 'playlist_id')
|
|
@@ -416,6 +467,7 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
|
|
|
416
467
|
is_live = media.get('isOnAir')
|
|
417
468
|
formats = []
|
|
418
469
|
subtitles = {}
|
|
470
|
+
expected_error = None
|
|
419
471
|
|
|
420
472
|
for quality, media_list in metadata['qualities'].items():
|
|
421
473
|
for m in media_list:
|
|
@@ -424,8 +476,8 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
|
|
|
424
476
|
if not media_url or media_type == 'application/vnd.lumberjack.manifest':
|
|
425
477
|
continue
|
|
426
478
|
if media_type == 'application/x-mpegURL':
|
|
427
|
-
fmt, subs = self.
|
|
428
|
-
media_url, video_id,
|
|
479
|
+
fmt, subs, expected_error = self._extract_dailymotion_m3u8_formats_and_subtitles(
|
|
480
|
+
media_url, video_id, live=is_live)
|
|
429
481
|
formats.extend(fmt)
|
|
430
482
|
self._merge_subtitles(subs, target=subtitles)
|
|
431
483
|
else:
|
|
@@ -442,6 +494,10 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
|
|
|
442
494
|
'width': width,
|
|
443
495
|
})
|
|
444
496
|
formats.append(f)
|
|
497
|
+
|
|
498
|
+
if not formats and expected_error:
|
|
499
|
+
self.raise_no_formats(expected_error, expected=True)
|
|
500
|
+
|
|
445
501
|
for f in formats:
|
|
446
502
|
f['url'] = f['url'].split('#')[0]
|
|
447
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
|
+
}
|
yt_dlp/extractor/facebook.py
CHANGED
|
@@ -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.
|
|
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}))
|
yt_dlp/extractor/francetv.py
CHANGED
|
@@ -371,15 +371,16 @@ class FranceTVSiteIE(FranceTVBaseInfoExtractor):
|
|
|
371
371
|
|
|
372
372
|
|
|
373
373
|
class FranceTVInfoIE(FranceTVBaseInfoExtractor):
|
|
374
|
-
IE_NAME = '
|
|
375
|
-
|
|
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
|
|
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*["\']([^"\']+)',
|
yt_dlp/extractor/frontro.py
CHANGED
|
@@ -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/
|
|
107
|
+
_VALID_URL = r'https?://(?:www\.)?watch\.thechosen\.tv/watch/(?P<id>[0-9]+)'
|
|
108
108
|
_TESTS = [{
|
|
109
|
-
'url': 'https://watch.thechosen.tv/
|
|
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/
|
|
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/
|
|
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 = [{
|