feat:m-team x-api-key
This commit is contained in:
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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]:
|
||||||
"""
|
"""
|
||||||
测试站点是否可用
|
测试站点是否可用
|
||||||
|
@ -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]):
|
||||||
"""
|
"""
|
||||||
删除系统设置
|
删除系统设置
|
||||||
|
@ -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编码
|
||||||
|
@ -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字典
|
||||||
|
@ -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:
|
||||||
"""
|
"""
|
||||||
|
Reference in New Issue
Block a user