Browse Source

正在实现本地视频信息汇总到数据库中,与 IMDB INFO 挂钩

Signed-off-by: 716 <[email protected]>
716 3 years ago
parent
commit
8d378f13b1

+ 1 - 1
cmd/chinesesubfinder/main.go

@@ -36,7 +36,7 @@ func main() {
 	//	log_helper.GetLogger().Panicln("pre_job", err)
 	//}
 	//// ----------------------------------------------
-	//scan, err := scan_played_video_subinfo.NewScanPlayedVideoSubInfo(*settings.GetSettings())
+	//scan, err := scan_played_video_subinfo.NewScanPlayedVideoSubInfo(log_helper.GetLogger(), settings.GetSettings())
 	//if err != nil {
 	//	log_helper.GetLogger().Panicln(err)
 	//}

+ 1 - 1
internal/dao/init.go

@@ -68,7 +68,7 @@ func InitDb() error {
 	}
 	// 迁移 schema
 	err = db.AutoMigrate(&models.HotFix{}, &models.SubFormatRec{},
-		&models.IMDBInfo{}, &models.VideoSubInfo{})
+		&models.IMDBInfo{}, &models.VideoSubInfo{}, &models.MovieOrSeriesLocalInfo{})
 	if err != nil {
 		return errors.New(fmt.Sprintf("db AutoMigrate error, %s", err.Error()))
 	}

+ 1 - 1
internal/logic/movie_helper/moviehelper.go

