https://germanupa\.de/media/oembed\?url=(?:(?!\1).)+)\1',
+ webpage, 'embedded video', default=None, group='url'),
+ ({parse_qs}, 'url', 0, {url_or_none}))
+
+ if not param_url:
+ if self._search_regex(
+ r']+class\s*?=\s*?([\'"])(?:(?!\1).)*login-wrapper(?:(?!\1).)*\1',
+ webpage, 'login wrapper', default=None):
+ self.raise_login_required('This video is only available for members')
+ return self.url_result(url, 'Generic') # Fall back to generic to extract audio
+
+ real_url = param_url.replace('https://vimeo.com/', 'https://player.vimeo.com/video/')
+ return self.url_result(VimeoIE._smuggle_referrer(real_url, url), VimeoIE, video_id)
diff --git a/yt-dlp/yt_dlp/extractor/mediaklikk.py b/yt-dlp/yt_dlp/extractor/mediaklikk.py
index f51342060b..197e91d1d9 100644
--- a/yt-dlp/yt_dlp/extractor/mediaklikk.py
+++ b/yt-dlp/yt_dlp/extractor/mediaklikk.py
@@ -16,6 +16,15 @@ class MediaKlikkIE(InfoExtractor):
(?P[^/#?_]+)'''
_TESTS = [{
+ 'url': 'https://mediaklikk.hu/filmajanlo/cikk/az-ajto/',
+ 'info_dict': {
+ 'id': '668177',
+ 'title': 'Az ajtó',
+ 'display_id': 'az-ajto',
+ 'ext': 'mp4',
+ 'thumbnail': 'https://cdn.cms.mtv.hu/wp-content/uploads/sites/4/2016/01/vlcsnap-2023-07-31-14h18m52s111.jpg',
+ },
+ }, {
# (old) mediaklikk. date in html.
'url': 'https://mediaklikk.hu/video/hazajaro-delnyugat-bacska-a-duna-menten-palankatol-doroszloig/',
'info_dict': {
@@ -37,6 +46,7 @@ class MediaKlikkIE(InfoExtractor):
'upload_date': '20230903',
'thumbnail': 'https://mediaklikk.hu/wp-content/uploads/sites/4/2014/02/hazajarouj_JO.jpg',
},
+ 'skip': 'Webpage redirects to 404 page',
}, {
# (old) m4sport
'url': 'https://m4sport.hu/video/2021/08/30/gyemant-liga-parizs/',
@@ -59,6 +69,7 @@ class MediaKlikkIE(InfoExtractor):
'upload_date': '20230908',
'thumbnail': 'https://m4sport.hu/wp-content/uploads/sites/4/2023/09/vlcsnap-2023-09-08-22h43m18s691.jpg',
},
+ 'skip': 'Webpage redirects to 404 page',
}, {
# m4sport with *video/ url and no date
'url': 'https://m4sport.hu/bl-video/real-madrid-chelsea-1-1/',
@@ -69,6 +80,7 @@ class MediaKlikkIE(InfoExtractor):
'ext': 'mp4',
'thumbnail': 'https://m4sport.hu/wp-content/uploads/sites/4/2021/04/Sequence-01.Still001-1024x576.png',
},
+ 'skip': 'Webpage redirects to 404 page',
}, {
# (old) hirado
'url': 'https://hirado.hu/videok/felteteleket-szabott-a-fovaros/',
@@ -90,6 +102,7 @@ class MediaKlikkIE(InfoExtractor):
'upload_date': '20230911',
'thumbnail': 'https://hirado.hu/wp-content/uploads/sites/4/2023/09/vlcsnap-2023-09-11-09h16m09s882.jpg',
},
+ 'skip': 'Webpage redirects to video list page',
}, {
# (old) petofilive
'url': 'https://petofilive.hu/video/2021/06/07/tha-shudras-az-akusztikban/',
@@ -112,6 +125,7 @@ class MediaKlikkIE(InfoExtractor):
'upload_date': '20230909',
'thumbnail': 'https://petofilive.hu/wp-content/uploads/sites/4/2023/09/Clipboard11-2.jpg',
},
+ 'skip': 'Webpage redirects to video list page',
}]
def _real_extract(self, url):
@@ -143,14 +157,14 @@ class MediaKlikkIE(InfoExtractor):
if not playlist_url:
raise ExtractorError('Unable to extract playlist url')
- formats = self._extract_wowza_formats(
- playlist_url, video_id, skip_protocols=['f4m', 'smil', 'dash'])
+ formats, subtitles = self._extract_m3u8_formats_and_subtitles(playlist_url, video_id)
return {
'id': video_id,
'title': title,
'display_id': display_id,
'formats': formats,
+ 'subtitles': subtitles,
'upload_date': upload_date,
'thumbnail': player_data.get('bgImage') or self._og_search_thumbnail(webpage),
}
diff --git a/yt-dlp/yt_dlp/extractor/mojevideo.py b/yt-dlp/yt_dlp/extractor/mojevideo.py
new file mode 100644
index 0000000000..145e306970
--- /dev/null
+++ b/yt-dlp/yt_dlp/extractor/mojevideo.py
@@ -0,0 +1,121 @@
+from .common import InfoExtractor
+from ..utils import js_to_json, remove_end, update_url_query
+
+
+class MojevideoIE(InfoExtractor):
+ IE_DESC = 'mojevideo.sk'
+ _VALID_URL = r'https?://(?:www\.)?mojevideo\.sk/video/(?P\w+)/(?P[\w()]+?)\.html'
+
+ _TESTS = [{
+ 'url': 'https://www.mojevideo.sk/video/3d17c/chlapci_dobetonovali_sme_mame_hotovo.html',
+ 'md5': '384a4628bd2bbd261c5206cf77c38c17',
+ 'info_dict': {
+ 'id': '3d17c',
+ 'ext': 'mp4',
+ 'title': 'Chlapci dobetónovali sme, máme hotovo!',
+ 'display_id': 'chlapci_dobetonovali_sme_mame_hotovo',
+ 'description': 'md5:a0822126044050d304a9ef58c92ddb34',
+ 'thumbnail': 'https://fs5.mojevideo.sk/imgfb/250236.jpg',
+ 'duration': 21.0,
+ 'upload_date': '20230919',
+ 'timestamp': 1695129706,
+ 'like_count': int,
+ 'dislike_count': int,
+ 'view_count': int,
+ 'comment_count': int,
+ },
+ }, {
+ # 720p
+ 'url': 'https://www.mojevideo.sk/video/14677/den_blbec.html',
+ 'md5': '517c3e111c53a67d10b429c1f344ba2f',
+ 'info_dict': {
+ 'id': '14677',
+ 'ext': 'mp4',
+ 'title': 'Deň blbec?',
+ 'display_id': 'den_blbec',
+ 'description': 'I maličkosť vám môže zmeniť celý deň. Nikdy nezahadzujte žuvačky na zem!',
+ 'thumbnail': 'https://fs5.mojevideo.sk/imgfb/83575.jpg',
+ 'duration': 100.0,
+ 'upload_date': '20120515',
+ 'timestamp': 1337076481,
+ 'like_count': int,
+ 'dislike_count': int,
+ 'view_count': int,
+ 'comment_count': int,
+ },
+ }, {
+ # 1080p
+ 'url': 'https://www.mojevideo.sk/video/2feb2/band_maid_onset_(instrumental)_live_zepp_tokyo_(full_hd).html',
+ 'md5': '64599a23d3ac31cf2fe069e4353d8162',
+ 'info_dict': {
+ 'id': '2feb2',
+ 'ext': 'mp4',
+ 'title': 'BAND-MAID - onset (Instrumental) Live - Zepp Tokyo (Full HD)',
+ 'display_id': 'band_maid_onset_(instrumental)_live_zepp_tokyo_(full_hd)',
+ 'description': 'Výborná inštrumentálna skladba od skupiny BAND-MAID.',
+ 'thumbnail': 'https://fs5.mojevideo.sk/imgfb/196274.jpg',
+ 'duration': 240.0,
+ 'upload_date': '20190708',
+ 'timestamp': 1562576592,
+ 'like_count': int,
+ 'dislike_count': int,
+ 'view_count': int,
+ 'comment_count': int,
+ },
+ }, {
+ # 720p
+ 'url': 'https://www.mojevideo.sk/video/358c8/dva_nissany_skyline_strielaju_v_londyne.html',
+ 'only_matching': True,
+ }, {
+ # 720p
+ 'url': 'https://www.mojevideo.sk/video/2455d/gopro_hero4_session_nova_sportova_vodotesna_kamera.html',
+ 'only_matching': True,
+ }, {
+ # 1080p
+ 'url': 'https://www.mojevideo.sk/video/352ee/amd_rx_6800_xt_vs_nvidia_rtx_3080_(test_v_9_hrach).html',
+ 'only_matching': True,
+ }, {
+ # 1080p
+ 'url': 'https://www.mojevideo.sk/video/2cbeb/trailer_z_avengers_infinity_war.html',
+ 'only_matching': True,
+ }]
+
+ def _real_extract(self, url):
+ video_id, display_id = self._match_valid_url(url).groups()
+ webpage = self._download_webpage(url, video_id)
+
+ video_id_dec = self._search_regex(
+ r'\bvId\s*=\s*(\d+)', webpage, 'video id', fatal=False) or str(int(video_id, 16))
+ video_exp = self._search_regex(r'\bvEx\s*=\s*["\'](\d+)', webpage, 'video expiry')
+ video_hashes = self._search_json(
+ r'\bvHash\s*=', webpage, 'video hashes', video_id,
+ contains_pattern=r'\[(?s:.+)\]', transform_source=js_to_json)
+
+ formats = []
+ for video_hash, (suffix, quality, format_note) in zip(video_hashes, [
+ ('', 1, 'normálna kvalita'),
+ ('_lq', 0, 'nízka kvalita'),
+ ('_hd', 2, 'HD-720p'),
+ ('_fhd', 3, 'FULL HD-1080p'),
+ ('_2k', 4, '2K-1440p'),
+ ]):
+ formats.append({
+ 'format_id': f'mp4-{quality}',
+ 'quality': quality,
+ 'format_note': format_note,
+ 'url': update_url_query(
+ f'https://cache01.mojevideo.sk/securevideos69/{video_id_dec}{suffix}.mp4', {
+ 'md5': video_hash,
+ 'expires': video_exp,
+ }),
+ })
+
+ return {
+ 'id': video_id,
+ 'display_id': display_id,
+ 'formats': formats,
+ 'title': (self._og_search_title(webpage, default=None)
+ or remove_end(self._html_extract_title(webpage, 'title'), ' - Mojevideo')),
+ 'description': self._og_search_description(webpage),
+ **self._search_json_ld(webpage, video_id, default={}),
+ }
diff --git a/yt-dlp/yt_dlp/extractor/rumble.py b/yt-dlp/yt_dlp/extractor/rumble.py
index db780a2cf4..74c7e4f176 100644
--- a/yt-dlp/yt_dlp/extractor/rumble.py
+++ b/yt-dlp/yt_dlp/extractor/rumble.py
@@ -8,14 +8,17 @@ from ..utils import (
UnsupportedError,
clean_html,
determine_ext,
+ extract_attributes,
format_field,
get_element_by_class,
+ get_elements_html_by_class,
int_or_none,
join_nonempty,
parse_count,
parse_iso8601,
traverse_obj,
unescapeHTML,
+ urljoin,
)
@@ -382,8 +385,10 @@ class RumbleChannelIE(InfoExtractor):
if isinstance(e.cause, HTTPError) and e.cause.status == 404:
break
raise
- for video_url in re.findall(r'class="[^>"]*videostream__link[^>]+href="([^"]+\.html)"', webpage):
- yield self.url_result('https://rumble.com' + video_url)
+ for video_url in traverse_obj(
+ get_elements_html_by_class('videostream__link', webpage), (..., {extract_attributes}, 'href'),
+ ):
+ yield self.url_result(urljoin('https://rumble.com', video_url))
def _real_extract(self, url):
url, playlist_id = self._match_valid_url(url).groups()
diff --git a/yt-dlp/yt_dlp/extractor/snapchat.py b/yt-dlp/yt_dlp/extractor/snapchat.py
new file mode 100644
index 0000000000..732677c190
--- /dev/null
+++ b/yt-dlp/yt_dlp/extractor/snapchat.py
@@ -0,0 +1,76 @@
+from .common import InfoExtractor
+from ..utils import float_or_none, int_or_none, url_or_none
+from ..utils.traversal import traverse_obj
+
+
+class SnapchatSpotlightIE(InfoExtractor):
+ _VALID_URL = r'https?://(?:www\.)?snapchat\.com/spotlight/(?P\w+)'
+
+ _TESTS = [{
+ 'url': 'https://www.snapchat.com/spotlight/W7_EDlXWTBiXAEEniNoMPwAAYYWtidGhudGZpAX1TKn0JAX1TKnXJAAAAAA',
+ 'md5': '46c580f63592d0cbb76e974d2f9f0fcc',
+ 'info_dict': {
+ 'id': 'W7_EDlXWTBiXAEEniNoMPwAAYYWtidGhudGZpAX1TKn0JAX1TKnXJAAAAAA',
+ 'ext': 'mp4',
+ 'title': 'Views 💕',
+ 'description': '',
+ 'thumbnail': r're:https://cf-st\.sc-cdn\.net/d/kKJHIR1QAznRKK9jgYYDq\.256\.IRZXSOY',
+ 'duration': 4.665,
+ 'timestamp': 1637777831.369,
+ 'upload_date': '20211124',
+ 'repost_count': int,
+ 'uploader': 'shreypatel57',
+ 'uploader_url': 'https://www.snapchat.com/add/shreypatel57',
+ },
+ }, {
+ 'url': 'https://www.snapchat.com/spotlight/W7_EDlXWTBiXAEEniNoMPwAAYcnVjYWdwcGV1AZEaIYn5AZEaIYnrAAAAAQ',
+ 'md5': '4cd9626458c1a0e3e6dbe72c544a9ec2',
+ 'info_dict': {
+ 'id': 'W7_EDlXWTBiXAEEniNoMPwAAYcnVjYWdwcGV1AZEaIYn5AZEaIYnrAAAAAQ',
+ 'ext': 'mp4',
+ 'title': 'Spotlight Snap',
+ 'description': 'How he flirt her teacher🤭🤭🤩😍 #kdrama#cdrama #dramaclips #dramaspotlight',
+ 'thumbnail': r're:https://cf-st\.sc-cdn\.net/i/ztfr6xFs0FOcFhwVczWfj\.256\.IRZXSOY',
+ 'duration': 10.91,
+ 'timestamp': 1722720291.307,
+ 'upload_date': '20240803',
+ 'view_count': int,
+ 'repost_count': int,
+ 'uploader': 'ganda0535',
+ 'uploader_url': 'https://www.snapchat.com/add/ganda0535',
+ 'tags': ['#dramaspotlight', '#dramaclips', '#cdrama', '#kdrama'],
+ },
+ }]
+
+ def _real_extract(self, url):
+ video_id = self._match_id(url)
+ webpage = self._download_webpage(url, video_id)
+ page_props = self._search_nextjs_data(webpage, video_id)['props']['pageProps']
+ video_data = traverse_obj(page_props, (
+ 'spotlightFeed', 'spotlightStories',
+ lambda _, v: v['story']['storyId']['value'] == video_id, 'metadata', any), None)
+
+ return {
+ 'id': video_id,
+ 'ext': 'mp4',
+ **traverse_obj(video_data, ('videoMetadata', {
+ 'title': ('name', {str}),
+ 'description': ('description', {str}),
+ 'timestamp': ('uploadDateMs', {lambda x: float_or_none(x, 1000)}),
+ 'view_count': ('viewCount', {int_or_none}, {lambda x: None if x == -1 else x}),
+ 'repost_count': ('shareCount', {int_or_none}),
+ 'url': ('contentUrl', {url_or_none}),
+ 'width': ('width', {int_or_none}),
+ 'height': ('height', {int_or_none}),
+ 'duration': ('durationMs', {lambda x: float_or_none(x, 1000)}),
+ 'thumbnail': ('thumbnailUrl', {url_or_none}),
+ 'uploader': ('creator', 'personCreator', 'username', {str}),
+ 'uploader_url': ('creator', 'personCreator', 'url', {url_or_none}),
+ })),
+ **traverse_obj(video_data, {
+ 'description': ('description', {str}),
+ 'tags': ('hashtags', ..., {str}),
+ 'view_count': ('engagementStats', 'viewCount', {int_or_none}, {lambda x: None if x == -1 else x}),
+ 'repost_count': ('engagementStats', 'shareCount', {int_or_none}),
+ }),
+ }
diff --git a/yt-dlp/yt_dlp/extractor/svt.py b/yt-dlp/yt_dlp/extractor/svt.py
index 38782abac7..b5df2e1a18 100644
--- a/yt-dlp/yt_dlp/extractor/svt.py
+++ b/yt-dlp/yt_dlp/extractor/svt.py
@@ -472,7 +472,7 @@ class SVTPageIE(SVTBaseIE):
title = self._og_search_title(webpage)
urql_state = self._search_json(
- r'window\.svt\.nyh\.urqlState\s*=', webpage, 'json data', display_id)
+ r'window\.svt\.(?:nyh\.)?urqlState\s*=', webpage, 'json data', display_id)
data = traverse_obj(urql_state, (..., 'data', {str}, {json.loads}), get_all=False) or {}
diff --git a/yt-dlp/yt_dlp/networking/_curlcffi.py b/yt-dlp/yt_dlp/networking/_curlcffi.py
index e8a67b7347..0643348e7e 100644
--- a/yt-dlp/yt_dlp/networking/_curlcffi.py
+++ b/yt-dlp/yt_dlp/networking/_curlcffi.py
@@ -31,9 +31,9 @@ if curl_cffi is None:
curl_cffi_version = tuple(map(int, re.split(r'[^\d]+', curl_cffi.__version__)[:3]))
-if curl_cffi_version != (0, 5, 10) and not ((0, 7, 0) <= curl_cffi_version < (0, 8, 0)):
+if curl_cffi_version != (0, 5, 10) and not ((0, 7, 0) <= curl_cffi_version < (0, 7, 2)):
curl_cffi._yt_dlp__version = f'{curl_cffi.__version__} (unsupported)'
- raise ImportError('Only curl_cffi versions 0.5.10, 0.7.X are supported')
+ raise ImportError('Only curl_cffi versions 0.5.10, 0.7.0 and 0.7.1 are supported')
import curl_cffi.requests
from curl_cffi.const import CurlECode, CurlOpt