upload_played_video_sub.go 14 KB

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