rdt-client/server/RdtClient.Service/Services/TorrentClients/AllDebridTorrentClient.cs

349 lines
No EOL
10 KiB
C#

using AllDebridNET;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using RdtClient.Data.Enums;
using RdtClient.Data.Models.TorrentClient;
using RdtClient.Service.Helpers;
using System.Web;
using File = AllDebridNET.File;
using Torrent = RdtClient.Data.Models.Data.Torrent;
namespace RdtClient.Service.Services.TorrentClients;
public class AllDebridTorrentClient(ILogger<AllDebridTorrentClient> logger, IHttpClientFactory httpClientFactory) : ITorrentClient
{
private AllDebridNETClient GetClient()
{
try
{
var apiKey = Settings.Get.Provider.ApiKey;
if (String.IsNullOrWhiteSpace(apiKey))
{
throw new("All-Debrid API Key not set in the settings");
}
var httpClient = httpClientFactory.CreateClient();
httpClient.Timeout = TimeSpan.FromSeconds(10);
var allDebridNetClient = new AllDebridNETClient("RealDebridClient", apiKey, httpClient);
return allDebridNetClient;
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
{
logger.LogError(ex, $"The connection to AllDebrid has timed out: {ex.Message}");
throw;
}
catch (TaskCanceledException ex)
{
logger.LogError(ex, $"The connection to AllDebrid has timed out: {ex.Message}");
throw;
}
}
private static TorrentClientTorrent Map(Magnet torrent)
{
return new()
{
Id = torrent.Id.ToString(),
Filename = torrent.Filename,
OriginalFilename = torrent.Filename,
Hash = torrent.Hash,
Bytes = torrent.Size,
OriginalBytes = torrent.Size,
Host = null,
Split = 0,
Progress = (Int64) Math.Round(torrent.Downloaded * 100.0 / torrent.Size),
Status = torrent.Status,
StatusCode = torrent.StatusCode,
Added = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.UploadDate),
Files = torrent.Links.Select((m, i) => new TorrentClientFile
{
Path = m.Filename,
Bytes = m.Size,
Id = i,
Selected = true,
}).ToList(),
Links = torrent.Links.Select(m => m.LinkUrl.ToString()).ToList(),
Ended = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.CompletionDate),
Speed = torrent.DownloadSpeed,
Seeders = torrent.Seeders
};
}
public async Task<IList<TorrentClientTorrent>> GetTorrents()
{
var results = await GetClient().Magnet.StatusAllAsync();
return results.Select(Map).ToList();
}
public async Task<TorrentClientUser> GetUser()
{
var user = await GetClient().User.GetAsync() ?? throw new("Unable to get user");
return new()
{
Username = user.Username,
Expiration = user.PremiumUntil > 0 ? new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(user.PremiumUntil) : null
};
}
public async Task<String> AddMagnet(String magnetLink)
{
var result = await GetClient().Magnet.UploadMagnetAsync(magnetLink);
if (result?.Id == null)
{
throw new("Unable to add magnet link");
}
var resultId = result.Id.ToString() ?? throw new($"Invalid responseID {result.Id}");
return resultId;
}
public async Task<String> AddFile(Byte[] bytes)
{
var result = await GetClient().Magnet.UploadFileAsync(bytes);
if (result?.Id == null)
{
throw new("Unable to add torrent file");
}
var resultId = result.Id.ToString() ?? throw new($"Invalid responseID {result.Id}");
return resultId;
}
public Task<IList<TorrentClientAvailableFile>> GetAvailableFiles(String hash)
{
return Task.FromResult<IList<TorrentClientAvailableFile>>([]);
}
public Task SelectFiles(Torrent torrent)
{
return Task.CompletedTask;
}
public async Task Delete(String torrentId)
{
await GetClient().Magnet.DeleteAsync(torrentId);
}
public async Task<String> Unrestrict(String link)
{
var result = await GetClient().Links.DownloadLinkAsync(link);
if (result.Link == null)
{
throw new("Invalid result link");
}
return result.Link;
}
public async Task<Torrent> UpdateData(Torrent torrent, TorrentClientTorrent? torrentClientTorrent)
{
try
{
if (torrent.RdId == null)
{
return torrent;
}
torrentClientTorrent ??= await GetInfo(torrent.RdId);
if (!String.IsNullOrWhiteSpace(torrentClientTorrent.Filename))
{
torrent.RdName = torrentClientTorrent.Filename;
}
if (torrentClientTorrent.Bytes > 0)
{
torrent.RdSize = torrentClientTorrent.Bytes;
}
if (torrentClientTorrent.Files != null)
{
torrent.RdFiles = JsonConvert.SerializeObject(torrentClientTorrent.Files);
}
torrent.RdHost = torrentClientTorrent.Host;
torrent.RdSplit = torrentClientTorrent.Split;
torrent.RdProgress = torrentClientTorrent.Progress;
torrent.RdAdded = torrentClientTorrent.Added;
torrent.RdEnded = torrentClientTorrent.Ended;
torrent.RdSpeed = torrentClientTorrent.Speed;
torrent.RdSeeders = torrentClientTorrent.Seeders;
torrent.RdStatusRaw = torrentClientTorrent.Status;
torrent.RdStatus = torrentClientTorrent.StatusCode switch
{
0 => TorrentStatus.Processing, // Processing In Queue.
1 => TorrentStatus.Downloading, // Processing Downloading.
2 => TorrentStatus.Downloading, // Processing Compressing / Moving.
3 => TorrentStatus.Uploading, // Processing Uploading.
4 => TorrentStatus.Finished, // Finished Ready.
5 => TorrentStatus.Error, // Error Upload fail.
6 => TorrentStatus.Error, // Error Internal error on unpacking.
7 => TorrentStatus.Error, // Error Not downloaded in 20 min.
8 => TorrentStatus.Error, // Error File too big.
9 => TorrentStatus.Error, // Error Internal error.
10 => TorrentStatus.Error, // Error Download took more than 72h.
11 => TorrentStatus.Error, // Error Deleted on the hoster website
_ => TorrentStatus.Error
};
}
catch (AllDebridException ex)
{
if (ex.ErrorCode == "MAGNET_INVALID_ID")
{
torrent.RdStatusRaw = "deleted";
}
else
{
throw;
}
}
return torrent;
}
public async Task<IList<String>?> GetDownloadLinks(Torrent torrent)
{
if (torrent.RdId == null)
{
return null;
}
var magnet = await GetClient().Magnet.StatusAsync(torrent.RdId);
if (magnet == null)
{
return null;
}
var links = magnet.Links;
Log($"Getting download links", torrent);
if (torrent.DownloadMinSize > 0)
{
var minFileSize = torrent.DownloadMinSize * 1024 * 1024;
Log($"Determining which files are over {minFileSize} bytes", torrent);
links = links.Where(m => m.Size > minFileSize)
.ToList();
Log($"Found {links.Count} files that match the minimum file size criterea", torrent);
}
if (links.Count == 0)
{
Log($"Filtered all files out! Downloading ALL files instead!", torrent);
links = magnet.Links;
}
Log($"Selecting links:");
foreach (var link in links)
{
var fileList = GetFiles(link.Files, "");
Log($"{link.Filename} ({link.Size}b) {link.LinkUrl}, contains files:{Environment.NewLine}{String.Join(Environment.NewLine, fileList)}");
}
Log("", torrent);
return links.Select(m => m.LinkUrl.ToString()).ToList();
}
public Task<String?> GetFileName(Data.Models.Data.Download download)
{
if (String.IsNullOrWhiteSpace(download.Link))
{
return Task.FromResult<String?>(null);
}
var uri = new Uri(download.Link);
return Task.FromResult<String?>(HttpUtility.UrlDecode(uri.Segments.Last()));
}
private async Task<TorrentClientTorrent> GetInfo(String torrentId)
{
var result = await GetClient().Magnet.StatusAsync(torrentId) ?? throw new($"Unable to find magnet with ID {torrentId}");
return Map(result);
}
private static List<String> GetFiles(IList<File> files, String parent)
{
var result = new List<String>();
foreach (var file in files)
{
if (!String.IsNullOrWhiteSpace(file.N))
{
result.Add($"{parent}/{file.N}");
}
if (file.E != null && file.E.Value.PurpleEArray != null && file.E.Value.PurpleEArray.Count > 0)
{
result.AddRange(GetFiles(file.E.Value.PurpleEArray, file.N));
}
}
return result;
}
private static List<String> GetFiles(IList<FileE1> files, String parent)
{
var result = new List<String>();
foreach (var file in files)
{
if (!String.IsNullOrWhiteSpace(file.N))
{
result.Add($"{parent}/{file.N}");
}
if (file.E != null && file.E.Count > 0)
{
result.AddRange(GetFiles(file.E, file.N));
}
}
return result;
}
private static List<String> GetFiles(IList<FileE2> files, String parent)
{
var result = new List<String>();
foreach (var file in files)
{
if (!String.IsNullOrWhiteSpace(file.N))
{
result.Add($"{parent}/{file.N}");
}
}
return result;
}
private void Log(String message, Torrent? torrent = null)
{
if (torrent != null)
{
message = $"{message} {torrent.ToLog()}";
}
logger.LogDebug(message);
}
}