mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-06-14 07:26:50 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65412a4263 | ||
|
|
0233b78c8e | ||
|
|
b0b25e4cfa | ||
|
|
806288d587 | ||
|
|
97265fc43b | ||
|
|
41ca50d0d4 | ||
|
|
9d02206fd9 | ||
|
|
ba2293eb30 | ||
|
|
8b9e28975d | ||
|
|
22ae8b8f87 | ||
|
|
187e352cbd | ||
|
|
23ef8ad28d | ||
|
|
1dadf56c42 | ||
|
|
52640b80c0 | ||
|
|
16b6c0da33 | ||
|
|
488a691f29 |
72
app/actions/invoke_plugin.py
Normal file
72
app/actions/invoke_plugin.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from pydantic import Field
|
||||
|
||||
from app.actions import BaseAction
|
||||
from app.core.plugin import PluginManager
|
||||
from app.log import logger
|
||||
from app.schemas import ActionParams, ActionContext
|
||||
|
||||
|
||||
class InvokePluginParams(ActionParams):
|
||||
"""
|
||||
调用插件动作参数
|
||||
"""
|
||||
plugin_id: str = Field(default=None, description="插件ID")
|
||||
action_id: str = Field(default=None, description="动作ID")
|
||||
action_params: dict = Field(default={}, description="动作参数")
|
||||
|
||||
|
||||
class InvokePluginAction(BaseAction):
|
||||
"""
|
||||
调用插件
|
||||
"""
|
||||
|
||||
_success = False
|
||||
|
||||
def __init__(self, action_id: str):
|
||||
super().__init__(action_id)
|
||||
self._success = False
|
||||
|
||||
@classmethod
|
||||
@property
|
||||
def name(cls) -> str: # noqa
|
||||
return "调用插件"
|
||||
|
||||
@classmethod
|
||||
@property
|
||||
def description(cls) -> str: # noqa
|
||||
return "调用插件提供的动作"
|
||||
|
||||
@classmethod
|
||||
@property
|
||||
def data(cls) -> dict: # noqa
|
||||
return InvokePluginParams().dict()
|
||||
|
||||
@property
|
||||
def success(self) -> bool:
|
||||
return self._success
|
||||
|
||||
def execute(self, workflow_id: int, params: dict, context: ActionContext) -> ActionContext:
|
||||
"""
|
||||
执行插件定义的动作
|
||||
"""
|
||||
params = InvokePluginParams(**params)
|
||||
if not params.plugin_id or not params.action_id:
|
||||
return context
|
||||
try:
|
||||
plugin_actions = PluginManager().get_plugin_actions(params.plugin_id)
|
||||
if not plugin_actions:
|
||||
logger.error(f"插件不存在: {params.plugin_id}")
|
||||
return context
|
||||
actions = plugin_actions[0].get("actions", [])
|
||||
action = next((action for action in actions if action.action_id == params.action_id), None)
|
||||
if not action or not action.get("func"):
|
||||
logger.error(f"插件动作不存在: {params.plugin_id} - {params.action_id}")
|
||||
return context
|
||||
# 执行插件动作
|
||||
self._success, context = action["func"](context, **params.action_params)
|
||||
except Exception as e:
|
||||
self._success = False
|
||||
logger.error(f"调用插件动作失败: {e}")
|
||||
return context
|
||||
self.job_done()
|
||||
return context
|
||||
@@ -11,7 +11,7 @@ from app.chain.mediaserver import MediaServerChain
|
||||
from app.core import security
|
||||
from app.core.config import settings
|
||||
from app.helper.sites import SitesHelper
|
||||
from app.utils.web import WebUtils
|
||||
from app.helper.wallpaper import WallpaperHelper
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -55,9 +55,11 @@ def wallpaper() -> Any:
|
||||
获取登录页面电影海报
|
||||
"""
|
||||
if settings.WALLPAPER == "bing":
|
||||
url = WebUtils.get_bing_wallpaper()
|
||||
url = WallpaperHelper().get_bing_wallpaper()
|
||||
elif settings.WALLPAPER == "mediaserver":
|
||||
url = MediaServerChain().get_latest_wallpaper()
|
||||
elif settings.WALLPAPER == "customize":
|
||||
url = WallpaperHelper().get_customize_wallpaper()
|
||||
else:
|
||||
url = TmdbChain().get_random_wallpager()
|
||||
if url:
|
||||
@@ -74,10 +76,12 @@ def wallpapers() -> Any:
|
||||
获取登录页面电影海报
|
||||
"""
|
||||
if settings.WALLPAPER == "bing":
|
||||
return WebUtils.get_bing_wallpapers()
|
||||
return WallpaperHelper().get_bing_wallpapers()
|
||||
elif settings.WALLPAPER == "mediaserver":
|
||||
return MediaServerChain().get_latest_wallpapers()
|
||||
elif settings.WALLPAPER == "tmdb":
|
||||
return TmdbChain().get_trending_wallpapers()
|
||||
elif settings.WALLPAPER == "customize":
|
||||
return WallpaperHelper().get_customize_wallpapers()
|
||||
else:
|
||||
return []
|
||||
|
||||
@@ -6,6 +6,7 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from app import schemas
|
||||
from app.core.config import global_vars
|
||||
from app.core.plugin import PluginManager
|
||||
from app.core.workflow import WorkFlowManager
|
||||
from app.db import get_db
|
||||
from app.db.models.workflow import Workflow
|
||||
@@ -43,6 +44,14 @@ def create_workflow(workflow: schemas.Workflow,
|
||||
return schemas.Response(success=True, message="创建工作流成功")
|
||||
|
||||
|
||||
@router.get("/plugin/actions", summary="查询插件动作", response_model=List[dict])
|
||||
def list_plugin_actions(plugin_id: str = None, _: schemas.TokenPayload = Depends(get_current_active_user)) -> Any:
|
||||
"""
|
||||
获取所有动作
|
||||
"""
|
||||
return PluginManager().get_plugin_actions(plugin_id)
|
||||
|
||||
|
||||
@router.get("/actions", summary="所有动作", response_model=List[dict])
|
||||
def list_actions(_: schemas.TokenPayload = Depends(get_current_active_user)) -> Any:
|
||||
"""
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import secrets
|
||||
@@ -89,6 +90,8 @@ class ConfigModel(BaseModel):
|
||||
PROXY_HOST: Optional[str] = None
|
||||
# 登录页面电影海报,tmdb/bing/mediaserver
|
||||
WALLPAPER: str = "tmdb"
|
||||
# 自定义壁纸api地址
|
||||
CUSTOMIZE_WALLPAPER_API_URL: Optional[str] = None
|
||||
# 媒体搜索来源 themoviedb/douban/bangumi,多个用,分隔
|
||||
SEARCH_SOURCE: str = "themoviedb,douban,bangumi"
|
||||
# 媒体识别来源 themoviedb/douban
|
||||
@@ -218,7 +221,15 @@ class ConfigModel(BaseModel):
|
||||
"https://github.com/honue/MoviePilot-Plugins,"
|
||||
"https://github.com/InfinityPacer/MoviePilot-Plugins,"
|
||||
"https://github.com/DDS-Derek/MoviePilot-Plugins,"
|
||||
"https://github.com/madrays/MoviePilot-Plugins")
|
||||
"https://github.com/madrays/MoviePilot-Plugins,"
|
||||
"https://github.com/justzerock/MoviePilot-Plugins,"
|
||||
"https://github.com/KoWming/MoviePilot-Plugins,"
|
||||
"https://github.com/wikrin/MoviePilot-Plugins,"
|
||||
"https://github.com/HankunYu/MoviePilot-Plugins,"
|
||||
"https://github.com/baozaodetudou/MoviePilot-Plugins,"
|
||||
"https://github.com/Aqr-K/MoviePilot-Plugins,"
|
||||
"https://github.com/hotlcc/MoviePilot-Plugins-Third,"
|
||||
"https://github.com/gxterry/MoviePilot-Plugins")
|
||||
# 插件安装数据共享
|
||||
PLUGIN_STATISTIC_SHARE: bool = True
|
||||
# 是否开启插件热加载
|
||||
@@ -359,13 +370,16 @@ class Settings(BaseSettings, ConfigModel, LogConfigModel):
|
||||
if field_name in fields_not_keep_spaces:
|
||||
value = re.sub(r"\s+", "", value)
|
||||
return value, str(value) != str(original_value)
|
||||
# # 后续考虑支持 list 类型的处理
|
||||
# elif expected_type is list:
|
||||
# if isinstance(value, list):
|
||||
# return value, False
|
||||
# if isinstance(value, str):
|
||||
# items = [item.strip() for item in value.split(",") if item.strip()]
|
||||
# return items, items != original_value.split(",")
|
||||
# 支持 list 类型的处理
|
||||
elif expected_type is list:
|
||||
if isinstance(value, list):
|
||||
return value, str(value) != str(original_value)
|
||||
if isinstance(value, str):
|
||||
items = json.loads(value)
|
||||
if isinstance(original_value, list):
|
||||
return items, items != original_value
|
||||
else:
|
||||
return items, str(items) != str(original_value)
|
||||
# 可根据需要添加更多类型处理
|
||||
else:
|
||||
return value, str(value) != str(original_value)
|
||||
@@ -406,7 +420,13 @@ class Settings(BaseSettings, ConfigModel, LogConfigModel):
|
||||
logger.warning(message)
|
||||
return False, message
|
||||
else:
|
||||
set_key(SystemUtils.get_env_path(), field.name, str(converted_value) if converted_value is not None else "")
|
||||
# 如果是列表、字典或集合类型,将其转换为JSON字符串
|
||||
if isinstance(converted_value, (list, dict, set)):
|
||||
value_to_write = json.dumps(converted_value)
|
||||
else:
|
||||
value_to_write = str(converted_value) if converted_value is not None else ""
|
||||
|
||||
set_key(SystemUtils.get_env_path(), field.name, value_to_write)
|
||||
if is_converted:
|
||||
logger.info(f"配置项 '{field.name}' 已自动修正并写入到 'app.env' 文件")
|
||||
return True, message
|
||||
|
||||
@@ -31,7 +31,7 @@ class MetaVideo(MetaBase):
|
||||
_part_re = r"(^PART[0-9ABI]{0,2}$|^CD[0-9]{0,2}$|^DVD[0-9]{0,2}$|^DISK[0-9]{0,2}$|^DISC[0-9]{0,2}$)"
|
||||
_roman_numerals = r"^(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$"
|
||||
_source_re = r"^BLURAY$|^HDTV$|^UHDTV$|^HDDVD$|^WEBRIP$|^DVDRIP$|^BDRIP$|^BLU$|^WEB$|^BD$|^HDRip$|^REMUX$|^UHD$"
|
||||
_effect_re = r"^SDR$|^HDR\d*$|^DOLBY$|^DOVI$|^DV$|^3D$|^REPACK$"
|
||||
_effect_re = r"^SDR$|^HDR\d*$|^DOLBY$|^DOVI$|^DV$|^3D$|^REPACK$|^HLG$"
|
||||
_resources_type_re = r"%s|%s" % (_source_re, _effect_re)
|
||||
_name_no_begin_re = r"^[\[【].+?[\]】]"
|
||||
_name_no_chinese_re = r".*版|.*字幕"
|
||||
@@ -50,8 +50,8 @@ class MetaVideo(MetaBase):
|
||||
r"|CD[\s.]*[1-9]|DVD[\s.]*[1-9]|DISK[\s.]*[1-9]|DISC[\s.]*[1-9]|\s+GB"
|
||||
_resources_pix_re = r"^[SBUHD]*(\d{3,4}[PI]+)|\d{3,4}X(\d{3,4})"
|
||||
_resources_pix_re2 = r"(^[248]+K)"
|
||||
_video_encode_re = r"^[HX]26[45]$|^AVC$|^HEVC$|^VC\d?$|^MPEG\d?$|^Xvid$|^DivX$|^HDR\d*$"
|
||||
_audio_encode_re = r"^DTS\d?$|^DTSHD$|^DTSHDMA$|^Atmos$|^TrueHD\d?$|^AC3$|^\dAudios?$|^DDP\d?$|^DD\d?$|^LPCM\d?$|^AAC\d?$|^FLAC\d?$|^HD\d?$|^MA\d?$"
|
||||
_video_encode_re = r"^(H26[45])$|^(x26[45])$|^AVC$|^HEVC$|^VC\d?$|^MPEG\d?$|^Xvid$|^DivX$|^AV1$|^HDR\d*$|^AVS(\+|[23])$"
|
||||
_audio_encode_re = r"^DTS\d?$|^DTSHD$|^DTSHDMA$|^Atmos$|^TrueHD\d?$|^AC3$|^\dAudios?$|^DDP\d?$|^DD\+\d?$|^DD\d?$|^LPCM\d?$|^AAC\d?$|^FLAC\d?$|^HD\d?$|^MA\d?$|^HR\d?$|^Opus\d?$|^Vorbis\d?$"
|
||||
|
||||
def __init__(self, title: str, subtitle: str = None, isfile: bool = False):
|
||||
"""
|
||||
@@ -592,7 +592,12 @@ class MetaVideo(MetaBase):
|
||||
self._stop_name_flag = True
|
||||
self._last_token_type = "videoencode"
|
||||
if not self.video_encode:
|
||||
self.video_encode = re_res.group(1).upper()
|
||||
if re_res.group(1):
|
||||
self.video_encode = re_res.group(1).upper()
|
||||
elif re_res.group(2):
|
||||
self.video_encode = re_res.group(2).lower()
|
||||
else:
|
||||
self.video_encode = re_res.group(0).upper()
|
||||
self._last_token = self.video_encode
|
||||
elif self.video_encode == "10bit":
|
||||
self.video_encode = f"{re_res.group(1).upper()} 10bit"
|
||||
|
||||
@@ -536,6 +536,35 @@ class PluginManager(metaclass=Singleton):
|
||||
logger.error(f"获取插件 {plugin_id} 模块出错:{str(e)}")
|
||||
return ret_modules
|
||||
|
||||
def get_plugin_actions(self, pid: Optional[str] = None) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
获取插件动作
|
||||
[{
|
||||
"id": "动作ID",
|
||||
"name": "动作名称",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 需要附加传递的参数
|
||||
}]
|
||||
"""
|
||||
ret_actions = []
|
||||
for plugin_id, plugin in self._running_plugins.items():
|
||||
if pid and pid != plugin_id:
|
||||
continue
|
||||
if hasattr(plugin, "get_actions") and ObjectUtils.check_method(plugin.get_actions):
|
||||
try:
|
||||
if not plugin.get_state():
|
||||
continue
|
||||
actions = plugin.get_actions()
|
||||
if actions:
|
||||
ret_actions.append({
|
||||
"plugin_id": plugin_id,
|
||||
"plugin_name": plugin.plugin_name,
|
||||
"actions": actions
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"获取插件 {plugin_id} 动作出错:{str(e)}")
|
||||
return ret_actions
|
||||
|
||||
@staticmethod
|
||||
def get_plugin_remote_entry(plugin_id: str, dist_path: str) -> str:
|
||||
"""
|
||||
|
||||
105
app/helper/wallpaper.py
Normal file
105
app/helper/wallpaper.py
Normal file
@@ -0,0 +1,105 @@
|
||||
from typing import Optional, List
|
||||
|
||||
from app.core.cache import cached
|
||||
from app.core.config import settings
|
||||
from app.utils.http import RequestUtils
|
||||
from app.utils.singleton import Singleton
|
||||
|
||||
|
||||
class WallpaperHelper(metaclass=Singleton):
|
||||
|
||||
def __init__(self):
|
||||
self.req = RequestUtils(timeout=5)
|
||||
|
||||
@cached(maxsize=1, ttl=3600)
|
||||
def get_bing_wallpaper(self) -> Optional[str]:
|
||||
"""
|
||||
获取Bing每日壁纸
|
||||
"""
|
||||
url = "https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1"
|
||||
resp = self.req.get_res(url)
|
||||
if resp and resp.status_code == 200:
|
||||
try:
|
||||
result = resp.json()
|
||||
if isinstance(result, dict):
|
||||
for image in result.get('images') or []:
|
||||
return f"https://cn.bing.com{image.get('url')}" if 'url' in image else ''
|
||||
except Exception as err:
|
||||
print(str(err))
|
||||
return None
|
||||
|
||||
@cached(maxsize=1, ttl=3600)
|
||||
def get_bing_wallpapers(self, num: int = 7) -> List[str]:
|
||||
"""
|
||||
获取7天的Bing每日壁纸
|
||||
"""
|
||||
url = f"https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n={num}"
|
||||
resp = self.req.get_res(url)
|
||||
if resp and resp.status_code == 200:
|
||||
try:
|
||||
result = resp.json()
|
||||
if isinstance(result, dict):
|
||||
return [f"https://cn.bing.com{image.get('url')}" for image in result.get('images') or []]
|
||||
except Exception as err:
|
||||
print(str(err))
|
||||
return []
|
||||
|
||||
@cached(maxsize=1, ttl=3600)
|
||||
def get_customize_wallpaper(self) -> Optional[str]:
|
||||
"""
|
||||
获取自定义壁纸api壁纸
|
||||
"""
|
||||
wallpaper_list = self.get_customize_wallpapers()
|
||||
if wallpaper_list:
|
||||
return wallpaper_list[0]
|
||||
return None
|
||||
|
||||
@cached(maxsize=1, ttl=3600)
|
||||
def get_customize_wallpapers(self) -> List[str]:
|
||||
"""
|
||||
获取自定义壁纸api壁纸
|
||||
"""
|
||||
|
||||
def find_files_with_suffixes(obj, suffixes: List[str]) -> List[str]:
|
||||
"""
|
||||
递归查找对象中所有包含特定后缀的文件,返回匹配的字符串列表
|
||||
支持输入:字典、列表、字符串
|
||||
"""
|
||||
_result = []
|
||||
|
||||
# 处理字符串
|
||||
if isinstance(obj, str):
|
||||
if obj.endswith(tuple(suffixes)):
|
||||
_result.append(obj)
|
||||
|
||||
# 处理字典
|
||||
elif isinstance(obj, dict):
|
||||
for value in obj.values():
|
||||
_result.extend(find_files_with_suffixes(value, suffixes))
|
||||
|
||||
# 处理列表
|
||||
elif isinstance(obj, list):
|
||||
for item in obj:
|
||||
_result.extend(find_files_with_suffixes(item, suffixes))
|
||||
|
||||
return _result
|
||||
|
||||
# 判断是否存在自定义壁纸api
|
||||
if settings.CUSTOMIZE_WALLPAPER_API_URL:
|
||||
wallpaper_list = []
|
||||
resp = self.req.get_res(settings.CUSTOMIZE_WALLPAPER_API_URL)
|
||||
if resp and resp.status_code == 200:
|
||||
# 如果返回的是图片格式
|
||||
content_type = resp.headers.get('Content-Type')
|
||||
if content_type and content_type.lower() == 'image/jpeg':
|
||||
wallpaper_list.append(resp.url)
|
||||
else:
|
||||
try:
|
||||
result = resp.json()
|
||||
if isinstance(result, list) or isinstance(result, dict) or isinstance(result, str):
|
||||
wallpaper_list = find_files_with_suffixes(result, settings.SECURITY_IMAGE_SUFFIXES)
|
||||
except Exception as err:
|
||||
print(str(err))
|
||||
return wallpaper_list
|
||||
else:
|
||||
return []
|
||||
@@ -115,11 +115,18 @@ class CategoryHelper(metaclass=Singleton):
|
||||
for attr, value in item.items():
|
||||
if not value:
|
||||
continue
|
||||
info_value = tmdb_info.get(attr)
|
||||
if attr == "release_year":
|
||||
# 发行年份
|
||||
info_value = tmdb_info.get("release_date") or tmdb_info.get("first_air_date")
|
||||
if info_value:
|
||||
info_value = str(info_value)[:4]
|
||||
else:
|
||||
info_value = tmdb_info.get(attr)
|
||||
if not info_value:
|
||||
match_flag = False
|
||||
continue
|
||||
elif attr == "production_countries":
|
||||
# 制片国家
|
||||
info_values = [str(val.get("iso_3166_1")).upper() for val in info_value]
|
||||
else:
|
||||
if isinstance(info_value, list):
|
||||
@@ -128,7 +135,18 @@ class CategoryHelper(metaclass=Singleton):
|
||||
info_values = [str(info_value).upper()]
|
||||
|
||||
if value.find(",") != -1:
|
||||
# , 分隔多个值
|
||||
values = [str(val).upper() for val in value.split(",") if val]
|
||||
elif value.find("-") != -1:
|
||||
# - 表示范围,仅限于数字
|
||||
value_begin = value.split("-")[0]
|
||||
value_end = value.split("-")[1]
|
||||
if value_begin.isdigit() and value_end.isdigit():
|
||||
# 数字范围
|
||||
values = [str(val) for val in range(int(value_begin), int(value_end) + 1)]
|
||||
else:
|
||||
# 字符串范围
|
||||
values = [str(value_begin), str(value_end)]
|
||||
else:
|
||||
values = [str(value).upper()]
|
||||
|
||||
|
||||
@@ -182,6 +182,22 @@ class _PluginBase(metaclass=ABCMeta):
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_actions(self) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
获取插件工作流动作
|
||||
[{
|
||||
"id": "动作ID",
|
||||
"name": "动作名称",
|
||||
"func": self.xxx,
|
||||
"kwargs": {} # 需要附加传递的参数
|
||||
}]
|
||||
|
||||
对实现函数的要求:
|
||||
1、函数的第一个参数固定为 ActionContent 实例,如需要传递额外参数,在kwargs中定义
|
||||
2、函数的返回:执行状态 True / False,更新后的 ActionContent 实例
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def stop_service(self):
|
||||
"""
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
from typing import Optional, List
|
||||
|
||||
from app.core.cache import cached
|
||||
|
||||
from app.utils.http import RequestUtils
|
||||
|
||||
|
||||
@@ -73,38 +69,3 @@ class WebUtils:
|
||||
except Exception as err:
|
||||
print(str(err))
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
@cached(maxsize=1, ttl=3600)
|
||||
def get_bing_wallpaper() -> Optional[str]:
|
||||
"""
|
||||
获取Bing每日壁纸
|
||||
"""
|
||||
url = "https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1"
|
||||
resp = RequestUtils(timeout=5).get_res(url)
|
||||
if resp and resp.status_code == 200:
|
||||
try:
|
||||
result = resp.json()
|
||||
if isinstance(result, dict):
|
||||
for image in result.get('images') or []:
|
||||
return f"https://cn.bing.com{image.get('url')}" if 'url' in image else ''
|
||||
except Exception as err:
|
||||
print(str(err))
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
@cached(maxsize=1, ttl=3600)
|
||||
def get_bing_wallpapers(num: int = 7) -> List[str]:
|
||||
"""
|
||||
获取7天的Bing每日壁纸
|
||||
"""
|
||||
url = f"https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n={num}"
|
||||
resp = RequestUtils(timeout=5).get_res(url)
|
||||
if resp and resp.status_code == 200:
|
||||
try:
|
||||
result = resp.json()
|
||||
if isinstance(result, dict):
|
||||
return [f"https://cn.bing.com{image.get('url')}" for image in result.get('images') or []]
|
||||
except Exception as err:
|
||||
print(str(err))
|
||||
return []
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
# `original_language` 语种,具体含义参考下方字典
|
||||
# `production_countries` 国家或地区(电影)、`origin_country` 国家或地区(电视剧),具体含义参考下方字典
|
||||
# `genre_ids` 内容类型,具体含义参考下方字典
|
||||
# `release_year` 发行年份,格式:YYYY,电影实际对应`release_date`字段,电视剧实际对应`first_air_date`字段,支持范围设定,如:`YYYY-YYYY`
|
||||
# themoviedb 详情API返回的其它一级字段
|
||||
# 4. 配置多项条件时需要同时满足,一个条件需要匹配多个值是使用`,`分隔
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
APP_VERSION = 'v2.4.7'
|
||||
FRONTEND_VERSION = 'v2.4.7'
|
||||
APP_VERSION = 'v2.4.8'
|
||||
FRONTEND_VERSION = 'v2.4.8'
|
||||
|
||||
Reference in New Issue
Block a user