Skip to content

Commit

Permalink
More video info (#774)
Browse files Browse the repository at this point in the history
* Add views, game, length, and length_custom filename parameters

* Update translations
Note: Google translate was used to check punctuation

* Better memory performance when serializing FFmetadata

* Bump ChatRootVersion
  • Loading branch information
ScrubN authored Aug 3, 2023
1 parent 0a1a97a commit 5b3ea38
Show file tree
Hide file tree
Showing 25 changed files with 161 additions and 61 deletions.
8 changes: 8 additions & 0 deletions TwitchDownloaderCore/ChatDownloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ public async Task DownloadAsync(IProgress<ProgressReport> progress, Cancellation
double videoEnd = 0.0;
double videoDuration = 0.0;
double videoTotalLength;
int viewCount;
string game;
int connectionCount = downloadOptions.ConnectionCount;

if (downloadType == DownloadType.Video)
Expand All @@ -286,6 +288,8 @@ public async Task DownloadAsync(IProgress<ProgressReport> progress, Cancellation
videoStart = downloadOptions.CropBeginning ? downloadOptions.CropBeginningTime : 0.0;
videoEnd = downloadOptions.CropEnding ? downloadOptions.CropEndingTime : videoInfoResponse.data.video.lengthSeconds;
videoTotalLength = videoInfoResponse.data.video.lengthSeconds;
viewCount = videoInfoResponse.data.video.viewCount;
game = videoInfoResponse.data.video.game?.displayName ?? "Unknown";

GqlVideoChapterResponse videoChapterResponse = await TwitchHelper.GetVideoChapters(int.Parse(videoId));
foreach (var responseChapter in videoChapterResponse.data.video.moments.edges)
Expand Down Expand Up @@ -325,6 +329,8 @@ public async Task DownloadAsync(IProgress<ProgressReport> progress, Cancellation
videoStart = (int)clipInfoResponse.data.clip.videoOffsetSeconds;
videoEnd = (int)clipInfoResponse.data.clip.videoOffsetSeconds + clipInfoResponse.data.clip.durationSeconds;
videoTotalLength = clipInfoResponse.data.clip.durationSeconds;
viewCount = clipInfoResponse.data.clip.viewCount;
game = clipInfoResponse.data.clip.game?.displayName ?? "Unknown";
connectionCount = 1;
}

Expand All @@ -334,6 +340,8 @@ public async Task DownloadAsync(IProgress<ProgressReport> progress, Cancellation
chatRoot.video.start = videoStart;
chatRoot.video.end = videoEnd;
chatRoot.video.length = videoTotalLength;
chatRoot.video.viewCount = viewCount;
chatRoot.video.game = game;
videoDuration = videoEnd - videoStart;

var tasks = new List<Task<List<Comment>>>();
Expand Down
13 changes: 10 additions & 3 deletions TwitchDownloaderCore/Tools/FfmpegMetadata.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TwitchDownloaderCore.TwitchObjects.Gql;
Expand Down Expand Up @@ -36,7 +37,7 @@ private static async Task SerializeGlobalMetadata(StreamWriter sw, string stream

private static async Task SerializeChapters(StreamWriter sw, List<VideoMomentEdge> videoMomentEdges, double startOffsetSeconds)
{
// Note: Ffmpeg automatically handles out of range chapters for us
// Note: FFmpeg automatically handles out of range chapters for us
var startOffsetMillis = (int)(startOffsetSeconds * 1000);
foreach (var momentEdge in videoMomentEdges)
{
Expand Down Expand Up @@ -64,11 +65,17 @@ private static string SanitizeKeyValue(string str)
return str;
}

return str
if (str.AsSpan().IndexOfAny(@"=;#\") == -1)
{
return str;
}

return new StringBuilder(str)
.Replace("=", @"\=")
.Replace(";", @"\;")
.Replace("#", @"\#")
.Replace(@"\", @"\\");
.Replace(@"\", @"\\")
.ToString();
}
}
}
2 changes: 2 additions & 0 deletions TwitchDownloaderCore/TwitchObjects/ChatRoot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,8 @@ public class Video
public double start { get; set; }
public double end { get; set; }
public double length { get; set; } = -1;
public int viewCount { get; set; }
public string game { get; set; }
public List<VideoChapter> chapters { get; set; } = new();

#region DeprecatedProperties
Expand Down
2 changes: 1 addition & 1 deletion TwitchDownloaderCore/TwitchObjects/ChatRootInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class ChatRootVersion
public int Minor { get; set; } = 0;
public int Patch { get; set; } = 0;

public static ChatRootVersion CurrentVersion { get; } = new(1, 3, 0);
public static ChatRootVersion CurrentVersion { get; } = new(1, 3, 1);

// Constructors
/// <summary>
Expand Down
10 changes: 8 additions & 2 deletions TwitchDownloaderCore/TwitchObjects/Gql/GqlClipResponse.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace TwitchDownloaderCore.TwitchObjects.Gql
{
Expand All @@ -15,6 +13,12 @@ public class ClipVideo
public string id { get; set; }
}

public class ClipGame
{
public string id { get; set; }
public string displayName { get; set; }
}

public class Clip
{
public string title { get; set; }
Expand All @@ -24,6 +28,8 @@ public class Clip
public ClipBroadcaster broadcaster { get; set; }
public int? videoOffsetSeconds { get; set; }
public ClipVideo video { get; set; }
public int viewCount { get; set; }
public ClipGame game { get; set; }
}

public class ClipData
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace TwitchDownloaderCore.TwitchObjects.Gql
{
public class ClipNodeGame
{
public string id { get; set; }
public string displayName { get; set; }
}

public class ClipNode
{
public string id { get; set; }
Expand All @@ -13,6 +18,7 @@ public class ClipNode
public int durationSeconds { get; set; }
public string thumbnailURL { get; set; }
public int viewCount { get; set; }
public ClipNodeGame game { get; set; }
}

public class Edge
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class GameChangeMomentDetails

public class VideoMoment
{
public VideoMomentConnection moments { get; set; } // seemingly always blank. Probably needs Oauth in the request to be populated
public VideoMomentConnection moments { get; set; } // seemingly always blank. Oauth does not seem to make a difference
public string id { get; set; }
public int durationMilliseconds { get; set; }
public int positionMilliseconds { get; set; }
Expand Down
8 changes: 8 additions & 0 deletions TwitchDownloaderCore/TwitchObjects/Gql/GqlVideoResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,21 @@ public class VideoOwner
public string displayName { get; set; }
}

public class VideoGame
{
public string id { get; set; }
public string displayName { get; set; }
}

public class VideoInfo
{
public string title { get; set; }
public List<string> thumbnailURLs { get; set; }
public DateTime createdAt { get; set; }
public int lengthSeconds { get; set; }
public VideoOwner owner { get; set; }
public int viewCount { get; set; }
public VideoGame game { get; set; }
}

public class VideoData
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace TwitchDownloaderCore.TwitchObjects.Gql
{
public class VideoNodeGame
{
public string id { get; set; }
public string displayName { get; set; }
}

public class VideoNode
{
public string title { get; set; }
Expand All @@ -12,6 +17,7 @@ public class VideoNode
public string previewThumbnailURL { get; set; }
public DateTime createdAt { get; set; }
public int viewCount { get; set; }
public VideoNodeGame game { get; set; }
}

public class VideoEdge
Expand Down
7 changes: 6 additions & 1 deletion TwitchDownloaderWPF/PageChatDownload.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public partial class PageChatDownload : Page
public int streamerId;
public DateTime currentVideoTime;
public TimeSpan vodLength;
public int viewCount;
public string game;
private CancellationTokenSource _cancellationTokenSource;

public PageChatDownload()
Expand Down Expand Up @@ -136,6 +138,8 @@ private async Task GetVideoInfo()
textCreatedAt.Text = Settings.Default.UTCVideoTime ? videoTime.ToString(CultureInfo.CurrentCulture) : videoTime.ToLocalTime().ToString(CultureInfo.CurrentCulture);
currentVideoTime = Settings.Default.UTCVideoTime ? videoTime : videoTime.ToLocalTime();
streamerId = int.Parse(videoInfo.data.video.owner.id);
viewCount = videoInfo.data.video.viewCount;
game = videoInfo.data.video.game?.displayName ?? "Unknown";
var urlTimeCodeMatch = Regex.Match(textUrl.Text, @"(?<=\?t=)\d+h\d+m\d+s");
if (urlTimeCodeMatch.Success)
{
Expand Down Expand Up @@ -469,7 +473,8 @@ private async void SplitBtnDownload_Click(object sender, RoutedEventArgs e)

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);
checkCropEnd.IsChecked == true ? new TimeSpan((int)numEndHour.Value, (int)numEndMinute.Value, (int)numEndSecond.Value) : vodLength,
viewCount.ToString(), game);

if (saveFileDialog.ShowDialog() != true)
{
Expand Down
13 changes: 11 additions & 2 deletions TwitchDownloaderWPF/PageChatUpdate.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public partial class PageChatUpdate : Page
public string VideoId;
public DateTime VideoCreatedAt;
public TimeSpan VideoLength;
public int ViewCount;
public string Game;
private CancellationTokenSource _cancellationTokenSource;

public PageChatUpdate()
Expand Down Expand Up @@ -62,7 +64,7 @@ private async void btnBrowse_Click(object sender, RoutedEventArgs e)
ChatJsonInfo.comments.RemoveRange(1, ChatJsonInfo.comments.Count - 2);
GC.Collect();

var videoCreatedAt = ChatJsonInfo.video.created_at == DateTime.MinValue
var videoCreatedAt = ChatJsonInfo.video.created_at == default
? ChatJsonInfo.comments[0].created_at - TimeSpan.FromSeconds(ChatJsonInfo.comments[0].content_offset_seconds)
: ChatJsonInfo.video.created_at;
textCreatedAt.Text = Settings.Default.UTCVideoTime ? videoCreatedAt.ToString(CultureInfo.CurrentCulture) : videoCreatedAt.ToLocalTime().ToString(CultureInfo.CurrentCulture);
Expand All @@ -87,6 +89,8 @@ private async void btnBrowse_Click(object sender, RoutedEventArgs e)
: Translations.Strings.Unknown;

VideoId = ChatJsonInfo.video.id ?? ChatJsonInfo.comments.FirstOrDefault()?.content_id ?? "-1";
ViewCount = ChatJsonInfo.video.viewCount;
Game = ChatJsonInfo.video.game ?? ChatJsonInfo.video.chapters.FirstOrDefault()?.gameDisplayName ?? "Unknown";

if (VideoId.All(char.IsDigit))
{
Expand All @@ -108,6 +112,8 @@ private async void btnBrowse_Click(object sender, RoutedEventArgs e)
labelLength.Text = VideoLength.ToString("c");
numStartHour.Maximum = (int)VideoLength.TotalHours;
numEndHour.Maximum = (int)VideoLength.TotalHours;
ViewCount = videoInfo.data.video.viewCount;
Game = videoInfo.data.video.game?.displayName;

try
{
Expand Down Expand Up @@ -146,6 +152,8 @@ private async void btnBrowse_Click(object sender, RoutedEventArgs e)
{
VideoLength = TimeSpan.FromSeconds(videoInfo.data.clip.durationSeconds);
labelLength.Text = VideoLength.ToString("c");
ViewCount = videoInfo.data.clip.viewCount;
Game = videoInfo.data.clip.game?.displayName;

try
{
Expand Down Expand Up @@ -471,7 +479,8 @@ private async void SplitBtnUpdate_Click(object sender, RoutedEventArgs e)
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);
checkEnd.IsChecked == true ? new TimeSpan((int)numEndHour.Value, (int)numEndMinute.Value, (int)numEndSecond.Value) : VideoLength,
ViewCount.ToString(), Game);

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

public PageClipDownload()
Expand Down Expand Up @@ -79,6 +81,8 @@ private async Task GetClipInfo()
currentVideoTime = Settings.Default.UTCVideoTime ? clipCreatedAt : clipCreatedAt.ToLocalTime();
textTitle.Text = clipData.data.clip.title;
labelLength.Text = clipLength.ToString("c");
viewCount = taskClipInfo.Result.data.clip.viewCount;
game = taskClipInfo.Result.data.clip.game?.displayName ?? "Unknown";

foreach (var quality in taskLinks.Result[0].data.clip.videoQualities)
{
Expand Down Expand Up @@ -180,7 +184,7 @@ private async void SplitBtnDownload_Click(object sender, RoutedEventArgs e)
SaveFileDialog saveFileDialog = new SaveFileDialog
{
Filter = "MP4 Files | *.mp4",
FileName = FilenameService.GetFilename(Settings.Default.TemplateClip, textTitle.Text, clipId, currentVideoTime, textStreamer.Text, TimeSpan.Zero, clipLength)
FileName = FilenameService.GetFilename(Settings.Default.TemplateClip, textTitle.Text, clipId, currentVideoTime, textStreamer.Text, TimeSpan.Zero, clipLength, viewCount.ToString(), game)
};
if (saveFileDialog.ShowDialog() != true)
{
Expand Down
10 changes: 8 additions & 2 deletions TwitchDownloaderWPF/PageVodDownload.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public partial class PageVodDownload : Page
public int currentVideoId;
public DateTime currentVideoTime;
public TimeSpan vodLength;
public int viewCount;
public string game;
private CancellationTokenSource _cancellationTokenSource;

public PageVodDownload()
Expand Down Expand Up @@ -170,6 +172,8 @@ private async Task GetVideoInfo()
numEndMinute.Value = vodLength.Minutes;
numEndSecond.Value = vodLength.Seconds;
labelLength.Text = vodLength.ToString("c");
viewCount = taskVideoInfo.Result.data.video.viewCount;
game = taskVideoInfo.Result.data.video.game?.displayName ?? "Unknown";

UpdateVideoSizeEstimates();

Expand Down Expand Up @@ -209,7 +213,8 @@ public VideoDownloadOptions GetOptions(string filename, string folder)
: -1,
Filename = filename ?? Path.Combine(folder, FilenameService.GetFilename(Settings.Default.TemplateVod, textTitle.Text, currentVideoId.ToString(), currentVideoTime, textStreamer.Text,
checkStart.IsChecked == true ? new TimeSpan((int)numStartHour.Value, (int)numStartMinute.Value, (int)numStartSecond.Value) : TimeSpan.Zero,
checkEnd.IsChecked == true ? new TimeSpan((int)numEndHour.Value, (int)numEndMinute.Value, (int)numEndSecond.Value) : vodLength) + ".mp4"),
checkEnd.IsChecked == true ? new TimeSpan((int)numEndHour.Value, (int)numEndMinute.Value, (int)numEndSecond.Value) : vodLength,
viewCount.ToString(), game) + ".mp4"),
Oauth = TextOauth.Text,
Quality = GetQualityWithoutSize(comboQuality.Text).ToString(),
Id = currentVideoId,
Expand Down Expand Up @@ -407,7 +412,8 @@ private async void SplitBtnDownloader_Click(object sender, RoutedEventArgs e)
Filter = "MP4 Files | *.mp4",
FileName = FilenameService.GetFilename(Settings.Default.TemplateVod, textTitle.Text, currentVideoId.ToString(), currentVideoTime, textStreamer.Text,
checkStart.IsChecked == true ? new TimeSpan((int)numStartHour.Value, (int)numStartMinute.Value, (int)numStartSecond.Value) : TimeSpan.Zero,
checkEnd.IsChecked == true ? new TimeSpan((int)numEndHour.Value, (int)numEndMinute.Value, (int)numEndSecond.Value) : vodLength)
checkEnd.IsChecked == true ? new TimeSpan((int)numEndHour.Value, (int)numEndMinute.Value, (int)numEndSecond.Value) : vodLength,
viewCount.ToString(), game)
};
if (saveFileDialog.ShowDialog() == false)
{
Expand Down
Loading

0 comments on commit 5b3ea38

Please sign in to comment.