mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-04 23:17:20 +08:00
feat(monitor): enhance file handling with transfer history checks
This commit is contained in:
+50
-21
@@ -17,6 +17,7 @@ from app.chain.storage import StorageChain
|
|||||||
from app.chain.transfer import TransferChain
|
from app.chain.transfer import TransferChain
|
||||||
from app.core.cache import TTLCache, FileCache
|
from app.core.cache import TTLCache, FileCache
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
from app.db.transferhistory_oper import TransferHistoryOper
|
||||||
from app.helper.directory import DirectoryHelper
|
from app.helper.directory import DirectoryHelper
|
||||||
from app.helper.message import MessageHelper
|
from app.helper.message import MessageHelper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
@@ -328,10 +329,9 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
|
|||||||
try:
|
try:
|
||||||
if not self.__is_transfer_candidate_path(Path(file_path)):
|
if not self.__is_transfer_candidate_path(Path(file_path)):
|
||||||
continue
|
continue
|
||||||
logger.info(f"处理文件:{file_path}")
|
|
||||||
file_size = file_info.get('size', 0) if isinstance(file_info, dict) else file_info
|
file_size = file_info.get('size', 0) if isinstance(file_info, dict) else file_info
|
||||||
self.__handle_file(storage=storage, event_path=Path(file_path), file_size=file_size)
|
if self.__handle_file(storage=storage, event_path=Path(file_path), file_size=file_size):
|
||||||
processed_count += 1
|
processed_count += 1
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"处理文件 {file_path} 失败: {e}")
|
logger.error(f"处理文件 {file_path} 失败: {e}")
|
||||||
continue
|
continue
|
||||||
@@ -453,6 +453,26 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
|
|||||||
return False
|
return False
|
||||||
return self.__has_suffix_in(file_path, self.all_exts)
|
return self.__has_suffix_in(file_path, self.all_exts)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __build_transfer_src_path(event_path: Path, is_bluray_folder: bool) -> str:
|
||||||
|
"""
|
||||||
|
生成整理记录使用的源路径。
|
||||||
|
"""
|
||||||
|
if is_bluray_folder:
|
||||||
|
return f"{event_path.as_posix()}/"
|
||||||
|
return event_path.as_posix()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __has_transfer_history(storage: str, src_path: str) -> Optional[bool]:
|
||||||
|
"""
|
||||||
|
判断源文件是否已经存在整理记录。
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return bool(TransferHistoryOper().get_by_src(src_path, storage=storage))
|
||||||
|
except Exception as err:
|
||||||
|
logger.error(f"查询整理历史失败: {src_path} - {err}")
|
||||||
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def count_directory_files(directory: Path, max_check: int = 10000) -> int:
|
def count_directory_files(directory: Path, max_check: int = 10000) -> int:
|
||||||
"""
|
"""
|
||||||
@@ -761,22 +781,24 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
|
|||||||
]
|
]
|
||||||
|
|
||||||
# 处理新增文件
|
# 处理新增文件
|
||||||
|
handled_added_count = 0
|
||||||
for new_file in added_files:
|
for new_file in added_files:
|
||||||
logger.info(f"发现新增文件:{new_file}")
|
|
||||||
file_info = new_snapshot.get(new_file, {})
|
file_info = new_snapshot.get(new_file, {})
|
||||||
file_size = file_info.get('size', 0) if isinstance(file_info, dict) else file_info
|
file_size = file_info.get('size', 0) if isinstance(file_info, dict) else file_info
|
||||||
self.__handle_file(storage=storage, event_path=Path(new_file), file_size=file_size)
|
if self.__handle_file(storage=storage, event_path=Path(new_file), file_size=file_size):
|
||||||
|
handled_added_count += 1
|
||||||
|
|
||||||
# 处理修改文件
|
# 处理修改文件
|
||||||
|
handled_modified_count = 0
|
||||||
for modified_file in modified_files:
|
for modified_file in modified_files:
|
||||||
logger.info(f"发现修改文件:{modified_file}")
|
|
||||||
file_info = new_snapshot.get(modified_file, {})
|
file_info = new_snapshot.get(modified_file, {})
|
||||||
file_size = file_info.get('size', 0) if isinstance(file_info, dict) else file_info
|
file_size = file_info.get('size', 0) if isinstance(file_info, dict) else file_info
|
||||||
self.__handle_file(storage=storage, event_path=Path(modified_file), file_size=file_size)
|
if self.__handle_file(storage=storage, event_path=Path(modified_file), file_size=file_size):
|
||||||
|
handled_modified_count += 1
|
||||||
|
|
||||||
if added_files or modified_files:
|
if handled_added_count or handled_modified_count:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"{storage} 发现 {len(added_files)} 个新增文件,{len(modified_files)} 个修改文件")
|
f"{storage} 发现 {handled_added_count} 个新增文件,{handled_modified_count} 个修改文件")
|
||||||
else:
|
else:
|
||||||
logger.debug(f"{storage} 无文件变化")
|
logger.debug(f"{storage} 无文件变化")
|
||||||
else:
|
else:
|
||||||
@@ -813,17 +835,16 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
|
|||||||
if not event.is_directory:
|
if not event.is_directory:
|
||||||
if not self.__is_transfer_candidate_path(Path(event_path)):
|
if not self.__is_transfer_candidate_path(Path(event_path)):
|
||||||
return
|
return
|
||||||
# 文件发生变化
|
|
||||||
logger.debug(f"检测到文件变化: {event_path} [{text}]")
|
|
||||||
# 整理文件
|
# 整理文件
|
||||||
self.__handle_file(storage="local", event_path=Path(event_path), file_size=file_size)
|
self.__handle_file(storage="local", event_path=Path(event_path), file_size=file_size)
|
||||||
|
|
||||||
def __handle_file(self, storage: str, event_path: Path, file_size: float = None):
|
def __handle_file(self, storage: str, event_path: Path, file_size: float = None) -> bool:
|
||||||
"""
|
"""
|
||||||
整理一个文件
|
整理一个文件
|
||||||
:param storage: 存储
|
:param storage: 存储
|
||||||
:param event_path: 事件文件路径
|
:param event_path: 事件文件路径
|
||||||
:param file_size: 文件大小
|
:param file_size: 文件大小
|
||||||
|
:return: 是否进入整理链
|
||||||
"""
|
"""
|
||||||
# 全程加锁
|
# 全程加锁
|
||||||
with lock:
|
with lock:
|
||||||
@@ -832,17 +853,27 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
|
|||||||
if self.__is_bluray_sub(event_path):
|
if self.__is_bluray_sub(event_path):
|
||||||
event_path = self.__get_bluray_dir(event_path)
|
event_path = self.__get_bluray_dir(event_path)
|
||||||
if not event_path:
|
if not event_path:
|
||||||
return
|
return False
|
||||||
is_bluray_folder = True
|
is_bluray_folder = True
|
||||||
elif not self.__is_transfer_candidate_path(event_path):
|
elif not self.__is_transfer_candidate_path(event_path):
|
||||||
return
|
return False
|
||||||
|
|
||||||
# TTL缓存控重
|
# TTL缓存控重
|
||||||
if self._cache.get(str(event_path)):
|
if self._cache.get(str(event_path)):
|
||||||
logger.debug(f"文件 {event_path} 在缓存中,跳过处理")
|
return False
|
||||||
return
|
|
||||||
self._cache[str(event_path)] = True
|
self._cache[str(event_path)] = True
|
||||||
|
|
||||||
|
src_path = self.__build_transfer_src_path(
|
||||||
|
event_path=event_path,
|
||||||
|
is_bluray_folder=is_bluray_folder,
|
||||||
|
)
|
||||||
|
has_transfer_history = self.__has_transfer_history(
|
||||||
|
storage=storage,
|
||||||
|
src_path=src_path,
|
||||||
|
)
|
||||||
|
if has_transfer_history is not False:
|
||||||
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if is_bluray_folder:
|
if is_bluray_folder:
|
||||||
logger.info(f"开始整理蓝光原盘: {event_path}")
|
logger.info(f"开始整理蓝光原盘: {event_path}")
|
||||||
@@ -852,11 +883,7 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
|
|||||||
TransferChain().do_transfer(
|
TransferChain().do_transfer(
|
||||||
fileitem=FileItem(
|
fileitem=FileItem(
|
||||||
storage=storage,
|
storage=storage,
|
||||||
path=(
|
path=src_path,
|
||||||
event_path.as_posix()
|
|
||||||
if not is_bluray_folder
|
|
||||||
else event_path.as_posix() + "/"
|
|
||||||
),
|
|
||||||
type="file" if not is_bluray_folder else "dir",
|
type="file" if not is_bluray_folder else "dir",
|
||||||
name=event_path.name,
|
name=event_path.name,
|
||||||
basename=event_path.stem,
|
basename=event_path.stem,
|
||||||
@@ -864,8 +891,10 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
|
|||||||
size=file_size
|
size=file_size
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("目录监控整理文件发生错误:%s - %s" % (str(e), traceback.format_exc()))
|
logger.error("目录监控整理文件发生错误:%s - %s" % (str(e), traceback.format_exc()))
|
||||||
|
return False
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
+221
-139
@@ -1,5 +1,3 @@
|
|||||||
import tempfile
|
|
||||||
import unittest
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
@@ -30,160 +28,244 @@ class CallbackRecorder:
|
|||||||
self.events.append((event, text, event_path, file_size))
|
self.events.append((event, text, event_path, file_size))
|
||||||
|
|
||||||
|
|
||||||
class LocalDirectoryWatcherTest(unittest.TestCase):
|
def test_handle_changes_dispatches_added_and_modified_files(tmp_path):
|
||||||
"""
|
"""
|
||||||
watchfiles 本地目录监控测试。
|
新增和修改文件应转换成目录监控整理回调。
|
||||||
"""
|
"""
|
||||||
|
added_file = tmp_path / "a_added.mkv"
|
||||||
|
modified_file = tmp_path / "b_modified.mkv"
|
||||||
|
skipped_dir = tmp_path / "c_dir"
|
||||||
|
added_file.write_bytes(b"added")
|
||||||
|
modified_file.write_bytes(b"modified")
|
||||||
|
skipped_dir.mkdir()
|
||||||
|
|
||||||
def test_handle_changes_dispatches_added_and_modified_files(self):
|
callback = CallbackRecorder()
|
||||||
"""
|
watcher = LocalDirectoryWatcher(tmp_path, callback=callback, force_polling=True)
|
||||||
新增和修改文件应转换成目录监控整理回调。
|
watcher._handle_changes({
|
||||||
"""
|
(Change.added, added_file.as_posix()),
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
(Change.modified, modified_file.as_posix()),
|
||||||
watch_dir = Path(temp_dir)
|
(Change.deleted, added_file.as_posix()),
|
||||||
added_file = watch_dir / "a_added.mkv"
|
(Change.added, skipped_dir.as_posix()),
|
||||||
modified_file = watch_dir / "b_modified.mkv"
|
})
|
||||||
skipped_dir = watch_dir / "c_dir"
|
|
||||||
added_file.write_bytes(b"added")
|
|
||||||
modified_file.write_bytes(b"modified")
|
|
||||||
skipped_dir.mkdir()
|
|
||||||
|
|
||||||
callback = CallbackRecorder()
|
assert len(callback.events) == 2
|
||||||
watcher = LocalDirectoryWatcher(watch_dir, callback=callback, force_polling=True)
|
assert (
|
||||||
watcher._handle_changes({
|
Change.added,
|
||||||
(Change.added, added_file.as_posix()),
|
"新增",
|
||||||
(Change.modified, modified_file.as_posix()),
|
added_file.as_posix(),
|
||||||
(Change.deleted, added_file.as_posix()),
|
5,
|
||||||
(Change.added, skipped_dir.as_posix()),
|
) == (
|
||||||
})
|
callback.events[0][0].change_type,
|
||||||
|
callback.events[0][1],
|
||||||
self.assertEqual(2, len(callback.events))
|
callback.events[0][2],
|
||||||
self.assertEqual((Change.added, "新增", added_file.as_posix(), 5),
|
callback.events[0][3],
|
||||||
(callback.events[0][0].change_type,
|
)
|
||||||
callback.events[0][1],
|
assert (
|
||||||
callback.events[0][2],
|
Change.modified,
|
||||||
callback.events[0][3]))
|
"修改",
|
||||||
self.assertEqual((Change.modified, "修改", modified_file.as_posix(), 8),
|
modified_file.as_posix(),
|
||||||
(callback.events[1][0].change_type,
|
8,
|
||||||
callback.events[1][1],
|
) == (
|
||||||
callback.events[1][2],
|
callback.events[1][0].change_type,
|
||||||
callback.events[1][3]))
|
callback.events[1][1],
|
||||||
|
callback.events[1][2],
|
||||||
def test_handle_changes_skips_missing_paths(self):
|
callback.events[1][3],
|
||||||
"""
|
)
|
||||||
事件到达时已经消失的路径不应触发整理。
|
|
||||||
"""
|
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
|
||||||
watch_dir = Path(temp_dir)
|
|
||||||
missing_file = watch_dir / "missing.mkv"
|
|
||||||
|
|
||||||
callback = CallbackRecorder()
|
|
||||||
watcher = LocalDirectoryWatcher(watch_dir, callback=callback, force_polling=True)
|
|
||||||
watcher._handle_changes({(Change.added, missing_file.as_posix())})
|
|
||||||
|
|
||||||
self.assertEqual([], callback.events)
|
|
||||||
|
|
||||||
|
|
||||||
class MonitorWatchfilesEventTest(unittest.TestCase):
|
def test_handle_changes_skips_missing_paths(tmp_path):
|
||||||
"""
|
"""
|
||||||
Monitor 对 watchfiles 事件的兼容处理测试。
|
事件到达时已经消失的路径不应触发整理。
|
||||||
"""
|
"""
|
||||||
|
missing_file = tmp_path / "missing.mkv"
|
||||||
|
|
||||||
def test_event_handler_routes_file_events_to_transfer_handler(self):
|
callback = CallbackRecorder()
|
||||||
|
watcher = LocalDirectoryWatcher(tmp_path, callback=callback, force_polling=True)
|
||||||
|
watcher._handle_changes({(Change.added, missing_file.as_posix())})
|
||||||
|
|
||||||
|
assert callback.events == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_event_handler_routes_file_events_to_transfer_handler():
|
||||||
|
"""
|
||||||
|
文件事件应继续按 local 存储交给整理流程。
|
||||||
|
"""
|
||||||
|
monitor = object.__new__(Monitor)
|
||||||
|
monitor.all_exts = [".mkv"]
|
||||||
|
handle_file = MagicMock()
|
||||||
|
setattr(monitor, "_Monitor__handle_file", handle_file)
|
||||||
|
event_path = Path("/downloads/movie.mkv")
|
||||||
|
event = DirectoryChangeEvent(
|
||||||
|
change_type=Change.added,
|
||||||
|
src_path=event_path.as_posix(),
|
||||||
|
is_directory=False
|
||||||
|
)
|
||||||
|
|
||||||
|
monitor.event_handler(
|
||||||
|
event=event,
|
||||||
|
text="新增",
|
||||||
|
event_path=event_path.as_posix(),
|
||||||
|
file_size=1024
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_file.assert_called_once_with(
|
||||||
|
storage="local",
|
||||||
|
event_path=event_path,
|
||||||
|
file_size=1024
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_event_handler_ignores_directory_events():
|
||||||
|
"""
|
||||||
|
目录事件不应进入文件整理流程。
|
||||||
|
"""
|
||||||
|
monitor = object.__new__(Monitor)
|
||||||
|
monitor.all_exts = [".mkv"]
|
||||||
|
handle_file = MagicMock()
|
||||||
|
setattr(monitor, "_Monitor__handle_file", handle_file)
|
||||||
|
event_path = Path("/downloads/folder")
|
||||||
|
event = DirectoryChangeEvent(
|
||||||
|
change_type=Change.added,
|
||||||
|
src_path=event_path.as_posix(),
|
||||||
|
is_directory=True
|
||||||
|
)
|
||||||
|
|
||||||
|
monitor.event_handler(
|
||||||
|
event=event,
|
||||||
|
text="新增",
|
||||||
|
event_path=event_path.as_posix()
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_file.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_event_handler_ignores_download_temp_files():
|
||||||
|
"""
|
||||||
|
下载器临时文件不应进入整理流程。
|
||||||
|
"""
|
||||||
|
monitor = object.__new__(Monitor)
|
||||||
|
monitor.all_exts = [".mkv"]
|
||||||
|
handle_file = MagicMock()
|
||||||
|
setattr(monitor, "_Monitor__handle_file", handle_file)
|
||||||
|
event_path = Path("/downloads/movie.mkv.!qB")
|
||||||
|
event = DirectoryChangeEvent(
|
||||||
|
change_type=Change.modified,
|
||||||
|
src_path=event_path.as_posix(),
|
||||||
|
is_directory=False
|
||||||
|
)
|
||||||
|
|
||||||
|
monitor.event_handler(
|
||||||
|
event=event,
|
||||||
|
text="修改",
|
||||||
|
event_path=event_path.as_posix(),
|
||||||
|
file_size=1024
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_file.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_event_handler_ignores_non_transferable_files():
|
||||||
|
"""
|
||||||
|
非可整理后缀文件不应进入整理流程。
|
||||||
|
"""
|
||||||
|
monitor = object.__new__(Monitor)
|
||||||
|
monitor.all_exts = [".mkv"]
|
||||||
|
handle_file = MagicMock()
|
||||||
|
setattr(monitor, "_Monitor__handle_file", handle_file)
|
||||||
|
event_path = Path("/downloads/movie.nfo")
|
||||||
|
event = DirectoryChangeEvent(
|
||||||
|
change_type=Change.added,
|
||||||
|
src_path=event_path.as_posix(),
|
||||||
|
is_directory=False
|
||||||
|
)
|
||||||
|
|
||||||
|
monitor.event_handler(
|
||||||
|
event=event,
|
||||||
|
text="新增",
|
||||||
|
event_path=event_path.as_posix(),
|
||||||
|
file_size=1024
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_file.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_handle_file_skips_transfer_when_history_exists(monkeypatch):
|
||||||
|
"""
|
||||||
|
已有整理记录的源文件不应再次进入整理链。
|
||||||
|
"""
|
||||||
|
monitor = object.__new__(Monitor)
|
||||||
|
monitor.all_exts = [".mkv"]
|
||||||
|
monitor._cache = {}
|
||||||
|
event_path = Path("/downloads/movie.mkv")
|
||||||
|
lookups = []
|
||||||
|
|
||||||
|
class FakeTransferHistoryOper:
|
||||||
"""
|
"""
|
||||||
文件事件应继续按 local 存储交给整理流程。
|
测试用整理历史查询。
|
||||||
"""
|
"""
|
||||||
monitor = object.__new__(Monitor)
|
|
||||||
monitor.all_exts = [".mkv"]
|
|
||||||
handle_file = MagicMock()
|
|
||||||
setattr(monitor, "_Monitor__handle_file", handle_file)
|
|
||||||
event_path = Path("/downloads/movie.mkv")
|
|
||||||
event = DirectoryChangeEvent(
|
|
||||||
change_type=Change.added,
|
|
||||||
src_path=event_path.as_posix(),
|
|
||||||
is_directory=False
|
|
||||||
)
|
|
||||||
|
|
||||||
monitor.event_handler(
|
def get_by_src(self, src: str, storage: str = None):
|
||||||
event=event,
|
"""
|
||||||
text="新增",
|
记录查询参数并返回已有记录。
|
||||||
event_path=event_path.as_posix(),
|
"""
|
||||||
file_size=1024
|
lookups.append((src, storage))
|
||||||
)
|
return object()
|
||||||
|
|
||||||
handle_file.assert_called_once_with(
|
transfer_chain = MagicMock()
|
||||||
storage="local",
|
logger_info = MagicMock()
|
||||||
event_path=event_path,
|
logger_debug = MagicMock()
|
||||||
file_size=1024
|
monkeypatch.setattr("app.monitor.TransferHistoryOper", FakeTransferHistoryOper)
|
||||||
)
|
monkeypatch.setattr("app.monitor.TransferChain", transfer_chain)
|
||||||
|
monkeypatch.setattr("app.monitor.logger.info", logger_info)
|
||||||
|
monkeypatch.setattr("app.monitor.logger.debug", logger_debug)
|
||||||
|
|
||||||
def test_event_handler_ignores_directory_events(self):
|
handled = monitor._Monitor__handle_file(
|
||||||
|
storage="local",
|
||||||
|
event_path=event_path,
|
||||||
|
file_size=1024,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert not handled
|
||||||
|
assert lookups == [(event_path.as_posix(), "local")]
|
||||||
|
transfer_chain.assert_not_called()
|
||||||
|
logger_info.assert_not_called()
|
||||||
|
logger_debug.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_handle_file_invokes_transfer_when_history_missing(monkeypatch):
|
||||||
|
"""
|
||||||
|
没有整理记录的源文件应继续进入整理链。
|
||||||
|
"""
|
||||||
|
monitor = object.__new__(Monitor)
|
||||||
|
monitor.all_exts = [".mkv"]
|
||||||
|
monitor._cache = {}
|
||||||
|
event_path = Path("/downloads/movie.mkv")
|
||||||
|
|
||||||
|
class FakeTransferHistoryOper:
|
||||||
"""
|
"""
|
||||||
目录事件不应进入文件整理流程。
|
测试用空整理历史查询。
|
||||||
"""
|
"""
|
||||||
monitor = object.__new__(Monitor)
|
|
||||||
monitor.all_exts = [".mkv"]
|
|
||||||
handle_file = MagicMock()
|
|
||||||
setattr(monitor, "_Monitor__handle_file", handle_file)
|
|
||||||
event_path = Path("/downloads/folder")
|
|
||||||
event = DirectoryChangeEvent(
|
|
||||||
change_type=Change.added,
|
|
||||||
src_path=event_path.as_posix(),
|
|
||||||
is_directory=True
|
|
||||||
)
|
|
||||||
|
|
||||||
monitor.event_handler(
|
def get_by_src(self, src: str, storage: str = None):
|
||||||
event=event,
|
"""
|
||||||
text="新增",
|
返回空整理记录。
|
||||||
event_path=event_path.as_posix()
|
"""
|
||||||
)
|
return None
|
||||||
|
|
||||||
handle_file.assert_not_called()
|
transfer_chain_instance = MagicMock()
|
||||||
|
transfer_chain = MagicMock(return_value=transfer_chain_instance)
|
||||||
|
monkeypatch.setattr("app.monitor.TransferHistoryOper", FakeTransferHistoryOper)
|
||||||
|
monkeypatch.setattr("app.monitor.TransferChain", transfer_chain)
|
||||||
|
|
||||||
def test_event_handler_ignores_download_temp_files(self):
|
handled = monitor._Monitor__handle_file(
|
||||||
"""
|
storage="local",
|
||||||
下载器临时文件不应进入整理流程。
|
event_path=event_path,
|
||||||
"""
|
file_size=1024,
|
||||||
monitor = object.__new__(Monitor)
|
)
|
||||||
monitor.all_exts = [".mkv"]
|
|
||||||
handle_file = MagicMock()
|
|
||||||
setattr(monitor, "_Monitor__handle_file", handle_file)
|
|
||||||
event_path = Path("/downloads/movie.mkv.!qB")
|
|
||||||
event = DirectoryChangeEvent(
|
|
||||||
change_type=Change.modified,
|
|
||||||
src_path=event_path.as_posix(),
|
|
||||||
is_directory=False
|
|
||||||
)
|
|
||||||
|
|
||||||
monitor.event_handler(
|
assert handled
|
||||||
event=event,
|
transfer_chain_instance.do_transfer.assert_called_once()
|
||||||
text="修改",
|
fileitem = transfer_chain_instance.do_transfer.call_args.kwargs["fileitem"]
|
||||||
event_path=event_path.as_posix(),
|
assert fileitem.storage == "local"
|
||||||
file_size=1024
|
assert fileitem.path == event_path.as_posix()
|
||||||
)
|
assert fileitem.size == 1024
|
||||||
|
|
||||||
handle_file.assert_not_called()
|
|
||||||
|
|
||||||
def test_event_handler_ignores_non_transferable_files(self):
|
|
||||||
"""
|
|
||||||
非可整理后缀文件不应进入整理流程。
|
|
||||||
"""
|
|
||||||
monitor = object.__new__(Monitor)
|
|
||||||
monitor.all_exts = [".mkv"]
|
|
||||||
handle_file = MagicMock()
|
|
||||||
setattr(monitor, "_Monitor__handle_file", handle_file)
|
|
||||||
event_path = Path("/downloads/movie.nfo")
|
|
||||||
event = DirectoryChangeEvent(
|
|
||||||
change_type=Change.added,
|
|
||||||
src_path=event_path.as_posix(),
|
|
||||||
is_directory=False
|
|
||||||
)
|
|
||||||
|
|
||||||
monitor.event_handler(
|
|
||||||
event=event,
|
|
||||||
text="新增",
|
|
||||||
event_path=event_path.as_posix(),
|
|
||||||
file_size=1024
|
|
||||||
)
|
|
||||||
|
|
||||||
handle_file.assert_not_called()
|
|
||||||
|
|||||||
Reference in New Issue
Block a user