queue_local.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. package downloader
  2. import (
  3. "fmt"
  4. "github.com/allanpk716/ChineseSubFinder/pkg"
  5. "github.com/allanpk716/ChineseSubFinder/pkg/decode"
  6. "github.com/allanpk716/ChineseSubFinder/pkg/log_helper"
  7. "github.com/allanpk716/ChineseSubFinder/pkg/my_util"
  8. "github.com/allanpk716/ChineseSubFinder/pkg/task_queue"
  9. common2 "github.com/allanpk716/ChineseSubFinder/pkg/types/common"
  10. taskQueue2 "github.com/allanpk716/ChineseSubFinder/pkg/types/task_queue"
  11. )
  12. func (d *Downloader) queueDownloaderLocal() {
  13. d.log.Debugln("Download.QueueDownloader() Try Start ...")
  14. d.downloaderLock.Lock()
  15. d.log.Debugln("Download.QueueDownloader() Start ...")
  16. defer func() {
  17. if p := recover(); p != nil {
  18. d.log.Errorln("Downloader.QueueDownloader() panic")
  19. my_util.PrintPanicStack(d.log)
  20. }
  21. d.downloaderLock.Unlock()
  22. d.log.Debugln("Download.QueueDownloader() End")
  23. }()
  24. var downloadCounter int64
  25. downloadCounter = 0
  26. // 移除查过三个月的 Done 任务
  27. d.downloadQueue.BeforeGetOneJob()
  28. // 从队列取数据出来,见《任务生命周期》
  29. bok, oneJob, err := d.downloadQueue.GetOneJob()
  30. if err != nil {
  31. d.log.Errorln("d.downloadQueue.GetOneWaitingJob()", err)
  32. return
  33. }
  34. if bok == false {
  35. d.log.Debugln("Download Queue Is Empty, Skip This Time")
  36. return
  37. }
  38. // --------------------------------------------------
  39. // 这个任务如果是 series 那么需要考虑是否原始存入的信息是缺失的,需要补全
  40. {
  41. if oneJob.VideoType == common2.Series && (oneJob.SeriesRootDirPath == "" || oneJob.Season <= 0 || oneJob.Episode <= 0) {
  42. // 连续剧的时候需要额外提交信息
  43. epsVideoNfoInfo, err := decode.GetVideoNfoInfo4OneSeriesEpisode(oneJob.VideoFPath)
  44. if err != nil {
  45. d.log.Errorln("decode.GetVideoNfoInfo4OneSeriesEpisode()", err)
  46. d.log.Infoln("maybe you moved video file to another place or delete it, so will delete this job")
  47. bok, err = d.downloadQueue.Del(oneJob.Id)
  48. if err != nil {
  49. d.log.Errorln("d.downloadQueue.Del()", err)
  50. return
  51. }
  52. if bok == false {
  53. d.log.Errorln(fmt.Sprintf("d.downloadQueue.Del(%d) == false", oneJob.Id))
  54. return
  55. }
  56. return
  57. }
  58. seriesInfoDirPath := decode.GetSeriesDirRootFPath(oneJob.VideoFPath)
  59. if seriesInfoDirPath == "" {
  60. d.log.Errorln(fmt.Sprintf("decode.GetSeriesDirRootFPath == Empty, %s", oneJob.VideoFPath))
  61. d.log.Infoln("you need check the directory structure of a series, so will delete this job")
  62. bok, err = d.downloadQueue.Del(oneJob.Id)
  63. if err != nil {
  64. d.log.Errorln("d.downloadQueue.Del()", err)
  65. return
  66. }
  67. if bok == false {
  68. d.log.Errorln(fmt.Sprintf("d.downloadQueue.Del(%d) == false", oneJob.Id))
  69. return
  70. }
  71. return
  72. }
  73. oneJob.Season = epsVideoNfoInfo.Season
  74. oneJob.Episode = epsVideoNfoInfo.Episode
  75. oneJob.SeriesRootDirPath = seriesInfoDirPath
  76. }
  77. }
  78. // --------------------------------------------------
  79. // 这个视频文件不存在了
  80. {
  81. isBlue, _, _ := decode.IsFakeBDMVWorked(oneJob.VideoFPath)
  82. if isBlue == false && my_util.IsFile(oneJob.VideoFPath) == false {
  83. // 不是蓝光,那么就判断文件是否存在,不存在,那么就标记 ignore
  84. bok, err = d.downloadQueue.Del(oneJob.Id)
  85. if err != nil {
  86. d.log.Errorln("d.downloadQueue.Del()", err)
  87. return
  88. }
  89. if bok == false {
  90. d.log.Errorln(fmt.Sprintf("d.downloadQueue.Del(%d) == false", oneJob.Id))
  91. return
  92. }
  93. d.log.Infoln(oneJob.VideoFPath, "is missing, Delete This Job")
  94. return
  95. }
  96. }
  97. // --------------------------------------------------
  98. // 判断是否看过,这个只有 Emby 情况下才会生效
  99. {
  100. isPlayed := false
  101. if d.embyHelper != nil {
  102. // 在拿出来后,如果是有内部媒体服务器媒体 ID 的,那么就去查询是否已经观看过了
  103. isPlayed, err = d.embyHelper.IsVideoPlayed(oneJob.MediaServerInsideVideoID)
  104. if err != nil {
  105. d.log.Errorln("d.embyHelper.IsVideoPlayed()", oneJob.VideoFPath, err)
  106. return
  107. }
  108. }
  109. // TODO 暂时屏蔽掉 http api 提交的已看字幕的接口上传
  110. // 不管如何,只要是发现数据库中有 HTTP API 提交的信息,就认为是看过
  111. //var videoPlayedInfos []models.ThirdPartSetVideoPlayedInfo
  112. //dao.GetDb().Where("physical_video_file_full_path = ?", oneJob.VideoFPath).Find(&videoPlayedInfos)
  113. //if len(videoPlayedInfos) > 0 {
  114. // isPlayed = true
  115. //}
  116. // --------------------------------------------------
  117. // 如果已经播放过 且 这个任务的优先级 > 3 ,不是很急的那种,说明是可以设置忽略继续下载的
  118. if isPlayed == true && oneJob.TaskPriority > task_queue.HighTaskPriorityLevel {
  119. // 播放过了,那么就标记 ignore
  120. oneJob.JobStatus = taskQueue2.Ignore
  121. bok, err = d.downloadQueue.Update(oneJob)
  122. if err != nil {
  123. d.log.Errorln("d.downloadQueue.Update()", err)
  124. return
  125. }
  126. if bok == false {
  127. d.log.Errorln("d.downloadQueue.Update() Failed")
  128. return
  129. }
  130. d.log.Infoln("Is Played, Ignore This Job")
  131. return
  132. }
  133. }
  134. // --------------------------------------------------
  135. // 判断是否需要跳过,因为如果是 Normal 扫描出来的,那么可能因为视频时间久远,下载一次即可
  136. {
  137. if oneJob.TaskPriority > task_queue.HighTaskPriorityLevel {
  138. // 优先级大于 3,那么就不是很急的任务,才需要判断
  139. if oneJob.VideoType == common2.Movie {
  140. if d.subSupplierHub.MovieNeedDlSub(oneJob.VideoFPath, false) == false {
  141. // 需要标记忽略
  142. oneJob.JobStatus = taskQueue2.Ignore
  143. bok, err = d.downloadQueue.Update(oneJob)
  144. if err != nil {
  145. d.log.Errorln("d.downloadQueue.Update()", err)
  146. return
  147. }
  148. if bok == false {
  149. d.log.Errorln("d.downloadQueue.Update() Failed")
  150. return
  151. }
  152. d.log.Infoln("MovieNeedDlSub == false, Ignore This Job")
  153. return
  154. }
  155. } else if oneJob.VideoType == common2.Series {
  156. bNeedDlSub, seriesInfo, err := d.subSupplierHub.SeriesNeedDlSub(oneJob.SeriesRootDirPath,
  157. false, false)
  158. if err != nil {
  159. d.log.Errorln("SeriesNeedDlSub", err)
  160. return
  161. }
  162. needMarkSkip := false
  163. if bNeedDlSub == false {
  164. // 需要跳过
  165. needMarkSkip = true
  166. } else {
  167. // 需要下载的 Eps 是否与 Normal 判断这个连续剧中有那些剧集需要下载的,情况符合。通过下载的时间来判断
  168. epsKey := my_util.GetEpisodeKeyName(oneJob.Season, oneJob.Episode)
  169. _, found := seriesInfo.NeedDlEpsKeyList[epsKey]
  170. if found == false {
  171. // 需要跳过
  172. needMarkSkip = true
  173. }
  174. }
  175. if needMarkSkip == true {
  176. // 需要标记忽略
  177. oneJob.JobStatus = taskQueue2.Ignore
  178. bok, err = d.downloadQueue.Update(oneJob)
  179. if err != nil {
  180. d.log.Errorln("d.downloadQueue.Update()", err)
  181. return
  182. }
  183. if bok == false {
  184. d.log.Errorln("d.downloadQueue.Update() Failed")
  185. return
  186. }
  187. d.log.Infoln("SeriesNeedDlSub == false, Ignore This Job")
  188. return
  189. }
  190. }
  191. }
  192. }
  193. // 取出来后,需要标记为正在下载
  194. oneJob.JobStatus = taskQueue2.Downloading
  195. bok, err = d.downloadQueue.Update(oneJob)
  196. if err != nil {
  197. d.log.Errorln("d.downloadQueue.Update()", err)
  198. return
  199. }
  200. if bok == false {
  201. d.log.Errorln("d.downloadQueue.Update() Failed")
  202. return
  203. }
  204. // ------------------------------------------------------------------------
  205. // 开始标记,这个是单次扫描的开始,要注意格式,在日志的内部解析识别单个日志开头的时候需要特殊的格式
  206. d.log.Infoln("------------------------------------------")
  207. d.log.Infoln(log_helper.OnceSubsScanStart + "#" + oneJob.Id)
  208. // ------------------------------------------------------------------------
  209. defer func() {
  210. d.log.Infoln(log_helper.OnceSubsScanEnd)
  211. d.log.Infoln("------------------------------------------")
  212. }()
  213. downloadCounter++
  214. // 创建一个 chan 用于任务的中断和超时
  215. done := make(chan interface{}, 1)
  216. // 接收内部任务的 panic
  217. panicChan := make(chan interface{}, 1)
  218. go func() {
  219. defer func() {
  220. if p := recover(); p != nil {
  221. panicChan <- p
  222. }
  223. close(done)
  224. close(panicChan)
  225. // 每下载完毕一次,进行一次缓存和 Chrome 的清理
  226. err = pkg.ClearRootTmpFolder()
  227. if err != nil {
  228. d.log.Error("ClearRootTmpFolder", err)
  229. }
  230. if pkg.LiteMode() == false {
  231. my_util.CloseChrome(d.log)
  232. }
  233. }()
  234. if oneJob.VideoType == common2.Movie {
  235. // 电影
  236. // 具体的下载逻辑 func()
  237. done <- d.movieDlFunc(d.ctx, oneJob, downloadCounter)
  238. } else if oneJob.VideoType == common2.Series {
  239. // 连续剧
  240. // 具体的下载逻辑 func()
  241. done <- d.seriesDlFunc(d.ctx, oneJob, downloadCounter)
  242. } else {
  243. d.log.Errorln("oneJob.VideoType not support, oneJob.VideoType = ", oneJob.VideoType)
  244. done <- nil
  245. }
  246. }()
  247. select {
  248. case err := <-done:
  249. // 跳出 select,可以外层继续,不会阻塞在这里
  250. if err != nil {
  251. d.log.Errorln(err)
  252. }
  253. // 刷新视频的缓存结构
  254. d.UpdateInfo(oneJob)
  255. break
  256. case p := <-panicChan:
  257. // 遇到内部的 panic,向外抛出
  258. panic(p)
  259. case <-d.ctx.Done():
  260. {
  261. // 取消这个 context
  262. d.log.Warningln("cancel Downloader.QueueDownloader()")
  263. return
  264. }
  265. }
  266. }