Restructured the project structure back to the way it was, there's no reasonable way to split the modules

This commit is contained in:
Kwoth
2024-04-26 22:26:24 +00:00
parent 6c9c8bf63e
commit e0819f760c
768 changed files with 192 additions and 1047 deletions

View File

@@ -0,0 +1,6 @@
namespace NadekoBot.Modules.Searches.Youtube;
public interface IYoutubeSearchService
{
Task<VideoInfo?> SearchAsync(string query);
}

View File

@@ -0,0 +1,9 @@
using System.Text.Json.Serialization;
namespace NadekoBot.Modules.Searches;
public sealed class InvidiousSearchResponse
{
[JsonPropertyName("videoId")]
public string VideoId { get; set; } = null!;
}

View File

@@ -0,0 +1,46 @@
using NadekoBot.Modules.Searches.Youtube;
using System.Net.Http.Json;
namespace NadekoBot.Modules.Searches;
public sealed class InvidiousYtSearchService : IYoutubeSearchService, INService
{
private readonly IHttpClientFactory _http;
private readonly SearchesConfigService _scs;
private readonly NadekoRandom _rng;
public InvidiousYtSearchService(
IHttpClientFactory http,
SearchesConfigService scs)
{
_http = http;
_scs = scs;
_rng = new();
}
public async Task<VideoInfo?> SearchAsync(string query)
{
ArgumentNullException.ThrowIfNull(query);
var instances = _scs.Data.InvidiousInstances;
if (instances is null or { Count: 0 })
{
Log.Warning("Attempted to use Invidious as the .youtube provider but there are no 'invidiousInstances' "
+ "specified in `data/searches.yml`");
return null;
}
var instance = instances[_rng.Next(0, instances.Count)];
using var http = _http.CreateClient();
var res = await http.GetFromJsonAsync<List<InvidiousSearchResponse>>(
$"{instance}/api/v1/search"
+ $"?q={query}"
+ $"&type=video");
if (res is null or {Count: 0})
return null;
return new VideoInfo(res[0].VideoId);
}
}

View File

@@ -0,0 +1,9 @@
namespace NadekoBot.Modules.Searches.Youtube;
public readonly struct VideoInfo
{
public VideoInfo(string videoId)
=> Url = $"https://youtube.com/watch?v={videoId}";
public string Url { get; init; }
}

View File

@@ -0,0 +1,26 @@
namespace NadekoBot.Modules.Searches.Youtube;
public sealed class YoutubeDataApiSearchService : IYoutubeSearchService, INService
{
private readonly IGoogleApiService _gapi;
public YoutubeDataApiSearchService(IGoogleApiService gapi)
{
_gapi = gapi;
}
public async Task<VideoInfo?> SearchAsync(string query)
{
ArgumentNullException.ThrowIfNull(query);
var results = await _gapi.GetVideoLinksByKeywordAsync(query);
var first = results.FirstOrDefault();
if (first is null)
return null;
return new()
{
Url = first
};
}
}

View File

@@ -0,0 +1,7 @@
namespace NadekoBot.Modules.Searches.Youtube;
public sealed class YtdlYoutubeSearchService : YoutubedlxServiceBase, INService
{
public override async Task<VideoInfo?> SearchAsync(string query)
=> await InternalGetInfoAsync(query, false);
}

View File

@@ -0,0 +1,7 @@
namespace NadekoBot.Modules.Searches.Youtube;
public sealed class YtdlpYoutubeSearchService : YoutubedlxServiceBase, INService
{
public override async Task<VideoInfo?> SearchAsync(string query)
=> await InternalGetInfoAsync(query, true);
}

View File

@@ -0,0 +1,34 @@
namespace NadekoBot.Modules.Searches.Youtube;
public abstract class YoutubedlxServiceBase : IYoutubeSearchService
{
private YtdlOperation CreateYtdlOp(bool isYtDlp)
=> new YtdlOperation("-4 "
+ "--geo-bypass "
+ "--encoding UTF8 "
+ "--get-id "
+ "--no-check-certificate "
+ "--default-search "
+ "\"ytsearch:\" -- \"{0}\"",
isYtDlp: isYtDlp);
protected async Task<VideoInfo?> InternalGetInfoAsync(string query, bool isYtDlp)
{
var op = CreateYtdlOp(isYtDlp);
var data = await op.GetDataAsync(query);
var items = data?.Split('\n');
if (items is null or { Length: 0 })
return null;
var id = items.FirstOrDefault(x => x.Length is > 5 and < 15);
if (id is null)
return null;
return new VideoInfo()
{
Url = $"https://youtube.com/watch?v={id}"
};
}
public abstract Task<VideoInfo?> SearchAsync(string query);
}