if opts.overwrites:
# --yes-overwrites implies --no-continue
opts.continue_dl = False
+ if opts.concurrent_fragment_downloads <= 0:
+ raise ValueError('Concurrent fragments must be positive')
def parse_retries(retries, name=''):
if retries in ('inf', 'infinite'):
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']:
+ if opts.convertsubtitles not in ('srt', 'vtt', 'ass', 'lrc'):
parser.error('invalid subtitle format specified')
+ if opts.convertthumbnails is not None:
+ if opts.convertthumbnails not in ('jpg', ):
+ parser.error('invalid thumbnail format specified')
if opts.date is not None:
date = DateRange.day(opts.date)
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.sponskrub_cut and opts.split_chapters and opts.sponskrub is not False:
+ report_conflict('--split-chapter', '--sponskrub-cut')
+ opts.sponskrub_cut = False
+
if opts.allow_unplayable_formats:
if opts.extractaudio:
report_conflict('--allow-unplayable-formats', '--extract-audio')
postprocessors.append({
'key': 'MetadataFromField',
'formats': opts.metafromfield,
- 'when': 'beforedl'
+ # Run this immediately after extraction is complete
+ 'when': 'pre_process'
+ })
+ if opts.convertsubtitles:
+ postprocessors.append({
+ 'key': 'FFmpegSubtitlesConvertor',
+ 'format': opts.convertsubtitles,
+ # Run this before the actual video download
+ 'when': 'before_dl'
+ })
+ if opts.convertthumbnails:
+ postprocessors.append({
+ 'key': 'FFmpegThumbnailsConvertor',
+ 'format': opts.convertthumbnails,
+ # Run this before the actual video download
+ 'when': 'before_dl'
})
if opts.extractaudio:
postprocessors.append({
# so metadata can be added here.
if opts.addmetadata:
postprocessors.append({'key': 'FFmpegMetadata'})
- if opts.convertsubtitles:
- postprocessors.append({
- 'key': 'FFmpegSubtitlesConvertor',
- 'format': opts.convertsubtitles,
- })
if opts.embedsubtitles:
already_have_subtitle = opts.writesubtitles
postprocessors.append({
'key': 'FFmpegEmbedSubtitle',
+ # already_have_subtitle = True prevents the file from being deleted after embedding
'already_have_subtitle': already_have_subtitle
})
if not already_have_subtitle:
# 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({
- 'key': 'EmbedThumbnail',
- 'already_have_thumbnail': already_have_thumbnail
- })
- if not already_have_thumbnail:
- opts.writethumbnail = True
- # XAttrMetadataPP should be run after post-processors that may change file
- # contents
- if opts.xattrs:
- postprocessors.append({'key': 'XAttrMetadata'})
- # This should be below all ffmpeg PP because it may cut parts out from the video
+ # This should be above EmbedThumbnail since sponskrub removes the thumbnail attachment
+ # but must be below EmbedSubtitle and FFmpegMetadata
+ # See https://github.com/yt-dlp/yt-dlp/issues/204 , https://github.com/faissaloo/SponSkrub/issues/29
# If opts.sponskrub is None, sponskrub is used, but it silently fails if the executable can't be found
if opts.sponskrub is not False:
postprocessors.append({
'force': opts.sponskrub_force,
'ignoreerror': opts.sponskrub is None,
})
+ if opts.embedthumbnail:
+ already_have_thumbnail = opts.writethumbnail or opts.write_all_thumbnails
+ postprocessors.append({
+ 'key': 'EmbedThumbnail',
+ # already_have_thumbnail = True prevents the file from being deleted after embedding
+ 'already_have_thumbnail': already_have_thumbnail
+ })
+ if not already_have_thumbnail:
+ opts.writethumbnail = True
+ if opts.split_chapters:
+ postprocessors.append({'key': 'FFmpegSplitChapters'})
+ # XAttrMetadataPP should be run after post-processors that may change file contents
+ if opts.xattrs:
+ postprocessors.append({'key': 'XAttrMetadata'})
# ExecAfterDownload must be the last PP
if opts.exec_cmd:
postprocessors.append({
'key': 'ExecAfterDownload',
'exec_cmd': opts.exec_cmd,
- 'when': 'aftermove'
+ # Run this only after the files have been moved to their final locations
+ 'when': 'after_move'
})
def report_args_compat(arg, name):
else match_filter_func(opts.match_filter))
ydl_opts = {
- 'convertsubtitles': opts.convertsubtitles,
'usenetrc': opts.usenetrc,
'username': opts.username,
'password': opts.password,
'extractor_retries': opts.extractor_retries,
'skip_unavailable_fragments': opts.skip_unavailable_fragments,
'keep_fragments': opts.keep_fragments,
+ 'concurrent_fragment_downloads': opts.concurrent_fragment_downloads,
'buffersize': opts.buffersize,
'noresizebuffer': opts.noresizebuffer,
'http_chunk_size': opts.http_chunk_size,
'writeannotations': opts.writeannotations,
'writeinfojson': opts.writeinfojson,
'allow_playlist_files': opts.allow_playlist_files,
+ 'clean_infojson': opts.clean_infojson,
'getcomments': opts.getcomments,
'writethumbnail': opts.writethumbnail,
'write_all_thumbnails': opts.write_all_thumbnails,