Browse Source

完成 normal 的视频列表返回数据拼接收集

Signed-off-by: allan716 <[email protected]>
allan716 3 years ago
parent
commit
f89d9f4f23

+ 4 - 2
internal/backend/controllers/v1/controller_base.go

@@ -20,7 +20,8 @@ type ControllerBase struct {
 	videoScanAndRefreshHelperIsRunning  bool
 	videoScanAndRefreshHelperLocker     lock.Lock
 	videoScanAndRefreshHelperErrMessage string
-	MovieInfo                           []backend.MovieInfo
+	MovieInfos                          []backend.MovieInfo
+	SeasonInfos                         []backend.SeasonInfo
 }
 
 func NewControllerBase(log *logrus.Logger, cronHelper *cron_helper.CronHelper) *ControllerBase {
@@ -31,7 +32,8 @@ func NewControllerBase(log *logrus.Logger, cronHelper *cron_helper.CronHelper) *
 		// 这里因为不进行任务的添加,仅仅是扫描,所以 downloadQueue 可以为 nil
 		videoScanAndRefreshHelper:       video_scan_and_refresh_helper.NewVideoScanAndRefreshHelper(cronHelper.FileDownloader, nil),
 		videoScanAndRefreshHelperLocker: lock.NewLock(),
-		MovieInfo:                       make([]backend.MovieInfo, 0),
+		MovieInfos:                      make([]backend.MovieInfo, 0),
+		SeasonInfos:                     make([]backend.SeasonInfo, 0),
 	}
 }
 

+ 1 - 35
internal/backend/controllers/v1/video_list.go

