From 9a1a0b0d0f1c7ff150066be13d0f50c849ea682b Mon Sep 17 00:00:00 2001 From: niksedk Date: Sat, 1 Jan 2022 16:22:50 +0100 Subject: [PATCH] Work on installer --- build.bat | 1 + build_beta.bat | 1 + installer/Subtitle_Edit_installer.iss | 2 + src/ui/Forms/AudioToText.Designer.cs | 208 +++++++++++++++++ src/ui/Forms/AudioToText.cs | 315 ++++++++++++++++++++++++++ src/ui/Forms/Main.cs | 63 ++++++ 6 files changed, 590 insertions(+) create mode 100644 src/ui/Forms/AudioToText.Designer.cs create mode 100644 src/ui/Forms/AudioToText.cs diff --git a/build.bat b/build.bat index 48ad47d4e..cbc9bb8ec 100644 --- a/build.bat +++ b/build.bat @@ -185,6 +185,7 @@ COPY /Y /V "libse.dll" "temp_zip\" COPY /Y /V "zlib.net.dll" "temp_zip\" COPY /Y /V "NHunspell.dll" "temp_zip\" COPY /Y /V "UtfUnknown.dll" "temp_zip\" +COPY /Y /V "Vosk.dll" "temp_zip\" COPY /Y /V "..\..\DLLs\Interop.QuartzTypeLib.dll" "temp_zip\" COPY /Y /V "System.Net.Http.Extensions.dll" "temp_zip\" COPY /Y /V "Newtonsoft.Json.dll" "temp_zip\" diff --git a/build_beta.bat b/build_beta.bat index 9fa1baff5..17292d388 100644 --- a/build_beta.bat +++ b/build_beta.bat @@ -173,6 +173,7 @@ COPY /Y /V "libse.dll" "temp_zip\" COPY /Y /V "zlib.net.dll" "temp_zip\" COPY /Y /V "NHunspell.dll" "temp_zip\" COPY /Y /V "UtfUnknown.dll" "temp_zip\" +COPY /Y /V "Vosk.dll" "temp_zip\" COPY /Y /V "..\..\DLLs\Interop.QuartzTypeLib.dll" "temp_zip\" COPY /Y /V "System.Net.Http.Extensions.dll" "temp_zip\" COPY /Y /V "Newtonsoft.Json.dll" "temp_zip\" diff --git a/installer/Subtitle_Edit_installer.iss b/installer/Subtitle_Edit_installer.iss index 562e06723..426862d06 100644 --- a/installer/Subtitle_Edit_installer.iss +++ b/installer/Subtitle_Edit_installer.iss @@ -304,6 +304,7 @@ Source: {#bindir}\libse.dll; DestDir: {app}; Source: {#bindir}\zlib.net.dll; DestDir: {app}; Flags: ignoreversion; Components: main Source: {#bindir}\NHunspell.dll; DestDir: {app}; Flags: ignoreversion; Components: main Source: {#bindir}\UtfUnknown.dll; DestDir: {app}; Flags: ignoreversion; Components: main +Source: {#bindir}\Vosk.dll; DestDir: {app}; Flags: ignoreversion; Components: main Source: ..\src\ui\DLLs\Interop.QuartzTypeLib.dll; DestDir: {app}; Flags: ignoreversion; Components: main Source: {#bindir}\Newtonsoft.Json.dll; DestDir: {app}; Flags: ignoreversion; Components: main Source: {#bindir}\System.Net.Http.Extensions.dll; DestDir: {app}; Flags: ignoreversion; Components: main @@ -341,6 +342,7 @@ Type: files; Name: {app}\libse.dll; Check: IsU Type: files; Name: {app}\zlib.net.dll; Check: IsUpgrade() Type: files; Name: {app}\NHunspell.dll; Check: IsUpgrade() Type: files; Name: {app}\UtfUnknown.dll; Check: IsUpgrade() +Type: files; Name: {app}\Vosk.dll; Check: IsUpgrade() Type: files; Name: {app}\Interop.QuartzTypeLib.dll; Check: IsUpgrade() Type: files; Name: {app}\Newtonsoft.Json.dll; Check: IsUpgrade() Type: files; Name: {app}\System.Net.Http.Extensions.dll; Check: IsUpgrade() diff --git a/src/ui/Forms/AudioToText.Designer.cs b/src/ui/Forms/AudioToText.Designer.cs new file mode 100644 index 000000000..1b1c3b0ac --- /dev/null +++ b/src/ui/Forms/AudioToText.Designer.cs @@ -0,0 +1,208 @@ +namespace Nikse.SubtitleEdit.Forms +{ + partial class AudioToText + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonGenerate = new System.Windows.Forms.Button(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.labelProgress = new System.Windows.Forms.Label(); + this.textBoxLog = new System.Windows.Forms.TextBox(); + this.labelInfo = new System.Windows.Forms.Label(); + this.groupBoxModels = new System.Windows.Forms.GroupBox(); + this.labelModel = new System.Windows.Forms.Label(); + this.comboBoxModels = new System.Windows.Forms.ComboBox(); + this.linkLabelVoskWebSite = new System.Windows.Forms.LinkLabel(); + this.linkLabelOpenModelFolder = new System.Windows.Forms.LinkLabel(); + this.groupBoxModels.SuspendLayout(); + this.SuspendLayout(); + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.ImeMode = System.Windows.Forms.ImeMode.NoControl; + this.buttonCancel.Location = new System.Drawing.Point(529, 176); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 112; + this.buttonCancel.Text = "C&ancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonGenerate + // + this.buttonGenerate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonGenerate.ImeMode = System.Windows.Forms.ImeMode.NoControl; + this.buttonGenerate.Location = new System.Drawing.Point(398, 176); + this.buttonGenerate.Name = "buttonGenerate"; + this.buttonGenerate.Size = new System.Drawing.Size(125, 23); + this.buttonGenerate.TabIndex = 111; + this.buttonGenerate.Text = "&Generate"; + this.buttonGenerate.UseVisualStyleBackColor = true; + this.buttonGenerate.Click += new System.EventHandler(this.ButtonGenerate_Click); + // + // progressBar1 + // + this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progressBar1.Location = new System.Drawing.Point(12, 186); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(380, 13); + this.progressBar1.TabIndex = 114; + this.progressBar1.Visible = false; + // + // labelProgress + // + this.labelProgress.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.labelProgress.AutoSize = true; + this.labelProgress.Location = new System.Drawing.Point(12, 170); + this.labelProgress.Name = "labelProgress"; + this.labelProgress.Size = new System.Drawing.Size(70, 13); + this.labelProgress.TabIndex = 115; + this.labelProgress.Text = "labelProgress"; + // + // textBoxLog + // + this.textBoxLog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBoxLog.Location = new System.Drawing.Point(15, 9); + this.textBoxLog.Multiline = true; + this.textBoxLog.Name = "textBoxLog"; + this.textBoxLog.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.textBoxLog.Size = new System.Drawing.Size(589, 158); + this.textBoxLog.TabIndex = 116; + // + // labelInfo + // + this.labelInfo.AutoSize = true; + this.labelInfo.Location = new System.Drawing.Point(12, 9); + this.labelInfo.Name = "labelInfo"; + this.labelInfo.Size = new System.Drawing.Size(288, 13); + this.labelInfo.TabIndex = 118; + this.labelInfo.Text = "Generate text from audio via Vosk/Kaldi speech recognition"; + // + // groupBoxModels + // + this.groupBoxModels.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBoxModels.Controls.Add(this.linkLabelOpenModelFolder); + this.groupBoxModels.Controls.Add(this.labelModel); + this.groupBoxModels.Controls.Add(this.comboBoxModels); + this.groupBoxModels.Location = new System.Drawing.Point(15, 66); + this.groupBoxModels.Name = "groupBoxModels"; + this.groupBoxModels.Size = new System.Drawing.Size(589, 84); + this.groupBoxModels.TabIndex = 120; + this.groupBoxModels.TabStop = false; + this.groupBoxModels.Text = "Models"; + // + // labelModel + // + this.labelModel.AutoSize = true; + this.labelModel.Location = new System.Drawing.Point(16, 29); + this.labelModel.Name = "labelModel"; + this.labelModel.Size = new System.Drawing.Size(167, 13); + this.labelModel.TabIndex = 121; + this.labelModel.Text = "Choose speech recognition model"; + // + // comboBoxModels + // + this.comboBoxModels.FormattingEnabled = true; + this.comboBoxModels.Location = new System.Drawing.Point(19, 45); + this.comboBoxModels.Name = "comboBoxModels"; + this.comboBoxModels.Size = new System.Drawing.Size(240, 21); + this.comboBoxModels.TabIndex = 120; + // + // linkLabelVoskWebSite + // + this.linkLabelVoskWebSite.AutoSize = true; + this.linkLabelVoskWebSite.Location = new System.Drawing.Point(12, 22); + this.linkLabelVoskWebSite.Name = "linkLabelVoskWebSite"; + this.linkLabelVoskWebSite.Size = new System.Drawing.Size(70, 13); + this.linkLabelVoskWebSite.TabIndex = 121; + this.linkLabelVoskWebSite.TabStop = true; + this.linkLabelVoskWebSite.Text = "Vosk website"; + this.linkLabelVoskWebSite.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelVoskWebsite_LinkClicked); + // + // linkLabelOpenModelFolder + // + this.linkLabelOpenModelFolder.AutoSize = true; + this.linkLabelOpenModelFolder.Location = new System.Drawing.Point(265, 50); + this.linkLabelOpenModelFolder.Name = "linkLabelOpenModelFolder"; + this.linkLabelOpenModelFolder.Size = new System.Drawing.Size(93, 13); + this.linkLabelOpenModelFolder.TabIndex = 122; + this.linkLabelOpenModelFolder.TabStop = true; + this.linkLabelOpenModelFolder.Text = "Open model folder"; + this.linkLabelOpenModelFolder.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabelOpenModelFolder_LinkClicked); + // + // AudioToText + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(616, 211); + this.Controls.Add(this.linkLabelVoskWebSite); + this.Controls.Add(this.groupBoxModels); + this.Controls.Add(this.labelInfo); + this.Controls.Add(this.textBoxLog); + this.Controls.Add(this.labelProgress); + this.Controls.Add(this.progressBar1); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonGenerate); + this.KeyPreview = true; + this.MinimumSize = new System.Drawing.Size(575, 250); + this.Name = "AudioToText"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Video/audio to text"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.AudioToText_FormClosing); + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.AudioToText_KeyDown); + this.groupBoxModels.ResumeLayout(false); + this.groupBoxModels.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonGenerate; + private System.Windows.Forms.ProgressBar progressBar1; + private System.Windows.Forms.Label labelProgress; + private System.Windows.Forms.TextBox textBoxLog; + private System.Windows.Forms.Label labelInfo; + private System.Windows.Forms.GroupBox groupBoxModels; + private System.Windows.Forms.LinkLabel linkLabelVoskWebSite; + private System.Windows.Forms.Label labelModel; + private System.Windows.Forms.ComboBox comboBoxModels; + private System.Windows.Forms.LinkLabel linkLabelOpenModelFolder; + } +} \ No newline at end of file diff --git a/src/ui/Forms/AudioToText.cs b/src/ui/Forms/AudioToText.cs new file mode 100644 index 000000000..e5295b34e --- /dev/null +++ b/src/ui/Forms/AudioToText.cs @@ -0,0 +1,315 @@ +using Nikse.SubtitleEdit.Core.AudioToText; +using Nikse.SubtitleEdit.Core.Common; +using Nikse.SubtitleEdit.Logic; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Globalization; +using System.IO; +using System.Windows.Forms; +using Vosk; + +namespace Nikse.SubtitleEdit.Forms +{ + public partial class AudioToText : Form + { + private readonly string _videoFileName; + private readonly string _voskFolder; + private bool _cancel; + public Subtitle TranscribedSubtitle { get; private set; } + + public AudioToText(string videoFileName) + { + UiUtil.PreInitialize(this); + InitializeComponent(); + UiUtil.FixFonts(this); + UiUtil.FixLargeFonts(this, buttonGenerate); + _videoFileName = videoFileName; + + _voskFolder = Path.Combine(Configuration.DataDirectory, "Vosk"); + if (!Directory.Exists(_voskFolder)) + { + Directory.CreateDirectory(_voskFolder); + } + + comboBoxModels.Items.Clear(); + foreach (var directory in Directory.GetDirectories(_voskFolder)) + { + var name = Path.GetFileName(directory); + if (!Directory.Exists(Path.Combine(directory, "conf"))) + { + continue; + } + + comboBoxModels.Items.Add(name); + if (name == Configuration.Settings.Tools.VoskModel) + { + comboBoxModels.SelectedIndex = comboBoxModels.Items.Count - 1; + } + } + + if (comboBoxModels.SelectedIndex < 0 && comboBoxModels.Items.Count > 0) + { + comboBoxModels.SelectedIndex = 0; + } + + textBoxLog.Visible = false; + labelProgress.Text = string.Empty; + } + + private void ButtonGenerate_Click(object sender, EventArgs e) + { + if (comboBoxModels.Items.Count == 0) + { + MessageBox.Show(string.Format("Please download an audio-to-text model from the Vosk website and unpack to {0}", _voskFolder)); + return; + } + + progressBar1.Maximum = 100; + progressBar1.Value = 0; + progressBar1.Visible = true; + var modelFileName = Path.Combine(_voskFolder, comboBoxModels.Text); + buttonGenerate.Enabled = false; + var waveFileName = GenerateWavFile(_videoFileName, 0); + textBoxLog.AppendText("Wav file name: " + waveFileName); + textBoxLog.AppendText(Environment.NewLine); + progressBar1.Style = ProgressBarStyle.Blocks; + var transcript = TranscribeViaVosk(waveFileName, modelFileName); + if (_cancel) + { + DialogResult = DialogResult.Cancel; + return; + } + + var subtitleGenerator = new Core.AudioToText.Vosk.SubtitleGenerator(transcript); + TranscribedSubtitle = subtitleGenerator.Generate("en"); + DialogResult = DialogResult.OK; + } + + public List TranscribeViaVosk(string waveFileName, string modelFileName) + { + labelProgress.Text = "Loading Vosk speach model..."; + labelProgress.Refresh(); + Application.DoEvents(); + Vosk.Vosk.SetLogLevel(0); + var model = new Model(modelFileName); + var rec = new VoskRecognizer(model, 16000.0f); + rec.SetMaxAlternatives(0); + rec.SetWords(true); + var list = new List(); + labelProgress.Text = "Transcribing audio to text..."; + labelProgress.Refresh(); + Application.DoEvents(); + var totalRead = 0; + var buffer = new byte[4096]; + var totalLength = new FileInfo(waveFileName).Length; + using (var source = File.OpenRead(waveFileName)) + { + int bytesRead; + while ((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) + { + totalRead += bytesRead; + progressBar1.Value = (int)(totalRead * 100.0 / totalLength); + progressBar1.Refresh(); + Application.DoEvents(); + + if (rec.AcceptWaveform(buffer, bytesRead)) + { + var res = rec.Result(); + var results = ParseJsonToResult(res); + list.AddRange(results); + + } + else + { + var res = rec.PartialResult(); + textBoxLog.AppendText(res.RemoveChar('\r', '\n')); + } + } + + if (_cancel) + { + return null; + } + } + + var finalResult = rec.FinalResult(); + var finalResults = ParseJsonToResult(finalResult); + list.AddRange(finalResults); + return list; + } + + private static List ParseJsonToResult(string result) + { + var list = new List(); + var jsonParser = new SeJsonParser(); + var root = jsonParser.GetArrayElementsByName(result, "result"); + foreach (var item in root) + { + var conf = jsonParser.GetFirstObject(item, "conf"); + var start = jsonParser.GetFirstObject(item, "start"); + var end = jsonParser.GetFirstObject(item, "end"); + var word = jsonParser.GetFirstObject(item, "word"); + if (!string.IsNullOrWhiteSpace(word) && + decimal.TryParse(conf, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var confidence) && + decimal.TryParse(start, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var startSeconds) && + decimal.TryParse(end, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var endSeconds)) + { + var rt = new ResultText { Confidence = confidence, Text = word, Start = startSeconds, End = endSeconds }; + list.Add(rt); + } + } + + return list; + } + + private string GenerateWavFile(string videoFileName, int audioTrackNumber) + { + var outWaveFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".wav"); + var process = GetFfmpegProcess(videoFileName, audioTrackNumber, outWaveFile); + + process.Start(); + progressBar1.Style = ProgressBarStyle.Marquee; + progressBar1.Visible = true; + double seconds = 0; + buttonCancel.Visible = true; + try + { + process.PriorityClass = ProcessPriorityClass.Normal; + } + catch + { + // ignored + } + + _cancel = false; + string targetDriveLetter = null; + if (Configuration.IsRunningOnWindows) + { + var root = Path.GetPathRoot(outWaveFile); + if (root.Length > 1 && root[1] == ':') + { + targetDriveLetter = root.Remove(1); + } + } + + while (!process.HasExited) + { + Application.DoEvents(); + System.Threading.Thread.Sleep(100); + seconds += 0.1; + if (seconds < 60) + { + labelProgress.Text = string.Format(LanguageSettings.Current.AddWaveform.ExtractingSeconds, seconds); + } + else + { + labelProgress.Text = string.Format(LanguageSettings.Current.AddWaveform.ExtractingMinutes, (int)(seconds / 60), (int)(seconds % 60)); + } + + Refresh(); + if (_cancel) + { + process.Kill(); + progressBar1.Visible = false; + buttonCancel.Visible = false; + DialogResult = DialogResult.Cancel; + return null; + } + + if (targetDriveLetter != null && seconds > 1 && Convert.ToInt32(seconds) % 10 == 0) + { + try + { + var drive = new DriveInfo(targetDriveLetter); + if (drive.IsReady) + { + if (drive.AvailableFreeSpace < 50 * 1000000) // 50 mb + { + labelInfo.ForeColor = Color.Red; + labelInfo.Text = LanguageSettings.Current.AddWaveform.LowDiskSpace; + } + } + } + catch + { + // ignored + } + } + } + + return outWaveFile; + } + + private static Process GetFfmpegProcess(string videoFileName, int audioTrackNumber, string outWaveFile) + { + if (!File.Exists(Configuration.Settings.General.FFmpegLocation) && Configuration.IsRunningOnWindows) + { + return null; + } + + string audioParameter = string.Empty; + if (audioTrackNumber > 0) + { + audioParameter = $"-map 0:a:{audioTrackNumber}"; + } + + const string fFmpegWaveTranscodeSettings = "-i \"{0}\" -vn -ar 16000 -ac 1 -ab 128 -vol 448 -f wav {2} \"{1}\""; + //-i indicates the input + //-vn means no video ouput + //-ar 44100 indicates the sampling frequency. + //-ab indicates the bit rate (in this example 160kb/s) + //-vol 448 will boot volume... 256 is normal + //-ac 2 means 2 channels + // "-map 0:a:0" is the first audio stream, "-map 0:a:1" is the second audio stream + + var exeFilePath = Configuration.Settings.General.FFmpegLocation; + if (!Configuration.IsRunningOnWindows) + { + exeFilePath = "ffmpeg"; + } + + var parameters = string.Format(fFmpegWaveTranscodeSettings, videoFileName, outWaveFile, audioParameter); + return new Process { StartInfo = new ProcessStartInfo(exeFilePath, parameters) { WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true } }; + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + } + + private void linkLabelVoskWebsite_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + UiUtil.OpenUrl("https://alphacephei.com/vosk/models"); + } + + private void AudioToText_FormClosing(object sender, FormClosingEventArgs e) + { + Configuration.Settings.Tools.VoskModel = comboBoxModels.Text; + } + + private void AudioToText_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.F2) + { + if (textBoxLog.Visible) + { + textBoxLog.Visible = true; + textBoxLog.BringToFront(); + } + else + { + textBoxLog.Visible = false; + } + + e.SuppressKeyPress = true; + } + } + + private void linkLabelOpenModelFolder_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + UiUtil.OpenFolder(_voskFolder); + } + } +} diff --git a/src/ui/Forms/Main.cs b/src/ui/Forms/Main.cs index 2cf2d37e2..58bfaff36 100644 --- a/src/ui/Forms/Main.cs +++ b/src/ui/Forms/Main.cs @@ -32867,5 +32867,68 @@ namespace Nikse.SubtitleEdit.Forms } } } + + private void videoaudioToTextToolStripMenuItem_Click(object sender, EventArgs e) + { + if (string.IsNullOrEmpty(VideoFileName)) + { + MessageBox.Show(LanguageSettings.Current.General.NoVideoLoaded); + return; + } + + if (!ContinueNewOrExit()) + { + return; + } + + var ffmpegFullPath = Path.Combine(Configuration.DataDirectory, "ffmpeg", "ffmpeg.exe"); + if (Configuration.IsRunningOnWindows && string.IsNullOrWhiteSpace(Configuration.Settings.General.FFmpegLocation) && File.Exists(ffmpegFullPath)) + { + Configuration.Settings.General.FFmpegLocation = ffmpegFullPath; + } + + if (Configuration.IsRunningOnWindows && (string.IsNullOrWhiteSpace(Configuration.Settings.General.FFmpegLocation) || !File.Exists(Configuration.Settings.General.FFmpegLocation))) + { + if (MessageBox.Show(LanguageSettings.Current.Settings.DownloadFFmpeg, "Subtitle Edit", MessageBoxButtons.YesNoCancel) != DialogResult.Yes) + { + return; + } + + using (var form = new DownloadFfmpeg()) + { + if (form.ShowDialog(this) == DialogResult.OK && !string.IsNullOrEmpty(form.FFmpegPath)) + { + Configuration.Settings.General.FFmpegLocation = form.FFmpegPath; + Configuration.Settings.General.UseFFmpegForWaveExtraction = true; + } + else + { + return; + } + } + } + + using (var form = new AudioToText(VideoFileName)) + { + var result = form.ShowDialog(this); + if (result != DialogResult.OK) + { + return; + } + + if (form.TranscribedSubtitle.Paragraphs.Count == 0) + { + MessageBox.Show("No text found!"); + return; + } + + _subtitle.Paragraphs.Clear(); + _subtitle.Paragraphs.AddRange(form.TranscribedSubtitle.Paragraphs); + var idx = FirstSelectedIndex; + SubtitleListview1.Fill(_subtitle, _subtitleOriginal); + _subtitleListViewIndex = -1; + SubtitleListview1.SelectIndexAndEnsureVisibleFaster(idx); + } + } } } \ No newline at end of file