diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index d411ece..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: "Genshin Impact Helper" - -on: - schedule: - - cron: "0 22 * * *" # scheduled at 06:00 (UTC+8) everyday - workflow_dispatch: - -jobs: - build: - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/master' - - steps: - - name: Checkout master - uses: actions/checkout@v2 - with: - ref: master - - - name: Set up python - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - - name: Run sign - run: | - pip install -r requirements.txt - echo "${{ secrets.COOKIE }}" | tr '#' "\n" | xargs -I {} sh -c 'echo "{}" | python3 ./genshin.py' diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml deleted file mode 100644 index 5d7a114..0000000 --- a/.github/workflows/sync.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: "Auto Sync Fork" - -on: - schedule: - - cron: "0 16 * * *" # scheduled at 00:00 (UTC+8) everyday - workflow_dispatch: - -jobs: - sync: - runs-on: ubuntu-latest - if: github.ref == 'refs/heads/master' - - steps: - - name: Fork sync - uses: tgymnich/fork-sync@v1.2 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - owner: y1ndan - base: master - head: master diff --git a/README.md b/README.md index 6c5e88b..7363850 100644 --- a/README.md +++ b/README.md @@ -1,159 +1 @@ -
-

-Genshin Impact Helper -

- -![Genshin Impact Helper](https://i.loli.net/2020/11/18/3zogEraBFtOm5nI.jpg) -[![GitHub stars](https://img.shields.io/github/stars/y1ndan/genshin-impact-helper?style=flat-square)](https://github.com/y1ndan/genshin-impact-helper/stargazers) -[![GitHub forks](https://img.shields.io/github/forks/y1ndan/genshin-impact-helper?style=flat-square)](https://github.com/y1ndan/genshin-impact-helper/network) -[![GitHub issues](https://img.shields.io/github/issues/y1ndan/genshin-impact-helper?style=flat-square)](https://github.com/y1ndan/genshin-impact-helper/issues) -[![GitHub contributors](https://img.shields.io/github/contributors/y1ndan/genshin-impact-helper?style=flat-square)](https://github.com/y1ndan/genshin-impact-helper/graphs/contributors) -[![QQ Group](https://img.shields.io/badge/chat-130516740-0d86d7?style=flat-square)](https://qm.qq.com/cgi-bin/qm/qr?k=_M9lYFxkYD7yQQR2btyG3pkZWFys_I-l&authKey=evGDzE2eFVBm46jsHpgcWrokveg70Z9GKl3H45o0oJuia620UGeO27lDPG9gKb/2&noverify=0) -![Github workflow status](https://img.shields.io/github/workflow/status/y1ndan/genshin-impact-helper/Genshin%20Impact%20Helper?label=status&style=flat-square) - -
- -## 💭前言 - -> 吹水交流:[130516740](https://qm.qq.com/cgi-bin/qm/qr?k=_M9lYFxkYD7yQQR2btyG3pkZWFys_I-l&authKey=evGDzE2eFVBm46jsHpgcWrokveg70Z9GKl3H45o0oJuia620UGeO27lDPG9gKb/2&noverify=0) - -原神是我见过的唯一一个游戏本体和签到福利分离的游戏,玩家为了签到还要额外下载米游社 App。 - -平心而论,目前的每日签到奖励真的不咋地,都知道是蚊子腿。事实上,你完全可以选择无视签到,不签也没啥大的损失;或者选择手动签到,但这样的话哪天忘记打卡了就很头疼。 - -我承认是馋了这 **6W+** 摩拉和紫色经验书的奖励,于是撸了这个项目,实现自动每日签到。 - -**如果觉得本项目对你有帮助,请顺手点个`Star`吧QAQ ♥** - -## 🌀简介 - -Genshin Impact Helper 可以自动化为你获取原神每日福利。 - -## 💡特性 - -- [x] **自动签到** 程序会在每天早上自动执行签到流程,也可以随时通过部署教程的`步骤4`手动触发,具体时间参照[此处](.github/workflows/main.yml) -- [x] **自动同步** 自动从上游源仓库拉取代码至复刻仓库 -- [x] **支持多服务器** 支持绑定单个官服或 Bilibili 服的米游社账号,目前不支持同时绑定多个服务器的账号 -- [x] **支持多账号** 不同`Cookie`值之间用`#`分开即可,如:`#` - -## 📐部署 - -
-查看教程 - -### 1. Fork 仓库 - -- 项目地址:[github/genshin-impact-helper](https://github.com/y1ndan/genshin-impact-helper) -- 点击右上角`Fork`到自己的账号下 - -> ![fork](https://i.loli.net/2020/10/28/qpXowZmIWeEUyrJ.png) - -### 2. 获取 Cookie - -浏览器打开 https://bbs.mihoyo.com/ys/ 并登录账号 - -#### 2.1 方法一 - -- 按`F12`,打开`开发者工具`,找到`Network`并点击 -- 按`F5`刷新页面,按下图复制`Cookie` - -> ![cookie](https://i.loli.net/2020/10/28/TMKC6lsnk4w5A8i.png) - -#### 2.2 方法二 - -- 复制以下代码 - -``` -var cookie = document.cookie; -var ask = confirm('Cookie:' + cookie + '\n\n是否复制内容到剪切板?'); -if (ask == true) { - copy(cookie); - msg = cookie; -} else { - msg = 'Cancel'; -} -``` - -- 按`F12`,打开`开发者工具`,找到`Console`并点击 -- 命令行粘贴代码并运行,获得类似`Cookie:xxxxxx`的输出信息 -- `xxxxxx`部分即为所需复制的`Cookie`,点击确定复制 - -### 3. 添加 Cookie 至 Secrets - -- 回到项目页面,依次点击`Settings`-->`Secrets`-->`New secret` - -> ![new-secret.png](https://i.loli.net/2020/10/28/sxTuBFtRvzSgUaA.png) - -- 建立名为`COOKIE`的 secret,值为`步骤2`中复制的`Cookie`内容,最后点击`Add secret` - -> ![add-secret](https://i.loli.net/2020/10/28/sETkVdmrNcCUpgq.png) - -### 4. 启用 Actions - -> Actions 默认为关闭状态,Fork 之后需要手动执行一次,若成功运行其才会激活。 - -返回项目主页面,点击上方的`Actions`,再点击左侧的`Genshin Impact Helper`,再点击`Run workflow` - -> ![run](https://i.loli.net/2020/10/28/5ylvgdYf9BDMqAH.png) - -
- -至此,部署完毕。 - -## 🔍结果 - -当你完成上述流程,可以在`Actions`页面点击`Genshin Impact Helper`-->`build`-->`Run sign`查看结果。 - -
-查看结果 - -### 签到成功 - -如果成功,会输出类似`"result": "Success"`的信息: - -``` -2020-11-18T22:11:45 INFO Sleep for 100 seconds ... -2020-11-18T22:13:26 INFO UID is 100***000 -2020-11-18T22:13:27 INFO { - "result": "Success", - "message": "{\"retcode\": 0, \"message\": \"OK\", \"data\": {\"code\": \"ok\"}}" -} -``` - -### 签到失败 - -如果失败,会输出类似`"result": "Failed"`的信息: - -``` -2020-11-17T22:11:33 INFO Sleep for 54 seconds ... -2020-11-17T22:12:28 INFO UID is 100***000 -2020-11-17T22:12:29 INFO { - "result": "Failed", - "message": "{\"data\": null, \"message\": \"请求异常\", \"retcode\": -401}" -} -Error: Process completed with exit code 255. -``` - -同时你会收到一封来自GitHub、标题为`Run failed: Genshin Impact Helper - master`的邮件。 - -
- -## 🔄更新 - -因为接口请求上可能发生一些变化,所以上游源代码需要作出更改来适配这些变化,如果你没有及时更新项目源代码,可能会导致签到失败。 - -为解决此问题,项目开启了自动同步上游源代码的工作流程。该功能生效于 2020 年 12 月 04 日之后复刻的项目。 - -若在此时间之前复刻,可按照以下步骤更新: - -- 下载[sync.yml](https://raw.githubusercontent.com/y1ndan/genshin-impact-helper/master/.github/workflows/sync.yml)文件 -- 自行上传`sync.yml`文件至**你的 Fork 仓库**的`.github/workflows`目录下 -- 到`Actions`页面手动触发一次名为`Auto Sync Fork`的工作流程 - -## ❗️协议 - -使用 Genshin Impact Helper 即表明,您知情并同意: - -- 此代码通过模拟浏览器使用 Cookies 登录米游社网页,点击页面完成签到来实现签到。功能通过官方公开的 API 实现,并非游戏外挂 -- 用户之 Cookie 被储存于 Github 服务器,只供本项目使用。若 Github 服务器被攻破,则您的 Cookie 有遭到泄露的风险。除此之外,开发者无权获取您的 Cookie;即使是用户,一旦创建完成`Secrets`,也无法再次从中查看 Cookie -- Genshin Impact Helper 不会对您的任何损失负责,包括但不限于奖励回收、账号异常、刻晴被削、矿产被挖、核弹爆炸、第三次世界大战等 +# See you later \ No newline at end of file diff --git a/genshin.py b/genshin.py deleted file mode 100755 index d57d605..0000000 --- a/genshin.py +++ /dev/null @@ -1,251 +0,0 @@ -#!/usr/bin/env python3 - -import requests -import json -import uuid -import logging -import time -import random -import hashlib -import string -from requests.exceptions import * - -logging.basicConfig( - level = logging.INFO, - format = '%(asctime)s %(levelname)s %(message)s', - datefmt = '%Y-%m-%dT%H:%M:%S') - - -class ConfMeta(type): - @property - def index_url(self): - return 'https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html' - - @property - def app_version(self): - return '2.1.0' - - @property - def ua(self): - return 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) ' \ - 'AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/%s' \ - %(self.app_version) - - -class Conf(metaclass=ConfMeta): - pass - - -class Roles(object): - def __init__(self, cookie:str=None): - if type(cookie) is not str: - raise TypeError("%s want a %s but got %s" %( - self.__class__, type(__name__), type(cookie))) - - self._cookie = cookie - self._url = "https://api-takumi.mihoyo.com/binding/api/" \ - "getUserGameRolesByCookie?game_biz=%s" %('hk4e_cn') - - def get_header(self): - actid = 'e202009291139501' - ref = "%s?bbs_auth_required=%s&act_id=%s&utm_source=%s" \ - "&utm_medium=%s&utm_campaign=%s" %( - Conf.index_url, 'true', actid, 'bbs', 'mys', 'icon') - - return { - 'User-Agent': Conf.ua, - 'Referer': ref, - 'Accept-Encoding': 'gzip, deflate, br', - 'Cookie': self._cookie - } - - def get_roles(self): - try: - jdict = json.loads( - requests.Session().get( - self._url, headers = self.get_header()).text) - except Exception as e: - logging.error(e) - raise HTTPError - - return jdict - - def get_rolesInfo(self): - logging.info('Start getting user information ...') - errstr = None - - for i in range(1, 4): - try: - self._rolesInfo = self.get_roles() - except HTTPError as e: - logging.error("HTTP error when get user game roles, " \ - "retry %s time(s) ..." %(i)) - logging.error("error is %s" %(e)) - errstr = str(e) - continue - except KeyError as e: - logging.error("Wrong response to get user game roles, " \ - "retry %s time(s) ..." %(i)) - logging.error("response is %s" %(e)) - errstr = str(e) - continue - except Exception as e: - logging.error("Unknown error %s, die" %(e)) - errstr = str(e) - raise - else: - break - - try: - self._rolesInfo - except AttributeError: - raise Exception(errstr) - - return self._rolesInfo - - -class Sign(object): - def __init__(self, cookie:str=None): - if type(cookie) is not str: - raise TypeError("%s want a %s but got %s" %( - self.__class__, type(__name__), type(cookie))) - - self._cookie = cookie - self._url = 'https://api-takumi.mihoyo.com/event/bbs_sign_reward/sign' - - # Provided by Steesha - def md5(self, text): - md5 = hashlib.md5() - md5.update(text.encode()) - return (md5.hexdigest()) - - def get_DS(self): - n = self.md5(Conf.app_version) - i = str(int(time.time())) - r = ''.join(random.sample(string.ascii_lowercase + string.digits, 6)) - c = self.md5("salt=" + n + "&t="+ i + "&r=" + r) - return i + "," + r + "," + c - - def get_header(self): - actid = 'e202009291139501' - ref = "%s?bbs_auth_required=%s&act_id=%s&utm_source=%s" \ - "&utm_medium=%s&utm_campaign=%s" %( - Conf.index_url, 'true', actid, 'bbs', 'mys', 'icon') - - return { - 'x-rpc-device_id': str(uuid.uuid3( - uuid.NAMESPACE_URL, self._cookie)).replace('-','').upper(), - # 1: ios - # 2: android - # 4: pc web - # 5: mobile web - 'x-rpc-client_type': '5', - 'Accept-Encoding': 'gzip, deflate, br', - 'User-Agent': Conf.ua, - 'Referer': ref, - 'x-rpc-app_version': Conf.app_version, - 'DS': self.get_DS(), - 'Cookie': self._cookie - } - - def run(self): - # cn_gf01: 天空岛 - # cn_qd01: 世界树 - self._region = rolesList[i]['region'] - self._region_name = rolesList[i]['region_name'] - self._uid = rolesList[i]['game_uid'] - - data = { - 'act_id': 'e202009291139501', - 'region': self._region, - 'uid': self._uid - } - - logging.info('Start signing in the NO.%s role which UID is %s in %s ...' %( - i+1, str(self._uid).replace(str(self._uid)[3:6],'***',1), self._region_name)) - try: - jdict = json.loads(requests.Session().post( - self._url, headers = self.get_header(), - data = json.dumps(data, ensure_ascii=False)).text) - except Exception as e: - raise - - return jdict - - -def makeResult(result:str, data=None): - return json.dumps( - { - 'result': result, - 'message': data - }, - sort_keys=False, indent=2, ensure_ascii=False - ) - -def notify(key, massage): - if key != '': - logging.info('正在推送通知...') - url = 'https://sc.ftqq.com/%s.send' %(key) - data = {'text':'原神签到小助手', 'desp':massage} - try: - jdict = json.loads( - requests.Session().post(url, data = data).text) - errmsg = jdict['errmsg'] - if errmsg == 'success': - logging.info('推送通知成功') - else: - logging.info('推送通知失败') - logging.error(jdict) - except Exception as e: - logging.error(e) - raise HTTPError - - return jdict - else: - logging.info('未配置SCKEY,正在跳过推送...') - - -if __name__ == "__main__": - secret = input().strip().rsplit(' ', 1) - secret.append('') - cookie=secret[0] - sckey=secret[1] - jstr = Roles(cookie).get_rolesInfo() - result = makeResult('Failed', jstr) - ret = -1 - - try: - rolesList = jstr['data']['list'] - logging.info('Your account has been bound %s role(s)' %(len(rolesList))) - - for i in range(len(rolesList)): - seconds = random.randint(10, 300) - logging.info('Sleep for %s seconds ...' %(seconds)) - time.sleep(seconds) - - try: - jdict = Sign(cookie).run() - jstr = json.dumps(jdict, ensure_ascii=False) - code = jdict['retcode'] - except Exception as e: - jstr = str(e) - - try: - code - except NameError: - code = -1 - - # 0: success - # -5003: already signed in - if code in [0, -5003]: - result = makeResult('Success', jstr) - ret = 0 - - logging.info(result) - - except Exception as e: - logging.info(result) - - notify(sckey, result) - logging.info('签到完成!') - exit(ret) diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index c20f36f..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -requests==2.20.0