Jelajahi Sumber

完成 scan_played_video_subinfo.go 基础逻辑测试

Signed-off-by: 716 <[email protected]>
716 3 tahun lalu
induk
melakukan
adedc17ceb

+ 15 - 0
cmd/chinesesubfinder/main.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"github.com/allanpk716/ChineseSubFinder/internal/backend"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/cron_helper"
+	"github.com/allanpk716/ChineseSubFinder/internal/logic/scan_played_video_subinfo"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/global_value"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
@@ -40,6 +41,20 @@ func main() {
 	nowPort := readCustomPortFile()
 	log_helper.GetLogger().Infoln(fmt.Sprintf("WebUI will listen at 0.0.0.0:%d", nowPort))
 
+	scan, err := scan_played_video_subinfo.NewScanPlayedVideoSubInfo(*settings.GetSettings())
+	if err != nil {
+		log_helper.GetLogger().Panicln(err)
+	}
+	_, err = scan.GetPlayedItemsSubtitle()
+	if err != nil {
+		log_helper.GetLogger().Panicln(err)
+	}
+
+	err = scan.Scan()
+	if err != nil {
+		log_helper.GetLogger().Panicln(err)
+	}
+
 	// 支持在外部配置特殊的端口号,以防止本地本占用了无法使用
 	backend.StartBackEnd(nowPort, cronHelper)
 }

+ 57 - 54
internal/logic/scan_played_video_subinfo/scan_played_video_subinfo.go

@@ -15,6 +15,7 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/task_control"
+	"github.com/allanpk716/ChineseSubFinder/internal/types"
 	"github.com/sirupsen/logrus"
 	"path/filepath"
 	"sync"
@@ -86,59 +87,82 @@ func (s *ScanPlayedVideoSubInfo) GetPlayedItemsSubtitle() (bool, error) {
 	return true, nil
 }
 
