mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-14 21:23:05 +00:00
Compare commits
3 Commits
f1d130902b
...
45806d44a7
Author | SHA1 | Date | |
---|---|---|---|
|
45806d44a7 | ||
|
747c0bd127 | ||
|
acea8d7cfb |
@ -210,28 +210,41 @@ class FileDownloader(object):
|
||||
def ytdl_filename(self, filename):
|
||||
return filename + '.ytdl'
|
||||
|
||||
def sanitize_open(self, filename, open_mode):
|
||||
file_access_retries = self.params.get('file_access_retries', 10)
|
||||
retry = 0
|
||||
while True:
|
||||
try:
|
||||
return sanitize_open(filename, open_mode)
|
||||
except (IOError, OSError) as err:
|
||||
retry = retry + 1
|
||||
if retry > file_access_retries or err.errno not in (errno.EACCES,):
|
||||
raise
|
||||
self.to_screen(
|
||||
'[download] Got file access error. Retrying (attempt %d of %s) ...'
|
||||
% (retry, self.format_retries(file_access_retries)))
|
||||
time.sleep(0.01)
|
||||
def wrap_file_access(action, *, fatal=False):
|
||||
def outer(func):
|
||||
def inner(self, *args, **kwargs):
|
||||
file_access_retries = self.params.get('file_access_retries', 0)
|
||||
retry = 0
|
||||
while True:
|
||||
try:
|
||||
return func(self, *args, **kwargs)
|
||||
except (IOError, OSError) as err:
|
||||
retry = retry + 1
|
||||
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
|
||||
self.to_screen(
|
||||
f'[download] Unable to {action} file due to file access error. '
|
||||
f'Retrying (attempt {retry} of {self.format_retries(file_access_retries)}) ...')
|
||||
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):
|
||||
if old_filename == new_filename:
|
||||
return
|
||||
try:
|
||||
os.replace(old_filename, new_filename)
|
||||
except (IOError, OSError) as err:
|
||||
self.report_error(f'unable to rename file: {err}')
|
||||
os.replace(old_filename, new_filename)
|
||||
|
||||
def try_utime(self, filename, last_modified_hdr):
|
||||
"""Try to set the last-modified time of the given file."""
|
||||
|
@ -159,9 +159,9 @@ class ExternalFD(FragmentFD):
|
||||
dest.write(decrypt_fragment(fragment, src.read()))
|
||||
src.close()
|
||||
if not self.params.get('keep_fragments', False):
|
||||
os.remove(encodeFilename(fragment_filename))
|
||||
self.try_remove(encodeFilename(fragment_filename))
|
||||
dest.close()
|
||||
os.remove(encodeFilename('%s.frag.urls' % tmpfilename))
|
||||
self.try_remove(encodeFilename('%s.frag.urls' % tmpfilename))
|
||||
return 0
|
||||
|
||||
|
||||
|
@ -159,7 +159,7 @@ class FragmentFD(FileDownloader):
|
||||
if self.__do_ytdl_file(ctx):
|
||||
self._write_ytdl_file(ctx)
|
||||
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']
|
||||
|
||||
def _prepare_frag_download(self, ctx):
|
||||
@ -305,7 +305,7 @@ class FragmentFD(FileDownloader):
|
||||
if self.__do_ytdl_file(ctx):
|
||||
ytdl_filename = encodeFilename(self.ytdl_filename(ctx['filename']))
|
||||
if os.path.isfile(ytdl_filename):
|
||||
os.remove(ytdl_filename)
|
||||
self.try_remove(ytdl_filename)
|
||||
elapsed = time.time() - ctx['started']
|
||||
|
||||
if ctx['tmpfilename'] == '-':
|
||||
|
@ -727,7 +727,7 @@ def create_parser():
|
||||
help='Number of retries (default is %default), or "infinite"')
|
||||
downloader.add_option(
|
||||
'--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"')
|
||||
downloader.add_option(
|
||||
'--fragment-retries',
|
||||
|
@ -2122,37 +2122,47 @@ if sys.platform == 'win32':
|
||||
whole_low = 0xffffffff
|
||||
whole_high = 0x7fffffff
|
||||
|
||||
def _lock_file(f, exclusive, block): # todo: block unused on win32
|
||||
def _lock_file(f, exclusive, block):
|
||||
overlapped = OVERLAPPED()
|
||||
overlapped.Offset = 0
|
||||
overlapped.OffsetHigh = 0
|
||||
overlapped.hEvent = 0
|
||||
f._lock_file_overlapped_p = ctypes.pointer(overlapped)
|
||||
handle = msvcrt.get_osfhandle(f.fileno())
|
||||
if not LockFileEx(handle, 0x2 if exclusive else 0x0, 0,
|
||||
whole_low, whole_high, f._lock_file_overlapped_p):
|
||||
raise OSError('Locking file failed: %r' % ctypes.FormatError())
|
||||
|
||||
if not LockFileEx(msvcrt.get_osfhandle(f.fileno()),
|
||||
(0x2 if exclusive else 0x0) | (0x0 if block else 0x1),
|
||||
0, whole_low, whole_high, f._lock_file_overlapped_p):
|
||||
raise BlockingIOError('Locking file failed: %r' % ctypes.FormatError())
|
||||
|
||||
def _unlock_file(f):
|
||||
assert f._lock_file_overlapped_p
|
||||
handle = msvcrt.get_osfhandle(f.fileno())
|
||||
if not UnlockFileEx(handle, 0,
|
||||
whole_low, whole_high, f._lock_file_overlapped_p):
|
||||
if not UnlockFileEx(handle, 0, whole_low, whole_high, f._lock_file_overlapped_p):
|
||||
raise OSError('Unlocking file failed: %r' % ctypes.FormatError())
|
||||
|
||||
else:
|
||||
# Some platforms, such as Jython, is missing fcntl
|
||||
try:
|
||||
import fcntl
|
||||
|
||||
def _lock_file(f, exclusive, block):
|
||||
fcntl.flock(f,
|
||||
fcntl.LOCK_SH if not exclusive
|
||||
else fcntl.LOCK_EX if block
|
||||
else fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
try:
|
||||
fcntl.flock(f,
|
||||
fcntl.LOCK_SH if not exclusive
|
||||
else fcntl.LOCK_EX if block
|
||||
else fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
except BlockingIOError:
|
||||
raise
|
||||
except OSError: # AOSP does not have flock()
|
||||
fcntl.lockf(f,
|
||||
fcntl.LOCK_SH if not exclusive
|
||||
else fcntl.LOCK_EX if block
|
||||
else fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
|
||||
def _unlock_file(f):
|
||||
fcntl.flock(f, fcntl.LOCK_UN)
|
||||
try:
|
||||
fcntl.flock(f, fcntl.LOCK_UN)
|
||||
except OSError:
|
||||
fcntl.lockf(f, fcntl.LOCK_UN)
|
||||
|
||||
except ImportError:
|
||||
UNSUPPORTED_MSG = 'file locking is not supported on this platform'
|
||||
@ -2165,6 +2175,8 @@ else:
|
||||
|
||||
|
||||
class locked_file(object):
|
||||
_closed = False
|
||||
|
||||
def __init__(self, filename, mode, block=True, encoding=None):
|
||||
assert mode in ['r', 'rb', 'a', 'ab', 'w', 'wb']
|
||||
self.f = io.open(filename, mode, encoding=encoding)
|
||||
@ -2182,9 +2194,11 @@ class locked_file(object):
|
||||
|
||||
def __exit__(self, etype, value, traceback):
|
||||
try:
|
||||
_unlock_file(self.f)
|
||||
if not self._closed:
|
||||
_unlock_file(self.f)
|
||||
finally:
|
||||
self.f.close()
|
||||
self._closed = True
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.f)
|
||||
|
Loading…
Reference in New Issue
Block a user