Telegram Bot¶
之前搞了一个Plex实况,然而没过多久Plex的刮削服务在中国大陆就无法访问了,必须翻墙、非常麻烦。
加上,我唯一的主力PT站tjupt
也遭遇了事故,何时恢复杳无音信。
于是,最近我加入了网盘大军,开通了VidHub的永久会员,搞了个夸克网盘+Alist,似乎也还不错。
但这样一来我的Plex实况就无法更新了。为此,我做了一个telegram bot,实现手动更新。
效果¶
和之前的tautulli自动更新效果一致:
功能演示¶
把bot加入到频道之后,可以发送最近在看 tmdb_id season_num
来实现打卡,bot会自动生成一条带海报的打卡消息:
此外,还加入了查询tmdb_id
的功能,与bot对话,发送/s name
可以搜索相关的影视:
点击影视的名称可以显示详细信息:
点击ok结束查询,点击取消删掉查询的消息。
代码分享¶
项目在:
telegram bot¶
本bot使用Python开发,基于python-telegram-bot
库。
第一个开发要点是handler
,也就是规定bot接受哪些消息、收到了消息之后如何处理。
我只用到了以下三种handler:
MessageHandler # 处理消息
CommandHandler # 处理命令
CallbackQueryHandler # 处理callback
MessageHandler
一般搭配正则过滤器使用:watched_reg = filters.Regex("最近在看 (.*?)") watched_handler = MessageHandler(watched_reg, watched)
CommandHandler
需要绑定相应的命令:hello_handler = CommandHandler("start", hello) search_handler = CommandHandler("s", search) unknown_handler = MessageHandler(filters.COMMAND, unknown)
CallbackQueryHandler
只需要规定回调函数就行了:CallbackQueryHandler(button_callback)
CallbackQueryHandler
这个Handler是特殊的,只会响应Query
这类消息。也就是我们下面提到的InlineKeyboard
发送的消息。所以它的回调函数不同于一般的CommandHandler
和MessageHandler
第二个开发要点就是各种回调函数。
例如我们定义命令/start
的回调函数hello
:
async def hello(update: Update, context: ContextTypes.DEFAULT_TYPE):
text = "你好~我是TMbot"
await context.bot.send_message(chat_id=update.effective_chat.id, text=text)
"你好~我是TMbot"
: Note
注意这里需要使用async def
来定义一个异步函数,回调函数默认会收到update, context
两个参数。update
包含了本次收到的消息,context
包含了上下文信息。
对于CallbackQueryHandler
,我们需要额外处理Query
数据:
async def button_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
if query.data == "cancel":
await query.answer()
await query.delete_message()
elif query.data == "ok":
await query.answer()
if update.effective_message.text is not None:
await query.edit_message_text(update.effective_message.text)
else:
await query.edit_message_caption(caption=query.message.caption)
...
Note
这里可以使用query.edit_message_text
来直接编辑当前发出query
的消息。
也可以使用之前的通用接口context.bot.edit_message_text(chat_id=..., ...)
,但是需要手动传入chait_id
。
第三个开发要点是InlineKeyboardMarkup
,这种telegram提供的一种对message的markup
,效果就是:
图中文字/s 好东西
下方的几个按钮就是InlineKeyboard
,它可以实现消息内的交互。用过的都说好。
如何发送InlineKeyboard
await context.bot.send_message(
chat_id=update.effective_chat.id,
text=effective_message,
reply_markup=button_markup,
)
reply_markup
发送。 它的定义方式如下:
def parse_button(search_res: list[dict], query: str, more=True):
buttons = [
[
InlineKeyboardButton(
text=f"{r.get('title', r.get('name'))} ({r.get('original_title', r.get('original_name'))}, {r.get('media_type')}-{r.get('id')})",
callback_data=f"{r.get('media_type')}-{r.get('id')}",
)
]
for r in search_res
if r.get("media_type") in ["movie", "tv"]
] + [
[
(
InlineKeyboardButton(text="更多", callback_data=("more: " + query))
if more
else InlineKeyboardButton(text="返回", callback_data=("less: " + query))
),
InlineKeyboardButton(text="OK", callback_data="ok"),
InlineKeyboardButton(text="取消", callback_data="cancel"),
]
]
return InlineKeyboardMarkup(inline_keyboard=buttons)
实际上,InlineKeyboardMarkup
的参数必须是[[InlineKeyboardButton, ...], ...]
这种形状(list of lists of InlineKeyboardButton)。外层的大列表是所有的行,内层每个列表代表一行的按钮。
在创建按钮的时候可以设置显示的文字和callback_data
,在用户点击该按钮的时候就会触发CallbackQueryHandler
,并且把callback_data
发送过去。
InlineKeyboardButton(text="更多", callback_data=("more: " + query))
tmdb api¶
为了实现搜索和自动检索海报、简介等信息的功能,本bot使用了tmdb的api。
其实就两个:
f"https://api.themoviedb.org/3/movie/{movie_id}?api_key={TMDB_TOKEN}&language=zh-CN"
f"https://api.themoviedb.org/3/tv/{tv_id}?api_key={TMDB_TOKEN}&language=zh-CN"
未来计划加入自动同步TMDB片单的功能。但是现阶段tmdb list v4的api需要用户手动授权:
我还在探索当中:
此致
创建日期: 2025-01-28 14:18:06