changes
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VDownload.Sources.Twitch.Api.Helix.GetUsers.Response
|
||||
{
|
||||
public class Data
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
[JsonProperty("login")]
|
||||
public string Login { get; set; }
|
||||
|
||||
[JsonProperty("display_name")]
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
[JsonProperty("broadcaster_type")]
|
||||
public string BroadcasterType { get; set; }
|
||||
|
||||
[JsonProperty("description")]
|
||||
public string Description { get; set; }
|
||||
|
||||
[JsonProperty("profile_image_url")]
|
||||
public string ProfileImageUrl { get; set; }
|
||||
|
||||
[JsonProperty("offline_image_url")]
|
||||
public string OfflineImageUrl { get; set; }
|
||||
|
||||
[JsonProperty("view_count")]
|
||||
public int ViewCount { get; set; }
|
||||
|
||||
[JsonProperty("email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[JsonProperty("created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VDownload.Sources.Twitch.Api.Helix.GetUsers.Response
|
||||
{
|
||||
public class GetUsersResponse
|
||||
{
|
||||
[JsonProperty("data")]
|
||||
public List<Data> Data { get; } = new List<Data>();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using VDownload.Services.Data.Configuration;
|
||||
using VDownload.Services.Utility.HttpClient;
|
||||
using VDownload.Sources.Twitch.Api.GQL.GetVideoToken.Response;
|
||||
using VDownload.Sources.Twitch.Api.Helix.GetUsers.Response;
|
||||
using VDownload.Sources.Twitch.Api.Helix.GetVideos.Response;
|
||||
using VDownload.Sources.Twitch.Search.Models.GetVideoToken.Request;
|
||||
|
||||
@@ -10,7 +11,9 @@ namespace VDownload.Sources.Twitch.Api
|
||||
{
|
||||
Task<string> AuthValidate(byte[] token);
|
||||
Task<GetVideoTokenResponse> GQLGetVideoToken(string id);
|
||||
Task<GetVideosResponse> HelixGetVideos(string id, byte[] token);
|
||||
Task<GetUsersResponse> HelixGetUser(string login, byte[] token);
|
||||
Task<GetVideosResponse> HelixGetVideo(string id, byte[] token);
|
||||
Task<GetVideosResponse> HelixGetUserVideos(string user_id, byte[] token, int count, string? cursor = null);
|
||||
Task<string> UsherGetVideoPlaylist(string id, string videoToken, string videoTokenSignature);
|
||||
}
|
||||
|
||||
@@ -49,12 +52,47 @@ namespace VDownload.Sources.Twitch.Api
|
||||
return await _httpClientService.SendRequestAsync(request);
|
||||
}
|
||||
|
||||
public async Task<GetVideosResponse> HelixGetVideos(string id, byte[] token)
|
||||
public async Task<GetUsersResponse> HelixGetUser(string login, byte[] token)
|
||||
{
|
||||
Token tokenData = new Token(_configurationService.Twitch.Api.Helix.TokenSchema, token);
|
||||
|
||||
HttpRequest request = new HttpRequest(HttpMethodType.GET, _configurationService.Twitch.Api.Helix.Endpoints.GetUsers);
|
||||
|
||||
request.Query.Add("login", login);
|
||||
|
||||
request.Headers.Add("Authorization", $"{tokenData}");
|
||||
request.Headers.Add("Client-Id", _configurationService.Twitch.Api.Helix.ClientId);
|
||||
|
||||
return await _httpClientService.SendRequestAsync<GetUsersResponse>(request);
|
||||
}
|
||||
|
||||
public async Task<GetVideosResponse> HelixGetVideo(string id, byte[] token)
|
||||
{
|
||||
Token tokenData = new Token(_configurationService.Twitch.Api.Helix.TokenSchema, token);
|
||||
|
||||
HttpRequest request = new HttpRequest(HttpMethodType.GET, _configurationService.Twitch.Api.Helix.Endpoints.GetVideos);
|
||||
|
||||
request.Query.Add("id", id);
|
||||
|
||||
request.Headers.Add("Authorization", tokenData.ToString());
|
||||
request.Headers.Add("Client-Id", _configurationService.Twitch.Api.Helix.ClientId);
|
||||
|
||||
return await _httpClientService.SendRequestAsync<GetVideosResponse>(request);
|
||||
}
|
||||
|
||||
public async Task<GetVideosResponse> HelixGetUserVideos(string user_id, byte[] token, int count, string? cursor = null)
|
||||
{
|
||||
Token tokenData = new Token(_configurationService.Twitch.Api.Helix.TokenSchema, token);
|
||||
|
||||
HttpRequest request = new HttpRequest(HttpMethodType.GET, _configurationService.Twitch.Api.Helix.Endpoints.GetVideos);
|
||||
|
||||
request.Query.Add("user_id", user_id);
|
||||
request.Query.Add("first", count);
|
||||
if (cursor is not null)
|
||||
{
|
||||
request.Query.Add("after", cursor);
|
||||
}
|
||||
|
||||
request.Headers.Add("Authorization", tokenData.ToString());
|
||||
request.Headers.Add("Client-Id", _configurationService.Twitch.Api.Helix.ClientId);
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VDownload.Sources.Twitch.Configuration.Models
|
||||
{
|
||||
public class Channel
|
||||
{
|
||||
[ConfigurationKeyName("regexes")]
|
||||
public List<string> Regexes { get; } = new List<string>();
|
||||
|
||||
[ConfigurationKeyName("url")]
|
||||
public string Url { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VDownload.Sources.Twitch.Configuration.Models
|
||||
{
|
||||
public class Clip
|
||||
{
|
||||
[ConfigurationKeyName("regexes")]
|
||||
public List<string> Regexes { get; } = new List<string>();
|
||||
}
|
||||
}
|
||||
@@ -6,5 +6,8 @@ namespace VDownload.Sources.Twitch.Configuration.Models
|
||||
{
|
||||
[ConfigurationKeyName("get_videos")]
|
||||
public string GetVideos { get; set; }
|
||||
|
||||
[ConfigurationKeyName("get_users")]
|
||||
public string GetUsers { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,12 @@ namespace VDownload.Sources.Twitch.Configuration.Models{
|
||||
|
||||
[ConfigurationKeyName("vod")]
|
||||
public Vod Vod { get; set; }
|
||||
|
||||
[ConfigurationKeyName("clip")]
|
||||
public Clip Clip { get; set; }
|
||||
|
||||
[ConfigurationKeyName("channel")]
|
||||
public Channel Channel { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VDownload.Sources.Twitch.Models
|
||||
{
|
||||
public class TwitchChannel : TwitchPlaylist
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
public required string Id { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -9,5 +9,13 @@ namespace VDownload.Sources.Twitch.Models
|
||||
{
|
||||
public abstract class TwitchPlaylist : Playlist
|
||||
{
|
||||
#region CONSTRUCTORS
|
||||
|
||||
protected TwitchPlaylist()
|
||||
{
|
||||
Source = Source.Twitch;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using VDownload.Services.Data.Configuration;
|
||||
using VDownload.Sources.Common;
|
||||
using VDownload.Sources.Twitch.Api;
|
||||
using VDownload.Sources.Twitch.Api.GQL.GetVideoToken.Response;
|
||||
using VDownload.Sources.Twitch.Api.Helix.GetUsers.Response;
|
||||
using VDownload.Sources.Twitch.Api.Helix.GetVideos.Response;
|
||||
using VDownload.Sources.Twitch.Authentication;
|
||||
using VDownload.Sources.Twitch.Configuration.Models;
|
||||
@@ -71,7 +72,16 @@ namespace VDownload.Sources.Twitch
|
||||
async Task<Playlist> ISourceSearchService.SearchPlaylist(string url, int maxVideoCount) => await SearchPlaylist(url, maxVideoCount);
|
||||
public async Task<TwitchPlaylist> SearchPlaylist(string url, int maxVideoCount)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
foreach (Regex regex in _configurationService.Twitch.Search.Channel.Regexes.Select(x => new Regex(x)))
|
||||
{
|
||||
Match match = regex.Match(url);
|
||||
if (match.Success)
|
||||
{
|
||||
string id = match.Groups[1].Value;
|
||||
return await GetChannel(id, maxVideoCount);
|
||||
}
|
||||
}
|
||||
throw new MediaSearchException("Invalid url");
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -82,23 +92,68 @@ namespace VDownload.Sources.Twitch
|
||||
|
||||
protected async Task<TwitchVod> GetVod(string id)
|
||||
{
|
||||
Task<IEnumerable<TwitchVodStream>> streamsTask = GetVodStreams(id);
|
||||
|
||||
byte[] token = await GetToken();
|
||||
GetVideosResponse info = await _apiService.HelixGetVideos(id, token);
|
||||
Data vodResponse = info.Data[0];
|
||||
|
||||
GetVideosResponse info = await _apiService.HelixGetVideo(id, token);
|
||||
|
||||
Api.Helix.GetVideos.Response.Data vodResponse = info.Data[0];
|
||||
|
||||
TwitchVod vod = await ParseVod(vodResponse);
|
||||
|
||||
return vod;
|
||||
}
|
||||
|
||||
protected async Task<TwitchChannel> GetChannel(string id, int count)
|
||||
{
|
||||
byte[] token = await GetToken();
|
||||
GetUsersResponse info = await _apiService.HelixGetUser(id, token);
|
||||
Api.Helix.GetUsers.Response.Data userResponse = info.Data[0];
|
||||
|
||||
TwitchChannel channel = new TwitchChannel
|
||||
{
|
||||
Id = userResponse.Id,
|
||||
Name = userResponse.DisplayName,
|
||||
Description = userResponse.Description,
|
||||
Url = new Uri(string.Format(_configurationService.Twitch.Search.Channel.Url, id)),
|
||||
};
|
||||
|
||||
List<Task<TwitchVod>> tasks = new List<Task<TwitchVod>>();
|
||||
string? cursor = null;
|
||||
List<Api.Helix.GetVideos.Response.Data> videosList;
|
||||
int videos = 0;
|
||||
do
|
||||
{
|
||||
videos = count == 0 || count > 100 ? 100 : count;
|
||||
GetVideosResponse videosResponse = await _apiService.HelixGetUserVideos(channel.Id, token, videos, cursor);
|
||||
videosList = videosResponse.Data;
|
||||
count -= videosList.Count;
|
||||
cursor = videosResponse.Pagination.Cursor;
|
||||
tasks.AddRange(videosList.Select(ParseVod));
|
||||
}
|
||||
while (videosList.Count == videos);
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
channel.AddRange(tasks.Select(x => x.Result));
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
public async Task<TwitchVod> ParseVod(Api.Helix.GetVideos.Response.Data data)
|
||||
{
|
||||
Task<IEnumerable<TwitchVodStream>> streamsTask = GetVodStreams(data.Id);
|
||||
|
||||
Thumbnail thumbnail = _configurationService.Twitch.Search.Vod.Thumbnail;
|
||||
TwitchVod vod = new TwitchVod
|
||||
{
|
||||
Title = vodResponse.Title,
|
||||
Description = vodResponse.Description,
|
||||
Author = vodResponse.UserName,
|
||||
PublishDate = vodResponse.PublishedAt,
|
||||
Duration = ParseVodDuration(vodResponse.Duration),
|
||||
Views = vodResponse.ViewCount,
|
||||
ThumbnailUrl = new Uri(vodResponse.ThumbnailUrl.Replace("%{width}", thumbnail.Width.ToString()).Replace("%{height}", thumbnail.Height.ToString())),
|
||||
Url = new Uri(vodResponse.Url),
|
||||
Title = data.Title,
|
||||
Description = data.Description,
|
||||
Author = data.UserName,
|
||||
PublishDate = data.PublishedAt,
|
||||
Duration = ParseVodDuration(data.Duration),
|
||||
Views = data.ViewCount,
|
||||
ThumbnailUrl = new Uri(data.ThumbnailUrl.Replace("%{width}", thumbnail.Width.ToString()).Replace("%{height}", thumbnail.Height.ToString())),
|
||||
Url = new Uri(data.Url),
|
||||
};
|
||||
|
||||
await streamsTask;
|
||||
|
||||
Reference in New Issue
Block a user