152 lines
4 KiB
Go
152 lines
4 KiB
Go
package ass
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"sub-cli/internal/model"
|
|
)
|
|
|
|
// 常量定义
|
|
const (
|
|
ASSHeader = "[Script Info]"
|
|
ASSStylesHeader = "[V4+ Styles]"
|
|
ASSEventsHeader = "[Events]"
|
|
DefaultFormat = "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"
|
|
)
|
|
|
|
// Parse 解析ASS文件为ASSFile结构
|
|
func Parse(filePath string) (model.ASSFile, error) {
|
|
file, err := os.Open(filePath)
|
|
if err != nil {
|
|
return model.ASSFile{}, fmt.Errorf("打开ASS文件失败: %w", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
result := model.NewASSFile()
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
|
|
// 当前解析的区块
|
|
currentSection := ""
|
|
var styleFormat, eventFormat []string
|
|
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
if line == "" || strings.HasPrefix(line, ";") {
|
|
// 跳过空行和注释行
|
|
continue
|
|
}
|
|
|
|
// 检查章节标题
|
|
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
|
|
currentSection = line
|
|
continue
|
|
}
|
|
|
|
switch currentSection {
|
|
case ASSHeader:
|
|
// 解析脚本信息
|
|
if strings.Contains(line, ":") {
|
|
parts := strings.SplitN(line, ":", 2)
|
|
key := strings.TrimSpace(parts[0])
|
|
value := strings.TrimSpace(parts[1])
|
|
result.ScriptInfo[key] = value
|
|
}
|
|
|
|
case ASSStylesHeader:
|
|
// 解析样式格式行和样式定义
|
|
if strings.HasPrefix(line, "Format:") {
|
|
formatStr := strings.TrimPrefix(line, "Format:")
|
|
styleFormat = parseFormatLine(formatStr)
|
|
} else if strings.HasPrefix(line, "Style:") {
|
|
styleValues := parseStyleLine(line)
|
|
if len(styleFormat) > 0 && len(styleValues) > 0 {
|
|
style := model.ASSStyle{
|
|
Name: styleValues[0], // 第一个值通常是样式名称
|
|
Properties: make(map[string]string),
|
|
}
|
|
|
|
// 将原始格式行保存下来
|
|
style.Properties["Format"] = "Name, " + strings.Join(styleFormat[1:], ", ")
|
|
style.Properties["Style"] = strings.Join(styleValues, ", ")
|
|
|
|
// 解析各个样式属性
|
|
for i := 0; i < len(styleFormat) && i < len(styleValues); i++ {
|
|
style.Properties[styleFormat[i]] = styleValues[i]
|
|
}
|
|
|
|
result.Styles = append(result.Styles, style)
|
|
}
|
|
}
|
|
|
|
case ASSEventsHeader:
|
|
// 解析事件格式行和对话行
|
|
if strings.HasPrefix(line, "Format:") {
|
|
formatStr := strings.TrimPrefix(line, "Format:")
|
|
eventFormat = parseFormatLine(formatStr)
|
|
} else if len(eventFormat) > 0 &&
|
|
(strings.HasPrefix(line, "Dialogue:") ||
|
|
strings.HasPrefix(line, "Comment:")) {
|
|
|
|
eventType := "Dialogue"
|
|
if strings.HasPrefix(line, "Comment:") {
|
|
eventType = "Comment"
|
|
line = strings.TrimPrefix(line, "Comment:")
|
|
} else {
|
|
line = strings.TrimPrefix(line, "Dialogue:")
|
|
}
|
|
|
|
values := parseEventLine(line)
|
|
if len(values) >= len(eventFormat) {
|
|
event := model.NewASSEvent()
|
|
event.Type = eventType
|
|
|
|
// 填充事件属性
|
|
for i, format := range eventFormat {
|
|
value := values[i]
|
|
switch strings.TrimSpace(format) {
|
|
case "Layer":
|
|
layer, _ := strconv.Atoi(value)
|
|
event.Layer = layer
|
|
case "Start":
|
|
event.StartTime = parseASSTimestamp(value)
|
|
case "End":
|
|
event.EndTime = parseASSTimestamp(value)
|
|
case "Style":
|
|
event.Style = value
|
|
case "Name":
|
|
event.Name = value
|
|
case "MarginL":
|
|
marginL, _ := strconv.Atoi(value)
|
|
event.MarginL = marginL
|
|
case "MarginR":
|
|
marginR, _ := strconv.Atoi(value)
|
|
event.MarginR = marginR
|
|
case "MarginV":
|
|
marginV, _ := strconv.Atoi(value)
|
|
event.MarginV = marginV
|
|
case "Effect":
|
|
event.Effect = value
|
|
case "Text":
|
|
// 文本可能包含逗号,所以需要特殊处理
|
|
textStartIndex := strings.Index(line, value)
|
|
if textStartIndex >= 0 {
|
|
event.Text = line[textStartIndex:]
|
|
} else {
|
|
event.Text = value
|
|
}
|
|
}
|
|
}
|
|
|
|
result.Events = append(result.Events, event)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result, nil
|
|
}
|