Explorar o código

新增视频列表的刷新和状态获取后端接口

Signed-off-by: allan716 <[email protected]>
allan716 %!s(int64=3) %!d(string=hai) anos
pai
achega
39dc751cd2

+ 4 - 2
internal/backend/backend.go

@@ -22,8 +22,10 @@ func StartBackEnd(fileDownloader *file_downloader.FileDownloader, httpPort int,
 	engine := gin.Default()
 	// 默认所有都通过
 	engine.Use(cors.Default())
-	routers.InitRouter(fileDownloader, engine, cronHelper)
-
+	v1Router := routers.InitRouter(fileDownloader, engine, cronHelper)
+	defer func() {
+		v1Router.Close()
+	}()
 	engine.GET("/", func(c *gin.Context) {
 		c.Header("content-type", "text/html;charset=utf-8")
 		c.String(http.StatusOK, string(dist.SpaIndexHtml))

+ 17 - 0
internal/backend/controllers/v1/controller_base.go

@@ -3,6 +3,8 @@ package v1
 import (
 	"github.com/allanpk716/ChineseSubFinder/internal/backend/controllers/base"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/cron_helper"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/lock"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/video_scan_and_refresh_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/backend"
 	"github.com/gin-gonic/gin"
 	"github.com/sirupsen/logrus"
@@ -13,6 +15,12 @@ type ControllerBase struct {
 	log                     *logrus.Logger
 	cronHelper              *cron_helper.CronHelper
 	StaticFileSystemBackEnd *base.StaticFileSystemBackEnd
+
+	videoScanAndRefreshHelper           *video_scan_and_refresh_helper.VideoScanAndRefreshHelper
+	videoScanAndRefreshHelperIsRunning  bool
+	videoScanAndRefreshHelperLocker     lock.Lock
+	scanVideoResult                     *video_scan_and_refresh_helper.ScanVideoResult
+	videoScanAndRefreshHelperErrMessage string
 }
 
 func NewControllerBase(log *logrus.Logger, cronHelper *cron_helper.CronHelper) *ControllerBase {
@@ -20,9 +28,18 @@ func NewControllerBase(log *logrus.Logger, cronHelper *cron_helper.CronHelper) *
 		log:                     log,
 		cronHelper:              cronHelper,
 		StaticFileSystemBackEnd: base.NewStaticFileSystemBackEnd(log),
+		// 这里因为不进行任务的添加,仅仅是扫描,所以 downloadQueue 可以为 nil
+		videoScanAndRefreshHelper:       video_scan_and_refresh_helper.NewVideoScanAndRefreshHelper(cronHelper.FileDownloader, nil),
+		videoScanAndRefreshHelperLocker: lock.NewLock(),
 	}
 }
 
+func (cb *ControllerBase) Close() {
+	cb.cronHelper.Stop()
+	cb.videoScanAndRefreshHelper.Cancel()
+	cb.videoScanAndRefreshHelperLocker.Close()
+}
+
 func (cb ControllerBase) GetVersion() string {
 	return "v1"
 }

+ 64 - 0
internal/backend/controllers/v1/video_list.go

@@ -7,6 +7,70 @@ import (
 	"net/http"
 )
 
+func (cb *ControllerBase) RefreshVideoListStatusHandler(c *gin.Context) {
+	var err error
+	defer func() {
+		// 统一的异常处理
+		cb.ErrorProcess(c, "RefreshVideoListStatusHandler", err)
+	}()
+
+	status := "running"
+	if cb.videoScanAndRefreshHelperIsRunning == false {
+		status = "stopped"
+	}
+
+	c.JSON(http.StatusOK, backend.ReplyRefreshVideoList{
+		Status:     status,
+		ErrMessage: cb.videoScanAndRefreshHelperErrMessage})
+	return
+}
+
+func (cb *ControllerBase) RefreshVideoListHandler(c *gin.Context) {
+	var err error
+	defer func() {
+		// 统一的异常处理
+		cb.ErrorProcess(c, "RefreshVideoListHandler", err)
+	}()
+
+	if cb.videoScanAndRefreshHelperLocker.Lock() == false {
+		// 已经在执行,跳过
+		c.JSON(http.StatusOK, backend.ReplyRefreshVideoList{
+			Status: "running"})
+		return
+	}
+	cb.videoScanAndRefreshHelperIsRunning = true
+	go func() {
+		defer func() {
+			cb.videoScanAndRefreshHelperIsRunning = false
+			cb.videoScanAndRefreshHelperLocker.Unlock()
+			cb.log.Infoln("Video Scan End By webui")
+			cb.log.Infoln("------------------------------------")
+		}()
+
+		cb.log.Infoln("------------------------------------")
+		cb.log.Infoln("Video Scan Started By webui...")
+		// 先进行扫描
+		var err2 error
+		cb.videoScanAndRefreshHelperErrMessage = ""
+		cb.scanVideoResult, err2 = cb.videoScanAndRefreshHelper.ScanNormalMovieAndSeries()
+		if err2 != nil {
+			cb.log.Errorln("ScanNormalMovieAndSeries", err2)
+			cb.videoScanAndRefreshHelperErrMessage = err2.Error()
+			return
+		}
+		err2 = cb.videoScanAndRefreshHelper.ScanEmbyMovieAndSeries(cb.scanVideoResult)
+		if err2 != nil {
+			cb.log.Errorln("ScanEmbyMovieAndSeries", err2)
+			cb.videoScanAndRefreshHelperErrMessage = err2.Error()
+			return
+		}
+	}()
+
+	c.JSON(http.StatusOK, backend.ReplyRefreshVideoList{
+		Status: "running"})
+	return
+}
+
 func (cb ControllerBase) MovieListHandler(c *gin.Context) {
 	var err error
 	defer func() {

+ 7 - 3
internal/backend/routers/base_router.go

@@ -9,7 +9,7 @@ import (
 	"github.com/gin-gonic/gin"
 )
 
-func InitRouter(fileDownloader *file_downloader.FileDownloader, router *gin.Engine, cronHelper *cron_helper.CronHelper) {
+func InitRouter(fileDownloader *file_downloader.FileDownloader, router *gin.Engine, cronHelper *cron_helper.CronHelper) *v1.ControllerBase {
 
 	cbBase := base.NewControllerBase(fileDownloader)
 	cbV1 := v1.NewControllerBase(fileDownloader.Log, cronHelper)
@@ -51,7 +51,11 @@ func InitRouter(fileDownloader *file_downloader.FileDownloader, router *gin.Engi
 		GroupV1.POST("/jobs/change-job-status", cbV1.ChangeJobStatusHandler)
 		GroupV1.POST("/jobs/log", cbV1.JobLogHandler)
 
-		GroupV1.POST("/video/list/movies", cbV1.MovieListHandler)
-		GroupV1.POST("/video/list/series", cbV1.SeriesListHandler)
+		GroupV1.POST("/video/list/refresh", cbV1.RefreshVideoListHandler)
+		GroupV1.GET("/video/list/refresh", cbV1.RefreshVideoListStatusHandler)
+		GroupV1.GET("/video/list/movies", cbV1.MovieListHandler)
+		GroupV1.GET("/video/list/series", cbV1.SeriesListHandler)
 	}
+
+	return cbV1
 }

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

@@ -18,7 +18,7 @@ type CronHelper struct {
 	stopping                      bool                                                     // 正在停止
 	cronHelperRunning             bool                                                     // 这个是定时器启动的状态,它为true,不代表核心函数在执行
 	scanPlayedVideoSubInfo        *scan_played_video_subinfo.ScanPlayedVideoSubInfo        // 扫描已经播放过的视频的字幕信息
-	fileDownloader                *file_downloader.FileDownloader                          // 文件下载器
+	FileDownloader                *file_downloader.FileDownloader                          // 文件下载器
 	DownloadQueue                 *task_queue.TaskQueue                                    // 需要下载的视频的队列
 	downloader                    *downloader.Downloader                                   // 下载者线程
 	videoScanAndRefreshHelper     *video_scan_and_refresh_helper.VideoScanAndRefreshHelper // 视频扫描和刷新的帮助类
@@ -35,7 +35,7 @@ type CronHelper struct {
 func NewCronHelper(fileDownloader *file_downloader.FileDownloader) *CronHelper {
 
 	ch := CronHelper{
-		fileDownloader: fileDownloader,
+		FileDownloader: fileDownloader,
 		log:            fileDownloader.Log,
 		Settings:       fileDownloader.Settings,
 		// 实例化下载队列
@@ -50,7 +50,7 @@ func NewCronHelper(fileDownloader *file_downloader.FileDownloader) *CronHelper {
 	}
 	// 字幕扫描器
 	ch.videoScanAndRefreshHelper = video_scan_and_refresh_helper.NewVideoScanAndRefreshHelper(
-		ch.fileDownloader,
+		ch.FileDownloader,
 		ch.DownloadQueue)
 
 	return &ch
@@ -75,7 +75,7 @@ func (ch *CronHelper) Start(runImmediately bool) {
 	// 初始化下载者,里面的两个 func 需要使用定时器启动 SupplierCheck QueueDownloader
 	ch.downloader = downloader.NewDownloader(
 		sub_formatter.GetSubFormatter(ch.log, ch.Settings.AdvancedSettings.SubNameFormatter),
-		ch.fileDownloader, ch.DownloadQueue)
+		ch.FileDownloader, ch.DownloadQueue)
 	// ----------------------------------------------
 	// 判断扫描任务的时间间隔是否符合要求,不符合则重写默认值
 	_, err := cron.ParseStandard(ch.Settings.CommonSettings.ScanInterval)

+ 24 - 0
internal/pkg/lock/example_test.go

@@ -0,0 +1,24 @@
+//go:build !windows && !plan9
+// +build !windows,!plan9
+
+package lock
+
+func ExampleNewLock() {
+	var l = NewLock()
+	var wg sync.WaitGroup
+	for i := 0; i < 10; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			if l.Lock() == false {
+				// log error
+				println("lock failed")
+				return
+			}
+			counter++
+			println("current counter", counter)
+			l.Unlock()
+		}()
+	}
+	wg.Wait()
+}

+ 34 - 0
internal/pkg/lock/lock.go

@@ -0,0 +1,34 @@
+package lock
+
+// Lock try lock
+type Lock struct {
+	c chan struct{}
+}
+
+// NewLock generate a try lock
+func NewLock() Lock {
+	var l Lock
+	l.c = make(chan struct{}, 1)
+	l.c <- struct{}{}
+	return l
+}
+
+// Lock try lock, return lock result
+func (l Lock) Lock() bool {
+	lockResult := false
+	select {
+	case <-l.c:
+		lockResult = true
+	default:
+	}
+	return lockResult
+}
+
+// Unlock , Unlock the try lock
+func (l Lock) Unlock() {
+	l.c <- struct{}{}
+}
+
+func (l Lock) Close() {
+	close(l.c)
+}

+ 6 - 0
internal/types/backend/reply_refresh_video_list.go

@@ -0,0 +1,6 @@
+package backend
+
+type ReplyRefreshVideoList struct {
+	Status     string `json:"status"` // "status": "running","stopped"
+	ErrMessage string `json:"err_message"`
+}