Merge pull request #489 from thsrite/main

fix 目录监控已处理逻辑 && feat 新增已入库媒体是否跟随TMDB信息变化开关,关闭则延用媒体库名称
This commit is contained in:
jxxghp
2023-09-07 14:29:08 +08:00
committed by GitHub
8 changed files with 186 additions and 156 deletions

View File

@ -65,6 +65,7 @@ docker pull jxxghp/moviepilot:latest
- **DOWNLOAD_SUBTITLE** 下载站点字幕,`true`/`false`,默认`true` - **DOWNLOAD_SUBTITLE** 下载站点字幕,`true`/`false`,默认`true`
- **REFRESH_MEDIASERVER** 入库刷新媒体库,`true`/`false`,默认`true` - **REFRESH_MEDIASERVER** 入库刷新媒体库,`true`/`false`,默认`true`
- **SCRAP_METADATA** 刮削入库的媒体文件,`true`/`false`,默认`true` - **SCRAP_METADATA** 刮削入库的媒体文件,`true`/`false`,默认`true`
- **SCRAP_FOLLOW_TMDB** 新增已入库媒体是否跟随TMDB信息变化`true`/`false`,默认`true`
- **TORRENT_TAG** 种子标签,默认为`MOVIEPILOT`设置后只有MoviePilot添加的下载才会处理留空所有下载器中的任务均会处理 - **TORRENT_TAG** 种子标签,默认为`MOVIEPILOT`设置后只有MoviePilot添加的下载才会处理留空所有下载器中的任务均会处理
- **LIBRARY_PATH** 媒体库目录,多个目录使用`,`分隔 - **LIBRARY_PATH** 媒体库目录,多个目录使用`,`分隔
- **LIBRARY_MOVIE_NAME** 电影媒体库目录名,默认`电影` - **LIBRARY_MOVIE_NAME** 电影媒体库目录名,默认`电影`

View File

@ -242,7 +242,12 @@ class TransferChain(ChainBase):
f"回复:```\n/redo {his.id} [tmdbid]|[类型]\n``` 手动识别转移。" f"回复:```\n/redo {his.id} [tmdbid]|[类型]\n``` 手动识别转移。"
)) ))
continue continue
# 如果未开启新增已入库媒体是否跟随TMDB信息变化则根据tmdbid查询之前的title
if not settings.SCRAP_FOLLOW_TMDB:
transfer_historys = self.transferhis.get_by(tmdbid=file_mediainfo.tmdb_id,
type=file_mediainfo.type.value)
if transfer_historys:
file_mediainfo.title = transfer_historys[0].title
logger.info(f"{file_path.name} 识别为:{file_mediainfo.type.value} {file_mediainfo.title_year}") logger.info(f"{file_path.name} 识别为:{file_mediainfo.type.value} {file_mediainfo.title_year}")
# 电视剧没有集无法转移 # 电视剧没有集无法转移

View File

@ -39,6 +39,8 @@ class Settings(BaseSettings):
SEARCH_SOURCE: str = "themoviedb" SEARCH_SOURCE: str = "themoviedb"
# 刮削入库的媒体文件 # 刮削入库的媒体文件
SCRAP_METADATA: bool = True SCRAP_METADATA: bool = True
# 新增已入库媒体是否跟随TMDB信息变化
SCRAP_FOLLOW_TMDB: bool = True
# 刮削来源 # 刮削来源
SCRAP_SOURCE: str = "themoviedb" SCRAP_SOURCE: str = "themoviedb"
# TMDB图片地址 # TMDB图片地址

View File

