-
Notifications
You must be signed in to change notification settings - Fork 836
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
15619
committed
May 24, 2022
0 parents
commit 0d2ea6b
Showing
9 changed files
with
649 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
__pycache__ | ||
# *.go | ||
*.json | ||
test.py | ||
go.mod | ||
go.sum |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
<p align="center"> | ||
<img src="https://s1.ax1x.com/2022/05/24/XPx1tx.png" width="200" height="200" alt=""> | ||
</p> | ||
<div align="center"> | ||
<h1> 新 B 站粉丝牌助手 | ||
</h1> | ||
<p>当前版本:0.1.0</p> | ||
</div> | ||
|
||
**TODO** | ||
|
||
- [x] 每日直播区签到 | ||
- [x] 每日点赞3次直播间 (200*3 亲密度) | ||
- [x] 每日分享5次直播间 (100*5 亲密度) | ||
- [x] 每日弹幕打卡 (100 亲密度) | ||
- [x] 多账号支持 | ||
- [ ] 每日观看30分钟 | ||
- [ ] 微信推送通知 | ||
|
||
<small>ps: 新版B站粉丝牌的亲密度每一个牌子都将单独计算 </small> | ||
|
||
--- | ||
|
||
### 使用说明 | ||
|
||
##### 环境需求:Python 版本大于 3.8 | ||
|
||
> 克隆本项目 安装依赖 | ||
```shell | ||
git clone https://github.com/XiaoMiku01/fansMedalHelper.git | ||
cd fansMedalHelper | ||
pip install -r requirements.txt | ||
``` | ||
|
||
> 获取B站账号的 access_key | ||
... | ||
|
||
> 填写配置文件 users.yaml | ||
```shell | ||
vim users.yaml | ||
``` | ||
|
||
```yaml | ||
USERS: | ||
- access_key: XXXXXX # 注意冒号后的空格 否则会读取失败 | ||
shared_uid: 123,456 # 需要分享房间的房主UID!不是房间号! 多个用逗号分隔,最多28个 | ||
|
||
- access_key: | ||
shared_uid: | ||
# 多用户以上格式添加 | ||
``` | ||
|
||
> 运行主程序 | ||
```shell | ||
python main.py | ||
``` | ||
|
||
> 效果图 | ||
[![XiifQP.md.png](https://s1.ax1x.com/2022/05/24/XiifQP.md.png)](https://imgtu.com/i/XiifQP) | ||
|
||
--- | ||
|
||
### 注意事项 | ||
|
||
- 本脚本暂时没有集成定时模块 还需要用户定时运行 | ||
- 由于B站分享接口并不是每次分享都会加亲密度,它会有10分钟的CD,所以设置一个拿满500需要40分钟,以此类推,但是得益于Python3的异步机制,多个账号将并发完成任务,例如:A账号设置了2个房间的分享任务,B账号设置了1个,所需时间为90分钟。所以一天24小时最多可以拿满28个房间的分享亲密度 | ||
|
||
--- | ||
|
||
### 赞助 | ||
|
||
![](http://i0.hdslb.com/bfs/album/c267037c9513b8e44bc6ec95dbf772ff0439dce6.jpg) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
package main | ||
|
||
import ( | ||
"crypto/md5" | ||
"encoding/hex" | ||
"fmt" | ||
"io/ioutil" | ||
"net/http" | ||
"net/url" | ||
"sort" | ||
"strings" | ||
"time" | ||
|
||
qrcodeTerminal "github.com/Baozisoftware/qrcode-terminal-go" | ||
gjson "github.com/tidwall/gjson" | ||
) | ||
|
||
var AccessKey string | ||
|
||
var Csrf string | ||
|
||
var Cookies []*http.Cookie | ||
|
||
func Login() { | ||
filename := "login_info.json" | ||
data, err := ioutil.ReadFile(filename) | ||
if err != nil || len(data) == 0 { | ||
fmt.Println("未登录,请扫码登录") | ||
loginBili() | ||
} else { | ||
AccessKey = gjson.Parse(string(data)).Get("data.access_token").String() | ||
for _, c := range gjson.Parse(string(data)).Get("data.cookie_info.cookies").Array() { | ||
Cookies = append(Cookies, &http.Cookie{ | ||
Name: c.Get("name").String(), | ||
Value: c.Get("value").String(), | ||
}) | ||
if c.Get("name").String() == "bili_jct" { | ||
Csrf = c.Get("value").String() | ||
} | ||
} | ||
l, name := is_login() | ||
if l { | ||
fmt.Println("登录成功:", name) | ||
} else { | ||
fmt.Println("登录失败,请重新扫码登录") | ||
loginBili() | ||
} | ||
} | ||
|
||
} | ||
|
||
func is_login() (bool, string) { | ||
api := "https://api.bilibili.com/x/web-interface/nav" | ||
client := http.Client{} | ||
req, _ := http.NewRequest("GET", api, nil) | ||
for _, c := range Cookies { | ||
req.AddCookie(c) | ||
} | ||
resp, err := client.Do(req) | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer resp.Body.Close() | ||
body, _ := ioutil.ReadAll(resp.Body) | ||
data := gjson.ParseBytes(body) | ||
return data.Get("code").Int() == 0, data.Get("data.uname").String() | ||
} | ||
|
||
func get_tv_qrcode_url_and_auth_code() (string, string) { | ||
api := "http://passport.bilibili.com/x/passport-tv-login/qrcode/auth_code" | ||
data := make(map[string]string) | ||
data["local_id"] = "0" | ||
data["ts"] = fmt.Sprintf("%d", time.Now().Unix()) | ||
signature(&data) | ||
data_string := strings.NewReader(map_to_string(data)) | ||
client := http.Client{} | ||
req, _ := http.NewRequest("POST", api, data_string) | ||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
resp, err := client.Do(req) | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer resp.Body.Close() | ||
body, _ := ioutil.ReadAll(resp.Body) | ||
code := gjson.Parse(string(body)).Get("code").Int() | ||
if code == 0 { | ||
qrcode_url := gjson.Parse(string(body)).Get("data.url").String() | ||
auth_code := gjson.Parse(string(body)).Get("data.auth_code").String() | ||
return qrcode_url, auth_code | ||
} else { | ||
panic("get_tv_qrcode_url_and_auth_code error") | ||
} | ||
} | ||
|
||
func verify_login(auth_code string) { | ||
api := "http://passport.bilibili.com/x/passport-tv-login/qrcode/poll" | ||
data := make(map[string]string) | ||
data["auth_code"] = auth_code | ||
data["local_id"] = "0" | ||
data["ts"] = fmt.Sprintf("%d", time.Now().Unix()) | ||
signature(&data) | ||
data_string := strings.NewReader(map_to_string(data)) | ||
client := http.Client{} | ||
req, _ := http.NewRequest("POST", api, data_string) | ||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
for { | ||
resp, err := client.Do(req) | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer resp.Body.Close() | ||
body, _ := ioutil.ReadAll(resp.Body) | ||
code := gjson.Parse(string(body)).Get("code").Int() | ||
AccessKey = gjson.Parse(string(body)).Get("data.access_token").String() | ||
if code == 0 { | ||
fmt.Println("登录成功") | ||
fmt.Println("access_key:", string(AccessKey)) | ||
filename := "login_info.txt" | ||
err := ioutil.WriteFile(filename, []byte(string(AccessKey)), 0644) | ||
if err != nil { | ||
panic(err) | ||
} | ||
fmt.Println("access_key已保存在", filename) | ||
break | ||
} else { | ||
fmt.Println(string(body)) | ||
time.Sleep(time.Second * 3) | ||
} | ||
} | ||
} | ||
|
||
var appkey = "4409e2ce8ffd12b8" | ||
var appsec = "59b43e04ad6965f34319062b478f83dd" | ||
|
||
func signature(params *map[string]string) { | ||
var keys []string | ||
(*params)["appkey"] = appkey | ||
for k := range *params { | ||
keys = append(keys, k) | ||
} | ||
sort.Strings(keys) | ||
var query string | ||
for _, k := range keys { | ||
query += k + "=" + url.QueryEscape((*params)[k]) + "&" | ||
} | ||
query = query[:len(query)-1] + appsec | ||
hash := md5.New() | ||
hash.Write([]byte(query)) | ||
(*params)["sign"] = hex.EncodeToString(hash.Sum(nil)) | ||
} | ||
|
||
func map_to_string(params map[string]string) string { | ||
var query string | ||
for k, v := range params { | ||
query += k + "=" + v + "&" | ||
} | ||
query = query[:len(query)-1] | ||
return query | ||
} | ||
|
||
func loginBili() { | ||
fmt.Println("请最大化窗口,以确保二维码完整显示,回车继续") | ||
fmt.Scanf("%s", "") | ||
login_url, auth_code := get_tv_qrcode_url_and_auth_code() | ||
qrcode := qrcodeTerminal.New() | ||
qrcode.Get([]byte(login_url)).Print() | ||
fmt.Println("或将此链接复制到手机B站打开:", login_url) | ||
verify_login(auth_code) | ||
} | ||
|
||
func main() { | ||
loginBili() | ||
fmt.Scanf("%s", "") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
|
||
import asyncio | ||
import yaml | ||
from src import BiliUser | ||
|
||
|
||
async def main(): | ||
initTasks = [] | ||
startTasks = [] | ||
with open('users.yaml', 'r', encoding='utf-8') as f: | ||
users = yaml.load(f, Loader=yaml.FullLoader) | ||
for user in users['USERS']: | ||
if user['access_key']: | ||
biliUser = BiliUser(user['access_key'], user['shared_uid']) | ||
initTasks.append(biliUser.init()) | ||
startTasks.append(biliUser.start()) | ||
await asyncio.gather(*initTasks) | ||
await asyncio.gather(*startTasks) | ||
if __name__ == '__main__': | ||
loop = asyncio.get_event_loop() | ||
loop.run_until_complete(main()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
aiohttp >=3.7.4 | ||
loguru >= 0.5.3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from .user import BiliUser | ||
from .api import BiliApi |
Oops, something went wrong.