sub_timeline_fixer_helper.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. package sub_timeline_fixer
  2. //
  3. //import (
  4. // "fmt"
  5. // "github.com/allanpk716/ChineseSubFinder/internal/common"
  6. // "github.com/allanpk716/ChineseSubFinder/internal/ifaces"
  7. // "github.com/allanpk716/ChineseSubFinder/internal/logic/emby_helper"
  8. // "github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/ass"
  9. // "github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/srt"
  10. // "github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
  11. // "github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
  12. // formatterEmby "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_formatter/emby"
  13. // "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_formatter/normal"
  14. // "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
  15. // "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
  16. // "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_timeline_fixer"
  17. // "github.com/allanpk716/ChineseSubFinder/internal/pkg/vad"
  18. // "github.com/allanpk716/ChineseSubFinder/internal/types/emby"
  19. // "github.com/allanpk716/ChineseSubFinder/internal/types/sub_timeline_fiexer"
  20. // "github.com/allanpk716/ChineseSubFinder/internal/types/subparser"
  21. // "os"
  22. // "path"
  23. // "path/filepath"
  24. // "strings"
  25. // "time"
  26. //)
  27. //
  28. //type SubTimelineFixerHelper struct {
  29. // embyHelper *emby_helper.EmbyHelper
  30. // EmbyConfig emby.EmbyConfig
  31. // FixerConfig sub_timeline_fiexer.SubTimelineFixerConfig
  32. // subParserHub *sub_parser_hub.SubParserHub
  33. // subTimelineFixer *sub_timeline_fixer.SubTimelineFixer
  34. // formatter map[string]ifaces.ISubFormatter
  35. // threads int
  36. // timeOut time.Duration
  37. //}
  38. //
  39. //func NewSubTimelineFixerHelper(embyConfig emby.EmbyConfig, subTimelineFixerConfig sub_timeline_fiexer.SubTimelineFixerConfig) *SubTimelineFixerHelper {
  40. // sub := SubTimelineFixerHelper{
  41. // EmbyConfig: embyConfig,
  42. // FixerConfig: subTimelineFixerConfig,
  43. // embyHelper: emby_helper.NewEmbyHelper(embyConfig),
  44. // subParserHub: sub_parser_hub.NewSubParserHub(ass.NewParser(), srt.NewParser()),
  45. // subTimelineFixer: sub_timeline_fixer.NewSubTimelineFixer(subTimelineFixerConfig),
  46. // formatter: make(map[string]ifaces.ISubFormatter),
  47. // threads: 6,
  48. // timeOut: 60 * time.Second,
  49. // }
  50. // // TODO 如果字幕格式新增了实现,这里也需要添加对应的实例
  51. // // 初始化支持的 formatter
  52. // // normal
  53. // sub.formatter = make(map[string]ifaces.ISubFormatter)
  54. // normalM := normal.NewFormatter()
  55. // sub.formatter[normalM.GetFormatterName()] = normalM
  56. // // emby
  57. // embyM := formatterEmby.NewFormatter()
  58. // sub.formatter[embyM.GetFormatterName()] = embyM
  59. //
  60. // return &sub
  61. //}
  62. //
  63. //func (s SubTimelineFixerHelper) FixRecentlyItemsSubTimeline(movieRootDir, seriesRootDir string) error {
  64. //
  65. // // 首先得开启,不然就直接跳过不执行
  66. // if s.EmbyConfig.FixTimeLine == false {
  67. // log_helper.GetLogger().Debugf("EmbyConfig.FixTimeLine = false, Skip")
  68. // return nil
  69. // }
  70. //
  71. // movieList, seriesList, err := s.embyHelper.GetRecentlyAddVideoList(movieRootDir, seriesRootDir)
  72. // if err != nil {
  73. // return err
  74. // }
  75. //
  76. // // 输出调试信息
  77. // log_helper.GetLogger().Debugln("FixRecentlyItemsSubTimeline - DebugInfo - movieList Start")
  78. // for s, value := range movieList {
  79. // log_helper.GetLogger().Debugln(s, value)
  80. // }
  81. // log_helper.GetLogger().Debugln("FixRecentlyItemsSubTimeline - DebugInfo - movieList End")
  82. //
  83. // log_helper.GetLogger().Debugln("FixRecentlyItemsSubTimeline - DebugInfo - seriesList Start")
  84. // for s, _ := range seriesList {
  85. // log_helper.GetLogger().Debugln(s)
  86. // }
  87. // log_helper.GetLogger().Debugln("FixRecentlyItemsSubTimeline - DebugInfo - seriesList End")
  88. //
  89. // log_helper.GetLogger().Debugln("Start movieList fix Timeline")
  90. // // 先做电影的字幕校正、然后才是连续剧的
  91. // for _, info := range movieList {
  92. // // path.Dir 在 Windows 有梗,所以换个方式获取路径
  93. // videoRootPath := filepath.Dir(info.VideoFileFullPath)
  94. // err = s.fixOneVideoSub(info.VideoInfo.Id, videoRootPath)
  95. // if err != nil {
  96. // return err
  97. // }
  98. // }
  99. // log_helper.GetLogger().Debugln("End movieList fix Timeline")
  100. //
  101. // log_helper.GetLogger().Debugln("Start seriesList fix Timeline")
  102. // for _, infos := range seriesList {
  103. // for _, info := range infos {
  104. // // path.Dir 在 Windows 有梗,所以换个方式获取路径
  105. // videoRootPath := filepath.Dir(info.VideoFileFullPath)
  106. // err = s.fixOneVideoSub(info.VideoInfo.Id, videoRootPath)
  107. // if err != nil {
  108. // return err
  109. // }
  110. // }
  111. // }
  112. // log_helper.GetLogger().Debugln("End seriesList fix Timeline")
  113. //
  114. // // 强制调用,测试 CGO=1 编译问题
  115. // log_helper.GetLogger().Debugln("VAD Mode", vad.Mode)
  116. //
  117. // return nil
  118. //}
  119. //
  120. //func (s SubTimelineFixerHelper) fixOneVideoSub(videoId string, videoRootPath string) error {
  121. // log_helper.GetLogger().Debugln("fixOneVideoSub VideoROotPath:", videoRootPath)
  122. // // internalEngSub 默认第一个是 srt 然后第二个是 ass,就不要去遍历了
  123. // found, internalEngSub, containChineseSubFile, err := s.embyHelper.GetInternalEngSubAndExChineseEnglishSub(videoId)
  124. // if err != nil {
  125. // return err
  126. // }
  127. //
  128. // if found == false {
  129. // log_helper.GetLogger().Debugln("GetInternalEngSubAndExChineseEnglishSub - found == false")
  130. // return nil
  131. // }
  132. //
  133. // log_helper.GetLogger().Debugln("internalEngSub:", len(internalEngSub), "containChineseSubFile:", len(containChineseSubFile))
  134. // // 需要先把原有的外置字幕带有 -fix 的删除,然后再做修正
  135. // // 不然如果调整了条件,之前修复的本次其实就不修正了,那么就会“残留”下来,误以为是本次配置的信息导致的
  136. // for _, exSubInfo := range containChineseSubFile {
  137. // // 没有编辑的就跳过
  138. // if strings.Contains(exSubInfo.FileName, sub_timeline_fixer.FixMask) == false {
  139. // continue
  140. // }
  141. //
  142. // subFileNeedRemove := filepath.Join(videoRootPath, exSubInfo.FileName)
  143. //
  144. // if videoRootPath == "" {
  145. // log_helper.GetLogger().Debugln("videoRootPath == \"\", Skip Remove:", subFileNeedRemove)
  146. // continue
  147. // }
  148. //
  149. // log_helper.GetLogger().Debugln("Remove fixed sub:", subFileNeedRemove)
  150. // err = os.Remove(subFileNeedRemove)
  151. // if err != nil {
  152. // return err
  153. // }
  154. // }
  155. //
  156. // // 从外置双语(中英)字幕中找对对应的内置 srt 字幕进行匹配比较
  157. // for _, exSubInfo := range containChineseSubFile {
  158. // inSelectSubIndex := 1
  159. // if exSubInfo.Ext == common.SubExtSRT {
  160. // inSelectSubIndex = 0
  161. // }
  162. // // 修正过的字幕有标记,将不会再次修复
  163. // if strings.Contains(exSubInfo.FileName, sub_timeline_fixer.FixMask) == true {
  164. // continue
  165. // }
  166. //
  167. // log_helper.GetLogger().Debugln("fixSubTimeline start")
  168. // bFound, subFixInfos, subNewName, err := s.fixSubTimeline(internalEngSub[inSelectSubIndex], exSubInfo)
  169. // if err != nil {
  170. // return err
  171. // }
  172. // if bFound == false {
  173. // log_helper.GetLogger().Debugln("fixSubTimeline bFound == false", exSubInfo.FileName)
  174. // continue
  175. // }
  176. // // 调试的时候用
  177. // if videoRootPath == "" {
  178. // log_helper.GetLogger().Debugln("videoRootPath == \"\", Skip fix sub:", exSubInfo.FileName)
  179. // continue
  180. // }
  181. // for _, info := range subFixInfos {
  182. // // 写入 fix 后的字幕文件覆盖之前的字幕文件
  183. // desFixedSubFullName := filepath.Join(videoRootPath, subNewName)
  184. // err = s.saveSubFile(desFixedSubFullName, info.FixContent)
  185. // if err != nil {
  186. // return err
  187. // }
  188. // log_helper.GetLogger().Infoln("Sub Timeline fixed:", desFixedSubFullName)
  189. // }
  190. // }
  191. //
  192. // return nil
  193. //}
  194. //
  195. //// fixSubTimeline 修复时间轴,containChineseSubFile 这里可能是,只要是带有中文的都算,简体、繁体、简英、繁英,需要后续额外的判断
  196. //func (s SubTimelineFixerHelper) fixSubTimeline(enSubFile emby.SubInfo, containChineseSubFile emby.SubInfo) (bool, []sub_timeline_fixer.SubFixInfo, string, error) {
  197. // fixedSubName := ""
  198. // log_helper.GetLogger().Debugln("fixSubTimeline - DetermineFileTypeFromBytes", enSubFile.FileName)
  199. // bFind, infoBase, err := s.subParserHub.DetermineFileTypeFromBytes(enSubFile.Content, enSubFile.Ext)
  200. // if err != nil {
  201. // return false, nil, fixedSubName, err
  202. // }
  203. // if bFind == false {
  204. // return false, nil, fixedSubName, nil
  205. // }
  206. // infoBase.Name = enSubFile.FileName
  207. // /*
  208. // 这里发现一个梗,内置的英文字幕导出的时候,有可能需要合并多个 Dialogue,见
  209. // internal/pkg/sub_helper/sub_helper.go 中 MergeMultiDialogue4EngSubtitle 的实现
  210. // */
  211. // sub_helper.MergeMultiDialogue4EngSubtitle(infoBase)
  212. //
  213. // log_helper.GetLogger().Debugln("fixSubTimeline - DetermineFileTypeFromBytes", containChineseSubFile.FileName)
  214. // bFind, infoSrc, err := s.subParserHub.DetermineFileTypeFromBytes(containChineseSubFile.Content, containChineseSubFile.Ext)
  215. // if err != nil {
  216. // return false, nil, fixedSubName, err
  217. // }
  218. // if bFind == false {
  219. // return false, nil, fixedSubName, nil
  220. // }
  221. // infoSrc.Name = containChineseSubFile.FileName
  222. // /*
  223. // 这里发现一个梗,内置的英文字幕导出的时候,有可能需要合并多个 Dialogue,见
  224. // internal/pkg/sub_helper/sub_helper.go 中 MergeMultiDialogue4EngSubtitle 的实现
  225. // */
  226. // sub_helper.MergeMultiDialogue4EngSubtitle(infoSrc)
  227. //
  228. // infoBaseNameWithOutExt := strings.Replace(infoBase.Name, path.Ext(infoBase.Name), "", -1)
  229. // //infoSrcNameWithOutExt := strings.Replace(infoSrc.Name, path.Ext(infoSrc.Name), "", -1)
  230. //
  231. // // 把原始的文件缓存下来,新建缓存的文件夹
  232. // subFixCacheRootPath, err := my_util.GetRootSubFixCacheFolder()
  233. // if err != nil {
  234. // return false, nil, fixedSubName, err
  235. // }
  236. // cacheTmpPath := filepath.Join(subFixCacheRootPath, infoBaseNameWithOutExt)
  237. // if my_util.IsDir(cacheTmpPath) == false {
  238. // err = os.MkdirAll(cacheTmpPath, os.ModePerm)
  239. // if err != nil {
  240. // return false, nil, fixedSubName, err
  241. // }
  242. // }
  243. // // 写入内置字幕、外置字幕原始文件
  244. // err = s.saveSubFile(filepath.Join(cacheTmpPath, infoBaseNameWithOutExt+".chinese(inside)"+infoBase.Ext), infoBase.Content)
  245. // if err != nil {
  246. // return false, nil, fixedSubName, err
  247. // }
  248. // err = s.saveSubFile(filepath.Join(cacheTmpPath, infoSrc.Name), infoSrc.Content)
  249. // if err != nil {
  250. // return false, nil, fixedSubName, err
  251. // }
  252. // bok, offsetTime, sd, err := s.subTimelineFixer.GetOffsetTimeV1(infoBase, infoSrc, filepath.Join(cacheTmpPath, infoSrc.Name+"-bar.html"), filepath.Join(cacheTmpPath, infoSrc.Name+".log"))
  253. // if offsetTime != 0 {
  254. // log_helper.GetLogger().Infoln(infoSrc.Name, "offset time is", fmt.Sprintf("%f", offsetTime), "s")
  255. // }
  256. // // 超过 SD 阈值了
  257. // if sd > s.FixerConfig.V1_MaxStartTimeDiffSD {
  258. // log_helper.GetLogger().Infoln(infoSrc.Name, "Start Time Diff SD, skip", fmt.Sprintf("%f", sd))
  259. // return false, nil, fixedSubName, nil
  260. // } else {
  261. // log_helper.GetLogger().Infoln(infoSrc.Name, "Start Time Diff SD", fmt.Sprintf("%f", sd))
  262. // }
  263. //
  264. // if err != nil || bok == false {
  265. // return false, nil, fixedSubName, err
  266. // }
  267. //
  268. // // 偏移很小就无视了
  269. // if offsetTime < s.FixerConfig.V1_MinOffset && offsetTime > -s.FixerConfig.V1_MinOffset {
  270. // log_helper.GetLogger().Infoln(infoSrc.Name, fmt.Sprintf("Min Offset Config is %f, skip ", s.FixerConfig.V1_MinOffset), fmt.Sprintf("now is %f", offsetTime))
  271. // return false, nil, fixedSubName, nil
  272. // }
  273. // // 写入校准时间轴后的字幕
  274. // var subFixInfos = make([]sub_timeline_fixer.SubFixInfo, 0)
  275. // for _, formatter := range s.formatter {
  276. // // 符合已知的字幕命名格式,不符合就跳过,都跳过也行,就不做任何操作而已
  277. // bMatch, fileNameWithOutExt, subExt, subLang, extraSubName := formatter.IsMatchThisFormat(infoSrc.Name)
  278. // if bMatch == false {
  279. // log_helper.GetLogger().Debugln(fmt.Sprintf("%s IsMatchThisFormat == false, Skip, %s", formatter.GetFormatterName(), infoSrc.Name))
  280. // continue
  281. // }
  282. // // 是否包含 default 关键词,暂时无需判断 forced
  283. // hasDefault := false
  284. // if strings.Contains(strings.ToLower(infoSrc.Name), subparser.Sub_Ext_Mark_Default) == true {
  285. // hasDefault = true
  286. // }
  287. // // 生成对应字幕命名格式的,字幕命名。这里注意,normal 的时候, extraSubName+"-fix" 是无效的,不会被设置,也就是直接覆盖之前的字幕了。
  288. // subNewName, subNewNameDefault, _ := formatter.GenerateMixSubNameBase(fileNameWithOutExt, subExt, subLang, extraSubName+sub_timeline_fixer.FixMask)
  289. //
  290. // desFixSubFileFullPath := ""
  291. // if hasDefault == true {
  292. // fixedSubName = subNewNameDefault
  293. // desFixSubFileFullPath = filepath.Join(cacheTmpPath, subNewNameDefault)
  294. //
  295. // } else {
  296. // fixedSubName = subNewName
  297. // desFixSubFileFullPath = filepath.Join(cacheTmpPath, subNewName)
  298. // }
  299. // fixContent, err := s.subTimelineFixer.FixSubTimelineOneOffsetTime(infoSrc, offsetTime, desFixSubFileFullPath)
  300. // if err != nil {
  301. // return false, nil, fixedSubName, err
  302. // }
  303. // subFixInfos = append(subFixInfos, *sub_timeline_fixer.NewSubFixInfo(infoSrc.Name, fixContent))
  304. // }
  305. //
  306. // return true, subFixInfos, fixedSubName, nil
  307. //}
  308. //
  309. //func (s SubTimelineFixerHelper) saveSubFile(desSaveSubFileFullPath string, content string) error {
  310. // dstFile, err := os.Create(desSaveSubFileFullPath)
  311. // if err != nil {
  312. // return err
  313. // }
  314. // defer func() {
  315. // _ = dstFile.Close()
  316. // }()
  317. // _, err = dstFile.WriteString(content)
  318. // if err != nil {
  319. // return err
  320. // }
  321. //
  322. // return nil
  323. //}