From 6ba2eff56a40a7ad18d5def6a8849785a4dbf64f Mon Sep 17 00:00:00 2001
From: 641453620 <641453620@qq.com>
Date: Tue, 1 Sep 2020 16:19:28 +0800
Subject: [PATCH] =?UTF-8?q?=E5=8F=91=E5=B8=83=20Videosrt-0.3.2=20=E7=89=88?=
=?UTF-8?q?=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
1.修复个别视频分段处理报错的bug
2.支持设定关闭软件智能分段的功能
3.美化软件界面,优化提示
---
README.md | 10 +-
app/aliyun/tool.go | 37 +++++--
app/data.go | 1 +
app/event.go | 14 +++
app/tool/chinese_simple.go | 36 ++++---
app/video.go | 194 ++++++++++++++++++++++++++-----------
go.mod | 9 +-
main.go | 36 +++++--
8 files changed, 240 insertions(+), 97 deletions(-)
diff --git a/README.md b/README.md
index 943646b..a9edf59 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
这是一个可以识别视频语音自动生成字幕SRT文件的开源软件工具。
适用于快速、批量的为媒体(视频/音频)生成中/英文字幕、文本文件的业务场景。
-0.3.1 版本将会使用以下接口:
+0.3.2 版本将会使用以下接口:
- 阿里云 [OSS对象存储](https://www.aliyun.com/product/oss?spm=5176.12825654.eofdhaal5.13.e9392c4aGfj5vj&aly_as=K11FcpO8)
- 阿里云 [录音文件识别](https://ai.aliyun.com/nls/filetrans?spm=5176.12061031.1228726.1.47fe3cb43I34mn)
- 百度翻译开放平台 [翻译API](http://api.fanyi.baidu.com/api/trans/product/index)
@@ -14,8 +14,12 @@ CLI(命令行)版本:[https://github.com/wxbool/video-srt](https://github.
软件帮助文档/使用教程看这个:[https://www.yuque.com/viggo-t7cdi/videosrt](https://www.yuque.com/viggo-t7cdi/videosrt)
+B站Up主自制教程:[https://search.bilibili.com/all?keyword=videosrt](https://search.bilibili.com/all?keyword=videosrt)
+
线上“字幕生成/字幕翻译”解决方案:[字幕酱(付费)](https://www.zimujiang.com/aff?code=aannv4os)
+线上“文字配音/字幕配音/文章转视频”解决方案:[幕言](https://www.mu-yan.com/?videosrt)
+
## 界面预览
@@ -46,8 +50,8 @@ CLI(命令行)版本:[https://github.com/wxbool/video-srt](https://github.
##### 下载地址:
-- (v0.3.1)(含ffmpeg依赖) [点我下载](http://file.viggo.site/video-srt/0.3.1/video-srt-gui-ffmpeg-0.3.1-x64.zip)
-- (v0.3.1)(不含ffmpeg依赖) [点我下载](http://file.viggo.site/video-srt/0.3.1/video-srt-gui-0.3.1-x64.zip)
+- (v0.3.2)(含ffmpeg依赖) [点我下载](http://file.viggo.site/video-srt/0.3.2/video-srt-gui-ffmpeg-0.3.2-x64.zip)
+- (v0.3.2)(不含ffmpeg依赖) [点我下载](http://file.viggo.site/video-srt/0.3.2/video-srt-gui-0.3.2-x64.zip)
- (v0.2.6)(含ffmpeg依赖) [点我下载](http://file.viggo.site/video-srt/0.2.6/video-srt-gui-ffmpeg-0.2.6-x64.zip)
- (v0.2.6)(不含ffmpeg依赖) [点我下载](http://file.viggo.site/video-srt/0.2.6/video-srt-gui-0.2.6-x64.zip)
diff --git a/app/aliyun/tool.go b/app/aliyun/tool.go
index 35e0662..1690fbd 100644
--- a/app/aliyun/tool.go
+++ b/app/aliyun/tool.go
@@ -83,10 +83,13 @@ func AliyunAudioResultWordHandle(result [] byte , callback func (vresult *Aliyun
}
- var symbol = []string{"?","。",",","!",";","?",".",",","!"}
+ var symbol = []string{"?","。",",","!",";","、","?",".",",","!"}
//数据集处理
for _ , value := range audioResult {
for _ , data := range value {
+ // filter
+ data.Text = FilterText(data.Text)
+
data.Blocks = GetTextBlock(data.Text)
data.Text = ReplaceStrs(data.Text , symbol , "")
@@ -125,11 +128,20 @@ func AliyunAudioResultWordHandle(result [] byte , callback func (vresult *Aliyun
if ischinese {
block += word.Word
if tool.CheckChineseNumber(word.Word) && FindSliceIntCount(chineseNumberWordIndexs , i) == 0 {
- cl := tool.ChineseNumberToLowercaseLength(word.Word)
-
- if (cl - utf8.RuneCountInString(word.Word)) > 0 {
- chineseNumberDiffLength += (cl - utf8.RuneCountInString(word.Word))
+ cl := tool.ChineseNumberToLowercaseLength(word.Word) - utf8.RuneCountInString(word.Word)
+ if cl > 0 {
+ chineseNumberDiffLength += cl
chineseNumberWordIndexs = append(chineseNumberWordIndexs , i)
+ } else {
+ //例外
+ if i != 0 {
+ newWord := value[i-1].Word + word.Word
+ cl := tool.ChineseNumberToLowercaseLength(newWord) - utf8.RuneCountInString(newWord)
+ if cl > 0 {
+ chineseNumberDiffLength += cl
+ chineseNumberWordIndexs = append(chineseNumberWordIndexs , i)
+ }
+ }
}
}
} else {
@@ -157,11 +169,11 @@ func AliyunAudioResultWordHandle(result [] byte , callback func (vresult *Aliyun
if ((blockRune >= B) || (blockRune + chineseNumberDiffLength >= B)) && B != -1 {
flag = true
- //fmt.Println( w.Blocks )
+ //fmt.Println(w.Blocks)
//fmt.Println(B , lastBlock , (B - lastBlock) , word.Word)
//fmt.Println(w.Text)
//fmt.Println( block )
- //fmt.Println("\n\n\n")
+ //fmt.Println("\n")
var thisText = ""
//容错机制
@@ -353,7 +365,7 @@ func IndexRunes(strs string , olds []rune) int {
}
func GetTextBlock(strs string) ([]int) {
- var symbol_zhcn = []rune{'?','。',',','!',';','?','.',',','!'}
+ var symbol_zhcn = []rune{'?','。',',','!',';','、','?','.',',','!'}
//var symbol_en = []rune{'?','.',',','!'}
strsRune := []rune(strs)
@@ -390,3 +402,12 @@ func SubString(str string , begin int ,length int) (substr string) {
// 返回子串
return string(rs[begin:end])
}
+
+
+//过滤文本
+func FilterText(text string) string {
+ //去除换行符
+ re, _ := regexp.Compile("[\n|\r|\r\n]+")
+ text = re.ReplaceAllString(text, "")
+ return text
+}
\ No newline at end of file
diff --git a/app/data.go b/app/data.go
index ee01859..a609b1e 100644
--- a/app/data.go
+++ b/app/data.go
@@ -138,6 +138,7 @@ type AppSetings struct {
OutputLanguage int //输出字幕语言
OutputMainSubtitleInputLanguage bool //双语主字幕(输入语言)
+ CloseIntelligentBlockSwitch bool //关闭智能分段
CloseNewVersionMessage bool //关闭软件新版本提醒(默认开启)[false开启 true关闭]
CloseAutoDeleteOssTempFile bool //关闭自动删除临时音频文件(默认开启)[false开启 true关闭]
}
diff --git a/app/event.go b/app/event.go
index 016703e..5ed8d44 100644
--- a/app/event.go
+++ b/app/event.go
@@ -46,6 +46,7 @@ func(mw *MyMainWindow) RunAppSetingDialog(owner walk.Form , confirmCall func(*Ap
Dialog{
AssignTo: &dlg,
Title: "软件设置",
+ Font:Font{Family: "微软雅黑", PointSize: 9},
DefaultButton: &acceptPB,
CancelButton: &cancelPB,
DataBinder: DataBinder{
@@ -82,6 +83,12 @@ func(mw *MyMainWindow) RunAppSetingDialog(owner walk.Form , confirmCall func(*Ap
},
+ Label{
+ Text: "关闭软件智能分段处理:",
+ },
+ CheckBox{
+ Checked: Bind("CloseIntelligentBlockSwitch"),
+ },
Label{
Text: "关闭OSS临时文件清理:",
},
@@ -153,6 +160,7 @@ func(mw *MyMainWindow) RunSpeechEngineSetingDialog(owner walk.Form , confirmCall
Dialog{
AssignTo: &dlg,
Title: "新建语音引擎",
+ Font:Font{Family: "微软雅黑", PointSize: 9},
DefaultButton: &acceptPB,
CancelButton: &cancelPB,
DataBinder: DataBinder{
@@ -295,6 +303,7 @@ func(mw *MyMainWindow) RunBaiduTranslateEngineSetingDialog(owner walk.Form , con
Dialog{
AssignTo: &dlg,
Title: "新建翻译引擎(百度翻译)",
+ Font:Font{Family: "微软雅黑", PointSize: 9},
DefaultButton: &acceptPB,
CancelButton: &cancelPB,
DataBinder: DataBinder{
@@ -424,6 +433,7 @@ func(mw *MyMainWindow) RunTengxunyunTranslateEngineSetingDialog(owner walk.Form
Dialog{
AssignTo: &dlg,
Title: "新建翻译引擎(腾讯云)",
+ Font:Font{Family: "微软雅黑", PointSize: 9},
DefaultButton: &acceptPB,
CancelButton: &cancelPB,
DataBinder: DataBinder{
@@ -543,6 +553,7 @@ func (mw *MyMainWindow) RunObjectStorageSetingDialog(owner walk.Form) {
Dialog{
AssignTo: &dlg,
Title: "OSS对象存储设置",
+ Font:Font{Family: "微软雅黑", PointSize: 9},
DefaultButton: &acceptPB,
CancelButton: &cancelPB,
DataBinder: DataBinder{
@@ -670,6 +681,7 @@ func (mw *MyMainWindow) RunGlobalFilterSetingDialog (owner walk.Form , historyWo
Dialog{
AssignTo: &dlg,
Title: "全局语气词过滤设置",
+ Font:Font{Family: "微软雅黑", PointSize: 9},
DefaultButton: &acceptPB,
CancelButton: &cancelPB,
DataBinder: DataBinder{
@@ -837,6 +849,7 @@ func (mw *MyMainWindow) RunDefinedFilterSetingDialog (owner walk.Form , historyR
Dialog{
AssignTo: &dlg,
Title: "自定义过滤设置",
+ Font:Font{Family: "微软雅黑", PointSize: 9},
DefaultButton: &acceptPB,
CancelButton: &cancelPB,
MinSize: Size{600, 500},
@@ -955,6 +968,7 @@ func (mw *MyMainWindow) RunNewDefinedFilterRuleDialog (owner walk.Form , copyRow
Dialog{
AssignTo: &dlg,
Title: "新增自定义过滤规则",
+ Font:Font{Family: "微软雅黑", PointSize: 9},
DefaultButton: &acceptPB,
CancelButton: &cancelPB,
DataBinder: DataBinder{
diff --git a/app/tool/chinese_simple.go b/app/tool/chinese_simple.go
index 26f726d..5f0c66f 100644
--- a/app/tool/chinese_simple.go
+++ b/app/tool/chinese_simple.go
@@ -31,25 +31,29 @@ func ChineseNumberToLowercaseLength(s string) int {
numberPosi := true
maxBaseNumber := 1
- for i:=0; i 20 {
+ //输出比例
+ app.Log("字幕翻译已处理:" + fmt.Sprintf("%.2f" , rv) + "%" , video)
+ lastrv = rv
+ }
}
}
+ }
- for _ , data := range result {
- transResult,e := app.RunTranslate(data.Text , video)
- if e != nil {
- return e
- //panic(e) //终止翻译
+ if app.OutputType.TXT {
+ for channel,result := range AudioResult {
+ soundChannel := channel + 1
+ if outputSoundTrack != 3 && outputSoundTrack != 0 {
+ if outputSoundTrack != int(soundChannel) {
+ continue //跳出非输出音轨转换
+ }
}
- data.TranslateText = strings.TrimSpace(transResult.TransResultDst) //译文
- index++
- rv := (float64(index)/float64(totalRow))*100
- if (rv - lastrv) > 20 {
- //输出比例
- app.Log("字幕翻译已处理:" + fmt.Sprintf("%.2f" , rv) + "%" , video)
- lastrv = rv
+ for _ , data := range result {
+ transResult,e := app.RunTranslate(data.Text , video)
+ if e != nil {
+ return e
+ //panic(e) //终止翻译
+ }
+ data.TranslateText = strings.TrimSpace(transResult.TransResultDst) //译文
+
+ index++
+ rv := (float64(index)/float64(totalRow))*100
+ if (rv - lastrv) > 20 {
+ //输出比例
+ app.Log("字幕翻译已处理:" + fmt.Sprintf("%.2f" , rv) + "%" , video)
+ lastrv = rv
+ }
}
}
}
- }
+ } else { //关闭智能分段
+ for channel,result := range AudioResult {
+ soundChannel := channel + 1
+ if outputSoundTrack != 3 && outputSoundTrack != 0 {
+ if outputSoundTrack != int(soundChannel) {
+ continue //跳出非输出音轨转换
+ }
+ }
+ totalRow += len(result)
+ }
- if app.OutputType.TXT {
+ index := 0
+ //翻译任务
for channel,result := range AudioResult {
soundChannel := channel + 1
if outputSoundTrack != 3 && outputSoundTrack != 0 {
@@ -539,8 +610,6 @@ func AliyunAudioResultTranslate(app *VideoSrt , video string , AudioResult map[i
//panic(e) //终止翻译
}
data.TranslateText = strings.TrimSpace(transResult.TransResultDst) //译文
-
-
index++
rv := (float64(index)/float64(totalRow))*100
if (rv - lastrv) > 20 {
@@ -639,12 +708,19 @@ func AliyunAudioResultMakeSubtitleFile(app *VideoSrt , video string , outputType
//注入合适的数据块
thisAudioResult := make(map[int64][] *aliyun.AliyunAudioRecognitionResult)
- if outputType == OUTPUT_SRT || outputType == OUTPUT_LRC {
- thisAudioResult = IntelligentBlockResult
- } else if outputType == OUTPUT_STRING {
+
+ //开启智能分段
+ if !app.CloseIntelligentBlockSwitch {
+ if outputType == OUTPUT_SRT || outputType == OUTPUT_LRC {
+ thisAudioResult = IntelligentBlockResult
+ } else if outputType == OUTPUT_STRING {
+ thisAudioResult = AudioResult
+ }
+ } else {
thisAudioResult = AudioResult
}
+
oneSoundChannel := false //是否输出单条音轨
//根据音轨,输出文件
for channel,result := range thisAudioResult {
diff --git a/go.mod b/go.mod
index 6fab679..f1f6a9a 100644
--- a/go.mod
+++ b/go.mod
@@ -3,21 +3,24 @@ module videosrt
go 1.12
require (
+ github.com/JamesHovious/w32 v1.1.0
+ github.com/Onelio/winmm v0.0.0-20191219112928-4c30bd2f3ec1
github.com/PuerkitoBio/goquery v1.5.0
github.com/aliyun/alibaba-cloud-sdk-go v1.60.268
github.com/aliyun/aliyun-oss-go-sdk v2.0.4+incompatible
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
- github.com/bitly/go-simplejson v0.5.0
- github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/buger/jsonparser v0.0.0-20191004114745-ee4c978eae7e
github.com/dreamCodeMan/xfyun_go_sdk v0.0.0-20200227025001-249b66fa8600
- github.com/kr/pretty v0.2.0 // indirect
+ github.com/gen2brain/malgo v0.10.15 // indirect
+ github.com/hajimehoshi/go-mp3 v0.3.0 // indirect
github.com/lxn/walk v0.0.0-20191121152919-b7c43041fb1b
github.com/lxn/win v0.0.0-20191106123917-121afc750dd3 // indirect
github.com/mewkiz/flac v1.0.6
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/tencentcloud/tencentcloud-sdk-go v3.0.128+incompatible
+ github.com/youpy/go-riff v0.0.0-20131220112943-557d78c11efb // indirect
+ github.com/youpy/go-wav v0.0.0-20160223082350-b63a9887d320 // indirect
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect
diff --git a/main.go b/main.go
index b0fc0c0..6f0b690 100644
--- a/main.go
+++ b/main.go
@@ -13,7 +13,7 @@ import (
)
//应用版本号
-const APP_VERSION = "0.3.1"
+const APP_VERSION = "0.3.2"
var AppRootDir string
var mw *MyMainWindow
@@ -108,6 +108,7 @@ func main() {
AssignTo: &mw.MainWindow,
Icon:"./data/img/index.png",
Title: "VideoSrt - 一键字幕生成、字幕翻译小工具" + " - " + APP_VERSION,
+ Font:Font{Family: "微软雅黑", PointSize: 9},
ToolBar: ToolBar{
ButtonStyle: ToolBarButtonImageBeforeText,
Items: []MenuItem{
@@ -255,6 +256,7 @@ func main() {
appSetings.SrtFileDir = setings.SrtFileDir
appSetings.CloseNewVersionMessage = setings.CloseNewVersionMessage
appSetings.CloseAutoDeleteOssTempFile = setings.CloseAutoDeleteOssTempFile
+ appSetings.CloseIntelligentBlockSwitch = setings.CloseIntelligentBlockSwitch
multitask.SetMaxConcurrencyNumber( setings.MaxConcurrency )
srtTranslateMultitask.SetMaxConcurrencyNumber( setings.MaxConcurrency )
@@ -305,13 +307,13 @@ func main() {
Text: "语音合成配音/文章转视频",
Image: "./data/img/muyan.png",
OnTriggered: func() {
- _ = tool.OpenUrl("http://www.mu-yan.net/")
+ _ = tool.OpenUrl("https://www.mu-yan.net/")
},
},
},
},
- Size: Size{800, 600},
- MinSize: Size{300, 500},
+ Size: Size{800, 650},
+ MinSize: Size{300, 650},
Layout: VBox{},
Children: []Widget{
HSplitter{
@@ -728,9 +730,24 @@ func main() {
tlens := len(taskFiles.Files)
if tlens == 0 {
- mw.NewErrormationTips("错误" , "请先拖入要处理的媒体文件")
- return
+ //兼容外部调用
+ tempDropFilesEdit := dropFilesEdit.Text()
+ if tempDropFilesEdit != "" {
+ tempFileLists := strings.Split(tempDropFilesEdit , "\r\n")
+ //检测文件列表
+ tempResult , _ := VaildateHandleFiles(tempFileLists , true ,false)
+ if len(tempResult) != 0 {
+ taskFiles.Files = tempResult
+ dropFilesEdit.SetText(strings.Join(tempResult, "\r\n"))
+ }
+ }
+
+ if len(taskFiles.Files) == 0 {
+ mw.NewErrormationTips("错误" , "请先拖入要处理的媒体文件")
+ return
+ }
}
+
//校验文件列表
if _,e := VaildateHandleFiles(taskFiles.Files , true , false); e!=nil {
mw.NewErrormationTips("错误" , e.Error())
@@ -756,8 +773,10 @@ func main() {
if tempAppSetting.InputLanguage != LANGUAGE_ZH &&
tempAppSetting.InputLanguage != LANGUAGE_EN &&
tempAppSetting.InputLanguage != LANGUAGE_JP &&
+ tempAppSetting.InputLanguage != LANGUAGE_KOR &&
+ tempAppSetting.InputLanguage != LANGUAGE_RU &&
tempAppSetting.InputLanguage != LANGUAGE_SPA {
- mw.NewErrormationTips("错误" , "由于语音提供商的限制,生成字幕仅支持中文、英文、日语、西班牙语")
+ mw.NewErrormationTips("错误" , "由于语音提供商的限制,生成字幕仅支持中文、英文、日语、韩语、俄语、西班牙语")
return
}
@@ -808,6 +827,7 @@ func main() {
videosrt.SetSoundTrack(appSetings.SoundTrack)
videosrt.SetMaxConcurrency(appSetings.MaxConcurrency)
videosrt.SetCloseAutoDeleteOssTempFile(appSetings.CloseAutoDeleteOssTempFile)
+ videosrt.SetCloseIntelligentBlockSwitch(appSetings.CloseIntelligentBlockSwitch)
//设置输出文件
videosrt.SetOutputType(operateFrom.OutputType)
@@ -887,7 +907,7 @@ func main() {
//待处理的文件
tlens := len(taskFiles.Files)
if tlens == 0 {
- mw.NewErrormationTips("错误" , "请先拖入要处理的字幕文件")
+ mw.NewErrormationTips("错误" , "请先拖入需要处理的SRT字幕文件")
return
}
//校验文件列表