Browse Source

完成共享字幕缓存文件功能

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

+ 1 - 2
go.mod

@@ -61,6 +61,7 @@ require (
 	gonum.org/v1/gonum v0.9.3
 	gopkg.in/errgo.v2 v2.1.0
 	gopkg.in/ini.v1 v1.62.0 // indirect
+	gopkg.in/mail.v2 v2.3.1
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gorm.io/driver/sqlite v1.2.6
 	gorm.io/gorm v1.22.5
@@ -78,7 +79,6 @@ require (
 	github.com/bodgit/windows v1.0.0 // indirect
 	github.com/connesc/cipherio v0.2.1 // indirect
 	github.com/dsnet/compress v0.0.1 // indirect
-	github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect
 	github.com/gin-contrib/sse v0.1.0 // indirect
 	github.com/go-git/gcfg v1.5.0 // indirect
 	github.com/go-git/go-billy/v5 v5.3.1 // indirect
@@ -121,7 +121,6 @@ require (
 	golang.org/x/exp v0.0.0-20211123021643-48cbe7f80d7c // indirect
 	google.golang.org/protobuf v1.27.1 // indirect
 	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
-	gopkg.in/mail.v2 v2.3.1 // indirect
 	gopkg.in/warnings.v0 v0.1.2 // indirect
 )
 

+ 0 - 8
go.sum

@@ -130,14 +130,6 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
 github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
 github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
-github.com/emersion/go-imap v1.2.0 h1:lyUQ3+EVM21/qbWE/4Ya5UG9r5+usDxlg4yfp3TgHFA=
-github.com/emersion/go-imap v1.2.0/go.mod h1:Qlx1FSx2FTxjnjWpIlVNEuX+ylerZQNFE5NsmKFSejY=
-github.com/emersion/go-imap-id v0.0.0-20190926060100-f94a56b9ecde h1:43mBoVwooyLm1+1YVf5nvn1pSFWhw7rOpcrp1Jg/qk0=
-github.com/emersion/go-imap-id v0.0.0-20190926060100-f94a56b9ecde/go.mod h1:sPwp0FFboaK/bxsrUz1lNrDMUCsZUsKC5YuM4uRVRVs=
-github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
-github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
-github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
-github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
 github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
 github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
 github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=

+ 49 - 9
internal/logic/scan_played_video_subinfo/scan_played_video_subinfo.go

@@ -2,6 +2,7 @@ package scan_played_video_subinfo
 
 import (
 	"github.com/allanpk716/ChineseSubFinder/internal/dao"
+	"github.com/allanpk716/ChineseSubFinder/internal/ifaces"
 	embyHelper "github.com/allanpk716/ChineseSubFinder/internal/logic/emby_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/ass"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/srt"
@@ -13,7 +14,9 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_formatter/emby"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_share_center"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/task_control"
 	"github.com/allanpk716/ChineseSubFinder/internal/types"
 	"github.com/sirupsen/logrus"
@@ -35,6 +38,8 @@ type ScanPlayedVideoSubInfo struct {
 
 	movieSubMap  map[string]string
 	seriesSubMap map[string]string
+
+	subFormatter ifaces.ISubFormatter
 }
 
 func NewScanPlayedVideoSubInfo(_settings settings.Settings) (*ScanPlayedVideoSubInfo, error) {
@@ -57,6 +62,8 @@ func NewScanPlayedVideoSubInfo(_settings settings.Settings) (*ScanPlayedVideoSub
 	}
 	// 字幕解析器
 	scanPlayedVideoSubInfo.subParserHub = sub_parser_hub.NewSubParserHub(ass.NewParser(), srt.NewParser())
+	// 字幕命名格式解析器
+	scanPlayedVideoSubInfo.subFormatter = emby.NewFormatter()
 
 	return &scanPlayedVideoSubInfo, nil
 }
@@ -104,6 +111,11 @@ func (s *ScanPlayedVideoSubInfo) Scan() error {
 
 func (s *ScanPlayedVideoSubInfo) scan(videos map[string]string, isMovie bool) error {
 
+	shareRootDir, err := my_util.GetShareSubRootFolder()
+	if err != nil {
+		return err
+	}
+
 	videoTypes := ""
 	if isMovie == true {
 		videoTypes = "Movie"
@@ -120,7 +132,13 @@ func (s *ScanPlayedVideoSubInfo) scan(videos map[string]string, isMovie bool) er
 	s.log.Infoln("ScanPlayedVideoSubInfo", videoTypes, "Sub Start...")
 
 	imdbInfoCache := make(map[string]*models.IMDBInfo)
-	for movieFPath, subFPath := range videos {
+	for movieFPath, orgSubFPath := range videos {
+
+		if my_util.IsFile(orgSubFPath) == false {
+
+			log_helper.GetLogger().Errorln("Skip", orgSubFPath, "not exist")
+			continue
+		}
 
 		// 通过视频的绝对路径,从本地的视频文件对应的 nfo 获取到这个视频的 IMDB ID,
 		var err error
@@ -157,8 +175,9 @@ func (s *ScanPlayedVideoSubInfo) scan(videos map[string]string, isMovie bool) er
 		var exist bool
 		for _, info := range imdbInfo.VideoSubInfos {
 
+			// 转绝对路径存储
 			// 首先,这里会进行已有缓存字幕是否存在的判断,把不存在的字幕给删除了
-			if my_util.IsFile(info.StoreFPath) == false {
+			if my_util.IsFile(filepath.Join(shareRootDir, info.StoreRPath)) == false {
 				// 关联删除了,但是不会删除这些对象,所以后续还需要再次删除
 				err := dao.GetDb().Model(imdbInfo).Association("VideoSubInfos").Delete(&info)
 				if err != nil {
@@ -170,7 +189,7 @@ func (s *ScanPlayedVideoSubInfo) scan(videos map[string]string, isMovie bool) er
 				s.log.Infoln("Delete Not Exist Sub Association", info.SubName, err)
 				continue
 			}
-
+			// 文件对应的视频唯一 ID 一致
 			if info.Feature == fileHash {
 				exist = true
 				break
@@ -180,29 +199,50 @@ func (s *ScanPlayedVideoSubInfo) scan(videos map[string]string, isMovie bool) er
 			// 存在
 			continue
 		}
+
+		// 把现有的字幕 copy 到缓存目录中
+		bok, subCacheFPath := sub_share_center.CopySub2Cache(orgSubFPath, imdbInfo.Year)
+		if bok == false {
+			continue
+		}
+
 		// 不存在,插入,建立关系
-		bok, fileInfo, err := s.subParserHub.DetermineFileTypeFromFile(subFPath)
+		bok, fileInfo, err := s.subParserHub.DetermineFileTypeFromFile(subCacheFPath)
 		if err != nil {
-			return err
+			s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".DetermineFileTypeFromFile", imdbInfo4Video.ImdbId, err)
+			continue
 		}
 		if bok == false {
-			s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".DetermineFileTypeFromFile", imdbInfo4Video.ImdbId, err)
+			s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".DetermineFileTypeFromFile == false", imdbInfo4Video.ImdbId)
 			continue
 		}
 
+		// 特指 emby 字幕的情况
+		bok, _, _, _, extraSubPreName := s.subFormatter.IsMatchThisFormat(filepath.Base(subCacheFPath))
+		if bok == false {
+			s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".IsMatchThisFormat == false", imdbInfo4Video.ImdbId)
+			continue
+		}
+		// 转相对路径存储
+		subRelPath, err := filepath.Rel(shareRootDir, subCacheFPath)
+		if err != nil {
+			return err
+		}
+
 		oneVideoSubInfo := models.NewVideoSubInfo(
 			fileHash,
-			filepath.Base(subFPath),
+			filepath.Base(subCacheFPath),
 			language.MyLang2ISO_639_1_String(fileInfo.Lang),
 			language.IsBilingualSubtitle(fileInfo.Lang),
 			language.MyLang2ChineseISO(fileInfo.Lang),
 			fileInfo.Lang.String(),
-			subFPath,
+			subRelPath,
+			extraSubPreName,
 		)
 
 		if isMovie == false {
 			// 连续剧的时候,如果可能应该获取是 第几季  第几集
-			torrentInfo, _, err := decode.GetVideoInfoFromFileFullPath(subFPath)
+			torrentInfo, _, err := decode.GetVideoInfoFromFileFullPath(subCacheFPath)
 			if err != nil {
 				s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".GetVideoInfoFromFileFullPath", imdbInfo4Video.Title, err)
 				continue

+ 13 - 12
internal/models/video_sub_info.go

@@ -2,18 +2,19 @@ package models
 
 // VideoSubInfo 属于 IMDBInfo,IMDBInfoID 是外键,使用了 GORM 的 HasMany 关联
 type VideoSubInfo struct {
-	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 文件,这里区分简体、繁体等,如果语言是非中文则这里是空
-	MyLanguage  string `json:"my_language"`               // 这个是本程序定义的语言类型,见 my_language.go 文件
-	StoreFPath  string `json:"store_f_path"`              // 字幕存在出本地的哪里绝对路径上
-	IMDBInfoID  string
+	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 文件,这里区分简体、繁体等,如果语言是非中文则这里是空
+	MyLanguage   string `json:"my_language"`               // 这个是本程序定义的语言类型,见 my_language.go 文件
+	StoreRPath   string `json:"store_r_path"`              // 字幕存在出本地的哪里相对路径上,cache/CSF-ShareSubCache
+	ExtraPreName string `json:"extra_pre_name"`            // 字幕额外的命名信息,指 Emby 字幕命名格式(简英,subhd),的 subhd
+	IMDBInfoID   string
 }
 
-func NewVideoSubInfo(feature string, subName string, languageISO string, isDouble bool, chineseISO string, myLanguage string, storeFPath string) *VideoSubInfo {
-	return &VideoSubInfo{Feature: feature, SubName: subName, LanguageISO: languageISO, IsDouble: isDouble, ChineseISO: chineseISO, MyLanguage: myLanguage, StoreFPath: storeFPath}
+func NewVideoSubInfo(feature string, subName string, languageISO string, isDouble bool, chineseISO string, myLanguage string, storeFPath string, extraPreName string) *VideoSubInfo {
+	return &VideoSubInfo{Feature: feature, SubName: subName, LanguageISO: languageISO, IsDouble: isDouble, ChineseISO: chineseISO, MyLanguage: myLanguage, StoreRPath: storeFPath, ExtraPreName: extraPreName}
 }

+ 31 - 0
internal/pkg/sub_share_center/share_sub_cache_helper.go

@@ -0,0 +1,31 @@
+package sub_share_center
+
+import (
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
+	"path/filepath"
+)
+
+// CopySub2Cache 检测原有字幕是否存在,然后放到缓存目录中
+func CopySub2Cache(orgSubFileFPath string, year int) (bool, string) {
+
+	nowFolderDir, err := my_util.GetShareFolderByYear(year)
+	if err != nil {
+		log_helper.GetLogger().Errorln("CheckOrgSubFileExistAndCopy2Cache.GetShareFolderByYear", err)
+		return false, ""
+	}
+
+	desSubFileFPath := filepath.Join(nowFolderDir, filepath.Base(orgSubFileFPath))
+	err = my_util.CopyFile(orgSubFileFPath, desSubFileFPath)
+	if err != nil {
+		log_helper.GetLogger().Errorln("CheckOrgSubFileExistAndCopy2Cache.CopyFile", err)
+		return false, ""
+	}
+
+	return true, desSubFileFPath
+}
+
+// ClearExpiredFiles 情况过期的字幕文件,比如数据库中没有其的引用,那么就需要清理
+func ClearExpiredFiles() {
+
+}