aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md26
-rw-r--r--youtube_dlc/YoutubeDL.py139
-rw-r--r--youtube_dlc/__init__.py25
-rw-r--r--youtube_dlc/options.py15
-rw-r--r--youtube_dlc/postprocessor/embedthumbnail.py9
-rw-r--r--youtube_dlc/postprocessor/ffmpeg.py4
-rw-r--r--youtube_dlc/postprocessor/movefilesafterdownload.py3
-rw-r--r--youtube_dlc/utils.py13
8 files changed, 136 insertions, 98 deletions
diff --git a/README.md b/README.md
index 2ff137e45..60d32d6e3 100644
--- a/README.md
+++ b/README.md
@@ -333,16 +333,16 @@ Then simply type this
comments and ignored
-P, --paths TYPE:PATH The paths where the files should be
downloaded. Specify the type of file and
- the path separated by a colon ":"
- (supported: description|annotation|subtitle
- |infojson|thumbnail). Additionally, you can
- also provide "home" and "temp" paths. All
- intermediary files are first downloaded to
- the temp path and then the final files are
- moved over to the home path after download
- is finished. Note that this option is
- ignored if --output is an absolute path
- -o, --output TEMPLATE Output filename template, see "OUTPUT
+ the path separated by a colon ":". All the
+ same types as --output are supported.
+ Additionally, you can also provide "home"
+ and "temp" paths. All intermediary files
+ are first downloaded to the temp path and
+ then the final files are moved over to the
+ home path after download is finished. This
+ option is ignored if --output is an
+ absolute path
+ -o, --output [TYPE:]TEMPLATE Output filename template, see "OUTPUT
TEMPLATE" for details
--output-na-placeholder TEXT Placeholder value for unavailable meta
fields in output filename template
@@ -751,7 +751,9 @@ The `-o` option is used to indicate a template for the output file names while `
**tl;dr:** [navigate me to examples](#output-template-examples).
-The basic usage of `-o` is not to set any template arguments when downloading a single file, like in `youtube-dlc -o funny_video.flv "https://some/video"`. However, it may contain special sequences that will be replaced when downloading each video. The special sequences may be formatted according to [python string formatting operations](https://docs.python.org/2/library/stdtypes.html#string-formatting). For example, `%(NAME)s` or `%(NAME)05d`. To clarify, that is a percent symbol followed by a name in parentheses, followed by formatting operations. Additionally, date/time fields can be formatted according to [strftime formatting](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes) by specifying it inside the parantheses seperated from the field name using a `>`. For example, `%(duration>%H-%M-%S)s`.
+The basic usage of `-o` is not to set any template arguments when downloading a single file, like in `youtube-dlc -o funny_video.flv "https://some/video"`. However, it may contain special sequences that will be replaced when downloading each video. The special sequences may be formatted according to [python string formatting operations](https://docs.python.org/2/library/stdtypes.html#string-formatting). For example, `%(NAME)s` or `%(NAME)05d`. To clarify, that is a percent symbol followed by a name in parentheses, followed by formatting operations. Date/time fields can also be formatted according to [strftime formatting](https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes) by specifying it inside the parantheses seperated from the field name using a `>`. For example, `%(duration>%H-%M-%S)s`.
+
+Additionally, you can set different output templates for the various metadata files seperately from the general output template by specifying the type of file followed by the template seperated by a colon ":". The different filetypes supported are subtitle|thumbnail|description|annotation|infojson|pl_description|pl_infojson. For example, `-o '%(title)s.%(ext)s' -o 'thumbnail:%(title)s\%(title)s.%(ext)s'` will put the thumbnails in a folder with the same name as the video.
The available fields are:
@@ -860,7 +862,7 @@ If you are using an output template inside a Windows batch file then you must es
#### Output template examples
-Note that on Windows you may need to use double quotes instead of single.
+Note that on Windows you need to use double quotes instead of single.
```bash
$ youtube-dlc --get-filename -o '%(title)s.%(ext)s' BaW_jenozKc
diff --git a/youtube_dlc/YoutubeDL.py b/youtube_dlc/YoutubeDL.py
index da5001f07..9631745de 100644
--- a/youtube_dlc/YoutubeDL.py
+++ b/youtube_dlc/YoutubeDL.py
@@ -49,6 +49,7 @@ from .utils import (
date_from_str,
DateRange,
DEFAULT_OUTTMPL,
+ OUTTMPL_TYPES,
determine_ext,
determine_protocol,
DOT_DESKTOP_LINK_TEMPLATE,
@@ -182,7 +183,8 @@ class YoutubeDL(object):
format_sort_force: Force the given format_sort. see "Sorting Formats" for more details.
allow_multiple_video_streams: Allow multiple video streams to be merged into a single file
allow_multiple_audio_streams: Allow multiple audio streams to be merged into a single file
- outtmpl: Template for output names.
+ outtmpl: Dictionary of templates for output names. Allowed keys
+ are 'default' and the keys of OUTTMPL_TYPES (in utils.py)
outtmpl_na_placeholder: Placeholder for unavailable meta fields.
restrictfilenames: Do not allow "&" and spaces in file names
trim_file_name: Limit length of filename (extension excluded)
@@ -493,10 +495,7 @@ class YoutubeDL(object):
'Set the LC_ALL environment variable to fix this.')
self.params['restrictfilenames'] = True
- if isinstance(params.get('outtmpl'), bytes):
- self.report_warning(
- 'Parameter outtmpl is bytes, but should be a unicode string. '
- 'Put from __future__ import unicode_literals at the top of your code file or consider switching to Python 3.x.')
+ self.outtmpl_dict = self.parse_outtmpl()
self._setup_opener()
@@ -732,8 +731,21 @@ class YoutubeDL(object):
except UnicodeEncodeError:
self.to_screen('Deleting already existent file')
- def prepare_filename(self, info_dict, warn=False):
- """Generate the output filename."""
+ def parse_outtmpl(self):
+ outtmpl_dict = self.params.get('outtmpl', {})
+ if not isinstance(outtmpl_dict, dict):
+ outtmpl_dict = {'default': outtmpl_dict}
+ outtmpl_dict.update({
+ k: v for k, v in DEFAULT_OUTTMPL.items()
+ if not outtmpl_dict.get(k)})
+ for key, val in outtmpl_dict.items():
+ if isinstance(val, bytes):
+ self.report_warning(
+ 'Parameter outtmpl is bytes, but should be a unicode string. '
+ 'Put from __future__ import unicode_literals at the top of your code file or consider switching to Python 3.x.')
+ return outtmpl_dict
+
+ def _prepare_filename(self, info_dict, tmpl_type='default'):
try:
template_dict = dict(info_dict)
@@ -765,7 +777,8 @@ class YoutubeDL(object):
na = self.params.get('outtmpl_na_placeholder', 'NA')
template_dict = collections.defaultdict(lambda: na, template_dict)
- outtmpl = self.params.get('outtmpl', DEFAULT_OUTTMPL)
+ outtmpl = self.outtmpl_dict.get(tmpl_type, self.outtmpl_dict['default'])
+ force_ext = OUTTMPL_TYPES.get(tmpl_type)
# For fields playlist_index and autonumber convert all occurrences
# of %(field)s to %(field)0Nd for backward compatibility
@@ -835,6 +848,9 @@ class YoutubeDL(object):
# title "Hello $PATH", we don't want `$PATH` to be expanded.
filename = expand_path(outtmpl).replace(sep, '') % template_dict
+ if force_ext is not None:
+ filename = replace_extension(filename, force_ext, template_dict.get('ext'))
+
# https://github.com/blackjack4494/youtube-dlc/issues/85
trim_file_name = self.params.get('trim_file_name', False)
if trim_file_name:
@@ -852,25 +868,28 @@ class YoutubeDL(object):
filename = encodeFilename(filename, True).decode(preferredencoding())
filename = sanitize_path(filename)
- if warn and not self.__prepare_filename_warned:
- if not self.params.get('paths'):
- pass
- elif filename == '-':
- self.report_warning('--paths is ignored when an outputting to stdout')
- elif os.path.isabs(filename):
- self.report_warning('--paths is ignored since an absolute path is given in output template')
- self.__prepare_filename_warned = True
-
return filename
except ValueError as err:
self.report_error('Error in output template: ' + str(err) + ' (encoding: ' + repr(preferredencoding()) + ')')
return None
- def prepare_filepath(self, filename, dir_type=''):
- if filename == '-':
- return filename
+ def prepare_filename(self, info_dict, dir_type='', warn=False):
+ """Generate the output filename."""
paths = self.params.get('paths', {})
assert isinstance(paths, dict)
+ filename = self._prepare_filename(info_dict, dir_type or 'default')
+
+ if warn and not self.__prepare_filename_warned:
+ if not paths:
+ pass
+ elif filename == '-':
+ self.report_warning('--paths is ignored when an outputting to stdout')
+ elif os.path.isabs(filename):
+ self.report_warning('--paths is ignored since an absolute path is given in output template')
+ self.__prepare_filename_warned = True
+ if filename == '-' or not filename:
+ return filename
+
homepath = expand_path(paths.get('home', '').strip())
assert isinstance(homepath, compat_str)
subdir = expand_path(paths.get(dir_type, '').strip()) if dir_type else ''
@@ -1041,10 +1060,7 @@ class YoutubeDL(object):
extract_flat = self.params.get('extract_flat', False)
if ((extract_flat == 'in_playlist' and 'playlist' in extra_info)
or extract_flat is True):
- self.__forced_printings(
- ie_result,
- self.prepare_filepath(self.prepare_filename(ie_result)),
- incomplete=True)
+ self.__forced_printings(ie_result, self.prepare_filename(ie_result), incomplete=True)
return ie_result
if result_type == 'video':
@@ -1150,9 +1166,7 @@ class YoutubeDL(object):
return make_dir(path, self.report_error)
if self.params.get('writeinfojson', False):
- infofn = replace_extension(
- self.prepare_filepath(self.prepare_filename(ie_copy), 'infojson'),
- 'info.json', ie_result.get('ext'))
+ infofn = self.prepare_filename(ie_copy, 'pl_infojson')
if not ensure_dir_exists(encodeFilename(infofn)):
return
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(infofn)):
@@ -1168,9 +1182,7 @@ class YoutubeDL(object):
self.report_error('Cannot write playlist metadata to JSON file ' + infofn)
if self.params.get('writedescription', False):
- descfn = replace_extension(
- self.prepare_filepath(self.prepare_filename(ie_copy), 'description'),
- 'description', ie_result.get('ext'))
+ descfn = self.prepare_filename(ie_copy, 'pl_description')
if not ensure_dir_exists(encodeFilename(descfn)):
return
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(descfn)):
@@ -1370,7 +1382,7 @@ class YoutubeDL(object):
and (
not can_merge()
or info_dict.get('is_live', False)
- or self.params.get('outtmpl', DEFAULT_OUTTMPL) == '-'))
+ or self.outtmpl_dict['default'] == '-'))
return (
'best/bestvideo+bestaudio'
@@ -2032,10 +2044,10 @@ class YoutubeDL(object):
info_dict = self.pre_process(info_dict)
- filename = self.prepare_filename(info_dict, warn=True)
- info_dict['_filename'] = full_filename = self.prepare_filepath(filename)
- temp_filename = self.prepare_filepath(filename, 'temp')
+ info_dict['_filename'] = full_filename = self.prepare_filename(info_dict, warn=True)
+ temp_filename = self.prepare_filename(info_dict, 'temp')
files_to_move = {}
+ skip_dl = self.params.get('skip_download', False)
# Forced printings
self.__forced_printings(info_dict, full_filename, incomplete=False)
@@ -2047,7 +2059,7 @@ class YoutubeDL(object):
# Do nothing else if in simulate mode
return
- if filename is None:
+ if full_filename is None:
return
def ensure_dir_exists(path):
@@ -2059,9 +2071,7 @@ class YoutubeDL(object):
return
if self.params.get('writedescription', False):
- descfn = replace_extension(
- self.prepare_filepath(filename, 'description'),
- 'description', info_dict.get('ext'))
+ descfn = self.prepare_filename(info_dict, 'description')
if not ensure_dir_exists(encodeFilename(descfn)):
return
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(descfn)):
@@ -2078,9 +2088,7 @@ class YoutubeDL(object):
return
if self.params.get('writeannotations', False):
- annofn = replace_extension(
- self.prepare_filepath(filename, 'annotation'),
- 'annotations.xml', info_dict.get('ext'))
+ annofn = self.prepare_filename(info_dict, 'annotation')
if not ensure_dir_exists(encodeFilename(annofn)):
return
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(annofn)):
@@ -2116,10 +2124,11 @@ class YoutubeDL(object):
# ie = self.get_info_extractor(info_dict['extractor_key'])
for sub_lang, sub_info in subtitles.items():
sub_format = sub_info['ext']
- sub_filename = subtitles_filename(temp_filename, sub_lang, sub_format, info_dict.get('ext'))
- sub_filename_final = subtitles_filename(
- self.prepare_filepath(filename, 'subtitle'),
+ sub_fn = self.prepare_filename(info_dict, 'subtitle')
+ sub_filename = subtitles_filename(
+ temp_filename if not skip_dl else sub_fn,
sub_lang, sub_format, info_dict.get('ext'))
+ sub_filename_final = subtitles_filename(sub_fn, sub_lang, sub_format, info_dict.get('ext'))
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(sub_filename)):
self.to_screen('[info] Video subtitle %s.%s is already present' % (sub_lang, sub_format))
files_to_move[sub_filename] = sub_filename_final
@@ -2153,10 +2162,10 @@ class YoutubeDL(object):
(sub_lang, error_to_compat_str(err)))
continue
- if self.params.get('skip_download', False):
+ if skip_dl:
if self.params.get('convertsubtitles', False):
# subconv = FFmpegSubtitlesConvertorPP(self, format=self.params.get('convertsubtitles'))
- filename_real_ext = os.path.splitext(filename)[1][1:]
+ filename_real_ext = os.path.splitext(full_filename)[1][1:]
filename_wo_ext = (
os.path.splitext(full_filename)[0]
if filename_real_ext == info_dict['ext']
@@ -2176,9 +2185,7 @@ class YoutubeDL(object):
return
if self.params.get('writeinfojson', False):
- infofn = replace_extension(
- self.prepare_filepath(filename, 'infojson'),
- 'info.json', info_dict.get('ext'))
+ infofn = self.prepare_filename(info_dict, 'infojson')
if not ensure_dir_exists(encodeFilename(infofn)):
return
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(infofn)):
@@ -2190,11 +2197,14 @@ class YoutubeDL(object):
except (OSError, IOError):
self.report_error('Cannot write video metadata to JSON file ' + infofn)
return
- info_dict['__infojson_filepath'] = infofn
+ info_dict['__infojson_filename'] = infofn
- thumbdir = os.path.dirname(self.prepare_filepath(filename, 'thumbnail'))
- for thumbfn in self._write_thumbnails(info_dict, temp_filename):
- files_to_move[thumbfn] = os.path.join(thumbdir, os.path.basename(thumbfn))
+ thumbfn = self.prepare_filename(info_dict, 'thumbnail')
+ thumb_fn_temp = temp_filename if not skip_dl else thumbfn
+ for thumb_ext in self._write_thumbnails(info_dict, thumb_fn_temp):
+ thumb_filename_temp = replace_extension(thumb_fn_temp, thumb_ext, info_dict.get('ext'))
+ thumb_filename = replace_extension(thumbfn, thumb_ext, info_dict.get('ext'))
+ files_to_move[thumb_filename_temp] = info_dict['__thumbnail_filename'] = thumb_filename
# Write internet shortcut files
url_link = webloc_link = desktop_link = False
@@ -2247,7 +2257,7 @@ class YoutubeDL(object):
# Download
must_record_download_archive = False
- if not self.params.get('skip_download', False):
+ if not skip_dl:
try:
def existing_file(*filepaths):
@@ -2327,7 +2337,7 @@ class YoutubeDL(object):
new_info = dict(info_dict)
new_info.update(f)
fname = prepend_extension(
- self.prepare_filepath(self.prepare_filename(new_info), 'temp'),
+ self.prepare_filename(new_info, 'temp'),
'f%s' % f['format_id'], new_info['ext'])
if not ensure_dir_exists(fname):
return
@@ -2357,7 +2367,7 @@ class YoutubeDL(object):
self.report_error('content too short (expected %s bytes and served %s)' % (err.expected, err.downloaded))
return
- if success and filename != '-':
+ if success and full_filename != '-':
# Fixup content
fixup_policy = self.params.get('fixup')
if fixup_policy is None:
@@ -2439,7 +2449,7 @@ class YoutubeDL(object):
def download(self, url_list):
"""Download a given list of URLs."""
- outtmpl = self.params.get('outtmpl', DEFAULT_OUTTMPL)
+ outtmpl = self.outtmpl_dict['default']
if (len(url_list) > 1
and outtmpl != '-'
and '%' not in outtmpl
@@ -2522,12 +2532,13 @@ class YoutubeDL(object):
"""Run all the postprocessors on the given file."""
info = dict(ie_info)
info['filepath'] = filename
+ info['__files_to_move'] = {}
for pp in ie_info.get('__postprocessors', []) + self._pps['normal']:
files_to_move, info = self.run_pp(pp, info, files_to_move)
- info = self.run_pp(MoveFilesAfterDownloadPP(self, files_to_move), info, files_to_move)[1]
+ info = self.run_pp(MoveFilesAfterDownloadPP(self, files_to_move), info)[1]
for pp in self._pps['aftermove']:
- files_to_move, info = self.run_pp(pp, info, {})
+ info = self.run_pp(pp, info, {})[1]
def _make_archive_id(self, info_dict):
video_id = info_dict.get('id')
@@ -2878,7 +2889,7 @@ class YoutubeDL(object):
encoding = preferredencoding()
return encoding
- def _write_thumbnails(self, info_dict, filename):
+ def _write_thumbnails(self, info_dict, filename): # return the extensions
if self.params.get('writethumbnail', False):
thumbnails = info_dict.get('thumbnails')
if thumbnails:
@@ -2891,12 +2902,12 @@ class YoutubeDL(object):
ret = []
for t in thumbnails:
thumb_ext = determine_ext(t['url'], 'jpg')
- suffix = '_%s' % t['id'] if len(thumbnails) > 1 else ''
+ suffix = '%s.' % t['id'] if len(thumbnails) > 1 else ''
thumb_display_id = '%s ' % t['id'] if len(thumbnails) > 1 else ''
- t['filename'] = thumb_filename = replace_extension(filename + suffix, thumb_ext, info_dict.get('ext'))
+ t['filename'] = thumb_filename = replace_extension(filename, suffix + thumb_ext, info_dict.get('ext'))
if not self.params.get('overwrites', True) and os.path.exists(encodeFilename(thumb_filename)):
- ret.append(thumb_filename)
+ ret.append(suffix + thumb_ext)
self.to_screen('[%s] %s: Thumbnail %sis already present' %
(info_dict['extractor'], info_dict['id'], thumb_display_id))
else:
@@ -2906,7 +2917,7 @@ class YoutubeDL(object):
uf = self.urlopen(t['url'])
with open(encodeFilename(thumb_filename), 'wb') as thumbf:
shutil.copyfileobj(uf, thumbf)
- ret.append(thumb_filename)
+ ret.append(suffix + thumb_ext)
self.to_screen('[%s] %s: Writing thumbnail %sto: %s' %
(info_dict['extractor'], info_dict['id'], thumb_display_id, thumb_filename))
except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
diff --git a/youtube_dlc/__init__.py b/youtube_dlc/__init__.py
index bb94389e5..646b13519 100644
--- a/youtube_dlc/__init__.py
+++ b/youtube_dlc/__init__.py
@@ -237,18 +237,21 @@ def _real_main(argv=None):
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:
@@ -413,7 +416,7 @@ def _real_main(argv=None):
'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,
diff --git a/youtube_dlc/options.py b/youtube_dlc/options.py
index 98946666d..06fbaa3cd 100644
--- a/youtube_dlc/options.py
+++ b/youtube_dlc/options.py
@@ -16,6 +16,7 @@ from .compat import (
from .utils import (
expand_path,
get_executable_path,
+ OUTTMPL_TYPES,
preferredencoding,
write_string,
)
@@ -831,19 +832,23 @@ def parseOpts(overrideArguments=None):
metavar='TYPE:PATH', dest='paths', default={}, type='str',
action='callback', callback=_dict_from_multiple_values_options_callback,
callback_kwargs={
- 'allowed_keys': 'home|temp|config|description|annotation|subtitle|infojson|thumbnail',
+ 'allowed_keys': 'home|temp|%s' % '|'.join(OUTTMPL_TYPES.keys()),
'process': lambda x: x.strip()},
help=(
'The paths where the files should be downloaded. '
- 'Specify the type of file and the path separated by a colon ":" '
- '(supported: description|annotation|subtitle|infojson|thumbnail). '
+ 'Specify the type of file and the path separated by a colon ":". '
+ 'All the same types as --output are supported. '
'Additionally, you can also provide "home" and "temp" paths. '
'All intermediary files are first downloaded to the temp path and '
'then the final files are moved over to the home path after download is finished. '
- 'Note that this option is ignored if --output is an absolute path'))
+ 'This option is ignored if --output is an absolute path'))
filesystem.add_option(
'-o', '--output',
- dest='outtmpl', metavar='TEMPLATE',
+ metavar='[TYPE:]TEMPLATE', dest='outtmpl', default={}, type='str',
+ action='callback', callback=_dict_from_multiple_values_options_callback,
+ callback_kwargs={
+ 'allowed_keys': '|'.join(OUTTMPL_TYPES.keys()),
+ 'default_key': 'default', 'process': lambda x: x.strip()},
help='Output filename template, see "OUTPUT TEMPLATE" for details')
filesystem.add_option(
'--output-na-placeholder',
diff --git a/youtube_dlc/postprocessor/embedthumbnail.py b/youtube_dlc/postprocessor/embedthumbnail.py
index 334e05955..da6b6797f 100644
--- a/youtube_dlc/postprocessor/embedthumbnail.py
+++ b/youtube_dlc/postprocessor/embedthumbnail.py
@@ -42,6 +42,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
def run(self, info):
filename = info['filepath']
temp_filename = prepend_extension(filename, 'temp')
+ files_to_delete = []
if not info.get('thumbnails'):
self.to_screen('There aren\'t any thumbnails to embed')
@@ -78,7 +79,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
escaped_thumbnail_jpg_filename = replace_extension(escaped_thumbnail_filename, 'jpg')
self.to_screen('Converting thumbnail "%s" to JPEG' % escaped_thumbnail_filename)
self.run_ffmpeg(escaped_thumbnail_filename, escaped_thumbnail_jpg_filename, ['-bsf:v', 'mjpeg2jpeg'])
- os.remove(encodeFilename(escaped_thumbnail_filename))
+ files_to_delete.append(escaped_thumbnail_filename)
thumbnail_jpg_filename = replace_extension(thumbnail_filename, 'jpg')
# Rename back to unescaped for further processing
os.rename(encodeFilename(escaped_thumbnail_jpg_filename), encodeFilename(thumbnail_jpg_filename))
@@ -183,5 +184,9 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
if success and temp_filename != filename:
os.remove(encodeFilename(filename))
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
- files_to_delete = [] if self._already_have_thumbnail else [thumbnail_filename]
+ if self._already_have_thumbnail:
+ info['__files_to_move'][thumbnail_filename] = replace_extension(
+ info['__thumbnail_filename'], os.path.splitext(thumbnail_filename)[1][1:])
+ else:
+ files_to_delete.append(thumbnail_filename)
return files_to_delete, info
diff --git a/youtube_dlc/postprocessor/ffmpeg.py b/youtube_dlc/postprocessor/ffmpeg.py
index a364237ce..948c34287 100644
--- a/youtube_dlc/postprocessor/ffmpeg.py
+++ b/youtube_dlc/postprocessor/ffmpeg.py
@@ -578,7 +578,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor):
in_filenames.append(metadata_filename)
options.extend(['-map_metadata', '1'])
- if '__infojson_filepath' in info and info['ext'] in ('mkv', 'mka'):
+ if '__infojson_filename' in info and info['ext'] in ('mkv', 'mka'):
old_stream, new_stream = self.get_stream_number(
filename, ('tags', 'mimetype'), 'application/json')
if old_stream is not None:
@@ -586,7 +586,7 @@ class FFmpegMetadataPP(FFmpegPostProcessor):
new_stream -= 1
options.extend([
- '-attach', info['__infojson_filepath'],
+ '-attach', info['__infojson_filename'],
'-metadata:s:%d' % new_stream, 'mimetype=application/json'
])
diff --git a/youtube_dlc/postprocessor/movefilesafterdownload.py b/youtube_dlc/postprocessor/movefilesafterdownload.py
index 7dcf12a3b..7f34ac5c5 100644
--- a/youtube_dlc/postprocessor/movefilesafterdownload.py
+++ b/youtube_dlc/postprocessor/movefilesafterdownload.py
@@ -25,6 +25,7 @@ class MoveFilesAfterDownloadPP(PostProcessor):
dl_path, dl_name = os.path.split(encodeFilename(info['filepath']))
finaldir = info.get('__finaldir', dl_path)
finalpath = os.path.join(finaldir, dl_name)
+ self.files_to_move.update(info['__files_to_move'])
self.files_to_move[info['filepath']] = finalpath
for oldfile, newfile in self.files_to_move.items():
@@ -39,7 +40,7 @@ class MoveFilesAfterDownloadPP(PostProcessor):
if os.path.exists(encodeFilename(newfile)):
if self.get_param('overwrites', True):
self.report_warning('Replacing existing file "%s"' % newfile)
- os.path.remove(encodeFilename(newfile))
+ os.remove(encodeFilename(newfile))
else:
self.report_warning(
'Cannot move file "%s" out of temporary directory since "%s" already exists. '
diff --git a/youtube_dlc/utils.py b/youtube_dlc/utils.py
index be27a5622..987f4bcc0 100644
--- a/youtube_dlc/utils.py
+++ b/youtube_dlc/utils.py
@@ -4169,7 +4169,18 @@ def qualities(quality_ids):
return q
-DEFAULT_OUTTMPL = '%(title)s [%(id)s].%(ext)s'
+DEFAULT_OUTTMPL = {
+ 'default': '%(title)s [%(id)s].%(ext)s',
+}
+OUTTMPL_TYPES = {
+ 'subtitle': None,
+ 'thumbnail': None,
+ 'description': 'description',
+ 'annotation': 'annotations.xml',
+ 'infojson': 'info.json',
+ 'pl_description': 'description',
+ 'pl_infojson': 'info.json',
+}
def limit_length(s, length):