import (
"bytes"
+ "context"
"encoding/json"
"errors"
"fmt"
}
// 设定字幕文件名,为""时停止输出
-func Ass_f(save_path string, filePath string, st time.Time) {
+func Ass_f(contextC context.Context, save_path string, filePath string, st time.Time) {
if !IsOn(`仅保存当前直播间流`) {
return
}
}
f.Write([]byte(ass.header), true)
ass.startT = st
+
+ <-contextC.Done()
+ ass.file = ""
}
// 传入要显示的单条字幕
return
}
tmp.common.Roomid = roomid
-
- //录制回调,关于ass
- tmp.Callback_startRec = func(ms *M4SStream) error {
- StartRecDanmu(ms.Current_save_path + "0.csv")
- Ass_f(ms.Current_save_path, ms.Current_save_path+"0", time.Now()) //开始ass
- return nil
- }
- tmp.Callback_stopRec = func(_ *M4SStream) {
- StopRecDanmu()
- Ass_f("", "", time.Now()) //停止ass
- }
//实例回调,避免重复录制
tmp.Callback_start = func(ms *M4SStream) error {
//流服务添加
}
}
+// 实例切断
+func StreamOCut(roomid int) {
+ if v, ok := streamO.Load(roomid); ok {
+ if v.(*M4SStream).Status.Islive() {
+ v.(*M4SStream).msg.PushLock_tag(`cut`, v.(*M4SStream))
+ flog.L(`I: `, `已切片 `+strconv.Itoa(roomid))
+ }
+ }
+}
+
// type Obs struct {
// c obsws.Client
// Prog string //程序路径
Server: StreamWs,
}
-func StartRecDanmu(filePath string) {
+func StartRecDanmu(c context.Context, filePath string) {
if !IsOn(`仅保存当前直播间流`) || !IsOn("弹幕回放") {
return
}
} else {
f.L(`E: `, e)
}
+ <-c.Done()
+ flog.Base("弹幕回放").L(`T: `, `停止`)
+ Recoder.Stop()
}
func PlayRecDanmu(filePath string) (*websocket.Server, func()) {
return websocket.Play(filePath)
}
-func StopRecDanmu() {
- if !IsOn(`仅保存当前直播间流`) || !IsOn("弹幕回放") {
- return
- }
- flog.Base("弹幕回放").L(`T: `, `停止`)
- Recoder.Stop()
-}
-
// 此次直播的交互人数
var communicate Communicate
if t.reload.CompareAndSwap(false, true) {
flog.Base_add("指定弹幕重启录制").L(`I: `, uid, msg, "请求重启录制")
go func() {
- if v, ok := c.C.K_v.LoadV(`仅保存当前直播间流`).(bool); ok && v {
- StreamOStop(c.C.Roomid) //停止其他房间录制
- }
- StreamOStart(c.C.Roomid)
+ StreamOCut(c.C.Roomid)
time.Sleep(time.Minute)
t.reload.Store(false)
}()
var sh = []interface{}{"房间改变"}
if c.C.Title != title.(string) {
- //录制
- go func() {
- if v, ok := c.C.K_v.LoadV(`修改标题时重新录制`).(bool); ok && v {
- StreamOStop(c.C.Roomid) //停止其他房间录制
- }
- StreamOStart(c.C.Roomid)
- }()
+ StreamOCut(c.C.Roomid)
}
if title != nil {
msglog := msglog.Log_show_control(false)
{ //附加功能 弹幕机 封禁 弹幕合并
+ //对指定弹幕重新录制
+ danmuReLiveTriger.Init(&c.C)
+ danmuReLiveTriger.Check(item.uid, item.msg)
go Danmujif(item.msg)
// if Autobanf(item.msg) {
// Gui_show(Itos([]interface{}{"风险", item.auth, ":", item.msg}))
} else {
item.msg = _msg
}
- //对指定弹幕重新录制
- danmuReLiveTriger.Init(&c.C)
- danmuReLiveTriger.Check(item.uid, item.msg)
}
Msg_showdanmu(item)
}
return nil
}
-func (t *M4SStream) saveStream() (e error) {
- // 设置保存路径
+// 设置保存路径
+func (t *M4SStream) getSavepath() {
t.Current_save_path = t.config.save_path + "/" +
time.Now().Format("2006_01_02-15_04_05") + "-" +
strconv.Itoa(t.common.Roomid) + "-" +
t.common.Qn[t.common.Live_qn] + "-" +
pstring.Rand(2, 3) +
`/`
-
- // 清除初始值
- t.last_m4s = nil
- t.first_buf = nil
-
// 显示保存位置
if rel, err := filepath.Rel(t.config.save_path, t.Current_save_path); err == nil {
t.log.L(`I: `, "保存到", rel+`/0.`+t.stream_type)
} else {
t.log.L(`W: `, err)
}
+}
+
+func (t *M4SStream) saveStream() (e error) {
+ // 清除初始值
+ t.last_m4s = nil
+ t.first_buf = nil
+
if s, ok := t.common.K_v.LoadV("直播Web服务路径").(string); ok && s != "" {
t.log.L(`I: `, "Web服务地址:", t.common.Stream_url.String()+s)
}
// 保存到文件
if t.config.save_to_file {
- var (
- contextC context.Context
- cancle context.CancelFunc
- )
- t.msg.Pull_tag_async(map[string]func(*M4SStream) (disable bool){
- `cut`: func(ms *M4SStream) (disable bool) {
- select {
- case <-contextC.Done():
-
- }
- if contextC != nil {
- cancle()
- }
- contextC, cancle = context.WithCancel(context.Background())
- defer cancle()
-
- l := ms.log.Base_add(`文件`)
- startf := func(_ *M4SStream) error {
- l.L(`T: `, `start`)
- return nil
- }
- stopf := func(_ *M4SStream) error {
- l.L(`T: `, `stop`)
- return nil
- }
- if e := ms.PusherToFile(contextC, ms.Current_save_path+`0.`+ms.stream_type, startf, stopf); e != nil {
- l.L(`E: `, e)
- }
- return false
- },
- })
t.msg.Pull_tag_only(`load`, func(ms *M4SStream) (disable bool) {
ms.msg.Push_tag(`cut`, ms)
return true
}
}
- go func(link *m4s_link_item, path string) {
+ go func(link *m4s_link_item) {
defer download_limit.UnBlock()
link.status = 1 // 设置切片状态为正在下载
link.data.Append(r.Respon)
link.status = 2 // 设置切片状态为下载完成
}
- }(v, t.Current_save_path)
+ }(v)
}
// 等待队列下载完成
t.Stream_msg = msgq.NewType[[]byte]()
// 设置事件
+ if t.config.save_to_file {
+ var fc funcCtrl.FlashFunc
+ t.msg.Pull_tag_async(map[string]func(*M4SStream) (disable bool){
+ `cut`: func(ms *M4SStream) (disable bool) {
+ contextC, cancle := context.WithCancel(context.Background())
+ fc.FlashWithCallback(cancle)
+
+ l := ms.log.Base_add(`文件`)
+ startf := func(_ *M4SStream) error {
+ l.L(`T: `, `start`)
+ return nil
+ }
+ stopf := func(_ *M4SStream) error {
+ l.L(`T: `, `stop`)
+ return nil
+ }
+ ms.getSavepath()
+ go StartRecDanmu(contextC, ms.Current_save_path+"0.csv") //保存弹幕
+ go Ass_f(contextC, ms.Current_save_path, ms.Current_save_path+"0", time.Now()) //开始ass
+ if e := ms.PusherToFile(contextC, ms.Current_save_path+`0.`+ms.stream_type, startf, stopf); e != nil {
+ l.L(`E: `, e)
+ }
+ return false
+ },
+ })
+ }
if t.Callback_stopRec != nil {
t.msg.Pull_tag_only("stopRec", func(ms *M4SStream) (disable bool) {
ms.Callback_stopRec(ms)
return false
})
}
- if t.Callback_stop != nil {
- t.msg.Pull_tag_only("stop", func(ms *M4SStream) (disable bool) {
+ t.msg.Pull_tag_only("stop", func(ms *M4SStream) (disable bool) {
+ if ms.Callback_stop != nil {
ms.Callback_stop(ms)
- return false
- })
- }
- t.msg.Pull_tag_only("stop", func(_ *M4SStream) (disable bool) {
+ }
+ t.msg.ClearAll()
return true
})
}
// 保存到文件
-func (t *M4SStream) PusherToFile(cont context.Context, filepath string, startFunc func(*M4SStream) error, stopFunc func(*M4SStream) error) error {
+func (t *M4SStream) PusherToFile(contextC context.Context, filepath string, startFunc func(*M4SStream) error, stopFunc func(*M4SStream) error) error {
f := file.New(filepath, 0, false)
defer f.Close()
f.Delete()
if len(t.boot_buf) != 0 {
f.Write(t.boot_buf, true)
}
- contextC, cancel := context.WithCancel(cont)
t.Stream_msg.Pull_tag(map[string]func([]byte) bool{
`data`: func(b []byte) bool {
select {
default:
}
if len(b) == 0 {
- cancel()
return true
}
f.Write(b, true)
return false
},
`close`: func(_ []byte) bool {
- cancel()
return true
},
})
github.com/qydysky/part v0.24.3/go.mod h1:AQJH+BYeN30eKXjkDqGEtw0vx3wVGplBeOMLSyleEDo=
github.com/qydysky/part v0.24.4 h1:JCA1CyggvUNu/B0xKEjnODaUp6rgEi1hjtJwqOTvnaw=
github.com/qydysky/part v0.24.4/go.mod h1:AQJH+BYeN30eKXjkDqGEtw0vx3wVGplBeOMLSyleEDo=
+github.com/qydysky/part v0.24.5 h1:DNvtDp/HEv59eYmsVnFk+dvEML5liFf/hQlSfPQmnRU=
+github.com/qydysky/part v0.24.5/go.mod h1:AQJH+BYeN30eKXjkDqGEtw0vx3wVGplBeOMLSyleEDo=
+github.com/qydysky/part v0.24.6 h1:IPNfsQG/er3gdN4beYe7kLzJiC/ds2FtsRgA9W/On/w=
+github.com/qydysky/part v0.24.6/go.mod h1:AQJH+BYeN30eKXjkDqGEtw0vx3wVGplBeOMLSyleEDo=
+github.com/qydysky/part v0.24.7 h1:wOtm1jvljIb1HZclDAfNMnw3rA/r5oQwifUCBt/d7qY=
+github.com/qydysky/part v0.24.7/go.mod h1:AQJH+BYeN30eKXjkDqGEtw0vx3wVGplBeOMLSyleEDo=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=