├── V2 ├── src │ ├── Type1.png │ ├── Type2.png │ ├── dir.png │ ├── movie.png │ ├── series.jpg │ ├── password.jpg │ ├── WordsWrite1.png │ ├── WordsWrite2.png │ ├── WordsWrite3.png │ └── WordsWrite4.png └── docker-compose.yml ├── Words ├── anime.txt └── Audiences.txt ├── docs └── tencent_notify.md └── src └── tencent_subscribe.py /V2/src/Type1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4Nest/MoviePilot-Settings/HEAD/V2/src/Type1.png -------------------------------------------------------------------------------- /V2/src/Type2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4Nest/MoviePilot-Settings/HEAD/V2/src/Type2.png -------------------------------------------------------------------------------- /V2/src/dir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4Nest/MoviePilot-Settings/HEAD/V2/src/dir.png -------------------------------------------------------------------------------- /V2/src/movie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4Nest/MoviePilot-Settings/HEAD/V2/src/movie.png -------------------------------------------------------------------------------- /V2/src/series.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4Nest/MoviePilot-Settings/HEAD/V2/src/series.jpg -------------------------------------------------------------------------------- /V2/src/password.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4Nest/MoviePilot-Settings/HEAD/V2/src/password.jpg -------------------------------------------------------------------------------- /V2/src/WordsWrite1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4Nest/MoviePilot-Settings/HEAD/V2/src/WordsWrite1.png -------------------------------------------------------------------------------- /V2/src/WordsWrite2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4Nest/MoviePilot-Settings/HEAD/V2/src/WordsWrite2.png -------------------------------------------------------------------------------- /V2/src/WordsWrite3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4Nest/MoviePilot-Settings/HEAD/V2/src/WordsWrite3.png -------------------------------------------------------------------------------- /V2/src/WordsWrite4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4Nest/MoviePilot-Settings/HEAD/V2/src/WordsWrite4.png -------------------------------------------------------------------------------- /Words/anime.txt: -------------------------------------------------------------------------------- 1 | \[Movie\] 2 | episode\.\d{1} 3 | \.(第\d{1,2}集)\. => \1 4 | (?i)Season( *)0?(\d+) => S\2 5 | (?<=SBSUB.*DR.*?)- => part 6 | \[CHS\_CHT\_JP\]\(\w{8}\) 7 | \[CHT\_JP\]\(\w{8}\) 8 | \[CHS\_JP\]\(\w{8}\) 9 | chs&jpn => jpsc 10 | cht&jpn => jptc 11 | \[SBSUB\]\[CONAN\]\[DR => [银色子弹字幕组][名侦探柯南][S01E 12 | \[SBSUB\]\[CONAN\]\[ => [银色子弹字幕组][名侦探柯南][S01E 13 | (?<=(VCB-Studio|ANi).*?)2nd Season => S02 14 | (?<=(VCB-Studio|ANi).*?)IV => S04 15 | (?<=(VCB-Studio|ANi).*?)III => S03 16 | (?<=(VCB-Studio|ANi).*?)II => S02 17 | [【\[](Fin|END)[】\]]|(?:|\s|\s-\s)(Fin|END)(?=\])|(?<=\d{1,2})_?(Fin|END) 18 | (?<=[\[【].*?(?:组|組|sub|S(?:UB|ub|tudio)|Raw(?:|s)|社)[\]】])(?:(?:\[|【|★|)\d{1,2}月新番(?:\]|】|★|)|)[\[【](.*?)[\]】] => \1 19 | (?<=[\W_])(CR|Baha|KKTV|Abema|B-Global|Sentai|MyVideo|AMZN|KKTV|friDay|DSNP|LINETV|NF|Viu)(?=[\W_]) => -\1 20 | (?i)(CHS|GB|SC)(&|_|&|\x20)(CHT|BIG5|TC)(&|_|&|\x20)JA?PN? => 简繁日内封 21 | (?i)(CHS|GB|SC)_JA?PN?(&|&|\x20)(CHT|BIG5|TC)_JA?PN? => 简繁日内封 22 | (?i)(CHS|GB|SC)(&|&|\x20)(CHT|BIG5|TC) => 简繁内封 23 | (?i)(CHS|GB|SC)(_|&|&|\x20)JA?PN? => 简日双语 24 | (?i)\[JA?PN?(_|&|&|\x20)?(SC|CHS|GB)\] => [简日双语] 25 | (.*)(VCB-Studio)(.*)(Ma10p_?|Hi10p_?)(.*) => \1\2\3\5 26 | S(eason)? ?0?([2-9]) *\[(OVA|OAD)0?\(?(\d)?\)?\] => S0E\2\4 27 | (S(eason)? ?0?1 *)?\[(OVA|OAD)(\d+)?\] => S0E\4 28 | (S(eason)? ?\d+)? *\[\d+\(?(OVA|OAD)\)?\] => S0 29 | (?<=[\W_])4(?:k|K)(?=[\W_]) => 2160p 30 | (?i)\bSBSUB\b => 银色子弹字幕组 31 | (?i)\bNekomoe kisstan\b => 喵萌奶茶屋 32 | (?i)\bOPFansMaplesnow\b => OPFans枫雪动漫 33 | (?i)\bSakurato\b|樱都字幕组|桜都字幕组|桜都 => 桜都字幕组 34 | (?i)\bHaruhana\b => ❀拨雪寻春❀ 35 | (?<=[\W_])CR(?=[\W_]) => Crunchyroll 36 | (?<=[\W_])NF(?=[\W_]) => Netflix 37 | (?<=[\W_])AMZN(?=[\W_]) => Amazon 38 | (?<=[\W_])((H?MAX)|ATVP)(?=[\W_]) => -\1 39 | (?<=[\W_])ATVP(?=[\W_]) => AppleTV+ 40 | (?<=[\W_])DSNP(?=[\W_]) => Disney+ 41 | (?<=(1080p|2160p)\.)Max\. => -MAX. 42 | (?<=(1080p|2160p)\.)iT\. => -iTunes. 43 | (?<=S\d{2}E\d{2}).+(?=(2160|1080)p.+NTb) => 44 | (? -\1 45 | -------------------------------------------------------------------------------- /V2/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | 3 | moviepilot: 4 | stdin_open: true 5 | tty: true 6 | container_name: moviepilot-v2 7 | hostname: moviepilot-v2 8 | ports: 9 | - '4500:4500' 10 | - '4501:4501' 11 | - '9096:9096' 12 | volumes: 13 | - '/mnt/disk1/Media:/media' #媒体 14 | - './config:/config' #持久化配置 15 | - './core:/moviepilot/.cache/ms-playwright' #内核浏览器 16 | - '/var/run/docker.sock:/var/run/docker.sock:ro' #重启MP权限 17 | environment: 18 | - 'NGINX_PORT=4500' 19 | - 'PORT=4501' 20 | - 'PUID=0' 21 | - 'PGID=0' 22 | - 'UMASK=000' 23 | - 'TZ=Asia/Shanghai' 24 | - 'MOVIEPILOT_AUTO_UPDATE=true' 25 | - 'SUPERUSER=admin' 26 | - 'PROXY_HOST=http://192.168.2.2:7890' #代理 27 | - 'DB_TYPE=postgresql' 28 | - 'DB_POSTGRESQL_HOST=postgresql' 29 | - 'DB_POSTGRESQL_PORT=5432' 30 | - 'DB_POSTGRESQL_DATABASE=moviepilot' 31 | - 'DB_POSTGRESQL_USERNAME=moviepilot' 32 | - 'DB_POSTGRESQL_PASSWORD=moviepilot' 33 | - 'CACHE_BACKEND_TYPE=redis' 34 | - 'CACHE_BACKEND_URL=redis://:moviepilot@redis:6379' 35 | restart: always 36 | depends_on: 37 | postgresql: 38 | condition: service_healthy 39 | redis: 40 | condition: service_healthy 41 | image: jxxghp/moviepilot-v2:latest 42 | 43 | redis: 44 | volumes: 45 | - ./redis/data:/data 46 | image: redis 47 | command: redis-server --save 600 1 --requirepass moviepilot 48 | healthcheck: 49 | test: ["CMD", "redis-cli", "--raw", "incr", "ping"] 50 | interval: 10s 51 | timeout: 5s 52 | retries: 5 53 | 54 | postgresql: 55 | image: postgres:17.6 56 | restart: always 57 | environment: 58 | POSTGRES_DB: moviepilot 59 | POSTGRES_USER: moviepilot 60 | POSTGRES_PASSWORD: moviepilot 61 | volumes: 62 | - ./postgresql:/var/lib/postgresql/data 63 | healthcheck: 64 | test: ["CMD-SHELL", "pg_isready -U moviepilot -d moviepilot"] 65 | interval: 10s 66 | timeout: 5s 67 | retries: 5 68 | -------------------------------------------------------------------------------- /docs/tencent_notify.md: -------------------------------------------------------------------------------- 1 | # QQ订阅+通知教程 2 | 3 | 本教程用到的两个项目 4 | 5 | 1. [llonebot-docker](https://github.com/LLOneBot/llonebot-docker) 6 | 2. [LiteyukiBot](https://github.com/LiteyukiStudio/LiteyukiBot) 7 | 8 | ## QQ订阅 9 | 10 | ### 1.构建docker 11 | 12 | cd进入compose的目录 13 | 14 | 使用`git clone https://github.com/LiteyukiStudio/LiteyukiBot --depth=1`拉取代码 15 | 16 | 群晖可以去套件中心安装Git 17 | 18 | compose启动 19 | 20 | ``` 21 | version: '3' 22 | services: 23 | llonebot-docker: 24 | image: mlikiowa/llonebot-docker:vnc 25 | tty: true 26 | container_name: llonebot-docker 27 | restart: always 28 | ports: 29 | - "5900:5900" 30 | - "6099:6099" 31 | - "3000:3000" 32 | - "3001:3001" 33 | environment: 34 | - TZ=Asia/Shanghai 35 | - VNC_PASSWD=yourpassword 36 | volumes: 37 | - ./LiteLoader/:/opt/QQ/resources/app/LiteLoader 38 | 39 | 40 | liteyukibot: 41 | image: git.liteyuki.icu/bot/app:latest 42 | restart: always 43 | ports: 44 | - "20216:20216" 45 | volumes: 46 | - ./LiteyukiBot:/liteyukibot 47 | - ./LiteyukiBot/.cache:/root/.cache 48 | environment: 49 | - TZ=Asia/Shanghai 50 | # - http_proxy=http://192.168.2.5:7890 51 | # - https_proxy=http://192.168.2.5:7890 52 | ``` 53 | 54 | ### 2.修改liteyukibot配置文件 55 | 56 | 修改`LiteyukiBot/config/default.yml` 57 | 58 | `host`修改为`0.0.0.0` 59 | 60 | 添加一行 61 | 62 | `superusers: ["your qq"]` 63 | 64 | ### 3.MP订阅插件 65 | 66 | [下载](https://github.com/4Nest/MoviePilot-Settings/blob/main/src/tencent_subscribe.py) 67 | 68 | #### 修改插件 69 | 70 | 将插件中的mp_url、username、password修改为你自己的 71 | 72 | #### 添加插件 73 | 74 | 进入`LiteyukiBot/src/liteyuki_plugins/nonebot/nonebot_plugins` 75 | 76 | 创建文件夹`nonebot_plugin_subscribe` 77 | 78 | 将插件重命名为`__init__.py`放入文件夹中 79 | 80 | docker ps找到容器 81 | 82 | 进入容器 docker exec -it xxxx /bin/bash 83 | 84 | 输入pip install requests 85 | 86 | 最后重启容器 87 | 88 | ### 4.登录QQ 89 | 90 | 使用VNC登录`x.x.x.x:5900` 91 | 92 | 密码为前面环境变量中设置的密码 93 | 94 | ### 5.设置LLOneBot插件 95 | 96 | 登录后进入设置中的LLOneBot 97 | 98 | 打开**启用WebSocket服务** 99 | 100 | 添加地址:`ws://x.x.x.x:20216/onebot/v11/ws` 101 | 102 | 点击保存 103 | 104 | ## QQ通知 105 | 106 | ### 1.安装插件 107 | 108 | 插件市场安装**聚合消息通知** 109 | 110 | ### 2.配置插件 111 | 112 | 选中ONEBOT-11 113 | 114 | 服务器地址:`http://x.x.x.x:3000` 115 | -------------------------------------------------------------------------------- /Words/Audiences.txt: -------------------------------------------------------------------------------- 1 | #此词表仅适用于Audiences资源,其他未检测 2 | #此词表仅适用于Audiences资源,其他未检测 3 | #此词表仅适用于Audiences资源,其他未检测 4 | 5 | #从零开始的异世界【ADWeb】 6 | Re.Zero.kara.Hajimeru.Isekai.Seikatsu.S03 => Re.Zero.kara.Hajimeru.Isekai.Seikatsu.S01 && S01 <> 2024 >> EP+50 7 | 8 | #乱马【ADWeb】 9 | Ranma.S01(?=.*2024) => Ranma.½.S01 10 | 11 | #斗破苍穹【ADWeb】 12 | 斗破苍穹.年番.Fights.Break.Sphere.S05 => 斗破苍穹.Fights.Break.Sphere.S05 13 | 14 | #香格里拉边境S02【ADWeb】 15 | ShangriLa.Frontier.S02E => ShangriLa.Frontier.S01E && S01 <> 2024 >> EP+25 16 | 17 | #吞噬星空【ADWeb】 18 | (?<=Swallowed.Star.S05.*?)2024 => 2020 19 | (?<=Swallowed.Star.S04.*?)2023 => 2020 20 | (?<=Swallowed.Star.S03.*?)2022 => 2020 21 | (?<=Swallowed.Star.S02.*?)2021 => 2020 22 | Swallowed.Star.S05(?=.*ADWeb) => Swallowed.Star.S01 23 | Swallowed.Star.S04 => Swallowed.Star.S01 && S01 <> 2020 >> EP+85 24 | Swallowed.Star.S03 => Swallowed.Star.S01 25 | Swallowed.Star.S02 => Swallowed.Star.S01 26 | 27 | #一念永恒【ADWeb】 28 | (?<=A.Will.Eternal.S03.*?)2024 => 2020 29 | A.Will.Eternal.S03E => A.Will.Eternal.S01E && S01E <> 2020 >> EP+106 30 | (?<=Yi.Nian.Yong.Heng.S03.*?)2024 => 2020 31 | Yi.Nian.Yong.Heng.S03E => Yi.Nian.Yong.Heng.S01E && S01E <> 2020 >> EP+106 32 | 33 | #白夜追凶【ADWeb】 34 | Day.and.Night(?=.+ADWeb) => 白夜追凶.Day.and.Night 35 | 36 | #沧元图【ADWeb】 37 | Azure.Legacy.S01E(?=.+ADWeb) => Azure.Legacy.S02E && S02E <> 2023 >> EP-30 38 | 39 | #少年白马醉春风【ADWeb】 40 | 少年白马醉春风.The.Young.Brewmaster(?:s|'s).Adventure.S02E(?=.+ADWeb) => The.Young.Brewmasters.Adventure.S02E && S02E <> 2024 >> EP-20 41 | 42 | #死神【ADWeb】 43 | (?i)BLEACH.Sennen.Kessen.hen.S01(?=.*ADWeb) => BLEACH.Sennen.Kessen.hen.S02 {[tmdbid=30984;type=tv;s=2]} 44 | (?i)BLEACH.Sennen.Kessenhen.S01(?=.*ADWeb) => BLEACH.Sennen.Kessen.hen.S02 {[tmdbid=30984;type=tv;s=2]} 45 | 46 | #2025年1月新番【ADWeb】 47 | #最弱技能《果实大师》 ~关于能无限食用技能果实(吃了就会死)这件事~【ADWeb】 48 | Hazure.Skill.Kinomi.Master.Skill.no.Mi.Tabetara.Shinu.wo.Mugen.ni.Taberareru.You.ni.Natta.Ken.Nitsuite => Kinomi.Master 49 | (?<=Kinomi.Master.S01.*?)2025 => 2024 50 | #S级怪兽《贝希摩斯》被误认成小猫,成为精灵女孩的骑士(宠物)一起生活【ADWeb】 51 | (?<=S-Rank.Monster.no.Behemoth.Dakedo.Neko.to.Machigawarete.Elf.Musume.no.Pet.to.Shite.Kurashitemasu.S01.*?)2024 => 2025 52 | 53 | #假面骑士加布【ADWeb】 54 | 假面骑士加布.Kamen.Rider.Gavv.S01 => Kamen.Rider.Gavv.S35 55 | Kamen.Rider.Gavv.S01 => Kamen.Rider.Gavv.S35 56 | 57 | #药屋少女的呢喃【ADWeb】 58 | (?<=Kusuriya.no.Hitorigoto.S02.+?)2025 => 2024 59 | Kusuriya.no.Hitorigoto.S02 => Kusuriya.no.Hitorigoto.S01 && S01E <> 2024 >> EP+24 -------------------------------------------------------------------------------- /src/tencent_subscribe.py: -------------------------------------------------------------------------------- 1 | from nonebot import on_command, get_driver 2 | from nonebot.typing import T_State 3 | from nonebot.adapters import Bot, Event 4 | import requests 5 | import json 6 | from liteyuki.plugin import PluginMetadata, PluginType 7 | 8 | # 获取配置文件中的信息 9 | # config = get_driver().config 10 | mp_url = "http://192.168.2.110:4501" 11 | username = "Tencent" 12 | password = "Tencent" 13 | 14 | # 定义插件元数据 15 | __plugin_meta__ = PluginMetadata( 16 | name="Subscribe", # 插件名称 17 | version="1.0.0", # 插件版本 18 | description="Movie Subscribe", # 插件描述 19 | type=PluginType.SERVICE # 插件类型 20 | ) 21 | 22 | 23 | # 获取MoviePilot-Token 24 | async def get_access_token(url, username, password): 25 | url = f"{url}/api/v1/login/access-token" 26 | payload = { 27 | "username": username, 28 | "password": password 29 | } 30 | try: 31 | response = requests.post(url, data=payload) 32 | response.raise_for_status() 33 | json_data = response.json() 34 | access_token = json_data.get("access_token") 35 | return access_token 36 | except requests.exceptions.RequestException as e: 37 | print(f"Error fetching access token: {e}") 38 | return None 39 | 40 | # 处理返回的影片 41 | async def search_media_info(url, media_name, mp_token): 42 | search_url = f"{url}/api/v1/media/search?title={media_name}" 43 | headers = {'Authorization': mp_token} 44 | try: 45 | response = requests.get(search_url, headers=headers) 46 | response.raise_for_status() 47 | movies = response.json() 48 | return movies 49 | except requests.exceptions.RequestException as e: 50 | print(f"Error searching movies: {e}") 51 | return None 52 | # 列出所有季 53 | async def list_all_seasons(url, tmdbid, mp_token): 54 | season_url = f'{url}/api/v1/tmdb/seasons/{tmdbid}' 55 | headers = { 56 | 'Authorization': f'{mp_token}', 57 | 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" 58 | } 59 | try: 60 | response = requests.get(season_url, headers=headers) 61 | response.raise_for_status() # 检查请求是否成功 62 | # 解析响应的JSON数据 63 | seasons = response.json() 64 | return seasons 65 | except requests.exceptions.RequestException as e: 66 | print(f"Error: {e}") 67 | return None 68 | # 订阅电影 69 | async def subscribe_movie(url, movie, mp_token): 70 | subscribe_url = f"{url}/api/v1/subscribe/" 71 | headers = { 72 | 'Authorization': mp_token, 73 | 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" 74 | } 75 | body = { 76 | "name": movie['title'], 77 | "tmdbid": movie['tmdb_id'], 78 | "type": "电影" 79 | } 80 | try: 81 | response = requests.post(subscribe_url, json=body, headers=headers) 82 | response.raise_for_status() 83 | json_data = response.json() 84 | return json_data.get("success") 85 | except requests.exceptions.RequestException as e: 86 | print(f"Error subscribing to movie: {e}") 87 | return False 88 | 89 | # 订阅剧集 90 | async def subscribe_series(url, movie, season, mp_token): 91 | subscribe_url = f"{url}/api/v1/subscribe/" 92 | headers = { 93 | 'Authorization': mp_token, 94 | 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" 95 | } 96 | season = int(season) 97 | body = { 98 | "name": movie['title'], 99 | "tmdbid": movie['tmdb_id'], 100 | "type": "电视剧", 101 | "season": season 102 | } 103 | try: 104 | response = requests.post(subscribe_url, json=body, headers=headers) 105 | response.raise_for_status() 106 | json_data = response.json() 107 | return json_data.get("success") 108 | except requests.exceptions.RequestException as e: 109 | print(f"Error subscribing to movie: {e}") 110 | return False 111 | 112 | # 创建查询电影的命令处理器 113 | search_movie = on_command("sub") 114 | 115 | @search_movie.handle() 116 | async def handle_first_receive(bot: Bot, event: Event, state: T_State): 117 | args = str(event.get_message()).strip() 118 | if args: 119 | movie_name = args.replace("/sub ", "", 1) # 使用str.replace()移除"/sub ",第三个参数1表示只替换第一次出现的"/sub " 120 | state["movie_name"] = movie_name 121 | 122 | @search_movie.got("movie_name", prompt="你要查询哪部影片?") 123 | async def handle_movie_name(bot: Bot, event: Event, state: T_State): 124 | movie_name = state["movie_name"] 125 | print(movie_name) 126 | access_token = await get_access_token(mp_url, username, password) 127 | if access_token: 128 | mp_token = "Bearer " + access_token 129 | movies = await search_media_info(mp_url, movie_name, mp_token) 130 | if movies: 131 | movie_list = "\n".join([f"{i+1}. {movie['title']} ({movie['year']})\n" 132 | f"{movie['detail_link']}\n" for i, movie in enumerate(movies)]) 133 | await bot.send( 134 | event=event, 135 | message=f"查询到的影片如下,请回复序号进行订阅:\n提示:同一部片,请使用themoviedb链接的序号\n{movie_list}" 136 | ) 137 | state["movies"] = movies 138 | else: 139 | await search_movie.finish("没有查询到影片,请检查名字。") 140 | else: 141 | await search_movie.finish("获取访问令牌失败。") 142 | 143 | @search_movie.got("movie_index", prompt="请输入序号进行订阅\n!!!别选Douban的,选TMDB的!!!\n输入0退出:") 144 | async def handle_movie_index(bot: Bot, event: Event, state: T_State): 145 | movie_index = str(event.get_message()).strip() # 将 Message 对象转换为字符串并去除空格 146 | 147 | # 如果用户输入0,则结束对话 148 | if movie_index == "0": 149 | await search_movie.finish("操作已取消。") 150 | return 151 | 152 | try: 153 | selected_index = int(movie_index) - 1 154 | movies = state["movies"] 155 | if 0 <= selected_index < len(movies): 156 | selected_movie = movies[selected_index] 157 | access_token = await get_access_token(mp_url, username, password) 158 | if access_token: 159 | mp_token = "Bearer " + access_token 160 | if selected_movie['type'] == "电视剧": 161 | # 如果是电视剧,获取所有季数 162 | seasons = await list_all_seasons(mp_url, selected_movie['tmdb_id'], mp_token) 163 | if seasons: 164 | season_list = "\n".join([f"第 {season['season_number']} 季 {season['name']}" for season in seasons]) 165 | await bot.send( 166 | event=event, 167 | message=f"请选择季数:\n{season_list}" 168 | ) 169 | state["selected_movie"] = selected_movie 170 | state["seasons"] = seasons 171 | return 172 | else: 173 | await search_movie.finish("没有找到可用的季数。") 174 | else: 175 | # 如果是电影,直接订阅 176 | success = await subscribe_movie(mp_url, selected_movie, mp_token) 177 | if success: 178 | await search_movie.finish("订阅成功!") 179 | else: 180 | await search_movie.finish("订阅失败。") 181 | else: 182 | await search_movie.finish("获取访问令牌失败。") 183 | else: 184 | await search_movie.reject("序号无效,请重新输入:") 185 | except ValueError: 186 | await search_movie.reject("请输入有效的数字序号:") 187 | 188 | @search_movie.got("season_number", prompt="请输入季数进行订阅,或输入0退出:") 189 | async def handle_season_number(bot: Bot, event: Event, state: T_State): 190 | season_number = str(event.get_message()).strip() # 将 Message 对象转换为字符串并去除空格 191 | 192 | # 如果用户输入0,则结束对话 193 | if season_number == "0": 194 | await search_movie.finish("操作已取消。") 195 | return 196 | 197 | try: 198 | selected_season_number = int(season_number) 199 | selected_movie = state["selected_movie"] 200 | access_token = await get_access_token(mp_url, username, password) 201 | if access_token: 202 | mp_token = "Bearer " + access_token 203 | # 订阅指定季数的电视剧 204 | success = await subscribe_series(mp_url, selected_movie, selected_season_number, mp_token) 205 | if success: 206 | await search_movie.finish("订阅成功!") 207 | else: 208 | await search_movie.finish("订阅失败。") 209 | else: 210 | await search_movie.finish("获取访问令牌失败。") 211 | except ValueError: 212 | await search_movie.reject("请输入有效的数字序号:") 213 | --------------------------------------------------------------------------------