]> 127.0.0.1 Git - bili_danmu/.git/commitdiff
Improve 优化fmp4保存,更新api (#185)
authorqydysky <qydysky@foxmail.com>
Sun, 6 Apr 2025 11:53:37 +0000 (19:53 +0800)
committerGitHub <noreply@github.com>
Sun, 6 Apr 2025 11:53:37 +0000 (19:53 +0800)
* Improve 优化fmp4保存

* Improve 优化fmp4保存

* Improve 依赖更新

* Improve 依赖更新

* Improve 优化停止

* Improve 优化停止

* Improve 依赖更新

* Improve 依赖更新

* Improve 优化提示

* Improve 修正data race

* Improve race need cgo

* Improve 依赖更新

* Improve set test room

* Improve set test room

* Improve 更新无效api

13 files changed:
.github/workflows/go.yml
.github/workflows/test.yml
Reply/F.go
Reply/F/comp.go
Reply/F/rev/rev.go [new file with mode: 0644]
Reply/Reply.go
Reply/fmp4Decode.go
Reply/stream.go
bili_danmu.go
demo/main.go
demo/main_test.go [new file with mode: 0644]
go.mod
go.sum

index 731fb08fc89491811fb0daf61009668b22dc1824..3ca12a5adb38081e2c5a68795bb1d03f744661ed 100644 (file)
@@ -40,9 +40,10 @@ jobs:
       run: |
         sudo apt-get update
         sudo apt-get install libgtk-3-dev libcairo2-dev libglib2.0-dev
+        export r=213
         go get .
         go mod vendor
-        CGO_ENABLED=0 go test -v --cover -coverprofile=coverage ./...
+        CGO_ENABLED=1 go test -v --cover -coverprofile=coverage -race -count=1 ./...
 
     - name: Codecov
       uses: codecov/codecov-action@v4
index 9c0d6df0205b6efaae300c026838595651f26b87..e533bab41c760cae29c9d2b7e38b6de30f2aeb4e 100644 (file)
@@ -43,9 +43,10 @@ jobs:
       run: |
         sudo apt-get update
         sudo apt-get install libgtk-3-dev libcairo2-dev libglib2.0-dev
+        export r=213
         go get .
         go mod vendor
-        CGO_ENABLED=0 go test -v --cover -coverprofile=coverage ./...
+        CGO_ENABLED=1 go test -v --cover -coverprofile=coverage -race -count=1 ./...
 
     - name: Codecov
       uses: codecov/codecov-action@v4
index 8954bf371a56ea51e7d6a1751580ad9330574d81..de06fab3271fe9385037b3fc0438d12b7117ac32 100644 (file)
@@ -127,33 +127,6 @@ func selfcross2(a []string) (float32, string) {
 
 // 功能区
 
-// 显示营收
-func init() {
-       if !IsOn("统计营收") {
-               return
-       }
-       go func() {
-               var ShowRev = make(map[int]float64)
-
-               clog := c.C.Log.Base_add(`营收`)
-               for {
-                       if _, ok := ShowRev[c.C.Roomid]; !ok && c.C.Roomid != 0 {
-                               ShowRev[c.C.Roomid] = 0
-                       }
-                       for room, rev := range ShowRev {
-                               if c.C.Roomid != room {
-                                       clog.L(`I: `, fmt.Sprintf("%d ¥%.2f", room, c.C.Rev))
-                                       delete(ShowRev, room)
-                               } else if c.C.Rev != rev {
-                                       ShowRev[room] = c.C.Rev
-                                       clog.L(`I: `, fmt.Sprintf("%d ¥%.2f", room, c.C.Rev))
-                               }
-                       }
-                       time.Sleep(time.Minute)
-               }
-       }()
-}
-
 // 获取实例的Common
 func StreamOCommon(roomid int) (array []*c.Common) {
        if roomid != -1 { //返回特定房间
index f75d2b9c4a38393a3b50b338240b45d55fca0e4d..06cb920f0e2209ed32c9f699773c2865a52f67f9 100644 (file)
@@ -11,11 +11,17 @@ import (
        _ "github.com/qydysky/bili_danmu/Reply/F/danmuEmotes"
        _ "github.com/qydysky/bili_danmu/Reply/F/danmuji"
        _ "github.com/qydysky/bili_danmu/Reply/F/parseM3u8"
+       _ "github.com/qydysky/bili_danmu/Reply/F/rev"
        _ "github.com/qydysky/bili_danmu/Reply/F/videoFastSeed"
        comp "github.com/qydysky/part/component2"
        log "github.com/qydysky/part/log"
 )
 
+var Rev = comp.Get[interface {
+       Init(l *log.Log_interface)
+       ShowRev(roomid int, rev float64)
+}](`rev`)
+
 var DanmuCountPerMin = comp.Get[interface {
        // will WriteHeader
        GetRec(savePath string, r *http.Request, w http.ResponseWriter) error
diff --git a/Reply/F/rev/rev.go b/Reply/F/rev/rev.go
new file mode 100644 (file)
index 0000000..30ea9a1
--- /dev/null
@@ -0,0 +1,53 @@
+package rev
+
+import (
+       "fmt"
+       "sync"
+       "time"
+
+       comp "github.com/qydysky/part/component2"
+       log "github.com/qydysky/part/log"
+)
+
+func init() {
+       comp.RegisterOrPanic[interface {
+               Init(l *log.Log_interface)
+               ShowRev(roomid int, rev float64)
+       }](`rev`, &rev{})
+}
+
+type rev struct {
+       l           *log.Log_interface
+       currentRoom int
+       currentRev  float64
+       lastShow    time.Time
+       sync.Mutex
+}
+
+func (t *rev) Init(l *log.Log_interface) {
+       t.Lock()
+       defer t.Unlock()
+
+       t.l = l.Base(`营收`)
+}
+
+func (t *rev) ShowRev(roomid int, rev float64) {
+       t.Lock()
+       defer t.Unlock()
+
+       if t.l == nil {
+               return
+       }
+
+       if roomid != t.currentRoom {
+               if t.currentRoom != 0 {
+                       t.l.L(`I: `, fmt.Sprintf("%d ¥%.2f", t.currentRoom, t.currentRev))
+               }
+               t.l.L(`I: `, fmt.Sprintf("%d ¥%.2f", roomid, rev))
+       } else if rev != t.currentRev && time.Since(t.lastShow).Minutes() > 1 {
+               t.lastShow = time.Now()
+               t.l.L(`I: `, fmt.Sprintf("%d ¥%.2f", roomid, rev))
+       }
+       t.currentRev = rev
+       t.currentRoom = roomid
+}
index 901913d38a4dedc8b91f27cd2a1af4caa7d13df4..b0fa62e3396b9edee2698dcd6b65a4cfb9d213c4 100644 (file)
@@ -5,7 +5,6 @@ import (
        "compress/zlib"
        "context"
        "encoding/json"
-       "errors"
        "fmt"
        "strconv"
        "strings"
@@ -28,7 +27,6 @@ import (
 )
 
 var reply_log = c.C.Log.Base(`Reply`)
-var ErrDecode = errors.New(`ErrDecode`)
 
 // brotliDecoder
 type brotliDecoder struct {
index 667769c1131151347e3d2f81641fb9250be419f4..b127257166a6bf24ba589d70051668bbcea0aae9 100644 (file)
@@ -25,6 +25,7 @@ var (
        ActionGenFastSeedFmp4 pe.Action = `GenFastSeedFmp4`
        ActionSeekFmp4        pe.Action = `SeekFmp4`
        ActionOneFFmp4        pe.Action = `OneFFmp4`
+       ActionCheckTFail      pe.Action = `CheckTFail`
 )
 
 var boxs map[string]bool
@@ -232,25 +233,25 @@ func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframe *slice.Buf[byte])
                }
 
                //is t error?
-               check_set_maxT = func(ts timeStamp, equal func(ts timeStamp) error, larger func(ts timeStamp) error) (err error) {
+               checkAndSetMaxT = func(ts timeStamp) (err error) {
                        switch ts.handlerType {
                        case 'v':
                                if maxVT == 0 {
                                        maxVT = ts.getT()
-                               } else if maxVT == ts.getT() && equal != nil {
-                                       err = equal(ts)
-                               } else if maxVT > ts.getT() && larger != nil {
-                                       err = larger(ts)
+                               } else if maxVT == ts.getT() {
+                                       err = ActionCheckTFail.New("equal VT detect")
+                               } else if maxVT > ts.getT() {
+                                       err = ActionCheckTFail.New("lower VT detect")
                                } else {
                                        maxVT = ts.getT()
                                }
                        case 'a':
                                if maxAT == 0 {
                                        maxAT = ts.getT()
-                               } else if maxAT == ts.getT() && equal != nil {
-                                       err = equal(ts)
-                               } else if maxAT > ts.getT() && larger != nil {
-                                       err = larger(ts)
+                               } else if maxAT == ts.getT() {
+                                       err = ActionCheckTFail.New("equal AT detect")
+                               } else if maxAT > ts.getT() {
+                                       err = ActionCheckTFail.New("lower AT detect")
                                } else {
                                        maxAT = ts.getT()
                                }
@@ -258,6 +259,12 @@ func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframe *slice.Buf[byte])
                        }
                        return
                }
+
+               dropKeyFrame = func(index int) {
+                       t.buf.Reset()
+                       haveKeyframe = false
+                       cu = index
+               }
        )
 
        ies, e := decode(buf, "moof")
@@ -280,21 +287,13 @@ func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframe *slice.Buf[byte])
                                                if ts.handlerType == 'v' {
                                                        if e := checkSampleEntries(m[5].i, m[6].i); e != nil {
                                                                //skip
-                                                               t.buf.Reset()
-                                                               haveKeyframe = false
-                                                               cu = m[0].i
-                                                               return pe.Join(ErrDealIESkip, e)
+                                                               dropKeyFrame(m[0].e)
+                                                               return pe.Join(ErrDecode, e)
                                                        }
                                                }
-                                               if e := check_set_maxT(ts, func(_ timeStamp) error {
-                                                       return errors.New("skip")
-                                               }, func(_ timeStamp) error {
-                                                       t.buf.Reset()
-                                                       haveKeyframe = false
-                                                       cu = m[0].i
-                                                       return errors.New("skip")
-                                               }); e != nil {
-                                                       return pe.Join(ErrDealIESkip, e)
+                                               if e := checkAndSetMaxT(ts); e != nil {
+                                                       dropKeyFrame(m[0].e)
+                                                       return pe.Join(ErrDecode, e)
                                                }
                                        }
 
@@ -304,10 +303,9 @@ func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframe *slice.Buf[byte])
                                        if keyframeMoof {
                                                if v, e := t.buf.HadModified(bufModified); e == nil && v && !t.buf.IsEmpty() {
                                                        if e := t.buf.AppendTo(keyframe); e != nil {
-                                                               return pe.Join(ErrDealIEBreak, e)
+                                                               return e
                                                        }
-                                                       cu = m[0].i
-                                                       t.buf.Reset()
+                                                       dropKeyFrame(m[0].i)
                                                }
                                                haveKeyframe = true
                                        } else if !haveKeyframe {
@@ -315,7 +313,7 @@ func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframe *slice.Buf[byte])
                                        }
                                        if haveKeyframe {
                                                if e := t.buf.Append(buf[m[0].i:m[6].e]); e != nil {
-                                                       return pe.Join(ErrDealIEBreak, e)
+                                                       return e
                                                }
                                        }
                                        return nil
@@ -338,10 +336,8 @@ func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframe *slice.Buf[byte])
                                                if handlerType == 'v' {
                                                        if e := checkSampleEntries(m[5].i, m[6].i); e != nil {
                                                                //skip
-                                                               t.buf.Reset()
-                                                               haveKeyframe = false
-                                                               cu = m[0].i
-                                                               return pe.Join(ErrDealIESkip, e)
+                                                               dropKeyFrame(m[0].e)
+                                                               return pe.Join(ErrDecode, e)
                                                        }
                                                }
                                                switch handlerType {
@@ -350,15 +346,9 @@ func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframe *slice.Buf[byte])
                                                case 's':
                                                        audio = ts
                                                }
