Skip to content

Commit 8c46ea1

Browse files
committed
add clear formating. add replacing subtitle track instead of injecting to new track. add font size setting for higher and lower subtitles.
1 parent 4e2f76f commit 8c46ea1

8 files changed

Lines changed: 697 additions & 208 deletions

File tree

MP4SubtitleMerger/App.config

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,31 @@
2929
<value>False</value>
3030
</setting>
3131
<setting name="OutputFolder" serializeAs="String">
32-
<value></value>
32+
<value />
33+
</setting>
34+
<setting name="ClearFormating" serializeAs="String">
35+
<value>False</value>
36+
</setting>
37+
<setting name="RestoreBoundsTopLeft" serializeAs="String">
38+
<value>0, 0</value>
39+
</setting>
40+
<setting name="RestoreBoundsSize" serializeAs="String">
41+
<value>0, 0</value>
42+
</setting>
43+
<setting name="Maximized" serializeAs="String">
44+
<value>False</value>
45+
</setting>
46+
<setting name="ReplaceLastTopLanguageTrackExceptFirst" serializeAs="String">
47+
<value>False</value>
48+
</setting>
49+
<setting name="TopRowFontSize" serializeAs="String">
50+
<value />
51+
</setting>
52+
<setting name="BottomRowFontSize" serializeAs="String">
53+
<value />
54+
</setting>
55+
<setting name="ReplaceTrackLanguage" serializeAs="String">
56+
<value />
3357
</setting>
3458
</MP4SubtitleMerger.Properties.Settings>
3559
</userSettings>

