Merge pull request #201 from thsrite/main

This commit is contained in:
jxxghp 2023-08-21 07:51:24 +08:00 committed by GitHub
commit 5d9b45a2f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 193 additions and 94 deletions

View File

@ -319,7 +319,7 @@ class ChainBase(metaclass=ABCMeta):
def torrent_files(self, tid: str) -> Optional[Union[TorrentFilesList, List[File]]]:
"""
根据种子文件选择并添加下载任务
获取种子文件
:param tid: 种子Hash
:return: 种子文件
"""

View File

@ -72,12 +72,13 @@ class CookieCloudChain(ChainBase):
for domain, cookie in cookies.items():
# 获取站点信息
indexer = self.siteshelper.get_indexer(domain)
if self.siteoper.exists(domain):
site_info = self.siteoper.get_by_domain(domain)
if site_info:
# 检查站点连通性
status, msg = self.sitechain.test(domain)
# 更新站点Cookie
if status:
logger.info(f"站点【{indexer.get('name')}】连通性正常不同步CookieCloud数据")
logger.info(f"站点【{site_info.name}】连通性正常不同步CookieCloud数据")
continue
# 更新站点Cookie
self.siteoper.update_cookie(domain=domain, cookies=cookie)

View File

@ -1,5 +1,5 @@
from pathlib import Path
from typing import Any
from typing import Any, List
from app.db import DbOper
from app.db.models.downloadhistory import DownloadHistory
@ -44,7 +44,7 @@ class DownloadHistoryOper(DbOper):
DownloadHistory.truncate(self._db)
def get_last_by(self, mtype=None, title: str = None, year: str = None,
season: str = None, episode: str = None, tmdbid=None) -> DownloadHistory:
season: str = None, episode: str = None, tmdbid=None):
"""
按类型标题年份季集查询下载记录
"""

View File

