demo/demo.run
demo/ui/*.glade~
demo/tts.mp3
+demo/cpu.pprof
"bytes"
"strconv"
- p "github.com/qydysky/part"
c "github.com/qydysky/bili_danmu/CV"
)
-var flog = p.Logf().New().Open("danmu.log").Base(-1, "F.go")
+var flog = c.Log.Base(`F/F.go`)
//base on source/player-loader-2.0.7.min.js L3313
//base on source/player-loader-2.0.7.min.js L3455
func HeadChe(head []byte) (header) {
- if len(head) != c.WS_PACKAGE_HEADER_TOTAL_LENGTH {flog.Base(1, "头部检查").E("输入头长度错误");return header{}}
+ if len(head) != c.WS_PACKAGE_HEADER_TOTAL_LENGTH {flog.Base_add("头部检查").L(`E: `,"输入头长度错误");return header{}}
PackL := Btoi32(head, c.WS_PACKAGE_OFFSET)
HeadL := Btoi16(head, c.WS_HEADER_OFFSET)
//认证生成与检查
func HelloGen(roomid int, key string) []byte {
- flog.Base(-1, "认证生成")
- defer flog.Base(0)
+ flog := flog.Base_add("认证生成")
if roomid == 0 || key == "" {
- flog.E("roomid == 0 || key == \"\"")
+ flog.L(`E: `,"roomid == 0 || key == \"\"")
return []byte("")
}
func Ass_f(file string, st time.Time){
ass.file = file
if file == "" {return}
- p.Logf().New().Open("danmu.log").Base(1, "Ass").I("保存至", ass.file + ".ass")
+ c.Log.Base(`Ass`).L(`I: `,"保存至", ass.file + ".ass")
p.File().FileWR(p.Filel{
File:ass.file + ".ass",
if !IsOn("Saveflv") {return}
if saveflv.cancel.Islive() {return}
- l := p.Logf().New().Open("danmu.log").Base(-1, "saveflv")
+ l := c.Log.Base(`saveflv`)
cuLinkIndex := 0
api := F.New_api(c.Roomid)
}
{//重试
- l.I("尝试连接live")
+ l.L(`I: `,"尝试连接live")
if e := rr.Reqf(p.Rval{
Url:c.Live[cuLinkIndex],
Retry:10,
},
Timeout:5,
JustResponseCode:true,
- }); e != nil{l.W(e)}
+ }); e != nil{l.L(`W: `,e)}
if rr.Response == nil ||
rr.Response.StatusCode != 200 {
}
Ass_f(saveflv.path, time.Now())
- l.I("保存到", saveflv.path + ".flv")
+ l.L(`I: `,"保存到", saveflv.path + ".flv")
if e := rr.Reqf(p.Rval{
Url:c.Live[cuLinkIndex],
},
SaveToPath:saveflv.path + ".flv",
Timeout:-1,
- }); e != nil{l.W(e)}
+ }); e != nil{l.L(`W: `,e)}
- l.I("结束")
+ l.L(`I: `,"结束")
Ass_f("", time.Now())//ass
if !saveflv.cancel.Islive() {break}//cancel
/*
ffmpeg http://ffmpeg.org/download.html
*/
// if p.Checkfile().IsExist(saveflv.path+".flv"){
- // l.I("转码中")
+ // l.L(`I: `,"转码中")
// p.Exec().Run(false, "ffmpeg", "-i", saveflv.path+".flv", "-c", "copy", saveflv.path+".mkv")
// if p.Checkfile().IsExist(saveflv.path+".mkv"){os.Remove(saveflv.path+".flv")}
// }
- // l.I("转码结束")
+ // l.L(`I: `,"转码结束")
saveflv.wait.Done()
saveflv.cancel.Done()
}
func Saveflv_wait(){
if !IsOn("Saveflv") {return}
saveflv.cancel.Done()
- p.Logf().New().Open("danmu.log").Base(-1, "saveflv").I("等待").Block()
+ c.Log.Base(`saveflv`).L(`I: `,"等待")
saveflv.wait.Wait()
}
func Obsf(on bool){
if !IsOn("Obs") {return}
- l := p.Logf().New().Open("danmu.log").Base(1, "obs")
- defer l.BC()
+ l := c.Log.Base(`obs`)
if on {
- if p.Sys().CheckProgram("obs")[0] != 0 {l.W("obs已经启动");return}
+ if p.Sys().CheckProgram("obs")[0] != 0 {l.L(`W: `,"obs已经启动");return}
if p.Sys().CheckProgram("obs")[0] == 0 {
if obs.Prog == "" {
- l.E("未知的obs程序位置")
+ l.L(`E: `,"未知的obs程序位置")
return
}
- l.I("启动obs")
+ l.L(`I: `,"启动obs")
p.Exec().Start(exec.Command(obs.Prog))
p.Sys().Timeoutf(3)
}
// Connect a client.
if err := obs.c.Connect(); err != nil {
- l.E(err)
+ l.L(`E: `,err)
return
}
} else {
- if p.Sys().CheckProgram("obs")[0] == 0 {l.W("obs未启动");return}
+ if p.Sys().CheckProgram("obs")[0] == 0 {l.L(`W: `,"obs未启动");return}
obs.c.Disconnect()
}
}
func Obs_R(on bool){
if !IsOn("Obs") {return}
- l := p.Logf().New().Open("danmu.log").Base(1, "obs_R")
- defer l.BC()
+ l := c.Log.Base("obs_R")
if p.Sys().CheckProgram("obs")[0] == 0 {
- l.W("obs未启动")
+ l.L(`W: `,"obs未启动")
return
} else {
if err := obs.c.Connect(); err != nil {
- l.E(err)
+ l.L(`E: `,err)
return
}
}
if on {
req := obsws.NewStartRecordingRequest()
if err := req.Send(obs.c); err != nil {
- l.E(err)
+ l.L(`E: `,err)
return
}
resp, err := req.Receive()
if err != nil {
- l.E(err)
+ l.L(`E: `,err)
return
}
if resp.Status() == "ok" {
- l.I("开始录制")
+ l.L(`I: `,"开始录制")
}
} else {
req := obsws.NewStopRecordingRequest()
if err := req.Send(obs.c); err != nil {
- l.E(err)
+ l.L(`E: `,err)
return
}
resp, err := req.Receive()
if err != nil {
- l.E(err)
+ l.L(`E: `,err)
return
}
if resp.Status() == "ok" {
- l.I("停止录制")
+ l.L(`I: `,"停止录制")
}
p.Sys().Timeoutf(3)
}
if pt < 0.8 {return false}//ban字符重复低去除
res = append(res, pt)
}
- l := p.Logf().New().Open("danmu.log").Base(1, "autoban")
- l.W(res).Block()
+ l := c.Log.Base("autoban")
+ l.L(`W: `,res)
return true
}
}
type Autoskip struct {
- num int
- buf sync.Map
- bufbreak chan bool
+ buf map[string]Autoskip_item
+ now uint
+ ticker *time.Ticker
+}
+
+type Autoskip_item struct {
+ Exprie uint
+ Num uint
}
var autoskip = Autoskip{
- bufbreak:make(chan bool, 100),
+ buf:make(map[string]Autoskip_item),
+ ticker:time.NewTicker(time.Duration(2)*time.Second),
}
-func Autoskipf(s string, maxNum,muteSecond int) int {
- if !IsOn("Autoskip") || s == "" || maxNum <= 0 || muteSecond <= 0 {return 0}
- if v, ok := autoskip.buf.LoadOrStore(s, 0); ok {
- autoskip.buf.Store(s, v.(int) + 1)
- return v.(int) + 1
- }
-
- autoskip.num += 1
- if autoskip.num > maxNum {autoskip.bufbreak <- true}
-
+func init(){
go func(){
- select {
- case <- autoskip.bufbreak:
- case <- time.After(time.Duration(muteSecond)*time.Second):
- }
- autoskip.num -= 1
- i, ok := autoskip.buf.LoadAndDelete(s);
- if ok {//多人重复提示
- switch i.(int) {
- case 0,1:
- case 2,3:Msg_showdanmu(nil, strconv.Itoa(i.(int)) + " x " + s,`0default`)
- default:Msg_showdanmu(nil, strconv.Itoa(i.(int)) + " x " + s,`0multi`)
+ for {
+ <-autoskip.ticker.C
+ if len(autoskip.buf) == 0 {continue}
+ autoskip.now += 1
+ for k,v := range autoskip.buf{
+ if v.Exprie <= autoskip.now {
+ delete(autoskip.buf,k)
+ {//超时显示
+ if v.Num > 3 {
+ Msg_showdanmu(nil, strconv.Itoa(int(v.Num)) + " x " + k,`0multi`)
+ } else if v.Num > 1 {
+ Msg_showdanmu(nil, strconv.Itoa(int(v.Num)) + " x " + k,`0default`)
+ }
+ }
+ }
}
}
}()
+}
+
+func Autoskipf(s string) uint {
+ if !IsOn("Autoskip") || s == ""{return 0}
+ {//验证是否已经存在
+ if v,ok := autoskip.buf[s];ok && autoskip.now < v.Exprie{
+ autoskip.buf[s] = Autoskip_item{
+ Exprie:v.Exprie,
+ Num:v.Num+1,
+ }
+ return v.Num
+ }
+ }
+ {//设置
+ autoskip.buf[s] = Autoskip_item{
+ Exprie:autoskip.now + 8,
+ Num:1,
+ }
+ }
return 0
}
jiezou.Lock()
if now > 1.3 * jiezou.avg {//触发
- l := p.Logf().New().Open("danmu.log").Base(1, "jiezou")
- l.W("节奏注意", now, jiezou.avg, S).Block()
+ c.Log.Base("jiezou").L(`W: `,"节奏注意", now, jiezou.avg, S)
jiezou.avg = now //沉默
jiezou.Unlock()
//Msg类型数据处理方法map
var Msg_map = map[string]func(replyF, string) {
+ `ENTRY_EFFECT_MUST_RECEIVE`:nil,//高能榜前三进入
+ `GIFT_BAG_DOT`:nil,
`LITTLE_MESSAGE_BOX`:replyF.little_message_box,//小消息
`MESSAGEBOX_USER_MEDAL_CHANGE`:replyF.messagebox_user_medal_change,//粉丝牌切换
`HOT_RANK_SETTLEMENT`:replyF.hot_rank_settlement,//热门榜获得
msglog.Base_add("风险").L(`I: `, auth, ":", msg)
return
}
- if i := Autoskipf(msg, 50, 15); i > 0 {
+ if i := Autoskipf(msg); i > 0 {
msglog.L(`I: `, auth, ":", msg)
return
}
var (
Gtk_on bool
Gtk_img_path string = "face"
- Gtk_danmu_pool = make(map[string]string)
+ Gtk_danmu_pool_index uint
+ Gtk_danmu_pool = make(map[uint]Danmu_mq_t)
)
func init(){
//使用带tag的消息队列在功能间传递消息
Danmu_mq.Pull_tag(map[string]func(interface{})(bool){
`danmu`:func(data interface{})(bool){//弹幕
- Gtk_danmu_pool[data.(Danmu_mq_t).uid] = data.(Danmu_mq_t).msg
+ if int(Gtk_danmu_pool_index) - len(Gtk_danmu_pool) > 1e5 {Gtk_danmu_pool_index = 0}
+ Gtk_danmu_pool_index += 1
+ Gtk_danmu_pool[Gtk_danmu_pool_index] = data.(Danmu_mq_t)
return false
},
})
return
})
glib.TimeoutAdd(uint(1000 / (len(Gtk_danmu_pool) + 1)),func()(bool){
- for uid,msg := range Gtk_danmu_pool {
- delete(Gtk_danmu_pool,uid)
- y(msg,load_face(uid))
+ for id,item := range Gtk_danmu_pool {
+ delete(Gtk_danmu_pool,id)
+ y(item.msg,load_face(item.uid))
return true
}
return false
}
step := (max - cu) / 30
- if step > 20 {
+ if step > 20 || max > 5 * float64(h){//太长或太快
if i,e := grid0.GetChildAt(0,0); e != nil{i.(*gtk.Widget).Destroy()}
if i,e := grid0.GetChildAt(1,0); e != nil{i.(*gtk.Widget).Destroy()}
grid0.RemoveRow(0)
in_smooth_roll = false
tmp.SetValue(max)
loc := int(grid0.Container.GetChildren().Length())/2
- for v,ok := K_v[`gtk_保留弹幕数量`].(int);ok && loc > v;loc -= 1{
+ if v,ok := K_v[`gtk_保留弹幕数量`].(int);ok {
+ loc -= v
+ } else {
+ loc -= 25
+ }
+ for loc > 0 {
if i,e := grid0.GetChildAt(0,0); e != nil{i.(*gtk.Widget).Destroy()}
if i,e := grid0.GetChildAt(1,0); e != nil{i.(*gtk.Widget).Destroy()}
grid0.RemoveRow(0)
+ loc -= 1
}
}
old_cu = tmp.GetValue()
return
}
if v,ok := K_v[`gtk_头像获取等待最大数量`].(int);ok && len(gtkGetList) > v {return}
- //加入前先行检查
- if _,ok := gtkGetList[uid];ok {return}
-
gtkGetList[uid] = struct{}{}
return
}
\ No newline at end of file
--- /dev/null
+package part
+
+type ENTRY_EFFECT_MUST_RECEIVE struct {
+ Cmd string `json:"cmd"`
+ Data struct {
+ Id int `json:"id"`
+ Uid int `json:"uid"`
+ Target_id int `json:"target_id"`
+ Mock_effect int `json:"mock_effect"`
+ Face string `json:"face"`
+ Privilege_type int `json:"privilege_type"`
+ Copy_writing string `json:"copy_writing"`
+ Copy_color string `json:"copy_color"`
+ Highlight_color string `json:"highlight_color"`
+ Priority int `json:"priority"`
+ Basemap_url string `json:"basemap_url"`
+ Show_avatar int `json:"show_avatar"`
+ Effective_time int `json:"effective_time"`
+ Web_basemap_url string `json:"web_basemap_url"`
+ Web_effective_time int `json:"web_effective_time"`
+ Web_effect_close int `json:"web_effect_close"`
+ Web_close_time int `json:"web_close_time"`
+ Business int `json:"business"`
+ Copy_writing_v2 string `json:"copy_writing_v2"`
+ Icon_list []int `json:"icon_list"`
+ Max_delay_time int `json:"max_delay_time"`
+ } `json:"data"`
+}
+/*
+{
+ "cmd": "ENTRY_EFFECT_MUST_RECEIVE",
+ "data": {
+ "id": 136,
+ "uid": 29183321,
+ "target_id": 612524985,
+ "mock_effect": 0,
+ "face": "https://i2.hdslb.com/bfs/face/8c6d1ce3f96dc86d0fc7876a2824910c92ae6802.jpg",
+ "privilege_type": 0,
+ "copy_writing": "欢迎 \u003c%qydysky...%\u003e 进入直播间",
+ "copy_color": "#000000",
+ "highlight_color": "#FFF100",
+ "priority": 1,
+ "basemap_url": "https://i0.hdslb.com/bfs/live/mlive/586f12135b6002c522329904cf623d3f13c12d2c.png",
+ "show_avatar": 1,
+ "effective_time": 2,
+ "web_basemap_url": "https://i0.hdslb.com/bfs/live/mlive/586f12135b6002c522329904cf623d3f13c12d2c.png",
+ "web_effective_time": 2,
+ "web_effect_close": 0,
+ "web_close_time": 900,
+ "business": 3,
+ "copy_writing_v2": "欢迎 \u003c^icon^\u003e \u003c%qydysk…%\u003e 进入直播间",
+ "icon_list": [
+ 2
+ ],
+ "max_delay_time": 7
+ }
+}
+*/
\ No newline at end of file
"strings"
"strconv"
+ c "github.com/qydysky/bili_danmu/CV"
p "github.com/qydysky/part"
)
//等待令牌时阻塞,超时返回true
if danmu_s_limit.TO() {return}
- l := p.Logf().New().Base(-1, "弹幕发送").Level(1)
- defer l.Block()
+ l := c.Log.Base("弹幕发送")
if msg == "" || Cookie == "" || roomid == 0{
- l.E("输入参数不足")
+ l.L(`E: `,"输入参数不足")
return
}
if i := strings.Index(Cookie, "{"); i != -1 {
- l.E("Cookie格式错误,需为 key=val; key=val 式")
+ l.L(`E: `,"Cookie格式错误,需为 key=val; key=val 式")
return
}
var csrf string
if i := strings.Index(Cookie, "bili_jct="); i == -1 {
- l.E("Cookie错误,无bili_jct=")
+ l.L(`E: `,"Cookie错误,无bili_jct=")
return
} else {
if d := strings.Index(Cookie[i + 9:], ";"); d == -1 {
}
PostStr := `color=16777215&fontsize=25&mode=1&msg=` + msg + `&rnd=` + strconv.Itoa(int(p.Sys().GetSTime())) + `&roomid=` + strconv.Itoa(roomid) + `&bubble=0&csrf_token=` + csrf + `&csrf=` + csrf
- l.I("发送", msg, "至", roomid)
+ l.L(`I: `,"发送", msg, "至", roomid)
r := p.Req()
err := r.Reqf(p.Rval{
Url:"https://api.live.bilibili.com/msg/send",
},
})
if err != nil {
- l.E(err)
+ l.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)
+ l.L(`E: `,message)
} else {
- l.E(string(r.Respon))
+ l.L(`E: `,string(r.Respon))
}
return
}
"Ass": true,
"Obs": false,
"Autoban": false,
- "Jiezou": true,
+ "Jiezou": false,
"Danmuji": true,
"Danmuji_auto": false,
"Autoskip": true,
- "Lessdanmu": true,
+ "Lessdanmu": false,
"Moredanmu": false,
"Shortdanmu": true
}
\ No newline at end of file
"弹幕_礼物金额显示阈值":20,
"gtk":"GTK相关",
- "gtk_保留弹幕数量":50,
+ "gtk_保留弹幕数量":25,
"gtk_内存头像数量":100,
"gtk_头像获取等待最大数量":100
}
\ No newline at end of file
github.com/miekg/dns v1.1.35 // indirect
github.com/mitchellh/mapstructure v1.4.0 // indirect
github.com/qydysky/bili_danmu v0.5.7
- github.com/qydysky/part v0.3.5-0.20210113130821-3c354d18111a // indirect
+ github.com/qydysky/part v0.3.5-0.20210115055155-7961661607d9 // indirect
github.com/shirou/gopsutil v3.20.12+incompatible // indirect
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect
+ github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect
)
github.com/qydysky/part v0.3.5-0.20210110025721-48b2732f9fb8/go.mod h1:SxxNav0Z7DbsDLoG5uxo0wW5EKU/JBu2CAkZzZeLnX0=
github.com/qydysky/part v0.3.5-0.20210113130821-3c354d18111a h1:r+3GSv1/biomzrDSdJ0Sm7dXjDtdj2lqSUBT5FcqHcU=
github.com/qydysky/part v0.3.5-0.20210113130821-3c354d18111a/go.mod h1:zE9KPP+RD3EQ4wYL14szrB927AU3amyha/2wKPjPWzo=
+github.com/qydysky/part v0.3.5-0.20210115055155-7961661607d9 h1:itpSznD2XZeV6BJEkW85Qt0goh0b/YMtWXR7F7hA9EE=
+github.com/qydysky/part v0.3.5-0.20210115055155-7961661607d9/go.mod h1:zE9KPP+RD3EQ4wYL14szrB927AU3amyha/2wKPjPWzo=
github.com/qydysky/part/msgq v0.0.0-20201213031129-ca3253dc72ad h1:Jtzf509lQrkUMGTV0Sc6IDCAiR1VrBcHrIban7hpye4=
github.com/qydysky/part/msgq v0.0.0-20201213031129-ca3253dc72ad/go.mod h1:w32TkJNVtTJd4LOS09cq+4uYG6itcN2vsqw+slp44Rg=
github.com/qydysky/part/msgq v0.0.0-20201213120821-f36e49c32bba h1:1ew9dRpc0Rux0WkWeT/4AE15ynYWmL2D7onJEJIFOB8=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
+github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
+github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
package main
import (
+ // "time"
+ // "runtime/pprof"
+ // "os"
+ // "log"
// "net/http"
+ // "fmt"
// _ "net/http/pprof"
+ // "github.com/skratchdot/open-golang/open"
q "github.com/qydysky/bili_danmu"
)
// go func() {
// http.ListenAndServe("0.0.0.0:8899", nil)
// }()
+ // defer func(){
+ // open.Run("http://127.0.0.1:8899/debug/pprof/goroutine?debug=2")
+ // time.Sleep(time.Duration(3)*time.Second)
+ // }()
+ // go func(){
+ // // var memStats_old runtime.MemStats
+ // for{
+ // time.Sleep(time.Duration(10)*time.Second)
+ // var memStats runtime.MemStats
+ // runtime.ReadMemStats(&memStats)
+ // fmt.Printf("=====\n")
+ // // fmt.Printf("总内存:%v MB\n",memStats.Sys/1024e2/8)
+ // fmt.Printf("GC次数:%v \n",memStats.NumGC)
+
+ // fmt.Printf("堆 :%v %v MB\n",memStats.HeapInuse/1024e2/8,(memStats.HeapIdle - memStats.HeapReleased)/1024e2/8)
+
+ // fmt.Printf("栈 :%v/%v MB\n",memStats.StackInuse/1024e2/8,memStats.StackSys/1024e2/8)
+ // fmt.Printf("=====\n")
+ // // memStats_old = memStats
+ // }
+ // }()
+ // f, err := os.OpenFile("cpu.pprof", os.O_RDWR|os.O_CREATE, 0644)
+ // if err != nil {
+ // log.Fatal(err)
+ // }
+ // defer f.Close()
+ // pprof.StartCPUProfile(f)
+
q.Demo()
+
+ // pprof.StopCPUProfile()
}
\ No newline at end of file