Răsfoiți Sursa

保存进度,正在大范围重构

Signed-off-by: allan716 <[email protected]>
allan716 3 ani în urmă
părinte
comite
2bac1316cb
48 a modificat fișierele cu 846 adăugiri și 369 ștergeri
  1. 1 1
      cmd/GetCAPTCHA/backend/git_helper.go
  2. 2 1
      internal/logic/cron_helper/cron_helper.go
  3. 4 16
      internal/logic/downloader_helper/downloader_helper.go
  4. 7 7
      internal/logic/emby_helper/embyhelper.go
  5. 3 7
      internal/logic/movie_helper/moviehelper.go
  6. 8 8
      internal/logic/pre_download_process/pre_download_proces.go
  7. 3 3
      internal/logic/scan_played_video_subinfo/scan_played_video_subinfo.go
  8. 43 29
      internal/logic/series_helper/seriesHelper.go
  9. 14 1
      internal/logic/series_helper/seriesHelper_test.go
  10. 5 5
      internal/logic/sub_supplier/shooter/shooter.go
  11. 68 76
      internal/logic/sub_supplier/subSupplierHub.go
  12. 12 12
      internal/logic/sub_supplier/subhd/subhd.go
  13. 7 6
      internal/logic/sub_supplier/subhd/subhd_test.go
  14. 4 4
      internal/logic/sub_supplier/xunlei/xunlei.go
  15. 11 11
      internal/logic/sub_supplier/zimuku/zimuku.go
  16. 4 4
      internal/logic/sub_supplier/zimuku/zimuku_test.go
  17. 3 0
      internal/logic/task_queue/bucket_name.go
  18. 314 0
      internal/logic/task_queue/task_queue.go
  19. 8 8
      internal/pkg/decode/decode.go
  20. 177 127
      internal/pkg/downloader/downloader.go
  21. 0 6
      internal/pkg/downloader/downloader_things.go
  22. 1 1
      internal/pkg/ffmpeg_helper/ffmpeg_helper.go
  23. 1 1
      internal/pkg/ffmpeg_helper/ffmpeg_info.go
  24. 7 12
      internal/pkg/imdb_helper/imdb.go
  25. 1 1
      internal/pkg/imdb_helper/imdb_test.go
  26. 10 1
      internal/pkg/my_util/util.go
  27. 6 2
      internal/pkg/settings/advanced_settings.go
  28. 3 1
      internal/pkg/settings/emby_settings.go
  29. 7 5
      internal/pkg/settings/supplier_settings.go
  30. 11 0
      internal/pkg/settings/task_queue.go
  31. 1 1
      internal/pkg/something_static/something_static.go
  32. 1 1
      internal/pkg/sub_file_hash/sub_file_hash.go
  33. 1 1
      internal/pkg/sub_formatter/emby/emby_test.go
  34. 1 1
      internal/pkg/sub_formatter/normal/normal_test.go
  35. 1 1
      internal/pkg/sub_formatter/old/old.go
  36. 1 1
      internal/pkg/sub_formatter/sub_format_changer.go
  37. 1 1
      internal/pkg/sub_helper/sub_helper.go
  38. 1 1
      internal/pkg/sub_parser_hub/subParserHub.go
  39. 0 0
      internal/types/common/constvalue.go
  40. 0 0
      internal/types/common/global_value.go
  41. 0 0
      internal/types/common/selferr.go
  42. 0 0
      internal/types/common/subtypes.go
  43. 0 0
      internal/types/common/urls.go
  44. 12 0
      internal/types/common/video_type.go
  45. 1 1
      internal/types/emby/type.go
  46. 4 4
      internal/types/subparser/fileinfo.go
  47. 24 0
      internal/types/task_queue/job_status.go
  48. 52 0
      internal/types/task_queue/task_queue.go

+ 1 - 1
cmd/GetCAPTCHA/backend/git_helper.go

