Skip to content

Commit

Permalink
Crop filename parameters (#650)
Browse files Browse the repository at this point in the history
* Add 'crop_start' 'crop_end' 'crop_start_custom' and 'crop_end_custom' filename parameters, cleanup filename computation.

* Fix txt chat relative timestamps resetting after 24 hours

* Adjust window height
  • Loading branch information
ScrubN authored Apr 3, 2023
1 parent 2edbabc commit 479ac7a
Show file tree
Hide file tree
Showing 17 changed files with 334 additions and 95 deletions.
10 changes: 5 additions & 5 deletions TwitchDownloaderCore/Chat/ChatText.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Threading.Tasks;
using TwitchDownloaderCore.Tools;
using TwitchDownloaderCore.TwitchObjects;

namespace TwitchDownloaderCore.Chat
Expand Down Expand Up @@ -28,17 +29,16 @@ public static async Task SerializeAsync(string filePath, ChatRoot chatRoot, Time
if (timeFormat == TimestampFormat.Utc)
{
string timestamp = comment.created_at.ToString("u").Replace("Z", " UTC");
await sw.WriteLineAsync(string.Format("[{0}] {1}: {2}", timestamp, username, message));
await sw.WriteLineAsync($"[{timestamp}] {username}: {message}");
}
else if (timeFormat == TimestampFormat.Relative)
{
var time = new TimeSpan(0, 0, (int)comment.content_offset_seconds);
string timestamp = time.ToString(@"h\:mm\:ss");
await sw.WriteLineAsync(string.Format("[{0}] {1}: {2}", timestamp, username, message));
var time = TimeSpan.FromSeconds(comment.content_offset_seconds);
await sw.WriteLineAsync(string.Format(new TimeSpanHFormat(), @"[{0:H\:mm\:ss}] {1}: {2}", time, username, message));
}
else if (timeFormat == TimestampFormat.None)
{
await sw.WriteLineAsync(string.Format("{0}: {1}", username, message));
await sw.WriteLineAsync($"{username}: {message}");
}
}

Expand Down
109 changes: 109 additions & 0 deletions TwitchDownloaderCore/Tools/TimeSpanHFormat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using System;
using System.Globalization;
using System.IO;
using System.Text;

namespace TwitchDownloaderCore.Tools
{
/// <summary>
/// Adds an 'H' parameter to TimeSpan string formatting. The 'H' parameter is equivalent to flooring <see cref="TimeSpan"/>.TotalHours.
/// </summary>
/// <remarks>
/// The fact that this is not part of .NET is stupid.
/// </remarks>
public class TimeSpanHFormat : IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
return this;
else
return null;
}

public string Format(string format, object arg, IFormatProvider formatProvider)
{
if (!(arg is TimeSpan timeSpan))
{
return HandleOtherFormats(format, arg);
}

if (!format.Contains('H'))
{
return HandleOtherFormats(format, arg);
}

var reader = new StringReader(format);
var builder = new StringBuilder(format.Length);
var regularFormatCharStart = -1;
var bigHStart = -1;
var position = -1;
do
{
var readChar = reader.Read();
position++;

if (readChar == 'H')
{
if (bigHStart == -1)
{
bigHStart = position;
}

if (regularFormatCharStart != -1)
{
builder.Append(timeSpan.ToString(format.Substring(regularFormatCharStart, position - regularFormatCharStart)));
regularFormatCharStart = -1;
}
}
else
{
if (regularFormatCharStart == -1)
{
regularFormatCharStart = position;
}

if (bigHStart != -1)
{
var formatString = "";
for (var i = 0; i < position - bigHStart; i++)
{
formatString += "0";
}

builder.Append(((int)timeSpan.TotalHours).ToString(formatString));
bigHStart = -1;
}
}
} while (reader.Peek() != -1);

position++;
if (regularFormatCharStart != -1)
{
builder.Append(timeSpan.ToString(format.Substring(regularFormatCharStart, position - regularFormatCharStart)));
}
else if (bigHStart != -1)
{
var formatString = "";
for (var i = 0; i < position - bigHStart; i++)
{
formatString += "0";
}

builder.Append(((int)timeSpan.TotalHours).ToString(formatString));
}

return builder.ToString();
}

private string HandleOtherFormats(string format, object arg)
{
if (arg is IFormattable)
return ((IFormattable)arg).ToString(format, CultureInfo.CurrentCulture);
else if (arg != null)
return arg.ToString();
else
return "";
}
}
}
38 changes: 0 additions & 38 deletions TwitchDownloaderWPF/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,43 +83,5 @@ private async void Window_Loaded(object sender, RoutedEventArgs e)
AutoUpdater.Start("https://downloader-update.twitcharchives.workers.dev");
#endif
}

