download_processer.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. package downloader
  2. import (
  3. "errors"
  4. "fmt"
  5. "path/filepath"
  6. taskQueue2 "github.com/allanpk716/ChineseSubFinder/pkg/types/task_queue"
  7. "github.com/allanpk716/ChineseSubFinder/pkg/logic/series_helper"
  8. "github.com/allanpk716/ChineseSubFinder/pkg/my_util"
  9. "github.com/allanpk716/ChineseSubFinder/pkg/sub_helper"
  10. "github.com/allanpk716/ChineseSubFinder/pkg/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("字幕下载完毕,尝试刷新 Emby 中对应字幕", job.VideoFPath, 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("字幕下载完毕,尝试刷新 Emby 中对应字幕", job.VideoFPath, "Skip, because Emby enable is false")
  49. } else if d.embyHelper == nil {
  50. d.log.Infoln("字幕下载完毕,尝试刷新 Emby 中对应字幕", job.VideoFPath, "Skip, because EmbyHelper is nil")
  51. } else if job.MediaServerInsideVideoID == "" {
  52. d.log.Infoln("字幕下载完毕,尝试刷新 Emby 中对应字幕", 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. d.settings.AdvancedSettings.ProxySettings,
  74. epsMap)
  75. if err != nil {
  76. err = errors.New(fmt.Sprintf("seriesDlFunc.ReadSeriesInfoFromDir, Error: %v", err))
  77. d.downloadQueue.AutoDetectUpdateJobStatus(job, err)
  78. return err
  79. }
  80. // 下载好的字幕文件
  81. var organizeSubFiles map[string][]string
  82. // 下载的接口是统一的
  83. organizeSubFiles, err = nowSubSupplierHub.DownloadSub4Series(job.SeriesRootDirPath,
  84. seriesInfo,
  85. downloadIndex)
  86. if err != nil {
  87. err = errors.New(fmt.Sprintf("seriesDlFunc.DownloadSub4Series %v S%vE%v %v", filepath.Base(job.SeriesRootDirPath), job.Season, job.Episode, err))
  88. d.downloadQueue.AutoDetectUpdateJobStatus(job, err)
  89. return err
  90. }
  91. // 是否下载到字幕了
  92. if organizeSubFiles == nil || len(organizeSubFiles) < 1 {
  93. d.log.Infoln(task_queue.ErrNoSubFound.Error(), filepath.Base(job.VideoFPath), job.Season, job.Episode)
  94. d.downloadQueue.AutoDetectUpdateJobStatus(job, task_queue.ErrNoSubFound)
  95. return nil
  96. }
  97. var errSave2Local error
  98. save2LocalSubCount := 0
  99. // 只针对需要下载字幕的视频进行字幕的选择保存
  100. subVideoCount := 0
  101. for epsKey, episodeInfo := range seriesInfo.NeedDlEpsKeyList {
  102. // 创建一个 chan 用于任务的中断和超时
  103. done := make(chan interface{}, 1)
  104. // 接收内部任务的 panic
  105. panicChan := make(chan interface{}, 1)
  106. go func() {
  107. defer func() {
  108. if p := recover(); p != nil {
  109. panicChan <- p
  110. }
  111. close(done)
  112. close(panicChan)
  113. }()
  114. // 匹配对应的 Eps 去处理
  115. done <- d.oneVideoSelectBestSub(episodeInfo.FileFullPath, organizeSubFiles[epsKey])
  116. }()
  117. select {
  118. case errInterface := <-done:
  119. if errInterface != nil {
  120. errSave2Local = errInterface.(error)
  121. d.log.Errorln(errInterface.(error))
  122. } else {
  123. save2LocalSubCount++
  124. }
  125. break
  126. case p := <-panicChan:
  127. // 遇到内部的 panic,向外抛出
  128. d.log.Errorln("seriesDlFunc.oneVideoSelectBestSub panicChan", p)
  129. break
  130. case <-ctx.Done():
  131. {
  132. err = errors.New(fmt.Sprintf("cancel at NeedDlEpsKeyList.oneVideoSelectBestSub, %v S%dE%d", seriesInfo.Name, episodeInfo.Season, episodeInfo.Episode))
  133. d.downloadQueue.AutoDetectUpdateJobStatus(job, err)
  134. return err
  135. }
  136. }
  137. subVideoCount++
  138. }
  139. // 这里会拿到一份季度字幕的列表比如,Key 是 S1E0 S2E0 S3E0,value 是新的存储位置
  140. fullSeasonSubDict := d.saveFullSeasonSub(seriesInfo, organizeSubFiles)
  141. // TODO 季度的字幕包,应该优先于零散的字幕吧,暂定就这样了,注意是全部都替换
  142. // 需要与有下载需求的季交叉
  143. for _, episodeInfo := range seriesInfo.EpList {
  144. _, ok := seriesInfo.NeedDlSeasonDict[episodeInfo.Season]
  145. if ok == false {
  146. continue
  147. }
  148. // 创建一个 chan 用于任务的中断和超时
  149. done := make(chan interface{}, 1)
  150. // 接收内部任务的 panic
  151. panicChan := make(chan interface{}, 1)
  152. go func() {
  153. defer func() {
  154. if p := recover(); p != nil {
  155. panicChan <- p
  156. }
  157. close(done)
  158. close(panicChan)
  159. }()
  160. // 匹配对应的 Eps 去处理
  161. seasonEpsKey := my_util.GetEpisodeKeyName(episodeInfo.Season, episodeInfo.Episode)
  162. if fullSeasonSubDict[seasonEpsKey] == nil || len(fullSeasonSubDict[seasonEpsKey]) < 1 {
  163. d.log.Infoln("seriesDlFunc.saveFullSeasonSub, no sub found, Skip", seasonEpsKey)
  164. done <- nil
  165. }
  166. done <- d.oneVideoSelectBestSub(episodeInfo.FileFullPath, fullSeasonSubDict[seasonEpsKey])
  167. }()
  168. select {
  169. case errInterface := <-done:
  170. if errInterface != nil {
  171. errSave2Local = errInterface.(error)
  172. d.log.Errorln(errInterface.(error))
  173. } else {
  174. save2LocalSubCount++
  175. }
  176. break
  177. case p := <-panicChan:
  178. // 遇到内部的 panic,向外抛出
  179. d.log.Errorln("seriesDlFunc.oneVideoSelectBestSub panicChan", p)
  180. break
  181. case <-ctx.Done():
  182. {
  183. err = errors.New(fmt.Sprintf("cancel at NeedDlEpsKeyList.oneVideoSelectBestSub, %v S%dE%d", seriesInfo.Name, episodeInfo.Season, episodeInfo.Episode))
  184. d.downloadQueue.AutoDetectUpdateJobStatus(job, err)
  185. return err
  186. }
  187. }
  188. }
  189. // 是否清理全季的缓存字幕文件夹
  190. if d.settings.AdvancedSettings.SaveFullSeasonTmpSubtitles == false {
  191. err = sub_helper.DeleteOneSeasonSubCacheFolder(seriesInfo.DirPath)
  192. if err != nil {
  193. d.log.Errorln("seriesDlFunc.DeleteOneSeasonSubCacheFolder", err)
  194. }
  195. }
  196. if save2LocalSubCount < 1 {
  197. // 下载的字幕都没有一个能够写入到本地的,那么就有问题了
  198. d.downloadQueue.AutoDetectUpdateJobStatus(job, errSave2Local)
  199. return errSave2Local
  200. }
  201. // 哪怕有一个写入到本地成功了,也无需对本次任务报错
  202. d.downloadQueue.AutoDetectUpdateJobStatus(job, nil)
  203. // TODO 刷新字幕,这里是 Emby 的,如果是其他的,需要再对接对应的媒体服务器
  204. if d.settings.EmbySettings.Enable == true && d.embyHelper != nil {
  205. if job.MediaServerInsideVideoID != "" {
  206. d.log.Infoln("字幕下载完毕,尝试刷新 Emby 中对应字幕", job.SeriesRootDirPath, job.MediaServerInsideVideoID, job.Season, job.Episode)
  207. err = d.embyHelper.EmbyApi.UpdateVideoSubList(job.MediaServerInsideVideoID)
  208. if err != nil {
  209. d.log.Errorln("UpdateVideoSubList", job.SeriesRootDirPath, job.MediaServerInsideVideoID, job.Season, job.Episode, "Error:", err)
  210. return err
  211. }
  212. } else {
  213. d.log.Warningln("字幕下载完毕,尝试刷新 Emby 中对应字幕,跳过,因为 MediaServerInsideVideoID 为空", job.SeriesRootDirPath, job.Season, job.Episode)
  214. }
  215. }
  216. return nil
  217. }