mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-28 19:47:41 +08:00
fix: skip non-transferable monitor files
This commit is contained in:
+56
-22
@@ -326,6 +326,8 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
|
|||||||
processed_count = 0
|
processed_count = 0
|
||||||
for file_path, file_info in new_snapshot.items():
|
for file_path, file_info in new_snapshot.items():
|
||||||
try:
|
try:
|
||||||
|
if not self.__is_transfer_candidate_path(Path(file_path)):
|
||||||
|
continue
|
||||||
logger.info(f"处理文件:{file_path}")
|
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)
|
self.__handle_file(storage=storage, event_path=Path(file_path), file_size=file_size)
|
||||||
@@ -417,6 +419,40 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
|
|||||||
|
|
||||||
return changes
|
return changes
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __is_bluray_sub(_path: Path) -> bool:
|
||||||
|
"""
|
||||||
|
判断是否蓝光原盘目录内的媒体流文件。
|
||||||
|
"""
|
||||||
|
return True if re.search(r"BDMV[/\\]STREAM", _path.as_posix(), re.IGNORECASE) else False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __get_bluray_dir(_path: Path) -> Optional[Path]:
|
||||||
|
"""
|
||||||
|
获取蓝光原盘BDMV目录的上级目录。
|
||||||
|
"""
|
||||||
|
for p in _path.parents:
|
||||||
|
if p.name == "BDMV":
|
||||||
|
return p.parent
|
||||||
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __has_suffix_in(file_path: Path, extensions: List[str]) -> bool:
|
||||||
|
"""
|
||||||
|
判断路径后缀是否命中给定扩展名列表。
|
||||||
|
"""
|
||||||
|
if not file_path.suffix:
|
||||||
|
return False
|
||||||
|
return file_path.suffix.casefold() in {ext.casefold() for ext in extensions}
|
||||||
|
|
||||||
|
def __is_transfer_candidate_path(self, file_path: Path) -> bool:
|
||||||
|
"""
|
||||||
|
判断监控事件路径是否需要进入整理链。
|
||||||
|
"""
|
||||||
|
if self.__has_suffix_in(file_path, settings.DOWNLOAD_TMPEXT):
|
||||||
|
return False
|
||||||
|
return self.__has_suffix_in(file_path, self.all_exts)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def count_directory_files(directory: Path, max_check: int = 10000) -> int:
|
def count_directory_files(directory: Path, max_check: int = 10000) -> int:
|
||||||
"""
|
"""
|
||||||
@@ -713,24 +749,34 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
|
|||||||
if not is_first_snapshot:
|
if not is_first_snapshot:
|
||||||
# 比较快照找出变化
|
# 比较快照找出变化
|
||||||
changes = self.compare_snapshots(old_snapshot, new_snapshot)
|
changes = self.compare_snapshots(old_snapshot, new_snapshot)
|
||||||
|
added_files = [
|
||||||
|
file_path
|
||||||
|
for file_path in changes['added']
|
||||||
|
if self.__is_transfer_candidate_path(Path(file_path))
|
||||||
|
]
|
||||||
|
modified_files = [
|
||||||
|
file_path
|
||||||
|
for file_path in changes['modified']
|
||||||
|
if self.__is_transfer_candidate_path(Path(file_path))
|
||||||
|
]
|
||||||
|
|
||||||
# 处理新增文件
|
# 处理新增文件
|
||||||
for new_file in changes['added']:
|
for new_file in added_files:
|
||||||
logger.info(f"发现新增文件:{new_file}")
|
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)
|
self.__handle_file(storage=storage, event_path=Path(new_file), file_size=file_size)
|
||||||
|
|
||||||
# 处理修改文件
|
# 处理修改文件
|
||||||
for modified_file in changes['modified']:
|
for modified_file in modified_files:
|
||||||
logger.info(f"发现修改文件:{modified_file}")
|
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)
|
self.__handle_file(storage=storage, event_path=Path(modified_file), file_size=file_size)
|
||||||
|
|
||||||
if changes['added'] or changes['modified']:
|
if added_files or modified_files:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"{storage} 发现 {len(changes['added'])} 个新增文件,{len(changes['modified'])} 个修改文件")
|
f"{storage} 发现 {len(added_files)} 个新增文件,{len(modified_files)} 个修改文件")
|
||||||
else:
|
else:
|
||||||
logger.debug(f"{storage} 无文件变化")
|
logger.debug(f"{storage} 无文件变化")
|
||||||
else:
|
else:
|
||||||
@@ -765,6 +811,8 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
|
|||||||
:param file_size: 文件大小
|
:param file_size: 文件大小
|
||||||
"""
|
"""
|
||||||
if not event.is_directory:
|
if not event.is_directory:
|
||||||
|
if not self.__is_transfer_candidate_path(Path(event_path)):
|
||||||
|
return
|
||||||
# 文件发生变化
|
# 文件发生变化
|
||||||
logger.debug(f"检测到文件变化: {event_path} [{text}]")
|
logger.debug(f"检测到文件变化: {event_path} [{text}]")
|
||||||
# 整理文件
|
# 整理文件
|
||||||
@@ -777,31 +825,17 @@ class Monitor(ConfigReloadMixin, metaclass=SingletonClass):
|
|||||||
:param event_path: 事件文件路径
|
:param event_path: 事件文件路径
|
||||||
:param file_size: 文件大小
|
:param file_size: 文件大小
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __is_bluray_sub(_path: Path) -> bool:
|
|
||||||
"""
|
|
||||||
判断是否蓝光原盘目录内的子目录或文件
|
|
||||||
"""
|
|
||||||
return True if re.search(r"BDMV/STREAM", _path.as_posix(), re.IGNORECASE) else False
|
|
||||||
|
|
||||||
def __get_bluray_dir(_path: Path) -> Optional[Path]:
|
|
||||||
"""
|
|
||||||
获取蓝光原盘BDMV目录的上级目录
|
|
||||||
"""
|
|
||||||
for p in _path.parents:
|
|
||||||
if p.name == "BDMV":
|
|
||||||
return p.parent
|
|
||||||
return None
|
|
||||||
|
|
||||||
# 全程加锁
|
# 全程加锁
|
||||||
with lock:
|
with lock:
|
||||||
is_bluray_folder = False
|
is_bluray_folder = False
|
||||||
# 蓝光原盘文件处理
|
# 蓝光原盘文件处理
|
||||||
if __is_bluray_sub(event_path):
|
if self.__is_bluray_sub(event_path):
|
||||||
event_path = __get_bluray_dir(event_path)
|
event_path = self.__get_bluray_dir(event_path)
|
||||||
if not event_path:
|
if not event_path:
|
||||||
return
|
return
|
||||||
is_bluray_folder = True
|
is_bluray_folder = True
|
||||||
|
elif not self.__is_transfer_candidate_path(event_path):
|
||||||
|
return
|
||||||
|
|
||||||
# TTL缓存控重
|
# TTL缓存控重
|
||||||
if self._cache.get(str(event_path)):
|
if self._cache.get(str(event_path)):
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ class MonitorWatchfilesEventTest(unittest.TestCase):
|
|||||||
文件事件应继续按 local 存储交给整理流程。
|
文件事件应继续按 local 存储交给整理流程。
|
||||||
"""
|
"""
|
||||||
monitor = object.__new__(Monitor)
|
monitor = object.__new__(Monitor)
|
||||||
|
monitor.all_exts = [".mkv"]
|
||||||
handle_file = MagicMock()
|
handle_file = MagicMock()
|
||||||
setattr(monitor, "_Monitor__handle_file", handle_file)
|
setattr(monitor, "_Monitor__handle_file", handle_file)
|
||||||
event_path = Path("/downloads/movie.mkv")
|
event_path = Path("/downloads/movie.mkv")
|
||||||
@@ -121,6 +122,7 @@ class MonitorWatchfilesEventTest(unittest.TestCase):
|
|||||||
目录事件不应进入文件整理流程。
|
目录事件不应进入文件整理流程。
|
||||||
"""
|
"""
|
||||||
monitor = object.__new__(Monitor)
|
monitor = object.__new__(Monitor)
|
||||||
|
monitor.all_exts = [".mkv"]
|
||||||
handle_file = MagicMock()
|
handle_file = MagicMock()
|
||||||
setattr(monitor, "_Monitor__handle_file", handle_file)
|
setattr(monitor, "_Monitor__handle_file", handle_file)
|
||||||
event_path = Path("/downloads/folder")
|
event_path = Path("/downloads/folder")
|
||||||
@@ -137,3 +139,51 @@ class MonitorWatchfilesEventTest(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
handle_file.assert_not_called()
|
handle_file.assert_not_called()
|
||||||
|
|
||||||
|
def test_event_handler_ignores_download_temp_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.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(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