diff --git a/.gitignore b/.gitignore index 70a961d..73e92a1 100644 --- a/.gitignore +++ b/.gitignore @@ -141,3 +141,5 @@ config.ini temp/ assets/icon/ assets/data/list.json +assets/voice/voice.json +ID_DATA.db diff --git a/assets/voice/voice.json.example b/assets/voice/voice.json.example new file mode 100644 index 0000000..a4a160d --- /dev/null +++ b/assets/voice/voice.json.example @@ -0,0 +1 @@ +{"重云 - 突破的感受(起)": "CQACAgUAAxkBAAIDm2HxVmAwtE6UIIdb_mEw1SiKWI-nAAIaBgACMP6IV7trQ3Ew337lHgQ"} \ No newline at end of file diff --git a/ci.py b/ci.py new file mode 100644 index 0000000..d2fe8b4 --- /dev/null +++ b/ci.py @@ -0,0 +1,14 @@ +from configparser import RawConfigParser +from pyrogram import Client +from apscheduler.schedulers.asyncio import AsyncIOScheduler +# 读取配置文件 +config = RawConfigParser() +config.read("config.ini") +bot_token: str = "" +bot_token = config.get("basic", "bot_token", fallback=bot_token) +# 初始化客户端 +scheduler = AsyncIOScheduler() +if not scheduler.running: + scheduler.configure(timezone="Asia/ShangHai") + scheduler.start() +app = Client("bot", bot_token=bot_token) diff --git a/defs/db.py b/defs/db.py new file mode 100644 index 0000000..7469cfc --- /dev/null +++ b/defs/db.py @@ -0,0 +1,363 @@ +import hashlib +import json +import random +import sqlite3 +import re +import string +import time +import traceback + +import requests +from httpx import AsyncClient + +mhyVersion = "2.11.1" + + +async def cookiesDB(uid, Cookies, qid): + conn = sqlite3.connect('ID_DATA.db') + c = conn.cursor() + + c.execute('''CREATE TABLE IF NOT EXISTS NewCookiesTable + (UID INT PRIMARY KEY NOT NULL, + Cookies TEXT, + QID INT, + StatusA TEXT, + StatusB TEXT, + StatusC TEXT, + NUM INT, + Extra TEXT);''') + + c.execute('''CREATE TABLE IF NOT EXISTS CookiesCache + (UID TEXT PRIMARY KEY, + MYSID TEXT, + Cookies TEXT);''') + + cursor = c.execute("SELECT * from NewCookiesTable WHERE UID = ?", (uid,)) + c_data = cursor.fetchall() + if len(c_data) == 0: + c.execute("INSERT OR IGNORE INTO NewCookiesTable (Cookies,UID,StatusA,StatusB,StatusC,NUM,QID) \ + VALUES (?, ?,?,?,?,?,?)", (Cookies, uid, "off", "off", "off", 140, qid)) + else: + c.execute("UPDATE NewCookiesTable SET Cookies = ? WHERE UID=?", (Cookies, uid)) + + conn.commit() + conn.close() + + +async def deal_ck(mes, qid): + aid = re.search(r"account_id=(\d*)", mes) + mysid_data = aid.group(0).split('=') + mysid = mysid_data[1] + cookie = ';'.join(filter(lambda x: x.split('=')[0] in [ + "cookie_token", "account_id"], [i.strip() for i in mes.split(';')])) + mys_data = await GetMysInfo(mysid, cookie) + for i in mys_data['data']['list']: + if i['game_id'] != 2: + mys_data['data']['list'].remove(i) + uid = mys_data['data']['list'][0]['game_role_id'] + + conn = sqlite3.connect('ID_DATA.db') + c = conn.cursor() + + test = c.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name = 'CookiesCache'") + if test == 0: + pass + else: + try: + c.execute("DELETE from CookiesCache where uid=? or mysid = ?", (uid, mysid)) + except sqlite3.OperationalError: + pass + + conn.commit() + conn.close() + + await cookiesDB(uid, cookie, qid) + + +def md5(text): + md5_ = hashlib.md5() + md5_.update(text.encode()) + return md5_.hexdigest() + + +def random_hex(length): + result = hex(random.randint(0, 16 ** length)).replace('0x', '').upper() + if len(result) < length: + result = "0" * (length - len(result)) + result + return result + + +def oldDSGet(): + n = "h8w582wxwgqvahcdkpvdhbh2w9casgfl" + i = str(int(time.time())) + r = ''.join(random.sample(string.ascii_lowercase + string.digits, 6)) + c = md5("salt=" + n + "&t=" + i + "&r=" + r) + return i + "," + r + "," + c + + +def DSGet(q="", b=None): + if b: + br = json.dumps(b) + else: + br = "" + s = "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs" + t = str(int(time.time())) + r = str(random.randint(100000, 200000)) + c = md5("salt=" + s + "&t=" + t + "&r=" + r + "&b=" + br + "&q=" + q) + return t + "," + r + "," + c + + +async def GetMysInfo(mysid, ck): + try: + async with AsyncClient() as client: + req = await client.get( + url="https://api-takumi.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid=" + mysid, + headers={ + 'DS': DSGet("uid=" + mysid), + 'x-rpc-app_version': mhyVersion, + 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1', + 'x-rpc-client_type': '5', + 'Referer': 'https://webstatic.mihoyo.com/', + "Cookie": ck}) + data = json.loads(req.text) + return data + except requests.exceptions.SSLError: + try: + async with AsyncClient() as client: + req = await client.get( + url="https://api-takumi-record.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid=" + mysid, + headers={ + 'DS': DSGet("uid=" + mysid), + 'x-rpc-app_version': mhyVersion, + 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1', + 'x-rpc-client_type': '5', + 'Referer': 'https://webstatic.mihoyo.com/', + "Cookie": ck}) + data = json.loads(req.text) + return data + except json.decoder.JSONDecodeError: + print("米游社信息读取新Api失败!") + except Exception as e: + print("米游社信息读取老Api失败!") + print(e.with_traceback) + + +async def selectDB(userid, mode="auto"): + conn = sqlite3.connect('ID_DATA.db') + c = conn.cursor() + cursor = c.execute("SELECT * FROM UIDDATA WHERE USERID = ?", (userid,)) + for row in cursor: + if mode == "auto": + if row[0]: + if row[2]: + return [row[2], 3] + elif row[1]: + return [row[1], 2] + else: + return None + else: + return None + elif mode == "uid": + return [row[1], 2] + elif mode == "mys": + return [row[2], 3] + + +async def OpenPush(uid, qid, status, mode): + conn = sqlite3.connect('ID_DATA.db') + c = conn.cursor() + cursor = c.execute("SELECT * from NewCookiesTable WHERE UID = ?", (uid,)) + c_data = cursor.fetchall() + if len(c_data) != 0: + try: + c.execute("UPDATE NewCookiesTable SET {s} = ?,QID = ? WHERE UID=?".format(s=mode), (status, qid, uid)) + conn.commit() + conn.close() + return "成功!" + except: + return "未找到Ck绑定记录。" + else: + return "未找到Ck绑定记录。" + + +async def OwnerCookies(uid): + conn = sqlite3.connect('ID_DATA.db') + c = conn.cursor() + try: + cursor = c.execute("SELECT * FROM NewCookiesTable WHERE UID = ?", (uid,)) + c_data = cursor.fetchall() + cookies = c_data[0][1] + except: + return + return cookies + + +async def GetAward(Uid, ServerID="cn_gf01"): + if Uid[0] == '5': + ServerID = "cn_qd01" + try: + async with AsyncClient() as client: + req = await client.get( + url="https://hk4e-api.mihoyo.com/event/ys_ledger/monthInfo?month={}&bind_uid={}&bind_region={}&bbs_presentation_style=fullscreen&bbs_auth_required=true&utm_source=bbs&utm_medium=mys&utm_campaign=icon".format( + "0", Uid, ServerID), + headers={ + 'x-rpc-app_version': mhyVersion, + "Cookie": await OwnerCookies(Uid), + 'DS': oldDSGet(), + "x-rpc-device_id": random_hex(32), + 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1', + 'x-rpc-client_type': '5', + 'Referer': 'https://webstatic.mihoyo.com/'}) + data = json.loads(req.text) + return data + except: + traceback.print_exc() + print("访问失败,请重试!") + # sys.exit(1) + + +async def MysSign(Uid, ServerID="cn_gf01"): + if Uid[0] == '5': + ServerID = "cn_qd01" + try: + req = requests.post( + url="https://api-takumi.mihoyo.com/event/bbs_sign_reward/sign", + headers={ + 'User_Agent': 'Mozilla/5.0 (Linux; Android 10; MIX 2 Build/QKQ1.190825.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.101 Mobile Safari/537.36 miHoYoBBS/2.3.0', + "Cookie": await OwnerCookies(Uid), + "x-rpc-device_id": random_hex(32), + 'Origin': 'https://webstatic.mihoyo.com', + 'X_Requested_With': 'com.mihoyo.hyperion', + 'DS': oldDSGet(), + 'x-rpc-client_type': '5', + 'Referer': 'https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true&act_id=e202009291139501&utm_source=bbs&utm_medium=mys&utm_campaign=icon', + 'x-rpc-app_version': '2.3.0' + }, + json={"act_id": "e202009291139501", "uid": Uid, "region": ServerID} + ) + data2 = json.loads(req.text) + return data2 + except: + print("签到失败,请重试") + + +async def GetSignInfo(Uid, ServerID="cn_gf01"): + if Uid[0] == '5': + ServerID = "cn_qd01" + try: + async with AsyncClient() as client: + req = await client.get( + url="https://api-takumi.mihoyo.com/event/bbs_sign_reward/info?act_id=e202009291139501®ion=" + ServerID + "&uid=" + Uid, + headers={ + 'x-rpc-app_version': mhyVersion, + "Cookie": await OwnerCookies(Uid), + 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1', + 'x-rpc-client_type': '5', + 'Referer': 'https://webstatic.mihoyo.com/'}) + data = json.loads(req.text) + return data + except: + print("获取签到信息失败,请重试") + + +async def GetSignList(): + try: + async with AsyncClient() as client: + req = await client.get( + url="https://api-takumi.mihoyo.com/event/bbs_sign_reward/home?act_id=e202009291139501", + headers={ + 'x-rpc-app_version': mhyVersion, + 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1', + 'x-rpc-client_type': '5', + 'Referer': 'https://webstatic.mihoyo.com/'}) + data = json.loads(req.text) + return data + except: + print("获取签到奖励列表失败,请重试") + + +async def CheckDB(): + str = '' + conn = sqlite3.connect('ID_DATA.db') + c = conn.cursor() + cursor = c.execute("SELECT UID,Cookies from NewCookiesTable") + c_data = cursor.fetchall() + for row in c_data: + try: + aid = re.search(r"account_id=(\d*)", row[1]) + mysid_data = aid.group(0).split('=') + mysid = mysid_data[1] + mys_data = await GetMysInfo(mysid, row[1]) + for i in mys_data['data']['list']: + if i['game_id'] != 2: + mys_data['data']['list'].remove(i) + uid = mys_data['data']['list'][0]['game_role_id'] + str = str + f"uid{row[0]}/mysid{mysid}的Cookies是正常的!\n" + except: + str = str + f"uid{row[0]}的Cookies是异常的!已删除该条Cookies!\n" + c.execute("DELETE from NewCookiesTable where UID=?", (row[0],)) + test = c.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name = 'CookiesCache'") + if test == 0: + pass + else: + c.execute("DELETE from CookiesCache where Cookies=?", (row[1],)) + conn.commit() + conn.close() + return str + + +async def GetDaily(Uid, ServerID="cn_gf01"): + if Uid[0] == '5': + ServerID = "cn_qd01" + try: + async with AsyncClient() as client: + req = await client.get( + url="https://api-takumi.mihoyo.com/game_record/app/genshin/api/dailyNote?server=" + ServerID + "&role_id=" + Uid, + headers={ + 'DS': DSGet("role_id=" + Uid + "&server=" + ServerID), + 'x-rpc-app_version': mhyVersion, + 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1', + 'x-rpc-client_type': '5', + 'Referer': 'https://webstatic.mihoyo.com/', + "Cookie": await OwnerCookies(Uid)}) + data = json.loads(req.text) + return data + except requests.exceptions.SSLError: + try: + async with AsyncClient() as client: + req = await client.get( + url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote?server=" + ServerID + "&role_id=" + Uid, + headers={ + 'DS': DSGet("role_id=" + Uid + "&server=" + ServerID), + 'x-rpc-app_version': mhyVersion, + 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1', + 'x-rpc-client_type': '5', + 'Referer': 'https://webstatic.mihoyo.com/', + "Cookie": await OwnerCookies(Uid)}) + data = json.loads(req.text) + return data + except json.decoder.JSONDecodeError: + print("当前状态读取Api失败!") + except Exception as e: + print("访问每日信息失败,请重试!") + print(e.with_traceback) + + +async def connectDB(userid, uid=None, mys=None): + conn = sqlite3.connect('ID_DATA.db') + c = conn.cursor() + c.execute('''CREATE TABLE IF NOT EXISTS UIDDATA + (USERID INT PRIMARY KEY NOT NULL, + UID TEXT, + MYSID TEXT);''') + + c.execute("INSERT OR IGNORE INTO UIDDATA (USERID,UID,MYSID) \ + VALUES (?, ?,?)", (userid, uid, mys)) + + if uid: + c.execute("UPDATE UIDDATA SET UID = ? WHERE USERID=?", (uid, userid)) + if mys: + c.execute("UPDATE UIDDATA SET MYSID = ? WHERE USERID=?", (mys, userid)) + + conn.commit() + conn.close() diff --git a/defs/inline_query_result_cached_media.py b/defs/inline_query_result_cached_media.py new file mode 100644 index 0000000..77edc44 --- /dev/null +++ b/defs/inline_query_result_cached_media.py @@ -0,0 +1,146 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan httpsgithub.comdelivrance +# +# This file is part of Pyrogram. +# +# Pyrogram is free software you can redistribute it andor modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Optional, List, Union + +import pyrogram +from pyrogram import raw, types, utils +from pyrogram.types import InlineQueryResult +from pyrogram.file_id import FileId, FileType, PHOTO_TYPES, DOCUMENT_TYPES + + +def get_input_file_from_file_id( + file_id: str, + expected_file_type: FileType = None +) -> Union["raw.types.InputPhoto", "raw.types.InputDocument"]: + try: + decoded = FileId.decode(file_id) + except Exception: + raise ValueError(f'Failed to decode "{file_id}". The value does not represent an existing local file, ' + f'HTTP URL, or valid file id.') + + file_type = decoded.file_type + + if expected_file_type is not None and file_type != expected_file_type: + raise ValueError(f'Expected: "{expected_file_type}", got "{file_type}" file_id instead') + + if file_type in (FileType.THUMBNAIL, FileType.CHAT_PHOTO): + raise ValueError(f"This file_id can only be used for download: {file_id}") + + if file_type in PHOTO_TYPES: + return raw.types.InputPhoto( + id=decoded.media_id, + access_hash=decoded.access_hash, + file_reference=decoded.file_reference + ) + + if file_type in DOCUMENT_TYPES: + return raw.types.InputDocument( + id=decoded.media_id, + access_hash=decoded.access_hash, + file_reference=decoded.file_reference + ) + + raise ValueError(f"Unknown file id: {file_id}") + + +class InlineQueryResultCachedDocument(InlineQueryResult): + """Link to a file stored on the Telegram servers. + + By default, this file will be sent by the user with an optional caption. + Alternatively, you can use input_message_content to send a message with the specified content instead of the file. + + Parameters: + title (``str``): + Title for the result. + + file_id (``str``): + Pass a file_id as string to send a media that exists on the Telegram servers. + + id (``str``, *optional*): + Unique identifier for this result, 1-64 bytes. + Defaults to a randomly generated UUID4. + + description (``str``, *optional*): + Short description of the result. + + caption (``str``, *optional*): + Caption of the document to be sent, 0-1024 characters. + + parse_mode (``str``, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + Pass "markdown" or "md" to enable Markdown-style parsing only. + Pass "html" to enable HTML-style parsing only. + Pass None to completely disable style parsing. + caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): + List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup`, *optional*): + Inline keyboard attached to the message. + + input_message_content (:obj:`~pyrogram.types.InputMessageContent`): + Content of the message to be sent. + """ + + def __init__( + self, + title: str, + file_id: str, + id: str = None, + description: str = None, + caption: str = "", + parse_mode: Optional[str] = object, + caption_entities: List["types.MessageEntity"] = None, + reply_markup: "types.InlineKeyboardMarkup" = None, + input_message_content: "types.InputMessageContent" = None + ): + super().__init__("file", id, input_message_content, reply_markup) + + self.file_id = file_id + self.title = title + self.description = description + self.caption = caption + self.caption_entities = caption_entities + self.parse_mode = parse_mode + self.reply_markup = reply_markup + self.input_message_content = input_message_content + + async def write(self, client: "pyrogram.Client"): + document = get_input_file_from_file_id(self.file_id) + + message, entities = (await utils.parse_text_entities( + client, self.caption, self.parse_mode, self.caption_entities + )).values() + + return raw.types.InputBotInlineResultDocument( + id=self.id, + type=self.type, + title=self.title, + description=self.description, + document=document, + send_message=( + await self.input_message_content.write(client, self.reply_markup) + if self.input_message_content + else raw.types.InputBotInlineMessageMediaAuto( + reply_markup=await self.reply_markup.write(client) if self.reply_markup else None, + message=message, + entities=entities + ) + ) + ) diff --git a/defs/mys2.py b/defs/mys2.py new file mode 100644 index 0000000..404e723 --- /dev/null +++ b/defs/mys2.py @@ -0,0 +1,216 @@ +import math +import sqlite3 + +from defs.db import GetAward, MysSign, GetSignInfo, GetSignList, GetDaily + +avatar_json = { + "Albedo": "阿贝多", + "Ambor": "安柏", + "Barbara": "芭芭拉", + "Beidou": "北斗", + "Bennett": "班尼特", + "Chongyun": "重云", + "Diluc": "迪卢克", + "Diona": "迪奥娜", + "Eula": "优菈", + "Fischl": "菲谢尔", + "Ganyu": "甘雨", + "Hutao": "胡桃", + "Jean": "琴", + "Kazuha": "枫原万叶", + "Kaeya": "凯亚", + "Ayaka": "神里绫华", + "Keqing": "刻晴", + "Klee": "可莉", + "Lisa": "丽莎", + "Mona": "莫娜", + "Ningguang": "凝光", + "Noel": "诺艾尔", + "Qiqi": "七七", + "Razor": "雷泽", + "Rosaria": "罗莎莉亚", + "Sucrose": "砂糖", + "Tartaglia": "达达利亚", + "Venti": "温迪", + "Xiangling": "香菱", + "Xiao": "魈", + "Xingqiu": "行秋", + "Xinyan": "辛焱", + "Yanfei": "烟绯", + "Zhongli": "钟离", + "Yoimiya": "宵宫", + "Sayu": "早柚", + "Shogun": "雷电将军", + "Aloy": "埃洛伊", + "Sara": "九条裟罗", + "Kokomi": "珊瑚宫心海", + "Shenhe": "申鹤" +} +daily_im = ''' +*数据刷新可能存在一定延迟,请以当前游戏实际数据为准{} +============== +原粹树脂:{}/{}{} +每日委托:{}/{} 奖励{}领取 +周本减半:{}/{} +洞天宝钱:{} +探索派遣: +总数/完成/上限:{}/{}/{} +{}''' +month_im = ''' +============== +{} +UID:{} +============== +本日获取原石:{} +本日获取摩拉:{} +============== +昨日获取原石:{} +昨日获取摩拉:{} +============== +本月获取原石:{} +本月获取摩拉:{} +============== +上月获取原石:{} +上月获取摩拉:{} +============== +原石收入组成: +{}==============''' + + +async def award(uid): + data = await GetAward(uid) + nickname = data['data']['nickname'] + day_stone = data['data']['day_data']['current_primogems'] + day_mora = data['data']['day_data']['current_mora'] + lastday_stone = data['data']['day_data']['last_primogems'] + lastday_mora = data['data']['day_data']['last_mora'] + month_stone = data['data']['month_data']['current_primogems'] + month_mora = data['data']['month_data']['current_mora'] + lastmonth_stone = data['data']['month_data']['last_primogems'] + lastmonth_mora = data['data']['month_data']['last_mora'] + group_str = '' + for i in data['data']['month_data']['group_by']: + group_str = group_str + \ + i['action'] + ":" + str(i['num']) + \ + "(" + str(i['percent']) + "%)" + '\n' + + im = month_im.format(nickname, uid, day_stone, day_mora, lastday_stone, lastday_mora, + month_stone, month_mora, lastmonth_stone, lastmonth_mora, group_str) + return im + + +# 签到函数 +async def sign(uid): + try: + sign_data = await MysSign(uid) + sign_info = await GetSignInfo(uid) + sign_info = sign_info['data'] + sign_list = await GetSignList() + status = sign_data['message'] + getitem = sign_list['data']['awards'][int( + sign_info['total_sign_day']) - 1]['name'] + getnum = sign_list['data']['awards'][int( + sign_info['total_sign_day']) - 1]['cnt'] + get_im = f"本次签到获得{getitem}x{getnum}" + if status == "OK" and sign_info['is_sign']: + mes_im = "签到成功" + else: + mes_im = status + sign_missed = sign_info['sign_cnt_missed'] + im = mes_im + "!" + "\n" + get_im + "\n" + f"本月漏签次数:{sign_missed}" + except: + im = "签到失败,请检查Cookies是否失效。" + return im + + +# 统计状态函数 +async def daily(mode="push", uid=None): + def seconds2hours(seconds: int) -> str: + m, s = divmod(int(seconds), 60) + h, m = divmod(m, 60) + return "%02d:%02d:%02d" % (h, m, s) + + temp_list = [] + conn = sqlite3.connect('ID_DATA.db') + c = conn.cursor() + if mode == "ask": + c_data = ([uid, 0, 0, 0, 0, 0, 0],) + else: + cursor = c.execute( + "SELECT * FROM NewCookiesTable WHERE StatusA != ?", ("off",)) + c_data = cursor.fetchall() + + for row in c_data: + raw_data = await GetDaily(str(row[0])) + if raw_data["retcode"] != 0: + temp_list.append( + {"qid": row[2], "gid": row[3], "message": "你的推送状态有误;可能是uid绑定错误或没有在米游社打开“实时便筏”功能。"}) + else: + dailydata = raw_data["data"] + current_resin = dailydata['current_resin'] + + current_expedition_num = dailydata['current_expedition_num'] + max_expedition_num = dailydata['max_expedition_num'] + finished_expedition_num = 0 + expedition_info: list[str] = [] + for expedition in dailydata['expeditions']: + avatar: str = expedition['avatar_side_icon'][89:-4] + try: + avatar_name: str = avatar_json[avatar] + except KeyError: + avatar_name: str = avatar + + if expedition['status'] == 'Finished': + expedition_info.append(f"{avatar_name} 探索完成") + finished_expedition_num += 1 + else: + remained_timed: str = seconds2hours( + expedition['remained_time']) + expedition_info.append( + f"{avatar_name} 剩余时间{remained_timed}") + + if current_resin >= row[6] or dailydata["max_home_coin"] - dailydata[ + "current_home_coin"] <= 100 or finished_expedition_num > 0: + tip = '' + + if current_resin >= row[6] != 0: + tip += "\n==============\n你的树脂快满了!" + if dailydata["max_home_coin"] - dailydata["current_home_coin"] <= 100: + tip += "\n==============\n你的洞天宝钱快满了!" + if finished_expedition_num > 0: + tip += "\n==============\n你有探索派遣完成了!" + max_resin = dailydata['max_resin'] + rec_time = '' + # print(dailydata) + if current_resin < 160: + resin_recovery_time = seconds2hours( + dailydata['resin_recovery_time']) + next_resin_rec_time = seconds2hours( + 8 * 60 - ((dailydata['max_resin'] - dailydata['current_resin']) * 8 * 60 - int( + dailydata['resin_recovery_time']))) + rec_time = f' ({next_resin_rec_time}/{resin_recovery_time})' + + finished_task_num = dailydata['finished_task_num'] + total_task_num = dailydata['total_task_num'] + is_extra_got = '已' if dailydata['is_extra_task_reward_received'] else '未' + + resin_discount_num_limit = dailydata['resin_discount_num_limit'] + used_resin_discount_num = resin_discount_num_limit - \ + dailydata['remain_resin_discount_num'] + + coin = f'{dailydata["current_home_coin"]}/{dailydata["max_home_coin"]}' + if dailydata["current_home_coin"] < dailydata["max_home_coin"]: + coin_rec_time = seconds2hours(int(dailydata["home_coin_recovery_time"])) + coin_add_speed = math.ceil((dailydata["max_home_coin"] - dailydata["current_home_coin"]) / ( + int(dailydata["home_coin_recovery_time"]) / 60 / 60)) + coin += f'({coin_rec_time} 约{coin_add_speed}/h)' + + expedition_data = "\n".join(expedition_info) + send_mes = daily_im.format(tip, current_resin, max_resin, rec_time, finished_task_num, total_task_num, + is_extra_got, used_resin_discount_num, + resin_discount_num_limit, coin, current_expedition_num, + finished_expedition_num, max_expedition_num, expedition_data) + + temp_list.append( + {"qid": row[2], "gid": row[3], "message": send_mes}) + return temp_list diff --git a/main.py b/main.py index 4c23079..22ac90a 100644 --- a/main.py +++ b/main.py @@ -1,15 +1,6 @@ import logging -from configparser import RawConfigParser -from pyrogram import Client - +from ci import app # 日志记录 logging.basicConfig(level=logging.INFO) -# 读取配置文件 -config = RawConfigParser() -config.read("config.ini") -bot_token: str = "" -bot_token = config.get("basic", "bot_token", fallback=bot_token) -# 初始化客户端 -app = Client("bot", bot_token=bot_token) app.run() diff --git a/plugins/mys2.py b/plugins/mys2.py new file mode 100644 index 0000000..9b772fd --- /dev/null +++ b/plugins/mys2.py @@ -0,0 +1,197 @@ +import asyncio +import random +import re +import sqlite3 +import traceback + +from pyrogram import Client +from pyrogram.types import Message + +from defs.db import deal_ck, selectDB, OpenPush, CheckDB, connectDB +from defs.event import generate_event +from defs.mys2 import award, sign, daily + +from ci import scheduler, app + +SUPERUSERS = [] + + +async def mys2_msg(client: Client, message: Message): + text = message.text.replace("米游社", "") + userid = message.from_user.id + if '添加 ' in text: + try: + mes = text.replace('添加', '').strip() + if not mes: + return await message.reply_text("获取 Cookie 请参考:[link](https://github.com/Womsxd/AutoMihoyoBBS/" + "#%E8%8E%B7%E5%8F%96%E7%B1%B3%E6%B8%B8%E7%A4%BEcookie)", quote=True) + await deal_ck(mes, userid) + await message.reply(f'添加Cookies成功!\n' + f'Cookies属于个人重要信息,如果你是在不知情的情况下添加,' + f'请马上修改米游社账户密码,保护个人隐私!\n' + f'=============\n' + f'如果需要【开启自动签到】和【开启推送】还需要使用命令 ' + f'米游社绑定uid绑定你的uid。\n' + f'例如:米游社绑定uid123456789。') + except Exception as e: + traceback.print_exc() + await message.reply(f'校验失败!请输入正确的Cookies!', quote=True) + elif '推送' in text: + try: + uid = await selectDB(userid, mode="uid") + if '开启' in text: + im = await OpenPush(int(uid[0]), userid, "on", "StatusA") + await message.reply(im, quote=True) + else: + im = await OpenPush(int(uid[0]), userid, "off", "StatusA") + await message.reply(im, quote=True) + except Exception as e: + print(e.with_traceback) + await message.reply("未找到uid绑定记录。", quote=True) + elif '自动签到' in text: + try: + uid = await selectDB(userid, mode="uid") + if '开启' in text: + im = await OpenPush(int(uid[0]), userid, "on", "StatusB") + await message.reply(im, quote=True) + else: + im = await OpenPush(int(uid[0]), userid, "off", "StatusA") + await message.reply(im, quote=True) + except Exception as e: + print(e.with_traceback) + await message.reply("未找到uid绑定记录。", quote=True) + + +async def mys2_qun_msg(client: Client, message: Message): + text = message.text.replace("米游社", "") + + qid = message.from_user.id + at = message.reply_to_message + if "自动签到" in text: + try: + if at and qid in SUPERUSERS: + qid = at.from_user.id + elif at and qid not in SUPERUSERS: + return await message.reply("你没有权限。") + gid = message.chat.id + uid = await selectDB(qid, mode="uid") + if "开启" in text: + im = await OpenPush(int(uid[0]), message.from_user.id, str(gid), "StatusB") + await message.reply(im, quote=True) + elif "关闭" in text: + im = await OpenPush(int(uid[0]), message.from_user.id, "off", "StatusB") + await message.reply(im) + except Exception as e: + print(e.with_traceback) + await message.reply("未绑定uid信息!") + elif "推送" in text: + try: + if at and qid in SUPERUSERS: + qid = at.from_user.id + elif at and qid not in SUPERUSERS: + return await message.reply("你没有权限。") + gid = message.chat.id + uid = await selectDB(qid, mode="uid") + if "开启" in text: + im = await OpenPush(int(uid[0]), message.from_user.id, str(gid), "StatusA") + await message.reply(im, quote=True) + elif "关闭" in text: + im = await OpenPush(int(uid[0]), message.from_user.id, "off", "StatusA") + await message.reply(im) + except Exception as e: + print(e.with_traceback) + await message.reply("未绑定uid信息!") + elif "每月统计" in text: + try: + uid = await selectDB(message.from_user.id, mode="uid") + uid = uid[0] + im = await award(uid) + await message.reply(im) + except Exception as e: + traceback.print_exc() + await message.reply('未找到绑定信息') + elif "签到" in text: + try: + uid = await selectDB(message.from_user.id, mode="uid") + uid = uid[0] + im = await sign(uid) + await message.reply(im) + except Exception as e: + print(e.with_traceback) + await message.reply('未找到绑定信息') + elif "效验全部" in text: + im = await CheckDB() + await message.reply(im) + elif "当前状态" in text: + try: + uid = await selectDB(message.from_user.id, mode="uid") + uid = uid[0] + mes = await daily("ask", uid) + im = mes[0]['message'] + except Exception as e: + print(e.with_traceback) + im = "没有找到绑定信息。" + await message.reply(im) + elif "绑定uid" in text: + uid = text.replace("绑定uid", "") # str + await connectDB(message.from_user.id, uid) + await message.reply('绑定uid成功!') + elif "绑定mys" in text: + mys = text.replace("绑定mys", "") # str + await connectDB(message.from_user.id, None, mys) + await message.reply('绑定米游社id成功!') + + +# 每隔一小时检测树脂是否超过设定值 +@scheduler.scheduled_job('interval', hours=1) +async def push(): + daily_data = await daily() + if daily_data is not None: + for i in daily_data: + if i['gid'] == "on": + await app.send_message(int(i['qid']), i['message']) + else: + await app.send_message(int(i['gid']), f"[NOTICE](tg://user?id={i['qid']})" + "\n" + i['message']) + else: + pass + + +# 每日零点半进行米游社签到 +@scheduler.scheduled_job('cron', hour='0', minute="30") +async def daily_sign(): + conn = sqlite3.connect('ID_DATA.db') + c = conn.cursor() + cursor = c.execute( + "SELECT * FROM NewCookiesTable WHERE StatusB != ?", ("off",)) + c_data = cursor.fetchall() + temp_list = [] + + for row in c_data: + if row[4] == "on": + try: + im = await sign(str(row[0])) + await app.send_message(int(row[2]), im) + except Exception as e: + traceback.print_exc() + else: + im = await sign(str(row[0])) + message = f"[CQ:at,qq={row[2]}]\n{im}" + for i in temp_list: + if row[4] == i["push_group"]: + i["push_message"] = i["push_message"] + "\n" + message + break + else: + temp_list.append({"push_group": row[4], "push_message": message}) + await asyncio.sleep(6 + random.randint(0, 2)) + + for i in temp_list: + try: + await app.send_message(int(i["push_group"]), i["push_message"]) + except Exception as e: + traceback.print_exc() + await asyncio.sleep(3 + random.randint(0, 2)) + + +@scheduler.scheduled_job('cron', hour='2') +async def delete(): + await generate_event() diff --git a/plugins/process.py b/plugins/process.py index fa1d330..8b3d3f9 100644 --- a/plugins/process.py +++ b/plugins/process.py @@ -1,6 +1,12 @@ -from pyrogram import Client -from pyrogram.types import Message +import json +from os import sep +from os.path import exists + +from pyrogram import Client, emoji +from pyrogram.types import Message, InlineQuery from pyrogram import filters as Filters + +from plugins.mys2 import mys2_msg, mys2_qun_msg from plugins.start import welcome_command, ping_command, help_command, leave_command from plugins.almanac import almanac_msg from plugins.challenge import tf_msg, wq_msg, zb_msg @@ -12,6 +18,8 @@ from plugins.artifacts import artifacts_msg from plugins.artifact_rate import artifact_rate_msg from plugins.query_resource_points import inquire_resource_points, inquire_resource_list from plugins.mys import mys_msg, promote_command + +from defs.inline_query_result_cached_media import InlineQueryResultCachedDocument from defs.log import log @@ -88,6 +96,8 @@ async def process_private_msg(client: Client, message: Message): if '资源列表' in message.text: await inquire_resource_list(client, message) await log(client, message, '查询资源列表') + if '米游社' in message.text: + await mys2_msg(client, message) # 账号信息(cookie 过期过快 不推荐启用) # if '账号信息' in message.text or '用户信息' in message.text: # await mys_msg(client, message) @@ -155,6 +165,9 @@ async def process_group_msg(client: Client, message: Message): if text.startswith('资源列表'): await inquire_resource_list(client, message) await log(client, message, '查询资源列表') + # 米游社功能 + if text.startswith('米游社'): + await mys2_qun_msg(client, message) @Client.on_message(Filters.photo) @@ -166,9 +179,42 @@ async def process_photo(client: Client, message: Message): await log(client, message, '圣遗物评分') +@Client.on_message(Filters.audio & Filters.private & ~Filters.edited) +async def process_audio(client: Client, message: Message): + await message.reply(f"File_id:{message.audio.file_id}") + + @Client.on_message(Filters.new_chat_members) async def send_self_intro(client: Client, message: Message): # 发送欢迎消息 if message.new_chat_members[0].is_self: await message.reply('感谢邀请小派蒙到本群!\n请使用 /help 查看咱已经学会的功能。', quote=True) await log(client, message, '邀请入群') + + +@Client.on_inline_query() +async def inline_process(client: Client, query: InlineQuery): + data = [] + text = query.query + nums = 0 + if not exists(f"assets{sep}voice{sep}voice.json"): + return + with open(f"assets{sep}voice{sep}voice.json", "r", encoding='utf-8') as f: + data_ = json.load(f) + for index, value in enumerate(data_): + if text != "": + if text in value: + data.append(InlineQueryResultCachedDocument(value, file_id=data_[value])) + nums += 1 + else: + data.append(InlineQueryResultCachedDocument(value, file_id=data_[value])) + nums += 1 + if nums >= 25: + break + if nums == 0: + return await query.answer( + results=[], + switch_pm_text=f'{emoji.CROSS_MARK} 字符串 "{text}" 没有搜索到任何结果', + switch_pm_parameter="start", + ) + await query.answer(data) diff --git a/plugins/start.py b/plugins/start.py index 5ee3b24..745710a 100644 --- a/plugins/start.py +++ b/plugins/start.py @@ -39,7 +39,7 @@ async def leave_command(client: Client, message: Message): async def help_command(client: Client, message: Message): - text = 'PaimonBot 0.2.3beta By Xtao-Labs\n\n' \ + text = 'PaimonBot 0.2.5beta By Xtao-Labs\n\n' \ '🔅 以下是小派蒙我学会了的功能(部分):\n' \ '① [武器/今日武器] 查看今日武器材料和武器\n' \ '② [天赋/今日天赋] 查看今日天赋材料和角色\n' \ @@ -57,5 +57,14 @@ async def help_command(client: Client, message: Message): '⑨ [活动列表] 查看今日活动列表和祈愿列表\n' \ '⑩ [圣遗物评分] 我也想拥有这种分数的圣遗物(切实)\n' \ '(11) [哪里有 (资源名)] 查看资源的位置\n' \ - '(12) [资源列表] 查看原神所有资源' + '(12) [资源列表] 查看原神所有资源\n' \ + '(13) [米游社] 米游社相关功能\n' \ + ' 💠 米游社添加(私聊)\n' \ + ' 💠 米游社推送开启/关闭\n' \ + ' 💠 米游社自动签到开启/关闭\n' \ + ' 💠 米游社每月统计(群聊)\n' \ + ' 💠 米游社签到(群聊)\n' \ + ' 💠 米游社当前状态(群聊)\n' \ + ' 💠 米游社绑定uid(群聊)\n' \ + ' 💠 米游社绑定mys(群聊)' await message.reply(text, quote=True, disable_web_page_preview=True) diff --git a/requirements.txt b/requirements.txt index 7eece31..d5b994f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,5 @@ xpinyin>=0.7.6 lxml>=4.6.3 httpx>=0.21.3 pyyaml>=6.0 +httpx==0.18.1 +apscheduler>=3.8.1