)
from .compat import (
compat_getpass,
- compat_shlex_split,
workaround_optparse_bug9161,
)
from .utils import (
DateRange,
decodeOption,
- DEFAULT_OUTTMPL,
DownloadError,
ExistingVideoReached,
expand_path,
preferredencoding,
read_batch_urls,
RejectedVideoReached,
+ REMUX_EXTENSIONS,
+ render_table,
SameFileError,
setproctitle,
std_headers,
write_string,
- render_table,
)
from .update import update_self
from .downloader import (
from .extractor import gen_extractors, list_extractors
from .extractor.common import InfoExtractor
from .extractor.adobepass import MSO_INFO
+from .postprocessor.metadatafromfield import MetadataFromFieldPP
from .YoutubeDL import YoutubeDL
opts.audioquality = opts.audioquality.strip('k').strip('K')
if not opts.audioquality.isdigit():
parser.error('invalid audio quality specified')
- if opts.remuxvideo is not None:
- if opts.remuxvideo not in ['mp4', 'mkv']:
- parser.error('invalid video container format specified')
if opts.recodevideo is not None:
- if opts.recodevideo not in ['mp4', 'flv', 'webm', 'ogg', 'mkv', 'avi']:
+ if opts.recodevideo not in REMUX_EXTENSIONS:
parser.error('invalid video recode format specified')
+ if opts.remuxvideo is not None:
+ opts.remuxvideo = opts.remuxvideo.replace(' ', '')
+ remux_regex = r'{0}(?:/{0})*$'.format(r'(?:\w+>)?(?:%s)' % '|'.join(REMUX_EXTENSIONS))
+ if not re.match(remux_regex, opts.remuxvideo):
+ parser.error('invalid video remux format specified')
if opts.convertsubtitles is not None:
if opts.convertsubtitles not in ['srt', 'vtt', 'ass', 'lrc']:
parser.error('invalid subtitle format specified')
if opts.extractaudio and not opts.keepvideo and opts.format is None:
opts.format = 'bestaudio/best'
- # --all-sub automatically sets --write-sub if --write-auto-sub is not given
- # this was the old behaviour if only --all-sub was given.
- if opts.allsubtitles and not opts.writeautomaticsub:
- opts.writesubtitles = True
-
- outtmpl = ((opts.outtmpl is not None and opts.outtmpl)
- or (opts.format == '-1' and opts.usetitle and '%(title)s-%(id)s-%(format)s.%(ext)s')
- or (opts.format == '-1' and '%(id)s-%(format)s.%(ext)s')
- or (opts.usetitle and opts.autonumber and '%(autonumber)s-%(title)s-%(id)s.%(ext)s')
- or (opts.usetitle and '%(title)s-%(id)s.%(ext)s')
- or (opts.useid and '%(id)s.%(ext)s')
- or (opts.autonumber and '%(autonumber)s-%(id)s.%(ext)s')
- or DEFAULT_OUTTMPL)
- if not os.path.splitext(outtmpl)[1] and opts.extractaudio:
+ outtmpl = opts.outtmpl
+ if not outtmpl:
+ outtmpl = {'default': (
+ '%(title)s-%(id)s-%(format)s.%(ext)s' if opts.format == '-1' and opts.usetitle
+ else '%(id)s-%(format)s.%(ext)s' if opts.format == '-1'
+ else '%(autonumber)s-%(title)s-%(id)s.%(ext)s' if opts.usetitle and opts.autonumber
+ else '%(title)s-%(id)s.%(ext)s' if opts.usetitle
+ else '%(id)s.%(ext)s' if opts.useid
+ else '%(autonumber)s-%(id)s.%(ext)s' if opts.autonumber
+ else None)}
+ outtmpl_default = outtmpl.get('default')
+ if outtmpl_default is not None and not os.path.splitext(outtmpl_default)[1] and opts.extractaudio:
parser.error('Cannot download a video and extract audio into the same'
' file! Use "{0}.%(ext)s" instead of "{0}" as the output'
- ' template'.format(outtmpl))
+ ' template'.format(outtmpl_default))
+
for f in opts.format_sort:
if re.match(InfoExtractor.FormatSort.regex, f) is None:
parser.error('invalid format sort string "%s" specified' % f)
+ if opts.metafromfield is None:
+ opts.metafromfield = []
+ if opts.metafromtitle is not None:
+ opts.metafromfield.append('title:%s' % opts.metafromtitle)
+ for f in opts.metafromfield:
+ if re.match(MetadataFromFieldPP.regex, f) is None:
+ parser.error('invalid format string "%s" specified for --parse-metadata' % f)
+
any_getting = opts.geturl or opts.gettitle or opts.getid or opts.getthumbnail or opts.getdescription or opts.getfilename or opts.getformat or opts.getduration or opts.dumpjson or opts.dump_single_json
any_printing = opts.print_json
download_archive_fn = expand_path(opts.download_archive) if opts.download_archive is not None else opts.download_archive
+ def report_conflict(arg1, arg2):
+ write_string('WARNING: %s is ignored since %s was given\n' % (arg2, arg1), out=sys.stderr)
+ if opts.remuxvideo and opts.recodevideo:
+ report_conflict('--recode-video', '--remux-video')
+ opts.remuxvideo = False
+ if opts.allow_unplayable_formats:
+ if opts.extractaudio:
+ report_conflict('--allow-unplayable-formats', '--extract-audio')
+ opts.extractaudio = False
+ if opts.remuxvideo:
+ report_conflict('--allow-unplayable-formats', '--remux-video')
+ opts.remuxvideo = False
+ if opts.recodevideo:
+ report_conflict('--allow-unplayable-formats', '--recode-video')
+ opts.recodevideo = False
+ if opts.addmetadata:
+ report_conflict('--allow-unplayable-formats', '--add-metadata')
+ opts.addmetadata = False
+ if opts.embedsubtitles:
+ report_conflict('--allow-unplayable-formats', '--embed-subs')
+ opts.embedsubtitles = False
+ if opts.embedthumbnail:
+ report_conflict('--allow-unplayable-formats', '--embed-thumbnail')
+ opts.embedthumbnail = False
+ if opts.xattrs:
+ report_conflict('--allow-unplayable-formats', '--xattrs')
+ opts.xattrs = False
+ if opts.fixup and opts.fixup.lower() not in ('never', 'ignore'):
+ report_conflict('--allow-unplayable-formats', '--fixup')
+ opts.fixup = 'never'
+ if opts.sponskrub:
+ report_conflict('--allow-unplayable-formats', '--sponskrub')
+ opts.sponskrub = False
+
# PostProcessors
postprocessors = []
- if opts.metafromtitle:
+ if opts.metafromfield:
postprocessors.append({
- 'key': 'MetadataFromTitle',
- 'titleformat': opts.metafromtitle
+ 'key': 'MetadataFromField',
+ 'formats': opts.metafromfield,
+ 'when': 'beforedl'
})
if opts.extractaudio:
postprocessors.append({
'format': opts.convertsubtitles,
})
if opts.embedsubtitles:
+ already_have_subtitle = opts.writesubtitles
postprocessors.append({
'key': 'FFmpegEmbedSubtitle',
+ 'already_have_subtitle': already_have_subtitle
})
+ if not already_have_subtitle:
+ opts.writesubtitles = True
+ # --all-sub automatically sets --write-sub if --write-auto-sub is not given
+ # this was the old behaviour if only --all-sub was given.
+ if opts.allsubtitles and not opts.writeautomaticsub:
+ opts.writesubtitles = True
if opts.embedthumbnail:
already_have_thumbnail = opts.writethumbnail or opts.write_all_thumbnails
postprocessors.append({
'force': opts.sponskrub_force,
'ignoreerror': opts.sponskrub is None,
})
- # Please keep ExecAfterDownload towards the bottom as it allows the user to modify the final file in any way.
- # So if the user is able to remove the file before your postprocessor runs it might cause a few problems.
+ # ExecAfterDownload must be the last PP
if opts.exec_cmd:
postprocessors.append({
'key': 'ExecAfterDownload',
'exec_cmd': opts.exec_cmd,
+ 'when': 'aftermove'
})
+ def report_args_compat(arg, name):
+ write_string(
+ 'WARNING: %s given without specifying name. The arguments will be given to all %s\n' % (arg, name),
+ out=sys.stderr)
+ if 'default' in opts.external_downloader_args:
+ report_args_compat('--external-downloader-args', 'external downloaders')
+
if 'default-compat' in opts.postprocessor_args and 'default' not in opts.postprocessor_args:
+ report_args_compat('--post-processor-args', 'post-processors')
opts.postprocessor_args.setdefault('sponskrub', [])
opts.postprocessor_args['default'] = opts.postprocessor_args['default-compat']
+ final_ext = (
+ opts.recodevideo
+ or (opts.remuxvideo in REMUX_EXTENSIONS) and opts.remuxvideo
+ or (opts.extractaudio and opts.audioformat != 'best') and opts.audioformat
+ or None)
+
match_filter = (
None if opts.match_filter is None
else match_filter_func(opts.match_filter))
'simulate': opts.simulate or any_getting,
'skip_download': opts.skip_download,
'format': opts.format,
+ 'allow_unplayable_formats': opts.allow_unplayable_formats,
'format_sort': opts.format_sort,
'format_sort_force': opts.format_sort_force,
'allow_multiple_video_streams': opts.allow_multiple_video_streams,
'listformats': opts.listformats,
'listformats_table': opts.listformats_table,
'outtmpl': outtmpl,
+ 'outtmpl_na_placeholder': opts.outtmpl_na_placeholder,
+ 'paths': opts.paths,
'autonumber_size': opts.autonumber_size,
'autonumber_start': opts.autonumber_start,
'restrictfilenames': opts.restrictfilenames,
+ 'windowsfilenames': opts.windowsfilenames,
'ignoreerrors': opts.ignoreerrors,
'force_generic_extractor': opts.force_generic_extractor,
'ratelimit': opts.ratelimit,
'playlistreverse': opts.playlist_reverse,
'playlistrandom': opts.playlist_random,
'noplaylist': opts.noplaylist,
- 'logtostderr': opts.outtmpl == '-',
+ 'logtostderr': outtmpl_default == '-',
'consoletitle': opts.consoletitle,
'nopart': opts.nopart,
'updatetime': opts.updatetime,
'writedescription': opts.writedescription,
'writeannotations': opts.writeannotations,
- 'writeinfojson': opts.writeinfojson,
+ 'writeinfojson': opts.writeinfojson or opts.getcomments,
+ 'allow_playlist_files': opts.allow_playlist_files,
+ 'getcomments': opts.getcomments,
'writethumbnail': opts.writethumbnail,
'write_all_thumbnails': opts.write_all_thumbnails,
'writelink': opts.writelink,
'extract_flat': opts.extract_flat,
'mark_watched': opts.mark_watched,
'merge_output_format': opts.merge_output_format,
+ 'final_ext': final_ext,
'postprocessors': postprocessors,
'fixup': opts.fixup,
'source_address': opts.source_address,
'ffmpeg_location': opts.ffmpeg_location,
'hls_prefer_native': opts.hls_prefer_native,
'hls_use_mpegts': opts.hls_use_mpegts,
+ 'hls_split_discontinuity': opts.hls_split_discontinuity,
'external_downloader_args': opts.external_downloader_args,
'postprocessor_args': opts.postprocessor_args,
'cn_verification_proxy': opts.cn_verification_proxy,
}
with YoutubeDL(ydl_opts) as ydl:
- # Update version
- if opts.update_self:
- update_self(ydl.to_screen, opts.verbose, ydl._opener)
+ actual_use = len(all_urls) or opts.load_info_filename
# Remove cache dir
if opts.rm_cachedir:
ydl.cache.remove()
+ # Update version
+ if opts.update_self:
+ # If updater returns True, exit. Required for windows
+ if update_self(ydl.to_screen, opts.verbose, ydl._opener):
+ if actual_use:
+ sys.exit('ERROR: The program must exit for the update to complete')
+ sys.exit()
+
# Maybe do nothing
- if (len(all_urls) < 1) and (opts.load_info_filename is None):
+ if not actual_use:
if opts.update_self or opts.rm_cachedir:
sys.exit()