|
|
|
@ -12,6 +12,8 @@ import json
|
|
|
|
|
import locale
|
|
|
|
|
import operator
|
|
|
|
|
import os
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
import platform
|
|
|
|
|
import random
|
|
|
|
|
import re
|
|
|
|
|
import shutil
|
|
|
|
@ -1442,9 +1444,42 @@ class YoutubeDL:
|
|
|
|
|
|
|
|
|
|
return EXTERNAL_FORMAT_RE.sub(create_key, outtmpl), TMPL_DICT
|
|
|
|
|
|
|
|
|
|
def evaluate_outtmpl(self, outtmpl, info_dict, *args, **kwargs):
|
|
|
|
|
def evaluate_outtmpl(self, outtmpl, info_dict, *args, trim_filename=False, **kwargs):
|
|
|
|
|
outtmpl, info_dict = self.prepare_outtmpl(outtmpl, info_dict, *args, **kwargs)
|
|
|
|
|
return self.escape_outtmpl(outtmpl) % info_dict
|
|
|
|
|
if not trim_filename:
|
|
|
|
|
return self.escape_outtmpl(outtmpl) % info_dict
|
|
|
|
|
|
|
|
|
|
ext_suffix = '.%(ext\0s)s'
|
|
|
|
|
suffix = ''
|
|
|
|
|
if outtmpl.endswith(ext_suffix):
|
|
|
|
|
outtmpl = outtmpl[:-len(ext_suffix)]
|
|
|
|
|
suffix = ext_suffix % info_dict
|
|
|
|
|
outtmpl = self.escape_outtmpl(outtmpl)
|
|
|
|
|
filename = outtmpl % info_dict
|
|
|
|
|
|
|
|
|
|
def parse_trim_file_name(trim_file_name):
|
|
|
|
|
if trim_file_name is None or trim_file_name == 'none':
|
|
|
|
|
return 0, None
|
|
|
|
|
mobj = re.match(r'(?:(?P<length>\d+)(?P<mode>b|c)?|none)', trim_file_name)
|
|
|
|
|
return int(mobj.group('length')), mobj.group('mode') or 'c'
|
|
|
|
|
|
|
|
|
|
max_file_name, mode = parse_trim_file_name(self.params.get('trim_file_name'))
|
|
|
|
|
if max_file_name == 0:
|
|
|
|
|
# no maximum
|
|
|
|
|
return filename + suffix
|
|
|
|
|
|
|
|
|
|
encoding = sys.getfilesystemencoding() if platform.system() != 'Windows' else 'utf-16-le'
|
|
|
|
|
|
|
|
|
|
def trim_filename(name: str):
|
|
|
|
|
if mode == 'b':
|
|
|
|
|
name = name.encode(encoding)
|
|
|
|
|
name = name[:max_file_name]
|
|
|
|
|
return name.decode(encoding, 'ignore')
|
|
|
|
|
else:
|
|
|
|
|
return name[:max_file_name]
|
|
|
|
|
|
|
|
|
|
filename = os.path.join(*map(trim_filename, Path(filename).parts or '.'))
|
|
|
|
|
return filename + suffix
|
|
|
|
|
|
|
|
|
|
@_catch_unsafe_extension_error
|
|
|
|
|
def _prepare_filename(self, info_dict, *, outtmpl=None, tmpl_type=None):
|
|
|
|
@ -1453,7 +1488,7 @@ class YoutubeDL:
|
|
|
|
|
outtmpl = self.params['outtmpl'].get(tmpl_type or 'default', self.params['outtmpl']['default'])
|
|
|
|
|
try:
|
|
|
|
|
outtmpl = self._outtmpl_expandpath(outtmpl)
|
|
|
|
|
filename = self.evaluate_outtmpl(outtmpl, info_dict, True)
|
|
|
|
|
filename = self.evaluate_outtmpl(outtmpl, info_dict, True, trim_filename=True)
|
|
|
|
|
if not filename:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
@ -1465,13 +1500,6 @@ class YoutubeDL:
|
|
|
|
|
force_ext = OUTTMPL_TYPES[tmpl_type]
|
|
|
|
|
if force_ext:
|
|
|
|
|
filename = replace_extension(filename, force_ext, info_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:
|
|
|
|
|
no_ext, *ext = filename.rsplit('.', 2)
|
|
|
|
|
filename = join_nonempty(no_ext[:trim_file_name], *ext, delim='.')
|
|
|
|
|
|
|
|
|
|
return filename
|
|
|
|
|
except ValueError as err:
|
|
|
|
|
self.report_error('Error in output template: ' + str(err) + ' (encoding: ' + repr(preferredencoding()) + ')')
|
|
|
|
|