fix:优化下载

This commit is contained in:
jxxghp
2025-09-08 09:50:08 +08:00
parent a018e1228c
commit c1bd2d6cf1
4 changed files with 91 additions and 75 deletions

View File

@@ -1,4 +1,5 @@
from pathlib import Path from pathlib import Path
from tempfile import NamedTemporaryFile
from threading import Lock from threading import Lock
from typing import Optional, List, Tuple, Union from typing import Optional, List, Tuple, Union
@@ -456,36 +457,53 @@ class MediaChain(ChainBase):
""" """
if not _fileitem or not _content or not _path: if not _fileitem or not _content or not _path:
return return
# 保存文件到临时目录 # 使用tempfile创建临时文件自动删除
tmp_dir = settings.TEMP_PATH / StringUtils.generate_random_str(10) with NamedTemporaryFile(delete=True, suffix=_path.suffix) as tmp_file:
tmp_dir.mkdir(parents=True, exist_ok=True) # 写入内容
tmp_file = tmp_dir / _path.name if isinstance(_content, bytes):
tmp_file.write_bytes(_content) tmp_file.write(_content)
# 获取文件的父目录 else:
try: tmp_file.write(_content.encode('utf-8'))
item = storagechain.upload_file(fileitem=_fileitem, path=tmp_file, new_name=_path.name) tmp_file.flush()
# 上传文件
item = storagechain.upload_file(fileitem=_fileitem, path=Path(tmp_file.name), new_name=_path.name)
if item: if item:
logger.info(f"已保存文件:{item.path}") logger.info(f"已保存文件:{item.path}")
else: else:
logger.warn(f"文件保存失败:{_path}") logger.warn(f"文件保存失败:{_path}")
finally:
if tmp_file.exists():
tmp_file.unlink()
def __download_image(_url: str) -> Optional[bytes]: def __download_and_save_image(_fileitem: schemas.FileItem, _path: Path, _url: str):
""" """
下载图片并保存 流式下载图片并直接保存到文件(减少内存占用)
:param _fileitem: 关联的媒体文件项
:param _path: 图片文件路径
:param _url: 图片下载URL
""" """
if not _fileitem or not _url or not _path:
return
try: try:
logger.info(f"正在下载图片:{_url} ...") logger.info(f"正在下载图片:{_url} ...")
r = RequestUtils(proxies=settings.PROXY, ua=settings.NORMAL_USER_AGENT).get_res(url=_url) request_utils = RequestUtils(proxies=settings.PROXY, ua=settings.NORMAL_USER_AGENT)
if r: with request_utils.get_stream(url=_url) as r:
return r.content if r and r.status_code == 200:
else: # 使用tempfile创建临时文件自动删除
logger.info(f"{_url} 图片下载失败,请检查网络连通性!") with NamedTemporaryFile(delete=True, suffix=_path.suffix) as tmp_file:
# 流式写入文件
for chunk in r.iter_content(chunk_size=8192):
if chunk:
tmp_file.write(chunk)
tmp_file.flush()
# 上传文件
item = storagechain.upload_file(fileitem=_fileitem, path=Path(tmp_file.name),
new_name=_path.name)
if item:
logger.info(f"已保存图片:{item.path}")
else:
logger.warn(f"图片保存失败:{_path}")
else:
logger.info(f"{_url} 图片下载失败")
except Exception as err: except Exception as err:
logger.error(f"{_url} 图片下载失败:{str(err)}") logger.error(f"{_url} 图片下载失败:{str(err)}")
return None
if not fileitem: if not fileitem:
return return
@@ -587,11 +605,8 @@ class MediaChain(ChainBase):
image_path = filepath.with_name(image_name) image_path = filepath.with_name(image_name)
if overwrite or not storagechain.get_file_item(storage=fileitem.storage, if overwrite or not storagechain.get_file_item(storage=fileitem.storage,
path=image_path): path=image_path):
# 下载图片 # 流式下载图片并直接保存
content = __download_image(image_url) __download_and_save_image(_fileitem=fileitem, _path=image_path, _url=image_url)
# 写入图片到当前目录
if content:
__save_file(_fileitem=fileitem, _path=image_path, _content=content)
else: else:
logger.info(f"已存在图片文件:{image_path}") logger.info(f"已存在图片文件:{image_path}")
else: else:
@@ -637,13 +652,10 @@ class MediaChain(ChainBase):
for episode, image_url in image_dict.items(): for episode, image_url in image_dict.items():
image_path = filepath.with_suffix(Path(image_url).suffix) image_path = filepath.with_suffix(Path(image_url).suffix)
if overwrite or not storagechain.get_file_item(storage=fileitem.storage, path=image_path): if overwrite or not storagechain.get_file_item(storage=fileitem.storage, path=image_path):
# 下载图片 # 流式下载图片并直接保存
content = __download_image(image_url) if not parent:
# 保存图片文件到当前目录 parent = storagechain.get_parent_item(fileitem)
if content: __download_and_save_image(_fileitem=parent, _path=image_path, _url=image_url)
if not parent:
parent = storagechain.get_parent_item(fileitem)
__save_file(_fileitem=parent, _path=image_path, _content=content)
else: else:
logger.info(f"已存在图片文件:{image_path}") logger.info(f"已存在图片文件:{image_path}")
else: else:
@@ -694,13 +706,10 @@ class MediaChain(ChainBase):
image_path = filepath.with_name(image_name) image_path = filepath.with_name(image_name)
if overwrite or not storagechain.get_file_item(storage=fileitem.storage, if overwrite or not storagechain.get_file_item(storage=fileitem.storage,
path=image_path): path=image_path):
# 下载图片 # 流式下载图片并直接保存
content = __download_image(image_url) if not parent:
# 保存图片文件到剧集目录 parent = storagechain.get_parent_item(fileitem)
if content: __download_and_save_image(_fileitem=parent, _path=image_path, _url=image_url)
if not parent:
parent = storagechain.get_parent_item(fileitem)
__save_file(_fileitem=parent, _path=image_path, _content=content)
else: else:
logger.info(f"已存在图片文件:{image_path}") logger.info(f"已存在图片文件:{image_path}")
else: else:
@@ -730,13 +739,11 @@ class MediaChain(ChainBase):
continue continue
if overwrite or not storagechain.get_file_item(storage=fileitem.storage, if overwrite or not storagechain.get_file_item(storage=fileitem.storage,
path=image_path): path=image_path):
# 下载图片 # 流式下载图片并直接保存
content = __download_image(image_url) if not parent:
# 保存图片文件到当前目录 parent = storagechain.get_parent_item(fileitem)
if content: __download_and_save_image(_fileitem=parent, _path=image_path,
if not parent: _url=image_url)
parent = storagechain.get_parent_item(fileitem)
__save_file(_fileitem=parent, _path=image_path, _content=content)
else: else:
logger.info(f"已存在图片文件:{image_path}") logger.info(f"已存在图片文件:{image_path}")
else: else:
@@ -786,11 +793,8 @@ class MediaChain(ChainBase):
image_path = filepath / image_name image_path = filepath / image_name
if overwrite or not storagechain.get_file_item(storage=fileitem.storage, if overwrite or not storagechain.get_file_item(storage=fileitem.storage,
path=image_path): path=image_path):
# 下载图片 # 流式下载图片并直接保存
content = __download_image(image_url) __download_and_save_image(_fileitem=fileitem, _path=image_path, _url=image_url)
# 保存图片文件到当前目录
if content:
__save_file(_fileitem=fileitem, _path=image_path, _content=content)
else: else:
logger.info(f"已存在图片文件:{image_path}") logger.info(f"已存在图片文件:{image_path}")
else: else:

