| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 | 
							- package sub_timeline_fixer
 
- import (
 
- 	"errors"
 
- 	"math"
 
- 	"os"
 
- 	"github.com/allanpk716/ChineseSubFinder/pkg/types/subparser"
 
- 	"github.com/allanpk716/ChineseSubFinder/pkg/ffmpeg_helper"
 
- 	"github.com/allanpk716/ChineseSubFinder/pkg/logic/sub_parser/ass"
 
- 	"github.com/allanpk716/ChineseSubFinder/pkg/logic/sub_parser/srt"
 
- 	"github.com/allanpk716/ChineseSubFinder/pkg/my_util"
 
- 	"github.com/allanpk716/ChineseSubFinder/pkg/settings"
 
- 	"github.com/allanpk716/ChineseSubFinder/pkg/sub_parser_hub"
 
- 	"github.com/allanpk716/ChineseSubFinder/pkg/sub_timeline_fixer"
 
- 	"github.com/allanpk716/ChineseSubFinder/pkg/vad"
 
- 	"github.com/emirpasic/gods/maps/treemap"
 
- 	"github.com/emirpasic/gods/utils"
 
- 	"github.com/sirupsen/logrus"
 
- )
 
- type SubTimelineFixerHelperEx struct {
 
- 	log                 *logrus.Logger
 
- 	ffmpegHelper        *ffmpeg_helper.FFMPEGHelper
 
- 	subParserHub        *sub_parser_hub.SubParserHub
 
- 	timelineFixPipeLine *sub_timeline_fixer.Pipeline
 
- 	fixerConfig         settings.TimelineFixerSettings
 
- 	needDownloadFFMPeg  bool
 
- }
 
- func NewSubTimelineFixerHelperEx(log *logrus.Logger, fixerConfig settings.TimelineFixerSettings) *SubTimelineFixerHelperEx {
 
- 	fixerConfig.Check()
 
- 	return &SubTimelineFixerHelperEx{
 
- 		log:                 log,
 
- 		ffmpegHelper:        ffmpeg_helper.NewFFMPEGHelper(log),
 
- 		subParserHub:        sub_parser_hub.NewSubParserHub(log, ass.NewParser(log), srt.NewParser(log)),
 
- 		timelineFixPipeLine: sub_timeline_fixer.NewPipeline(fixerConfig.MaxOffsetTime),
 
- 		fixerConfig:         fixerConfig,
 
- 		needDownloadFFMPeg:  false,
 
- 	}
 
- }
 
- // Check 是否安装了 ffmpeg 和 ffprobe
 
- func (s *SubTimelineFixerHelperEx) Check() bool {
 
- 	version, err := s.ffmpegHelper.Version()
 
- 	if err != nil {
 
- 		s.needDownloadFFMPeg = false
 
- 		s.log.Errorln("Need Install ffmpeg and ffprobe !")
 
- 		return false
 
- 	}
 
- 	s.needDownloadFFMPeg = true
 
- 	s.log.Infoln(version)
 
- 	return true
 
- }
 
