Selaa lähdekoodia

新增,基本的是否跳过某一个具体的视频文件的存储逻辑

Signed-off-by: allan716 <[email protected]>
allan716 3 vuotta sitten
vanhempi
sitoutus
a69afd4b26

+ 1 - 1
cmd/chinesesubfinder/main.go

@@ -125,7 +125,7 @@ func main() {
 		common.SetApiToken("")
 	}
 	// 是否开启开发模式,跳过某些流程
-	settings.GetSettings().SpeedDevMode = false
+	settings.GetSettings().SpeedDevMode = true
 	if settings.GetSettings().SpeedDevMode == true {
 		loggerBase.Infoln("Speed Dev Mode is On")
 		pkg.SetLiteMode(true)

+ 2 - 0
internal/backend/base_router.go

@@ -91,6 +91,8 @@ func InitRouter(
 		GroupV1.POST("/video/list/series_poster", cbV1.SeriesPoster)
 		GroupV1.POST("/video/list/one_movie_subs", cbV1.OneMovieSubs)
 		GroupV1.POST("/video/list/one_series_subs", cbV1.OneSeriesSubs)
+		GroupV1.POST("/video/list/scan_skip_info", cbV1.ScanSkipInfo)
+		GroupV1.PUT("/video/list/scan_skip_info", cbV1.ScanSkipInfo)
 	}
 
 	GroupAPIV1 := router.Group("/api/v1")

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

@@ -3,8 +3,13 @@ package v1
 import (
 	"fmt"
 	"net/http"
+	"path/filepath"
 	"time"
 
+	PTN "github.com/middelink/go-parse-torrent-name"
+
+	"github.com/allanpk716/ChineseSubFinder/internal/models"
+
 	"github.com/allanpk716/ChineseSubFinder/pkg/search"
 
 	"github.com/allanpk716/ChineseSubFinder/pkg/sub_helper"
@@ -243,4 +248,63 @@ func (cb *ControllerBase) OneSeriesSubs(c *gin.Context) {
 	c.JSON(http.StatusOK, seasonInfo)
 }
 
+// ScanSkipInfo 设置或者获取跳过扫描信息的状态
+func (cb *ControllerBase) ScanSkipInfo(c *gin.Context) {
+	var err error
+	defer func() {
+		// 统一的异常处理
+		cb.ErrorProcess(c, "ScanSkipInfo", err)
+	}()
+
+	switch c.Request.Method {
+	case "POST":
+		{
+			// 查询
+			videoSkipInfo := backend2.ReqVideoSkipInfo{}
+			err = c.ShouldBindJSON(&videoSkipInfo)
+			if err != nil {
+				return
+			}
+			isSkip := cb.cronHelper.Downloader.ScanLogic.Get(videoSkipInfo.VideoType, videoSkipInfo.PhysicalVideoFileFullPath)
+			c.JSON(http.StatusOK, backend2.ReplyVideoSkipInfo{
+				IsSkip: isSkip,
+			})
+			return
+		}
+	case "PUT":
+		{
+			// 设置
+			videoSkipInfo := backend2.ReqVideoSkipInfo{}
+			err = c.ShouldBindJSON(&videoSkipInfo)
+			if err != nil {
+				return
+			}
+
+			var skipInfo *models.SkipScanInfo
+			if videoSkipInfo.VideoType == 0 {
+				// 电影
+				skipInfo = models.NewSkipScanInfoByMovie(videoSkipInfo.PhysicalVideoFileFullPath, videoSkipInfo.IsSkip)
+			} else {
+				// 电视剧
+				var parse *PTN.TorrentInfo
+				parse, err = PTN.Parse(videoSkipInfo.PhysicalVideoFileFullPath)
+				if err != nil {
+					cb.log.Errorln("SetScanSkipInfo.PTN.Parse", err)
+					return
+				}
+				dirFPath := filepath.Dir(filepath.Dir(videoSkipInfo.PhysicalVideoFileFullPath))
+				skipInfo = models.NewSkipScanInfoBySeries(dirFPath, parse.Season, parse.Episode, videoSkipInfo.IsSkip)
+			}
+
+			cb.cronHelper.Downloader.ScanLogic.Set(skipInfo)
+
+			c.JSON(http.StatusOK, backend2.ReplyCommon{
+				Message: "ok"})
+			return
+		}
+	default:
+		c.JSON(http.StatusNoContent, backend2.ReplyCommon{Message: "ScanSkipInfo Request.Method Error"})
+	}
+}
+
 // v.refreshEmbySubList() 可以使用这个方案去刷新最近视频的字幕列表,最近的多少条可以 V 来设置

+ 1 - 0
internal/dao/init.go

@@ -76,6 +76,7 @@ func InitDb() error {
 		&models.MediaInfo{},
 		&models.LowVideoSubInfo{},
 		&models.Info{},
+		&models.SkipScanInfo{},
 	)
 	if err != nil {
 		return errors.New(fmt.Sprintf("db AutoMigrate error, %s", err.Error()))

+ 58 - 0
internal/models/skip_scan_info.go

@@ -0,0 +1,58 @@
+package models
+
+import (
+	"crypto/sha256"
+	"fmt"
+	"path/filepath"
+)
+
+type SkipScanInfo struct {
+	/*
+		这里的 UID 计算方式有两种:
+		1. 电影,由电影的文件夹路径计算 sha256 得到,X:\电影\Three Thousand Years of Longing (2022)
+		2. 连续剧,由连续剧的文件夹路径计算 sha256 得到,只能具体到一集(S01E01 这里是拼接出来的不是真正的文件名)
+			X:\连续剧\绝命毒师S01E01
+	*/
+	UID  string `gorm:"type:varchar(64);primarykey"`
+	Skip bool   `gorm:"type:bool;default:false"`
+}
+
+func NewSkipScanInfoByUID(uid string, skip bool) *SkipScanInfo {
+
+	var skipScanInfo SkipScanInfo
+	skipScanInfo.UID = uid
+	skipScanInfo.Skip = skip
+
+	return &skipScanInfo
+}
+
+func GenerateUID4Movie(movieFPath string) string {
+	movieDirPath := filepath.Dir(movieFPath)
+	fileUID := fmt.Sprintf("%x", sha256.Sum256([]byte(movieDirPath)))
+	return fileUID
+}
+
+func GenerateUID4Series(seriesDirFPath string, season, eps int) string {
+
+	mixInfo := fmt.Sprintf("%sS%02dE%02d", seriesDirFPath, season, eps)
+	fileUID := fmt.Sprintf("%x", sha256.Sum256([]byte(mixInfo)))
+	return fileUID
+}
+
+func NewSkipScanInfoByMovie(movieFPath string, skip bool) *SkipScanInfo {
+
+	var skipScanInfo SkipScanInfo
+	skipScanInfo.UID = GenerateUID4Movie(movieFPath)
+	skipScanInfo.Skip = skip
+
+	return &skipScanInfo
+}
+
+func NewSkipScanInfoBySeries(seriesDirFPath string, season, eps int, skip bool) *SkipScanInfo {
+
+	var skipScanInfo SkipScanInfo
+	skipScanInfo.UID = GenerateUID4Series(seriesDirFPath, season, eps)
+	skipScanInfo.Skip = skip
+
+	return &skipScanInfo
+}

+ 5 - 0
pkg/downloader/downloader.go

@@ -5,6 +5,8 @@ import (
 	"fmt"
 	"sync"
 
+	"github.com/allanpk716/ChineseSubFinder/pkg/scan_logic"
+
 	"github.com/allanpk716/ChineseSubFinder/pkg"
 
 	"github.com/allanpk716/ChineseSubFinder/pkg/logic/sub_supplier/assrt"
@@ -40,6 +42,7 @@ type Downloader struct {
 	downloaderLock           sync.Mutex                                   // 取消执行 task control 的 Lock
 	downloadQueue            *task_queue.TaskQueue                        // 需要下载的视频的队列
 	embyHelper               *embyHelper.EmbyHelper                       // Emby 的实例
+	ScanLogic                *scan_logic.ScanLogic                        // 是否扫描逻辑
 
 	cacheLocker   sync.Mutex
 	movieInfoMap  map[string]MovieInfo  // 给 Web 界面使用的,Key: VideoFPath
@@ -88,6 +91,8 @@ func NewDownloader(inSubFormatter ifaces.ISubFormatter, fileDownloader *file_dow
 		downloader.embyHelper = embyHelper.NewEmbyHelper(downloader.log, downloader.settings)
 	}
 
+	downloader.ScanLogic = scan_logic.NewScanLogic(downloader.log)
+
 	downloader.movieInfoMap = make(map[string]MovieInfo)
 	downloader.seasonInfoMap = make(map[string]SeasonInfo)
 

+ 80 - 0
pkg/scan_logic/scan_logic.go

@@ -0,0 +1,80 @@
+package scan_logic
+
+import (
+	"path/filepath"
+	"sync"
+
+	PTN "github.com/middelink/go-parse-torrent-name"
+	"github.com/sirupsen/logrus"
+
+	"github.com/allanpk716/ChineseSubFinder/internal/dao"
+	"github.com/allanpk716/ChineseSubFinder/internal/models"
+)
+
+type ScanLogic struct {
+	l            *logrus.Logger
+	scanLogicMap sync.Map
+}
+
+func NewScanLogic(l *logrus.Logger) *ScanLogic {
+
+	s := &ScanLogic{
+		l: l,
+	}
+	// 那么尝试读取数据库,进行缓存,仅执行一次
+	var skipInfos []*models.SkipScanInfo
+	dao.GetDb().Find(&skipInfos)
+	for _, skipInfo := range skipInfos {
+		s.scanLogicMap.Store(skipInfo.UID, skipInfo.Skip)
+	}
+
+	return s
+}
+
+// Set 设置跳过扫描的信息
+func (s *ScanLogic) Set(skipInfo *models.SkipScanInfo) {
+
+	s.scanLogicMap.Store(skipInfo.UID, skipInfo.Skip)
+	dao.GetDb().Save(skipInfo)
+}
+
+// Get 获取跳过扫描的信息设置,带有缓存
+func (s *ScanLogic) Get(videoType int, videoPath string) bool {
+
+	var uid string
+	if videoType == 0 {
+		// 电影
+		uid = models.GenerateUID4Movie(videoPath)
+	} else {
+		// 电视剧
+		var parse *PTN.TorrentInfo
+		parse, err := PTN.Parse(videoPath)
+		if err != nil {
+			s.l.Errorln("scan_logic.Get.PTN.Parse", err)
+			return true
+		}
+		dirFPath := filepath.Dir(filepath.Dir(videoPath))
+		uid = models.GenerateUID4Series(dirFPath, parse.Season, parse.Episode)
+	}
+
+	value, found := s.scanLogicMap.Load(uid)
+	if found == false {
+		// 缓存没有找到那么就从数据库查询
+		var skipInfos []models.SkipScanInfo
+		dao.GetDb().Where("uid = ?", uid).Find(&skipInfos)
+		if len(skipInfos) < 1 {
+			// 数据库中没有找到,但是也需要写入一份到数据库中,默认是扫描
+			skipInfo := models.NewSkipScanInfoByUID(uid, false)
+			dao.GetDb().Save(skipInfo)
+			// 缓存下来
+			s.scanLogicMap.Store(uid, false)
+			return false
+		} else {
+			// 数据库中找到了,缓存下来
+			s.scanLogicMap.Store(uid, skipInfos[0].Skip)
+			return skipInfos[0].Skip
+		}
+	} else {
+		return value.(bool)
+	}
+}

+ 11 - 0
pkg/types/backend/req_video_list_add.go

@@ -5,5 +5,16 @@ type ReqVideoListAdd struct {
 	PhysicalVideoFileFullPath string `json:"physical_video_file_full_path"` // 视频的物理路径
 	TaskPriorityLevel         int    `json:"task_priority_level"`           // 任务优先级
 	MediaServerInsideVideoID  string `json:"media_server_inside_video_id"`  // 媒体服务器内部视频ID
+	IsBluray                  bool   `json:"is_bluray"`                     // 这个偏向于给外部 API 调用的时候传递使用。是否是蓝光,目前只支持电影的蓝光,连续剧没有调试过
+}
+
+type ReqVideoSkipInfo struct {
+	VideoType                 int    `json:"video_type"`                    // 0 是 movie or 1 是 series
+	PhysicalVideoFileFullPath string `json:"physical_video_file_full_path"` // 视频的物理路径
 	IsBluray                  bool   `json:"is_bluray"`                     // 是否是蓝光,目前只支持电影的蓝光,连续剧没有调试过
+	IsSkip                    bool   `json:"is_skip"`                       // 是否跳过
+}
+
+type ReplyVideoSkipInfo struct {
+	IsSkip bool `json:"is_skip"` // 是否跳过
 }