@@ -3,10 +3,10 @@ package backend
 import (
 	"fmt"
 	"github.com/allanpk716/ChineseSubFinder/cmd/GetCAPTCHA/backend/config"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/something_static"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing/object"
 	"github.com/go-git/go-git/v5/plumbing/transport/ssh"

+ 2 - 1
internal/logic/cron_helper/cron_helper.go

@@ -219,7 +219,8 @@ func (ch *CronHelper) coreSubDownloadProcess() {
 		return
 	}
 	// 开始下载
-	ch.dh = downloader_helper.NewDownloaderHelper(*settings.GetSettings(true),
+	ch.dh = downloader_helper.NewDownloaderHelper(settings.GetSettings(true),
+		ch.log,
 		preDownloadProcess.SubSupplierHub)
 	err = ch.dh.Start()
 	if err != nil {

+ 4 - 16
internal/logic/downloader_helper/downloader_helper.go

@@ -4,7 +4,6 @@ import (
 	subSupplier "github.com/allanpk716/ChineseSubFinder/internal/logic/sub_supplier"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/downloader"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/global_value"
-	"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/notify_center"
@@ -18,15 +17,15 @@ import (
 type DownloaderHelper struct {
 	subSupplierHub *subSupplier.SubSupplierHub
 	downloader     *downloader.Downloader
-	settings       settings.Settings
+	settings       *settings.Settings
 	logger         *logrus.Logger
 }
 
-func NewDownloaderHelper(settings settings.Settings, _subSupplierHub *subSupplier.SubSupplierHub) *DownloaderHelper {
+func NewDownloaderHelper(settings *settings.Settings, logger *logrus.Logger, _subSupplierHub *subSupplier.SubSupplierHub) *DownloaderHelper {
 	return &DownloaderHelper{
 		subSupplierHub: _subSupplierHub,
 		settings:       settings,
-		logger:         log_helper.GetLogger(),
+		logger:         logger,
 	}
 }
 
@@ -34,7 +33,7 @@ func NewDownloaderHelper(settings settings.Settings, _subSupplierHub *subSupplie
 func (d *DownloaderHelper) Start() error {
 	var err error
 	// 下载实例
-	d.downloader, err = downloader.NewDownloader(d.subSupplierHub, sub_formatter.GetSubFormatter(d.settings.AdvancedSettings.SubNameFormatter), d.settings)
+	d.downloader, err = downloader.NewDownloader(d.subSupplierHub, sub_formatter.GetSubFormatter(d.settings.AdvancedSettings.SubNameFormatter), d.settings, d.logger)
 	if err != nil {
 		d.logger.Errorln("NewDownloader", err)
 	}
@@ -60,17 +59,6 @@ func (d *DownloaderHelper) Start() error {
 			d.logger.Errorln("RestoreFixTimelineBK", err)
 		}
 	}
-	// 刷新 Emby 的字幕,如果下载了字幕倒是没有刷新,则先刷新一次,便于后续的 Emby api 统计逻辑
-	err = d.downloader.RefreshEmbySubList()
-	if err != nil {
-		d.logger.Errorln("RefreshEmbySubList", err)
-		return err
-	}
-	err = d.downloader.GetUpdateVideoListFromEmby()
-	if err != nil {
-		d.logger.Errorln("GetUpdateVideoListFromEmby", err)
-		return err
-	}
 	// 开始下载,电影
 	err = d.downloader.DownloadSub4Movie()
 	if err != nil {

+ 7 - 7
internal/logic/emby_helper/embyhelper.go

@@ -2,13 +2,13 @@ package emby_helper
 
 import (
 	"fmt"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	embyHelper "github.com/allanpk716/ChineseSubFinder/internal/pkg/emby_api"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/path_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
+	common2 "github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/emby"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/language"
 	"github.com/panjf2000/ants/v2"
@@ -378,7 +378,7 @@ func (em *EmbyHelper) findMappingPathWithMixInfo(mixInfo *emby.EmbyMixInfo, isMo
 
 		if len(mixInfo.VideoInfo.MediaSources) > 0 && mixInfo.VideoInfo.MediaSources[0].Container == "bluray" {
 			// 这个就是蓝光了
-			fakeVideoFPath := filepath.Join(mixInfo.VideoInfo.Path, filepath.Base(mixInfo.VideoInfo.Path)+common.VideoExtMp4)
+			fakeVideoFPath := filepath.Join(mixInfo.VideoInfo.Path, filepath.Base(mixInfo.VideoInfo.Path)+common2.VideoExtMp4)
 			mixInfo.PhysicalVideoFileFullPath = strings.ReplaceAll(fakeVideoFPath, pathSlices[0].Path, nowPhRootPath)
 			// 这个电影的文件夹
 			mixInfo.VideoFolderName = filepath.Base(filepath.Dir(fakeVideoFPath))
@@ -515,8 +515,8 @@ func (em *EmbyHelper) getMoreVideoInfoList(videoIdList []string, isMovieOrSeries
 // filterNoChineseSubVideoList 将没有中文字幕的视频找出来
 func (em *EmbyHelper) filterNoChineseSubVideoList(videoList []emby.EmbyMixInfo) ([]emby.EmbyMixInfo, error) {
 	currentTime := time.Now()
-	dayRange3Months, _ := time.ParseDuration(common.DownloadSubDuring3Months)
-	dayRange7Days, _ := time.ParseDuration(common.DownloadSubDuring7Days)
+	dayRange3Months, _ := time.ParseDuration(common2.DownloadSubDuring3Months)
+	dayRange7Days, _ := time.ParseDuration(common2.DownloadSubDuring7Days)
 
 	var noSubVideoList = make([]emby.EmbyMixInfo, 0)
 	// TODO 这里有一种情况需要考虑的,如果内置有中文的字幕,那么是否需要跳过,目前暂定的一定要有外置的字幕
@@ -667,7 +667,7 @@ func (em *EmbyHelper) GetInternalEngSubAndExChineseEnglishSub(videoId string) (b
 		var tmpSubContentLenList = make([]int, 0)
 		for _, index := range insideEngSUbIndexList {
 			// TODO 这里默认是去 Emby 去拿字幕,但是其实可以缓存在视频文件同级的目录下,这样后续就无需多次下载了,毕竟每次下载都需要读取完整的视频
-			subFileData, err := em.embyApi.GetSubFileData(videoId, mediaSourcesId, fmt.Sprintf("%d", index), common.SubExtSRT)
+			subFileData, err := em.embyApi.GetSubFileData(videoId, mediaSourcesId, fmt.Sprintf("%d", index), common2.SubExtSRT)
 			if err != nil {
 				return false, nil, nil, err
 			}
@@ -683,9 +683,9 @@ func (em *EmbyHelper) GetInternalEngSubAndExChineseEnglishSub(videoId string) (b
 	}
 	// 这里才是下载最佳的那个字幕
 	for i := 0; i < 2; i++ {
-		tmpExt := common.SubExtSRT
+		tmpExt := common2.SubExtSRT
 		if i == 1 {
-			tmpExt = common.SubExtASS
+			tmpExt = common2.SubExtASS
 		}
 		subFileData, err := em.embyApi.GetSubFileData(videoId, mediaSourcesId, fmt.Sprintf("%d", InsideEngSubIndex), tmpExt)
 		if err != nil {

+ 3 - 7
internal/logic/movie_helper/moviehelper.go

@@ -1,7 +1,6 @@
 package movie_helper
 
 import (
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/ifaces"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/ass"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/srt"
@@ -11,6 +10,7 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/supplier"
 	"github.com/jinzhu/now"
 	"os"
@@ -125,17 +125,13 @@ func MovieHasChineseSub(videoFilePath string) (bool, []string, []string, error)
 }
 
 // SkipChineseMovie 跳过中文的电影
-func SkipChineseMovie(videoFullPath string, _proxySettings ...settings.ProxySettings) (bool, error) {
+func SkipChineseMovie(videoFullPath string, _proxySettings ...*settings.ProxySettings) (bool, error) {
 
-	var proxySettings settings.ProxySettings
-	if len(_proxySettings) > 0 {
-		proxySettings = _proxySettings[0]
-	}
 	imdbInfo, err := decode.GetImdbInfo4Movie(videoFullPath)
 	if err != nil {
 		return false, err
 	}
-	isChineseVideo, _, err := imdb_helper.IsChineseVideo(imdbInfo.ImdbId, proxySettings)
+	isChineseVideo, _, err := imdb_helper.IsChineseVideo(imdbInfo.ImdbId, _proxySettings...)
 	if err != nil {
 		return false, err
 	}

+ 8 - 8
internal/logic/pre_download_process/pre_download_proces.go

@@ -3,7 +3,6 @@ package pre_download_process
 import (
 	"errors"
 	"fmt"
-	commonValue "github.com/allanpk716/ChineseSubFinder/internal/common"
 	subSupplier "github.com/allanpk716/ChineseSubFinder/internal/logic/sub_supplier"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_supplier/shooter"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_supplier/subhd"
@@ -20,6 +19,7 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_formatter/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/url_connectedness_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/types"
+	common2 "github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/sirupsen/logrus"
 	"time"
 )
@@ -67,7 +67,7 @@ func (p *PreDownloadProcess) Init() *PreDownloadProcess {
 		p.log.Errorln("something_static.GetCodeFromWeb", err)
 		p.log.Errorln("Skip Subhd download")
 		// 没有则需要清空
-		commonValue.SubhdCode = ""
+		common2.SubhdCode = ""
 	} else {
 
 		// 获取到的更新时间不是当前的日期,那么本次也跳过本次
@@ -75,17 +75,17 @@ func (p *PreDownloadProcess) Init() *PreDownloadProcess {
 		if err != nil {
 			p.log.Errorln("something_static.GetCodeFromWeb.time.Parse", err)
 			// 没有则需要清空
-			commonValue.SubhdCode = ""
+			common2.SubhdCode = ""
 		} else {
 
 			nowTime := time.Now()
 			if codeTime.YearDay() != nowTime.YearDay() {
 				// 没有则需要清空
-				commonValue.SubhdCode = ""
+				common2.SubhdCode = ""
 				p.log.Warningln("something_static.GetCodeFromWeb, GetCodeTime:", updateTimeString, "NowTime:", time.Now().String(), "Skip")
 			} else {
 				p.log.Infoln("GetCode", updateTimeString, code)
-				commonValue.SubhdCode = code
+				common2.SubhdCode = code
 			}
 		}
 	}
@@ -98,7 +98,7 @@ func (p *PreDownloadProcess) Init() *PreDownloadProcess {
 		xunlei.NewSupplier(p.sets, p.log),
 		shooter.NewSupplier(p.sets, p.log),
 	)
-	if commonValue.SubhdCode != "" {
+	if common2.SubhdCode != "" {
 		// 如果找到 code 了,那么就可以继续用这个实例
 		p.SubSupplierHub.AddSubSupplier(subhd.NewSupplier(p.sets, p.log))
 	}
@@ -194,7 +194,7 @@ func (p *PreDownloadProcess) HotFix() *PreDownloadProcess {
 	p.log.Infoln("PreDownloadProcess.HotFix() Start...")
 	// ------------------------------------------------------------------------
 	// 开始修复
-	p.log.Infoln(commonValue.NotifyStringTellUserWait)
+	p.log.Infoln(common2.NotifyStringTellUserWait)
 	err := hot_fix.HotFixProcess(types.HotFixParam{
 		MovieRootDirs:  p.sets.CommonSettings.MoviePaths,
 		SeriesRootDirs: p.sets.CommonSettings.SeriesPaths,
@@ -225,7 +225,7 @@ func (p *PreDownloadProcess) ChangeSubNameFormat() *PreDownloadProcess {
 		如果数据库没有记录经过转换,那么默认从 Emby 的格式作为检测的起点,转换到目标的格式
 		然后需要在数据库中记录本次的转换结果
 	*/
-	p.log.Infoln(commonValue.NotifyStringTellUserWait)
+	p.log.Infoln(common2.NotifyStringTellUserWait)
 	renameResults, err := sub_formatter.SubFormatChangerProcess(
 		p.sets.CommonSettings.MoviePaths,
 		p.sets.CommonSettings.SeriesPaths,

+ 3 - 3
internal/logic/scan_played_video_subinfo/scan_played_video_subinfo.go

@@ -3,7 +3,6 @@ package scan_played_video_subinfo
 import (
 	"errors"
 	"fmt"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/dao"
 	"github.com/allanpk716/ChineseSubFinder/internal/ifaces"
 	embyHelper "github.com/allanpk716/ChineseSubFinder/internal/logic/emby_helper"
@@ -22,6 +21,7 @@ import (
 	"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/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubModels/models"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/net/context"
@@ -291,7 +291,7 @@ func (s *ScanPlayedVideoSubInfo) dealOneVideo(index int, videoFPath, orgSubFPath
 
 	s.log.Debugln(1)
 
-	// 使用 shooter 的技术 hash 的算法,得到视频的唯一 ID
+	// 使用本程序的 hash 的算法,得到视频的唯一 ID
 	fileHash, err := sub_file_hash.Calculate(videoFPath)
 	if err != nil {
 		s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".ComputeFileHash", videoFPath, err)
@@ -392,7 +392,7 @@ func (s *ScanPlayedVideoSubInfo) dealOneVideo(index int, videoFPath, orgSubFPath
 
 	if isMovie == false {
 		// 连续剧的时候,如果可能应该获取是 第几季  第几集
-		torrentInfo, _, err := decode.GetVideoInfoFromFileFullPath(subCacheFPath)
+		torrentInfo, _, err := decode.GetVideoInfoFromFileFullPath(videoFPath)
 		if err != nil {
 			s.log.Warningln("ScanPlayedVideoSubInfo.Scan", videoTypes, ".GetVideoInfoFromFileFullPath", imdbInfo4Video.Title, err)
 			return

+ 43 - 29
internal/logic/series_helper/seriesHelper.go

@@ -2,7 +2,6 @@ package series_helper
 
 import (
 	"fmt"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/ifaces"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/ass"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/srt"
@@ -13,6 +12,7 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/emby"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/series"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/supplier"
@@ -24,24 +24,21 @@ import (
 	"time"
 )
 
-// ReadSeriesInfoFromDir 读取剧集的信息,只有那些 Eps 需要下载字幕的 NeedDlEpsKeyList
-func ReadSeriesInfoFromDir(seriesDir string, imdbInfo *gModels.IMDBInfo, forcedScanAndDownloadSub bool) (*series.SeriesInfo, error) {
+func readSeriesInfo(seriesDir string, _proxySettings ...*settings.ProxySettings) (*series.SeriesInfo, map[string][]series.SubInfo, error) {
 
 	subParserHub := sub_parser_hub.NewSubParserHub(ass.NewParser(), srt.NewParser())
 
-	seriesInfo, err := getSeriesInfoFromDir(seriesDir, imdbInfo)
+	seriesInfo, err := getSeriesInfoFromDir(seriesDir, _proxySettings...)
 	if err != nil {
-		return nil, err
-	}
-	// 搜索所有的视频
-	videoFiles, err := my_util.SearchMatchedVideoFile(log_helper.GetLogger(), seriesDir)
-	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
+	seriesInfo.NeedDlSeasonDict = make(map[int]int)
+	seriesInfo.NeedDlEpsKeyList = make(map[string]series.EpisodeInfo)
+
 	// 搜索所有的字幕
 	subFiles, err := sub_helper.SearchMatchedSubFileByDir(seriesDir)
 	if err != nil {
-		return nil, err
+		return nil, nil, err
 	}
 	// 字幕字典 S01E01 - []SubInfo
 	SubDict := make(map[string][]series.SubInfo)
@@ -80,6 +77,22 @@ func ReadSeriesInfoFromDir(seriesDir string, imdbInfo *gModels.IMDBInfo, forcedS
 		}
 		SubDict[epsKey] = append(SubDict[epsKey], oneFileSubInfo)
 	}
+
+	return seriesInfo, SubDict, nil
+}
+
+// ReadSeriesInfoFromDir 读取剧集的信息,只有那些 Eps 需要下载字幕的 NeedDlEpsKeyList
+func ReadSeriesInfoFromDir(seriesDir string, forcedScanAndDownloadSub bool, _proxySettings ...*settings.ProxySettings) (*series.SeriesInfo, error) {
+
+	seriesInfo, SubDict, err := readSeriesInfo(seriesDir, _proxySettings...)
+	if err != nil {
+		return nil, err
+	}
+	// 搜索所有的视频
+	videoFiles, err := my_util.SearchMatchedVideoFile(log_helper.GetLogger(), seriesDir)
+	if err != nil {
+		return nil, err
+	}
 	// 视频字典 S01E01 - EpisodeInfo
 	EpisodeDict := make(map[string]series.EpisodeInfo)
 	for _, videoFile := range videoFiles {
@@ -96,17 +109,15 @@ func ReadSeriesInfoFromDir(seriesDir string, imdbInfo *gModels.IMDBInfo, forcedS
 	return seriesInfo, nil
 }
 
-// ReadSeriesInfoFromEmby 将 Emby API 读取到的数据进行转换到通用的结构中,需要填充那些剧集需要下载,这样要的是一个连续剧的,不是所有的传入
-func ReadSeriesInfoFromEmby(seriesDir string, imdbInfo *gModels.IMDBInfo, seriesList []emby.EmbyMixInfo) (*series.SeriesInfo, error) {
+// ReadSeriesInfoFromEmby 将 Emby API 读取到的数据进行转换到通用的结构中,需要填充那些剧集需要下载,这样要的是一个连续剧的,不是所有的传入(只有那些 Eps 需要下载字幕的 NeedDlEpsKeyList)
+func ReadSeriesInfoFromEmby(seriesDir string, seriesList []emby.EmbyMixInfo, _proxySettings ...*settings.ProxySettings) (*series.SeriesInfo, error) {
 
-	seriesInfo, err := getSeriesInfoFromDir(seriesDir, imdbInfo)
+	seriesInfo, SubDict, err := readSeriesInfo(seriesDir, _proxySettings...)
 	if err != nil {
 		return nil, err
 	}
-	seriesInfo.NeedDlSeasonDict = make(map[int]int)
-	seriesInfo.NeedDlEpsKeyList = make(map[string]series.EpisodeInfo)
+
 	EpisodeDict := make(map[string]series.EpisodeInfo)
-	SubDict := make(map[string][]series.SubInfo)
 	for _, info := range seriesList {
 		getEpsInfoAndSubDic(info.PhysicalVideoFileFullPath, EpisodeDict, SubDict)
 	}
@@ -122,17 +133,14 @@ func ReadSeriesInfoFromEmby(seriesDir string, imdbInfo *gModels.IMDBInfo, series
 }
 
 // SkipChineseSeries 跳过中文连续剧
-func SkipChineseSeries(seriesRootPath string, _proxySettings ...settings.ProxySettings) (bool, *gModels.IMDBInfo, error) {
-	var proxySettings settings.ProxySettings
-	if len(_proxySettings) > 0 {
-		proxySettings = _proxySettings[0]
-	}
+func SkipChineseSeries(seriesRootPath string, _proxySettings ...*settings.ProxySettings) (bool, *gModels.IMDBInfo, error) {
+
 	imdbInfo, err := decode.GetImdbInfo4SeriesDir(seriesRootPath)
 	if err != nil {
 		return false, nil, err
 	}
 
-	isChineseVideo, t, err := imdb_helper.IsChineseVideo(imdbInfo.ImdbId, proxySettings)
+	isChineseVideo, t, err := imdb_helper.IsChineseVideo(imdbInfo.ImdbId, _proxySettings...)
 	if err != nil {
 		return false, nil, err
 	}
@@ -255,7 +263,7 @@ func GetSeriesListFromDirs(dirs []string) (*treemap.Map, error) {
 			fileFullPathMap.Put(dir, seriesList)
 		} else {
 			value = append(value.([]string), seriesList...)
-			fileFullPathMap.Put(value, dir)
+			fileFullPathMap.Put(dir, value)
 		}
 	}
 
@@ -330,19 +338,25 @@ func whichSeasonEpsNeedDownloadSub(seriesInfo *series.SeriesInfo, forcedScanAndD
 	return needDlSubEpsList, needDlSeasonList
 }
 
-func getSeriesInfoFromDir(seriesDir string, imdbInfo *gModels.IMDBInfo) (*series.SeriesInfo, error) {
+func getSeriesInfoFromDir(seriesDir string, _proxySettings ...*settings.ProxySettings) (*series.SeriesInfo, error) {
 	seriesInfo := series.SeriesInfo{}
 	// 只考虑 IMDB 去查询,文件名目前发现可能会跟电影重复,导致很麻烦,本来也有前置要求要削刮器处理的
 	videoInfo, err := decode.GetImdbInfo4SeriesDir(seriesDir)
 	if err != nil {
 		return nil, err
 	}
+
+	imdbInfoFromLocal, err := imdb_helper.GetVideoIMDBInfoFromLocal(videoInfo.ImdbId, _proxySettings...)
+	if err != nil {
+		return nil, err
+	}
+
 	// 使用 IMDB ID 得到通用的剧集名称
 	// 以 IMDB 的信息为准
-	if imdbInfo != nil {
-		seriesInfo.Name = imdbInfo.Name
-		seriesInfo.ImdbId = imdbInfo.IMDBID
-		seriesInfo.Year = imdbInfo.Year
+	if imdbInfoFromLocal != nil {
+		seriesInfo.Name = imdbInfoFromLocal.Name
+		seriesInfo.ImdbId = imdbInfoFromLocal.IMDBID
+		seriesInfo.Year = imdbInfoFromLocal.Year
 	} else {
 		seriesInfo.Name = videoInfo.Title
 		seriesInfo.ImdbId = videoInfo.ImdbId

+ 14 - 1
internal/logic/series_helper/seriesHelper_test.go

@@ -8,7 +8,7 @@ import (
 func TestReadSeriesInfoFromDir(t *testing.T) {
 
 	series := unit_test_helper.GetTestDataResourceRootPath([]string{"series", "Loki"}, 4, false)
-	seriesInfo, err := ReadSeriesInfoFromDir(series, nil, false)
+	seriesInfo, err := ReadSeriesInfoFromDir(series, false)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -21,3 +21,16 @@ func TestReadSeriesInfoFromDir(t *testing.T) {
 		}
 	}
 }
+
+func TestGetSeriesListFromDirs(t *testing.T) {
+
+	series := unit_test_helper.GetTestDataResourceRootPath([]string{"series"}, 4, false)
+	got, err := GetSeriesListFromDirs([]string{series})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if got.Size() < 1 {
+		t.Fatal("GetSeriesListFromDirs got len < 1")
+	}
+}

+ 5 - 5
internal/logic/sub_supplier/shooter/shooter.go

@@ -4,13 +4,13 @@ import (
 	"crypto/md5"
 	"errors"
 	"fmt"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/task_queue"
 	pkgcommon "github.com/allanpk716/ChineseSubFinder/internal/pkg/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/notify_center"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
+	common2 "github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/language"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/series"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/supplier"
@@ -33,7 +33,7 @@ func NewSupplier(_settings *settings.Settings, _logger *logrus.Logger) *Supplier
 
 	sup := Supplier{}
 	sup.log = _logger
-	sup.topic = common.DownloadSubsPerSite
+	sup.topic = common2.DownloadSubsPerSite
 	sup.isAlive = true // 默认是可以使用的,如果 check 后,再调整状态
 
 	sup.settings = _settings
@@ -68,7 +68,7 @@ func (s *Supplier) OverDailyDownloadLimit() bool {
 }
 
 func (s *Supplier) GetSupplierName() string {
-	return common.SubSiteShooter
+	return common2.SubSiteShooter
 }
 
 func (s *Supplier) GetSubListFromFile4Movie(filePath string) ([]supplier.SubInfo, error) {
@@ -116,7 +116,7 @@ func (s *Supplier) getSubListFromFile(filePath string) ([]supplier.SubInfo, erro
 		return nil, err
 	}
 	if hash == "" {
-		return nil, common.ShooterFileHashIsEmpty
+		return nil, common2.ShooterFileHashIsEmpty
 	}
 
 	fileName := filepath.Base(filePath)
@@ -196,7 +196,7 @@ func ComputeFileHash(filePath string) (string, error) {
 	}
 	size := float64(stat.Size())
 	if size < 0xF000 {
-		return "", common.VideoFileIsTooSmall
+		return "", common2.VideoFileIsTooSmall
 	}
 	samplePositions := [4]int64{
 		4 * 1024,

+ 68 - 76
internal/logic/sub_supplier/subSupplierHub.go

@@ -1,11 +1,9 @@
 package sub_supplier
 
 import (
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/ifaces"
 	movieHelper "github.com/allanpk716/ChineseSubFinder/internal/logic/movie_helper"
 	seriesHelper "github.com/allanpk716/ChineseSubFinder/internal/logic/series_helper"
-	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/backend"
@@ -44,6 +42,7 @@ func (d *SubSupplierHub) AddSubSupplier(one ifaces.ISupplier) {
 	d.Suppliers = append(d.Suppliers, one)
 }
 
+// DelSubSupplier 移除一个下载器
 func (d *SubSupplierHub) DelSubSupplier(one ifaces.ISupplier) {
 
 	for i := 0; i < len(d.Suppliers); i++ {
@@ -54,26 +53,22 @@ func (d *SubSupplierHub) DelSubSupplier(one ifaces.ISupplier) {
 	}
 }
 
-// DownloadSub4Movie 某一个电影字幕下载,下载完毕后,返回下载缓存每个字幕的位置
-func (d *SubSupplierHub) DownloadSub4Movie(videoFullPath string, index int, forcedScanAndDownloadSub bool) ([]string, error) {
+// MovieNeedDlSub 电影是否符合要求需要下载字幕,比如
+func (d *SubSupplierHub) MovieNeedDlSub(videoFullPath string, skipChineseMovie, forcedScanAndDownloadSub bool) bool {
 
-	if forcedScanAndDownloadSub == false {
-		// 非强制扫描的时候,需要判断这个视频根目录是否有 .ignore 文件,有也跳过
-		if my_util.IsFile(filepath.Join(filepath.Dir(videoFullPath), common.Ignore)) == true {
-			d.log.Infoln("Found", common.Ignore, "Skip", videoFullPath)
-			// 跳过下载字幕
-			return nil, nil
+	var err error
+	if skipChineseMovie == true {
+		var skip bool
+		// 跳过中文的电影,不是一定要跳过的
+		skip, err = movieHelper.SkipChineseMovie(videoFullPath, d.settings.AdvancedSettings.ProxySettings)
+		if err != nil {
+			d.log.Warnln("SkipChineseMovie", videoFullPath, err)
+		}
+		if skip == true {
+			return false
 		}
 	}
 
-	// 跳过中文的电影,不是一定要跳过的
-	skip, err := movieHelper.SkipChineseMovie(videoFullPath, *d.settings.AdvancedSettings.ProxySettings)
-	if err != nil {
-		d.log.Warnln("SkipChineseMovie", videoFullPath, err)
-	}
-	if skip == true {
-		return nil, nil
-	}
 	var needDlSub = false
 	if forcedScanAndDownloadSub == true {
 		// 强制下载字幕
@@ -81,88 +76,85 @@ func (d *SubSupplierHub) DownloadSub4Movie(videoFullPath string, index int, forc
 	} else {
 		needDlSub, err = movieHelper.MovieNeedDlSub(videoFullPath)
 		if err != nil {
-			return nil, errors.Newf("MovieNeedDlSub %v %v", videoFullPath, err)
+			d.log.Errorln(errors.Newf("MovieNeedDlSub %v %v", videoFullPath, err))
+			return false
 		}
 	}
-	if needDlSub == true {
-		// 需要下载字幕
-		// 下载所有字幕
-		subInfos := movieHelper.OneMovieDlSubInAllSite(d.Suppliers, videoFullPath, index)
-		// 整理字幕,比如解压什么的
-		organizeSubFiles, err := sub_helper.OrganizeDlSubFiles(filepath.Base(videoFullPath), subInfos)
+
+	return needDlSub
+}
+
+// SeriesNeedDlSub 连续剧是否符合要求需要下载字幕
+func (d *SubSupplierHub) SeriesNeedDlSub(seriesRootPath string, skipChineseMovie, forcedScanAndDownloadSub bool) (bool, *series.SeriesInfo, error) {
+
+	if skipChineseMovie == true {
+		var skip bool
+		var err error
+		// 跳过中文的电影,不是一定要跳过的
+		skip, _, err = seriesHelper.SkipChineseSeries(seriesRootPath, d.settings.AdvancedSettings.ProxySettings)
 		if err != nil {
-			return nil, errors.Newf("OrganizeDlSubFiles %v %v", videoFullPath, err)
+			d.log.Warnln("SkipChineseMovie", seriesRootPath, err)
 		}
-		// 因为是下载电影,需要合并返回
-		var outSubFileFullPathList = make([]string, 0)
-		for s := range organizeSubFiles {
-			outSubFileFullPathList = append(outSubFileFullPathList, organizeSubFiles[s]...)
-		}
-
-		for i, subFile := range outSubFileFullPathList {
-			d.log.Debugln("OneMovieDlSubInAllSite", videoFullPath, i, "SubFileFPath:", subFile)
+		if skip == true {
+			return false, nil, nil
 		}
+	}
 
-		return outSubFileFullPathList, nil
-	} else {
-		// 无需下载字幕
-		return nil, nil
+	// 读取本地的视频和字幕信息
+	seriesInfo, err := seriesHelper.ReadSeriesInfoFromDir(seriesRootPath, forcedScanAndDownloadSub, d.settings.AdvancedSettings.ProxySettings)
+	if err != nil {
+		return false, nil, errors.Newf("ReadSeriesInfoFromDir %v %v", seriesRootPath, err)
 	}
+
+	return true, seriesInfo, nil
 }
 
-// DownloadSub4Series 某一部连续剧的字幕下载,下载完毕后,返回下载缓存每个字幕的位置
-func (d *SubSupplierHub) DownloadSub4Series(seriesDirPath string, index int, forcedScanAndDownloadSub bool) (*series.SeriesInfo, map[string][]string, error) {
-
-	if forcedScanAndDownloadSub == false {
-		// 非强制扫描的时候,需要判断这个视频根目录是否有 .ignore 文件,有也跳过
-		if my_util.IsFile(filepath.Join(seriesDirPath, common.Ignore)) == true {
-			d.log.Infoln("Found", common.Ignore, "Skip", seriesDirPath)
-			// 跳过下载字幕
-			return nil, nil, nil
-		}
-	}
+// DownloadSub4Movie 某一个电影字幕下载,下载完毕后,返回下载缓存每个字幕的位置,这里将只关心下载字幕,判断是否在时间范围内要不要下载不在这里判断,包括是否是中文视频的问题
+func (d *SubSupplierHub) DownloadSub4Movie(videoFullPath string, index int) ([]string, error) {
 
-	// 跳过中文的连续剧,不是一定要跳过的
-	skip, imdbInfo, err := seriesHelper.SkipChineseSeries(seriesDirPath, *d.settings.AdvancedSettings.ProxySettings)
+	// 下载所有字幕
+	subInfos := movieHelper.OneMovieDlSubInAllSite(d.Suppliers, videoFullPath, index)
+	// 整理字幕,比如解压什么的
+	organizeSubFiles, err := sub_helper.OrganizeDlSubFiles(filepath.Base(videoFullPath), subInfos)
 	if err != nil {
-		d.log.Warnln("SkipChineseSeries", seriesDirPath, err)
+		return nil, errors.Newf("OrganizeDlSubFiles %v %v", videoFullPath, err)
 	}
-	if skip == true {
-		return nil, nil, nil
+	// 因为是下载电影,需要合并返回
+	var outSubFileFullPathList = make([]string, 0)
+	for s := range organizeSubFiles {
+		outSubFileFullPathList = append(outSubFileFullPathList, organizeSubFiles[s]...)
 	}
-	// 读取本地的视频和字幕信息
-	seriesInfo, err := seriesHelper.ReadSeriesInfoFromDir(seriesDirPath, imdbInfo, forcedScanAndDownloadSub)
-	if err != nil {
-		return nil, nil, errors.Newf("ReadSeriesInfoFromDir %v %v", seriesDirPath, err)
+
+	for i, subFile := range outSubFileFullPathList {
+		d.log.Debugln("OneMovieDlSubInAllSite", videoFullPath, i, "SubFileFPath:", subFile)
 	}
-	organizeSubFiles, err := d.dlSubFromSeriesInfo(seriesDirPath, index, seriesInfo, err)
+
+	return outSubFileFullPathList, nil
+}
+
+// DownloadSub4Series 某一部连续剧的字幕下载,下载完毕后,返回下载缓存每个字幕的位置
+func (d *SubSupplierHub) DownloadSub4Series(seriesDirPath string, seriesInfo *series.SeriesInfo, index int) (map[string][]string, error) {
+
+	organizeSubFiles, err := d.dlSubFromSeriesInfo(seriesDirPath, index, seriesInfo)
 	if err != nil {
-		return nil, nil, err
+		return nil, err
 	}
-	return seriesInfo, organizeSubFiles, nil
+	return organizeSubFiles, nil
 }
 
 // DownloadSub4SeriesFromEmby 通过 Emby 查询到的信息进行字幕下载,下载完毕后,返回下载缓存每个字幕的位置
-func (d *SubSupplierHub) DownloadSub4SeriesFromEmby(seriesDirPath string, seriesList []emby.EmbyMixInfo, index int) (*series.SeriesInfo, map[string][]string, error) {
+func (d *SubSupplierHub) DownloadSub4SeriesFromEmby(seriesDirPath string, seriesList []emby.EmbyMixInfo, index int) (map[string][]string, error) {
 
-	// 跳过中文的连续剧,不是一定要跳过的
-	skip, imdbInfo, err := seriesHelper.SkipChineseSeries(seriesDirPath, *d.settings.AdvancedSettings.ProxySettings)
-	if err != nil {
-		d.log.Warnln("SkipChineseSeries", seriesDirPath, err)
-	}
-	if skip == true {
-		return nil, nil, nil
-	}
 	// 读取本地的视频和字幕信息
-	seriesInfo, err := seriesHelper.ReadSeriesInfoFromEmby(seriesDirPath, imdbInfo, seriesList)
+	seriesInfo, err := seriesHelper.ReadSeriesInfoFromEmby(seriesDirPath, seriesList, d.settings.AdvancedSettings.ProxySettings)
 	if err != nil {
-		return nil, nil, errors.Newf("ReadSeriesInfoFromDir %v %v", seriesDirPath, err)
+		return nil, errors.Newf("ReadSeriesInfoFromDir %v %v", seriesDirPath, err)
 	}
-	organizeSubFiles, err := d.dlSubFromSeriesInfo(seriesDirPath, index, seriesInfo, err)
+	organizeSubFiles, err := d.dlSubFromSeriesInfo(seriesDirPath, index, seriesInfo)
 	if err != nil {
-		return nil, nil, err
+		return nil, err
 	}
-	return seriesInfo, organizeSubFiles, nil
+	return organizeSubFiles, nil
 }
 
 // CheckSubSiteStatus 检测多个字幕提供的网站是否是有效的,是否下载次数超限
@@ -209,7 +201,7 @@ func (d *SubSupplierHub) CheckSubSiteStatus() backend.ReplyCheckStatus {
 	return outStatus
 }
 
-func (d *SubSupplierHub) dlSubFromSeriesInfo(seriesDirPath string, index int, seriesInfo *series.SeriesInfo, err error) (map[string][]string, error) {
+func (d *SubSupplierHub) dlSubFromSeriesInfo(seriesDirPath string, index int, seriesInfo *series.SeriesInfo) (map[string][]string, error) {
 	// 下载好的字幕
 	subInfos := seriesHelper.DownloadSubtitleInAllSiteByOneSeries(d.Suppliers, seriesInfo, index)
 	// 整理字幕,比如解压什么的

+ 12 - 12
internal/logic/sub_supplier/subhd/subhd.go

@@ -5,7 +5,6 @@ import (
 	"fmt"
 	"github.com/PuerkitoBio/goquery"
 	"github.com/Tnze/go.num/v2/zh"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/task_queue"
 	pkgcommon "github.com/allanpk716/ChineseSubFinder/internal/pkg/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
@@ -16,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/url_connectedness_helper"
+	common2 "github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/language"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/series"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/supplier"
@@ -45,7 +45,7 @@ func NewSupplier(_settings *settings.Settings, _logger *logrus.Logger) *Supplier
 
 	sup := Supplier{}
 	sup.log = _logger
-	sup.topic = common.DownloadSubsPerSite
+	sup.topic = common2.DownloadSubsPerSite
 
 	sup.settings = _settings
 	if sup.settings.AdvancedSettings.Topic > 0 && sup.settings.AdvancedSettings.Topic != sup.topic {
@@ -54,10 +54,10 @@ func NewSupplier(_settings *settings.Settings, _logger *logrus.Logger) *Supplier
 	sup.isAlive = true // 默认是可以使用的,如果 check 后,再调整状态
 
 	// 默认超时是 2 * 60s,如果是调试模式则是 5 min
-	sup.tt = common.HTMLTimeOut
+	sup.tt = common2.HTMLTimeOut
 	sup.debugMode = sup.settings.AdvancedSettings.DebugMode
 	if sup.debugMode == true {
-		sup.tt = common.OneMovieProcessTimeOut
+		sup.tt = common2.OneMovieProcessTimeOut
 	}
 
 	return &sup
@@ -102,7 +102,7 @@ func (s *Supplier) OverDailyDownloadLimit() bool {
 }
 
 func (s *Supplier) GetSupplierName() string {
-	return common.SubSiteSubHd
+	return common2.SubSiteSubHd
 }
 
 func (s *Supplier) GetSubListFromFile4Movie(filePath string) ([]supplier.SubInfo, error) {
@@ -347,7 +347,7 @@ func (s *Supplier) step0(browser *rod.Browser, keyword string) (string, error) {
 		}
 	}()
 
-	result, page, err := rod_helper.HttpGetFromBrowser(browser, fmt.Sprintf(s.settings.AdvancedSettings.SuppliersSettings.SubHD.RootUrl+common.SubSubHDSearchUrl, url.QueryEscape(keyword)), s.tt)
+	result, page, err := rod_helper.HttpGetFromBrowser(browser, fmt.Sprintf(s.settings.AdvancedSettings.SuppliersSettings.SubHD.RootUrl+common2.SubSubHDSearchUrl, url.QueryEscape(keyword)), s.tt)
 	if err != nil {
 		return "", err
 	}
@@ -358,7 +358,7 @@ func (s *Supplier) step0(browser *rod.Browser, keyword string) (string, error) {
 	re := regexp.MustCompile(`共\s*(\d+)\s*条`)
 	matched := re.FindAllStringSubmatch(result, -1)
 	if matched == nil || len(matched) < 1 {
-		return "", common.SubHDStep0SubCountElementNotFound
+		return "", common2.SubHDStep0SubCountElementNotFound
 	}
 	subCount, err := decode.GetNumber2int(matched[0][0])
 	if err != nil {
@@ -378,7 +378,7 @@ func (s *Supplier) step0(browser *rod.Browser, keyword string) (string, error) {
 	if ok == true {
 
 		if len(imgSelection.Nodes) < 1 {
-			return "", common.SubHDStep0ImgParentLessThan1
+			return "", common2.SubHDStep0ImgParentLessThan1
 		}
 		step1Url := ""
 		if imgSelection.Nodes[0].Parent.Data == "a" {
@@ -399,11 +399,11 @@ func (s *Supplier) step0(browser *rod.Browser, keyword string) (string, error) {
 			}
 		}
 		if step1Url == "" {
-			return "", common.SubHDStep0HrefIsNull
+			return "", common2.SubHDStep0HrefIsNull
 		}
 		return step1Url, nil
 	} else {
-		return "", common.SubHDStep0HrefIsNull
+		return "", common2.SubHDStep0HrefIsNull
 	}
 }
 
@@ -549,7 +549,7 @@ func (s *Supplier) downloadSubFile(browser *rod.Browser, page *rod.Page) (bool,
 			element.MustClick()
 			time.Sleep(time.Second * 2)
 			// 填写“验证码”
-			page.MustEval(`$("#gzhcode").attr("value","` + common.SubhdCode + `");`)
+			page.MustEval(`$("#gzhcode").attr("value","` + common2.SubhdCode + `");`)
 			// 是否有“完成验证”按钮
 			downBtn := doc.Find(btnCommitCode)
 			if len(downBtn.Nodes) < 1 {
@@ -609,7 +609,7 @@ func (s *Supplier) downloadSubFile(browser *rod.Browser, page *rod.Page) (bool,
 	hdContent.Data = fileByte
 
 	if downloadSuccess == false {
-		return false, &hdContent, common.SubHDStep2ExCannotFindDownloadBtn
+		return false, &hdContent, common2.SubHDStep2ExCannotFindDownloadBtn
 	}
 
 	// 下载成功需要统计到今天的次数中

+ 7 - 6
internal/logic/sub_supplier/subhd/subhd_test.go

@@ -2,11 +2,12 @@ package subhd
 
 import (
 	"fmt"
-	commonValue "github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/series_helper"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/something_static"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/unit_test_helper"
+	commonValue "github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"path/filepath"
 	"testing"
 	"time"
@@ -26,7 +27,7 @@ func TestSupplier_GetSubListFromFile(t *testing.T) {
 	rootDir := unit_test_helper.GetTestDataResourceRootPath([]string{"sub_spplier"}, 5, true)
 	movie1 := filepath.Join(rootDir, "zimuku", "movies", "消失爱人 (2016)", "消失爱人 (2016) 720p AAC.rmvb")
 
-	subhd := NewSupplier(*settings.NewSettings())
+	subhd := NewSupplier(settings.NewSettings(), log_helper.GetLogger())
 	outList, err := subhd.getSubListFromFile4Movie(movie1)
 	if err != nil {
 		t.Error(err)
@@ -59,11 +60,11 @@ func TestSupplier_GetSubListFromFile4Series(t *testing.T) {
 	rootDir := unit_test_helper.GetTestDataResourceRootPath([]string{"sub_spplier"}, 5, true)
 	ser := filepath.Join(rootDir, "zimuku", "series", "黄石 (2018)")
 	// 读取本地的视频和字幕信息
-	seriesInfo, err := series_helper.ReadSeriesInfoFromDir(ser, nil, false)
+	seriesInfo, err := series_helper.ReadSeriesInfoFromDir(ser, false)
 	if err != nil {
 		t.Fatal(err)
 	}
-	s := NewSupplier(*settings.NewSettings())
+	s := NewSupplier(settings.NewSettings(), log_helper.GetLogger())
 	outList, err := s.GetSubListFromFile4Series(seriesInfo)
 	if err != nil {
 		t.Fatal(err)
@@ -85,7 +86,7 @@ func TestSupplier_getSubListFromKeyword4Movie(t *testing.T) {
 	//imdbID := "tt15299712" // 云南虫谷
 	//imdbID := "tt3626476" // Vacation Friends (2021)
 	getCode()
-	subhd := NewSupplier(*settings.NewSettings())
+	subhd := NewSupplier(settings.NewSettings(), log_helper.GetLogger())
 	subInfos, err := subhd.getSubListFromKeyword4Movie(imdbID)
 	if err != nil {
 		t.Fatal(err)
@@ -99,7 +100,7 @@ func getCode() {
 
 	nowTT := time.Now()
 	nowTimeFileNamePrix := fmt.Sprintf("%d%d%d", nowTT.Year(), nowTT.Month(), nowTT.Day())
-	updateTimeString, code, err := something_static.GetCodeFromWeb(nowTimeFileNamePrix)
+	updateTimeString, code, err := something_static.GetCodeFromWeb(log_helper.GetLogger(), nowTimeFileNamePrix)
 	if err != nil {
 		commonValue.SubhdCode = ""
 	} else {

+ 4 - 4
internal/logic/sub_supplier/xunlei/xunlei.go

@@ -4,7 +4,6 @@ import (
 	"crypto/sha1"
 	"errors"
 	"fmt"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/task_queue"
 	pkgcommon "github.com/allanpk716/ChineseSubFinder/internal/pkg/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
@@ -13,6 +12,7 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/notify_center"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
+	common2 "github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/series"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/supplier"
 	"github.com/sirupsen/logrus"
@@ -33,7 +33,7 @@ func NewSupplier(_settings *settings.Settings, _logger *logrus.Logger) *Supplier
 
 	sup := Supplier{}
 	sup.log = _logger
-	sup.topic = common.DownloadSubsPerSite
+	sup.topic = common2.DownloadSubsPerSite
 	sup.isAlive = true // 默认是可以使用的,如果 check 后,再调整状态
 
 	sup.settings = _settings
@@ -75,7 +75,7 @@ func (s *Supplier) OverDailyDownloadLimit() bool {
 }
 
 func (s *Supplier) GetSupplierName() string {
-	return common.SubSiteXunLei
+	return common2.SubSiteXunLei
 }
 
 func (s *Supplier) GetSubListFromFile4Movie(filePath string) ([]supplier.SubInfo, error) {
@@ -119,7 +119,7 @@ func (s *Supplier) getSubListFromFile(filePath string) ([]supplier.SubInfo, erro
 	var tmpXunLeiSubListChinese = make([]SublistXunLei, 0)
 	var outSubList []supplier.SubInfo
 	if len(cid) == 0 {
-		return nil, common.XunLeiCIdIsEmpty
+		return nil, common2.XunLeiCIdIsEmpty
 	}
 
 	jsonList, err = s.getSubInfos(filePath, cid)

+ 11 - 11
internal/logic/sub_supplier/zimuku/zimuku.go

@@ -4,7 +4,6 @@ import (
 	"fmt"
 	"github.com/PuerkitoBio/goquery"
 	"github.com/Tnze/go.num/v2/zh"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/task_queue"
 	pkgcommon "github.com/allanpk716/ChineseSubFinder/internal/pkg/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
@@ -15,6 +14,7 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/rod_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
+	common2 "github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	language2 "github.com/allanpk716/ChineseSubFinder/internal/types/language"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/series"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/supplier"
@@ -43,7 +43,7 @@ func NewSupplier(_settings *settings.Settings, _logger *logrus.Logger) *Supplier
 
 	sup := Supplier{}
 	sup.log = _logger
-	sup.topic = common.DownloadSubsPerSite
+	sup.topic = common2.DownloadSubsPerSite
 	sup.isAlive = true // 默认是可以使用的,如果 check 后,再调整状态
 
 	sup.settings = _settings
@@ -52,10 +52,10 @@ func NewSupplier(_settings *settings.Settings, _logger *logrus.Logger) *Supplier
 	}
 
 	// 默认超时是 2 * 60s,如果是调试模式则是 5 min
-	sup.tt = common.HTMLTimeOut
+	sup.tt = common2.HTMLTimeOut
 	sup.debugMode = sup.settings.AdvancedSettings.DebugMode
 	if sup.debugMode == true {
-		sup.tt = common.OneMovieProcessTimeOut
+		sup.tt = common2.OneMovieProcessTimeOut
 	}
 	// 判断是否启用代理
 	if sup.settings.AdvancedSettings.ProxySettings.UseHttpProxy == true {
@@ -110,7 +110,7 @@ func (s *Supplier) OverDailyDownloadLimit() bool {
 }
 
 func (s *Supplier) GetSupplierName() string {
-	return common.SubSiteZiMuKu
+	return common2.SubSiteZiMuKu
 }
 
 func (s *Supplier) GetSubListFromFile4Movie(filePath string) ([]supplier.SubInfo, error) {
@@ -161,7 +161,7 @@ func (s *Supplier) GetSubListFromFile4Series(seriesInfo *series.SeriesInfo) ([]s
 		if err != nil {
 			s.log.Errorln(s.GetSupplierName(), "step 0", "0 times", "keyword:", keyword, err)
 			// 如果只是搜索不到,则继续换关键词
-			if err != common.ZiMuKuSearchKeyWordStep0DetailPageUrlNotFound {
+			if err != common2.ZiMuKuSearchKeyWordStep0DetailPageUrlNotFound {
 				s.log.Errorln(s.GetSupplierName(), "ZiMuKuSearchKeyWordStep0DetailPageUrlNotFound", keyword, err)
 				continue
 			}
@@ -439,7 +439,7 @@ func (s *Supplier) step0(browser *rod.Browser, keyword string) (string, error) {
 		}
 	}()
 
-	desUrl := fmt.Sprintf(s.settings.AdvancedSettings.SuppliersSettings.Zimuku.RootUrl+common.SubZiMuKuSearchFormatUrl, url.QueryEscape(keyword))
+	desUrl := fmt.Sprintf(s.settings.AdvancedSettings.SuppliersSettings.Zimuku.RootUrl+common2.SubZiMuKuSearchFormatUrl, url.QueryEscape(keyword))
 	result, page, err := rod_helper.HttpGetFromBrowser(browser, desUrl, s.tt)
 	if err != nil {
 		return "", err
@@ -451,7 +451,7 @@ func (s *Supplier) step0(browser *rod.Browser, keyword string) (string, error) {
 	re := regexp.MustCompile(`<p\s+class="tt\s+clearfix"><a\s+href="(/subs/[\w]+\.html)"\s+target="_blank"><b>(.*?)</b></a></p>`)
 	matched := re.FindAllStringSubmatch(result, -1)
 	if matched == nil || len(matched) < 1 {
-		return "", common.ZiMuKuSearchKeyWordStep0DetailPageUrlNotFound
+		return "", common2.ZiMuKuSearchKeyWordStep0DetailPageUrlNotFound
 	}
 	// 影片的详情界面 url
 	filmDetailPageUrl := matched[0][1]
@@ -584,7 +584,7 @@ func (s *Supplier) step2(browser *rod.Browser, subInfo *SubInfo) error {
 	matched := re.FindAllStringSubmatch(result, -1)
 	if matched == nil || len(matched) == 0 || len(matched[0]) == 0 {
 		s.log.Warnln("Step2,sub download url not found", detailUrl)
-		return common.ZiMuKuDownloadUrlStep2NotFound
+		return common2.ZiMuKuDownloadUrlStep2NotFound
 	}
 	if strings.Contains(matched[0][1], "://") {
 		subInfo.SubDownloadPageUrl = matched[0][1]
@@ -614,7 +614,7 @@ func (s *Supplier) step3(browser *rod.Browser, subDownloadPageUrl string) (strin
 	matched := re.FindAllStringSubmatch(result, -1)
 	if matched == nil || len(matched) == 0 || len(matched[0]) == 0 {
 		s.log.Debugln("Step3,sub download url not found", subDownloadPageUrl)
-		return "", nil, common.ZiMuKuDownloadUrlStep3NotFound
+		return "", nil, common2.ZiMuKuDownloadUrlStep3NotFound
 	}
 
 	fileName := ""
@@ -661,7 +661,7 @@ func (s *Supplier) step3(browser *rod.Browser, subDownloadPageUrl string) (strin
 		return fileName, fileByte, nil
 	} else {
 		s.log.Debugln("Step3,sub download url not found", subDownloadPageUrl)
-		return "", nil, common.ZiMuKuDownloadUrlStep3AllFailed
+		return "", nil, common2.ZiMuKuDownloadUrlStep3AllFailed
 	}
 }
 

+ 4 - 4
internal/logic/sub_supplier/zimuku/zimuku_test.go

@@ -12,7 +12,7 @@ import (
 
 func TestSupplier_GetSubListFromKeyword(t *testing.T) {
 
-	browser, err := rod_helper.NewBrowser("", true, settings.NewSettings().SuppliersSettings.Zimuku.RootUrl)
+	browser, err := rod_helper.NewBrowser("", true, settings.NewSettings().AdvancedSettings.SuppliersSettings.Zimuku.RootUrl)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -35,7 +35,7 @@ func TestSupplier_GetSubListFromKeyword(t *testing.T) {
 
 func TestSupplier_GetSubListFromFile(t *testing.T) {
 
-	browser, err := rod_helper.NewBrowser("", true, settings.NewSettings().SuppliersSettings.Zimuku.RootUrl)
+	browser, err := rod_helper.NewBrowser("", true, settings.NewSettings().AdvancedSettings.SuppliersSettings.Zimuku.RootUrl)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -73,7 +73,7 @@ func TestSupplier_GetSubListFromFile4Series(t *testing.T) {
 	rootDir := unit_test_helper.GetTestDataResourceRootPath([]string{"sub_spplier"}, 5, true)
 	ser := filepath.Join(rootDir, "zimuku", "series", "黄石 (2018)")
 	// 读取本地的视频和字幕信息
-	seriesInfo, err := series_helper.ReadSeriesInfoFromDir(ser, nil, false)
+	seriesInfo, err := series_helper.ReadSeriesInfoFromDir(ser, false)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -97,7 +97,7 @@ func TestSupplier_GetSubListFromFile4Series(t *testing.T) {
 
 func TestSupplier_getSubListFromKeyword(t *testing.T) {
 
-	browser, err := rod_helper.NewBrowser("", true, settings.NewSettings().SuppliersSettings.Zimuku.RootUrl)
+	browser, err := rod_helper.NewBrowser("", true, settings.NewSettings().AdvancedSettings.SuppliersSettings.Zimuku.RootUrl)
 	if err != nil {
 		t.Fatal(err)
 	}

+ 3 - 0
internal/logic/task_queue/bucket_name.go

@@ -27,4 +27,7 @@ const (
 
 	// 今日有那些视频进行了字幕的下载
 	BucketNamePrefixDailyVideoDownloadCounter = "DailyVideoDownloadCounter"
+
+	// 单机缓存的视频下载队列
+	BucketNamePrefixVideoSubDownloadQueue = "VideoSubDownloadQueue"
 )

+ 314 - 0
internal/logic/task_queue/task_queue.go

@@ -0,0 +1,314 @@
+package task_queue
+
+import (
+	"encoding/json"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/task_queue"
+	"github.com/dgraph-io/badger/v3"
+	dll "github.com/emirpasic/gods/lists/doublylinkedlist"
+	"github.com/sirupsen/logrus"
+	"sync"
+)
+
+type TaskQueue struct {
+	queueName      string
+	settings       *settings.Settings
+	log            *logrus.Logger
+	doubleList     *dll.List
+	doubleListLock sync.Mutex
+	lockList       bool
+	lockListLock   sync.Mutex
+}
+
+func NewTaskQueue(queueName string, settings *settings.Settings, log *logrus.Logger) *TaskQueue {
+
+	tq := &TaskQueue{queueName: queueName, settings: settings, log: log, doubleList: dll.New()}
+	tq.read()
+	return tq
+}
+
+func (t *TaskQueue) QueueName() string {
+	return t.queueName
+}
+
+func (t *TaskQueue) Clear() error {
+
+	defer t.doubleListLock.Unlock()
+	t.doubleListLock.Lock()
+
+	t.doubleList.Clear()
+
+	err := GetDb().Update(
+		func(tx *badger.Txn) error {
+			var err error
+			key := []byte(MergeBucketAndKeyName(BucketNamePrefixVideoSubDownloadQueue, t.queueName))
+			// 因为已经查询了一次,确保一定存在,所以直接更新+1,TTL 多加 5s 确保今天过去,暂时去除 TTL uint32(restOfDaySecond.Seconds())+5
+			if err = tx.Delete(key); err != nil {
+				return err
+			}
+			return nil
+		})
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// isEmpty 这个没有锁,所以需要在 Sync 中使用,不对外开放
+func (t *TaskQueue) isEmpty() bool {
+
+	if t.doubleList.Size() > 0 {
+		return false
+	}
+
+	return true
+}
+
+// IsEmpty 是否队列为空,对外暴露,有锁
+func (t *TaskQueue) IsEmpty() bool {
+	defer t.doubleListLock.Unlock()
+	t.doubleListLock.Lock()
+
+	return t.isEmpty()
+}
+
+func (t *TaskQueue) Size() int {
+	defer t.doubleListLock.Unlock()
+	t.doubleListLock.Lock()
+
+	return t.doubleList.Size()
+}
+
+func (t *TaskQueue) read() {
+
+	err := GetDb().View(
+		func(tx *badger.Txn) error {
+			var err error
+
+			key := []byte(MergeBucketAndKeyName(BucketNamePrefixVideoSubDownloadQueue, t.queueName))
+			e, err := tx.Get(key)
+			if err != nil {
+
+				if IsErrOk(err) == true {
+					return nil
+				}
+
+				return err
+			}
+			valCopy, err := e.ValueCopy(nil)
+			if err != nil {
+				return err
+			}
+			err = json.Unmarshal(valCopy, t.doubleList)
+			if err != nil {
+				return err
+			}
+
+			return nil
+		})
+	if err != nil {
+		t.log.Panicln(err)
+	}
+}
+
+// save 需要把改变的数据保持到 K/V 数据库中,这个没有锁,所以需要在 Sync 中使用,不对外开放
+func (t *TaskQueue) save() error {
+
+	err := GetDb().Update(
+		func(tx *badger.Txn) error {
+			var err error
+			key := []byte(MergeBucketAndKeyName(BucketNamePrefixVideoSubDownloadQueue, t.queueName))
+			if err != nil {
+				return err
+			}
+			b, err := json.Marshal(t.doubleList)
+			if err != nil {
+				return err
+			}
+			e := badger.NewEntry(key, b)
+			err = tx.SetEntry(e)
+			if err != nil {
+				return err
+			}
+			return nil
+		})
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// RPush 向右边放入元素
+func (t *TaskQueue) RPush(oneJob task_queue.OneJob) (bool, error) {
+
+	if t.isLockList() == true {
+		return false, nil
+	}
+
+	defer t.doubleListLock.Unlock()
+	t.doubleListLock.Lock()
+
+	t.doubleList.Add(oneJob)
+
+	err := t.save()
+	if err != nil {
+		return false, err
+	}
+
+	return true, nil
+}
+
+// LPush 向左边放入元素
+func (t *TaskQueue) LPush(oneJob task_queue.OneJob) (bool, error) {
+
+	if t.isLockList() == true {
+		return false, nil
+	}
+
+	defer t.doubleListLock.Unlock()
+	t.doubleListLock.Lock()
+
+	t.doubleList.Add(0, oneJob)
+
+	err := t.save()
+	if err != nil {
+		return false, err
+	}
+
+	return true, nil
+}
+
+// RPop 从右边取出第一个元素,并移除
+func (t *TaskQueue) RPop() (bool, task_queue.OneJob, error) {
+
+	if t.isLockList() == true {
+		return false, task_queue.OneJob{}, nil
+	}
+
+	defer t.doubleListLock.Unlock()
+	t.doubleListLock.Lock()
+
+	// 如果队列里面没有东西,则返回 false
+	if t.isEmpty() == true {
+		return false, task_queue.OneJob{}, nil
+	}
+
+	rightLastOneIndex := t.doubleList.Size() - 1
+	value, bok := t.doubleList.Get(rightLastOneIndex)
+	if bok == false {
+		return false, task_queue.OneJob{}, nil
+	}
+	// 移除最后一个元素
+	t.doubleList.Remove(rightLastOneIndex)
+
+	err := t.save()
+	if err != nil {
+		return false, task_queue.OneJob{}, err
+	}
+
+	return true, value.(task_queue.OneJob), nil
+}
+
+// RPeek 获取右边取出第一个元素,不移除
+func (t *TaskQueue) RPeek() (bool, task_queue.OneJob) {
+
+	defer t.doubleListLock.Unlock()
+	t.doubleListLock.Lock()
+
+	// 如果队列里面没有东西,则返回 false
+	if t.isEmpty() == true {
+		return false, task_queue.OneJob{}
+	}
+
+	rightLastOneIndex := t.doubleList.Size() - 1
+	value, bok := t.doubleList.Get(rightLastOneIndex)
+	if bok == false {
+		return false, task_queue.OneJob{}
+	}
+
+	return true, value.(task_queue.OneJob)
+}
+
+// LPop 向左边取出第一个元素,并移除
+func (t *TaskQueue) LPop() (bool, task_queue.OneJob, error) {
+
+	if t.isLockList() == true {
+		return false, task_queue.OneJob{}, nil
+	}
+
+	defer t.doubleListLock.Unlock()
+	t.doubleListLock.Lock()
+
+	// 如果队列里面没有东西,则返回 false
+	if t.isEmpty() == true {
+		return false, task_queue.OneJob{}, nil
+	}
+
+	leftFistOneIndex := 0
+	value, bok := t.doubleList.Get(leftFistOneIndex)
+	if bok == false {
+		return false, task_queue.OneJob{}, nil
+	}
+	// 移除左边第一个元素
+	t.doubleList.Remove(leftFistOneIndex)
+
+	err := t.save()
+	if err != nil {
+		return false, task_queue.OneJob{}, err
+	}
+
+	return true, value.(task_queue.OneJob), nil
+}
+
+// LPeek 向左边获取第一个元素,不移除
+func (t *TaskQueue) LPeek() (bool, task_queue.OneJob) {
+
+	defer t.doubleListLock.Unlock()
+	t.doubleListLock.Lock()
+
+	// 如果队列里面没有东西,则返回 false
+	if t.isEmpty() == true {
+		return false, task_queue.OneJob{}
+	}
+
+	leftFistOneIndex := 0
+	value, bok := t.doubleList.Get(leftFistOneIndex)
+	if bok == false {
+		return false, task_queue.OneJob{}
+	}
+
+	return true, value.(task_queue.OneJob)
+}
+
+// LockList 锁住 List,这样才能够正确的进行遍历
+func (t *TaskQueue) LockList() {
+	defer t.lockListLock.Unlock()
+	t.lockListLock.Lock()
+
+	t.lockList = true
+}
+
+// UnLockList 解锁 List,就可以正常的 Push 和 Pop
+func (t *TaskQueue) UnLockList() {
+	defer t.lockListLock.Unlock()
+	t.lockListLock.Lock()
+
+	t.lockList = false
+}
+
+func (t *TaskQueue) isLockList() bool {
+
+	bLock := false
+	t.lockListLock.Lock()
+	bLock = t.lockList
+	t.lockListLock.Unlock()
+
+	return bLock
+}
+
+// GetList 使用的时候不要插入数据,否则会有问题
+func (t *TaskQueue) GetList() dll.Iterator {
+	return t.doubleList.Iterator()
+}

+ 8 - 8
internal/pkg/decode/decode.go

@@ -2,9 +2,9 @@ package decode
 
 import (
 	"errors"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/types"
+	common2 "github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/beevik/etree"
 	PTN "github.com/middelink/go-parse-torrent-name"
 	"os"
@@ -34,7 +34,7 @@ func getImdbAndYearMovieXml(movieFilePath string) (types.VideoIMDBInfo, error) {
 	if videoInfo.ImdbId != "" {
 		return videoInfo, nil
 	}
-	return videoInfo, common.CanNotFindIMDBID
+	return videoInfo, common2.CanNotFindIMDBID
 }
 
 func getImdbAndYearNfo(nfoFilePath string, rootKey string) (types.VideoIMDBInfo, error) {
@@ -91,7 +91,7 @@ func getImdbAndYearNfo(nfoFilePath string, rootKey string) (types.VideoIMDBInfo,
 	if imdbInfo.ImdbId != "" {
 		return imdbInfo, nil
 	}
-	return imdbInfo, common.CanNotFindIMDBID
+	return imdbInfo, common2.CanNotFindIMDBID
 }
 
 // GetImdbInfo4Movie 从电影视频文件获取 IMDB info
@@ -135,7 +135,7 @@ func GetImdbInfo4Movie(movieFileFullPath string) (types.VideoIMDBInfo, error) {
 	}
 	// 根据找到的开始解析
 	if movieNameNfoFPath == "" && movieXmlFPath == "" && nfoFilePath == "" {
-		return imdbInfo, common.NoMetadataFile
+		return imdbInfo, common2.NoMetadataFile
 	}
 	// 优先分析 movieName.nfo 文件
 	if movieNameNfoFPath != "" {
@@ -163,7 +163,7 @@ func GetImdbInfo4Movie(movieFileFullPath string) (types.VideoIMDBInfo, error) {
 		}
 	}
 
-	return imdbInfo, common.CanNotFindIMDBID
+	return imdbInfo, common2.CanNotFindIMDBID
 }
 
 // GetImdbInfo4SeriesDir 从一个连续剧的根目录获取 IMDB info
@@ -193,7 +193,7 @@ func GetImdbInfo4SeriesDir(seriesDir string) (types.VideoIMDBInfo, error) {
 	}
 	// 根据找到的开始解析
 	if nfoFilePath == "" {
-		return imdbInfo, common.NoMetadataFile
+		return imdbInfo, common2.NoMetadataFile
 	}
 	imdbInfo, err = getImdbAndYearNfo(nfoFilePath, "tvshow")
 	if err != nil {
@@ -272,7 +272,7 @@ func GetImdbInfo4OneSeriesEpisode(oneEpFPath string) (types.VideoIMDBInfo, error
 	if imdbInfo.ReleaseDate != "" {
 		return imdbInfo, nil
 	}
-	return imdbInfo, common.CanNotFindEpAiredTime
+	return imdbInfo, common2.CanNotFindEpAiredTime
 }
 
 // GetVideoInfoFromFileName 从文件名推断文件信息
@@ -433,7 +433,7 @@ func IsFakeBDMVWorked(fakseVideFPath string) (bool, string) {
 
 	CERDir := filepath.Join(rootDir, "CERTIFICATE")
 	BDMVDir := filepath.Join(rootDir, "BDMV")
-	idBDMVFPath := filepath.Join(CERDir, common.FileBDMV)
+	idBDMVFPath := filepath.Join(CERDir, common2.FileBDMV)
 
 	if IsDir(CERDir) == true && IsDir(BDMVDir) == true && IsFile(idBDMVFPath) == true {
 		return true, idBDMVFPath

+ 177 - 127
internal/pkg/downloader/downloader.go

@@ -3,7 +3,6 @@ package downloader
 import (
 	"errors"
 	"fmt"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/ifaces"
 	embyHelper "github.com/allanpk716/ChineseSubFinder/internal/logic/emby_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/forced_scan_and_down_sub"
@@ -12,6 +11,7 @@ import (
 	seriesHelper "github.com/allanpk716/ChineseSubFinder/internal/logic/series_helper"
 	subSupplier "github.com/allanpk716/ChineseSubFinder/internal/logic/sub_supplier"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_timeline_fixer"
+	"github.com/allanpk716/ChineseSubFinder/internal/logic/task_queue"
 	pkgcommon "github.com/allanpk716/ChineseSubFinder/internal/pkg/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_folder"
@@ -21,8 +21,10 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
 	subTimelineFixerPKG "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_timeline_fixer"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/task_control"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/emby"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/series"
+	TTaskqueue "github.com/allanpk716/ChineseSubFinder/internal/types/task_queue"
 	"github.com/emirpasic/gods/maps/treemap"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/net/context"
@@ -32,33 +34,28 @@ import (
 
 // Downloader 实例化一次用一次,不要反复的使用,很多临时标志位需要清理。
 type Downloader struct {
-	settings settings.Settings
-	log      *logrus.Logger
-
-	subSupplierHub *subSupplier.SubSupplierHub
-
-	mk                       *markSystem.MarkingSystem // MarkingSystem
-	embyHelper               *embyHelper.EmbyHelper
-	movieFileFullPathList    []string                      //  多个需要搜索字幕的电影文件全路径
-	seriesSubNeedDlMap       map[string][]emby.EmbyMixInfo //  多个需要搜索字幕的连续剧目录,连续剧文件夹名称 -- 每一集的 EmbyMixInfo List
-	subFormatter             ifaces.ISubFormatter          //	字幕格式化命名的实现
-	subNameFormatter         subCommon.FormatterName       // 从 inSubFormatter 推断出来
-	needForcedScanAndDownSub bool                          // 将会强制扫描所有的视频,下载字幕,替换已经存在的字幕,不进行时间段和已存在则跳过的判断。且不会进过 Emby API 的逻辑,智能进行强制去以本程序的方式去扫描。
-	NeedRestoreFixTimeLineBK bool                          // 从 csf-bk 文件还原时间轴修复前的字幕文件
-
+	settings                 *settings.Settings
+	log                      *logrus.Logger
+	subSupplierHub           *subSupplier.SubSupplierHub                  // 字幕提供源的集合
+	mk                       *markSystem.MarkingSystem                    // MarkingSystem,字幕的评价系统
+	embyHelper               *embyHelper.EmbyHelper                       // Emby 的实例
+	subFormatter             ifaces.ISubFormatter                         //	字幕格式化命名的实现
+	subNameFormatter         subCommon.FormatterName                      // 从 inSubFormatter 推断出来
+	needForcedScanAndDownSub bool                                         // 将会强制扫描所有的视频,下载字幕,替换已经存在的字幕,不进行时间段和已存在则跳过的判断。且不会进过 Emby API 的逻辑,智能进行强制去以本程序的方式去扫描。
+	NeedRestoreFixTimeLineBK bool                                         // 从 csf-bk 文件还原时间轴修复前的字幕文件
 	subTimelineFixerHelperEx *sub_timeline_fixer.SubTimelineFixerHelperEx // 字幕时间轴校正
-
-	taskControl  *task_control.TaskControl
-	canceled     bool
-	canceledLock sync.Mutex
+	taskControl              *task_control.TaskControl                    // 具体下载字幕的任务控制
+	canceled                 bool                                         // 取消执行 task control
+	canceledLock             sync.Mutex                                   // 取消执行 task control 的 Lock
+	downloadQueue            *task_queue.TaskQueue                        // 需要下载的视频的队列
 }
 
-func NewDownloader(_supplierHub *subSupplier.SubSupplierHub, inSubFormatter ifaces.ISubFormatter, _settings settings.Settings) (*Downloader, error) {
+func NewDownloader(_supplierHub *subSupplier.SubSupplierHub, inSubFormatter ifaces.ISubFormatter, _settings *settings.Settings, log *logrus.Logger) (*Downloader, error) {
 
 	var downloader Downloader
 	var err error
 	downloader.subFormatter = inSubFormatter
-	downloader.log = log_helper.GetLogger()
+	downloader.log = log
 	// 参入设置信息
 	downloader.settings = _settings
 	// 检测是否某些参数超出范围
@@ -80,9 +77,6 @@ func NewDownloader(_supplierHub *subSupplier.SubSupplierHub, inSubFormatter ifac
 	sitesSequence = append(sitesSequence, common.SubSiteXunLei)
 	downloader.mk = markSystem.NewMarkingSystem(sitesSequence, downloader.settings.AdvancedSettings.SubTypePriority)
 
-	downloader.movieFileFullPathList = make([]string, 0)
-	downloader.seriesSubNeedDlMap = make(map[string][]emby.EmbyMixInfo)
-
 	// 初始化,字幕校正的实例
 	downloader.subTimelineFixerHelperEx = sub_timeline_fixer.NewSubTimelineFixerHelperEx(*downloader.settings.TimelineFixerSettings)
 
@@ -94,6 +88,8 @@ func NewDownloader(_supplierHub *subSupplier.SubSupplierHub, inSubFormatter ifac
 	if err != nil {
 		return nil, err
 	}
+	// 需要下载的视频的队列
+	downloader.downloadQueue = task_queue.NewTaskQueue("NormalDownloadQueue", _settings, downloader.log)
 
 	return &downloader, nil
 }
@@ -119,10 +115,116 @@ func (d *Downloader) ReadSpeFile() error {
 	return nil
 }
 
+// ScanMovieAndSeriesWait2DownloadSub 扫描出有那些电影、连续剧需要进行字幕下载的
+func (d *Downloader) ScanMovieAndSeriesWait2DownloadSub() (*ScanVideoResult, error) {
+
+	var err error
+	// -----------------------------------------------------
+	// 优先判断特殊的操作
+	if d.needForcedScanAndDownSub == true || d.embyHelper == nil {
+
+		normalScanResult := NormalScanVideoResult{}
+		// 直接由本程序自己去扫描视频视频有哪些
+		// 全扫描
+		if d.needForcedScanAndDownSub == true {
+			d.log.Infoln("Forced Scan And DownSub")
+		}
+		// --------------------------------------------------
+		// 电影
+		// 没有填写 emby_helper api 的信息,那么就走常规的全文件扫描流程
+		normalScanResult.MovieFileFullPathList, err = my_util.SearchMatchedVideoFileFromDirs(d.log, d.settings.CommonSettings.MoviePaths)
+		if err != nil {
+			return nil, err
+		}
+		// --------------------------------------------------
+		// 连续剧
+		// 遍历连续剧总目录下的第一层目录
+		normalScanResult.SeriesDirMap, err = seriesHelper.GetSeriesListFromDirs(d.settings.CommonSettings.SeriesPaths)
+		if err != nil {
+			return nil, err
+		}
+		// ------------------------------------------------------------------------------
+		// 输出调试信息,有那些连续剧文件夹名称
+		normalScanResult.SeriesDirMap.Each(func(key interface{}, value interface{}) {
+			for i, s := range value.([]string) {
+				d.log.Debugln("embyHelper == nil GetSeriesList", i, s)
+			}
+		})
+		// ------------------------------------------------------------------------------
+		return &ScanVideoResult{Normal: &normalScanResult}, nil
+	} else {
+		// TODO 如果后续支持了 Jellyfin、Plex 那么这里需要额外正在对应的扫描逻辑
+		// 进过 emby_helper api 的信息读取
+		embyScanResult := EmbyScanVideoResult{}
+		d.log.Infoln("Movie Sub Dl From Emby API...")
+		// Emby 情况,从 Emby 获取视频信息
+		err = d.RefreshEmbySubList()
+		if err != nil {
+			d.log.Errorln("RefreshEmbySubList", err)
+			return nil, err
+		}
+		// ------------------------------------------------------------------------------
+		// 有哪些更新的视频列表,包含电影、连续剧
+		embyScanResult.MovieSubNeedDlEmbyMixInfoList, embyScanResult.SeriesSubNeedDlEmbyMixInfoMap, err = d.GetUpdateVideoListFromEmby()
+		if err != nil {
+			d.log.Errorln("GetUpdateVideoListFromEmby", err)
+			return nil, err
+		}
+		// ------------------------------------------------------------------------------
+		return &ScanVideoResult{Emby: &embyScanResult}, nil
+	}
+}
+
+// FilterMovieAndSeriesNeedDownload 过滤出需要下载字幕的视频,比如是否跳过中文的剧集,是否超过3个月的下载时间,丢入队列中
+func (d *Downloader) FilterMovieAndSeriesNeedDownload(scanVideoResult *ScanVideoResult) error {
+
+	// ----------------------------------------
+	// 过滤,电影
+	// ----------------------------------------
+	// 放入队列
+	// ----------------------------------------
+	// Normal
+	for _, oneMovieFPath := range scanVideoResult.Normal.MovieFileFullPathList {
+
+		if d.subSupplierHub.MovieNeedDlSub(oneMovieFPath, true, d.needForcedScanAndDownSub) == false {
+			continue
+		}
+		_, err := d.downloadQueue.RPush(*TTaskqueue.NewOneJob(
+			common.Movie, oneMovieFPath, 5,
+		))
+		if err != nil {
+			return err
+		}
+	}
+	// Emby
+
+	// ----------------------------------------
+	// 过滤,连续剧
+	// seriesDirMap: dir <--> seriesList
+	scanVideoResult.Normal.SeriesDirMap.Each(func(seriesRootPathName interface{}, seriesNames interface{}) {
+
+		for _, oneSeriesRootDir := range seriesNames.([]string) {
+
+			// 因为可能回去 Web 获取 IMDB 信息,所以这里的错误不返回
+			bNeedDlSub, seriesInfo, err := d.subSupplierHub.SeriesNeedDlSub(oneSeriesRootDir, true, d.needForcedScanAndDownSub)
+			if err != nil {
+				d.log.Errorln("FilterMovieAndSeriesNeedDownload.SeriesNeedDlSub", err)
+				continue
+			}
+			if bNeedDlSub == false {
+				continue
+			}
+			//RootDirPath:   seriesRootPathName.(string),
+			//OneSeriesPath: oneSeriesRootDir,
+		}
+	})
+
+}
+
 // GetUpdateVideoListFromEmby 这里首先会进行近期影片的获取,然后对这些影片进行刷新,然后在获取字幕列表,最终得到需要字幕获取的 video 列表
-func (d *Downloader) GetUpdateVideoListFromEmby() error {
+func (d *Downloader) GetUpdateVideoListFromEmby() ([]emby.EmbyMixInfo, map[string][]emby.EmbyMixInfo, error) {
 	if d.embyHelper == nil {
-		return nil
+		return nil, nil, nil
 	}
 	defer func() {
 		d.log.Infoln("GetUpdateVideoListFromEmby End")
@@ -136,32 +238,29 @@ func (d *Downloader) GetUpdateVideoListFromEmby() error {
 	d.canceledLock.Unlock()
 	if nowCancel == true {
 		d.log.Infoln("GetUpdateVideoListFromEmby Canceled")
-		return nil
+		return nil, nil, nil
 	}
 	var err error
 	var movieList []emby.EmbyMixInfo
-	movieList, d.seriesSubNeedDlMap, err = d.embyHelper.GetRecentlyAddVideoListWithNoChineseSubtitle()
+	var seriesSubNeedDlMap map[string][]emby.EmbyMixInfo //  多个需要搜索字幕的连续剧目录,连续剧文件夹名称 -- 每一集的 EmbyMixInfo List
+	movieList, seriesSubNeedDlMap, err = d.embyHelper.GetRecentlyAddVideoListWithNoChineseSubtitle()
 	if err != nil {
-		return err
+		return nil, nil, err
 	}
-	// 获取全路径
+	// 输出调试信息
+	d.log.Debugln("GetUpdateVideoListFromEmby - DebugInfo - movieFileFullPathList Start")
 	for _, info := range movieList {
-		d.movieFileFullPathList = append(d.movieFileFullPathList, info.PhysicalVideoFileFullPath)
+		d.log.Debugln(info.PhysicalVideoFileFullPath)
 	}
-	// 输出调试信息
+	d.log.Debugln("GetUpdateVideoListFromEmby - DebugInfo - movieFileFullPathList End")
+
 	d.log.Debugln("GetUpdateVideoListFromEmby - DebugInfo - seriesSubNeedDlMap Start")
-	for s := range d.seriesSubNeedDlMap {
+	for s := range seriesSubNeedDlMap {
 		d.log.Debugln(s)
 	}
 	d.log.Debugln("GetUpdateVideoListFromEmby - DebugInfo - seriesSubNeedDlMap End")
 
-	d.log.Debugln("GetUpdateVideoListFromEmby - DebugInfo - movieFileFullPathList Start")
-	for s, value := range d.movieFileFullPathList {
-		d.log.Debugln(s, value)
-	}
-	d.log.Debugln("GetUpdateVideoListFromEmby - DebugInfo - movieFileFullPathList End")
-
-	return nil
+	return movieList, seriesSubNeedDlMap, nil
 }
 
 func (d *Downloader) RefreshEmbySubList() error {
@@ -221,35 +320,11 @@ func (d *Downloader) DownloadSub4Movie() error {
 		return nil
 	}
 	// -----------------------------------------------------
-	// 优先判断特殊的操作
-	if d.needForcedScanAndDownSub == true {
-		// 全扫描
-		d.movieFileFullPathList, err = my_util.SearchMatchedVideoFileFromDirs(d.log, d.settings.CommonSettings.MoviePaths)
-		if err != nil {
-			return err
-		}
-	} else {
-		// 是否是通过 emby_helper api 获取的列表
-		if d.embyHelper == nil {
-			// 没有填写 emby_helper api 的信息,那么就走常规的全文件扫描流程
-			d.movieFileFullPathList, err = my_util.SearchMatchedVideoFileFromDirs(d.log, d.settings.CommonSettings.MoviePaths)
-			if err != nil {
-				return err
-			}
-		} else {
-			// 进过 emby_helper api 的信息读取
-			d.log.Infoln("Movie Sub Dl From Emby API...")
-			if len(d.movieFileFullPathList) < 1 {
-				d.log.Infoln("Movie Sub Dl From Emby API no movie need Dl sub")
-				return nil
-			}
-		}
-	}
-	// -----------------------------------------------------
 	// 并发控制,设置为 movie 的处理函数
 	d.taskControl.SetCtxProcessFunc("MoviePool", d.movieDlFunc, common.OneMovieProcessTimeOut)
 	// -----------------------------------------------------
 	// 一个视频文件同时多个站点查询,阻塞完毕后,在进行下一个
+	// 需要从队列里面取出来 downloadQueue
 	for i, oneVideoFullPath := range d.movieFileFullPathList {
 
 		err = d.taskControl.Invoke(&task_control.TaskData{
@@ -318,44 +393,7 @@ func (d *Downloader) DownloadSub4Series() error {
 	// -----------------------------------------------------
 	// 是否是通过 emby_helper api 获取的列表
 	// x://连续剧 -- 连续剧A、连续剧B、连续剧C 的名称列表
-	var seriesDirMap = treemap.NewWithStringComparator()
-	if d.embyHelper == nil {
-		// 不使用 Emby 的情况
-		// 遍历连续剧总目录下的第一层目录
-		seriesDirMap, err = seriesHelper.GetSeriesListFromDirs(d.settings.CommonSettings.SeriesPaths)
-		if err != nil {
-			return err
-		}
-
-		// 输出调试信息,有那些连续剧文件夹名称
-		seriesDirMap.Each(func(key interface{}, value interface{}) {
-
-			for i, s := range value.([]string) {
-				d.log.Debugln("embyHelper == nil GetSeriesList", i, s)
-			}
-		})
-	} else {
-		// 使用 Emby 的情况
-		// 这里给出的是连续剧的文件夹名称
-		d.log.Debugln("embyHelper seriesSubNeedDlMap Count:", len(d.seriesSubNeedDlMap))
-		for seriesFolderName, mixInfos := range d.seriesSubNeedDlMap {
-
-			if len(mixInfos) < 1 {
-				continue
-			}
-			nowPhRootPath := mixInfos[0].PhysicalRootPath
-			value, found := seriesDirMap.Get(nowPhRootPath)
-			if found == false {
-				seriesDirMap.Put(nowPhRootPath, []string{seriesFolderName})
-			} else {
-				value = append(value.([]string), seriesFolderName)
-				seriesDirMap.Put(nowPhRootPath, value)
-			}
-
-			d.log.Debugln("embyHelper seriesSubNeedDlMap:", seriesFolderName)
-		}
-	}
-
+	// 需要从队列里面取出来 downloadQueue
 	seriesCount := 0
 	seriesIndexNameMap := make(map[int]string)
 	seriesDirMap.Each(func(seriesRootPathName interface{}, seriesNames interface{}) {
@@ -440,7 +478,7 @@ func (d *Downloader) movieDlFunc(ctx context.Context, inData interface{}) error
 	pkgcommon.SetSubScanJobStatusScanMovie(taskData.Index+1, taskData.Count, filepath.Base(downloadInputData.OneVideoFullPath))
 	// -----------------------------------------------------
 	// 字幕都下载缓存好了,需要抉择存哪一个,优先选择中文双语的,然后到中文
-	organizeSubFiles, err := d.subSupplierHub.DownloadSub4Movie(downloadInputData.OneVideoFullPath, taskData.Index, d.needForcedScanAndDownSub)
+	organizeSubFiles, err := d.subSupplierHub.DownloadSub4Movie(downloadInputData.OneVideoFullPath, taskData.Index)
 	if err != nil {
 		d.log.Errorln("subSupplierHub.DownloadSub4Movie", downloadInputData.OneVideoFullPath, err)
 		return err
@@ -466,38 +504,28 @@ func (d *Downloader) seriesDlFunc(ctx context.Context, inData interface{}) error
 	taskData := inData.(*task_control.TaskData)
 	downloadInputData := taskData.DataEx.(DownloadInputData)
 	// 这里拿到了这一部连续剧的所有的剧集信息,以及所有下载到的字幕信息
-	var seriesInfo *series.SeriesInfo
+	// 下载好的字幕文件
 	var organizeSubFiles map[string][]string
-
 	// 设置任务的状态
 	pkgcommon.SetSubScanJobStatusScanSeriesMain(taskData.Index+1, taskData.Count, downloadInputData.OneSeriesPath)
 
-	// 优先判断特殊的操作
-	if d.needForcedScanAndDownSub == true {
-		// 全盘扫描
-		seriesInfo, organizeSubFiles, err = d.subSupplierHub.DownloadSub4Series(downloadInputData.OneSeriesPath, taskData.Index, d.needForcedScanAndDownSub)
+	if d.needForcedScanAndDownSub == true || d.embyHelper == nil {
+		organizeSubFiles, err = d.subSupplierHub.DownloadSub4Series(downloadInputData.OneSeriesPath,
+			downloadInputData.SeriesInfo,
+			taskData.Index)
 		if err != nil {
 			d.log.Errorln("subSupplierHub.DownloadSub4Series", downloadInputData.OneSeriesPath, err)
 			return err
 		}
 	} else {
-		// 是否是通过 emby_helper api 获取的列表
-		if d.embyHelper == nil {
-			// 不适用 emby api
-			seriesInfo, organizeSubFiles, err = d.subSupplierHub.DownloadSub4Series(downloadInputData.OneSeriesPath, taskData.Index, d.needForcedScanAndDownSub)
-			if err != nil {
-				d.log.Errorln("subSupplierHub.DownloadSub4Series", downloadInputData.OneSeriesPath, err)
-				return err
-			}
-		} else {
-			// 先进行 emby_helper api 的操作,读取需要更新字幕的项目
-			seriesInfo, organizeSubFiles, err = d.subSupplierHub.DownloadSub4SeriesFromEmby(
-				filepath.Join(downloadInputData.RootDirPath, downloadInputData.OneSeriesPath),
-				d.seriesSubNeedDlMap[downloadInputData.OneSeriesPath], taskData.Index)
-			if err != nil {
-				d.log.Errorln("subSupplierHub.DownloadSub4Series", downloadInputData.OneSeriesPath, err)
-				return err
-			}
+		// 先进行 emby_helper api 的操作
+		organizeSubFiles, err = d.subSupplierHub.DownloadSub4SeriesFromEmby(
+			filepath.Join(downloadInputData.RootDirPath, downloadInputData.OneSeriesPath),
+			seriesSubNeedDlMap[downloadInputData.OneSeriesPath],
+			taskData.Index)
+		if err != nil {
+			d.log.Errorln("subSupplierHub.DownloadSub4Series", downloadInputData.OneSeriesPath, err)
+			return err
 		}
 	}
 	if organizeSubFiles == nil || len(organizeSubFiles) < 1 {
@@ -566,3 +594,25 @@ func (d *Downloader) seriesDlFunc(ctx context.Context, inData interface{}) error
 
 	return nil
 }
+
+type DownloadInputData struct {
+	OneVideoFullPath string
+	OneSeriesPath    string
+	RootDirPath      string
+	SeriesInfo       *series.SeriesInfo
+}
+
+type ScanVideoResult struct {
+	Normal *NormalScanVideoResult
+	Emby   *EmbyScanVideoResult
+}
+
+type NormalScanVideoResult struct {
+	MovieFileFullPathList []string
+	SeriesDirMap          *treemap.Map
+}
+
+type EmbyScanVideoResult struct {
+	MovieSubNeedDlEmbyMixInfoList []emby.EmbyMixInfo
+	SeriesSubNeedDlEmbyMixInfoMap map[string][]emby.EmbyMixInfo
+}

+ 0 - 6
internal/pkg/downloader/downloader_things.go

@@ -229,9 +229,3 @@ func (d *Downloader) writeSubFile2VideoPath(videoFileFullPath string, finalSubFi
 
 	return nil
 }
-
-type DownloadInputData struct {
-	OneVideoFullPath string
-	OneSeriesPath    string
-	RootDirPath      string
-}

+ 1 - 1
internal/pkg/ffmpeg_helper/ffmpeg_helper.go

@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"errors"
 	"fmt"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/ass"
 	"github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/srt"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/language"
@@ -12,6 +11,7 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_folder"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/tidwall/gjson"
 	"os"
 	"os/exec"

+ 1 - 1
internal/pkg/ffmpeg_helper/ffmpeg_info.go

@@ -1,12 +1,12 @@
 package ffmpeg_helper
 
 import (
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"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/sub_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/subparser"
 	"os"
 	"path/filepath"

+ 7 - 12
internal/pkg/imdb_helper/imdb.go

@@ -14,11 +14,11 @@ import (
 	"time"
 )
 
-// GetVideoInfoFromIMDB 从 IMDB ID 查询影片的信息
-func GetVideoInfoFromIMDB(imdbID string, _proxySettings ...settings.ProxySettings) (*imdb.Title, error) {
+// GetVideoInfoFromIMDBWeb 从 IMDB 网站 ID 查询影片的信息
+func GetVideoInfoFromIMDBWeb(imdbID string, _proxySettings ...*settings.ProxySettings) (*imdb.Title, error) {
 
 	var cli *http.Client
-	var proxySettings settings.ProxySettings
+	var proxySettings *settings.ProxySettings
 	if len(_proxySettings) > 0 && _proxySettings[0].UseHttpProxy == true || len(_proxySettings[0].HttpProxyAddress) > 0 {
 		proxySettings = _proxySettings[0]
 
@@ -51,12 +51,7 @@ func GetVideoInfoFromIMDB(imdbID string, _proxySettings ...settings.ProxySetting
 }
 
 // GetVideoIMDBInfoFromLocal 从本地获取 IMDB 信息,如果找不到则去网络获取并写入本地缓存
-func GetVideoIMDBInfoFromLocal(imdbID string, _proxySettings ...settings.ProxySettings) (*gModels.IMDBInfo, error) {
-
-	var proxySettings settings.ProxySettings
-	if len(_proxySettings) > 0 {
-		proxySettings = _proxySettings[0]
-	}
+func GetVideoIMDBInfoFromLocal(imdbID string, _proxySettings ...*settings.ProxySettings) (*gModels.IMDBInfo, error) {
 
 	log_helper.GetLogger().Debugln("GetVideoIMDBInfoFromLocal", 0)
 
@@ -69,7 +64,7 @@ func GetVideoIMDBInfoFromLocal(imdbID string, _proxySettings ...settings.ProxySe
 
 	if len(imdbInfos) <= 0 {
 		// 没有找到,去网上获取
-		t, err := GetVideoInfoFromIMDB(imdbID, proxySettings)
+		t, err := GetVideoInfoFromIMDBWeb(imdbID, _proxySettings...)
 		if err != nil {
 			return nil, err
 		}
@@ -93,12 +88,12 @@ func GetVideoIMDBInfoFromLocal(imdbID string, _proxySettings ...settings.ProxySe
 }
 
 // IsChineseVideo 从 imdbID 去查询判断是否是中文视频
-func IsChineseVideo(imdbID string, _proxySettings ...settings.ProxySettings) (bool, *gModels.IMDBInfo, error) {
+func IsChineseVideo(imdbID string, _proxySettings ...*settings.ProxySettings) (bool, *gModels.IMDBInfo, error) {
 
 	const chName0 = "chinese"
 	const chName1 = "mandarin"
 
-	var proxySettings settings.ProxySettings
+	var proxySettings *settings.ProxySettings
 	if len(_proxySettings) > 0 {
 		proxySettings = _proxySettings[0]
 	}

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

@@ -12,7 +12,7 @@ func TestGetVideoInfoFromIMDB(t *testing.T) {
 	//imdbID := "tt3032476" 	// 风骚律师
 	//imdbID := "tt6468322" 	// 纸钞屋
 	imdbID := "tt15299712" // 云南虫谷
-	imdbInfo, err := GetVideoInfoFromIMDB(imdbID)
+	imdbInfo, err := GetVideoInfoFromIMDBWeb(imdbID)
 	if err != nil {
 		t.Fatal(err)
 	}

+ 10 - 1
internal/pkg/my_util/util.go

@@ -7,10 +7,10 @@ import (
 	"encoding/binary"
 	"encoding/hex"
 	"fmt"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/regex_things"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	browser "github.com/allanpk716/fake-useragent"
 	"github.com/go-resty/resty/v2"
 	"github.com/google/uuid"
@@ -152,6 +152,11 @@ func VideoNameSearchKeywordMaker(l *logrus.Logger, title string, year string) st
 // SearchMatchedVideoFileFromDirs 搜索符合后缀名的视频文件
 func SearchMatchedVideoFileFromDirs(l *logrus.Logger, dirs []string) ([]string, error) {
 
+	defer func() {
+		l.Debugln("SearchMatchedVideoFileFromDirs End ----------------")
+	}()
+	l.Debugln("SearchMatchedVideoFileFromDirs Start ----------------")
+
 	var fileFullPathList = make([]string, 0)
 	for _, dir := range dirs {
 
@@ -163,6 +168,10 @@ func SearchMatchedVideoFileFromDirs(l *logrus.Logger, dirs []string) ([]string,
 		fileFullPathList = append(fileFullPathList, matchedVideoFile...)
 	}
 
+	for _, s := range fileFullPathList {
+		l.Debugln(s)
+	}
+
 	return fileFullPathList, nil
 }
 

+ 6 - 2
internal/pkg/settings/advanced_settings.go

@@ -1,6 +1,8 @@
 package settings
 
-import "github.com/allanpk716/ChineseSubFinder/internal/common"
+import (
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
+)
 
 type AdvancedSettings struct {
 	ProxySettings              *ProxySettings     `json:"proxy_settings"`
@@ -12,7 +14,8 @@ type AdvancedSettings struct {
 	CustomVideoExts            []string           `json:"custom_video_exts""`             // 自定义视频扩展名,是在原有基础上新增。
 	FixTimeLine                bool               `json:"fix_time_line"`                  // 开启校正字幕时间轴,默认 false
 	Topic                      int                `json:"topic"`                          // 搜索结果的时候,返回 Topic N 以内的
-	SuppliersSettings          *SuppliersSettings `json:"suppliers_settings"`
+	SuppliersSettings          *SuppliersSettings `json:"suppliers_settings"`             // 每个字幕源的设置
+	TaskQueue                  *TaskQueue         `json:"task_queue"`                     // 任务队列的设置
 }
 
 func NewAdvancedSettings() *AdvancedSettings {
@@ -21,5 +24,6 @@ func NewAdvancedSettings() *AdvancedSettings {
 		CustomVideoExts:   make([]string, 0),
 		Topic:             common.DownloadSubsPerSite,
 		SuppliersSettings: NewSuppliersSettings(),
+		TaskQueue:         NewTaskQueue(),
 	}
 }

+ 3 - 1
internal/pkg/settings/emby_settings.go

@@ -1,6 +1,8 @@
 package settings
 
-import "github.com/allanpk716/ChineseSubFinder/internal/common"
+import (
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
+)
 
 type EmbySettings struct {
 	Enable                bool              `json:"enable"`                   // 是否启用

+ 7 - 5
internal/pkg/settings/supplier_settings.go

@@ -1,6 +1,8 @@
 package settings
 
-import "github.com/allanpk716/ChineseSubFinder/internal/common"
+import (
+	common2 "github.com/allanpk716/ChineseSubFinder/internal/types/common"
+)
 
 type SuppliersSettings struct {
 	Xunlei  *OneSupplierSettings `json:"xunlei"`
@@ -11,10 +13,10 @@ type SuppliersSettings struct {
 
 func NewSuppliersSettings() *SuppliersSettings {
 	return &SuppliersSettings{
-		Xunlei:  NewOneSupplierSettings(common.SubSiteXunLei, common.SubXunLeiRootUrlDef, -1),
-		Shooter: NewOneSupplierSettings(common.SubSiteShooter, common.SubShooterRootUrlDef, -1),
-		SubHD:   NewOneSupplierSettings(common.SubSiteSubHd, common.SubSubHDRootUrlDef, 50),
-		Zimuku:  NewOneSupplierSettings(common.SubSiteZiMuKu, common.SubZiMuKuRootUrlDef, 50),
+		Xunlei:  NewOneSupplierSettings(common2.SubSiteXunLei, common2.SubXunLeiRootUrlDef, -1),
+		Shooter: NewOneSupplierSettings(common2.SubSiteShooter, common2.SubShooterRootUrlDef, -1),
+		SubHD:   NewOneSupplierSettings(common2.SubSiteSubHd, common2.SubSubHDRootUrlDef, 50),
+		Zimuku:  NewOneSupplierSettings(common2.SubSiteZiMuKu, common2.SubZiMuKuRootUrlDef, 50),
 	}
 }
 

+ 11 - 0
internal/pkg/settings/task_queue.go

@@ -0,0 +1,11 @@
+package settings
+
+type TaskQueue struct {
+	MaxRetryTimes  int `json:"max_retry_times" default:"3"`   // 单个任务失败后,最大重试次数,超过后会降级为 Low
+	Interval       int `json:"interval" default:"30"`         // 任务的间隔,单位 s,这里会有一个限制,不允许太快,然后会做一定的随机时间范围
+	ExpirationTime int `json:"expiration_time"  default:"30"` // 添加任务后,过期的时间(单位 day),超过后,任务会降级到 Low
+}
+
+func NewTaskQueue() *TaskQueue {
+	return &TaskQueue{MaxRetryTimes: 3, Interval: 30, ExpirationTime: 30}
+}

+ 1 - 1
internal/pkg/something_static/something_static.go

@@ -2,8 +2,8 @@ package something_static
 
 import (
 	b64 "encoding/base64"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/sirupsen/logrus"
 	"os"
 	"path/filepath"

+ 1 - 1
internal/pkg/sub_file_hash/sub_file_hash.go

@@ -4,7 +4,7 @@ import (
 	"crypto/md5"
 	"crypto/sha1"
 	"fmt"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"math"
 	"os"
 )

+ 1 - 1
internal/pkg/sub_formatter/emby/emby_test.go

@@ -1,8 +1,8 @@
 package emby
 
 import (
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	subCommon "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_formatter/common"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/language"
 	"testing"
 )

+ 1 - 1
internal/pkg/sub_formatter/normal/normal_test.go

@@ -1,8 +1,8 @@
 package normal
 
 import (
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	subCommon "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_formatter/common"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/language"
 	"path/filepath"
 	"testing"

+ 1 - 1
internal/pkg/sub_formatter/old/old.go

@@ -1,7 +1,7 @@
 package old
 
 import (
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/language"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/subparser"
 	"path/filepath"

+ 1 - 1
internal/pkg/sub_formatter/sub_format_changer.go

@@ -3,7 +3,6 @@ package sub_formatter
 import (
 	"errors"
 	"fmt"
-	interCommon "github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/dao"
 	"github.com/allanpk716/ChineseSubFinder/internal/ifaces"
 	movieHelper "github.com/allanpk716/ChineseSubFinder/internal/logic/movie_helper"
@@ -15,6 +14,7 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_formatter/emby"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_formatter/normal"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
+	interCommon "github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/subparser"
 	"gorm.io/gorm"
 	"os"

+ 1 - 1
internal/pkg/sub_helper/sub_helper.go

@@ -2,7 +2,6 @@ package sub_helper
 
 import (
 	"errors"
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/archive_helper"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/language"
@@ -12,6 +11,7 @@ import (
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/regex_things"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_parser_hub"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/vad"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/subparser"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/supplier"
 	"math"

+ 1 - 1
internal/pkg/sub_parser_hub/subParserHub.go

@@ -1,10 +1,10 @@
 package sub_parser_hub
 
 import (
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/ifaces"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/language"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/log_helper"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	languageConst "github.com/allanpk716/ChineseSubFinder/internal/types/language"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/subparser"
 	"os"

+ 0 - 0
internal/common/constvalue.go → internal/types/common/constvalue.go


+ 0 - 0
internal/common/global_value.go → internal/types/common/global_value.go


+ 0 - 0
internal/common/selferr.go → internal/types/common/selferr.go


+ 0 - 0
internal/common/subtypes.go → internal/types/common/subtypes.go


+ 0 - 0
internal/common/urls.go → internal/types/common/urls.go


+ 12 - 0
internal/common/videotype.go → internal/types/common/video_type.go

@@ -7,3 +7,15 @@ const (
 	Series                  // 连续剧,可能需要分美剧、日剧、韩剧?
 	Anime                   // 动画
 )
+
+func (c VideoType) String() string {
+	switch c {
+	case Movie:
+		return "movie"
+	case Series:
+		return "series"
+	case Anime:
+		return "anime"
+	}
+	return "N/A"
+}

+ 1 - 1
internal/types/emby/type.go

@@ -160,7 +160,7 @@ type EmbyMixInfo struct {
 	VideoFolderName           string // 电影就是电影的文件夹名称,连续剧就是对应的剧集的 root 文件夹
 	VideoFileName             string // 视频文件名
 	PhysicalVideoFileFullPath string // 视频的物理路径(这里指的物理路径是相对于本程序而言,如果是用 docker 使用的话,那么就是映射容器内的路径,如果是用物理机器比如 Windows 使用的话,那么就是相对于物理机器的路径)
-	PhysicalRootPath          string // 视频在那个物理根目录中(这里指的物理路径是相对于本程序而言,如果是用 docker 使用的话,那么就是映射容器内的路径,如果是用物理机器比如 Windows 使用的话,那么就是相对于物理机器的路径)
+	PhysicalRootPath          string // 不是 Emby 扫描的情况,无需关注。视频在那个物理根目录中(这里指的物理路径是相对于本程序而言,如果是用 docker 使用的话,那么就是映射容器内的路径,如果是用物理机器比如 Windows 使用的话,那么就是相对于物理机器的路径)
 	Ancestors                 []EmbyItemsAncestors
 	VideoInfo                 EmbyVideoInfo
 }

+ 4 - 4
internal/types/subparser/fileinfo.go

@@ -1,8 +1,8 @@
 package subparser
 
 import (
-	"github.com/allanpk716/ChineseSubFinder/internal/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
+	common2 "github.com/allanpk716/ChineseSubFinder/internal/types/common"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/language"
 	"math"
 	"sort"
@@ -33,10 +33,10 @@ func (f *FileInfo) SortDialogues() {
 
 // GetTimeFormat 获取时间轴的格式化格式
 func (f FileInfo) GetTimeFormat() string {
-	if f.Ext == common.SubExtASS || f.Ext == common.SubExtSSA {
-		return common.TimeFormatPoint2
+	if f.Ext == common2.SubExtASS || f.Ext == common2.SubExtSSA {
+		return common2.TimeFormatPoint2
 	} else {
-		return common.TimeFormatPoint3
+		return common2.TimeFormatPoint3
 	}
 }
 

+ 24 - 0
internal/types/task_queue/job_status.go

@@ -0,0 +1,24 @@
+package task_queue
+
+type JobStatus int
+
+const (
+	Waiting   JobStatus = iota // 任务正在等待处理
+	Committed                  // 任务已经提交
+	Failed                     // 任务失败了,在允许的范围内依然会允许重试
+	Done                       // 任务完成
+)
+
+func (c JobStatus) String() string {
+	switch c {
+	case Waiting:
+		return "waiting"
+	case Committed:
+		return "committed"
+	case Failed:
+		return "failed"
+	case Done:
+		return "done"
+	}
+	return "N/A"
+}

+ 52 - 0
internal/types/task_queue/task_queue.go

@@ -0,0 +1,52 @@
+package task_queue
+
+import (
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_file_hash"
+	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
+	"path/filepath"
+	"time"
+)
+
+type OneJob struct {
+	Id           string           `json:"id"`                        // 任务的唯一 ID
+	VideoType    common.VideoType `json:"video_type"`                // 视频的类型
+	VideoFPath   string           `json:"video_f_path"`              // 视频的全路径
+	VideoName    string           `json:"video_name"`                // 视频的名称
+	Feature      string           `json:"feature"`                   // 视频的特征码,蓝光的时候可能是空
+	Season       int              `json:"season"`                    // 如果对应的是电影则可能是 0,没有
+	Episode      int              `json:"episode"`                   // 如果对应的是电影则可能是 0,没有
+	JobStatus    JobStatus        `json:"job_status"`                // 任务的状态
+	TaskPriority int              `json:"task_priority" default:"5"` // 任务的优先级,0 - 10 个级别,0 是最高,10 是最低
+	RetryTimes   int              `json:"retry_times"`               // 重试了多少次
+	AddedTime    time.Time        `json:"added_time"`                // 任务添加的时间
+	UpdateTime   time.Time        `json:"update_time"`               // 任务更新的时间
+}
+
+func NewOneJob(videoType common.VideoType, videoFPath string, taskPriority int) *OneJob {
+
+	ob := &OneJob{VideoType: videoType, VideoFPath: videoFPath, TaskPriority: taskPriority}
+	ob.Id = my_util.GenerateAccessToken() // 其实是 UUID
+	ob.VideoName = filepath.Base(videoFPath)
+	// -------------------------------------------------
+	// 使用本程序的 hash 的算法,得到视频的唯一 ID
+	ob.Feature, _ = sub_file_hash.Calculate(videoFPath)
+	// -------------------------------------------------
+	if videoType == common.Series {
+		// 连续剧的时候,如果可能应该获取是 第几季  第几集
+		torrentInfo, _, err := decode.GetVideoInfoFromFileFullPath(videoFPath)
+		if err == nil {
+			ob.Season = torrentInfo.Season
+			ob.Episode = torrentInfo.Episode
+		}
+	}
+	// -------------------------------------------------
+	ob.JobStatus = Waiting
+	ob.TaskPriority = 5
+	nTime := time.Now()
+	ob.AddedTime = nTime
+	ob.UpdateTime = nTime
+
+	return ob
+}