Merge remote-tracking branch 'origin/main'
This commit is contained in:
@ -115,16 +115,18 @@ class ChainBase(metaclass=ABCMeta):
|
|||||||
"""
|
"""
|
||||||
return self.run_module("recognize_media", meta=meta, mtype=mtype, tmdbid=tmdbid)
|
return self.run_module("recognize_media", meta=meta, mtype=mtype, tmdbid=tmdbid)
|
||||||
|
|
||||||
def match_doubaninfo(self, name: str, mtype: str = None,
|
def match_doubaninfo(self, name: str, imdbid: str = None,
|
||||||
year: str = None, season: int = None) -> Optional[dict]:
|
mtype: str = None, year: str = None, season: int = None) -> Optional[dict]:
|
||||||
"""
|
"""
|
||||||
搜索和匹配豆瓣信息
|
搜索和匹配豆瓣信息
|
||||||
:param name: 标题
|
:param name: 标题
|
||||||
|
:param imdbid: imdbid
|
||||||
:param mtype: 类型
|
:param mtype: 类型
|
||||||
:param year: 年份
|
:param year: 年份
|
||||||
:param season: 季
|
:param season: 季
|
||||||
"""
|
"""
|
||||||
return self.run_module("match_doubaninfo", name=name, mtype=mtype, year=year, season=season)
|
return self.run_module("match_doubaninfo", name=name, imdbid=imdbid,
|
||||||
|
mtype=mtype, year=year, season=season)
|
||||||
|
|
||||||
def obtain_images(self, mediainfo: MediaInfo) -> Optional[MediaInfo]:
|
def obtain_images(self, mediainfo: MediaInfo) -> Optional[MediaInfo]:
|
||||||
"""
|
"""
|
||||||
|
@ -6,6 +6,7 @@ from typing import Dict, List, Optional, Union, Tuple
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from app.chain import ChainBase
|
from app.chain import ChainBase
|
||||||
|
from app.chain.douban import DoubanChain
|
||||||
from app.chain.download import DownloadChain
|
from app.chain.download import DownloadChain
|
||||||
from app.chain.search import SearchChain
|
from app.chain.search import SearchChain
|
||||||
from app.chain.torrents import TorrentsChain
|
from app.chain.torrents import TorrentsChain
|
||||||
@ -50,18 +51,28 @@ class SubscribeChain(ChainBase):
|
|||||||
识别媒体信息并添加订阅
|
识别媒体信息并添加订阅
|
||||||
"""
|
"""
|
||||||
logger.info(f'开始添加订阅,标题:{title} ...')
|
logger.info(f'开始添加订阅,标题:{title} ...')
|
||||||
# 识别元数据
|
metainfo = None
|
||||||
metainfo = MetaInfo(title)
|
mediainfo = None
|
||||||
if year:
|
if not tmdbid and doubanid:
|
||||||
metainfo.year = year
|
# 将豆瓣信息转换为TMDB信息
|
||||||
if mtype:
|
context = DoubanChain().recognize_by_doubanid(doubanid)
|
||||||
metainfo.type = mtype
|
if context:
|
||||||
if season:
|
metainfo = context.meta_info
|
||||||
metainfo.type = MediaType.TV
|
mediainfo = context.media_info
|
||||||
metainfo.begin_season = season
|
else:
|
||||||
# 识别媒体信息
|
# 识别元数据
|
||||||
mediainfo: MediaInfo = self.recognize_media(meta=metainfo, mtype=mtype, tmdbid=tmdbid)
|
metainfo = MetaInfo(title)
|
||||||
if not mediainfo:
|
if year:
|
||||||
|
metainfo.year = year
|
||||||
|
if mtype:
|
||||||
|
metainfo.type = mtype
|
||||||
|
if season:
|
||||||
|
metainfo.type = MediaType.TV
|
||||||
|
metainfo.begin_season = season
|
||||||
|
# 识别媒体信息
|
||||||
|
mediainfo = self.recognize_media(meta=metainfo, mtype=mtype, tmdbid=tmdbid)
|
||||||
|
# 识别失败
|
||||||
|
if not mediainfo or not metainfo or not mediainfo.tmdb_id:
|
||||||
logger.warn(f'未识别到媒体信息,标题:{title},tmdbid:{tmdbid}')
|
logger.warn(f'未识别到媒体信息,标题:{title},tmdbid:{tmdbid}')
|
||||||
return None, "未识别到媒体信息"
|
return None, "未识别到媒体信息"
|
||||||
# 更新媒体图片
|
# 更新媒体图片
|
||||||
@ -74,8 +85,8 @@ class SubscribeChain(ChainBase):
|
|||||||
if not kwargs.get('total_episode'):
|
if not kwargs.get('total_episode'):
|
||||||
if not mediainfo.seasons:
|
if not mediainfo.seasons:
|
||||||
# 补充媒体信息
|
# 补充媒体信息
|
||||||
mediainfo: MediaInfo = self.recognize_media(mtype=mediainfo.type,
|
mediainfo = self.recognize_media(mtype=mediainfo.type,
|
||||||
tmdbid=mediainfo.tmdb_id)
|
tmdbid=mediainfo.tmdb_id)
|
||||||
if not mediainfo:
|
if not mediainfo:
|
||||||
logger.error(f"媒体信息识别失败!")
|
logger.error(f"媒体信息识别失败!")
|
||||||
return None, "媒体信息识别失败"
|
return None, "媒体信息识别失败"
|
||||||
@ -85,7 +96,7 @@ class SubscribeChain(ChainBase):
|
|||||||
total_episode = len(mediainfo.seasons.get(season) or [])
|
total_episode = len(mediainfo.seasons.get(season) or [])
|
||||||
if not total_episode:
|
if not total_episode:
|
||||||
logger.error(f'未获取到总集数,标题:{title},tmdbid:{tmdbid}')
|
logger.error(f'未获取到总集数,标题:{title},tmdbid:{tmdbid}')
|
||||||
return None, "未获取到总集数"
|
return None, f"未获取到第 {season} 季的总集数"
|
||||||
kwargs.update({
|
kwargs.update({
|
||||||
'total_episode': total_episode
|
'total_episode': total_episode
|
||||||
})
|
})
|
||||||
|
@ -61,8 +61,7 @@ class WordsMatcher(metaclass=Singleton):
|
|||||||
|
|
||||||
if state:
|
if state:
|
||||||
appley_words.append(word)
|
appley_words.append(word)
|
||||||
else:
|
|
||||||
logger.debug(f"自定义识别词替换失败:{message}")
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
print(str(err))
|
print(str(err))
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from datetime import datetime
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional, Tuple, Union
|
from typing import List, Optional, Tuple, Union
|
||||||
|
|
||||||
@ -406,17 +406,29 @@ class DoubanModule(_ModuleBase):
|
|||||||
return ret_medias
|
return ret_medias
|
||||||
|
|
||||||
@retry(Exception, 5, 3, 3, logger=logger)
|
@retry(Exception, 5, 3, 3, logger=logger)
|
||||||
def match_doubaninfo(self, name: str, mtype: str = None,
|
def match_doubaninfo(self, name: str, imdbid: str = None,
|
||||||
year: str = None, season: int = None) -> dict:
|
mtype: str = None, year: str = None, season: int = None) -> dict:
|
||||||
"""
|
"""
|
||||||
搜索和匹配豆瓣信息
|
搜索和匹配豆瓣信息
|
||||||
:param name: 名称
|
:param name: 名称
|
||||||
|
:param imdbid: IMDB ID
|
||||||
:param mtype: 类型 电影/电视剧
|
:param mtype: 类型 电影/电视剧
|
||||||
:param year: 年份
|
:param year: 年份
|
||||||
:param season: 季号
|
:param season: 季号
|
||||||
"""
|
"""
|
||||||
result = self.doubanapi.search(f"{name} {year or ''}".strip(),
|
if imdbid:
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d%H%M%S'))
|
# 优先使用IMDBID查询
|
||||||
|
logger.info(f"开始使用IMDBID {imdbid} 查询豆瓣信息 ...")
|
||||||
|
result = self.doubanapi.imdbid(imdbid)
|
||||||
|
if result:
|
||||||
|
doubanid = result.get("id")
|
||||||
|
if doubanid and not str(doubanid).isdigit():
|
||||||
|
doubanid = re.search(r"\d+", doubanid).group(0)
|
||||||
|
result["id"] = doubanid
|
||||||
|
return result
|
||||||
|
# 搜索
|
||||||
|
logger.info(f"开始使用名称 {name} 查询豆瓣信息 ...")
|
||||||
|
result = self.doubanapi.search(f"{name} {year or ''}".strip())
|
||||||
if not result:
|
if not result:
|
||||||
logger.warn(f"未找到 {name} 的豆瓣信息")
|
logger.warn(f"未找到 {name} 的豆瓣信息")
|
||||||
return {}
|
return {}
|
||||||
@ -473,12 +485,16 @@ class DoubanModule(_ModuleBase):
|
|||||||
return
|
return
|
||||||
# 根据名称查询豆瓣数据
|
# 根据名称查询豆瓣数据
|
||||||
doubaninfo = self.match_doubaninfo(name=mediainfo.title,
|
doubaninfo = self.match_doubaninfo(name=mediainfo.title,
|
||||||
|
imdbid=mediainfo.imdb_id,
|
||||||
mtype=mediainfo.type.value,
|
mtype=mediainfo.type.value,
|
||||||
year=mediainfo.year,
|
year=mediainfo.year,
|
||||||
season=meta.begin_season)
|
season=meta.begin_season)
|
||||||
if not doubaninfo:
|
if not doubaninfo:
|
||||||
logger.warn(f"未找到 {mediainfo.title} 的豆瓣信息")
|
logger.warn(f"未找到 {mediainfo.title} 的豆瓣信息")
|
||||||
return
|
return
|
||||||
|
# 查询豆瓣详情
|
||||||
|
doubaninfo = self.douban_info(doubaninfo.get("id"))
|
||||||
|
# 刮削路径
|
||||||
scrape_path = path / path.name
|
scrape_path = path / path.name
|
||||||
self.scraper.gen_scraper_files(meta=meta,
|
self.scraper.gen_scraper_files(meta=meta,
|
||||||
mediainfo=MediaInfo(douban_info=doubaninfo),
|
mediainfo=MediaInfo(douban_info=doubaninfo),
|
||||||
@ -495,12 +511,15 @@ class DoubanModule(_ModuleBase):
|
|||||||
continue
|
continue
|
||||||
# 根据名称查询豆瓣数据
|
# 根据名称查询豆瓣数据
|
||||||
doubaninfo = self.match_doubaninfo(name=mediainfo.title,
|
doubaninfo = self.match_doubaninfo(name=mediainfo.title,
|
||||||
|
imdbid=mediainfo.imdb_id,
|
||||||
mtype=mediainfo.type.value,
|
mtype=mediainfo.type.value,
|
||||||
year=mediainfo.year,
|
year=mediainfo.year,
|
||||||
season=meta.begin_season)
|
season=meta.begin_season)
|
||||||
if not doubaninfo:
|
if not doubaninfo:
|
||||||
logger.warn(f"未找到 {mediainfo.title} 的豆瓣信息")
|
logger.warn(f"未找到 {mediainfo.title} 的豆瓣信息")
|
||||||
break
|
break
|
||||||
|
# 查询豆瓣详情
|
||||||
|
doubaninfo = self.douban_info(doubaninfo.get("id"))
|
||||||
# 刮削
|
# 刮削
|
||||||
self.scraper.gen_scraper_files(meta=meta,
|
self.scraper.gen_scraper_files(meta=meta,
|
||||||
mediainfo=MediaInfo(douban_info=doubaninfo),
|
mediainfo=MediaInfo(douban_info=doubaninfo),
|
||||||
|
@ -18,28 +18,29 @@ class DoubanApi(metaclass=Singleton):
|
|||||||
_urls = {
|
_urls = {
|
||||||
# 搜索类
|
# 搜索类
|
||||||
# sort=U:近期热门 T:标记最多 S:评分最高 R:最新上映
|
# sort=U:近期热门 T:标记最多 S:评分最高 R:最新上映
|
||||||
# q=search_word&start=0&count=20&sort=U
|
# q=search_word&start: int = 0&count: int = 20&sort=U
|
||||||
# 聚合搜索
|
# 聚合搜索
|
||||||
"search": "/search/weixin",
|
"search": "/search/weixin",
|
||||||
"search_agg": "/search",
|
"search_agg": "/search",
|
||||||
|
"imdbid": "/movie/imdb/%s",
|
||||||
|
|
||||||
# 电影探索
|
# 电影探索
|
||||||
# sort=U:综合排序 T:近期热度 S:高分优先 R:首播时间
|
# sort=U:综合排序 T:近期热度 S:高分优先 R:首播时间
|
||||||
# tags='日本,动画,2022'&start=0&count=20&sort=U
|
# tags='日本,动画,2022'&start: int = 0&count: int = 20&sort=U
|
||||||
"movie_recommend": "/movie/recommend",
|
"movie_recommend": "/movie/recommend",
|
||||||
# 电视剧探索
|
# 电视剧探索
|
||||||
"tv_recommend": "/tv/recommend",
|
"tv_recommend": "/tv/recommend",
|
||||||
# 搜索
|
# 搜索
|
||||||
"movie_tag": "/movie/tag",
|
"movie_tag": "/movie/tag",
|
||||||
"tv_tag": "/tv/tag",
|
"tv_tag": "/tv/tag",
|
||||||
# q=search_word&start=0&count=20
|
# q=search_word&start: int = 0&count: int = 20
|
||||||
"movie_search": "/search/movie",
|
"movie_search": "/search/movie",
|
||||||
"tv_search": "/search/movie",
|
"tv_search": "/search/movie",
|
||||||
"book_search": "/search/book",
|
"book_search": "/search/book",
|
||||||
"group_search": "/search/group",
|
"group_search": "/search/group",
|
||||||
|
|
||||||
# 各类主题合集
|
# 各类主题合集
|
||||||
# start=0&count=20
|
# start: int = 0&count: int = 20
|
||||||
# 正在上映
|
# 正在上映
|
||||||
"movie_showing": "/subject_collection/movie_showing/items",
|
"movie_showing": "/subject_collection/movie_showing/items",
|
||||||
# 热门电影
|
# 热门电影
|
||||||
@ -145,7 +146,9 @@ class DoubanApi(metaclass=Singleton):
|
|||||||
"api-client/1 com.douban.frodo/7.3.0(207) Android/22 product/MI 9 vendor/Xiaomi model/MI 9 brand/Android rom/miui6 network/wifi platform/mobile nd/1"]
|
"api-client/1 com.douban.frodo/7.3.0(207) Android/22 product/MI 9 vendor/Xiaomi model/MI 9 brand/Android rom/miui6 network/wifi platform/mobile nd/1"]
|
||||||
_api_secret_key = "bf7dddc7c9cfe6f7"
|
_api_secret_key = "bf7dddc7c9cfe6f7"
|
||||||
_api_key = "0dad551ec0f84ed02907ff5c42e8ec70"
|
_api_key = "0dad551ec0f84ed02907ff5c42e8ec70"
|
||||||
|
_api_key2 = "0ab215a8b1977939201640fa14c66bab"
|
||||||
_base_url = "https://frodo.douban.com/api/v2"
|
_base_url = "https://frodo.douban.com/api/v2"
|
||||||
|
_api_url = "https://api.douban.com/v2"
|
||||||
_session = None
|
_session = None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -153,6 +156,9 @@ class DoubanApi(metaclass=Singleton):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __sign(cls, url: str, ts: int, method='GET') -> str:
|
def __sign(cls, url: str, ts: int, method='GET') -> str:
|
||||||
|
"""
|
||||||
|
签名
|
||||||
|
"""
|
||||||
url_path = parse.urlparse(url).path
|
url_path = parse.urlparse(url).path
|
||||||
raw_sign = '&'.join([method.upper(), parse.quote(url_path, safe=''), str(ts)])
|
raw_sign = '&'.join([method.upper(), parse.quote(url_path, safe=''), str(ts)])
|
||||||
return base64.b64encode(
|
return base64.b64encode(
|
||||||
@ -164,7 +170,10 @@ class DoubanApi(metaclass=Singleton):
|
|||||||
).decode()
|
).decode()
|
||||||
|
|
||||||
@lru_cache(maxsize=settings.CACHE_CONF.get('douban'))
|
@lru_cache(maxsize=settings.CACHE_CONF.get('douban'))
|
||||||
def __invoke(self, url, **kwargs):
|
def __invoke(self, url: str, **kwargs) -> dict:
|
||||||
|
"""
|
||||||
|
GET请求
|
||||||
|
"""
|
||||||
req_url = self._base_url + url
|
req_url = self._base_url + url
|
||||||
|
|
||||||
params = {'apiKey': self._api_key}
|
params = {'apiKey': self._api_key}
|
||||||
@ -189,119 +198,224 @@ class DoubanApi(metaclass=Singleton):
|
|||||||
return resp.json()
|
return resp.json()
|
||||||
return resp.json() if resp else {}
|
return resp.json() if resp else {}
|
||||||
|
|
||||||
def search(self, keyword, start=0, count=20,
|
@lru_cache(maxsize=settings.CACHE_CONF.get('douban'))
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
def __post(self, url: str, **kwargs) -> dict:
|
||||||
|
"""
|
||||||
|
POST请求
|
||||||
|
esponse = requests.post(
|
||||||
|
url="https://api.douban.com/v2/movie/imdb/tt29139455",
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
||||||
|
"Cookie": "bid=J9zb1zA5sJc",
|
||||||
|
},
|
||||||
|
data={
|
||||||
|
"apikey": "0ab215a8b1977939201640fa14c66bab",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
req_url = self._api_url + url
|
||||||
|
params = {'apikey': self._api_key2}
|
||||||
|
if kwargs:
|
||||||
|
params.update(kwargs)
|
||||||
|
if '_ts' in params:
|
||||||
|
params.pop('_ts')
|
||||||
|
resp = RequestUtils(
|
||||||
|
ua=settings.USER_AGENT,
|
||||||
|
session=self._session,
|
||||||
|
).post_res(url=req_url, data=params)
|
||||||
|
if resp.status_code == 400 and "rate_limit" in resp.text:
|
||||||
|
return resp.json()
|
||||||
|
return resp.json() if resp else {}
|
||||||
|
|
||||||
|
def search(self, keyword: str, start: int = 0, count: int = 20,
|
||||||
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')) -> dict:
|
||||||
|
"""
|
||||||
|
关键字搜索
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["search"], q=keyword,
|
return self.__invoke(self._urls["search"], q=keyword,
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def movie_search(self, keyword, start=0, count=20,
|
def imdbid(self, imdbid: str,
|
||||||
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
IMDBID搜索
|
||||||
|
"""
|
||||||
|
return self.__post(self._urls["imdbid"] % imdbid, _ts=ts)
|
||||||
|
|
||||||
|
def movie_search(self, keyword: str, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
电影搜索
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["movie_search"], q=keyword,
|
return self.__invoke(self._urls["movie_search"], q=keyword,
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def tv_search(self, keyword, start=0, count=20,
|
def tv_search(self, keyword: str, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
电视搜索
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["tv_search"], q=keyword,
|
return self.__invoke(self._urls["tv_search"], q=keyword,
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def book_search(self, keyword, start=0, count=20,
|
def book_search(self, keyword: str, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
书籍搜索
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["book_search"], q=keyword,
|
return self.__invoke(self._urls["book_search"], q=keyword,
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def group_search(self, keyword, start=0, count=20,
|
def group_search(self, keyword: str, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
小组搜索
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["group_search"], q=keyword,
|
return self.__invoke(self._urls["group_search"], q=keyword,
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def movie_showing(self, start=0, count=20,
|
def movie_showing(self, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
正在热映
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["movie_showing"],
|
return self.__invoke(self._urls["movie_showing"],
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def movie_soon(self, start=0, count=20,
|
def movie_soon(self, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
即将上映
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["movie_soon"],
|
return self.__invoke(self._urls["movie_soon"],
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def movie_hot_gaia(self, start=0, count=20,
|
def movie_hot_gaia(self, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
热门电影
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["movie_hot_gaia"],
|
return self.__invoke(self._urls["movie_hot_gaia"],
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def tv_hot(self, start=0, count=20,
|
def tv_hot(self, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
热门剧集
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["tv_hot"],
|
return self.__invoke(self._urls["tv_hot"],
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def tv_animation(self, start=0, count=20,
|
def tv_animation(self, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
动画
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["tv_animation"],
|
return self.__invoke(self._urls["tv_animation"],
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def tv_variety_show(self, start=0, count=20,
|
def tv_variety_show(self, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
综艺
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["tv_variety_show"],
|
return self.__invoke(self._urls["tv_variety_show"],
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def tv_rank_list(self, start=0, count=20,
|
def tv_rank_list(self, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
电视剧排行榜
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["tv_rank_list"],
|
return self.__invoke(self._urls["tv_rank_list"],
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def show_hot(self, start=0, count=20,
|
def show_hot(self, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
综艺热门
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["show_hot"],
|
return self.__invoke(self._urls["show_hot"],
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def movie_detail(self, subject_id):
|
def movie_detail(self, subject_id: str):
|
||||||
|
"""
|
||||||
|
电影详情
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["movie_detail"] + subject_id)
|
return self.__invoke(self._urls["movie_detail"] + subject_id)
|
||||||
|
|
||||||
def movie_celebrities(self, subject_id):
|
def movie_celebrities(self, subject_id: str):
|
||||||
|
"""
|
||||||
|
电影演职员
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["movie_celebrities"] % subject_id)
|
return self.__invoke(self._urls["movie_celebrities"] % subject_id)
|
||||||
|
|
||||||
def tv_detail(self, subject_id):
|
def tv_detail(self, subject_id: str):
|
||||||
|
"""
|
||||||
|
电视剧详情
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["tv_detail"] + subject_id)
|
return self.__invoke(self._urls["tv_detail"] + subject_id)
|
||||||
|
|
||||||
def tv_celebrities(self, subject_id):
|
def tv_celebrities(self, subject_id: str):
|
||||||
|
"""
|
||||||
|
电视剧演职员
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["tv_celebrities"] % subject_id)
|
return self.__invoke(self._urls["tv_celebrities"] % subject_id)
|
||||||
|
|
||||||
def book_detail(self, subject_id):
|
def book_detail(self, subject_id: str):
|
||||||
|
"""
|
||||||
|
书籍详情
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["book_detail"] + subject_id)
|
return self.__invoke(self._urls["book_detail"] + subject_id)
|
||||||
|
|
||||||
def movie_top250(self, start=0, count=20,
|
def movie_top250(self, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
电影TOP250
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["movie_top250"],
|
return self.__invoke(self._urls["movie_top250"],
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def movie_recommend(self, tags='', sort='R', start=0, count=20,
|
def movie_recommend(self, tags='', sort='R', start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
电影探索
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["movie_recommend"], tags=tags, sort=sort,
|
return self.__invoke(self._urls["movie_recommend"], tags=tags, sort=sort,
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def tv_recommend(self, tags='', sort='R', start=0, count=20,
|
def tv_recommend(self, tags='', sort='R', start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
电视剧探索
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["tv_recommend"], tags=tags, sort=sort,
|
return self.__invoke(self._urls["tv_recommend"], tags=tags, sort=sort,
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def tv_chinese_best_weekly(self, start=0, count=20,
|
def tv_chinese_best_weekly(self, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
华语口碑周榜
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["tv_chinese_best_weekly"],
|
return self.__invoke(self._urls["tv_chinese_best_weekly"],
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def tv_global_best_weekly(self, start=0, count=20,
|
def tv_global_best_weekly(self, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
|
"""
|
||||||
|
全球口碑周榜
|
||||||
|
"""
|
||||||
return self.__invoke(self._urls["tv_global_best_weekly"],
|
return self.__invoke(self._urls["tv_global_best_weekly"],
|
||||||
start=start, count=count, _ts=ts)
|
start=start, count=count, _ts=ts)
|
||||||
|
|
||||||
def doulist_detail(self, subject_id):
|
def doulist_detail(self, subject_id: str):
|
||||||
"""
|
"""
|
||||||
豆列详情
|
豆列详情
|
||||||
:param subject_id: 豆列id
|
:param subject_id: 豆列id
|
||||||
"""
|
"""
|
||||||
return self.__invoke(self._urls["doulist"] + subject_id)
|
return self.__invoke(self._urls["doulist"] + subject_id)
|
||||||
|
|
||||||
def doulist_items(self, subject_id, start=0, count=20,
|
def doulist_items(self, subject_id: str, start: int = 0, count: int = 20,
|
||||||
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
ts=datetime.strftime(datetime.now(), '%Y%m%d')):
|
||||||
"""
|
"""
|
||||||
豆列列表
|
豆列列表
|
||||||
|
@ -382,13 +382,14 @@ class FileTransferModule(_ModuleBase):
|
|||||||
path=in_path,
|
path=in_path,
|
||||||
message=f"{in_path} 路径不存在")
|
message=f"{in_path} 路径不存在")
|
||||||
|
|
||||||
if not target_dir.exists():
|
if transfer_type not in ['rclone_copy', 'rclone_move']:
|
||||||
return TransferInfo(success=False,
|
# 检查目标路径
|
||||||
path=in_path,
|
if not target_dir.exists():
|
||||||
message=f"{target_dir} 目标路径不存在")
|
return TransferInfo(success=False,
|
||||||
|
path=in_path,
|
||||||
# 媒体库目的目录
|
message=f"{target_dir} 目标路径不存在")
|
||||||
target_dir = self.__get_dest_dir(mediainfo=mediainfo, target_dir=target_dir)
|
# 媒体库目的目录
|
||||||
|
target_dir = self.__get_dest_dir(mediainfo=mediainfo, target_dir=target_dir)
|
||||||
|
|
||||||
# 重命名格式
|
# 重命名格式
|
||||||
rename_format = settings.TV_RENAME_FORMAT \
|
rename_format = settings.TV_RENAME_FORMAT \
|
||||||
@ -401,6 +402,8 @@ class FileTransferModule(_ModuleBase):
|
|||||||
bluray_flag = SystemUtils.is_bluray_dir(in_path)
|
bluray_flag = SystemUtils.is_bluray_dir(in_path)
|
||||||
if bluray_flag:
|
if bluray_flag:
|
||||||
logger.info(f"{in_path} 是蓝光原盘文件夹")
|
logger.info(f"{in_path} 是蓝光原盘文件夹")
|
||||||
|
# 原文件大小
|
||||||
|
file_size = in_path.stat().st_size
|
||||||
# 目的路径
|
# 目的路径
|
||||||
new_path = self.get_rename_path(
|
new_path = self.get_rename_path(
|
||||||
path=target_dir,
|
path=target_dir,
|
||||||
@ -425,7 +428,7 @@ class FileTransferModule(_ModuleBase):
|
|||||||
return TransferInfo(success=True,
|
return TransferInfo(success=True,
|
||||||
path=in_path,
|
path=in_path,
|
||||||
target_path=new_path,
|
target_path=new_path,
|
||||||
total_size=new_path.stat().st_size,
|
total_size=file_size,
|
||||||
is_bluray=bluray_flag)
|
is_bluray=bluray_flag)
|
||||||
else:
|
else:
|
||||||
# 转移单个文件
|
# 转移单个文件
|
||||||
@ -466,7 +469,8 @@ class FileTransferModule(_ModuleBase):
|
|||||||
if new_file.stat().st_size < in_path.stat().st_size:
|
if new_file.stat().st_size < in_path.stat().st_size:
|
||||||
logger.info(f"目标文件已存在,但文件大小更小,将覆盖:{new_file}")
|
logger.info(f"目标文件已存在,但文件大小更小,将覆盖:{new_file}")
|
||||||
overflag = True
|
overflag = True
|
||||||
|
# 原文件大小
|
||||||
|
file_size = in_path.stat().st_size
|
||||||
# 转移文件
|
# 转移文件
|
||||||
retcode = self.__transfer_file(file_item=in_path,
|
retcode = self.__transfer_file(file_item=in_path,
|
||||||
new_file=new_file,
|
new_file=new_file,
|
||||||
@ -485,7 +489,7 @@ class FileTransferModule(_ModuleBase):
|
|||||||
path=in_path,
|
path=in_path,
|
||||||
target_path=new_file,
|
target_path=new_file,
|
||||||
file_count=1,
|
file_count=1,
|
||||||
total_size=new_file.stat().st_size,
|
total_size=file_size,
|
||||||
is_bluray=False,
|
is_bluray=False,
|
||||||
file_list=[str(in_path)],
|
file_list=[str(in_path)],
|
||||||
file_list_new=[str(new_file)])
|
file_list_new=[str(new_file)])
|
||||||
|
@ -103,7 +103,12 @@ class FilterModule(_ModuleBase):
|
|||||||
"CNVOI": {
|
"CNVOI": {
|
||||||
"include": [r'[国國][语語]配音|[国國]配|[国國][语語]'],
|
"include": [r'[国國][语語]配音|[国國]配|[国國][语語]'],
|
||||||
"exclude": []
|
"exclude": []
|
||||||
}
|
},
|
||||||
|
# 60FPS
|
||||||
|
"60FPS": {
|
||||||
|
"include": [r'60fps'],
|
||||||
|
"exclude": []
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def init_module(self) -> None:
|
def init_module(self) -> None:
|
||||||
|
@ -283,6 +283,8 @@ class TheMovieDbModule(_ModuleBase):
|
|||||||
:param mediainfo: 识别的媒体信息
|
:param mediainfo: 识别的媒体信息
|
||||||
:return: 更新后的媒体信息
|
:return: 更新后的媒体信息
|
||||||
"""
|
"""
|
||||||
|
if not mediainfo.tmdb_id:
|
||||||
|
return mediainfo
|
||||||
if mediainfo.logo_path \
|
if mediainfo.logo_path \
|
||||||
and mediainfo.poster_path \
|
and mediainfo.poster_path \
|
||||||
and mediainfo.backdrop_path:
|
and mediainfo.backdrop_path:
|
||||||
|
@ -251,6 +251,6 @@ class ChineseSubFinder(_PluginBase):
|
|||||||
else:
|
else:
|
||||||
logger.info("ChineseSubFinder任务添加成功:%s" % job_id)
|
logger.info("ChineseSubFinder任务添加成功:%s" % job_id)
|
||||||
else:
|
else:
|
||||||
logger.error("%s 目录缺失nfo元数据" % file_path)
|
logger.warn(f"ChineseSubFinder调用出错:{res.status_code} - {res.reason}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("连接ChineseSubFinder出错:" + str(e))
|
logger.error("连接ChineseSubFinder出错:" + str(e))
|
||||||
|
@ -587,6 +587,7 @@ class PersonMeta(_PluginBase):
|
|||||||
time.sleep(sleep_time)
|
time.sleep(sleep_time)
|
||||||
# 匹配豆瓣信息
|
# 匹配豆瓣信息
|
||||||
doubaninfo = self.chain.match_doubaninfo(name=mediainfo.title,
|
doubaninfo = self.chain.match_doubaninfo(name=mediainfo.title,
|
||||||
|
imdbid=mediainfo.imdb_id,
|
||||||
mtype=mediainfo.type.value,
|
mtype=mediainfo.type.value,
|
||||||
year=mediainfo.year,
|
year=mediainfo.year,
|
||||||
season=season)
|
season=season)
|
||||||
|
@ -99,6 +99,8 @@ class SystemUtils:
|
|||||||
try:
|
try:
|
||||||
# link到当前目录并改名
|
# link到当前目录并改名
|
||||||
tmp_path = src.parent / (dest.name + ".mp")
|
tmp_path = src.parent / (dest.name + ".mp")
|
||||||
|
if tmp_path.exists():
|
||||||
|
tmp_path.unlink()
|
||||||
tmp_path.hardlink_to(src)
|
tmp_path.hardlink_to(src)
|
||||||
# 移动到目标目录
|
# 移动到目标目录
|
||||||
shutil.move(tmp_path, dest)
|
shutil.move(tmp_path, dest)
|
||||||
|
@ -1 +1 @@
|
|||||||
APP_VERSION = 'v1.3.1'
|
APP_VERSION = 'v1.3.2-1'
|
||||||
|
Reference in New Issue
Block a user