-                                               if e := check_set_maxT(ts, func(_ timeStamp) error {
-                                                       return errors.New("skip")
-                                               }, func(_ timeStamp) error {
-                                                       t.buf.Reset()
-                                                       haveKeyframe = false
-                                                       cu = m[0].i
-                                                       return errors.New("skip")
-                                               }); e != nil {
-                                                       return pe.Join(ErrDealIESkip, e)
+                                               if e := checkAndSetMaxT(ts); e != nil {
+                                                       dropKeyFrame(m[0].e)
+                                                       return pe.Join(ErrDecode, e)
                                                }
                                        }
                                        {
@@ -366,10 +356,8 @@ func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframe *slice.Buf[byte])
                                                if handlerType == 'v' {
                                                        if e := checkSampleEntries(m[9].i, m[10].i); e != nil {
                                                                //skip
-                                                               t.buf.Reset()
-                                                               haveKeyframe = false
-                                                               cu = m[0].i
-                                                               return pe.Join(ErrDealIESkip, e)
+                                                               dropKeyFrame(m[0].e)
+                                                               return pe.Join(ErrDecode, e)
                                                        }
                                                }
                                                switch handlerType {
@@ -378,15 +366,9 @@ func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframe *slice.Buf[byte])
                                                case 's':
                                                        audio = ts
                                                }
