kopia lustrzana https://github.com/yt-dlp/yt-dlp
Porównaj commity
8 Commity
52f0b6f1ce
...
ca168c9a46
Autor | SHA1 | Data |
---|---|---|
TuxCoder | ca168c9a46 | |
Simon Sawicki | 64766459e3 | |
bashonly | 89f535e265 | |
tuxcoder | f51d16b307 | |
tuxcoder | 90a4ecb25a | |
tuxcoder | 501f7e068e | |
tuxcoder | 8c6550ae43 | |
tuxcoder | f9c443ba2c |
|
@ -53,7 +53,7 @@ jobs:
|
|||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install test requirements
|
||||
run: python3 ./devscripts/install_deps.py --include dev --include curl_cffi
|
||||
run: python3 ./devscripts/install_deps.py --include dev --include curl-cffi
|
||||
- name: Run tests
|
||||
continue-on-error: False
|
||||
run: |
|
||||
|
|
|
@ -2059,7 +2059,22 @@ Line 1
|
|||
assert extract_basic_auth('http://user:pass@foo.bar') == ('http://foo.bar', 'Basic dXNlcjpwYXNz')
|
||||
|
||||
@unittest.skipUnless(compat_os_name == 'nt', 'Only relevant on Windows')
|
||||
def test_Popen_windows_escaping(self):
|
||||
def test_windows_escaping(self):
|
||||
tests = [
|
||||
'test"&',
|
||||
'%CMDCMDLINE:~-1%&',
|
||||
'a\nb',
|
||||
'"',
|
||||
'\\',
|
||||
'!',
|
||||
'^!',
|
||||
'a \\ b',
|
||||
'a \\" b',
|
||||
'a \\ b\\',
|
||||
# We replace \r with \n
|
||||
('a\r\ra', 'a\n\na'),
|
||||
]
|
||||
|
||||
def run_shell(args):
|
||||
stdout, stderr, error = Popen.run(
|
||||
args, text=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
@ -2067,15 +2082,18 @@ Line 1
|
|||
assert not error
|
||||
return stdout
|
||||
|
||||
# Test escaping
|
||||
assert run_shell(['echo', 'test"&']) == '"test""&"\n'
|
||||
assert run_shell(['echo', '%CMDCMDLINE:~-1%&']) == '"%CMDCMDLINE:~-1%&"\n'
|
||||
assert run_shell(['echo', 'a\nb']) == '"a"\n"b"\n'
|
||||
assert run_shell(['echo', '"']) == '""""\n'
|
||||
assert run_shell(['echo', '\\']) == '\\\n'
|
||||
# Test if delayed expansion is disabled
|
||||
assert run_shell(['echo', '^!']) == '"^!"\n'
|
||||
assert run_shell('echo "^!"') == '"^!"\n'
|
||||
for argument in tests:
|
||||
if isinstance(argument, str):
|
||||
expected = argument
|
||||
else:
|
||||
argument, expected = argument
|
||||
|
||||
args = [sys.executable, '-c', 'import sys; print(end=sys.argv[1])', argument, 'end']
|
||||
assert run_shell(args) == expected
|
||||
|
||||
escaped = shell_quote(argument, shell=True)
|
||||
args = f'{sys.executable} -c "import sys; print(end=sys.argv[1])" {escaped} end'
|
||||
assert run_shell(args) == expected
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -569,19 +569,20 @@ class ORFFM4StoryIE(InfoExtractor):
|
|||
|
||||
class ORFONIE(InfoExtractor):
|
||||
IE_NAME = 'orf:on'
|
||||
_VALID_URL = r'https?://on\.orf\.at/video/(?P<id>\d{8})/(?P<slug>[\w-]+)'
|
||||
_VALID_URL = r'https?://on\.orf\.at/video/(?P<id>\d+)(/(?P<slug>[\w-]+))?'
|
||||
_TESTS = [{
|
||||
'url': 'https://on.orf.at/video/14210000/school-of-champions-48',
|
||||
'url': 'https://on.orf.at/video/3220355',
|
||||
'md5': 'f94d98e667cf9a3851317efb4e136662',
|
||||
'info_dict': {
|
||||
'id': '14210000',
|
||||
'id': '3220355',
|
||||
'ext': 'mp4',
|
||||
'duration': 2651.08,
|
||||
'thumbnail': 'https://api-tvthek.orf.at/assets/segments/0167/98/thumb_16697671_segments_highlight_teaser.jpeg',
|
||||
'title': 'School of Champions (4/8)',
|
||||
'description': 'md5:d09ad279fc2e8502611e7648484b6afd',
|
||||
'duration': 445.04,
|
||||
'thumbnail': 'https://api-tvthek.orf.at/assets/segments/0002/60/thumb_159573_segments_highlight_teaser.png',
|
||||
'title': '50 Jahre Burgenland: Der Festumzug',
|
||||
'description': 'md5:1560bf855119544ee8c4fa5376a2a6b0',
|
||||
'media_type': 'episode',
|
||||
'timestamp': 1706472362,
|
||||
'upload_date': '20240128',
|
||||
'timestamp': 52916400,
|
||||
'upload_date': '19710905',
|
||||
}
|
||||
}]
|
||||
|
||||
|
@ -590,6 +591,9 @@ class ORFONIE(InfoExtractor):
|
|||
api_json = self._download_json(
|
||||
f'https://api-tvthek.orf.at/api/v4.3/public/episode/encrypted/{encrypted_id}', display_id)
|
||||
|
||||
if traverse_obj(api_json, 'is_drm_protected'):
|
||||
self.report_drm(video_id)
|
||||
|
||||
formats, subtitles = [], {}
|
||||
for manifest_type in traverse_obj(api_json, ('sources', {dict.keys}, ...)):
|
||||
for manifest_url in traverse_obj(api_json, ('sources', manifest_type, ..., 'src', {url_or_none})):
|
||||
|
@ -604,10 +608,33 @@ class ORFONIE(InfoExtractor):
|
|||
formats.extend(fmts)
|
||||
self._merge_subtitles(subs, target=subtitles)
|
||||
|
||||
for subtitle_type in ['vtt']: # not working formats 'xml', 'srt', 'sami', 'ttml', 'stl'
|
||||
subtitle_url = traverse_obj(api_json, ('_embedded', 'subtitle', f'{subtitle_type}_url'), {str})
|
||||
if subtitle_url is None:
|
||||
continue
|
||||
self._merge_subtitles({
|
||||
'de': [
|
||||
{
|
||||
'url': subtitle_url,
|
||||
'ext': f'{subtitle_type}',
|
||||
}
|
||||
],
|
||||
}, target=subtitles)
|
||||
|
||||
age_classification = traverse_obj(api_json, ('age_classification'), {str})
|
||||
age_limit = None
|
||||
if isinstance(age_classification, str) and len(age_classification) != 0:
|
||||
# age_classification is in the format `<age:int>+`
|
||||
# example: "6+" or "18+"
|
||||
age_limit_str = age_classification[:-1]
|
||||
if age_limit_str.isdigit():
|
||||
age_limit = int(age_limit_str)
|
||||
|
||||
return {
|
||||
'id': video_id,
|
||||
'formats': formats,
|
||||
'subtitles': subtitles,
|
||||
'age_limit': age_limit,
|
||||
**traverse_obj(api_json, {
|
||||
'duration': ('duration_second', {float_or_none}),
|
||||
'title': (('title', 'headline'), {str}),
|
||||
|
@ -618,6 +645,8 @@ class ORFONIE(InfoExtractor):
|
|||
|
||||
def _real_extract(self, url):
|
||||
video_id, display_id = self._match_valid_url(url).group('id', 'slug')
|
||||
if display_id is None:
|
||||
display_id = video_id
|
||||
webpage = self._download_webpage(url, display_id)
|
||||
|
||||
return {
|
||||
|
|
|
@ -1638,16 +1638,14 @@ def get_filesystem_encoding():
|
|||
return encoding if encoding is not None else 'utf-8'
|
||||
|
||||
|
||||
_WINDOWS_QUOTE_TRANS = str.maketrans({'"': '\\"', '\\': '\\\\'})
|
||||
_WINDOWS_QUOTE_TRANS = str.maketrans({'"': R'\"'})
|
||||
_CMD_QUOTE_TRANS = str.maketrans({
|
||||
# Keep quotes balanced by replacing them with `""` instead of `\\"`
|
||||
'"': '""',
|
||||
# Requires a variable `=` containing `"^\n\n"` (set in `utils.Popen`)
|
||||
# These require an env-variable `=` containing `"^\n\n"` (set in `utils.Popen`)
|
||||
# `=` should be unique since variables containing `=` cannot be set using cmd
|
||||
'\n': '%=%',
|
||||
# While we are only required to escape backslashes immediately before quotes,
|
||||
# we instead escape all of 'em anyways to be consistent
|
||||
'\\': '\\\\',
|
||||
'\r': '%=%',
|
||||
# Use zero length variable replacement so `%` doesn't get expanded
|
||||
# `cd` is always set as long as extensions are enabled (`/E:ON` in `utils.Popen`)
|
||||
'%': '%%cd:~,%',
|
||||
|
@ -1656,19 +1654,14 @@ _CMD_QUOTE_TRANS = str.maketrans({
|
|||
|
||||
def shell_quote(args, *, shell=False):
|
||||
args = list(variadic(args))
|
||||
if any(isinstance(item, bytes) for item in args):
|
||||
deprecation_warning('Passing bytes to utils.shell_quote is deprecated')
|
||||
encoding = get_filesystem_encoding()
|
||||
for index, item in enumerate(args):
|
||||
if isinstance(item, bytes):
|
||||
args[index] = item.decode(encoding)
|
||||
|
||||
if compat_os_name != 'nt':
|
||||
return shlex.join(args)
|
||||
|
||||
trans = _CMD_QUOTE_TRANS if shell else _WINDOWS_QUOTE_TRANS
|
||||
return ' '.join(
|
||||
s if re.fullmatch(r'[\w#$*\-+./:?@\\]+', s, re.ASCII) else s.translate(trans).join('""')
|
||||
s if re.fullmatch(r'[\w#$*\-+./:?@\\]+', s, re.ASCII)
|
||||
else re.sub(r'(\\+)("|$)', r'\1\1\2', s).translate(trans).join('""')
|
||||
for s in args)
|
||||
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue