From ad273b82aaa782cad5c5a77272aac2b2d92468d6 Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Fri, 12 Jul 2024 11:54:03 -0400 Subject: [PATCH 01/14] Fix inconsistent capitalization --- TwitchDownloaderCore/ChatDownloader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TwitchDownloaderCore/ChatDownloader.cs b/TwitchDownloaderCore/ChatDownloader.cs index 1367267c..c37db366 100644 --- a/TwitchDownloaderCore/ChatDownloader.cs +++ b/TwitchDownloaderCore/ChatDownloader.cs @@ -326,7 +326,7 @@ private async Task DownloadAsyncImpl(FileInfo outputFileInfo, FileStream outputF await BackfillUserInfo(chatRoot); } - _progress.SetStatus("Writing output file"); + _progress.SetStatus("Writing Output File"); switch (downloadOptions.DownloadFormat) { case ChatFormat.Json: From d7aa28a5bc5df8ebf040a12142c7e1761d1e1e75 Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Sat, 13 Jul 2024 22:19:28 -0400 Subject: [PATCH 02/14] Reduce repeat memory allocations due to excessive EnsureCapacity calls --- TwitchDownloaderCore/ChatDownloader.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/TwitchDownloaderCore/ChatDownloader.cs b/TwitchDownloaderCore/ChatDownloader.cs index c37db366..c2e88e02 100644 --- a/TwitchDownloaderCore/ChatDownloader.cs +++ b/TwitchDownloaderCore/ChatDownloader.cs @@ -104,7 +104,6 @@ private static async Task> DownloadSection(double videoStart, doub } var convertedComments = ConvertComments(commentResponse[0].data.video, format); - comments.EnsureCapacity(Math.Min(0, comments.Capacity + convertedComments.Count)); foreach (var comment in convertedComments) { if (latestMessage < videoEnd && comment.content_offset_seconds > videoStart) From 99b30dcb5732297533b2e58288ca16a91c1368ea Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Sat, 13 Jul 2024 22:21:21 -0400 Subject: [PATCH 03/14] Manually report 100% progress --- TwitchDownloaderCore/ChatDownloader.cs | 2 ++ TwitchDownloaderCore/TsMerger.cs | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/TwitchDownloaderCore/ChatDownloader.cs b/TwitchDownloaderCore/ChatDownloader.cs index c2e88e02..5fe5597d 100644 --- a/TwitchDownloaderCore/ChatDownloader.cs +++ b/TwitchDownloaderCore/ChatDownloader.cs @@ -303,6 +303,8 @@ private async Task DownloadAsyncImpl(FileInfo outputFileInfo, FileStream outputF _progress.SetTemplateStatus("Downloading {0}%", 0); await Task.WhenAll(downloadTasks); + _progress.ReportProgress(100); + var sortedComments = new List(downloadTasks.Count); foreach (var commentTask in downloadTasks) { diff --git a/TwitchDownloaderCore/TsMerger.cs b/TwitchDownloaderCore/TsMerger.cs index 59c86252..0070faf5 100644 --- a/TwitchDownloaderCore/TsMerger.cs +++ b/TwitchDownloaderCore/TsMerger.cs @@ -75,8 +75,6 @@ private async Task MergeAsyncImpl(FileStream outputFs, CancellationToken cancell _progress.SetTemplateStatus("Combining Parts {0}% [2/2]", 0); await CombineVideoParts(fileList, outputFs, cancellationToken); - - _progress.ReportProgress(100); } private async Task VerifyVideoParts(IReadOnlyCollection fileList, CancellationToken cancellationToken) @@ -100,6 +98,8 @@ private async Task VerifyVideoParts(IReadOnlyCollection fileList, Cancel cancellationToken.ThrowIfCancellationRequested(); } + _progress.ReportProgress(100); + if (failedParts.Count != 0) { if (failedParts.Count == fileList.Count) @@ -153,6 +153,8 @@ private async Task CombineVideoParts(IReadOnlyCollection fileList, FileS cancellationToken.ThrowIfCancellationRequested(); } + + _progress.ReportProgress(100); } } } From 6978030f4f3f05395cecf49800b8a3ea4f46098f Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Sat, 13 Jul 2024 22:22:15 -0400 Subject: [PATCH 04/14] Use adjusted FileInfo instead of mergeOptions.OutputFile --- TwitchDownloaderCore/TsMerger.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/TwitchDownloaderCore/TsMerger.cs b/TwitchDownloaderCore/TsMerger.cs index 0070faf5..6c6f8764 100644 --- a/TwitchDownloaderCore/TsMerger.cs +++ b/TwitchDownloaderCore/TsMerger.cs @@ -34,7 +34,7 @@ public async Task MergeAsync(CancellationToken cancellationToken) try { - await MergeAsyncImpl(outputFs, cancellationToken); + await MergeAsyncImpl(outputFileInfo, outputFs, cancellationToken); } catch { @@ -46,7 +46,7 @@ public async Task MergeAsync(CancellationToken cancellationToken) } } - private async Task MergeAsyncImpl(FileStream outputFs, CancellationToken cancellationToken) + private async Task MergeAsyncImpl(FileInfo outputFileInfo, FileStream outputFs, CancellationToken cancellationToken) { var isM3U8 = false; var isFirst = true; @@ -74,7 +74,7 @@ private async Task MergeAsyncImpl(FileStream outputFs, CancellationToken cancell _progress.SetTemplateStatus("Combining Parts {0}% [2/2]", 0); - await CombineVideoParts(fileList, outputFs, cancellationToken); + await CombineVideoParts(fileList, outputFileInfo, outputFs, cancellationToken); } private async Task VerifyVideoParts(IReadOnlyCollection fileList, CancellationToken cancellationToken) @@ -131,9 +131,9 @@ private static async Task VerifyVideoPart(string filePath) return true; } - private async Task CombineVideoParts(IReadOnlyCollection fileList, FileStream outputStream, CancellationToken cancellationToken) + private async Task CombineVideoParts(IReadOnlyCollection fileList, FileInfo outputFileInfo, FileStream outputStream, CancellationToken cancellationToken) { - DriveInfo outputDrive = DriveHelper.GetOutputDrive(mergeOptions.OutputFile); + DriveInfo outputDrive = DriveHelper.GetOutputDrive(outputFileInfo.FullName); int partCount = fileList.Count; int doneCount = 0; From a97a40785b7fe6ada319b451cbc1850d78b08b75 Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Sun, 14 Jul 2024 01:21:07 -0400 Subject: [PATCH 05/14] Reduce allocations when aggregating & sorting comments --- TwitchDownloaderCore/ChatDownloader.cs | 13 +++++-------- TwitchDownloaderCore/ChatUpdater.cs | 14 ++++---------- .../Tools/CommentIdEqualityComparer.cs | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 18 deletions(-) create mode 100644 TwitchDownloaderCore/Tools/CommentIdEqualityComparer.cs diff --git a/TwitchDownloaderCore/ChatDownloader.cs b/TwitchDownloaderCore/ChatDownloader.cs index 5fe5597d..c0dfe828 100644 --- a/TwitchDownloaderCore/ChatDownloader.cs +++ b/TwitchDownloaderCore/ChatDownloader.cs @@ -305,15 +305,12 @@ private async Task DownloadAsyncImpl(FileInfo outputFileInfo, FileStream outputF _progress.ReportProgress(100); - var sortedComments = new List(downloadTasks.Count); - foreach (var commentTask in downloadTasks) - { - sortedComments.AddRange(commentTask.Result); - } - - sortedComments.Sort(new CommentOffsetComparer()); + chatRoot.comments = downloadTasks + .SelectMany(task => task.Result) + .ToHashSet(new CommentIdEqualityComparer()) + .ToList(); - chatRoot.comments = sortedComments.DistinctBy(x => x._id).ToList(); + chatRoot.comments.Sort(new CommentOffsetComparer()); if (downloadOptions.EmbedData && (downloadOptions.DownloadFormat is ChatFormat.Json or ChatFormat.Html)) { diff --git a/TwitchDownloaderCore/ChatUpdater.cs b/TwitchDownloaderCore/ChatUpdater.cs index 8613d823..25d5d7f7 100644 --- a/TwitchDownloaderCore/ChatUpdater.cs +++ b/TwitchDownloaderCore/ChatUpdater.cs @@ -431,24 +431,18 @@ private async Task ChatTrimEndingTask(CancellationToken cancellationToken) ChatRoot newChatRoot = await ChatJson.DeserializeAsync(inputFile, getComments: true, onlyFirstAndLastComments: false, getEmbeds: false, cancellationToken); // Append the new comment section - SortedSet commentsSet = new SortedSet(new CommentOffsetComparer()); - foreach (var comment in newChatRoot.comments) - { - if (comment.content_offset_seconds < downloadOptions.TrimEndingTime && comment.content_offset_seconds >= downloadOptions.TrimBeginningTime) - { - commentsSet.Add(comment); - } - } + var commentsSet = newChatRoot.comments.ToHashSet(new CommentIdEqualityComparer()); lock (_trimChatRootLock) { + commentsSet.EnsureCapacity(commentsSet.Count + chatRoot.comments.Count); foreach (var comment in chatRoot.comments) { commentsSet.Add(comment); } - List comments = commentsSet.DistinctBy(x => x._id).ToList(); - commentsSet.Clear(); + var comments = commentsSet.ToList(); + comments.Sort(new CommentOffsetComparer()); chatRoot.comments = comments; } diff --git a/TwitchDownloaderCore/Tools/CommentIdEqualityComparer.cs b/TwitchDownloaderCore/Tools/CommentIdEqualityComparer.cs new file mode 100644 index 00000000..200fb8ee --- /dev/null +++ b/TwitchDownloaderCore/Tools/CommentIdEqualityComparer.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using TwitchDownloaderCore.TwitchObjects; + +namespace TwitchDownloaderCore.Tools +{ + public class CommentIdEqualityComparer : IEqualityComparer + { + public bool Equals(Comment x, Comment y) + { + if (x is null) return y is null; + if (y is null) return false; + + return x._id.Equals(y._id); + } + + public int GetHashCode(Comment obj) => obj._id.GetHashCode(); + } +} \ No newline at end of file From 89c97158b2a85fefd19e3564674c7e8a0eea2043 Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Sun, 14 Jul 2024 14:20:30 -0400 Subject: [PATCH 06/14] Extract comment downloading & aggregating --- TwitchDownloaderCore/ChatDownloader.cs | 77 ++++++++++++++------------ 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/TwitchDownloaderCore/ChatDownloader.cs b/TwitchDownloaderCore/ChatDownloader.cs index c0dfe828..bedded6f 100644 --- a/TwitchDownloaderCore/ChatDownloader.cs +++ b/TwitchDownloaderCore/ChatDownloader.cs @@ -275,42 +275,8 @@ private async Task DownloadAsyncImpl(FileInfo outputFileInfo, FileStream outputF DownloadType downloadType = downloadOptions.Id.All(char.IsDigit) ? DownloadType.Video : DownloadType.Clip; var (chatRoot, connectionCount) = await InitChatRoot(downloadType); - var videoStart = chatRoot.video.start; - var videoEnd = chatRoot.video.end; - var videoId = chatRoot.video.id; - var videoDuration = videoEnd - videoStart; - - var downloadTasks = new List>>(connectionCount); - var percentages = new int[connectionCount]; - - double chunk = videoDuration / connectionCount; - for (int i = 0; i < connectionCount; i++) - { - int tc = i; - - var taskProgress = new Progress(percent => - { - percentages[tc] = Math.Clamp(percent, 0, 100); - - var reportPercent = percentages.Sum() / connectionCount; - _progress.ReportProgress(reportPercent); - }); - double start = videoStart + chunk * i; - downloadTasks.Add(DownloadSection(start, start + chunk, videoId, taskProgress, downloadOptions.DownloadFormat, cancellationToken)); - } - - _progress.SetTemplateStatus("Downloading {0}%", 0); - await Task.WhenAll(downloadTasks); - - _progress.ReportProgress(100); - - chatRoot.comments = downloadTasks - .SelectMany(task => task.Result) - .ToHashSet(new CommentIdEqualityComparer()) - .ToList(); - - chatRoot.comments.Sort(new CommentOffsetComparer()); + chatRoot.comments = await DownloadComments(cancellationToken, chatRoot.video, connectionCount); if (downloadOptions.EmbedData && (downloadOptions.DownloadFormat is ChatFormat.Json or ChatFormat.Html)) { @@ -438,6 +404,47 @@ private async Task DownloadAsyncImpl(FileInfo outputFileInfo, FileStream outputF return (chatRoot, connectionCount); } + private async Task> DownloadComments(CancellationToken cancellationToken, Video video, int connectionCount) + { + _progress.SetTemplateStatus("Downloading {0}%", 0); + + var videoStart = (int)Math.Floor(video.start); + var videoEnd = (int)Math.Ceiling(video.end); + var videoDuration = videoEnd - videoStart; + + var downloadTasks = new List>>(connectionCount); + var percentages = new int[connectionCount]; + + var chunk = videoDuration / connectionCount; + for (var i = 0; i < connectionCount; i++) + { + var tc = i; + + var taskProgress = new Progress(percent => + { + percentages[tc] = Math.Clamp(percent, 0, 100); + + var reportPercent = percentages.Sum() / connectionCount; + _progress.ReportProgress(reportPercent); + }); + + var start = videoStart + chunk * i; + downloadTasks.Add(DownloadSection(start, start + chunk, video.id, taskProgress, downloadOptions.DownloadFormat, cancellationToken)); + } + + await Task.WhenAll(downloadTasks); + + _progress.ReportProgress(100); + + var commentList = downloadTasks + .SelectMany(task => task.Result) + .ToHashSet(new CommentIdEqualityComparer()) + .ToList(); + + commentList.Sort(new CommentOffsetComparer()); + return commentList; + } + private async Task EmbedImages(ChatRoot chatRoot, CancellationToken cancellationToken) { _progress.SetTemplateStatus("Downloading Embed Images {0}%", 0); From 860d1abe4f76f77777c28bda18ec2e81b33c3cef Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Sun, 14 Jul 2024 14:23:15 -0400 Subject: [PATCH 07/14] Use a Range for holding download region --- TwitchDownloaderCore/ChatDownloader.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/TwitchDownloaderCore/ChatDownloader.cs b/TwitchDownloaderCore/ChatDownloader.cs index bedded6f..0dc18970 100644 --- a/TwitchDownloaderCore/ChatDownloader.cs +++ b/TwitchDownloaderCore/ChatDownloader.cs @@ -42,12 +42,12 @@ public ChatDownloader(ChatDownloadOptions chatDownloadOptions, ITaskProgress pro "TwitchDownloader"); } - private static async Task> DownloadSection(double videoStart, double videoEnd, string videoId, IProgress progress, ChatFormat format, CancellationToken cancellationToken) + private static async Task> DownloadSection(Range downloadRange, string videoId, IProgress progress, ChatFormat format, CancellationToken cancellationToken) { var comments = new List(); - //GQL only wants ints - videoStart = Math.Floor(videoStart); - double videoDuration = videoEnd - videoStart; + int videoStart = downloadRange.Start.Value; + int videoEnd = downloadRange.End.Value; + int videoDuration = videoEnd - videoStart; double latestMessage = videoStart - 1; bool isFirst = true; string cursor = ""; @@ -429,7 +429,8 @@ private async Task> DownloadComments(CancellationToken cancellatio }); var start = videoStart + chunk * i; - downloadTasks.Add(DownloadSection(start, start + chunk, video.id, taskProgress, downloadOptions.DownloadFormat, cancellationToken)); + var downloadRange = new Range(start, start + chunk); + downloadTasks.Add(DownloadSection(downloadRange, video.id, taskProgress, downloadOptions.DownloadFormat, cancellationToken)); } await Task.WhenAll(downloadTasks); From 9443ecbc943d3e246a2bd99b828adc3e3b535e14 Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Sun, 14 Jul 2024 14:49:57 -0400 Subject: [PATCH 08/14] Clarify converted comment adding logic --- TwitchDownloaderCore/ChatDownloader.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/TwitchDownloaderCore/ChatDownloader.cs b/TwitchDownloaderCore/ChatDownloader.cs index 0dc18970..2388d296 100644 --- a/TwitchDownloaderCore/ChatDownloader.cs +++ b/TwitchDownloaderCore/ChatDownloader.cs @@ -106,10 +106,15 @@ private static async Task> DownloadSection(Range downloadRange, st var convertedComments = ConvertComments(commentResponse[0].data.video, format); foreach (var comment in convertedComments) { - if (latestMessage < videoEnd && comment.content_offset_seconds > videoStart) + if (comment.content_offset_seconds >= videoStart && comment.content_offset_seconds < videoEnd) + { comments.Add(comment); + } - latestMessage = comment.content_offset_seconds; + if (comment.content_offset_seconds > latestMessage) + { + latestMessage = comment.content_offset_seconds; + } } if (!commentResponse[0].data.video.comments.pageInfo.hasNextPage) From 568858df4424f1bac79637596f3d827416dcb325 Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Sun, 14 Jul 2024 21:17:06 -0400 Subject: [PATCH 09/14] Fix potential for the last few seconds of chat messages to be not downloaded The number of seconds that can be skipped is <= the number of chat connections --- TwitchDownloaderCore/ChatDownloader.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/TwitchDownloaderCore/ChatDownloader.cs b/TwitchDownloaderCore/ChatDownloader.cs index 2388d296..f8857137 100644 --- a/TwitchDownloaderCore/ChatDownloader.cs +++ b/TwitchDownloaderCore/ChatDownloader.cs @@ -420,7 +420,7 @@ private async Task> DownloadComments(CancellationToken cancellatio var downloadTasks = new List>>(connectionCount); var percentages = new int[connectionCount]; - var chunk = videoDuration / connectionCount; + var chunkSize = (int)Math.Ceiling(videoDuration / (double)connectionCount); for (var i = 0; i < connectionCount; i++) { var tc = i; @@ -433,8 +433,9 @@ private async Task> DownloadComments(CancellationToken cancellatio _progress.ReportProgress(reportPercent); }); - var start = videoStart + chunk * i; - var downloadRange = new Range(start, start + chunk); + var start = videoStart + chunkSize * i; + var end = Math.Min(videoEnd, start + chunkSize); + var downloadRange = new Range(start, end); downloadTasks.Add(DownloadSection(downloadRange, video.id, taskProgress, downloadOptions.DownloadFormat, cancellationToken)); } From f26df1ce76ca85cd93475dd2c430794156406878 Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Sun, 14 Jul 2024 21:17:13 -0400 Subject: [PATCH 10/14] Cleanup --- TwitchDownloaderCore/ChatUpdater.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/TwitchDownloaderCore/ChatUpdater.cs b/TwitchDownloaderCore/ChatUpdater.cs index 25d5d7f7..1edcaa41 100644 --- a/TwitchDownloaderCore/ChatUpdater.cs +++ b/TwitchDownloaderCore/ChatUpdater.cs @@ -441,10 +441,8 @@ private async Task ChatTrimEndingTask(CancellationToken cancellationToken) commentsSet.Add(comment); } - var comments = commentsSet.ToList(); - comments.Sort(new CommentOffsetComparer()); - - chatRoot.comments = comments; + chatRoot.comments = commentsSet.ToList(); + chatRoot.comments.Sort(new CommentOffsetComparer()); } } From 3457250a09e94502b8c94cc1f62d94a2acb24e8b Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Sun, 14 Jul 2024 21:53:44 -0400 Subject: [PATCH 11/14] Make videoEnd exclusive to catch comments sent on last second of the broadcast --- TwitchDownloaderCore/ChatDownloader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TwitchDownloaderCore/ChatDownloader.cs b/TwitchDownloaderCore/ChatDownloader.cs index f8857137..a8f24eb6 100644 --- a/TwitchDownloaderCore/ChatDownloader.cs +++ b/TwitchDownloaderCore/ChatDownloader.cs @@ -414,7 +414,7 @@ private async Task> DownloadComments(CancellationToken cancellatio _progress.SetTemplateStatus("Downloading {0}%", 0); var videoStart = (int)Math.Floor(video.start); - var videoEnd = (int)Math.Ceiling(video.end); + var videoEnd = (int)Math.Ceiling(video.end) + 1; // Exclusive end var videoDuration = videoEnd - videoStart; var downloadTasks = new List>>(connectionCount); From 07c40f6048d864bf9b8bff1b2f326d79966af7b7 Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Sun, 14 Jul 2024 21:54:05 -0400 Subject: [PATCH 12/14] progress will never be null --- TwitchDownloaderCore/ChatDownloader.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/TwitchDownloaderCore/ChatDownloader.cs b/TwitchDownloaderCore/ChatDownloader.cs index a8f24eb6..d89b18aa 100644 --- a/TwitchDownloaderCore/ChatDownloader.cs +++ b/TwitchDownloaderCore/ChatDownloader.cs @@ -122,11 +122,8 @@ private static async Task> DownloadSection(Range downloadRange, st cursor = commentResponse[0].data.video.comments.edges.Last().cursor; - if (progress != null) - { - int percent = (int)Math.Floor((latestMessage - videoStart) / videoDuration * 100); - progress.Report(percent); - } + var percent = (int)Math.Floor((latestMessage - videoStart) / videoDuration * 100); + progress.Report(percent); if (isFirst) { From d0a9e163ce804581cfb47c529c7fc823b4e37dc4 Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Mon, 15 Jul 2024 18:52:42 -0400 Subject: [PATCH 13/14] Use constrained generic instead of IFormattable --- TwitchDownloaderCore/Tools/FilenameService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TwitchDownloaderCore/Tools/FilenameService.cs b/TwitchDownloaderCore/Tools/FilenameService.cs index 338dddcc..0603a25e 100644 --- a/TwitchDownloaderCore/Tools/FilenameService.cs +++ b/TwitchDownloaderCore/Tools/FilenameService.cs @@ -55,7 +55,7 @@ public static string GetFilename(string template, [AllowNull] string title, [All return Path.Combine(Path.Combine(additionalSubfolders), ReplaceInvalidFilenameChars(fileName)); } - private static void ReplaceCustomWithFormattable(StringBuilder sb, Regex regex, IFormattable formattable, IFormatProvider formatProvider = null) + private static void ReplaceCustomWithFormattable(StringBuilder sb, Regex regex, TFormattable formattable, IFormatProvider formatProvider = null) where TFormattable : IFormattable { do { From e07ee464df0f8e64d5f12e9313ca1ccce940c38e Mon Sep 17 00:00:00 2001 From: ScrubN <72096833+ScrubN@users.noreply.github.com> Date: Mon, 15 Jul 2024 19:21:03 -0400 Subject: [PATCH 14/14] Support TimeSpanHFormat in FilenameService --- TwitchDownloaderCore/Tools/FilenameService.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/TwitchDownloaderCore/Tools/FilenameService.cs b/TwitchDownloaderCore/Tools/FilenameService.cs index 0603a25e..67796551 100644 --- a/TwitchDownloaderCore/Tools/FilenameService.cs +++ b/TwitchDownloaderCore/Tools/FilenameService.cs @@ -35,19 +35,19 @@ public static string GetFilename(string template, [AllowNull] string title, [All if (template.Contains("{trim_start_custom=")) { var trimStartRegex = new Regex("{trim_start_custom=\"(.*?)\"}"); - ReplaceCustomWithFormattable(stringBuilder, trimStartRegex, trimStart); + ReplaceCustomWithFormattable(stringBuilder, trimStartRegex, trimStart, TimeSpanHFormat.ReusableInstance); } if (template.Contains("{trim_end_custom=")) { var trimEndRegex = new Regex("{trim_end_custom=\"(.*?)\"}"); - ReplaceCustomWithFormattable(stringBuilder, trimEndRegex, trimEnd); + ReplaceCustomWithFormattable(stringBuilder, trimEndRegex, trimEnd, TimeSpanHFormat.ReusableInstance); } if (template.Contains("{length_custom=")) { var lengthRegex = new Regex("{length_custom=\"(.*?)\"}"); - ReplaceCustomWithFormattable(stringBuilder, lengthRegex, videoLength); + ReplaceCustomWithFormattable(stringBuilder, lengthRegex, videoLength, TimeSpanHFormat.ReusableInstance); } var fileName = stringBuilder.ToString(); @@ -55,7 +55,7 @@ public static string GetFilename(string template, [AllowNull] string title, [All return Path.Combine(Path.Combine(additionalSubfolders), ReplaceInvalidFilenameChars(fileName)); } - private static void ReplaceCustomWithFormattable(StringBuilder sb, Regex regex, TFormattable formattable, IFormatProvider formatProvider = null) where TFormattable : IFormattable + private static void ReplaceCustomWithFormattable(StringBuilder sb, Regex regex, TFormattable formattable, [AllowNull] IFormatProvider formatProvider = null) where TFormattable : IFormattable { do { @@ -66,8 +66,12 @@ private static void ReplaceCustomWithFormattable(StringBuilder sb, break; var formatString = match.Groups[1].Value; + var formattedString = formatProvider?.GetFormat(typeof(ICustomFormatter)) is ICustomFormatter customFormatter + ? customFormatter.Format(formatString, formattable, formatProvider) + : formattable.ToString(formatString, formatProvider); + sb.Remove(match.Groups[0].Index, match.Groups[0].Length); - sb.Insert(match.Groups[0].Index, ReplaceInvalidFilenameChars(formattable.ToString(formatString, formatProvider))); + sb.Insert(match.Groups[0].Index, ReplaceInvalidFilenameChars(formattedString)); } while (true); }