-                                               if e := check_set_maxT(ts, func(_ timeStamp) error {
-                                                       return errors.New("skip")
-                                               }, func(_ timeStamp) error {
-                                                       t.buf.Reset()
-                                                       haveKeyframe = false
-                                                       cu = m[0].i
-                                                       return errors.New("skip")
-                                               }); e != nil {
-                                                       return pe.Join(ErrDealIESkip, e)
+                                               if e := checkAndSetMaxT(ts); e != nil {
+                                                       dropKeyFrame(m[0].e)
+                                                       return pe.Join(ErrDecode, e)
                                                }
                                        }
 
@@ -395,7 +377,7 @@ func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframe *slice.Buf[byte])
                                                t.AVTDiff = 0.1
                                        }
                                        if diff := math.Abs(video.getT() - audio.getT()); diff > t.AVTDiff {
-                                               return pe.Join(ErrDealIEBreak, fmt.Errorf("时间戳不匹配 %v %v (或许应调整fmp4音视频时间戳容差s>%.2f)", video.timeStamp, audio.timeStamp, diff))
+                                               return pe.Join(ErrDecode, fmt.Errorf("时间戳不匹配 %v %v (或许应调整fmp4音视频时间戳容差s>%.2f)", video.timeStamp, audio.timeStamp, diff))
                                                // copy(video.data, F.Itob64(int64(audio.getT()*float64(video.timescale))))
                                        }
 
