| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- package series_helper
- import (
- "fmt"
- "github.com/allanpk716/ChineseSubFinder/internal/ifaces"
- "github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/ass"
- "github.com/allanpk716/ChineseSubFinder/internal/logic/sub_parser/srt"
- "github.com/allanpk716/ChineseSubFinder/internal/models"
- "github.com/allanpk716/ChineseSubFinder/internal/pkg/decode"
- "github.com/allanpk716/ChineseSubFinder/internal/pkg/imdb_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/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"
- "github.com/emirpasic/gods/maps/treemap"
- "github.com/jinzhu/now"
- "github.com/sirupsen/logrus"
- "path/filepath"
- "strconv"
- "time"
- )
- func readSeriesInfo(log *logrus.Logger, seriesDir string, _proxySettings ...*settings.ProxySettings) (*series.SeriesInfo, map[string][]series.SubInfo, error) {
- subParserHub := sub_parser_hub.NewSubParserHub(log, ass.NewParser(log), srt.NewParser(log))
- seriesInfo, err := getSeriesInfoFromDir(log, seriesDir, _proxySettings...)
- if err != nil {
- return nil, nil, err
- }
- seriesInfo.NeedDlSeasonDict = make(map[int]int)
- seriesInfo.NeedDlEpsKeyList = make(map[string]series.EpisodeInfo)
- // 搜索所有的字幕
- subFiles, err := sub_helper.SearchMatchedSubFileByDir(log, seriesDir)
- if err != nil {
- return nil, nil, err
- }
- // 字幕字典 S01E01 - []SubInfo
- SubDict := make(map[string][]series.SubInfo)
- for _, subFile := range subFiles {
- // 判断这个字幕是否包含中文
- if subParserHub.IsSubHasChinese(subFile) == false {
- continue
- }
- info, _, err := decode.GetVideoInfoFromFileFullPath(subFile)
- if err != nil {
- log.Errorln(err)
- continue
- }
- bFind, subParserFileInfo, err := subParserHub.DetermineFileTypeFromFile(subFile)
- if err != nil {
- log.Errorln("DetermineFileTypeFromFile", subFile, err)
- continue
- }
- if bFind == false {
- log.Warnln("DetermineFileTypeFromFile", subFile, "not support SubType")
- continue
- }
- epsKey := my_util.GetEpisodeKeyName(info.Season, info.Episode)
- oneFileSubInfo := series.SubInfo{
- Title: info.Title,
- Season: info.Season,
- Episode: info.Episode,
- Language: subParserFileInfo.Lang,
- Dir: filepath.Dir(subFile),
- FileFullPath: subFile,
- }
- _, ok := SubDict[epsKey]
- if ok == false {
- // 初始化
- SubDict[epsKey] = make([]series.SubInfo, 0)
- }
- SubDict[epsKey] = append(SubDict[epsKey], oneFileSubInfo)
- }
- return seriesInfo, SubDict, nil
- }
- // ReadSeriesInfoFromDir 读取剧集的信息,只有那些 Eps 需要下载字幕的 NeedDlEpsKeyList
- func ReadSeriesInfoFromDir(log *logrus.Logger, seriesDir string, ExpirationTime int, forcedScanAndDownloadSub bool, _proxySettings ...*settings.ProxySettings) (*series.SeriesInfo, error) {
- seriesInfo, SubDict, err := readSeriesInfo(log, seriesDir, _proxySettings...)
- if err != nil {
- return nil, err
- }
- // 搜索所有的视频
- videoFiles, err := my_util.SearchMatchedVideoFile(log, seriesDir)
- if err != nil {
- return nil, err
- }
- // 视频字典 S01E01 - EpisodeInfo
- EpisodeDict := make(map[string]series.EpisodeInfo)
- for _, videoFile := range videoFiles {
- getEpsInfoAndSubDic(log, videoFile, EpisodeDict, SubDict)
- }
- for _, episodeInfo := range EpisodeDict {
- seriesInfo.EpList = append(seriesInfo.EpList, episodeInfo)
- seriesInfo.SeasonDict[episodeInfo.Season] = episodeInfo.Season
- }
- seriesInfo.NeedDlEpsKeyList, seriesInfo.NeedDlSeasonDict = whichSeasonEpsNeedDownloadSub(log, seriesInfo, ExpirationTime, forcedScanAndDownloadSub)
- return seriesInfo, nil
- }
- // ReadSeriesInfoFromEmby 将 Emby API 读取到的数据进行转换到通用的结构中,需要填充那些剧集需要下载,这样要的是一个连续剧的,不是所有的传入(只有那些 Eps 需要下载字幕的 NeedDlEpsKeyList)
- func ReadSeriesInfoFromEmby(log *logrus.Logger, seriesDir string, seriesVideoList []emby.EmbyMixInfo, ExpirationTime int, forcedScanAndDownloadSub bool, _proxySettings ...*settings.ProxySettings) (*series.SeriesInfo, error) {
- seriesInfo, SubDict, err := readSeriesInfo(log, seriesDir, _proxySettings...)
- if err != nil {
- return nil, err
- }
- EpisodeDict := make(map[string]series.EpisodeInfo)
- for _, info := range seriesVideoList {
- getEpsInfoAndSubDic(log, info.PhysicalVideoFileFullPath, EpisodeDict, SubDict)
- }
- for _, episodeInfo := range EpisodeDict {
- seriesInfo.EpList = append(seriesInfo.EpList, episodeInfo)
- seriesInfo.SeasonDict[episodeInfo.Season] = episodeInfo.Season
- }
- seriesInfo.NeedDlEpsKeyList, seriesInfo.NeedDlSeasonDict = whichSeasonEpsNeedDownloadSub(log, seriesInfo, ExpirationTime, forcedScanAndDownloadSub)
- return seriesInfo, nil
- }
- // SkipChineseSeries 跳过中文连续剧
- func SkipChineseSeries(log *logrus.Logger, seriesRootPath string, _proxySettings ...*settings.ProxySettings) (bool, *models.IMDBInfo, error) {
- imdbInfo, err := decode.GetImdbInfo4SeriesDir(seriesRootPath)
- if err != nil {
- return false, nil, err
- }
- isChineseVideo, t, err := imdb_helper.IsChineseVideo(log, imdbInfo, _proxySettings...)
- if err != nil {
- return false, nil, err
- }
- if isChineseVideo == true {
- log.Infoln("Skip", filepath.Base(seriesRootPath), "Sub Download, because series is Chinese")
- return true, t, nil
- } else {
- return false, t, nil
- }
- }
- // DownloadSubtitleInAllSiteByOneSeries 一部连续剧,在所有的网站,下载相应的字幕
- func DownloadSubtitleInAllSiteByOneSeries(log *logrus.Logger, Suppliers []ifaces.ISupplier, seriesInfo *series.SeriesInfo, i int64) []supplier.SubInfo {
- defer func() {
- log.Infoln(i, "DlSub End", seriesInfo.DirPath)
- }()
- log.Infoln(common.QueueName, i, "DlSub Start", seriesInfo.DirPath)
- log.Infoln(common.QueueName, i, seriesInfo.Name, "IMDB ID:", seriesInfo.ImdbId, "NeedDownloadSubs:", len(seriesInfo.NeedDlEpsKeyList))
- var outSUbInfos = make([]supplier.SubInfo, 0)
- if len(seriesInfo.NeedDlEpsKeyList) < 1 {
- return outSUbInfos
- }
- for key := range seriesInfo.NeedDlEpsKeyList {
- log.Infoln(common.QueueName, i, seriesInfo.Name, "-", key)
- }
- for _, oneSupplier := range Suppliers {
- oneSupplierFunc := func() {
- defer func() {
- log.Infoln(common.QueueName, i, oneSupplier.GetSupplierName(), "End")
- log.Infoln("------------------------------------------")
- }()
- var subInfos []supplier.SubInfo
- log.Infoln("------------------------------------------")
- log.Infoln(common.QueueName, i, oneSupplier.GetSupplierName(), "Start...")
- // 一次性把这一部连续剧的所有字幕下载完
- subInfos, err := oneSupplier.GetSubListFromFile4Series(seriesInfo)
- if err != nil {
- log.Errorln(common.QueueName, i, oneSupplier.GetSupplierName(), "GetSubListFromFile4Series", err)
- return
- }
- // 把后缀名给改好
- sub_helper.ChangeVideoExt2SubExt(subInfos)
- outSUbInfos = append(outSUbInfos, subInfos...)
- }
- oneSupplierFunc()
- }
- return outSUbInfos
- }
- // SetTheSpecifiedEps2Download 设置指定的 Eps 去下载,可以方便调试或者是后续新功能,能够手动指定 Eps 下载字幕
- func SetTheSpecifiedEps2Download(seriesInfo *series.SeriesInfo, epsMap map[int]int) {
- seriesInfo.NeedDlSeasonDict = make(map[int]int, 0)
- seriesInfo.SeasonDict = make(map[int]int, 0)
- nowNeedDlEpsKeyList := make(map[string]series.EpisodeInfo, 0)
- for needDownloadSeason, needDownloadEp := range epsMap {
- // 选择某一集去下载
- seriesInfo.NeedDlSeasonDict[needDownloadSeason] = needDownloadSeason
- seriesInfo.SeasonDict[needDownloadSeason] = needDownloadSeason
- tmp := series.EpisodeInfo{}
- for _, value := range seriesInfo.NeedDlEpsKeyList {
- if value.Season == needDownloadSeason && value.Episode == needDownloadEp {
- tmp = value
- // 缓存下来
- nowNeedDlEpsKeyList[fmt.Sprintf("S%dE%d", needDownloadSeason, needDownloadEp)] = tmp
- break
- }
- }
- }
- // 一次性写进去
- seriesInfo.NeedDlEpsKeyList = make(map[string]series.EpisodeInfo, 0)
- for s, info := range nowNeedDlEpsKeyList {
- seriesInfo.NeedDlEpsKeyList[s] = info
- }
- }
- // GetSeriesListFromDirs 获取这个目录下的所有文件夹名称,默认为一个连续剧的目录的List
- func GetSeriesListFromDirs(log *logrus.Logger, dirs []string) (*treemap.Map, error) {
- var fileFullPathMap = treemap.NewWithStringComparator()
- for _, dir := range dirs {
- seriesList, err := GetSeriesList(log, dir)
- if err != nil {
- return nil, err
- }
- value, found := fileFullPathMap.Get(dir)
- if found == false {
- fileFullPathMap.Put(dir, seriesList)
- } else {
- value = append(value.([]string), seriesList...)
- fileFullPathMap.Put(dir, value)
- }
- }
- return fileFullPathMap, nil
- }
- // GetSeriesList 获取这个目录下的所有文件夹名称,默认为一个连续剧的目录的List
- func GetSeriesList(log *logrus.Logger, dir string) ([]string, error) {
- // 需要把所有 tvshow.nfo 搜索出来,那么这些文件对应的目录就是目标连续剧的目录
- tvNFOs, err := my_util.SearchTVNfo(log, dir)
- if err != nil {
- return nil, err
- }
- var seriesDirList = make([]string, 0)
- for _, tvNfo := range tvNFOs {
- seriesDirList = append(seriesDirList, filepath.Dir(tvNfo))
- }
- return seriesDirList, err
- }
- // whichSeasonEpsNeedDownloadSub 有那些 Eps 需要下载的,按 SxEx 反回 epsKey
- func whichSeasonEpsNeedDownloadSub(log *logrus.Logger, 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()
- // 直接强制所有视频都下载字幕
- if forcedScanAndDownloadSub == true {
- for _, epsInfo := range seriesInfo.EpList {
- // 添加
- epsKey := my_util.GetEpisodeKeyName(epsInfo.Season, epsInfo.Episode)
- needDlSubEpsList[epsKey] = epsInfo
- needDlSeasonList[epsInfo.Season] = epsInfo.Season
- }
- return needDlSubEpsList, needDlSeasonList
- }
- for _, epsInfo := range seriesInfo.EpList {
- // 如果没有字幕,则加入下载列表
- // 如果每一集的播出时间能够读取到,那么就以这个完后推算 3个月
- // 如果读取不到 Aired Time 那么,这一集下载后的 ModifyTime 3个月天内,都进行字幕的下载
- var err error
- var baseTime time.Time
- if epsInfo.AiredTime != "" {
- baseTime, err = now.Parse(epsInfo.AiredTime)
- if err != nil {
- log.Errorln("SeriesInfo parse AiredTime", epsInfo.Title, epsInfo.Season, epsInfo.Episode, err)
- baseTime = epsInfo.ModifyTime
- }
- } else {
- baseTime = epsInfo.ModifyTime
- }
- if len(epsInfo.SubAlreadyDownloadedList) < 1 || baseTime.AddDate(0, 0, ExpirationTime).After(currentTime) == true {
- // 添加
- epsKey := my_util.GetEpisodeKeyName(epsInfo.Season, epsInfo.Episode)
- needDlSubEpsList[epsKey] = epsInfo
- needDlSeasonList[epsInfo.Season] = epsInfo.Season
- } else {
- if len(epsInfo.SubAlreadyDownloadedList) > 0 {
- log.Infoln("Skip because find sub file and downloaded or aired over 3 months,", epsInfo.Title, epsInfo.Season, epsInfo.Episode)
- } else if baseTime.AddDate(0, 0, ExpirationTime).After(currentTime) == false {
- log.Infoln("Skip because 3 months pass,", epsInfo.Title, epsInfo.Season, epsInfo.Episode)
- }
- }
- }
- return needDlSubEpsList, needDlSeasonList
- }
- func getSeriesInfoFromDir(log *logrus.Logger, 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(log, videoInfo, _proxySettings...)
- if err != nil {
- return nil, err
- }
- // 使用 IMDB ID 得到通用的剧集名称
- // 以 IMDB 的信息为准
- if imdbInfoFromLocal != nil {
- seriesInfo.Name = imdbInfoFromLocal.Name
- seriesInfo.ImdbId = imdbInfoFromLocal.IMDBID
- seriesInfo.Year = imdbInfoFromLocal.Year
- } else {
- seriesInfo.Name = videoInfo.Title
- seriesInfo.ImdbId = videoInfo.ImdbId
- iYear, err := strconv.Atoi(videoInfo.Year)
- if err != nil {
- // 不是必须的
- seriesInfo.Year = 0
- log.Warnln("ReadSeriesInfoFromDir.GetImdbInfo4SeriesDir.strconv.Atoi", seriesDir, err)
- } else {
- seriesInfo.Year = iYear
- }
- }
- seriesInfo.ReleaseDate = videoInfo.ReleaseDate
- seriesInfo.DirPath = seriesDir
- seriesInfo.EpList = make([]series.EpisodeInfo, 0)
- seriesInfo.SeasonDict = make(map[int]int)
- return &seriesInfo, nil
- }
- func getEpsInfoAndSubDic(log *logrus.Logger, videoFile string, EpisodeDict map[string]series.EpisodeInfo, SubDict map[string][]series.SubInfo) {
- // 正常来说,一集只有一个格式的视频,也就是 S01E01 只有一个,如果有多个则会只保存第一个
- info, modifyTime, err := decode.GetVideoInfoFromFileFullPath(videoFile)
- if err != nil {
- log.Errorln("model.GetVideoInfoFromFileFullPath", videoFile, err)
- return
- }
- episodeInfo, err := decode.GetImdbInfo4OneSeriesEpisode(videoFile)
- if err != nil {
- log.Errorln("model.GetImdbInfo4OneSeriesEpisode", videoFile, err)
- return
- }
- epsKey := my_util.GetEpisodeKeyName(info.Season, info.Episode)
- _, ok := EpisodeDict[epsKey]
- if ok == false {
- // 初始化
- oneFileEpInfo := series.EpisodeInfo{
- Title: info.Title,
- Season: info.Season,
- Episode: info.Episode,
- Dir: filepath.Dir(videoFile),
- FileFullPath: videoFile,
- ModifyTime: modifyTime,
- AiredTime: episodeInfo.ReleaseDate,
- }
- // 需要匹配同级目录下的字幕
- oneFileEpInfo.SubAlreadyDownloadedList = make([]series.SubInfo, 0)
- for _, subInfo := range SubDict[epsKey] {
- if subInfo.Dir == oneFileEpInfo.Dir {
- oneFileEpInfo.SubAlreadyDownloadedList = append(oneFileEpInfo.SubAlreadyDownloadedList, subInfo)
- }
- }
- EpisodeDict[epsKey] = oneFileEpInfo
- } else {
- // 存在则跳过
- return
- }
- return
- }
|