173 lines
3.8 KiB
Go
173 lines
3.8 KiB
Go
package lrc2srt
|
||
|
||
import (
|
||
"bufio"
|
||
"fmt"
|
||
"github.com/Hami-Lemon/lrc2srt/glist"
|
||
"io"
|
||
"os"
|
||
"sort"
|
||
"strconv"
|
||
"strings"
|
||
)
|
||
|
||
type SRTMergeMode int
|
||
|
||
const (
|
||
SRT_MERGE_MODE_STACK SRTMergeMode = iota
|
||
SRT_MERGE_MODE_UP
|
||
SRT_MERGE_MODE_BOTTOM
|
||
)
|
||
|
||
type SRTContent struct {
|
||
//序号,从1开始
|
||
Index int
|
||
//开始时间,单位毫秒
|
||
Start int
|
||
//结束时间,单位毫秒
|
||
End int
|
||
//歌词内容
|
||
Text string
|
||
}
|
||
|
||
/**
|
||
1
|
||
00:00:01,111 --> 00:00:10,111
|
||
字幕
|
||
|
||
*/
|
||
//返回SRT文件中,一句字幕的字符串表示形式
|
||
func (s *SRTContent) String() string {
|
||
builder := strings.Builder{}
|
||
builder.WriteString(strconv.Itoa(s.Index))
|
||
builder.WriteByte('\n')
|
||
sh, sm, ss, sms := millisecond2Time(s.Start)
|
||
eh, em, es, ems := millisecond2Time(s.End)
|
||
builder.WriteString(fmt.Sprintf("%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\n",
|
||
sh, sm, ss, sms, eh, em, es, ems))
|
||
builder.WriteString(s.Text)
|
||
builder.WriteString("\n\n")
|
||
return builder.String()
|
||
}
|
||
|
||
type SRT struct {
|
||
//歌曲名
|
||
Title string
|
||
//歌手名 未指定文件名是,文件名格式为:歌曲名-歌手名.srt
|
||
Artist string
|
||
Content glist.Queue[*SRTContent]
|
||
}
|
||
|
||
// LrcToSrt LRC对象转换成SRT对象
|
||
func LrcToSrt(lrc *LRC) *SRT {
|
||
if lrc == nil {
|
||
return nil
|
||
}
|
||
srt := &SRT{
|
||
Title: lrc.Title,
|
||
Artist: lrc.Artist,
|
||
Content: glist.NewLinkedList[*SRTContent](),
|
||
}
|
||
index := 1
|
||
//上一条srt信息
|
||
var prevSRT *SRTContent
|
||
for it := lrc.LrcList.Iterator(); it.Has(); {
|
||
lrcNode := it.Next()
|
||
srtContent := &SRTContent{
|
||
Index: index,
|
||
Start: lrcNode.time,
|
||
Text: lrcNode.content,
|
||
}
|
||
if index != 1 {
|
||
//上一条歌词的结束时间设置为当前歌词的开始时间
|
||
prevSRT.End = srtContent.Start
|
||
}
|
||
srt.Content.PushBack(srtContent)
|
||
index++
|
||
prevSRT = srtContent
|
||
}
|
||
//最后一条歌词
|
||
if prevSRT != nil {
|
||
//结束时间是为其 开始时间+10 秒
|
||
prevSRT.End = prevSRT.Start + 1000
|
||
}
|
||
return srt
|
||
}
|
||
|
||
// Merge 将另一个srt信息合并到当前srt中,有三种合并模式
|
||
//1. SRT_MERGE_MODE_STACK: 按照开始时间对两个srt信息进行排序,交错合并
|
||
//2. SRT_MERGE_MODE_UP: 当前srt信息排列在上,另一个排列在下,即 other 追加到后面
|
||
//3. SRT_MERGE_MODE_BOTTOM: 当前srt信息排列在下,另一个排列在上,即 other 添加到前面
|
||
func (s *SRT) Merge(other *SRT, mode SRTMergeMode) {
|
||
switch mode {
|
||
case SRT_MERGE_MODE_STACK:
|
||
s.mergeStack(other)
|
||
case SRT_MERGE_MODE_UP:
|
||
s.mergeUp(other)
|
||
case SRT_MERGE_MODE_BOTTOM:
|
||
s.mergeBottom(other)
|
||
}
|
||
}
|
||
|
||
//todo 改进算法,现在的算法太慢了
|
||
func (s *SRT) mergeStack(other *SRT) {
|
||
size := s.Content.Size() + other.Content.Size()
|
||
temp := make([]*SRTContent, size, size)
|
||
index := 0
|
||
for it := s.Content.Iterator(); it.Has(); {
|
||
temp[index] = it.Next()
|
||
index++
|
||
}
|
||
for it := other.Content.Iterator(); it.Has(); {
|
||
temp[index] = it.Next()
|
||
index++
|
||
}
|
||
sort.SliceStable(temp, func(i, j int) bool {
|
||
return temp[i].Start < temp[j].Start
|
||
})
|
||
list := glist.NewLinkedList[*SRTContent]()
|
||
for _, v := range temp {
|
||
list.Append(v)
|
||
}
|
||
s.Content = list
|
||
}
|
||
|
||
func (s *SRT) mergeUp(other *SRT) {
|
||
if other.Content.IsNotEmpty() {
|
||
for it := other.Content.Iterator(); it.Has(); {
|
||
s.Content.Append(it.Next())
|
||
}
|
||
}
|
||
}
|
||
|
||
func (s *SRT) mergeBottom(other *SRT) {
|
||
oq := other.Content
|
||
if oq.IsNotEmpty() {
|
||
s.Content.PushFront(*(oq.PullBack()))
|
||
}
|
||
}
|
||
|
||
// WriteFile 将SRT格式的数据写入指定的文件中
|
||
func (s *SRT) WriteFile(path string) error {
|
||
f, err := os.Create(path)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
err = s.Write(f)
|
||
err = f.Close()
|
||
return err
|
||
}
|
||
|
||
// Write 将SRT格式的数据写入dst中
|
||
func (s *SRT) Write(dst io.Writer) error {
|
||
//6KB的缓冲
|
||
bufSize := 1024 * 6
|
||
writer := bufio.NewWriterSize(dst, bufSize)
|
||
for it := s.Content.Iterator(); it.Has(); {
|
||
_, err := writer.WriteString(it.Next().String())
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
return writer.Flush()
|
||
}
|