aboutsummaryrefslogtreecommitdiffstats
path: root/yt_dlp/downloader
diff options
context:
space:
mode:
Diffstat (limited to 'yt_dlp/downloader')
-rw-r--r--yt_dlp/downloader/common.py18
-rw-r--r--yt_dlp/downloader/external.py7
-rw-r--r--yt_dlp/downloader/fragment.py9
-rw-r--r--yt_dlp/downloader/http.py3
4 files changed, 26 insertions, 11 deletions
diff --git a/yt_dlp/downloader/common.py b/yt_dlp/downloader/common.py
index 9f6577a12..37321e34b 100644
--- a/yt_dlp/downloader/common.py
+++ b/yt_dlp/downloader/common.py
@@ -4,12 +4,14 @@ import os
import re
import time
import random
+import errno
from ..utils import (
decodeArgument,
encodeFilename,
error_to_compat_str,
format_bytes,
+ sanitize_open,
shell_quote,
timeconvert,
timetuple_from_msec,
@@ -39,6 +41,7 @@ class FileDownloader(object):
ratelimit: Download speed limit, in bytes/sec.
throttledratelimit: Assume the download is being throttled below this speed (bytes/sec)
retries: Number of times to retry for HTTP error 5xx
+ file_access_retries: Number of times to retry on file access error
buffersize: Size of download buffer in bytes.
noresizebuffer: Do not automatically resize the download buffer.
continuedl: Try to continue downloads if possible.
@@ -207,6 +210,21 @@ 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 try_rename(self, old_filename, new_filename):
if old_filename == new_filename:
return
diff --git a/yt_dlp/downloader/external.py b/yt_dlp/downloader/external.py
index da69423f7..84738221b 100644
--- a/yt_dlp/downloader/external.py
+++ b/yt_dlp/downloader/external.py
@@ -22,7 +22,6 @@ from ..utils import (
handle_youtubedl_headers,
check_executable,
Popen,
- sanitize_open,
)
@@ -144,11 +143,11 @@ class ExternalFD(FragmentFD):
return -1
decrypt_fragment = self.decrypter(info_dict)
- dest, _ = sanitize_open(tmpfilename, 'wb')
+ dest, _ = self.sanitize_open(tmpfilename, 'wb')
for frag_index, fragment in enumerate(info_dict['fragments']):
fragment_filename = '%s-Frag%d' % (tmpfilename, frag_index)
try:
- src, _ = sanitize_open(fragment_filename, 'rb')
+ src, _ = self.sanitize_open(fragment_filename, 'rb')
except IOError as err:
if skip_unavailable_fragments and frag_index > 1:
self.report_skip_fragment(frag_index, err)
@@ -290,7 +289,7 @@ class Aria2cFD(ExternalFD):
for frag_index, fragment in enumerate(info_dict['fragments']):
fragment_filename = '%s-Frag%d' % (os.path.basename(tmpfilename), frag_index)
url_list.append('%s\n\tout=%s' % (fragment['url'], fragment_filename))
- stream, _ = sanitize_open(url_list_file, 'wb')
+ stream, _ = self.sanitize_open(url_list_file, 'wb')
stream.write('\n'.join(url_list).encode('utf-8'))
stream.close()
cmd += ['-i', url_list_file]
diff --git a/yt_dlp/downloader/fragment.py b/yt_dlp/downloader/fragment.py
index 79c6561c7..c1b90e2a2 100644
--- a/yt_dlp/downloader/fragment.py
+++ b/yt_dlp/downloader/fragment.py
@@ -24,7 +24,6 @@ from ..utils import (
DownloadError,
error_to_compat_str,
encodeFilename,
- sanitize_open,
sanitized_Request,
)
@@ -96,7 +95,7 @@ class FragmentFD(FileDownloader):
def _read_ytdl_file(self, ctx):
assert 'ytdl_corrupt' not in ctx
- stream, _ = sanitize_open(self.ytdl_filename(ctx['filename']), 'r')
+ stream, _ = self.sanitize_open(self.ytdl_filename(ctx['filename']), 'r')
try:
ytdl_data = json.loads(stream.read())
ctx['fragment_index'] = ytdl_data['downloader']['current_fragment']['index']
@@ -108,7 +107,7 @@ class FragmentFD(FileDownloader):
stream.close()
def _write_ytdl_file(self, ctx):
- frag_index_stream, _ = sanitize_open(self.ytdl_filename(ctx['filename']), 'w')
+ frag_index_stream, _ = self.sanitize_open(self.ytdl_filename(ctx['filename']), 'w')
try:
downloader = {
'current_fragment': {
@@ -140,7 +139,7 @@ class FragmentFD(FileDownloader):
return True, self._read_fragment(ctx)
def _read_fragment(self, ctx):
- down, frag_sanitized = sanitize_open(ctx['fragment_filename_sanitized'], 'rb')
+ down, frag_sanitized = self.sanitize_open(ctx['fragment_filename_sanitized'], 'rb')
ctx['fragment_filename_sanitized'] = frag_sanitized
frag_content = down.read()
down.close()
@@ -216,7 +215,7 @@ class FragmentFD(FileDownloader):
self._write_ytdl_file(ctx)
assert ctx['fragment_index'] == 0
- dest_stream, tmpfilename = sanitize_open(tmpfilename, open_mode)
+ dest_stream, tmpfilename = self.sanitize_open(tmpfilename, open_mode)
ctx.update({
'dl': dl,
diff --git a/yt_dlp/downloader/http.py b/yt_dlp/downloader/http.py
index 6290884a8..34a1eb59b 100644
--- a/yt_dlp/downloader/http.py
+++ b/yt_dlp/downloader/http.py
@@ -16,7 +16,6 @@ from ..utils import (
ContentTooShortError,
encodeFilename,
int_or_none,
- sanitize_open,
sanitized_Request,
ThrottledDownload,
write_xattr,
@@ -263,7 +262,7 @@ class HttpFD(FileDownloader):
# Open destination file just in time
if ctx.stream is None:
try:
- ctx.stream, ctx.tmpfilename = sanitize_open(
+ ctx.stream, ctx.tmpfilename = self.sanitize_open(
ctx.tmpfilename, ctx.open_mode)
assert ctx.stream is not None
ctx.filename = self.undo_temp_name(ctx.tmpfilename)