forked from EllieBotDevs/elliebot
108 lines
No EOL
3.7 KiB
C#
108 lines
No EOL
3.7 KiB
C#
using EllieBot.Modules.Searches;
|
|
using System.Net.Http.Json;
|
|
|
|
namespace EllieBot.Modules.Music;
|
|
|
|
public sealed class InvidiousYoutubeResolver : IYoutubeResolver
|
|
{
|
|
private readonly IHttpClientFactory _httpFactory;
|
|
private readonly SearchesConfigService _sc;
|
|
private readonly EllieRandom _rng;
|
|
|
|
private string InvidiousApiUrl
|
|
=> _sc.Data.InvidiousInstances[_rng.Next(0, _sc.Data.InvidiousInstances.Count)];
|
|
|
|
public InvidiousYoutubeResolver(IHttpClientFactory httpFactory, SearchesConfigService sc)
|
|
{
|
|
_rng = new EllieRandom();
|
|
_httpFactory = httpFactory;
|
|
_sc = sc;
|
|
}
|
|
|
|
public async Task<ITrackInfo?> ResolveByQueryAsync(string query)
|
|
{
|
|
using var http = _httpFactory.CreateClient();
|
|
|
|
var items = await http.GetFromJsonAsync<List<InvidiousSearchResponse>>(
|
|
$"{InvidiousApiUrl}/api/v1/search"
|
|
+ $"?q={query}"
|
|
+ $"&type=video");
|
|
|
|
if (items is null || items.Count == 0)
|
|
return null;
|
|
|
|
|
|
var res = items.First();
|
|
|
|
return new InvTrackInfo()
|
|
{
|
|
Id = res.VideoId,
|
|
Title = res.Title,
|
|
Url = $"https://youtube.com/watch?v={res.VideoId}",
|
|
Thumbnail = res.Thumbnails?.Select(x => x.Url).FirstOrDefault() ?? string.Empty,
|
|
Duration = TimeSpan.FromSeconds(res.LengthSeconds),
|
|
Platform = MusicPlatform.Youtube,
|
|
StreamUrl = null,
|
|
};
|
|
}
|
|
|
|
public async Task<ITrackInfo?> ResolveByIdAsync(string id)
|
|
=> await InternalResolveByIdAsync(id);
|
|
|
|
private async Task<InvTrackInfo?> InternalResolveByIdAsync(string id)
|
|
{
|
|
using var http = _httpFactory.CreateClient();
|
|
|
|
var res = await http.GetFromJsonAsync<InvidiousVideoResponse>(
|
|
$"{InvidiousApiUrl}/api/v1/videos/{id}");
|
|
|
|
if (res is null)
|
|
return null;
|
|
|
|
return new InvTrackInfo()
|
|
{
|
|
Id = res.VideoId,
|
|
Title = res.Title,
|
|
Url = $"https://youtube.com/watch?v={res.VideoId}",
|
|
Thumbnail = res.Thumbnails?.Select(x => x.Url).FirstOrDefault() ?? string.Empty,
|
|
Duration = TimeSpan.FromSeconds(res.LengthSeconds),
|
|
Platform = MusicPlatform.Youtube,
|
|
StreamUrl = res.AdaptiveFormats.FirstOrDefault(x => x.AudioQuality == "AUDIO_QUALITY_HIGH")?.Url
|
|
?? res.AdaptiveFormats.FirstOrDefault(x => x.AudioQuality == "AUDIO_QUALITY_MEDIUM")?.Url
|
|
?? res.AdaptiveFormats.FirstOrDefault(x => x.AudioQuality == "AUDIO_QUALITY_LOW")?.Url
|
|
};
|
|
}
|
|
|
|
public async IAsyncEnumerable<ITrackInfo> ResolveTracksFromPlaylistAsync(string query)
|
|
{
|
|
using var http = _httpFactory.CreateClient();
|
|
var res = await http.GetFromJsonAsync<InvidiousPlaylistResponse>(
|
|
$"{InvidiousApiUrl}/api/v1/search?type=video&q={query}");
|
|
|
|
if (res is null)
|
|
yield break;
|
|
|
|
foreach (var video in res.Videos)
|
|
{
|
|
yield return new InvTrackInfo()
|
|
{
|
|
Id = video.VideoId,
|
|
Title = video.Title,
|
|
Url = $"https://youtube.com/watch?v={video.VideoId}",
|
|
Thumbnail = video.Thumbnails?.Select(x => x.Url).FirstOrDefault() ?? string.Empty,
|
|
Duration = TimeSpan.FromSeconds(video.LengthSeconds),
|
|
Platform = MusicPlatform.Youtube,
|
|
StreamUrl = null
|
|
};
|
|
}
|
|
}
|
|
|
|
public Task<ITrackInfo?> ResolveByQueryAsync(string query, bool tryExtractingId)
|
|
=> ResolveByQueryAsync(query);
|
|
|
|
public async Task<string?> GetStreamUrl(string videoId)
|
|
{
|
|
var video = await InternalResolveByIdAsync(videoId);
|
|
return video?.StreamUrl;
|
|
}
|
|
} |