Add Premiumize support.
This commit is contained in:
parent
3974189c5e
commit
998ddb05ac
19 changed files with 385 additions and 62 deletions
|
|
@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [2.0.22] - 2023-03-11
|
||||||
|
### Added
|
||||||
|
- Add support for Premiumize
|
||||||
|
|
||||||
## [2.0.21] - 2023-03-09
|
## [2.0.21] - 2023-03-09
|
||||||
### Changed
|
### Changed
|
||||||
- Fixed docker build by pinning the .NET version to LTS.
|
- Fixed docker build by pinning the .NET version to LTS.
|
||||||
|
|
|
||||||
14
README.md
14
README.md
|
|
@ -1,18 +1,20 @@
|
||||||
# Real-Debrid Torrent Client
|
# Real-Debrid Torrent Client
|
||||||
|
|
||||||
This is a web interface to manage your torrents on Real-Debrid or AllDebrid. It supports the following features:
|
This is a web interface to manage your torrents on Real-Debrid, AllDebrid or Premiumize. It supports the following features:
|
||||||
|
|
||||||
- Add new torrents through magnets or files
|
- Add new torrents through magnets or files
|
||||||
- Download all files from Real-Debrid or AllDebrid to your local machine automatically
|
- Download all files from Real-Debrid, AllDebrid or Premiumize to your local machine automatically
|
||||||
- Unpack all files when finished downloading
|
- Unpack all files when finished downloading
|
||||||
- Implements a fake qBittorrent API so you can hook up other applications like Sonarr, Radarr or Couchpotato.
|
- Implements a fake qBittorrent API so you can hook up other applications like Sonarr, Radarr or Couchpotato.
|
||||||
- Built with Angular 14 and .NET 6
|
- Built with Angular 15 and .NET 6
|
||||||
|
|
||||||
**You will need a Premium service at Real-Debrid or AllDebrid!**
|
**You will need a Premium service at Real-Debrid, AllDebrid or Premiumize!**
|
||||||
|
|
||||||
[Click here to sign up at Real-Debrid.](https://real-debrid.com/?id=1348683)
|
[Click here to sign up for Real-Debrid.](https://real-debrid.com/?id=1348683)
|
||||||
|
|
||||||
[Click here to sign up AllDebrid.](https://alldebrid.com/?uid=2v91l)
|
[Click here to sign up for AllDebrid.](https://alldebrid.com/?uid=2v91l)
|
||||||
|
|
||||||
|
[Click here to sign up for Premiumize.](https://www.premiumize.me/)
|
||||||
|
|
||||||
<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>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">Post Torrent Download Action</label>
|
<label class="label">Post Torrent Download Action</label>
|
||||||
<div class="control select is-fullwidth">
|
<div class="control select is-fullwidth">
|
||||||
<select [(ngModel)]="downloadAction" [disabled]="provider === 'AllDebrid'">
|
<select [(ngModel)]="downloadAction" [disabled]="provider === 'AllDebrid' || provider === 'Premiumize'">
|
||||||
<option [ngValue]="0">Download all files</option>
|
<option [ngValue]="0">Download all files</option>
|
||||||
<option [ngValue]="1">Download all available files</option>
|
<option [ngValue]="1">Download all available files</option>
|
||||||
<option [ngValue]="2">Manually pick files</option>
|
<option [ngValue]="2">Manually pick files</option>
|
||||||
|
|
@ -61,7 +61,7 @@
|
||||||
</div>
|
</div>
|
||||||
<p class="help">When a torrent is fully downloaded on the provider, perform this action.</p>
|
<p class="help">When a torrent is fully downloaded on the provider, perform this action.</p>
|
||||||
<p class="help" *ngIf="provider === 'AllDebrid'">
|
<p class="help" *ngIf="provider === 'AllDebrid'">
|
||||||
This option is only available for RealDebrid. AllDebrid will always download the full torrent.
|
This option is only available for RealDebrid. AllDebrid and Premiumize will always download the full torrent.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
<a class="navbar-item" routerLink="profile"> Profile </a>
|
<a class="navbar-item" routerLink="profile"> Profile </a>
|
||||||
<a class="navbar-item" (click)="logout()"> Logout </a>
|
<a class="navbar-item" (click)="logout()"> Logout </a>
|
||||||
<hr class="navbar-divider" />
|
<hr class="navbar-divider" />
|
||||||
<div class="navbar-item">Version 2.0.21</div>
|
<div class="navbar-item">Version 2.0.22</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,9 @@ export class NavbarComponent implements OnInit {
|
||||||
case 'AllDebrid':
|
case 'AllDebrid':
|
||||||
this.providerLink = 'https://alldebrid.com/?uid=2v91l&lang=en';
|
this.providerLink = 'https://alldebrid.com/?uid=2v91l&lang=en';
|
||||||
break;
|
break;
|
||||||
|
case 'Premiumize':
|
||||||
|
this.providerLink = 'https://www.premiumize.me/';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,10 @@
|
||||||
<a href="https://alldebrid.com/?uid=2v91l&lang=en" target="_blank" rel="noopener"
|
<a href="https://alldebrid.com/?uid=2v91l&lang=en" target="_blank" rel="noopener"
|
||||||
>Use this link to sign up to AllDebrid.</a
|
>Use this link to sign up to AllDebrid.</a
|
||||||
>
|
>
|
||||||
|
<br />
|
||||||
|
<a href="https://www.premiumize.me/" target="_blank" rel="noopener"
|
||||||
|
>Use this link to sign up to Premiumize.</a
|
||||||
|
>
|
||||||
<br />
|
<br />
|
||||||
<small>(Referal links)</small>
|
<small>(Referal links)</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -60,6 +64,7 @@
|
||||||
<select [(ngModel)]="provider">
|
<select [(ngModel)]="provider">
|
||||||
<option [value]="0">Real-Debrid</option>
|
<option [value]="0">Real-Debrid</option>
|
||||||
<option [value]="1">AllDebrid</option>
|
<option [value]="1">AllDebrid</option>
|
||||||
|
<option [value]="2">Premiumize</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -79,6 +84,12 @@
|
||||||
<a href="https://alldebrid.com/apikeys/" target="_blank" rel="noopener"
|
<a href="https://alldebrid.com/apikeys/" target="_blank" rel="noopener"
|
||||||
>https://alldebrid.com/apikeys/</a
|
>https://alldebrid.com/apikeys/</a
|
||||||
>.
|
>.
|
||||||
|
</p>
|
||||||
|
<p class="help" *ngIf="provider === 'Premiumize'">
|
||||||
|
You can find your API key here:
|
||||||
|
<a href="https://www.premiumize.me/account" target="_blank" rel="noopener"
|
||||||
|
>https://www.premiumize.me/account</a
|
||||||
|
>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "rdt-client",
|
"name": "rdt-client",
|
||||||
"version": "2.0.21",
|
"version": "2.0.22",
|
||||||
"description": "This is a web interface to manage your torrents on Real-Debrid.",
|
"description": "This is a web interface to manage your torrents on Real-Debrid.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
||||||
|
|
@ -8,5 +8,8 @@ public enum Provider
|
||||||
RealDebrid,
|
RealDebrid,
|
||||||
|
|
||||||
[Description("AllDebrid")]
|
[Description("AllDebrid")]
|
||||||
AllDebrid
|
AllDebrid,
|
||||||
|
|
||||||
|
[Description("Premiumize")]
|
||||||
|
Premiumize
|
||||||
}
|
}
|
||||||
|
|
@ -123,6 +123,7 @@ public class DbSettingsProvider
|
||||||
[Description(@"The following 2 providers are supported:
|
[Description(@"The following 2 providers are supported:
|
||||||
<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>
|
||||||
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;
|
||||||
|
|
||||||
|
|
@ -130,15 +131,17 @@ At this point only 1 provider can be used at the time.")]
|
||||||
[Description(@"You can find your API key here:
|
[Description(@"You can find your API key here:
|
||||||
<a href=""https://real-debrid.com/apitoken"" target=""_blank"" rel=""noopener"">https://real-debrid.com/apitoken</a>
|
<a href=""https://real-debrid.com/apitoken"" target=""_blank"" rel=""noopener"">https://real-debrid.com/apitoken</a>
|
||||||
or
|
or
|
||||||
<a href=""https://alldebrid.com/apikeys/"" target=""_blank"" rel=""noopener"">https://alldebrid.com/apikeys/</a>.")]
|
<a href=""""https://alldebrid.com/apikeys/"""" target=""""_blank"""" rel=""""noopener"""">https://alldebrid.com/apikeys/</a>
|
||||||
|
or
|
||||||
|
<a href=""https://www.premiumize.me/account/"" target=""_blank"" rel=""noopener"">https://www.premiumize.me/account/</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")]
|
||||||
[Description("When selected, import downloads that are not added through RealDebridClient but have been directly added to Real-Debrid or AllDebrid.")]
|
[Description("When selected, import downloads that are not added through RealDebridClient but have been directly added to Real-Debrid, AllDebrid or Premiumize.")]
|
||||||
public Boolean AutoImport { get; set; } = false;
|
public Boolean AutoImport { get; set; } = false;
|
||||||
|
|
||||||
[DisplayName("Automatically delete downloads removed from provider")]
|
[DisplayName("Automatically delete downloads removed from provider")]
|
||||||
[Description("When selected, cancel and delete downloads that have been removed from Real-Debrid or AllDebrid.")]
|
[Description("When selected, cancel and delete downloads that have been removed from Real-Debrid, AllDebrid or Premiumize.")]
|
||||||
public Boolean AutoDelete { get; set; } = false;
|
public Boolean AutoDelete { get; set; } = false;
|
||||||
|
|
||||||
[DisplayName("Connection Timeout")]
|
[DisplayName("Connection Timeout")]
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,17 @@ public class TorrentClientTorrent
|
||||||
{
|
{
|
||||||
public String Id { get; set; } = default!;
|
public String Id { get; set; } = default!;
|
||||||
public String Filename { get; set; } = default!;
|
public String Filename { get; set; } = default!;
|
||||||
public String? OriginalFilename { get; set; } = default!;
|
public String? OriginalFilename { get; set; }
|
||||||
public String Hash { get; set; } = default!;
|
public String Hash { get; set; } = default!;
|
||||||
public Int64 Bytes { get; set; }
|
public Int64 Bytes { get; set; }
|
||||||
public Int64 OriginalBytes { get; set; }
|
public Int64 OriginalBytes { get; set; }
|
||||||
public String? Host { get; set; }
|
public String? Host { get; set; }
|
||||||
public Int64 Split { get; set; }
|
public Int64 Split { get; set; }
|
||||||
public Int64 Progress { get; set; }
|
public Int64 Progress { get; set; }
|
||||||
public String? Status { get; set; } = default!;
|
public String? Status { get; set; }
|
||||||
|
public String? Message { get; set; }
|
||||||
public Int64 StatusCode { get; set; }
|
public Int64 StatusCode { get; set; }
|
||||||
public DateTimeOffset Added { get; set; }
|
public DateTimeOffset? Added { get; set; }
|
||||||
public List<TorrentClientFile>? Files { get; set; }
|
public List<TorrentClientFile>? Files { get; set; }
|
||||||
public List<String>? Links { get; set; }
|
public List<String>? Links { get; set; }
|
||||||
public DateTimeOffset? Ended { get; set; }
|
public DateTimeOffset? Ended { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ public static class DiConfig
|
||||||
services.AddScoped<AllDebridTorrentClient>();
|
services.AddScoped<AllDebridTorrentClient>();
|
||||||
services.AddScoped<Authentication>();
|
services.AddScoped<Authentication>();
|
||||||
services.AddScoped<Downloads>();
|
services.AddScoped<Downloads>();
|
||||||
|
services.AddScoped<PremiumizeTorrentClient>();
|
||||||
services.AddScoped<QBittorrent>();
|
services.AddScoped<QBittorrent>();
|
||||||
services.AddScoped<RemoteService>();
|
services.AddScoped<RemoteService>();
|
||||||
services.AddScoped<RealDebridTorrentClient>();
|
services.AddScoped<RealDebridTorrentClient>();
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,12 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||||
<PackageReference Include="AllDebrid.NET" Version="1.0.10" />
|
<PackageReference Include="AllDebrid.NET" Version="1.0.12" />
|
||||||
<PackageReference Include="Aria2.NET" Version="1.0.5" />
|
<PackageReference Include="Aria2.NET" Version="1.0.5" />
|
||||||
<PackageReference Include="Downloader" Version="3.0.3" />
|
<PackageReference Include="Downloader" Version="3.0.4" />
|
||||||
<PackageReference Include="MonoTorrent" Version="2.0.7" />
|
<PackageReference Include="MonoTorrent" Version="2.0.7" />
|
||||||
<PackageReference Include="RD.NET" Version="2.1.3" />
|
<PackageReference Include="Premiumize.NET" Version="1.0.1" />
|
||||||
|
<PackageReference Include="RD.NET" Version="2.1.4" />
|
||||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.32.2" />
|
<PackageReference Include="SharpCompress" Version="0.32.2" />
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
using AllDebridNET;
|
using AllDebridNET;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using RDNET;
|
|
||||||
using RDNET.Exceptions;
|
|
||||||
using RdtClient.Data.Enums;
|
using RdtClient.Data.Enums;
|
||||||
using RdtClient.Data.Models.TorrentClient;
|
using RdtClient.Data.Models.TorrentClient;
|
||||||
using RdtClient.Service.Helpers;
|
using RdtClient.Service.Helpers;
|
||||||
|
|
@ -36,19 +34,19 @@ public class AllDebridTorrentClient : ITorrentClient
|
||||||
var httpClient = _httpClientFactory.CreateClient();
|
var httpClient = _httpClientFactory.CreateClient();
|
||||||
httpClient.Timeout = TimeSpan.FromSeconds(10);
|
httpClient.Timeout = TimeSpan.FromSeconds(10);
|
||||||
|
|
||||||
var allDebridNetClient = new AllDebridNETClient("RealDebridClient", apiKey);
|
var allDebridNetClient = new AllDebridNETClient("RealDebridClient", apiKey, httpClient);
|
||||||
|
|
||||||
return allDebridNetClient;
|
return allDebridNetClient;
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
|
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, $"The connection to RealDebrid has timed out: {ex.Message}");
|
_logger.LogError(ex, $"The connection to AllDebrid has timed out: {ex.Message}");
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException ex)
|
catch (TaskCanceledException ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, $"The connection to RealDebrid has timed out: {ex.Message}");
|
_logger.LogError(ex, $"The connection to AllDebrid has timed out: {ex.Message}");
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
@ -152,7 +150,7 @@ public class AllDebridTorrentClient : ITorrentClient
|
||||||
{
|
{
|
||||||
return new List<TorrentClientAvailableFile>
|
return new List<TorrentClientAvailableFile>
|
||||||
{
|
{
|
||||||
new TorrentClientAvailableFile
|
new()
|
||||||
{
|
{
|
||||||
Filename = "All files",
|
Filename = "All files",
|
||||||
Filesize = 0
|
Filesize = 0
|
||||||
|
|
@ -168,18 +166,6 @@ public class AllDebridTorrentClient : ITorrentClient
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TorrentClientTorrent> GetInfo(String torrentId)
|
|
||||||
{
|
|
||||||
var result = await GetClient().Magnet.StatusAsync(torrentId);
|
|
||||||
|
|
||||||
if (result == null)
|
|
||||||
{
|
|
||||||
throw new Exception($"Unable to find magnet with ID {torrentId}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Map(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(String torrentId)
|
public async Task Delete(String torrentId)
|
||||||
{
|
{
|
||||||
await GetClient().Magnet.DeleteAsync(torrentId);
|
await GetClient().Magnet.DeleteAsync(torrentId);
|
||||||
|
|
@ -260,17 +246,6 @@ public class AllDebridTorrentClient : ITorrentClient
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (RealDebridException ex)
|
|
||||||
{
|
|
||||||
if (ex.ErrorCode == 7)
|
|
||||||
{
|
|
||||||
torrent.RdStatusRaw = "deleted";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return torrent;
|
return torrent;
|
||||||
}
|
}
|
||||||
|
|
@ -326,6 +301,18 @@ public class AllDebridTorrentClient : ITorrentClient
|
||||||
return links.Select(m => m.LinkUrl.ToString()).ToList();
|
return links.Select(m => m.LinkUrl.ToString()).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<TorrentClientTorrent> GetInfo(String torrentId)
|
||||||
|
{
|
||||||
|
var result = await GetClient().Magnet.StatusAsync(torrentId);
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Unable to find magnet with ID {torrentId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Map(result);
|
||||||
|
}
|
||||||
|
|
||||||
private static IEnumerable<String> GetFiles(IList<File> files, String parent)
|
private static IEnumerable<String> GetFiles(IList<File> files, String parent)
|
||||||
{
|
{
|
||||||
var result = new List<String>();
|
var result = new List<String>();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,278 @@
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using PremiumizeNET;
|
||||||
|
using RdtClient.Data.Enums;
|
||||||
|
using RdtClient.Data.Models.TorrentClient;
|
||||||
|
using RdtClient.Service.Helpers;
|
||||||
|
using Torrent = RdtClient.Data.Models.Data.Torrent;
|
||||||
|
|
||||||
|
namespace RdtClient.Service.Services.TorrentClients;
|
||||||
|
|
||||||
|
public class PremiumizeTorrentClient : ITorrentClient
|
||||||
|
{
|
||||||
|
private readonly ILogger<PremiumizeTorrentClient> _logger;
|
||||||
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
|
||||||
|
public PremiumizeTorrentClient(ILogger<PremiumizeTorrentClient> logger, IHttpClientFactory httpClientFactory)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_httpClientFactory = httpClientFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PremiumizeNETClient GetClient()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var apiKey = Settings.Get.Provider.ApiKey;
|
||||||
|
|
||||||
|
if (String.IsNullOrWhiteSpace(apiKey))
|
||||||
|
{
|
||||||
|
throw new Exception("Premiumize API Key not set in the settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpClient = _httpClientFactory.CreateClient();
|
||||||
|
httpClient.Timeout = TimeSpan.FromSeconds(10);
|
||||||
|
|
||||||
|
var premiumizeNetClient = new PremiumizeNETClient(apiKey, httpClient);
|
||||||
|
|
||||||
|
return premiumizeNetClient;
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"The connection to Premiumize has timed out: {ex.Message}");
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"The connection to Premiumize has timed out: {ex.Message}");
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TorrentClientTorrent Map(Transfer transfer)
|
||||||
|
{
|
||||||
|
return new TorrentClientTorrent
|
||||||
|
{
|
||||||
|
Id = transfer.Id,
|
||||||
|
Filename = transfer.Name,
|
||||||
|
OriginalFilename = transfer.Name,
|
||||||
|
Hash = transfer.Src,
|
||||||
|
Bytes = 0,
|
||||||
|
OriginalBytes = 0,
|
||||||
|
Host = null,
|
||||||
|
Split = 0,
|
||||||
|
Progress = (Int64) ((transfer.Progress ?? 1.0) * 100.0),
|
||||||
|
Status = transfer.Status,
|
||||||
|
Message = transfer.Message,
|
||||||
|
StatusCode = 0,
|
||||||
|
Added = null,
|
||||||
|
Files = new List<TorrentClientFile>(),
|
||||||
|
Links = new List<String>
|
||||||
|
{
|
||||||
|
transfer.FolderId
|
||||||
|
},
|
||||||
|
Ended = null,
|
||||||
|
Speed = 0,
|
||||||
|
Seeders = 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IList<TorrentClientTorrent>> GetTorrents()
|
||||||
|
{
|
||||||
|
var results = await GetClient().Transfers.ListAsync();
|
||||||
|
return results.Select(Map).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TorrentClientUser> GetUser()
|
||||||
|
{
|
||||||
|
var user = await GetClient().Account.InfoAsync();
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Unable to get user");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TorrentClientUser
|
||||||
|
{
|
||||||
|
Username = user.CustomerId.ToString(),
|
||||||
|
Expiration = user.PremiumUntil > 0 ? new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(user.PremiumUntil.Value) : null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<String> AddMagnet(String magnetLink)
|
||||||
|
{
|
||||||
|
var result = await GetClient().Transfers.CreateAsync(magnetLink, "");
|
||||||
|
|
||||||
|
if (result?.Id == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Unable to add magnet link");
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultId = result.Id;
|
||||||
|
|
||||||
|
if (resultId == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid responseID {result.Id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<String> AddFile(Byte[] bytes)
|
||||||
|
{
|
||||||
|
var result = await GetClient().Transfers.CreateAsync(bytes, "");
|
||||||
|
|
||||||
|
if (result?.Id == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Unable to add torrent file");
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultId = result.Id;
|
||||||
|
|
||||||
|
if (resultId == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid responseID {result.Id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<IList<TorrentClientAvailableFile>> GetAvailableFiles(String hash)
|
||||||
|
{
|
||||||
|
var result = new List<TorrentClientAvailableFile>();
|
||||||
|
return Task.FromResult<IList<TorrentClientAvailableFile>>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SelectFiles(Torrent torrent)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Delete(String id)
|
||||||
|
{
|
||||||
|
await GetClient().Transfers.DeleteAsync(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<String> Unrestrict(String link)
|
||||||
|
{
|
||||||
|
return Task.FromResult(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.Status switch
|
||||||
|
{
|
||||||
|
"waiting" => TorrentStatus.Processing,
|
||||||
|
"queued" => TorrentStatus.Processing,
|
||||||
|
"running" => TorrentStatus.Downloading,
|
||||||
|
"seeding" => TorrentStatus.Uploading,
|
||||||
|
"finished" => TorrentStatus.Finished,
|
||||||
|
_ => TorrentStatus.Error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (PremiumizeException ex)
|
||||||
|
{
|
||||||
|
if (ex.Message == "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 transfers = await GetClient().Transfers.ListAsync();
|
||||||
|
var transfer = transfers.FirstOrDefault(m => m.Id == torrent.RdId);
|
||||||
|
|
||||||
|
if (transfer == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String.IsNullOrWhiteSpace(transfer.FolderId))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var zip = await GetClient()
|
||||||
|
.Zip.Generate(new List<String>(),
|
||||||
|
new List<String>
|
||||||
|
{
|
||||||
|
transfer.FolderId
|
||||||
|
});
|
||||||
|
|
||||||
|
return new List<String>
|
||||||
|
{
|
||||||
|
zip
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<TorrentClientTorrent> GetInfo(String id)
|
||||||
|
{
|
||||||
|
var results = await GetClient().Transfers.ListAsync();
|
||||||
|
var result = results.FirstOrDefault(m => m.Id == id);
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Unable to find transfer with ID {id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Map(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Log(String message, Torrent? torrent = null)
|
||||||
|
{
|
||||||
|
if (torrent != null)
|
||||||
|
{
|
||||||
|
message = $"{message} {torrent.ToLog()}";
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogDebug(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -214,13 +214,6 @@ public class RealDebridTorrentClient : ITorrentClient
|
||||||
await GetClient().Torrents.SelectFilesAsync(torrent.RdId!, fileIds.ToArray());
|
await GetClient().Torrents.SelectFilesAsync(torrent.RdId!, fileIds.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TorrentClientTorrent> GetInfo(String torrentId)
|
|
||||||
{
|
|
||||||
var result = await GetClient().Torrents.GetInfoAsync(torrentId);
|
|
||||||
|
|
||||||
return Map(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Delete(String torrentId)
|
public async Task Delete(String torrentId)
|
||||||
{
|
{
|
||||||
await GetClient().Torrents.DeleteAsync(torrentId);
|
await GetClient().Torrents.DeleteAsync(torrentId);
|
||||||
|
|
@ -372,6 +365,13 @@ public class RealDebridTorrentClient : ITorrentClient
|
||||||
return dateTimeOffset?.Subtract(_offset.Value).ToOffset(_offset.Value);
|
return dateTimeOffset?.Subtract(_offset.Value).ToOffset(_offset.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<TorrentClientTorrent> GetInfo(String torrentId)
|
||||||
|
{
|
||||||
|
var result = await GetClient().Torrents.GetInfoAsync(torrentId);
|
||||||
|
|
||||||
|
return Map(result);
|
||||||
|
}
|
||||||
|
|
||||||
private void Log(String message, Data.Models.Data.Torrent? torrent = null)
|
private void Log(String message, Data.Models.Data.Torrent? torrent = null)
|
||||||
{
|
{
|
||||||
if (torrent != null)
|
if (torrent != null)
|
||||||
|
|
|
||||||
|
|
@ -413,7 +413,7 @@ public class TorrentRunner
|
||||||
|
|
||||||
var extension = Path.GetExtension(fileName);
|
var extension = Path.GetExtension(fileName);
|
||||||
|
|
||||||
if (extension != ".rar")
|
if (extension != ".rar" && extension != ".zip")
|
||||||
{
|
{
|
||||||
Log($"No need to unpack, setting it as unpacked", download, torrent);
|
Log($"No need to unpack, setting it as unpacked", download, torrent);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ public class Torrents
|
||||||
TorrentData torrentData,
|
TorrentData torrentData,
|
||||||
Downloads downloads,
|
Downloads downloads,
|
||||||
AllDebridTorrentClient allDebridTorrentClient,
|
AllDebridTorrentClient allDebridTorrentClient,
|
||||||
|
PremiumizeTorrentClient premiumizeTorrentClient,
|
||||||
RealDebridTorrentClient realDebridTorrentClient)
|
RealDebridTorrentClient realDebridTorrentClient)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
@ -40,6 +41,7 @@ public class Torrents
|
||||||
|
|
||||||
_torrentClient = Settings.Get.Provider.Provider switch
|
_torrentClient = Settings.Get.Provider.Provider switch
|
||||||
{
|
{
|
||||||
|
Provider.Premiumize => premiumizeTorrentClient,
|
||||||
Provider.RealDebrid => realDebridTorrentClient,
|
Provider.RealDebrid => realDebridTorrentClient,
|
||||||
Provider.AllDebrid => allDebridTorrentClient,
|
Provider.AllDebrid => allDebridTorrentClient,
|
||||||
_ => throw new Exception("Invalid Provider")
|
_ => throw new Exception("Invalid Provider")
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
using RdtClient.Service.Helpers;
|
using RdtClient.Service.Helpers;
|
||||||
using SharpCompress.Archives;
|
using SharpCompress.Archives;
|
||||||
using SharpCompress.Archives.Rar;
|
using SharpCompress.Archives.Rar;
|
||||||
|
using SharpCompress.Archives.Zip;
|
||||||
using SharpCompress.Common;
|
using SharpCompress.Common;
|
||||||
|
|
||||||
namespace RdtClient.Service.Services;
|
namespace RdtClient.Service.Services;
|
||||||
|
|
@ -21,7 +22,7 @@ public class UnpackClient
|
||||||
|
|
||||||
private Boolean _cancelled;
|
private Boolean _cancelled;
|
||||||
|
|
||||||
private RarArchiveEntry? _rarCurrentEntry;
|
private IArchiveEntry? _rarCurrentEntry;
|
||||||
private Dictionary<String, Int64>? _rarfileStatus;
|
private Dictionary<String, Int64>? _rarfileStatus;
|
||||||
|
|
||||||
public UnpackClient(Download download, String destinationPath)
|
public UnpackClient(Download download, String destinationPath)
|
||||||
|
|
@ -135,7 +136,17 @@ public class UnpackClient
|
||||||
{
|
{
|
||||||
await using Stream stream = File.OpenRead(filePath);
|
await using Stream stream = File.OpenRead(filePath);
|
||||||
|
|
||||||
using var archive = RarArchive.Open(stream);
|
var extension = Path.GetExtension(filePath);
|
||||||
|
|
||||||
|
IArchive archive;
|
||||||
|
if (extension == ".zip")
|
||||||
|
{
|
||||||
|
archive = ZipArchive.Open(stream);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
archive = RarArchive.Open(stream);
|
||||||
|
}
|
||||||
|
|
||||||
BytesTotal = archive.TotalSize;
|
BytesTotal = archive.TotalSize;
|
||||||
|
|
||||||
|
|
@ -144,6 +155,8 @@ public class UnpackClient
|
||||||
.Select(m => m.Key)
|
.Select(m => m.Key)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
archive.Dispose();
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -151,7 +164,19 @@ public class UnpackClient
|
||||||
{
|
{
|
||||||
var parts = ArchiveFactory.GetFileParts(filePath);
|
var parts = ArchiveFactory.GetFileParts(filePath);
|
||||||
|
|
||||||
using var archive = RarArchive.Open(parts.Select(m => new FileInfo(m)));
|
var fi = parts.Select(m => new FileInfo(m));
|
||||||
|
|
||||||
|
var extension = Path.GetExtension(filePath);
|
||||||
|
|
||||||
|
IArchive archive;
|
||||||
|
if (extension == ".zip")
|
||||||
|
{
|
||||||
|
archive = ZipArchive.Open(fi);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
archive = RarArchive.Open(fi);
|
||||||
|
}
|
||||||
|
|
||||||
if (archive.IsComplete)
|
if (archive.IsComplete)
|
||||||
{
|
{
|
||||||
|
|
@ -181,6 +206,8 @@ public class UnpackClient
|
||||||
Overwrite = true
|
Overwrite = true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
archive.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ArchiveOnCompressedBytesRead(Object? sender, CompressedBytesReadEventArgs e)
|
private void ArchiveOnCompressedBytesRead(Object? sender, CompressedBytesReadEventArgs e)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<UserSecretsId>94c24cba-f03f-4453-a671-3640b517c573</UserSecretsId>
|
<UserSecretsId>94c24cba-f03f-4453-a671-3640b517c573</UserSecretsId>
|
||||||
<Version>2.0.21</Version>
|
<Version>2.0.22</Version>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue