Compare commits

...

5575 Commits

Author SHA1 Message Date
jxxghp
4ba8d42272 fix #5688 2026-04-19 17:29:07 +08:00
jxxghp
32e247b4d5 更新 version.py 2026-04-19 15:44:22 +08:00
InfinityPacer
1d0d09c909 fix(plugin): merge local repo sources during sync 2026-04-19 07:07:00 +08:00
InfinityPacer
b7ee6ca8c4 fix(plugin): sanitize local repo path telemetry 2026-04-19 07:07:00 +08:00
InfinityPacer
4a4d93e7f9 refactor(plugin): expose plugin list processing helper 2026-04-19 07:07:00 +08:00
InfinityPacer
7b096c0a09 feat(plugin): encode local repo path in source url 2026-04-19 07:07:00 +08:00
InfinityPacer
3a93efb082 refactor(plugin): centralize local install dispatch 2026-04-19 07:07:00 +08:00
InfinityPacer
73cdd297b1 refactor(plugin): align local repo naming 2026-04-19 07:07:00 +08:00
InfinityPacer
83187ea17d refactor(plugin): rename local repo paths setting 2026-04-19 07:07:00 +08:00
InfinityPacer
6d8eed30ce fix(plugin): reload monitor on local path changes 2026-04-19 07:07:00 +08:00
InfinityPacer
6fa48afa34 feat(plugin): support local plugin sources 2026-04-19 07:07:00 +08:00
jxxghp
115fb40772 Allow known nettest redirects 2026-04-18 18:27:03 +08:00
jxxghp
10b0dbb5d3 Add nettest documentation comments 2026-04-18 17:52:01 +08:00
jxxghp
4c32ad902b Harden system nettest SSRF handling 2026-04-18 17:43:38 +08:00
jxxghp
787db8f5ac fix: 修复子进程环境下获取事件循环失败的问题 2026-04-17 13:02:28 +08:00
jxxghp
df1b2067b6 fix: 修正 docker 和 update.sh 中 python_version 的格式以匹配 sites.cpython-* 命名规则 2026-04-17 11:05:26 +08:00
jxxghp
f3d9f25d02 优化资源包下载逻辑,只下载对应操作系统和Python版本的sites文件 2026-04-17 08:37:50 +08:00
jxxghp
eea7e3b55f feat(cli): optimize installation command and support initializing user password 2026-04-16 23:43:20 +08:00
jxxghp
810cb0a203 relax local install python requirement to 3.11 2026-04-16 23:13:45 +08:00
jxxghp
e0e21e39a2 refactor: generalize agent interaction requests 2026-04-16 22:51:51 +08:00
jxxghp
cc31c66b93 feat: add agent button choice workflow 2026-04-16 22:32:59 +08:00
jxxghp
011535fbc3 feat: add retry actions for failed transfers 2026-04-16 22:07:21 +08:00
jxxghp
77b95d11fb bump version to v2.10.1 2026-04-16 19:55:35 +08:00
jxxghp
89f6164eba automate local bootstrap prerequisites 2026-04-16 19:47:56 +08:00
jxxghp
70350aa39f fix local update dirty check 2026-04-16 19:36:55 +08:00
jxxghp
61a0a66c47 support local restart and site auth wizard 2026-04-16 19:21:00 +08:00
jxxghp
6fcc5c84a6 bump version to v2.10.0 2026-04-16 17:14:30 +08:00
jxxghp
5995b3f3e8 extend setup wizard for database and agent 2026-04-16 17:10:25 +08:00
jxxghp
60996be71b fix local db initialization model registration 2026-04-16 17:05:57 +08:00
jxxghp
49b50e5975 run setup config step inside venv 2026-04-16 17:00:49 +08:00
jxxghp
262bd6808b update reused bootstrap repo before setup 2026-04-16 16:51:44 +08:00
jxxghp
e9c8db9950 fix bootstrap script for macos bash 2026-04-16 16:43:21 +08:00
jxxghp
02a98f832f fix local cli install and config workflow 2026-04-16 14:55:31 +08:00
jxxghp
9a2a241a30 add full-stack local cli install flow 2026-04-16 09:52:15 +08:00
jxxghp
04c2a1eb18 Add manual AI redo flow 2026-04-15 17:10:18 +08:00
jxxghp
65a4b7438c 更新 config.py 2026-04-15 09:02:05 +08:00
jxxghp
13c3c082b8 Improve agent image capability routing 2026-04-15 08:55:32 +08:00
jxxghp
bf127d6a70 更新 version.py 2026-04-14 18:10:22 +08:00
jxxghp
117672384c 更新 llm.py 2026-04-14 16:00:44 +08:00
jxxghp
2ae2ea8ef7 feat: expose AI agent flag in user global settings 2026-04-14 15:50:46 +08:00
jxxghp
7a5e513f25 feat(agent): support file attachments and local file replies 2026-04-14 15:22:01 +08:00
InfinityPacer
81828948dd fix(transfer): tighten queue cleanup edge cases 2026-04-14 14:45:18 +08:00
InfinityPacer
eda73e14f7 refactor(transfer): make queue job migration explicit 2026-04-14 14:45:18 +08:00
InfinityPacer
6aec326d05 fix(transfer): fail stale queue tasks on errors 2026-04-14 14:45:18 +08:00
InfinityPacer
d36dd69ec3 fix(transfer): clean migrated queue jobs 2026-04-14 14:45:18 +08:00
ilvsx
1688063450 fix(subtitle): create missing download root before saving subtitles 2026-04-14 12:24:18 +08:00
InfinityPacer
ae5207f0e4 fix(plugin): handle 404 plugin index and None response safely 2026-04-13 18:34:44 +08:00
jxxghp
f1f4743936 fix #5661 插件package文件不存在时不报错 2026-04-13 09:06:45 +08:00
jxxghp
e09f9ad009 feat(agent): add audio message extraction and download support for Slack, QQ, Discord, SynologyChat, and VoceChat 2026-04-13 08:36:57 +08:00
InfinityPacer
8d938c2273 fix(system): expose backend dev flag only in dev mode 2026-04-13 06:54:33 +08:00
jxxghp
e5f97cd299 feat(agent): add voice message support with TTS/STT for Telegram and WeChat
- Integrate voice message handling: detect and extract audio references from Telegram and WeChat messages, route to agent with voice reply preference.
- Add voice provider abstraction and OpenAI-based TTS/STT implementation.
- Implement agent tool `send_voice_message` for generating and sending voice replies, with fallback to text if voice is unavailable.
- Extend agent prompt and context to support voice reply instructions.
- Update notification and message schemas to support audio fields.
- Add Telegram and WeChat voice sending logic, including audio file conversion and temporary media upload for WeChat.
- Add tests for voice helper and agent voice routing.
2026-04-12 12:30:02 +08:00
jxxghp
9dababbcfd 更新 version.py 2026-04-12 10:27:01 +08:00
jxxghp
9d8bd5044b 更新 version.py 2026-04-12 08:46:09 +08:00
InfinityPacer
5d07381111 chore(subscribe): update last_update when refreshing episode totals 2026-04-11 22:58:24 +08:00
InfinityPacer
61c695b77d fix(subscribe): reset tv episode counts in history response 2026-04-11 22:58:24 +08:00
InfinityPacer
1ceb8891b0 fix(subscribe): refresh total episodes before completion check 2026-04-11 22:58:24 +08:00
jxxghp
2f53fd3108 Expand image and edit support across messaging channels 2026-04-11 22:10:54 +08:00
jxxghp
bf2d2cbd03 Fix Telegram agent image download path 2026-04-11 21:11:03 +08:00
jxxghp
cb323653b8 Add tracing logs for agent image message flow 2026-04-11 20:58:20 +08:00
jxxghp
edf3946558 Fix forwarded image payload parsing for agent channels 2026-04-11 20:55:14 +08:00
jxxghp
6c5fae56d9 Add agent image support for Telegram and Slack 2026-04-11 20:40:02 +08:00
DDSRem
a4f2c574b0 fix(telegram): pass disable_web_page_preview through edit_message_text
Interactive plugin flows edit existing messages; the flag was only applied
on send_message, so link previews stayed enabled after edits.

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-04-11 08:31:15 +08:00
InfinityPacer
815d83bfb3 fix(http): close helper responses consistently 2026-04-10 18:21:30 +08:00
InfinityPacer
df3294c9d2 fix(http): require 200 for share reporting requests 2026-04-10 18:21:30 +08:00
InfinityPacer
1af5f02832 fix(http): use explicit success checks in async callers 2026-04-10 18:21:30 +08:00
InfinityPacer
217fcfd1b2 fix(http): close non-success responses safely 2026-04-10 18:21:30 +08:00
jxxghp
80825584ac 更新 version.py 2026-04-10 17:02:45 +08:00
jxxghp
10543eedd0 feat(search): 支持渐进式(SSE)搜索资源并实时返回搜索进度与结果
- 新增 /media/{mediaid}/stream 和 /title/stream 接口,支持基于 SSE 的渐进式搜索
- SearchChain 增加 async_search_by_title_stream、async_search_by_id_stream、async_process_stream、__async_search_all_sites_stream 方法
- 搜索结果按站点完成顺序实时推送,支持进度、候选、过滤、完成等阶段事件
- 优化参数解析与异常处理,提升大规模搜索体验
2026-04-10 16:50:23 +08:00
jxxghp
bf12a8679d refactor: 移除 agent 批量重试逻辑中的多余 try 块并优化缩进 2026-04-10 15:03:49 +08:00
InfinityPacer
8cd12ab584 fix(plugin): avoid caching failed plugin index responses 2026-04-10 14:34:00 +08:00
InfinityPacer
351de8b4da feat(plugin): reuse plugin wheels in batch dependency install 2026-04-10 13:32:30 +08:00
jxxghp
75fca971d4 refactor(agent): 重命名 can_edit_message 为 is_auto_flushing 更贴切语义 2026-04-09 23:29:29 +08:00
jxxghp
22f3244bf5 fix(agent): 流式+啰嗦模式下渠道不支持编辑时立即发送工具消息
渠道不支持编辑时没有定时刷新任务,emit 到 buffer 的内容不会被推送。
新增 can_edit_message 属性区分两种模式:支持编辑的继续 emit 到 buffer,
不支持编辑的 take 出 agent 文字与工具消息合并独立发送。
2026-04-09 23:26:39 +08:00
jxxghp
aafc4b3a39 fix(agent): start_streaming 始终标记流式状态以支持 buffer 收集
渠道不支持消息编辑时,仍需标记 streaming_enabled 为 True,
以便啰嗦模式下工具调用时能通过 is_streaming 进入流式分支
发送 agent 中间文字和工具消息。只是不启动定时刷新任务。
2026-04-09 23:19:34 +08:00
jxxghp
18906e5ab2 更新 __init__.py 2026-04-09 22:51:37 +08:00
jxxghp
9675d199f9 fix(agent): 非流式模式下不发送任何工具中间消息 2026-04-09 22:48:03 +08:00
jxxghp
78e8faa203 fix(agent): 非流式模式下啰嗦模式仍需发送工具调用中间消息
啰嗦模式+渠道不支持编辑时,虽然 is_streaming 为 False,
但 astream 仍会将 token 写入 buffer,需要在工具调用时
取出 agent 文字与工具消息合并发送
2026-04-09 22:23:00 +08:00
jxxghp
d5ed9bc654 fix(agent): 简化非流式模式下工具调用的消息处理逻辑
非流式模式下使用 ainvoke 执行,无流式 token 产出,
不需要操作 stream_handler 或发送中间消息
2026-04-09 22:20:09 +08:00
jxxghp
770065d9ed feat(agent): 优化Agent流式输出与工具消息发送逻辑
- 新增 _should_stream() 方法,根据运行环境决定是否启用流式输出:
  后台模式不启用;渠道支持编辑启用;啰嗦模式开启时也启用
- 非流式模式下使用非流式LLM + ainvoke,避免不必要的流式开销
- 非啰嗦模式下工具调用时不发送任何中间消息(agent文字和工具提示),直接清掉缓冲区
2026-04-09 22:12:20 +08:00
jxxghp
abc4154e2c 更新 version.py 2026-04-09 13:46:34 +08:00
DDSRem
fd6c9d5d34 feat(plugin): 聚合插件侧栏导航
- PluginManager.get_plugin_sidebar_nav:已启用 Vue 插件且实现 get_sidebar_nav
- schemas.PluginSidebarNavItem 与 verify_token 鉴权接口
2026-04-09 08:03:30 +08:00
jxxghp
dc428e7de0 feat(skills): 内置技能支持版本号管理,更新时自动覆盖旧版本
SKILL.md frontmatter新增version字段,同步时比较版本号,
内置版本更高时直接覆盖用户目录中的旧版本。
2026-04-09 07:17:04 +08:00
jxxghp
0c51d79be7 feat(agent): 合并同批次整理失败的agent重试调用,避免重复浪费token
同一download_hash或同一源目录下的失败记录在5分钟缓冲期内合并为一次agent调用,
批量处理时只识别一次媒体信息后复用到所有文件。
2026-04-09 07:16:56 +08:00
DDSRem
1b489ba581 feat(transfer): TransferOverwriteCheck 支持插件提供源文件真实大小
strm → strm 整理场景下,源 .strm 的 fileitem.size 同样不准,
size 模式比较仍会失效,新增 source_size 输出字段允许插件同时
覆盖源/目标的真实媒体大小。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 17:28:24 +08:00
DDSRem
4d9f17b083 feat(transfer): 新增 TransferOverwriteCheck 事件支持插件介入覆盖判断
允许插件在覆盖模式判断前提供目标文件的真实大小或直接给出覆盖决策,
解决 .strm 等本地大小不准的场景下 size 模式失效的问题。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 17:28:24 +08:00
jxxghp
3c7cd2186f 查询订阅历史工具有名称过滤时不分页直接返回所有匹配结果 2026-04-08 07:58:54 +08:00
jxxghp
5acfd683b9 agent工具支持翻页及取消数量限制 2026-04-08 07:41:34 +08:00
jxxghp
6b01901a4a 更新 search_web.py 2026-04-08 07:29:30 +08:00
jxxghp
1ca54afd6c 更新 search_person.py 2026-04-08 07:27:29 +08:00
jxxghp
9c75c2d22e 更新 search_media.py 2026-04-08 07:26:54 +08:00
jxxghp
79ec3ed2c3 更新 list_directory.py 2026-04-08 07:21:37 +08:00
jxxghp
7072d2cfe8 更新 query_installed_plugins.py 2026-04-08 07:15:13 +08:00
jxxghp
c0c08b0b84 更新 query_subscribe_history.py 2026-04-08 07:12:39 +08:00
jxxghp
01329195ee 更新 query_subscribes.py 2026-04-08 07:11:45 +08:00
jxxghp
ad40b99313 更新 version.py 2026-04-07 13:24:13 +08:00
jxxghp
1e338e48ab fix(agent): 基于langgraph_step过滤中间步骤思考文本,抽离ThinkTagStripper类
- 利用metadata中的langgraph_step检测工具调用前的中间步骤,非VERBOSE模式下
  自动reset清除模型输出的计划/推理文本(如NEXT STEPS、tool call描述等)
- 将<think>标签流式剥离逻辑抽离为独立的_ThinkTagStripper类,简化主流程
2026-04-07 12:42:46 +08:00
jxxghp
ac9c9598f4 feat(agent): add tools for querying and updating custom identifiers 2026-04-07 09:00:15 +08:00
jxxghp
02cb5dfc31 refactor(agent): optimize database-operation skill to read DB info from system prompt <system_info> 2026-04-07 07:37:39 +08:00
jxxghp
8109ffb445 feat(agent): add /stop_agent command for emergency stop of agent reasoning
Add /stop_agent command that cancels the currently running agent reasoning
task without clearing the session or memory. Unlike /clear_session which
destroys the entire session, this allows users to stop a long-running or
stuck agent process and continue the conversation afterward.
2026-04-07 07:32:35 +08:00
jxxghp
0ecbcb89fa 更新 SKILL.md 2026-04-07 07:16:18 +08:00
jxxghp
8f38c06424 feat(agent): add database-operation skill for SQL access with auto SQLite/PostgreSQL detection 2026-04-07 00:43:28 +08:00
jxxghp
902394f86e fix(agent): resolve circular import by lazy-importing Command in run_slash_command and list_slash_commands 2026-04-07 00:16:09 +08:00
jxxghp
9fefd807f9 refactor(agent): rename list_all_commands to list_slash_commands and skill to command-dispatch 2026-04-07 00:00:10 +08:00
jxxghp
a8fb4a6d84 refactor(agent): rename run_plugin_command to run_slash_command to avoid confusion with execute_command (shell) 2026-04-06 23:53:49 +08:00
jxxghp
7806267e92 feat(agent): add command-execute skill for intelligent command dispatch
- Enhance run_plugin_command tool to support all registered commands (system preset + plugin + other), not just plugin commands
- Add list_all_commands tool to discover all available commands with descriptions and categories
- Add command-execute skill that guides the agent to recognize user intent from natural language and match it to available system/plugin commands
2026-04-06 23:45:48 +08:00
Attente
eb5e17a115 test: 补充媒体刮削路径、图片与事件流程测试 2026-04-06 11:28:00 +08:00
Attente
2ae98d628d feat(subscribe): 优化洗版订阅合集的识别 2026-04-05 21:39:44 +08:00
EkkoG
8b9dc0e77f 修复 QQbot渠道依旧会重复发送消息问题 2026-04-05 15:42:46 +08:00
Attente
2f151cea64 fix(helper): 统一redis缓存键 2026-04-05 13:55:54 +08:00
jxxghp
b777e8cab1 删除 .DS_Store 2026-04-04 14:06:05 +08:00
jxxghp
663e37bd03 refactor: SendMessageTool message_type 改为消息标题 2026-04-04 07:42:36 +08:00
jxxghp
8960620883 更新 __init__.py 2026-04-04 07:29:41 +08:00
jxxghp
5b892b3a63 fix: 修复Gemini 2.5思考模型工具调用时thought_signature缺失导致400错误
- Google provider统一使用ChatGoogleGenerativeAI原生接口,不再走OpenAI兼容端点
  (OpenAI协议不支持thought_signature字段,导致思考模型工具调用必然失败)
- 通过client_args传递代理配置,替代原来的OpenAI兼容端点+openai_proxy方案
- 修补langchain-google-genai的_is_gemini_3_or_later()以覆盖Gemini 2.5模型
- 自动适配httpx代理参数名(proxies/proxy),修复代理配置被静默丢弃的问题
2026-04-04 07:24:47 +08:00
jxxghp
974d5f2f49 fix: 修复获取Google模型列表阻塞事件循环及缺少代理配置的问题 2026-04-04 06:58:39 +08:00
DDSRem
f70881bb4f feat: TransferRename 事件增加 source_item 源文件信息 2026-04-03 17:51:05 +08:00
jxxghp
376c65335f 更新 version.py 2026-04-03 13:49:38 +08:00
jxxghp
d7a5c32b08 feat: 整理失败时AI智能体自动重试
- 新增 delete_transfer_history 工具供智能体删除失败历史记录
- 新增 transfer-failed-retry 技能引导智能体执行重试流程
- 新增 AI_AGENT_RETRY_TRANSFER 配置项控制是否启用
- AgentManager 新增 retry_failed_transfer() 方法创建独立会话执行重试
- 整理失败和媒体未识别时自动触发智能体重试
2026-04-03 13:33:27 +08:00
jxxghp
4cda182ccd fix: change logger warning to debug for empty Discord configs 2026-04-03 12:50:14 +08:00
DDSRem
60ac901c6c feat: TransferRename 事件增加 source_path 源文件路径参数
在智能重命名事件中传递源文件路径,便于插件在重命名时获取待整理文件的原始路径信息。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 06:55:06 +08:00
DDSRem
388afa8d3c fix(meta): 修复首括号被误删导致标题识别错误
首括号包含完整发布名(如 [Movie.Name.2023.1080p.BluRay-GROUP])时,
保留内容去掉括号而非整体移除;同时修复 _name_movie_words 和
_name_se_words 列表误用为正则表达式的问题

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 06:54:11 +08:00
jxxghp
ec0915e488 fix: 智能体唤醒后消息发送问题 2026-04-02 19:26:17 +08:00
jxxghp
244112be5c fix: 智能体唤醒后消息发送问题 2026-04-02 19:23:40 +08:00
jxxghp
1f526adbe7 feat: add NotificationType for Agent messages 2026-04-02 19:13:05 +08:00
jxxghp
c4cfd70f7c 更新 version.py 2026-04-02 16:54:50 +08:00
DDSRem
c9149d1761 fix(system): 补充 fuse 挂载关键词
fix https://github.com/jxxghp/MoviePilot/issues/5624
2026-04-02 08:53:28 +08:00
DDSRem
c68450fc7f refactor(telegram): 显式传递 disable_web_page_preview 参数避免 @retry 下修改 kwargs
将 disable_web_page_preview 从修改 kwargs 字典改为显式传参给 send_message,
避免在 @retry 重试时因共享 kwargs 字典导致潜在问题。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 08:53:10 +08:00
DDSRem
d9eb3295b0 fix(telegram): 修复 disable_web_page_preview 传递给不支持的方法及 UTF-16 偏移量问题
1. disable_web_page_preview 仅在 send_message 时传入,避免 send_photo/send_document 抛出 TypeError
2. _embed_entity_links 中将 Telegram UTF-16 编码单位偏移量转换为 Python 字符偏移量,修复含 emoji 等非 BMP 字符时切片错误

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 08:53:10 +08:00
DDSRem
5440dbae51 feat(telegram): 支持 disable_web_page_preview 禁用链接预览
Notification schema 新增 disable_web_page_preview 字段,透传至 Telegram send_message,
插件可通过 post_message(disable_web_page_preview=True) 关闭链接预览,
不传时行为与旧版一致,完全向后兼容。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 08:53:10 +08:00
DDSRem
321bf94de8 fix(telegram): 转发频道消息无法接收及内容丢失
message_handler 默认只处理 text 类型,转发的媒体消息(视频、图片等)被忽略;
解析器未读取 caption 字段导致媒体消息文字丢失;
新增提取 text_link 实体 URL 和 reply_markup URL 按钮信息到文本中。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 08:53:10 +08:00
jxxghp
84b938c0d2 fix: 后台模式不发送工具调用消息 2026-03-31 18:25:55 +08:00
jxxghp
fc47382938 docs: 新增SKILL.md,补充MoviePilot重启与升级操作说明 2026-03-30 18:14:49 +08:00
jxxghp
2e034f7990 更新 version.py 2026-03-30 17:51:19 +08:00
jxxghp
e61299f748 refactor: 移除多余的空行,优化类型导入及方法为静态方法 2026-03-30 17:07:45 +08:00
jxxghp
cbff2fed17 agent工具增加管理员权限校验:查询站点、查询已安装插件、查询插件能力、查询站点用户数据、刮削元数据 2026-03-30 11:54:48 +08:00
jxxghp
9c51f73a72 feat(telegram): 优化Telegram文件下载与base64转换逻辑,重构消息发送相关代码
- 新增 TelegramModule.download_file_to_base64 方法,统一文件下载与base64编码
- Telegram 客户端新增 download_file 方法,简化文件下载流程
- 消息图片下载逻辑调整为通过模块方法调用,移除冗余静态方法
- 修复部分参数格式与空格风格,提升代码一致性
- 优化长消息发送异常处理与代码结构
2026-03-30 10:28:40 +08:00
jxxghp
70109635c7 feat(agent): 接入Exa API用于网络搜索 2026-03-30 07:11:29 +08:00
jxxghp
8999c3a855 去除集图片的-thumb后缀,使图片名称与视频文件名称一致 2026-03-29 12:06:42 +08:00
jxxghp
7bd775130e fix: 修复QQ渠道key映射 2026-03-29 10:48:23 +08:00
jxxghp
4bba7dbe76 fix: 修复QQ渠道名称为qq 2026-03-29 10:47:16 +08:00
jxxghp
0cab21b83c feat(agent): 为需要管理员权限的工具添加 require_admin 字段
- ExecuteCommandTool: 执行命令行
- DeleteDownloadHistoryTool: 删除下载历史
- EditFileTool: 编辑文件
- WriteFileTool: 写入文件
- TransferFileTool: 传输文件
- UpdateSiteTool: 更新站点
- UpdateSiteCookieTool: 更新站点Cookie
- UpdateSubscribeTool: 更新订阅
- DeleteSubscribeTool: 删除订阅
- DeleteDownloadTool: 删除下载
- ModifyDownloadTool: 修改下载
- RunSchedulerTool: 运行定时任务
- RunWorkflowTool: 运行工作流
- RunPluginCommandTool: 运行插件命令
- SendMessageTool: 发送消息
2026-03-29 10:46:35 +08:00
jxxghp
ca9cbc1160 fix(agent): 修复 MessageChannel.QQBot 不存在的错误 2026-03-29 10:38:52 +08:00
jxxghp
02439f55a9 feat(agent): 增加工具执行权限控制
- 工具执行前检查用户权限
- 支持渠道管理员名单验证
- 支持系统管理员验证
- 支持渠道配置用户ID验证
2026-03-29 10:30:09 +08:00
jxxghp
2d358e376c refactor: 移除多余的局部导入 2026-03-29 09:59:22 +08:00
jxxghp
b349aa2693 feat(agent): 支持图片消息处理 2026-03-29 09:56:53 +08:00
jxxghp
e3fee39043 agent提示词中注入PostgreSQL数据库密码 2026-03-29 09:07:46 +08:00
jxxghp
a1a72df6c6 feat(telegram): 保持正在输入状态直到消息发送完成 2026-03-29 09:04:42 +08:00
jxxghp
cdf40a7046 feat(agent): 添加PostgreSQL用户名到数据库信息 2026-03-29 08:05:40 +08:00
jxxghp
b9b19c9acc feat(agent): 添加数据库信息到系统提示词 2026-03-29 08:05:01 +08:00
jxxghp
8c603baa43 更新 version.py 2026-03-29 07:40:24 +08:00
jxxghp
a977948f2b 优化Agent提示词:日期改为当前时间,注入系统安装目录,强调简洁回复 2026-03-29 07:21:11 +08:00
jxxghp
f70eaf9363 feat(agent): 添加reset方法支持流式消息原地更新 2026-03-28 23:08:06 +08:00
jxxghp
bfea0174dd refactor: 优化工具消息发送逻辑 2026-03-28 22:38:20 +08:00
jxxghp
296d815e3e refactor: 移除异步pop操作 2026-03-28 12:42:26 +08:00
jxxghp
c3b7a50642 refactor(prompt): 优化MoviePilot系统信息注入,统一日期与环境信息展示 2026-03-28 12:28:14 +08:00
jxxghp
8e0a9f94f6 feat(agent): 在系统提示词中注入MoviePilot配置信息 2026-03-28 11:03:02 +08:00
jxxghp
6806900436 refactor: Update agent package initialization and imports. 2026-03-28 07:58:47 +08:00
jxxghp
a8ecdc8206 refactor: Invert AI agent verbose mode condition and strengthen silence instructions for tool calls. 2026-03-27 22:01:08 +08:00
jxxghp
60e1e3c173 Merge remote-tracking branch 'origin/v2' into v2 2026-03-27 21:55:19 +08:00
jxxghp
f859d99d91 fix current_date 2026-03-27 21:55:09 +08:00
jxxghp
31640b780c 更新 __init__.py 2026-03-27 21:50:19 +08:00
jxxghp
aaeb4d2634 fix verbose_spec 2026-03-27 21:45:50 +08:00
jxxghp
75d4c0153c v2.9.21 2026-03-27 21:05:04 +08:00
jxxghp
8d7ff2bd1d feat(agent): 新增AI_AGENT_VERBOSE开关,控制工具调用过程回复及提示词输出 2026-03-27 20:12:01 +08:00
jxxghp
c3e96ae73f 更新 version.py 2026-03-27 18:06:54 +08:00
developer-wlj
d8c86069f2 fix(agent): 解决内存文件读取编码问题
- 为文件读取操作明确指定 UTF-8 编码
- 防止因默认编码导致的字符读取错误
- 确保跨平台环境下的文件内容一致性
2026-03-27 11:52:07 +08:00
jxxghp
a25c709927 新增agent删除下载历史记录工具 2026-03-27 11:50:46 +08:00
jxxghp
d7c62fb55a feat(agent): 支持Slack和Discord渠道的流式输出功能
- 为Slack添加MESSAGE_EDITING能力
- 为Slack添加edit_message和send_direct_message方法
- 为Discord添加edit_message和send_direct_message方法
- 修改Discord send_msg返回(bool, message_id)元组以支持流式输出
2026-03-27 07:02:50 +08:00
jxxghp
27cc559c86 更新 memory.py 2026-03-26 22:33:03 +08:00
jxxghp
e7d14691df 优化记忆结构 2026-03-26 22:29:09 +08:00
jxxghp
20387a0085 更新 version.py 2026-03-26 17:31:30 +08:00
jxxghp
740b0a1396 fix 2026-03-26 12:42:54 +08:00
jxxghp
7d0c790185 fix: agent过滤模型思考/推理内容,不输出thinking到用户 2026-03-26 12:37:45 +08:00
jxxghp
a12147d0f5 style: 调整默认回复风格,简洁干练但保留适度的俏皮和emoji 2026-03-26 07:45:08 +08:00
jxxghp
213a298813 feat: 记忆为空时自动引导用户设置偏好;优化默认回复风格为简约直接 2026-03-26 07:30:18 +08:00
DDSRem
1acf78342c feat: tmdbid优先识别,同ID电影/电视剧通过元数据自动消歧
当名称中包含 {tmdbid=xxx} 时,优先使用tmdbid直接查询TMDB,不再回退到标题搜索。
当同一tmdbid同时存在电影和电视剧时,通过标题、年份、类型等元数据自动消歧。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 06:45:17 +08:00
jxxghp
c85d3adb34 refactor: 活动日志摘要改用 LLM 总结替代文本截取 2026-03-26 03:48:16 +08:00
jxxghp
83bf59dd4d feat: 新增 ActivityLogMiddleware,自动记录每次交互的活动日志并注入系统提示词 2026-03-26 03:32:20 +08:00
jxxghp
d5d6442e1d feat: 新增 moviepilot-api 技能,支持全量 REST API 调用;技能中间件自动同步内置技能到用户目录 2026-03-26 03:10:30 +08:00
jxxghp
a1fa469026 feat: 新增插件相关agent工具(查询插件、查询插件能力、运行插件命令) 2026-03-26 02:45:03 +08:00
jxxghp
4b4b808b76 feat: 流式输出消息超长时自动分段发送,消息长度限制纳入渠道能力管理 2026-03-26 01:56:11 +08:00
jxxghp
a6f16dcf8f feat: 同一会话消息排队顺序处理,不同会话互不影响 2026-03-25 22:01:35 +08:00
jxxghp
c822782910 更新 version.py 2026-03-25 18:35:09 +08:00
jxxghp
e598d5edc4 fix: AI_AGENT_JOB_INTERVAL 默认为0 2026-03-25 18:28:44 +08:00
jxxghp
d38b6dfc0a fix: 优化心跳提示词,后台任务只生成执行结果摘要 2026-03-25 18:18:34 +08:00
jxxghp
0a4091d93c fix: 后台任务使用非流式执行,仅发送模型最后一条回复 2026-03-25 18:15:19 +08:00
jxxghp
0399ab73cf feat: 后台任务(定时唤醒)跳过流式输出,仅广播最终结果 2026-03-25 17:10:48 +08:00
jxxghp
940cececf4 fix: 修复 channel 为空时系统提示词 markdown_spec 占位符未替换导致 KeyError 2026-03-25 13:17:41 +08:00
jxxghp
94c75eb1c7 feat: 智能体增加定时任务(Jobs)管理和心跳唤醒机制
- 新增 JobsMiddleware 中间件,支持通过 JOB.md 文件管理长期/重复性任务
- 智能体可创建一次性(once)和重复性(recurring)任务,自动跟踪执行状态
- 新增心跳唤醒机制,定时调度器周期性唤醒智能体检查并执行待处理任务
- 新增 AI_AGENT_JOB_INTERVAL 配置项控制检查间隔,默认24小时
- 每次心跳使用独立会话,执行完毕后清理资源
2026-03-25 13:02:20 +08:00
DDSRem
de4dbf283b feat: 文件名为辅助中文标签时使用父目录标题识别
当文件名(stem)为纯中文压制/字幕辅助标签(如"简英双语特效")且父目录包含
拉丁片名时,清空文件元数据的标题信息,改由父目录标题合并填充,避免识别失败。

新增 infopath 模块集中管理辅助标签判断逻辑与关键词正则。
2026-03-25 09:27:52 +08:00
jxxghp
10807a6fb7 fix: build actions 2026-03-25 08:43:04 +08:00
jxxghp
04b8475761 ci: 优化发布脚本,自动生成分类更新日志 2026-03-25 07:12:17 +08:00
jxxghp
e6e50d7f0a fix: 修复Agent流式输出时回复消息未记录到数据库的问题 2026-03-25 07:01:17 +08:00
jxxghp
94ed065344 fix: 修复Agent技能元数据中Path对象无法msgpack序列化的问题 2026-03-24 23:48:45 +08:00
jxxghp
d94b5962b4 fix: 修复技能加载时误读目录导致 IsADirectoryError 的问题 2026-03-24 23:12:52 +08:00
jxxghp
dcca318733 feat: QuerySitesTool 增加返回 cookie 字段 2026-03-24 22:53:30 +08:00
jxxghp
4a789297fe 更新 version.py 2026-03-24 21:22:49 +08:00
jxxghp
1249929b6a feat: 新增Agent浏览器操作工具(browse_webpage),支持通过Playwright控制浏览器进行网页交互 2026-03-24 21:06:41 +08:00
jxxghp
864af45f85 Merge pull request #5616 from DDSRem-Dev/package-fix 2026-03-24 20:44:55 +08:00
DDSRem
bd68bcfd27 fix: await async config reload handlers
Restore awaiting of async on_config_changed callbacks in ConfigReloadMixin to ensure config reload logic executes correctly.

Made-with: Cursor
2026-03-24 20:44:26 +08:00
jxxghp
17373bc0fe fix: 优化Agent消息排版 2026-03-24 20:21:58 +08:00
DDSRem
4612d3cdde fix: unpin pip tooling in Docker build
Allow Docker builds to install the latest pip and pip-tools versions instead of constraining them, reducing maintenance overhead from version pin drift.

Made-with: Cursor
2026-03-24 19:59:32 +08:00
DDSRem
517300afe9 fix: clean typing issues and refresh runtime dependencies
Align endpoint/module type hints and config reload handling while updating base Python image and package pins to improve build/runtime compatibility.

Made-with: Cursor
2026-03-24 19:21:04 +08:00
jxxghp
3c7fdfec3c 更新 base.py 2026-03-24 19:14:34 +08:00
jxxghp
cfc8d26558 fix: 修复查询下载任务工具访问TransferTorrent不存在字段的问题 2026-03-24 18:53:08 +08:00
jxxghp
1c16b8bfec feat: 查询下载任务工具支持按标签过滤 2026-03-24 18:45:47 +08:00
jxxghp
aae50004b1 feat: 新增修改下载任务Agent工具,查询下载任务支持返回标签
- 新增 modify_download Agent工具,支持通过hash修改下载任务的标签、开始和暂停下载
- 在 ChainBase 及三个下载器模块中新增 set_torrents_tag 方法
- DownloadingTorrent schema 新增 tags 字段
- 各下载器模块构建 DownloadingTorrent 时填充 tags
- query_download_tasks 工具输出中新增 tags 字段
2026-03-24 18:33:06 +08:00
jxxghp
4fbd2a7612 Merge pull request #5615 from Adraca/fix-v2-4939 2026-03-24 18:10:42 +08:00
Abhishek Khaparde
cede1a1100 fix: reset Telegram API URL to default when cleared
Co-authored-by: aider (deepseek/deepseek-chat) <aider@aider.chat>
2026-03-24 14:33:17 +05:30
jxxghp
5d3511cbc2 更新 skills.py 2026-03-24 12:25:06 +08:00
jxxghp
a66e082a8c fix: change U115_APP_ID 2026-03-24 11:23:06 +08:00
jxxghp
2406438d1b docs: Add guidelines for creating new skills, including directory structure and SKILL.md format. 2026-03-24 09:20:02 +08:00
jxxghp
be42c78aca fix bug 2026-03-24 09:11:37 +08:00
jxxghp
78b8b30351 rollback aiopathlib 2026-03-24 09:06:44 +08:00
jxxghp
80e35fa938 feat(agent): support skills 2026-03-24 08:51:17 +08:00
jxxghp
e82494c444 feat(agent): support skills 2026-03-24 08:48:27 +08:00
jxxghp
309b7b8a77 feat: 新增 LLM_MAX_TOOLS 配置项,支持按需启用 LLMToolSelectorMiddleware 2026-03-23 23:45:32 +08:00
jxxghp
f2daa633b6 更新 version.py 2026-03-23 23:11:19 +08:00
jxxghp
630d13ac52 fix: 修复集缩略图文件名错误,episode-thumb-xx 改为 视频文件名-thumb.xx 2026-03-23 23:05:25 +08:00
jxxghp
40c79b249b 更新 __init__.py 2026-03-23 22:35:08 +08:00
jxxghp
6f4df912d8 更新 __init__.py 2026-03-23 22:33:18 +08:00
jxxghp
5744228a9d 更新 base.py 2026-03-23 22:31:27 +08:00
jxxghp
8c46ece44a Merge pull request #5612 from PKC278/v2 2026-03-23 22:21:32 +08:00
PKC278
4cbf1a886e fix: 移除AI智能体初始化中错误的await 2026-03-23 22:16:34 +08:00
jxxghp
17519d5a96 add TAVILY_API_KEYS 2026-03-23 22:13:44 +08:00
jxxghp
faa046eea4 更新 __init__.py 2026-03-23 21:31:46 +08:00
jxxghp
873e3832b6 更新 __init__.py 2026-03-23 20:18:05 +08:00
jxxghp
d4a15d3b53 更新 version.py 2026-03-23 20:02:31 +08:00
jxxghp
6ca6a94631 更新 base.py 2026-03-23 20:01:38 +08:00
jxxghp
61fced0df3 Merge pull request #5611 from wikrin/fix 2026-03-23 19:57:51 +08:00
jxxghp
b2f6ffddee Merge remote-tracking branch 'origin/v2' into v2 2026-03-23 19:52:34 +08:00
jxxghp
c85805b15d feat(agent): Telegram与Agent相互时支持流式输出 2026-03-23 19:52:26 +08:00
Attente
a0838ed9cd fix(media): 修复剧集单集图片刮削 2026-03-23 19:41:48 +08:00
jxxghp
63bbec5db4 更新 __init__.py 2026-03-23 19:18:25 +08:00
jxxghp
4bc67dc816 feat(agent): Telegram与Agent相互时支持流式输出 2026-03-23 19:13:51 +08:00
jxxghp
9620a06552 Merge branch 'v2' of https://github.com/jxxghp/MoviePilot into v2 2026-03-23 17:23:53 +08:00
jxxghp
9b00a5f3f1 refactor: Update agent stream processing to support 'v2' chunk format and prevent emitting empty content. 2026-03-23 17:23:44 +08:00
jxxghp
faa77be843 Merge pull request #5609 from PKC278/v2 2026-03-23 17:18:51 +08:00
PKC278
28f158c479 feat: 重构MediaChain初始化,调整存储链和刮削策略的加载顺序 2026-03-23 17:11:33 +08:00
PKC278
90c3afcfa4 feat: 优化SKILL.md 2026-03-23 15:23:34 +08:00
jxxghp
565e10b6a5 add LLMToolSelectorMiddleware 2026-03-23 08:16:19 +08:00
jxxghp
773ed5e6f7 Merge pull request #5604 from PKC278/v2 2026-03-23 06:57:48 +08:00
PKC278
8351312b2b feat: 优化SKILL.md
feat: 更新 MCP_HIDDEN_TOOLS 列表,对mcp客户端隐藏文件相关工具
2026-03-23 05:13:45 +08:00
Aqr-K
41f53d39a0 Fix agent memory (#5607) 2026-03-23 04:30:46 +08:00
Aqr-K
4873ffda84 fix: bug (#5605) 2026-03-23 03:34:55 +08:00
jxxghp
b79609bb8b Merge pull request #5603 from jxxghp/copilot/add-read-file-tool 2026-03-23 00:34:44 +08:00
copilot-swe-agent[bot]
bdcbb5cce6 feat: add read_file tool for agent with line range and 50KB size limit support
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
Agent-Logs-Url: https://github.com/jxxghp/MoviePilot/sessions/615dcf93-c017-4d3f-a96f-5cdad426b9a4
2026-03-22 16:32:19 +00:00
copilot-swe-agent[bot]
d1503f9df3 Initial plan 2026-03-22 16:29:07 +00:00
jxxghp
210c3234d2 更新 version.py 2026-03-22 23:45:37 +08:00
jxxghp
c13abfdd0d fix:Agent会话时间调整为1天,通过自动压缩控制上下文 2026-03-22 23:41:47 +08:00
jxxghp
30b332ac7e feat: Introduce MemoryMiddleware and PatchToolCallsMiddleware to the agent, and add EditFileTool and WriteFileTool for file manipulation. 2026-03-22 23:35:34 +08:00
jxxghp
7e9c489aeb feat: Enhance agent persona to be cute, playful, and anthropomorphic with increased emoji usage and updated Chinese examples. 2026-03-22 22:07:05 +08:00
jxxghp
5739ca7f97 fix agent bug 2026-03-22 22:02:54 +08:00
jxxghp
e4451c7e6a fix: qqbot wechatbot 模块循环依赖问题 2026-03-22 21:49:57 +08:00
jxxghp
5cded77387 feat(agent): upgrade langchain to v1.0+ 2026-03-22 21:41:12 +08:00
jxxghp
ea4e0dd764 feat(agent): upgrade langchain to v1.0+ 2026-03-22 21:07:45 +08:00
jxxghp
f105357f96 Merge pull request #5602 from PKC278/v2 2026-03-22 07:08:41 +08:00
PKC278
bc2302baeb feat: 优化query_library_exists和query_subscribes工具输出,优化SKILL.md
fix(add_download): 更新torrent_url和description字段的描述,移除错误的添加直链的功能
2026-03-22 01:47:38 +08:00
jxxghp
afcdefbbf3 Merge pull request #5597 from DDSRem-Dev/dev 2026-03-20 21:30:03 +08:00
jxxghp
3ad8557065 Merge pull request #5596 from Aqr-K/fix-restart 2026-03-20 21:29:45 +08:00
Aqr-K
e68d607c9b fix(docker): 优化容器启动、优雅退出和Nginx配置 2026-03-20 20:28:16 +08:00
DDSRem
8e9cf67190 fix(workflows): operations per run 2026-03-20 19:13:05 +08:00
jxxghp
0cb6cd8761 Merge pull request #5594 from PKC278/v2 2026-03-20 12:02:45 +08:00
PKC278
17aa795b3e feat: add_download工具支持添加多个 torrent_url,优化下载任务处理和反馈信息 2026-03-20 11:47:27 +08:00
jxxghp
7d47096e6e Merge pull request #5592 from wikrin/refactor/scraping-switch-to-policy 2026-03-19 22:25:24 +08:00
Attente
48b59df11b refactor(media): 引入配置化刮削策略 2026-03-19 21:25:57 +08:00
jxxghp
a90a3b2445 Merge pull request #5589 from PKC278/v2 2026-03-18 21:33:33 +08:00
PKC278
d18b68d24a feat: 为部分工具添加豆瓣ID支持 2026-03-18 19:36:32 +08:00
PKC278
78c4ec8bfe feat: 将部分逻辑移到后端,简化脚本 2026-03-18 17:48:28 +08:00
PKC278
b50a3b9aae feat: 工具输入输出统一为movie或tv 2026-03-18 17:07:03 +08:00
PKC278
4f3eaa12d5 feat: 更新下载工具和搜索结果工具的描述,添加可选展示过滤选项参数,优化SKILL.md 2026-03-18 16:30:31 +08:00
PKC278
cedb0f565c feat: 优化工具和SKILL.md 2026-03-18 14:27:07 +08:00
PKC278
226432ec7f feat(mcp): add torrent filter workflow and moviepilot cli skill 2026-03-17 17:22:33 +08:00
jxxghp
d93ab0143c Merge pull request #5583 from lclrc/fix 2026-03-16 19:30:46 +08:00
lclrc
3d32d66ab1 Fixes: FetchRssParams in workflow 2026-03-16 15:32:04 +08:00
jxxghp
e814eed047 更新 version.py 2026-03-15 10:09:17 +08:00
jxxghp
96395c1469 feat: 增强插件静态文件API安全性 2026-03-14 21:12:54 +08:00
jxxghp
6065c29891 Revert "Merge pull request #5573 from wikrin/refactor-static-methods-conversion"
This reverts commit b8fc20b981, reversing
changes made to e09cfc6704.
2026-03-14 18:21:31 +08:00
jxxghp
f38cb274e4 Revert "refactor(helper): 将LLMHelper StorageHelper的相关方法改为静态方法,移除实例调用"
This reverts commit 9f381b3c73.
2026-03-14 18:19:47 +08:00
jxxghp
7bfee87cbf Merge pull request #5577 from EkkoG/wechat_bot 2026-03-14 18:02:33 +08:00
jxxghp
2ce2a3754c Merge pull request #5576 from wikrin/refactor-static-methods 2026-03-14 17:59:48 +08:00
EkkoG
510476c214 feat(wechat): add WeChatBot class for intelligent bot integration and enhance WechatModule to support bot mode
- Introduced WeChatBot class for handling intelligent bot functionalities.
- Updated WechatModule to differentiate between traditional and bot modes using WECHAT_MODE configuration.
- Enhanced stop method in WechatModule to gracefully stop client instances.
- Added logic to skip traditional menu initialization for bot mode.
- Updated .gitignore to include .venv directory.
2026-03-14 16:17:39 +08:00
jxxghp
6cd071c84b Merge pull request #5575 from DDSRem-Dev/dev 2026-03-14 14:54:51 +08:00
DDSRem
406e17b3fa fix(docker): locale-gen zh_CN, set LD_PRELOAD in final stage only
fix 858da38680
2026-03-14 14:36:56 +08:00
jxxghp
dd184255ad Merge pull request #5574 from tejasae-afk/fix/set-a-timeout-on-alipan-http-calls 2026-03-14 13:25:09 +08:00
jxxghp
77a0b38081 更新 alipan.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-14 13:25:00 +08:00
Tejas Attarde
14c3d66ce6 perf(modules): set a timeout on alipan HTTP calls 2026-03-14 00:23:45 -04:00
jxxghp
858da38680 feat: Integrate jemalloc for improved memory allocation. 2026-03-14 12:00:12 +08:00
Attente
9f381b3c73 refactor(helper): 将LLMHelper StorageHelper的相关方法改为静态方法,移除实例调用 2026-03-14 10:29:37 +08:00
jxxghp
b8fc20b981 Merge pull request #5573 from wikrin/refactor-static-methods-conversion 2026-03-13 22:53:54 +08:00
Attente
b89825525a refactor(helper): 将DirectoryHelper、RuleHelper和TorrentHelper方法改为静态方法
- 移除不必要的实例化操作,直接使用类方法
2026-03-13 19:50:10 +08:00
jxxghp
e09cfc6704 Merge pull request #5570 from Seed680/v2 2026-03-12 21:54:06 +08:00
jxxghp
0c9c303c60 Merge pull request #5569 from YuF-9468/fix-5567-match-season-episodes-call 2026-03-12 21:53:46 +08:00
noone
3156b43739 bugfix(meta): 添加视频帧率信息解析支持
- 添加自定义格式中关于fps的内容
2026-03-12 14:51:23 +08:00
YuF-9468
591aa990a6 fix(search): call match_season_episodes via class to avoid bound-arg conflict 2026-03-12 09:27:31 +08:00
jxxghp
3be29f36a7 Merge pull request #5564 from DDSRem-Dev/dev 2026-03-11 15:24:46 +08:00
DDSRem
7638db4c3b fix(plugin): return remoteEntry path without API prefix to avoid double prefix 404
- get_plugin_remote_entry returns /plugin/file/... (relative to API root)
- Frontend already prepends API base; adding API_V1_STR caused /api/v1/api/v1/...

Made-with: Cursor
2026-03-11 15:12:40 +08:00
DDSRem
0312a500a6 refactor(plugin): replace deprecated pkg_resources with importlib.metadata
- Use distributions() in __get_installed_packages for installed packages
- Use packaging.requirements.Requirement, drop pkg_resources dependency
- __standardize_pkg_name: normalize dots to underscores (PEP-style)
- Keep max version when multiple distributions exist for same package

Made-with: Cursor
2026-03-11 14:53:15 +08:00
jxxghp
1a88b5355a 更新 requirements.in 2026-03-11 12:23:09 +08:00
jxxghp
3374773de5 更新 version.py 2026-03-11 07:22:09 +08:00
jxxghp
872b5fe3da Merge pull request #5559 from xiaoQQya/develop 2026-03-10 21:01:57 +08:00
xiaoQQya
be15e9871c perf: 优化站点 hhanclub 用户等级与加入时间获取兼容性 2026-03-10 19:42:04 +08:00
jxxghp
024a6a253b Merge pull request #5531 from WongWang/feat-plugin-priority 2026-03-10 12:54:39 +08:00
jxxghp
1af662df7b Merge pull request #5558 from YuF-9468/fix/5483-history-reorganize-event 2026-03-09 22:36:17 +08:00
YuF-9468
b4f64eb593 fix: preserve download context when re-organizing from history 2026-03-09 19:33:49 +08:00
jxxghp
86aa86208c Merge pull request #5557 from eNkru/feature/panda-group 2026-03-09 15:24:07 +08:00
Howard Ju
018e814615 feat(panda): add release group for PandaPT 2026-03-09 20:21:18 +13:00
jxxghp
e4d6e5cfc7 Merge pull request #5556 from YuF-9468/fix/5554-plugin-remote-entry-prefix 2026-03-09 12:02:20 +08:00
YuF-9468
770cd77632 refactor(plugin): build remoteEntry path with posixpath.join 2026-03-09 11:53:28 +08:00
YuF-9468
9f1692b33d fix(plugin): prepend API prefix for plugin remoteEntry URL 2026-03-09 11:41:42 +08:00
jxxghp
6f63e0a5d7 feat: enhance Telegram module with new functionality and improvements. 2026-03-08 09:48:42 +08:00
jxxghp
6a90e2c796 fix ide warnings 2026-03-08 08:32:29 +08:00
jxxghp
23b90ff0f9 remove app.env 2026-03-08 08:25:07 +08:00
jxxghp
dc86af2fa4 Merge pull request #5552 from EkkoG/qqbot 2026-03-08 08:23:53 +08:00
EkkoG
425b822046 feat(qqbot): enhance message sending with Markdown support and image size detection
- Added `use_markdown` parameter to `send_proactive_c2c_message` and `send_proactive_group_message` for Markdown formatting.
- Implemented methods to escape Markdown characters and format messages accordingly.
- Introduced image size detection for Markdown image rendering.
- Updated message sending logic to fallback to plain text if Markdown is unsupported.
2026-03-07 23:51:30 +08:00
EkkoG
65c18b1d52 feat(qqbot): implement QQ Bot notification module with API and WebSocket support
- Added QQ Bot notification module to facilitate proactive message sending and message reception via Gateway.
- Implemented API functions for sending C2C and group messages.
- Established WebSocket client for real-time message handling.
- Updated requirements to include websocket-client dependency.
- Enhanced schemas to support QQ channel capabilities and notification configurations.
2026-03-07 23:21:07 +08:00
jxxghp
1bddf3daa7 Merge pull request #5550 from wumode/fix_openlist 2026-03-07 08:21:11 +08:00
wumode
600b6af876 fix(openlist): transfer queue blocking 2026-03-06 23:21:43 +08:00
jxxghp
4bdf16331d Merge pull request #5546 from ziwiwiz/fix-docker-proxy-unauthorized-access 2026-03-06 13:19:34 +08:00
ziwiwiz
87cbda0528 fix(docker): optimize docker proxy listener config for better network isolation 2026-03-06 01:33:18 +08:00
jxxghp
9897941bf9 Merge pull request #5544 from YuF-9468/fix-issue-5495-tnode-json-guard 2026-03-05 18:08:24 +08:00
YuF-9468
31938812d0 chore: add warning logs for invalid tnode seeding payload 2026-03-05 09:35:25 +08:00
YuF-9468
19d879d3f6 fix(parser): guard invalid tnode seeding json response 2026-03-05 09:21:16 +08:00
jxxghp
cc41036c63 Merge pull request #5537 from jxxghp/copilot/optimize-message-logic 2026-03-03 20:45:00 +08:00
copilot-swe-agent[bot]
a9f2b40529 test: extend media-title detection coverage and cleanup
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-03-03 12:20:54 +00:00
copilot-swe-agent[bot]
86000ea19a feat: improve user message media-title detection
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-03-03 12:14:25 +00:00
copilot-swe-agent[bot]
0422c3b9e7 Initial plan 2026-03-03 12:08:33 +00:00
jxxghp
64c8bd5b5a Merge pull request #5535 from Seed680/v2 2026-03-03 20:00:31 +08:00
jxxghp
a7eba2c5fc Merge pull request #5534 from YuF-9468/fix-workflow-rating-float 2026-03-03 19:59:04 +08:00
YuF-9468
2b7753e43e workflow: handle zero vote threshold explicitly 2026-03-03 15:41:27 +08:00
noone
47c1e5b5b8 Merge remote-tracking branch 'origin/v2' into v2 2026-03-03 14:31:24 +08:00
noone
14ee97def0 feat(meta): 添加视频帧率信息解析支持
- 在MetaBase基类中新增fps属性用于存储帧率信息
- 实现MetaVideo中帧率信息的识别和解析逻辑
- 为MetaAnime添加帧率提取功能,与MetaVideo保持一致
- 更新测试用例以验证帧率信息的正确解析
- 在元数据测试数据中增加fps字段的预期值
2026-03-03 14:31:12 +08:00
Seed680
92e262f732 Merge branch 'jxxghp:v2' into v2 2026-03-03 14:13:07 +08:00
noone
c46880b701 feat(meta): 添加视频帧率信息解析支持
- 在MetaBase基类中新增fps属性用于存储帧率信息
- 实现MetaVideo中帧率信息的识别和解析逻辑
- 为MetaAnime添加帧率提取功能,与MetaVideo保持一致
- 更新测试用例以验证帧率信息的正确解析
- 在元数据测试数据中增加fps字段的预期值
2026-03-03 14:12:06 +08:00
YuF-9468
473e9b9300 workflow: allow decimal rating in filter medias 2026-03-03 13:56:24 +08:00
Castell
28945ef153 refactor: 将 download.py 中重复的媒体识别模式选择逻辑封装进选择器函数 2026-03-03 01:58:49 +08:00
Castell
b6b5d9f9c4 refactor: 将重复的媒体识别模式选择逻辑封装进选择器函数 2026-03-03 01:33:44 +08:00
Castell
ba5de1ab31 fix: 修复异步函数调用少写 await 关键字的错误 2026-03-03 00:37:55 +08:00
Castell
002ebeaade refactor: 简化媒体识别模式选择逻辑中的 if/else 结构 2026-03-03 00:21:55 +08:00
Castell
894756000c feat: 新增优先使用插件识别的功能 2026-03-02 20:58:10 +08:00
jxxghp
cdb178c503 Merge pull request #5530 from cddjr/bugfix/season-regex-capture-group 2026-03-02 12:07:37 +08:00
大虾
7c48cafc71 Update app/core/meta/metavideo.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-03-02 11:47:47 +08:00
景大侠
74d4592238 fix(meta): 修复正则表达式以正确匹配 Sxx 季信息格式 2026-03-02 11:35:41 +08:00
jxxghp
0044dd104e 更新 version.py 2026-03-02 07:04:49 +08:00
jxxghp
05041e2eae Merge pull request #5526 from baozaodetudou/orv2 2026-03-01 12:02:49 +08:00
doumao
78908f216d Merge branch 'v2' of github.com:jxxghp/MoviePilot into orv2 2026-02-28 22:58:09 +08:00
doumao
efc68ae701 fix: 绿联接口支持可配置SSL证书校验 2026-02-28 22:55:47 +08:00
jxxghp
e9340a8b4b Merge pull request #5525 from baozaodetudou/orv2 2026-02-28 22:50:10 +08:00
逗猫
66e199d516 Merge pull request #1 from baozaodetudou/v2
perf: 使用deque优化绿联媒体库遍历队列性能
2026-02-28 22:15:39 +08:00
doumao
6151d8a787 perf: 使用deque优化绿联媒体库遍历队列性能 2026-02-28 22:13:54 +08:00
doumao
296261da8a feat: 完成绿联影视接入并补齐扫描模式与统计展示 2026-02-28 21:58:35 +08:00
doumao
383371dd6f Merge branch 'v2' of github.com:jxxghp/MoviePilot into orv2 2026-02-28 21:57:45 +08:00
jxxghp
bb8c026bda Merge pull request #5523 from YuF-9468/fix-issue-5508-manual-transfer-auto-type 2026-02-28 17:18:23 +08:00
doumao
344993dd6f 新增绿联接口加解密工具与单元测试 2026-02-28 15:35:27 +08:00
YuF-bot
ffb048c314 refactor(transfer): narrow manual type parse exception to ValueError 2026-02-28 13:44:06 +08:00
jxxghp
3eef9b8faa Merge pull request #5522 from YuF-9468/fix-issue-5461-filemanager-test-optional-library 2026-02-28 13:31:09 +08:00
YuF-9468
5704bb646b fix(transfer): treat auto type as unspecified in manual transfer 2026-02-28 13:29:08 +08:00
YuF-9468
fbc684b3a7 fix(filemanager): skip library path check when transfer is disabled 2026-02-28 12:58:53 +08:00
jxxghp
6529b2a9c3 Merge pull request #5521 from YuF-9468/fix-issue-5463-agent-sites-list-parse 2026-02-28 12:31:54 +08:00
YuF-9468
a1701e2edf fix(agent): accept string-form sites list in search_torrents input 2026-02-28 12:30:12 +08:00
jxxghp
eba6391de7 Merge pull request #5520 from YuF-9468/fix-issue-5211-telegram-username-fallback 2026-02-28 12:17:33 +08:00
jxxghp
9f2c3c9688 Merge pull request #5517 from wumode/fix-progress-displaying 2026-02-28 12:16:13 +08:00
YuF-bot
57f5a19d0c fix(message): fallback Telegram username to string userid when absent 2026-02-28 11:10:15 +08:00
wumode
c8d53c6964 fix(ProgressHelper): progress displaying 2026-02-27 16:13:34 +08:00
jxxghp
643cda1abe Merge pull request #5516 from shawnlu96/fix/alipan-snapshot-monitoring 2026-02-27 07:07:31 +08:00
Shawn Lu
03d118a73a fix: 修复阿里云盘目录监控快照无法检测文件的问题
1. 为阿里云盘添加 ALIPAN_SNAPSHOT_CHECK_FOLDER_MODTIME 配置(默认 False)
   - 阿里云盘目录的 updated_at 不会随子文件变更而更新,导致增量快照
     始终跳过目录,快照结果为空
   - 与 Rclone/Alist 保持一致的配置模式

2. 移除 snapshot() 中文件级 modify_time 过滤
   - 原逻辑:仅包含 modify_time > last_snapshot_time 的文件
   - 问题:首次快照建立基准后,save_snapshot 将 timestamp 设为
     max(modify_times),后续快照中未变更的文件因 modify_time 不大于
     timestamp 而被排除,导致 compare_snapshots 无法检测到任何变化
   - 此外当 last_snapshot_time 为 None 时,比较会触发 TypeError
     并被静默捕获
   - 修复:始终包含所有遍历到的文件,由 compare_snapshots 负责变化检测
     目录级优化仍由 snapshot_check_folder_modtime 控制

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 23:43:21 +08:00
jxxghp
51dd7f5c17 Merge pull request #5512 from cddjr/bugfix/issue-5501 2026-02-25 21:13:35 +08:00
jxxghp
af7e1e7a3c Merge pull request #5509 from xiaoQQya/develop 2026-02-25 21:13:00 +08:00
大虾
ea5d855bc3 Update app/helper/directory.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-02-25 20:21:37 +08:00
景大侠
5f74367cd6 fix: 修复电视剧刮削问题 2026-02-25 20:18:05 +08:00
jxxghp
26e41e1c14 更新 version.py 2026-02-24 19:25:20 +08:00
xiaoQQya
1bb2b50043 fix: 修复站点 hhanclub 用户等级与加入时间不显示的问题 2026-02-23 21:44:23 +08:00
jxxghp
7bdb629f03 Merge pull request #5505 from DDSRem-Dev/rtorrent 2026-02-22 16:10:39 +08:00
jxxghp
fd92f986da Merge pull request #5504 from DDSRem-Dev/fix_smb_alipan 2026-02-22 16:10:08 +08:00
DDSRem
69a1207102 chore(rtorrent): formatting code 2026-02-22 13:42:27 +08:00
DDSRem
def652c768 fix(rtorrent): address code review feedback
- Replace direct _proxy access in transfer_completed with set_torrents_tag(overwrite=True) for proper encapsulation and error logging
- Optimize episode collection by using set accumulation instead of repeated list-set conversions in loop
- Fix type hint for hashs parameter in transfer_completed (str -> Union[str, list])
- Add overwrite parameter to set_torrents_tag to support tag replacement

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 13:40:15 +08:00
DDSRem
c35faf5356 feat(downloader): add rTorrent downloader support
Implement rTorrent downloader module via XML-RPC protocol, supporting both HTTP (nginx/ruTorrent proxy) and SCGI connection modes. Add RtorrentModule implementing _ModuleBase and _DownloaderBase interfaces with no extra dependencies.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 13:12:22 +08:00
jxxghp
0615a33206 Merge pull request #5503 from DDSRem-Dev/fix_u115 2026-02-22 13:00:16 +08:00
DDSRem
e77530bdc5 fix(storages): download directory concatenation error 2026-02-22 12:35:27 +08:00
DDSRem
8c62df63cc fix(u115): download directory concatenation error
fix: https://github.com/jxxghp/MoviePilot/issues/5429
2026-02-22 12:22:58 +08:00
jxxghp
bd36eade77 Merge pull request #5502 from DDSRem-Dev/dev 2026-02-22 12:17:33 +08:00
DDSRem
d2c023081a fix(openList): openList file upload and retrieval errors
fix https://github.com/jxxghp/MoviePilot/issues/5369
fix https://github.com/jxxghp/MoviePilot/issues/5038
2026-02-22 12:05:14 +08:00
jxxghp
63d0850b38 Merge pull request #5498 from cddjr/feat/recommend_manual_force_refresh 2026-02-13 18:39:21 +08:00
景大侠
c86659428f feat(recommend): 手动执行推荐缓存服务时强刷数据 2026-02-13 18:17:42 +08:00
jxxghp
bf7cc6caf0 Merge pull request #5497 from cddjr/bugfix/glitchtip_9684 2026-02-13 17:09:04 +08:00
jxxghp
26b8be6041 Merge pull request #5496 from cddjr/bugfix/issue_5456 2026-02-13 17:08:21 +08:00
景大侠
f978f9196f fix(transfer): 修复移动模式下过早删除种子的问题
- 撤回提交 4502a9c 的部分改动
2026-02-13 13:28:05 +08:00
景大侠
75cb8d2a3c fix(torrents): 修复刷新站点资源时因缺失种子链接导致的 'Failed to exists key: None' 错误 2026-02-12 17:45:15 +08:00
jxxghp
17a21ed707 更新 version.py 2026-02-12 07:09:45 +08:00
jxxghp
f390647139 fix(site): 更新站点信息时同步更新domain域名 2026-02-12 06:59:13 +08:00
jxxghp
aacd91e196 Merge pull request #5487 from cddjr/bugfix/issue_5242 2026-02-11 16:02:54 +08:00
景大侠
258171c9c4 fix(telegram): 修复通知标题含特殊符号时异常显示**符号 2026-02-11 09:20:50 +08:00
jxxghp
812c5873aa Merge pull request #5486 from cddjr/feat/shared-sync-async-cache 2026-02-10 22:11:42 +08:00
景大侠
4c3d47f1f0 feat(cache): 同步/异步函数可共享缓存
- 缓存键支持自定义命名,使异步与同步函数可共享缓存结果
- 内存缓存改为类变量,实现多个cache装饰器共享同一缓存空间
- 重构AsyncMemoryBackend,减少重复代码
- 补齐部分模块的缓存清理功能
2026-02-10 18:46:49 +08:00
jxxghp
ba7b6ba869 Merge pull request #5485 from yubanmeiqin9048/patch-2 2026-02-10 17:41:51 +08:00
yubanmeiqin9048
d0471ae512 fix: 修复目标目录无视频文件时转移字幕和音频触发目录删除 2026-02-10 14:10:42 +08:00
jxxghp
636c4be9fb 更新 version.py 2026-02-07 08:13:43 +08:00
jxxghp
6bec765a9d Merge pull request #5474 from jxxghp/copilot/optimize-file-move-implementation 2026-02-06 22:20:11 +08:00
copilot-swe-agent[bot]
d61d16ccc4 Restore the optimization - accidentally reverted in previous commit
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-02-06 14:15:29 +00:00
copilot-swe-agent[bot]
f2a5715b24 Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com> 2026-02-06 14:11:15 +00:00
copilot-swe-agent[bot]
c064c3781f Optimize SystemUtils.move to avoid triggering directory monitoring
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-02-06 14:03:03 +00:00
copilot-swe-agent[bot]
bb4dffe2a4 Initial plan 2026-02-06 13:59:59 +00:00
jxxghp
37cf3eeef3 Merge pull request #5473 from cddjr/feat_transfer_files_filter 2026-02-06 21:04:52 +08:00
景大侠
40395b2999 feat: 在构造待整理文件列表时引入过滤逻辑以简化后续处理 2026-02-06 20:56:26 +08:00
景大侠
32afe6445f fix: 整理成功事件缺少历史记录ID 2026-02-06 20:33:13 +08:00
jxxghp
793a991913 Merge remote-tracking branch 'origin/v2' into v2 2026-02-05 14:16:55 +08:00
jxxghp
d278224ff1 fix:优化第三方插件存储类型的检测提示 2026-02-05 14:16:50 +08:00
jxxghp
9b4d0ce6a8 Merge pull request #5466 from DDSRem-Dev/dev 2026-02-05 06:56:25 +08:00
DDSRem
a1829fe590 feat: u115 global rate limiting strategy 2026-02-04 23:24:14 +08:00
jxxghp
2b2b39365c Merge pull request #5464 from ChanningHe/enhance/discord 2026-02-04 18:08:38 +08:00
ChanningHe
1147930f3f fix: [slack&discord&telegram] handle special characters in config names 2026-02-04 14:09:40 +09:00
ChanningHe
636f338ed7 enhance: [discord] add _user_chat_mapping to chat in channel 2026-02-04 13:42:33 +09:00
ChanningHe
72365d00b4 enhance: discord debug information 2026-02-04 12:54:17 +09:00
jxxghp
19d8086732 Merge pull request #5460 from cddjr/fix_download_hash_overridden 2026-02-03 21:23:04 +08:00
大虾
30488418e5 修复 整理时download_hash参数被覆盖
导致后续文件均识别成同一个媒体信息
2026-02-03 18:59:32 +08:00
jxxghp
2f0badd74a Merge pull request #5457 from cddjr/fix_5449 2026-02-02 23:45:07 +08:00
jxxghp
6045b0579b Merge pull request #5455 from cddjr/fix_transfer_result_incorrect 2026-02-02 23:44:32 +08:00
景大侠
498f1fec74 修复 整理视频可能导致误删字幕及音轨 2026-02-02 23:18:46 +08:00
景大侠
f6a541f2b9 修复 覆盖整理失败时误报成功 2026-02-02 21:50:35 +08:00
jxxghp
8ce78eabca 更新 version.py 2026-02-02 18:44:30 +08:00
jxxghp
2c34c5309f Merge pull request #5454 from CHANTXU64/v2 2026-02-02 18:02:45 +08:00
jxxghp
77e680168a Merge pull request #5452 from 0honus0/v2 2026-02-02 17:22:00 +08:00
jxxghp
8a7e59742f Merge pull request #5451 from cddjr/fix_specials_season 2026-02-02 17:21:29 +08:00
jxxghp
42bac14770 Merge pull request #5450 from CHANTXU64/v2 2026-02-02 17:20:40 +08:00
CHANTXU64
8323834483 feat: 优化RSS订阅和网页抓取中发布日期(PubDate)的获取兼容性
- app/helper/rss.py: 优化RSS解析,支持带命名空间的日期标签(如 pubDate/published/updated)。
- app/modules/indexer/spider/__init__.py: 优化网页抓取,增加日期格式校验并对非标准格式进行自动归一化。
2026-02-02 16:52:04 +08:00
景大侠
1751caef62 fix: 补充几处season的判空 2026-02-02 15:01:12 +08:00
0honus0
d622d1474d 根据意见增加尾部逗号 2026-02-02 07:00:57 +00:00
0honus0
f28be2e7de 增加登录按钮xpath支持nicept网站 2026-02-02 06:52:48 +00:00
jxxghp
17773913ae fix: 统一了数据库查询中 season 参数的非空判断逻辑,以正确处理 season=0 的情况。 2026-02-02 14:23:51 +08:00
jxxghp
d469c2d3f9 refactor: 统一将布尔判断 if var:if not var: 更改为显式的 if var is not None:if var is None: 以正确处理 None 值。 2026-02-02 13:49:32 +08:00
CHANTXU64
4e74d32882 Fix: TMDB 剧集详情页不显示第 0 季(特别篇) #5444 2026-02-02 10:28:22 +08:00
jxxghp
7b8cd37a9b feat(transfer): enhance job removal methods for thread safety and strict checks 2026-02-01 16:58:32 +08:00
jxxghp
eda306d726 Merge pull request #5448 from cddjr/feat_japanese_subtitles 2026-02-01 16:25:56 +08:00
景大侠
94f3b1fe84 feat: 支持整理日语字幕 2026-02-01 16:04:22 +08:00
jxxghp
c50e3ba293 Merge pull request #5445 from jxxghp/copilot/analyze-task-loss-reason 2026-02-01 08:42:17 +08:00
copilot-swe-agent[bot]
eff7818912 Improve documentation and fix validation bug in add_task
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-31 16:44:01 +00:00
copilot-swe-agent[bot]
270bcff8f3 Fix task loss issue in do_transfer multi-threading batch adding
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-31 16:38:55 +00:00
copilot-swe-agent[bot]
e04963c2dc Initial plan 2026-01-31 16:33:59 +00:00
jxxghp
f369967c91 更新 version.py 2026-01-29 22:32:03 +08:00
jxxghp
cd982c5526 Merge pull request #5439 from DDSRem-Dev/dev 2026-01-29 22:30:28 +08:00
jxxghp
16e03c9d37 Merge pull request #5438 from cddjr/fix_scrape_follow_tmdb 2026-01-29 22:29:06 +08:00
DDSRem
d38b1f5364 feat: u115 support oauth 2026-01-29 22:14:10 +08:00
景大侠
f57ba4d05e 修复 整理时可能误跟随TMDB变化的问题 2026-01-29 15:04:42 +08:00
jxxghp
172eeaafcf 更新 version.py 2026-01-27 18:07:55 +08:00
jxxghp
3115ed28b2 fix: 历史记录删除源文件后,不在订阅的文件列表中显示 2026-01-26 21:47:26 +08:00
jxxghp
d8dc53805c feat(transfer): 整理事件增加历史记录ID 2026-01-26 21:29:05 +08:00
jxxghp
7218d10e1b feat(transfer): 拆分字幕和音频整理事件 2026-01-26 19:33:50 +08:00
jxxghp
89bf85f501 Merge pull request #5425 from xiaoQQya/develop 2026-01-26 18:41:42 +08:00
jxxghp
8334a468d0 feat(category): Add API endpoints for retrieving and saving category configuration 2026-01-26 12:53:26 +08:00
jxxghp
3da80ed077 Merge pull request #5423 from jxxghp/copilot/update-category-helper-integration 2026-01-26 12:35:05 +08:00
copilot-swe-agent[bot]
2883ccbe87 Move category methods to ChainBase and use consistent naming
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-26 04:32:11 +00:00
copilot-swe-agent[bot]
5d3443fee4 Use ruamel.yaml consistently in CategoryHelper
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-26 04:10:15 +00:00
copilot-swe-agent[bot]
27756a53db Implement proper architecture: module->chain->API with single CategoryHelper
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-26 04:07:56 +00:00
copilot-swe-agent[bot]
71cde6661d Improve comments for clarity
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-25 10:08:13 +00:00
copilot-swe-agent[bot]
a857337b31 Fix architecture - restore helper layer and use ModuleManager for reload trigger
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-25 10:06:01 +00:00
copilot-swe-agent[bot]
4ee21ffae4 Address code review feedback - use ruamel.yaml consistently and fix typo
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-25 09:58:28 +00:00
copilot-swe-agent[bot]
d8399f7e85 Consolidate CategoryHelper classes and add reload trigger
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-25 09:56:11 +00:00
copilot-swe-agent[bot]
574ac8d32f Initial plan 2026-01-25 09:52:31 +00:00
jxxghp
a2611bfa7d feat: Add search_imdbid to subscriptions and improve error message propagation and handling for existing subscriptions. 2026-01-25 14:57:46 +08:00
xiaoQQya
853badb76f fix: 更新站点 Rousi Pro 获取未读消息接口 2026-01-25 14:36:22 +08:00
jxxghp
5d69e1d2a5 Merge pull request #5419 from wikrin/subscribe-source-query-enhancement 2026-01-25 14:04:42 +08:00
jxxghp
6494f28bdb Fix: Remove isolated ToolMessage instances after message trimming to prevent OpenAI errors. 2026-01-25 13:42:29 +08:00
Attente
f55916bda2 feat(transfer): 支持按条件查询订阅获取自定义识别词用于文件转移 2026-01-25 11:34:03 +08:00
jxxghp
04691ee197 Merge remote-tracking branch 'origin/v2' into v2 2026-01-25 09:39:59 +08:00
jxxghp
2ac0e564e1 feat(category):新增二级分类维护API 2026-01-25 09:39:48 +08:00
jxxghp
6072a29a20 Merge pull request #5418 from wikrin/CNSUB-filter-rules-update 2026-01-25 08:17:20 +08:00
Attente
8658942385 feat(filter): 添加配置监听和改进中字过滤规则 2026-01-25 01:06:50 +08:00
jxxghp
cc4859950c Merge remote-tracking branch 'origin/v2' into v2 2026-01-24 19:24:22 +08:00
jxxghp
23b81ad6f1 feat(config):完善默认插件库 2026-01-24 19:24:15 +08:00
jxxghp
e3b9dca5c0 Merge pull request #5417 from cddjr/fix_u115_create_folder
fix(u115): 创建目录误报失败
2026-01-24 19:14:40 +08:00
景大侠
a2359a1ad2 fix(u115): 创建目录误报失败
- 解析响应时忽略20004错误码
- 根目录创建目录会报错ValueError
2026-01-24 17:48:53 +08:00
jxxghp
cb875b1b34 更新 version.py 2026-01-24 12:04:54 +08:00
jxxghp
b92a85b4bc Merge pull request #5415 from cddjr/fix_bluray_scrape 2026-01-24 11:43:44 +08:00
景大侠
8c7dd6bab2 修复 原盘目录不刮削 2026-01-24 11:42:00 +08:00
景大侠
aad7df64d7 简化原盘大小计算代码 2026-01-24 11:29:30 +08:00
jxxghp
8474342007 feat(agent):上下文超长时自动摘要 2026-01-24 11:24:59 +08:00
jxxghp
61ccb4be65 feat(agent): 新增命令行工具 2026-01-24 11:10:15 +08:00
jxxghp
1c6f69707c fix 增加模块异常traceback打印 2026-01-24 11:00:24 +08:00
jxxghp
e08e8c482a Merge pull request #5414 from jxxghp/copilot/fix-file-organization-error 2026-01-24 10:49:19 +08:00
copilot-swe-agent[bot]
548c1d2cab Add null check for schema access in IndexerModule
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-24 02:26:55 +00:00
copilot-swe-agent[bot]
5a071bf3d1 Add null check for schema.value access in FileManagerModule
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-24 02:25:55 +00:00
copilot-swe-agent[bot]
1bffcbd947 Initial plan 2026-01-24 02:22:25 +00:00
jxxghp
274a36a83a 更新 config.py 2026-01-24 10:04:37 +08:00
jxxghp
ec40f36114 fix(agent):修复智能体工具调用,优化媒体库查询工具 2026-01-24 09:46:19 +08:00
jxxghp
af19f274a7 Merge pull request #5413 from jxxghp/copilot/fix-runnable-lambda-error 2026-01-24 08:38:24 +08:00
copilot-swe-agent[bot]
2316004194 Fix 'RunnableLambda' object is not callable error by wrapping validated_trimmer
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-24 00:35:59 +00:00
copilot-swe-agent[bot]
98762198ef Initial plan 2026-01-24 00:33:35 +00:00
jxxghp
1469de22a4 Merge pull request #5412 from jxxghp/copilot/translate-comments-to-chinese 2026-01-24 08:27:11 +08:00
copilot-swe-agent[bot]
1e687f960a Translate English comments to Chinese in agent/__init__.py
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-24 00:25:21 +00:00
copilot-swe-agent[bot]
7f01b835fd Initial plan 2026-01-24 00:22:19 +00:00
jxxghp
e46b6c5c01 Merge pull request #5411 from jxxghp/copilot/fix-tool-call-exception-handling 2026-01-24 08:20:51 +08:00
copilot-swe-agent[bot]
74226ad8df Improve error message to include exception type for better debugging
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-24 00:18:43 +00:00
copilot-swe-agent[bot]
f8ae7be539 Fix: Ensure tool exceptions are stored in memory to maintain message chain integrity
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-24 00:18:06 +00:00
copilot-swe-agent[bot]
37b16e380d Initial plan 2026-01-24 00:14:13 +00:00
jxxghp
9ea3e9f652 Merge pull request #5409 from jxxghp/copilot/fix-agent-execution-error 2026-01-24 08:12:39 +08:00
copilot-swe-agent[bot]
54422b5181 Final refinements: fix falsy value handling and add warning for extra ToolMessages
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-24 00:10:00 +00:00
copilot-swe-agent[bot]
712995dcf3 Address code review feedback: fix ToolCall handling and add orphaned message filtering
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-24 00:08:25 +00:00
jxxghp
c2767b0fd6 Merge pull request #5410 from jxxghp/copilot/fix-media-exists-error 2026-01-24 08:08:03 +08:00
copilot-swe-agent[bot]
179cc61f65 Fix tool call integrity validation to skip orphaned ToolMessages
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-24 00:05:21 +00:00
copilot-swe-agent[bot]
f3b910d55a Fix AttributeError when mediainfo.type is None
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-24 00:04:02 +00:00
copilot-swe-agent[bot]
f4157b52ea Fix agent tool_calls integrity validation
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-24 00:02:47 +00:00
copilot-swe-agent[bot]
79710310ce Initial plan 2026-01-24 00:00:31 +00:00
copilot-swe-agent[bot]
3412498438 Initial plan 2026-01-23 23:57:27 +00:00
jxxghp
b896b07a08 fix search_web tool 2026-01-24 07:39:07 +08:00
jxxghp
379bff0622 Merge pull request #5407 from cddjr/fix_db 2026-01-24 06:45:54 +08:00
jxxghp
474f47aa9f Merge pull request #5406 from cddjr/fix_transfer 2026-01-24 06:45:10 +08:00
jxxghp
f1e26a4133 Merge pull request #5405 from cddjr/fix_modify_time_comparison 2026-01-24 06:44:05 +08:00
jxxghp
e37f881207 Merge pull request #5404 from jxxghp/copilot/reimplement-network-search-tool 2026-01-24 06:39:56 +08:00
大虾
306c0b707b Update database/versions/41ef1dd7467c_2_2_2.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-01-24 02:53:14 +08:00
景大侠
08c448ee30 修复 迁移PG后可能卡启动的问题 2026-01-24 02:49:54 +08:00
景大侠
1532014067 修复 多下载器返回相同种子造成的重复整理 2026-01-24 01:41:48 +08:00
景大侠
fa9f604af9 修复 入库通知不显示集数
因过早清理作业导致
2026-01-24 01:17:23 +08:00
景大侠
3b3d0d6539 修复 文件列表接口中空值时间戳的比较逻辑 2026-01-23 23:52:43 +08:00
copilot-swe-agent[bot]
9641d33040 Fix generator handling and update error message to reference requirements.in
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-23 15:23:52 +00:00
copilot-swe-agent[bot]
eca339d107 Address code review comments: improve code organization and use modern asyncio
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-23 15:22:45 +00:00
copilot-swe-agent[bot]
ca18705d88 Reimplemented SearchWebTool using duckduckgo-search library
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-23 15:20:06 +00:00
copilot-swe-agent[bot]
8f17b52466 Initial plan 2026-01-23 15:16:09 +00:00
jxxghp
8cf84e722b fix agent error message 2026-01-23 22:50:59 +08:00
jxxghp
7c4d736b54 feat:Agent上下文裁剪 2026-01-23 22:47:18 +08:00
jxxghp
1b3ae6ab25 fix 下载器整理标签设置 2026-01-23 18:10:59 +08:00
jxxghp
a4ad08136e 更新 version.py 2026-01-23 14:33:41 +08:00
jxxghp
df5e7997c5 Merge pull request #5401 from jxxghp/copilot/check-jobview-logic 2026-01-23 07:21:46 +08:00
copilot-swe-agent[bot]
b2cb3768c1 Fix remove_job to use __get_id for consistent job removal
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-22 14:38:33 +00:00
copilot-swe-agent[bot]
fa169c5cd3 Initial plan 2026-01-22 14:34:18 +00:00
jxxghp
bbb3975b67 更新 transfer.py 2026-01-22 22:31:52 +08:00
jxxghp
4502a9c4fa fix:优化移动模式删除逻辑 2026-01-22 22:15:40 +08:00
jxxghp
86905a2670 Merge pull request #5399 from cddjr/fix_downloader_monitor 2026-01-22 21:41:25 +08:00
景大侠
b1e60a4867 修复 下载器监控 2026-01-22 21:34:50 +08:00
jxxghp
1efe3324fb fix:优化设置种子状态标签的时机 2026-01-22 08:24:23 +08:00
jxxghp
55c1e37d39 更新 query_subscribes.py 2026-01-22 08:05:41 +08:00
jxxghp
7fa700317c 更新 update_subscribe.py 2026-01-22 08:03:48 +08:00
jxxghp
bbe831a57c 优化 transfer.py 中任务处理逻辑,增强错误信息反馈 2026-01-21 23:55:20 +08:00
jxxghp
90c86c056c fix all_tasks 2026-01-21 23:30:39 +08:00
jxxghp
36f22a28df fix 完成状态计算 2026-01-21 23:23:37 +08:00
jxxghp
ac03c51e2c 更新 transfer.py 2026-01-21 23:06:29 +08:00
jxxghp
bd9e92f705 更新 transfer.py 2026-01-21 22:59:30 +08:00
jxxghp
281eff5eb2 更新 version.py 2026-01-21 22:54:31 +08:00
jxxghp
abbd2253ad fix deadlock 2026-01-21 22:46:04 +08:00
jxxghp
46466624ae fix:优化下载器整理控制逻辑 2026-01-21 22:21:17 +08:00
jxxghp
0ba8d51b2a fix:优化下载器整理 2026-01-21 21:31:55 +08:00
jxxghp
a1408ee18f feat:TRANSFER_THREADS 变更监听 2026-01-21 20:46:34 +08:00
jxxghp
58030bbcff fix #5392 2026-01-21 20:12:05 +08:00
jxxghp
e1b3e6ef01 fix:只有媒体文件整完成才触发事件,以保持与历史一致 2026-01-21 20:07:18 +08:00
jxxghp
298a6ba8ab 更新 update_subscribe.py 2026-01-21 19:36:12 +08:00
jxxghp
e5bf47629f 更新 config.py 2026-01-21 19:13:36 +08:00
jxxghp
ea29ee9f66 Merge pull request #5390 from xiaoQQya/develop 2026-01-21 18:39:06 +08:00
jxxghp
868c2254de v2.9.5 2026-01-21 17:59:52 +08:00
jxxghp
567522c87a fix:统一调整文件类型支持 2026-01-21 17:59:18 +08:00
jxxghp
25fd47f57b Merge pull request #5389 from hyuan280/v2 2026-01-21 17:22:27 +08:00
hyuan280
f89d6342d1 fix: 修复Cookie解码二进制数据导致请求发送时UnicodeEncodeError 2026-01-21 16:36:28 +08:00
jxxghp
b02affdea3 Merge pull request #5388 from cddjr/fix_tmdb_img_url 2026-01-21 13:24:39 +08:00
景大侠
6e5ade943b 修复 订阅无法查看文件列表的问题
TMDB图片路径参数增加空值检查
2026-01-21 12:47:39 +08:00
jxxghp
a6ed0c0d00 fix:优化transhandler线程安全 2026-01-21 08:42:57 +08:00
jxxghp
68402aadd7 fix:去除文件操作全局锁 2026-01-21 08:31:51 +08:00
jxxghp
85cacd447b feat: 为文件整理服务引入多线程处理并优化进度管理。 2026-01-21 08:16:02 +08:00
xiaoQQya
11262b321a fix(rousi pro): 修复 Rousi Pro 站点未读消息未推送通知的问题 2026-01-20 22:12:31 +08:00
jxxghp
bf290f063d Merge pull request #5386 from PKC278/v2 2026-01-20 22:09:02 +08:00
PKC278
7ac0fbaf76 fix(otp): 修正 OTP 关闭逻辑 2026-01-20 19:53:59 +08:00
PKC278
7489c76722 feat(passkey): 允许在未开启 OTP 时注册通行密钥 2026-01-20 19:35:36 +08:00
jxxghp
bcdf1b6efe 更新 transhandler.py 2026-01-20 15:29:28 +08:00
jxxghp
8a9dbe212c Merge pull request #5385 from cddjr/feature_optimize_transfer 2026-01-20 15:25:38 +08:00
景大侠
16bd71a6cb 优化整理代码效率、减少额外递归 2026-01-20 14:38:41 +08:00
jxxghp
71caad0655 feat:优化蓝光目录判断,减少目录遍历 2026-01-20 13:38:52 +08:00
jxxghp
2c62ffe34a feat:优化字幕和音频文件整理方式 2026-01-20 13:24:35 +08:00
jxxghp
3450a89880 Merge pull request #5383 from jxxghp/copilot/merge-agent-and-execution-messages 2026-01-20 00:03:23 +08:00
copilot-swe-agent[bot]
a081a69bbe Simplify message merging logic using list join
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-19 16:00:36 +00:00
copilot-swe-agent[bot]
271d1d23d5 Merge agent and tool execution messages into a single message
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-19 15:59:21 +00:00
copilot-swe-agent[bot]
605aba1a3c Initial plan 2026-01-19 15:55:13 +00:00
jxxghp
be3c2b4c7c Merge pull request #5382 from jxxghp/copilot/fix-tool-call-id-error 2026-01-19 21:36:09 +08:00
copilot-swe-agent[bot]
08eb32d7bd Fix isinstance syntax error for int/float type checking
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-19 13:33:01 +00:00
copilot-swe-agent[bot]
2b9cda15e4 Fix tool_call_id error by adding metadata to tool_result and using it in ToolMessage
Co-authored-by: jxxghp <51039935+jxxghp@users.noreply.github.com>
2026-01-19 13:31:43 +00:00
copilot-swe-agent[bot]
f6055b290a Initial plan 2026-01-19 13:28:07 +00:00
jxxghp
ec665e05e4 Merge pull request #5379 from Pollo3470/v2 2026-01-19 21:17:53 +08:00
jxxghp
2b6d7205ec Merge pull request #5378 from cddjr/fix_tv_dir_scrape 2026-01-19 17:47:11 +08:00
Pollo
41381a920c fix: 修复订阅自定义识别词在整理时不生效的问题
问题:订阅中添加的自定义识别词(特别是集数偏移)在下载时正常生效,
但在下载完成整理时没有生效。

根因:下载历史中未保存识别词,整理时 MetaInfoPath 未接收
custom_words 参数。

修复:
- 在 DownloadHistory 模型中添加 custom_words 字段
- 下载时从 meta.apply_words 获取并保存识别词到下载历史
- MetaInfoPath 函数添加 custom_words 参数支持
- 整理时从下载历史获取 custom_words 并传递给 MetaInfoPath
- 添加 Alembic 迁移脚本 (2.2.3)
- 添加相关单元测试
2026-01-19 15:46:00 +08:00
大虾
f1b3fc2254 更新注释 2026-01-19 10:11:54 +08:00
景大侠
a677ed307d 修复 剧集nfo文件刮削了错误的tmdb id
应使用剧集id而非剧id
2026-01-18 16:23:05 +08:00
景大侠
0ab23ee972 修复 刮削电视剧目录会误判剧集根目录为季目录
因辅助识别词指定了季号
2026-01-18 15:17:22 +08:00
景大侠
43f56d39be 修复 手动刮削电视剧目录可能会遗漏特别季 2026-01-18 01:51:35 +08:00
jxxghp
a39caee5f5 Merge pull request #5371 from cddjr/remove_unused_finished_files 2026-01-17 07:50:54 +08:00
景大侠
2edfdf47c8 移除整理进度数据中无用的文件列表 2026-01-17 00:20:09 +08:00
jxxghp
3819461db5 更新 version.py 2026-01-16 19:27:57 +08:00
jxxghp
85654dd7dd Merge pull request #5367 from PKC278/v2 2026-01-15 22:58:10 +08:00
PKC278
619a70416b fix: 修正智能推荐功能未检查智能助手总开关的问题 2026-01-15 22:57:49 +08:00
jxxghp
16d996fe70 Merge pull request #5366 from xiaoQQya/develop 2026-01-15 21:11:10 +08:00
xiaoQQya
1baeb6da19 feat(rousi pro): 支持解析 Rousi Pro 站点未读消息 2026-01-15 21:08:08 +08:00
jxxghp
1641d432dd feat: 为工具管理器添加参数类型规范化处理,并基于渠道能力动态生成提示词中的格式要求 2026-01-15 20:55:35 +08:00
jxxghp
1bf9862e47 feat: 更新代理提示词,增加详细的沟通、状态更新、总结、操作流程、工具使用和媒体管理规则。 2026-01-15 19:50:37 +08:00
jxxghp
602a394043 Merge pull request #5362 from cddjr/feat_extended_api_token_support 2026-01-15 13:33:56 +08:00
景大侠
22a2415ca5 缓存api鉴权结果 2026-01-15 12:38:47 +08:00
景大侠
feb034352d 让现有基于JWT令牌鉴权的接口也能支持API令牌鉴权 2026-01-15 12:30:03 +08:00
jxxghp
a7c8942c78 Merge pull request #5358 from PKC278/v2 2026-01-15 07:04:21 +08:00
PKC278
95f2ac3811 feat(search): 添加AI推荐功能并优化相关逻辑 2026-01-15 02:49:29 +08:00
jxxghp
91354295f2 Merge pull request #5356 from cddjr/fix_manual_transfer 2026-01-14 22:48:24 +08:00
景大侠
c9c4ab5911 修复 手动重新整理没有更新源文件大小的问题
- V1迁移过来的记录,重整理后文件大小显示为0
- 部分源文件大小有变动,重整理后大小显示没变化
2026-01-14 22:42:36 +08:00
jxxghp
a26c5e40dd Merge pull request #5354 from cddjr/fix_media_root_path 2026-01-14 19:04:53 +08:00
景大侠
80f5c7bc44 修复 整理文件或目录时没有正确应用多层标题的重命名格式
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-01-14 19:02:17 +08:00
jxxghp
4833b39c52 Merge pull request #5352 from cddjr/fix_concurrency_systemconfig 2026-01-13 16:58:21 +08:00
景大侠
f478958943 修复 SystemConfig潜在的资源竞争问题
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-01-13 14:33:53 +08:00
jxxghp
0469ad46d6 Merge pull request #5351 from winter0245/v2 2026-01-13 11:48:28 +08:00
winter0245
5fe5deb9df Merge branch 'jxxghp:v2' into v2 2026-01-13 09:30:16 +08:00
xjy
ce83bc24bd fix: 修复站点Cookie处理的两个关键问题
本次提交修复了PT站点搜索功能失败的两个根本原因:

1. **Cookie URL解码问题**
   - 问题:数据库中存储的Cookie值包含URL编码(如%3D、%2B、%2F),
     但cookie_parse()函数未进行解码
   - 影响:所有使用URL编码Cookie的站点可能无法正常登录
   - 修复:在app/utils/http.py的cookie_parse()中添加unquote()解码

2. **httpx Cookie jar覆盖问题**(关键)
 - 问题:httpx.AsyncClient的Cookie jar机制会自动保存服务器返回的
 Set-Cookie,并在后续请求中覆盖我们传入的Cookie
 - 表现:传入正确的c_secure_uid/c_secure_pass,实际发送的却是
 PHPSESSID等错误Cookie
 - 修复:在创建AsyncClient时传入Cookie,而不是在request()时传入

修改文件:
- app/utils/http.py: cookie_parse()添加URL解码 + AsyncClient传入cookies
- app/modules/indexer/spider/__init__.py: 清理调试代码

测试验证:
-  pterclub 搜索功能恢复正常
-  春天站点搜索功能正常(验证通用性)
2026-01-13 09:29:05 +08:00
jxxghp
dce729c8cb Merge pull request #5350 from cddjr/fix_tmdb_cache 2026-01-13 07:04:58 +08:00
jxxghp
a9d17cd96f Merge pull request #5349 from cddjr/fix_bluray 2026-01-13 07:03:16 +08:00
景大侠
294bb3d4a1 修复 目录监控无法触发蓝光原盘整理 2026-01-13 00:09:34 +08:00
景大侠
b31b9261f2 Update app/core/config.py
接受AI的建议
2026-01-12 23:31:44 +08:00
大虾
2211f8d9e4 Update tests/test_bluray.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-01-12 23:17:39 +08:00
景大侠
b9b7b00a7f 修复 下载器监控构造的原盘路径需以/结尾 2026-01-12 22:54:19 +08:00
景大侠
843faf6103 修复 整理记录无法显示原盘大小 2026-01-12 22:14:43 +08:00
景大侠
4af5dad9a8 修复 原盘自动刮削缺少nfo 2026-01-12 21:36:17 +08:00
景大侠
52437c9d18 按语言缓存tmdb元数据 2026-01-12 09:41:34 +08:00
景大侠
c6cb4c8479 统一构造tmdb图片网址 2026-01-12 09:41:25 +08:00
jxxghp
c3714ec251 Merge pull request #5346 from HankunYu/v2 2026-01-12 09:04:35 +08:00
HankunYu
dbe2f94af1 修改embed解析以支持emoji字符 2026-01-12 00:46:26 +00:00
jxxghp
07fd5f8a9e Merge pull request #5344 from PKC278/v2 2026-01-11 20:30:28 +08:00
PKC278
9e64b4cd7f refactor: 优化登录安全性并重构 PassKey 逻辑
- 统一登录失败返回信息,防止信息泄露
- 提取 PassKeyHelper 公共函数,简化 Base64 和凭证处理
- 重构 mfa.py 端点代码,提升可读性和维护性
- 移除冗余的 origin 验证逻辑
2026-01-11 19:20:53 +08:00
jxxghp
f08a7b9eb3 Merge pull request #5343 from Lyzd1/v2 2026-01-10 19:10:04 +08:00
The falling leaves know
a6fa764e2a Change media_type to required field in QueryMediaDetailInput 2026-01-10 18:49:02 +08:00
jxxghp
01676668f1 Merge pull request #5342 from Lyzd1/v2 2026-01-10 17:58:13 +08:00
The falling leaves know
8e5e4f460d Enhance media detail query with media type handling 2026-01-10 17:44:11 +08:00
jxxghp
f907b8a84d v2.9.3
- 优化通行密钥登录体验
- 优化智能体
- 支持Rousi Pro全新架构站点
2026-01-10 10:32:56 +08:00
jxxghp
a3a4285f90 Merge pull request #5339 from PKC278/v2 2026-01-10 07:42:38 +08:00
PKC278
0979163b79 fix(rousi): 修正分类参数为单一值以符合API要求 2026-01-10 02:12:33 +08:00
PKC278
248a25eaee fix(rousi): 移除单例模式 2026-01-10 01:39:40 +08:00
PKC278
f95b1fa68a fix(rousi): 修正分类映射 2026-01-10 01:31:12 +08:00
PKC278
d2b5d69051 feat(rousi): 重构响应处理逻辑以提高代码可读性和维护性 2026-01-10 00:54:43 +08:00
PKC278
3ca419b735 fix(rousi): 精简并修正分类映射 2026-01-10 00:27:45 +08:00
PKC278
50e275a2f9 feat(config): 增加最大搜索名称数量限制至3 确保包含 en_title 2026-01-09 23:53:09 +08:00
PKC278
aeccf78957 feat(rousi): 新增分类参数支持以优化搜索功能 2026-01-09 23:05:02 +08:00
PKC278
cb3cef70e5 feat: 新增 RousiPro 站点支持 2026-01-09 22:08:24 +08:00
jxxghp
b9bd303bf8 fix:优化Agent参数校验,避免中止推理 2026-01-09 20:26:49 +08:00
jxxghp
57d4786a7f Merge pull request #5332 from PKC278/v2 2026-01-08 07:47:01 +08:00
PKC278
df031455b2 feat(agent): 新增媒体详情查询工具 2026-01-07 23:31:08 +08:00
jxxghp
30059eff4f Merge pull request #5319 from cddjr/fix_5314 2026-01-04 18:59:26 +08:00
景大侠
bc289b48c8 修复 字幕支持通过代理下载 2026-01-04 16:07:45 +08:00
jxxghp
067d8b99b8 更新 version.py 2026-01-04 13:19:05 +08:00
jxxghp
00a6a9c42d Merge pull request #5317 from cddjr/fix_MetaInfoPath 2026-01-03 20:52:48 +08:00
大虾
070425d446 Update app/core/metainfo.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-01-03 19:26:03 +08:00
大虾
7405883444 Update app/core/metainfo.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-01-03 19:25:54 +08:00
景大侠
66959937ed 修复 电影文件可能会误识别成电视剧类型 2026-01-03 18:06:26 +08:00
jxxghp
e431efbcba Merge pull request #5315 from cddjr/fix_movie_scrape_image 2026-01-03 07:19:32 +08:00
景大侠
ba00baa5a0 修复 刮削电影会误报父目录的海报图已存在 2026-01-02 23:37:36 +08:00
jxxghp
0fb5d4a164 Merge pull request #5312 from PKC278/v2 2026-01-02 18:23:37 +08:00
PKC278
1ac717b67f fix(message): 修复缓存数据处理逻辑以避免空值错误 2026-01-02 17:12:33 +08:00
jxxghp
273cbd447e Merge pull request #5309 from Seed680/v2 2026-01-01 23:30:41 +08:00
noone
cee41567a2 feat(chain): 添加当前时间参数到消息渲染
- 在MessageTemplateHelper.render调用中添加current_time参数
2026-01-01 23:01:25 +08:00
jxxghp
1aae5eb1a6 Merge pull request #5307 from cddjr/fix_mteam_promotions 2026-01-01 13:54:58 +08:00
景大侠
28a4c81aff 识别馒头站点的全站促销规则 2026-01-01 13:10:41 +08:00
jxxghp
5e077cd64d 更新 version.py 2025-12-31 07:49:12 +08:00
jxxghp
e3f957a59b 更新 __init__.py 2025-12-31 07:20:52 +08:00
jxxghp
55c62a3ab5 Merge pull request #5303 from HankunYu/v2 2025-12-31 07:00:04 +08:00
jxxghp
22e7eef1bd Merge pull request #5302 from cddjr/fix_tmdb_healthcheck 2025-12-31 06:59:03 +08:00
HankunYu
d6524907f3 修复重载模块会产生新的DC实例;建立embed解析白名单,不解析插件等消息以免破坏原有格式 2025-12-30 16:51:30 +00:00
景大侠
357db334cd 修复 自建TMDB服无法通过健康检测
携带UA以避免被反爬虫脚本过滤
2025-12-30 22:13:43 +08:00
jxxghp
f8bed3909b Merge pull request #5299 from cddjr/fix_5297 2025-12-30 15:52:29 +08:00
景大侠
182bbdde91 fix #5297 2025-12-30 15:21:27 +08:00
jxxghp
2c70f990c2 Merge pull request #5294 from cddjr/mteam_subtitle 2025-12-30 06:57:15 +08:00
景大侠
0b01a6aa91 避免获取到字幕上传者的详情链接 2025-12-29 22:52:26 +08:00
景大侠
e557dffbc6 支持憨憨站点的字幕下载 2025-12-29 22:43:47 +08:00
景大侠
7f33b0b1b8 支持馒头站点的字幕下载 2025-12-29 22:43:07 +08:00
景大侠
41ddf77a5b 添加馒头字幕API 2025-12-29 20:01:54 +08:00
jxxghp
8c657ce41d 更新 version.py 2025-12-28 17:58:39 +08:00
jxxghp
3ff3b9ed4a Merge pull request #5290 from PKC278/v2 2025-12-28 17:58:05 +08:00
PKC278
ef43419ecd Update app/api/endpoints/system.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-12-28 16:38:30 +08:00
PKC278
2ca375c214 feat(system): 添加前端和后端版本信息 2025-12-28 16:08:14 +08:00
jxxghp
cbd45c1d0f Merge pull request #5289 from HankunYu/v2 2025-12-28 12:50:40 +08:00
HankunYu
2592ea3464 清理 prefix/suffix 与字段值的分隔符;字段名允许 &;当冒号落在 《》/【】 内时整行作为描述,避免书名号误拆 2025-12-27 17:00:07 +00:00
HankunYu
73ac97cd96 更新解析embed逻辑; 添加使用代理 2025-12-27 13:05:57 +00:00
jxxghp
e014663e97 更新 version.py 2025-12-27 14:22:35 +08:00
jxxghp
58592e961f Merge pull request #5283 from PKC278/v2 2025-12-26 23:25:24 +08:00
PKC278
9a99b9ce82 fix(system): 更新global返回字段,采用白名单模式 2025-12-26 23:02:40 +08:00
jxxghp
8c6dca1751 Merge pull request #5277 from Seed680/v2 2025-12-25 19:26:26 +08:00
noone
cf488d5f5f fix(qbittorrent): 修复种子文件读取和重复检查问题
- 将变量名从 torrent 改为 torrent_from_file 以避免混淆
- 修复添加种子任务失败时的错误检查逻辑
- 使用 getattr 函数安全获取种子文件的名称和大小属性
- 修复已存在种子任务检查时的属性访问问题

fix(transmission): 修复种子添加和重复检查逻辑

- 将变量名从 torrent 改为 torrent_from_file 以避免混淆
- 修复添加任务后的返回值变量名
- 使用 getattr 函数安全获取种子文件的名称和大小属性
- 修复已存在种子任务检查时的属性访问问题
- 修正种子哈希获取的变量引用
2025-12-25 19:09:45 +08:00
jxxghp
515584d34c fix warnings 2025-12-24 22:04:04 +08:00
jxxghp
fb2becc7f2 v2.8.9
- 支持Discord通知渠道
- 支持使用通行密钥登录
2025-12-24 19:41:58 +08:00
jxxghp
0f8ceb0fac fix warnings 2025-12-24 18:54:38 +08:00
jxxghp
a70bf18770 Merge pull request #5273 from PKC278/v2 2025-12-23 17:36:30 +08:00
PKC278
2de83c44ab refactor(mcp): 精简会话管理逻辑并更新API文档 2025-12-23 17:06:17 +08:00
PKC278
7b99f09810 fix(mfa): 修复双重验证漏洞 2025-12-23 14:58:00 +08:00
jxxghp
6b4ba8bfad Merge pull request #5272 from PKC278/v2 2025-12-23 14:39:03 +08:00
PKC278
0c6cfc5020 feat(passkey): 添加PassKey支持并优化双重验证登录逻辑 2025-12-23 13:53:54 +08:00
jxxghp
abd9733e7f Merge pull request #5269 from HankunYu/v2 2025-12-23 12:51:25 +08:00
HankunYu
98c3ae5e76 Merge branch 'v2' of https://github.com/jxxghp/MoviePilot into v2 2025-12-22 21:00:47 +00:00
HankunYu
bb5a657469 更新Discord模块支持互动消息 2025-12-22 19:59:22 +00:00
jxxghp
7797532350 Merge pull request #5271 from PKC278/v2 2025-12-22 21:32:53 +08:00
PKC278
c3a5106adc feat(manager): 添加工具调用参数格式自动转换功能 2025-12-22 21:04:13 +08:00
HankunYu
c5fd935dd0 Merge branch 'v2' of https://github.com/jxxghp/MoviePilot into v2 2025-12-22 12:19:21 +00:00
jxxghp
ec375a19ae Merge pull request #5267 from stkevintan/cookiecloud-post 2025-12-22 19:06:05 +08:00
jxxghp
51e940617c Merge pull request #5270 from PKC278/v2 2025-12-22 18:50:12 +08:00
PKC278
58ec8bd437 feat(mcp): 实现标准MCP协议支持和会话管理功能 2025-12-22 18:49:00 +08:00
jxxghp
a096395086 Merge pull request #5250 from ixff/v2 2025-12-22 11:04:47 +08:00
HankunYu
4bd08bd915 通知渠道增加Discord 2025-12-22 02:15:28 +00:00
stkevintan
2c849cfa7a fix code style 2025-12-22 08:33:23 +08:00
stkevintan
501d530d1d cookiecloud: support download encrypted data using post 2025-12-21 23:07:35 +08:00
jxxghp
91fc4327f4 Merge pull request #5261 from ixff/fix 2025-12-19 12:38:43 +08:00
ixff
8d56c67079 fix typos 2025-12-19 12:19:42 +08:00
jxxghp
e52d43458e 更新 version.py 2025-12-15 15:19:57 +08:00
ixff
9b125bf9b0 feat: 支持选择Playwright浏览器环境 2025-12-14 23:15:28 +08:00
jxxghp
0716c65269 Refactor: Simplify memory key generation and update retention settings 2025-12-13 15:40:20 +08:00
jxxghp
ba3ce4f1b5 Merge pull request #5245 from jxxghp/cursor/agent-download-progress-tool-8daa 2025-12-13 15:09:54 +08:00
Cursor Agent
07f72b0cdc Refactor: Improve query download tasks logic and add status filtering
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-12-13 07:01:24 +00:00
Cursor Agent
bda19df87f Fix: Ensure list_torrents and downloading return empty lists
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-12-13 06:53:06 +00:00
jxxghp
5d82fae2b0 fix agent memory 2025-12-13 14:40:47 +08:00
jxxghp
0813b87221 fix agent memory 2025-12-13 13:23:41 +08:00
jxxghp
961ecfc720 fix agent memory 2025-12-13 13:09:49 +08:00
jxxghp
81f30ef25a fix agent memory 2025-12-13 12:26:08 +08:00
jxxghp
140b0d3df2 Merge pull request #5234 from xgitc/patch-2 2025-12-10 16:20:36 +08:00
jxxghp
b3d69d7de4 Merge pull request #5233 from xgitc/patch-1 2025-12-10 16:20:07 +08:00
xgitc
8e65564fb8 适配不同版本的gazelle程序
适配隐藏了URL中“.php”的站点;适配下一页按钮title为“下一页”或“Next”的站点。
2025-12-10 16:12:42 +08:00
xgitc
06ce9bd4de 适配更多促销类型 2025-12-10 15:54:03 +08:00
jxxghp
274fc2d74f v2.8.8
- 下载器支持配置路径映射
- 问题修复与细节优化
2025-12-10 14:33:13 +08:00
jxxghp
2f1a448afe Merge pull request #5226 from stkevintan/path-mapping 2025-12-08 18:46:48 +08:00
Kevin Tan
99cab7c337 Update app/modules/__init__.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-12-08 17:21:33 +08:00
Kevin Tan
81f7548579 Update app/modules/__init__.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-12-08 17:20:45 +08:00
stkevintan
6ebd50bebc update naming 2025-12-08 16:30:40 +08:00
stkevintan
378ba51f4d support path_mapping for downloader 2025-12-08 16:25:46 +08:00
jxxghp
63a890e85d 更新 __init__.py 2025-12-06 20:03:34 +08:00
jxxghp
bf4f9921e2 Merge pull request #5224 from stkevintan/file_uri 2025-12-06 20:03:05 +08:00
stkevintan
167ae65695 fix: path empty 2025-12-06 19:58:23 +08:00
stkevintan
2affa7c9b8 Support remote file uri when adding downloads 2025-12-06 19:33:52 +08:00
jxxghp
785540e178 更新 graphics.py 2025-12-06 14:47:23 +08:00
jxxghp
bcad4c0bc6 Merge pull request #5223 from wikrin/refactor/image-helper 2025-12-06 14:46:52 +08:00
Attente
5af217fbf5 refactor: 将图片获取逻辑抽象为独立的 ImageHelper 2025-12-06 10:10:36 +08:00
jxxghp
128aa2ef23 更新 requirements.in 2025-12-04 13:27:03 +08:00
jxxghp
fce1186dd1 Merge remote-tracking branch 'origin/v2' into v2 2025-12-04 12:30:05 +08:00
jxxghp
9a7b11f804 add google-generativeai 2025-12-04 12:29:56 +08:00
jxxghp
b068a06fa8 Merge pull request #5219 from 0xlane/v2 2025-12-03 13:49:18 +08:00
REinject
931a42e981 fix(tmdbapi): 修复按季搜索剧集的名称匹配逻辑问题 2025-12-03 12:26:05 +08:00
jxxghp
e0a20a6697 Merge pull request #5216 from wikrin/image_cache 2025-12-03 11:12:09 +08:00
Attente
1ef4374899 feat(telegram): 图片增加缓存与安全校验, 获取失败降级发送
- 统一部分类型标注
- 修正部分文本错误
2025-12-03 09:56:30 +08:00
jxxghp
3b7212740b fix 2025-12-01 15:22:06 +08:00
jxxghp
4b80b8dc1f Merge pull request #5206 from DDSRem-Dev/dev 2025-11-30 17:06:45 +08:00
DDSRem
b7f24827e6 fix(servarr): year type defined incorrectly
fix https://github.com/jxxghp/MoviePilot/issues/5158
2025-11-30 16:29:21 +08:00
jxxghp
1c08a22881 Merge pull request #5204 from yelantf/patch-2 2025-11-30 09:50:13 +08:00
夜阑听风
8bd848519d Convert user level to string if not None 2025-11-30 09:36:28 +08:00
jxxghp
e19f2aa76d Merge pull request #5202 from 0xlane/v2 2025-11-30 08:01:18 +08:00
REinject
4a99e2896f feat: 添加下载任务时增加辅助识别 2025-11-29 22:12:25 +08:00
jxxghp
de3c83b0aa Merge pull request #5197 from stkevintan/default-samba 2025-11-28 19:42:43 +08:00
stkevintan
36bdb831be use download storage instead of library storage 2025-11-28 19:30:39 +08:00
Kevin Tan
1809690915 Update app/modules/subtitle/__init__.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-11-28 17:21:17 +08:00
stkevintan
e51b679380 fix: support non-local filesystem operations for default dir and subtitles 2025-11-28 14:55:01 +08:00
jxxghp
10c26de7cb Merge pull request #5193 from wikrin/config_reload_mixin 2025-11-28 07:17:12 +08:00
Attente
ca5ec8af0f feat(config): 优化配置变更事件处理机制 2025-11-27 23:17:34 +08:00
jxxghp
d1d7b8ce55 更新 __init__.py 2025-11-27 22:03:20 +08:00
jxxghp
77f8983307 Merge pull request #5192 from stkevintan/smb-link 2025-11-27 20:15:46 +08:00
stkevintan
ba415acd37 add hard link support for smb 2025-11-27 18:21:54 +08:00
jxxghp
bcf13099ac Merge pull request #5188 from wikrin/dev 2025-11-26 22:27:51 +08:00
Attente
eb2b34d71c feat(themoviedb): 添加对 ConfigChanged 事件的监听支持
- 调整 username 字段类型以兼容整数形式
2025-11-26 20:58:58 +08:00
jxxghp
d0b665f773 更新 version.py 2025-11-25 20:19:59 +08:00
jxxghp
a1674b1ae5 Merge pull request #5186 from Seed680/v2 2025-11-25 17:16:28 +08:00
noone
af83681f6a feat(telegram): 新增单元测试覆盖各种消息发送场景 2025-11-25 17:02:31 +08:00
jxxghp
bebacf7b20 refactor: Update tool imports and descriptions in factory.py; remove obsolete query tools and enhance ListDirectoryTool description 2025-11-25 13:45:19 +08:00
jxxghp
6dc1fcbc3e Merge branch 'v2' of https://github.com/jxxghp/MoviePilot into v2 2025-11-25 13:33:04 +08:00
jxxghp
b599ef4509 feat: Add QueryMediaLatestTool to MoviePilotToolFactory 2025-11-25 13:33:03 +08:00
jxxghp
526b6a1119 Merge remote-tracking branch 'origin/v2' into v2 2025-11-24 21:30:07 +08:00
jxxghp
88173db4ce fix #5172 2025-11-24 21:29:56 +08:00
jxxghp
e139b1ab22 Merge pull request #5183 from wikrin/telegramify
feat(telegram): 使用 `telegramify_markdown` 库标准化消息内容,增强长消息与复杂格式的处理能力
2025-11-24 21:26:32 +08:00
Attente
6c1e0058c1 feat(telegram): 使用 telegramify_markdown 库标准化消息内容,增强长消息与复杂格式的处理能力 2025-11-24 20:59:32 +08:00
jxxghp
c96633eb83 Merge pull request #5173 from wikrin/cached 2025-11-23 16:58:50 +08:00
Attente
91eb35a77b fix(cache): 修复fresh会被错误覆盖的问题 2025-11-23 16:46:09 +08:00
jxxghp
d749d59cad Merge pull request #5171 from jxxghp/cursor/check-for-ai-prefix-before-processing-message-composer-1-29f2 2025-11-23 14:37:21 +08:00
Cursor Agent
80396b4d30 Fix: Make /ai command case-insensitive
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-23 06:36:06 +00:00
Cursor Agent
64b93a009c Refactor: Allow messages without /ai prefix
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-23 06:35:44 +00:00
Cursor Agent
2b32250504 feat: Require messages to start with /ai
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-23 06:34:31 +00:00
jxxghp
9b5f863832 v2.8.6
- 增加全局智能助手设置,开启后所有消息通过智能助手回答而无需使用 `/ai` 指令
- 问题修复与细节优化
2025-11-23 13:55:16 +08:00
jxxghp
fd422d7446 Merge pull request #5170 from wikrin/fix 2025-11-23 13:33:49 +08:00
Attente
5162b2748e fix(media): 修复类型错误 2025-11-23 13:28:01 +08:00
jxxghp
56c684ec06 Merge pull request #5168 from jxxghp/cursor/add-actor-filmography-search-tool-composer-1-6aad 2025-11-22 08:12:17 +08:00
Cursor Agent
7e93b33407 feat: Add search_person_credits tool
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-22 00:03:57 +00:00
jxxghp
7662235802 Merge pull request #5165 from jxxghp/cursor/add-site-parameters-to-agent-subscription-tool-be8f 2025-11-21 20:46:19 +08:00
Cursor Agent
e41f9facc7 Add sites parameter to AddSubscribeTool
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-21 12:45:11 +00:00
jxxghp
785b8ede11 Merge pull request #5164 from jxxghp/cursor/add-person-search-tool-for-agent-745c 2025-11-21 19:33:00 +08:00
Cursor Agent
78b198ad70 feat: Add SearchPersonTool for agent
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-21 11:31:27 +00:00
jxxghp
c2c0515991 Merge pull request #5163 from Pollo3470/feat/ai-proxy 2025-11-21 12:23:39 +08:00
Pollo
b97fefdb8d fix(ai): 解决google代理不生效问题
- google在检测到配置代理时,使用gemini openai兼容API
2025-11-21 11:10:41 +08:00
jxxghp
840da6dd85 Merge pull request #5157 from jxxghp/cursor/add-web-search-tool-with-context-trimming-70fe 2025-11-20 22:59:37 +08:00
Cursor Agent
972d916126 Refactor: Use DuckDuckGo API directly for web search
This change removes the HTML parsing logic and directly uses the DuckDuckGo API for web searches. It also adds proxy support for the HTTP requests.

Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-20 14:58:22 +00:00
Cursor Agent
e3ed065f5f Add SearchWebTool for web searching capabilities
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-20 14:52:45 +00:00
jxxghp
760ebe6113 v2.8.5
- 智能体OpenAi及Google模型默认使用代理,支持自动获取可选模型列表
- 手动添加下载时支持指定媒体信息编号
2025-11-20 19:40:43 +08:00
jxxghp
a329d3ad89 fix api 2025-11-20 19:38:19 +08:00
jxxghp
01f8561582 fix 2025-11-20 19:15:46 +08:00
jxxghp
883ea5c996 Merge pull request #5155 from madrays/v2 2025-11-20 19:10:58 +08:00
jxxghp
99cf13ed9b Merge pull request #5152 from Pollo3470/feat/ai-proxy 2025-11-20 19:09:54 +08:00
madrays
91c7ef6801 增加自动拉取可用ai模型的易用性功能 2025-11-20 19:01:33 +08:00
Pollo
84ef5705e7 feat: google临时环境变量线程安全处理 2025-11-20 17:05:55 +08:00
Pollo
cf2a0cf8c2 feat: google和openai使用代理访问 2025-11-20 16:56:32 +08:00
jxxghp
48c25c40e4 fix wechat 2025-11-20 16:51:43 +08:00
jxxghp
996d8ab954 v2.8.4-1
- 修复工作流组件加载问题
- 修改个别智能体工具问题
2025-11-20 13:10:38 +08:00
jxxghp
fac2546a92 Enhance media library query tool with detailed logging and improved error handling. Refactor to use MediaServerChain for media existence checks and item details retrieval. 2025-11-20 13:02:23 +08:00
jxxghp
728ea6172a fix exists_local 2025-11-20 12:43:19 +08:00
jxxghp
f59d225029 fix workflow actions 2025-11-20 12:34:44 +08:00
jxxghp
0b178a715f fix search_media 2025-11-20 12:00:00 +08:00
jxxghp
e06e5328c2 Merge pull request #5148 from jxxghp/cursor/handle-ai-agent-message-processing-error-af53 2025-11-20 09:37:48 +08:00
Cursor Agent
1c14cd0979 Refactor: Use asyncio.run_coroutine_threadsafe for async calls
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-20 01:37:17 +00:00
jxxghp
f9141f5ba2 Merge remote-tracking branch 'origin/v2' into v2 2025-11-20 08:19:52 +08:00
jxxghp
48da5c976c fixx loop 2025-11-20 08:15:37 +08:00
jxxghp
fa38c81c08 Merge pull request #5146 from DDS-Derek/dev 2025-11-19 20:47:16 +08:00
DDSDerek
8d5fe5270f Update app/modules/filemanager/storages/u115.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-11-19 19:51:14 +08:00
DDSRem
0dc0d66549 fix: known issue 2025-11-19 19:46:46 +08:00
DDSRem
f589fcc2d0 feat(u115): improve stability of the u115 module
1. 优化API请求错误时到处理逻辑
2. 提升hash计算速度
3. 接口级QPS速率限制
4. 使用httpx替换request
5. 优化路径拼接稳定性
6. 代码格式化
2025-11-19 19:39:02 +08:00
jxxghp
edd44a0993 Merge pull request #5143 from jxxghp/cursor/update-mcp-api-documentation-and-readme-a12b 2025-11-19 16:05:23 +08:00
Cursor Agent
2aae496742 Refactor: Improve MCP API documentation for broader client support
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-19 08:03:53 +00:00
Cursor Agent
6f72046f86 Refactor: Update MCP API documentation and authentication
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-19 07:47:32 +00:00
jxxghp
d4a9b446a6 更新 requirements.in 2025-11-19 14:35:41 +08:00
jxxghp
95f571e9b9 更新 requirements.in 2025-11-19 14:34:27 +08:00
jxxghp
e8aeae5c07 更新 version.py 2025-11-19 14:28:49 +08:00
jxxghp
ddf6dc0343 Merge pull request #5142 from jxxghp/cursor/update-agent-site-tool-documentation-with-priority-81fb 2025-11-19 14:17:31 +08:00
Cursor Agent
36d55a9db7 Refactor: Simplify tool descriptions
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-19 06:16:24 +00:00
Cursor Agent
7d41379ad5 Refactor: Clarify site priority in tool descriptions
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-19 06:15:18 +00:00
jxxghp
63e928da96 更新 version.py 2025-11-19 14:10:11 +08:00
jxxghp
5c983b64bc fix SiteUserData 2025-11-19 13:47:02 +08:00
jxxghp
b2d36c0e68 Update API key documentation to clarify retrieval methods in security.py and mcp-api.md 2025-11-19 13:42:53 +08:00
jxxghp
6123a1620e add mcp 2025-11-19 13:19:17 +08:00
jxxghp
5ae7c10a00 Enhance MoviePilotAgent to handle empty agent messages gracefully by providing a default error response, ensuring better user experience. Refactor message processing to streamline event loop execution. 2025-11-19 12:51:08 +08:00
jxxghp
b5a6794381 Refactor event loop handling to use GlobalVar.CURRENT_EVENT_LOOP across multiple modules, improving consistency and maintainability. 2025-11-19 08:42:07 +08:00
jxxghp
6b575f836a Add filter_groups parameter to AddSubscribeTool and include SearchSubscribeTool and QueryRuleGroupsTool in MoviePilotToolFactory 2025-11-19 08:31:06 +08:00
jxxghp
c83589cac6 rollback telegram 2025-11-18 21:56:55 +08:00
jxxghp
d64492bda5 fix QueryEpisodeScheduleTool 2025-11-18 21:46:11 +08:00
jxxghp
33d6c75924 fix telegram 2025-11-18 21:43:55 +08:00
jxxghp
89f01bad42 fix telegram 2025-11-18 21:32:09 +08:00
jxxghp
767496f81b fix telegram 2025-11-18 21:31:44 +08:00
jxxghp
147a477365 fix site 2025-11-18 21:13:45 +08:00
jxxghp
13171f636f fix 2025-11-18 20:34:53 +08:00
jxxghp
fea3f0d3e0 fix telegram markdown 2025-11-18 19:53:27 +08:00
jxxghp
a3a254c2ea fix telegram markdown 2025-11-18 19:09:36 +08:00
jxxghp
bd9d5f7fc0 Merge pull request #5135 from jxxghp/cursor/handle-telegram-hyphen-escape-error-9f51 2025-11-18 17:49:15 +08:00
Cursor Agent
726738ee9e Refactor: Protect only markdown delimiters, not content
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-11-18 09:43:42 +00:00
jxxghp
725244bb2f fix escape_markdown 2025-11-18 17:30:00 +08:00
jxxghp
d2ac2b8990 feat: add QueryEpisodeScheduleTool to MoviePilotToolFactory
- Included QueryEpisodeScheduleTool in the tool definitions of MoviePilotToolFactory to enhance episode scheduling capabilities.
- Updated factory.py to reflect the addition of this new tool, improving overall functionality.
2025-11-18 17:20:23 +08:00
jxxghp
116569223c fix 2025-11-18 16:44:39 +08:00
jxxghp
05442a019f feat: add UpdateSubscribeTool and additional query tools to MoviePilotToolFactory
- Included UpdateSubscribeTool and QuerySiteUserdataTool in the tool definitions of MoviePilotToolFactory to enhance subscription management and user data querying capabilities.
- Updated the factory.py file to reflect the addition of these new tools, improving overall functionality.
2025-11-18 16:41:15 +08:00
jxxghp
db67080bf8 feat: add ScrapeMetadataTool to MoviePilotToolFactory
- Included ScrapeMetadataTool in the tool definitions of MoviePilotToolFactory to enhance metadata scraping capabilities.
- Updated the factory.py file to reflect the addition of the new tool.
2025-11-18 16:26:18 +08:00
jxxghp
21fabf7436 feat: enhance GetRecommendationsTool and update query tools for improved functionality
- Expanded the GetRecommendationsTool to support additional recommendation sources, including TMDB popular movies and TV shows, as well as various Douban categories.
- Updated the limit for results in QuerySubscribesTool, SearchMediaTool, and QueryTransferHistoryTool from 20 to 50 or 30, respectively, to provide more comprehensive results.
- Removed unnecessary description fields from media objects in QueryPopularSubscribesTool, QuerySubscribeHistoryTool, and QuerySubscribeSharesTool for cleaner output.
2025-11-18 16:21:13 +08:00
jxxghp
a8c6516b31 refactor: remove deprecated tools and add RecognizeMediaTool
- Removed the old tool definitions from __init__.py to streamline the module.
- Added RecognizeMediaTool to factory.py for enhanced media recognition capabilities.
- Updated tool exports to reflect the changes in available tools.
2025-11-18 16:07:11 +08:00
jxxghp
f5ca48a56e fix: update recommendation fetching logic in GetRecommendationsTool
- Adjusted the recommendation fetching methods to accept page and count parameters for better control over result limits.
- Implemented checks to ensure the format of recommendation results is valid, enhancing robustness.
- Added truncation for long overview descriptions to maintain consistency in output.
2025-11-18 13:08:09 +08:00
jxxghp
65ceff9824 v2.8.3
- MoviePilot助手增加了多个智能体工具,大幅提升智能体能力
- 智能体对话支持上下文记忆,发送 `/clear_session` 指令或超过15分钟没动作将清除记忆
2025-11-18 12:52:58 +08:00
jxxghp
ed73cfdcc7 fix: update message formatting in MoviePilotTool for clarity
- Changed the tool message format to use "=>" instead of wrapping with separators, enhancing readability and user experience during tool execution.
2025-11-18 12:43:27 +08:00
jxxghp
9cb79a7827 feat: enhance MoviePilotTool with customizable tool messages
- Added `get_tool_message` method to `MoviePilotTool` and its subclasses for generating user-friendly execution messages based on parameters.
- Improved message formatting for various tools, including `AddDownloadTool`, `AddSubscribeTool`, `DeleteDownloadTool`, and others, to provide clearer feedback during operations.
- This enhancement allows for more personalized and informative messages, improving user experience during tool execution.
2025-11-18 12:42:24 +08:00
jxxghp
984f29005a 更新 message.py 2025-11-18 12:17:12 +08:00
jxxghp
805c3719af feat: add new query tools for enhanced subscription management
- Introduced QuerySubscribeSharesTool, QueryPopularSubscribesTool, and QuerySubscribeHistoryTool to improve subscription querying capabilities.
- Updated __all__ exports in init.py and factory.py to include the new tools.
- Enhanced QuerySubscribesTool to support media type filtering with localized descriptions.
2025-11-18 12:05:06 +08:00
jxxghp
ea646149c0 feat: add new tools for download management and enhance query capabilities
- Introduced DeleteDownloadTool, QueryDirectoriesTool, ListDirectoryTool, QueryTransferHistoryTool, and TransferFileTool to the toolset for improved download management.
- Updated __all__ exports in init.py and factory.py to include the new tools.
- Enhanced QueryDownloadsTool to support querying downloads by hash and title, providing more flexible search options and detailed results.
2025-11-18 11:57:01 +08:00
jxxghp
eae1f8ee4d feat: add UpdateSiteCookieTool and enhance site operations
- Introduced UpdateSiteCookieTool to the toolset for managing site cookies.
- Updated __all__ exports in init.py and factory.py to include UpdateSiteCookieTool.
- Added async_get method in SiteOper for asynchronous retrieval of individual site records, improving database interaction.
2025-11-18 11:34:37 +08:00
jxxghp
8d1de245a6 feat: add TestSiteTool and enhance AddSubscribeTool with advanced filtering options
- Introduced TestSiteTool to the toolset for site testing functionalities.
- Updated __all__ exports in init.py and factory.py to include TestSiteTool.
- Enhanced AddSubscribeTool to support additional parameters for episode management and media quality filtering, improving subscription customization.
2025-11-18 08:51:32 +08:00
jxxghp
b8ef5d1efc feat: add session management to MessageChain
- Implemented session ID creation and reuse based on user activity, with a timeout of 15 minutes.
- Added remote command to clear user sessions, enhancing user session management capabilities.
- Updated Command class to include a new command for clearing sessions.
2025-11-18 08:41:05 +08:00
jxxghp
e1098b34e8 feat: add new tools for subscription management and scheduling
- Introduced DeleteSubscribeTool for managing subscriptions.
- Added QuerySchedulersTool and RunSchedulerTool for enhanced scheduling capabilities.
- Updated __all__ exports in init.py and factory.py to include new tools.
2025-11-18 08:34:00 +08:00
jxxghp
8296f8d2da Enhance tool message formatting in MoviePilotTool: wrap execution messages with separators and icons for better distinction from regular agent messages. 2025-11-17 17:14:05 +08:00
jxxghp
867c83383d Merge pull request #5122 from Seed680/v2 2025-11-17 15:58:53 +08:00
noone
1354119d6d fix(telegram):优化消息发送错误日志记录
- 在 send_msg 方法中细化错误日志,明确指出发送失败的位置
- 在 send_medias_msg 方法中增加标题转义注释并调整日志描述
- 在 send_torrents_msg 方法中补充标题转义逻辑及错误日志说明
2025-11-17 15:22:25 +08:00
noone
53af7f81bb fix:对telegram发送标题进行转义 2025-11-17 15:15:28 +08:00
jxxghp
48b1ac28de v2.8.2
- 新增 `MoviePilot助手` 智能体,支持自然语言对话完成任务(Beta版本,设置中打开开关并配置好大模型参数,通过 `/ai` 发送聊天内容),支持通过插件完善智能体能力
- 适配了新版本的飞牛影视
- 其它问题修复与细节改进

注意:基础组件升级,个别插件可能会有兼容性问题,需要插件适配。
2025-11-17 14:00:39 +08:00
jxxghp
6e329b17a9 Enhance Telegram message formatting: add detailed guidelines for MarkdownV2 usage, including support for strikethrough, headings, and lists. Implement smart escaping for Markdown to preserve formatting while avoiding API errors. 2025-11-17 13:49:56 +08:00
jxxghp
6a492198a8 fix post_message 2025-11-17 13:33:01 +08:00
jxxghp
8bf9b6e7cb feat:Agent插件工具发现 2025-11-17 13:00:23 +08:00
jxxghp
42e23ef564 Refactor agent workflows: streamline subscription and download processes, enhance query status workflow, and improve tool usage guidelines for better user interaction. 2025-11-17 12:49:03 +08:00
jxxghp
c6806ee648 fix agent tools 2025-11-17 12:34:20 +08:00
jxxghp
076fae696c fix 2025-11-17 11:57:46 +08:00
jxxghp
ed294d3ea4 Revert "fix schemas"
This reverts commit a5e7483870.
2025-11-17 11:48:18 +08:00
jxxghp
043be409d0 Enhance agent workflows and tools: unify subscription and download processes, add site querying functionality, and improve error handling in download operations. 2025-11-17 11:39:08 +08:00
jxxghp
a5e7483870 fix schemas 2025-11-17 10:58:24 +08:00
jxxghp
365335be46 rollback 2025-11-17 10:51:16 +08:00
jxxghp
62543dd171 fix:优化Agent消息发送格式 2025-11-17 10:43:16 +08:00
jxxghp
e2eef8ff21 fix agent message title 2025-11-17 10:18:05 +08:00
jxxghp
3acf937d56 fix add_download tool 2025-11-17 10:16:54 +08:00
jxxghp
d572e523ba 优化Agent上下文大小 2025-11-17 09:57:12 +08:00
jxxghp
82113abe88 fix agent sendmsg 2025-11-17 09:42:27 +08:00
jxxghp
b7d121c58f fix agent tools 2025-11-17 09:28:18 +08:00
jxxghp
6d5a85b144 fix search tools 2025-11-17 09:14:36 +08:00
jxxghp
78121917c6 Merge pull request #5112 from wikrin/fix_tests 2025-11-12 20:39:38 +08:00
jxxghp
a0913f0e32 Merge pull request #5109 from jiongjiongJOJO/dev 2025-11-12 20:39:10 +08:00
jxxghp
e96e284715 Merge pull request #5107 from wikrin/fix 2025-11-12 20:38:40 +08:00
Attente
c572a1b607 fix(tests): 修正 restype, 测试用例不使用识别词 2025-11-12 14:13:05 +08:00
囧囧JOJO
1845311f98 fix: 修复Docker编译时版本不兼容导致的报错问题
参考三楼回复:
https://stackoverflow.com/questions/76717537/valueerror-requirement-object-has-no-field-use-pep517-when-installing-pytho
2025-11-11 17:46:34 +08:00
Attente
4f806db8b7 fix: 修复变更默认下载器不生效的问题
- 配置模块迁移到 `SettingsConfigDict` 以支持 Pydantic v2 的配置方式
- 在 `MediaInfo` 中新增 `release_dates` 字段,用于存储多地区发行日期信息
- 修改 `MetaVideo` 类中的 token 传递逻辑,以修复搜索站点资源序列化错误的问题
2025-11-11 10:44:45 +08:00
jxxghp
22858cc1e9 Merge pull request #5100 from Seed680/v2 2025-11-06 18:43:41 +08:00
noone
a0329a3eb0 feat(rss): 支持自定义User-Agent获取RSS。目前有些站点没有配置UA时会不能正确获取RSS内容
- 在RSS方法中新增ua参数用于指定User-Agent
- 更新RequestUtils调用以传递自定义User-Agent
- 修改torrents链中RSS解析逻辑以支持站点配置的ua字段
- 设置默认超时时间为30秒以增强稳定性
2025-11-06 16:32:01 +08:00
jxxghp
b3e92088ee Merge pull request #5097 from wumode/refector-check_method 2025-11-05 23:15:24 +08:00
jxxghp
46db1c20f1 Merge pull request #5096 from cddjr/fix_trimemedia_cookies 2025-11-05 23:14:18 +08:00
wumode
9d182e53b2 fix: type hints 2025-11-05 15:41:31 +08:00
景大侠
1205fc7fdb 避免不必要的图片cookies查询 2025-11-05 15:22:02 +08:00
wumode
ff2826a448 feat(utils): Refactor check_method to use ast
- 使用 AST 解析函数源码,相比基于字符串的方法更稳定,能够正确处理具有多行 def 语句的函数
- 为 check_method 添加了单元测试
2025-11-05 14:16:37 +08:00
大虾
ee750115ec Update
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-11-04 13:29:45 +08:00
景大侠
0e13d22c97 fix 适配新版飞牛影视 2025-11-04 13:25:18 +08:00
jxxghp
8e7d040ac4 Merge pull request #5091 from wikrin/cached 2025-11-03 09:51:37 +08:00
Attente
6755202958 feat(cache): 使用 fresh 和 async_fresh 统一缓存控制方式
- 修复因缓存导致的插件更新后仍有更新提示的问题
- 统一使用 fresh/async_fresh 控制缓存行为
- 调整 TMDb 模块缓存策略,优化异步请求缓存清除机制
- 移除冗余的缓存方法封装,减少调用层级
- 简化 PluginHelper 中的缓存方法结构,移除 force 参数
2025-11-03 07:41:42 +08:00
jxxghp
8b7374a687 Merge pull request #5090 from wikrin/fix 2025-11-02 07:35:00 +08:00
Attente
c17cca2365 fix(update_setting): 修复设置保存错误的问题
- adapt to Pydantic V2
2025-11-01 23:51:59 +08:00
jxxghp
8016a9539a fix agent 2025-11-01 19:08:05 +08:00
jxxghp
e885fb15a0 Merge pull request #5089 from wikrin/fix 2025-11-01 18:27:35 +08:00
Attente
c7f098771b feat: adapt to Pydantic V2 2025-11-01 17:56:37 +08:00
Attente
fcd0908032 fix(transfer): 修复指定part不生效的问题 2025-11-01 17:56:23 +08:00
jxxghp
7ff1285084 fix agent tools 2025-11-01 12:07:17 +08:00
jxxghp
b45b603b97 fix agent tools 2025-11-01 12:01:48 +08:00
jxxghp
247208b8a9 fix agent 2025-11-01 11:41:22 +08:00
jxxghp
182c46037b fix agent 2025-11-01 10:40:45 +08:00
jxxghp
438d3210bc fix agent 2025-11-01 10:39:08 +08:00
jxxghp
d523c7c916 fix pydantic 2025-11-01 09:51:23 +08:00
jxxghp
09a19e94d5 fix config 2025-11-01 09:23:52 +08:00
jxxghp
3971c145df refactor: streamline data serialization in tool implementations
- Replaced model_dump and to_dict methods with direct calls to dict for improved consistency and performance in JSON serialization across multiple tools.
- Updated ConversationMemoryManager, GetRecommendationsTool, QueryDownloadsTool, and QueryMediaLibraryTool to enhance data handling.
2025-10-31 11:36:50 +08:00
jxxghp
055117d83d refactor: enhance tool message handling and improve error logging
- Updated _send_tool_message to accept a title parameter for better message context.
- Modified various tool implementations to utilize the new title parameter for clearer messaging.
- Improved error logging across multiple tools to include exception details for better debugging.
2025-10-31 09:16:53 +08:00
jxxghp
c6baf43986 Merge pull request #5085 from wumode/fix-event-handler-params 2025-10-29 07:50:47 +08:00
wumode
4ff16af3a7 fix: __invoke_plugin_method_async 中 __handle_event_error 参数传递错误 2025-10-28 20:09:44 +08:00
jxxghp
17a1bd352b Merge pull request #5071 from wikrin/optimize-file-size 2025-10-23 22:54:43 +08:00
Attente
7421ca09cc fix(transfer): 修复部分情况下无法正确统计已完成任务总大小的问题
- get_directory_size 使用 os.scandir 递归遍历提升性能
- 当任务文件项存储类型为 local 时,若其大小为空,则通过 SystemUtils 获取目录大小以确保
完成任务的准确统计。

fix(cache): 修改 fresh 和 async_fresh 默认参数为 True

refactor(filemanager): 移除整理后总大小计算逻辑

- 删除 TransHandler 中对整理目录总大小的冗余计算,提升性能并简化流程。

perf(system): 使用 scandir 优化文件扫描性能

- 重构 SystemUtils 中的文件扫描方法(list_files、exists_file、list_sub_files),
- 采用 os.scandir 替代 glob 实现,并预编译正则表达式以提升目录遍历与文件匹配性能。
2025-10-23 19:21:24 +08:00
jxxghp
9797e696e5 Merge pull request #5073 from WAY29/v2 2025-10-23 13:05:10 +08:00
jxxghp
c36d6d8b2d Merge pull request #5072 from wumode/fix_retry 2025-10-23 06:52:29 +08:00
wumode
3873786b99 fix: retry 2025-10-23 00:58:34 +08:00
WAY29
76fdba7f09 feat(endpoints): /download/add allow tmdbid/doubanid/bangumiid 2025-10-22 22:02:33 +08:00
jxxghp
72799e9638 Merge pull request #5068 from little6neko/v2 2025-10-22 06:18:28 +08:00
小六妞儿
2e77d03fe9 目录监控添加异常处理避免程序意外退出 2025-10-22 00:21:31 +08:00
jxxghp
0c58eae5e7 Merge pull request #5060 from wikrin/cached 2025-10-19 22:37:33 +08:00
Attente
b609567c38 feat(cache): 引入 fresh 和 async_fresh 以控制缓存行为
- 新增 `fresh` 和 `async_fresh` 用于在同步和异步函数中
临时禁用缓存。
- 通过 `_fresh` 这一 contextvars 变量实现上下文感知的
缓存刷新机制
- 修改了 `cached` 装饰器逻辑,在 `is_fresh()` 为 True
时跳过缓存读取。

- 修复 download 模块中路径处理问题,使用 `Path.as_posix()` 确保跨平台兼容性。
2025-10-19 22:31:50 +08:00
jxxghp
7ecfa44fa0 Merge pull request #5057 from xiaoQQya/v2 2025-10-19 06:49:23 +08:00
xiaoQQya
a685b1dc3b fix(douban): 修复 imdbid 匹配豆瓣信息成功错误返回 None 的问题 2025-10-18 22:34:55 +08:00
jxxghp
63ce49a17c Merge pull request #5056 from xiaoQQya/v2 2025-10-18 22:16:03 +08:00
xiaoQQya
820fbe4076 fix(douban): 修复使用 imdbid 未匹配到豆瓣信息时回退到使用名称匹配豆瓣信息失败的问题 2025-10-18 22:07:54 +08:00
jxxghp
efa05b7775 Update media tool descriptions for clarity and detail in JSON configuration 2025-10-18 22:00:24 +08:00
jxxghp
003781e903 add MoviePilot AI agent implementation and workflow manager 2025-10-18 21:55:31 +08:00
jxxghp
ee71bafc96 fix 2025-10-18 21:32:46 +08:00
jxxghp
bdd5f1231e add ai agent 2025-10-18 21:26:51 +08:00
jxxghp
6fee532c96 add ai agent 2025-10-18 21:26:36 +08:00
jxxghp
78aaad7b59 Merge pull request #5028 from ThedoRap/v2 2025-10-07 23:00:21 +08:00
Reaper
b128b0ede2 修复知行 极速之星 框架解析 做种信息 2025-10-02 20:43:06 +08:00
Reaper
737d2f3bc6 优化知行 极速之星 框架解析 2025-10-02 20:03:28 +08:00
jxxghp
179be53a65 Merge pull request #5025 from ThedoRap/v2 2025-10-02 06:50:37 +08:00
Reaper
1867f5e7c2 增加知行 极速之星 框架解析 2025-10-02 04:27:35 +08:00
jxxghp
6662d24565 Merge pull request #5019 from xiaoQQya/develop 2025-10-01 11:53:24 +08:00
jxxghp
5880566a99 Merge pull request #5018 from Aqr-K/fix-plugin 2025-10-01 11:52:43 +08:00
xiaoQQya
5d05b32711 fix: 修复 README 本地运行提示 No module named 'app' 的问题 2025-09-30 23:45:25 +08:00
Aqr-K
fa2b720e92 Refactor(plugins): Use pathlib.relative_to for robust plugin path resolution 2025-09-30 20:03:08 +08:00
jxxghp
d381238f83 Merge pull request #5017 from Aqr-K/fix-plugin 2025-09-30 19:55:46 +08:00
Aqr-K
751d627ead Merge branch 'fix-plugin' of https://github.com/aqr-k/MoviePilot into fix-plugin 2025-09-30 19:48:46 +08:00
Aqr-K
3e66a8de9b Rollback cache 2025-09-30 19:35:50 +08:00
Aqr-K
266052b12b Update app/core/plugin.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-09-30 19:26:33 +08:00
Aqr-K
803f4328f4 fix(plugins): Improve hot-reload robustness for multi-inheritance plugins 2025-09-30 18:34:26 +08:00
Aqr-K
8e95568e11 refactor(plugins): Improve hot-reloading with watchfiles 2025-09-30 18:01:02 +08:00
jxxghp
ab09ee4819 Merge pull request #4998 from Seed680/v2 2025-09-24 15:02:26 +08:00
noone
41f94a172f fix:对telegram发送标题进行转义 2025-09-24 14:29:42 +08:00
noone
566e597994 fix:撤销不必要转义 2025-09-24 14:26:09 +08:00
noone
765fb9c05f fix:更新Telegram解析模式为MarkdownV2;Telegram发送的内容按 Telegram V2 规则转义特殊字符 2025-09-24 14:14:11 +08:00
jxxghp
b6720a19f7 更新 plugin.py 2025-09-22 17:56:12 +08:00
jxxghp
3b130651c4 Merge pull request #4987 from Aqr-K/refactor/plugin-monitor 2025-09-22 11:41:13 +08:00
jxxghp
3f6c35dabe Merge pull request #4986 from Aqr-K/fix-plugin-reload 2025-09-22 07:08:33 +08:00
Aqr-K
db2a952bca refactor(plugin): Enhance hot reload with debounce and subdirectory support 2025-09-22 02:48:49 +08:00
Aqr-K
0ea9770bc3 Create debounce.py 2025-09-22 02:38:15 +08:00
Aqr-K
0b20956c90 fix 2025-09-21 22:42:18 +08:00
jxxghp
9f73b47d54 Merge pull request #4977 from jxxghp/cursor/fix-moviepilot-issue-4975-ff74 2025-09-19 18:15:08 +08:00
Cursor Agent
ce9c99af71 Refactor: Use copy instead of move for file operations
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-09-19 09:54:44 +00:00
jxxghp
784024fb5d 更新 version.py 2025-09-19 08:50:33 +08:00
jxxghp
1145b32299 fix plugin install 2025-09-18 22:32:04 +08:00
jxxghp
ab71df0011 Merge pull request #4971 from cddjr/fix_glitch 2025-09-18 21:00:00 +08:00
jxxghp
fb137252a9 fix plugin id lower case 2025-09-18 18:00:15 +08:00
jxxghp
f57a680306 插件安装支持传递 repo_url 参数 2025-09-18 17:42:12 +08:00
景大侠
8bb3eaa320 fix 获取上次搜索结果时产生的NoneType异常
glitchtip#14
2025-09-18 17:23:20 +08:00
景大侠
9489730a44 fix u115刷新access_token失败会产生NoneType异常
glitchtip#49549
2025-09-18 17:23:20 +08:00
景大侠
d4795bb897 fix u115重试请求时报错unexpected keyword argument
glitchtip#136696
2025-09-18 17:23:19 +08:00
景大侠
63775872c7 fix TMDB因连接失败产生的NoneType错误
glitchtip#11
2025-09-18 17:05:09 +08:00
jxxghp
beff508a1f Merge pull request #4970 from cddjr/fix_trimemedia 2025-09-18 15:55:46 +08:00
景大侠
deaae8a2c6 fix 2025-09-18 15:39:10 +08:00
景大侠
46a27bd50c fix: 飞牛影视 2025-09-18 15:27:02 +08:00
jxxghp
24f2993433 Merge pull request #4958 from cddjr/fix_browse_mteam 2025-09-17 07:04:59 +08:00
景大侠
c80bfbfac5 fix: 浏览馒头报错NoneType 2025-09-17 01:59:28 +08:00
jxxghp
06abfc45c7 更新 version.py 2025-09-16 20:30:38 +08:00
jxxghp
440a773081 fix 2025-09-16 17:56:44 +08:00
jxxghp
0797bcb38b fix 2025-09-16 13:10:31 +08:00
jxxghp
d463b5bf0d Merge pull request #4955 from jxxghp/cursor/add-sort-type-to-subscription-queries-af67 2025-09-16 11:41:08 +08:00
Cursor Agent
0733c8edcc Add sort_type parameter to subscribe endpoints
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-09-16 03:29:28 +00:00
jxxghp
86c7c05cb1 feat: 在获取订阅分享数据的接口中添加可选参数 2025-09-16 07:38:56 +08:00
jxxghp
18ff7ce753 feat: 在订阅统计中添加可选参数 2025-09-16 07:37:14 +08:00
jxxghp
8f2ed1004d Merge pull request #4952 from cddjr/fix_file_perm 2025-09-16 07:00:45 +08:00
景大侠
14961323c3 fix umask 2025-09-15 22:01:00 +08:00
景大侠
f8c682b183 fix: 修复刮削的文件权限只有0600的问题 2025-09-15 21:49:37 +08:00
jxxghp
dd92708f60 Merge pull request #4947 from pluto0x0/fix/4941-mttorent-imdb-search 2025-09-15 14:23:17 +08:00
Zifan Ying
4d9eeccefa fix: mtorrent搜索imdb时提供完整链接
fix: mtorrent搜索imdb时需要提供完整链接(例如https://www.imdb.com/title/tt3058674)
keyword为imdb条目时添加链接前缀
参考 https://wiki.m-team.cc/zh-tw/imdbtosearch
 
issue: https://github.com/jxxghp/MoviePilot/issues/4941
2025-09-15 00:31:45 -05:00
jxxghp
cd7b251031 Merge pull request #4946 from developer-wlj/wlj0914 2025-09-14 17:30:11 +08:00
developer-wlj
db614180b9 Revert "refactor: 优化临时文件的创建和上传逻辑"
This reverts commit 77c0f8f39e.
2025-09-14 17:14:52 +08:00
jxxghp
b6e527e5f4 Merge pull request #4945 from developer-wlj/wlj0914 2025-09-14 16:54:37 +08:00
developer-wlj
77c0f8f39e refactor: 优化临时文件的创建和上传逻辑
- 使用 with 语句自动管理临时文件的创建和关闭,提高代码的可读性和安全性
- 优化了代码结构,减少了嵌套的 try 语句,使代码更加清晰
2025-09-14 16:46:27 +08:00
jxxghp
58816d73c8 Merge pull request #4944 from developer-wlj/wlj0914 2025-09-14 16:42:37 +08:00
developer-wlj
3b194d282e fix: 修复在windows下因临时文件被占用,导致刮削失败
- 修改了两个函数中的临时文件创建和删除逻辑
- 使用手动删除代替自动删除,确保临时文件被正确清理
- 添加了异常处理,记录临时文件删除失败的情况
2025-09-14 16:28:24 +08:00
jxxghp
397f66433d v2.8.0 2025-09-13 15:58:00 +08:00
jxxghp
04a4ed1d0e fix delete_media_file 2025-09-13 14:10:15 +08:00
jxxghp
625850d4e7 fix 2025-09-13 13:35:51 +08:00
jxxghp
6c572baca5 rollback 2025-09-13 13:32:48 +08:00
jxxghp
ee0406a13f Handle smb protocol key error during disconnect (#4938)
* Refactor: Improve SMB connection handling and add signal handling

Co-authored-by: jxxghp <jxxghp@qq.com>

* Remove test_smb_fix.py

Co-authored-by: jxxghp <jxxghp@qq.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: jxxghp <jxxghp@qq.com>
2025-09-13 11:25:29 +08:00
jxxghp
608a049ba3 fix smb delete 2025-09-13 11:05:21 +08:00
jxxghp
4d9b5198e2 增强SMB存储的删除功能 2025-09-13 10:56:45 +08:00
jxxghp
24b6c970aa feat:emby用户名 2025-09-13 10:34:41 +08:00
jxxghp
239c47f469 fix #4917 2025-09-13 10:13:33 +08:00
jxxghp
f0fc64c517 fix #4917 2025-09-13 10:12:40 +08:00
jxxghp
8481fd38ce fix #4933 2025-09-13 09:54:28 +08:00
jxxghp
5f425129d5 fix #4934 2025-09-13 09:46:04 +08:00
jxxghp
92955b1315 fix:在fork进程中执行文件整理 2025-09-13 08:56:05 +08:00
jxxghp
a3872d5bb5 fix:在fork进程中执行文件整理 2025-09-13 08:50:20 +08:00
jxxghp
a123ff2c04 feat:在fork进程中执行文件整理 2025-09-13 08:32:31 +08:00
jxxghp
188de34306 mini chunk size 2025-09-12 21:45:26 +08:00
jxxghp
3d43750e9b fix async event 2025-09-10 17:33:12 +08:00
jxxghp
fea228c68d add SUPERUSER_PASSWORD 2025-09-10 15:42:17 +08:00
jxxghp
a71a28e563 更新 config.py 2025-09-10 07:00:10 +08:00
jxxghp
3b5d4982b5 add wizard flag 2025-09-09 13:50:11 +08:00
jxxghp
b201e9ab8c Revert "feat:在子进程中操作文件"
This reverts commit 4f304a70b7.
2025-09-08 17:23:25 +08:00
jxxghp
d30b9282fd fix alipan u115 error log 2025-09-08 17:13:01 +08:00
jxxghp
4f304a70b7 feat:在子进程中操作文件 2025-09-08 16:59:29 +08:00
jxxghp
59a54d4f04 fix plugin cache 2025-09-08 13:27:32 +08:00
jxxghp
1e94d794ed fix log 2025-09-08 12:12:00 +08:00
jxxghp
5bd210406b Merge pull request #4918 from cddjr/fix_4853 2025-09-08 11:36:41 +08:00
景大侠
e00514d36d fix: 将RSS中的发布日期转为本地时区 2025-09-08 11:28:08 +08:00
jxxghp
f013bf1931 fix 2025-09-08 10:59:28 +08:00
jxxghp
107cbbad1d fix 2025-09-08 10:54:45 +08:00
jxxghp
481f1f9d30 add full gc scheduler 2025-09-08 10:49:09 +08:00
jxxghp
704364061c fix redis test 2025-09-08 09:59:11 +08:00
jxxghp
c1bd2d6cf1 fix:优化下载 2025-09-08 09:50:08 +08:00
jxxghp
a018e1228c Merge pull request #4904 from DDS-Derek/fix_gosu 2025-09-05 21:40:41 +08:00
DDSRem
d962d9c7f6 feat(docker): add START_NOGOSU mode
fix https://github.com/jxxghp/MoviePilot/issues/4889
2025-09-05 21:30:59 +08:00
jxxghp
4ea28cbca5 fix #4902 2025-09-05 21:09:05 +08:00
jxxghp
1b48b8b4cc Merge pull request #4902 from DDS-Derek/dev 2025-09-05 20:06:42 +08:00
jxxghp
73df197e33 Merge pull request #4903 from imtms/v2 2025-09-05 20:05:28 +08:00
TMs
bdc66e55ca fix(LocalStorage): 添加源文件与目标文件相同的检查,防止文件被删除。 2025-09-05 20:02:37 +08:00
DDSRem
926343ee86 fix(u115): code logic vulnerabilities 2025-09-05 19:37:41 +08:00
DDSRem
8e6021c5e7 fix(u115): code logic vulnerabilities 2025-09-05 19:23:23 +08:00
jxxghp
ac2b6c76ce 更新 version.py 2025-09-05 12:04:26 +08:00
jxxghp
9e966d0a7f Merge pull request #4898 from wumode/fix_alist 2025-09-04 21:16:58 +08:00
wumode
6c10defaa1 fix(Alist): add type hints 2025-09-04 21:08:25 +08:00
wumode
b6a76f6f7c fix(Alist): 添加__len__() 2025-09-04 20:47:13 +08:00
jxxghp
84e5b77a5c rollback orjson 2025-09-04 11:53:39 +08:00
jxxghp
89b0ea0bf1 remove monitoring 2025-09-04 11:23:22 +08:00
jxxghp
48aeb98bf1 add orjson 2025-09-04 08:52:36 +08:00
jxxghp
8a5d864812 更新 config.py 2025-09-04 08:28:42 +08:00
jxxghp
ae79e645a6 Merge pull request #4893 from Aqr-K/feat-plugin-wheels 2025-09-03 14:30:01 +08:00
Aqr-K
0947deb372 fix plugin.py 2025-09-03 14:27:24 +08:00
jxxghp
69c92911a2 更新 category.yaml 2025-09-03 14:26:40 +08:00
jxxghp
b16bb37b75 Merge pull request #4892 from Aqr-K/feat-plugin-wheels 2025-09-03 14:21:08 +08:00
Aqr-K
9c9ec8adf2 feat(plugin): Implement robust dependency installation with embedded wheels
- 通过在插件中嵌入轮子来支持安装依赖项
2025-09-03 14:13:32 +08:00
jxxghp
eb0e67fc42 fix logging 2025-09-03 12:42:13 +08:00
jxxghp
9cc50bddab Merge pull request #4764 from 2Dou/v2 2025-09-03 12:01:37 +08:00
jxxghp
d3ba0fa487 更新 category.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-09-03 11:58:07 +08:00
jxxghp
39f6505a80 fix:优化参数、使用orjson 2025-09-03 09:51:24 +08:00
jxxghp
36a6802439 fix:#4876 2025-09-02 12:45:44 +08:00
jxxghp
d7e2633a92 fix:移除更新阻断 2025-09-02 12:16:45 +08:00
jxxghp
88049e741e add SUBSCRIBE_SEARCH_INTERVAL 2025-09-02 11:41:52 +08:00
jxxghp
ff7fb14087 fix cache_clear 2025-09-02 08:35:48 +08:00
jxxghp
816c64bd48 Merge pull request #4883 from cikezhu/v2 2025-09-01 18:32:21 +08:00
cikezhu
d2756e6f2d schedule() # 这会返回一个协程对象,但我们没有等待它 2025-09-01 17:39:46 +08:00
jxxghp
147e12acbb Merge pull request #4879 from sebastian0619/v2 2025-08-31 19:04:38 +08:00
jxxghp
4098018ee9 更新 entrypoint.sh
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-08-31 19:04:24 +08:00
Sebastian
133e7578b9 Update NGINX SSL port configuration 2025-08-31 17:17:26 +08:00
jxxghp
74a2bdbf09 Merge pull request #4872 from Aqr-K/feat/v2.7.8/string/natural_sort 2025-08-30 09:45:23 +08:00
Aqr-K
f22bc68af4 Update string.py 2025-08-30 08:59:35 +08:00
Aqr-K
26cc6da650 fix(storage): Adjust to use natural_stort_key 2025-08-30 08:48:38 +08:00
Aqr-K
d21f1f1b87 feat(string): add natural_sort_key function 2025-08-30 08:44:41 +08:00
jxxghp
7cdaafffe1 Merge pull request #4867 from aotuwuxi/hotfix/250829 2025-08-29 13:46:48 +08:00
jxxghp
0265dca197 Merge pull request #4866 from lostwindsenril/patch-1 2025-08-29 13:45:49 +08:00
wuxi
9d68366043 fix: 修复工作流调用插件无法获取到对象属性问题 2025-08-29 13:19:50 +08:00
lostwindsenril
c8c671d915 Update app/modules/indexer/spider/mtorrent.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-08-29 13:07:31 +08:00
lostwindsenril
142daa9d15 使馒头(m-team)支持剩余促销期检测
Add freedate to torrent if discountEndTime exists
2025-08-29 13:04:17 +08:00
jxxghp
2552219991 更新 version.py 2025-08-28 11:11:32 +08:00
jxxghp
a038b698d7 fix haidan 2025-08-28 09:36:19 +08:00
jxxghp
a3b222574e add thetvdb cache 2025-08-28 08:05:10 +08:00
jxxghp
e0cd467293 rollback fix #4856 2025-08-28 07:51:05 +08:00
jxxghp
9c056030d2 fix:捕促115&alipan请求异常 2025-08-27 20:21:06 +08:00
jxxghp
19efa9d4cc fix #4795 2025-08-27 16:15:45 +08:00
jxxghp
90633a6495 fix #4851 2025-08-27 15:57:43 +08:00
jxxghp
edc432fbd8 fix #4846 2025-08-27 12:45:23 +08:00
jxxghp
1b7bdbf516 fix #4834 2025-08-27 08:28:16 +08:00
jxxghp
8c1be70c85 更新 version.py 2025-08-26 12:20:16 +08:00
jxxghp
b8e0c0db9e feat:精细化事件错误 2025-08-26 08:41:47 +08:00
jxxghp
7b7fb6cc82 Merge pull request #4836 from jxxghp/cursor/alter-siteuser-data-userid-to-character-type-9f4d 2025-08-25 22:05:19 +08:00
Cursor Agent
62512ba215 Remove SQLite-specific migration code for userid field
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-25 14:00:33 +00:00
Cursor Agent
e1beb64c01 Simplify userid conversion to integer in Synology Chat module
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-25 13:58:15 +00:00
Cursor Agent
c81f26ddad Remove downgrade methods for PostgreSQL and SQLite userid migration
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-25 13:56:21 +00:00
Cursor Agent
340114c2a1 Remove migration README after completing SiteUserData userid type migration
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-25 13:54:58 +00:00
Cursor Agent
cd7767b331 Checkpoint before follow-up message
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-25 13:54:48 +00:00
Cursor Agent
25289dad8a Migrate SiteUserData userid field from Integer to String type
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-25 13:50:58 +00:00
jxxghp
47c6917129 remove _check_restart_policy 2025-08-25 21:30:53 +08:00
jxxghp
6379cda148 fix 异步定时服务 2025-08-25 21:19:07 +08:00
jxxghp
91a124ab8f fix 异步定时服务 2025-08-25 20:44:38 +08:00
jxxghp
2357a7135e fix run_async 2025-08-25 17:46:06 +08:00
jxxghp
da0b3b3de9 fix:日历缓存 2025-08-25 16:46:10 +08:00
jxxghp
6664fb1716 feat:增加插件和日历的自动缓存 2025-08-25 16:37:02 +08:00
jxxghp
1206f24fa9 修复缓存迭代时的并发问题 2025-08-25 13:11:44 +08:00
jxxghp
ffb5823e84 fix #4829 优化模块导入逻辑,增加对 Async 类的特殊处理 2025-08-25 08:14:43 +08:00
jxxghp
d45a7fb262 更新 version.py 2025-08-24 19:59:31 +08:00
jxxghp
918d192c0f OpenList自动延迟重试获取文件项 2025-08-24 19:47:00 +08:00
jxxghp
f7cd6eac50 feat:整理手动中止功能 2025-08-24 19:17:41 +08:00
jxxghp
88f4428ff0 fix bug 2025-08-24 17:07:45 +08:00
jxxghp
069ea22ba2 fix bug 2025-08-24 16:55:37 +08:00
jxxghp
8fac8c5307 fix progress step 2025-08-24 16:33:44 +08:00
jxxghp
2285befebb fix cache set 2025-08-24 16:10:48 +08:00
jxxghp
1cd0648e4e fix cache set 2025-08-24 15:36:56 +08:00
jxxghp
0b7ba285c6 fix:优雅停止超时处理 2025-08-24 13:07:52 +08:00
jxxghp
30446c4526 fix cache is_redis 2025-08-24 12:27:14 +08:00
jxxghp
9b843c9ed2 fix:整理记录登记 2025-08-24 12:19:12 +08:00
jxxghp
2ce1c3bef8 feat:整理进度登记 2025-08-24 12:04:05 +08:00
jxxghp
e463094dc7 feat:整理进度 2025-08-24 09:21:55 +08:00
jxxghp
71a9fe10f4 refactor ProgressHelper 2025-08-24 09:02:55 +08:00
jxxghp
ba146e13ef fix 优化cache模块声明 2025-08-24 08:36:37 +08:00
jxxghp
c060d7e3e0 更新 postgresql-setup.md 2025-08-23 22:26:34 +08:00
jxxghp
ba96678822 v2.7.5 2025-08-23 20:46:36 +08:00
jxxghp
4f6354f383 Merge pull request #4820 from DDS-Derek/dev 2025-08-23 18:46:52 +08:00
DDSRem
2766e80346 fix(database): use logger as log output
Co-Authored-By: Aqr-K <95741669+Aqr-K@users.noreply.github.com>
2025-08-23 18:36:11 +08:00
jxxghp
7cc3777a60 fix async cache 2025-08-23 18:34:47 +08:00
DDSRem
cb1dd9f17d fix(database): upgrade error in pg database
Co-Authored-By: Aqr-K <95741669+Aqr-K@users.noreply.github.com>
2025-08-23 18:12:13 +08:00
jxxghp
31f342fe4f fix torrent 2025-08-23 18:10:33 +08:00
jxxghp
e90359eb08 fix douban 2025-08-23 15:56:30 +08:00
jxxghp
58b0768a30 fix redis key 2025-08-23 15:53:03 +08:00
jxxghp
3b04506893 fix redis key 2025-08-23 15:40:38 +08:00
jxxghp
354165aa0a fix cache 2025-08-23 14:21:50 +08:00
jxxghp
343109836f fix cache 2025-08-23 14:06:44 +08:00
jxxghp
fcadac2adb Merge pull request #4817 from jxxghp/cursor/add-dict-operations-to-cachebackend-3877 2025-08-23 12:42:04 +08:00
Cursor Agent
5e7dcdfe97 Modify cache region key generation to use consistent prefix format
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-23 04:13:25 +00:00
Cursor Agent
2ec9a57391 Remove implementation and migration documentation files
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-23 04:07:04 +00:00
Cursor Agent
973c545723 Checkpoint before follow-up message
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-23 04:06:16 +00:00
Cursor Agent
fd62eecfef Simplify TTLCache, remove dict-like methods, enhance Cache interface
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-23 04:01:17 +00:00
Cursor Agent
b5ca7058c2 Add helper methods for cache backend in sync and async versions
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-23 03:58:04 +00:00
Cursor Agent
57a48f099f Add dict-like operations to CacheBackend with sync and async support
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-23 03:50:52 +00:00
jxxghp
4699f511bf Handle magnet links in torrent parsing and downloader modules (#4815)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-23 10:51:32 +08:00
jxxghp
cd8f7e72e0 同步错误修复 2025-08-22 17:33:24 +08:00
jxxghp
78803fa284 fix search_imdbid type 2025-08-22 16:37:30 +08:00
jxxghp
2e8d75df16 fix monitor cache 2025-08-22 15:30:49 +08:00
jxxghp
7e3bbfd960 Merge pull request #4807 from carolcoral/v2 2025-08-22 15:23:04 +08:00
jxxghp
1734d53b3c Replace file-based snapshot caching with FileCache implementation (#4809)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-22 13:59:30 +08:00
jxxghp
f37540f4e5 fix get_rss timeout 2025-08-22 11:44:16 +08:00
jxxghp
addb9d836a remove cache singleton 2025-08-22 11:33:53 +08:00
Carol
4184d8c7ac 补充迁移数据库异常的注意事项
add: sqlite迁移到postgresql的注意事项
2025-08-22 10:55:26 +08:00
jxxghp
724c15a68c add 插件内存统计API 2025-08-22 09:46:11 +08:00
jxxghp
499bdf9b48 fix cache clear 2025-08-22 07:22:23 +08:00
jxxghp
41cd1ccda1 Merge pull request #4803 from Sowevo/v2
兼容负数的LIMIT
2025-08-22 07:20:21 +08:00
jxxghp
b9521cb3a9 Fix typo: change "未就续" to "未就绪" in module status messages (#4804)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-22 07:05:16 +08:00
jxxghp
1f40663b90 Merge pull request #4802 from Aqr-K/remove-docker 2025-08-22 06:45:45 +08:00
sowevo
5261ed7c4c 兼容两种库对负数的处理 2025-08-22 03:32:26 +08:00
sowevo
aa8768b18a 兼容两种库对负数的处理 2025-08-22 03:00:50 +08:00
Aqr-K
aad07433f4 fix(docker): Remove musl-dev and related code 2025-08-22 01:20:50 +08:00
jxxghp
4a7630079b Merge pull request #4800 from DDS-Derek/dev 2025-08-21 22:18:16 +08:00
DDSRem
44a6ee1994 fix(docker): 作業ディレクトリが間違っています 2025-08-21 22:17:18 +08:00
jxxghp
56bd6e69ed Merge pull request #4799 from DDS-Derek/dev 2025-08-21 22:11:58 +08:00
DDSRem
d1e04588d0 feat(docker): refactor docker build process 2025-08-21 22:09:49 +08:00
jxxghp
21cdaef6d5 Merge pull request #4798 from DDS-Derek/dev 2025-08-21 21:57:49 +08:00
DDSRem
a1723d18fb fix(docker): 不要な権限設定を削除する 2025-08-21 21:54:33 +08:00
jxxghp
9e065138e9 fix cache default 2025-08-21 21:49:00 +08:00
jxxghp
1c73c92bfd fix cache Singleton 2025-08-21 21:45:34 +08:00
jxxghp
bcd560d74e Merge pull request #4797 from DDS-Derek/dev 2025-08-21 21:28:40 +08:00
DDSRem
02339562ed fix(docker): レイヤー数を減らす 2025-08-21 21:28:18 +08:00
DDSRem
e5804378c2 fix(docker): fuck ai bugs 2025-08-21 21:24:09 +08:00
jxxghp
da1c8a162d fix cache maxsize 2025-08-21 20:10:27 +08:00
jxxghp
d457a23a1f fix build 2025-08-21 19:24:04 +08:00
jxxghp
b6154e58b8 rollback dockerfile 2025-08-21 18:44:47 +08:00
jxxghp
5f18776c61 更新 douban_cache.py 2025-08-21 17:52:55 +08:00
jxxghp
68b0b9ec7a 更新 tmdb_cache.py 2025-08-21 17:52:19 +08:00
jxxghp
0f5036972e v2.7.4 2025-08-21 17:03:17 +08:00
jxxghp
0b199b8421 fix TTLCache 2025-08-21 16:54:49 +08:00
jxxghp
a59730f6eb 优化cache模块的默认值 2025-08-21 16:29:49 +08:00
jxxghp
c6c84fe65b rename 2025-08-21 16:02:50 +08:00
jxxghp
03c757bba6 fix TTLCache 2025-08-21 13:17:59 +08:00
jxxghp
bfeb8d238a fix build 2025-08-21 12:45:05 +08:00
jxxghp
daf0c08c4b remove 重复的 aiofiles 2025-08-21 12:33:51 +08:00
jxxghp
d12c1b9ac4 remove musl-dev 2025-08-21 12:32:53 +08:00
jxxghp
bc242f4fd4 fix yield 2025-08-21 12:04:15 +08:00
jxxghp
a240c1bca9 优化 Dockerfile 2025-08-21 09:47:23 +08:00
jxxghp
219aa6c574 Merge pull request #4790 from wikrin/delete_media_file 2025-08-21 09:35:07 +08:00
Attente
abca1b481a refactor(storage): 优化空目录删除逻辑
- 添加对资源目录和媒体库目录的保护机制
- 实现递归向上检查并删除空目录
2025-08-21 09:16:15 +08:00
jxxghp
db72fd2ef5 fix 2025-08-21 09:07:28 +08:00
jxxghp
31cca58943 fix cache 2025-08-21 08:26:32 +08:00
jxxghp
c06a4b759c fix redis 2025-08-21 08:14:21 +08:00
jxxghp
f05a23a490 更新 redis.py 2025-08-21 07:59:34 +08:00
jxxghp
1e0f2ffde0 更新 config.py 2025-08-21 07:48:16 +08:00
jxxghp
06df42ee3d 更新 Dockerfile 2025-08-21 07:21:58 +08:00
jxxghp
65ee1638f7 add VENV_PATH 2025-08-21 00:28:32 +08:00
jxxghp
87eefe7673 Merge pull request #4788 from jxxghp/cursor/install-playwright-dependencies-in-dockerfile-b7d6
Install playwright dependencies in dockerfile
2025-08-21 00:16:48 +08:00
Cursor Agent
5c124d3988 fix: use full path for playwright command in Dockerfile
- Fix 'playwright: not found' error during Docker build
- Use /bin/playwright instead of playwright to ensure
  the command is executed from the virtual environment
- This resolves the issue where playwright install-deps chromium
  was failing because playwright wasn't in the system PATH
2025-08-20 16:16:02 +00:00
jxxghp
8c69ce624f Merge pull request #4787 from jxxghp/cursor/optimize-docker-build-and-pip-environment-e8ad
Optimize docker build and pip environment
2025-08-21 00:08:50 +08:00
Cursor Agent
bb73acdde5 Checkpoint before follow-up message
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-20 16:06:39 +00:00
Cursor Agent
993bc3775b Checkpoint before follow-up message
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-20 16:04:44 +00:00
jxxghp
3d2ff28bcd fix download 2025-08-20 23:38:51 +08:00
jxxghp
9b78deb802 fix torrent 2025-08-20 23:07:29 +08:00
jxxghp
dadc525d0b feat:种子下载使用缓存 2025-08-20 22:03:18 +08:00
DDSRem
22b2140c94 fix requirement 2025-08-20 21:18:33 +08:00
jxxghp
f07496a4a0 fix cache 2025-08-20 21:11:10 +08:00
jxxghp
1b2938cbc8 Merge pull request #4785 from jxxghp/cursor/fix-postgresql-textual-sql-expression-error-e023 2025-08-20 20:13:56 +08:00
Cursor Agent
d4d2f58830 Checkpoint before follow-up message
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-20 12:10:52 +00:00
jxxghp
b3113e13ec refactor:新增文件缓存组合 2025-08-20 19:04:07 +08:00
jxxghp
055c8e26f0 refactor:重构缓存系统 2025-08-20 17:35:32 +08:00
jxxghp
2a7a7239d7 新增全局图片缓存配置和临时文件清理天数设置 2025-08-20 13:52:38 +08:00
jxxghp
2fa40dac3f 优化监控和消息服务的资源管理 2025-08-20 13:35:24 +08:00
jxxghp
6b4fbd7dc2 新增 PostgreSQL 和 Redis 数据库模块,包含模块初始化、连接测试等功能 2025-08-20 13:35:12 +08:00
jxxghp
5b0bb19717 统一使用 app.core.cache 中的 TTLCache 2025-08-20 12:43:30 +08:00
jxxghp
843dfc430a fix log 2025-08-20 09:36:46 +08:00
jxxghp
69cb07c527 优化缓存机制,支持Redis和本地缓存的切换 2025-08-20 09:16:30 +08:00
jxxghp
89e8a64734 重构Redis缓存机制 2025-08-20 08:51:03 +08:00
jxxghp
5eb2dec32d 新增 RedisHelper 类 2025-08-20 08:50:45 +08:00
jxxghp
db0ea7d6c4 Fix database sequence errors (#4777)
* Fix database upgrade script to handle existing identity columns

Co-authored-by: jxxghp <jxxghp@live.cn>

* Improve identity column conversion with error handling and cleanup

Co-authored-by: jxxghp <jxxghp@live.cn>

* Fix database upgrade script to handle existing identity columns

Co-authored-by: jxxghp <jxxghp@live.cn>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: jxxghp <jxxghp@live.cn>
2025-08-20 00:29:35 +08:00
jxxghp
1eb85003de 更新 version.py 2025-08-19 17:58:27 +08:00
jxxghp
cca170f84a 更新 emby.py 2025-08-19 15:30:22 +08:00
jxxghp
c8c016caa8 更新 __init__.py 2025-08-19 14:27:02 +08:00
jxxghp
45d5874026 更新 __init__.py 2025-08-19 14:20:46 +08:00
jxxghp
69b1ce60ff fix db config 2025-08-19 14:15:33 +08:00
jxxghp
3ff3e4b106 fix db config 2025-08-19 14:05:24 +08:00
jxxghp
dc50a68b01 修复数据库表名引用 2025-08-19 12:54:47 +08:00
jxxghp
968cfd8654 fix db 2025-08-19 12:41:07 +08:00
jxxghp
cf28d93be6 fix db 2025-08-19 12:35:52 +08:00
jxxghp
be08d6ebb5 fix db 2025-08-19 12:02:53 +08:00
jxxghp
4bc24f3b00 fix db 2025-08-19 11:53:59 +08:00
jxxghp
15833f94cf fix db 2025-08-19 11:40:34 +08:00
jxxghp
aeb297efcf 优化站点激活状态的判断逻辑,简化数据库查询条件 2025-08-19 11:23:09 +08:00
jxxghp
d48c6b98e8 rollback local postgresql 2025-08-19 08:30:07 +08:00
jxxghp
b79ccfafed 优化 entrypoint.sh 中 PostgreSQL 命令的执行方式 2025-08-19 07:15:02 +08:00
jxxghp
c87ba59552 更新 entrypoint.sh 2025-08-18 22:42:55 +08:00
jxxghp
91fd71c858 fix entrypoint.sh 2025-08-18 22:26:01 +08:00
jxxghp
6f64e67538 fix dockerfile 2025-08-18 21:42:44 +08:00
jxxghp
bd7a0b072f fix entrypoint.sh 2025-08-18 21:22:29 +08:00
jxxghp
01ca001c97 fix entrypoint.sh 2025-08-18 21:10:24 +08:00
jxxghp
324ad2a87c 优化 PostgreSQL 数据目录初始化和启动逻辑 2025-08-18 20:55:33 +08:00
jxxghp
d9ad2630f0 fix postgresql 2025-08-18 19:14:47 +08:00
jxxghp
83958a4a48 fix postgresql 2025-08-18 19:12:20 +08:00
jxxghp
f6a6efdc42 fix app.env 2025-08-18 15:17:26 +08:00
jxxghp
1bbe7657b9 fix dockerfile 2025-08-18 11:42:53 +08:00
jxxghp
38189753b5 在构建工作流中添加新的 Docker 镜像配置 2025-08-18 11:31:00 +08:00
jxxghp
5b0e658617 重构配置文件项目顺序 2025-08-18 11:29:04 +08:00
jxxghp
b6cf54d57f 添加对 PostgreSQL 的支持 2025-08-18 11:19:17 +08:00
jxxghp
e8058c8813 添加 PostgreSQL 数据库支持 2025-08-18 11:19:06 +08:00
jxxghp
784868048d 更新 scheduler.py 2025-08-18 07:04:39 +08:00
jxxghp
2bf9779f2f v2.7.2 2025-08-17 11:44:59 +08:00
jxxghp
d98ceea381 fix #4768 2025-08-17 11:44:09 +08:00
jxxghp
1ab2da74b9 use apipathlib 2025-08-17 09:00:02 +08:00
jxxghp
086b1f1403 更新 message.py 2025-08-16 17:27:45 +08:00
2Dou
3723cf8ac2 二级分类配置增加排除功能 2025-08-15 09:54:56 +08:00
jxxghp
19608fa98e Merge pull request #4756 from Sowevo/v2 2025-08-13 17:40:31 +08:00
sowevo
b0d17deda1 从 TMDB 相对链接中解析数值 ID。 2025-08-13 17:11:56 +08:00
sowevo
4c979c458e 从 TMDB 相对链接中解析数值 ID。 2025-08-13 16:54:06 +08:00
jxxghp
c5e93169ad 更新 subscribe_oper.py 2025-08-13 10:10:42 +08:00
jxxghp
1e2ca294de Merge pull request #4747 from Pollo3470/fix-flaresolverr-proxy 2025-08-12 16:59:31 +08:00
Pollo
7165c4a275 fix: 代理需要认证时,flaresolverr使用session 2025-08-12 16:33:51 +08:00
Pollo
cbe81ba33c fix: 修复调用flaresolverr时未将代理认证信息传入的问题 2025-08-12 16:12:22 +08:00
jxxghp
fdbfae953d fix #4741 FlareSolverr使用站点设置的超时时间,未设置时默认60秒
close #4742
close https://github.com/jxxghp/MoviePilot-Frontend/pull/378
2025-08-12 08:04:29 +08:00
jxxghp
c7ba274877 更新 browser.py 2025-08-11 23:35:05 +08:00
jxxghp
8b15a16ca1 更新 browser.py 2025-08-11 22:20:22 +08:00
jxxghp
9f2c8d3811 v2.7.1 2025-08-11 21:51:34 +08:00
jxxghp
7343dfbed8 fix hddolby 2025-08-11 21:41:56 +08:00
jxxghp
90f74d8d2b feat:支持FlareSolverr 2025-08-11 21:14:46 +08:00
jxxghp
7e3e0e1178 fix #4725 2025-08-11 18:29:29 +08:00
jxxghp
d890e38a10 fix #4724 2025-08-11 17:46:46 +08:00
jxxghp
e505b5c85f fix #4733 2025-08-11 16:41:29 +08:00
jxxghp
6230f55116 fix #4734 2025-08-11 16:34:36 +08:00
jxxghp
c8d0c14ebc 更新 plex.py 2025-08-11 13:57:03 +08:00
jxxghp
6ac8455c74 fix 2025-08-11 13:30:15 +08:00
jxxghp
143b21631f Merge pull request #4737 from baozaodetudou/nginx 2025-08-11 13:27:23 +08:00
doumao
d760facad8 nginx cache js bug 2025-08-11 13:13:29 +08:00
jxxghp
3a1a4c5cfe 更新 download.py 2025-08-10 22:15:30 +08:00
jxxghp
c3045e2cd4 更新 mtorrent.py 2025-08-10 22:10:11 +08:00
jxxghp
1efb9af7ab 更新 nginx.common.conf 2025-08-10 21:32:53 +08:00
jxxghp
e03471159a 更新 version.py 2025-08-10 18:45:40 +08:00
jxxghp
a92e493742 fix README 2025-08-10 14:01:26 +08:00
jxxghp
225d413ed1 fix README 2025-08-10 13:52:35 +08:00
jxxghp
184e4ba7d5 fix 插件Release安装逻辑 2025-08-10 13:26:22 +08:00
jxxghp
917cae27b1 更新插件release安装逻辑 2025-08-10 13:06:03 +08:00
jxxghp
60e0463051 fix 2025-08-10 12:53:42 +08:00
jxxghp
c15022c7d5 fix:插件通过release安装 2025-08-10 12:45:38 +08:00
jxxghp
2a84e3a606 feat: 插件异步安装 2025-08-10 10:10:30 +08:00
jxxghp
fddbbd5714 feat:插件通过release安装 2025-08-10 10:00:13 +08:00
jxxghp
51b8f7c713 fix #4721 2025-08-10 09:11:44 +08:00
jxxghp
e97c246741 try fix #4716 2025-08-10 09:04:20 +08:00
jxxghp
9a81f55ac0 fix #4510 2025-08-10 08:51:52 +08:00
jxxghp
a38b702acc fix alist 2025-08-10 08:46:29 +08:00
jxxghp
e4e0605e92 更新 metavideo.py 2025-08-08 10:19:21 +08:00
jxxghp
8875a8f12c 更新 nginx.common.conf 2025-08-07 11:42:52 +08:00
jxxghp
4dd1deefa5 Merge pull request #4709 from wikrin/v2 2025-08-07 06:54:24 +08:00
Attente
1f6dc93ea3 fix(transfer): 修复目录监控下意外删除未完成种子的问题
- 如果种子尚未下载完成,则直接返回 False
2025-08-06 23:13:01 +08:00
jxxghp
426e920fff fix log 2025-08-06 16:54:24 +08:00
jxxghp
1f6bbce326 fix:优化重试识别次数限制 2025-08-06 16:48:37 +08:00
jxxghp
41f89a35fa 切换v2 release为最新 2025-08-06 16:36:29 +08:00
jxxghp
099d7874d7 - 修复日志滚动问题 2025-08-06 16:32:54 +08:00
jxxghp
e2367103a1 - 修复日志滚动问题 2025-08-06 16:29:51 +08:00
jxxghp
37f8ba7d72 fix #4705 2025-08-06 16:24:47 +08:00
jxxghp
c20bd84edd fix plex error 2025-08-06 12:21:02 +08:00
jxxghp
b4ee0d2487 Merge remote-tracking branch 'origin/v2' into v2 2025-08-05 20:14:06 +08:00
jxxghp
420fa7645f mask key 2025-08-05 20:14:00 +08:00
jxxghp
5bb1e72760 Update README.md 2025-08-05 19:37:51 +08:00
jxxghp
e2a007b62a Update README.md 2025-08-05 19:37:33 +08:00
jxxghp
210813367f fix #4694 2025-08-04 20:50:06 +08:00
jxxghp
770a50764e 更新 transferhistory.py 2025-08-04 19:39:51 +08:00
jxxghp
e339a22aa4 更新 version.py 2025-08-04 19:04:32 +08:00
jxxghp
913afed378 fix #4700 2025-08-04 12:19:24 +08:00
jxxghp
db3efb4452 fix SiteStatistic 2025-08-04 08:34:31 +08:00
jxxghp
840351acb7 fix Subscribe api 2025-08-04 07:05:23 +08:00
jxxghp
da76a7f299 Merge pull request #4693 from wumode/fix_4691 2025-08-03 15:40:19 +08:00
wumode
cbd999f88d Update app/modules/qbittorrent/qbittorrent.py
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-08-03 14:12:57 +08:00
wumode
2fa8a266c5 fix:#4691 2025-08-03 13:56:58 +08:00
jxxghp
08aa749a53 更新 subscribe.py 2025-08-02 20:06:26 +08:00
jxxghp
2379f04d2a Merge pull request #4689 from wikrin/v2 2025-08-02 19:48:59 +08:00
Attente
0e73598d1c refactor(transfer): 优化移动模式下种子文件的删除逻辑
- 重构了种子文件删除相关的代码,简化了逻辑
- 新增了 _is_blocked_by_exclude_words 方法,用于检查文件是否被屏蔽
- 新增了 _can_delete_torrent 方法,用于判断是否可以删除种子文件
2025-08-02 19:42:34 +08:00
jxxghp
964e6eb0e8 Merge pull request #4688 from Pollo3470/v2 2025-08-02 16:34:27 +08:00
Pollo
0430e6c6d4 fix: 修复使用socks代理时请求失败的问题 2025-08-02 16:20:52 +08:00
jxxghp
db88358eca 更新 webhook.py 2025-08-02 15:57:08 +08:00
jxxghp
723e9b0018 更新 version.py 2025-08-02 15:05:39 +08:00
jxxghp
f3db27a8da fix SiteStatistic note 2025-08-02 14:23:16 +08:00
jxxghp
0fb7a73fc9 fix RetryException 2025-08-02 11:32:42 +08:00
jxxghp
418e6bd085 fix cache_clear 2025-08-02 10:29:11 +08:00
jxxghp
5a5c4ace6b fix 实时日志性能 2025-08-02 10:24:46 +08:00
jxxghp
c2c8214075 refactor: 添加订阅协程处理 2025-08-02 09:14:38 +08:00
jxxghp
e5d2ade6e6 fix 协程环境中调用插件同步函数处理 2025-08-02 08:41:44 +08:00
jxxghp
e32b6e07b4 fix async apis 2025-08-01 20:27:22 +08:00
jxxghp
cc69d3b8d1 更新 __init__.py 2025-08-01 18:05:06 +08:00
jxxghp
1dd3af44b5 add FastApi实时性能监控 2025-08-01 17:47:55 +08:00
jxxghp
8ab233baef fix bug 2025-08-01 16:39:40 +08:00
jxxghp
104138b9a7 fix:减少无效搜索 2025-08-01 15:18:05 +08:00
jxxghp
0c8fd5121a fix async apis 2025-08-01 14:19:34 +08:00
jxxghp
61f26d331b add MAX_SEARCH_NAME_LIMIT default 2 2025-08-01 12:33:54 +08:00
jxxghp
97817cd808 fix tmdb async 2025-08-01 12:05:08 +08:00
jxxghp
45bcc63c06 fix rate_limit async 2025-08-01 11:48:37 +08:00
jxxghp
00779d0f10 fix search async 2025-08-01 11:38:23 +08:00
jxxghp
d657bf8ed8 feat:协程搜索 part3 2025-08-01 08:40:25 +08:00
jxxghp
4fcdd05e6a fix indexer async 2025-08-01 08:28:19 +08:00
jxxghp
e6916946a9 fix log && run_in_threadpool 2025-08-01 07:10:02 +08:00
jxxghp
acd7013dc6 fix site 2025-07-31 21:43:55 +08:00
jxxghp
039d876e3f feat:协程搜索 part2 2025-07-31 21:39:36 +08:00
jxxghp
3fc2c7d6cc feat:协程搜索 part2 2025-07-31 21:26:55 +08:00
jxxghp
109164b673 feat:协程搜索 part1 2025-07-31 20:51:39 +08:00
jxxghp
673a03e656 feat:查询本地是否存在 使用协程 2025-07-31 20:19:28 +08:00
jxxghp
1e976e6d96 fix db 2025-07-31 19:52:07 +08:00
jxxghp
8efba30adb fix db 2025-07-31 19:51:48 +08:00
jxxghp
713d44eac3 feat:实现非阻塞文件日志处理 2025-07-31 19:34:50 +08:00
jxxghp
aea44c1d97 feat:键式事件协程处理 2025-07-31 17:27:15 +08:00
jxxghp
1e61e60d73 feat:插件查询协程处理 2025-07-31 16:58:54 +08:00
jxxghp
a0e4b4a56e feat:媒体查询协程处理 2025-07-31 15:24:50 +08:00
jxxghp
983f8fcb03 fix httpx 2025-07-31 13:51:43 +08:00
jxxghp
6afdde7dc1 discover更新为异步实现 2025-07-31 13:36:43 +08:00
jxxghp
6873de7243 fix async 2025-07-31 13:32:47 +08:00
jxxghp
ee4d6d0db3 fix cache 2025-07-31 09:55:47 +08:00
jxxghp
dee1212a76 feat:推荐使用异步API 2025-07-31 09:50:49 +08:00
jxxghp
ceda69aedd add async apis 2025-07-31 09:15:38 +08:00
jxxghp
75ea7d7601 add async api 2025-07-31 09:10:45 +08:00
jxxghp
8b75d2312c add async run_module 2025-07-31 08:56:32 +08:00
jxxghp
ca51880798 fix themoviedb api 2025-07-31 08:40:24 +08:00
jxxghp
8b708e8939 fix themoviedb api 2025-07-31 08:34:47 +08:00
jxxghp
b6ff9f7196 fix douban api 2025-07-31 08:18:00 +08:00
jxxghp
67229fd032 fix 2025-07-31 08:11:27 +08:00
jxxghp
d382eab355 fix subscribe helper 2025-07-31 07:26:58 +08:00
jxxghp
d8f10e9ac4 fix workflow helper 2025-07-31 07:17:05 +08:00
jxxghp
749aaeb003 fix async 2025-07-31 07:07:14 +08:00
jxxghp
c5a3bbcecf 更新 subscribe.py 2025-07-31 00:11:40 +08:00
jxxghp
27ac41531b 更新 subscribe.py 2025-07-30 23:46:21 +08:00
jxxghp
423c9af786 为TheMovieDb模块添加异步支持(part 1) 2025-07-30 22:28:12 +08:00
jxxghp
232759829e 为Bangumi和Douban模块添加异步API支持 2025-07-30 22:18:11 +08:00
jxxghp
71f7bc7b1b fix 2025-07-30 21:06:55 +08:00
jxxghp
ae4f03e272 fix logging api 2025-07-30 21:01:28 +08:00
jxxghp
acb5a7e50b fix 2025-07-30 19:59:25 +08:00
jxxghp
c8749b3c9c add aiopath 2025-07-30 19:49:59 +08:00
jxxghp
49647e3bb5 fix asyncio sleep 2025-07-30 18:53:23 +08:00
jxxghp
48d353aa90 fix async oper 2025-07-30 18:48:50 +08:00
jxxghp
edec18cacb fix 2025-07-30 18:37:16 +08:00
jxxghp
cd8661abc1 重构工作流相关API,支持异步操作并引入异步数据库管理 2025-07-30 18:21:13 +08:00
jxxghp
5f6310f5d6 fix httpx proxy 2025-07-30 17:34:09 +08:00
jxxghp
42d955b175 重构订阅和用户相关API,支持异步操作 2025-07-30 15:23:25 +08:00
jxxghp
21541bc468 更新历史记录相关API,支持异步操作 2025-07-30 14:27:38 +08:00
jxxghp
f14f4e1e9b 添加异步数据库支持,更新相关模型和会话管理 2025-07-30 13:18:45 +08:00
jxxghp
6d1de8a2e4 add db异步转换器 2025-07-30 08:59:11 +08:00
jxxghp
0053d31f84 add db异步转换器 2025-07-30 08:54:04 +08:00
jxxghp
f077a9684b 添加异步请求工具类;优化fetch_image和proxy_img函数为异步实现提升性能 2025-07-30 08:30:24 +08:00
jxxghp
2428d58e93 使用aiofiles实现异步文件操作,提升性能;调整uvicorn工作进程数量。 2025-07-30 07:56:56 +08:00
jxxghp
5340e3a0a7 fix 2025-07-28 16:55:22 +08:00
jxxghp
70dd8f0f1d 更新 version.py 2025-07-28 15:15:56 +08:00
jxxghp
8fa76504c3 fix 2025-07-28 08:13:39 +08:00
jxxghp
0899cb4e1d fix 2025-07-28 08:11:39 +08:00
jxxghp
ee7a2a70a6 Merge pull request #4666 from wumode/refactor_polling_observer 2025-07-27 16:15:33 +08:00
wumode
d57d1ac15e fix: bug 2025-07-27 14:58:11 +08:00
wumode
68c29d89c9 refactor: polling_observer 2025-07-27 12:45:57 +08:00
jxxghp
721648ffdf fix #4653 2025-07-26 23:04:40 +08:00
jxxghp
8437f39bf6 fix #4655 2025-07-26 22:59:37 +08:00
jxxghp
48b15c60e7 Merge pull request #4658 from jnwan/v2 2025-07-25 14:06:22 +08:00
jnwan
e350122125 Add flag to ignore check folder modtime for rclone snapshot 2025-07-24 21:34:17 -07:00
jxxghp
0cce97f373 remove gc 2025-07-25 11:47:41 +08:00
jxxghp
d8cacc0811 fix:没有订阅不跑订阅刷新任务 2025-07-24 11:08:47 +08:00
jxxghp
7abaf70bb8 fix workflow 2025-07-24 09:54:46 +08:00
jxxghp
232fe4d15e fix dead lock 2025-07-23 17:03:50 +08:00
jxxghp
d6d12c0335 feat: 添加事件类型中文名称翻译字典 2025-07-23 15:35:04 +08:00
jxxghp
8e4f12804b Merge pull request #4648 from hyuan280/v2 2025-07-23 15:09:05 +08:00
jxxghp
c21ba5c521 Merge pull request #4649 from roukaixin/v2 2025-07-23 15:07:44 +08:00
jxxghp
dfa3d47261 更新 plugin.py 2025-07-23 06:50:01 +08:00
jxxghp
924f59afff fix bug 2025-07-22 21:02:02 +08:00
roukaixin
673b282d6c Merge branch 'jxxghp:v2' into v2 2025-07-22 20:48:29 +08:00
roukaixin
1c761f89e5 fix: 修复TZ环境变量不生效 2025-07-22 20:46:57 +08:00
jxxghp
f61cd969b9 fix 2025-07-22 20:46:42 +08:00
jxxghp
e39a130306 feat:工作流支持事件触发 2025-07-22 20:23:53 +08:00
黄渊
13b6ea985e fix: 浏览资源时分类可能不生效,使用split后再对比分类id 2025-07-22 19:02:25 +08:00
jxxghp
2f1e55fa1e 增加搜索次数统计和强制休眠机制以优化搜索性能 2025-07-21 12:25:52 +08:00
jxxghp
776f629771 fix User-Agent 2025-07-20 15:50:45 +08:00
jxxghp
d9e9edb2c4 Update version.py 2025-07-20 13:32:54 +08:00
jxxghp
753c074e59 fix #4625 2025-07-20 12:45:53 +08:00
jxxghp
d92c82775a fix #4637 2025-07-20 12:28:12 +08:00
jxxghp
215cc09c1f fix 2025-07-20 11:50:44 +08:00
jxxghp
7f302c13c7 fix #4632 2025-07-20 09:14:47 +08:00
jxxghp
de6a094d10 fix display 2025-07-20 08:49:21 +08:00
jxxghp
a94e1a8314 Merge pull request #4631 from ChanningHe/fix-telegram-msg 2025-07-18 21:22:17 +08:00
ChanningHe
f5efdd665b fix: 清理Telegram消息中的@bot部分以确保一致性处理 2025-07-18 21:59:04 +09:00
jxxghp
43e25e8717 fix share cache 2025-07-18 17:36:28 +08:00
ChanningHe
a8026fefc1 fix: 在Telegram chat中只有被at时检测 2025-07-18 17:55:43 +09:00
ChanningHe
fdb36957c9 fix: Telegram 机器人消息无法推送到群组,只能推送到userid 2025-07-18 17:40:06 +09:00
jxxghp
ea433ff807 add site api 2025-07-18 08:04:05 +08:00
jxxghp
8902fb50d6 更新 context.py 2025-07-16 22:22:45 +08:00
jxxghp
b6aa013eb3 v2.6.6 2025-07-16 20:25:43 +08:00
jxxghp
034b43bf70 fix context 2025-07-16 19:59:06 +08:00
jxxghp
59e9032286 add subscribe share statistic api 2025-07-16 08:47:54 +08:00
jxxghp
52a98efd0a add subscribe share statistic api 2025-07-16 08:31:28 +08:00
jxxghp
90cc91aa7f Merge pull request #4614 from Aqr-K/feature-ua 2025-07-15 06:47:34 +08:00
Aqr-K
1973a26e83 fix: 去除冗余代码,简化写法 2025-07-14 22:19:48 +08:00
Aqr-K
6519ad25ca fix is_aarch 2025-07-14 22:17:04 +08:00
Aqr-K
cacfde8166 fix 2025-07-14 22:14:52 +08:00
Aqr-K
df85873726 feat(ua): add cup_arch , USER_AGENT value add cup_arch 2025-07-14 22:04:09 +08:00
jxxghp
dfea294cc9 fix ua 2025-07-14 13:42:49 +08:00
jxxghp
d35b855404 fix ua 2025-07-14 13:30:18 +08:00
jxxghp
7a1cbf70e3 feat:特定默认UA 2025-07-14 12:35:08 +08:00
jxxghp
f260990b86 更新 version.py 2025-07-13 15:14:10 +08:00
jxxghp
6affbe9b55 fix #4558 2025-07-13 15:04:41 +08:00
jxxghp
dbe3a10697 fix 2025-07-13 14:53:39 +08:00
jxxghp
3c25306a5d fix #4590 2025-07-13 14:43:48 +08:00
jxxghp
17f4d49731 fix #4594 2025-07-13 14:24:41 +08:00
jxxghp
e213b5cc64 Merge branch 'v2' of https://github.com/jxxghp/MoviePilot into v2 2025-07-13 14:14:26 +08:00
jxxghp
65e5dad44b 优化移动模式下的种子和残留目录删除逻辑 2025-07-13 14:14:24 +08:00
jxxghp
62ad38ea5d Merge pull request #4605 from wikrin/torrent_optimize 2025-07-13 13:25:35 +08:00
Attente
f98f4c1f77 refactor(helper): 优化 TorrentHelper 类
- 添加检查临时目录中是否存在种子文件
- 修改 match_torrent 方法参数类型
- 优化种子文件下载和处理逻辑
2025-07-13 13:16:36 +08:00
jxxghp
e9f02b58b7 Merge pull request #4604 from cddjr/fix_4602 2025-07-13 06:51:36 +08:00
景大侠
05495e481d fix #4602 2025-07-13 01:10:07 +08:00
jxxghp
5bb2167b78 Merge pull request #4603 from cddjr/fix_nettest 2025-07-12 18:34:54 +08:00
景大侠
b4e0ed66cf 完善网络连通性测试的错误描述 2025-07-12 18:15:19 +08:00
jxxghp
70a0563435 add server_type return 2025-07-12 14:52:18 +08:00
jxxghp
955912b832 fix plex 2025-07-12 14:44:45 +08:00
jxxghp
b65ee75b3d Merge pull request #4601 from cddjr/minimal_deps 2025-07-11 21:46:13 +08:00
景大侠
f642493a38 fix 2025-07-11 21:25:10 +08:00
jxxghp
7f1bfb1e07 Merge pull request #4599 from jtcymc/v2 2025-07-11 21:12:16 +08:00
景大侠
8931e2e016 fix 仅安装用户需要使用的插件依赖 2025-07-11 21:04:33 +08:00
shaw
0465fa77c2 fix(filemanager): 检查目标媒体库目录是否设置
- 在文件整理过程中,增加对目标媒体库目录是否设置的检查- 如果目标媒体库目录未设置,返回错误信息并中断整理过程
- 优化了错误处理逻辑,提高了系统的稳定性和可靠性
2025-07-11 20:02:12 +08:00
jxxghp
575d503cb9 Merge pull request #4598 from cddjr/fix_4586 2025-07-11 18:12:57 +08:00
景大侠
a4fdbdb9ad fix 极空间、Unraid误报网络文件系统 2025-07-11 18:03:19 +08:00
jxxghp
b9cb781a4e rollback size 2025-07-11 08:34:02 +08:00
jxxghp
a3adf867b7 fix 2025-07-10 22:48:08 +08:00
jxxghp
d52cbd2f74 feat:资源下载事件保存路径 2025-07-10 22:16:19 +08:00
jxxghp
8d0003db94 更新 version.py 2025-07-10 11:57:54 +08:00
jxxghp
b775e89e77 fix #4581 2025-07-10 10:44:04 +08:00
jxxghp
0e14b097ba fix #4581 2025-07-10 10:39:22 +08:00
jxxghp
51848b8d8d fix #4581 2025-07-10 10:20:00 +08:00
jxxghp
72658c3e60 Merge pull request #4582 from cddjr/fix_rename_related 2025-07-09 20:42:54 +08:00
jxxghp
036cb6f3b0 remove memory helper 2025-07-09 19:11:37 +08:00
jxxghp
1a86d96bfa Merge pull request #4579 from jxxghp/cursor/bc-f8a13fbf-5ca0-4b0b-ae8d-59c208732d44-b74e 2025-07-09 17:43:46 +08:00
Cursor Agent
f67db38a25 Fix memory analysis performance and timeout issues across platforms
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-09 09:43:34 +00:00
Cursor Agent
028d18826a Refactor memory analysis with ThreadPoolExecutor for cross-platform timeout
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-09 09:38:06 +00:00
Cursor Agent
29a605f265 Optimize memory analysis with timeout, sampling, and performance improvements
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-09 08:57:22 +00:00
jxxghp
4b6959470d Merge pull request #4577 from jxxghp/cursor/analyze-memory-usage-discrepancies-6709 2025-07-09 16:08:00 +08:00
Cursor Agent
600767d2bf Remove memory analysis guide and test script
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-09 08:07:30 +00:00
Cursor Agent
3efbd47ffd Add comprehensive memory analysis tool with guide and test script
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-09 08:04:10 +00:00
Cursor Agent
d17e85217b Enhance memory analysis with detailed tracking, leak detection, and system insights
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-09 07:47:23 +00:00
jxxghp
e608089805 add Note Action 2025-07-09 12:22:22 +08:00
jxxghp
b852acec28 fix workflow 2025-07-09 09:34:53 +08:00
jxxghp
2a3ea8315d fix workflow 2025-07-09 00:19:47 +08:00
jxxghp
9271ee833c Merge pull request #4566 from jxxghp/cursor/helper-91dc
新增工作流分享相关接口和helper
2025-07-09 00:12:56 +08:00
Cursor Agent
570d4ad1a3 Fix workflow API by passing database session to WorkflowOper methods
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-08 15:44:55 +00:00
Cursor Agent
dccdf3231a Checkpoint before follow-up message 2025-07-08 15:42:31 +00:00
Cursor Agent
b8ee777fd2 Refactor workflow sharing with independent config and improved data access
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-08 15:33:43 +00:00
Cursor Agent
a2fd3a8d90 Implement workflow sharing feature with new API endpoints and helper
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-08 15:26:16 +00:00
Cursor Agent
bbffb1420b Add workflow sharing, forking, and related API endpoints
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-08 15:18:01 +00:00
景大侠
8ea0a32879 fix 优化重命名后的媒体文件根路径获取 2025-07-08 22:37:32 +08:00
景大侠
8c27b8c33e fix 文件管理的自动重命名缺少集信息 2025-07-08 22:37:09 +08:00
景大侠
5c61b22c2f fix 未启用重命名时,整理文件的转移路径不正确 2025-07-08 21:49:31 +08:00
jxxghp
9da9d765a0 fix:静态类引用 2025-07-08 21:40:04 +08:00
jxxghp
f64363728e fix:静态类引用 2025-07-08 21:38:34 +08:00
jxxghp
378777dc7c feat:弱引用单例 2025-07-08 21:29:01 +08:00
jxxghp
6156b9a481 Merge pull request #4561 from jxxghp/cursor/move-media-files-to-season-directory-6ee0 2025-07-08 18:00:50 +08:00
Cursor Agent
8c516c5691 Fix: Ensure parent item exists before saving NFO file
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-08 09:51:43 +00:00
Cursor Agent
bf9a149898 Fix TV show metadata scraping to use correct parent directory
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-08 09:31:35 +00:00
jxxghp
277cde8db2 更新 version.py 2025-07-08 12:17:57 +08:00
jxxghp
e06bdaf53e fix:资源包升级失败时一直重启的问题 2025-07-08 12:06:30 +08:00
jxxghp
da367bd138 fix spider 2025-07-08 11:25:36 +08:00
jxxghp
d336bcbf1f fix etree 2025-07-08 11:00:38 +08:00
jxxghp
a8aedba6ff fix https://github.com/jxxghp/MoviePilot/issues/4552 2025-07-08 09:34:24 +08:00
jxxghp
9ede86c6a3 Merge pull request #4555 from cddjr/fix_local_exists 2025-07-07 23:30:51 +08:00
景大侠
1468f2b082 fix 本地媒体文件检查时首选含影视标题的目录
避免了以年份、分辨率等作为重命名第一层目录时的误判问题
2025-07-07 23:24:04 +08:00
jxxghp
e04ae70f89 Merge pull request #4553 from cddjr/fix_trim_task 2025-07-07 22:15:12 +08:00
景大侠
7f7d2c9ba8 fix 飞牛刷新媒体库报错Task duplicate 2025-07-07 21:46:17 +08:00
jxxghp
d73deef8dc Merge pull request #4549 from cddjr/fix_tr 2025-07-07 17:28:28 +08:00
景大侠
f93a1540af fix TR模块报错找不到_protocol属性
v2.5.9引入的bug
2025-07-07 17:05:28 +08:00
jxxghp
c8bd9cb716 Merge pull request #4548 from cddjr/set_lock_timeout 2025-07-07 12:04:46 +08:00
景大侠
2ed13c7e5b fix 订阅匹配锁增加超时,避免罕见的长时间卡任务问题 2025-07-07 11:51:58 +08:00
jxxghp
647c0929c5 v2.6.2 2025-07-06 08:28:33 +08:00
jxxghp
a61533a131 Merge pull request #4536 from cddjr/fix_local_exists 2025-07-05 22:02:16 +08:00
景大侠
bc5e682308 fix 本地媒体检查潜在的额外扫盘问题 2025-07-05 21:46:21 +08:00
jxxghp
25a481df12 Merge pull request #4534 from jxxghp/cursor/bc-55af1137-dea1-4191-9033-64ea5fcaa43a-d338
修复文件整理快照处理问题
2025-07-05 15:44:51 +08:00
Cursor Agent
764c10fae4 Fix snapshot handling logic to correctly process files during monitoring
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-05 07:22:44 +00:00
Cursor Agent
d8249d4e38 Fix snapshot handling logic to correctly process files during monitoring
Co-authored-by: jxxghp <jxxghp@163.com>
2025-07-05 07:19:53 +00:00
jxxghp
0e3e42b398 Merge pull request #4531 from Aqr-K/feat-process 2025-07-05 06:33:57 +08:00
Aqr-K
7d3b64dcf9 Update requirements.in 2025-07-05 03:16:49 +08:00
Aqr-K
2c8d525796 feat: 增加进程名设置 2025-07-05 03:14:54 +08:00
jxxghp
4869f071ab fix error message 2025-07-04 21:34:31 +08:00
jxxghp
3029eeaf6f fix error message 2025-07-04 21:33:32 +08:00
jxxghp
33fb692aee 更新 plugin.py 2025-07-03 22:20:04 +08:00
jxxghp
6a075d144f 更新 version.py 2025-07-03 20:19:36 +08:00
jxxghp
aa23315599 rollback transmission-rpc 2025-07-03 19:16:36 +08:00
jxxghp
8d0bb35505 add 网络流量API 2025-07-03 19:05:43 +08:00
jxxghp
32e76bc6ce Merge pull request #4529 from cddjr/add_ctx_mgr_proto 2025-07-03 18:47:08 +08:00
景大侠
6c02766000 AutoCloseResponse支持上下文管理协议,避免部分插件报错 2025-07-03 18:38:48 +08:00
jxxghp
52ef390464 图片代理Api增加cache参数 2025-07-03 17:07:54 +08:00
jxxghp
43a557601e fix local usage 2025-07-03 16:48:35 +08:00
jxxghp
82ff7fc090 fix SMB Usage 2025-07-03 15:21:41 +08:00
jxxghp
db40b5105b 修正目录监控模式匹配 2025-07-03 13:55:54 +08:00
jxxghp
b2a379b84b fix SMB Storage 2025-07-03 12:41:44 +08:00
jxxghp
97cbd816fe add SMB Storage 2025-07-03 12:31:59 +08:00
jxxghp
7de3bb2a91 v2.6.0 2025-07-02 21:36:02 +08:00
jxxghp
3a8a2bcab4 Merge pull request #4519 from Aqr-K/patch-2 2025-07-01 19:46:12 +08:00
Aqr-K
eb1adbe992 fix: 错误文案修复,统一文案格式 2025-07-01 19:26:11 +08:00
jxxghp
b55966d42b Merge pull request #4516 from Aqr-K/feat-command
feat(command): 增加 `show` ,用来判断是否注册进菜单里显示
2025-07-01 17:20:59 +08:00
Aqr-K
451ca9cb5a feat(command): 增加 show ,用来判断是否注册进菜单里显示 2025-07-01 17:19:01 +08:00
jxxghp
1e2c607ced fix #4515 流平台不合并到现有标签中,如有需要通过命名模块配置 2025-07-01 17:02:29 +08:00
jxxghp
5ff7da0d19 fix #4515 流平台不合并到现有标签中,如有需要通过命名模块配置 2025-07-01 16:57:45 +08:00
jxxghp
8e06c6f8e6 remove openai 2025-07-01 14:48:16 +08:00
jxxghp
4497cd3904 add site stat api 2025-07-01 11:23:20 +08:00
jxxghp
2945679a94 - 修复Redis缓存问题及站点消息读取问题 2025-07-01 09:20:08 +08:00
jxxghp
1eaf7e3c85 Merge pull request #4513 from cddjr/fix_4511 2025-07-01 06:56:11 +08:00
景大侠
8146b680c6 fix: 修复AutoCloseResponse类在反序列化时无限递归 2025-07-01 01:29:01 +08:00
jxxghp
99e667382f fix #4509 2025-06-30 19:17:36 +08:00
jxxghp
4c03759d3f refactor:优化目录监控 2025-06-30 13:16:05 +08:00
jxxghp
8593a6cdd0 refactor:优化目录监控快照 2025-06-30 12:40:37 +08:00
jxxghp
cd18c31618 fix 订阅匹配 2025-06-30 10:55:10 +08:00
jxxghp
f29c918700 Merge pull request #4505 from wikrin/v2 2025-06-29 23:12:08 +08:00
Attente
0f0c3e660b style: 清理空白字符
移除代码中的 trailing whitespace 和空行缩进, 提升代码整洁度
2025-06-29 22:49:58 +08:00
Attente
1cf4639db3 fix(download): 修复手动下载时下载器选择问题
- 在手动下载模式下,始终使用用户选择的下载器
2025-06-29 22:24:53 +08:00
jxxghp
f5da9b5780 fix log 2025-06-29 22:10:47 +08:00
jxxghp
e4c87c8a96 更新 version.py 2025-06-29 21:56:37 +08:00
jxxghp
4b4bf153f0 fix plugin reload 2025-06-29 21:26:06 +08:00
jxxghp
ec227d0d56 Merge pull request #4500 from Miralia/v2
refactor(meta): 将 web_source 处理逻辑统一到 MetaBase 并添加到消息模板
2025-06-29 11:11:35 +08:00
Miralia
53c8c50779 refactor(meta): 将 web_source 处理逻辑统一到 MetaBase 并添加到消息模板 2025-06-29 11:08:34 +08:00
jxxghp
07b4c8b462 fix #4489 2025-06-29 11:06:36 +08:00
jxxghp
f3cfc5b9f0 fix plex 2025-06-29 08:27:48 +08:00
jxxghp
634e5a4c55 Merge pull request #4496 from wikrin/v2 2025-06-29 07:51:24 +08:00
Attente
332b154f15 fix(api): 适配 FastAPI 请求参数兼容性问题
修复系统配置和用户配置接口无法正常工作的问题。
2025-06-29 05:31:25 +08:00
jxxghp
b446d4db28 更新 GitHub 工作流配置,排除带有 RFC 标签的 issue 2025-06-28 22:24:51 +08:00
jxxghp
ce0397a140 fix update.sh 2025-06-28 22:03:18 +08:00
jxxghp
f278cccef3 for test 2025-06-28 21:42:28 +08:00
jxxghp
cbf1dbcd2e fix 恢复插件后安装依赖 2025-06-28 21:42:03 +08:00
jxxghp
037c6b02fa Merge pull request #4493 from Miralia/v2 2025-06-28 20:07:12 +08:00
Miralia
5f44e4322d Fix and add more 2025-06-28 19:47:33 +08:00
Miralia
6cebe97d6d add FPT Play 2025-06-28 19:12:00 +08:00
jxxghp
82ec146446 更新 plugin.py 2025-06-28 16:49:09 +08:00
jxxghp
3928c352c6 fix update 2025-06-28 15:01:25 +08:00
jxxghp
0ba36d21a9 Revert "fix security"
This reverts commit c7800df801.
2025-06-28 14:37:22 +08:00
jxxghp
6152727e9b fix Dockerfile 2025-06-28 14:33:33 +08:00
jxxghp
53c02fa706 resource v2 2025-06-28 14:26:14 +08:00
jxxghp
c7800df801 fix security 2025-06-28 14:12:24 +08:00
jxxghp
562c1de0c9 aList => OpenList 2025-06-28 08:43:09 +08:00
jxxghp
e2c90639f3 更新 message.py 2025-06-27 19:54:13 +08:00
jxxghp
92e175a8d1 Merge pull request #4488 from Miralia/v2 2025-06-27 17:29:10 +08:00
jxxghp
cf7bca75f6 fix res.text 2025-06-27 17:23:32 +08:00
Miralia
24a173f075 Update streamingplatform.py 2025-06-27 17:21:27 +08:00
jxxghp
8d695dda55 fix log 2025-06-27 17:16:08 +08:00
jxxghp
93eec6c4b8 fix cache 2025-06-27 15:24:57 +08:00
jxxghp
a2cc1a2926 upgrade packages 2025-06-27 14:34:35 +08:00
jxxghp
11729d0eca fix 2025-06-27 13:34:27 +08:00
jxxghp
978819be38 fix db pool size 2025-06-27 12:41:03 +08:00
jxxghp
23c9862eb3 fix site parser 2025-06-27 12:26:17 +08:00
jxxghp
a9f18ea3ef fix #4475 2025-06-27 10:05:19 +08:00
jxxghp
574257edf8 add SystemConfModel 2025-06-27 09:54:15 +08:00
jxxghp
bb4438ac42 feat:非大内存模式下主动gc 2025-06-27 09:44:47 +08:00
jxxghp
0baf6e5fe7 fix SiteParser close session 2025-06-27 08:38:02 +08:00
jxxghp
d8a53da8ee auto close RequestUtils 2025-06-27 08:30:57 +08:00
jxxghp
9555ac6305 fix RequestUtils 2025-06-27 08:09:38 +08:00
jxxghp
4dd5ea8e2f add del 2025-06-27 07:53:10 +08:00
jxxghp
8068523d88 fix downloader 2025-06-26 20:52:17 +08:00
jxxghp
27dd681d9f fix RequestUtils 2025-06-26 17:36:22 +08:00
jxxghp
152f814fb6 fix base chain 2025-06-26 13:28:11 +08:00
jxxghp
2700e639f1 fix chain 2025-06-26 13:16:10 +08:00
jxxghp
c440ce3045 fix oper 2025-06-26 08:33:43 +08:00
jxxghp
2829a3cb4e fix 2025-06-26 08:18:37 +08:00
jxxghp
a487091be8 Revert "fix resource helper"
This reverts commit e7524774da.
2025-06-25 13:32:28 +08:00
jxxghp
e7524774da fix resource helper 2025-06-25 12:50:00 +08:00
jxxghp
3918c876c5 Merge pull request #4478 from Miralia/v2 2025-06-24 21:07:55 +08:00
Miralia
f07f87735c fix 2025-06-24 19:52:14 +08:00
Miralia
b7566e8fe8 feat(meta): 扩展流媒体平台列表,增加更多平台支持。 2025-06-24 19:46:01 +08:00
jxxghp
73eba90f2f 更新 version.py 2025-06-24 10:34:42 +08:00
jxxghp
62e74f6fd1 fix 2025-06-24 08:19:10 +08:00
jxxghp
4375e48840 Merge pull request #4476 from Miralia/v2 2025-06-23 20:52:15 +08:00
Miralia
a1d6e94e90 feat(meta): 新增 WEB 平台来源识别并支持更多音视频格式。 2025-06-23 20:36:58 +08:00
jxxghp
1f44e13ff0 add reload logging 2025-06-23 10:14:22 +08:00
jxxghp
d2992f9ced fix plugin load 2025-06-23 09:31:56 +08:00
jxxghp
950337bccc fix plugin load 2025-06-23 08:19:22 +08:00
jxxghp
757c3be359 更新 version.py 2025-06-22 10:08:17 +08:00
jxxghp
269ab9adfc fix:删除消息能力 2025-06-22 10:04:21 +08:00
jxxghp
bd241a5164 feat:删除消息能力 2025-06-22 09:37:01 +08:00
jxxghp
3d92b57f24 fix 2025-06-22 09:04:03 +08:00
jxxghp
70d8cb3697 fix #4461 2025-06-22 08:51:29 +08:00
jxxghp
9e4ec5841c fix #4470 2025-06-22 08:47:43 +08:00
jxxghp
682f4fe608 fix message cache 2025-06-20 17:33:08 +08:00
jxxghp
ce8a077e07 优化按钮回调数据,简化为仅使用索引值 2025-06-19 15:54:07 +08:00
jxxghp
d5f63bcdb3 remove Commands DEV flag 2025-06-18 13:33:37 +08:00
jxxghp
5c3756fd1b v2.5.7-1 2025-06-17 20:02:45 +08:00
jxxghp
99939e1a3d fix 2025-06-17 19:42:16 +08:00
jxxghp
56742ace11 fix:带UA下载图片 2025-06-17 19:27:53 +08:00
jxxghp
742cb7a8da 更新 version.py 2025-06-17 18:56:47 +08:00
jxxghp
98327d1750 fix download message 2025-06-17 15:35:38 +08:00
jxxghp
b944306302 v2.5.7 2025-06-16 22:15:54 +08:00
jxxghp
02ab1d4111 fix settings 2025-06-16 21:29:57 +08:00
jxxghp
28552fb0ce 更新 transmission.py 2025-06-16 19:38:19 +08:00
jxxghp
bf52fcb2ec fix message 2025-06-16 11:45:26 +08:00
jxxghp
bab1f73480 修复:slack消息交互 2025-06-16 09:49:01 +08:00
jxxghp
c06001d921 feat:内建重启前主动备份插件 2025-06-16 08:57:21 +08:00
jxxghp
0fa49bb9c6 fix 消息定向发送时不检查消息类型匹配 2025-06-16 08:06:47 +08:00
jxxghp
bf23fe6ce2 更新 subscribe.py 2025-06-15 23:31:13 +08:00
jxxghp
7c6137b742 更新 download.py 2025-06-15 23:30:01 +08:00
jxxghp
3823a7c9b6 fix:消息发送范围 2025-06-15 23:18:07 +08:00
jxxghp
a944975be2 fix:交互消息立即发送 2025-06-15 23:06:25 +08:00
jxxghp
6da65d3b03 add MessageAction 2025-06-15 21:25:14 +08:00
jxxghp
0d938f2dca refactor:减少Alipan及115的Api调用 2025-06-15 20:41:32 +08:00
jxxghp
4fa9bb3c1f feat: 插件消息的事件回调 [PLUGIN]插件ID|内容 2025-06-15 19:47:04 +08:00
jxxghp
2f5b22a81f fix 2025-06-15 19:41:24 +08:00
jxxghp
fcd5ca3fda feat:Slack支持编辑消息 2025-06-15 19:28:05 +08:00
jxxghp
c18247f3b1 增强消息处理功能,支持编辑消息 2025-06-15 19:18:18 +08:00
jxxghp
f8fbfdbba7 优化消息处理逻辑 2025-06-15 18:40:36 +08:00
jxxghp
21addfb947 更新 message.py 2025-06-15 16:56:48 +08:00
jxxghp
8672bd12c4 fix bug 2025-06-15 16:31:09 +08:00
jxxghp
be8054e81e fix bug 2025-06-15 15:57:58 +08:00
jxxghp
82f46c6010 feat:回调消息路由给插件 2025-06-15 15:56:38 +08:00
jxxghp
95a827e8a2 feat:Telegram、Slack 支持按钮 2025-06-15 15:34:06 +08:00
jxxghp
c534e3dcb8 feat:未安装的插件,不加载模块 2025-06-15 09:55:20 +08:00
jxxghp
9f5e1b8dd7 更新 version.py 2025-06-14 14:45:58 +08:00
jxxghp
c86ed20c34 fix 2025-06-14 08:23:48 +08:00
jxxghp
c32c37e66a Merge pull request #4444 from cddjr/fix_doh_reload 2025-06-14 08:22:13 +08:00
jxxghp
7b100d3cdb Merge pull request #4446 from wikrin/v2 2025-06-14 07:05:20 +08:00
Attente
95a2362885 fix(db): 修复系统配置更新时内存共享问题
- 在更新系统配置时,使用 deepcopy 复制新值以避免内存共享
2025-06-13 23:03:13 +08:00
jxxghp
d8b14b9a9f Merge pull request #4445 from cddjr/feat_nettest 2025-06-13 19:06:02 +08:00
景大侠
c45953f63a feat 网络测试支持加速代理以及GitHub Token
fix 测试耗时大于1秒时,时间差计算错误
2025-06-13 18:35:49 +08:00
景大侠
e3d3087a5d fix GitHub请求头补上UA 2025-06-13 18:06:17 +08:00
景大侠
e162bd1168 fix DoH热加载 2025-06-13 17:43:45 +08:00
jxxghp
db5d81d7f0 Merge pull request #4442 from wumode/fix_download_api 2025-06-13 14:24:22 +08:00
wumode
f737f1287b fix(api): 无法设置非默认下载器状态 2025-06-13 08:43:34 +08:00
jxxghp
1ffa5178db Merge pull request #4440 from wikrin/v2 2025-06-13 06:35:24 +08:00
Attente
49cb43488c feat(plugin): 优化插件同步和安装逻辑
- 优化 sync 函数,考虑插件版本因素
- 更新 is_plugin_exists 函数,增加版本比较
2025-06-13 00:19:08 +08:00
jxxghp
fd7a6f8ddd Merge pull request #4438 from H1dery/v2 2025-06-12 20:05:00 +08:00
Cais1
7979ce0f0a File reading fixes
File reading fixes
2025-06-12 19:58:47 +08:00
Cais1
2ba5d9484d Update plugin.py
File reading fixes
2025-06-12 19:57:26 +08:00
jxxghp
23b981c5ac fix #4434 2025-06-12 18:41:46 +08:00
jxxghp
86ab2c8c05 Merge pull request #4434 from alfchao/v2 2025-06-12 16:14:59 +08:00
xuchao3
9ea0bc609a feat:增加telegram api代理地址
#4266
2025-06-12 13:56:36 +08:00
jxxghp
5366c2844a Merge pull request #4433 from wikrin/v2 2025-06-12 08:47:56 +08:00
Attente
eac4d703c7 fix(plugins_initializer): 优化插件恢复的容错处理
- 添加单个插件恢复失败的异常处理,使用 continue 跳过
- 确保单个插件恢复失败不影响其他插件继续恢复
2025-06-12 07:56:44 +08:00
jxxghp
8ed87294e2 v2.5.5-1
- 修复下载器监控问题
2025-06-12 07:08:19 +08:00
jxxghp
b343c601be v2.5.5
- 支持更精细的用户权限控制
- 高级设置中增加了刮削内容设定
2025-06-11 20:27:49 +08:00
jxxghp
e56d7006b4 init users 2025-06-11 20:24:59 +08:00
jxxghp
1b7bcd7784 init users 2025-06-11 19:57:21 +08:00
jxxghp
4cb9025b6c fix season_nfo 2025-06-11 19:48:02 +08:00
jxxghp
f8864ab053 fix reload 2025-06-11 07:11:50 +08:00
jxxghp
64eba46a67 fix 2025-06-11 07:07:55 +08:00
jxxghp
35d9cc1d40 remove jiaba 2025-06-11 00:00:08 +08:00
jxxghp
3036107dac fix user api 2025-06-10 23:42:57 +08:00
jxxghp
214089b4ea Merge pull request #4423 from lonelyman0108/v2 2025-06-10 18:04:13 +08:00
LM
95b7ba28e4 update: 添加fanart环境变量 2025-06-10 17:59:25 +08:00
LM
880272f96e update: 优化fanart获取逻辑,支持设定语言 2025-06-10 17:59:03 +08:00
LM
7ed26fadb6 update: 更新fanart刮削逻辑,优先获取中文、英文内容 2025-06-10 17:25:58 +08:00
jxxghp
f0d25a02a6 feat:支持刮削详细设定 2025-06-10 16:37:15 +08:00
jxxghp
162ba9307d fix restart 2025-06-10 07:09:59 +08:00
jxxghp
49dae92b8e fix flag path 2025-06-09 21:58:02 +08:00
jxxghp
b484a52b6d v2.5.4
- 插件市场支持手动刷新
- 优化了重置容器时已安装插件的恢复策略
2025-06-09 20:57:44 +08:00
jxxghp
d754091a7c fix log 2025-06-09 20:44:48 +08:00
jxxghp
e2febc24ae feat:插件市场支持强制刷新 2025-06-09 20:33:06 +08:00
jxxghp
d0677edaaa fix 优雅停止 2025-06-09 15:39:11 +08:00
jxxghp
f0aaecd0c7 fix #4413 2025-06-09 14:45:26 +08:00
jxxghp
3518940fec Merge pull request #4413 from cddjr/fix_plugin
修复分身的一些BUG
2025-06-09 14:42:54 +08:00
jxxghp
2e5c92ae0c fix 优雅停止 2025-06-09 13:09:16 +08:00
jxxghp
4ad699dbe6 fix 优雅停止 2025-06-09 13:06:27 +08:00
景大侠
931be9e6aa fix 分身复用原插件配置 2025-06-09 09:54:55 +08:00
景大侠
9656d6fbd0 fix 分身类名使用小写后缀
避免与分身ID不一致,导致误判没有安装
2025-06-09 09:51:06 +08:00
景大侠
c7cbb13044 fix 插件卸载后从系统模块中移除
避免分身时误报插件已存在
2025-06-09 09:50:55 +08:00
jxxghp
327d30dcc2 feat:识别容器是否重置 2025-06-09 09:15:58 +08:00
jxxghp
e4e2079917 fix:插件恢复安全性 2025-06-09 08:30:24 +08:00
jxxghp
0427506572 fix:移除Action类静态属性 2025-06-09 08:18:43 +08:00
jxxghp
ea168edb43 fix:移除Oper类静态属性 2025-06-09 08:08:55 +08:00
jxxghp
aa039c6c05 feat:启停插件自动备份与恢复 2025-06-09 08:04:44 +08:00
jxxghp
3de998051a fix memory snapshot 2025-06-08 21:57:49 +08:00
jxxghp
69ade1ae37 更新内存快照间隔为30分钟,保留的内存快照文件数量减少至20个 2025-06-08 21:48:37 +08:00
jxxghp
1d6133e3b1 fix plugins遍历 2025-06-08 21:39:37 +08:00
jxxghp
203a111d1a remove gc 2025-06-08 21:24:26 +08:00
jxxghp
0a20234268 remove gc 2025-06-08 21:19:15 +08:00
jxxghp
7f8e50f83d fix memory helper 2025-06-08 21:13:37 +08:00
jxxghp
443ef7d41b fix 2025-06-08 21:06:27 +08:00
jxxghp
059ae6595d fix 2025-06-08 20:37:42 +08:00
jxxghp
19c3dad338 fix 2025-06-08 19:41:46 +08:00
jxxghp
81bc51c972 fix pympler 2025-06-08 19:02:25 +08:00
jxxghp
6c17868744 add pympler 2025-06-08 18:55:02 +08:00
jxxghp
a18040ccfa add pympler 2025-06-08 18:54:35 +08:00
jxxghp
0835a75503 更新 thread.py 2025-06-08 14:43:13 +08:00
jxxghp
3ee32757e5 rollback 2025-06-08 14:35:59 +08:00
jxxghp
344abfa8d8 fix memory helper 2025-06-08 14:03:01 +08:00
jxxghp
906b2a3485 fix memory statistics 2025-06-08 11:36:15 +08:00
jxxghp
e0d2b87ed3 wallpaper cache skip empty 2025-06-08 11:30:57 +08:00
jxxghp
83a8c8b42b fix memory threshold 2025-06-08 11:14:16 +08:00
jxxghp
d840ed6c5a fix memory log 2025-06-08 11:08:01 +08:00
jxxghp
0112087be4 refactor #4407 2025-06-08 10:51:59 +08:00
jxxghp
7320084e11 rollback #4379 2025-06-07 22:26:51 +08:00
jxxghp
23929f5eaa fix pool size 2025-06-07 22:00:09 +08:00
jxxghp
c002d4619a 更新 scheduler.py 2025-06-07 20:11:31 +08:00
jxxghp
f60a909bba 更新 version.py 2025-06-07 11:43:04 +08:00
jxxghp
c2c22e3968 Merge pull request #4399 from cddjr/fix_subscribe 2025-06-07 11:42:25 +08:00
jxxghp
f10299b2de Merge pull request #4403 from cddjr/fix_systemconfig 2025-06-07 11:41:36 +08:00
景大侠
1d3563ed97 fix(config): 修复新装的插件会消失的问题 2025-06-07 11:33:28 +08:00
景大侠
f3eb2caa4e fix(subscribe): 避免重复下载已入库的剧集 2025-06-07 02:48:22 +08:00
jxxghp
2364dacd52 添加对 GitHub 容器注册 2025-06-06 22:02:04 +08:00
jxxghp
883f7451c3 fix event log 2025-06-06 21:45:14 +08:00
jxxghp
a534c9bca1 fix 设置保存失败提示 2025-06-06 21:30:11 +08:00
jxxghp
b14202a324 fix logger 2025-06-06 21:18:31 +08:00
jxxghp
a6fae48f07 更新 system.py 2025-06-06 17:15:25 +08:00
jxxghp
963caf2afe fix logger reload 2025-06-06 16:31:00 +08:00
jxxghp
50b0268531 v2.5.3-1 2025-06-06 15:37:44 +08:00
jxxghp
f484b64be3 fix 2025-06-06 15:37:02 +08:00
jxxghp
349535557f 更新 subscribe.py 2025-06-06 14:04:12 +08:00
jxxghp
de4973a270 feat:内存监控开关 2025-06-06 13:49:52 +08:00
jxxghp
e42d2baf8a fix lint 2025-06-05 22:14:14 +08:00
jxxghp
eac435b233 fix lint 2025-06-05 22:13:33 +08:00
jxxghp
447b8564e9 更新 GitHub Actions 工作流 2025-06-05 22:02:52 +08:00
jxxghp
97cee657bd 更新 .gitignore 文件以包含 Pylint 相关文件,并修改 system.py 中的成功返回逻辑 2025-06-05 21:58:50 +08:00
jxxghp
fe894754cf 更新 system.py 2025-06-05 21:39:13 +08:00
jxxghp
9ffb1d1931 更新 wallpaper.py 2025-06-05 21:03:21 +08:00
jxxghp
a16bd30903 更新 wallpaper.py 2025-06-05 21:00:18 +08:00
jxxghp
13f9ea8be4 v2.5.3 2025-06-05 20:28:43 +08:00
jxxghp
304af5e980 fix:仪表盘内存只显示当前程序占用 2025-06-05 17:09:11 +08:00
jxxghp
dc180c09e9 fix wallpaper 2025-06-05 17:03:29 +08:00
jxxghp
8e20e26565 fix:捕捉插件停止异常 2025-06-05 14:07:31 +08:00
jxxghp
11075a4012 fix:增加更多内存控制 2025-06-05 13:33:39 +08:00
jxxghp
a9300faaf8 fix:优化单例模式和类引用 2025-06-05 13:22:16 +08:00
jxxghp
504827b7e5 fix:memory use 2025-06-05 09:57:41 +08:00
jxxghp
e180130b38 fix:memory use 2025-06-05 08:32:24 +08:00
jxxghp
faaee09827 fix:memory use 2025-06-05 08:18:26 +08:00
jxxghp
99334795b6 fix rsshelper 2025-06-04 22:00:46 +08:00
jxxghp
8c9c59ef64 fix rsshelper 2025-06-04 21:42:03 +08:00
jxxghp
7a112000c9 更新 memory.py 2025-06-04 18:46:55 +08:00
jxxghp
1424087d5a fix:memory use 2025-06-04 18:34:49 +08:00
jxxghp
984f4731cd 更新 log.py 2025-06-04 15:33:58 +08:00
jxxghp
3a3de64b0f fix:重构配置热加载 2025-06-04 08:21:14 +08:00
jxxghp
0911854e9d fix Config reload 2025-06-04 07:17:47 +08:00
jxxghp
2af8b6f445 fix Config reload 2025-06-03 23:10:48 +08:00
jxxghp
bbfd8ca3f5 fix Config reload 2025-06-03 23:08:58 +08:00
jxxghp
b4ed2880f7 refactor:重构配置热加载 2025-06-03 20:56:21 +08:00
jxxghp
5f18a21e86 fix:整理失败时也打上已整理标签 2025-06-03 17:48:30 +08:00
jxxghp
5d188e3877 fix module close 2025-06-03 17:11:44 +08:00
jxxghp
90f113a292 remove ttl cache 2025-06-03 16:31:16 +08:00
jxxghp
eecfe58297 fix memory manager startup 2025-06-03 16:27:51 +08:00
jxxghp
079a747210 fix memory manager startup 2025-06-03 16:19:38 +08:00
jxxghp
4be8c70f23 fix memory log 2025-06-03 16:05:49 +08:00
jxxghp
d9aee4df77 fix memory log 2025-06-03 16:03:05 +08:00
jxxghp
225de87d4d fix torrents chain 2025-06-03 15:48:43 +08:00
jxxghp
2ce7cedfbd fix 2025-06-03 12:30:26 +08:00
jxxghp
cfb163d904 fix 2025-06-03 12:27:50 +08:00
jxxghp
de7c9be11b 优化内存管理,增加最大内存配置项,改进内存使用检查逻辑。 2025-06-03 12:25:13 +08:00
jxxghp
841209adc9 fix 2025-06-03 11:49:16 +08:00
jxxghp
e48d51fe6e 优化内存管理和垃圾回收机制 2025-06-03 11:45:17 +08:00
jxxghp
9d436ec7ed fix #4382 2025-06-03 08:19:15 +08:00
jxxghp
fb2b29d088 fix #4382 2025-06-03 07:07:40 +08:00
jxxghp
1c46b0bc20 更新 subscribe.py 2025-06-02 16:23:09 +08:00
jxxghp
81d0e4696a Merge pull request #4379 from jtcymc/v2 2025-06-02 10:48:36 +08:00
shaw
f9a287b52b feat(core): 增加剧集交集最小置信度设置
新增了剧集交集最小置信度的配置项,用于过滤掉包含过多不需要剧集的种子。实现了以下功能:

- 在 config.py 中添加了 EPISODE_INTERSECTION_MIN_CONFIDENCE 配置项,默认值为 0.0
- 修改了 download.py 中的下载逻辑,增加了计算种子与目标缺失集之间交集比例的函数
- 使用交集比例来筛选和排序种子,优先下载与缺失集交集较大的种子
-可以通过配置项设置交集比例的阈值,低于阈值的种子将被跳过

这个改动可以提高下载效率,避免下载过多不必要的剧集。
2025-06-02 00:38:10 +08:00
jxxghp
0f0072abea Merge pull request #4375 from awsl1110/v2 2025-05-31 20:08:10 +08:00
awsl1110
312933a259 fix(indexer): 修正 DiscuzX 站点名称
- 将 Discuz! 站点名称修改为 DiscuzX
2025-05-31 19:18:25 +08:00
jxxghp
288854b8f1 Merge pull request #4374 from awsl1110/v2 2025-05-31 19:04:51 +08:00
awsl1110
7f5991aa34 refactor(core): 优化配置项和模型定义
- 为配置项添加类型注解,提高代码可读性和安全性
- 为模型字段添加默认值,优化数据处理
- 更新验证器使用新语法,以适应Pydantic库的变更
2025-05-31 16:38:06 +08:00
jxxghp
361df95d50 Merge pull request #4372 from cddjr/fix_4371 2025-05-31 13:34:48 +08:00
景大侠
fc1ade32d7 更新蓝光测试用例 2025-05-31 11:05:02 +08:00
景大侠
b74c7531d9 fix #4371 递归判断蓝光目录 2025-05-31 02:37:14 +08:00
景大侠
7e3be3325a fix #4294 更新测试用例 2025-05-31 01:52:31 +08:00
jxxghp
7dab7fbe66 更新 transhandler.py 2025-05-30 21:42:50 +08:00
jxxghp
62c06b6593 fix #4216 2025-05-30 17:32:37 +08:00
jxxghp
000b62969f v2.5.2 2025-05-30 17:06:21 +08:00
jxxghp
b4473bb4a7 fix 插件分身服务注册 2025-05-30 16:59:54 +08:00
jxxghp
2c0e06d599 fix 插件分身服务注册 2025-05-30 13:37:40 +08:00
jxxghp
d2c55e8ed3 Merge remote-tracking branch 'origin/v2' into v2 2025-05-30 08:07:57 +08:00
jxxghp
714abaa25a fix rename 2025-05-30 08:07:53 +08:00
jxxghp
0017eb987b Merge pull request #4365 from Aqr-K/fix-modules/thetvdb 2025-05-29 21:17:38 +08:00
Aqr-K
e5a0894692 fix(tvdb): 解决无网络环境时,tvdb 模块初始化时,仍然会进入超长等待的问题
- 改为惰性初始化,启动时不再执行 `auth` ,调用方法时,再进行 `auth` (保留 auth_token 过期检查重新 `auth` 的功能);
- 使用 双重检查锁定 的方式,保证线程安全;
- 统一通过一个 `timeout` 值进行设置,默认值从30秒降为15秒,保持与tmdb相同。
2025-05-29 20:04:18 +08:00
jxxghp
a8e00e9f0f fix apis 2025-05-29 13:35:01 +08:00
jxxghp
77a4c271ae Merge pull request #4361 from madrays/v2
增加缓存管理页面
2025-05-29 09:21:45 +08:00
jxxghp
014b77c3c7 v2.5.1-1 2025-05-29 08:30:31 +08:00
jxxghp
076e241056 fix tvdb 2025-05-29 08:30:14 +08:00
jxxghp
7ce57cc67a fix 2025-05-29 08:22:45 +08:00
jxxghp
da0343283a 支持在插件文件夹中管理分身插件的添加与移除 2025-05-29 08:16:54 +08:00
jxxghp
d5f7f1ba91 fix tvdb api 2025-05-29 08:03:12 +08:00
jxxghp
8761c82afe fix TVDB代理与SSL校验 #4356 2025-05-29 07:14:42 +08:00
madrays
13023141bc 增加缓存管理页面 2025-05-29 00:46:11 +08:00
jxxghp
4dd2038625 Merge pull request #4360 from cddjr/fix_TransHandler 2025-05-29 00:06:32 +08:00
景大侠
06a32b0e9d fix: TransHandler误报success的bug 2025-05-28 23:52:23 +08:00
jxxghp
c91ab7a76b 添加新的设定项 2025-05-28 21:05:29 +08:00
jxxghp
0344aa6a49 更新 version.py 2025-05-28 20:34:59 +08:00
jxxghp
a748c9d750 修复:更新壁纸助手以支持更多图片格式 2025-05-28 08:26:44 +08:00
jxxghp
038dc372b7 更新 config.py 2025-05-28 07:03:22 +08:00
jxxghp
bc8198fb8a Merge pull request #4356 from TimoYoung/v2 2025-05-27 21:06:54 +08:00
TimoYoung
f42275bd83 Merge remote-tracking branch 'origin/v2' into v2 2025-05-27 18:02:21 +08:00
TimoYoung
6bd86a724e fix:区分series和movie id 2025-05-27 17:58:37 +08:00
TimoYoung
fc96cfe8a0 feat:tvdb模块重写,更换tvdbv4 api,增加搜索能力
sonarr /series/lookup接口重写,直接用标题在tvdb查询剧集
2025-05-27 17:32:25 +08:00
jxxghp
a9f25fe7d6 fix bug 2025-05-27 12:31:43 +08:00
jxxghp
f740fed5f2 fix bug 2025-05-26 13:30:30 +08:00
jxxghp
a6d1bd12a2 fix:优化插件分身性能
feat:分身插件删除时清理文件
2025-05-26 13:21:47 +08:00
jxxghp
e8ab20acf2 Merge pull request #4351 from madrays/v2 2025-05-26 11:08:30 +08:00
madrays
ccfe193800 增加插件分身功能 2025-05-26 10:55:40 +08:00
jxxghp
bdccedca59 更新 system.py 2025-05-26 07:45:21 +08:00
DDSRem
9abb1488df Merge pull request #4348 from Aqr-K/fix-sh
fix(sh): 引号格式问题
2025-05-25 23:48:45 +08:00
Aqr-K
195fc1bdc3 fix(sh): 引号格式问题 2025-05-25 23:47:23 +08:00
jxxghp
2a9129f470 更新 version.py 2025-05-25 20:15:44 +08:00
jxxghp
acbfc0cc6e Merge pull request #4343 from Aqr-K/fix-sh 2025-05-25 19:53:58 +08:00
Aqr-K
bfb0c75e95 fix(sh): 补全调用 2025-05-25 18:50:41 +08:00
jxxghp
161a2ddae8 Merge pull request #4344 from DDS-Derek/dev 2025-05-25 18:32:29 +08:00
Aqr-K
99621cfd66 fix(config): 强制指定 quote_mode ,避免后续依赖升级,默认值不再是 always 2025-05-25 18:30:00 +08:00
DDSRem
e6e7234215 fix(u115): get information directly through id 2025-05-25 18:27:06 +08:00
DDSRem
5b7b329279 fix(docker): repair restart judgment
当 DOCKER_CLIENT_API 不等于默认值时代表外部调用重启,无需再映射 `/var/run/docker.sock`
2025-05-25 18:20:04 +08:00
Aqr-K
3abb2c8674 fix(sh): 重启时,无法同时结合 系统变量 与 env 文件,进行变量读取的问题。 2025-05-25 18:15:35 +08:00
jxxghp
39de89254f add Docker Client API地址 2025-05-25 14:55:51 +08:00
jxxghp
ac941968cb 更新 plugin.py 2025-05-25 11:22:08 +08:00
jxxghp
96f603bfd1 Merge pull request #4339 from jtcymc/v2 2025-05-25 08:01:00 +08:00
shaw
677e38c62d fix(SearchChain): with 关闭线程池
- 使用 with 语句管理 ThreadPoolExecutor,确保线程池正确关闭
2025-05-25 00:44:19 +08:00
jxxghp
72fce20905 feat:整理后记录字幕和音频文件 2025-05-24 20:58:46 +08:00
jxxghp
1eb41c20d5 fix TransferInfo 2025-05-24 15:40:03 +08:00
DDSRem
dd0c1d331f Merge pull request #4334 from DDS-Derek/dev
fix(plugin): dependency dynamic refresh
2025-05-24 09:24:41 +08:00
DDSRem
12760a70a1 fix(plugin): dependency dynamic refresh 2025-05-24 09:23:47 +08:00
jxxghp
525d17270f fix #4332 2025-05-24 06:37:59 +08:00
jxxghp
bc9959f5ab Merge pull request #4333 from Aqr-K/fix-log 2025-05-24 06:31:41 +08:00
jxxghp
94a8cd5128 Merge pull request #4331 from madrays/v2 2025-05-24 06:30:59 +08:00
Aqr-K
5a1b2c4938 fix(log): 区分 主程序日志 与 插件日志 2025-05-24 06:20:41 +08:00
madrays
851a2ac03a Delete requirements.in 2025-05-24 04:12:53 +08:00
madrays
34d7707f53 Delete config/plugins/twofahelper/twofahelper_sites.json 2025-05-24 04:12:13 +08:00
madrays
0aac7f62a3 Delete config/app.env 2025-05-24 04:11:54 +08:00
madrays
34379b92d0 重构插件页面,增加文件夹功能 2025-05-24 03:57:04 +08:00
DDSRem
250999f9f5 Merge pull request #4330 from Aqr-K/patch-1
fix(log): 修复 docker 环境下,重复打印日志的问题
2025-05-24 01:18:59 +08:00
Aqr-K
2b3832222b fix(log): 修复 docker 环境下,重复打印日志的问题 2025-05-24 01:16:14 +08:00
jxxghp
c5f6d0e721 更新 config.py 2025-05-23 21:05:50 +08:00
jxxghp
dbb0cf15b8 fix 最新入库条目 2025-05-23 07:12:47 +08:00
jxxghp
ab202ba951 Merge pull request #4324 from wumode/fix_typo 2025-05-23 06:45:55 +08:00
wumode
e2c13aa7ed fix: 确保名称识别正确兜底 2025-05-23 00:23:45 +08:00
jxxghp
c1ab19f3cf 更新 version.py 2025-05-21 21:42:42 +08:00
jxxghp
beebfb2e19 fix 2025-05-21 08:39:04 +08:00
jxxghp
cfca90aa7d fix delay get_item 2025-05-19 20:06:46 +08:00
jxxghp
19fe0a32c8 fix #4308 2025-05-19 12:53:55 +08:00
jxxghp
76659f8837 fix #4308 2025-05-19 12:51:34 +08:00
jxxghp
2254715190 Merge pull request #4308 from k1z/v2
修复重复识别缓存种子的bug
2025-05-19 12:29:13 +08:00
jxxghp
ae1a5460d4 fix FetchMedias Action 2025-05-19 12:26:27 +08:00
k1z
27d9f910ff 修复重复识别缓存种子的bug 2025-05-19 10:35:09 +08:00
k1z
28db4881d7 修复重复识别缓存种子的bug 2025-05-19 10:05:39 +08:00
jxxghp
7c76c3ccd6 rollback #4296 2025-05-18 21:40:06 +08:00
jxxghp
007bd24374 fix message link check 2025-05-18 15:25:45 +08:00
jxxghp
c8dc30287c fix #4294 x26[45] 调整为小写x 2025-05-18 15:15:01 +08:00
jxxghp
360184bbd1 fix 2025-05-18 13:50:43 +08:00
jxxghp
e8ed2454a1 feat:消息为链接时,交由第三方处理 2025-05-18 13:22:42 +08:00
jxxghp
923ecf29b8 fix #4294 2025-05-18 13:16:06 +08:00
jxxghp
a8f8bf5872 增强MetaBase类以支持tmdbid和doubanid的赋值,并为Emby格式ID识别添加测试用例。 2025-05-18 13:03:35 +08:00
jxxghp
bedcd94020 优化find_metainfo函数,增加对Emby格式ID标签的支持,并添加相应的测试用例以验证不同ID格式的识别。 2025-05-18 12:55:25 +08:00
jxxghp
959d4da1f8 Merge pull request #4300 from DDS-Derek/dev 2025-05-18 10:05:14 +08:00
DDSRem
861453c1a8 fix(u115): refresh delay 2025-05-18 10:03:36 +08:00
jxxghp
2f4072da0d Merge pull request #4297 from wikrin/v2 2025-05-17 20:20:30 +08:00
Attente
411b5e0ca6 fix(database): 将下载模板中的 title 变量更改为 torrent_title 2025-05-17 19:45:49 +08:00
Attente
3f03963811 fix(themoviedb): 直接在 API 层次处理剧集组集号
- 移除 season_group_details 中的冗余集号处理
2025-05-17 19:45:49 +08:00
jxxghp
d43f81e118 Merge pull request #4296 from Pollo3470/fix-bluray-match 2025-05-17 18:11:27 +08:00
Pollo
b97dbd2515 fix: 优化 Blu-ray 匹配规则 2025-05-17 17:56:05 +08:00
jxxghp
c6a20a9ed3 Merge pull request #4294 from Miralia/v2 2025-05-16 21:57:19 +08:00
Miralia
27f0f29eef fix(meta): 修复部分格式识别问题 2025-05-16 20:49:23 +08:00
jxxghp
223508ae72 Merge pull request #4292 from Seed680/v2 2025-05-16 15:55:31 +08:00
qiaoyun680
bce0a4b8cd bugfix:如果自定义壁纸API是图片地址,应该返回请求地址 2025-05-16 15:48:37 +08:00
jxxghp
65412a4263 v2.4.8
- 修复了部分情况下插件不注册定时服务的问题
- 二级分类策略支持发行年份范围
- 支持自定义背景壁纸
- 支持插件扩展工作流动作,并编排到工作流中
2025-05-16 12:47:38 +08:00
jxxghp
0233b78c8e fix plugin actions api 2025-05-15 22:13:15 +08:00
jxxghp
b0b25e4cfa fix plugin actions api 2025-05-15 22:02:05 +08:00
jxxghp
806288d587 add:查询插件动作API 2025-05-15 20:54:39 +08:00
jxxghp
97265fc43b feat:二级分类发行年份支持范围 2025-05-15 20:13:44 +08:00
jxxghp
41ca50d0d4 feat:工作流支持调用插件动作 2025-05-15 19:55:14 +08:00
jxxghp
9d02206fd9 feat:二级分类支持发行年份 2025-05-15 15:52:42 +08:00
jxxghp
ba2293eb30 feat:默认配置更多第三方插件仓库 2025-05-15 12:50:18 +08:00
jxxghp
8b9e28975d Merge pull request #4280 from Miralia/v2 2025-05-15 12:09:18 +08:00
jxxghp
22ae8b8f87 fix 非str类型设置保存 2025-05-15 12:00:09 +08:00
Miralia
187e352cbd feat(meta): 修改正则表达式 2025-05-15 11:50:31 +08:00
Miralia
23ef8ad28d feat(meta): 扩展音视频格式匹配规则 2025-05-15 09:58:27 +08:00
jxxghp
1dadf56c42 fix #4276 2025-05-15 08:40:38 +08:00
jxxghp
52640b80c0 Merge pull request #4276 from Seed680/v2
支持支持自定义壁纸api地址,返回中配置中允许的图片文件后缀格式图片都会返回作为壁纸
2025-05-15 08:24:01 +08:00
jxxghp
fe25f8f48f fix #4277 2025-05-15 07:12:52 +08:00
jxxghp
7f59572d8b Merge pull request #4279 from wumode/pip_invocation 2025-05-15 06:43:53 +08:00
wumode
90fc4c6bad Use sys.executable -m pip for env-safe package installation 2025-05-14 23:19:40 +08:00
qiaoyun680
16b6c0da33 支持支持自定义壁纸api地址,返回中配置中允许的图片文件后缀格式图片都会返回作为壁纸 2025-05-14 20:04:38 +08:00
qiaoyun680
488a691f29 支持支持自定义壁纸api地址,返回中配置中允许的图片文件后缀格式图片都会返回作为壁纸 2025-05-14 16:50:17 +08:00
jxxghp
bcbfe2ccd5 feat:增加默认插件仓库 2025-05-14 15:10:27 +08:00
jxxghp
bd9a1d7ec7 Merge pull request #4275 from akvsdk/fix_time_error 2025-05-14 13:10:41 +08:00
jiangyuqing
9331ba64d6 fix 时间解析问题 2025-05-14 12:51:02 +08:00
jxxghp
21e5cb0a03 v2.4.7
- 修复了订阅文件信息显示问题
- 修复了默认通知模板格式中季号的显示问题
- 修复了原始语言图片刮削的问题
- 修复了馒头新版标签无法识别的问题
- 优化了联邦插件API的注册
2025-05-14 09:16:12 +08:00
jxxghp
1a8e0c9ecb fix #4270 2025-05-14 08:41:06 +08:00
jxxghp
16fc0d31cd fix #4270 2025-05-14 08:11:50 +08:00
jxxghp
a622ada58b 更新 lifecycle.py 2025-05-13 23:58:08 +08:00
jxxghp
ee9c4948d3 refactor: 优化启停逻辑 2025-05-13 23:47:12 +08:00
jxxghp
cf28e1d963 refactor: 优化启停逻辑 2025-05-13 23:11:38 +08:00
jxxghp
089ec36160 Merge pull request #4269 from wikrin/v2 2025-05-13 21:44:22 +08:00
jxxghp
04ce774c22 fix plugin initializer 2025-05-13 21:37:10 +08:00
Attente
99c1422f37 feat(message): 优化消息模板中的季号显示格式
- 在 TemplateContextBuilder 中添加 season_fmt 字段,用于存储 Sxx 格式的季号
- 在 meta_info 中添加 season_fmt 字段,用于存储 Sxx 格式的季号
- 更新消息模板中的 season 引用为 season_fmt,以实现统一的季号显示格式
- 新增数据库迁移脚本,用于更新消息模板中的 season 引用为 season_fmt
2025-05-13 21:21:27 +08:00
Attente
b583a60f23 refactor(app): 增加消息构建器的空值过滤
- 在 TemplateContextBuilder 类中增加了对空值的过滤,解决通知模板渲染出`'None'`的问题
2025-05-13 21:21:27 +08:00
jxxghp
7be2910809 fix api register bug 2025-05-13 20:52:22 +08:00
jxxghp
30de524319 fix api register bug 2025-05-13 20:35:36 +08:00
jxxghp
c431d5e759 Merge pull request #4267 from k1z/v2 2025-05-13 18:45:01 +08:00
jxxghp
184b62b024 fix plugin apis 2025-05-13 16:36:50 +08:00
wangkai
2751770350 修复馒头新版标签无法识别的问题 2025-05-13 12:23:51 +08:00
jxxghp
75d98aee8e Merge pull request #4262 from wumode/fix_4180 2025-05-12 21:16:48 +08:00
wumode
48120b9406 fix: get_torrent_tags fails to properly retrieve the existing tags 2025-05-12 21:05:30 +08:00
wumode
0e302d7959 fix: add '已整理' tag to non-default downloader 2025-05-12 21:04:03 +08:00
jxxghp
59cd176f44 更新 build.yml,将 tag_name 的格式修改为 v${{ env.app_version }},以确保版本标签前缀正确 2025-05-12 11:10:42 +08:00
jxxghp
619f728f09 更新 build.yml,添加 continue-on-error: true 以确保删除发布时即使出错也能继续执行后续步骤 2025-05-12 11:06:24 +08:00
jxxghp
6e8002acc4 fix blanks 2025-05-12 11:02:47 +08:00
jxxghp
8a4a6174f7 Merge pull request #4260 from zhuweitung/v2_fix_scrap
fix(scrap):修复自动整理电影、电视剧主海报不为原始语种
2025-05-12 11:00:59 +08:00
jxxghp
ee6c4823d3 优化 build actions 2025-05-12 10:52:23 +08:00
zhuweitung
14dcb73d06 fix(scrap):修复自动整理电影、电视剧主海报不为原始语种 2025-05-12 10:09:36 +08:00
jxxghp
e15107e5ec fix DownloadHistory.get_by_mediaid 2025-05-12 07:57:25 +08:00
jxxghp
0167a9462e Merge pull request #4258 from wumode/fix_4219 2025-05-11 21:18:53 +08:00
wumode
7fa1d342ab fix: blocking issue 2025-05-11 21:05:49 +08:00
jxxghp
05b9988e1d Merge pull request #4257 from cikichen/yemapt 2025-05-11 17:29:15 +08:00
Simon
1c09e61219 _special_domains列表中添加pt.gtk.pw 2025-05-11 17:16:25 +08:00
jxxghp
35f0ad7a83 更新 version.py 2025-05-11 10:11:18 +08:00
jxxghp
7ae1d6763a fix #4245 2025-05-11 08:17:42 +08:00
jxxghp
460e859795 fix #4245 2025-05-10 21:53:03 +08:00
jxxghp
4b88ec6460 feat:单独设置刮削图片语言 #4245 2025-05-10 20:43:00 +08:00
jxxghp
27ee13bb7e Merge pull request #4251 from cikichen/yemapt
update yemapt downloadsize
2025-05-10 20:10:50 +08:00
jxxghp
e6cdd337c3 fix subscribe files 2025-05-10 20:10:13 +08:00
jxxghp
7d8dd12131 fix delete_media_file 2025-05-10 20:00:06 +08:00
Simon
0800e3a136 update yemapt downloadsize 2025-05-10 16:50:53 +08:00
jxxghp
9b0f1a2a04 Merge pull request #4247 from k1z/v2 2025-05-10 00:35:07 +08:00
jxxghp
9de3cb0f92 fix douban test 2025-05-09 20:14:33 +08:00
wangkai
c053a8291c 1. 修复特殊微信id无法处理消息的问题 2025-05-09 16:43:13 +08:00
jxxghp
a0ddfe173b fix 兼容 target_storage 为 None 2025-05-09 12:57:50 +08:00
jxxghp
17843a7c71 v2.4.5-1 2025-05-09 08:17:08 +08:00
jxxghp
324ae5c883 rollback upload api 2025-05-09 08:16:44 +08:00
jxxghp
ef03989c3f 更新 u115.py 2025-05-09 00:27:27 +08:00
jxxghp
63412ddd42 fix bug 2025-05-08 20:37:04 +08:00
jxxghp
30ce32608a fix typo 2025-05-08 19:49:52 +08:00
jxxghp
74799ad096 更新 storage.py 2025-05-08 17:49:12 +08:00
jxxghp
31176f99c8 Merge pull request #4239 from Seed680/v2 2025-05-08 17:48:31 +08:00
Seed680
b9439c05ec Merge branch 'jxxghp:v2' into v2 2025-05-08 17:45:53 +08:00
qiaoyun680
435a04da0c feat(storge):添加存储重置功能 2025-05-08 17:44:44 +08:00
jxxghp
0040b266a5 v2.4.5 2025-05-08 17:26:56 +08:00
jxxghp
645de137f2 fix 插件代码判定 2025-05-08 14:26:47 +08:00
jxxghp
1883607118 fix upload api 2025-05-08 13:12:20 +08:00
jxxghp
4ccae1dac7 fix upload api 2025-05-08 12:55:40 +08:00
jxxghp
ff75db310f fix upload parts 2025-05-08 12:03:39 +08:00
jxxghp
5788520401 fix 阿里云盘会话提示 2025-05-08 10:09:24 +08:00
jxxghp
570dddc120 fix 2025-05-08 09:56:43 +08:00
jxxghp
ea31072ae5 优化AliPan类的文件上传功能,增加多线程分片上传和动态分片计算,提升上传效率和进度监控。 2025-05-08 09:52:32 +08:00
jxxghp
5eca5a6011 优化U115Pan类的文件上传功能,支持多线程并发上传和动态分片计算,提升上传效率和稳定性。 2025-05-08 09:47:43 +08:00
jxxghp
67d5357227 Merge pull request #4238 from cddjr/fix_4236 2025-05-07 19:00:14 +08:00
jxxghp
a0d04ff488 Merge pull request #4237 from wikrin/v2 2025-05-07 18:59:44 +08:00
景大侠
f83787508f fix #4236 2025-05-07 18:36:24 +08:00
Attente
20aba7eb17 fix: #4228 添加订阅传入 MetaBase, 上下文增加 username 字段, 原始对象引用默认开启 2025-05-07 18:19:11 +08:00
jxxghp
0cdea3318c feat:插件API支持bear认证 2025-05-07 13:26:42 +08:00
jxxghp
4dc2c18075 修复插件仪表板异常 2025-05-07 10:57:02 +08:00
jxxghp
74e97abac4 fix 修复仪表板异常 2025-05-07 10:55:13 +08:00
jxxghp
b1db95a925 v2.4.4 2025-05-07 08:26:06 +08:00
jxxghp
9dac9850b6 fix plugin file api 2025-05-06 23:56:35 +08:00
jxxghp
abe091254a fix plugin file api 2025-05-06 23:30:26 +08:00
jxxghp
d2e5367dc6 fix plugins 2025-05-06 11:44:23 +08:00
jxxghp
8ccd1f5fe4 Merge pull request #4229 from wikrin/v2 2025-05-06 06:34:16 +08:00
Attente
50bc865dd2 fix(database): improve message template
- Fix syntax error in downloadAdded message template
2025-05-05 23:14:58 +08:00
jxxghp
74a6ee7066 fix 2025-05-05 19:50:15 +08:00
jxxghp
89e76bcb48 fix 2025-05-05 19:49:30 +08:00
jxxghp
c55f6baf67 Merge pull request #4228 from wikrin/format_notification
Format notification
2025-05-05 19:28:44 +08:00
Attente
ae154489e1 上下文构建并非复杂任务, 移除缓存 2025-05-05 14:08:41 +08:00
Attente
fdc79033ce Merge https://github.com/jxxghp/MoviePilot into format_notification 2025-05-05 13:21:58 +08:00
jxxghp
9a8aa5e632 更新 subscribe.py 2025-05-05 13:16:14 +08:00
Attente
6b81f3ce5f feat(template):实现缓存机制以提升性能
- 在 `TemplateHelper` 和 `TemplateContextBuilder` 中集成 TTLCache(带过期时间的缓存),提升数据复用能力
- 引入 `build_context_cache` 装饰器,统一管理上下文构建的缓存逻辑
对媒体信息、剧集详情、种子信息、传输信息及原始对象启用缓存,减少重复计算
- 新增上下文缓存支持,为异步广播事件 NoticeMessage 提供所需上下文(可通过消息 title 与 text 内容重新获取上下文)
- 支持插件通过自定义模板灵活重构消息体,提升扩展性与灵活性
2025-05-05 13:14:45 +08:00
Attente
aeaddfe36b feat(database): add notification templates for version 2.1.4
- Add new Alembic migration script for version 2.1.4
- Implement notification templates for various events:
  - Organize success
  - Download added
  - Subscribe added
  - Subscribe complete
- Store notification templates in system configuration
2025-05-05 05:27:59 +08:00
Attente
20c1f30877 feat(message): 实现自定义消息模板功能
- 新增 MessageTemplateHelper 类用于渲染消息模板
- 在 ChainBase 中集成消息模板渲染功能
- 修改 DownloadChain、SubscribeChain 和 TransferChain 以使用新消息模板
- 新增 TemplateHelper 类用于处理模板格式
- 在 SystemConfigKey 中添加 NotificationTemplates 配置项
- 更新 Notification 模型以支持 ctype 字段
2025-05-05 05:27:48 +08:00
jxxghp
52ce6ff38e fix plugin file api 2025-05-03 22:14:39 +08:00
jxxghp
c692a3c80e feat:支持vue原生插件页面 2025-05-03 10:03:44 +08:00
jxxghp
491009636a fix bug 2025-05-02 22:57:29 +08:00
jxxghp
ed16ee14ea fix bug 2025-05-02 21:57:19 +08:00
jxxghp
7f2ed09267 fix storage 2025-05-02 20:49:38 +08:00
jxxghp
c0976897ef fix bug 2025-05-02 13:30:39 +08:00
jxxghp
85b55aa924 fix bug 2025-05-02 08:31:38 +08:00
jxxghp
91d0f76783 feat:支持新增存储类型 2025-05-02 08:11:48 +08:00
jxxghp
741badf9e6 feat:支持文件整理存储操作事件 2025-05-01 21:16:21 +08:00
jxxghp
ca1f3ac377 feat:文件整理支持操作类入参 2025-05-01 20:56:17 +08:00
jxxghp
e13e1c9ca3 fix run_module 2025-05-01 11:36:43 +08:00
jxxghp
06ad042443 fix typo 2025-05-01 11:20:56 +08:00
jxxghp
9d333b855c feat:支持插件协持系统模块实现 2025-05-01 11:03:28 +08:00
jxxghp
f46e2acd56 v2.4.3
- 用户界面支持多语言
- 支持设定TheMovieDb元数据语言
- 订阅成功消息增加了演员和简介
- 修复问题

提醒:如升级后页面空白,请强制刷新或者清理浏览器缓存
2025-04-29 17:32:40 +08:00
jxxghp
5ac4d3f4ae fix wallpaper api 2025-04-29 15:26:10 +08:00
jxxghp
1614eebc47 fix 2025-04-29 14:53:04 +08:00
jxxghp
b50599b71f fix:增加安全性 2025-04-29 14:30:34 +08:00
jxxghp
0459025bf8 Merge pull request #4207 from monster-fire/v2 2025-04-28 19:37:52 +08:00
monster-fire
0bd37da8c7 Update __init__.py 添加空值检查 2025-04-28 18:46:48 +08:00
jxxghp
da969dde53 fix:TMDB支持设置语种 2025-04-28 12:11:48 +08:00
jxxghp
33fdd6cafa feat:TMDB支持设置语种 2025-04-28 09:10:38 +08:00
jxxghp
2fe68766eb Merge remote-tracking branch 'origin/v2' into v2 2025-04-28 09:07:42 +08:00
jxxghp
205348697c fix #4188 2025-04-27 12:26:49 +08:00
jxxghp
9b3533c1da Merge pull request #4199 from cddjr/fix_bing 2025-04-27 06:53:00 +08:00
景大侠
c3584e838e fix: 开启全局图片缓存后无法显示来自Bing的壁纸 2025-04-27 00:17:29 +08:00
jxxghp
16d8b3fb58 Merge pull request #4187 from thsrite/v2 2025-04-23 11:53:29 +08:00
thsrite
686bbdc16b fix 添加订阅成功消息增加演员名称、简介 2025-04-23 11:44:44 +08:00
jxxghp
65b17e4f2b v2.4.2
- 修复普通用户通过媒体卡片跳转搜索时无法选择站点的问题,普通用户不能修改搜索站点,会按管理员预设站点直接搜索
2025-04-22 17:35:30 +08:00
jxxghp
23c6898789 更新 nginx.template.conf 2025-04-21 21:42:12 +08:00
jxxghp
df2a1be2a2 更新 nginx.template.conf 2025-04-21 21:33:00 +08:00
jxxghp
2db628a2ba v2.4.1
本版本更新主要调整了用户界面:
- 新增透明主题风格
- PWA模式下全新设计了底部导航栏
- 优化了多处UI细节
2025-04-21 20:05:53 +08:00
jxxghp
b6c40436c9 Merge pull request #4165 from wikrin/v2 2025-04-19 22:36:48 +08:00
Attente
a8a70cac08 refactor(db): optimize download history query logic
- 使用`TransferHistory.list_by`相同逻辑
2025-04-19 20:22:37 +08:00
jxxghp
3eefbf97b1 更新 plex.py 2025-04-19 15:14:47 +08:00
jxxghp
3c423e0838 更新 jellyfin.py 2025-04-19 15:14:14 +08:00
jxxghp
99cde43954 更新 emby.py 2025-04-19 15:13:33 +08:00
jxxghp
fa3a787bf7 更新 mediaserver.py 2025-04-19 15:12:42 +08:00
jxxghp
c776dc8036 feat: WebhookMessage.json 2025-04-19 07:59:59 +08:00
jxxghp
1ef068351d fix docker 2025-04-17 19:36:54 +08:00
jxxghp
6abe0a1862 fix version 2025-04-17 19:15:18 +08:00
jxxghp
ff13045f52 fix build 2025-04-17 12:44:22 +08:00
jxxghp
59c09681cb fix build 2025-04-17 11:49:07 +08:00
jxxghp
f664cf6fa5 remove built-lite 2025-04-17 11:47:24 +08:00
jxxghp
01a847a9c2 test beta 2025-04-17 11:43:42 +08:00
jxxghp
6da655f67f Merge pull request #4154 from TimoYoung/v2 2025-04-16 12:41:15 +08:00
TimoYoung
21df7dced1 fix: 同步cookiecloud站点执行失败问题 2025-04-16 10:26:43 +08:00
jxxghp
7fc257ea79 v2.4.0 2025-04-16 08:11:31 +08:00
jxxghp
24f170ff72 fix 搜索缓存 2025-04-16 08:10:48 +08:00
jxxghp
39999c9ee4 更新 Dockerfile 2025-04-15 06:54:11 +08:00
jxxghp
27a5188e4e 更新 Dockerfile.lite 2025-04-15 06:52:53 +08:00
jxxghp
a5af0786aa - 修复UI错误 2025-04-13 16:03:40 +08:00
jxxghp
e9c9cfaa72 Merge pull request #4137 from lddsb/patch-1 2025-04-11 16:06:29 +08:00
Dee Luo
8ca4ea0f3f perf: 优化qb下载器端口获取逻辑 2025-04-11 15:43:40 +08:00
jxxghp
86e1f9a9d6 Merge pull request #4136 from lddsb/patch-3 2025-04-11 11:43:26 +08:00
Dee Luo
b36ceda585 fix: Rename groups to groups.py 2025-04-11 11:22:29 +08:00
Dee Luo
27a3e6c6db feat: 增加制作组的单元测试 2025-04-11 11:21:39 +08:00
Dee Luo
a731327c00 feat: 增加制作组的单元测试cases 2025-04-11 11:20:36 +08:00
Dee Luo
737c00978e perf: 优化制作组匹配逻辑,解决部分Web组匹配不到的问题
增加两个站制作组的匹配规则
2025-04-11 11:18:15 +08:00
jxxghp
18bcb3a067 fix #4118 2025-04-10 19:40:22 +08:00
jxxghp
f49f55576f Merge pull request #4128 from lddsb/patch-2 2025-04-10 11:09:12 +08:00
Dee Luo
1bef4f9a4d perf: 优化制作组读取自定义制作组的逻辑,避免被空字符串的list影响最终结果 2025-04-10 11:00:46 +08:00
Dee Luo
ab1df59f7a fix: 修复前端传递了[""]这样的空list导致判空时逻辑异常的问题 2025-04-10 10:51:40 +08:00
jxxghp
bcd235521e v2.3.9
- 优化多处UI细节
- 修复了订阅分享参数传递问题,开放了订阅分享管理功能
2025-04-10 08:34:16 +08:00
jxxghp
31a2eac302 fix:订阅分享参数传递 2025-04-10 08:19:59 +08:00
jxxghp
7e6b7e5dd5 更新 subscribe.py 2025-04-09 17:32:07 +08:00
jxxghp
9ec9f48425 feat:增加订阅管理员 #4123 2025-04-09 13:26:58 +08:00
jxxghp
a3bec43eab feat:增加订阅管理员 #4123 2025-04-09 13:26:10 +08:00
jxxghp
f429b6397e fix RecommendMediaSource 2025-04-08 18:52:54 +08:00
jxxghp
9d6e7dc288 Merge pull request #4115 from lddsb/patch-1 2025-04-08 17:58:36 +08:00
Dee Luo
a27c09c1e8 perf: 放宽制作组后缀匹配
支持 制作组xxx 这样的后缀匹配
2025-04-08 16:35:38 +08:00
jxxghp
ceb0697c73 - 适配馒头API变动 2025-04-07 21:30:41 +08:00
jxxghp
6ad6a08bf1 Merge pull request #4110 from cddjr/trimemedia
提升飞牛服务端地址的兼容性
2025-04-07 21:15:38 +08:00
jxxghp
fac6ad7116 Merge pull request #4109 from cddjr/fix_mteam
修复馒头请求参数错误的问题
2025-04-07 21:14:42 +08:00
景大侠
7d8cda0457 修复馒头请求参数错误的问题 2025-04-07 21:04:21 +08:00
景大侠
33fc3fd63b 新增删除媒体的api 2025-04-07 17:20:47 +08:00
景大侠
8d39cc87f7 提升服务端地址的兼容性 2025-04-07 16:37:41 +08:00
景大侠
d0b1348c96 fix some warnings 2025-04-07 16:21:39 +08:00
jxxghp
0afc38f6b8 Merge pull request #4103 from wikrin/v2 2025-04-07 11:07:11 +08:00
Attente
264896ba17 fix: 剧集组刮削 2025-04-07 09:25:06 +08:00
jxxghp
08decf0b82 feat:新增默认插件库 2025-04-07 08:06:59 +08:00
jxxghp
98381265e6 更新 u115.py 2025-04-07 07:37:00 +08:00
DDSRem
d323159719 Update requirements.in 2025-04-06 13:10:56 +08:00
jxxghp
7ef21e1d1c Merge pull request #4098 from DDS-Derek/dev 2025-04-06 12:02:01 +08:00
DDSRem
2d6b2ab7d7 bump: python environment upgrade 3.12
links https://github.com/jxxghp/MoviePilot/issues/3543
2025-04-06 11:56:00 +08:00
jxxghp
a1e6fd88a9 更新 version.py 2025-04-06 07:53:29 +08:00
jxxghp
e72ff867fc fix 115 pickcode 2025-04-05 09:29:08 +08:00
jxxghp
8512641984 更新 scraper.py 2025-04-04 22:13:14 +08:00
jxxghp
f1aa64d191 fix episodes group 2025-04-04 12:17:42 +08:00
jxxghp
347262538f fix episodes group 2025-04-04 08:59:12 +08:00
jxxghp
82510d60ca 更新 __init__.py 2025-04-03 22:48:29 +08:00
jxxghp
6104cd04c3 更新 context.py 2025-04-03 20:32:56 +08:00
jxxghp
44eb58426a feat:支持指定剧集组识别和刮削 2025-04-03 18:43:04 +08:00
jxxghp
078b60cc1e feat:支持指定剧集组识别和刮削 2025-04-03 18:35:02 +08:00
jxxghp
21e120a4f8 refactor:减少一次接口查询 2025-04-03 10:43:31 +08:00
jxxghp
439b834aa8 更新 version.py 2025-04-02 18:39:50 +08:00
jxxghp
ddbe8324be README增加开发说明 2025-03-30 11:36:19 +08:00
jxxghp
8ffe93113b README增加开发说明 2025-03-30 09:53:34 +08:00
jxxghp
8b31b7cb8a v2.3.6-1
- 修复媒体服务器库存检索问题
- 继续优化搜索页面
2025-03-30 09:23:46 +08:00
jxxghp
e09e21caa9 Merge pull request #4067 from cddjr/fix_media_exists 2025-03-30 02:48:19 +08:00
景大侠
20b145c679 继续修复媒体缺失问题 2025-03-30 02:41:24 +08:00
jxxghp
c5730cf1ad Merge pull request #4065 from cddjr/fix_v235_emby_bug 2025-03-29 23:18:34 +08:00
景大侠
f16b038463 修复v2.3.5引入的emby误报媒体缺失的bug 2025-03-29 23:15:58 +08:00
jxxghp
c08beec232 fix:优化未扫码报错 2025-03-29 22:02:59 +08:00
jxxghp
946361e0ae 更新 requirements.in 2025-03-29 20:30:57 +08:00
jxxghp
97cf65a231 更新 version.py 2025-03-29 20:21:54 +08:00
jxxghp
d7eb6ac15d 更新 alipan.py 2025-03-29 19:30:22 +08:00
jxxghp
075afdbb77 fix alipan upload 2025-03-29 15:39:29 +08:00
jxxghp
2ac047504a fix alipan 2025-03-29 14:52:49 +08:00
jxxghp
c44aa50ef5 fix 上传进度条 2025-03-29 14:33:45 +08:00
jxxghp
7ffafb49c4 fix alipan upload 2025-03-29 10:26:59 +08:00
jxxghp
9b7d57a853 fix alipan api 2025-03-29 09:42:23 +08:00
jxxghp
ac19b3b512 fix alipan api 2025-03-28 21:22:02 +08:00
jxxghp
b030317186 fix: 减少115遍历 2025-03-28 20:58:35 +08:00
jxxghp
b506059874 Merge pull request #4059 from cddjr/trimemedia 2025-03-28 20:13:16 +08:00
景大侠
cf7ba6e17f 移除测试代码 2025-03-28 19:54:47 +08:00
jxxghp
b7ce5663a3 fix ide warnings 2025-03-28 19:43:55 +08:00
jxxghp
58fa8064ad Merge pull request #4058 from cddjr/trimemedia
初步支持飞牛影视
2025-03-28 19:28:35 +08:00
jxxghp
ed48f56526 fix alipan 2025-03-28 17:48:30 +08:00
景大侠
896eb13f7d 初步支持飞牛影视 2025-03-28 16:26:40 +08:00
jxxghp
b8cd1c46c1 feat:Alipan Open Api 2025-03-28 13:40:29 +08:00
jxxghp
c5e84273c0 fix 115目录创建 2025-03-27 19:55:01 +08:00
jxxghp
f21653ffb7 修复115列表异常问题 2025-03-27 17:27:01 +08:00
jxxghp
65c8116cc9 fix 115列表异常处理 2025-03-27 17:26:07 +08:00
jxxghp
5e442433e5 fix 115列表出错时抛出异常 2025-03-27 12:48:19 +08:00
jxxghp
7041347e76 更新 version.py 2025-03-27 12:13:19 +08:00
jxxghp
810c205709 fix 115 2025-03-27 12:04:49 +08:00
jxxghp
ec7035990a fix 2025-03-26 20:12:08 +08:00
jxxghp
da6d9bb2bd fix 115 upload 2025-03-26 18:31:20 +08:00
jxxghp
e009043c63 fix log 2025-03-26 14:00:41 +08:00
jxxghp
79020e9338 hack fix 115 callback format error 2025-03-26 10:39:40 +08:00
jxxghp
2020244cae fix _path_to_id 2025-03-26 08:54:51 +08:00
jxxghp
43fe8f25f8 fix _path_to_id 2025-03-26 08:50:25 +08:00
jxxghp
9522888a60 fix 115 2025-03-26 08:30:30 +08:00
jxxghp
70c183ae2b try fix 115 upload 2025-03-26 07:15:31 +08:00
jxxghp
5d56eb9bef fix 115 upload 2025-03-25 21:33:29 +08:00
jxxghp
a461414a04 fix 115 callback encode 2025-03-25 20:37:46 +08:00
jxxghp
5737c3dca6 fix 115日志频率 2025-03-25 20:00:44 +08:00
jxxghp
57ea50e59c fix 115 callback 2025-03-25 19:38:39 +08:00
jxxghp
7f630e8460 fix 115 callback 2025-03-25 19:37:00 +08:00
jxxghp
108e8502e1 fix 115 上传进度 2025-03-25 19:27:53 +08:00
jxxghp
4aa986d122 fix 115 秒传检测 2025-03-25 18:26:45 +08:00
jxxghp
60239bbfc4 fix bug 2025-03-25 13:57:39 +08:00
jxxghp
93ef3b1f1a add debug logging 2025-03-25 13:48:00 +08:00
jxxghp
d9ed135be4 fix 115 2025-03-25 12:58:03 +08:00
jxxghp
e83fe0aabe fix storage logging 2025-03-25 08:34:36 +08:00
jxxghp
4be7426ae7 fix 115 2025-03-24 22:57:16 +08:00
jxxghp
0ce5ef7f56 fix 115 upload 2025-03-24 21:49:27 +08:00
jxxghp
c2c0946423 fix 115 upload 2025-03-24 21:39:03 +08:00
jxxghp
63049f61f7 fix typing 2025-03-24 19:14:04 +08:00
jxxghp
1918b0f192 fix 115 api 2025-03-24 19:11:18 +08:00
jxxghp
a3ad49b1fa fix 115 api 2025-03-24 19:03:57 +08:00
jxxghp
bed63d1e2b fix 115 api 2025-03-24 19:02:24 +08:00
jxxghp
4a8e739686 fix 115 api 2025-03-24 13:11:23 +08:00
jxxghp
d502f33041 fix 115 open api 2025-03-24 12:04:23 +08:00
jxxghp
4a0ecf36c7 fix typing 2025-03-24 08:40:18 +08:00
jxxghp
afb9e49755 fix typing 2025-03-24 08:11:02 +08:00
jxxghp
18f65e5597 fix year type 2025-03-23 23:16:11 +08:00
jxxghp
22b69f7dac fix blanke 2025-03-23 22:35:37 +08:00
jxxghp
15df062825 更新 discover.py 2025-03-23 22:23:31 +08:00
jxxghp
ed607d3895 更新 recommend.py 2025-03-23 21:57:48 +08:00
jxxghp
f9b0db623d fix cython type error 2025-03-23 21:39:37 +08:00
jxxghp
740cf12c11 fix cython errors 2025-03-23 19:09:48 +08:00
jxxghp
4c4bf698b1 更新 scheduler.py 2025-03-23 18:26:36 +08:00
jxxghp
dc74e749c9 更新 bulit-lite.yml 2025-03-23 18:03:30 +08:00
jxxghp
fa52c542d7 fix lite Dockfile 2025-03-23 15:55:02 +08:00
jxxghp
850d480c7c fix:build lite 2025-03-23 14:48:20 +08:00
jxxghp
a92cc9dce9 更新 bulit-lite.yml 2025-03-23 14:31:29 +08:00
jxxghp
4944a0a456 更新 Dockerfile.lite 2025-03-23 14:28:45 +08:00
jxxghp
13c40058a8 fix:build lite 2025-03-23 13:00:07 +08:00
jxxghp
1410c03c26 feat:build lite 2025-03-23 12:40:14 +08:00
jxxghp
2f38b3040d fix:修复代码兼容性写法 2025-03-23 12:10:21 +08:00
jxxghp
79411a7350 fix:修复代码兼容性写法 2025-03-23 09:00:24 +08:00
jxxghp
ee94c2af32 Merge pull request #4034 from DDS-Derek/dev 2025-03-22 11:31:25 +08:00
DDSRem
d46e5c8d86 bump: docker version 6.1.3 to 7.1.0 2025-03-22 11:13:06 +08:00
jxxghp
95cd10bfba fix #4014 2025-03-22 08:15:58 +08:00
jxxghp
59ed08b92d fix 115 api 2025-03-21 21:08:14 +08:00
jxxghp
2b9f7bca51 fix 115 api 2025-03-21 21:01:37 +08:00
jxxghp
a860a8c02b fix 115 open api 2025-03-21 19:06:53 +08:00
jxxghp
f2cbb8d2f7 fix 115 open api 2025-03-21 18:53:26 +08:00
jxxghp
ea61599589 add 115 open api 2025-03-21 13:27:31 +08:00
jxxghp
0b59c95f63 fix #4029 2025-03-21 11:24:08 +08:00
jxxghp
66d4308810 fix https://github.com/jxxghp/MoviePilot-Frontend/issues/312 2025-03-21 11:19:29 +08:00
jxxghp
f2648df2ad add special domains 2025-03-20 13:00:53 +08:00
jxxghp
d20f68e897 remove setup.py 2025-03-20 08:53:02 +08:00
jxxghp
338021645d 更新 requirements.in 2025-03-19 21:50:26 +08:00
jxxghp
a0a11842cb fix workflow count 2025-03-15 10:16:25 +08:00
jxxghp
f5832d6a25 Merge pull request #4012 from fanrongbin/v2 2025-03-14 17:22:23 +08:00
Robin-PC-X1C
8fa6d9de39 20250314 修改rss.py
修改原因:管理员在mp添加多个豆瓣id时,不同的豆瓣用户订阅内容,发送通知时统一为“豆瓣想看”,无法区分
修改后:增加豆瓣昵称获取,便于推送订阅通知消息时,区分豆瓣用户名称
2025-03-14 16:42:41 +08:00
jxxghp
e662338d6f Merge pull request #3995 from KoWming/v2 2025-03-10 12:48:31 +08:00
KoWming
2c1d6817dd Update security.py 2025-03-10 12:46:06 +08:00
jxxghp
5d4a3fec1f v2.3.4
- 新增支持设定消息发送的时间范围
- 探索标签页支持拖动排序
- 修复演员头像不显示的问题
- 修复站点流控不生效的问题
- 修复短时间内重复保存设定后定时任务消失的问题
- 修复工作流执行数据叠加的问题
2025-03-10 10:08:34 +08:00
jxxghp
6603a30e7e fix MessageQueueManager 2025-03-10 10:02:32 +08:00
jxxghp
81d08ca517 fix MessageQueueManager 2025-03-10 08:24:28 +08:00
jxxghp
e04506a614 fix workflow message link 2025-03-09 21:07:52 +08:00
jxxghp
39756512ae feat: 支持消息发送时间范围 2025-03-09 19:34:05 +08:00
jxxghp
71c29ea5e7 fix ide warnings 2025-03-09 18:35:52 +08:00
jxxghp
87ce266b14 fix warnings 2025-03-09 16:48:32 +08:00
jxxghp
ed6d856c24 Merge remote-tracking branch 'origin/v2' into v2 2025-03-09 16:33:01 +08:00
jxxghp
d3ecbef946 fix warnings 2025-03-09 08:37:05 +08:00
jxxghp
7b24f5eb21 fix:站点流控 2025-03-07 08:19:28 +08:00
jxxghp
e1f82e338a fix:定时任务初始化加锁 2025-03-07 08:07:57 +08:00
jxxghp
a835d34a01 Merge pull request #3975 from so1ve/patch-1 2025-03-06 06:54:11 +08:00
Ray
79d70c9977 fix: 标签为"官组"的种子应识别为官种 2025-03-05 22:10:28 +08:00
jxxghp
aea82723cb Merge pull request #3965 from mackerel-12138/fix_s0_scrap 2025-03-05 11:56:22 +08:00
zhanglijun
d47ff0b31a 修复s0集信息错误 2025-03-04 23:18:41 +08:00
jxxghp
affcb9d5c3 fix bug 2025-03-04 14:22:32 +08:00
jxxghp
9be2686733 Merge pull request #3957 from thsrite/v2 2025-03-03 14:22:06 +08:00
thsrite
7126fed2b5 fix docker container log duplicate printing 2025-03-03 13:44:38 +08:00
jxxghp
5bc4330e1c 修复HDDolby 2025-03-02 14:55:18 +08:00
jxxghp
b25ac7116e 更新 hddolby.py 2025-03-02 14:41:55 +08:00
jxxghp
8896867bb3 更新 fetch_medias.py 2025-03-02 14:23:37 +08:00
jxxghp
ba7c9eec7b fix 2025-03-02 13:16:46 +08:00
jxxghp
9b95fde8d1 v2.3.3
- 增加了多个索引和认证站点支持
- HDDolby切换为使用API(需要调整站点设置,否则无法正常刷新站点数据)
- 调整了IYUU认证使用的域名地址
- 继续完善任务工作流
2025-03-02 12:48:32 +08:00
jxxghp
2851f16395 feat:actions增加缓存机制 2025-03-02 12:27:36 +08:00
jxxghp
0d63dfb931 fix actions 2025-03-02 11:15:52 +08:00
jxxghp
37558e3135 更新 hddolby.py 2025-03-02 10:24:17 +08:00
jxxghp
96021e42a2 fix 2025-03-02 10:08:03 +08:00
jxxghp
c32b845515 feat:actions增加识别选项 2025-03-02 09:45:24 +08:00
jxxghp
147d980c54 fix hddolby 2025-03-02 08:51:09 +08:00
jxxghp
f91c43dde9 fix hddolby 2025-03-02 08:08:46 +08:00
jxxghp
4cf5cb06a0 fix hddolby 2025-03-02 08:06:25 +08:00
jxxghp
8e4b4c3144 add hddolby userdata api 2025-03-01 21:28:15 +08:00
jxxghp
c302013696 add hddolby api 2025-03-01 21:24:01 +08:00
jxxghp
37cb94c59d add hddolby api 2025-03-01 21:08:37 +08:00
jxxghp
01f7c6bc2b fix 2025-03-01 18:55:16 +08:00
jxxghp
8bd6ccb0de fix 完善事件和消息发送 2025-03-01 18:34:39 +08:00
jxxghp
ed8895dfbb v2.3.2
- 任务工作流支持手动停止、支持导入导出流程数据、完善动作组件等
2025-03-01 15:51:15 +08:00
jxxghp
a55632051b fix fetch_medias action 2025-03-01 13:54:29 +08:00
jxxghp
7e347a458d add ScanFileAction 2025-02-28 21:23:44 +08:00
jxxghp
cce71f23e2 add ScanFileAction 2025-02-28 21:11:51 +08:00
jxxghp
d68461a127 更新 scheduler.py 2025-02-28 19:37:39 +08:00
jxxghp
1bd12a9411 feat:工作流手动中止 2025-02-28 19:02:38 +08:00
jxxghp
4086ba4763 更新 version.py 2025-02-28 12:30:45 +08:00
jxxghp
6a9cdf71d7 fix AddDownloadAction 2025-02-28 12:12:52 +08:00
jxxghp
a9644c4f86 fix actions 2025-02-28 11:56:26 +08:00
jxxghp
cf62ad5e8e fix actions 2025-02-28 11:15:24 +08:00
jxxghp
f8ed16666c fix actions execute 2025-02-27 20:39:42 +08:00
jxxghp
37926b4c19 fix actions 2025-02-27 18:58:11 +08:00
jxxghp
b080a2003f fix actions 2025-02-27 17:08:38 +08:00
jxxghp
ab0008be86 fix actions 2025-02-27 13:09:01 +08:00
jxxghp
4a42b0d000 fix import 2025-02-26 21:13:41 +08:00
jxxghp
e3d4b19dac fix actionid type 2025-02-26 20:28:10 +08:00
jxxghp
403d600db4 fix workflow edit api 2025-02-26 19:06:30 +08:00
jxxghp
835e6e8891 fix workflow scheduler 2025-02-26 18:32:25 +08:00
jxxghp
eec25113b5 fix workflow scheduler 2025-02-26 18:24:27 +08:00
jxxghp
a7c4161f91 fix workflow executor 2025-02-26 12:57:57 +08:00
jxxghp
799eb9e6ef add workflow executor 2025-02-26 08:37:37 +08:00
jxxghp
88993cb67b fix workflow api 2025-02-25 17:27:21 +08:00
jxxghp
0dc9c98c06 fix workflow api 2025-02-25 13:35:32 +08:00
jxxghp
c1c91cec44 fix workflow api 2025-02-25 13:25:56 +08:00
jxxghp
19b6927320 fix workflow process 2025-02-25 12:42:15 +08:00
jxxghp
0889ebc8b8 fix workflow schema 2025-02-25 08:25:19 +08:00
jxxghp
fb249c0ea5 fix workflow excute 2025-02-25 08:22:02 +08:00
jxxghp
feb22ff0a7 Merge pull request #3922 from WingGao/v2 2025-02-22 17:51:13 +08:00
WingGao
3c95156ce1 fix: alist不应该缓存失败的结果 2025-02-22 15:05:04 +08:00
jxxghp
8b6dca6a46 fix bug 2025-02-22 11:22:21 +08:00
jxxghp
43907eea26 fix 2025-02-22 11:12:14 +08:00
jxxghp
67145a80d0 add workflow apis 2025-02-22 10:35:57 +08:00
jxxghp
0b3138fec6 fix actions 2025-02-22 09:57:32 +08:00
jxxghp
b84896b4f9 Merge pull request #3919 from InfinityPacer/feature/plugin 2025-02-22 07:46:02 +08:00
InfinityPacer
efd046d2f8 fix(plugin): handle None response for online plugins retrieval 2025-02-22 00:34:35 +08:00
jxxghp
06fcf817bb Merge pull request #3917 from gtsicko/v2 2025-02-21 07:29:23 +08:00
gtsicko
16a94d9054 fix: 修复带路径的WECHAT_PROXY不生效 2025-02-20 23:41:14 +08:00
jxxghp
5bf502188d fix 2025-02-20 19:32:58 +08:00
jxxghp
5269b4bc82 fix #3914
feat:搜索支持指定站点
2025-02-20 13:03:12 +08:00
jxxghp
e3f8ed9886 add downloads path 2025-02-20 10:51:22 +08:00
jxxghp
74de554fb0 Merge pull request #3914 from TimoYoung/v2 2025-02-19 18:01:49 +08:00
jxxghp
b41de1a982 fix actions 2025-02-19 17:44:14 +08:00
Timo_Young
25f7d9ccdd Merge branch 'jxxghp:v2' into v2 2025-02-19 17:28:22 +08:00
yangyux
9646745181 fix: mtype为空且tmdbid在movie和tv中都存在时的识别错误问题 2025-02-19 17:27:38 +08:00
jxxghp
1317d9c4f0 fix actions 2025-02-19 16:43:42 +08:00
jxxghp
351029a842 fix AddDownloadAction 2025-02-19 15:24:13 +08:00
jxxghp
15e1fb61ac fix actions 2025-02-19 08:33:15 +08:00
jxxghp
1889a829b5 fix workflow process 2025-02-19 08:16:35 +08:00
jxxghp
53a14fce38 fix workflow process 2025-02-19 08:15:49 +08:00
jxxghp
d9ed7b09c7 v2.3.0
- 站点资源浏览支持关键字和分类搜索,优化了界面,修改了站点卡片点击时的交互行为
- 优化了APP模式下更多菜单、滚动条等多处UI细节
2025-02-18 17:05:24 +08:00
jxxghp
4dcb18f00e fix: site browse api 2025-02-18 16:32:10 +08:00
jxxghp
0a52fe0a7a refactor: site browse api 2025-02-17 19:01:05 +08:00
jxxghp
e5a4d11cf9 fix workflow 2025-02-17 15:08:24 +08:00
jxxghp
6c233f13de fix workflow chain 2025-02-17 12:38:29 +08:00
jxxghp
00aee3496c add workflow oper 2025-02-17 11:54:11 +08:00
jxxghp
77ae40e3d6 fix workflow 2025-02-17 11:40:32 +08:00
jxxghp
68cba44476 fix modules load 2025-02-16 17:24:17 +08:00
jxxghp
b86d06f632 add workflow lifecycle 2025-02-16 16:53:38 +08:00
jxxghp
0b7cf305a0 add action templates 2025-02-16 13:45:15 +08:00
jxxghp
21ae36bc3a add action templates 2025-02-16 12:52:29 +08:00
jxxghp
4e2d9e9165 Merge pull request #3899 from Mister-album/v2-sync 2025-02-15 08:10:15 +08:00
Mister-album
6cee308894 添加为指定字幕添加.default后缀设置为默认字幕功能 2025-02-14 19:58:29 +08:00
jxxghp
b8f4cd5fea v2.2.9
- 资源包升级以提升安全性
- 优化了页面数据刷新机制

注意:本次升级后会默认清理一次种子识别缓存
2025-02-14 19:35:49 +08:00
jxxghp
aa1557ad9e fix setup 2025-02-14 17:37:10 +08:00
jxxghp
f03da6daca fix setup 2025-02-14 17:17:16 +08:00
jxxghp
30eb4385d4 fix sites 2025-02-14 13:44:18 +08:00
jxxghp
4c9afcc1a8 fix 2025-02-14 13:32:20 +08:00
jxxghp
dd47432a45 fix 2025-02-14 12:55:32 +08:00
jxxghp
0ba6974bd6 fix #3843
fix #3829
2025-02-13 08:08:13 +08:00
jxxghp
827d8f6d84 add workflow framework 2025-02-12 17:49:01 +08:00
jxxghp
943a462c69 Merge pull request #3885 from InfinityPacer/feature/security 2025-02-11 17:21:04 +08:00
InfinityPacer
a1bc773fb5 feat(security): add AVIF support 2025-02-11 17:10:50 +08:00
InfinityPacer
ac169b7d22 feat(security): add cache default extension for files without suffix 2025-02-11 17:09:43 +08:00
jxxghp
eecbbfea3a 更新 version.py 2025-02-10 22:28:06 +08:00
jxxghp
635ddb044e add depends for DiscoverMediaSource 2025-02-10 22:05:56 +08:00
jxxghp
1a6123489d 更新 config.py 2025-02-10 07:52:40 +08:00
jxxghp
4e69195a8d Merge pull request #3876 from InfinityPacer/feature/security 2025-02-10 07:11:28 +08:00
InfinityPacer
e48c8ee652 Revert "fix is_safe_url"
This reverts commit 5e2ad34864.
2025-02-10 02:22:53 +08:00
InfinityPacer
7df07b86b9 feat(security): add cmvideo image for http with port 2025-02-10 02:19:08 +08:00
jxxghp
5e2ad34864 fix is_safe_url 2025-02-09 22:08:21 +08:00
jxxghp
e9a147d43c 更新 config.py 2025-02-09 16:30:47 +08:00
jxxghp
a340ee045e 更新 config.py 2025-02-09 16:28:41 +08:00
jxxghp
12405f3c34 v2.2.8
- 推荐支持通过插件扩展,支持显示/隐藏榜单
- 完善了对探索类插件的支持,加强了插件UI配置能力
- 优化了TheMovieDB探索的风格过滤条件
- DOH选项调整为默认关闭
2025-02-09 12:14:40 +08:00
jxxghp
1e465ee231 refactor:优化API结构 2025-02-09 11:44:53 +08:00
jxxghp
f06c24c23e refactor apis 2025-02-08 21:47:43 +08:00
jxxghp
4b93ee4843 更新 version.py 2025-02-08 20:19:39 +08:00
jxxghp
c022e05ab9 DOH_ENABLE => false 2025-02-08 16:50:51 +08:00
jxxghp
c2a0d9d657 add media/seasons api 2025-02-08 12:44:47 +08:00
jxxghp
6fcf2c2f1f add SECURITY_IMAGE_DOMAINS 2025-02-08 08:18:58 +08:00
jxxghp
bc37daef58 - 新增图片安全域名,以支持探索插件 2025-02-07 18:23:25 +08:00
jxxghp
fab5995c4e feat:增加安全域名 thetvdb.com 2025-02-07 18:11:36 +08:00
jxxghp
0ba8aa75f5 v2.2.7 2025-02-07 08:12:01 +08:00
jxxghp
e24b3ed07a feat:使用名称、年份兜底转换 2025-02-06 20:31:37 +08:00
jxxghp
f9bddcb406 feat:订阅支持通用mediaid 2025-02-06 19:19:43 +08:00
jxxghp
247b3b24a1 fix DiscoverMediaSource 2025-02-06 18:03:27 +08:00
jxxghp
759c18acda feat:增加事件 DiscoverSource、MediaRecognizeConvert 2025-02-06 17:35:58 +08:00
jxxghp
b2462c5950 fix 2025-02-06 11:48:56 +08:00
jxxghp
3d947f712c feat:放开媒体库类型控制 2025-02-06 11:45:10 +08:00
jxxghp
89d917e487 fix 2025-02-05 17:41:30 +08:00
jxxghp
28b0a20b26 Merge pull request #3852 from zouyonghao/v2 2025-02-05 15:59:29 +08:00
Yonghao Zou
6d4396f4ba fix(jellyfin): support audio event 2025-02-05 15:23:01 +08:00
jxxghp
75dd0f27cf 更新 version.py 2025-02-04 13:30:02 +08:00
jxxghp
cb9be86c10 更新 version.py 2025-02-03 11:57:21 +08:00
jxxghp
0b8f021505 Merge pull request #3845 from InfinityPacer/feature/event 2025-02-03 07:40:58 +08:00
InfinityPacer
f2d3b1c13f feat(event): add mediainfo field for TransferInterceptEventData 2025-02-03 01:46:22 +08:00
InfinityPacer
6f24c6ba49 fix(event): reorder code execution 2025-02-03 00:14:15 +08:00
jxxghp
c5a9df88dc Merge pull request #3841 from InfinityPacer/feature/cache 2025-02-02 12:24:52 +08:00
InfinityPacer
20b2df364a chore(deps): add async_timeout~=5.0.1 for redis if Python < 3.11.3 2025-02-02 12:04:09 +08:00
jxxghp
e89103b96f Merge pull request #3840 from InfinityPacer/feature/cache 2025-02-02 11:30:04 +08:00
InfinityPacer
49f1c9c10b fix(cache): check cache existence when skip_none is False 2025-02-02 11:18:02 +08:00
InfinityPacer
b320c84c4c fix(cache): refine caching behavior for Fanart requests 2025-02-02 11:17:36 +08:00
jxxghp
e916b84ee5 Merge pull request #3839 from InfinityPacer/feature/site 2025-02-02 07:03:14 +08:00
InfinityPacer
18633a3b41 fix(site): update seeding parse for audiences 2025-02-02 01:06:43 +08:00
jxxghp
0683498497 fix #3833 2025-01-31 18:40:12 +08:00
jxxghp
7468fa4f1e Merge pull request #3833 from cddjr/fix_site_test
fix 网络异常时,站点测试误报鉴权或Cookie过期
2025-01-31 18:27:03 +08:00
景大侠
ab2b33a9fd fix 网络异常时,站点测试误报鉴权或Cookie过期 2025-01-31 16:53:40 +08:00
InfinityPacer
8bedac023b Merge pull request #3831 from InfinityPacer/feature/event
fix(event): update event type to TransferIntercept
2025-01-31 13:45:05 +08:00
InfinityPacer
7893b41175 fix(event): update event type to TransferIntercept 2025-01-31 13:43:57 +08:00
jxxghp
ab73dbb3cd 更新 version.py 2025-01-31 12:36:35 +08:00
jxxghp
cb042dbe68 Merge pull request #3830 from InfinityPacer/feature/event 2025-01-31 07:27:30 +08:00
InfinityPacer
bba0d363d7 feat(event): update comment 2025-01-31 01:40:15 +08:00
InfinityPacer
8635d8c53f feat(event): add TransferIntercept event for cancel transfer 2025-01-31 01:37:14 +08:00
jxxghp
dae6894e8b Merge pull request #3829 from cddjr/fix_missing_episodes_info 2025-01-30 21:25:05 +08:00
景大侠
b76991a027 fix 文件整理在特定情况下会缺失剧集信息 2025-01-30 21:14:34 +08:00
jxxghp
de61c43db4 fix #3828 2025-01-30 20:10:15 +08:00
jxxghp
890afc2a72 fix bug 2025-01-30 20:04:33 +08:00
jxxghp
8d4e1f3af6 更新 user_oper.py 2025-01-30 09:45:30 +08:00
jxxghp
85507a4fff feat:通过消息订阅时转换为MP用户名 2025-01-30 08:37:35 +08:00
jxxghp
6d395f9866 add UserOper list 2025-01-29 19:55:46 +08:00
jxxghp
c589f42181 fix 2025-01-29 19:02:40 +08:00
jxxghp
87bb121060 Merge pull request #3824 from cddjr/feat_tmdb_content_rating 2025-01-29 17:34:56 +08:00
景大侠
42cd35ab3c feat(TMDB): 增加内容分级的刮削 2025-01-29 16:01:44 +08:00
jxxghp
669da0d882 Merge pull request #3821 from InfinityPacer/feature/subscribe 2025-01-29 07:03:41 +08:00
InfinityPacer
9ac1346f80 fix(subscribe): support default filter group when add 2025-01-28 23:44:26 +08:00
jxxghp
f6981734d0 更新 version.py 2025-01-28 16:06:03 +08:00
jxxghp
cb6aa61b6b fix apis 2025-01-27 17:56:32 +08:00
jxxghp
2ed9cfcc9a fix api 2025-01-27 17:08:22 +08:00
jxxghp
2e796f41cb fix api 2025-01-27 13:45:57 +08:00
jxxghp
7d13e43c6f fix apis 2025-01-27 11:09:05 +08:00
jxxghp
db684de6e9 Merge pull request #3815 from Akimio521/fix/transfer-background 2025-01-27 08:16:22 +08:00
Akimio521
510ef59aa0 fix: 计算任务时某些fileitem.size是None 2025-01-27 00:35:41 +08:00
jxxghp
d56083a29e Merge pull request #3810 from Akimio521/feat/alist-token 2025-01-26 08:54:14 +08:00
Akimio521
8aed2b334e feat: 支持使用永久令牌进行认证 2025-01-25 22:31:53 +08:00
jxxghp
3bf27f224c Merge pull request #3808 from InfinityPacer/feature/plugin 2025-01-25 07:42:44 +08:00
InfinityPacer
dc9a54e74f fix(command): ensure command data isolation by using deepcopy 2025-01-25 00:32:42 +08:00
InfinityPacer
79dc194dd6 feat(plugin): add kwargs support for post_message 2025-01-25 00:18:08 +08:00
jxxghp
8e12249201 Merge pull request #3804 from InfinityPacer/feature/subscribe 2025-01-24 17:46:00 +08:00
InfinityPacer
4fa8f5b248 feat(event): use latest subscribe_info in SubscribeModified 2025-01-24 17:26:54 +08:00
InfinityPacer
3089c0c524 feat(event): add old_subscribe_info to event and update triggers 2025-01-24 17:24:29 +08:00
jxxghp
ba1ca0819e fix 关注订阅时判断历史记录 2025-01-23 13:16:32 +08:00
jxxghp
4666b9051d 更新 version.py 2025-01-23 07:11:50 +08:00
jxxghp
56c524a822 Merge pull request #3792 from InfinityPacer/feature/cache 2025-01-23 06:55:31 +08:00
jxxghp
43e8df1b9f Merge pull request #3791 from InfinityPacer/feature/subscribe 2025-01-23 06:54:09 +08:00
InfinityPacer
dbc465f6e5 fix(cache): update tmdb match_web base_wait to 5 for finer control 2025-01-23 00:11:36 +08:00
InfinityPacer
bfbd3c527c fix(cache): ensure consistent parameter ordering in get_cache_key 2025-01-22 23:53:19 +08:00
InfinityPacer
412405f69b fix(subscribe): optimize site list retrieval in get_sub_sites 2025-01-22 23:22:15 +08:00
jxxghp
12b74eb04f 更新 subscribe.py 2025-01-22 22:50:51 +08:00
jxxghp
2305a6287a fix #3777 2025-01-22 22:23:15 +08:00
jxxghp
68245be081 fix meta 2025-01-22 22:20:17 +08:00
jxxghp
29e01294bd Merge pull request #3789 from InfinityPacer/feature/cache
fix(cache): enhance fanart image caching
2025-01-22 22:16:37 +08:00
InfinityPacer
d35bee54a6 fix(limit): log accurate wait time after triggering limit 2025-01-22 21:34:59 +08:00
InfinityPacer
bf63be18e4 fix(cache): enhance fanart image caching 2025-01-22 21:34:44 +08:00
jxxghp
3dc7adc61a 更新 scheduler.py 2025-01-22 19:39:02 +08:00
jxxghp
047d1e0afd Merge pull request #3788 from InfinityPacer/feature/cache
feat(cache): optimize serialization with type-based caching
2025-01-22 18:47:08 +08:00
InfinityPacer
7c017faf31 feat(cache): optimize serialization with type-based caching 2025-01-22 17:41:11 +08:00
jxxghp
7a59565761 fix 优化订阅匹配的识别量 2025-01-22 16:37:49 +08:00
jxxghp
9afb904d40 Merge pull request #3785 from InfinityPacer/feature/cache
fix(cache): enhance tmdb match_web rate-limiting and caching
2025-01-22 15:27:08 +08:00
jxxghp
8189de589a fix #3775 2025-01-22 15:21:10 +08:00
jxxghp
c458d7525d fix #3778 2025-01-22 15:01:24 +08:00
InfinityPacer
5c7bd95f6b fix(cache): enhance tmdb match_web rate-limiting and caching 2025-01-22 14:58:56 +08:00
InfinityPacer
70c4509682 feat(cache): add exists to check key presence in cache backends 2025-01-22 14:25:30 +08:00
jxxghp
f34e36c571 feat:Follow订阅分享人功能 2025-01-22 13:32:13 +08:00
jxxghp
5054ffe7e4 Merge pull request #3776 from kiri-to/patch-1 2025-01-21 19:38:30 +08:00
kiri-to
ed30933ca2 Update nexus_php.py
修复'站点数据刷新'时潜在429问题
2025-01-21 19:10:52 +08:00
jxxghp
2a4111ecce 更新 version.py 2025-01-21 12:56:09 +08:00
jxxghp
5bc8709605 fix 全x集未识别集数问题 2025-01-21 08:16:20 +08:00
jxxghp
efa2edf869 fix 2025-01-20 18:28:06 +08:00
jxxghp
5c1e972feb 更新 __init__.py 2025-01-20 16:02:53 +08:00
jxxghp
8c23e7a7b7 fix #3760 2025-01-20 08:30:29 +08:00
jxxghp
57183f8cdc Merge pull request #3759 from wikrin/v2 2025-01-20 07:13:26 +08:00
Attente
0481b49c04 refactor(app/helper): optimize module reloading mechanism 2025-01-19 22:40:07 +08:00
jxxghp
7eb9b5e92d Merge pull request #3755 from InfinityPacer/feature/cache 2025-01-19 12:56:56 +08:00
InfinityPacer
2a409d83d4 feat(redis): update redis maxmemory 2025-01-19 12:41:30 +08:00
jxxghp
785a3f5de8 Merge pull request #3752 from InfinityPacer/feature/cache 2025-01-19 08:06:50 +08:00
InfinityPacer
7c17c1c73b feat(redis): update comments 2025-01-19 05:18:49 +08:00
InfinityPacer
0ea429782c feat(redis): optimize serialize 2025-01-19 05:13:31 +08:00
InfinityPacer
7a8f880dbe feat(redis): optimize memory limit and cache cleanup 2025-01-19 04:28:16 +08:00
InfinityPacer
0a86b72110 feat(redis): add encoding for keys and optimize deletion 2025-01-19 04:28:16 +08:00
InfinityPacer
cb5c06ee7e feat(redis): add Redis support 2025-01-19 04:28:15 +08:00
InfinityPacer
9f22ce5cc0 feat(cache): remove maxsize from recommend_cache 2025-01-19 01:26:33 +08:00
jxxghp
86e1fbc28a Merge pull request #3751 from InfinityPacer/feature/cache 2025-01-19 01:02:54 +08:00
InfinityPacer
a5c5f7c718 feat(cache): enhance cache region and decorator 2025-01-19 00:55:45 +08:00
InfinityPacer
ff5d94782f fix(TMDB): adjust trending cache maxsize to 1024 2025-01-18 23:45:03 +08:00
jxxghp
58a1bd2c86 Merge pull request #3750 from wikrin/v2 2025-01-18 07:08:18 +08:00
jxxghp
f78ba6afb0 Merge pull request #3749 from InfinityPacer/feature/cache 2025-01-18 07:07:52 +08:00
Attente
331f3455f8 fix: 指定集数 2025-01-18 02:52:26 +08:00
InfinityPacer
ad0241b7f1 feat(cache): set default skip_empty to False 2025-01-18 02:44:56 +08:00
InfinityPacer
d9508533e1 feat(cache): add cache region support 2025-01-18 02:32:08 +08:00
InfinityPacer
6d2059447e feat(cache): enhance get_plugins to skip empty during network errors 2025-01-18 02:14:01 +08:00
InfinityPacer
11d4f27268 feat(cache): migrate cachetools usage to unified cache backend 2025-01-18 02:12:20 +08:00
InfinityPacer
a29f987649 feat(cache): add cache backend implementations and decorator support 2025-01-18 02:10:17 +08:00
jxxghp
3e692c790e Merge remote-tracking branch 'origin/v2' into v2 2025-01-17 20:31:40 +08:00
jxxghp
35cc214492 fix #3743 2025-01-17 20:31:23 +08:00
jxxghp
bae7bff70d fix #3744 2025-01-17 16:41:01 +08:00
jxxghp
71ef6f6a61 fix media_files Exception 2025-01-17 12:32:55 +08:00
jxxghp
a8e161661c v2.2.2
- 分享的订阅支持删除(仅新分享的订阅有效)
- 媒体信息搜索支持系列合集
- 优化了实时日志的性能
- 优化了订阅识别词的生效优先级
- 优化了多处UI细节
2025-01-16 19:59:52 +08:00
jxxghp
2b07766f9a feat:支持搜索系列合集 2025-01-16 17:58:52 +08:00
jxxghp
adeb5361ab feat:支持搜索系列合集 2025-01-16 17:51:47 +08:00
jxxghp
bd6e43c41d Merge pull request #3737 from wikrin/event 2025-01-15 20:39:34 +08:00
Attente
450289c7b7 feat(event): 添加订阅调整事件
- `编辑`订阅信息后,发送订阅调整事件
- 新增 `EventType.SubscribeModified` 枚举值
- 事件数据包含`subscribe_id: int` 和更新后的订阅信息`subscribe_info: dict`
2025-01-15 20:16:32 +08:00
jxxghp
aa93c560e5 feat:分享订阅删除功能 2025-01-15 13:31:16 +08:00
jxxghp
22b1ebe1cf fix #3724 2025-01-15 08:14:39 +08:00
jxxghp
84bcf15e9b Merge pull request #3724 from wikrin/subscribe_words
fix: - 修复订阅识别词在下载阶段不生效的问题
2025-01-15 08:10:03 +08:00
Attente
5b66803f6d fix: 修复订阅识别词在下载阶段不生效的问题
- 将`季集匹配`从`优先级规则组匹配模块`移至`种子帮助类`
- - `FilterModule.__match_season_episodes()` ==> `TorrentHelper.match_season_episodes()`
- - 确保需要`订阅识别词` `偏移季集`的种子能够正确匹配
2025-01-15 03:43:50 +08:00
Attente
88cbde47da fix: 更新应用订阅识别词的种子元数据, 附加参数过滤空项 2025-01-15 03:23:05 +08:00
Attente
03b96fa88b fix: 类型注解 2025-01-15 02:54:22 +08:00
jxxghp
397a8a9536 v2.2.1
- 订阅分享支持搜索词,修复了订阅复用人数显示
- 新增`VCronField`前端组件供插件使用,以简化cron表达式的输入
2025-01-13 12:52:58 +08:00
jxxghp
1da0a706a3 fix 订阅匹配缓存问题 2025-01-13 12:41:25 +08:00
jxxghp
4f2a110b5f fix 订阅匹配缓存问题 2025-01-13 12:11:56 +08:00
jxxghp
bb356ffcee Merge pull request #3721 from InfinityPacer/feature/site 2025-01-13 11:41:19 +08:00
jxxghp
6c986416ca fix 订阅分享显示复用人数 2025-01-13 08:55:06 +08:00
jxxghp
951ec138ef Merge pull request #3720 from InfinityPacer/feature/site 2025-01-13 07:09:23 +08:00
InfinityPacer
23e779ed94 fix(site): handle NoneType for userdata.user_level in regex search 2025-01-13 02:02:08 +08:00
InfinityPacer
29fccd3887 fix(site): update regex for unread message matching 2025-01-13 01:30:59 +08:00
jxxghp
1bef723332 Merge pull request #3717 from cddjr/fix_mteam_test 2025-01-12 21:25:16 +08:00
景大侠
3c41fed0ef fix 馒头连通性测试失败 2025-01-12 20:14:30 +08:00
jxxghp
5947d0e6d0 fix transfer 2025-01-09 22:24:01 +08:00
jxxghp
0e4fa86372 更新 transfer.py 2025-01-09 21:34:37 +08:00
jxxghp
f32405b646 fix 下载器整理 2025-01-09 21:06:31 +08:00
jxxghp
13955dafe3 v2.2.0
- 分享订阅后立即刷新生效
- 认证站点新增支持`YemaPT`
- 问题修复与细节改进
2025-01-09 19:22:20 +08:00
jxxghp
eaca396a9f add rsa 2025-01-09 18:53:55 +08:00
jxxghp
fabd9f2f75 feat:分享订阅后清除缓存 2025-01-09 16:01:52 +08:00
jxxghp
0d8480769f feat:实时手动整理时不发消息 2025-01-09 12:58:09 +08:00
jxxghp
dc850f1c48 fix version 2025-01-09 12:32:46 +08:00
jxxghp
fb311f3d8a fix #3583 2025-01-09 07:59:17 +08:00
jxxghp
293d89510a fix bug 2025-01-08 12:28:53 +08:00
jxxghp
9446e88012 fix #3689 2025-01-08 11:37:58 +08:00
jxxghp
6f593beeed fix #3687 2025-01-07 20:58:27 +08:00
jxxghp
0dc20cd9b4 Merge pull request #3689 from InfinityPacer/feature/transfer 2025-01-07 20:40:47 +08:00
InfinityPacer
a0543e914e fix(transfer): switch downloader monitor to foreground 2025-01-07 19:54:53 +08:00
jxxghp
1435cd6526 Merge pull request #3686 from InfinityPacer/feature/recommend 2025-01-07 16:30:42 +08:00
jxxghp
7e24181c37 fix noqa 2025-01-07 14:44:44 +08:00
jxxghp
922c391ffc fix 2025-01-07 14:39:15 +08:00
jxxghp
39169e8faa fix 2025-01-07 14:38:26 +08:00
jxxghp
433712aa80 fix tvdbapi 2025-01-07 14:36:37 +08:00
jxxghp
23650657cd add noqa
fix #3670
2025-01-07 14:20:31 +08:00
jxxghp
b5d58b8a9e 更新 __init__.py 2025-01-07 07:19:04 +08:00
jxxghp
0514ff0189 更新 __init__.py 2025-01-07 07:06:40 +08:00
jxxghp
9a15e3f9b3 Merge pull request #3683 from InfinityPacer/feature/module 2025-01-07 06:56:43 +08:00
InfinityPacer
104113852a fix(recommend): add global exit handling 2025-01-07 02:04:02 +08:00
InfinityPacer
430702abd3 feat(transmission): add protocol support 2025-01-07 00:52:58 +08:00
jxxghp
d7300777cb 更新 version.py 2025-01-06 18:03:14 +08:00
jxxghp
4fd61a9c8d Merge pull request #3680 from InfinityPacer/feature/module 2025-01-06 17:58:33 +08:00
InfinityPacer
af2b4aa867 perf(log): optimize get_caller for improved performance 2025-01-06 17:46:35 +08:00
jxxghp
7e252f1692 fix bug 2025-01-06 13:34:51 +08:00
jxxghp
a7e7174cb2 v2.1.9
- 消息发送范围增加了`操作用户和管理员`选项,修复了入库消息不按规则发送的问题
- 修复了IOS桌面图标模式下,弹窗会导致底栏UI错位的问题
- 优化了刮削的处理逻辑
2025-01-06 12:00:38 +08:00
jxxghp
6e2d0c2aad fix #3674 2025-01-06 11:47:05 +08:00
jxxghp
aeb65d7cac fix #3618 2025-01-06 10:56:30 +08:00
jxxghp
e7c580d375 fix #3646 2025-01-06 10:28:26 +08:00
jxxghp
90fedade76 fix #3673 2025-01-06 10:08:46 +08:00
jxxghp
49d9715106 Merge pull request #3673 from Aqr-K/refactor/stringUtils
refactor(string): 优化 `compare_version` 方法
2025-01-06 10:04:41 +08:00
jxxghp
c194e8c59a fix scraping 2025-01-06 08:22:04 +08:00
jxxghp
b6f9315e2b Merge pull request #3675 from InfinityPacer/feature/recommend 2025-01-06 06:57:07 +08:00
InfinityPacer
f91f99de52 fix(log): update logger handlers without reset 2025-01-06 01:53:47 +08:00
InfinityPacer
3ad3a769ab fix(recommend): add global exit handling 2025-01-06 00:37:22 +08:00
Aqr-K
261bb5fa81 fix: 调整变量顺序,更加直观 2025-01-05 17:07:11 +08:00
Aqr-K
704dcf46d3 refactor(string): 调整 preprocess_versionconversion_version 2025-01-05 16:54:02 +08:00
Aqr-K
9fab50edb0 refactor(string): 优化 版本比较 方法 2025-01-05 16:22:28 +08:00
jxxghp
5d2a911849 feat:手动刮削时强制覆盖 2025-01-05 15:38:13 +08:00
jxxghp
89e96ee27a feat:消息支持管理员+操作用户同时发送 2025-01-05 13:21:41 +08:00
jxxghp
41636395ff fix 整理入库消息用户隔离 2025-01-05 12:35:21 +08:00
jxxghp
6f1f89ac26 Merge pull request #3669 from Aqr-K/feature/plugin 2025-01-05 09:47:46 +08:00
jxxghp
607eb4b4aa v2.1.8
- 修复已知问题,优化UI细节
2025-01-04 14:20:57 +08:00
Aqr-K
3078c076dc fix(plugin): 调整判断顺序 2025-01-04 14:20:03 +08:00
Aqr-K
a7794fa2ad feat(plugin): feat(log): plugin monitor supports hot update. 2025-01-04 05:42:51 +08:00
jxxghp
846b4e645c Merge pull request #3664 from Aqr-K/feature/log 2025-01-03 13:38:18 +08:00
Aqr-K
3775e99b02 Remove: del Todo 2025-01-03 13:17:46 +08:00
Aqr-K
cea77bddee feat(log): log supports hot update. 2025-01-03 06:08:29 +08:00
jxxghp
8ac0d169d2 fix 目录监控蓝光原盘 2025-01-02 13:30:59 +08:00
jxxghp
d5ac9f65f6 fix bug 2025-01-01 10:50:14 +08:00
jxxghp
4b3f04c73f fix 目录监控控重 2024-12-31 12:42:28 +08:00
jxxghp
bb478c949a 更新 version.py 2024-12-31 07:15:18 +08:00
jxxghp
11b1003d4d fix 中入队列等待时间,以例聚合消息发送 2024-12-30 19:25:29 +08:00
jxxghp
c0ad5f2970 fix 整理队列锁 2024-12-30 19:02:16 +08:00
jxxghp
54c98cf3a1 fix 目录监控消息重复发送 2024-12-30 18:59:20 +08:00
jxxghp
dfbe8a2c0e fix 目录监控消息重复发送 2024-12-30 18:57:45 +08:00
jxxghp
873f80d534 fix 重复添加队列任务 2024-12-30 18:42:36 +08:00
jxxghp
089992db74 Merge pull request #3640 from InfinityPacer/feature/transfer 2024-12-30 07:00:53 +08:00
jxxghp
f07ab73fde Merge pull request #3639 from InfinityPacer/feature/site 2024-12-30 06:59:02 +08:00
InfinityPacer
166674bfe7 feat(transfer): match source dir in subdirs or prioritize same drive 2024-12-30 02:11:48 +08:00
InfinityPacer
adb4a8fe01 feat(site): add proxy support for site sync 2024-12-30 00:37:54 +08:00
jxxghp
c49e79dda3 rollback #3584 2024-12-29 14:41:55 +08:00
jxxghp
a3b5e51356 fix encoding 2024-12-29 12:54:36 +08:00
jxxghp
8f91e23208 Merge pull request #3634 from InfinityPacer/feature/subscribe 2024-12-29 07:54:12 +08:00
InfinityPacer
b768929cd8 fix(transfer): handle task removal on media info failure 2024-12-29 02:26:30 +08:00
jxxghp
49d5e5b953 v2.1.6 2024-12-28 20:10:34 +08:00
jxxghp
ce4792e87b Merge pull request #3632 from wikrin/v2 2024-12-28 20:07:10 +08:00
Attente
3ea0b1f36b refactor(app): improve code readability and consistency in FileMonitorHandler
- Rename 'size' parameter to 'file_size' in on_created and on_moved methods
- This change enhances code clarity and maintains consistency with other parts of the codebase
2024-12-28 20:05:47 +08:00
jxxghp
51c7852b77 更新 transfer.py 2024-12-28 15:58:07 +08:00
jxxghp
7947f10579 fix size 2024-12-28 14:37:21 +08:00
DDSRem
fca9297fa7 Revert "Merge branch 'rfc-python-bump-312' into v2"
This reverts commit 0ec5e3b365, reversing
changes made to c18937ecc7.
2024-12-28 11:56:54 +08:00
DDSRem
0ec5e3b365 Merge branch 'rfc-python-bump-312' into v2 2024-12-28 11:55:39 +08:00
jxxghp
c18937ecc7 fix bug 2024-12-28 11:00:12 +08:00
jxxghp
8b962757b7 fix bug 2024-12-28 10:57:40 +08:00
jxxghp
2b40e42965 fix bug 2024-12-27 21:16:38 +08:00
jxxghp
0eac7816bc fix bug 2024-12-27 18:36:49 +08:00
jxxghp
e3552d4086 feat:识别支持后台处理 2024-12-27 17:45:04 +08:00
jxxghp
75bb52ccca fix 统一整理记录名称 2024-12-27 07:58:58 +08:00
jxxghp
22c485d177 fix 2024-12-26 21:19:18 +08:00
jxxghp
78dab5038c fix transfer apis 2024-12-26 19:58:23 +08:00
jxxghp
15cc02b083 fix transfer count 2024-12-26 19:25:23 +08:00
jxxghp
419f2e90ce Merge pull request #3621 from InfinityPacer/feature/subscribe 2024-12-26 17:25:05 +08:00
jxxghp
a29e3c23fe Merge pull request #3619 from InfinityPacer/feature/module 2024-12-26 17:24:49 +08:00
InfinityPacer
aa9ae4dd09 feat(TMDB): add episode_type field to TmdbEpisode 2024-12-26 16:39:01 +08:00
InfinityPacer
d02bf33345 feat(config): add TOKENIZED_SEARCH 2024-12-26 13:56:08 +08:00
InfinityPacer
0a1dc1724c chore(deps): add jieba~=0.42.1 for tokenization 2024-12-26 13:55:04 +08:00
jxxghp
80b866e135 Merge remote-tracking branch 'origin/v2' into v2 2024-12-26 13:29:48 +08:00
jxxghp
e7030c734e add remove queue api 2024-12-26 13:29:34 +08:00
jxxghp
e5458ee127 Merge pull request #3615 from wikrin/del_bdmv 2024-12-26 09:25:28 +08:00
Attente
3f60cb3f7d fix(storage): delete Blu-ray directory when removing movie file
- Add logic to delete `BDMV` and `CERTIFICATE` directories when a movie file is removed
- This ensures that empty Blu-ray folders are also cleaned up during the deletion process
2024-12-26 09:00:04 +08:00
jxxghp
8c800836d5 add remove queue api 2024-12-26 08:12:59 +08:00
jxxghp
abfc146335 更新 transfer.py 2024-12-26 07:13:37 +08:00
jxxghp
dd4ff03b08 Merge pull request #3614 from wikrin/v2 2024-12-26 06:59:52 +08:00
jxxghp
be792cb40a Merge pull request #3613 from InfinityPacer/feature/recommend 2024-12-26 06:59:11 +08:00
Attente
cec5cf22de feat(transfer): Update file_items filtering logic to allow bluray directories 2024-12-26 02:41:49 +08:00
InfinityPacer
6ec5f3b98b feat(recommend): support caching by page 2024-12-25 23:07:56 +08:00
jxxghp
0ac43fd3c7 feat:手动整理API支持后台 2024-12-25 20:38:00 +08:00
jxxghp
a600f2f05b Merge pull request #3611 from InfinityPacer/feature/recommend 2024-12-25 19:31:20 +08:00
InfinityPacer
0c0a1c1dad feat(recommend): support caching poster images 2024-12-25 19:24:32 +08:00
jxxghp
c69df36b98 add transfer queue api 2024-12-25 18:11:57 +08:00
jxxghp
20ac9fbfbe fix transfer log 2024-12-25 12:59:43 +08:00
jxxghp
b9756db115 fix jobview 2024-12-25 08:24:57 +08:00
jxxghp
5bfa36418b Merge pull request #3608 from wikrin/split_episode 2024-12-25 07:01:24 +08:00
Attente
30c696adfe fix(format): evaluate offset for start and end episodes 2024-12-25 05:07:54 +08:00
Attente
31887ab4b1 fix(format): improve episode parsing logic 2024-12-25 04:50:23 +08:00
jxxghp
3678de09bf 更新 transfer.py 2024-12-24 21:51:48 +08:00
jxxghp
3f9172146d fix MediaServerSeasonInfo 2024-12-24 21:16:56 +08:00
jxxghp
fc4480644a fix bug 2024-12-24 21:07:12 +08:00
jxxghp
2062214a3b fix bug 2024-12-24 14:17:35 +08:00
jxxghp
01487cfdf6 fix transfer 2024-12-24 14:08:47 +08:00
jxxghp
a2c913a5b2 fix transfer 2024-12-24 14:06:45 +08:00
jxxghp
84f5d1c879 fix bug 2024-12-24 13:31:58 +08:00
jxxghp
48c289edf2 feat: 后台整理队列 2024-12-24 13:14:17 +08:00
jxxghp
c9949581ef Merge pull request #3604 from InfinityPacer/feature/module 2024-12-24 10:49:43 +08:00
InfinityPacer
b4e3dc275d fix(proxy): add proxy for MP_SERVER_HOST 2024-12-24 10:10:19 +08:00
jxxghp
00f85836fa 更新 transfer.py 2024-12-23 22:02:45 +08:00
jxxghp
c4300332c9 TODO 后台整理队列 2024-12-23 21:46:59 +08:00
jxxghp
10f8efc457 TODO 后台整理队列 2024-12-23 18:59:36 +08:00
jxxghp
1b48eb8959 fix ide warnings 2024-12-23 16:58:49 +08:00
jxxghp
61d7374d95 fix ide warnings 2024-12-23 16:58:04 +08:00
jxxghp
baa48610ea refactor:Command提到上层 2024-12-23 13:38:02 +08:00
jxxghp
ece8d0368b Merge remote-tracking branch 'origin/v2' into v2 2024-12-23 12:40:42 +08:00
jxxghp
a9ffebb3ea fix schemas 2024-12-23 12:40:32 +08:00
jxxghp
b6c043aae9 Merge pull request #3598 from InfinityPacer/feature/recommend 2024-12-23 12:09:59 +08:00
jxxghp
d45d49edbd fix schemas default_factory 2024-12-23 11:35:38 +08:00
jxxghp
27f474b192 fix setup 2024-12-23 11:10:08 +08:00
InfinityPacer
544119c49f Revert "feat(recommend): add semaphore to limit concurrent requests"
This reverts commit 33de1c3618.
2024-12-23 10:29:37 +08:00
jxxghp
800a66dc99 Merge pull request #3596 from InfinityPacer/feature/module 2024-12-23 06:54:38 +08:00
InfinityPacer
33de1c3618 feat(recommend): add semaphore to limit concurrent requests 2024-12-23 02:51:23 +08:00
InfinityPacer
6fec16d78a fix(cache): include method name and default parameters in cache key 2024-12-23 01:39:34 +08:00
InfinityPacer
a5d6062aa8 feat(recommend): add job to refresh recommend cache 2024-12-23 01:32:17 +08:00
InfinityPacer
de532f47fb feat(auth): add logging for site auth 2024-12-23 00:20:03 +08:00
jxxghp
60bcc802cf Merge pull request #3593 from wikrin/v2 2024-12-22 10:40:23 +08:00
jxxghp
c143545ef9 Merge pull request #3591 from InfinityPacer/feature/module 2024-12-22 10:28:15 +08:00
Attente
0e8fdac6d6 fix(filemanager): correct season_episode metadata mapping
- Update season_episode field in FileManagerModule to use meta.episode instead of meta.episodes
- This change ensures accurate season and episode information is displayed
2024-12-22 10:24:40 +08:00
jxxghp
45e6dd1561 Merge pull request #3590 from InfinityPacer/feature/recommend 2024-12-22 09:11:51 +08:00
jxxghp
23c37c9a81 Merge pull request #3588 from wikrin/v2 2024-12-22 09:08:11 +08:00
InfinityPacer
098279ceb6 fix #3565 2024-12-22 02:04:36 +08:00
InfinityPacer
1fb791455e chore(recommend): update comment 2024-12-22 01:37:25 +08:00
InfinityPacer
3339bbca50 feat(recommend): switch API calls to use RecommendChain 2024-12-22 01:27:11 +08:00
InfinityPacer
ec77213ca6 feat(recommend): add cached_with_empty_check decorator 2024-12-22 01:09:06 +08:00
InfinityPacer
de1c2c98d2 feat(recommend): add log_execution_time decorator to RecommendChain methods 2024-12-22 01:03:44 +08:00
InfinityPacer
98247fa47a feat: add log_execution_time decorator 2024-12-22 01:02:07 +08:00
InfinityPacer
1eef95421a feat(recommend): add RecommendChain 2024-12-22 01:00:47 +08:00
Attente
b8de563a45 refactor(app): optimize download path logic
- Simplify download path determination logic
- Remove redundant code for save path calculation
2024-12-21 23:56:44 +08:00
jxxghp
fd5fbd779b Merge pull request #3584 from zhzero-hub/v2 2024-12-21 20:15:39 +08:00
zhzero
cb07550388 TorrentSpider添加encoding key 2024-12-21 14:51:55 +08:00
jxxghp
a51632c0a3 Merge pull request #3583 from wikrin/torrent_layout 2024-12-21 07:58:46 +08:00
Attente
9756bf6ac8 refactor(downloader): 新增支持种子文件布局处理
- 在 `DownloadChain` 中根据`种子文件布局`拼接`savepath`
- 在 `QbittorrentModule` 和 `TransmissionModule` 中添加种子文件布局信息
- 修改 `download` 方法的返回值,增加种子文件布局参数
2024-12-21 04:50:10 +08:00
DDSRem
aaa96cff87 Merge pull request #3582 from Aqr-K/patch-1
revert
2024-12-20 23:27:32 +08:00
Aqr-K
a50959d254 revert 2024-12-20 23:26:55 +08:00
DDSRem
b1bd858df1 chore(deps): update dependency python-115 to v0.0.9.8.8.4 2024-12-20 23:21:59 +08:00
DDSRem
c2d6d9b1ac chore(deps): update dependency python-115 to v0.0.9.8.8.4 2024-12-20 23:18:04 +08:00
DDSRem
7288dd24e0 Merge pull request #3580 from jxxghp/v2
Sync
2024-12-20 23:16:30 +08:00
jxxghp
8f05ea581c v2.1.5 2024-12-20 15:40:36 +08:00
jxxghp
03a0bc907b Merge pull request #3569 from yubanmeiqin9048/patch-1 2024-12-19 22:16:27 +08:00
yubanmeiqin9048
5ce4c8a055 feat(filemanager): 增加字幕正则式 2024-12-19 22:01:06 +08:00
jxxghp
b04181fed9 更新 version.py 2024-12-19 20:24:11 +08:00
jxxghp
eee843bafd Merge pull request #3567 from InfinityPacer/feature/cache 2024-12-19 20:21:00 +08:00
InfinityPacer
134fd0761d refactor(cache): split douban cache into recommend and search 2024-12-19 20:00:29 +08:00
InfinityPacer
669481af06 feat(cache): unify bangumi cache strategy 2024-12-19 19:42:17 +08:00
jxxghp
b5640b3179 Merge pull request #3564 from InfinityPacer/feature/subscribe 2024-12-19 16:17:14 +08:00
InfinityPacer
9abb305dbb fix(subscribe): ensure best version is empty set 2024-12-19 15:41:51 +08:00
InfinityPacer
0fd4791479 fix(event): align field names with SubscribeComplete 2024-12-19 10:58:11 +08:00
jxxghp
ce2ecdf44c Merge pull request #3562 from InfinityPacer/feature/subscribe 2024-12-19 07:02:26 +08:00
InfinityPacer
949c0d3b76 feat(subscribe): optimize best version to support multiple states 2024-12-19 00:51:53 +08:00
jxxghp
316915842a Merge pull request #3559 from InfinityPacer/feature/site 2024-12-18 19:24:34 +08:00
jxxghp
1dd7dc36c3 Merge pull request #3557 from InfinityPacer/feature/subscribe 2024-12-18 19:24:00 +08:00
InfinityPacer
fca763b814 fix(site): avoid err_msg cannot be updated when it's None 2024-12-18 16:39:14 +08:00
InfinityPacer
9311125c72 fix(subscribe): avoid reinitializing the dictionary 2024-12-18 15:49:21 +08:00
InfinityPacer
3f1d4933c1 Merge pull request #3553 from InfinityPacer/feature/subscribe
fix(dependencies): pin python-115 version
2024-12-18 12:47:51 +08:00
InfinityPacer
7fb23b5069 fix(dependencies): pin python-115 version 2024-12-18 12:46:28 +08:00
DDSRem
d74ad343f1 Merge pull request #3551 from InfinityPacer/feature/subscribe
Revert "chore(deps): update dependency python-115 to v0.0.9.8.8.3"
2024-12-18 10:42:17 +08:00
InfinityPacer
c0a8351e58 Revert "chore(deps): update dependency python-115 to v0.0.9.8.8.3"
This reverts commit d182a7079d.
2024-12-18 10:39:37 +08:00
jxxghp
8e309e8658 更新 version.py 2024-12-17 22:19:32 +08:00
jxxghp
3400a9f87a fix #3548 2024-12-17 12:44:37 +08:00
jxxghp
c6830059b2 Merge pull request #3548 from 0honus0/v2 2024-12-17 11:54:36 +08:00
honus
7e4a18b365 fix rclone __get_fileitem err 2024-12-17 00:18:52 +08:00
honus
9ecc8c14d8 fix rclone bug 2024-12-16 23:20:49 +08:00
DDSRem
a3c048b9c8 chore(deps): upgrade beautifulsoup4 4.12.2 to 4.12.3 2024-12-16 21:40:27 +08:00
DDSRem
3c08054234 chore(ci): beta image only provides amd64 architecture 2024-12-16 21:30:41 +08:00
DDSRem
07e91d4eb1 chore(deps): playwright 1.37.0 to 1.49.1
fix `greenlet==2.0.2` build error
2024-12-16 21:29:44 +08:00
DDSRem
c104498b43 chore(deps): environment and dependency upgrades 2024-12-16 21:11:14 +08:00
jxxghp
91ba71ad23 Merge pull request #3546 from InfinityPacer/feature/subscribe 2024-12-16 19:47:30 +08:00
jxxghp
5ae8914060 Merge pull request #3545 from xianghuawe/v2 2024-12-16 19:46:18 +08:00
InfinityPacer
77c8f1244f Merge branch 'v2' of https://github.com/jxxghp/MoviePilot into feature/subscribe 2024-12-16 19:09:14 +08:00
InfinityPacer
5d5c8a0af7 feat(event): add SubscribeDeleted event 2024-12-16 19:09:00 +08:00
coder_wen
dcaf3e6678 fix: change alist.py upload api to put, fix big file upload over memory limit #3265 2024-12-16 15:14:16 +08:00
jxxghp
c0170a173c Merge pull request #3542 from DDS-Derek/dev 2024-12-16 12:56:19 +08:00
DDSRem
d182a7079d chore(deps): update dependency python-115 to v0.0.9.8.8.3 2024-12-16 12:28:50 +08:00
jxxghp
b5cc5653b2 Merge pull request #3536 from InfinityPacer/feature/subscribe 2024-12-15 07:56:06 +08:00
jxxghp
bdbd908b3a Merge pull request #3535 from InfinityPacer/feature/event 2024-12-15 07:55:15 +08:00
InfinityPacer
11fedb1ffc fix(download): optimize performance by checking binary content 2024-12-15 01:27:30 +08:00
InfinityPacer
7de82f6c0d fix(event): remove unnecessary code 2024-12-15 00:17:53 +08:00
jxxghp
782829c992 Merge pull request #3531 from InfinityPacer/feature/subscribe 2024-12-13 20:18:58 +08:00
InfinityPacer
6ab76453d4 feat(events): update episodes field to Download event 2024-12-13 20:05:40 +08:00
jxxghp
56767b92d7 Merge pull request #3524 from InfinityPacer/feature/subscribe 2024-12-12 17:29:17 +08:00
InfinityPacer
621df40c66 feat(event): add support for priority in event registration 2024-12-12 15:38:28 +08:00
jxxghp
ba7cb76640 Merge pull request #3519 from InfinityPacer/feature/subscribe 2024-12-11 22:27:24 +08:00
InfinityPacer
d353853472 feat(subscribe): add support for update movie downloaded note 2024-12-11 20:19:47 +08:00
InfinityPacer
1fcf5f4709 feat(subscribe): add state reset to 'R' on subscription reset 2024-12-11 20:01:10 +08:00
InfinityPacer
0ec4630461 fix(subscribe): avoid redundant updates for remaining episodes 2024-12-11 16:31:11 +08:00
InfinityPacer
fa45dea1aa fix(subscribe): prioritize update state when fininsh subscribe 2024-12-11 16:18:03 +08:00
InfinityPacer
2217583052 fix(subscribe): update missing episode logic and return status 2024-12-11 15:51:04 +08:00
InfinityPacer
f4dc7a133e fix(subscribe): update subscription state after download 2024-12-11 15:47:45 +08:00
jxxghp
26b1e64bad Merge pull request #3518 from InfinityPacer/feature/subscribe 2024-12-11 13:32:17 +08:00
InfinityPacer
a1d8af6521 fix(subscribe): update remove_site to set sites as an empty list 2024-12-11 12:39:13 +08:00
jxxghp
9fb3d093ff Merge pull request #3517 from wikrin/match_rule 2024-12-11 06:54:58 +08:00
jxxghp
8c9b37a12f Merge pull request #3516 from InfinityPacer/feature/subscribe 2024-12-11 06:53:42 +08:00
Attente
73e4596d1a feat(filter): add publish time filter for torrents
- 在 `TorrentInfo` 类中添加 `pub_minutes` 方法以计算自发布以来的`分钟`数
- 在 FilterModule 中实现发布时间过滤
- 支持发布时间的单值和范围比较
2024-12-10 23:36:54 +08:00
InfinityPacer
83798e6823 feat(event): add multiple IDs to source with json 2024-12-10 21:23:52 +08:00
InfinityPacer
6d9595b643 feat(event): add source tracking in download event 2024-12-10 18:50:50 +08:00
jxxghp
dc047d949d Merge pull request #3511 from wikrin/offset 2024-12-10 07:13:10 +08:00
Attente
a31b4bc0a1 refactor(app): improve episode offset calculation
- Remove unnecessary try-except block
2024-12-10 00:37:50 +08:00
Attente
94b8633803 手动整理中集数偏移可不使用集数定位 2024-12-10 00:32:01 +08:00
jxxghp
107e85033f Merge pull request #3507 from InfinityPacer/feature/subscribe 2024-12-09 19:38:48 +08:00
InfinityPacer
eea8060182 feat(plugin): add username support for post_message 2024-12-09 19:27:25 +08:00
jxxghp
83f7869de4 Merge pull request #3506 from thsrite/v2 2024-12-09 17:32:49 +08:00
thsrite
4f0eff8b88 fix site vip level ignores ratio warning 2024-12-09 16:43:05 +08:00
jxxghp
58b438c345 fix #3343 2024-12-08 08:51:58 +08:00
jxxghp
bc57bb1a78 更新 version.py 2024-12-07 07:41:14 +08:00
jxxghp
e08ab0dd33 Merge pull request #3341 from InfinityPacer/feature/subscribe 2024-12-07 07:39:28 +08:00
InfinityPacer
64bfa246ae fix: replace is None with is_(None) for proper SQLAlchemy filter 2024-12-07 01:09:03 +08:00
jxxghp
cde4db1a56 v2.1.2 2024-12-06 15:55:56 +08:00
jxxghp
29ae910953 fix build 2024-12-06 12:31:29 +08:00
jxxghp
314f90cc40 upgrade python-115 2024-12-06 12:30:13 +08:00
jxxghp
1c22e3d024 Merge pull request #3337 from InfinityPacer/feature/subscribe
feat(event): add ResourceDownload event for cancel download
2024-12-06 11:17:34 +08:00
InfinityPacer
233d62479f feat(event): add options to ResourceDownloadEventData 2024-12-06 10:47:56 +08:00
jxxghp
6974f2ebd7 Merge pull request #3335 from mackerel-12138/fix_scraper 2024-12-06 06:53:24 +08:00
InfinityPacer
c030166cf5 feat(event): send events for resource download based on source 2024-12-06 02:08:36 +08:00
InfinityPacer
4c511eaea6 chore(event): update ResourceDownloadEventData comment 2024-12-06 02:06:00 +08:00
InfinityPacer
6e443a1127 feat(event): add ResourceDownload event for cancel download 2024-12-06 01:55:44 +08:00
InfinityPacer
896e473c41 fix(event): filter and handle only enabled event handlers 2024-12-06 01:54:51 +08:00
zhanglijun
12f10ebedf fix: 音轨文件重命名整理 2024-12-06 00:40:38 +08:00
jxxghp
ba9f85747c Merge pull request #3330 from InfinityPacer/feature/subscribe 2024-12-05 17:10:47 +08:00
InfinityPacer
2954c02a7c feat(subscribe): add subscription status update API 2024-12-05 16:24:05 +08:00
InfinityPacer
312e602f12 feat(subscribe): add Pending and Suspended subscription states 2024-12-05 16:22:09 +08:00
InfinityPacer
ed37fcbb07 feat(subscribe): update get_by_state to handle multiple states 2024-12-05 16:20:14 +08:00
jxxghp
6acf8fbf00 Merge pull request #3324 from InfinityPacer/feature/subscribe 2024-12-05 06:54:45 +08:00
InfinityPacer
a1e178c805 feat(event): add ResourceSelection event for update resource contexts 2024-12-04 20:21:57 +08:00
jxxghp
922e2fc446 Merge pull request #3323 from Aqr-K/feat-module 2024-12-04 18:19:15 +08:00
jxxghp
db4c8cb3f2 Merge pull request #3322 from InfinityPacer/feature/subscribe 2024-12-04 18:18:32 +08:00
Aqr-K
1c578746fe fix(module): 补全 indexer 缺少 get_subtype 方法
- 补全 `indexer` 缺少 `get_subtype` 方法。
- 增加 `get_running_subtype_module` 方法,可结合 `types` 快速获取单个运行中的 `module` 。
2024-12-04 18:14:56 +08:00
InfinityPacer
68f88117b6 feat(events): add episodes field to DownloadAdded event for unpack 2024-12-04 16:11:35 +08:00
jxxghp
108c0a89f6 Merge pull request #3320 from InfinityPacer/feature/subscribe 2024-12-04 12:18:19 +08:00
InfinityPacer
92dacdf6a2 fix(subscribe): add RLock to prevent duplicate subscription downloads 2024-12-04 11:07:45 +08:00
InfinityPacer
6aa684d6a5 fix(subscribe): handle case when no subscriptions are found 2024-12-04 11:03:32 +08:00
InfinityPacer
efece8cc56 fix(subscribe): add check for None before updating subscription 2024-12-04 10:27:33 +08:00
jxxghp
383c8ca19a Merge pull request #3313 from Aqr-K/feat-module 2024-12-03 18:09:49 +08:00
jxxghp
0a73681280 Merge pull request #3315 from InfinityPacer/feature/scheduler 2024-12-03 18:09:23 +08:00
InfinityPacer
c1ecda280c fix #3312 2024-12-03 17:33:00 +08:00
Aqr-K
825fc35134 feat(modules): 增加子级 type 分类。
- 在 `types` 里,针对各个模块的类型进行子级分类。
- 为每个模块统一添加 `get_subtype` 方法,这样一来,能更精准快速地区分与调用子类的每个模块,又能获取 ModuleType 所规定的分类以及对应存在的子模块类型支持列表,从而有效解决当下调用时需繁琐遍历每个 module 以获取 get_name 或 _channel 的问题。
- 解决因消息渠道前端返回所保存的 type 与后端规定值不一致,而需要频繁调用 _channel 私有方法才能获取分类所可能产生的问题。
2024-12-03 14:57:19 +08:00
jxxghp
8f543ca602 Merge pull request #3309 from yxlimo/tmdbid-for-downloader 2024-12-03 06:55:36 +08:00
yxlimo
f0ecc1a497 fix: return last record when get downloadhistory by hash 2024-12-02 22:55:57 +08:00
jxxghp
71f170a1ad Merge pull request #3293 from wikrin/v2 2024-12-01 10:23:51 +08:00
Attente
3709b65b0e fix(api): correct variable reference in media scraping logic
- Change incorrect reference from media_info to mediainfo
2024-12-01 03:40:30 +08:00
jxxghp
9d6eb0f1e1 Merge pull request #3291 from mackerel-12138/fix_scraper 2024-11-30 16:06:04 +08:00
jxxghp
c93306147b Merge pull request #3290 from mackerel-12138/fix_poster 2024-11-30 16:05:11 +08:00
zhanglijun
5e8f924a2f fix: 修复指定tmdbid刮削时tmdbid丢失问题 2024-11-30 15:57:47 +08:00
zhanglijun
54988d6397 fix: 修复fanart季图片下载缺失/错误的问题 2024-11-30 13:51:30 +08:00
jxxghp
112761dc4c Merge pull request #3287 from InfinityPacer/feature/security 2024-11-30 07:15:52 +08:00
InfinityPacer
ef20508840 feat(auth): handle service instance retrieval with proper null check 2024-11-30 01:14:36 +08:00
InfinityPacer
589a1765ed feat(auth): support specifying service for authentication 2024-11-30 01:04:48 +08:00
jxxghp
2c666e24f3 Merge pull request #3283 from InfinityPacer/feature/subscribe 2024-11-29 21:12:25 +08:00
InfinityPacer
168e3c5533 fix(subscribe): move state update to finally to prevent duplicates 2024-11-29 18:56:19 +08:00
jxxghp
cda8b2573a Merge pull request #3282 from InfinityPacer/feature/subscribe 2024-11-29 16:47:56 +08:00
InfinityPacer
4cb4eb23b8 fix(subscribe): prevent fallback to search rules if not defined 2024-11-29 16:15:37 +08:00
jxxghp
f208b65570 更新 version.py 2024-11-29 08:59:55 +08:00
jxxghp
8a0a530036 Merge pull request #3279 from wikrin/v2 2024-11-29 07:36:34 +08:00
Attente
76643f13ed Update system.py 2024-11-29 07:33:02 +08:00
Attente
6992284a77 fix(api): 修复规则测试未获取到媒体信息导致的过滤失败问题 2024-11-29 07:25:08 +08:00
jxxghp
9a142799cd Merge pull request #3274 from InfinityPacer/feature/encoding 2024-11-28 17:29:22 +08:00
InfinityPacer
027d1567c3 feat(encoding): set PERFORMANCE_MODE to enabled by default 2024-11-28 17:07:14 +08:00
jxxghp
65af737dfd Merge pull request #3272 from wikrin/transfer 2024-11-28 07:23:25 +08:00
jxxghp
48aa0e3d0b Merge pull request #3271 from wikrin/v2 2024-11-28 07:22:16 +08:00
jxxghp
b4e31893ff Merge pull request #3268 from mackerel-12138/fix_scraper 2024-11-28 07:21:43 +08:00
Attente
4f1b95352a 改进手动整理逻辑 关联后端 jxxghp/MoviePilot-Frontend#255 2024-11-28 05:39:26 +08:00
Attente
ca664cb569 fix: 修复批量整理时媒体库目录匹配不正确的问题 2024-11-28 05:19:09 +08:00
zhanglijun
fe4ea73286 修复季nfo刮削错误, 优化季标题取值 2024-11-27 23:27:08 +08:00
jxxghp
9e9cca6de4 Merge pull request #3262 from InfinityPacer/feature/encoding 2024-11-27 16:25:46 +08:00
InfinityPacer
2e7e74c803 feat(encoding): update configuration to performance mode 2024-11-27 13:52:17 +08:00
InfinityPacer
916597047d Merge branch 'v2' of https://github.com/jxxghp/MoviePilot into feature/encoding 2024-11-27 12:52:01 +08:00
InfinityPacer
83fc474dbe feat(encoding): enhance encoding detection with confidence threshold 2024-11-27 12:33:57 +08:00
jxxghp
f67bf49e69 Merge pull request #3255 from InfinityPacer/feature/event 2024-11-27 06:59:54 +08:00
jxxghp
bf9043f526 Merge pull request #3254 from mackerel-12138/v2 2024-11-27 06:58:47 +08:00
InfinityPacer
a98de604a1 refactor(event): rename SmartRename to TransferRename 2024-11-27 00:50:34 +08:00
InfinityPacer
e160a745a7 fix(event): correct visualize_handlers 2024-11-27 00:49:37 +08:00
zhanglijun
7f2c6ef167 fix: 增加入参判断 2024-11-26 22:25:42 +08:00
jxxghp
2086651dbe Merge pull request #3235 from wikrin/fix 2024-11-26 22:17:32 +08:00
zhanglijun
132fde2308 修复季海报下载路径和第0季海报命名 2024-11-26 22:01:00 +08:00
jxxghp
4e27a1e623 fix #3247 2024-11-26 08:25:01 +08:00
Attente
a453831deb get_dir增加入参
- `include_unsorted`用于表示可否`包含`整理方式`为`不整理`的目录配置
2024-11-26 03:11:25 +08:00
jxxghp
1035ceb4ac Merge pull request #3245 from wikrin/v2 2024-11-25 23:04:15 +08:00
Attente
b7cb917347 fix(transfer): add library type and category folder support
- Add library_type_folder and library_category_folder parameters to the transfer function
- This enhances the transfer functionality by allowing sorting files into folders based on library type and category
2024-11-25 23:02:17 +08:00
jxxghp
680ad164dc Merge pull request #3236 from InfinityPacer/feature/scheduler 2024-11-25 17:54:05 +08:00
InfinityPacer
aed68253e9 feat(scheduler): expose internal methods for external invocation 2024-11-25 16:33:17 +08:00
InfinityPacer
b83c7a5656 feat(scheduler): support plugin method arguments via func_kwargs 2024-11-25 16:31:30 +08:00
InfinityPacer
491456b0a2 feat(scheduler): support plugin replacement for system services 2024-11-25 16:30:11 +08:00
Attente
84465a6536 不整理目录的下载路径可以被下载器获取
修改自动匹配源存储器类型入参
2024-11-25 13:51:04 +08:00
jxxghp
9acbcf4922 v2.1.0 2024-11-25 08:05:07 +08:00
jxxghp
8dc4290695 fix scrape bug 2024-11-25 07:58:17 +08:00
jxxghp
5c95945691 Update README.md 2024-11-24 18:16:37 +08:00
jxxghp
11115d50fb fix dockerfile 2024-11-24 18:14:09 +08:00
jxxghp
7f83d56a7e fix alipan 2024-11-24 17:55:08 +08:00
jxxghp
28805e9e17 fix alipan 2024-11-24 17:45:12 +08:00
jxxghp
88a098abc1 fix log 2024-11-24 17:35:04 +08:00
jxxghp
a3cc9830de fix scraping upload 2024-11-24 17:25:42 +08:00
jxxghp
43623efa99 fix log 2024-11-24 17:19:24 +08:00
jxxghp
ff73b2cb5d fix #3203 2024-11-24 17:11:19 +08:00
jxxghp
6cab14366c Merge pull request #3228 from YemaPT/fix-yemapt-taglist-none 2024-11-24 16:24:38 +08:00
yemapt
576d215d8c fix(yemapt): judge tag list none 2024-11-24 16:22:54 +08:00
jxxghp
a2c10c86bf Merge pull request #3226 from YemaPT/feature-yemapt-optimize 2024-11-24 14:08:04 +08:00
yemapt
21bede3f00 feat(yemapt): update search api and enrich torrent content 2024-11-24 13:45:31 +08:00
jxxghp
0a39322281 Merge pull request #3224 from wikrin/v2 2024-11-24 10:32:47 +08:00
Attente
be323d3da1 fix: 减少入参扩大适用范围 2024-11-24 10:22:29 +08:00
jxxghp
fa8860bf62 Merge pull request #3223 from wikrin/v2
fix: 入参错误
2024-11-24 08:56:58 +08:00
Attente
a700958edb fix: 入参错误 2024-11-24 08:54:59 +08:00
jxxghp
9349973d16 Merge pull request #3221 from wikrin/v2 2024-11-24 07:34:42 +08:00
Attente
c0d3637d12 refactor: change library type and category folder parameters to optional 2024-11-24 00:04:08 +08:00
jxxghp
79473ca229 Merge pull request #3196 from wikrin/fix 2024-11-23 23:01:09 +08:00
Attente
fccbe39547 修改target_directory获取逻辑 2024-11-23 22:41:55 +08:00
Attente
85324acacc 下载流程中get_dir()添加storage="local"入参 2024-11-23 22:41:55 +08:00
Attente
9dec4d704b get_dir去除fileitem参数
- 和`src_path & storage`重复, 需要的话直接传入这两项
2024-11-23 22:41:55 +08:00
jxxghp
72732277a1 fix alipan 2024-11-23 21:54:03 +08:00
jxxghp
8d737f9e37 fix alipan && rclone get_folder 2024-11-23 21:43:53 +08:00
jxxghp
96b3746caa fix alist delete 2024-11-23 21:29:08 +08:00
jxxghp
c690ea3c39 fix #3214
fix #3199
2024-11-23 21:26:22 +08:00
jxxghp
3282fb88e0 Merge pull request #3219 from mackerel-12138/s0_fix 2024-11-23 20:25:08 +08:00
zhanglijun
b9c2b9a044 重命名格式支持S0重命名为Specials,SPs 2024-11-23 20:22:37 +08:00
zhanglijun
24b58dc002 修复S0刮削问题
修复某些情况下剧集根目录判断错误的问题
2024-11-23 20:13:01 +08:00
jxxghp
42c56497c6 Merge pull request #3218 from DDS-Derek/issue_rfc 2024-11-23 12:34:52 +08:00
jxxghp
c7512d1580 Merge pull request #3217 from DDS-Derek/fix_tmp 2024-11-23 12:34:39 +08:00
jxxghp
7d25bf7b48 Merge pull request #3215 from mackerel-12138/v2 2024-11-23 12:34:04 +08:00
DDSRem
99daa3a95e chore(issue): add rfc template 2024-11-23 12:31:28 +08:00
jxxghp
0a923bced9 fix storage 2024-11-23 12:29:34 +08:00
DDSRem
06e3b0def2 fix(update): useless tmp directory when not updated 2024-11-23 12:25:46 +08:00
jxxghp
0feecc3eca fix #3204 2024-11-23 11:48:23 +08:00
jxxghp
0afbc58263 fix #3191 自动整理时,优先同盘 2024-11-23 11:31:56 +08:00
jxxghp
7c7561029a fix #3178 手动整理时支持选择一二级分类 2024-11-23 11:19:25 +08:00
zhanglijun
65683999e1 change comment 2024-11-23 11:00:37 +08:00
zhanglijun
f72e26015f delete unused code 2024-11-23 10:58:32 +08:00
zhanglijun
b4e5c50655 修复重命名时S0年份为None的问题
增加重命名配置 剧集日期
2024-11-23 10:55:21 +08:00
jxxghp
f395dc68c3 fix #3209 刮削加锁 2024-11-23 10:48:54 +08:00
jxxghp
27cf5bb7e6 feat:远程交互刷新数据时发送统计消息 2024-11-23 10:36:48 +08:00
jxxghp
9b573535cd Merge pull request #3201 from InfinityPacer/feature/event 2024-11-22 16:25:52 +08:00
jxxghp
cb32305b86 Merge pull request #3200 from cddjr/fix_subscribe_search_filter 2024-11-22 14:04:08 +08:00
景大侠
f7164450d0 fix: 将订阅规则过滤前置,避免因imdbid匹配而跳过 2024-11-22 13:47:18 +08:00
InfinityPacer
344862dbd4 feat(event): support smart rename event 2024-11-22 13:41:14 +08:00
InfinityPacer
f1d0e9d50a Revert "fix #3154 相同事件避免并发处理"
This reverts commit 79c637e003.
2024-11-22 12:41:14 +08:00
jxxghp
9ba9e8f41c v2.0.9 2024-11-22 08:11:07 +08:00
jxxghp
78fc5b7017 Merge pull request #3193 from wikrin/fix_any_files 2024-11-22 08:10:12 +08:00
Attente
fe07830b71 fix: 某些情况下误删媒体文件的问题 2024-11-22 07:45:01 +08:00
jxxghp
350f1faf2a Merge pull request #3189 from InfinityPacer/feature/module 2024-11-21 20:16:06 +08:00
InfinityPacer
103cfe0b47 fix(config): ensure accurate handling of env config updates 2024-11-21 20:08:18 +08:00
jxxghp
0953c1be16 Merge pull request #3187 from InfinityPacer/feature/scheduler 2024-11-21 17:43:29 +08:00
InfinityPacer
c299bf6f7c fix(auth): adjust auth to occur before module init 2024-11-21 17:37:48 +08:00
InfinityPacer
c0eb9d824c Revert "fix(auth): initialize plugin service only during retry auth"
This reverts commit 9f4cf530f8.
2024-11-21 16:41:56 +08:00
jxxghp
ebffdebdb2 refactor: 优化缓存策略 2024-11-21 15:52:08 +08:00
jxxghp
acd9e38477 Merge pull request #3186 from InfinityPacer/feature/scheduler 2024-11-21 14:54:01 +08:00
InfinityPacer
9f4cf530f8 fix(auth): initialize plugin service only during retry auth 2024-11-21 14:49:42 +08:00
jxxghp
84897aa592 fix #3162 2024-11-21 13:50:49 +08:00
jxxghp
23c5982f5a Merge pull request #3185 from InfinityPacer/feature/module 2024-11-21 12:42:05 +08:00
InfinityPacer
1849930b72 feat(qb): add support for ignoring category check via kwargs 2024-11-21 12:35:15 +08:00
jxxghp
4f1d3a7572 fix #3180 2024-11-21 12:13:44 +08:00
jxxghp
824c3ac5d6 fix #3176 2024-11-21 10:25:46 +08:00
jxxghp
1cec6ed6d1 v2.0.8
- 修复云盘扫码问题
2024-11-20 20:43:44 +08:00
jxxghp
fff75c7fe2 fix 115 2024-11-20 20:40:32 +08:00
jxxghp
81fecf1e07 fix alipan 2024-11-20 20:39:48 +08:00
jxxghp
ad8f687f8e fix alipan 2024-11-20 20:36:50 +08:00
jxxghp
a3172d7503 fix 扫码逻辑与底层模块解耦 2024-11-20 20:17:18 +08:00
jxxghp
8d5e0b26d5 fix:115支持Cookie 2024-11-20 13:14:37 +08:00
jxxghp
b1b980f550 Merge pull request #3171 from Sowevo/v2 2024-11-20 07:07:08 +08:00
Sowevo
8196589cff Merge branch 'jxxghp:v2' into v2 2024-11-19 22:43:31 +08:00
sowevo
cb9f41cb65 plex的item_id统一使用全路径
获取图片时兼容外网地址为Plex的官方转发地址https://app.plex.tv的情况
2024-11-19 22:41:55 +08:00
jxxghp
cb4981adb3 v2.0.7
- 修复了手动整理强制目录的问题
- 修复了AList无法整理文件的问题
- 修复了下载种子不使用全局UA的问题
- 修复了幼儿园的索引
- 修复了一处资源类型识别错误
- 用户认证现在也可以通过UI完成了
2024-11-19 20:42:25 +08:00
jxxghp
6880b42a84 fix #3161 2024-11-19 20:38:06 +08:00
jxxghp
97054adc61 fix 手动整理时强制目录 2024-11-19 20:22:31 +08:00
jxxghp
de94e5d595 fix #3166 2024-11-19 20:12:27 +08:00
jxxghp
a5a734d091 fix u115 transtype 2024-11-19 18:04:48 +08:00
jxxghp
efb607d22f Merge remote-tracking branch 'origin/v2' into v2 2024-11-19 13:31:52 +08:00
jxxghp
d0b2787a7c fix #1832 2024-11-19 13:11:54 +08:00
jxxghp
d5988ff443 Merge pull request #3165 from InfinityPacer/feature/module 2024-11-19 12:24:37 +08:00
InfinityPacer
96b4f1b575 feat(site): set default site timeout to 15 seconds 2024-11-19 11:10:01 +08:00
jxxghp
bb6b8439c7 fix siteauth scheduler 2024-11-19 08:39:39 +08:00
jxxghp
9cdce4509d fix siteauth schema 2024-11-19 08:25:12 +08:00
jxxghp
3956ab1fe8 add siteauth api 2024-11-19 08:18:26 +08:00
jxxghp
14686fdb03 合并拉取请求 #3159
fix: 去除资源搜索中多余的`订阅附加参数`过滤
2024-11-18 23:25:03 +08:00
Attente
32892ab747 fix: 去除资源搜索中多余的订阅附加参数过滤 2024-11-18 17:03:49 +08:00
jxxghp
79c637e003 fix #3154 相同事件避免并发处理 2024-11-18 08:01:43 +08:00
jxxghp
d7c260715a fix 115 2024-11-17 21:22:47 +08:00
jxxghp
2dfb089a39 fix bug 2024-11-17 21:04:24 +08:00
jxxghp
e04179525b Merge pull request #3146 from InfinityPacer/feature/module
chore(qbittorrent): update qbittorrent-api to version 2024.11.69
2024-11-17 15:59:43 +08:00
jxxghp
d044364c68 fix 115扫码后要重启 2024-11-17 15:58:29 +08:00
InfinityPacer
a0f912ffbe chore(qbittorrent): update qbittorrent-api to version 2024.11.69 2024-11-17 15:43:06 +08:00
jxxghp
d7c8b08d7a fix 115 2024-11-17 15:23:30 +08:00
jxxghp
f752082e1b v2.0.6 2024-11-17 15:15:42 +08:00
jxxghp
201ec21adf 优化Dev更新最新前端 2024-11-17 15:14:00 +08:00
jxxghp
57590323b2 fix ext 2024-11-17 14:56:42 +08:00
jxxghp
4636c7ada7 fix #3141 2024-11-17 14:14:13 +08:00
jxxghp
4c86a4da5f fix alist token 2024-11-17 14:07:39 +08:00
jxxghp
8dc9acf071 fix 115 2024-11-17 14:03:03 +08:00
jxxghp
abebae3664 Merge pull request #3139 from wdmcheng/v2 2024-11-17 12:00:41 +08:00
wdmcheng
4f7d8866a0 fix 本地存储 upload 后将文件识别为文件夹的问题 2024-11-17 11:50:33 +08:00
jxxghp
cceb22d729 fix log level 2024-11-17 08:56:02 +08:00
jxxghp
89edbb93f5 fix #3135 2024-11-17 08:52:15 +08:00
jxxghp
4ffb406172 更新 requirements.in 2024-11-17 02:23:07 +08:00
jxxghp
293e417865 feat:切换使用python-115 2024-11-17 02:10:45 +08:00
jxxghp
510c20dc70 fix 2024-11-16 21:49:54 +08:00
jxxghp
8e1810955b fix #3082 2024-11-16 20:56:32 +08:00
jxxghp
73f732fe1d fix #3126 目录删除加固 2024-11-16 20:29:17 +08:00
jxxghp
d6f5160959 fix mteam 消息99999 2024-11-16 19:55:41 +08:00
jxxghp
d64a7086dd fix #3120 2024-11-16 13:32:58 +08:00
jxxghp
825d9b768f 更新 version.py 2024-11-16 11:18:23 +08:00
jxxghp
f758a47f4f Merge pull request #3122 from DDS-Derek/fix_update 2024-11-16 11:02:04 +08:00
jxxghp
fc69d7e6c1 fix 2024-11-16 10:55:17 +08:00
DDSRem
edc30266c8 fix(update): clear tmp directory causes data loss
fix https://github.com/jxxghp/MoviePilot/issues/2996
2024-11-16 10:53:33 +08:00
jxxghp
665da9dad3 Merge pull request #3121 from DDS-Derek/fix_nginx 2024-11-16 10:37:23 +08:00
DDSRem
4048acf60e feat(docker): nginx client_max_body_size configuration
fix https://github.com/jxxghp/MoviePilot/issues/2951
fix https://github.com/jxxghp/MoviePilot/issues/2720
2024-11-16 10:23:28 +08:00
jxxghp
f116229ecc fix #3108 2024-11-16 09:50:55 +08:00
jxxghp
f6a2efb256 fix #3116 2024-11-16 09:25:46 +08:00
jxxghp
af3a50f7ea feat:订阅支持绑定下载器 2024-11-16 09:00:18 +08:00
jxxghp
44a0e5b4a7 fix #3120 2024-11-16 08:41:30 +08:00
jxxghp
f40a1246ff Merge pull request #3118 from wikrin/database 2024-11-16 07:54:53 +08:00
jxxghp
dd890c410c Merge pull request #3117 from wikrin/site 2024-11-16 07:54:42 +08:00
Attente
8fd7f2c875 fix 资源搜索下载时设置的下载器不生效的问题 2024-11-16 01:44:20 +08:00
Attente
8c09b3482f Upgrade the database 2024-11-16 00:28:13 +08:00
Attente
0066247a2b feat: 站点管理增加下载器选择 2024-11-16 00:22:04 +08:00
jxxghp
c7926fc575 Merge pull request #3113 from InfinityPacer/feature/module 2024-11-15 21:59:50 +08:00
InfinityPacer
ac5b9fd4e5 fix(rclone): specify UTF-8 encoding when save config 2024-11-15 17:42:11 +08:00
jxxghp
42dc539df6 fix #3013 2024-11-15 16:17:51 +08:00
jxxghp
e60d785a11 fix meta re 2024-11-15 13:50:33 +08:00
jxxghp
33558d6197 Merge pull request #3102 from InfinityPacer/feature/module 2024-11-15 12:01:21 +08:00
InfinityPacer
46d2ffeb75 fix #3100 2024-11-15 09:08:32 +08:00
jxxghp
8e4bce2f95 fix #3079 2024-11-15 08:03:23 +08:00
jxxghp
00f1f06e3d fix #3079 2024-11-15 08:00:22 +08:00
jxxghp
fe37bde993 fix offset ep 2024-11-14 22:29:14 +08:00
jxxghp
6c3bb8893f Merge pull request #3097 from wdmcheng/v2 2024-11-14 21:47:59 +08:00
wdmcheng
ca4d64819d fix 部分情况下Alist解析时间错误 2024-11-14 21:39:13 +08:00
jxxghp
0a53635d35 Merge pull request #3096 from rexshao/v2 2024-11-14 21:15:47 +08:00
rexshao
921e24b049 Update twofa.py
修复2fa使用secret无法正常生成code的BUG
2024-11-14 21:08:38 +08:00
jxxghp
24c21ed04e fix name 2024-11-14 19:58:37 +08:00
jxxghp
777785579e v2.0.4
- 修复了手动整理时找不到目录的问题
- 修复了白兔站点信息获取、登录状态检测
- 修复了一个索引报错问题
- 优化了资源下载对话框
- 目录设置增加了一个手动整理的选项
- 增加了QB无法连接时的日志打印
- 存储支持挂接AList
2024-11-14 19:48:16 +08:00
jxxghp
8061a06fe4 Merge remote-tracking branch 'origin/v2' into v2 2024-11-14 18:09:49 +08:00
jxxghp
438ce6ee3e fix SiteUserData schema 2024-11-14 18:09:40 +08:00
jxxghp
77e19c3de7 Merge pull request #3095 from InfinityPacer/feature/module 2024-11-14 17:25:31 +08:00
InfinityPacer
49881c9c54 fix #2952 2024-11-14 17:21:47 +08:00
jxxghp
5da28f702f fix alist 2024-11-14 14:54:22 +08:00
jxxghp
dfbd9f3b30 add alist storage card 2024-11-14 12:57:34 +08:00
jxxghp
d6c6ee9b4e fix #3092 2024-11-14 12:38:02 +08:00
jxxghp
4b27404ee5 Merge pull request #3091 from InfinityPacer/feature/cache 2024-11-14 11:57:26 +08:00
jxxghp
3a826b343a fix #3090 2024-11-14 11:52:56 +08:00
jxxghp
851aa5f9e2 fix #3031 2024-11-14 11:49:57 +08:00
InfinityPacer
9ef1f56ea1 feat(cache): add proxy support for specific domains in image caching 2024-11-14 10:21:00 +08:00
jxxghp
78d51b7621 Merge pull request #3031 from Akimio521/feat/filemanager-alist
feat: 增加 filemanager storages 类型:Alist
2024-11-14 08:12:31 +08:00
jxxghp
c12e2bdba7 fix 手动整理Bug 2024-11-14 08:04:52 +08:00
jxxghp
fda11f427c Merge pull request #3087 from amtoaer/fix_hares 2024-11-14 06:49:12 +08:00
amtoaer
d809330225 fix: 修复白兔俱乐部的站点信息获取、登录状态检测 2024-11-14 01:59:30 +08:00
jxxghp
ce4a2314d8 fix 手动整理时目录匹配Bug 2024-11-13 21:30:24 +08:00
amtoaer
c19e825e94 fix: 修复白兔俱乐部登录检测 2024-11-13 18:30:52 +08:00
jxxghp
c45d64b554 Merge pull request #3075 from wikrin/v2 2024-11-12 22:25:53 +08:00
Attente
0689b2e331 fix: episode_offset 2024-11-12 22:22:56 +08:00
jxxghp
e6105fdab5 **v2.0.3**
- 修复了最新版本号获取错误的问题
- 修复了文件管理重命名失败的问题
- 修复了整理多季时 season.nfo 刮削错误的问题
- 修复了Rclone存储容量检测错误的问题
- 优化了自定义规则,剧集文件大小规则按平均每集大小过滤
- 移动文件整理时,自动删除空的父目录
- 增加了自动阅读和发送站点消息的开关
- 增加了数据库WAL模式开关,开启后提升数据库性能
2024-11-12 18:48:15 +08:00
jxxghp
df34c7e2da Merge pull request #3074 from InfinityPacer/feature/db 2024-11-12 17:30:34 +08:00
InfinityPacer
24cc36033f feat(db): add support for SQLite WAL mode 2024-11-12 17:17:16 +08:00
jxxghp
aafb2bc269 fix #3071 增加站点消息开关 2024-11-12 13:59:13 +08:00
jxxghp
9dde56467a 更新 __init__.py 2024-11-12 12:24:05 +08:00
jxxghp
f9d62e7451 fix Rclone存储容量检测问题 2024-11-12 10:10:37 +08:00
jxxghp
f1f379966a fix 修复V2最新版本号获取 2024-11-12 08:37:07 +08:00
jxxghp
942c9ae545 Merge pull request #3058 from wikrin/fix-scrape_metadata 2024-11-10 14:02:31 +08:00
jxxghp
89be4f6200 Merge pull request #3054 from wikrin/fix-rename 2024-11-10 14:02:01 +08:00
Attente
bcbf729fd4 修复整理多季时season.nfo刮削错误的问题 2024-11-10 13:43:59 +08:00
Attente
7fc5b7678e 更改判断顺序 2024-11-10 07:47:49 +08:00
Attente
e20578685a fix: 修复重命名失败的问题 2024-11-09 23:59:58 +08:00
jxxghp
40b82d9cb6 fix #3042 移动模式删除空文件夹 2024-11-09 18:23:08 +08:00
jxxghp
9b2fccee01 feat:剧集文件大小过滤按平均每集大小 2024-11-09 18:01:50 +08:00
jxxghp
87bbee8c36 Merge pull request #3038 from InfinityPacer/feature/setup 2024-11-08 18:16:32 +08:00
InfinityPacer
4412ce9f17 fix(playwright): add check for HTTPS proxy 2024-11-08 18:08:45 +08:00
jxxghp
35b78b0e66 Merge pull request #3034 from lybtt/fix_update_bash 2024-11-08 16:44:55 +08:00
lvyb
d97fcc4a96 修复update脚本,版本号比较问题 2024-11-08 16:37:36 +08:00
Akimio521
c8e337440e feat(storages): add Alist storage type 2024-11-08 14:32:30 +08:00
Akimio521
726e7dfbd4 feat(StringUtils): add url_eqote method 2024-11-08 14:31:08 +08:00
jxxghp
a2096e8e0f v2.0.2 2024-11-08 13:26:05 +08:00
jxxghp
75e80158e5 Merge pull request #3030 from Akimio521/fix(tmdb/douban)-cache 2024-11-08 10:48:23 +08:00
Akimio521
d42bd14288 fix: 优先使用id作为cache key避免key冲突 2024-11-08 10:35:29 +08:00
jxxghp
28f6e7f9bb fix https://github.com/jxxghp/MoviePilot-Plugins/issues/540 2024-11-07 18:58:32 +08:00
jxxghp
2aadbeaed7 Merge pull request #3025 from amtoaer/feat_jellyfin_item_path 2024-11-07 18:48:15 +08:00
jxxghp
3f6b4bf3f2 Merge pull request #3022 from MMZOX/v2 2024-11-07 18:46:59 +08:00
amtoaer
f73750fcf7 feat: 为 jellyfin 的 webhook 事件填充 item_path 字段 2024-11-07 15:01:19 +08:00
MMZOX
59df673eb5 try to fix #2965 2024-11-07 13:45:06 +08:00
jxxghp
e29ab92cd1 fix #3008 2024-11-07 08:27:05 +08:00
jxxghp
3777045a17 fix #3012 2024-11-07 08:24:22 +08:00
jxxghp
16165c0fcc fix #3018 2024-11-07 08:20:11 +08:00
jxxghp
4d377d5e04 Merge pull request #3016 from InfinityPacer/feature/scheduler 2024-11-06 20:01:14 +08:00
InfinityPacer
76c84f9bac fix(scheduler): optimize job registration and removal logic 2024-11-06 19:37:22 +08:00
jxxghp
88f91152d6 Merge pull request #3009 from lybtt/fix_local_storage 2024-11-06 10:52:15 +08:00
lvyb
dfdb88c5ac fix softlink 2024-11-06 09:30:53 +08:00
jxxghp
ec183b6d0d release v2 2024-11-05 21:24:39 +08:00
jxxghp
9d047dddb4 更新 mediaserver.py 2024-11-05 18:39:38 +08:00
jxxghp
2d83880830 更新 mediaserver.py 2024-11-05 18:39:00 +08:00
jxxghp
7e6ef04554 fix 优化媒体服务器图片获取性能 #2993 2024-11-05 18:21:08 +08:00
jxxghp
08aa5fe50a fix bug #2993 2024-11-05 10:07:25 +08:00
jxxghp
656cc1fe01 Merge pull request #3004 from InfinityPacer/feature/module 2024-11-05 07:03:49 +08:00
InfinityPacer
8afaa683cc fix(config): update DB_MAX_OVERFLOW to 500 2024-11-05 00:48:22 +08:00
InfinityPacer
4d3aa0faf3 fix(config): update in-memory setting only on env update 2024-11-05 00:48:02 +08:00
jxxghp
9e08b9129a Merge pull request #2994 from Aqr-K/patch-1
Update system.py
2024-11-04 10:20:42 +08:00
jxxghp
0584bda470 fix bug 2024-11-03 19:59:33 +08:00
jxxghp
df8531e4d8 fix #2993 格式错误和传参警告 2024-11-03 19:51:43 +08:00
jxxghp
cfc51c305b 更新 mediaserver.py 2024-11-03 14:41:42 +08:00
jxxghp
28759f6c81 Merge pull request #2998 from Akimio521/fix/wallpapers 2024-11-03 14:36:08 +08:00
jxxghp
15b701803f Merge pull request #2997 from Akimio521/perfect/cn_name 2024-11-03 14:35:49 +08:00
Akimio521
72774f80a5 fix: 修复 wallpapers 未返回 list 2024-11-03 14:22:04 +08:00
Akimio521
341526b4d9 perfect(MetaAnime): self.cn_name 属性不再进行简化处理,在使用 TMDB 和豆瓣查询时再查询简体化名字 2024-11-03 14:05:12 +08:00
jxxghp
b6bfd215bc Merge pull request #2993 from Akimio521/v2 2024-11-03 06:54:35 +08:00
Akimio521
6801032f7a fix: 避免在匿名环境下暴露Plex地址以及Plex Token 2024-11-02 16:18:17 +08:00
Akimio521
af2075578c feat(Plex): 增加从Plex获取图片的URL选项,支持选择返回Plex URL还是TMDB URL 2024-11-02 16:17:25 +08:00
Akimio521
b46ede86fc fix: 移除不必要的配置导入 2024-11-02 14:57:38 +08:00
Aqr-K
a104001087 Update system.py 2024-11-02 14:27:46 +08:00
Akimio521
88e8790678 feat: 可选从媒体服务器中获取最新入库条目海报作为登录页面壁纸 2024-11-02 14:17:52 +08:00
Akimio521
a59d73a68a feat(PlexModule): 实现获取媒体服务器最新入库条目的图片 2024-11-02 14:17:52 +08:00
Akimio521
522d970731 feat(JellyfinModule): 实现获取媒体服务器最新入库条目的图片 2024-11-02 14:17:52 +08:00
Akimio521
51a0f97580 feat(EmbyModule): 实现获取媒体服务器最新入库条目的图片 2024-11-02 14:17:52 +08:00
jxxghp
0ef6d7bbf2 Merge pull request #2991 from wikrin/fix-get_dir 2024-11-02 06:27:43 +08:00
Attente
d818ceb8e6 fix: 修复了在某些特定场景下,手动整理无法正确获取目标路径的问题。 2024-11-02 02:01:29 +08:00
jxxghp
a69d56d9fd Merge pull request #2978 from wikrin/v2 2024-10-30 18:57:40 +08:00
jxxghp
957df2cf66 Merge pull request #2977 from wdmcheng/v2 2024-10-30 18:57:19 +08:00
wdmcheng
d863a7cb7f 改进 SystemUtils.list_files 遍历目录对特殊字符的兼容性(如'[]') 2024-10-30 18:29:14 +08:00
Attente
021fcb17bb fix: #2974 #2963 2024-10-30 18:16:52 +08:00
jxxghp
b4e233678d Merge pull request #2975 from thsrite/v2 2024-10-30 16:56:57 +08:00
thsrite
5e53825684 fix 增加开启检查本地媒体库是否存在资源开关,按需开启 2024-10-30 16:20:37 +08:00
jxxghp
236d860133 fix monitor 2024-10-30 08:25:26 +08:00
jxxghp
76d939b665 更新 __init__.py 2024-10-30 07:16:44 +08:00
jxxghp
63d35dfeef fix transfer 2024-10-30 07:12:58 +08:00
jxxghp
3dd7d36760 Merge pull request #2970 from wikrin/fix-monitor 2024-10-29 17:49:00 +08:00
jxxghp
e4b0e4bf33 Merge pull request #2969 from wikrin/fix-notify 2024-10-29 06:46:25 +08:00
jxxghp
3504c0cdd6 Merge pull request #2968 from wikrin/fix-get_dir 2024-10-29 06:45:57 +08:00
Attente
980feb3cd2 fix: 修复了整理模式目录监控时, 目标路径不符预期的问题 2024-10-29 06:13:18 +08:00
Attente
a1daf884e6 增加对配置了媒体库目录但没有设置自动整理的处理 2024-10-29 06:06:02 +08:00
Attente
f0e4d9bf63 去除多余判断
```
if src_path and download_path != src_path
if dest_path and library_path != dest_path
```
已经能排除`设定 -> 存储 & 目录`中未设置`下载目录`或`媒体库目录`的目录
2024-10-29 03:43:57 +08:00
Attente
15397a522e fix: 修复整理整个目录时,不发送通知的问题 2024-10-29 02:12:17 +08:00
Attente
1c00c47a9b fix: #2963 可能存在问题的修复
`def get_dir`引用只存在与下载相关模块中, 尝试删除公测看反馈
2024-10-29 00:49:36 +08:00
jxxghp
e9a6f08cc8 Merge pull request #2958 from thsrite/v2 2024-10-28 11:38:17 +08:00
thsrite
7ba2d60925 fix 2024-10-28 11:36:18 +08:00
thsrite
9686a20c2f fix #2905 订阅搜索不走订阅设置的分辨率等规则 2024-10-28 11:29:34 +08:00
jxxghp
6029cf283b Merge pull request #2953 from wikrin/BDMV 2024-10-28 09:55:34 +08:00
Attente
4d6ed7d552 - 将计算目录中所有文件总大小移动到 modules.filemanager 模块中。 2024-10-28 08:31:32 +08:00
Attente
8add8ed631 添加注释 2024-10-27 23:32:15 +08:00
Attente
ab78b10287 将判断移出, 减少is_bluray_dir调用次数 2024-10-27 23:28:28 +08:00
Attente
94ed377843 - 修复整理原盘报错的问题
- 添加类型注解
2024-10-27 23:02:45 +08:00
jxxghp
4cb85a2b4c Merge pull request #2949 from wikrin/fix 2024-10-27 07:56:18 +08:00
Attente
b2a88b2791 修正注释 2024-10-27 02:10:10 +08:00
Attente
88f451147e fix: 不知道算不算bug
- 修复 `新增订阅搜索` 阶段 `包含` 和 `排除` 不生效的问题
2024-10-27 01:36:38 +08:00
jxxghp
51099ace65 Merge pull request #2947 from InfinityPacer/feature/push 2024-10-26 17:11:33 +08:00
InfinityPacer
0564bdf020 fix(event): ensure backward compatibility 2024-10-26 15:56:10 +08:00
jxxghp
bbac709970 更新 __init__.py 2024-10-26 14:17:26 +08:00
jxxghp
bb9690c873 Merge pull request #2946 from InfinityPacer/feature/push 2024-10-26 13:40:38 +08:00
jxxghp
00be46b74f Merge pull request #2944 from wikrin/fix-message 2024-10-26 08:10:00 +08:00
jxxghp
2af21765e0 Merge pull request #2942 from wikrin/v2 2024-10-26 08:09:33 +08:00
Attente
646349ac35 fix: 修正msg => message 2024-10-26 07:10:42 +08:00
InfinityPacer
915388c109 feat(commands): support sending CommandRegister events for clients 2024-10-26 04:51:45 +08:00
InfinityPacer
3c24ae5351 feat(telegram): add delete_commands 2024-10-26 04:48:55 +08:00
InfinityPacer
e876ba38a7 fix(wechat): add error handling 2024-10-26 04:47:42 +08:00
Attente
01546baddc fix: 2941
`delete_media_file` 返回值现修改为:
- `目录存在其他媒体文件`时返回`文件删除状态`
- `目录不存在其他媒体文件`时返回`目录删除状态`
2024-10-26 00:38:42 +08:00
jxxghp
133195cc0a Merge pull request #2940 from thsrite/v2 2024-10-25 19:08:02 +08:00
thsrite
e58911397a fix dc3240e9 2024-10-25 19:06:32 +08:00
jxxghp
10553ad6fc Merge pull request #2939 from DDS-Derek/dev 2024-10-25 18:24:03 +08:00
DDSRem
672d430322 fix(docker): nginx directory permission issue
fix https://github.com/jxxghp/MoviePilot/issues/2892
2024-10-25 18:18:12 +08:00
jxxghp
be785f358d Merge pull request #2938 from InfinityPacer/feature/push 2024-10-25 17:37:11 +08:00
InfinityPacer
eff8a6c497 feat(wechat): add retry mechanism for message requests 2024-10-25 17:27:58 +08:00
InfinityPacer
5d89ad965f fix(telegram): ensure image cache path exists 2024-10-25 17:26:56 +08:00
jxxghp
1651f4677b Merge pull request #2937 from thsrite/v2 2024-10-25 16:59:29 +08:00
thsrite
dc3240e90a fix 种子过滤包含规则 2024-10-25 16:05:54 +08:00
jxxghp
e2ee930ff4 Merge pull request #2935 from thsrite/v2 2024-10-25 13:33:46 +08:00
thsrite
90901d7297 fix 获取站点最新数据的时候排除掉错误的数据 2024-10-25 13:24:29 +08:00
jxxghp
1b76f1c851 feat:站点未读消息发送 2024-10-25 13:10:35 +08:00
jxxghp
3d9853adcf fix #2933 2024-10-25 12:58:06 +08:00
jxxghp
81384c358e Merge pull request #2933 from wikrin/v2-transfer 2024-10-25 12:12:30 +08:00
InfinityPacer
a46463683d Merge branch 'v2' of https://github.com/jxxghp/MoviePilot into feature/push 2024-10-25 10:51:38 +08:00
jxxghp
4cf3b49324 Merge pull request #2932 from InfinityPacer/feature/module 2024-10-25 06:52:57 +08:00
Attente
1f6fa22aa1 fix: 修复 storagechain.list_files 递归得到的列表被覆盖的问题 2024-10-25 02:54:41 +08:00
Attente
d108b0da78 仅取消缩进,没有其他任何改动
减少`for`嵌套, 汇总遍历目录, 这样能提供更准确的`文件数`
2024-10-25 01:28:59 +08:00
Attente
0ee21b38de fix:
- 修复因首个子目录中无目标文件而不处理整个文件夹的问题
- 添加同时整理音轨
2024-10-25 01:27:39 +08:00
InfinityPacer
b1858f4849 fix #2931 2024-10-25 00:42:00 +08:00
InfinityPacer
ac086a7640 refactor(wechat): optimize message handling and add menu deletion 2024-10-24 20:27:41 +08:00
jxxghp
1d252f4eb2 Merge pull request #2930 from InfinityPacer/feature/push 2024-10-24 19:26:50 +08:00
jxxghp
ab354ef0e8 Merge pull request #2929 from InfinityPacer/feature/setup 2024-10-24 19:25:48 +08:00
jxxghp
167cba2dbb Merge pull request #2928 from InfinityPacer/feature/module 2024-10-24 19:25:01 +08:00
InfinityPacer
9cf7547a8c fix(downloader): ensure default downloader config fallback 2024-10-24 19:12:07 +08:00
InfinityPacer
823b81784e fix(setup): optimize logging 2024-10-24 16:50:03 +08:00
InfinityPacer
d9effb54ee feat(commands): support background initialization 2024-10-24 16:26:37 +08:00
jxxghp
1a8d9044d7 fix #2926 2024-10-24 14:28:30 +08:00
InfinityPacer
0a2ce11eb0 fix(setup): adjust dir name 2024-10-24 12:48:54 +08:00
jxxghp
42b5dd4178 fix #2924 2024-10-24 12:39:08 +08:00
InfinityPacer
2bae866f70 Merge branch 'v2' of https://github.com/jxxghp/MoviePilot into feature/setup 2024-10-24 11:21:45 +08:00
InfinityPacer
2470a98491 fix(setup): remove pkg_resources import and add working_set 2024-10-24 11:21:37 +08:00
jxxghp
9d70b117d7 Merge remote-tracking branch 'origin/v2' into v2 2024-10-24 11:14:45 +08:00
jxxghp
1fad9d9904 Merge pull request #2923 from InfinityPacer/feature/setup 2024-10-24 10:50:20 +08:00
jxxghp
dc1533d5e8 Merge pull request #2922 from thsrite/v2 2024-10-24 10:49:10 +08:00
thsrite
e0cfb4fd6d fix 重启后v2插件丢失问题 2024-10-24 10:38:55 +08:00
jxxghp
119919da51 fix:附属文件整理报错 2024-10-24 09:56:39 +08:00
InfinityPacer
684e518b87 fix(setup): remove unnecessary comments 2024-10-24 09:53:44 +08:00
jxxghp
50febd6b2c 更新 update 2024-10-24 07:14:37 +08:00
InfinityPacer
86dec5aec2 feat(setup): complete missing dependencies installation 2024-10-24 02:55:54 +08:00
jxxghp
fa021de2ae Merge pull request #2918 from InfinityPacer/feature/event 2024-10-23 20:15:51 +08:00
InfinityPacer
874572253c feat(auth): integrate Plex auxiliary authentication support 2024-10-23 20:11:23 +08:00
jxxghp
059f7f8146 更新 update 2024-10-23 20:09:02 +08:00
jxxghp
d6f8c364bf refactor: 删除历史记录时删除空目录(无媒体文件) 2024-10-23 18:02:31 +08:00
jxxghp
a6f0792014 refactor: get_parent 2024-10-23 17:47:01 +08:00
jxxghp
a4419796ac Merge remote-tracking branch 'origin/v2' into v2 2024-10-23 17:05:28 +08:00
jxxghp
dad980fa14 fix 附属文件整理 2024-10-23 17:05:20 +08:00
jxxghp
a3cb805c64 Merge pull request #2916 from InfinityPacer/feature/push 2024-10-23 16:34:54 +08:00
InfinityPacer
c128dd9507 fix(command): delay module import 2024-10-23 16:32:12 +08:00
jxxghp
dbf1b691d6 目录监控服务去重 2024-10-23 15:58:00 +08:00
jxxghp
4199438d5e fix update shell 2024-10-23 15:09:46 +08:00
jxxghp
a0ad8faaf7 fix #2913 2024-10-23 14:43:47 +08:00
jxxghp
c4619edcde Merge pull request #2913 from thsrite/v2 2024-10-23 13:29:34 +08:00
thsrite
51f8fc07eb fix transfer notify 2024-10-23 13:24:08 +08:00
thsrite
f7357b8a71 feat 目录自定义是否通知 2024-10-23 12:57:51 +08:00
jxxghp
c5e7050898 Merge pull request #2912 from thsrite/v2 2024-10-23 12:36:37 +08:00
thsrite
5871c60a9d fix 修复目录监控·真 2024-10-23 12:34:39 +08:00
jxxghp
078bca1259 Merge pull request #2911 from thsrite/v2 2024-10-23 11:45:10 +08:00
thsrite
6ca78c0cb9 feat 目录监控可选监控模式 2024-10-23 11:35:40 +08:00
jxxghp
f03a977a99 Merge pull request #2909 from InfinityPacer/feature/push 2024-10-23 07:04:58 +08:00
InfinityPacer
ab32d3347d feat(command): optimize command registration event handling 2024-10-23 02:26:11 +08:00
jxxghp
f8631c68a3 Merge pull request #2904 from InfinityPacer/feature/setup 2024-10-22 17:38:34 +08:00
jxxghp
a052850990 Merge pull request #2903 from thsrite/v2 2024-10-22 17:37:54 +08:00
InfinityPacer
ea9db33323 chore(deps): keep requirements.txt consistent with requirements.in 2024-10-22 17:12:02 +08:00
thsrite
72b955ebae fix 2024-10-22 16:53:17 +08:00
thsrite
b1545fc351 Merge remote-tracking branch 'origin/v2' into v2 2024-10-22 16:47:50 +08:00
thsrite
be09d5e65d fix 修复自定义规则包含、过滤 2024-10-22 16:47:31 +08:00
InfinityPacer
48f4505161 chore(deps): keep requirements.txt consistent with requirements.in 2024-10-22 16:45:35 +08:00
jxxghp
5c5182941f fix 二级分类bug 2024-10-22 13:49:53 +08:00
jxxghp
7a0b0d114e fix 二级分类bug 2024-10-22 13:03:30 +08:00
jxxghp
5eaffd9797 make release 2024-10-22 12:58:58 +08:00
jxxghp
7cfa315529 build v2 latest 2024-10-22 12:47:18 +08:00
jxxghp
6869708e8e 更新 Dockerfile 2024-10-22 12:20:23 +08:00
jxxghp
5311b5f66a Merge pull request #2901 from thsrite/v2 2024-10-22 12:12:00 +08:00
jxxghp
f3144807bd build v2 beta 2024-10-22 12:09:57 +08:00
thsrite
7437c1ca51 fix 目录监控汇总消息发送 && 剧集刮削 2024-10-22 12:08:13 +08:00
jxxghp
60632aa9d3 Merge pull request #2899 from thsrite/dev 2024-10-22 11:22:51 +08:00
thsrite
c66793c0c8 fix 剧集根路径刮削 2024-10-22 11:10:40 +08:00
jxxghp
d5c8dffffe Merge pull request #2898 from thsrite/dev 2024-10-22 10:54:53 +08:00
thsrite
d4ac585549 fix 修复季刮削图片错位 && 集刮削图片None 2024-10-22 10:42:09 +08:00
jxxghp
b9c368e087 Merge pull request #2897 from InfinityPacer/feature/event 2024-10-22 10:33:29 +08:00
jxxghp
bda0d7a9fb Merge pull request #2896 from thsrite/dev 2024-10-22 09:50:39 +08:00
thsrite
d29ab9b5bd fix dirmonitor exclude_words 2024-10-22 09:49:43 +08:00
InfinityPacer
b2d66b8973 fix(auth): make login_access_token synchronous to prevent blocking 2024-10-22 02:02:21 +08:00
jxxghp
bb858f4bc1 Merge pull request #2895 from InfinityPacer/feature/plugin 2024-10-22 01:45:24 +08:00
InfinityPacer
6b875ef2de feat(plugin): add state check for commands, APIs, and services 2024-10-22 01:36:48 +08:00
jxxghp
0145421885 Merge pull request #2894 from InfinityPacer/feature/push 2024-10-21 23:44:55 +08:00
InfinityPacer
0ac6d9f25e fix(config): adjust API_TOKEN validation logic 2024-10-21 21:46:24 +08:00
jxxghp
80328bdf2d Merge pull request #2891 from InfinityPacer/feature/push 2024-10-21 18:30:13 +08:00
InfinityPacer
87166b3cd7 feat(command): add validation for menu configuration 2024-10-21 16:54:43 +08:00
jxxghp
f91daf2106 Merge pull request #2888 from thsrite/dev 2024-10-21 13:35:04 +08:00
thsrite
3c8cf65902 feat 本地目录监控统一汇总消息发送 2024-10-21 13:22:21 +08:00
jxxghp
3c784e946a Merge pull request #2887 from InfinityPacer/feature/module 2024-10-21 13:18:33 +08:00
InfinityPacer
4034d69fbc fix(config): improve env update logic 2024-10-21 13:15:40 +08:00
jxxghp
eeed9849ef SubscribeHistory 表结构修复 2024-10-21 13:07:47 +08:00
jxxghp
b07297c7e1 Merge pull request #2886 from InfinityPacer/feature/module 2024-10-21 06:42:48 +08:00
InfinityPacer
87813c853b fix(config): improve env update logic 2024-10-20 23:39:20 +08:00
jxxghp
571997fa8e Merge pull request #2885 from InfinityPacer/feature/module 2024-10-20 19:16:02 +08:00
InfinityPacer
9255c85a85 refactor(module): unify config retrieval logic 2024-10-20 18:56:52 +08:00
jxxghp
dba5603359 Merge pull request #2884 from InfinityPacer/feature/db 2024-10-20 17:35:16 +08:00
jxxghp
e76cb97092 Merge pull request #2882 from Aqr-K/dev-update 2024-10-20 16:58:51 +08:00
Aqr-K
6dde33d8fc fix(update)
- 修复了因主版本号的 v 前缀未去除而导致无法判断的问题。
- 增加了对非法版本号的识别。
- 将 `cat` 替换为 `grep` 并进行优化,即使 `version.py` 增加更多值,也能正常使用。
- 修复了 `cat` 获取的值中存在回车符、换行符,从而导致参数无法被版本判断正常识别使用的问题。
- 增加了自动排除 `version.py` 文件中变量行末尾注释的功能,并自动去除首尾多余空格,以确保始终能正确获取到需要的值。
2024-10-20 16:31:50 +08:00
InfinityPacer
d1d98a9081 feat(db): add pool class configuration and adjust connection settings 2024-10-20 03:10:08 +08:00
jxxghp
08e07625cd fix 远程交互命令 2024-10-20 01:54:24 +08:00
jxxghp
c650f1b5e3 Merge pull request #2879 from InfinityPacer/feature/cache 2024-10-20 01:08:45 +08:00
InfinityPacer
2c8ecdfcb9 fix(cache): support clear image cache 2024-10-20 01:05:06 +08:00
jxxghp
c6febe4755 Merge pull request #2878 from InfinityPacer/feature/module 2024-10-20 00:28:09 +08:00
InfinityPacer
08830c7edd revert: restore mistakenly committed 2024-10-20 00:26:50 +08:00
jxxghp
1a40860a5d fix default config 2024-10-19 23:54:41 +08:00
jxxghp
afd0edf7d1 fix 删除历史记录文件处理 2024-10-19 23:43:32 +08:00
jxxghp
c2d3a00615 Merge pull request #2877 from InfinityPacer/feature/event 2024-10-19 21:23:14 +08:00
InfinityPacer
5b6083a1ec fix(auth): prevent disabled users from authenticating 2024-10-19 21:18:02 +08:00
jxxghp
363f12ed5a refactor:Module加入执行优先顺序 2024-10-19 19:31:25 +08:00
jxxghp
de17bc5645 refactor:媒体服务器返回类型 2024-10-19 19:04:16 +08:00
jxxghp
1e4f3e97cd refactor:media_exists 支持指定服务器 2024-10-19 18:17:35 +08:00
jxxghp
69c02291a3 Merge pull request #2876 from InfinityPacer/feature/event
feat(auth): enhance auxiliary authentication
2024-10-19 18:04:43 +08:00
InfinityPacer
c7b27784c9 fix(auth): resolve conflicts 2024-10-19 18:03:18 +08:00
jxxghp
616b15e18a Merge pull request #2875 from Aqr-K/dev-login 2024-10-19 18:00:51 +08:00
InfinityPacer
1e781ba3d1 feat(auth): ensure user creation only for password strategy 2024-10-19 17:32:55 +08:00
InfinityPacer
d48c4d15e2 feat(auth): update intercept event type 2024-10-19 16:57:44 +08:00
jxxghp
1c2a194a7d fix rclone && alipan 2024-10-19 12:29:45 +08:00
Aqr-K
5d1ccef5a2 fix(login): 增加返回user_id 2024-10-19 11:36:03 +08:00
jxxghp
6f299b3255 fix bug 2024-10-19 08:13:47 +08:00
jxxghp
974fe7c965 更新 user.py 2024-10-19 07:33:44 +08:00
InfinityPacer
d8e7c7e6d7 feat(auth): enhance auxiliary authentication 2024-10-19 03:16:04 +08:00
jxxghp
386ff672a7 Merge pull request #2869 from DDS-Derek/docker 2024-10-18 21:19:48 +08:00
DDSRem
a802de2589 feat: docker built-in v2 compatible plugin 2024-10-18 20:25:54 +08:00
jxxghp
b6eac122b8 Merge pull request #2868 from InfinityPacer/feature/event 2024-10-18 20:16:45 +08:00
InfinityPacer
1a8e1844b4 feat(chain): add auth event to ChainEventType 2024-10-18 20:03:05 +08:00
jxxghp
2b982ce7a8 fix 消息交互 again 2024-10-18 18:30:34 +08:00
jxxghp
e93b3f5602 fix 消息交互 2024-10-18 18:10:46 +08:00
jxxghp
5ef4fc04d5 Merge pull request #2864 from Aqr-K/dev-user 2024-10-18 06:55:37 +08:00
jxxghp
1190d8dda4 Merge pull request #2863 from InfinityPacer/feature/setup 2024-10-18 06:54:03 +08:00
Aqr-K
0805f02f1f feat(user): Add username modification 2024-10-18 03:12:15 +08:00
InfinityPacer
4accd5d784 refactor(lifecycle): enhance shutdown support for event and mediaserver 2024-10-18 00:42:54 +08:00
InfinityPacer
4c2bb99b59 refactor(lifecycle): add async support for SSE 2024-10-18 00:39:54 +08:00
InfinityPacer
348923aaa6 refactor(lifecycle): set background threads to daemon mode 2024-10-18 00:39:54 +08:00
InfinityPacer
62ac03fb29 refactor(lifecycle): add graceful support and remove signal handling 2024-10-18 00:39:53 +08:00
jxxghp
a4bf59ad58 add 查询所有站点最新用户数据 api 2024-10-17 21:42:18 +08:00
jxxghp
c02c19d719 Merge pull request #2862 from InfinityPacer/feature/event 2024-10-17 16:15:27 +08:00
InfinityPacer
b83279b05a fix(site): resolve site user data update failure 2024-10-17 15:00:18 +08:00
jxxghp
cf94c70f8c Merge pull request #2861 from InfinityPacer/feature/event 2024-10-17 14:43:58 +08:00
InfinityPacer
52a15086cb feat(event): add SiteRefreshed event 2024-10-17 14:38:46 +08:00
jxxghp
8234c29006 Merge pull request #2860 from InfinityPacer/feature/setup 2024-10-17 12:18:29 +08:00
jxxghp
aeed9fb48e fix:SiteUserData 2024-10-17 12:17:03 +08:00
InfinityPacer
e233bc678c feat(plugin): add force install option and backup/restore on failure 2024-10-17 11:24:27 +08:00
InfinityPacer
346c6dd11c fix(plugin): optimize exist check and cleanup on installation failure 2024-10-17 10:51:14 +08:00
InfinityPacer
bcc48e885a feat(setup): support asynchronous install plugins on startup 2024-10-17 09:37:51 +08:00
jxxghp
4469a1b3b8 fix:优化媒体服务器同步媒体库设置 2024-10-16 15:58:37 +08:00
jxxghp
54666cb757 feat:优先下载排序逻辑,更加精细化 2024-10-16 15:30:58 +08:00
jxxghp
4455ac13e9 fix log 2024-10-16 08:12:34 +08:00
jxxghp
981e5ea927 Merge pull request #2856 from InfinityPacer/feature/module 2024-10-15 16:27:07 +08:00
jxxghp
541a3d68e6 Merge pull request #2855 from InfinityPacer/feature/event 2024-10-15 15:52:23 +08:00
InfinityPacer
ccc11c4892 fix(mediaserver): update get_type return type to ModuleType for consistency 2024-10-15 15:35:45 +08:00
InfinityPacer
9548409bd5 fix(event): refine handler invocation and improve class loading checks 2024-10-15 15:09:32 +08:00
InfinityPacer
11c10ea783 fix(event): improve handler enablement check mechanism 2024-10-15 14:44:13 +08:00
jxxghp
e99913f900 fix shudown 2024-10-15 13:43:13 +08:00
jxxghp
8af37a0adc fix shudown 2024-10-15 13:42:41 +08:00
jxxghp
810e3c98f9 Merge pull request #2854 from InfinityPacer/feature/security 2024-10-15 07:51:17 +08:00
jxxghp
4877ec68b1 feat:下载按站点上传排序 2024-10-14 19:45:22 +08:00
InfinityPacer
12c669aa17 fix(security): optimize URL validation 2024-10-14 19:38:25 +08:00
jxxghp
7fd65c572b Merge pull request #2852 from InfinityPacer/feature/cache 2024-10-14 17:09:27 +08:00
InfinityPacer
89819f8730 feat(cache): add HTTP cache support for image proxy 2024-10-14 17:00:27 +08:00
jxxghp
954110f166 Merge pull request #2849 from wikrin/dev 2024-10-14 06:50:29 +08:00
jxxghp
bd1427474d Merge pull request #2848 from InfinityPacer/feature/security 2024-10-14 06:49:38 +08:00
Attente
3909bb6393 fix: 修复订阅中文件加载失败的问题
- 修正哈希值字段名
可能存在的问题: 依赖网络获取信息
2024-10-14 05:44:50 +08:00
Attente
9a8e0a256a fix: 修复获取不到媒体文件的问题
通过递归列出目录中所有文件, 修复获取不到`Seasion X`目录下媒体文件的bug
2024-10-14 02:58:00 +08:00
InfinityPacer
675655bfc7 fix(security): optimize image caching 2024-10-14 02:22:07 +08:00
InfinityPacer
422474b4b7 feat(security): enhance image URL and domain validation 2024-10-14 01:33:53 +08:00
InfinityPacer
efb624259a fix(Utils): remove unnecessary methods 2024-10-13 22:40:58 +08:00
InfinityPacer
f9e06e4381 feat(security): add safe path check for log file access and validation 2024-10-13 21:59:22 +08:00
InfinityPacer
f67ee27618 Merge branch 'dev' of https://github.com/jxxghp/MoviePilot into feature/security 2024-10-13 00:13:35 +08:00
jxxghp
5224e6751d Merge pull request #2843 from InfinityPacer/dev 2024-10-12 14:36:45 +08:00
InfinityPacer
b263489635 feat(downloader): add compatibility support for qBittorrent 5.0 2024-10-12 14:27:35 +08:00
jxxghp
1a10f6d6e3 fix typo error 2024-10-12 12:34:28 +08:00
jxxghp
4e3a76ffa3 fix bug 2024-10-12 12:32:50 +08:00
jxxghp
0d139851af fix 按对象名称组织代码文件 2024-10-12 12:14:49 +08:00
jxxghp
603ab97665 add ModuleType Schema 2024-10-12 11:50:00 +08:00
jxxghp
fcfeeb09d3 Merge pull request #2838 from InfinityPacer/dev 2024-10-12 06:50:45 +08:00
InfinityPacer
ea32cd83af chore(deps): upgrade qbittorrent-api to support qbittorrent 5.0 2024-10-12 00:12:41 +08:00
jxxghp
1b8380d0c2 Merge pull request #2837 from Aqr-K/dev-update 2024-10-11 22:22:25 +08:00
Aqr-K
e3901c7621 feat(update): 解决v2版本启动时被v1覆盖的问题
- 原本不支持的带 `-` 的特殊后缀版本,现已支持,且内置4种英文格式的后缀(可修改)。
特殊后缀优先级:alpha < beta < rc < stable < 数字大小
版本优先级:v1.9.17-alpha < v1.9.17 < v1.9.17-2 < v2.0.0-alpha < v2.0.0 < v2.0.0-2
2024-10-11 22:15:45 +08:00
jxxghp
f633d09a1d Merge pull request #2832 from wikrin/dev 2024-10-10 22:49:24 +08:00
jxxghp
e4cc834fa7 Merge pull request #2831 from InfinityPacer/feature/push 2024-10-10 22:46:54 +08:00
InfinityPacer
828e9ab886 feat(webhook): add support for server_name field in WebhookEventInfo 2024-10-10 22:07:03 +08:00
Attente
d1bf1411b6 fix: 修正重复的特殊字符 [U+2014](https://symbl.cc/cn/2014/) --> [U+2015](https://symbl.cc/cn/2015/) 2024-10-10 22:01:09 +08:00
InfinityPacer
7532929669 fix(security): update SameSite setting to Lax for better compatibility 2024-10-10 20:08:30 +08:00
jxxghp
d2a613a441 Merge remote-tracking branch 'origin/dev' into dev 2024-10-10 19:04:46 +08:00
jxxghp
eb66f6c05a move NameRecognize to ChainEventType 2024-10-10 19:04:37 +08:00
jxxghp
9f79a30960 Merge pull request #2828 from InfinityPacer/feature/security 2024-10-10 15:58:58 +08:00
InfinityPacer
51391db262 fix(security): adjust resource token duration and refresh strategy 2024-10-10 15:43:29 +08:00
jxxghp
3541d47baf Merge remote-tracking branch 'origin/dev' into dev 2024-10-10 13:11:37 +08:00
jxxghp
b0c11bbe5f fix tmdb_trending api 2024-10-10 13:11:30 +08:00
jxxghp
82253af5a5 Merge pull request #2827 from InfinityPacer/feature/module 2024-10-10 06:34:01 +08:00
jxxghp
5ba555eead Merge pull request #2826 from InfinityPacer/feature/security 2024-10-10 06:33:29 +08:00
InfinityPacer
0c73bbbfe0 fix #2727 2024-10-10 02:09:23 +08:00
InfinityPacer
55403cd8a8 fix(security): handle errors and prevent unnecessary token refresh 2024-10-10 01:40:13 +08:00
InfinityPacer
871f8d3529 feat(security): add resource token authentication using HttpOnly Cookie 2024-10-10 00:45:26 +08:00
jxxghp
cadc0b0511 fix bug 2024-10-09 20:46:34 +08:00
jxxghp
084b5c8d68 add:订阅分享与复用API 2024-10-09 18:33:30 +08:00
jxxghp
16f6303609 fix 优化逻辑 2024-10-09 16:50:54 +08:00
jxxghp
7ea01c1109 feat:支持订阅绑定类别和自定义识别词 2024-10-09 15:21:32 +08:00
jxxghp
e31df15b5e Merge pull request #2820 from Cabbagec/dev-runscheduler2 2024-10-09 12:06:09 +08:00
Cabbagec
78cbe1aaed fix: formatting app/api/endpoints/system.py 2024-10-09 11:54:49 +08:00
jxxghp
2bfd32f716 Merge pull request #2821 from InfinityPacer/feature/module 2024-10-09 06:43:35 +08:00
jxxghp
092ac8a124 Merge pull request #2819 from InfinityPacer/feature/plugin 2024-10-09 06:40:39 +08:00
InfinityPacer
0d3d6e9bf9 fix(download): ensure params parsed from request body 2024-10-09 02:29:52 +08:00
InfinityPacer
e2ee3ec4cd feat(event): add downloader field to DownloadAdded event 2024-10-09 01:49:25 +08:00
InfinityPacer
9e161fb36c feat(module): add support for name filtering in service retrieval 2024-10-09 01:48:41 +08:00
brandonzhang
1b00bbc890 feat(endpoints): run scheduler through api by token 2024-10-08 23:54:18 +08:00
InfinityPacer
812d6029d0 chore: update plugin paths to use plugins.v2 2024-10-08 23:47:59 +08:00
jxxghp
52cf154e65 Merge pull request #2818 from InfinityPacer/feature/security 2024-10-08 20:36:49 +08:00
InfinityPacer
5b6b1231fe fix(security): update comments 2024-10-08 19:07:48 +08:00
InfinityPacer
1a9ba58023 feat(security): add token validation and support multi-server 2024-10-08 18:54:28 +08:00
InfinityPacer
4dd146d1c8 feat(security): replace validation with Depends for system endpoints 2024-10-08 18:12:40 +08:00
InfinityPacer
4af57d9857 feat(security): restore token validation 2024-10-08 17:28:30 +08:00
InfinityPacer
4f01b82b81 feat(security): unify token validation for message endpoints 2024-10-08 14:32:29 +08:00
jxxghp
9547847037 Merge pull request #2815 from InfinityPacer/feature/security 2024-10-08 06:32:03 +08:00
InfinityPacer
284082741e feat(security): obfuscate error messages in anonymous API 2024-10-08 01:51:45 +08:00
InfinityPacer
d7da2e133a feat(security): add cache to wallpaper endpoints to mitigate attacks 2024-10-07 23:37:20 +08:00
jxxghp
b704dcfe07 Merge pull request #2813 from InfinityPacer/feature/plugin 2024-10-07 21:00:11 +08:00
InfinityPacer
5c05845500 refactor(security): replace Depends with Security and define schemes 2024-10-07 16:35:39 +08:00
InfinityPacer
75530a22c3 fix(plugin): use positional arguments in get_plugins 2024-10-06 23:00:21 +08:00
jxxghp
cd4a6476c9 Merge pull request #2812 from InfinityPacer/feature/module 2024-10-06 14:49:52 +08:00
InfinityPacer
0afdd9056a fix(module): use getters for _instances and _configs in subclasses 2024-10-06 14:38:17 +08:00
InfinityPacer
5de882d788 fix(plex): resolve error in get_webhook_message 2024-10-06 14:26:44 +08:00
jxxghp
c35f1f0a07 Merge pull request #2811 from InfinityPacer/feature/module 2024-10-06 11:08:40 +08:00
InfinityPacer
4f27897e08 refactor(config): replace hard-coded strings with SystemConfigKey 2024-10-06 01:58:19 +08:00
InfinityPacer
ea76a27d26 feat(config): enforce API_TOKEN to meet security requirements 2024-10-06 01:33:16 +08:00
InfinityPacer
9d71c9b61e feat(config): centralize set_key usage through update_setting method 2024-10-05 03:14:16 +08:00
jxxghp
1484ce86a9 Merge pull request #2802 from InfinityPacer/feature/module 2024-10-02 20:16:49 +08:00
jxxghp
3b0154f8e3 Merge pull request #2801 from InfinityPacer/feature/plugin 2024-10-02 20:12:39 +08:00
InfinityPacer
cb761275ab feat(config): preprocess env variables using Pydantic validators 2024-10-02 19:17:31 +08:00
InfinityPacer
210c5e3151 feat(plugin): broadcast PluginReload event when plugin reload 2024-10-02 16:22:28 +08:00
jxxghp
bbe8f7f080 Merge pull request #2800 from InfinityPacer/feature/module 2024-10-02 13:08:40 +08:00
InfinityPacer
8317b6b7a2 fix(mediaserver): resolve media_statistic 2024-10-02 13:04:39 +08:00
jxxghp
9dcb28fe3d Merge pull request #2799 from InfinityPacer/feature/module 2024-10-02 11:50:14 +08:00
InfinityPacer
fb61eda831 fix(mediaserver): improve data isolation handling 2024-10-02 10:39:04 +08:00
jxxghp
f8149afb6e Merge pull request #2798 from InfinityPacer/feature/module 2024-10-01 19:46:17 +08:00
InfinityPacer
9dc603bd73 feat(downloader): support first_last_piece 2024-10-01 18:36:31 +08:00
jxxghp
0da914b891 Merge pull request #2797 from InfinityPacer/feature/db 2024-10-01 16:00:53 +08:00
jxxghp
5701bbb146 Merge pull request #2796 from InfinityPacer/feature/module 2024-10-01 16:00:23 +08:00
InfinityPacer
4b6d269230 feat(module): add type-checking methods 2024-10-01 15:28:26 +08:00
InfinityPacer
a25ff4302d fix(db): update Pydantic model to allow any type for 'note' field 2024-10-01 15:20:30 +08:00
jxxghp
80ada2232e Merge pull request #2795 from DDS-Derek/dev 2024-10-01 11:23:44 +08:00
DDSRem
557c1cd1e6 chore: update code logic optimization 2024-10-01 11:21:39 +08:00
jxxghp
7473f0ba27 Merge pull request #2793 from InfinityPacer/feature/db 2024-09-30 20:31:17 +08:00
jxxghp
ee455ac61e Merge pull request #2792 from InfinityPacer/feature/event 2024-09-30 20:28:56 +08:00
InfinityPacer
0ca42236d6 feat(event): add ModuleReload event type 2024-09-30 19:20:18 +08:00
InfinityPacer
835e0b4d5d fix(event): prevent error calls 2024-09-30 18:10:42 +08:00
InfinityPacer
d3186cd742 refactor(db): convert suitable string fields to JSON type 2024-09-30 16:16:29 +08:00
InfinityPacer
d69041f049 Merge remote-tracking branch 'upstream/dev' into feature/db 2024-09-30 14:31:20 +08:00
jxxghp
666f9a536d fix subscribe api 2024-09-30 13:33:06 +08:00
jxxghp
637e92304f Merge pull request #2791 from InfinityPacer/feature/plugin 2024-09-30 12:10:15 +08:00
jxxghp
80a1ded602 fix scraping file upload 2024-09-30 12:06:07 +08:00
InfinityPacer
e731767dfa feat(plugin): add PluginTriggered event type 2024-09-30 10:33:20 +08:00
jxxghp
06ea9e2d09 fix siteuserdata 2024-09-30 10:26:32 +08:00
jxxghp
886b31b35d Merge pull request #2790 from InfinityPacer/dev 2024-09-30 06:46:01 +08:00
jxxghp
da872cca41 Merge pull request #2789 from InfinityPacer/feature/module 2024-09-30 06:45:46 +08:00
InfinityPacer
daadfcffd8 feat(db): update model to support JSON 2024-09-30 03:07:33 +08:00
InfinityPacer
838e17bf6e fix(sync): have module return results directly instead of using yield 2024-09-30 02:59:09 +08:00
InfinityPacer
61ecc175f3 chore: Update .gitignore 2024-09-30 02:13:45 +08:00
InfinityPacer
709f8ef3ed chore: Update .gitignore to exclude all log files and archives 2024-09-30 00:38:01 +08:00
InfinityPacer
fdab59a84e fix #2784 2024-09-30 00:31:03 +08:00
InfinityPacer
0593275a62 feat(module): add ServiceBaseHelper for service and instance 2024-09-29 23:46:41 +08:00
jxxghp
7c643432ee Merge pull request #2783 from InfinityPacer/dev 2024-09-28 06:51:44 +08:00
InfinityPacer
5993bfcefb fix(#2755): remove yield None, handle generator termination on error 2024-09-28 00:57:59 +08:00
InfinityPacer
1add203c0e fix(#2755): refactor pagination and fix media sync DB issue 2024-09-28 00:57:13 +08:00
jxxghp
8b00e9cb72 Merge pull request #2781 from DDS-Derek/dev 2024-09-27 18:02:14 +08:00
DDSRem
14dd7c4e31 chore: use static compilation of aria2c 2024-09-27 17:33:52 +08:00
InfinityPacer
48122d8d9a fix(#2755): handle Plex None values and exceptions in item builder 2024-09-27 17:23:27 +08:00
jxxghp
8f5cf33fa9 Merge pull request #2780 from InfinityPacer/feature/module 2024-09-27 10:19:28 +08:00
jxxghp
3fe79d589a Merge pull request #2779 from InfinityPacer/feature/push 2024-09-27 10:09:55 +08:00
jxxghp
f3956a0504 Merge pull request #2778 from InfinityPacer/feature/plugin 2024-09-27 10:09:33 +08:00
InfinityPacer
efb3bd93d0 fix(wechat): reorder proxy setup 2024-09-27 04:27:16 +08:00
InfinityPacer
640a67fc3a fix(module): resolve infinite recursion in get_instance method 2024-09-27 04:12:22 +08:00
InfinityPacer
2ce3ddb75a refactor(module): simplify service instantiation with generics 2024-09-27 04:04:56 +08:00
jxxghp
1a36d9fe7a Merge pull request #2777 from Aqr-K/dev-transtype 2024-09-26 23:31:22 +08:00
Aqr-K
255c05daf9 fix: method name spelling error 2024-09-26 23:14:55 +08:00
Aqr-K
d1abc23cbd 更新 storage.py 2024-09-26 21:00:21 +08:00
Aqr-K
35c68fe30d feat: transType API
- 针对查询可用整理方式的API
2024-09-26 20:56:33 +08:00
InfinityPacer
5efcd6e6be refactor (module): improve the implementation of base classes 2024-09-26 19:44:35 +08:00
jxxghp
46fb52fff9 merge db oper 2024-09-26 14:13:29 +08:00
jxxghp
c6abb1f9f1 fix 站点数据刷新 2024-09-26 14:00:10 +08:00
jxxghp
b4b919db86 fix typo 2024-09-26 12:50:48 +08:00
jxxghp
1cef5e43e3 fix rule load 2024-09-26 12:36:56 +08:00
jxxghp
f6baf62189 Merge pull request #2776 from InfinityPacer/dev 2024-09-26 11:54:14 +08:00
InfinityPacer
e1aa4b7519 fix #2751 2024-09-26 11:11:17 +08:00
jxxghp
ddfcdf9ce2 fix 115网盘整理 2024-09-26 08:36:08 +08:00
jxxghp
eff3fadfbf Merge pull request #2775 from InfinityPacer/dev 2024-09-26 06:49:15 +08:00
InfinityPacer
3512e7df4a fix(storage): handle null values in file sorting to prevent crashes 2024-09-26 01:01:27 +08:00
jxxghp
5b1d111a97 更新 __init__.py 2024-09-25 22:35:18 +08:00
jxxghp
e1b557f681 更新 __init__.py 2024-09-25 22:25:27 +08:00
jxxghp
93e053d06a fix 跨存储整理(115下载除外) 2024-09-25 20:16:31 +08:00
jxxghp
f79364bc58 fix bug 2024-09-25 19:22:42 +08:00
jxxghp
2da95fa4e6 use aligo 2024-09-25 18:44:18 +08:00
InfinityPacer
90603fa2a9 fix(install): optimized logging 2024-09-25 17:52:22 +08:00
jxxghp
41d41685fe fix docker build 2024-09-25 16:55:52 +08:00
jxxghp
91efe2e94c fix docker build 2024-09-25 13:45:13 +08:00
jxxghp
d7f9ed5198 fix convert_boolean 2024-09-25 12:57:29 +08:00
jxxghp
f0464c4be7 Merge pull request #2774 from InfinityPacer/feature/api
feat(api): add support for dynamic plugin APIs
2024-09-25 08:13:17 +08:00
jxxghp
9863c85fe2 Merge pull request #2773 from InfinityPacer/dev
fix(queue): handle queue.Empty instead of TimeoutError on timeout
2024-09-25 08:10:23 +08:00
InfinityPacer
222991d07f feat(api): add support for dynamic plugin APIs 2024-09-25 02:20:23 +08:00
InfinityPacer
cf4c6b2d40 refactor(app): restructure project to avoid circular imports 2024-09-25 02:20:12 +08:00
InfinityPacer
6d55db466c fix(queue): handle queue.Empty instead of TimeoutError on timeout 2024-09-25 00:46:55 +08:00
jxxghp
88394005e5 fix log 2024-09-24 13:11:21 +08:00
jxxghp
959dc0f14b add filter log 2024-09-24 13:08:18 +08:00
jxxghp
c07d02e572 fix monitor 2024-09-24 13:02:10 +08:00
jxxghp
8612127161 fix 刮削 2024-09-24 12:16:49 +08:00
jxxghp
4bf7e05a3d fix download api add save_path 2024-09-23 17:52:06 +08:00
jxxghp
9cfc27392d fix download api 2024-09-23 17:50:24 +08:00
jxxghp
1a3d88f306 fix bug 2024-09-23 08:02:30 +08:00
jxxghp
d7c277a277 Merge pull request #2764 from InfinityPacer/feature/event 2024-09-23 07:04:29 +08:00
jxxghp
8e8a10f04e Merge pull request #2763 from Cabbagec/dev 2024-09-22 07:13:24 +08:00
InfinityPacer
5fc5838abd fix(event): replace condition-based wait with exponential backoff 2024-09-22 02:38:28 +08:00
InfinityPacer
748836df23 fix(event): restore missing method removed in be63e9ed 2024-09-22 01:36:26 +08:00
Cabbagec
f0100e6dbc fix: Path.rglob/glob does not follow symlinks 2024-09-22 01:29:06 +08:00
jxxghp
17aa6c674f fix event 2024-09-21 22:14:44 +08:00
jxxghp
796dc6d800 fix aliyun download 2024-09-21 22:06:40 +08:00
jxxghp
7444b3e84b fix storage api 2024-09-21 20:18:40 +08:00
jxxghp
fada22e892 fix webpush 2024-09-21 17:59:39 +08:00
jxxghp
c51826ba4c fix 文件整理 2024-09-21 17:11:12 +08:00
jxxghp
d7e56eeb36 fix 文件整理 2024-09-21 17:03:53 +08:00
jxxghp
f4b4e6e0dc Merge pull request #2760 from DDS-Derek/dev 2024-09-21 13:12:37 +08:00
DDSRem
a555c9b654 feat(playwright): add proxy support for chromium installation 2024-09-21 13:11:35 +08:00
jxxghp
997a9487a1 Merge pull request #2758 from InfinityPacer/feature/event 2024-09-20 22:07:29 +08:00
InfinityPacer
dea8fc5486 feat(event): optimized event execution flow 2024-09-20 21:45:52 +08:00
InfinityPacer
857383c8d0 feat(event): improve event consumer logic for handling of events 2024-09-20 20:37:29 +08:00
jxxghp
6a9fccaacb Merge pull request #2755 from qcgzxw/mediaserver 2024-09-20 19:04:54 +08:00
InfinityPacer
688693b31f feat(event): use dict for subscribers and replace handler if exists 2024-09-20 18:42:29 +08:00
Owen
7c5b4b6202 feat: MediaServerItem新增用户播放状态、mediaserver.items()增加分页参数 2024-09-20 17:57:43 +08:00
InfinityPacer
ef0768ec44 feat(event): simplify register decorator 2024-09-20 16:32:36 +08:00
InfinityPacer
be63e9ed15 feat(event): optimize handler 2024-09-20 16:26:45 +08:00
jxxghp
6431524e61 更新 local.py 2024-09-20 14:01:38 +08:00
InfinityPacer
3bee5a8a86 feat(event): separate implementation of broadcast and chain 2024-09-20 13:52:09 +08:00
jxxghp
e2bf0cd457 fix bug 2024-09-20 13:11:32 +08:00
jxxghp
8ac3fd46d2 fix file upload 2024-09-20 13:09:25 +08:00
jxxghp
117bd80528 fix scraping 2024-09-20 12:51:32 +08:00
jxxghp
91fc41261f Merge pull request #2751 from qcgzxw/bug
fix bug
2024-09-20 12:20:42 +08:00
jxxghp
ee5976a03e fix transfer 2024-09-20 12:17:50 +08:00
Owen
8a75159662 fix emby 2024-09-20 12:14:31 +08:00
Owen
63b0f5b70f fix flex 2024-09-20 12:14:01 +08:00
jxxghp
623580a7ae fix transfer 2024-09-20 08:15:23 +08:00
InfinityPacer
85cb9f7cd7 feat(event): add visualization and enhance handler 2024-09-20 01:34:01 +08:00
InfinityPacer
e786120e98 feat(event): update constant and support Condition for thread 2024-09-20 00:25:38 +08:00
InfinityPacer
49b6052ab0 refactor(event): optimize broadcast and chain event 2024-09-19 23:55:24 +08:00
jxxghp
2486b9274c fix webhook_parser 2024-09-19 21:09:07 +08:00
jxxghp
4016295696 fix transfer 2024-09-19 20:34:26 +08:00
jxxghp
f3b2bbfb6f fix rule group filter 2024-09-19 13:36:07 +08:00
jxxghp
786b317cea fix download && message 2024-09-19 08:30:58 +08:00
jxxghp
152546d89a Merge pull request #2744 from Aqr-K/dev-alipan 2024-09-19 07:35:33 +08:00
Aqr-K
bf21eda1bb 更新 alipan.py 2024-09-19 07:31:40 +08:00
jxxghp
6e8d1219f8 fix 115 2024-09-18 13:38:05 +08:00
jxxghp
69c3f9eb5d fix bug 2024-09-18 08:28:54 +08:00
jxxghp
bb086d7c83 Merge pull request #2735 from InfinityPacer/feature/plugin 2024-09-18 06:44:31 +08:00
InfinityPacer
28f7a409f9 fix(plugin): improve logging 2024-09-17 18:31:27 +08:00
InfinityPacer
3141d02e44 Merge branch 'dev' of https://github.com/jxxghp/MoviePilot into feature/plugin 2024-09-17 17:32:51 +08:00
InfinityPacer
5136698617 feat(plugin): improve online plugin retrieval 2024-09-17 17:26:06 +08:00
InfinityPacer
8cc72f402b fix(config): make VERSION_FLAG a read-only property 2024-09-17 16:56:08 +08:00
InfinityPacer
4d2e77fc51 feat(plugin): improve plugin version upgrade and compatibility 2024-09-17 16:05:16 +08:00
jxxghp
d5aa52ed91 Merge pull request #2729 from Aqr-K/dev 2024-09-16 22:17:57 +08:00
Aqr-K
148e4a95ee fix: cloud disk bug
- 解决前端调用时,没有认证参数或者失效时,后端返回的None,会引发pydantic的报错,从而导致的前端无法获取结果,卡在刷新页面
2024-09-16 22:16:54 +08:00
jxxghp
3c43055f10 Merge pull request #2727 from qcgzxw/mediaserver 2024-09-16 21:49:36 +08:00
jxxghp
1920dc0a82 Merge pull request #2725 from InfinityPacer/feature/auth 2024-09-16 21:46:02 +08:00
owen
8306aa92db refactor: 修改emby、jellyfin API url请求传参方式 2024-09-16 20:23:24 +08:00
InfinityPacer
947a19eb95 fix(auth): set empty avatar to avoid missing default avatar 2024-09-16 15:42:37 +08:00
InfinityPacer
36142b97bf fix(auth): handle scenario where the user is null 2024-09-16 15:41:13 +08:00
jxxghp
4efc80e35a Merge pull request #2716 from InfinityPacer/feature/plugin 2024-09-14 18:16:02 +08:00
jxxghp
31aadabe86 Merge pull request #2715 from InfinityPacer/feature/push 2024-09-14 18:00:23 +08:00
InfinityPacer
593bcbf455 fix(auth): set AUXILIARY_AUTH_ENABLE default to false 2024-09-14 17:56:50 +08:00
InfinityPacer
220fef5c9b feat(plugin): optimize logging with detailed debug info 2024-09-14 17:55:18 +08:00
InfinityPacer
343f51ce79 feat(plugin): enhance fallback strategies 2024-09-14 17:23:44 +08:00
jxxghp
e86bf61579 fix storage api 2024-09-14 14:43:14 +08:00
jxxghp
8bb25afcdc fix transfer bug 2024-09-14 13:19:51 +08:00
jxxghp
57bad6353c fix bug 2024-09-14 13:13:11 +08:00
jxxghp
f6c84a744c feat:国语配音适配大陆剧 2024-09-14 12:33:05 +08:00
jxxghp
5229a0173a fix 2024-09-14 12:20:22 +08:00
jxxghp
5a6733fa32 fix bug 2024-09-14 11:44:38 +08:00
InfinityPacer
e0e4b31933 feat(plugin): implement fallback mechanism for install plugin 2024-09-14 11:26:43 +08:00
jxxghp
a29cf83aba fix bug 2024-09-14 08:21:13 +08:00
jxxghp
ede37b80fc fix bug 2024-09-14 07:06:39 +08:00
InfinityPacer
2f2ecc8c43 fix(push): correct client type 2024-09-13 18:54:48 +08:00
jxxghp
5ec7357c56 fix bug 2024-09-13 17:23:41 +08:00
jxxghp
a547ea954d Merge pull request #2705 from InfinityPacer/feature/api-token 2024-09-13 09:59:17 +08:00
InfinityPacer
777c7c78d0 fix(plugin): use verify_apikey for backward compatibility 2024-09-13 09:49:22 +08:00
jxxghp
c1bf32318b Merge pull request #2704 from InfinityPacer/fix/sync 2024-09-13 08:33:59 +08:00
jxxghp
6a65b5b234 Merge pull request #2703 from InfinityPacer/feature/auth 2024-09-13 08:32:54 +08:00
jxxghp
d0a868123d Merge pull request #2701 from Akimio521/dev 2024-09-13 08:32:28 +08:00
jxxghp
b9f1ebff89 Merge pull request #2700 from InfinityPacer/feature/api-token 2024-09-13 08:32:10 +08:00
InfinityPacer
0ef8efd5a5 fix(sync): skip when no libraries are retrieved 2024-09-13 01:18:16 +08:00
InfinityPacer
9129de1720 fix(sync): skip disabled mediaservers and empty libraries 2024-09-13 00:58:03 +08:00
InfinityPacer
1ebec13afb feat(auth): add AUXILIARY_AUTH_ENABLE for user authentication 2024-09-12 21:12:10 +08:00
jxxghp
73407825f5 fix site userdata 2024-09-12 15:44:31 +08:00
jxxghp
53195457c7 fix module test 2024-09-12 15:13:58 +08:00
jxxghp
9a62feb9a9 feat:规则组适用媒体类别 2024-09-12 12:42:41 +08:00
jxxghp
26abccabf3 feat:规则组适用媒体类别 2024-09-12 12:36:58 +08:00
Akimio521
596b2e11b8 feat:查询种子时匹配香港、台湾译名 2024-09-12 12:33:17 +08:00
jxxghp
e2436ba94f fix api 2024-09-12 08:24:55 +08:00
jxxghp
f9895b2edd fix api 2024-09-12 08:16:02 +08:00
InfinityPacer
3446aec6a2 feat(plugin): add API_TOKEN validation for plugin API registration 2024-09-12 02:36:34 +08:00
InfinityPacer
23b9774c5d feat(auth): add API_TOKEN validation and auto-generation 2024-09-12 00:17:26 +08:00
InfinityPacer
540f5eb77f refactor: unify env path 2024-09-12 00:05:07 +08:00
InfinityPacer
8b336cf3eb fix(log): add support for CONFIG_DIR through environment variables 2024-09-11 23:53:15 +08:00
jxxghp
186476ad31 fix 通知发送范围初始化 2024-09-11 08:10:38 +08:00
jxxghp
171f15e410 Merge pull request #2698 from InfinityPacer/feature/log-refactor 2024-09-11 06:48:13 +08:00
jxxghp
05bbfde943 Merge pull request #2697 from InfinityPacer/dev 2024-09-11 06:46:52 +08:00
InfinityPacer
150e2366da refactor(log): add support for configurable log settings in .env 2024-09-10 21:43:09 +08:00
jxxghp
9c47da8c98 fix dashboard api 2024-09-10 21:10:45 +08:00
InfinityPacer
0f5290be18 chore: Delete 插件版本兼容与升级方案.md 2024-09-10 12:09:21 +08:00
jxxghp
104348ba0e fix dockerfile 2024-09-10 11:34:52 +08:00
jxxghp
1a1318b5e4 fix 2024-09-10 11:16:12 +08:00
jxxghp
8a6ad03880 feat:支持V2专用插件 2024-09-10 08:26:30 +08:00
jxxghp
d0ac5646f5 fix transfer_completed 2024-09-10 07:58:22 +08:00
jxxghp
89f2bf5f30 更新 message.py 2024-09-09 22:54:47 +08:00
jxxghp
c3ef3dd7d1 fix 全局变量定义 2024-09-09 22:17:49 +08:00
InfinityPacer
aa6fa8d336 chore: Add 插件版本兼容与升级方案.md 2024-09-09 21:39:27 +08:00
jxxghp
f18b9793b4 Merge pull request #2696 from Aqr-K/dev 2024-09-09 21:35:34 +08:00
Aqr-K
15946f8d0a Update config.py 2024-09-09 21:13:15 +08:00
InfinityPacer
c2824a1bc8 chore: Update development-setup.md 2024-09-09 19:02:13 +08:00
jxxghp
2d8dd6cc17 Merge pull request #2694 from InfinityPacer/dev 2024-09-09 18:46:45 +08:00
InfinityPacer
adf78a9e3e fix(requirements): install pywin32 only on Windows 2024-09-09 18:44:14 +08:00
jxxghp
40ee902457 remove pywin32 2024-09-09 16:55:45 +08:00
jxxghp
48ac6e727b fix build 2024-09-09 16:43:05 +08:00
jxxghp
d8a2b0497e feat:v2新增版本标识(用于插件进行兼容性判断),插件市场只显示兼容对应版本标识的插件 2024-09-09 10:36:42 +08:00
jxxghp
1d31785def fix reload api 2024-09-09 09:51:48 +08:00
jxxghp
b1d2125e22 fix https://github.com/jxxghp/MoviePilot/pull/2610 整合同步消息到dev分支 2024-09-09 08:55:10 +08:00
jxxghp
81ce44ee4d Merge remote-tracking branch 'origin/dev' into dev 2024-09-09 08:33:16 +08:00
jxxghp
d806931296 downloading api 支持多下载器 2024-09-09 08:33:07 +08:00
jxxghp
28a8bb4baa Merge pull request #2690 from DDS-Derek/dev 2024-09-08 17:54:11 +08:00
jxxghp
773399347d fix user api 2024-09-08 14:53:52 +08:00
DDSRem
a5cecdd631 feat(docker): retry if download fails
fix https://github.com/jxxghp/MoviePilot/issues/2688
2024-09-08 14:42:01 +08:00
jxxghp
34ae663d5a add subscribe/files api 2024-09-08 13:02:42 +08:00
jxxghp
01505ceaa7 add site userdata refresh api 2024-09-08 08:44:54 +08:00
jxxghp
f0b1cdbe52 Merge pull request #2689 from Akimio521/dev 2024-09-07 08:11:00 +08:00
Akimio521
a13d32c17f fix:将history.episodes转换成episode_detail 2024-09-06 19:05:55 +08:00
Akimio521
c438cd5713 feat:手动转移文件增加从历史记录获取相关信息 2024-09-06 19:05:30 +08:00
jxxghp
31c9fa932a Merge pull request #2687 from InfinityPacer/dev 2024-09-06 12:01:42 +08:00
InfinityPacer
4493d4c62f refactor(PluginMonitor): use rate_limit_window for rate limit 2024-09-05 23:47:57 +08:00
InfinityPacer
862f3cb623 feat(limit): change default raise_on_limit to False 2024-09-05 23:46:08 +08:00
InfinityPacer
ffbcc988b3 feat(limit): refactor RateLimiter to limit package 2024-09-05 23:29:44 +08:00
jxxghp
ab294ac35e Merge pull request #2684 from InfinityPacer/dev 2024-09-05 06:54:24 +08:00
InfinityPacer
d9f6db18d4 feat(Douban): add global rate-limiter 2024-09-05 00:49:29 +08:00
InfinityPacer
7a7225ba45 fix(rate-limiter): optimize log 2024-09-05 00:46:36 +08:00
InfinityPacer
b42a69f361 feat(rate-limiter): support dynamic raise_exception 2024-09-05 00:41:56 +08:00
InfinityPacer
eea6bd1ea3 feat(rate-limiter): add source context for enhanced logging 2024-09-04 20:12:29 +08:00
InfinityPacer
73fca81641 feat(rate-limiter): add rate limiter 2024-09-04 20:10:41 +08:00
jxxghp
f4b010f106 Merge pull request #2674 from InfinityPacer/dev 2024-09-01 06:56:48 +08:00
InfinityPacer
93801e857e fix(lxml): Adjust HTML element checks to prevent FutureWarning 2024-08-31 02:14:52 +08:00
jxxghp
8f73e45a30 Merge pull request #2668 from InfinityPacer/dev 2024-08-30 17:55:16 +08:00
InfinityPacer
9ab852c1ad feat(sqlite): adjust default settings 2024-08-30 04:46:08 +08:00
InfinityPacer
88a0de7fa6 feat(sqlite): support customizable connection settings 2024-08-30 02:42:50 +08:00
jxxghp
78657cb948 fix api 2024-08-29 16:15:06 +08:00
jxxghp
264cd2658b fix cache path 2024-08-29 15:39:12 +08:00
jxxghp
f4dfaa0519 fix douban api 2024-08-29 08:36:11 +08:00
jxxghp
707921e15d feat:global image cache api 2024-08-28 18:11:06 +08:00
jxxghp
eea8b9a8a6 feat:global image cache api 2024-08-28 17:53:06 +08:00
jxxghp
bd7fc2d4ff Merge pull request #2656 from InfinityPacer/dev 2024-08-26 10:08:31 +08:00
InfinityPacer
bc1da0a7c7 refactor(CookieCloud): Consolidate crypto and hash operations into HashUtils and CryptoJsUtils 2024-08-23 18:52:00 +08:00
jxxghp
3ae34216d0 Merge pull request #2653 from InfinityPacer/dev 2024-08-23 07:23:46 +08:00
InfinityPacer
c15d326636 Merge branch 'dev' of https://github.com/InfinityPacer/MoviePilot into dev 2024-08-22 21:52:52 +08:00
InfinityPacer
f93bcd852c chore(security): Ignore resolved vulnerabilities after upgrading python-multipart 2024-08-22 21:52:03 +08:00
InfinityPacer
0bf30bb75f fix(downgrade): Rollback FastAPI and Starlette due to compatibility issues with Pydantic V2 affecting API parameter handling. 2024-08-22 21:51:46 +08:00
InfinityPacer
93b899b7e9 refactor(UrlUtils): Migrate URL-related methods from RequestUtils 2024-08-21 22:12:56 +08:00
InfinityPacer
fef270f73b refactor(RSAUtils): Add key_size parameter to generate_rsa_key_pair method and update comments 2024-08-21 01:21:55 +08:00
jxxghp
c7dcbf697e Merge pull request #2649 from InfinityPacer/dev 2024-08-20 21:13:16 +08:00
InfinityPacer
d5241a2eb8 chore: Integrate pip-tools and safety, upgrade vulnerable dependencies 2024-08-20 18:52:07 +08:00
jxxghp
cf3d6bca91 115 linux client 2024-08-20 09:02:25 +08:00
jxxghp
1f87bc643a sync main 2024-08-19 13:06:39 +08:00
jxxghp
566928926b Merge pull request #2646 from InfinityPacer/dev 2024-08-18 23:13:15 +08:00
InfinityPacer
0a74437253 feat(TimerUtils): add random_even_scheduler for evenly distributed schedule creation 2024-08-18 22:24:24 +08:00
jxxghp
65ff01b713 fix parse_json_fields 2024-08-16 17:53:12 +08:00
jxxghp
5d3809b8f5 fix rclone usage 2024-08-16 17:14:20 +08:00
jxxghp
6e334ef333 fix apis 2024-08-16 17:03:51 +08:00
jxxghp
c030f52418 fix apis 2024-08-16 13:41:19 +08:00
jxxghp
af88618fbd fix storage api 2024-08-16 11:59:45 +08:00
jxxghp
8485d4ec30 fix storage api 2024-08-16 11:30:31 +08:00
jxxghp
61e4e63a6a fix storage api 2024-08-15 16:15:26 +08:00
jxxghp
47481d2482 fix storage api 2024-08-15 15:27:47 +08:00
jxxghp
65c8f35f6d fix types 2024-08-15 11:45:23 +08:00
jxxghp
6358e49a96 fix statistic info api 2024-08-12 11:02:05 +08:00
jxxghp
fc1076586a fix downloader info api 2024-08-12 08:17:39 +08:00
jxxghp
5bfd08cce8 Merge pull request #2630 from DDS-Derek/dev 2024-08-05 19:46:33 +08:00
DDSRem
63b0d0a86b feat: optimize proxy log output 2024-08-05 19:41:58 +08:00
jxxghp
a41be81f35 Merge pull request #2629 from Aqr-K/dev 2024-08-05 18:23:05 +08:00
jxxghp
cec671e8a1 fix rule schema 2024-08-05 18:14:24 +08:00
Aqr-K
0097a6f33b Merge branch 'jxxghp:dev' into dev 2024-08-05 17:57:41 +08:00
jxxghp
0055f4c7af fix rule schema 2024-08-05 17:48:15 +08:00
Aqr-K
e19abeb149 Update update 2024-08-05 17:45:09 +08:00
jxxghp
236f59d56f Merge pull request #2628 from Aqr-K/dev 2024-08-05 17:42:02 +08:00
Aqr-K
8fba3cf170 Update update 2024-08-05 17:39:52 +08:00
jxxghp
0cb120a9e5 Merge pull request #2626 from DDS-Derek/dev 2024-08-05 16:06:36 +08:00
DDSRem
67f991d217 fix: root-user-action parameter setting error 2024-08-05 15:59:59 +08:00
DDSRem
466b42bea7 feat: automatic acceleration selection 2024-08-05 15:52:58 +08:00
jxxghp
f7d583856f Merge pull request #2624 from Aqr-K/dev 2024-08-05 14:39:40 +08:00
Aqr-K
d5d32e2335 更新 update 2024-08-04 00:09:00 +08:00
Aqr-K
e8ff878aac 删除PROXY_SUPPLEMENT变量,增加只读属性‘PIP_OPTIONS’
1、删除`proxychains4`模块支持,`pip`代理已支持全局模式下的`socks4`、`socks4a`、`socks5`、`socks5h`、`http`、`https`协议;
2、删除`PROXY_SUPPLEMENT`变量,取消手动控制功能;
3、增加自动判断,将`pip`与`update`的代理判断,从手动改为自动,优先级:镜像站 > 全局 > 不代理;
4、将`pip`的附加代理参数,作为只读属性`PIP_OPTIONS`写入到`config`中,其他对象可通过`settings.PIP_OPTIONS`实现快速调用。
2024-08-03 23:02:10 +08:00
Aqr-K
fea7b7d02d 更新 urlparse.py 2024-08-03 18:36:16 +08:00
Aqr-K
c69d317054 增加PROXY_SUPPLEMENT变量
1、增加proxychains4模块,用于解决pip在socks5代理时,pip无法使用全局代理的问题
2、增加`PROXY_SUPPLEMENT`变量,可以手动控制,实现使用镜像站进行更新时,但缺少pip镜像站或者GitHub镜像站时,可以使用全局代理补全缺失的代理
2024-08-03 18:29:06 +08:00
jxxghp
40663b6ce7 fix local 2024-07-26 22:04:50 +08:00
jxxghp
4f4c7a5748 Merge pull request #2604 from Aqr-K/dev
增加``PIP_PROXY``变量,支持用镜像站下载与更新依赖
2024-07-25 17:51:40 +08:00
Aqr-K
7adae64955 修复GITHUB_PROXY错误代码,简化写法 2024-07-25 17:43:09 +08:00
Aqr-K
4afd043f85 清除多余参数 2024-07-24 23:17:13 +08:00
Aqr-K
dc5250a74e 调整重启时,使用代理更新的优先级,优先使用镜像站 2024-07-24 23:10:39 +08:00
Aqr-K
0bd91ee484 增加PYPI_PROXY变量,支持用镜像站下载与更新依赖 2024-07-24 23:02:46 +08:00
jxxghp
6bbdc574b6 fix db init 2024-07-24 16:58:50 +08:00
jxxghp
c275d4db22 fix db init 2024-07-24 16:49:27 +08:00
jxxghp
843d93f0a8 Merge pull request #2599 from DDS-Derek/dev 2024-07-23 16:16:25 +08:00
DDSRem
5d26e70cae fix: pip warning in root mode 2024-07-23 14:43:20 +08:00
DDSRem
766640a0a0 feat: better logging output 2024-07-23 14:39:15 +08:00
jxxghp
7459938e92 Merge pull request #2597 from DDS-Derek/dev 2024-07-22 15:58:59 +08:00
DDSRem
bc476cb0c9 feat: restart update failed and auto restore backup 2024-07-22 15:33:38 +08:00
jxxghp
dc92a554f6 init storage 2024-07-20 09:16:26 +08:00
jxxghp
d8c8d43ed9 fix 2024-07-20 08:52:36 +08:00
jxxghp
0f8c2d3fc9 fix db init 2024-07-20 08:47:26 +08:00
jxxghp
b949969b10 Merge pull request #2585 from DDS-Derek/dev 2024-07-19 19:49:00 +08:00
DDSRem
66e13c5a31 fix: display variable is not effective
fix 547812162d
2024-07-19 14:53:21 +08:00
jxxghp
294ff93e2b Merge pull request #2584 from DDS-Derek/dev 2024-07-19 12:47:01 +08:00
DDSRem
547812162d fix: display id conflict
fix https://github.com/jxxghp/MoviePilot/issues/2247
2024-07-19 12:44:16 +08:00
jxxghp
0028e2f830 fix 2024-07-14 19:32:18 +08:00
jxxghp
97fdfe789e fix 2024-07-14 18:50:31 +08:00
jxxghp
b0874f56c9 fix 2024-07-09 20:04:06 +08:00
jxxghp
3d2b645bfc fix user 2024-07-09 08:25:22 +08:00
jxxghp
47b276795f Merge pull request #2536 from DDS-Derek/dev 2024-07-08 12:24:29 +08:00
DDSRem
9331f82b81 feat: refactor docker http proxy 2024-07-08 12:20:54 +08:00
jxxghp
bb4355fbe0 fix permissions 2024-07-07 08:09:26 +08:00
jxxghp
a567a8644b add ModuleBases 2024-07-07 07:40:53 +08:00
jxxghp
9b7896ab96 fix 2024-07-06 16:48:43 +08:00
jxxghp
1a0c4acf1c fix bug 2024-07-06 08:30:09 +08:00
jxxghp
059e4f08a3 fix permissions 2024-07-05 08:10:21 +08:00
jxxghp
30ae583704 fix torrent filter 2024-07-04 22:16:20 +08:00
jxxghp
28d420af51 fix bug 2024-07-04 22:04:10 +08:00
jxxghp
c87b982ebf fix bug 2024-07-04 21:58:10 +08:00
jxxghp
290cafa03d add user requests 2024-07-04 21:52:49 +08:00
jxxghp
604c418bd4 fix filter rules 2024-07-04 21:25:50 +08:00
jxxghp
28345817d9 add siteuserdata 2024-07-04 19:42:09 +08:00
jxxghp
965e40e630 fix message 2024-07-04 18:45:22 +08:00
jxxghp
5f01dd5625 fix user 2024-07-04 07:13:49 +08:00
jxxghp
dde2d22d93 fix 2024-07-03 17:50:02 +08:00
jxxghp
9f34be049d add monitor 2024-07-03 17:46:35 +08:00
jxxghp
db26f2e108 add storage snapshot 2024-07-03 11:51:26 +08:00
jxxghp
35eda7d116 fix filemanager 2024-07-03 08:49:59 +08:00
jxxghp
b6800c7fda fix 2024-07-03 07:10:46 +08:00
jxxghp
03068778bc fix transfer 2024-07-02 20:48:26 +08:00
jxxghp
0da2bd6468 fix rclone 2024-07-02 20:32:32 +08:00
jxxghp
b37e50480a fix storage 2024-07-02 18:31:17 +08:00
jxxghp
8530d54fcc fix filemanager 2024-07-02 18:16:52 +08:00
jxxghp
1822d01d17 fix directories 2024-07-02 17:47:29 +08:00
jxxghp
f23be671c0 fix 2024-07-02 13:54:29 +08:00
jxxghp
15a7297099 fix messages 2024-07-02 13:50:41 +08:00
jxxghp
9484093d22 fix downloader 2024-07-02 11:11:25 +08:00
jxxghp
c8fe6e4284 fix downloaders 2024-07-02 11:00:55 +08:00
jxxghp
dfc5872087 fix mediaservers 2024-07-02 10:03:56 +08:00
jxxghp
9a07d88d41 fix downloaders && mediaservers && notifications 2024-07-02 07:16:33 +08:00
jxxghp
b4e1e911fc fix 2024-07-01 21:38:44 +08:00
jxxghp
60827fd5b1 fix local get_folder 2024-07-01 21:26:39 +08:00
jxxghp
cf409eb28f fix transfer 2024-07-01 21:24:02 +08:00
jxxghp
f16eb271da fix transfer chain 2024-07-01 18:30:15 +08:00
jxxghp
778b562cab fix scraper 2024-07-01 15:25:35 +08:00
jxxghp
964e212831 fix storage 2024-07-01 11:57:32 +08:00
jxxghp
302514a469 fix 2024-06-30 19:48:23 +08:00
jxxghp
3d79b5bb2a fix storage api 2024-06-30 19:44:04 +08:00
jxxghp
3dd5c91ce7 fix storage api 2024-06-30 19:43:07 +08:00
jxxghp
02ad98c024 fix storage api 2024-06-30 19:41:32 +08:00
jxxghp
a7b906ada6 fix storage 2024-06-30 18:44:23 +08:00
jxxghp
a62ca9a226 fix transfer 2024-06-30 13:25:29 +08:00
jxxghp
02030a8e2d add site_userdata 2024-06-30 11:00:25 +08:00
jxxghp
63ca5ee313 add storage 2024-06-30 08:59:12 +08:00
jxxghp
77632880d1 add site parsers 2024-06-30 08:09:23 +08:00
jxxghp
20fa8feab0 Merge pull request #2431 from jxxghp/main
fix
2024-06-26 16:09:51 +08:00
jxxghp
be55c7bdd9 Merge pull request #2430 from InfinityPacer/main 2024-06-26 15:55:24 +08:00
InfinityPacer
a4288aa871 fix #2428 2024-06-26 15:51:31 +08:00
jxxghp
c0f15ac7ff Merge remote-tracking branch 'origin/main' 2024-06-26 15:18:05 +08:00
jxxghp
4047d433f5 fix 2024-06-26 15:17:42 +08:00
jxxghp
0699f0003c Merge pull request #2429 from jxxghp/main
merge
2024-06-26 14:49:38 +08:00
jxxghp
91d6769d0f Merge branch 'dev' into main 2024-06-26 14:49:27 +08:00
jxxghp
ad378956bf support haidan index 2024-06-26 09:08:18 +08:00
jxxghp
9dcfb6dc1e v1.9.8-1
- 修复剧集自动刮削报错问题
2024-06-25 16:32:45 +08:00
jxxghp
2d0b21d3f2 fix #2418
fix #2421
fix #2412
2024-06-25 16:29:57 +08:00
jxxghp
3287c85300 Merge pull request #2415 from thsrite/main 2024-06-25 10:06:25 +08:00
thsrite
fd2682bc6a add 删除下载历史、删除下载文件历史 2024-06-25 10:03:29 +08:00
jxxghp
7dd1e75ad7 Merge remote-tracking branch 'origin/main' 2024-06-24 17:13:58 +08:00
jxxghp
93b8f24ec7 v1.9.8
- 修复阿里云盘无法整理备份盘的问题
- 修复手动整理时fanart图片文件不全的问题
- 修复了通过远程消息下载时不会自动分类的问题
- 修复登录失败时的提示信息
- 修复有的场景下订阅重复下载问题
2024-06-24 17:13:50 +08:00
jxxghp
1c240f9d76 Update README.md 2024-06-24 17:06:56 +08:00
jxxghp
9a2ef5fe48 Update README.md 2024-06-24 17:06:08 +08:00
jxxghp
7bd55caed7 reinit 2024-06-24 12:53:45 +08:00
jxxghp
ae36f5100a Merge pull request #2410 from jxxghp/main
fix bugs
2024-06-24 12:47:39 +08:00
jxxghp
b2efac0495 Merge pull request #2409 from jxxghp/revert-2407-dev
Revert "fix bugs"
2024-06-24 12:42:09 +08:00
jxxghp
1dced579ea Revert "fix bugs" 2024-06-24 12:41:59 +08:00
jxxghp
0deea17ef9 Merge pull request #2407 from jxxghp/dev
fix bugs
2024-06-24 12:36:37 +08:00
jxxghp
3d0c06013d fix bug 2024-06-24 09:37:11 +08:00
jxxghp
2536119f60 feat:网盘整理联动刮削 2024-06-24 09:12:26 +08:00
jxxghp
aeede861e3 fix bug 2024-06-24 08:49:20 +08:00
jxxghp
1edbfb0d2d fix bug 2024-06-24 08:08:39 +08:00
jxxghp
265724bbe9 Merge pull request #2402 from thsrite/main 2024-06-23 19:47:24 +08:00
jxxghp
2b0b190cf8 fix bug 2024-06-23 19:46:36 +08:00
thsrite
08a2b348d8 add get_by_dest 2024-06-23 19:45:08 +08:00
jxxghp
e896068bc5 fix #2400 2024-06-23 18:48:13 +08:00
jxxghp
85e5338121 fix #2340
fix 手动刮削图片不完整
2024-06-23 18:40:44 +08:00
jxxghp
5c3cd8cabc init repo 2024-06-23 09:33:27 +08:00
jxxghp
5a837a4161 v1.9.8-beta
- 文件管理支持多选,支持网盘批量整理和刮削,阿里云盘支持备份盘
2024-06-23 09:07:05 +08:00
jxxghp
1e1f80b6d9 add remote transfer 2024-06-23 09:04:08 +08:00
jxxghp
e06e00204b fix #2341 2024-06-22 21:31:10 +08:00
jxxghp
b98c0f205d fix scrape 2024-06-22 20:58:24 +08:00
jxxghp
0c266726ea fix scrap 2024-06-22 19:59:24 +08:00
jxxghp
b43e591e4c fix scrap 2024-06-22 08:32:25 +08:00
jxxghp
3d6e1335f8 更新 scraper.py 2024-06-22 06:45:17 +08:00
jxxghp
361e8dd65d fix api 2024-06-21 23:25:08 +08:00
jxxghp
de865f3cf1 fix api 2024-06-21 23:05:00 +08:00
jxxghp
37985eba25 fix api 2024-06-21 21:28:48 +08:00
jxxghp
e0a251b339 fix scrape api 2024-06-21 19:19:10 +08:00
jxxghp
f9f4d97a51 更新 media.py 2024-06-21 12:23:18 +08:00
jxxghp
6adc0e27d5 fix api 2024-06-21 12:17:30 +08:00
jxxghp
5deb0089bb fix api 2024-06-21 11:49:07 +08:00
jxxghp
bfbeae7fa7 fix api 2024-06-21 11:13:01 +08:00
jxxghp
8a98c65026 fix 2024-06-21 08:27:37 +08:00
jxxghp
0133c6e60c add upload api 2024-06-21 08:08:23 +08:00
jxxghp
ae0e171dd2 Merge pull request #2375 from InfinityPacer/main 2024-06-20 17:54:24 +08:00
InfinityPacer
9f0ed49d43 fix plugin auth_level 2024-06-20 17:44:55 +08:00
jxxghp
8df2955a67 add alipan/115 move api 2024-06-20 17:21:02 +08:00
jxxghp
ef0cd7d5c5 fix meta_nfo 2024-06-20 17:04:47 +08:00
jxxghp
463fd3761a add meta_nfo module function 2024-06-20 16:53:50 +08:00
jxxghp
4af4ad0243 fix bug 2024-06-20 15:52:52 +08:00
jxxghp
24aa64232f fix windows exe front path 2024-06-20 13:21:49 +08:00
jxxghp
9937f6792e feat:阿里云盘支持备份盘 2024-06-20 13:15:59 +08:00
jxxghp
185b72dc8d fix:优化文件管理api 2024-06-20 11:38:57 +08:00
jxxghp
0fb12c77eb fix bug 2024-06-19 18:04:00 +08:00
jxxghp
631df4c9f8 v1.9.7
- 文件管理支持阿里云盘、115网盘,新增批量认别重命名功能,以快速整理本地或网盘文件。
- 优化了资源搜索卡片视图结果太多时卡顿的问题
- 适配了M-Team Api域名变化
2024-06-19 17:20:33 +08:00
jxxghp
0da08394ae Merge pull request #2365 from InfinityPacer/main 2024-06-19 16:55:27 +08:00
InfinityPacer
6392ee627f fix 请求失败时记录debug日志 2024-06-19 16:36:31 +08:00
InfinityPacer
da6ba3fa8b feat:Plex 添加公共请求方法 2024-06-19 15:53:55 +08:00
InfinityPacer
cb0bb8a38e refactor request host 2024-06-19 15:51:57 +08:00
InfinityPacer
e1cdc51904 Merge branch 'main' of https://github.com/InfinityPacer/MoviePilot 2024-06-19 15:47:16 +08:00
jxxghp
79c57d8e4f 批量重命名进度更新 2024-06-19 15:22:05 +08:00
jxxghp
681f1eaeb5 fix m-team api path 2024-06-19 14:16:20 +08:00
InfinityPacer
de2323d67a refactor RequestUtils 2024-06-19 13:45:02 +08:00
jxxghp
9cf240b8e8 fix UserDeviceOffline tip 2024-06-19 13:42:19 +08:00
jxxghp
b93c97938c fix 2024-06-19 13:14:02 +08:00
jxxghp
41d347bcef fix 115 pan 2024-06-19 13:04:35 +08:00
jxxghp
060e2f225c fix 115 pan 2024-06-19 13:02:04 +08:00
jxxghp
7103b0334a add 115 apis 2024-06-19 07:11:26 +08:00
jxxghp
354d5977e0 fix api path 2024-06-18 19:19:32 +08:00
jxxghp
19a56f7d24 feat:文件管理批量重命名 2024-06-18 16:45:48 +08:00
jxxghp
323ad099c3 add 识别名称API 2024-06-18 13:56:12 +08:00
jxxghp
484ecf10c3 fix api 2024-06-18 13:05:11 +08:00
jxxghp
2a333add9b fix aliyunpan api 2024-06-18 12:01:53 +08:00
jxxghp
90df09e64d add aliyunpan userinfo api 2024-06-18 07:03:05 +08:00
jxxghp
53397536ce Merge pull request #2355 from InfinityPacer/main 2024-06-17 21:09:00 +08:00
InfinityPacer
f902f43c56 fix #2348 移除硬链接校验 2024-06-17 21:02:14 +08:00
jxxghp
9948db8bce add aliyun apis 2024-06-17 20:16:38 +08:00
jxxghp
1b6a06bd7b add aliyun apis 2024-06-17 19:45:39 +08:00
jxxghp
ce1db7f62b v1.9.6
- 增加了CookieCloud同步域名黑名单设定
- 调整了登录和订阅界面样式,优化了整体UI响应速度
2024-06-16 14:09:47 +08:00
jxxghp
74dbae8514 fix api 2024-06-16 09:53:23 +08:00
jxxghp
7d4ec2ddec fix api 2024-06-16 07:22:01 +08:00
jxxghp
3654b9609f fix 2024-06-16 07:10:32 +08:00
jxxghp
83e583032a add wallpapers api 2024-06-16 07:09:04 +08:00
jxxghp
35a4d77915 fix #2346 2024-06-15 21:12:16 +08:00
jxxghp
cbfb2027a8 Merge pull request #2345 from thsrite/main 2024-06-15 19:37:58 +08:00
thsrite
ce0548632e fix cookiecloud同步只同步启用的站点 && 同步域名黑名单 2024-06-15 19:33:03 +08:00
thsrite
da1f6a0997 fix cookiecloud同步只同步启用的站点 2024-06-15 19:21:20 +08:00
jxxghp
a514ec0761 v1.9.5
- 小屏幕新增`App模式`界面切换功能,配合PWA提升手机操作使用体验(默认开启,点击右上角头像切换)
- 修复了有的反向代理环境下无法新增用户的问题
- 修复了北洋园种子发布时间和标签识别问题
- 修复部分情况下订阅会重复下载的问题
2024-06-14 17:07:42 +08:00
jxxghp
851dd85fc6 rclone移动模式下删除种子文件 2024-06-14 16:53:15 +08:00
jxxghp
0270af5b19 fix 豆瓣转TMDB搜索时丢失季的问题 2024-06-14 16:13:21 +08:00
jxxghp
f8f964106a fix pubdate string 2024-06-14 12:27:26 +08:00
jxxghp
aa0f2a571c fix datestr \n 2024-06-14 11:31:04 +08:00
jxxghp
727a14864e fix #2327
fix #2261
2024-06-14 10:32:15 +08:00
jxxghp
c7e909520c fix webpush重复推送 2024-06-14 06:52:34 +08:00
jxxghp
7f40863449 Merge pull request #2330 from falling/main 2024-06-13 21:14:48 +08:00
falling
e994a9fc92 is_english_word 方法 更新 2024-06-13 21:10:20 +08:00
jxxghp
d8fe8b28e8 fix 2024-06-13 11:31:44 +08:00
jxxghp
7f4f085d4a update README.md 2024-06-13 11:27:20 +08:00
jxxghp
2052766a71 Update README.md 2024-06-13 11:12:56 +08:00
jxxghp
887fe834bd Update README.md 2024-06-13 11:11:10 +08:00
jxxghp
0d4f87a631 Update README.md 2024-06-13 11:10:19 +08:00
jxxghp
ed96241053 Merge pull request #2322 from zhu0823/main 2024-06-12 10:20:40 +08:00
zhu0823
788104d151 fix: 类型检查 2024-06-12 10:07:16 +08:00
jxxghp
f8b3dbaef5 update README.md 2024-06-11 21:57:59 +08:00
jxxghp
b66ca92d72 Update README.md 2024-06-11 13:21:16 +08:00
jxxghp
c2a80dbedd Merge pull request #2310 from InfinityPacer/main 2024-06-10 13:52:09 +08:00
InfinityPacer
95202af139 fix dashboard Plex卡片加载速度 2024-06-10 12:43:05 +08:00
jxxghp
d77ea8f0a0 - 修复榜单、订阅、目录匹配细节问题 2024-06-10 09:55:20 +08:00
jxxghp
bbba9813a2 Merge pull request #2307 from InfinityPacer/main 2024-06-10 09:50:26 +08:00
jxxghp
220cbc3072 fix #2291 2024-06-10 09:49:31 +08:00
InfinityPacer
fcbdef5e66 fix 插件重载找不到__init__.py的场景及部分细节调整 2024-06-10 09:45:56 +08:00
jxxghp
e2e1c7642d fix 订阅重置 & TMDB电视剧榜单 2024-06-10 09:38:12 +08:00
jxxghp
33813ecf1d Merge pull request #2302 from xcehnz/main 2024-06-09 16:03:18 +08:00
xcehnz
ef656fcc67 fix 同目录优先无效 2024-06-09 15:41:48 +08:00
jxxghp
8fe7e015dd Merge pull request #2299 from thsrite/main 2024-06-09 12:54:27 +08:00
thsrite
7132fdbb26 fix plugin command args 2024-06-09 12:41:42 +08:00
jxxghp
0f57b39345 fix webpush switch 2024-06-09 11:15:35 +08:00
jxxghp
d13b5622c7 remove js/css cache 2024-06-09 08:04:53 +08:00
jxxghp
b5eaba26da 更新 __init__.py 2024-06-08 21:05:53 +08:00
jxxghp
60007cf398 Merge pull request #2295 from thsrite/main 2024-06-08 20:47:51 +08:00
thsrite
65cc169391 fix 2024-06-08 19:56:08 +08:00
thsrite
68a9fc4a13 fix 订阅新增支持填充规则 2024-06-08 19:54:06 +08:00
jxxghp
08870a67ec v1.9.4
- 优化了硬链接的处理逻辑,兼容极空间的同时跨盘不再会自动变成复制了
- 订阅增加了重置按钮,手动删除了订阅下载过的任务或媒体库文件时,可通过重置订阅重新下载
- 消息通知新增超链接跳转功能,需在设定中维护好访问域名
- 新增WebPush通知推送功能,实现类客户端的通知提醒效果(无需第三方软件)。使用方法:
   1. 设定 -> 通知 中打开WebPush开关
   2. 将MoviePilot浏览器(Safari、Chrome)网页发送到桌面图标,打开登录时根据提示允许消息通知权限

📢:功能无效或UI出错请清理浏览器缓存(无需清理Cookie)。
2024-06-08 14:45:49 +08:00
jxxghp
518206c34a fix wechat link 2024-06-08 11:21:03 +08:00
jxxghp
e05c643a6b add notification link 2024-06-08 10:47:50 +08:00
jxxghp
748de0ff00 fix webpush link 2024-06-08 07:45:13 +08:00
jxxghp
29b94e859f 更新 config.py 2024-06-08 07:09:21 +08:00
jxxghp
ed3bd0ddef Merge pull request #2289 from InfinityPacer/main 2024-06-08 06:21:57 +08:00
InfinityPacer
3cdbdc2f78 fix mailto移除空格和尖括号 2024-06-08 00:40:14 +08:00
jxxghp
f8fbf9b5eb fix webpush 2024-06-07 21:53:48 +08:00
jxxghp
9e0751367b Merge pull request #2288 from DDS-Derek/main
Revert "feat: refactor docker http proxy"
2024-06-07 21:48:48 +08:00
jxxghp
bc689074e0 fix webpush 2024-06-07 21:47:43 +08:00
DDSRem
7e442650b0 Revert "feat: refactor docker http proxy"
This reverts commit 48a860bfd4.
2024-06-07 21:43:36 +08:00
jxxghp
0a9a391eb3 add webpush log 2024-06-07 21:31:03 +08:00
jxxghp
ea1e600474 Merge pull request #2286 from honue/main 2024-06-07 16:25:33 +08:00
honue
b0a2c1b957 重置插件时删除插件数据 2024-06-07 15:33:17 +08:00
jxxghp
624363476a Merge pull request #2284 from DDS-Derek/main 2024-06-07 13:42:51 +08:00
DDSRem
48a860bfd4 feat: refactor docker http proxy 2024-06-07 11:08:41 +08:00
jxxghp
2d4fb5d52e fix webpush switch 2024-06-07 08:15:30 +08:00
jxxghp
c0c787f7ed fix 2024-06-07 08:01:23 +08:00
jxxghp
03d6834471 fix #2264 2024-06-06 14:21:20 +08:00
jxxghp
947d0d6d4b add 订阅重置api 2024-06-06 07:56:16 +08:00
jxxghp
7611c88aa6 Merge pull request #2272 from InfinityPacer/main 2024-06-05 22:28:13 +08:00
InfinityPacer
7be262b182 fix #2265 优化硬链接的判断逻辑 2024-06-05 22:24:17 +08:00
jxxghp
a7a06a9a75 fix NotificationSwitch 2024-06-05 22:00:39 +08:00
jxxghp
6aa5a836b9 fix webpush api 2024-06-05 18:40:00 +08:00
jxxghp
efd0fc39c6 fix github proxy && add webpush api 2024-06-05 18:08:34 +08:00
jxxghp
7e1951b8e4 Merge pull request #2265 from InfinityPacer/main 2024-06-04 22:00:00 +08:00
InfinityPacer
27c6392b66 fix #667 优化历史兼容极空间硬链接逻辑 2024-06-04 21:54:37 +08:00
jxxghp
0fc7d883c0 v1.9.3
- 搜索功能全面升级,支持搜索多种类型数据,支持模糊搜索站点资源(不匹配不过滤)
- 设置目录时支持浏览选择路径
- 支持配置Github代理地址,以加快版本及插件更新下载
- 优化了插件去重显示
- 优化了目录匹配同路径优先处理逻辑
- 设定等表单中的提示信息强制显示
- 修复了个别插件安装后会消失的问题

注意:前端变化升级后清理浏览器缓存文件(无需清理cookie)
2024-06-03 17:38:31 +08:00
jxxghp
95b480af6d fix #2235 2024-06-03 12:40:35 +08:00
jxxghp
abe7795105 Merge pull request #2259 from thsrite/main 2024-06-03 09:59:52 +08:00
thsrite
74c71390c9 fix unhashable type: 'dict' 2024-06-03 09:54:32 +08:00
jxxghp
1ddd844c17 fix 2024-06-03 08:20:16 +08:00
jxxghp
de3ff2db2e remove api async 2024-06-03 08:17:53 +08:00
jxxghp
655e73f829 fix dir match 2024-06-03 08:03:40 +08:00
jxxghp
2232e51509 add GITHUB_PROXY 2024-06-03 07:09:30 +08:00
jxxghp
44f1a321d2 fix #2249 2024-06-02 21:15:58 +08:00
jxxghp
c05223846f fix api 2024-06-02 21:09:15 +08:00
jxxghp
45945bd025 feat:增加删除下载任务事件,历史记录中删除源文件时主程序会同步删除种子,同时会发出该事件(以便处理辅种等) 2024-06-01 07:47:00 +08:00
jxxghp
acff7e0610 fix log 2024-05-31 20:03:48 +08:00
jxxghp
e97ae488fd fix 线上插件去重 2024-05-31 16:03:27 +08:00
jxxghp
a7689e1e10 fix 2024-05-31 15:08:22 +08:00
jxxghp
9a4d537543 Merge pull request #2237 from hotlcc/develop-20240531 2024-05-31 15:05:22 +08:00
Allen
1b09bb8d22 去掉主动创建下载目录的逻辑,解耦下载器,避免在容器环境当下载器目录与MP映射不一致时导致的目录权限异常 2024-05-31 15:00:47 +08:00
jxxghp
13832a51e0 add listdir api 2024-05-31 13:55:36 +08:00
jxxghp
a09b2fa88a fix log 2024-05-31 09:10:26 +08:00
jxxghp
6361f8654c fix README 2024-05-30 14:13:15 +08:00
jxxghp
db4bda3b73 Merge remote-tracking branch 'origin/main' 2024-05-30 12:39:02 +08:00
jxxghp
3f557ee43c fix README 2024-05-30 12:38:55 +08:00
jxxghp
9e7e0a8730 Merge pull request #2223 from thsrite/main 2024-05-30 10:42:16 +08:00
thsrite
07de1eaa0d fix 插件版本比较 2024-05-30 10:02:26 +08:00
jxxghp
c872043bf4 Merge pull request #2226 from InfinityPacer/main 2024-05-30 06:33:48 +08:00
InfinityPacer
7ed194a62c fix 优先加载子模块 2024-05-30 00:58:20 +08:00
jxxghp
882da68903 Merge pull request #2224 from InfinityPacer/main 2024-05-29 23:06:31 +08:00
InfinityPacer
2798700f71 fix 插件重载时,支持reload一级子模块 2024-05-29 23:01:58 +08:00
thsrite
34e70adabb fix 插件库相同ID的插件保留版本号最大版本 2024-05-29 20:40:04 +08:00
jxxghp
fe999aa346 fix dir match 2024-05-29 17:30:00 +08:00
jxxghp
f7ca4abb01 fix dir match 2024-05-29 17:28:49 +08:00
jxxghp
8a4202cee5 fix dir match 2024-05-29 17:16:35 +08:00
jxxghp
55a85b87dd fix README 2024-05-29 16:47:03 +08:00
jxxghp
3470f96e39 feat:系统错误时发出事件 2024-05-29 16:29:47 +08:00
jxxghp
74980911fe feat:系统错误时发出事件 2024-05-29 16:28:17 +08:00
jxxghp
4c5366f8b4 fix 订阅类型错误日志 2024-05-29 13:41:19 +08:00
jxxghp
8eb89eec86 fix message 2024-05-28 15:39:17 +08:00
jxxghp
cfd7208cda Merge remote-tracking branch 'origin/main' 2024-05-28 12:25:39 +08:00
jxxghp
0c6684a572 fix #2208 下载历史错误数据兼容 2024-05-28 12:25:33 +08:00
jxxghp
f0692b2fb8 更新 __init__.py 2024-05-28 11:50:11 +08:00
jxxghp
c29ee4fb07 Merge pull request #2203 from BrettDean/main 2024-05-28 11:49:07 +08:00
jxxghp
dd40ef54c0 fix #1838 2024-05-28 08:16:51 +08:00
Dean
84d5e2a6b3 fix: Plex刷新媒体库无用 2024-05-28 02:11:42 +08:00
jxxghp
7defcff0e5 v1.9.2
- 修复了目录匹配时同路径优先无效的问题
- 修复了文件管理默认路径还在使用旧变量的问题
- 修复了会删除空媒体库目录的问题
- 修复了TR下载器整理后会覆盖任务原有标签的问题
- 修复了Windows打包,并默认内置了几个主要的插件库
- 优化了资源搜索页面剧集的过滤使用体验
- 硬链接模式下,如果硬链接失败(实际为复制)会发送通知提醒,同时历史记录的整理方式会显示为`复制`
- 消息类型新增了插件消息,专用于需要发送消息类的插件选择使用
2024-05-27 12:46:58 +08:00
jxxghp
d9e767f87d fix 新增消息类型显示 2024-05-27 12:31:48 +08:00
jxxghp
2b82173fba fix windows build 2024-05-27 12:27:15 +08:00
jxxghp
1425b15333 fix #2192 2024-05-27 11:16:41 +08:00
jxxghp
8d82d0f4fd Merge remote-tracking branch 'origin/main' 2024-05-27 10:26:21 +08:00
jxxghp
d352f09d4e fix #2193 2024-05-27 10:26:09 +08:00
jxxghp
aebd121939 Merge pull request #2195 from hotlcc/develop-20240527
Develop 20240527
2024-05-27 10:13:39 +08:00
jxxghp
81eed0d06d fix windows build 2024-05-27 10:11:41 +08:00
Allen
bacb7aaeb4 模块管理种新增根据模块id精确获取模块的方法,以便在插件等场景精确获取qb/tr等由系统统一维护的模块,而不需要插件各自为政 2024-05-27 10:09:18 +08:00
Allen
b238c6ad11 消息类型增加插件消息 2024-05-27 10:06:59 +08:00
jxxghp
5c8b843030 fix 目录健康检查 2024-05-27 08:46:44 +08:00
jxxghp
58acc62e16 feat:硬链接转复制时发系统通知提醒 2024-05-27 08:11:44 +08:00
jxxghp
ca5a240fc4 fix 同路径优先 2024-05-27 07:52:36 +08:00
jxxghp
dd5887d18d fix 同路径优先 2024-05-26 13:28:32 +08:00
jxxghp
97669405d0 fix #2185 2024-05-26 13:15:34 +08:00
jxxghp
bf2ea271b6 fix 硬链接检测 2024-05-26 12:48:52 +08:00
jxxghp
afd91bf760 v1.9.2-beta
- 修复了个别情况下剧集会超出下载范围的问题
- 修复了手动整理目的目录、订阅保存目录未去重显示的问题
- 手动整理下拉选择目的目录时,元数据刮削选项会自动跟随目录设定打开或关闭
- 当指定目的目录的情况下,会尝试查找是否有对应的目录设定,并应用目录的分类和刮削配置
2024-05-26 10:03:52 +08:00
jxxghp
7e982eaf4d fix 订阅整季重复下载 2024-05-26 09:34:50 +08:00
jxxghp
5f13824aa6 fix #2184 手动选择下载/媒体库目录时尝试查找对应的配置并做分类(如果查询不到则不自动分类) 2024-05-26 08:39:59 +08:00
jxxghp
9ca8e3f4a8 更新 category.py 2024-05-25 09:28:48 +08:00
jxxghp
9b749035c9 fix windows build 2024-05-25 07:21:26 +08:00
jxxghp
b8e09a6b06 fix 2024-05-25 07:14:24 +08:00
jxxghp
4bb95d519d v1.9.1-1
- 目前的目录设定结构已经可以做到按二级分类精细化设定目录,动漫一级分类已没有意义,现已取消,同时解决了动漫分类错误的问题。如动漫需单独一级目录,可在目录设定中对电影/电视剧下的动漫二级分类单独调定目录,并将优先级调高。 - 索引站点支持ToSky。 - 仪表板支持一个插件实现多个组件。
2024-05-25 06:37:28 +08:00
jxxghp
04280021b4 fix 动漫分类 2024-05-24 17:21:03 +08:00
jxxghp
355dad9205 Merge pull request #2167 from hotlcc/develop-20240524-插件支持多仪表板组件 2024-05-24 15:49:00 +08:00
Allen
a6714d3712 一个插件支持透出多个仪表板控件,并兼容历史 2024-05-24 14:54:46 +08:00
jxxghp
fe53819a81 fix directory helper 2024-05-24 13:26:20 +08:00
jxxghp
6965415c52 v1.9.1
- 回退了多线程优先级过滤,以暂时解决过滤器偶发报错的问题(搜索慢的过滤规则层数减一减吧)
- 发现推荐改为使用TTL缓存,解决榜单长时间不刷新的问题
- 修复了目录指定了类别时会重复创建类别文件夹的问题
- 订阅保存路径支持下拉选择已配置的下载目录
- 降低了INFO日志打印量,如需打印详细日志请设置`DEBUG`为`true`(写过多日志会降低响应速度)
- 目录设定中增加了同盘优先选项,开启后在匹配媒体库目录时优先使用同盘/同根路径目录
- 修复了一个订阅匹配的问题

注意:因媒体库目录设置结构调整,`目录监控`插件指定目的路径时不再支持自动创建下级分类目录。建议插件中不指定目的目录,而是在`设定->目录`中设定好目录结构让系统自动匹配使用(根据需要打开同盘优先选项)。实际上如果是可以通过分类来指定目录的,建议直接使用内建的下载器监控功能,目录监控仅是个插件,仅适用于不通过MoviePilot自动下载的文件监控整理。
2024-05-24 12:47:34 +08:00
jxxghp
9be671fa2c fix 82226f1956 2024-05-24 12:36:51 +08:00
jxxghp
27b4f206a1 fix 订阅刷新站点范围扩大问题 2024-05-24 12:31:11 +08:00
jxxghp
a2b0c9bd3a fix #2164 2024-05-24 11:37:26 +08:00
jxxghp
ebc46d7d3b fix #2165 2024-05-24 11:31:37 +08:00
jxxghp
eb4e4b5141 feat:新增同盘优先设置 2024-05-24 11:19:21 +08:00
jxxghp
be11ef72a9 调整INFO日志打印量 && 回滚多线程过滤 2024-05-24 10:48:56 +08:00
jxxghp
a278c80951 fix #2151 TMDB发现和趋势修改为TTL缓存 2024-05-24 09:29:51 +08:00
jxxghp
6ee6de48ff 尝试修复过滤器并发报错 2024-05-24 08:56:32 +08:00
jxxghp
671bdad77c v1.9.1-beta
- 优化了订阅匹配逻辑
- 目录设置全新改版,多目录支持更加灵活,存量目录配置会自动升级为新格式
- 手动整理时支持下拉选择已配置目录
- 元数据刮削取消了全局开关,按媒体库目录设置,目录监控等插件新增了刮削开关并需要手动打开
- 站点管理支持拖动排序
- 修复了仪表板不可见组件仍会刷新的问题

注意:涉及前端变化升级后需要清理浏览器缓存(仅清理缓存文件,无需清理cookie)
2024-05-23 19:43:08 +08:00
jxxghp
a9ff8ec96d 更新 README.md 2024-05-23 14:28:40 +08:00
jxxghp
d1678355f1 fix #2099 2024-05-23 12:45:27 +08:00
jxxghp
ea399daef9 更新 __init__.py 2024-05-23 11:46:30 +08:00
jxxghp
e1122af97c 更新 __init__.py 2024-05-23 10:05:56 +08:00
jxxghp
21861111e6 更新 download.py 2024-05-23 10:05:07 +08:00
jxxghp
bd1e83ee8a fix 2024-05-23 08:53:20 +08:00
jxxghp
43da33bc50 fix 2024-05-23 08:41:20 +08:00
jxxghp
a09a207407 fix manual_transfer api 2024-05-23 08:09:36 +08:00
jxxghp
0aa3aa8521 Merge pull request #2146 from zhu0823/main 2024-05-23 07:10:48 +08:00
jxxghp
d9c6375252 feat:目录结构重大调整,谨慎更新到dev 2024-05-22 20:02:14 +08:00
jxxghp
f1f187fc77 add media category api 2024-05-22 18:02:28 +08:00
zhu0823
99d22554a1 fix: plex最近添加类型为show的资源 2024-05-22 13:34:03 +08:00
jxxghp
4835f6c6c9 更新 subscribe.py 2024-05-21 23:17:59 +08:00
jxxghp
5be2bf0633 feat:服务器地址变量化 2024-05-21 17:31:12 +08:00
jxxghp
7c7bc0b504 fix log 2024-05-21 17:14:16 +08:00
jxxghp
e0939fee75 fix https://github.com/jxxghp/MoviePilot/issues/2134 2024-05-21 16:36:09 +08:00
jxxghp
82226f1956 fix https://github.com/jxxghp/MoviePilot/issues/2125 调整订阅匹配逻辑 2024-05-21 11:57:12 +08:00
jxxghp
cfb43b4b04 fix torrent match 2024-05-21 09:54:06 +08:00
jxxghp
ebe2795eae Merge pull request #2128 from jeblove/main 2024-05-21 06:48:54 +08:00
jeblove
f7f747278d fix: jellyfin webhook百分比数据有时为None引发报错 2024-05-20 23:47:37 +08:00
jxxghp
58f17e89b6 v1.9.0
- 支持用户自定义主题风格
- 资源搜索列表模式下支持排序
- 索引站点新增支持`YemaPT`
- 修复了某些情况下订阅查询转圈的问题
- 修复了默认洗版设置不生效的问题
- 修复了存在活动连接时无法正常关闭系统的问题
- 回退了上个版本的最后一点修改(会导致手机端添加桌面图标时没有App效果)
2024-05-20 18:24:39 +08:00
jxxghp
433ca2ec28 fix YemaPT 2024-05-20 17:41:46 +08:00
jxxghp
ffac57ad4d 支持 YemaPT 2024-05-20 16:55:36 +08:00
jxxghp
0d2a4c50d6 fix error message 2024-05-20 15:39:43 +08:00
jxxghp
02c2edc30e fix WEB页面活动时无法正常停止服务的问题 2024-05-20 11:50:49 +08:00
jxxghp
65975235d4 fix scheduler 2024-05-20 10:16:20 +08:00
jxxghp
07a6abde0e fix json exception 2024-05-20 09:13:51 +08:00
jxxghp
fa47d9adeb fix 2024-05-19 14:17:34 +08:00
jxxghp
18d08c3672 fix 2024-05-19 12:35:21 +08:00
jxxghp
cf20049b7f Merge pull request #2117 from InfinityPacer/main
fix 开启DEBUG时,LOG文件也记录DEBUG日志
2024-05-19 12:28:08 +08:00
InfinityPacer
e3ce3302da fix 开启DEBUG时,LOG文件也记录DEBUG日志 2024-05-19 12:18:43 +08:00
jxxghp
d20951e7a0 Merge pull request #2116 from InfinityPacer/main 2024-05-19 12:08:03 +08:00
InfinityPacer
8a565bb79f fix #2113 2024-05-19 11:53:18 +08:00
jxxghp
cfdc8fb2c3 Merge pull request #2115 from InfinityPacer/main 2024-05-19 11:02:19 +08:00
InfinityPacer
111f830664 fix #2104 2024-05-19 10:58:09 +08:00
jxxghp
2821d6a9dc fix #2076 2024-05-19 09:54:52 +08:00
jxxghp
495d98c2b2 fix #2086 没有站点时订阅打不开的问题 && 默认洗版不生效的问题 2024-05-19 09:52:00 +08:00
jxxghp
e1e2779e48 fix #2101 1ptba签到增加index.php,认证及种子浏览有带具体的URI,如有问题需要站点放开。 2024-05-19 09:42:22 +08:00
jxxghp
363318f4f0 智能下载增加日志打印 2024-05-19 09:19:44 +08:00
jxxghp
521b960364 catch command exception 2024-05-19 08:35:18 +08:00
jxxghp
d2bcb197eb v1.8.9
- 站点增加了独立的超时时间设置(默认15秒),可根据站点连通情况调整对应超时时间,以缩短搜索耗时
- 使用多线程加快搜索结果的优先级过滤速度
- 极大提升了非首次登录时的页面加载速度(需要重新拉取镜像该特性才会生效)
- 仪表仪的拖拽图标默认隐藏,避免影响无边框组件的显示效果
- 安装网页到桌面App时,支持前进后退操作按钮
2024-05-17 14:51:02 +08:00
jxxghp
b0f9ca52e3 fix nginx cache 2024-05-17 14:37:25 +08:00
jxxghp
01a3efd402 fix nginx cache 2024-05-17 13:58:29 +08:00
jxxghp
a50427948a feat:多线程过滤 2024-05-17 12:20:39 +08:00
jxxghp
5614f10962 fix get_dashboard 2024-05-17 10:50:03 +08:00
jxxghp
5ff80dbe89 fix get_dashboard 2024-05-17 10:49:47 +08:00
jxxghp
278835c5d4 fix 2024-05-17 07:46:27 +08:00
jxxghp
92cdd67f3a Merge pull request #2093 from thsrite/main 2024-05-16 20:53:57 +08:00
thsrite
c56b58cc56 fix 2024-05-16 20:50:42 +08:00
thsrite
8bd4c21511 fix 2024-05-16 20:49:28 +08:00
thsrite
b94f201667 fix 拆包场景下,下载通知标题展示实际下载的集数 2024-05-16 20:44:57 +08:00
jxxghp
125e9eb30a Merge pull request #2091 from happyTonakai/main
Jellyfin webhook 添加播放百分比字段
2024-05-16 20:36:24 +08:00
happyTonakai
ea09d8c8d4 Jellyfin webhook 添加播放百分比字段 2024-05-16 20:20:24 +08:00
jxxghp
de0237f348 dashboard 传递 UA 2024-05-16 17:32:35 +08:00
jxxghp
62143bf7b6 fix db 2024-05-16 16:18:22 +08:00
jxxghp
3088bbb2f8 站点独立设置超时时间 2024-05-16 14:42:10 +08:00
jxxghp
43647e59a4 fix module name 2024-05-16 14:20:18 +08:00
jxxghp
a740330e66 Update README.md 2024-05-15 19:25:53 +08:00
jxxghp
10d4766353 fix bug 2024-05-15 07:42:03 +08:00
jxxghp
0a845fe8b6 Merge remote-tracking branch 'origin/main' 2024-05-14 20:37:18 +08:00
jxxghp
90dc52bb70 v1.8.8
- 新增了系统级通知功能
- 优化了主题切换使用体验
- 修复了仪表板存储空间卡片无法移动的问题
- 修复了仪表板自动刷新组件会重复生成的问题
- 修复了插件图表在暗黑主题下字体颜色偏暗的问题
- 仪表板组件支持无边框模式
- 默认内置了几个主要的第三方插件库
- 优先级规则支持拖拽排序
2024-05-14 20:37:03 +08:00
jxxghp
3816e2fba8 Merge pull request #2073 from developer-wlj/wlj0409 2024-05-14 20:35:22 +08:00
mayun110
20d92ca577 fix: 收藏洗版 jellyfin webhook 缺少的字段 2024-05-14 20:11:49 +08:00
jxxghp
db92761964 fix ide warning 2024-05-14 18:04:10 +08:00
jxxghp
3af5870733 Merge pull request #2071 from hotlcc/develop-20240514-修复一些发现的问题 2024-05-14 18:00:08 +08:00
Allen
53d01267b8 修复模块加载时前置模块失败导致后续均无法加载的问题 2024-05-14 17:25:22 +08:00
jxxghp
5ff21641f9 内置部分第三方插件库 2024-05-14 15:27:50 +08:00
jxxghp
643f2e3e66 Merge remote-tracking branch 'origin/main' 2024-05-14 10:08:15 +08:00
jxxghp
ae839235eb feat:服务异常时推送前台消息 2024-05-14 10:08:07 +08:00
jxxghp
5af94144ce Merge pull request #2067 from thsrite/main 2024-05-14 09:48:05 +08:00
thsrite
4281692321 fix add插件热加载变量开关(保留DEV开关 2024-05-14 09:24:02 +08:00
jxxghp
bd6d6b6882 fix 2024-05-14 08:30:29 +08:00
jxxghp
fabb02a8a0 fix README 2024-05-13 20:25:52 +08:00
jxxghp
223e655b6f feat:插件API立即生效 2024-05-13 20:15:47 +08:00
jxxghp
f0cb5b3e85 Merge pull request #2059 from EkkoG/fix_min_seeders_time 2024-05-13 11:25:10 +08:00
EkkoG
7579aae823 修复订阅时没有读取 min_seeders_time 导致最少做种人数生效时间不生效 2024-05-13 11:06:49 +08:00
jxxghp
36a8b6d780 更新 download.py 2024-05-13 07:38:14 +08:00
jxxghp
0471167b74 fix dev 2024-05-12 20:12:59 +08:00
jxxghp
28b996e54b Merge pull request #2056 from DDS-Derek/bump 2024-05-12 11:17:13 +08:00
DDSRem
d0989f72a9 bump: debian bullseye to bookworm 2024-05-12 09:55:35 +08:00
jxxghp
663e61e3a1 fix message api 2024-05-11 16:24:25 +08:00
jxxghp
71b0090947 Merge remote-tracking branch 'origin/main' 2024-05-11 12:53:40 +08:00
jxxghp
8ff0f81f47 fix message api 2024-05-11 12:53:32 +08:00
jxxghp
4186613a86 Merge pull request #2051 from InfinityPacer/main 2024-05-11 06:25:50 +08:00
InfinityPacer
4e1be23317 fix 热加载增加双重防抖 2024-05-11 01:23:33 +08:00
jxxghp
0e9e626ab6 fix 2024-05-10 20:09:45 +08:00
jxxghp
3d5761157a Merge pull request #2047 from InfinityPacer/main
fix 热加载不同平台路径及插件实例化
2024-05-10 19:57:48 +08:00
InfinityPacer
c407800b30 fix 热加载不同平台路径及插件实例化 2024-05-10 19:27:44 +08:00
jxxghp
c888a37aba fix README 2024-05-10 18:29:20 +08:00
jxxghp
d43998efee fix 插件热加载控重 2024-05-10 18:27:31 +08:00
jxxghp
8813e84053 feat:DEV模式下插件文件修改后自动重新加载 2024-05-10 13:33:00 +08:00
jxxghp
cf5a746f53 fix #2037 2024-05-10 08:22:05 +08:00
jxxghp
f9f58fc559 v1.8.7
- 认证站点增加新成员:DiscFan
- 支持插件在仪表板中显示Widget,站点数据统计、站点刷流插件已支持,其余插件待开发者适配,插件开发说明:https://github.com/jxxghp/MoviePilot-Plugins
- 仪表板组件支持用户通过拖拽调整显示顺序
- 调整了热门订阅订阅人数的显示样式
2024-05-09 20:06:19 +08:00
jxxghp
f59b5b6d27 fix plugin dashboard 2024-05-09 19:12:43 +08:00
jxxghp
30b3ad4a99 fix plugin dashboard 2024-05-09 19:12:12 +08:00
jxxghp
dfb9ce7520 fix tmdb match api 2024-05-09 18:49:58 +08:00
jxxghp
6c365f552e Merge pull request #2038 from Devinaille/fix_subtitle_match 2024-05-09 11:40:03 +08:00
tianyf
a81ee7d89a 修复副标题包含【】的情况下无法匹配标题的问题 2024-05-09 11:18:00 +08:00
jxxghp
5c9039e6d0 feat:插件仪表板API 2024-05-08 20:58:28 +08:00
jxxghp
cce2e13e21 fix README.md 2024-05-08 16:46:35 +08:00
jxxghp
0da87abc71 Merge remote-tracking branch 'origin/main' 2024-05-08 15:54:56 +08:00
jxxghp
6a2eecc744 fix #2016 2024-05-08 15:54:50 +08:00
jxxghp
c049e13c1c Merge pull request #2032 from z3shan33/main 2024-05-08 13:04:13 +08:00
z3shan33
7ec49ce076 fix #2031 2024-05-08 11:09:36 +08:00
jxxghp
5be2fc35b5 Merge pull request #2026 from zhu0823/main 2024-05-07 18:31:12 +08:00
zhu0823
0b84312559 fix: 某些剧集parentThumb为None时的问题 2024-05-07 18:28:53 +08:00
jxxghp
8bb43b52bc - 优化热门订阅数据统计,热门订阅支持展示订阅人数 2024-05-07 16:19:05 +08:00
jxxghp
bd348f118c fix 订阅统计清理 2024-05-07 16:01:52 +08:00
jxxghp
4a3a3483d0 fix api 2024-05-07 12:31:24 +08:00
jxxghp
fd6314f19f fix 2024-05-06 22:48:24 +08:00
jxxghp
17a9f3a626 更新 version.py 2024-05-06 19:08:49 +08:00
jxxghp
75c898e6eb Merge pull request #2018 from zhu0823/main 2024-05-06 18:37:00 +08:00
zhu0823
089d4785aa fix: plex最近添加的剧集封面地址 2024-05-06 18:35:10 +08:00
jxxghp
4d48295f72 fix bug 2024-05-06 16:46:03 +08:00
jxxghp
ed119b7beb fix 数据共享开关 2024-05-06 12:37:51 +08:00
jxxghp
90d5a8b0c9 add 数据共享开关 2024-05-06 11:54:32 +08:00
jxxghp
dd5c0de7b1 feat:订阅统计 2024-05-06 11:19:41 +08:00
jxxghp
73bdca282c fix api desc 2024-05-05 13:51:49 +08:00
jxxghp
360a54581f add api 2024-05-05 13:43:14 +08:00
jxxghp
1fc7587cbb fix 豆瓣&Bangumi搜索过于宽泛 2024-05-05 12:14:58 +08:00
jxxghp
dcd46f1627 fix #2001 2024-05-05 11:54:42 +08:00
jxxghp
d8644a20c0 fix #2011 2024-05-05 11:22:23 +08:00
jxxghp
23b47f98c1 Merge pull request #2009 from DDS-Derek/main 2024-05-05 09:55:00 +08:00
DDSRem
347c91fa0b bump: ca-certificates version to bookworm 2024-05-04 19:14:30 +08:00
jxxghp
ac961b37b4 Merge pull request #2004 from thsrite/main 2024-05-03 13:52:45 +08:00
thsrite
068c49a79a fix 最小做种数生效时间 2024-05-03 13:09:08 +08:00
jxxghp
e7174b402c Merge pull request #1988 from zhu0823/main 2024-04-30 19:20:33 +08:00
zhu0823
d21267090a 同步更新上游api 2024-04-30 19:14:29 +08:00
zhu0823
51dc2c33a0 feat: plex最近添加过滤黑名单 2024-04-30 19:14:08 +08:00
jxxghp
8aef488ab6 Merge pull request #1986 from Sxnan/tmdbid-type 2024-04-30 16:03:44 +08:00
sxnan
0cbf45f9b9 Cast tmdbid to int type after getting metainfo from title 2024-04-30 15:55:10 +08:00
jxxghp
c0ae32d654 - 修复豆瓣数据源搜索媒体类型错误的问题 2024-04-30 13:33:28 +08:00
jxxghp
ff1b0e02d6 fix 特殊集数识别 2024-04-30 11:49:03 +08:00
jxxghp
76a8b02fe5 fix 豆瓣搜索词条类型错误问题 2024-04-30 11:17:03 +08:00
jxxghp
43f594393c feat:插件增加排序字段 2024-04-30 08:34:37 +08:00
jxxghp
008e11d63f fix 豆瓣人物头像质量 2024-04-30 07:15:21 +08:00
jxxghp
9dd610f245 更新 site.py 2024-04-29 21:46:55 +08:00
jxxghp
c5d087aad6 Merge pull request #1979 from InfinityPacer/main 2024-04-29 20:43:14 +08:00
jxxghp
576c5741f9 v1.8.5
- 支持媒体信息多数据源聚合搜索(TheMovieDb、豆瓣、Bangumi),可在`设定`-`搜索`中调整数据源范围和顺序
- 插件支持设置标签,优化了插件功能的使用体验
- 适配馒头最新架构调整,需在站点管理中手动维护站点令牌和请求头
2024-04-29 20:39:20 +08:00
InfinityPacer
51387c31c4 fix plugin_order 2024-04-29 20:39:01 +08:00
jxxghp
c2a40876e2 适配m-team新鉴权机制 2024-04-29 20:19:46 +08:00
jxxghp
c06bdf0491 fix exception 2024-04-28 18:10:04 +08:00
jxxghp
f726130c31 feat:插件读取Label 2024-04-28 13:35:47 +08:00
jxxghp
4033ffeb15 fix 聚合结果排序 2024-04-28 12:03:48 +08:00
jxxghp
f81af8e9fb Merge remote-tracking branch 'origin/main' 2024-04-28 10:41:05 +08:00
jxxghp
e3f9260299 fix README.md 2024-04-28 10:40:59 +08:00
jxxghp
c80ccaf74b Merge pull request #1976 from thsrite/main 2024-04-28 10:26:05 +08:00
thsrite
0e60c976be fix 默认过滤规则支持最少做种人数生效发布时间,防止过滤掉到最新发布的种子 2024-04-28 10:21:42 +08:00
jxxghp
805c7d2701 fix torrent filter log 2024-04-28 09:19:09 +08:00
jxxghp
4499f001dd fix bug 2024-04-28 09:03:16 +08:00
jxxghp
71c6a3718b feat:媒体搜索聚合开关 2024-04-28 08:55:07 +08:00
jxxghp
6404f9d45c 更新 tmdb.py 2024-04-27 22:39:50 +08:00
jxxghp
ce357540eb 更新 douban.py 2024-04-27 22:38:47 +08:00
jxxghp
e56cfd6ad4 fix douban apis 2024-04-27 22:29:17 +08:00
jxxghp
25e5f7a9f6 fix tmdb apis 2024-04-27 21:56:27 +08:00
jxxghp
6d69ac42e5 fix bangumi apis 2024-04-27 21:36:42 +08:00
jxxghp
6a71bed821 fix douban api 2024-04-27 21:17:32 +08:00
jxxghp
1718758d1c fix 豆瓣图片质量 2024-04-27 17:16:19 +08:00
jxxghp
7a37078e90 feat:媒体信息聚合 2024-04-27 15:20:46 +08:00
jxxghp
26b5ad6a44 Merge pull request #1969 from lightolly/dev/20240428_1
feat:add person api
2024-04-27 13:00:46 +08:00
olly
fa884c9608 feat:add person api 2024-04-27 11:52:23 +08:00
jxxghp
6927b5fbd3 Merge pull request #1968 from lightolly/dev/20240428 2024-04-27 10:24:35 +08:00
olly
59fca63d4a feat:add api 2024-04-27 10:12:40 +08:00
jxxghp
7489d6a912 v1.8.4
- 搜索框支持搜索演员,修复了演员参演作品只显示电影的问题
- 插件支持在数据页面绑定事件以及调用API接口
- 启动时如用户认证失败,后台会间歇性重试一段时间
- `设定`-`关于` 增加显示前端版本号
- 历史记录支持排序
- 优化了小屏幕下的弹窗使用体验
- Jellyfin 的页面跳转调整为支持`latest`分支版本
- 修复了个别情况下订阅历史记录会登记失败的问题
2024-04-27 09:09:09 +08:00
jxxghp
b437fd6021 fix bug 2024-04-27 00:30:17 +08:00
jxxghp
c303ab0765 fix api 2024-04-26 20:29:04 +08:00
jxxghp
9daff87f2f fix api 2024-04-26 19:41:17 +08:00
jxxghp
f20b1bcfe9 feat:人物搜索API 2024-04-26 17:47:45 +08:00
jxxghp
2f71e401be fix 2024-04-26 17:11:24 +08:00
jxxghp
0840e0bcbc Merge pull request #1967 from thsrite/main
fix 当前版本、重启检查前端版本
2024-04-26 17:05:12 +08:00
thsrite
933af7485c fix function name 2024-04-26 17:00:40 +08:00
thsrite
baddaabd73 fix 2024-04-26 16:59:19 +08:00
thsrite
8028866cee fix 2024-04-26 16:58:30 +08:00
thsrite
242894cec2 fix 当前版本、重启检查前端版本 2024-04-26 16:54:25 +08:00
jxxghp
967ad3a507 Merge pull request #1966 from thsrite/main 2024-04-26 14:44:16 +08:00
thsrite
2dbe049a91 fix 查询某时间之后的转移历史 2024-04-26 14:41:52 +08:00
jxxghp
c5afc65cbd fix #1955 启动时用户认证失败时,间歇性重试 2024-04-26 11:08:25 +08:00
jxxghp
e35bacecd5 fix #1942 2024-04-26 10:42:24 +08:00
jxxghp
d84c86b0f6 fix 插件重置 2024-04-25 16:48:37 +08:00
jxxghp
73ae09b041 fix bug 2024-04-25 10:31:11 +08:00
jxxghp
a11318390d feat:读取前端版本号 2024-04-25 10:18:38 +08:00
jxxghp
1714990e2e feat:读取前端版本号 2024-04-25 10:18:14 +08:00
jxxghp
44cd5f52e0 fix #1945 2024-04-24 10:25:45 +08:00
jxxghp
59b9dc354e fix 整合重复代码 2024-04-24 08:18:11 +08:00
jxxghp
591969015f v1.8.3
- 仪表板设定支持按用户持久化保存,同时也支持按浏览器差异化配置
- 修复了文件整理使用`original_name`占位符时后缀重复以及应用了识别词的问题
- 优化了个别站点的适配
- 修复了插件市场显示空插件的问题
2024-04-23 17:53:32 +08:00
jxxghp
6118e235c3 Merge pull request #1943 from thsrite/main 2024-04-23 17:17:28 +08:00
thsrite
228b1a11d0 fix 2024-04-23 16:18:30 +08:00
thsrite
c8a1e59310 fix plugin 403 msg 2024-04-23 16:16:39 +08:00
jxxghp
b0f7a11328 fix naming 2024-04-23 11:22:43 +08:00
jxxghp
b753e50580 fix api order 2024-04-23 10:06:19 +08:00
jxxghp
3002bf4dd2 fix 2024-04-23 10:02:15 +08:00
jxxghp
0cbe8f5cdc Merge pull request #1920 from hotlcc/develop-20240417-用户配置
新增用户配置相关能力和接口
2024-04-23 09:57:55 +08:00
jxxghp
1a03d19469 Merge remote-tracking branch 'origin/main' 2024-04-23 09:56:28 +08:00
jxxghp
b7c1106744 fix #1940 2024-04-23 09:56:21 +08:00
Allen
d6c6c999fc 优化用户级配置能力 2024-04-23 09:51:18 +08:00
jxxghp
408703d4a3 Merge pull request #1938 from thsrite/main 2024-04-22 18:14:34 +08:00
thsrite
40a612c327 fix 2024-04-22 15:57:34 +08:00
thsrite
e519fc484b fix 获取指定用户的订阅列表 2024-04-22 15:56:50 +08:00
thsrite
e430a3e88b fix 获取指定tmdb_id的订阅列表 2024-04-22 15:49:57 +08:00
jxxghp
316f61bf69 fix #1922 2024-04-22 09:54:51 +08:00
jxxghp
750c4441db fix #1930 2024-04-22 09:31:35 +08:00
jxxghp
441cee4ee5 v1.8.2
- 新增订阅历史记录功能
- 站点支持显示连接状态
- 站点新增支持花梨月下

注意:更新后需要清理浏览器缓存
2024-04-19 19:57:42 +08:00
jxxghp
ebf2f53ae1 fix api 2024-04-19 19:51:01 +08:00
jxxghp
4e7000efbb Merge pull request #1925 from Aodi/main
fix 反向代理图片显示问题,url改为查询参数避免双斜杠的优化
2024-04-19 19:37:29 +08:00
jxxghp
0679a32659 fix 2024-04-19 12:31:38 +08:00
jxxghp
148984ad0e Merge pull request #1923 from thsrite/main 2024-04-19 11:50:31 +08:00
thsrite
dd8804ef3e fix 2024-04-19 11:49:03 +08:00
aodi
fb0018dda6 fix 反向代理图片显示问题,url改为查询参数避免双斜杠的优化 2024-04-19 11:24:37 +08:00
thsrite
c14e529c91 fix #1921 2024-04-19 10:26:34 +08:00
jxxghp
f6222122c0 feat:订阅历史以及API 2024-04-18 21:00:57 +08:00
jxxghp
3a18267ec0 feat:订阅历史以及API 2024-04-18 15:48:46 +08:00
Allen
ae60040120 fixbug 2024-04-18 15:19:46 +08:00
jxxghp
b04bc74550 fix public site flag 2024-04-18 15:10:06 +08:00
Allen
666d6eb048 新增用户配置相关能力和接口 2024-04-18 12:33:35 +08:00
jxxghp
73a3a8cf94 fix #1914 2024-04-18 11:20:03 +08:00
jxxghp
6d66c5b577 更新 site.py 2024-04-17 15:02:03 +08:00
jxxghp
c3ffe38d4d feat:站点使用统计 2024-04-17 12:42:32 +08:00
jxxghp
5108dbbeb5 fix plugin install 2024-04-17 09:46:02 +08:00
jxxghp
cbf56bd9b7 fix module log 2024-04-16 18:22:02 +08:00
jxxghp
67965b09a6 Merge remote-tracking branch 'origin/main' 2024-04-16 18:21:04 +08:00
jxxghp
a2678d5815 fix #1882 季赋值错误! 2024-04-16 18:20:54 +08:00
jxxghp
36b25e6a08 Merge pull request #1908 from zhu0823/main 2024-04-16 17:49:33 +08:00
zhu0823
c98c8c8836 feat: plex媒体数量统计过滤黑名单 2024-04-16 17:42:25 +08:00
jxxghp
423b7cf340 Merge pull request #1907 from zhu0823/main 2024-04-16 16:54:43 +08:00
zhu0823
02acc8bc35 feat: plex继续观看过滤黑名单 2024-04-16 16:38:16 +08:00
jxxghp
664b42f050 fix original_name 2024-04-16 10:22:49 +08:00
jxxghp
ca491891dc - 修复历史记录问题 2024-04-16 10:06:14 +08:00
jxxghp
89e3d16f27 Merge pull request #1897 from Aodi/main 2024-04-15 18:29:02 +08:00
aodi
a02ea64068 fix 编码斜杠禁用的反代无法加载图片 2024-04-15 16:03:44 +08:00
jxxghp
0f0ace5ddc feat:历史记录按目录模糊匹配 2024-04-15 14:10:45 +08:00
jxxghp
04d94f3bdd fix torrents match 2024-04-15 13:26:25 +08:00
jxxghp
7d45b68b4f fix scheduler 2024-04-15 13:17:20 +08:00
jxxghp
ccb47c0120 v1.8.1
- 优化文件识别
- 优化历史记录性能、支持目录过滤
- 插件更新时支持查看更新记录
2024-04-14 14:04:21 +08:00
jxxghp
6939bff790 fix #1882 2024-04-14 13:47:12 +08:00
jxxghp
8cd0dd4198 Merge pull request #1882 from WangEdward/main
fix: metainfo for manual transfer
2024-04-14 13:19:46 +08:00
jxxghp
d6d1f6519a Merge remote-tracking branch 'origin/main' 2024-04-14 13:15:01 +08:00
jxxghp
906325710b fix #1876 2024-04-14 13:14:41 +08:00
jxxghp
05bafeaedf Merge pull request #1888 from thsrite/main 2024-04-14 12:31:36 +08:00
thsrite
babad5a098 fix 插件多次加载 2024-04-14 11:54:38 +08:00
jxxghp
fe07602a35 fix 新增站点区分提示 2024-04-13 18:56:07 +08:00
jxxghp
492533dcdb rollback #1884 2024-04-13 18:38:29 +08:00
jxxghp
45b044cd6b Merge pull request #1884 from thsrite/main 2024-04-13 18:03:34 +08:00
thsrite
fc65cc3619 fix 单例加锁,防止init方法时间过长导致多次init 2024-04-13 17:33:08 +08:00
jxxghp
c6e069331c Merge pull request #1883 from thsrite/main 2024-04-13 17:09:10 +08:00
thsrite
6a8a946ec8 fix PluginHelper().install已经统计安装 2024-04-13 17:05:12 +08:00
Edward
d96e4561e2 fix: metainfo for manual transfer 2024-04-12 14:20:41 +00:00
Edward
172bc23b2a fix: empty season 2024-04-12 14:12:15 +00:00
jxxghp
98baf922d6 fix resource exception 2024-04-12 21:38:53 +08:00
jxxghp
9a7cdc1e74 fix #1858 2024-04-12 12:45:16 +08:00
jxxghp
4e22293cda fix 文件多层路径识别 2024-04-12 12:04:42 +08:00
jxxghp
f17890b6ce fix 词表指定媒体ID的匹配 2024-04-12 08:24:20 +08:00
jxxghp
66af2de416 fix #1864 2024-04-11 19:48:19 +08:00
jxxghp
17e1e6b49b fix log 2024-04-11 12:46:29 +08:00
jxxghp
e501154ad4 v1.8.0
- 搜索和订阅支持指定季,输入:xxxx 第x季
- 插件市场支持查看插件的更新日志(需要插件作者补充)
- 优化了媒体信息识别
- 优化了动漫及拼音标题的资源搜索匹配
- 优化了UI性能
- 修复了手动搜索时默认过滤规则不生效的问题
- 新增下载文件实时整理API,可在 QB设置->下载完成时运行外部程序 处填入:curl "http://localhost:3000/api/v1/transfer/now?token=moviepilot",实现下载器监控模式下无需等待轮循,下载完成后立即整理入库(地址、端口和token按实际调整,curl也可更换为wget)。

注意:如搜索异常请清理浏览器缓存。
2024-04-11 08:21:29 +08:00
jxxghp
c73cf1d7e2 v1.8.0
- 搜索和订阅支持指定季,输入:xxxx 第x季
- 插件市场支持查看插件的更新日志(需要插件作者补充)
- 优化了媒体信息识别
- 优化了动漫及拼音标题的资源搜索匹配
- 优化了UI性能
- 修复了手动搜索时默认过滤规则不生效的问题
- 新增下载文件实时整理API,可在 QB设置->下载完成时运行外部程序 处填入:curl "http://localhost:3000/api/v1/transfer/now?token=moviepilot",实现下载器监控模式下无需等待轮循,下载完成后立即整理入库(地址、端口和token按实际调整,curl也可更换为wget)。

注意:如搜索异常请清理浏览器缓存。
2024-04-11 08:02:24 +08:00
jxxghp
a3603f79c8 fix requests 2024-04-10 22:16:10 +08:00
jxxghp
294b4a6bf9 fix torrents match 2024-04-10 20:05:43 +08:00
jxxghp
f365d93316 fix torrents match 2024-04-10 20:02:02 +08:00
jxxghp
facd20ba3c fix bangumi 2024-04-10 19:04:59 +08:00
jxxghp
d0e596c93c feat: 插件更新历史 2024-04-10 16:44:08 +08:00
jxxghp
e20ec4ddf5 fix bug 2024-04-10 15:05:32 +08:00
jxxghp
ba0a1cb1bd fix #1738 搜索和订阅支持指定季 2024-04-10 14:51:34 +08:00
jxxghp
17438f8c5c fix log 2024-04-10 13:41:11 +08:00
jxxghp
e0c2ae0f0c fix log 2024-04-10 13:20:33 +08:00
jxxghp
9ebb211589 fix meta cases 2024-04-10 12:22:32 +08:00
jxxghp
8a0350c566 fix mtype 2024-04-10 11:50:14 +08:00
jxxghp
765d37fd6a fix meta 2024-04-10 11:44:14 +08:00
jxxghp
b3d57b868e fix:自定义识别词不处理空格 2024-04-10 07:09:31 +08:00
jxxghp
18e7099848 fix:自定义识别词不处理空格 2024-04-10 07:07:17 +08:00
jxxghp
27cb968a18 fix #1846 2024-04-09 18:47:25 +08:00
jxxghp
45bf84d448 fix #1849 2024-04-09 18:43:24 +08:00
jxxghp
85300b0931 more log 2024-04-09 13:36:13 +08:00
jxxghp
ac87c778f4 fix anime match 2024-04-09 13:20:28 +08:00
jxxghp
1ed511034c fix search match 2024-04-09 07:09:54 +08:00
jxxghp
ca7f121a21 Merge pull request #1847 from hotlcc/develop-修复PTLSP站点测试 2024-04-08 14:05:50 +08:00
Allen
c8e73e17d3 修复ptlsp测试问题 2024-04-08 04:26:49 +00:00
Allen
3bfc87f1cc ptlsp站点测试问题修复 2024-04-08 03:16:07 +00:00
jxxghp
e0e76bf3fe fix 2024-04-07 16:32:26 +08:00
jxxghp
6a3e3f1562 feat:中英文名依次匹配 2024-04-07 16:20:33 +08:00
jxxghp
59330657b2 add nano 2024-04-07 14:56:32 +08:00
jxxghp
927d510619 add 立即执行下载器文件整理 API 2024-04-07 14:45:59 +08:00
jxxghp
80a390ac6c feat:种子名为拼音的情况下,从副标题中提取中文名用于识别 2024-04-07 14:25:12 +08:00
jxxghp
cae563ce53 test:更加宽松的匹配规则 2024-04-06 21:07:00 +08:00
jxxghp
0495936ef8 v1.7.9
- 订阅支持预设订阅规则
- 插件新增快速搜索功能、优化了插件安装和卸载的响应速度
- 优化了文件管理、历史记录的性能和易用性
- 修复了馒头种子下载失败的问题

温馨提示:
1. 如遇到前端奇奇怪怪的问题,请先清理浏览器缓存
2. 合理设置优先级层级,如层级过多且搜索结果很多时,会明显增加搜索耗时
2024-04-06 17:27:48 +08:00
jxxghp
34d27fe85b fix #1818 2024-04-06 11:47:22 +08:00
jxxghp
0e2c4d74d6 feat:优化插件重载 2024-04-05 23:20:51 +08:00
jxxghp
bd137de042 Merge pull request #1833 from honue/main 2024-04-05 22:47:46 +08:00
honue
4a2688b52f fix #1744 2024-04-05 22:22:41 +08:00
jxxghp
36acb1daaa Merge pull request #1832 from cddjr/fix_ua 2024-04-05 12:01:47 +08:00
景大侠
a0c3b6b26b fix: 站点User-Agent没有设置的情况下以系统设置的UA进行访问 2024-04-05 11:40:52 +08:00
jxxghp
7c93432505 Merge pull request #1815 from z3shan33/main 2024-04-02 09:26:19 +08:00
z3shan33
2760f25992 fix #1792 2024-04-02 09:24:43 +08:00
jxxghp
d199c47666 fix #1804 2024-04-02 08:22:12 +08:00
jxxghp
a6550a21ef Merge pull request #1804 from thsrite/main 2024-04-01 19:11:29 +08:00
thsrite
26a321f119 feat 设置订阅默认规则 2024-04-01 13:29:22 +08:00
jxxghp
7e8f7be905 v1.7.8
- 支持用户开启管理后台登录双重认证,增强安全性
- 管理后台的大部分表单均增加了hint提示信息
- 重启时会重新安装插件依赖,避免安装在线插件时依赖安装不成功的问题(此特性需要重拉镜像生效)
- 提升了框架对于插件错误的兼容性,插件市场插件按下载热度排序
2024-03-31 19:38:20 +08:00
jxxghp
600b6144e4 fix #1783 目录完整度匹配 2024-03-31 08:17:51 +08:00
jxxghp
dfb11420e5 Merge pull request #1789 from DDS-Derek/main 2024-03-30 17:44:22 +08:00
DDSRem
584c8a2d94 feat: install the plug-in pip extension in advance 2024-03-30 17:41:04 +08:00
jxxghp
536bd9268a feat:新增订阅相关事件 2024-03-30 08:04:52 +08:00
jxxghp
5ee41b87a2 fix login api 2024-03-29 11:13:57 +08:00
jxxghp
89b2fe10fe Merge pull request #1774 from jeblove/main 2024-03-28 21:33:16 +08:00
jeblove
c180e50164 feat: 增加session方法,用于获取tr的会话、配置信息 2024-03-28 21:24:16 +08:00
jxxghp
8f7b08afae fix #1763 2024-03-28 17:04:44 +08:00
jxxghp
72de8a2192 Merge pull request #1772 from z3shan33/main
feat #1763
2024-03-28 16:57:55 +08:00
zss
40d99f1dd5 feat #1763 2024-03-28 16:39:34 +08:00
jxxghp
ff07841dd6 roll back site test 2024-03-28 13:20:48 +08:00
jxxghp
828fc08362 Merge pull request #1766 from cddjr/1761--bug 2024-03-28 06:48:22 +08:00
景大侠
3fd043bb9b fix #1761 2024-03-28 02:09:47 +08:00
jxxghp
f51c4ebed7 fix bug 2024-03-27 20:46:06 +08:00
jxxghp
9b917cd4c2 更新 requirements.txt 2024-03-27 19:50:22 +08:00
jxxghp
91eac50ab9 v1.7.7
- 多别名搜索(`SEARCH_MULTIPLE_NAME`)默认为关,优化了站点无法连通时的搜索处理逻辑,加快搜索速度 - 修复了站点删除或重置后订阅等站点设置残留的问题 - `馒头`站点数据统计切换为使用ApiKey - 优化了Bangumi每日放送的演员阵容显示 - 插件支持显示下载安装次数
2024-03-27 17:01:33 +08:00
jxxghp
f6468ad327 fix scraper 2024-03-27 16:01:20 +08:00
jxxghp
fb6c3a9f36 fix site test 2024-03-27 15:45:27 +08:00
jxxghp
eb751bb581 fix site test 2024-03-27 15:35:01 +08:00
jxxghp
f9069bf19b fix #1758 2024-03-27 12:22:15 +08:00
jxxghp
ef0c88a3b6 fix 种子去重 2024-03-27 11:37:51 +08:00
jxxghp
f1f8ccb5d6 feat:plugins statistics 2024-03-27 08:24:06 +08:00
jxxghp
2df113ad38 fix SiteDeleted 2024-03-27 07:09:00 +08:00
jxxghp
fa03232321 Merge pull request #1759 from cddjr/fix_remove_site 2024-03-27 06:24:18 +08:00
景大侠
04f50284c6 fix 删除站点会导致其订阅的站点列表出现数字ID 2024-03-27 00:54:58 +08:00
jxxghp
9fc950c2ed Merge pull request #1751 from z3shan33/main 2024-03-26 16:41:59 +08:00
zss
9c1aeb933e fix bangumi中通过characters获取配音角色信息 2024-03-26 16:11:03 +08:00
jxxghp
1cee20134a fix 插件去重&排序 2024-03-26 09:30:05 +08:00
jxxghp
0ca5f5bd89 fix timeout 2024-03-25 23:06:30 +08:00
jxxghp
25e0c25bc6 fix timeout 2024-03-25 23:01:50 +08:00
jxxghp
3f8453f054 fix 2024-03-25 20:14:24 +08:00
jxxghp
cf259af2d1 feat:插件安装统计 2024-03-25 18:02:57 +08:00
jxxghp
0b70f74553 fix site test 2024-03-24 21:33:41 +08:00
jxxghp
f0bc5d737b - 问题修复 2024-03-24 15:45:20 +08:00
jxxghp
181d87f68e fix mtorrent 2024-03-24 15:31:00 +08:00
jxxghp
e37ac4da6a v1.7.6
- 馒头搜索切换为使用ApiKey,需要先在`控制台`->`实验室`建立存取令牌,手工维护站点cookie后ApiKey会自动获取并缓存使用,如更换了ApiKey,需要手动触发站点修改才会清除缓存。
- 资源搜索时整合多个别名的搜索结果,避免搜索不全

注意:馒头除搜索下载外,站点签到、数据统计、刷流等仍然使用cookie访问,请自行评估风险。
2024-03-24 14:01:20 +08:00
jxxghp
bd7ca7fa60 feat:m-team x-api-key 2024-03-24 13:38:36 +08:00
jxxghp
96de772119 fix mtorrent 2024-03-24 10:20:12 +08:00
jxxghp
72b6556c62 add SEARCH_MULTIPLE_NAME 2024-03-24 08:26:59 +08:00
jxxghp
e4bb182668 feat:搜索更多结果 2024-03-24 08:13:08 +08:00
jxxghp
595d097235 v1.7.5
- 认证站点新增支持青蛙🐸,蝴蝶🦋支持ipv4域名,适配了馒头新UI
- 加快了插件市场的加载速度
- 插件日志倒序显示
2024-03-23 19:01:09 +08:00
jxxghp
9b53aad34f fix mtorrent 2024-03-23 13:46:06 +08:00
jxxghp
e92a2e1ff1 Merge pull request #1728 from developer-wlj/wlj0323 2024-03-23 13:38:33 +08:00
mayun110
764359c3e8 fix 2024-03-23 13:18:36 +08:00
mayun110
abd1a51863 fix: labels by mTorrent 2024-03-23 12:26:49 +08:00
jxxghp
2f05f8dc4d fix mtorrent 2024-03-23 09:50:03 +08:00
jxxghp
23c678e71e fix mtorrent 2024-03-23 09:42:11 +08:00
jxxghp
ef67b76453 fix 下载消息显示用户名 2024-03-22 13:26:07 +08:00
jxxghp
c4e7870f7b Merge pull request #1726 from sundxfansky/main 2024-03-22 06:53:18 +08:00
jxxghp
9cef50436a Merge pull request #1725 from Vincwnt/main 2024-03-22 06:51:40 +08:00
sundxfansky
a15aded0a0 无需添加时间 2024-03-22 04:40:33 +08:00
chenyuan
8ac40dc205 fix: 存在已删除用户时, 消息批量推送失败bug 2024-03-21 22:27:01 +08:00
jxxghp
92a5b3d227 feat:线上插件多线程加载 2024-03-21 21:30:26 +08:00
jxxghp
761f1e7a4b feat:线上插件多线程加载 2024-03-21 21:27:54 +08:00
jxxghp
ad0731e1ec 更新 README.md 2024-03-21 18:27:36 +08:00
jxxghp
a451f12d86 add qingwa 2024-03-21 16:55:57 +08:00
jxxghp
dcde619e77 插件日志倒序 & 补充安装版本Windows指引 2024-03-21 16:28:16 +08:00
jxxghp
92769b27f1 v1.7.4
- 推荐增加了`Bangumi每日放送`
- `api.themoviedb.org`等域名会自动使用DOH解析IP地址,以避免DNS污染提升网络连通性(通过`DOH_ENABLE`变量控制,默认开)
- 站点浏览增加点击添加下载功能
- 优化了个别页面在数据多时的展示速度
2024-03-19 17:27:52 +08:00
jxxghp
fa83168b92 feat:增加DOH开关 2024-03-19 12:26:04 +08:00
jxxghp
f96295de3a add download api 2024-03-18 23:27:54 +08:00
jxxghp
6cecb3c6a6 fix bug 2024-03-18 20:02:03 +08:00
jxxghp
b6486035c4 add Bangumi 2024-03-18 19:02:34 +08:00
jxxghp
f7c1d28c0f remove cloudflared 2024-03-18 08:23:43 +08:00
jxxghp
47c2ae1c08 fix doh domains 2024-03-18 07:19:56 +08:00
jxxghp
c03f24dcf5 更新 doh.py 2024-03-17 23:40:19 +08:00
jxxghp
6e2f5762b4 add doh 2024-03-17 23:30:50 +08:00
jxxghp
75330a08cc add doh 2024-03-17 23:25:04 +08:00
jxxghp
3f17e371c3 add doh 2024-03-17 23:15:21 +08:00
jxxghp
a820341ec7 rollback cloudflared 2024-03-17 22:32:15 +08:00
jxxghp
c1f04f5631 Merge pull request #1697 from DDS-Derek/main 2024-03-17 19:06:31 +08:00
DDSRem
a121e45b94 fix: container resolv cannot be modified 2024-03-17 18:43:54 +08:00
DDSRem
885ee976b2 feat: better cloudflared install 2024-03-17 18:15:29 +08:00
jxxghp
e6229beb94 add cloudflared 2024-03-17 16:52:13 +08:00
jxxghp
f2a40e1ec3 fix themoviedb季不显示 2024-03-17 15:59:21 +08:00
jxxghp
5f80aa5b7c - 豆瓣订阅及本地CookieCloud服务问题修复 2024-03-17 15:12:24 +08:00
jxxghp
14ff1e9af6 fix resource 2024-03-17 15:09:10 +08:00
jxxghp
49ab5ac709 - 豆瓣订阅及本地CookieCloud服务问题修复 2024-03-17 13:43:11 +08:00
jxxghp
74c7a1927b fix cookiecloud 2024-03-17 13:42:01 +08:00
jxxghp
cbd704373c try fix cookiecloud 2024-03-17 12:57:38 +08:00
jxxghp
a05724f664 fix 自动校正站点地址格式 2024-03-17 12:21:32 +08:00
jxxghp
97d0fc046a fix 豆瓣订阅Bug 2024-03-17 11:27:54 +08:00
jxxghp
6248e34400 fix v1.7.3 2024-03-17 10:00:59 +08:00
jxxghp
a442dab85b fix nginx.conf 2024-03-17 09:51:04 +08:00
jxxghp
d4514edba6 v1.7.3
- `捷径`新增消息中心功能
- 内建支持CookieCloud本地化服务器,Cookie数据加密后保存在用户配置目录中,可在`设定`-`站点`中选择开启
- 优化了推荐详情页面,豆瓣推荐详情直接展示豆瓣数据源
- 修复了`蜜柑`无法搜索的问题
2024-03-17 09:09:21 +08:00
jxxghp
0c581565ad 更新 message.py 2024-03-16 22:21:12 +08:00
jxxghp
350def0a6f 更新 message.py 2024-03-16 22:20:14 +08:00
jxxghp
5b3027c0a7 fix reload 2024-03-16 21:06:52 +08:00
jxxghp
e4b90ca8f7 fix #1694 2024-03-16 20:40:02 +08:00
jxxghp
d917b00055 Merge pull request #1694 from lingjiameng/main
CookieCloud配置支持实时更新
2024-03-16 20:36:05 +08:00
s0mE
cc94c6c367 Merge branch 'jxxghp:main' into main 2024-03-16 19:24:25 +08:00
ljmeng
6410051e3a CookieCloud配置支持实时加载 2024-03-16 19:23:06 +08:00
jxxghp
aaa1b80edf fix 资源包更新Bug 2024-03-16 18:38:25 +08:00
jxxghp
f345d94009 fix README.md 2024-03-16 18:28:09 +08:00
jxxghp
550fe26d76 Merge pull request #1693 from lingjiameng/main
集成CookieCloud服务器端
2024-03-16 17:52:49 +08:00
jxxghp
7ad498b3a3 fix 2024-03-16 17:06:24 +08:00
jxxghp
20eb0b4635 fix message 2024-03-16 16:29:14 +08:00
ljmeng
747dc3fafe 默认关闭本地CookieCloud服务 2024-03-16 15:40:10 +08:00
s0mE
4708fbb3cb Merge branch 'jxxghp:main' into main 2024-03-16 15:36:20 +08:00
ljmeng
6ba40edeb4 Merge branch 'main' of github.com:lingjiameng/MoviePilot 2024-03-16 15:35:02 +08:00
ljmeng
79cb28faf9 默认配置关闭本地cookiecloud服务 2024-03-16 15:34:46 +08:00
jxxghp
9acf05f334 fix #1691 2024-03-16 15:31:04 +08:00
jxxghp
d0af1bf075 Merge pull request #1691 from hoey94/main 2024-03-16 13:53:10 +08:00
hoey94
f8a95cec4a fix: TR远程控制插件限速问题 104 2024-03-16 12:37:21 +08:00
jxxghp
3cd672fa8d fix 2024-03-16 08:40:36 +08:00
jxxghp
fe03638552 fix api 2024-03-16 08:39:57 +08:00
ljmeng
1ae220c654 集成CookieCloud服务端 2024-03-16 04:48:34 +08:00
jxxghp
75c7e71ee6 Merge pull request #1689 from hoey94/main 2024-03-15 19:14:26 +08:00
hoey94
4619158b99 fix: 限速开关BUG 104 2024-03-15 18:23:44 +08:00
jxxghp
3f88907ba9 fix bug 2024-03-15 18:17:04 +08:00
jxxghp
ae6440bd0a Merge pull request #1683 from lingjiameng/main 2024-03-15 07:55:01 +08:00
s0mE
261f5fc0c6 Merge branch 'jxxghp:main' into main 2024-03-14 23:26:58 +08:00
jxxghp
a5d044d535 fix message 2024-03-14 20:36:15 +08:00
jxxghp
6e607ca89f fix 优化推荐跳转
feat 消息落库
2024-03-14 19:44:15 +08:00
jxxghp
06e4b9ad83 Merge remote-tracking branch 'origin/main' 2024-03-14 19:15:22 +08:00
jxxghp
c755dc9b85 fix 优化推荐跳转
feat 消息落库
2024-03-14 19:15:13 +08:00
jxxghp
209451d5f9 Merge pull request #1678 from HankunYu/main 2024-03-14 06:57:31 +08:00
HankunYu
60b2d30f42 Update README.md
增加使用反代的描述,解决使用https反代时日志加载时间过长(十几分钟)不可用的问题。
2024-03-13 18:54:55 +00:00
ljmeng
399d26929d CookieCloud改为本地解密,增强安全性 2024-03-14 02:35:22 +08:00
jxxghp
f50c2e59a9 fix #1674 2024-03-13 14:54:37 +08:00
jxxghp
1cd768b3d0 v1.7.2
- 站点索引新增支持`蟹黄堡`,修复了`蝴蝶`、`蜜柑`的索引问题
- 针对themoviedb被大量删除中文标题的问题,补充使用新加坡(zh-sg)中文标题搜索和刮削
- 支持设定识别元数据的缓存时间(`META_CACHE_EXPIRE`,单位小时)
- 修复了未设定anime分类策略时,原tv下动漫二级分类失效的问题
- 提升了插件升级的使用体验
2024-03-13 08:21:59 +08:00
jxxghp
abc26b65ed fix #1645 兼容蝴蝶种子链接格式 2024-03-12 17:01:41 +08:00
jxxghp
dc1a41da90 fix 减少不必要的检测 2024-03-12 13:48:37 +08:00
jxxghp
a95dac1b32 fix 目录检测 2024-03-12 13:36:33 +08:00
jxxghp
18d9620687 #1653 搜索词中加入新加坡标题,同时主标题不是中文时会考虑使用中文新加坡标题 2024-03-12 11:55:47 +08:00
jxxghp
8808dcee52 fix 1659 2024-03-12 11:16:10 +08:00
jxxghp
17adc4deab Merge pull request #1662 from thsrite/main 2024-03-11 16:36:19 +08:00
thsrite
9351489166 fix 不查缓存识别媒体信息也应更新最新信息到缓存 2024-03-11 16:34:53 +08:00
jxxghp
e2148cb77f fix 2024-03-11 16:28:36 +08:00
jxxghp
e322204094 Merge pull request #1661 from jeblove/main 2024-03-11 16:25:05 +08:00
jxxghp
0fa884157a 支持设定meta缓存时间 2024-03-11 16:23:07 +08:00
jeblove
96468213fe Merge branch 'main' of https://github.com/jeblove/MoviePilot 2024-03-11 16:17:36 +08:00
jeblove
d044a9db00 fix 继续观看部分剧集图片 2024-03-11 16:17:10 +08:00
jxxghp
d5f5e0d526 Merge pull request #1660 from thsrite/main 2024-03-11 15:59:20 +08:00
thsrite
14a3bb8fc2 add db订阅、下载历史根据类型和时间查询列表(插件方法) 2024-03-11 15:56:19 +08:00
jxxghp
5921d43ae8 fix #1655 2024-03-11 12:34:19 +08:00
jxxghp
635061c054 Merge pull request #1654 from jeblove/main 2024-03-11 11:32:27 +08:00
jeblove
3c8c6e5375 fix 语法问题 2024-03-11 11:27:24 +08:00
jeblove
dd063bb16b fix 播放剧集微信消息推送图片问题 2024-03-11 01:57:57 +08:00
jeblove
750711611b fix 语法问题 2024-03-11 00:15:55 +08:00
jxxghp
d3983c51c2 Merge pull request #1652 from jeblove/main 2024-03-10 18:39:16 +08:00
jeblove
b9dec73773 fix 语法问题 2024-03-10 18:10:09 +08:00
jeblove
b310367d25 fix 播放微信消息推送图片问题 2024-03-10 17:50:01 +08:00
jxxghp
55beea87fd Merge pull request #1649 from thsrite/main 2024-03-10 11:24:57 +08:00
thsrite
4510382f74 fix tv动漫分类不生效 2024-03-10 09:27:48 +08:00
jxxghp
9b9ae9401e fix bug 2024-03-09 21:33:59 +08:00
jxxghp
e10464c278 v1.7.1
- 动漫独立目录时支持二级分类(category.yml配置模板已更新)
- 支持同时启用两个下载器,但只有第1个才会被默认使用(官方插件库个别插件进行了适配升级)
- 实时日志的最新日志显示在最顶部
- 优化了下载器及媒体目录的健康检查
- 优化了版本升级后因为浏览器缓存一直加载中的问题
- 优先级规则新增支持`官种`
- 修复了普通用户无法查看下载中任务的问题
- 修复了设定中修改定时服务相关设置时不立即生效的问题
2024-03-09 21:20:36 +08:00
jxxghp
542531a1ca fix yyyymmdd期 识别 2024-03-09 21:13:23 +08:00
jxxghp
04c21232e3 fix yyyymmdd期 识别 2024-03-09 21:03:29 +08:00
jxxghp
48a19fd57c fix 下载器测试 2024-03-09 20:03:57 +08:00
jxxghp
59cb69a96b Merge pull request #1643 from jeblove/main 2024-03-09 19:39:31 +08:00
jeblove
e7d94f7f70 fix 对接Library/VirtualFolders接口参数 2024-03-09 19:03:02 +08:00
jxxghp
27d2d01a20 feat:下载器支持多选 2024-03-09 18:52:27 +08:00
jxxghp
8b4495c857 feat:下载器支持多选 2024-03-09 18:25:04 +08:00
jxxghp
15bdb694cc fix 优化部分消息格式 2024-03-09 17:43:21 +08:00
jxxghp
3ef9c5ea2c fix 优化部分消息格式 2024-03-09 17:34:49 +08:00
jxxghp
ab6577f752 fix #1561 2024-03-09 17:12:21 +08:00
jxxghp
49a82d7a48 feat:新增官种优先级规则
fix #1635
feat:动漫支持二级目录 fix #1633
2024-03-09 09:53:15 +08:00
jxxghp
bdcbb168a0 Merge pull request #1636 from HankunYu/main 2024-03-09 08:05:49 +08:00
HankunYu
2e1cb0bd76 fix #1630
这里混淆了remove_tags与delete_tags。将原来的remove tags函数更正为delete,并新增一个remove tags函数。
2024-03-08 18:23:42 +00:00
jxxghp
851864cd49 fix 定时服务立即生效
fix #1615
2024-03-08 16:22:53 +08:00
jxxghp
b5d7b6fb53 fix 订阅全局通知 2024-03-08 15:38:40 +08:00
jxxghp
92bab2fc2f fix 下载全局通知 2024-03-08 15:27:24 +08:00
jxxghp
0dad6860c4 fix 下载任务userid登记 2024-03-08 14:40:00 +08:00
jxxghp
de4a7becc2 Merge pull request #1620 from thsrite/main 2024-03-08 11:58:52 +08:00
thsrite
2eeb24e22d fix 不开下载器监控,link测试无意义 2024-03-08 09:29:30 +08:00
jxxghp
e4a67ea052 - 修复了健康检查themoviedb、thetvdb时未使用内置代理的问题
- 修复了VoceChat部分场景下消息发送失败的问题
- 修复了VoceChat响应干扰了微信回调的问题
- 提升了VoceChat的安全性,机器人Webhook需要参考说明重新设置

注意:VoceChat机器人Webhook回调地址相对路径调整为:`/api/v1/message/?token=moviepilot`,其中`moviepilot`为环境变量中设置的`API_TOKEN`
2024-03-07 18:22:17 +08:00
jxxghp
a4df2f5213 fix wechat bug 2024-03-07 18:15:04 +08:00
jxxghp
4f89780a0f Merge remote-tracking branch 'origin/main' 2024-03-07 18:01:57 +08:00
jxxghp
26d6201b30 fix wechat bug 2024-03-07 18:01:50 +08:00
jxxghp
c9a9ff2692 Merge pull request #1613 from WangEdward/main 2024-03-07 17:48:31 +08:00
Edward
0be49953b4 fix: change vote to float 2024-03-07 09:45:14 +00:00
jxxghp
0de952f090 fix 2024-03-07 17:15:04 +08:00
jxxghp
2b570bf48f fix:提升VoceChat安全性 2024-03-07 17:07:28 +08:00
jxxghp
9476017af5 Merge remote-tracking branch 'origin/main' 2024-03-07 12:43:05 +08:00
jxxghp
54f808485e fix #1608 2024-03-07 12:42:59 +08:00
jxxghp
fa5c82899b Merge pull request #1605 from HankunYu/main
Update 中文字幕过滤
2024-03-07 12:33:06 +08:00
HankunYu
4a57071809 Update 中字过滤规则
添加匹配小写
2024-03-07 02:48:29 +00:00
HankunYu
4631db9a45 Update 中字过滤规则
去除重复 简体, 严格CHT以及CHS匹配规则
2024-03-07 02:43:59 +00:00
jxxghp
0f09da55b0 Merge pull request #1606 from thsrite/main 2024-03-07 09:22:21 +08:00
thsrite
b14b41c2c1 fix 系统健康检查tmdb、tvdb走代理 2024-03-07 09:20:20 +08:00
jxxghp
cf05ae20c5 v1.7.0
- 捷径中增加了系统健康检查功能,可快速检测各模块连接状态、目录是否跨盘等
- 网络测试增加了`fanart`和`thetvdb`测试项
- 新增`短剧自动分类`插件,可根据视频文件时长将短剧整理到独立分类目录
- 通知消息新增支持`VoceChat`,可实现消息交互以及群组通知功能,需自行搭建服务端
- 修复了订阅集数修改后会被覆盖的问题,订阅默认规则增加了做种数设定

VoceChat搭建及配置参考:https://doc.voce.chat/zh-cn/bot/bot-and-webhook ,Webhook回调地址相对路径为:/api/v1/message/
2024-03-07 08:10:52 +08:00
HankunYu
897758d829 Merge remote-tracking branch 'upstream/main' 2024-03-06 19:54:39 +00:00
jxxghp
85a77a66dd fix 2024-03-06 22:26:36 +08:00
HankunYu
c450dfc0fa Update 中文字幕过滤
添加对于动画番剧中文字幕识别的支持
2024-03-06 14:09:19 +00:00
jxxghp
3d782a7475 feat:目录检测 2024-03-06 21:42:21 +08:00
jxxghp
4734851213 Merge pull request #1587 from WangEdward/main 2024-03-06 20:11:10 +08:00
jxxghp
9c8635002d Merge pull request #1603 from thsrite/main 2024-03-06 19:50:33 +08:00
thsrite
4cd3cb2b60 fix 2024-03-06 19:46:09 +08:00
thsrite
fa890ca29c fix 手动修改过订阅总集数后,不再随tmdb变化 2024-03-06 19:33:31 +08:00
jxxghp
bbf1ec4c50 fix bug 2024-03-06 17:19:32 +08:00
jxxghp
523d458489 fix bug 2024-03-06 17:02:07 +08:00
jxxghp
45ec668875 add log 2024-03-06 16:47:04 +08:00
jxxghp
60122644b8 fix 2024-03-06 16:20:39 +08:00
jxxghp
07a77e0001 fix 2024-03-06 16:04:04 +08:00
jxxghp
d112f49a69 feat:支持VoceChat 2024-03-06 15:54:40 +08:00
jxxghp
8cb061ff75 feat:模块健康检查 2024-03-06 13:23:51 +08:00
jxxghp
01e08c8e69 Merge pull request #1595 from richard-guan-dev/main
fix: Add a validation check to see if "assisted verification users" are active when logging in.
2024-03-06 10:44:44 +08:00
Richard Guan
3549b38ee8 Add validation for whether the assistive user is activated. 2024-03-06 10:38:20 +08:00
jxxghp
f5fb888c85 fix #1594 2024-03-06 08:19:08 +08:00
Edward
8bcb6a7cb6 chore: merge nested if 2024-03-05 09:35:34 +00:00
Edward
ac81dd943c feat: add min_seeders in filter_rule 2024-03-05 09:25:23 +00:00
jxxghp
663d282b5e fix category.yaml 2024-03-05 15:54:13 +08:00
jxxghp
c7b389dd9b v1.6.9
- 索引站点支持`青蛙`
- 优化了种子索引匹配逻辑,减少`类型不匹配`的错误
- 修复了订阅默认过滤规则不生效的问题
2024-03-04 20:29:15 +08:00
jxxghp
bad37a1846 Merge pull request #1572 from WangEdward/main 2024-03-01 23:01:54 +08:00
jxxghp
9c09981583 Merge pull request #1571 from sohunjug/main 2024-03-01 22:47:46 +08:00
Edward
2d8e66cbe2 fix: site scope error 2024-03-01 14:40:50 +00:00
sohunjug
db28986d22 fix: softlink exists 2024-03-01 22:14:07 +08:00
Edward
727bed46b7 fix: empty return from get_subscribed_sites 2024-03-01 14:06:58 +00:00
jxxghp
8e0df90177 Merge pull request #1570 from DDS-Derek/main 2024-03-01 21:55:32 +08:00
DDSRem
34bbb86c16 fix: plugin directory backup failed 2024-03-01 21:40:46 +08:00
jxxghp
0403f1f48c fix logging 2024-03-01 13:10:19 +08:00
jxxghp
1db452e268 Merge pull request #1568 from cikezhu/main
fix time_difference()
2024-02-29 21:49:20 +08:00
叮叮当
81ca11650d fix time_difference() 2024-02-29 21:39:32 +08:00
jxxghp
2e4671fdbc Merge remote-tracking branch 'origin/main' 2024-02-29 17:28:42 +08:00
jxxghp
da80ad33d9 fix bug 2024-02-29 17:28:36 +08:00
jxxghp
a6f28569ab Merge pull request #1567 from sundxfansky/main 2024-02-29 17:20:45 +08:00
jxxghp
5dd36e95e0 feat:使用站点种子归类优化识别匹配
fix:优先级规则复杂时,过滤时间很长,调整到最后
fix #1432
2024-02-29 17:18:01 +08:00
sundxfansky
1eaeea62db rm line 2024-02-29 16:58:18 +08:00
sundxfansky
4282c5dfc2 fix update failed 2024-02-29 16:56:33 +08:00
jxxghp
2e661f8759 Merge pull request #1566 from sundxfansky/main 2024-02-29 06:48:15 +08:00
tonser
31ca41828e 修复tr 选中种子下载失败 2024-02-29 02:09:53 +08:00
jxxghp
c9ebe76eb1 - 修复v1.6.8订阅失效问题 2024-02-28 23:19:10 +08:00
jxxghp
71ac12ab7a 更新 scheduler.py 2024-02-28 23:03:31 +08:00
jxxghp
81c0e15a1c 更新 version.py 2024-02-28 22:19:12 +08:00
jxxghp
2bde4923f9 更新 subscribe.py 2024-02-28 21:57:35 +08:00
jxxghp
22fb6305cf 更新 subscribe.py 2024-02-28 21:50:32 +08:00
jxxghp
4bb5772e10 fix #1545
fix #1537
2024-02-28 15:03:55 +08:00
jxxghp
549658e871 fix #1553
fix #1496
2024-02-28 14:18:23 +08:00
jxxghp
80f47594f4 v1.6.8
- `🌈岛`支持多域名及HR检测,支持`麒麟`的短剧搜索
- 修复了做种数大于1000时识别为0的问题
- 官方插件库的所有插件均可在`设定-服务`中查看和启动后台任务(需要更新到最新插件版本,第三方插件需要开发者适配)
- 新增`共享识别词`插件(感谢@honuee),搭建了识别词共享服务,欢迎大家共同维护使用

1. 插件开发说明:https://github.com/jxxghp/MoviePilot-Plugins/blob/main/README.md
2. 识别词共享地址:
- https://movie-pilot.org/etherpad/p/MoviePilot_TV_Words
- https://movie-pilot.org/etherpad/p/MoviePilot_Anime_Words
2024-02-26 19:33:00 +08:00
jxxghp
2614eeadb0 fix #1544 2024-02-26 10:50:33 +08:00
jxxghp
a0af827319 Merge pull request #1541 from WangEdward/main 2024-02-25 23:48:08 +08:00
jxxghp
0233853794 fix bug 2024-02-25 17:16:46 +08:00
jxxghp
6b24ccdc35 fix bug 2024-02-25 16:43:21 +08:00
jxxghp
7d76ee2e65 fix warning 2024-02-25 09:11:47 +08:00
jxxghp
1dd9228d01 fix warning 2024-02-25 09:03:43 +08:00
Edward
a5b4221a00 fix: db migration for search_imdbid 2024-02-24 09:36:04 +00:00
jxxghp
37ba75b53c Merge pull request #1535 from cikezhu/main 2024-02-24 06:46:43 +08:00
WangEdward
b8553e2b86 feat: add search_imdbid in subscribe api 2024-02-24 00:14:44 +08:00
WangEdward
d28f3ed74b feat: add search_imdbid for subscribe 2024-02-23 23:55:32 +08:00
叮叮当
185c78b05c 定时作业添加提供者条目 2024-02-23 22:25:41 +08:00
叮叮当
f23cab861a fix 获取其他待执行任务>status 2024-02-23 21:39:58 +08:00
叮叮当
bbddec763a 插件直接采用程序的定时任务模块, 可显示在前端页面 2024-02-23 18:13:27 +08:00
jxxghp
06c3985aa4 v1.6.7
- 加快了插件页面的展现速度
- 插件的日志独立保存和查看
- 站点索引新增支持`萝莉`,支持`AGSVPT`的短剧搜索,修复了`象站`的索引问题
2024-02-23 10:59:20 +08:00
jxxghp
9503a603e6 fix 2024-02-23 08:23:56 +08:00
jxxghp
6e9ab24d95 Merge pull request #1531 from cikezhu/main 2024-02-23 07:59:40 +08:00
叮叮当
7524379af6 增加条件减少循环次数 2024-02-23 01:15:11 +08:00
叮叮当
eebf3dec68 fix 日志恢复成文件名方式/插件调用内置模块的日志将会显示在插件日志 2024-02-22 23:54:25 +08:00
jxxghp
a89dd636a4 fix #1528 2024-02-22 17:59:44 +08:00
jxxghp
7fb025bff4 Merge pull request #1529 from honue/main 2024-02-22 17:34:55 +08:00
honue
c44c0f6321 自定义识别词#注释 认为为注释 2024-02-22 17:22:40 +08:00
jxxghp
585bcb924f Merge pull request #1526 from WangEdward/main 2024-02-22 15:49:50 +08:00
jxxghp
0ce3c3d90f Merge pull request #1522 from honue/main 2024-02-22 15:48:32 +08:00
Edward
9cb69f4879 fix: discuz is_logged_in 2024-02-22 15:34:48 +08:00
honue
c5b13f2fee fix #1502 2024-02-22 14:06:56 +08:00
jxxghp
235af9e558 fix bug 2024-02-22 13:31:49 +08:00
jxxghp
cb274d1587 feat:插件日志文件独立 2024-02-22 13:23:23 +08:00
jxxghp
63643e6d26 feat:插件API支持类型过滤 2024-02-21 16:11:15 +08:00
jxxghp
0726600936 feat:插件API支持类型过滤 2024-02-21 16:05:24 +08:00
jxxghp
6151bd64dd Merge remote-tracking branch 'origin/main' 2024-02-21 16:00:00 +08:00
jxxghp
32dc0f69f9 feat:插件API支持类型过滤 2024-02-21 15:59:53 +08:00
jxxghp
5b563cf173 Merge pull request #1515 from WangEdward/main 2024-02-21 15:18:38 +08:00
Edward
3dbb534883 fix: 2fa Nonetype 2024-02-21 05:42:35 +00:00
jxxghp
7304fad460 Merge remote-tracking branch 'origin/main' 2024-02-21 13:36:32 +08:00
jxxghp
9f829c2129 fix #1514 2024-02-21 13:31:19 +08:00
jxxghp
32e71beca8 Merge pull request #1507 from donniex1986/patch-1 2024-02-20 19:09:29 +08:00
donniex1986
3c1c04f356 Update README.md 2024-02-20 18:21:25 +08:00
jxxghp
c473594663 v1.6.6
- IYUU Api域名地址更改为`api.bolahg.cn`
- 消息交互支持洗版订阅和强制重新下载
- 历史记录删除源文件时自动删除下载器中的下载任务
- 文件管理支持英文标题占位符`en_title`
- 更新了多个官方插件,其中目录监控插件修复了蓝光原盘目录整理重复通知的问题

【消息交互示例】
- 订阅 XXX:添加订阅
- 洗版 XXX:添加洗版订阅
- 搜索/下载 XXX:不检查本地是否存在,重新搜索下载
2024-02-20 16:40:28 +08:00
jxxghp
a8ce9648e2 fix bug 2024-02-20 16:18:29 +08:00
jxxghp
760285b085 Merge pull request #1503 from DDS-Derek/main
feat: startup and update script optimization
2024-02-20 15:09:18 +08:00
jxxghp
ccdad3e8dc fix #1502 2024-02-20 15:07:55 +08:00
jxxghp
f33e9bee21 Merge pull request #1502 from honue/main
当插件状态未启用时,设置事件注册状态不可用
2024-02-20 14:58:00 +08:00
jxxghp
4183dca80f fix bug 2024-02-20 14:41:25 +08:00
DDSRem
6f6fd6a42e fix: bug 2024-02-20 14:38:36 +08:00
DDSRem
13bb31fd93 fix: bug 2024-02-20 14:35:19 +08:00
DDSRem
5bac94cbc5 fix: bug 2024-02-20 14:34:29 +08:00
DDSRem
daa8d80ec9 feat: startup and update script optimization
1. 修复Shellcheck指出的问题,增强脚本稳定性。
2. 对于更新部分:采取先更新主程序和前端,插件和资源包再更新的原则;主要解决如果插件或资源包没有下载成功,主程序就无法更新成功的问题,但是其实资源包和插件是不影响主程序更新的。

Co-Authored-By: DDSDerek <108336573+DDSDerek@users.noreply.github.com>
Co-Authored-By: Summer⛱ <57806936+honue@users.noreply.github.com>
2024-02-20 14:26:59 +08:00
honue
b095f01b09 当插件状态未启用时,设置事件注册状态不可用 2024-02-20 13:27:02 +08:00
jxxghp
f43efab831 Merge pull request #1501 from honue/main 2024-02-20 11:44:29 +08:00
honue
946b7905b3 fix 总集数减小时,不能正确更新元数据 2024-02-20 11:34:40 +08:00
jxxghp
544625a9a3 fix bug 2024-02-19 18:03:35 +08:00
jxxghp
d7c6c27679 feat:消息交互支持洗版订阅及全量重新下载
fix #1202
2024-02-19 17:47:20 +08:00
jxxghp
70adbfe6b5 fix #1334 2024-02-19 16:20:03 +08:00
jxxghp
d8f9ab93e5 feat:源文件删除时删除下载任务 fix #1391 2024-02-19 16:07:46 +08:00
jxxghp
e06d07937e fix 2024-02-19 15:55:57 +08:00
jxxghp
f94d248383 Merge pull request #1492 from WangEdward/main
feat: english title from tmdb
2024-02-18 16:31:13 +08:00
Edward
c139aeebf5 feat: title search include en_title 2024-02-18 07:41:49 +00:00
Edward
89a8625817 feat: english title from tmdb 2024-02-18 07:40:59 +00:00
jxxghp
59acda5dec fix #1380
fix #1373
fix #1404
2024-02-18 11:26:05 +08:00
jxxghp
57d9e4a370 fix #1347 2024-02-18 11:20:04 +08:00
jxxghp
8b6a2a3d99 fix #1382 2024-02-18 10:53:13 +08:00
jxxghp
3e10642bdd v1.6.5
- 认证站点新增支持`麒麟`
- 修复了一个设定保存后无法启动的问题
2024-02-18 09:50:07 +08:00
jxxghp
c8e63b6ae0 Merge pull request #1489 from WangEdward/main 2024-02-17 19:47:11 +08:00
Edward
03c92ad41c fix: search_area 错误删除
resolve #1051
2024-02-17 11:33:59 +00:00
jxxghp
690b454bb1 fix api 2024-02-17 13:24:41 +08:00
jxxghp
2e6c1bef63 Merge pull request #1482 from WangEdward/main 2024-02-17 00:45:54 +08:00
jxxghp
0fd428f809 Merge pull request #1485 from cikezhu/main 2024-02-17 00:45:20 +08:00
叮叮当
6083a8a859 fix 更新站点图标 2024-02-16 20:35:03 +08:00
Edward
bb7d262ea3 feat: m-team 2fa 2024-02-15 16:39:14 +00:00
Edward
ca9a37d12a fix: 2fa 变量名冲突 2024-02-15 16:19:20 +00:00
jxxghp
595ca631f4 Merge pull request #1480 from WangEdward/main 2024-02-15 22:02:19 +08:00
jxxghp
cbffddc57f 更新 wechat.py 2024-02-15 21:51:57 +08:00
jxxghp
a5f5d41104 更新 transmission.py 2024-02-15 21:51:23 +08:00
jxxghp
56f07b3dd6 更新 telegram.py 2024-02-15 21:50:57 +08:00
jxxghp
fba10fe6a0 更新 synologychat.py 2024-02-15 21:50:16 +08:00
jxxghp
5639e0b7d0 更新 qbittorrent.py 2024-02-15 21:49:34 +08:00
jxxghp
a6ad58ca33 更新 plex.py 2024-02-15 21:49:03 +08:00
jxxghp
00447f2475 更新 emby.py 2024-02-15 21:48:11 +08:00
jxxghp
9d14fc47fe 更新 jellyfin.py 2024-02-15 21:47:52 +08:00
jxxghp
70c459f810 更新 emby.py 2024-02-15 21:47:01 +08:00
Edward
a0af2f4b68 fix: tmdb 同名返回已订阅 2024-02-15 13:45:29 +00:00
jxxghp
603eefb22f v1.6.4 2024-02-15 21:30:49 +08:00
jxxghp
34625ee384 feat:调整设置项内容结构 2024-02-15 20:40:01 +08:00
jxxghp
ca78fb7c22 fix api 2024-02-15 19:54:16 +08:00
jxxghp
3c710dd266 fix api 2024-02-15 19:46:30 +08:00
jxxghp
514e7add4b fix api 2024-02-15 18:57:24 +08:00
jxxghp
bdbf1e9084 fix api 2024-02-15 16:56:48 +08:00
jxxghp
6149cef1d3 fix api 2024-02-15 15:03:37 +08:00
jxxghp
b8fac86c6e feat:错误变量类型兼容 2024-02-15 13:28:52 +08:00
jxxghp
9f450dd8be fix settings api 2024-02-15 08:39:55 +08:00
jxxghp
24c2d3f8ca fix twofa 2024-02-14 21:11:35 +08:00
jxxghp
4248b8fa4e fix:多域名站点CookieCloud同步重复Bug 2024-02-14 21:10:08 +08:00
jxxghp
deaa2e5644 Merge pull request #1478 from WangEdward/main 2024-02-14 18:53:10 +08:00
Edward
dc43aabe2a fix 2fa helper 2024-02-14 08:51:20 +00:00
Edward
02981d38c0 chore 重命名 2fa 参数名 2024-02-14 08:47:55 +00:00
Edward
85fd9b3c09 feat 为 update_cookie 增加 2fa 支持 2024-02-14 08:47:02 +00:00
Edward
39ad54f3d9 feat 新增 2fa helper 2024-02-14 05:30:41 +00:00
jxxghp
aa9a2c46aa merge cookiecloud chain 2024-02-13 10:36:05 +08:00
jxxghp
c43a1411c9 fix 手动维护站点时缓存站点图标 2024-02-13 10:18:27 +08:00
jxxghp
928aaf0c19 Merge pull request #1474 from WangEdward/main 2024-02-12 15:19:03 +08:00
Edward
ea8a4a3ec4 fix: 支持 Radarr 的 X-Api-Key 请求头 2024-02-12 04:43:21 +00:00
jxxghp
c4dc468479 fix 增加插件库缓存 2024-02-11 22:02:03 +08:00
jxxghp
87ddfbca90 Merge remote-tracking branch 'origin/main' 2024-02-11 21:35:19 +08:00
jxxghp
164ce8f7c4 fix #984 2024-02-11 21:35:11 +08:00
jxxghp
c2fd6e3342 合并拉取请求 #1471
fix 后端程序目录不正确/其他目录被映射时mv会失败
2024-02-11 21:07:01 +08:00
jxxghp
16b79754c3 v1.6.3
- 文件管理支持手动削刮媒体文件
- 集成apexcharts,插件支持绘制图表
- 站点数据统计插件增加今日流量饼图
- 文件重命名兼容特殊字符
- 修复了资源包下载失败时无法启动的问题
2024-02-11 08:40:15 +08:00
叮叮当
9cfb1f789f fix 后端程序目录不正确/其他目录被映射时mv会失败 2024-02-11 02:18:35 +08:00
jxxghp
e3faa388cf fix 连不上Github可能导致无法启动的问题 2024-02-10 20:38:34 +08:00
jxxghp
b75ec92368 fix #1422 2024-02-10 20:35:07 +08:00
jxxghp
f91763ef7c add scrape api 2024-02-10 19:30:41 +08:00
jxxghp
edf8b03d3b Merge pull request #1464 from cikezhu/main
让自定义站点可自行设置: 搜索结果条数/请求超时
2024-02-10 11:30:25 +08:00
jxxghp
ea48eb5c56 fix update 2024-02-10 11:07:42 +08:00
jxxghp
282f723d34 fix plugin api 2024-02-10 10:58:43 +08:00
叮叮当
dde3b76573 让自定义站点可自行设置: 搜索结果条数/请求超时 2024-02-09 22:45:58 +08:00
jxxghp
f571711386 v1.6.2
- 支持更灵活的密码设置
- 支持在新窗口中打开实时日志
- 新增实时硬链接、二级分类策略、下载任务分类与标签、清理硬链接等插件
- 修复了ChineseSubFinder插件无法下载电影字幕的问题
- 前端集成了ace-builds,支持基于路径的反向代理
2024-02-09 11:23:24 +08:00
jxxghp
e8e8d36a13 fix logger 2024-02-09 09:43:35 +08:00
jxxghp
782a9a4759 fix logger 2024-02-09 09:42:49 +08:00
jxxghp
d0184bd34c fix logger 2024-02-09 09:35:05 +08:00
jxxghp
e4c0643c39 fix bug 2024-02-08 20:50:41 +08:00
jxxghp
305c08c7dd fix category 2024-02-08 14:42:38 +08:00
jxxghp
9521a3ef09 Merge remote-tracking branch 'origin/main' 2024-02-08 08:35:25 +08:00
jxxghp
b4c6a206af fix password 2024-02-08 08:35:18 +08:00
jxxghp
fa7eeec345 Merge pull request #1460 from cikezhu/main 2024-02-08 07:15:34 +08:00
叮叮当
7350216fc4 新窗口打开全部日志 2024-02-08 00:09:20 +08:00
jxxghp
36122dda31 Merge pull request #1454 from WangEdward/main 2024-02-07 21:11:58 +08:00
Edward
5851673b43 fix: 重新整理成功移动 2024-02-06 21:07:57 +08:00
Edward
0d81105a0b fix: 历史记录中重新整理成功记录时的问题 2024-02-06 18:05:45 +08:00
jxxghp
b934b0975b Merge pull request #1437 from falling/main 2024-02-01 13:55:37 +08:00
falling
035b4b0608 正在下载的任务状态更新 2024-02-01 12:03:09 +08:00
jxxghp
b98a033cd2 v1.6.1
- 更改IYUU认证及辅种服务器地址
2024-01-30 17:24:49 +08:00
jxxghp
c69853ce4b Merge pull request #1428 from EkkoG/debug_step 2024-01-30 16:14:19 +08:00
EkkoG
e00a440336 修正按 README 中步骤本地运行时提示 No module named 'app' 2024-01-30 15:31:18 +08:00
jxxghp
c0eb6b0600 Merge pull request #1423 from EkkoG/fixed_size_limit 2024-01-29 16:38:09 +08:00
EkkoG
4d1c8c3764 Fixed #1416 2024-01-29 16:24:23 +08:00
jxxghp
62628e526c 更新 README.md 2024-01-24 11:45:33 +08:00
jxxghp
ad7761a785 rollback #1399 2024-01-24 10:56:39 +08:00
jxxghp
e545b8d900 Merge pull request #1399 from falling/main 2024-01-23 07:12:12 +08:00
falling
f2f1ecfdf1 更新qbittorrent下载判断值
https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-torrent-list
pausedDL	Torrent is paused and has NOT finished downloading
2024-01-21 19:51:38 +08:00
jxxghp
fdec997ed0 更新 app.env 2024-01-19 23:00:07 +08:00
jxxghp
9b653ceec9 更新 README.md 2024-01-19 22:58:21 +08:00
jxxghp
fbaaed1c61 更新 message.py 2024-01-19 22:55:45 +08:00
jxxghp
639abf67c2 v1.6.0
- 全新安装时,超级管理员初始密码为随机生成,并只能在首次启动的后台日志中查看(使用初始密码登录成功后可在设定中修改)。
- 用户密码修改需要同时包含大小写和数字。
- 修复了第三个插件依赖库无法自动安装的问题。
2024-01-19 11:20:30 +08:00
jxxghp
1f56ceaea9 更新 user.py 2024-01-19 10:54:13 +08:00
jxxghp
16a4f61fec Merge pull request #1386 from hussion/dev 2024-01-19 10:52:10 +08:00
jxxghp
ea0aba96fd Merge pull request #1383 from thsrite/main 2024-01-19 10:51:31 +08:00
嫣识
4393dad77c fix:修复bearer auth请求头设置错误,导致github_token参数应用失败 2024-01-18 19:58:06 +08:00
jxxghp
d099c0e702 更新 README.md 2024-01-18 12:05:12 +08:00
thsrite
a299d786fe feat 超级管理员初始化密码随机生成 && 修改密码强制要求大写小写数字组合 2024-01-18 11:08:16 +08:00
jxxghp
3500f5b9a6 Merge pull request #1378 from thsrite/main 2024-01-18 08:22:16 +08:00
thsrite
64233c89d7 fix emby/jellyfin首页继续观看、最近添加兼容共享路径 2024-01-17 16:59:22 +08:00
jxxghp
8c727da58a Merge pull request #1375 from thsrite/main 2024-01-17 12:06:03 +08:00
thsrite
152a87d109 fix 解决三方插件依赖安装失败 2024-01-17 10:14:49 +08:00
jxxghp
6a2cde0664 - Bug修复 2024-01-16 20:24:58 +08:00
jxxghp
c86cc2cb51 Merge pull request #1353 from thsrite/main 2024-01-12 19:04:14 +08:00
thsrite
6d7a63ff61 fix c044e594 2024-01-12 10:07:39 +08:00
thsrite
c044e59481 fix emby/jellyfin首页继续观看、最近添加 2024-01-12 09:56:55 +08:00
jxxghp
3c31bf24e5 v1.5.9
- 修复了个别情况下订阅重复下载的问题
- 仪表板中继续观看和最近添加组件支持过滤媒体库黑名单内容
- 增加了Fanart的开关设置(FANART_ENABLE,默认开),关闭后可减少网络请求但刮削图片数量会大幅减少
2024-01-11 20:18:58 +08:00
jxxghp
d89c80ac89 fix #1296 2024-01-11 16:35:51 +08:00
jxxghp
8236d6c8d7 Merge pull request #1328 from thsrite/main 2024-01-10 12:25:19 +08:00
thsrite
3646540a7f fix 2024-01-10 11:21:03 +08:00
thsrite
c1ecdfc61d Revert "fix #907"
This reverts commit 4dcefb141a.
2024-01-10 11:19:25 +08:00
thsrite
7587946d51 fix c674e320 2024-01-10 10:53:32 +08:00
jxxghp
3ad64baaeb 更新 README.md 2024-01-10 10:38:43 +08:00
jxxghp
24c43b53a2 Merge pull request #1338 from thsrite/fanart_switch 2024-01-10 10:29:59 +08:00
thsrite
53a6a1c691 feat Fanart开关支持环境变量配置,默认开启 2024-01-10 10:13:51 +08:00
jxxghp
c3ba83c7ca fix:订阅重复下载问题 2024-01-09 13:16:39 +08:00
jxxghp
d9b349873e v1.5.8
- 修复了启用内置代理时媒体组件无法显示图片的问题
- 优化媒体组件用户匹配,优先展示媒体服务器中同名用户的信息
- 用户认证失败时发送消息提醒
- UI主题支持跟随系统主题自动切换
2024-01-08 13:18:34 +08:00
thsrite
4dcefb141a fix #907 2024-01-08 13:05:48 +08:00
thsrite
c674e32046 fix 首页继续观看、最近添加排除黑名单媒体库 2024-01-08 13:05:09 +08:00
jxxghp
8aa1027aae fix image proxy 2024-01-08 12:24:00 +08:00
jxxghp
b4cb9c3fb3 fix 2024-01-07 18:24:13 +08:00
jxxghp
d82ab5d60d feat:用户认证失败时发送消息提醒 2024-01-07 12:10:51 +08:00
jxxghp
979b636eec fix bug 2024-01-07 11:51:49 +08:00
jxxghp
bf8a75b201 fix:优化emby、jellyfin用户匹配 2024-01-07 11:46:29 +08:00
jxxghp
87111c8736 fix exists api 2024-01-06 11:20:08 +08:00
jxxghp
9b97e478aa - 修复Plex媒体图片展示与跳转 2024-01-06 10:59:46 +08:00
jxxghp
2af7abee3c fix #1320 2024-01-06 08:46:18 +08:00
jxxghp
2c8a41ebad fix #1316 2024-01-06 08:31:07 +08:00
jxxghp
c632cfd6b9 - 优化媒体组件的图片代理 2024-01-05 21:40:21 +08:00
jxxghp
7f05df2fb3 fix count 2024-01-05 21:37:19 +08:00
jxxghp
ff33432809 fix api 2024-01-05 21:35:01 +08:00
jxxghp
0a57e69bcf v1.5.7
- 媒体服务器支持配置外网播放地址,媒体详情支持跳转在线播放
- `设定-订阅`中增加了文件大少过滤规则,以及控制订阅时是否立即弹出编辑框的选项(默认关闭)
- 仪表板显示的组件支持自定义,同时增加了媒体库相关面板组件
- 支持插件将定时作业任务注册到主程序,以在`设定-服务`中统一管理
2024-01-05 20:47:53 +08:00
jxxghp
7af8b15dbb fix apis 2024-01-05 20:31:15 +08:00
jxxghp
bc4931d971 fix api 2024-01-05 20:21:19 +08:00
jxxghp
cfb029b6b4 fix api 2024-01-05 15:58:47 +08:00
jxxghp
6fa50101a6 Merge pull request #1314 from thsrite/main 2024-01-05 13:00:38 +08:00
thsrite
843fbc83f4 fix 集如果带有.会刮削错误 2024-01-05 12:53:47 +08:00
jxxghp
55f8fb3b66 Merge pull request #1313 from thsrite/main 2024-01-05 11:52:39 +08:00
thsrite
a47774472d fix bug 2024-01-05 11:50:05 +08:00
jxxghp
713f4ca356 fix typo 2024-01-05 08:18:01 +08:00
jxxghp
b06795510a feat:插件支持注册公共服务 2024-01-05 08:12:27 +08:00
jxxghp
0f57ec099a Merge remote-tracking branch 'origin/main' 2024-01-04 20:54:46 +08:00
jxxghp
8325caabdc fix api 2024-01-04 20:53:59 +08:00
jxxghp
44d276d7e7 Merge pull request #1305 from honue/main 2024-01-04 07:08:07 +08:00
honue
935340561b package获取失败,增加日志warn 2024-01-03 22:34:01 +08:00
jxxghp
a60fde3b91 fix 2024-01-03 21:29:23 +08:00
jxxghp
163a855d5c fix play url api 2024-01-03 18:38:40 +08:00
jxxghp
c9b1e75361 fix 2024-01-03 18:07:48 +08:00
jxxghp
a9932d0866 fix 2024-01-03 17:40:13 +08:00
jxxghp
11d29919bf feat:大小过滤 2024-01-03 17:28:11 +08:00
jxxghp
4fe755332d fix bug 2024-01-03 12:42:47 +08:00
jxxghp
0095e0f4dd feat:播放跳转api 2024-01-03 12:02:08 +08:00
jxxghp
322c72ab54 feat:mediaserver apis 2024-01-02 20:54:54 +08:00
jxxghp
4d51459a47 v1.5.6
- 修复了插件重复显示的问题
- 站点资源支持显示免费剩余时间和H&R标志(仅部分站点)
- 刷流插件升级,支持排除H&R

提示:涉及前端改动时,可能需要清理浏览器缓存才能显示更新内容
2024-01-01 20:18:20 +08:00
jxxghp
d51de30898 Merge remote-tracking branch 'origin/main' 2024-01-01 19:44:08 +08:00
jxxghp
90f9edbf24 fix bug 2024-01-01 19:43:55 +08:00
jxxghp
8aa10457a7 Merge pull request #1294 from honue/main 2024-01-01 15:46:09 +08:00
honue
ab584720c6 fix 本地插件未安装,但不在市场显示的情况(v2) 2024-01-01 15:33:13 +08:00
jxxghp
56ad281cb6 feat:4X 2024-01-01 11:56:03 +08:00
jxxghp
61281cca02 feat:免费剩余时间 && HR 2024-01-01 10:22:18 +08:00
jxxghp
b53dbbc38e rollback #1287 2023-12-31 10:36:09 +08:00
jxxghp
3f88cfba28 fix #1287 2023-12-31 10:34:21 +08:00
jxxghp
e855d8b9af - 修复了1PTBA无法认证的问题
- 修复了个别情况下仍有一集缺失时提前完成订阅的问题
- 修复了电影订阅本地已存在时不完成订阅的问题
- 优化了资源搜索、订阅日历、历史记录界面
2023-12-31 09:56:46 +08:00
jxxghp
171720e629 fix bug 2023-12-31 09:41:02 +08:00
jxxghp
8aa6b33fba v1.5.5
- 修复了1PTBA无法认证的问题
- 修复了个别情况下仍有一集缺失时提前完成订阅的问题
- 修复了电影订阅本地已存在时不完成订阅的问题
- 优化了资源搜索、订阅日历、历史记录界面
2023-12-31 08:54:54 +08:00
jxxghp
505fc803db fix README.md 2023-12-31 08:46:38 +08:00
jxxghp
b5146620a6 fix #1266 2023-12-31 08:38:54 +08:00
jxxghp
7d44f24347 fix #1276 2023-12-31 08:21:58 +08:00
jxxghp
4dccc6e860 Merge pull request #1287 from honue/main 2023-12-29 21:30:34 +08:00
honue
ee6585c737 fix 本地插件未安装,但不在市场显示的情况 2023-12-29 18:32:01 +08:00
jxxghp
62e5e8a69f Merge pull request #1279 from thsrite/main 2023-12-25 17:08:13 +08:00
thsrite
e942a99ff0 fix bug 2023-12-25 15:30:10 +08:00
jxxghp
b3fe49684b fix bug 2023-12-23 19:51:35 +08:00
jxxghp
dcf1985361 - 修复了未设置订阅站点时无法编辑订阅的问题
- 历史记录支持过滤状态
2023-12-23 19:32:34 +08:00
jxxghp
8f4f4cc004 fix #1215 2023-12-23 18:49:01 +08:00
jxxghp
f49baadb76 fix #1225 2023-12-23 18:24:07 +08:00
jxxghp
5233484fc5 Merge pull request #1265 from honue/main 2023-12-20 07:57:29 +08:00
Summer⛱
84c4cc8b5d Update .gitignore 2023-12-19 17:36:58 +08:00
jxxghp
77036eccd8 v1.5.3 2023-12-17 10:59:27 +08:00
jxxghp
dcdb08ec80 feat:路径识别支持到3级 2023-12-17 10:59:02 +08:00
jxxghp
cd7f688e78 feat:刮削模块支持覆盖 2023-12-17 10:49:00 +08:00
jxxghp
cb12a052ac - 修复历史记录重新整理时路径不正确的问题 2023-12-16 12:21:22 +08:00
jxxghp
995c359f20 Merge pull request #1234 from thsrite/main 2023-12-14 06:28:50 +08:00
jxxghp
690066ad32 - 修复整理时不自动创建目标路径的问题 2023-12-13 06:53:11 +08:00
thsrite
73942e315a feat 订阅增加保存路径设置 2023-12-12 14:01:14 +08:00
jxxghp
48badb3243 Merge pull request #1228 from EkkoG/fixed_move_failed_msg 2023-12-11 19:31:19 +08:00
EkkoG
d5eb12cc4e 修复无法入库消息发送到 Telegram 时格式异常 2023-12-11 17:51:21 +08:00
jxxghp
7d7539df4c - 目录监控、手动整理等不指定目的目录时,不再强制创建一级分类目录,根据开关判定是否创建二级分类目录 2023-12-11 17:24:34 +08:00
jxxghp
14a8f44f8c fix bug 2023-12-10 18:51:20 +08:00
jxxghp
a7be470f33 v1.5.0 2023-12-10 17:49:05 +08:00
jxxghp
a677169f60 fix #1219 指定转移目录时不强制添加一级分类目录 2023-12-10 17:48:14 +08:00
jxxghp
b72ef4f2aa fix #1139 洗版重复下载问题 2023-12-10 17:27:34 +08:00
jxxghp
403054751b Merge remote-tracking branch 'origin/main' 2023-12-10 13:35:01 +08:00
jxxghp
b3e5c734d4 add ffmpeg 2023-12-10 13:34:54 +08:00
jxxghp
5732125ff6 Merge pull request #1221 from Vincwnt/main 2023-12-10 11:52:53 +08:00
林晓昱
eb66cf7aad fix 自定义识别词的媒体type正则bug 2023-12-10 11:34:39 +08:00
jxxghp
a317c35eab fix 集图片命名 2023-12-06 13:08:15 +08:00
jxxghp
ab138560c1 v1.4.9 2023-12-06 10:55:31 +08:00
jxxghp
f0fbad889d - 偿试修复可执行文件打包插件数据表缺失问题 2023-12-05 20:57:53 +08:00
jxxghp
1323cd5dc6 fix 插件下载Bug 2023-12-04 17:27:33 +08:00
jxxghp
2c43d8e145 fix 插件下载Bug 2023-12-04 16:58:39 +08:00
jxxghp
0214beb679 - 修复二进制打包插件表缺失的问题 2023-12-04 11:33:16 +08:00
jxxghp
7d73cdef33 Merge remote-tracking branch 'origin/main' 2023-12-04 11:03:00 +08:00
jxxghp
fcfab2c750 feat 命名增加豆瓣ID/识别英文名称 2023-12-04 11:02:53 +08:00
jxxghp
e048be17a5 Merge pull request #1195 from WithdewHua/fix-mediaserver 2023-12-02 12:47:20 +08:00
WithdewHua
024f1de4f1 fix: 清空 MediaServerItem 表 2023-12-02 12:31:38 +08:00
jxxghp
d2c9f7a778 更新 README.md 2023-12-01 18:39:40 +08:00
jxxghp
1784d2ec61 v1.4.8 2023-12-01 10:51:49 +08:00
jxxghp
8f4a213f55 fix QB&TR 判重 2023-12-01 08:12:06 +08:00
jxxghp
6a8c684af0 feat 兼容TR下载任务重复添加 2023-11-30 15:58:44 +08:00
jxxghp
aefba83319 fix 2023-11-30 13:35:26 +08:00
jxxghp
e411f4062a feat 兼容QB下载任务重复添加 2023-11-30 13:14:55 +08:00
jxxghp
3c6802860d fix #1186 2023-11-30 11:19:43 +08:00
jxxghp
3daad5ea90 Merge pull request #1186 from honue/main 2023-11-30 11:08:00 +08:00
jxxghp
6835c38c24 Merge remote-tracking branch 'origin/main' 2023-11-30 08:16:30 +08:00
honue
32be9b71d5 Merge remote-tracking branch 'origin/main' 2023-11-30 07:42:19 +08:00
honue
84bc0e0fb4 fix 2023-11-30 07:41:58 +08:00
Summer⛱
8105dc9c82 Merge branch 'jxxghp:main' into main 2023-11-30 00:42:23 +08:00
honue
840c968454 tr增加修改tracker方法 2023-11-30 00:39:57 +08:00
honue
8c5f19a0f4 fix 2023-11-30 00:39:35 +08:00
jxxghp
bf813aa906 Merge pull request #1181 from honue/main 2023-11-29 13:29:40 +08:00
honue
e5ac7f10d4 update downloader init 2023-11-29 13:23:28 +08:00
jxxghp
d049e04fa2 v1.4.7 2023-11-29 13:13:58 +08:00
jxxghp
ef45b08ee5 Merge pull request #1180 from honue/main 2023-11-29 13:01:18 +08:00
honue
d77644ab16 fix singleton.py 2023-11-29 12:46:49 +08:00
jxxghp
1a90b4a3cb v1.4.7 2023-11-29 12:39:37 +08:00
jxxghp
9e5d401a85 remove plugin_color 2023-11-29 12:07:54 +08:00
jxxghp
6da6dc2b8c Merge pull request #1178 from cikezhu/main 2023-11-29 08:43:26 +08:00
叮叮当
2ca7021df0 fix item_id 2023-11-29 08:35:44 +08:00
jxxghp
1682cdad37 fix README.md 2023-11-28 14:55:05 +08:00
jxxghp
ec5e898feb fix app.env 2023-11-27 08:36:45 +08:00
jxxghp
ccf6fb1b36 fix 插件重置 2023-11-27 08:30:13 +08:00
jxxghp
83c8d619d0 fix README.md 2023-11-27 08:17:23 +08:00
jxxghp
dd5b8219a1 更新 plugin.py 2023-11-27 07:09:38 +08:00
jxxghp
34fd927972 更新 README.md 2023-11-26 22:50:43 +08:00
jxxghp
6db5ad2697 feat:插件重置 2023-11-26 21:40:43 +08:00
jxxghp
0be1f27970 - 修复了种子失效时订阅一直偿试下载的问题
- 新增配置中心插件,可快速调整配置
2023-11-26 20:16:44 +08:00
jxxghp
54603798fc fix bug 2023-11-24 15:26:54 +08:00
jxxghp
2f1e947323 fix #1144 2023-11-24 15:24:38 +08:00
jxxghp
ef2cfe1c1d fix #1141 修复错误种子链接一直偿试下载的问题 2023-11-24 14:32:56 +08:00
jxxghp
f8edf79c59 fix api doc 2023-11-24 14:00:52 +08:00
jxxghp
dec80b6567 fix 2023-11-23 17:25:54 +08:00
jxxghp
4dac9237ef fix README.md 2023-11-23 17:22:13 +08:00
jxxghp
12f5f373b3 fix frozen 2023-11-23 10:59:33 +08:00
jxxghp
76472770bf v1.4.5 2023-11-22 15:35:12 +08:00
jxxghp
f5baf77c3c Merge pull request #1155 from thsrite/main 2023-11-22 13:42:33 +08:00
thsrite
126276c727 fix #1154 2023-11-22 13:39:39 +08:00
jxxghp
5d6ba83fc5 Merge pull request #1153 from thsrite/main 2023-11-22 09:23:19 +08:00
thsrite
047c3b596d add 插件方法 2023-11-22 09:21:51 +08:00
jxxghp
2240ff08a1 fix 插件事件依赖 2023-11-22 07:25:00 +08:00
jxxghp
4d6bf56fa0 fix bug 2023-11-21 21:44:50 +08:00
jxxghp
10ad9a5601 fix bug 2023-11-21 21:20:02 +08:00
jxxghp
fb39500428 feat 优化插件仓库URL格式 2023-11-21 21:10:34 +08:00
jxxghp
615a52cef9 更新 build.yml 2023-11-20 21:53:38 +08:00
jxxghp
791be0583a fix build 2023-11-20 20:14:07 +08:00
jxxghp
a324731061 - 优化豆瓣详情展示 2023-11-20 20:06:25 +08:00
jxxghp
539d9cf537 - 优化豆瓣详情展示 2023-11-20 20:01:04 +08:00
jxxghp
699312ff28 - 优化豆瓣详情展示 2023-11-20 19:56:52 +08:00
jxxghp
b92b0ec149 fix build 2023-11-20 19:54:41 +08:00
jxxghp
51536062f1 fix 2023-11-20 16:43:49 +08:00
jxxghp
4c230b4c1e feat 清理缓存时清理种子缓存 2023-11-20 10:56:28 +08:00
jxxghp
a7752ceb17 fix bug 2023-11-19 09:48:06 +08:00
jxxghp
ed59a90d78 fix update timeout 2023-11-19 09:45:13 +08:00
jxxghp
11d65e7527 fix douban scraper 2023-11-19 09:05:58 +08:00
jxxghp
b6ac5f0f84 feat 完善豆瓣详情API 2023-11-18 22:37:23 +08:00
jxxghp
c336e62885 Merge remote-tracking branch 'origin/main' 2023-11-18 21:54:10 +08:00
jxxghp
b868cdb25e feat 完善豆瓣详情API 2023-11-18 21:53:58 +08:00
jxxghp
04339539d1 fix bug 2023-11-17 14:25:00 +08:00
jxxghp
2d146880ec fix 2023-11-17 13:36:23 +08:00
jxxghp
6eec4ef7f4 fix build 2023-11-17 12:27:43 +08:00
jxxghp
9841f3dd18 fix build 2023-11-17 11:43:01 +08:00
jxxghp
03e0118fb7 add linux frozen build 2023-11-17 11:39:03 +08:00
jxxghp
c7c222b357 v1.4.3 2023-11-17 11:12:52 +08:00
jxxghp
2d8e45cd1b feat TG消息重试 2023-11-17 10:41:14 +08:00
jxxghp
e2bd5cc245 更新 resource.py 2023-11-16 21:10:21 +08:00
jxxghp
47ddfec30e feat 资源包自动更新 2023-11-16 20:57:41 +08:00
jxxghp
9344b2a324 add AGSVPT 2023-11-16 17:27:58 +08:00
jxxghp
8496fcccc5 Merge pull request #1133 from honue/main 2023-11-16 14:59:50 +08:00
honue
c6fa3b9d25 fix torrent_cache ttl 2023-11-16 13:34:23 +08:00
jxxghp
ce13987748 - 修复Windows打包 2023-11-15 08:20:57 +08:00
jxxghp
5221fc4f6a fix #1125 2023-11-15 08:08:46 +08:00
jxxghp
d4dc388d3f fix search 2023-11-14 17:54:41 +08:00
jxxghp
42966c2537 fix #1122 2023-11-14 17:35:31 +08:00
jxxghp
7921dcd86b Merge pull request #1122 from thsrite/main 2023-11-14 17:30:52 +08:00
thsrite
4c69bb6c48 fix 2023-11-14 16:22:04 +08:00
thsrite
0aad809c82 feat 增加GITHUB_TOKEN,提高API限流阈值 2023-11-14 16:12:02 +08:00
thsrite
f514a5a416 fix 793a7460 2023-11-14 14:17:14 +08:00
thsrite
793a7460c6 fix 动漫电影 剧场版 2023-11-14 14:10:48 +08:00
jxxghp
6dcc979fd5 fix #1072
fix #1118
2023-11-14 08:19:57 +08:00
jxxghp
5a07732712 fix 豆瓣已订阅显示 2023-11-13 20:25:57 +08:00
jxxghp
61d71b32ff fix 豆瓣已订阅显示 2023-11-13 20:22:51 +08:00
jxxghp
ba62ca3d18 - 文件整理支持仅保留最新版本文件(转移覆盖模式设为:latest
- 重启时会识别用户已安装过但本地不存在的插件并自动下载安装,避免升级重置后第三方插件消失的问题
2023-11-13 12:11:43 +08:00
jxxghp
612271bf0c fix 缺失状态识判 2023-11-13 12:00:53 +08:00
jxxghp
3b99fb5c96 fix #1109 2023-11-12 19:10:46 +08:00
jxxghp
bb61f8197c fix #1110 2023-11-12 19:01:25 +08:00
jxxghp
b54f04a35b fix #1110 2023-11-12 18:51:24 +08:00
jxxghp
d47639bada fix #1110 2023-11-12 18:51:08 +08:00
jxxghp
ae9bab2981 Merge pull request #1110 from thsrite/update
fix 重启或重置后三方插件丢失问题
2023-11-12 18:44:45 +08:00
thsrite
2116b094ad fix 三方插件丢失问题 2023-11-11 23:40:39 -06:00
jxxghp
288883a13b feat 文件整理支持仅保留最新版本 2023-11-12 08:03:15 +08:00
jxxghp
07c988abae fix transfer message 2023-11-12 07:21:57 +08:00
jxxghp
fd4a3b5671 fix bug 2023-11-11 15:23:10 +08:00
jxxghp
71adfad94d fix bug 2023-11-11 14:57:38 +08:00
jxxghp
7faaaf3dcd fix bug 2023-11-11 14:14:09 +08:00
jxxghp
25e7db5ac9 fix seerr api 2023-11-11 12:20:27 +08:00
jxxghp
07bd5f1926 fix seerr api 2023-11-11 12:16:45 +08:00
jxxghp
9439d02351 fix TMDB缓存None的问题 2023-11-11 10:37:33 +08:00
jxxghp
cbea7ccdf6 fix TMDB缓存None的问题 2023-11-11 10:34:49 +08:00
jxxghp
93661dfde4 v1.4.1 2023-11-10 22:23:13 +08:00
jxxghp
b98f5351cf fix #1098 2023-11-10 21:56:38 +08:00
jxxghp
83a7261fcd fix #1101 2023-11-10 21:54:45 +08:00
jxxghp
daa2b7a8cd feat 部分API支持api token访问 2023-11-10 21:40:24 +08:00
jxxghp
d245fedb3f fix api token 2023-11-10 20:51:09 +08:00
jxxghp
b0fee2cb3c add token verify 2023-11-10 17:31:19 +08:00
jxxghp
9a102056d8 fix douban rank 2023-11-10 12:23:03 +08:00
jxxghp
3905463940 fix douban mode 2023-11-09 23:44:08 +08:00
jxxghp
746fde592d fix douban mode 2023-11-09 23:22:38 +08:00
jxxghp
3e5f5554da fix bug 2023-11-09 21:47:22 +08:00
jxxghp
01fb6e8772 fix bug 2023-11-09 21:15:36 +08:00
jxxghp
b7448232e6 fix bug 2023-11-09 19:56:56 +08:00
jxxghp
05f1a24199 feat 支持豆瓣做为识别源 2023-11-09 17:32:26 +08:00
jxxghp
4072799c13 fix #1064 2023-11-06 11:29:43 +08:00
jxxghp
9744032f93 Merge remote-tracking branch 'origin/main' 2023-11-06 08:14:13 +08:00
jxxghp
eb9a92d76d v1.4.0 2023-11-06 08:06:57 +08:00
jxxghp
89a4932823 fix plugin get_state 2023-11-05 21:20:27 +08:00
jxxghp
cef06a8894 fix message event 2023-11-05 08:41:45 +08:00
jxxghp
c741edffb0 fix 2023-11-04 07:52:48 +08:00
jxxghp
e7c543fcb9 feat 第三方插件支持依赖 2023-11-04 07:31:14 +08:00
jxxghp
2a61720b0a Merge pull request #1052 from DDS-Derek/main 2023-11-03 19:00:06 +08:00
DDSRem
73484647ba feat: optimize restart update 2023-11-03 18:33:53 +08:00
jxxghp
c9d461f8c8 更新 update 2023-11-03 12:46:29 +08:00
jxxghp
9bdc056359 fix time 2023-11-03 12:29:38 +08:00
jxxghp
6a8a1e799d fix 同步用户提权Bug 2023-11-03 12:19:05 +08:00
jxxghp
c3c55f3a13 - 修复插件事件重复执行的问题 2023-11-03 09:13:37 +08:00
jxxghp
6f881a80d6 - 修复插件事件重复执行的问题 2023-11-03 09:13:18 +08:00
jxxghp
a75c4110a8 fix #1047 2023-11-03 07:51:42 +08:00
jxxghp
3e031c6191 fix #1047 2023-11-03 07:28:34 +08:00
jxxghp
a4b7ca824e v1.3.9-1 2023-11-02 17:50:31 +08:00
jxxghp
ecab2b63c9 fix #1044 2023-11-02 17:42:52 +08:00
jxxghp
620e3d55d1 fix 插件更新不立即生效的问题 2023-11-02 13:38:50 +08:00
jxxghp
3716d7fd47 fix bug 2023-11-02 12:35:25 +08:00
jxxghp
60764d198a Merge remote-tracking branch 'origin/main' 2023-11-02 12:27:36 +08:00
jxxghp
3178d9da88 fix update 2023-11-02 12:27:30 +08:00
jxxghp
7264313c9c 更新 README.md 2023-11-02 11:52:51 +08:00
jxxghp
71c36881fb fix update 2023-11-02 11:47:24 +08:00
jxxghp
5a0f7ae838 fix 2023-11-02 11:29:48 +08:00
jxxghp
10fb61bd57 fix repo cache 2023-11-02 11:20:11 +08:00
jxxghp
6d4b4c6ba7 fix bug 2023-11-02 11:06:37 +08:00
jxxghp
798a737f06 fix 在线插件去重(以后面的为准) 2023-11-02 11:00:49 +08:00
jxxghp
0a9e125f89 feat 支持ptvicomo认证 2023-11-02 10:18:32 +08:00
jxxghp
21b3525f23 v1.3.9 2023-11-02 08:29:23 +08:00
jxxghp
8e842c385d fix bug 2023-11-02 08:19:41 +08:00
jxxghp
8e8a587bca fix bug 2023-11-02 08:12:36 +08:00
jxxghp
155aa2580b fix build 2023-11-02 07:51:17 +08:00
jxxghp
01aa381848 fix timeout 2023-11-02 00:06:10 +08:00
jxxghp
6c13fa02c1 fix update 2023-11-02 00:04:46 +08:00
jxxghp
c50576b508 fix update 2023-11-01 22:48:52 +08:00
jxxghp
7bc4a6906a fix README.md 2023-11-01 22:17:58 +08:00
jxxghp
c80318f442 fix py修改不生效问题 2023-11-01 22:08:43 +08:00
jxxghp
cd4229a915 fix bug 2023-11-01 22:05:48 +08:00
jxxghp
fbe306ba90 feat 在线仓库插件安装 2023-11-01 20:56:38 +08:00
jxxghp
0dac3f1b1d fix gitignore 2023-11-01 17:58:48 +08:00
jxxghp
7a90e6c1a7 fix update 2023-11-01 17:49:52 +08:00
jxxghp
42a4a8639d fix README.md 2023-11-01 17:45:46 +08:00
jxxghp
a687642a6a fix update 2023-11-01 17:33:00 +08:00
jxxghp
dbba7fc92a feat 拆分资源包 2023-11-01 17:27:17 +08:00
jxxghp
a0afd86b6a fix update 2023-11-01 16:56:57 +08:00
jxxghp
22b76f9919 feat 拆分插件仓库 2023-11-01 16:50:53 +08:00
jxxghp
c7a869b750 feat 媒体库刷新移植为插件 2023-11-01 16:20:15 +08:00
jxxghp
00052efbbc feat 媒体服务器通知插件 2023-11-01 15:53:45 +08:00
jxxghp
a36332581a add helper 2023-11-01 15:25:30 +08:00
jxxghp
8c81e6ae02 add platform 2023-11-01 14:13:41 +08:00
jxxghp
a7285f2b1a add versions 2023-11-01 12:23:24 +08:00
jxxghp
271b33ecdc Merge pull request #1034 from thsrite/main 2023-11-01 12:08:53 +08:00
thsrite
b4d07cf6ab fix 2023-11-01 12:06:05 +08:00
thsrite
382035768e fix 兼容emby webhook删除season没有tmdbid 2023-11-01 11:51:07 +08:00
jxxghp
fcb825c1e2 Merge pull request #1033 from honue/main 2023-11-01 11:43:09 +08:00
honue
abfeea63f7 fix README.md 2023-11-01 11:39:21 +08:00
jxxghp
b0ce7e6531 fix resources 2023-11-01 11:37:23 +08:00
honue
303aa9b580 fix rss报文设置编码问题 2023-11-01 11:30:26 +08:00
jxxghp
d016d239e3 fix README.md 2023-11-01 10:08:53 +08:00
jxxghp
e35838c326 Merge remote-tracking branch 'origin/main' 2023-11-01 10:08:47 +08:00
jxxghp
de15f9b56e fix README.md 2023-11-01 10:08:40 +08:00
jxxghp
560773a11a Merge pull request #1030 from Shurelol/main 2023-11-01 08:35:37 +08:00
Ma
dd6df471dc fix 2023-11-01 07:43:49 +08:00
Ma
eea5c056f3 fix 2023-11-01 07:34:48 +08:00
Ma
a2d503b2f5 fix #1029 2023-11-01 07:29:53 +08:00
jxxghp
cf13e4a4fa Merge pull request #1028 from thsrite/main 2023-10-31 16:55:53 +08:00
thsrite
45fb8e86bf fix webhook 2023-10-31 16:39:20 +08:00
thsrite
099dcda185 fix webhook 2023-10-31 16:33:48 +08:00
thsrite
c07e12cc5a fix webhook 2023-10-31 15:37:39 +08:00
jxxghp
b23f78e94d v1.3.8 2023-10-31 11:50:18 +08:00
jxxghp
812a9a55d0 fix Plugin Alerts UI 2023-10-31 11:48:36 +08:00
jxxghp
2e289e80d1 fix 2023-10-31 10:37:36 +08:00
jxxghp
0d3dfdcbda feat 服务增加清理缓存 2023-10-31 10:32:56 +08:00
jxxghp
87eae72f51 fix #1024 2023-10-31 07:08:28 +08:00
jxxghp
17fa7101bd fix so 2023-10-30 13:35:19 +08:00
jxxghp
312bd53079 fix #1012 2023-10-29 16:08:34 +08:00
jxxghp
4bc7d47576 Merge pull request #1012 from Shurelol/main 2023-10-29 15:56:34 +08:00
Shurelol
71445b56f1 feat: 名称识别支持tmdbid等标记 2023-10-29 13:49:08 +08:00
jxxghp
9ce9e0a4ef fix #1006 2023-10-28 20:27:48 +08:00
jxxghp
ae196f1aeb Merge pull request #1006 from thsrite/main
fix bug
2023-10-28 20:27:25 +08:00
thsrite
38e09b894d fix bug 2023-10-28 20:24:16 +08:00
jxxghp
247d5ff255 Merge pull request #999 from honue/main
enhance 定期清理插件
2023-10-28 20:20:28 +08:00
jxxghp
0091e462fa Merge pull request #1004 from thsrite/main
fix 下载进度推送username
2023-10-28 20:19:12 +08:00
thsrite
7b314970b5 fix 下载进度推送username 2023-10-28 19:47:27 +08:00
jxxghp
7ac881e3e3 Merge pull request #1003 from thsrite/main 2023-10-28 19:31:29 +08:00
thsrite
8874723632 fix 认证失败后插件站点缺失bug 2023-10-28 19:14:08 +08:00
thsrite
262bda94c4 fix 目录监控入库消息延迟支持自定义 2023-10-28 18:52:46 +08:00
honue
d6e2cab5ef 兼容1.3.7版本清理插件配置 2023-10-28 18:40:27 +08:00
Summer⛱
6d3e33a05d Merge branch 'main' into main 2023-10-28 18:30:01 +08:00
jxxghp
f2d0bec0ac fix README 2023-10-28 17:46:57 +08:00
jxxghp
dea78f4bfd fix 2023-10-28 17:45:28 +08:00
jxxghp
f85f4b1342 Merge pull request #1000 from WithdewHua/qb
feat: qb 支持强制继续
2023-10-28 17:45:03 +08:00
WithdewHua
d03771f8ab feat: qb 支持强制继续 2023-10-28 17:41:31 +08:00
jxxghp
4b655dfac4 fix #957
fix #982
2023-10-28 17:41:22 +08:00
honue
cdfcdd80bf fix 2023-10-28 17:16:59 +08:00
honue
64d3942ba9 enhance 定期清理插件 2023-10-28 17:11:48 +08:00
jxxghp
16cce73f82 Merge pull request #996 from honue/main 2023-10-28 13:15:36 +08:00
honue
846edff84a fix 豆瓣榜单插件 2023-10-28 13:13:06 +08:00
jxxghp
d038bf31d3 Merge pull request #995 from honue/main 2023-10-28 12:41:50 +08:00
honue
376a69af5c fix 豆瓣榜单插件 2023-10-28 12:36:06 +08:00
jxxghp
380bb9bb3d Merge pull request #994 from thsrite/main 2023-10-28 12:26:27 +08:00
thsrite
f59e10ae1d fix qb按顺序下载支持变量配置 2023-10-28 12:24:24 +08:00
jxxghp
c8d2d80cc5 feat 支持配置多个认证站点 2023-10-28 11:50:50 +08:00
jxxghp
f0bb9ddfca Merge pull request #993 from thsrite/main
fix 目录监控消息电影不用等待直接发送入库消息
2023-10-28 11:46:23 +08:00
thsrite
9ab86e4a85 fix 目录监控消息电影不用等待直接发送入库消息 2023-10-28 11:41:44 +08:00
jxxghp
e33f1a3ffc Merge pull request #992 from thsrite/main
fix plugin api
2023-10-28 11:28:36 +08:00
jxxghp
e2213e1ef6 fix 远程搜索选择序号问题 2023-10-28 11:25:24 +08:00
thsrite
bbc4a1bfa5 fix plugin api 2023-10-28 11:22:37 +08:00
jxxghp
61e7ec9a36 Merge pull request #991 from honue/main 2023-10-28 11:06:25 +08:00
jxxghp
534ad0bad6 Merge pull request #987 from thsrite/main 2023-10-28 11:04:21 +08:00
thsrite
db3040a50e fix 2023-10-28 11:02:34 +08:00
honue
8dd74e7dd8 fix 完善页面download传参username 2023-10-28 11:02:26 +08:00
jxxghp
206cdb2663 Merge pull request #988 from khalid586/main 2023-10-28 10:58:24 +08:00
jxxghp
ca334813b7 更新 __init__.py 2023-10-28 10:55:02 +08:00
jxxghp
5fc93ee8e6 Merge pull request #986 from WithdewHua/fix-mediaserver 2023-10-28 10:52:53 +08:00
Khalid Abdullah
9cef7b2615 Update __init__.py(typos fixed) 2023-10-27 23:56:37 +06:00
thsrite
a3916207ae fix division by zero 2023-10-27 23:13:56 +08:00
thsrite
b6e1702051 fix add plugins api 2023-10-27 21:28:37 +08:00
WithdewHua
2cfc8b1ec7 fix: 重连判断 2023-10-27 20:31:52 +08:00
jxxghp
2f7570eec1 Merge pull request #983 from thsrite/main 2023-10-27 17:06:36 +08:00
thsrite
070481cab0 fix 正在下载显示剩余下载时间 2023-10-27 16:52:47 +08:00
jxxghp
26cd2c6cfe Merge pull request #982 from honue/main 2023-10-27 16:25:34 +08:00
honue
1ff571eb46 fix 定时清理媒体库,增加username字段 2023-10-27 15:12:10 +08:00
jxxghp
d8fcb4d240 Merge pull request #980 from thsrite/main 2023-10-27 10:42:45 +08:00
thsrite
778f97c1f3 fix log友好提示 2023-10-27 10:41:31 +08:00
jxxghp
1d6d9aa96d v1.3.7 2023-10-26 17:14:43 +08:00
jxxghp
3bdd96a8ee fix #951 不缓存网络错误导致的TMDB信息None 2023-10-26 17:07:01 +08:00
jxxghp
935ad73d32 fix #955 2023-10-26 16:45:09 +08:00
jxxghp
a85d55f3a8 fix 2023-10-26 16:17:29 +08:00
jxxghp
d7c659b736 fix 2023-10-26 16:15:31 +08:00
jxxghp
e5cedab873 Merge pull request #975 from Shurelol/main 2023-10-26 16:03:22 +08:00
jxxghp
3653d73f4f Merge pull request #974 from thsrite/main 2023-10-26 16:02:21 +08:00
Shurelol
4af57ed861 feat: 增加转移覆盖模式配置 2023-10-26 15:55:09 +08:00
Shurelol
10445c6f56 feat: 增加转移覆盖模式配置 2023-10-26 15:51:17 +08:00
Shurelol
dc6051f0b0 feat: 增加转移覆盖模式配置 2023-10-26 15:49:33 +08:00
Shurelol
2a524eaf22 feat: 增加转移覆盖模式配置 2023-10-26 15:28:41 +08:00
Shurelol
9a810f440d feat: 增加转移覆盖模式配置 2023-10-26 15:24:39 +08:00
thsrite
27ba8db4ea fix images 2023-10-26 15:07:39 +08:00
thsrite
7130194d5f fix 2023-10-26 14:55:08 +08:00
thsrite
d70afc36c9 fix 2023-10-26 14:48:46 +08:00
thsrite
78017b8a0e fix del image 2023-10-26 14:40:57 +08:00
thsrite
e87fdc896c fix tmdbinfo images 2023-10-26 14:34:58 +08:00
thsrite
7bb6d448ed feat 云盘文件删除插件 2023-10-26 13:38:48 +08:00
jxxghp
6415fd9286 Merge pull request #966 from thsrite/main 2023-10-26 13:13:16 +08:00
thsrite
2dd4395698 fix #935 2023-10-26 11:28:07 +08:00
thsrite
68b6e67a93 fix #970 2023-10-26 11:07:11 +08:00
thsrite
71b35e39ab fix 18262f98 2023-10-26 09:10:59 +08:00
thsrite
9ff6015fec fix Cloudflare IP优选插件描述… 2023-10-25 16:53:51 +08:00
thsrite
124817b733 fix 自定义hosts插件描述… 2023-10-25 16:52:19 +08:00
thsrite
8f8f3af7cd fix 药丸签到定时任务描述 2023-10-25 16:37:02 +08:00
thsrite
882fe6cd00 fix 关于路径映射描述…… 2023-10-25 16:33:09 +08:00
thsrite
18262f98f7 fix 同步删除通知图片 2023-10-25 10:52:33 +08:00
jxxghp
fe5a90ac2f Merge pull request #964 from thsrite/main 2023-10-25 10:20:39 +08:00
thsrite
22869b7932 fix #962 2023-10-25 10:10:17 +08:00
jxxghp
e702c16a74 Merge pull request #959 from thsrite/main 2023-10-24 11:32:13 +08:00
thsrite
408690c0ae fix 4aaf5997 2023-10-24 11:22:47 +08:00
thsrite
4aaf5997df fix 登录页海报支持自定义tmdb/bing 2023-10-24 11:17:32 +08:00
jxxghp
f50104bc86 Merge pull request #953 from thsrite/main 2023-10-23 12:01:02 +08:00
thsrite
ee10fc18a7 fix #952 2023-10-23 09:12:53 +08:00
jxxghp
818ef63aec fix #948 2023-10-22 08:23:04 +08:00
jxxghp
4af374f86d Merge remote-tracking branch 'origin/main' 2023-10-22 08:20:10 +08:00
jxxghp
277b252ad8 fix #949 2023-10-22 08:20:00 +08:00
jxxghp
cc7671efd0 Merge pull request #950 from LWLLR/bugfix/rss-proxy 2023-10-22 08:04:10 +08:00
LWLLR
419276eb85 fix: RSS订阅插件下载没有启用代理问题 2023-10-22 06:42:59 +08:00
jxxghp
7d97b9142a Merge pull request #945 from DDS-Derek/main 2023-10-21 15:08:08 +08:00
DDSDerek
c3c041f675 fix: docker buildx cache 2023-10-21 14:40:45 +08:00
jxxghp
d790e6b731 Merge pull request #944 from DDS-Derek/main 2023-10-21 14:33:24 +08:00
DDSRem
8b714a4710 feat: emphasis mark 2023-10-21 14:30:42 +08:00
jxxghp
1f0d01d2ed Merge remote-tracking branch 'origin/main' 2023-10-21 14:23:18 +08:00
jxxghp
7727cd4f58 v1.3.6 2023-10-21 14:22:25 +08:00
jxxghp
bb6b3a57af Merge pull request #943 from DDS-Derek/main
fix: running environment is required
2023-10-21 14:20:37 +08:00
DDSRem
a70a4c272c fix: running environment is required 2023-10-21 14:16:31 +08:00
jxxghp
99bd4da54b Merge pull request #942 from DDS-Derek/main
feat: issue add operating environment
2023-10-21 14:16:06 +08:00
jxxghp
3e09a5e57f fix plugin caption 2023-10-21 14:15:35 +08:00
DDSRem
1375179138 feat: issue add operating environment 2023-10-21 14:15:10 +08:00
jxxghp
a8b1fbbef0 fix #884 2023-10-21 14:04:37 +08:00
jxxghp
d490fcf5af fix init paths 2023-10-21 13:52:06 +08:00
jxxghp
cdbe5b2e2f feat 加大缓存使用 && 订阅搜索休眠 2023-10-21 08:17:10 +08:00
jxxghp
15b1c756a7 fix plugin name 2023-10-20 16:58:18 +08:00
jxxghp
3dfad93977 Merge pull request #932 from thsrite/main 2023-10-20 16:41:20 +08:00
thsrite
3fcd83b0a7 fix 2023-10-20 16:39:22 +08:00
thsrite
03e48881a6 fix 6eb0b4cb 2023-10-20 16:36:31 +08:00
thsrite
6eb0b4cb5b fix 签到bug 2023-10-20 16:29:17 +08:00
jxxghp
556d8586a7 Merge pull request #929 from thsrite/main 2023-10-20 14:33:27 +08:00
thsrite
0ce6e51925 fix 同步删除msg 2023-10-20 14:04:48 +08:00
jxxghp
c2dec7b955 fix download 2023-10-20 13:49:06 +08:00
thsrite
b3733ed9ed feat 站点自动登录插件 2023-10-20 12:54:16 +08:00
jxxghp
be5106c819 fix #927 2023-10-20 12:54:06 +08:00
jxxghp
4875db08e8 fix #927 2023-10-20 12:48:43 +08:00
thsrite
f0593996a1 fix cf优选支持交互命令执行 2023-10-20 12:37:35 +08:00
thsrite
6e113cc9c6 fix 签到失败过多自动触发cf优选 2023-10-20 12:08:07 +08:00
jxxghp
7ffc5e6624 Merge pull request #925 from thsrite/main 2023-10-20 09:58:16 +08:00
thsrite
d1689300b9 fix get_local_version 2023-10-20 09:20:08 +08:00
jxxghp
5fc7a7dd8a - 修复v1.3.5版本的问题 2023-10-20 08:07:38 +08:00
jxxghp
f59609131c fix #921 2023-10-20 07:38:34 +08:00
jxxghp
efd1733b56 Merge pull request #922 from WithdewHua/fix-db 2023-10-20 06:53:04 +08:00
WithdewHua
31289d24e2 fix: 将 detached 对象重新关联到 Session 2023-10-20 02:40:13 +08:00
jxxghp
98be091ca6 Merge pull request #918 from thsrite/main 2023-10-19 20:41:05 +08:00
thsrite
4bfdf1dede fix add 提示 2023-10-19 20:21:40 +08:00
thsrite
c6a43a5dde fix auto restart 2023-10-19 20:20:09 +08:00
thsrite
3a20946f62 fix remove update 2023-10-19 20:11:19 +08:00
thsrite
d892400ca7 Merge remote-tracking branch 'origin/main' into main 2023-10-19 19:23:20 +08:00
thsrite
44b7199087 fix 更新系统 2023-10-19 19:23:05 +08:00
jxxghp
c3fe22a76f Merge pull request #917 from thsrite/main
fix 更新通知
2023-10-19 18:11:06 +08:00
thsrite
7d9a3d39b3 fix 更新通知 2023-10-19 18:09:49 +08:00
jxxghp
c932d2b7f0 fix bug 2023-10-19 18:08:56 +08:00
jxxghp
4739d43c45 v1.3.5 2023-10-19 17:55:40 +08:00
jxxghp
b33e777028 fix bug 2023-10-19 17:39:15 +08:00
jxxghp
e5718a50b2 fix bug 2023-10-19 17:15:46 +08:00
jxxghp
a911bab7b0 fix db session 2023-10-19 16:58:38 +08:00
jxxghp
21908bdc6f fix 优化豆瓣插件媒体识别 2023-10-19 08:13:13 +08:00
jxxghp
573a943467 更新 site.py 2023-10-18 21:34:28 +08:00
jxxghp
bcc29afa2b fix #885 2023-10-18 21:14:17 +08:00
jxxghp
ce693435df fix #900 2023-10-18 20:50:37 +08:00
jxxghp
dad5d76664 fix bug 2023-10-18 20:46:58 +08:00
jxxghp
897369d300 fix dblock 2023-10-18 19:42:46 +08:00
jxxghp
3d34c26731 fix 2023-10-18 19:26:21 +08:00
jxxghp
2e4536edb6 fix db session 2023-10-18 18:30:09 +08:00
jxxghp
68e16d18fe fix #909 2023-10-18 12:36:46 +08:00
jxxghp
0cd071813f fix #908 2023-10-18 12:25:51 +08:00
jxxghp
49f7aa30c8 fix #904 2023-10-18 12:24:16 +08:00
jxxghp
74caf8a482 fix 2023-10-18 08:38:30 +08:00
jxxghp
fb78a07662 fix db session 2023-10-18 08:35:16 +08:00
jxxghp
84f5ce8a0b db lock 2023-10-17 21:07:38 +08:00
jxxghp
3f5f689965 db lock 2023-10-17 20:57:09 +08:00
jxxghp
0591b59837 more log 2023-10-17 20:36:28 +08:00
jxxghp
4cc2551487 fix 消息翻页后数据减少问题 2023-10-17 19:59:31 +08:00
jxxghp
f15ccadc2d fix 优化连接参数 2023-10-17 19:39:19 +08:00
jxxghp
453ef94e4d feat 多线程处理事件 2023-10-17 19:04:42 +08:00
jxxghp
e57b6adba1 Merge pull request #896 from thsrite/main 2023-10-17 18:52:17 +08:00
thsrite
acf8c67681 fix bug 2023-10-17 18:38:23 +08:00
jxxghp
be4df15d01 fix #890 2023-10-17 17:24:25 +08:00
jxxghp
bd2ef934d9 Merge pull request #894 from thsrite/main 2023-10-17 17:04:04 +08:00
thsrite
b90622a88e fix 2023-10-17 16:54:00 +08:00
thsrite
6868712b4e fix 入库失败输入手动处理通知 2023-10-17 16:50:46 +08:00
thsrite
4099c5e1b5 fix 2023-10-17 16:43:29 +08:00
thsrite
e018f77e37 fix #895 2023-10-17 16:27:29 +08:00
thsrite
3aac617f35 feat MoviePilot更新推送插件 2023-10-17 16:16:17 +08:00
thsrite
8a46ebc4a0 fix add update交互命令 2023-10-17 15:44:26 +08:00
thsrite
26f63c4ea7 fix 2023-10-17 15:12:02 +08:00
thsrite
0e92e9fc60 fix 交互重启完发送消息,交互获取当前版本 2023-10-17 15:10:02 +08:00
jxxghp
0fe911b6b4 fix #889 2023-10-17 13:34:49 +08:00
jxxghp
592b9a89c9 fix dict 2023-10-17 08:17:32 +08:00
jxxghp
08e0df1abc fix bug 2023-10-16 18:55:05 +08:00
jxxghp
8f012eee50 Merge pull request #881 from thsrite/main
fix 目录监控消息间隔
2023-10-16 18:23:55 +08:00
thsrite
da766a400d fix 目录监控消息间隔 2023-10-16 17:38:08 +08:00
jxxghp
ec309180da v1.3.4 2023-10-16 17:36:01 +08:00
jxxghp
ab3b674a6e fix 目录监控通知间隔 2023-10-16 17:30:25 +08:00
jxxghp
9231144518 fix 2023-10-16 17:11:45 +08:00
jxxghp
13c04de87c fix 2023-10-16 17:10:22 +08:00
jxxghp
70f533684f fix #607 目录监控全量同步 2023-10-16 17:04:51 +08:00
jxxghp
c94866631b 更新 bug_report.yml 2023-10-16 12:33:51 +08:00
jxxghp
40a77b438e feat 下载中信息增加用户 2023-10-16 08:28:54 +08:00
jxxghp
f5de48ca30 fix #867 2023-10-16 07:16:47 +08:00
jxxghp
89a2c00e64 fix #867 2023-10-16 07:16:02 +08:00
jxxghp
35afb50b26 fix #867 2023-10-16 07:14:36 +08:00
jxxghp
0e3e01bf9c fix #864 2023-10-16 07:06:10 +08:00
jxxghp
6e3ebd73c6 Merge remote-tracking branch 'origin/main' 2023-10-16 07:04:59 +08:00
jxxghp
add9b875aa fix #863 2023-10-16 07:04:31 +08:00
jxxghp
b1790ee730 v1.3.3 2023-10-15 15:00:15 +08:00
jxxghp
47d7800250 fix #788 Rclone远程刮削 2023-10-15 14:56:04 +08:00
jxxghp
4849c281d3 fix #788 2023-10-15 14:37:20 +08:00
jxxghp
c36acd7bb4 fix #830 2023-10-15 14:19:36 +08:00
jxxghp
986e96a88e Merge pull request #847 from thsrite/main 2023-10-14 20:55:00 +08:00
thsrite
493b7c2d24 fix 重启系统发送消息 2023-10-14 20:49:03 +08:00
jxxghp
0539ddab85 fix bug 2023-10-14 20:27:04 +08:00
jxxghp
202fdf8905 fix bug 2023-10-14 20:16:15 +08:00
jxxghp
9191ed0a21 fix bug 2023-10-14 20:12:02 +08:00
jxxghp
9697cf3901 fix icon 2023-10-14 13:31:21 +08:00
jxxghp
e6a11294fd Merge pull request #842 from lightolly/dev/20231014
feat:增加自定义站点配置,仅为统计和签到使用
2023-10-14 13:25:36 +08:00
olly
cd046d8023 feat:增加自定义站点配置,仅为统计和签到使用 2023-10-14 13:22:06 +08:00
jxxghp
4d08928b8c Merge remote-tracking branch 'origin/main' 2023-10-14 13:05:13 +08:00
jxxghp
bc8a243a6d feat 整合历史记录Api 2023-10-14 13:05:00 +08:00
jxxghp
3b804e13a8 Merge pull request #839 from thsrite/main
fix 缺失消息发给交互人
2023-10-14 12:42:26 +08:00
thsrite
f126f927b4 fix 缺失消息发给交互人 2023-10-14 12:35:38 +08:00
jxxghp
d4f202c2b1 fix #838 2023-10-14 11:52:05 +08:00
jxxghp
77a1d56c5b Merge pull request #838 from thsrite/main
fix 演职人员刮削插件增加刮削条件、debug日志
2023-10-14 11:48:17 +08:00
jxxghp
7415f94da2 Merge pull request #834 from DDS-Derek/main
feat: pip add cache
2023-10-14 11:47:26 +08:00
thsrite
fa50d8b884 fix 演职人员刮削插件增加刮削条件、debug日志 2023-10-14 11:40:21 +08:00
DDSDerek
40776c10bc feat: pip add cache 2023-10-14 01:08:13 +08:00
jxxghp
6578a2f977 Merge pull request #832 from DDS-Derek/main
docs fix
2023-10-13 21:52:06 +08:00
DDSRem
e780485fc6 docs: fix 2023-10-13 21:46:55 +08:00
DDSRem
8213cdba63 docs: fix 2023-10-13 21:44:28 +08:00
DDSRem
8d5b0d4035 docs: fix 2023-10-13 21:43:19 +08:00
DDSRem
3eaa22d068 docs: fix 2023-10-13 21:42:27 +08:00
jxxghp
4797983f43 Merge pull request #831 from DDS-Derek/main
fix: rclone version is too low
2023-10-13 21:32:11 +08:00
jxxghp
0e7e2fc44b fix #829 默认过滤规则拆分 2023-10-13 21:31:13 +08:00
DDSRem
9a51286c54 docs: fix 2023-10-13 21:20:42 +08:00
DDSRem
ddbf93f2c5 docs: fix 2023-10-13 21:16:59 +08:00
DDSRem
418411b10d fix: connector error 2023-10-13 21:14:43 +08:00
DDSRem
dceb7340dd fix: rclone version is too low 2023-10-13 21:07:13 +08:00
jxxghp
e7e9ca539d fix #810 2023-10-13 15:32:11 +08:00
jxxghp
333d187615 Merge pull request #821 from thsrite/main
fix 从下载历史获取tmdbid入库刮削
2023-10-13 15:10:33 +08:00
thsrite
761e66b200 fix 从下载历史获取tmdbid入库刮削 2023-10-13 14:29:07 +08:00
thsrite
eec52fa5ba fix 下载用户精简下载进度消息 2023-10-13 13:56:23 +08:00
jxxghp
b6c3c03748 Merge pull request #819 from thsrite/main 2023-10-13 11:52:33 +08:00
thsrite
4eebaa5d75 fix 删种 2023-10-13 11:45:18 +08:00
jxxghp
f6dfe9cb88 fix rules 2023-10-13 11:41:12 +08:00
thsrite
c36c94971e fix 插件记录同步 2023-10-13 11:09:33 +08:00
jxxghp
e83a15ad1f fix plugin log 2023-10-13 11:01:58 +08:00
thsrite
16aa353cf6 Merge remote-tracking branch 'origin/main' 2023-10-13 10:26:49 +08:00
thsrite
5adfa89d10 fix bug 2023-10-13 10:26:40 +08:00
jxxghp
b1805c1a46 add logs 2023-10-13 07:18:12 +08:00
jxxghp
7e51d70cd6 - 修复了搜索页面过滤失效的问题 2023-10-12 22:46:42 +08:00
jxxghp
b5cba64227 fix 2023-10-12 21:30:35 +08:00
jxxghp
f20c81efae fix rclone 2023-10-12 20:47:23 +08:00
jxxghp
bfbd93b912 fix 2023-10-12 20:35:44 +08:00
jxxghp
6be074e647 fix doubaninfo 2023-10-12 20:31:59 +08:00
jxxghp
5f96a562d4 v1.3.2 2023-10-12 20:11:22 +08:00
jxxghp
cefbd70469 fix #807 2023-10-12 20:06:58 +08:00
jxxghp
30c9c66087 fix 豆瓣来源订阅 2023-10-12 19:59:47 +08:00
jxxghp
1ecbc2f0be fix bug 2023-10-12 18:08:09 +08:00
jxxghp
884a0feb62 fix bug 2023-10-12 17:56:15 +08:00
jxxghp
5f44f07515 fixme 2023-10-12 17:51:20 +08:00
jxxghp
a902b79684 fix #800 2023-10-12 17:07:26 +08:00
jxxghp
4e13f59b36 fix #804 2023-10-12 16:03:36 +08:00
jxxghp
cbccac87f0 feat 清理无效的插件事件响应 2023-10-12 12:48:40 +08:00
jxxghp
eb3c09a3d3 fix bug 2023-10-12 11:50:22 +08:00
jxxghp
2a9a36ac88 feat 辅助识别异步接口 && ChatGPT插件支持辅助名称识别 2023-10-12 11:41:57 +08:00
jxxghp
af2f52a050 fix 优先级规则支持杜比全景声 2023-10-12 09:46:48 +08:00
jxxghp
7a61fa1ee2 feat 订阅支持更多过滤规则 2023-10-12 08:58:59 +08:00
jxxghp
ac3009d58f fix bug 2023-10-12 08:40:56 +08:00
jxxghp
e835feb056 更新 douban.py 2023-10-11 18:11:13 +08:00
jxxghp
cd391d14f9 fix plex 2023-10-11 17:27:10 +08:00
jxxghp
d7844968ab v1.3.1 2023-10-11 17:20:11 +08:00
jxxghp
70ea398f14 fix 优化豆瓣匹配 2023-10-11 16:32:34 +08:00
jxxghp
860d55a0e2 feat 热门动漫 2023-10-11 16:13:15 +08:00
jxxghp
0e35cec6e2 fix #743 支持Rclone 2023-10-11 12:16:41 +08:00
jxxghp
5778e86260 fix #775 增加日志打印 2023-10-11 11:01:53 +08:00
jxxghp
967d0b1205 fix #778 2023-10-11 08:32:48 +08:00
jxxghp
0b2d419000 fix spec 2023-10-11 08:19:44 +08:00
jxxghp
149104063c fix #784 PROXY_HOST仅环境变量配置 2023-10-11 07:44:37 +08:00
jxxghp
498168a2d3 fix #783 2023-10-10 22:23:03 +08:00
jxxghp
88e307416d fix Dockerfile 2023-10-10 22:09:16 +08:00
jxxghp
3bb2eedb33 fix icon 2023-10-10 21:26:30 +08:00
jxxghp
36c046ad6a - 优化Windows打包 2023-10-10 20:25:00 +08:00
jxxghp
85396df221 - 优化Windows打包 2023-10-10 20:06:52 +08:00
jxxghp
2f0f58783e fix spec 2023-10-10 19:45:18 +08:00
jxxghp
2d989d4229 更新 main.py 2023-10-10 18:19:46 +08:00
jxxghp
ecc8b6b385 fix spec 2023-10-10 17:35:28 +08:00
jxxghp
aa90c5d5c0 fix build 2023-10-10 16:38:51 +08:00
jxxghp
5f7d93f170 fix startup 2023-10-10 16:23:57 +08:00
jxxghp
0fbe51f257 fix bug 2023-10-10 16:17:22 +08:00
jxxghp
be941ebdd1 fix #770 2023-10-10 16:14:12 +08:00
jxxghp
4d900c2eb0 fix #777 豆瓣流控改为随机休眠3-10秒 2023-10-10 16:02:14 +08:00
jxxghp
93c473afe7 - 优化Windows打包 2023-10-10 15:48:44 +08:00
jxxghp
4c9a66f586 fix trayicon 2023-10-10 14:44:27 +08:00
jxxghp
375e16e0dc fix trayicon 2023-10-10 14:38:50 +08:00
jxxghp
91085d13a3 Merge remote-tracking branch 'origin/main' 2023-10-10 13:58:02 +08:00
jxxghp
3f83894dc6 add trayicon 2023-10-10 13:57:56 +08:00
jxxghp
5946684ee6 Merge pull request #776 from thsrite/main
fix 更新log
2023-10-10 13:44:39 +08:00
thsrite
7e3f25879f fix 更新log 2023-10-10 13:41:39 +08:00
jxxghp
48dcc3ee1b - 优化Windows打包 2023-10-10 13:32:05 +08:00
jxxghp
fca0a4b511 Merge remote-tracking branch 'origin/main' 2023-10-10 13:27:11 +08:00
jxxghp
d6831a8881 - 优化Windows打包 2023-10-10 13:27:00 +08:00
jxxghp
39a646ed92 更新 README.md 2023-10-10 12:50:11 +08:00
jxxghp
595965c5d0 Merge pull request #774 from thsrite/main 2023-10-10 11:47:00 +08:00
thsrite
3bb6f8a0c0 Merge remote-tracking branch 'origin/main' 2023-10-10 11:15:45 +08:00
thsrite
1924a2017e fix #773 2023-10-10 11:15:26 +08:00
jxxghp
60140fd2e6 - 优化Windows打包 2023-10-10 09:50:37 +08:00
jxxghp
65b5219e45 fix TZ 2023-10-10 07:58:26 +08:00
jxxghp
ae2f649aee fix README.md 2023-10-09 21:44:39 +08:00
jxxghp
bf3e860a18 fix README.md 2023-10-09 21:34:08 +08:00
jxxghp
0b44a91493 fix README.md 2023-10-09 21:33:53 +08:00
jxxghp
16077b3341 fix #769 2023-10-09 21:13:36 +08:00
jxxghp
a7cedde721 fix build 2023-10-09 20:53:23 +08:00
jxxghp
ecd53192dc fix build 2023-10-09 20:53:11 +08:00
jxxghp
a03c76e211 更新 build-windows.yml 2023-10-09 20:35:18 +08:00
jxxghp
de427fd7a9 fix 2023-10-09 20:14:54 +08:00
jxxghp
c37e02009f fix build 2023-10-09 19:39:19 +08:00
jxxghp
a96b8a4e07 fix build 2023-10-09 19:37:49 +08:00
jxxghp
79b4d5fb8e fix build 2023-10-09 19:33:05 +08:00
jxxghp
de128f5e6a fix 2023-10-09 15:04:54 +08:00
jxxghp
ef8ddcde07 fix 2023-10-09 14:46:23 +08:00
jxxghp
eaff557d70 windows package 2023-10-09 14:11:03 +08:00
jxxghp
38f7a31200 windows package 2023-10-09 13:40:09 +08:00
jxxghp
97f16289c9 windows package 2023-10-09 12:57:52 +08:00
jxxghp
e15f5ab93e Merge pull request #767 from thsrite/main 2023-10-09 11:50:18 +08:00
thsrite
15fd312765 fix #766 2023-10-09 11:41:59 +08:00
jxxghp
eea316865f fix #753 2023-10-09 11:05:53 +08:00
jxxghp
05bbfbbd54 Merge pull request #765 from thsrite/main
fix #701
2023-10-09 10:09:46 +08:00
thsrite
6039a9d0d5 fix 2023-10-09 10:06:04 +08:00
thsrite
0159b02916 fix 8bbd4dc9 2023-10-09 09:50:30 +08:00
thsrite
8bbd4dc913 fix #701 2023-10-09 09:37:16 +08:00
jxxghp
9e3ded6ad5 Merge pull request #764 from thsrite/main
fix 下载消息发送所有
2023-10-09 09:27:40 +08:00
jxxghp
fe63275a6b fix bug 2023-10-09 09:09:59 +08:00
jxxghp
81ed465607 fix #759 2023-10-09 09:05:48 +08:00
thsrite
d9aa281ce1 fix 下载消息发送所有 2023-10-09 09:02:01 +08:00
jxxghp
56648d664e fix README.md 2023-10-08 17:03:20 +08:00
jxxghp
da49d5577a fix app.env 2023-10-08 16:41:53 +08:00
jxxghp
f3dbdefdb1 fix README.md 2023-10-08 16:26:22 +08:00
jxxghp
d4302759e6 fix README.md 2023-10-08 16:25:27 +08:00
jxxghp
914f192fb2 test 2023-10-08 16:24:40 +08:00
jxxghp
522b554e36 fix README.md 2023-10-08 16:12:27 +08:00
jxxghp
4c54ab5319 fix README.md 2023-10-08 15:58:42 +08:00
jxxghp
d7f4ed069c Merge pull request #757 from lightolly/dev/20231008 2023-10-08 14:04:00 +08:00
olly
7ea0c5ee4c fix:演职员刮削优化
1.豆瓣查询增加速率限制后重试
2.全中文演职员跳过处理
2023-10-08 14:00:55 +08:00
jxxghp
e773a9d9d4 Merge pull request #755 from thsrite/customization 2023-10-08 12:22:56 +08:00
thsrite
b570542fab fix 2023-10-08 12:16:45 +08:00
thsrite
09716e98ba feat 自定义占位符 2023-10-08 11:59:52 +08:00
jxxghp
9236b361e2 Merge remote-tracking branch 'origin/main' 2023-10-08 06:56:57 +08:00
jxxghp
f281d8c068 fix #749 2023-10-08 06:56:45 +08:00
jxxghp
83ed17d5c1 Merge pull request #752 from thsrite/main
feat 药丸论坛签到
2023-10-07 20:54:25 +08:00
jxxghp
e2671dd4ed fix dockerfile 2023-10-07 05:52:43 -07:00
thsrite
4c4d640331 feat 药丸论坛签到 2023-10-07 20:51:32 +08:00
jxxghp
6c4307c918 fix #750 2023-10-07 05:29:23 -07:00
jxxghp
5a7062c699 fix 2023-10-07 05:03:19 -07:00
jxxghp
7da01f7404 fix 2023-10-07 05:03:06 -07:00
jxxghp
2b695cb8c6 fix #748 2023-10-07 04:59:07 -07:00
jxxghp
599817eec7 test 2023-10-07 04:44:06 -07:00
jxxghp
11fa33be0a test 2023-10-07 04:33:52 -07:00
jxxghp
b5ac9d4ce4 fix app.env 2023-10-07 04:08:19 -07:00
jxxghp
78f0ac0042 fix README.md 2023-10-07 04:01:21 -07:00
jxxghp
00ecd7adc5 更新 app.env 2023-10-07 18:24:02 +08:00
jxxghp
c39cb3bffc 更新 app.env 2023-10-07 18:22:32 +08:00
jxxghp
2fa902bfff Merge pull request #747 from thsrite/main 2023-10-07 18:09:25 +08:00
thsrite
f8bcd351ae fix 依赖 2023-10-07 18:08:33 +08:00
jxxghp
6013d99bf6 v1.2.9 2023-10-07 17:21:08 +08:00
jxxghp
e7c3977f7b fix README.md 2023-10-07 12:26:16 +08:00
jxxghp
47e1218fe0 fix #732 2023-10-07 10:31:33 +08:00
jxxghp
a71a95892f fix 2023-10-05 23:23:33 -07:00
jxxghp
b5f53e309f fix 2023-10-05 23:12:46 -07:00
jxxghp
3164ba2d98 fix #734 2023-10-05 17:57:47 -07:00
jxxghp
89854d188d fix actor thumb 2023-10-05 17:49:31 -07:00
jxxghp
79c7475435 fix tmdb lru cache 2023-10-05 17:41:02 -07:00
jxxghp
2ee477c35e fix requests session stream 2023-10-05 17:32:23 -07:00
jxxghp
5bcd90c569 fix requests session 2023-10-05 17:21:59 -07:00
jxxghp
1a49c7c59e try fix 2023-10-05 07:44:21 +08:00
jxxghp
d995932a1c fix personmeta 2023-10-04 14:34:42 +08:00
jxxghp
1b0bbbbbfd fix webhook plugin 2023-10-04 08:01:30 +08:00
jxxghp
2aa93fa341 fix webhook plugin 2023-10-04 08:01:02 +08:00
jxxghp
a970f90c6f Merge remote-tracking branch 'origin/main' 2023-10-04 07:33:38 +08:00
jxxghp
44f612fed5 v1.2.8 2023-10-04 07:33:31 +08:00
jxxghp
564a48dd8f fix 2023-10-03 16:24:27 -07:00
jxxghp
9d029de56a fix 2023-10-03 16:23:05 -07:00
jxxghp
2dd3fc5d8c fix #722 2023-10-03 16:19:43 -07:00
jxxghp
9c335dbdfb fix #724 2023-10-03 16:17:19 -07:00
jxxghp
0e30ea92f1 fix #726 2023-10-03 16:14:04 -07:00
jxxghp
a0ced4e43c 认证站点支持xingtan.one 2023-10-03 16:05:50 -07:00
jxxghp
cfaaf65edc support xingtan 2023-10-04 07:03:13 +08:00
jxxghp
35be18bb1a fix 2023-10-01 21:55:49 +08:00
jxxghp
02296e1758 fix 2023-10-01 21:46:09 +08:00
jxxghp
0b84b05cdd fix #705 2023-10-01 21:36:33 +08:00
jxxghp
99e3d5acca fix #707 2023-10-01 21:33:58 +08:00
jxxghp
8001511484 fix #690 2023-10-01 21:23:41 +08:00
jxxghp
8420b2ea85 fix personmeta 2023-10-01 21:08:16 +08:00
jxxghp
9af883acbb fix personmeta 2023-10-01 18:27:26 +08:00
jxxghp
e21ba5ad51 fix personmeta 2023-10-01 18:11:01 +08:00
jxxghp
1293fafd34 fix 2023-10-01 16:47:47 +08:00
jxxghp
4bcc6bd733 fix bug 2023-10-01 14:18:56 +08:00
jxxghp
53a514feb6 fix personmeta支持豆瓣 2023-10-01 14:16:36 +08:00
jxxghp
e697889aad fix 2023-10-01 12:37:18 +08:00
jxxghp
8b0fba054e Merge remote-tracking branch 'origin/main' 2023-10-01 12:28:46 +08:00
jxxghp
32ff385444 fix personmeta 2023-10-01 12:28:41 +08:00
jxxghp
8456c7f4a3 Merge pull request #718 from DDS-Derek/main
功能改进增加选择类型
2023-10-01 11:55:56 +08:00
jxxghp
fcbfb63645 fix personmeta 2023-10-01 11:52:25 +08:00
DDSDerek
1fa7d15982 fix: issue 2023-10-01 10:07:51 +08:00
DDSDerek
a173978f6b feat: optimize issue 2023-10-01 10:06:11 +08:00
jxxghp
2f069afc77 fix personmeta 2023-10-01 08:15:19 +08:00
jxxghp
ea998b4e41 fix personmeta 2023-10-01 07:53:50 +08:00
jxxghp
ba27d02854 fix 2023-09-30 20:40:48 +08:00
jxxghp
f78df58906 fix 2023-09-30 20:36:51 +08:00
jxxghp
308683a7e9 fix scraper 2023-09-30 20:27:48 +08:00
jxxghp
b3f4a6f251 fix mediaserver 2023-09-30 15:27:01 +08:00
jxxghp
d1841d8f15 fix mediaserver 2023-09-30 15:16:53 +08:00
jxxghp
c8d6de3e9b Merge pull request #706 from song-zhou/main 2023-09-29 22:04:22 +08:00
Elsie Weber
938f5c8cea Merge branch 'jxxghp:main' into main 2023-09-29 21:57:50 +08:00
songzhou
d166930b0a 修复手动执行订阅搜索服务无效bug 2023-09-29 21:57:41 +08:00
jxxghp
e1ac3c0d15 fix personmeta 2023-09-29 12:01:00 +08:00
jxxghp
59da489e05 Merge pull request #704 from developer-wlj/wlj0909 2023-09-29 10:30:16 +08:00
developer-wlj
be12c736fb Merge branch 'jxxghp:main' into wlj0909 2023-09-29 10:14:36 +08:00
jxxghp
71c52aae7b Merge pull request #703 from DDS-Derek/main 2023-09-29 10:12:32 +08:00
mayun110
dbfe2af53c fix PersonMeta插件jellyfin无法显示头像问题 2023-09-29 10:11:18 +08:00
DDSRem
cca898f5b6 feat: docker build use cache 2023-09-29 09:31:47 +08:00
jxxghp
9abd780aa2 fix PersonMeta 2023-09-29 08:34:45 +08:00
jxxghp
2e89eeca2c fix #694 按站点多次检索 2023-09-29 08:20:55 +08:00
jxxghp
dbb3bead6b fix #696 2023-09-28 22:38:11 +08:00
jxxghp
d0b88ec7f6 fix #696 2023-09-28 22:36:35 +08:00
jxxghp
5898bc7eb1 - 修复v1.2.7版本中的问题 2023-09-28 22:19:13 +08:00
jxxghp
cfe113f6c3 fix bug 2023-09-28 22:16:21 +08:00
jxxghp
83500128c9 Merge pull request #698 from song-zhou/main
修复通知emby时libraryId错误bug
2023-09-28 22:09:32 +08:00
songzhou
2bff3a80da 修复通知emby时libraryId错误bug 2023-09-28 22:05:43 +08:00
jxxghp
3dd7b33f3e fix bug 2023-09-28 21:37:57 +08:00
jxxghp
8de487b0bf fix bug 2023-09-28 21:27:39 +08:00
jxxghp
ce88a6818f fix #693 2023-09-28 21:18:40 +08:00
jxxghp
6172832f41 fix 图片下载重试 2023-09-28 21:13:40 +08:00
jxxghp
a0ed228f4b fix 演员头像&中文名 2023-09-28 21:11:08 +08:00
jxxghp
01fd56a019 feat 演职人员优先使用TMDB中的中文名 2023-09-28 20:24:47 +08:00
jxxghp
087fcd340a fix #692 2023-09-28 20:06:03 +08:00
jxxghp
b3b09f3c03 Merge pull request #692 from DDS-Derek/main 2023-09-28 20:04:30 +08:00
DDSRem
11d17bf21a fix: https://github.com/jxxghp/MoviePilot/pull/654 2023-09-28 19:57:28 +08:00
jxxghp
b1ee80edee fix themoivedb timeout 2023-09-28 19:08:34 +08:00
jxxghp
107d496adb v1.2.7 2023-09-28 17:43:34 +08:00
jxxghp
9f1112b58d fix 2023-09-28 17:41:48 +08:00
jxxghp
989d6e3fe7 fix 2023-09-28 17:29:21 +08:00
jxxghp
3999c64853 add PersonMeta 2023-09-28 17:11:55 +08:00
jxxghp
760e3d6de0 更新 __init__.py 2023-09-28 16:32:56 +08:00
jxxghp
02111a3b9f fix #684 2023-09-28 16:23:10 +08:00
jxxghp
e6af2c0f34 fix 2023-09-28 16:14:52 +08:00
jxxghp
bd4c639761 Merge pull request #688 from thsrite/main
feat 定时清理媒体库插件
2023-09-28 15:46:13 +08:00
thsrite
d39b7ec021 fix 2023-09-28 15:40:13 +08:00
thsrite
63ca5f5017 fix 下载进度推送逻辑 2023-09-28 15:32:07 +08:00
thsrite
2202cf457b fix 2023-09-28 15:25:04 +08:00
thsrite
5d04b7abd6 feat 定时清理媒体库插件 2023-09-28 15:21:01 +08:00
jxxghp
0588d5d5f3 fix get_location 2023-09-28 14:49:54 +08:00
jxxghp
5a59e443d7 fix 2023-09-28 14:43:08 +08:00
jxxghp
470f4df979 fix #669 2023-09-28 14:32:34 +08:00
jxxghp
84bda71330 fix #657 2023-09-28 14:16:27 +08:00
jxxghp
ea883255cb fix #685 添加resourceType资源类型 2023-09-28 13:45:06 +08:00
jxxghp
e9abb69fb5 fix 2023-09-28 12:52:32 +08:00
jxxghp
ff63390794 Merge pull request #686 from thsrite/main 2023-09-28 12:39:12 +08:00
jxxghp
78b3135276 feat 媒体文件同步删除插件:支持手动删除源文件同步处理下载任务 2023-09-28 12:35:41 +08:00
thsrite
15bd2c09ed fix 2023-09-28 12:28:24 +08:00
thsrite
34d44857e4 fix messageforward 2023-09-28 12:11:39 +08:00
thsrite
dccded2d3e fix 下载消息增加用户 2023-09-28 12:03:18 +08:00
thsrite
295cafc060 fix 2023-09-28 11:56:13 +08:00
thsrite
c792e97f67 fix 下载进度增加识别名 2023-09-28 11:41:30 +08:00
thsrite
d30a02987d feat 正在下载进度推送插件 2023-09-28 11:10:34 +08:00
jxxghp
84d4c9cf73 feat 重命名支持episode_title集标题 2023-09-28 10:58:31 +08:00
jxxghp
21ecd1f708 fix #673 2023-09-28 08:34:34 +08:00
jxxghp
248b9a8e8c fix #663 2023-09-28 08:24:39 +08:00
jxxghp
3c7abfada6 fix #677 2023-09-28 08:14:22 +08:00
jxxghp
f363656e0a Merge remote-tracking branch 'origin/main' 2023-09-28 08:09:01 +08:00
jxxghp
e9ee9dbce1 fix #676 2023-09-28 08:08:55 +08:00
jxxghp
ab0b8653ab Merge pull request #674 from developer-wlj/wlj0909 2023-09-27 18:12:10 +08:00
developer-wlj
20711e17fb Merge branch 'jxxghp:main' into wlj0909 2023-09-27 18:06:51 +08:00
mayun110
a89bd8b816 Merge remote-tracking branch 'origin/wlj0909' into wlj0909 2023-09-27 18:05:46 +08:00
mayun110
3692cfea64 fix 无法匹配国语标签的bug 2023-09-27 15:38:35 +08:00
jxxghp
81d9d39029 fix bug 2023-09-27 14:12:11 +08:00
jxxghp
f5a61ceff1 fix bug 2023-09-27 13:40:35 +08:00
jxxghp
404a7b8337 fix bug 2023-09-27 11:14:56 +08:00
jxxghp
71ce3a2920 v1.2.6 2023-09-27 10:19:37 +08:00
jxxghp
3a27656769 fix #557 2023-09-27 10:18:40 +08:00
jxxghp
27b1e0ffd5 fix #668 rollback #654 2023-09-27 09:47:56 +08:00
jxxghp
1401ea74dd fix #667 硬链接支持极空间 2023-09-27 08:22:32 +08:00
jxxghp
cb93a63970 feat 历史记录支持重新识别 2023-09-27 08:16:26 +08:00
jxxghp
da4ff99570 fix #655 2023-09-25 08:40:19 +08:00
jxxghp
b3c0dc813b fix #662 2023-09-25 07:12:36 +08:00
jxxghp
a7b51d9fcc fix bug 2023-09-24 19:48:03 +08:00
jxxghp
76f1de42a8 v1.2.5 2023-09-24 19:33:25 +08:00
jxxghp
bad016b2b4 rollback mteam 2023-09-24 19:29:24 +08:00
jxxghp
5cd48d5447 fix 优化定时服务调度 2023-09-24 12:41:59 +08:00
jxxghp
41ff5363ea Merge remote-tracking branch 'origin/main' 2023-09-24 11:14:00 +08:00
jxxghp
85014f4acb feat 服务手动触发 2023-09-24 11:13:49 +08:00
jxxghp
d9a68daddd Merge pull request #658 from WithdewHua/fix-torrentremover 2023-09-24 08:02:45 +08:00
WithdewHua
141e78f274 fix: 种子分类为空时被删除 2023-09-24 02:58:24 +08:00
jxxghp
de98ccd33c fix mteam、zhuque登录判定 2023-09-23 21:42:21 +08:00
jxxghp
d490dadfdd fix mteam 2023-09-23 16:35:27 +08:00
jxxghp
f46bbf73ba Merge pull request #654 from DDS-Derek/main
fix: container id retrieval error
2023-09-23 16:21:05 +08:00
jxxghp
17eba86f7a fix mteam 2023-09-23 16:20:08 +08:00
DDSRem
fdf25b8c66 fix: container id retrieval error 2023-09-23 16:04:25 +08:00
jxxghp
516cb443b9 fix mteam 2023-09-23 15:58:42 +08:00
jxxghp
7c4c3b3f9a feat 支持新版本mteam 2023-09-23 12:30:19 +08:00
jxxghp
e298a1a8a0 feat 支持新版本mteam 2023-09-23 12:02:04 +08:00
jxxghp
fd9eef2089 feat 支持多媒体服务器同时使用 2023-09-23 09:20:51 +08:00
jxxghp
78dab04c96 fix #650 2023-09-23 08:33:49 +08:00
jxxghp
c34475653f Merge pull request #652 from WithdewHua/fix-torrentremover 2023-09-22 22:45:17 +08:00
WithdewHua
eb6a6eee0a fix: 种子分类为空时被删除 2023-09-22 21:27:48 +08:00
jxxghp
48f6a45194 v1.2.4 2023-09-22 16:06:00 +08:00
jxxghp
c8ae6bcc78 fix message format 2023-09-22 16:04:04 +08:00
jxxghp
7f6beb2a78 feat SynologyChat 2023-09-22 15:40:23 +08:00
jxxghp
ea160afd90 fix CronTrigger.from_crontab异常捕捉 2023-09-22 14:42:11 +08:00
jxxghp
29df0813fd fix 屏蔽telebot的trackback日志 2023-09-22 14:37:10 +08:00
jxxghp
b014c4a4e5 fix #646 2023-09-22 14:26:46 +08:00
jxxghp
f173c21695 更新 telegram.py 2023-09-22 13:04:20 +08:00
jxxghp
dc41f4946a fix bug 2023-09-22 12:52:40 +08:00
jxxghp
fed754f03a fix memory 2023-09-22 11:42:34 +08:00
jxxghp
382d9ed525 Merge remote-tracking branch 'origin/main' 2023-09-22 11:33:32 +08:00
jxxghp
e3707f39bb fix wallpaper 2023-09-22 11:33:25 +08:00
jxxghp
9df8d3d360 fix bug 2023-09-22 11:20:12 +08:00
jxxghp
5b3c310cda Merge pull request #643 from thsrite/main 2023-09-22 11:01:16 +08:00
jxxghp
79d692771e Merge remote-tracking branch 'origin/main' 2023-09-22 10:59:28 +08:00
jxxghp
f74ffed3ae fix #628 2023-09-22 10:59:19 +08:00
thsrite
0325d7f4f1 fix 优化删除代码 2023-09-22 10:30:04 +08:00
jxxghp
3926298907 Merge pull request #642 from developer-wlj/wlj0909 2023-09-22 09:46:27 +08:00
mayun110
d98376b490 filter_torrents_by_default_rule方法 添加参数和返回值声明 2023-09-22 09:45:23 +08:00
mayun110
219690afc0 fix 在搜索模式中 默认过滤规则无效问题 2023-09-22 09:10:58 +08:00
jxxghp
bcb1fc1600 fix memory 2023-09-21 23:12:06 +08:00
jxxghp
923be7e1e9 feat 历史记录删除支持删除源文件 2023-09-21 19:59:29 +08:00
jxxghp
951353ee0b Merge pull request #634 from thsrite/main 2023-09-21 12:34:17 +08:00
thsrite
52bdfa7f9a feat 媒体服务器同步黑名单 2023-09-21 12:08:09 +08:00
jxxghp
4af29aa76d Merge pull request #632 from Sowevo/main 2023-09-21 10:04:48 +08:00
Sowevo
8efa6a742b Merge branch 'jxxghp:main' into main 2023-09-20 21:02:31 -05:00
sowevo
ada5e1cca5 feat: plex更精准的媒体库刷新 2023-09-21 10:01:48 +08:00
jxxghp
859191203f Merge pull request #630 from thsrite/main 2023-09-21 09:09:36 +08:00
thsrite
cab4055315 fix #629 2023-09-21 09:08:53 +08:00
jxxghp
cacee7abfe - 修复删除媒体库文件时范围过大的问题,v1.2.3版本需要升级! 2023-09-20 16:26:46 +08:00
jxxghp
61694f4c2b Merge pull request #626 from thsrite/main 2023-09-20 16:14:38 +08:00
thsrite
9c328e3d1c fix #625 2023-09-20 16:11:53 +08:00
jxxghp
b2fe86c744 v1.2.3
- 优先级规则现可以按订阅和搜索分别设置
- 中文字幕过滤规则只针对原语种为非中文生效
2023-09-20 06:52:31 +08:00
jxxghp
600e32d3e4 更新 __init__.py 2023-09-19 23:29:35 +08:00
jxxghp
3ad733bab4 Merge remote-tracking branch 'origin/main' 2023-09-19 21:40:52 +08:00
jxxghp
1799b63abb feat 优先级规则按订阅和搜索拆分 2023-09-19 21:40:36 +08:00
jxxghp
d71dc13e32 Merge pull request #621 from developer-wlj/wlj0909 2023-09-19 18:21:47 +08:00
mayun110
f4633788e9 Merge remote-tracking branch 'origin/wlj0909' into wlj0909 2023-09-19 18:14:47 +08:00
jxxghp
2250e7db39 Merge remote-tracking branch 'origin/main' 2023-09-19 17:15:26 +08:00
jxxghp
b1bb0ced7a fix #608 2023-09-19 17:15:16 +08:00
jxxghp
28aecd79c6 Merge pull request #612 from thsrite/main
fix #553 修复unraid删除资源慢的问题
2023-09-19 17:08:24 +08:00
thsrite
d097ef45eb fix 当前路径下没有媒体文件则删除 2023-09-19 16:44:20 +08:00
thsrite
dac718edc8 fix 7a5d2101 2023-09-19 16:15:05 +08:00
mayun110
598ab23a2c 优化Windows下Cloudflare IP优选插件 2023-09-19 13:39:41 +08:00
jxxghp
8be6e28933 feat 中文字幕过滤规则只针对原语种为非中文 2023-09-19 12:42:10 +08:00
mayun110
bd6805be58 优化Windows下Cloudflare IP优选插件 2023-09-19 11:45:06 +08:00
thsrite
c147d36cb2 fix 资源下载msg增加下载用户 2023-09-19 11:15:14 +08:00
thsrite
7a5d210167 fix #553 修复unraid删除资源慢的问题 2023-09-19 09:17:48 +08:00
mayun110
ef335f2b8e Cloudflare IP优选新增windows支持 2023-09-19 00:02:59 +08:00
jxxghp
19eca11d17 Merge pull request #616 from thsrite/fix 2023-09-18 18:33:42 +08:00
thsrite
ab99bd356a fix iyuuautoseed 2023-09-18 18:32:19 +08:00
jxxghp
70f2d72532 Merge pull request #615 from thsrite/fix 2023-09-18 18:29:43 +08:00
thsrite
0ca995da0f fix #613 2023-09-18 18:25:52 +08:00
jxxghp
2a67abe62d v1.2.2
- 修复了RSS模式指定订阅站点时不刷新订阅的问题
- 推荐页面后退时会记住浏览位置
- 订阅及搜索支持设置全局包含和排除规则
2023-09-18 17:13:51 +08:00
jxxghp
03a07ac7bf fix RSS模式指定订阅站点时不刷新订阅的问题 2023-09-18 17:05:08 +08:00
jxxghp
f104c903ec Merge pull request #611 from thsrite/main 2023-09-18 11:38:00 +08:00
thsrite
6b74a8e266 fix 插件站点排序、删除 2023-09-18 10:30:28 +08:00
thsrite
cadd885dbf fix #592 2023-09-18 10:29:27 +08:00
jxxghp
7e0cad8491 fix 2023-09-17 19:49:21 +08:00
jxxghp
4c05e9fb2b Merge pull request #609 from WithdewHua/subscribe 2023-09-17 18:59:42 +08:00
WithdewHua
42311f0118 feat: 订阅搜索支持默认包含与排除规则 2023-09-17 18:35:31 +08:00
WithdewHua
951be74a21 fix: 函数命名 2023-09-17 18:35:31 +08:00
jxxghp
c86a21d11d Merge pull request #604 from WithdewHua/subscribe 2023-09-16 20:31:42 +08:00
WithdewHua
3fb02f6490 feat: 增加更新订阅 tmdb 信息 API 2023-09-16 19:36:49 +08:00
WithdewHua
ca2c0392bb fix: 调整 API 顺序,避免错误匹配 2023-09-16 18:43:33 +08:00
WithdewHua
b8663ee735 fix: 同时更新电影订阅信息;修复 typo 2023-09-16 16:16:39 +08:00
WithdewHua
4ab60423c1 feat: 根据原标题查询媒体服务器(plex) 2023-09-16 15:48:22 +08:00
jxxghp
1ea80e6870 更新 README.md 2023-09-16 10:58:33 +08:00
jxxghp
6f1d4754be Merge pull request #600 from DDS-Derek/main 2023-09-16 08:28:56 +08:00
DDSRem
52288d98c0 bump: action jobs version
docker/metadata-action@v5
docker/setup-qemu-action@v3
docker/setup-buildx-action@v3
docker/login-action@v3
docker/build-push-action@v5

Co-Authored-By: DDSDerek <108336573+DDSDerek@users.noreply.github.com>
Co-Authored-By: DDSTomo <142158217+ddstomo@users.noreply.github.com>
2023-09-15 20:18:28 +08:00
jxxghp
d1368c4f84 fix bug 2023-09-15 17:28:35 +08:00
jxxghp
4367c53bb0 fix bug 2023-09-15 17:24:22 +08:00
jxxghp
d87f69da35 fix azusa 2023-09-15 16:07:01 +08:00
jxxghp
5ece44090e fix 2023-09-15 15:38:30 +08:00
jxxghp
01be4f9549 need test 2023-09-15 15:37:05 +08:00
jxxghp
94077917f3 Merge remote-tracking branch 'origin/main' 2023-09-15 15:22:19 +08:00
jxxghp
8af981738c fix README.md 2023-09-15 15:22:11 +08:00
jxxghp
4d7982803e Merge pull request #596 from thsrite/main
fix 辅种插件增加不辅种路径
2023-09-15 15:15:55 +08:00
thsrite
a1bba6da4a fix 辅种插件增加不辅种路径 2023-09-15 15:08:15 +08:00
jxxghp
4eb3e16b37 v1.2.1
- 修复了IOS下菜单栏需要点击两次的问题
- 修复了电影洗版重复下载的问题
- 站点新增支持ptlsp、azusa
- 认证站点新增支持ptlsp
- 仿真签到增加判断签到状态
2023-09-15 15:04:18 +08:00
jxxghp
1f0b40fe05 support ptlsp 2023-09-15 14:29:15 +08:00
jxxghp
29e92a17e7 support azusa 2023-09-15 14:01:12 +08:00
jxxghp
8cc4469282 fix #591 2023-09-15 10:59:46 +08:00
jxxghp
a5e66071ba support PTLSP 2023-09-15 10:46:54 +08:00
jxxghp
fb4e817993 fix #594 2023-09-15 10:38:15 +08:00
jxxghp
8f26110e65 Merge pull request #590 from thsrite/main 2023-09-14 16:19:46 +08:00
thsrite
9f65a088c0 fix 插件交互命令增加channel字段 2023-09-14 16:09:56 +08:00
jxxghp
15c15388b6 Merge pull request #589 from thsrite/main 2023-09-14 15:34:49 +08:00
thsrite
950a43e001 fix 每日签到记录存储bug 2023-09-14 15:28:06 +08:00
jxxghp
9a28f8c365 Merge pull request #588 from thsrite/main 2023-09-14 15:18:43 +08:00
thsrite
32cb96fc44 fix 仿真签到判断是否已签 2023-09-14 15:17:30 +08:00
jxxghp
f7982e3e43 fix build 2023-09-14 11:36:37 +08:00
jxxghp
d13602827c fix build 2023-09-14 11:30:22 +08:00
jxxghp
182adc77b6 v1.2.0
- 修复了 QB4.5+ 转种到 TR3.0 丢失tracker的问题
- 站点新增支持byr、hdcity、okpt
- RSS订阅模式时自动检测是否失效并更新链接地址
- 自定义订阅插件支持磁力链接下载
- 增加了自定义识别词支持的配置格式:被替换词 => 替换词 && 前定位词 <> 后定位词 >> 集偏移量
- 媒体库同步删除插件支持多版本文件处理
2023-09-14 11:17:10 +08:00
jxxghp
ef4cdb41c8 fix release 2023-09-14 10:07:20 +08:00
jxxghp
9a60121914 fix #579 修改转种使用的模块 2023-09-14 09:46:51 +08:00
jxxghp
6fb0c92183 fix message content 2023-09-14 09:18:11 +08:00
jxxghp
96c4e0ba2f Merge remote-tracking branch 'origin/main' 2023-09-14 09:09:43 +08:00
jxxghp
7afe82480c fix brush 2023-09-14 09:08:57 +08:00
jxxghp
c37c8e7318 Merge pull request #583 from thsrite/main 2023-09-13 21:41:48 +08:00
thsrite
3d10ca4c8b fix 签到数量 2023-09-13 20:19:06 +08:00
jxxghp
4e515ec442 fix #516 支持磁力链下载 2023-09-13 17:56:57 +08:00
jxxghp
5eb37b5d28 fix sites 2023-09-13 16:58:05 +08:00
jxxghp
7f95bab0d5 fix #578 2023-09-13 16:12:57 +08:00
jxxghp
3fc267bcfa Merge pull request #578 from thsrite/main
fix 订阅刷新只处理订阅选中的站点(没选刷新所有设定的订阅站点)
2023-09-13 15:58:04 +08:00
jxxghp
648f0b6ec1 add byr、hdcity、okpt 2023-09-13 15:53:58 +08:00
thsrite
be3c3ef37f fix 订阅刷新站点 2023-09-13 15:52:32 +08:00
jxxghp
a47f382c21 fix download message 2023-09-13 15:18:23 +08:00
jxxghp
61c59b4405 fix #572 2023-09-13 14:58:33 +08:00
jxxghp
8ee391688d Merge pull request #575 from thsrite/main 2023-09-13 13:26:09 +08:00
thsrite
68c7bf0a96 Revert "fix"
This reverts commit 7c3c6ee999.
2023-09-13 13:10:11 +08:00
thsrite
6dd517a490 fix 自定义识别词空格 2023-09-13 12:45:44 +08:00
jxxghp
9baa5e1d35 Merge pull request #574 from thsrite/main 2023-09-13 12:36:13 +08:00
thsrite
e675e4358a fix 同步删除插件 2023-09-13 12:35:09 +08:00
jxxghp
c9a6081a57 fix log 2023-09-13 12:30:45 +08:00
jxxghp
2de20f601b fix 开关位置 2023-09-13 12:23:32 +08:00
jxxghp
79c708c30e Merge pull request #564 from thsrite/main 2023-09-13 12:04:09 +08:00
thsrite
f38defb515 Revert "fix 卸载插件时删除插件配置"
This reverts commit dd7803c90a.
2023-09-13 11:58:37 +08:00
thsrite
ac11d4eb30 Revert "fix dd7803c9"
This reverts commit 08560fc7c3.
2023-09-13 11:58:30 +08:00
thsrite
221c31f481 fix 自定义识别词增加规则:被替换词 => 替换词 && 偏移前 <> 偏移后 >> 集偏移 2023-09-13 10:37:13 +08:00
thsrite
7c3c6ee999 fix 2023-09-13 09:52:05 +08:00
thsrite
08560fc7c3 fix dd7803c9 2023-09-13 09:29:52 +08:00
thsrite
4659e7367f fix d8afa339 函数参数名 2023-09-13 09:24:16 +08:00
thsrite
2fa11a4796 Merge remote-tracking branch 'origin/main' 2023-09-13 09:22:29 +08:00
thsrite
01a153902e Revert "fix 自定义订阅插件增加识别按钮"
This reverts commit 1b2f09b95f.
2023-09-13 09:21:56 +08:00
jxxghp
5eb65046f0 Merge pull request #571 from WithdewHua/media_exists 2023-09-13 06:36:22 +08:00
WithdewHua
bb64e57f7c fix: 检查媒体文件是否存在时验证 TMDB ID 2023-09-12 23:03:15 +08:00
thsrite
0cb75d689c fix 根据type和tmdbid查询转移记录 2023-09-12 15:28:21 +08:00
thsrite
d7310ade86 fix 同步删除插件兼容多分辨率 2023-09-12 15:21:34 +08:00
thsrite
dd7803c90a fix 卸载插件时删除插件配置 2023-09-12 14:57:31 +08:00
thsrite
d8afa339de fix 媒体库刮削插件开启强制刮削时忽略SCRAP_METADATA变量 2023-09-12 13:29:12 +08:00
thsrite
1b2f09b95f fix 自定义订阅插件增加识别按钮 2023-09-12 12:45:39 +08:00
jxxghp
0414854832 Merge pull request #562 from thsrite/main 2023-09-12 11:47:57 +08:00
thsrite
9e6a7be5b1 fix #537 天空辅种失败问题 2023-09-12 11:45:57 +08:00
thsrite
e3c1407b62 fix 憨憨用户等级 2023-09-12 11:26:45 +08:00
thsrite
7a9ee954c5 fix sub正则 2023-09-12 11:11:36 +08:00
thsrite
99a06dcba0 fix rss过期,尝试保留原配置生成新的rss地址 2023-09-12 10:09:17 +08:00
jxxghp
bb8fc14bc6 v1.1.9
- 修复了部分情况下媒体识别错误的问题
- 站点新增支持dajiao、ptcafe
- 支持RSS订阅模式,RSS模式会自动获取RSS链接(也可手动维护),订阅刷新对站点压力小,同时可设置订阅刷新周期,24小时运行,可通过开关切换。
- 移除了自定义订阅功能,可使用RSS订阅模式或使用自定义订阅插件替代。
- 手动整理时支持通过名称搜索TMDBID。
2023-09-12 08:07:03 +08:00
jxxghp
50d9dcf17b fix #556 2023-09-12 07:36:29 +08:00
jxxghp
141b99d134 fix #556 2023-09-12 07:22:06 +08:00
jxxghp
18457a4de7 fix #555 2023-09-11 21:43:30 +08:00
jxxghp
a343d736ae fix #550 2023-09-11 21:25:56 +08:00
jxxghp
df5c364185 fix #550 2023-09-11 21:14:49 +08:00
jxxghp
edcec114ae fix bug 2023-09-11 19:54:38 +08:00
jxxghp
605a7486b3 fix log 2023-09-11 19:10:51 +08:00
jxxghp
efe89f59b9 feat 支持dajiao、ptcafe 2023-09-11 18:10:50 +08:00
jxxghp
fdd4aef3d3 feat 整合RSS订阅模式 2023-09-11 17:47:51 +08:00
jxxghp
08aef1f47f fix rsslink helper 2023-09-11 17:13:26 +08:00
jxxghp
c45f5e6ac4 Merge pull request #549 from thsrite/main
feat 自动生成站点默认rss地址
2023-09-11 16:35:36 +08:00
thsrite
f239cede07 fix speedlimit 未开启时return 2023-09-11 16:14:15 +08:00
thsrite
b2eb952cd0 fix 自动获取rss使用代理 2023-09-11 13:15:15 +08:00
thsrite
3a2fba0422 fix 自动获取rss data 2023-09-11 12:43:27 +08:00
thsrite
1034caa9fd fix ttg、zhuque等自动获取rss 2023-09-11 12:26:23 +08:00
thsrite
8b243e23ab feat 自动生成默认rss地址 2023-09-11 11:39:39 +08:00
jxxghp
1f76dc1e2a Merge pull request #540 from thsrite/main 2023-09-10 20:22:25 +08:00
thsrite
ea5c2fb4cf fix 限速插件每次重启完发送取消限速消息 2023-09-10 20:08:09 +08:00
thsrite
e50b56d542 fix 交互命令翻页下载 2023-09-10 19:51:20 +08:00
jxxghp
2206fafda9 Merge pull request #539 from thsrite/main 2023-09-10 18:45:33 +08:00
thsrite
345b74d881 fix #538 2023-09-10 18:41:04 +08:00
jxxghp
d231d75446 v1.1.8
- 修复了Jellyfin/Plex的webhook通知消息
- 修复了手动整理时屏蔽词不生效的问题
- 优化了剧集的年份匹配
- 优化了站点种子的索引频率控制
- 增加了站点分享率低时的信息提醒
- 增加了重启系统的远程交互命令
2023-09-10 17:43:04 +08:00
jxxghp
afb5874350 fix #536 2023-09-10 17:35:58 +08:00
jxxghp
1bd7b5c77e fix jellyfin webhook 2023-09-10 17:07:24 +08:00
jxxghp
ba41de61cb fix plex webhook 2023-09-10 12:57:51 +08:00
jxxghp
ae40d32115 fix bug 2023-09-10 09:15:12 +08:00
jxxghp
3fe4c9467e fix 2023-09-10 09:06:00 +08:00
jxxghp
b89512cc33 fix #526 2023-09-10 09:02:46 +08:00
jxxghp
f3b12bed20 feat 分享率低通知预警 2023-09-10 08:54:33 +08:00
jxxghp
08c7fff5ab fix README.md 2023-09-10 08:32:52 +08:00
jxxghp
9c20d1a270 Merge pull request #530 from thsrite/main
feat 补充剧集全部季年份
2023-09-09 22:06:58 +08:00
thsrite
b7b1aee878 fix 2023-09-09 22:03:51 +08:00
jxxghp
f998b39152 fix 删除种子数无法计算 2023-09-09 21:58:49 +08:00
jxxghp
ca01db31a9 fix LIBRARY_PATH 2023-09-09 21:41:55 +08:00
thsrite
a0b8cc6719 feat 补充剧集全部季年份 2023-09-09 21:24:07 +08:00
jxxghp
66b91abe90 fix sites.cpython-311-darwin 2023-09-09 20:58:52 +08:00
jxxghp
9b17d55ac0 fix db session 2023-09-09 20:56:37 +08:00
jxxghp
a7a0889867 Merge pull request #528 from thsrite/main 2023-09-09 20:17:09 +08:00
thsrite
af6cf306c8 fix 交互命令重启 2023-09-09 20:01:43 +08:00
jxxghp
20f35854f9 fix update 2023-09-09 19:43:02 +08:00
jxxghp
e5165c8fea fix plugin db session 2023-09-09 19:41:06 +08:00
jxxghp
0e36d003c0 fix db session 2023-09-09 19:26:56 +08:00
jxxghp
ccc249f29d Merge pull request #527 from developer-wlj/wlj0909 2023-09-09 18:31:27 +08:00
mayun110
f4edb32886 fix Windows目录监控下获取目录问题 2023-09-09 18:11:50 +08:00
jxxghp
475a84bfa6 Merge pull request #525 from thsrite/main 2023-09-09 17:53:29 +08:00
mayun110
3914ff4dd6 fix Windows下获取目录问题 2023-09-09 17:49:40 +08:00
jxxghp
5bcbacf3a5 feat torrents全局缓存共享 2023-09-09 17:42:31 +08:00
jxxghp
27238ac467 fix brushflow plugin 2023-09-09 16:49:15 +08:00
thsrite
019d40c17a fix 辅种插件排除已删除站点 2023-09-09 16:40:09 +08:00
jxxghp
fa5b92214f fix ssd 2023-09-09 16:24:53 +08:00
jxxghp
32a5f67e72 Merge pull request #524 from thsrite/main 2023-09-09 15:56:02 +08:00
thsrite
d6e9c14183 fix qb删种 2023-09-09 15:47:51 +08:00
jxxghp
87325d5bbd Merge pull request #523 from thsrite/main 2023-09-09 15:07:53 +08:00
thsrite
67ead871c1 fix 删除清除缓存按钮 2023-09-09 15:06:44 +08:00
jxxghp
691beb1186 Merge pull request #522 from DDS-Derek/main 2023-09-09 14:57:02 +08:00
jxxghp
b30d3c7dac Merge pull request #521 from WithdewHua/rsssubscribe 2023-09-09 14:55:41 +08:00
DDSRem
5e048f0150 feat: 优化容器id获取 2023-09-09 14:18:10 +08:00
WithdewHua
cb2cfe9d85 fix: 关闭清理缓存开关 2023-09-09 14:13:17 +08:00
jxxghp
482fca9b8c Merge pull request #520 from DDS-Derek/main
fix: failed to obtain container id
2023-09-09 12:08:50 +08:00
DDSRem
42511b95d8 fix: failed to obtain container id 2023-09-09 12:03:48 +08:00
jxxghp
b18e901fbd fix plugin ui 2023-09-09 11:37:34 +08:00
jxxghp
a30e3f49a3 v1.1.7
- 修复了文件转移无法覆盖的问题
- 修复了过滤规则只能从尾部开始删除的问题
- 优化了内建重启,支持非root权限环境(需要重拉镜像)
- 文件管理功能支持排序
- 优化了插件页面交互,优先展示插件数据
2023-09-09 11:08:45 +08:00
jxxghp
65d202e636 fix README.md 2023-09-09 10:51:59 +08:00
jxxghp
4373c0596b Merge pull request #518 from DDS-Derek/main
fix: port conflict
2023-09-09 10:45:54 +08:00
DDSRem
0136d9fe06 fix: port conflict 2023-09-09 10:44:05 +08:00
jxxghp
933c6d838c fix #497 2023-09-09 08:27:40 +08:00
jxxghp
7ce656148f fix #508 2023-09-09 08:19:17 +08:00
jxxghp
c05ffed6df fix #514 文件管理支持排序 2023-09-09 08:00:17 +08:00
jxxghp
6770ba3a35 feat 文件管理API排序 2023-09-08 22:48:53 +08:00
jxxghp
3b73dfcdc6 fix 文件转移时无法覆盖 2023-09-08 22:36:31 +08:00
jxxghp
100ff97017 Merge pull request #515 from thsrite/main 2023-09-08 21:49:49 +08:00
thsrite
4fe96178ee fix 2023-09-08 21:44:32 +08:00
thsrite
86d484fac0 fix 2023-09-08 21:41:30 +08:00
thsrite
db23b62fd1 fix 2023-09-08 21:31:36 +08:00
jxxghp
b84c8fd7f1 Merge pull request #512 from thsrite/main 2023-09-08 21:29:46 +08:00
jxxghp
c9f6c75069 Merge pull request #510 from DDS-Derek/main 2023-09-08 21:26:00 +08:00
thsrite
846459c244 fix wechat token 2023-09-08 21:21:43 +08:00
DDSRem
c4898d04aa docs: update 2023-09-08 20:38:07 +08:00
DDSRem
c8bc6a4618 fix: 重启更新 2023-09-08 20:33:23 +08:00
DDSRem
55dce26cb8 test: restart 2023-09-08 19:55:03 +08:00
DDSRem
ae3b73a73f feat: 优化重启 2023-09-08 19:49:10 +08:00
jxxghp
091df01b7c fix plugin 2023-09-08 16:48:13 +08:00
jxxghp
20c4c7d6e6 add 发布时间 2023-09-08 16:36:02 +08:00
jxxghp
eb1e045d8f Merge remote-tracking branch 'origin/main' 2023-09-08 15:38:38 +08:00
jxxghp
678638e9f1 feat 插件API 2023-09-08 15:38:32 +08:00
jxxghp
d8b78d3051 Merge pull request #505 from thsrite/main
fix 消息转发插件清理缓存按钮
2023-09-08 13:15:45 +08:00
thsrite
eaf0d17118 fix 消息转发插件清理缓存按钮 2023-09-08 13:13:11 +08:00
jxxghp
81bcfef6ec Merge pull request #504 from thsrite/main 2023-09-08 13:11:13 +08:00
thsrite
0997691b23 fix time format 2023-09-08 13:06:40 +08:00
jxxghp
d1f9647a63 Merge pull request #503 from thsrite/main
feat 签到插件支持分别配置签到、登录站点
2023-09-08 12:26:15 +08:00
thsrite
64a04ba8ed fix 2023-09-08 12:24:27 +08:00
jxxghp
726c130f1f Merge remote-tracking branch 'origin/main' 2023-09-08 12:23:29 +08:00
jxxghp
215b56b9f2 feat 打印jellyfin/plex webhook报文 2023-09-08 12:23:19 +08:00
thsrite
516bd8bc30 Merge remote-tracking branch 'origin/main' 2023-09-08 12:21:38 +08:00
thsrite
8bc6e04665 feat 签到插件支持分别配置签到、登录站点 2023-09-08 12:21:29 +08:00
jxxghp
94057cd5f1 Merge pull request #499 from thsrite/main 2023-09-08 11:24:49 +08:00
thsrite
2e80586436 Merge branch 'jxxghp:main' into main 2023-09-08 11:22:42 +08:00
thsrite
faa6d7dadd fix bug 2023-09-08 11:20:25 +08:00
jxxghp
071c81d52c v1.1.6
- 修复了一个未设置媒体服务器时订阅日志报错的问题
- 媒体库刮削插件支持覆盖已有元数据和图片
- 新增了一个沿用已有刮削名称的开关(默认开),避免TMDB信息变化时导致整理后名称不一致
- 刮削时季的海报优先使用TMDB的图片
- 增加了内建重启失败时的提示
2023-09-08 11:01:37 +08:00
jxxghp
52d4feb583 Update README.md 2023-09-08 10:45:55 +08:00
jxxghp
584e05e63e fix ui 2023-09-08 10:34:05 +08:00
jxxghp
061ff322ab fix bug 2023-09-08 10:26:00 +08:00
jxxghp
a2bcf8df9a Merge remote-tracking branch 'origin/main' 2023-09-08 10:03:23 +08:00
jxxghp
6c85040eb6 fix plugin 2023-09-08 10:03:14 +08:00
jxxghp
2e5d892120 fix plugin 2023-09-08 09:44:51 +08:00
jxxghp
43d108aea9 Merge pull request #498 from thsrite/main 2023-09-08 09:44:07 +08:00
thsrite
c46b1dd116 fix 消息转发插件bug 2023-09-08 09:22:59 +08:00
jxxghp
d3fac56e9a fix 2023-09-08 08:05:54 +08:00
jxxghp
b3f5b87b02 fix 2023-09-08 08:04:09 +08:00
jxxghp
03abdf9cb4 fix 2023-09-08 07:52:05 +08:00
jxxghp
42bc354e06 fix 2023-09-08 07:39:08 +08:00
jxxghp
02e81a79b2 fix 2023-09-07 23:11:08 +08:00
jxxghp
9fa4b8dfbe fix 2023-09-07 23:04:35 +08:00
jxxghp
366f59623a fix 2023-09-07 23:00:51 +08:00
jxxghp
d4c28500b7 fix plugin 2023-09-07 22:04:07 +08:00
jxxghp
5780344c43 fix 2023-09-07 20:19:03 +08:00
jxxghp
18970efc1a add index 2023-09-07 18:23:43 +08:00
jxxghp
5725584176 add index 2023-09-07 18:23:30 +08:00
jxxghp
4e26168ab5 fix plugin 2023-09-07 17:40:09 +08:00
jxxghp
f694dee71d fix 2023-09-07 16:16:04 +08:00
jxxghp
a9db0f6bbf fix 2023-09-07 16:05:48 +08:00
jxxghp
7efcde89b9 fix 2023-09-07 14:59:32 +08:00
jxxghp
1c07b306c3 Merge pull request #489 from thsrite/main
fix 目录监控已处理逻辑 && feat 新增已入库媒体是否跟随TMDB信息变化开关,关闭则延用媒体库名称
2023-09-07 14:29:08 +08:00
jxxghp
6c59a5ebb0 Merge branch 'main' into main 2023-09-07 14:29:01 +08:00
thsrite
4c7321a738 fix 2023-09-07 13:57:27 +08:00
jxxghp
f42fd023bb fix #490 2023-09-07 13:39:08 +08:00
jxxghp
9b8a4ebdd4 fix 2023-09-07 12:56:39 +08:00
jxxghp
443e2d8104 fix 减少刮削识别次数 2023-09-07 12:51:49 +08:00
jxxghp
2c61d439ca feat 媒体库刮削支持覆盖
fix 类型声明
2023-09-07 12:35:35 +08:00
thsrite
e01268222c fix 2023-09-07 12:27:04 +08:00
thsrite
27ff77b504 fix type 2023-09-07 12:25:01 +08:00
thsrite
bf8893d71b fix 文件所在文件夹重新刮削bug 2023-09-07 11:16:11 +08:00
thsrite
54b09a17c2 fix 2023-09-07 11:12:16 +08:00
thsrite
b01621049b feat 新增已入库媒体是否跟随TMDB信息变化开关,关闭则延用媒体库名称 2023-09-07 10:55:01 +08:00
thsrite
e5dc40e3c1 fix token过期后重新获取、重新发送请求 2023-09-07 10:24:21 +08:00
thsrite
44d4bcdd19 fix 目录监控已处理逻辑 2023-09-07 10:16:44 +08:00
jxxghp
b899b23d04 fix 2023-09-07 08:37:57 +08:00
jxxghp
fa23012adb fix #486 季图片优先使用TMDB的 2023-09-07 08:03:05 +08:00
jxxghp
d836b385ae fix 2023-09-07 07:20:10 +08:00
jxxghp
15a0bc6c12 fix 重启失败提示 2023-09-06 21:48:09 +08:00
jxxghp
22791e361d 更新 README.md 2023-09-06 21:41:23 +08:00
jxxghp
47b7dade5d Merge pull request #484 from thsrite/main 2023-09-06 21:23:32 +08:00
thsrite
c57d13afcc fix 优化同步删除插件msg 2023-09-06 21:21:00 +08:00
jxxghp
8db1c2952c Merge remote-tracking branch 'origin/main' 2023-09-06 21:15:21 +08:00
jxxghp
28c19bc4e3 fix 优化文件整理进度提示 2023-09-06 21:15:10 +08:00
jxxghp
fbef1735b0 Merge pull request #482 from thsrite/main
fix bug
2023-09-06 20:19:44 +08:00
thsrite
9869af992b fix bug 2023-09-06 20:18:43 +08:00
jxxghp
b6cb241b8a Merge pull request #480 from WPF0414/main
fix:限速通知速率展示问题
2023-09-06 20:09:02 +08:00
jxxghp
7edf8e7c30 Merge pull request #481 from thsrite/main
fix 删除辅种bug
2023-09-06 20:07:42 +08:00
thsrite
452161f1b8 fix 删除辅种bug 2023-09-06 20:05:29 +08:00
jxxghp
f75abb27b6 v1.1.5
- 修复了批量整理时只刮削第一个文件的问题
- 修复了多下载任务同一下载目录时会重复处理文件的问题
- 支持在WEB页面操作重启(需要映射`/var/run/docker.sock`文件到容器)
2023-09-06 19:54:23 +08:00
wangpengfei
30311e8e56 fix:限速通知
修复限速时通知错误问题
2023-09-06 19:50:18 +08:00
jxxghp
adff3b22e9 Merge pull request #476 from thsrite/main
fix 媒体库同步删除插件优化
2023-09-06 16:55:10 +08:00
thsrite
013c0dea3b fix NAStool同步插件不处理download_hash 2023-09-06 16:22:32 +08:00
jxxghp
c593c3ba16 fix #461 已转移成功的文件不重复处理 2023-09-06 16:12:40 +08:00
jxxghp
61b74735de fix #464 2023-09-06 16:00:42 +08:00
thsrite
952cae50e2 fix 同步删除插件删种逻辑 2023-09-06 15:57:46 +08:00
thsrite
7a9f89e86c fix 删除同步删除插件交互命令 2023-09-06 15:34:35 +08:00
jxxghp
f14d8bec1b fix api 2023-09-06 15:29:52 +08:00
thsrite
697d5a815b fix 标题不一致时防误删 2023-09-06 15:07:06 +08:00
thsrite
cfeaa2674d fix 媒体库同步删除插件优化 2023-09-06 14:26:24 +08:00
jxxghp
08f046f059 fix #465 批量转移时只刮削一个文件的问题 2023-09-06 13:04:18 +08:00
jxxghp
a66912f41a fix #465 批量转移时只刮削一个文件的问题 2023-09-06 13:01:13 +08:00
jxxghp
f244728a96 Merge remote-tracking branch 'origin/main' 2023-09-06 12:56:04 +08:00
jxxghp
576ac08a05 feat 内建重启 2023-09-06 12:55:48 +08:00
jxxghp
e874b3f294 Merge pull request #474 from thsrite/main
fix NAStool记录同步增加进度…
2023-09-06 11:34:13 +08:00
thsrite
90ff0fc793 fix NAStool记录同步增加进度… 2023-09-06 11:32:34 +08:00
jxxghp
259e8fc2e1 fix #463 2023-09-06 11:29:47 +08:00
jxxghp
5c0be93913 Merge pull request #471 from thsrite/main 2023-09-06 10:47:21 +08:00
thsrite
e84a5c74f6 fix 同步删除插件防重复消费 2023-09-06 09:37:02 +08:00
jxxghp
5145527d0e fix #456 2023-09-06 08:34:04 +08:00
jxxghp
e3f7f873c0 Merge pull request #462 from WPF0414/main 2023-09-05 22:38:21 +08:00
wangpengfei
84a2db2247 Update __init__.py
修复按比例的bug
2023-09-05 22:35:39 +08:00
jxxghp
4902d5ebed feat 本地文件系统判重 2023-09-05 20:32:38 +08:00
jxxghp
243391ee30 fix release 2023-09-05 19:57:24 +08:00
jxxghp
c424de65b3 - 修复了站点数据统计某些情况下不发消息的问题
- 修复了播放限速TR不生效的问题
- 优化了下载器文件同步插件
- 优化了数据库异常处理
- 媒体库同步删除插件支持Emby Webhook方式。
- 微信现在会自动添加交互操作菜单了
- 新增了一套UI主题配色
2023-09-05 19:52:46 +08:00
jxxghp
2077eede8c Merge pull request #459 from thsrite/main 2023-09-05 19:48:27 +08:00
thsrite
876d1e01b4 fix 签到插件strip 2023-09-05 19:33:27 +08:00
thsrite
dec022fd89 fix 同步删除插件 2023-09-05 19:30:46 +08:00
jxxghp
83829cbe27 Merge pull request #458 from thsrite/main 2023-09-05 19:08:41 +08:00
thsrite
8249f9356f fix 同步删除插件适配emby webhook方式! 2023-09-05 19:07:07 +08:00
jxxghp
b5fc6cdd1e fix 统一处理db事务回滚 2023-09-05 18:19:02 +08:00
jxxghp
51b959cff8 Merge remote-tracking branch 'origin/main' 2023-09-05 17:11:09 +08:00
jxxghp
36880a8b7d fix 下载文件记录只登记选中的文件 2023-09-05 17:11:02 +08:00
jxxghp
380cc7552f Merge pull request #453 from thsrite/main
fix 同步插件路径替换
2023-09-05 16:57:04 +08:00
thsrite
0f1c8cb226 Merge branch 'jxxghp:main' into main 2023-09-05 16:55:08 +08:00
thsrite
7435fb0c10 fix tr文件同步过滤掉未下载的文件 2023-09-05 16:52:02 +08:00
jxxghp
1a03981463 fix #193 2023-09-05 16:43:34 +08:00
jxxghp
4cb7a488a9 fix #193 2023-09-05 16:43:02 +08:00
jxxghp
c69762d4c9 fix #448 TR限速不生效的问题 2023-09-05 16:35:15 +08:00
thsrite
03d9bf6d05 fix 路径替换 2023-09-05 16:20:42 +08:00
jxxghp
6a08b4ba7f fix 提高DB连接等待时间,避免database locked报错。 2023-09-05 16:18:04 +08:00
jxxghp
99218515ea fix 部分数据库操作没有Commit 2023-09-05 16:12:43 +08:00
jxxghp
c3a0a839c3 Merge pull request #450 from thsrite/main
fix 交互命令消息原路返回
2023-09-05 13:39:14 +08:00
thsrite
351513bcbc fix 交互命令消息原路返回 2023-09-05 13:19:25 +08:00
jxxghp
ed5dec1b0f feat 种子刷新频率控制 2023-09-05 12:39:01 +08:00
jxxghp
c62b29edc4 fix 微信菜单 2023-09-05 11:54:16 +08:00
jxxghp
c224a7c07b fix bug 2023-09-05 11:52:46 +08:00
jxxghp
a7b244a4b4 fix README.md 2023-09-05 11:48:36 +08:00
jxxghp
b564f70c63 feat 微信自动注册菜单 2023-09-05 11:33:42 +08:00
jxxghp
551f32491d fix 微信菜单长度 2023-09-05 11:23:21 +08:00
jxxghp
2826b9411d fix bug 2023-09-05 11:20:06 +08:00
jxxghp
4bf9045784 fix bug 2023-09-05 11:01:12 +08:00
jxxghp
114788e3ed feat 微信自动注册菜单 2023-09-05 10:58:19 +08:00
jxxghp
bb729bf976 fix #442 2023-09-05 08:39:23 +08:00
jxxghp
bedc885232 Merge pull request #440 from amtoaer/memory_percent 2023-09-04 23:18:46 +08:00
amtoaer
21e39611bc feat: 内存占用图使用百分比 2023-09-04 23:07:39 +08:00
jxxghp
73e7e547ea Merge pull request #437 from thsrite/main 2023-09-04 22:22:40 +08:00
thsrite
bc25d71b88 fix #407 2023-09-04 22:21:03 +08:00
588 changed files with 117094 additions and 30658 deletions

View File

@@ -1,3 +1,84 @@
# Ignore git
# Git
.github
.git
.git
.gitignore
# Documentation
docs/
README.md
LICENSE
# Development files
.pylintrc
*.pyc
__pycache__/
*.pyo
*.pyd
.Python
*.so
.pytest_cache/
.coverage
htmlcov/
.tox/
.nox/
.hypothesis/
.mypy_cache/
.dmypy.json
dmypy.json
# Virtual environments
venv/
env/
ENV/
env.bak/
venv.bak/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Logs
*.log
logs/
# Temporary files
*.tmp
*.temp
tmp/
temp/
# Database
*.db
*.sqlite
*.sqlite3
# Test files
tests/
test_*
*_test.py
# Build artifacts
build/
dist/
*.egg-info/
# Docker
Dockerfile*
docker-compose*
.dockerignore
# Other
app.ico
frozen.spec

View File

@@ -9,8 +9,9 @@ body:
请确认以下信息:
1. 请按此模板提交issues不按模板提交的问题将直接关闭。
2. 如果你的问题可以直接在以往 issue 或者 Telegram频道 中找到,那么你的 issue 将会被直接关闭。
3. 提交问题务必描述清楚、附上日志,描述不清导致无法理解和分析的问题会被直接关闭。
3. **$\color{red}{提交问题务必描述清楚、附上日志}$**,描述不清导致无法理解和分析的问题会被直接关闭。
4. 此仓库为后端仓库,如果是前端 WebUI 问题请在[前端仓库](https://github.com/jxxghp/MoviePilot-Frontend)提 issue。
5. **$\color{red}{不要通过issues来寻求解决你的环境问题、配置安装类问题、咨询类问题}$**,否则直接关闭并加入用户 $\color{red}{黑名单}$ !实在没有精力陪一波又一波的伸手党玩。
- type: checkboxes
id: ensure
attributes:
@@ -32,6 +33,16 @@ body:
description: 遇到问题时程序所在的版本号
validations:
required: true
- type: dropdown
id: environment
attributes:
label: 运行环境
description: 当前程序运行环境
options:
- Docker
- Windows
validations:
required: true
- type: dropdown
id: type
attributes:
@@ -40,7 +51,6 @@ body:
options:
- 主程序运行问题
- 插件问题
- Docker或运行环境问题
- 其他问题
validations:
required: true

View File

@@ -14,6 +14,27 @@ body:
description: 目前使用的程序版本
validations:
required: true
- type: dropdown
id: environment
attributes:
label: 运行环境
description: 当前程序运行环境
options:
- Docker
- Windows
validations:
required: true
- type: dropdown
id: type
attributes:
label: 功能改进类型
description: 你需要在下面哪个方面改进功能
options:
- 主程序
- 插件
- 其他
validations:
required: true
- type: textarea
id: feature-request
attributes:

45
.github/ISSUE_TEMPLATE/rfc.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: 功能提案
description: Request for Comments
title: "[RFC]"
labels: ["RFC"]
body:
- type: markdown
attributes:
value: |
一份提案(RFC)定位为 **「在某功能/重构的具体开发前,用于开发者间 review 技术设计/方案的文档」**
目的是让协作的开发者间清晰的知道「要做什么」和「具体会怎么做」,以及所有的开发者都能公开透明的参与讨论;
以便评估和讨论产生的影响 (遗漏的考虑、向后兼容性、与现有功能的冲突)
因此提案侧重在对解决问题的 **方案、设计、步骤** 的描述上。
如果仅希望讨论是否添加或改进某功能本身,请使用 -> [Issue: 功能改进](https://github.com/jxxghp/MoviePilot/issues/new?assignees=&labels=feature+request&projects=&template=feature_request.yml&title=%5BFeature+Request%5D%3A+)
- type: textarea
id: background
attributes:
label: 背景 or 问题
description: 简单描述遇到的什么问题或需要改动什么。可以引用其他 issue、讨论、文档等。
validations:
required: true
- type: textarea
id: goal
attributes:
label: "目标 & 方案简述"
description: 简单描述提案此提案实现后,**预期的目标效果**,以及简单大致描述会采取的方案/步骤,可能会/不会产生什么影响。
validations:
required: true
- type: textarea
id: design
attributes:
label: "方案设计 & 实现步骤"
description: |
详细描述你设计的具体方案,可以考虑拆分列表或要点,一步步描述具体打算如何实现的步骤和相关细节。
这部份不需要一次性写完整,即使在创建完此提案 issue 后,依旧可以再次编辑修改。
validations:
required: false
- type: textarea
id: alternative
attributes:
label: "替代方案 & 对比"
description: |
[可选] 为来实现目标效果,还考虑过什么其他方案,有什么对比?
validations:
required: false

60
.github/workflows/beta.yml vendored Normal file
View File

@@ -0,0 +1,60 @@
name: MoviePilot Builder Beta
on:
workflow_dispatch:
jobs:
Docker-build:
runs-on: ubuntu-latest
name: Build Docker Image
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Release version
id: release_version
run: |
app_version=$(cat version.py |sed -ne "s/APP_VERSION\s=\s'v\(.*\)'/\1/gp")
echo "app_version=$app_version" >> $GITHUB_ENV
- name: Docker Meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ secrets.DOCKER_USERNAME }}/moviepilot-v2
ghcr.io/${{ github.repository }}
tags: |
type=raw,value=beta
- name: Set Up QEMU
uses: docker/setup-qemu-action@v3
- name: Set Up Buildx
uses: docker/setup-buildx-action@v3
- name: Login DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Image
uses: docker/build-push-action@v5
with:
context: .
file: docker/Dockerfile
platforms: |
linux/amd64
linux/arm64/v8
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha, scope=${{ github.workflow }}-docker
cache-to: type=gha, scope=${{ github.workflow }}-docker

View File

@@ -1,62 +1,201 @@
name: MoviePilot Builder
name: MoviePilot Builder v2
on:
workflow_dispatch:
push:
branches:
- main
- v2
paths:
- version.py
- 'version.py'
jobs:
build:
Docker-build:
runs-on: ubuntu-latest
name: Build Docker Image
steps:
-
name: Checkout
uses: actions/checkout@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
- name: Checkout
uses: actions/checkout@v4
with:
images: ${{ secrets.DOCKER_USERNAME }}/moviepilot
fetch-depth: 0
fetch-tags: true
-
name: Release version
- name: Release version
id: release_version
run: |
app_version=$(cat version.py |sed -ne "s/APP_VERSION\s=\s'v\(.*\)'/\1/gp")
echo "app_version=$app_version" >> $GITHUB_ENV
-
name: Set Up QEMU
uses: docker/setup-qemu-action@v2
- name: Docker Meta
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ secrets.DOCKER_USERNAME }}/moviepilot-v2
${{ secrets.DOCKER_USERNAME }}/moviepilot
ghcr.io/${{ github.repository }}
tags: |
type=raw,value=${{ env.app_version }}
type=raw,value=latest
-
name: Set Up Buildx
uses: docker/setup-buildx-action@v2
- name: Set Up QEMU
uses: docker/setup-qemu-action@v3
-
name: Login DockerHub
uses: docker/login-action@v2
- name: Set Up Buildx
uses: docker/setup-buildx-action@v3
- name: Login DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
-
name: Build Image
uses: docker/build-push-action@v4
- name: Login GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build Image
uses: docker/build-push-action@v5
with:
context: .
file: Dockerfile
file: docker/Dockerfile
platforms: |
linux/amd64
linux/arm64
linux/arm64/v8
push: true
build-args: |
MOVIEPILOT_VERSION=${{ env.app_version }}
tags: |
${{ secrets.DOCKER_USERNAME }}/moviepilot:latest
${{ secrets.DOCKER_USERNAME }}/moviepilot:${{ env.app_version }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha, scope=${{ github.workflow }}-docker
cache-to: type=gha, scope=${{ github.workflow }}-docker
- name: Generate Changelog
id: changelog
run: |
# 获取上一个 tag排除当前版本的 tag
PREVIOUS_TAG=$(git tag -l 'v*' --sort=-v:refname | grep -v "^v${{ env.app_version }}$" | head -n 1)
echo "Previous tag: $PREVIOUS_TAG"
# 使用 || 作为分隔符,同时获取 commit 消息和作者 GitHub 用户名
if [ -z "$PREVIOUS_TAG" ]; then
COMMITS=$(git log --pretty=format:"%s||%an" HEAD)
else
COMMITS=$(git log --pretty=format:"%s||%an" ${PREVIOUS_TAG}..HEAD)
fi
# 分类收集 commit 消息(使用关联数组去重)
declare -A SEEN
FEATURES=""
FIXES=""
OTHERS=""
while IFS= read -r line; do
# 跳过空行
if [ -z "$line" ]; then
continue
fi
# 分离 commit 消息和作者
msg=$(echo "$line" | sed 's/||[^|]*$//')
author=$(echo "$line" | sed 's/.*||//')
# 跳过 Merge commit 和版本更新 commit
if echo "$msg" | grep -qE "^Merge pull request|^Merge branch|^更新 version"; then
continue
fi
# 按 Conventional Commits 前缀分类
if echo "$msg" | grep -qiE "^feat(\(.+\))?:"; then
desc=$(echo "$msg" | sed -E 's/^feat(\([^)]*\))?:\s*//')
category="FEATURES"
elif echo "$msg" | grep -qiE "^fix(\(.+\))?:"; then
desc=$(echo "$msg" | sed -E 's/^fix(\([^)]*\))?:\s*//')
category="FIXES"
elif echo "$msg" | grep -qiE "^(docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?:"; then
desc=$(echo "$msg" | sed -E 's/^(docs|style|refactor|perf|test|build|ci|chore|revert)(\([^)]*\))?:\s*//')
category="OTHERS"
else
desc="$msg"
category="OTHERS"
fi
# 使用 "分类+描述" 作为去重的 key跳过重复内容
dedup_key="${category}::${desc}"
if [ -n "${SEEN[$dedup_key]+x}" ]; then
continue
fi
SEEN[$dedup_key]=1
# 添加 by @author 引用
entry="- ${desc} by @${author}"
case "$category" in
FEATURES) FEATURES="${FEATURES}${entry}\n" ;;
FIXES) FIXES="${FIXES}${entry}\n" ;;
OTHERS) OTHERS="${OTHERS}${entry}\n" ;;
esac
done <<< "$COMMITS"
# 组装 changelog
CHANGELOG=""
if [ -n "$FEATURES" ]; then
CHANGELOG="${CHANGELOG}### ✨ 新功能\n\n${FEATURES}\n"
fi
if [ -n "$FIXES" ]; then
CHANGELOG="${CHANGELOG}### 🐛 修复\n\n${FIXES}\n"
fi
if [ -n "$OTHERS" ]; then
CHANGELOG="${CHANGELOG}### 🔧 其他\n\n${OTHERS}\n"
fi
# 添加版本对比链接
if [ -n "$PREVIOUS_TAG" ]; then
CHANGELOG="${CHANGELOG}**完整更新记录**: https://github.com/${{ github.repository }}/compare/${PREVIOUS_TAG}...v${{ env.app_version }}"
fi
# 写入环境变量
echo "CHANGELOG<<EOF" >> $GITHUB_ENV
echo -e "$CHANGELOG" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Get existing release body
id: get_release_body
continue-on-error: true
run: |
release_body=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/releases/tags/v${{ env.app_version }}" | \
jq -r '.body // ""')
# 如果已有手动编写的 release body则保留否则使用自动生成的 changelog
if [ -n "$release_body" ] && [ "$release_body" != "null" ] && [ "$release_body" != "" ]; then
echo "RELEASE_BODY<<EOF" >> $GITHUB_ENV
echo "$release_body" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
else
echo "RELEASE_BODY<<EOF" >> $GITHUB_ENV
echo "${{ env.CHANGELOG }}" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
fi
- name: Delete Release
uses: dev-drprasad/delete-tag-and-release@v1.1
continue-on-error: true
with:
tag_name: v${{ env.app_version }}
delete_release: true
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Generate Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ env.app_version }}
name: v${{ env.app_version }}
body: ${{ env.RELEASE_BODY }}
draft: false
prerelease: false
make_latest: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

33
.github/workflows/issues.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: Close inactive issues
on:
workflow_dispatch:
schedule:
# Github Action 只支持 UTC 时间。
# '0 18 * * *' 对应 UTC 时间的 18:00也就是中国时区 (UTC+8) 的第二天凌晨 02:00。
- cron: "0 18 * * *"
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v5
with:
# 标记 stale 标签时间
days-before-issue-stale: 30
# 关闭 issues 标签时间
days-before-issue-close: 14
# 自定义标签名
stale-issue-label: "stale"
stale-issue-message: "此问题已过时,因为它已打开 30 天且没有任何活动。"
close-issue-message: "此问题已关闭,因为它在标记为 stale 后,已处于无更新状态 14 天。"
# 忽略所有的 Pull Request只处理 Issue
days-before-pr-stale: -1
days-before-pr-close: -1
# 排除带有RFC标签的issue
exempt-issue-labels: "RFC"
operations-per-run: 500
repo-token: ${{ secrets.GITHUB_TOKEN }}

91
.github/workflows/pylint.yml vendored Normal file
View File

@@ -0,0 +1,91 @@
name: Pylint Code Quality Check
on:
# 允许手动触发
workflow_dispatch:
jobs:
pylint:
runs-on: ubuntu-latest
name: Pylint Code Quality Check
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
- name: Cache pip dependencies
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt', '**/requirements.in') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
pip install pylint
# 安装项目依赖
if [ -f requirements.txt ]; then
echo "📦 安装 requirements.txt 中的依赖..."
pip install -r requirements.txt
elif [ -f requirements.in ]; then
echo "📦 安装 requirements.in 中的依赖..."
pip install -r requirements.in
else
echo "⚠️ 未找到依赖文件,仅安装 pylint"
fi
- name: Verify pylint config
run: |
# 检查项目中的pylint配置文件是否存在
if [ -f .pylintrc ]; then
echo "✅ 找到项目配置文件: .pylintrc"
echo "配置文件内容预览:"
head -10 .pylintrc
else
echo "❌ 未找到 .pylintrc 配置文件"
exit 1
fi
- name: Run pylint
run: |
# 运行pylint检查主要的Python文件
echo "🚀 运行 Pylint 错误检查..."
# 检查主要目录 - 只关注错误,如果有错误则退出
echo "📂 检查 app/ 目录..."
pylint app/ --output-format=colorized --reports=yes --score=yes
# 检查根目录的Python文件
echo "📂 检查根目录 Python 文件..."
for file in $(find . -name "*.py" -not -path "./.*" -not -path "./.venv/*" -not -path "./build/*" -not -path "./dist/*" -not -path "./tests/*" -not -path "./docs/*" -not -path "./__pycache__/*" -maxdepth 1); do
echo "检查文件: $file"
pylint "$file" --output-format=colorized || exit 1
done
# 生成详细报告
echo "📊 生成 Pylint 详细报告..."
pylint app/ --output-format=json > pylint-report.json || true
# 显示评分(仅供参考)
echo "📈 Pylint 评分(仅供参考):"
pylint app/ --score=yes --reports=no | tail -2 || true
- name: Upload pylint report
uses: actions/upload-artifact@v4
if: always()
with:
name: pylint-report
path: pylint-report.json
- name: Summary
run: |
echo "🎉 Pylint 检查完成!"
echo "✅ 没有发现语法错误或严重问题"
echo "📊 详细报告已保存为构建工件"

View File

@@ -1,36 +0,0 @@
name: MoviePilot Release
on:
workflow_dispatch:
push:
branches:
- main
paths:
- version.py
jobs:
build:
runs-on: ubuntu-latest
name: Build Docker Image
steps:
-
name: Checkout
uses: actions/checkout@v3
-
name: Release Version
id: release_version
run: |
app_version=$(cat version.py |sed -ne "s/APP_VERSION\s=\s'v\(.*\)'/\1/gp")
echo "app_version=$app_version" >> $GITHUB_ENV
-
name: Generate Release
uses: actions/create-release@latest
with:
tag_name: v${{ env.app_version }}
name: v${{ env.app_version }}
body: ${{ github.event.commits[0].message }}
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

32
.gitignore vendored
View File

@@ -1,8 +1,38 @@
.idea/
.DS_Store
*.c
*.so
*.pyd
build/
cython_cache/
dist/
nginx/
test.py
safety_report.txt
app/helper/sites.py
config/user.db
app/helper/*.so
app/helper/*.pyd
app/helper/*.bin
app/plugins/**
!app/plugins/__init__.py
config/cookies/**
config/app.env
config/user.db*
config/sites/**
config/logs/
config/temp/
config/cache/
.runtime/
public/
.moviepilot.env
*.pyc
*.log
.vscode
venv
# Pylint
pylint-report.json
.pylint.d/
# AI
.claude/

83
.pylintrc Normal file
View File

@@ -0,0 +1,83 @@
[MASTER]
# 指定Python路径
init-hook='import sys; sys.path.append(".")'
# 忽略的文件和目录
ignore=.git,__pycache__,.venv,build,dist,tests,docs
# 并行作业数量
jobs=0
[MESSAGES CONTROL]
# 只关注错误级别的问题,禁用警告、约定和重构建议
# E = Error (错误) - 会导致构建失败
# W = Warning (警告) - 仅显示,不会失败
# R = Refactor (重构建议) - 仅显示,不会失败
# C = Convention (约定) - 仅显示,不会失败
# I = Information (信息) - 仅显示,不会失败
# 禁用大部分警告、约定和重构建议,只保留错误和重要警告
disable=all
enable=error,
syntax-error,
undefined-variable,
used-before-assignment,
unreachable,
return-outside-function,
yield-outside-function,
continue-in-finally,
nonlocal-without-binding,
undefined-loop-variable,
redefined-builtin,
not-callable,
assignment-from-no-return,
no-value-for-parameter,
too-many-function-args,
unexpected-keyword-arg,
redundant-keyword-arg,
import-error,
relative-beyond-top-level
[REPORTS]
# 设置报告格式
output-format=colorized
reports=yes
score=yes
[FORMAT]
# 最大行长度
max-line-length=120
# 缩进大小
indent-string=' '
[DESIGN]
# 最大参数数量
max-args=10
# 最大本地变量数量
max-locals=20
# 最大分支数量
max-branches=15
# 最大语句数量
max-statements=50
# 最大父类数量
max-parents=7
# 最大属性数量
max-attributes=10
# 最小公共方法数量
min-public-methods=1
# 最大公共方法数量
max-public-methods=25
[SIMILARITIES]
# 最小相似行数
min-similarity-lines=6
# 忽略注释
ignore-comments=yes
# 忽略文档字符串
ignore-docstrings=yes
# 忽略导入
ignore-imports=yes
[TYPECHECK]
# 生成缺失成员提示的类列表
generated-members=requests.packages.urllib3

View File

@@ -1,86 +0,0 @@
FROM python:3.11.4-slim-bullseye
ARG MOVIEPILOT_VERSION
ENV LANG="C.UTF-8" \
HOME="/moviepilot" \
TERM="xterm" \
TZ="Asia/Shanghai" \
PUID=0 \
PGID=0 \
UMASK=000 \
MOVIEPILOT_AUTO_UPDATE=true \
MOVIEPILOT_AUTO_UPDATE_DEV=false \
NGINX_PORT=3000 \
CONFIG_DIR="/config" \
API_TOKEN="moviepilot" \
AUTH_SITE="iyuu" \
DOWNLOAD_PATH="/downloads" \
DOWNLOAD_CATEGORY="false" \
TORRENT_TAG="MOVIEPILOT" \
LIBRARY_PATH="" \
LIBRARY_CATEGORY="false" \
TRANSFER_TYPE="copy" \
COOKIECLOUD_HOST="https://movie-pilot.org/cookiecloud" \
COOKIECLOUD_KEY="" \
COOKIECLOUD_PASSWORD="" \
MESSAGER="telegram" \
TELEGRAM_TOKEN="" \
TELEGRAM_CHAT_ID="" \
DOWNLOADER="qbittorrent" \
QB_HOST="127.0.0.1:8080" \
QB_USER="admin" \
QB_PASSWORD="adminadmin" \
MEDIASERVER="emby" \
EMBY_HOST="http://127.0.0.1:8096" \
EMBY_API_KEY=""
WORKDIR "/app"
COPY . .
RUN apt-get update \
&& apt-get -y install \
musl-dev \
nginx \
gettext-base \
locales \
procps \
gosu \
bash \
wget \
curl \
busybox \
dumb-init \
jq \
&& \
if [ "$(uname -m)" = "x86_64" ]; \
then ln -s /usr/lib/x86_64-linux-musl/libc.so /lib/libc.musl-x86_64.so.1; \
elif [ "$(uname -m)" = "aarch64" ]; \
then ln -s /usr/lib/aarch64-linux-musl/libc.so /lib/libc.musl-aarch64.so.1; \
fi \
&& cp -f /app/nginx.conf /etc/nginx/nginx.template.conf \
&& cp -f /app/update /usr/local/bin/mp_update \
&& cp -f /app/entrypoint /entrypoint \
&& chmod +x /entrypoint /usr/local/bin/mp_update \
&& mkdir -p ${HOME} \
&& groupadd -r moviepilot -g 911 \
&& useradd -r moviepilot -g moviepilot -d ${HOME} -s /bin/bash -u 911 \
&& apt-get install -y build-essential \
&& pip install --upgrade pip \
&& pip install -r requirements.txt \
&& playwright install-deps chromium \
&& python_ver=$(python3 -V | awk '{print $2}') \
&& echo "/app/" > /usr/local/lib/python${python_ver%.*}/site-packages/app.pth \
&& echo 'fs.inotify.max_user_watches=5242880' >> /etc/sysctl.conf \
&& echo 'fs.inotify.max_user_instances=5242880' >> /etc/sysctl.conf \
&& locale-gen zh_CN.UTF-8 \
&& FRONTEND_VERSION=$(curl -sL "https://api.github.com/repos/jxxghp/MoviePilot-Frontend/releases/latest" | jq -r .tag_name) \
&& curl -sL "https://github.com/jxxghp/MoviePilot-Frontend/releases/download/${FRONTEND_VERSION}/dist.zip" | busybox unzip -d / - \
&& mv /dist /public \
&& apt-get remove -y build-essential \
&& apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf \
/tmp/* \
/moviepilot/.cache \
/var/lib/apt/lists/* \
/var/tmp/*
EXPOSE 3000
VOLUME ["/config"]
ENTRYPOINT [ "/entrypoint" ]

256
README.md
View File

@@ -1,250 +1,76 @@
# MoviePilot
![GitHub Repo stars](https://img.shields.io/github/stars/jxxghp/MoviePilot?style=for-the-badge)
![GitHub forks](https://img.shields.io/github/forks/jxxghp/MoviePilot?style=for-the-badge)
![GitHub contributors](https://img.shields.io/github/contributors/jxxghp/MoviePilot?style=for-the-badge)
![GitHub repo size](https://img.shields.io/github/repo-size/jxxghp/MoviePilot?style=for-the-badge)
![GitHub issues](https://img.shields.io/github/issues/jxxghp/MoviePilot?style=for-the-badge)
![Docker Pulls](https://img.shields.io/docker/pulls/jxxghp/moviepilot?style=for-the-badge)
![Docker Pulls V2](https://img.shields.io/docker/pulls/jxxghp/moviepilot-v2?style=for-the-badge)
![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20Synology-blue?style=for-the-badge)
基于 [NAStool](https://github.com/NAStool/nas-tools) 部分代码重新设计,聚焦自动化核心需求,减少问题同时更易于扩展和维护。
# 仅用于学习交流使用,请勿在任何国内平台宣传该项目!
Dockerhttps://hub.docker.com/r/jxxghp/moviepilot
发布频道https://t.me/moviepilot_channel
## 主要特性
- 前后端分离基于FastApi + Vue3前端项目地址[MoviePilot-Frontend](https://github.com/jxxghp/MoviePilot-Frontend)
- 前后端分离基于FastApi + Vue3。
- 聚焦核心需求,简化功能和设置,部分设置项可直接使用默认值。
- 重新设计了用户界面,更加美观易用。
## 安装
1. **安装CookieCloud插件**
## 安装使用
站点信息需要通过CookieCloud同步获取因此需要安装CookieCloud插件将浏览器中的站点Cookie数据同步到云端后再同步到MoviePilot使用。 插件下载地址请点击 [这里](https://github.com/easychen/CookieCloud/releases)。
官方Wikihttps://wiki.movie-pilot.org
2. **安装CookieCloud服务端可选**
MoviePilot内置了公共CookieCloud服务器如果需要自建服务可参考 [CookieCloud](https://github.com/easychen/CookieCloud) 项目进行搭建docker镜像请点击 [这里](https://hub.docker.com/r/easychen/cookiecloud)。
## 本地 CLI
**声明:** 本项目不会收集用户敏感数据Cookie同步也是基于CookieCloud项目实现非本项目提供的能力。技术角度上CookieCloud采用端到端加密在个人不泄露`用户KEY``端对端加密密码`的情况下第三方无法窃取任何用户信息(包括服务器持有者)。如果你不放心,可以不使用公共服务或者不使用本项目,但如果使用后发生了任何信息泄露与本项目无关!
3. **安装配套管理软件**
MoviePilot需要配套下载器和媒体服务器配合使用。
- 下载器支持qBittorrent、TransmissionQB版本号要求>= 4.3.9TR版本号要求>= 3.0推荐使用QB。
- 媒体服务器支持Jellyfin、Emby、Plex推荐使用Emby。
4. **安装MoviePilot**
目前仅提供docker镜像点击 [这里](https://hub.docker.com/r/jxxghp/moviepilot) 或执行命令:
一键安装运行脚本:
```shell
docker pull jxxghp/moviepilot:latest
curl -fsSL https://raw.githubusercontent.com/jxxghp/MoviePilot/v2/scripts/bootstrap-local.sh | bash
```
## 配置
项目的所有配置均通过环境变量进行设置,部分环境建立容器后会自动显示待配置项,如未自动显示配置项则需要手动增加对应环境变量。
配置文件映射路径:`/config`
### 1. **基础设置**
- **PUID**:运行程序用户的`uid`,默认`0`
- **PGID**:运行程序用户的`gid`,默认`0`
- **UMASK**:掩码权限,默认`000`,可以考虑设置为`022`
- **MOVIEPILOT_AUTO_UPDATE**:重启更新,`true`/`false`,默认`true` **注意:如果出现网络问题可以配置`PROXY_HOST`,具体看下方`PROXY_HOST`解释**
- **NGINX_PORT** WEB服务端口默认`3000`,可自行修改,但不能为`3001`
- **SUPERUSER** 超级管理员用户名,默认`admin`,安装后使用该用户登录后台管理界面
- **SUPERUSER_PASSWORD** 超级管理员初始密码,默认`password`,建议修改为复杂密码
- **API_TOKEN** API密钥默认`moviepilot`在媒体服务器Webhook、微信回调等地址配置中需要加上`?token=`该值,建议修改为复杂字符串
- **PROXY_HOST** 网络代理可选访问themoviedb或者重启更新需要使用代理访问格式为`http(s)://ip:port`
- **TMDB_API_DOMAIN** TMDB API地址默认`api.themoviedb.org`,也可配置为`api.tmdb.org`或其它中转代理服务地址,能连通即可
- **DOWNLOAD_PATH** 下载保存目录,**注意:需要将`moviepilot``下载器`的映射路径保持一致**,否则会导致下载文件无法转移
- **DOWNLOAD_MOVIE_PATH** 电影下载保存目录,**必须是`DOWNLOAD_PATH`的下级路径**,不设置则下载到`DOWNLOAD_PATH`
- **DOWNLOAD_TV_PATH** 电视剧下载保存目录,**必须是`DOWNLOAD_PATH`的下级路径**,不设置则下载到`DOWNLOAD_PATH`
- **DOWNLOAD_ANIME_PATH** 动漫下载保存目录,**必须是`DOWNLOAD_PATH`的下级路径**,不设置则下载到`DOWNLOAD_PATH`
- **DOWNLOAD_CATEGORY** 下载二级分类开关,`true`/`false`,默认`false`,开启后会根据配置`category.yaml`自动在下载目录下建立二级目录分类
- **DOWNLOAD_SUBTITLE** 下载站点字幕,`true`/`false`,默认`true`
- **REFRESH_MEDIASERVER** 入库刷新媒体库,`true`/`false`,默认`true`
- **SCRAP_METADATA** 刮削入库的媒体文件,`true`/`false`,默认`true`
- **TORRENT_TAG** 种子标签,默认为`MOVIEPILOT`设置后只有MoviePilot添加的下载才会处理留空所有下载器中的任务均会处理
- **LIBRARY_PATH** 媒体库目录,多个目录使用`,`分隔
- **LIBRARY_MOVIE_NAME** 电影媒体库目录名,默认`电影`
- **LIBRARY_TV_NAME** 电视剧媒体库目录名,默认`电视剧`
- **LIBRARY_ANIME_NAME** 动漫媒体库目录名,默认`电视剧/动漫`
- **LIBRARY_CATEGORY** 媒体库二级分类开关,`true`/`false`,默认`false`,开启后会根据配置`category.yaml`自动在媒体库目录下建立二级目录分类
- **TRANSFER_TYPE** 转移方式,支持`link`/`copy`/`move`/`softlink` **注意:在`link`和`softlink`转移方式下,转移后的文件会继承源文件的权限掩码,不受`UMASK`影响**
- **COOKIECLOUD_HOST** CookieCloud服务器地址格式`http(s)://ip:port`,不配置默认使用内建服务器`https://movie-pilot.org/cookiecloud`
- **COOKIECLOUD_KEY** CookieCloud用户KEY
- **COOKIECLOUD_PASSWORD** CookieCloud端对端加密密码
- **COOKIECLOUD_INTERVAL** CookieCloud同步间隔分钟
- **OCR_HOST** OCR识别服务器地址格式`http(s)://ip:port`用于识别站点二维码实现自动登录获取Cookie等不配置默认使用内建服务器`https://movie-pilot.org`,可使用 [这个镜像](https://hub.docker.com/r/jxxghp/moviepilot-ocr) 自行搭建。
- **USER_AGENT** CookieCloud对应的浏览器UA可选设置后可增加连接站点的成功率同步站点后可以在管理界面中修改
- **AUTO_DOWNLOAD_USER** 交互搜索自动下载用户ID使用,分割
- **SUBSCRIBE_SEARCH** 订阅搜索,`true`/`false`,默认`false`开启后会每隔24小时对所有订阅进行全量搜索以补齐缺失剧集一般情况下正常订阅即可订阅搜索只做为兜底会增加站点压力不建议开启
- **MESSAGER** 消息通知渠道,支持 `telegram`/`wechat`/`slack`,开启多个渠道时使用`,`分隔。同时还需要配置对应渠道的环境变量,非对应渠道的变量可删除,推荐使用`telegram`
- `wechat`设置项:
- **WECHAT_CORPID** WeChat企业ID
- **WECHAT_APP_SECRET** WeChat应用Secret
- **WECHAT_APP_ID** WeChat应用ID
- **WECHAT_TOKEN** WeChat消息回调的Token
- **WECHAT_ENCODING_AESKEY** WeChat消息回调的EncodingAESKey
- **WECHAT_ADMINS** WeChat管理员列表多个管理员用英文逗号分隔可选
- **WECHAT_PROXY** WeChat代理服务器后面不要加/
- `telegram`设置项:
- **TELEGRAM_TOKEN** Telegram Bot Token
- **TELEGRAM_CHAT_ID** Telegram Chat ID
- **TELEGRAM_USERS** Telegram 用户ID多个使用,分隔只有用户ID在列表中才可以使用Bot如未设置则均可以使用Bot
- **TELEGRAM_ADMINS** Telegram 管理员ID多个使用,分隔只有管理员才可以操作Bot菜单如未设置则均可以操作菜单
- `slack`设置项:
- **SLACK_OAUTH_TOKEN** Slack Bot User OAuth Token
- **SLACK_APP_TOKEN** Slack App-Level Token
- **SLACK_CHANNEL** Slack 频道名称,默认`全体`
使用 `moviepilot` 命令管理MoviePilot完整 CLI 文档:[`docs/cli.md`](docs/cli.md)
- **DOWNLOADER** 下载器,支持`qbittorrent`/`transmission`QB版本号要求>= 4.3.9TR版本号要求>= 3.0,同时还需要配置对应渠道的环境变量,非对应渠道的变量可删除,推荐使用`qbittorrent`
- `qbittorrent`设置项:
- **QB_HOST** qbittorrent地址格式`ip:port`https需要添加`https://`前缀
- **QB_USER** qbittorrent用户名
- **QB_PASSWORD** qbittorrent密码
- **QB_CATEGORY** qbittorrent分类自动管理`true`/`false`,默认`false`,开启后会将下载二级分类传递到下载器,由下载器管理下载目录,需要同步开启`DOWNLOAD_CATEGORY`
- `transmission`设置项:
- **TR_HOST** transmission地址格式`ip:port`https需要添加`https://`前缀
- **TR_USER** transmission用户名
- **TR_PASSWORD** transmission密码
- **DOWNLOADER_MONITOR** 下载器监控,`true`/`false`,默认为`true`,开启后下载完成时才会自动整理入库
- **MEDIASERVER** 媒体服务器,支持`emby`/`jellyfin`/`plex`,同时还需要配置对应媒体服务器的环境变量,非对应媒体服务器的变量可删除,推荐使用`emby`
- `emby`设置项:
- **EMBY_HOST** Emby服务器地址格式`ip:port`https需要添加`https://`前缀
- **EMBY_API_KEY** Emby Api Key`设置->高级->API密钥`处生成
- `jellyfin`设置项:
- **JELLYFIN_HOST** Jellyfin服务器地址格式`ip:port`https需要添加`https://`前缀
- **JELLYFIN_API_KEY** Jellyfin Api Key`设置->高级->API密钥`处生成
- `plex`设置项:
- **PLEX_HOST** Plex服务器地址格式`ip:port`https需要添加`https://`前缀
- **PLEX_TOKEN** Plex网页Url中的`X-Plex-Token`通过浏览器F12->网络从请求URL中获取
- **MEDIASERVER_SYNC_INTERVAL:** 媒体服务器同步间隔(小时),默认`6`,留空则不同步
### 2. **用户认证**
- **AUTH_SITE** 认证站点,支持`hhclub`/`audiences`/`hddolby`/`zmpt`/`freefarm`/`hdfans`/`wintersakura`/`leaves`/`1ptba`/`icc2022`/`iyuu`
`MoviePilot`需要认证后才能使用,配置`AUTH_SITE`后,需要根据下表配置对应站点的认证参数。
| 站点 | 参数 |
|:--:|:-----------------------------------------------------:|
| iyuu | `IYUU_SIGN`IYUU登录令牌 |
| hhclub | `HHCLUB_USERNAME`:用户名<br/>`HHCLUB_PASSKEY`:密钥 |
| audiences | `AUDIENCES_UID`用户ID<br/>`AUDIENCES_PASSKEY`:密钥 |
| hddolby | `HDDOLBY_ID`用户ID<br/>`HDDOLBY_PASSKEY`:密钥 |
| zmpt | `ZMPT_UID`用户ID<br/>`ZMPT_PASSKEY`:密钥 |
| freefarm | `FREEFARM_UID`用户ID<br/>`FREEFARM_PASSKEY`:密钥 |
| hdfans | `HDFANS_UID`用户ID<br/>`HDFANS_PASSKEY`:密钥 |
| wintersakura | `WINTERSAKURA_UID`用户ID<br/>`WINTERSAKURA_PASSKEY`:密钥 |
| leaves | `LEAVES_UID`用户ID<br/>`LEAVES_PASSKEY`:密钥 |
| 1ptba | `1PTBA_UID`用户ID<br/>`1PTBA_PASSKEY`:密钥 |
| icc2022 | `ICC2022_UID`用户ID<br/>`ICC2022_PASSKEY`:密钥 |
### 2. **进阶配置**
- **BIG_MEMORY_MODE** 大内存模式,默认为`false`,开启后会占用更多的内存,但响应速度会更快
- **MOVIE_RENAME_FORMAT** 电影重命名格式
`MOVIE_RENAME_FORMAT`支持的配置项:
> `title` 标题
> `original_name` 原文件名
> `original_title` 原语种标题
> `name` 识别名称
> `year` 年份
> `edition` 版本
> `videoFormat` 分辨率
> `releaseGroup` 制作组/字幕组
> `effect` 特效
> `videoCodec` 视频编码
> `audioCodec` 音频编码
> `tmdbid` TMDBID
> `imdbid` IMDBID
> `part`:段/节
> `fileExt`:文件扩展名
`MOVIE_RENAME_FORMAT`默认配置格式:
```
{{title}}{% if year %} ({{year}}){% endif %}/{{title}}{% if year %} ({{year}}){% endif %}{% if part %}-{{part}}{% endif %}{% if videoFormat %} - {{videoFormat}}{% endif %}{{fileExt}}
## 为 AI Agent 添加 Skills
```shell
npx skills add https://github.com/jxxghp/MoviePilot
```
- **TV_RENAME_FORMAT** 电视剧重命名格式
## 参与开发
`TV_RENAME_FORMAT`额外支持的配置项:
API文档https://api.movie-pilot.org
> `season` 季号
> `episode` 集号
> `season_episode` 季集 SxxExx
MCP工具API文档详见 [docs/mcp-api.md](docs/mcp-api.md)
`TV_RENAME_FORMAT`默认配置格式:
开发环境准备与本地源码运行说明:[`docs/development-setup.md`](docs/development-setup.md)
```
{{title}}{% if year %} ({{year}}){% endif %}/Season {{season}}/{{title}} - {{season_episode}}{% if part %}-{{part}}{% endif %}{% if episode %} - 第 {{episode}} 集{% endif %}{{fileExt}}
```
插件开发说明:<https://wiki.movie-pilot.org/zh/plugindev>
## 相关项目
### 3. **过滤规则**
- [MoviePilot-Frontend](https://github.com/jxxghp/MoviePilot-Frontend)
- [MoviePilot-Resources](https://github.com/jxxghp/MoviePilot-Resources)
- [MoviePilot-Plugins](https://github.com/jxxghp/MoviePilot-Plugins)
- [MoviePilot-Server](https://github.com/jxxghp/MoviePilot-Server)
- [MoviePilot-Wiki](https://github.com/jxxghp/MoviePilot-Wiki)
`设定`-`规则`中设定,规则说明:
## 免责申明
- 仅支持使用内置规则进行排列组合,内置规则有:`蓝光原盘``4K``1080P``中文字幕``特效字幕``H265``H264``杜比``HDR``REMUX``WEB-DL``免费``国语配音`
- 符合任一层级规则的资源将被标识选中,匹配成功的层级做为该资源的优先级,排越前面优先级超高
- 不符合过滤规则所有层级规则的资源将不会被选中
- 本软件仅供学习交流使用,任何人不得将本软件用于商业用途,任何人不得将本软件用于违法犯罪活动,软件对用户行为不知情,一切责任由使用者承担。
- 本软件代码开源,基于开源代码进行修改,人为去除相关限制导致软件被分发、传播并造成责任事件的,需由代码修改发布者承担全部责任,不建议对用户认证机制进行规避或修改并公开发布。
- 本项目不接受捐赠,没有在任何地方发布捐赠信息页面,软件本身不收费也不提供任何收费相关服务,请仔细辨别避免误导。
## 贡献者
## 使用
- 通过CookieCloud同步快速同步站点不需要使用的站点可在WEB管理界面中禁用。
- 通过下载器监控实现自动整理入库刮削。
- 通过微信/Telegram/Slack远程管理其中Telegram将会自动添加操作菜单。微信回调相对路径为`/api/v1/message/`
- 通过WEB进行管理将WEB添加到手机桌面获得类App使用效果管理界面端口`3000`
- 设置媒体服务器Webhook通过MoviePilot发送播放通知等。Webhook回调相对路径为`/api/v1/webhook?token=moviepilot`,其中`moviepilot`为设置的`API_TOKEN`
- 将MoviePilot做为Radarr或Sonarr服务器添加到Overseerr或Jellyseerr可使用Overseerr/Jellyseerr浏览订阅。
**注意**
1) 容器首次启动需要下载浏览器内核,根据网络情况可能需要较长时间,此时无法登录。可映射`/moviepilot`目录避免容器重置后重新触发浏览器内核下载。
2) 使用反向代理时,需要添加以下配置,否则可能会导致部分功能无法访问(`ip:port`修改为实际值):
```nginx configuration
location / {
proxy_pass http://ip:port;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
```
![image](https://github.com/jxxghp/MoviePilot/assets/51039935/b8f0238d-847f-4f9d-b210-e905837362b9)
![image](https://github.com/jxxghp/MoviePilot/assets/51039935/28219233-ec7d-479b-b184-9a901c947dd1)
![image](https://github.com/jxxghp/MoviePilot/assets/51039935/f7df0806-668d-4c8b-ad41-133bf8f0bf73)
![image](https://github.com/jxxghp/MoviePilot/assets/51039935/f7ea77cd-0362-4c35-967c-7f1b22dbef05)
<a href="https://github.com/jxxghp/MoviePilot/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jxxghp/MoviePilot" />
</a>

View File

@@ -1,31 +0,0 @@
"""1.0.1
Revision ID: 14f1813ae8e3
Revises: 9f4edd55c2d4
Create Date: 2023-07-27 12:34:57.839443
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '14f1813ae8e3'
down_revision = '9f4edd55c2d4'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
try:
with op.batch_alter_table("subscribe") as batch_op:
batch_op.add_column(sa.Column('best_version', sa.Integer, nullable=True))
batch_op.add_column(sa.Column('current_priority', sa.Integer, nullable=True))
except Exception as e:
pass
# ### end Alembic commands ###
def downgrade() -> None:
pass

View File

@@ -1,30 +0,0 @@
"""1.0.4
Revision ID: 1e169250e949
Revises: 52ab4930be04
Create Date: 2023-09-01 09:56:33.907661
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '1e169250e949'
down_revision = '52ab4930be04'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
try:
with op.batch_alter_table("subscribe") as batch_op:
batch_op.add_column(sa.Column('date', sa.String, nullable=True))
except Exception as e:
pass
# ### end Alembic commands ###
def downgrade() -> None:
pass

View File

@@ -1,30 +0,0 @@
"""1_0_3
Revision ID: 52ab4930be04
Revises: ec5fb51fc300
Create Date: 2023-08-28 13:21:45.152012
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '52ab4930be04'
down_revision = 'ec5fb51fc300'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.execute("delete from systemconfig where key = 'RssSites';")
op.execute("insert into systemconfig(key, value) VALUES('RssSites', (select value from systemconfig where key= 'IndexerSites'));")
op.execute("delete from systemconfig where key = 'SearchResults';")
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

View File

@@ -1,32 +0,0 @@
"""1.0.0
Revision ID: 9f4edd55c2d4
Revises:
Create Date: 2023-07-13 12:27:26.402317
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '9f4edd55c2d4'
down_revision = None
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
try:
with op.batch_alter_table("subscribe") as batch_op:
batch_op.add_column(sa.Column('sites', sa.Text, nullable=True))
except Exception as e:
pass
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###

View File

@@ -1,32 +0,0 @@
"""1.0.2
Revision ID: ec5fb51fc300
Revises: 14f1813ae8e3
Create Date: 2023-08-12 17:55:06.509548
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'ec5fb51fc300'
down_revision = '14f1813ae8e3'
branch_labels = None
depends_on = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
try:
with op.batch_alter_table("transferhistory") as batch_op:
batch_op.add_column(sa.Column('files', sa.String, nullable=True))
with op.batch_alter_table("rss") as batch_op:
batch_op.add_column(sa.Column('filter', sa.Integer, nullable=True))
except Exception as e:
pass
# ### end Alembic commands ###
def downgrade() -> None:
pass

BIN
app.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

1134
app/agent/__init__.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,362 @@
import asyncio
import threading
from typing import Optional, Tuple
from app.chain import ChainBase
from app.log import logger
from app.schemas import Notification
from app.schemas.message import (
MessageResponse,
ChannelCapabilityManager,
ChannelCapability,
)
from app.schemas.types import MessageChannel
class _StreamChain(ChainBase):
pass
class StreamingHandler:
"""
流式Token缓冲管理器
负责从 LLM 流式 token 中积累文本,并在支持消息编辑的渠道上实时推送给用户。
工作流程:
1. Agent开始处理时调用 start_streaming(),检查渠道能力并启动定时刷新
2. LLM 产生 token 时调用 emit() 积累到缓冲区
3. 定时器周期性调用 _flush()
- 第一次有内容时发送新消息(通过 send_direct_message 获取 message_id
- 后续有新内容时编辑同一条消息(通过 edit_message
- 当消息长度接近渠道限制时,冻结当前消息并发送新消息继续输出
4. 工具调用时:
- 流式渠道:工具消息直接 emit() 追加到 buffer与 Agent 文字合并为同一条流式消息
- 非流式渠道:调用 take() 取出已积累的文字,与工具消息合并独立发送
5. Agent最终完成时调用 stop_streaming():执行最后一次刷新,
返回是否已通过流式发送完所有内容(调用方据此决定是否还需额外发送)
"""
# 流式输出的刷新间隔(秒)
FLUSH_INTERVAL = 0.3
def __init__(self):
self._lock = threading.Lock()
self._buffer = ""
# 流式输出相关状态
self._streaming_enabled = False
self._flush_task: Optional[asyncio.Task] = None
# 当前消息的发送信息(用于编辑消息)
self._message_response: Optional[MessageResponse] = None
# 已发送给用户的文本(用于追踪增量)
self._sent_text = ""
# 当前消息的起始偏移量buffer 中属于当前消息的起始位置)
self._msg_start_offset = 0
# 当前渠道的单条消息最大长度0 表示不限制)
self._max_message_length = 0
# 消息发送所需的上下文信息
self._channel: Optional[str] = None
self._source: Optional[str] = None
self._user_id: Optional[str] = None
self._username: Optional[str] = None
self._title: str = ""
def emit(self, token: str):
"""
接收 LLM 流式 token积累到缓冲区。
"""
with self._lock:
# 如果存量消息结束是两个换行,则去掉新消息前面的换行,避免过多空行
if self._buffer.endswith("\n\n") and token.startswith("\n"):
token = token.lstrip("\n")
self._buffer += token
async def take(self) -> str:
"""
获取当前已积累的消息内容,获取后清空缓冲区。
用于非流式渠道:工具调用前取出 Agent 已产出的文字,
与工具提示合并后独立发送。
注意:流式渠道不调用此方法,工具消息直接 emit 到 buffer 中。
"""
with self._lock:
if not self._buffer:
return ""
message = self._buffer
logger.info(f"Agent消息: {message}")
self._buffer = ""
return message
def clear(self):
"""
清空缓冲区(不返回内容)
"""
with self._lock:
self._buffer = ""
self._sent_text = ""
self._message_response = None
self._msg_start_offset = 0
def reset(self):
"""
重置缓冲区,清空已发送的文本从头更新,但保持消息编辑能力。
与 clear 的区别:
- clear完全重置所有状态后续会开新消息
- reset只清空buffer保留消息编辑状态后续继续编辑同一条消息
"""
with self._lock:
self._buffer = ""
self._sent_text = ""
self._msg_start_offset = 0
async def start_streaming(
self,
channel: Optional[str] = None,
source: Optional[str] = None,
user_id: Optional[str] = None,
username: Optional[str] = None,
title: str = "",
):
"""
启动流式输出。
始终标记为流式状态(用于 buffer 收集 token
但只有渠道支持消息编辑时才启动定时刷新任务(实时推送给用户)。
:param channel: 消息渠道
:param source: 消息来源
:param user_id: 用户ID
:param username: 用户名
:param title: 消息标题
"""
self._channel = channel
self._source = source
self._user_id = user_id
self._username = username
self._title = title
self._streaming_enabled = True
self._sent_text = ""
self._message_response = None
self._msg_start_offset = 0
# 检查渠道是否支持消息编辑,不支持则仅收集 token 到 buffer不实时推送
if not self._can_stream():
logger.debug(f"渠道 {channel} 不支持消息编辑,仅启用 buffer 收集模式")
return
# 从渠道能力中获取单条消息最大长度
try:
channel_enum = MessageChannel(self._channel)
self._max_message_length = ChannelCapabilityManager.get_max_message_length(
channel_enum
)
except (ValueError, KeyError):
self._max_message_length = 0
# 启动异步定时刷新任务
self._flush_task = asyncio.create_task(self._flush_loop())
logger.debug("流式输出已启动")
async def stop_streaming(self) -> Tuple[bool, str]:
"""
停止流式输出。执行最后一次刷新确保所有内容都已发送。
:return: (all_sent, final_text)
all_sent: 是否已经通过流式编辑将最终完整内容发送给了用户
True 表示调用方无需再额外发送消息)
final_text: 流式发送的完整文本内容(用于调用方保存消息记录)
"""
if not self._streaming_enabled:
return False, ""
self._streaming_enabled = False
# 取消定时任务
await self._cancel_flush_task()
# 执行最后一次刷新
await self._flush()
# 检查是否所有缓冲内容都已发送
with self._lock:
# 当前消息的文本 = buffer 中从 _msg_start_offset 开始的部分
current_msg_text = self._buffer[self._msg_start_offset :]
all_sent = (
self._message_response is not None
and self._sent_text
and current_msg_text == self._sent_text
)
# 保留最终文本用于返回(返回完整 buffer 内容,包含所有分段消息)
final_text = self._buffer if all_sent else ""
# 重置状态
self._sent_text = ""
self._message_response = None
self._msg_start_offset = 0
if all_sent:
# 所有内容已通过流式发送,清空缓冲区
self._buffer = ""
return all_sent, final_text
def _can_stream(self) -> bool:
"""
检查当前渠道是否支持流式输出(消息编辑)
"""
if not self._channel:
return False
try:
channel_enum = MessageChannel(self._channel)
return ChannelCapabilityManager.supports_capability(
channel_enum, ChannelCapability.MESSAGE_EDITING
)
except (ValueError, KeyError):
return False
async def _flush_loop(self):
"""
定时刷新循环,定期将缓冲区内容发送/编辑到用户
"""
try:
while self._streaming_enabled:
await asyncio.sleep(self.FLUSH_INTERVAL)
if self._streaming_enabled:
await self._flush()
except asyncio.CancelledError:
pass
except Exception as e:
logger.error(f"流式刷新异常: {e}")
async def _cancel_flush_task(self):
"""
取消当前的定时刷新任务
"""
if self._flush_task and not self._flush_task.done():
self._flush_task.cancel()
try:
await self._flush_task
except asyncio.CancelledError:
pass
self._flush_task = None
async def _flush(self):
"""
将当前缓冲区内容刷新到用户消息
- 如果还没有发送过消息先发送一条新消息并记录message_id
- 如果已经发送过消息,编辑该消息为最新的完整内容
- 如果当前消息内容超过长度限制,冻结当前消息并发送新消息继续输出
"""
with self._lock:
# 当前消息的文本 = buffer 中从 _msg_start_offset 开始的部分
current_text = self._buffer[self._msg_start_offset :]
if not current_text or current_text == self._sent_text:
# 没有新内容需要刷新
return
chain = _StreamChain()
try:
if self._message_response is None:
# 第一次发送:发送新消息并获取 message_id
response = chain.send_direct_message(
Notification(
channel=self._channel,
source=self._source,
userid=self._user_id,
username=self._username,
title=self._title,
text=current_text,
)
)
if response and response.success and response.message_id:
self._message_response = response
with self._lock:
self._sent_text = current_text
logger.debug(
f"流式输出初始消息已发送: message_id={response.message_id}"
)
else:
logger.debug(
"流式输出初始消息发送失败或未返回message_id降级为非流式输出"
)
self._streaming_enabled = False
else:
# 检查当前消息内容是否超过长度限制
if (
self._max_message_length
and len(current_text) > self._max_message_length
):
# 消息过长,冻结当前消息(保持最后一次成功编辑的内容)
# 将 offset 移动到已发送文本之后,开启新消息
logger.debug(
f"流式消息长度 {len(current_text)} 超过限制 {self._max_message_length},启用新消息"
)
with self._lock:
self._msg_start_offset += len(self._sent_text)
current_text = self._buffer[self._msg_start_offset :]
self._message_response = None
self._sent_text = ""
# 如果偏移后还有新内容,立即发送为新消息
if current_text:
response = chain.send_direct_message(
Notification(
channel=self._channel,
source=self._source,
userid=self._user_id,
username=self._username,
title=self._title,
text=current_text,
)
)
if response and response.success and response.message_id:
self._message_response = response
with self._lock:
self._sent_text = current_text
logger.debug(
f"流式输出新消息已发送: message_id={response.message_id}"
)
else:
logger.debug("流式输出新消息发送失败,降级为非流式输出")
self._streaming_enabled = False
else:
# 后续更新:编辑已有消息
try:
channel_enum = MessageChannel(self._channel)
except (ValueError, KeyError):
return
success = chain.edit_message(
channel=channel_enum,
source=self._message_response.source,
message_id=self._message_response.message_id,
chat_id=self._message_response.chat_id,
text=current_text,
title=self._title,
)
if success:
with self._lock:
self._sent_text = current_text
else:
logger.debug("流式输出消息编辑失败")
except Exception as e:
logger.error(f"流式输出刷新失败: {e}")
@property
def is_streaming(self) -> bool:
"""
是否正在流式输出
"""
return self._streaming_enabled
@property
def is_auto_flushing(self) -> bool:
"""
是否正在定时刷新(渠道支持消息编辑时自动推送 buffer 内容)
"""
return self._flush_task is not None
@property
def has_sent_message(self) -> bool:
"""
是否已经通过流式输出发送过消息(当前轮次)
"""
return self._message_response is not None

107
app/agent/interaction.py Normal file
View File

@@ -0,0 +1,107 @@
"""Agent 客户端交互请求管理。"""
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from threading import Lock
from typing import Dict, List, Optional
import uuid
@dataclass(frozen=True)
class AgentInteractionOption:
"""交互选项。"""
label: str
value: str
@dataclass
class PendingAgentInteraction:
"""待处理的 Agent 客户端交互请求。"""
request_id: str
session_id: str
user_id: str
channel: Optional[str]
source: Optional[str]
username: Optional[str]
title: Optional[str]
prompt: str
options: List[AgentInteractionOption]
created_at: datetime = field(default_factory=datetime.now)
class AgentInteractionManager:
"""管理 Agent 发起的客户端交互请求。"""
_ttl = timedelta(hours=24)
def __init__(self):
self._pending_interactions: Dict[str, PendingAgentInteraction] = {}
self._lock = Lock()
def _cleanup_locked(self):
expire_before = datetime.now() - self._ttl
expired_ids = [
request_id
for request_id, request in self._pending_interactions.items()
if request.created_at < expire_before
]
for request_id in expired_ids:
self._pending_interactions.pop(request_id, None)
def create_request(
self,
session_id: str,
user_id: str,
channel: Optional[str],
source: Optional[str],
username: Optional[str],
title: Optional[str],
prompt: str,
options: List[AgentInteractionOption],
) -> PendingAgentInteraction:
with self._lock:
self._cleanup_locked()
request_id = uuid.uuid4().hex[:12]
while request_id in self._pending_interactions:
request_id = uuid.uuid4().hex[:12]
request = PendingAgentInteraction(
request_id=request_id,
session_id=session_id,
user_id=str(user_id),
channel=channel,
source=source,
username=username,
title=title,
prompt=prompt,
options=options,
)
self._pending_interactions[request_id] = request
return request
def resolve(
self,
request_id: str,
option_index: int,
user_id: Optional[str] = None,
) -> Optional[tuple[PendingAgentInteraction, AgentInteractionOption]]:
with self._lock:
self._cleanup_locked()
request = self._pending_interactions.get(request_id)
if not request:
return None
if user_id is not None and str(request.user_id) != str(user_id):
return None
if option_index < 1 or option_index > len(request.options):
return None
option = request.options[option_index - 1]
self._pending_interactions.pop(request_id, None)
return request, option
def clear(self):
with self._lock:
self._pending_interactions.clear()
agent_interaction_manager = AgentInteractionManager()

View File

@@ -0,0 +1,154 @@
"""对话记忆管理器"""
import asyncio
from datetime import datetime
from typing import Dict, List, Optional
from langchain_core.messages import BaseMessage
from app.core.config import settings
from app.log import logger
from app.schemas.agent import ConversationMemory
class MemoryManager:
"""
对话记忆管理器
"""
def __init__(self):
# 内存中的会话记忆缓存
self.memory_cache: Dict[str, ConversationMemory] = {}
# 内存缓存清理任务
self.cleanup_task: Optional[asyncio.Task] = None
def initialize(self):
"""
初始化记忆管理器
"""
try:
# 启动内存缓存清理任务Redis通过TTL自动过期
self.cleanup_task = asyncio.create_task(
self._cleanup_expired_memories()
)
logger.info("对话记忆管理器初始化完成")
except Exception as e:
logger.warning(f"Redis连接失败将使用内存存储: {e}")
async def close(self):
"""
关闭记忆管理器
"""
if self.cleanup_task:
self.cleanup_task.cancel()
try:
await self.cleanup_task
except asyncio.CancelledError:
pass
logger.info("对话记忆管理器已关闭")
@staticmethod
def _get_memory_key(session_id: str, user_id: str):
"""
计算内存Key
"""
return f"{user_id}:{session_id}" if user_id else session_id
def get_memory(self, session_id: str, user_id: str) -> Optional[ConversationMemory]:
"""
获取内存中的记忆
"""
cache_key = self._get_memory_key(session_id, user_id)
return self.memory_cache.get(cache_key)
def get_agent_messages(
self, session_id: str, user_id: str
) -> List[BaseMessage]:
"""
为Agent获取最近的消息仅内存缓存
如果消息Token数量超过模型最大上下文长度的阀值会自动进行摘要裁剪
"""
memory = self.get_memory(session_id, user_id)
if not memory:
return []
# 获取所有消息
return memory.messages
def save_agent_messages(
self, session_id: str, user_id: str, messages: List[BaseMessage]
):
"""
保存Agent消息仅内存缓存
注意Redis中的记忆通过TTL机制自动过期这里只更新内存缓存Redis会在下次访问时自动过期
"""
memory = self.get_memory(session_id, user_id)
if not memory:
memory = ConversationMemory(session_id=session_id, user_id=user_id)
memory.messages = messages
memory.updated_at = datetime.now()
# 更新内存缓存
self.save_memory(memory)
def save_memory(self, memory: ConversationMemory):
"""
保存记忆到内存缓存
注意Redis中的记忆通过TTL机制自动过期这里只更新内存缓存Redis会在下次访问时自动过期
"""
cache_key = self._get_memory_key(memory.session_id, memory.user_id)
self.memory_cache[cache_key] = memory
def clear_memory(self, session_id: str, user_id: str):
"""
清空会话记忆
"""
cache_key = self._get_memory_key(session_id, user_id)
if cache_key in self.memory_cache:
del self.memory_cache[cache_key]
logger.info(f"会话记忆已清空: session_id={session_id}, user_id={user_id}")
async def _cleanup_expired_memories(self):
"""
清理内存中过期记忆的后台任务
注意Redis中的记忆通过TTL机制自动过期这里只清理内存缓存
"""
while True:
try:
# 每小时清理一次
await asyncio.sleep(3600)
current_time = datetime.now()
expired_sessions = []
# 只检查内存缓存中的过期记忆
# Redis中的记忆会通过TTL自动过期无需手动处理
for cache_key, memory in self.memory_cache.items():
if (
current_time - memory.updated_at
).days > settings.LLM_MEMORY_RETENTION_DAYS:
expired_sessions.append(cache_key)
# 只清理内存缓存不删除Redis中的键Redis会自动过期
for cache_key in expired_sessions:
if cache_key in self.memory_cache:
del self.memory_cache[cache_key]
if expired_sessions:
logger.info(f"清理了{len(expired_sessions)}个过期内存会话记忆")
except asyncio.CancelledError:
break
except Exception as e:
logger.error(f"清理记忆时发生错误: {e}")
memory_manager = MemoryManager()

View File

View File

@@ -0,0 +1,406 @@
"""
活动日志中间件 - 自动记录 Agent 每次交互的操作摘要。
按日期存储在 CONFIG_PATH/agent/activity/YYYY-MM-DD.md 中,
每次 Agent 执行完毕后自动调用 LLM 对本轮对话生成简洁的活动摘要,
并在每次 Agent 启动时加载近几天的活动日志注入系统提示词。
"""
import re
from collections.abc import Awaitable, Callable
from datetime import datetime, timedelta
from typing import Annotated, Any, NotRequired, TypedDict
from anyio import Path as AsyncPath
from langchain.agents.middleware.types import (
AgentMiddleware,
AgentState,
ContextT,
ModelRequest,
ModelResponse,
PrivateStateAttr, # noqa
ResponseT,
)
from langchain_core.messages import AIMessage, HumanMessage, ToolMessage
from langgraph.runtime import Runtime
from app.agent.middleware.utils import append_to_system_message
from app.log import logger
# 活动日志保留天数
DEFAULT_RETENTION_DAYS = 7
# 注入系统提示词时加载的天数
PROMPT_LOAD_DAYS = 3
# 每日日志文件最大大小 (256KB)
MAX_LOG_FILE_SIZE = 256 * 1024
# 提取本轮对话上下文的最大字符数(避免过长的对话消耗太多 token
MAX_CONTEXT_FOR_SUMMARY = 4000
# LLM 总结的提示词
SUMMARY_PROMPT = """请根据以下 AI 助手与用户的对话记录生成一条简洁的活动摘要中文一句话不超过80字
摘要应包含:用户的需求是什么、助手做了什么、结果如何。
只输出摘要内容,不要加任何前缀、标点序号或解释。
对话记录:
{conversation}"""
class ActivityLogState(AgentState):
"""ActivityLogMiddleware 的状态模型。"""
activity_log_contents: NotRequired[Annotated[dict[str, str], PrivateStateAttr]]
"""将日期字符串映射到日志内容的字典。标记为私有,不包含在最终代理状态中。"""
class ActivityLogStateUpdate(TypedDict):
"""ActivityLogMiddleware 的状态更新。"""
activity_log_contents: dict[str, str]
def _extract_last_round(messages: list) -> list | None:
"""从完整消息列表中提取最后一轮交互。
从最后一条 HumanMessage 到消息末尾即为本轮交互。
参数:
messages: Agent 执行后的完整消息列表。
返回:
本轮交互的消息子列表,如果无有效交互则返回 None。
"""
if not messages:
return None
# 找到最后一条用户消息的索引
last_human_idx = None
for i in range(len(messages) - 1, -1, -1):
if isinstance(messages[i], HumanMessage) and messages[i].content:
last_human_idx = i
break
if last_human_idx is None:
return None
round_messages = messages[last_human_idx:]
# 检查是否为系统心跳消息
user_msg = round_messages[0]
user_content = (
user_msg.content if isinstance(user_msg.content, str) else str(user_msg.content)
)
if user_content.strip().startswith("[System Heartbeat]"):
return None
return round_messages
def _format_conversation_for_summary(round_messages: list) -> str:
"""将本轮对话消息格式化为文本,供 LLM 总结。
参数:
round_messages: 本轮交互的消息列表。
返回:
格式化后的对话文本。
"""
lines = []
total_len = 0
for msg in round_messages:
if isinstance(msg, HumanMessage):
content = msg.content if isinstance(msg.content, str) else str(msg.content)
line = f"用户: {content}"
elif isinstance(msg, AIMessage):
if hasattr(msg, "tool_calls") and msg.tool_calls:
tool_names = [
tc["name"]
for tc in msg.tool_calls
if isinstance(tc, dict) and "name" in tc
]
line = f"助手调用工具: {', '.join(tool_names)}"
elif msg.content:
content = (
msg.content if isinstance(msg.content, str) else str(msg.content)
)
line = f"助手: {content}"
else:
continue
elif isinstance(msg, ToolMessage):
content = msg.content if isinstance(msg.content, str) else str(msg.content)
# 工具返回可能很长,截断
if len(content) > 200:
content = content[:200] + "..."
line = f"工具返回: {content}"
else:
continue
# 控制总长度
if total_len + len(line) > MAX_CONTEXT_FOR_SUMMARY:
lines.append("...(后续对话省略)")
break
lines.append(line)
total_len += len(line)
return "\n".join(lines)
async def _summarize_with_llm(conversation_text: str) -> str | None:
"""调用 LLM 对对话文本生成活动摘要。
参数:
conversation_text: 格式化后的对话文本。
返回:
LLM 生成的摘要字符串,失败时返回 None。
"""
try:
from app.helper.llm import LLMHelper
llm = LLMHelper.get_llm(streaming=False)
prompt = SUMMARY_PROMPT.format(conversation=conversation_text)
response = await llm.ainvoke(prompt)
summary = response.content.strip()
# 清理模型可能输出的前缀(如 "摘要:" "总结:"
summary = re.sub(r"^(摘要|总结|活动记录)[:]\s*", "", summary)
return summary if summary else None
except Exception as e:
logger.debug("LLM summarization failed: %s", e)
return None
ACTIVITY_LOG_SYSTEM_PROMPT = """<activity_log>
{activity_log}
</activity_log>
<activity_log_guidelines>
The above <activity_log> contains a record of your recent interactions with the user, automatically maintained by the system.
**How to use this information:**
- Reference past activities when relevant to provide continuity (e.g., "之前帮你订阅了《XXX》现在有更新了")
- Use activity history to understand ongoing tasks and user patterns
- When the user asks "你之前帮我做了什么" or similar questions, refer to this log
- Activity logs are automatically recorded after each interaction - you do NOT need to manually update them
**What is automatically logged:**
- Each user interaction: what was asked, which tools were used, and the outcome
- Timestamps for all activities
- The log is organized by date for easy reference
**Important:**
- Activity logs are READ-ONLY from your perspective - the system manages them automatically
- Do not attempt to edit or write to activity log files
- For long-term preferences and knowledge, continue to use MEMORY.md
- Activity logs are retained for {retention_days} days and then automatically cleaned up
</activity_log_guidelines>
"""
class ActivityLogMiddleware(AgentMiddleware[ActivityLogState, ContextT, ResponseT]): # noqa
"""自动记录和加载 Agent 活动日志的中间件。
- abefore_agent: 加载近几天的活动日志
- awrap_model_call: 将活动日志注入系统提示词
- aafter_agent: 从本次对话中提取摘要并追加到当日日志文件
参数:
activity_dir: 活动日志存储目录路径。
retention_days: 日志保留天数(默认 7 天)。
prompt_load_days: 注入系统提示词时加载的天数(默认 3 天)。
"""
state_schema = ActivityLogState
def __init__(
self,
*,
activity_dir: str,
retention_days: int = DEFAULT_RETENTION_DAYS,
prompt_load_days: int = PROMPT_LOAD_DAYS,
) -> None:
self.activity_dir = activity_dir
self.retention_days = retention_days
self.prompt_load_days = prompt_load_days
def _get_log_path(self, date_str: str) -> AsyncPath:
"""获取指定日期的日志文件路径。"""
return AsyncPath(self.activity_dir) / f"{date_str}.md"
def _format_activity_log(self, contents: dict[str, str]) -> str:
"""格式化活动日志用于系统提示词注入。"""
if not contents:
return ACTIVITY_LOG_SYSTEM_PROMPT.format(
activity_log="(暂无活动记录)",
retention_days=self.retention_days,
)
# 按日期排序(最近的在前)
sorted_dates = sorted(contents.keys(), reverse=True)
sections = []
for date_str in sorted_dates:
content = contents[date_str].strip()
if content:
sections.append(f"### {date_str}\n{content}")
if not sections:
return ACTIVITY_LOG_SYSTEM_PROMPT.format(
activity_log="(暂无活动记录)",
retention_days=self.retention_days,
)
log_body = "\n\n".join(sections)
return ACTIVITY_LOG_SYSTEM_PROMPT.format(
activity_log=log_body,
retention_days=self.retention_days,
)
async def _load_recent_logs(self) -> dict[str, str]:
"""加载近几天的活动日志。"""
contents: dict[str, str] = {}
today = datetime.now().date()
for i in range(self.prompt_load_days):
date = today - timedelta(days=i)
date_str = date.strftime("%Y-%m-%d")
log_path = self._get_log_path(date_str)
if await log_path.exists():
try:
content = await log_path.read_text(encoding="utf-8")
contents[date_str] = content
logger.debug("Loaded activity log for %s", date_str)
except Exception as e:
logger.warning("Failed to load activity log %s: %s", date_str, e)
return contents
async def _append_activity(self, summary: str) -> None:
"""将一条活动记录追加到当日日志文件。"""
today_str = datetime.now().strftime("%Y-%m-%d")
now_str = datetime.now().strftime("%H:%M")
log_path = self._get_log_path(today_str)
# 确保目录存在
dir_path = AsyncPath(self.activity_dir)
if not await dir_path.exists():
await dir_path.mkdir(parents=True, exist_ok=True)
# 检查文件大小
if await log_path.exists():
stat = await log_path.stat()
if stat.st_size >= MAX_LOG_FILE_SIZE:
logger.warning(
"Activity log %s exceeds size limit (%d bytes), skipping append",
today_str,
stat.st_size,
)
return
# 追加记录
entry = f"- **{now_str}** {summary}\n"
try:
if await log_path.exists():
existing = await log_path.read_text(encoding="utf-8")
await log_path.write_text(existing + entry, encoding="utf-8")
else:
header = f"# {today_str} 活动日志\n\n"
await log_path.write_text(header + entry, encoding="utf-8")
logger.debug("Activity logged: %s", summary[:80])
except Exception as e:
logger.warning("Failed to append activity log: %s", e)
async def _cleanup_old_logs(self) -> None:
"""清理超过保留天数的旧日志文件。"""
dir_path = AsyncPath(self.activity_dir)
if not await dir_path.exists():
return
cutoff_date = datetime.now().date() - timedelta(days=self.retention_days)
date_pattern = re.compile(r"^(\d{4}-\d{2}-\d{2})\.md$")
try:
async for path in dir_path.iterdir():
if not await path.is_file():
continue
match = date_pattern.match(path.name)
if not match:
continue
try:
file_date = datetime.strptime(match.group(1), "%Y-%m-%d").date()
if file_date < cutoff_date:
await path.unlink()
logger.debug("Cleaned up old activity log: %s", path.name)
except ValueError:
continue
except Exception as e:
logger.warning("Failed to cleanup old activity logs: %s", e)
async def abefore_agent(
self, state: ActivityLogState, runtime: Runtime
) -> ActivityLogStateUpdate | None:
"""在 Agent 执行前加载近期活动日志。"""
# 如果已经加载则跳过
if "activity_log_contents" in state:
return None
contents = await self._load_recent_logs()
# 趁机清理旧日志(低频操作,不影响性能)
await self._cleanup_old_logs()
return ActivityLogStateUpdate(activity_log_contents=contents)
def modify_request(self, request: ModelRequest[ContextT]) -> ModelRequest[ContextT]:
"""将活动日志注入系统消息。"""
contents = request.state.get("activity_log_contents", {})
activity_log_prompt = self._format_activity_log(contents)
new_system_message = append_to_system_message(
request.system_message, activity_log_prompt
)
return request.override(system_message=new_system_message)
async def awrap_model_call(
self,
request: ModelRequest[ContextT],
handler: Callable[
[ModelRequest[ContextT]], Awaitable[ModelResponse[ResponseT]]
],
) -> ModelResponse[ResponseT]:
"""异步包装模型调用,注入活动日志到系统提示词。"""
modified_request = self.modify_request(request)
return await handler(modified_request)
async def aafter_agent(
self, state: ActivityLogState, runtime: Runtime
) -> dict[str, Any] | None:
"""Agent 执行完毕后,调用 LLM 对本轮对话生成摘要并追加到当日活动日志。"""
try:
messages = state.get("messages", [])
if not messages:
return None
# 提取本轮交互
round_messages = _extract_last_round(messages)
if not round_messages:
return None
# 格式化对话文本
conversation_text = _format_conversation_for_summary(round_messages)
if not conversation_text:
return None
# 调用 LLM 生成摘要
summary = await _summarize_with_llm(conversation_text)
if summary:
await self._append_activity(summary)
except Exception as e:
logger.warning("Failed to record activity: %s", e)
return None
__all__ = ["ActivityLogMiddleware"]

View File

@@ -0,0 +1,350 @@
import re
from collections.abc import Awaitable, Callable
from typing import Annotated, NotRequired, TypedDict
import yaml # noqa
from anyio import Path as AsyncPath
from langchain.agents.middleware.types import (
AgentMiddleware,
AgentState,
ContextT,
ModelRequest,
ModelResponse,
PrivateStateAttr, # noqa
ResponseT,
)
from langchain_core.runnables import RunnableConfig
from langgraph.runtime import Runtime
from app.agent.middleware.utils import append_to_system_message
from app.log import logger
# JOB.md 文件最大限制为 1MB
MAX_JOB_FILE_SIZE = 1 * 1024 * 1024
class JobMetadata(TypedDict):
"""Job 元数据。"""
path: str
"""JOB.md 文件路径。"""
id: str
"""Job 标识符(目录名)。"""
name: str
"""Job 名称。"""
description: str
"""Job 描述。"""
schedule: str
"""调度类型: once一次性/ recurring重复性"""
status: str
"""当前状态: pending / in_progress / completed / cancelled。"""
last_run: str | None
"""上次执行时间。"""
class JobsState(AgentState):
"""jobs 中间件状态。"""
jobs_metadata: NotRequired[Annotated[list[JobMetadata], PrivateStateAttr]]
"""已加载的 job 元数据列表,不传播给父 agent。"""
class JobsStateUpdate(TypedDict):
"""jobs 中间件状态更新项。"""
jobs_metadata: list[JobMetadata]
"""待合并的 job 元数据列表。"""
def _parse_job_metadata(
content: str,
job_path: str,
job_id: str,
) -> JobMetadata | None:
"""从 JOB.md 内容中解析 YAML 前言并验证元数据。"""
if len(content) > MAX_JOB_FILE_SIZE:
logger.warning(
"Skipping %s: content too large (%d bytes)", job_path, len(content)
)
return None
# 匹配 --- 分隔的 YAML 前言
frontmatter_pattern = r"^---\s*\n(.*?)\n---\s*\n"
match = re.match(frontmatter_pattern, content, re.DOTALL)
if not match:
logger.warning("Skipping %s: no valid YAML frontmatter found", job_path)
return None
frontmatter_str = match.group(1)
# 解析 YAML
try:
frontmatter_data = yaml.safe_load(frontmatter_str)
except yaml.YAMLError as e:
logger.warning("Invalid YAML in %s: %s", job_path, e)
return None
if not isinstance(frontmatter_data, dict):
logger.warning("Skipping %s: frontmatter is not a mapping", job_path)
return None
# Job 名称和描述
name = str(frontmatter_data.get("name", "")).strip()
description = str(frontmatter_data.get("description", "")).strip()
if not name:
logger.warning("Skipping %s: missing required 'name'", job_path)
return None
# 调度类型
schedule = str(frontmatter_data.get("schedule", "once")).strip().lower()
if schedule not in ("once", "recurring"):
schedule = "once"
# 状态
status = str(frontmatter_data.get("status", "pending")).strip().lower()
if status not in ("pending", "in_progress", "completed", "cancelled"):
status = "pending"
# 上次执行时间
last_run = str(frontmatter_data.get("last_run", "")).strip() or None
return JobMetadata(
id=job_id,
name=name,
description=description,
path=job_path,
schedule=schedule,
status=status,
last_run=last_run,
)
async def _alist_jobs(source_path: AsyncPath) -> list[JobMetadata]:
"""异步列出指定路径下的所有任务。
扫描包含 JOB.md 的目录并解析其元数据。
"""
jobs: list[JobMetadata] = []
if not await source_path.exists():
return []
# 查找所有任务目录(包含 JOB.md 的目录)
job_dirs: list[AsyncPath] = []
async for path in source_path.iterdir():
if await path.is_dir() and await (path / "JOB.md").is_file():
job_dirs.append(path)
if not job_dirs:
return []
# 解析 JOB.md
for job_path in job_dirs:
job_md_path = job_path / "JOB.md"
job_content = await job_md_path.read_text(encoding="utf-8")
# 解析元数据
job_metadata = _parse_job_metadata(
content=job_content,
job_path=str(job_md_path),
job_id=job_path.name,
)
if job_metadata:
jobs.append(job_metadata)
return jobs
JOBS_SYSTEM_PROMPT = """
<jobs_system>
You have a **scheduled jobs** system that allows you to track and execute long-running or recurring tasks.
**Jobs Location:** `{jobs_location}`
**Current Jobs:**
{jobs_list}
**Job File Format:**
Each job is a directory containing a `JOB.md` file with YAML frontmatter followed by task details:
```markdown
---
name: 任务名称(简短中文描述)
description: 任务的详细描述,说明要做什么
schedule: once 或 recurring
status: pending / in_progress / completed / cancelled
last_run: "YYYY-MM-DD HH:MM"(上次执行时间,可选)
---
# 任务详情
## 目标
详细描述这个任务要完成的目标。
## 执行日志
记录每次执行的情况和结果。
- **2024-01-15 10:00** - 执行了XXX操作结果成功/失败
- **2024-01-16 10:00** - 继续执行XXX...
```
**Job Lifecycle Rules:**
1. **Creating a Job**: When a user asks you to do something periodically or at a later time:
- Create a new directory under the jobs location, directory name is the `job-id` (lowercase, hyphens, 1-64 chars)
- Write a `JOB.md` file with proper frontmatter and detailed task description
- Set `schedule: once` for one-time tasks, `schedule: recurring` for repeating tasks (e.g., daily sign-in, weekly checks)
- Set initial `status: pending`
2. **Executing a Job**: When you work on a job:
- Update `status: in_progress` in the frontmatter
- Execute the required actions using your tools
- Log the execution result in the "执行日志" section with timestamp
- Update `last_run` in frontmatter to current time
3. **Completing a Job**:
- For `schedule: once` tasks: set `status: completed` after successful execution
- For `schedule: recurring` tasks: keep `status: pending` after execution, only update `last_run` time. The job stays active for the next scheduled run.
- Set `status: cancelled` if the user explicitly asks to cancel/stop a task
4. **Heartbeat Check**: You will be periodically woken up to check pending jobs. When woken up:
- Read the jobs directory to find all active jobs (status: pending or in_progress)
- Skip jobs with `status: completed` or `status: cancelled`
- For `schedule: recurring` jobs, check `last_run` to determine if it's time to run again
- Execute pending jobs and update their status/logs accordingly
**Important Notes:**
- Each job MUST have its own separate directory and JOB.md file to avoid conflicts
- Always update the frontmatter fields (status, last_run) when executing a job
- Keep execution logs concise but informative
- For recurring jobs, maintain a rolling log (keep recent entries, you can summarize/remove old entries to keep the file manageable)
- When creating jobs, make the description detailed enough that you can understand and execute the task in future sessions without additional context
**When to Create Jobs:**
- User says "每天帮我..." / "定期..." / "定时..." / "提醒我..." / "以后每次..."
- User requests a task that should be done repeatedly
- User asks for monitoring or periodic checking of something
**When NOT to Create Jobs:**
- User asks for an immediate one-time action (just do it now)
- Simple questions or conversations
- Tasks that are already handled by MoviePilot's built-in scheduler services
</jobs_system>
"""
class JobsMiddleware(AgentMiddleware[JobsState, ContextT, ResponseT]): # noqa
"""加载并向系统提示词注入 Agent Jobs 的中间件。
扫描 jobs 目录下的 JOB.md 文件,解析元数据并注入到系统提示词中,
使智能体了解当前的长期任务及其状态。
"""
state_schema = JobsState
def __init__(self, *, sources: list[str]) -> None:
"""初始化 Jobs 中间件。"""
self.sources = sources
self.system_prompt_template = JOBS_SYSTEM_PROMPT
@staticmethod
def _format_jobs_list(jobs: list[JobMetadata]) -> str:
"""格式化任务元数据列表用于系统提示词。"""
if not jobs:
return "(No active jobs. You can create jobs when users request periodic or scheduled tasks.)"
lines = []
for job in jobs:
status_emoji = {
"pending": "",
"in_progress": "🔄",
"completed": "",
"cancelled": "",
}.get(job["status"], "")
schedule_label = (
"recurring (重复)"
if job["schedule"] == "recurring"
else "once (一次性)"
)
desc_line = (
f"- {status_emoji} **{job['id']}**: {job['name']}"
f" [{schedule_label}] - {job['description']}"
)
if job.get("last_run"):
desc_line += f" (上次执行: {job['last_run']})"
lines.append(desc_line)
lines.append(f" -> Read `{job['path']}` for full details")
return "\n".join(lines)
def modify_request(self, request: ModelRequest[ContextT]) -> ModelRequest[ContextT]:
"""将任务文档注入模型请求的系统消息中。"""
jobs_metadata = request.state.get("jobs_metadata", []) # noqa
# 过滤只展示活跃任务pending / in_progress / recurring
active_jobs = [
j
for j in jobs_metadata
if j["status"] in ("pending", "in_progress")
or (j["schedule"] == "recurring" and j["status"] not in ("cancelled",))
]
jobs_list = self._format_jobs_list(active_jobs)
jobs_location = self.sources[0] if self.sources else ""
jobs_section = self.system_prompt_template.format(
jobs_location=jobs_location,
jobs_list=jobs_list,
)
new_system_message = append_to_system_message(
request.system_message, jobs_section
)
return request.override(system_message=new_system_message)
async def abefore_agent( # noqa
self, state: JobsState, runtime: Runtime, config: RunnableConfig
) -> JobsStateUpdate | None:
"""在 Agent 执行前异步加载任务元数据。
每个会话仅加载一次。若 state 中已有则跳过。
"""
# 如果 state 中已存在元数据则跳过
if "jobs_metadata" in state:
return None
all_jobs: list[JobMetadata] = []
# 遍历源加载任务
for source_path_str in self.sources:
source_path = AsyncPath(source_path_str)
if not await source_path.exists():
await source_path.mkdir(parents=True, exist_ok=True)
continue
source_jobs = await _alist_jobs(source_path)
all_jobs.extend(source_jobs)
return JobsStateUpdate(jobs_metadata=all_jobs)
async def awrap_model_call(
self,
request: ModelRequest[ContextT],
handler: Callable[
[ModelRequest[ContextT]], Awaitable[ModelResponse[ResponseT]]
],
) -> ModelResponse[ResponseT]:
"""在模型调用时注入任务文档。"""
modified_request = self.modify_request(request)
return await handler(modified_request)
__all__ = ["JobMetadata", "JobsMiddleware"]

View File

@@ -0,0 +1,396 @@
from collections.abc import Awaitable, Callable
from typing import Annotated, NotRequired, TypedDict, Dict
from anyio import Path as AsyncPath
from langchain.agents.middleware.types import (
AgentMiddleware,
AgentState,
ContextT,
ModelRequest,
ModelResponse,
PrivateStateAttr, # noqa
ResponseT,
)
from langchain_core.runnables import RunnableConfig
from langgraph.runtime import Runtime
from app.agent.middleware.utils import append_to_system_message
from app.log import logger
# 记忆文件最大限制为 100KB防止单文件过大导致上下文溢出
MAX_MEMORY_FILE_SIZE = 100 * 1024
# 默认记忆文件名(用户主记忆)
DEFAULT_MEMORY_FILE = "MEMORY.md"
class MemoryState(AgentState):
"""`MemoryMiddleware` 的状态模型。
属性:
memory_contents: 将源路径映射到其加载内容的字典。
标记为私有,因此不包含在最终的代理状态中。
memory_empty: 记忆文件是否为空或不存在。
标记为私有,用于判断是否需要触发初始化引导流程。
"""
memory_contents: NotRequired[Annotated[dict[str, str], PrivateStateAttr]]
memory_empty: NotRequired[Annotated[bool, PrivateStateAttr]]
class MemoryStateUpdate(TypedDict):
"""`MemoryMiddleware` 的状态更新。"""
memory_contents: dict[str, str]
memory_empty: bool
MEMORY_SYSTEM_PROMPT = """<agent_memory>
The following memory files were loaded from your memory directory: `{memory_dir}`
You can create, edit, or organize any `.md` files in this directory to manage your knowledge.
{agent_memory}
</agent_memory>
<memory_guidelines>
The above <agent_memory> was loaded from `.md` files in your memory directory (`{memory_dir}`). As you learn from your interactions with the user, you can save new knowledge by calling the `edit_file` or `write_file` tool on files in this directory.
**Memory file organization:**
- All `.md` files in `{memory_dir}` are automatically loaded as memory.
- `MEMORY.md` is the default/primary memory file for general user preferences and profile.
- You may create additional `.md` files to organize knowledge by topic (e.g., `MEDIA_RULES.md`, `DOWNLOAD_PREFERENCES.md`, `SITE_CONFIGS.md`, etc.).
- Keep each file focused on a specific domain or topic for better organization.
- Subdirectories are NOT scanned — only `.md` files directly in `{memory_dir}`.
**Learning from feedback:**
- One of your MAIN PRIORITIES is to learn from your interactions with the user. These learnings can be implicit or explicit. This means that in the future, you will remember this important information.
- When you need to remember something, updating memory must be your FIRST, IMMEDIATE action - before responding to the user, before calling other tools, before doing anything else. Just update memory immediately.
- When user says something is better/worse, capture WHY and encode it as a pattern.
- Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions.
- A great opportunity to update your memories is when the user interrupts a tool call and provides feedback. You should update your memories immediately before revising the tool call.
- Look for the underlying principle behind corrections, not just the specific mistake.
- The user might not explicitly ask you to remember something, but if they provide information that is useful for future use, you should update your memories immediately.
**Asking for information:**
- If you lack context to perform an action (e.g. send a Slack DM, requires a user ID/email) you should explicitly ask the user for this information.
- It is preferred for you to ask for information, don't assume anything that you do not know!
- When the user provides information that is useful for future use, you should update your memories immediately.
**When to update memories:**
- When the user explicitly asks you to remember something (e.g., "remember my email", "save this preference")
- When the user describes your role or how you should behave (e.g., "you are a web researcher", "always do X")
- When the user gives feedback on your work - capture what was wrong and how to improve
- When the user provides information required for tool use (e.g., slack channel ID, email addresses)
- When the user provides context useful for future tasks, such as how to use tools, or which actions to take in a particular situation
- When you discover new patterns or preferences (coding styles, conventions, workflows)
**When to NOT update memories:**
- When the information is temporary or transient (e.g., "I'm running late", "I'm on my phone right now")
- When the information is a one-time task request (e.g., "Find me a recipe", "What's 25 * 4?")
- When the information is a simple question that doesn't reveal lasting preferences (e.g., "What day is it?", "Can you explain X?")
- When the information is an acknowledgment or small talk (e.g., "Sounds good!", "Hello", "Thanks for that")
- When the information is stale or irrelevant in future conversations
- Never store API keys, access tokens, passwords, or any other credentials in any file, memory, or system prompt.
- If the user asks where to put API keys or provides an API key, do NOT echo or save it.
- Do NOT record daily activities or task execution history in memory files - these are automatically tracked in the activity log system (see <activity_log>). Memory files are only for long-term knowledge, preferences, and patterns.
**Examples:**
Example 1 (remembering user information):
User: Can you connect to my google account?
Agent: Sure, I'll connect to your google account, what's your google account email?
User: john@example.com
Agent: Let me save this to my memory.
Tool Call: edit_file(...) -> remembers that the user's google account email is john@example.com
Example 2 (remembering implicit user preferences):
User: Can you write me an example for creating a deep agent in LangChain?
Agent: Sure, I'll write you an example for creating a deep agent in LangChain <example code in Python>
User: Can you do this in JavaScript
Agent: Let me save this to my memory.
Tool Call: edit_file(...) -> remembers that the user prefers to get LangChain code examples in JavaScript
Agent: Sure, here is the JavaScript example<example code in JavaScript>
Example 3 (do not remember transient information):
User: I'm going to play basketball tonight so I will be offline for a few hours.
Agent: Okay I'll add a block to your calendar.
Tool Call: create_calendar_event(...) -> just calls a tool, does not commit anything to memory, as it is transient information
</memory_guidelines>
"""
MEMORY_ONBOARDING_PROMPT = """<agent_memory>
(No memory loaded — this is a brand new user with no saved preferences.)
Memory directory: {memory_dir}
Default memory file: {memory_file}
</agent_memory>
<memory_onboarding>
**IMPORTANT — First-time user detected!**
The memory directory is currently empty. This means this is likely the user's first interaction, or their preferences have been reset.
**Your MANDATORY first action in this conversation:**
Before doing ANYTHING else (before answering questions, before calling tools, before performing any task), you MUST proactively greet the user warmly and ask them about their preferences so you can provide personalized service going forward. Specifically, ask about:
1. **How to address the user** — Ask what name or nickname they'd like you to call them (e.g., a real name, a nickname, or a fun title). This is the top priority for building a personal connection.
2. **Communication style preference** — Do they prefer a cute/playful tone (with emojis), a formal/professional tone, a concise/minimalist style, or something else?
3. **Media preferences** — What types of media do they primarily care about? (e.g., movies, TV shows, anime, documentaries, etc.)
4. **Quality preferences** — Do they have preferred video quality (4K, 1080p), codecs (H.265, H.264), or subtitle language preferences?
5. **Any other special requests** — Anything else they'd like you to always keep in mind?
**After the user replies**, you MUST immediately:
1. Use the `write_file` tool to save ALL their preferences to the memory file at: `{memory_file}`
2. Format the memory file in clean Markdown with clear sections (e.g., `## User Profile`, `## Communication Style`, `## Media Preferences`, etc.)
3. The `## User Profile` section MUST include the user's preferred name/nickname at the top
4. Only AFTER saving the preferences, proceed to help with whatever the user originally asked about (if anything)
5. From this point on, always address the user by their preferred name/nickname in conversations
6. You may also create additional `.md` files in the memory directory (`{memory_dir}`) for different topics as needed.
**If the user skips the preference questions** and directly asks you to do something:
- Go ahead and help them with their request first
- But still ask about their preferences naturally at the end of the interaction
- Save whatever you learn about them (implicit or explicit) to the memory file
**Example onboarding flow:**
The greeting should introduce yourself, explain this is the first meeting, and ask the above questions in a numbered list. Adapt the tone to your persona defined in the base system prompt.
</memory_onboarding>
<memory_guidelines>
Your memory directory is at: {memory_dir}. You can save new knowledge by calling the `edit_file` or `write_file` tool on any `.md` file in this directory.
**Memory file organization:**
- `MEMORY.md` is the default/primary memory file for general user preferences and profile.
- You may create additional `.md` files to organize knowledge by topic.
- All `.md` files directly in the memory directory are automatically loaded on each conversation.
**Learning from feedback:**
- One of your MAIN PRIORITIES is to learn from your interactions with the user. These learnings can be implicit or explicit. This means that in the future, you will remember this important information.
- When you need to remember something, updating memory must be your FIRST, IMMEDIATE action - before responding to the user, before calling other tools, before doing anything else. Just update memory immediately.
- When user says something is better/worse, capture WHY and encode it as a pattern.
- Each correction is a chance to improve permanently - don't just fix the immediate issue, update your instructions.
- The user might not explicitly ask you to remember something, but if they provide information that is useful for future use, you should update your memories immediately.
**When to update memories:**
- When the user explicitly asks you to remember something
- When the user describes your role or how you should behave
- When the user gives feedback on your work
- When the user provides information required for tool use
- When you discover new patterns or preferences
**When to NOT update memories:**
- Temporary/transient information
- One-time task requests
- Simple questions, acknowledgments, or small talk
- Never store API keys, access tokens, passwords, or credentials
- Do NOT record daily activities in memory files — those go to the activity log
</memory_guidelines>
"""
class MemoryMiddleware(AgentMiddleware[MemoryState, ContextT, ResponseT]): # noqa
"""从代理记忆目录加载所有 MD 文件作为记忆的中间件。
自动扫描指定目录下的所有 `.md` 文件,加载其内容并注入到系统提示词中。
支持多文件记忆组织:用户可以创建多个 `.md` 文件来按主题组织知识。
参数:
memory_dir: 记忆文件目录路径。
"""
state_schema = MemoryState
def __init__(
self,
*,
memory_dir: str,
) -> None:
"""初始化记忆中间件。
参数:
memory_dir: 记忆文件目录路径(例如,`"/config/agent"`)。
该目录下所有 `.md` 文件都会被自动加载为记忆。
"""
self.memory_dir = memory_dir
self.default_memory_file = str(AsyncPath(memory_dir) / DEFAULT_MEMORY_FILE)
@staticmethod
def _is_memory_empty(contents: dict[str, str]) -> bool:
"""判断记忆内容是否为空。
检查所有源文件的内容,如果全部为空或仅包含空白字符则返回 True。
参数:
contents: 将源路径映射到内容的字典。
返回:
如果记忆为空则返回 True否则返回 False。
"""
if not contents:
return True
return all(not content.strip() for content in contents.values())
def _format_agent_memory(
self, contents: dict[str, str], memory_empty: bool = False
) -> str:
"""格式化记忆,将位置和内容成对组合。
当记忆为空时,返回初始化引导提示词,引导智能体主动询问用户偏好。
当记忆非空时,返回标准记忆系统提示词,包含所有加载的文件内容。
参数:
contents: 将源路径映射到内容的字典。
memory_empty: 记忆是否为空的标志位。
返回:
在 <agent_memory> 标签中包装了位置+内容对的格式化字符串。
"""
# 记忆为空时返回初始化引导提示词
if memory_empty or self._is_memory_empty(contents):
return MEMORY_ONBOARDING_PROMPT.format(
memory_dir=self.memory_dir,
memory_file=self.default_memory_file,
)
# 按文件名排序,确保 MEMORY.md 排在最前面
sorted_paths = sorted(
[p for p in contents if contents[p].strip()],
key=lambda p: (0 if AsyncPath(p).name == DEFAULT_MEMORY_FILE else 1, p),
)
if not sorted_paths:
return MEMORY_ONBOARDING_PROMPT.format(
memory_dir=self.memory_dir,
memory_file=self.default_memory_file,
)
sections = []
for path in sorted_paths:
file_name = AsyncPath(path).name
sections.append(f"### {file_name}\n**Path:** `{path}`\n\n{contents[path]}")
memory_body = "\n\n---\n\n".join(sections)
return MEMORY_SYSTEM_PROMPT.format(
agent_memory=memory_body,
memory_dir=self.memory_dir,
)
async def _scan_memory_files(self) -> list[str]:
"""扫描记忆目录下的所有 .md 文件。
仅扫描目录下直接存在的 `.md` 文件(不递归子目录)。
文件大小超过限制的将被跳过。
返回:
发现的 .md 文件路径列表。
"""
dir_path = AsyncPath(self.memory_dir)
if not await dir_path.exists():
return []
md_files: list[str] = []
async for entry in dir_path.iterdir():
if await entry.is_file() and entry.name.lower().endswith(".md"):
md_files.append(str(entry))
return md_files
async def abefore_agent(
self,
state: MemoryState,
runtime: Runtime, # noqa
config: RunnableConfig,
) -> MemoryStateUpdate | None:
"""在代理执行前扫描记忆目录并加载所有 .md 文件的内容。
自动发现目录下所有 `.md` 文件并加载其内容到状态中。
如果状态中尚未存在则进行加载。
同时检测记忆文件是否为空,设置 memory_empty 标志位,
以便在系统提示词中触发初始化引导流程。
参数:
state: 当前代理状态。
runtime: 运行时上下文。
config: Runnable 配置。
返回:
填充了 memory_contents 和 memory_empty 的状态更新。
"""
# 如果已经加载则跳过
if "memory_contents" in state:
return None
# 扫描目录下所有 .md 文件
md_files = await self._scan_memory_files()
contents: Dict[str, str] = {}
for path in md_files:
file_path = AsyncPath(path)
try:
# 检查文件大小
stat = await file_path.stat()
if stat.st_size > MAX_MEMORY_FILE_SIZE:
logger.warning(
"Skipping memory file %s: too large (%d bytes, max %d)",
path,
stat.st_size,
MAX_MEMORY_FILE_SIZE,
)
continue
contents[path] = await file_path.read_text(encoding="utf-8")
logger.debug("Loaded memory from: %s", path)
except Exception as e:
logger.warning("Failed to read memory file %s: %s", path, e)
if contents:
logger.info(
"Loaded %d memory file(s) from %s: %s",
len(contents),
self.memory_dir,
[AsyncPath(p).name for p in contents],
)
# 检测记忆是否为空(文件不存在、文件内容为空白)
is_empty = self._is_memory_empty(contents)
if is_empty:
logger.info(
"Memory is empty, onboarding prompt will be activated for user preference collection."
)
return MemoryStateUpdate(memory_contents=contents, memory_empty=is_empty)
def modify_request(self, request: ModelRequest[ContextT]) -> ModelRequest[ContextT]:
"""将记忆内容注入系统消息。
参数:
request: 要修改的模型请求。
返回:
将记忆注入系统消息后的修改后请求。
"""
contents = request.state.get("memory_contents", {}) # noqa
memory_empty = request.state.get("memory_empty", False) # noqa
agent_memory = self._format_agent_memory(contents, memory_empty=memory_empty)
new_system_message = append_to_system_message(
request.system_message, agent_memory
)
return request.override(system_message=new_system_message)
async def awrap_model_call(
self,
request: ModelRequest[ContextT],
handler: Callable[
[ModelRequest[ContextT]], Awaitable[ModelResponse[ResponseT]]
],
) -> ModelResponse[ResponseT]:
"""异步包装模型调用,将记忆注入系统提示词。
参数:
request: 正在处理的模型请求。
handler: 使用修改后的请求进行调用的异步处理函数。
返回:
来自处理函数的模型响应。
"""
modified_request = self.modify_request(request)
return await handler(modified_request)

View File

@@ -0,0 +1,43 @@
from typing import Any
from langchain.agents.middleware import AgentMiddleware, AgentState
from langchain_core.messages import AIMessage, ToolMessage
from langgraph.runtime import Runtime
from langgraph.types import Overwrite
class PatchToolCallsMiddleware(AgentMiddleware):
"""修复消息历史中悬空工具调用的中间件。"""
def before_agent(self, state: AgentState, runtime: Runtime[Any]) -> dict[str, Any] | None: # noqa: ARG002
"""在代理运行之前,处理任何 AIMessage 中悬空的工具调用。"""
messages = state["messages"]
if not messages or len(messages) == 0:
return None
patched_messages = []
# 遍历消息并添加任何悬空的工具调用
for i, msg in enumerate(messages):
patched_messages.append(msg)
if isinstance(msg, AIMessage) and msg.tool_calls:
for tool_call in msg.tool_calls:
corresponding_tool_msg = next(
(msg for msg in messages[i:] if msg.type == "tool" and msg.tool_call_id == tool_call["id"]),
# ty: ignore[unresolved-attribute]
None,
)
if corresponding_tool_msg is None:
# 我们有一个悬空的工具调用,需要一个 ToolMessage
tool_msg = (
f"Tool call {tool_call['name']} with id {tool_call['id']} was "
"cancelled - another message came in before it could be completed."
)
patched_messages.append(
ToolMessage(
content=tool_msg,
name=tool_call["name"],
tool_call_id=tool_call["id"],
)
)
return {"messages": Overwrite(patched_messages)}

View File

@@ -0,0 +1,524 @@
import re
import shutil
from collections.abc import Awaitable, Callable
from pathlib import Path
from typing import Annotated, List
from typing import NotRequired, TypedDict
import yaml # noqa
from anyio import Path as AsyncPath
from langchain.agents.middleware.types import (
AgentMiddleware,
AgentState,
ContextT,
ModelRequest,
ModelResponse,
ResponseT,
)
from langchain.agents.middleware.types import PrivateStateAttr # noqa
from langchain_core.runnables import RunnableConfig
from langgraph.runtime import Runtime
from app.agent.middleware.utils import append_to_system_message
from app.log import logger
# 安全提示: SKILL.md 文件最大限制为 10MB防止 DoS 攻击
MAX_SKILL_FILE_SIZE = 10 * 1024 * 1024
# Agent Skills 规范约束 (https://agentskills.io/specification)
MAX_SKILL_NAME_LENGTH = 64
MAX_SKILL_DESCRIPTION_LENGTH = 1024
MAX_SKILL_COMPATIBILITY_LENGTH = 500
class SkillMetadata(TypedDict):
"""Skill 元数据,符合 Agent Skills 规范。"""
path: str
"""SKILL.md 文件路径。"""
id: str
"""Skill 标识符。
约束: 1-64 字符,仅限小写字母/数字/连字符,不能以连字符开头或结尾,无连续连字符,需与父目录名一致。
"""
name: str
"""Skill 名称。
约束: Skill中文描述。
"""
version: int
"""Skill 版本号。
用于内置技能的版本管理,同步时比较版本号决定是否覆盖用户目录中的旧版本。
"""
description: str
"""Skill 功能描述。
约束: 1-1024 字符,应说明功能及适用场景。
"""
license: str | None
"""许可证信息。"""
compatibility: str | None
"""环境依赖或兼容性要求 (最多 500 字符)。"""
metadata: dict[str, str]
"""附加元数据。"""
allowed_tools: list[str]
"""(实验性) Skill 建议使用的工具列表。"""
class SkillsState(AgentState):
"""skills 中间件状态。"""
skills_metadata: NotRequired[Annotated[list[SkillMetadata], PrivateStateAttr]]
"""已加载的 skill 元数据列表,不传播给父 agent。"""
class SkillsStateUpdate(TypedDict):
"""skills 中间件状态更新项。"""
skills_metadata: list[SkillMetadata]
"""待合并的 skill 元数据列表。"""
def _parse_skill_metadata( # noqa: C901
content: str,
skill_path: str,
skill_id: str,
) -> SkillMetadata | None:
"""从 SKILL.md 内容中解析 YAML 前言并验证元数据。"""
if len(content) > MAX_SKILL_FILE_SIZE:
logger.warning(
"Skipping %s: content too large (%d bytes)", skill_path, len(content)
)
return None
# 匹配 --- 分隔的 YAML 前言
frontmatter_pattern = r"^---\s*\n(.*?)\n---\s*\n"
match = re.match(frontmatter_pattern, content, re.DOTALL)
if not match:
logger.warning("Skipping %s: no valid YAML frontmatter found", skill_path)
return None
frontmatter_str = match.group(1)
# 解析 YAML
try:
frontmatter_data = yaml.safe_load(frontmatter_str)
except yaml.YAMLError as e:
logger.warning("Invalid YAML in %s: %s", skill_path, e)
return None
if not isinstance(frontmatter_data, dict):
logger.warning("Skipping %s: frontmatter is not a mapping", skill_path)
return None
# SKill名称和描述
name = str(frontmatter_data.get("name", "")).strip()
description = str(frontmatter_data.get("description", "")).strip()
if not name or not description:
logger.warning(
"Skipping %s: missing required 'name' or 'description'", skill_path
)
return None
description_str = description
if len(description_str) > MAX_SKILL_DESCRIPTION_LENGTH:
logger.warning(
"Description exceeds %d characters in %s, truncating",
MAX_SKILL_DESCRIPTION_LENGTH,
skill_path,
)
description_str = description_str[:MAX_SKILL_DESCRIPTION_LENGTH]
# 可选的工具列表,支持空格或逗号分隔
raw_tools = frontmatter_data.get("allowed-tools")
if isinstance(raw_tools, str):
allowed_tools = [
t.strip(",") # 兼容 Claude Code 风格的逗号分隔
for t in raw_tools.split()
if t.strip(",")
]
else:
if raw_tools is not None:
logger.warning(
"Ignoring non-string 'allowed-tools' in %s (got %s)",
skill_path,
type(raw_tools).__name__,
)
allowed_tools = []
# 能力或环境兼容性说明,最多 500 字符
compatibility_str = str(frontmatter_data.get("compatibility", "")).strip() or None
if compatibility_str and len(compatibility_str) > MAX_SKILL_COMPATIBILITY_LENGTH:
logger.warning(
"Compatibility exceeds %d characters in %s, truncating",
MAX_SKILL_COMPATIBILITY_LENGTH,
skill_path,
)
compatibility_str = compatibility_str[:MAX_SKILL_COMPATIBILITY_LENGTH]
# 版本号,默认为 0表示未设置版本
raw_version = frontmatter_data.get("version")
version = 0
if raw_version is not None:
try:
version = int(raw_version)
except (ValueError, TypeError):
logger.warning(
"Invalid 'version' in %s (got %r), defaulting to 0",
skill_path,
raw_version,
)
return SkillMetadata(
id=skill_id,
name=name,
version=version,
description=description_str,
path=skill_path,
metadata=_validate_metadata(frontmatter_data.get("metadata", {}), skill_path),
license=str(frontmatter_data.get("license", "")).strip() or None,
compatibility=compatibility_str,
allowed_tools=allowed_tools,
)
def _validate_metadata(
raw: object,
skill_path: str,
) -> dict[str, str]:
"""验证并规范化 YAML 前言中的元数据字段,确保为 dict[str, str] 类型。"""
if not isinstance(raw, dict):
if raw:
logger.warning(
"Ignoring non-dict metadata in %s (got %s)",
skill_path,
type(raw).__name__,
)
return {}
return {str(k): str(v) for k, v in raw.items()}
def _format_skill_annotations(skill: SkillMetadata) -> str:
"""构建许可证和兼容性说明字符串。"""
parts: list[str] = []
if skill.get("license"):
parts.append(f"License: {skill['license']}")
if skill.get("compatibility"):
parts.append(f"Compatibility: {skill['compatibility']}")
return ", ".join(parts)
async def _alist_skills(source_path: AsyncPath) -> list[SkillMetadata]:
"""异步列出指定路径下的所有技能。
扫描包含 SKILL.md 的目录并解析其元数据。
"""
skills: list[SkillMetadata] = []
# 查找所有技能目录 (包含 SKILL.md 的目录)
skill_dirs: List[AsyncPath] = []
async for path in source_path.iterdir():
if await path.is_dir() and await (path / "SKILL.md").is_file():
skill_dirs.append(path)
if not skill_dirs:
return []
# 解析已下载的 SKILL.md
for skill_path in skill_dirs:
skill_md_path = skill_path / "SKILL.md"
skill_content = await skill_md_path.read_text(encoding="utf-8")
# 解析元数据
skill_metadata = _parse_skill_metadata(
content=skill_content,
skill_path=str(skill_md_path),
skill_id=skill_path.name,
)
if skill_metadata:
skills.append(skill_metadata)
return skills
SKILLS_SYSTEM_PROMPT = """
<skills_system>
You have access to a skills library that provides specialized capabilities and domain knowledge.
{skills_locations}
**Available Skills:**
{skills_list}
**How to Use Skills (Progressive Disclosure):**
Skills follow a **progressive disclosure** pattern - you see their name and description above, but only read full instructions when needed:
1. **Recognize when a skill applies**: Check if the user's task matches a skill's description
2. **Read the skill's full instructions**: Use the path shown in the skill list above
3. **Follow the skill's instructions**: SKILL.md contains step-by-step workflows, best practices, and examples
4. **Access supporting files**: Skills may include helper scripts, configs, or reference docs - use absolute paths
**Creating New Skills:**
When you identify a repetitive complex workflow or specialized task that would benefit from being a skill, you can create one:
1. **Directory Structure**: Create a new directory in one of the skills locations. The directory name is the `skill-id`.
- Path format: `<skills_location>/<skill-id>/SKILL.md`
- `skill-id` constraints: 1-64 characters, lowercase letters, numbers, and hyphens only.
2. **SKILL.md Format**: Must start with a YAML frontmatter followed by markdown instructions.
```markdown
---
name: Brief tool name (Chinese)
description: Detailed functional description and use cases (1-1024 chars)
allowed-tools: "tool1 tool2" (optional, space-separated list of recommended tools)
compatibility: "Environment requirements" (optional, max 500 chars)
---
# Skill Instructions
Step-by-step workflows, best practices, and examples go here.
```
3. **Supporting Files**: You can add `.py` scripts, `.yaml` configs, or other files within the same skill directory. Reference them using absolute paths in `SKILL.md`.
**When to Use Skills:**
- User's request matches a skill's domain (e.g., "research X" -> web-research skill)
- You need specialized knowledge or structured workflows
- A skill provides proven patterns for complex tasks
**Executing Skill Scripts:**
Skills may contain Python scripts or other executable files. Always use absolute paths from the skill list.
**Example Workflow:**
User: "Can you research the latest developments in quantum computing?"
1. Check available skills -> See "web-research" skill with its path
2. Read the skill using the path shown
3. Follow the skill's research workflow (search -> organize -> synthesize)
4. Use any helper scripts with absolute paths
Remember: Skills make you more capable and consistent. When in doubt, check if a skill exists for the task!
</skills_system>
"""
def _extract_version(skill_md: Path) -> int:
"""从 SKILL.md 文件中快速提取 version 字段,无法提取时返回 0。"""
try:
content = skill_md.read_text(encoding="utf-8")
except Exception:
return 0
match = re.match(r"^---\s*\n(.*?)\n---\s*\n", content, re.DOTALL)
if not match:
return 0
try:
frontmatter = yaml.safe_load(match.group(1))
except yaml.YAMLError:
return 0
if not isinstance(frontmatter, dict):
return 0
raw = frontmatter.get("version")
if raw is None:
return 0
try:
return int(raw)
except (ValueError, TypeError):
return 0
def _sync_bundled_skills(bundled_dir: Path, target_dir: Path) -> None:
"""将项目自带的技能同步到用户目录。
- 目标目录中不存在对应技能子目录时,直接复制。
- 目标目录中已存在时,比较内置与用户目录中 SKILL.md 的 version 字段:
- 内置版本更高时,直接覆盖用户目录中的旧版本。
- 版本相同或用户版本更高时,跳过。
- 内置 SKILL.md 无 version 字段(视为 0不覆盖。
Parameters
----------
bundled_dir : Path
项目内置技能目录(如 ``ROOT_PATH / "skills"``)。
target_dir : Path
用户配置技能目录(如 ``CONFIG_PATH / "agent" / "skills"``)。
"""
if not bundled_dir.is_dir():
return
target_dir.mkdir(parents=True, exist_ok=True)
for skill_src in bundled_dir.iterdir():
if not skill_src.is_dir():
continue
skill_md = skill_src / "SKILL.md"
if not skill_md.is_file():
continue
skill_dst = target_dir / skill_src.name
if not skill_dst.exists():
# 目标不存在,直接复制
try:
shutil.copytree(str(skill_src), str(skill_dst))
logger.info(
"已自动复制内置技能 '%s' -> '%s'", skill_src.name, skill_dst
)
except Exception as e:
logger.warning("复制内置技能 '%s' 失败: %s", skill_src.name, e)
continue
# 目标已存在,比较版本号
bundled_version = _extract_version(skill_md)
if bundled_version <= 0:
# 内置技能无版本号,保持旧逻辑不覆盖
continue
user_skill_md = skill_dst / "SKILL.md"
user_version = _extract_version(user_skill_md) if user_skill_md.is_file() else 0
if bundled_version <= user_version:
# 用户版本 >= 内置版本,跳过
continue
# 内置版本更高,删除旧版本后覆盖
try:
shutil.rmtree(str(skill_dst))
shutil.copytree(str(skill_src), str(skill_dst))
logger.info(
"已更新内置技能 '%s' (v%d -> v%d)",
skill_src.name,
user_version,
bundled_version,
)
except Exception as e:
logger.warning("更新内置技能 '%s' 失败: %s", skill_src.name, e)
class SkillsMiddleware(AgentMiddleware[SkillsState, ContextT, ResponseT]): # noqa
"""加载并向系统提示词注入 Agent Skill 的中间件。
按源顺序加载 Skill后加载的会覆盖重名的。
启动时自动将项目内置技能bundled_skills_dir同步到用户技能目录。
"""
state_schema = SkillsState
def __init__(
self,
*,
sources: list[str],
bundled_skills_dir: str | None = None,
) -> None:
"""初始化 Skill 中间件。
Parameters
----------
sources : list[str]
用户技能目录列表。
bundled_skills_dir : str | None
项目内置技能目录路径。若提供,在首次加载前会将其中不存在于
sources 首个目录的技能自动复制过去。
"""
self.sources = sources
self.bundled_skills_dir = bundled_skills_dir
self.system_prompt_template = SKILLS_SYSTEM_PROMPT
def _format_skills_locations(self) -> str:
"""格式化技能位置信息用于系统提示词。"""
locations = []
for i, source_path in enumerate(self.sources):
suffix = " (higher priority)" if i == len(self.sources) - 1 else ""
locations.append(f"**MoviePilot Skills**: `{source_path}`{suffix}")
return "\n".join(locations)
def _format_skills_list(self, skills: list[SkillMetadata]) -> str:
"""格式化技能元数据列表用于系统提示词。"""
if not skills:
paths = [f"{source_path}" for source_path in self.sources]
return f"(No skills available yet. You can create skills in {' or '.join(paths)})"
lines = []
for skill in skills:
annotations = _format_skill_annotations(skill)
desc_line = f"- **{skill['id']}**: {skill['name']} - {skill['description']}"
if annotations:
desc_line += f" ({annotations})"
lines.append(desc_line)
if skill["allowed_tools"]:
lines.append(f" -> Allowed tools: {', '.join(skill['allowed_tools'])}")
lines.append(f" -> Read `{skill['path']}` for full instructions")
return "\n".join(lines)
def modify_request(self, request: ModelRequest[ContextT]) -> ModelRequest[ContextT]:
"""将技能文档注入模型请求的系统消息中。"""
skills_metadata = request.state.get("skills_metadata", []) # noqa
skills_locations = self._format_skills_locations()
skills_list = self._format_skills_list(skills_metadata)
skills_section = self.system_prompt_template.format(
skills_locations=skills_locations,
skills_list=skills_list,
)
new_system_message = append_to_system_message(
request.system_message, skills_section
)
return request.override(system_message=new_system_message)
async def abefore_agent( # noqa
self, state: SkillsState, runtime: Runtime, config: RunnableConfig
) -> SkillsStateUpdate | None: # ty: ignore[invalid-method-override]
"""在 Agent 执行前异步加载技能元数据。
每个会话仅加载一次。若 state 中已有则跳过。
首次加载时,会先将内置技能同步到用户目录(如不存在)。
"""
# 如果 state 中已存在元数据则跳过
if "skills_metadata" in state:
return None
# 自动同步内置技能到首个用户技能目录
if self.bundled_skills_dir and self.sources:
bundled = Path(self.bundled_skills_dir)
target = Path(self.sources[0])
try:
_sync_bundled_skills(bundled, target)
except Exception as e:
logger.warning("同步内置技能失败: %s", e)
all_skills: dict[str, SkillMetadata] = {}
# 遍历源按顺序加载技能,重名时后者覆盖前者
for source_path in self.sources:
skill_source_path = AsyncPath(source_path)
if not await skill_source_path.exists():
await skill_source_path.mkdir(parents=True, exist_ok=True)
continue
source_skills = await _alist_skills(skill_source_path)
for skill in source_skills:
all_skills[skill["name"]] = skill
skills = list(all_skills.values())
return SkillsStateUpdate(skills_metadata=skills)
async def awrap_model_call(
self,
request: ModelRequest[ContextT],
handler: Callable[
[ModelRequest[ContextT]], Awaitable[ModelResponse[ResponseT]]
],
) -> ModelResponse[ResponseT]:
"""在模型调用时注入技能文档。"""
modified_request = self.modify_request(request)
return await handler(modified_request)
__all__ = ["SkillMetadata", "SkillsMiddleware"]

View File

@@ -0,0 +1,21 @@
from langchain_core.messages import SystemMessage, ContentBlock
def append_to_system_message(
system_message: SystemMessage | None,
text: str,
) -> SystemMessage:
"""将文本追加到系统消息。
参数:
system_message: 现有的系统消息或 None。
text: 要添加到系统消息的文本。
返回:
追加了文本的新 SystemMessage。
"""
new_content: list[ContentBlock] = list(system_message.content_blocks) if system_message else [] # noqa
if new_content:
text = f"\n\n{text}"
new_content.append({"type": "text", "text": text})
return SystemMessage(content_blocks=new_content)

View File

@@ -0,0 +1,68 @@
You are an AI media assistant powered by MoviePilot. You specialize in managing home media ecosystems: searching for movies/TV shows, managing subscriptions, overseeing downloads, and organizing media libraries.
All your responses must be in **Chinese (中文)**.
You act as a proactive agent. Your goal is to fully resolve the user's media-related requests autonomously. Do not end your turn until the task is complete or you are blocked and require user feedback.
Core Capabilities:
1. Media Search & Recognition — Identify movies, TV shows, and anime; recognize media from fuzzy filenames or incomplete titles.
2. Subscription Management — Create rules for automated downloading; monitor trending content.
3. Download Control — Search torrents across trackers; filter by quality, codec, and release group.
4. System Status & Organization — Monitor downloads, server health, file transfers, renaming, and library cleanup.
5. Visual Input Handling — Users may attach images from supported channels; analyze them together with the text when relevant.
6. File Context Handling — User messages may arrive as structured JSON. Treat the `message` field as the user's text. Attachments appear in `files`; when `local_path` is present, use local file tools to inspect the uploaded file directly. When image input is disabled for the current model, user images may also be delivered through `files`.
<communication>
{verbose_spec}
- Tone: friendly, concise. Like a knowledgeable friend, not a corporate bot.
- Use emojis sparingly (1-3 per response): greetings, completions, errors.
- Be direct. NO unnecessary preamble, NO repeating user's words, NO explaining your thinking.
- Use Markdown for structured data. Use `inline code` for media titles/paths.
- Include key details (year, rating, resolution) but do NOT over-explain.
- Do not stop for approval on read-only operations. Only confirm before critical actions (starting downloads, deleting subscriptions).
- If the current channel supports image sending and an image would materially help, you may use the `send_message` tool with `image_url` to send it.
- If the current channel supports file sending and you need to return a local image/file for the user to download, use `send_local_file`.
{button_choice_spec}
- Voice replies: {voice_reply_spec}
- NOT a coding assistant. Do not offer code snippets.
- If user has set preferred communication style in memory, follow that strictly.
</communication>
<response_format>
- Responses MUST be short and punchy: one sentence for confirmations, brief list for search results.
- NO filler phrases like "Let me help you", "Here are the results", "I found..." — skip all unnecessary preamble.
- NO repeating what user said.
- NO narrating your internal reasoning.
- After task completion: one line summary only.
- When error occurs: brief acknowledgment + suggestion, then move on.
</response_format>
<flow>
1. Media Discovery: Identify exact media metadata (TMDB ID, Season/Episode) using search tools.
2. Context Checking: Verify current status (already in library? already subscribed?).
3. Action Execution: Perform the task with a brief status update only if the operation takes time.
4. Final Confirmation: State the result concisely.
</flow>
<tool_calling_strategy>
- Call independent tools in parallel whenever possible.
- If search results are ambiguous, use `query_media_detail` or `recognize_media` to clarify before proceeding.
- If `search_media` fails, fall back to `search_web` or `recognize_media`. Only ask the user when all automated methods are exhausted.
</tool_calling_strategy>
<media_management_rules>
1. Download Safety: Present found torrents (size, seeds, quality) and get explicit consent before downloading.
2. Subscription Logic: Check for the best matching quality profile based on user history or defaults.
3. Library Awareness: Check if content already exists in the library to avoid duplicates.
4. Error Handling: If a tool or site fails, briefly explain what went wrong and suggest an alternative.
</media_management_rules>
<markdown_spec>
Specific markdown rules:
{markdown_spec}
</markdown_spec>
<system_info>
{moviepilot_info}
</system_info>

View File

@@ -0,0 +1,217 @@
"""提示词管理器"""
import socket
from pathlib import Path
from time import strftime
from typing import Dict
from app.core.config import settings
from app.log import logger
from app.schemas import (
ChannelCapability,
ChannelCapabilities,
MessageChannel,
ChannelCapabilityManager,
)
from app.utils.system import SystemUtils
class PromptManager:
"""
提示词管理器
"""
def __init__(self, prompts_dir: str = None):
if prompts_dir is None:
self.prompts_dir = Path(__file__).parent
else:
self.prompts_dir = Path(prompts_dir)
self.prompts_cache: Dict[str, str] = {}
def load_prompt(self, prompt_name: str) -> str:
"""
加载指定的提示词
"""
if prompt_name in self.prompts_cache:
return self.prompts_cache[prompt_name]
prompt_file = self.prompts_dir / prompt_name
try:
with open(prompt_file, "r", encoding="utf-8") as f:
content = f.read().strip()
# 缓存提示词
self.prompts_cache[prompt_name] = content
logger.info(f"提示词加载成功: {prompt_name},长度:{len(content)} 字符")
return content
except FileNotFoundError:
logger.error(f"提示词文件不存在: {prompt_file}")
raise
except Exception as e:
logger.error(f"加载提示词失败: {prompt_name}, 错误: {e}")
raise
def get_agent_prompt(
self, channel: str = None, prefer_voice_reply: bool = False
) -> str:
"""
获取智能体提示词
:param channel: 消息渠道Telegram、微信、Slack等
:param prefer_voice_reply: 是否优先使用语音回复
:return: 提示词内容
"""
# 基础提示词
base_prompt = self.load_prompt("Agent Prompt.txt")
# 识别渠道
markdown_spec = ""
msg_channel = (
next(
(c for c in MessageChannel if c.value.lower() == channel.lower()), None
)
if channel
else None
)
# 获取渠道能力说明
if msg_channel:
caps = ChannelCapabilityManager.get_capabilities(msg_channel)
if caps:
markdown_spec = self._generate_formatting_instructions(caps)
button_choice_spec = self._generate_button_choice_instructions(msg_channel)
# 啰嗦模式
verbose_spec = ""
if not settings.AI_AGENT_VERBOSE:
verbose_spec = (
"\n\n[Important Instruction] STRICTLY ENFORCED: DO NOT output any conversational "
"text, thinking processes, or explanations before or during tool calls. Call tools "
"directly without any transitional phrases. "
"You MUST remain completely silent until the task is completely finished. "
"DO NOT output any content whatsoever until your final summary reply."
)
# MoviePilot系统信息
moviepilot_info = self._get_moviepilot_info()
voice_reply_spec = self._generate_voice_reply_instructions(
prefer_voice_reply=prefer_voice_reply
)
# 始终替换占位符,避免后续 .format() 时因残留花括号报 KeyError
base_prompt = base_prompt.format(
markdown_spec=markdown_spec,
verbose_spec=verbose_spec,
moviepilot_info=moviepilot_info,
voice_reply_spec=voice_reply_spec,
button_choice_spec=button_choice_spec,
)
return base_prompt
@staticmethod
def _get_moviepilot_info() -> str:
"""
获取MoviePilot系统信息用于注入到系统提示词中
"""
# 获取主机名和IP地址
try:
hostname = socket.gethostname()
ip_address = socket.gethostbyname(hostname)
except Exception: # noqa
hostname = "localhost"
ip_address = "127.0.0.1"
# 配置文件和日志文件目录
config_path = str(settings.CONFIG_PATH)
log_path = str(settings.LOG_PATH)
# API地址构建
api_port = settings.PORT
api_path = settings.API_V1_STR
# API令牌
api_token = settings.API_TOKEN or "未设置"
# 数据库信息
db_type = settings.DB_TYPE
if db_type == "sqlite":
db_info = f"SQLite ({settings.CONFIG_PATH / 'db' / 'moviepilot.db'})"
else:
db_password = settings.DB_POSTGRESQL_PASSWORD or ""
db_info = f"PostgreSQL ({settings.DB_POSTGRESQL_USERNAME}:{db_password}@{settings.DB_POSTGRESQL_HOST}:{settings.DB_POSTGRESQL_PORT}/{settings.DB_POSTGRESQL_DATABASE})"
info_lines = [
f"- 当前时间: {strftime('%Y-%m-%d %H:%M:%S')}",
f"- 运行环境: {SystemUtils.platform} {'docker' if SystemUtils.is_docker() else ''}",
f"- 主机名: {hostname}",
f"- IP地址: {ip_address}",
f"- API端口: {api_port}",
f"- API路径: {api_path}",
f"- API令牌: {api_token}",
f"- 外网域名: {settings.APP_DOMAIN or '未设置'}",
f"- 数据库类型: {db_type}",
f"- 数据库: {db_info}",
f"- 配置文件目录: {config_path}",
f"- 日志文件目录: {log_path}",
f"- 系统安装目录: {settings.ROOT_PATH}",
]
return "\n".join(info_lines)
@staticmethod
def _generate_formatting_instructions(caps: ChannelCapabilities) -> str:
"""
根据渠道能力动态生成格式指令
"""
instructions = []
if ChannelCapability.RICH_TEXT not in caps.capabilities:
instructions.append(
"- Formatting: Use **Plain Text ONLY**. The channel does NOT support Markdown."
)
instructions.append(
"- No Markdown Symbols: NEVER use `**`, `*`, `__`, or `[` blocks. Use natural text to emphasize (e.g., using ALL CAPS or separators)."
)
instructions.append(
"- Lists: Use plain text symbols like `>` or `*` at the start of lines, followed by manual line breaks."
)
instructions.append("- Links: Paste URLs directly as text.")
return "\n".join(instructions)
@staticmethod
def _generate_voice_reply_instructions(prefer_voice_reply: bool) -> str:
if not prefer_voice_reply:
return (
"- Voice replies: Use normal text replies by default. "
"Only call `send_voice_message` when spoken playback is clearly better than plain text."
)
return (
"- Current message context: The user sent a voice message.\n"
"- Reply preference: Prioritize calling `send_voice_message` for the main user-facing reply.\n"
"- Fallback: If voice is unavailable on the current channel, `send_voice_message` will fall back to text.\n"
"- Do not repeat the same full reply again after calling `send_voice_message`."
)
@staticmethod
def _generate_button_choice_instructions(
channel: MessageChannel = None,
) -> str:
if channel and ChannelCapabilityManager.supports_buttons(
channel
) and ChannelCapabilityManager.supports_callbacks(channel):
return (
"- User questions: If you need the user to choose from a few clear options, "
"call `ask_user_choice` to send button options. After the user clicks a button, "
"the selected value will come back as the user's next message. After calling this tool, "
"wait for the user's selection instead of repeating the question in plain text."
)
return (
"- User questions: When you truly need user input, ask briefly in plain text."
)
def clear_cache(self):
"""
清空缓存
"""
self.prompts_cache.clear()
logger.info("提示词缓存已清空")
prompt_manager = PromptManager()

View File

275
app/agent/tools/base.py Normal file
View File

@@ -0,0 +1,275 @@
import json
from abc import ABCMeta, abstractmethod
from typing import Any, Optional
from langchain_core.tools import BaseTool
from pydantic import PrivateAttr
from app.agent import StreamingHandler
from app.chain import ChainBase
from app.core.config import settings
from app.db.user_oper import UserOper
from app.helper.service import ServiceConfigHelper
from app.log import logger
from app.schemas import Notification
from app.schemas.types import MessageChannel
class ToolChain(ChainBase):
pass
class MoviePilotTool(BaseTool, metaclass=ABCMeta):
"""
MoviePilot专用工具基类LangChain v1 / langchain_core
"""
_session_id: str = PrivateAttr()
_user_id: str = PrivateAttr()
_channel: Optional[str] = PrivateAttr(default=None)
_source: Optional[str] = PrivateAttr(default=None)
_username: Optional[str] = PrivateAttr(default=None)
_stream_handler: Optional[StreamingHandler] = PrivateAttr(default=None)
_require_admin: bool = PrivateAttr(default=False)
_agent_context: dict = PrivateAttr(default_factory=dict)
def __init__(self, session_id: str, user_id: str, **kwargs):
super().__init__(**kwargs)
self._session_id = session_id
self._user_id = user_id
self._require_admin = getattr(self.__class__, "require_admin", False)
def _run(self, *args: Any, **kwargs: Any) -> Any:
raise NotImplementedError("MoviePilotTool 只支持异步调用,请使用 _arun")
async def _arun(self, *args: Any, **kwargs: Any) -> str:
"""
异步运行工具,负责:
1. 在工具调用前将流式消息推送给用户
2. 持久化工具调用记录到会话记忆
3. 调用具体工具逻辑(子类实现的 execute 方法)
4. 持久化工具结果到会话记忆
5. 权限检查
"""
permission_result = await self._check_permission()
if permission_result:
return permission_result
# 获取工具执行提示消息
tool_message = self.get_tool_message(**kwargs)
if not tool_message:
explanation = kwargs.get("explanation")
if explanation:
tool_message = explanation
# 发送工具执行过程消息
if self._stream_handler and self._stream_handler.is_streaming:
if settings.AI_AGENT_VERBOSE:
if self._stream_handler.is_auto_flushing:
# 渠道支持编辑:工具消息追加到 buffer由定时刷新推送
if tool_message:
self._stream_handler.emit(f"\n\n⚙️ => {tool_message}\n\n")
else:
# 渠道不支持编辑:取出 Agent 文字 + 工具消息合并独立发送
agent_message = await self._stream_handler.take()
messages = []
if agent_message:
messages.append(agent_message)
if tool_message:
messages.append(f"⚙️ => {tool_message}")
if messages:
merged_message = "\n\n".join(messages)
await self.send_tool_message(merged_message)
else:
# 非VERBOSE重置缓冲区从头更新保持消息编辑能力
self._stream_handler.reset()
else:
# 未启用流式传输,不发送任何工具消息内容
pass
logger.debug(f"Executing tool {self.name} with args: {kwargs}")
# 执行具体工具逻辑
try:
result = await self.run(**kwargs)
logger.debug(f"Tool {self.name} executed with result: {result}")
except Exception as e:
error_message = f"工具执行异常 ({type(e).__name__}): {str(e)}"
logger.error(f"Tool {self.name} execution failed: {e}", exc_info=True)
result = error_message
# 格式化结果
if isinstance(result, str):
formatted_result = result
elif isinstance(result, (int, float)):
formatted_result = str(result)
else:
formatted_result = json.dumps(result, ensure_ascii=False, indent=2)
return formatted_result
def get_tool_message(self, **kwargs) -> Optional[str]:
"""
获取工具执行时的友好提示消息。
子类可以重写此方法,根据实际参数生成个性化的提示消息。
如果返回 None 或空字符串,将回退使用 explanation 参数。
Args:
**kwargs: 工具的所有参数(包括 explanation
Returns:
str: 友好的提示消息,如果返回 None 或空字符串则使用 explanation
"""
return None
@abstractmethod
async def run(self, **kwargs) -> str:
"""子类实现具体的工具执行逻辑"""
raise NotImplementedError
def set_message_attr(self, channel: str, source: str, username: str):
"""
设置消息属性
"""
self._channel = channel
self._source = source
self._username = username
def set_stream_handler(self, stream_handler: StreamingHandler):
"""
设置回调处理器
"""
self._stream_handler = stream_handler
def set_agent_context(self, agent_context: Optional[dict]):
"""
设置与当前 Agent 共享的上下文。
"""
self._agent_context = agent_context or {}
async def _check_permission(self) -> Optional[str]:
"""
检查用户权限:
1. 首先检查工具是否需要管理员权限
2. 如果需要管理员权限,则检查用户是否是渠道管理员
3. 如果渠道没有设置管理员名单,则检查用户是否是系统管理员
4. 如果都不是系统管理员检查用户ID是否等于渠道配置的用户ID
5. 如果都不是,返回权限拒绝消息
"""
if not self._require_admin:
return None
if not self._channel or not self._source:
return None
user_id_str = str(self._user_id) if self._user_id else None
channel_type_map = {
MessageChannel.Telegram: "telegram",
MessageChannel.Discord: "discord",
MessageChannel.Wechat: "wechat",
MessageChannel.Slack: "slack",
MessageChannel.VoceChat: "vocechat",
MessageChannel.SynologyChat: "synologychat",
MessageChannel.QQ: "qqbot",
}
channel_type = None
for key, value in channel_type_map.items():
if self._channel == key.value:
channel_type = value
break
if not channel_type:
return None
admin_key_map = {
"telegram": "TELEGRAM_ADMINS",
"discord": "DISCORD_ADMINS",
"wechat": "WECHAT_ADMINS",
"slack": "SLACK_ADMINS",
"vocechat": "VOCECHAT_ADMINS",
"synologychat": "SYNOLOGYCHAT_ADMINS",
"qqbot": "QQBOT_ADMINS",
}
user_id_key_map = {
"telegram": "TELEGRAM_CHAT_ID",
"vocechat": "VOCECHAT_CHANNEL_ID",
"wechat": "WECHAT_BOT_CHAT_ID",
}
admin_key = admin_key_map.get(channel_type)
user_id_key = user_id_key_map.get(channel_type)
try:
configs = ServiceConfigHelper.get_notification_configs()
for config in configs:
if config.name == self._source and config.config:
channel_admins = config.config.get(admin_key) if admin_key else None
if channel_admins:
admin_list = [
aid.strip()
for aid in str(channel_admins).split(",")
if aid.strip()
]
if user_id_str and user_id_str in admin_list:
return None
user = (
UserOper().get_by_name(self._username)
if self._username
else None
)
if user and user.is_superuser:
return None
return (
"抱歉,您没有执行此工具的权限。"
"只有渠道管理员或系统管理员才能执行工具操作。"
"如需执行工具请联系渠道管理员将您的用户ID添加到渠道管理员列表中"
"或联系系统管理员为您设置权限。"
)
else:
user = (
UserOper().get_by_name(self._username)
if self._username
else None
)
if user and user.is_superuser:
return None
if user_id_key:
config_user_id = config.config.get(user_id_key)
if config_user_id and str(config_user_id) == user_id_str:
return None
return (
"抱歉,您没有执行此工具的权限。"
"只有系统管理员才能执行工具操作。"
"如需执行工具,请联系系统管理员为您设置权限。"
)
except Exception as e:
logger.error(f"检查权限失败: {e}")
return None
async def send_tool_message(
self, message: str, title: str = "", image: Optional[str] = None
):
"""
发送工具消息
"""
await ToolChain().async_post_message(
Notification(
channel=self._channel,
source=self._source,
userid=self._user_id,
username=self._username,
title=title,
text=message,
image=image,
)
)

209
app/agent/tools/factory.py Normal file
View File

@@ -0,0 +1,209 @@
from typing import List, Callable
from app.agent.tools.impl.add_download import AddDownloadTool
from app.agent.tools.impl.add_subscribe import AddSubscribeTool
from app.agent.tools.impl.update_subscribe import UpdateSubscribeTool
from app.agent.tools.impl.search_subscribe import SearchSubscribeTool
from app.agent.tools.impl.get_recommendations import GetRecommendationsTool
from app.agent.tools.impl.query_downloaders import QueryDownloadersTool
from app.agent.tools.impl.query_download_tasks import QueryDownloadTasksTool
from app.agent.tools.impl.query_library_exists import QueryLibraryExistsTool
from app.agent.tools.impl.query_library_latest import QueryLibraryLatestTool
from app.agent.tools.impl.query_sites import QuerySitesTool
from app.agent.tools.impl.update_site import UpdateSiteTool
from app.agent.tools.impl.query_site_userdata import QuerySiteUserdataTool
from app.agent.tools.impl.test_site import TestSiteTool
from app.agent.tools.impl.query_subscribes import QuerySubscribesTool
from app.agent.tools.impl.query_subscribe_shares import QuerySubscribeSharesTool
from app.agent.tools.impl.query_rule_groups import QueryRuleGroupsTool
from app.agent.tools.impl.query_popular_subscribes import QueryPopularSubscribesTool
from app.agent.tools.impl.query_subscribe_history import QuerySubscribeHistoryTool
from app.agent.tools.impl.delete_subscribe import DeleteSubscribeTool
from app.agent.tools.impl.search_media import SearchMediaTool
from app.agent.tools.impl.search_person import SearchPersonTool
from app.agent.tools.impl.search_person_credits import SearchPersonCreditsTool
from app.agent.tools.impl.recognize_media import RecognizeMediaTool
from app.agent.tools.impl.scrape_metadata import ScrapeMetadataTool
from app.agent.tools.impl.query_episode_schedule import QueryEpisodeScheduleTool
from app.agent.tools.impl.query_media_detail import QueryMediaDetailTool
from app.agent.tools.impl.search_torrents import SearchTorrentsTool
from app.agent.tools.impl.get_search_results import GetSearchResultsTool
from app.agent.tools.impl.search_web import SearchWebTool
from app.agent.tools.impl.send_message import SendMessageTool
from app.agent.tools.impl.ask_user_choice import AskUserChoiceTool
from app.agent.tools.impl.send_local_file import SendLocalFileTool
from app.agent.tools.impl.send_voice_message import SendVoiceMessageTool
from app.agent.tools.impl.query_schedulers import QuerySchedulersTool
from app.agent.tools.impl.run_scheduler import RunSchedulerTool
from app.agent.tools.impl.query_workflows import QueryWorkflowsTool
from app.agent.tools.impl.run_workflow import RunWorkflowTool
from app.agent.tools.impl.update_site_cookie import UpdateSiteCookieTool
from app.agent.tools.impl.delete_download import DeleteDownloadTool
from app.agent.tools.impl.delete_download_history import DeleteDownloadHistoryTool
from app.agent.tools.impl.delete_transfer_history import DeleteTransferHistoryTool
from app.agent.tools.impl.modify_download import ModifyDownloadTool
from app.agent.tools.impl.query_directory_settings import QueryDirectorySettingsTool
from app.agent.tools.impl.list_directory import ListDirectoryTool
from app.agent.tools.impl.query_transfer_history import QueryTransferHistoryTool
from app.agent.tools.impl.transfer_file import TransferFileTool
from app.agent.tools.impl.execute_command import ExecuteCommandTool
from app.agent.tools.impl.edit_file import EditFileTool
from app.agent.tools.impl.write_file import WriteFileTool
from app.agent.tools.impl.read_file import ReadFileTool
from app.agent.tools.impl.browse_webpage import BrowseWebpageTool
from app.agent.tools.impl.query_installed_plugins import QueryInstalledPluginsTool
from app.agent.tools.impl.query_plugin_capabilities import QueryPluginCapabilitiesTool
from app.agent.tools.impl.run_slash_command import RunSlashCommandTool
from app.agent.tools.impl.list_slash_commands import ListSlashCommandsTool
from app.agent.tools.impl.query_custom_identifiers import QueryCustomIdentifiersTool
from app.agent.tools.impl.update_custom_identifiers import UpdateCustomIdentifiersTool
from app.core.plugin import PluginManager
from app.log import logger
from app.schemas.message import ChannelCapabilityManager
from app.schemas.types import MessageChannel
from .base import MoviePilotTool
class MoviePilotToolFactory:
"""
MoviePilot工具工厂
"""
@staticmethod
def _should_enable_choice_tool(channel: str = None) -> bool:
if not channel:
return False
try:
message_channel = MessageChannel(channel)
except ValueError:
return False
return ChannelCapabilityManager.supports_buttons(
message_channel
) and ChannelCapabilityManager.supports_callbacks(message_channel)
@staticmethod
def create_tools(
session_id: str,
user_id: str,
channel: str = None,
source: str = None,
username: str = None,
stream_handler: Callable = None,
agent_context: dict = None,
) -> List[MoviePilotTool]:
"""
创建MoviePilot工具列表
"""
tools = []
tool_definitions = [
SearchMediaTool,
SearchPersonTool,
SearchPersonCreditsTool,
RecognizeMediaTool,
ScrapeMetadataTool,
QueryEpisodeScheduleTool,
QueryMediaDetailTool,
AddSubscribeTool,
UpdateSubscribeTool,
SearchSubscribeTool,
SearchTorrentsTool,
GetSearchResultsTool,
SearchWebTool,
AddDownloadTool,
QuerySubscribesTool,
QuerySubscribeSharesTool,
QueryPopularSubscribesTool,
QueryRuleGroupsTool,
QuerySubscribeHistoryTool,
DeleteSubscribeTool,
QueryDownloadTasksTool,
DeleteDownloadTool,
DeleteDownloadHistoryTool,
DeleteTransferHistoryTool,
ModifyDownloadTool,
QueryDownloadersTool,
QuerySitesTool,
UpdateSiteTool,
QuerySiteUserdataTool,
TestSiteTool,
UpdateSiteCookieTool,
GetRecommendationsTool,
QueryLibraryExistsTool,
QueryLibraryLatestTool,
QueryDirectorySettingsTool,
ListDirectoryTool,
QueryTransferHistoryTool,
TransferFileTool,
SendMessageTool,
QuerySchedulersTool,
RunSchedulerTool,
QueryWorkflowsTool,
RunWorkflowTool,
ExecuteCommandTool,
EditFileTool,
WriteFileTool,
ReadFileTool,
BrowseWebpageTool,
QueryInstalledPluginsTool,
QueryPluginCapabilitiesTool,
RunSlashCommandTool,
ListSlashCommandsTool,
QueryCustomIdentifiersTool,
UpdateCustomIdentifiersTool,
]
if MoviePilotToolFactory._should_enable_choice_tool(channel):
tool_definitions.append(AskUserChoiceTool)
tool_definitions.extend(
[
SendLocalFileTool,
SendVoiceMessageTool,
]
)
# 创建内置工具
for ToolClass in tool_definitions:
tool = ToolClass(session_id=session_id, user_id=user_id)
tool.set_message_attr(channel=channel, source=source, username=username)
tool.set_stream_handler(stream_handler=stream_handler)
tool.set_agent_context(agent_context=agent_context)
tools.append(tool)
# 加载插件提供的工具
plugin_tools_count = 0
plugin_tools_info = PluginManager().get_plugin_agent_tools()
for plugin_info in plugin_tools_info:
plugin_id = plugin_info.get("plugin_id")
plugin_name = plugin_info.get("plugin_name")
tool_classes = plugin_info.get("tools", [])
for ToolClass in tool_classes:
try:
# 验证工具类是否继承自 MoviePilotTool
if not issubclass(ToolClass, MoviePilotTool):
logger.warning(
f"插件 {plugin_name}({plugin_id}) 提供的工具类 {ToolClass.__name__} 未继承自 MoviePilotTool已跳过"
)
continue
# 创建工具实例
tool = ToolClass(session_id=session_id, user_id=user_id)
tool.set_message_attr(
channel=channel, source=source, username=username
)
tool.set_stream_handler(stream_handler=stream_handler)
tool.set_agent_context(agent_context=agent_context)
tools.append(tool)
plugin_tools_count += 1
logger.debug(
f"成功加载插件 {plugin_name}({plugin_id}) 的工具: {ToolClass.__name__}"
)
except Exception as e:
logger.error(
f"加载插件 {plugin_name}({plugin_id}) 的工具 {ToolClass.__name__} 失败: {str(e)}"
)
builtin_tools_count = len(tool_definitions)
if plugin_tools_count > 0:
logger.info(
f"成功创建 {len(tools)} 个MoviePilot工具内置工具: {builtin_tools_count} 个,插件工具: {plugin_tools_count} 个)"
)
else:
logger.info(f"成功创建 {len(tools)} 个MoviePilot工具")
return tools

View File

View File

@@ -0,0 +1,176 @@
"""种子搜索工具辅助函数"""
import re
from typing import List, Optional
from app.core.context import Context
from app.utils.crypto import HashUtils
from app.utils.string import StringUtils
SEARCH_RESULT_CACHE_FILE = "__search_result__"
TORRENT_RESULT_LIMIT = 50
def build_torrent_ref(context: Optional[Context]) -> str:
"""生成用于下载校验的短引用"""
if not context or not context.torrent_info:
return ""
return HashUtils.sha1(context.torrent_info.enclosure or "")[:7]
def sort_season_options(options: List[str]) -> List[str]:
"""按前端逻辑排序季集选项"""
if len(options) <= 1:
return options
parsed_options = []
for index, option in enumerate(options):
match = re.match(r"^S(\d+)(?:-S(\d+))?\s*(?:E(\d+)(?:-E(\d+))?)?$", option or "")
if not match:
parsed_options.append({
"original": option,
"season_num": 0,
"episode_num": 0,
"max_episode_num": 0,
"is_whole_season": False,
"index": index,
})
continue
episode_num = int(match.group(3)) if match.group(3) else 0
max_episode_num = int(match.group(4)) if match.group(4) else episode_num
parsed_options.append({
"original": option,
"season_num": int(match.group(1)),
"episode_num": episode_num,
"max_episode_num": max_episode_num,
"is_whole_season": not match.group(3),
"index": index,
})
whole_seasons = [item for item in parsed_options if item["is_whole_season"]]
episodes = [item for item in parsed_options if not item["is_whole_season"]]
whole_seasons.sort(key=lambda item: (-item["season_num"], item["index"]))
episodes.sort(
key=lambda item: (
-item["season_num"],
-(item["max_episode_num"] or item["episode_num"]),
-item["episode_num"],
item["index"],
)
)
return [item["original"] for item in whole_seasons + episodes]
def append_option(options: List[str], value: Optional[str]) -> None:
"""按前端逻辑收集去重后的筛选项"""
if value and value not in options:
options.append(value)
def build_filter_options(items: List[Context]) -> dict:
"""从搜索结果中构建筛选项汇总"""
filter_options = {
"site": [],
"season": [],
"freeState": [],
"edition": [],
"resolution": [],
"videoCode": [],
"releaseGroup": [],
}
for item in items:
torrent_info = item.torrent_info
meta_info = item.meta_info
append_option(filter_options["site"], getattr(torrent_info, "site_name", None))
append_option(filter_options["season"], getattr(meta_info, "season_episode", None))
append_option(filter_options["freeState"], getattr(torrent_info, "volume_factor", None))
append_option(filter_options["edition"], getattr(meta_info, "edition", None))
append_option(filter_options["resolution"], getattr(meta_info, "resource_pix", None))
append_option(filter_options["videoCode"], getattr(meta_info, "video_encode", None))
append_option(filter_options["releaseGroup"], getattr(meta_info, "resource_team", None))
filter_options["season"] = sort_season_options(filter_options["season"])
return filter_options
def match_filter(filter_values: Optional[List[str]], value: Optional[str]) -> bool:
"""匹配前端同款多选筛选规则"""
return not filter_values or bool(value and value in filter_values)
def filter_contexts(items: List[Context],
site: Optional[List[str]] = None,
season: Optional[List[str]] = None,
free_state: Optional[List[str]] = None,
video_code: Optional[List[str]] = None,
edition: Optional[List[str]] = None,
resolution: Optional[List[str]] = None,
release_group: Optional[List[str]] = None) -> List[Context]:
"""按前端同款维度筛选结果"""
filtered_items = []
for item in items:
torrent_info = item.torrent_info
meta_info = item.meta_info
if (
match_filter(site, getattr(torrent_info, "site_name", None))
and match_filter(free_state, getattr(torrent_info, "volume_factor", None))
and match_filter(season, getattr(meta_info, "season_episode", None))
and match_filter(release_group, getattr(meta_info, "resource_team", None))
and match_filter(video_code, getattr(meta_info, "video_encode", None))
and match_filter(resolution, getattr(meta_info, "resource_pix", None))
and match_filter(edition, getattr(meta_info, "edition", None))
):
filtered_items.append(item)
return filtered_items
def simplify_search_result(context: Context, index: int) -> dict:
"""精简单条搜索结果"""
simplified = {}
torrent_info = context.torrent_info
meta_info = context.meta_info
media_info = context.media_info
if torrent_info:
simplified["torrent_info"] = {
"title": torrent_info.title,
"size": StringUtils.format_size(torrent_info.size),
"seeders": torrent_info.seeders,
"peers": torrent_info.peers,
"site_name": torrent_info.site_name,
"torrent_url": f"{build_torrent_ref(context)}:{index}",
"page_url": torrent_info.page_url,
"volume_factor": torrent_info.volume_factor,
"freedate_diff": torrent_info.freedate_diff,
"pubdate": torrent_info.pubdate,
}
if media_info:
simplified["media_info"] = {
"title": media_info.title,
"en_title": media_info.en_title,
"year": media_info.year,
"type": media_info.type.value if media_info.type else None,
"season": media_info.season,
"tmdb_id": media_info.tmdb_id,
}
if meta_info:
simplified["meta_info"] = {
"name": meta_info.name,
"cn_name": meta_info.cn_name,
"en_name": meta_info.en_name,
"year": meta_info.year,
"type": meta_info.type.value if meta_info.type else None,
"begin_season": meta_info.begin_season,
"season_episode": meta_info.season_episode,
"resource_team": meta_info.resource_team,
"video_encode": meta_info.video_encode,
"edition": meta_info.edition,
"resource_pix": meta_info.resource_pix,
}
return simplified

View File

@@ -0,0 +1,277 @@
"""添加下载工具"""
import re
from pathlib import Path
from typing import List, Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool, ToolChain
from app.chain.search import SearchChain
from app.chain.download import DownloadChain
from app.core.config import settings
from app.core.context import Context
from app.core.metainfo import MetaInfo
from app.db.site_oper import SiteOper
from app.helper.directory import DirectoryHelper
from app.log import logger
from app.schemas import TorrentInfo, FileURI
from app.utils.crypto import HashUtils
class AddDownloadInput(BaseModel):
"""添加下载工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
torrent_url: List[str] = Field(
...,
description="One or more torrent_url values. Supports refs from get_search_results (`hash:id`) and magnet links."
)
downloader: Optional[str] = Field(None,
description="Name of the downloader to use (optional, uses default if not specified)")
save_path: Optional[str] = Field(None,
description="Directory path where the downloaded files should be saved. Using `<storage>:<path>` for remote storage. e.g. rclone:/MP, smb:/server/share/Movies. (optional, uses default path if not specified)")
labels: Optional[str] = Field(None,
description="Comma-separated list of labels/tags to assign to the download (optional, e.g., 'movie,hd,bluray')")
class AddDownloadTool(MoviePilotTool):
name: str = "add_download"
description: str = "Add torrent download tasks using refs from get_search_results or magnet links."
args_schema: Type[BaseModel] = AddDownloadInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据下载参数生成友好的提示消息"""
torrent_urls = self._normalize_torrent_urls(kwargs.get("torrent_url"))
downloader = kwargs.get("downloader")
if torrent_urls:
if len(torrent_urls) == 1:
if self._is_torrent_ref(torrent_urls[0]):
message = f"正在添加下载任务: 资源 {torrent_urls[0]}"
else:
message = "正在添加下载任务: 磁力链接"
else:
message = f"正在批量添加下载任务: 共 {len(torrent_urls)} 个资源"
else:
message = "正在添加下载任务"
if downloader:
message += f" [下载器: {downloader}]"
return message
@staticmethod
def _build_torrent_ref(context: Context) -> str:
"""生成用于校验缓存项的短引用"""
if not context or not context.torrent_info:
return ""
return HashUtils.sha1(context.torrent_info.enclosure or "")[:7]
@staticmethod
def _is_torrent_ref(torrent_ref: Optional[str]) -> bool:
"""判断是否为内部搜索结果引用"""
if not torrent_ref:
return False
return bool(re.fullmatch(r"[0-9a-f]{7}:\d+", str(torrent_ref).strip()))
@staticmethod
def _is_magnet_link_input(torrent_url: Optional[str]) -> bool:
"""判断输入是否为允许直接添加的磁力链接"""
if not torrent_url:
return False
value = str(torrent_url).strip()
return value.startswith("magnet:")
@classmethod
def _resolve_cached_context(cls, torrent_ref: str) -> Optional[Context]:
"""从最近一次搜索缓存中解析种子上下文,仅支持 hash:id 格式"""
ref = str(torrent_ref).strip()
if ":" not in ref:
return None
try:
ref_hash, ref_index = ref.split(":", 1)
index = int(ref_index)
except (TypeError, ValueError):
return None
if index < 1:
return None
results = SearchChain().last_search_results() or []
if index > len(results):
return None
context = results[index - 1]
if not ref_hash or cls._build_torrent_ref(context) != ref_hash:
return None
return context
@staticmethod
def _merge_labels_with_system_tag(labels: Optional[str]) -> Optional[str]:
"""合并用户标签与系统默认标签,确保任务可被系统管理"""
system_tag = (settings.TORRENT_TAG or "").strip()
user_labels = [item.strip() for item in (labels or "").split(",") if item.strip()]
if system_tag and system_tag not in user_labels:
user_labels.append(system_tag)
return ",".join(user_labels) if user_labels else None
@staticmethod
def _format_failed_result(failed_messages: List[str]) -> str:
"""统一格式化失败结果"""
return ", ".join([message for message in failed_messages if message])
@staticmethod
def _build_failure_message(torrent_ref: str, error_msg: Optional[str] = None) -> str:
"""构造失败提示"""
normalized_error = (error_msg or "").strip()
prefix = "添加种子任务失败:"
if normalized_error.startswith(prefix):
normalized_error = normalized_error[len(prefix):].lstrip()
if AddDownloadTool._is_magnet_link_input(normalized_error):
normalized_error = ""
if normalized_error:
return f"{torrent_ref} {normalized_error}"
if AddDownloadTool._is_torrent_ref(torrent_ref):
return torrent_ref
return ""
@classmethod
def _normalize_torrent_urls(cls, torrent_url: Optional[List[str] | str]) -> List[str]:
"""统一规范 torrent_url 输入,保留所有非空值"""
if torrent_url is None:
return []
if isinstance(torrent_url, str):
candidates = torrent_url.split(",")
else:
candidates = torrent_url
return [str(item).strip() for item in candidates if item and str(item).strip()]
@staticmethod
def _resolve_direct_download_dir(save_path: Optional[str]) -> Optional[Path]:
"""解析直接下载使用的目录,优先使用 save_path其次使用默认下载目录"""
if save_path:
return Path(save_path)
download_dirs = DirectoryHelper().get_download_dirs()
if not download_dirs:
return None
dir_conf = download_dirs[0]
if not dir_conf.download_path:
return None
return Path(FileURI(storage=dir_conf.storage or "local", path=dir_conf.download_path).uri)
async def run(self, torrent_url: Optional[List[str]] = None,
downloader: Optional[str] = None, save_path: Optional[str] = None,
labels: Optional[str] = None, **kwargs) -> str:
logger.info(
f"执行工具: {self.name}, 参数: torrent_url={torrent_url}, downloader={downloader}, save_path={save_path}, labels={labels}")
try:
torrent_inputs = self._normalize_torrent_urls(torrent_url)
if not torrent_inputs:
return "错误torrent_url 不能为空。"
download_chain = DownloadChain()
merged_labels = self._merge_labels_with_system_tag(labels)
success_count = 0
failed_messages = []
for torrent_input in torrent_inputs:
if self._is_torrent_ref(torrent_input):
cached_context = self._resolve_cached_context(torrent_input)
if not cached_context or not cached_context.torrent_info:
failed_messages.append(f"{torrent_input} 引用无效,请重新使用 get_search_results 查看搜索结果")
continue
cached_torrent = cached_context.torrent_info
site_name = cached_torrent.site_name
torrent_title = cached_torrent.title or torrent_input
torrent_description = cached_torrent.description
enclosure = cached_torrent.enclosure
if not site_name:
failed_messages.append(f"{torrent_input} 缺少站点名称")
continue
siteinfo = await SiteOper().async_get_by_name(site_name)
if not siteinfo:
failed_messages.append(f"{torrent_input} 未找到站点信息 {site_name}")
continue
torrent_info = TorrentInfo(
title=torrent_title,
description=torrent_description,
enclosure=enclosure,
site_name=site_name,
site_ua=siteinfo.ua,
site_cookie=siteinfo.cookie,
site_proxy=siteinfo.proxy,
site_order=siteinfo.pri,
site_downloader=siteinfo.downloader
)
meta_info = MetaInfo(title=torrent_title, subtitle=torrent_description)
media_info = cached_context.media_info if cached_context.media_info else None
if not media_info:
media_info = await ToolChain().async_recognize_media(meta=meta_info)
if not media_info:
failed_messages.append(f"{torrent_input} 无法识别媒体信息")
continue
context = Context(
torrent_info=torrent_info,
meta_info=meta_info,
media_info=media_info
)
else:
if not self._is_magnet_link_input(torrent_input):
failed_messages.append(
f"{torrent_input} 不是有效的下载内容,非 hash:id 时仅支持 magnet: 开头"
)
continue
download_dir = self._resolve_direct_download_dir(save_path)
if not download_dir:
failed_messages.append(f"{torrent_input} 缺少保存路径,且系统未配置可用下载目录")
continue
result = download_chain.download(
content=torrent_input,
download_dir=download_dir,
cookie=None,
label=merged_labels,
downloader=downloader
)
if result:
_, did, _, error_msg = result
else:
did, error_msg = None, "未找到下载器"
if did:
success_count += 1
else:
failed_messages.append(self._build_failure_message(torrent_input, error_msg))
continue
did, error_msg = download_chain.download_single(
context=context,
downloader=downloader,
save_path=save_path,
label=merged_labels,
return_detail=True
)
if did:
success_count += 1
else:
failed_messages.append(self._build_failure_message(torrent_input, error_msg))
if success_count and not failed_messages:
return "任务添加成功"
if success_count:
return f"部分任务添加失败:{self._format_failed_result(failed_messages)}"
return f"任务添加失败:{self._format_failed_result(failed_messages)}"
except Exception as e:
logger.error(f"添加下载任务失败: {e}", exc_info=True)
return f"添加下载任务时发生错误: {str(e)}"

View File

@@ -0,0 +1,138 @@
"""添加订阅工具"""
from typing import Optional, Type, List
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.subscribe import SubscribeChain
from app.log import logger
from app.schemas.types import MediaType
class AddSubscribeInput(BaseModel):
"""添加订阅工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
title: str = Field(..., description="The title of the media to subscribe to (e.g., 'The Matrix', 'Breaking Bad')")
year: str = Field(..., description="Release year of the media (required for accurate identification)")
media_type: str = Field(...,
description="Allowed values: movie, tv")
season: Optional[int] = Field(None,
description="Season number for TV shows (optional, if not specified will subscribe to all seasons)")
tmdb_id: Optional[int] = Field(None,
description="TMDB database ID for precise media identification (optional, can be obtained from search_media tool)")
douban_id: Optional[str] = Field(None,
description="Douban ID for precise media identification (optional, alternative to tmdb_id)")
start_episode: Optional[int] = Field(None,
description="Starting episode number for TV shows (optional, defaults to 1 if not specified)")
total_episode: Optional[int] = Field(None,
description="Total number of episodes for TV shows (optional, will be auto-detected from TMDB if not specified)")
quality: Optional[str] = Field(None,
description="Quality filter as regular expression (optional, e.g., 'BluRay|WEB-DL|HDTV')")
resolution: Optional[str] = Field(None,
description="Resolution filter as regular expression (optional, e.g., '1080p|720p|2160p')")
effect: Optional[str] = Field(None,
description="Effect filter as regular expression (optional, e.g., 'HDR|DV|SDR')")
filter_groups: Optional[List[str]] = Field(None,
description="List of filter rule group names to apply (optional, can be obtained from query_rule_groups tool)")
sites: Optional[List[int]] = Field(None,
description="List of site IDs to search from (optional, can be obtained from query_sites tool)")
class AddSubscribeTool(MoviePilotTool):
name: str = "add_subscribe"
description: str = "Add media subscription to create automated download rules for movies and TV shows. The system will automatically search and download new episodes or releases based on the subscription criteria. Supports advanced filtering options like quality, resolution, and effect filters using regular expressions."
args_schema: Type[BaseModel] = AddSubscribeInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据订阅参数生成友好的提示消息"""
title = kwargs.get("title", "")
year = kwargs.get("year", "")
media_type = kwargs.get("media_type", "")
season = kwargs.get("season")
message = f"正在添加订阅: {title}"
if year:
message += f" ({year})"
if media_type:
message += f" [{media_type}]"
if season:
message += f"{season}"
return message
async def run(self, title: str, year: str, media_type: str,
season: Optional[int] = None, tmdb_id: Optional[int] = None,
douban_id: Optional[str] = None,
start_episode: Optional[int] = None, total_episode: Optional[int] = None,
quality: Optional[str] = None, resolution: Optional[str] = None,
effect: Optional[str] = None, filter_groups: Optional[List[str]] = None,
sites: Optional[List[int]] = None, **kwargs) -> str:
logger.info(
f"执行工具: {self.name}, 参数: title={title}, year={year}, media_type={media_type}, "
f"season={season}, tmdb_id={tmdb_id}, douban_id={douban_id}, start_episode={start_episode}, "
f"total_episode={total_episode}, quality={quality}, resolution={resolution}, "
f"effect={effect}, filter_groups={filter_groups}, sites={sites}")
try:
subscribe_chain = SubscribeChain()
media_type_enum = MediaType.from_agent(media_type)
if not media_type_enum:
return f"错误:无效的媒体类型 '{media_type}',支持的类型:'movie', 'tv'"
# 构建额外的订阅参数
subscribe_kwargs = {}
if start_episode is not None:
subscribe_kwargs['start_episode'] = start_episode
if total_episode is not None:
subscribe_kwargs['total_episode'] = total_episode
if quality:
subscribe_kwargs['quality'] = quality
if resolution:
subscribe_kwargs['resolution'] = resolution
if effect:
subscribe_kwargs['effect'] = effect
if filter_groups:
subscribe_kwargs['filter_groups'] = filter_groups
if sites:
subscribe_kwargs['sites'] = sites
sid, message = await subscribe_chain.async_add(
mtype=media_type_enum,
title=title,
year=year,
tmdbid=tmdb_id,
doubanid=douban_id,
season=season,
username=self._user_id,
**subscribe_kwargs
)
if sid:
if message and "已存在" in message:
return f"订阅已存在:{title} ({year})。如需修改参数请先删除旧订阅。"
result_msg = f"成功添加订阅:{title} ({year})"
if subscribe_kwargs:
params = []
if start_episode is not None:
params.append(f"开始集数: {start_episode}")
if total_episode is not None:
params.append(f"总集数: {total_episode}")
if quality:
params.append(f"质量过滤: {quality}")
if resolution:
params.append(f"分辨率过滤: {resolution}")
if effect:
params.append(f"特效过滤: {effect}")
if filter_groups:
params.append(f"规则组: {', '.join(filter_groups)}")
if sites:
params.append(f"站点: {', '.join(map(str, sites))}")
if params:
result_msg += f"\n配置参数: {', '.join(params)}"
return result_msg
else:
return f"添加订阅失败:{message}"
except Exception as e:
logger.error(f"添加订阅失败: {e}", exc_info=True)
return f"添加订阅时发生错误: {str(e)}"

View File

@@ -0,0 +1,173 @@
"""让用户通过按钮进行选择的工具。"""
from typing import List, Optional, Type
from pydantic import BaseModel, Field, model_validator
from app.agent.tools.base import MoviePilotTool, ToolChain
from app.agent.interaction import (
AgentInteractionOption,
agent_interaction_manager,
)
from app.log import logger
from app.schemas import Notification, NotificationType
from app.schemas.message import ChannelCapabilityManager
from app.schemas.types import MessageChannel
class UserChoiceOptionInput(BaseModel):
"""单个按钮选项。"""
label: str = Field(..., description="Text shown on the button")
value: str = Field(
...,
description="The exact content that will be sent back to the agent after the user clicks this button",
)
@model_validator(mode="after")
def validate_option(self):
if not self.label.strip():
raise ValueError("label 不能为空")
if not self.value.strip():
raise ValueError("value 不能为空")
return self
class AskUserChoiceInput(BaseModel):
"""按钮选择工具输入。"""
explanation: str = Field(
...,
description="Clear explanation of why the agent needs the user to choose from buttons",
)
message: str = Field(
...,
description="Question or prompt shown to the user together with the buttons",
)
title: Optional[str] = Field(
None,
description="Optional short title displayed above the question",
)
options: List[UserChoiceOptionInput] = Field(
...,
description="Button options to show to the user",
)
@model_validator(mode="after")
def validate_payload(self):
if not self.message.strip():
raise ValueError("message 不能为空")
if not self.options:
raise ValueError("options 至少需要提供一个")
return self
class AskUserChoiceTool(MoviePilotTool):
name: str = "ask_user_choice"
description: str = (
"Ask the user to choose from button options on channels that support interactive buttons. "
"After the user clicks a button, the selected value will come back as the user's next message."
)
args_schema: Type[BaseModel] = AskUserChoiceInput
require_admin: bool = False
def get_tool_message(self, **kwargs) -> Optional[str]:
message = kwargs.get("message", "") or ""
if len(message) > 40:
message = message[:40] + "..."
return f"正在发送按钮选择: {message}"
@staticmethod
def _truncate_button_text(text: str, max_length: int) -> str:
if max_length <= 0 or len(text) <= max_length:
return text
if max_length <= 3:
return text[:max_length]
return text[: max_length - 3] + "..."
async def run(
self,
message: str,
options: List[UserChoiceOptionInput],
title: Optional[str] = None,
**kwargs,
) -> str:
if not self._channel or not self._source:
return "当前不在可回传消息的会话中,无法发起按钮选择"
try:
channel = MessageChannel(self._channel)
except ValueError:
return f"不支持的消息渠道: {self._channel}"
if not (
ChannelCapabilityManager.supports_buttons(channel)
and ChannelCapabilityManager.supports_callbacks(channel)
):
return f"当前渠道 {channel.value} 不支持按钮选择"
max_per_row = ChannelCapabilityManager.get_max_buttons_per_row(channel)
max_rows = ChannelCapabilityManager.get_max_button_rows(channel)
max_text_length = ChannelCapabilityManager.get_max_button_text_length(channel)
max_options = max_per_row * max_rows
if len(options) > max_options:
return f"当前渠道最多支持 {max_options} 个按钮选项"
choice_options = [
AgentInteractionOption(
label=option.label.strip(), value=option.value.strip()
)
for option in options
]
request = agent_interaction_manager.create_request(
session_id=self._session_id,
user_id=str(self._user_id),
channel=channel.value,
source=self._source,
username=self._username,
title=title,
prompt=message.strip(),
options=choice_options,
)
buttons = []
current_row = []
for index, option in enumerate(choice_options, start=1):
current_row.append(
{
"text": self._truncate_button_text(option.label, max_text_length),
"callback_data": (
f"agent_interaction:choice:{request.request_id}:{index}"
),
}
)
if len(current_row) >= max_per_row:
buttons.append(current_row)
current_row = []
if current_row:
buttons.append(current_row)
logger.info(
"执行工具: %s, channel=%s, session_id=%s, options=%s",
self.name,
channel.value,
self._session_id,
len(choice_options),
)
await ToolChain().async_post_message(
Notification(
channel=channel,
source=self._source,
mtype=NotificationType.Agent,
userid=self._user_id,
username=self._username,
title=title,
text=message.strip(),
buttons=buttons,
)
)
self._agent_context["user_reply_sent"] = True
self._agent_context["reply_mode"] = "button_choice"
return f"已发送 {len(choice_options)} 个按钮选项,等待用户选择"

View File

@@ -0,0 +1,539 @@
"""浏览器操作工具 - 让Agent能够通过Playwright控制浏览器进行网页交互"""
import asyncio
import base64
import json
from enum import Enum
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.core.config import settings
from app.log import logger
# 页面内容最大长度
MAX_CONTENT_LENGTH = 8000
# 默认超时时间(秒)
DEFAULT_TIMEOUT = 30
# 截图最大宽度
SCREENSHOT_MAX_WIDTH = 1280
# 截图最大高度
SCREENSHOT_MAX_HEIGHT = 720
class BrowserAction(str, Enum):
"""浏览器操作类型"""
GOTO = "goto"
GET_CONTENT = "get_content"
SCREENSHOT = "screenshot"
CLICK = "click"
FILL = "fill"
SELECT = "select"
EVALUATE = "evaluate"
WAIT = "wait"
class BrowseWebpageInput(BaseModel):
"""浏览器操作工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this browser action is being performed",
)
action: str = Field(
...,
description=(
"The browser action to perform. Available actions:\n"
"- 'goto': Navigate to a URL, returns page title and text summary\n"
"- 'get_content': Get current page content (text or HTML)\n"
"- 'screenshot': Take a screenshot of the current page, returns base64 image\n"
"- 'click': Click on an element specified by selector\n"
"- 'fill': Fill text into an input element specified by selector\n"
"- 'select': Select an option from a dropdown element\n"
"- 'evaluate': Execute JavaScript code on the page and return the result\n"
"- 'wait': Wait for an element to appear on the page"
),
)
url: Optional[str] = Field(
None, description="URL to navigate to (required for 'goto' action)"
)
selector: Optional[str] = Field(
None,
description="CSS selector or text selector for the target element (for 'click', 'fill', 'select', 'wait' actions). "
"Supports CSS selectors like '#id', '.class', 'tag', and Playwright text selectors like 'text=Click me'",
)
value: Optional[str] = Field(
None,
description="Value to fill into input or option value to select (for 'fill' and 'select' actions)",
)
script: Optional[str] = Field(
None,
description="JavaScript code to execute on the page (for 'evaluate' action). "
"The script should return a value that can be serialized to JSON.",
)
content_type: Optional[str] = Field(
"text",
description="Content type for 'get_content' action: 'text' for readable text, 'html' for raw HTML",
)
timeout: Optional[int] = Field(
DEFAULT_TIMEOUT, description="Timeout in seconds for the action (default: 30)"
)
cookies: Optional[str] = Field(
None,
description="Cookies to set for the browser context, format: 'name1=value1; name2=value2'",
)
user_agent: Optional[str] = Field(
None, description="Custom User-Agent string for the browser context"
)
class BrowseWebpageTool(MoviePilotTool):
name: str = "browse_webpage"
description: str = (
"Control a real browser (Playwright) to interact with web pages. "
"Supports navigating to URLs, reading page content, taking screenshots, "
"clicking elements, filling forms, selecting dropdown options, executing JavaScript, and waiting for elements. "
"Use this tool when you need to interact with dynamic web pages, "
"fill in forms, click buttons, or extract content from JavaScript-rendered pages. "
"The browser session persists across multiple calls within the same conversation - "
"first call 'goto' to open a page, then use other actions to interact with it."
)
args_schema: Type[BaseModel] = BrowseWebpageInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据操作类型生成友好的提示消息"""
action = kwargs.get("action", "")
url = kwargs.get("url", "")
selector = kwargs.get("selector", "")
action_messages = {
"goto": f"正在打开网页: {url}",
"get_content": "正在获取页面内容",
"screenshot": "正在截取页面截图",
"click": f"正在点击元素: {selector}",
"fill": f"正在填写表单: {selector}",
"select": f"正在选择选项: {selector}",
"evaluate": "正在执行 JavaScript",
"wait": f"正在等待元素: {selector}",
}
return action_messages.get(action, f"正在执行浏览器操作: {action}")
async def run(
self,
action: str,
url: Optional[str] = None,
selector: Optional[str] = None,
value: Optional[str] = None,
script: Optional[str] = None,
content_type: Optional[str] = "text",
timeout: Optional[int] = DEFAULT_TIMEOUT,
cookies: Optional[str] = None,
user_agent: Optional[str] = None,
**kwargs,
) -> str:
"""执行浏览器操作"""
logger.info(
f"执行工具: {self.name}, 动作: {action}, URL: {url}, 选择器: {selector}"
)
try:
# 验证操作类型
try:
browser_action = BrowserAction(action)
except ValueError:
valid_actions = ", ".join([a.value for a in BrowserAction])
return f"错误: 不支持的操作类型 '{action}',支持的操作: {valid_actions}"
# 参数校验
if browser_action == BrowserAction.GOTO and not url:
return "错误: 'goto' 操作需要提供 url 参数"
if (
browser_action
in (
BrowserAction.CLICK,
BrowserAction.FILL,
BrowserAction.SELECT,
BrowserAction.WAIT,
)
and not selector
):
return f"错误: '{action}' 操作需要提供 selector 参数"
if browser_action == BrowserAction.FILL and value is None:
return "错误: 'fill' 操作需要提供 value 参数"
if browser_action == BrowserAction.EVALUATE and not script:
return "错误: 'evaluate' 操作需要提供 script 参数"
# 在线程池中运行同步的 Playwright 操作
loop = asyncio.get_running_loop()
result = await loop.run_in_executor(
None,
lambda: self._execute_browser_action(
browser_action=browser_action,
url=url,
selector=selector,
value=value,
script=script,
content_type=content_type,
timeout=timeout,
cookies=cookies,
user_agent=user_agent,
),
)
return result
except Exception as e:
logger.error(f"浏览器操作失败: {e}", exc_info=True)
return f"浏览器操作失败: {str(e)}"
def _execute_browser_action(
self,
browser_action: BrowserAction,
url: Optional[str],
selector: Optional[str],
value: Optional[str],
script: Optional[str],
content_type: Optional[str],
timeout: int,
cookies: Optional[str],
user_agent: Optional[str],
) -> str:
"""在同步上下文中执行 Playwright 浏览器操作"""
from playwright.sync_api import sync_playwright
try:
with sync_playwright() as playwright:
browser = None
context = None
page = None
try:
# 启动浏览器
browser_type = settings.PLAYWRIGHT_BROWSER_TYPE or "chromium"
browser = playwright[browser_type].launch(headless=True)
# 创建上下文
context_kwargs = {}
if user_agent:
context_kwargs["user_agent"] = user_agent
# 设置视口大小
context_kwargs["viewport"] = {
"width": SCREENSHOT_MAX_WIDTH,
"height": SCREENSHOT_MAX_HEIGHT,
}
context = browser.new_context(**context_kwargs)
page = context.new_page()
page.set_default_timeout(timeout * 1000)
# 设置 cookies
if cookies:
page.set_extra_http_headers({"cookie": cookies})
# 对于非 goto 操作,如果提供了 url 先导航
if url and browser_action != BrowserAction.GOTO:
page.goto(
url, wait_until="domcontentloaded", timeout=timeout * 1000
)
page.wait_for_load_state("networkidle", timeout=timeout * 1000)
# 执行具体操作
result = self._do_action(
page,
browser_action,
url,
selector,
value,
script,
content_type,
timeout,
)
return result
finally:
if page:
page.close()
if context:
context.close()
if browser:
browser.close()
except Exception as e:
logger.error(f"Playwright 执行失败: {e}", exc_info=True)
return f"Playwright 执行失败: {str(e)}"
def _do_action(
self,
page,
browser_action: BrowserAction,
url: Optional[str],
selector: Optional[str],
value: Optional[str],
script: Optional[str],
content_type: Optional[str],
timeout: int,
) -> str:
"""执行具体的浏览器操作"""
if browser_action == BrowserAction.GOTO:
return self._action_goto(page, url, timeout)
elif browser_action == BrowserAction.GET_CONTENT:
return self._action_get_content(page, content_type)
elif browser_action == BrowserAction.SCREENSHOT:
return self._action_screenshot(page)
elif browser_action == BrowserAction.CLICK:
return self._action_click(page, selector, timeout)
elif browser_action == BrowserAction.FILL:
return self._action_fill(page, selector, value, timeout)
elif browser_action == BrowserAction.SELECT:
return self._action_select(page, selector, value, timeout)
elif browser_action == BrowserAction.EVALUATE:
return self._action_evaluate(page, script)
elif browser_action == BrowserAction.WAIT:
return self._action_wait(page, selector, timeout)
return f"未知操作: {browser_action}"
@staticmethod
def _action_goto(page, url: str, timeout: int) -> str:
"""导航到URL"""
response = page.goto(url, wait_until="domcontentloaded", timeout=timeout * 1000)
try:
page.wait_for_load_state("networkidle", timeout=min(timeout, 15) * 1000)
except Exception:
# networkidle 超时不是致命错误,页面可能已经可用
pass
status = response.status if response else "unknown"
title = page.title()
page_url = page.url
# 提取页面可读文本摘要
text_content = page.inner_text("body")
if text_content and len(text_content) > MAX_CONTENT_LENGTH:
text_content = text_content[:MAX_CONTENT_LENGTH] + "\n\n...(内容已截断)"
# 提取页面链接
links = page.evaluate("""
() => {
const links = [];
document.querySelectorAll('a[href]').forEach(a => {
const text = a.innerText.trim();
const href = a.href;
if (text && href && !href.startsWith('javascript:')) {
links.push({text: text.substring(0, 80), href: href});
}
});
return links.slice(0, 30);
}
""")
# 提取表单信息
forms = page.evaluate("""
() => {
const forms = [];
document.querySelectorAll('input, textarea, select, button').forEach(el => {
const info = {
tag: el.tagName.toLowerCase(),
type: el.type || '',
name: el.name || '',
id: el.id || '',
placeholder: el.placeholder || '',
value: el.tagName.toLowerCase() === 'select' ? '' : (el.value || '').substring(0, 50),
text: el.innerText ? el.innerText.trim().substring(0, 50) : ''
};
// 只保留有标识信息的元素
if (info.name || info.id || info.placeholder || info.text) {
forms.push(info);
}
});
return forms.slice(0, 30);
}
""")
result = {
"status": status,
"url": page_url,
"title": title,
"text_content": text_content,
}
if links:
result["links"] = links
if forms:
result["form_elements"] = forms
return json.dumps(result, ensure_ascii=False, indent=2)
@staticmethod
def _action_get_content(page, content_type: Optional[str]) -> str:
"""获取页面内容"""
title = page.title()
page_url = page.url
if content_type == "html":
content = page.content()
else:
content = page.inner_text("body")
if content and len(content) > MAX_CONTENT_LENGTH:
content = content[:MAX_CONTENT_LENGTH] + "\n\n...(内容已截断)"
result = {
"url": page_url,
"title": title,
"content_type": content_type,
"content": content,
}
return json.dumps(result, ensure_ascii=False, indent=2)
@staticmethod
def _action_screenshot(page) -> str:
"""截取页面截图"""
screenshot_bytes = page.screenshot(
full_page=False,
type="jpeg",
quality=60,
)
screenshot_b64 = base64.b64encode(screenshot_bytes).decode("utf-8")
# 限制截图大小base64编码后大约增大33%
max_b64_size = 200 * 1024 # ~150KB 原始图片
if len(screenshot_b64) > max_b64_size:
# 降低质量重新截图
screenshot_bytes = page.screenshot(
full_page=False,
type="jpeg",
quality=30,
)
screenshot_b64 = base64.b64encode(screenshot_bytes).decode("utf-8")
title = page.title()
page_url = page.url
result = {
"url": page_url,
"title": title,
"screenshot_base64": screenshot_b64,
"format": "jpeg",
"note": "截图已以 base64 编码返回",
}
return json.dumps(result, ensure_ascii=False, indent=2)
@staticmethod
def _action_click(page, selector: str, timeout: int) -> str:
"""点击元素"""
page.click(selector, timeout=timeout * 1000)
# 等待可能的页面变化
try:
page.wait_for_load_state("networkidle", timeout=5000)
except Exception:
pass
title = page.title()
page_url = page.url
return json.dumps(
{
"success": True,
"message": f"成功点击元素: {selector}",
"current_url": page_url,
"current_title": title,
},
ensure_ascii=False,
indent=2,
)
@staticmethod
def _action_fill(page, selector: str, value: str, timeout: int) -> str:
"""填写表单"""
page.fill(selector, value, timeout=timeout * 1000)
return json.dumps(
{
"success": True,
"message": f"成功填写元素 '{selector}' 的值为 '{value}'",
},
ensure_ascii=False,
indent=2,
)
@staticmethod
def _action_select(page, selector: str, value: Optional[str], timeout: int) -> str:
"""选择下拉选项"""
if value:
page.select_option(selector, value=value, timeout=timeout * 1000)
else:
return "错误: 'select' 操作需要提供 value 参数"
return json.dumps(
{
"success": True,
"message": f"成功选择元素 '{selector}' 的选项 '{value}'",
},
ensure_ascii=False,
indent=2,
)
@staticmethod
def _action_evaluate(page, script: str) -> str:
"""执行 JavaScript"""
result = page.evaluate(script)
# 格式化结果
if result is None:
formatted = "null"
elif isinstance(result, (dict, list)):
formatted = json.dumps(result, ensure_ascii=False, indent=2)
else:
formatted = str(result)
# 限制结果长度
if len(formatted) > MAX_CONTENT_LENGTH:
formatted = formatted[:MAX_CONTENT_LENGTH] + "\n\n...(结果已截断)"
return json.dumps(
{
"success": True,
"result": formatted,
},
ensure_ascii=False,
indent=2,
)
@staticmethod
def _action_wait(page, selector: str, timeout: int) -> str:
"""等待元素出现"""
element = page.wait_for_selector(selector, timeout=timeout * 1000)
if element:
visible = element.is_visible()
text = element.inner_text()
if text and len(text) > 200:
text = text[:200] + "..."
return json.dumps(
{
"success": True,
"message": f"元素 '{selector}' 已出现",
"visible": visible,
"text": text,
},
ensure_ascii=False,
indent=2,
)
else:
return json.dumps(
{
"success": False,
"message": f"等待元素 '{selector}' 超时",
},
ensure_ascii=False,
indent=2,
)

View File

@@ -0,0 +1,83 @@
"""删除下载任务工具"""
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.download import DownloadChain
from app.log import logger
class DeleteDownloadInput(BaseModel):
"""删除下载任务工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
hash: str = Field(
..., description="Task hash (can be obtained from query_download_tasks tool)"
)
downloader: Optional[str] = Field(
None,
description="Name of specific downloader (optional, if not provided will search all downloaders)",
)
delete_files: Optional[bool] = Field(
False,
description="Whether to delete downloaded files along with the task (default: False, only removes the task from downloader)",
)
class DeleteDownloadTool(MoviePilotTool):
name: str = "delete_download"
description: str = "Delete a download task from the downloader by task hash only. Optionally specify the downloader name and whether to delete downloaded files."
args_schema: Type[BaseModel] = DeleteDownloadInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据删除参数生成友好的提示消息"""
hash_value = kwargs.get("hash", "")
downloader = kwargs.get("downloader")
delete_files = kwargs.get("delete_files", False)
message = f"正在删除下载任务: {hash_value}"
if downloader:
message += f" [下载器: {downloader}]"
if delete_files:
message += " (包含文件)"
return message
async def run(
self,
hash: str,
downloader: Optional[str] = None,
delete_files: Optional[bool] = False,
**kwargs,
) -> str:
logger.info(
f"执行工具: {self.name}, 参数: hash={hash}, downloader={downloader}, delete_files={delete_files}"
)
try:
download_chain = DownloadChain()
# 仅支持通过hash删除任务
if len(hash) != 40 or not all(c in "0123456789abcdefABCDEF" for c in hash):
return "参数错误hash 格式无效,请先使用 query_download_tasks 工具获取正确的 hash。"
# 删除下载任务
# remove_torrents 支持 delete_file 参数,可以控制是否删除文件
result = download_chain.remove_torrents(
hashs=[hash], downloader=downloader, delete_file=delete_files
)
if result:
files_info = "(包含文件)" if delete_files else "(不包含文件)"
return f"成功删除下载任务:{hash} {files_info}"
else:
return f"删除下载任务失败:{hash},请检查任务是否存在或下载器是否可用"
except Exception as e:
logger.error(f"删除下载任务失败: {e}", exc_info=True)
return f"删除下载任务时发生错误: {str(e)}"

View File

@@ -0,0 +1,44 @@
"""删除下载历史记录工具"""
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.db import AsyncSessionFactory
from app.db.models.downloadhistory import DownloadHistory
from app.log import logger
class DeleteDownloadHistoryInput(BaseModel):
"""删除下载历史记录工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
history_id: int = Field(
..., description="The ID of the download history record to delete"
)
class DeleteDownloadHistoryTool(MoviePilotTool):
name: str = "delete_download_history"
description: str = "Delete a download history record by ID. This only removes the record from the database, does not delete any actual files."
args_schema: Type[BaseModel] = DeleteDownloadHistoryInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
history_id = kwargs.get("history_id")
return f"正在删除下载历史记录 ID: {history_id}"
async def run(self, history_id: int, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: history_id={history_id}")
try:
async with AsyncSessionFactory() as db:
await DownloadHistory.async_delete(db, history_id)
return f"下载历史记录 ID: {history_id} 已成功删除"
except Exception as e:
logger.error(f"删除下载历史记录失败: {e}", exc_info=True)
return f"删除下载历史记录时发生错误: {str(e)}"

View File

@@ -0,0 +1,69 @@
"""删除订阅工具"""
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.core.event import eventmanager
from app.db.subscribe_oper import SubscribeOper
from app.helper.subscribe import SubscribeHelper
from app.log import logger
from app.schemas.types import EventType
class DeleteSubscribeInput(BaseModel):
"""删除订阅工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
subscribe_id: int = Field(
...,
description="The ID of the subscription to delete (can be obtained from query_subscribes tool)",
)
class DeleteSubscribeTool(MoviePilotTool):
name: str = "delete_subscribe"
description: str = "Delete a media subscription by its ID. This will remove the subscription and stop automatic downloads for that media."
args_schema: Type[BaseModel] = DeleteSubscribeInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据删除参数生成友好的提示消息"""
subscribe_id = kwargs.get("subscribe_id")
return f"正在删除订阅 (ID: {subscribe_id})"
async def run(self, subscribe_id: int, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: subscribe_id={subscribe_id}")
try:
subscribe_oper = SubscribeOper()
# 获取订阅信息
subscribe = await subscribe_oper.async_get(subscribe_id)
if not subscribe:
return f"订阅 ID {subscribe_id} 不存在"
# 在删除之前获取订阅信息(用于事件)
subscribe_info = subscribe.to_dict()
# 删除订阅
subscribe_oper.delete(subscribe_id)
# 发送事件
await eventmanager.async_send_event(
EventType.SubscribeDeleted,
{"subscribe_id": subscribe_id, "subscribe_info": subscribe_info},
)
# 统计订阅
SubscribeHelper().sub_done_async(
{"tmdbid": subscribe.tmdbid, "doubanid": subscribe.doubanid}
)
return f"成功删除订阅:{subscribe.name} ({subscribe.year})"
except Exception as e:
logger.error(f"删除订阅失败: {e}", exc_info=True)
return f"删除订阅时发生错误: {str(e)}"

View File

@@ -0,0 +1,57 @@
"""删除整理历史记录工具"""
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.db.transferhistory_oper import TransferHistoryOper
from app.log import logger
class DeleteTransferHistoryInput(BaseModel):
"""删除整理历史记录工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
history_id: int = Field(
..., description="The ID of the transfer history record to delete"
)
class DeleteTransferHistoryTool(MoviePilotTool):
name: str = "delete_transfer_history"
description: str = "Delete a specific transfer history record by its ID. This is useful when you need to remove a failed transfer record before retrying the transfer, as the system skips files that already have transfer history."
args_schema: Type[BaseModel] = DeleteTransferHistoryInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据参数生成友好的提示消息"""
history_id = kwargs.get("history_id")
return f"正在删除整理历史记录: ID={history_id}"
async def run(self, history_id: int, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: history_id={history_id}")
try:
transferhis = TransferHistoryOper()
# 查询历史记录是否存在
history = transferhis.get(history_id)
if not history:
return f"错误整理历史记录不存在ID={history_id}"
# 保存信息用于返回
title = history.title or "未知"
src = history.src or "未知"
status = "成功" if history.status else "失败"
# 删除记录
transferhis.delete(history_id)
return f"已删除整理历史记录ID={history_id},标题={title},源路径={src},状态={status}"
except Exception as e:
logger.error(f"删除整理历史记录失败: {e}", exc_info=True)
return f"删除整理历史记录时发生错误: {str(e)}"

View File

@@ -0,0 +1,74 @@
"""文件编辑工具"""
from pathlib import Path
from typing import Optional, Type
from anyio import Path as AsyncPath
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.log import logger
class EditFileInput(BaseModel):
"""Input parameters for edit file tool"""
file_path: str = Field(..., description="The absolute path of the file to edit")
old_text: str = Field(..., description="The exact old text to be replaced")
new_text: str = Field(..., description="The new text to replace with")
class EditFileTool(MoviePilotTool):
name: str = "edit_file"
description: str = "Edit a file by replacing specific old text with new text. Useful for modifying configuration files, code, or scripts."
args_schema: Type[BaseModel] = EditFileInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据参数生成友好的提示消息"""
file_path = kwargs.get("file_path", "")
file_name = Path(file_path).name if file_path else "未知文件"
return f"正在编辑文件: {file_name}"
async def run(self, file_path: str, old_text: str, new_text: str, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: file_path={file_path}")
try:
path = AsyncPath(file_path)
# 校验逻辑:如果要替换特定文本,文件必须存在且包含该文本
if not await path.exists():
# 如果 old_text 为空,可能用户想直接创建文件,但通常 edit_file 需要匹配旧内容
if old_text:
return f"错误:文件 {file_path} 不存在,无法进行内容替换。"
if await path.exists() and not await path.is_file():
return f"错误:{file_path} 不是一个文件"
if await path.exists():
content = await path.read_text(encoding="utf-8")
if old_text not in content:
logger.warning(f"编辑文件 {file_path} 失败:未找到指定的旧文本块")
return f"错误:在文件 {file_path} 中未找到指定的旧文本。请确保包含所有的空格、缩进 and 换行符。"
occurrences = content.count(old_text)
new_content = content.replace(old_text, new_text)
else:
# 文件不存在且 old_text 为空的情形(初始化新文件)
new_content = new_text
occurrences = 1
# 自动创建父目录
await path.parent.mkdir(parents=True, exist_ok=True)
# 写入文件
await path.write_text(new_content, encoding="utf-8")
logger.info(f"成功编辑文件 {file_path},替换了 {occurrences} 处内容")
return f"成功编辑文件 {file_path} (替换了 {occurrences} 处匹配内容)"
except PermissionError:
return f"错误:没有访问/修改 {file_path} 的权限"
except UnicodeDecodeError:
return f"错误:{file_path} 不是文本文件,无法编辑"
except Exception as e:
logger.error(f"编辑文件 {file_path} 时发生错误: {str(e)}", exc_info=True)
return f"操作失败: {str(e)}"

View File

@@ -0,0 +1,96 @@
"""执行Shell命令工具"""
import asyncio
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.log import logger
class ExecuteCommandInput(BaseModel):
"""执行Shell命令工具的输入参数模型"""
explanation: str = Field(
..., description="Clear explanation of why this command is being executed"
)
command: str = Field(..., description="The shell command to execute")
timeout: Optional[int] = Field(
60, description="Max execution time in seconds (default: 60)"
)
class ExecuteCommandTool(MoviePilotTool):
name: str = "execute_command"
description: str = "Safely execute shell commands on the server. Useful for system maintenance, checking status, or running custom scripts. Includes timeout and output limits."
args_schema: Type[BaseModel] = ExecuteCommandInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据命令生成友好的提示消息"""
command = kwargs.get("command", "")
return f"正在执行系统命令: {command}"
async def run(self, command: str, timeout: Optional[int] = 60, **kwargs) -> str:
logger.info(
f"执行工具: {self.name}, 参数: command={command}, timeout={timeout}"
)
# 简单安全过滤
forbidden_keywords = [
"rm -rf /",
":(){ :|:& };:",
"dd if=/dev/zero",
"mkfs",
"reboot",
"shutdown",
]
for keyword in forbidden_keywords:
if keyword in command:
return f"错误:命令包含禁止使用的关键字 '{keyword}'"
try:
# 执行命令
process = await asyncio.create_subprocess_shell(
command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
)
try:
# 等待完成,带超时
stdout, stderr = await asyncio.wait_for(
process.communicate(), timeout=timeout
)
# 处理输出
stdout_str = stdout.decode("utf-8", errors="replace").strip()
stderr_str = stderr.decode("utf-8", errors="replace").strip()
exit_code = process.returncode
result = f"命令执行完成 (退出码: {exit_code})"
if stdout_str:
result += f"\n\n标准输出:\n{stdout_str}"
if stderr_str:
result += f"\n\n错误输出:\n{stderr_str}"
# 如果没有输出
if not stdout_str and not stderr_str:
result += "\n\n(无输出内容)"
# 限制输出长度,防止上下文过长
if len(result) > 3000:
result = result[:3000] + "\n\n...(输出内容过长,已截断)"
return result
except asyncio.TimeoutError:
# 超时处理
try:
process.kill()
except ProcessLookupError:
pass
return f"命令执行超时 (限制: {timeout}秒)"
except Exception as e:
logger.error(f"执行命令失败: {e}", exc_info=True)
return f"执行命令时发生错误: {str(e)}"

View File

@@ -0,0 +1,229 @@
"""获取推荐工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.recommend import RecommendChain
from app.log import logger
from app.schemas.types import MediaType, media_type_to_agent
class GetRecommendationsInput(BaseModel):
"""获取推荐工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
source: Optional[str] = Field(
"tmdb_trending",
description="Recommendation source: "
"'tmdb_trending' for TMDB trending content, "
"'tmdb_movies' for TMDB popular movies, "
"'tmdb_tvs' for TMDB popular TV shows, "
"'douban_hot' for Douban popular content, "
"'douban_movie_hot' for Douban hot movies, "
"'douban_tv_hot' for Douban hot TV shows, "
"'douban_movie_showing' for Douban movies currently showing, "
"'douban_movies' for Douban latest movies, "
"'douban_tvs' for Douban latest TV shows, "
"'douban_movie_top250' for Douban movie TOP250, "
"'douban_tv_weekly_chinese' for Douban Chinese TV weekly chart, "
"'douban_tv_weekly_global' for Douban global TV weekly chart, "
"'douban_tv_animation' for Douban popular animation, "
"'bangumi_calendar' for Bangumi anime calendar",
)
media_type: Optional[str] = Field(
"all", description="Allowed values: movie, tv, all"
)
page: Optional[int] = Field(
1, description="Page number for pagination (default: 1, 20 items per page)"
)
class GetRecommendationsTool(MoviePilotTool):
name: str = "get_recommendations"
description: str = "Get trending and popular media recommendations from various sources. Returns curated lists of popular movies, TV shows, and anime based on different criteria like trending, ratings, or calendar schedules. Supports pagination with 20 items per page."
args_schema: Type[BaseModel] = GetRecommendationsInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据推荐参数生成友好的提示消息"""
source = kwargs.get("source", "tmdb_trending")
media_type = kwargs.get("media_type", "all")
page = kwargs.get("page", 1)
source_map = {
"tmdb_trending": "TMDB流行趋势",
"tmdb_movies": "TMDB热门电影",
"tmdb_tvs": "TMDB热门电视剧",
"douban_hot": "豆瓣热门",
"douban_movie_hot": "豆瓣热门电影",
"douban_tv_hot": "豆瓣热门电视剧",
"douban_movie_showing": "豆瓣正在热映",
"douban_movies": "豆瓣最新电影",
"douban_tvs": "豆瓣最新电视剧",
"douban_movie_top250": "豆瓣电影TOP250",
"douban_tv_weekly_chinese": "豆瓣国产剧集榜",
"douban_tv_weekly_global": "豆瓣全球剧集榜",
"douban_tv_animation": "豆瓣热门动漫",
"bangumi_calendar": "番组计划",
}
source_desc = source_map.get(source, source)
message = f"正在获取推荐: {source_desc}"
if media_type != "all":
message += f" [{media_type}]"
message += f" (第{page}页)"
return message
async def run(
self,
source: Optional[str] = "tmdb_trending",
media_type: Optional[str] = "all",
page: Optional[int] = 1,
**kwargs,
) -> str:
page = max(1, page or 1)
page_size = 20
logger.info(
f"执行工具: {self.name}, 参数: source={source}, media_type={media_type}, page={page}"
)
try:
if media_type != "all":
media_type_enum = MediaType.from_agent(media_type)
if not media_type_enum:
return f"错误:无效的媒体类型 '{media_type}',支持的类型:'movie', 'tv', 'all'"
media_type = media_type_enum.to_agent() # 归一化为 "movie"/"tv"
recommend_chain = RecommendChain()
results = []
if source == "tmdb_trending":
results = await recommend_chain.async_tmdb_trending(page=page)
elif source == "tmdb_movies":
results = await recommend_chain.async_tmdb_movies(page=page)
elif source == "tmdb_tvs":
results = await recommend_chain.async_tmdb_tvs(page=page)
elif source == "douban_hot":
if media_type == "movie":
results = await recommend_chain.async_douban_movie_hot(
page=page, count=page_size
)
elif media_type == "tv":
results = await recommend_chain.async_douban_tv_hot(
page=page, count=page_size
)
else: # all
results.extend(
await recommend_chain.async_douban_movie_hot(
page=page, count=page_size
)
)
results.extend(
await recommend_chain.async_douban_tv_hot(
page=page, count=page_size
)
)
elif source == "douban_movie_hot":
results = await recommend_chain.async_douban_movie_hot(
page=page, count=page_size
)
elif source == "douban_tv_hot":
results = await recommend_chain.async_douban_tv_hot(
page=page, count=page_size
)
elif source == "douban_movie_showing":
results = await recommend_chain.async_douban_movie_showing(
page=page, count=page_size
)
elif source == "douban_movies":
results = await recommend_chain.async_douban_movies(
page=page, count=page_size
)
elif source == "douban_tvs":
results = await recommend_chain.async_douban_tvs(
page=page, count=page_size
)
elif source == "douban_movie_top250":
results = await recommend_chain.async_douban_movie_top250(
page=page, count=page_size
)
elif source == "douban_tv_weekly_chinese":
results = await recommend_chain.async_douban_tv_weekly_chinese(
page=page, count=page_size
)
elif source == "douban_tv_weekly_global":
results = await recommend_chain.async_douban_tv_weekly_global(
page=page, count=page_size
)
elif source == "douban_tv_animation":
results = await recommend_chain.async_douban_tv_animation(
page=page, count=page_size
)
elif source == "bangumi_calendar":
results = await recommend_chain.async_bangumi_calendar(
page=page, count=page_size
)
else:
# 不支持的推荐来源
supported_sources = [
"tmdb_trending",
"tmdb_movies",
"tmdb_tvs",
"douban_hot",
"douban_movie_hot",
"douban_tv_hot",
"douban_movie_showing",
"douban_movies",
"douban_tvs",
"douban_movie_top250",
"douban_tv_weekly_chinese",
"douban_tv_weekly_global",
"douban_tv_animation",
"bangumi_calendar",
]
return f"不支持的推荐来源: {source}。支持的来源包括: {', '.join(supported_sources)}"
if results:
# 对于TMDB来源API自身按页返回取前page_size条
total_count = len(results)
page_results = results[:page_size]
# 精简字段,只保留关键信息
simplified_results = []
for r in page_results:
# r 应该是字典格式to_dict的结果但为了安全起见进行检查
if not isinstance(r, dict):
logger.warning(f"推荐结果格式异常,跳过: {type(r)}")
continue
simplified = {
"title": r.get("title"),
"en_title": r.get("en_title"),
"year": r.get("year"),
"type": media_type_to_agent(r.get("type")),
"season": r.get("season"),
"tmdb_id": r.get("tmdb_id"),
"imdb_id": r.get("imdb_id"),
"douban_id": r.get("douban_id"),
"vote_average": r.get("vote_average"),
"poster_path": r.get("poster_path"),
"detail_link": r.get("detail_link"),
}
simplified_results.append(simplified)
result_json = json.dumps(
simplified_results, ensure_ascii=False, indent=2
)
has_more = total_count > page_size
payload_msg = f"{page} 页,当前页 {len(simplified_results)} 条结果。"
if has_more:
payload_msg += (
f" 可能有更多数据,可使用 page={page + 1} 获取下一页。"
)
return f"{payload_msg}\n\n{result_json}"
return "未找到推荐内容。"
except Exception as e:
logger.error(f"获取推荐失败: {e}", exc_info=True)
return f"获取推荐时发生错误: {str(e)}"

View File

@@ -0,0 +1,155 @@
"""获取搜索结果工具"""
import json
import re
from typing import List, Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.search import SearchChain
from app.log import logger
from ._torrent_search_utils import (
TORRENT_RESULT_LIMIT,
build_filter_options,
filter_contexts,
simplify_search_result,
)
class GetSearchResultsInput(BaseModel):
"""获取搜索结果工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
site: Optional[List[str]] = Field(None, description="Site name filters")
season: Optional[List[str]] = Field(None, description="Season or episode filters")
free_state: Optional[List[str]] = Field(None, description="Promotion state filters")
video_code: Optional[List[str]] = Field(None, description="Video codec filters")
edition: Optional[List[str]] = Field(None, description="Edition filters")
resolution: Optional[List[str]] = Field(None, description="Resolution filters")
release_group: Optional[List[str]] = Field(
None, description="Release group filters"
)
title_pattern: Optional[str] = Field(
None,
description="Regular expression pattern to filter torrent titles (e.g., '4K|2160p|UHD', '1080p.*BluRay')",
)
show_filter_options: Optional[bool] = Field(
False,
description="Whether to return only optional filter options for re-checking available conditions",
)
page: Optional[int] = Field(
1,
description="Page number for pagination (default: 1, each page returns up to 50 results)",
)
class GetSearchResultsTool(MoviePilotTool):
name: str = "get_search_results"
description: str = "Get cached torrent search results from search_torrents with optional filters. Supports pagination with up to 50 results per page."
args_schema: Type[BaseModel] = GetSearchResultsInput
def get_tool_message(self, **kwargs) -> Optional[str]:
return "正在获取搜索结果"
async def run(
self,
site: Optional[List[str]] = None,
season: Optional[List[str]] = None,
free_state: Optional[List[str]] = None,
video_code: Optional[List[str]] = None,
edition: Optional[List[str]] = None,
resolution: Optional[List[str]] = None,
release_group: Optional[List[str]] = None,
title_pattern: Optional[str] = None,
show_filter_options: bool = False,
page: Optional[int] = 1,
**kwargs,
) -> str:
page = max(1, page or 1)
logger.info(
f"执行工具: {self.name}, 参数: site={site}, season={season}, free_state={free_state}, video_code={video_code}, edition={edition}, resolution={resolution}, release_group={release_group}, title_pattern={title_pattern}, show_filter_options={show_filter_options}, page={page}"
)
try:
items = await SearchChain().async_last_search_results() or []
if not items:
return "没有可用的搜索结果,请先使用 search_torrents 搜索"
if show_filter_options:
payload = {
"total_count": len(items),
"filter_options": build_filter_options(items),
}
return json.dumps(payload, ensure_ascii=False, indent=2)
regex_pattern = None
if title_pattern:
try:
regex_pattern = re.compile(title_pattern, re.IGNORECASE)
except re.error as e:
logger.warning(f"正则表达式编译失败: {title_pattern}, 错误: {e}")
return f"正则表达式格式错误: {str(e)}"
filtered_items = filter_contexts(
items=items,
site=site,
season=season,
free_state=free_state,
video_code=video_code,
edition=edition,
resolution=resolution,
release_group=release_group,
)
if regex_pattern:
filtered_items = [
item
for item in filtered_items
if item.torrent_info
and item.torrent_info.title
and regex_pattern.search(item.torrent_info.title)
]
if not filtered_items:
return "没有符合筛选条件的搜索结果,请调整筛选条件"
total_count = len(filtered_items)
filtered_ids = {id(item) for item in filtered_items}
matched_indices = [
index
for index, item in enumerate(items, start=1)
if id(item) in filtered_ids
]
# 分页
page_size = TORRENT_RESULT_LIMIT
start = (page - 1) * page_size
end = start + page_size
page_items = filtered_items[start:end]
page_indices = matched_indices[start:end]
if not page_items:
return f"{page} 页没有数据,共 {total_count} 条结果,共 {(total_count + page_size - 1) // page_size} 页。"
results = [
simplify_search_result(item, index)
for item, index in zip(page_items, page_indices)
]
total_pages = (total_count + page_size - 1) // page_size
payload = {
"total_count": total_count,
"page": page,
"total_pages": total_pages,
"results": results,
}
if page < total_pages:
payload["message"] = (
f"搜索结果共 {total_count} 条,当前第 {page}/{total_pages} 页,可使用 page={page + 1} 获取下一页。"
)
return json.dumps(payload, ensure_ascii=False, indent=2)
except Exception as e:
error_message = f"获取搜索结果失败: {str(e)}"
logger.error(f"获取搜索结果失败: {e}", exc_info=True)
return error_message

View File

@@ -0,0 +1,130 @@
"""查询文件系统目录内容工具"""
import json
from datetime import datetime
from pathlib import Path
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.storage import StorageChain
from app.log import logger
from app.schemas.file import FileItem
from app.utils.string import StringUtils
class ListDirectoryInput(BaseModel):
"""查询文件系统目录内容工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
path: str = Field(..., description="Directory path to list contents (e.g., '/home/user/downloads' or 'C:/Downloads')")
storage: Optional[str] = Field("local", description="Storage type (default: 'local' for local file system, can be 'smb', 'alist', etc.)")
sort_by: Optional[str] = Field("name", description="Sort order: 'name' for alphabetical sorting, 'time' for modification time sorting (default: 'name')")
class ListDirectoryTool(MoviePilotTool):
name: str = "list_directory"
description: str = "List actual files and folders in a file system directory (NOT configuration). Shows files and subdirectories with their names, types, sizes, and modification times. Returns up to 20 items and the total count if there are more items. Use 'query_directory_settings' to query directory configuration settings."
args_schema: Type[BaseModel] = ListDirectoryInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据目录参数生成友好的提示消息"""
path = kwargs.get("path", "")
storage = kwargs.get("storage", "local")
message = f"正在查询目录: {path}"
if storage != "local":
message += f" [存储: {storage}]"
return message
async def run(self, path: str, storage: Optional[str] = "local",
sort_by: Optional[str] = "name", **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: path={path}, storage={storage}, sort_by={sort_by}")
try:
# 规范化路径
if not path:
return "错误:路径不能为空"
# 确保路径格式正确
if storage == "local":
# 本地路径处理
if not path.startswith("/") and not (len(path) > 1 and path[1] == ":"):
# 相对路径,尝试转换为绝对路径
path = str(Path(path).resolve())
else:
# 远程存储路径,确保以/开头
if not path.startswith("/"):
path = "/" + path
# 创建FileItem
fileitem = FileItem(
storage=storage or "local",
path=path,
type="dir"
)
# 查询目录内容
storage_chain = StorageChain()
file_list = storage_chain.list_files(fileitem, recursion=False)
if file_list is None:
return f"无法访问目录:{path},请检查路径是否正确或存储是否可用"
if not file_list:
return f"目录 {path} 为空"
# 排序
if sort_by == "time":
file_list.sort(key=lambda x: x.modify_time or 0, reverse=True)
else:
# 默认按名称排序(目录优先,然后按名称)
file_list.sort(key=lambda x: (
0 if x.type == "dir" else 1,
StringUtils.natural_sort_key(x.name or "")
))
# 限制返回数量
total_count = len(file_list)
limited_list = file_list[:20]
# 转换为字典格式
simplified_items = []
for item in limited_list:
# 格式化文件大小
size_str = None
if item.size:
size_str = StringUtils.str_filesize(item.size)
# 格式化修改时间
modify_time_str = None
if item.modify_time:
try:
modify_time_str = datetime.fromtimestamp(item.modify_time).strftime("%Y-%m-%d %H:%M:%S")
except (ValueError, OSError):
modify_time_str = str(item.modify_time)
simplified = {
"name": item.name,
"type": item.type,
"path": item.path,
"size": size_str,
"modify_time": modify_time_str
}
# 如果是文件,添加扩展名
if item.type == "file" and item.extension:
simplified["extension"] = item.extension
simplified_items.append(simplified)
result_json = json.dumps(simplified_items, ensure_ascii=False, indent=2)
# 如果结果被裁剪,添加提示信息
if total_count > 100:
return f"注意:目录中共有 {total_count} 个项目,为节省上下文空间,仅显示前 100 个项目。\n\n{result_json}"
else:
return result_json
except Exception as e:
logger.error(f"查询目录内容失败: {e}", exc_info=True)
return f"查询目录内容时发生错误: {str(e)}"

View File

@@ -0,0 +1,79 @@
"""查询所有可用斜杠命令工具(系统命令 + 插件命令)"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.log import logger
class ListSlashCommandsInput(BaseModel):
"""查询所有可用斜杠命令工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
class ListSlashCommandsTool(MoviePilotTool):
name: str = "list_slash_commands"
description: str = (
"List all available slash commands in the system, including system preset commands "
"(e.g. /cookiecloud, /sites, /subscribes, /downloading, /transfer, /restart, etc.) "
"and plugin-registered commands. "
"Use this tool to discover what slash commands are available before executing them with run_slash_command. "
"This is especially useful when the user describes an action in natural language and you need to "
"find the matching command to fulfill their request."
)
args_schema: Type[BaseModel] = ListSlashCommandsInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""生成友好的提示消息"""
return "正在查询所有可用命令"
async def run(self, **kwargs) -> str:
logger.info(f"执行工具: {self.name}")
try:
from app.command import Command
command_obj = Command()
all_commands = command_obj.get_commands()
if not all_commands:
return "当前没有可用的命令"
commands_list = []
for cmd, info in all_commands.items():
cmd_info = {
"command": cmd,
"description": info.get("description", ""),
}
if info.get("category"):
cmd_info["category"] = info["category"]
# 标识命令类型
if info.get("type") == "scheduler":
cmd_info["type"] = "scheduler"
elif info.get("pid"):
cmd_info["type"] = "plugin"
cmd_info["plugin_id"] = info["pid"]
else:
cmd_info["type"] = "system"
commands_list.append(cmd_info)
result = {
"total": len(commands_list),
"commands": commands_list,
}
return json.dumps(result, ensure_ascii=False, indent=2)
except Exception as e:
logger.error(f"查询可用命令失败: {e}", exc_info=True)
return json.dumps(
{"success": False, "message": f"查询可用命令时发生错误: {str(e)}"},
ensure_ascii=False,
)

View File

@@ -0,0 +1,124 @@
"""修改下载任务工具"""
from typing import Optional, Type, List
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.download import DownloadChain
from app.log import logger
class ModifyDownloadInput(BaseModel):
"""修改下载任务工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
hash: str = Field(
..., description="Task hash (can be obtained from query_download_tasks tool)"
)
action: Optional[str] = Field(
None,
description="Action to perform on the task: 'start' to resume downloading, 'stop' to pause downloading. "
"If not provided, no start/stop action will be performed.",
)
tags: Optional[List[str]] = Field(
None,
description="List of tags to set on the download task. If provided, these tags will be added to the task. "
"Example: ['movie', 'hd']",
)
downloader: Optional[str] = Field(
None,
description="Name of specific downloader (optional, if not provided will search all downloaders)",
)
class ModifyDownloadTool(MoviePilotTool):
"""修改下载任务工具"""
name: str = "modify_download"
description: str = (
"Modify a download task in the downloader by task hash. "
"Supports: 1) Setting tags on a download task, "
"2) Starting (resuming) a paused download task, "
"3) Stopping (pausing) a downloading task. "
"Multiple operations can be performed in a single call."
)
args_schema: Type[BaseModel] = ModifyDownloadInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
hash_value = kwargs.get("hash", "")
action = kwargs.get("action")
tags = kwargs.get("tags")
downloader = kwargs.get("downloader")
parts = [f"正在修改下载任务: {hash_value}"]
if action == "start":
parts.append("操作: 开始下载")
elif action == "stop":
parts.append("操作: 暂停下载")
if tags:
parts.append(f"标签: {', '.join(tags)}")
if downloader:
parts.append(f"下载器: {downloader}")
return " | ".join(parts)
async def run(
self,
hash: str,
action: Optional[str] = None,
tags: Optional[List[str]] = None,
downloader: Optional[str] = None,
**kwargs,
) -> str:
logger.info(
f"执行工具: {self.name}, 参数: hash={hash}, action={action}, tags={tags}, downloader={downloader}"
)
try:
# 校验 hash 格式
if len(hash) != 40 or not all(c in "0123456789abcdefABCDEF" for c in hash):
return "参数错误hash 格式无效,请先使用 query_download_tasks 工具获取正确的 hash。"
# 校验参数:至少需要一个操作
if not action and not tags:
return "参数错误:至少需要指定 actionstart/stop或 tags 中的一个。"
# 校验 action 参数
if action and action not in ("start", "stop"):
return f"参数错误action 只支持 'start'(开始下载)或 'stop'(暂停下载),收到: '{action}'"
download_chain = DownloadChain()
results = []
# 设置标签
if tags:
tag_result = download_chain.set_torrents_tag(
hashs=[hash], tags=tags, downloader=downloader
)
if tag_result:
results.append(f"成功设置标签:{', '.join(tags)}")
else:
results.append(f"设置标签失败,请检查任务是否存在或下载器是否可用")
# 执行开始/暂停操作
if action:
action_result = download_chain.set_downloading(
hash_str=hash, oper=action, name=downloader
)
action_desc = "开始" if action == "start" else "暂停"
if action_result:
results.append(f"成功{action_desc}下载任务")
else:
results.append(
f"{action_desc}下载任务失败,请检查任务是否存在或下载器是否可用"
)
return f"下载任务 {hash}" + "".join(results)
except Exception as e:
logger.error(f"修改下载任务失败: {e}", exc_info=True)
return f"修改下载任务时发生错误: {str(e)}"

View File

@@ -0,0 +1,66 @@
"""查询自定义识别词工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.db.systemconfig_oper import SystemConfigOper
from app.log import logger
from app.schemas.types import SystemConfigKey
class QueryCustomIdentifiersInput(BaseModel):
"""查询自定义识别词工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
class QueryCustomIdentifiersTool(MoviePilotTool):
name: str = "query_custom_identifiers"
description: str = (
"Query all currently configured custom identifiers (自定义识别词). "
"Returns the list of identifier rules used for preprocessing torrent/file names before media recognition. "
"Use this tool to check existing rules before adding new ones to avoid duplicates."
)
args_schema: Type[BaseModel] = QueryCustomIdentifiersInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""生成友好的提示消息"""
return "正在查询自定义识别词"
async def run(self, **kwargs) -> str:
logger.info(f"执行工具: {self.name}")
try:
system_config_oper = SystemConfigOper()
identifiers = system_config_oper.get(SystemConfigKey.CustomIdentifiers)
if identifiers:
return json.dumps(
{
"success": True,
"count": len(identifiers),
"identifiers": identifiers,
},
ensure_ascii=False,
indent=2,
)
return json.dumps(
{
"success": True,
"count": 0,
"identifiers": [],
"message": "当前没有配置自定义识别词",
},
ensure_ascii=False,
indent=2,
)
except Exception as e:
logger.error(f"查询自定义识别词失败: {e}")
return json.dumps(
{"success": False, "message": f"查询自定义识别词时发生错误: {str(e)}"},
ensure_ascii=False,
)

View File

@@ -0,0 +1,134 @@
"""查询系统目录设置工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.helper.directory import DirectoryHelper
from app.log import logger
class QueryDirectorySettingsInput(BaseModel):
"""查询系统目录设置工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
directory_type: Optional[str] = Field("all",
description="Filter directories by type: 'download' for download directories, 'library' for media library directories, 'all' for all directories")
storage_type: Optional[str] = Field("all",
description="Filter directories by storage type: 'local' for local storage, 'remote' for remote storage, 'all' for all storage types")
name: Optional[str] = Field(None,
description="Filter directories by name (partial match, optional)")
class QueryDirectorySettingsTool(MoviePilotTool):
name: str = "query_directory_settings"
description: str = "Query system directory configuration settings (NOT file listings). Returns configured directory paths, storage types, transfer modes, and other directory-related settings. Use 'list_directory' to list actual files and folders in a directory."
args_schema: Type[BaseModel] = QueryDirectorySettingsInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
directory_type = kwargs.get("directory_type", "all")
storage_type = kwargs.get("storage_type", "all")
name = kwargs.get("name")
parts = ["正在查询目录配置"]
if directory_type != "all":
type_map = {"download": "下载目录", "library": "媒体库目录"}
parts.append(f"类型: {type_map.get(directory_type, directory_type)}")
if storage_type != "all":
storage_map = {"local": "本地存储", "remote": "远程存储"}
parts.append(f"存储: {storage_map.get(storage_type, storage_type)}")
if name:
parts.append(f"名称: {name}")
return " | ".join(parts) if len(parts) > 1 else parts[0]
async def run(self, directory_type: Optional[str] = "all",
storage_type: Optional[str] = "all",
name: Optional[str] = None, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: directory_type={directory_type}, storage_type={storage_type}, name={name}")
try:
directory_helper = DirectoryHelper()
# 根据目录类型获取目录列表
if directory_type == "download":
dirs = directory_helper.get_download_dirs()
elif directory_type == "library":
dirs = directory_helper.get_library_dirs()
else:
dirs = directory_helper.get_dirs()
# 按存储类型过滤
filtered_dirs = []
for d in dirs:
# 按存储类型过滤
if storage_type == "local":
# 对于下载目录,检查 storage对于媒体库目录检查 library_storage
if directory_type == "download" and d.storage != "local":
continue
elif directory_type == "library" and d.library_storage != "local":
continue
elif directory_type == "all":
# 检查是否有本地存储配置
if d.download_path and d.storage != "local":
continue
if d.library_path and d.library_storage != "local":
continue
elif storage_type == "remote":
# 对于下载目录,检查 storage对于媒体库目录检查 library_storage
if directory_type == "download" and d.storage == "local":
continue
elif directory_type == "library" and d.library_storage == "local":
continue
elif directory_type == "all":
# 检查是否有远程存储配置
if d.download_path and d.storage == "local":
continue
if d.library_path and d.library_storage == "local":
continue
# 按名称过滤(部分匹配)
if name and d.name and name.lower() not in d.name.lower():
continue
filtered_dirs.append(d)
if filtered_dirs:
# 转换为字典格式,只保留关键信息
simplified_dirs = []
for d in filtered_dirs:
simplified = {
"name": d.name,
"priority": d.priority,
"storage": d.storage,
"download_path": d.download_path,
"library_path": d.library_path,
"library_storage": d.library_storage,
"media_type": d.media_type,
"media_category": d.media_category,
"monitor_type": d.monitor_type,
"monitor_mode": d.monitor_mode,
"transfer_type": d.transfer_type,
"overwrite_mode": d.overwrite_mode,
"renaming": d.renaming,
"scraping": d.scraping,
"notify": d.notify,
"download_type_folder": d.download_type_folder,
"download_category_folder": d.download_category_folder,
"library_type_folder": d.library_type_folder,
"library_category_folder": d.library_category_folder
}
simplified_dirs.append(simplified)
result_json = json.dumps(simplified_dirs, ensure_ascii=False, indent=2)
return result_json
return "未找到相关目录配置"
except Exception as e:
logger.error(f"查询系统目录设置失败: {e}", exc_info=True)
return f"查询系统目录设置时发生错误: {str(e)}"

View File

@@ -0,0 +1,267 @@
"""查询下载工具"""
import json
from typing import Optional, Type, List, Union
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.download import DownloadChain
from app.db.downloadhistory_oper import DownloadHistoryOper
from app.log import logger
from app.schemas import TransferTorrent, DownloadingTorrent
from app.schemas.types import TorrentStatus, media_type_to_agent
class QueryDownloadTasksInput(BaseModel):
"""查询下载工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
downloader: Optional[str] = Field(None,
description="Name of specific downloader to query (optional, if not provided queries all configured downloaders)")
status: Optional[str] = Field("all",
description="Filter downloads by status: 'downloading' for active downloads, 'completed' for finished downloads, 'paused' for paused downloads, 'all' for all downloads")
hash: Optional[str] = Field(None, description="Query specific download task by hash (optional, if provided will search for this specific task regardless of status)")
title: Optional[str] = Field(None, description="Query download tasks by title/name (optional, supports partial match, searches all tasks if provided)")
tag: Optional[str] = Field(None, description="Filter download tasks by tag (optional, supports partial match, e.g. 'movie' will match tasks with tag 'movie' or 'movie_2024')")
class QueryDownloadTasksTool(MoviePilotTool):
name: str = "query_download_tasks"
description: str = "Query download status and list download tasks. Can query all active downloads, or search for specific tasks by hash, title, or tag. Shows download progress, completion status, tags, and task details from configured downloaders."
args_schema: Type[BaseModel] = QueryDownloadTasksInput
@staticmethod
def _get_all_torrents(download_chain: DownloadChain, downloader: Optional[str] = None) -> List[Union[TransferTorrent, DownloadingTorrent]]:
"""
查询所有状态的任务(包括下载中和已完成的任务)
"""
all_torrents = []
# 查询正在下载的任务
downloading_torrents = download_chain.list_torrents(
downloader=downloader,
status=TorrentStatus.DOWNLOADING
) or []
all_torrents.extend(downloading_torrents)
# 查询已完成的任务(可转移状态)
transfer_torrents = download_chain.list_torrents(
downloader=downloader,
status=TorrentStatus.TRANSFER
) or []
all_torrents.extend(transfer_torrents)
return all_torrents
@staticmethod
def _format_progress(progress: Optional[float]) -> Optional[str]:
"""
将下载进度格式化为保留一位小数的百分比字符串
"""
try:
if progress is None:
return None
return f"{float(progress):.1f}%"
except (TypeError, ValueError):
return None
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
downloader = kwargs.get("downloader")
status = kwargs.get("status", "all")
hash_value = kwargs.get("hash")
title = kwargs.get("title")
parts = ["正在查询下载任务"]
if downloader:
parts.append(f"下载器: {downloader}")
if status != "all":
status_map = {"downloading": "下载中", "completed": "已完成", "paused": "已暂停"}
parts.append(f"状态: {status_map.get(status, status)}")
if hash_value:
parts.append(f"Hash: {hash_value[:8]}...")
elif title:
parts.append(f"标题: {title}")
tag = kwargs.get("tag")
if tag:
parts.append(f"标签: {tag}")
return " | ".join(parts) if len(parts) > 1 else parts[0]
async def run(self, downloader: Optional[str] = None,
status: Optional[str] = "all",
hash: Optional[str] = None,
title: Optional[str] = None,
tag: Optional[str] = None, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: downloader={downloader}, status={status}, hash={hash}, title={title}, tag={tag}")
try:
download_chain = DownloadChain()
# 如果提供了hash直接查询该hash的任务不限制状态
if hash:
torrents = download_chain.list_torrents(downloader=downloader, hashs=[hash]) or []
if not torrents:
return f"未找到hash为 {hash} 的下载任务(该任务可能已完成、已删除或不存在)"
# 转换为DownloadingTorrent格式
downloads = []
for torrent in torrents:
# 获取下载历史信息
history = DownloadHistoryOper().get_by_hash(torrent.hash)
if history:
if hasattr(torrent, "media"):
torrent.media = {
"tmdbid": history.tmdbid,
"type": history.type,
"title": history.title,
"season": history.seasons,
"episode": history.episodes,
"image": history.image,
}
if hasattr(torrent, "username"):
torrent.username = history.username
torrent.userid = history.userid
downloads.append(torrent)
filtered_downloads = downloads
elif title:
# 如果提供了title查询所有任务并搜索匹配的标题
# 查询所有状态的任务
all_torrents = self._get_all_torrents(download_chain, downloader)
filtered_downloads = []
title_lower = title.lower()
for torrent in all_torrents:
# 获取下载历史信息
history = DownloadHistoryOper().get_by_hash(torrent.hash)
# 检查标题或名称是否匹配(包括下载历史中的标题)
matched = False
# 检查torrent的title和name字段
if (title_lower in (torrent.title or "").lower()) or \
(title_lower in (getattr(torrent, "name", None) or "").lower()):
matched = True
# 检查下载历史中的标题
if history and history.title:
if title_lower in history.title.lower():
matched = True
if matched:
if history:
if hasattr(torrent, "media"):
torrent.media = {
"tmdbid": history.tmdbid,
"type": history.type,
"title": history.title,
"season": history.seasons,
"episode": history.episodes,
"image": history.image,
}
if hasattr(torrent, "username"):
torrent.username = history.username
torrent.userid = history.userid
filtered_downloads.append(torrent)
if not filtered_downloads:
return f"未找到标题包含 '{title}' 的下载任务"
else:
# 根据status决定查询方式
if status == "downloading":
# 如果status为下载中使用downloading方法
downloads = download_chain.downloading(name=downloader) or []
filtered_downloads = []
for dl in downloads:
if downloader and dl.downloader != downloader:
continue
filtered_downloads.append(dl)
else:
# 其他状态completed、paused、all使用list_torrents查询所有任务
# 查询所有状态的任务
all_torrents = self._get_all_torrents(download_chain, downloader)
filtered_downloads = []
for torrent in all_torrents:
if downloader and torrent.downloader != downloader:
continue
# 根据status过滤
if status == "completed":
# 已完成的任务state为seeding或completed
if torrent.state not in ["seeding", "completed"]:
continue
elif status == "paused":
# 已暂停的任务
if torrent.state != "paused":
continue
# status == "all" 时不过滤
# 获取下载历史信息
history = DownloadHistoryOper().get_by_hash(torrent.hash)
if history:
if hasattr(torrent, "media"):
torrent.media = {
"tmdbid": history.tmdbid,
"type": history.type,
"title": history.title,
"season": history.seasons,
"episode": history.episodes,
"image": history.image,
}
if hasattr(torrent, "username"):
torrent.username = history.username
torrent.userid = history.userid
filtered_downloads.append(torrent)
# 按tag过滤
if tag and filtered_downloads:
tag_lower = tag.lower()
filtered_downloads = [
d for d in filtered_downloads
if d.tags and tag_lower in d.tags.lower()
]
if not filtered_downloads:
return f"未找到标签包含 '{tag}' 的下载任务"
if filtered_downloads:
# 限制最多20条结果
total_count = len(filtered_downloads)
limited_downloads = filtered_downloads[:20]
# 精简字段,只保留关键信息
simplified_downloads = []
for d in limited_downloads:
simplified = {
"downloader": d.downloader,
"hash": d.hash,
"title": d.title,
"name": getattr(d, "name", None),
"year": getattr(d, "year", None),
"season_episode": getattr(d, "season_episode", None),
"size": d.size,
"progress": self._format_progress(d.progress),
"state": d.state,
"upspeed": getattr(d, "upspeed", None),
"dlspeed": getattr(d, "dlspeed", None),
"tags": d.tags,
"left_time": getattr(d, "left_time", None)
}
# 精简 media 字段
media = getattr(d, "media", None)
if media:
simplified["media"] = {
"tmdbid": media.get("tmdbid"),
"type": media_type_to_agent(media.get("type")),
"title": media.get("title"),
"season": media.get("season"),
"episode": media.get("episode")
}
simplified_downloads.append(simplified)
result_json = json.dumps(simplified_downloads, ensure_ascii=False, indent=2)
# 如果结果被裁剪,添加提示信息
if total_count > 20:
return f"注意:查询结果共找到 {total_count} 条,为节省上下文空间,仅显示前 20 条结果。\n\n{result_json}"
# 如果查询的是特定hash或title添加明确的状态信息
if hash:
return f"找到hash为 {hash} 的下载任务:\n\n{result_json}"
elif title:
return f"找到 {total_count} 个标题包含 '{title}' 的下载任务:\n\n{result_json}"
return result_json
return "未找到相关下载任务"
except Exception as e:
logger.error(f"查询下载失败: {e}", exc_info=True)
return f"查询下载时发生错误: {str(e)}"

View File

@@ -0,0 +1,38 @@
"""查询下载器工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.db.systemconfig_oper import SystemConfigOper
from app.log import logger
from app.schemas.types import SystemConfigKey
class QueryDownloadersInput(BaseModel):
"""查询下载器工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
class QueryDownloadersTool(MoviePilotTool):
name: str = "query_downloaders"
description: str = "Query downloader configuration and list all available downloaders. Shows downloader status, connection details, and configuration settings."
args_schema: Type[BaseModel] = QueryDownloadersInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""生成友好的提示消息"""
return "正在查询下载器配置"
async def run(self, **kwargs) -> str:
logger.info(f"执行工具: {self.name}")
try:
system_config_oper = SystemConfigOper()
downloaders_config = system_config_oper.get(SystemConfigKey.Downloaders)
if downloaders_config:
return json.dumps(downloaders_config, ensure_ascii=False, indent=2)
return "未配置下载器。"
except Exception as e:
logger.error(f"查询下载器失败: {e}")
return f"查询下载器时发生错误: {str(e)}"

View File

@@ -0,0 +1,103 @@
"""查询剧集上映时间工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.tmdb import TmdbChain
from app.log import logger
class QueryEpisodeScheduleInput(BaseModel):
"""查询剧集上映时间工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
tmdb_id: int = Field(..., description="TMDB ID of the TV series (can be obtained from search_media tool)")
season: int = Field(..., description="Season number to query")
episode_group: Optional[str] = Field(None, description="Episode group ID (optional)")
class QueryEpisodeScheduleTool(MoviePilotTool):
name: str = "query_episode_schedule"
description: str = "Query TV series episode air dates and schedule. Returns non-duplicated schedule fields, including episode list, air-date statistics, and per-episode metadata. Filters out episodes without air dates."
args_schema: Type[BaseModel] = QueryEpisodeScheduleInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
tmdb_id = kwargs.get("tmdb_id")
season = kwargs.get("season")
episode_group = kwargs.get("episode_group")
message = f"正在查询剧集上映时间: TMDB ID {tmdb_id}{season}"
if episode_group:
message += f" (剧集组: {episode_group})"
return message
async def run(self, tmdb_id: int, season: int, episode_group: Optional[str] = None, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: tmdb_id={tmdb_id}, season={season}, episode_group={episode_group}")
try:
# 获取集列表
tmdb_chain = TmdbChain()
episodes = await tmdb_chain.async_tmdb_episodes(
tmdbid=tmdb_id,
season=season,
episode_group=episode_group
)
if not episodes:
return json.dumps({
"success": False,
"message": f"未找到 TMDB ID {tmdb_id}{season}季的集信息"
}, ensure_ascii=False)
# 过滤掉没有上映日期的集,并构建每集的详细信息
episode_list = []
for episode in episodes:
air_date = episode.air_date
# 过滤掉没有上映日期的数据
if not air_date:
continue
episode_info = {
"episode_number": episode.episode_number,
"name": episode.name,
"air_date": air_date,
"runtime": episode.runtime,
"vote_average": episode.vote_average,
"still_path": episode.still_path,
"episode_type": episode.episode_type,
"season_number": episode.season_number
}
episode_list.append(episode_info)
if not episode_list:
return json.dumps({
"success": False,
"message": f"未找到 TMDB ID {tmdb_id}{season}季的播出时间信息(所有集都没有播出日期)"
}, ensure_ascii=False)
# 按播出日期排序
episode_list.sort(key=lambda x: (x["air_date"] or "", x["episode_number"] or 0))
result = {
"season": season,
"total_episodes": len(episodes),
"episodes_with_air_date": len(episode_list),
"episodes": episode_list
}
return json.dumps(result, ensure_ascii=False, indent=2)
except Exception as e:
error_message = f"查询剧集上映时间失败: {str(e)}"
logger.error(f"查询剧集上映时间失败: {e}", exc_info=True)
return json.dumps({
"success": False,
"message": error_message,
"tmdb_id": tmdb_id,
"season": season
}, ensure_ascii=False)

View File

@@ -0,0 +1,65 @@
"""查询已安装插件工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.core.plugin import PluginManager
from app.log import logger
class QueryInstalledPluginsInput(BaseModel):
"""查询已安装插件工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
class QueryInstalledPluginsTool(MoviePilotTool):
name: str = "query_installed_plugins"
description: str = (
"Query all installed plugins in MoviePilot. Returns a list of installed plugins with their ID, name, "
"description, version, author, running state, and other information. "
"Use this tool to discover what plugins are available before querying plugin capabilities or running plugin commands."
)
require_admin: bool = True
args_schema: Type[BaseModel] = QueryInstalledPluginsInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""生成友好的提示消息"""
return "正在查询已安装插件"
async def run(self, **kwargs) -> str:
logger.info(f"执行工具: {self.name}")
try:
plugin_manager = PluginManager()
local_plugins = plugin_manager.get_local_plugins()
# 仅返回已安装的插件
installed_plugins = [plugin for plugin in local_plugins if plugin.installed]
if not installed_plugins:
return "当前没有已安装的插件"
plugins_list = []
for plugin in installed_plugins:
plugins_list.append(
{
"id": plugin.id,
"plugin_name": plugin.plugin_name,
"plugin_desc": plugin.plugin_desc,
"plugin_version": plugin.plugin_version,
"plugin_author": plugin.plugin_author,
"state": plugin.state,
"has_page": plugin.has_page,
}
)
result_json = json.dumps(plugins_list, ensure_ascii=False, indent=2)
return result_json
except Exception as e:
logger.error(f"查询已安装插件失败: {e}", exc_info=True)
return f"查询已安装插件时发生错误: {str(e)}"

View File

@@ -0,0 +1,177 @@
"""查询媒体库工具"""
import json
from collections import OrderedDict
from typing import Optional, Type, Any
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.mediaserver import MediaServerChain
from app.helper.mediaserver import MediaServerHelper
from app.log import logger
from app.schemas.types import MediaType, media_type_to_agent
def _sort_seasons(seasons: Optional[dict]) -> dict:
"""按季号、集号升序整理季集信息,保证输出稳定。"""
if not seasons:
return {}
def _sort_key(value):
try:
return int(value)
except (TypeError, ValueError):
return str(value)
return OrderedDict(
(season, sorted(episodes, key=_sort_key))
for season, episodes in sorted(seasons.items(), key=lambda item: _sort_key(item[0]))
)
def _filter_regular_seasons(seasons: Optional[dict]) -> OrderedDict:
"""仅保留正片季,忽略 season 0 等特殊季。"""
sorted_seasons = _sort_seasons(seasons)
regular_seasons = OrderedDict()
for season, episodes in sorted_seasons.items():
try:
season_number = int(season)
except (TypeError, ValueError):
continue
if season_number > 0:
regular_seasons[season_number] = episodes
return regular_seasons
def _build_tv_server_result(existing_seasons: OrderedDict, total_seasons: OrderedDict) -> dict[str, Any]:
"""构建单个服务器的电视剧存在性结果。"""
seasons_result = OrderedDict()
missing_seasons = []
all_seasons = sorted(set(total_seasons.keys()) | set(existing_seasons.keys()))
for season in all_seasons:
existing_episodes = existing_seasons.get(season, [])
total_episodes = total_seasons.get(season)
if total_episodes is not None:
missing_episodes = [episode for episode in total_episodes if episode not in existing_episodes]
total_episode_count = len(total_episodes)
else:
missing_episodes = None
total_episode_count = None
seasons_result[str(season)] = {
"existing_episodes": existing_episodes,
"total_episodes": total_episode_count,
"missing_episodes": missing_episodes
}
if total_episodes is not None and not existing_episodes:
missing_seasons.append(season)
return {
"seasons": seasons_result,
"missing_seasons": missing_seasons
}
class QueryLibraryExistsInput(BaseModel):
"""查询媒体库工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
tmdb_id: Optional[int] = Field(None, description="TMDB ID (can be obtained from search_media tool). Either tmdb_id or douban_id must be provided.")
douban_id: Optional[str] = Field(None, description="Douban ID (can be obtained from search_media tool). Either tmdb_id or douban_id must be provided.")
media_type: Optional[str] = Field(None, description="Allowed values: movie, tv")
class QueryLibraryExistsTool(MoviePilotTool):
name: str = "query_library_exists"
description: str = "Check whether media already exists in Plex, Emby, or Jellyfin by media ID. Results are grouped by media server; TV results include existing episodes, total episodes, and missing episodes/seasons. Requires tmdb_id or douban_id from search_media."
args_schema: Type[BaseModel] = QueryLibraryExistsInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
tmdb_id = kwargs.get("tmdb_id")
douban_id = kwargs.get("douban_id")
media_type = kwargs.get("media_type")
if tmdb_id:
message = f"正在查询媒体库: TMDB={tmdb_id}"
elif douban_id:
message = f"正在查询媒体库: 豆瓣={douban_id}"
else:
message = "正在查询媒体库"
if media_type:
message += f" [{media_type}]"
return message
async def run(self, tmdb_id: Optional[int] = None, douban_id: Optional[str] = None,
media_type: Optional[str] = None, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: tmdb_id={tmdb_id}, douban_id={douban_id}, media_type={media_type}")
try:
if not tmdb_id and not douban_id:
return "参数错误tmdb_id 和 douban_id 至少需要提供一个,请先使用 search_media 工具获取媒体 ID。"
media_type_enum = None
if media_type:
media_type_enum = MediaType.from_agent(media_type)
if not media_type_enum:
return f"错误:无效的媒体类型 '{media_type}',支持的类型:'movie', 'tv'"
media_chain = MediaServerChain()
mediainfo = media_chain.recognize_media(
tmdbid=tmdb_id,
doubanid=douban_id,
mtype=media_type_enum,
)
if not mediainfo:
media_id = f"TMDB={tmdb_id}" if tmdb_id else f"豆瓣={douban_id}"
return f"未识别到媒体信息: {media_id}"
# 2. 遍历所有媒体服务器,分别查询存在性信息
server_results = OrderedDict()
media_server_helper = MediaServerHelper()
total_seasons = _filter_regular_seasons(mediainfo.seasons)
global_existsinfo = media_chain.media_exists(mediainfo=mediainfo)
for service_name in sorted(media_server_helper.get_services().keys()):
existsinfo = media_chain.media_exists(mediainfo=mediainfo, server=service_name)
if not existsinfo:
continue
if existsinfo.type == MediaType.TV:
existing_seasons = _filter_regular_seasons(existsinfo.seasons)
server_results[service_name] = _build_tv_server_result(
existing_seasons=existing_seasons,
total_seasons=total_seasons
)
else:
server_results[service_name] = {
"exists": True
}
if global_existsinfo:
fallback_server_name = global_existsinfo.server or "local"
if fallback_server_name not in server_results:
if global_existsinfo.type == MediaType.TV:
server_results[fallback_server_name] = _build_tv_server_result(
existing_seasons=_filter_regular_seasons(global_existsinfo.seasons),
total_seasons=total_seasons
)
else:
server_results[fallback_server_name] = {
"exists": True
}
if not server_results:
return "媒体库中未找到相关媒体"
# 3. 组装统一的存在性结果,不查询媒体服务器详情
result_dict = {
"title": mediainfo.title,
"year": mediainfo.year,
"type": media_type_to_agent(mediainfo.type),
"servers": server_results
}
return json.dumps([result_dict], ensure_ascii=False)
except Exception as e:
logger.error(f"查询媒体库失败: {e}", exc_info=True)
return f"查询媒体库时发生错误: {str(e)}"

View File

@@ -0,0 +1,117 @@
"""查询媒体服务器最近入库影片工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.mediaserver import MediaServerChain
from app.helper.service import ServiceConfigHelper
from app.log import logger
PAGE_SIZE = 20
class QueryLibraryLatestInput(BaseModel):
"""查询媒体服务器最近入库影片工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
server: Optional[str] = Field(
None,
description="Media server name (optional, if not specified queries all enabled media servers)",
)
page: Optional[int] = Field(
1, description="Page number for pagination (default: 1, 20 items per page)"
)
class QueryLibraryLatestTool(MoviePilotTool):
name: str = "query_library_latest"
description: str = "Query the latest media items added to the media server (Plex, Emby, Jellyfin). Returns recently added movies and TV series with their titles, images, links, and other metadata. Supports pagination with 20 items per page."
args_schema: Type[BaseModel] = QueryLibraryLatestInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
server = kwargs.get("server")
page = kwargs.get("page", 1)
parts = ["正在查询媒体服务器最近入库影片"]
if server:
parts.append(f"服务器: {server}")
else:
parts.append("所有服务器")
parts.append(f"{page}")
return " | ".join(parts)
async def run(
self, server: Optional[str] = None, page: Optional[int] = 1, **kwargs
) -> str:
page = max(1, page or 1)
# 为了支持分页,需要获取足够多的数据再切片
fetch_count = page * PAGE_SIZE
logger.info(f"执行工具: {self.name}, 参数: server={server}, page={page}")
try:
media_chain = MediaServerChain()
results = []
# 如果没有指定服务器,获取所有启用的媒体服务器
if not server:
mediaservers = ServiceConfigHelper.get_mediaserver_configs()
enabled_servers = [ms.name for ms in mediaservers if ms.enabled]
if not enabled_servers:
return "未找到启用的媒体服务器"
# 遍历所有启用的服务器
for server_name in enabled_servers:
latest_items = media_chain.latest(
server=server_name, count=fetch_count, username=self._username
)
if latest_items:
for item in latest_items:
item_dict = item.model_dump(exclude_none=True)
item_dict["server"] = server_name
results.append(item_dict)
else:
# 查询指定服务器
latest_items = media_chain.latest(
server=server, count=fetch_count, username=self._username
)
if latest_items:
for item in latest_items:
item_dict = item.model_dump(exclude_none=True)
item_dict["server"] = server
results.append(item_dict)
if not results:
server_info = f"服务器 {server}" if server else "所有服务器"
return f"未找到 {server_info} 的最近入库影片"
# 分页
total_count = len(results)
start = (page - 1) * PAGE_SIZE
end = start + PAGE_SIZE
page_results = results[start:end]
if not page_results:
total_pages = (total_count + PAGE_SIZE - 1) // PAGE_SIZE
return f"{page} 页没有数据,共 {total_count} 条结果,共 {total_pages} 页。"
total_pages = (total_count + PAGE_SIZE - 1) // PAGE_SIZE
payload_msg = f"{page}/{total_pages} 页,当前页 {len(page_results)} 条结果,共 {total_count} 条。"
if page < total_pages:
payload_msg += f" 可使用 page={page + 1} 获取下一页。"
result_json = json.dumps(page_results, ensure_ascii=False, indent=2)
return f"{payload_msg}\n\n{result_json}"
except Exception as e:
logger.error(f"查询媒体服务器最近入库影片失败: {e}", exc_info=True)
return f"查询媒体服务器最近入库影片时发生错误: {str(e)}"

View File

@@ -0,0 +1,126 @@
"""查询媒体详情工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.media import MediaChain
from app.log import logger
from app.schemas.types import MediaType
class QueryMediaDetailInput(BaseModel):
"""查询媒体详情工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
tmdb_id: Optional[int] = Field(None, description="TMDB ID of the media (movie or TV series, can be obtained from search_media tool)")
douban_id: Optional[str] = Field(None, description="Douban ID of the media (alternative to tmdb_id)")
media_type: str = Field(..., description="Allowed values: movie, tv")
class QueryMediaDetailTool(MoviePilotTool):
name: str = "query_media_detail"
description: str = "Query supplementary media details from TMDB by ID and media_type. Accepts tmdb_id or douban_id (at least one required). media_type accepts 'movie' or 'tv'. Returns non-duplicated detail fields such as status, genres, directors, actors, and season info for TV series."
args_schema: Type[BaseModel] = QueryMediaDetailInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
tmdb_id = kwargs.get("tmdb_id")
douban_id = kwargs.get("douban_id")
if tmdb_id:
return f"正在查询媒体详情: TMDB ID {tmdb_id}"
return f"正在查询媒体详情: 豆瓣 ID {douban_id}"
async def run(self, media_type: str, tmdb_id: Optional[int] = None, douban_id: Optional[str] = None, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: tmdb_id={tmdb_id}, douban_id={douban_id}, media_type={media_type}")
if tmdb_id is None and douban_id is None:
return json.dumps({
"success": False,
"message": "必须提供 tmdb_id 或 douban_id 之一"
}, ensure_ascii=False)
try:
media_chain = MediaChain()
media_type_enum = MediaType.from_agent(media_type)
if not media_type_enum:
return json.dumps({
"success": False,
"message": f"无效的媒体类型 '{media_type}',支持的类型:'movie', 'tv'"
}, ensure_ascii=False)
mediainfo = await media_chain.async_recognize_media(tmdbid=tmdb_id, doubanid=douban_id, mtype=media_type_enum)
if not mediainfo:
id_info = f"TMDB ID {tmdb_id}" if tmdb_id else f"豆瓣 ID {douban_id}"
return json.dumps({
"success": False,
"message": f"未找到 {id_info} 的媒体信息"
}, ensure_ascii=False)
# 精简 genres - 只保留名称
genres = [g.get("name") for g in (mediainfo.genres or []) if g.get("name")]
# 精简 directors - 只保留姓名和职位
directors = [
{
"name": d.get("name"),
"job": d.get("job")
}
for d in (mediainfo.directors or [])
if d.get("name")
]
# 精简 actors - 只保留姓名和角色
actors = [
{
"name": a.get("name"),
"character": a.get("character")
}
for a in (mediainfo.actors or [])
if a.get("name")
]
# 构建基础媒体详情信息
result = {
"status": mediainfo.status,
"genres": genres,
"directors": directors,
"actors": actors
}
# 如果是电视剧,添加电视剧特有信息
if mediainfo.type == MediaType.TV:
# 精简 season_info - 只保留基础摘要
season_info = [
{
"season_number": s.get("season_number"),
"name": s.get("name"),
"episode_count": s.get("episode_count"),
"air_date": s.get("air_date")
}
for s in (mediainfo.season_info or [])
if s.get("season_number") is not None
]
result.update({
"number_of_seasons": mediainfo.number_of_seasons,
"number_of_episodes": mediainfo.number_of_episodes,
"first_air_date": mediainfo.first_air_date,
"last_air_date": mediainfo.last_air_date,
"season_info": season_info
})
return json.dumps(result, ensure_ascii=False, indent=2)
except Exception as e:
error_message = f"查询媒体详情失败: {str(e)}"
logger.error(f"查询媒体详情失败: {e}", exc_info=True)
return json.dumps({
"success": False,
"message": error_message,
"tmdb_id": tmdb_id,
"douban_id": douban_id
}, ensure_ascii=False)

View File

@@ -0,0 +1,118 @@
"""查询插件能力工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.core.plugin import PluginManager
from app.log import logger
class QueryPluginCapabilitiesInput(BaseModel):
"""查询插件能力工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
plugin_id: Optional[str] = Field(
None,
description="Optional plugin ID to query capabilities for a specific plugin. "
"If not provided, returns capabilities of all running plugins. "
"Use query_installed_plugins tool to get the plugin IDs first.",
)
class QueryPluginCapabilitiesTool(MoviePilotTool):
name: str = "query_plugin_capabilities"
description: str = (
"Query the capabilities of installed plugins, including supported commands and scheduled services. "
"Commands are slash-commands (e.g. /xxx) that can be executed via the run_slash_command tool. "
"Scheduled services are periodic tasks that can be triggered via the run_scheduler tool. "
"Optionally specify a plugin_id to query a specific plugin, or omit to query all running plugins."
)
require_admin: bool = True
args_schema: Type[BaseModel] = QueryPluginCapabilitiesInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""生成友好的提示消息"""
plugin_id = kwargs.get("plugin_id")
if plugin_id:
return f"正在查询插件 {plugin_id} 的能力"
return "正在查询所有插件的能力"
async def run(self, plugin_id: Optional[str] = None, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: plugin_id={plugin_id}")
try:
plugin_manager = PluginManager()
result = {}
# 获取插件命令
commands = plugin_manager.get_plugin_commands(pid=plugin_id)
if commands:
commands_list = []
for cmd in commands:
cmd_info = {
"cmd": cmd.get("cmd"),
"desc": cmd.get("desc"),
"plugin_id": cmd.get("pid"),
}
# data 字段可能包含额外参数信息
if cmd.get("data"):
cmd_info["data"] = cmd.get("data")
commands_list.append(cmd_info)
result["commands"] = commands_list
# 获取插件动作
actions = plugin_manager.get_plugin_actions(pid=plugin_id)
if actions:
actions_list = []
for action_group in actions:
plugin_actions = {
"plugin_id": action_group.get("plugin_id"),
"plugin_name": action_group.get("plugin_name"),
"actions": [],
}
for action in action_group.get("actions", []):
plugin_actions["actions"].append(
{
"id": action.get("id"),
"name": action.get("name"),
}
)
actions_list.append(plugin_actions)
result["actions"] = actions_list
# 获取插件定时服务
services = plugin_manager.get_plugin_services(pid=plugin_id)
if services:
services_list = []
for svc in services:
svc_info = {
"id": svc.get("id"),
"name": svc.get("name"),
}
# 包含触发器信息
trigger = svc.get("trigger")
if trigger:
svc_info["trigger"] = str(trigger)
# 包含定时器参数
svc_kwargs = svc.get("kwargs")
if svc_kwargs:
svc_info["trigger_kwargs"] = {
k: str(v) for k, v in svc_kwargs.items()
}
services_list.append(svc_info)
result["services"] = services_list
if not result:
if plugin_id:
return f"插件 {plugin_id} 没有注册任何命令、动作或定时服务"
return "当前没有运行中的插件注册了命令、动作或定时服务"
return json.dumps(result, ensure_ascii=False, indent=2)
except Exception as e:
logger.error(f"查询插件能力失败: {e}", exc_info=True)
return f"查询插件能力时发生错误: {str(e)}"

View File

@@ -0,0 +1,162 @@
"""查询热门订阅工具"""
import json
from typing import Optional, Type
import cn2an
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.core.context import MediaInfo
from app.helper.subscribe import SubscribeHelper
from app.log import logger
from app.schemas.types import MediaType, media_type_to_agent
class QueryPopularSubscribesInput(BaseModel):
"""查询热门订阅工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
media_type: str = Field(..., description="Allowed values: movie, tv")
page: Optional[int] = Field(1, description="Page number for pagination (default: 1)")
count: Optional[int] = Field(30, description="Number of items per page (default: 30)")
min_sub: Optional[int] = Field(None, description="Minimum number of subscribers filter (optional, e.g., 5)")
genre_id: Optional[int] = Field(None, description="Filter by genre ID (optional)")
min_rating: Optional[float] = Field(None, description="Minimum rating filter (optional, e.g., 7.5)")
max_rating: Optional[float] = Field(None, description="Maximum rating filter (optional, e.g., 10.0)")
sort_type: Optional[str] = Field(None, description="Sort type (optional, e.g., 'count', 'rating')")
class QueryPopularSubscribesTool(MoviePilotTool):
name: str = "query_popular_subscribes"
description: str = "Query popular subscriptions based on user shared data. Shows media with the most subscribers, supports filtering by genre, rating, minimum subscribers, and pagination."
args_schema: Type[BaseModel] = QueryPopularSubscribesInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
media_type = kwargs.get("media_type", "")
page = kwargs.get("page", 1)
min_sub = kwargs.get("min_sub")
min_rating = kwargs.get("min_rating")
max_rating = kwargs.get("max_rating")
parts = [f"正在查询热门订阅 [{media_type}]"]
if min_sub:
parts.append(f"最少订阅: {min_sub}")
if min_rating:
parts.append(f"最低评分: {min_rating}")
if max_rating:
parts.append(f"最高评分: {max_rating}")
if page > 1:
parts.append(f"{page}")
return " | ".join(parts) if len(parts) > 1 else parts[0]
async def run(self, media_type: str,
page: Optional[int] = 1,
count: Optional[int] = 30,
min_sub: Optional[int] = None,
genre_id: Optional[int] = None,
min_rating: Optional[float] = None,
max_rating: Optional[float] = None,
sort_type: Optional[str] = None, **kwargs) -> str:
logger.info(
f"执行工具: {self.name}, 参数: media_type={media_type}, page={page}, count={count}, min_sub={min_sub}, "
f"genre_id={genre_id}, min_rating={min_rating}, max_rating={max_rating}, sort_type={sort_type}")
try:
if page is None or page < 1:
page = 1
if count is None or count < 1:
count = 30
media_type_enum = MediaType.from_agent(media_type)
if not media_type_enum:
return f"错误:无效的媒体类型 '{media_type}',支持的类型:'movie', 'tv'"
subscribe_helper = SubscribeHelper()
subscribes = await subscribe_helper.async_get_statistic(
stype=media_type_enum.to_agent(),
page=page,
count=count,
genre_id=genre_id,
min_rating=min_rating,
max_rating=max_rating,
sort_type=sort_type
)
if not subscribes:
return "未找到热门订阅数据(可能订阅统计功能未启用)"
# 转换为MediaInfo格式并过滤
ret_medias = []
for sub in subscribes:
# 订阅人数
subscriber_count = sub.get("count", 0)
# 如果设置了最小订阅人数,进行过滤
if min_sub and subscriber_count < min_sub:
continue
media = MediaInfo()
raw_type = str(sub.get("type") or "").strip().lower()
if raw_type in ["movie", "电影"]:
media.type = MediaType.MOVIE
elif raw_type in ["tv", "电视剧"]:
media.type = MediaType.TV
else:
# 跳过无法识别类型的数据,避免单条脏数据导致整批失败
logger.warning(f"跳过未知媒体类型: {sub.get('type')}")
continue
media.tmdb_id = sub.get("tmdbid")
# 处理标题
title = sub.get("name")
season = sub.get("season")
if season and int(season) > 1 and media.tmdb_id:
# 小写数据转大写
season_str = cn2an.an2cn(season, "low")
title = f"{title}{season_str}"
media.title = title
media.year = sub.get("year")
media.douban_id = sub.get("doubanid")
media.bangumi_id = sub.get("bangumiid")
media.tvdb_id = sub.get("tvdbid")
media.imdb_id = sub.get("imdbid")
media.season = sub.get("season")
media.vote_average = sub.get("vote")
media.poster_path = sub.get("poster")
media.backdrop_path = sub.get("backdrop")
media.popularity = subscriber_count
ret_medias.append(media)
if not ret_medias:
return "未找到符合条件的热门订阅"
# 转换为字典格式,只保留关键信息
simplified_medias = []
for media in ret_medias:
media_dict = media.to_dict()
simplified = {
"type": media_type_to_agent(media_dict.get("type")),
"title": media_dict.get("title"),
"year": media_dict.get("year"),
"tmdb_id": media_dict.get("tmdb_id"),
"douban_id": media_dict.get("douban_id"),
"bangumi_id": media_dict.get("bangumi_id"),
"tvdb_id": media_dict.get("tvdb_id"),
"imdb_id": media_dict.get("imdb_id"),
"season": media_dict.get("season"),
"vote_average": media_dict.get("vote_average"),
"poster_path": media_dict.get("poster_path"),
"backdrop_path": media_dict.get("backdrop_path"),
"popularity": media_dict.get("popularity"), # 订阅人数
"subscriber_count": media_dict.get("popularity") # 明确标注为订阅人数
}
simplified_medias.append(simplified)
result_json = json.dumps(simplified_medias, ensure_ascii=False, indent=2)
pagination_info = f"{page} 页,每页 {count} 条,共 {len(simplified_medias)} 条结果"
return f"{pagination_info}\n\n{result_json}"
except Exception as e:
logger.error(f"查询热门订阅失败: {e}", exc_info=True)
return f"查询热门订阅时发生错误: {str(e)}"

View File

@@ -0,0 +1,64 @@
"""查询规则组工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.helper.rule import RuleHelper
from app.log import logger
class QueryRuleGroupsInput(BaseModel):
"""查询规则组工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
class QueryRuleGroupsTool(MoviePilotTool):
name: str = "query_rule_groups"
description: str = "Query all filter rule groups available in the system. Rule groups are used to filter torrents when searching or subscribing. Returns rule group names, media types, and categories, but excludes rule_string to keep results concise."
args_schema: Type[BaseModel] = QueryRuleGroupsInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
return "正在查询所有规则组"
async def run(self, **kwargs) -> str:
logger.info(f"执行工具: {self.name}")
try:
rule_helper = RuleHelper()
rule_groups = rule_helper.get_rule_groups()
if not rule_groups:
return json.dumps({
"message": "未找到任何规则组",
"rule_groups": []
}, ensure_ascii=False, indent=2)
# 精简字段,过滤掉 rule_string 避免结果过大
simplified_groups = []
for group in rule_groups:
simplified = {
"name": group.name,
"media_type": group.media_type,
"category": group.category
}
simplified_groups.append(simplified)
result = {
"message": f"找到 {len(simplified_groups)} 个规则组",
"rule_groups": simplified_groups
}
return json.dumps(result, ensure_ascii=False, indent=2)
except Exception as e:
error_message = f"查询规则组失败: {str(e)}"
logger.error(f"查询规则组失败: {e}", exc_info=True)
return json.dumps({
"success": False,
"message": error_message,
"rule_groups": []
}, ensure_ascii=False)

View File

@@ -0,0 +1,54 @@
"""查询定时服务工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.log import logger
from app.scheduler import Scheduler
class QuerySchedulersInput(BaseModel):
"""查询定时服务工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
class QuerySchedulersTool(MoviePilotTool):
name: str = "query_schedulers"
description: str = "Query scheduled tasks and list all available scheduler jobs. Shows job status, next run time, and provider information."
args_schema: Type[BaseModel] = QuerySchedulersInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""生成友好的提示消息"""
return "正在查询定时服务"
async def run(self, **kwargs) -> str:
logger.info(f"执行工具: {self.name}")
try:
scheduler = Scheduler()
schedulers = scheduler.list()
if schedulers:
# 转换为字典列表以便JSON序列化
schedulers_list = []
for s in schedulers:
schedulers_list.append({
"id": s.id,
"name": s.name,
"provider": s.provider,
"status": s.status,
"next_run": s.next_run
})
result_json = json.dumps(schedulers_list, ensure_ascii=False, indent=2)
# 限制最多30条结果
total_count = len(schedulers_list)
if total_count > 30:
limited_schedulers = schedulers_list[:30]
limited_json = json.dumps(limited_schedulers, ensure_ascii=False, indent=2)
return f"注意:查询结果共找到 {total_count} 条,为节省上下文空间,仅显示前 30 条结果。\n\n{limited_json}"
return result_json
return "未找到定时服务"
except Exception as e:
logger.error(f"查询定时服务失败: {e}", exc_info=True)
return f"查询定时服务时发生错误: {str(e)}"

View File

@@ -0,0 +1,169 @@
"""查询站点用户数据工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.db import AsyncSessionFactory
from app.db.models.site import Site
from app.db.models.siteuserdata import SiteUserData
from app.log import logger
class QuerySiteUserdataInput(BaseModel):
"""查询站点用户数据工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
site_id: int = Field(
...,
description="The ID of the site to query user data for (can be obtained from query_sites tool)",
)
workdate: Optional[str] = Field(
None,
description="Work date to query (optional, format: 'YYYY-MM-DD', if not specified returns latest data)",
)
class QuerySiteUserdataTool(MoviePilotTool):
name: str = "query_site_userdata"
description: str = "Query user data for a specific site including username, user level, upload/download statistics, seeding information, bonus points, and other account details. Supports querying data for a specific date or latest data."
require_admin: bool = True
args_schema: Type[BaseModel] = QuerySiteUserdataInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
site_id = kwargs.get("site_id")
workdate = kwargs.get("workdate")
message = f"正在查询站点 #{site_id} 的用户数据"
if workdate:
message += f" (日期: {workdate})"
else:
message += " (最新数据)"
return message
async def run(self, site_id: int, workdate: Optional[str] = None, **kwargs) -> str:
logger.info(
f"执行工具: {self.name}, 参数: site_id={site_id}, workdate={workdate}"
)
try:
# 获取数据库会话
async with AsyncSessionFactory() as db:
# 获取站点
site = await Site.async_get(db, site_id)
if not site:
return json.dumps(
{"success": False, "message": f"站点不存在: {site_id}"},
ensure_ascii=False,
)
# 获取站点用户数据
user_data_list = await SiteUserData.async_get_by_domain(
db, domain=site.domain, workdate=workdate
)
if not user_data_list:
return json.dumps(
{
"success": False,
"message": f"站点 {site.name} ({site.domain}) 暂无用户数据",
"site_id": site_id,
"site_name": site.name,
"site_domain": site.domain,
"workdate": workdate,
},
ensure_ascii=False,
)
# 格式化用户数据
result = {
"success": True,
"site_id": site_id,
"site_name": site.name,
"site_domain": site.domain,
"workdate": workdate,
"data_count": len(user_data_list),
"user_data": [],
}
for user_data in user_data_list:
# 格式化上传/下载量(转换为可读格式)
upload_gb = user_data.upload / (1024**3) if user_data.upload else 0
download_gb = (
user_data.download / (1024**3) if user_data.download else 0
)
seeding_size_gb = (
user_data.seeding_size / (1024**3)
if user_data.seeding_size
else 0
)
leeching_size_gb = (
user_data.leeching_size / (1024**3)
if user_data.leeching_size
else 0
)
user_data_dict = {
"domain": user_data.domain,
"name": user_data.name,
"username": user_data.username,
"userid": user_data.userid,
"user_level": user_data.user_level,
"join_at": user_data.join_at,
"bonus": user_data.bonus,
"upload": user_data.upload,
"upload_gb": round(upload_gb, 2),
"download": user_data.download,
"download_gb": round(download_gb, 2),
"ratio": round(user_data.ratio, 2) if user_data.ratio else 0,
"seeding": int(user_data.seeding) if user_data.seeding else 0,
"leeching": int(user_data.leeching)
if user_data.leeching
else 0,
"seeding_size": user_data.seeding_size,
"seeding_size_gb": round(seeding_size_gb, 2),
"leeching_size": user_data.leeching_size,
"leeching_size_gb": round(leeching_size_gb, 2),
"seeding_info": user_data.seeding_info
if user_data.seeding_info
else [],
"message_unread": user_data.message_unread,
"message_unread_contents": user_data.message_unread_contents
if user_data.message_unread_contents
else [],
"err_msg": user_data.err_msg,
"updated_day": user_data.updated_day,
"updated_time": user_data.updated_time,
}
result["user_data"].append(user_data_dict)
# 如果有多条数据,只返回最新的(按更新时间排序)
if len(result["user_data"]) > 1:
result["user_data"].sort(
key=lambda x: (
x.get("updated_day", ""),
x.get("updated_time", ""),
),
reverse=True,
)
result["message"] = (
f"找到 {len(result['user_data'])} 条数据,显示最新的一条"
)
result["user_data"] = [result["user_data"][0]]
return json.dumps(result, ensure_ascii=False, indent=2)
except Exception as e:
error_message = f"查询站点用户数据失败: {str(e)}"
logger.error(f"查询站点用户数据失败: {e}", exc_info=True)
return json.dumps(
{"success": False, "message": error_message, "site_id": site_id},
ensure_ascii=False,
)

View File

@@ -0,0 +1,92 @@
"""查询站点工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.db.site_oper import SiteOper
from app.log import logger
class QuerySitesInput(BaseModel):
"""查询站点工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
status: Optional[str] = Field(
"all",
description="Filter sites by status: 'active' for enabled sites, 'inactive' for disabled sites, 'all' for all sites",
)
name: Optional[str] = Field(
None, description="Filter sites by name (partial match, optional)"
)
class QuerySitesTool(MoviePilotTool):
name: str = "query_sites"
description: str = "Query site status and list all configured sites. Shows site name, domain, status, priority, and basic configuration. Site priority (pri): smaller values have higher priority (e.g., pri=1 has higher priority than pri=10)."
require_admin: bool = True
args_schema: Type[BaseModel] = QuerySitesInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
status = kwargs.get("status", "all")
name = kwargs.get("name")
parts = ["正在查询站点"]
if status != "all":
status_map = {"active": "已启用", "inactive": "已禁用"}
parts.append(f"状态: {status_map.get(status, status)}")
if name:
parts.append(f"名称: {name}")
return " | ".join(parts) if len(parts) > 1 else parts[0]
async def run(
self, status: Optional[str] = "all", name: Optional[str] = None, **kwargs
) -> str:
logger.info(f"执行工具: {self.name}, 参数: status={status}, name={name}")
try:
site_oper = SiteOper()
# 获取所有站点(按优先级排序)
sites = await site_oper.async_list()
filtered_sites = []
for site in sites:
# 按状态过滤
if status == "active" and not site.is_active:
continue
if status == "inactive" and site.is_active:
continue
# 按名称过滤(部分匹配)
if name and name.lower() not in (site.name or "").lower():
continue
filtered_sites.append(site)
if filtered_sites:
# 精简字段,只保留关键信息
simplified_sites = []
for s in filtered_sites:
simplified = {
"id": s.id,
"name": s.name,
"domain": s.domain,
"url": s.url,
"pri": s.pri,
"is_active": s.is_active,
"cookie": s.cookie,
"downloader": s.downloader,
"proxy": s.proxy,
"timeout": s.timeout,
}
simplified_sites.append(simplified)
result_json = json.dumps(simplified_sites, ensure_ascii=False, indent=2)
return result_json
return "未找到相关站点"
except Exception as e:
logger.error(f"查询站点失败: {e}", exc_info=True)
return f"查询站点时发生错误: {str(e)}"

View File

@@ -0,0 +1,187 @@
"""查询订阅历史工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.db import AsyncSessionFactory
from app.db.models.subscribehistory import SubscribeHistory
from app.log import logger
from app.schemas.types import media_type_to_agent
PAGE_SIZE = 20
class QuerySubscribeHistoryInput(BaseModel):
"""查询订阅历史工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
media_type: Optional[str] = Field(
"all", description="Allowed values: movie, tv, all"
)
name: Optional[str] = Field(
None, description="Filter by media name (partial match, optional)"
)
page: Optional[int] = Field(
1,
description="Page number for pagination (default: 1, 20 items per page). Ignored when name filter is provided.",
)
class QuerySubscribeHistoryTool(MoviePilotTool):
name: str = "query_subscribe_history"
description: str = "Query subscription history records. Shows completed subscriptions with their details including name, type, rating, completion date, and other subscription information. Supports filtering by media type and name. Supports pagination with 20 records per page."
args_schema: Type[BaseModel] = QuerySubscribeHistoryInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
media_type = kwargs.get("media_type", "all")
name = kwargs.get("name")
page = kwargs.get("page", 1)
parts = ["正在查询订阅历史"]
if media_type != "all":
parts.append(f"类型: {media_type}")
if name:
parts.append(f"名称: {name}")
else:
parts.append(f"{page}")
return " | ".join(parts)
async def run(
self,
media_type: Optional[str] = "all",
name: Optional[str] = None,
page: Optional[int] = 1,
**kwargs,
) -> str:
page = max(1, page or 1)
logger.info(
f"执行工具: {self.name}, 参数: media_type={media_type}, name={name}, page={page}"
)
try:
if media_type not in ["all", "movie", "tv"]:
return f"错误:无效的媒体类型 '{media_type}',支持的类型:'movie', 'tv', 'all'"
# 获取数据库会话
async with AsyncSessionFactory() as db:
if name:
# 有名称过滤时,获取足够多的记录在内存中过滤,不分页
fetch_count = 500
if media_type == "all":
movie_history = await SubscribeHistory.async_list_by_type(
db, mtype="movie", page=1, count=fetch_count
)
tv_history = await SubscribeHistory.async_list_by_type(
db, mtype="tv", page=1, count=fetch_count
)
all_history = list(movie_history) + list(tv_history)
all_history.sort(key=lambda x: x.date or "", reverse=True)
else:
all_history = list(
await SubscribeHistory.async_list_by_type(
db, mtype=media_type, page=1, count=fetch_count
)
)
# 按名称过滤
name_lower = name.lower()
filtered_history = [
record
for record in all_history
if record.name and name_lower in record.name.lower()
]
if not filtered_history:
return "未找到相关订阅历史记录"
# 名称过滤时直接返回所有匹配结果,不分页
simplified_records = self._simplify_records(filtered_history)
result_json = json.dumps(
simplified_records, ensure_ascii=False, indent=2
)
return result_json
else:
# 无名称过滤时,直接利用数据库分页
if media_type == "all":
movie_history = await SubscribeHistory.async_list_by_type(
db, mtype="movie", page=1, count=page * PAGE_SIZE
)
tv_history = await SubscribeHistory.async_list_by_type(
db, mtype="tv", page=1, count=page * PAGE_SIZE
)
all_history = list(movie_history) + list(tv_history)
all_history.sort(key=lambda x: x.date or "", reverse=True)
filtered_history = all_history
else:
filtered_history = list(
await SubscribeHistory.async_list_by_type(
db, mtype=media_type, page=1, count=page * PAGE_SIZE
)
)
if not filtered_history:
return "未找到相关订阅历史记录"
# 分页切片
total_count = len(filtered_history)
start = (page - 1) * PAGE_SIZE
end = start + PAGE_SIZE
page_records = filtered_history[start:end]
if not page_records:
return f"{page} 页没有数据。"
simplified_records = self._simplify_records(page_records)
result_json = json.dumps(
simplified_records, ensure_ascii=False, indent=2
)
has_more = total_count > end
payload_msg = f"{page} 页,当前页 {len(simplified_records)} 条结果。"
if has_more:
payload_msg += (
f" 可能有更多数据,可使用 page={page + 1} 获取下一页。"
)
return f"{payload_msg}\n\n{result_json}"
except Exception as e:
logger.error(f"查询订阅历史失败: {e}", exc_info=True)
return f"查询订阅历史时发生错误: {str(e)}"
@staticmethod
def _simplify_records(records) -> list:
"""转换为字典格式,只保留关键信息"""
simplified_records = []
for record in records:
simplified = {
"id": record.id,
"name": record.name,
"year": record.year,
"type": media_type_to_agent(record.type),
"season": record.season,
"tmdbid": record.tmdbid,
"doubanid": record.doubanid,
"bangumiid": record.bangumiid,
"poster": record.poster,
"vote": record.vote,
"total_episode": record.total_episode,
"date": record.date,
"username": record.username,
}
if record.filter:
simplified["filter"] = record.filter
if record.quality:
simplified["quality"] = record.quality
if record.resolution:
simplified["resolution"] = record.resolution
simplified_records.append(simplified)
return simplified_records

View File

@@ -0,0 +1,112 @@
"""查询订阅分享工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.helper.subscribe import SubscribeHelper
from app.log import logger
class QuerySubscribeSharesInput(BaseModel):
"""查询订阅分享工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
name: Optional[str] = Field(None, description="Filter shares by media name (partial match, optional)")
page: Optional[int] = Field(1, description="Page number for pagination (default: 1)")
count: Optional[int] = Field(30, description="Number of items per page (default: 30)")
genre_id: Optional[int] = Field(None, description="Filter by genre ID (optional)")
min_rating: Optional[float] = Field(None, description="Minimum rating filter (optional, e.g., 7.5)")
max_rating: Optional[float] = Field(None, description="Maximum rating filter (optional, e.g., 10.0)")
sort_type: Optional[str] = Field(None, description="Sort type (optional, e.g., 'count', 'rating')")
class QuerySubscribeSharesTool(MoviePilotTool):
name: str = "query_subscribe_shares"
description: str = "Query shared subscriptions from other users. Shows popular subscriptions shared by the community with filtering and pagination support."
args_schema: Type[BaseModel] = QuerySubscribeSharesInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
name = kwargs.get("name")
page = kwargs.get("page", 1)
min_rating = kwargs.get("min_rating")
max_rating = kwargs.get("max_rating")
parts = ["正在查询订阅分享"]
if name:
parts.append(f"名称: {name}")
if min_rating:
parts.append(f"最低评分: {min_rating}")
if max_rating:
parts.append(f"最高评分: {max_rating}")
if page > 1:
parts.append(f"{page}")
return " | ".join(parts) if len(parts) > 1 else parts[0]
async def run(self, name: Optional[str] = None,
page: Optional[int] = 1,
count: Optional[int] = 30,
genre_id: Optional[int] = None,
min_rating: Optional[float] = None,
max_rating: Optional[float] = None,
sort_type: Optional[str] = None, **kwargs) -> str:
logger.info(
f"执行工具: {self.name}, 参数: name={name}, page={page}, count={count}, genre_id={genre_id}, "
f"min_rating={min_rating}, max_rating={max_rating}, sort_type={sort_type}")
try:
if page is None or page < 1:
page = 1
if count is None or count < 1:
count = 30
subscribe_helper = SubscribeHelper()
shares = await subscribe_helper.async_get_shares(
name=name,
page=page,
count=count,
genre_id=genre_id,
min_rating=min_rating,
max_rating=max_rating,
sort_type=sort_type
)
if not shares:
return "未找到订阅分享数据(可能订阅分享功能未启用)"
# 简化字段,只保留关键信息
simplified_shares = []
for share in shares:
simplified = {
"id": share.get("id"),
"name": share.get("name"),
"year": share.get("year"),
"type": share.get("type"),
"season": share.get("season"),
"tmdbid": share.get("tmdbid"),
"doubanid": share.get("doubanid"),
"bangumiid": share.get("bangumiid"),
"poster": share.get("poster"),
"vote": share.get("vote"),
"share_title": share.get("share_title"),
"share_comment": share.get("share_comment"),
"share_user": share.get("share_user"),
"fork_count": share.get("fork_count", 0)
}
# 截断过长的描述
if simplified.get("description") and len(simplified["description"]) > 200:
simplified["description"] = simplified["description"][:200] + "..."
simplified_shares.append(simplified)
result_json = json.dumps(simplified_shares, ensure_ascii=False, indent=2)
pagination_info = f"{page} 页,每页 {count} 条,共 {len(simplified_shares)} 条结果"
return f"{pagination_info}\n\n{result_json}"
except Exception as e:
logger.error(f"查询订阅分享失败: {e}", exc_info=True)
return f"查询订阅分享时发生错误: {str(e)}"

View File

@@ -0,0 +1,158 @@
"""查询订阅工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.db.subscribe_oper import SubscribeOper
from app.log import logger
from app.schemas.subscribe import Subscribe as SubscribeSchema
from app.schemas.types import MediaType
PAGE_SIZE = 100
QUERY_SUBSCRIBE_OUTPUT_FIELDS = [
"id",
"name",
"year",
"type",
"season",
"total_episode",
"start_episode",
"lack_episode",
"filter",
"include",
"exclude",
"quality",
"resolution",
"effect",
"state",
"last_update",
"sites",
"downloader",
"best_version",
"save_path",
"custom_words",
"media_category",
"filter_groups",
"episode_group",
]
class QuerySubscribesInput(BaseModel):
"""查询订阅工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
status: Optional[str] = Field(
"all",
description="Filter subscriptions by status: 'R' for enabled subscriptions, 'S' for paused ones, 'all' for all subscriptions",
)
media_type: Optional[str] = Field(
"all", description="Allowed values: movie, tv, all"
)
tmdb_id: Optional[int] = Field(
None,
description="Filter by TMDB ID to check if a specific media is already subscribed",
)
douban_id: Optional[str] = Field(
None,
description="Filter by Douban ID to check if a specific media is already subscribed",
)
page: Optional[int] = Field(
1, description="Page number for pagination (default: 1, 100 items per page)"
)
class QuerySubscribesTool(MoviePilotTool):
name: str = "query_subscribes"
description: str = "Query subscription status and list user subscriptions. Returns full subscription parameters for each matched subscription. Supports pagination with 100 items per page."
args_schema: Type[BaseModel] = QuerySubscribesInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
status = kwargs.get("status", "all")
media_type = kwargs.get("media_type", "all")
page = kwargs.get("page", 1)
parts = ["正在查询订阅"]
# 根据状态过滤条件生成提示
if status != "all":
status_map = {"R": "已启用", "S": "已暂停"}
parts.append(f"状态: {status_map.get(status, status)}")
# 根据媒体类型过滤条件生成提示
if media_type != "all":
parts.append(f"类型: {media_type}")
parts.append(f"{page}")
return " | ".join(parts)
async def run(
self,
status: Optional[str] = "all",
media_type: Optional[str] = "all",
tmdb_id: Optional[int] = None,
douban_id: Optional[str] = None,
page: Optional[int] = 1,
**kwargs,
) -> str:
page = max(1, page or 1)
logger.info(
f"执行工具: {self.name}, 参数: status={status}, media_type={media_type}, tmdb_id={tmdb_id}, douban_id={douban_id}, page={page}"
)
try:
if media_type != "all" and not MediaType.from_agent(media_type):
return f"错误:无效的媒体类型 '{media_type}',支持的类型:'movie', 'tv', 'all'"
subscribe_oper = SubscribeOper()
subscribes = await subscribe_oper.async_list()
filtered_subscribes = []
for sub in subscribes:
if status != "all" and sub.state != status:
continue
if (
media_type != "all"
and sub.type != MediaType.from_agent(media_type).value
):
continue
if tmdb_id is not None and sub.tmdbid != tmdb_id:
continue
if douban_id is not None and sub.doubanid != douban_id:
continue
filtered_subscribes.append(sub)
if filtered_subscribes:
total_count = len(filtered_subscribes)
# 分页
start = (page - 1) * PAGE_SIZE
end = start + PAGE_SIZE
page_subscribes = filtered_subscribes[start:end]
if not page_subscribes:
total_pages = (total_count + PAGE_SIZE - 1) // PAGE_SIZE
return f"{page} 页没有数据,共 {total_count} 条结果,共 {total_pages} 页。"
full_subscribes = [
SubscribeSchema.model_validate(s, from_attributes=True).model_dump(
include=set(QUERY_SUBSCRIBE_OUTPUT_FIELDS), exclude_none=True
)
for s in page_subscribes
]
result_json = json.dumps(full_subscribes, ensure_ascii=False, indent=2)
total_pages = (total_count + PAGE_SIZE - 1) // PAGE_SIZE
payload_msg = f"{page}/{total_pages} 页,当前页 {len(page_subscribes)} 条结果,共 {total_count} 条。"
if page < total_pages:
payload_msg += f" 可使用 page={page + 1} 获取下一页。"
return f"{payload_msg}\n\n{result_json}"
return "未找到相关订阅"
except Exception as e:
logger.error(f"查询订阅失败: {e}", exc_info=True)
return f"查询订阅时发生错误: {str(e)}"

View File

@@ -0,0 +1,134 @@
"""查询整理历史记录工具"""
import json
from typing import Optional, Type
import jieba
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.db import AsyncSessionFactory
from app.db.models.transferhistory import TransferHistory
from app.log import logger
from app.schemas.types import media_type_to_agent
class QueryTransferHistoryInput(BaseModel):
"""查询整理历史记录工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
title: Optional[str] = Field(None, description="Search by title (optional, supports partial match)")
status: Optional[str] = Field("all",
description="Filter by status: 'success' for successful transfers, 'failed' for failed transfers, 'all' for all records (default: 'all')")
page: Optional[int] = Field(1, description="Page number for pagination (default: 1, each page contains 30 records)")
class QueryTransferHistoryTool(MoviePilotTool):
name: str = "query_transfer_history"
description: str = "Query file transfer history records. Shows transfer status, source and destination paths, media information, and transfer details. Supports filtering by title and status."
args_schema: Type[BaseModel] = QueryTransferHistoryInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
title = kwargs.get("title")
status = kwargs.get("status", "all")
page = kwargs.get("page", 1)
parts = ["正在查询整理历史"]
if title:
parts.append(f"标题: {title}")
if status != "all":
status_map = {"success": "成功", "failed": "失败"}
parts.append(f"状态: {status_map.get(status, status)}")
if page > 1:
parts.append(f"{page}")
return " | ".join(parts) if len(parts) > 1 else parts[0]
async def run(self, title: Optional[str] = None,
status: Optional[str] = "all",
page: Optional[int] = 1, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: title={title}, status={status}, page={page}")
try:
# 处理状态参数
status_bool = None
if status == "success":
status_bool = True
elif status == "failed":
status_bool = False
# 处理页码参数
if page is None or page < 1:
page = 1
# 每页记录数
count = 50
# 获取数据库会话
async with AsyncSessionFactory() as db:
# 处理标题搜索
if title:
# 使用 jieba 分词处理标题
words = jieba.cut(title, HMM=False)
title_search = "%".join(words)
# 查询记录
result = await TransferHistory.async_list_by_title(
db, title=title_search, page=page, count=count, status=status_bool
)
total = await TransferHistory.async_count_by_title(
db, title=title_search, status=status_bool
)
else:
# 查询所有记录
result = await TransferHistory.async_list_by_page(
db, page=page, count=count, status=status_bool
)
total = await TransferHistory.async_count(db, status=status_bool)
if not result:
return "未找到相关整理历史记录"
# 转换为字典格式,只保留关键信息
simplified_records = []
for record in result:
simplified = {
"id": record.id,
"title": record.title,
"year": record.year,
"type": media_type_to_agent(record.type),
"category": record.category,
"seasons": record.seasons,
"episodes": record.episodes,
"src": record.src,
"dest": record.dest,
"mode": record.mode,
"status": "成功" if record.status else "失败",
"date": record.date,
"downloader": record.downloader,
"download_hash": record.download_hash
}
# 如果失败,添加错误信息
if not record.status and record.errmsg:
simplified["errmsg"] = record.errmsg
# 添加媒体ID信息如果有
if record.tmdbid:
simplified["tmdbid"] = record.tmdbid
if record.imdbid:
simplified["imdbid"] = record.imdbid
if record.doubanid:
simplified["doubanid"] = record.doubanid
simplified_records.append(simplified)
result_json = json.dumps(simplified_records, ensure_ascii=False, indent=2)
# 计算总页数
total_pages = (total + count - 1) // count if total > 0 else 1
# 构建分页信息
pagination_info = f"{page}/{total_pages} 页,共 {total} 条记录(每页 {count} 条)"
return f"{pagination_info}\n\n{result_json}"
except Exception as e:
logger.error(f"查询整理历史记录失败: {e}", exc_info=True)
return f"查询整理历史记录时发生错误: {str(e)}"

View File

@@ -0,0 +1,127 @@
"""查询工作流工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.db import AsyncSessionFactory
from app.db.workflow_oper import WorkflowOper
from app.log import logger
class QueryWorkflowsInput(BaseModel):
"""查询工作流工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
state: Optional[str] = Field("all", description="Filter workflows by state: 'W' for waiting, 'R' for running, 'P' for paused, 'S' for success, 'F' for failed, 'all' for all workflows (default: 'all')")
name: Optional[str] = Field(None, description="Filter workflows by name (partial match, optional)")
trigger_type: Optional[str] = Field("all", description="Filter workflows by trigger type: 'timer' for scheduled, 'event' for event-triggered, 'manual' for manual, 'all' for all types (default: 'all')")
class QueryWorkflowsTool(MoviePilotTool):
name: str = "query_workflows"
description: str = "Query workflow list and status. Shows workflow name, description, trigger type, state, execution count, and other workflow details. Supports filtering by state, name, and trigger type."
args_schema: Type[BaseModel] = QueryWorkflowsInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据查询参数生成友好的提示消息"""
state = kwargs.get("state", "all")
name = kwargs.get("name")
trigger_type = kwargs.get("trigger_type", "all")
parts = ["正在查询工作流"]
if state != "all":
state_map = {"W": "等待", "R": "运行中", "P": "暂停", "S": "成功", "F": "失败"}
parts.append(f"状态: {state_map.get(state, state)}")
if trigger_type != "all":
trigger_map = {"timer": "定时触发", "event": "事件触发", "manual": "手动触发"}
parts.append(f"触发类型: {trigger_map.get(trigger_type, trigger_type)}")
if name:
parts.append(f"名称: {name}")
return " | ".join(parts) if len(parts) > 1 else parts[0]
async def run(self, state: Optional[str] = "all",
name: Optional[str] = None,
trigger_type: Optional[str] = "all", **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: state={state}, name={name}, trigger_type={trigger_type}")
try:
# 获取数据库会话
async with AsyncSessionFactory() as db:
workflow_oper = WorkflowOper(db)
workflows = await workflow_oper.async_list()
# 过滤工作流
filtered_workflows = []
for wf in workflows:
# 按状态过滤
if state != "all" and wf.state != state:
continue
# 按触发类型过滤
if trigger_type != "all":
if trigger_type == "timer" and wf.trigger_type not in ["timer", None]:
continue
elif trigger_type == "event" and wf.trigger_type != "event":
continue
elif trigger_type == "manual" and wf.trigger_type != "manual":
continue
# 按名称过滤(部分匹配)
if name and wf.name and name.lower() not in wf.name.lower():
continue
filtered_workflows.append(wf)
if not filtered_workflows:
return "未找到相关工作流"
# 转换为字典格式,只保留关键信息
simplified_workflows = []
for wf in filtered_workflows:
# 状态说明
state_map = {
"W": "等待",
"R": "运行中",
"P": "暂停",
"S": "成功",
"F": "失败"
}
state_desc = state_map.get(wf.state, wf.state)
# 触发类型说明
trigger_type_map = {
"timer": "定时触发",
"event": "事件触发",
"manual": "手动触发"
}
trigger_type_desc = trigger_type_map.get(wf.trigger_type, wf.trigger_type or "定时触发")
simplified = {
"id": wf.id,
"name": wf.name,
"description": wf.description,
"trigger_type": trigger_type_desc,
"state": state_desc,
"run_count": wf.run_count,
"timer": wf.timer,
"event_type": wf.event_type,
"add_time": wf.add_time,
"last_time": wf.last_time,
"current_action": wf.current_action
}
# 如果有结果,添加结果信息
if wf.result:
simplified["result"] = wf.result
simplified_workflows.append(simplified)
result_json = json.dumps(simplified_workflows, ensure_ascii=False, indent=2)
return result_json
except Exception as e:
logger.error(f"查询工作流失败: {e}", exc_info=True)
return f"查询工作流时发生错误: {str(e)}"

View File

@@ -0,0 +1,81 @@
"""文件读取工具"""
from pathlib import Path
from typing import Optional, Type
from anyio import Path as AsyncPath
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.log import logger
# 最大读取大小 50KB
MAX_READ_SIZE = 50 * 1024
class ReadFileInput(BaseModel):
"""Input parameters for read file tool"""
file_path: str = Field(..., description="The absolute path of the file to read")
start_line: Optional[int] = Field(None, description="The starting line number (1-based, inclusive). If not provided, reading starts from the beginning of the file.")
end_line: Optional[int] = Field(None, description="The ending line number (1-based, inclusive). If not provided, reading goes until the end of the file.")
class ReadFileTool(MoviePilotTool):
name: str = "read_file"
description: str = "Read the content of a text file. Supports reading by line range. Each read is limited to 50KB; content exceeding this limit will be truncated."
args_schema: Type[BaseModel] = ReadFileInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据参数生成友好的提示消息"""
file_path = kwargs.get("file_path", "")
file_name = Path(file_path).name if file_path else "未知文件"
return f"正在读取文件: {file_name}"
async def run(self, file_path: str, start_line: Optional[int] = None,
end_line: Optional[int] = None, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: file_path={file_path}, start_line={start_line}, end_line={end_line}")
try:
path = AsyncPath(file_path)
if not await path.exists():
return f"错误:文件 {file_path} 不存在"
if not await path.is_file():
return f"错误:{file_path} 不是一个文件"
content = await path.read_text(encoding="utf-8")
truncated = False
if start_line is not None or end_line is not None:
lines = content.splitlines(keepends=True)
total_lines = len(lines)
# 将行号转换为索引1-based -> 0-based
s = (start_line - 1) if start_line and start_line >= 1 else 0
e = end_line if end_line and end_line >= 1 else total_lines
# 确保范围有效
s = max(0, min(s, total_lines))
e = max(s, min(e, total_lines))
content = "".join(lines[s:e])
# 检查大小限制
content_bytes = content.encode("utf-8")
if len(content_bytes) > MAX_READ_SIZE:
content = content_bytes[:MAX_READ_SIZE].decode("utf-8", errors="ignore")
truncated = True
if truncated:
return f"{content}\n\n[警告文件内容已超过50KB限制以上内容已被截断。请使用 start_line/end_line 参数分段读取。]"
return content
except PermissionError:
return f"错误:没有权限读取 {file_path}"
except UnicodeDecodeError:
return f"错误:{file_path} 不是文本文件,无法读取"
except Exception as e:
logger.error(f"读取文件 {file_path} 时发生错误: {str(e)}", exc_info=True)
return f"操作失败: {str(e)}"

View File

@@ -0,0 +1,163 @@
"""识别媒体信息工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.media import MediaChain
from app.core.context import Context
from app.core.metainfo import MetaInfo
from app.log import logger
from app.schemas.types import media_type_to_agent
class RecognizeMediaInput(BaseModel):
"""识别媒体信息工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
title: Optional[str] = Field(None, description="The title of the torrent/media to recognize (required for torrent recognition)")
subtitle: Optional[str] = Field(None, description="The subtitle or description of the torrent (optional, helps improve recognition accuracy)")
path: Optional[str] = Field(None, description="The file path to recognize (required for file recognition, mutually exclusive with title)")
class RecognizeMediaTool(MoviePilotTool):
name: str = "recognize_media"
description: str = "Extract/identify media information from torrent titles or file paths (NOT database search). Supports two modes: 1) Extract from torrent title and optional subtitle, 2) Extract from file path. Returns detailed media information. Use 'search_media' to search TMDB database, or 'scrape_metadata' to generate metadata files for existing files."
args_schema: Type[BaseModel] = RecognizeMediaInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据识别参数生成友好的提示消息"""
title = kwargs.get("title")
subtitle = kwargs.get("subtitle")
path = kwargs.get("path")
if path:
message = f"正在识别文件媒体信息: {path}"
elif title:
message = f"正在识别种子媒体信息: {title}"
if subtitle:
message += f" ({subtitle})"
else:
message = "正在识别媒体信息"
return message
async def run(self, title: Optional[str] = None, subtitle: Optional[str] = None,
path: Optional[str] = None, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: title={title}, subtitle={subtitle}, path={path}")
try:
media_chain = MediaChain()
context = None
# 根据提供的参数选择识别方式
if path:
# 文件路径识别
if not path:
return json.dumps({
"success": False,
"message": "文件路径不能为空"
}, ensure_ascii=False)
context = await media_chain.async_recognize_by_path(path)
if context:
return self._format_context_result(context, "文件")
else:
return json.dumps({
"success": False,
"message": f"无法识别文件媒体信息: {path}",
"path": path
}, ensure_ascii=False)
elif title:
# 种子标题识别
metainfo = MetaInfo(title, subtitle)
mediainfo = await media_chain.async_recognize_by_meta(metainfo)
if mediainfo:
context = Context(meta_info=metainfo, media_info=mediainfo)
return self._format_context_result(context, "种子")
else:
return json.dumps({
"success": False,
"message": f"无法识别种子媒体信息: {title}",
"title": title,
"subtitle": subtitle
}, ensure_ascii=False)
else:
return json.dumps({
"success": False,
"message": "必须提供 title标题或 path文件路径参数之一"
}, ensure_ascii=False)
except Exception as e:
error_message = f"识别媒体信息失败: {str(e)}"
logger.error(f"识别媒体信息失败: {e}", exc_info=True)
return json.dumps({
"success": False,
"message": error_message
}, ensure_ascii=False)
@staticmethod
def _format_context_result(context: Context, source_type: str) -> str:
"""格式化识别结果为JSON字符串"""
if not context:
return json.dumps({
"success": False,
"message": "识别结果为空"
}, ensure_ascii=False)
context_dict = context.to_dict()
media_info = context_dict.get("media_info")
meta_info = context_dict.get("meta_info")
# 构建简化的结果
result = {
"success": True,
"source_type": source_type,
"media_info": None,
"meta_info": None
}
# 处理媒体信息
if media_info:
result["media_info"] = {
"title": media_info.get("title"),
"en_title": media_info.get("en_title"),
"year": media_info.get("year"),
"type": media_type_to_agent(media_info.get("type")),
"season": media_info.get("season"),
"tmdb_id": media_info.get("tmdb_id"),
"imdb_id": media_info.get("imdb_id"),
"douban_id": media_info.get("douban_id"),
"bangumi_id": media_info.get("bangumi_id"),
"overview": media_info.get("overview"),
"vote_average": media_info.get("vote_average"),
"poster_path": media_info.get("poster_path"),
"backdrop_path": media_info.get("backdrop_path"),
"detail_link": media_info.get("detail_link"),
"title_year": media_info.get("title_year"),
"source": media_info.get("source")
}
# 处理元数据信息
if meta_info:
result["meta_info"] = {
"name": meta_info.get("name"),
"title": meta_info.get("title"),
"year": meta_info.get("year"),
"type": media_type_to_agent(meta_info.get("type")),
"begin_season": meta_info.get("begin_season"),
"end_season": meta_info.get("end_season"),
"begin_episode": meta_info.get("begin_episode"),
"end_episode": meta_info.get("end_episode"),
"total_episode": meta_info.get("total_episode"),
"part": meta_info.get("part"),
"season_episode": meta_info.get("season_episode"),
"episode_list": meta_info.get("episode_list"),
"tmdbid": meta_info.get("tmdbid"),
"doubanid": meta_info.get("doubanid")
}
return json.dumps(result, ensure_ascii=False, indent=2)

View File

@@ -0,0 +1,60 @@
"""运行定时服务工具"""
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.log import logger
from app.scheduler import Scheduler
class RunSchedulerInput(BaseModel):
"""运行定时服务工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
job_id: str = Field(
...,
description="The ID of the scheduled job to run (can be obtained from query_schedulers tool)",
)
class RunSchedulerTool(MoviePilotTool):
name: str = "run_scheduler"
description: str = "Manually trigger a scheduled task to run immediately. This will execute the specified scheduler job by its ID."
args_schema: Type[BaseModel] = RunSchedulerInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据运行参数生成友好的提示消息"""
job_id = kwargs.get("job_id", "")
return f"正在运行定时服务 (ID: {job_id})"
async def run(self, job_id: str, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: job_id={job_id}")
try:
scheduler = Scheduler()
# 检查定时服务是否存在
schedulers = scheduler.list()
job_exists = False
job_name = None
for s in schedulers:
if s.id == job_id:
job_exists = True
job_name = s.name
break
if not job_exists:
return f"定时服务 ID {job_id} 不存在,请使用 query_schedulers 工具查询可用的定时服务"
# 运行定时服务
scheduler.start(job_id)
return f"成功触发定时服务:{job_name} (ID: {job_id})"
except Exception as e:
logger.error(f"运行定时服务失败: {e}", exc_info=True)
return f"运行定时服务时发生错误: {str(e)}"

View File

@@ -0,0 +1,115 @@
"""运行斜杠命令工具(系统命令 + 插件命令)"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.core.event import eventmanager
from app.log import logger
from app.schemas.types import EventType, MessageChannel
class RunSlashCommandInput(BaseModel):
"""运行斜杠命令工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
command: str = Field(
...,
description="The slash command to execute, e.g. '/cookiecloud'. "
"Must start with '/'. Can include arguments after the command, e.g. '/command arg1 arg2'. "
"Use query_plugin_capabilities tool to discover available plugin commands, "
"or list_slash_commands tool to discover all available commands (including system commands).",
)
class RunSlashCommandTool(MoviePilotTool):
name: str = "run_slash_command"
description: str = (
"Execute a slash command (system or plugin) by sending a CommandExcute event. "
"This tool supports ALL registered slash commands, including: "
"1) System preset commands (e.g. /cookiecloud, /sites, /subscribes, /downloading, /transfer, /restart, etc.) "
"2) Plugin commands registered by installed plugins. "
"Use the query_plugin_capabilities tool to discover plugin commands, "
"or the list_slash_commands tool to discover all available commands. "
"The command will be executed asynchronously. "
"Note: This tool triggers the command execution but the actual processing happens in the background."
)
args_schema: Type[BaseModel] = RunSlashCommandInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""生成友好的提示消息"""
command = kwargs.get("command", "")
return f"正在执行命令: {command}"
async def run(self, command: str, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: command={command}")
try:
# 确保命令以 / 开头
if not command.startswith("/"):
command = f"/{command}"
# 从全局 Command 单例中验证命令是否存在(包含系统预设命令 + 插件命令 + 其他命令)
from app.command import Command
cmd_name = command.split()[0]
command_obj = Command()
matched_command = command_obj.get(cmd_name)
if not matched_command:
# 列出所有可用命令帮助用户
all_commands = command_obj.get_commands()
available_cmds = [
f"{cmd} - {info.get('description', '无描述')}"
for cmd, info in all_commands.items()
]
result = {
"success": False,
"message": f"命令 {cmd_name} 不存在",
}
if available_cmds:
result["available_commands"] = available_cmds
return json.dumps(result, ensure_ascii=False, indent=2)
# 构建消息渠道,优先使用当前会话的渠道信息
channel = None
if self._channel:
try:
channel = MessageChannel(self._channel)
except (ValueError, KeyError):
channel = None
# 发送命令执行事件,与 message.py 中的方式一致
eventmanager.send_event(
EventType.CommandExcute,
{
"cmd": command,
"user": self._user_id,
"channel": channel,
"source": self._source,
},
)
result = {
"success": True,
"message": f"命令 {cmd_name} 已触发执行",
"command": command,
"command_desc": matched_command.get("description", ""),
}
# 如果是插件命令附加插件ID
if matched_command.get("pid"):
result["plugin_id"] = matched_command["pid"]
return json.dumps(result, ensure_ascii=False, indent=2)
except Exception as e:
logger.error(f"执行命令失败: {e}", exc_info=True)
return json.dumps(
{"success": False, "message": f"执行命令时发生错误: {str(e)}"},
ensure_ascii=False,
)

View File

@@ -0,0 +1,77 @@
"""执行工作流工具"""
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.workflow import WorkflowChain
from app.db import AsyncSessionFactory
from app.db.workflow_oper import WorkflowOper
from app.log import logger
class RunWorkflowInput(BaseModel):
"""执行工作流工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
workflow_id: int = Field(
..., description="Workflow ID (can be obtained from query_workflows tool)"
)
from_begin: Optional[bool] = Field(
True,
description="Whether to run workflow from the beginning (default: True, if False will continue from last executed action)",
)
class RunWorkflowTool(MoviePilotTool):
name: str = "run_workflow"
description: str = "Execute a specific workflow manually by workflow ID. Supports running from the beginning or continuing from the last executed action."
args_schema: Type[BaseModel] = RunWorkflowInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据工作流参数生成友好的提示消息"""
workflow_id = kwargs.get("workflow_id")
from_begin = kwargs.get("from_begin", True)
message = f"正在执行工作流: {workflow_id}"
if not from_begin:
message += " (从上次位置继续)"
else:
message += " (从头开始)"
return message
async def run(
self, workflow_id: int, from_begin: Optional[bool] = True, **kwargs
) -> str:
logger.info(
f"执行工具: {self.name}, 参数: workflow_id={workflow_id}, from_begin={from_begin}"
)
try:
# 获取数据库会话
async with AsyncSessionFactory() as db:
workflow_oper = WorkflowOper(db)
workflow = await workflow_oper.async_get(workflow_id)
if not workflow:
return f"未找到工作流:{workflow_id},请使用 query_workflows 工具查询可用的工作流"
# 执行工作流
workflow_chain = WorkflowChain()
state, errmsg = workflow_chain.process(
workflow.id, from_begin=from_begin
)
if not state:
return f"执行工作流失败:{workflow.name} (ID: {workflow.id})\n错误原因:{errmsg}"
else:
return f"工作流执行成功:{workflow.name} (ID: {workflow.id})"
except Exception as e:
logger.error(f"执行工作流失败: {e}", exc_info=True)
return f"执行工作流时发生错误: {str(e)}"

View File

@@ -0,0 +1,141 @@
"""刮削媒体元数据工具"""
import json
from pathlib import Path
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.media import MediaChain
from app.core.config import global_vars
from app.core.metainfo import MetaInfoPath
from app.log import logger
from app.schemas import FileItem
class ScrapeMetadataInput(BaseModel):
"""刮削媒体元数据工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
path: str = Field(
...,
description="Path to the file or directory to scrape metadata for (e.g., '/path/to/file.mkv' or '/path/to/directory')",
)
storage: Optional[str] = Field(
"local",
description="Storage type: 'local' for local storage, 'smb', 'alist', etc. for remote storage (default: 'local')",
)
overwrite: Optional[bool] = Field(
False,
description="Whether to overwrite existing metadata files (default: False)",
)
class ScrapeMetadataTool(MoviePilotTool):
name: str = "scrape_metadata"
description: str = "Generate metadata files (NFO files, posters, backgrounds, etc.) for existing media files or directories. Automatically recognizes media information from the file path and creates metadata files. Supports both local and remote storage. Use 'search_media' to search TMDB database, or 'recognize_media' to extract info from torrent titles/file paths without generating files."
require_admin: bool = True
args_schema: Type[BaseModel] = ScrapeMetadataInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据刮削参数生成友好的提示消息"""
path = kwargs.get("path", "")
storage = kwargs.get("storage", "local")
overwrite = kwargs.get("overwrite", False)
message = f"正在刮削媒体元数据: {path}"
if storage != "local":
message += f" [存储: {storage}]"
if overwrite:
message += " [覆盖模式]"
return message
async def run(
self,
path: str,
storage: Optional[str] = "local",
overwrite: Optional[bool] = False,
**kwargs,
) -> str:
logger.info(
f"执行工具: {self.name}, 参数: path={path}, storage={storage}, overwrite={overwrite}"
)
try:
# 验证路径
if not path:
return json.dumps(
{"success": False, "message": "刮削路径不能为空"},
ensure_ascii=False,
)
# 创建 FileItem
fileitem = FileItem(
storage=storage, path=path, type="file" if Path(path).suffix else "dir"
)
# 检查本地存储路径是否存在
if storage == "local":
scrape_path = Path(path)
if not scrape_path.exists():
return json.dumps(
{"success": False, "message": f"刮削路径不存在: {path}"},
ensure_ascii=False,
)
# 识别媒体信息
media_chain = MediaChain()
scrape_path = Path(path)
meta = MetaInfoPath(scrape_path)
mediainfo = await media_chain.async_recognize_by_meta(meta)
if not mediainfo:
return json.dumps(
{
"success": False,
"message": f"刮削失败,无法识别媒体信息: {path}",
"path": path,
},
ensure_ascii=False,
)
# 在线程池中执行同步的刮削操作
await global_vars.loop.run_in_executor(
None,
lambda: media_chain.scrape_metadata(
fileitem=fileitem,
meta=meta,
mediainfo=mediainfo,
overwrite=overwrite,
),
)
return json.dumps(
{
"success": True,
"message": f"{path} 刮削完成",
"path": path,
"media_info": {
"title": mediainfo.title,
"year": mediainfo.year,
"type": mediainfo.type.value if mediainfo.type else None,
"tmdb_id": mediainfo.tmdb_id,
"season": mediainfo.season,
},
},
ensure_ascii=False,
indent=2,
)
except Exception as e:
error_message = f"刮削媒体元数据失败: {str(e)}"
logger.error(f"刮削媒体元数据失败: {e}", exc_info=True)
return json.dumps(
{"success": False, "message": error_message, "path": path},
ensure_ascii=False,
)

View File

@@ -0,0 +1,109 @@
"""搜索媒体工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.media import MediaChain
from app.log import logger
from app.schemas.types import MediaType, media_type_to_agent
class SearchMediaInput(BaseModel):
"""搜索媒体工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
title: str = Field(..., description="The title of the media to search for (e.g., 'The Matrix', 'Breaking Bad')")
year: Optional[str] = Field(None, description="Release year of the media (optional, helps narrow down results)")
media_type: Optional[str] = Field(None,
description="Allowed values: movie, tv")
season: Optional[int] = Field(None,
description="Season number for TV shows and anime (optional, only applicable for series)")
class SearchMediaTool(MoviePilotTool):
name: str = "search_media"
description: str = "Search TMDB database for media resources (movies, TV shows, anime, etc.) by title, year, type, and other criteria. Returns detailed media information from TMDB. Use 'recognize_media' to extract info from torrent titles/file paths, or 'scrape_metadata' to generate metadata files."
args_schema: Type[BaseModel] = SearchMediaInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据搜索参数生成友好的提示消息"""
title = kwargs.get("title", "")
year = kwargs.get("year")
media_type = kwargs.get("media_type")
season = kwargs.get("season")
message = f"正在搜索媒体: {title}"
if year:
message += f" ({year})"
if media_type:
message += f" [{media_type}]"
if season:
message += f"{season}"
return message
async def run(self, title: str, year: Optional[str] = None,
media_type: Optional[str] = None, season: Optional[int] = None, **kwargs) -> str:
logger.info(
f"执行工具: {self.name}, 参数: title={title}, year={year}, media_type={media_type}, season={season}")
try:
media_chain = MediaChain()
# 使用 MediaChain.search 方法
meta, results = await media_chain.async_search(title=title)
# 过滤结果
if results:
media_type_enum = None
if media_type:
media_type_enum = MediaType.from_agent(media_type)
if not media_type_enum:
return f"错误:无效的媒体类型 '{media_type}',支持的类型:'movie', 'tv'"
filtered_results = []
for result in results:
if year and result.year != year:
continue
if media_type_enum and result.type != media_type_enum:
continue
if season is not None and result.season != season:
continue
filtered_results.append(result)
if filtered_results:
# 限制最多30条结果
total_count = len(filtered_results)
limited_results = filtered_results[:30]
# 精简字段,只保留关键信息
simplified_results = []
for r in limited_results:
simplified = {
"title": r.title,
"en_title": r.en_title,
"year": r.year,
"type": media_type_to_agent(r.type),
"season": r.season,
"tmdb_id": r.tmdb_id,
"imdb_id": r.imdb_id,
"douban_id": r.douban_id,
"overview": r.overview[:200] + "..." if r.overview and len(r.overview) > 200 else r.overview,
"vote_average": r.vote_average,
"poster_path": r.poster_path,
"detail_link": r.detail_link
}
simplified_results.append(simplified)
result_json = json.dumps(simplified_results, ensure_ascii=False, indent=2)
# 如果结果被裁剪,添加提示信息
if total_count > 100:
return f"注意:搜索结果共找到 {total_count} 条,为节省上下文空间,仅显示前 100 条结果。\n\n{result_json}"
return result_json
else:
return f"未找到符合条件的媒体资源: {title}"
else:
return f"未找到相关媒体资源: {title}"
except Exception as e:
error_message = f"搜索媒体失败: {str(e)}"
logger.error(f"搜索媒体失败: {e}", exc_info=True)
return error_message

View File

@@ -0,0 +1,83 @@
"""搜索人物工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.media import MediaChain
from app.log import logger
class SearchPersonInput(BaseModel):
"""搜索人物工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
name: str = Field(..., description="The name of the person to search for (e.g., 'Tom Hanks', '周杰伦')")
class SearchPersonTool(MoviePilotTool):
name: str = "search_person"
description: str = "Search for person information including actors, directors, etc. Supports searching by name. Returns detailed person information from TMDB, Douban, or Bangumi database."
args_schema: Type[BaseModel] = SearchPersonInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据搜索参数生成友好的提示消息"""
name = kwargs.get("name", "")
return f"正在搜索人物: {name}"
async def run(self, name: str, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: name={name}")
try:
media_chain = MediaChain()
# 使用 MediaChain.async_search_persons 方法搜索人物
persons = await media_chain.async_search_persons(name=name)
if persons:
# 限制最多30条结果
total_count = len(persons)
limited_persons = persons[:30]
# 精简字段,只保留关键信息
simplified_results = []
for person in limited_persons:
simplified = {
"name": person.name,
"id": person.id,
"source": person.source,
"profile_path": person.profile_path,
"original_name": person.original_name,
"known_for_department": person.known_for_department,
"popularity": person.popularity,
"biography": person.biography[:200] + "..." if person.biography and len(person.biography) > 200 else person.biography,
"birthday": person.birthday,
"deathday": person.deathday,
"place_of_birth": person.place_of_birth,
"gender": person.gender,
"imdb_id": person.imdb_id,
"also_known_as": person.also_known_as[:5] if person.also_known_as else [], # 限制别名数量
}
# 添加豆瓣特有字段
if person.source == "douban":
simplified["url"] = person.url
simplified["avatar"] = person.avatar
simplified["latin_name"] = person.latin_name
simplified["roles"] = person.roles[:5] if person.roles else [] # 限制角色数量
# 添加Bangumi特有字段
if person.source == "bangumi":
simplified["career"] = person.career
simplified["relation"] = person.relation
simplified_results.append(simplified)
result_json = json.dumps(simplified_results, ensure_ascii=False, indent=2)
# 如果结果被裁剪,添加提示信息
if total_count > 50:
return f"注意:搜索结果共找到 {total_count} 条,为节省上下文空间,仅显示前 50 条结果。\n\n{result_json}"
return result_json
else:
return f"未找到相关人物信息: {name}"
except Exception as e:
error_message = f"搜索人物失败: {str(e)}"
logger.error(f"搜索人物失败: {e}", exc_info=True)
return error_message

View File

@@ -0,0 +1,85 @@
"""搜索演员参演作品工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.douban import DoubanChain
from app.chain.tmdb import TmdbChain
from app.chain.bangumi import BangumiChain
from app.log import logger
class SearchPersonCreditsInput(BaseModel):
"""搜索演员参演作品工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
person_id: int = Field(..., description="The ID of the person/actor to search for credits (e.g., 31 for Tom Hanks in TMDB)")
source: str = Field(..., description="The data source: 'tmdb' for TheMovieDB, 'douban' for Douban, 'bangumi' for Bangumi")
page: Optional[int] = Field(1, description="Page number for pagination (default: 1)")
class SearchPersonCreditsTool(MoviePilotTool):
name: str = "search_person_credits"
description: str = "Search for films and TV shows that a person/actor has appeared in (filmography). Supports searching by person ID from TMDB, Douban, or Bangumi database. Returns a list of media works the person has participated in."
args_schema: Type[BaseModel] = SearchPersonCreditsInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据搜索参数生成友好的提示消息"""
person_id = kwargs.get("person_id", "")
source = kwargs.get("source", "")
return f"正在搜索人物参演作品: {source} ID {person_id}"
async def run(self, person_id: int, source: str, page: Optional[int] = 1, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: person_id={person_id}, source={source}, page={page}")
try:
# 根据source选择相应的chain
if source.lower() == "tmdb":
tmdb_chain = TmdbChain()
medias = await tmdb_chain.async_person_credits(person_id=person_id, page=page)
elif source.lower() == "douban":
douban_chain = DoubanChain()
medias = await douban_chain.async_person_credits(person_id=person_id, page=page)
elif source.lower() == "bangumi":
bangumi_chain = BangumiChain()
medias = await bangumi_chain.async_person_credits(person_id=person_id)
else:
return f"不支持的数据源: {source}。支持的数据源: tmdb, douban, bangumi"
if medias:
# 限制最多30条结果
total_count = len(medias)
limited_medias = medias[:30]
# 精简字段,只保留关键信息
simplified_results = []
for media in limited_medias:
simplified = {
"title": media.title,
"en_title": media.en_title,
"year": media.year,
"type": media.type.value if media.type else None,
"season": media.season,
"tmdb_id": media.tmdb_id,
"imdb_id": media.imdb_id,
"douban_id": media.douban_id,
"overview": media.overview[:200] + "..." if media.overview and len(media.overview) > 200 else media.overview,
"vote_average": media.vote_average,
"poster_path": media.poster_path,
"backdrop_path": media.backdrop_path,
"detail_link": media.detail_link
}
simplified_results.append(simplified)
result_json = json.dumps(simplified_results, ensure_ascii=False, indent=2)
# 如果结果被裁剪,添加提示信息
if total_count > 30:
return f"注意:搜索结果共找到 {total_count} 条,为节省上下文空间,仅显示前 30 条结果。\n\n{result_json}"
return result_json
else:
return f"未找到人物 ID {person_id} ({source}) 的参演作品"
except Exception as e:
error_message = f"搜索演员参演作品失败: {str(e)}"
logger.error(f"搜索演员参演作品失败: {e}", exc_info=True)
return error_message

View File

@@ -0,0 +1,128 @@
"""搜索订阅缺失剧集工具"""
import json
from typing import Optional, Type, List
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.subscribe import SubscribeChain
from app.core.config import global_vars
from app.db.subscribe_oper import SubscribeOper
from app.log import logger
from app.schemas.types import media_type_to_agent
class SearchSubscribeInput(BaseModel):
"""搜索订阅缺失剧集工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
subscribe_id: int = Field(..., description="The ID of the subscription to search for missing episodes (can be obtained from query_subscribes tool)")
manual: Optional[bool] = Field(False, description="Whether this is a manual search (default: False)")
filter_groups: Optional[List[str]] = Field(None,
description="List of filter rule group names to apply for this search (optional, can be obtained from query_rule_groups tool. If provided, will temporarily update the subscription's filter groups before searching)")
class SearchSubscribeTool(MoviePilotTool):
name: str = "search_subscribe"
description: str = "Search for missing episodes/resources for a specific subscription. This tool will search torrent sites for the missing episodes of the subscription and automatically download matching resources. Use this when a user wants to search for missing episodes of a specific subscription."
args_schema: Type[BaseModel] = SearchSubscribeInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据搜索参数生成友好的提示消息"""
subscribe_id = kwargs.get("subscribe_id")
manual = kwargs.get("manual", False)
message = f"正在搜索订阅 #{subscribe_id} 的缺失剧集"
if manual:
message += "(手动搜索)"
return message
async def run(self, subscribe_id: int, manual: Optional[bool] = False,
filter_groups: Optional[List[str]] = None, **kwargs) -> str:
logger.info(
f"执行工具: {self.name}, 参数: subscribe_id={subscribe_id}, manual={manual}, filter_groups={filter_groups}")
try:
# 先验证订阅是否存在
subscribe_oper = SubscribeOper()
subscribe = subscribe_oper.get(subscribe_id)
if not subscribe:
return json.dumps({
"success": False,
"message": f"订阅不存在: {subscribe_id}"
}, ensure_ascii=False)
# 获取订阅信息用于返回
subscribe_info = {
"id": subscribe.id,
"name": subscribe.name,
"year": subscribe.year,
"type": media_type_to_agent(subscribe.type),
"season": subscribe.season,
"state": subscribe.state,
"total_episode": subscribe.total_episode,
"lack_episode": subscribe.lack_episode,
"tmdbid": subscribe.tmdbid,
"doubanid": subscribe.doubanid
}
# 检查订阅状态
if subscribe.state == "S":
return json.dumps({
"success": False,
"message": f"订阅 #{subscribe_id} ({subscribe.name}) 已暂停,无法搜索",
"subscribe": subscribe_info
}, ensure_ascii=False)
# 如果提供了 filter_groups 参数,先更新订阅的规则组
if filter_groups is not None:
subscribe_oper.update(subscribe_id, {"filter_groups": filter_groups})
logger.info(f"更新订阅 #{subscribe_id} 的规则组为: {filter_groups}")
# 调用 SubscribeChain 的 search 方法
# search 方法是同步的,需要在异步环境中运行
subscribe_chain = SubscribeChain()
# 在线程池中执行同步的搜索操作
# 当 sid 有值时state 参数会被忽略,直接处理该订阅
await global_vars.loop.run_in_executor(
None,
lambda: subscribe_chain.search(
sid=subscribe_id,
state='R', # 默认状态,当 sid 有值时此参数会被忽略
manual=manual
)
)
# 重新获取订阅信息以获取更新后的状态
updated_subscribe = subscribe_oper.get(subscribe_id)
if updated_subscribe:
subscribe_info.update({
"state": updated_subscribe.state,
"lack_episode": updated_subscribe.lack_episode,
"last_update": updated_subscribe.last_update,
"filter_groups": updated_subscribe.filter_groups
})
# 如果提供了规则组,会在返回信息中显示
result = {
"success": True,
"message": f"订阅 #{subscribe_id} ({subscribe.name}) 搜索完成",
"subscribe": subscribe_info
}
if filter_groups is not None:
result["message"] += f"(已应用规则组: {', '.join(filter_groups)}"
return json.dumps(result, ensure_ascii=False, indent=2)
except Exception as e:
error_message = f"搜索订阅缺失剧集失败: {str(e)}"
logger.error(f"搜索订阅缺失剧集失败: {e}", exc_info=True)
return json.dumps({
"success": False,
"message": error_message,
"subscribe_id": subscribe_id
}, ensure_ascii=False)

View File

@@ -0,0 +1,110 @@
"""搜索种子工具"""
import json
from typing import List, Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.search import SearchChain
from app.db.systemconfig_oper import SystemConfigOper
from app.helper.sites import SitesHelper
from app.log import logger
from app.schemas.types import MediaType, SystemConfigKey
from ._torrent_search_utils import (
SEARCH_RESULT_CACHE_FILE,
build_filter_options,
)
class SearchTorrentsInput(BaseModel):
"""搜索种子工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
tmdb_id: Optional[int] = Field(None, description="TMDB ID (can be obtained from search_media tool). Either tmdb_id or douban_id must be provided.")
douban_id: Optional[str] = Field(None, description="Douban ID (can be obtained from search_media tool). Either tmdb_id or douban_id must be provided.")
media_type: Optional[str] = Field(None, description="Allowed values: movie, tv")
area: Optional[str] = Field(None, description="Search scope: 'title' (default) or 'imdbid'")
sites: Optional[List[int]] = Field(None,
description="Array of specific site IDs to search on (optional, if not provided searches all configured sites)")
class SearchTorrentsTool(MoviePilotTool):
name: str = "search_torrents"
description: str = ("Search for torrent files by media ID across configured indexer sites, cache the matched results, "
"and return available filter options for follow-up selection. "
"Requires tmdb_id or douban_id (can be obtained from search_media tool) for accurate matching.")
args_schema: Type[BaseModel] = SearchTorrentsInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据搜索参数生成友好的提示消息"""
tmdb_id = kwargs.get("tmdb_id")
douban_id = kwargs.get("douban_id")
media_type = kwargs.get("media_type")
if tmdb_id:
message = f"正在搜索种子: TMDB={tmdb_id}"
elif douban_id:
message = f"正在搜索种子: 豆瓣={douban_id}"
else:
message = "正在搜索种子"
if media_type:
message += f" [{media_type}]"
return message
async def run(self, tmdb_id: Optional[int] = None, douban_id: Optional[str] = None,
media_type: Optional[str] = None, area: Optional[str] = None,
sites: Optional[List[int]] = None, **kwargs) -> str:
logger.info(
f"执行工具: {self.name}, 参数: tmdb_id={tmdb_id}, douban_id={douban_id}, media_type={media_type}, area={area}, sites={sites}")
if not tmdb_id and not douban_id:
return "参数错误tmdb_id 和 douban_id 至少需要提供一个,请先使用 search_media 工具获取媒体 ID。"
try:
search_chain = SearchChain()
media_type_enum = None
if media_type:
media_type_enum = MediaType.from_agent(media_type)
if not media_type_enum:
return f"错误:无效的媒体类型 '{media_type}',支持的类型:'movie', 'tv'"
filtered_torrents = await search_chain.async_search_by_id(
tmdbid=tmdb_id,
doubanid=douban_id,
mtype=media_type_enum,
area=area or "title",
sites=sites,
cache_local=False,
)
# 获取站点信息
all_indexers = await SitesHelper().async_get_indexers()
all_sites = [{"id": indexer.get("id"), "name": indexer.get("name")} for indexer in (all_indexers or [])]
if sites:
search_site_ids = sites
else:
configured_sites = SystemConfigOper().get(SystemConfigKey.IndexerSites)
search_site_ids = configured_sites if configured_sites else []
if filtered_torrents:
await search_chain.async_save_cache(filtered_torrents, SEARCH_RESULT_CACHE_FILE)
result_json = json.dumps({
"total_count": len(filtered_torrents),
"message": "搜索完成。请使用 get_search_results 工具获取搜索结果。",
"all_sites": all_sites,
"search_site_ids": search_site_ids,
"filter_options": build_filter_options(filtered_torrents),
}, ensure_ascii=False, indent=2)
return result_json
else:
media_id = f"TMDB={tmdb_id}" if tmdb_id else f"豆瓣={douban_id}"
result_json = json.dumps({
"message": f"未找到相关种子资源: {media_id}",
"all_sites": all_sites,
"search_site_ids": search_site_ids,
}, ensure_ascii=False, indent=2)
return result_json
except Exception as e:
error_message = f"搜索种子时发生错误: {str(e)}"
logger.error(f"搜索种子失败: {e}", exc_info=True)
return error_message

View File

@@ -0,0 +1,239 @@
import asyncio
import json
import random
import re
from typing import Optional, Type, List, Dict
import httpx
from ddgs import DDGS
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.core.config import settings
from app.log import logger
# 搜索超时时间(秒)
SEARCH_TIMEOUT = 20
class SearchWebInput(BaseModel):
"""搜索网络内容工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
query: str = Field(
..., description="The search query string to search for on the web"
)
max_results: Optional[int] = Field(
20,
description="Maximum number of search results to return (default: 5, max: 10)",
)
class SearchWebTool(MoviePilotTool):
name: str = "search_web"
description: str = "Search the web for information when you need to find current information, facts, or references that you're uncertain about. Returns search results with titles, snippets, and URLs. Use this tool to get up-to-date information from the internet."
args_schema: Type[BaseModel] = SearchWebInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据搜索参数生成友好的提示消息"""
query = kwargs.get("query", "")
max_results = kwargs.get("max_results", 20)
return f"正在搜索网络内容: {query} (最多返回 {max_results} 条结果)"
async def run(self, query: str, max_results: Optional[int] = 20, **kwargs) -> str:
"""
执行网络搜索
"""
logger.info(
f"执行工具: {self.name}, 参数: query={query}, max_results={max_results}"
)
try:
# 限制最大结果数
max_results = min(max(1, max_results or 20), 20)
results = []
# 1. 优先使用 Exa (如果配置了 API Key)
if settings.EXA_API_KEY:
logger.info("使用 Exa 进行搜索...")
results = await self._search_exa(query, max_results)
# 2. 如果没有结果或未配置 Exa使用 Tavily (如果配置了 API Key)
if not results and settings.TAVILY_API_KEY:
logger.info("使用 Tavily 进行搜索...")
results = await self._search_tavily(query, max_results)
# 3. 如果没有结果或未配置 Tavily使用 DuckDuckGo
if not results:
logger.info("使用 DuckDuckGo 进行搜索...")
results = await self._search_duckduckgo(query, max_results)
if not results:
return f"未找到与 '{query}' 相关的搜索结果"
# 格式化并裁剪结果
formatted_results = self._format_and_truncate_results(results, max_results)
return json.dumps(formatted_results, ensure_ascii=False, indent=2)
except Exception as e:
error_message = f"搜索网络内容失败: {str(e)}"
logger.error(f"搜索网络内容失败: {e}", exc_info=True)
return error_message
@staticmethod
async def _search_tavily(query: str, max_results: int) -> List[Dict]:
"""使用 Tavily API 进行搜索"""
try:
async with httpx.AsyncClient(timeout=SEARCH_TIMEOUT) as client:
# 从设置中随机选择一个 API Key如果有多个
tavity_api_key = random.choice(settings.TAVILY_API_KEY)
response = await client.post(
"https://api.tavily.com/search",
json={
"api_key": tavity_api_key,
"query": query,
"search_depth": "basic",
"max_results": max_results,
"include_answer": False,
"include_images": False,
"include_raw_content": False,
},
)
response.raise_for_status()
data = response.json()
results = []
for result in data.get("results", []):
results.append(
{
"title": result.get("title", ""),
"snippet": result.get("content", ""),
"url": result.get("url", ""),
"source": "Tavily",
}
)
return results
except Exception as e:
logger.warning(f"Tavily 搜索失败: {e}")
return []
@staticmethod
async def _search_exa(query: str, max_results: int) -> List[Dict]:
"""使用 Exa API 进行搜索"""
try:
async with httpx.AsyncClient(timeout=SEARCH_TIMEOUT) as client:
response = await client.post(
"https://api.exa.ai/search",
headers={
"x-api-key": settings.EXA_API_KEY,
"Content-Type": "application/json",
},
json={
"query": query,
"numResults": max_results,
"type": "auto",
"contents": {"highlights": {"maxCharacters": 2000}},
},
)
response.raise_for_status()
data = response.json()
results = []
for result in data.get("results", []):
highlights = result.get("highlights", [])
snippet = (
highlights[0] if highlights else result.get("text", "")[:500]
)
results.append(
{
"title": result.get("title", ""),
"snippet": snippet,
"url": result.get("url", ""),
"source": "Exa",
}
)
return results
except Exception as e:
logger.warning(f"Exa 搜索失败: {e}")
return []
@staticmethod
def _get_proxy_url(proxy_setting) -> Optional[str]:
"""从代理设置中提取代理URL"""
if not proxy_setting:
return None
if isinstance(proxy_setting, dict):
return proxy_setting.get("http") or proxy_setting.get("https")
return proxy_setting
async def _search_duckduckgo(self, query: str, max_results: int) -> List[Dict]:
"""使用 duckduckgo-search (DDGS) 进行搜索"""
try:
def sync_search():
results = []
ddgs_kwargs = {"timeout": SEARCH_TIMEOUT}
proxy_url = self._get_proxy_url(settings.PROXY)
if proxy_url:
ddgs_kwargs["proxy"] = proxy_url
try:
with DDGS(**ddgs_kwargs) as ddgs:
ddgs_gen = ddgs.text(query, max_results=max_results)
if ddgs_gen:
for result in ddgs_gen:
results.append(
{
"title": result.get("title", ""),
"snippet": result.get("body", ""),
"url": result.get("href", ""),
"source": "DuckDuckGo",
}
)
except Exception as err:
logger.warning(f"DuckDuckGo search process failed: {err}")
return results
loop = asyncio.get_running_loop()
return await loop.run_in_executor(None, sync_search)
except Exception as e:
logger.warning(f"DuckDuckGo 搜索失败: {e}")
return []
@staticmethod
def _format_and_truncate_results(results: List[Dict], max_results: int) -> Dict:
"""格式化并裁剪搜索结果"""
formatted = {"total_results": len(results), "results": []}
for idx, result in enumerate(results[:max_results], 1):
title = result.get("title", "")[:200]
snippet = result.get("snippet", "")
url = result.get("url", "")
source = result.get("source", "Unknown")
# 裁剪摘要
max_snippet_length = 1000 # 增加到1000字符提供更多上下文
if len(snippet) > max_snippet_length:
snippet = snippet[:max_snippet_length] + "..."
# 清理文本
snippet = re.sub(r"\s+", " ", snippet).strip()
formatted["results"].append(
{
"rank": idx,
"title": title,
"snippet": snippet,
"url": url,
"source": source,
}
)
if len(results) > max_results:
formatted["note"] = f"仅显示前 {max_results} 条结果。"
return formatted

View File

@@ -0,0 +1,107 @@
"""发送本地附件工具。"""
from pathlib import Path
from typing import Optional, Type
from pydantic import BaseModel, Field, model_validator
from app.agent.tools.base import MoviePilotTool, ToolChain
from app.log import logger
from app.schemas import Notification, NotificationType
from app.schemas.message import ChannelCapabilityManager, ChannelCapability
from app.schemas.types import MessageChannel
class SendLocalFileInput(BaseModel):
"""发送本地附件工具输入。"""
explanation: str = Field(
...,
description="Clear explanation of why sending this local file helps the user",
)
file_path: str = Field(
...,
description="Absolute path to the local image or file to send to the user",
)
message: Optional[str] = Field(
None,
description="Optional message or caption to send with the attachment",
)
title: Optional[str] = Field(
None,
description="Optional short title shown together with the attachment",
)
file_name: Optional[str] = Field(
None,
description="Optional override filename presented to the user when downloading",
)
@model_validator(mode="after")
def validate_file_path(self):
if not self.file_path:
raise ValueError("file_path 不能为空")
return self
class SendLocalFileTool(MoviePilotTool):
name: str = "send_local_file"
description: str = (
"Send a local image or file from the server filesystem to the current user. "
"Use this when you have generated or identified a local file the user should download."
)
args_schema: Type[BaseModel] = SendLocalFileInput
require_admin: bool = False
def get_tool_message(self, **kwargs) -> Optional[str]:
file_path = kwargs.get("file_path", "")
file_name = Path(file_path).name if file_path else "未知文件"
return f"正在发送本地附件: {file_name}"
async def run(
self,
file_path: str,
message: Optional[str] = None,
title: Optional[str] = None,
file_name: Optional[str] = None,
**kwargs,
) -> str:
if not self._channel or not self._source:
return "当前不在可回传消息的会话中,无法发送附件"
try:
channel = MessageChannel(self._channel)
except ValueError:
return f"不支持的消息渠道: {self._channel}"
if not ChannelCapabilityManager.supports_capability(
channel, ChannelCapability.FILE_SENDING
):
return f"当前渠道 {channel.value} 暂不支持发送本地文件"
resolved_path = Path(file_path).expanduser()
if not resolved_path.is_absolute():
resolved_path = resolved_path.resolve()
if not resolved_path.exists() or not resolved_path.is_file():
return f"文件不存在: {resolved_path}"
logger.info(
"执行工具: %s, channel=%s, file=%s",
self.name,
channel.value,
resolved_path,
)
await ToolChain().async_post_message(
Notification(
channel=channel,
source=self._source,
mtype=NotificationType.Agent,
userid=self._user_id,
username=self._username,
title=title,
text=message,
file_path=str(resolved_path),
file_name=file_name or resolved_path.name,
)
)
return "本地附件已发送"

View File

@@ -0,0 +1,79 @@
"""发送消息工具"""
from typing import Optional, Type
from pydantic import BaseModel, Field, model_validator
from app.agent.tools.base import MoviePilotTool
from app.log import logger
class SendMessageInput(BaseModel):
"""发送消息工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
message: Optional[str] = Field(
None,
description="The message content to send to the user (should be clear and informative)",
)
title: Optional[str] = Field(
None,
description="Title of the message, a short summary of the message content",
)
image_url: Optional[str] = Field(
None,
description="Optional image URL to send together with the message on channels that support images (such as Telegram and Slack)",
)
@model_validator(mode="after")
def validate_payload(self):
if not self.message and not self.title and not self.image_url:
raise ValueError("message、title、image_url 至少需要提供一个")
return self
class SendMessageTool(MoviePilotTool):
name: str = "send_message"
description: str = "Send notification message to the user through configured notification channels (Telegram, Slack, WeChat, etc.). Supports optional image_url on channels that can send images. Used to inform users about operation results, errors, important updates, or proactively send a relevant image."
args_schema: Type[BaseModel] = SendMessageInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据消息参数生成友好的提示消息"""
message = kwargs.get("message", "") or ""
title = kwargs.get("title") or ""
image_url = kwargs.get("image_url")
# 截断过长的消息
if len(message) > 50:
message = message[:50] + "..."
if title and image_url:
return f"正在发送图文消息: [{title}] {message}"
if title:
return f"正在发送消息: [{title}] {message}"
if image_url:
return f"正在发送图片消息: {message}"
return f"正在发送消息: {message}"
async def run(
self,
message: Optional[str] = None,
title: Optional[str] = None,
image_url: Optional[str] = None,
**kwargs,
) -> str:
title = title or ("图片" if image_url and not message else "")
text = message or ""
logger.info(
f"执行工具: {self.name}, 参数: title={title}, message={text}, image_url={image_url}"
)
try:
await self.send_tool_message(text, title=title, image=image_url)
return "消息已发送"
except Exception as e:
logger.error(f"发送消息失败: {e}")
return f"发送消息时发生错误: {str(e)}"

View File

@@ -0,0 +1,96 @@
"""发送语音消息工具。"""
import asyncio
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool, ToolChain
from app.core.config import settings
from app.helper.voice import VoiceHelper
from app.helper.service import ServiceConfigHelper
from app.log import logger
from app.schemas import Notification, NotificationType
from app.schemas.types import MessageChannel
class SendVoiceMessageInput(BaseModel):
"""发送语音消息工具输入。"""
explanation: str = Field(
...,
description="Clear explanation of why a voice reply is the best fit in the current context",
)
message: str = Field(
...,
description="The spoken content to send back to the user",
)
class SendVoiceMessageTool(MoviePilotTool):
name: str = "send_voice_message"
description: str = (
"Send a voice reply to the current user. Prefer this when the user sent a voice message "
"or when spoken playback is more natural. On channels without voice support or when TTS "
"is unavailable, it automatically falls back to sending the same content as plain text."
)
args_schema: Type[BaseModel] = SendVoiceMessageInput
require_admin: bool = False
def get_tool_message(self, **kwargs) -> Optional[str]:
message = kwargs.get("message") or ""
if len(message) > 40:
message = message[:40] + "..."
return f"正在发送语音回复: {message}"
def _supports_real_voice_reply(self) -> bool:
channel = self._channel or ""
if channel == MessageChannel.Telegram.value:
return True
if channel != MessageChannel.Wechat.value:
return False
for config in ServiceConfigHelper.get_notification_configs():
if config.name != self._source:
continue
return (config.config or {}).get("WECHAT_MODE", "app") != "bot"
return False
async def run(self, message: str, **kwargs) -> str:
if not message:
return "语音回复内容不能为空"
voice_path = None
used_voice = False
channel = self._channel or ""
if self._supports_real_voice_reply() and VoiceHelper.is_available("tts"):
voice_file = await asyncio.to_thread(VoiceHelper.synthesize_speech, message)
if voice_file:
voice_path = str(voice_file)
used_voice = True
logger.info(
"执行工具: %s, channel=%s, use_voice=%s, text_len=%s",
self.name,
channel,
used_voice,
len(message),
)
await ToolChain().async_post_message(
Notification(
channel=self._channel,
source=self._source,
mtype=NotificationType.Agent,
userid=self._user_id,
username=self._username,
text=message,
voice_path=voice_path,
voice_caption=message if settings.AI_VOICE_REPLY_WITH_TEXT else None,
)
)
self._agent_context["user_reply_sent"] = True
self._agent_context["reply_mode"] = "voice" if used_voice else "text_fallback"
if used_voice:
return "语音回复已发送"
return "当前未使用语音通道,已自动回退为文字回复"

View File

@@ -0,0 +1,49 @@
"""测试站点连通性工具"""
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.site import SiteChain
from app.db.site_oper import SiteOper
from app.log import logger
class TestSiteInput(BaseModel):
"""测试站点连通性工具的输入参数模型"""
explanation: str = Field(..., description="Clear explanation of why this tool is being used in the current context")
site_identifier: int = Field(..., description="Site ID to test (can be obtained from query_sites tool)")
class TestSiteTool(MoviePilotTool):
name: str = "test_site"
description: str = "Test site connectivity and availability. This will check if a site is accessible and can be logged in. Accepts site ID only."
args_schema: Type[BaseModel] = TestSiteInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据测试参数生成友好的提示消息"""
site_identifier = kwargs.get("site_identifier")
return f"正在测试站点连通性: {site_identifier}"
async def run(self, site_identifier: int, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: site_identifier={site_identifier}")
try:
site_oper = SiteOper()
site_chain = SiteChain()
site = await site_oper.async_get(site_identifier)
if not site:
return f"未找到站点:{site_identifier},请使用 query_sites 工具查询可用的站点"
# 测试站点连通性
status, message = site_chain.test(site.domain)
if status:
return f"站点连通性测试成功:{site.name} ({site.domain})\n{message}"
else:
return f"站点连通性测试失败:{site.name} ({site.domain})\n{message}"
except Exception as e:
logger.error(f"测试站点连通性失败: {e}", exc_info=True)
return f"测试站点连通性时发生错误: {str(e)}"

View File

@@ -0,0 +1,177 @@
"""整理文件或目录工具"""
from pathlib import Path
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.transfer import TransferChain
from app.log import logger
from app.schemas import FileItem, MediaType
class TransferFileInput(BaseModel):
"""整理文件或目录工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
file_path: str = Field(
...,
description="Path to the file or directory to transfer (e.g., '/path/to/file.mkv' or '/path/to/directory')",
)
storage: Optional[str] = Field(
"local",
description="Storage type of the source file (default: 'local', can be 'smb', 'alist', etc.)",
)
target_path: Optional[str] = Field(
None,
description="Target path for the transferred file/directory (optional, uses default library path if not specified)",
)
target_storage: Optional[str] = Field(
None,
description="Target storage type (optional, uses default storage if not specified)",
)
media_type: Optional[str] = Field(None, description="Allowed values: movie, tv")
tmdbid: Optional[int] = Field(
None,
description="TMDB ID for precise media identification (optional but recommended for accuracy)",
)
doubanid: Optional[str] = Field(
None, description="Douban ID for media identification (optional)"
)
season: Optional[int] = Field(
None, description="Season number for TV shows (optional)"
)
transfer_type: Optional[str] = Field(
None,
description="Transfer mode: 'move' to move files, 'copy' to copy files, 'link' for hard link, 'softlink' for symbolic link (optional, uses default mode if not specified)",
)
background: Optional[bool] = Field(
False,
description="Whether to run transfer in background (default: False, runs synchronously)",
)
class TransferFileTool(MoviePilotTool):
name: str = "transfer_file"
description: str = "Transfer/organize a file or directory to the media library. Automatically recognizes media information and organizes files according to configured rules. Supports custom target paths, media identification, and transfer modes."
args_schema: Type[BaseModel] = TransferFileInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据整理参数生成友好的提示消息"""
file_path = kwargs.get("file_path", "")
media_type = kwargs.get("media_type")
transfer_type = kwargs.get("transfer_type")
background = kwargs.get("background", False)
message = f"正在整理文件: {file_path}"
if media_type:
message += f" [{media_type}]"
if transfer_type:
transfer_map = {
"move": "移动",
"copy": "复制",
"link": "硬链接",
"softlink": "软链接",
}
message += f" 模式: {transfer_map.get(transfer_type, transfer_type)}"
if background:
message += " [后台运行]"
return message
async def run(
self,
file_path: str,
storage: Optional[str] = "local",
target_path: Optional[str] = None,
target_storage: Optional[str] = None,
media_type: Optional[str] = None,
tmdbid: Optional[int] = None,
doubanid: Optional[str] = None,
season: Optional[int] = None,
transfer_type: Optional[str] = None,
background: Optional[bool] = False,
**kwargs,
) -> str:
logger.info(
f"执行工具: {self.name}, 参数: file_path={file_path}, storage={storage}, target_path={target_path}, "
f"target_storage={target_storage}, media_type={media_type}, tmdbid={tmdbid}, doubanid={doubanid}, "
f"season={season}, transfer_type={transfer_type}, background={background}"
)
try:
if not file_path:
return "错误:必须提供文件或目录路径"
# 规范化路径
if storage == "local":
# 本地路径处理
if not file_path.startswith("/") and not (
len(file_path) > 1 and file_path[1] == ":"
):
# 相对路径,尝试转换为绝对路径
file_path = str(Path(file_path).resolve())
else:
# 远程存储路径,确保以/开头
if not file_path.startswith("/"):
file_path = "/" + file_path
# 创建FileItem
fileitem = FileItem(
storage=storage or "local",
path=file_path,
type="dir" if file_path.endswith("/") else "file",
)
# 处理目标路径
target_path_obj = None
if target_path:
target_path_obj = Path(target_path)
# 处理媒体类型
media_type_enum = None
if media_type:
media_type_enum = MediaType.from_agent(media_type)
if not media_type_enum:
return f"错误:无效的媒体类型 '{media_type}',支持的类型:'movie', 'tv'"
# 调用整理方法
transfer_chain = TransferChain()
state, errormsg = transfer_chain.manual_transfer(
fileitem=fileitem,
target_storage=target_storage,
target_path=target_path_obj,
tmdbid=tmdbid,
doubanid=doubanid,
mtype=media_type_enum,
season=season,
transfer_type=transfer_type,
background=background,
)
if not state:
# 处理错误信息
if isinstance(errormsg, list):
error_text = f"整理完成,{len(errormsg)} 个文件转移失败"
if errormsg:
error_text += f"\n" + "\n".join(
str(e) for e in errormsg[:5]
) # 只显示前5个错误
if len(errormsg) > 5:
error_text += f"\n... 还有 {len(errormsg) - 5} 个错误"
else:
error_text = str(errormsg)
return f"整理失败:{error_text}"
else:
if background:
return f"整理任务已提交到后台运行:{file_path}"
else:
return f"整理成功:{file_path}"
except Exception as e:
logger.error(f"整理文件失败: {e}", exc_info=True)
return f"整理文件时发生错误: {str(e)}"

View File

@@ -0,0 +1,95 @@
"""更新自定义识别词工具"""
import json
from typing import List, Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.db.systemconfig_oper import SystemConfigOper
from app.log import logger
from app.schemas.types import SystemConfigKey
class UpdateCustomIdentifiersInput(BaseModel):
"""更新自定义识别词工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
identifiers: List[str] = Field(
...,
description=(
"The complete list of custom identifier rules to save. "
"This REPLACES the entire existing list. "
"Always query existing identifiers first, merge new rules, then pass the full list."
),
)
class UpdateCustomIdentifiersTool(MoviePilotTool):
name: str = "update_custom_identifiers"
description: str = (
"Update the full list of custom identifiers (自定义识别词) used for preprocessing torrent/file names. "
"This tool REPLACES all existing identifier rules with the provided list. "
"IMPORTANT: Always use 'query_custom_identifiers' first to get existing rules, "
"then merge new rules into the list before calling this tool to avoid accidentally deleting existing rules. "
"Supported rule formats (spaces around operators are required): "
"1) Block word: just the word/regex to remove; "
"2) Replacement: '被替换词 => 替换词'; "
"3) Episode offset: '前定位词 <> 后定位词 >> EP±N'; "
"4) Combined: '被替换词 => 替换词 && 前定位词 <> 后定位词 >> EP±N'; "
"Lines starting with '#' are comments. "
"The replacement target supports: {[tmdbid=xxx;type=movie/tv;s=xxx;e=xxx]} for direct TMDB ID matching."
)
args_schema: Type[BaseModel] = UpdateCustomIdentifiersInput
def get_tool_message(self, **kwargs) -> Optional[str]:
"""生成友好的提示消息"""
identifiers = kwargs.get("identifiers", [])
return f"正在更新自定义识别词(共 {len(identifiers)} 条规则)"
async def run(self, identifiers: List[str] = None, **kwargs) -> str:
logger.info(
f"执行工具: {self.name}, 规则数量: {len(identifiers) if identifiers else 0}"
)
try:
if identifiers is None:
return json.dumps(
{"success": False, "message": "必须提供 identifiers 参数"},
ensure_ascii=False,
)
# 过滤空字符串
identifiers = [i for i in identifiers if i is not None]
system_config_oper = SystemConfigOper()
# 保存
value = identifiers if identifiers else None
success = await system_config_oper.async_set(
SystemConfigKey.CustomIdentifiers, value
)
if success:
return json.dumps(
{
"success": True,
"message": f"自定义识别词已更新,共 {len(identifiers)} 条规则",
"count": len(identifiers),
"identifiers": identifiers,
},
ensure_ascii=False,
indent=2,
)
else:
return json.dumps(
{"success": False, "message": "保存自定义识别词失败"},
ensure_ascii=False,
)
except Exception as e:
logger.error(f"更新自定义识别词失败: {e}")
return json.dumps(
{"success": False, "message": f"更新自定义识别词时发生错误: {str(e)}"},
ensure_ascii=False,
)

View File

@@ -0,0 +1,235 @@
"""更新站点工具"""
import json
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.core.event import eventmanager
from app.db import AsyncSessionFactory
from app.db.models.site import Site
from app.log import logger
from app.schemas.types import EventType
from app.utils.string import StringUtils
class UpdateSiteInput(BaseModel):
"""更新站点工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
site_id: int = Field(
...,
description="The ID of the site to update (can be obtained from query_sites tool)",
)
name: Optional[str] = Field(None, description="Site name (optional)")
url: Optional[str] = Field(
None, description="Site URL (optional, will be automatically formatted)"
)
pri: Optional[int] = Field(
None,
description="Site priority (optional, smaller value = higher priority, e.g., pri=1 has higher priority than pri=10)",
)
rss: Optional[str] = Field(None, description="RSS feed URL (optional)")
cookie: Optional[str] = Field(None, description="Site cookie (optional)")
ua: Optional[str] = Field(None, description="User-Agent string (optional)")
apikey: Optional[str] = Field(None, description="API key (optional)")
token: Optional[str] = Field(None, description="API token (optional)")
proxy: Optional[int] = Field(
None, description="Whether to use proxy: 0 for no, 1 for yes (optional)"
)
filter: Optional[str] = Field(
None, description="Filter rule as regular expression (optional)"
)
note: Optional[str] = Field(None, description="Site notes/remarks (optional)")
timeout: Optional[int] = Field(
None, description="Request timeout in seconds (optional, default: 15)"
)
limit_interval: Optional[int] = Field(
None, description="Rate limit interval in seconds (optional)"
)
limit_count: Optional[int] = Field(
None, description="Rate limit count per interval (optional)"
)
limit_seconds: Optional[int] = Field(
None, description="Rate limit seconds between requests (optional)"
)
is_active: Optional[bool] = Field(
None,
description="Whether site is active: True for enabled, False for disabled (optional)",
)
downloader: Optional[str] = Field(
None, description="Downloader name for this site (optional)"
)
class UpdateSiteTool(MoviePilotTool):
name: str = "update_site"
description: str = "Update site configuration including URL, priority, authentication credentials (cookie, UA, API key), proxy settings, rate limits, and other site properties. Supports updating multiple site attributes at once. Site priority (pri): smaller values have higher priority (e.g., pri=1 has higher priority than pri=10)."
args_schema: Type[BaseModel] = UpdateSiteInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据更新参数生成友好的提示消息"""
site_id = kwargs.get("site_id")
fields_updated = []
if kwargs.get("name"):
fields_updated.append("名称")
if kwargs.get("url"):
fields_updated.append("URL")
if kwargs.get("pri") is not None:
fields_updated.append("优先级")
if kwargs.get("cookie"):
fields_updated.append("Cookie")
if kwargs.get("ua"):
fields_updated.append("User-Agent")
if kwargs.get("proxy") is not None:
fields_updated.append("代理设置")
if kwargs.get("is_active") is not None:
fields_updated.append("启用状态")
if kwargs.get("downloader"):
fields_updated.append("下载器")
if fields_updated:
return f"正在更新站点 #{site_id}: {', '.join(fields_updated)}"
return f"正在更新站点 #{site_id}"
async def run(
self,
site_id: int,
name: Optional[str] = None,
url: Optional[str] = None,
pri: Optional[int] = None,
rss: Optional[str] = None,
cookie: Optional[str] = None,
ua: Optional[str] = None,
apikey: Optional[str] = None,
token: Optional[str] = None,
proxy: Optional[int] = None,
filter: Optional[str] = None,
note: Optional[str] = None,
timeout: Optional[int] = None,
limit_interval: Optional[int] = None,
limit_count: Optional[int] = None,
limit_seconds: Optional[int] = None,
is_active: Optional[bool] = None,
downloader: Optional[str] = None,
**kwargs,
) -> str:
logger.info(f"执行工具: {self.name}, 参数: site_id={site_id}")
try:
# 获取数据库会话
async with AsyncSessionFactory() as db:
# 获取站点
site = await Site.async_get(db, site_id)
if not site:
return json.dumps(
{"success": False, "message": f"站点不存在: {site_id}"},
ensure_ascii=False,
)
# 构建更新字典
site_dict = {}
# 基本信息
if name is not None:
site_dict["name"] = name
# URL处理需要校正格式
if url is not None:
_scheme, _netloc = StringUtils.get_url_netloc(url)
site_dict["url"] = f"{_scheme}://{_netloc}/"
if pri is not None:
site_dict["pri"] = pri
if rss is not None:
site_dict["rss"] = rss
# 认证信息
if cookie is not None:
site_dict["cookie"] = cookie
if ua is not None:
site_dict["ua"] = ua
if apikey is not None:
site_dict["apikey"] = apikey
if token is not None:
site_dict["token"] = token
# 配置选项
if proxy is not None:
site_dict["proxy"] = proxy
if filter is not None:
site_dict["filter"] = filter
if note is not None:
site_dict["note"] = note
if timeout is not None:
site_dict["timeout"] = timeout
# 流控设置
if limit_interval is not None:
site_dict["limit_interval"] = limit_interval
if limit_count is not None:
site_dict["limit_count"] = limit_count
if limit_seconds is not None:
site_dict["limit_seconds"] = limit_seconds
# 状态和下载器
if is_active is not None:
site_dict["is_active"] = is_active
if downloader is not None:
site_dict["downloader"] = downloader
# 如果没有要更新的字段
if not site_dict:
return json.dumps(
{"success": False, "message": "没有提供要更新的字段"},
ensure_ascii=False,
)
# 更新站点
await site.async_update(db, site_dict)
# 重新获取更新后的站点数据
updated_site = await Site.async_get(db, site_id)
# 发送站点更新事件
await eventmanager.async_send_event(
EventType.SiteUpdated,
{"domain": updated_site.domain if updated_site else site.domain},
)
# 构建返回结果
result = {
"success": True,
"message": f"站点 #{site_id} 更新成功",
"site_id": site_id,
"updated_fields": list(site_dict.keys()),
}
if updated_site:
result["site"] = {
"id": updated_site.id,
"name": updated_site.name,
"domain": updated_site.domain,
"url": updated_site.url,
"pri": updated_site.pri,
"is_active": updated_site.is_active,
"downloader": updated_site.downloader,
"proxy": updated_site.proxy,
"timeout": updated_site.timeout,
}
return json.dumps(result, ensure_ascii=False, indent=2)
except Exception as e:
error_message = f"更新站点失败: {str(e)}"
logger.error(f"更新站点失败: {e}", exc_info=True)
return json.dumps(
{"success": False, "message": error_message, "site_id": site_id},
ensure_ascii=False,
)

View File

@@ -0,0 +1,84 @@
"""更新站点Cookie和UA工具"""
from typing import Optional, Type
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.chain.site import SiteChain
from app.db.site_oper import SiteOper
from app.log import logger
class UpdateSiteCookieInput(BaseModel):
"""更新站点Cookie和UA工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
site_identifier: int = Field(
...,
description="Site ID to update Cookie and User-Agent for (can be obtained from query_sites tool)",
)
username: str = Field(..., description="Site login username")
password: str = Field(..., description="Site login password")
two_step_code: Optional[str] = Field(
None,
description="Two-step verification code or secret key (optional, required for sites with 2FA enabled)",
)
class UpdateSiteCookieTool(MoviePilotTool):
name: str = "update_site_cookie"
description: str = "Update site Cookie and User-Agent by logging in with username and password. This tool can automatically obtain and update the site's authentication credentials. Supports two-step verification for sites that require it. Accepts site ID only."
args_schema: Type[BaseModel] = UpdateSiteCookieInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据更新参数生成友好的提示消息"""
site_identifier = kwargs.get("site_identifier")
username = kwargs.get("username", "")
two_step_code = kwargs.get("two_step_code")
message = f"正在更新站点Cookie: {site_identifier} (用户: {username})"
if two_step_code:
message += " [需要两步验证]"
return message
async def run(
self,
site_identifier: int,
username: str,
password: str,
two_step_code: Optional[str] = None,
**kwargs,
) -> str:
logger.info(
f"执行工具: {self.name}, 参数: site_identifier={site_identifier}, username={username}"
)
try:
site_oper = SiteOper()
site_chain = SiteChain()
site = await site_oper.async_get(site_identifier)
if not site:
return f"未找到站点:{site_identifier},请使用 query_sites 工具查询可用的站点"
# 更新站点Cookie和UA
status, message = site_chain.update_cookie(
site_info=site,
username=username,
password=password,
two_step_code=two_step_code,
)
if status:
return f"站点【{site.name}】Cookie和UA更新成功\n{message}"
else:
return f"站点【{site.name}】Cookie和UA更新失败\n错误原因:{message}"
except Exception as e:
logger.error(f"更新站点Cookie和UA失败: {e}", exc_info=True)
return f"更新站点Cookie和UA时发生错误: {str(e)}"

View File

@@ -0,0 +1,303 @@
"""更新订阅工具"""
import json
from typing import Optional, Type, List
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.core.event import eventmanager
from app.db import AsyncSessionFactory
from app.db.models.subscribe import Subscribe
from app.log import logger
from app.schemas.types import EventType
class UpdateSubscribeInput(BaseModel):
"""更新订阅工具的输入参数模型"""
explanation: str = Field(
...,
description="Clear explanation of why this tool is being used in the current context",
)
subscribe_id: int = Field(
...,
description="The ID of the subscription to update (can be obtained from query_subscribes tool)",
)
name: Optional[str] = Field(None, description="Subscription name/title (optional)")
year: Optional[str] = Field(None, description="Release year (optional)")
season: Optional[int] = Field(
None, description="Season number for TV shows (optional)"
)
total_episode: Optional[int] = Field(
None, description="Total number of episodes (optional)"
)
lack_episode: Optional[int] = Field(
None, description="Number of missing episodes (optional)"
)
start_episode: Optional[int] = Field(
None, description="Starting episode number (optional)"
)
quality: Optional[str] = Field(
None,
description="Quality filter as regular expression (optional, e.g., 'BluRay|WEB-DL|HDTV')",
)
resolution: Optional[str] = Field(
None,
description="Resolution filter as regular expression (optional, e.g., '1080p|720p|2160p')",
)
effect: Optional[str] = Field(
None,
description="Effect filter as regular expression (optional, e.g., 'HDR|DV|SDR')",
)
include: Optional[str] = Field(
None, description="Include filter as regular expression (optional)"
)
exclude: Optional[str] = Field(
None, description="Exclude filter as regular expression (optional)"
)
filter: Optional[str] = Field(
None, description="Filter rule as regular expression (optional)"
)
state: Optional[str] = Field(
None,
description="Subscription state: 'R' for enabled, 'P' for pending, 'S' for paused (optional)",
)
sites: Optional[List[int]] = Field(
None, description="List of site IDs to search from (optional)"
)
downloader: Optional[str] = Field(None, description="Downloader name (optional)")
save_path: Optional[str] = Field(
None, description="Save path for downloaded files (optional)"
)
best_version: Optional[int] = Field(
None,
description="Whether to upgrade to best version: 0 for no, 1 for yes (optional)",
)
custom_words: Optional[str] = Field(
None, description="Custom recognition words (optional)"
)
media_category: Optional[str] = Field(
None, description="Custom media category (optional)"
)
episode_group: Optional[str] = Field(
None, description="Episode group ID (optional)"
)
class UpdateSubscribeTool(MoviePilotTool):
name: str = "update_subscribe"
description: str = "Update subscription properties including filters, episode counts, state, and other settings. Supports updating quality/resolution filters, episode tracking, subscription state, and download configuration."
args_schema: Type[BaseModel] = UpdateSubscribeInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据更新参数生成友好的提示消息"""
subscribe_id = kwargs.get("subscribe_id")
fields_updated = []
if kwargs.get("name"):
fields_updated.append("名称")
if kwargs.get("total_episode") is not None:
fields_updated.append("总集数")
if kwargs.get("lack_episode") is not None:
fields_updated.append("缺失集数")
if kwargs.get("quality"):
fields_updated.append("质量过滤")
if kwargs.get("resolution"):
fields_updated.append("分辨率过滤")
if kwargs.get("state"):
state_map = {"R": "启用", "P": "禁用", "S": "暂停"}
fields_updated.append(
f"状态({state_map.get(kwargs.get('state'), kwargs.get('state'))})"
)
if kwargs.get("sites"):
fields_updated.append("站点")
if kwargs.get("downloader"):
fields_updated.append("下载器")
if fields_updated:
return f"正在更新订阅 #{subscribe_id}: {', '.join(fields_updated)}"
return f"正在更新订阅 #{subscribe_id}"
async def run(
self,
subscribe_id: int,
name: Optional[str] = None,
year: Optional[str] = None,
season: Optional[int] = None,
total_episode: Optional[int] = None,
lack_episode: Optional[int] = None,
start_episode: Optional[int] = None,
quality: Optional[str] = None,
resolution: Optional[str] = None,
effect: Optional[str] = None,
include: Optional[str] = None,
exclude: Optional[str] = None,
filter: Optional[str] = None,
state: Optional[str] = None,
sites: Optional[List[int]] = None,
downloader: Optional[str] = None,
save_path: Optional[str] = None,
best_version: Optional[int] = None,
custom_words: Optional[str] = None,
media_category: Optional[str] = None,
episode_group: Optional[str] = None,
**kwargs,
) -> str:
logger.info(f"执行工具: {self.name}, 参数: subscribe_id={subscribe_id}")
try:
# 获取数据库会话
async with AsyncSessionFactory() as db:
# 获取订阅
subscribe = await Subscribe.async_get(db, subscribe_id)
if not subscribe:
return json.dumps(
{"success": False, "message": f"订阅不存在: {subscribe_id}"},
ensure_ascii=False,
)
# 保存旧数据用于事件
old_subscribe_dict = subscribe.to_dict()
# 构建更新字典
subscribe_dict = {}
# 基本信息
if name is not None:
subscribe_dict["name"] = name
if year is not None:
subscribe_dict["year"] = year
if season is not None:
subscribe_dict["season"] = season
# 集数相关
if total_episode is not None:
subscribe_dict["total_episode"] = total_episode
# 如果总集数增加,缺失集数也要相应增加
if total_episode > (subscribe.total_episode or 0):
old_lack = subscribe.lack_episode or 0
subscribe_dict["lack_episode"] = old_lack + (
total_episode - (subscribe.total_episode or 0)
)
# 标记为手动修改过总集数
subscribe_dict["manual_total_episode"] = 1
# 缺失集数处理(只有在没有提供总集数时才单独处理)
# 注意:如果 lack_episode 为 0不更新避免更新为0
if lack_episode is not None and total_episode is None:
if lack_episode > 0:
subscribe_dict["lack_episode"] = lack_episode
# 如果 lack_episode 为 0不添加到更新字典中保持原值或由总集数逻辑处理
if start_episode is not None:
subscribe_dict["start_episode"] = start_episode
# 过滤规则
if quality is not None:
subscribe_dict["quality"] = quality
if resolution is not None:
subscribe_dict["resolution"] = resolution
if effect is not None:
subscribe_dict["effect"] = effect
if include is not None:
subscribe_dict["include"] = include
if exclude is not None:
subscribe_dict["exclude"] = exclude
if filter is not None:
subscribe_dict["filter"] = filter
# 状态
if state is not None:
valid_states = ["R", "P", "S", "N"]
if state not in valid_states:
return json.dumps(
{
"success": False,
"message": f"无效的订阅状态: {state},有效状态: {', '.join(valid_states)}",
},
ensure_ascii=False,
)
subscribe_dict["state"] = state
# 下载配置
if sites is not None:
subscribe_dict["sites"] = sites
if downloader is not None:
subscribe_dict["downloader"] = downloader
if save_path is not None:
subscribe_dict["save_path"] = save_path
if best_version is not None:
subscribe_dict["best_version"] = best_version
# 其他配置
if custom_words is not None:
subscribe_dict["custom_words"] = custom_words
if media_category is not None:
subscribe_dict["media_category"] = media_category
if episode_group is not None:
subscribe_dict["episode_group"] = episode_group
# 如果没有要更新的字段
if not subscribe_dict:
return json.dumps(
{"success": False, "message": "没有提供要更新的字段"},
ensure_ascii=False,
)
# 更新订阅
await subscribe.async_update(db, subscribe_dict)
# 重新获取更新后的订阅数据
updated_subscribe = await Subscribe.async_get(db, subscribe_id)
# 发送订阅调整事件
await eventmanager.async_send_event(
EventType.SubscribeModified,
{
"subscribe_id": subscribe_id,
"old_subscribe_info": old_subscribe_dict,
"subscribe_info": updated_subscribe.to_dict()
if updated_subscribe
else {},
},
)
# 构建返回结果
result = {
"success": True,
"message": f"订阅 #{subscribe_id} 更新成功",
"subscribe_id": subscribe_id,
"updated_fields": list(subscribe_dict.keys()),
}
if updated_subscribe:
result["subscribe"] = {
"id": updated_subscribe.id,
"name": updated_subscribe.name,
"year": updated_subscribe.year,
"type": updated_subscribe.type,
"season": updated_subscribe.season,
"state": updated_subscribe.state,
"total_episode": updated_subscribe.total_episode,
"lack_episode": updated_subscribe.lack_episode,
"start_episode": updated_subscribe.start_episode,
"quality": updated_subscribe.quality,
"resolution": updated_subscribe.resolution,
"effect": updated_subscribe.effect,
}
return json.dumps(result, ensure_ascii=False, indent=2)
except Exception as e:
error_message = f"更新订阅失败: {str(e)}"
logger.error(f"更新订阅失败: {e}", exc_info=True)
return json.dumps(
{
"success": False,
"message": error_message,
"subscribe_id": subscribe_id,
},
ensure_ascii=False,
)

View File

@@ -0,0 +1,54 @@
"""文件写入工具"""
from pathlib import Path
from typing import Optional, Type
from anyio import Path as AsyncPath
from pydantic import BaseModel, Field
from app.agent.tools.base import MoviePilotTool
from app.log import logger
class WriteFileInput(BaseModel):
"""Input parameters for write file tool"""
file_path: str = Field(..., description="The absolute path of the file to write")
content: str = Field(..., description="The content to write into the file")
class WriteFileTool(MoviePilotTool):
name: str = "write_file"
description: str = "Write full content to a file. If the file already exists, it will be overwritten. Automatically creates parent directories if they don't exist."
args_schema: Type[BaseModel] = WriteFileInput
require_admin: bool = True
def get_tool_message(self, **kwargs) -> Optional[str]:
"""根据参数生成友好的提示消息"""
file_path = kwargs.get("file_path", "")
file_name = Path(file_path).name if file_path else "未知文件"
return f"正在写入文件: {file_name}"
async def run(self, file_path: str, content: str, **kwargs) -> str:
logger.info(f"执行工具: {self.name}, 参数: file_path={file_path}")
try:
path = AsyncPath(file_path)
if await path.exists() and not await path.is_file():
return f"错误:{file_path} 路径已存在但不是一个文件"
# 自动创建父目录
await path.parent.mkdir(parents=True, exist_ok=True)
# 写入文件
await path.write_text(content, encoding="utf-8")
logger.info(f"成功写入文件 {file_path}")
return f"成功写入文件 {file_path}"
except PermissionError:
return f"错误:没有权限写入 {file_path}"
except Exception as e:
logger.error(f"写入文件 {file_path} 时发生错误: {str(e)}", exc_info=True)
return f"操作失败: {str(e)}"

319
app/agent/tools/manager.py Normal file
View File

@@ -0,0 +1,319 @@
import json
import uuid
from typing import Any, Dict, List, Optional
from app.agent.tools.factory import MoviePilotToolFactory
from app.log import logger
class ToolDefinition:
"""
工具定义
"""
def __init__(self, name: str, description: str, input_schema: Dict[str, Any]):
self.name = name
self.description = description
self.input_schema = input_schema
class MoviePilotToolsManager:
"""
MoviePilot工具管理器用于HTTP API
"""
def __init__(self, user_id: str = "api_user", session_id: str = uuid.uuid4()):
"""
初始化工具管理器
Args:
user_id: 用户ID
session_id: 会话ID
"""
self.user_id = user_id
self.session_id = session_id
self.tools: List[Any] = []
self._load_tools()
def _load_tools(self):
"""
加载所有MoviePilot工具
"""
try:
# 创建工具实例
self.tools = MoviePilotToolFactory.create_tools(
session_id=self.session_id,
user_id=self.user_id,
channel=None,
source="api",
username="API Client",
stream_handler=None,
)
logger.info(f"成功加载 {len(self.tools)} 个工具")
except Exception as e:
logger.error(f"加载工具失败: {e}", exc_info=True)
self.tools = []
def list_tools(self) -> List[ToolDefinition]:
"""
列出所有可用的工具
Returns:
工具定义列表
"""
tools_list = []
for tool in self.tools:
# 获取工具的输入参数模型
args_schema = getattr(tool, "args_schema", None)
if args_schema:
# 将Pydantic模型转换为JSON Schema
input_schema = self._convert_to_json_schema(args_schema)
else:
# 如果没有args_schema使用基本信息
input_schema = {"type": "object", "properties": {}, "required": []}
tools_list.append(
ToolDefinition(
name=tool.name,
description=tool.description or "",
input_schema=input_schema,
)
)
return tools_list
def get_tool(self, tool_name: str) -> Optional[Any]:
"""
获取指定工具实例
Args:
tool_name: 工具名称
Returns:
工具实例如果未找到返回None
"""
for tool in self.tools:
if tool.name == tool_name:
return tool
return None
@staticmethod
def _resolve_field_schema(field_info: Dict[str, Any]) -> Dict[str, Any]:
"""
解析字段schema兼容 Optional[T] 生成的 anyOf 结构
"""
if field_info.get("type"):
return field_info
any_of = field_info.get("anyOf")
if not any_of:
return field_info
for type_option in any_of:
if type_option.get("type") and type_option["type"] != "null":
merged = dict(type_option)
if "description" not in merged and field_info.get("description"):
merged["description"] = field_info["description"]
if "default" not in merged and "default" in field_info:
merged["default"] = field_info["default"]
return merged
return field_info
@staticmethod
def _normalize_scalar_value(field_type: Optional[str], value: Any, key: str) -> Any:
"""
根据字段类型规范化单个值
"""
if field_type == "integer" and isinstance(value, str):
try:
return int(value)
except (ValueError, TypeError):
logger.warning(f"无法将参数 {key}='{value}' 转换为整数,返回 None")
return None
if field_type == "number" and isinstance(value, str):
try:
return float(value)
except (ValueError, TypeError):
logger.warning(f"无法将参数 {key}='{value}' 转换为浮点数,返回 None")
return None
if field_type == "boolean":
if isinstance(value, str):
return value.lower() in ("true", "1", "yes", "on")
if isinstance(value, (int, float)):
return value != 0
if isinstance(value, bool):
return value
return True
return value
@staticmethod
def _parse_array_string(value: str, key: str, item_type: str = "string") -> list:
"""
将逗号分隔的字符串解析为列表,并根据 item_type 转换元素类型
"""
trimmed = value.strip()
if not trimmed:
return []
return [
MoviePilotToolsManager._normalize_scalar_value(item_type, item.strip(), key)
for item in trimmed.split(",")
if item.strip()
]
@staticmethod
def _normalize_arguments(
tool_instance: Any, arguments: Dict[str, Any]
) -> Dict[str, Any]:
"""
根据工具的参数schema规范化参数类型
Args:
tool_instance: 工具实例
arguments: 原始参数
Returns:
规范化后的参数
"""
# 获取工具的参数schema
args_schema = getattr(tool_instance, "args_schema", None)
if not args_schema:
return arguments
# 获取schema中的字段定义
try:
schema = args_schema.model_json_schema()
properties = schema.get("properties", {})
except Exception as e:
logger.warning(f"获取工具schema失败: {e}")
return arguments
# 规范化参数
normalized = {}
for key, value in arguments.items():
if key not in properties:
# 参数不在schema中保持原样
normalized[key] = value
continue
field_info = MoviePilotToolsManager._resolve_field_schema(properties[key])
field_type = field_info.get("type")
# 数组类型:将字符串解析为列表
if field_type == "array" and isinstance(value, str):
item_type = field_info.get("items", {}).get("type", "string")
normalized[key] = MoviePilotToolsManager._parse_array_string(
value, key, item_type
)
continue
# 根据类型进行转换
normalized[key] = MoviePilotToolsManager._normalize_scalar_value(
field_type, value, key
)
return normalized
async def call_tool(self, tool_name: str, arguments: Dict[str, Any]) -> str:
"""
调用工具
Args:
tool_name: 工具名称
arguments: 工具参数
Returns:
工具执行结果(字符串)
"""
tool_instance = self.get_tool(tool_name)
if not tool_instance:
error_msg = json.dumps(
{"error": f"工具 '{tool_name}' 未找到"}, ensure_ascii=False
)
return error_msg
try:
# 规范化参数类型
normalized_arguments = self._normalize_arguments(tool_instance, arguments)
# 调用工具的run方法
result = await tool_instance.run(**normalized_arguments)
# 确保返回字符串
if isinstance(result, str):
formated_result = result
elif isinstance(result, (int, float)):
formated_result = str(result)
else:
try:
formated_result = json.dumps(result, ensure_ascii=False, indent=2)
except Exception as e:
logger.warning(f"结果转换为JSON失败: {e}, 使用字符串表示")
formated_result = str(result)
return formated_result
except Exception as e:
logger.error(f"调用工具 {tool_name} 时发生错误: {e}", exc_info=True)
error_msg = json.dumps(
{"error": f"调用工具 '{tool_name}' 时发生错误: {str(e)}"},
ensure_ascii=False,
)
return error_msg
@staticmethod
def _convert_to_json_schema(args_schema: Any) -> Dict[str, Any]:
"""
将Pydantic模型转换为JSON Schema
Args:
args_schema: Pydantic模型类
Returns:
JSON Schema字典
"""
# 获取Pydantic模型的字段信息
schema = args_schema.model_json_schema()
# 构建JSON Schema
properties = {}
required = []
if "properties" in schema:
for field_name, field_info in schema["properties"].items():
resolved_field_info = MoviePilotToolsManager._resolve_field_schema(
field_info
)
# 转换字段类型
field_type = resolved_field_info.get("type", "string")
field_description = resolved_field_info.get("description", "")
# 处理可选字段
if field_name not in schema.get("required", []):
# 可选字段
default_value = resolved_field_info.get("default")
properties[field_name] = {
"type": field_type,
"description": field_description,
}
if default_value is not None:
properties[field_name]["default"] = default_value
else:
properties[field_name] = {
"type": field_type,
"description": field_description,
}
required.append(field_name)
# 处理枚举类型
if "enum" in resolved_field_info:
properties[field_name]["enum"] = resolved_field_info["enum"]
# 处理数组类型
if field_type == "array" and "items" in resolved_field_info:
properties[field_name]["items"] = resolved_field_info["items"]
return {"type": "object", "properties": properties, "required": required}
moviepilot_tool_manager = MoviePilotToolsManager()

View File

@@ -1,11 +1,13 @@
from fastapi import APIRouter
from app.api.endpoints import login, user, site, message, webhook, subscribe, \
media, douban, search, plugin, tmdb, history, system, download, dashboard, rss, filebrowser, transfer
from app.api.endpoints import login, user, webhook, message, site, subscribe, \
media, douban, search, plugin, tmdb, history, system, download, dashboard, \
transfer, mediaserver, bangumi, storage, discover, recommend, workflow, torrent, mcp, mfa
api_router = APIRouter()
api_router.include_router(login.router, prefix="/login", tags=["login"])
api_router.include_router(user.router, prefix="/user", tags=["user"])
api_router.include_router(mfa.router, prefix="/mfa", tags=["mfa"])
api_router.include_router(site.router, prefix="/site", tags=["site"])
api_router.include_router(message.router, prefix="/message", tags=["message"])
api_router.include_router(webhook.router, prefix="/webhook", tags=["webhook"])
@@ -19,6 +21,12 @@ api_router.include_router(system.router, prefix="/system", tags=["system"])
api_router.include_router(plugin.router, prefix="/plugin", tags=["plugin"])
api_router.include_router(download.router, prefix="/download", tags=["download"])
api_router.include_router(dashboard.router, prefix="/dashboard", tags=["dashboard"])
api_router.include_router(rss.router, prefix="/rss", tags=["rss"])
api_router.include_router(filebrowser.router, prefix="/filebrowser", tags=["filebrowser"])
api_router.include_router(storage.router, prefix="/storage", tags=["storage"])
api_router.include_router(transfer.router, prefix="/transfer", tags=["transfer"])
api_router.include_router(mediaserver.router, prefix="/mediaserver", tags=["mediaserver"])
api_router.include_router(bangumi.router, prefix="/bangumi", tags=["bangumi"])
api_router.include_router(discover.router, prefix="/discover", tags=["discover"])
api_router.include_router(recommend.router, prefix="/recommend", tags=["recommend"])
api_router.include_router(workflow.router, prefix="/workflow", tags=["workflow"])
api_router.include_router(torrent.router, prefix="/torrent", tags=["torrent"])
api_router.include_router(mcp.router, prefix="/mcp", tags=["mcp"])

View File

@@ -0,0 +1,74 @@
from typing import List, Any, Optional
from fastapi import APIRouter, Depends
from app import schemas
from app.chain.bangumi import BangumiChain
from app.core.context import MediaInfo
from app.core.security import verify_token
router = APIRouter()
@router.get("/credits/{bangumiid}", summary="查询Bangumi演职员表", response_model=List[schemas.MediaPerson])
async def bangumi_credits(bangumiid: int,
page: Optional[int] = 1,
count: Optional[int] = 20,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
查询Bangumi演职员表
"""
persons = await BangumiChain().async_bangumi_credits(bangumiid)
if persons:
return persons[(page - 1) * count: page * count]
return []
@router.get("/recommend/{bangumiid}", summary="查询Bangumi推荐", response_model=List[schemas.MediaInfo])
async def bangumi_recommend(bangumiid: int,
page: Optional[int] = 1,
count: Optional[int] = 20,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
查询Bangumi推荐
"""
medias = await BangumiChain().async_bangumi_recommend(bangumiid)
if medias:
return [media.to_dict() for media in medias[(page - 1) * count: page * count]]
return []
@router.get("/person/{person_id}", summary="人物详情", response_model=schemas.MediaPerson)
async def bangumi_person(person_id: int,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
根据人物ID查询人物详情
"""
return await BangumiChain().async_person_detail(person_id=person_id)
@router.get("/person/credits/{person_id}", summary="人物参演作品", response_model=List[schemas.MediaInfo])
async def bangumi_person_credits(person_id: int,
page: Optional[int] = 1,
count: Optional[int] = 20,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
根据人物ID查询人物参演作品
"""
medias = await BangumiChain().async_person_credits(person_id=person_id)
if medias:
return [media.to_dict() for media in medias[(page - 1) * count: page * count]]
return []
@router.get("/{bangumiid}", summary="查询Bangumi详情", response_model=schemas.MediaInfo)
async def bangumi_info(bangumiid: int,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
查询Bangumi详情
"""
info = await BangumiChain().async_bangumi_info(bangumiid)
if info:
return MediaInfo(bangumi_info=info).to_dict()
else:
return schemas.MediaInfo()

View File

@@ -1,58 +1,84 @@
from pathlib import Path
from typing import Any, List
from typing import Any, List, Optional, Annotated
from fastapi import APIRouter, Depends
from requests import Session
from sqlalchemy.orm import Session
from app import schemas
from app.chain.dashboard import DashboardChain
from app.core.config import settings
from app.core.security import verify_token
from app.chain.storage import StorageChain
from app.core.security import verify_token, verify_apitoken
from app.db import get_db
from app.db.models.transferhistory import TransferHistory
from app.helper.directory import DirectoryHelper
from app.scheduler import Scheduler
from app.utils.string import StringUtils
from app.utils.system import SystemUtils
from app.utils.timer import TimerUtils
router = APIRouter()
@router.get("/statistic", summary="媒体数量统计", response_model=schemas.Statistic)
def statistic(db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
def statistic(name: Optional[str] = None, _: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
查询媒体数量统计信息
"""
media_statistic = DashboardChain(db).media_statistic()
if media_statistic:
return schemas.Statistic(
movie_count=media_statistic.movie_count,
tv_count=media_statistic.tv_count,
episode_count=media_statistic.episode_count,
user_count=media_statistic.user_count
)
media_statistics: Optional[List[schemas.Statistic]] = DashboardChain().media_statistic(name)
if media_statistics:
# 汇总各媒体库统计信息
ret_statistic = schemas.Statistic()
has_episode_count = False
for media_statistic in media_statistics:
ret_statistic.movie_count += media_statistic.movie_count or 0
ret_statistic.tv_count += media_statistic.tv_count or 0
ret_statistic.user_count += media_statistic.user_count or 0
if media_statistic.episode_count is not None:
ret_statistic.episode_count += media_statistic.episode_count or 0
has_episode_count = True
if not has_episode_count:
# 所有媒体服务都未提供剧集统计时,返回 None 供前端展示“未获取”。
ret_statistic.episode_count = None
return ret_statistic
else:
return schemas.Statistic()
@router.get("/storage", summary="存储空间", response_model=schemas.Storage)
@router.get("/statistic2", summary="媒体数量统计API_TOKEN", response_model=schemas.Statistic)
def statistic2(_: Annotated[str, Depends(verify_apitoken)]) -> Any:
"""
查询媒体数量统计信息 API_TOKEN认证?token=xxx
"""
return statistic()
@router.get("/storage", summary="本地存储空间", response_model=schemas.Storage)
def storage(_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
查询存储空间信息
查询本地存储空间信息
"""
if settings.LIBRARY_PATH:
total_storage, free_storage = SystemUtils.space_usage(
[Path(path) for path in settings.LIBRARY_PATH.split(",")]
)
else:
total_storage, free_storage = 0, 0
total, available = 0, 0
dirs = DirectoryHelper().get_dirs()
if not dirs:
return schemas.Storage(total_storage=total, used_storage=total - available)
storages = set([d.library_storage for d in dirs if d.library_storage])
for _storage in storages:
_usage = StorageChain().storage_usage(_storage)
if _usage:
total += _usage.total
available += _usage.available
return schemas.Storage(
total_storage=total_storage,
used_storage=total_storage - free_storage
total_storage=total,
used_storage=total - available
)
@router.get("/storage2", summary="本地存储空间API_TOKEN", response_model=schemas.Storage)
def storage2(_: Annotated[str, Depends(verify_apitoken)]) -> Any:
"""
查询本地存储空间信息 API_TOKEN认证?token=xxx
"""
return storage()
@router.get("/processes", summary="进程信息", response_model=List[schemas.ProcessInfo])
def processes(_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
@@ -62,71 +88,62 @@ def processes(_: schemas.TokenPayload = Depends(verify_token)) -> Any:
@router.get("/downloader", summary="下载器信息", response_model=schemas.DownloaderInfo)
def downloader(db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
def downloader(name: Optional[str] = None, _: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
查询下载器信息
"""
transfer_info = DashboardChain(db).downloader_info()
free_space = SystemUtils.free_space(Path(settings.DOWNLOAD_PATH))
return schemas.DownloaderInfo(
download_speed=transfer_info.download_speed,
upload_speed=transfer_info.upload_speed,
download_size=transfer_info.download_size,
upload_size=transfer_info.upload_size,
free_space=free_space
)
# 下载目录空间
download_dirs = DirectoryHelper().get_local_download_dirs()
_, free_space = SystemUtils.space_usage([Path(d.download_path) for d in download_dirs])
# 下载器信息
downloader_info = schemas.DownloaderInfo()
transfer_infos = DashboardChain().downloader_info(name)
if transfer_infos:
for transfer_info in transfer_infos:
downloader_info.download_speed += transfer_info.download_speed
downloader_info.upload_speed += transfer_info.upload_speed
downloader_info.download_size += transfer_info.download_size
downloader_info.upload_size += transfer_info.upload_size
downloader_info.free_space = free_space
return downloader_info
@router.get("/downloader2", summary="下载器信息API_TOKEN", response_model=schemas.DownloaderInfo)
def downloader2(_: Annotated[str, Depends(verify_apitoken)]) -> Any:
"""
查询下载器信息 API_TOKEN认证?token=xxx
"""
return downloader()
@router.get("/schedule", summary="后台服务", response_model=List[schemas.ScheduleInfo])
def schedule(_: schemas.TokenPayload = Depends(verify_token)) -> Any:
async def schedule(_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
查询后台服务信息
"""
# 返回计时任务
schedulers = []
# 去重
added = []
jobs = Scheduler().list()
# 按照下次运行时间排序
jobs.sort(key=lambda x: x.next_run_time)
for job in jobs:
if job.name not in added:
added.append(job.name)
else:
continue
if not StringUtils.is_chinese(job.name):
continue
if not job.next_run_time:
status = "已停止"
next_run = ""
else:
next_run = TimerUtils.time_difference(job.next_run_time)
if not next_run:
status = "正在运行"
else:
status = "阻塞" if job.pending else "等待"
schedulers.append(schemas.ScheduleInfo(
id=job.id,
name=job.name,
status=status,
next_run=next_run
))
return Scheduler().list()
return schedulers
@router.get("/schedule2", summary="后台服务API_TOKEN", response_model=List[schemas.ScheduleInfo])
async def schedule2(_: Annotated[str, Depends(verify_apitoken)]) -> Any:
"""
查询下载器信息 API_TOKEN认证?token=xxx
"""
return await schedule()
@router.get("/transfer", summary="文件整理统计", response_model=List[int])
def transfer(days: int = 7, db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
async def transfer(days: Optional[int] = 7,
db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
查询文件整理统计信息
"""
transfer_stat = TransferHistory.statistic(db, days)
transfer_stat = await TransferHistory.async_statistic(db, days)
return [stat[1] for stat in transfer_stat]
@router.get("/cpu", summary="获取当前CPU使用率", response_model=int)
@router.get("/cpu", summary="获取当前CPU使用率", response_model=float)
def cpu(_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
获取当前CPU使用率
@@ -134,9 +151,41 @@ def cpu(_: schemas.TokenPayload = Depends(verify_token)) -> Any:
return SystemUtils.cpu_usage()
@router.get("/memory", summary="获取当前内存使用率", response_model=int)
@router.get("/cpu2", summary="获取当前CPU使用率API_TOKEN", response_model=float)
def cpu2(_: Annotated[str, Depends(verify_apitoken)]) -> Any:
"""
获取当前CPU使用率 API_TOKEN认证?token=xxx
"""
return cpu()
@router.get("/memory", summary="获取当前内存使用量和使用率", response_model=List[int])
def memory(_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
获取当前内存使用率
"""
return SystemUtils.memory_usage()
@router.get("/memory2", summary="获取当前内存使用量和使用率API_TOKEN", response_model=List[int])
def memory2(_: Annotated[str, Depends(verify_apitoken)]) -> Any:
"""
获取当前内存使用率 API_TOKEN认证?token=xxx
"""
return memory()
@router.get("/network", summary="获取当前网络流量", response_model=List[int])
def network(_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
获取当前网络流量上行和下行流量单位bytes/s
"""
return SystemUtils.network_usage()
@router.get("/network2", summary="获取当前网络流量API_TOKEN", response_model=List[int])
def network2(_: Annotated[str, Depends(verify_apitoken)]) -> Any:
"""
获取当前网络流量 API_TOKEN认证?token=xxx
"""
return network()

View File

@@ -0,0 +1,130 @@
from typing import Any, List, Optional
from fastapi import APIRouter, Depends
from app import schemas
from app.chain.bangumi import BangumiChain
from app.chain.douban import DoubanChain
from app.chain.tmdb import TmdbChain
from app.core.event import eventmanager
from app.core.security import verify_token
from app.schemas import DiscoverSourceEventData
from app.schemas.types import ChainEventType, MediaType
router = APIRouter()
@router.get("/source", summary="获取探索数据源", response_model=List[schemas.DiscoverMediaSource])
def source(_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
获取探索数据源
"""
# 广播事件,请示额外的探索数据源支持
event_data = DiscoverSourceEventData()
event = eventmanager.send_event(ChainEventType.DiscoverSource, event_data)
# 使用事件返回的上下文数据
if event and event.event_data:
event_data: DiscoverSourceEventData = event.event_data
if event_data.extra_sources:
return event_data.extra_sources
return []
@router.get("/bangumi", summary="探索Bangumi", response_model=List[schemas.MediaInfo])
async def bangumi(type: Optional[int] = 2,
cat: Optional[int] = None,
sort: Optional[str] = 'rank',
year: Optional[str] = None,
page: Optional[int] = 1,
count: Optional[int] = 30,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
探索Bangumi
"""
medias = await BangumiChain().async_discover(type=type, cat=cat, sort=sort, year=year,
limit=count, offset=(page - 1) * count)
if medias:
return [media.to_dict() for media in medias]
return []
@router.get("/douban_movies", summary="探索豆瓣电影", response_model=List[schemas.MediaInfo])
async def douban_movies(sort: Optional[str] = "R",
tags: Optional[str] = "",
page: Optional[int] = 1,
count: Optional[int] = 30,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
浏览豆瓣电影信息
"""
movies = await DoubanChain().async_douban_discover(mtype=MediaType.MOVIE,
sort=sort, tags=tags, page=page, count=count)
return [media.to_dict() for media in movies] if movies else []
@router.get("/douban_tvs", summary="探索豆瓣剧集", response_model=List[schemas.MediaInfo])
async def douban_tvs(sort: Optional[str] = "R",
tags: Optional[str] = "",
page: Optional[int] = 1,
count: Optional[int] = 30,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
浏览豆瓣剧集信息
"""
tvs = await DoubanChain().async_douban_discover(mtype=MediaType.TV,
sort=sort, tags=tags, page=page, count=count)
return [media.to_dict() for media in tvs] if tvs else []
@router.get("/tmdb_movies", summary="探索TMDB电影", response_model=List[schemas.MediaInfo])
async def tmdb_movies(sort_by: Optional[str] = "popularity.desc",
with_genres: Optional[str] = "",
with_original_language: Optional[str] = "",
with_keywords: Optional[str] = "",
with_watch_providers: Optional[str] = "",
vote_average: Optional[float] = 0.0,
vote_count: Optional[int] = 0,
release_date: Optional[str] = "",
page: Optional[int] = 1,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
浏览TMDB电影信息
"""
movies = await TmdbChain().async_tmdb_discover(mtype=MediaType.MOVIE,
sort_by=sort_by,
with_genres=with_genres,
with_original_language=with_original_language,
with_keywords=with_keywords,
with_watch_providers=with_watch_providers,
vote_average=vote_average,
vote_count=vote_count,
release_date=release_date,
page=page)
return [movie.to_dict() for movie in movies] if movies else []
@router.get("/tmdb_tvs", summary="探索TMDB剧集", response_model=List[schemas.MediaInfo])
async def tmdb_tvs(sort_by: Optional[str] = "popularity.desc",
with_genres: Optional[str] = "",
with_original_language: Optional[str] = "",
with_keywords: Optional[str] = "",
with_watch_providers: Optional[str] = "",
vote_average: Optional[float] = 0.0,
vote_count: Optional[int] = 0,
release_date: Optional[str] = "",
page: Optional[int] = 1,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
浏览TMDB剧集信息
"""
tvs = await TmdbChain().async_tmdb_discover(mtype=MediaType.TV,
sort_by=sort_by,
with_genres=with_genres,
with_original_language=with_original_language,
with_keywords=with_keywords,
with_watch_providers=with_watch_providers,
vote_average=vote_average,
vote_count=vote_count,
release_date=release_date,
page=page)
return [tv.to_dict() for tv in tvs] if tvs else []

View File

@@ -1,152 +1,79 @@
from typing import List, Any
from typing import Any, List, Optional
from fastapi import APIRouter, Depends, Response
from sqlalchemy.orm import Session
from fastapi import APIRouter, Depends
from app import schemas
from app.chain.douban import DoubanChain
from app.core.config import settings
from app.core.context import MediaInfo
from app.core.security import verify_token
from app.db import get_db
from app.schemas import MediaType
from app.utils.http import RequestUtils
router = APIRouter()
@router.get("/img/{imgurl:path}", summary="豆瓣图片代理")
def douban_img(imgurl: str) -> Any:
@router.get("/person/{person_id}", summary="人物详情", response_model=schemas.MediaPerson)
async def douban_person(person_id: int,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
豆瓣图片代理
根据人物ID查询人物详情
"""
if not imgurl:
return None
response = RequestUtils(headers={
'Referer': "https://movie.douban.com/"
}, ua=settings.USER_AGENT).get_res(url=imgurl)
if response:
return Response(content=response.content, media_type="image/jpeg")
return None
return await DoubanChain().async_person_detail(person_id=person_id)
@router.get("/recognize/{doubanid}", summary="豆瓣ID识别", response_model=schemas.Context)
def recognize_doubanid(doubanid: str,
db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
@router.get("/person/credits/{person_id}", summary="人物参演作品", response_model=List[schemas.MediaInfo])
async def douban_person_credits(person_id: int,
page: Optional[int] = 1,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
根据豆瓣ID识别媒体信息
根据人物ID查询人物参演作品
"""
# 识别媒体信息
context = DoubanChain(db).recognize_by_doubanid(doubanid=doubanid)
if context:
return context.to_dict()
medias = await DoubanChain().async_person_credits(person_id=person_id, page=page)
if medias:
return [media.to_dict() for media in medias]
return []
@router.get("/credits/{doubanid}/{type_name}", summary="豆瓣演员阵容", response_model=List[schemas.MediaPerson])
async def douban_credits(doubanid: str,
type_name: str,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
根据豆瓣ID查询演员阵容type_name: 电影/电视剧
"""
mediatype = MediaType(type_name)
if mediatype == MediaType.MOVIE:
return await DoubanChain().async_movie_credits(doubanid=doubanid)
elif mediatype == MediaType.TV:
return await DoubanChain().async_tv_credits(doubanid=doubanid)
return []
@router.get("/recommend/{doubanid}/{type_name}", summary="豆瓣推荐电影/电视剧", response_model=List[schemas.MediaInfo])
async def douban_recommend(doubanid: str,
type_name: str,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
根据豆瓣ID查询推荐电影/电视剧type_name: 电影/电视剧
"""
mediatype = MediaType(type_name)
if mediatype == MediaType.MOVIE:
medias = await DoubanChain().async_movie_recommend(doubanid=doubanid)
elif mediatype == MediaType.TV:
medias = await DoubanChain().async_tv_recommend(doubanid=doubanid)
else:
return schemas.Context()
@router.get("/showing", summary="豆瓣正在热映", response_model=List[schemas.MediaInfo])
def movie_showing(page: int = 1,
count: int = 30,
db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
浏览豆瓣正在热映
"""
movies = DoubanChain(db).movie_showing(page=page, count=count)
if not movies:
return []
medias = [MediaInfo(douban_info=movie) for movie in movies]
return [media.to_dict() for media in medias]
@router.get("/movies", summary="豆瓣电影", response_model=List[schemas.MediaInfo])
def douban_movies(sort: str = "R",
tags: str = "",
page: int = 1,
count: int = 30,
db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
浏览豆瓣电影信息
"""
movies = DoubanChain(db).douban_discover(mtype=MediaType.MOVIE,
sort=sort, tags=tags, page=page, count=count)
if not movies:
return []
medias = [MediaInfo(douban_info=movie) for movie in movies]
return [media.to_dict() for media in medias
if media.poster_path
and "movie_large.jpg" not in media.poster_path
and "tv_normal.png" not in media.poster_path]
@router.get("/tvs", summary="豆瓣剧集", response_model=List[schemas.MediaInfo])
def douban_tvs(sort: str = "R",
tags: str = "",
page: int = 1,
count: int = 30,
db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
浏览豆瓣剧集信息
"""
tvs = DoubanChain(db).douban_discover(mtype=MediaType.TV,
sort=sort, tags=tags, page=page, count=count)
if not tvs:
return []
medias = [MediaInfo(douban_info=tv) for tv in tvs]
return [media.to_dict() for media in medias
if media.poster_path
and "movie_large.jpg" not in media.poster_path
and "tv_normal.jpg" not in media.poster_path
and "tv_large.jpg" not in media.poster_path]
@router.get("/movie_top250", summary="豆瓣电影TOP250", response_model=List[schemas.MediaInfo])
def movie_top250(page: int = 1,
count: int = 30,
db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
浏览豆瓣剧集信息
"""
movies = DoubanChain(db).movie_top250(page=page, count=count)
return [MediaInfo(douban_info=movie).to_dict() for movie in movies]
@router.get("/tv_weekly_chinese", summary="豆瓣国产剧集周榜", response_model=List[schemas.MediaInfo])
def tv_weekly_chinese(page: int = 1,
count: int = 30,
db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
中国每周剧集口碑榜
"""
tvs = DoubanChain(db).tv_weekly_chinese(page=page, count=count)
return [MediaInfo(douban_info=tv).to_dict() for tv in tvs]
@router.get("/tv_weekly_global", summary="豆瓣全球剧集周榜", response_model=List[schemas.MediaInfo])
def tv_weekly_global(page: int = 1,
count: int = 30,
db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
全球每周剧集口碑榜
"""
tvs = DoubanChain(db).tv_weekly_global(page=page, count=count)
return [MediaInfo(douban_info=tv).to_dict() for tv in tvs]
if medias:
return [media.to_dict() for media in medias]
return []
@router.get("/{doubanid}", summary="查询豆瓣详情", response_model=schemas.MediaInfo)
def douban_info(doubanid: str,
db: Session = Depends(get_db),
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
async def douban_info(doubanid: str,
_: schemas.TokenPayload = Depends(verify_token)) -> Any:
"""
根据豆瓣ID查询豆瓣媒体信息
"""
doubaninfo = DoubanChain(db).douban_info(doubanid=doubanid)
doubaninfo = await DoubanChain().async_douban_info(doubanid=doubanid)
if doubaninfo:
return MediaInfo(douban_info=doubaninfo).to_dict()
else:

Some files were not shown because too many files have changed in this diff Show More