Merge pull request #881 from wumode/imdbsource

This commit is contained in:
jxxghp
2025-08-20 00:34:31 +08:00
committed by GitHub
6 changed files with 101 additions and 33 deletions

View File

@@ -432,11 +432,12 @@
"name": "绕过Trackers",
"description": "提供tracker服务器IP地址列表帮助IPv6连接绕过OpenClash。",
"labels": "工具",
"version": "1.4.2",
"version": "1.4.3",
"icon": "Clash_A.png",
"author": "wumode",
"level": 2,
"history": {
"v1.4.3": "修复 bug",
"v1.4.2": "修复插件动作",
"v1.4.1": "修复通知类型错误",
"v1.4": "异步查询DNS",
@@ -450,11 +451,12 @@
"name": "IMDb源",
"description": "让探索推荐和媒体识别支持IMDb数据源。",
"labels": "探索",
"version": "1.5.6",
"version": "1.5.7",
"icon": "IMDb_IOS-OSX_App.png",
"author": "wumode",
"level": 1,
"history": {
"v1.5.7": "改进异常处理",
"v1.5.6": "固定仪表盘组件海报比例; 修复 bug",
"v1.5.5": "修复初始化错误",
"v1.5.4": "改进媒体识别",

View File

@@ -29,7 +29,7 @@ class ImdbSource(_PluginBase):
# 插件图标
plugin_icon = "IMDb_IOS-OSX_App.png"
# 插件版本
plugin_version = "1.5.6"
plugin_version = "1.5.7"
# 插件作者
plugin_author = "wumode"
# 作者主页
@@ -60,7 +60,7 @@ class ImdbSource(_PluginBase):
def init_plugin(self, config: dict = None):
plugin_instance = self
plugin_instance: ImdbSource = self
def patched_recognize_media(chain_self, meta: MetaBase = None,
mtype: Optional[MediaType] = None,
@@ -822,6 +822,14 @@ class ImdbSource(_PluginBase):
ChainBase.async_recognize_media._patched_by == id(self) and
self._original_async_method):
ChainBase.async_recognize_media = self._original_async_method
if self._scheduler:
try:
self._scheduler.remove_all_jobs()
if self._scheduler.running:
self._scheduler.shutdown()
self._scheduler = None
except Exception as e:
logger.error(f"退出插件失败:{e}")
def get_module(self) -> Dict[str, Any]:
"""

View File

@@ -484,7 +484,11 @@ class ImdbHelper:
params = {"operationName": operation_name,
"variables": variables}
data = await self._async_request(params, sha256)
try:
data = await self._async_request(params, sha256)
except Exception as e:
logger.debug(f"An error occurred while querying {operation_name}: {e}")
return None
if not data:
return None
if 'error' in data:
@@ -530,7 +534,11 @@ class ImdbHelper:
'videos': videos or [],
'isRegistered': is_registered,
}
data = self._query_graphql(query, variables)
try:
data = self._query_graphql(query, variables)
except Exception as e:
logger.debug(f"An error occurred while querying VerticalListPageItems: {e}")
return None
if 'error' in data:
error = data['error']
if error:
@@ -602,7 +610,11 @@ class ImdbHelper:
'videos': videos or [],
'isRegistered': is_registered,
}
data = await self._async_query_graphql(query, variables)
try:
data = await self._async_query_graphql(query, variables)
except Exception as e:
logger.debug(f"An error occurred while querying VerticalListPageItems: {e}")
return None
if 'error' in data:
error = data['error']
if error:
@@ -650,7 +662,11 @@ class ImdbHelper:
params: Dict[str, Any] = {'query': query}
if limit:
params['limit'] = limit
r = self.__free_imdb_api(path=endpoint, params=params)
try:
r = self.__free_imdb_api(path=endpoint, params=params)
except Exception as e:
logger.debug(f"An error occurred while searching for titles: {e}")
return None
if r is None:
return None
return r.get('titles')
@@ -685,7 +701,11 @@ class ImdbHelper:
See `curl -X 'GET' 'https://api.imdbapi.dev/titles/tt0944947' -H 'accept: application/json'`
"""
endpoint = '/titles/%s'
r = self.__free_imdb_api(path=endpoint % title_id)
try:
r = self.__free_imdb_api(path=endpoint % title_id)
except Exception as e:
logger.debug(f"An error occurred while retrieving details: {e}")
return None
return r
def episodes(self, title_id: str, season: Optional[str] = None,
@@ -709,7 +729,11 @@ class ImdbHelper:
param['pageSize'] = page_size
if page_token is not None:
param['pageToken'] = page_token
r = self.__free_imdb_api(path=endpoint % title_id, params=param)
try:
r = self.__free_imdb_api(path=endpoint % title_id, params=param)
except Exception as e:
logger.debug(f"An error occurred while retrieving episodes: {e}")
return None
return r
def seasons(self, title_id: str) -> Optional[List[dict]]:
@@ -722,7 +746,11 @@ class ImdbHelper:
{[{"season": "1", "episodeCount": 11}]}
"""
endpoint = '/titles/%s/seasons'
r = self.__free_imdb_api(path=endpoint % title_id)
try:
r = self.__free_imdb_api(path=endpoint % title_id)
except Exception as e:
logger.debug(f"An error occurred while retrieving seasons: {e}")
return None
if r is None:
return None
return r.get('seasons')
@@ -753,7 +781,11 @@ class ImdbHelper:
param['pageSize'] = page_size
if page_token is not None:
param['pageToken'] = page_token
r = self.__free_imdb_api(path=endpoint % title_id, params=param) or {}
try:
r = self.__free_imdb_api(path=endpoint % title_id, params=param) or {}
except Exception as e:
logger.debug(f"An error occurred while retrieving credits: {e}")
return None
return r.get('credits')
def akas(self, title_id: str) -> Optional[list]:
@@ -774,7 +806,11 @@ class ImdbHelper:
},]
"""
endpoint = '/titles/%s/akas'
r = self.__free_imdb_api(path=endpoint % title_id)
try:
r = self.__free_imdb_api(path=endpoint % title_id)
except Exception as e:
logger.debug(f"An error occurred while retrieving alternative titles: {e}")
return None
if r is None:
return None
return r.get('akas')
@@ -968,7 +1004,11 @@ class ImdbHelper:
params: Dict[str, Any] = {'query': query}
if limit:
params['limit'] = limit
r = await self._async_free_imdb_api(path=endpoint, params=params)
try:
r = await self._async_free_imdb_api(path=endpoint, params=params)
except Exception as e:
logger.debug(f"An error occurred while searching for titles: {e}")
return None
if r is None:
return None
return r.get('titles')
@@ -981,7 +1021,11 @@ class ImdbHelper:
See `curl -X 'GET' 'https://api.imdbapi.dev/titles/tt0944947' -H 'accept: application/json'`
"""
endpoint = '/titles/%s'
r = await self._async_free_imdb_api(path=endpoint % title_id)
try:
r = await self._async_free_imdb_api(path=endpoint % title_id)
except Exception as e:
logger.debug(f"An error occurred while retrieving details: {e}")
return None
return r
async def async_episodes(self, title_id: str, season: Optional[str] = None,
@@ -1005,7 +1049,11 @@ class ImdbHelper:
param['pageSize'] = page_size
if page_token is not None:
param['pageToken'] = page_token
r = await self._async_free_imdb_api(path=endpoint % title_id, params=param)
try:
r = await self._async_free_imdb_api(path=endpoint % title_id, params=param)
except Exception as e:
logger.debug(f"An error occurred while retrieving episodes: {e}")
return None
return r
async def async_seasons(self, title_id: str) -> Optional[List[dict]]:
@@ -1018,7 +1066,11 @@ class ImdbHelper:
{[{"season": "1", "episodeCount": 11}]}
"""
endpoint = '/titles/%s/seasons'
r = await self._async_free_imdb_api(path=endpoint % title_id)
try:
r = await self._async_free_imdb_api(path=endpoint % title_id)
except Exception as e:
logger.debug(f"An error occurred while retrieving seasons: {e}")
return None
if r is None:
return None
return r.get('seasons')
@@ -1049,7 +1101,11 @@ class ImdbHelper:
param['pageSize'] = page_size
if page_token is not None:
param['pageToken'] = page_token
r = await self._async_free_imdb_api(path=endpoint % title_id, params=param) or {}
try:
r = await self._async_free_imdb_api(path=endpoint % title_id, params=param) or {}
except Exception as e:
logger.debug(f"An error occurred while retrieving credits: {e}")
return None
return r.get('credits')
async def async_akas(self, title_id: str) -> Optional[list]:
@@ -1070,7 +1126,11 @@ class ImdbHelper:
},]
"""
endpoint = '/titles/%s/akas'
r = await self._async_free_imdb_api(path=endpoint % title_id)
try:
r = await self._async_free_imdb_api(path=endpoint % title_id)
except Exception as e:
logger.debug(f"An error occurred while retrieving alternative titles: {e}")
return None
if r is None:
return None
return r.get('akas')

View File

@@ -17,7 +17,6 @@ from pysubs2 import SSAFile, SSAEvent
import pymediainfo
from langdetect import detect
import spacy
from spacy.util import compile_infix_regex
from spacy.tokenizer import Tokenizer
from app.core.config import settings
@@ -975,11 +974,12 @@ class LexiAnnot(_PluginBase):
logger.error(f"字典加载失败")
return
try:
# 为减少内存占用,只在处理时加载 spaCy 模型
nlp = spacy.load(self._spacy_model)
infixes = list(nlp.Defaults.infixes)
infixes = [i for i in infixes if '-' not in i]
# 使用修改后的正则表达式重新创建 tokenizer
infix_re = compile_infix_regex(infixes)
infix_re = spacy.util.compile_infix_regex(infixes)
nlp.tokenizer = Tokenizer(
nlp.vocab,
prefix_search=nlp.tokenizer.prefix_search,
@@ -1062,7 +1062,7 @@ class LexiAnnot(_PluginBase):
lexicon = json.load(f)
except Exception as e:
logger.debug(f"词典文件读取失败: {e}")
lexicon_files = ('cefr', 'coca20k', 'swear_words', 'examinations')
lexicon_files = ('cefr', 'coca20k', 'swear_words', 'examinations', 'version')
if any(file not in lexicon for file in lexicon_files):
return None
return lexicon
@@ -1588,7 +1588,7 @@ class LexiAnnot(_PluginBase):
例如:"[Hi]" 会被替换成 " " (4个空格)
"""
pattern = r'(\[.*?\])'
return re.sub(pattern, lambda match: ' ' * len(match.group(1)), text)
return re.sub(pattern, lambda match: ' ' * len(match.group(1)), _text)
simple_vocabulary = list(filter(lambda x: x < self._annot_level, ['A1', 'A2', 'B1', 'B2', 'C1', 'C2']))
patterns = [r'\d+th|\d?1st|\d?2nd|\d?3rd', r"\w+'s$", r"\w+'t$", "[Ii]'m$", r"\w+'re$", r"\w+'ve$", r"\w+'ll$"]

View File

@@ -29,7 +29,7 @@ class ToBypassTrackers(_PluginBase):
# 插件图标
plugin_icon = "Clash_A.png"
# 插件版本
plugin_version = "1.4.2"
plugin_version = "1.4.3"
# 插件作者
plugin_author = "wumode"
# 作者主页
@@ -68,7 +68,8 @@ class ToBypassTrackers(_PluginBase):
self.ipv6_txt = self.get_data("ipv6_txt") if self.get_data("ipv6_txt") else ""
self.ipv4_txt = self.get_data("ipv4_txt") if self.get_data("ipv4_txt") else ""
try:
with open(f"{settings.ROOT_PATH}/app/plugins/tobypasstrackers/sites/trackers", "r", encoding="utf-8") as f:
site_file = settings.ROOT_PATH/'app'/'plugins'/'tobypasstrackers'/'sites'/'trackers'
with open(site_file, "r", encoding="utf-8") as f:
base64_str = f.read()
self.trackers = json.loads(base64.b64decode(base64_str).decode("utf-8"))
except Exception as e:
@@ -101,7 +102,6 @@ class ToBypassTrackers(_PluginBase):
)
self._onlyonce = False
self.__update_config()
# self._scheduler.print_jobs()
self._scheduler.start()
def get_state(self) -> bool:
@@ -619,16 +619,14 @@ class ToBypassTrackers(_PluginBase):
# Load Chnroute6 Lists
res = RequestUtils().get_res(url=chnroute6_lists_url)
if res is not None and res.status_code == 200:
chnroute6_lists = res.text[:-1].split('\n')
for ipr in chnroute6_lists:
ipv6_list.append(ipr)
chnroute6_lists = res.text.strip().split('\n')
ipv6_list = [*chnroute6_lists]
if self._china_ip_route:
# Load Chnroute Lists
res = RequestUtils().get_res(url=chnroute_lists_url)
if res is not None and res.status_code == 200:
chnroute_lists = res.text[:-1].split('\n')
for ipr in chnroute_lists:
ip_list.append(ipr)
chnroute_lists = res.text.strip().split('\n')
ip_list = [*chnroute_lists]
do_sites = {site.domain: site.name for site in SiteOper().list_order_by_pri() if
site.id in self._bypassed_sites}
domain_name_map = {}