MP4SubtitleMerger/BackgroundWorkerArguments.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
namespace MP4SubtitleMerger;
22
public class BackgroundWorkerArguments {
3-
public BackgroundWorkerArguments(string fFMPEGPath, string videoPath, string topRowLanguage, string bottomRowLanguage, string outputFolder, BackgroundWorkerWorkMode workMode
4-
,bool setAsDefault)
3+
public BackgroundWorkerArguments(string fFMPEGPath, string videoPath, string topRowLanguage,
4+
string bottomRowLanguage, string outputFolder, BackgroundWorkerWorkMode workMode
5+
,bool setAsDefault,bool clearFormating,bool replaceLastTopRowLanguageTrackIfNotFirst
6+
, string topRowFontSize
7+
, string bottomRowFontSize,
8+
string replaceTrackLanguage)
59
{
610
FFMPEGPath = fFMPEGPath;
711
VideoPath = videoPath;
@@ -10,6 +14,11 @@ public BackgroundWorkerArguments(string fFMPEGPath, string videoPath, string top
1014
OutputFolder = outputFolder;
1115
WorkMode = workMode;
1216
SetAsDefault = setAsDefault;
17+
ClearFormating = clearFormating;
18+
ReplaceLastTopRowLanguageTrackIfNotFirst = replaceLastTopRowLanguageTrackIfNotFirst;
19+
TopRowFontSize = topRowFontSize;
20+
BottomRowFontSize = bottomRowFontSize;
21+
ReplaceTrackLanguage = replaceTrackLanguage;
1322
}
1423

1524
public string FFMPEGPath { get; set; }
@@ -19,6 +28,12 @@ public BackgroundWorkerArguments(string fFMPEGPath, string videoPath, string top
1928
public string OutputFolder { get; set; }
2029
public BackgroundWorkerWorkMode WorkMode { get; set; }
2130
public bool SetAsDefault { get; }
31+
public bool ClearFormating { get; set; }
32+
public bool ReplaceLastTopRowLanguageTrackIfNotFirst { get; set; }
33+
34+
public string TopRowFontSize { get; set; }
35+
public string BottomRowFontSize { get; set; }
36+
public string ReplaceTrackLanguage { get; set; }
2237

2338
}
2439

MP4SubtitleMerger/FormMain.Designer.cs

Lines changed: 244 additions & 120 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

MP4SubtitleMerger/FormMain.cs

Lines changed: 109 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using FFMpegCore;
2+
using FFMpegCore.Arguments;
3+
using System.Diagnostics;
24
using System.Drawing.Drawing2D;
35
using System.IO;
46
using System.IO.Enumeration;
@@ -56,6 +58,28 @@ private void FormMain_Load(object sender, EventArgs e)
5658
radioButtonExtractFiles.Checked = Properties.Settings.Default.CreateSeparateFilesChecked;
5759
radioButtonInjectToVideo.Checked = Properties.Settings.Default.InjectToVideo;
5860
textBoxOutputFolder.Text = Properties.Settings.Default.OutputFolder;
61+
checkBoxClearFormating.Checked = Properties.Settings.Default.ClearFormating;
62+
checkBoxReplaceLastTopRowLanguageTrackIfNotFirst.Checked = Properties.Settings.Default.ReplaceLastTopLanguageTrackExceptFirst;
63+
textBoxTopRowFontSize.Text=Properties.Settings.Default.TopRowFontSize ;
64+
textBoxButtomRowFontSize.Text=Properties.Settings.Default.BottomRowFontSize ;
65+
66+
textBoxReplaceTrackLanguage.Text=Properties.Settings.Default.ReplaceTrackLanguage ;
67+
68+
if (Properties.Settings.Default.RestoreBoundsSize.Width > 0
69+
&& Properties.Settings.Default.RestoreBoundsSize.Height > 0)
70+
{
71+
var restoreBounds = new System.Drawing.Rectangle(
72+
Properties.Settings.Default.RestoreBoundsTopLeft, Properties.Settings.Default.RestoreBoundsSize);
73+
if (Screen.AllScreens.Any(screen => screen.WorkingArea.IntersectsWith(restoreBounds)))
74+
{
75+
StartPosition = FormStartPosition.Manual;
76+
DesktopBounds = restoreBounds;
77+
WindowState = FormWindowState.Normal;
78+
}
79+
}
80+
if (Properties.Settings.Default.Maximized)
81+
WindowState = FormWindowState.Maximized;
82+
5983
}
6084

6185
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
@@ -69,13 +93,24 @@ private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
6993
Properties.Settings.Default.CreateSeparateFilesChecked = radioButtonExtractFiles.Checked;
7094
Properties.Settings.Default.InjectToVideo = radioButtonInjectToVideo.Checked;
7195
Properties.Settings.Default.OutputFolder = textBoxOutputFolder.Text;
96+
97+
Properties.Settings.Default.ClearFormating = checkBoxClearFormating.Checked;
98+
99+
Properties.Settings.Default.Maximized = (WindowState == FormWindowState.Maximized);
100+
101+
Properties.Settings.Default.RestoreBoundsTopLeft = new Point(DesktopBounds.Left, DesktopBounds.Top);
102+
Properties.Settings.Default.RestoreBoundsSize = DesktopBounds.Size;
103+
Properties.Settings.Default.ReplaceLastTopLanguageTrackExceptFirst = checkBoxReplaceLastTopRowLanguageTrackIfNotFirst.Checked;
104+
Properties.Settings.Default.TopRowFontSize = textBoxTopRowFontSize.Text;
105+
Properties.Settings.Default.BottomRowFontSize=textBoxButtomRowFontSize.Text;
106+
Properties.Settings.Default.ReplaceTrackLanguage= textBoxReplaceTrackLanguage.Text;
72107
Properties.Settings.Default.Save();
73108
}
74109

