mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-06-06 07:26:45 +00:00
fix(alist): support openlist rapid upload headers (#5897)
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import hashlib
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime
|
||||
@@ -708,6 +709,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
|
||||
# 获取文件大小
|
||||
target_name = new_name or path.name
|
||||
target_path = Path(fileitem.path) / target_name
|
||||
stat = path.stat()
|
||||
|
||||
# 初始化进度回调
|
||||
progress_callback = transfer_process(path.as_posix())
|
||||
@@ -718,6 +720,9 @@ class Alist(StorageBase, metaclass=WeakSingleton):
|
||||
headers.setdefault("Content-Type", "application/octet-stream")
|
||||
headers.setdefault("As-Task", str(task).lower())
|
||||
headers.setdefault("File-Path", encoded_path)
|
||||
headers.setdefault("Content-Length", str(stat.st_size))
|
||||
headers.setdefault("Last-Modified", str(int(stat.st_mtime * 1000)))
|
||||
headers.update(self.__get_upload_hash_headers(path))
|
||||
|
||||
# 创建自定义的文件流,支持进度回调
|
||||
class ProgressFileReader:
|
||||
@@ -783,6 +788,28 @@ class Alist(StorageBase, metaclass=WeakSingleton):
|
||||
logger.error(f"【OpenList】上传文件 {path} 失败:{e}")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def __get_upload_hash_headers(path: Path) -> dict:
|
||||
"""
|
||||
计算 OpenList 秒传所需的文件哈希请求头。
|
||||
"""
|
||||
md5_hash = hashlib.md5()
|
||||
sha1_hash = hashlib.sha1()
|
||||
sha256_hash = hashlib.sha256()
|
||||
with open(path, "rb") as file_handler:
|
||||
while True:
|
||||
chunk = file_handler.read(1024 * 1024)
|
||||
if not chunk:
|
||||
break
|
||||
md5_hash.update(chunk)
|
||||
sha1_hash.update(chunk)
|
||||
sha256_hash.update(chunk)
|
||||
return {
|
||||
"X-File-Md5": md5_hash.hexdigest(),
|
||||
"X-File-Sha1": sha1_hash.hexdigest(),
|
||||
"X-File-Sha256": sha256_hash.hexdigest(),
|
||||
}
|
||||
|
||||
def detail(self, fileitem: schemas.FileItem) -> Optional[schemas.FileItem]:
|
||||
"""
|
||||
获取文件详情
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import hashlib
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from app.modules.filemanager.storages import alist as alist_module
|
||||
@@ -137,3 +139,47 @@ class AlistStorageTest(unittest.TestCase):
|
||||
self.assertEqual("alist", target.storage)
|
||||
self.assertEqual("file", target.type)
|
||||
self.assertEqual(1024, target.size)
|
||||
|
||||
def test_upload_sends_hash_headers_for_rapid_upload(self):
|
||||
"""
|
||||
OpenList 上传应附带文件哈希头,供服务端尝试秒传。
|
||||
"""
|
||||
with TemporaryDirectory() as temp_dir:
|
||||
local_path = Path(temp_dir) / "rapid.bin"
|
||||
content = b"moviepilot-openlist-rapid-upload"
|
||||
local_path.write_bytes(content)
|
||||
upload_dir = FileItem(
|
||||
storage="alist",
|
||||
type="dir",
|
||||
path="/library/",
|
||||
name="library",
|
||||
basename="library",
|
||||
)
|
||||
uploaded_item = FileItem(
|
||||
storage="alist",
|
||||
type="file",
|
||||
path="/library/rapid.bin",
|
||||
name="rapid.bin",
|
||||
basename="rapid",
|
||||
extension="bin",
|
||||
size=len(content),
|
||||
)
|
||||
request_utils = MagicMock()
|
||||
request_utils.put_res.return_value = _FakeResponse(
|
||||
{"code": 200, "message": "success", "data": None}
|
||||
)
|
||||
|
||||
with patch.object(Alist, "get_conf", return_value={"url": "http://openlist.test", "token": "token"}):
|
||||
with patch.object(alist_module, "RequestUtils", return_value=request_utils) as request_utils_factory:
|
||||
with patch.object(self.storage, "_delay_get_item", return_value=uploaded_item):
|
||||
result = self.storage.upload(upload_dir, local_path)
|
||||
|
||||
self.assertEqual(uploaded_item, result)
|
||||
request_utils.put_res.assert_called_once()
|
||||
headers = request_utils_factory.call_args.kwargs["headers"]
|
||||
self.assertEqual(hashlib.md5(content).hexdigest(), headers["X-File-Md5"])
|
||||
self.assertEqual(hashlib.sha1(content).hexdigest(), headers["X-File-Sha1"])
|
||||
self.assertEqual(hashlib.sha256(content).hexdigest(), headers["X-File-Sha256"])
|
||||
self.assertEqual(str(len(content)), headers["Content-Length"])
|
||||
self.assertEqual("application/octet-stream", headers["Content-Type"])
|
||||
self.assertEqual("/library/rapid.bin", headers["File-Path"])
|
||||
|
||||
Reference in New Issue
Block a user