| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- package csf
- import (
- "errors"
- "fmt"
- "io/ioutil"
- "os"
- "path/filepath"
- "strconv"
- "strings"
- "time"
- "github.com/allanpk716/ChineseSubFinder/internal/pkg/logic/file_downloader"
- "github.com/allanpk716/ChineseSubFinder/internal/pkg/my_folder"
- "github.com/allanpk716/ChineseSubFinder/internal/types/subparser"
- "github.com/allanpk716/ChineseSubFinder/internal/pkg/subtitle_best_api"
- "github.com/allanpk716/ChineseSubFinder/internal/pkg/my_util"
- "github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_file_hash"
- "github.com/allanpk716/ChineseSubFinder/internal/pkg/mix_media_info"
- "github.com/allanpk716/ChineseSubFinder/internal/pkg/settings"
- 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"
- )
- type Supplier struct {
- settings *settings.Settings
- log *logrus.Logger
- fileDownloader *file_downloader.FileDownloader
- topic int
- isAlive bool
- }
- func NewSupplier(fileDownloader *file_downloader.FileDownloader) *Supplier {
- sup := Supplier{}
- sup.log = fileDownloader.Log
- sup.fileDownloader = fileDownloader
- sup.topic = common2.DownloadSubsPerSite
- sup.isAlive = true // 默认是可以使用的,如果 check 后,再调整状态
- sup.settings = fileDownloader.Settings
- if sup.settings.AdvancedSettings.Topic > 0 && sup.settings.AdvancedSettings.Topic != sup.topic {
- sup.topic = sup.settings.AdvancedSettings.Topic
- }
- return &sup
- }
- func (s *Supplier) CheckAlive() (bool, int64) {
- // 计算当前时间
- startT := time.Now()
- _, err := s.fileDownloader.SubtitleBestApi.GetMediaInfo("tt4236770", "imdb", "series")
- if err != nil {
- s.log.Errorln(s.GetSupplierName(), "CheckAlive", "Error", err)
- s.isAlive = false
- return false, 0
- }
- s.isAlive = true
- return true, time.Since(startT).Milliseconds()
- }
- func (s *Supplier) IsAlive() bool {
- return s.isAlive
- }
- func (s *Supplier) OverDailyDownloadLimit() bool {
- if s.settings.AdvancedSettings.SuppliersSettings.ChineseSubFinder.DailyDownloadLimit == 0 {
- s.log.Warningln(s.GetSupplierName(), "DailyDownloadLimit is 0, will Skip Download")
- return true
- }
- // 对于这个接口暂时没有限制
- return false
- }
- func (s *Supplier) GetLogger() *logrus.Logger {
- return s.log
- }
- func (s *Supplier) GetSettings() *settings.Settings {
- return s.settings
- }
- func (s *Supplier) GetSupplierName() string {
- return common2.SubSiteChineseSubFinder
- }
- func (s *Supplier) GetSubListFromFile4Movie(filePath string) ([]supplier.SubInfo, error) {
- outSubInfos := make([]supplier.SubInfo, 0)
- if s.settings.ExperimentalFunction.ShareSubSettings.ShareSubEnabled == false {
- return outSubInfos, nil
- }
- return s.findAndDownload(filePath, true, 0, 0)
- }
- func (s *Supplier) GetSubListFromFile4Series(seriesInfo *series.SeriesInfo) ([]supplier.SubInfo, error) {
- outSubInfos := make([]supplier.SubInfo, 0)
- if s.settings.ExperimentalFunction.ShareSubSettings.ShareSubEnabled == false {
- return outSubInfos, nil
- }
- // 这里拿到的 seriesInfo ,里面包含了,需要下载字幕的 Eps 信息
- for _, episodeInfo := range seriesInfo.NeedDlEpsKeyList {
- oneSubInfoList, err := s.findAndDownload(episodeInfo.FileFullPath, false, episodeInfo.Season, episodeInfo.Episode)
- if err != nil {
- return outSubInfos, errors.New("FindAndDownload error:" + err.Error())
- }
- outSubInfos = append(outSubInfos, oneSubInfoList...)
- }
- return outSubInfos, nil
- }
- func (s *Supplier) GetSubListFromFile4Anime(seriesInfo *series.SeriesInfo) ([]supplier.SubInfo, error) {
- outSubInfos := make([]supplier.SubInfo, 0)
- if s.settings.ExperimentalFunction.ShareSubSettings.ShareSubEnabled == false {
- return outSubInfos, nil
- }
- // 这里拿到的 seriesInfo ,里面包含了,需要下载字幕的 Eps 信息
- for _, episodeInfo := range seriesInfo.NeedDlEpsKeyList {
- oneSubInfoList, err := s.findAndDownload(episodeInfo.FileFullPath, false, episodeInfo.Season, episodeInfo.Episode)
- if err != nil {
- return outSubInfos, errors.New("FindAndDownload error:" + err.Error())
- }
- outSubInfos = append(outSubInfos, oneSubInfoList...)
- }
- return outSubInfos, nil
- }
- func (s *Supplier) findAndDownload(videoFPath string, isMovie bool, Season, Episode int) (outSubInfoList []supplier.SubInfo, err error) {
- defer func() {
- s.log.Debugln(s.GetSupplierName(), videoFPath, "End...")
- }()
- s.log.Debugln(s.GetSupplierName(), videoFPath, "Start...")
- outSubInfoList = make([]supplier.SubInfo, 0)
- fileHash, err := sub_file_hash.Calculate(videoFPath)
- if err != nil {
- err = errors.New(fmt.Sprintf("%s.Calculate %s %s", s.GetSupplierName(), videoFPath, err))
- return
- }
- mediaInfo, err := mix_media_info.GetMixMediaInfo(s.log, s.fileDownloader.SubtitleBestApi, videoFPath, isMovie, s.settings.AdvancedSettings.ProxySettings)
- if err != nil {
- err = errors.New(fmt.Sprintf("%s.GetMixMediaInfo %s %s", s.GetSupplierName(), videoFPath, err))
- return
- }
- if isMovie == true {
- Season = 0
- Episode = 0
- }
- // 标记本次请求的归属性
- randomAuthToken := my_util.RandStringBytesMaskImprSrcSB(10)
- var bestOneSub subtitle_best_api.Subtitle
- var queueIsFull bool
- var waitTime int64
- reTryTimes := 0
- const maxRetryTimes = 5
- retryFail := false
- // 重试多次排队
- for {
- reTryTimes++
- if reTryTimes > maxRetryTimes {
- // 超过了最大重试次数,直接返回
- retryFail = true
- break
- }
- bestOneSub, queueIsFull, waitTime, err = s.askFindSubProcess(fileHash, mediaInfo.ImdbId, mediaInfo.TmdbId, Season, Episode, randomAuthToken, "")
- if err != nil {
- return nil, errors.New(fmt.Sprintf("askFindSubProcess Error: %s", err.Error()))
- }
- if queueIsFull == true {
- // 队列满了,需要等待再次重试
- time.Sleep(5 * time.Second)
- continue
- }
- // 没有错误,没有队列满,可以继续
- break
- }
- if retryFail == true {
- // 没有等待时间,直接返回
- s.log.Warningln("ask find queue is full, over max retry times, skip this time")
- return
- }
- if bestOneSub.SubSha256 != "" {
- // 说明查询的时候名中了缓存,无需往下继续查询,直接去排队下载即可
- } else {
- // 没有命中缓存,需要主动去查询
- // 等待一定的时间去查询
- if waitTime <= 0 {
- waitTime = 5
- }
- s.log.Infoln("will wait", waitTime, "s 2 ask find sub")
- // 等待耗时的动作
- var sleepCounter int64
- sleepCounter = 0
- for true {
- if sleepCounter > waitTime {
- break
- }
- if sleepCounter%30 == 0 {
- s.log.Infoln("wait 2 ask find sub")
- }
- time.Sleep(1 * time.Second)
- sleepCounter++
- }
- // 直接查询
- findSubReply, err := s.fileDownloader.SubtitleBestApi.FindSub(fileHash, mediaInfo.ImdbId, mediaInfo.TmdbId, strconv.Itoa(Season), strconv.Itoa(Episode), randomAuthToken, "")
- if err != nil {
- return nil, errors.New(fmt.Sprintf("FindSub Error: %s", err.Error()))
- }
- if len(findSubReply.Subtitle) < 1 {
- s.log.Warningln("FindSub Error: no sub found")
- return outSubInfoList, nil
- }
- bestOneSub = s.findBestSub(findSubReply.Subtitle)
- }
- tmpFolder, err := my_folder.GetRootTmpFolder()
- if err != nil {
- return nil, errors.New(fmt.Sprintf("GetRootTmpFolder Error: %s", err.Error()))
- }
- desSubSaveFPath := filepath.Join(tmpFolder, bestOneSub.SubSha256+bestOneSub.Ext)
- foundSubCache, cacheSubInfo, err := s.fileDownloader.GetCSF(bestOneSub.SubSha256)
- if err != nil {
- return nil, errors.New(fmt.Sprintf("GetCSF Error: %s", err.Error()))
- }
- if foundSubCache == true {
- // 在本地缓存中找到了
- cacheSubInfo.Season = Season
- cacheSubInfo.Episode = Episode
- outSubInfoList = append(outSubInfoList, *cacheSubInfo)
- return
- }
- // 需要从服务器拿去
- // 得到查询结果,去排队下载
- reTryTimes = 0
- retryFail = false
- // 重试多次排队
- for {
- reTryTimes++
- if reTryTimes > maxRetryTimes {
- // 超过了最大重试次数,直接返回
- retryFail = true
- break
- }
- queueIsFull, waitTime, err = s.askDownloadSubProcess(bestOneSub.SubSha256, randomAuthToken, "")
- if err != nil {
- err = errors.New(fmt.Sprintf("AskDownloadSub Error: %s", err.Error()))
- return
- }
- if queueIsFull == true {
- // 队列满了,需要等待再次重试
- time.Sleep(5 * time.Second)
- continue
- }
- // 没有错误,没有队列满,可以继续
- break
- }
- if retryFail == true {
- // 没有等待时间,直接返回
- s.log.Warningln("ask download queue is full, over max retry times, skip this time")
- return
- }
- // 等待一定的时间去查询
- if waitTime <= 0 {
- waitTime = 5
- }
- s.log.Infoln("will wait", waitTime, "s 2 ask download sub")
- // 等待耗时的动作
- var sleepCounter int64
- sleepCounter = 0
- for true {
- if sleepCounter > waitTime {
- break
- }
- if sleepCounter%30 == 0 {
- s.log.Infoln("wait 2 ask download sub")
- }
- time.Sleep(1 * time.Second)
- sleepCounter++
- }
- // 直接下载,这里需要再前面的过程中搞清楚这个字幕是什么后缀名,然后写入到缓存目录中
- downloadSubReply, err := s.fileDownloader.SubtitleBestApi.DownloadSub(bestOneSub.SubSha256, randomAuthToken, "", desSubSaveFPath)
- if err != nil {
- return nil, errors.New(fmt.Sprintf("DownloadSub Error: %s", err.Error()))
- }
- if downloadSubReply.Status == 0 {
- // 下载失败了
- err = errors.New(fmt.Sprintf("DownloadSub Error: %s", downloadSubReply.Message))
- return
- } else if downloadSubReply.Status == 1 {
- // 下载成功
- } else {
- // 不支持的返回值
- err = errors.New(fmt.Sprintf("DownloadSub Not Support Status: %d, Message: %s", downloadSubReply.Status, downloadSubReply.Message))
- return
- }
- // 下载成功后,需要判断一下这里的文件是否是字幕文件,如果不是,需要删除掉,然后跳过
- bok := false
- var subFileInfo *subparser.FileInfo
- bok, subFileInfo, err = s.fileDownloader.SubParserHub.DetermineFileTypeFromFile(desSubSaveFPath)
- if err != nil {
- return nil, errors.New(fmt.Sprintf("DetermineFileTypeFromFile Error: %s", err.Error()))
- }
- if bok == false {
- // 不是字幕文件,需要删除掉
- err = os.Remove(desSubSaveFPath)
- if err != nil {
- return nil, errors.New(fmt.Sprintf("Remove File %s Error: %s", desSubSaveFPath, err.Error()))
- }
- }
- subFileName := strings.ReplaceAll(filepath.Base(videoFPath), filepath.Ext(videoFPath), "")
- subBytes, err := ioutil.ReadFile(desSubSaveFPath)
- if err != nil {
- return nil, errors.New(fmt.Sprintf("ReadFile Error: %s", err.Error()))
- }
- oneSubInfo := supplier.NewSubInfo(s.GetSupplierName(), 1, subFileName, subFileInfo.Lang, bestOneSub.SubSha256, 0, 0, bestOneSub.Ext, subBytes)
- oneSubInfo.Season = Season
- oneSubInfo.Episode = Episode
- err = s.fileDownloader.AddCSF(oneSubInfo)
- if err != nil {
- return nil, errors.New(fmt.Sprintf("AddCSF Error: %s", err.Error()))
- }
- outSubInfoList = append(outSubInfoList, *oneSubInfo)
- return
- }
- // askFindSubProcess 查找字幕
- func (s *Supplier) askFindSubProcess(VideoFeature, ImdbId, TmdbId string, Season, Episode int, FindSubToken, ApiKey string) (bestOneSub subtitle_best_api.Subtitle, queueIsFull bool, waitTime int64, err error) {
- // 开始排队查询
- askFindSubReply, err := s.fileDownloader.SubtitleBestApi.AskFindSub(VideoFeature, ImdbId, TmdbId, strconv.Itoa(Season), strconv.Itoa(Episode), FindSubToken, ApiKey)
- if err != nil {
- err = errors.New(fmt.Sprintf("AskFindSub Error: %s", err.Error()))
- return
- }
- if askFindSubReply.Status == 0 {
- err = errors.New(fmt.Sprintf("AskFindSub Error: %s", askFindSubReply.Message))
- return
- } else if askFindSubReply.Status == 1 {
- // 成功,查询到了字幕列表(缓存有的)
- if len(askFindSubReply.Subtitle) < 1 {
- // 查询到了,但是返回的列表是空的,也直接返回
- return
- }
- // 那么获取到了字幕列表,接下来就要去排队请求这个字幕
- /*
- 每个返回的字幕中有两个特别的字段
- 1. match_video_feature,是否匹配传入的视频特征
- 2. low_trust,是否是低可信
- */
- bestOneSub = s.findBestSub(askFindSubReply.Subtitle)
- return
- } else if askFindSubReply.Status == 2 {
- // 放入队列,或者已经在队列中了,根据服务器安排的时间去请求排队下载
- // 得到目标时间与当前时间的差值,单位是s
- waitTime = askFindSubReply.ScheduledUnixTime - time.Now().Unix()
- return
- } else if askFindSubReply.Status == 3 {
- // 查询的队列满了
- queueIsFull = true
- return
- } else {
- // 不支持的返回值
- err = errors.New(fmt.Sprintf("AskFindSub Not Support Status: %d, Message: %s", askFindSubReply.Status, askFindSubReply.Message))
- return
- }
- }
- // askDownloadSubProcess 下载排队
- func (s *Supplier) askDownloadSubProcess(SubSha256, DownloadSubToken, ApiKey string) (queueIsFull bool, waitTime int64, err error) {
- askDownloadSubReply, err := s.fileDownloader.SubtitleBestApi.AskDownloadSub(SubSha256, DownloadSubToken, ApiKey)
- if err != nil {
- err = errors.New(fmt.Sprintf("AskDownloadSub Error: %s", err.Error()))
- return
- }
- if askDownloadSubReply.Status == 0 {
- err = errors.New(fmt.Sprintf("AskDownloadSub Error: %s", askDownloadSubReply.Message))
- return
- } else if askDownloadSubReply.Status == 2 {
- // 放入队列,或者已在队列中,根据等待的时间再去下载即可
- waitTime = askDownloadSubReply.ScheduledUnixTime - time.Now().Unix()
- return
- } else if askDownloadSubReply.Status == 3 {
- // 队列满了
- queueIsFull = true
- return
- } else {
- // 不应该出现 status = 1 的情况,这个先不改了,懒
- // 其他情况也是
- // 不支持的返回值
- err = errors.New(fmt.Sprintf("AskFindSub Not Support Status: %d, Message: %s", askDownloadSubReply.Status, askDownloadSubReply.Message))
- return
- }
- }
- func (s *Supplier) findBestSub(subtitles []subtitle_best_api.Subtitle) (bestOneSub subtitle_best_api.Subtitle) {
- found := false
- for _, subtitle := range subtitles {
- if subtitle.MatchVideoFeature == true && subtitle.LowTrust == false {
- // 匹配视频 且 高可信
- bestOneSub = subtitle
- found = true
- s.log.Infoln("Find Best Subtitle, MatchVideoFeature == true and HighTrust", subtitle.SubSha256)
- break
- }
- }
- if found == false {
- // 没有找到,那么就按照高可信来查询
- for _, subtitle := range subtitles {
- if subtitle.LowTrust == false {
- // 高可信
- bestOneSub = subtitle
- found = true
- s.log.Infoln("Find Best Subtitle, HighTrust", subtitle.SubSha256)
- break
- }
- }
- }
- if found == false {
- // 没有找到,那么就按照高视频匹配的来查询
- for _, subtitle := range subtitles {
- if subtitle.MatchVideoFeature == false {
- // 匹配视频
- bestOneSub = subtitle
- s.log.Infoln("Find Best Subtitle, MatchVideoFeature == true", subtitle.SubSha256)
- found = true
- break
- }
- }
- }
- if found == false {
- // 上面的都没触发,那么就返回第一个字幕吧
- bestOneSub = subtitles[0]
- s.log.Infoln("Find Best Subtitle, LowTrust", bestOneSub.SubSha256)
- }
- return
- }
|