- func (s SubTimelineFixerHelperEx) Process(videoFileFullPath, srcSubFPath string) error {
 
- 	if s.needDownloadFFMPeg == false {
 
- 		s.log.Errorln("Need Install ffmpeg and ffprobe, Can't Do TimeLine Fix")
 
- 		return nil
 
- 	}
 
- 	var infoSrc *subparser.FileInfo
 
- 	var pipeResultMax sub_timeline_fixer.PipeResult
 
- 	bProcess := false
 
- 	bok := false
 
- 	var ffmpegInfo *ffmpeg_helper.FFMPEGInfo
 
- 	var err error
 
- 	// 先尝试获取内置字幕的信息
 
- 	bok, ffmpegInfo, err = s.ffmpegHelper.GetFFMPEGInfo(videoFileFullPath, ffmpeg_helper.Subtitle)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	if bok == false {
 
- 		return errors.New("SubTimelineFixerHelperEx.Process.GetFFMPEGInfo = false Subtitle -- " + videoFileFullPath)
 
- 	}
 
- 	// 这个需要提前考虑,如果只有一个内置的字幕,且这个字幕的大小小于 2kb,那么认为这个字幕是有问题的,就直接切换到 audio 校正
 
- 	oneSubAndIsError := false
 
- 	if len(ffmpegInfo.SubtitleInfoList) == 1 {
 
- 		fi, err := os.Stat(ffmpegInfo.SubtitleInfoList[0].FullPath)
 
- 		if err != nil {
 
- 			oneSubAndIsError = true
 
- 		} else {
 
- 			if fi.Size() <= 2048 {
 
- 				oneSubAndIsError = true
 
- 			}
 
- 		}
 
- 	}
 
- 	// 内置的字幕,这里只列举一种格式出来,其实会有一个字幕的 srt 和 ass 两种格式都导出存在
 
- 	if ffmpegInfo.SubtitleInfoList == nil || len(ffmpegInfo.SubtitleInfoList) <= 0 || oneSubAndIsError == true {
 
- 		if ffmpegInfo.AudioInfoList == nil || len(ffmpegInfo.AudioInfoList) == 0 {
 
- 			return errors.New("SubTimelineFixerHelperEx.Process.GetFFMPEGInfo Can`t Find SubTitle And Audio To Export -- " + videoFileFullPath)
 
- 		}
 
- 		// 如果内置字幕没有,那么就需要尝试获取音频信息
 
- 		bok, ffmpegInfo, err = s.ffmpegHelper.GetFFMPEGInfo(videoFileFullPath, ffmpeg_helper.Audio)
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 		if bok == false {
 
- 			return errors.New("SubTimelineFixerHelperEx.Process.GetFFMPEGInfo = false Audio -- " + videoFileFullPath)
 
- 		}
 
- 		// 使用音频进行时间轴的校正
 
- 		if len(ffmpegInfo.AudioInfoList) <= 0 {
 
- 			s.log.Warnln("Can`t find audio info, skip time fix --", videoFileFullPath)
 
- 			return nil
 
- 		}
 
- 		bProcess, infoSrc, pipeResultMax, err = s.processByAudio(ffmpegInfo.AudioInfoList[0].FullPath, srcSubFPath)
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 	} else {
 
- 		// 使用内置的字幕进行时间轴的校正,这里需要考虑一个问题,内置的字幕可能是有问题的(先考虑一种,就是字幕的长度不对,是一小段的)
 
- 		// 那么就可以比较多个内置字幕的大小选择大的去使用
 
- 		// 如果有多个内置的字幕,还是要判断下的,选体积最大的那个吧
 
- 		fileSizes := treemap.NewWith(utils.Int64Comparator)
 
- 		for index, info := range ffmpegInfo.SubtitleInfoList {
 
- 			fi, err := os.Stat(info.FullPath)
 
- 			if err != nil {
 
- 				fileSizes.Put(0, index)
 
- 			} else {
 
- 				fileSizes.Put(fi.Size(), index)
 
- 			}
 
- 		}
 
- 		_, index := fileSizes.Max()
 
- 		baseSubFPath := ffmpegInfo.SubtitleInfoList[index.(int)].FullPath
 
- 		bProcess, infoSrc, pipeResultMax, err = s.processBySub(baseSubFPath, srcSubFPath)
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 	}
 
- 	// 开始调整字幕时间轴
 
- 	if bProcess == false || math.Abs(pipeResultMax.GetOffsetTime()) < s.fixerConfig.MinOffset {
 
- 		s.log.Infoln("Skip TimeLine Fix -- OffsetTime:", pipeResultMax.GetOffsetTime(), srcSubFPath)
 
- 		return nil
 
- 	}
 
- 	err = s.changeTimeLineAndSave(infoSrc, pipeResultMax, srcSubFPath)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	s.log.Infoln("Fix Offset:", pipeResultMax.GetOffsetTime(), srcSubFPath)
 
- 	s.log.Infoln("BackUp Org SubFile:", pipeResultMax.GetOffsetTime(), srcSubFPath+sub_timeline_fixer.BackUpExt)
 
- 	return nil
 
- }
 
