diff --git a/README.md b/README.md
index cd8e97f..5bb32f3 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
这是一个可以识别视频语音自动生成字幕SRT文件的开源软件工具。
适用于快速、批量的为媒体(视频/音频)生成中/英文字幕、文本文件的业务场景。
-0.2.9 版本将会使用以下接口:
+0.3.0 版本将会使用以下接口:
- 阿里云 [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)
@@ -25,7 +25,7 @@ CLI(命令行)版本:[https://github.com/wxbool/video-srt](https://github.
- 识别**视频/音频**的语音生成字幕文件(支持中英互译,双语字幕)
- 提取**视频/音频**的语音文本
-- 批量翻译、编码SRT字幕文件
+- 批量翻译、过滤处理/编码SRT字幕文件
@@ -36,7 +36,8 @@ CLI(命令行)版本:[https://github.com/wxbool/video-srt](https://github.
- 支持多任务多文件批量处理
- 支持视频、音频常见多种格式文件
- 支持同时输出字幕SRT文件、LRC文件、普通文本3种类型
-- 支持字幕中英互译、双语字幕输出
+- 支持语气词过滤、自定义文本过滤、正则过滤等,使软件生成的字幕更加精准
+- 支持字幕中英互译、双语字幕输出,及日语、韩语、法语、德语、西班牙语、俄语、意大利语、泰语等
- 支持多翻译引擎(百度翻译、腾讯云翻译)
- 支持批量翻译、编码SRT字幕文件
@@ -45,8 +46,8 @@ CLI(命令行)版本:[https://github.com/wxbool/video-srt](https://github.
##### 下载地址:
-- (v0.2.9.5)(含ffmpeg依赖) [点我下载](http://file.viggo.site/video-srt/0.2.9.5/video-srt-gui-ffmpeg-0.2.9.5-x64.zip)
-- (v0.2.9.5)(不含ffmpeg依赖) [点我下载](http://file.viggo.site/video-srt/0.2.9.5/video-srt-gui-0.2.9.5-x64.zip)
+- (v0.3.0)(含ffmpeg依赖) [点我下载](http://file.viggo.site/video-srt/0.3.0/video-srt-gui-ffmpeg-0.3.0-x64.zip)
+- (v0.3.0)(不含ffmpeg依赖) [点我下载](http://file.viggo.site/video-srt/0.3.0/video-srt-gui-0.3.0-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)
@@ -63,7 +64,7 @@ CLI(命令行)版本:[https://github.com/wxbool/video-srt](https://github.
- 先下载最新版本的软件包
- 然后用旧版本软件的 `data` 文件夹覆盖新版软件的 `data` 文件夹
-- 0.2.6 升级至 0.2.9时,翻译设置无法直接兼容低版本,需要重新手动创建翻译引擎才能继续使用翻译功能
+- 0.2.6 升级至 0.2.9 以上的版本时,由于翻译设置无法直接兼容低版本,可能需要重新在软件创建翻译引擎才能继续使用翻译功能
## FAQ
##### 1.为什么Linux和Mac不能用?
diff --git a/app/aliyun/tool.go b/app/aliyun/tool.go
index 05f60a6..5910d92 100644
--- a/app/aliyun/tool.go
+++ b/app/aliyun/tool.go
@@ -13,6 +13,8 @@ import (
type AliyunAudioRecognitionResultBlock struct {
AliyunAudioRecognitionResult
Blocks []int
+ BlockEmptyTag bool
+ BlockEmptyHandle bool
}
//阿里云录音录音文件识别 - 智能分段处理
@@ -87,6 +89,10 @@ func AliyunAudioResultWordHandle(result [] byte , callback func (vresult *Aliyun
for _ , data := range value {
data.Blocks = GetTextBlock(data.Text)
data.Text = ReplaceStrs(data.Text , symbol , "")
+
+ if len(data.Blocks) == 0 {
+ data.BlockEmptyTag = true
+ }
}
}
@@ -144,101 +150,124 @@ func AliyunAudioResultWordHandle(result [] byte , callback func (vresult *Aliyun
flag := false
early := false
- for t , B := range w.Blocks{
- //fmt.Println("blockRune : " , blockRune , B , word.Word)
- if ((blockRune >= B) || (blockRune + chineseNumberDiffLength >= B)) && B != -1 {
- flag = true
-
- //fmt.Println( w.Blocks )
- //fmt.Println(B , lastBlock , (B - lastBlock) , word.Word)
- //fmt.Println(w.Text)
- //fmt.Println( block )
- //fmt.Println("\n\n\n")
-
- var thisText = ""
- //容错机制
- if t == (len(w.Blocks) - 1) {
- thisText = SubString(w.Text , lastBlock , 10000)
- } else {
- //下个词提前结束
- if i < len(value)-1 && value[i+1].BeginTime >= w.EndTime{
+ if !w.BlockEmptyTag {
+ for t , B := range w.Blocks{
+ //fmt.Println("blockRune : " , blockRune , B , word.Word)
+ if ((blockRune >= B) || (blockRune + chineseNumberDiffLength >= B)) && B != -1 {
+ flag = true
+
+ //fmt.Println( w.Blocks )
+ //fmt.Println(B , lastBlock , (B - lastBlock) , word.Word)
+ //fmt.Println(w.Text)
+ //fmt.Println( block )
+ //fmt.Println("\n\n\n")
+
+ var thisText = ""
+ //容错机制
+ if t == (len(w.Blocks) - 1) {
thisText = SubString(w.Text , lastBlock , 10000)
- early = true
} else {
- thisText = SubString(w.Text , lastBlock , (B - lastBlock))
+ //下个词提前结束
+ if i < len(value)-1 && value[i+1].BeginTime >= w.EndTime{
+ thisText = SubString(w.Text , lastBlock , 10000)
+ early = true
+ } else {
+ thisText = SubString(w.Text , lastBlock , (B - lastBlock))
+ }
}
- }
- lastBlock = B
- if early == true {
- //全部设置为-1
- for vt,vb := range w.Blocks{
- if vb != -1 {
- w.Blocks[vt] = -1;
+ lastBlock = B
+ if early == true {
+ //全部设置为-1
+ for vt,vb := range w.Blocks{
+ if vb != -1 {
+ w.Blocks[vt] = -1;
+ }
}
+ } else {
+ w.Blocks[t] = -1
}
- } else {
- w.Blocks[t] = -1
+
+ vresult := &AliyunAudioRecognitionResult{
+ Text:thisText,
+ ChannelId:channel,
+ BeginTime:beginTime,
+ EndTime:word.EndTime,
+ SilenceDuration:w.SilenceDuration,
+ SpeechRate:w.SpeechRate,
+ EmotionValue:w.EmotionValue,
+ }
+ callback(vresult) //回调传参
+
+ blockBool = true
+ break
}
+ }
+
+ //fmt.Println("word.Word : " , word.Word)
+ //fmt.Println(block)
+
+ if FindSliceIntCount(w.Blocks , -1) == len(w.Blocks) {
+ //全部截取完成
+ block = ""
+ lastBlock = 0
+ }
+ //容错机制
+ if FindSliceIntCount(w.Blocks , -1) == (len(w.Blocks)-1) && flag == false {
+ var thisText = SubString(w.Text , lastBlock , 10000)
+ w.Blocks[len(w.Blocks) - 1] = -1
+ //vresult
vresult := &AliyunAudioRecognitionResult{
Text:thisText,
ChannelId:channel,
BeginTime:beginTime,
- EndTime:word.EndTime,
+ EndTime:w.EndTime,
SilenceDuration:w.SilenceDuration,
SpeechRate:w.SpeechRate,
EmotionValue:w.EmotionValue,
}
- callback(vresult) //回调传参
-
- blockBool = true
- break
- }
- }
- //fmt.Println("word.Word : " , word.Word)
- //fmt.Println(block)
-
- if FindSliceIntCount(w.Blocks , -1) == len(w.Blocks) {
- //全部截取完成
- block = ""
- lastBlock = 0
- }
-
- //容错机制
- if FindSliceIntCount(w.Blocks , -1) == (len(w.Blocks)-1) && flag == false {
- var thisText = SubString(w.Text , lastBlock , 10000)
-
- w.Blocks[len(w.Blocks) - 1] = -1
- //vresult
- vresult := &AliyunAudioRecognitionResult{
- Text:thisText,
- ChannelId:channel,
- BeginTime:beginTime,
- EndTime:w.EndTime,
- SilenceDuration:w.SilenceDuration,
- SpeechRate:w.SpeechRate,
- EmotionValue:w.EmotionValue,
- }
+ //fmt.Println( thisText )
+ //fmt.Println( block )
+ //fmt.Println( word.Word , beginTime, w.EndTime , flag , word.EndTime )
- //fmt.Println( thisText )
- //fmt.Println( block )
- //fmt.Println( word.Word , beginTime, w.EndTime , flag , word.EndTime )
+ callback(vresult) //回调传参
- callback(vresult) //回调传参
+ //覆盖下一段落的时间戳
+ if windex < (len(p)-1) {
+ beginTime = p[windex+1].BeginTime
+ } else {
+ beginTime = w.EndTime
+ }
- //覆盖下一段落的时间戳
- if windex < (len(p)-1) {
- beginTime = p[windex+1].BeginTime
- } else {
- beginTime = w.EndTime
+ //清除参数
+ block = ""
+ lastBlock = 0
}
+ } else {
//清除参数
block = ""
lastBlock = 0
+ blockBool = true
+
+ if w.BlockEmptyHandle == false {
+ vresult := &AliyunAudioRecognitionResult{
+ Text:w.Text,
+ ChannelId:w.ChannelId,
+ BeginTime:w.BeginTime,
+ EndTime:w.EndTime,
+ SilenceDuration:w.SilenceDuration,
+ SpeechRate:w.SpeechRate,
+ EmotionValue:w.EmotionValue,
+ }
+ callback(vresult) //回调传参
+ w.BlockEmptyHandle = true
+ }
+
}
+
}
}
}
diff --git a/app/app_tool.go b/app/app_tool.go
index 7f67478..6a27cc7 100644
--- a/app/app_tool.go
+++ b/app/app_tool.go
@@ -2,10 +2,48 @@ package app
import (
"bytes"
+ "regexp"
"strconv"
+ "strings"
"videosrt/app/tool"
)
+
+//语气词过滤
+func ModalWordsFilter(s string , w string) string {
+ tmpText := strings.ReplaceAll(s , w , "")
+ if strings.TrimSpace(tmpText) == "" || tool.CheckOnlySymbolText(strings.TrimSpace(tmpText)) {
+ return ""
+ } else {
+ //尝试过滤重复语气词
+ compile, e := regexp.Compile(w + "{2,}")
+ if e != nil {
+ return s
+ }
+ return compile.ReplaceAllString(s , "")
+ }
+}
+
+//自定义规则过滤
+func DefinedWordRuleFilter(s string , rule *AppDefinedFilterRule) string {
+ if rule.Way == FILTER_TYPE_STRING {
+ //文本过滤
+ s = strings.ReplaceAll(s , rule.Target , rule.Replace)
+ } else if rule.Way == FILTER_TYPE_REGX {
+ //正则过滤
+ compile, e := regexp.Compile(rule.Target)
+ if e != nil {
+ return s
+ }
+ s = compile.ReplaceAllString(s , rule.Replace)
+ }
+ if strings.TrimSpace(s) == "" || tool.CheckOnlySymbolText(strings.TrimSpace(s)) {
+ return ""
+ }
+ return s
+}
+
+
//拼接字幕字符串
func MakeSubtitleText(index int , startTime int64 , endTime int64 , text string , translateText string , bilingualSubtitleSwitch bool , bilingualAsc bool) string {
var content bytes.Buffer
diff --git a/app/data.go b/app/data.go
index e00cceb..ee01859 100644
--- a/app/data.go
+++ b/app/data.go
@@ -25,6 +25,12 @@ const (
LANGUAGE_EN = 2 //英文
LANGUAGE_JP = 3 //日语
LANGUAGE_KOR = 4 //韩语
+ LANGUAGE_FRA = 5 //法语 fra
+ LANGUAGE_DE = 6 //德语 de
+ LANGUAGE_SPA = 7 //西班牙语 spa
+ LANGUAGE_RU = 8 //俄语 ru
+ LANGUAGE_IT = 9 //意大利语 it
+ LANGUAGE_TH = 10 //泰语 th
)
//缓存结构
@@ -40,12 +46,16 @@ type SpeechEngineAppStruct struct {
type AppSetingsAppStruct struct {
Data *datacache.AppCache
}
+type AppFilterAppStruct struct {
+ Data *datacache.AppCache
+}
var RootDir string
var Oss *OssAppStruct
var Translate *TranslateEngineAppStruct
var Engine *SpeechEngineAppStruct
var Setings *AppSetingsAppStruct
+var Filter *AppFilterAppStruct
func init() {
@@ -58,11 +68,13 @@ func init() {
Translate = new(TranslateEngineAppStruct)
Engine = new(SpeechEngineAppStruct)
Setings = new(AppSetingsAppStruct)
+ Filter = new(AppFilterAppStruct)
Oss.Data = datacache.NewAppCahce(RootDir , "oss")
Translate.Data = datacache.NewAppCahce(RootDir , "translate_engine")
Engine.Data = datacache.NewAppCahce(RootDir , "engine")
Setings.Data = datacache.NewAppCahce(RootDir , "setings")
+ Filter.Data = datacache.NewAppCahce(RootDir , "filter")
}
@@ -110,7 +122,7 @@ type AppSetingsOutput struct {
TXT bool
}
-//应用配置 - 缓存结构
+//应用配置结构
type AppSetings struct {
CurrentEngineId int //目前语音引擎Id
CurrentTranslateEngineId int //目前翻译引擎Id
@@ -130,6 +142,32 @@ type AppSetings struct {
CloseAutoDeleteOssTempFile bool //关闭自动删除临时音频文件(默认开启)[false开启 true关闭]
}
+
+const (
+ FILTER_TYPE_STRING = 1 //文本过滤
+ FILTER_TYPE_REGX = 2 //正则过滤
+)
+//自定义过滤器规则
+type AppDefinedFilterRule struct {
+ Target string //目标规则
+ Replace string //替换规则
+ Way int //规则类型
+}
+//应用字幕过滤器结构
+type AppFilterSetings struct {
+ //通用过滤器
+ GlobalFilter struct{
+ Switch bool
+ Words string //过滤词组
+ }
+ //自定义过滤器
+ DefinedFilter struct{
+ Switch bool
+ Rule [] *AppDefinedFilterRule
+ }
+}
+
+
//任务文件列表 - 结构
type TaskHandleFile struct {
Files [] string
@@ -224,6 +262,12 @@ func GetTranslateInputLanguageOptionsSelects() []*LanguageSelects {
&LanguageSelects{Id:LANGUAGE_EN , Name:"英文"},
&LanguageSelects{Id:LANGUAGE_JP , Name:"日语"},
&LanguageSelects{Id:LANGUAGE_KOR , Name:"韩语"},
+ &LanguageSelects{Id:LANGUAGE_FRA , Name:"法语"},
+ &LanguageSelects{Id:LANGUAGE_DE , Name:"德语"},
+ &LanguageSelects{Id:LANGUAGE_SPA , Name:"西班牙语"},
+ &LanguageSelects{Id:LANGUAGE_RU , Name:"俄语"},
+ &LanguageSelects{Id:LANGUAGE_IT , Name:"意大利语"},
+ &LanguageSelects{Id:LANGUAGE_TH , Name:"泰语"},
}
}
@@ -234,6 +278,12 @@ func GetTranslateOutputLanguageOptionsSelects() []*LanguageSelects {
&LanguageSelects{Id:LANGUAGE_EN , Name:"英文"},
&LanguageSelects{Id:LANGUAGE_JP , Name:"日语"},
&LanguageSelects{Id:LANGUAGE_KOR , Name:"韩语"},
+ &LanguageSelects{Id:LANGUAGE_FRA , Name:"法语"},
+ &LanguageSelects{Id:LANGUAGE_DE , Name:"德语"},
+ &LanguageSelects{Id:LANGUAGE_SPA , Name:"西班牙语"},
+ &LanguageSelects{Id:LANGUAGE_RU , Name:"俄语"},
+ &LanguageSelects{Id:LANGUAGE_IT , Name:"意大利语"},
+ &LanguageSelects{Id:LANGUAGE_TH , Name:"泰语"},
}
}
@@ -259,6 +309,32 @@ func (setings *AppSetingsAppStruct) SetCacheAppSetingsData(data *AppSetings) {
+//获取 应用过滤器配置
+func (setings *AppFilterAppStruct) GetCacheAppFilterData() *AppFilterSetings {
+ data := new(AppFilterSetings)
+ vdata := setings.Data.Get(data)
+ if v, ok := vdata.(*AppFilterSetings); ok {
+ return v
+ }
+ return data
+}
+//设置 应用过滤器配置
+func (setings *AppFilterAppStruct) SetCacheAppFilterData(data *AppFilterSetings) {
+ setings.Data.Set(data)
+}
+
+//过滤类型选项结构
+type FilterTypeSelects struct {
+ Id int
+ Name string
+}
+//获取 过滤类型选项列表
+func GetFilterTypeOptionsSelects() []*FilterTypeSelects {
+ return []*FilterTypeSelects{
+ &FilterTypeSelects{Id:FILTER_TYPE_STRING , Name:"文本替换"},
+ &FilterTypeSelects{Id:FILTER_TYPE_REGX , Name:"正则替换"},
+ }
+}
@@ -291,6 +367,7 @@ func (oss *OssAppStruct) GetCacheAliyunOssData() *AliyunOssCache {
+
//阿里云语音识别引擎 - 缓存结构
type AliyunEngineCache struct {
aliyun.AliyunClound
@@ -530,6 +607,18 @@ func GetLanguageChar(Language int , Supplier int) string {
return "jp"
case LANGUAGE_KOR:
return "kor"
+ case LANGUAGE_FRA:
+ return "fra"
+ case LANGUAGE_DE:
+ return "de"
+ case LANGUAGE_SPA:
+ return "spa"
+ case LANGUAGE_RU:
+ return "ru"
+ case LANGUAGE_IT:
+ return "it"
+ case LANGUAGE_TH:
+ return "th"
}
}
if Supplier == TRANSLATE_SUPPLIER_TENGXUNYUN {
@@ -542,6 +631,18 @@ func GetLanguageChar(Language int , Supplier int) string {
return "jp"
case LANGUAGE_KOR:
return "kr"
+ case LANGUAGE_FRA:
+ return "fr"
+ case LANGUAGE_DE:
+ return "de"
+ case LANGUAGE_SPA:
+ return "es"
+ case LANGUAGE_RU:
+ return "ru"
+ case LANGUAGE_IT:
+ return "it"
+ case LANGUAGE_TH:
+ return "th"
}
}
return ""
diff --git a/app/event.go b/app/event.go
index e96510f..016703e 100644
--- a/app/event.go
+++ b/app/event.go
@@ -8,6 +8,7 @@ import (
"os"
"path"
"path/filepath"
+ "regexp"
"strings"
"videosrt/app/aliyun"
"videosrt/app/tool"
@@ -241,6 +242,11 @@ func(mw *MyMainWindow) RunSpeechEngineSetingDialog(owner walk.Form , confirmCall
return
}
+ //去空格
+ engine.AppKey = strings.TrimSpace(engine.AppKey)
+ engine.AccessKeyId = strings.TrimSpace(engine.AccessKeyId)
+ engine.AccessKeySecret = strings.TrimSpace(engine.AccessKeySecret)
+
//获取缓存数据
localData := Engine.GetCacheAliyunEngineListData()
//生成id
@@ -273,8 +279,6 @@ func(mw *MyMainWindow) RunSpeechEngineSetingDialog(owner walk.Form , confirmCall
}
-
-
// 运行 新建[百度]翻译引擎 Dialog
func(mw *MyMainWindow) RunBaiduTranslateEngineSetingDialog(owner walk.Form , confirmCall func()) {
var engine *TranslateEngineStruct
@@ -370,6 +374,10 @@ func(mw *MyMainWindow) RunBaiduTranslateEngineSetingDialog(owner walk.Form , con
return
}
+ //去空格
+ engine.BaiduEngine.AppId = strings.TrimSpace(engine.BaiduEngine.AppId)
+ engine.BaiduEngine.AppSecret = strings.TrimSpace(engine.BaiduEngine.AppSecret)
+
//获取缓存数据
localData := Translate.GetCacheTranslateEngineListData()
//生成id
@@ -485,6 +493,10 @@ func(mw *MyMainWindow) RunTengxunyunTranslateEngineSetingDialog(owner walk.Form
return
}
+ //去空格
+ engine.TengxunyunEngine.SecretId = strings.TrimSpace(engine.TengxunyunEngine.SecretId)
+ engine.TengxunyunEngine.SecretKey = strings.TrimSpace(engine.TengxunyunEngine.SecretKey)
+
//获取缓存数据
localData := Translate.GetCacheTranslateEngineListData()
//生成id
@@ -646,6 +658,396 @@ func (mw *MyMainWindow) RunObjectStorageSetingDialog(owner walk.Form) {
}
+//运行 语气词过滤设置 Dialog
+func (mw *MyMainWindow) RunGlobalFilterSetingDialog (owner walk.Form , historyWords string , confirmCall func(words string)) {
+ var dlg *walk.Dialog
+ var db *walk.DataBinder
+ var acceptPB, cancelPB *walk.PushButton
+
+ var tmpData = new(AppFilterSetings)
+ tmpData.GlobalFilter.Words = historyWords
+
+ Dialog{
+ AssignTo: &dlg,
+ Title: "全局语气词过滤设置",
+ DefaultButton: &acceptPB,
+ CancelButton: &cancelPB,
+ DataBinder: DataBinder{
+ AssignTo: &db,
+ Name: "filter",
+ DataSource: tmpData,
+ },
+ MinSize: Size{500, 300},
+ Layout: VBox{},
+ Children: []Widget{
+ Composite{
+ Layout: Grid{Columns: 2},
+ Children: []Widget{
+ Label{
+ ColumnSpan: 1,
+ Text: "过滤语气词:",
+ },
+ TextEdit{
+ ColumnSpan: 1,
+ MinSize: Size{150, 80},
+ Text: Bind("GlobalFilter.Words"),
+ VScroll: true,
+ },
+ Label{
+ ColumnSpan: 2,
+ Text: "说明:\r\n“过滤语气词” 支持设置多个,请保持每个词语都单独一行",
+ TextColor:walk.RGB(190 , 190 , 190),
+ },
+ },
+ },
+ Composite{
+ Layout: HBox{},
+ Children: []Widget{
+ HSpacer{},
+ PushButton{
+ AssignTo: &acceptPB,
+ Text: "保存",
+ OnClicked: func() {
+ if err := db.Submit(); err != nil {
+ log.Fatal(err)
+ return
+ }
+ confirmCall(tmpData.GlobalFilter.Words)
+ //参数验证
+ dlg.Accept()
+ },
+ },
+ PushButton{
+ AssignTo: &cancelPB,
+ Text: "取消",
+ OnClicked: func() { dlg.Cancel() },
+ },
+ },
+ },
+ },
+ }.Run( owner )
+}
+
+
+
+type DefinedRuleTableRows struct {
+ Id int
+ Target string //目标规则
+ Replace string //替换规则
+ Way int //规则类型
+}
+type DefinedRuleTableModel struct {
+ walk.SortedReflectTableModelBase
+ maxIndex int
+ items []*DefinedRuleTableRows
+}
+func NewDefinedRuleTableModel () *DefinedRuleTableModel {
+ t := new(DefinedRuleTableModel)
+ return t
+}
+func (m *DefinedRuleTableModel) Items() interface{} {
+ return m.items
+}
+func (m *DefinedRuleTableModel) AddRow (row *DefinedRuleTableRows) {
+ m.maxIndex++
+ row.Id = m.maxIndex;
+ m.items = append(m.items , row)
+}
+func (m *DefinedRuleTableModel) BatchDelRow (indexs []int) {
+ id := make([]int , 0)
+ for row_i , row_v := range m.items {
+ for _ , op_v := range indexs {
+ if row_i == op_v {
+ id = append(id , row_v.Id)
+ }
+ }
+ }
+ for _ , vid := range id {
+ m.DelRow(vid)
+ }
+}
+func (m *DefinedRuleTableModel) GetRowIndex (index int) *DefinedRuleTableRows {
+ tmp := new(DefinedRuleTableRows)
+ for row_i , row_v := range m.items {
+ if row_i == index {
+ tmp = row_v
+ break
+ }
+ }
+ return tmp
+}
+func (m *DefinedRuleTableModel) DelRow (id int) {
+ t := len(m.items)
+ for row_i , row_v := range m.items {
+ if row_v.Id == id {
+ if row_i == 0 {
+ if t <= 1 {
+ m.items = make([]*DefinedRuleTableRows , 0)
+ } else {
+ m.items = m.items[row_i+1:]
+ }
+ } else if row_i+1 >= t {
+ m.items = m.items[:row_i]
+ } else {
+ m.items = append(m.items[:row_i] , m.items[row_i+1:]...)
+ }
+ break
+ }
+ }
+}
+func (tv *DefinedRuleTableModel) SetAndInitFilterRules (rules []*AppDefinedFilterRule) {
+ //初始化
+ tv.maxIndex = 0
+ tv.items = make([]*DefinedRuleTableRows , 0)
+
+ for _ , v := range rules {
+ tv.maxIndex++
+ tv.items = append(tv.items , &DefinedRuleTableRows{
+ Id:tv.maxIndex,
+ Target:v.Target,
+ Replace:v.Replace,
+ Way:v.Way,
+ })
+ }
+}
+func (tv *DefinedRuleTableModel) GetFilterRuleResult () []*AppDefinedFilterRule {
+ result := make([]*AppDefinedFilterRule , 0)
+ for _ , v := range tv.items {
+ result = append(result , &AppDefinedFilterRule{
+ Target:v.Target,
+ Replace:v.Replace,
+ Way:v.Way,
+ })
+ }
+ return result
+}
+
+
+//运行 自定义过滤设置 Dialog
+func (mw *MyMainWindow) RunDefinedFilterSetingDialog (owner walk.Form , historyRule []*AppDefinedFilterRule , confirmCall func(rule []*AppDefinedFilterRule)) {
+ var dlg *walk.Dialog
+ var acceptPB, cancelPB *walk.PushButton
+ var tv *walk.TableView
+
+ tableModel := NewDefinedRuleTableModel()
+ tableModel.SetAndInitFilterRules(historyRule)
+
+ var currentIndexs []int = make([]int , 0) //选择的项
+
+ Dialog{
+ AssignTo: &dlg,
+ Title: "自定义过滤设置",
+ DefaultButton: &acceptPB,
+ CancelButton: &cancelPB,
+ MinSize: Size{600, 500},
+ Layout: VBox{},
+ Children: []Widget{
+ Composite{
+ Layout: Grid{Columns: 2},
+ Children: []Widget{
+ PushButton{
+ Text: "新增规则",
+ OnClicked: func() {
+ copyRow := new(DefinedRuleTableRows)
+ if len(currentIndexs) == 1 {
+ copyRow = tableModel.GetRowIndex(currentIndexs[0])
+ }
+
+ mw.RunNewDefinedFilterRuleDialog(mw , copyRow , func(rule *DefinedRuleTableRows) {
+ tableModel.AddRow(rule)
+ tv.SetModel(tableModel)
+ })
+ },
+ },
+ PushButton{
+ Text: "删除规则",
+ OnClicked: func() {
+ if len(currentIndexs) < 1 {
+ mw.NewErrormationTips("错误" , "请选择操作的对象")
+ return
+ }
+ tableModel.BatchDelRow(currentIndexs)
+ tv.SetModel(tableModel)
+ },
+ },
+ },
+ },
+ Composite{
+ Layout: HBox{},
+ Children: []Widget{
+ TableView{
+ Name:"tableView",
+ AssignTo: &tv,
+ AlternatingRowBG: true,
+ NotSortableByHeaderClick: true,
+ MultiSelection:true,
+ Columns: []TableViewColumn{
+ {Title: "编号", DataMember: "Id" , Width:90},
+ {Title: "类型", DataMember: "Way", Width:90 , FormatFunc: func(value interface{}) string {
+ switch v := value.(type) {
+ case int:
+ if v == FILTER_TYPE_STRING {
+ return "文本过滤"
+ }
+ if v == FILTER_TYPE_REGX {
+ return "正则过滤"
+ }
+ return ""
+ default:
+ return ""
+ }
+ }},
+ {Title: "目标规则", DataMember: "Target", Width:165},
+ {Title: "替换规则", DataMember: "Replace", Width:185},
+ },
+ Model: tableModel,
+ OnSelectedIndexesChanged: func() {
+ indexs := tv.SelectedIndexes()
+ if (len(indexs) > 0) {
+ currentIndexs = indexs
+ } else {
+ currentIndexs = []int{}
+ }
+ },
+ },
+ },
+ },
+ Composite{
+ Layout: HBox{},
+ Children: []Widget{
+ HSpacer{},
+ PushButton{
+ AssignTo: &acceptPB,
+ Text: "保存",
+ OnClicked: func() {
+ confirmCall(tableModel.GetFilterRuleResult())
+
+ //参数验证
+ dlg.Accept()
+ },
+ },
+ PushButton{
+ AssignTo: &cancelPB,
+ Text: "取消",
+ OnClicked: func() { dlg.Cancel() },
+ },
+ },
+ },
+ },
+ }.Run(owner)
+}
+
+//新建自定义过滤规则 Dialog
+func (mw *MyMainWindow) RunNewDefinedFilterRuleDialog (owner walk.Form , copyRows *DefinedRuleTableRows , confirmCall func(rule *DefinedRuleTableRows)) {
+ var dlg *walk.Dialog
+ var db *walk.DataBinder
+ var acceptPB, cancelPB *walk.PushButton
+
+ var tmpData = new(DefinedRuleTableRows)
+ if copyRows.Id != 0 {
+ tmpData.Target = copyRows.Target
+ tmpData.Replace = copyRows.Replace
+ tmpData.Way = copyRows.Way
+ } else {
+ tmpData.Way = 1 //默认
+ }
+
+ Dialog{
+ AssignTo: &dlg,
+ Title: "新增自定义过滤规则",
+ DefaultButton: &acceptPB,
+ CancelButton: &cancelPB,
+ DataBinder: DataBinder{
+ AssignTo: &db,
+ Name: "defined",
+ DataSource: tmpData,
+ },
+ MinSize: Size{500, 300},
+ Layout: VBox{},
+ Children: []Widget{
+ Composite{
+ Layout: Grid{Columns: 2},
+ Children: []Widget{
+ Label{
+ ColumnSpan: 1,
+ Text: "目标规则:",
+ },
+ LineEdit{
+ ColumnSpan: 1,
+ MinSize: Size{Width:150},
+ Text: Bind("Target"),
+ },
+ Label{
+ ColumnSpan: 1,
+ Text: "替换规则:",
+ },
+ LineEdit{
+ ColumnSpan: 1,
+ MinSize: Size{Width:150},
+ Text: Bind("Replace"),
+ },
+ Label{
+ Text: "过滤类型:",
+ },
+ ComboBox{
+ Value: Bind("Way", SelRequired{}),
+ BindingMember: "Id",
+ DisplayMember: "Name",
+ Model: GetFilterTypeOptionsSelects(),
+ },
+
+ Label{
+ ColumnSpan: 2,
+ Text: "说明:\r\n1.“目标规则” 填写查找的文本/正则, “替换规则” 填写替换的文本/正则\r\n2.过滤类型为正则时,“替换规则” 允许使用 $1...$9 进行反向引用",
+ TextColor:walk.RGB(190 , 190 , 190),
+ },
+ },
+ },
+ Composite{
+ Layout: HBox{},
+ Children: []Widget{
+ HSpacer{},
+ PushButton{
+ AssignTo: &acceptPB,
+ Text: "保存",
+ OnClicked: func() {
+ if err := db.Submit(); err != nil {
+ log.Fatal(err)
+ return
+ }
+ if strings.TrimSpace(tmpData.Target) == "" {
+ mw.NewErrormationTips("错误" , "必须填写目标规则噢")
+ return
+ }
+ if tmpData.Way == FILTER_TYPE_REGX {
+ //正则规则
+ //校验规则
+ _, e := regexp.Compile(tmpData.Target)
+ if e != nil {
+ mw.NewErrormationTips("错误" , "目标正则规则格式校验不通过,请检查是否正确")
+ return
+ }
+ }
+
+ confirmCall(tmpData)
+ //参数验证
+ dlg.Accept()
+ },
+ },
+ PushButton{
+ AssignTo: &cancelPB,
+ Text: "取消",
+ OnClicked: func() { dlg.Cancel() },
+ },
+ },
+ },
+ },
+ }.Run( owner )
+}
+
+
+
+
//打开 Github
func (mw *MyMainWindow) OpenAboutGithub() {
tool.OpenUrl("https://github.com/wxbool/video-srt-windows")
diff --git a/app/srt.go b/app/srt.go
index 27d8a7a..767a67a 100644
--- a/app/srt.go
+++ b/app/srt.go
@@ -57,6 +57,7 @@ type SrtTranslateApp struct {
OutputEncode int //输出文件编码
MaxConcurrency int //最大处理并发数
TranslateCfg *SrtTranslateStruct //翻译配置
+ FilterSetings *AppFilterSetings //过滤器配置
LogHandler func(s string , file string) //日志回调
SuccessHandler func(file string) //成功回调
@@ -79,6 +80,11 @@ func NewSrtTranslateApp(appDir string) *SrtTranslateApp {
func (app *SrtTranslateApp) InitTranslateConfig (translateSettings *SrtTranslateStruct) {
app.TranslateCfg = translateSettings
}
+//加载过滤器配置
+func (app *SrtTranslateApp) InitFilterConfig (filterSetings *AppFilterSetings) {
+ app.FilterSetings = filterSetings
+}
+
func (app *SrtTranslateApp) SetSrtDir(dir string) {
app.SrtDir = dir
@@ -154,6 +160,9 @@ func (app *SrtTranslateApp) Run(srtfile string) {
//字幕翻译
app.SrtTranslate(srtfile , srtRows)
+ //字幕过滤
+ app.SrtFilters(srtRows , srtfile)
+
//输出文件
if app.OutputType.SRT {
app.SrtOutputFile(srtfile , srtRows , OUTPUT_SRT)
@@ -236,6 +245,40 @@ func (app *SrtTranslateApp) SrtTranslate(file string , srtRows []*SrtRows) {
}
+//字幕过滤处理
+func (app *SrtTranslateApp) SrtFilters (srtRows []*SrtRows , file string) {
+ if !app.FilterSetings.DefinedFilter.Switch && !app.FilterSetings.GlobalFilter.Switch {
+ return
+ }
+
+ app.Log("字幕过滤处理中 ..." , file)
+
+ //语气词过滤
+ if app.FilterSetings.GlobalFilter.Switch && strings.TrimSpace(app.FilterSetings.GlobalFilter.Words) != "" {
+ modalWords := strings.Split(app.FilterSetings.GlobalFilter.Words , "\r\n")
+ for _ , row := range srtRows {
+ for _ , w := range modalWords {
+ row.Text = ModalWordsFilter(row.Text , w)
+ if app.TranslateCfg.TranslateSwitch {
+ row.TranslateText = ModalWordsFilter(row.TranslateText , w)
+ }
+ }
+ }
+ }
+ //自定义规则过滤
+ if app.FilterSetings.DefinedFilter.Switch && len(app.FilterSetings.DefinedFilter.Rule) > 0 {
+ rules := app.FilterSetings.DefinedFilter.Rule
+ for _ , row := range srtRows {
+ for _ , ru := range rules {
+ row.Text = DefinedWordRuleFilter(row.Text , ru)
+ if app.TranslateCfg.TranslateSwitch {
+ row.TranslateText = DefinedWordRuleFilter(row.TranslateText , ru)
+ }
+ }
+ }
+ }
+}
+
//文件输出
func (app *SrtTranslateApp) SrtOutputFile(file string , srtRows []*SrtRows , outputType int) {
var subfileDir string
@@ -283,6 +326,10 @@ func (app *SrtTranslateApp) SrtOutputFile(file string , srtRows []*SrtRows , out
for _ , data := range srtRows {
var linestr string
+ if data.Text == "" {
+ continue //跳过空行
+ }
+
//字幕、歌词文件处理
if outputType == OUTPUT_SRT || outputType == OUTPUT_LRC {
//拼接
diff --git a/app/tool/chinese_simple.go b/app/tool/chinese_simple.go
index eb9c590..2d544f8 100644
--- a/app/tool/chinese_simple.go
+++ b/app/tool/chinese_simple.go
@@ -1,7 +1,9 @@
package tool
import (
+ "regexp"
"strings"
+ "unicode/utf8"
)
@@ -81,3 +83,23 @@ func ValiChineseNumberChar(s string , unit bool) bool {
}
return false
}
+
+
+//获取utf8字符长度
+func GetStringUtf8Length(s string) int {
+ return utf8.RuneCountInString(s)
+}
+
+
+//检测文本是否仅符号
+func CheckOnlySymbolText(s string) bool {
+ if GetStringUtf8Length(s) > 6 {
+ return false
+ }
+ regx := regexp.MustCompile(`^(\\|\{|\}|\[|\]|(|)|\(|\)|\*|/|~|<|>|_|\-|\+|=|&|%|\$|@|#|—|」|「|!|,|。|。||、|?|;|:|‘|’|”|“|"|'|,|\.|\?|;|:|!|\s)+$`)
+ if regx.Match([]byte(s)) {
+ return true
+ } else {
+ return false
+ }
+}
\ No newline at end of file
diff --git a/app/video.go b/app/video.go
index 4d784b7..10854d4 100644
--- a/app/video.go
+++ b/app/video.go
@@ -54,6 +54,7 @@ type VideoSrt struct {
MaxConcurrency int //最大处理并发数
TranslateCfg *VideoSrtTranslateStruct //翻译配置
+ FilterSetings *AppFilterSetings //过滤器配置
LogHandler func(s string , video string) //日志回调
SuccessHandler func(video string) //成功回调
@@ -97,6 +98,10 @@ func (app *VideoSrt) InitAppConfig(oss *AliyunOssCache , engine *AliyunEngineCac
func (app *VideoSrt) InitTranslateConfig (translateSettings *VideoSrtTranslateStruct) {
app.TranslateCfg = translateSettings
}
+//加载过滤器配置
+func (app *VideoSrt) InitFilterConfig (filterSetings *AppFilterSetings) {
+ app.FilterSetings = filterSetings
+}
func (app *VideoSrt) SetCloseAutoDeleteOssTempFile(state bool) {
@@ -224,7 +229,13 @@ func (app *VideoSrt) Run(video string) {
app.Log("文件识别成功 , 字幕处理中 ..." , video)
//翻译字幕块
- AliyunAudioResultTranslate(app , video , AudioResult , IntelligentBlockResult)
+ if e := AliyunAudioResultTranslate(app , video , AudioResult , IntelligentBlockResult); e != nil {
+ app.Log("字幕翻译失败,已强制关闭翻译,仅保留原始文件" , video)
+ app.TranslateCfg.TranslateSwitch = false
+ }
+
+ //字幕过滤
+ AliyunResultFilter(app , video , AudioResult , IntelligentBlockResult)
//输出文件
if app.OutputType.SRT {
@@ -371,7 +382,7 @@ func AliyunAudioRecognition(engine aliyun.AliyunClound , filelink string) (Audio
//遍历获取识别结果
resultError := engine.GetAudioFileResult(taskid , client , func(result []byte) {
- //mylog.WriteLog( string( result ) )
+ //mylog.WriteLog(string(result))
//结果处理
statusText, _ := jsonparser.GetString(result, "StatusText") //结果状态
@@ -438,7 +449,7 @@ func AliyunAudioRecognition(engine aliyun.AliyunClound , filelink string) (Audio
//阿里云识别字幕块翻译处理
-func AliyunAudioResultTranslate(app *VideoSrt , video string , AudioResult map[int64][] *aliyun.AliyunAudioRecognitionResult , IntelligentBlockResult map[int64][] *aliyun.AliyunAudioRecognitionResult) {
+func AliyunAudioResultTranslate(app *VideoSrt , video string , AudioResult map[int64][] *aliyun.AliyunAudioRecognitionResult , IntelligentBlockResult map[int64][] *aliyun.AliyunAudioRecognitionResult) error {
//输出日志
if app.TranslateCfg.TranslateSwitch {
app.Log("字幕翻译处理中 ..." , video)
@@ -448,7 +459,7 @@ func AliyunAudioResultTranslate(app *VideoSrt , video string , AudioResult map[i
app.Log("你使用的是 “百度翻译标准版” 账号,翻译速度较慢,请耐心等待 ..." , video)
}
} else {
- return
+ return nil
}
if app.OutputType.SRT || app.OutputType.LRC {
@@ -456,7 +467,8 @@ func AliyunAudioResultTranslate(app *VideoSrt , video string , AudioResult map[i
for _ , data := range result {
transResult,e := app.RunTranslate(data.Text , video)
if e != nil {
- panic(e) //终止翻译
+ return e
+ //panic(e) //终止翻译
}
data.TranslateText = strings.TrimSpace(transResult.TransResultDst) //译文
}
@@ -468,14 +480,88 @@ func AliyunAudioResultTranslate(app *VideoSrt , video string , AudioResult map[i
for _ , data := range result {
transResult,e := app.RunTranslate(data.Text , video)
if e != nil {
- panic(e) //终止翻译
+ return e
+ //panic(e) //终止翻译
}
data.TranslateText = strings.TrimSpace(transResult.TransResultDst) //译文
}
}
}
+
+ return nil
}
+//阿里云识别字幕过滤
+func AliyunResultFilter(app *VideoSrt , video string , AudioResult map[int64][] *aliyun.AliyunAudioRecognitionResult , IntelligentBlockResult map[int64][] *aliyun.AliyunAudioRecognitionResult) {
+ if !app.FilterSetings.DefinedFilter.Switch && !app.FilterSetings.GlobalFilter.Switch {
+ return
+ }
+
+ app.Log("字幕过滤处理中 ..." , video)
+
+ //语气词过滤
+ if app.FilterSetings.GlobalFilter.Switch && strings.TrimSpace(app.FilterSetings.GlobalFilter.Words) != "" {
+ modalWords := strings.Split(app.FilterSetings.GlobalFilter.Words , "\r\n")
+
+ for _,result := range IntelligentBlockResult {
+ for _ , data := range result {
+ for _ , w := range modalWords {
+
+ data.Text = ModalWordsFilter(data.Text , w)
+ if app.TranslateCfg.TranslateSwitch {
+ data.TranslateText = ModalWordsFilter(data.TranslateText , w)
+ }
+
+ }
+ }
+ }
+ for _,result := range AudioResult {
+ for _ , data := range result {
+ for _ , w := range modalWords {
+
+ data.Text = ModalWordsFilter(data.Text , w)
+ if app.TranslateCfg.TranslateSwitch {
+ data.TranslateText = ModalWordsFilter(data.TranslateText , w)
+ }
+
+ }
+ }
+ }
+ }
+
+ //自定义规则过滤
+ if app.FilterSetings.DefinedFilter.Switch && len(app.FilterSetings.DefinedFilter.Rule) > 0 {
+ rules := app.FilterSetings.DefinedFilter.Rule
+
+ for _,result := range IntelligentBlockResult {
+ for _ , data := range result {
+ for _ , rule := range rules {
+
+ data.Text = DefinedWordRuleFilter(data.Text , rule)
+ if app.TranslateCfg.TranslateSwitch {
+ data.TranslateText = DefinedWordRuleFilter(data.TranslateText , rule)
+ }
+
+ }
+ }
+ }
+ for _,result := range AudioResult {
+ for _ , data := range result {
+ for _ , rule := range rules {
+
+ data.Text = DefinedWordRuleFilter(data.Text , rule)
+ if app.TranslateCfg.TranslateSwitch {
+ data.TranslateText = DefinedWordRuleFilter(data.TranslateText , rule)
+ }
+
+ }
+ }
+ }
+ }
+}
+
+
+
//阿里云录音识别结果集生成字幕文件
func AliyunAudioResultMakeSubtitleFile(app *VideoSrt , video string , outputType int , AudioResult map[int64][] *aliyun.AliyunAudioRecognitionResult , IntelligentBlockResult map[int64][] *aliyun.AliyunAudioRecognitionResult) {
var subfileDir string
@@ -552,6 +638,10 @@ func AliyunAudioResultMakeSubtitleFile(app *VideoSrt , video string , outputType
for _ , data := range result {
var linestr string
+ if data.Text == "" {
+ continue //跳过空行
+ }
+
//字幕、歌词文件处理
if outputType == OUTPUT_SRT || outputType == OUTPUT_LRC {
//拼接
diff --git a/data/img/muyan.png b/data/img/muyan.png
new file mode 100644
index 0000000..0837d28
Binary files /dev/null and b/data/img/muyan.png differ
diff --git a/go.mod b/go.mod
index 14a44ce..6fab679 100644
--- a/go.mod
+++ b/go.mod
@@ -3,19 +3,23 @@ module videosrt
go 1.12
require (
- github.com/CodyGuo/win v0.0.0-20170113125346-08e6b7208274
github.com/PuerkitoBio/goquery v1.5.0
- github.com/TencentCloud/tencentcloud-sdk-go v3.0.128+incompatible
github.com/aliyun/alibaba-cloud-sdk-go v1.60.268
github.com/aliyun/aliyun-oss-go-sdk v2.0.4+incompatible
- github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394
+ 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/lxn/walk v0.0.0-20191121152919-b7c43041fb1b
- github.com/lxn/win v0.0.0-20191106123917-121afc750dd3
- github.com/russross/blackfriday v2.0.0+incompatible
- github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
+ 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
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
+ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
)
diff --git a/main.go b/main.go
index bdf3724..12d5dbc 100644
--- a/main.go
+++ b/main.go
@@ -13,7 +13,7 @@ import (
)
//应用版本号
-const APP_VERSION = "0.2.9.5"
+const APP_VERSION = "0.3.0"
var AppRootDir string
var mw *MyMainWindow
@@ -22,6 +22,9 @@ var (
outputSrtChecked *walk.CheckBox
outputLrcChecked *walk.CheckBox
outputTxtChecked *walk.CheckBox
+
+ globalFilterChecked *walk.CheckBox
+ definedFilterChecked *walk.CheckBox
)
@@ -53,6 +56,8 @@ func main() {
var operateTranslateEngineDb *walk.DataBinder
var operateTranslateDb *walk.DataBinder
var operateDb *walk.DataBinder
+ var operateFilter *walk.DataBinder
+
var operateFrom = new(OperateFrom)
var startBtn *walk.PushButton //生成字幕Btn
@@ -62,6 +67,7 @@ func main() {
var dropFilesEdit *walk.TextEdit
var appSetings = Setings.GetCacheAppSetingsData()
+ var appFilter = Filter.GetCacheAppFilterData()
//初始化展示配置
operateFrom.Init(appSetings)
@@ -272,7 +278,7 @@ func main() {
OnTriggered: mw.OpenAboutGitee,
},
Action{
- Text: "帮助文本",
+ Text: "帮助文档",
Image: "./data/img/version.png",
OnTriggered: func() {
_ = tool.OpenUrl("https://www.yuque.com/viggo-t7cdi/videosrt")
@@ -286,12 +292,22 @@ func main() {
},
Action{
Text: "QQ交流群",
+ Checked:false,
+ Visible:false,
+ Checkable:false,
OnTriggered: func() {
_ = tool.OpenUrl("https://gitee.com/641453620/video-srt-windows#%E4%BA%A4%E6%B5%81%E8%81%94%E7%B3%BB")
},
},
},
},
+ Menu{
+ Text: "语音合成配音/文章转视频",
+ Image: "./data/img/muyan.png",
+ OnTriggered: func() {
+ _ = tool.OpenUrl("http://www.mu-yan.net/")
+ },
+ },
},
},
Size: Size{800, 600},
@@ -527,6 +543,69 @@ func main() {
},
},
+
+ /*过滤器设置*/
+ HSplitter{
+ Children:[]Widget{
+ Composite{
+ DataBinder: DataBinder{
+ AssignTo: &operateFilter,
+ DataSource: appFilter,
+ },
+ Layout: Grid{Columns: 5},
+ Children: []Widget{
+ Label{
+ Text: "过滤设置:",
+ },
+ CheckBox{
+ AssignTo:&globalFilterChecked,
+ Text:"语气词过滤 ",
+ Checked: Bind("GlobalFilter.Switch"),
+ OnClicked: func() {
+ _ = operateFilter.Submit()
+ //更新缓存
+ Filter.SetCacheAppFilterData(appFilter)
+ },
+ },
+ CheckBox{
+ AssignTo:&definedFilterChecked,
+ Text:"自定义过滤 ",
+ Checked: Bind("DefinedFilter.Switch"),
+ OnClicked: func() {
+ _ = operateFilter.Submit()
+ //更新缓存
+ Filter.SetCacheAppFilterData(appFilter)
+ },
+ },
+
+ PushButton{
+ Text: "语气词过滤设置",
+ MaxSize:Size{95 , 55},
+ OnClicked: func() {
+ mw.RunGlobalFilterSetingDialog(mw , appFilter.GlobalFilter.Words , func(words string) {
+ appFilter.GlobalFilter.Words = words
+ //更新缓存
+ Filter.SetCacheAppFilterData(appFilter)
+ })
+ },
+ },
+ PushButton{
+ Text: "自定义过滤设置",
+ MaxSize:Size{95 , 55},
+ OnClicked: func() {
+ mw.RunDefinedFilterSetingDialog(mw , appFilter.DefinedFilter.Rule , func(rule []*AppDefinedFilterRule) {
+ appFilter.DefinedFilter.Rule = rule
+ //更新缓存
+ Filter.SetCacheAppFilterData(appFilter)
+ })
+ },
+ },
+ },
+ },
+ },
+ },
+
+
/*输出设置*/
HSplitter{
Children:[]Widget{
@@ -674,8 +753,11 @@ func main() {
return
}
//校验输入语言
- if tempAppSetting.InputLanguage == LANGUAGE_KOR {
- mw.NewErrormationTips("错误" , "由于语音提供商的限制,生成字幕允许的输入语言目前不支持韩语")
+ if tempAppSetting.InputLanguage != LANGUAGE_ZH &&
+ tempAppSetting.InputLanguage != LANGUAGE_EN &&
+ tempAppSetting.InputLanguage != LANGUAGE_JP &&
+ tempAppSetting.InputLanguage != LANGUAGE_SPA {
+ mw.NewErrormationTips("错误" , "由于语音提供商的限制,生成字幕仅支持中文、英文、日语、西班牙语")
return
}
@@ -721,6 +803,7 @@ func main() {
//加载配置
videosrt.InitAppConfig(ossData , currentEngine)
videosrt.InitTranslateConfig(tempTranslateCfg)
+ videosrt.InitFilterConfig(appFilter)
videosrt.SetSrtDir(appSetings.SrtFileDir)
videosrt.SetSoundTrack(appSetings.SoundTrack)
videosrt.SetMaxConcurrency(appSetings.MaxConcurrency)
@@ -806,7 +889,7 @@ func main() {
PushButton{
AssignTo: &startTranslateBtn,
- Text: "字幕翻译",
+ Text: "字幕处理",
MinSize:Size{Height:50},
OnClicked: func() {
//待处理的文件
@@ -863,6 +946,7 @@ func main() {
//加载配置
srtTranslateApp.InitTranslateConfig(tempTranslateCfg)
+ srtTranslateApp.InitFilterConfig(appFilter)
srtTranslateApp.SetSrtDir(appSetings.SrtFileDir)
srtTranslateApp.SetMaxConcurrency(appSetings.MaxConcurrency)