瀏覽代碼

调整ing

Signed-off-by: allan716 <[email protected]>
allan716 3 年之前
父節點
當前提交
77c39ff1b2

+ 22 - 22
internal/downloader_test.go

@@ -9,15 +9,15 @@ import (
 
 
 func TestDownloader_DownloadSub4Movie(t *testing.T) {
 func TestDownloader_DownloadSub4Movie(t *testing.T) {
 	var err error
 	var err error
-	//dirRoot := "X:\\电影\\Spiral From the Book of Saw (2021)"
-	//dirRoot := "X:\\电影\\Oslo (2021)"
-	//dirRoot := "X:\\电影\\The Devil All the Time (2020)"
-	//dirRoot := "X:\\电影\\21座桥 (2019)"
-	//dirRoot := "X:\\电影\\An Invisible Sign (2010)"
-	//dirRoot := "X:\\电影\\送你一朵小红花 (2020)"
-	//dirRoot := "X:\\电影\\冰海陷落 (2018)"
-	dirRoot := "X:\\电影\\The Boss Baby Family Business (2021)"
-	//dirRoot := "X:\\电影"
+	//dirRoot := "XLen:\\电影\\Spiral From the Book of Saw (2021)"
+	//dirRoot := "XLen:\\电影\\Oslo (2021)"
+	//dirRoot := "XLen:\\电影\\The Devil All the Time (2020)"
+	//dirRoot := "XLen:\\电影\\21座桥 (2019)"
+	//dirRoot := "XLen:\\电影\\An Invisible Sign (2010)"
+	//dirRoot := "XLen:\\电影\\送你一朵小红花 (2020)"
+	//dirRoot := "XLen:\\电影\\冰海陷落 (2018)"
+	dirRoot := "XLen:\\电影\\The Boss Baby Family Business (2021)"
+	//dirRoot := "XLen:\\电影"
 	config := config.GetConfig()
 	config := config.GetConfig()
 	dl := NewDownloader(sub_formatter.GetSubFormatter(config.SubNameFormatter), types.ReqParam{
 	dl := NewDownloader(sub_formatter.GetSubFormatter(config.SubNameFormatter), types.ReqParam{
 		SaveMultiSub:    true,
 		SaveMultiSub:    true,
@@ -36,21 +36,21 @@ func TestDownloader_DownloadSub4Movie(t *testing.T) {
 
 
 func TestDownloader_DownloadSub4Series(t *testing.T) {
 func TestDownloader_DownloadSub4Series(t *testing.T) {
 	var err error
 	var err error
-	//dirRoot := "X:\\连续剧\\隐秘的角落 (2020)"
-	//dirRoot := "X:\\连续剧\\The Bad Batch"
-	//dirRoot := "X:\\连续剧\\Loki"
-	//dirRoot := "X:\\连续剧\\豪斯医生 (2004)"
-	//dirRoot := "X:\\连续剧\\Why Women Kill"
-	//dirRoot := "X:\\连续剧\\Mare of Easttown"
-	//dirRoot := "X:\\连续剧\\瑞克和莫蒂 (2013)"
-	//dirRoot := "X:\\连续剧\\黑钱胜地 (2017)"
-	//dirRoot := "X:\\连续剧\\黑道家族 (1999)"
-	//dirRoot := "X:\\连续剧\\黑镜 (2011)"
-	//dirRoot := "X:\\连续剧\\黄石 (2018)"
-	dirRoot := "X:\\连续剧\\少年间谍 (2020)"
+	//dirRoot := "XLen:\\连续剧\\隐秘的角落 (2020)"
+	//dirRoot := "XLen:\\连续剧\\The Bad Batch"
+	//dirRoot := "XLen:\\连续剧\\Loki"
+	//dirRoot := "XLen:\\连续剧\\豪斯医生 (2004)"
+	//dirRoot := "XLen:\\连续剧\\Why Women Kill"
+	//dirRoot := "XLen:\\连续剧\\Mare of Easttown"
+	//dirRoot := "XLen:\\连续剧\\瑞克和莫蒂 (2013)"
+	//dirRoot := "XLen:\\连续剧\\黑钱胜地 (2017)"
+	//dirRoot := "XLen:\\连续剧\\黑道家族 (1999)"
+	//dirRoot := "XLen:\\连续剧\\黑镜 (2011)"
+	//dirRoot := "XLen:\\连续剧\\黄石 (2018)"
+	dirRoot := "XLen:\\连续剧\\少年间谍 (2020)"
 
 
 	config := config.GetConfig()
 	config := config.GetConfig()
-	// 如果需要调试 Emby 一定需要 dirRoot := "X:\\连续剧"
+	// 如果需要调试 Emby 一定需要 dirRoot := "XLen:\\连续剧"
 	dl := NewDownloader(sub_formatter.GetSubFormatter(config.SubNameFormatter), types.ReqParam{
 	dl := NewDownloader(sub_formatter.GetSubFormatter(config.SubNameFormatter), types.ReqParam{
 		SaveMultiSub:    true,
 		SaveMultiSub:    true,
 		SubTypePriority: 1,
 		SubTypePriority: 1,

+ 2 - 2
internal/logic/series_helper/seriesHelper_test.go

@@ -6,8 +6,8 @@ import (
 
 
 func TestReadSeriesInfoFromDir(t *testing.T) {
 func TestReadSeriesInfoFromDir(t *testing.T) {
 
 
-	series := "X:\\连续剧\\杀死伊芙 (2018)"
-	//series := "X:\\连续剧\\Money.Heist"
+	series := "XLen:\\连续剧\\杀死伊芙 (2018)"
+	//series := "XLen:\\连续剧\\Money.Heist"
 
 
 	seriesInfo, err := ReadSeriesInfoFromDir(series, nil, false)
 	seriesInfo, err := ReadSeriesInfoFromDir(series, nil, false)
 	if err != nil {
 	if err != nil {

+ 28 - 6
internal/logic/sub_parser/ass/ass.go

@@ -51,13 +51,14 @@ func (p Parser) DetermineFileTypeFromBytes(inBytes []byte, nowExt string) (bool,
 	// 找到 start end text
 	// 找到 start end text
 	matched := regex_things.ReMatchDialogueASS.FindAllStringSubmatch(allString, -1)
 	matched := regex_things.ReMatchDialogueASS.FindAllStringSubmatch(allString, -1)
 	if matched == nil || len(matched) < 1 {
 	if matched == nil || len(matched) < 1 {
-		log_helper.GetLogger().Debugln("DetermineFileTypeFromBytes can't found Dialogues, Skip")
+		log_helper.GetLogger().Debugln("DetermineFileTypeFromBytes can't found DialoguesFilter, Skip")
 		return false, nil, nil
 		return false, nil, nil
 	}
 	}
 	subFileInfo := subparser.FileInfo{}
 	subFileInfo := subparser.FileInfo{}
 	subFileInfo.Content = string(inBytes)
 	subFileInfo.Content = string(inBytes)
 	subFileInfo.Ext = nowExt
 	subFileInfo.Ext = nowExt
 	subFileInfo.Dialogues = make([]subparser.OneDialogue, 0)
 	subFileInfo.Dialogues = make([]subparser.OneDialogue, 0)
+	subFileInfo.DialoguesFilter = make([]subparser.OneDialogue, 0)
 	// 这里需要统计一共有几个 \N,以及这个数量在整体行数中的比例,这样就知道是不是双语字幕了
 	// 这里需要统计一共有几个 \N,以及这个数量在整体行数中的比例,这样就知道是不是双语字幕了
 	countLineFeed := 0
 	countLineFeed := 0
 	// 有意义的对话统计数,排除 Style 类型
 	// 有意义的对话统计数,排除 Style 类型
@@ -94,6 +95,10 @@ func (p Parser) DetermineFileTypeFromBytes(inBytes []byte, nowExt string) (bool,
 		如果没有那么多,或者就没得。就任务是情况 1 的双语字幕,这个也不能说就是双语字幕,只不过走之前的逻辑就够了。
 		如果没有那么多,或者就没得。就任务是情况 1 的双语字幕,这个也不能说就是双语字幕,只不过走之前的逻辑就够了。
 	*/
 	*/
 	mapByValue := sortMapByValue(nameMap)
 	mapByValue := sortMapByValue(nameMap)
+
+	// 把所有的对白缓存下来,其实优先是把时间信息缓存,其他信息无所谓
+	p.oneLineSubDialogueParser0(matched, &subFileInfo)
+
 	if p.detectOneOrTwoLineDialogue(matched) == true {
 	if p.detectOneOrTwoLineDialogue(matched) == true {
 		// 情况1
 		// 情况1
 		usefullyDialogueCount, countLineFeed = p.oneLineSubDialogueParser1(matched, mapByValue, &subFileInfo)
 		usefullyDialogueCount, countLineFeed = p.oneLineSubDialogueParser1(matched, mapByValue, &subFileInfo)
@@ -111,21 +116,38 @@ func (p Parser) DetermineFileTypeFromBytes(inBytes []byte, nowExt string) (bool,
 	var otherLines = make([]string, 0)
 	var otherLines = make([]string, 0)
 	// 抽取出来的对话数组,为了后续用来匹配和修改时间轴
 	// 抽取出来的对话数组,为了后续用来匹配和修改时间轴
 	var usefulDialogueExs = make([]subparser.OneDialogueEx, 0)
 	var usefulDialogueExs = make([]subparser.OneDialogueEx, 0)
-	// 在这之前需要把 subFileInfo.Dialogues 的内容填好,Lines 这里如果是单种语言应该就是一个元素,如果是双语就需要拆分成两个元素
+	// 在这之前需要把 subFileInfo.DialoguesFilter 的内容填好,Lines 这里如果是单种语言应该就是一个元素,如果是双语就需要拆分成两个元素
 	// 这样向后传递就简单了,也统一了
 	// 这样向后传递就简单了,也统一了
-	for _, dialogue := range subFileInfo.Dialogues {
+	for _, dialogue := range subFileInfo.DialoguesFilter {
 		language.DetectSubLangAndStatistics(dialogue, langDict, &usefulDialogueExs, &chLines, &otherLines)
 		language.DetectSubLangAndStatistics(dialogue, langDict, &usefulDialogueExs, &chLines, &otherLines)
 	}
 	}
 	// 从统计出来的字典,找出 Top 1 或者 2 的出来,然后计算出是什么语言的字幕
 	// 从统计出来的字典,找出 Top 1 或者 2 的出来,然后计算出是什么语言的字幕
 	detectLang := language.SubLangStatistics2SubLangType(float32(countLineFeed), float32(usefullyDialogueCount), langDict, chLines)
 	detectLang := language.SubLangStatistics2SubLangType(float32(countLineFeed), float32(usefullyDialogueCount), langDict, chLines)
 	subFileInfo.Lang = detectLang
 	subFileInfo.Lang = detectLang
 	subFileInfo.Data = inBytes
 	subFileInfo.Data = inBytes
-	subFileInfo.DialoguesEx = usefulDialogueExs
+	subFileInfo.DialoguesFilterEx = usefulDialogueExs
 	subFileInfo.CHLines = chLines
 	subFileInfo.CHLines = chLines
 	subFileInfo.OtherLines = otherLines
 	subFileInfo.OtherLines = otherLines
 	return true, &subFileInfo, nil
 	return true, &subFileInfo, nil
 }
 }
 
 
+// oneLineSubDialogueParser0 情况 0 时候的解析器,不过滤,只要是对白都加进去
+func (p Parser) oneLineSubDialogueParser0(matched [][]string, subFileInfo *subparser.FileInfo) {
+
+	for _, oneLine := range matched {
+		startTime := oneLine[1]
+		endTime := oneLine[2]
+		nowStyleName := oneLine[3]
+		odl := subparser.OneDialogue{
+			StyleName: nowStyleName,
+			StartTime: startTime,
+			EndTime:   endTime,
+		}
+		odl.Lines = make([]string, 0)
+		subFileInfo.Dialogues = append(subFileInfo.Dialogues, odl)
+	}
+}
+
 // oneLineSubDialogueParser1 情况 1 时候的解析器
 // oneLineSubDialogueParser1 情况 1 时候的解析器
 func (p Parser) oneLineSubDialogueParser1(matched [][]string, mapByValue StyleNameInfos, subFileInfo *subparser.FileInfo) (int, int) {
 func (p Parser) oneLineSubDialogueParser1(matched [][]string, mapByValue StyleNameInfos, subFileInfo *subparser.FileInfo) (int, int) {
 
 
@@ -151,7 +173,7 @@ func (p Parser) oneLineSubDialogueParser1(matched [][]string, mapByValue StyleNa
 		odl.Lines = make([]string, 0)
 		odl.Lines = make([]string, 0)
 		countLineFeed = p.parseOneDialogueText(nowText, &odl, countLineFeed)
 		countLineFeed = p.parseOneDialogueText(nowText, &odl, countLineFeed)
 
 
-		subFileInfo.Dialogues = append(subFileInfo.Dialogues, odl)
+		subFileInfo.DialoguesFilter = append(subFileInfo.DialoguesFilter, odl)
 	}
 	}
 	return usefullyDialogueCount, countLineFeed
 	return usefullyDialogueCount, countLineFeed
 }
 }
@@ -196,7 +218,7 @@ func (p Parser) oneLineSubDialogueParser2(matched [][]string, mapByValue StyleNa
 
 
 	for _, value := range timeMap.Values() {
 	for _, value := range timeMap.Values() {
 		odl := value.(subparser.OneDialogue)
 		odl := value.(subparser.OneDialogue)
-		subFileInfo.Dialogues = append(subFileInfo.Dialogues, odl)
+		subFileInfo.DialoguesFilter = append(subFileInfo.DialoguesFilter, odl)
 	}
 	}
 
 
 	return usefullyDialogueCount, countLineFeed
 	return usefullyDialogueCount, countLineFeed

+ 5 - 3
internal/logic/sub_parser/srt/srt.go

@@ -54,7 +54,7 @@ func (p Parser) DetermineFileTypeFromBytes(inBytes []byte, nowExt string) (bool,
 	if matched == nil || len(matched) < 1 {
 	if matched == nil || len(matched) < 1 {
 		matched = regex_things.ReMatchDialogueSRT2.FindAllStringSubmatch(allString, -1)
 		matched = regex_things.ReMatchDialogueSRT2.FindAllStringSubmatch(allString, -1)
 		if matched == nil || len(matched) < 1 {
 		if matched == nil || len(matched) < 1 {
-			log_helper.GetLogger().Debugln("DetermineFileTypeFromBytes can't found Dialogues, Skip")
+			log_helper.GetLogger().Debugln("DetermineFileTypeFromBytes can't found DialoguesFilter, Skip")
 			return false, nil, nil
 			return false, nil, nil
 		}
 		}
 	}
 	}
@@ -62,6 +62,7 @@ func (p Parser) DetermineFileTypeFromBytes(inBytes []byte, nowExt string) (bool,
 	subFileInfo.Content = string(inBytes)
 	subFileInfo.Content = string(inBytes)
 	subFileInfo.Ext = nowExt
 	subFileInfo.Ext = nowExt
 	subFileInfo.Dialogues = make([]subparser.OneDialogue, 0)
 	subFileInfo.Dialogues = make([]subparser.OneDialogue, 0)
+	subFileInfo.DialoguesFilter = make([]subparser.OneDialogue, 0)
 	// 这里需要统计一共有几个 \N,以及这个数量在整体行数中的比例,这样就知道是不是双语字幕了
 	// 这里需要统计一共有几个 \N,以及这个数量在整体行数中的比例,这样就知道是不是双语字幕了
 	countLineFeed := 0
 	countLineFeed := 0
 	for _, oneDial := range matched {
 	for _, oneDial := range matched {
@@ -87,6 +88,7 @@ func (p Parser) DetermineFileTypeFromBytes(inBytes []byte, nowExt string) (bool,
 			odl.Lines = append(odl.Lines, text)
 			odl.Lines = append(odl.Lines, text)
 		}
 		}
 		subFileInfo.Dialogues = append(subFileInfo.Dialogues, odl)
 		subFileInfo.Dialogues = append(subFileInfo.Dialogues, odl)
+		subFileInfo.DialoguesFilter = append(subFileInfo.DialoguesFilter, odl)
 	}
 	}
 	// 再分析
 	// 再分析
 	// 需要判断每一个 Line 是啥语言,[语言的code]次数
 	// 需要判断每一个 Line 是啥语言,[语言的code]次数
@@ -98,14 +100,14 @@ func (p Parser) DetermineFileTypeFromBytes(inBytes []byte, nowExt string) (bool,
 	var otherLines = make([]string, 0)
 	var otherLines = make([]string, 0)
 	// 抽取出来的对话数组,为了后续用来匹配和修改时间轴
 	// 抽取出来的对话数组,为了后续用来匹配和修改时间轴
 	var usefulDialogueExs = make([]subparser.OneDialogueEx, 0)
 	var usefulDialogueExs = make([]subparser.OneDialogueEx, 0)
-	for _, dialogue := range subFileInfo.Dialogues {
+	for _, dialogue := range subFileInfo.DialoguesFilter {
 		language.DetectSubLangAndStatistics(dialogue, langDict, &usefulDialogueExs, &chLines, &otherLines)
 		language.DetectSubLangAndStatistics(dialogue, langDict, &usefulDialogueExs, &chLines, &otherLines)
 	}
 	}
 	// 从统计出来的字典,找出 Top 1 或者 2 的出来,然后计算出是什么语言的字幕
 	// 从统计出来的字典,找出 Top 1 或者 2 的出来,然后计算出是什么语言的字幕
 	detectLang := language.SubLangStatistics2SubLangType(float32(countLineFeed), float32(len(matched)), langDict, chLines)
 	detectLang := language.SubLangStatistics2SubLangType(float32(countLineFeed), float32(len(matched)), langDict, chLines)
 	subFileInfo.Lang = detectLang
 	subFileInfo.Lang = detectLang
 	subFileInfo.Data = inBytes
 	subFileInfo.Data = inBytes
-	subFileInfo.DialoguesEx = usefulDialogueExs
+	subFileInfo.DialoguesFilterEx = usefulDialogueExs
 	subFileInfo.CHLines = chLines
 	subFileInfo.CHLines = chLines
 	subFileInfo.OtherLines = otherLines
 	subFileInfo.OtherLines = otherLines
 	return true, &subFileInfo, nil
 	return true, &subFileInfo, nil

+ 7 - 7
internal/logic/sub_supplier/shooter/shooter_test.go

@@ -6,13 +6,13 @@ import (
 )
 )
 
 
 func TestNewSupplier(t *testing.T) {
 func TestNewSupplier(t *testing.T) {
-	//movie1 := "X:\\电影\\The Devil All the Time (2020)\\The Devil All the Time (2020) WEBDL-1080p.mkv"
-	//movie1 := "X:\\电影\\龙猫 (1988)\\龙猫 (1988) 1080p DTS.mkv"
-	//movie1 := "X:\\电影\\消失爱人 (2016)\\消失爱人 (2016) 720p AAC.rmvb"
-	//movie1 := "X:\\电影\\机动战士Z高达:星之继承者 (2005)\\机动战士Z高达:星之继承者 (2005) 1080p TrueHD.mkv"
-	//movie1 := "X:\\连续剧\\The Bad Batch\\Season 1\\The Bad Batch - S01E01 - Aftermath WEBDL-1080p.mkv"
-	//movie1 := "X:\\电影\\An Invisible Sign (2010)\\An Invisible Sign (2010) 720p AAC.mp4"
-	movie1 := "X:\\连续剧\\少年间谍 (2020)\\Season 2\\Alex Rider - S02E01 - Episode One WEBDL-1080p.mkv"
+	//movie1 := "XLen:\\电影\\The Devil All the Time (2020)\\The Devil All the Time (2020) WEBDL-1080p.mkv"
+	//movie1 := "XLen:\\电影\\龙猫 (1988)\\龙猫 (1988) 1080p DTS.mkv"
+	//movie1 := "XLen:\\电影\\消失爱人 (2016)\\消失爱人 (2016) 720p AAC.rmvb"
+	//movie1 := "XLen:\\电影\\机动战士Z高达:星之继承者 (2005)\\机动战士Z高达:星之继承者 (2005) 1080p TrueHD.mkv"
+	//movie1 := "XLen:\\连续剧\\The Bad Batch\\Season 1\\The Bad Batch - S01E01 - Aftermath WEBDL-1080p.mkv"
+	//movie1 := "XLen:\\电影\\An Invisible Sign (2010)\\An Invisible Sign (2010) 720p AAC.mp4"
+	movie1 := "XLen:\\连续剧\\少年间谍 (2020)\\Season 2\\Alex Rider - S02E01 - Episode One WEBDL-1080p.mkv"
 	shooter := NewSupplier(types.ReqParam{Topic: 3})
 	shooter := NewSupplier(types.ReqParam{Topic: 3})
 	outList, err := shooter.getSubListFromFile(movie1)
 	outList, err := shooter.getSubListFromFile(movie1)
 	if err != nil {
 	if err != nil {

+ 13 - 13
internal/logic/sub_supplier/subhd/subhd_test.go

@@ -9,14 +9,14 @@ import (
 
 
 func TestSupplier_GetSubListFromFile(t *testing.T) {
 func TestSupplier_GetSubListFromFile(t *testing.T) {
 
 
-	//movie1 := "X:\\电影\\The Devil All the Time (2020)\\The Devil All the Time (2020) WEBDL-1080p.mkv"
-	//movie1 := "X:\\电影\\Luca (2021)\\Luca (2021) WEBDL-1080p.mkv"
-	movie1 := "X:\\电影\\The Boss Baby Family Business (2021)\\The Boss Baby Family Business (2021) WEBDL-1080p.mkv"
-	//movie1 := "X:\\电影\\Oslo (2021)\\Oslo (2021) WEBDL-1080p.mkv"
-	//movie1 := "X:\\电影\\Spiral From the Book of Saw (2021)\\Spiral From the Book of Saw (2021) WEBDL-1080p.mkv"
-	//movie1 := "X:\\电影\\消失爱人 (2016)\\消失爱人 (2016) 720p AAC.rmvb"
-	//movie1 := "X:\\电影\\机动战士Z高达:星之继承者 (2005)\\机动战士Z高达:星之继承者 (2005) 1080p TrueHD.mkv"
-	//movie1 := "X:\\连续剧\\The Bad Batch\\Season 1\\The Bad Batch - S01E01 - Aftermath WEBDL-1080p.mkv"
+	//movie1 := "XLen:\\电影\\The Devil All the Time (2020)\\The Devil All the Time (2020) WEBDL-1080p.mkv"
+	//movie1 := "XLen:\\电影\\Luca (2021)\\Luca (2021) WEBDL-1080p.mkv"
+	movie1 := "XLen:\\电影\\The Boss Baby Family Business (2021)\\The Boss Baby Family Business (2021) WEBDL-1080p.mkv"
+	//movie1 := "XLen:\\电影\\Oslo (2021)\\Oslo (2021) WEBDL-1080p.mkv"
+	//movie1 := "XLen:\\电影\\Spiral From the Book of Saw (2021)\\Spiral From the Book of Saw (2021) WEBDL-1080p.mkv"
+	//movie1 := "XLen:\\电影\\消失爱人 (2016)\\消失爱人 (2016) 720p AAC.rmvb"
+	//movie1 := "XLen:\\电影\\机动战士Z高达:星之继承者 (2005)\\机动战士Z高达:星之继承者 (2005) 1080p TrueHD.mkv"
+	//movie1 := "XLen:\\连续剧\\The Bad Batch\\Season 1\\The Bad Batch - S01E01 - Aftermath WEBDL-1080p.mkv"
 	subhd := NewSupplier(getReqParam())
 	subhd := NewSupplier(getReqParam())
 	outList, err := subhd.getSubListFromFile4Movie(movie1)
 	outList, err := subhd.getSubListFromFile4Movie(movie1)
 	if err != nil {
 	if err != nil {
@@ -35,11 +35,11 @@ func TestSupplier_GetSubListFromFile(t *testing.T) {
 
 
 func TestSupplier_GetSubListFromFile4Series(t *testing.T) {
 func TestSupplier_GetSubListFromFile4Series(t *testing.T) {
 
 
-	//ser := "X:\\连续剧\\The Bad Batch"	// tt12708542
-	ser := "X:\\连续剧\\瑞克和莫蒂 (2013)" //
-	//ser := "X:\\连续剧\\杀死伊芙 (2018)"	// tt7016936
-	//ser := "X:\\连续剧\\Money.Heist"
-	//ser := "X:\\连续剧\\黑钱胜地 (2017)"
+	//ser := "XLen:\\连续剧\\The Bad Batch"	// tt12708542
+	ser := "XLen:\\连续剧\\瑞克和莫蒂 (2013)" //
+	//ser := "XLen:\\连续剧\\杀死伊芙 (2018)"	// tt7016936
+	//ser := "XLen:\\连续剧\\Money.Heist"
+	//ser := "XLen:\\连续剧\\黑钱胜地 (2017)"
 
 
 	// 读取本地的视频和字幕信息
 	// 读取本地的视频和字幕信息
 	seriesInfo, err := series_helper2.ReadSeriesInfoFromDir(ser, nil, false)
 	seriesInfo, err := series_helper2.ReadSeriesInfoFromDir(ser, nil, false)

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

@@ -161,7 +161,7 @@ func (s Supplier) getCid(filePath string) (string, error) {
 		sha1Ctx.Write(buffer)
 		sha1Ctx.Write(buffer)
 	}
 	}
 
 
-	hash = fmt.Sprintf("%X", sha1Ctx.Sum(nil))
+	hash = fmt.Sprintf("%XLen", sha1Ctx.Sum(nil))
 	return hash, nil
 	return hash, nil
 }
 }
 
 

+ 6 - 6
internal/logic/sub_supplier/xunlei/xunlei_test.go

@@ -6,12 +6,12 @@ import (
 )
 )
 
 
 func TestGetList(t *testing.T) {
 func TestGetList(t *testing.T) {
-	//movie1 := "X:\\电影\\The Devil All the Time (2020)\\The Devil All the Time (2020) WEBDL-1080p.mkv"
-	//movie1 := "X:\\电影\\龙猫 (1988)\\龙猫 (1988) 1080p DTS.mkv"
-	//movie1 := "X:\\电影\\消失爱人 (2016)\\消失爱人 (2016) 720p AAC.rmvb"
-	//movie1:= "X:\\电影\\Spiral From the Book of Saw (2021)\\Spiral From the Book of Saw (2021) WEBDL-1080p.mkv"
-	movie1 := "X:\\电影\\机动战士Z高达:星之继承者 (2005)\\机动战士Z高达:星之继承者 (2005) 1080p TrueHD.mkv"
-	//movie1 := "X:\\连续剧\\The Bad Batch\\Season 1\\The Bad Batch - S01E01 - Aftermath WEBDL-1080p.mkv"
+	//movie1 := "XLen:\\电影\\The Devil All the Time (2020)\\The Devil All the Time (2020) WEBDL-1080p.mkv"
+	//movie1 := "XLen:\\电影\\龙猫 (1988)\\龙猫 (1988) 1080p DTS.mkv"
+	//movie1 := "XLen:\\电影\\消失爱人 (2016)\\消失爱人 (2016) 720p AAC.rmvb"
+	//movie1:= "XLen:\\电影\\Spiral From the Book of Saw (2021)\\Spiral From the Book of Saw (2021) WEBDL-1080p.mkv"
+	movie1 := "XLen:\\电影\\机动战士Z高达:星之继承者 (2005)\\机动战士Z高达:星之继承者 (2005) 1080p TrueHD.mkv"
+	//movie1 := "XLen:\\连续剧\\The Bad Batch\\Season 1\\The Bad Batch - S01E01 - Aftermath WEBDL-1080p.mkv"
 	xunlie := NewSupplier(types.ReqParam{Topic: 3})
 	xunlie := NewSupplier(types.ReqParam{Topic: 3})
 	outList, err := xunlie.getSubListFromFile(movie1)
 	outList, err := xunlie.getSubListFromFile(movie1)
 	if err != nil {
 	if err != nil {

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

@@ -21,12 +21,12 @@ func TestSupplier_GetSubListFromKeyword(t *testing.T) {
 }
 }
 
 
 func TestSupplier_GetSubListFromFile(t *testing.T) {
 func TestSupplier_GetSubListFromFile(t *testing.T) {
-	movie1 := "X:\\电影\\The Devil All the Time (2020)\\The Devil All the Time (2020) WEBDL-1080p.mkv"
-	//movie1 := "X:\\电影\\龙猫 (1988)\\龙猫 (1988) 1080p DTS.mkv"
-	//movie1 := "X:\\电影\\消失爱人 (2016)\\消失爱人 (2016) 720p AAC.rmvb"
-	//movie1:= "X:\\电影\\Spiral From the Book of Saw (2021)\\Spiral From the Book of Saw (2021) WEBDL-1080p.mkv"
-	//movie1 := "X:\\电影\\机动战士Z高达:星之继承者 (2005)\\机动战士Z高达:星之继承者 (2005) 1080p TrueHD.mkv"
-	//movie1 := "X:\\连续剧\\The Bad Batch\\Season 1\\The Bad Batch - S01E01 - Aftermath WEBDL-1080p.mkv"
+	movie1 := "XLen:\\电影\\The Devil All the Time (2020)\\The Devil All the Time (2020) WEBDL-1080p.mkv"
+	//movie1 := "XLen:\\电影\\龙猫 (1988)\\龙猫 (1988) 1080p DTS.mkv"
+	//movie1 := "XLen:\\电影\\消失爱人 (2016)\\消失爱人 (2016) 720p AAC.rmvb"
+	//movie1:= "XLen:\\电影\\Spiral From the Book of Saw (2021)\\Spiral From the Book of Saw (2021) WEBDL-1080p.mkv"
+	//movie1 := "XLen:\\电影\\机动战士Z高达:星之继承者 (2005)\\机动战士Z高达:星之继承者 (2005) 1080p TrueHD.mkv"
+	//movie1 := "XLen:\\连续剧\\The Bad Batch\\Season 1\\The Bad Batch - S01E01 - Aftermath WEBDL-1080p.mkv"
 
 
 	s := NewSupplier()
 	s := NewSupplier()
 	outList, err := s.getSubListFromMovie(movie1)
 	outList, err := s.getSubListFromMovie(movie1)
@@ -41,9 +41,9 @@ func TestSupplier_GetSubListFromFile(t *testing.T) {
 
 
 func TestSupplier_GetSubListFromFile4Series(t *testing.T) {
 func TestSupplier_GetSubListFromFile4Series(t *testing.T) {
 
 
-	ser := "X:\\连续剧\\The Bad Batch" // tt12708542
-	//ser := "X:\\连续剧\\杀死伊芙 (2018)"	// tt12708542
-	//ser := "X:\\连续剧\\Money.Heist"
+	ser := "XLen:\\连续剧\\The Bad Batch" // tt12708542
+	//ser := "XLen:\\连续剧\\杀死伊芙 (2018)"	// tt12708542
+	//ser := "XLen:\\连续剧\\Money.Heist"
 
 
 	// 读取本地的视频和字幕信息
 	// 读取本地的视频和字幕信息
 	seriesInfo, err := series_helper2.ReadSeriesInfoFromDir(ser, nil, false)
 	seriesInfo, err := series_helper2.ReadSeriesInfoFromDir(ser, nil, false)

+ 2 - 2
internal/logic/sub_timeline_fixer/SubTimelineFixerHelperEx_test.go

@@ -25,13 +25,13 @@ func TestSubTimelineFixerHelperEx_Process(t *testing.T) {
 	}{
 	}{
 		{
 		{
 			name: "Foundation (2021) - S01E09", args: args{
 			name: "Foundation (2021) - S01E09", args: args{
-				videoFileFullPath: "X:\\连续剧\\Foundation (2021)\\Season 1\\Foundation (2021) - S01E09 - The First Crisis WEBDL-1080p.mkv",
+				videoFileFullPath: "XLen:\\连续剧\\Foundation (2021)\\Season 1\\Foundation (2021) - S01E09 - The First Crisis WEBDL-1080p.mkv",
 				srcSubFPath:       "C:\\WorkSpace\\Go2Hell\\src\\github.com\\allanpk716\\ChineseSubFinder\\internal\\logic\\sub_timeline_fixer\\CSF-SubFixCache\\Foundation (2021) - S01E09 - The First Crisis WEBDL-1080p\\chinese(简英,zimuku).default.ass"},
 				srcSubFPath:       "C:\\WorkSpace\\Go2Hell\\src\\github.com\\allanpk716\\ChineseSubFinder\\internal\\logic\\sub_timeline_fixer\\CSF-SubFixCache\\Foundation (2021) - S01E09 - The First Crisis WEBDL-1080p\\chinese(简英,zimuku).default.ass"},
 			wantErr: false,
 			wantErr: false,
 		},
 		},
 		{
 		{
 			name: "Foundation (2021) - S01E09", args: args{
 			name: "Foundation (2021) - S01E09", args: args{
-				videoFileFullPath: "X:\\连续剧\\Foundation (2021)\\Season 1\\Foundation (2021) - S01E09 - The First Crisis WEBDL-1080p.mkv",
+				videoFileFullPath: "XLen:\\连续剧\\Foundation (2021)\\Season 1\\Foundation (2021) - S01E09 - The First Crisis WEBDL-1080p.mkv",
 				srcSubFPath:       "C:\\WorkSpace\\Go2Hell\\src\\github.com\\allanpk716\\ChineseSubFinder\\internal\\logic\\sub_timeline_fixer\\CSF-SubFixCache\\Foundation (2021) - S01E09 - The First Crisis WEBDL-1080p\\chinese(简英,zimuku).default.ass"},
 				srcSubFPath:       "C:\\WorkSpace\\Go2Hell\\src\\github.com\\allanpk716\\ChineseSubFinder\\internal\\logic\\sub_timeline_fixer\\CSF-SubFixCache\\Foundation (2021) - S01E09 - The First Crisis WEBDL-1080p\\chinese(简英,zimuku).default.ass"},
 			wantErr: false,
 			wantErr: false,
 		},
 		},

+ 1 - 1
internal/logic/sub_timeline_fixer/sub_timeline_fixer_helper_test.go

@@ -25,7 +25,7 @@ func TestSubTimelineFixerHelper_fixOneVideoSub(t *testing.T) {
 	// 178071 -- The Night House
 	// 178071 -- The Night House
 	config := config.GetConfig()
 	config := config.GetConfig()
 	fixer := NewSubTimelineFixerHelper(config.EmbyConfig, config.SubTimelineFixerConfig)
 	fixer := NewSubTimelineFixerHelper(config.EmbyConfig, config.SubTimelineFixerConfig)
-	err := fixer.fixOneVideoSub("178071", "X:\\电影\\The Night House (2021)")
+	err := fixer.fixOneVideoSub("178071", "XLen:\\电影\\The Night House (2021)")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}

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

@@ -23,7 +23,7 @@ func SaveDebugChartBase(vadList []vad.VADInfo, title, subTitle string) error {
 		Title:    title,
 		Title:    title,
 		Subtitle: subTitle,
 		Subtitle: subTitle,
 	}))
 	}))
-	// 构建 X 轴
+	// 构建 XLen
 	xAxis := make([]string, len(vadList))
 	xAxis := make([]string, len(vadList))
 	for i := 0; i < len(vadList); i++ {
 	for i := 0; i < len(vadList); i++ {
 		xAxis[i] = fmt.Sprintf("%d", i)
 		xAxis[i] = fmt.Sprintf("%d", i)

+ 4 - 4
internal/pkg/decode/decode_test.go

@@ -23,7 +23,7 @@ func Test_get_IMDB_movie_xml(t *testing.T) {
 func Test_get_IMDB_nfo(t *testing.T) {
 func Test_get_IMDB_nfo(t *testing.T) {
 	wantid := "tt0993840"
 	wantid := "tt0993840"
 	wantyear := "2021"
 	wantyear := "2021"
-	dirPth := "X:\\电影\\Army of the Dead (2021)\\Army of the Dead (2021) WEBDL-1080p.nfo"
+	dirPth := "XLen:\\电影\\Army of the Dead (2021)\\Army of the Dead (2021) WEBDL-1080p.nfo"
 	imdbInfo, err := getImdbAndYearNfo(dirPth, "movie")
 	imdbInfo, err := getImdbAndYearNfo(dirPth, "movie")
 	if err != nil {
 	if err != nil {
 		t.Error(err)
 		t.Error(err)
@@ -38,12 +38,12 @@ func Test_get_IMDB_nfo(t *testing.T) {
 
 
 func Test_GetVideoInfoFromFileFullPath(t *testing.T) {
 func Test_GetVideoInfoFromFileFullPath(t *testing.T) {
 
 
-	subTitle := "X:\\电影\\Spiral From the Book of Saw (2021)\\Spiral From the Book of Saw (2021) WEBDL-1080p.mkv"
+	subTitle := "XLen:\\电影\\Spiral From the Book of Saw (2021)\\Spiral From the Book of Saw (2021) WEBDL-1080p.mkv"
 	//subTitle := "人之怒 WEBDL-1080p.mkv"
 	//subTitle := "人之怒 WEBDL-1080p.mkv"
 	//subTitle := "機動戦士Zガンダム WEBDL-1080p.mkv"
 	//subTitle := "機動戦士Zガンダム WEBDL-1080p.mkv"
 	//subTitle := "机动战士Z高达:星之继承者 (2005) 1080p TrueHD.mkv"
 	//subTitle := "机动战士Z高达:星之继承者 (2005) 1080p TrueHD.mkv"
-	//subTitle := "X:\\连续剧\\The Bad Batch\\Season 1\\The Bad Batch - S01E01 - Aftermath WEBDL-1080p.mkv"
-	//subTitle := "X:\\连续剧\\Money.Heist\\Season 1\\Money.Heist.S01E01.SPANISH.WEBRip.x264-ION10.zh-cn.ssa"
+	//subTitle := "XLen:\\连续剧\\The Bad Batch\\Season 1\\The Bad Batch - S01E01 - Aftermath WEBDL-1080p.mkv"
+	//subTitle := "XLen:\\连续剧\\Money.Heist\\Season 1\\Money.Heist.S01E01.SPANISH.WEBRip.x264-ION10.zh-cn.ssa"
 	//subTitle := "Spiral.From.the.Book.of.Saw.2021.1080p.WEBRip.x264-RARBG.chi.srt"
 	//subTitle := "Spiral.From.the.Book.of.Saw.2021.1080p.WEBRip.x264-RARBG.chi.srt"
 	//subTitle := "Spiral.From.the.Book.of.Saw.2021.1080p.WEBRip.x264-RARBG.eng.srt"
 	//subTitle := "Spiral.From.the.Book.of.Saw.2021.1080p.WEBRip.x264-RARBG.eng.srt"
 	//subTitle := "东城梅尔 第一季第一集【YYeTs字幕组 简繁英双语字幕】Mare.of.Easttown.S01E01.Miss.Lady.Hawk.Herself.720p/1080p.AMZN.WEB-DL.DDP5.1.H.264-TEPES"
 	//subTitle := "东城梅尔 第一季第一集【YYeTs字幕组 简繁英双语字幕】Mare.of.Easttown.S01E01.Miss.Lady.Hawk.Herself.720p/1080p.AMZN.WEB-DL.DDP5.1.H.264-TEPES"

+ 4 - 4
internal/pkg/ffmpeg_helper/ffmpeg_helper_test.go

@@ -8,10 +8,10 @@ import (
 )
 )
 
 
 func TestGetFFMPEGInfo(t *testing.T) {
 func TestGetFFMPEGInfo(t *testing.T) {
-	//videoFile := "X:\\连续剧\\瑞克和莫蒂 (2013)\\Season 5\\Rick and Morty - S05E10 - Rickmurai Jack WEBRip-1080p.mkv"
-	videoFile := "X:\\连续剧\\瑞克和莫蒂 (2013)\\Season 5\\Rick and Morty - S05E01 - Mort Dinner Rick Andre WEBDL-1080p.mkv"
-	//videoFile := "X:\\TestSeries\\Blade Runner - Black Lotus\\Season 1\\Blade Runner - Black Lotus - S01E03 - The Human Condition WEBDL-1080p.mkv"
-	//videoFile := "X:\\连续剧\\Foundation (2021)\\Season 1\\Foundation (2021) - S01E10 - The Leap WEBDL-1080p.mkv"
+	//videoFile := "XLen:\\连续剧\\瑞克和莫蒂 (2013)\\Season 5\\Rick and Morty - S05E10 - Rickmurai Jack WEBRip-1080p.mkv"
+	videoFile := "XLen:\\连续剧\\瑞克和莫蒂 (2013)\\Season 5\\Rick and Morty - S05E01 - Mort Dinner Rick Andre WEBDL-1080p.mkv"
+	//videoFile := "XLen:\\TestSeries\\Blade Runner - Black Lotus\\Season 1\\Blade Runner - Black Lotus - S01E03 - The Human Condition WEBDL-1080p.mkv"
+	//videoFile := "XLen:\\连续剧\\Foundation (2021)\\Season 1\\Foundation (2021) - S01E10 - The Leap WEBDL-1080p.mkv"
 
 
 	f := NewFFMPEGHelper()
 	f := NewFFMPEGHelper()
 	bok, ffmpegInfo, err := f.GetFFMPEGInfo(videoFile, Audio)
 	bok, ffmpegInfo, err := f.GetFFMPEGInfo(videoFile, Audio)

+ 2 - 2
internal/pkg/log_helper/loghelper.go

@@ -28,9 +28,9 @@ func NewLogHelper(appName string, level logrus.Level, maxAge time.Duration, rota
 	}
 	}
 	pathRoot := filepath.Join(nowpath, "Logs")
 	pathRoot := filepath.Join(nowpath, "Logs")
 	fileAbsPath := filepath.Join(pathRoot, appName+".log")
 	fileAbsPath := filepath.Join(pathRoot, appName+".log")
-	// 下面配置日志每隔 X 分钟轮转一个新文件,保留最近 X 分钟的日志文件,多余的自动清理掉。
+	// 下面配置日志每隔 XLen 分钟轮转一个新文件,保留最近 XLen 分钟的日志文件,多余的自动清理掉。
 	writer, _ := rotatelogs.New(
 	writer, _ := rotatelogs.New(
-		filepath.Join(pathRoot, appName+"--%Y%m%d%H%M--.log"),
+		filepath.Join(pathRoot, appName+"--%YLen%m%d%H%M--.log"),
 		rotatelogs.WithLinkName(fileAbsPath),
 		rotatelogs.WithLinkName(fileAbsPath),
 		rotatelogs.WithMaxAge(maxAge),
 		rotatelogs.WithMaxAge(maxAge),
 		rotatelogs.WithRotationTime(rotationTime),
 		rotatelogs.WithRotationTime(rotationTime),

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

@@ -25,7 +25,7 @@ import (
 
 
 // NewHttpClient 新建一个 resty 的对象
 // NewHttpClient 新建一个 resty 的对象
 func NewHttpClient(_reqParam ...types.ReqParam) *resty.Client {
 func NewHttpClient(_reqParam ...types.ReqParam) *resty.Client {
-	//const defUserAgent = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"
+	//const defUserAgent = "Mozilla/5.0 (Macintosh; U; Intel Mac OS XLen 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"
 	//const defUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 Edg/91.0.864.41"
 	//const defUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 Edg/91.0.864.41"
 	// 随机的 Browser
 	// 随机的 Browser
 	defUserAgent := browser.Random()
 	defUserAgent := browser.Random()

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

@@ -25,19 +25,19 @@ var (
 		// 百度移动 UA
 		// 百度移动 UA
 		"Mozilla/5.0 (Linux;u;Android 4.2.2;zh-cn;) AppleWebKit/534.46 (KHTML,like Gecko) Version/5.1",
 		"Mozilla/5.0 (Linux;u;Android 4.2.2;zh-cn;) AppleWebKit/534.46 (KHTML,like Gecko) Version/5.1",
 		"Mobile Safari/10600.6.3 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)",
 		"Mobile Safari/10600.6.3 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)",
-		"Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1 (compatible; Baiduspider-render/2.0; +http://www.baidu.com/search/spider.html)",
+		"Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS XLen) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1 (compatible; Baiduspider-render/2.0; +http://www.baidu.com/search/spider.html)",
 		// 百度图片UA
 		// 百度图片UA
 		//"Baiduspider-image+(+http://www.baidu.com/search/spider.htm)",
 		//"Baiduspider-image+(+http://www.baidu.com/search/spider.htm)",
 		// 神马搜索User-Agent:
 		// 神马搜索User-Agent:
 		// B神马搜索 PC UA
 		// B神马搜索 PC UA
 		"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 YisouSpider/5.0 Safari/537.36",
 		"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 YisouSpider/5.0 Safari/537.36",
 		// 神马搜索移动 UA
 		// 神马搜索移动 UA
-		"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e YisouSpider/5.0 Safari/602.1",
+		"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS XLen) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e YisouSpider/5.0 Safari/602.1",
 		// 谷歌User-Agent:
 		// 谷歌User-Agent:
 		// 谷歌 PC UA
 		// 谷歌 PC UA
 		"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
 		"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
 		// 谷歌移动UA
 		// 谷歌移动UA
-		"AdsBot-Google-Mobile (+http://www.google.com/mobile/adsbot.html) Mozilla (iPhone; U; CPU iPhone OS 3 0 like Mac OS X) AppleWebKit (KHTML, like Gecko) Mobile Safari",
+		"AdsBot-Google-Mobile (+http://www.google.com/mobile/adsbot.html) Mozilla (iPhone; U; CPU iPhone OS 3 0 like Mac OS XLen) AppleWebKit (KHTML, like Gecko) Mobile Safari",
 		// 谷歌图片UA
 		// 谷歌图片UA
 		"Mozilla/5.0 (compatible; Googlebot-Image/1.0; +http://www.google.com/bot.html)",
 		"Mozilla/5.0 (compatible; Googlebot-Image/1.0; +http://www.google.com/bot.html)",
 		// 搜狗User-Agent:
 		// 搜狗User-Agent:

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

@@ -74,7 +74,7 @@ func TestNewDialogueMerger(t *testing.T) {
 	}
 	}
 
 
 	merger := NewDialogueMerger()
 	merger := NewDialogueMerger()
-	for _, ex := range infoBase.DialoguesEx {
+	for _, ex := range infoBase.DialoguesFilterEx {
 		merger.Add(ex)
 		merger.Add(ex)
 	}
 	}
 	newEx := merger.Get()
 	newEx := merger.Get()

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

@@ -359,20 +359,20 @@ func DeleteOneSeasonSubCacheFolder(seriesDir string) error {
 }
 }
 
 
 /*
 /*
-	只针对英文字幕进行合并分散的 Dialogues
+	只针对英文字幕进行合并分散的 DialoguesFilter
 	会遇到这样的字幕,如下0
 	会遇到这样的字幕,如下0
 	2line-The Card Counter (2021) WEBDL-1080p.chinese(inside).ass
 	2line-The Card Counter (2021) WEBDL-1080p.chinese(inside).ass
 	它的对白一句话分了两个 dialogue 去做。这样做后续字幕时间轴校正就会遇到问题,因为只有一半,匹配占比会很低
 	它的对白一句话分了两个 dialogue 去做。这样做后续字幕时间轴校正就会遇到问题,因为只有一半,匹配占比会很低
 	(每一个 Dialogue 的首字母需要分析,大写和小写的占比是多少,统计一下,正常的,和上述特殊的)
 	(每一个 Dialogue 的首字母需要分析,大写和小写的占比是多少,统计一下,正常的,和上述特殊的)
-	那么,就需要额外的逻辑去对 DialoguesEx 进行额外的推断
+	那么,就需要额外的逻辑去对 DialoguesFilterEx 进行额外的推断
 	暂时考虑的方案是,英文对白每一句的开头应该是英文大写字幕,如果是小写字幕,就应该与上语句合并,且每一句的字符长度有大于一定才触发
 	暂时考虑的方案是,英文对白每一句的开头应该是英文大写字幕,如果是小写字幕,就应该与上语句合并,且每一句的字符长度有大于一定才触发
 */
 */
 func MergeMultiDialogue4EngSubtitle(inSubParser *subparser.FileInfo) {
 func MergeMultiDialogue4EngSubtitle(inSubParser *subparser.FileInfo) {
 	merger := NewDialogueMerger()
 	merger := NewDialogueMerger()
-	for _, dialogueEx := range inSubParser.DialoguesEx {
+	for _, dialogueEx := range inSubParser.DialoguesFilterEx {
 		merger.Add(dialogueEx)
 		merger.Add(dialogueEx)
 	}
 	}
-	inSubParser.DialoguesEx = merger.Get()
+	inSubParser.DialoguesFilterEx = merger.Get()
 }
 }
 
 
 // GetVADInfoFeatureFromSub 跟下面的 GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert 函数功能一致
 // GetVADInfoFeatureFromSub 跟下面的 GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert 函数功能一致
@@ -397,7 +397,7 @@ func GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert(fileInfo *subparser.FileIn
 	srcOneSubUnit := NewSubUnit()
 	srcOneSubUnit := NewSubUnit()
 
 
 	// 最后一个对话的结束时间
 	// 最后一个对话的结束时间
-	lastDialogueExTimeEnd, err := fileInfo.ParseTime(fileInfo.DialoguesEx[len(fileInfo.DialoguesEx)-1].EndTime)
+	lastDialogueExTimeEnd, err := fileInfo.ParseTime(fileInfo.DialoguesFilterEx[len(fileInfo.DialoguesFilterEx)-1].EndTime)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -410,13 +410,13 @@ func GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert(fileInfo *subparser.FileIn
 	println(startRangeTimeMin)
 	println(startRangeTimeMin)
 	println(endRangeTimeMax)
 	println(endRangeTimeMax)
 
 
-	for i := 0; i < len(fileInfo.DialoguesEx); i++ {
+	for i := 0; i < len(fileInfo.DialoguesFilterEx); i++ {
 
 
-		oneDialogueExTimeStart, err := fileInfo.ParseTime(fileInfo.DialoguesEx[i].StartTime)
+		oneDialogueExTimeStart, err := fileInfo.ParseTime(fileInfo.DialoguesFilterEx[i].StartTime)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		oneDialogueExTimeEnd, err := fileInfo.ParseTime(fileInfo.DialoguesEx[i].EndTime)
+		oneDialogueExTimeEnd, err := fileInfo.ParseTime(fileInfo.DialoguesFilterEx[i].EndTime)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
@@ -445,7 +445,7 @@ func GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert(fileInfo *subparser.FileIn
 				srcOneSubUnit.Add(oneDialogueExTimeStart, oneDialogueExTimeEnd)
 				srcOneSubUnit.Add(oneDialogueExTimeStart, oneDialogueExTimeEnd)
 			}
 			}
 			// 这一个单元的 Dialogue 需要合并起来,才能判断是否符合“钥匙”的要求
 			// 这一个单元的 Dialogue 需要合并起来,才能判断是否符合“钥匙”的要求
-			srcSubDialogueList = append(srcSubDialogueList, fileInfo.DialoguesEx[i])
+			srcSubDialogueList = append(srcSubDialogueList, fileInfo.DialoguesFilterEx[i])
 
 
 		} else {
 		} else {
 			// 用完清空
 			// 用完清空
@@ -469,7 +469,7 @@ func GetVADInfoFeatureFromSubNeedOffsetTimeWillInsert(fileInfo *subparser.FileIn
 func GetVADInfoFeatureFromSubNew(fileInfo *subparser.FileInfo, SkipFrontAndEndPer float64) (*SubUnit, error) {
 func GetVADInfoFeatureFromSubNew(fileInfo *subparser.FileInfo, SkipFrontAndEndPer float64) (*SubUnit, error) {
 
 
 	outSubUnits := NewSubUnit()
 	outSubUnits := NewSubUnit()
-	if len(fileInfo.DialoguesEx) <= 0 {
+	if len(fileInfo.DialoguesFilterEx) <= 0 {
 		return nil, errors.New("GetVADInfoFeatureFromSubNew fileInfo Dialogue Length is 0")
 		return nil, errors.New("GetVADInfoFeatureFromSubNew fileInfo Dialogue Length is 0")
 	}
 	}
 	/*
 	/*
@@ -497,7 +497,7 @@ func GetVADInfoFeatureFromSubNew(fileInfo *subparser.FileInfo, SkipFrontAndEndPe
 	skipEndIndex := vadLen - skipLen
 	skipEndIndex := vadLen - skipLen
 	// 现在需要从 fileInfo 的每一句对白也就对应一段连续的 VAD active = true 来进行改写,记得向下取整
 	// 现在需要从 fileInfo 的每一句对白也就对应一段连续的 VAD active = true 来进行改写,记得向下取整
 	lastDialogueIndex := 0
 	lastDialogueIndex := 0
-	for index, dialogueEx := range fileInfo.DialoguesEx {
+	for index, dialogueEx := range fileInfo.DialoguesFilterEx {
 
 
 		// 如果当前的这一句话,为空,或者进过正则表达式剔除特殊字符后为空,则跳过
 		// 如果当前的这一句话,为空,或者进过正则表达式剔除特殊字符后为空,则跳过
 		if my_util.ReplaceSpecString(fileInfo.GetDialogueExContent(index), "") == "" {
 		if my_util.ReplaceSpecString(fileInfo.GetDialogueExContent(index), "") == "" {
@@ -583,12 +583,12 @@ func ReadSubStartAndEndTime(fileInfo *subparser.FileInfo) (float64, float64, err
 
 
 	getTimeFunc := func(fileInfo *subparser.FileInfo, startIndex int) (bool, float64, float64, error) {
 	getTimeFunc := func(fileInfo *subparser.FileInfo, startIndex int) (bool, float64, float64, error) {
 		// 字幕的开始时间
 		// 字幕的开始时间
-		subStartTime, err := fileInfo.ParseTime(fileInfo.DialoguesEx[startIndex].StartTime)
+		subStartTime, err := fileInfo.ParseTime(fileInfo.DialoguesFilterEx[startIndex].StartTime)
 		if err != nil {
 		if err != nil {
 			return false, 0, 0, err
 			return false, 0, 0, err
 		}
 		}
 		// 字幕的结束时间
 		// 字幕的结束时间
-		subEndTime, err := fileInfo.ParseTime(fileInfo.DialoguesEx[len(fileInfo.DialoguesEx)-1].EndTime)
+		subEndTime, err := fileInfo.ParseTime(fileInfo.DialoguesFilterEx[len(fileInfo.DialoguesFilterEx)-1].EndTime)
 		if err != nil {
 		if err != nil {
 			return false, 0, 0, err
 			return false, 0, 0, err
 		}
 		}

+ 3 - 3
internal/pkg/sub_helper/sub_helper_test.go

@@ -48,9 +48,9 @@ func TestGetVADInfosFromSub(t *testing.T) {
 		t.Fatal("sub not match")
 		t.Fatal("sub not match")
 	}
 	}
 
 
-	if len(infoBase.DialoguesEx) != len(infoSrc.DialoguesEx) {
-		t.Fatal(fmt.Sprintf("info Base And Src Parse Error, infoBase.DialoguesEx Len = %v, infoSrc.DialoguesEx Len = %v",
-			len(infoBase.DialoguesEx), len(infoSrc.DialoguesEx)))
+	if len(infoBase.DialoguesFilterEx) != len(infoSrc.DialoguesFilterEx) {
+		t.Fatal(fmt.Sprintf("info Base And Src Parse Error, infoBase.DialoguesFilterEx Len = %v, infoSrc.DialoguesFilterEx Len = %v",
+			len(infoBase.DialoguesFilterEx), len(infoSrc.DialoguesFilterEx)))
 	}
 	}
 
 
 	baseSubUnit, err := GetVADInfoFeatureFromSubNew(infoBase, FrontAndEndPerBase)
 	baseSubUnit, err := GetVADInfoFeatureFromSubNew(infoBase, FrontAndEndPerBase)

+ 89 - 5
internal/pkg/sub_timeline_fixer/fix_result.go

@@ -1,9 +1,93 @@
 package sub_timeline_fixer
 package sub_timeline_fixer
 
 
+import (
+	"github.com/allanpk716/ChineseSubFinder/internal/pkg/sub_helper"
+	"github.com/emirpasic/gods/maps/treemap"
+	"github.com/grd/stat"
+	"sync"
+)
+
 type FixResult struct {
 type FixResult struct {
-	OldMean float64
-	OldSD   float64
-	NewMean float64
-	NewSD   float64
-	Per     float64 // 占比
+	StartVADIndex int
+	EndVADIndex   int
+	OldMean       float64
+	OldSD         float64
+	NewMean       float64
+	NewSD         float64
+	Per           float64   // 占比
+	OP            OverParts // 越接处信息
+}
+
+func (f FixResult) InRange(baseTimeDouble, timeStartDouble float64) (bool, float64) {
+
+	if baseTimeDouble+float64(f.StartVADIndex) <= timeStartDouble &&
+		baseTimeDouble+float64(f.EndVADIndex) >= timeStartDouble {
+		// 在当前的范围内
+		if f.OP.Has == true {
+			// 这里需要特殊处理,因为这个越接处,还需要二分
+			if timeStartDouble <= baseTimeDouble+float64(f.StartVADIndex)+f.OP.XLen {
+				return true, f.OP.XMean
+			} else {
+				return true, f.OP.YMean
+			}
+		} else {
+			// 无需特殊处理
+			return true, f.NewMean
+
+		}
+	} else if baseTimeDouble+float64(f.StartVADIndex) > timeStartDouble {
+		// 小于当前的范围
+		return true, f.NewMean
+	} else if timeStartDouble > baseTimeDouble+float64(f.EndVADIndex) {
+		// 大于当前的范围
+		return true, f.NewMean
+	} else {
+		return false, 0
+	}
+}
+
+// MatchInfo 匹配的信息
+type MatchInfo struct {
+	StartDiffTimeList   []float64
+	StartDiffTimeMap    *treemap.Map
+	StartDiffTimeListEx stat.Float64Slice
+}
+
+// WindowInfo 滑动窗体信息
+type WindowInfo struct {
+	BaseAudioFloatList []float64           // 基准 VAD
+	BaseUnit           *sub_helper.SubUnit // 基准 VAD
+	SrcUnit            *sub_helper.SubUnit // 需要匹配的 VAD
+	MatchedTimes       int                 // 匹配上的次数
+	SrcWindowLen       int                 // 滑动窗体长度
+	SrcSlideStartIndex int                 // 滑动起始索引
+	SrcSlideLen        int                 // 滑动距离
+	OneStep            int                 // 每次滑动的长度
+}
+
+// InputData 修复函数传入多线程的数据结构
+type InputData struct {
+	BaseUnit         sub_helper.SubUnit // 基准 VAD
+	BaseAudioVADList []float64          // 基准 VAD
+	SrcUnit          sub_helper.SubUnit // 需要匹配的 VAD
+	OffsetIndex      int                // 滑动窗体的移动偏移索引
+	Wg               *sync.WaitGroup    // 并发锁
+}
+
+// SubVADBlockInfo 字幕分块信息
+type SubVADBlockInfo struct {
+	Index      int
+	StartIndex int
+	EndIndex   int
+}
+
+/*
+	OverParts 总长度 D = XLen + YLen
+*/
+type OverParts struct {
+	Has   bool    // 是否有越接处
+	XLen  float64 // 分段处长度
+	YLen  float64 // 分段处长度
+	XMean float64 // X 段的 Mean 值
+	YMean float64 // Y 段的 Mean 值
 }
 }

+ 213 - 80
internal/pkg/sub_timeline_fixer/fixer.go

@@ -18,6 +18,7 @@ import (
 	"github.com/panjf2000/ants/v2"
 	"github.com/panjf2000/ants/v2"
 	"golang.org/x/net/context"
 	"golang.org/x/net/context"
 	"gonum.org/v1/gonum/mat"
 	"gonum.org/v1/gonum/mat"
+	"math"
 	"os"
 	"os"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
@@ -113,12 +114,81 @@ func (s *SubTimelineFixer) FixSubTimelineOneOffsetTime(infoSrc *subparser.FileIn
 	return fixContent, nil
 	return fixContent, nil
 }
 }
 
 
+// FixSubTimelineByFixResults V2 专用的时间校正函数
+func (s SubTimelineFixer) FixSubTimelineByFixResults(infoSrc *subparser.FileInfo, srcUnitNew *sub_helper.SubUnit, fixedResults []FixResult, desSaveSubFileFullPath string) (string, error) {
+
+	startTime := srcUnitNew.GetStartTime(true)
+	startTimeBaseDouble := my_util.Time2SecondNumber(startTime)
+	/*
+		这里拿到的 fixedResults ,是进行过 V2_FrontAndEndPerSrc 头尾去除
+		那么调整目标字幕的时候,需要考虑截取掉的部分也要算进去
+	*/
+	/*
+		从解析的实例中,正常来说是可以匹配出所有的 Dialogue 对话的 Start 和 End time 的信息
+		然后找到对应的字幕的文件,进行文件内容的替换来做时间轴的校正
+	*/
+	fixContent := infoSrc.Content
+	/*
+		这里进行时间转字符串的时候有一点比较特殊
+		正常来说输出的格式是类似 15:04:05.00
+		那么有个问题,字幕的时间格式是 0:00:12.00, 小时,是个数,除非有跨度到 20 小时的视频,不然小时就应该是个数
+		这就需要一个额外的函数去处理这些情况
+	*/
+	timeFormat := infoSrc.GetTimeFormat()
+	cacheIndex := 0
+	for _, srcOneDialogue := range infoSrc.Dialogues {
+
+		timeStart, err := infoSrc.ParseTime(srcOneDialogue.StartTime)
+		if err != nil {
+			return "", err
+		}
+		timeEnd, err := infoSrc.ParseTime(srcOneDialogue.EndTime)
+		if err != nil {
+			return "", err
+		}
+
+		inOffsetTime := 0.0
+		orgStartTimeDouble := my_util.Time2SecondNumber(timeStart)
+		for cacheIndex < len(fixedResults) {
+
+			inRange, nowOffsetTime := fixedResults[cacheIndex].InRange(startTimeBaseDouble, orgStartTimeDouble)
+			if inRange == false {
+				cacheIndex++
+				continue
+			} else {
+				inOffsetTime = nowOffsetTime
+				break
+			}
+		}
+		// 偏移时间
+		println(inOffsetTime)
+		offsetTime := time.Duration(inOffsetTime*1000) * time.Millisecond
+		fixTimeStart := timeStart.Add(offsetTime)
+		fixTimeEnd := timeEnd.Add(offsetTime)
+
+		fixContent = strings.ReplaceAll(fixContent, srcOneDialogue.StartTime, my_util.Time2SubTimeString(fixTimeStart, timeFormat))
+		fixContent = strings.ReplaceAll(fixContent, srcOneDialogue.EndTime, my_util.Time2SubTimeString(fixTimeEnd, timeFormat))
+	}
+
+	dstFile, err := os.Create(desSaveSubFileFullPath)
+	if err != nil {
+		return "", err
+	}
+	defer func() {
+		_ = dstFile.Close()
+	}()
+	_, err = dstFile.WriteString(fixContent)
+	if err != nil {
+		return "", err
+	}
+	return fixContent, nil
+}
+
 /*
 /*
 	对于 V1 版本的字幕时间轴校正来说,是有特殊的前置要求的
 	对于 V1 版本的字幕时间轴校正来说,是有特殊的前置要求的
 	1. 视频要有英文字幕
 	1. 视频要有英文字幕
 	2. 外置的字幕必须是中文的双语字幕(简英、繁英)
 	2. 外置的字幕必须是中文的双语字幕(简英、繁英)
 */
 */
-
 // GetOffsetTimeV1 暂时只支持英文的基准字幕,源字幕必须是双语中英字幕
 // GetOffsetTimeV1 暂时只支持英文的基准字幕,源字幕必须是双语中英字幕
 func (s *SubTimelineFixer) GetOffsetTimeV1(infoBase, infoSrc *subparser.FileInfo, staticLineFileSavePath string, debugInfoFileSavePath string) (bool, float64, float64, error) {
 func (s *SubTimelineFixer) GetOffsetTimeV1(infoBase, infoSrc *subparser.FileInfo, staticLineFileSavePath string, debugInfoFileSavePath string) (bool, float64, float64, error) {
 
 
@@ -130,7 +200,7 @@ func (s *SubTimelineFixer) GetOffsetTimeV1(infoBase, infoSrc *subparser.FileInfo
 		这里原来的写法是所有的 base 的都放进去匹配,这样会带来一些不必要的对白
 		这里原来的写法是所有的 base 的都放进去匹配,这样会带来一些不必要的对白
 		需要剔除空白。那么就需要建立一个转换的字典
 		需要剔除空白。那么就需要建立一个转换的字典
 	*/
 	*/
-	for index, oneDialogueEx := range infoBase.DialoguesEx {
+	for index, oneDialogueEx := range infoBase.DialoguesFilterEx {
 		if oneDialogueEx.EnLine == "" {
 		if oneDialogueEx.EnLine == "" {
 			continue
 			continue
 		}
 		}
@@ -152,9 +222,9 @@ func (s *SubTimelineFixer) GetOffsetTimeV1(infoBase, infoSrc *subparser.FileInfo
 	var matchIndexList = make([]MatchIndex, 0)
 	var matchIndexList = make([]MatchIndex, 0)
 	sc := NewSubCompare(maxCompareDialogue)
 	sc := NewSubCompare(maxCompareDialogue)
 	// 开始比较相似度,默认认为是 Ch_en 就行了
 	// 开始比较相似度,默认认为是 Ch_en 就行了
-	for srcIndex := 0; srcIndex < len(infoSrc.DialoguesEx); {
+	for srcIndex := 0; srcIndex < len(infoSrc.DialoguesFilterEx); {
 
 
-		srcOneDialogueEx := infoSrc.DialoguesEx[srcIndex]
+		srcOneDialogueEx := infoSrc.DialoguesFilterEx[srcIndex]
 		// 这里只考虑 英文 的语言
 		// 这里只考虑 英文 的语言
 		if srcOneDialogueEx.EnLine == "" {
 		if srcOneDialogueEx.EnLine == "" {
 			srcIndex++
 			srcIndex++
@@ -214,7 +284,7 @@ func (s *SubTimelineFixer) GetOffsetTimeV1(infoBase, infoSrc *subparser.FileInfo
 
 
 		//println(fmt.Sprintf("Similarity: %f Base[%d] %s-%s '%s' <--> Src[%d] %s-%s '%s'",
 		//println(fmt.Sprintf("Similarity: %f Base[%d] %s-%s '%s' <--> Src[%d] %s-%s '%s'",
 		//	highestSimilarity,
 		//	highestSimilarity,
-		//	baseIndex, infoBase.DialoguesEx[baseIndex].relativelyStartTime, infoBase.DialoguesEx[baseIndex].relativelyEndTime, baseCorpus[baseIndex],
+		//	baseIndex, infoBase.DialoguesFilterEx[baseIndex].relativelyStartTime, infoBase.DialoguesFilterEx[baseIndex].relativelyEndTime, baseCorpus[baseIndex],
 		//	srcIndex, srcOneDialogueEx.relativelyStartTime, srcOneDialogueEx.relativelyEndTime, srcOneDialogueEx.EnLine))
 		//	srcIndex, srcOneDialogueEx.relativelyStartTime, srcOneDialogueEx.relativelyEndTime, srcOneDialogueEx.EnLine))
 
 
 		srcIndex++
 		srcIndex++
@@ -237,19 +307,19 @@ func (s *SubTimelineFixer) GetOffsetTimeV1(infoBase, infoSrc *subparser.FileInfo
 			tmpBaseIndex := baseDialogueFilterMap[matchIndexItem.BaseNowIndex+i]
 			tmpBaseIndex := baseDialogueFilterMap[matchIndexItem.BaseNowIndex+i]
 			tmpSrcIndex := matchIndexItem.SrcNowIndex + i
 			tmpSrcIndex := matchIndexItem.SrcNowIndex + i
 
 
-			baseTimeStart, err := infoBase.ParseTime(infoBase.DialoguesEx[tmpBaseIndex].StartTime)
+			baseTimeStart, err := infoBase.ParseTime(infoBase.DialoguesFilterEx[tmpBaseIndex].StartTime)
 			if err != nil {
 			if err != nil {
 				return false, 0, 0, err
 				return false, 0, 0, err
 			}
 			}
-			baseTimeEnd, err := infoBase.ParseTime(infoBase.DialoguesEx[tmpBaseIndex].EndTime)
+			baseTimeEnd, err := infoBase.ParseTime(infoBase.DialoguesFilterEx[tmpBaseIndex].EndTime)
 			if err != nil {
 			if err != nil {
 				return false, 0, 0, err
 				return false, 0, 0, err
 			}
 			}
-			srtTimeStart, err := infoBase.ParseTime(infoSrc.DialoguesEx[tmpSrcIndex].StartTime)
+			srtTimeStart, err := infoBase.ParseTime(infoSrc.DialoguesFilterEx[tmpSrcIndex].StartTime)
 			if err != nil {
 			if err != nil {
 				return false, 0, 0, err
 				return false, 0, 0, err
 			}
 			}
-			srtTimeEnd, err := infoBase.ParseTime(infoSrc.DialoguesEx[tmpSrcIndex].EndTime)
+			srtTimeEnd, err := infoBase.ParseTime(infoSrc.DialoguesFilterEx[tmpSrcIndex].EndTime)
 			if err != nil {
 			if err != nil {
 				return false, 0, 0, err
 				return false, 0, 0, err
 			}
 			}
@@ -268,13 +338,13 @@ func (s *SubTimelineFixer) GetOffsetTimeV1(infoBase, infoSrc *subparser.FileInfo
 
 
 			xAxis = append(xAxis, fmt.Sprintf("%d_%d", mIndex, i))
 			xAxis = append(xAxis, fmt.Sprintf("%d_%d", mIndex, i))
 
 
-			debugInfos = append(debugInfos, "bs "+infoBase.DialoguesEx[tmpBaseIndex].StartTime+" <-> "+infoBase.DialoguesEx[tmpBaseIndex].EndTime)
-			debugInfos = append(debugInfos, "sc "+infoSrc.DialoguesEx[tmpSrcIndex].StartTime+" <-> "+infoSrc.DialoguesEx[tmpSrcIndex].EndTime)
+			debugInfos = append(debugInfos, "bs "+infoBase.DialoguesFilterEx[tmpBaseIndex].StartTime+" <-> "+infoBase.DialoguesFilterEx[tmpBaseIndex].EndTime)
+			debugInfos = append(debugInfos, "sc "+infoSrc.DialoguesFilterEx[tmpSrcIndex].StartTime+" <-> "+infoSrc.DialoguesFilterEx[tmpSrcIndex].EndTime)
 			debugInfos = append(debugInfos, "StartDiffTime: "+fmt.Sprintf("%f", TimeDiffStart.Seconds()))
 			debugInfos = append(debugInfos, "StartDiffTime: "+fmt.Sprintf("%f", TimeDiffStart.Seconds()))
 			//println(fmt.Sprintf("Diff Start-End: %s - %s Base[%d] %s-%s '%s' <--> Src[%d] %s-%s '%s'",
 			//println(fmt.Sprintf("Diff Start-End: %s - %s Base[%d] %s-%s '%s' <--> Src[%d] %s-%s '%s'",
 			//	TimeDiffStart, TimeDiffEnd,
 			//	TimeDiffStart, TimeDiffEnd,
-			//	tmpBaseIndex, infoBase.DialoguesEx[tmpBaseIndex].relativelyStartTime, infoBase.DialoguesEx[tmpBaseIndex].relativelyEndTime, infoBase.DialoguesEx[tmpBaseIndex].EnLine,
-			//	tmpSrcIndex, infoSrc.DialoguesEx[tmpSrcIndex].relativelyStartTime, infoSrc.DialoguesEx[tmpSrcIndex].relativelyEndTime, infoSrc.DialoguesEx[tmpSrcIndex].EnLine))
+			//	tmpBaseIndex, infoBase.DialoguesFilterEx[tmpBaseIndex].relativelyStartTime, infoBase.DialoguesFilterEx[tmpBaseIndex].relativelyEndTime, infoBase.DialoguesFilterEx[tmpBaseIndex].EnLine,
+			//	tmpSrcIndex, infoSrc.DialoguesFilterEx[tmpSrcIndex].relativelyStartTime, infoSrc.DialoguesFilterEx[tmpSrcIndex].relativelyEndTime, infoSrc.DialoguesFilterEx[tmpSrcIndex].EnLine))
 		}
 		}
 		debugInfos = append(debugInfos, "---------------------------------------------")
 		debugInfos = append(debugInfos, "---------------------------------------------")
 		//println("---------------------------------------------")
 		//println("---------------------------------------------")
@@ -338,7 +408,7 @@ func (s *SubTimelineFixer) GetOffsetTimeV1(infoBase, infoSrc *subparser.FileInfo
 	// 跳过的逻辑是 mean 是 0 ,那么现在如果判断有问题,缓存的调试文件继续生成,然后强制返回 0 来跳过后续的逻辑
 	// 跳过的逻辑是 mean 是 0 ,那么现在如果判断有问题,缓存的调试文件继续生成,然后强制返回 0 来跳过后续的逻辑
 	// 这里需要考虑,找到的连续 5 句话匹配的有多少句,占比整体所有的 Dialogue 是多少,太低也需要跳过
 	// 这里需要考虑,找到的连续 5 句话匹配的有多少句,占比整体所有的 Dialogue 是多少,太低也需要跳过
 	matchIndexLineCount := len(matchIndexList) * maxCompareDialogue
 	matchIndexLineCount := len(matchIndexList) * maxCompareDialogue
-	//perMatch := float64(matchIndexLineCount) / float64(len(infoSrc.DialoguesEx))
+	//perMatch := float64(matchIndexLineCount) / float64(len(infoSrc.DialoguesFilterEx))
 	perMatch := float64(matchIndexLineCount) / float64(len(baseCorpus))
 	perMatch := float64(matchIndexLineCount) / float64(len(baseCorpus))
 	if perMatch < s.FixerConfig.V1_MinMatchedPercent {
 	if perMatch < s.FixerConfig.V1_MinMatchedPercent {
 		tmpContent := infoSrc.Name + fmt.Sprintf(" Sequence match %d dialogues (< %f%%), Skip,", s.FixerConfig.V1_MaxCompareDialogue, s.FixerConfig.V1_MinMatchedPercent*100) + fmt.Sprintf(" %f%% ", perMatch*100)
 		tmpContent := infoSrc.Name + fmt.Sprintf(" Sequence match %d dialogues (< %f%%), Skip,", s.FixerConfig.V1_MaxCompareDialogue, s.FixerConfig.V1_MinMatchedPercent*100) + fmt.Sprintf(" %f%% ", perMatch*100)
@@ -370,7 +440,7 @@ func (s *SubTimelineFixer) GetOffsetTimeV1(infoBase, infoSrc *subparser.FileInfo
 }
 }
 
 
 // GetOffsetTimeV2 使用内置的字幕校正外置的字幕时间轴
 // GetOffsetTimeV2 使用内置的字幕校正外置的字幕时间轴
-func (s *SubTimelineFixer) GetOffsetTimeV2(baseUnit, srcUnit *sub_helper.SubUnit, audioVadList []vad.VADInfo) (bool, float64, float64, error) {
+func (s *SubTimelineFixer) GetOffsetTimeV2(baseUnit, srcUnit *sub_helper.SubUnit, audioVadList []vad.VADInfo) (bool, []FixResult, error) {
 
 
 	// -------------------------------------------------
 	// -------------------------------------------------
 	/*
 	/*
@@ -424,21 +494,17 @@ func (s *SubTimelineFixer) GetOffsetTimeV2(baseUnit, srcUnit *sub_helper.SubUnit
 		// 时间轴差值数组
 		// 时间轴差值数组
 		matchInfo, err := s.slidingWindowProcessor(&windowInfo)
 		matchInfo, err := s.slidingWindowProcessor(&windowInfo)
 		if err != nil {
 		if err != nil {
-			return false, 0, 0, err
+			return false, nil, err
 		}
 		}
 
 
 		matchedInfos = append(matchedInfos, *matchInfo)
 		matchedInfos = append(matchedInfos, *matchInfo)
 	}
 	}
 
 
-	// 这里可能遇到匹配的时候没有能够执行够 V2_CompareParts 次,有可能是负数跳过或者时间转换失败导致,前者为主(可能是这两个就是一个东西的时候,或者说没有时间轴偏移的时候)
-	//if len(matchInfo.StartDiffTimeList) < s.FixerConfig.V2_CompareParts/2 {
-	//	log_helper.GetLogger().Infoln("Can't Match, Parts=", len(matchInfo.StartDiffTimeList), "At Least", s.FixerConfig.V2_CompareParts/2)
-	//	return false, 0, 0, nil
-	//}
-
+	fixedResults := make([]FixResult, 0)
+	sdLessCount := 0
 	for index, matchInfo := range matchedInfos {
 	for index, matchInfo := range matchedInfos {
 
 
-		log_helper.GetLogger().Infoln("------------------------------------")
+		log_helper.GetLogger().Infoln(index, "------------------------------------")
 		outCorrelationFixResult := s.calcMeanAndSD(matchInfo.StartDiffTimeListEx, matchInfo.StartDiffTimeList)
 		outCorrelationFixResult := s.calcMeanAndSD(matchInfo.StartDiffTimeListEx, matchInfo.StartDiffTimeList)
 		log_helper.GetLogger().Infoln(fmt.Sprintf("FFTAligner Old Mean: %v SD: %f Per: %v", outCorrelationFixResult.OldMean, outCorrelationFixResult.OldSD, outCorrelationFixResult.Per))
 		log_helper.GetLogger().Infoln(fmt.Sprintf("FFTAligner Old Mean: %v SD: %f Per: %v", outCorrelationFixResult.OldMean, outCorrelationFixResult.OldSD, outCorrelationFixResult.Per))
 		log_helper.GetLogger().Infoln(fmt.Sprintf("FFTAligner New Mean: %v SD: %f Per: %v", outCorrelationFixResult.NewMean, outCorrelationFixResult.NewSD, outCorrelationFixResult.Per))
 		log_helper.GetLogger().Infoln(fmt.Sprintf("FFTAligner New Mean: %v SD: %f Per: %v", outCorrelationFixResult.NewMean, outCorrelationFixResult.NewSD, outCorrelationFixResult.Per))
@@ -446,36 +512,132 @@ func (s *SubTimelineFixer) GetOffsetTimeV2(baseUnit, srcUnit *sub_helper.SubUnit
 		value, indexMax := matchInfo.StartDiffTimeMap.Max()
 		value, indexMax := matchInfo.StartDiffTimeMap.Max()
 		log_helper.GetLogger().Infoln("FFTAligner Max score:", fmt.Sprintf("%v", value.(float64)), "Time:", fmt.Sprintf("%v", matchInfo.StartDiffTimeList[indexMax.(int)]))
 		log_helper.GetLogger().Infoln("FFTAligner Max score:", fmt.Sprintf("%v", value.(float64)), "Time:", fmt.Sprintf("%v", matchInfo.StartDiffTimeList[indexMax.(int)]))
 
 
-		/*
-			如果 outCorrelationFixResult 的 SD > 0.1,那么大概率这个时间轴的值匹配的有问题,需要向左或者向右找一个值进行继承
-			-4 0.001
-			-4 0.001
-			-4 0.001
-			-200 0.1
-			-4 0.001
-			比如这种情况,那么就需要向左找到 -4 去继承。
-			具体的实现:
-				找到一个 SD > 0.1 的项目,那么就需要从左边和右边同时对比
-				首先是他们的差值要在 1s (绝对值)以内,优先往左边找,如果绝对值成立则判断 SD (SD 必须 < 0.1)
-				如果只是 SD 不成立,那么就继续往左,继续判断差值和 SD。如果都找不到合适的,就要回到”起点“,从右开始找,逻辑一样
-				直到没有找到合适的信息,就报错
-		*/
+		outCorrelationFixResult.StartVADIndex = index * perPartLen
+		outCorrelationFixResult.EndVADIndex = index*perPartLen + perPartLen
+		fixedResults = append(fixedResults, outCorrelationFixResult)
+
 		if outCorrelationFixResult.NewSD < 0.1 {
 		if outCorrelationFixResult.NewSD < 0.1 {
-			continue
+			sdLessCount++
 		}
 		}
-		// 是否找到合适的继承值
-		bProcess := false
-		// 先往左
-		if index-1 >= 0 {
-			// 说明至少可以往左
+	}
+
+	// 如果 0.1 sd 以下的占比低于 70% 那么就认为字幕匹配失败
+	perLess := float64(sdLessCount) / float64(len(matchedInfos))
+	if perLess < 0.7 {
+		return false, nil, nil
+	}
+	/*
+		如果 outCorrelationFixResult 的 SD > 0.1,那么大概率这个时间轴的值匹配的有问题,需要向左或者向右找一个值进行继承
+		-4 0.001
+		-4 0.001
+		-4 0.001
+		-200 0.1
+		-4 0.001
+		比如这种情况,那么就需要向左找到 -4 去继承。
+		具体的实现:
+			找到一个 SD > 0.1 的项目,那么就需要从左边和右边同时对比
+			首先是他们的差值要在 0.3s (绝对值)以内,优先往左边找,如果绝对值成立则判断 SD (SD 必须 < 0.1)
+			如果只是 SD 不成立,那么就继续往左,继续判断差值和 SD。
+			如果都找不到合适的,就要回到”起点“,从右开始找,逻辑一样
+			直到没有找到合适的信息,就报错
+	*/
+	// 进行细节的修正
+	for index, fixedResult := range fixedResults {
+		if fixedResult.NewSD >= 0.1 {
+			bok, newMean, newSD, op := s.fixOnePart(index, fixedResults, perPartLen)
+			if bok == true {
+				fixedResults[index].NewMean = newMean
+				fixedResults[index].NewSD = newSD
+				fixedResults[index].OP = op
+			}
 		}
 		}
 	}
 	}
 
 
-	return true, 0, 0, nil
+	return true, fixedResults, nil
 }
 }
 
 
-func (s SubTimelineFixer) fixOnePart() {
+// fixOnePart 轻微地跳动可以根据左或者右去微调
+func (s SubTimelineFixer) fixOnePart(startIndex int, fixedResults []FixResult, perPartLen int) (bool, float64, float64, OverParts) {
+	op := OverParts{}
+	/*
+		找到这样情况的进行修正
+	*/
+	// 先往左
+	if startIndex-1 >= 0 {
+		// 说明至少可以往左
+		// 如果左边的这个值,与当前值超过了 0.3 的绝对差值,那么是不适合的,就需要往右找
+		if math.Abs(fixedResults[startIndex-1].NewMean-fixedResults[startIndex].NewMean) < 0.3 {
+			// 差值在接受的范围内,那么就使用这个左边的值去校正当前的值
+			return true, fixedResults[startIndex-1].NewMean, fixedResults[startIndex-1].NewSD, OverParts{}
+		}
+	}
+
+	// 那么就需要向右看看
+	//if startIndex+1 < len(fixedResults) {
+	//	// 说明至少可以往右
+	//	// 如果右边的这个值,与当前值超过了 0.3 的绝对差值,那么是不适合的
+	//	if math.Abs(fixedResults[startIndex+1].NewMean-fixedResults[startIndex].NewMean) < 0.3 {
+	//		// 差值在接受的范围内,那么就使用这个左边的值去校正当前的值
+	//		return true, fixedResults[startIndex+1].NewMean, fixedResults[startIndex+1].NewSD, OverParts{}
+	//	}
+	//}
 
 
+	// 如果上面的理想情况都没有进去,那么就是这个差值很大
+	if fixedResults[startIndex].NewSD > 1 {
+		// SD 比较大,可能当前的位置是值是错误的,那么直接就使用左边的值
+		/*
+			-6.3	0.06
+			-146.85	243.83
+		*/
+		if startIndex-1 >= 0 {
+			return true, fixedResults[startIndex-1].NewMean, fixedResults[startIndex-1].NewSD, OverParts{}
+		}
+	} else {
+		// SD 不是很大,可能就是正常的字幕分段的时间轴偏移的 越接处 !
+		// 那么需要取,越接处,前三和后三,进行均值计算
+		/*
+			-6.21
+			-6.22
+			-6.29	0.06
+
+			-7.13	0.14		越接处
+
+			-7.32
+			-7.31
+			-7.44
+		*/
+		left3Mean := 0.0
+		right3Mean := 0.0
+		// 向左,三个或者三个位置
+		if startIndex-3 >= 0 {
+			left3Mean = float64(fixedResults[startIndex-1].NewMean+fixedResults[startIndex-2].NewMean+fixedResults[startIndex-3].NewMean) / 3.0
+		} else if startIndex-2 >= 0 {
+			left3Mean = float64(fixedResults[startIndex-1].NewMean+fixedResults[startIndex-2].NewMean) / 2.0
+		} else {
+			return false, 0, 0, OverParts{}
+		}
+		// 向右,三个或者三个位置
+		if startIndex+3 >= 0 {
+			right3Mean = float64(fixedResults[startIndex+1].NewMean+fixedResults[startIndex+2].NewMean+fixedResults[startIndex+3].NewMean) / 3.0
+		} else if startIndex+2 >= 0 {
+			right3Mean = float64(fixedResults[startIndex+1].NewMean+fixedResults[startIndex+2].NewMean) / 2.0
+		} else {
+			return false, 0, 0, OverParts{}
+		}
+		// xLen 计算公式见推到公式截图
+		xLen := (fixedResults[startIndex].NewMean*float64(perPartLen) - right3Mean*float64(perPartLen)) / (left3Mean - right3Mean)
+		yLen := float64(perPartLen) - xLen
+
+		op.Has = true
+		op.XLen = xLen
+		op.YLen = yLen
+		op.XMean = left3Mean
+		op.YMean = right3Mean
+
+		return true, fixedResults[startIndex+1].NewMean, fixedResults[startIndex+1].NewSD, op
+	}
+
+	return false, 0, 0, OverParts{}
 }
 }
 
 
 // slidingWindowProcessor 滑动窗口计算时间轴偏移
 // slidingWindowProcessor 滑动窗口计算时间轴偏移
@@ -634,11 +796,14 @@ func (s *SubTimelineFixer) calcMeanAndSD(startDiffTimeList stat.Float64Slice, tm
 
 
 	if len(tmpStartDiffTime) < 3 {
 	if len(tmpStartDiffTime) < 3 {
 		return FixResult{
 		return FixResult{
+			0,
+			0,
 			oldMean,
 			oldMean,
 			oldSd,
 			oldSd,
 			oldMean,
 			oldMean,
 			oldSd,
 			oldSd,
 			per,
 			per,
+			OverParts{},
 		}
 		}
 	}
 	}
 
 
@@ -680,11 +845,14 @@ func (s *SubTimelineFixer) calcMeanAndSD(startDiffTimeList stat.Float64Slice, tm
 		newSd = oldSd
 		newSd = oldSd
 	}
 	}
 	return FixResult{
 	return FixResult{
+		0,
+		0,
 		oldMean,
 		oldMean,
 		oldSd,
 		oldSd,
 		newMean,
 		newMean,
 		newSd,
 		newSd,
 		per,
 		per,
+		OverParts{},
 	}
 	}
 }
 }
 
 
@@ -692,38 +860,3 @@ const FixMask = "-fix"
 const MinValue = -9999.0
 const MinValue = -9999.0
 
 
 var mutexFixV2 sync.Mutex
 var mutexFixV2 sync.Mutex
-
-// MatchInfo 匹配的信息
-type MatchInfo struct {
-	StartDiffTimeList   []float64
-	StartDiffTimeMap    *treemap.Map
-	StartDiffTimeListEx stat.Float64Slice
-}
-
-// WindowInfo 滑动窗体信息
-type WindowInfo struct {
-	BaseAudioFloatList []float64           // 基准 VAD
-	BaseUnit           *sub_helper.SubUnit // 基准 VAD
-	SrcUnit            *sub_helper.SubUnit // 需要匹配的 VAD
-	MatchedTimes       int                 // 匹配上的次数
-	SrcWindowLen       int                 // 滑动窗体长度
-	SrcSlideStartIndex int                 // 滑动起始索引
-	SrcSlideLen        int                 // 滑动距离
-	OneStep            int                 // 每次滑动的长度
-}
-
-// InputData 修复函数传入多线程的数据结构
-type InputData struct {
-	BaseUnit         sub_helper.SubUnit // 基准 VAD
-	BaseAudioVADList []float64          // 基准 VAD
-	SrcUnit          sub_helper.SubUnit // 需要匹配的 VAD
-	OffsetIndex      int                // 滑动窗体的移动偏移索引
-	Wg               *sync.WaitGroup    // 并发锁
-}
-
-// SubVADBlockInfo 字幕分块信息
-type SubVADBlockInfo struct {
-	Index      int
-	StartIndex int
-	EndIndex   int
-}

+ 32 - 29
internal/pkg/sub_timeline_fixer/fixer_test.go

@@ -617,7 +617,7 @@ func TestGetOffsetTimeV2_BaseSub(t *testing.T) {
 			}
 			}
 			// ---------------------------------------------------------------------------------------
 			// ---------------------------------------------------------------------------------------
 			//bok, got, sd, err := timelineFixer.GetOffsetTimeV2(&baseUnitOld, &srcUnitOld, nil, 0)
 			//bok, got, sd, err := timelineFixer.GetOffsetTimeV2(&baseUnitOld, &srcUnitOld, nil, 0)
-			bok, got, sd, err := timelineFixer.GetOffsetTimeV2(baseUnitNew, srcUnitNew, nil)
+			bok, _, err := timelineFixer.GetOffsetTimeV2(baseUnitNew, srcUnitNew, nil)
 			if (err != nil) != tt.wantErr {
 			if (err != nil) != tt.wantErr {
 				t.Errorf("GetOffsetTimeV2() error = %v, wantErr %v", err, tt.wantErr)
 				t.Errorf("GetOffsetTimeV2() error = %v, wantErr %v", err, tt.wantErr)
 				return
 				return
@@ -626,24 +626,24 @@ func TestGetOffsetTimeV2_BaseSub(t *testing.T) {
 				t.Fatal("GetOffsetTimeV2 return false")
 				t.Fatal("GetOffsetTimeV2 return false")
 			}
 			}
 
 
-			if got > -0.2 && got < 0.2 && tt.want == 0 {
-				// 如果 offset time > -0.2 且 < 0.2 则认为无需调整时间轴,为0
-			} else if got > tt.want-0.1 && got < tt.want+0.1 {
-				// 在一个正负范围内都可以接受
-			} else {
-				t.Errorf("GetOffsetTimeV2() got = %v, want %v", got, tt.want)
-			}
+			//if got > -0.2 && got < 0.2 && tt.want == 0 {
+			//	// 如果 offset time > -0.2 且 < 0.2 则认为无需调整时间轴,为0
+			//} else if got > tt.want-0.1 && got < tt.want+0.1 {
+			//	// 在一个正负范围内都可以接受
+			//} else {
+			//	t.Errorf("GetOffsetTimeV2() got = %v, want %v", got, tt.want)
+			//}
 
 
 			debug_view.SaveDebugChart(*baseUnitNew, tt.name+" -- baseUnitNew", "baseUnitNew")
 			debug_view.SaveDebugChart(*baseUnitNew, tt.name+" -- baseUnitNew", "baseUnitNew")
 			debug_view.SaveDebugChart(*srcUnitNew, tt.name+" -- srcUnitNew", "srcUnitNew")
 			debug_view.SaveDebugChart(*srcUnitNew, tt.name+" -- srcUnitNew", "srcUnitNew")
 
 
 			//if bok == true && got != 0 {
 			//if bok == true && got != 0 {
-			_, err = timelineFixer.FixSubTimelineOneOffsetTime(infoSrc, got, tt.args.srcSubFile+FixMask+infoBase.Ext)
-			if err != nil {
-				t.Fatal(err)
-			}
+			//_, err = timelineFixer.FixSubTimelineOneOffsetTime(infoSrc, got, tt.args.srcSubFile+FixMask+infoBase.Ext)
+			//if err != nil {
+			//	t.Fatal(err)
 			//}
 			//}
-			println(fmt.Sprintf("GetOffsetTimeV2: %fs SD:%f", got, sd))
+			////}
+			//println(fmt.Sprintf("GetOffsetTimeV2: %fs SD:%f", got, sd))
 		})
 		})
 	}
 	}
 }
 }
@@ -712,7 +712,7 @@ func TestGetOffsetTimeV2_BaseAudio(t *testing.T) {
 			}
 			}
 
 
 			println("-------New--------")
 			println("-------New--------")
-			bok, offsetTime, sd, err := timelineFixer.GetOffsetTimeV2(nil, srcUnitNew, audioVADInfos)
+			bok, _, err := timelineFixer.GetOffsetTimeV2(nil, srcUnitNew, audioVADInfos)
 			if (err != nil) != tt.wantErr {
 			if (err != nil) != tt.wantErr {
 				t.Errorf("GetOffsetTimeV2() error = %v, wantErr %v", err, tt.wantErr)
 				t.Errorf("GetOffsetTimeV2() error = %v, wantErr %v", err, tt.wantErr)
 				return
 				return
@@ -724,20 +724,20 @@ func TestGetOffsetTimeV2_BaseAudio(t *testing.T) {
 				t.Errorf("GetOffsetTimeV2() bok = %v, want %v", bok, tt.want)
 				t.Errorf("GetOffsetTimeV2() bok = %v, want %v", bok, tt.want)
 			}
 			}
 
 
-			if offsetTime > -0.2 && offsetTime < 0.2 && tt.want1 == 0 {
-				// 如果 offset time > -0.2 且 < 0.2 则认为无需调整时间轴,为0
-			} else if offsetTime > tt.want1-0.1 && offsetTime < tt.want1+0.1 {
-				// 在一个正负范围内都可以接受
-			} else {
-				t.Errorf("GetOffsetTimeV2() bok = %v, want %v", offsetTime, tt.want1)
-			}
+			//if offsetTime > -0.2 && offsetTime < 0.2 && tt.want1 == 0 {
+			//	// 如果 offset time > -0.2 且 < 0.2 则认为无需调整时间轴,为0
+			//} else if offsetTime > tt.want1-0.1 && offsetTime < tt.want1+0.1 {
+			//	// 在一个正负范围内都可以接受
+			//} else {
+			//	t.Errorf("GetOffsetTimeV2() bok = %v, want %v", offsetTime, tt.want1)
+			//}
 
 
-			_, err = timelineFixer.FixSubTimelineOneOffsetTime(infoSrc, offsetTime, tt.args.subFilePath+FixMask+infoSrc.Ext)
-			if err != nil {
-				t.Fatal(err)
-			}
+			//_, err = timelineFixer.FixSubTimelineOneOffsetTime(infoSrc, offsetTime, tt.args.subFilePath+FixMask+infoSrc.Ext)
+			//if err != nil {
+			//	t.Fatal(err)
+			//}
 
 
-			println(fmt.Sprintf("GetOffsetTimeV2: %vs SD:%v", offsetTime, sd))
+			//println(fmt.Sprintf("GetOffsetTimeV2: %vs SD:%v", offsetTime, sd))
 		})
 		})
 	}
 	}
 }
 }
@@ -763,6 +763,10 @@ func TestGetOffsetTimeV2_MoreTest(t *testing.T) {
 			baseSubFile: "C:\\Tmp\\Rick and Morty - S05E10\\英_2.ass",
 			baseSubFile: "C:\\Tmp\\Rick and Morty - S05E10\\英_2.ass",
 			srcSubFile:  "C:\\Tmp\\Rick and Morty - S05E10\\org.ass",
 			srcSubFile:  "C:\\Tmp\\Rick and Morty - S05E10\\org.ass",
 		}, want: -4.1, wantErr: false},
 		}, want: -4.1, wantErr: false},
+		{name: "mix", args: args{
+			baseSubFile: "C:\\Tmp\\Rick and Morty - S05E10\\英_2.ass",
+			srcSubFile:  "C:\\Tmp\\BL - S01E03\\org.ass",
+		}, want: -4.1, wantErr: false},
 	}
 	}
 
 
 	for _, tt := range tests {
 	for _, tt := range tests {
@@ -802,7 +806,7 @@ func TestGetOffsetTimeV2_MoreTest(t *testing.T) {
 			//	t.Errorf("GetOffsetTimeV1() error = %v, wantErr %v", err, tt.wantErr)
 			//	t.Errorf("GetOffsetTimeV1() error = %v, wantErr %v", err, tt.wantErr)
 			//	return
 			//	return
 			//}
 			//}
-			bok, got, sd, err := timelineFixer.GetOffsetTimeV2(baseUnitNew, srcUnitNew, nil)
+			bok, fixedResults, err := timelineFixer.GetOffsetTimeV2(baseUnitNew, srcUnitNew, nil)
 			if (err != nil) != tt.wantErr {
 			if (err != nil) != tt.wantErr {
 				t.Errorf("GetOffsetTimeV2() error = %v, wantErr %v", err, tt.wantErr)
 				t.Errorf("GetOffsetTimeV2() error = %v, wantErr %v", err, tt.wantErr)
 				return
 				return
@@ -814,12 +818,11 @@ func TestGetOffsetTimeV2_MoreTest(t *testing.T) {
 			debug_view.SaveDebugChart(*baseUnitNew, tt.name+" -- baseUnitNew", "baseUnitNew")
 			debug_view.SaveDebugChart(*baseUnitNew, tt.name+" -- baseUnitNew", "baseUnitNew")
 			debug_view.SaveDebugChart(*srcUnitNew, tt.name+" -- srcUnitNew", "srcUnitNew")
 			debug_view.SaveDebugChart(*srcUnitNew, tt.name+" -- srcUnitNew", "srcUnitNew")
 
 
-			_, err = timelineFixer.FixSubTimelineOneOffsetTime(infoSrc, got, tt.args.srcSubFile+FixMask+infoBase.Ext)
+			_, err = timelineFixer.FixSubTimelineByFixResults(infoSrc, srcUnitNew, fixedResults, tt.args.srcSubFile+FixMask+infoBase.Ext)
 			if err != nil {
 			if err != nil {
 				t.Fatal(err)
 				t.Fatal(err)
 			}
 			}
 
 
-			println(fmt.Sprintf("GetOffsetTimeV2: %fs SD:%f", got, sd))
 		})
 		})
 	}
 	}
 }
 }

+ 2 - 2
internal/pkg/sub_timeline_fixer/restore_test.go

@@ -6,7 +6,7 @@ import (
 
 
 func Test_searchBackUpSubFile(t *testing.T) {
 func Test_searchBackUpSubFile(t *testing.T) {
 
 
-	dir := "X:\\连续剧"
+	dir := "XLen:\\连续剧"
 	files, err := searchBackUpSubFile(dir)
 	files, err := searchBackUpSubFile(dir)
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
@@ -16,7 +16,7 @@ func Test_searchBackUpSubFile(t *testing.T) {
 
 
 func TestRestore(t *testing.T) {
 func TestRestore(t *testing.T) {
 
 
-	err := Restore("X:\\电影", "X:\\连续剧")
+	err := Restore("XLen:\\电影", "XLen:\\连续剧")
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}

+ 17 - 16
internal/types/subparser/fileinfo.go

@@ -7,17 +7,18 @@ import (
 )
 )
 
 
 type FileInfo struct {
 type FileInfo struct {
-	Content       string              // 字幕的内容
-	FromWhereSite string              // 从那个网站下载的
-	Name          string              // 字幕的名称,注意,这里需要额外的赋值,不会自动检测
-	Ext           string              // 字幕的后缀名
-	Lang          language.MyLanguage // 识别出来的语言
-	FileFullPath  string              // 字幕文件的全路径
-	Data          []byte              // 字幕的二进制文件内容
-	Dialogues     []OneDialogue       // 整个字幕文件的所有对话
-	DialoguesEx   []OneDialogueEx     // 整个字幕文件的所有对话,这里会把一句话中支持的 中、英、韩、日 四国语言给分离出来
-	CHLines       []string            // 抽取出所有的中文对话
-	OtherLines    []string            // 抽取出所有的第二语言对话,可能是英文、韩文、日文
+	Content           string              // 字幕的内容
+	FromWhereSite     string              // 从那个网站下载的
+	Name              string              // 字幕的名称,注意,这里需要额外的赋值,不会自动检测
+	Ext               string              // 字幕的后缀名
+	Lang              language.MyLanguage // 识别出来的语言
+	FileFullPath      string              // 字幕文件的全路径
+	Data              []byte              // 字幕的二进制文件内容
+	Dialogues         []OneDialogue       // 整个字幕文件的所有对话
+	DialoguesFilter   []OneDialogue       // 整个字幕文件的所有对话,过滤掉特殊字符的对白
+	DialoguesFilterEx []OneDialogueEx     // 整个字幕文件的所有对话,过滤掉特殊字符的对白,这里会把一句话中支持的 中、英、韩、日 四国语言给分离出来
+	CHLines           []string            // 抽取出所有的中文对话
+	OtherLines        []string            // 抽取出所有的第二语言对话,可能是英文、韩文、日文
 }
 }
 
 
 // GetTimeFormat 获取时间轴的格式化格式
 // GetTimeFormat 获取时间轴的格式化格式
@@ -51,15 +52,15 @@ func (f FileInfo) GetDialogueExContent(index int) string {
 		language.ChineseSimpleJapanese, language.ChineseSimpleKorean,
 		language.ChineseSimpleJapanese, language.ChineseSimpleKorean,
 		language.ChineseTraditionalJapanese, language.ChineseTraditionalKorean:
 		language.ChineseTraditionalJapanese, language.ChineseTraditionalKorean:
 		// 带有中文的,但是又不是中英的
 		// 带有中文的,但是又不是中英的
-		return f.DialoguesEx[index].ChLine
+		return f.DialoguesFilterEx[index].ChLine
 	case language.English, language.ChineseSimpleEnglish, language.ChineseTraditionalEnglish:
 	case language.English, language.ChineseSimpleEnglish, language.ChineseTraditionalEnglish:
-		return f.DialoguesEx[index].EnLine
+		return f.DialoguesFilterEx[index].EnLine
 	case language.Japanese:
 	case language.Japanese:
-		return f.DialoguesEx[index].JpLine
+		return f.DialoguesFilterEx[index].JpLine
 	case language.Korean:
 	case language.Korean:
-		return f.DialoguesEx[index].KrLine
+		return f.DialoguesFilterEx[index].KrLine
 	default:
 	default:
-		return f.DialoguesEx[index].EnLine
+		return f.DialoguesFilterEx[index].EnLine
 	}
 	}
 }
 }