video_list_v2.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. package v1
  2. import (
  3. "fmt"
  4. "net/http"
  5. "path/filepath"
  6. "time"
  7. PTN "github.com/middelink/go-parse-torrent-name"
  8. "github.com/ChineseSubFinder/ChineseSubFinder/internal/models"
  9. "github.com/ChineseSubFinder/ChineseSubFinder/pkg/search"
  10. "github.com/ChineseSubFinder/ChineseSubFinder/pkg/sub_helper"
  11. "github.com/ChineseSubFinder/ChineseSubFinder/pkg/path_helper"
  12. backend2 "github.com/ChineseSubFinder/ChineseSubFinder/pkg/types/backend"
  13. vsh "github.com/ChineseSubFinder/ChineseSubFinder/pkg/video_scan_and_refresh_helper"
  14. "github.com/gin-gonic/gin"
  15. "github.com/pkg/errors"
  16. )
  17. // RefreshMainList 重构后的视频列表,比如 x:\电影\壮志凌云\壮志凌云.mp4 或者是连续剧的 x:\连续剧\绝命毒师 根目录
  18. func (cb *ControllerBase) RefreshMainList(c *gin.Context) {
  19. var err error
  20. defer func() {
  21. // 统一的异常处理
  22. cb.ErrorProcess(c, "RefreshMainList", err)
  23. }()
  24. if cb.videoScanAndRefreshHelperLocker.Lock() == false {
  25. // 已经在执行,跳过
  26. c.JSON(http.StatusOK, backend2.ReplyRefreshVideoList{
  27. Status: "running"})
  28. return
  29. }
  30. cb.videoScanAndRefreshHelperIsRunning = true
  31. go func() {
  32. startT := time.Now()
  33. cb.log.Infoln("------------------------------------")
  34. cb.log.Infoln("Video Scan Started By webui...")
  35. pathUrlMap := cb.GetPathUrlMap()
  36. cb.log.Infoln("---------------------------------")
  37. cb.log.Infoln("GetPathUrlMap")
  38. for s, s2 := range pathUrlMap {
  39. cb.log.Infoln("pathUrlMap", s, s2)
  40. }
  41. cb.log.Infoln("---------------------------------")
  42. defer func() {
  43. cb.videoScanAndRefreshHelperIsRunning = false
  44. cb.videoScanAndRefreshHelperLocker.Unlock()
  45. cb.log.Infoln("Video Scan Finished By webui, cost:", time.Since(startT).Minutes(), "min")
  46. cb.log.Infoln("------------------------------------")
  47. }()
  48. var err2 error
  49. cb.videoScanAndRefreshHelperErrMessage = ""
  50. var mainList *vsh.NormalScanVideoResult
  51. mainList, err2 = cb.videoListHelper.RefreshMainList()
  52. if err2 != nil {
  53. cb.log.Errorln("RefreshMainList", err2)
  54. cb.videoScanAndRefreshHelperErrMessage = err2.Error()
  55. return
  56. }
  57. err2 = cb.cronHelper.Downloader.SetMovieAndSeasonInfoV2(mainList)
  58. if err2 != nil {
  59. cb.log.Errorln("SetMovieAndSeasonInfoV2", err2)
  60. cb.videoScanAndRefreshHelperErrMessage = err2.Error()
  61. return
  62. }
  63. }()
  64. c.JSON(http.StatusOK, backend2.ReplyRefreshVideoList{
  65. Status: "running"})
  66. return
  67. }
  68. // VideoMainList 获取电影和连续剧的基础结构
  69. func (cb *ControllerBase) VideoMainList(c *gin.Context) {
  70. var err error
  71. defer func() {
  72. // 统一的异常处理
  73. cb.ErrorProcess(c, "MoviePoster", err)
  74. }()
  75. outMovieInfos, outSeasonInfo, err := cb.cronHelper.Downloader.GetMovieInfoAndSeasonInfoV2()
  76. if err != nil {
  77. cb.log.Errorln("GetMovieInfoAndSeasonInfoV2", err)
  78. return
  79. }
  80. c.JSON(http.StatusOK, backend2.ReplyMainList{
  81. MovieInfos: outMovieInfos,
  82. SeasonInfos: outSeasonInfo,
  83. })
  84. }
  85. // MoviePoster 获取电影海报
  86. func (cb *ControllerBase) MoviePoster(c *gin.Context) {
  87. var err error
  88. defer func() {
  89. // 统一的异常处理
  90. cb.ErrorProcess(c, "MoviePoster", err)
  91. }()
  92. movieInfo := backend2.MovieInfoV2{}
  93. err = c.ShouldBindJSON(&movieInfo)
  94. if err != nil {
  95. return
  96. }
  97. // 然后还需要将这个全路径信息转换为 静态文件服务器对应的路径返回给前端
  98. desUrl, found := cb.GetPathUrlMap()[movieInfo.MainRootDirFPath]
  99. if found == false {
  100. // 没有找到对应的 URL
  101. errMessage := fmt.Sprintf("MoviePoster.GetPathUrlMap can not find url for path %s", movieInfo.MainRootDirFPath)
  102. cb.log.Warningln(errMessage)
  103. err = errors.New(errMessage)
  104. return
  105. }
  106. posterFPath := cb.videoListHelper.GetMoviePoster(movieInfo.VideoFPath)
  107. posterUrl := path_helper.ChangePhysicalPathToSharePath(posterFPath, movieInfo.MainRootDirFPath, desUrl)
  108. c.JSON(http.StatusOK, backend2.PosterInfo{
  109. Url: posterUrl,
  110. })
  111. }
  112. // SeriesPoster 从一个连续剧的根目录中,获取连续剧的海报
  113. func (cb *ControllerBase) SeriesPoster(c *gin.Context) {
  114. var err error
  115. defer func() {
  116. // 统一的异常处理
  117. cb.ErrorProcess(c, "SeriesPoster", err)
  118. }()
  119. seriesInfo := backend2.SeasonInfoV2{}
  120. err = c.ShouldBindJSON(&seriesInfo)
  121. if err != nil {
  122. return
  123. }
  124. // 然后还需要将这个全路径信息转换为 静态文件服务器对应的路径返回给前端
  125. desUrl, found := cb.GetPathUrlMap()[seriesInfo.MainRootDirFPath]
  126. if found == false {
  127. // 没有找到对应的 URL
  128. errMessage := fmt.Sprintf("SeriesPoster.GetPathUrlMap can not find url for path %s", seriesInfo.MainRootDirFPath)
  129. cb.log.Warningln(errMessage)
  130. err = errors.New(errMessage)
  131. return
  132. }
  133. posterFPath := cb.videoListHelper.GetSeriesPoster(seriesInfo.RootDirPath)
  134. posterUrl := path_helper.ChangePhysicalPathToSharePath(posterFPath, seriesInfo.MainRootDirFPath, desUrl)
  135. c.JSON(http.StatusOK, backend2.PosterInfo{
  136. Url: posterUrl,
  137. })
  138. }
  139. // OneMovieSubs 由一部电影去搜索其当前目录下的对应字幕
  140. func (cb *ControllerBase) OneMovieSubs(c *gin.Context) {
  141. var err error
  142. defer func() {
  143. // 统一的异常处理
  144. cb.ErrorProcess(c, "OneMovieSubs", err)
  145. }()
  146. movieInfo := backend2.MovieInfoV2{}
  147. err = c.ShouldBindJSON(&movieInfo)
  148. if err != nil {
  149. return
  150. }
  151. // 然后还需要将这个全路径信息转换为 静态文件服务器对应的路径返回给前端
  152. desUrl, found := cb.GetPathUrlMap()[movieInfo.MainRootDirFPath]
  153. if found == false {
  154. // 没有找到对应的 URL
  155. errMessage := fmt.Sprintf("OneMovieSubs.GetPathUrlMap can not find url for path %s", movieInfo.MainRootDirFPath)
  156. cb.log.Warningln(errMessage)
  157. err = errors.New(errMessage)
  158. return
  159. }
  160. matchedSubs, err := sub_helper.SearchMatchedSubFileByOneVideo(cb.log, movieInfo.VideoFPath)
  161. if err != nil {
  162. cb.log.Errorln("OneMovieSubs.SearchMatchedSubFileByOneVideo", err)
  163. return
  164. }
  165. movieSubsInfo := backend2.MovieSubsInfo{
  166. SubUrlList: make([]string, 0),
  167. }
  168. // 将匹配到的字幕文件转换为 URL
  169. for _, sub := range matchedSubs {
  170. subUrl := path_helper.ChangePhysicalPathToSharePath(sub, movieInfo.MainRootDirFPath, desUrl)
  171. movieSubsInfo.SubUrlList = append(movieSubsInfo.SubUrlList, subUrl)
  172. movieSubsInfo.SubFPathList = append(movieSubsInfo.SubFPathList, sub)
  173. }
  174. c.JSON(http.StatusOK, movieSubsInfo)
  175. }
  176. func (cb *ControllerBase) OneSeriesSubs(c *gin.Context) {
  177. var err error
  178. defer func() {
  179. // 统一的异常处理
  180. cb.ErrorProcess(c, "OneSeriesSubs", err)
  181. }()
  182. seriesInfo := backend2.SeasonInfoV2{}
  183. err = c.ShouldBindJSON(&seriesInfo)
  184. if err != nil {
  185. return
  186. }
  187. // 然后还需要将这个全路径信息转换为 静态文件服务器对应的路径返回给前端
  188. desUrl, found := cb.GetPathUrlMap()[seriesInfo.MainRootDirFPath]
  189. if found == false {
  190. // 没有找到对应的 URL
  191. errMessage := fmt.Sprintf("OneSeriesSubs.GetPathUrlMap can not find url for path %s", seriesInfo.MainRootDirFPath)
  192. cb.log.Warningln(errMessage)
  193. err = errors.New(errMessage)
  194. return
  195. }
  196. seasonInfo, err := search.SeriesAllEpsAndSubtitles(cb.log, seriesInfo.RootDirPath)
  197. if err != nil {
  198. cb.log.Errorln("OneSeriesSubs.SeriesAllEpsAndSubtitles", err)
  199. return
  200. }
  201. for i, videoInfo := range seasonInfo.OneVideoInfos {
  202. for _, subFPath := range videoInfo.SubFPathList {
  203. subUrl := path_helper.ChangePhysicalPathToSharePath(subFPath, seriesInfo.MainRootDirFPath, desUrl)
  204. seasonInfo.OneVideoInfos[i].SubUrlList = append(seasonInfo.OneVideoInfos[i].SubUrlList, subUrl)
  205. }
  206. videoUrl := path_helper.ChangePhysicalPathToSharePath(videoInfo.VideoFPath, seriesInfo.MainRootDirFPath, desUrl)
  207. seasonInfo.OneVideoInfos[i].VideoUrl = videoUrl
  208. }
  209. c.JSON(http.StatusOK, seasonInfo)
  210. }
  211. // ScanSkipInfo 设置或者获取跳过扫描信息的状态
  212. func (cb *ControllerBase) ScanSkipInfo(c *gin.Context) {
  213. var err error
  214. defer func() {
  215. // 统一的异常处理
  216. cb.ErrorProcess(c, "ScanSkipInfo", err)
  217. }()
  218. switch c.Request.Method {
  219. case "POST":
  220. {
  221. // 查询
  222. videoSkipInfo := backend2.ReqVideoSkipInfo{}
  223. err = c.ShouldBindJSON(&videoSkipInfo)
  224. if err != nil {
  225. return
  226. }
  227. isSkip := cb.cronHelper.Downloader.ScanLogic.Get(videoSkipInfo.VideoType, videoSkipInfo.PhysicalVideoFileFullPath)
  228. c.JSON(http.StatusOK, backend2.ReplyVideoSkipInfo{
  229. IsSkip: isSkip,
  230. })
  231. return
  232. }
  233. case "PUT":
  234. {
  235. // 设置
  236. videoSkipInfo := backend2.ReqVideoSkipInfo{}
  237. err = c.ShouldBindJSON(&videoSkipInfo)
  238. if err != nil {
  239. return
  240. }
  241. var skipInfo *models.SkipScanInfo
  242. if videoSkipInfo.VideoType == 0 {
  243. // 电影
  244. skipInfo = models.NewSkipScanInfoByMovie(videoSkipInfo.PhysicalVideoFileFullPath, videoSkipInfo.IsSkip)
  245. } else {
  246. // 电视剧
  247. var parse *PTN.TorrentInfo
  248. parse, err = PTN.Parse(videoSkipInfo.PhysicalVideoFileFullPath)
  249. if err != nil {
  250. cb.log.Errorln("SetScanSkipInfo.PTN.Parse", err)
  251. return
  252. }
  253. dirFPath := filepath.Dir(filepath.Dir(videoSkipInfo.PhysicalVideoFileFullPath))
  254. skipInfo = models.NewSkipScanInfoBySeries(dirFPath, parse.Season, parse.Episode, videoSkipInfo.IsSkip)
  255. }
  256. cb.cronHelper.Downloader.ScanLogic.Set(skipInfo)
  257. c.JSON(http.StatusOK, backend2.ReplyCommon{
  258. Message: "ok"})
  259. return
  260. }
  261. default:
  262. c.JSON(http.StatusNoContent, backend2.ReplyCommon{Message: "ScanSkipInfo Request.Method Error"})
  263. }
  264. }