@@ -1,14 +1,11 @@
 package v1
 
 import (
-	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sort_things"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/video_scan_and_refresh_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/backend"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/task_queue"
 	"github.com/gin-gonic/gin"
 	"net/http"
-	"path/filepath"
-	"strings"
 )
 
 func (cb *ControllerBase) RefreshVideoListStatusHandler(c *gin.Context) {
@@ -72,10 +69,6 @@ func (cb *ControllerBase) RefreshVideoListHandler(c *gin.Context) {
 		}
 
 		pathUrlMap := cb.StaticFileSystemBackEnd.GetPathUrlMap()
-		// 排序得到匹配上的路径,最长的那个
-		sortMoviePaths := sort_things.SortStringSliceByLength(cb.cronHelper.Settings.CommonSettings.MoviePaths)
-		sortSeriesPaths := sort_things.SortStringSliceByLength(cb.cronHelper.Settings.CommonSettings.SeriesPaths)
-
 		if cb.cronHelper.Settings.EmbySettings.Enable == true {
 			// Emby 情况
 			if scanVideoResult.Emby == nil {
@@ -87,34 +80,7 @@ func (cb *ControllerBase) RefreshVideoListHandler(c *gin.Context) {
 			if scanVideoResult.Normal == nil {
 				return
 			}
-			replaceIndexMap := make(map[int]int)
-			for _, orgPrePath := range sortMoviePaths {
-				for i, oneMovieFPath := range scanVideoResult.Normal.MovieFileFullPathList {
-
-					_, found := replaceIndexMap[i]
-					if found == true {
-						// 替换过了,跳过
-						continue
-					}
-					if strings.HasPrefix(oneMovieFPath, orgPrePath.Path) == true {
-
-						desUrl, found := pathUrlMap[orgPrePath.Path]
-						if found == false {
-							// 没有找到对应的 URL
-							continue
-						}
-						// 匹配上了前缀就替换这个,并记录
-						movieFUrl := strings.ReplaceAll(oneMovieFPath, orgPrePath.Path, desUrl)
-						oneMovieInfo := backend.MovieInfo{
-							Name:       filepath.Base(movieFUrl),
-							DirRootUrl: filepath.Dir(movieFUrl),
-							VideoUrl:   movieFUrl,
-						}
-						replaceIndexMap[i] = i
-						cb.MovieInfo = append(cb.MovieInfo, oneMovieInfo)
-					}
-				}
-			}
+			cb.MovieInfos, cb.SeasonInfos = cb.videoScanAndRefreshHelper.ScrabbleUpVideoList(scanVideoResult, pathUrlMap)
 		}
 
 		println("haha")

+ 2 - 2
internal/logic/cron_helper/cron_helper.go

@@ -114,6 +114,8 @@ func (ch *CronHelper) Start(runImmediately bool) {
 		ch.log.Panicln("CronHelper QueueDownloader, Cron entryID:", ch.entryIDScanPlayedVideoSubInfo, "Error:", err)
 	}
 
+	ch.downloader.SupplierCheck()
+
 	// 是否在定时器开启前先执行一次任务
 	if runImmediately == true {
 
@@ -123,8 +125,6 @@ func (ch *CronHelper) Start(runImmediately bool) {
 			ch.scanVideoProcessAdd2DownloadQueue()
 		}
 
-		ch.downloader.SupplierCheck()
-
 		ch.log.Infoln("First Time scanVideoProcessAdd2DownloadQueue End")
 
 	} else {

+ 22 - 65
internal/pkg/my_util/util.go

@@ -12,8 +12,10 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/regex_things"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sort_things"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	browser "github.com/allanpk716/fake-useragent"
+	"github.com/emirpasic/gods/maps/treemap"
 	"github.com/go-resty/resty/v2"
 	"github.com/google/uuid"
 	"github.com/sirupsen/logrus"
@@ -27,7 +29,6 @@ import (
 	"path/filepath"
 	"regexp"
 	"runtime"
-	"sort"
 	"strconv"
 	"strings"
 	"time"
@@ -226,7 +227,7 @@ func VideoNameSearchKeywordMaker(l *logrus.Logger, title string, year string) st
 }
 
 // SearchMatchedVideoFileFromDirs 搜索符合后缀名的视频文件
-func SearchMatchedVideoFileFromDirs(l *logrus.Logger, dirs []string) ([]string, error) {
+func SearchMatchedVideoFileFromDirs(l *logrus.Logger, dirs []string) (*treemap.Map, error) {
 
 	defer func() {
 		l.Infoln("SearchMatchedVideoFileFromDirs End")
@@ -235,25 +236,35 @@ func SearchMatchedVideoFileFromDirs(l *logrus.Logger, dirs []string) ([]string,
 	l.Infoln(" --------------------------------------------------")
 	l.Infoln("SearchMatchedVideoFileFromDirs Start...")
 
-	var fileFullPathList = make([]string, 0)
+	var fileFullPathMap = treemap.NewWithStringComparator()
 	for _, dir := range dirs {
 
 		matchedVideoFile, err := SearchMatchedVideoFile(l, dir)
 		if err != nil {
 			return nil, err
 		}
-
-		fileFullPathList = append(fileFullPathList, matchedVideoFile...)
+		value, found := fileFullPathMap.Get(dir)
+		if found == false {
+			fileFullPathMap.Put(dir, matchedVideoFile)
+		} else {
+			value = append(value.([]string), matchedVideoFile...)
+			fileFullPathMap.Put(dir, value)
+		}
 	}
 
-	// 排序,从最新的到最早的
-	fileFullPathList = SortByModTime(fileFullPathList)
+	fileFullPathMap.Each(func(seriesRootPathName interface{}, seriesNames interface{}) {
 
-	for _, s := range fileFullPathList {
-		l.Debugln(s)
-	}
+		oneSeriesRootPathName := seriesRootPathName.(string)
+		fileFullPathList := seriesNames.([]string)
+		// 排序,从最新的到最早的
+		fileFullPathList = sort_things.SortByModTime(fileFullPathList)
+		for _, s := range fileFullPathList {
+			l.Debugln(s)
+		}
+		fileFullPathMap.Put(oneSeriesRootPathName, fileFullPathList)
+	})
 
-	return fileFullPathList, nil
+	return fileFullPathMap, nil
 }
 
 // SearchMatchedVideoFile 搜索符合后缀名的视频文件,现在也会把 BDMV 的文件搜索出来,但是这个并不是一个视频文件,需要在后续特殊处理
@@ -315,60 +326,6 @@ func SearchMatchedVideoFile(l *logrus.Logger, dir string) ([]string, error) {
 	return fileFullPathList, nil
 }
 
-func GetFileModTime(fileFPath string) time.Time {
-
-	if IsFile(fileFPath) == true {
-		// 存在
-		fi, err := os.Stat(fileFPath)
-		if err != nil {
-			return time.Time{}
-		}
-
-		return fi.ModTime()
-	} else {
-		// 不存在才需要考虑蓝光情况
-		bok, idBDMVFPath, _ := decode.IsFakeBDMVWorked(fileFPath)
-		if bok == false {
-			// 也不是蓝光
-			return time.Time{}
-		}
-		// 获取这个蓝光 ID BDMV 文件的时间
-		fInfo, err := os.Stat(idBDMVFPath)
-		if err != nil {
-			return time.Time{}
-		}
-		return fInfo.ModTime()
-	}
-}
-
-// SortByModTime 根据文件的 Mod Time 进行排序,递减
-func SortByModTime(fileList []string) []string {
-
-	byModTime := make(ByModTime, 0)
-	byModTime = append(byModTime, fileList...)
-	sort.Sort(sort.Reverse(byModTime))
-
-	return byModTime
-}
-
-type ByModTime []string
-
-func (fis ByModTime) Len() int {
-	return len(fis)
-}
-
-func (fis ByModTime) Swap(i, j int) {
-	fis[i], fis[j] = fis[j], fis[i]
-}
-
-func (fis ByModTime) Less(i, j int) bool {
-
-	aModTime := GetFileModTime(fis[i])
-	bModTime := GetFileModTime(fis[j])
-
-	return aModTime.Before(bModTime)
-}
-
 // FileNameIsBDMV 是否是 BDMV 蓝光目录,符合返回 true,以及 fakseVideoFPath
 func FileNameIsBDMV(id_bdmv_fileFPath string) (bool, string) {
 	/*

+ 73 - 1
internal/pkg/sort_things/sort_things.go

@@ -1,6 +1,11 @@
 package sort_things
 
-import "sort"
+import (
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
+	"os"
+	"sort"
+	"time"
+)
 
 type PathSlice struct {
 	Path string
@@ -22,3 +27,70 @@ func SortStringSliceByLength(m []string) PathSlices {
 	sort.Sort(sort.Reverse(p))
 	return p
 }
+
+// -----------------------------------------------------------------------------
+
+// SortByModTime 根据文件的 Mod Time 进行排序,递减
+func SortByModTime(fileList []string) []string {
+
+	byModTime := make(ByModTime, 0)
+	byModTime = append(byModTime, fileList...)
+	sort.Sort(sort.Reverse(byModTime))
+
+	return byModTime
+}
+
+type ByModTime []string
+
+func (fis ByModTime) Len() int {
+	return len(fis)
+}
+
+func (fis ByModTime) Swap(i, j int) {
+	fis[i], fis[j] = fis[j], fis[i]
+}
+
+func (fis ByModTime) Less(i, j int) bool {
+
+	aModTime := GetFileModTime(fis[i])
+	bModTime := GetFileModTime(fis[j])
+
+	return aModTime.Before(bModTime)
+}
+
+func GetFileModTime(fileFPath string) time.Time {
+
+	if IsFile(fileFPath) == true {
+		// 存在
+		fi, err := os.Stat(fileFPath)
+		if err != nil {
+			return time.Time{}
+		}
+
+		return fi.ModTime()
+	} else {
+		// 不存在才需要考虑蓝光情况
+		bok, idBDMVFPath, _ := decode.IsFakeBDMVWorked(fileFPath)
+		if bok == false {
+			// 也不是蓝光
+			return time.Time{}
+		}
+		// 获取这个蓝光 ID BDMV 文件的时间
+		fInfo, err := os.Stat(idBDMVFPath)
+		if err != nil {
+			return time.Time{}
+		}
+		return fInfo.ModTime()
+	}
+}
+
+// -----------------------------------------------------------------------------
+
+// IsFile 存在且是文件
+func IsFile(filePath string) bool {
+	s, err := os.Stat(filePath)
+	if err != nil {
+		return false
+	}
+	return !s.IsDir()
+}

+ 147 - 29
internal/pkg/video_scan_and_refresh_helper/video_scan_and_refresh_helper.go

@@ -16,6 +16,7 @@ import (
 	subTimelineFixerPKG "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_timeline_fixer"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/task_control"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/task_queue"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/backend"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/emby"
 	TTaskqueue "github.com/allanpk716/ChineseSubFinder/internal/types/task_queue"
@@ -24,6 +25,7 @@ import (
 	"github.com/sirupsen/logrus"
 	"golang.org/x/net/context"
 	"path/filepath"
+	"strings"
 	"sync"
 )
 
@@ -129,7 +131,7 @@ func (v *VideoScanAndRefreshHelper) ScanNormalMovieAndSeries() (*ScanVideoResult
 		// --------------------------------------------------
 		// 电影
 		// 没有填写 emby_helper api 的信息,那么就走常规的全文件扫描流程
-		normalScanResult.MovieFileFullPathList, errMovie = my_util.SearchMatchedVideoFileFromDirs(v.log, v.settings.CommonSettings.MoviePaths)
+		normalScanResult.MoviesDirMap, errMovie = my_util.SearchMatchedVideoFileFromDirs(v.log, v.settings.CommonSettings.MoviePaths)
 		wg.Done()
 	}()
 	wg.Add(1)
@@ -231,6 +233,109 @@ func (v *VideoScanAndRefreshHelper) FilterMovieAndSeriesNeedDownload(scanVideoRe
 	return nil
 }
 
+func (v *VideoScanAndRefreshHelper) ScrabbleUpVideoList(scanVideoResult *ScanVideoResult, pathUrlMap map[string]string) ([]backend.MovieInfo, []backend.SeasonInfo) {
+
+	if scanVideoResult.Normal != nil && v.settings.EmbySettings.Enable == false {
+		return v.scrabbleUpVideoListNormal(scanVideoResult.Normal, pathUrlMap)
+	}
+
+	if scanVideoResult.Emby != nil && v.settings.EmbySettings.Enable == true {
+		return v.scrabbleUpVideoListEmby(scanVideoResult.Emby, pathUrlMap)
+	}
+
+	return nil, nil
+}
+
+func (v *VideoScanAndRefreshHelper) scrabbleUpVideoListNormal(normal *NormalScanVideoResult, pathUrlMap map[string]string) ([]backend.MovieInfo, []backend.SeasonInfo) {
+
+	movieInfos := make([]backend.MovieInfo, 0)
+	seasonInfos := make([]backend.SeasonInfo, 0)
+
+	if normal == nil {
+		return movieInfos, seasonInfos
+	}
+	// 电影
+	normal.MoviesDirMap.Each(func(movieDirRootPath interface{}, movieFPath interface{}) {
+
+		oneMovieDirRootPath := movieDirRootPath.(string)
+		for _, oneMovieFPath := range movieFPath.([]string) {
+
+			desUrl, found := pathUrlMap[oneMovieDirRootPath]
+			if found == false {
+				// 没有找到对应的 URL
+				continue
+			}
+			// 匹配上了前缀就替换这个,并记录
+			movieFUrl := strings.ReplaceAll(oneMovieFPath, oneMovieDirRootPath, desUrl)
+			oneMovieInfo := backend.MovieInfo{
+				Name:       filepath.Base(movieFUrl),
+				DirRootUrl: filepath.Dir(movieFUrl),
+				VideoFPath: oneMovieFPath,
+				VideoUrl:   movieFUrl,
+			}
+			movieInfos = append(movieInfos, oneMovieInfo)
+		}
+	})
+	// 连续剧
+	// seriesDirMap: dir <--> seriesList
+	normal.SeriesDirMap.Each(func(seriesRootPathName interface{}, seriesNames interface{}) {
+
+		oneSeriesRootPathName := seriesRootPathName.(string)
+		for _, oneSeriesRootDir := range seriesNames.([]string) {
+
+			desUrl, found := pathUrlMap[oneSeriesRootPathName]
+			if found == false {
+				// 没有找到对应的 URL
+				continue
+			}
+			bNeedDlSub, seriesInfo, err := v.subSupplierHub.SeriesNeedDlSub(oneSeriesRootDir,
+				v.NeedForcedScanAndDownSub, false)
+			if err != nil {
+				v.log.Errorln("filterMovieAndSeriesNeedDownloadNormal.SeriesNeedDlSub", err)
+				continue
+			}
+			if bNeedDlSub == false {
+				continue
+			}
+			seriesDirRootFUrl := strings.ReplaceAll(oneSeriesRootDir, oneSeriesRootPathName, desUrl)
+			oneSeasonInfo := backend.SeasonInfo{
+				Name:          filepath.Base(oneSeriesRootDir),
+				RootDirPath:   oneSeriesRootDir,
+				DirRootUrl:    seriesDirRootFUrl,
+				OneVideoInfos: make([]backend.OneVideoInfo, 0),
+			}
+			for _, epsInfo := range seriesInfo.EpList {
+
+				videoFUrl := strings.ReplaceAll(epsInfo.FileFullPath, oneSeriesRootPathName, desUrl)
+				oneVideoInfo := backend.OneVideoInfo{
+					Name:       epsInfo.Title,
+					VideoFPath: epsInfo.FileFullPath,
+					VideoUrl:   videoFUrl,
+					Season:     epsInfo.Season,
+					Episode:    epsInfo.Episode,
+				}
+				oneSeasonInfo.OneVideoInfos = append(oneSeasonInfo.OneVideoInfos, oneVideoInfo)
+			}
+
+			seasonInfos = append(seasonInfos, oneSeasonInfo)
+		}
+	})
+
+	return movieInfos, seasonInfos
+}
+
+func (v VideoScanAndRefreshHelper) scrabbleUpVideoListEmby(emby *EmbyScanVideoResult, pathUrlMap map[string]string) ([]backend.MovieInfo, []backend.SeasonInfo) {
+
+	movieInfos := make([]backend.MovieInfo, 0)
+	seasonInfos := make([]backend.SeasonInfo, 0)
+
+	if emby == nil {
+		return movieInfos, seasonInfos
+	}
+
+	return movieInfos, seasonInfos
+}
+
 func (v *VideoScanAndRefreshHelper) refreshEmbySubList() error {
 
 	if v.embyHelper == nil {
@@ -294,19 +399,26 @@ func (v *VideoScanAndRefreshHelper) updateLocalVideoCacheInfo(scanVideoResult *S
 	// ------------------------------------------------------------------------------
 	v.taskControl.SetCtxProcessFunc("updateLocalVideoCacheInfo", movieProcess, common.ScanPlayedSubTimeOut)
 	// ------------------------------------------------------------------------------
-	for i, oneMovieFPath := range scanVideoResult.Normal.MovieFileFullPathList {
-		err := v.taskControl.Invoke(&task_control.TaskData{
-			Index: i,
-			Count: len(scanVideoResult.Normal.MovieFileFullPathList),
-			DataEx: TaskInputData{
-				Index:     i,
-				InputPath: oneMovieFPath,
-			},
-		})
-		if err != nil {
-			return err
+	scanVideoResult.Normal.MoviesDirMap.Any(func(movieDirRootPath interface{}, movieFPath interface{}) bool {
+
+		//oneMovieDirRootPath := movieDirRootPath.(string)
+		for i, oneMovieFPath := range movieFPath.([]string) {
+			err := v.taskControl.Invoke(&task_control.TaskData{
+				Index: i,
+				Count: len(movieFPath.([]string)),
+				DataEx: TaskInputData{
+					Index:     i,
+					InputPath: oneMovieFPath,
+				},
+			})
+			if err != nil {
+				v.log.Errorln("updateLocalVideoCacheInfo.MoviesDirMap.Invoke", err)
+				return true
+			}
 		}
-	}
+
+		return false
+	})
 	v.taskControl.Hold()
 	// ------------------------------------------------------------------------------
 	seriesProcess := func(ctx context.Context, inData interface{}) error {
@@ -388,21 +500,27 @@ func (v *VideoScanAndRefreshHelper) filterMovieAndSeriesNeedDownloadNormal(norma
 	// ----------------------------------------
 	v.taskControl.SetCtxProcessFunc("updateLocalVideoCacheInfo", movieProcess, common.ScanPlayedSubTimeOut)
 	// ----------------------------------------
-	for i, oneMovieFPath := range normal.MovieFileFullPathList {
-		// 放入队列
-		err := v.taskControl.Invoke(&task_control.TaskData{
-			Index: i,
-			Count: len(normal.MovieFileFullPathList),
-			DataEx: TaskInputData{
-				Index:     i,
-				InputPath: oneMovieFPath,
-			},
-		})
-		if err != nil {
-			v.log.Errorln(err)
-			return err
+	normal.MoviesDirMap.Any(func(movieDirRootPath interface{}, movieFPath interface{}) bool {
+
+		//oneMovieDirRootPath := movieDirRootPath.(string)
+		for i, oneMovieFPath := range movieFPath.([]string) {
+			// 放入队列
+			err := v.taskControl.Invoke(&task_control.TaskData{
+				Index: i,
+				Count: len(movieFPath.([]string)),
+				DataEx: TaskInputData{
+					Index:     i,
+					InputPath: oneMovieFPath,
+				},
+			})
+			if err != nil {
+				v.log.Errorln(err)
+				return true
+			}
 		}
-	}
+
+		return false
+	})
 	v.taskControl.Hold()
 	// ----------------------------------------
 	// Normal 过滤,连续剧
@@ -580,8 +698,8 @@ type ScanVideoResult struct {
 }
 
 type NormalScanVideoResult struct {
-	MovieFileFullPathList []string
-	SeriesDirMap          *treemap.Map
+	MoviesDirMap *treemap.Map
+	SeriesDirMap *treemap.Map
 }
 
 type EmbyScanVideoResult struct {

+ 1 - 0
internal/types/backend/reply_movie_list.go

@@ -7,6 +7,7 @@ type ReplyMovieList struct {
 type MovieInfo struct {
 	Name                     string `json:"name"`
 	DirRootUrl               string `json:"dir_root_url"`
+	VideoFPath               string `json:"video_f_path"`
 	VideoUrl                 string `json:"video_url"`
 	MediaServerInsideVideoID string `json:"media_server_inside_video_id"`
 }

+ 10 - 6
internal/types/backend/reply_series_list.go

@@ -1,17 +1,21 @@
 package backend
 
 type ReplySeriesList struct {
-	Movies []MovieInfo `json:"movies"`
+	SeasonInfos []SeasonInfo `json:"season_infos"`
 }
 
 type SeasonInfo struct {
-	Name                     string `json:"name"`
-	Url                      string `json:"dir_root_url"`
-	MediaServerInsideVideoID string `json:"media_server_inside_video_id"`
+	Name          string         `json:"name"`
+	RootDirPath   string         `json:"root_dir_path"`
+	DirRootUrl    string         `json:"dir_root_url"`
+	OneVideoInfos []OneVideoInfo `json:"one_video_info"`
 }
 
-type EpsInfo struct {
+type OneVideoInfo struct {
 	Name                     string `json:"name"`
-	Url                      string `json:"dir_root_url"`
+	VideoFPath               string `json:"video_f_path"`
+	VideoUrl                 string `json:"video_url"`
+	Season                   int    `json:"season"`
+	Episode                  int    `json:"episode"`
 	MediaServerInsideVideoID string `json:"media_server_inside_video_id"`
 }