View File

@@ -15,7 +15,7 @@ def transfer_process(path: str) -> Callable[[int | float], None]:
""" """
传输进度回调 传输进度回调
""" """
pbar = tqdm(total=100, desc="整理进度", unit="%") pbar = tqdm(total=100, desc="进度", unit="%")
progress = ProgressHelper(HashUtils.md5(path)) progress = ProgressHelper(HashUtils.md5(path))
progress.start() progress.start()

View File

@@ -14,6 +14,7 @@ from app.log import logger
from app.modules.filemanager import StorageBase from app.modules.filemanager import StorageBase
from app.modules.filemanager.storages import transfer_process from app.modules.filemanager.storages import transfer_process
from app.schemas.types import StorageSchema from app.schemas.types import StorageSchema
from app.utils.http import RequestUtils
from app.utils.singleton import WeakSingleton from app.utils.singleton import WeakSingleton
from app.utils.string import StringUtils from app.utils.string import StringUtils
@@ -729,7 +730,25 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
progress_callback = transfer_process(Path(fileitem.path).as_posix()) progress_callback = transfer_process(Path(fileitem.path).as_posix())
try: try:
with requests.get(download_url, stream=True) as r: # 构建请求头,包含必要的认证信息
headers = {
"User-Agent": settings.NORMAL_USER_AGENT,
"Referer": "https://www.aliyundrive.com/",
"Accept": "*/*",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "cross-site"
}
# 如果有access_token添加到请求头
if self.access_token:
headers["Authorization"] = f"Bearer {self.access_token}"
request_utils = RequestUtils(headers=headers)
with request_utils.get_stream(download_url, raise_exception=True) as r:
r.raise_for_status() r.raise_for_status()
downloaded_size = 0 downloaded_size = 0
with open(local_path, "wb") as f: with open(local_path, "wb") as f:
@@ -748,22 +767,13 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
# 完成下载 # 完成下载
progress_callback(100) progress_callback(100)
logger.info(f"【阿里云盘】下载完成: {fileitem.name}") logger.info(f"【阿里云盘】下载完成: {fileitem.name}")
return local_path
except requests.exceptions.RequestException as e:
logger.error(f"【阿里云盘】下载网络错误: {fileitem.name} - {str(e)}")
# 删除可能部分下载的文件
if local_path.exists():
local_path.unlink()
return None
except Exception as e: except Exception as e:
logger.error(f"【阿里云盘】下载失败: {fileitem.name} - {str(e)}") logger.error(f"【阿里云盘】下载失败: {fileitem.name} - {str(e)}")
# 删除可能部分下载的文件
if local_path.exists(): if local_path.exists():
local_path.unlink() local_path.unlink()
return None return None
return local_path
def check(self) -> bool: def check(self) -> bool:
return self.access_token is not None return self.access_token is not None

