]+\bclass=["\']video["\'][^>]+\bdata-pid=["\'](%s)' % self._ID_REGEX,
+ rf'
]+\bclass=["\']video["\'][^>]+\bdata-pid=["\']({self._ID_REGEX})',
webpage, 'group id', default=None)
if group_id:
return self.url_result(
@@ -1043,9 +1043,9 @@ def _real_extract(self, url):
# single video story (e.g. http://www.bbc.com/travel/story/20150625-sri-lankas-spicy-secret)
programme_id = self._search_regex(
- [r'data-(?:video-player|media)-vpid="(%s)"' % self._ID_REGEX,
- r'
]+name="externalIdentifier"[^>]+value="(%s)"' % self._ID_REGEX,
- r'videoId\s*:\s*["\'](%s)["\']' % self._ID_REGEX],
+ [rf'data-(?:video-player|media)-vpid="({self._ID_REGEX})"',
+ rf'
]+name="externalIdentifier"[^>]+value="({self._ID_REGEX})"',
+ rf'videoId\s*:\s*["\']({self._ID_REGEX})["\']'],
webpage, 'vpid', default=None)
if programme_id:
@@ -1142,7 +1142,7 @@ def _real_extract(self, url):
video_id, url_transparent=True)
entry.update({
'timestamp': traverse_obj(morph_payload, (
- 'body', 'content', 'article', 'dateTimeInfo', 'dateTime', {parse_iso8601})
+ 'body', 'content', 'article', 'dateTimeInfo', 'dateTime', {parse_iso8601}),
),
**traverse_obj(video_data, {
'thumbnail': (('iChefImage', 'image'), {url_or_none}, any),
@@ -1189,7 +1189,7 @@ def _real_extract(self, url):
'primary', 'secondary', 'tertiary', delim=' - ', from_dict=x)}),
'start_time': ('offset', 'start', {float_or_none}),
'end_time': ('offset', 'end', {float_or_none}),
- })
+ }),
),
}
@@ -1287,7 +1287,7 @@ def parse_model(model):
'description': ('synopses', ('long', 'medium', 'short'), {str}, {lambda x: x or None}, any),
'duration': ('versions', 0, 'duration', {int}),
'timestamp': ('versions', 0, 'availableFrom', {functools.partial(int_or_none, scale=1000)}),
- })
+ }),
}
def is_type(*types):
@@ -1331,7 +1331,7 @@ def parse_media(media):
if blocks:
summary = []
for block in blocks:
- text = try_get(block, lambda x: x['model']['text'], compat_str)
+ text = try_get(block, lambda x: x['model']['text'], str)
if text:
summary.append(text)
if summary:
@@ -1411,9 +1411,9 @@ def parse_media(media):
entries, playlist_id, playlist_title, playlist_description)
def extract_all(pattern):
- return list(filter(None, map(
- lambda s: self._parse_json(s, playlist_id, fatal=False),
- re.findall(pattern, webpage))))
+ return list(filter(None, (
+ self._parse_json(s, playlist_id, fatal=False)
+ for s in re.findall(pattern, webpage))))
# US accessed article with single embedded video (e.g.
# https://www.bbc.com/news/uk-68546268)
@@ -1435,14 +1435,14 @@ def extract_all(pattern):
# Multiple video article (e.g.
# http://www.bbc.co.uk/blogs/adamcurtis/entries/3662a707-0af9-3149-963f-47bea720b460)
- EMBED_URL = r'https?://(?:www\.)?bbc\.co\.uk/(?:[^/]+/)+%s(?:\b[^"]+)?' % self._ID_REGEX
+ EMBED_URL = rf'https?://(?:www\.)?bbc\.co\.uk/(?:[^/]+/)+{self._ID_REGEX}(?:\b[^"]+)?'
entries = []
for match in extract_all(r'new\s+SMP\(({.+?})\)'):
embed_url = match.get('playerSettings', {}).get('externalEmbedUrl')
if embed_url and re.match(EMBED_URL, embed_url):
entries.append(embed_url)
entries.extend(re.findall(
- r'setPlaylist\("(%s)"\)' % EMBED_URL, webpage))
+ rf'setPlaylist\("({EMBED_URL})"\)', webpage))
if entries:
return self.playlist_result(
[self.url_result(entry_, 'BBCCoUk') for entry_ in entries],
@@ -1492,11 +1492,11 @@ def extract_all(pattern):
video_id = media_meta.get('externalId')
if not video_id:
- video_id = playlist_id if len(medias) == 1 else '%s-%s' % (playlist_id, num)
+ video_id = playlist_id if len(medias) == 1 else f'{playlist_id}-{num}'
title = media_meta.get('caption')
if not title:
- title = playlist_title if len(medias) == 1 else '%s - Video %s' % (playlist_title, num)
+ title = playlist_title if len(medias) == 1 else f'{playlist_title} - Video {num}'
duration = int_or_none(media_meta.get('durationInSeconds')) or parse_duration(media_meta.get('duration'))
@@ -1557,8 +1557,8 @@ def _real_extract(self, url):
class BBCCoUkPlaylistBaseIE(InfoExtractor):
def _entries(self, webpage, url, playlist_id):
- single_page = 'page' in compat_urlparse.parse_qs(
- compat_urlparse.urlparse(url).query)
+ single_page = 'page' in urllib.parse.parse_qs(
+ urllib.parse.urlparse(url).query)
for page_num in itertools.count(2):
for video_id in re.findall(
self._VIDEO_ID_TEMPLATE % BBCCoUkIE._ID_REGEX, webpage):
@@ -1572,8 +1572,8 @@ def _entries(self, webpage, url, playlist_id):
if not next_page:
break
webpage = self._download_webpage(
- compat_urlparse.urljoin(url, next_page), playlist_id,
- 'Downloading page %d' % page_num, page_num)
+ urllib.parse.urljoin(url, next_page), playlist_id,
+ f'Downloading page {page_num}', page_num)
def _real_extract(self, url):
playlist_id = self._match_id(url)
@@ -1588,7 +1588,7 @@ def _real_extract(self, url):
class BBCCoUkIPlayerPlaylistBaseIE(InfoExtractor):
- _VALID_URL_TMPL = r'https?://(?:www\.)?bbc\.co\.uk/iplayer/%%s/(?P
%s)' % BBCCoUkIE._ID_REGEX
+ _VALID_URL_TMPL = rf'https?://(?:www\.)?bbc\.co\.uk/iplayer/%s/(?P{BBCCoUkIE._ID_REGEX})'
@staticmethod
def _get_default(episode, key, default_key='default'):
@@ -1712,11 +1712,11 @@ def _call_api(self, pid, per_page, page=1, series_id=None):
variables['sliceId'] = series_id
return self._download_json(
'https://graph.ibl.api.bbc.co.uk/', pid, headers={
- 'Content-Type': 'application/json'
+ 'Content-Type': 'application/json',
}, data=json.dumps({
'id': '5692d93d5aac8d796a0305e895e61551',
'variables': variables,
- }).encode('utf-8'))['data']['programme']
+ }).encode())['data']['programme']
@staticmethod
def _get_playlist_data(data):
@@ -1776,7 +1776,7 @@ def _get_episode(element):
def _call_api(self, pid, per_page, page=1, series_id=None):
return self._download_json(
- 'http://ibl.api.bbc.co.uk/ibl/v1/groups/%s/episodes' % pid,
+ f'http://ibl.api.bbc.co.uk/ibl/v1/groups/{pid}/episodes',
pid, query={
'page': page,
'per_page': per_page,
@@ -1792,7 +1792,7 @@ def _get_playlist_title(self, data):
class BBCCoUkPlaylistIE(BBCCoUkPlaylistBaseIE):
IE_NAME = 'bbc.co.uk:playlist'
- _VALID_URL = r'https?://(?:www\.)?bbc\.co\.uk/programmes/(?P%s)/(?:episodes|broadcasts|clips)' % BBCCoUkIE._ID_REGEX
+ _VALID_URL = rf'https?://(?:www\.)?bbc\.co\.uk/programmes/(?P{BBCCoUkIE._ID_REGEX})/(?:episodes|broadcasts|clips)'
_URL_TEMPLATE = 'http://www.bbc.co.uk/programmes/%s'
_VIDEO_ID_TEMPLATE = r'data-pid=["\'](%s)'
_TESTS = [{
diff --git a/yt_dlp/extractor/beatport.py b/yt_dlp/extractor/beatport.py
index 0aecbd089d..acc8d12595 100644
--- a/yt_dlp/extractor/beatport.py
+++ b/yt_dlp/extractor/beatport.py
@@ -1,7 +1,6 @@
import re
from .common import InfoExtractor
-from ..compat import compat_str
from ..utils import int_or_none
@@ -33,7 +32,7 @@ class BeatportIE(InfoExtractor):
'display_id': 'birds-original-mix',
'ext': 'mp4',
'title': "Tos, Middle Milk, Mumblin' Johnsson - Birds (Original Mix)",
- }
+ },
}]
def _real_extract(self, url):
@@ -51,7 +50,7 @@ def _real_extract(self, url):
track = next(t for t in playables['tracks'] if t['id'] == int(track_id))
- title = ', '.join((a['name'] for a in track['artists'])) + ' - ' + track['name']
+ title = ', '.join(a['name'] for a in track['artists']) + ' - ' + track['name']
if track['mix']:
title += ' (' + track['mix'] + ')'
@@ -89,7 +88,7 @@ def _real_extract(self, url):
images.append(image)
return {
- 'id': compat_str(track.get('id')) or track_id,
+ 'id': str(track.get('id')) or track_id,
'display_id': track.get('slug') or display_id,
'title': title,
'formats': formats,
diff --git a/yt_dlp/extractor/beeg.py b/yt_dlp/extractor/beeg.py
index da98ac3140..960cdfabdd 100644
--- a/yt_dlp/extractor/beeg.py
+++ b/yt_dlp/extractor/beeg.py
@@ -23,7 +23,7 @@ class BeegIE(InfoExtractor):
'upload_date': '20220131',
'timestamp': 1643656455,
'display_id': '2540839',
- }
+ },
}, {
'url': 'https://beeg.com/-0599050563103750?t=4-861',
'md5': 'bd8b5ea75134f7f07fad63008db2060e',
@@ -38,7 +38,7 @@ class BeegIE(InfoExtractor):
'timestamp': 1643623200,
'display_id': '2569965',
'upload_date': '20220131',
- }
+ },
}, {
# api/v6 v2
'url': 'https://beeg.com/1941093077?t=911-1391',
@@ -55,8 +55,8 @@ def _real_extract(self, url):
webpage = self._download_webpage(url, video_id)
video = self._download_json(
- 'https://store.externulls.com/facts/file/%s' % video_id,
- video_id, 'Downloading JSON for %s' % video_id)
+ f'https://store.externulls.com/facts/file/{video_id}',
+ video_id, f'Downloading JSON for {video_id}')
fc_facts = video.get('fc_facts')
first_fact = {}
diff --git a/yt_dlp/extractor/behindkink.py b/yt_dlp/extractor/behindkink.py
index 9d2324f4f4..45f45d03ba 100644
--- a/yt_dlp/extractor/behindkink.py
+++ b/yt_dlp/extractor/behindkink.py
@@ -16,7 +16,7 @@ class BehindKinkIE(InfoExtractor):
'upload_date': '20141205',
'thumbnail': 'http://www.behindkink.com/wp-content/uploads/2014/12/blaze-1.jpg',
'age_limit': 18,
- }
+ },
}
def _real_extract(self, url):
diff --git a/yt_dlp/extractor/bellmedia.py b/yt_dlp/extractor/bellmedia.py
index 677680b428..ac45dd4779 100644
--- a/yt_dlp/extractor/bellmedia.py
+++ b/yt_dlp/extractor/bellmedia.py
@@ -86,6 +86,6 @@ def _real_extract(self, url):
return {
'_type': 'url_transparent',
'id': video_id,
- 'url': '9c9media:%s_web:%s' % (self._DOMAINS.get(domain, domain), video_id),
+ 'url': f'9c9media:{self._DOMAINS.get(domain, domain)}_web:{video_id}',
'ie_key': 'NineCNineMedia',
}
diff --git a/yt_dlp/extractor/berufetv.py b/yt_dlp/extractor/berufetv.py
index 8160cbd9a7..5bba33a44c 100644
--- a/yt_dlp/extractor/berufetv.py
+++ b/yt_dlp/extractor/berufetv.py
@@ -16,7 +16,7 @@ class BerufeTVIE(InfoExtractor):
'tags': ['Studienfilm'],
'duration': 602.440,
'thumbnail': r're:^https://asset-out-cdn\.video-cdn\.net/private/videos/DvKC3DUpMKvUZ_6fEnfg3u/thumbnails/793063\?quality=thumbnail&__token__=[^\s]+$',
- }
+ },
}]
def _real_extract(self, url):
@@ -54,7 +54,7 @@ def _real_extract(self, url):
subtitles.setdefault(track['language'], []).append({
'url': track['source'],
'name': track.get('label'),
- 'ext': 'vtt'
+ 'ext': 'vtt',
})
return {
diff --git a/yt_dlp/extractor/bet.py b/yt_dlp/extractor/bet.py
index cbf3dd0824..3a8e743092 100644
--- a/yt_dlp/extractor/bet.py
+++ b/yt_dlp/extractor/bet.py
@@ -19,7 +19,7 @@ class BetIE(MTVServicesInfoExtractor):
'thumbnail': r're:(?i)^https?://.*\.jpg$',
'subtitles': {
'en': 'mincount:2',
- }
+ },
},
'params': {
# rtmp download
@@ -39,16 +39,16 @@ class BetIE(MTVServicesInfoExtractor):
'thumbnail': r're:(?i)^https?://.*\.jpg$',
'subtitles': {
'en': 'mincount:2',
- }
+ },
},
'params': {
# rtmp download
'skip_download': True,
},
- }
+ },
]
- _FEED_URL = "http://feeds.mtvnservices.com/od/feed/bet-mrss-player"
+ _FEED_URL = 'http://feeds.mtvnservices.com/od/feed/bet-mrss-player'
def _get_feed_query(self, uri):
return {
diff --git a/yt_dlp/extractor/bfmtv.py b/yt_dlp/extractor/bfmtv.py
index c4621ca826..87f011783b 100644
--- a/yt_dlp/extractor/bfmtv.py
+++ b/yt_dlp/extractor/bfmtv.py
@@ -98,8 +98,8 @@ class BFMTVArticleIE(BFMTVBaseIE):
'timestamp': 1673341692,
'duration': 109.269,
'tags': ['rmc', 'show', 'apolline de malherbe', 'info', 'talk', 'matinale', 'radio'],
- 'thumbnail': 'https://cf-images.eu-west-1.prod.boltdns.net/v1/static/876630703001/5bef74b8-9d5e-4480-a21f-60c2e2480c46/96c88b74-f9db-45e1-8040-e199c5da216c/1920x1080/match/image.jpg'
- }
+ 'thumbnail': 'https://cf-images.eu-west-1.prod.boltdns.net/v1/static/876630703001/5bef74b8-9d5e-4480-a21f-60c2e2480c46/96c88b74-f9db-45e1-8040-e199c5da216c/1920x1080/match/image.jpg',
+ },
}]
def _real_extract(self, url):
diff --git a/yt_dlp/extractor/bigflix.py b/yt_dlp/extractor/bigflix.py
index 02d1ba0e3f..9c55bb9682 100644
--- a/yt_dlp/extractor/bigflix.py
+++ b/yt_dlp/extractor/bigflix.py
@@ -1,10 +1,8 @@
+import base64
import re
+import urllib.parse
from .common import InfoExtractor
-from ..compat import (
- compat_b64decode,
- compat_urllib_parse_unquote,
-)
class BigflixIE(InfoExtractor):
@@ -21,7 +19,7 @@ class BigflixIE(InfoExtractor):
},
'params': {
'skip_download': True,
- }
+ },
}, {
# multiple formats
'url': 'http://www.bigflix.com/Malayalam-movies/Drama-movies/Indian-Rupee/15967',
@@ -38,7 +36,7 @@ def _real_extract(self, url):
webpage, 'title')
def decode_url(quoted_b64_url):
- return compat_b64decode(compat_urllib_parse_unquote(
+ return base64.b64decode(urllib.parse.unquote(
quoted_b64_url)).decode('utf-8')
formats = []
@@ -47,7 +45,7 @@ def decode_url(quoted_b64_url):
video_url = decode_url(encoded_url)
f = {
'url': video_url,
- 'format_id': '%sp' % height,
+ 'format_id': f'{height}p',
'height': int(height),
}
if video_url.startswith('rtmp'):
@@ -69,5 +67,5 @@ def decode_url(quoted_b64_url):
'id': video_id,
'title': title,
'description': description,
- 'formats': formats
+ 'formats': formats,
}
diff --git a/yt_dlp/extractor/bigo.py b/yt_dlp/extractor/bigo.py
index acf78e49a7..b1c230f357 100644
--- a/yt_dlp/extractor/bigo.py
+++ b/yt_dlp/extractor/bigo.py
@@ -36,7 +36,7 @@ def _real_extract(self, url):
raise ExtractorError('Received invalid JSON data')
if info_raw.get('code'):
raise ExtractorError(
- 'Bigo says: %s (code %s)' % (info_raw.get('msg'), info_raw.get('code')), expected=True)
+ 'Bigo says: {} (code {})'.format(info_raw.get('msg'), info_raw.get('code')), expected=True)
info = info_raw.get('data') or {}
if not info.get('alive'):
diff --git a/yt_dlp/extractor/bild.py b/yt_dlp/extractor/bild.py
index eb289329d8..2ba63700c6 100644
--- a/yt_dlp/extractor/bild.py
+++ b/yt_dlp/extractor/bild.py
@@ -20,7 +20,7 @@ class BildIE(InfoExtractor):
'description': 'md5:a4058c4fa2a804ab59c00d7244bbf62f',
'thumbnail': r're:^https?://.*\.jpg$',
'duration': 196,
- }
+ },
}, {
'note': 'static MP4 and HLS',
'url': 'https://www.bild.de/video/clip/news-ausland/deftiger-abgang-vom-10m-turm-bademeister-sorgt-fuer-skandal-85158620.bild.html',
@@ -32,7 +32,7 @@ class BildIE(InfoExtractor):
'description': 'md5:709b543c24dc31bbbffee73bccda34ad',
'thumbnail': r're:^https?://.*\.jpg$',
'duration': 69,
- }
+ },
}]
def _real_extract(self, url):
diff --git a/yt_dlp/extractor/bilibili.py b/yt_dlp/extractor/bilibili.py
index b38c90b1d1..411b48c282 100644
--- a/yt_dlp/extractor/bilibili.py
+++ b/yt_dlp/extractor/bilibili.py
@@ -112,7 +112,7 @@ def _get_subtitles(self, video_id, cid, aid=None):
'danmaku': [{
'ext': 'xml',
'url': f'https://comment.bilibili.com/{cid}.xml',
- }]
+ }],
}
subtitle_info = traverse_obj(self._download_json(
@@ -126,7 +126,7 @@ def _get_subtitles(self, video_id, cid, aid=None):
for s in subs_list:
subtitles.setdefault(s['lan'], []).append({
'ext': 'srt',
- 'data': self.json2srt(self._download_json(s['subtitle_url'], video_id))
+ 'data': self.json2srt(self._download_json(s['subtitle_url'], video_id)),
})
return subtitles
@@ -215,7 +215,7 @@ def _get_interactive_entries(self, video_id, cid, metainfo):
yield {
**metainfo,
'id': f'{video_id}_{cid}',
- 'title': f'{metainfo.get("title")} - {list(edges.values())[0].get("title")}',
+ 'title': f'{metainfo.get("title")} - {next(iter(edges.values())).get("title")}',
'formats': self.extract_formats(play_info),
'description': f'{json.dumps(edges, ensure_ascii=False)}\n{metainfo.get("description", "")}',
'duration': float_or_none(play_info.get('timelength'), scale=1000),
@@ -269,7 +269,7 @@ class BiliBiliIE(BilibiliBaseIE):
'url': 'https://www.bilibili.com/video/BV1bK411W797',
'info_dict': {
'id': 'BV1bK411W797',
- 'title': '物语中的人物是如何吐槽自己的OP的'
+ 'title': '物语中的人物是如何吐槽自己的OP的',
},
'playlist_count': 18,
'playlist': [{
@@ -288,8 +288,8 @@ class BiliBiliIE(BilibiliBaseIE):
'view_count': int,
'description': 'md5:e3c401cf7bc363118d1783dd74068a68',
'duration': 90.314,
- }
- }]
+ },
+ }],
}, {
'note': 'Specific page of Anthology',
'url': 'https://www.bilibili.com/video/BV1bK411W797?p=1',
@@ -308,7 +308,7 @@ class BiliBiliIE(BilibiliBaseIE):
'view_count': int,
'description': 'md5:e3c401cf7bc363118d1783dd74068a68',
'duration': 90.314,
- }
+ },
}, {
'note': 'video has subtitles',
'url': 'https://www.bilibili.com/video/BV12N4y1M7rh',
@@ -327,7 +327,7 @@ class BiliBiliIE(BilibiliBaseIE):
'view_count': int,
'like_count': int,
'thumbnail': r're:^https?://.*\.(jpg|jpeg|png)$',
- 'subtitles': 'count:2'
+ 'subtitles': 'count:2',
},
'params': {'listsubtitles': True},
}, {
@@ -586,10 +586,9 @@ def _real_extract(self, url):
is_interactive = traverse_obj(video_data, ('rights', 'is_stein_gate'))
if is_interactive:
return self.playlist_result(
- self._get_interactive_entries(video_id, cid, metainfo), **metainfo, **{
- 'duration': traverse_obj(initial_state, ('videoData', 'duration', {int_or_none})),
- '__post_extractor': self.extract_comments(aid),
- })
+ self._get_interactive_entries(video_id, cid, metainfo), **metainfo,
+ duration=traverse_obj(initial_state, ('videoData', 'duration', {int_or_none})),
+ __post_extractor=self.extract_comments(aid))
else:
return {
**metainfo,
@@ -640,7 +639,7 @@ class BiliBiliBangumiIE(BilibiliBaseIE):
'duration': 1425.256,
'timestamp': 1554566400,
'upload_date': '20190406',
- 'thumbnail': r're:^https?://.*\.(jpg|jpeg|png)$'
+ 'thumbnail': r're:^https?://.*\.(jpg|jpeg|png)$',
},
'skip': 'Geo-restricted',
}, {
@@ -661,7 +660,7 @@ class BiliBiliBangumiIE(BilibiliBaseIE):
'duration': 1922.129,
'timestamp': 1602853860,
'upload_date': '20201016',
- 'thumbnail': r're:^https?://.*\.(jpg|jpeg|png)$'
+ 'thumbnail': r're:^https?://.*\.(jpg|jpeg|png)$',
},
}]
@@ -764,7 +763,7 @@ class BiliBiliBangumiMediaIE(BilibiliBaseIE):
'duration': 1525.777,
'timestamp': 1425074413,
'upload_date': '20150227',
- 'thumbnail': r're:^https?://.*\.(jpg|jpeg|png)$'
+ 'thumbnail': r're:^https?://.*\.(jpg|jpeg|png)$',
},
}],
}]
@@ -794,7 +793,7 @@ class BiliBiliBangumiSeasonIE(BilibiliBaseIE):
'title': '鬼灭之刃',
'description': 'md5:e2cc9848b6f69be6db79fc2a82d9661b',
},
- 'playlist_mincount': 26
+ 'playlist_mincount': 26,
}, {
'url': 'https://www.bilibili.com/bangumi/play/ss2251',
'info_dict': {
@@ -819,7 +818,7 @@ class BiliBiliBangumiSeasonIE(BilibiliBaseIE):
'duration': 1436.992,
'timestamp': 1343185080,
'upload_date': '20120725',
- 'thumbnail': r're:^https?://.*\.(jpg|jpeg|png)$'
+ 'thumbnail': r're:^https?://.*\.(jpg|jpeg|png)$',
},
}],
}]
@@ -906,7 +905,7 @@ class BilibiliCheeseIE(BilibiliCheeseBaseIE):
'upload_date': '20230924',
'thumbnail': r're:^https?://.*\.(jpg|jpeg|png)$',
'view_count': int,
- }
+ },
}]
def _real_extract(self, url):
@@ -939,7 +938,7 @@ class BilibiliCheeseSeasonIE(BilibiliCheeseBaseIE):
'upload_date': '20230924',
'thumbnail': r're:^https?://.*\.(jpg|jpeg|png)$',
'view_count': int,
- }
+ },
}],
'params': {'playlist_items': '1'},
}, {
@@ -1012,7 +1011,7 @@ def _extract_signature(self, playlist_id):
for position in (
46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42, 19, 29, 28, 14, 39,
12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63,
- 57, 62, 11, 36, 20, 34, 44, 52
+ 57, 62, 11, 36, 20, 34, 44, 52,
):
char_at_position = try_call(lambda: session_key[position])
if char_at_position:
@@ -1163,7 +1162,7 @@ def get_metadata(page_data):
'uploader_id': ('meta', 'mid', {str_or_none}),
'timestamp': ('meta', 'ptime', {int_or_none}),
'thumbnail': ('meta', 'cover', {url_or_none}),
- })
+ }),
}
def get_entries(page_data):
@@ -1195,7 +1194,7 @@ def _real_extract(self, url):
mid, sid = self._match_valid_url(url).group('mid', 'sid')
playlist_id = f'{mid}_{sid}'
playlist_meta = traverse_obj(self._download_json(
- f'https://api.bilibili.com/x/series/series?series_id={sid}', playlist_id, fatal=False
+ f'https://api.bilibili.com/x/series/series?series_id={sid}', playlist_id, fatal=False,
), {
'title': ('data', 'meta', 'name', {str}),
'description': ('data', 'meta', 'description', {str}),
@@ -1217,7 +1216,7 @@ def get_metadata(page_data):
'page_count': math.ceil(entry_count / page_size),
'page_size': page_size,
'uploader': self._get_uploader(mid, playlist_id),
- **playlist_meta
+ **playlist_meta,
}
def get_entries(page_data):
@@ -1241,7 +1240,7 @@ class BilibiliFavoritesListIE(BilibiliSpaceListBaseIE):
'upload_date': '20201109',
'modified_timestamp': int,
'modified_date': str,
- 'thumbnail': r"re:http://i\d\.hdslb\.com/bfs/archive/14b83c62aa8871b79083df1e9ab4fbc699ad16fe\.jpg",
+ 'thumbnail': r're:http://i\d\.hdslb\.com/bfs/archive/14b83c62aa8871b79083df1e9ab4fbc699ad16fe\.jpg',
'view_count': int,
'like_count': int,
},
@@ -1345,7 +1344,7 @@ class BilibiliPlaylistIE(BilibiliSpaceListBaseIE):
'uploader_id': '84912',
'timestamp': 1604905176,
'upload_date': '20201109',
- 'thumbnail': r"re:http://i\d\.hdslb\.com/bfs/archive/14b83c62aa8871b79083df1e9ab4fbc699ad16fe\.jpg",
+ 'thumbnail': r're:http://i\d\.hdslb\.com/bfs/archive/14b83c62aa8871b79083df1e9ab4fbc699ad16fe\.jpg',
},
'playlist_mincount': 22,
}, {
@@ -1371,7 +1370,7 @@ def _extract_medialist(self, query, list_id):
for page_num in itertools.count(1):
page_data = self._download_json(
'https://api.bilibili.com/x/v2/medialist/resource/list',
- list_id, query=query, note=f'getting playlist {query["biz_id"]} page {page_num}'
+ list_id, query=query, note=f'getting playlist {query["biz_id"]} page {page_num}',
)['data']
yield from self._get_entries(page_data, 'media_list', ending_key='bv_id')
query['oid'] = traverse_obj(page_data, ('media_list', -1, 'id'))
@@ -1407,7 +1406,7 @@ def _real_extract(self, url):
'tid': ('tid', {int_or_none}),
'sort_field': ('sortFiled', {int_or_none}),
'desc': ('desc', {bool_or_none}, {str_or_none}, {str.lower}),
- })
+ }),
}
metadata = {
'id': f'{query["type"]}_{query["biz_id"]}',
@@ -1430,26 +1429,26 @@ class BilibiliCategoryIE(InfoExtractor):
'url': 'https://www.bilibili.com/v/kichiku/mad',
'info_dict': {
'id': 'kichiku: mad',
- 'title': 'kichiku: mad'
+ 'title': 'kichiku: mad',
},
'playlist_mincount': 45,
'params': {
- 'playlistend': 45
- }
+ 'playlistend': 45,
+ },
}]
def _fetch_page(self, api_url, num_pages, query, page_num):
parsed_json = self._download_json(
api_url, query, query={'Search_key': query, 'pn': page_num},
- note='Extracting results from page %s of %s' % (page_num, num_pages))
+ note=f'Extracting results from page {page_num} of {num_pages}')
video_list = traverse_obj(parsed_json, ('data', 'archives'), expected_type=list)
if not video_list:
- raise ExtractorError('Failed to retrieve video list for page %d' % page_num)
+ raise ExtractorError(f'Failed to retrieve video list for page {page_num}')
for video in video_list:
yield self.url_result(
- 'https://www.bilibili.com/video/%s' % video['bvid'], 'BiliBili', video['bvid'])
+ 'https://www.bilibili.com/video/{}'.format(video['bvid']), 'BiliBili', video['bvid'])
def _entries(self, category, subcategory, query):
# map of categories : subcategories : RIDs
@@ -1459,7 +1458,7 @@ def _entries(self, category, subcategory, query):
'manual_vocaloid': 126,
'guide': 22,
'theatre': 216,
- 'course': 127
+ 'course': 127,
},
}
@@ -1485,7 +1484,7 @@ def _entries(self, category, subcategory, query):
def _real_extract(self, url):
category, subcategory = urllib.parse.urlparse(url).path.split('/')[2:4]
- query = '%s: %s' % (category, subcategory)
+ query = f'{category}: {subcategory}'
return self.playlist_result(self._entries(category, subcategory, query), query, query)
@@ -1588,7 +1587,7 @@ def _real_extract(self, url):
formats = [{
'url': play_data['cdns'][0],
'filesize': int_or_none(play_data.get('size')),
- 'vcodec': 'none'
+ 'vcodec': 'none',
}]
for a_format in formats:
@@ -1606,7 +1605,7 @@ def _real_extract(self, url):
subtitles = {
'origin': [{
'url': lyric,
- }]
+ }],
}
return {
@@ -1674,7 +1673,7 @@ class BiliBiliPlayerIE(InfoExtractor):
def _real_extract(self, url):
video_id = self._match_id(url)
return self.url_result(
- 'http://www.bilibili.tv/video/av%s/' % video_id,
+ f'http://www.bilibili.tv/video/av{video_id}/',
ie=BiliBiliIE.ie_key(), video_id=video_id)
@@ -1702,11 +1701,10 @@ def _call_api(self, endpoint, *args, **kwargs):
return json.get('data')
def json2srt(self, json):
- data = '\n\n'.join(
+ return '\n\n'.join(
f'{i + 1}\n{srt_subtitles_timecode(line["from"])} --> {srt_subtitles_timecode(line["to"])}\n{line["content"]}'
for i, line in enumerate(traverse_obj(json, (
'body', lambda _, l: l['content'] and l['from'] and l['to']))))
- return data
def _get_subtitles(self, *, ep_id=None, aid=None):
sub_json = self._call_api(
@@ -1808,14 +1806,14 @@ def _perform_login(self, username, password):
note='Downloading login key', errnote='Unable to download login key')['data']
public_key = Cryptodome.RSA.importKey(key_data['key'])
- password_hash = Cryptodome.PKCS1_v1_5.new(public_key).encrypt((key_data['hash'] + password).encode('utf-8'))
+ password_hash = Cryptodome.PKCS1_v1_5.new(public_key).encrypt((key_data['hash'] + password).encode())
login_post = self._download_json(
'https://passport.bilibili.tv/x/intl/passport-login/web/login/password?lang=en-US', None, data=urlencode_postdata({
'username': username,
'password': base64.b64encode(password_hash).decode('ascii'),
'keep_me': 'true',
's_locale': 'en_US',
- 'isTrusted': 'true'
+ 'isTrusted': 'true',
}), note='Logging in', errnote='Unable to log in')
if login_post.get('code'):
if login_post.get('message'):
@@ -1842,17 +1840,17 @@ class BiliIntlIE(BiliIntlBaseIE):
'chapters': [{
'start_time': 0,
'end_time': 76.242,
- 'title': ''
+ 'title': '',
}, {
'start_time': 76.242,
'end_time': 161.161,
- 'title': 'Intro'
+ 'title': 'Intro',
}, {
'start_time': 1325.742,
'end_time': 1403.903,
- 'title': 'Outro'
+ 'title': 'Outro',
}],
- }
+ },
}, {
# Non-Bstation page
'url': 'https://www.bilibili.tv/en/play/1033760/11005006',
@@ -1869,17 +1867,17 @@ class BiliIntlIE(BiliIntlBaseIE):
'chapters': [{
'start_time': 0,
'end_time': 88.0,
- 'title': ''
+ 'title': '',
}, {
'start_time': 88.0,
'end_time': 156.0,
- 'title': 'Intro'
+ 'title': 'Intro',
}, {
'start_time': 1173.0,
'end_time': 1259.535,
- 'title': 'Outro'
+ 'title': 'Outro',
}],
- }
+ },
}, {
# Subtitle with empty content
'url': 'https://www.bilibili.tv/en/play/1005144/10131790',
@@ -1890,7 +1888,7 @@ class BiliIntlIE(BiliIntlBaseIE):
'thumbnail': r're:^https://pic\.bstarstatic\.com/ogv/.+\.png$',
'episode_number': 140,
},
- 'skip': 'According to the copyright owner\'s request, you may only watch the video after you log in.'
+ 'skip': 'According to the copyright owner\'s request, you may only watch the video after you log in.',
}, {
# episode comment extraction
'url': 'https://www.bilibili.tv/en/play/34580/340317',
@@ -1908,20 +1906,20 @@ class BiliIntlIE(BiliIntlBaseIE):
'chapters': [{
'start_time': 0,
'end_time': 61.0,
- 'title': ''
+ 'title': '',
}, {
'start_time': 61.0,
'end_time': 134.0,
- 'title': 'Intro'
+ 'title': 'Intro',
}, {
'start_time': 1290.0,
'end_time': 1379.0,
- 'title': 'Outro'
+ 'title': 'Outro',
}],
},
'params': {
- 'getcomments': True
- }
+ 'getcomments': True,
+ },
}, {
# user generated content comment extraction
'url': 'https://www.bilibili.tv/en/video/2045730385',
@@ -1936,8 +1934,8 @@ class BiliIntlIE(BiliIntlBaseIE):
'thumbnail': r're:https://pic\.bstarstatic\.(?:com|net)/ugc/f6c363659efd2eabe5683fbb906b1582\.jpg',
},
'params': {
- 'getcomments': True
- }
+ 'getcomments': True,
+ },
}, {
# episode id without intro and outro
'url': 'https://www.bilibili.tv/en/play/1048837/11246489',
@@ -1992,7 +1990,7 @@ def _extract_video_metadata(self, url, video_id, season_id):
# Non-Bstation layout, read through episode list
season_json = self._call_api(f'/web/v2/ogv/play/episodes?season_id={season_id}&platform=web', video_id)
video_data = traverse_obj(season_json, (
- 'sections', ..., 'episodes', lambda _, v: str(v['episode_id']) == video_id
+ 'sections', ..., 'episodes', lambda _, v: str(v['episode_id']) == video_id,
), expected_type=dict, get_all=False)
# XXX: webpage metadata may not accurate, it just used to not crash when video_data not found
@@ -2024,7 +2022,7 @@ def _get_comments_reply(self, root_id, next_id=0, display_id=None):
'id': replies.get('rpid'),
'like_count': int_or_none(replies.get('like_count')),
'parent': replies.get('parent'),
- 'timestamp': unified_timestamp(replies.get('ctime_text'))
+ 'timestamp': unified_timestamp(replies.get('ctime_text')),
}
if not traverse_obj(comment_api_raw_data, ('data', 'cursor', 'is_end')):
@@ -2077,11 +2075,11 @@ def _real_extract(self, url):
chapters = [{
'start_time': float_or_none(traverse_obj(intro_ending_json, ('skip', 'opening_start_time')), 1000),
'end_time': float_or_none(traverse_obj(intro_ending_json, ('skip', 'opening_end_time')), 1000),
- 'title': 'Intro'
+ 'title': 'Intro',
}, {
'start_time': float_or_none(traverse_obj(intro_ending_json, ('skip', 'ending_start_time')), 1000),
'end_time': float_or_none(traverse_obj(intro_ending_json, ('skip', 'ending_end_time')), 1000),
- 'title': 'Outro'
+ 'title': 'Outro',
}]
return {
@@ -2137,7 +2135,7 @@ def _entries(self, series_id):
episode_id = str(episode['episode_id'])
yield self.url_result(smuggle_url(
BiliIntlIE._make_url(episode_id, series_id),
- self._parse_video_metadata(episode)
+ self._parse_video_metadata(episode),
), BiliIntlIE, episode_id)
def _real_extract(self, url):
@@ -2156,19 +2154,19 @@ class BiliLiveIE(InfoExtractor):
'url': 'https://live.bilibili.com/196',
'info_dict': {
'id': '33989',
- 'description': "周六杂谈回,其他时候随机游戏。 | \n录播:@下播型泛式录播组。 | \n直播通知群(全员禁言):666906670,902092584,59971⑧481 (功能一样,别多加)",
+ 'description': '周六杂谈回,其他时候随机游戏。 | \n录播:@下播型泛式录播组。 | \n直播通知群(全员禁言):666906670,902092584,59971⑧481 (功能一样,别多加)',
'ext': 'flv',
- 'title': "太空狼人杀联动,不被爆杀就算赢",
- 'thumbnail': "https://i0.hdslb.com/bfs/live/new_room_cover/e607bc1529057ef4b332e1026e62cf46984c314d.jpg",
+ 'title': '太空狼人杀联动,不被爆杀就算赢',
+ 'thumbnail': 'https://i0.hdslb.com/bfs/live/new_room_cover/e607bc1529057ef4b332e1026e62cf46984c314d.jpg',
'timestamp': 1650802769,
},
- 'skip': 'not live'
+ 'skip': 'not live',
}, {
'url': 'https://live.bilibili.com/196?broadcast_type=0&is_room_feed=1?spm_id_from=333.999.space_home.strengthen_live_card.click',
- 'only_matching': True
+ 'only_matching': True,
}, {
'url': 'https://live.bilibili.com/blanc/196',
- 'only_matching': True
+ 'only_matching': True,
}]
_FORMATS = {
@@ -2209,7 +2207,7 @@ def _real_extract(self, url):
raise ExtractorError('Streamer is not live', expected=True)
formats = []
- for qn in self._FORMATS.keys():
+ for qn in self._FORMATS:
stream_data = self._call_api('xlive/web-room/v2/index/getRoomPlayInfo', room_id, {
'room_id': room_id,
'qn': qn,
diff --git a/yt_dlp/extractor/bitchute.py b/yt_dlp/extractor/bitchute.py
index 194bf1f468..c74f34c2a9 100644
--- a/yt_dlp/extractor/bitchute.py
+++ b/yt_dlp/extractor/bitchute.py
@@ -39,7 +39,7 @@ class BitChuteIE(InfoExtractor):
'upload_date': '20170103',
'uploader_url': 'https://www.bitchute.com/profile/I5NgtHZn9vPj/',
'channel': 'BitChute',
- 'channel_url': 'https://www.bitchute.com/channel/bitchute/'
+ 'channel_url': 'https://www.bitchute.com/channel/bitchute/',
},
}, {
# test case: video with different channel and uploader
@@ -55,7 +55,7 @@ class BitChuteIE(InfoExtractor):
'upload_date': '20231106',
'uploader_url': 'https://www.bitchute.com/profile/9K0kUWA9zmd9/',
'channel': 'Full Measure with Sharyl Attkisson',
- 'channel_url': 'https://www.bitchute.com/channel/sharylattkisson/'
+ 'channel_url': 'https://www.bitchute.com/channel/sharylattkisson/',
},
}, {
# video not downloadable in browser, but we can recover it
@@ -72,7 +72,7 @@ class BitChuteIE(InfoExtractor):
'upload_date': '20181113',
'uploader_url': 'https://www.bitchute.com/profile/I5NgtHZn9vPj/',
'channel': 'BitChute',
- 'channel_url': 'https://www.bitchute.com/channel/bitchute/'
+ 'channel_url': 'https://www.bitchute.com/channel/bitchute/',
},
'params': {'check_formats': None},
}, {
@@ -115,7 +115,7 @@ def _check_format(self, video_url, video_id):
continue
return {
'url': url,
- 'filesize': int_or_none(response.headers.get('Content-Length'))
+ 'filesize': int_or_none(response.headers.get('Content-Length')),
}
def _raise_if_restricted(self, webpage):
@@ -196,7 +196,7 @@ class BitChuteChannelIE(InfoExtractor):
'duration': 16,
'view_count': int,
},
- }
+ },
],
'params': {
'skip_download': True,
@@ -209,7 +209,7 @@ class BitChuteChannelIE(InfoExtractor):
'id': 'wV9Imujxasw9',
'title': 'Bruce MacDonald and "The Light of Darkness"',
'description': 'md5:747724ef404eebdfc04277714f81863e',
- }
+ },
}]
_TOKEN = 'zyG6tQcGPE5swyAEFLqKUwMuMMuF6IO2DZ6ZDQjGfsL0e4dcTLwqkTTul05Jdve7'
@@ -224,7 +224,7 @@ class BitChuteChannelIE(InfoExtractor):
'container': 'playlist-video',
'title': 'title',
'description': 'description',
- }
+ },
}
diff --git a/yt_dlp/extractor/blackboardcollaborate.py b/yt_dlp/extractor/blackboardcollaborate.py
index 8f41c897ad..535890979b 100644
--- a/yt_dlp/extractor/blackboardcollaborate.py
+++ b/yt_dlp/extractor/blackboardcollaborate.py
@@ -47,7 +47,7 @@ def _real_extract(self, url):
region = mobj.group('region')
video_id = mobj.group('id')
info = self._download_json(
- 'https://{}.bbcollab.com/collab/api/csa/recordings/{}/data'.format(region, video_id), video_id)
+ f'https://{region}.bbcollab.com/collab/api/csa/recordings/{video_id}/data', video_id)
duration = info.get('duration')
title = info['name']
upload_date = info.get('created')
diff --git a/yt_dlp/extractor/bleacherreport.py b/yt_dlp/extractor/bleacherreport.py
index aa3d63ee7b..71b237d4b2 100644
--- a/yt_dlp/extractor/bleacherreport.py
+++ b/yt_dlp/extractor/bleacherreport.py
@@ -44,7 +44,7 @@ class BleacherReportIE(InfoExtractor):
def _real_extract(self, url):
article_id = self._match_id(url)
- article_data = self._download_json('http://api.bleacherreport.com/api/v1/articles/%s' % article_id, article_id)['article']
+ article_data = self._download_json(f'http://api.bleacherreport.com/api/v1/articles/{article_id}', article_id)['article']
thumbnails = []
primary_photo = article_data.get('primaryPhoto')
@@ -71,11 +71,11 @@ def _real_extract(self, url):
if video:
video_type = video['type']
if video_type in ('cms.bleacherreport.com', 'vid.bleacherreport.com'):
- info['url'] = 'http://bleacherreport.com/video_embed?id=%s' % video['id']
+ info['url'] = 'http://bleacherreport.com/video_embed?id={}'.format(video['id'])
elif video_type == 'youtube.com':
info['url'] = video['id']
elif video_type == 'vine.co':
- info['url'] = 'https://vine.co/v/%s' % video['id']
+ info['url'] = 'https://vine.co/v/{}'.format(video['id'])
else:
info['url'] = video_type + video['id']
return info
@@ -99,12 +99,12 @@ class BleacherReportCMSIE(AMPIE):
},
'expected_warnings': [
- 'Unable to download f4m manifest'
- ]
+ 'Unable to download f4m manifest',
+ ],
}]
def _real_extract(self, url):
video_id = self._match_id(url)
- info = self._extract_feed_info('http://vid.bleacherreport.com/videos/%s.akamai' % video_id)
+ info = self._extract_feed_info(f'http://vid.bleacherreport.com/videos/{video_id}.akamai')
info['id'] = video_id
return info
diff --git a/yt_dlp/extractor/blerp.py b/yt_dlp/extractor/blerp.py
index 4631ad2e97..f4f22488e9 100644
--- a/yt_dlp/extractor/blerp.py
+++ b/yt_dlp/extractor/blerp.py
@@ -16,7 +16,7 @@ class BlerpIE(InfoExtractor):
'uploader_id': '5fb81e51aa66ae000c395478',
'ext': 'mp3',
'tags': ['samsung', 'galaxy', 's8', 'over the horizon', '2016', 'ringtone'],
- }
+ },
}, {
'url': 'https://blerp.com/soundbites/5bc94ef4796001000498429f',
'info_dict': {
@@ -25,11 +25,11 @@ class BlerpIE(InfoExtractor):
'uploader': '179617322678353920',
'uploader_id': '5ba99cf71386730004552c42',
'ext': 'mp3',
- 'tags': ['YEE', 'YEET', 'wo ha haah catchy tune yee', 'yee']
- }
+ 'tags': ['YEE', 'YEET', 'wo ha haah catchy tune yee', 'yee'],
+ },
}]
- _GRAPHQL_OPERATIONNAME = "webBitePageGetBite"
+ _GRAPHQL_OPERATIONNAME = 'webBitePageGetBite'
_GRAPHQL_QUERY = (
'''query webBitePageGetBite($_id: MongoID!) {
web {
@@ -141,27 +141,26 @@ def _real_extract(self, url):
'operationName': self._GRAPHQL_OPERATIONNAME,
'query': self._GRAPHQL_QUERY,
'variables': {
- '_id': audio_id
- }
+ '_id': audio_id,
+ },
}
headers = {
- 'Content-Type': 'application/json'
+ 'Content-Type': 'application/json',
}
- json_result = self._download_json('https://api.blerp.com/graphql',
- audio_id, data=json.dumps(data).encode('utf-8'), headers=headers)
+ json_result = self._download_json(
+ 'https://api.blerp.com/graphql', audio_id,
+ data=json.dumps(data).encode(), headers=headers)
bite_json = json_result['data']['web']['biteById']
- info_dict = {
+ return {
'id': bite_json['_id'],
'url': bite_json['audio']['mp3']['url'],
'title': bite_json['title'],
'uploader': traverse_obj(bite_json, ('ownerObject', 'username'), expected_type=strip_or_none),
'uploader_id': traverse_obj(bite_json, ('ownerObject', '_id'), expected_type=strip_or_none),
'ext': 'mp3',
- 'tags': list(filter(None, map(strip_or_none, (traverse_obj(bite_json, 'userKeywords', expected_type=list) or []))) or None)
+ 'tags': list(filter(None, map(strip_or_none, (traverse_obj(bite_json, 'userKeywords', expected_type=list) or []))) or None),
}
-
- return info_dict
diff --git a/yt_dlp/extractor/blogger.py b/yt_dlp/extractor/blogger.py
index ef0151de67..1614b6f947 100644
--- a/yt_dlp/extractor/blogger.py
+++ b/yt_dlp/extractor/blogger.py
@@ -21,14 +21,14 @@ class BloggerIE(InfoExtractor):
'ext': 'mp4',
'thumbnail': r're:^https?://.*',
'duration': 76.068,
- }
+ },
}]
def _real_extract(self, url):
token_id = self._match_id(url)
webpage = self._download_webpage(url, token_id)
data_json = self._search_regex(r'var\s+VIDEO_CONFIG\s*=\s*(\{.*)', webpage, 'JSON data')
- data = self._parse_json(data_json.encode('utf-8').decode('unicode_escape'), token_id)
+ data = self._parse_json(data_json.encode().decode('unicode_escape'), token_id)
streams = data['streams']
formats = [{
'ext': mimetype2ext(traverse_obj(parse_qs(stream['play_url']), ('mime', 0))),
diff --git a/yt_dlp/extractor/bloomberg.py b/yt_dlp/extractor/bloomberg.py
index 792155e51a..ec6b7a86eb 100644
--- a/yt_dlp/extractor/bloomberg.py
+++ b/yt_dlp/extractor/bloomberg.py
@@ -55,7 +55,7 @@ def _real_extract(self, url):
title = re.sub(': Video$', '', self._og_search_title(webpage))
embed_info = self._download_json(
- 'http://www.bloomberg.com/multimedia/api/embed?id=%s' % video_id, video_id)
+ f'http://www.bloomberg.com/multimedia/api/embed?id={video_id}', video_id)
formats = []
for stream in embed_info['streams']:
stream_url = stream.get('url')
diff --git a/yt_dlp/extractor/bokecc.py b/yt_dlp/extractor/bokecc.py
index ca326f25fa..5fe937a6ac 100644
--- a/yt_dlp/extractor/bokecc.py
+++ b/yt_dlp/extractor/bokecc.py
@@ -1,5 +1,6 @@
+import urllib.parse
+
from .common import InfoExtractor
-from ..compat import compat_parse_qs
from ..utils import ExtractorError
@@ -9,20 +10,18 @@ def _extract_bokecc_formats(self, webpage, video_id, format_id=None):
r'<(?:script|embed)[^>]+src=(?P["\'])(?:https?:)?//p\.bokecc\.com/(?:player|flash/player\.swf)\?(?P.+?)(?P=q)',
webpage, 'player params', group='query')
- player_params = compat_parse_qs(player_params_str)
+ player_params = urllib.parse.parse_qs(player_params_str)
info_xml = self._download_xml(
- 'http://p.bokecc.com/servlet/playinfo?uid=%s&vid=%s&m=1' % (
+ 'http://p.bokecc.com/servlet/playinfo?uid={}&vid={}&m=1'.format(
player_params['siteid'][0], player_params['vid'][0]), video_id)
- formats = [{
+ return [{
'format_id': format_id,
'url': quality.find('./copy').attrib['playurl'],
'quality': int(quality.attrib['value']),
} for quality in info_xml.findall('./video/quality')]
- return formats
-
class BokeCCIE(BokeCCBaseIE):
_IE_DESC = 'CC视频'
@@ -38,11 +37,11 @@ class BokeCCIE(BokeCCBaseIE):
}]
def _real_extract(self, url):
- qs = compat_parse_qs(self._match_valid_url(url).group('query'))
+ qs = urllib.parse.parse_qs(self._match_valid_url(url).group('query'))
if not qs.get('vid') or not qs.get('uid'):
raise ExtractorError('Invalid URL', expected=True)
- video_id = '%s_%s' % (qs['uid'][0], qs['vid'][0])
+ video_id = '{}_{}'.format(qs['uid'][0], qs['vid'][0])
webpage = self._download_webpage(url, video_id)
diff --git a/yt_dlp/extractor/bongacams.py b/yt_dlp/extractor/bongacams.py
index bf955668df..ab85477de4 100644
--- a/yt_dlp/extractor/bongacams.py
+++ b/yt_dlp/extractor/bongacams.py
@@ -1,5 +1,4 @@
from .common import InfoExtractor
-from ..compat import compat_str
from ..utils import (
int_or_none,
try_get,
@@ -38,7 +37,7 @@ def _real_extract(self, url):
channel_id = mobj.group('id')
amf = self._download_json(
- 'https://%s/tools/amf.php' % host, channel_id,
+ f'https://{host}/tools/amf.php', channel_id,
data=urlencode_postdata((
('method', 'getRoomData'),
('args[]', channel_id),
@@ -48,14 +47,14 @@ def _real_extract(self, url):
server_url = amf['localData']['videoServerUrl']
uploader_id = try_get(
- amf, lambda x: x['performerData']['username'], compat_str) or channel_id
+ amf, lambda x: x['performerData']['username'], str) or channel_id
uploader = try_get(
- amf, lambda x: x['performerData']['displayName'], compat_str)
+ amf, lambda x: x['performerData']['displayName'], str)
like_count = int_or_none(try_get(
amf, lambda x: x['performerData']['loversCount']))
formats = self._extract_m3u8_formats(
- '%s/hls/stream_%s/playlist.m3u8' % (server_url, uploader_id),
+ f'{server_url}/hls/stream_{uploader_id}/playlist.m3u8',
channel_id, 'mp4', m3u8_id='hls', live=True)
return {
diff --git a/yt_dlp/extractor/bostonglobe.py b/yt_dlp/extractor/bostonglobe.py
index 2675866872..f5b8196788 100644
--- a/yt_dlp/extractor/bostonglobe.py
+++ b/yt_dlp/extractor/bostonglobe.py
@@ -57,8 +57,7 @@ def _real_extract(self, url):
if video_id and account_id and player_id and embed:
entries.append(
- 'http://players.brightcove.net/%s/%s_%s/index.html?videoId=%s'
- % (account_id, player_id, embed, video_id))
+ f'http://players.brightcove.net/{account_id}/{player_id}_{embed}/index.html?videoId={video_id}')
if len(entries) == 0:
return self.url_result(url, 'Generic')
diff --git a/yt_dlp/extractor/box.py b/yt_dlp/extractor/box.py
index 008c011cc8..3547ad9973 100644
--- a/yt_dlp/extractor/box.py
+++ b/yt_dlp/extractor/box.py
@@ -72,20 +72,20 @@ def _real_extract(self, url):
'BoxApi': 'shared_link=' + shared_link,
'X-Rep-Hints': '[dash]', # TODO: extract `hls` formats
}, query={
- 'fields': 'authenticated_download_url,created_at,created_by,description,extension,is_download_available,name,representations,size'
+ 'fields': 'authenticated_download_url,created_at,created_by,description,extension,is_download_available,name,representations,size',
})
title = f['name']
query = {
'access_token': access_token,
- 'shared_link': shared_link
+ 'shared_link': shared_link,
}
formats = []
for url_tmpl in traverse_obj(f, (
'representations', 'entries', lambda _, v: v['representation'] == 'dash',
- 'content', 'url_template', {url_or_none}
+ 'content', 'url_template', {url_or_none},
)):
manifest_url = update_url_query(url_tmpl.replace('{+asset_path}', 'manifest.mpd'), query)
fmts = self._extract_mpd_formats(manifest_url, file_id)
diff --git a/yt_dlp/extractor/boxcast.py b/yt_dlp/extractor/boxcast.py
index da06cc3f86..efa66994aa 100644
--- a/yt_dlp/extractor/boxcast.py
+++ b/yt_dlp/extractor/boxcast.py
@@ -21,7 +21,7 @@ class BoxCastVideoIE(InfoExtractor):
'release_date': '20221210',
'uploader_id': 're8w0v8hohhvpqtbskpe',
'uploader': 'Children\'s Health Defense',
- }
+ },
}, {
'url': 'https://boxcast.tv/video-portal/vctwevwntun3o0ikq7af/rvyblnn0fxbfjx5nwxhl/otbpltj2kzkveo2qz3ad',
'info_dict': {
@@ -30,8 +30,8 @@ class BoxCastVideoIE(InfoExtractor):
'uploader_id': 'vctwevwntun3o0ikq7af',
'uploader': 'Legacy Christian Church',
'title': 'The Quest | 1: Beginner\'s Bay | Jamie Schools',
- 'thumbnail': r're:https?://uploads.boxcast.com/(?:[\w-]+/){3}.+\.jpg'
- }
+ 'thumbnail': r're:https?://uploads.boxcast.com/(?:[\w-]+/){3}.+\.jpg',
+ },
}, {
'url': 'https://boxcast.tv/channel/z03fqwaeaby5lnaawox2?b=ssihlw5gvfij2by8tkev',
'info_dict': {
@@ -44,7 +44,7 @@ class BoxCastVideoIE(InfoExtractor):
'uploader': 'Lighthouse Ministries International - Beltsville, Maryland',
'description': 'md5:ac23e3d01b0b0be592e8f7fe0ec3a340',
'title': 'New Year\'s Eve CROSSOVER Service at LHMI | December 31, 2022',
- }
+ },
}]
_WEBPAGE_TESTS = [{
'url': 'https://childrenshealthdefense.eu/live-stream/',
@@ -57,7 +57,7 @@ class BoxCastVideoIE(InfoExtractor):
'release_date': '20221210',
'uploader_id': 're8w0v8hohhvpqtbskpe',
'uploader': 'Children\'s Health Defense',
- }
+ },
}]
def _real_extract(self, url):
diff --git a/yt_dlp/extractor/br.py b/yt_dlp/extractor/br.py
index 6e1c63e2bb..0568e06f68 100644
--- a/yt_dlp/extractor/br.py
+++ b/yt_dlp/extractor/br.py
@@ -61,7 +61,7 @@ class BRIE(InfoExtractor):
'title': 'Umweltbewusster Häuslebauer',
'description': 'md5:d52dae9792d00226348c1dbb13c9bae2',
'duration': 116,
- }
+ },
},
{
'url': 'http://www.br.de/fernsehen/br-alpha/sendungen/kant-fuer-anfaenger/kritik-der-reinen-vernunft/kant-kritik-01-metaphysik100.html',
@@ -74,7 +74,7 @@ class BRIE(InfoExtractor):
'duration': 893,
'uploader': 'Eva Maria Steimle',
'upload_date': '20170208',
- }
+ },
},
]
@@ -142,7 +142,7 @@ def _extract_formats(self, assets, media_id):
http_format_info = format_info.copy()
http_format_info.update({
'url': format_url,
- 'format_id': 'http-%s' % asset_type,
+ 'format_id': f'http-{asset_type}',
})
formats.append(http_format_info)
server_prefix = xpath_text(asset, 'serverPrefix')
@@ -151,7 +151,7 @@ def _extract_formats(self, assets, media_id):
rtmp_format_info.update({
'url': server_prefix,
'play_path': xpath_text(asset, 'fileName'),
- 'format_id': 'rtmp-%s' % asset_type,
+ 'format_id': f'rtmp-{asset_type}',
})
formats.append(rtmp_format_info)
return formats
diff --git a/yt_dlp/extractor/brainpop.py b/yt_dlp/extractor/brainpop.py
index 04b1dd80c8..df10299a0c 100644
--- a/yt_dlp/extractor/brainpop.py
+++ b/yt_dlp/extractor/brainpop.py
@@ -52,8 +52,8 @@ def _extract_adaptive_formats(self, data, token, display_id, key_format='%s', ex
'%s': {},
'ad_%s': {
'format_note': 'Audio description',
- 'source_preference': -2
- }
+ 'source_preference': -2,
+ },
}
for additional_key_format, additional_key_fields in additional_key_formats.items():
for key_quality, key_index in enumerate(('high', 'low')):
@@ -62,7 +62,7 @@ def _extract_adaptive_formats(self, data, token, display_id, key_format='%s', ex
formats.extend(self._assemble_formats(data[full_key_index], full_key_index, display_id, token, {
'quality': -1 - key_quality,
**additional_key_fields,
- **extra_fields
+ **extra_fields,
}))
return formats
@@ -72,7 +72,7 @@ def _perform_login(self, username, password):
data=json.dumps({'username': username, 'password': password}).encode(),
headers={
'Content-Type': 'application/json',
- 'Referer': self._ORIGIN
+ 'Referer': self._ORIGIN,
}, note='Logging in', errnote='Unable to log in', expected_status=400)
status_code = int_or_none(login_res['status_code'])
if status_code != 1505:
@@ -131,12 +131,12 @@ def _real_extract(self, url):
formats, subtitles = [], {}
formats.extend(self._extract_adaptive_formats(movie_feature_data, movie_feature_data.get('token', ''), display_id, '%s_v2', {
'language': movie_feature.get('language') or 'en',
- 'language_preference': 10
+ 'language_preference': 10,
}))
for lang, localized_feature in traverse_obj(movie_feature, 'localization', default={}, expected_type=dict).items():
formats.extend(self._extract_adaptive_formats(localized_feature, localized_feature.get('token', ''), display_id, '%s_v2', {
'language': lang,
- 'language_preference': -10
+ 'language_preference': -10,
}))
# TODO: Do localization fields also have subtitles?
@@ -145,7 +145,7 @@ def _real_extract(self, url):
r'^subtitles_(?P\w+)$', name, 'subtitle metadata', default=None)
if lang and url:
subtitles.setdefault(lang, []).append({
- 'url': urljoin(self._CDN_URL, url)
+ 'url': urljoin(self._CDN_URL, url),
})
return {
diff --git a/yt_dlp/extractor/bravotv.py b/yt_dlp/extractor/bravotv.py
index 419fe8c9c8..ec72f0d884 100644
--- a/yt_dlp/extractor/bravotv.py
+++ b/yt_dlp/extractor/bravotv.py
@@ -185,5 +185,5 @@ def _real_extract(self, url):
'episode_number': ('episodeNumber', {int_or_none}),
'episode': 'episodeTitle',
'series': 'show',
- }))
+ })),
}
diff --git a/yt_dlp/extractor/breitbart.py b/yt_dlp/extractor/breitbart.py
index b5abb7f194..fedf4772a9 100644
--- a/yt_dlp/extractor/breitbart.py
+++ b/yt_dlp/extractor/breitbart.py
@@ -13,7 +13,7 @@ class BreitBartIE(InfoExtractor):
'description': 'md5:bac35eb0256d1cb17f517f54c79404d5',
'thumbnail': 'https://cdn.jwplayer.com/thumbs/5cOz1yup-1920.jpg',
'age_limit': 0,
- }
+ },
}, {
'url': 'https://www.breitbart.com/videos/v/eaiZjVOn/',
'only_matching': True,
@@ -30,5 +30,5 @@ def _real_extract(self, url):
'description': self._og_search_description(webpage),
'thumbnail': self._og_search_thumbnail(webpage),
'age_limit': self._rta_search(webpage),
- 'formats': formats
+ 'formats': formats,
}
diff --git a/yt_dlp/extractor/brightcove.py b/yt_dlp/extractor/brightcove.py
index 4190e1a099..dc0c83572a 100644
--- a/yt_dlp/extractor/brightcove.py
+++ b/yt_dlp/extractor/brightcove.py
@@ -1,15 +1,12 @@
import base64
import re
import struct
+import urllib.parse
import xml.etree.ElementTree
from .adobepass import AdobePassIE
from .common import InfoExtractor
-from ..compat import (
- compat_etree_fromstring,
- compat_parse_qs,
- compat_urlparse,
-)
+from ..compat import compat_etree_fromstring
from ..networking.exceptions import HTTPError
from ..utils import (
ExtractorError,
@@ -142,7 +139,7 @@ class BrightcoveLegacyIE(InfoExtractor):
# from http://www.un.org/chinese/News/story.asp?NewsID=27724
'url': 'https://link.brightcove.com/services/player/bcpid1722935254001/?bctid=5360463607001&autoStart=false&secureConnections=true&width=650&height=350',
'only_matching': True, # Tested in GenericIE
- }
+ },
]
_WEBPAGE_TESTS = [{
@@ -315,7 +312,7 @@ def _build_brightcove_url(cls, object_str):
object_str = fix_xml_ampersands(object_str)
try:
- object_doc = compat_etree_fromstring(object_str.encode('utf-8'))
+ object_doc = compat_etree_fromstring(object_str.encode())
except xml.etree.ElementTree.ParseError:
return
@@ -323,7 +320,7 @@ def _build_brightcove_url(cls, object_str):
if fv_el is not None:
flashvars = dict(
(k, v[0])
- for k, v in compat_parse_qs(fv_el.attrib['value']).items())
+ for k, v in urllib.parse.parse_qs(fv_el.attrib['value']).items())
else:
flashvars = {}
@@ -340,32 +337,32 @@ def find_param(name):
params = {}
- playerID = find_param('playerID') or find_param('playerId')
- if playerID is None:
+ player_id = find_param('playerID') or find_param('playerId')
+ if player_id is None:
raise ExtractorError('Cannot find player ID')
- params['playerID'] = playerID
+ params['playerID'] = player_id
- playerKey = find_param('playerKey')
+ player_key = find_param('playerKey')
# Not all pages define this value
- if playerKey is not None:
- params['playerKey'] = playerKey
+ if player_key is not None:
+ params['playerKey'] = player_key
# These fields hold the id of the video
- videoPlayer = find_param('@videoPlayer') or find_param('videoId') or find_param('videoID') or find_param('@videoList')
- if videoPlayer is not None:
- if isinstance(videoPlayer, list):
- videoPlayer = videoPlayer[0]
- videoPlayer = videoPlayer.strip()
+ video_player = find_param('@videoPlayer') or find_param('videoId') or find_param('videoID') or find_param('@videoList')
+ if video_player is not None:
+ if isinstance(video_player, list):
+ video_player = video_player[0]
+ video_player = video_player.strip()
# UUID is also possible for videoPlayer (e.g.
# http://www.popcornflix.com/hoodies-vs-hooligans/7f2d2b87-bbf2-4623-acfb-ea942b4f01dd
# or http://www8.hp.com/cn/zh/home.html)
if not (re.match(
r'^(?:\d+|[\da-fA-F]{8}-?[\da-fA-F]{4}-?[\da-fA-F]{4}-?[\da-fA-F]{4}-?[\da-fA-F]{12})$',
- videoPlayer) or videoPlayer.startswith('ref:')):
+ video_player) or video_player.startswith('ref:')):
return None
- params['@videoPlayer'] = videoPlayer
- linkBase = find_param('linkBaseURL')
- if linkBase is not None:
- params['linkBaseURL'] = linkBase
+ params['@videoPlayer'] = video_player
+ link_base = find_param('linkBaseURL')
+ if link_base is not None:
+ params['linkBaseURL'] = link_base
return cls._make_brightcove_url(params)
@classmethod
@@ -448,13 +445,13 @@ def _real_extract(self, url):
url = re.sub(r'(?<=[?&])bckey', 'playerKey', url)
mobj = self._match_valid_url(url)
query_str = mobj.group('query')
- query = compat_urlparse.parse_qs(query_str)
+ query = urllib.parse.parse_qs(query_str)
- videoPlayer = query.get('@videoPlayer')
- if videoPlayer:
+ video_player = query.get('@videoPlayer')
+ if video_player:
# We set the original url as the default 'Referer' header
referer = query.get('linkBaseURL', [None])[0] or smuggled_data.get('Referer', url)
- video_id = videoPlayer[0]
+ video_id = video_player[0]
if 'playerID' not in query:
mobj = re.search(r'/bcpid(\d+)', url)
if mobj is not None:
@@ -483,7 +480,7 @@ def _real_extract(self, url):
enc_pub_id = player_key.split(',')[1].replace('~', '=')
publisher_id = struct.unpack('>Q', base64.urlsafe_b64decode(enc_pub_id))[0]
if publisher_id:
- brightcove_new_url = 'http://players.brightcove.net/%s/default_default/index.html?videoId=%s' % (publisher_id, video_id)
+ brightcove_new_url = f'http://players.brightcove.net/{publisher_id}/default_default/index.html?videoId={video_id}'
if referer:
brightcove_new_url = smuggle_url(brightcove_new_url, {'referrer': referer})
return self.url_result(brightcove_new_url, BrightcoveNewIE.ie_key(), video_id)
@@ -543,9 +540,9 @@ def _parse_brightcove_metadata(self, json_data, video_id, headers={}):
def build_format_id(kind):
format_id = kind
if tbr:
- format_id += '-%dk' % int(tbr)
+ format_id += f'-{int(tbr)}k'
if height:
- format_id += '-%dp' % height
+ format_id += f'-{height}p'
return format_id
if src or streaming_src:
@@ -654,7 +651,7 @@ class BrightcoveNewIE(BrightcoveNewBaseIE):
'params': {
# m3u8 download
'skip_download': True,
- }
+ },
}, {
# playlist stream
'url': 'https://players.brightcove.net/1752604059001/S13cJdUBz_default/index.html?playlistId=5718313430001',
@@ -666,7 +663,7 @@ class BrightcoveNewIE(BrightcoveNewBaseIE):
'params': {
# m3u8 download
'skip_download': True,
- }
+ },
}, {
'url': 'http://players.brightcove.net/5690807595001/HyZNerRl7_default/index.html?playlistId=5743160747001',
'only_matching': True,
@@ -833,8 +830,7 @@ def _extract_brightcove_urls(ie, webpage):
player_id = player_id or attrs.get('data-player') or 'default'
embed = embed or attrs.get('data-embed') or 'default'
- bc_url = 'http://players.brightcove.net/%s/%s_%s/index.html?videoId=%s' % (
- account_id, player_id, embed, video_id)
+ bc_url = f'http://players.brightcove.net/{account_id}/{player_id}_{embed}/index.html?videoId={video_id}'
# Some brightcove videos may be embedded with video tag only and
# without script tag or any mentioning of brightcove at all. Such
@@ -865,13 +861,13 @@ def _real_extract(self, url):
account_id, player_id, embed, content_type, video_id = self._match_valid_url(url).groups()
- policy_key_id = '%s_%s' % (account_id, player_id)
+ policy_key_id = f'{account_id}_{player_id}'
policy_key = self.cache.load('brightcove', policy_key_id)
policy_key_extracted = False
store_pk = lambda x: self.cache.store('brightcove', policy_key_id, x)
def extract_policy_key():
- base_url = 'http://players.brightcove.net/%s/%s_%s/' % (account_id, player_id, embed)
+ base_url = f'http://players.brightcove.net/{account_id}/{player_id}_{embed}/'
config = self._download_json(
base_url + 'config.json', video_id, fatal=False) or {}
policy_key = try_get(
@@ -910,7 +906,7 @@ def extract_policy_key():
if not policy_key:
policy_key = extract_policy_key()
policy_key_extracted = True
- headers['Accept'] = 'application/json;pk=%s' % policy_key
+ headers['Accept'] = f'application/json;pk={policy_key}'
try:
json_data = self._download_json(api_url, video_id, headers=headers)
break
@@ -936,7 +932,7 @@ def extract_policy_key():
custom_fields['bcadobepassresourceid'])
json_data = self._download_json(
api_url, video_id, headers={
- 'Accept': 'application/json;pk=%s' % policy_key
+ 'Accept': f'application/json;pk={policy_key}',
}, query={
'tveToken': tve_token,
})
diff --git a/yt_dlp/extractor/bundesliga.py b/yt_dlp/extractor/bundesliga.py
index e76dd58ddb..29f8f94157 100644
--- a/yt_dlp/extractor/bundesliga.py
+++ b/yt_dlp/extractor/bundesliga.py
@@ -16,17 +16,17 @@ class BundesligaIE(InfoExtractor):
'upload_date': '20220928',
'duration': 146,
'timestamp': 1664366511,
- 'description': 'md5:803d4411bd134140c774021dd4b7598b'
- }
+ 'description': 'md5:803d4411bd134140c774021dd4b7598b',
+ },
},
{
'url': 'https://www.bundesliga.com/en/bundesliga/videos/latest-features/T8IKc8TX?vid=ROHjs06G',
- 'only_matching': True
+ 'only_matching': True,
},
{
'url': 'https://www.bundesliga.com/en/bundesliga/videos/goals?vid=mOG56vWA',
- 'only_matching': True
- }
+ 'only_matching': True,
+ },
]
def _real_extract(self, url):
diff --git a/yt_dlp/extractor/businessinsider.py b/yt_dlp/extractor/businessinsider.py
index 4b3f5e68b8..7cb9af692a 100644
--- a/yt_dlp/extractor/businessinsider.py
+++ b/yt_dlp/extractor/businessinsider.py
@@ -10,7 +10,7 @@ class BusinessInsiderIE(InfoExtractor):
'info_dict': {
'id': 'cjGDb0X9',
'ext': 'mp4',
- 'title': "Bananas give you more radiation exposure than living next to a nuclear power plant",
+ 'title': 'Bananas give you more radiation exposure than living next to a nuclear power plant',
'description': 'md5:0175a3baf200dd8fa658f94cade841b3',
'upload_date': '20160611',
'timestamp': 1465675620,
@@ -41,5 +41,5 @@ def _real_extract(self, url):
r'(?:jwplatform\.com/players/|jwplayer_)([a-zA-Z0-9]{8})'),
webpage, 'jwplatform id')
return self.url_result(
- 'jwplatform:%s' % jwplatform_id, ie=JWPlatformIE.ie_key(),
+ f'jwplatform:{jwplatform_id}', ie=JWPlatformIE.ie_key(),
video_id=video_id)
diff --git a/yt_dlp/extractor/buzzfeed.py b/yt_dlp/extractor/buzzfeed.py
index b30a3b7ae2..9847095bcf 100644
--- a/yt_dlp/extractor/buzzfeed.py
+++ b/yt_dlp/extractor/buzzfeed.py
@@ -23,8 +23,8 @@ class BuzzFeedIE(InfoExtractor):
'upload_date': '20141024',
'uploader_id': 'Buddhanz1',
'uploader': 'Angry Ram',
- }
- }]
+ },
+ }],
}, {
'url': 'http://www.buzzfeed.com/sheridanwatson/look-at-this-cute-dog-omg?utm_term=4ldqpia',
'params': {
@@ -45,7 +45,7 @@ class BuzzFeedIE(InfoExtractor):
'uploader_id': 'CindysMunchkin',
'uploader': 're:^Munchkin the',
},
- }]
+ }],
}, {
'url': 'http://www.buzzfeed.com/craigsilverman/the-most-adorable-crash-landing-ever#.eq7pX0BAmK',
'info_dict': {
diff --git a/yt_dlp/extractor/byutv.py b/yt_dlp/extractor/byutv.py
index ad35427ed7..e9796f7dab 100644
--- a/yt_dlp/extractor/byutv.py
+++ b/yt_dlp/extractor/byutv.py
@@ -36,7 +36,7 @@ class BYUtvIE(InfoExtractor):
'duration': 11645,
},
'params': {
- 'skip_download': True
+ 'skip_download': True,
},
}, {
'url': 'http://www.byutv.org/watch/6587b9a3-89d2-42a6-a7f7-fd2f81840a7d',
diff --git a/yt_dlp/extractor/c56.py b/yt_dlp/extractor/c56.py
index e4b1c9a84c..6264803dd6 100644
--- a/yt_dlp/extractor/c56.py
+++ b/yt_dlp/extractor/c56.py
@@ -38,7 +38,7 @@ def _real_extract(self, url):
return self.url_result(sohu_video_info['url'], 'Sohu')
page = self._download_json(
- 'http://vxml.56.com/json/%s/' % text_id, text_id, 'Downloading video info')
+ f'http://vxml.56.com/json/{text_id}/', text_id, 'Downloading video info')
info = page['info']
@@ -46,7 +46,7 @@ def _real_extract(self, url):
{
'format_id': f['type'],
'filesize': int(f['filesize']),
- 'url': f['url']
+ 'url': f['url'],
} for f in info['rfiles']
]
diff --git a/yt_dlp/extractor/callin.py b/yt_dlp/extractor/callin.py
index c77179c7bb..b7061a7d14 100644
--- a/yt_dlp/extractor/callin.py
+++ b/yt_dlp/extractor/callin.py
@@ -29,8 +29,8 @@ class CallinIE(InfoExtractor):
'series_id': '436d1f82ddeb30cd2306ea9156044d8d2cfdc3f1f1552d245117a42173e78553',
'episode': 'The Title IX Regime and the Long March Through and Beyond the Institutions',
'episode_number': 1,
- 'episode_id': '218b979630a35ead12c6fd096f2996c56c37e4d0dc1f6dc0feada32dcf7b31cd'
- }
+ 'episode_id': '218b979630a35ead12c6fd096f2996c56c37e4d0dc1f6dc0feada32dcf7b31cd',
+ },
}, {
'url': 'https://www.callin.com/episode/fcc-commissioner-brendan-carr-on-elons-PrumRdSQJW',
'md5': '14ede27ee2c957b7e4db93140fc0745c',
@@ -54,7 +54,7 @@ class CallinIE(InfoExtractor):
'thumbnail': 'https://d1z76fhpoqkd01.cloudfront.net/shows/legacy/1ade9142625344045dc17cf523469ced1d93610762f4c886d06aa190a2f979e8.png',
'episode_id': 'c3dab47f237bf953d180d3f243477a84302798be0e0b29bc9ade6d60a69f04f5',
'timestamp': 1662100688.005,
- }
+ },
}, {
'url': 'https://www.callin.com/episode/episode-81-elites-melt-down-over-student-debt-lzxMidUnjA',
'md5': '16f704ddbf82a27e3930533b12062f07',
@@ -78,7 +78,7 @@ class CallinIE(InfoExtractor):
'thumbnail': 'https://d1z76fhpoqkd01.cloudfront.net/shows/legacy/461ea0d86172cb6aff7d6c80fd49259cf5e64bdf737a4650f8bc24cf392ca218.png',
'episode_id': '8d06f869798f93a7814e380bceabea72d501417e620180416ff6bd510596e83c',
'timestamp': 1661476708.282,
- }
+ },
}]
def try_get_user_name(self, d):
@@ -94,7 +94,7 @@ def _real_extract(self, url):
next_data = self._search_nextjs_data(webpage, display_id)
episode = next_data['props']['pageProps']['episode']
- id = episode['id']
+ video_id = episode['id']
title = episode.get('title') or self._generic_title('', webpage)
url = episode['m3u8']
formats = self._extract_m3u8_formats(url, display_id, ext='ts')
@@ -125,11 +125,11 @@ def _real_extract(self, url):
episode_list = traverse_obj(show_json, ('pageProps', 'show', 'episodes')) or []
episode_number = next(
- (len(episode_list) - i for (i, e) in enumerate(episode_list) if e.get('id') == id),
+ (len(episode_list) - i for i, e in enumerate(episode_list) if e.get('id') == video_id),
None)
return {
- 'id': id,
+ 'id': video_id,
'_old_archive_ids': [make_archive_id(self, display_id.rsplit('-', 1)[-1])],
'display_id': display_id,
'title': title,
@@ -151,5 +151,5 @@ def _real_extract(self, url):
'series_id': show_id,
'episode': title,
'episode_number': episode_number,
- 'episode_id': id
+ 'episode_id': video_id,
}
diff --git a/yt_dlp/extractor/caltrans.py b/yt_dlp/extractor/caltrans.py
index f4a4a834b8..5513bb2dfa 100644
--- a/yt_dlp/extractor/caltrans.py
+++ b/yt_dlp/extractor/caltrans.py
@@ -11,7 +11,7 @@ class CaltransIE(InfoExtractor):
'title': 'US-50 : Sacramento : Hwy 50 at 24th',
'live_status': 'is_live',
'thumbnail': 'https://cwwp2.dot.ca.gov/data/d3/cctv/image/hwy50at24th/hwy50at24th.jpg',
- }
+ },
}
def _real_extract(self, url):
diff --git a/yt_dlp/extractor/cam4.py b/yt_dlp/extractor/cam4.py
index 2650cc1ef1..0d0dccb794 100644
--- a/yt_dlp/extractor/cam4.py
+++ b/yt_dlp/extractor/cam4.py
@@ -12,12 +12,12 @@ class CAM4IE(InfoExtractor):
'age_limit': 18,
'live_status': 'is_live',
'thumbnail': 'https://snapshots.xcdnpro.com/thumbnails/foxynesss',
- }
+ },
}
def _real_extract(self, url):
channel_id = self._match_id(url)
- m3u8_playlist = self._download_json('https://www.cam4.com/rest/v1.0/profile/{}/streamInfo'.format(channel_id), channel_id).get('cdnURL')
+ m3u8_playlist = self._download_json(f'https://www.cam4.com/rest/v1.0/profile/{channel_id}/streamInfo', channel_id).get('cdnURL')
formats = self._extract_m3u8_formats(m3u8_playlist, channel_id, 'mp4', m3u8_id='hls', live=True)
diff --git a/yt_dlp/extractor/camdemy.py b/yt_dlp/extractor/camdemy.py
index c7079e4224..34dc095af8 100644
--- a/yt_dlp/extractor/camdemy.py
+++ b/yt_dlp/extractor/camdemy.py
@@ -1,10 +1,7 @@
import re
+import urllib.parse
from .common import InfoExtractor
-from ..compat import (
- compat_urllib_parse_urlencode,
- compat_urlparse,
-)
from ..utils import (
clean_html,
parse_duration,
@@ -28,7 +25,7 @@ class CamdemyIE(InfoExtractor):
'duration': 1591,
'upload_date': '20130114',
'view_count': int,
- }
+ },
}, {
# With non-empty description
# webpage returns "No permission or not login"
@@ -42,7 +39,7 @@ class CamdemyIE(InfoExtractor):
'description': 'md5:2a9f989c2b153a2342acee579c6e7db6',
'creator': 'evercam',
'duration': 318,
- }
+ },
}, {
# External source (YouTube)
'url': 'http://www.camdemy.com/media/14842',
@@ -76,12 +73,12 @@ def _real_extract(self, url):
title = oembed_obj['title']
thumb_url = oembed_obj['thumbnail_url']
- video_folder = compat_urlparse.urljoin(thumb_url, 'video/')
+ video_folder = urllib.parse.urljoin(thumb_url, 'video/')
file_list_doc = self._download_xml(
- compat_urlparse.urljoin(video_folder, 'fileList.xml'),
+ urllib.parse.urljoin(video_folder, 'fileList.xml'),
video_id, 'Downloading filelist XML')
file_name = file_list_doc.find('./video/item/fileName').text
- video_url = compat_urlparse.urljoin(video_folder, file_name)
+ video_url = urllib.parse.urljoin(video_folder, file_name)
# Some URLs return "No permission or not login" in a webpage despite being
# freely available via oembed JSON URL (e.g. http://www.camdemy.com/media/13885)
@@ -117,35 +114,35 @@ class CamdemyFolderIE(InfoExtractor):
'id': '450',
'title': '信號與系統 2012 & 2011 (Signals and Systems)',
},
- 'playlist_mincount': 145
+ 'playlist_mincount': 145,
}, {
# links without trailing slash
# and multi-page
'url': 'http://www.camdemy.com/folder/853',
'info_dict': {
'id': '853',
- 'title': '科學計算 - 使用 Matlab'
+ 'title': '科學計算 - 使用 Matlab',
},
- 'playlist_mincount': 20
+ 'playlist_mincount': 20,
}, {
# with displayMode parameter. For testing the codes to add parameters
'url': 'http://www.camdemy.com/folder/853/?displayMode=defaultOrderByOrg',
'info_dict': {
'id': '853',
- 'title': '科學計算 - 使用 Matlab'
+ 'title': '科學計算 - 使用 Matlab',
},
- 'playlist_mincount': 20
+ 'playlist_mincount': 20,
}]
def _real_extract(self, url):
folder_id = self._match_id(url)
# Add displayMode=list so that all links are displayed in a single page
- parsed_url = list(compat_urlparse.urlparse(url))
- query = dict(compat_urlparse.parse_qsl(parsed_url[4]))
+ parsed_url = list(urllib.parse.urlparse(url))
+ query = dict(urllib.parse.parse_qsl(parsed_url[4]))
query.update({'displayMode': 'list'})
- parsed_url[4] = compat_urllib_parse_urlencode(query)
- final_url = compat_urlparse.urlunparse(parsed_url)
+ parsed_url[4] = urllib.parse.urlencode(query)
+ final_url = urllib.parse.urlunparse(parsed_url)
page = self._download_webpage(final_url, folder_id)
matches = re.findall(r"href='(/media/\d+/?)'", page)
diff --git a/yt_dlp/extractor/camfm.py b/yt_dlp/extractor/camfm.py
index 11dafa4a21..6036f136fd 100644
--- a/yt_dlp/extractor/camfm.py
+++ b/yt_dlp/extractor/camfm.py
@@ -37,7 +37,7 @@ def _real_extract(self, url):
'thumbnail': urljoin('https://camfm.co.uk', self._search_regex(
r'
]+class="thumb-expand"[^>]+src="([^"]+)"', page, 'thumbnail', fatal=False)),
'title': self._html_search_regex('([^<]+)
', page, 'title', fatal=False),
- 'description': clean_html(get_element_by_class('small-12 medium-8 cell', page))
+ 'description': clean_html(get_element_by_class('small-12 medium-8 cell', page)),
}
@@ -56,7 +56,7 @@ class CamFMEpisodeIE(InfoExtractor):
'series': 'AITAA: Am I the Agony Aunt?',
'thumbnail': 'md5:5980a831360d0744c3764551be3d09c1',
'categories': ['Entertainment'],
- }
+ },
}]
def _real_extract(self, url):
diff --git a/yt_dlp/extractor/cammodels.py b/yt_dlp/extractor/cammodels.py
index 135b31529f..7388cfb6cd 100644
--- a/yt_dlp/extractor/cammodels.py
+++ b/yt_dlp/extractor/cammodels.py
@@ -7,14 +7,14 @@ class CamModelsIE(InfoExtractor):
_TESTS = [{
'url': 'https://www.cammodels.com/cam/AutumnKnight/',
'only_matching': True,
- 'age_limit': 18
+ 'age_limit': 18,
}]
def _real_extract(self, url):
user_id = self._match_id(url)
manifest = self._download_json(
- 'https://manifest-server.naiadsystems.com/live/s:%s.json' % user_id, user_id)
+ f'https://manifest-server.naiadsystems.com/live/s:{user_id}.json', user_id)
formats = []
thumbnails = []
@@ -36,7 +36,7 @@ def _real_extract(self, url):
format_id_list = [format_id]
height = int_or_none(media.get('videoHeight'))
if height is not None:
- format_id_list.append('%dp' % height)
+ format_id_list.append(f'{height}p')
f = {
'url': media_url,
'format_id': '-'.join(format_id_list),
@@ -73,5 +73,5 @@ def _real_extract(self, url):
'thumbnails': thumbnails,
'is_live': True,
'formats': formats,
- 'age_limit': 18
+ 'age_limit': 18,
}
diff --git a/yt_dlp/extractor/camtasia.py b/yt_dlp/extractor/camtasia.py
index 70ab6c62a1..326643175b 100644
--- a/yt_dlp/extractor/camtasia.py
+++ b/yt_dlp/extractor/camtasia.py
@@ -17,7 +17,7 @@ class CamtasiaEmbedIE(InfoExtractor):
'title': 'Fenn-AA_PA_Radar_Course_Lecture_1c_Final - video1',
'ext': 'flv',
'duration': 2235.90,
- }
+ },
}, {
'md5': '10e4bb3aaca9fd630e273ff92d9f3c63',
'info_dict': {
@@ -25,12 +25,12 @@ class CamtasiaEmbedIE(InfoExtractor):
'title': 'Fenn-AA_PA_Radar_Course_Lecture_1c_Final - pip',
'ext': 'flv',
'duration': 2235.93,
- }
+ },
}],
'info_dict': {
'title': 'Fenn-AA_PA_Radar_Course_Lecture_1c_Final',
},
- 'skip': 'webpage dead'
+ 'skip': 'webpage dead',
},
]
diff --git a/yt_dlp/extractor/canalalpha.py b/yt_dlp/extractor/canalalpha.py
index 745e6954c7..3a0df95450 100644
--- a/yt_dlp/extractor/canalalpha.py
+++ b/yt_dlp/extractor/canalalpha.py
@@ -21,7 +21,7 @@ class CanalAlphaIE(InfoExtractor):
'upload_date': '20211028',
'duration': 1125,
},
- 'params': {'skip_download': True}
+ 'params': {'skip_download': True},
}, {
'url': 'https://www.canalalpha.ch/play/le-journal/topic/24512/la-poste-fait-de-neuchatel-un-pole-cryptographique',
'info_dict': {
@@ -33,7 +33,7 @@ class CanalAlphaIE(InfoExtractor):
'upload_date': '20211028',
'duration': 138,
},
- 'params': {'skip_download': True}
+ 'params': {'skip_download': True},
}, {
'url': 'https://www.canalalpha.ch/play/eureka/episode/24484/ces-innovations-qui-veulent-rendre-lagriculture-plus-durable',
'info_dict': {
@@ -45,7 +45,7 @@ class CanalAlphaIE(InfoExtractor):
'upload_date': '20211026',
'duration': 360,
},
- 'params': {'skip_download': True}
+ 'params': {'skip_download': True},
}, {
'url': 'https://www.canalalpha.ch/play/avec-le-temps/episode/23516/redonner-de-leclat-grace-au-polissage',
'info_dict': {
@@ -57,7 +57,7 @@ class CanalAlphaIE(InfoExtractor):
'upload_date': '20210726',
'duration': 360,
},
- 'params': {'skip_download': True}
+ 'params': {'skip_download': True},
}, {
'url': 'https://www.canalalpha.ch/play/le-journal/topic/33500/encore-des-mesures-deconomie-dans-le-jura',
'info_dict': {
diff --git a/yt_dlp/extractor/canalc2.py b/yt_dlp/extractor/canalc2.py
index 597cb2a6b0..c725545fa2 100644
--- a/yt_dlp/extractor/canalc2.py
+++ b/yt_dlp/extractor/canalc2.py
@@ -26,7 +26,7 @@ def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(
- 'http://www.canalc2.tv/video/%s' % video_id, video_id)
+ f'http://www.canalc2.tv/video/{video_id}', video_id)
title = self._html_search_regex(
r'(?s)class="[^"]*col_description[^"]*">.*?(.+?)
',
diff --git a/yt_dlp/extractor/canalplus.py b/yt_dlp/extractor/canalplus.py
index 3ff5c3fbfc..728b7a0472 100644
--- a/yt_dlp/extractor/canalplus.py
+++ b/yt_dlp/extractor/canalplus.py
@@ -53,7 +53,7 @@ def _real_extract(self, url):
video_data = self._download_json(info_url, video_id, 'Downloading video JSON')
if isinstance(video_data, list):
- video_data = [video for video in video_data if video.get('ID') == video_id][0]
+ video_data = next(video for video in video_data if video.get('ID') == video_id)
media = video_data['MEDIA']
infos = video_data['INFOS']
@@ -97,8 +97,7 @@ def _real_extract(self, url):
return {
'id': video_id,
'display_id': display_id,
- 'title': '%s - %s' % (titrage['TITRE'],
- titrage['SOUS_TITRE']),
+ 'title': '{} - {}'.format(titrage['TITRE'], titrage['SOUS_TITRE']),
'upload_date': unified_strdate(infos.get('PUBLICATION', {}).get('DATE')),
'thumbnails': thumbnails,
'description': infos.get('DESCRIPTION'),
diff --git a/yt_dlp/extractor/caracoltv.py b/yt_dlp/extractor/caracoltv.py
index 79f7752fe0..493ffdae5e 100644
--- a/yt_dlp/extractor/caracoltv.py
+++ b/yt_dlp/extractor/caracoltv.py
@@ -78,13 +78,13 @@ def _perform_login(self, email, password):
'device_data': {
'device_id': str(uuid.uuid4()),
'device_token': '',
- 'device_type': 'web'
+ 'device_type': 'web',
},
'login_data': {
'enabled': True,
'email': email,
'password': password,
- }
+ },
}).encode())['user_token']
def _extract_video(self, video_data, series_id=None, season_id=None, season_number=None):
diff --git a/yt_dlp/extractor/cartoonnetwork.py b/yt_dlp/extractor/cartoonnetwork.py
index 4dd7ac46d4..1749a008a2 100644
--- a/yt_dlp/extractor/cartoonnetwork.py
+++ b/yt_dlp/extractor/cartoonnetwork.py
@@ -27,7 +27,7 @@ def find_field(global_re, name, content_re=None, value_re='[^"]+', fatal=False):
if content_re:
metadata_re = r'|video_metadata\.content_' + content_re
return self._search_regex(
- r'(?:_cnglobal\.currentVideo\.%s%s)\s*=\s*"(%s)";' % (global_re, metadata_re, value_re),
+ rf'(?:_cnglobal\.currentVideo\.{global_re}{metadata_re})\s*=\s*"({value_re})";',
webpage, name, fatal=fatal)
media_id = find_field('mediaId', 'media id', 'id', '[0-9a-f]{40}', True)
diff --git a/yt_dlp/extractor/cbc.py b/yt_dlp/extractor/cbc.py
index a4180262b7..740e129264 100644
--- a/yt_dlp/extractor/cbc.py
+++ b/yt_dlp/extractor/cbc.py
@@ -6,9 +6,6 @@
import xml.etree.ElementTree
from .common import InfoExtractor
-from ..compat import (
- compat_str,
-)
from ..utils import (
ExtractorError,
int_or_none,
@@ -99,7 +96,7 @@ class CBCIE(InfoExtractor):
# multiple CBC.APP.Caffeine.initInstance(...)
'url': 'http://www.cbc.ca/news/canada/calgary/dog-indoor-exercise-winter-1.3928238',
'info_dict': {
- 'title': 'Keep Rover active during the deep freeze with doggie pushups and other fun indoor tasks', # FIXME
+ 'title': 'Keep Rover active during the deep freeze with doggie pushups and other fun indoor tasks', # FIXME: actual title includes " | CBC News"
'id': 'dog-indoor-exercise-winter-1.3928238',
'description': 'md5:c18552e41726ee95bd75210d1ca9194c',
},
@@ -108,7 +105,7 @@ class CBCIE(InfoExtractor):
@classmethod
def suitable(cls, url):
- return False if CBCPlayerIE.suitable(url) else super(CBCIE, cls).suitable(url)
+ return False if CBCPlayerIE.suitable(url) else super().suitable(url)
def _extract_player_init(self, player_init, display_id):
player_info = self._parse_json(player_init, display_id, js_to_json)
@@ -116,15 +113,15 @@ def _extract_player_init(self, player_init, display_id):
if not media_id:
clip_id = player_info['clipId']
feed = self._download_json(
- 'http://tpfeed.cbc.ca/f/ExhSPC/vms_5akSXx4Ng_Zn?byCustomValue={:mpsReleases}{%s}' % clip_id,
+ f'http://tpfeed.cbc.ca/f/ExhSPC/vms_5akSXx4Ng_Zn?byCustomValue={{:mpsReleases}}{{{clip_id}}}',
clip_id, fatal=False)
if feed:
- media_id = try_get(feed, lambda x: x['entries'][0]['guid'], compat_str)
+ media_id = try_get(feed, lambda x: x['entries'][0]['guid'], str)
if not media_id:
media_id = self._download_json(
'http://feed.theplatform.com/f/h9dtGB/punlNGjMlc1F?fields=id&byContent=byReleases%3DbyId%253D' + clip_id,
clip_id)['entries'][0]['id'].split('/')[-1]
- return self.url_result('cbcplayer:%s' % media_id, 'CBCPlayer', media_id)
+ return self.url_result(f'cbcplayer:{media_id}', 'CBCPlayer', media_id)
def _real_extract(self, url):
display_id = self._match_id(url)
@@ -142,7 +139,7 @@ def _real_extract(self, url):
r'guid["\']\s*:\s*["\'](\d+)'):
media_ids.extend(re.findall(media_id_re, webpage))
entries.extend([
- self.url_result('cbcplayer:%s' % media_id, 'CBCPlayer', media_id)
+ self.url_result(f'cbcplayer:{media_id}', 'CBCPlayer', media_id)
for media_id in orderedSet(media_ids)])
return self.playlist_result(
entries, display_id, strip_or_none(title),
@@ -322,11 +319,11 @@ def _real_extract(self, url):
'_type': 'url_transparent',
'ie_key': 'ThePlatform',
'url': smuggle_url(
- 'http://link.theplatform.com/s/ExhSPC/media/guid/2655402169/%s?mbr=true&formats=MPEG4,FLV,MP3' % video_id, {
- 'force_smil_url': True
+ f'http://link.theplatform.com/s/ExhSPC/media/guid/2655402169/{video_id}?mbr=true&formats=MPEG4,FLV,MP3', {
+ 'force_smil_url': True,
}),
'id': video_id,
- '_format_sort_fields': ('res', 'proto') # Prioritize direct http formats over HLS
+ '_format_sort_fields': ('res', 'proto'), # Prioritize direct http formats over HLS
}
@@ -338,13 +335,13 @@ class CBCPlayerPlaylistIE(InfoExtractor):
'playlist_mincount': 25,
'info_dict': {
'id': 'news/tv shows/the national/latest broadcast',
- }
+ },
}, {
'url': 'https://www.cbc.ca/player/news/Canada/North',
'playlist_mincount': 25,
'info_dict': {
'id': 'news/canada/north',
- }
+ },
}]
def _real_extract(self, url):
@@ -355,7 +352,7 @@ def _real_extract(self, url):
def entries():
for video_id in traverse_obj(json_content, (
- 'video', 'clipsByCategory', lambda k, _: k.lower() == playlist_id, 'items', ..., 'id'
+ 'video', 'clipsByCategory', lambda k, _: k.lower() == playlist_id, 'items', ..., 'id',
)):
yield self.url_result(f'https://www.cbc.ca/player/play/{video_id}', CBCPlayerIE)
@@ -453,7 +450,7 @@ def _get_claims_token_expiry(self):
# JWT is decoded here and 'exp' field is extracted
# It is a Unix timestamp for when the token expires
b64_data = self._claims_token.split('.')[1]
- data = base64.urlsafe_b64decode(b64_data + "==")
+ data = base64.urlsafe_b64decode(b64_data + '==')
return json.loads(data)['exp']
def claims_token_expired(self):
@@ -535,17 +532,17 @@ def _real_extract(self, url):
self._remove_duplicate_formats(formats)
formats.extend(self._find_secret_formats(formats, video_id))
- for format in formats:
- if format.get('vcodec') == 'none':
- if format.get('ext') is None:
- format['ext'] = 'm4a'
- if format.get('acodec') is None:
- format['acodec'] = 'mp4a.40.2'
+ for fmt in formats:
+ if fmt.get('vcodec') == 'none':
+ if fmt.get('ext') is None:
+ fmt['ext'] = 'm4a'
+ if fmt.get('acodec') is None:
+ fmt['acodec'] = 'mp4a.40.2'
# Put described audio at the beginning of the list, so that it
# isn't chosen by default, as most people won't want it.
- if 'descriptive' in format['format_id'].lower():
- format['preference'] = -2
+ if 'descriptive' in fmt['format_id'].lower():
+ fmt['preference'] = -2
return {
'id': video_id,
@@ -670,7 +667,7 @@ class CBCGemLiveIE(InfoExtractor):
'title': r're:^Ottawa [0-9\-: ]+',
'description': 'The live TV channel and local programming from Ottawa',
'live_status': 'is_live',
- 'thumbnail': r're:https://images.gem.cbc.ca/v1/cbc-gem/live/.*'
+ 'thumbnail': r're:https://images.gem.cbc.ca/v1/cbc-gem/live/.*',
},
'params': {'skip_download': True},
'skip': 'Live might have ended',
@@ -690,7 +687,7 @@ class CBCGemLiveIE(InfoExtractor):
},
'params': {'skip_download': True},
'skip': 'Live might have ended',
- }
+ },
]
def _real_extract(self, url):
@@ -729,5 +726,5 @@ def _real_extract(self, url):
'description': 'description',
'thumbnail': ('images', 'card', 'url'),
'timestamp': ('airDate', {parse_iso8601}),
- })
+ }),
}
diff --git a/yt_dlp/extractor/cbs.py b/yt_dlp/extractor/cbs.py
index aca9782c76..e825588972 100644
--- a/yt_dlp/extractor/cbs.py
+++ b/yt_dlp/extractor/cbs.py
@@ -31,7 +31,7 @@ def _parse_smil_subtitles(self, smil, namespace=None, subtitles_lang='en'):
return subtitles
def _extract_common_video_info(self, content_id, asset_types, mpx_acc, extra_info):
- tp_path = 'dJ5BDC/media/guid/%d/%s' % (mpx_acc, content_id)
+ tp_path = f'dJ5BDC/media/guid/{mpx_acc}/{content_id}'
tp_release_url = f'https://link.theplatform.com/s/{tp_path}'
info = self._extract_theplatform_metadata(tp_path, content_id)
@@ -41,7 +41,7 @@ def _extract_common_video_info(self, content_id, asset_types, mpx_acc, extra_inf
try:
tp_formats, tp_subtitles = self._extract_theplatform_smil(
update_url_query(tp_release_url, query), content_id,
- 'Downloading %s SMIL data' % asset_type)
+ f'Downloading {asset_type} SMIL data')
except ExtractorError as e:
last_e = e
if asset_type != 'fallback':
@@ -50,7 +50,7 @@ def _extract_common_video_info(self, content_id, asset_types, mpx_acc, extra_inf
try:
tp_formats, tp_subtitles = self._extract_theplatform_smil(
update_url_query(tp_release_url, query), content_id,
- 'Downloading %s SMIL data, trying again with another format' % asset_type)
+ f'Downloading {asset_type} SMIL data, trying again with another format')
except ExtractorError as e:
last_e = e
continue
diff --git a/yt_dlp/extractor/ccc.py b/yt_dlp/extractor/ccc.py
index ca6b82c981..1d781cc477 100644
--- a/yt_dlp/extractor/ccc.py
+++ b/yt_dlp/extractor/ccc.py
@@ -25,7 +25,7 @@ class CCCIE(InfoExtractor):
'timestamp': 1388188800,
'duration': 3710,
'tags': list,
- }
+ },
}, {
'url': 'https://media.ccc.de/v/32c3-7368-shopshifting#download',
'only_matching': True,
@@ -35,7 +35,7 @@ def _real_extract(self, url):
display_id = self._match_id(url)
webpage = self._download_webpage(url, display_id)
event_id = self._search_regex(r"data-id='(\d+)'", webpage, 'event id')
- event_data = self._download_json('https://media.ccc.de/public/events/%s' % event_id, event_id)
+ event_data = self._download_json(f'https://media.ccc.de/public/events/{event_id}', event_id)
formats = []
for recording in event_data.get('recordings', []):
@@ -96,7 +96,7 @@ class CCCPlaylistIE(InfoExtractor):
'title': 'Datenspuren 2023',
'id': 'DS2023',
},
- 'playlist_count': 37
+ 'playlist_count': 37,
}]
def _real_extract(self, url):
diff --git a/yt_dlp/extractor/ccma.py b/yt_dlp/extractor/ccma.py
index ab840f3016..ffe4b49c15 100644
--- a/yt_dlp/extractor/ccma.py
+++ b/yt_dlp/extractor/ccma.py
@@ -24,7 +24,7 @@ class CCMAIE(InfoExtractor):
'timestamp': 1478608140,
'upload_date': '20161108',
'age_limit': 0,
- }
+ },
}, {
'url': 'http://www.ccma.cat/catradio/alacarta/programa/el-consell-de-savis-analitza-el-derbi/audio/943685/',
'md5': 'fa3e38f269329a278271276330261425',
@@ -37,7 +37,7 @@ class CCMAIE(InfoExtractor):
'timestamp': 1494622500,
'vcodec': 'none',
'categories': ['Esports'],
- }
+ },
}, {
'url': 'http://www.ccma.cat/tv3/alacarta/crims/crims-josep-tallada-lespereu-me-capitol-1/video/6031387/',
'md5': 'b43c3d3486f430f3032b5b160d80cbc3',
@@ -51,7 +51,7 @@ class CCMAIE(InfoExtractor):
'subtitles': 'mincount:4',
'age_limit': 16,
'series': 'Crims',
- }
+ },
}]
def _real_extract(self, url):
diff --git a/yt_dlp/extractor/cctv.py b/yt_dlp/extractor/cctv.py
index 8552ee511c..18c080df1b 100644
--- a/yt_dlp/extractor/cctv.py
+++ b/yt_dlp/extractor/cctv.py
@@ -1,7 +1,6 @@
import re
from .common import InfoExtractor
-from ..compat import compat_str
from ..utils import (
float_or_none,
try_get,
@@ -167,17 +166,17 @@ def _real_extract(self, url):
if isinstance(video, dict):
for quality, chapters_key in enumerate(('lowChapters', 'chapters')):
video_url = try_get(
- video, lambda x: x[chapters_key][0]['url'], compat_str)
+ video, lambda x: x[chapters_key][0]['url'], str)
if video_url:
formats.append({
'url': video_url,
'format_id': 'http',
'quality': quality,
# Sample clip
- 'preference': -10
+ 'preference': -10,
})
- hls_url = try_get(data, lambda x: x['hls_url'], compat_str)
+ hls_url = try_get(data, lambda x: x['hls_url'], str)
if hls_url:
hls_url = re.sub(r'maxbr=\d+&?', '', hls_url)
formats.extend(self._extract_m3u8_formats(
diff --git a/yt_dlp/extractor/cda.py b/yt_dlp/extractor/cda.py
index 0a5a524c16..62ee8b17f1 100644
--- a/yt_dlp/extractor/cda.py
+++ b/yt_dlp/extractor/cda.py
@@ -6,9 +6,10 @@
import json
import random
import re
+import urllib.parse
from .common import InfoExtractor
-from ..compat import compat_ord, compat_urllib_parse_unquote
+from ..compat import compat_ord
from ..utils import (
ExtractorError,
float_or_none,
@@ -51,7 +52,7 @@ class CDAIE(InfoExtractor):
'age_limit': 0,
'upload_date': '20160221',
'timestamp': 1456078244,
- }
+ },
}, {
'url': 'http://www.cda.pl/video/57413289',
'md5': 'a88828770a8310fc00be6c95faf7f4d5',
@@ -67,7 +68,7 @@ class CDAIE(InfoExtractor):
'age_limit': 0,
'upload_date': '20160220',
'timestamp': 1455968218,
- }
+ },
}, {
# Age-restricted with vfilm redirection
'url': 'https://www.cda.pl/video/8753244c4',
@@ -85,7 +86,7 @@ class CDAIE(InfoExtractor):
'average_rating': float,
'timestamp': 1633888264,
'upload_date': '20211010',
- }
+ },
}, {
# Age-restricted without vfilm redirection
'url': 'https://www.cda.pl/video/17028157b8',
@@ -103,7 +104,7 @@ class CDAIE(InfoExtractor):
'average_rating': float,
'timestamp': 1699705901,
'upload_date': '20231111',
- }
+ },
}, {
'url': 'http://ebd.cda.pl/0x0/5749950c',
'only_matching': True,
@@ -263,7 +264,7 @@ def _web_extract(self, video_id):
def decrypt_file(a):
for p in ('_XDDD', '_CDA', '_ADC', '_CXD', '_QWE', '_Q5', '_IKSDE'):
a = a.replace(p, '')
- a = compat_urllib_parse_unquote(a)
+ a = urllib.parse.unquote(a)
b = []
for c in a:
f = compat_ord(c)
@@ -280,16 +281,16 @@ def decrypt_file(a):
def extract_format(page, version):
json_str = self._html_search_regex(
r'player_data=(\\?["\'])(?P.+?)\1', page,
- '%s player_json' % version, fatal=False, group='player_data')
+ f'{version} player_json', fatal=False, group='player_data')
if not json_str:
return
player_data = self._parse_json(
- json_str, '%s player_data' % version, fatal=False)
+ json_str, f'{version} player_data', fatal=False)
if not player_data:
return
video = player_data.get('video')
if not video or 'file' not in video:
- self.report_warning('Unable to extract %s version information' % version)
+ self.report_warning(f'Unable to extract {version} version information')
return
if video['file'].startswith('uggc'):
video['file'] = codecs.decode(video['file'], 'rot_13')
@@ -310,11 +311,11 @@ def extract_format(page, version):
continue
data = {'jsonrpc': '2.0', 'method': 'videoGetLink', 'id': 2,
'params': [video_id, cda_quality, video.get('ts'), video.get('hash2'), {}]}
- data = json.dumps(data).encode('utf-8')
+ data = json.dumps(data).encode()
video_url = self._download_json(
f'https://www.cda.pl/video/{video_id}', video_id, headers={
'Content-Type': 'application/json',
- 'X-Requested-With': 'XMLHttpRequest'
+ 'X-Requested-With': 'XMLHttpRequest',
}, data=data, note=f'Fetching {quality} url',
errnote=f'Failed to fetch {quality} url', fatal=False)
if try_get(video_url, lambda x: x['result']['status']) == 'ok':
@@ -322,7 +323,7 @@ def extract_format(page, version):
info_dict['formats'].append({
'url': video_url,
'format_id': quality,
- 'height': int_or_none(quality[:-1])
+ 'height': int_or_none(quality[:-1]),
})
if not info_dict['duration']:
@@ -340,11 +341,11 @@ def extract_format(page, version):
webpage = handler(
urljoin(self._BASE_URL, href), video_id,
- 'Downloading %s version information' % resolution, fatal=False)
+ f'Downloading {resolution} version information', fatal=False)
if not webpage:
# Manually report warning because empty page is returned when
# invalid version is requested.
- self.report_warning('Unable to download %s version information' % resolution)
+ self.report_warning(f'Unable to download {resolution} version information')
continue
extract_format(webpage, resolution)
diff --git a/yt_dlp/extractor/cellebrite.py b/yt_dlp/extractor/cellebrite.py
index 9896a31afe..e90365a8be 100644
--- a/yt_dlp/extractor/cellebrite.py
+++ b/yt_dlp/extractor/cellebrite.py
@@ -14,7 +14,7 @@ class CellebriteIE(InfoExtractor):
'title': 'Ask the Expert: Chat Capture - Collect Data from Android Devices in Cellebrite UFED',
'duration': 455,
'tags': [],
- }
+ },
}, {
'url': 'https://cellebrite.com/en/how-to-lawfully-collect-the-maximum-amount-of-data-from-android-devices/',
'info_dict': {
@@ -25,7 +25,7 @@ class CellebriteIE(InfoExtractor):
'description': 'md5:e9a3d124c7287b0b07bad2547061cacf',
'thumbnail': 'https://cellebrite.com/wp-content/uploads/2022/07/How-to-Lawfully-Collect-the-Maximum-Amount-of-Data-From-Android-Devices.png',
'title': 'Android Extractions Explained',
- }
+ },
}]
def _get_formats_and_subtitles(self, json_data, display_id):
diff --git a/yt_dlp/extractor/ceskatelevize.py b/yt_dlp/extractor/ceskatelevize.py
index 5d63357296..c323985caf 100644
--- a/yt_dlp/extractor/ceskatelevize.py
+++ b/yt_dlp/extractor/ceskatelevize.py
@@ -1,7 +1,7 @@
import re
+import urllib.parse
from .common import InfoExtractor
-from ..compat import compat_urllib_parse_unquote, compat_urllib_parse_urlparse
from ..networking import Request
from ..utils import (
ExtractorError,
@@ -97,11 +97,11 @@ class CeskaTelevizeIE(InfoExtractor):
def _real_extract(self, url):
playlist_id = self._match_id(url)
webpage, urlh = self._download_webpage_handle(url, playlist_id)
- parsed_url = compat_urllib_parse_urlparse(urlh.url)
+ parsed_url = urllib.parse.urlparse(urlh.url)
site_name = self._og_search_property('site_name', webpage, fatal=False, default='Česká televize')
playlist_title = self._og_search_title(webpage, default=None)
if site_name and playlist_title:
- playlist_title = re.split(r'\s*[—|]\s*%s' % (site_name, ), playlist_title, maxsplit=1)[0]
+ playlist_title = re.split(rf'\s*[—|]\s*{site_name}', playlist_title, maxsplit=1)[0]
playlist_description = self._og_search_description(webpage, default=None)
if playlist_description:
playlist_description = playlist_description.replace('\xa0', ' ')
@@ -122,15 +122,15 @@ def _real_extract(self, url):
iframe_hash = self._download_webpage(
'https://www.ceskatelevize.cz/v-api/iframe-hash/',
playlist_id, note='Getting IFRAME hash')
- query = {'hash': iframe_hash, 'origin': 'iVysilani', 'autoStart': 'true', type_: idec, }
+ query = {'hash': iframe_hash, 'origin': 'iVysilani', 'autoStart': 'true', type_: idec}
webpage = self._download_webpage(
'https://www.ceskatelevize.cz/ivysilani/embed/iFramePlayer.php',
playlist_id, note='Downloading player', query=query)
NOT_AVAILABLE_STRING = 'This content is not available at your territory due to limited copyright.'
- if '%s' % NOT_AVAILABLE_STRING in webpage:
+ if f'{NOT_AVAILABLE_STRING}' in webpage:
self.raise_geo_restricted(NOT_AVAILABLE_STRING)
- if any(not_found in webpage for not_found in ('Neplatný parametr pro videopřehrávač', 'IDEC nebyl nalezen', )):
+ if any(not_found in webpage for not_found in ('Neplatný parametr pro videopřehrávač', 'IDEC nebyl nalezen')):
raise ExtractorError('no video with IDEC available', video_id=idec, expected=True)
type_ = None
@@ -183,7 +183,7 @@ def _real_extract(self, url):
if playlist_url == 'error_region':
raise ExtractorError(NOT_AVAILABLE_STRING, expected=True)
- req = Request(compat_urllib_parse_unquote(playlist_url))
+ req = Request(urllib.parse.unquote(playlist_url))
req.headers['Referer'] = url
playlist = self._download_json(req, playlist_id, fatal=False)
@@ -203,11 +203,11 @@ def _real_extract(self, url):
if 'playerType=flash' in stream_url:
stream_formats = self._extract_m3u8_formats(
stream_url, playlist_id, 'mp4', 'm3u8_native',
- m3u8_id='hls-%s' % format_id, fatal=False)
+ m3u8_id=f'hls-{format_id}', fatal=False)
else:
stream_formats = self._extract_mpd_formats(
stream_url, playlist_id,
- mpd_id='dash-%s' % format_id, fatal=False)
+ mpd_id=f'dash-{format_id}', fatal=False)
if 'drmOnly=true' in stream_url:
for f in stream_formats:
f['has_drm'] = True
@@ -236,7 +236,7 @@ def _real_extract(self, url):
if playlist_len == 1:
final_title = playlist_title or title
else:
- final_title = '%s (%s)' % (playlist_title, title)
+ final_title = f'{playlist_title} ({title})'
entries.append({
'id': item_id,
@@ -261,7 +261,7 @@ def _get_subtitles(self, episode_id, subs):
'cs': [{
'ext': 'srt',
'data': srt_subs,
- }]
+ }],
}
@staticmethod
@@ -282,7 +282,7 @@ def _fix_subtitle(subtitle):
if m:
yield m.group(1)
start, stop = (_msectotimecode(int(t)) for t in m.groups()[1:])
- yield '{0} --> {1}'.format(start, stop)
+ yield f'{start} --> {stop}'
else:
yield line
diff --git a/yt_dlp/extractor/cgtn.py b/yt_dlp/extractor/cgtn.py
index 5d9d9bcde7..b9757e0639 100644
--- a/yt_dlp/extractor/cgtn.py
+++ b/yt_dlp/extractor/cgtn.py
@@ -20,8 +20,8 @@ class CGTNIE(InfoExtractor):
'categories': ['Video'],
},
'params': {
- 'skip_download': True
- }
+ 'skip_download': True,
+ },
}, {
'url': 'https://news.cgtn.com/news/2021-06-06/China-Indonesia-vow-to-further-deepen-maritime-cooperation-10REvJCewCY/index.html',
'info_dict': {
@@ -36,9 +36,9 @@ class CGTNIE(InfoExtractor):
'upload_date': '20210606',
},
'params': {
- 'skip_download': False
- }
- }
+ 'skip_download': False,
+ },
+ },
]
def _real_extract(self, url):
diff --git a/yt_dlp/extractor/chaturbate.py b/yt_dlp/extractor/chaturbate.py
index 99dfcfdebb..b49f741efa 100644
--- a/yt_dlp/extractor/chaturbate.py
+++ b/yt_dlp/extractor/chaturbate.py
@@ -37,7 +37,7 @@ def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(
- 'https://chaturbate.com/%s/' % video_id, video_id,
+ f'https://chaturbate.com/{video_id}/', video_id,
headers=self.geo_verification_headers())
found_m3u8_urls = []
@@ -85,7 +85,7 @@ def _real_extract(self, url):
formats = []
for m3u8_url in m3u8_urls:
for known_id in ('fast', 'slow'):
- if '_%s' % known_id in m3u8_url:
+ if f'_{known_id}' in m3u8_url:
m3u8_id = known_id
break
else:
@@ -99,7 +99,7 @@ def _real_extract(self, url):
return {
'id': video_id,
'title': video_id,
- 'thumbnail': 'https://roomimg.stream.highwebmedia.com/ri/%s.jpg' % video_id,
+ 'thumbnail': f'https://roomimg.stream.highwebmedia.com/ri/{video_id}.jpg',
'age_limit': self._rta_search(webpage),
'is_live': True,
'formats': formats,
diff --git a/yt_dlp/extractor/cinemax.py b/yt_dlp/extractor/cinemax.py
index 706ec8553b..66831ef62d 100644
--- a/yt_dlp/extractor/cinemax.py
+++ b/yt_dlp/extractor/cinemax.py
@@ -20,6 +20,6 @@ class CinemaxIE(HBOBaseIE):
def _real_extract(self, url):
path, video_id = self._match_valid_url(url).groups()
- info = self._extract_info('https://www.cinemax.com/%s.xml' % path, video_id)
+ info = self._extract_info(f'https://www.cinemax.com/{path}.xml', video_id)
info['id'] = video_id
return info
diff --git a/yt_dlp/extractor/cinetecamilano.py b/yt_dlp/extractor/cinetecamilano.py
index 745b71f243..834890d56f 100644
--- a/yt_dlp/extractor/cinetecamilano.py
+++ b/yt_dlp/extractor/cinetecamilano.py
@@ -27,8 +27,8 @@ class CinetecaMilanoIE(InfoExtractor):
'modified_date': '20200520',
'duration': 3139,
'release_timestamp': 1643446208,
- 'modified_timestamp': int
- }
+ 'modified_timestamp': int,
+ },
}]
def _real_extract(self, url):
@@ -38,7 +38,7 @@ def _real_extract(self, url):
f'https://www.cinetecamilano.it/api/catalogo/{video_id}/?',
video_id, headers={
'Referer': url,
- 'Authorization': try_get(self._get_cookies('https://www.cinetecamilano.it'), lambda x: f'Bearer {x["cnt-token"].value}') or ''
+ 'Authorization': try_get(self._get_cookies('https://www.cinetecamilano.it'), lambda x: f'Bearer {x["cnt-token"].value}') or '',
})
except ExtractorError as e:
if ((isinstance(e.cause, HTTPError) and e.cause.status == 500)
@@ -58,5 +58,5 @@ def _real_extract(self, url):
'modified_timestamp': parse_iso8601(archive.get('created_at'), delimiter=' '),
'thumbnail': urljoin(url, try_get(archive, lambda x: x['thumb']['src'].replace('/public/', '/storage/'))),
'formats': self._extract_m3u8_formats(
- urljoin(url, traverse_obj(archive, ('drm', 'hls'))), video_id, 'mp4')
+ urljoin(url, traverse_obj(archive, ('drm', 'hls'))), video_id, 'mp4'),
}
diff --git a/yt_dlp/extractor/cineverse.py b/yt_dlp/extractor/cineverse.py
index 4405297c62..c8c6c48c27 100644
--- a/yt_dlp/extractor/cineverse.py
+++ b/yt_dlp/extractor/cineverse.py
@@ -13,7 +13,7 @@
class CineverseBaseIE(InfoExtractor):
- _VALID_URL_BASE = r'https?://www\.(?P%s)' % '|'.join(map(re.escape, (
+ _VALID_URL_BASE = r'https?://www\.(?P{})'.format('|'.join(map(re.escape, (
'cineverse.com',
'asiancrush.com',
'dovechannel.com',
@@ -21,7 +21,7 @@ class CineverseBaseIE(InfoExtractor):
'midnightpulp.com',
'fandor.com',
'retrocrush.tv',
- )))
+ ))))
class CineverseIE(CineverseBaseIE):
@@ -38,7 +38,7 @@ class CineverseIE(CineverseBaseIE):
'duration': 5811.597,
'description': 'md5:892fd62a05611d394141e8394ace0bc6',
'age_limit': 13,
- }
+ },
}, {
'url': 'https://www.retrocrush.tv/watch/1000000023016/Archenemy! Crystal Bowie',
'skip': 'geo-blocked',
@@ -55,7 +55,7 @@ class CineverseIE(CineverseBaseIE):
'duration': 1485.067,
'description': 'Cobra meets a beautiful bounty hunter by the name of Jane Royal.',
'series': 'Space Adventure COBRA (Original Japanese)',
- }
+ },
}]
def _real_extract(self, url):
@@ -104,7 +104,7 @@ class CineverseDetailsIE(CineverseBaseIE):
'info_dict': {
'title': 'Space Adventure COBRA (Original Japanese)',
'id': '1000000023012',
- }
+ },
}, {
'url': 'https://www.asiancrush.com/details/NNVG4938/Hansel-and-Gretel',
'info_dict': {
diff --git a/yt_dlp/extractor/ciscolive.py b/yt_dlp/extractor/ciscolive.py
index 0668578170..1584ca6657 100644
--- a/yt_dlp/extractor/ciscolive.py
+++ b/yt_dlp/extractor/ciscolive.py
@@ -105,7 +105,7 @@ class CiscoLiveSearchIE(CiscoLiveBaseIE):
@classmethod
def suitable(cls, url):
- return False if CiscoLiveSessionIE.suitable(url) else super(CiscoLiveSearchIE, cls).suitable(url)
+ return False if CiscoLiveSessionIE.suitable(url) else super().suitable(url)
@staticmethod
def _check_bc_id_exists(rf_item):
@@ -117,7 +117,7 @@ def _entries(self, query, url):
for page_num in itertools.count(1):
results = self._call_api(
'search', None, query, url,
- 'Downloading search JSON page %d' % page_num)
+ f'Downloading search JSON page {page_num}')
sl = try_get(results, lambda x: x['sectionList'][0], dict)
if sl:
results = sl
diff --git a/yt_dlp/extractor/ciscowebex.py b/yt_dlp/extractor/ciscowebex.py
index 85585dffbb..d39347c82c 100644
--- a/yt_dlp/extractor/ciscowebex.py
+++ b/yt_dlp/extractor/ciscowebex.py
@@ -46,7 +46,7 @@ def _real_extract(self, url):
headers['accessPwd'] = password
stream, urlh = self._download_json_handle(
- 'https://%s.webex.com/webappng/api/v1/recordings/%s/stream' % (subdomain, video_id),
+ f'https://{subdomain}.webex.com/webappng/api/v1/recordings/{video_id}/stream',
video_id, headers=headers, query={'siteurl': siteurl}, expected_status=(403, 429))
if urlh.status == 403:
@@ -101,6 +101,6 @@ def _real_extract(self, url):
'uploader_id': stream.get('ownerUserName') or stream.get('ownerId'),
'timestamp': unified_timestamp(stream.get('createTime')),
'duration': int_or_none(stream.get('duration'), 1000),
- 'webpage_url': 'https://%s.webex.com/recordingservice/sites/%s/recording/playback/%s' % (subdomain, siteurl, video_id),
+ 'webpage_url': f'https://{subdomain}.webex.com/recordingservice/sites/{siteurl}/recording/playback/{video_id}',
'formats': formats,
}
diff --git a/yt_dlp/extractor/cjsw.py b/yt_dlp/extractor/cjsw.py
index c37a3b8482..b80236a7ee 100644
--- a/yt_dlp/extractor/cjsw.py
+++ b/yt_dlp/extractor/cjsw.py
@@ -27,7 +27,7 @@ class CJSWIE(InfoExtractor):
def _real_extract(self, url):
mobj = self._match_valid_url(url)
program, episode_id = mobj.group('program', 'id')
- audio_id = '%s/%s' % (program, episode_id)
+ audio_id = f'{program}/{episode_id}'
webpage = self._download_webpage(url, episode_id)
diff --git a/yt_dlp/extractor/clippit.py b/yt_dlp/extractor/clippit.py
index 67b56e00d9..393f217308 100644
--- a/yt_dlp/extractor/clippit.py
+++ b/yt_dlp/extractor/clippit.py
@@ -23,7 +23,7 @@ class ClippitIE(InfoExtractor):
'upload_date': '20160826',
'description': 'BattleBots | ABC',
'thumbnail': r're:^https?://.*\.jpg$',
- }
+ },
}
def _real_extract(self, url):
@@ -36,7 +36,7 @@ def _real_extract(self, url):
quality = qualities(FORMATS)
formats = []
for format_id in FORMATS:
- url = self._html_search_regex(r'data-%s-file="(.+?)"' % format_id,
+ url = self._html_search_regex(rf'data-{format_id}-file="(.+?)"',
webpage, 'url', fatal=False)
if not url:
continue
diff --git a/yt_dlp/extractor/cliprs.py b/yt_dlp/extractor/cliprs.py
index c2add02da4..42f78cac65 100644
--- a/yt_dlp/extractor/cliprs.py
+++ b/yt_dlp/extractor/cliprs.py
@@ -15,7 +15,7 @@ class ClipRsIE(OnetBaseIE):
'duration': 229,
'timestamp': 1459850243,
'upload_date': '20160405',
- }
+ },
}
def _real_extract(self, url):
diff --git a/yt_dlp/extractor/closertotruth.py b/yt_dlp/extractor/closertotruth.py
index 1f9a5f6114..77469eda99 100644
--- a/yt_dlp/extractor/closertotruth.py
+++ b/yt_dlp/extractor/closertotruth.py
@@ -15,7 +15,7 @@ class CloserToTruthIE(InfoExtractor):
'title': 'Solutions to the Mind-Body Problem?',
'upload_date': '20140221',
'timestamp': 1392956007,
- 'uploader_id': 'CTTXML'
+ 'uploader_id': 'CTTXML',
},
'params': {
'skip_download': True,
@@ -29,7 +29,7 @@ class CloserToTruthIE(InfoExtractor):
'title': 'How do Brains Work?',
'upload_date': '20140221',
'timestamp': 1392956024,
- 'uploader_id': 'CTTXML'
+ 'uploader_id': 'CTTXML',
},
'params': {
'skip_download': True,
@@ -69,7 +69,7 @@ def _real_extract(self, url):
entry_ids.add(entry_id)
entries.append({
'_type': 'url_transparent',
- 'url': 'kaltura:%s:%s' % (partner_id, entry_id),
+ 'url': f'kaltura:{partner_id}:{entry_id}',
'ie_key': 'Kaltura',
'title': mobj.group('title'),
})
@@ -83,7 +83,7 @@ def _real_extract(self, url):
return {
'_type': 'url_transparent',
'display_id': display_id,
- 'url': 'kaltura:%s:%s' % (partner_id, entry_id),
+ 'url': f'kaltura:{partner_id}:{entry_id}',
'ie_key': 'Kaltura',
- 'title': title
+ 'title': title,
}
diff --git a/yt_dlp/extractor/cloudflarestream.py b/yt_dlp/extractor/cloudflarestream.py
index a812c24af8..f902daacf6 100644
--- a/yt_dlp/extractor/cloudflarestream.py
+++ b/yt_dlp/extractor/cloudflarestream.py
@@ -53,7 +53,7 @@ class CloudflareStreamIE(InfoExtractor):
def _real_extract(self, url):
video_id = self._match_id(url)
domain = 'bytehighway.net' if 'bytehighway.net/' in url else 'videodelivery.net'
- base_url = 'https://%s/%s/' % (domain, video_id)
+ base_url = f'https://{domain}/{video_id}/'
if '.' in video_id:
video_id = self._parse_json(base64.urlsafe_b64decode(
video_id.split('.')[1] + '==='), video_id)['sub']
diff --git a/yt_dlp/extractor/cloudycdn.py b/yt_dlp/extractor/cloudycdn.py
index e6e470e073..58bde46663 100644
--- a/yt_dlp/extractor/cloudycdn.py
+++ b/yt_dlp/extractor/cloudycdn.py
@@ -22,7 +22,7 @@ class CloudyCDNIE(InfoExtractor):
'upload_date': '20231121',
'title': 'D23-6000-105_cetstud',
'thumbnail': 'https://store.cloudycdn.services/tmsp00060/assets/media/660858/placeholder1700589200.jpg',
- }
+ },
}, {
'url': 'https://embed.cloudycdn.services/izm/media/26e_lv-8-5-1',
'md5': '798828a479151e2444d8dcfbec76e482',
@@ -34,7 +34,7 @@ class CloudyCDNIE(InfoExtractor):
'thumbnail': 'https://store.cloudycdn.services/tmsp00120/assets/media/488306/placeholder1679423604.jpg',
'duration': 1205,
'upload_date': '20221130',
- }
+ },
}]
_WEBPAGE_TESTS = [{
'url': 'https://www.tavaklase.lv/video/es-esmu-mina-um-2/',
@@ -47,7 +47,7 @@ class CloudyCDNIE(InfoExtractor):
'thumbnail': 'https://store.cloudycdn.services/tmsp00120/assets/media/518407/placeholder1678748124.jpg',
'timestamp': 1677181513,
'title': 'LIB-2',
- }
+ },
}]
def _real_extract(self, url):
diff --git a/yt_dlp/extractor/clubic.py b/yt_dlp/extractor/clubic.py
index 716f259694..c908e61a1e 100644
--- a/yt_dlp/extractor/clubic.py
+++ b/yt_dlp/extractor/clubic.py
@@ -18,7 +18,7 @@ class ClubicIE(InfoExtractor):
'title': 'Clubic Week 2.0 : le FBI se lance dans la photo d\u0092identité',
'description': 're:Gueule de bois chez Nokia. Le constructeur a indiqué cette.*',
'thumbnail': r're:^http://img\.clubic\.com/.*\.jpg$',
- }
+ },
}, {
'url': 'http://www.clubic.com/video/video-clubic-week-2-0-apple-iphone-6s-et-plus-mais-surtout-le-pencil-469792.html',
'only_matching': True,
@@ -27,7 +27,7 @@ class ClubicIE(InfoExtractor):
def _real_extract(self, url):
video_id = self._match_id(url)
- player_url = 'http://player.m6web.fr/v1/player/clubic/%s.html' % video_id
+ player_url = f'http://player.m6web.fr/v1/player/clubic/{video_id}.html'
player_page = self._download_webpage(player_url, video_id)
config = self._parse_json(self._search_regex(
diff --git a/yt_dlp/extractor/clyp.py b/yt_dlp/extractor/clyp.py
index 273d0025f0..2702427c86 100644
--- a/yt_dlp/extractor/clyp.py
+++ b/yt_dlp/extractor/clyp.py
@@ -58,13 +58,13 @@ def _real_extract(self, url):
query['token'] = token
metadata = self._download_json(
- 'https://api.clyp.it/%s' % audio_id, audio_id, query=query)
+ f'https://api.clyp.it/{audio_id}', audio_id, query=query)
formats = []
for secure in ('', 'Secure'):
for ext in ('Ogg', 'Mp3'):
- format_id = '%s%s' % (secure, ext)
- format_url = metadata.get('%sUrl' % format_id)
+ format_id = f'{secure}{ext}'
+ format_url = metadata.get(f'{format_id}Url')
if format_url:
formats.append({
'url': format_url,
diff --git a/yt_dlp/extractor/cmt.py b/yt_dlp/extractor/cmt.py
index 6359102aa5..8e53b7fbf8 100644
--- a/yt_dlp/extractor/cmt.py
+++ b/yt_dlp/extractor/cmt.py
@@ -1,6 +1,6 @@
from .mtv import MTVIE
-# TODO Remove - Reason: Outdated Site
+# TODO: Remove - Reason: Outdated Site
class CMTIE(MTVIE): # XXX: Do not subclass from concrete IE
@@ -52,4 +52,4 @@ def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
mgid = self._extract_mgid(webpage, url)
- return self.url_result('http://media.mtvnservices.com/embed/%s' % mgid)
+ return self.url_result(f'http://media.mtvnservices.com/embed/{mgid}')
diff --git a/yt_dlp/extractor/cnn.py b/yt_dlp/extractor/cnn.py
index 61b62fae9f..fe7615a891 100644
--- a/yt_dlp/extractor/cnn.py
+++ b/yt_dlp/extractor/cnn.py
@@ -26,7 +26,7 @@ class CNNIE(TurnerBaseIE):
'id': 'us/2013/08/21/sot-student-gives-epic-speech.georgia-institute-of-technology',
'ext': 'mp4',
'title': "Student's epic speech stuns new freshmen",
- 'description': "A Georgia Tech student welcomes the incoming freshmen with an epic speech backed by music from \"2001: A Space Odyssey.\"",
+ 'description': 'A Georgia Tech student welcomes the incoming freshmen with an epic speech backed by music from "2001: A Space Odyssey."',
'upload_date': '20130821',
},
'expected_warnings': ['Failed to download m3u8 information'],
@@ -161,7 +161,7 @@ class CNNIndonesiaIE(InfoExtractor):
'release_timestamp': 1662859088,
'release_date': '20220911',
'uploader': 'Asfahan Yahsyi',
- }
+ },
}, {
'url': 'https://www.cnnindonesia.com/internasional/20220911104341-139-846189/video-momen-charles-disambut-meriah-usai-dilantik-jadi-raja-inggris',
'info_dict': {
@@ -178,7 +178,7 @@ class CNNIndonesiaIE(InfoExtractor):
'release_date': '20220911',
'uploader': 'REUTERS',
'release_timestamp': 1662869995,
- }
+ },
}]
def _real_extract(self, url):
@@ -194,5 +194,5 @@ def _real_extract(self, url):
'_type': 'url_transparent',
'url': embed_url,
'upload_date': upload_date,
- 'tags': try_call(lambda: self._html_search_meta('keywords', webpage).split(', '))
+ 'tags': try_call(lambda: self._html_search_meta('keywords', webpage).split(', ')),
})
diff --git a/yt_dlp/extractor/common.py b/yt_dlp/extractor/common.py
index 1d2c443c0b..2799747ece 100644
--- a/yt_dlp/extractor/common.py
+++ b/yt_dlp/extractor/common.py
@@ -60,7 +60,6 @@
determine_ext,
dict_get,
encode_data_uri,
- error_to_compat_str,
extract_attributes,
filter_dict,
fix_xml_ampersands,
@@ -767,8 +766,8 @@ def __maybe_fake_ip_and_retry(self, countries):
self._x_forwarded_for_ip = GeoUtils.random_ipv4(country_code)
if self._x_forwarded_for_ip:
self.report_warning(
- 'Video is geo restricted. Retrying extraction with fake IP %s (%s) as X-Forwarded-For.'
- % (self._x_forwarded_for_ip, country_code.upper()))
+ 'Video is geo restricted. Retrying extraction with fake IP '
+ f'{self._x_forwarded_for_ip} ({country_code.upper()}) as X-Forwarded-For.')
return True
return False
@@ -841,7 +840,7 @@ def _request_webpage(self, url_or_request, video_id, note=None, errnote=None, fa
if not self._downloader._first_webpage_request:
sleep_interval = self.get_param('sleep_interval_requests') or 0
if sleep_interval > 0:
- self.to_screen('Sleeping %s seconds ...' % sleep_interval)
+ self.to_screen(f'Sleeping {sleep_interval} seconds ...')
time.sleep(sleep_interval)
else:
self._downloader._first_webpage_request = False
@@ -898,7 +897,7 @@ def _request_webpage(self, url_or_request, video_id, note=None, errnote=None, fa
if errnote is None:
errnote = 'Unable to download webpage'
- errmsg = f'{errnote}: {error_to_compat_str(err)}'
+ errmsg = f'{errnote}: {err}'
if fatal:
raise ExtractorError(errmsg, cause=err)
else:
@@ -987,7 +986,7 @@ def __check_blocked(self, content):
r'