@@ -110,7 +110,7 @@ func SkipChineseMovie(videoFullPath string, _proxySettings ...*settings.ProxySet
 	if err != nil {
 		return false, err
 	}
-	isChineseVideo, _, err := imdb_helper.IsChineseVideo(imdbInfo.ImdbId, _proxySettings...)
+	isChineseVideo, _, err := imdb_helper.IsChineseVideo(imdbInfo, _proxySettings...)
 	if err != nil {
 		return false, err
 	}

+ 5 - 6
internal/logic/scan_played_video_subinfo/scan_played_video_subinfo.go

@@ -12,7 +12,6 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/imdb_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/language"
-	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_folder"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
@@ -50,10 +49,10 @@ type ScanPlayedVideoSubInfo struct {
 	shareRootDir string
 }
 
-func NewScanPlayedVideoSubInfo(_settings *settings.Settings) (*ScanPlayedVideoSubInfo, error) {
+func NewScanPlayedVideoSubInfo(log *logrus.Logger, _settings *settings.Settings) (*ScanPlayedVideoSubInfo, error) {
 	var err error
 	var scanPlayedVideoSubInfo ScanPlayedVideoSubInfo
-	scanPlayedVideoSubInfo.log = log_helper.GetLogger()
+	scanPlayedVideoSubInfo.log = log
 	// 参入设置信息
 	// 最大获取的视频数目设置到 100W
 	_settings.EmbySettings.MaxRequestVideoNumber = 1000000
@@ -66,7 +65,7 @@ func NewScanPlayedVideoSubInfo(_settings *settings.Settings) (*ScanPlayedVideoSu
 	}
 
 	// 初始化任务控制
-	scanPlayedVideoSubInfo.taskControl, err = task_control.NewTaskControl(scanPlayedVideoSubInfo.settings.CommonSettings.Threads, log_helper.GetLogger())
+	scanPlayedVideoSubInfo.taskControl, err = task_control.NewTaskControl(scanPlayedVideoSubInfo.settings.CommonSettings.Threads, log)
 	if err != nil {
 		return nil, err
 	}
@@ -268,7 +267,7 @@ func (s *ScanPlayedVideoSubInfo) dealOneVideo(index int, videoFPath, orgSubFPath
 
 	if my_util.IsFile(orgSubFPath) == false {
 
-		log_helper.GetLogger().Errorln("Skip", orgSubFPath, "not exist")
+		s.log.Errorln("Skip", orgSubFPath, "not exist")
 		return
 	}
 
@@ -305,7 +304,7 @@ func (s *ScanPlayedVideoSubInfo) dealOneVideo(index int, videoFPath, orgSubFPath
 	// 先把 IMDB 信息查询查来,不管是从数据库还是网络(查询出来也得写入到数据库)
 	if imdbInfo, ok = imdbInfoCache[imdbInfo4Video.ImdbId]; ok == false {
 		// 不存在,那么就去查询和新建缓存
-		imdbInfo, err = imdb_helper.GetVideoIMDBInfoFromLocal(imdbInfo4Video.ImdbId, s.settings.AdvancedSettings.ProxySettings)
+		imdbInfo, err = imdb_helper.GetVideoIMDBInfoFromLocal(imdbInfo4Video, s.settings.AdvancedSettings.ProxySettings)
 		if err != nil {
 			s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".GetVideoIMDBInfoFromLocal", videoFPath, err)
 			return

+ 2 - 2
internal/logic/series_helper/seriesHelper.go

@@ -140,7 +140,7 @@ func SkipChineseSeries(seriesRootPath string, _proxySettings ...*settings.ProxyS
 		return false, nil, err
 	}
 
-	isChineseVideo, t, err := imdb_helper.IsChineseVideo(imdbInfo.ImdbId, _proxySettings...)
+	isChineseVideo, t, err := imdb_helper.IsChineseVideo(imdbInfo, _proxySettings...)
 	if err != nil {
 		return false, nil, err
 	}
@@ -323,7 +323,7 @@ func getSeriesInfoFromDir(seriesDir string, _proxySettings ...*settings.ProxySet
 		return nil, err
 	}
 
-	imdbInfoFromLocal, err := imdb_helper.GetVideoIMDBInfoFromLocal(videoInfo.ImdbId, _proxySettings...)
+	imdbInfoFromLocal, err := imdb_helper.GetVideoIMDBInfoFromLocal(videoInfo, _proxySettings...)
 	if err != nil {
 		return nil, err
 	}

+ 8 - 7
internal/models/imdb_info.go

@@ -1,13 +1,14 @@
 package models
 
 type IMDBInfo struct {
-	IMDBID        string         `gorm:"primaryKey" json:"imdb_id"  binding:"required"`                   // IMDB ID
-	Name          string         `json:"name" binding:"required"`                                         // 视频名称
-	Year          int            `gorm:"default:0" json:"year"  binding:"required"`                       // 发布的时间
-	Description   string         `json:"description"  binding:"required"`                                 // 描述
-	Languages     StringList     `gorm:"type:varchar(255);not null" json:"languages"  binding:"required"` // 语言
-	AKA           StringList     `gorm:"type:varchar(255);not null" json:"AKA"  binding:"required"`       // 又名 xx xxx
-	VideoSubInfos []VideoSubInfo `gorm:"foreignKey:IMDBInfoID"`                                           // 视频对应的字幕,外键约束
+	IMDBID                  string                   `gorm:"primaryKey" json:"imdb_id"  binding:"required"`                   // IMDB ID
+	Name                    string                   `json:"name" binding:"required"`                                         // 视频名称
+	Year                    int                      `gorm:"default:0" json:"year"  binding:"required"`                       // 发布的时间
+	Description             string                   `json:"description"  binding:"required"`                                 // 描述
+	Languages               StringList               `gorm:"type:varchar(255);not null" json:"languages"  binding:"required"` // 语言
+	AKA                     StringList               `gorm:"type:varchar(255);not null" json:"AKA"  binding:"required"`       // 又名 xx xxx
+	VideoSubInfos           []VideoSubInfo           `gorm:"foreignKey:IMDBInfoID"`                                           // 视频对应的字幕,外键约束
+	MovieOrSeriesLocalInfos []MovieOrSeriesLocalInfo `gorm:"foreignKey:IMDBInfoID"`                                           // 视频对应的本地信息,外键约束
 }
 
 func NewIMDBInfo(IMDBID string, name string, year int, description string, languages StringList, AKA StringList) *IMDBInfo {

+ 12 - 0
internal/models/movie_or_series_local_info.go

@@ -0,0 +1,12 @@
+package models
+
+type MovieOrSeriesLocalInfo struct {
+	IsMovie      bool   `json:"is_movie"`                         // 不是电影就是连续剧
+	Season       int    `json:"season"`                           // 季度
+	RootDirRPath string `json:"root_dir_r_path"`                  // 这个电影或者连续剧(不是季的文件夹,而是这个连续剧的目录)的相对路径
+	IMDBInfoID   string `json:"imdb_info_id"  binding:"required"` // IMDB ID
+}
+
+func NewMovieOrSeriesLocalInfo(isMovie bool, season int, rootDirRPath string) *MovieOrSeriesLocalInfo {
+	return &MovieOrSeriesLocalInfo{IsMovie: isMovie, Season: season, RootDirRPath: rootDirRPath}
+}

+ 20 - 8
internal/pkg/imdb_helper/imdb.go

@@ -8,14 +8,16 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/notify_center"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
+	"github.com/allanpk716/ChineseSubFinder/internal/types"
 	"net/http"
 	"net/url"
+	"strconv"
 	"strings"
 	"time"
 )
 
 // GetVideoInfoFromIMDBWeb 从 IMDB 网站 ID 查询影片的信息
-func GetVideoInfoFromIMDBWeb(imdbID string, _proxySettings ...*settings.ProxySettings) (*imdb.Title, error) {
+func GetVideoInfoFromIMDBWeb(imdbInfo types.VideoIMDBInfo, _proxySettings ...*settings.ProxySettings) (*imdb.Title, error) {
 
 	var cli *http.Client
 	var proxySettings *settings.ProxySettings
@@ -41,37 +43,47 @@ func GetVideoInfoFromIMDBWeb(imdbID string, _proxySettings ...*settings.ProxySet
 		}
 	}
 
-	t, err := imdb.NewTitle(cli, imdbID)
+	t, err := imdb.NewTitle(cli, imdbInfo.ImdbId)
 	if err != nil {
 		notify_center.Notify.Add("imdb model - imdb.NewTitle :", err.Error())
 		return nil, err
 	}
+	if t.Year == 0 {
+		// IMDB 信息获取的库(1.0.7),目前有bug,比如,tt6856242 年份为 0
+		if imdbInfo.Year != "" {
+			year, err := strconv.Atoi(imdbInfo.Year)
+			if err != nil {
+				return nil, err
+			}
+			t.Year = year
+		}
+	}
 
 	return t, nil
 }
 
 // GetVideoIMDBInfoFromLocal 从本地获取 IMDB 信息,如果找不到则去网络获取并写入本地缓存
-func GetVideoIMDBInfoFromLocal(imdbID string, _proxySettings ...*settings.ProxySettings) (*models.IMDBInfo, error) {
+func GetVideoIMDBInfoFromLocal(imdbInfo types.VideoIMDBInfo, _proxySettings ...*settings.ProxySettings) (*models.IMDBInfo, error) {
 
 	log_helper.GetLogger().Debugln("GetVideoIMDBInfoFromLocal", 0)
 
 	// 首先从数据库中查找是否存在这个 IMDB 信息,如果不存在再使用 Web 查找,且写入数据库
 	var imdbInfos []models.IMDBInfo
 	// 把嵌套关联的 has many 的信息都查询出来
-	dao.GetDb().Preload("VideoSubInfos").Limit(1).Where(&models.IMDBInfo{IMDBID: imdbID}).Find(&imdbInfos)
+	dao.GetDb().Preload("VideoSubInfos").Limit(1).Where(&models.IMDBInfo{IMDBID: imdbInfo.ImdbId}).Find(&imdbInfos)
 
 	log_helper.GetLogger().Debugln("GetVideoIMDBInfoFromLocal", 1)
 
 	if len(imdbInfos) <= 0 {
 		// 没有找到,去网上获取
-		t, err := GetVideoInfoFromIMDBWeb(imdbID, _proxySettings...)
+		t, err := GetVideoInfoFromIMDBWeb(imdbInfo, _proxySettings...)
 		if err != nil {
 			return nil, err
 		}
 		log_helper.GetLogger().Debugln("GetVideoIMDBInfoFromLocal", 2)
 
 		// 存入数据库
-		nowIMDBInfo := models.NewIMDBInfo(imdbID, t.Name, t.Year, t.Description, t.Languages, t.AKA)
+		nowIMDBInfo := models.NewIMDBInfo(imdbInfo.ImdbId, t.Name, t.Year, t.Description, t.Languages, t.AKA)
 		imdbInfos = make([]models.IMDBInfo, 0)
 		imdbInfos = append(imdbInfos, *nowIMDBInfo)
 		dao.GetDb().Create(nowIMDBInfo)
@@ -88,7 +100,7 @@ func GetVideoIMDBInfoFromLocal(imdbID string, _proxySettings ...*settings.ProxyS
 }
 
 // IsChineseVideo 从 imdbID 去查询判断是否是中文视频
-func IsChineseVideo(imdbID string, _proxySettings ...*settings.ProxySettings) (bool, *models.IMDBInfo, error) {
+func IsChineseVideo(imdbInfo types.VideoIMDBInfo, _proxySettings ...*settings.ProxySettings) (bool, *models.IMDBInfo, error) {
 
 	const chName0 = "chinese"
 	const chName1 = "mandarin"
@@ -98,7 +110,7 @@ func IsChineseVideo(imdbID string, _proxySettings ...*settings.ProxySettings) (b
 		proxySettings = _proxySettings[0]
 	}
 
-	localIMDBInfo, err := GetVideoIMDBInfoFromLocal(imdbID, proxySettings)
+	localIMDBInfo, err := GetVideoIMDBInfoFromLocal(imdbInfo, proxySettings)
 	if err != nil {
 		return false, nil, err
 	}

+ 1 - 1
internal/pkg/imdb_helper/imdb_test.go

@@ -45,7 +45,7 @@ func TestIsChineseVideo(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			got, _, err := IsChineseVideo(tt.args.imdbID, tt.args._reqParam...)
+			got, _, err := IsChineseVideo(tt.args.imdbID)
 			if (err != nil) != tt.wantErr {
 				t.Errorf("IsChineseVideo() error = %v, wantErr %v", err, tt.wantErr)
 				return

+ 86 - 42
internal/pkg/video_scan_and_refresh_helper/video_scan_and_refresh_helper.go

@@ -1,6 +1,7 @@
 package video_scan_and_refresh_helper
 
 import (
+	"github.com/allanpk716/ChineseSubFinder/internal/dao"
 	embyHelper "github.com/allanpk716/ChineseSubFinder/internal/logic/emby_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/file_downloader"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/forced_scan_and_down_sub"
@@ -9,7 +10,9 @@ import (
 	subSupplier "github.com/allanpk716/ChineseSubFinder/internal/logic/sub_supplier"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_supplier/xunlei"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/task_queue"
+	"github.com/allanpk716/ChineseSubFinder/internal/models"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/imdb_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
 	subTimelineFixerPKG "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_timeline_fixer"
@@ -18,17 +21,18 @@ import (
 	TTaskqueue "github.com/allanpk716/ChineseSubFinder/internal/types/task_queue"
 	"github.com/emirpasic/gods/maps/treemap"
 	"github.com/sirupsen/logrus"
+	"path/filepath"
 )
 
 type VideoScanAndRefreshHelper struct {
-	settings                 *settings.Settings // 设置的实例
-	log                      *logrus.Logger     // 日志实例
-	fileDownloader           *file_downloader.FileDownloader
-	needForcedScanAndDownSub bool                        // 将会强制扫描所有的视频,下载字幕,替换已经存在的字幕,不进行时间段和已存在则跳过的判断。且不会进过 Emby API 的逻辑,智能进行强制去以本程序的方式去扫描。
-	NeedRestoreFixTimeLineBK bool                        // 从 csf-bk 文件还原时间轴修复前的字幕文件
-	embyHelper               *embyHelper.EmbyHelper      // Emby 的实例
-	downloadQueue            *task_queue.TaskQueue       // 需要下载的视频的队列
-	subSupplierHub           *subSupplier.SubSupplierHub // 字幕提供源的集合,仅仅是 check 是否需要下载字幕是足够的,如果要下载则需要额外的初始化和检查
+	settings                 *settings.Settings              // 设置的实例
+	log                      *logrus.Logger                  // 日志实例
+	fileDownloader           *file_downloader.FileDownloader // 文件下载器
+	needForcedScanAndDownSub bool                            // 将会强制扫描所有的视频,下载字幕,替换已经存在的字幕,不进行时间段和已存在则跳过的判断。且不会进过 Emby API 的逻辑,智能进行强制去以本程序的方式去扫描。
+	NeedRestoreFixTimeLineBK bool                            // 从 csf-bk 文件还原时间轴修复前的字幕文件
+	embyHelper               *embyHelper.EmbyHelper          // Emby 的实例
+	downloadQueue            *task_queue.TaskQueue           // 需要下载的视频的队列
+	subSupplierHub           *subSupplier.SubSupplierHub     // 字幕提供源的集合,仅仅是 check 是否需要下载字幕是足够的,如果要下载则需要额外的初始化和检查
 }
 
 func NewVideoScanAndRefreshHelper(fileDownloader *file_downloader.FileDownloader, downloadQueue *task_queue.TaskQueue) *VideoScanAndRefreshHelper {
@@ -69,41 +73,44 @@ func (v *VideoScanAndRefreshHelper) ScanMovieAndSeriesWait2DownloadSub() (*ScanV
 		v.embyHelper = embyHelper.NewEmbyHelper(v.settings)
 	}
 
+	outScanVideoResult := ScanVideoResult{}
 	var err error
-	// -----------------------------------------------------
-	// 强制下载和常规模式(没有媒体服务器)
-	if v.needForcedScanAndDownSub == true || v.embyHelper == nil {
-
-		normalScanResult := NormalScanVideoResult{}
-		// 直接由本程序自己去扫描视频视频有哪些
-		// 全扫描
-		if v.needForcedScanAndDownSub == true {
-			v.log.Infoln("Forced Scan And DownSub")
-		}
-		// --------------------------------------------------
-		// 电影
-		// 没有填写 emby_helper api 的信息,那么就走常规的全文件扫描流程
-		normalScanResult.MovieFileFullPathList, err = my_util.SearchMatchedVideoFileFromDirs(v.log, v.settings.CommonSettings.MoviePaths)
-		if err != nil {
-			return nil, err
-		}
-		// --------------------------------------------------
-		// 连续剧
-		// 遍历连续剧总目录下的第一层目录
-		normalScanResult.SeriesDirMap, err = seriesHelper.GetSeriesListFromDirs(v.settings.CommonSettings.SeriesPaths)
-		if err != nil {
-			return nil, err
+	// ------------------------------------------------------------------------------
+	// ------------------------------------------------------------------------------
+	// 由于需要进行视频信息的缓存,用于后续的逻辑,那么本地视频的扫描默认都会进行
+	normalScanResult := NormalScanVideoResult{}
+	// 直接由本程序自己去扫描视频视频有哪些
+	// 全扫描
+	if v.needForcedScanAndDownSub == true {
+		v.log.Infoln("Forced Scan And DownSub")
+	}
+	// --------------------------------------------------
+	// 电影
+	// 没有填写 emby_helper api 的信息,那么就走常规的全文件扫描流程
+	normalScanResult.MovieFileFullPathList, err = my_util.SearchMatchedVideoFileFromDirs(v.log, v.settings.CommonSettings.MoviePaths)
+	if err != nil {
+		return nil, err
+	}
+	// --------------------------------------------------
+	// 连续剧
+	// 遍历连续剧总目录下的第一层目录
+	normalScanResult.SeriesDirMap, err = seriesHelper.GetSeriesListFromDirs(v.settings.CommonSettings.SeriesPaths)
+	if err != nil {
+		return nil, err
+	}
+	// ------------------------------------------------------------------------------
+	// 输出调试信息,有那些连续剧文件夹名称
+	normalScanResult.SeriesDirMap.Each(func(key interface{}, value interface{}) {
+		for i, s := range value.([]string) {
+			v.log.Debugln("embyHelper == nil GetSeriesList", i, s)
 		}
-		// ------------------------------------------------------------------------------
-		// 输出调试信息,有那些连续剧文件夹名称
-		normalScanResult.SeriesDirMap.Each(func(key interface{}, value interface{}) {
-			for i, s := range value.([]string) {
-				v.log.Debugln("embyHelper == nil GetSeriesList", i, s)
-			}
-		})
-		// ------------------------------------------------------------------------------
-		return &ScanVideoResult{Normal: &normalScanResult}, nil
-	} else {
+	})
+	// ------------------------------------------------------------------------------
+	outScanVideoResult.Normal = &normalScanResult
+	// ------------------------------------------------------------------------------
+	// ------------------------------------------------------------------------------
+	// 从 Emby 获取视频
+	if v.embyHelper != nil {
 		// TODO 如果后续支持了 Jellyfin、Plex 那么这里需要额外正在对应的扫描逻辑
 		// 进过 emby_helper api 的信息读取
 		embyScanResult := EmbyScanVideoResult{}
@@ -122,8 +129,45 @@ func (v *VideoScanAndRefreshHelper) ScanMovieAndSeriesWait2DownloadSub() (*ScanV
 			return nil, err
 		}
 		// ------------------------------------------------------------------------------
-		return &ScanVideoResult{Emby: &embyScanResult}, nil
+		outScanVideoResult.Emby = &embyScanResult
 	}
+
+	return &outScanVideoResult, nil
+}
+
+// UpdateLocalVideoCacheInfo 将扫描到的信息缓存到本地中,用于后续的 Video 展示界面 和 Emby IMDB ID 匹配进行路径的转换
+func (v *VideoScanAndRefreshHelper) UpdateLocalVideoCacheInfo(scanVideoResult *ScanVideoResult) error {
+	// 这里只使用 Normal 情况下获取到的信息
+	if scanVideoResult.Normal == nil {
+		return nil
+	}
+
+	// 电影
+	for i, oneMovieFPath := range scanVideoResult.Normal.MovieFileFullPathList {
+
+		v.log.Debugln("UpdateLocalVideoCacheInfo", i, oneMovieFPath)
+		videoImdbInfo, err := decode.GetImdbInfo4Movie(oneMovieFPath)
+		if err != nil {
+			// 允许的错误,跳过,继续进行文件名的搜索
+			v.log.Warningln("GetImdbInfo4Movie", oneMovieFPath, err)
+			continue
+		}
+		// 获取 IMDB 信息
+		localIMDBInfo, err := imdb_helper.GetVideoIMDBInfoFromLocal(videoImdbInfo, v.settings.AdvancedSettings.ProxySettings)
+		if err != nil {
+			v.log.Warningln("GetVideoIMDBInfoFromLocal,IMDB:", videoImdbInfo.ImdbId, oneMovieFPath, err)
+			continue
+		}
+		// 插入数据
+		localInfo := models.NewMovieOrSeriesLocalInfo(true, 0, filepath.Dir(oneMovieFPath))
+		err = dao.GetDb().Model(localIMDBInfo).Association("MovieOrSeriesLocalInfos").Append(localInfo)
+		if err != nil {
+			v.log.Errorln("UpdateLocalVideoCacheInfo", oneMovieFPath, err)
+			continue
+		}
+	}
+
+	return nil
 }
 
 // FilterMovieAndSeriesNeedDownload 过滤出需要下载字幕的视频,比如是否跳过中文的剧集,是否超过3个月的下载时间,丢入队列中