🎉 add support of DebridLinkFr

This commit is contained in:
Wald764 2023-10-22 00:14:52 +02:00
parent dc2ec486d7
commit 59c47bfe1a
8 changed files with 346 additions and 6 deletions

View file

@ -35,6 +35,9 @@ export class NavbarComponent implements OnInit {
case 'Premiumize':
this.providerLink = 'https://www.premiumize.me/';
break;
case 'DebridLinkFr':
this.providerLink = 'https://debrid-link.fr/';
break;
case 'TorBox':
this.providerLink = 'https://torbox.app/';
break;

View file

@ -56,6 +56,9 @@
>Use this link to sign up to Premiumize.</a
>
<br />
<a href="https://debrid-link.com/" target="_blank" rel="noopener"
>Use this link to sign up to DebridLinkFr.</a
>
<a href="https://torbox.app/" target="_blank" rel="noopener"
>Use this link to sign up to TorBox.</a>
<br />
@ -68,7 +71,8 @@
<option [ngValue]="0">Real-Debrid</option>
<option [ngValue]="1">AllDebrid</option>
<option [ngValue]="2">Premiumize</option>
<option [ngValue]="3">TorBox</option>
<option [ngValue]="3">DebridLinkFr</option>
<option [ngValue]="4">TorBox</option>
</select>
</div>
</div>
@ -99,6 +103,12 @@
You can find your API key here:
<a href="https://torbox.app/settings" target="_blank" rel="noopener">https://torbox.app/settings</a>.
</p>
<p class="help" *ngIf="provider === 4">
You can find your API key here:
<a href="https://debrid-link.com/webapp/apikey" target="_blank" rel="noopener"
>https://debrid-link.com/webapp/apikey</a
>.
</p>
</div>
<div class="field">

View file

@ -13,6 +13,9 @@ public enum Provider
[Description("Premiumize")]
Premiumize,
[Description("DebridLinkFr")]
DebridLinkFr,
[Description("TorBox")]
TorBox
}

View file

@ -159,6 +159,7 @@ public class DbSettingsProvider
<a href=""https://real-debrid.com/?id=1348683"" target=""_blank"" rel=""noopener"">https://real-debrid.com</a>
<a href=""https://alldebrid.com/?uid=2v91l&lang=en"" target=""_blank"" rel=""noopener"">https://alldebrid.com</a>
<a href=""https://www.premiumize.me/"" target=""_blank"" rel=""noopener"">https://www.premiumize.me/</a>
<a href=""https://debrid-link.com/"" target=""_blank"" rel=""noopener"">https://debrid-link.com/</a>
<a href=""https://torbox.app/"" target=""_blank"" rel=""noopener"">https://torbox.app/</a>
At this point only 1 provider can be used at the time.")]
public Provider Provider { get; set; } = Provider.RealDebrid;
@ -171,7 +172,9 @@ or
or
<a href=""https://www.premiumize.me/account/"" target=""_blank"" rel=""noopener"">https://www.premiumize.me/account/</a>
or
<a href=""https://torbox.app/settings/"" target=""_blank"" rel=""noopener"">https://torbox.app/settings/</a>")]
<a href=""https://torbox.app/settings/"" target=""_blank"" rel=""noopener"">https://torbox.app/settings/</a>
or
<a href=""https://debrid-link.com/webapp/apikey"" target=""_blank"" rel=""noopener"">https://debrid-link.com/webapp/apikey</a>")]
public String ApiKey { get; set; } = "";
[DisplayName("Automatically import and process torrents added to provider")]

View file

@ -27,6 +27,7 @@ public static class DiConfig
services.AddScoped<TorBoxTorrentClient>();
services.AddScoped<Torrents>();
services.AddScoped<TorrentRunner>();
services.AddScoped<DebridLinkFrClient>();
services.AddSingleton<IAuthorizationHandler, AuthSettingHandler>();

View file

@ -11,6 +11,7 @@
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="AllDebrid.NET" Version="1.0.12" />
<PackageReference Include="Aria2.NET" Version="1.0.5" />
<PackageReference Include="DebridLinkFr.NET" Version="1.0.3" />
<PackageReference Include="Downloader" Version="3.3.3" />
<PackageReference Include="Downloader.NET" Version="1.0.12" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="9.0.1" />

View file