@@ -403,10 +385,9 @@ func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframe *slice.Buf[byte])
                                        if keyframeMoof {
                                                if v, e := t.buf.HadModified(bufModified); e == nil && v && !t.buf.IsEmpty() {
                                                        if e := t.buf.AppendTo(keyframe); e != nil {
-                                                               return pe.Join(ErrDealIEBreak, e)
+                                                               return e
                                                        }
-                                                       cu = m[0].i
-                                                       t.buf.Reset()
+                                                       dropKeyFrame(m[0].i)
                                                }
                                                haveKeyframe = true
                                        } else if !haveKeyframe {
@@ -414,7 +395,7 @@ func (t *Fmp4Decoder) Search_stream_fmp4(buf []byte, keyframe *slice.Buf[byte])
                                        }
                                        if haveKeyframe {
                                                if e := t.buf.Append(buf[m[0].i:m[10].e]); e != nil {
-                                                       return pe.Join(ErrDealIEBreak, e)
+                                                       return e
                                                }
                                        }
                                        return nil
@@ -497,25 +478,25 @@ func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
                }
 
                //is t error?
-               check_set_maxT = func(ts timeStamp, equal func(ts timeStamp) error, larger func(ts timeStamp) error) (err error) {
+               checkAndSetMaxT = func(ts timeStamp) (err error) {
                        switch ts.handlerType {
                        case 'v':
                                if maxVT == 0 {
                                        maxVT = ts.getT()
-                               } else if maxVT == ts.getT() && equal != nil {
-                                       err = equal(ts)
-                               } else if maxVT > ts.getT() && larger != nil {
-                                       err = larger(ts)
+                               } else if maxVT == ts.getT() {
+                                       err = ActionCheckTFail.New("equal VT detect")
+                               } else if maxVT > ts.getT() {
+                                       err = ActionCheckTFail.New("lower VT detect")
                                } else {
                                        maxVT = ts.getT()
                                }
                        case 'a':
                                if maxAT == 0 {
                                        maxAT = ts.getT()
-                               } else if maxAT == ts.getT() && equal != nil {
-                                       err = equal(ts)
-                               } else if maxAT > ts.getT() && larger != nil {
-                                       err = larger(ts)
+                               } else if maxAT == ts.getT() {
+                                       err = ActionCheckTFail.New("equal AT detect")
+                               } else if maxAT > ts.getT() {
+                                       err = ActionCheckTFail.New("lower AT detect")
                                } else {
                                        maxAT = ts.getT()
                                }
@@ -523,6 +504,12 @@ func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
                        }
                        return
                }
+
+               dropKeyFrame = func(index int) {
+                       t.buf.Reset()
+                       haveKeyframe = false
+                       cu = index
+               }
        )
 
        ies, e := decode(buf, "moof")
@@ -530,7 +517,7 @@ func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
                return 0, e
        }
 
