[downloader] Obey `--file-access-retries` when deleting/renaming (#2224)

Authored by: ehoogeveen-medweb
This commit is contained in:
Emanuel Hoogeveen 2022-03-03 15:33:32 +01:00 committed by GitHub
parent 747c0bd127
commit 45806d44a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 23 deletions

View File

@ -210,28 +210,41 @@ class FileDownloader(object):
def ytdl_filename(self, filename): def ytdl_filename(self, filename):
return filename + '.ytdl' return filename + '.ytdl'
def sanitize_open(self, filename, open_mode): def wrap_file_access(action, *, fatal=False):
file_access_retries = self.params.get('file_access_retries', 10) def outer(func):
def inner(self, *args, **kwargs):
file_access_retries = self.params.get('file_access_retries', 0)
retry = 0 retry = 0
while True: while True:
try: try:
return sanitize_open(filename, open_mode) return func(self, *args, **kwargs)
except (IOError, OSError) as err: except (IOError, OSError) as err:
retry = retry + 1 retry = retry + 1
if retry > file_access_retries or err.errno not in (errno.EACCES,): if retry > file_access_retries or err.errno not in (errno.EACCES, errno.EINVAL):
if not fatal:
self.report_error(f'unable to {action} file: {err}')
return
raise raise
self.to_screen( self.to_screen(
'[download] Got file access error. Retrying (attempt %d of %s) ...' f'[download] Unable to {action} file due to file access error. '
% (retry, self.format_retries(file_access_retries))) f'Retrying (attempt {retry} of {self.format_retries(file_access_retries)}) ...')
time.sleep(0.01) time.sleep(0.01)
return inner
return outer
@wrap_file_access('open', fatal=True)
def sanitize_open(self, filename, open_mode):
return sanitize_open(filename, open_mode)
@wrap_file_access('remove')
def try_remove(self, filename):
os.remove(filename)
@wrap_file_access('rename')
def try_rename(self, old_filename, new_filename): def try_rename(self, old_filename, new_filename):
if old_filename == new_filename: if old_filename == new_filename:
return return
try:
os.replace(old_filename, new_filename) os.replace(old_filename, new_filename)
except (IOError, OSError) as err:
self.report_error(f'unable to rename file: {err}')
def try_utime(self, filename, last_modified_hdr): def try_utime(self, filename, last_modified_hdr):
"""Try to set the last-modified time of the given file.""" """Try to set the last-modified time of the given file."""

View File

@ -159,9 +159,9 @@ class ExternalFD(FragmentFD):
dest.write(decrypt_fragment(fragment, src.read())) dest.write(decrypt_fragment(fragment, src.read()))
src.close() src.close()
if not self.params.get('keep_fragments', False): if not self.params.get('keep_fragments', False):
os.remove(encodeFilename(fragment_filename)) self.try_remove(encodeFilename(fragment_filename))
dest.close() dest.close()
os.remove(encodeFilename('%s.frag.urls' % tmpfilename)) self.try_remove(encodeFilename('%s.frag.urls' % tmpfilename))
return 0 return 0

View File

@ -159,7 +159,7 @@ class FragmentFD(FileDownloader):
if self.__do_ytdl_file(ctx): if self.__do_ytdl_file(ctx):
self._write_ytdl_file(ctx) self._write_ytdl_file(ctx)
if not self.params.get('keep_fragments', False): if not self.params.get('keep_fragments', False):
os.remove(encodeFilename(ctx['fragment_filename_sanitized'])) self.try_remove(encodeFilename(ctx['fragment_filename_sanitized']))
del ctx['fragment_filename_sanitized'] del ctx['fragment_filename_sanitized']
def _prepare_frag_download(self, ctx): def _prepare_frag_download(self, ctx):
@ -305,7 +305,7 @@ class FragmentFD(FileDownloader):
if self.__do_ytdl_file(ctx): if self.__do_ytdl_file(ctx):
ytdl_filename = encodeFilename(self.ytdl_filename(ctx['filename'])) ytdl_filename = encodeFilename(self.ytdl_filename(ctx['filename']))
if os.path.isfile(ytdl_filename): if os.path.isfile(ytdl_filename):
os.remove(ytdl_filename) self.try_remove(ytdl_filename)
elapsed = time.time() - ctx['started'] elapsed = time.time() - ctx['started']
if ctx['tmpfilename'] == '-': if ctx['tmpfilename'] == '-':

View File

@ -727,7 +727,7 @@ def create_parser():
help='Number of retries (default is %default), or "infinite"') help='Number of retries (default is %default), or "infinite"')
downloader.add_option( downloader.add_option(
'--file-access-retries', '--file-access-retries',
dest='file_access_retries', metavar='RETRIES', default=10, dest='file_access_retries', metavar='RETRIES', default=3,
help='Number of times to retry on file access error (default is %default), or "infinite"') help='Number of times to retry on file access error (default is %default), or "infinite"')
downloader.add_option( downloader.add_option(
'--fragment-retries', '--fragment-retries',