-func (s *ScanPlayedVideoSubInfo) ScanMovie() error {
+func (s *ScanPlayedVideoSubInfo) Scan() error {
+
+	err := s.scan(s.movieSubMap, true)
+	if err != nil {
+		return err
+	}
+
+	err = s.scan(s.seriesSubMap, false)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (s *ScanPlayedVideoSubInfo) scan(videos map[string]string, isMovie bool) error {
+
+	videoTypes := ""
+	if isMovie == true {
+		videoTypes = "Movie"
+	} else {
+		videoTypes = "Series"
+	}
 
 	defer func() {
-		s.log.Infoln("ScanPlayedVideoSubInfo Movie Sub End")
+		s.log.Infoln("ScanPlayedVideoSubInfo", videoTypes, "Sub End")
+		s.log.Infoln("-----------------------------------------------")
 	}()
 
 	s.log.Infoln("-----------------------------------------------")
-	s.log.Infoln("ScanPlayedVideoSubInfo Movie Sub Start...")
+	s.log.Infoln("ScanPlayedVideoSubInfo", videoTypes, "Sub Start...")
 
 	imdbInfoCache := make(map[string]*models.IMDBInfo)
-	for movieFPath, subFPath := range s.movieSubMap {
+	for movieFPath, subFPath := range videos {
 
 		// 通过视频的绝对路径,从本地的视频文件对应的 nfo 获取到这个视频的 IMDB ID,
-		imdbInfo4Movie, err := decode.GetImdbInfo4Movie(movieFPath)
+		var err error
+		var imdbInfo4Video types.VideoIMDBInfo
+
+		if isMovie == true {
+			imdbInfo4Video, err = decode.GetImdbInfo4Movie(movieFPath)
+		} else {
+			imdbInfo4Video, err = decode.GetSeriesImdbInfoFromEpisode(movieFPath)
+		}
 		if err != nil {
 			// 如果找不到当前电影的 IMDB Info 本地文件,那么就跳过
-			s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.GetImdbInfo4Movie", movieFPath, err)
+			s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".GetImdbInfo4Movie", movieFPath, err)
 			continue
 		}
 		// 使用 shooter 的技术 hash 的算法,得到视频的唯一 ID
 		fileHash, err := shooter.ComputeFileHash(movieFPath)
 		if err != nil {
-			s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.ComputeFileHash", movieFPath, err)
+			s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".ComputeFileHash", movieFPath, err)
 			continue
 		}
 
 		var imdbInfo *models.IMDBInfo
 		var ok bool
-		if imdbInfo, ok = imdbInfoCache[imdbInfo4Movie.ImdbId]; ok == false {
+		if imdbInfo, ok = imdbInfoCache[imdbInfo4Video.ImdbId]; ok == false {
 			// 不存在,那么就去查询和新建缓存
-			imdbInfo, err = imdb_helper.GetVideoIMDBInfoFromLocal(imdbInfo4Movie.ImdbId, *s.settings.AdvancedSettings.ProxySettings)
+			imdbInfo, err = imdb_helper.GetVideoIMDBInfoFromLocal(imdbInfo4Video.ImdbId, *s.settings.AdvancedSettings.ProxySettings)
 			if err != nil {
 				return err
 			}
-			imdbInfoCache[imdbInfo4Movie.ImdbId] = imdbInfo
-		}
-
-		// 查找关联的 VideoSubInfo
-		var videoSubInfos []models.VideoSubInfo
-		err = dao.GetDb().Model(imdbInfo).Association("VideoSubInfos").Find(&videoSubInfos)
-		if err != nil {
-			return err
+			imdbInfoCache[imdbInfo4Video.ImdbId] = imdbInfo
 		}
 		// 判断找到的关联字幕信息是否已经存在了,不存在则新增关联
 		var exist bool
-		for _, info := range videoSubInfos {
+		for _, info := range imdbInfo.VideoSubInfos {
 
 			// 首先,这里会进行已有缓存字幕是否存在的判断,把不存在的字幕给删除了
 			if my_util.IsFile(info.StoreFPath) == false {
 				// 关联删除了,但是不会删除这些对象,所以后续还需要再次删除
 				err := dao.GetDb().Model(imdbInfo).Association("VideoSubInfos").Delete(&info)
 				if err != nil {
-					s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.Delete Association", info.Feature, err)
+					s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".Delete Association", info.SubName, err)
 					continue
 				}
 				// 继续删除这个对象
@@ -162,58 +186,37 @@ func (s *ScanPlayedVideoSubInfo) ScanMovie() error {
 			return err
 		}
 		if bok == false {
-			s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.DetermineFileTypeFromFile", imdbInfo4Movie.Title, err)
+			s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".DetermineFileTypeFromFile", imdbInfo4Video.ImdbId, err)
 			continue
 		}
 
 		oneVideoSubInfo := models.NewVideoSubInfo(
 			fileHash,
 			filepath.Base(subFPath),
-			"language_iso",
+			language.MyLang2ISO_639_1_String(fileInfo.Lang),
 			language.IsBilingualSubtitle(fileInfo.Lang),
-			"chinese_iso",
+			language.MyLang2ChineseISO(fileInfo.Lang),
 			fileInfo.Lang.String(),
 			subFPath,
 		)
 
-		err = dao.GetDb().Model(imdbInfo).Association("VideoSubInfos").Append(oneVideoSubInfo)
-		if err != nil {
-			s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.Append Association", oneVideoSubInfo.SubName, err)
-			continue
+		if isMovie == false {
+			// 连续剧的时候,如果可能应该获取是 第几季  第几集
+			torrentInfo, _, err := decode.GetVideoInfoFromFileFullPath(subFPath)
+			if err != nil {
+				s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".GetVideoInfoFromFileFullPath", imdbInfo4Video.Title, err)
+				continue
+			}
+			oneVideoSubInfo.Season = torrentInfo.Season
+			oneVideoSubInfo.Episode = torrentInfo.Episode
 		}
 
-	}
-
-	return nil
-}
-
-func (s *ScanPlayedVideoSubInfo) ScanSeries() error {
-
-	defer func() {
-		s.log.Infoln("ScanPlayedVideoSubInfo Series Sub End")
-	}()
-
-	s.log.Infoln("ScanPlayedVideoSubInfo Series Sub Start...")
-
-	for episodeFPath, subFPath := range s.seriesSubMap {
-
-		// 通过视频的绝对路径,,从本地的视频文件对应的 nfo 获取到这个视频的 IMDB ID
-		imdbInfo4Series, err := decode.GetSeriesImdbInfoFromEpisode(episodeFPath)
-		if err != nil {
-			// 如果找不到当前电影的 IMDB Info 本地文件,那么就跳过
-			s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.GetSeriesImdbInfoFromEpisode", episodeFPath, err)
-			continue
-		}
-		// 使用 shooter 的技术 hash 的算法,得到视频的唯一 ID
-		fileHash, err := shooter.ComputeFileHash(episodeFPath)
+		err = dao.GetDb().Model(imdbInfo).Association("VideoSubInfos").Append(oneVideoSubInfo)
 		if err != nil {
-			s.log.Warningln("ScanPlayedVideoSubInfo.ScanMovie.ComputeFileHash", episodeFPath, err)
+			s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".Append Association", oneVideoSubInfo.SubName, err)
 			continue
 		}
 
-		println(subFPath)
-		println(imdbInfo4Series)
-		println(fileHash)
 	}
 
 	return nil

+ 3 - 6
internal/models/imdb_info.go

@@ -1,16 +1,13 @@
 package models
 
-import "gorm.io/gorm"
-
 type IMDBInfo struct {
-	gorm.Model
 	IMDBID        string         `gorm:"primaryKey"` // IMDB ID
 	Name          string         // 视频名称
 	Year          int            `gorm:"default:0"` // 发布的时间
 	Description   string         // 描述
-	Languages     StringList     `gorm:"type:varchar(255);not null"`                     // 语言
-	AKA           StringList     `gorm:"type:varchar(255);not null"`                     // 又名 xx xxx
-	VideoSubInfos []VideoSubInfo `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"` // 视频对应的字幕,外键约束
+	Languages     StringList     `gorm:"type:varchar(255);not null"` // 语言
+	AKA           StringList     `gorm:"type:varchar(255);not null"` // 又名 xx xxx
+	VideoSubInfos []VideoSubInfo `gorm:"foreignKey:IMDBInfoID"`      // 视频对应的字幕,外键约束
 }
 
 func NewIMDBInfo(IMDBID string, name string, year int, description string, languages StringList, AKA StringList) *IMDBInfo {

+ 2 - 5
internal/models/video_sub_info.go

@@ -1,20 +1,17 @@
 package models
 
-import "gorm.io/gorm"
-
 // VideoSubInfo 属于 IMDBInfo,IMDBInfoID 是外键,使用了 GORM 的 HasMany 关联
 type VideoSubInfo struct {
-	gorm.Model
 	Feature     string `gorm:"primaryKey" json:"feature"` // 特征码,这个未必有,比如是蓝光格式,分散成多个视频文件的时候,暂定使用 shooter 的特征提前方式
 	SubName     string `json:"sub_name"`                  // 字幕的文件名
 	Season      int    `json:"season"`                    // 如果对应的是电影则可能是 0,没有
 	Episode     int    `json:"episode"`                   // 如果对应的是电影则可能是 0,没有
 	LanguageISO string `json:"language_iso"`              // 字幕的语言,目标语言,就算是双语,中英,也应该是中文。ISO_639-1_codes 标准,见 ISOLanguage.go 文件,这里无法区分简体繁体
 	IsDouble    bool   `json:"is_double"`                 // 是否是双语,上面是主体语言,比如是中文,
-	ChineseISO  string `json:"chinese_iso"`               // 中文语言编码变种,见 ISOLanguage.go 文件,这里区分简体繁体
+	ChineseISO  string `json:"chinese_iso"`               // 中文语言编码变种,见 ISOLanguage.go 文件,这里区分简体繁体等,如果语言是非中文则这里是空
 	MyLanguage  string `json:"my_language"`               // 这个是本程序定义的语言类型,见 my_language.go 文件
 	StoreFPath  string `json:"store_f_path"`              // 字幕存在出本地的哪里绝对路径上
-	IMDBInfoID  uint
+	IMDBInfoID  string
 }
 
 func NewVideoSubInfo(feature string, subName string, languageISO string, isDouble bool, chineseISO string, myLanguage string, storeFPath string) *VideoSubInfo {

+ 4 - 0
internal/pkg/decode/decode.go

@@ -94,6 +94,7 @@ func getImdbAndYearNfo(nfoFilePath string, rootKey string) (types.VideoIMDBInfo,
 	return imdbInfo, common.CanNotFindIMDBID
 }
 
+// GetImdbInfo4Movie 从电影视频文件获取 IMDB info
 func GetImdbInfo4Movie(movieFileFullPath string) (types.VideoIMDBInfo, error) {
 	imdbInfo := types.VideoIMDBInfo{}
 	// movie 当前的目录
@@ -165,6 +166,7 @@ func GetImdbInfo4Movie(movieFileFullPath string) (types.VideoIMDBInfo, error) {
 	return imdbInfo, common.CanNotFindIMDBID
 }
 
+// GetImdbInfo4SeriesDir 从一个连续剧的根目录获取 IMDB info
 func GetImdbInfo4SeriesDir(seriesDir string) (types.VideoIMDBInfo, error) {
 	imdbInfo := types.VideoIMDBInfo{}
 	dir, err := os.ReadDir(seriesDir)
@@ -200,6 +202,7 @@ func GetImdbInfo4SeriesDir(seriesDir string) (types.VideoIMDBInfo, error) {
 	return imdbInfo, nil
 }
 
+// GetSeriesImdbInfoFromEpisode 从一集获取这个 Series 的 IMDB info
 func GetSeriesImdbInfoFromEpisode(oneEpFPath string) (types.VideoIMDBInfo, error) {
 
 	var err error
@@ -237,6 +240,7 @@ func GetSeriesImdbInfoFromEpisode(oneEpFPath string) (types.VideoIMDBInfo, error
 	}
 }
 
+// GetImdbInfo4OneSeriesEpisode 获取这一集的 IMDB info
 func GetImdbInfo4OneSeriesEpisode(oneEpFPath string) (types.VideoIMDBInfo, error) {
 
 	// 从这一集的视频文件全路径去推算对应的 nfo 文件是否存在

+ 2 - 1
internal/pkg/imdb_helper/imdb.go

@@ -35,7 +35,8 @@ func GetVideoIMDBInfoFromLocal(imdbID string, _proxySettings ...settings.ProxySe
 
 	// 首先从数据库中查找是否存在这个 IMDB 信息,如果不存在再使用 Web 查找,且写入数据库
 	var imdbInfos []models.IMDBInfo
-	dao.GetDb().Limit(1).Where(&models.IMDBInfo{IMDBID: imdbID}).Find(&imdbInfos)
+	// 把嵌套关联的 has many 的信息都查询出来
+	dao.GetDb().Preload("VideoSubInfos").Limit(1).Where(&models.IMDBInfo{IMDBID: imdbID}).Find(&imdbInfos)
 
 	if len(imdbInfos) <= 0 {
 		// 没有找到,去网上获取

+ 46 - 0
internal/pkg/language/ISOLanguage.go

@@ -165,6 +165,52 @@ func IsSupportISOChineseString(isoString string) bool {
 	return false
 }
 
+// MyLang2ISO_639_1_String 内置的语言转换到 ISO_639-1_codes 标准
+func MyLang2ISO_639_1_String(myLanguage language.MyLanguage) string {
+
+	switch myLanguage {
+	case language.ChineseSimple,
+		language.ChineseTraditional,
+		language.ChineseSimpleEnglish,
+		language.ChineseTraditionalEnglish,
+		language.ChineseSimpleJapanese,
+		language.ChineseTraditionalJapanese,
+		language.ChineseSimpleKorean,
+		language.ChineseTraditionalKorean:
+		return language.ISO_639_1_Chinese
+	case language.English:
+		return language.ISO_639_1_English
+	case language.Japanese:
+		return language.ISO_639_1_Japanese
+	case language.Korean:
+		return language.ISO_639_1_Korean
+	default:
+		return language.MathLangChnUnknown
+	}
+}
+
+// MyLang2ChineseISO 中文语言编码变种,见 ISOLanguage.go 文件,这里区分简体、繁体等,如果语言是非中文则这里是空
+func MyLang2ChineseISO(myLanguage language.MyLanguage) string {
+	switch myLanguage {
+	case language.ChineseSimple,
+		language.ChineseSimpleEnglish,
+		language.ChineseSimpleJapanese,
+		language.ChineseSimpleKorean:
+		return language.ChineseISO_Hans
+
+	case language.ChineseTraditional,
+		language.ChineseTraditionalEnglish,
+		language.ChineseTraditionalJapanese,
+		language.ChineseTraditionalKorean:
+		return language.ChineseISO_Hant
+
+	case language.English, language.Japanese, language.Korean:
+		return ""
+	default:
+		return ""
+	}
+}
+
 // ISOSupportRegexRule 获取 ISO 匹配的 regex 表达式
 func ISOSupportRegexRule() string {