mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 07:27:15 +08:00
fix #4834
This commit is contained in:
@@ -246,6 +246,17 @@ class LocalStorage(StorageBase):
|
|||||||
logger.error(f"【本地】移动文件失败:{err}")
|
logger.error(f"【本地】移动文件失败:{err}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __should_show_progress(src: Path, dest: Path):
|
||||||
|
"""
|
||||||
|
是否显示进度条
|
||||||
|
"""
|
||||||
|
src_isnetwork = SystemUtils.is_network_filesystem(src)
|
||||||
|
dest_isnetwork = SystemUtils.is_network_filesystem(dest)
|
||||||
|
if src_isnetwork and dest_isnetwork and SystemUtils.is_same_disk(src, dest):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def copy(
|
def copy(
|
||||||
self,
|
self,
|
||||||
fileitem: schemas.FileItem,
|
fileitem: schemas.FileItem,
|
||||||
@@ -258,8 +269,15 @@ class LocalStorage(StorageBase):
|
|||||||
try:
|
try:
|
||||||
src = Path(fileitem.path)
|
src = Path(fileitem.path)
|
||||||
dest = path / new_name
|
dest = path / new_name
|
||||||
if self._copy_with_progress(src, dest):
|
if self.__should_show_progress(src, dest):
|
||||||
return True
|
if self._copy_with_progress(src, dest):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
code, message = SystemUtils.copy(src, dest)
|
||||||
|
if code == 0:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
logger.error(f"【本地】复制文件失败:{message}")
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"【本地】复制文件失败:{err}")
|
logger.error(f"【本地】复制文件失败:{err}")
|
||||||
return False
|
return False
|
||||||
@@ -276,10 +294,17 @@ class LocalStorage(StorageBase):
|
|||||||
try:
|
try:
|
||||||
src = Path(fileitem.path)
|
src = Path(fileitem.path)
|
||||||
dest = path / new_name
|
dest = path / new_name
|
||||||
if self._copy_with_progress(src, dest):
|
if self.__should_show_progress(src, dest):
|
||||||
# 复制成功删除源文件
|
if self._copy_with_progress(src, dest):
|
||||||
src.unlink()
|
# 复制成功删除源文件
|
||||||
return True
|
src.unlink()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
code, message = SystemUtils.move(src, dest)
|
||||||
|
if code == 0:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
logger.error(f"【本地】移动文件失败:{message}")
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"【本地】移动文件失败:{err}")
|
logger.error(f"【本地】移动文件失败:{err}")
|
||||||
return False
|
return False
|
||||||
|
|||||||
+5
-43
@@ -1,7 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
import platform
|
import platform
|
||||||
import re
|
import re
|
||||||
import subprocess
|
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
@@ -10,13 +9,13 @@ from threading import Lock
|
|||||||
from typing import Any, Optional, Dict, List
|
from typing import Any, Optional, Dict, List
|
||||||
|
|
||||||
from apscheduler.schedulers.background import BackgroundScheduler
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
from app.core.cache import TTLCache, FileCache
|
|
||||||
from watchdog.events import FileSystemEventHandler, FileSystemMovedEvent, FileSystemEvent
|
from watchdog.events import FileSystemEventHandler, FileSystemMovedEvent, FileSystemEvent
|
||||||
from watchdog.observers.polling import PollingObserver
|
from watchdog.observers.polling import PollingObserver
|
||||||
|
|
||||||
from app.chain import ChainBase
|
from app.chain import ChainBase
|
||||||
from app.chain.storage import StorageChain
|
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.config import settings
|
from app.core.config import settings
|
||||||
from app.core.event import Event, eventmanager
|
from app.core.event import Event, eventmanager
|
||||||
from app.helper.directory import DirectoryHelper
|
from app.helper.directory import DirectoryHelper
|
||||||
@@ -26,6 +25,7 @@ from app.schemas import ConfigChangeEventData
|
|||||||
from app.schemas import FileItem
|
from app.schemas import FileItem
|
||||||
from app.schemas.types import SystemConfigKey, EventType
|
from app.schemas.types import SystemConfigKey, EventType
|
||||||
from app.utils.singleton import SingletonClass
|
from app.utils.singleton import SingletonClass
|
||||||
|
from app.utils.system import SystemUtils
|
||||||
|
|
||||||
lock = Lock()
|
lock = Lock()
|
||||||
snapshot_lock = Lock()
|
snapshot_lock = Lock()
|
||||||
@@ -355,7 +355,8 @@ class Monitor(metaclass=SingletonClass):
|
|||||||
|
|
||||||
return tips
|
return tips
|
||||||
|
|
||||||
def should_use_polling(self, directory: Path, monitor_mode: str,
|
@staticmethod
|
||||||
|
def should_use_polling(directory: Path, monitor_mode: str,
|
||||||
file_count: int, limits: dict) -> tuple[bool, str]:
|
file_count: int, limits: dict) -> tuple[bool, str]:
|
||||||
"""
|
"""
|
||||||
判断是否应该使用轮询模式
|
判断是否应该使用轮询模式
|
||||||
@@ -369,7 +370,7 @@ class Monitor(metaclass=SingletonClass):
|
|||||||
return True, "用户配置为兼容模式"
|
return True, "用户配置为兼容模式"
|
||||||
|
|
||||||
# 检查网络文件系统
|
# 检查网络文件系统
|
||||||
if self.is_network_filesystem(directory):
|
if SystemUtils.is_network_filesystem(directory):
|
||||||
return True, "检测到网络文件系统,建议使用兼容模式"
|
return True, "检测到网络文件系统,建议使用兼容模式"
|
||||||
|
|
||||||
max_watches = limits.get('max_user_watches')
|
max_watches = limits.get('max_user_watches')
|
||||||
@@ -377,45 +378,6 @@ class Monitor(metaclass=SingletonClass):
|
|||||||
return True, f"目录文件数量({file_count})接近系统限制({max_watches})"
|
return True, f"目录文件数量({file_count})接近系统限制({max_watches})"
|
||||||
return False, "使用快速模式"
|
return False, "使用快速模式"
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def is_network_filesystem(directory: Path) -> bool:
|
|
||||||
"""
|
|
||||||
检测是否为网络文件系统
|
|
||||||
:param directory: 目录路径
|
|
||||||
:return: 是否为网络文件系统
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
system = platform.system()
|
|
||||||
if system == 'Linux':
|
|
||||||
# 检查挂载信息
|
|
||||||
result = subprocess.run(['df', '-T', str(directory)],
|
|
||||||
capture_output=True, text=True, timeout=5)
|
|
||||||
if result.returncode == 0:
|
|
||||||
output = result.stdout.lower()
|
|
||||||
# 以下本地文件系统含有fuse关键字
|
|
||||||
local_fs = [
|
|
||||||
"fuse.shfs", # Unraid
|
|
||||||
"zfuse.zfsv", # 极空间(zfuse.zfsv2、zfuse.zfsv3、...)
|
|
||||||
# TBD
|
|
||||||
]
|
|
||||||
if any(fs in output for fs in local_fs):
|
|
||||||
return False
|
|
||||||
network_fs = ['nfs', 'cifs', 'smbfs', 'fuse', 'sshfs', 'ftpfs']
|
|
||||||
return any(fs in output for fs in network_fs)
|
|
||||||
elif system == 'Darwin':
|
|
||||||
# macOS 检查
|
|
||||||
result = subprocess.run(['df', '-T', str(directory)],
|
|
||||||
capture_output=True, text=True, timeout=5)
|
|
||||||
if result.returncode == 0:
|
|
||||||
output = result.stdout.lower()
|
|
||||||
return 'nfs' in output or 'smbfs' in output
|
|
||||||
elif system == 'Windows':
|
|
||||||
# Windows 检查网络驱动器
|
|
||||||
return str(directory).startswith('\\\\')
|
|
||||||
except Exception as e:
|
|
||||||
logger.debug(f"检测网络文件系统时出错: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
"""
|
"""
|
||||||
启动监控
|
启动监控
|
||||||
|
|||||||
@@ -527,6 +527,45 @@ class SystemUtils:
|
|||||||
print(f"Error occurred: {e}")
|
print(f"Error occurred: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_network_filesystem(directory: Path) -> bool:
|
||||||
|
"""
|
||||||
|
检测是否为网络文件系统
|
||||||
|
:param directory: 目录路径
|
||||||
|
:return: 是否为网络文件系统
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
system = platform.system()
|
||||||
|
if system == 'Linux':
|
||||||
|
# 检查挂载信息
|
||||||
|
result = subprocess.run(['df', '-T', str(directory)],
|
||||||
|
capture_output=True, text=True, timeout=5)
|
||||||
|
if result.returncode == 0:
|
||||||
|
output = result.stdout.lower()
|
||||||
|
# 以下本地文件系统含有fuse关键字
|
||||||
|
local_fs = [
|
||||||
|
"fuse.shfs", # Unraid
|
||||||
|
"zfuse.zfsv", # 极空间(zfuse.zfsv2、zfuse.zfsv3、...)
|
||||||
|
# TBD
|
||||||
|
]
|
||||||
|
if any(fs in output for fs in local_fs):
|
||||||
|
return False
|
||||||
|
network_fs = ['nfs', 'cifs', 'smbfs', 'fuse', 'sshfs', 'ftpfs']
|
||||||
|
return any(fs in output for fs in network_fs)
|
||||||
|
elif system == 'Darwin':
|
||||||
|
# macOS 检查
|
||||||
|
result = subprocess.run(['df', '-T', str(directory)],
|
||||||
|
capture_output=True, text=True, timeout=5)
|
||||||
|
if result.returncode == 0:
|
||||||
|
output = result.stdout.lower()
|
||||||
|
return 'nfs' in output or 'smbfs' in output
|
||||||
|
elif system == 'Windows':
|
||||||
|
# Windows 检查网络驱动器
|
||||||
|
return str(directory).startswith('\\\\')
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error occurred: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_same_disk(src: Path, dest: Path) -> bool:
|
def is_same_disk(src: Path, dest: Path) -> bool:
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user