diff --git a/yt_dlp/YoutubeDL.py b/yt_dlp/YoutubeDL.py index d1b4a7c25..aec9f7a00 100644 --- a/yt_dlp/YoutubeDL.py +++ b/yt_dlp/YoutubeDL.py @@ -70,7 +70,6 @@ from .update import ( ) from .utils import ( DEFAULT_OUTTMPL, - DEFAULT_MAX_FILE_NAME, IDENTITY, LINK_TEMPLATES, MEDIA_EXTENSIONS, @@ -267,6 +266,7 @@ class YoutubeDL: 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) + trim_file_name_mode: Mode of filename trimming ('c' for characters or 'b' for bytes) filesystem_encoding: Encoding to use when calculating filename length in bytes windowsfilenames: True: Force filenames to be Windows compatible False: Sanitize filenames only minimally @@ -1438,31 +1438,8 @@ class YoutubeDL: outtmpl = self.escape_outtmpl(outtmpl) filename = outtmpl % info_dict - def parse_max_file_name(max_file_name: str): - # old --trim-filenames format - try: - return 'c', int(max_file_name) - except ValueError: - pass - - try: - max_length = int(max_file_name[:-1]) - except ValueError: - raise ValueError('Invalid --trim-filenames specified') - - if max_file_name[-1].lower() == 'c': - return 'c', max_length - elif max_file_name[-1].lower() == 'b': - return 'b', max_length - else: - raise ValueError("--trim-filenames must end with 'b' or 'c'") - max_file_name = self.params.get('trim_file_name') - if max_file_name is None: - max_file_name = DEFAULT_MAX_FILE_NAME - mode, max_file_name = parse_max_file_name(max_file_name) - if max_file_name < 0: - raise ValueError('Invalid --trim-filenames specified') + mode = self.params.get('trim_file_name_mode') if max_file_name == 0: # no maximum return filename + suffix diff --git a/yt_dlp/__init__.py b/yt_dlp/__init__.py index 69d1e9ed3..b22c4c1dd 100644 --- a/yt_dlp/__init__.py +++ b/yt_dlp/__init__.py @@ -1,3 +1,4 @@ +import codecs import sys if sys.version_info < (3, 9): @@ -429,6 +430,21 @@ def validate_options(opts): } # Other options + opts.trim_file_name_mode = 'c' + if opts.trim_file_name is not None: + mobj = re.match(r'(?:(?P\d+)(?Pb|c)?|notrim)', opts.trim_file_name) + validate(mobj, 'trim filenames', opts.trim_file_name) + if opts.trim_file_name == 'notrim': + opts.trim_file_name = 0 + else: + opts.trim_file_name = int(mobj.group('length')) + opts.trim_file_name_mode = mobj.group('mode') or 'c' + if opts.filesystem_encoding is not None: + try: + codecs.lookup(opts.filesystem_encoding) + except LookupError: + raise ValueError(f'Invalid filesystem encoding: {opts.filesystem_encoding}') + if opts.playlist_items is not None: try: tuple(PlaylistEntries.parse_playlist_items(opts.playlist_items)) @@ -886,6 +902,7 @@ def parse_options(argv=None): 'max_downloads': opts.max_downloads, 'prefer_free_formats': opts.prefer_free_formats, 'trim_file_name': opts.trim_file_name, + 'trim_file_name_mode': opts.trim_file_name_mode, 'filesystem_encoding': opts.filesystem_encoding, 'verbose': opts.verbose, 'dump_intermediate_pages': opts.dump_intermediate_pages, diff --git a/yt_dlp/options.py b/yt_dlp/options.py index 49387a821..ba1b55b14 100644 --- a/yt_dlp/options.py +++ b/yt_dlp/options.py @@ -1378,7 +1378,7 @@ def create_parser(): help='Sanitize filenames only minimally') filesystem.add_option( '--trim-filenames', '--trim-file-names', metavar='LENGTH', - dest='trim_file_name', + dest='trim_file_name', default='notrim', help='Limit the filename length (excluding extension) to the specified number of characters or bytes') filesystem.add_option( '--filesystem-encoding', metavar='ENCODING', diff --git a/yt_dlp/utils/_utils.py b/yt_dlp/utils/_utils.py index 15e92dfec..699bf1e7f 100644 --- a/yt_dlp/utils/_utils.py +++ b/yt_dlp/utils/_utils.py @@ -2852,12 +2852,6 @@ OUTTMPL_TYPES = { 'pl_infojson': 'info.json', } -# https://en.m.wikipedia.org/wiki/Comparison_of_file_systems#Limits -if platform.system() in ('Darwin', 'Windows'): - DEFAULT_MAX_FILE_NAME = f'{255 - len(".annotations.xml")}c' -else: - DEFAULT_MAX_FILE_NAME = f'{255 - len(".annotations.xml".encode(sys.getfilesystemencoding()))}b' - # As of [1] format syntax is: # %[mapping_key][conversion_flags][minimum_width][.precision][length_modifier]type # 1. https://docs.python.org/2/library/stdtypes.html#string-formatting