Browse Source

调整 任务队列中 Done 状态下任务的细节

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

+ 1 - 0
go.mod

@@ -77,6 +77,7 @@ require (
 	github.com/acomagu/bufpipe v1.0.3 // indirect
 	github.com/andybalholm/brotli v1.0.0 // indirect
 	github.com/andybalholm/cascadia v1.2.0 // indirect
+	github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de // indirect
 	github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 // indirect
 	github.com/bodgit/plumbing v1.1.0 // indirect
 	github.com/bodgit/windows v1.0.0 // indirect

+ 5 - 0
go.sum

@@ -67,6 +67,8 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
 github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
 github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
+github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
@@ -408,6 +410,7 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
 github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
 github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
 github.com/mattn/go-sqlite3 v1.14.10 h1:MLn+5bFRlWMGoSRmJour3CL1w/qL96mvipqpwQW/Sfk=
 github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
@@ -513,6 +516,7 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
 github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=
 github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@@ -530,6 +534,7 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
 github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI=
 github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
 github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
+github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=

+ 1 - 1
internal/backend/controllers/base/path_things.go

@@ -63,7 +63,7 @@ func (cb ControllerBase) CheckEmbyPathHandler(c *gin.Context) {
 		emSettings.SeriesPathsMapping[reqCheckPath.CFSMediaPath] = reqCheckPath.EmbyMediaPath
 	}
 
-	emHelper := emby_helper.NewEmbyHelper(&emSettings)
+	emHelper := emby_helper.NewEmbyHelper(&settings.Settings{EmbySettings: &emSettings})
 
 	outList, err := emHelper.CheckPath(reqCheckPath.PathType)
 	if err != nil {

+ 8 - 8
internal/logic/cron_helper/cron_helper.go

@@ -40,7 +40,7 @@ func NewCronHelper(_log *logrus.Logger, _sets *settings.Settings) *CronHelper {
 	return &ch
 }
 
-// Start 开启定时器任务,这个任务是非阻塞的,scanVideoProcess 仅仅可能是这个函数执行耗时而已
+// Start 开启定时器任务,这个任务是非阻塞的,scanVideoProcessAdd2DownloadQueue 仅仅可能是这个函数执行耗时而已
 // runImmediately == false 那么 ch.c.Start() 是不会阻塞的
 func (ch *CronHelper) Start(runImmediately bool) {
 
@@ -77,9 +77,9 @@ func (ch *CronHelper) Start(runImmediately bool) {
 	// ----------------------------------------------
 	ch.c = cron.New(cron.WithChain(cron.SkipIfStillRunning(cron.DefaultLogger)))
 	// 定时器
-	ch.entryIDScanVideoProcess, err = ch.c.AddFunc(ch.sets.CommonSettings.ScanInterval, ch.scanVideoProcess)
+	ch.entryIDScanVideoProcess, err = ch.c.AddFunc(ch.sets.CommonSettings.ScanInterval, ch.scanVideoProcessAdd2DownloadQueue)
 	if err != nil {
-		ch.log.Panicln("CronHelper scanVideoProcess, Cron entryID:", ch.entryIDScanVideoProcess, "Error:", err)
+		ch.log.Panicln("CronHelper scanVideoProcessAdd2DownloadQueue, Cron entryID:", ch.entryIDScanVideoProcess, "Error:", err)
 	}
 	ch.entryIDSupplierCheck, err = ch.c.AddFunc("@every 1h", ch.downloader.SupplierCheck)
 	if err != nil {
@@ -93,13 +93,13 @@ func (ch *CronHelper) Start(runImmediately bool) {
 	// 是否在定时器开启前先执行一次任务
 	if runImmediately == true {
 
-		ch.log.Infoln("First Time scanVideoProcess Start")
+		ch.log.Infoln("First Time scanVideoProcessAdd2DownloadQueue Start")
 
-		ch.scanVideoProcess()
+		ch.scanVideoProcessAdd2DownloadQueue()
 
 		ch.downloader.SupplierCheck()
 
-		ch.log.Infoln("First Time scanVideoProcess End")
+		ch.log.Infoln("First Time scanVideoProcessAdd2DownloadQueue End")
 
 	} else {
 		ch.log.Infoln("RunAtStartup: false, so will not Run At Startup")
@@ -190,8 +190,8 @@ func (ch *CronHelper) CronRunningStatusString() string {
 	}
 }
 
-// scanVideoProcess 定时执行的视频扫描任务,提交给任务队列,然后由额外的下载者线程去取队列中的任务下载
-func (ch *CronHelper) scanVideoProcess() {
+// scanVideoProcessAdd2DownloadQueue 定时执行的视频扫描任务,提交给任务队列,然后由额外的下载者线程去取队列中的任务下载
+func (ch *CronHelper) scanVideoProcessAdd2DownloadQueue() {
 
 	defer func() {
 		ch.cronLock.Lock()

+ 18 - 20
internal/logic/emby_helper/embyhelper.go

@@ -22,16 +22,16 @@ import (
 )
 
 type EmbyHelper struct {
-	embyApi    *embyHelper.EmbyApi
-	EmbyConfig *settings.EmbySettings
-	threads    int
-	timeOut    time.Duration
-	listLock   sync.Mutex
+	embyApi  *embyHelper.EmbyApi
+	settings *settings.Settings
+	threads  int
+	timeOut  time.Duration
+	listLock sync.Mutex
 }
 
-func NewEmbyHelper(embyConfig *settings.EmbySettings) *EmbyHelper {
-	em := EmbyHelper{EmbyConfig: embyConfig}
-	em.embyApi = embyHelper.NewEmbyApi(embyConfig)
+func NewEmbyHelper(_settings *settings.Settings) *EmbyHelper {
+	em := EmbyHelper{settings: _settings}
+	em.embyApi = embyHelper.NewEmbyApi(_settings.EmbySettings)
 	em.threads = 6
 	em.timeOut = 60 * time.Second
 	return &em
@@ -255,14 +255,14 @@ func (em *EmbyHelper) findMappingPath(fileFPathWithEmby string, isMovieOrSeries
 	matchedEmbyPaths := make([]string, 0)
 	if isMovieOrSeries == true {
 		// 电影的情况
-		for _, embyPath := range em.EmbyConfig.MoviePathsMapping {
+		for _, embyPath := range em.settings.EmbySettings.MoviePathsMapping {
 			if strings.HasPrefix(fileFPathWithEmby, embyPath) == true {
 				matchedEmbyPaths = append(matchedEmbyPaths, embyPath)
 			}
 		}
 	} else {
 		// 连续剧的情况
-		for _, embyPath := range em.EmbyConfig.SeriesPathsMapping {
+		for _, embyPath := range em.settings.EmbySettings.SeriesPathsMapping {
 			if strings.HasPrefix(fileFPathWithEmby, embyPath) == true {
 				matchedEmbyPaths = append(matchedEmbyPaths, embyPath)
 			}
@@ -279,7 +279,7 @@ func (em *EmbyHelper) findMappingPath(fileFPathWithEmby string, isMovieOrSeries
 	nowPhRootPath := ""
 	if isMovieOrSeries == true {
 		// 电影的情况
-		for physicalPath, embyPath := range em.EmbyConfig.MoviePathsMapping {
+		for physicalPath, embyPath := range em.settings.EmbySettings.MoviePathsMapping {
 			if embyPath == pathSlices[0].Path {
 				nowPhRootPath = physicalPath
 				break
@@ -287,7 +287,7 @@ func (em *EmbyHelper) findMappingPath(fileFPathWithEmby string, isMovieOrSeries
 		}
 	} else {
 		// 连续剧的情况
-		for physicalPath, embyPath := range em.EmbyConfig.SeriesPathsMapping {
+		for physicalPath, embyPath := range em.settings.EmbySettings.SeriesPathsMapping {
 			if embyPath == pathSlices[0].Path {
 				nowPhRootPath = physicalPath
 				break
@@ -321,14 +321,14 @@ func (em *EmbyHelper) findMappingPathWithMixInfo(mixInfo *emby.EmbyMixInfo, isMo
 	matchedEmbyPaths := make([]string, 0)
 	if isMovieOrSeries == true {
 		// 电影的情况
-		for _, embyPath := range em.EmbyConfig.MoviePathsMapping {
+		for _, embyPath := range em.settings.EmbySettings.MoviePathsMapping {
 			if strings.HasPrefix(mixInfo.VideoInfo.Path, embyPath) == true {
 				matchedEmbyPaths = append(matchedEmbyPaths, embyPath)
 			}
 		}
 	} else {
 		// 连续剧的情况
-		for _, embyPath := range em.EmbyConfig.SeriesPathsMapping {
+		for _, embyPath := range em.settings.EmbySettings.SeriesPathsMapping {
 			if strings.HasPrefix(mixInfo.VideoInfo.Path, embyPath) == true {
 				matchedEmbyPaths = append(matchedEmbyPaths, embyPath)
 			}
@@ -344,7 +344,7 @@ func (em *EmbyHelper) findMappingPathWithMixInfo(mixInfo *emby.EmbyMixInfo, isMo
 	nowPhRootPath := ""
 	if isMovieOrSeries == true {
 		// 电影的情况
-		for physicalPath, embyPath := range em.EmbyConfig.MoviePathsMapping {
+		for physicalPath, embyPath := range em.settings.EmbySettings.MoviePathsMapping {
 			if embyPath == pathSlices[0].Path {
 				nowPhRootPath = physicalPath
 				break
@@ -352,7 +352,7 @@ func (em *EmbyHelper) findMappingPathWithMixInfo(mixInfo *emby.EmbyMixInfo, isMo
 		}
 	} else {
 		// 连续剧的情况
-		for physicalPath, embyPath := range em.EmbyConfig.SeriesPathsMapping {
+		for physicalPath, embyPath := range em.settings.EmbySettings.SeriesPathsMapping {
 			if embyPath == pathSlices[0].Path {
 				nowPhRootPath = physicalPath
 				break
@@ -519,8 +519,6 @@ func (em *EmbyHelper) getMoreVideoInfoList(videoIdList []string, isMovieOrSeries
 // filterNoChineseSubVideoList 将没有中文字幕的视频找出来
 func (em *EmbyHelper) filterNoChineseSubVideoList(videoList []emby.EmbyMixInfo) ([]emby.EmbyMixInfo, error) {
 	currentTime := time.Now()
-	dayRange3Months, _ := time.ParseDuration(common2.DownloadSubDuring3Months)
-	dayRange7Days, _ := time.ParseDuration(common2.DownloadSubDuring7Days)
 
 	var noSubVideoList = make([]emby.EmbyMixInfo, 0)
 	// TODO 这里有一种情况需要考虑的,如果内置有中文的字幕,那么是否需要跳过,目前暂定的一定要有外置的字幕
@@ -528,7 +526,7 @@ func (em *EmbyHelper) filterNoChineseSubVideoList(videoList []emby.EmbyMixInfo)
 
 		needDlSub3Month := false
 		// 3个月内,或者没有字幕都要进行下载
-		if info.VideoInfo.PremiereDate.Add(dayRange3Months).After(currentTime) == true {
+		if info.VideoInfo.PremiereDate.AddDate(0, 0, em.settings.AdvancedSettings.TaskQueue.ExpirationTime).After(currentTime) == true {
 			// 需要下载的
 			needDlSub3Month = true
 		}
@@ -563,7 +561,7 @@ func (em *EmbyHelper) filterNoChineseSubVideoList(videoList []emby.EmbyMixInfo)
 		if haveExternalChineseSub == false {
 			// 没有外置字幕
 			// 如果创建了7天,且有内置的中文字幕,那么也不进行下载了
-			if info.VideoInfo.DateCreated.Add(dayRange7Days).After(currentTime) == false && haveInsideChineseSub == true {
+			if info.VideoInfo.DateCreated.AddDate(0, 0, em.settings.AdvancedSettings.TaskQueue.DownloadSubDuringXDays).After(currentTime) == false && haveInsideChineseSub == true {
 				log_helper.GetLogger().Debugln("Create Over 7 Days, And It Has Inside ChineseSub, Than Skip", info.VideoFileName)
 				continue
 			}

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

@@ -122,7 +122,7 @@ func SkipChineseMovie(videoFullPath string, _proxySettings ...*settings.ProxySet
 	}
 }
 
-func MovieNeedDlSub(videoFullPath string) (bool, error) {
+func MovieNeedDlSub(videoFullPath string, ExpirationTime int) (bool, error) {
 	// 视频下面有不有字幕
 	found, _, _, err := MovieHasChineseSub(videoFullPath)
 	if err != nil {
@@ -130,7 +130,6 @@ func MovieNeedDlSub(videoFullPath string) (bool, error) {
 	}
 	// 资源下载的时间后的多少天内都进行字幕的自动下载,替换原有的字幕
 	currentTime := time.Now()
-	dayRange, _ := time.ParseDuration(common.DownloadSubDuring3Months)
 	mInfo, modifyTime, err := decode.GetVideoInfoFromFileFullPath(videoFullPath)
 	if err != nil {
 		return false, err
@@ -165,11 +164,11 @@ func MovieNeedDlSub(videoFullPath string) (bool, error) {
 		}
 
 		// 3个月内,或者没有字幕都要进行下载
-		if baseTime.Add(dayRange).After(currentTime) == true || found == false {
+		if baseTime.AddDate(0, 0, ExpirationTime).After(currentTime) == true || found == false {
 			// 需要下载的
 			return true, nil
 		} else {
-			if baseTime.Add(dayRange).After(currentTime) == false {
+			if baseTime.AddDate(0, 0, ExpirationTime).After(currentTime) == false {
 				log_helper.GetLogger().Infoln("Skip", filepath.Base(videoFullPath), "Sub Download, because movie has sub and downloaded or aired more than 3 months")
 				return false, nil
 			}

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

@@ -281,7 +281,7 @@ func (s *ScanPlayedVideoSubInfo) dealOneVideo(index int, videoFPath, orgSubFPath
 	if isMovie == true {
 		imdbInfo4Video, err = decode.GetImdbInfo4Movie(videoFPath)
 	} else {
-		imdbInfo4Video, err = decode.GetSeriesImdbInfoFromEpisode(videoFPath)
+		imdbInfo4Video, err = decode.GetSeriesSeasonImdbInfoFromEpisode(videoFPath)
 	}
 	if err != nil {
 		// 如果找不到当前电影的 IMDB Info 本地文件,那么就跳过

+ 7 - 9
internal/logic/series_helper/seriesHelper.go

@@ -82,7 +82,7 @@ func readSeriesInfo(seriesDir string, _proxySettings ...*settings.ProxySettings)
 }
 
 // ReadSeriesInfoFromDir 读取剧集的信息,只有那些 Eps 需要下载字幕的 NeedDlEpsKeyList
-func ReadSeriesInfoFromDir(seriesDir string, forcedScanAndDownloadSub bool, _proxySettings ...*settings.ProxySettings) (*series.SeriesInfo, error) {
+func ReadSeriesInfoFromDir(seriesDir string, ExpirationTime int, forcedScanAndDownloadSub bool, _proxySettings ...*settings.ProxySettings) (*series.SeriesInfo, error) {
 
 	seriesInfo, SubDict, err := readSeriesInfo(seriesDir, _proxySettings...)
 	if err != nil {
@@ -104,13 +104,13 @@ func ReadSeriesInfoFromDir(seriesDir string, forcedScanAndDownloadSub bool, _pro
 		seriesInfo.SeasonDict[episodeInfo.Season] = episodeInfo.Season
 	}
 
-	seriesInfo.NeedDlEpsKeyList, seriesInfo.NeedDlSeasonDict = whichSeasonEpsNeedDownloadSub(seriesInfo, forcedScanAndDownloadSub)
+	seriesInfo.NeedDlEpsKeyList, seriesInfo.NeedDlSeasonDict = whichSeasonEpsNeedDownloadSub(seriesInfo, ExpirationTime, forcedScanAndDownloadSub)
 
 	return seriesInfo, nil
 }
 
 // ReadSeriesInfoFromEmby 将 Emby API 读取到的数据进行转换到通用的结构中,需要填充那些剧集需要下载,这样要的是一个连续剧的,不是所有的传入(只有那些 Eps 需要下载字幕的 NeedDlEpsKeyList)
-func ReadSeriesInfoFromEmby(seriesDir string, seriesVideoList []emby.EmbyMixInfo, forcedScanAndDownloadSub bool, _proxySettings ...*settings.ProxySettings) (*series.SeriesInfo, error) {
+func ReadSeriesInfoFromEmby(seriesDir string, seriesVideoList []emby.EmbyMixInfo, ExpirationTime int, forcedScanAndDownloadSub bool, _proxySettings ...*settings.ProxySettings) (*series.SeriesInfo, error) {
 
 	seriesInfo, SubDict, err := readSeriesInfo(seriesDir, _proxySettings...)
 	if err != nil {
@@ -127,7 +127,7 @@ func ReadSeriesInfoFromEmby(seriesDir string, seriesVideoList []emby.EmbyMixInfo
 		seriesInfo.SeasonDict[episodeInfo.Season] = episodeInfo.Season
 	}
 
-	seriesInfo.NeedDlEpsKeyList, seriesInfo.NeedDlSeasonDict = whichSeasonEpsNeedDownloadSub(seriesInfo, forcedScanAndDownloadSub)
+	seriesInfo.NeedDlEpsKeyList, seriesInfo.NeedDlSeasonDict = whichSeasonEpsNeedDownloadSub(seriesInfo, ExpirationTime, forcedScanAndDownloadSub)
 
 	return seriesInfo, nil
 }
@@ -267,12 +267,10 @@ func GetSeriesList(dir string) ([]string, error) {
 }
 
 // whichSeasonEpsNeedDownloadSub 有那些 Eps 需要下载的,按 SxEx 反回 epsKey
-func whichSeasonEpsNeedDownloadSub(seriesInfo *series.SeriesInfo, forcedScanAndDownloadSub bool) (map[string]series.EpisodeInfo, map[int]int) {
+func whichSeasonEpsNeedDownloadSub(seriesInfo *series.SeriesInfo, ExpirationTime int, forcedScanAndDownloadSub bool) (map[string]series.EpisodeInfo, map[int]int) {
 	var needDlSubEpsList = make(map[string]series.EpisodeInfo, 0)
 	var needDlSeasonList = make(map[int]int, 0)
 	currentTime := time.Now()
-	// 3个月
-	dayRange, _ := time.ParseDuration(common.DownloadSubDuring3Months)
 	// 直接强制所有视频都下载字幕
 	if forcedScanAndDownloadSub == true {
 		for _, epsInfo := range seriesInfo.EpList {
@@ -301,7 +299,7 @@ func whichSeasonEpsNeedDownloadSub(seriesInfo *series.SeriesInfo, forcedScanAndD
 			baseTime = epsInfo.ModifyTime
 		}
 
-		if len(epsInfo.SubAlreadyDownloadedList) < 1 || baseTime.Add(dayRange).After(currentTime) == true {
+		if len(epsInfo.SubAlreadyDownloadedList) < 1 || baseTime.AddDate(0, 0, ExpirationTime).After(currentTime) == true {
 			// 添加
 			epsKey := my_util.GetEpisodeKeyName(epsInfo.Season, epsInfo.Episode)
 			needDlSubEpsList[epsKey] = epsInfo
@@ -309,7 +307,7 @@ func whichSeasonEpsNeedDownloadSub(seriesInfo *series.SeriesInfo, forcedScanAndD
 		} else {
 			if len(epsInfo.SubAlreadyDownloadedList) > 0 {
 				log_helper.GetLogger().Infoln("Skip because find sub file and downloaded or aired over 3 months,", epsInfo.Title, epsInfo.Season, epsInfo.Episode)
-			} else if baseTime.Add(dayRange).After(currentTime) == false {
+			} else if baseTime.AddDate(0, 0, ExpirationTime).After(currentTime) == false {
 				log_helper.GetLogger().Infoln("Skip because 3 months pass,", epsInfo.Title, epsInfo.Season, epsInfo.Episode)
 			}
 		}

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

@@ -74,7 +74,7 @@ func (d *SubSupplierHub) MovieNeedDlSub(videoFullPath string, forcedScanAndDownl
 		// 强制下载字幕
 		needDlSub = true
 	} else {
-		needDlSub, err = movieHelper.MovieNeedDlSub(videoFullPath)
+		needDlSub, err = movieHelper.MovieNeedDlSub(videoFullPath, d.settings.AdvancedSettings.TaskQueue.ExpirationTime)
 		if err != nil {
 			d.log.Errorln(errors.Newf("MovieNeedDlSub %v %v", videoFullPath, err))
 			return false
@@ -101,7 +101,7 @@ func (d *SubSupplierHub) SeriesNeedDlSub(seriesRootPath string, forcedScanAndDow
 	}
 
 	// 读取本地的视频和字幕信息
-	seriesInfo, err := seriesHelper.ReadSeriesInfoFromDir(seriesRootPath, forcedScanAndDownloadSub, d.settings.AdvancedSettings.ProxySettings)
+	seriesInfo, err := seriesHelper.ReadSeriesInfoFromDir(seriesRootPath, d.settings.AdvancedSettings.TaskQueue.ExpirationTime, forcedScanAndDownloadSub, d.settings.AdvancedSettings.ProxySettings)
 	if err != nil {
 		return false, nil, errors.Newf("ReadSeriesInfoFromDir %v %v", seriesRootPath, err)
 	}
@@ -110,7 +110,7 @@ func (d *SubSupplierHub) SeriesNeedDlSub(seriesRootPath string, forcedScanAndDow
 }
 
 // SeriesNeedDlSubFromEmby 连续剧是否符合要求需要下载字幕
-func (d *SubSupplierHub) SeriesNeedDlSubFromEmby(seriesRootPath string, seriesVideoList []emby.EmbyMixInfo, skipChineseMovie, forcedScanAndDownloadSub bool) (bool, *series.SeriesInfo, error) {
+func (d *SubSupplierHub) SeriesNeedDlSubFromEmby(seriesRootPath string, seriesVideoList []emby.EmbyMixInfo, ExpirationTime int, skipChineseMovie, forcedScanAndDownloadSub bool) (bool, *series.SeriesInfo, error) {
 
 	if skipChineseMovie == true {
 		var skip bool
@@ -125,7 +125,7 @@ func (d *SubSupplierHub) SeriesNeedDlSubFromEmby(seriesRootPath string, seriesVi
 		}
 	}
 	// 读取本地的视频和字幕信息
-	seriesInfo, err := seriesHelper.ReadSeriesInfoFromEmby(seriesRootPath, seriesVideoList, forcedScanAndDownloadSub, d.settings.AdvancedSettings.ProxySettings)
+	seriesInfo, err := seriesHelper.ReadSeriesInfoFromEmby(seriesRootPath, seriesVideoList, ExpirationTime, forcedScanAndDownloadSub, d.settings.AdvancedSettings.ProxySettings)
 	if err != nil {
 		return false, nil, errors.Newf("ReadSeriesInfoFromDir %v %v", seriesRootPath, err)
 	}

+ 57 - 1
internal/logic/task_queue/task_queue.go

@@ -79,6 +79,7 @@ func (t *TaskQueue) Size() int {
 	return t.taskKeyMap.Size()
 }
 
+// checkPriority 检测优先级,会校验范围
 func (t *TaskQueue) checkPriority(oneJob taskQueue2.OneJob) taskQueue2.OneJob {
 
 	if oneJob.TaskPriority > taskPriorityCount {
@@ -92,6 +93,7 @@ func (t *TaskQueue) checkPriority(oneJob taskQueue2.OneJob) taskQueue2.OneJob {
 	return oneJob
 }
 
+// degrade 降一级,会校验范围
 func (t *TaskQueue) degrade(oneJob taskQueue2.OneJob) taskQueue2.OneJob {
 
 	oneJob.TaskPriority -= 1
@@ -177,6 +179,7 @@ func (t *TaskQueue) AutoDetectUpdateJobStatus(oneJob task_queue.OneJob, inErr er
 
 	if inErr == nil {
 		// 没有错误就是完成
+		oneJob.TaskPriority = DefaultTaskPriorityLevel
 		oneJob.JobStatus = taskQueue2.Done
 		oneJob.DownloadTimes += 1
 	} else {
@@ -219,6 +222,19 @@ func (t *TaskQueue) AutoDetectUpdateJobStatus(oneJob task_queue.OneJob, inErr er
 	}
 }
 
+// GetOneJob 优先获取 GetOneWaitingJob 然后才是 GetOneDoneJob
+func (t *TaskQueue) GetOneJob() (bool, task_queue.OneJob, error) {
+	found, waitingJob, err := t.GetOneWaitingJob()
+	if err != nil {
+		return false, task_queue.OneJob{}, err
+	}
+	if found == false {
+		return t.GetOneDoneJob()
+	}
+
+	return true, waitingJob, nil
+}
+
 // GetOneWaitingJob 获取一个元素,按优先级,0 - taskPriorityCount 的级别去拿去任务,不会移除任务
 func (t *TaskQueue) GetOneWaitingJob() (bool, task_queue.OneJob, error) {
 
@@ -241,7 +257,47 @@ func (t *TaskQueue) GetOneWaitingJob() (bool, task_queue.OneJob, error) {
 			// 默认是 12h, A.After(B) : A > B == true
 			// 见《任务队列设计》--以优先级顺序取出描述
 			if tOneJob.JobStatus == task_queue.Waiting && (tOneJob.DownloadTimes == 0 ||
-				tOneJob.UpdateTime.AddDate(0, 0, t.settings.AdvancedSettings.TaskQueue.OneSubDownloadInterval).After(time.Now()) == true && tOneJob.DownloadTimes > 0) {
+				tOneJob.UpdateTime.AddDate(0, 0, t.settings.AdvancedSettings.TaskQueue.OneSubDownloadInterval).After(time.Now()) == false && tOneJob.DownloadTimes > 0) {
+				// 找到就返回
+				found = true
+				return
+			}
+		})
+
+		if found == true {
+			return true, tOneJob, nil
+		}
+	}
+
+	return false, tOneJob, nil
+}
+
+// GetOneDoneJob 获取一个元素,按优先级,0 - taskPriorityCount 的级别去拿去任务,不会移除任务
+func (t *TaskQueue) GetOneDoneJob() (bool, task_queue.OneJob, error) {
+
+	defer t.queueLock.Unlock()
+	t.queueLock.Lock()
+
+	// 如果队列里面没有东西,则返回 false
+	if t.isEmpty() == true {
+		return false, task_queue.OneJob{}, nil
+	}
+
+	found := false
+	tOneJob := task_queue.OneJob{}
+	for TaskPriority := 0; TaskPriority <= taskPriorityCount; TaskPriority++ {
+
+		t.taskPriorityMapList[TaskPriority].Each(func(key interface{}, value interface{}) {
+
+			tOneJob = value.(task_queue.OneJob)
+			// 任务的 UpdateTime 与现在的时间大于单个字幕下载的间隔
+			// 默认是 12h, A.After(B) : A > B == true
+			// 见《任务队列设计》--以优先级顺序取出描述
+			if tOneJob.JobStatus == task_queue.Done &&
+				// 要在 三个月内
+				tOneJob.CreateTime.AddDate(0, 0, t.settings.AdvancedSettings.TaskQueue.ExpirationTime).After(time.Now()) == true &&
+				// 已经下载过的视频,要间隔 12 小时再次下载
+				tOneJob.UpdateTime.AddDate(0, 0, t.settings.AdvancedSettings.TaskQueue.OneSubDownloadInterval).After(time.Now()) == false {
 				// 找到就返回
 				found = true
 				return

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

@@ -202,8 +202,8 @@ func GetImdbInfo4SeriesDir(seriesDir string) (types.VideoIMDBInfo, error) {
 	return imdbInfo, nil
 }
 
-// GetSeriesImdbInfoFromEpisode 从一集获取这个 Series 的 IMDB info
-func GetSeriesImdbInfoFromEpisode(oneEpFPath string) (types.VideoIMDBInfo, error) {
+// GetSeriesSeasonImdbInfoFromEpisode 从一集获取这个 Series 的 IMDB info
+func GetSeriesSeasonImdbInfoFromEpisode(oneEpFPath string) (types.VideoIMDBInfo, error) {
 
 	var err error
 	// 当前季的路径

+ 3 - 3
internal/pkg/downloader/downloader.go

@@ -151,8 +151,8 @@ func (d *Downloader) QueueDownloader() {
 
 	var downloadCounter int64
 	downloadCounter = 0
-	// 从队列取数据出来
-	bok, oneJob, err := d.downloadQueue.GetOneWaitingJob()
+	// 从队列取数据出来,见《任务生命周期》
+	bok, oneJob, err := d.downloadQueue.GetOneJob()
 	if err != nil {
 		d.log.Errorln("d.downloadQueue.GetOneWaitingJob()", err)
 		return
@@ -261,7 +261,7 @@ func (d *Downloader) seriesDlFunc(ctx context.Context, job taskQueue2.OneJob, do
 	}
 	var err error
 	// 这里拿到了这一部连续剧的所有的剧集信息,以及所有下载到的字幕信息
-	seriesInfo, err := series_helper.ReadSeriesInfoFromDir(job.SeriesRootDirPath, false, d.settings.AdvancedSettings.ProxySettings)
+	seriesInfo, err := series_helper.ReadSeriesInfoFromDir(job.SeriesRootDirPath, d.settings.AdvancedSettings.TaskQueue.ExpirationTime, false, d.settings.AdvancedSettings.ProxySettings)
 	if err != nil {
 		err = errors.New(fmt.Sprintf("seriesDlFunc.ReadSeriesInfoFromDir, Error: %v", err))
 		d.downloadQueue.AutoDetectUpdateJobStatus(job, err)

+ 10 - 2
internal/pkg/settings/task_queue.go

@@ -4,10 +4,18 @@ type TaskQueue struct {
 	MaxRetryTimes          int `json:"max_retry_times" default:"3"`            // 单个任务失败后,最大重试次数,超过后会降一级
 	OneJobTimeOut          int `json:"one_job_time_out" default:"300"`         // 单个任务的超时时间 5 * 60 s
 	Interval               int `json:"interval" default:"10"`                  // 任务的间隔,单位 s,这里会有一个限制,不允许太快,然后会做一定的随机时间范围,当前值 x ~ 2*x 之内随机
-	ExpirationTime         int `json:"expiration_time"  default:"90"`          // 添加任务后,过期的时间(单位 day),超过后,任务会降级到 Low
+	ExpirationTime         int `json:"expiration_time"  default:"90"`          // 单位天。1. 一个视频的 CreateTime 在这个时间范围内,都会被下载字幕(除非已经观看跳过启用了)。2. 如果下载失败的任务,AddTime 超过了这个时间,那么就标记为 Failed
+	DownloadSubDuringXDays int `json:"download_sub_during_x_days" default:"7"` // 如果创建了 x 天,且有内置的中文字幕,那么也不进行下载了
 	OneSubDownloadInterval int `json:"one_sub_download_interval" default:"12"` // 一个字幕下载的间隔(单位 h),不然老是一个循环。对比的基准是 OneJob 的 UpdateTime
 }
 
 func NewTaskQueue() *TaskQueue {
-	return &TaskQueue{MaxRetryTimes: 3, Interval: 10, ExpirationTime: 90, OneJobTimeOut: 300, OneSubDownloadInterval: 12}
+	return &TaskQueue{
+		MaxRetryTimes:          3,
+		OneJobTimeOut:          300,
+		Interval:               10,
+		ExpirationTime:         90,
+		DownloadSubDuringXDays: 7,
+		OneSubDownloadInterval: 12,
+	}
 }

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

@@ -65,7 +65,7 @@ func (v *VideoScanAndRefreshHelper) ScanMovieAndSeriesWait2DownloadSub() (*ScanV
 		v.embyHelper = nil
 
 	} else {
-		v.embyHelper = embyHelper.NewEmbyHelper(v.settings.EmbySettings)
+		v.embyHelper = embyHelper.NewEmbyHelper(v.settings)
 	}
 
 	var err error

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

@@ -12,11 +12,6 @@ const DownloadSubsPerSite = 1            // 默认,每个网站下载一个字
 const EmbyApiGetItemsLimitMin = 50
 const EmbyApiGetItemsLimitMax = 50000
 
-const (
-	DownloadSubDuring3Months = "2160h"
-	DownloadSubDuring7Days   = "168h"
-)
-
 const (
 	SubSiteZiMuKu  = "zimuku"
 	SubSiteSubHd   = "subhd"

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

@@ -3,8 +3,10 @@ package task_queue
 import (
 	"crypto/sha256"
 	"fmt"
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
 	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_file_hash"
 	"github.com/allanpk716/ChineseSubFinder/internal/types/common"
+	"github.com/araddon/dateparse"
 	"path/filepath"
 	"time"
 )
@@ -21,6 +23,7 @@ type OneJob struct {
 	JobStatus                JobStatus        `json:"job_status"`                   // 任务的状态
 	TaskPriority             int              `json:"task_priority" default:"5"`    // 任务的优先级,0 - 10 个级别,0 是最高,10 是最低
 	RetryTimes               int              `json:"retry_times"`                  // 重试了多少次
+	CreateTime               time.Time        `json:"create_time"`                  // 视频的发布时间或者是文件的创建时间
 	AddedTime                time.Time        `json:"added_time"`                   // 任务添加的时间
 	UpdateTime               time.Time        `json:"update_time"`                  // 任务更新的时间
 	MediaServerInsideVideoID string           `json:"media_server_inside_video_id"` // 媒体服务器中,这个视频的 ID,如果是 Emby 就对应它内部这个视频的 ID,后续用于指定刷新视频信息
@@ -56,6 +59,19 @@ func NewOneJob(videoType common.VideoType, videoFPath string, taskPriority int,
 	nTime := time.Now()
 	ob.AddedTime = nTime
 	ob.UpdateTime = nTime
+	// 需要获取这个视频的创建时间或者发布时间
+	if ob.VideoType == common.Movie {
+
+		imdbInfo4Movie, err := decode.GetImdbInfo4Movie(videoFPath)
+		if err == nil {
+			ob.CreateTime, err = dateparse.ParseAny(imdbInfo4Movie.ReleaseDate)
+		}
+	} else if ob.VideoType == common.Series {
+		imdbInfo4Eps, err := decode.GetImdbInfo4OneSeriesEpisode(videoFPath)
+		if err == nil {
+			ob.CreateTime, err = dateparse.ParseAny(imdbInfo4Eps.ReleaseDate)
+		}
+	}
 
 	if len(MediaServerInsideVideoID) > 0 && MediaServerInsideVideoID[0] != "" {
 		ob.MediaServerInsideVideoID = MediaServerInsideVideoID[0]