]> 127.0.0.1 Git - bili_danmu/.git/commitdiff
14
authorqydysky <qydysky@foxmail.com>
Sat, 19 Sep 2020 01:36:23 +0000 (09:36 +0800)
committerqydysky <qydysky@foxmail.com>
Sat, 19 Sep 2020 01:36:38 +0000 (09:36 +0800)
.gitignore
F.go
Msg.go
bili_danmu.go

index beb92ad41bfe2682836b1a6023a7167baea1d812..4c635dbc1d2ed87042076ee8607ce0b695d0201c 100644 (file)
@@ -5,5 +5,6 @@ demo/cookie.txt
 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
diff --git a/F.go b/F.go
index c2a9aa78778cb2a32b3645b0984700db36cb0652..c7a2a4c6147254261919d86791aa23331c1e5ef3 100644 (file)
--- a/F.go
+++ b/F.go
@@ -1,8 +1,9 @@
 package bili_danmu
 
 import (
+       // "fmt"
        "strconv"
-       "bytes"
+       "strings"
        "sync"
        "time"
 
@@ -11,7 +12,7 @@ import (
 
 //功能开关
 var AllF = map[string]bool{
-       "Autoban":false,//自动封禁(仅提示,未完成)
+       "Autoban":true,//自动封禁(仅提示,未完成)
        "Danmuji":true,//反射型弹幕机,回应弹幕
        "Danmuji_auto":false,//自动型弹幕机,定时输出
        "Autoskip":true,//刷屏缩减,相同合并
@@ -26,10 +27,36 @@ func IsOn(s string) bool {
        }
        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
 }
 
@@ -37,22 +64,48 @@ var autoban = Autoban {
        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 {
@@ -140,34 +193,18 @@ var lessdanmu = Lessdanmu{
        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
 }
 
 /*
@@ -175,7 +212,56 @@ func cross(a string,buf []string) (float32) {
        目标:弹幕机自动发送弹幕
        原理:留存弹幕,称为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
diff --git a/Msg.go b/Msg.go
index 5d08e7b2e7c8d9fe549d5a5f9d159badccb2cb36..27b473ef9c8c3ade91557bf82ae54895a1ef178a 100644 (file)
--- a/Msg.go
+++ b/Msg.go
@@ -2,8 +2,6 @@ package bili_danmu
 
 import (
        "fmt"
-       "bytes"
-       "compress/zlib"
 
        p "github.com/qydysky/part"
 )
@@ -32,7 +30,8 @@ var Msg_map = map[string]func(replayF, string) {
        "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,//弹幕
@@ -50,39 +49,18 @@ var Msg_map = map[string]func(replayF, string) {
        "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)
                }
        }
 
@@ -95,6 +73,39 @@ func (replayF) defaultMsg(s string){
        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)
@@ -115,9 +126,9 @@ func (replayF) guard_buy(s string){
                sh = append(sh, "¥", int(price.(float64)) / 1000)
        }
 
-       fmt.Println("====")
+       fmt.Println("\n====")
        fmt.Println(sh...)
-       fmt.Println("====")
+       fmt.Println("====\n")
        msglog.I(sh...)
 
 }
@@ -198,9 +209,9 @@ func (replayF) send_gift(s string){
        //小于3万金瓜子
        if allprice < 30000 {msglog.T(sh...);return}
 
-       fmt.Println("====")
+       fmt.Println("\n====")
        fmt.Println(sh...)
-       fmt.Println("====")
+       fmt.Println("====\n")
        msglog.I(sh...)
 }
 
@@ -270,9 +281,9 @@ func (replayF) super_chat_message(s string){
        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...)
 }
 
@@ -345,7 +356,8 @@ func (replayF) danmu(s string) {
 
                //F附加方法
                Danmujif(msg, Msg_cookie, Msg_roomid)
-               if Autobanf(msg) > 0.5 {
+               if Autobanf(msg) {
+                       fmt.Println("风险", msg)
                        msglog.Base(1, "风险").I(msg)
                        return
                }
@@ -355,14 +367,15 @@ func (replayF) danmu(s string) {
                }
 
                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
index dc5fc3ebe7d4e89a0b0530c56d26cdc7894111ae..bf273e25b98836348aba3387be62ed726881c5c4 100644 (file)
@@ -6,6 +6,7 @@ import (
        "strconv"
        "os"
        "os/signal"
+       "compress/zlib"
 
        p "github.com/qydysky/part"
 )
@@ -116,22 +117,43 @@ const (
 
 //返回数据分派
 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
 }
 
 //头部生成与检查
@@ -147,29 +169,23 @@ func headGen(datalenght,Opeation,Sequence int) []byte {
        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,
+       }
 }
 
 //认证生成与检查