processor.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. package manual_upload_sub_2_local
  2. import (
  3. "sync"
  4. "github.com/ChineseSubFinder/ChineseSubFinder/internal/models"
  5. "github.com/ChineseSubFinder/ChineseSubFinder/pkg/scan_logic"
  6. "github.com/pkg/errors"
  7. "github.com/ChineseSubFinder/ChineseSubFinder/pkg/save_sub_helper"
  8. subCommon "github.com/ChineseSubFinder/ChineseSubFinder/pkg/sub_formatter/common"
  9. "github.com/ChineseSubFinder/ChineseSubFinder/pkg/logic/sub_parser/ass"
  10. "github.com/ChineseSubFinder/ChineseSubFinder/pkg/logic/sub_parser/srt"
  11. "github.com/ChineseSubFinder/ChineseSubFinder/pkg/sub_parser_hub"
  12. "github.com/ChineseSubFinder/ChineseSubFinder/pkg/sub_helper"
  13. "github.com/sirupsen/logrus"
  14. llq "github.com/emirpasic/gods/queues/linkedlistqueue"
  15. "github.com/emirpasic/gods/sets/hashset"
  16. )
  17. type ManualUploadSub2Local struct {
  18. log *logrus.Logger
  19. saveSubHelper *save_sub_helper.SaveSubHelper // 保存字幕的逻辑
  20. scanLogic *scan_logic.ScanLogic // 是否扫描逻辑
  21. subNameFormatter subCommon.FormatterName // 从 inSubFormatter 推断出来
  22. processQueue *llq.Queue
  23. jobSet *hashset.Set
  24. jobResultMap sync.Map
  25. addOneSignal chan interface{}
  26. addLocker sync.Mutex
  27. subParserHub *sub_parser_hub.SubParserHub
  28. workingJob *Job // 正在操作的任务的路径
  29. }
  30. func NewManualUploadSub2Local(log *logrus.Logger, saveSubHelper *save_sub_helper.SaveSubHelper, scanLogic *scan_logic.ScanLogic) *ManualUploadSub2Local {
  31. m := &ManualUploadSub2Local{
  32. log: log,
  33. saveSubHelper: saveSubHelper,
  34. scanLogic: scanLogic,
  35. processQueue: llq.New(),
  36. jobSet: hashset.New(),
  37. jobResultMap: sync.Map{},
  38. addOneSignal: make(chan interface{}, 1),
  39. subParserHub: sub_parser_hub.NewSubParserHub(log, ass.NewParser(log), srt.NewParser(log)),
  40. workingJob: nil,
  41. }
  42. // 这里就不单独弄一个 settings.SubNameFormatter 字段来传递值了,因为 inSubFormatter 就已经知道是什么 formatter 了
  43. m.subNameFormatter = subCommon.FormatterName(saveSubHelper.SubFormatter.GetFormatterFormatterName())
  44. go func(mu *ManualUploadSub2Local) {
  45. for {
  46. select {
  47. case _ = <-mu.addOneSignal:
  48. // 有新任务了
  49. m.dealers()
  50. }
  51. }
  52. }(m)
  53. return m
  54. }
  55. // IsJobInQueue 是否正在队列中排队,或者正在被处理
  56. func (m *ManualUploadSub2Local) IsJobInQueue(job *Job) bool {
  57. m.addLocker.Lock()
  58. defer func() {
  59. m.addLocker.Unlock()
  60. }()
  61. if job == nil || job.VideoFPath == "" {
  62. return false
  63. }
  64. if m.jobSet.Contains(job.VideoFPath) == true {
  65. // 已经在队列中了
  66. return true
  67. } else {
  68. if m.workingJob == nil {
  69. return false
  70. }
  71. // 还有一种可能,任务从队列拿出来了,正在处理,那么在外部开来也还是在队列中的
  72. if m.workingJob.VideoFPath == job.VideoFPath {
  73. return true
  74. }
  75. }
  76. return false
  77. }
  78. // Add 添加任务
  79. func (m *ManualUploadSub2Local) Add(job *Job) {
  80. m.addLocker.Lock()
  81. defer func() {
  82. m.addLocker.Unlock()
  83. }()
  84. if m.jobSet.Contains(job.VideoFPath) == true {
  85. // 已经在队列中了
  86. return
  87. }
  88. m.processQueue.Enqueue(job)
  89. m.jobSet.Add(job.VideoFPath)
  90. // 通知有新任务了
  91. m.addOneSignal <- struct{}{}
  92. return
  93. }
  94. // JobResult 任务结果,如果成功 ok,如果没有就是空,其他就是错误信息
  95. func (m *ManualUploadSub2Local) JobResult(job *Job) string {
  96. value, found := m.jobResultMap.LoadAndDelete(job.VideoFPath)
  97. if found == false {
  98. return ""
  99. }
  100. return value.(string)
  101. }
  102. // ListJob 任务列表
  103. func (m *ManualUploadSub2Local) ListJob() []*Job {
  104. m.addLocker.Lock()
  105. defer func() {
  106. m.addLocker.Unlock()
  107. }()
  108. ret := make([]*Job, 0)
  109. for _, v := range m.processQueue.Values() {
  110. ret = append(ret, v.(*Job))
  111. }
  112. if m.workingJob != nil {
  113. ret = append(ret, m.workingJob)
  114. }
  115. return ret
  116. }
  117. func (m *ManualUploadSub2Local) dealers() {
  118. m.addLocker.Lock()
  119. if m.processQueue.Empty() == true {
  120. // 没有任务了
  121. m.addLocker.Unlock()
  122. return
  123. }
  124. job, ok := m.processQueue.Dequeue()
  125. if ok == false {
  126. // 没有任务了
  127. m.addLocker.Unlock()
  128. return
  129. }
  130. // 移除这个任务
  131. m.jobSet.Remove(job.(*Job).VideoFPath)
  132. // 标记这个正在处理
  133. m.workingJob = job.(*Job)
  134. m.addLocker.Unlock()
  135. // 具体处理这个任务
  136. err := m.processSub(job.(*Job))
  137. if err != nil {
  138. m.log.Error(err)
  139. }
  140. }
  141. func (m *ManualUploadSub2Local) processSub(job *Job) error {
  142. var err error
  143. defer func() {
  144. // 任务处理完了
  145. m.addLocker.Lock()
  146. m.workingJob = nil
  147. m.addLocker.Unlock()
  148. if err != nil {
  149. m.jobResultMap.Store(job.VideoFPath, err.Error())
  150. } else {
  151. m.jobResultMap.Store(job.VideoFPath, "ok")
  152. }
  153. }()
  154. // 不管是不是保存多个字幕,都要先扫描本地的字幕,进行 .Default .Forced 去除
  155. // 这个视频的所有字幕,去除 .default .Forced 标记
  156. err = sub_helper.SearchVideoMatchSubFileAndRemoveExtMark(m.log, job.VideoFPath)
  157. if err != nil {
  158. // 找个错误可以忍
  159. m.log.Errorln("SearchVideoMatchSubFileAndRemoveExtMark,", job.VideoFPath, err)
  160. }
  161. bFind, subFileInfo, err := m.subParserHub.DetermineFileTypeFromFile(job.SubFPath)
  162. if err != nil {
  163. err = errors.New("DetermineFileTypeFromFile," + job.SubFPath + "," + err.Error())
  164. return err
  165. }
  166. if bFind == false {
  167. err = errors.New("DetermineFileTypeFromFile," + job.SubFPath + ",not support SubType")
  168. return err
  169. }
  170. var skipInfo *models.SkipScanInfo
  171. if m.subNameFormatter == subCommon.Emby {
  172. err = m.saveSubHelper.WriteSubFile2VideoPath(job.VideoFPath, *subFileInfo, "manual", true, false)
  173. if err != nil {
  174. err = errors.New("WriteSubFile2VideoPath," + job.VideoFPath + "," + err.Error())
  175. return err
  176. }
  177. // 默认设置这个视频“跳过”(跳过扫描和下载字幕)属性
  178. skipInfo = models.NewSkipScanInfoByMovie(job.VideoFPath, true)
  179. } else {
  180. err = m.saveSubHelper.WriteSubFile2VideoPath(job.VideoFPath, *subFileInfo, "manual", false, false)
  181. if err != nil {
  182. err = errors.New("WriteSubFile2VideoPath," + job.VideoFPath + "," + err.Error())
  183. return err
  184. }
  185. // 默认设置这个视频“跳过”(跳过扫描和下载字幕)属性
  186. skipInfo = models.NewSkipScanInfoBySeriesEx(job.VideoFPath, true)
  187. }
  188. m.scanLogic.Set(skipInfo)
  189. return nil
  190. }
  191. type Job struct {
  192. VideoFPath string `json:"video_f_path"`
  193. SubFPath string `json:"sub_f_path"`
  194. }
  195. type Reply struct {
  196. Jobs []*Job `json:"jobs"`
  197. }