186 lines
5.3 KiB
Go
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)
|
|
}
|