- [x] cookie加密
- [x] 弹幕自动重连(30s无响应)
- [x] 直播流开播自动下载、断流再保存、故障转移、移除历史
-- [x] ~~多房间直播流保存~~
+- [x] 指定弹幕、标题切换重启录制
- [x] 命令行支持房间切换、弹幕发送、表情发送、启停录制、重载弹幕、查看历史记录、查看正在直播的主播
- [x] GTK信息窗支持房间切换、弹幕格式化发送、时长统计
- [x] GTK弹幕窗支持自定义人/事件消息停留
前往[releases](https://github.com/qydysky/bili_danmu/releases)页下载对应系统版本。解压后进入`demo`目录(文件夹),运行`demo.run`(`demo.exe`)。
```
-./demo.run [-r 房间ID]
+./demo.run [-r 房间ID] [-ckv 自定义config_K_v.json]
+./demo.exe [-r 房间ID] [-ckv 自定义config_K_v.json]
```
#### 注意事项
"strconv"
"strings"
"sync"
+ "sync/atomic"
"time"
// "runtime"
func (t *Communicate) Store(k interface{}) {
t.Buf.Store(k, nil)
}
+
+// 指定弹幕重启录制
+var danmuReLiveTriger DanmuReLiveTriger
+
+type DanmuReLiveTriger struct {
+ l map[string]struct{}
+ reload atomic.Bool
+ init sync.Once
+}
+
+func (t *DanmuReLiveTriger) Init(c *c.Common) {
+ t.init.Do(func() {
+ t.l = make(map[string]struct{})
+ if v, ok := c.K_v.LoadV(`指定弹幕重启录制`).([]any); ok && len(v) > 0 {
+ for i := 0; i < len(v); i++ {
+ var item = v[i].(map[string]any)
+ var uid = strings.TrimSpace(item["uid"].(string))
+ var danmu = strings.TrimSpace(item["danmu"].(string))
+ if uid != "" && danmu != "" {
+ t.l[uid+" "+danmu] = struct{}{}
+ }
+ }
+ }
+ })
+}
+
+func (t *DanmuReLiveTriger) Check(uid, msg string) {
+ if _, ok := t.l[uid+" "+msg]; ok {
+ if t.reload.CompareAndSwap(false, true) {
+ flog.Base_add("指定弹幕重启录制").L(`I: `, uid, msg, "请求重启录制")
+ go func() {
+ if v, ok := c.C.K_v.LoadV(`仅保存当前直播间流`).(bool); ok && v {
+ StreamOStop(c.C.Roomid) //停止其他房间录制
+ }
+ StreamOStart(c.C.Roomid)
+ time.Sleep(time.Minute)
+ t.reload.Store(false)
+ }()
+ }
+ }
+}
"仅保存当前直播间流-help": "启用此项,才会保存Ass",
"仅保存当前直播间流": true,
"修改标题时重新录制": true,
+ "指定弹幕重启录制-help":"接收到特定uid的danmu将进行重新录制, uid或danmu为空无效,触发后有1分钟冷却",
+ "指定弹幕重启录制":[
+ {
+ "uid":"",
+ "danmu":""
+ }
+ ],
"Web服务地址-help":"填写本程序各组件所用的服务地址 例0.0.0.0:10000 为空时不启动Web服务",
"Web服务地址":"0.0.0.0:10000",
"直播Web服务路径":"/web/",