internal static string[] GetTemplateSubfolders(ref string fullPath)
{
string[] returnString = fullPath.Split(new char[] { '\\', '/'}, StringSplitOptions.RemoveEmptyEntries);
fullPath = returnString[returnString.Length- 1];
Array.Resize(ref returnString, returnString.Length - 1);
return returnString;
}

internal static string GetFilename(string template, string title, string id, DateTime date, string channel)
{
StringBuilder returnString = new StringBuilder(template.Replace("{title}", title).Replace("{id}", id).Replace("{channel}", channel).Replace("{date}", date.ToString("Mdyy")).Replace("{random_string}", Path.GetRandomFileName().Split('.').First()));
Regex dateRegex = new Regex("{date_custom=\"(.*)\"}");
bool done = false;
while (!done)
{
Match dateRegexMatch = dateRegex.Match(returnString.ToString());
if (dateRegexMatch.Success)
{
string formatString = dateRegexMatch.Groups[1].Value;
returnString.Remove(dateRegexMatch.Groups[0].Index, dateRegexMatch.Groups[0].Length);
returnString.Insert(dateRegexMatch.Groups[0].Index, date.ToString(formatString));
}
else
{
done = true;
}
}

string fileName = returnString.ToString();
string[] additionalSubfolders = GetTemplateSubfolders(ref fileName);
return Path.Combine(Path.Combine(additionalSubfolders), RemoveInvalidChars(fileName));
}

public static string RemoveInvalidChars(string filename)
{
return string.Concat(filename.Split(Path.GetInvalidFileNameChars()));
}
}
}
7 changes: 5 additions & 2 deletions TwitchDownloaderWPF/PageChatDownload.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public partial class PageChatDownload : Page
public string downloadId;
public int streamerId;
public DateTime currentVideoTime;
public TimeSpan vodLength;
private CancellationTokenSource _cancellationTokenSource;

public PageChatDownload()
Expand Down Expand Up @@ -121,7 +122,7 @@ private async void btnGetInfo_Click(object sender, RoutedEventArgs e)
imgThumbnail.Source = image;
}
}
TimeSpan vodLength = TimeSpan.FromSeconds(videoInfo.data.video.lengthSeconds);
vodLength = TimeSpan.FromSeconds(videoInfo.data.video.lengthSeconds);
textTitle.Text = videoInfo.data.video.title;
textStreamer.Text = videoInfo.data.video.owner.displayName;
var videoTime = videoInfo.data.video.createdAt;
Expand Down Expand Up @@ -456,7 +457,9 @@ private async void SplitBtnDownload_Click(object sender, RoutedEventArgs e)
else if (radioText.IsChecked == true)
saveFileDialog.Filter = "TXT Files | *.txt";

saveFileDialog.FileName = MainWindow.GetFilename(Settings.Default.TemplateChat, textTitle.Text, downloadId, currentVideoTime, textStreamer.Text);
saveFileDialog.FileName = FilenameService.GetFilename(Settings.Default.TemplateChat, textTitle.Text, downloadId, currentVideoTime, textStreamer.Text,
checkCropStart.IsChecked == true ? new TimeSpan((int)numStartHour.Value, (int)numStartMinute.Value, (int)numStartSecond.Value) : TimeSpan.Zero,
checkCropEnd.IsChecked == true ? new TimeSpan((int)numEndHour.Value, (int)numEndMinute.Value, (int)numEndSecond.Value) : vodLength);

