diff --git a/src/Test/Logic/DimensionTest.cs b/src/Test/Logic/DimensionTest.cs new file mode 100644 index 000000000..c43ad570c --- /dev/null +++ b/src/Test/Logic/DimensionTest.cs @@ -0,0 +1,34 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Nikse.SubtitleEdit.Core.Common; + +namespace Test.Logic +{ + [TestClass] + public class DimensionTest + { + [TestMethod] + public void InvalidTest() + { + var dimension = new Dimension(); + Assert.AreEqual(0, dimension.Width); + Assert.AreEqual(0, dimension.Height); + Assert.IsTrue(!dimension.IsValid()); + } + + [TestMethod] + public void ValidTest() + { + var dimension = new Dimension(10, 10); + Assert.IsTrue(dimension.IsValid()); + } + + [TestMethod] + public void EqualityTest() + { + var dimensionOne = new Dimension(); + var dimensionTwo = new Dimension(); + Assert.AreEqual(dimensionOne, dimensionTwo); + Assert.IsTrue(dimensionOne == dimensionTwo); + } + } +} \ No newline at end of file diff --git a/src/Test/Test.csproj b/src/Test/Test.csproj index 0bbe85949..c0c2f74a0 100644 --- a/src/Test/Test.csproj +++ b/src/Test/Test.csproj @@ -76,6 +76,7 @@ + diff --git a/src/libse/Common/Dimension.cs b/src/libse/Common/Dimension.cs new file mode 100644 index 000000000..e70de3674 --- /dev/null +++ b/src/libse/Common/Dimension.cs @@ -0,0 +1,40 @@ +using System; + +namespace Nikse.SubtitleEdit.Core.Common +{ + /// + /// Struct representing the dimensions of an object. + /// + public struct Dimension : IEquatable + { + public int Height { get; set; } + public int Width { get; set; } + + public Dimension(int height, int width) => (Height, Width) = (height, width); + + /// + /// Returns a string representation of the Dimension object, representing its height and width. + /// + /// A string representation of the Dimension object, in the format "height x width". + public override string ToString() => $"{Height}x{Width}"; + + public bool Equals(Dimension other) => Height == other.Height && Width == other.Width; + public override bool Equals(object obj) => obj is Dimension other && Equals(other); + public static bool operator ==(Dimension left, Dimension right) => left.Equals(right); + public static bool operator !=(Dimension left, Dimension right) => !(left == right); + + /// + /// Checks if the dimension (height and width) is valid. + /// + /// True if the dimension is valid; otherwise, false. + public bool IsValid() => Width > 0 && Height > 0; + + public override int GetHashCode() + { + unchecked + { + return (Height * 397) ^ Width; + } + } + } +} \ No newline at end of file diff --git a/src/libse/Common/FfmpegMediaInfo.cs b/src/libse/Common/FfmpegMediaInfo.cs index d4ff98e53..a45176794 100644 --- a/src/libse/Common/FfmpegMediaInfo.cs +++ b/src/libse/Common/FfmpegMediaInfo.cs @@ -11,8 +11,8 @@ namespace Nikse.SubtitleEdit.Core.Common public class FfmpegMediaInfo { public List Tracks { get; set; } - public int VideoWidth { get; set; } - public int VideoHeight { get; set; } + + public Dimension Dimension { get; set; } private static readonly Regex ResolutionRegex = new Regex(@"\d\d+x\d\d+", RegexOptions.Compiled); @@ -65,13 +65,12 @@ namespace Nikse.SubtitleEdit.Core.Common if (resolutionMatch.Success) { var parts = resolutionMatch.Value.Split('x'); - if (info.VideoWidth == 0 && + if (info.Dimension.Width == 0 && parts.Length == 2 && int.TryParse(parts[0], out var w) && int.TryParse(parts[1], out var h)) { - info.VideoWidth = w; - info.VideoHeight = h; + info.Dimension = new Dimension(h, w); } } diff --git a/src/libse/Common/FileUtil.cs b/src/libse/Common/FileUtil.cs index 7da4577ae..f9fa0760c 100644 --- a/src/libse/Common/FileUtil.cs +++ b/src/libse/Common/FileUtil.cs @@ -6,6 +6,7 @@ using Nikse.SubtitleEdit.Core.VobSub; using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using System.Text.RegularExpressions; @@ -707,5 +708,53 @@ namespace Nikse.SubtitleEdit.Core.Common return false; } + + public static string TryLocateSubtitleFile(string path, string videoFileName) + { + // search in these subdirectories: \Subs;\Sub;\Subtitles; + var knownSubtitleDirectories = new[] + { + path, Path.Combine(path, "Subs"), Path.Combine(path, "Sub"), Path.Combine(path, "Subtitles") + }; + + // handles if video file was sent with full path + if (Path.IsPathRooted(videoFileName)) + { + videoFileName = Path.GetFileName(videoFileName); + } + + foreach (var knownSubtitleDirectory in knownSubtitleDirectories) + { + if (!Directory.Exists(knownSubtitleDirectory)) + { + continue; + } + + // try to locate subtitle file that has the same name as the video file + var defaultSubtitles = new[] + { + Path.Combine(knownSubtitleDirectory, Path.ChangeExtension(videoFileName, ".ass")), + Path.Combine(knownSubtitleDirectory, Path.ChangeExtension(videoFileName, ".srt")) + }; + foreach (var defaultSubtitle in defaultSubtitles) + { + if (File.Exists(defaultSubtitle)) + { + return defaultSubtitle; + } + } + + // get first subtitle in path with extension .ass or .srt + var assEnumerable = Directory.EnumerateFiles(knownSubtitleDirectory, "*.ass", SearchOption.TopDirectoryOnly); + var subRipEnumerable = Directory.EnumerateFiles(knownSubtitleDirectory, "*.srt", SearchOption.TopDirectoryOnly); + var subtitleFile = assEnumerable.Concat(subRipEnumerable).FirstOrDefault(); + if (!string.IsNullOrEmpty(subtitleFile)) + { + return subtitleFile; + } + } + + return string.Empty; + } } } diff --git a/src/ui/Forms/GenerateVideoWithHardSubs.cs b/src/ui/Forms/GenerateVideoWithHardSubs.cs index 722e7ca6a..e5b64fa2e 100644 --- a/src/ui/Forms/GenerateVideoWithHardSubs.cs +++ b/src/ui/Forms/GenerateVideoWithHardSubs.cs @@ -2139,100 +2139,88 @@ namespace Nikse.SubtitleEdit.Forms } } - private void AddInputFile(string fileName) + private void AddInputFile(string videoFileName) { - if (string.IsNullOrEmpty(fileName)) + if (string.IsNullOrEmpty(videoFileName)) { return; } - var ext = Path.GetExtension(fileName).ToLowerInvariant(); - if ((Utilities.AudioFileExtensions.Contains(ext) || Utilities.VideoFileExtensions.Contains(ext)) && File.Exists(fileName)) + var ext = Path.GetExtension(videoFileName).ToLowerInvariant(); + if ((Utilities.AudioFileExtensions.Contains(ext) || Utilities.VideoFileExtensions.Contains(ext)) && File.Exists(videoFileName)) { - var item = new BatchVideoAndSub(); - item.VideoFileName = fileName; - item.VideoFileSizeInBytes = new FileInfo(fileName).Length; - - var path = Path.GetDirectoryName(fileName); - var fileNameNoExt = Path.GetFileNameWithoutExtension(fileName); - var subFileName = Path.ChangeExtension(fileName, ".ass"); - - if (!File.Exists(subFileName)) + var videoDimension = GetVideoDimension(videoFileName); + if (!videoDimension.IsValid()) { - subFileName = Path.ChangeExtension(fileName, ".srt"); + return; } - - if (!File.Exists(subFileName)) - { - var files = Directory.GetFiles(path, fileNameNoExt + "*.ass"); - if (files.Length > 0) - { - subFileName = files[0]; - } - } - - if (!File.Exists(subFileName)) - { - var files = Directory.GetFiles(path, fileNameNoExt + "*.srt"); - if (files.Length > 0) - { - subFileName = files[0]; - } - } - - if (File.Exists(subFileName)) - { - item.SubtitleFileName = subFileName; - item.SubtitleFileFileSizeInBytes = new FileInfo(subFileName).Length; - } - - var mediaInfo = FfmpegMediaInfo.Parse(fileName); - int width; - int height; - if (mediaInfo.VideoWidth > 0 && mediaInfo.VideoHeight > 0) - { - width = mediaInfo.VideoWidth; - height = mediaInfo.VideoHeight; - } - else - { - var vInfo = new VideoInfo { Success = false }; - if (fileName.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase)) - { - vInfo = QuartsPlayer.GetVideoInfo(fileName); - if (!vInfo.Success) - { - vInfo = LibMpvDynamic.GetVideoInfo(fileName); - } - } - - if (!vInfo.Success) - { - vInfo = UiUtil.GetVideoInfo(fileName); - } - - width = vInfo.Width; - height = vInfo.Height; - } - - if (width == 0 || height == 0) - { - SeLogger.Error("Skipping burn-in file with no video: " + fileName); - return; // skip audio or damaged files - } - - var listViewItem = new ListViewItem(fileName); - listViewItem.Tag = item; - listViewItem.SubItems.Add($"{width}x{height}"); - var s = Utilities.FormatBytesToDisplayFileSize(item.VideoFileSizeInBytes); + + var batchVideoAndSub = CreateBatchVideoAndSub(videoFileName); + var listViewItem = new ListViewItem(videoFileName) { Tag = batchVideoAndSub }; + listViewItem.SubItems.Add(videoDimension.ToString()); + var s = Utilities.FormatBytesToDisplayFileSize(batchVideoAndSub.VideoFileSizeInBytes); listViewItem.SubItems.Add(s); - listViewItem.SubItems.Add(Path.GetFileName(item.SubtitleFileName)); + listViewItem.SubItems.Add(Path.GetFileName(batchVideoAndSub.SubtitleFileName)); listViewItem.SubItems.Add(string.Empty); listViewBatch.Items.Add(listViewItem); - _batchVideoAndSubList.Add(item); + _batchVideoAndSubList.Add(batchVideoAndSub); } } + private BatchVideoAndSub CreateBatchVideoAndSub(string videoFileName) + { + var batchVideoAndSub = new BatchVideoAndSub + { + VideoFileName = videoFileName, + VideoFileSizeInBytes = new FileInfo(videoFileName).Length + }; + + var path = Path.GetDirectoryName(videoFileName); + // try to locate subtitle file for the input vide file + var subtitleFile = FileUtil.TryLocateSubtitleFile(path, videoFileName); + if (File.Exists(subtitleFile)) + { + batchVideoAndSub.SubtitleFileName = subtitleFile; + batchVideoAndSub.SubtitleFileFileSizeInBytes = new FileInfo(subtitleFile).Length; + } + + return batchVideoAndSub; + } + + private Dimension GetVideoDimension(string videoFileName) + { + var mediaInfo = FfmpegMediaInfo.Parse(videoFileName); + if (mediaInfo.Dimension.IsValid()) + { + return mediaInfo.Dimension; + } + + var vInfo = new VideoInfo { Success = false }; + if (videoFileName.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase)) + { + vInfo = QuartsPlayer.GetVideoInfo(videoFileName); + if (!vInfo.Success) + { + vInfo = LibMpvDynamic.GetVideoInfo(videoFileName); + } + } + + if (!vInfo.Success) + { + vInfo = UiUtil.GetVideoInfo(videoFileName); + } + + var dimension = new Dimension(vInfo.Height, vInfo.Width); + + // skip audio or damaged files + if (!dimension.IsValid()) + { + SeLogger.Error("Skipping burn-in file with no video: " + videoFileName); + } + + return dimension; + } + private void deleteToolStripMenuItem_Click(object sender, EventArgs e) { var indices = new List();