aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesus <heckyel@riseup.net>2023-09-04 08:58:35 +0800
committerJesus <heckyel@riseup.net>2023-09-04 08:58:35 +0800
commitcae7fb9f44f16b45caa22914952fc35eb17ebf40 (patch)
treeffa0ec7d86c567fc60c01578b9301dc6b53965b3
parentb3013540b41d1eb77c4803c5fca46f8d75b40fc1 (diff)
downloadhypervideo-cae7fb9f44f16b45caa22914952fc35eb17ebf40.tar.lz
hypervideo-cae7fb9f44f16b45caa22914952fc35eb17ebf40.tar.xz
hypervideo-cae7fb9f44f16b45caa22914952fc35eb17ebf40.zip
yt_dlp/__init__.py: minor fix
-rw-r--r--hypervideo_dl/__init__.py127
1 files changed, 69 insertions, 58 deletions
diff --git a/hypervideo_dl/__init__.py b/hypervideo_dl/__init__.py
index 60b012f..275ab85 100644
--- a/hypervideo_dl/__init__.py
+++ b/hypervideo_dl/__init__.py
@@ -3,6 +3,7 @@ f'You are using an unsupported version of Python. Only Python versions 3.6 and a
__license__ = 'CC0-1.0'
+import collections
import getpass
import itertools
import optparse
@@ -11,16 +12,16 @@ import re
import sys
import traceback
-from .compat import compat_shlex_quote, workaround_optparse_bug9161
+from .compat import compat_shlex_quote
from .cookies import SUPPORTED_BROWSERS, SUPPORTED_KEYRINGS
-from .downloader import FileDownloader
from .downloader.external import get_external_downloader
from .extractor import list_extractor_classes
from .extractor.adobepass import MSO_INFO
-from .extractor.common import InfoExtractor
from .options import parseOpts
from .postprocessor import (
FFmpegExtractAudioPP,
+ FFmpegMergerPP,
+ FFmpegPostProcessor,
FFmpegSubtitlesConvertorPP,
FFmpegThumbnailsConvertorPP,
FFmpegVideoConvertorPP,
@@ -34,6 +35,7 @@ from .utils import (
DateRange,
DownloadCancelled,
DownloadError,
+ FormatSorter,
GeoUtils,
PlaylistEntries,
SameFileError,
@@ -44,6 +46,7 @@ from .utils import (
format_field,
int_or_none,
match_filter_func,
+ parse_bytes,
parse_duration,
preferredencoding,
read_batch_urls,
@@ -57,6 +60,8 @@ from .utils import (
from .utils.networking import std_headers
from .YoutubeDL import YoutubeDL
+_IN_CLI = False
+
def _exit(status=0, *args):
for msg in args:
@@ -98,22 +103,17 @@ def print_extractor_information(opts, urls):
urls.update(dict.fromkeys(matched_urls, True))
out += ''.join(f' {url}\n' for url in matched_urls)
elif opts.list_extractor_descriptions:
- for ie in list_extractors(opts.age_limit):
- if not ie.working():
- continue
- if ie.IE_DESC is False:
- continue
- desc = ie.IE_DESC or ie.IE_NAME
- if getattr(ie, 'SEARCH_KEY', None) is not None:
- _SEARCHES = ('cute kittens', 'slithering pythons', 'falling cat', 'angry poodle', 'purple fish', 'running tortoise', 'sleeping bunny', 'burping cow')
- _COUNTS = ('', '5', '10', 'all')
- desc += f'; "{ie.SEARCH_KEY}:" prefix (Example: "{ie.SEARCH_KEY}{random.choice(_COUNTS)}:{random.choice(_SEARCHES)}")'
- write_string(desc + '\n', out=sys.stdout)
+ _SEARCHES = ('cute kittens', 'slithering pythons', 'falling cat', 'angry poodle', 'purple fish', 'running tortoise', 'sleeping bunny', 'burping cow')
+ out = '\n'.join(
+ ie.description(markdown=False, search_examples=_SEARCHES)
+ for ie in list_extractor_classes(opts.age_limit) if ie.working() and ie.IE_DESC is not False)
elif opts.ap_list_mso:
- table = [[mso_id, mso_info['name']] for mso_id, mso_info in MSO_INFO.items()]
- write_string('Supported TV Providers:\n' + render_table(['mso', 'mso name'], table) + '\n', out=sys.stdout)
+ out = 'Supported TV Providers:\n%s\n' % render_table(
+ ['mso', 'mso name'],
+ [[mso_id, mso_info['name']] for mso_id, mso_info in MSO_INFO.items()])
else:
return False
+ write_string(out, out=sys.stdout)
return True
@@ -148,7 +148,7 @@ def set_compat_opts(opts):
else:
opts.embed_infojson = False
if 'format-sort' in opts.compat_opts:
- opts.format_sort.extend(InfoExtractor.FormatSort.ytdl_default)
+ opts.format_sort.extend(FormatSorter.ytdl_default)
_video_multistreams_set = set_default_compat('multistreams', 'allow_multiple_video_streams', False, remove_compat=False)
_audio_multistreams_set = set_default_compat('multistreams', 'allow_multiple_audio_streams', False, remove_compat=False)
if _video_multistreams_set is False and _audio_multistreams_set is False:
@@ -223,9 +223,11 @@ def validate_options(opts):
# Format sort
for f in opts.format_sort:
- validate_regex('format sorting', f, InfoExtractor.FormatSort.regex)
+ validate_regex('format sorting', f, FormatSorter.regex)
# Postprocessor formats
+ validate_regex('merge output format', opts.merge_output_format,
+ r'({0})(/({0}))*'.format('|'.join(map(re.escape, FFmpegMergerPP.SUPPORTED_EXTS))))
validate_regex('audio format', opts.audioformat, FFmpegExtractAudioPP.FORMAT_RE)
validate_in('subtitle format', opts.convertsubtitles, FFmpegSubtitlesConvertorPP.SUPPORTED_EXTS)
validate_regex('thumbnail format', opts.convertthumbnails, FFmpegThumbnailsConvertorPP.FORMAT_RE)
@@ -275,19 +277,19 @@ def validate_options(opts):
raise ValueError(f'invalid {key} retry sleep expression {expr!r}')
# Bytes
- def parse_bytes(name, value):
+ def validate_bytes(name, value):
if value is None:
return None
- numeric_limit = FileDownloader.parse_bytes(value)
+ numeric_limit = parse_bytes(value)
validate(numeric_limit is not None, 'rate limit', value)
return numeric_limit
- opts.ratelimit = parse_bytes('rate limit', opts.ratelimit)
- opts.throttledratelimit = parse_bytes('throttled rate limit', opts.throttledratelimit)
- opts.min_filesize = parse_bytes('min filesize', opts.min_filesize)
- opts.max_filesize = parse_bytes('max filesize', opts.max_filesize)
- opts.buffersize = parse_bytes('buffer size', opts.buffersize)
- opts.http_chunk_size = parse_bytes('http chunk size', opts.http_chunk_size)
+ opts.ratelimit = validate_bytes('rate limit', opts.ratelimit)
+ opts.throttledratelimit = validate_bytes('throttled rate limit', opts.throttledratelimit)
+ opts.min_filesize = validate_bytes('min filesize', opts.min_filesize)
+ opts.max_filesize = validate_bytes('max filesize', opts.max_filesize)
+ opts.buffersize = validate_bytes('buffer size', opts.buffersize)
+ opts.http_chunk_size = validate_bytes('http chunk size', opts.http_chunk_size)
# Output templates
def validate_outtmpl(tmpl, msg):
@@ -369,7 +371,7 @@ def validate_options(opts):
''', opts.cookiesfrombrowser)
if mobj is None:
raise ValueError(f'invalid cookies from browser arguments: {opts.cookiesfrombrowser}')
- browser_name, keyring, profile = mobj.group('name', 'keyring', 'profile')
+ browser_name, keyring, profile, container = mobj.group('name', 'keyring', 'profile', 'container')
browser_name = browser_name.lower()
if browser_name not in SUPPORTED_BROWSERS:
raise ValueError(f'unsupported browser specified for cookies: "{browser_name}". '
@@ -379,7 +381,7 @@ def validate_options(opts):
if keyring not in SUPPORTED_KEYRINGS:
raise ValueError(f'unsupported keyring specified for cookies: "{keyring}". '
f'Supported keyrings are: {", ".join(sorted(SUPPORTED_KEYRINGS))}')
- opts.cookiesfrombrowser = (browser_name, profile, keyring)
+ opts.cookiesfrombrowser = (browser_name, profile, keyring, container)
# MetadataParser
def metadataparser_actions(f):
@@ -431,6 +433,9 @@ def validate_options(opts):
if opts.download_archive is not None:
opts.download_archive = expand_path(opts.download_archive)
+ if opts.ffmpeg_location is not None:
+ opts.ffmpeg_location = expand_path(opts.ffmpeg_location)
+
if opts.user_agent is not None:
opts.headers.setdefault('User-Agent', opts.user_agent)
if opts.referer is not None:
@@ -499,22 +504,24 @@ def validate_options(opts):
report_conflict('--playlist-random', 'playlist_random', '--lazy-playlist', 'lazy_playlist')
report_conflict('--dateafter', 'dateafter', '--date', 'date', default=None)
report_conflict('--datebefore', 'datebefore', '--date', 'date', default=None)
- report_conflict('--exec-before-download', 'exec_before_dl_cmd', '"--exec before_dl:"', 'exec_cmd', opts.exec_cmd.get('before_dl'))
+ report_conflict('--exec-before-download', 'exec_before_dl_cmd',
+ '"--exec before_dl:"', 'exec_cmd', val2=opts.exec_cmd.get('before_dl'))
report_conflict('--id', 'useid', '--output', 'outtmpl', val2=opts.outtmpl.get('default'))
report_conflict('--remux-video', 'remuxvideo', '--recode-video', 'recodevideo')
report_conflict('--sponskrub', 'sponskrub', '--remove-chapters', 'remove_chapters')
report_conflict('--sponskrub', 'sponskrub', '--sponsorblock-mark', 'sponsorblock_mark')
report_conflict('--sponskrub', 'sponskrub', '--sponsorblock-remove', 'sponsorblock_remove')
- report_conflict('--sponskrub-cut', 'sponskrub_cut', '--split-chapter', 'split_chapters', val1=opts.sponskrub and opts.sponskrub_cut)
+ report_conflict('--sponskrub-cut', 'sponskrub_cut', '--split-chapter', 'split_chapters',
+ val1=opts.sponskrub and opts.sponskrub_cut)
# Conflicts with --allow-unplayable-formats
- report_conflict('--add-metadata', 'addmetadata')
+ report_conflict('--embed-metadata', 'addmetadata')
report_conflict('--embed-chapters', 'addchapters')
report_conflict('--embed-info-json', 'embed_infojson')
report_conflict('--embed-subs', 'embedsubtitles')
report_conflict('--embed-thumbnail', 'embedthumbnail')
report_conflict('--extract-audio', 'extractaudio')
- report_conflict('--fixup', 'fixup', val1=(opts.fixup or '').lower() in ('', 'never', 'ignore'), default='never')
+ report_conflict('--fixup', 'fixup', val1=opts.fixup not in (None, 'never', 'ignore'), default='never')
report_conflict('--recode-video', 'recodevideo')
report_conflict('--remove-chapters', 'remove_chapters', default=[])
report_conflict('--remux-video', 'remuxvideo')
@@ -556,7 +563,7 @@ def validate_options(opts):
# Do not unnecessarily download audio
opts.format = 'bestaudio/best'
- if opts.getcomments and opts.writeinfojson is None:
+ if opts.getcomments and opts.writeinfojson is None and not opts.embed_infojson:
# If JSON is not printed anywhere, but comments are requested, save it to file
if not opts.dumpjson or opts.print_json or opts.dump_single_json:
opts.writeinfojson = True
@@ -705,8 +712,11 @@ def get_postprocessors(opts):
}
+ParsedOptions = collections.namedtuple('ParsedOptions', ('parser', 'options', 'urls', 'ydl_opts'))
+
+
def parse_options(argv=None):
- """ @returns (parser, opts, urls, ydl_opts) """
+ """@returns ParsedOptions(parser, opts, urls, ydl_opts)"""
parser, opts, urls = parseOpts(argv)
urls = get_urls(urls, opts.batchfile, opts.verbose)
@@ -726,7 +736,20 @@ def parse_options(argv=None):
if opts.quiet is None:
opts.quiet = any_getting or opts.print_json or bool(opts.forceprint)
- any_printing = opts.print_json
+ playlist_pps = [pp for pp in postprocessors if pp.get('when') == 'playlist']
+ write_playlist_infojson = (opts.writeinfojson and not opts.clean_infojson
+ and opts.allow_playlist_files and opts.outtmpl.get('pl_infojson') != '')
+ if not any((
+ opts.extract_flat,
+ opts.dump_single_json,
+ opts.forceprint.get('playlist'),
+ opts.print_to_file.get('playlist'),
+ write_playlist_infojson,
+ )):
+ if not playlist_pps:
+ opts.extract_flat = 'discard'
+ elif playlist_pps == [{'key': 'FFmpegConcat', 'only_multi_video': True, 'when': 'playlist'}]:
+ opts.extract_flat = 'discard_in_playlist'
final_ext = (
opts.recodevideo if opts.recodevideo in FFmpegVideoConvertorPP.SUPPORTED_EXTS
@@ -734,7 +757,7 @@ def parse_options(argv=None):
else opts.audioformat if (opts.extractaudio and opts.audioformat in FFmpegExtractAudioPP.SUPPORTED_EXTS)
else None)
- return parser, opts, urls, {
+ return ParsedOptions(parser, opts, urls, {
'usenetrc': opts.usenetrc,
'netrc_location': opts.netrc_location,
'netrc_cmd': opts.netrc_cmd,
@@ -763,7 +786,7 @@ def parse_options(argv=None):
'forcejson': opts.dumpjson or opts.print_json,
'dump_single_json': opts.dump_single_json,
'force_write_download_archive': opts.force_write_download_archive,
- 'simulate': (any_getting or None) if opts.simulate is None else opts.simulate,
+ 'simulate': (print_only or any_getting or None) if opts.simulate is None else opts.simulate,
'skip_download': opts.skip_download,
'format': opts.format,
'allow_unplayable_formats': opts.allow_unplayable_formats,
@@ -784,6 +807,7 @@ def parse_options(argv=None):
'windowsfilenames': opts.windowsfilenames,
'ignoreerrors': opts.ignoreerrors,
'force_generic_extractor': opts.force_generic_extractor,
+ 'allowed_extractors': opts.allowed_extractors or ['default'],
'ratelimit': opts.ratelimit,
'throttledratelimit': opts.throttledratelimit,
'overwrites': opts.overwrites,
@@ -909,17 +933,10 @@ def parse_options(argv=None):
'_warnings': warnings,
'_deprecation_warnings': deprecation_warnings,
'compat_opts': opts.compat_opts,
- }
+ })
def _real_main(argv=None):
- # Compatibility fixes for Windows
- if sys.platform == 'win32':
- # https://github.com/ytdl-org/youtube-dl/issues/820
- codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)
-
- workaround_optparse_bug9161()
-
setproctitle('hypervideo')
parser, opts, all_urls, ydl_opts = parse_options(argv)
@@ -933,6 +950,11 @@ def _real_main(argv=None):
if print_extractor_information(opts, all_urls):
return
+ # We may need ffmpeg_location without having access to the YoutubeDL instance
+ # See https://github.com/hypervideo/hypervideo/issues/2191
+ if opts.ffmpeg_location:
+ FFmpegPostProcessor._ffmpeg_location.set(opts.ffmpeg_location)
+
with YoutubeDL(ydl_opts) as ydl:
pre_process = opts.update_self or opts.rm_cachedir
actual_use = all_urls or opts.load_info_filename
@@ -940,19 +962,6 @@ def _real_main(argv=None):
if opts.rm_cachedir:
ydl.cache.remove()
- try:
- updater = Updater(ydl, opts.update_self)
- if opts.update_self and updater.update() and actual_use:
- if updater.cmd:
- return updater.restart()
- # This code is reachable only for zip variant in py < 3.10
- # It makes sense to exit here, but the old behavior is to continue
- ydl.report_warning('Restart hypervideo to use the updated version')
- # return 100, 'ERROR: The program must exit for the update to complete'
- except Exception:
- traceback.print_exc()
- ydl._download_retcode = 100
-
if not actual_use:
if pre_process:
return ydl._download_retcode
@@ -976,6 +985,8 @@ def _real_main(argv=None):
def main(argv=None):
+ global _IN_CLI
+ _IN_CLI = True
try:
_exit(*variadic(_real_main(argv)))
except DownloadError: