feat:m-team x-api-key

This commit is contained in:
jxxghp
2024-03-24 13:38:36 +08:00
parent 96de772119
commit bd7ca7fa60
7 changed files with 119 additions and 13 deletions

View File

@ -57,8 +57,8 @@ def add_site(
site_in.id = None site_in.id = None
site = Site(**site_in.dict()) site = Site(**site_in.dict())
site.create(db) site.create(db)
# 通知缓存站点图标 # 通知站点更新
EventManager().send_event(EventType.CacheSiteIcon, { EventManager().send_event(EventType.SiteUpdated, {
"domain": domain "domain": domain
}) })
return schemas.Response(success=True) return schemas.Response(success=True)
@ -81,8 +81,8 @@ def update_site(
_scheme, _netloc = StringUtils.get_url_netloc(site_in.url) _scheme, _netloc = StringUtils.get_url_netloc(site_in.url)
site_in.url = f"{_scheme}://{_netloc}/" site_in.url = f"{_scheme}://{_netloc}/"
site.update(db, site_in.dict()) site.update(db, site_in.dict())
# 通知缓存站点图标 # 通知站点更新
EventManager().send_event(EventType.CacheSiteIcon, { EventManager().send_event(EventType.SiteUpdated, {
"domain": site_in.domain "domain": site_in.domain
}) })
return schemas.Response(success=True) return schemas.Response(success=True)

View File

@ -109,17 +109,27 @@ class DownloadChain(ChainBase):
# 解码参数 # 解码参数
req_str = base64.b64decode(base64_str.encode('utf-8')).decode('utf-8') req_str = base64.b64decode(base64_str.encode('utf-8')).decode('utf-8')
req_params: Dict[str, dict] = json.loads(req_str) req_params: Dict[str, dict] = json.loads(req_str)
# 是否使用cookie
if not req_params.get('cookie'):
cookie = None
# 请求头
if req_params.get('header'):
headers = req_params.get('header')
else:
headers = None
if req_params.get('method') == 'get': if req_params.get('method') == 'get':
# GET请求 # GET请求
res = RequestUtils( res = RequestUtils(
ua=ua, ua=ua,
cookies=cookie cookies=cookie,
headers=headers
).get_res(url, params=req_params.get('params')) ).get_res(url, params=req_params.get('params'))
else: else:
# POST请求 # POST请求
res = RequestUtils( res = RequestUtils(
ua=ua, ua=ua,
cookies=cookie cookies=cookie,
headers=headers
).post_res(url, params=req_params.get('params')) ).post_res(url, params=req_params.get('params'))
if not res: if not res:
return None return None

View File

@ -12,6 +12,7 @@ from app.core.event import eventmanager, Event, EventManager
from app.db.models.site import Site from app.db.models.site import Site
from app.db.site_oper import SiteOper from app.db.site_oper import SiteOper
from app.db.siteicon_oper import SiteIconOper from app.db.siteicon_oper import SiteIconOper
from app.db.systemconfig_oper import SystemConfigOper
from app.helper.browser import PlaywrightHelper from app.helper.browser import PlaywrightHelper
from app.helper.cloudflare import under_challenge from app.helper.cloudflare import under_challenge
from app.helper.cookie import CookieHelper from app.helper.cookie import CookieHelper
@ -41,6 +42,7 @@ class SiteChain(ChainBase):
self.cookiehelper = CookieHelper() self.cookiehelper = CookieHelper()
self.message = MessageHelper() self.message = MessageHelper()
self.cookiecloud = CookieCloudHelper() self.cookiecloud = CookieCloudHelper()
self.systemconfig = SystemConfigOper()
# 特殊站点登录验证 # 特殊站点登录验证
self.special_site_test = { self.special_site_test = {
@ -237,9 +239,9 @@ class SiteChain(ChainBase):
public=1 if indexer.get("public") else 0) public=1 if indexer.get("public") else 0)
_add_count += 1 _add_count += 1
# 通知缓存站点图标 # 通知站点更新
if indexer: if indexer:
EventManager().send_event(EventType.CacheSiteIcon, { EventManager().send_event(EventType.SiteUpdated, {
"domain": domain, "domain": domain,
}) })
# 处理完成 # 处理完成
@ -251,7 +253,7 @@ class SiteChain(ChainBase):
logger.info(f"CookieCloud同步成功{ret_msg}") logger.info(f"CookieCloud同步成功{ret_msg}")
return True, ret_msg return True, ret_msg
@eventmanager.register(EventType.CacheSiteIcon) @eventmanager.register(EventType.SiteUpdated)
def cache_site_icon(self, event: Event): def cache_site_icon(self, event: Event):
""" """
缓存站点图标 缓存站点图标
@ -293,6 +295,27 @@ class SiteChain(ChainBase):
else: else:
logger.warn(f"缓存站点 {indexer.get('name')} 图标失败") logger.warn(f"缓存站点 {indexer.get('name')} 图标失败")
@eventmanager.register(EventType.SiteUpdated)
def clear_site_data(self, event: Event):
"""
清理站点数据
"""
if not event:
return
event_data = event.event_data or {}
# 主域名
domain = event_data.get("domain")
if not domain:
return
# 获取主域名中间那段
domain_host = StringUtils.get_url_host(domain)
# 查询以"site.domain_host"开头的配置项,并清除
site_keys = self.systemconfig.all().keys()
for key in site_keys:
if key.startswith(f"site.{domain_host}"):
logger.info(f"清理站点配置:{key}")
self.systemconfig.delete(key)
def test(self, url: str) -> Tuple[bool, str]: def test(self, url: str) -> Tuple[bool, str]:
""" """
测试站点是否可用 测试站点是否可用

View File

@ -56,6 +56,12 @@ class SystemConfigOper(DbOper, metaclass=Singleton):
return self.__SYSTEMCONF return self.__SYSTEMCONF
return self.__SYSTEMCONF.get(key) return self.__SYSTEMCONF.get(key)
def all(self):
"""
获取所有系统设置
"""
return self.__SYSTEMCONF or {}
def delete(self, key: Union[str, SystemConfigKey]): def delete(self, key: Union[str, SystemConfigKey]):
""" """
删除系统设置 删除系统设置

View File

@ -6,6 +6,7 @@ from typing import Tuple, List
from ruamel.yaml import CommentedMap from ruamel.yaml import CommentedMap
from app.core.config import settings from app.core.config import settings
from app.db.systemconfig_oper import SystemConfigOper
from app.log import logger from app.log import logger
from app.schemas import MediaType from app.schemas import MediaType
from app.utils.http import RequestUtils from app.utils.http import RequestUtils
@ -13,6 +14,9 @@ from app.utils.string import StringUtils
class MTorrentSpider: class MTorrentSpider:
"""
mTorrent API需要缓存ApiKey
"""
_indexerid = None _indexerid = None
_domain = None _domain = None
_name = "" _name = ""
@ -28,6 +32,9 @@ class MTorrentSpider:
_movie_category = ['401', '419', '420', '421', '439', '405', '404'] _movie_category = ['401', '419', '420', '421', '439', '405', '404']
_tv_category = ['403', '402', '435', '438', '404', '405'] _tv_category = ['403', '402', '435', '438', '404', '405']
# API KEY
_apikey = None
# 标签 # 标签
_labels = { _labels = {
"0": "", "0": "",
@ -41,6 +48,7 @@ class MTorrentSpider:
} }
def __init__(self, indexer: CommentedMap): def __init__(self, indexer: CommentedMap):
self.systemconfig = SystemConfigOper()
if indexer: if indexer:
self._indexerid = indexer.get('id') self._indexerid = indexer.get('id')
self._domain = indexer.get('domain') self._domain = indexer.get('domain')
@ -51,10 +59,50 @@ class MTorrentSpider:
self._cookie = indexer.get('cookie') self._cookie = indexer.get('cookie')
self._ua = indexer.get('ua') self._ua = indexer.get('ua')
def __get_apikey(self) -> str:
"""
获取ApiKey
"""
domain_host = StringUtils.get_url_host(self._domain)
if not self.systemconfig.get(f"site.{domain_host}.apikey"):
try:
res = RequestUtils(
headers={
"Content-Type": "application/json",
"User-Agent": f"{self._ua}"
},
cookies=self._cookie,
ua=self._ua,
proxies=self._proxy,
referer=f"{self._domain}usercp?tab=laboratory",
timeout=30
).post_res(url=f"{self._domain}api/apikey/getKeyList")
if res and res.status_code == 200:
api_keys = res.json().get('data')
if api_keys:
logger.info(f"{self._name} 获取ApiKey成功")
# 按lastModifiedDate倒序排序
api_keys.sort(key=lambda x: x.get('lastModifiedDate'), reverse=True)
self._apikey = api_keys[0].get('apiKey')
self.systemconfig.set(f"site.{domain_host}.apikey", self._apikey)
else:
logger.warn(f"{self._name} 获取ApiKey失败请先在`控制台`->`实验室`建立存取令牌")
else:
logger.warn(f"{self._name} 获取ApiKey失败请检查Cookie是否有效")
except Exception as e:
logger.error(f"{self._name} 获取ApiKey出错{e}")
return self._apikey
def search(self, keyword: str, mtype: MediaType = None, page: int = 0) -> Tuple[bool, List[dict]]: def search(self, keyword: str, mtype: MediaType = None, page: int = 0) -> Tuple[bool, List[dict]]:
""" """
搜索 搜索
""" """
# 检查ApiKey
self.__get_apikey()
if not self._apikey:
return True, []
if not mtype: if not mtype:
categories = [] categories = []
elif mtype == MediaType.TV: elif mtype == MediaType.TV:
@ -71,9 +119,9 @@ class MTorrentSpider:
res = RequestUtils( res = RequestUtils(
headers={ headers={
"Content-Type": "application/json", "Content-Type": "application/json",
"User-Agent": f"{self._ua}" "User-Agent": f"{self._ua}",
"x-api-key": self._apikey
}, },
cookies=self._cookie,
proxies=self._proxy, proxies=self._proxy,
referer=f"{self._domain}browse", referer=f"{self._domain}browse",
timeout=30 timeout=30
@ -168,9 +216,16 @@ class MTorrentSpider:
url = self._downloadurl % self._domain url = self._downloadurl % self._domain
params = { params = {
'method': 'post', 'method': 'post',
'cookie': False,
'params': { 'params': {
'id': torrent_id 'id': torrent_id
}, },
'header': {
'Content-Type': 'application/json',
'User-Agent': f'{self._ua}',
'Accept': 'application/json, text/plain, */*',
'x-api-key': self._apikey
},
'result': 'data' 'result': 'data'
} }
# base64编码 # base64编码

View File

@ -40,8 +40,8 @@ class EventType(Enum):
NameRecognize = "name.recognize" NameRecognize = "name.recognize"
# 名称识别结果 # 名称识别结果
NameRecognizeResult = "name.recognize.result" NameRecognizeResult = "name.recognize.result"
# 缓存站点图标 # 站点发生更新
CacheSiteIcon = "cache.siteicon" SiteUpdated = "site.updated"
# 系统配置Key字典 # 系统配置Key字典

View File

@ -282,6 +282,18 @@ class StringUtils:
return netloc[-2] return netloc[-2]
return netloc[0] return netloc[0]
@staticmethod
def get_url_host(url: str) -> str:
"""
获取URL的一级域名
"""
if not url:
return ""
_, netloc = StringUtils.get_url_netloc(url)
if not netloc:
return ""
return netloc.split(".")[-2]
@staticmethod @staticmethod
def get_base_url(url: str) -> str: def get_base_url(url: str) -> str:
""" """