.directory
demo/danmu.log
a.json
+demo/cookie.txt
+player-loader-2.0.4.min.js
+pv-tracker.js
*/
var msglog = p.Logf().New().Base(-1, "Msg.go>").Open("danmu.log").Level(1)
+var Msg_cookie string
+var Msg_roomid int
func Msg(b []byte, compress bool) {
if compress {
return
} else {
switch cmd.(string) {
+ case "ANCHOR_LOT_START"://天选之人开始
+ case "ANCHOR_LOT_CHECKSTATUS":
+ case "ANCHOR_LOT_END"://天选之人结束
+ case "ANCHOR_LOT_AWARD"://天选之人获奖
case "COMBO_SEND":
case "INTERACT_WORD":
case "ACTIVITY_BANNER_UPDATE_V2":
}
func welcome_guard(s string){
+ msglog.Base(1, "房")
+
username := p.Json().GetValFromS(s, "data.username");
guard_level := p.Json().GetValFromS(s, "data.guard_level");
}
func send_gift(s string){
+ msglog.Base(1, "礼")
+
coin_type := p.Json().GetValFromS(s, "data.coin_type");
num := p.Json().GetValFromS(s, "data.num");
uname := p.Json().GetValFromS(s, "data.uname");
price := p.Json().GetValFromS(s, "data.price");
var sh []interface{}
+ var allprice int64
+ if num != nil {
+ sh = append(sh, int64(num.(float64)), "x")
+ }
+ if price != nil {
+ allprice = int64(num.(float64) * price.(float64))
+ sh = append(sh, "(", allprice, "x 金瓜子 )")
+ }
if uname != nil {
sh = append(sh, uname.(string))
}
if action != nil {
sh = append(sh, action.(string))
}
- if num != nil {
- sh = append(sh, int64(num.(float64)), "x")
- }
if giftName != nil {
sh = append(sh, giftName.(string))
}
- if price != nil {
- sh = append(sh, "(", int64(price.(float64)), "x 金瓜子 )")
- }
-
+
if len(sh) == 0 {return}
- if coin_type.(string) == "silver" {msglog.T(sh...);return}
+ //小于1万金瓜子 银瓜子不显示
+ if allprice < 10000 || coin_type.(string) == "silver" {msglog.T(sh...);return}
msglog.I(sh...)
}
func room_block_msg(s string) {
+ msglog.Base(1, "封")
+
if uname := p.Json().GetValFromS(s, "uname");uname == nil {
msglog.E("uname", uname)
return
}
func preparing(s string) {
+ msglog.Base(1, "房")
+
if roomid := p.Json().GetValFromS(s, "roomid");roomid == nil {
msglog.E("roomid", roomid)
return
}
func live(s string) {
+ msglog.Base(1, "房")
+
if roomid := p.Json().GetValFromS(s, "roomid");roomid == nil {
msglog.E("roomid", roomid)
return
}
func super_chat_message(s string){
+ msglog.Base(1, "礼")
+
uname := p.Json().GetValFromS(s, "data.user_info.uname");
price := p.Json().GetValFromS(s, "data.price");
message := p.Json().GetValFromS(s, "data.message");
}
func panel(s string){
+ msglog.Base(1, "房")
+
if note := p.Json().GetValFromS(s, "data.note");note == nil {
msglog.E("note", note)
return
}
func entry_effect(s string){
+ msglog.Base(1, "房")
+
if copy_writing := p.Json().GetValFromS(s, "data.copy_writing");copy_writing == nil {
msglog.E("copy_writing", copy_writing)
return
}
func roomsilent(s string){
+ msglog.Base(1, "房")
+
if level := p.Json().GetValFromS(s, "data.level");level == nil {
msglog.E("level", level)
return
}
func roominfo(s string){
+ msglog.Base(1, "粉")
+
fans := p.Json().GetValFromS(s, "data.fans");
fans_club := p.Json().GetValFromS(s, "data.fans_club");
infob := info.([]interface{})
msg := infob[1].(string)
auth := infob[2].([]interface{})[1].(string)
+
+ if Msg_roomid != 0 && Msg_cookie != "" && msg == "弹幕机在么" {Danmu_s("在", Msg_cookie, Msg_roomid)}
+
msglog.I(auth, ":", msg)
}
}
INFO: 2020/09/15 06:40:21 [bili_danmu.go>测试] [连接 wss://tx-sh-live-comet-01.chat.bilibili.com/sub]
INFO: 2020/09/15 06:40:21 [bili_danmu.go>测试] [已连接到房间 13946381]
INFO: 2020/09/15 06:40:22 [bili_danmu.go>测试] [开始心跳]
+弹幕
INFO: 2020/09/15 06:40:29 [Msg.go>] [pek0pek0 : 外掛]
-INFO: 2020/09/15 06:40:30 [Msg.go>] [NealxS : 明显是挂了]
-INFO: 2020/09/15 06:40:33 [Msg.go>] [懒得起昵称丶 : 真大哥]
-INFO: 2020/09/15 06:40:36 [Msg.go>] [恩里克-普奇-神父 : 这场战役我们失去了天义佬]
-INFO: 2020/09/15 06:40:36 [Msg.go>] [ntwww 投喂 1 x 冰阔落 ( 1000 x 金瓜子 )]
-INFO: 2020/09/15 06:40:38 [Msg.go>] [方舟之下幽兰呆鹅 : 外挂]
-INFO: 2020/09/15 06:40:38 [Msg.go>] [一般通りのまこちゅう : 科技大佬]
-^CINFO: 2020/09/15 06:46:14 [ws.go>心跳] [fin]
-INFO: 2020/09/15 06:46:14 [ws.go>关闭] [*ws.Close]
-INFO: 2020/09/15 06:46:14 [ws.go>关闭] [ok]
+弹幕机
+INFO: 2020/09/15 14:45:54 [弹幕发送] [发送 在 至 12345]
+INFO: 2020/09/15 14:45:55 [弹幕发送] [成功]
+INFO: 2020/09/15 14:45:55 [Msg.go>] [12345 : 弹幕机在么]
+INFO: 2020/09/15 14:45:56 [Msg.go>] [12345 : 在]
+礼物
+INFO: 2020/09/15 09:00:26 [Msg.go> 礼] [不能一命通关的M桑 投喂 5 x 冰阔落 ( 5000 x 金瓜子 )]
+入场提示
+INFO: 2020/09/15 09:00:41 [Msg.go> 房] [欢迎舰长 <%不同选择%> 进入直播间]
+排行
+INFO: 2020/09/15 09:01:00 [Msg.go> 房] [排行 手游 第4名]
+粉丝更新
+INFO: 2020/09/15 09:01:00 [Msg.go> 粉] [粉丝总人数: 395189 粉丝团人数: 2391]
+。。。
+
+^CINFO: 2020/09/15 09:18:28 [ws.go>关闭] [关闭!]
+INFO: 2020/09/15 09:18:28 [bili_danmu.go>测试] [停止,等待服务器断开连接]
+INFO: 2020/09/15 09:18:28 [ws.go>处理] [捕获到中断]
+INFO: 2020/09/15 09:18:28 [ws.go>心跳] [停止!]
+ERROR: 2020/09/15 09:18:28 [ws.go>处理] [服务器意外关闭连接]
+INFO: 2020/09/15 09:18:29 [bili_danmu.go>测试] [结束退出]
ctrl+c退出,日志会同时追加记录到文件danmu.log中
```
)
const LogLevel = 1
+var danmulog = p.Logf().New().Open("danmu.log").Base(-1, "bili_danmu.go").Level(LogLevel)
func Demo() {
- l:=p.Logf().New().Open("danmu.log").Base(-1, "bili_danmu.go>测试").Level(LogLevel)
- defer l.Block()
+ danmulog.Base(-1, "测试")
+ defer danmulog.Base(0)
//ctrl+c退出
interrupt := make(chan os.Signal, 1)
fmt.Printf("输入房间号: ")
_, err := fmt.Scanln(&room)
if err != nil {
- l.E("输入错误", err)
+ danmulog.E("输入错误", err)
return
}
//获取房间相关信息
api := New_api(room).Get_host_Token()
if len(api.Url) == 0 || api.Roomid == 0 || api.Token == "" || api.Uid == 0 {
- l.E("some err")
+ danmulog.E("some err")
return
}
- l.I("连接到房间", room)
+ danmulog.I("连接到房间", room)
//对每个弹幕服务器尝试
for _, v := range api.Url {
//SendChan 传入发送[]byte
//RecvChan 接收[]byte
- l.I("连接", v)
+ danmulog.I("连接", v)
ws.SendChan <- hello_send(api.Roomid, api.Token)
if hello_ok(<- ws.RecvChan) {
- l.I("已连接到房间", room)
+ danmulog.I("已连接到房间", room)
//开始心跳
go func(){
+ danmulog.I("开始心跳")
p.Sys().MTimeoutf(500)//500ms
- l.I("开始心跳")
heartbeatmsg, heartinterval := heartbeat()
- ws.Heartbeat(1000 * heartinterval, heartbeatmsg)
+ ws.Heartbeat(1000 * heartinterval, heartbeatmsg)
+
+ //打招呼
+ if p.Checkfile().IsExist("cookie.txt") {
+ f := p.File().FileWR(p.Filel{
+ File:"cookie.txt",
+ Write:false,
+ })
+ //传输变量至Msg,以便响应弹幕"弹幕机在么"
+ Msg_roomid = api.Roomid
+ Msg_cookie = f
+ }
}()
}
}
case <- interrupt:
ws.Close()
- isclose = true
+ danmulog.I("停止,等待服务器断开连接")
break_sign = true
}
}
if break_sign {break}
-
- p.Sys().Timeoutf(1)
}
+
+ p.Sys().Timeoutf(1)
}
+
+ danmulog.I("结束退出")
}
}
//返回数据分派
func Reply(b []byte) {
- l := p.Logf().New().Base(-1, "bili_danmu.go>返回分派").Level(LogLevel)
- defer l.Block()
+ danmulog.Base(-1, "返回分派")
+ defer danmulog.Base(0)
if ist, _ := headChe(b[:16], len(b), WS_BODY_PROTOCOL_VERSION_DEFLATE, WS_OP_MESSAGE, 0, 4); ist {
Msg(b, true);return
}
if ist, _ := headChe(b[:16], len(b), WS_HEADER_DEFAULT_VERSION, WS_OP_HEARTBEAT_REPLY, WS_HEADER_DEFAULT_SEQUENCE, 4); ist {
- l.T("heartbeat replay!");
+ danmulog.T("heartbeat replay!");
return
}
- l.T("unknow reply", b)
+ danmulog.T("unknow reply", b)
}
//头部生成与检查
func headChe(head []byte, datalenght,Bodyv,Opeation,Sequence,show int) (bool,int32) {
if len(head) != WS_PACKAGE_HEADER_TOTAL_LENGTH {return false, 0}
- l := p.Logf().New().Base(-1, "bili_danmu.go>头检查").Level(show)
- defer l.Block()
+ danmulog.Base(-1, "头部检查").Level(show)
+ defer danmulog.Base(0)
packL := Btoi32(head[:4])
headL := Btoi16(head[4:6])
OpeaT := Btoi32(head[8:12])
Seque := Btoi32(head[12:16])
- if packL > int32(datalenght) {l.E("包缺损", packL, datalenght);return false, packL}
- if headL != WS_PACKAGE_HEADER_TOTAL_LENGTH {l.E("头错误", headL);return false, packL}
- if OpeaT != int32(Opeation) {l.E("类型错误");return false, packL}
- if Seque != int32(Sequence) {l.E("Seq错误");return false, packL}
- if BodyV != int16(Bodyv) {l.E("压缩算法错误");return false, packL}
+ if packL > int32(datalenght) {danmulog.E("包缺损", packL, datalenght);return false, packL}
+ if headL != WS_PACKAGE_HEADER_TOTAL_LENGTH {danmulog.E("头错误", headL);return false, packL}
+ if OpeaT != int32(Opeation) {danmulog.E("类型错误");return false, packL}
+ if Seque != int32(Sequence) {danmulog.E("Seq错误");return false, packL}
+ if BodyV != int16(Bodyv) {danmulog.E("压缩算法错误");return false, packL}
return true, packL
}
//认证生成与检查
func hello_send(roomid int, key string) []byte {
- l := p.Logf().New().Base(-1, "bili_danmu.go>头生成").Level(LogLevel).T("hello_ws")
- defer l.Block()
if roomid == 0 || key == "" {
- l.E("roomid == 0 || key == \"\"")
+ danmulog.Base(1, "认证生成").E("roomid == 0 || key == \"\"")
return []byte("")
}
github.com/qydysky/part v0.0.0-20200914222559-436abc80976a/go.mod h1:+8N3UgJBVyJj8ar31eZtucwrKpLpay854Y5qq0xk3x0=
github.com/qydysky/part v0.0.0-20200914225111-80645055bc83 h1:iAqwOKLRNeJ2kwgFOWRifJGEomYPKvCpygSQqSXzdSM=
github.com/qydysky/part v0.0.0-20200914225111-80645055bc83/go.mod h1:+8N3UgJBVyJj8ar31eZtucwrKpLpay854Y5qq0xk3x0=
+github.com/qydysky/part v0.0.0-20200915003959-bbc60ec9e47e h1:/APS+qy3b5k432eh1W5lFIHUWC4mTV0i0neDTtanI0A=
+github.com/qydysky/part v0.0.0-20200915003959-bbc60ec9e47e/go.mod h1:+8N3UgJBVyJj8ar31eZtucwrKpLpay854Y5qq0xk3x0=
+github.com/qydysky/part v0.0.0-20200915060427-df3e1d541451 h1:0cLySh/YtFFzKapmgeZttO6qMH8gcixXvrIvswbVYeo=
+github.com/qydysky/part v0.0.0-20200915060427-df3e1d541451/go.mod h1:+8N3UgJBVyJj8ar31eZtucwrKpLpay854Y5qq0xk3x0=
+github.com/qydysky/part v0.0.0-20200915064846-d3f2213b9508 h1:RQgjB7cwDWinNOVRkstHrYaZUydCwyZFvoiVtZX7rKo=
+github.com/qydysky/part v0.0.0-20200915064846-d3f2213b9508/go.mod h1:+8N3UgJBVyJj8ar31eZtucwrKpLpay854Y5qq0xk3x0=
github.com/shirou/gopsutil v2.20.7+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/gopsutil v2.20.8+incompatible h1:8c7Atn0FAUZJo+f4wYbN0iVpdWniCQk7IYwGtgdh1mY=
github.com/shirou/gopsutil v2.20.8+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200915050820-6d893a6b696e h1:RGS7MuoO4EeRp68J5OWuANAi5oVYtLRl+3LoD5fkMns=
+golang.org/x/sys v0.0.0-20200915050820-6d893a6b696e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
require (
github.com/gorilla/websocket v1.4.2
github.com/klauspost/compress v1.11.0 // indirect
- github.com/qydysky/part v0.0.0-20200914225111-80645055bc83
+ github.com/qydysky/part v0.0.0-20200915064846-d3f2213b9508
github.com/shirou/gopsutil v2.20.8+incompatible // indirect
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect
- golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 // indirect
+ golang.org/x/sys v0.0.0-20200915050820-6d893a6b696e // indirect
)
//replace github.com/qydysky/part => ../part
github.com/qydysky/part v0.0.0-20200914222559-436abc80976a/go.mod h1:+8N3UgJBVyJj8ar31eZtucwrKpLpay854Y5qq0xk3x0=
github.com/qydysky/part v0.0.0-20200914225111-80645055bc83 h1:iAqwOKLRNeJ2kwgFOWRifJGEomYPKvCpygSQqSXzdSM=
github.com/qydysky/part v0.0.0-20200914225111-80645055bc83/go.mod h1:+8N3UgJBVyJj8ar31eZtucwrKpLpay854Y5qq0xk3x0=
+github.com/qydysky/part v0.0.0-20200915003959-bbc60ec9e47e h1:/APS+qy3b5k432eh1W5lFIHUWC4mTV0i0neDTtanI0A=
+github.com/qydysky/part v0.0.0-20200915003959-bbc60ec9e47e/go.mod h1:+8N3UgJBVyJj8ar31eZtucwrKpLpay854Y5qq0xk3x0=
+github.com/qydysky/part v0.0.0-20200915060427-df3e1d541451 h1:0cLySh/YtFFzKapmgeZttO6qMH8gcixXvrIvswbVYeo=
+github.com/qydysky/part v0.0.0-20200915060427-df3e1d541451/go.mod h1:+8N3UgJBVyJj8ar31eZtucwrKpLpay854Y5qq0xk3x0=
+github.com/qydysky/part v0.0.0-20200915064846-d3f2213b9508 h1:RQgjB7cwDWinNOVRkstHrYaZUydCwyZFvoiVtZX7rKo=
+github.com/qydysky/part v0.0.0-20200915064846-d3f2213b9508/go.mod h1:+8N3UgJBVyJj8ar31eZtucwrKpLpay854Y5qq0xk3x0=
github.com/shirou/gopsutil v2.20.7+incompatible h1:Ymv4OD12d6zm+2yONe39VSmp2XooJe8za7ngOLW/o/w=
github.com/shirou/gopsutil v2.20.7+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/gopsutil v2.20.8+incompatible h1:8c7Atn0FAUZJo+f4wYbN0iVpdWniCQk7IYwGtgdh1mY=
golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200915050820-6d893a6b696e h1:RGS7MuoO4EeRp68J5OWuANAi5oVYtLRl+3LoD5fkMns=
+golang.org/x/sys v0.0.0-20200915050820-6d893a6b696e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
--- /dev/null
+package bili_danmu
+
+import (
+ "strings"
+ "strconv"
+
+ p "github.com/qydysky/part"
+)
+
+//每秒一个令牌,最多等5秒
+var danmu_s_limit = p.Limit(1, 1000, 5000)
+
+//弹幕发送
+func Danmu_s(msg,Cookie string, roomid int) {
+ //等待令牌时阻塞,超时返回false
+ if danmu_s_limit.TO() {return}
+
+ l := p.Logf().New().Base(-1, "弹幕发送").Level(1)
+ defer l.Block()
+
+ if msg == "" || Cookie == "" || roomid == 0{
+ l.E("输入参数不足")
+ return
+ }
+ if i := strings.Index(Cookie, "{"); i != -1 {
+ l.E("Cookie格式错误,需为 key=val; key=val 式")
+ return
+ }
+
+ if i := strings.Index(Cookie, "PVID="); i == -1 {
+ l.E("Cookie错误,无PVID=")
+ return
+ } else {
+ if d := strings.Index(Cookie[i:], ";"); d == -1 {
+ Cookie = Cookie[:i]
+ } else {
+ Cookie = Cookie[:i] + Cookie[i + d + 1:]
+ }
+ }
+
+ var csrf string
+ if i := strings.Index(Cookie, "bili_jct="); i == -1 {
+ l.E("Cookie错误,无bili_jct=")
+ return
+ } else {
+ if d := strings.Index(Cookie[i + 9:], ";"); d == -1 {
+ csrf = Cookie[i + 9:]
+ } else {
+ csrf = Cookie[i + 9:][:d]
+ }
+ }
+
+ PostStr := `color=16777215&fontsize=25&mode=1&msg=` + msg + `&rnd=` + strconv.Itoa(int(p.Sys().GetMTime())) + `&roomid=` + strconv.Itoa(roomid) + `&bubble=0&csrf_token=` + csrf + `&csrf=` + csrf
+
+ l.I("发送", msg, "至", roomid)
+ r := p.Req()
+ err := r.Reqf(p.Rval{
+ Url:"https://api.live.bilibili.com/msg/send",
+ PostStr:PostStr,
+ Timeout:5,
+ Referer:"https://live.bilibili.com/" + strconv.Itoa(roomid),
+ Cookie:Cookie,
+ })
+ if err != nil {
+ l.E(err)
+ return
+ }
+
+ if code := p.Json().GetValFromS(string(r.Respon), "code");code == nil || code.(float64) != 0 {
+ if message := p.Json().GetValFromS(string(r.Respon), "message");message != nil {
+ l.E(message)
+ } else {
+ l.E(string(r.Respon))
+ }
+ return
+ }
+
+ l.I("成功")
+
+}
\ No newline at end of file
return
}
case <- o.interrupt:
- l.I("interrupt")
+ l.I("捕获到中断")
// Cleanly close the connection by sending a close message and then
// waiting (with timeout) for the server to close the connection.
err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
case <-ticker.C:
o.SendChan <- msg
case <- o.interrupt:
- l.I("fin")
+ l.I("停止!")
return
}
}
}
func (o *ws) Close() {
- l := p.Logf().New().Base(-1, "ws.go>关闭").Level(LogLevel).I("*ws.Close")
+ l := p.Logf().New().Base(-1, "ws.go>关闭").Level(LogLevel)
defer l.Block()
if !o.used {
- l.I("!o.used")
+ l.E("未在使用的连接")
return
}
o.used = false
close(o.interrupt)
- l.I("ok")
+ l.I("关闭!")
}
func (o *ws) Isclose() bool {