75110
private void toolStripButtonStart_Click(object sender, EventArgs e)
76111
{
77112
if (backgroundWorker1.IsBusy) return;
78-
if (!Directory.Exists(textBoxFFMPEGPath.Text))
113+
if (!Directory.Exists(textBoxFFMPEGPath.Text))
79114
{
80115
MessageBox.Show("Specified video folder does not exist");
81116
return;
@@ -95,7 +130,21 @@ private void toolStripButtonStart_Click(object sender, EventArgs e)
95130
MessageBox.Show("ffmpeg.exe not found in specified folder");
96131
return;
97132
}
98-
133+
int topRowFontSize = 0;
134+
if (!int.TryParse(textBoxTopRowFontSize.Text, out topRowFontSize))
135+
{
136+
if(!int.TryParse(textBoxTopRowFontSize.Text.Replace("px",string.Empty), out topRowFontSize))
137+
MessageBox.Show("Invalid font size, expect something like 14 or 14px");
138+
return;
139+
}
140+
int bottomRowFontSize = 0;
141+
if (!int.TryParse(textBoxButtomRowFontSize.Text, out bottomRowFontSize))
142+
{
143+
if (!int.TryParse(textBoxButtomRowFontSize.Text.Replace("px", string.Empty), out bottomRowFontSize))
144+
MessageBox.Show("Invalid font size, expect something like 14 or 14px");
145+
return;
146+
}
147+
99148
GlobalFFOptions.Configure(new FFOptions { BinaryFolder = textBoxFFMPEGPath.Text, TemporaryFilesFolder = Path.GetTempPath() });
100149

101150
backgroundWorker1.RunWorkerAsync(new BackgroundWorkerArguments(
@@ -107,12 +156,17 @@ private void toolStripButtonStart_Click(object sender, EventArgs e)
107156
radioButtonExtractFiles.Checked ? BackgroundWorkerWorkMode.ExtractSubtitle
108157
: BackgroundWorkerWorkMode.InjectToVideo
109158
, checkBoxSetAsDefault.Checked
159+
, checkBoxClearFormating.Checked
160+
, checkBoxReplaceLastTopRowLanguageTrackIfNotFirst.Checked
161+
, textBoxTopRowFontSize.Text
162+
, textBoxButtomRowFontSize.Text
163+
, textBoxReplaceTrackLanguage.Text
110164
));
111165
}
112166

