Merge branch 'master' into docs/torbox-initial
This commit is contained in:
commit
09d929db17
20 changed files with 481 additions and 154 deletions
|
|
@ -16,8 +16,9 @@ This is a web interface to manage your torrents on Real-Debrid, AllDebrid, Premi
|
||||||
|
|
||||||
[Click here to sign up for Premiumize.](https://www.premiumize.me/)
|
[Click here to sign up for Premiumize.](https://www.premiumize.me/)
|
||||||
|
|
||||||
[//]: # (TODO: add referral link)
|
[Click here to sign up for TorBox](https://torbox.app/subscription?referral=3d25018e-f30d-4c4b-a714-48c04bc76765)
|
||||||
[Click here to sign up for TorBox](https://torbox.app/subscription)
|
|
||||||
|
[Click here to sign up for DebridLink.](https://debrid-link.fr/id/6duif)
|
||||||
|
|
||||||
<sub>(referal links so I can get a few free premium days)</sub>
|
<sub>(referal links so I can get a few free premium days)</sub>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,9 @@ export class NavbarComponent implements OnInit {
|
||||||
case 'TorBox':
|
case 'TorBox':
|
||||||
this.providerLink = 'https://torbox.app/';
|
this.providerLink = 'https://torbox.app/';
|
||||||
break;
|
break;
|
||||||
|
case 'DebridLink':
|
||||||
|
this.providerLink = 'https://debrid-link.com/';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
<div class="notification is-primary">
|
<div class="notification is-primary">
|
||||||
To be able to use the Real-Debrid Client you need a premium subscription to download torrents.
|
To be able to use the Real-Debrid Client you need a premium subscription to download torrents.
|
||||||
<br /><br />
|
<br /><br />
|
||||||
Not premium yet? You have the choice of 4 providers:
|
Not premium yet? You have the choice of 5 providers:
|
||||||
<br />
|
<br />
|
||||||
<a href="https://real-debrid.com/?id=1348683" target="_blank" rel="noopener"
|
<a href="https://real-debrid.com/?id=1348683" target="_blank" rel="noopener"
|
||||||
>Use this link to sign up to Real-Debrid.</a
|
>Use this link to sign up to Real-Debrid.</a
|
||||||
|
|
@ -59,6 +59,9 @@
|
||||||
<a href="https://torbox.app/" target="_blank" rel="noopener"
|
<a href="https://torbox.app/" target="_blank" rel="noopener"
|
||||||
>Use this link to sign up to TorBox.</a>
|
>Use this link to sign up to TorBox.</a>
|
||||||
<br />
|
<br />
|
||||||
|
<a href="https://debrid-link.com/" target="_blank" rel="noopener"
|
||||||
|
>Use this link to sign up to DebridLink.</a
|
||||||
|
>
|
||||||
<small>(Referal links)</small>
|
<small>(Referal links)</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
|
@ -69,6 +72,7 @@
|
||||||
<option [ngValue]="1">AllDebrid</option>
|
<option [ngValue]="1">AllDebrid</option>
|
||||||
<option [ngValue]="2">Premiumize</option>
|
<option [ngValue]="2">Premiumize</option>
|
||||||
<option [ngValue]="3">TorBox</option>
|
<option [ngValue]="3">TorBox</option>
|
||||||
|
<option [ngValue]="4">DebridLink</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -99,6 +103,12 @@
|
||||||
You can find your API key here:
|
You can find your API key here:
|
||||||
<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>.
|
||||||
</p>
|
</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>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
|
|
|
||||||
|
|
@ -14,5 +14,8 @@ public enum Provider
|
||||||
Premiumize,
|
Premiumize,
|
||||||
|
|
||||||
[Description("TorBox")]
|
[Description("TorBox")]
|
||||||
TorBox
|
TorBox,
|
||||||
|
|
||||||
|
[Description("DebridLink")]
|
||||||
|
DebridLink
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +44,7 @@ public class Torrent
|
||||||
[InverseProperty("Torrent")]
|
[InverseProperty("Torrent")]
|
||||||
public IList<Download> Downloads { get; set; } = [];
|
public IList<Download> Downloads { get; set; } = [];
|
||||||
|
|
||||||
public TorrentClientKind? ClientKind { get; set; }
|
public Provider? ClientKind { get; set; }
|
||||||
public String? RdId { get; set; }
|
public String? RdId { get; set; }
|
||||||
public String? RdName { get; set; }
|
public String? RdName { get; set; }
|
||||||
public Int64? RdSize { get; set; }
|
public Int64? RdSize { get; set; }
|
||||||
|
|
@ -93,12 +93,4 @@ public class Torrent
|
||||||
return DownloadManualFiles.Split(",");
|
return DownloadManualFiles.Split(",");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TorrentClientKind
|
|
||||||
{
|
|
||||||
AllDebrid,
|
|
||||||
Premiumize,
|
|
||||||
RealDebrid,
|
|
||||||
TorBox
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -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://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://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://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>
|
<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.")]
|
At this point only 1 provider can be used at the time.")]
|
||||||
public Provider Provider { get; set; } = Provider.RealDebrid;
|
public Provider Provider { get; set; } = Provider.RealDebrid;
|
||||||
|
|
@ -171,7 +172,9 @@ or
|
||||||
or
|
or
|
||||||
<a href=""https://www.premiumize.me/account/"" target=""_blank"" rel=""noopener"">https://www.premiumize.me/account/</a>
|
<a href=""https://www.premiumize.me/account/"" target=""_blank"" rel=""noopener"">https://www.premiumize.me/account/</a>
|
||||||
or
|
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; } = "";
|
public String ApiKey { get; set; } = "";
|
||||||
|
|
||||||
[DisplayName("Automatically import and process torrents added to provider")]
|
[DisplayName("Automatically import and process torrents added to provider")]
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,5 @@ public class TorrentClientFile
|
||||||
public String Path { get; set; } = default!;
|
public String Path { get; set; } = default!;
|
||||||
public Int64 Bytes { get; set; }
|
public Int64 Bytes { get; set; }
|
||||||
public Boolean Selected { get; set; }
|
public Boolean Selected { get; set; }
|
||||||
|
public String? DownloadLink { get; set; }
|
||||||
}
|
}
|
||||||
|
|
@ -8,11 +8,11 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.1" />
|
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="9.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.1">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.2">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ public static class DiConfig
|
||||||
services.AddScoped<TorBoxTorrentClient>();
|
services.AddScoped<TorBoxTorrentClient>();
|
||||||
services.AddScoped<Torrents>();
|
services.AddScoped<Torrents>();
|
||||||
services.AddScoped<TorrentRunner>();
|
services.AddScoped<TorrentRunner>();
|
||||||
|
services.AddScoped<DebridLinkClient>();
|
||||||
|
|
||||||
services.AddSingleton<IAuthorizationHandler, AuthSettingHandler>();
|
services.AddSingleton<IAuthorizationHandler, AuthSettingHandler>();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,21 +9,22 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="AllDebrid.NET" Version="1.0.12" />
|
<PackageReference Include="AllDebrid.NET" Version="1.0.16" />
|
||||||
<PackageReference Include="Aria2.NET" Version="1.0.5" />
|
<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" Version="3.3.3" />
|
||||||
<PackageReference Include="Downloader.NET" Version="1.0.12" />
|
<PackageReference Include="Downloader.NET" Version="1.0.13" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="9.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.1.0" />
|
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="9.2.0" />
|
||||||
<PackageReference Include="MonoTorrent" Version="3.0.2" />
|
<PackageReference Include="MonoTorrent" Version="3.0.2" />
|
||||||
<PackageReference Include="Polly" Version="8.5.1" />
|
<PackageReference Include="Polly" Version="8.5.2" />
|
||||||
<PackageReference Include="Premiumize.NET" Version="1.0.4" />
|
<PackageReference Include="Premiumize.NET" Version="1.0.4" />
|
||||||
<PackageReference Include="RD.NET" Version="2.1.6" />
|
<PackageReference Include="RD.NET" Version="2.1.6" />
|
||||||
<PackageReference Include="Serilog" Version="4.2.0" />
|
<PackageReference Include="Serilog" Version="4.2.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.39.0" />
|
<PackageReference Include="SharpCompress" Version="0.39.0" />
|
||||||
<PackageReference Include="Synology.Api.Client" Version="0.3.87" />
|
<PackageReference Include="Synology.Api.Client" Version="0.3.87" />
|
||||||
<PackageReference Include="TorBox.NET" Version="1.3.2" />
|
<PackageReference Include="TorBox.NET" Version="1.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using RdtClient.Data.Models.Data;
|
using RdtClient.Data.Enums;
|
||||||
|
using RdtClient.Data.Models.Data;
|
||||||
using RdtClient.Service.Helpers;
|
using RdtClient.Service.Helpers;
|
||||||
using RdtClient.Service.Services.Downloaders;
|
using RdtClient.Service.Services.Downloaders;
|
||||||
using RdtClient.Service.Services.TorrentClients;
|
using RdtClient.Service.Services.TorrentClients;
|
||||||
|
|
@ -40,11 +41,16 @@ public class DownloadClient(Download download, Torrent torrent, String destinati
|
||||||
var filePath = DownloadHelper.GetDownloadPath(destinationPath, torrent, download);
|
var filePath = DownloadHelper.GetDownloadPath(destinationPath, torrent, download);
|
||||||
var downloadPath = DownloadHelper.GetDownloadPath(torrent, download);
|
var downloadPath = DownloadHelper.GetDownloadPath(torrent, download);
|
||||||
|
|
||||||
if (torrent.ClientKind == Torrent.TorrentClientKind.AllDebrid && Type == Data.Enums.DownloadClient.Symlink)
|
if (torrent.ClientKind == Provider.AllDebrid && Type == Data.Enums.DownloadClient.Symlink)
|
||||||
{
|
{
|
||||||
downloadPath = AllDebridTorrentClient.GetSymlinkPath(torrent, download);
|
downloadPath = AllDebridTorrentClient.GetSymlinkPath(torrent, download);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (torrent.ClientKind == Provider.DebridLink && Type == Data.Enums.DownloadClient.Symlink)
|
||||||
|
{
|
||||||
|
downloadPath = DebridLinkClient.GetSymlinkPath(torrent, download);
|
||||||
|
}
|
||||||
|
|
||||||
if (filePath == null || downloadPath == null)
|
if (filePath == null || downloadPath == null)
|
||||||
{
|
{
|
||||||
throw new("Invalid download path");
|
throw new("Invalid download path");
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
using RdtClient.Data.Models.Data;
|
using RdtClient.Data.Enums;
|
||||||
using RdtClient.Service.Helpers;
|
using RdtClient.Service.Helpers;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace RdtClient.Service.Services.Downloaders;
|
namespace RdtClient.Service.Services.Downloaders;
|
||||||
|
|
||||||
public class SymlinkDownloader(String uri, String destinationPath, String path, Torrent.TorrentClientKind? clientKind) : IDownloader
|
public class SymlinkDownloader(String uri, String destinationPath, String path, Provider? clientKind) : IDownloader
|
||||||
{
|
{
|
||||||
public event EventHandler<DownloadCompleteEventArgs>? DownloadComplete;
|
public event EventHandler<DownloadCompleteEventArgs>? DownloadComplete;
|
||||||
public event EventHandler<DownloadProgressEventArgs>? DownloadProgress;
|
public event EventHandler<DownloadProgressEventArgs>? DownloadProgress;
|
||||||
|
|
@ -62,7 +62,7 @@ public class SymlinkDownloader(String uri, String destinationPath, String path,
|
||||||
var shouldSearch = true;
|
var shouldSearch = true;
|
||||||
|
|
||||||
// When resolving symlinks for AllDebrid, we know the exact file path, so we can skip the search.
|
// When resolving symlinks for AllDebrid, we know the exact file path, so we can skip the search.
|
||||||
if (clientKind == Torrent.TorrentClientKind.AllDebrid)
|
if (clientKind == Provider.AllDebrid)
|
||||||
{
|
{
|
||||||
var potentialFilePath = Path.Combine(rcloneMountPath, path);
|
var potentialFilePath = Path.Combine(rcloneMountPath, path);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
|
||||||
if (!String.IsNullOrWhiteSpace(torrent.RdName))
|
if (!String.IsNullOrWhiteSpace(torrent.RdName))
|
||||||
{
|
{
|
||||||
// Alldebrid stores single file torrents at the root folder.
|
// Alldebrid stores single file torrents at the root folder.
|
||||||
if (torrent.ClientKind == Torrent.TorrentClientKind.AllDebrid && torrent.Files.Count == 1)
|
if (torrent.ClientKind == Provider.AllDebrid && torrent.Files.Count == 1)
|
||||||
{
|
{
|
||||||
torrentPath = Path.Combine(downloadPath, torrent.Files[0].Path);
|
torrentPath = Path.Combine(downloadPath, torrent.Files[0].Path);
|
||||||
} else
|
} else
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,16 @@ using RdtClient.Service.Helpers;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using RdtClient.Data.Models.Data;
|
using RdtClient.Data.Models.Data;
|
||||||
using File = AllDebridNET.File;
|
using File = AllDebridNET.File;
|
||||||
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
|
|
||||||
using Torrent = RdtClient.Data.Models.Data.Torrent;
|
using Torrent = RdtClient.Data.Models.Data.Torrent;
|
||||||
|
|
||||||
namespace RdtClient.Service.Services.TorrentClients;
|
namespace RdtClient.Service.Services.TorrentClients;
|
||||||
|
|
||||||
public class AllDebridTorrentClient(ILogger<AllDebridTorrentClient> logger, IHttpClientFactory httpClientFactory) : ITorrentClient
|
public class AllDebridTorrentClient(ILogger<AllDebridTorrentClient> logger, IHttpClientFactory httpClientFactory) : ITorrentClient
|
||||||
{
|
{
|
||||||
|
private static readonly Int64 SessionId = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||||
|
private static List<TorrentClientTorrent> _cache = [];
|
||||||
|
private static Int64 _sessionCounter = 0;
|
||||||
|
|
||||||
private AllDebridNETClient GetClient()
|
private AllDebridNETClient GetClient()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
@ -49,30 +52,24 @@ public class AllDebridTorrentClient(ILogger<AllDebridTorrentClient> logger, IHtt
|
||||||
|
|
||||||
private static TorrentClientTorrent Map(Magnet torrent)
|
private static TorrentClientTorrent Map(Magnet torrent)
|
||||||
{
|
{
|
||||||
|
var files = GetFiles(torrent.Files);
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
Id = torrent.Id.ToString(),
|
Id = torrent.Id.ToString(),
|
||||||
Filename = torrent.Filename,
|
Filename = torrent.Filename ?? "",
|
||||||
OriginalFilename = torrent.Filename,
|
OriginalFilename = torrent.Filename,
|
||||||
Hash = torrent.Hash,
|
Hash = torrent.Hash ?? "",
|
||||||
Bytes = torrent.Size,
|
Bytes = torrent.Size ?? 0,
|
||||||
OriginalBytes = torrent.Size,
|
OriginalBytes = torrent.Size ?? 0,
|
||||||
Host = null,
|
Host = null,
|
||||||
Split = 0,
|
Split = 0,
|
||||||
Progress = (Int64)Math.Round(torrent.Downloaded * 100.0 / torrent.Size),
|
Progress = (Int64)Math.Round((torrent.Downloaded ?? 0) * 100.0 / (torrent.Size ?? 1)),
|
||||||
Status = torrent.Status,
|
Status = torrent.Status,
|
||||||
StatusCode = torrent.StatusCode,
|
StatusCode = torrent.StatusCode ?? 0,
|
||||||
Added = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.UploadDate),
|
Added = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.UploadDate ?? 0),
|
||||||
Files = torrent.Links.Select((m, i) => new TorrentClientFile
|
Files = files,
|
||||||
{
|
Links = [],
|
||||||
Path = GetFiles(m.Files),
|
Ended = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(torrent.CompletionDate ?? 0),
|
||||||
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,
|
Speed = torrent.DownloadSpeed,
|
||||||
Seeders = torrent.Seeders
|
Seeders = torrent.Seeders
|
||||||
};
|
};
|
||||||
|
|
@ -80,9 +77,31 @@ public class AllDebridTorrentClient(ILogger<AllDebridTorrentClient> logger, IHtt
|
||||||
|
|
||||||
public async Task<IList<TorrentClientTorrent>> GetTorrents()
|
public async Task<IList<TorrentClientTorrent>> GetTorrents()
|
||||||
{
|
{
|
||||||
var results = await GetClient().Magnet.StatusAllAsync();
|
var results = await GetClient().Magnet.StatusLiveAsync(SessionId, _sessionCounter);
|
||||||
|
|
||||||
return results.Select(Map).ToList();
|
_sessionCounter = results.Counter;
|
||||||
|
|
||||||
|
if (results.Fullsync == true)
|
||||||
|
{
|
||||||
|
_cache = (results.Magnets ?? []).Select(Map).ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Replace the existing items in the cache with the new ones based on the ID
|
||||||
|
foreach (var result in results.Magnets ?? [])
|
||||||
|
{
|
||||||
|
var existing = _cache.FirstOrDefault(m => m.Id == result.Id.ToString());
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
_cache.Remove(existing);
|
||||||
|
}
|
||||||
|
_cache.Add(Map(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_cache = _cache.Where(m => m.Status != null).ToList();
|
||||||
|
|
||||||
|
return _cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TorrentClientUser> GetUser()
|
public async Task<TorrentClientUser> GetUser()
|
||||||
|
|
@ -177,7 +196,7 @@ public class AllDebridTorrentClient(ILogger<AllDebridTorrentClient> logger, IHtt
|
||||||
torrent.RdFiles = JsonConvert.SerializeObject(torrentClientTorrent.Files);
|
torrent.RdFiles = JsonConvert.SerializeObject(torrentClientTorrent.Files);
|
||||||
}
|
}
|
||||||
|
|
||||||
torrent.ClientKind = Torrent.TorrentClientKind.AllDebrid;
|
torrent.ClientKind = Provider.AllDebrid;
|
||||||
torrent.RdHost = torrentClientTorrent.Host;
|
torrent.RdHost = torrentClientTorrent.Host;
|
||||||
torrent.RdSplit = torrentClientTorrent.Split;
|
torrent.RdSplit = torrentClientTorrent.Split;
|
||||||
torrent.RdProgress = torrentClientTorrent.Progress;
|
torrent.RdProgress = torrentClientTorrent.Progress;
|
||||||
|
|
@ -226,14 +245,9 @@ public class AllDebridTorrentClient(ILogger<AllDebridTorrentClient> logger, IHtt
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var magnet = await GetClient().Magnet.StatusAsync(torrent.RdId);
|
var allFiles = await GetClient().Magnet.FilesAsync(Int64.Parse(torrent.RdId));
|
||||||
|
|
||||||
if (magnet == null)
|
var files = GetFiles(allFiles);
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var links = magnet.Links;
|
|
||||||
|
|
||||||
Log($"Getting download links", torrent);
|
Log($"Getting download links", torrent);
|
||||||
|
|
||||||
|
|
@ -243,83 +257,74 @@ public class AllDebridTorrentClient(ILogger<AllDebridTorrentClient> logger, IHtt
|
||||||
|
|
||||||
Log($"Determining which files are over {minFileSize} bytes", torrent);
|
Log($"Determining which files are over {minFileSize} bytes", torrent);
|
||||||
|
|
||||||
links = links.Where(m => m.Size > minFileSize)
|
files = files.Where(m => m.Bytes > minFileSize)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
Log($"Found {links.Count} files that match the minimum file size criterea", torrent);
|
Log($"Found {files.Count} files that match the minimum file size criterea", torrent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!String.IsNullOrWhiteSpace(torrent.IncludeRegex))
|
if (!String.IsNullOrWhiteSpace(torrent.IncludeRegex))
|
||||||
{
|
{
|
||||||
Log($"Using regular expression {torrent.IncludeRegex} to include only files matching this regex", torrent);
|
Log($"Using regular expression {torrent.IncludeRegex} to include only files matching this regex", torrent);
|
||||||
|
|
||||||
var newLinks = new List<Link>();
|
var newFiles = new List<TorrentClientFile>();
|
||||||
|
|
||||||
foreach (var link in links)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
var path = GetFiles(link.Files);
|
if (Regex.IsMatch(file.Path, torrent.IncludeRegex))
|
||||||
|
|
||||||
if (Regex.IsMatch(path, torrent.IncludeRegex))
|
|
||||||
{
|
{
|
||||||
Log($"* Including {path}", torrent);
|
Log($"* Including {file.Path}", torrent);
|
||||||
newLinks.Add(link);
|
newFiles.Add(file);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log($"* Excluding {path}", torrent);
|
Log($"* Excluding {file.Path}", torrent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
links = newLinks;
|
files = newFiles;
|
||||||
|
|
||||||
Log($"Found {newLinks.Count} files that match the regex", torrent);
|
Log($"Found {newFiles.Count} files that match the regex", torrent);
|
||||||
}
|
}
|
||||||
else if (!String.IsNullOrWhiteSpace(torrent.ExcludeRegex))
|
else if (!String.IsNullOrWhiteSpace(torrent.ExcludeRegex))
|
||||||
{
|
{
|
||||||
Log($"Using regular expression {torrent.IncludeRegex} to ignore files matching this regex", torrent);
|
Log($"Using regular expression {torrent.IncludeRegex} to ignore files matching this regex", torrent);
|
||||||
|
|
||||||
var newLinks = new List<Link>();
|
var newLinks = new List<TorrentClientFile>();
|
||||||
|
|
||||||
foreach (var link in links)
|
foreach (var link in files)
|
||||||
{
|
{
|
||||||
var path = GetFiles(link.Files);
|
if (!Regex.IsMatch(link.Path, torrent.ExcludeRegex))
|
||||||
|
|
||||||
if (!Regex.IsMatch(path, torrent.ExcludeRegex))
|
|
||||||
{
|
{
|
||||||
Log($"* Including {path}", torrent);
|
Log($"* Including {link.Path}", torrent);
|
||||||
newLinks.Add(link);
|
newLinks.Add(link);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log($"* Excluding {path}", torrent);
|
Log($"* Excluding {link.Path}", torrent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
links = newLinks;
|
files = newLinks;
|
||||||
|
|
||||||
Log($"Found {newLinks.Count} files that match the regex", torrent);
|
Log($"Found {newLinks.Count} files that match the regex", torrent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (links.Count == 0)
|
if (files.Count == 0)
|
||||||
{
|
{
|
||||||
Log($"Filtered all files out! Downloading ALL files instead!", torrent);
|
Log($"Filtered all files out! Downloading ALL files instead!", torrent);
|
||||||
|
|
||||||
links = magnet.Links;
|
files = GetFiles(allFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logger.IsEnabled(LogLevel.Debug))
|
Log($"Selecting links:");
|
||||||
|
|
||||||
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
Log($"Selecting links:");
|
Log($"{file.Path} ({file.Bytes}b) {file.DownloadLink}");
|
||||||
|
|
||||||
foreach (var link in links)
|
|
||||||
{
|
|
||||||
Log($"{GetFiles(link.Files)} ({link.Size}b) {link.LinkUrl}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Log("", torrent);
|
return files.Where(m => m.DownloadLink != null).Select(m => m.DownloadLink!.ToString()).ToList();
|
||||||
|
|
||||||
return links.Select(m => m.LinkUrl.ToString()).ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<String> GetFileName(String downloadUrl)
|
public Task<String> GetFileName(String downloadUrl)
|
||||||
|
|
@ -341,64 +346,40 @@ public class AllDebridTorrentClient(ILogger<AllDebridTorrentClient> logger, IHtt
|
||||||
return Map(result);
|
return Map(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String GetFiles(IList<File> files)
|
private static List<TorrentClientFile> GetFiles(List<File>? files, String parentPath = "")
|
||||||
{
|
{
|
||||||
var result = new List<String>();
|
if (files == null)
|
||||||
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
{
|
||||||
if (!String.IsNullOrWhiteSpace(file.N))
|
return [];
|
||||||
{
|
}
|
||||||
result.Add(file.N);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file.E != null && file.E.Value.PurpleEArray != null && file.E.Value.PurpleEArray.Count > 0)
|
return files.SelectMany(file =>
|
||||||
|
{
|
||||||
|
var currentPath = String.IsNullOrEmpty(parentPath)
|
||||||
|
? file.FolderOrFileName
|
||||||
|
: Path.Combine(parentPath, file.FolderOrFileName);
|
||||||
|
|
||||||
|
var result = new List<TorrentClientFile>();
|
||||||
|
|
||||||
|
// If it's a file (has size)
|
||||||
|
if (file.Size.HasValue)
|
||||||
{
|
{
|
||||||
if (file.E.Value.PurpleEArray.Count != 1)
|
result.Add(new()
|
||||||
{
|
{
|
||||||
throw new("Unexpected number of nested files");
|
Path = currentPath,
|
||||||
}
|
Bytes = file.Size.Value,
|
||||||
|
DownloadLink = file.DownloadLink
|
||||||
result.AddRange(GetFiles(file.E.Value.PurpleEArray));
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return String.Join("/", result);
|
// Process sub-nodes if they exist
|
||||||
}
|
if (file.SubNodes != null)
|
||||||
|
|
||||||
private static List<String> GetFiles(IList<FileE1> files)
|
|
||||||
{
|
|
||||||
var result = new List<String>();
|
|
||||||
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
if (!String.IsNullOrWhiteSpace(file.N))
|
|
||||||
{
|
{
|
||||||
result.Add(file.N);
|
result.AddRange(GetFiles(file.SubNodes, currentPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.E != null && file.E.Count > 0)
|
return result;
|
||||||
{
|
}).ToList();
|
||||||
result.AddRange(GetFiles(file.E));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<String> GetFiles(IList<FileE2> files)
|
|
||||||
{
|
|
||||||
var result = new List<String>();
|
|
||||||
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
if (!String.IsNullOrWhiteSpace(file.N))
|
|
||||||
{
|
|
||||||
result.Add(file.N);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Log(String message, Torrent? torrent = null)
|
private void Log(String message, Torrent? torrent = null)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,323 @@
|
||||||
|
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;
|
||||||
|
using System.Web;
|
||||||
|
using Download = RdtClient.Data.Models.Data.Download;
|
||||||
|
|
||||||
|
namespace RdtClient.Service.Services.TorrentClients;
|
||||||
|
|
||||||
|
public class DebridLinkClient(ILogger<DebridLinkClient> logger, IHttpClientFactory httpClientFactory) : ITorrentClient
|
||||||
|
{
|
||||||
|
private DebridLinkFrNETClient GetClient()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var apiKey = Settings.Get.Provider.ApiKey;
|
||||||
|
|
||||||
|
if (String.IsNullOrWhiteSpace(apiKey))
|
||||||
|
{
|
||||||
|
throw new("DebridLink API Key not set in the settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpClient = httpClientFactory.CreateClient();
|
||||||
|
httpClient.Timeout = TimeSpan.FromSeconds(Settings.Get.Provider.Timeout);
|
||||||
|
|
||||||
|
var debridLinkClient = new DebridLinkFrNETClient(apiKey, httpClient);
|
||||||
|
|
||||||
|
return debridLinkClient;
|
||||||
|
}
|
||||||
|
catch (AggregateException ae)
|
||||||
|
{
|
||||||
|
foreach (var inner in ae.InnerExceptions)
|
||||||
|
{
|
||||||
|
logger.LogError(inner, $"The connection to DebridLink has failed: {inner.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
|
||||||
|
{
|
||||||
|
logger.LogError(ex, $"The connection to DebridLink has timed out: {ex.Message}");
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException ex)
|
||||||
|
{
|
||||||
|
logger.LogError(ex, $"The connection to DebridLink has timed out: {ex.Message}");
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TorrentClientTorrent Map(Torrent torrent)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
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 ?? []).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()
|
||||||
|
{
|
||||||
|
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 Task<IList<TorrentClientAvailableFile>> GetAvailableFiles(String hash)
|
||||||
|
{
|
||||||
|
return Task.FromResult<IList<TorrentClientAvailableFile>>([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SelectFiles(Data.Models.Data.Torrent torrent)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Delete(String torrentId)
|
||||||
|
{
|
||||||
|
await GetClient().Seedbox.DeleteAsync(torrentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<String> Unrestrict(String link)
|
||||||
|
{
|
||||||
|
return Task.FromResult(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) ?? throw new($"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.ClientKind = Provider.DebridLink;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<String> GetFileName(String downloadUrl)
|
||||||
|
{
|
||||||
|
if (String.IsNullOrWhiteSpace(downloadUrl))
|
||||||
|
{
|
||||||
|
return Task.FromResult("");
|
||||||
|
}
|
||||||
|
|
||||||
|
var uri = new Uri(downloadUrl);
|
||||||
|
|
||||||
|
return Task.FromResult(HttpUtility.UrlDecode(uri.Segments.Last()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String? GetSymlinkPath(Data.Models.Data.Torrent torrent, Download download)
|
||||||
|
{
|
||||||
|
if (torrent.RdName == null || download.FileName == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single file torrents always have that file at `/mnt-root/Seedbox/filename.ext`
|
||||||
|
if (torrent.Files.Count == 1)
|
||||||
|
{
|
||||||
|
return download.FileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Path.Combine(torrent.RdName, download.FileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -162,7 +162,7 @@ public class PremiumizeTorrentClient(ILogger<PremiumizeTorrentClient> logger, IH
|
||||||
torrent.RdFiles = JsonConvert.SerializeObject(torrentClientTorrent.Files);
|
torrent.RdFiles = JsonConvert.SerializeObject(torrentClientTorrent.Files);
|
||||||
}
|
}
|
||||||
|
|
||||||
torrent.ClientKind = Torrent.TorrentClientKind.Premiumize;
|
torrent.ClientKind = Provider.Premiumize;
|
||||||
torrent.RdHost = torrentClientTorrent.Host;
|
torrent.RdHost = torrentClientTorrent.Host;
|
||||||
torrent.RdSplit = torrentClientTorrent.Split;
|
torrent.RdSplit = torrentClientTorrent.Split;
|
||||||
torrent.RdProgress = torrentClientTorrent.Progress;
|
torrent.RdProgress = torrentClientTorrent.Progress;
|
||||||
|
|
|
||||||
|
|
@ -295,7 +295,7 @@ public class RealDebridTorrentClient(ILogger<RealDebridTorrentClient> logger, IH
|
||||||
torrent.RdFiles = JsonConvert.SerializeObject(torrentClientTorrent.Files);
|
torrent.RdFiles = JsonConvert.SerializeObject(torrentClientTorrent.Files);
|
||||||
}
|
}
|
||||||
|
|
||||||
torrent.ClientKind = Data.Models.Data.Torrent.TorrentClientKind.RealDebrid;
|
torrent.ClientKind = Provider.RealDebrid;
|
||||||
torrent.RdHost = torrentClientTorrent.Host;
|
torrent.RdHost = torrentClientTorrent.Host;
|
||||||
torrent.RdSplit = torrentClientTorrent.Split;
|
torrent.RdSplit = torrentClientTorrent.Split;
|
||||||
torrent.RdProgress = torrentClientTorrent.Progress;
|
torrent.RdProgress = torrentClientTorrent.Progress;
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,7 @@ public class TorBoxTorrentClient(ILogger<TorBoxTorrentClient> logger, IHttpClien
|
||||||
torrent.RdFiles = JsonConvert.SerializeObject(rdTorrent.Files);
|
torrent.RdFiles = JsonConvert.SerializeObject(rdTorrent.Files);
|
||||||
}
|
}
|
||||||
|
|
||||||
torrent.ClientKind = Torrent.TorrentClientKind.TorBox;
|
torrent.ClientKind = Provider.TorBox;
|
||||||
torrent.RdHost = rdTorrent.Host;
|
torrent.RdHost = rdTorrent.Host;
|
||||||
torrent.RdSplit = rdTorrent.Split;
|
torrent.RdSplit = rdTorrent.Split;
|
||||||
torrent.RdProgress = rdTorrent.Progress;
|
torrent.RdProgress = rdTorrent.Progress;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ public class Torrents(
|
||||||
AllDebridTorrentClient allDebridTorrentClient,
|
AllDebridTorrentClient allDebridTorrentClient,
|
||||||
PremiumizeTorrentClient premiumizeTorrentClient,
|
PremiumizeTorrentClient premiumizeTorrentClient,
|
||||||
RealDebridTorrentClient realDebridTorrentClient,
|
RealDebridTorrentClient realDebridTorrentClient,
|
||||||
|
DebridLinkClient debridLinkClient,
|
||||||
TorBoxTorrentClient torBoxTorrentClient)
|
TorBoxTorrentClient torBoxTorrentClient)
|
||||||
{
|
{
|
||||||
private static readonly SemaphoreSlim RealDebridUpdateLock = new(1, 1);
|
private static readonly SemaphoreSlim RealDebridUpdateLock = new(1, 1);
|
||||||
|
|
@ -41,6 +42,7 @@ public class Torrents(
|
||||||
Provider.Premiumize => premiumizeTorrentClient,
|
Provider.Premiumize => premiumizeTorrentClient,
|
||||||
Provider.RealDebrid => realDebridTorrentClient,
|
Provider.RealDebrid => realDebridTorrentClient,
|
||||||
Provider.AllDebrid => allDebridTorrentClient,
|
Provider.AllDebrid => allDebridTorrentClient,
|
||||||
|
Provider.DebridLink => debridLinkClient,
|
||||||
Provider.TorBox => torBoxTorrentClient,
|
Provider.TorBox => torBoxTorrentClient,
|
||||||
_ => throw new("Invalid Provider")
|
_ => throw new("Invalid Provider")
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -29,15 +29,15 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="9.0.1" />
|
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="9.0.1" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.1">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.2">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.2" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.2" />
|
||||||
<PackageReference Include="Serilog" Version="4.2.0" />
|
<PackageReference Include="Serilog" Version="4.2.0" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue