download_processer.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. package downloader
  2. import (
  3. "errors"
  4. "fmt"
  5. "path/filepath"
  6. "github.com/allanpk716/ChineseSubFinder/internal/logic/series_helper"
  7. "github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
  8. "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
  9. "github.com/allanpk716/ChineseSubFinder/internal/pkg/task_queue"
  10. taskQueue2 "github.com/allanpk716/ChineseSubFinder/internal/types/task_queue"
  11. "golang.org/x/net/context"
  12. )
  13. func (d *Downloader) movieDlFunc(ctx context.Context, job taskQueue2.OneJob, downloadIndex int64) error {
  14. nowSubSupplierHub := d.subSupplierHub
  15. if nowSubSupplierHub.Suppliers == nil || len(nowSubSupplierHub.Suppliers) < 1 {
  16. d.log.Infoln("Wait SupplierCheck Update *subSupplierHub, movieDlFunc Skip this time")
  17. return nil
  18. }
  19. // 字幕都下载缓存好了,需要抉择存哪一个,优先选择中文双语的,然后到中文
  20. organizeSubFiles, err := nowSubSupplierHub.DownloadSub4Movie(job.VideoFPath, downloadIndex)
  21. if err != nil {
  22. err = errors.New(fmt.Sprintf("subSupplierHub.DownloadSub4Movie: %v, %v", job.VideoFPath, err))
  23. d.downloadQueue.AutoDetectUpdateJobStatus(job, err)
  24. return err
  25. }
  26. // 返回的两个值都是 nil 的时候,就是没有下载到字幕
  27. if organizeSubFiles == nil || len(organizeSubFiles) < 1 {
  28. d.log.Infoln(task_queue.ErrNoSubFound.Error(), filepath.Base(job.VideoFPath))
  29. d.downloadQueue.AutoDetectUpdateJobStatus(job, task_queue.ErrNoSubFound)
  30. return nil
  31. }
  32. err = d.oneVideoSelectBestSub(job.VideoFPath, organizeSubFiles)
  33. if err != nil {
  34. d.downloadQueue.AutoDetectUpdateJobStatus(job, err)
  35. return err
  36. }
  37. d.downloadQueue.AutoDetectUpdateJobStatus(job, nil)
  38. // TODO 刷新字幕,这里是 Emby 的,如果是其他的,需要再对接对应的媒体服务器
  39. if d.settings.EmbySettings.Enable == true && d.embyHelper != nil && job.MediaServerInsideVideoID != "" {
  40. d.log.Infoln("Refresh Emby Subtitle with id:", job.MediaServerInsideVideoID)
  41. err = d.embyHelper.EmbyApi.UpdateVideoSubList(job.MediaServerInsideVideoID)
  42. if err != nil {
  43. d.log.Errorln("UpdateVideoSubList", job.VideoFPath, job.MediaServerInsideVideoID, "Error:", err)
  44. return err
  45. }
  46. } else {
  47. if d.settings.EmbySettings.Enable == false {
  48. d.log.Infoln("UpdateVideoSubList", job.VideoFPath, "Skip, because Emby enable is false")
  49. } else if d.embyHelper == nil {
  50. d.log.Infoln("UpdateVideoSubList", job.VideoFPath, "Skip, because EmbyHelper is nil")
  51. } else if job.MediaServerInsideVideoID == "" {
  52. d.log.Infoln("UpdateVideoSubList", job.VideoFPath, "Skip, because MediaServerInsideVideoID is empty")
  53. }
  54. }
  55. return nil
  56. }
  57. func (d *Downloader) seriesDlFunc(ctx context.Context, job taskQueue2.OneJob, downloadIndex int64) error {
  58. nowSubSupplierHub := d.subSupplierHub
  59. if nowSubSupplierHub == nil || nowSubSupplierHub.Suppliers == nil || len(nowSubSupplierHub.Suppliers) < 1 {
  60. d.log.Infoln("Wait SupplierCheck Update *subSupplierHub, movieDlFunc Skip this time")
  61. return nil
  62. }
  63. var err error
  64. // 设置只有一集需要下载
  65. epsMap := make(map[int][]int, 0)
  66. epsMap[job.Season] = []int{job.Episode}
  67. // 这里拿到了这一部连续剧的所有的剧集信息,以及所有下载到的字幕信息
  68. seriesInfo, err := series_helper.ReadSeriesInfoFromDir(
  69. d.log, job.SeriesRootDirPath,
  70. d.settings.AdvancedSettings.TaskQueue.ExpirationTime,
  71. false,
  72. false,
  73. epsMap)
  74. if err != nil {
  75. err = errors.New(fmt.Sprintf("seriesDlFunc.ReadSeriesInfoFromDir, Error: %v", err))
  76. d.downloadQueue.AutoDetectUpdateJobStatus(job, err)
  77. return err
  78. }
  79. // 下载好的字幕文件
  80. var organizeSubFiles map[string][]string
  81. // 下载的接口是统一的
  82. organizeSubFiles, err = nowSubSupplierHub.DownloadSub4Series(job.SeriesRootDirPath,
  83. seriesInfo,
  84. downloadIndex)
  85. if err != nil {
  86. err = errors.New(fmt.Sprintf("seriesDlFunc.DownloadSub4Series %v S%vE%v %v", filepath.Base(job.SeriesRootDirPath), job.Season, job.Episode, err))
  87. d.downloadQueue.AutoDetectUpdateJobStatus(job, err)
  88. return err
  89. }
  90. // 是否下载到字幕了
  91. if organizeSubFiles == nil || len(organizeSubFiles) < 1 {
  92. d.log.Infoln(task_queue.ErrNoSubFound.Error(), filepath.Base(job.VideoFPath), job.Season, job.Episode)
  93. d.downloadQueue.AutoDetectUpdateJobStatus(job, task_queue.ErrNoSubFound)
  94. return nil
  95. }
  96. var errSave2Local error
  97. save2LocalSubCount := 0
  98. // 只针对需要下载字幕的视频进行字幕的选择保存
  99. subVideoCount := 0
  100. for epsKey, episodeInfo := range seriesInfo.NeedDlEpsKeyList {
  101. // 创建一个 chan 用于任务的中断和超时
  102. done := make(chan interface{}, 1)
  103. // 接收内部任务的 panic
  104. panicChan := make(chan interface{}, 1)
  105. go func() {
  106. defer func() {
  107. if p := recover(); p != nil {
  108. panicChan <- p
  109. }
  110. close(done)
  111. close(panicChan)
  112. }()
  113. // 匹配对应的 Eps 去处理
  114. done <- d.oneVideoSelectBestSub(episodeInfo.FileFullPath, organizeSubFiles[epsKey])
  115. }()
  116. select {
  117. case errInterface := <-done:
  118. if errInterface != nil {
  119. errSave2Local = errInterface.(error)
  120. d.log.Errorln(errInterface.(error))
  121. } else {
  122. save2LocalSubCount++
  123. }
  124. break
  125. case p := <-panicChan:
  126. // 遇到内部的 panic,向外抛出
  127. d.log.Errorln("seriesDlFunc.oneVideoSelectBestSub panicChan", p)
  128. break
  129. case <-ctx.Done():
  130. {
  131. err = errors.New(fmt.Sprintf("cancel at NeedDlEpsKeyList.oneVideoSelectBestSub, %v S%dE%d", seriesInfo.Name, episodeInfo.Season, episodeInfo.Episode))
  132. d.downloadQueue.AutoDetectUpdateJobStatus(job, err)
  133. return err
  134. }
  135. }
  136. subVideoCount++
  137. }
  138. // 这里会拿到一份季度字幕的列表比如,Key 是 S1E0 S2E0 S3E0,value 是新的存储位置
  139. fullSeasonSubDict := d.saveFullSeasonSub(seriesInfo, organizeSubFiles)
  140. // TODO 季度的字幕包,应该优先于零散的字幕吧,暂定就这样了,注意是全部都替换
  141. // 需要与有下载需求的季交叉
  142. for _, episodeInfo := range seriesInfo.EpList {
  143. _, ok := seriesInfo.NeedDlSeasonDict[episodeInfo.Season]
  144. if ok == false {
  145. continue
  146. }
  147. // 创建一个 chan 用于任务的中断和超时
  148. done := make(chan interface{}, 1)
  149. // 接收内部任务的 panic
  150. panicChan := make(chan interface{}, 1)
  151. go func() {
  152. defer func() {
  153. if p := recover(); p != nil {
  154. panicChan <- p
  155. }
  156. close(done)
  157. close(panicChan)
  158. }()
  159. // 匹配对应的 Eps 去处理
  160. seasonEpsKey := my_util.GetEpisodeKeyName(episodeInfo.Season, episodeInfo.Episode)
  161. if fullSeasonSubDict[seasonEpsKey] == nil || len(fullSeasonSubDict[seasonEpsKey]) < 1 {
  162. d.log.Infoln("seriesDlFunc.saveFullSeasonSub, no sub found, Skip", seasonEpsKey)
  163. done <- nil
  164. }
  165. done <- d.oneVideoSelectBestSub(episodeInfo.FileFullPath, fullSeasonSubDict[seasonEpsKey])
  166. }()
  167. select {
  168. case errInterface := <-done:
  169. if errInterface != nil {
  170. errSave2Local = errInterface.(error)
  171. d.log.Errorln(errInterface.(error))
  172. } else {
  173. save2LocalSubCount++
  174. }
  175. break
  176. case p := <-panicChan:
  177. // 遇到内部的 panic,向外抛出
  178. d.log.Errorln("seriesDlFunc.oneVideoSelectBestSub panicChan", p)
  179. break
  180. case <-ctx.Done():
  181. {
  182. err = errors.New(fmt.Sprintf("cancel at NeedDlEpsKeyList.oneVideoSelectBestSub, %v S%dE%d", seriesInfo.Name, episodeInfo.Season, episodeInfo.Episode))
  183. d.downloadQueue.AutoDetectUpdateJobStatus(job, err)
  184. return err
  185. }
  186. }
  187. }
  188. // 是否清理全季的缓存字幕文件夹
  189. if d.settings.AdvancedSettings.SaveFullSeasonTmpSubtitles == false {
  190. err = sub_helper.DeleteOneSeasonSubCacheFolder(seriesInfo.DirPath)
  191. if err != nil {
  192. d.log.Errorln("seriesDlFunc.DeleteOneSeasonSubCacheFolder", err)
  193. }
  194. }
  195. if save2LocalSubCount < 1 {
  196. // 下载的字幕都没有一个能够写入到本地的,那么就有问题了
  197. d.downloadQueue.AutoDetectUpdateJobStatus(job, errSave2Local)
  198. return errSave2Local
  199. }
  200. // 哪怕有一个写入到本地成功了,也无需对本次任务报错
  201. d.downloadQueue.AutoDetectUpdateJobStatus(job, nil)
  202. // TODO 刷新字幕,这里是 Emby 的,如果是其他的,需要再对接对应的媒体服务器
  203. if d.settings.EmbySettings.Enable == true && d.embyHelper != nil && job.MediaServerInsideVideoID != "" {
  204. err = d.embyHelper.EmbyApi.UpdateVideoSubList(job.MediaServerInsideVideoID)
  205. if err != nil {
  206. d.log.Errorln("UpdateVideoSubList", job.SeriesRootDirPath, job.MediaServerInsideVideoID, job.Season, job.Episode, "Error:", err)
  207. return err
  208. }
  209. }
  210. return nil
  211. }