113167
private void toolStripButtonStop_Click(object sender, EventArgs e)
114168
{
115-
if(backgroundWorker1.IsBusy)
169+
if (backgroundWorker1.IsBusy)
116170
backgroundWorker1.CancelAsync();
117171
}
118172
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
@@ -124,16 +178,16 @@ private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWor
124178
int fileCount = files.Count();
125179
if (fileCount == 0)
126180
throw new FileNotFoundException("No mp4 file under specified folder");
127-
List<Exception> exceptions=new List<Exception>();
181+
List<Exception> exceptions = new List<Exception>();
128182
int filesProcessed = 0;
129-
foreach (var file in files)
183+
foreach (var file in files)
130184
{
131185
if (backgroundWorker1.CancellationPending) break;
132186
backgroundWorker1.ReportProgress(
133187
(filesProcessed) * 100 / fileCount,
134188
string.Format("Processing file {0} of {1} :{2}", filesProcessed + 1, fileCount, file)
135189
);
136-
190+
137191
try
138192
{
139193
ProcessFile(file, arguments);
@@ -143,16 +197,16 @@ private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWor
143197
{
144198
exceptions.Add(ex);
145199
}
146-
200+
147201
filesProcessed++;
148202
}
149203
backgroundWorker1.ReportProgress(
150204
0,
151205
string.Format("Processed file {0} of {1}", filesProcessed, fileCount)
152206
);
153207
if (exceptions.Any())
154-
{
155-
throw new AggregateException(exceptions.ToArray());
208+
{
209+
throw new AggregateException(exceptions.ToArray());
156210
}
157211
}
158212
private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
@@ -181,7 +235,7 @@ static void ProcessFile(string file, BackgroundWorkerArguments arguments)
181235
if (parentFolder != null)
182236
Directory.CreateDirectory(parentFolder);
183237
var tempFolder = Path.GetTempPath();
184-
238+
185239
var mediaInfo = FFProbe.Analyse(file);
186240

187241
if (mediaInfo != null && mediaInfo.SubtitleStreams != null)
@@ -192,19 +246,19 @@ static void ProcessFile(string file, BackgroundWorkerArguments arguments)
192246
}
193247
var topRowSubtitleStream = mediaInfo.SubtitleStreams.Where(
194248
s => s.Language == arguments.TopRowLanguage
195-
&&s.CodecName!= "dvd_subtitle").FirstOrDefault();
249+
&& s.CodecName != "dvd_subtitle").FirstOrDefault();
196250
var buttonRowSubtitleStream = mediaInfo.SubtitleStreams.Where(
197251
s => s.Language == arguments.BottomRowLanguage && s.CodecName != "dvd_subtitle").FirstOrDefault();
198252
SubtitleInfo? higherSubtitle = SubtitleInfo.FFMPEGReadSubtitleFromFile(file, topRowSubtitleStream);
199253
SubtitleInfo? lowerSubtitle = SubtitleInfo.FFMPEGReadSubtitleFromFile(file, buttonRowSubtitleStream);
200-
var mergedSubtitle = SubtitleInfo.Merge(higherSubtitle, lowerSubtitle);
254+
var mergedSubtitle = SubtitleInfo.Merge(higherSubtitle, lowerSubtitle, arguments);
201255
SubtitleInfo? mergedSubtitleInfo;
202256
if (mergedSubtitle != null)
203257
{
204258
mergedSubtitleInfo = new SubtitleInfo(mergedSubtitle);
205259
string? mergedSubtitleText;
206260
if (mergedSubtitleInfo != null)
207-
mergedSubtitleText = mergedSubtitleInfo.ToText();
261+
mergedSubtitleText = mergedSubtitleInfo.ToText(arguments.ClearFormating);
208262
switch (arguments.WorkMode)
209263
{
210264
case BackgroundWorkerWorkMode.ExtractSubtitle:
@@ -235,23 +289,34 @@ static void ProcessFile(string file, BackgroundWorkerArguments arguments)
235289
//check if already injected
236290
if (subtitleInfos.Any(s => subtitleInfoToBeInjected.RawData.SequenceEqual(s.RawData)))
237291
break;
292+
if (arguments.ReplaceLastTopRowLanguageTrackIfNotFirst)
293+
{
294+
if (mediaInfo.SubtitleStreams.Where(s => s.CodecName != "dvd_subtitle"
295+
&&s.Language== arguments.ReplaceTrackLanguage).Count() < 2)
296+
{
297+
throw new FileNotFoundException(
298+
string.Format("The specified file {0} does not have more than one of the required subtitle track in the specified replacement language and in text format.", file));
299+
}
300+
}
238301
SubtitleInfo.FFMPEGInjectToFile(file, arguments,
239-
relativePathToRoot, outputVideoFileName, tempSubtitleTargetFile, arguments.TopRowLanguage, mediaInfo);
302+
relativePathToRoot, outputVideoFileName, tempSubtitleTargetFile, arguments.ReplaceTrackLanguage,
303+
mediaInfo);
240304
break;
241305
default:
242306
break;
243307
}
244308
}
245309
else
246310
throw new FileNotFoundException(
247-
string.Format("The specified file {0} does not have one of the required subtitle track in text format.",file));
311+
string.Format("The specified file {0} does not have one of the required subtitle track in text format.", file));
248312
}
249313
}
250314

251315