View File

@@ -1 +1 @@
eyJoZGRvbGJ5LmNvbSI6IFsidC5oZGRvbGJ5LmNvbSJdLCAidGp1cHQub3JnIjogWyJ0cmFja2VyLXB1YmxpYy50anVwdC5vcmciXSwgIm5pY2VwdC5uZXQiOiBbInd3dy5uaWNlcHQubmV0Il0sICJyb3VzaS56aXAiOiBbImhpdHB0LmNvbSJdLCAicHRob21lLm5ldCI6IFsicHRob21lLm5ldCJdLCAiaGR0aW1lLm9yZyI6IFsiaGR0aW1lLm9yZyJdLCAiZWFzdGdhbWUub3JnIjogWyJwdC5lYXN0Z2FtZS5vcmciXSwgInB0dGltZS5vcmciOiBbInd3dy5wdHRpbWUub3JnIl0sICJtLXRlYW0uY2MiOiBbInRyYWNrZXIubS10ZWFtLmNjIiwgInRyYWNrZXIubS10ZWFtLmlvIl0sICI1MnB0LnNpdGUiOiBbIjUycHQuc2l0ZSJdLCAicWluZ3dhcHQuY29tIjogWyJ0cmFja2VyLnFpbmd3YS5wcm8iLCAidHJhY2tlci5xaW5nd2FwdC5jb20iXSwgImhka3lsLmluIjogWyJ0cmFja2VyLmhka3lsLmluIl0sICJyYWluZ2ZoLnRvcCI6IFsicmFpbmdmaC50b3AiXSwgImhkZmFucy5vcmciOiBbImhkZmFucy5vcmciXSwgInB0bGdzLm9yZyI6IFsicHRsLmdzIiwgInJlbGF5MDEucHRsLmdzIl0sICJtb25pa2FkZXNpZ24udWsiOiBbInRyYWNrZXIubW9uaWthZGVzaWduLnVrIiwgImRhaWtpcmFpLm1vbmlrYWRlc2lnbi51ayIsICJhbmltZS1uby1pbmRleC5jb20iXSwgInB0c2Jhby5jbHViIjogWyJwdHNiYW8uY2x1YiJdLCAidG90aGVnbG9yeS5pbSI6IFsidHJhY2tlci50b3RoZWdsb3J5LmltIl0sICJ1Mi5kbWh5Lm9yZyI6IFsiZGF5ZHJlYW0uZG1oeS5iZXN0Il0sICJieXIucHQiOiBbInRyYWNrZXIuYnlyLnB0Il0sICJodWRidC5odXN0LmVkdS5jbiI6IFsiaHVkYnQuaHVzdC5lZHUuY24iXSwgImlsb2xpY29uLmNvbSI6IFsidHJhY2tlci5pbG9saWNvbi5jYyJdLCAiaGl0cHQuY29tIjogWyJoaXRwdC5jb20iXSwgImJ0c2Nob29sLmNsdWIiOiBbInB0LmJ0c2Nob29sLmNsdWIiXSwgImhkYXJlYS5jbHViIjogWyJ0cmFja2VyLmhkYXJlYS5jbHViIl0sICJzcHJpbmdzdW5kYXkubmV0IjogWyJvbjYuc3ByaW5nc3VuZGF5Lm5ldCIsICJvbi5zcHJpbmdzdW5kYXkubmV0Il0sICJ6bXB0LmNjIjogWyJ6bXB0LmNjIl0sICJjYXJwdC5uZXQiOiBbInRyYWNrZXIuY2FycHQubmV0Il0sICJpY2MyMDIyLmNvbSI6IFsidHJhY2tlci5pY2MyMDIyLnh5eiJdLCAia2VlcGZyZHMuY29tIjogWyJ0cmFja2VyLmtlZXBmcmRzLmNvbSJdLCAicHR6b25lLnh5eiI6IFsicHR6b25lLnh5eiJdLCAiY3NwdC50b3AiOiBbInRyYWNrZXIuY3NwdC50b3AiLCAidHJhY2tlci5jc3B0LmNjIiwgInRyYWNrZXIuY3NwdC5kYXRlIl0sICJjcmFicHQudmlwIjogWyJjcmFicHQudmlwIl0sICJva3B0Lm5ldCI6IFsid3d3Lm9rcHQubmV0Il0sICJnYW1lZ2FtZXB0LmNvbSI6IFsid3d3LmdhbWVnYW1lcHQuY29tIl0sICJhdWRpZW5jZXMubWUiOiBbInQuYXVkaWVuY2VzLm1lIiwgInRyYWNrZXIuY2luZWZpbGVzLmluZm8iXSwgInhpbmd5dW5nZS50b3AiOiBbInRyYWNrZXIueGluZ3l1bmdlLnRvcCIsICJ0cmFja2VyLnhpbmd5dW5nZS5zYnMiXSwgImV0OC5vcmciOiBbImV0OC5vcmciLCAidC5ldDgub3JnIl0sICJkaXNjZmFuLm5ldCI6IFsiZGlzY2Zhbi54eXoiXX0=
eyI1MnB0LnNpdGUiOiBbIjUycHQuc2l0ZSJdLCAiYXVkaWVuY2VzLm1lIjogWyJ0LmF1ZGllbmNlcy5tZSIsICJ0cmFja2VyLmNpbmVmaWxlcy5pbmZvIl0sICJidHNjaG9vbC5jbHViIjogWyJwdC5idHNjaG9vbC5jbHViIl0sICJieXIucHQiOiBbInRyYWNrZXIuYnlyLnB0Il0sICJjYXJwdC5uZXQiOiBbInRyYWNrZXIuY2FycHQubmV0Il0sICJjcmFicHQudmlwIjogWyJjcmFicHQudmlwIl0sICJjc3B0LnRvcCI6IFsidHJhY2tlci5jc3B0LnRvcCIsICJ0cmFja2VyLmNzcHQuY2MiLCAidHJhY2tlci5jc3B0LmRhdGUiXSwgImRpc2NmYW4ubmV0IjogWyJkaXNjZmFuLnh5eiJdLCAiZWFzdGdhbWUub3JnIjogWyJwdC5lYXN0Z2FtZS5vcmciXSwgImV0OC5vcmciOiBbImV0OC5vcmciLCAidC5ldDgub3JnIl0sICJnYW1lZ2FtZXB0LmNvbSI6IFsid3d3LmdhbWVnYW1lcHQuY29tIl0sICJoZGFyZWEuY2x1YiI6IFsidHJhY2tlci5oZGFyZWEuY2x1YiJdLCAiaGRkb2xieS5jb20iOiBbInQuaGRkb2xieS5jb20iXSwgImhkZmFucy5vcmciOiBbImhkZmFucy5vcmciXSwgImhka3lsLmluIjogWyJ0cmFja2VyLmhka3lsLmluIl0sICJoZHRpbWUub3JnIjogWyJoZHRpbWUub3JnIl0sICJoaXRwdC5jb20iOiBbImhpdHB0LmNvbSJdLCAiaHVkYnQuaHVzdC5lZHUuY24iOiBbImh1ZGJ0Lmh1c3QuZWR1LmNuIl0sICJpY2MyMDIyLmNvbSI6IFsidHJhY2tlci5pY2MyMDIyLnh5eiJdLCAiaWxvbGljb24uY29tIjogWyJ0cmFja2VyLmlsb2xpY29uLmNjIl0sICJrZWVwZnJkcy5jb20iOiBbInRyYWNrZXIua2VlcGZyZHMuY29tIl0sICJtLXRlYW0uY2MiOiBbInRyYWNrZXIubS10ZWFtLmNjIiwgInRyYWNrZXIubS10ZWFtLmlvIl0sICJtb25pa2FkZXNpZ24udWsiOiBbInRyYWNrZXIubW9uaWthZGVzaWduLnVrIiwgImRhaWtpcmFpLm1vbmlrYWRlc2lnbi51ayIsICJhbmltZS1uby1pbmRleC5jb20iXSwgIm5pY2VwdC5uZXQiOiBbInd3dy5uaWNlcHQubmV0Il0sICJva3B0Lm5ldCI6IFsid3d3Lm9rcHQubmV0Il0sICJwdGhvbWUubmV0IjogWyJwdGhvbWUubmV0Il0sICJwdGxncy5vcmciOiBbInB0bC5ncyIsICJyZWxheTAxLnB0bC5ncyJdLCAicHRzYmFvLmNsdWIiOiBbInB0c2Jhby5jbHViIl0sICJwdHRpbWUub3JnIjogWyJ3d3cucHR0aW1lLm9yZyJdLCAicHR6b25lLnh5eiI6IFsicHR6b25lLnh5eiJdLCAicWluZ3dhcHQuY29tIjogWyJ0cmFja2VyLnFpbmd3YS5wcm8iLCAidHJhY2tlci5xaW5nd2FwdC5jb20iXSwgInJhaW5nZmgudG9wIjogWyJyYWluZ2ZoLnRvcCJdLCAicm91c2kuemlwIjogWyJoaXRwdC5jb20iXSwgInNwcmluZ3N1bmRheS5uZXQiOiBbIm9uNi5zcHJpbmdzdW5kYXkubmV0IiwgIm9uLnNwcmluZ3N1bmRheS5uZXQiXSwgInRqdXB0Lm9yZyI6IFsidHJhY2tlci1wdWJsaWMudGp1cHQub3JnIl0sICJ0b3RoZWdsb3J5LmltIjogWyJ0cmFja2VyLnRvdGhlZ2xvcnkuaW0iXSwgInUyLmRtaHkub3JnIjogWyJkYXlkcmVhbS5kbWh5LmJlc3QiXSwgInhpbmd5dW5nZS50b3AiOiBbInRyYWNrZXIueGluZ3l1bmdlLnRvcCIsICJ0cmFja2VyLnhpbmd5dW5nZS5zYnMiXSwgInptcHQuY2MiOiBbInptcHQuY2MiXSwgImhoYW5jbHViLnRvcCI6IFsidHJhY2tlci5oaGFuY2x1Yi50b3AiXSwgImhkY2l0eS5jaXR5IjogWyJzeW5jLmxlbml0ZXIub3JnIl19