commit
2e4039952f
@ -8,19 +8,16 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.7
|
||||
- run: |
|
||||
python-version: 3.8
|
||||
|
||||
- name: run sign
|
||||
run: |
|
||||
pip install -r requirements.txt
|
||||
string="${{ secrets.COOKIE }}"
|
||||
IFS="#"
|
||||
array=($string)
|
||||
for var in ${array[@]}
|
||||
do
|
||||
python3 genshin.py <<EOF
|
||||
$var
|
||||
EOF
|
||||
done
|
||||
echo "${{ secrets.COOKIE }}" | tr '#' "\n" | xargs -I {} sh -c 'echo "{}" | python3 ./genshin.py'
|
||||
|
||||
51
README.md
51
README.md
@ -13,40 +13,65 @@
|
||||
## 部署
|
||||
|
||||
### 1. Fork 仓库
|
||||
* 项目地址:[github/genshin-impact-helper](https://github.com/y1ndan/genshin-impact-helper)
|
||||
* 点击右上角**Fork**到自己的账号下
|
||||
|
||||

|
||||
* 项目地址:[github/genshin-impact-helper](https://github.com/y1ndan/genshin-impact-helper)
|
||||
* 点击右上角`Fork`到自己的账号下
|
||||
|
||||
> 
|
||||
|
||||
### 2. 获取 Cookie
|
||||
* 浏览器打开 https://bbs.mihoyo.com/ys/ 并登录账号
|
||||
* 按**F12**,打开**开发者工具**,找到**Network**并点击
|
||||
* 按**F5**刷新页面,按下图复制**Cookie**
|
||||
|
||||

|
||||
* 浏览器打开 https://bbs.mihoyo.com/ys/ 并登录账号
|
||||
* 按`F12`,打开`开发者工具`,找到`Network`并点击
|
||||
* 按`F5`刷新页面,按下图复制`Cookie`
|
||||
|
||||
> 
|
||||
|
||||
### 3. 添加 Cookie 至 Secrets
|
||||
* 回到项目页面,依次点击 Settings --> Secrets --> New secret
|
||||
|
||||

|
||||
* 回到项目页面,依次点击`Settings`-->`Secrets`-->`New secret`
|
||||
|
||||
* 建立名为`COOKIE`的 secret,值为**步骤2**中复制的**Cookie**内容,最后点击**Add secret**
|
||||
> 
|
||||
|
||||

|
||||
* 建立名为`COOKIE`的 secret,值为`步骤2`中复制的`Cookie`内容,最后点击`Add secret`
|
||||
|
||||
> 
|
||||
|
||||
### 4. 启用 Action
|
||||
|
||||
> Actions 默认处于关闭状态,首次需要手动执行一次,验证是否可以正常工作。
|
||||
|
||||
点击 **Actions**,再点击左侧的**Genshin Impact Helper**,再点击**Run workflow**
|
||||
返回项目主页面,点击上方的`Actions`,再点击左侧的`Genshin Impact Helper`,再点击`Run workflow`
|
||||
|
||||

|
||||
|
||||
至此,部署完毕。
|
||||
|
||||
首先会运行一遍,如果成功,会输出类似以下结果`"result": "Success"`。
|
||||
|
||||
```
|
||||
2020-10-30T11:30:08 INFO sleep for 214 seconds ...
|
||||
2020-10-30T11:30:08 INFO UID is 102445054
|
||||
2020-10-30T11:30:09 INFO {
|
||||
"result": "Success",
|
||||
"message": "{'data': None, 'message': '旅行者,你已经签到过了', 'retcode': -5003}"
|
||||
}
|
||||
```
|
||||
|
||||
如果失败,会输出类似以下结果`"result": "Failed"`。
|
||||
|
||||
```
|
||||
2020-10-30T11:14:26 INFO sleep for 207 seconds ...
|
||||
2020-10-30T11:14:26 ERROR get uid failed, request is "{'data': None, 'message': '登录失效,请重新登录', 'retcode': -100}"
|
||||
2020-10-30T11:14:26 INFO {
|
||||
"result": "Failed",
|
||||
"message": ""{'data': None, 'message': '登录失效,请重新登录', 'retcode': -100}""
|
||||
}
|
||||
```
|
||||
|
||||
## 说明
|
||||
|
||||
1. 程序会在每天早上 6 点自动执行签到,也可以通过上述**步骤4**手动触发执行
|
||||
1. 程序会在每天早上 6 点自动执行签到(可能会延迟五分钟),也可以通过上述**步骤4**手动触发执行
|
||||
2. 登录失效时,尝试重新更换 `Cookie`
|
||||
3. 支持多账号,不同 `Cookie` 之间用 `#` 分开即可
|
||||
|
||||
|
||||
189
genshin.py
Normal file → Executable file
189
genshin.py
Normal file → Executable file
@ -1,52 +1,159 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import requests
|
||||
import json
|
||||
import uuid
|
||||
import logging
|
||||
from time import sleep
|
||||
from random import randint
|
||||
from requests.exceptions import *
|
||||
|
||||
s = requests.Session()
|
||||
logging.basicConfig(
|
||||
level = logging.INFO,
|
||||
format = '%(asctime)s %(levelname)s %(message)s',
|
||||
datefmt = '%Y-%m-%dT%H:%M:%S')
|
||||
|
||||
cookie = ""
|
||||
if (cookie == ""):
|
||||
cookie = input().strip()
|
||||
|
||||
def main():
|
||||
url1 = f'https://api-takumi.mihoyo.com/binding/api/getUserGameRolesByCookie?game_biz=hk4e_cn'
|
||||
url2 = f'https://api-takumi.mihoyo.com/event/bbs_sign_reward/sign'
|
||||
device_id = str(uuid.uuid3(uuid.NAMESPACE_URL,cookie)).replace('-','').upper()
|
||||
headers1 = {
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.1.0',
|
||||
'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',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
'Cookie': cookie
|
||||
}
|
||||
headers2 = {
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.1.0',
|
||||
'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',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
'cookie': cookie,
|
||||
'x-rpc-device_id': device_id
|
||||
}
|
||||
r1 = s.get(url1, headers = headers1)
|
||||
d1 = json.loads(r1.text)
|
||||
uid = d1['data']['list'][0]['game_uid']
|
||||
data = {
|
||||
'act_id': 'e202009291139501',
|
||||
'region': 'cn_gf01',
|
||||
'uid': uid
|
||||
}
|
||||
r2 = s.post(url2, headers = headers2, data = json.dumps(data))
|
||||
d2 = json.loads(r2.text)
|
||||
if d2['retcode'] == 0:
|
||||
print("======\n签到成功!\n======")
|
||||
else :
|
||||
if d2['retcode'] == -5003:
|
||||
print("======\n" + d2['message'] + "\n======")
|
||||
else :
|
||||
print("======\n签到失败!\n详细信息:" + d2['message'] + "\n======")
|
||||
exit(100)
|
||||
class ConfMeta(type):
|
||||
@property
|
||||
def index_url(cls):
|
||||
return 'https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html'
|
||||
|
||||
@property
|
||||
def ua(cls):
|
||||
return 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) ' \
|
||||
'AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.1.0'
|
||||
|
||||
|
||||
class Conf(metaclass = ConfMeta):
|
||||
pass
|
||||
|
||||
|
||||
class UID(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_uid(self):
|
||||
# XXX Loop this code for try N times ?
|
||||
try:
|
||||
jdict = json.loads(
|
||||
requests.Session().get(
|
||||
self._url, headers = self.get_header()).text)
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
raise HTTPError
|
||||
|
||||
try:
|
||||
return jdict['data']['list'][0]['game_uid']
|
||||
except:
|
||||
raise KeyError(str(jdict))
|
||||
|
||||
|
||||
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._url = 'https://api-takumi.mihoyo.com/event/bbs_sign_reward/sign'
|
||||
|
||||
try:
|
||||
self._uid = UID(cookie).get_uid()
|
||||
except KeyError as e:
|
||||
logging.error("get uid failed, request is %s" %(e))
|
||||
raise
|
||||
except Exception as e:
|
||||
logging.error("Unknown error %s" %(e))
|
||||
raise
|
||||
|
||||
self._cookie = cookie
|
||||
|
||||
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,
|
||||
'x-rpc-device_id': str(uuid.uuid3(
|
||||
uuid.NAMESPACE_URL, self._cookie)).replace('-','').upper()
|
||||
}
|
||||
|
||||
def run(self):
|
||||
logging.info('UID is %s' %(self._uid))
|
||||
|
||||
data = {
|
||||
'act_id': 'e202009291139501',
|
||||
'region': 'cn_gf01',
|
||||
'uid': self._uid
|
||||
}
|
||||
|
||||
try:
|
||||
jdict = json.loads(requests.Session().post(
|
||||
self._url, headers = self.get_header(),
|
||||
data = json.dumps(data)).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
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sleep(randint(10,300))
|
||||
main()
|
||||
seconds = randint(10, 300)
|
||||
logging.info('sleep for %s seconds ...' %(seconds))
|
||||
|
||||
sleep(seconds)
|
||||
|
||||
try:
|
||||
jdict = Sign(input().strip()).run()
|
||||
jstr = str(jdict)
|
||||
code = jdict['retcode']
|
||||
except Exception as e:
|
||||
jstr = str(e)
|
||||
|
||||
result = makeResult('Failed', jstr)
|
||||
|
||||
try:
|
||||
code
|
||||
except NameError:
|
||||
code = -1
|
||||
|
||||
# 0: success
|
||||
# -5003: already signed in
|
||||
if code in [0, -5003]:
|
||||
result = makeResult('Success', jstr)
|
||||
|
||||
logging.info(result.encode('utf-8').decode('unicode_escape'))
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user