mirror of
https://github.com/metatube-community/jellyfin-plugin-metatube.git
synced 2026-02-03 02:25:02 +08:00
109 lines
4.0 KiB
C#
109 lines
4.0 KiB
C#
using System.Collections.Specialized;
|
|
using Jellyfin.Plugin.MetaTube.Configuration;
|
|
using Jellyfin.Plugin.MetaTube.Metadata;
|
|
|
|
namespace Jellyfin.Plugin.MetaTube.Translation;
|
|
|
|
public static class TranslationHelper
|
|
{
|
|
private const string AutoLanguageCode = "auto";
|
|
private const string JapaneseLanguageCode = "ja";
|
|
|
|
private static readonly SemaphoreSlim Semaphore = new(1);
|
|
|
|
private static PluginConfiguration Configuration => Plugin.Instance.Configuration;
|
|
|
|
private static async Task<string> TranslateAsync(string q, string from, string to,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
int millisecondsDelay;
|
|
var nv = new NameValueCollection();
|
|
switch (Configuration.TranslationEngine)
|
|
{
|
|
case TranslationEngine.Baidu:
|
|
millisecondsDelay = 1000; // Limit Baidu API request rate to 1 rps.
|
|
nv.Add(new NameValueCollection
|
|
{
|
|
{ "baidu-app-id", Configuration.BaiduAppId },
|
|
{ "baidu-app-key", Configuration.BaiduAppKey }
|
|
});
|
|
break;
|
|
case TranslationEngine.Google:
|
|
millisecondsDelay = 100; // Limit Google API request rate to 10 rps.
|
|
nv.Add(new NameValueCollection
|
|
{
|
|
{ "google-api-key", Configuration.GoogleApiKey },
|
|
{ "google-api-url", Configuration.GoogleApiUrl }
|
|
});
|
|
break;
|
|
case TranslationEngine.GoogleFree:
|
|
millisecondsDelay = 100;
|
|
nv.Add(new NameValueCollection());
|
|
break;
|
|
case TranslationEngine.DeepL:
|
|
millisecondsDelay = 100;
|
|
nv.Add(new NameValueCollection
|
|
{
|
|
{ "deepl-api-key", Configuration.DeepLApiKey },
|
|
{ "deepl-api-url", Configuration.DeepLApiUrl }
|
|
});
|
|
break;
|
|
case TranslationEngine.OpenAi:
|
|
millisecondsDelay = 1000;
|
|
nv.Add(new NameValueCollection
|
|
{
|
|
{ "openai-api-key", Configuration.OpenAiApiKey },
|
|
{ "openai-api-url", Configuration.OpenAiApiUrl },
|
|
{ "openai-model", Configuration.OpenAiModel }
|
|
});
|
|
break;
|
|
default:
|
|
throw new ArgumentException($"Invalid translation engine: {Configuration.TranslationEngine}");
|
|
}
|
|
|
|
await Semaphore.WaitAsync(cancellationToken);
|
|
|
|
try
|
|
{
|
|
async Task<string> TranslateWithDelay()
|
|
{
|
|
await Task.Delay(millisecondsDelay, cancellationToken);
|
|
return (await ApiClient
|
|
.TranslateAsync(q, from, to, Configuration.TranslationEngine.ToString(), nv, cancellationToken)
|
|
.ConfigureAwait(false)).TranslatedText;
|
|
}
|
|
|
|
return await RetryAsync(TranslateWithDelay, 5);
|
|
}
|
|
finally
|
|
{
|
|
Semaphore.Release();
|
|
}
|
|
}
|
|
|
|
public static async Task TranslateAsync(MovieInfo m, string to, CancellationToken cancellationToken)
|
|
{
|
|
if (string.Equals(to, JapaneseLanguageCode, StringComparison.OrdinalIgnoreCase))
|
|
throw new ArgumentException($"language not allowed: {to}");
|
|
|
|
if (Configuration.TranslationMode.HasFlag(TranslationMode.Title) && !string.IsNullOrWhiteSpace(m.Title))
|
|
m.Title = await TranslateAsync(m.Title, AutoLanguageCode, to, cancellationToken);
|
|
|
|
if (Configuration.TranslationMode.HasFlag(TranslationMode.Summary) && !string.IsNullOrWhiteSpace(m.Summary))
|
|
m.Summary = await TranslateAsync(m.Summary, AutoLanguageCode, to, cancellationToken);
|
|
}
|
|
|
|
private static async Task<T> RetryAsync<T>(Func<Task<T>> func, int retryCount)
|
|
{
|
|
while (true)
|
|
{
|
|
try
|
|
{
|
|
return await func();
|
|
}
|
|
catch when (--retryCount > 0)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
} |