mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 15:38:19 +08:00
support path_mapping for downloader
This commit is contained in:
@@ -707,19 +707,17 @@ class ChainBase(metaclass=ABCMeta):
|
|||||||
cookie=cookie, episodes=episodes, category=category, label=label,
|
cookie=cookie, episodes=episodes, category=category, label=label,
|
||||||
downloader=downloader)
|
downloader=downloader)
|
||||||
|
|
||||||
def download_added(self, context: Context, download_dir: Path, storage: str, torrent_content: Union[str, bytes] = None) -> None:
|
def download_added(self, context: Context, download_dir: Path, torrent_content: Union[str, bytes] = None) -> None:
|
||||||
"""
|
"""
|
||||||
添加下载任务成功后,从站点下载字幕,保存到下载目录
|
添加下载任务成功后,从站点下载字幕,保存到下载目录
|
||||||
:param context: 上下文,包括识别信息、媒体信息、种子信息
|
:param context: 上下文,包括识别信息、媒体信息、种子信息
|
||||||
:param download_dir: 下载目录
|
:param download_dir: 下载目录
|
||||||
:param storage: 存储类型
|
|
||||||
:param torrent_content: 种子内容,如果有则直接使用该内容,否则从context中获取种子文件路径
|
:param torrent_content: 种子内容,如果有则直接使用该内容,否则从context中获取种子文件路径
|
||||||
:return: None,该方法可被多个模块同时处理
|
:return: None,该方法可被多个模块同时处理
|
||||||
"""
|
"""
|
||||||
return self.run_module("download_added", context=context,
|
return self.run_module("download_added", context=context,
|
||||||
torrent_content=torrent_content,
|
torrent_content=torrent_content,
|
||||||
download_dir=download_dir,
|
download_dir=download_dir)
|
||||||
storage=storage)
|
|
||||||
|
|
||||||
def list_torrents(self, status: TorrentStatus = None,
|
def list_torrents(self, status: TorrentStatus = None,
|
||||||
hashs: Union[list, str] = None,
|
hashs: Union[list, str] = None,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from app.db.mediaserver_oper import MediaServerOper
|
|||||||
from app.helper.directory import DirectoryHelper
|
from app.helper.directory import DirectoryHelper
|
||||||
from app.helper.torrent import TorrentHelper
|
from app.helper.torrent import TorrentHelper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.schemas import ExistMediaInfo, NotExistMediaInfo, DownloadingTorrent, Notification, ResourceSelectionEventData, \
|
from app.schemas import ExistMediaInfo, FileURI, NotExistMediaInfo, DownloadingTorrent, Notification, ResourceSelectionEventData, \
|
||||||
ResourceDownloadEventData
|
ResourceDownloadEventData
|
||||||
from app.schemas.types import MediaType, TorrentStatus, EventType, MessageChannel, NotificationType, ContentType, \
|
from app.schemas.types import MediaType, TorrentStatus, EventType, MessageChannel, NotificationType, ContentType, \
|
||||||
ChainEventType
|
ChainEventType
|
||||||
@@ -235,10 +235,7 @@ class DownloadChain(ChainBase):
|
|||||||
storage = 'local'
|
storage = 'local'
|
||||||
# 下载目录
|
# 下载目录
|
||||||
if save_path:
|
if save_path:
|
||||||
uri = schemas.FileURI.from_uri(save_path)
|
download_dir = Path(save_path)
|
||||||
# 下载目录使用自定义的
|
|
||||||
download_dir = Path(uri.path)
|
|
||||||
storage = uri.storage
|
|
||||||
else:
|
else:
|
||||||
# 根据媒体信息查询下载目录配置
|
# 根据媒体信息查询下载目录配置
|
||||||
dir_info = DirectoryHelper().get_dir(_media, include_unsorted=True)
|
dir_info = DirectoryHelper().get_dir(_media, include_unsorted=True)
|
||||||
@@ -263,6 +260,8 @@ class DownloadChain(ChainBase):
|
|||||||
self.messagehelper.put(f"{_media.type.value} {_media.title_year} 未找到下载目录!",
|
self.messagehelper.put(f"{_media.type.value} {_media.title_year} 未找到下载目录!",
|
||||||
title="下载失败", role="system")
|
title="下载失败", role="system")
|
||||||
return None
|
return None
|
||||||
|
fileURI = FileURI(storage=storage, path=download_dir.as_posix())
|
||||||
|
download_dir = Path(fileURI.uri)
|
||||||
|
|
||||||
# 添加下载
|
# 添加下载
|
||||||
result: Optional[tuple] = self.download(content=torrent_content,
|
result: Optional[tuple] = self.download(content=torrent_content,
|
||||||
@@ -362,7 +361,7 @@ class DownloadChain(ChainBase):
|
|||||||
username=username,
|
username=username,
|
||||||
)
|
)
|
||||||
# 下载成功后处理
|
# 下载成功后处理
|
||||||
self.download_added(context=context, download_dir=download_dir, storage=storage, torrent_content=torrent_content)
|
self.download_added(context=context, download_dir=download_dir, torrent_content=torrent_content)
|
||||||
# 广播事件
|
# 广播事件
|
||||||
self.eventmanager.send_event(EventType.DownloadAdded, {
|
self.eventmanager.send_event(EventType.DownloadAdded, {
|
||||||
"hash": _hash,
|
"hash": _hash,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from abc import abstractmethod, ABCMeta
|
from abc import abstractmethod, ABCMeta
|
||||||
from typing import Generic, Tuple, Union, TypeVar, Type, Dict, Optional, Callable
|
from typing import Generic, Tuple, Union, TypeVar, Type, Dict, Optional, Callable
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from app.helper.service import ServiceConfigHelper
|
from app.helper.service import ServiceConfigHelper
|
||||||
from app.schemas import Notification, NotificationConf, MediaServerConf, DownloaderConf
|
from app.schemas import Notification, NotificationConf, MediaServerConf, DownloaderConf
|
||||||
@@ -291,6 +292,30 @@ class _DownloaderBase(ServiceBase[TService, DownloaderConf]):
|
|||||||
"""
|
"""
|
||||||
self._default_config_name = None
|
self._default_config_name = None
|
||||||
|
|
||||||
|
def normalize_path(self, path: Path, downloader: Optional[str]) -> str:
|
||||||
|
"""
|
||||||
|
根据下载器配置和路径映射,规范化下载路径
|
||||||
|
|
||||||
|
:param path: 原始路径
|
||||||
|
:param conf: 下载器配置
|
||||||
|
:return: 规范化后的路径
|
||||||
|
"""
|
||||||
|
dir = path.as_posix()
|
||||||
|
conf = self.get_config(downloader)
|
||||||
|
if conf and conf.path_mapping:
|
||||||
|
for (src, dst) in conf.path_mapping:
|
||||||
|
src = Path(src.strip()).as_posix()
|
||||||
|
dst = Path(dst.strip()).as_posix()
|
||||||
|
if dir.startswith(src):
|
||||||
|
dir = dir.replace(src, dst, 1)
|
||||||
|
break
|
||||||
|
# 处理存储协议前缀
|
||||||
|
for s in StorageSchema:
|
||||||
|
prefix = f"{s.value}:"
|
||||||
|
if dir.startswith(prefix):
|
||||||
|
return dir[len(prefix):]
|
||||||
|
return dir
|
||||||
|
|
||||||
|
|
||||||
class _MediaServerBase(ServiceBase[TService, MediaServerConf]):
|
class _MediaServerBase(ServiceBase[TService, MediaServerConf]):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ class QbittorrentModule(_ModuleBase, _DownloaderBase[Qbittorrent]):
|
|||||||
# 添加任务
|
# 添加任务
|
||||||
state = server.add_torrent(
|
state = server.add_torrent(
|
||||||
content=content,
|
content=content,
|
||||||
download_dir=download_dir.as_posix(),
|
download_dir=self.normalize_path(download_dir, downloader),
|
||||||
is_paused=is_paused,
|
is_paused=is_paused,
|
||||||
tag=tags,
|
tag=tags,
|
||||||
cookie=cookie,
|
cookie=cookie,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from app.core.context import Context
|
|||||||
from app.helper.torrent import TorrentHelper
|
from app.helper.torrent import TorrentHelper
|
||||||
from app.log import logger
|
from app.log import logger
|
||||||
from app.modules import _ModuleBase
|
from app.modules import _ModuleBase
|
||||||
from app.schemas.file import FileItem
|
from app.schemas.file import FileURI
|
||||||
from app.schemas.types import ModuleType, OtherModulesType
|
from app.schemas.types import ModuleType, OtherModulesType
|
||||||
from app.utils.http import RequestUtils
|
from app.utils.http import RequestUtils
|
||||||
from app.utils.string import StringUtils
|
from app.utils.string import StringUtils
|
||||||
@@ -65,12 +65,11 @@ class SubtitleModule(_ModuleBase):
|
|||||||
def test(self):
|
def test(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def download_added(self, context: Context, download_dir: Path, storage: str, torrent_content: Union[str, bytes] = None):
|
def download_added(self, context: Context, download_dir: Path, torrent_content: Union[str, bytes] = None):
|
||||||
"""
|
"""
|
||||||
添加下载任务成功后,从站点下载字幕,保存到下载目录
|
添加下载任务成功后,从站点下载字幕,保存到下载目录
|
||||||
:param context: 上下文,包括识别信息、媒体信息、种子信息
|
:param context: 上下文,包括识别信息、媒体信息、种子信息
|
||||||
:param download_dir: 下载目录
|
:param download_dir: 下载目录
|
||||||
:param storage: 存储类型
|
|
||||||
:param torrent_content: 种子内容,如果是种子文件,则为文件内容,否则为种子字符串
|
:param torrent_content: 种子内容,如果是种子文件,则为文件内容,否则为种子字符串
|
||||||
:return: None,该方法可被多个模块同时处理
|
:return: None,该方法可被多个模块同时处理
|
||||||
"""
|
"""
|
||||||
@@ -93,6 +92,10 @@ class SubtitleModule(_ModuleBase):
|
|||||||
storageChain = StorageChain()
|
storageChain = StorageChain()
|
||||||
# 等待目录存在
|
# 等待目录存在
|
||||||
working_dir_item = None
|
working_dir_item = None
|
||||||
|
# split download_dir into storage and path
|
||||||
|
fileURI = FileURI.from_uri(download_dir.as_posix())
|
||||||
|
storage = fileURI.storage
|
||||||
|
download_dir = Path(fileURI.path)
|
||||||
for _ in range(30):
|
for _ in range(30):
|
||||||
found = storageChain.get_file_item(storage, download_dir / folder_name)
|
found = storageChain.get_file_item(storage, download_dir / folder_name)
|
||||||
if found:
|
if found:
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ class TransmissionModule(_ModuleBase, _DownloaderBase[Transmission]):
|
|||||||
# 添加任务
|
# 添加任务
|
||||||
torrent = server.add_torrent(
|
torrent = server.add_torrent(
|
||||||
content=content,
|
content=content,
|
||||||
download_dir=download_dir.as_posix(),
|
download_dir=self.normalize_path(download_dir, downloader),
|
||||||
is_paused=is_paused,
|
is_paused=is_paused,
|
||||||
labels=labels,
|
labels=labels,
|
||||||
cookie=cookie
|
cookie=cookie
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ class DownloaderConf(BaseModel):
|
|||||||
config: Optional[dict] = Field(default_factory=dict)
|
config: Optional[dict] = Field(default_factory=dict)
|
||||||
# 是否启用
|
# 是否启用
|
||||||
enabled: Optional[bool] = False
|
enabled: Optional[bool] = False
|
||||||
|
# 路径映射
|
||||||
|
path_mapping: Optional[list[tuple[str, str]]] = Field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
class NotificationConf(BaseModel):
|
class NotificationConf(BaseModel):
|
||||||
|
|||||||
Reference in New Issue
Block a user