- func (s SubTimelineFixerHelperEx) processBySub(baseSubFileFPath, srcSubFileFPath string) (bool, *subparser.FileInfo, sub_timeline_fixer.PipeResult, error) {
 
- 	bFind, infoBase, err := s.subParserHub.DetermineFileTypeFromFile(baseSubFileFPath)
 
- 	if err != nil {
 
- 		return false, nil, sub_timeline_fixer.PipeResult{}, err
 
- 	}
 
- 	if bFind == false {
 
- 		s.log.Warnln("processBySub.DetermineFileTypeFromFile sub not match --", baseSubFileFPath)
 
- 		return false, nil, sub_timeline_fixer.PipeResult{}, nil
 
- 	}
 
- 	bFind, infoSrc, err := s.subParserHub.DetermineFileTypeFromFile(srcSubFileFPath)
 
- 	if err != nil {
 
- 		return false, nil, sub_timeline_fixer.PipeResult{}, err
 
- 	}
 
- 	if bFind == false {
 
- 		s.log.Warnln("processBySub.DetermineFileTypeFromFile sub not match --", srcSubFileFPath)
 
- 		return false, nil, sub_timeline_fixer.PipeResult{}, nil
 
- 	}
 
- 	// ---------------------------------------------------------------------------------------
 
- 	pipeResult, err := s.timelineFixPipeLine.CalcOffsetTime(infoBase, infoSrc, nil, false)
 
- 	if err != nil {
 
- 		return false, nil, sub_timeline_fixer.PipeResult{}, err
 
- 	}
 
- 	return true, infoSrc, pipeResult, nil
 
- }
 
- func (s SubTimelineFixerHelperEx) processByAudio(baseAudioFileFPath, srcSubFileFPath string) (bool, *subparser.FileInfo, sub_timeline_fixer.PipeResult, error) {
 
- 	audioVADInfos, err := vad.GetVADInfoFromAudio(vad.AudioInfo{
 
- 		FileFullPath: baseAudioFileFPath,
 
- 		SampleRate:   16000,
 
- 		BitDepth:     16,
 
- 	}, true)
 
- 	if err != nil {
 
- 		return false, nil, sub_timeline_fixer.PipeResult{}, err
 
- 	}
 
- 	bFind, infoSrc, err := s.subParserHub.DetermineFileTypeFromFile(srcSubFileFPath)
 
- 	if err != nil {
 
- 		return false, nil, sub_timeline_fixer.PipeResult{}, err
 
- 	}
 
- 	if bFind == false {
 
- 		s.log.Warnln("processByAudio.DetermineFileTypeFromFile sub not match --", srcSubFileFPath)
 
- 		return false, nil, sub_timeline_fixer.PipeResult{}, nil
 
- 	}
 
- 	// ---------------------------------------------------------------------------------------
 
- 	pipeResult, err := s.timelineFixPipeLine.CalcOffsetTime(nil, infoSrc, audioVADInfos, false)
 
- 	if err != nil {
 
- 		return false, nil, sub_timeline_fixer.PipeResult{}, err
 
- 	}
 
- 	return true, infoSrc, pipeResult, nil
 
- }
 
- func (s SubTimelineFixerHelperEx) changeTimeLineAndSave(infoSrc *subparser.FileInfo, pipeResult sub_timeline_fixer.PipeResult, desSubSaveFPath string) error {
 
- 	/*
 
- 		修复的字幕先存放到缓存目录,然后需要把原有的字幕进行“备份”,改名,然后再替换过来
 
- 	*/
 
- 	subFileName := desSubSaveFPath + sub_timeline_fixer.TmpExt
 
- 	if my_util.IsFile(subFileName) == true {
 
- 		err := os.Remove(subFileName)
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 	}
 
- 	_, err := s.timelineFixPipeLine.FixSubFileTimeline(infoSrc, pipeResult.ScaledFileInfo, pipeResult.GetOffsetTime(), subFileName)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	if my_util.IsFile(desSubSaveFPath+sub_timeline_fixer.BackUpExt) == true {
 
- 		err = os.Remove(desSubSaveFPath + sub_timeline_fixer.BackUpExt)
 
- 		if err != nil {
 
- 			return err
 
- 		}
 
- 	}
 
- 	err = os.Rename(desSubSaveFPath, desSubSaveFPath+sub_timeline_fixer.BackUpExt)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	err = os.Rename(subFileName, desSubSaveFPath)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	return nil
 
- }
 
 
  |