@ -85,11 +85,14 @@ class TransferHistory(Base):
return db.query(func.count(TransferHistory.id)).filter(TransferHistory.title.like(f'%{title}%')).first()[0] return db.query(func.count(TransferHistory.id)).filter(TransferHistory.title.like(f'%{title}%')).first()[0]
@staticmethod @staticmethod
def list_by(db: Session, title: str = None, year: int = None, season: str = None, def list_by(db: Session, type: str = None, title: str = None, year: int = None, season: str = None,
episode: str = None, tmdbid: int = None): episode: str = None, tmdbid: int = None):
""" """
据tmdbid、season、season_episode查询转移记录 据tmdbid、season、season_episode查询转移记录
""" """
if tmdbid and type:
return db.query(TransferHistory).filter(TransferHistory.tmdbid == tmdbid,
TransferHistory.type == type).all()
if tmdbid and not season and not episode: if tmdbid and not season and not episode:
return db.query(TransferHistory).filter(TransferHistory.tmdbid == tmdbid).all() return db.query(TransferHistory).filter(TransferHistory.tmdbid == tmdbid).all()
if tmdbid and season and not episode: if tmdbid and season and not episode:

View File

@ -51,12 +51,13 @@ class TransferHistoryOper(DbOper):
""" """
return TransferHistory.statistic(self._db, days) return TransferHistory.statistic(self._db, days)
def get_by(self, title: str = None, year: str = None, def get_by(self, title: str = None, year: str = None, type: str = None,
season: str = None, episode: str = None, tmdbid: int = None) -> List[TransferHistory]: season: str = None, episode: str = None, tmdbid: int = None) -> List[TransferHistory]:
""" """
按类型、标题、年份、季集查询转移记录 按类型、标题、年份、季集查询转移记录
""" """
return TransferHistory.list_by(db=self._db, return TransferHistory.list_by(db=self._db,
type=type,
title=title, title=title,
year=year, year=year,
season=season, season=season,

View File

@ -69,9 +69,6 @@ class DirMonitor(_PluginBase):
# 可使用的用户级别 # 可使用的用户级别
auth_level = 1 auth_level = 1
# 已处理的文件清单
_synced_files = []
# 私有属性 # 私有属性
_scheduler = None _scheduler = None
transferhis = None transferhis = None
@ -193,9 +190,8 @@ class DirMonitor(_PluginBase):
# 全程加锁 # 全程加锁
with lock: with lock:
if event_path not in self._synced_files: transfer_history = self.transferhis.get_by_src(event_path)
self._synced_files.append(event_path) if transfer_history:
else:
logger.debug("文件已处理过:%s" % event_path) logger.debug("文件已处理过:%s" % event_path)
return return
@ -264,6 +260,13 @@ class DirMonitor(_PluginBase):
meta=file_meta meta=file_meta
) )
return return
# 如果未开启新增已入库媒体是否跟随TMDB信息变化则根据tmdbid查询之前的title
if not settings.SCRAP_FOLLOW_TMDB:
transfer_historys = self.transferhis.get_by(tmdbid=mediainfo.tmdb_id,
type=mediainfo.type.value)
if transfer_historys:
mediainfo.title = transfer_historys[0].title
logger.info(f"{file_path.name} 识别为:{mediainfo.type.value} {mediainfo.title_year}") logger.info(f"{file_path.name} 识别为:{mediainfo.type.value} {mediainfo.title_year}")
# 更新媒体图片 # 更新媒体图片
@ -482,149 +485,149 @@ class DirMonitor(_PluginBase):
def get_form(self) -> Tuple[List[dict], Dict[str, Any]]: def get_form(self) -> Tuple[List[dict], Dict[str, Any]]:
return [ return [
{ {
'component': 'VForm', 'component': 'VForm',
'content': [ 'content': [
{ {
'component': 'VRow', 'component': 'VRow',
'content': [ 'content': [
{ {
'component': 'VCol', 'component': 'VCol',
'props': { 'props': {
'cols': 12, 'cols': 12,
'md': 6 'md': 6
}, },
'content': [ 'content': [
{ {
'component': 'VSwitch', 'component': 'VSwitch',
'props': { 'props': {
'model': 'enabled', 'model': 'enabled',
'label': '启用插件', 'label': '启用插件',
} }
} }
] ]
}, },
{ {
'component': 'VCol', 'component': 'VCol',
'props': { 'props': {
'cols': 12, 'cols': 12,
'md': 6 'md': 6
}, },
'content': [ 'content': [
{ {
'component': 'VSwitch', 'component': 'VSwitch',
'props': { 'props': {
'model': 'notify', 'model': 'notify',
'label': '发送通知', 'label': '发送通知',
} }
} }
] ]
} }
] ]
}, },
{ {
'component': 'VRow', 'component': 'VRow',
'content': [ 'content': [
{ {
'component': 'VCol', 'component': 'VCol',
'props': { 'props': {
'cols': 12, 'cols': 12,
'md': 6 'md': 6
}, },
'content': [ 'content': [
{ {
'component': 'VSelect', 'component': 'VSelect',
'props': { 'props': {
'model': 'mode', 'model': 'mode',
'label': '监控模式', 'label': '监控模式',
'items': [ 'items': [
{'title': '兼容模式', 'value': 'compatibility'}, {'title': '兼容模式', 'value': 'compatibility'},
{'title': '性能模式', 'value': 'fast'} {'title': '性能模式', 'value': 'fast'}
] ]
} }
} }
] ]
}, },
{ {
'component': 'VCol', 'component': 'VCol',
'props': { 'props': {
'cols': 12, 'cols': 12,
'md': 6 'md': 6
}, },
'content': [ 'content': [
{ {
'component': 'VSelect', 'component': 'VSelect',
'props': { 'props': {
'model': 'transfer_type', 'model': 'transfer_type',
'label': '转移方式', 'label': '转移方式',
'items': [ 'items': [
{'title': '移动', 'value': 'move'}, {'title': '移动', 'value': 'move'},
{'title': '复制', 'value': 'copy'}, {'title': '复制', 'value': 'copy'},
{'title': '硬链接', 'value': 'link'}, {'title': '硬链接', 'value': 'link'},
{'title': '软链接', 'value': 'softlink'} {'title': '软链接', 'value': 'softlink'}
] ]
} }
} }
] ]
} }
] ]
}, },
{ {
'component': 'VRow', 'component': 'VRow',
'content': [ 'content': [
{ {
'component': 'VCol', 'component': 'VCol',
'props': { 'props': {
'cols': 12 'cols': 12
}, },
'content': [ 'content': [
{ {
'component': 'VTextarea', 'component': 'VTextarea',
'props': { 'props': {
'model': 'monitor_dirs', 'model': 'monitor_dirs',
'label': '监控目录', 'label': '监控目录',
'rows': 5, 'rows': 5,
'placeholder': '每一行一个目录,支持两种配置方式:\n' 'placeholder': '每一行一个目录,支持两种配置方式:\n'
'监控目录\n' '监控目录\n'
'监控目录:转移目的目录' '监控目录:转移目的目录'
} }
} }
] ]
} }
] ]
}, },
{ {
'component': 'VRow', 'component': 'VRow',
'content': [ 'content': [
{ {
'component': 'VCol', 'component': 'VCol',
'props': { 'props': {
'cols': 12 'cols': 12
}, },
'content': [ 'content': [
{ {
'component': 'VTextarea', 'component': 'VTextarea',
'props': { 'props': {
'model': 'exclude_keywords', 'model': 'exclude_keywords',
'label': '排除关键词', 'label': '排除关键词',
'rows': 2, 'rows': 2,
'placeholder': '每一行一个关键词' 'placeholder': '每一行一个关键词'
} }
} }
] ]
} }
] ]
} }
] ]
} }
], { ], {
"enabled": False, "enabled": False,
"notify": False, "notify": False,
"mode": "fast", "mode": "fast",
"transfer_type": settings.TRANSFER_TYPE, "transfer_type": settings.TRANSFER_TYPE,
"monitor_dirs": "", "monitor_dirs": "",
"exclude_keywords": "" "exclude_keywords": ""
} }
def get_page(self) -> List[dict]: def get_page(self) -> List[dict]:
pass pass

View File

@ -9,6 +9,7 @@ from apscheduler.triggers.cron import CronTrigger
from app.core.config import settings from app.core.config import settings
from app.core.metainfo import MetaInfo from app.core.metainfo import MetaInfo
from app.db.transferhistory_oper import TransferHistoryOper
from app.helper.nfo import NfoReader from app.helper.nfo import NfoReader
from app.log import logger from app.log import logger
from app.plugins import _PluginBase from app.plugins import _PluginBase
@ -40,6 +41,7 @@ class LibraryScraper(_PluginBase):
user_level = 1 user_level = 1
# 私有属性 # 私有属性
transferhis = None
_scheduler = None _scheduler = None
_scraper = None _scraper = None
# 限速开关 # 限速开关
@ -67,6 +69,7 @@ class LibraryScraper(_PluginBase):
# 启动定时任务 & 立即运行一次 # 启动定时任务 & 立即运行一次
if self._enabled or self._onlyonce: if self._enabled or self._onlyonce:
self.transferhis = TransferHistoryOper(self.db)
self._scheduler = BackgroundScheduler(timezone=settings.TZ) self._scheduler = BackgroundScheduler(timezone=settings.TZ)
if self._cron: if self._cron:
logger.info(f"媒体库刮削服务启动,周期:{self._cron}") logger.info(f"媒体库刮削服务启动,周期:{self._cron}")
@ -346,6 +349,13 @@ class LibraryScraper(_PluginBase):
if not mediainfo: if not mediainfo:
logger.warn(f"未识别到媒体信息:{file}") logger.warn(f"未识别到媒体信息:{file}")
continue continue
# 如果未开启新增已入库媒体是否跟随TMDB信息变化则根据tmdbid查询之前的title
if not settings.SCRAP_FOLLOW_TMDB:
transfer_historys = self.transferhis.get_by(tmdbid=mediainfo.tmdb_id,
type=mediainfo.type.value)
if transfer_historys:
mediainfo.title = transfer_historys[0].title
# 覆盖模式时提前删除nfo # 覆盖模式时提前删除nfo
if self._mode in ["force_all", "force_nfo"]: if self._mode in ["force_all", "force_nfo"]:

View File

@ -303,7 +303,7 @@ class MessageForward(_PluginBase):
"enable_id_trans": 0, "enable_id_trans": 0,
"enable_duplicate_check": 0 "enable_duplicate_check": 0
} }
return self.__post_request(message_url, req_json, i, title) return self.__post_request(message_url=message_url, req_json=req_json, i=i, title=title)
def __send_image_message(self, title: str, text: str, image_url: str, userid: str = None, access_token: str = None, def __send_image_message(self, title: str, text: str, image_url: str, userid: str = None, access_token: str = None,
appid: str = None, i: int = None) -> Optional[bool]: appid: str = None, i: int = None) -> Optional[bool]:
@ -335,9 +335,9 @@ class MessageForward(_PluginBase):
] ]
} }
} }
return self.__post_request(message_url, req_json, i, title) return self.__post_request(message_url=message_url, req_json=req_json, i=i, title=title)
def __post_request(self, message_url: str, req_json: dict, i: int, title: str) -> bool: def __post_request(self, message_url: str, req_json: dict, i: int, title: str, retry: int = 0) -> bool:
""" """
向微信发送请求 向微信发送请求
""" """
@ -355,6 +355,11 @@ class MessageForward(_PluginBase):
if ret_json.get('errcode') == 42001: if ret_json.get('errcode') == 42001:
# 重新获取token # 重新获取token
self.__flush_access_token(i) self.__flush_access_token(i)
retry += 1
# 重发请求
if retry <= 3:
self.__post_request(message_url=message_url, req_json=req_json, i=i, title=title,
retry=retry)
logger.error(f"转发消息 {title} 失败,错误信息:{ret_json}") logger.error(f"转发消息 {title} 失败,错误信息:{ret_json}")
return False return False
elif res is not None: elif res is not None:
@ -364,7 +369,7 @@ class MessageForward(_PluginBase):
logger.error(f"转发消息 {title} 失败,未获取到返回信息") logger.error(f"转发消息 {title} 失败,未获取到返回信息")
return False return False
except Exception as err: except Exception as err:
logger.error(f"转发消息 {title} 失败,错误信息:{err}") logger.error(f"转发消息 {title} 异常,错误信息:{err}")
return False return False
def __get_access_token(self, corpid, appsecret): def __get_access_token(self, corpid, appsecret):