queue_local.go 9.9 KB

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