This repository has been archived on 2024-12-22. You can view files and clone it, but cannot push or open issues or pull requests.
elliebot/src/EllieBot/Modules/Music/_common/Resolvers/InvidiousYoutubeResolver.cs
2024-09-21 01:02:47 +12:00

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;
}
}