* YoutubeDL:validate_destination_filename(): Bugfix of the previous commit when -o contains a directory.

* test_YoutubeDL:test_prepare_outtmpl_and_filename(): Prevents bogus test failure.
pull/12450/head
Teika Kazura 2 months ago
parent 4f46e5a323
commit 52d0130a37

@ -742,6 +742,7 @@ class TestYoutubeDL(unittest.TestCase):
params['outtmpl'] = tmpl params['outtmpl'] = tmpl
ydl = FakeYDL(params) ydl = FakeYDL(params)
ydl._num_downloads = 1 ydl._num_downloads = 1
ydl.validate_destination_filename = lambda *args: None
self.assertEqual(ydl.validate_outtmpl(tmpl), None) self.assertEqual(ydl.validate_outtmpl(tmpl), None)
out = ydl.evaluate_outtmpl(tmpl, info or self.outtmpl_info) out = ydl.evaluate_outtmpl(tmpl, info or self.outtmpl_info)

@ -12,6 +12,7 @@ import json
import locale import locale
import operator import operator
import os import os
import pathlib
import random import random
import re import re
import shutil import shutil
@ -1481,27 +1482,39 @@ it checks if the length does not exceed the OS limit. However currently
any error is simply raised, independent of the cause. any error is simply raised, independent of the cause.
Without this, download would fail only after the entire file is downloaded.""" Without this, download would fail only after the entire file is downloaded."""
cwd = os.getcwd() # An improvement idea:
# by default, retry (exec yt-dlp itself) by
# -o "%(id)s.%(ext)s" --write-info-json,
# but respect the directory from --output of the original call.
with tempfile.TemporaryDirectory() as d: with tempfile.TemporaryDirectory() as d:
os.chdir(d)
try: try:
with open(filename, 'w') as f: # To make sure it's confined under tmpdir
f.close() tmpfn = '.' + os.sep + os.path.splitdrive(filename)[1]
parentDirStr = os.sep + '..' + os.sep
# This may contain '../' so remove them.
while parentDirStr in tmpfn:
tmpfn = tmpfn.replace(parentDirStr, os.sep)
tmpfn = os.path.join(d, tmpfn)
pathlib.Path(os.path.dirname(tmpfn)).mkdir(parents=True, exist_ok=True)
open(tmpfn, 'w').close()
except OSError as e: except OSError as e:
if (os.name == 'nt' and e.errno == 206) or (e.errno == errno.ENAMETOOLONG): if (os.name == 'nt' and e.errno == 206) or (os.name != 'nt' and e.errno == errno.ENAMETOOLONG):
# The first condition is for windows, # For Win, 206 means filename length exceeds MAX_PATH.
# and the second for unix-ish systems.
e.filename = filename
# An improvement idea:
# by default, retry (exec yt-dlp itself) by
# -o "%(id)s.%(ext)s" --write-info-json,
# but respect the directory from --output of the original call.
self.to_screen('''[Notice] The file name to be saved is too long, exceeding the OS limit. self.to_screen('''[Notice] The file name to be saved is too long, exceeding the OS limit.
[Notice] Consider options --trim-filenames or -o (--output).''') [Notice] Consider options --trim-filenames or -o (--output).''')
raise elif os.name == 'nt' and e.errno == 22:
finally: # Even when MAX_PATH is disabled, 255 chars is the limit, resulting in 22.
os.chdir(cwd) # https://github.com/python/cpython/issues/126929#issuecomment-2483684861
e.filename = filename
self.to_screen(f'''[Notice] Attempt to create file {filename} resulted in Errno 22.
This is often caused e.g. by too long filename or forbidden characters.''')
raise
def prepare_filename(self, info_dict, dir_type='', *, outtmpl=None, warn=False): def prepare_filename(self, info_dict, dir_type='', *, outtmpl=None, warn=False):
"""Generate the output filename""" """Generate the output filename"""

Loading…
Cancel
Save