generated by Claude-3.7-Sonnet
This commit is contained in:
91
utils/json_parser.go
Normal file
91
utils/json_parser.go
Normal file
@@ -0,0 +1,91 @@
|
||||
// Package utils 提供工具函数
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gitea.malaihome.work/ans/podcast_search/model"
|
||||
)
|
||||
|
||||
// JsonParser 用于解析JSON格式的转录文件
|
||||
type JsonParser struct{}
|
||||
|
||||
// NewJsonParser 创建新的JSON解析器
|
||||
func NewJsonParser() *JsonParser {
|
||||
return &JsonParser{}
|
||||
}
|
||||
|
||||
// Parse 解析JSON格式的转录文件
|
||||
func (p *JsonParser) Parse(jsonData string) (*model.Transcript, error) {
|
||||
// 解析JSON
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(jsonData), &data); err != nil {
|
||||
return nil, fmt.Errorf("解析JSON失败: %w", err)
|
||||
}
|
||||
|
||||
// 创建转录
|
||||
transcript := &model.Transcript{
|
||||
Subtitles: make([]model.Subtitle, 0),
|
||||
}
|
||||
|
||||
// 解析版本
|
||||
_, ok := data["version"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("无效的JSON格式: 缺少版本信息")
|
||||
}
|
||||
|
||||
// 解析段落
|
||||
segments, ok := data["segments"].([]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("无效的JSON格式: 缺少段落信息")
|
||||
}
|
||||
|
||||
// 解析每个段落
|
||||
for i, segment := range segments {
|
||||
seg, ok := segment.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// 解析开始时间
|
||||
startTime, ok := seg["startTime"].(float64)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// 解析结束时间
|
||||
endTime, ok := seg["endTime"].(float64)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// 解析内容
|
||||
body, ok := seg["body"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// 解析发言人
|
||||
speaker := ""
|
||||
if s, ok := seg["speaker"].(string); ok {
|
||||
speaker = s
|
||||
}
|
||||
|
||||
// 创建字幕
|
||||
subtitle := model.Subtitle{
|
||||
Index: i,
|
||||
Start: time.Duration(startTime * float64(time.Second)),
|
||||
End: time.Duration(endTime * float64(time.Second)),
|
||||
Data: body,
|
||||
Speaker: speaker,
|
||||
}
|
||||
|
||||
transcript.Subtitles = append(transcript.Subtitles, subtitle)
|
||||
}
|
||||
|
||||
// 我们已经解析了版本信息,但Transcript结构体中没有Version字段
|
||||
// 所以这里只返回解析好的transcript对象
|
||||
return transcript, nil
|
||||
}
|
||||
107
utils/srt_parser.go
Normal file
107
utils/srt_parser.go
Normal file
@@ -0,0 +1,107 @@
|
||||
// Package utils 提供工具函数
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitea.malaihome.work/ans/podcast_search/model"
|
||||
)
|
||||
|
||||
// SrtParser 用于解析SRT格式的转录文件
|
||||
type SrtParser struct {
|
||||
// SRT格式匹配正则表达式
|
||||
srtMatcher *regexp.Regexp
|
||||
// 换行符匹配正则表达式
|
||||
newlineMatcher *regexp.Regexp
|
||||
}
|
||||
|
||||
// NewSrtParser 创建新的SRT解析器
|
||||
func NewSrtParser() *SrtParser {
|
||||
return &SrtParser{
|
||||
srtMatcher: regexp.MustCompile(
|
||||
`(\d*)\s?((\d{2}):(\d{2}):(\d{2})[,|.](\d{3})) +--> +((\d{2}):(\d{2}):(\d{2})[,|.](\d{3})).*[\r\n]+\s*([^\r\n]+(\n|\r|\n)(?:.*))`,
|
||||
),
|
||||
newlineMatcher: regexp.MustCompile(`[\r\n]+`),
|
||||
}
|
||||
}
|
||||
|
||||
// Parse 解析SRT格式的转录文件
|
||||
func (p *SrtParser) Parse(srtData string) (*model.Transcript, error) {
|
||||
matches := p.srtMatcher.FindAllStringSubmatch(srtData, -1)
|
||||
subtitles := make([]model.Subtitle, 0)
|
||||
i := 0
|
||||
|
||||
for _, match := range matches {
|
||||
i++
|
||||
|
||||
// 索引可能存在也可能不存在
|
||||
index := i
|
||||
if match[1] != "" {
|
||||
parsedIndex, err := strconv.Atoi(match[1])
|
||||
if err == nil {
|
||||
index = parsedIndex
|
||||
}
|
||||
}
|
||||
|
||||
// 解析开始时间
|
||||
startTimeHours, _ := strconv.Atoi(match[3])
|
||||
startTimeMinutes, _ := strconv.Atoi(match[4])
|
||||
startTimeSeconds, _ := strconv.Atoi(match[5])
|
||||
startTimeMilliseconds, _ := strconv.Atoi(match[6])
|
||||
|
||||
// 解析结束时间
|
||||
endTimeHours, _ := strconv.Atoi(match[8])
|
||||
endTimeMinutes, _ := strconv.Atoi(match[9])
|
||||
endTimeSeconds, _ := strconv.Atoi(match[10])
|
||||
endTimeMilliseconds, _ := strconv.Atoi(match[11])
|
||||
|
||||
// 计算开始和结束时间的Duration
|
||||
startDuration := time.Duration(startTimeHours)*time.Hour +
|
||||
time.Duration(startTimeMinutes)*time.Minute +
|
||||
time.Duration(startTimeSeconds)*time.Second +
|
||||
time.Duration(startTimeMilliseconds)*time.Millisecond
|
||||
|
||||
endDuration := time.Duration(endTimeHours)*time.Hour +
|
||||
time.Duration(endTimeMinutes)*time.Minute +
|
||||
time.Duration(endTimeSeconds)*time.Second +
|
||||
time.Duration(endTimeMilliseconds)*time.Millisecond
|
||||
|
||||
// 解析文本内容
|
||||
textLines := p.newlineMatcher.Split(match[12], -1)
|
||||
text := ""
|
||||
|
||||
// 处理文本行
|
||||
for _, line := range textLines {
|
||||
if text == "" {
|
||||
text = line
|
||||
} else if strings.HasSuffix(text, " ") || strings.HasPrefix(line, " ") {
|
||||
text += line
|
||||
} else {
|
||||
text += " " + line
|
||||
}
|
||||
}
|
||||
|
||||
// 创建字幕
|
||||
subtitle := model.Subtitle{
|
||||
Index: index,
|
||||
Start: startDuration,
|
||||
End: endDuration,
|
||||
Data: strings.TrimSpace(text),
|
||||
Speaker: "", // SRT格式通常不包含发言人信息
|
||||
}
|
||||
|
||||
subtitles = append(subtitles, subtitle)
|
||||
}
|
||||
|
||||
if len(subtitles) == 0 {
|
||||
return nil, fmt.Errorf("解析SRT失败: 未找到有效的字幕")
|
||||
}
|
||||
|
||||
return &model.Transcript{
|
||||
Subtitles: subtitles,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user