upload_played_video_sub.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. package cron_helper
  2. import (
  3. "errors"
  4. "fmt"
  5. "path/filepath"
  6. "strconv"
  7. "strings"
  8. "time"
  9. "github.com/allanpk716/ChineseSubFinder/internal/pkg/common"
  10. "github.com/allanpk716/ChineseSubFinder/internal/dao"
  11. "github.com/allanpk716/ChineseSubFinder/internal/models"
  12. "github.com/allanpk716/ChineseSubFinder/internal/pkg/mix_media_info"
  13. "github.com/allanpk716/ChineseSubFinder/internal/pkg/my_folder"
  14. "github.com/jinzhu/now"
  15. )
  16. // uploadVideoSub 上传字幕的定时器
  17. func (ch *CronHelper) uploadVideoSub() {
  18. ch.uploadPlayedVideoSub()
  19. ch.uploadLowTrustVideoSub()
  20. }
  21. func (ch *CronHelper) uploadPlayedVideoSub() {
  22. // 找出没有上传过的字幕列表
  23. var notUploadedVideoSubInfos []models.VideoSubInfo
  24. dao.GetDb().Where("is_send = ?", false).Limit(1).Find(&notUploadedVideoSubInfos)
  25. if len(notUploadedVideoSubInfos) < 1 {
  26. ch.log.Debugln("No notUploadedVideoSubInfos")
  27. return
  28. }
  29. var imdbInfos []models.IMDBInfo
  30. dao.GetDb().Where("imdb_id = ?", notUploadedVideoSubInfos[0].IMDBInfoID).Find(&imdbInfos)
  31. if len(imdbInfos) < 1 {
  32. // 如果没有找到,那么就没有办法推断出 IMDB ID 的相关信息和 TMDB ID 信息,要来何用,删除即可
  33. ch.log.Infoln("No imdbInfos, will delete this VideoSubInfo,", notUploadedVideoSubInfos[0].SubName)
  34. dao.GetDb().Delete(&notUploadedVideoSubInfos[0])
  35. return
  36. }
  37. videoType := ""
  38. if imdbInfos[0].IsMovie == true {
  39. videoType = "movie"
  40. } else {
  41. videoType = "series"
  42. }
  43. var err error
  44. var finalQueryIMDBInfo *models.MediaInfo
  45. if imdbInfos[0].TmdbId == "" {
  46. // 需要先对这个字幕的 IMDB ID 转 TMDB ID 信息进行查询,得到 TMDB ID 和 Year (2019 2022)
  47. finalQueryIMDBInfo, err = mix_media_info.GetMediaInfoAndSave(ch.log, ch.FileDownloader.SubtitleBestApi, &imdbInfos[0], imdbInfos[0].IMDBID, "imdb", videoType)
  48. if err != nil {
  49. ch.log.Errorln(errors.New("GetMediaInfoAndSave error:" + err.Error()))
  50. return
  51. }
  52. } else {
  53. var mediaInfos []models.MediaInfo
  54. dao.GetDb().Where("tmdb_id = ?", imdbInfos[0].TmdbId).Find(&mediaInfos)
  55. if len(mediaInfos) < 1 {
  56. finalQueryIMDBInfo, err = mix_media_info.GetMediaInfoAndSave(ch.log, ch.FileDownloader.SubtitleBestApi, &imdbInfos[0], imdbInfos[0].IMDBID, "imdb", videoType)
  57. if err != nil {
  58. ch.log.Errorln(errors.New("GetMediaInfoAndSave error:" + err.Error()))
  59. return
  60. }
  61. } else {
  62. finalQueryIMDBInfo = &mediaInfos[0]
  63. }
  64. }
  65. // 在这之前,需要进行一次判断,这个字幕是否是有效的,因为可能会有是 1kb 的错误字幕
  66. // 如果解析这个字幕是错误的,那么也可以标记完成
  67. shareRootDir, err := my_folder.GetShareSubRootFolder()
  68. if err != nil {
  69. ch.log.Errorln("GetShareSubRootFolder error:", err.Error())
  70. return
  71. }
  72. bok, _, err := ch.FileDownloader.SubParserHub.DetermineFileTypeFromFile(filepath.Join(shareRootDir, notUploadedVideoSubInfos[0].StoreRPath))
  73. if err != nil {
  74. notUploadedVideoSubInfos[0].IsSend = true
  75. dao.GetDb().Save(&notUploadedVideoSubInfos[0])
  76. ch.log.Errorln("DetermineFileTypeFromFile upload sub error, mark is send,", err.Error())
  77. return
  78. }
  79. if bok == false {
  80. notUploadedVideoSubInfos[0].IsSend = true
  81. dao.GetDb().Save(&notUploadedVideoSubInfos[0])
  82. ch.log.Errorln("DetermineFileTypeFromFile upload sub == false, not match any SubType, mark is send")
  83. return
  84. }
  85. ch.log.Infoln("AskFroUpload", notUploadedVideoSubInfos[0].SubName)
  86. // 问询这个字幕是否上传过了,如果没有就需要进入上传的队列
  87. askForUploadReply, err := ch.FileDownloader.SubtitleBestApi.AskFroUpload(
  88. notUploadedVideoSubInfos[0].SHA256,
  89. notUploadedVideoSubInfos[0].IsMovie,
  90. true,
  91. finalQueryIMDBInfo.ImdbId,
  92. finalQueryIMDBInfo.TmdbId,
  93. notUploadedVideoSubInfos[0].Season,
  94. notUploadedVideoSubInfos[0].Episode,
  95. notUploadedVideoSubInfos[0].Feature,
  96. )
  97. if err != nil {
  98. ch.log.Errorln(fmt.Errorf("AskFroUpload err: %v", err))
  99. return
  100. }
  101. if askForUploadReply.Status == 3 {
  102. // 上传过了,直接标记本地的 is_send 字段为 true
  103. notUploadedVideoSubInfos[0].IsSend = true
  104. dao.GetDb().Save(&notUploadedVideoSubInfos[0])
  105. ch.log.Infoln("Subtitle has been uploaded, so will not upload again")
  106. return
  107. } else if askForUploadReply.Status == 4 {
  108. // 上传队列满了,等待下次定时器触发
  109. ch.log.Infoln("Subtitle upload queue is full, will try ask upload again")
  110. return
  111. } else if askForUploadReply.Status == 2 {
  112. // 这个上传任务已经在队列中了,也许有其他人也需要上传这个字幕,或者本机排队的时候故障了,重启也可能遇到这个故障
  113. ch.log.Infoln("Subtitle is int the queue")
  114. return
  115. } else if askForUploadReply.Status == 1 {
  116. // 正确放入了队列,然后需要按规划的时间进行上传操作
  117. // 这里可能需要执行耗时操作来等待到安排的时间点进行字幕的上传,不能直接长时间的 Sleep 操作
  118. // 每次 Sleep 1s 然后就判断一次定时器是否还允许允许,如果不运行了,那么也就需要退出循环
  119. // 得到目标时间与当前时间的差值,单位是s
  120. waitTime := askForUploadReply.ScheduledUnixTime - time.Now().Unix()
  121. if waitTime <= 0 {
  122. waitTime = 5
  123. }
  124. ch.log.Infoln("will wait", waitTime, "s 2 upload sub 2 server")
  125. var sleepCounter int64
  126. sleepCounter = 0
  127. normalStatus := false
  128. for ch.cronHelperRunning == true {
  129. if sleepCounter > waitTime {
  130. normalStatus = true
  131. break
  132. }
  133. if sleepCounter%30 == 0 {
  134. ch.log.Infoln("wait 2 upload sub")
  135. }
  136. time.Sleep(1 * time.Second)
  137. sleepCounter++
  138. }
  139. if normalStatus == false || ch.cronHelperRunning == false {
  140. // 说明不是正常跳出来的,是结束定时器来执行的
  141. ch.log.Infoln("uploadVideoSub early termination")
  142. return
  143. }
  144. // 发送字幕
  145. releaseTime, err := now.Parse(finalQueryIMDBInfo.Year)
  146. if err != nil {
  147. ch.log.Errorln("now.Parse error:", err.Error())
  148. return
  149. }
  150. ch.log.Infoln("UploadSub", notUploadedVideoSubInfos[0].SubName)
  151. uploadSubReply, err := ch.FileDownloader.SubtitleBestApi.UploadSub(&notUploadedVideoSubInfos[0], shareRootDir, finalQueryIMDBInfo.TmdbId, strconv.Itoa(releaseTime.Year()))
  152. if err != nil {
  153. ch.log.Errorln("UploadSub error:", err.Error())
  154. if errors.Is(err, common.ErrorUpload413) == true {
  155. // 文件发送大小超限
  156. notUploadedVideoSubInfos[0].IsSend = true
  157. dao.GetDb().Save(&notUploadedVideoSubInfos[0])
  158. ch.log.Infoln("subtitle upload file over size limit, will not upload again")
  159. return
  160. }
  161. return
  162. }
  163. if uploadSubReply.Status == 1 {
  164. // 成功,其他情况就等待 Ask for Upload
  165. notUploadedVideoSubInfos[0].IsSend = true
  166. dao.GetDb().Save(&notUploadedVideoSubInfos[0])
  167. ch.log.Infoln("subtitle is uploaded")
  168. return
  169. } else if uploadSubReply.Status == 0 {
  170. // 发送失败,然后需要判断具体的错误,有一些需要直接标记已发送,跳过
  171. if strings.Contains(uploadSubReply.Message, "sub file sha256 not match") == true ||
  172. strings.Contains(uploadSubReply.Message, "determine sub file type error") == true ||
  173. strings.Contains(uploadSubReply.Message, "determine sub file type not match") == true ||
  174. strings.Contains(uploadSubReply.Message, "sub file has no chinese") == true {
  175. notUploadedVideoSubInfos[0].IsSend = true
  176. dao.GetDb().Save(&notUploadedVideoSubInfos[0])
  177. ch.log.Infoln("subtitle upload error, uploadSubReply.Status == 0, ", uploadSubReply.Message, "will not upload again")
  178. return
  179. } else {
  180. ch.log.Errorln("subtitle upload error, uploadSubReply.Status == 0, not support error:", uploadSubReply.Message)
  181. return
  182. }
  183. } else {
  184. ch.log.Warningln("UploadSub Message:", uploadSubReply.Message)
  185. return
  186. }
  187. } else {
  188. // 不是预期的返回值,需要报警
  189. ch.log.Errorln(fmt.Errorf("AskFroUpload Not the expected return value, Status: %d, Message: %v", askForUploadReply.Status, askForUploadReply.Message))
  190. return
  191. }
  192. }
  193. func (ch *CronHelper) uploadLowTrustVideoSub() {
  194. // 找出没有上传过的字幕列表
  195. var notUploadedVideoSubInfos []models.LowVideoSubInfo
  196. dao.GetDb().Where("is_send = ?", false).Limit(1).Find(&notUploadedVideoSubInfos)
  197. if len(notUploadedVideoSubInfos) < 1 {
  198. ch.log.Debugln("No notUploadedVideoSubInfos")
  199. return
  200. }
  201. var imdbInfos []models.IMDBInfo
  202. dao.GetDb().Where("imdb_id = ?", notUploadedVideoSubInfos[0].IMDBID).Find(&imdbInfos)
  203. if len(imdbInfos) < 1 {
  204. // 如果没有找到,那么就没有办法推断出 IMDB ID 的相关信息和 TMDB ID 信息,要来何用,删除即可
  205. ch.log.Infoln("No imdbInfos, will delete this VideoSubInfo,", notUploadedVideoSubInfos[0].SubName)
  206. dao.GetDb().Delete(&notUploadedVideoSubInfos[0])
  207. return
  208. }
  209. videoType := ""
  210. if notUploadedVideoSubInfos[0].Season == 0 && notUploadedVideoSubInfos[0].Episode == 0 {
  211. videoType = "movie"
  212. } else if (notUploadedVideoSubInfos[0].Season == 0 && notUploadedVideoSubInfos[0].Episode != 0) || (notUploadedVideoSubInfos[0].Season != 0 && notUploadedVideoSubInfos[0].Episode == 0) {
  213. ch.log.Errorln(notUploadedVideoSubInfos[0].SubName, "has Season or Episode error")
  214. ch.log.Errorln("season - episode", notUploadedVideoSubInfos[0].Season, notUploadedVideoSubInfos[0].Episode)
  215. // 成功,其他情况就等待 Ask for Upload
  216. notUploadedVideoSubInfos[0].IsSend = true
  217. dao.GetDb().Save(&notUploadedVideoSubInfos[0])
  218. ch.log.Infoln("subtitle will skip upload")
  219. return
  220. } else {
  221. videoType = "series"
  222. }
  223. var err error
  224. var finalQueryIMDBInfo *models.MediaInfo
  225. if imdbInfos[0].TmdbId == "" {
  226. // 需要先对这个字幕的 IMDB ID 转 TMDB ID 信息进行查询,得到 TMDB ID 和 Year (2019 2022)
  227. finalQueryIMDBInfo, err = mix_media_info.GetMediaInfoAndSave(ch.log, ch.FileDownloader.SubtitleBestApi, &imdbInfos[0], imdbInfos[0].IMDBID, "imdb", videoType)
  228. if err != nil {
  229. ch.log.Errorln(errors.New("GetMediaInfoAndSave error:" + err.Error()))
  230. return
  231. }
  232. } else {
  233. var mediaInfos []models.MediaInfo
  234. dao.GetDb().Where("tmdb_id = ?", imdbInfos[0].TmdbId).Find(&mediaInfos)
  235. if len(mediaInfos) < 1 {
  236. finalQueryIMDBInfo, err = mix_media_info.GetMediaInfoAndSave(ch.log, ch.FileDownloader.SubtitleBestApi, &imdbInfos[0], imdbInfos[0].IMDBID, "imdb", videoType)
  237. if err != nil {
  238. ch.log.Errorln(errors.New("GetMediaInfoAndSave error:" + err.Error()))
  239. return
  240. }
  241. } else {
  242. finalQueryIMDBInfo = &mediaInfos[0]
  243. }
  244. }
  245. // 在这之前,需要进行一次判断,这个字幕是否是有效的,因为可能会有是 1kb 的错误字幕
  246. // 如果解析这个字幕是错误的,那么也可以标记完成
  247. shareRootDir, err := my_folder.GetShareSubRootFolder()
  248. if err != nil {
  249. ch.log.Errorln("GetShareSubRootFolder error:", err.Error())
  250. return
  251. }
  252. bok, _, err := ch.FileDownloader.SubParserHub.DetermineFileTypeFromFile(filepath.Join(shareRootDir, notUploadedVideoSubInfos[0].StoreRPath))
  253. if err != nil {
  254. notUploadedVideoSubInfos[0].IsSend = true
  255. dao.GetDb().Save(&notUploadedVideoSubInfos[0])
  256. ch.log.Errorln("DetermineFileTypeFromFile upload sub error, mark is send,", err.Error())
  257. return
  258. }
  259. if bok == false {
  260. notUploadedVideoSubInfos[0].IsSend = true
  261. dao.GetDb().Save(&notUploadedVideoSubInfos[0])
  262. ch.log.Errorln("DetermineFileTypeFromFile upload sub == false, not match any SubType, mark is send")
  263. return
  264. }
  265. ch.log.Infoln("AskFroUpload", notUploadedVideoSubInfos[0].SubName)
  266. // 问询这个字幕是否上传过了,如果没有就需要进入上传的队列
  267. askForUploadReply, err := ch.FileDownloader.SubtitleBestApi.AskFroUpload(
  268. notUploadedVideoSubInfos[0].SHA256,
  269. notUploadedVideoSubInfos[0].IsMovie,
  270. false,
  271. "",
  272. "",
  273. 0,
  274. 0,
  275. notUploadedVideoSubInfos[0].Feature,
  276. )
  277. if err != nil {
  278. ch.log.Errorln(fmt.Errorf("AskFroUpload err: %v", err))
  279. return
  280. }
  281. if askForUploadReply.Status == 3 {
  282. // 上传过了,直接标记本地的 is_send 字段为 true
  283. notUploadedVideoSubInfos[0].IsSend = true
  284. dao.GetDb().Save(&notUploadedVideoSubInfos[0])
  285. ch.log.Infoln("Subtitle has been uploaded, so will not upload again")
  286. return
  287. } else if askForUploadReply.Status == 4 {
  288. // 上传队列满了,等待下次定时器触发
  289. ch.log.Infoln("Subtitle upload queue is full, will try ask upload again")
  290. return
  291. } else if askForUploadReply.Status == 2 {
  292. // 这个上传任务已经在队列中了,也许有其他人也需要上传这个字幕,或者本机排队的时候故障了,重启也可能遇到这个故障
  293. ch.log.Infoln("Subtitle is int the queue")
  294. return
  295. } else if askForUploadReply.Status == 1 {
  296. // 正确放入了队列,然后需要按规划的时间进行上传操作
  297. // 这里可能需要执行耗时操作来等待到安排的时间点进行字幕的上传,不能直接长时间的 Sleep 操作
  298. // 每次 Sleep 1s 然后就判断一次定时器是否还允许允许,如果不运行了,那么也就需要退出循环
  299. // 得到目标时间与当前时间的差值,单位是s
  300. waitTime := askForUploadReply.ScheduledUnixTime - time.Now().Unix()
  301. if waitTime <= 0 {
  302. waitTime = 5
  303. }
  304. ch.log.Infoln("will wait", waitTime, "s 2 upload sub 2 server")
  305. var sleepCounter int64
  306. sleepCounter = 0
  307. normalStatus := false
  308. for ch.cronHelperRunning == true {
  309. if sleepCounter > waitTime {
  310. normalStatus = true
  311. break
  312. }
  313. if sleepCounter%30 == 0 {
  314. ch.log.Infoln("wait 2 upload sub")
  315. }
  316. time.Sleep(1 * time.Second)
  317. sleepCounter++
  318. }
  319. if normalStatus == false || ch.cronHelperRunning == false {
  320. // 说明不是正常跳出来的,是结束定时器来执行的
  321. ch.log.Infoln("uploadVideoSub early termination")
  322. return
  323. }
  324. // 发送字幕
  325. releaseTime, err := now.Parse(finalQueryIMDBInfo.Year)
  326. if err != nil {
  327. ch.log.Errorln("now.Parse error:", err.Error())
  328. return
  329. }
  330. ch.log.Infoln("UploadSub", notUploadedVideoSubInfos[0].SubName)
  331. uploadSubReply, err := ch.FileDownloader.SubtitleBestApi.UploadLowTrustSub(&notUploadedVideoSubInfos[0], shareRootDir, finalQueryIMDBInfo.TmdbId, strconv.Itoa(releaseTime.Year()))
  332. if err != nil {
  333. ch.log.Errorln("UploadLowTrustSub error:", err.Error())
  334. if errors.Is(err, common.ErrorUpload413) == true {
  335. // 文件发送大小超限
  336. notUploadedVideoSubInfos[0].IsSend = true
  337. dao.GetDb().Save(&notUploadedVideoSubInfos[0])
  338. ch.log.Infoln("subtitle upload file over size limit, will not upload again")
  339. return
  340. }
  341. return
  342. }
  343. if uploadSubReply.Status == 1 {
  344. // 成功,其他情况就等待 Ask for Upload
  345. notUploadedVideoSubInfos[0].IsSend = true
  346. dao.GetDb().Save(&notUploadedVideoSubInfos[0])
  347. ch.log.Infoln("subtitle is uploaded")
  348. return
  349. } else if uploadSubReply.Status == 0 {
  350. // 发送失败,然后需要判断具体的错误,有一些需要直接标记已发送,跳过
  351. if strings.Contains(uploadSubReply.Message, "sub file sha256 not match") == true ||
  352. strings.Contains(uploadSubReply.Message, "determine sub file type error") == true ||
  353. strings.Contains(uploadSubReply.Message, "determine sub file type not match") == true ||
  354. strings.Contains(uploadSubReply.Message, "sub file has no chinese") == true {
  355. notUploadedVideoSubInfos[0].IsSend = true
  356. dao.GetDb().Save(&notUploadedVideoSubInfos[0])
  357. ch.log.Infoln("subtitle upload error, uploadSubReply.Status == 0, Message:", uploadSubReply.Message, "will not upload again")
  358. return
  359. } else {
  360. ch.log.Errorln("subtitle upload error, uploadSubReply.Status == 0, not support error:", uploadSubReply.Message)
  361. return
  362. }
  363. } else {
  364. ch.log.Warningln("UploadSub Message:", uploadSubReply.Message)
  365. return
  366. }
  367. } else {
  368. // 不是预期的返回值,需要报警
  369. ch.log.Errorln(fmt.Errorf("AskFroUpload Not the expected return value, Status: %d, Message: %v", askForUploadReply.Status, askForUploadReply.Message))
  370. return
  371. }
  372. }