This repository has been archived on 2024-10-02. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
ltc/srt.go
2022-03-28 20:04:51 +08:00

189 lines
4.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package lrc2srt
import (
"bufio"
"fmt"
"github.com/Hami-Lemon/lrc2srt/glist"
"io"
"os"
"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)
}
}
//可以类比为合并两个有序链表,
//算法参考:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-by-leetcode-solu/
func (s *SRT) mergeStack(other *SRT) {
ls, _ := s.Content.(*glist.LinkedList[*SRTContent])
lo, _ := other.Content.(*glist.LinkedList[*SRTContent])
lhs, lho := ls.First, lo.First
//临时的空结点
preHead := &glist.Node[*SRTContent]{}
prev := preHead
for lhs != nil && lho != nil {
//副本结点,从而不改变other对象中的内容
oCopy := lho.Clone()
if lhs.Element.Start <= oCopy.Element.Start {
prev.Next = lhs
lhs.Prev = prev
lhs = lhs.Next
} else {
prev.Next = oCopy
oCopy.Prev = prev
lho = lho.Next
}
prev = prev.Next
}
if lhs == nil {
//如果剩下的内容是other中的,则依次迭代复制到s中
for n := lho; n != nil; n = n.Next {
c := n.Clone()
prev.Next = c
c.Prev = prev
prev = prev.Next
}
} else {
prev.Next = lhs
}
ls.First = preHead.Next
ls.First.Prev = nil
}
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()
}