diff --git a/README.md b/README.md index 35ff489..c7fec14 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,54 @@ docker-compose pull && docker-compose up -d 2. 点击`测试函数` 7. 完成 +## 使用青龙面板运行(V2.12+) + +### 1.拉取仓库 + +方式1:订阅管理 + +``` +名称:米游社签到 +类型:公开仓库 +链接:https://github.com/Womsxd/AutoMihoyoBBS.git +定时类型:crontab +定时规则:2 2 28 * * +白名单:ql_main.py +依赖文件:error|mihoyo|genshin|honkai3rd|log|push|req|set|tools|con|acc|honkai2|tearsofthemis|captcha|main +``` + +方式2:指令拉取 + +```sh +ql repo https://github.com/Womsxd/AutoMihoyoBBS.git "ql_main.py" "" "error|mihoyo|genshin|honkai3rd|log|push|req|set|tools|con|acc|honkai2|tearsofthemis|captcha|main" +``` + +### 2.环境变量添加 + +在config.sh中添加 + +```sh +export AutoMihoyoBBS_config_path="/ql/data/config/" +``` + +### 3.复制配置文件 + +**进入容器后运行以下命令**(docker exec -it ql bash)修改ql为你的青龙容器名字 + +```sh +cp /ql/data/repo/Womsxd_AutoMihoyoBBS/config/config.yaml.example /ql/data/config/config.yaml +``` + +### 4.添加依赖 + +在青龙面板依赖管理中添加httpx及PyYAML + +### 5.编辑配置文件 + +在配置文件内config.yaml中编辑信息 + +*注:通知配置为青龙config.sh中配置* + ## 使用的第三方库 requests: [github](https://github.com/psf/requests) [pypi](https://pypi.org/project/requests/) (当httpx无法使用时使用) diff --git a/captcha.py b/captcha.py new file mode 100644 index 0000000..3988c19 --- /dev/null +++ b/captcha.py @@ -0,0 +1,9 @@ +from request import http + + +def game_captcha(gt: str, challenge: str): + return None # 失败返回None 成功返回validate + + +def bbs_captcha(gt: str, challenge: str): + return None diff --git a/cloud_genshin.py b/cloud_genshin.py index 4e718ce..ce833af 100644 --- a/cloud_genshin.py +++ b/cloud_genshin.py @@ -25,9 +25,9 @@ class CloudGenshin: } # 分钟转小时 - def time_conversion(self,minute : int) -> str: - h = minute//60 - s = minute%60 + def time_conversion(self, minute: int) -> str: + h = minute // 60 + s = minute % 60 return f"{h}小时{s}分钟" def sign_account(self) -> str: @@ -42,7 +42,7 @@ class CloudGenshin: log.info('签到失败,未获得免费时长,可能是已经签到过了或者超出免费时长上线') ret_msg += '签到失败,未获得免费时长,可能是已经签到过了或者超出免费时长上线\n' ret_msg += f'你当前拥有免费时长 {self.time_conversion(int(data["data"]["free_time"]["free_time"]))} ,' \ - f'畅玩卡状态为 {data["data"]["play_card"]["short_msg"]},拥有米云币 {data["data"]["coin"]["coin_num"]} 枚' + f'畅玩卡状态为 {data["data"]["play_card"]["short_msg"]},拥有米云币 {data["data"]["coin"]["coin_num"]} 枚' log.info(ret_msg) elif data['retcode'] == -100: ret_msg = "云原神token失效/防沉迷" diff --git a/config.py b/config.py index 0174e11..8382d4a 100644 --- a/config.py +++ b/config.py @@ -42,6 +42,8 @@ config = { } } } +config_raw = {} +config_raw.update(config) path = os.path.dirname(os.path.realpath(__file__)) + "/config" if os.getenv("AutoMihoyoBBS_config_path") is not None: @@ -51,7 +53,7 @@ config_Path = f"{path}/config.yaml" def copy_config(): - return config + return config_raw def load_config_json(): diff --git a/config/push.ini.example b/config/push.ini.example index ffc8e7c..1cd7057 100644 --- a/config/push.ini.example +++ b/config/push.ini.example @@ -1,9 +1,9 @@ [setting] enable=true -#共有 cqhttp ftqq(sever酱) pushplus telegram wecom dingrobot bark pushdeer gotify smtp(邮件推送) -push_server=cqhttp -#server酱 pushplus dingrobot 的推送token -push_token=123456 +# 共有 cqhttp ftqq(sever酱) pushplus telegram wecom dingrobot feishubot bark pushdeer gotify smtp(邮件推送) +push_server=pushplus +# server酱 pushplus dingrobot 的推送token +push_token=XXXXXX [cqhttp] #cqhttp的服务端地址 @@ -32,6 +32,9 @@ token= webhook=https://oapi.dingtalk.com/robot/send?access_token=XXX secret= +[feishubot] +webhook=https://open.feishu.cn/open-apis/bot/v2/hook/XXX + [bark] api_url=https://api.day.app token=ssXXX diff --git a/genshin.py b/genshin.py index 65c0588..d0f7912 100644 --- a/genshin.py +++ b/genshin.py @@ -2,6 +2,7 @@ import time import tools import config import random +import captcha import setting from error import * from request import http @@ -46,10 +47,12 @@ class Genshin: return data["data"] def check_in(self, account): + header = {} + header.update(self.headers) for i in range(4): if i != 0: log.info(f'触发验证码,即将进行第{i}次重试,最多3次') - req = http.post(url=setting.genshin_Signurl, headers=self.headers, + req = http.post(url=setting.genshin_Signurl, headers=header, json={'act_id': setting.genshin_Act_id, 'region': account[2], 'uid': account[1]}) if req.status_code == 429: time.sleep(10) # 429同ip请求次数过多,尝试sleep10s进行解决 @@ -57,6 +60,11 @@ class Genshin: continue data = req.json() if data["retcode"] == 0 and data["data"]["success"] == 1: + validate = captcha.game_captcha(data["data"]["gt"], data["data"]["challenge"]) + if validate is not None: + header["x-rpc-challenge"] = data["data"]["challenge"] + header["x-rpc-validate"] = validate + header["x-rpc-seccode"] = f'{validate}|jordan' time.sleep(random.randint(6, 15)) else: break diff --git a/login.py b/login.py index fb1e2f5..d5bba3f 100644 --- a/login.py +++ b/login.py @@ -18,10 +18,10 @@ def login(): config.config["account"]["login_ticket"] = i.split("=")[1] break # 这里获取Stuid,但是实际是可以直接拿cookie里面的Uid - data = http.get(url=setting.bbs_Cookie_url.format(config.config["account"]["login_ticket"])).json() + data = http.get(url=setting.bbs_cookie_url.format(config.config["account"]["login_ticket"])).json() if "成功" in data["data"]["msg"]: config.config["account"]["stuid"] = str(data["data"]["cookie_info"]["account_id"]) - data = http.get(url=setting.bbs_Cookie_url2.format( + data = http.get(url=setting.bbs_cookie_url2.format( config.config["account"]["login_ticket"], config.config["account"]["stuid"])).json() config.config["account"]["stoken"] = data["data"]["list"][0]["token"] log.info("登录成功!") diff --git a/mihoyobbs.py b/mihoyobbs.py index ba7797e..6630fc7 100644 --- a/mihoyobbs.py +++ b/mihoyobbs.py @@ -3,6 +3,7 @@ import time import tools import config import random +import captcha import setting from request import http from loghelper import log @@ -47,13 +48,29 @@ class Mihoyobbs: def refresh_list(self) -> None: self.postsList = self.get_list() + def get_pass_challenge(self): + req = http.get(url=setting.bbs_get_captcha, headers=self.headers) + data = req.json() + if data["retcode"] != 0: + return None + validate = captcha.bbs_captcha(data["data"]["gt"], data["data"]["challenge"]) + if validate is not None: + check_req = http.post(url=setting.bbs_captcha_verify, headers=self.headers, + json={"geetest_challenge": data["data"]["challenge"], + "geetest_seccode": validate+"|jordan", + "geetest_validate": validate}) + check = check_req.json() + if check["retcode"] == 0: + return check["data"]["challenge"] + return None + # 获取任务列表,用来判断做了哪些任务 def get_tasks_list(self): global today_get_coins global today_have_get_coins global Have_coins log.info("正在获取任务列表") - req = http.get(url=setting.bbs_Tasks_list, headers=self.headers) + req = http.get(url=setting.bbs_tasks_list, headers=self.headers) data = req.json() if "err" in data["message"] or data["retcode"] == -100: log.error("获取任务列表失败,你的cookie可能已过期,请重新设置cookie。") @@ -104,7 +121,7 @@ class Mihoyobbs: def get_list(self) -> list: temp_list = [] log.info("正在获取帖子列表......") - req = http.get(url=setting.bbs_List_url.format(setting.mihoyobbs_List_Use[0]["forumId"]), + req = http.get(url=setting.bbs_post_list_url.format(setting.mihoyobbs_List_Use[0]["forumId"]), headers=self.headers) data = req.json()["data"]["list"] for n in range(5): @@ -125,17 +142,32 @@ class Mihoyobbs: log.info("正在签到......") header = {} header.update(self.headers) + challenge = None for i in setting.mihoyobbs_List_Use: - header["DS"] = tools.get_ds2("", json.dumps({"gids": i["id"]})) - req = http.post(url=setting.bbs_Sign_url, json={"gids": i["id"]}, headers=header) - data = req.json() - if "err" not in data["message"]: - log.info(str(i["name"] + data["message"])) - time.sleep(random.randint(2, 8)) - else: - log.error("签到失败,你的cookie可能已过期,请重新设置cookie。") - config.clear_cookies() - raise CookieError('Cookie expires') + challenge = None + check_pass = False + for i2 in range(2): + if check_pass: + continue + header["DS"] = tools.get_ds2("", json.dumps({"gids": i["id"]})) + req = http.post(url=setting.bbs_sign_url, json={"gids": i["id"]}, headers=header) + data = req.json() + if data["retcode"] == 1034: + log.warning("社区签到触发验证码") + challenge = self.get_pass_challenge() + if challenge is not None: + header["x-rpc-challenge"] = challenge + elif "err" not in data["message"] and data["retcode"] == 0: + log.info(str(i["name"] + data["message"])) + check_pass = True + if challenge is not None: + challenge = None + header.pop("x-rpc-challenge") + time.sleep(random.randint(2, 8)) + else: + log.error("签到失败,你的cookie可能已过期,请重新设置cookie。") + config.clear_cookies() + raise CookieError('Cookie expires') # 看帖子 def read_posts(self): @@ -144,7 +176,7 @@ class Mihoyobbs: else: log.info("正在看帖......") for i in range(self.Task_do["bbs_Read_posts_num"]): - req = http.get(url=setting.bbs_Detail_url.format(self.postsList[i][0]), headers=self.headers) + req = http.get(url=setting.bbs_detail_url.format(self.postsList[i][0]), headers=self.headers) data = req.json() if data["message"] == "OK": log.debug("看帖:{} 成功".format(self.postsList[i][1])) @@ -152,20 +184,31 @@ class Mihoyobbs: # 点赞 def like_posts(self): + header = {} + header.update(self.headers) + challenge = None if self.Task_do["bbs_Like_posts"]: log.info("点赞任务已经完成过了~") else: log.info("正在点赞......") for i in range(self.Task_do["bbs_Like_posts_num"]): - req = http.post(url=setting.bbs_Like_url, headers=self.headers, + req = http.post(url=setting.bbs_like_url, headers=header, json={"post_id": self.postsList[i][0], "is_cancel": False}) data = req.json() if data["message"] == "OK": log.debug("点赞:{} 成功".format(self.postsList[i][1])) - # 判断取消点赞是否打开 + if challenge is not None: + challenge = None + header.pop("x-rpc-challenge") + elif data["retcode"] == 1034: + log.warning("点赞触发验证码") + challenge = self.get_pass_challenge() + if challenge is not None: + header["x-rpc-challenge"] = challenge + # 判断取消点赞是否打开 if config.config["mihoyobbs"]["cancel_like_posts"]: time.sleep(random.randint(2, 8)) - req = http.post(url=setting.bbs_Like_url, headers=self.headers, + req = http.post(url=setting.bbs_like_url, headers=self.headers, json={"post_id": self.postsList[i][0], "is_cancel": True}) data = req.json() if data["message"] == "OK": @@ -180,7 +223,7 @@ class Mihoyobbs: else: log.info("正在执行分享任务......") for i in range(3): - req = http.get(url=setting.bbs_Share_url.format(self.postsList[0][0]), headers=self.headers) + req = http.get(url=setting.bbs_share_url.format(self.postsList[0][0]), headers=self.headers) data = req.json() if data["message"] == "OK": log.debug("分享:{} 成功".format(self.postsList[0][1])) diff --git a/push.py b/push.py index 93a5449..fcf2294 100644 --- a/push.py +++ b/push.py @@ -170,6 +170,17 @@ def dingrobot(send_title, push_message): ).json() log.info(f"推送结果:{rep.get('errmsg')}") +# 飞书机器人 +def feishubot(send_title, push_message): + api_url = cfg.get('feishubot', 'webhook') # https://open.feishu.cn/open-apis/bot/v2/hook/XXX + rep = http.post( + url=api_url, + headers={"Content-Type": "application/json; charset=utf-8"}, + json={ + "msg_type": "text", "content": {"text": send_title + "\r\n" + push_message} + } + ).json() + log.info(f"推送结果:{rep.get('msg')}") # Bark def bark(send_title, push_message): diff --git a/ql_main.py b/ql_main.py new file mode 100644 index 0000000..e293d1b --- /dev/null +++ b/ql_main.py @@ -0,0 +1,17 @@ +""" +new Env('米游社'); +""" +import notify +from loghelper import log +from error import CookieError +from main import main + +if __name__ == "__main__": + try: + status_code, message = main() + except CookieError: + status_code = 1 + message = "账号Cookie出错!" + log.error("账号Cookie有问题!") + notify.send("米游社", message) + diff --git a/setting.py b/setting.py index 163a18d..8009796 100644 --- a/setting.py +++ b/setting.py @@ -76,43 +76,45 @@ headers = { } # 通用设置 -bbs_Api = "https://bbs-api.mihoyo.com" -web_Api = "https://api-takumi.mihoyo.com" -account_Info_url = web_Api + "/binding/api/getUserGameRolesByCookie?game_biz=" +bbs_api = "https://bbs-api.mihoyo.com" +web_api = "https://api-takumi.mihoyo.com" +account_Info_url = web_api + "/binding/api/getUserGameRolesByCookie?game_biz=" # 米游社的API列表 -bbs_Cookie_url = "https://webapi.account.mihoyo.com/Api/cookie_accountinfo_by_loginticket?login_ticket={}" -bbs_Cookie_url2 = web_Api + "/auth/api/getMultiTokenByLoginTicket?login_ticket={}&token_types=3&uid={}" -bbs_Tasks_list = bbs_Api + "/apihub/sapi/getUserMissionsState" # 获取任务列表 -bbs_Sign_url = bbs_Api + "/apihub/app/api/signIn" # post -bbs_List_url = bbs_Api + "/post/api/getForumPostList?forum_id={}&is_good=false&is_hot=false&page_size=20&sort_type=1" -bbs_Detail_url = bbs_Api + "/post/api/getPostFull?post_id={}" -bbs_Share_url = bbs_Api + "/apihub/api/getShareConf?entity_id={}&entity_type=1" -bbs_Like_url = bbs_Api + "/apihub/sapi/upvotePost" # post json +bbs_cookie_url = "https://webapi.account.mihoyo.com/Api/cookie_accountinfo_by_loginticket?login_ticket={}" +bbs_cookie_url2 = web_api + "/auth/api/getMultiTokenByLoginTicket?login_ticket={}&token_types=3&uid={}" +bbs_tasks_list = bbs_api + "/apihub/sapi/getUserMissionsState" # 获取任务列表 +bbs_sign_url = bbs_api + "/apihub/app/api/signIn" # post +bbs_post_list_url = bbs_api + "/post/api/getForumPostList?forum_id={}&is_good=false&is_hot=false&page_size=20&sort_type=1" +bbs_detail_url = bbs_api + "/post/api/getPostFull?post_id={}" +bbs_share_url = bbs_api + "/apihub/api/getShareConf?entity_id={}&entity_type=1" +bbs_like_url = bbs_api + "/apihub/sapi/upvotePost" # post json +bbs_get_captcha = bbs_api + "/misc/api/createVerification?is_high=true" +bbs_captcha_verify = bbs_api + "/misc/api/verifyVerification" # 崩坏2自动签到相关的相关设置 honkai2_Act_id = "e202203291431091" -honkai2_checkin_rewards = f'{web_Api}/event/luna/home?lang=zh-cn&act_id={honkai2_Act_id}' -honkai2_Is_signurl = web_Api + "/event/luna/info?lang=zh-cn&act_id={}®ion={}&uid={}" -honkai2_Sign_url = web_Api + "/event/luna/sign" +honkai2_checkin_rewards = f'{web_api}/event/luna/home?lang=zh-cn&act_id={honkai2_Act_id}' +honkai2_Is_signurl = web_api + "/event/luna/info?lang=zh-cn&act_id={}®ion={}&uid={}" +honkai2_Sign_url = web_api + "/event/luna/sign" # 崩坏3自动签到相关的设置 honkai3rd_Act_id = "e202207181446311" -honkai3rd_checkin_rewards = f'{web_Api}/event/luna/home?lang=zh-cn&act_id={honkai3rd_Act_id}' -honkai3rd_Is_signurl = web_Api + "/event/luna/info?lang=zh-cn&act_id={}®ion={}&uid={}" -honkai3rd_Sign_url = web_Api + "/event/luna/sign" +honkai3rd_checkin_rewards = f'{web_api}/event/luna/home?lang=zh-cn&act_id={honkai3rd_Act_id}' +honkai3rd_Is_signurl = web_api + "/event/luna/info?lang=zh-cn&act_id={}®ion={}&uid={}" +honkai3rd_Sign_url = web_api + "/event/luna/sign" # 未定事件簿自动签到相关设置 tearsofthemis_Act_id = "e202202251749321" -tearsofthemis_checkin_rewards = f'{web_Api}/event/luna/home?lang=zh-cn&act_id={tearsofthemis_Act_id}' +tearsofthemis_checkin_rewards = f'{web_api}/event/luna/home?lang=zh-cn&act_id={tearsofthemis_Act_id}' tearsofthemis_Is_signurl = honkai2_Is_signurl tearsofthemis_Sign_url = honkai2_Sign_url # 和二崩完全一致 # 原神自动签到相关的设置 genshin_Act_id = "e202009291139501" -genshin_checkin_rewards = f'{web_Api}/event/bbs_sign_reward/home?act_id={genshin_Act_id}' -genshin_Is_signurl = web_Api + "/event/bbs_sign_reward/info?act_id={}®ion={}&uid={}" -genshin_Signurl = web_Api + "/event/bbs_sign_reward/sign" +genshin_checkin_rewards = f'{web_api}/event/bbs_sign_reward/home?act_id={genshin_Act_id}' +genshin_Is_signurl = web_api + "/event/bbs_sign_reward/info?act_id={}®ion={}&uid={}" +genshin_Signurl = web_api + "/event/bbs_sign_reward/sign" # 云原神相关api cloud_genshin_Api = "https://api-cloudgame.mihoyo.com"