if (saveFileDialog.ShowDialog() != true)
{
Expand Down
24 changes: 14 additions & 10 deletions TwitchDownloaderWPF/PageChatUpdate.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public partial class PageChatUpdate : Page
public ChatRoot ChatJsonInfo;
public string VideoId;
public DateTime VideoCreatedAt;
public TimeSpan VideoLength;
private CancellationTokenSource _cancellationTokenSource;

public PageChatUpdate()
Expand Down Expand Up @@ -76,9 +77,9 @@ private async void btnBrowse_Click(object sender, RoutedEventArgs e)
numEndMinute.Value = chatEnd.Minutes;
numEndSecond.Value = chatEnd.Seconds;

TimeSpan videoLength = TimeSpan.FromSeconds(double.IsNegative(ChatJsonInfo.video.length) ? 0.0 : ChatJsonInfo.video.length);
labelLength.Text = videoLength.Seconds > 0
? videoLength.ToString("c")
VideoLength = TimeSpan.FromSeconds(double.IsNegative(ChatJsonInfo.video.length) ? 0.0 : ChatJsonInfo.video.length);
labelLength.Text = VideoLength.Seconds > 0
? VideoLength.ToString("c")
: Translations.Strings.Unknown;

VideoId = ChatJsonInfo.video.id ?? ChatJsonInfo.comments.FirstOrDefault()?.content_id ?? "-1";
Expand All @@ -99,10 +100,10 @@ private async void btnBrowse_Click(object sender, RoutedEventArgs e)
}
else
{
videoLength = TimeSpan.FromSeconds(videoInfo.data.video.lengthSeconds);
labelLength.Text = videoLength.ToString("c");
numStartHour.Maximum = (int)videoLength.TotalHours;
numEndHour.Maximum = (int)videoLength.TotalHours;
VideoLength = TimeSpan.FromSeconds(videoInfo.data.video.lengthSeconds);
labelLength.Text = VideoLength.ToString("c");
numStartHour.Maximum = (int)VideoLength.TotalHours;
numEndHour.Maximum = (int)VideoLength.TotalHours;

try
{
Expand Down Expand Up @@ -136,8 +137,8 @@ private async void btnBrowse_Click(object sender, RoutedEventArgs e)
}
else
{
videoLength = TimeSpan.FromSeconds(videoInfo.data.clip.durationSeconds);
labelLength.Text = videoLength.ToString("c");
VideoLength = TimeSpan.FromSeconds(videoInfo.data.clip.durationSeconds);
labelLength.Text = VideoLength.ToString("c");

try
{
Expand Down Expand Up @@ -460,7 +461,10 @@ private async void SplitBtnUpdate_Click(object sender, RoutedEventArgs e)
else if (radioText.IsChecked == true)
saveFileDialog.Filter = "TXT Files | *.txt";

saveFileDialog.FileName = MainWindow.GetFilename(Settings.Default.TemplateChat, textTitle.Text, ChatJsonInfo.video.id ?? ChatJsonInfo.comments.FirstOrDefault()?.content_id ?? "-1", VideoCreatedAt, textStreamer.Text);
saveFileDialog.FileName = FilenameService.GetFilename(Settings.Default.TemplateChat, textTitle.Text,
ChatJsonInfo.video.id ?? ChatJsonInfo.comments.FirstOrDefault()?.content_id ?? "-1", VideoCreatedAt, textStreamer.Text,
checkStart.IsChecked == true ? new TimeSpan((int)numStartHour.Value, (int)numStartMinute.Value, (int)numStartSecond.Value) : TimeSpan.FromSeconds(double.IsNegative(ChatJsonInfo.video.start) ? 0.0 : ChatJsonInfo.video.start),
checkEnd.IsChecked == true ? new TimeSpan((int)numEndHour.Value, (int)numEndMinute.Value, (int)numEndSecond.Value) : VideoLength);

if (saveFileDialog.ShowDialog() != true)
{
Expand Down
5 changes: 3 additions & 2 deletions TwitchDownloaderWPF/PageClipDownload.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public partial class PageClipDownload : Page
{
public string clipId = "";
public DateTime currentVideoTime;
public TimeSpan clipLength;
private CancellationTokenSource _cancellationTokenSource;

public PageClipDownload()
Expand Down Expand Up @@ -65,7 +66,7 @@ private async void btnGetInfo_Click(object sender, RoutedEventArgs e)
imgThumbnail.Source = image;
}
}
TimeSpan clipLength = TimeSpan.FromSeconds(taskClipInfo.Result.data.clip.durationSeconds);
clipLength = TimeSpan.FromSeconds(taskClipInfo.Result.data.clip.durationSeconds);
textStreamer.Text = clipData.data.clip.broadcaster.displayName;
var clipCreatedAt = clipData.data.clip.createdAt;
textCreatedAt.Text = Settings.Default.UTCVideoTime ? clipCreatedAt.ToString(CultureInfo.CurrentCulture) : clipCreatedAt.ToLocalTime().ToString(CultureInfo.CurrentCulture);
Expand Down Expand Up @@ -173,7 +174,7 @@ private async void SplitBtnDownload_Click(object sender, RoutedEventArgs e)
SaveFileDialog saveFileDialog = new SaveFileDialog
{
Filter = "MP4 Files | *.mp4",
FileName = MainWindow.GetFilename(Settings.Default.TemplateClip, textTitle.Text, clipId, currentVideoTime, textStreamer.Text)
FileName = FilenameService.GetFilename(Settings.Default.TemplateClip, textTitle.Text, clipId, currentVideoTime, textStreamer.Text, TimeSpan.Zero, clipLength)
};
if (saveFileDialog.ShowDialog() != true)
{
Expand Down
Loading

0 comments on commit 479ac7a

Please sign in to comment.