-       var ErrNormal = pe.New("ErrNormal", "ErrNormal")
+       var ErrNormal pe.Action = "ErrNormal"
 
        err = deals(ies,
                []dealIE{
@@ -548,24 +535,16 @@ func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
                                                if ts.handlerType == 'v' {
                                                        if e := checkSampleEntries(m[5].i, m[6].i); e != nil {
                                                                //skip
-                                                               t.buf.Reset()
-                                                               haveKeyframe = false
-                                                               cu = m[0].i
-                                                               return pe.Join(ErrDealIESkip.New(), e)
+                                                               dropKeyFrame(m[0].e)
+                                                               return pe.Join(ErrDecode, e)
                                                        }
                                                }
                                                if handlerType == 'v' {
                                                        video = ts
                                                }
-                                               if e := check_set_maxT(ts, func(_ timeStamp) error {
-                                                       return errors.New("skip")
-                                               }, func(_ timeStamp) error {
-                                                       t.buf.Reset()
-                                                       haveKeyframe = false
-                                                       cu = m[0].i
-                                                       return errors.New("skip")
-                                               }); e != nil {
-                                                       return pe.Join(ErrDealIESkip.New(), e)
+                                               if e := checkAndSetMaxT(ts); e != nil {
+                                                       dropKeyFrame(m[0].e)
+                                                       return pe.Join(ErrDecode, e)
                                                }
                                        }
 
@@ -574,13 +553,12 @@ func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
                                        //deal frame
                                        if keyframeMoof {
                                                if v, e := t.buf.HadModified(bufModified); e == nil && v && !t.buf.IsEmpty() {
-                                                       cu = m[0].i
                                                        if haveKeyframe && len(w) > 0 {
                                                                err = w[0](video.getT(), cu, t.buf)
-                                                               t.buf.Reset()
+                                                               dropKeyFrame(m[0].i)
                                                                return ErrNormal
                                                        }
-                                                       t.buf.Reset()
+                                                       dropKeyFrame(m[0].i)
                                                }
                                                haveKeyframe = true
                                        } else if !haveKeyframe {
@@ -588,7 +566,7 @@ func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
                                        }
                                        if haveKeyframe {
                                                if e := t.buf.Append(buf[m[0].i:m[6].e]); e != nil {
-                                                       return pe.Join(ErrDealIEBreak.New(), e)
+                                                       return e
                                                }
                                        }
                                        return nil
@@ -609,10 +587,8 @@ func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
                                                if handlerType == 'v' {
                                                        if e := checkSampleEntries(m[5].i, m[6].i); e != nil {
                                                                //skip
-                                                               t.buf.Reset()
-                                                               haveKeyframe = false
-                                                               cu = m[0].i
-                                                               return pe.Join(ErrDealIESkip, e)
+                                                               dropKeyFrame(m[0].e)
+                                                               return pe.Join(ErrDecode, e)
                                                        }
                                                }
                                                switch handlerType {
@@ -621,15 +597,9 @@ func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
                                                case 's':
                                                        audio = ts
                                                }
-                                               if e := check_set_maxT(ts, func(_ timeStamp) error {
-                                                       return errors.New("skip")
-                                               }, func(_ timeStamp) error {
-                                                       t.buf.Reset()
-                                                       haveKeyframe = false
-                                                       cu = m[0].i
-                                                       return errors.New("skip")
-                                               }); e != nil {
-                                                       return pe.Join(ErrDealIESkip, e)
+                                               if e := checkAndSetMaxT(ts); e != nil {
+                                                       dropKeyFrame(m[0].e)
+                                                       return pe.Join(ErrDecode, e)
                                                }
                                        }
                                        {
@@ -637,10 +607,8 @@ func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
                                                if handlerType == 'v' {
                                                        if e := checkSampleEntries(m[9].i, m[10].i); e != nil {
                                                                //skip
-                                                               t.buf.Reset()
-                                                               haveKeyframe = false
-                                                               cu = m[0].i
-                                                               return pe.Join(ErrDealIESkip, e)
+                                                               dropKeyFrame(m[0].e)
+                                                               return pe.Join(ErrDecode, e)
                                                        }
                                                }
                                                switch handlerType {
@@ -649,15 +617,9 @@ func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
                                                case 's':
                                                        audio = ts
                                                }
-                                               if e := check_set_maxT(ts, func(_ timeStamp) error {
-                                                       return errors.New("skip")
-                                               }, func(_ timeStamp) error {
-                                                       t.buf.Reset()
-                                                       haveKeyframe = false
-                                                       cu = m[0].i
-                                                       return errors.New("skip")
-                                               }); e != nil {
-                                                       return pe.Join(ErrDealIESkip, e)
+                                               if e := checkAndSetMaxT(ts); e != nil {
+                                                       dropKeyFrame(m[0].e)
+                                                       return pe.Join(ErrDecode, e)
                                                }
                                        }
 
@@ -666,20 +628,19 @@ func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
                                                t.AVTDiff = 0.1
                                        }
                                        if diff := math.Abs(video.getT() - audio.getT()); diff > t.AVTDiff {
-                                               return pe.Join(ErrDealIEBreak, fmt.Errorf("时间戳不匹配 %v %v (或许应调整fmp4音视频时间戳容差s>%.2f)", video.timeStamp, audio.timeStamp, diff))
+                                               return pe.Join(ErrDecode, fmt.Errorf("时间戳不匹配 %v %v (或许应调整fmp4音视频时间戳容差s>%.2f)", video.timeStamp, audio.timeStamp, diff))
                                                // copy(video.data, F.Itob64(int64(audio.getT()*float64(video.timescale))))
                                        }
 
                                        //deal frame
                                        if keyframeMoof {
                                                if v, e := t.buf.HadModified(bufModified); e == nil && v && !t.buf.IsEmpty() {
-                                                       cu = m[0].i
                                                        if haveKeyframe && len(w) > 0 {
                                                                err = w[0](video.getT(), cu, t.buf)
-                                                               t.buf.Reset()
+                                                               dropKeyFrame(m[0].i)
                                                                return ErrNormal
                                                        }
-                                                       t.buf.Reset()
+                                                       dropKeyFrame(m[0].i)
                                                }
                                                haveKeyframe = true
                                        } else if !haveKeyframe {
@@ -687,7 +648,7 @@ func (t *Fmp4Decoder) oneF(buf []byte, w ...dealFMp4) (cu int, err error) {
                                        }
                                        if haveKeyframe {
                                                if e := t.buf.Append(buf[m[0].i:m[10].e]); e != nil {
-                                                       return pe.Join(ErrDealIEBreak, e)
+                                                       return e
                                                }
                                        }
                                        return nil
@@ -840,11 +801,6 @@ func (t *Fmp4Decoder) GenFastSeed(reader io.Reader, save func(seedTo time.Durati
        return
 }
 
-var (
-       ErrDealIEBreak = pe.Action(`ErrDealIEBreak`)
-       ErrDealIESkip  = pe.Action(`ErrDealIESkip`)
-)
-
 type dealIE struct {
        matchCounts int
        boxNames    []string
@@ -871,7 +827,7 @@ func deal(ies []ie, dealIEf dealIE) (err error) {
 func deals(ies []ie, dealIEs []dealIE) (err error) {
        for cu := 0; cu < len(ies) && len(dealIEs) != 0; cu++ {
                for i := 0; i < len(dealIEs); i++ {
-                       if e := dealIEs[i].deal(ies, cu); e != nil && !pe.Catch(e, ErrDealIESkip) {
+                       if e := dealIEs[i].deal(ies, cu); e != nil {
                                return e
                        }
                }
index cc49ea6818fd665c9e5f84b51b213eb170a7e021..4f620e8e48ec61377b0f9b7734d013f8cd876642 100644 (file)
@@ -43,6 +43,7 @@ import (
        pstring "github.com/qydysky/part/strings"
        pu "github.com/qydysky/part/util"
        pweb "github.com/qydysky/part/web"
+       "slices"
 )
 
 const (
@@ -141,7 +142,7 @@ func (t *m4s_link_item) getNo() (int, error) {
 }
 
 var (
-       AEFDCTO perrors.Action = `ActionErrFmp4DownloadCareTO`
+       ActionErrFmp4DownloadCareTO perrors.Action = `ActionErrFmp4DownloadCareTO`
 )
 
 func (link *m4s_link_item) download(reqPool *pool.Buf[reqf.Req], reqConfig reqf.Rval) (err error) {
@@ -164,7 +165,7 @@ func (link *m4s_link_item) download(reqPool *pool.Buf[reqf.Req], reqConfig reqf.
                return e
        } else {
                if int64(reqConfig.Timeout) < r.UsedTime.Milliseconds()+3000 {
-                       err = perrors.New(fmt.Sprintf("fmp4切片下载超时s(%d)或许应该大于%d", reqConfig.Timeout/1000, (r.UsedTime.Milliseconds()+4000)/1000), AEFDCTO)
+                       err = ActionErrFmp4DownloadCareTO.New(fmt.Sprintf("fmp4切片下载超时s(%d)或许应该大于%d", reqConfig.Timeout/1000, (r.UsedTime.Milliseconds()+4000)/1000))
                }
                link.status = 2 // 设置切片状态为下载完成
                return
@@ -675,6 +676,8 @@ func (t *M4SStream) getSavepath() {
        }
 }
 
+var ErrDecode = perrors.Action("ErrDecode")
+
 func (t *M4SStream) saveStream() (e error) {
        // 清除初始值
        t.first_buf = nil
@@ -1134,7 +1137,7 @@ func (t *M4SStream) saveStreamM4s() (e error) {
                                                        `Connection`: `close`,
                                                },
                                        })
-                                       if perrors.Catch(e, AEFDCTO) {
+                                       if ActionErrFmp4DownloadCareTO.Catch(e) {
                                                t.log.L(`W: `, e.Error())
                                        } else if e != nil {
                                                downErr.Store(true)
@@ -1181,12 +1184,12 @@ func (t *M4SStream) saveStreamM4s() (e error) {
                                        }
                                }
                                t.putM4s(cu)
-                               download_seq = append(download_seq[:k], download_seq[k+1:]...)
+                               download_seq = slices.Delete(download_seq, k, k+1)
                                k -= 1
                                continue
                        } else if t.first_buf == nil {
                                t.putM4s(cu)
-                               download_seq = append(download_seq[:k], download_seq[k+1:]...)
+                               download_seq = slices.Delete(download_seq, k, k+1)
                                k -= 1
                                continue
                        }
@@ -1195,7 +1198,7 @@ func (t *M4SStream) saveStreamM4s() (e error) {
                                t.log.L(`E: `, e)
                        }
                        t.putM4s(cu)
-                       download_seq = append(download_seq[:k], download_seq[k+1:]...)
+                       download_seq = slices.Delete(download_seq, k, k+1)
                        k -= 1
 
                        buff, unlock := buf.GetPureBufRLock()
@@ -1203,18 +1206,18 @@ func (t *M4SStream) saveStreamM4s() (e error) {
                        unlock()
 
                        if err != nil && !errors.Is(err, io.EOF) {
-                               t.log.L(`E: `, err)
-                               //丢弃所有数据
-                               buf.Reset()
-                               e = err
-                               if skipErrFrame {
+                               if ErrDecode.Catch(err) && skipErrFrame {
+                                       t.log.L(`W: `, err)
                                        // 将此切片服务器设置停用
                                        // if u, e := url.Parse(cu.Url); e == nil {
                                        t.common.DisableLiveAutoByUuid(cu.SerUuid)
                                        // t.common.DisableLiveAuto(u.Host)
                                        // }
                                } else {
-                                       return
+                                       e = err
+                                       download_seq = download_seq[:0]
+                                       _ = pctx.CallCancel(t.Status)
+                                       break
                                }
                        }
 
@@ -1427,6 +1430,45 @@ func (t *M4SStream) Start() bool {
                                        //保存弹幕
                                        go StartRecDanmu(ctx1, ms.GetSavePath())
 
+                                       //指定房间录制回调
+                                       if v, ok := ms.common.K_v.LoadV("指定房间录制回调").([]any); ok && len(v) > 0 {
+                                               l := l.Base(`录制回调`)
+                                               for i := 0; i < len(v); i++ {
+                                                       if vm, ok := v[i].(map[string]any); ok {
+                                                               if roomid, ok := vm["roomid"].(float64); ok && int(roomid) == ms.common.Roomid {
+                                                                       var (
+                                                                               durationS, _ = vm["durationS"].(float64)
+                                                                               start, _     = vm["start"].([]any)
+                                                                       )
+                                                                       if len(start) >= 2 && durationS >= 0 {
+                                                                               go func() {
+                                                                                       ctx2, done2 := pctx.WaitCtx(ctx1)
+                                                                                       defer done2()
+                                                                                       select {
+                                                                                       case <-ctx2.Done():
+                                                                                       case <-time.After(time.Second * time.Duration(durationS)):
+                                                                                               var cmds []string
+                                                                                               for i := 0; i < len(start); i++ {
+                                                                                                       if cmd, ok := start[i].(string); ok && cmd != "" {
+                                                                                                               cmds = append(cmds, strings.ReplaceAll(cmd, "{type}", ms.GetStreamType()))
+                                                                                                       }
+                                                                                               }
+
+                                                                                               cmd := exec.Command(cmds[0], cmds[1:]...)
+                                                                                               cmd.Dir = ms.GetSavePath()
+                                                                                               l.L(`I: `, "启动", cmd.Args)
+                                                                                               if e := cmd.Run(); e != nil {
+                                                                                                       l.L(`E: `, e)
+                                                                                               }
+                                                                                               l.L(`I: `, "结束")
+                                                                                       }
+                                                                               }()
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+
                                        path := ms.GetSavePath() + `0.` + ms.GetStreamType()
                                        startT := time.Now()
                                        if e := ms.PusherToFile(ctx1, path, startf, stopf); e != nil {
index bd40b988880a599836adeba716df869b84dfb77f..e283a5584bed5287d4c49ac7bd2d659d4331866c 100644 (file)
@@ -30,7 +30,7 @@ import (
        ws "github.com/qydysky/part/websocket"
 )
 
-func Start() {
+func Start(rootCtx context.Context) {
        danmulog := c.C.Log.Base(`bilidanmu`)
        danmulog.L(`I: `, `当前PID:`, c.C.PID)
        danmulog.L(`I: `, "version: ", c.C.Version)
@@ -97,6 +97,10 @@ func Start() {
                reply.KeepMedalLight(mainCtx, c.C)
                //ass初始化
                replyFunc.Ass.Init(c.C.K_v.LoadV("Ass"))
+               //rev初始化
+               if c.C.IsOn(`统计营收`) {
+                       replyFunc.Rev.Init(danmulog)
+               }
                // 指定房间录制区间
                if _, err := recStartEnd.InitF.Run(mainCtx, c.C); err != nil {
                        danmulog.Base("功能", "指定房间录制区间").L(`E: `, err)
@@ -149,6 +153,8 @@ func Start() {
                                                common, ok := c.Commons.LoadV(c.C.Roomid).(*c.Common)
                                                if ok {
                                                        common.Rev += rev.Rev
+                                                       // 显示营收
+                                                       replyFunc.Rev.ShowRev(common.Roomid, common.Rev)
                                                }
                                        }
                                        return false
@@ -234,7 +240,7 @@ func Start() {
                                common.Rev = 0.0 // 营收
                        }
 
-                       exitSign = entryRoom(mainCtx, danmulog.BaseAdd(common.Roomid), common)
+                       exitSign = entryRoom(rootCtx, mainCtx, danmulog.BaseAdd(common.Roomid), common)
 
                        common.InIdle = true
 
@@ -248,7 +254,7 @@ func Start() {
        }
 }
 
-func entryRoom(mainCtx context.Context, danmulog *part.Log_interface, common *c.Common) (exitSign bool) {
+func entryRoom(rootCtx, mainCtx context.Context, danmulog *part.Log_interface, common *c.Common) (exitSign bool) {
        //附加功能 自动发送即将过期礼物
        go reply.AutoSend_silver_gift(common)
        //获取热门榜
@@ -381,14 +387,14 @@ func entryRoom(mainCtx context.Context, danmulog *part.Log_interface, common *c.
                        replyFunc.Danmuji.Danmuji_auto(mainCtx, c.C.K_v.LoadV(`自动弹幕机_内容`).([]any), c.C.K_v.LoadV(`自动弹幕机_发送间隔s`).(float64), reply.Msg_senddanmu)
                }
                { //附加功能 进房间发送弹幕 直播流保存 每日签到
+                       F.RoomEntryAction(common.Roomid)
                        // go F.Dosign()
-                       go reply.Entry_danmu(common)
+                       reply.Entry_danmu(common)
                        if _, e := recStartEnd.RecStartCheck.Run(mainCtx, common); e == nil {
-                               go reply.StreamOStart(common, common.Roomid)
+                               reply.StreamOStart(common, common.Roomid)
                        } else {
                                danmulog.Base("功能", "指定房间录制区间").L(`I: `, common.Roomid, e)
                        }
-                       go F.RoomEntryAction(common.Roomid)
                }
 
                //当前ws
@@ -443,9 +449,16 @@ func entryRoom(mainCtx context.Context, danmulog *part.Log_interface, common *c.
                                },
                        })
 
+                       danmulog.L(`T: `, "启动完成", common.Uname, `(`, common.Roomid, `)`)
+
                        {
                                cancel, c := wsmsg.Pull_tag_chan(`exit`, 1, mainCtx)
-                               <-c
+                               select {
+                               case <-c:
+                               case <-rootCtx.Done():
+                                       common.Danmu_Main_mq.Push_tag(`interrupt`, nil)
+                                       <-c
+                               }
                                cancel()
                        }
 
index 9f9bb43a38b1a254f8ec043825f238d6723b4770..5068fc0dac07d3262e6db0d132a1d1b4980e474f 100644 (file)
@@ -1,9 +1,11 @@
 package main
 
 import (
+       "context"
+
        q "github.com/qydysky/bili_danmu"
 )
 
 func main() {
-       q.Start()
+       q.Start(context.Background())
 }
diff --git a/demo/main_test.go b/demo/main_test.go
new file mode 100644 (file)
index 0000000..29f0874
--- /dev/null
@@ -0,0 +1,16 @@
+package main
+
+import (
+       "context"
+       "testing"
+       "time"
+
+       q "github.com/qydysky/bili_danmu"
+)
+
+// go test -run ^TestMain$ github.com/qydysky/bili_danmu/demo -race -count=1 -v -r xxx
+func TestMain(m *testing.T) {
+       ctx, c := context.WithTimeout(context.Background(), time.Second*40)
+       defer c()
+       q.Start(ctx)
+}
diff --git a/go.mod b/go.mod
index 2d8bfff0bd4adcffdc539248043b871cd9ba141b..18d2b8faeb749e985acddaa7c1daf53edf623c24 100644 (file)
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.24
 require (
        github.com/gotk3/gotk3 v0.6.4
        github.com/mdp/qrterminal/v3 v3.2.0
-       github.com/qydysky/part v0.28.20250313160332
+       github.com/qydysky/part v0.28.20250330170611
        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.23.0 // indirect
@@ -13,7 +13,7 @@ require (
 
 require (
        github.com/google/uuid v1.6.0
-       github.com/qydysky/biliApi v0.0.0-20240725184407-15076dddb6fb
+       github.com/qydysky/biliApi v0.0.0-20250406112014-bf8c070170f6
        github.com/qydysky/brotli v0.0.0-20240828134800-e9913a6e7ed9
        golang.org/x/exp v0.0.0-20250215185904-eff6e970281f
 )
diff --git a/go.sum b/go.sum
index 1e19422ca2199e89c546d0bdbb6c1580a7f8ef5f..add27d58288273dc9f39ed7c58c8679d199203e6 100644 (file)
--- a/go.sum
+++ b/go.sum
@@ -42,12 +42,12 @@ github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdh
 github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/qydysky/biliApi v0.0.0-20240725184407-15076dddb6fb h1:dtSpNF9hLQa09TUfR+xbYFkHcx2breAFsXeU7e599gE=
-github.com/qydysky/biliApi v0.0.0-20240725184407-15076dddb6fb/go.mod h1:om024vfxALQ5vxsbaGoMm8IS0esLYBnEOpJI8FsGoDg=
+github.com/qydysky/biliApi v0.0.0-20250406112014-bf8c070170f6 h1:eWklz9YhqcLnJeHxWSlJZmL2V5rRyyEVqLKgLY3ipQs=
+github.com/qydysky/biliApi v0.0.0-20250406112014-bf8c070170f6/go.mod h1:1FbgCj+aOwIvuRRuX/l5uTLb3JIwWyJSa0uEfwpYV/8=
 github.com/qydysky/brotli v0.0.0-20240828134800-e9913a6e7ed9 h1:k451T+bpsLr+Dq9Ujo+Qtx0iomRA1XXS5ttlEojvfuQ=
 github.com/qydysky/brotli v0.0.0-20240828134800-e9913a6e7ed9/go.mod h1:cI8/gy/wjy2Eb+p2IUj2ZuDnC8R5Vrx3O0VMPvMvphA=
-github.com/qydysky/part v0.28.20250313160332 h1:3YwhIZwtIrnULREneqmjdQnL7vB1SxYZGVAZUiJAVZU=
-github.com/qydysky/part v0.28.20250313160332/go.mod h1:RHYTy8EbqCP6OioVf6BkvFcfWLNO0S220zl0DDlY84Y=
+github.com/qydysky/part v0.28.20250330170611 h1:8ll4oVALYXi0wFce12r8BkYRdlw8U50VZs7FI6AZTog=
+github.com/qydysky/part v0.28.20250330170611/go.mod h1:RHYTy8EbqCP6OioVf6BkvFcfWLNO0S220zl0DDlY84Y=
 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=