@ -0,0 +1,317 @@
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using DebridLinkFrNET;
using RdtClient.Data.Enums;
using RdtClient.Data.Models.TorrentClient;
using RdtClient.Service.Helpers;
using DebridLinkFrNET.Models;
namespace RdtClient.Service.Services.TorrentClients;
public class DebridLinkFrClient : ITorrentClient
{
private readonly ILogger<DebridLinkFrClient> _logger;
private readonly IHttpClientFactory _httpClientFactory;
public DebridLinkFrClient(ILogger<DebridLinkFrClient> logger, IHttpClientFactory httpClientFactory)
{
_logger = logger;
_httpClientFactory = httpClientFactory;
}
private DebridLinkFrNETClient GetClient()
{
try
{
var apiKey = Settings.Get.Provider.ApiKey;
if (String.IsNullOrWhiteSpace(apiKey))
{
throw new Exception("Real-Debrid API Key not set in the settings");
}
var httpClient = _httpClientFactory.CreateClient();
httpClient.Timeout = TimeSpan.FromSeconds(Settings.Get.Provider.Timeout);
var debridLinkFrClient = new DebridLinkFrNETClient(apiKey, httpClient);
return debridLinkFrClient;
}
catch (AggregateException ae)
{
foreach (var inner in ae.InnerExceptions)
{
_logger.LogError(inner, $"The connection to DebridLinkFr has failed: {inner.Message}");
}
throw;
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
{
_logger.LogError(ex, $"The connection to DebridLinkFr has timed out: {ex.Message}");
throw;
}
catch (TaskCanceledException ex)
{
_logger.LogError(ex, $"The connection to DebridLinkFr has timed out: {ex.Message}");
throw;
}
}
private TorrentClientTorrent Map(Torrent torrent)
{
return new TorrentClientTorrent
{
Id = torrent.Id ?? "",
Filename = torrent.Name ?? "",
OriginalFilename = torrent.Name ?? "",
Hash = torrent.HashString ?? "",
Bytes = torrent.TotalSize,
OriginalBytes = 0,
Host = torrent.ServerId ?? "",
Split = 0,
Progress = torrent.DownloadPercent,
Status = torrent.Status.ToString(),
Added = DateTimeOffset.FromUnixTimeSeconds(torrent.Created),
Files = (torrent.Files ?? new List<TorrentFile>()).Select((m, i) => new TorrentClientFile
{
Path = m.Name ?? "",
Bytes = m.Size,
Id = i,
Selected = true
}).ToList(),
Links = torrent.Files?.Select(m => m.DownloadUrl.ToString()).ToList(),
Ended = null,
Speed = torrent.UploadSpeed,
Seeders = torrent.PeersConnected,
};
}
public async Task<IList<TorrentClientTorrent>> GetTorrents()
{
var page = 0;
var results = new List<Torrent>();
while (true)
{
var pagedResults = await GetClient().Seedbox.ListAsync(null,page, 50);
results.AddRange(pagedResults);
if (pagedResults.Count == 0)
{
break;
}
page += 1;
}
return results.Select(Map).ToList();
}
public async Task<TorrentClientUser> GetUser()
{
var user = await GetClient().Account.Infos();
return new TorrentClientUser
{
Username = user.Username,
Expiration = user.PremiumLeft > 0 ? DateTimeOffset.Now.AddSeconds(user.PremiumLeft) : null
};
}
public async Task<String> AddMagnet(String magnetLink)
{
var result = await GetClient().Seedbox.AddTorrentAsync(magnetLink);
return result.Id ?? "";
}
public async Task<String> AddFile(Byte[] bytes)
{
var result = await GetClient().Seedbox.AddTorrentByFileAsync(bytes);
return result.Id ?? "";
}
public async Task<IList<TorrentClientAvailableFile>> GetAvailableFiles(String hash)
{
var result = await GetClient().Seedbox.CachedAsync(hash);
var files = result.First().Value.Files ?? new List<TorrentFile>();
var groups = files.Where(m => m.Name != null).GroupBy(m => $"{m.Name}-{m.Size}");
var torrentClientAvailableFiles = groups.Select(m => new TorrentClientAvailableFile
{
Filename = m.First().Name!,
Filesize = m.First().Size
}).ToList();
return torrentClientAvailableFiles;
}
public Task SelectFiles(Data.Models.Data.Torrent torrent)
{
return Task.CompletedTask;
}
public async Task Delete(String torrentId)
{
await GetClient().Seedbox.DeleteAsync(torrentId);
}
public async Task<String> Unrestrict(String link)
{
return link;
}
public async Task<Data.Models.Data.Torrent> UpdateData(Data.Models.Data.Torrent torrent, TorrentClientTorrent? torrentClientTorrent)
{
try
{
if (torrent.RdId == null)
{
return torrent;
}
var rdTorrent = await GetInfo(torrent.RdId);
if (rdTorrent == null)
{
throw new Exception($"Resource not found");
}
if (!String.IsNullOrWhiteSpace(rdTorrent.Filename))
{
torrent.RdName = rdTorrent.Filename;
}
if (!String.IsNullOrWhiteSpace(rdTorrent.OriginalFilename))
{
torrent.RdName = rdTorrent.OriginalFilename;
}
if (rdTorrent.Bytes > 0)
{
torrent.RdSize = rdTorrent.Bytes;
}
else if (rdTorrent.OriginalBytes > 0)
{
torrent.RdSize = rdTorrent.OriginalBytes;
}
if (rdTorrent.Files != null)
{
torrent.RdFiles = JsonConvert.SerializeObject(rdTorrent.Files);
}
torrent.RdHost = rdTorrent.Host;
torrent.RdSplit = rdTorrent.Split;
torrent.RdProgress = rdTorrent.Progress;
torrent.RdAdded = rdTorrent.Added;
torrent.RdEnded = rdTorrent.Ended;
torrent.RdSpeed = rdTorrent.Speed;
torrent.RdSeeders = rdTorrent.Seeders;
torrent.RdStatusRaw = rdTorrent.Status;
/**
*
* 0 Torrent is stopped
* 1 Torrent is queued to verify local data
* 2 Torrent is verifying local data
* 3 Torrent is queued to download
* 4 Torrent is downloading
* 5 Torrent is queued to seed
* 6 Torrent is seeding
* 100 Torrent is stored
*/
torrent.RdStatus = rdTorrent.Status switch
{
"100" => TorrentStatus.Finished,
"1" => TorrentStatus.Processing,
"2" => TorrentStatus.Processing,
"3" => TorrentStatus.Processing,
"4" => TorrentStatus.Downloading,
"5" => TorrentStatus.Finished,
"6" => TorrentStatus.Finished,
_ => TorrentStatus.Error
};
}
catch (Exception ex)
{
if (ex.Message == "Resource not found")
{
torrent.RdStatusRaw = "deleted";
}
else
{
throw;
}
}
return torrent;
}
public async Task<IList<String>?> GetDownloadLinks(Data.Models.Data.Torrent torrent)
{
if (torrent.RdId == null)
{
return null;
}
var rdTorrent = await GetInfo(torrent.RdId);
if (rdTorrent.Links == null)
{
return null;
}
var downloadLinks = rdTorrent.Links.Where(m => !String.IsNullOrWhiteSpace(m)).ToList();
Log($"Found {downloadLinks.Count} links", torrent);
foreach (var link in downloadLinks)
{
Log($"{link}", torrent);
}
// Check if all the links are set that have been selected
if (torrent.Files.Count(m => m.Selected) == downloadLinks.Count)
{
return downloadLinks;
}
// Check if all all the links are set for manual selection
if (torrent.ManualFiles.Count == downloadLinks.Count)
{
return downloadLinks;
}
// If there is only 1 link, delay for 1 minute to see if more links pop up.
if (downloadLinks.Count == 1 && torrent.RdEnded.HasValue && DateTime.UtcNow > torrent.RdEnded.Value.ToUniversalTime().AddMinutes(1))
{
return downloadLinks;
}
return null;
}
private async Task<TorrentClientTorrent> GetInfo(String torrentId)
{
var result = await GetClient().Seedbox.ListAsync(torrentId);
return Map(result.First());
}
private void Log(String message, Data.Models.Data.Torrent? torrent = null)
{
if (torrent != null)
{
message = $"{message} {torrent.ToLog()}";
}
_logger.LogDebug(message);
}
}

View file

@ -23,6 +23,7 @@ public class Torrents(
AllDebridTorrentClient allDebridTorrentClient,
PremiumizeTorrentClient premiumizeTorrentClient,
RealDebridTorrentClient realDebridTorrentClient,
DebridLinkFrClient debridLinkFrClient,
TorBoxTorrentClient torBoxTorrentClient)
{
private static readonly SemaphoreSlim RealDebridUpdateLock = new(1, 1);
@ -41,6 +42,7 @@ public class Torrents(
Provider.Premiumize => premiumizeTorrentClient,
Provider.RealDebrid => realDebridTorrentClient,
Provider.AllDebrid => allDebridTorrentClient,
Provider.DebridLinkFr => debridLinkFrClient,
Provider.TorBox => torBoxTorrentClient,
_ => throw new("Invalid Provider")
};
@ -575,7 +577,7 @@ public class Torrents(
await torrentData.UpdateComplete(download.TorrentId, null, null, false);
}
public async Task UpdateComplete(Guid torrentId, String? error, DateTimeOffset datetime, Boolean retry)
{
await torrentData.UpdateComplete(torrentId, error, datetime, retry);
@ -657,7 +659,7 @@ public class Torrents(
Torrent torrent)
{
await RealDebridUpdateLock.WaitAsync();
try
{
var existingTorrent = await torrentData.GetByHash(infoHash);
@ -732,7 +734,7 @@ public class Torrents(
var outputSb = new StringBuilder();
using var process = new Process();
process.StartInfo.FileName = fileName;
process.StartInfo.Arguments = arguments;
process.StartInfo.CreateNoWindow = true;
@ -758,7 +760,7 @@ public class Torrents(
errorSb.AppendLine(data.Data.Trim());
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();