@ -58,29 +58,29 @@ class DownloadHistory(Base):
"""
if tmdbid and not season and not episode:
return db.query(DownloadHistory).filter(DownloadHistory.tmdbid == tmdbid).order_by(
DownloadHistory.id.desc()).first()
DownloadHistory.id.desc()).all()
if tmdbid and season and not episode:
return db.query(DownloadHistory).filter(DownloadHistory.tmdbid == tmdbid,
DownloadHistory.seasons == season).order_by(
DownloadHistory.id.desc()).first()
DownloadHistory.id.desc()).all()
if tmdbid and season and episode:
return db.query(DownloadHistory).filter(DownloadHistory.tmdbid == tmdbid,
DownloadHistory.seasons == season,
DownloadHistory.episodes == episode).order_by(
DownloadHistory.id.desc()).first()
DownloadHistory.id.desc()).all()
# 电视剧所有季集|电影
if not season and not episode:
return db.query(DownloadHistory).filter(DownloadHistory.type == mtype,
DownloadHistory.title == title,
DownloadHistory.year == year).order_by(
DownloadHistory.id.desc()).first()
DownloadHistory.id.desc()).all()
# 电视剧某季
if season and not episode:
return db.query(DownloadHistory).filter(DownloadHistory.type == mtype,
DownloadHistory.title == title,
DownloadHistory.year == year,
DownloadHistory.seasons == season).order_by(
DownloadHistory.id.desc()).first()
DownloadHistory.id.desc()).all()
# 电视剧某季某集
if season and episode:
return db.query(DownloadHistory).filter(DownloadHistory.type == mtype,
@ -88,4 +88,4 @@ class DownloadHistory(Base):
DownloadHistory.year == year,
DownloadHistory.seasons == season,
DownloadHistory.episodes == episode).order_by(
DownloadHistory.id.desc()).first()
DownloadHistory.id.desc()).all()

View File

@ -85,7 +85,7 @@ class TransferHistory(Base):
return db.query(func.count(TransferHistory.id)).filter(TransferHistory.title.like(f'%{title}%')).first()[0]
@staticmethod
def list_by(db: Session, mtype: str = None, title: str = None, year: int = None, season: str = None,
def list_by(db: Session, title: str = None, year: int = None, season: str = None,
episode: str = None, tmdbid: str = None):
"""
据tmdbidseasonseason_episode查询转移记录
@ -101,19 +101,16 @@ class TransferHistory(Base):
TransferHistory.episodes == episode).all()
# 电视剧所有季集|电影
if not season and not episode:
return db.query(TransferHistory).filter(TransferHistory.type == mtype,
TransferHistory.title == title,
return db.query(TransferHistory).filter(TransferHistory.title == title,
TransferHistory.year == year).all()
# 电视剧某季
if season and not episode:
return db.query(TransferHistory).filter(TransferHistory.type == mtype,
TransferHistory.title == title,
return db.query(TransferHistory).filter(TransferHistory.title == title,
TransferHistory.year == year,
TransferHistory.seasons == season).all()
# 电视剧某季某集
if season and episode:
return db.query(TransferHistory).filter(TransferHistory.type == mtype,
TransferHistory.title == title,
return db.query(TransferHistory).filter(TransferHistory.title == title,
TransferHistory.year == year,
TransferHistory.seasons == season,
TransferHistory.episodes == episode).all()

View File

@ -50,13 +50,12 @@ class TransferHistoryOper(DbOper):
"""
return TransferHistory.statistic(self._db, days)
def get_by(self, mtype: str = None, title: str = None, year: str = None,
def get_by(self, title: str = None, year: str = None,
season: str = None, episode: str = None, tmdbid: str = None) -> Any:
"""
按类型标题年份季集查询转移记录
"""
return TransferHistory.list_by(db=self._db,
mtype=mtype,
title=title,
year=year,
season=season,
@ -79,4 +78,8 @@ class TransferHistoryOper(DbOper):
"""
新增转移历史
"""
if kwargs.get("src"):
transferhistory = TransferHistory.get_by_src(self._db, kwargs.get("src"))
if transferhistory:
transferhistory.delete(self._db, transferhistory.id)
return TransferHistory(**kwargs).create(self._db)

View File

@ -1,3 +1,4 @@
import os
import re
import threading
import time
@ -16,6 +17,8 @@ from app.core.metainfo import MetaInfo
from app.db.downloadhistory_oper import DownloadHistoryOper
from app.db.transferhistory_oper import TransferHistoryOper
from app.log import logger
from app.modules.qbittorrent import Qbittorrent
from app.modules.transmission import Transmission
from app.plugins import _PluginBase
from app.schemas import Notification, NotificationType, TransferInfo
from app.schemas.types import EventType
@ -82,6 +85,8 @@ class DirMonitor(_PluginBase):
_exclude_keywords = ""
# 存储源目录与目的目录关系
_dirconf: Dict[str, Path] = {}
qb = None
tr = None
def init_plugin(self, config: dict = None):
self.transferhis = TransferHistoryOper()
@ -104,6 +109,9 @@ class DirMonitor(_PluginBase):
self.stop_service()
if self._enabled:
self.qb = Qbittorrent()
self.tr = Transmission()
# 启动任务
monitor_dirs = self._monitor_dirs.split("\n")
if not monitor_dirs:
@ -255,12 +263,9 @@ class DirMonitor(_PluginBase):
return
# 获取downloadhash
downloadHis = self.downloadhis.get_last_by(mtype=mediainfo.type.value,
title=mediainfo.title,
year=mediainfo.year,
season=file_meta.season,
episode=file_meta.episode,
tmdbid=mediainfo.tmdb_id)
download_hash = self.get_download_hash(file_name=os.path.basename(event_path),
tmdb_id=mediainfo.tmdb_id,)
# 新增转移成功历史记录
self.transferhis.add_force(
src=event_path,
@ -277,7 +282,7 @@ class DirMonitor(_PluginBase):
seasons=file_meta.season,
episodes=file_meta.episode,
image=mediainfo.get_poster_image(),
download_hash=downloadHis.download_hash if downloadHis else None,
download_hash=download_hash,
status=1,
date=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
)
@ -300,6 +305,32 @@ class DirMonitor(_PluginBase):
except Exception as e:
logger.error("目录监控发生错误:%s - %s" % (str(e), traceback.format_exc()))
def get_download_hash(self, file_name, tmdb_id):
"""
获取download_hash
"""
downloadHis = self.downloadhis.get_last_by(tmdbid=tmdb_id)
if downloadHis:
for his in downloadHis:
# qb
if settings.DOWNLOADER == "qbittorrent":
files = self.qb.get_files(tid=his.download_hash)
if files:
for file in files:
torrent_file_name = file.get("name")
if str(file_name) == str(os.path.basename(torrent_file_name)):
return his.download_hash
# tr
if settings.DOWNLOADER == "transmission":
files = self.tr.get_files(tid=his.download_hash)
if files:
for file in files:
torrent_file_name = file.name
if str(file_name) == str(os.path.basename(torrent_file_name)):
return his.download_hash
return None
def get_state(self) -> bool:
return self._enabled

View File

@ -17,7 +17,9 @@ from app.db.transferhistory_oper import TransferHistoryOper
from app.log import logger
from app.modules.emby import Emby
from app.modules.jellyfin import Jellyfin
from app.modules.qbittorrent import Qbittorrent
from app.modules.themoviedb.tmdbv3api import Episode
from app.modules.transmission import Transmission
from app.plugins import _PluginBase
from app.schemas.types import NotificationType, EventType
from app.utils.path_utils import PathUtils
@ -55,10 +57,14 @@ class MediaSyncDel(_PluginBase):
_del_source = False
_exclude_path = None
_transferhis = None
qb = None
tr = None
def init_plugin(self, config: dict = None):
self._transferhis = TransferHistoryOper()
self.episode = Episode()
self.qb = Qbittorrent()
self.tr = Transmission()
# 停止现有任务
self.stop_service()
@ -487,14 +493,17 @@ class MediaSyncDel(_PluginBase):
logger.error(f"{media_name} 季同步删除失败,未获取到具体季")
return
msg = f'剧集 {media_name} S{season_num} {tmdb_id}'
transfer_history: List[TransferHistory] = self._transferhis.get_by(tmdbid=tmdb_id)
transfer_history: List[TransferHistory] = self._transferhis.get_by(tmdbid=tmdb_id,
season=f'S{season_num}')
# 删除剧集S02E02
elif media_type == "Episode":
if not season_num or not str(season_num).isdigit() or not episode_num or not str(episode_num).isdigit():
logger.error(f"{media_name} 集同步删除失败,未获取到具体集")
return
msg = f'剧集 {media_name} S{season_num}E{episode_num} {tmdb_id}'
transfer_history: List[TransferHistory] = self._transferhis.get_by(tmdbid=tmdb_id)
transfer_history: List[TransferHistory] = self._transferhis.get_by(tmdbid=tmdb_id,
season=f'S{season_num}',
episode=f'E{episode_num}')
else:
return
@ -507,11 +516,15 @@ class MediaSyncDel(_PluginBase):
# 开始删除
image = 'https://emby.media/notificationicon.png'
year = None
del_cnt = 0
stop_cnt = 0
for transferhis in transfer_history:
image = transferhis.image
year = transferhis.year
# 删除种子任务
if self._del_source:
# 0、删除转移记录
self._transferhis.delete(transferhis.id)
# 1、直接删除源文件
if transferhis.src and Path(transferhis.src).suffix in settings.RMT_MEDIAEXT:
source_name = os.path.basename(transferhis.src)
@ -521,9 +534,12 @@ class MediaSyncDel(_PluginBase):
if transferhis.download_hash:
try:
# 2、判断种子是否被删除完
self.handle_torrent(history_id=transferhis.id,
src=transferhis.src,
delete_flag, stop_flag = self.handle_torrent(src=source_path,
torrent_hash=transferhis.download_hash)
if delete_flag:
del_cnt += 1
if stop_flag:
stop_cnt += 1
except Exception as e:
logger.error("删除种子失败,尝试删除源文件:%s" % str(e))
@ -544,6 +560,7 @@ class MediaSyncDel(_PluginBase):
title="媒体库同步删除任务完成",
image=image,
text=f"{msg}\n"
f"数量 删除{del_cnt}个 暂停{stop_cnt}\n"
f"时间 {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))}"
)
@ -613,30 +630,29 @@ class MediaSyncDel(_PluginBase):
if media_type == "Movie":
msg = f'电影 {media_name}'
transfer_history: List[TransferHistory] = self._transferhis.get_by(
mtype="电影",
title=media_name,
year=media_year)
# 删除电视剧
elif media_type == "Series":
msg = f'剧集 {media_name}'
transfer_history: List[TransferHistory] = self._transferhis.get_by(
mtype="电视剧",
title=media_name,
year=media_year)
# 删除季 S02
elif media_type == "Season":
msg = f'剧集 {media_name} {media_season}'
transfer_history: List[TransferHistory] = self._transferhis.get_by(
mtype="电视剧",
title=media_name,
year=media_year)
year=media_year,
season=media_season)
# 删除剧集S02E02
elif media_type == "Episode":
msg = f'剧集 {media_name} {media_season}{media_episode}'
transfer_history: List[TransferHistory] = self._transferhis.get_by(
mtype="电视剧",
title=media_name,
year=media_year)
year=media_year,
season=media_season,
episode=media_episode)
else:
continue
@ -650,11 +666,15 @@ class MediaSyncDel(_PluginBase):
# 开始删除
image = 'https://emby.media/notificationicon.png'
del_cnt = 0
stop_cnt = 0
for transferhis in transfer_history:
image = transferhis.image
self._transferhis.delete(transferhis.id)
# 删除种子任务
if self._del_source:
# 0、删除转移记录
self._transferhis.delete(transferhis.id)
# 1、直接删除源文件
if transferhis.src and Path(transferhis.src).suffix in settings.RMT_MEDIAEXT:
source_name = os.path.basename(transferhis.src)
@ -664,9 +684,12 @@ class MediaSyncDel(_PluginBase):
if transferhis.download_hash:
try:
# 2、判断种子是否被删除完
self.handle_torrent(history_id=transferhis.id,
src=transferhis.src,
delete_flag, stop_flag = self.handle_torrent(src=source_path,
torrent_hash=transferhis.download_hash)
if delete_flag:
del_cnt += 1
if stop_flag:
stop_cnt += 1
except Exception as e:
logger.error("删除种子失败,尝试删除源文件:%s" % str(e))
@ -678,7 +701,7 @@ class MediaSyncDel(_PluginBase):
mtype=NotificationType.MediaServer,
title="媒体库同步删除任务完成",
text=f"{msg}\n"
f"数量 {len(transfer_history)}\n"
f"数量 删除{del_cnt}个 暂停{stop_cnt}\n"
f"时间 {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))}",
image=image)
@ -698,7 +721,7 @@ class MediaSyncDel(_PluginBase):
self.save_data("last_time", datetime.datetime.now())
def handle_torrent(self, history_id: int, src: str, torrent_hash: str):
def handle_torrent(self, src: str, torrent_hash: str):
"""
判断种子是否局部删除
局部删除则暂停种子
@ -716,9 +739,8 @@ class MediaSyncDel(_PluginBase):
del_history = False
# 删除种子标志
delete_flag = True
# 是否需要暂停源下载器种子
stop_from = False
stop_flag = False
# 如果有转种记录,则删除转种后的下载任务
if transfer_history and isinstance(transfer_history, dict):
@ -742,7 +764,7 @@ class MediaSyncDel(_PluginBase):
if Path(torrent_file).exists():
logger.warn(f"种子有文件被删除,种子文件{torrent_file}暂未删除,暂停种子")
delete_flag = False
stop_from = True
stop_flag = True
break
if delete_flag:
logger.info(f"删除下载任务:{settings.DOWNLOADER} - {torrent_hash}")
@ -753,25 +775,53 @@ class MediaSyncDel(_PluginBase):
# 如果是False则说明种子文件没有完全被删除暂停种子暂不处理
if delete_flag:
try:
dl_files = self.chain.torrent_files(tid=download_id)
# 转种download
if download == "transmission":
dl_files = self.tr.get_files(tid=download_id)
if not dl_files:
logger.info(f"未获取到 {download} - {download_id} 种子文件,种子已被删除")
else:
for dl_file in dl_files:
dl_file_name = dl_file.name
if not transfer_history or not stop_flag:
torrent_file = os.path.join(src, os.path.basename(dl_file_name))
if Path(torrent_file).exists():
logger.info(f"种子有文件被删除,种子文件{torrent_file}暂未删除,暂停种子")
delete_flag = False
stop_flag = True
break
if delete_flag:
# 删除源下载任务或转种后下载任务
logger.info(f"删除下载任务:{download} - {download_id}")
self.tr.delete_torrents(delete_file=True,
ids=download_id)
# 删除转种记录
if del_history:
self.del_data(key=history_key, plugin_id=plugin_id)
# 处理辅种
self.__del_seed(download=download, download_id=download_id, action_flag="del")
else:
dl_files = self.qb.get_files(tid=download_id)
if not dl_files:
logger.info(f"未获取到 {download} - {download_id} 种子文件,种子已被删除")
else:
for dl_file in dl_files:
dl_file_name = dl_file.get("name")
if not stop_from:
if not transfer_history or not stop_flag:
torrent_file = os.path.join(src, os.path.basename(dl_file_name))
if Path(torrent_file).exists():
logger.info(f"种子有文件被删除,种子文件{torrent_file}暂未删除,暂停种子")
delete_flag = False
stop_flag = True
break
if delete_flag:
# 删除源下载任务或转种后下载任务
logger.info(f"删除下载任务:{download} - {download_id}")
self.chain.remove_torrents(download_id)
# 删除转移记录
self._transferhis.delete(history_id)
self.qb.delete_torrents(delete_file=True,
ids=download_id)
# 删除转种记录
if del_history:
@ -786,18 +836,24 @@ class MediaSyncDel(_PluginBase):
if not delete_flag:
logger.error("开始暂停种子")
# 暂停种子
if stop_from:
if stop_flag:
# 暂停源种
self.chain.stop_torrents(torrent_hash)
logger.info(f"种子:{settings.DOWNLOADER} - {torrent_hash} 暂停")
# 转种
self.chain.stop_torrents(download_id)
# 暂停转种
if del_history:
if download == "qbittorrent":
self.qb.stop_torrents(download_id)
logger.info(f"转种:{download} - {download_id} 暂停")
# 辅种
else:
self.tr.stop_torrents(download_id)
logger.info(f"转种:{download} - {download_id} 暂停")
# 暂停辅种
self.__del_seed(download=download, download_id=download_id, action_flag="stop")
return delete_flag, stop_flag
def __del_seed(self, download, download_id, action_flag):
"""
删除辅种
@ -822,15 +878,26 @@ class MediaSyncDel(_PluginBase):
# 删除辅种历史中与本下载器相同的辅种记录
if int(downloader) == download:
for torrent in torrents:
if download == "qbittorrent":
# 删除辅种
if action_flag == "del":
logger.info(f"删除辅种:{downloader} - {torrent}")
self.chain.remove_torrents(torrent)
self.qb.delete_torrents(delete_file=True,
ids=torrent)
# 暂停辅种
if action_flag == "stop":
self.chain.stop_torrents(torrent)
self.qb.stop_torrents(torrent)
logger.info(f"辅种:{downloader} - {torrent} 暂停")
else:
# 删除辅种
if action_flag == "del":
logger.info(f"删除辅种:{downloader} - {torrent}")
self.tr.delete_torrents(delete_file=True,
ids=torrent)
# 暂停辅种
if action_flag == "stop":
self.tr.stop_torrents(torrent)
logger.info(f"辅种:{downloader} - {torrent} 暂停")
# 删除本下载器辅种历史
if action_flag == "del":
del history