View File

@@ -4,8 +4,6 @@ from datetime import datetime
from pathlib import Path from pathlib import Path
from typing import Optional, List from typing import Optional, List
import requests
from app import schemas from app import schemas
from app.core.cache import cached from app.core.cache import cached
from app.core.config import settings, global_vars from app.core.config import settings, global_vars
@@ -569,18 +567,22 @@ class Alist(StorageBase, metaclass=WeakSingleton):
else: else:
local_path = path / fileitem.name local_path = path / fileitem.name
with requests.get(download_url, headers=self.__get_header_with_token(), stream=True) as r: request_utils = RequestUtils(headers=self.__get_header_with_token())
r.raise_for_status() try:
with open(local_path, "wb") as f: with request_utils.get_stream(download_url, raise_exception=True) as r:
for chunk in r.iter_content(chunk_size=8192): r.raise_for_status()
if global_vars.is_transfer_stopped(fileitem.path): with open(local_path, "wb") as f:
logger.info(f"【OpenList】{fileitem.path} 下载已取消!") for chunk in r.iter_content(chunk_size=8192):
return None if global_vars.is_transfer_stopped(fileitem.path):
f.write(chunk) logger.info(f"【OpenList】{fileitem.path} 下载已取消!")
return None
f.write(chunk)
except Exception as e:
logger.error(f"【OpenList】下载文件 {fileitem.path} 失败:{e}")
if local_path.exists():
return local_path
if local_path.exists(): return local_path
return local_path
return None
def upload( def upload(
self, fileitem: schemas.FileItem, path: Path, new_name: Optional[str] = None, task: bool = False self, fileitem: schemas.FileItem, path: Path, new_name: Optional[str] = None, task: bool = False