Add Premiumize NZB support
This commit is contained in:
parent
4afee6938b
commit
d68b8b9bfe
2 changed files with 401 additions and 47 deletions
|
|
@ -0,0 +1,235 @@
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Moq;
|
||||||
|
using RdtClient.Data.Models.Internal;
|
||||||
|
using RdtClient.Service.Services;
|
||||||
|
using RdtClient.Service.Services.DebridClients;
|
||||||
|
|
||||||
|
namespace RdtClient.Service.Test.Services.TorrentClients;
|
||||||
|
|
||||||
|
[CollectionDefinition(nameof(PremiumizeSettingsCollection), DisableParallelization = true)]
|
||||||
|
public class PremiumizeSettingsCollection;
|
||||||
|
|
||||||
|
[Collection(nameof(PremiumizeSettingsCollection))]
|
||||||
|
public class PremiumizeDebridClientTest : IDisposable
|
||||||
|
{
|
||||||
|
private readonly Mock<IDownloadableFileFilter> _fileFilterMock;
|
||||||
|
private readonly Mock<IHttpClientFactory> _httpClientFactoryMock;
|
||||||
|
private readonly Mock<ILogger<PremiumizeDebridClient>> _loggerMock;
|
||||||
|
private readonly String _originalApiKey;
|
||||||
|
|
||||||
|
public PremiumizeDebridClientTest()
|
||||||
|
{
|
||||||
|
_loggerMock = new();
|
||||||
|
_httpClientFactoryMock = new();
|
||||||
|
_fileFilterMock = new();
|
||||||
|
_originalApiKey = Settings.Get.Provider.ApiKey ?? String.Empty;
|
||||||
|
|
||||||
|
Settings.Get.Provider.ApiKey = "test-api-key";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Settings.Get.Provider.ApiKey = _originalApiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddNzbLink_UsesPremiumizeNetTransferCreate_ReturnsTransferId()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var handler = new RecordingHttpMessageHandler(_ => JsonResponse("""{"status":"success","id":"transfer-id","name":"test.nzb"}"""));
|
||||||
|
var client = CreateClient(handler);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await client.AddNzbLink("http://example.com/test.nzb");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("transfer-id", result);
|
||||||
|
Assert.Equal(HttpMethod.Post, handler.Request!.Method);
|
||||||
|
Assert.Equal("https://www.premiumize.me/api/transfer/create?apikey=test-api-key", handler.Request.RequestUri!.ToString());
|
||||||
|
Assert.Null(handler.Request.Headers.Authorization);
|
||||||
|
Assert.Equal("application/x-www-form-urlencoded", handler.Request.Content!.Headers.ContentType!.MediaType);
|
||||||
|
Assert.Equal("src=http%3A%2F%2Fexample.com%2Ftest.nzb&folder_id=", handler.RequestBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddNzbFile_SubmitsMultipartTransferCreateRequest_ReturnsTransferId()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var handler = new RecordingHttpMessageHandler(_ => JsonResponse("""{"status":"success","id":"file-transfer-id","name":"test.nzb"}"""));
|
||||||
|
var client = CreateClient(handler);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await client.AddNzbFile(Encoding.UTF8.GetBytes("nzb body"), "test.nzb");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("file-transfer-id", result);
|
||||||
|
Assert.Equal(HttpMethod.Post, handler.Request!.Method);
|
||||||
|
Assert.Equal("https://www.premiumize.me/api/transfer/create", handler.Request.RequestUri!.ToString());
|
||||||
|
Assert.Equal("Bearer", handler.Request.Headers.Authorization!.Scheme);
|
||||||
|
Assert.Equal("test-api-key", handler.Request.Headers.Authorization.Parameter);
|
||||||
|
Assert.Equal("multipart/form-data", handler.Request.Content!.Headers.ContentType!.MediaType);
|
||||||
|
Assert.Contains("Content-Disposition: form-data", handler.RequestBody);
|
||||||
|
Assert.Contains("src", handler.RequestBody);
|
||||||
|
Assert.Contains("test.nzb", handler.RequestBody);
|
||||||
|
Assert.Contains("nzb body", handler.RequestBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddNzbFile_WhenNameIsMissing_UsesDefaultFilename()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var handler = new RecordingHttpMessageHandler(_ => JsonResponse("""{"status":"success","id":"file-transfer-id","name":"upload.nzb"}"""));
|
||||||
|
var client = CreateClient(handler);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await client.AddNzbFile(Encoding.UTF8.GetBytes("nzb body"), null);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Contains("upload.nzb", handler.RequestBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddNzbFile_WhenNameHasNoNzbExtension_AppendsNzbExtension()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var handler = new RecordingHttpMessageHandler(_ => JsonResponse("""{"status":"success","id":"file-transfer-id","name":"release-title.nzb"}"""));
|
||||||
|
var client = CreateClient(handler);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await client.AddNzbFile(Encoding.UTF8.GetBytes("nzb body"), "release-title");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Contains("release-title.nzb", handler.RequestBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddNzbLink_WhenSuccessResponseHasNoId_Throws()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var handler = new RecordingHttpMessageHandler(_ => JsonResponse("""{"status":"success","name":"test.nzb"}"""));
|
||||||
|
var client = CreateClient(handler);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var ex = await Assert.ThrowsAsync<Exception>(() => client.AddNzbLink("http://example.com/test.nzb"));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Contains("Unable to add NZB link", ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddNzbLink_WhenPremiumizeReturnsRateLimitError_ThrowsRateLimitException()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var handler = new RecordingHttpMessageHandler(_ => JsonResponse("""{"status":"error","code":"slow_down","message":"rate limit exceeded"}"""));
|
||||||
|
var client = CreateClient(handler);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var ex = await Assert.ThrowsAsync<RateLimitException>(() => client.AddNzbLink("http://example.com/test.nzb"));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(TimeSpan.FromMinutes(2), ex.RetryAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("You've made too many API requests too quickly.")]
|
||||||
|
[InlineData("Your fair-use points, booster points, or active-job count is exhausted.")]
|
||||||
|
[InlineData("This account's usage limit for this service has been reached.")]
|
||||||
|
[InlineData("The target service is unreachable right now. Retry after a delay.")]
|
||||||
|
public async Task AddNzbLink_WhenPremiumizeNetReturnsDocumentedRetryMessage_ThrowsRateLimitException(String message)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var handler = new RecordingHttpMessageHandler(_ => JsonResponse($$"""{"status":"error","message":"{{message}}","code":"rate_limit_reached"}"""));
|
||||||
|
var client = CreateClient(handler);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var ex = await Assert.ThrowsAsync<RateLimitException>(() => client.AddNzbLink("http://example.com/test.nzb"));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(TimeSpan.FromMinutes(2), ex.RetryAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("rate_limit_reached")]
|
||||||
|
[InlineData("account_limit_reached")]
|
||||||
|
[InlineData("service_limit_reached")]
|
||||||
|
[InlineData("service_down")]
|
||||||
|
[InlineData("semi_permanent_error")]
|
||||||
|
public async Task AddNzbFile_WhenPremiumizeReturnsDocumentedRetryCode_ThrowsRateLimitException(String code)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var handler = new RecordingHttpMessageHandler(_ => JsonResponse($$"""{"status":"error","code":"{{code}}","message":"retry later"}"""));
|
||||||
|
var client = CreateClient(handler);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var ex = await Assert.ThrowsAsync<RateLimitException>(() => client.AddNzbFile(Encoding.UTF8.GetBytes("nzb body"), "test.nzb"));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(TimeSpan.FromMinutes(2), ex.RetryAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddTorrentMagnet_UsesPremiumizeNetTransferCreate_ReturnsTransferId()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var handler = new RecordingHttpMessageHandler(_ => JsonResponse("""{"status":"success","id":"magnet-transfer-id","name":"test"}"""));
|
||||||
|
var client = CreateClient(handler);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await client.AddTorrentMagnet("magnet:?xt=urn:btih:test");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("magnet-transfer-id", result);
|
||||||
|
Assert.Equal("https://www.premiumize.me/api/transfer/create?apikey=test-api-key", handler.Request!.RequestUri!.ToString());
|
||||||
|
Assert.Equal("src=magnet%3A%3Fxt%3Durn%3Abtih%3Atest&folder_id=", handler.RequestBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddTorrentFile_UsesPremiumizeNetFileUpload_ReturnsTransferId()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var handler = new RecordingHttpMessageHandler(_ => JsonResponse("""{"status":"success","id":"torrent-transfer-id","name":"test"}"""));
|
||||||
|
var client = CreateClient(handler);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await client.AddTorrentFile(Encoding.UTF8.GetBytes("torrent body"));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("torrent-transfer-id", result);
|
||||||
|
Assert.Equal("https://www.premiumize.me/api/transfer/create?apikey=test-api-key", handler.Request!.RequestUri!.ToString());
|
||||||
|
Assert.Contains("name=file", handler.RequestBody);
|
||||||
|
Assert.Contains("filename=1.torrent", handler.RequestBody);
|
||||||
|
Assert.Contains("application/x-bittorrent", handler.RequestBody);
|
||||||
|
Assert.Contains("torrent body", handler.RequestBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PremiumizeDebridClient CreateClient(RecordingHttpMessageHandler handler)
|
||||||
|
{
|
||||||
|
_httpClientFactoryMock.Setup(m => m.CreateClient(It.IsAny<String>())).Returns(new HttpClient(handler));
|
||||||
|
|
||||||
|
return new(_loggerMock.Object, _httpClientFactoryMock.Object, _fileFilterMock.Object);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HttpResponseMessage JsonResponse(String json, HttpStatusCode statusCode = HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
return new(statusCode)
|
||||||
|
{
|
||||||
|
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RecordingHttpMessageHandler(Func<HttpRequestMessage, HttpResponseMessage> handler) : HttpMessageHandler
|
||||||
|
{
|
||||||
|
public HttpRequestMessage? Request { get; private set; }
|
||||||
|
public String? RequestBody { get; private set; }
|
||||||
|
|
||||||
|
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Request = request;
|
||||||
|
RequestBody = request.Content == null ? null : await request.Content.ReadAsStringAsync(cancellationToken);
|
||||||
|
|
||||||
|
return handler(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using PremiumizeNET;
|
using PremiumizeNET;
|
||||||
|
|
@ -13,6 +15,8 @@ namespace RdtClient.Service.Services.DebridClients;
|
||||||
|
|
||||||
public class PremiumizeDebridClient(ILogger<PremiumizeDebridClient> logger, IHttpClientFactory httpClientFactory, IDownloadableFileFilter fileFilter) : IDebridClient
|
public class PremiumizeDebridClient(ILogger<PremiumizeDebridClient> logger, IHttpClientFactory httpClientFactory, IDownloadableFileFilter fileFilter) : IDebridClient
|
||||||
{
|
{
|
||||||
|
private const String TransferCreateUrl = "https://www.premiumize.me/api/transfer/create";
|
||||||
|
|
||||||
public async Task<IList<DebridClientTorrent>> GetDownloads()
|
public async Task<IList<DebridClientTorrent>> GetDownloads()
|
||||||
{
|
{
|
||||||
var results = await GetClient().Transfers.ListAsync();
|
var results = await GetClient().Transfers.ListAsync();
|
||||||
|
|
@ -33,56 +37,22 @@ public class PremiumizeDebridClient(ILogger<PremiumizeDebridClient> logger, IHtt
|
||||||
|
|
||||||
public async Task<String> AddTorrentMagnet(String magnetLink)
|
public async Task<String> AddTorrentMagnet(String magnetLink)
|
||||||
{
|
{
|
||||||
try
|
return await CreatePremiumizeNetTransfer(() => GetClient().Transfers.CreateAsync(magnetLink, ""), "magnet link");
|
||||||
{
|
|
||||||
var result = await GetClient().Transfers.CreateAsync(magnetLink, "");
|
|
||||||
|
|
||||||
if (result?.Id == null)
|
|
||||||
{
|
|
||||||
throw new("Unable to add magnet link");
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultId = result.Id ?? throw new($"Invalid responseID {result.Id}");
|
|
||||||
|
|
||||||
return resultId;
|
|
||||||
}
|
|
||||||
catch (Exception ex) when (ex.Message.Contains("slow_down", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
ex.Message.Contains("rate limit exceeded", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
throw new RateLimitException(ex.Message, TimeSpan.FromMinutes(2));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<String> AddTorrentFile(Byte[] bytes)
|
public async Task<String> AddTorrentFile(Byte[] bytes)
|
||||||
{
|
{
|
||||||
try
|
return await CreatePremiumizeNetTransfer(() => GetClient().Transfers.CreateAsync(bytes, ""), "torrent file");
|
||||||
{
|
|
||||||
var result = await GetClient().Transfers.CreateAsync(bytes, "");
|
|
||||||
|
|
||||||
if (result?.Id == null)
|
|
||||||
{
|
|
||||||
throw new("Unable to add torrent file");
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultId = result.Id ?? throw new($"Invalid responseID {result.Id}");
|
|
||||||
|
|
||||||
return resultId;
|
|
||||||
}
|
|
||||||
catch (Exception ex) when (ex.Message.Contains("slow_down", StringComparison.OrdinalIgnoreCase) ||
|
|
||||||
ex.Message.Contains("rate limit exceeded", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
throw new RateLimitException(ex.Message, TimeSpan.FromMinutes(2));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<String> AddNzbLink(String nzbLink)
|
public async Task<String> AddNzbLink(String nzbLink)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
return await CreatePremiumizeNetTransfer(() => GetClient().Transfers.CreateAsync(nzbLink, ""), "NZB link");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<String> AddNzbFile(Byte[] bytes, String? name)
|
public async Task<String> AddNzbFile(Byte[] bytes, String? name)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
return await CreateTransferFromNzbFile(bytes, GetNzbFileName(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<IList<DebridClientAvailableFile>> GetAvailableFiles(String hash)
|
public Task<IList<DebridClientAvailableFile>> GetAvailableFiles(String hash)
|
||||||
|
|
@ -225,13 +195,7 @@ public class PremiumizeDebridClient(ILogger<PremiumizeDebridClient> logger, IHtt
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var apiKey = Settings.Get.Provider.ApiKey;
|
var apiKey = GetApiKey();
|
||||||
|
|
||||||
if (String.IsNullOrWhiteSpace(apiKey))
|
|
||||||
{
|
|
||||||
throw new("Premiumize API Key not set in the settings");
|
|
||||||
}
|
|
||||||
|
|
||||||
var httpClient = httpClientFactory.CreateClient();
|
var httpClient = httpClientFactory.CreateClient();
|
||||||
httpClient.Timeout = TimeSpan.FromSeconds(10);
|
httpClient.Timeout = TimeSpan.FromSeconds(10);
|
||||||
|
|
||||||
|
|
@ -253,6 +217,146 @@ public class PremiumizeDebridClient(ILogger<PremiumizeDebridClient> logger, IHtt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String GetApiKey()
|
||||||
|
{
|
||||||
|
var apiKey = Settings.Get.Provider.ApiKey;
|
||||||
|
|
||||||
|
if (String.IsNullOrWhiteSpace(apiKey))
|
||||||
|
{
|
||||||
|
throw new("Premiumize API Key not set in the settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<String> CreatePremiumizeNetTransfer(Func<Task<PremiumizeNET.TransferCreateResponse>> createTransfer, String description)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await createTransfer();
|
||||||
|
|
||||||
|
if (String.IsNullOrWhiteSpace(result?.Id))
|
||||||
|
{
|
||||||
|
throw new($"Unable to add {description}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.Id;
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (IsRateLimitMessage(ex.Message))
|
||||||
|
{
|
||||||
|
throw new RateLimitException(ex.Message, TimeSpan.FromMinutes(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<String> CreateTransferFromNzbFile(Byte[] bytes, String fileName)
|
||||||
|
{
|
||||||
|
var content = new MultipartFormDataContent();
|
||||||
|
var fileContent = new ByteArrayContent(bytes);
|
||||||
|
content.Add(fileContent, "src", fileName);
|
||||||
|
|
||||||
|
return await CreateTransfer(content, "NZB file");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String GetNzbFileName(String? name)
|
||||||
|
{
|
||||||
|
if (String.IsNullOrWhiteSpace(name))
|
||||||
|
{
|
||||||
|
return "upload.nzb";
|
||||||
|
}
|
||||||
|
|
||||||
|
return name.EndsWith(".nzb", StringComparison.OrdinalIgnoreCase) ? name : $"{name}.nzb";
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<String> CreateTransfer(HttpContent content, String description)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (content)
|
||||||
|
{
|
||||||
|
var httpClient = httpClientFactory.CreateClient();
|
||||||
|
httpClient.Timeout = TimeSpan.FromSeconds(10);
|
||||||
|
|
||||||
|
using var request = new HttpRequestMessage(HttpMethod.Post, TransferCreateUrl)
|
||||||
|
{
|
||||||
|
Content = content
|
||||||
|
};
|
||||||
|
|
||||||
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", GetApiKey());
|
||||||
|
|
||||||
|
using var response = await httpClient.SendAsync(request);
|
||||||
|
var responseBody = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
if (response.StatusCode == HttpStatusCode.TooManyRequests)
|
||||||
|
{
|
||||||
|
var retryAfter = response.Headers.RetryAfter?.Delta ?? TimeSpan.FromMinutes(2);
|
||||||
|
|
||||||
|
throw new RateLimitException($"Unable to add {description}: Premiumize rate limit exceeded", retryAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
throw new($"Unable to add {description}: Premiumize returned {(Int32)response.StatusCode} {response.ReasonPhrase}. {responseBody}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = JsonConvert.DeserializeObject<RawTransferCreateResponse>(responseBody) ?? throw new($"Unable to add {description}: invalid Premiumize response");
|
||||||
|
|
||||||
|
if (!String.Equals(result.Status, "success", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var error = FormatPremiumizeError(result);
|
||||||
|
|
||||||
|
if (IsRateLimitMessage(error))
|
||||||
|
{
|
||||||
|
throw new RateLimitException(error, TimeSpan.FromMinutes(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new($"Unable to add {description}: {error}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String.IsNullOrWhiteSpace(result.Id))
|
||||||
|
{
|
||||||
|
throw new($"Unable to add {description}: Premiumize did not return a transfer id");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (RateLimitException)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (IsRateLimitMessage(ex.Message))
|
||||||
|
{
|
||||||
|
throw new RateLimitException(ex.Message, TimeSpan.FromMinutes(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String FormatPremiumizeError(RawTransferCreateResponse result)
|
||||||
|
{
|
||||||
|
return String.Join(": ", new[]
|
||||||
|
{
|
||||||
|
result.Code,
|
||||||
|
result.Message
|
||||||
|
}.Where(m => !String.IsNullOrWhiteSpace(m)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Boolean IsRateLimitMessage(String message)
|
||||||
|
{
|
||||||
|
return message.Contains("slow_down", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
message.Contains("rate limit exceeded", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
message.Contains("rate_limit_reached", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
message.Contains("account_limit_reached", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
message.Contains("service_limit_reached", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
message.Contains("service_down", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
message.Contains("semi_permanent_error", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
message.Contains("too many API requests", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
message.Contains("fair-use points", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
message.Contains("booster points", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
message.Contains("active-job count", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
message.Contains("usage limit for this service", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
message.Contains("target service is unreachable", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
message.Contains("retry after a delay", StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
private static DebridClientTorrent Map(Transfer transfer)
|
private static DebridClientTorrent Map(Transfer transfer)
|
||||||
{
|
{
|
||||||
return new()
|
return new()
|
||||||
|
|
@ -363,4 +467,19 @@ public class PremiumizeDebridClient(ILogger<PremiumizeDebridClient> logger, IHtt
|
||||||
|
|
||||||
logger.LogDebug(message);
|
logger.LogDebug(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class RawTransferCreateResponse
|
||||||
|
{
|
||||||
|
[JsonProperty("status")]
|
||||||
|
public String? Status { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public String? Id { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("message")]
|
||||||
|
public String? Message { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("code")]
|
||||||
|
public String? Code { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue