diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..060b59b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+# config files
+config.json
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
diff --git a/Timer/__init__.py b/Timer/__init__.py
new file mode 100644
index 0000000..5da5b41
--- /dev/null
+++ b/Timer/__init__.py
@@ -0,0 +1,21 @@
+import asyncio
+import logging
+
+class Timer:
+ def __init__(self, callback, timeout):
+ logging.info("Created a schedule interval as " + str(timeout) + " seconds.")
+ loop = asyncio.get_event_loop()
+ self.callback = callback
+ self.timeout = timeout
+ self.task = loop.create_task(self.wait())
+
+ async def wait(self):
+ await asyncio.sleep(self.timeout)
+ logging.info("Successfully executed a timer schedule.")
+ await self.callback
+
+ def stop(self):
+ try:
+ self.task.cancel()
+ except asyncio.CancelledError:
+ pass
\ No newline at end of file
diff --git a/bot.session b/bot.session
new file mode 100644
index 0000000..89e55e9
Binary files /dev/null and b/bot.session differ
diff --git a/bot.session-journal b/bot.session-journal
new file mode 100644
index 0000000..4215a0f
Binary files /dev/null and b/bot.session-journal differ
diff --git a/car.service b/car.service
new file mode 100644
index 0000000..34bcbbc
--- /dev/null
+++ b/car.service
@@ -0,0 +1,17 @@
+[Unit]
+Description=captcha
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+Type=simple
+WorkingDirectory=/root/CAR
+ExecStart=/usr/bin/python3 /root/CAR/main.py
+Restart=always
+PrivateTmp=True
+KillSignal=SIGINT
+TimeoutStopSec=10s
+StartLimitInterval=400
+
+[Install]
+WantedBy=multi-user.target
diff --git a/challenge.py b/challenge.py
new file mode 100644
index 0000000..a3304d3
--- /dev/null
+++ b/challenge.py
@@ -0,0 +1,80 @@
+import random
+import configparser
+
+class Challenge:
+ """
+ 如果你是 Python 高手,请继续;如果你根本不会Python或者语法乱七八糟,我建议你还是先去 https://docs.python.org 学习一个。
+ 一个简单的验证问题变量说明
+ 请注意,如果要使用中文写出各个选项,建议把main.py里344-346行修改为如下形式:
+ [InlineKeyboardButton(str(c),
+ callback_data=bytes(
+ str(c), encoding="utf-8"))])
+ 这么做的目的是能让问题的选项每个一行,否则一行四个答案可能会显示不下
+ __str__ 方法返回问题的具体内容,
+ qus 返回上面的 __str__ 方法
+ ans 返回 Challenge 的答案
+ choices 返回 Challenge 的选项们
+ _ans 属性是问题,
+ _choices 是问题选项
+ 比如说你可以这么改写 Challenge 类
+ def __init(self):
+ self._ans= ''
+ self._choices = []
+ self.new()
+ def __str__(self):
+ return "下面哪一个不是路由器的架构?"
+ def new(self):
+ self._choices['MIPS','ARM','8051','x86']
+ self._answer = '8051'
+
+ qus, ans,choices 这三个函数可以放着不动
+ """
+ def __init__(self):
+ self._a = 0
+ self._pu = "A"
+ # 所以为啥要把a,b两个属性丢这里?我不是太懂。。。
+ self._op = "A"
+ self._ans = 0
+ self._choices = []
+ self.new()
+
+ def __str__(self):
+ return "{op} {a}的正确选项是?".format(a=self._a, op=self._op)
+
+ def new(self):
+ conf = configparser.ConfigParser()
+ conf.read("tk.json")
+ operation = str(random.randint(0, int(conf.get("ans", "all"))))
+ a, ans = "号题目", "A"
+ try:
+ f = open(str("pic/") + operation + str(".png"))
+ f.close()
+ pu = str("pic/") + operation + str(".png")
+ except IOError:
+ pu = str("pic/") + operation + str(".jpg")
+ if operation in conf.get("ans", "A").split():
+ ans = "A"
+ elif operation in conf.get("ans", "B").split():
+ ans = "B"
+ elif operation in conf.get("ans", "C").split():
+ ans = "C"
+ elif operation in conf.get("ans", "D").split():
+ ans = "D"
+ choices = ['A','B','C','D']
+ self._a = a
+ self._op = operation
+ self._ans = ans
+ self._pu = pu
+ self._choices = choices
+
+ def qus(self):
+ return self.__str__()
+
+ def ans(self):
+ return self._ans
+
+ def pu(self):
+ return self._pu
+
+ def choices(self):
+ return self._choices
diff --git a/do.txt b/do.txt
new file mode 100644
index 0000000..eed4728
--- /dev/null
+++ b/do.txt
@@ -0,0 +1,11 @@
+2018年全国卷1数学(理科)高考试题
+2018年全国卷1数学(文科)高考试题
+2018年全国卷1理综高考试题
+2019年全国I卷高考数学(理科)试题
+2019年全国I卷高考理综试题
+2019年全国III卷高考理综试题
+1C 2B 3A 4B 5D 6A 7B 8D 9C 10A 11B 12A
+13A 14C 15A 16C 17B 18D 19A 20B 21B 22C 23B 24D
+25D 26B 27A 28C 29D 30C 31D 32A 33D 34B 35C 36B 37C 38B 39A 40D 41B 42C
+43C 44C 45B 46B 47D 48A 49B 50A 51A 52B 53C 54D
+55B 56C 57A 58D 59C 60D 61A 62B 63D 64D 65C 66B 67C 68A 69D 70B 71B 72C
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..7ef9c43
--- /dev/null
+++ b/main.py
@@ -0,0 +1,600 @@
+# !/usr/bin/env python3
+import asyncio
+import json
+import threading
+import configparser
+import logging, subprocess
+from time import time, sleep
+from challenge import Challenge
+from pyrogram import (Client, Filters, Message, User, InlineKeyboardButton,
+ InlineKeyboardMarkup, CallbackQuery, ChatPermissions)
+from pyrogram.errors import ChatAdminRequired, ChannelPrivate, ChannelInvalid
+from Timer import Timer
+
+_app: Client = None
+_channel: str = None
+_start_message: str = None
+# _challenge_scheduler = sched.scheduler(time, sleep)
+_current_challenges = dict()
+_cch_lock = threading.Lock()
+_config = dict()
+logging.basicConfig(level=logging.INFO)
+# 设置一下日志记录,能够在诸如 systemctl status captchabot 这样的地方获得详细输出。
+conf = configparser.ConfigParser()
+
+def load_config():
+ global _config
+ with open("config.json", encoding="utf-8") as f:
+ _config = json.load(f)
+
+
+def save_config():
+ with open("config.json", "w") as f:
+ json.dump(_config, f, indent=4)
+
+def _update(app):
+ @app.on_message(Filters.command("ping") & Filters.private)
+ async def ping_command(client: Client, message: Message):
+ await message.reply("poi~poi~poi~")
+
+ @app.on_message(Filters.command("upload") & Filters.group)
+ async def upload_command(client: Client, message: Message):
+ if message.chat.id == -1001413542074:
+ conf.read("tk.json")
+ qustion_all = conf.get("ans", "all")
+ qustion_a = conf.get("ans", "A")
+ qustion_b = conf.get("ans", "B")
+ qustion_c = conf.get("ans", "C")
+ qustion_d = conf.get("ans", "D")
+ if message.reply_to_message.document.mime_type == "image/jpeg":
+ await client.download_media(message.reply_to_message, file_name="pic/" + str(int(qustion_all) + 1) + ".jpg")
+ elif message.reply_to_message.document.mime_type == "image/png":
+ await client.download_media(message.reply_to_message, file_name="pic/" + str(int(qustion_all) + 1) + ".png")
+ if message.text.split()[-1] == "A":
+ conf.set("ans", "A", qustion_a + " " + str(int(qustion_all) + 1))
+ conf.set("ans", "all", str(int(qustion_all) + 1))
+ conf.write(open("tk.json", "w"))
+ if message.text.split()[-1] == "B":
+ conf.set("ans", "B", qustion_b + " " + str(int(qustion_all) + 1))
+ conf.set("ans", "all", str(int(qustion_all) + 1))
+ conf.write(open("tk.json", "w"))
+ if message.text.split()[-1] == "C":
+ conf.set("ans", "C", qustion_c + " " + str(int(qustion_all) + 1))
+ conf.set("ans", "all", str(int(qustion_all) + 1))
+ conf.write(open("tk.json", "w"))
+ if message.text.split()[-1] == "D":
+ conf.set("ans", "D", qustion_d + " " + str(int(qustion_all) + 1))
+ conf.set("ans", "all", str(int(qustion_all) + 1))
+ conf.write(open("tk.json", "w"))
+ await message.reply("done")
+
+ @app.on_message(Filters.command("start") & Filters.private)
+ async def start_command(client: Client, message: Message):
+ await message.reply("" + message.from_user.first_name + " " + _start_message)
+
+ @app.on_message(Filters.command("answer"))
+ async def answer_command(client: Client, message: Message):
+ if message.from_user.id == int(347437156) or message.from_user.id == int(
+ 616760897) or message.from_user.id == int(441229454):
+ qustion_id = message.text.split()[-1]
+ conf.read("tk.json")
+ qustion_a = conf.get("ans", "A").split()
+ qustion_b = conf.get("ans", "B").split()
+ qustion_c = conf.get("ans", "C").split()
+ qustion_d = conf.get("ans", "D").split()
+ if qustion_id in qustion_a:
+ await message.reply("" + message.from_user.first_name + " 此题的正确答案为:`A`")
+ elif qustion_id in qustion_b:
+ await message.reply("" + message.from_user.first_name + " 此题的正确答案为:`B`")
+ elif qustion_id in qustion_c:
+ await message.reply("" + message.from_user.first_name + " 此题的正确答案为:`C`")
+ elif qustion_id in qustion_d:
+ await message.reply("" + message.from_user.first_name + " 此题的正确答案为:`D`")
+
+ @app.on_message(Filters.command("leave") & Filters.private)
+ async def leave_command(client: Client, message: Message):
+ chat_id = message.text.split()[-1]
+ if message.from_user.id == _config["manage_user"]:
+ try:
+ await client.send_message(int(chat_id),
+ _config["msg_leave_msg"])
+ await client.leave_chat(int(chat_id), True)
+ except:
+ await message.reply("指令出错了!可能是bot不在参数所在群里。")
+ else:
+ await message.reply("已离开群组: `" + chat_id + "`",
+ parse_mode="Markdown")
+ _me: User = await client.get_me()
+ try:
+ await client.send_message(
+ int(_channel),
+ _config["msg_leave_group"].format(
+ botid=str(_me.id),
+ groupid=chat_id,
+ ),
+ parse_mode="Markdown")
+ except Exception as e:
+ logging.error(str(e))
+ else:
+ pass
+
+ @app.on_callback_query()
+ async def challenge_callback(client: Client,
+ callback_query: CallbackQuery):
+ query_data = str(callback_query.data)
+ query_id = callback_query.id
+ chat_id = callback_query.message.chat.id
+ user_id = callback_query.from_user.id
+ msg_id = callback_query.message.message_id
+ chat_title = callback_query.message.chat.title
+ user_name = callback_query.from_user.first_name
+ group_config = _config.get(str(chat_id), _config["*"])
+ if query_data in ["+", "-"]:
+ admins = await client.get_chat_members(chat_id,
+ filter="administrators")
+ if not any([
+ admin.user.id == user_id and
+ (admin.status == "creator" or admin.can_restrict_members)
+ for admin in admins
+ ]):
+ await client.answer_callback_query(
+ query_id, group_config["msg_permission_denied"])
+ return
+
+ ch_id = "{chat}|{msg}".format(chat=chat_id, msg=msg_id)
+ _cch_lock.acquire()
+ # target: int = None
+ challenge, target, timeout_event = _current_challenges.get(
+ ch_id, (None, None, None))
+ if ch_id in _current_challenges:
+ del _current_challenges[ch_id]
+ _cch_lock.release()
+ timeout_event.stop()
+
+ if query_data == "+":
+ try:
+ await client.restrict_chat_member(
+ chat_id,
+ target,
+ permissions=ChatPermissions(
+ can_send_other_messages=True,
+ can_send_messages=True,
+ can_send_media_messages=True,
+ can_add_web_page_previews=True,
+ ))
+ except ChatAdminRequired:
+ await client.answer_callback_query(
+ query_id, group_config["msg_bot_no_permission"])
+ return
+
+ await client.edit_message_caption(
+ chat_id,
+ msg_id,
+ group_config["msg_approved"].format(user=user_name),
+ reply_markup=None,
+ )
+ _me: User = await client.get_me()
+ try:
+ await client.send_message(
+ int(_channel),
+ _config["msg_passed_admin"].format(
+ botid=str(_me.id),
+ targetuser=str(target),
+ groupid=str(chat_id),
+ grouptitle=str(chat_title),
+ ),
+ parse_mode="Markdown",
+ )
+ except Exception as e:
+ logging.error(str(e))
+ else:
+ try:
+ await client.kick_chat_member(chat_id, target)
+ except ChatAdminRequired:
+ await client.answer_callback_query(
+ query_id, group_config["msg_bot_no_permission"])
+ return
+ await client.edit_message_caption(
+ chat_id,
+ msg_id,
+ group_config["msg_refused"].format(user=user_name),
+ reply_markup=None,
+ )
+ _me: User = await client.get_me()
+ try:
+ await client.send_message(
+ int(_channel),
+ _config["msg_failed_admin"].format(
+ botid=str(_me.id),
+ targetuser=str(target),
+ groupid=str(chat_id),
+ grouptitle=str(chat_title),
+ ),
+ parse_mode="Markdown",
+ )
+ except Exception as e:
+ logging.error(str(e))
+ await client.answer_callback_query(query_id)
+ return
+
+ ch_id = "{chat}|{msg}".format(chat=chat_id, msg=msg_id)
+ _cch_lock.acquire()
+ challenge, target, timeout_event = _current_challenges.get(
+ ch_id, (None, None, None))
+ _cch_lock.release()
+ if user_id != target:
+ await client.answer_callback_query(
+ query_id, group_config["msg_challenge_not_for_you"])
+ return None
+ timeout_event.stop()
+ try:
+ await client.restrict_chat_member(
+ chat_id,
+ target,
+ permissions=ChatPermissions(can_send_other_messages=True,
+ can_send_messages=True,
+ can_send_media_messages=True,
+ can_add_web_page_previews=True,
+ can_send_polls=True))
+ except ChatAdminRequired:
+ pass
+
+ correct = str(challenge.ans()) == query_data
+ if correct:
+ await client.edit_message_caption(
+ chat_id,
+ msg_id,
+ group_config["msg_challenge_passed"],
+ reply_markup=None)
+ _me: User = await client.get_me()
+ try:
+ await client.send_message(
+ int(_channel),
+ _config["msg_passed_answer"].format(
+ botid=str(_me.id),
+ targetuser=str(target),
+ groupid=str(chat_id),
+ grouptitle=str(chat_title),
+ ),
+ parse_mode="Markdown",
+ )
+ except Exception as e:
+ logging.error(str(e))
+ else:
+ if not group_config["use_strict_mode"]:
+ await client.edit_message_caption(
+ chat_id,
+ msg_id,
+ group_config["msg_challenge_mercy_passed"],
+ reply_markup=None,
+ )
+ _me: User = await client.get_me()
+ try:
+ await client.send_message(
+ int(_channel),
+ _config["msg_passed_mercy"].format(
+ botid=str(_me.id),
+ targetuser=str(target),
+ groupid=str(chat_id),
+ grouptitle=str(chat_title),
+ ),
+ parse_mode="Markdown",
+ )
+ except Exception as e:
+ logging.error(str(e))
+ else:
+ try:
+ await client.edit_message_caption(
+ chat_id,
+ msg_id,
+ group_config["msg_challenge_failed"].format(challengeans=challenge.ans()),
+ reply_markup=None,
+ )
+ # await client.restrict_chat_member(chat_id, target)
+ _me: User = await client.get_me()
+ try:
+ await client.send_message(
+ int(_channel),
+ _config["msg_failed_answer"].format(
+ botid=str(_me.id),
+ targetuser=str(target),
+ groupid=str(chat_id),
+ grouptitle=str(chat_title),
+ ),
+ parse_mode="Markdown",
+ )
+ except Exception as e:
+ logging.error(str(e))
+ except ChatAdminRequired:
+ return
+
+ if group_config["challenge_timeout_action"] == "ban":
+ await client.kick_chat_member(chat_id, user_id)
+ elif group_config["challenge_timeout_action"] == "kick":
+ await client.kick_chat_member(chat_id, user_id)
+ await client.unban_chat_member(chat_id, user_id)
+ elif group_config["challenge_timeout_action"] == "mute":
+ await client.restrict_chat_member(
+ chat_id=chat_id,
+ user_id=user_id,
+ permissions=ChatPermissions(can_send_other_messages=False,
+ can_send_messages=False,
+ can_send_media_messages=False,
+ can_add_web_page_previews=False,
+ can_send_polls=False))
+ else:
+ pass
+
+ if group_config["delete_failed_challenge"]:
+ Timer(
+ client.delete_messages(chat_id, msg_id),
+ group_config["delete_failed_challenge_interval"],
+ )
+ if group_config["delete_passed_challenge"]:
+ Timer(
+ client.delete_messages(chat_id, msg_id),
+ group_config["delete_passed_challenge_interval"],
+ )
+
+ @app.on_message(Filters.new_chat_members)
+ async def challenge_user(client: Client, message: Message):
+ target = message.new_chat_members[0]
+ if message.from_user.id != target.id:
+ if target.is_self:
+ group_config = _config.get(str(message.chat.id), _config["*"])
+ try:
+ await client.send_message(
+ message.chat.id, group_config["msg_self_introduction"])
+ _me: User = await client.get_me()
+ try:
+ await client.send_message(
+ int(_channel),
+ _config["msg_into_group"].format(
+ botid=str(_me.id),
+ groupid=str(message.chat.id),
+ grouptitle=str(message.chat.title),
+ ),
+ parse_mode="Markdown",
+ )
+ except Exception as e:
+ logging.error(str(e))
+ except ChannelPrivate:
+ return
+ return
+ try:
+ await client.restrict_chat_member(
+ chat_id=message.chat.id,
+ user_id=target.id,
+ permissions=ChatPermissions(can_send_other_messages=False,
+ can_send_messages=False,
+ can_send_media_messages=False,
+ can_add_web_page_previews=False,
+ can_send_polls=False))
+ except ChatAdminRequired:
+ return
+ group_config = _config.get(str(message.chat.id), _config["*"])
+ challenge = Challenge()
+
+ def generate_challenge_button(e):
+ choices = []
+ answers = []
+ for c in e.choices():
+ answers.append(
+ InlineKeyboardButton(str(c),
+ callback_data=bytes(
+ str(c), encoding="utf-8")))
+ choices.append(answers)
+ return choices + [[
+ InlineKeyboardButton(group_config["msg_approve_manually"],
+ callback_data=b"+"),
+ InlineKeyboardButton(group_config["msg_refuse_manually"],
+ callback_data=b"-"),
+ ]]
+
+ timeout = group_config["challenge_timeout"]
+ reply_message = await client.send_photo(
+ message.chat.id,
+ photo = challenge.pu(),
+ caption = group_config["msg_challenge"].format(target=target.first_name,
+ target_id=target.id,
+ timeout=timeout,
+ challenge=challenge.qus()),
+ reply_to_message_id=message.message_id,
+ reply_markup=InlineKeyboardMarkup(
+ generate_challenge_button(challenge)),
+ )
+ _me: User = await client.get_me()
+ chat_id = message.chat.id
+ chat_title = message.chat.title
+ target = message.from_user.id
+ await client.send_message(
+ int(_channel), _config['msg_attempt_try'].format(
+ botid=str(_me.id),
+ targetuser=str(target),
+ groupid=str(chat_id),
+ grouptitle=str(chat_title),
+ ))
+ timeout_event = Timer(
+ challenge_timeout(client, message.chat.id, message.from_user.id, message.chat.title,
+ reply_message.message_id),
+ timeout=group_config["challenge_timeout"],
+ )
+ _cch_lock.acquire()
+ _current_challenges["{chat}|{msg}".format(
+ chat=message.chat.id,
+ msg=reply_message.message_id)] = (challenge, message.from_user.id,
+ timeout_event)
+ _cch_lock.release()
+
+ async def challenge_timeout(client: Client, chat_id, from_id, chat_title, reply_id):
+ global _current_challenges
+ _me: User = await client.get_me()
+ group_config = _config.get(str(chat_id), _config["*"])
+
+ _cch_lock.acquire()
+ del _current_challenges["{chat}|{msg}".format(chat=chat_id,
+ msg=reply_id)]
+ _cch_lock.release()
+
+ # TODO try catch
+ await client.edit_message_caption(
+ chat_id=chat_id,
+ message_id=reply_id,
+ caption=group_config["msg_challenge_timeout"],
+ reply_markup=None,
+ )
+ await client.send_message(chat_id=_config["channel"],
+ text=_config["msg_failed_timeout"].format(
+ botid=str(_me.id),
+ targetuser=str(from_id),
+ grouptitle=str(chat_title),
+ groupid=str(chat_id)))
+ if group_config["challenge_timeout_action"] == "ban":
+ await client.kick_chat_member(chat_id, from_id)
+ elif group_config["challenge_timeout_action"] == "kick":
+ await client.kick_chat_member(chat_id, from_id)
+ await client.unban_chat_member(chat_id, from_id)
+ elif group_config["challenge_timeout_action"] == "mute":
+ await client.restrict_chat_member(
+ chat_id=chat_id,
+ user_id=user_id,
+ permissions=ChatPermissions(can_send_other_messages=False,
+ can_send_messages=False,
+ can_send_media_messages=False,
+ can_add_web_page_previews=False,
+ can_send_polls=False))
+ else:
+ pass
+
+ if group_config["delete_failed_challenge"]:
+ Timer(
+ client.delete_messages(chat_id, reply_id),
+ group_config["delete_failed_challenge_interval"],
+ )
+
+ @app.on_message(Filters.command("challenge"))
+ async def challenge_user(client: Client, message: Message):
+ admins = await client.get_chat_members(message.chat.id,
+ filter="administrators")
+ if not any([
+ admin.user.id == message.from_user.id and
+ (admin.status == "creator" or admin.can_restrict_members)
+ for admin in admins
+ ]):
+ target = message.from_user
+ group_config = _config.get(str(message.chat.id), _config["*"])
+ challenge = Challenge()
+
+ def generate_challenge_button(e):
+ choices = []
+ answers = []
+ for c in e.choices():
+ answers.append(
+ InlineKeyboardButton(str(c),
+ callback_data=bytes(
+ str(c), encoding="utf-8")))
+ choices.append(answers)
+ return choices
+
+ timeout = group_config["challenge_timeout"]
+ reply_message = await client.send_photo(
+ message.chat.id,
+ photo = challenge.pu(),
+ caption = group_config["msg_challeng"].format(target=target.first_name,
+ target_id=target.id,
+ timeout=timeout,
+ challenge=challenge.qus()),
+ reply_to_message_id=message.message_id,
+ reply_markup=InlineKeyboardMarkup(
+ generate_challenge_button(challenge)),
+ )
+ _me: User = await client.get_me()
+ chat_id = message.chat.id
+ chat_title = message.chat.title
+ target = message.from_user.id
+ await client.send_message(
+ int(_channel), _config['msg_challenge_try'].format(
+ botid=str(_me.id),
+ targetuser=str(target),
+ groupid=str(chat_id),
+ grouptitle=str(chat_title),
+ ))
+ timeout_event = Timer(
+ challeng_timeout(client, message.chat.id, message.from_user.id, message.chat.title,
+ reply_message.message_id),
+ timeout=group_config["challenge_timeout"],
+ )
+ _cch_lock.acquire()
+ _current_challenges["{chat}|{msg}".format(
+ chat=message.chat.id,
+ msg=reply_message.message_id)] = (challenge, message.from_user.id,
+ timeout_event)
+ _cch_lock.release()
+
+ async def challeng_timeout(client: Client, chat_id, from_id, chat_title, reply_id):
+ global _current_challenges
+ _me: User = await client.get_me()
+ group_config = _config.get(str(chat_id), _config["*"])
+
+ _cch_lock.acquire()
+ del _current_challenges["{chat}|{msg}".format(chat=chat_id,
+ msg=reply_id)]
+ _cch_lock.release()
+
+ # TODO try catch
+ await client.edit_message_caption(
+ chat_id=chat_id,
+ message_id=reply_id,
+ caption=group_config["msg_challeng_timeout"],
+ reply_markup=None,
+ )
+ await client.send_message(chat_id=_config["channel"],
+ text=_config["msg_challenge_time"].format(
+ botid=str(_me.id),
+ targetuser=str(from_id),
+ grouptitle=str(chat_title),
+ groupid=str(chat_id)))
+
+ if group_config["delete_failed_challenge"]:
+ Timer(
+ client.delete_messages(chat_id, reply_id),
+ group_config["delete_failed_challenge_interval"],
+ )
+
+
+def _main():
+ global _app, _channel, _start_message, _config
+ load_config()
+ _api_id = _config["api_id"]
+ _api_hash = _config["api_hash"]
+ _token = _config["token"]
+ _channel = _config["channel"]
+ _start_message = _config["msg_start_message"]
+ _proxy_ip = _config["proxy_addr"].strip()
+ _proxy_port = _config["proxy_port"].strip()
+ if _proxy_ip and _proxy_port:
+ _app = Client("bot",
+ bot_token=_token,
+ api_id=_api_id,
+ api_hash=_api_hash,
+ proxy=dict(hostname=_proxy_ip, port=int(_proxy_port)))
+ else:
+ _app = Client("bot",
+ bot_token=_token,
+ api_id=_api_id,
+ api_hash=_api_hash)
+ try:
+ _update(_app)
+ _app.run()
+ except KeyboardInterrupt:
+ quit()
+ except Exception as e:
+ logging.error(e)
+ _main()
+
+
+if __name__ == "__main__":
+ _main()
diff --git a/pic/1.png b/pic/1.png
new file mode 100644
index 0000000..5ed0d61
Binary files /dev/null and b/pic/1.png differ
diff --git a/pic/10.png b/pic/10.png
new file mode 100644
index 0000000..c23ba4e
Binary files /dev/null and b/pic/10.png differ
diff --git a/pic/11.png b/pic/11.png
new file mode 100644
index 0000000..4bfced1
Binary files /dev/null and b/pic/11.png differ
diff --git a/pic/12.png b/pic/12.png
new file mode 100644
index 0000000..fba654d
Binary files /dev/null and b/pic/12.png differ
diff --git a/pic/13.png b/pic/13.png
new file mode 100644
index 0000000..5ebc49c
Binary files /dev/null and b/pic/13.png differ
diff --git a/pic/14.png b/pic/14.png
new file mode 100644
index 0000000..91200a5
Binary files /dev/null and b/pic/14.png differ
diff --git a/pic/15.png b/pic/15.png
new file mode 100644
index 0000000..ce95d49
Binary files /dev/null and b/pic/15.png differ
diff --git a/pic/16.png b/pic/16.png
new file mode 100644
index 0000000..a67844d
Binary files /dev/null and b/pic/16.png differ
diff --git a/pic/17.png b/pic/17.png
new file mode 100644
index 0000000..0870c22
Binary files /dev/null and b/pic/17.png differ
diff --git a/pic/18.png b/pic/18.png
new file mode 100644
index 0000000..a805bca
Binary files /dev/null and b/pic/18.png differ
diff --git a/pic/19.png b/pic/19.png
new file mode 100644
index 0000000..28cc3aa
Binary files /dev/null and b/pic/19.png differ
diff --git a/pic/2.png b/pic/2.png
new file mode 100644
index 0000000..d4995b9
Binary files /dev/null and b/pic/2.png differ
diff --git a/pic/20.png b/pic/20.png
new file mode 100644
index 0000000..1b0574c
Binary files /dev/null and b/pic/20.png differ
diff --git a/pic/21.png b/pic/21.png
new file mode 100644
index 0000000..68f4b53
Binary files /dev/null and b/pic/21.png differ
diff --git a/pic/22.png b/pic/22.png
new file mode 100644
index 0000000..86db559
Binary files /dev/null and b/pic/22.png differ
diff --git a/pic/23.png b/pic/23.png
new file mode 100644
index 0000000..46fc174
Binary files /dev/null and b/pic/23.png differ
diff --git a/pic/24.png b/pic/24.png
new file mode 100644
index 0000000..27a19e2
Binary files /dev/null and b/pic/24.png differ
diff --git a/pic/25.png b/pic/25.png
new file mode 100644
index 0000000..310d630
Binary files /dev/null and b/pic/25.png differ
diff --git a/pic/26.png b/pic/26.png
new file mode 100644
index 0000000..c3ed42e
Binary files /dev/null and b/pic/26.png differ
diff --git a/pic/27.png b/pic/27.png
new file mode 100644
index 0000000..78106c3
Binary files /dev/null and b/pic/27.png differ
diff --git a/pic/28.png b/pic/28.png
new file mode 100644
index 0000000..030031b
Binary files /dev/null and b/pic/28.png differ
diff --git a/pic/29.png b/pic/29.png
new file mode 100644
index 0000000..7c19b13
Binary files /dev/null and b/pic/29.png differ
diff --git a/pic/3.png b/pic/3.png
new file mode 100644
index 0000000..bb3e7cc
Binary files /dev/null and b/pic/3.png differ
diff --git a/pic/30.png b/pic/30.png
new file mode 100644
index 0000000..11dfa6f
Binary files /dev/null and b/pic/30.png differ
diff --git a/pic/31.png b/pic/31.png
new file mode 100644
index 0000000..ce0ffc5
Binary files /dev/null and b/pic/31.png differ
diff --git a/pic/32.png b/pic/32.png
new file mode 100644
index 0000000..7262b6a
Binary files /dev/null and b/pic/32.png differ
diff --git a/pic/33.png b/pic/33.png
new file mode 100644
index 0000000..8049adb
Binary files /dev/null and b/pic/33.png differ
diff --git a/pic/34.png b/pic/34.png
new file mode 100644
index 0000000..35d91bb
Binary files /dev/null and b/pic/34.png differ
diff --git a/pic/35.png b/pic/35.png
new file mode 100644
index 0000000..e1f5030
Binary files /dev/null and b/pic/35.png differ
diff --git a/pic/36.png b/pic/36.png
new file mode 100644
index 0000000..ebcba92
Binary files /dev/null and b/pic/36.png differ
diff --git a/pic/37.png b/pic/37.png
new file mode 100644
index 0000000..5929cd2
Binary files /dev/null and b/pic/37.png differ
diff --git a/pic/38.png b/pic/38.png
new file mode 100644
index 0000000..e91ef69
Binary files /dev/null and b/pic/38.png differ
diff --git a/pic/39.png b/pic/39.png
new file mode 100644
index 0000000..1f28dee
Binary files /dev/null and b/pic/39.png differ
diff --git a/pic/4.png b/pic/4.png
new file mode 100644
index 0000000..cc49576
Binary files /dev/null and b/pic/4.png differ
diff --git a/pic/40.png b/pic/40.png
new file mode 100644
index 0000000..cbb3f6c
Binary files /dev/null and b/pic/40.png differ
diff --git a/pic/41.png b/pic/41.png
new file mode 100644
index 0000000..4c7aa09
Binary files /dev/null and b/pic/41.png differ
diff --git a/pic/42.png b/pic/42.png
new file mode 100644
index 0000000..b2d8f09
Binary files /dev/null and b/pic/42.png differ
diff --git a/pic/43.png b/pic/43.png
new file mode 100644
index 0000000..6aec7d9
Binary files /dev/null and b/pic/43.png differ
diff --git a/pic/44.png b/pic/44.png
new file mode 100644
index 0000000..089c615
Binary files /dev/null and b/pic/44.png differ
diff --git a/pic/45.png b/pic/45.png
new file mode 100644
index 0000000..ca7e4ee
Binary files /dev/null and b/pic/45.png differ
diff --git a/pic/46.png b/pic/46.png
new file mode 100644
index 0000000..7e08ea2
Binary files /dev/null and b/pic/46.png differ
diff --git a/pic/47.png b/pic/47.png
new file mode 100644
index 0000000..af3aacc
Binary files /dev/null and b/pic/47.png differ
diff --git a/pic/48.png b/pic/48.png
new file mode 100644
index 0000000..73f17bc
Binary files /dev/null and b/pic/48.png differ
diff --git a/pic/49.png b/pic/49.png
new file mode 100644
index 0000000..f96b483
Binary files /dev/null and b/pic/49.png differ
diff --git a/pic/5.png b/pic/5.png
new file mode 100644
index 0000000..5b6f2bb
Binary files /dev/null and b/pic/5.png differ
diff --git a/pic/50.png b/pic/50.png
new file mode 100644
index 0000000..55dce8c
Binary files /dev/null and b/pic/50.png differ
diff --git a/pic/51.png b/pic/51.png
new file mode 100644
index 0000000..d056a8b
Binary files /dev/null and b/pic/51.png differ
diff --git a/pic/52.png b/pic/52.png
new file mode 100644
index 0000000..60ea008
Binary files /dev/null and b/pic/52.png differ
diff --git a/pic/53.png b/pic/53.png
new file mode 100644
index 0000000..c38f66d
Binary files /dev/null and b/pic/53.png differ
diff --git a/pic/54.png b/pic/54.png
new file mode 100644
index 0000000..75d87fb
Binary files /dev/null and b/pic/54.png differ
diff --git a/pic/55.png b/pic/55.png
new file mode 100644
index 0000000..817b69f
Binary files /dev/null and b/pic/55.png differ
diff --git a/pic/56.png b/pic/56.png
new file mode 100644
index 0000000..17e5332
Binary files /dev/null and b/pic/56.png differ
diff --git a/pic/57.png b/pic/57.png
new file mode 100644
index 0000000..58ac3c9
Binary files /dev/null and b/pic/57.png differ
diff --git a/pic/58.png b/pic/58.png
new file mode 100644
index 0000000..e6623bd
Binary files /dev/null and b/pic/58.png differ
diff --git a/pic/59.png b/pic/59.png
new file mode 100644
index 0000000..2f503f8
Binary files /dev/null and b/pic/59.png differ
diff --git a/pic/6.png b/pic/6.png
new file mode 100644
index 0000000..7539266
Binary files /dev/null and b/pic/6.png differ
diff --git a/pic/60.png b/pic/60.png
new file mode 100644
index 0000000..79b1b17
Binary files /dev/null and b/pic/60.png differ
diff --git a/pic/61.png b/pic/61.png
new file mode 100644
index 0000000..437310c
Binary files /dev/null and b/pic/61.png differ
diff --git a/pic/62.png b/pic/62.png
new file mode 100644
index 0000000..5adab02
Binary files /dev/null and b/pic/62.png differ
diff --git a/pic/63.png b/pic/63.png
new file mode 100644
index 0000000..371bf1a
Binary files /dev/null and b/pic/63.png differ
diff --git a/pic/64.png b/pic/64.png
new file mode 100644
index 0000000..19e5d44
Binary files /dev/null and b/pic/64.png differ
diff --git a/pic/65.png b/pic/65.png
new file mode 100644
index 0000000..b8b3435
Binary files /dev/null and b/pic/65.png differ
diff --git a/pic/66.png b/pic/66.png
new file mode 100644
index 0000000..7a900c2
Binary files /dev/null and b/pic/66.png differ
diff --git a/pic/67.png b/pic/67.png
new file mode 100644
index 0000000..5ae874a
Binary files /dev/null and b/pic/67.png differ
diff --git a/pic/68.png b/pic/68.png
new file mode 100644
index 0000000..3f7abe7
Binary files /dev/null and b/pic/68.png differ
diff --git a/pic/69.png b/pic/69.png
new file mode 100644
index 0000000..c3073d3
Binary files /dev/null and b/pic/69.png differ
diff --git a/pic/7.png b/pic/7.png
new file mode 100644
index 0000000..f562eb2
Binary files /dev/null and b/pic/7.png differ
diff --git a/pic/70.png b/pic/70.png
new file mode 100644
index 0000000..3612827
Binary files /dev/null and b/pic/70.png differ
diff --git a/pic/71.png b/pic/71.png
new file mode 100644
index 0000000..74d9835
Binary files /dev/null and b/pic/71.png differ
diff --git a/pic/72.png b/pic/72.png
new file mode 100644
index 0000000..4d29e3c
Binary files /dev/null and b/pic/72.png differ
diff --git a/pic/73.png b/pic/73.png
new file mode 100644
index 0000000..2b40c31
Binary files /dev/null and b/pic/73.png differ
diff --git a/pic/74.png b/pic/74.png
new file mode 100644
index 0000000..855bf98
Binary files /dev/null and b/pic/74.png differ
diff --git a/pic/75.png b/pic/75.png
new file mode 100644
index 0000000..8400af5
Binary files /dev/null and b/pic/75.png differ
diff --git a/pic/76.png b/pic/76.png
new file mode 100644
index 0000000..522cada
Binary files /dev/null and b/pic/76.png differ
diff --git a/pic/77.png b/pic/77.png
new file mode 100644
index 0000000..73449e9
Binary files /dev/null and b/pic/77.png differ
diff --git a/pic/78.png b/pic/78.png
new file mode 100644
index 0000000..6717214
Binary files /dev/null and b/pic/78.png differ
diff --git a/pic/79.png b/pic/79.png
new file mode 100644
index 0000000..e104eed
Binary files /dev/null and b/pic/79.png differ
diff --git a/pic/8.png b/pic/8.png
new file mode 100644
index 0000000..b61cc05
Binary files /dev/null and b/pic/8.png differ
diff --git a/pic/80.png b/pic/80.png
new file mode 100644
index 0000000..8428bef
Binary files /dev/null and b/pic/80.png differ
diff --git a/pic/81.png b/pic/81.png
new file mode 100644
index 0000000..ff03082
Binary files /dev/null and b/pic/81.png differ
diff --git a/pic/82.png b/pic/82.png
new file mode 100644
index 0000000..ccc06bc
Binary files /dev/null and b/pic/82.png differ
diff --git a/pic/83.png b/pic/83.png
new file mode 100644
index 0000000..7b6ca32
Binary files /dev/null and b/pic/83.png differ
diff --git a/pic/84.png b/pic/84.png
new file mode 100644
index 0000000..f8d193d
Binary files /dev/null and b/pic/84.png differ
diff --git a/pic/85.png b/pic/85.png
new file mode 100644
index 0000000..c261346
Binary files /dev/null and b/pic/85.png differ
diff --git a/pic/86.png b/pic/86.png
new file mode 100644
index 0000000..be93daf
Binary files /dev/null and b/pic/86.png differ
diff --git a/pic/87.png b/pic/87.png
new file mode 100644
index 0000000..b20e0f2
Binary files /dev/null and b/pic/87.png differ
diff --git a/pic/88.png b/pic/88.png
new file mode 100644
index 0000000..a8534f3
Binary files /dev/null and b/pic/88.png differ
diff --git a/pic/89.png b/pic/89.png
new file mode 100644
index 0000000..199290b
Binary files /dev/null and b/pic/89.png differ
diff --git a/pic/9.png b/pic/9.png
new file mode 100644
index 0000000..7ea6b78
Binary files /dev/null and b/pic/9.png differ
diff --git a/pic/90.png b/pic/90.png
new file mode 100644
index 0000000..63902a5
Binary files /dev/null and b/pic/90.png differ
diff --git a/tk.json b/tk.json
new file mode 100644
index 0000000..c0db437
--- /dev/null
+++ b/tk.json
@@ -0,0 +1,7 @@
+[ans]
+a = 3 6 10 12 13 15 19 27 32 39 48 50 51 57 61 68 75 76 78 82 84 87
+b = 2 4 7 11 17 20 21 23 26 34 36 38 41 45 46 49 52 55 62 66 70 71 74 81 83 90
+c = 1 9 14 16 22 28 30 35 37 42 43 44 53 56 59 65 67 72 79 89
+d = 5 8 18 24 25 29 31 33 40 47 54 58 60 63 64 69 73 77 80 85 86 88
+all = 90
+