scan_played_video_subinfo.go 7.1 KB

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