Pārlūkot izejas kodu

完成 sub formatter 与 downloader 的对接

Signed-off-by: allan716 <[email protected]>
allan716 4 gadi atpakaļ
vecāks
revīzija
4b3f732bad

+ 16 - 14
cmd/chinesesubfinder/main.go

@@ -7,7 +7,7 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/hot_fix"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/notify_center"
-	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_formatter/emby"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_formatter"
 	"github.com/allanpk716/ChineseSubFinder/internal/types"
 	"github.com/robfig/cron/v3"
 	"github.com/sirupsen/logrus"
@@ -43,6 +43,10 @@ func main() {
 		log.Errorln("SeriesFolder not found")
 		return
 	}
+	// 读取到的文件夹信息展示
+	log.Infoln("MovieFolder:", config.MovieFolder)
+	log.Infoln("SeriesFolder:", config.SeriesFolder)
+
 	// ------ 数据库相关操作 Start ------
 	err := dao.InitDb()
 	if err != nil {
@@ -80,9 +84,6 @@ func main() {
 	// 初始化通知缓存模块
 	notify_center.Notify = notify_center.NewNotifyCenter(config.WhenSubSupplierInvalidWebHook)
 
-	log.Infoln("MovieFolder:", config.MovieFolder)
-	log.Infoln("SeriesFolder:", config.SeriesFolder)
-
 	// ReloadBrowser 提前把浏览器下载好
 	pkg.ReloadBrowser()
 
@@ -117,16 +118,17 @@ func DownLoadStart(httpProxy string) {
 	notify_center.Notify.Clear()
 
 	// 下载实例
-	downloader := internal.NewDownloader(emby.NewFormatter(), types.ReqParam{
-		HttpProxy:                     httpProxy,
-		DebugMode:                     config.DebugMode,
-		SaveMultiSub:                  config.SaveMultiSub,
-		Threads:                       config.Threads,
-		SubTypePriority:               config.SubTypePriority,
-		WhenSubSupplierInvalidWebHook: config.WhenSubSupplierInvalidWebHook,
-		EmbyConfig:                    config.EmbyConfig,
-		SaveOneSeasonSub:              config.SaveOneSeasonSub,
-	})
+	downloader := internal.NewDownloader(sub_formatter.GetSubFormatter(config.SubNameFormatter),
+		types.ReqParam{
+			HttpProxy:                     httpProxy,
+			DebugMode:                     config.DebugMode,
+			SaveMultiSub:                  config.SaveMultiSub,
+			Threads:                       config.Threads,
+			SubTypePriority:               config.SubTypePriority,
+			WhenSubSupplierInvalidWebHook: config.WhenSubSupplierInvalidWebHook,
+			EmbyConfig:                    config.EmbyConfig,
+			SaveOneSeasonSub:              config.SaveOneSeasonSub,
+		})
 
 	log.Infoln("Download One Started...")
 

+ 61 - 14
internal/downloader.go

@@ -14,6 +14,7 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
+	subcommon "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_formatter/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/types"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/emby"
@@ -39,6 +40,7 @@ type Downloader struct {
 	movieFileFullPathList []string                      //  多个需要搜索字幕的电影文件全路径
 	seriesSubNeedDlMap    map[string][]emby.EmbyMixInfo //  多个需要搜索字幕的连续剧目录
 	subFormatter          ifaces.ISubFormatter          //	字幕格式化命名的实现
+	subNameFormatter      subcommon.FormatterName       // 从 inSubFormatter 推断出来
 }
 
 func NewDownloader(inSubFormatter ifaces.ISubFormatter, _reqParam ...types.ReqParam) *Downloader {
@@ -65,6 +67,8 @@ func NewDownloader(inSubFormatter ifaces.ISubFormatter, _reqParam ...types.ReqPa
 	} else {
 		downloader.reqParam = *types.NewReqParam()
 	}
+	// 这里就不单独弄一个 reqParam.SubNameFormatter 字段来传递值了,因为 inSubFormatter 就已经知道是什么 formatter 了
+	downloader.subNameFormatter = subcommon.FormatterName(downloader.subFormatter.GetFormatterFormatterName())
 
 	var sitesSequence = make([]string, 0)
 	// TODO 这里写固定了抉择字幕的顺序
@@ -384,12 +388,12 @@ func (d Downloader) oneVideoSelectBestSub(oneVideoFullPath string, organizeSubFi
 	}
 	// -------------------------------------------------
 	/*
-		这里需要额外考虑一点,有可能当前目录已经有一个 .Default 标记的字幕了
-		那么下载字幕丢进来的时候就需要提前把这个字幕找出来,去除整个 .Default 标记
+		这里需要额外考虑一点,有可能当前目录已经有一个 .Default .Forced 标记的字幕了
+		那么下载字幕丢进来的时候就需要提前把这个字幕找出来,去除整个 .Default .Forced  标记
 		然后进行正常的下载,存储和替换字幕,最后将本次操作的第一次标记为 .Default
 	*/
-	// 不管是不是保存多个字幕,都要先扫描本地的字幕,进行 .Default 去除
-	// 这个视频的所有字幕,去除 .default 标记
+	// 不管是不是保存多个字幕,都要先扫描本地的字幕,进行 .Default .Forced 去除
+	// 这个视频的所有字幕,去除 .default .Forced 标记
 	err = sub_helper.SearchVideoMatchSubFileAndRemoveExtMark(oneVideoFullPath)
 	if err != nil {
 		// 找个错误可以忍
@@ -403,8 +407,18 @@ func (d Downloader) oneVideoSelectBestSub(oneVideoFullPath string, organizeSubFi
 			d.log.Warnln("Found", len(organizeSubFiles), " subtitles but not one fit:", oneVideoFullPath)
 			return
 		}
+		/*
+			这里还有一个梗,Emby、jellyfin 支持 default 和 forced 扩展字段
+			但是,plex 只支持 forced
+			那么就比较麻烦,干脆,normal 的命名格式化实例,就不设置 default 了,forced 不想用,因为可能会跟你手动选择的字幕冲突(下次观看的时候,理论上也可能不会)
+		*/
+		// 判断配置文件中的字幕命名格式化的选择
+		bSetDefault := true
+		if d.subNameFormatter == subcommon.Normal {
+			bSetDefault = false
+		}
 		// 找到了,写入文件
-		err = d.writeSubFile2VideoPath(oneVideoFullPath, *finalSubFile, "", true)
+		err = d.writeSubFile2VideoPath(oneVideoFullPath, *finalSubFile, "", bSetDefault, false)
 		if err != nil {
 			d.log.Errorln("SaveMultiSub:", d.reqParam.SaveMultiSub, "writeSubFile2VideoPath:", err)
 			return
@@ -417,15 +431,38 @@ func (d Downloader) oneVideoSelectBestSub(oneVideoFullPath string, organizeSubFi
 			return
 		}
 		// 多网站 Top 1 字幕保存的时候,第一个设置为 Default 即可
-		for i, file := range finalSubFiles {
-			setDefault := false
-			if i == 0 {
-				setDefault = true
+		/*
+			由于新功能支持了字幕命名格式的选择,那么如果触发了多个字幕保存的逻辑,如果不调整
+			则会遇到,top1 先写入,然后 top2 覆盖 top1 ,以此类推的情况出现
+			所以如果开启了 Normal SubNameFormatter 的功能,则要反序写入文件
+			如果是 Emby 的字幕命名格式则无需考虑此问题,因为每个网站只会有一个字幕,且字幕命名格式决定了不会重复写入覆盖
+		*/
+		if d.subNameFormatter == subcommon.Emby {
+			for i, file := range finalSubFiles {
+				setDefault := false
+				if i == 0 {
+					setDefault = true
+				}
+				err = d.writeSubFile2VideoPath(oneVideoFullPath, file, siteNames[i], setDefault, false)
+				if err != nil {
+					d.log.Errorln("SaveMultiSub:", d.reqParam.SaveMultiSub, "writeSubFile2VideoPath:", err)
+					return
+				}
 			}
-			err = d.writeSubFile2VideoPath(oneVideoFullPath, file, siteNames[i], setDefault)
-			if err != nil {
-				d.log.Errorln("SaveMultiSub:", d.reqParam.SaveMultiSub, "writeSubFile2VideoPath:", err)
-				return
+		} else {
+			// 默认这里就是 normal 模式
+			// 逆序写入
+			/*
+				这里还有一个梗,Emby、jellyfin 支持 default 和 forced 扩展字段
+				但是,plex 只支持 forced
+				那么就比较麻烦,干脆,normal 的命名格式化实例,就不设置 default 了,forced 不想用,因为可能会跟你手动选择的字幕冲突(下次观看的时候,理论上也可能不会)
+			*/
+			for i := len(finalSubFiles) - 1; i > -1; i-- {
+				err = d.writeSubFile2VideoPath(oneVideoFullPath, finalSubFiles[i], siteNames[i], false, false)
+				if err != nil {
+					d.log.Errorln("SaveMultiSub:", d.reqParam.SaveMultiSub, "writeSubFile2VideoPath:", err)
+					return
+				}
 			}
 		}
 	}
@@ -473,7 +510,7 @@ func (d Downloader) saveFullSeasonSub(seriesInfo *series.SeriesInfo, organizeSub
 }
 
 // 在前面需要进行语言的筛选、排序,这里仅仅是存储, extraSubPreName 这里传递是字幕的网站,有就认为是多字幕的存储。空就是单字幕,单字幕就可以setDefault
-func (d Downloader) writeSubFile2VideoPath(videoFileFullPath string, finalSubFile subparser.FileInfo, extraSubPreName string, setDefault bool) error {
+func (d Downloader) writeSubFile2VideoPath(videoFileFullPath string, finalSubFile subparser.FileInfo, extraSubPreName string, setDefault bool, skipExistFile bool) error {
 
 	videoRootPath := filepath.Dir(videoFileFullPath)
 	subNewName, subNewNameWithDefault, _ := d.subFormatter.GenerateMixSubName(videoFileFullPath, finalSubFile.Ext, finalSubFile.Lang, extraSubPreName)
@@ -486,6 +523,15 @@ func (d Downloader) writeSubFile2VideoPath(videoFileFullPath string, finalSubFil
 		}
 		desSubFullPath = path.Join(videoRootPath, subNewNameWithDefault)
 	}
+
+	if skipExistFile == true {
+		// 需要判断文件是否存在在,有则跳过
+		if pkg.IsFile(desSubFullPath) == true {
+			d.log.Infoln("OrgSubName:", finalSubFile.Name)
+			d.log.Infoln("Sub Skip DownAt:", desSubFullPath)
+			return nil
+		}
+	}
 	// 最后写入字幕
 	err := utils.OutputFile(desSubFullPath, finalSubFile.Data)
 	if err != nil {
@@ -493,6 +539,7 @@ func (d Downloader) writeSubFile2VideoPath(videoFileFullPath string, finalSubFil
 	}
 	d.log.Infoln("OrgSubName:", finalSubFile.Name)
 	d.log.Infoln("SubDownAt:", desSubFullPath)
+
 	return nil
 }
 

+ 4 - 4
internal/downloader_test.go

@@ -4,7 +4,7 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/ass"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/srt"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg"
-	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_formatter/emby"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_formatter"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/types"
 	"testing"
@@ -22,7 +22,7 @@ func TestDownloader_DownloadSub4Movie(t *testing.T) {
 	dirRoot := "X:\\电影\\The Boss Baby Family Business (2021)"
 	//dirRoot := "X:\\电影"
 	config := pkg.GetConfig()
-	dl := NewDownloader(emby.NewFormatter(), types.ReqParam{
+	dl := NewDownloader(sub_formatter.GetSubFormatter(config.SubNameFormatter), types.ReqParam{
 		SaveMultiSub:    true,
 		SubTypePriority: 1,
 		EmbyConfig:      config.EmbyConfig,
@@ -54,7 +54,7 @@ func TestDownloader_DownloadSub4Series(t *testing.T) {
 
 	config := pkg.GetConfig()
 	// 如果需要调试 Emby 一定需要 dirRoot := "X:\\连续剧"
-	dl := NewDownloader(emby.NewFormatter(), types.ReqParam{
+	dl := NewDownloader(sub_formatter.GetSubFormatter(config.SubNameFormatter), types.ReqParam{
 		SaveMultiSub:    true,
 		SubTypePriority: 1,
 		EmbyConfig:      config.EmbyConfig,
@@ -72,7 +72,7 @@ func TestDownloader_DownloadSub4Series(t *testing.T) {
 func TestDownloader_GetUpdateVideoListFromEmby(t *testing.T) {
 	var err error
 	config := pkg.GetConfig()
-	dl := NewDownloader(emby.NewFormatter(), types.ReqParam{
+	dl := NewDownloader(sub_formatter.GetSubFormatter(config.SubNameFormatter), types.ReqParam{
 		SaveMultiSub:    true,
 		SubTypePriority: 1,
 		EmbyConfig:      config.EmbyConfig,

+ 2 - 0
internal/ifaces/iSubFormatter.go

@@ -5,6 +5,8 @@ import "github.com/allanpk716/ChineseSubFinder/internal/types"
 type ISubFormatter interface {
 	// GetFormatterName 当前的 formatter 是那个
 	GetFormatterName() string
+	// 需要转换为 FormatterName 使用
+	GetFormatterFormatterName() int
 	// IsMatchThisFormat 是否满足当前实现接口的字幕命名格式 - 是否符合规则、fileNameWithOutExt string, subExt string, subLang types.Language, extraSubPreName string
 	IsMatchThisFormat(subName string) (bool, string, string, types.Language, string)
 	// GenerateMixSubName 通过视频和字幕信息,生成当前实现接口的字幕命名格式。extraSubPreName 一般是填写字幕网站,不填写则留空 - 新名称、新名称带有 default 标记,新名称带有 forced 标记

+ 4 - 0
internal/pkg/sub_formatter/emby/emby.go

@@ -21,6 +21,10 @@ func (f Formatter) GetFormatterName() string {
 	return common.FormatterNameString_Emby
 }
 
+func (f Formatter) GetFormatterFormatterName() int {
+	return int(common.Emby)
+}
+
 // IsMatchThisFormat 是否满足当前实现接口的字幕命名格式 - 是否符合规则、fileNameWithOutExt string, subExt string, subLang types.Language, extraSubPreName string
 func (f Formatter) IsMatchThisFormat(subName string) (bool, string, string, types.Language, string) {
 	/*

+ 4 - 0
internal/pkg/sub_formatter/normal/normal.go

@@ -24,6 +24,10 @@ func (f Formatter) GetFormatterName() string {
 	return common.FormatterNameString_Normal
 }
 
+func (f Formatter) GetFormatterFormatterName() int {
+	return int(common.Normal)
+}
+
 // IsMatchThisFormat 是否满足当前实现接口的字幕命名格式 - 是否符合规则、fileNameWithOutExt string, subExt string, subLang types.Language, extraSubPreName string
 func (f Formatter) IsMatchThisFormat(subName string) (bool, string, string, types.Language, string) {
 	/*

+ 24 - 0
internal/pkg/sub_formatter/sub_format_changer.go

@@ -141,3 +141,27 @@ type RenameResults struct {
 	RenamedFiles map[string]int
 	ErrFiles     map[string]int
 }
+
+// GetSubFormatter 选择字幕命名格式化的实例
+func GetSubFormatter(subNameFormatter int) ifaces.ISubFormatter {
+	var subFormatter ifaces.ISubFormatter
+	switch subNameFormatter {
+	case int(common.Emby):
+		{
+			subFormatter = emby.NewFormatter()
+			break
+		}
+	case int(common.Normal):
+		{
+			subFormatter = normal.NewFormatter()
+			break
+		}
+	default:
+		{
+			subFormatter = emby.NewFormatter()
+			break
+		}
+	}
+
+	return subFormatter
+}

+ 1 - 0
internal/types/config.go

@@ -9,6 +9,7 @@ type Config struct {
 	DebugMode                     bool            // 是否启用 Debug 模式,调试功能
 	Threads                       int             // 同时并发的线程数(准确来说在go中不是线程,是 goroutine)
 	SubTypePriority               int             // 字幕下载的优先级,0 是自动,1 是 srt 优先,2 是 ass/ssa 优先
+	SubNameFormatter              int             // 字幕命名格式(默认不填写或者超出范围,则为 emby 格式),0 常规格式(兼容性更好,AAA.zh.ass or AAA.zh.default.ass),1 emby 支持的的格式(AAA.chinese(简英,subhd).ass or AAA.chinese(简英,xunlei).default.ass)
 	WhenSubSupplierInvalidWebHook string          // 当字幕网站失效的时候,触发的 webhook 地址,默认是 get
 	EmbyConfig                    emby.EmbyConfig // Emby API 高阶设置参数
 	SaveMultiSub                  bool            // 保存多个网站的 Top 1 字幕