package main import ( "bufio" "encoding/json" "os" "path/filepath" "testing" "github.com/orzogc/acfundanmu" ) // 用真正的录制写入器(danmuWriter)产生 jsonl,再按合并的流程重排一遍, // 验证「本程序自己录下来的弹幕」合出来和以前一模一样(弹道、宽度都不变)。 // 这也是手动合并与自动合并的分水岭:录制侧写文件完全不经过 relayoutLanes, // 只有合并渲染前会重排,所以磁盘上的 .ass/.nick.ass/.jsonl 一个字节都不变。 func TestLiveRecordingPathUnaffected(t *testing.T) { dir := t.TempDir() cfg := acfundanmu.SubConfig{Title: "测试直播", PlayResX: 1920, PlayResY: 1080, FontSize: 48, StartTime: 1700000000000000000} ass := filepath.Join(dir, "live.ass") w := newDanmuWriter("liveid", "stream", cfg, ass) texts := []string{"来啦", "这首歌好听", "主播加油啊", "打卡打卡", "哈哈哈哈哈哈哈哈哈", "这条弹幕稍微长一点看看弹道到底怎么排"} for i := 0; i < 500; i++ { relMs := int64(i) * 220 // 平均 0.22 秒一条,够密集 c := &acfundanmu.Comment{Content: texts[i%len(texts)]} c.SendTime = (cfg.StartTime + relMs*1e6) / 1e6 c.UserID = int64(2000 + i%9) c.Nickname = "观众" + string(rune('A'+i%9)) c.Avatar = "http://example.invalid/a.png" w.write(c) } w.close() f, err := os.Open(filepath.Join(dir, "live.jsonl")) if err != nil { t.Fatal(err) } defer f.Close() sc := bufio.NewScanner(f) sc.Buffer(make([]byte, 1<<20), 1<<20) var meta danmuMeta first := true var recs []danmuRecord for sc.Scan() { if first { json.Unmarshal(sc.Bytes(), &meta) first = false continue } var r danmuRecord if json.Unmarshal(sc.Bytes(), &r) == nil { recs = append(recs, r) } } type snap struct{ lane, width int } before := make([]snap, len(recs)) for i, r := range recs { before[i] = snap{r.Lane, r.Width} } relayoutLanes(recs, meta) laneDiff, widthDiff := 0, 0 for i, r := range recs { if r.Lane != before[i].lane { laneDiff++ if laneDiff <= 3 { t.Logf("第 %d 条弹道变了:%d → %d", i, before[i].lane, r.Lane) } } if r.Width != before[i].width { widthDiff++ } } t.Logf("录制产生 %d 条弹幕(含空内容 %d 条),重排后弹道变化 %d 条、宽度变化 %d 条", len(recs), countEmpty(recs), laneDiff, widthDiff) if laneDiff != 0 || widthDiff != 0 { t.Errorf("正常录制的弹幕重排后不应有任何变化") } } func countEmpty(recs []danmuRecord) int { n := 0 for _, r := range recs { if r.Content == "" { n++ } } return n }