queue_local.go 9.9 KB

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