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