fileinfo.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. package subparser
  2. import (
  3. "fmt"
  4. "math"
  5. "sort"
  6. "strings"
  7. "time"
  8. common2 "github.com/allanpk716/ChineseSubFinder/internal/types/common"
  9. "github.com/allanpk716/ChineseSubFinder/internal/types/language"
  10. "github.com/allanpk716/ChineseSubFinder/pkg/my_util"
  11. )
  12. type FileInfo struct {
  13. PrefixDialogueString string // 在 Dialogue: 这个关键词之前的字符串,ass 中的字体以及其他信息的描述
  14. Content string // 字幕的内容
  15. FromWhereSite string // 从那个网站下载的
  16. Name string // 字幕的名称,注意,这里需要额外的赋值,不会自动检测
  17. Ext string // 字幕的后缀名
  18. Lang language.MyLanguage // 识别出来的语言
  19. FileFullPath string // 字幕文件的全路径
  20. Data []byte // 字幕的二进制文件内容
  21. Dialogues []OneDialogue // 整个字幕文件的所有对话,如果是做时间轴匹配,就使用原始的
  22. DialoguesFilter []OneDialogue // 整个字幕文件的所有对话,过滤掉特殊字符的对白
  23. DialoguesFilterEx []OneDialogueEx // 整个字幕文件的所有对话,过滤掉特殊字符的对白,这里会把一句话中支持的 中、英、韩、日 四国语言给分离出来
  24. CHLines []string // 抽取出所有的中文对话
  25. OtherLines []string // 抽取出所有的第二语言对话,可能是英文、韩文、日文
  26. }
  27. // SaveTranslated 保存字幕文件,注意,这里是用于翻译后的字幕文件
  28. func (f *FileInfo) SaveTranslated(desSubFileFPath string) error {
  29. allString := ""
  30. allString += f.PrefixDialogueString + "\n"
  31. for _, oneDialogue := range f.Dialogues {
  32. if len(oneDialogue.Lines) < 1 {
  33. continue
  34. }
  35. oneDialogueString := "Dialogue: 0," + oneDialogue.StartTime + "," + oneDialogue.EndTime + ",Default,,0,0,0,," + oneDialogue.Lines[0]
  36. allString += oneDialogueString + "\n"
  37. }
  38. return my_util.WriteFile(desSubFileFPath, []byte(allString))
  39. }
  40. // GetSourceTranslateString 获取翻以前的字符串,会移除 \N 这样的信息,替换为空格
  41. func (f *FileInfo) GetSourceTranslateString() string {
  42. sourceString := ""
  43. // 去除每一句中的 \N
  44. for index, oneDialogue := range f.Dialogues {
  45. f.Dialogues[index].Lines[0] = strings.ReplaceAll(oneDialogue.Lines[0], `\N`, " ")
  46. sourceString += f.Dialogues[index].Lines[0] + "\n"
  47. }
  48. return sourceString
  49. }
  50. func (f *FileInfo) SetTranslatedStrings(translatedString string) error {
  51. // 分行
  52. lines := strings.Split(translatedString, "\n")
  53. linesWithOutEmpty := make([]string, 0)
  54. // 移除空行
  55. for _, line := range lines {
  56. if len(line) < 1 {
  57. continue
  58. }
  59. linesWithOutEmpty = append(linesWithOutEmpty, line)
  60. }
  61. // 比较两个数组是否长度一致
  62. if len(f.Dialogues) != len(linesWithOutEmpty) {
  63. return fmt.Errorf("dialogue line not the same,org:%d,translated:%d", len(f.Dialogues), len(linesWithOutEmpty))
  64. }
  65. // 对每一句话进行赋值
  66. for index := range f.Dialogues {
  67. f.Dialogues[index].Lines = []string{linesWithOutEmpty[index]}
  68. }
  69. return nil
  70. }
  71. // SortDialogues 排序对话,时间递减
  72. func (f *FileInfo) SortDialogues() {
  73. sort.Sort(OneDialogueByStartTime(f.Dialogues))
  74. sort.Sort(OneDialogueByStartTime(f.DialoguesFilter))
  75. sort.Sort(OneDialogueByStartTimeEx(f.DialoguesFilterEx))
  76. }
  77. // GetTimeFormat 获取时间轴的格式化格式
  78. func (f FileInfo) GetTimeFormat() string {
  79. if f.Ext == common2.SubExtASS || f.Ext == common2.SubExtSSA {
  80. return common2.TimeFormatPoint2
  81. } else {
  82. return common2.TimeFormatPoint3
  83. }
  84. }
  85. // GetDialogueExContent 获取当前字幕文件语言对应索引的对白内容
  86. // 凡是带有 Eng 的返回 Eng,其他的就与对应语言相关
  87. func (f FileInfo) GetDialogueExContent(index int) string {
  88. switch f.Lang {
  89. case language.ChineseSimple, language.ChineseTraditional,
  90. language.ChineseSimpleJapanese, language.ChineseSimpleKorean,
  91. language.ChineseTraditionalJapanese, language.ChineseTraditionalKorean:
  92. // 带有中文的,但是又不是中英的
  93. return f.DialoguesFilterEx[index].ChLine
  94. case language.English, language.ChineseSimpleEnglish, language.ChineseTraditionalEnglish:
  95. return f.DialoguesFilterEx[index].EnLine
  96. case language.Japanese:
  97. return f.DialoguesFilterEx[index].JpLine
  98. case language.Korean:
  99. return f.DialoguesFilterEx[index].KrLine
  100. default:
  101. return f.DialoguesFilterEx[index].EnLine
  102. }
  103. }
  104. // ChangeDialoguesTimeByFramerateRatio 根据帧数比率调整时间轴 对应 ffsubsync -- SubtitleScaler
  105. func (f *FileInfo) ChangeDialoguesTimeByFramerateRatio(framerateRatio float64) error {
  106. timeFormat := f.GetTimeFormat()
  107. f.changeOneDialoguesFramerateRatio(f.Dialogues, framerateRatio, timeFormat)
  108. f.changeOneDialoguesFramerateRatio(f.DialoguesFilter, framerateRatio, timeFormat)
  109. f.changeOneDialogueExsFramerateRatio(f.DialoguesFilterEx, framerateRatio, timeFormat)
  110. return nil
  111. }
  112. func (f *FileInfo) changeOneDialoguesFramerateRatio(oneDialogues []OneDialogue, framerateRatio float64, timeFormat string) {
  113. for i := 0; i < len(oneDialogues); i++ {
  114. timeStart := oneDialogues[i].GetStartTime()
  115. timeEnd := oneDialogues[i].GetEndTime()
  116. timeStartNumber := my_util.Time2SecondNumber(timeStart)
  117. timeEndNumber := my_util.Time2SecondNumber(timeEnd)
  118. scaleTimeStart := my_util.TimeNumber2Time(timeStartNumber * framerateRatio)
  119. scaleTimeEnd := my_util.TimeNumber2Time(timeEndNumber * framerateRatio)
  120. oneDialogues[i].StartTime = my_util.Time2SubTimeString(scaleTimeStart, timeFormat)
  121. oneDialogues[i].EndTime = my_util.Time2SubTimeString(scaleTimeEnd, timeFormat)
  122. }
  123. }
  124. func (f *FileInfo) changeOneDialogueExsFramerateRatio(oneDialogues []OneDialogueEx, framerateRatio float64, timeFormat string) {
  125. for i := 0; i < len(oneDialogues); i++ {
  126. timeStart := oneDialogues[i].GetStartTime()
  127. timeEnd := oneDialogues[i].GetEndTime()
  128. timeStartNumber := my_util.Time2SecondNumber(timeStart)
  129. timeEndNumber := my_util.Time2SecondNumber(timeEnd)
  130. scaleTimeStart := my_util.TimeNumber2Time(timeStartNumber * framerateRatio)
  131. scaleTimeEnd := my_util.TimeNumber2Time(timeEndNumber * framerateRatio)
  132. oneDialogues[i].StartTime = my_util.Time2SubTimeString(scaleTimeStart, timeFormat)
  133. oneDialogues[i].EndTime = my_util.Time2SubTimeString(scaleTimeEnd, timeFormat)
  134. }
  135. }
  136. // GetStartTime 获取的是从 Dialogues 得到的
  137. func (f FileInfo) GetStartTime() time.Time {
  138. startTime := math.MaxFloat64
  139. for i := 0; i < len(f.Dialogues); i++ {
  140. // 找到最小的开始时间
  141. tmpNowStartTimeNumber := my_util.Time2SecondNumber(f.Dialogues[i].GetStartTime())
  142. startTime = math.Min(startTime, tmpNowStartTimeNumber)
  143. }
  144. return my_util.TimeNumber2Time(startTime)
  145. }
  146. // GetEndTime 获取的是从 Dialogues 得到的
  147. func (f FileInfo) GetEndTime() time.Time {
  148. endTime := -math.MaxFloat64
  149. for i := 0; i < len(f.Dialogues); i++ {
  150. // 找到最大的结束时间
  151. tmpNowEndTimeNumber := my_util.Time2SecondNumber(f.Dialogues[i].GetEndTime())
  152. endTime = math.Max(endTime, tmpNowEndTimeNumber)
  153. }
  154. return my_util.TimeNumber2Time(endTime)
  155. }
  156. // GetNumFrames 获取这个字幕的时间 Frame 数量
  157. func (f FileInfo) GetNumFrames() int {
  158. return int(math.Abs((my_util.Time2SecondNumber(f.GetEndTime()) - my_util.Time2SecondNumber(f.GetStartTime())) * 100))
  159. }
  160. // OneDialogue 一句对话
  161. type OneDialogue struct {
  162. Index int // 对白的索引
  163. StartTime string // 开始时间
  164. EndTime string // 结束时间
  165. StyleName string // StyleName
  166. Lines []string // 台词
  167. }
  168. func NewOneDialogue() OneDialogue {
  169. return OneDialogue{
  170. Lines: make([]string, 0),
  171. }
  172. }
  173. func (o OneDialogue) GetStartTime() time.Time {
  174. srcTimeStartNow, err := my_util.ParseTime(o.StartTime)
  175. if err != nil {
  176. return time.Time{}
  177. }
  178. return srcTimeStartNow
  179. }
  180. func (o OneDialogue) GetEndTime() time.Time {
  181. srcTimeEndNow, err := my_util.ParseTime(o.EndTime)
  182. if err != nil {
  183. return time.Time{}
  184. }
  185. return srcTimeEndNow
  186. }
  187. type OneDialogueByStartTime []OneDialogue
  188. func (d OneDialogueByStartTime) Len() int {
  189. return len(d)
  190. }
  191. func (d OneDialogueByStartTime) Swap(i, j int) {
  192. d[i], d[j] = d[j], d[i]
  193. }
  194. func (d OneDialogueByStartTime) Less(i, j int) bool {
  195. subStartTimeI, err := my_util.ParseTime(d[i].StartTime)
  196. if err != nil {
  197. return false
  198. }
  199. subStartTimeJ, err := my_util.ParseTime(d[j].StartTime)
  200. if err != nil {
  201. return false
  202. }
  203. return my_util.Time2SecondNumber(subStartTimeI) < my_util.Time2SecondNumber(subStartTimeJ)
  204. }
  205. // OneDialogueEx 一句对话,这里会把一句话中支持的 中、英、韩、日 四国语言给分离出来
  206. type OneDialogueEx struct {
  207. StartTime string // 开始时间
  208. EndTime string // 结束时间
  209. ChLine string
  210. EnLine string
  211. KrLine string
  212. JpLine string
  213. }
  214. func (o OneDialogueEx) GetStartTime() time.Time {
  215. srcTimeStartNow, err := my_util.ParseTime(o.StartTime)
  216. if err != nil {
  217. return time.Time{}
  218. }
  219. return srcTimeStartNow
  220. }
  221. func (o OneDialogueEx) GetEndTime() time.Time {
  222. srcTimeEndNow, err := my_util.ParseTime(o.EndTime)
  223. if err != nil {
  224. return time.Time{}
  225. }
  226. return srcTimeEndNow
  227. }
  228. type OneDialogueByStartTimeEx []OneDialogueEx
  229. func (d OneDialogueByStartTimeEx) Len() int {
  230. return len(d)
  231. }
  232. func (d OneDialogueByStartTimeEx) Swap(i, j int) {
  233. d[i], d[j] = d[j], d[i]
  234. }
  235. func (d OneDialogueByStartTimeEx) Less(i, j int) bool {
  236. subStartTimeI, err := my_util.ParseTime(d[i].StartTime)
  237. if err != nil {
  238. return false
  239. }
  240. subStartTimeJ, err := my_util.ParseTime(d[j].StartTime)
  241. if err != nil {
  242. return false
  243. }
  244. return my_util.Time2SecondNumber(subStartTimeI) < my_util.Time2SecondNumber(subStartTimeJ)
  245. }
  246. const (
  247. Sub_Ext_Mark_Default = ".default" // 指定这个字幕是默认的
  248. Sub_Ext_Mark_Forced = ".forced" // 指定这个字幕是强制的
  249. )