Files
YYeTsBot/yyetsbot/yyetsbot.py

413 lines
16 KiB
Python
Raw Normal View History

2021-01-18 22:26:02 +08:00
# coding: utf-8
# YYeTsBot - bot.py
# 2019/8/15 18:27
2023-07-28 19:21:28 +02:00
__author__ = "Benny <benny.think@gmail.com>"
2021-01-18 22:26:02 +08:00
import io
import json
2021-07-11 15:53:39 +08:00
import logging
2022-04-04 22:59:50 +08:00
import os
2021-07-11 15:53:39 +08:00
import re
2021-01-18 22:26:02 +08:00
import tempfile
2021-07-11 15:53:39 +08:00
import time
2021-01-18 22:26:02 +08:00
from urllib.parse import quote_plus
2021-12-16 20:04:37 +08:00
import requests
2021-01-18 22:26:02 +08:00
import telebot
2022-04-08 20:34:54 +08:00
import zhconv
2021-04-15 20:15:59 +08:00
from apscheduler.schedulers.background import BackgroundScheduler
2021-07-11 15:53:39 +08:00
from telebot import apihelper, types
2021-01-18 22:26:02 +08:00
from tgbot_ping import get_runtime
import fansub
2023-07-28 19:21:28 +02:00
from config import DOMAIN, FANSUB_ORDER, MAINTAINER, PROXY, REPORT, TOKEN, YYETS_SEARCH_URL
from utils import get_error_dump, redis_announcement, reset_request, save_error_dump, show_usage, today_request
2021-01-18 22:26:02 +08:00
2023-07-28 19:21:28 +02:00
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(filename)s [%(levelname)s]: %(message)s")
2021-01-18 22:26:02 +08:00
if PROXY:
2023-07-28 19:21:28 +02:00
apihelper.proxy = {"https": PROXY}
2021-01-18 22:26:02 +08:00
bot = telebot.TeleBot(TOKEN, num_threads=100)
2021-01-18 22:26:02 +08:00
angry_count = 0
2023-07-28 19:21:28 +02:00
@bot.message_handler(commands=["start"], chat_types=["private"])
2021-01-18 22:26:02 +08:00
def send_welcome(message):
2023-07-28 19:21:28 +02:00
bot.send_chat_action(message.chat.id, "typing")
bot.send_message(
message.chat.id,
"欢迎使用,直接发送想要的剧集标题给我就可以了,不需要其他关键字,我会帮你搜索。\n\n"
"仅私聊使用,群组功能已禁用。"
f"目前搜索优先级 {FANSUB_ORDER}\n "
f"另外,可以尝试使用一下 https://yyets.click/ 哦!",
parse_mode="html",
disable_web_page_preview=True,
)
@bot.message_handler(commands=["help"], chat_types=["private"])
2021-01-18 22:26:02 +08:00
def send_help(message):
2023-07-28 19:21:28 +02:00
bot.send_chat_action(message.chat.id, "typing")
bot.send_message(
message.chat.id,
"""机器人无法使用或者报错?从 /ping 里可以看到运行状态以及最新信息。
2021-01-18 22:26:02 +08:00
同时你可以使用如下方式寻求使用帮助和报告错误\n
1. @BennyThink
2. <a href='https://github.com/BennyThink/YYeTsBot/issues'>Github issues</a>
2023-07-28 19:21:28 +02:00
3. <a href='https://t.me/mikuri520'>Telegram Channel</a>""",
parse_mode="html",
disable_web_page_preview=True,
)
2021-01-18 22:26:02 +08:00
2023-07-28 19:21:28 +02:00
@bot.message_handler(commands=["ping"], chat_types=["private"])
2021-01-18 22:26:02 +08:00
def send_ping(message):
logging.info("Pong!")
2023-07-28 19:21:28 +02:00
bot.send_chat_action(message.chat.id, "typing")
2021-01-18 22:26:02 +08:00
info = get_runtime("botsrunner_yyets_1")
2021-01-18 22:26:02 +08:00
usage = ""
if str(message.chat.id) == MAINTAINER:
usage = show_usage()
announcement = redis_announcement() or ""
if announcement:
announcement = f"\n\n*公告:{announcement}*\n\n"
2023-07-28 19:21:28 +02:00
bot.send_message(message.chat.id, f"{info}\n\n{usage}\n{announcement}", parse_mode="markdown")
2021-01-18 22:26:02 +08:00
2023-07-28 19:21:28 +02:00
@bot.message_handler(commands=["settings"], chat_types=["private"])
2021-01-18 22:26:02 +08:00
def settings(message):
is_admin = str(message.chat.id) == MAINTAINER
# 普通用户只可以查看,不可以设置。
# 管理员可以查看可以设置
if message.text != "/settings" and not is_admin:
bot.send_message(message.chat.id, "此功能只允许管理员使用。请使用 /ping 和 /settings 查看相关信息")
return
# 删除公告,设置新公告
if message.text != "/settings":
date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
text = message.text.replace("/settings", f"{date}\t")
logging.info("New announcement %s", text)
redis_announcement(text, "set")
setattr(message, "text", "/settings")
settings(message)
return
announcement = redis_announcement()
markup = types.InlineKeyboardMarkup()
btn1 = types.InlineKeyboardButton("删除公告", callback_data="announcement")
if is_admin and announcement:
markup.add(btn1)
bot.send_message(message.chat.id, f"目前公告:\n\n {announcement or '暂无公告'}", reply_markup=markup)
@bot.callback_query_handler(func=lambda call: re.findall(r"announcement(\S*)", call.data))
def delete_announcement(call):
2023-07-28 19:21:28 +02:00
bot.send_chat_action(call.message.chat.id, "typing")
2021-01-18 22:26:02 +08:00
redis_announcement(op="del")
2023-07-28 19:21:28 +02:00
bot.edit_message_text(f"目前公告:\n\n {redis_announcement() or '暂无公告'}", call.message.chat.id, call.message.message_id)
2021-01-18 22:26:02 +08:00
2023-07-28 19:21:28 +02:00
@bot.message_handler(commands=["credits"], chat_types=["private"])
2021-01-18 22:26:02 +08:00
def send_credits(message):
2023-07-28 19:21:28 +02:00
bot.send_chat_action(message.chat.id, "typing")
bot.send_message(
message.chat.id,
"""感谢字幕组的无私奉献!本机器人资源来源:\n
2021-01-18 22:26:02 +08:00
<a href="http://www.zmz2019.com/">人人影视</a>
<a href="http://cili001.com/">磁力下载站</a>
<a href="http://www.zhuixinfan.com/main.php">追新番</a>
2021-01-20 22:43:02 +08:00
<a href="https://www.zimuxia.cn/">FIX 字幕侠</a>
2023-07-28 19:21:28 +02:00
""",
parse_mode="html",
disable_web_page_preview=True,
)
2021-01-18 22:26:02 +08:00
for sub_name in dir(fansub):
2021-01-24 21:39:25 +08:00
if sub_name.endswith("_offline") or sub_name.endswith("_online"):
2023-07-28 19:21:28 +02:00
@bot.message_handler(commands=[sub_name], chat_types=["private"])
def varies_fansub(message):
2023-07-28 19:21:28 +02:00
bot.send_chat_action(message.chat.id, "typing")
2021-01-23 16:21:40 +08:00
# /YYeTsOffline 逃避可耻 /YYeTsOffline
tv_name: str = re.findall(r"/.*line\s*(\S*)", message.text)[0]
class_name: str = re.findall(r"/(.*line)", message.text)[0]
class_ = getattr(fansub, class_name)
if not tv_name:
2023-07-28 19:21:28 +02:00
bot.send_message(
message.chat.id, f"{class_.__name__}: 请附加你要搜索的剧集名称,如 `/{class_name} 逃避可耻`", parse_mode="markdown"
)
return
2021-01-23 16:21:40 +08:00
else:
setattr(message, "text", tv_name)
base_send_search(message, class_())
2021-01-18 22:26:02 +08:00
def download_to_io(photo):
logging.info("Initializing bytes io...")
mem = io.BytesIO()
file_id = photo[-1].file_id
logging.info("Downloading photos...")
file_info = bot.get_file(file_id)
content = bot.download_file(file_info.file_path)
mem.write(content)
logging.info("Downloading complete.")
return mem
def send_my_response(message):
2023-07-28 19:21:28 +02:00
bot.send_chat_action(message.chat.id, "record_video_note")
2021-01-18 22:26:02 +08:00
# I may also send picture
photo = message.photo
uid = message.reply_to_message.caption
text = f"主人说:{message.text or message.caption or '啥也没说😯'}"
if photo:
2023-07-28 19:21:28 +02:00
bot.send_chat_action(message.chat.id, "typing")
2021-01-18 22:26:02 +08:00
logging.info("Photo received from maintainer")
mem = download_to_io(photo)
2023-07-28 19:21:28 +02:00
mem.name = f"{uid}.jpg"
2021-01-18 22:26:02 +08:00
r = bot.send_photo(uid, mem.getvalue(), caption=text)
else:
r = bot.send_message(uid, text)
logging.info("Reply has been sent to %s with message id %s", uid, r.message_id)
bot.reply_to(message, "回复已经发送给这位用户")
fw = bot.forward_message(message.chat.id, uid, r.message_id)
time.sleep(3)
bot.delete_message(message.chat.id, fw.message_id)
logging.info("Forward has been deleted.")
2023-07-28 19:21:28 +02:00
@bot.message_handler(content_types=["photo", "text"], chat_types=["private"])
2021-01-18 22:26:02 +08:00
def send_search(message):
2022-04-04 22:59:50 +08:00
if str(message.chat.id) == os.getenv("SPECIAL_ID") and message.text == "❤️":
bot.reply_to(message, "❤️")
2021-01-23 16:21:40 +08:00
# normal ordered search
if message.text in ("Voice Chat started", "Voice Chat ended"):
2021-04-15 20:15:59 +08:00
logging.warning("This is really funny %s", message.text)
return
2021-01-23 16:21:40 +08:00
base_send_search(message)
2023-07-28 19:21:28 +02:00
@bot.message_handler(content_types=["document"], chat_types=["private"])
2022-03-26 11:17:56 +08:00
def ban_user(message):
if str(message.chat.id) != MAINTAINER:
return
mem = io.BytesIO()
file_id = message.document.file_id
file_info = bot.get_file(file_id)
content = bot.download_file(file_info.file_path)
mem.write(content)
user_list = mem.getvalue().decode("u8").split("\n")
yy = fansub.YYeTsOffline()
client = yy.mongo
user_col = client["zimuzu"]["users"]
2022-04-04 22:59:50 +08:00
comment_col = client["zimuzu"]["comment"]
2022-03-26 11:17:56 +08:00
text = ""
for line in user_list:
user, reason = line.split(maxsplit=1)
ban = {"disable": True, "reason": reason}
user_col.update_one({"username": user}, {"$set": {"status": ban}})
2022-04-04 22:59:50 +08:00
comment_col.delete_many({"username": user})
2022-03-26 11:17:56 +08:00
status = f"{user} 已经被禁言,原因:{reason}\n"
logging.info("Banning %s", status)
text += status
bot.reply_to(message, text)
mem.close()
2021-01-23 16:21:40 +08:00
def base_send_search(message, instance=None):
if instance is None:
fan = fansub.FansubEntrance()
else:
fan = instance
2023-07-28 19:21:28 +02:00
bot.send_chat_action(message.chat.id, "typing")
2021-01-18 22:26:02 +08:00
today_request("total")
2023-07-28 19:21:28 +02:00
if (
message.reply_to_message
and message.reply_to_message.document
and message.reply_to_message.document.file_name.startswith("error")
and str(message.chat.id) == MAINTAINER
):
2021-01-18 22:26:02 +08:00
today_request("answer")
send_my_response(message)
return
2022-04-08 20:34:54 +08:00
name = zhconv.convert(message.text, "zh-hans")
2023-07-28 19:21:28 +02:00
logging.info("Receiving message: %s from user %s(%s)", name, message.chat.username, message.chat.id)
2021-01-18 22:26:02 +08:00
if name is None:
today_request("invalid")
2023-07-28 19:21:28 +02:00
with open("warning.webp", "rb") as sti:
2021-01-18 22:26:02 +08:00
bot.send_message(message.chat.id, "不要调戏我!我会报警的")
bot.send_sticker(message.chat.id, sti)
return
result = fan.search_preview(name)
2021-01-18 22:26:02 +08:00
markup = types.InlineKeyboardMarkup()
2021-01-20 23:04:23 +08:00
source = result.get("class")
result.pop("class")
2021-08-18 21:41:08 +08:00
count, MAX, warning = 0, 20, ""
for url_hash, detail in result.items():
2021-08-18 21:41:08 +08:00
if count > MAX:
warning = f"*结果太多啦,目前只显示前{MAX}个。关键词再精准一下吧!*\n\n"
break
btn = types.InlineKeyboardButton(detail["name"], callback_data="choose%s" % url_hash)
2021-01-18 22:26:02 +08:00
markup.add(btn)
2021-08-18 21:41:08 +08:00
count += 1
2021-01-18 22:26:02 +08:00
if result:
logging.info("🎉 Resource match.")
today_request("success")
2023-07-28 19:21:28 +02:00
bot.reply_to(
message,
f"{warning}呐🌹,一共%d个结果选一个呀来源%s" % (len(result), source),
reply_markup=markup,
parse_mode="markdown",
)
2021-01-18 22:26:02 +08:00
else:
logging.warning("⚠️️ Resource not found")
today_request("fail")
2023-07-28 19:21:28 +02:00
bot.send_chat_action(message.chat.id, "typing")
2021-01-18 22:26:02 +08:00
encoded = quote_plus(name)
2023-07-28 19:21:28 +02:00
bot.reply_to(
message,
f"没有找到你想要的信息,是不是你打了错别字,或者搜索了一些国产影视剧。🤪\n" f"还是你想调戏我哦🙅‍ 本小可爱拒绝被调戏️\n\n" "⚠️如果确定要我背锅,那么请使用 /help 来提交错误",
disable_web_page_preview=True,
)
2021-01-18 22:26:02 +08:00
if REPORT:
btn = types.InlineKeyboardButton("快来修复啦", callback_data="fix")
markup.add(btn)
2023-07-28 19:21:28 +02:00
bot.send_chat_action(message.chat.id, "upload_document")
bot.send_message(
message.chat.id,
f"{name}》😭\n大部分情况下机器人是好用的,不要怀疑我的代码质量.\n"
f"如果你真的确定是机器人出问题了,那么点下面的按钮叫 @BennyThink 来修!\n"
f"⚠️报错前请三思,不要乱点,确保这锅应该甩给我。否则我会很生气的😡小心被拉黑哦",
reply_markup=markup,
)
2021-01-18 22:26:02 +08:00
content = f""" 报告者:{message.chat.first_name}{message.chat.last_name or ""}@{message.chat.username or ""}({message.chat.id})
问题发生时间{time.strftime("%Y-%m-%data %H:%M:%S", time.localtime(message.date))}
请求内容{name}
2021-01-20 21:51:03 +08:00
请求URL{YYETS_SEARCH_URL.format(kw=encoded)}\n\n
2021-01-18 22:26:02 +08:00
"""
save_error_dump(message.chat.id, content)
2021-01-21 19:32:55 +08:00
def magic_recycle(fan, call, url_hash):
if fan.redis.exists(url_hash):
return False
else:
logging.info("👏 Wonderful magic!")
2021-01-22 23:37:21 +08:00
bot.answer_callback_query(call.id, "小可爱使用魔法回收了你的搜索结果,你再搜索一次试试看嘛🥺", show_alert=True)
2021-01-21 19:32:55 +08:00
bot.delete_message(call.message.chat.id, call.message.message_id)
return True
2021-01-18 22:26:02 +08:00
@bot.callback_query_handler(func=lambda call: re.findall(r"choose(\S*)", call.data))
def choose_link(call):
fan = fansub.FansubEntrance()
2023-07-28 19:21:28 +02:00
bot.send_chat_action(call.message.chat.id, "typing")
# call.data is url_hash, with sha1, http://www.rrys2020.com/resource/36588
2021-01-21 19:32:55 +08:00
resource_url_hash = re.findall(r"choose(\S*)", call.data)[0]
if magic_recycle(fan, call, resource_url_hash):
return
2021-01-18 22:26:02 +08:00
2021-01-21 19:32:55 +08:00
result = fan.search_result(resource_url_hash)
2023-07-28 19:21:28 +02:00
with tempfile.NamedTemporaryFile(mode="wb+", prefix=result["cnname"].replace("/", " "), suffix=".txt") as tmp:
bytes_data = json.dumps(result["all"], ensure_ascii=False, indent=4).encode("u8")
2021-01-18 22:26:02 +08:00
tmp.write(bytes_data)
tmp.flush()
with open(tmp.name, "rb") as f:
2021-12-11 14:44:30 +08:00
if result.get("type") == "resource":
caption = "{}\n\n{}".format(result["cnname"], result["share"])
else:
2022-06-19 20:19:51 +08:00
caption = result["all"].replace(r"\n", " ")
2023-07-28 19:21:28 +02:00
bot.send_chat_action(call.message.chat.id, "upload_document")
2021-12-11 14:44:30 +08:00
bot.send_document(call.message.chat.id, f, caption=caption)
2021-01-18 22:26:02 +08:00
2021-12-16 20:04:37 +08:00
@bot.callback_query_handler(func=lambda call: re.findall(r"approve", call.data))
def approve_spam(call):
obj_id = re.findall(r"approve(\S*)", call.data)[0]
2023-07-28 19:21:28 +02:00
data = {"obj_id": obj_id, "token": TOKEN}
2021-12-16 20:04:37 +08:00
requests.post(f"{DOMAIN}api/admin/spam", json=data)
2023-07-28 19:21:28 +02:00
bot.answer_callback_query(call.id, "Approved")
2021-12-20 19:12:23 +08:00
bot.delete_message(call.message.chat.id, call.message.message_id)
2021-12-16 20:04:37 +08:00
2022-09-09 18:07:55 +08:00
@bot.callback_query_handler(func=lambda call: re.findall(r"ban", call.data))
def ban_spam(call):
obj_id = re.findall(r"ban(\S*)", call.data)[0]
2023-07-28 19:21:28 +02:00
data = {"obj_id": obj_id, "token": TOKEN}
2021-12-16 20:04:37 +08:00
requests.delete(f"{DOMAIN}api/admin/spam", json=data)
2023-07-28 19:21:28 +02:00
bot.answer_callback_query(call.id, "Banned")
2021-12-20 19:12:23 +08:00
bot.delete_message(call.message.chat.id, call.message.message_id)
2021-12-16 20:04:37 +08:00
2021-01-18 22:26:02 +08:00
@bot.callback_query_handler(func=lambda call: re.findall(r"unwelcome(\d*)", call.data))
def send_unwelcome(call):
# this will come from me only
logging.warning("I'm so unhappy!")
message = call.message
2023-07-28 19:21:28 +02:00
bot.send_chat_action(message.chat.id, "typing")
2021-01-18 22:26:02 +08:00
# angry_count = angry_count + 1
global angry_count
angry_count += 1
uid = re.findall(r"unwelcome(\d*)", call.data)[0]
if uid:
2023-07-28 19:21:28 +02:00
text = "人人影视主要提供欧美日韩等海外资源,你的这个真没有🤷‍。\n" "<b>麻烦你先从自己身上找原因</b>,我又不是你的专属客服。\n" "不要再报告这种错误了🙄️,面倒な。😡"
2021-01-18 22:26:02 +08:00
bot.send_message(uid, text, parse_mode="html")
bot.reply_to(message, f"有生之日 生气次数:{angry_count}")
2023-07-28 19:21:28 +02:00
@bot.callback_query_handler(func=lambda call: call.data == "fix")
2021-01-18 22:26:02 +08:00
def report_error(call):
logging.error("Reporting error to maintainer.")
2023-07-28 19:21:28 +02:00
bot.send_chat_action(call.message.chat.id, "typing")
2021-01-18 22:26:02 +08:00
error_content = get_error_dump(call.message.chat.id)
if error_content == "":
2023-07-28 19:21:28 +02:00
bot.answer_callback_query(call.id, "多次汇报重复的问题并不会加快处理速度。", show_alert=True)
2021-01-18 22:26:02 +08:00
return
2023-07-28 19:21:28 +02:00
text = f"人人影视机器人似乎出现了一些问题🤔🤔🤔……{error_content[0:300]}"
2021-01-18 22:26:02 +08:00
markup = types.InlineKeyboardMarkup()
btn = types.InlineKeyboardButton("unwelcome", callback_data=f"unwelcome{call.message.chat.id}")
markup.add(btn)
bot.send_message(MAINTAINER, text, disable_web_page_preview=True, reply_markup=markup)
2023-07-28 19:21:28 +02:00
with tempfile.NamedTemporaryFile(mode="wb+", prefix=f"error_{call.message.chat.id}_", suffix=".txt") as tmp:
tmp.write(error_content.encode("u8"))
2021-01-18 22:26:02 +08:00
tmp.flush()
with open(tmp.name, "rb") as f:
2023-07-28 19:21:28 +02:00
bot.send_chat_action(call.message.chat.id, "upload_document")
2021-01-18 22:26:02 +08:00
bot.send_document(MAINTAINER, f, caption=str(call.message.chat.id))
2023-07-28 19:21:28 +02:00
bot.answer_callback_query(call.id, "Debug信息已经发送给维护者请耐心等待回复~", show_alert=True)
2021-01-18 22:26:02 +08:00
2023-07-28 19:21:28 +02:00
if __name__ == "__main__":
logging.info("YYeTs bot is running...")
2021-01-18 22:26:02 +08:00
scheduler = BackgroundScheduler()
2023-07-28 19:21:28 +02:00
scheduler.add_job(reset_request, "cron", hour=0, minute=0)
2021-01-18 22:26:02 +08:00
scheduler.start()
bot.polling()