player-loader-2.0.4.min.js
pv-tracker.js
demo/Autoban.txt
-demo/his/danmu.log
+demo/his/*.log
danmu.log
+msg_sample/*.json
package bili_danmu
import (
+ // "fmt"
"strconv"
- "bytes"
+ "strings"
"sync"
"time"
//功能开关
var AllF = map[string]bool{
- "Autoban":false,//自动封禁(仅提示,未完成)
+ "Autoban":true,//自动封禁(仅提示,未完成)
"Danmuji":true,//反射型弹幕机,回应弹幕
"Danmuji_auto":false,//自动型弹幕机,定时输出
"Autoskip":true,//刷屏缩减,相同合并
}
return false
}
+//公共
+func cross(a string,buf []string) (float32) {
+ var s float32
+ var matched bool
+ for _,v1 := range a {
+ for _,v2 := range buf {
+ for _,v3 := range v2 {
+ if v3 == v1 {matched = true;break}
+ }
+ if matched {break}
+ }
+ if matched {s += 1}
+ matched = false
+ }
+ return s / float32(len([]rune(a)))
+}
+func selfcross(a string) (float32) {
+ buf := make(map[rune]bool)
+ for _,v := range a {
+ if _,ok := buf[v]; !ok {
+ buf[v] = true
+ }
+ }
+ return 1 - float32(len(buf)) / float32(len([]rune(a)))
+}
//功能区
type Autoban struct {
- buf []byte
+ Banbuf []string
+ buf []string
Inuse bool
}
Inuse:IsOn("Autoban"),
}
-func Autobanf(s string) float32 {
- if !autoban.Inuse {return 0}
+func Autobanf(s string) bool {
+ if !autoban.Inuse {return false}
- if len(autoban.buf) == 0 {
+ if len(autoban.Banbuf) == 0 {
f := p.File().FileWR(p.Filel{
File:"Autoban.txt",
- Write:false,
})
- autoban.buf = []byte(f)
+
+ for _,v := range strings.Split(f, "\n") {
+ autoban.Banbuf = append(autoban.Banbuf, v)
+ }
}
- var scop int
- for _, v := range []byte(s) {
- if bytes.Contains(autoban.buf, []byte{v}) {scop += 1}
+ if len(autoban.buf) < 10 {
+ autoban.buf = append(autoban.buf, s)
+ return false
}
- return float32(scop) / float32(len(s))
+ defer func(){
+ autoban.buf = append(autoban.buf[1:], s)
+ }()
+
+ var res []float32
+
+ pt := float32(len([]rune(s)))
+ if pt <= 3 {return false}//字数过少去除
+ res = append(res, pt)
+
+ pt = selfcross(s);
+ if pt > 0.6 {return false}//自身重复高去除
+ res = append(res, pt)
+
+ pt = cross(s, autoban.buf);
+ if pt < 0.7 {return false}//历史重复低去除
+ res = append(res, pt)
+
+ pt = cross(s, autoban.Banbuf);
+ if pt < 0.8 {return false}//ban字符重复低去除
+ res = append(res, pt)
+
+ l := p.Logf().New().Open("danmu.log").Base(1, "autoban")
+ l.W(res)
+ return true
}
type Danmuji struct {
Inuse:IsOn("Lessdanmu"),
}
-func Lessdanmuf(s string, bufsize int, drop float32) bool {
- if !lessdanmu.Inuse {return false}
+func Lessdanmuf(s string, bufsize int) float32 {
+ if !lessdanmu.Inuse {return 0}
if len(lessdanmu.buf) < bufsize {
lessdanmu.buf = append(lessdanmu.buf, s)
- return false
+ return 0
}
o := cross(s, lessdanmu.buf)
- if o == 1 {return true}//完全无用
+ if o == 1 {return 1}//完全无用
lessdanmu.buf = append(lessdanmu.buf[1:], s)
-
- return o > drop
-}
-func cross(a string,buf []string) (float32) {
- var s float32
- var matched bool
- for _,v1 := range a {
- for _,v2 := range buf {
- for _,v3 := range v2 {
- if v3 == v1 {matched = true;break}
- }
- if matched {break}
- }
- if matched {s += 1}
- matched = false
- }
- return s / float32(len([]rune(a)))
+ return o
}
/*
目标:弹幕机自动发送弹幕
原理:留存弹幕,称为buf。将当前若干弹幕在buf中的位置找出,根据位置聚集情况及该位置出现语句的频率,选择发送的弹幕
*/
-type Moredanmu struct {}
+// type Moredanmu struct {
+// Inuse bool
+// buf []string
+// }
+
+// var moredanmu = Moredanmu{
+// Inuse:IsOn("Moredanmu"),
+// }
+// func moredanmuf(s string) {
+// if !moredanmu.Inuse {return}
+// // if len(moredanmu.buf) < bufsize {
+// moredanmu.buf = append(moredanmu.buf, s)
+// // }
+
+// // b := p.Buf("danmu.buf").Load()
+// // if b.Get() != nil {
+// // moredanmu.buf = *b.Get()
+// // }
+// }
+
+// func moredanmu_get(tb []string) {
+// if !moredanmu.Inuse {return}
+
+// var tmp string
+// for _,v := range tb {
+// tmp += v
+// }
+// // for _,v := range tb {
+// // tmp += len([]rune(v[:len(v)-1]))
+// // }
+
+// var max float32
+// var loc int
+// for i := 0; len(moredanmu.buf) >= i + len(tb); i++ {
+// if m := cross(tmp, moredanmu.buf[i:i + len(tb)]);m > max {
+// max = m
+// loc = i
+// }
+// }
+// if loc != 0 {
+// p := moredanmu.buf[loc:loc + len(tb)]
+// for i,v := range p{
+// if m := cross(v, p);m > max {
+// max = m
+// loc = i
+// }
+// }
+// fmt.Println(len(moredanmu.buf),"=>",p[loc])
+// }
+// }
type Shortdanmu struct {
Inuse bool
import (
"fmt"
- "bytes"
- "compress/zlib"
p "github.com/qydysky/part"
)
"ROOM_RANK":nil,
"ROOM_SHIELD":nil,
"USER_TOAST_MSG":nil,
- "WIN_ACTIVITY":nil,
+ "WIN_ACTIVITY":replayF.win_activity,//活动
+ "SPECIAL_GIFT":replayF.special_gift,//节奏风暴
"GUARD_BUY":replayF.guard_buy,//大航海购买
"WELCOME_GUARD":replayF.welcome_guard,//大航海进入
"DANMU_MSG":replayF.danmu,//弹幕
"ROOM_REAL_TIME_MESSAGE_UPDATE":nil,//replayF.roominfo,//粉丝数
}
-func Msg(b []byte, compress bool) {
- if compress {
- readc, err := zlib.NewReader(bytes.NewReader(b[16:]))
- if err != nil {msglog.E("解压错误");return}
- defer readc.Close()
-
- buf := bytes.NewBuffer(nil)
- if _, err := buf.ReadFrom(readc);err != nil {msglog.E("解压错误");return}
- b = buf.Bytes()
- }
-
- for len(b) != 0 {
-
- var packL int32
- if ist, packl := headChe(b[:16], len(b), WS_BODY_PROTOCOL_VERSION_NORMAL, WS_OP_MESSAGE, 0, 0); !ist {
- msglog.E("头错误");return
- } else {
- packL = packl
- }
+func Msg(b []byte) {
+ s := string(b)
+ if cmd := p.Json().GetValFromS(s, "cmd");cmd == nil {
+ msglog.E("cmd", s)
+ return
+ } else {
+ var f replayF
- s := string(b[16:packL])
- b = b[packL:]
- if cmd := p.Json().GetValFromS(s, "cmd");cmd == nil {
- msglog.E("cmd", s)
- return
+ if F, ok := Msg_map[cmd.(string)]; ok {
+ if F != nil {F(f, s)}
} else {
- var f replayF
-
- if F, ok := Msg_map[cmd.(string)]; ok {
- if F != nil {F(f, s)}
- } else {
- f.defaultMsg(s)
- }
+ f.defaultMsg(s)
}
}
msglog.Base(1, "Unknow cmd").E(s)
}
+func (replayF) win_activity(s string){
+ msglog.Fileonly(true)
+ defer msglog.Fileonly(false)
+
+ title := p.Json().GetValFromS(s, "data.title");
+
+ fmt.Println("活动", title, "已开启")
+ msglog.Base(1, "房").I("活动", title, "已开启")
+}
+
+func (replayF) special_gift(s string){
+ msglog.Fileonly(true)
+ defer msglog.Fileonly(false)
+
+ content := p.Json().GetValFromS(s, "data.39.content");
+ action := p.Json().GetValFromS(s, "data.39.action");
+
+ var sh []interface{}
+
+ if action != nil && action.(string) == "end" {
+ return
+ }
+ if content != nil {
+ sh = append(sh, "节奏风暴", content, "¥ 100")
+ }
+
+ fmt.Println("\n====")
+ fmt.Println(sh...)
+ fmt.Println("====\n")
+ msglog.Base(1, "礼").I(sh...)
+
+}
+
func (replayF) guard_buy(s string){
msglog.Fileonly(true).Base(-1, "礼")
defer msglog.Base(0).Fileonly(false)
sh = append(sh, "¥", int(price.(float64)) / 1000)
}
- fmt.Println("====")
+ fmt.Println("\n====")
fmt.Println(sh...)
- fmt.Println("====")
+ fmt.Println("====\n")
msglog.I(sh...)
}
//小于3万金瓜子
if allprice < 30000 {msglog.T(sh...);return}
- fmt.Println("====")
+ fmt.Println("\n====")
fmt.Println(sh...)
- fmt.Println("====")
+ fmt.Println("====\n")
msglog.I(sh...)
}
msglog.Fileonly(true)
defer msglog.Fileonly(false)
- fmt.Println("====")
+ fmt.Println("\n====")
fmt.Println(sh...)
- fmt.Println("====")
+ fmt.Println("====\n")
msglog.Base(1, "礼").I(sh...)
}
//F附加方法
Danmujif(msg, Msg_cookie, Msg_roomid)
- if Autobanf(msg) > 0.5 {
+ if Autobanf(msg) {
+ fmt.Println("风险", msg)
msglog.Base(1, "风险").I(msg)
return
}
}
Msg_showdanmu(auth, msg)
- msglog.I(auth, ":", msg)
}
}
func Msg_showdanmu(auth interface{}, msg string) {
- if Lessdanmuf(msg, 20, 0.5) {//与前20条弹幕重复的字数占比度>0.5的屏蔽
+ if Lessdanmuf(msg, 20) > 0.7 {//与前20条弹幕重复的字数占比度>0.7的屏蔽
if auth != nil {msglog.I(auth, ":", msg)}
return
}
+
fmt.Println(Shortdanmuf(msg))
+ if auth != nil {msglog.I(auth, ":", msg)}
}
\ No newline at end of file
"strconv"
"os"
"os/signal"
+ "compress/zlib"
p "github.com/qydysky/part"
)
//返回数据分派
func Reply(b []byte) {
- danmulog.Base(-1, "返回分派")
- defer danmulog.Base(0)
+ danmulog.Base(-1, "返回分派").Level(4)
+ defer danmulog.Base(0).Level(LogLevel)
- 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_BODY_PROTOCOL_VERSION_NORMAL, WS_OP_MESSAGE, 0, 4); ist {
- Msg(b, false);return
+ head := headChe(b[:16])
+ if int(head.packL) > len(b) {danmulog.E("包缺损");return}
+
+ if head.BodyV == WS_BODY_PROTOCOL_VERSION_DEFLATE {
+ readc, err := zlib.NewReader(bytes.NewReader(b[16:]))
+ if err != nil {danmulog.E("解压错误");return}
+ defer readc.Close()
+
+ buf := bytes.NewBuffer(nil)
+ if _, err := buf.ReadFrom(readc);err != nil {danmulog.E("解压错误");return}
+ b = buf.Bytes()
}
- if ist, _ := headChe(b[:16], len(b), WS_HEADER_DEFAULT_VERSION, WS_OP_HEARTBEAT_REPLY, WS_HEADER_DEFAULT_SEQUENCE, 4); ist {
- danmulog.T("heartbeat replay!");
- return
+ for len(b) != 0 {
+ head := headChe(b[:16])
+ if int(head.packL) > len(b) {danmulog.E("包缺损");return}
+
+ contain := b[16:head.packL]
+ switch head.OpeaT {
+ case WS_OP_MESSAGE:Msg(contain)
+ case WS_OP_HEARTBEAT_REPLY:danmulog.T("heartbeat replay!")
+ default :danmulog.T("unknow reply", contain)
+ }
+
+ b = b[head.packL:]
}
+}
- danmulog.T("unknow reply", b)
+type header struct {
+ packL int32
+ headL int16
+ BodyV int16
+ OpeaT int32
+ Seque int32
}
//头部生成与检查
return buffer.Bytes()
}
-func headChe(head []byte, datalenght,Bodyv,Opeation,Sequence,show int) (bool,int32) {
- danmulog.Base(-1, "头部检查")
- defer danmulog.Base(0)
+func headChe(head []byte) (header) {
- if len(head) != WS_PACKAGE_HEADER_TOTAL_LENGTH {return false, 0}
-
- danmulog.Level(show)
- defer danmulog.Level(LogLevel)
+ if len(head) != WS_PACKAGE_HEADER_TOTAL_LENGTH {danmulog.Base(1, "头部检查").E("输入头长度错误");return header{}}
-
packL := Btoi32(head[:4])
headL := Btoi16(head[4:6])
BodyV := Btoi16(head[6:8])
OpeaT := Btoi32(head[8:12])
Seque := Btoi32(head[12:16])
- 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
+ return header{
+ packL :packL,
+ headL :headL,
+ BodyV :BodyV,
+ OpeaT :OpeaT,
+ Seque :Seque,
+ }
}
//认证生成与检查