scan_played_video_subinfo.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. package scan_played_video_subinfo
  2. import (
  3. "github.com/allanpk716/ChineseSubFinder/internal/dao"
  4. embyHelper "github.com/allanpk716/ChineseSubFinder/internal/logic/emby_helper"
  5. "github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/ass"
  6. "github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/srt"
  7. "github.com/allanpk716/ChineseSubFinder/internal/logic/sub_supplier/shooter"
  8. "github.com/allanpk716/ChineseSubFinder/internal/models"
  9. "github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
  10. "github.com/allanpk716/ChineseSubFinder/internal/pkg/imdb_helper"
  11. "github.com/allanpk716/ChineseSubFinder/internal/pkg/language"
  12. "github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
  13. "github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
  14. "github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
  15. "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
  16. "github.com/allanpk716/ChineseSubFinder/internal/pkg/task_control"
  17. "github.com/sirupsen/logrus"
  18. "path/filepath"
  19. "sync"
  20. )
  21. type ScanPlayedVideoSubInfo struct {
  22. settings settings.Settings
  23. log *logrus.Logger
  24. embyHelper *embyHelper.EmbyHelper
  25. taskControl *task_control.TaskControl
  26. canceled bool
  27. canceledLock sync.Mutex
  28. subParserHub *sub_parser_hub.SubParserHub
  29. movieSubMap map[string]string
  30. seriesSubMap map[string]string
  31. }
  32. func NewScanPlayedVideoSubInfo(_settings settings.Settings) (*ScanPlayedVideoSubInfo, error) {
  33. var err error
  34. var scanPlayedVideoSubInfo ScanPlayedVideoSubInfo
  35. scanPlayedVideoSubInfo.log = log_helper.GetLogger()
  36. // 参入设置信息
  37. scanPlayedVideoSubInfo.settings = _settings
  38. // 检测是否某些参数超出范围
  39. scanPlayedVideoSubInfo.settings.Check()
  40. // 初始化 Emby API 接口
  41. if scanPlayedVideoSubInfo.settings.EmbySettings.Enable == true && scanPlayedVideoSubInfo.settings.EmbySettings.AddressUrl != "" && scanPlayedVideoSubInfo.settings.EmbySettings.APIKey != "" {
  42. scanPlayedVideoSubInfo.embyHelper = embyHelper.NewEmbyHelper(*scanPlayedVideoSubInfo.settings.EmbySettings)
  43. }
  44. // 初始化任务控制
  45. scanPlayedVideoSubInfo.taskControl, err = task_control.NewTaskControl(scanPlayedVideoSubInfo.settings.CommonSettings.Threads, log_helper.GetLogger())
  46. if err != nil {
  47. return nil, err
  48. }
  49. // 字幕解析器
  50. scanPlayedVideoSubInfo.subParserHub = sub_parser_hub.NewSubParserHub(ass.NewParser(), srt.NewParser())
  51. return &scanPlayedVideoSubInfo, nil
  52. }
  53. func (s *ScanPlayedVideoSubInfo) Cancel() {
  54. s.canceledLock.Lock()
  55. s.canceled = true
  56. s.canceledLock.Unlock()
  57. s.taskControl.Release()
  58. }
  59. func (s *ScanPlayedVideoSubInfo) GetPlayedItemsSubtitle() (bool, error) {
  60. var err error
  61. // 是否是通过 emby_helper api 获取的列表
  62. if s.embyHelper == nil {
  63. // 没有填写 emby_helper api 的信息,那么就跳过
  64. s.log.Infoln("Skip ScanPlayedVideoSubInfo, Emby Settings is null")
  65. return false, nil
  66. }
  67. s.movieSubMap, s.seriesSubMap, err = s.embyHelper.GetPlayedItemsSubtitle()
  68. if err != nil {
  69. return false, err
  70. }
  71. return true, nil
  72. }
  73. func (s *ScanPlayedVideoSubInfo) ScanMovie() error {
  74. defer func() {
  75. s.log.Infoln("ScanPlayedVideoSubInfo Movie Sub End")
  76. }()
  77. s.log.Infoln("-----------------------------------------------")
  78. s.log.Infoln("ScanPlayedVideoSubInfo Movie Sub Start...")
  79. imdbInfoCache := make(map[string]*models.IMDBInfo)
  80. for movieFPath, subFPath := range s.movieSubMap {
  81. // 通过视频的绝对路径,从本地的视频文件对应的 nfo 获取到这个视频的 IMDB ID,
  82. imdbInfo4Movie, err := decode.GetImdbInfo4Movie(movieFPath)
  83. if err != nil {
  84. // 如果找不到当前电影的 IMDB Info 本地文件,那么就跳过
  85. s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.GetImdbInfo4Movie", movieFPath, err)
  86. continue
  87. }
  88. // 使用 shooter 的技术 hash 的算法,得到视频的唯一 ID
  89. fileHash, err := shooter.ComputeFileHash(movieFPath)
  90. if err != nil {
  91. s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.ComputeFileHash", movieFPath, err)
  92. continue
  93. }
  94. var imdbInfo *models.IMDBInfo
  95. var ok bool
  96. if imdbInfo, ok = imdbInfoCache[imdbInfo4Movie.ImdbId]; ok == false {
  97. // 不存在,那么就去查询和新建缓存
  98. imdbInfo, err = imdb_helper.GetVideoIMDBInfoFromLocal(imdbInfo4Movie.ImdbId, *s.settings.AdvancedSettings.ProxySettings)
  99. if err != nil {
  100. return err
  101. }
  102. imdbInfoCache[imdbInfo4Movie.ImdbId] = imdbInfo
  103. }
  104. // 查找关联的 VideoSubInfo
  105. var videoSubInfos []models.VideoSubInfo
  106. err = dao.GetDb().Model(imdbInfo).Association("VideoSubInfos").Find(&videoSubInfos)
  107. if err != nil {
  108. return err
  109. }
  110. // 判断找到的关联字幕信息是否已经存在了,不存在则新增关联
  111. var exist bool
  112. for _, info := range videoSubInfos {
  113. // 首先,这里会进行已有缓存字幕是否存在的判断,把不存在的字幕给删除了
  114. if my_util.IsFile(info.StoreFPath) == false {
  115. // 关联删除了,但是不会删除这些对象,所以后续还需要再次删除
  116. err := dao.GetDb().Model(imdbInfo).Association("VideoSubInfos").Delete(&info)
  117. if err != nil {
  118. s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.Delete Association", info.Feature, err)
  119. continue
  120. }
  121. // 继续删除这个对象
  122. dao.GetDb().Delete(&info)
  123. s.log.Infoln("Delete Not Exist Sub Association", info.SubName, err)
  124. continue
  125. }
  126. if info.Feature == fileHash {
  127. exist = true
  128. break
  129. }
  130. }
  131. if exist == true {
  132. // 存在
  133. continue
  134. }
  135. // 不存在,插入,建立关系
  136. bok, fileInfo, err := s.subParserHub.DetermineFileTypeFromFile(subFPath)
  137. if err != nil {
  138. return err
  139. }
  140. if bok == false {
  141. s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.DetermineFileTypeFromFile", imdbInfo4Movie.Title, err)
  142. continue
  143. }
  144. oneVideoSubInfo := models.NewVideoSubInfo(
  145. fileHash,
  146. filepath.Base(subFPath),
  147. "language_iso",
  148. language.IsBilingualSubtitle(fileInfo.Lang),
  149. "chinese_iso",
  150. fileInfo.Lang.String(),
  151. subFPath,
  152. )
  153. err = dao.GetDb().Model(imdbInfo).Association("VideoSubInfos").Append(oneVideoSubInfo)
  154. if err != nil {
  155. s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.Append Association", oneVideoSubInfo.SubName, err)
  156. continue
  157. }
  158. }
  159. return nil
  160. }
  161. func (s *ScanPlayedVideoSubInfo) ScanSeries() error {
  162. defer func() {
  163. s.log.Infoln("ScanPlayedVideoSubInfo Series Sub End")
  164. }()
  165. s.log.Infoln("ScanPlayedVideoSubInfo Series Sub Start...")
  166. for episodeFPath, subFPath := range s.seriesSubMap {
  167. // 通过视频的绝对路径,,从本地的视频文件对应的 nfo 获取到这个视频的 IMDB ID
  168. imdbInfo4Series, err := decode.GetSeriesImdbInfoFromEpisode(episodeFPath)
  169. if err != nil {
  170. // 如果找不到当前电影的 IMDB Info 本地文件,那么就跳过
  171. s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.GetSeriesImdbInfoFromEpisode", episodeFPath, err)
  172. continue
  173. }
  174. // 使用 shooter 的技术 hash 的算法,得到视频的唯一 ID
  175. fileHash, err := shooter.ComputeFileHash(episodeFPath)
  176. if err != nil {
  177. s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.ComputeFileHash", episodeFPath, err)
  178. continue
  179. }
  180. println(subFPath)
  181. println(imdbInfo4Series)
  182. println(fileHash)
  183. }
  184. return nil
  185. }