From c2934512c29e300e7a525c339751c9a8bde65e1b Mon Sep 17 00:00:00 2001 From: pukkandan Date: Thu, 18 Feb 2021 00:39:38 +0530 Subject: [PATCH] Option `--windows-filenames` to force use of windows compatible filenames * Also changed `--trim-file-name` to `--trim-filenames` to be similar to related options Related: https://web.archive.org/web/20210217190806/https://old.reddit.com/r/youtubedl/comments/llc4o5/do_you_guys_also_have_this_error :ci skip dl --- README.md | 8 ++++++-- youtube_dlc/YoutubeDL.py | 16 ++++++++-------- youtube_dlc/__init__.py | 1 + youtube_dlc/options.py | 18 +++++++++++++----- youtube_dlc/utils.py | 14 +++++++++----- 5 files changed, 37 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index b9ba226b77..be5195f1e6 100644 --- a/README.md +++ b/README.md @@ -361,6 +361,12 @@ Then simply type this filenames --no-restrict-filenames Allow Unicode characters, "&" and spaces in filenames (default) + --windows-filenames Force filenames to be windows compatible + --no-windows-filenames Make filenames windows compatible only if + using windows (default) + --trim-filenames LENGTH Limit the filename length (excluding + extension) to the specified number of + characters -w, --no-overwrites Do not overwrite any files --force-overwrites Overwrite all video and metadata files. This option includes --no-continue @@ -411,8 +417,6 @@ Then simply type this may change --no-cache-dir Disable filesystem caching --rm-cache-dir Delete all filesystem cache files - --trim-file-name LENGTH Limit the filename length (extension - excluded) ## Thumbnail Images: --write-thumbnail Write thumbnail image to disk diff --git a/youtube_dlc/YoutubeDL.py b/youtube_dlc/YoutubeDL.py index f88bc793ef..125ce767cd 100644 --- a/youtube_dlc/YoutubeDL.py +++ b/youtube_dlc/YoutubeDL.py @@ -868,13 +868,6 @@ class YoutubeDL(object): sub_ext = fn_groups[-2] filename = '.'.join(filter(None, [fn_groups[0][:trim_file_name], sub_ext, ext])) - # Temporary fix for #4787 - # 'Treat' all problem characters by passing filename through preferredencoding - # to workaround encoding issues with subprocess on python2 @ Windows - if sys.version_info < (3, 0) and sys.platform == 'win32': - filename = encodeFilename(filename, True).decode(preferredencoding()) - filename = sanitize_path(filename) - return filename except ValueError as err: self.report_error('Error in output template: ' + str(err) + ' (encoding: ' + repr(preferredencoding()) + ')') @@ -901,7 +894,14 @@ class YoutubeDL(object): assert isinstance(homepath, compat_str) subdir = expand_path(paths.get(dir_type, '').strip()) if dir_type else '' assert isinstance(subdir, compat_str) - return sanitize_path(os.path.join(homepath, subdir, filename)) + path = os.path.join(homepath, subdir, filename) + + # Temporary fix for #4787 + # 'Treat' all problem characters by passing filename through preferredencoding + # to workaround encoding issues with subprocess on python2 @ Windows + if sys.version_info < (3, 0) and sys.platform == 'win32': + path = encodeFilename(path, True).decode(preferredencoding()) + return sanitize_path(path, force=self.params.get('windowsfilenames')) def _match_entry(self, info_dict, incomplete): """ Returns None if the file should be downloaded """ diff --git a/youtube_dlc/__init__.py b/youtube_dlc/__init__.py index a14c8424ef..6451ed8c88 100644 --- a/youtube_dlc/__init__.py +++ b/youtube_dlc/__init__.py @@ -440,6 +440,7 @@ def _real_main(argv=None): '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, diff --git a/youtube_dlc/options.py b/youtube_dlc/options.py index cb8e8236ae..bb37554ec1 100644 --- a/youtube_dlc/options.py +++ b/youtube_dlc/options.py @@ -878,8 +878,20 @@ def parseOpts(overrideArguments=None): help='Restrict filenames to only ASCII characters, and avoid "&" and spaces in filenames') filesystem.add_option( '--no-restrict-filenames', - action='store_false', dest='restrictfilenames', default=False, + action='store_false', dest='restrictfilenames', help='Allow Unicode characters, "&" and spaces in filenames (default)') + filesystem.add_option( + '--windows-filenames', + action='store_true', dest='windowsfilenames', default=False, + help='Force filenames to be windows compatible') + filesystem.add_option( + '--no-windows-filenames', + action='store_false', dest='windowsfilenames', + help='Make filenames windows compatible only if using windows (default)') + filesystem.add_option( + '--trim-filenames', '--trim-file-names', metavar='LENGTH', + dest='trim_file_name', default=0, type=int, + help='Limit the filename length (excluding extension) to the specified number of characters') filesystem.add_option( '-A', '--auto-number', action='store_true', dest='autonumber', default=False, @@ -992,10 +1004,6 @@ def parseOpts(overrideArguments=None): '--rm-cache-dir', action='store_true', dest='rm_cachedir', help='Delete all filesystem cache files') - filesystem.add_option( - '--trim-file-name', metavar='LENGTH', - dest='trim_file_name', default=0, type=int, - help='Limit the filename length (extension excluded)') thumbnail = optparse.OptionGroup(parser, 'Thumbnail Images') thumbnail.add_option( diff --git a/youtube_dlc/utils.py b/youtube_dlc/utils.py index 5aaec4f171..99cbb8a28c 100644 --- a/youtube_dlc/utils.py +++ b/youtube_dlc/utils.py @@ -2125,13 +2125,17 @@ def sanitize_filename(s, restricted=False, is_id=False): return result -def sanitize_path(s): +def sanitize_path(s, force=False): """Sanitizes and normalizes path on Windows""" - if sys.platform != 'win32': + if sys.platform == 'win32': + drive_or_unc, _ = os.path.splitdrive(s) + if sys.version_info < (2, 7) and not drive_or_unc: + drive_or_unc, _ = os.path.splitunc(s) + elif force: + drive_or_unc = '' + else: return s - drive_or_unc, _ = os.path.splitdrive(s) - if sys.version_info < (2, 7) and not drive_or_unc: - drive_or_unc, _ = os.path.splitunc(s) + norm_path = os.path.normpath(remove_start(s, drive_or_unc)).split(os.path.sep) if drive_or_unc: norm_path.pop(0)