sub-cli/internal/format/ass/converter.go
2025-04-23 19:22:41 +08:00

186 lines
5.3 KiB
Go

package ass
import (
"fmt"
"sub-cli/internal/model"
)
// ConvertToSubtitle 将ASS文件转换为通用字幕格式
func ConvertToSubtitle(filePath string) (model.Subtitle, error) {
// 解析ASS文件
assFile, err := Parse(filePath)
if err != nil {
return model.Subtitle{}, fmt.Errorf("解析ASS文件失败: %w", err)
}
// 创建通用字幕结构
subtitle := model.NewSubtitle()
subtitle.Format = "ass"
// 转换标题
if title, ok := assFile.ScriptInfo["Title"]; ok {
subtitle.Title = title
}
// 转换事件为字幕条目
for i, event := range assFile.Events {
// 只转换对话类型的事件
if event.Type == "Dialogue" {
entry := model.SubtitleEntry{
Index: i + 1,
StartTime: event.StartTime,
EndTime: event.EndTime,
Text: event.Text,
Styles: make(map[string]string),
Metadata: make(map[string]string),
}
// 记录样式信息
entry.Styles["style"] = event.Style
// 记录ASS特有信息
entry.Metadata["Layer"] = fmt.Sprintf("%d", event.Layer)
entry.Metadata["Name"] = event.Name
entry.Metadata["MarginL"] = fmt.Sprintf("%d", event.MarginL)
entry.Metadata["MarginR"] = fmt.Sprintf("%d", event.MarginR)
entry.Metadata["MarginV"] = fmt.Sprintf("%d", event.MarginV)
entry.Metadata["Effect"] = event.Effect
subtitle.Entries = append(subtitle.Entries, entry)
}
}
return subtitle, nil
}
// ConvertFromSubtitle 将通用字幕格式转换为ASS文件
func ConvertFromSubtitle(subtitle model.Subtitle, filePath string) error {
// 创建ASS文件结构
assFile := model.NewASSFile()
// 设置标题
if subtitle.Title != "" {
assFile.ScriptInfo["Title"] = subtitle.Title
}
// 转换字幕条目为ASS事件
for _, entry := range subtitle.Entries {
event := model.NewASSEvent()
event.Type = "Dialogue"
event.StartTime = entry.StartTime
event.EndTime = entry.EndTime
event.Text = entry.Text
// 检查是否有ASS特有的元数据
if layer, ok := entry.Metadata["Layer"]; ok {
fmt.Sscanf(layer, "%d", &event.Layer)
}
if name, ok := entry.Metadata["Name"]; ok {
event.Name = name
}
if marginL, ok := entry.Metadata["MarginL"]; ok {
fmt.Sscanf(marginL, "%d", &event.MarginL)
}
if marginR, ok := entry.Metadata["MarginR"]; ok {
fmt.Sscanf(marginR, "%d", &event.MarginR)
}
if marginV, ok := entry.Metadata["MarginV"]; ok {
fmt.Sscanf(marginV, "%d", &event.MarginV)
}
if effect, ok := entry.Metadata["Effect"]; ok {
event.Effect = effect
}
// 处理样式
if style, ok := entry.Styles["style"]; ok {
event.Style = style
} else {
// 根据基本样式设置ASS样式
if _, ok := entry.Styles["bold"]; ok {
// 创建一个加粗样式(如果尚未存在)
styleName := "Bold"
found := false
for _, style := range assFile.Styles {
if style.Name == styleName {
found = true
break
}
}
if !found {
boldStyle := model.ASSStyle{
Name: styleName,
Properties: map[string]string{
"Format": "Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding",
"Style": "Bold,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,1,0,0,0,100,100,0,0,1,2,2,2,10,10,10,1",
},
}
assFile.Styles = append(assFile.Styles, boldStyle)
}
event.Style = styleName
}
if _, ok := entry.Styles["italic"]; ok {
// 创建一个斜体样式(如果尚未存在)
styleName := "Italic"
found := false
for _, style := range assFile.Styles {
if style.Name == styleName {
found = true
break
}
}
if !found {
italicStyle := model.ASSStyle{
Name: styleName,
Properties: map[string]string{
"Format": "Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding",
"Style": "Italic,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,1,0,0,100,100,0,0,1,2,2,2,10,10,10,1",
},
}
assFile.Styles = append(assFile.Styles, italicStyle)
}
event.Style = styleName
}
if _, ok := entry.Styles["underline"]; ok {
// 创建一个下划线样式(如果尚未存在)
styleName := "Underline"
found := false
for _, style := range assFile.Styles {
if style.Name == styleName {
found = true
break
}
}
if !found {
underlineStyle := model.ASSStyle{
Name: styleName,
Properties: map[string]string{
"Format": "Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding",
"Style": "Underline,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,1,0,100,100,0,0,1,2,2,2,10,10,10,1",
},
}
assFile.Styles = append(assFile.Styles, underlineStyle)
}
event.Style = styleName
}
}
assFile.Events = append(assFile.Events, event)
}
// 生成ASS文件
return Generate(assFile, filePath)
}