]> 127.0.0.1 Git - bili_danmu/.git/commitdiff
Improve 独立Common
authorqydysky <qydysky@foxmail.com>
Mon, 8 Jul 2024 18:23:58 +0000 (18:23 +0000)
committerqydysky <qydysky@foxmail.com>
Mon, 8 Jul 2024 18:23:58 +0000 (18:23 +0000)
CV/Var.go
F/api.go
Reply/F.go
Reply/Reply.go
Reply/stream.go
Send/Send_gift.go
bili_danmu.go
cmd/cmd.go
go.mod
go.sum

index 9ac13f0a1f16c1b84f942fa401f8c08e4ebb0a3d..d8535bd88224ebbf91df3d08455fb3c78e26e9f4 100644 (file)
--- a/CV/Var.go
+++ b/CV/Var.go
@@ -43,37 +43,38 @@ type StreamType struct {
 }
 
 type Common struct {
-       PID               int            `json:"pid"`           //进程id
-       Version           string         `json:"version"`       //版本
-       Uid               int            `json:"-"`             //client uid
-       Live              []*LiveQn      `json:"live"`          //直播流链接
-       Live_qn           int            `json:"liveQn"`        //当前直播流质量
-       Live_want_qn      int            `json:"-"`             //期望直播流质量
-       Roomid            int            `json:"roomid"`        //房间ID
-       Cookie            syncmap.Map    `json:"-"`             //Cookie
-       Title             string         `json:"title"`         //直播标题
-       Uname             string         `json:"uname"`         //主播名
-       UpUid             int            `json:"upUid"`         //主播uid
-       Rev               float64        `json:"rev"`           //营收
-       Renqi             int            `json:"renqi"`         //人气
-       Watched           int            `json:"watched"`       //观看人数
-       OnlineNum         int            `json:"onlineNum"`     //在线人数
-       GuardNum          int            `json:"guardNum"`      //舰长数
-       ParentAreaID      int            `json:"parentAreaID"`  //父分区
-       AreaID            int            `json:"areaID"`        //子分区
-       Locked            bool           `json:"locked"`        //直播间封禁
-       Note              string         `json:"note"`          //分区排行
-       Live_Start_Time   time.Time      `json:"liveStartTime"` //直播开始时间
-       Liveing           bool           `json:"liveing"`       //是否在直播
-       Wearing_FansMedal int            `json:"-"`             //当前佩戴的粉丝牌
-       Token             string         `json:"-"`             //弹幕钥
-       WSURL             []string       `json:"-"`             //弹幕链接
-       LiveBuvidUpdated  time.Time      `json:"-"`             //LIVE_BUVID更新时间
-       Stream_url        *url.URL       `json:"-"`             //直播Web服务
-       Proxy             string         `json:"-"`             //全局代理
-       SerLocation       int            `json:"-"`             //服务器时区
-       AcceptQn          map[int]string `json:"-"`             //允许的直播流质量
-       Qn                map[int]string `json:"-"`             //全部直播流质量
+       InIdle            bool           `json:"-"`                //闲置中?
+       PID               int            `json:"-"`                //进程id
+       Version           string         `json:"-"`                //版本
+       Uid               int            `json:"-"`                //client uid
+       Live              []*LiveQn      `json:"live"`             //直播流链接
+       Live_qn           int            `json:"liveQn"`           //当前直播流质量
+       Live_want_qn      int            `json:"-"`                //期望直播流质量
+       Roomid            int            `json:"-"`                //房间ID
+       Cookie            syncmap.Map    `json:"-"`                //Cookie
+       Title             string         `json:"title"`            //直播标题
+       Uname             string         `json:"uname"`            //主播名
+       UpUid             int            `json:"upUid"`            //主播uid
+       Rev               float64        `json:"rev"`              //营收
+       Renqi             int            `json:"renqi"`            //人气
+       Watched           int            `json:"watched"`          //观看人数
+       OnlineNum         int            `json:"onlineNum"`        //在线人数
+       GuardNum          int            `json:"guardNum"`         //舰长数
+       ParentAreaID      int            `json:"parentAreaID"`     //父分区
+       AreaID            int            `json:"areaID"`           //子分区
+       Locked            bool           `json:"locked"`           //直播间封禁
+       Note              string         `json:"note"`             //分区排行
+       Live_Start_Time   time.Time      `json:"-"`                //直播开始时间
+       Liveing           bool           `json:"liveing"`          //是否在直播
+       Wearing_FansMedal int            `json:"WearingFansMedal"` //当前佩戴的粉丝牌
+       Token             string         `json:"-"`                //弹幕钥
+       WSURL             []string       `json:"-"`                //弹幕链接
+       LiveBuvidUpdated  time.Time      `json:"-"`                //LIVE_BUVID更新时间
+       Stream_url        *url.URL       `json:"-"`                //直播Web服务
+       Proxy             string         `json:"-"`                //全局代理
+       SerLocation       int            `json:"-"`                //服务器时区
+       AcceptQn          map[int]string `json:"-"`                //允许的直播流质量
+       Qn                map[int]string `json:"-"`                //全部直播流质量
        // StreamType        StreamType            `json:"streamType"`    //当前直播流类型
        AllStreamType map[string]StreamType            `json:"-"` //直播流类型
        K_v           syncmap.Map                      `json:"-"` //配置文件
@@ -86,6 +87,40 @@ type Common struct {
        Cache         syncmap.MapExceeded[string, any] `json:"-"` //缓存
 }
 
+func (t *Common) MarshalJSON() ([]byte, error) {
+       return json.Marshal(struct {
+               Live          []*LiveQn
+               LiveQn        int
+               Title         string
+               Uname         string
+               UpUid         int
+               Rev           float64
+               Watched       int
+               OnlineNum     int
+               GuardNum      int
+               ParentAreaID  int
+               AreaID        int
+               Locked        bool
+               Note          string
+               LiveStartTime string
+       }{
+               Live:          append([]*LiveQn{}, t.Live...),
+               LiveQn:        t.Live_qn,
+               Title:         t.Title,
+               Uname:         t.Uname,
+               UpUid:         t.UpUid,
+               Rev:           t.Rev,
+               Watched:       t.Watched,
+               OnlineNum:     t.OnlineNum,
+               GuardNum:      t.GuardNum,
+               ParentAreaID:  t.ParentAreaID,
+               AreaID:        t.AreaID,
+               Locked:        t.Locked,
+               Note:          t.Note,
+               LiveStartTime: t.Live_Start_Time.Format(time.DateTime),
+       })
+}
+
 type LiveQn struct {
        Url          string `json:"-"`
        Uuid         string `json:"-"`
@@ -156,6 +191,7 @@ func (t *Common) IsOn(key string) bool {
 
 func (t *Common) Copy() *Common {
        var c = Common{
+               InIdle:            t.InIdle,
                PID:               t.PID,
                Version:           t.Version,
                Uid:               t.Uid,
@@ -440,7 +476,10 @@ func (t *Common) Init() *Common {
 
                                streams := make(map[int]any)
 
-                               StreamO.Range(func(key, value any) bool {
+                               Commons.Range(func(key, value any) bool {
+                                       if common, ok := value.(*Common); ok && common.InIdle {
+                                               return true
+                                       }
                                        streams[key.(int)] = value
                                        return true
                                })
@@ -624,6 +663,12 @@ var C = new(Common).Init()
 // fmp4
 // https://datatracker.ietf.org/doc/html/draft-pantos-http-live-streaming
 var StreamO = new(sync.Map)
+var Commons = new(syncmap.Map)
+var CommonsLoadOrStore = syncmap.LoadOrStoreFunc[Common]{
+       Init: func() *Common {
+               return C.Copy()
+       },
+}
 
 // 消息队列
 type Danmu_Main_mq_item struct {
index aa284e3843f4358682f1680bea9e5636acb11822..42a99611418c22c1c3e3df660152a66cfceee0fa 100644 (file)
--- a/F/api.go
+++ b/F/api.go
@@ -292,6 +292,18 @@ func (t *GetFunc) Get(key string) {
        }
 }
 
+// 房间实际id
+func GetRoomRealId(roomid int) int {
+       if err, res := biliApi.GetRoomBaseInfo(roomid); err == nil {
+               return res.RoomID
+       } else if err, res := biliApi.GetInfoByRoom(roomid); err == nil {
+               return res.RoomID
+       } else {
+               apilog.Base_add(`房间实际id`).L(`E: `, err)
+               return roomid
+       }
+}
+
 func (t *GetFunc) GetUid() (missKey []string) {
        if uid, ok := t.Cookie.LoadV(`DedeUserID`).(string); !ok { //cookie中无DedeUserID
                missKey = append(missKey, `Cookie`)
index b91b5de28615a75338aa61e35bc2574e908d4cdf..50b2f67058a89735975d1da24b4659399a6d2184 100644 (file)
@@ -37,6 +37,7 @@ import (
        p "github.com/qydysky/part"
        pctx "github.com/qydysky/part/ctx"
        file "github.com/qydysky/part/file"
+       fctrl "github.com/qydysky/part/funcCtrl"
        pio "github.com/qydysky/part/io"
        limit "github.com/qydysky/part/limit"
        msgq "github.com/qydysky/part/msgq"
@@ -354,19 +355,19 @@ func StreamOStop(roomid int) {
 }
 
 // 实例切断
-func StreamOCut(roomid int) (setTitle func(string)) {
+func StreamOCut(roomid int) (setTitle func(title ...string)) {
        if v, ok := c.StreamO.Load(roomid); ok {
                if !pctx.Done(v.(*M4SStream).Status) {
                        v.(*M4SStream).Cut()
                        flog.L(`I: `, `已切片 `+strconv.Itoa(roomid))
-                       return func(title string) {
-                               if title != "" {
-                                       v.(*M4SStream).Common().Title = title
+                       return func(title ...string) {
+                               if len(title) > 0 {
+                                       v.(*M4SStream).Common().Title = title[0]
                                }
                        }
                }
        }
-       return func(s string) {}
+       return func(s ...string) {}
 }
 
 // type Obs struct {
@@ -967,37 +968,45 @@ func (t *saveToJson) Close() {
 var SaveToJson saveToJson
 
 // 进入房间发送弹幕
-func Entry_danmu() {
+func Entry_danmu(common *c.Common) {
        flog := flog.Base_add(`进房弹幕`)
 
        //检查与切换粉丝牌,只在cookie存在时启用
-       F.Get(c.C).Get(`CheckSwitch_FansMedal`)
+       F.Get(common).Get(`CheckSwitch_FansMedal`)
 
-       if v, _ := c.C.K_v.LoadV(`进房弹幕_有粉丝牌时才发`).(bool); v && c.C.Wearing_FansMedal == 0 {
+       if v, _ := common.K_v.LoadV(`进房弹幕_有粉丝牌时才发`).(bool); v && common.Wearing_FansMedal == 0 {
                flog.L(`T: `, `无粉丝牌`)
                return
        }
-       if v, _ := c.C.K_v.LoadV(`进房弹幕_仅发首日弹幕`).(bool); v {
-               res := F.Get_weared_medal(c.C.Uid, c.C.UpUid)
+       if v, _ := common.K_v.LoadV(`进房弹幕_仅发首日弹幕`).(bool); v {
+               res := F.Get_weared_medal(common.Uid, common.UpUid)
                if res.TodayIntimacy > 0 {
                        flog.L(`T: `, `今日已发弹幕`)
                        return
                }
        }
-       if array, ok := c.C.K_v.LoadV(`进房弹幕_内容`).([]interface{}); ok && len(array) != 0 {
+       if array, ok := common.K_v.LoadV(`进房弹幕_内容`).([]interface{}); ok && len(array) != 0 {
                rand := p.Rand().MixRandom(0, int64(len(array)-1))
-               send.Danmu_s(array[rand].(string), c.C.Roomid)
+               send.Danmu_s(array[rand].(string), common.Roomid)
        }
 }
 
+var fc_Keep_medal_light fctrl.SkipFunc
+
 // 保持所有牌子点亮
-func Keep_medal_light() {
-       if v, _ := c.C.K_v.LoadV(`保持牌子亮着`).(bool); !v {
+func Keep_medal_light(common *c.Common) {
+       if fc_Keep_medal_light.NeedSkip() {
+               return
+       } else {
+               defer fc_Keep_medal_light.UnSet()
+       }
+
+       if v, _ := common.K_v.LoadV(`保持牌子亮着`).(bool); !v {
                return
        }
        flog := flog.Base_add(`保持亮牌`)
 
-       array, ok := c.C.K_v.LoadV(`进房弹幕_内容`).([]interface{})
+       array, ok := common.K_v.LoadV(`进房弹幕_内容`).([]interface{})
        if !ok || len(array) == 0 {
                flog.L(`I: `, `进房弹幕_内容 为 空,退出`)
                return
@@ -1065,20 +1074,28 @@ func Keep_medal_light() {
        }
 }
 
+var fc_AutoSend_silver_gift fctrl.SkipFunc
+
 // 自动发送即将过期的银瓜子礼物
-func AutoSend_silver_gift() {
-       day, _ := c.C.K_v.LoadV(`发送还有几天过期的礼物`).(float64)
+func AutoSend_silver_gift(common *c.Common) {
+       if fc_AutoSend_silver_gift.NeedSkip() {
+               return
+       } else {
+               defer fc_AutoSend_silver_gift.UnSet()
+       }
+
+       day, _ := common.K_v.LoadV(`发送还有几天过期的礼物`).(float64)
        if day <= 0 {
                return
        }
 
-       if c.C.UpUid == 0 {
-               F.Get(c.C).Get(`UpUid`)
+       if common.UpUid == 0 {
+               F.Get(common).Get(`UpUid`)
        }
 
        for _, v := range F.Gift_list() {
                if time.Now().Add(time.Hour*time.Duration(24*int(day))).Unix() > int64(v.Expire_at) {
-                       send.Send_gift(v.Gift_id, v.Bag_id, v.Gift_num)
+                       send.Send_gift(common, v.Gift_id, v.Bag_id, v.Gift_num)
                }
        }
 
index adbcc51592e1fba9552837443d78302bf4ab5814..0f670f15bb68419f87922f7b86449e403cb3b66b 100644 (file)
@@ -360,7 +360,13 @@ func (t replyF) user_toast_msg(s string) {
        }
        if price != 0 {
                sh_log = append(sh, "¥", price/1000) //不在界面显示价格
-               t.Common.Danmu_Main_mq.Push_tag(`c.Rev_add`, float64(price)/1000)
+               t.Common.Danmu_Main_mq.Push_tag(`c.Rev_add`, struct {
+                       Roomid int
+                       Rev    float64
+               }{
+                       Roomid: t.Roomid,
+                       Rev:    float64(price) / 1000,
+               })
        }
        { //语言tts
                t.Common.Danmu_Main_mq.Push_tag(`tts`, Danmu_mq_t{ //传入消息队列
@@ -417,7 +423,13 @@ func (t replyF) heartbeat(s int) {
        if v, ok := t.Common.K_v.LoadV("下播后不记录人气观看人数").(bool); ok && v && !t.Common.Liveing {
                return
        }
-       t.Common.Danmu_Main_mq.Push_tag(`c.Renqi`, s) //使用连续付费的新舰长无法区分,刷新舰长数
+       t.Common.Danmu_Main_mq.Push_tag(`c.Renqi`, struct {
+               Roomid int
+               Renqi  int
+       }{
+               Roomid: t.Roomid,
+               Renqi:  s,
+       }) //使用连续付费的新舰长无法区分,刷新舰长数
        if s == 1 {
                return
        } //人气为1,不输出
@@ -505,6 +517,7 @@ func (t replyF) watched_change(s string) {
        if data.Data.Num == t.Common.Watched {
                return
        }
+       // fmt.Printf("\t观看人数:%d\n", data.Data.Num)
        t.Common.Watched = data.Data.Num
        var pperm = float64(t.Common.Watched) / float64(time.Since(t.Common.Live_Start_Time)/time.Minute)
        msglog.Base_add("房").Log_show_control(false).L(`I: `, "观看人数", data.Data.Num, fmt.Sprintf(" avg:%.1f人/分", pperm))
@@ -756,7 +769,13 @@ func (t replyF) send_gift(s string) {
        if total_coin != 0 {
                allprice = float64(total_coin) / 1000
                sh_log = append(sh, fmt.Sprintf("¥%.1f", allprice)) //不在界面显示价格
-               t.Common.Danmu_Main_mq.Push_tag(`c.Rev_add`, allprice)
+               t.Common.Danmu_Main_mq.Push_tag(`c.Rev_add`, struct {
+                       Roomid int
+                       Rev    float64
+               }{
+                       Roomid: t.Roomid,
+                       Rev:    allprice,
+               })
        }
 
        if len(sh) == 0 {
@@ -916,7 +935,13 @@ func (t replyF) super_chat_message(s string) {
        if price != 0 {
                sh = append(sh, "\n") //界面不显示价格
                logg = append(logg, "¥", price)
-               t.Common.Danmu_Main_mq.Push_tag(`c.Rev_add`, float64(price))
+               t.Common.Danmu_Main_mq.Push_tag(`c.Rev_add`, struct {
+                       Roomid int
+                       Rev    float64
+               }{
+                       Roomid: t.Roomid,
+                       Rev:    float64(price),
+               })
        }
        fmt.Println("====")
        fmt.Println(sh...)
index 71b8fe7b03e0c7c94e8692619cccc304c606281d..18633b69a581632928529e0691630818d72cade5 100644 (file)
@@ -178,8 +178,6 @@ func (link *m4s_link_item) download(reqPool *pool.Buf[reqf.Req], reqConfig reqf.
 }
 
 func (t *M4SStream) MarshalJSON() ([]byte, error) {
-       t.common.Rev = c.C.Rev
-       t.common.Watched = c.C.Watched
        return json.MarshalIndent(t.common, "", "    ")
 }
 
index a2cb3fa552945696eab4f66f3c2c623d35e0497d..a540170002662df9cc87b8c681f30bb5dfd04c43 100644 (file)
@@ -16,40 +16,40 @@ import (
 // 每2s一个令牌,最多等10秒
 var gift_limit = limit.New(1, "2s", "10s")
 
-func Send_gift(gift_id, bag_id, gift_num int) {
-       log := c.C.Log.Base_add(`发送礼物`)
+func Send_gift(common *c.Common, gift_id, bag_id, gift_num int) {
+       log := common.Log.Base_add(`发送礼物`)
 
        if gift_limit.TO() {
                log.L(`W: `, "超时")
                return
        }
 
-       if c.C.UpUid == 0 {
+       if common.UpUid == 0 {
                log.L(`W: `, "还未获取到Up主uid")
                return
        }
 
-       if c.C.Locked {
+       if common.Locked {
                log.L(`W: `, "房间被封禁")
                return
        }
 
        { //发送请求(银瓜子礼物)
-               csrf, _ := c.C.Cookie.LoadV(`bili_jct`).(string)
+               csrf, _ := common.Cookie.LoadV(`bili_jct`).(string)
                if csrf == `` {
                        log.L(`E: `, "Cookie错误,无bili_jct=")
                        return
                }
 
-               var sendStr = `uid=` + strconv.Itoa(c.C.Uid) + `&` +
+               var sendStr = `uid=` + strconv.Itoa(common.Uid) + `&` +
                        `gift_id=` + strconv.Itoa(gift_id) + `&` +
-                       `ruid=` + strconv.Itoa(c.C.UpUid) + `&` +
+                       `ruid=` + strconv.Itoa(common.UpUid) + `&` +
                        `send_ruid=0&` +
                        `gift_num=` + strconv.Itoa(gift_num) + `&` +
                        `bag_id=` + strconv.Itoa(bag_id) + `&` +
                        `platform=pc&` +
                        `biz_code=live&` +
-                       `biz_id=` + strconv.Itoa(c.C.Roomid) + `&` +
+                       `biz_id=` + strconv.Itoa(common.Roomid) + `&` +
                        `rnd=` + strconv.Itoa(int(time.Now().Unix())) + `&` +
                        `storm_beat_id=0&` +
                        `metadata=&` +
@@ -59,18 +59,18 @@ func Send_gift(gift_id, bag_id, gift_num int) {
                        `visit_id=`
 
                Cookie := make(map[string]string)
-               c.C.Cookie.Range(func(k, v interface{}) bool {
+               common.Cookie.Range(func(k, v interface{}) bool {
                        Cookie[k.(string)] = v.(string)
                        return true
                })
 
-               req := c.C.ReqPool.Get()
-               defer c.C.ReqPool.Put(req)
+               req := common.ReqPool.Get()
+               defer common.ReqPool.Put(req)
                if e := req.Reqf(reqf.Rval{
                        Url:     `https://api.live.bilibili.com/xlive/revenue/v2/gift/sendBag`,
                        PostStr: url.PathEscape(sendStr),
                        Timeout: 10 * 1000,
-                       Proxy:   c.C.Proxy,
+                       Proxy:   common.Proxy,
                        Header: map[string]string{
                                `Host`:            `api.vc.bilibili.com`,
                                `User-Agent`:      c.UA,
@@ -102,7 +102,7 @@ func Send_gift(gift_id, bag_id, gift_num int) {
                        return
                }
                for i := 0; i < len(res.Data.GiftList); i++ {
-                       log.L(`I: `, `给`, c.C.Roomid, `赠送了`, res.Data.GiftList[i].GiftNum, `个`, res.Data.GiftList[i].GiftName)
+                       log.L(`I: `, `给`, common.Roomid, `赠送了`, res.Data.GiftList[i].GiftNum, `个`, res.Data.GiftList[i].GiftName)
                }
        }
 }
index 2026f821a69d3671b88ab73af8a8c45e45048b90..ba47c951453aa6817b619ad90febe55f85ea876b 100644 (file)
@@ -20,6 +20,7 @@ import (
        send "github.com/qydysky/bili_danmu/Send"
        Cmd "github.com/qydysky/bili_danmu/cmd"
        pctx "github.com/qydysky/part/ctx"
+       part "github.com/qydysky/part/log"
        sys "github.com/qydysky/part/sys"
 
        msgq "github.com/qydysky/part/msgq"
@@ -112,7 +113,7 @@ func Start() {
                // 指定弹幕重启录制
                if _, err := danmuReLiveTriger.Init.Run(mainCtx, danmuReLiveTriger.DanmuReLiveTriger{
                        StreamCut: func(i int, title ...string) {
-                               reply.StreamOCut(i)(title[0])
+                               reply.StreamOCut(i)(title...)
                        },
                        C: c.C,
                }); err != nil {
@@ -128,25 +129,39 @@ func Start() {
                //使用带tag的消息队列在功能间传递消息
                {
                        var cancelfunc = c.C.Danmu_Main_mq.Pull_tag(msgq.FuncMap{
-                               `change_room`: func(_ any) bool { //房间改变
-                                       c.C.Rev = 0.0     // 营收
-                                       c.C.Renqi = 1     // 人气置1
-                                       c.C.Watched = 0   // 观看人数
-                                       c.C.OnlineNum = 0 // 在线人数
-                                       c.C.GuardNum = 0  // 舰长数
-                                       c.C.Note = ``     // 分区排行
-                                       c.C.Uname = ``    // 主播id
-                                       c.C.Title = ``
-                                       c.C.Wearing_FansMedal = 0
-                                       return false
-                               },
+                               // `change_room`: func(_ any) bool { //房间改变
+                               //      c.C.Rev = 0.0     // 营收
+                               //      c.C.Renqi = 1     // 人气置1
+                               //      c.C.Watched = 0   // 观看人数
+                               //      c.C.OnlineNum = 0 // 在线人数
+                               //      c.C.GuardNum = 0  // 舰长数
+                               //      c.C.Note = ``     // 分区排行
+                               //      c.C.Uname = ``    // 主播id
+                               //      c.C.Title = ``
+                               //      c.C.Wearing_FansMedal = 0
+                               //      return false
+                               // },
                                `c.Rev_add`: func(data any) bool { //收入
-                                       c.C.Rev += data.(float64)
+                                       if rev, ok := data.(struct {
+                                               Roomid int
+                                               Rev    float64
+                                       }); ok {
+                                               common, ok := c.Commons.LoadV(c.C.Roomid).(*c.Common)
+                                               if ok {
+                                                       common.Rev += rev.Rev
+                                               }
+                                       }
                                        return false
                                },
                                `c.Renqi`: func(data any) bool { //人气更新
-                                       if tmp, ok := data.(int); ok {
-                                               c.C.Renqi = tmp
+                                       if tmp, ok := data.(struct {
+                                               Roomid int
+                                               Renqi  int
+                                       }); ok {
+                                               common, ok := c.Commons.LoadV(c.C.Roomid).(*c.Common)
+                                               if ok {
+                                                       common.Renqi = tmp.Renqi
+                                               }
                                        }
                                        return false
                                },
@@ -167,22 +182,20 @@ func Start() {
                }
 
                for exitSign := false; !exitSign; {
-                       common := c.C.Copy()
-
-                       if common.Roomid == 0 {
+                       if c.C.Roomid == 0 {
                                fmt.Println("回车查看指令")
                                ctx, cancel := context.WithCancel(mainCtx)
-                               cancel1, c := common.Danmu_Main_mq.Pull_tag_chan(`change_room`, 1, ctx)
+                               cancel1, ch := c.C.Danmu_Main_mq.Pull_tag_chan(`change_room`, 1, ctx)
                                select {
-                               case roomid := <-c:
-                                       common.Roomid = roomid.(int)
+                               case roomid := <-ch:
+                                       c.C.Roomid = roomid.(int)
                                case <-interrupt_chan:
                                        exitSign = true
                                }
                                cancel1()
                                cancel()
                        } else {
-                               fmt.Print("房间号: ", strconv.Itoa(common.Roomid), "\n")
+                               fmt.Print("房间号: ", strconv.Itoa(c.C.Roomid), "\n")
                        }
 
                        if exitSign {
@@ -190,234 +203,255 @@ func Start() {
                        }
 
                        danmulog.L(`T: `, "准备")
+
                        //如果连接中断,则等待
                        F.KeepConnect()
-                       //附加功能 保持牌子点亮
-                       go reply.Keep_medal_light()
-                       //附加功能 自动发送即将过期礼物
-                       go reply.AutoSend_silver_gift()
-                       //获取热门榜
-                       F.Get(common).Get(`Note`)
-
-                       danmulog.L(`I: `, "连接到房间", common.Roomid)
-
-                       Cookie := make(map[string]string)
-                       common.Cookie.Range(func(k, v any) bool {
-                               Cookie[k.(string)] = v.(string)
-                               return true
-                       })
 
-                       // 检查与切换粉丝牌,只在cookie存在时启用
-                       F.Get(common).Get(`CheckSwitch_FansMedal`)
-
-                       // 对每个弹幕服务器尝试
-                       F.Get(common).Get(`WSURL`)
-                       aliveT := time.Now().Add(3 * time.Hour)
-                       for i, exitloop := 0, false; !exitloop && i < len(common.WSURL) && time.Now().Before(aliveT); {
-                               v := common.WSURL[i]
-                               //ws启动
-                               danmulog.L(`T: `, "连接 "+v)
-                               u, _ := url.Parse(v)
-                               ws_c, err := ws.New_client(&ws.Client{
-                                       Url:               v,
-                                       TO:                35 * 1000,
-                                       Proxy:             common.Proxy,
-                                       Func_abort_close:  func() { danmulog.L(`I: `, `服务器连接中断`) },
-                                       Func_normal_close: func() { danmulog.L(`I: `, `服务器连接关闭`) },
-                                       Header: map[string]string{
-                                               `Cookie`:          reqf.Map_2_Cookies_String(Cookie),
-                                               `Host`:            u.Hostname(),
-                                               `User-Agent`:      c.UA,
-                                               `Accept`:          `*/*`,
-                                               `Accept-Language`: `zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2`,
-                                               `Origin`:          `https://live.bilibili.com`,
-                                               `Pragma`:          `no-cache`,
-                                               `Cache-Control`:   `no-cache`,
-                                       },
-                               })
-                               if err != nil {
-                                       danmulog.L(`E: `, "连接错误", err)
-                                       i += 1
-                                       continue
-                               }
-                               wsmsg, err := ws_c.Handle()
-                               if err != nil {
-                                       danmulog.L(`E: `, "连接错误", err)
-                                       i += 1
-                                       continue
-                               }
-                               if ws_c.Isclose() {
-                                       danmulog.L(`E: `, "连接错误", ws_c.Error())
-                                       i += 1
-                                       continue
-                               }
+                       // 获取房间实际id
+                       c.C.Roomid = F.GetRoomRealId(c.C.Roomid)
 
-                               // auth
-                               {
-                                       wsmsg.PushLock_tag(`send`, &ws.WsMsg{
-                                               Msg: F.HelloGen(common.Roomid, common.Token),
-                                       })
-                                       waitCheckAuth, cancel := context.WithTimeout(mainCtx, 5*time.Second)
-                                       doneAuth := wsmsg.Pull_tag_only(`rec`, func(wm *ws.WsMsg) (disable bool) {
-                                               if F.HelloChe(wm.Msg) {
-                                                       cancel()
-                                               }
-                                               return true
-                                       })
-                                       <-waitCheckAuth.Done()
-                                       doneAuth()
-                                       if err := waitCheckAuth.Err(); errors.Is(err, context.DeadlineExceeded) {
-                                               danmulog.L(`E: `, "连接验证失败")
-                                               i += 1
-                                               continue
-                                       }
-                               }
+                       common, loaded := c.CommonsLoadOrStore.LoadOrStoreP(c.Commons, c.C.Roomid)
 
-                               danmulog.L(`I: `, "已连接到房间", common.Uname, `(`, common.Roomid, `)`)
-                               reply.Gui_show(`进入直播间: `+common.Uname+` (`+strconv.Itoa(common.Roomid)+`)`, `0room`)
-                               if common.Title != `` {
-                                       danmulog.L(`I: `, `房间标题: `+common.Title)
-                                       reply.Gui_show(`房间标题: `+common.Title, `0room`)
-                               }
+                       if loaded {
+                               common.InIdle = false
+                               common.Rev = 0.0 // 营收
+                       }
+
+                       exitSign = entryRoom(mainCtx, danmulog.BaseAdd(common.Roomid), common)
+
+                       common.InIdle = true
+
+                       time.Sleep(time.Second)
+               }
+
+               { //附加功能 直播流停止 ws信息保存
+                       reply.SaveToJson.Close()
+                       reply.StreamOStopAll()
+               }
+       }
+}
+
+func entryRoom(mainCtx context.Context, danmulog *part.Log_interface, common *c.Common) (exitSign bool) {
+       //附加功能 保持牌子点亮
+       go reply.Keep_medal_light(common)
+       //附加功能 自动发送即将过期礼物
+       go reply.AutoSend_silver_gift(common)
+       //获取热门榜
+       F.Get(common).Get(`Note`)
+
+       danmulog.L(`I: `, "连接到房间", common.Roomid)
+
+       Cookie := make(map[string]string)
+       common.Cookie.Range(func(k, v any) bool {
+               Cookie[k.(string)] = v.(string)
+               return true
+       })
 
-                               // 直播状态
-                               if F.Get(common).Get(`Liveing`); common.Liveing {
-                                       danmulog.L(`I: `, "直播中")
-                               } else {
-                                       danmulog.L(`I: `, "未直播")
+       // 检查与切换粉丝牌,只在cookie存在时启用
+       F.Get(common).Get(`CheckSwitch_FansMedal`)
+
+       // 对每个弹幕服务器尝试
+       F.Get(common).Get(`WSURL`)
+       aliveT := time.Now().Add(3 * time.Hour)
+       for i, exitloop := 0, false; !exitloop && i < len(common.WSURL) && time.Now().Before(aliveT); {
+               v := common.WSURL[i]
+               //ws启动
+               danmulog.L(`T: `, "连接 "+v)
+               u, _ := url.Parse(v)
+               ws_c, err := ws.New_client(&ws.Client{
+                       Url:               v,
+                       TO:                35 * 1000,
+                       Proxy:             common.Proxy,
+                       Func_abort_close:  func() { danmulog.L(`I: `, `服务器连接中断`) },
+                       Func_normal_close: func() { danmulog.L(`I: `, `服务器连接关闭`) },
+                       Header: map[string]string{
+                               `Cookie`:          reqf.Map_2_Cookies_String(Cookie),
+                               `Host`:            u.Hostname(),
+                               `User-Agent`:      c.UA,
+                               `Accept`:          `*/*`,
+                               `Accept-Language`: `zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2`,
+                               `Origin`:          `https://live.bilibili.com`,
+                               `Pragma`:          `no-cache`,
+                               `Cache-Control`:   `no-cache`,
+                       },
+               })
+               if err != nil {
+                       danmulog.L(`E: `, "连接错误", err)
+                       i += 1
+                       continue
+               }
+               wsmsg, err := ws_c.Handle()
+               if err != nil {
+                       danmulog.L(`E: `, "连接错误", err)
+                       i += 1
+                       continue
+               }
+               if ws_c.Isclose() {
+                       danmulog.L(`E: `, "连接错误", ws_c.Error())
+                       i += 1
+                       continue
+               }
+
+               // auth
+               {
+                       wsmsg.PushLock_tag(`send`, &ws.WsMsg{
+                               Msg: F.HelloGen(common.Roomid, common.Token),
+                       })
+                       waitCheckAuth, cancel := context.WithTimeout(mainCtx, 5*time.Second)
+                       doneAuth := wsmsg.Pull_tag_only(`rec`, func(wm *ws.WsMsg) (disable bool) {
+                               if F.HelloChe(wm.Msg) {
+                                       cancel()
                                }
+                               return true
+                       })
+                       <-waitCheckAuth.Done()
+                       doneAuth()
+                       if err := waitCheckAuth.Err(); errors.Is(err, context.DeadlineExceeded) {
+                               danmulog.L(`E: `, "连接验证失败")
+                               i += 1
+                               continue
+                       }
+               }
 
-                               // 处理ws消息
-                               var cancelDeal = wsmsg.Pull_tag(map[string]func(*ws.WsMsg) (disable bool){
-                                       `rec`: func(wm *ws.WsMsg) (disable bool) {
-                                               go reply.Reply(common, wm.Msg)
-                                               return false
-                                       },
-                                       `close`: func(_ *ws.WsMsg) (disable bool) {
-                                               return true
-                                       },
+               danmulog.L(`I: `, "已连接到房间", common.Uname, `(`, common.Roomid, `)`)
+               reply.Gui_show(`进入直播间: `+common.Uname+` (`+strconv.Itoa(common.Roomid)+`)`, `0room`)
+               if common.Title != `` {
+                       danmulog.L(`I: `, `房间标题: `+common.Title)
+                       reply.Gui_show(`房间标题: `+common.Title, `0room`)
+               }
+
+               // 直播状态
+               if F.Get(common).Get(`Liveing`); common.Liveing {
+                       danmulog.L(`I: `, "直播中")
+               } else {
+                       danmulog.L(`I: `, "未直播")
+               }
+
+               // 处理ws消息
+               var cancelDeal = wsmsg.Pull_tag(map[string]func(*ws.WsMsg) (disable bool){
+                       `rec`: func(wm *ws.WsMsg) (disable bool) {
+                               go reply.Reply(common, wm.Msg)
+                               return false
+                       },
+                       `close`: func(_ *ws.WsMsg) (disable bool) {
+                               return true
+                       },
+               })
+
+               //30s获取一次人气
+               go func() {
+                       danmulog.L(`T: `, "获取人气")
+                       heartbeatmsg, heartinterval := F.Heartbeat()
+                       for !ws_c.Isclose() {
+                               wsmsg.Push_tag(`send`, &ws.WsMsg{
+                                       Msg: heartbeatmsg,
                                })
+                               time.Sleep(time.Millisecond * time.Duration(heartinterval*1000))
+                       }
+               }()
+
+               // 刷新舰长数
+               F.Get(common).Get(`GuardNum`)
+               // 在线人数
+               F.Get(common).Get(`getOnlineGoldRank`)
+               //验证cookie
+               if missKey := F.CookieCheck([]string{
+                       `bili_jct`,
+                       `DedeUserID`,
+                       `LIVE_BUVID`,
+               }); len(missKey) == 0 {
+                       //附加功能 弹幕机 无cookie无法发送弹幕
+                       reply.Danmuji_auto()
+               }
+               { //附加功能 进房间发送弹幕 直播流保存 每日签到
+                       go F.Dosign()
+                       go reply.Entry_danmu(common)
+                       if _, e := recStartEnd.RecStartCheck.Run(mainCtx, common); e == nil {
+                               go reply.StreamOStart(common, common.Roomid)
+                       } else {
+                               danmulog.Base("功能", "指定房间录制区间").L(`I: `, common.Roomid, e)
+                       }
+                       go F.RoomEntryAction(common.Roomid)
+               }
 
-                               //30s获取一次人气
-                               go func() {
-                                       danmulog.L(`T: `, "获取人气")
-                                       heartbeatmsg, heartinterval := F.Heartbeat()
-                                       for !ws_c.Isclose() {
-                                               wsmsg.Push_tag(`send`, &ws.WsMsg{
-                                                       Msg: heartbeatmsg,
-                                               })
-                                               time.Sleep(time.Millisecond * time.Duration(heartinterval*1000))
+               //当前ws
+               {
+                       // 处理各种指令
+                       var cancelfunc = common.Danmu_Main_mq.Pull_tag(msgq.FuncMap{
+                               `interrupt`: func(_ any) (disable bool) {
+                                       exitloop = true
+                                       exitSign = true
+                                       ws_c.Close()
+                                       danmulog.L(`I: `, "停止,等待服务器断开连接")
+                                       reply.StreamOStopAll() //停止录制
+                                       return true
+                               },
+                               `exit_room`: func(_ any) bool { //退出当前房间
+                                       exitloop = true
+                                       reply.StreamOStop(common.Roomid)
+                                       danmulog.L(`I: `, "退出房间", common.Roomid)
+                                       c.C.Roomid = 0
+                                       ws_c.Close()
+                                       return true
+                               },
+                               `change_room`: func(roomid any) bool { //换房时退出当前房间
+                                       c.C.Roomid = roomid.(int)
+                                       exitloop = true
+                                       ws_c.Close()
+                                       if v, ok := common.K_v.LoadV(`仅保存当前直播间流`).(bool); ok && v {
+                                               reply.StreamOStopOther(c.C.Roomid) //停止其他房间录制
                                        }
-                               }()
-
-                               // 刷新舰长数
-                               F.Get(common).Get(`GuardNum`)
-                               // 在线人数
-                               F.Get(common).Get(`getOnlineGoldRank`)
-                               //验证cookie
-                               if missKey := F.CookieCheck([]string{
-                                       `bili_jct`,
-                                       `DedeUserID`,
-                                       `LIVE_BUVID`,
-                               }); len(missKey) == 0 {
-                                       //附加功能 弹幕机 无cookie无法发送弹幕
-                                       reply.Danmuji_auto()
-                               }
-                               { //附加功能 进房间发送弹幕 直播流保存 每日签到
-                                       go F.Dosign()
-                                       go reply.Entry_danmu()
-                                       if _, e := recStartEnd.RecStartCheck.Run(mainCtx, common); e == nil {
-                                               go reply.StreamOStart(common, common.Roomid)
-                                       } else {
-                                               danmulog.Base("功能", "指定房间录制区间").L(`I: `, common.Roomid, e)
+                                       return true
+                               },
+                               `flash_room`: func(_ any) bool { //重进房时退出当前房间
+                                       go F.Get(common).Get(`WSURL`)
+                                       ws_c.Close()
+                                       return true
+                               },
+                               `guard_update`: func(_ any) bool { //舰长更新
+                                       go F.Get(common).Get(`GuardNum`)
+                                       return false
+                               },
+                               `every100s`: func(_ any) bool { //每100s
+                                       if time.Now().After(aliveT) {
+                                               common.Danmu_Main_mq.Push_tag(`flash_room`, nil)
+                                               return false
                                        }
-                                       go F.RoomEntryAction(common.Roomid)
-                               }
-
-                               //当前ws
-                               {
-                                       // 处理各种指令
-                                       var cancelfunc = common.Danmu_Main_mq.Pull_tag(msgq.FuncMap{
-                                               `interrupt`: func(_ any) (disable bool) {
-                                                       exitloop = true
-                                                       exitSign = true
-                                                       ws_c.Close()
-                                                       danmulog.L(`I: `, "停止,等待服务器断开连接")
-                                                       reply.StreamOStopAll() //停止录制
-                                                       return true
-                                               },
-                                               `exit_room`: func(_ any) bool { //退出当前房间
-                                                       exitloop = true
-                                                       reply.StreamOStop(common.Roomid)
-                                                       danmulog.L(`I: `, "退出房间", common.Roomid)
-                                                       common.Roomid = 0
-                                                       ws_c.Close()
-                                                       return true
-                                               },
-                                               `change_room`: func(roomid any) bool { //换房时退出当前房间
-                                                       common.Roomid = roomid.(int)
-                                                       exitloop = true
-                                                       ws_c.Close()
-                                                       if v, ok := common.K_v.LoadV(`仅保存当前直播间流`).(bool); ok && v {
-                                                               reply.StreamOStopOther(common.Roomid) //停止其他房间录制
-                                                       }
-                                                       return true
-                                               },
-                                               `flash_room`: func(_ any) bool { //重进房时退出当前房间
-                                                       go F.Get(common).Get(`WSURL`)
-                                                       ws_c.Close()
-                                                       return true
-                                               },
-                                               `guard_update`: func(_ any) bool { //舰长更新
-                                                       go F.Get(common).Get(`GuardNum`)
-                                                       return false
-                                               },
-                                               `every100s`: func(_ any) bool { //每100s
-                                                       if time.Now().After(aliveT) {
-                                                               common.Danmu_Main_mq.Push_tag(`flash_room`, nil)
-                                                               return false
-                                                       }
-                                                       if v, ok := common.K_v.LoadV("下播后不记录人气观看人数").(bool); ok && v && !common.Liveing {
-                                                               return false
-                                                       }
-                                                       // 在线人数
-                                                       go F.Get(common).Get(`getOnlineGoldRank`)
-                                                       return false
-                                               },
-                                               `new day`: func(_ any) bool { //日期更换
-                                                       go func() {
-                                                               //每日签到
-                                                               F.Dosign()
-                                                               //每日兑换硬币
-                                                               F.Get(common).Silver_2_coin()
-                                                               //附加功能 每日发送弹幕
-                                                               reply.Entry_danmu()
-                                                               //附加功能 保持牌子点亮
-                                                               reply.Keep_medal_light()
-                                                               //附加功能 自动发送即将过期礼物
-                                                               reply.AutoSend_silver_gift()
-                                                       }()
-                                                       return false
-                                               },
-                                       })
-
-                                       {
-                                               cancel, c := wsmsg.Pull_tag_chan(`exit`, 1, mainCtx)
-                                               <-c
-                                               cancel()
+                                       if v, ok := common.K_v.LoadV("下播后不记录人气观看人数").(bool); ok && v && !common.Liveing {
+                                               return false
                                        }
+                                       // 在线人数
+                                       go F.Get(common).Get(`getOnlineGoldRank`)
+                                       return false
+                               },
+                               `new day`: func(_ any) bool { //日期更换
+                                       go func() {
+                                               //每日签到
+                                               F.Dosign()
+                                               //每日兑换硬币
+                                               F.Get(common).Silver_2_coin()
+                                               //附加功能 每日发送弹幕
+                                               reply.Entry_danmu(common)
+                                               //附加功能 保持牌子点亮
+                                               reply.Keep_medal_light(common)
+                                               //附加功能 自动发送即将过期礼物
+                                               reply.AutoSend_silver_gift(common)
+                                       }()
+                                       return false
+                               },
+                       })
 
-                                       cancelfunc()
-                                       time.Sleep(time.Second)
-                               }
-                               cancelDeal()
+                       {
+                               cancel, c := wsmsg.Pull_tag_chan(`exit`, 1, mainCtx)
+                               <-c
+                               cancel()
                        }
-                       time.Sleep(time.Second)
-               }
 
-               { //附加功能 直播流停止 ws信息保存
-                       reply.SaveToJson.Close()
-                       reply.StreamOStopAll()
+                       cancelfunc()
+                       time.Sleep(time.Second)
                }
+               cancelDeal()
        }
+
+       return
 }
index 7c2e55717964f326329af0a7ab8c5b43d32deb3c..e70b57b2551922dd01d478a755003d01b7e2c707 100644 (file)
@@ -76,7 +76,8 @@ func Cmd() {
                                                if reply.StreamOStatus(room) {
                                                        reply.StreamOStop(room)
                                                } else {
-                                                       reply.StreamOStart(c.C.Copy(), room)
+                                                       common, _ := c.CommonsLoadOrStore.LoadOrStoreP(c.Commons, room)
+                                                       reply.StreamOStart(common, room)
                                                }
                                                continue
                                        }
@@ -87,7 +88,8 @@ func Cmd() {
                                        if reply.StreamOStatus(c.C.Roomid) {
                                                reply.StreamOStop(c.C.Roomid)
                                        } else {
-                                               reply.StreamOStart(c.C.Copy(), c.C.Roomid)
+                                               common, _ := c.Commons.LoadV(c.C.Roomid).(*c.Common)
+                                               reply.StreamOStart(common, c.C.Roomid)
                                        }
                                }
                                continue
@@ -184,22 +186,23 @@ func Cmd() {
                        if strings.Contains(inputs, ` room`) && c.C.Roomid != 0 {
                                fmt.Print("\n")
                                fmt.Println("当前直播间(" + strconv.Itoa(c.C.Roomid) + ")信息")
+                               common, _ := c.Commons.LoadV(c.C.Roomid).(*c.Common)
                                {
                                        living := `未在直播`
-                                       if c.C.Liveing {
+                                       if common.Liveing {
                                                living = `直播中`
                                        }
-                                       fmt.Println(c.C.Uname, c.C.Title, living)
+                                       fmt.Println(common.Uname, common.Title, living)
                                }
-                               if c.C.Liveing {
-                                       fmt.Println(`已直播时长:`, (time.Time{}).Add(time.Since(c.C.Live_Start_Time)).Format(time.TimeOnly))
+                               if common.Liveing {
+                                       fmt.Println(`已直播时长:`, (time.Time{}).Add(time.Since(common.Live_Start_Time)).Format(time.TimeOnly))
                                }
                                {
-                                       fmt.Println(`营收:`, fmt.Sprintf("¥%.2f", c.C.Rev))
+                                       fmt.Println(`营收:`, fmt.Sprintf("¥%.2f", common.Rev))
                                }
-                               fmt.Println(`舰长数:`, c.C.GuardNum)
-                               fmt.Println(`分区排行:`, c.C.Note, `人气:`, c.C.Renqi, `观看人数:`, c.C.Watched, `在线人数:`, c.C.OnlineNum)
-                               fmt.Println(`Web服务地址:`, c.C.Stream_url.String())
+                               fmt.Println(`舰长数:`, common.GuardNum)
+                               fmt.Println(`分区排行:`, common.Note, `观看人数:`, common.Watched, `在线人数:`, common.OnlineNum)
+                               fmt.Println(`Web服务地址:`, common.Stream_url.String())
                                var array = reply.StreamOCommon(-1)
                                fmt.Println(`正在录制的房间:`)
                                for i := 0; i < len(array); i++ {
diff --git a/go.mod b/go.mod
index 4bf7951e821cef16175ceea45a8ae0acbe8c22c1..4e4ce88750f7244255d5ef49be33e81223e74ba8 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.22.2
 require (
        github.com/gotk3/gotk3 v0.6.4
        github.com/mdp/qrterminal/v3 v3.2.0
-       github.com/qydysky/part v0.28.20240617114802
+       github.com/qydysky/part v0.28.20240708182044
        github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
        github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
        golang.org/x/text v0.16.0
diff --git a/go.sum b/go.sum
index 6b4042322c1bcf275e1c44bfaca1643709744698..b4466facf03ef3945bb0e13728a78b7b00416b90 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -46,8 +46,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/qydysky/biliApi v0.0.0-20240707084224-dd146610f462 h1:SblV/m+0mx6QgH2YYvdjE5QxhyfE/EOQglJ1PGd3x3E=
 github.com/qydysky/biliApi v0.0.0-20240707084224-dd146610f462/go.mod h1:om024vfxALQ5vxsbaGoMm8IS0esLYBnEOpJI8FsGoDg=
-github.com/qydysky/part v0.28.20240617114802 h1:cmDWin7303nKFQ7HAL2+Ur87vkh8d67xVqudvpXp96E=
-github.com/qydysky/part v0.28.20240617114802/go.mod h1:dgagZnPYRFZDbt7XJf7nADOJLoYwlebD9B8Z8g5aHhI=
+github.com/qydysky/part v0.28.20240708182044 h1:Av1SaUu/cvwGZ3xnsq9KabFjjn2Wwl+xjbAJbq6a2Iw=
+github.com/qydysky/part v0.28.20240708182044/go.mod h1:dgagZnPYRFZDbt7XJf7nADOJLoYwlebD9B8Z8g5aHhI=
 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
 github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=