252316
static void ExtractSubtitles(string file, BackgroundWorkerArguments arguments,
253-
string relativePathToRoot,string outputVideoFileName,
254-
IMediaAnalysis mediaInfo, SubtitleStream? topRowSubtitleStream, SubtitleStream? buttonRowSubtitleStream, List<MergedSubtitle>? mergedSubtitle,
317+
string relativePathToRoot, string outputVideoFileName,
318+
IMediaAnalysis mediaInfo, SubtitleStream? topRowSubtitleStream,
319+
SubtitleStream? buttonRowSubtitleStream, List<MergedSubtitle>? mergedSubtitle,
255320
SubtitleInfo? mergedSubtitleInfo)
256321
{
257322
foreach (var subtitleStream in mediaInfo.SubtitleStreams)
@@ -263,7 +328,7 @@ static void ExtractSubtitles(string file, BackgroundWorkerArguments arguments,
263328
var subtitleFileName =
264329
string.Format("{0}.{1}.{2}.srt", outputVideoFileName,
265330
subtitleStream.Index, subtitleStream.Language);
266-
File.WriteAllText(subtitleFileName, subtitleInfo.ToText());
331+
File.WriteAllText(subtitleFileName, subtitleInfo.ToText(arguments.ClearFormating));
267332
}
268333
}
269334

@@ -275,10 +340,35 @@ static void ExtractSubtitles(string file, BackgroundWorkerArguments arguments,
275340
topRowSubtitleStream.Language,
276341
buttonRowSubtitleStream.Language);
277342
if (mergedSubtitleInfo != null)
278-
File.WriteAllText(mergeSubtitleFileName, mergedSubtitleInfo.ToText());
343+
File.WriteAllText(mergeSubtitleFileName, mergedSubtitleInfo.ToText(arguments.ClearFormating));
279344
}
280345
}
281346

347+
private void buttonFFMPEGPath_Click(object sender, EventArgs e)
348+
{
349+
BrowseForFolder(this.textBoxFFMPEGPath, this.textBoxFFMPEGPath.Text, "Select FFMPEG Path");
350+
}
351+
void BrowseForFolder(TextBox textBox, string initialFolder, string dialogTitle)
352+
{
353+
using (FolderBrowserDialog fb = new FolderBrowserDialog())
354+
{
355+
fb.Description = dialogTitle;
356+
fb.InitialDirectory = initialFolder;
357+
if (fb.ShowDialog() == DialogResult.OK)
358+
{
359+
textBox.Text = fb.SelectedPath;
360+
}
361+
}
362+
}
282363

364+
private void buttonVideoPath_Click(object sender, EventArgs e)
365+
{
366+
BrowseForFolder(this.textBoxVideoPath, this.textBoxVideoPath.Text, "Select Input Video Path");
367+
}
368+
369+
private void buttonOutputFolder_Click(object sender, EventArgs e)
370+
{
371+
BrowseForFolder(this.textBoxOutputFolder, this.textBoxOutputFolder.Text, "Select Output Video Path");
372+
}
283373
}
284374
}

MP4SubtitleMerger/MergedSubtitle.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics.Eventing.Reader;
34
using System.Linq;
45
using System.Text;
56
using System.Threading.Tasks;
@@ -18,5 +19,26 @@ public MergedSubtitle(TimeSpan from, TimeSpan to, List<MergedSubtitleLine> lines
1819
public TimeSpan From { get; set; }
1920
public TimeSpan To { get; set; }
2021
public List<MergedSubtitleLine> Lines { get; set; }
22+
23+
//return true if difference found, otherwise false
24+
public static bool CompareLines(MergedSubtitle left, MergedSubtitle right)
25+
{
26+
if (left.Lines.Count!=right.Lines.Count) return true;
27+
for (int j = 0; j < left.Lines.Count; j++)
28+
{
29+
if (left.Lines[j].Source !=
30+
right.Lines[j].Source)
31+
{
32+
return true;
33+
}
34+
if (string.Compare(left.Lines[j].Text,
35+
right.Lines[j].Text,
36+
StringComparison.Ordinal) != 0)
37+
{
38+
return true;
39+
}
40+
}
41+
return false;
42+
}
2143
}
2244
}

0 commit comments

Comments
 (0)