Files
VDownload/VDownload.Core/Sources/Twitch/Clip.cs

159 lines
6.3 KiB
C#
Raw Normal View History

using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using VDownload.Core.Enums;
using VDownload.Core.Exceptions;
using VDownload.Core.Interfaces;
2022-03-07 14:59:11 +01:00
using VDownload.Core.Services.Sources.Twitch.Helpers;
using VDownload.Core.Structs;
using Windows.Storage;
namespace VDownload.Core.Services.Sources.Twitch
{
2022-05-05 15:06:10 +02:00
[Serializable]
public class Clip : IVideo
{
#region CONSTRUCTORS
public Clip(string id)
{
2022-05-05 15:06:10 +02:00
Source = VideoSource.TwitchClip;
ID = id;
Url = new Uri($"https://clips.twitch.tv/{ID}");
}
#endregion
#region PROPERTIES
2022-05-05 15:06:10 +02:00
public VideoSource Source { get; private set; }
public string ID { get; private set; }
2022-05-05 15:06:10 +02:00
public Uri Url { get; private set; }
public string Title { get; private set; }
public string Author { get; private set; }
public DateTime Date { get; private set; }
public TimeSpan Duration { get; private set; }
public long Views { get; private set; }
public Uri Thumbnail { get; private set; }
2022-03-07 14:59:11 +01:00
public BaseStream[] BaseStreams { get; private set; }
#endregion
#region PUBLIC METHODS
2022-02-26 14:32:34 +01:00
public async Task GetMetadataAsync(CancellationToken cancellationToken = default)
{
2022-03-02 22:13:28 +01:00
cancellationToken.ThrowIfCancellationRequested();
2022-03-07 14:59:11 +01:00
JToken response = null;
using (WebClient client = await Client.Helix())
{
client.QueryString.Add("id", ID);
response = JObject.Parse(await client.DownloadStringTaskAsync("https://api.twitch.tv/helix/clips")).GetValue("data");
if (((JArray)response).Count > 0) response = response[0];
else throw new MediaNotFoundException($"Twitch Clip (ID: {ID}) was not found");
2022-03-07 14:59:11 +01:00
}
2022-02-26 14:32:34 +01:00
Title = (string)response["title"];
Author = (string)response["broadcaster_name"];
Date = Convert.ToDateTime(response["created_at"]);
Duration = TimeSpan.FromSeconds((double)response["duration"]);
Views = (long)response["view_count"];
Thumbnail = new Uri((string)response["thumbnail_url"]);
}
2022-02-26 14:32:34 +01:00
public async Task GetStreamsAsync(CancellationToken cancellationToken = default)
{
2022-03-02 22:13:28 +01:00
cancellationToken.ThrowIfCancellationRequested();
2022-03-07 14:59:11 +01:00
JToken[] response;
using (WebClient client = Client.GQL())
{
response = JArray.Parse(await client.UploadStringTaskAsync("https://gql.twitch.tv/gql", "[{\"operationName\":\"VideoAccessToken_Clip\",\"variables\":{\"slug\":\"" + ID + "\"},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"36b89d2507fce29e5ca551df756d27c1cfe079e2609642b4390aa4c35796eb11\"}}}]"))[0]["data"]["clip"]["videoQualities"].ToArray();
}
List<BaseStream> streams = new List<BaseStream>();
foreach (JToken streamData in response)
{
2022-03-07 14:59:11 +01:00
BaseStream stream = new BaseStream()
{
2022-03-07 14:59:11 +01:00
Url = new Uri((string)streamData["sourceURL"]),
Height = int.Parse((string)streamData["quality"]),
FrameRate = (int)streamData["frameRate"],
};
streams.Add(stream);
}
2022-03-02 22:13:28 +01:00
BaseStreams = streams.ToArray();
}
public async Task<StorageFile> DownloadAndTranscodeAsync(StorageFolder downloadingFolder, BaseStream baseStream, MediaFileExtension extension, MediaType mediaType, TrimData trim, CancellationToken cancellationToken = default)
{
2022-03-07 14:59:11 +01:00
cancellationToken.ThrowIfCancellationRequested();
DownloadingProgressChanged(this, new EventArgs.ProgressChangedEventArgs(0));
2022-03-07 14:59:11 +01:00
JToken videoAccessToken = null;
using (WebClient client = Client.GQL())
{
videoAccessToken = JArray.Parse(await client.UploadStringTaskAsync("https://gql.twitch.tv/gql", "[{\"operationName\":\"VideoAccessToken_Clip\",\"variables\":{\"slug\":\"" + ID + "\"},\"extensions\":{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"36b89d2507fce29e5ca551df756d27c1cfe079e2609642b4390aa4c35796eb11\"}}}]"))[0]["data"]["clip"]["playbackAccessToken"];
}
2022-03-02 22:13:28 +01:00
// Download
2022-03-02 22:13:28 +01:00
cancellationToken.ThrowIfCancellationRequested();
StorageFile rawFile = await downloadingFolder.CreateFileAsync("raw.mp4");
2022-03-07 14:59:11 +01:00
using (WebClient client = new WebClient())
{
2022-03-07 14:59:11 +01:00
client.DownloadProgressChanged += (s, a) => { DownloadingProgressChanged(this, new EventArgs.ProgressChangedEventArgs(a.ProgressPercentage)); };
client.QueryString.Add("sig", (string)videoAccessToken["signature"]);
client.QueryString.Add("token", HttpUtility.UrlEncode((string)videoAccessToken["value"]));
2022-03-02 22:13:28 +01:00
cancellationToken.ThrowIfCancellationRequested();
using (cancellationToken.Register(client.CancelAsync))
{
2022-03-02 22:13:28 +01:00
await client.DownloadFileTaskAsync(baseStream.Url, rawFile.Path);
}
}
2022-03-07 14:59:11 +01:00
DownloadingProgressChanged(this, new EventArgs.ProgressChangedEventArgs(100, true));
// Processing
StorageFile outputFile = rawFile;
if (extension != MediaFileExtension.MP4 || mediaType != MediaType.AudioVideo || trim.Start != null || trim.End != null)
{
2022-03-02 22:13:28 +01:00
cancellationToken.ThrowIfCancellationRequested();
outputFile = await downloadingFolder.CreateFileAsync($"transcoded.{extension.ToString().ToLower()}");
2022-03-07 14:59:11 +01:00
MediaProcessor mediaProcessor = new MediaProcessor();
mediaProcessor.ProgressChanged += ProcessingProgressChanged;
await mediaProcessor.Run(rawFile, extension, mediaType, outputFile, trim, cancellationToken);
}
return outputFile;
}
#endregion
#region EVENTS
2022-03-07 14:59:11 +01:00
public event EventHandler<EventArgs.ProgressChangedEventArgs> DownloadingProgressChanged;
public event EventHandler<EventArgs.ProgressChangedEventArgs> ProcessingProgressChanged;
#endregion
}
}