Changed the unrestrict process to only unrestrict when the download is starting.

This commit is contained in:
Roger Far 2021-03-10 17:56:54 -07:00
parent e291989ace
commit 5265a8b442
23 changed files with 1095 additions and 102 deletions

View file

@ -1,6 +1,7 @@
export class Download {
public downloadId: string;
public torrentId: string;
public path: string;
public link: string;
public added: Date;
public downloadQueued: Date;

View file

@ -6,8 +6,6 @@ export class Torrent {
public category: string;
public added: Date;
public completed: Date;
public autoDownload: boolean;
public autoUnpack: boolean;
public autoDelete: boolean;
public rdId: string;

View file

@ -37,14 +37,6 @@
</div>
<hr />
<div class="field">
<label class="checkbox">
<input type="checkbox" [(ngModel)]="autoDownload" />
Download torrent to host when finished downloading on Real-Debrid
</label>
<label class="checkbox">
<input type="checkbox" [(ngModel)]="autoUnpack" />
Unpack files after downloading to host
</label>
<label class="checkbox">
<input type="checkbox" [(ngModel)]="autoDelete" />
Remove torrent when finished downloading on host
@ -56,7 +48,30 @@
<button class="button is-success" [disabled]="saving" [ngClass]="{ 'is-loading': saving }" (click)="ok()">
<span>Add Torrent</span>
</button>
<button class="button is-info" [disabled]="saving" [ngClass]="{ 'is-loading': saving }" (click)="checkFiles()">
<span>Check available files</span>
</button>
<button class="button" (click)="cancel()" [disabled]="saving">Cancel</button>
</footer>
</div>
</div>
<div class="modal" [class.is-active]="isFileModalActive">
<div class="modal-background"></div>
<div class="modal-card file-modal">
<header class="modal-card-head">
<p class="modal-card-title">Available Files</p>
<button class="delete" aria-label="close" (click)="isFileModalActive = false"></button>
</header>
<section class="modal-card-body">
<table class="table" style="width: 100%">
<tbody>
<tr *ngFor="let file of fileList">
<td>{{ file }}</td>
</tr>
</tbody>
</table>
</section>
<footer class="modal-card-foot"></footer>
</div>
</div>

View file

@ -2,3 +2,7 @@
max-width: 24em;
width: 24em;
}
.file-modal {
width: calc(75% - 40px);
}

View file

@ -21,13 +21,14 @@ export class AddNewTorrentComponent implements OnInit {
public openChange = new EventEmitter<boolean>();
public isActive = false;
public isFileModalActive = false;
public fileName: string;
public magnetLink: string;
public autoDownload: boolean;
public autoUnpack: boolean;
public autoDelete: boolean;
public fileList: string[];
public saving = false;
public error: string;
@ -41,7 +42,6 @@ export class AddNewTorrentComponent implements OnInit {
this.fileName = '';
this.magnetLink = '';
this.autoDelete = false;
this.autoDownload = true;
this.saving = false;
this.selectedFile = null;
@ -67,7 +67,7 @@ export class AddNewTorrentComponent implements OnInit {
this.error = null;
if (this.magnetLink) {
this.torrentService.uploadMagnet(this.magnetLink, this.autoDownload, this.autoUnpack, this.autoDelete).subscribe(
this.torrentService.uploadMagnet(this.magnetLink, this.autoDelete).subscribe(
() => {
this.cancel();
},
@ -77,7 +77,7 @@ export class AddNewTorrentComponent implements OnInit {
}
);
} else if (this.selectedFile) {
this.torrentService.uploadFile(this.selectedFile, this.autoDownload, this.autoUnpack, this.autoDelete).subscribe(
this.torrentService.uploadFile(this.selectedFile, this.autoDelete).subscribe(
() => {
this.cancel();
},
@ -91,6 +91,39 @@ export class AddNewTorrentComponent implements OnInit {
}
}
public checkFiles(): void {
this.saving = true;
this.error = null;
if (this.magnetLink) {
this.torrentService.checkFilesMagnet(this.magnetLink).subscribe(
(result) => {
this.saving = false;
this.isFileModalActive = true;
this.fileList = result;
},
(err) => {
this.error = err.error;
this.saving = false;
}
);
} else if (this.selectedFile) {
this.torrentService.checkFiles(this.selectedFile).subscribe(
(result) => {
this.saving = false;
this.isFileModalActive = true;
this.fileList = result;
},
(err) => {
this.error = err.error;
this.saving = false;
}
);
} else {
this.cancel();
}
}
public cancel(): void {
this.isActive = false;
this.openChange.emit(this.open);

View file

@ -1,6 +1,7 @@
<td colspan="4">
<i class="fas fa-download" aria-hidden="true"></i>
{{ download.link }}
<span *ngIf="download.link">{{ download.link }}</span>
<span *ngIf="!download.link">{{ download.path }}</span>
</td>
<td>
{{ download.bytesTotal | filesize }}

View file

@ -6,8 +6,6 @@
{{ torrent.downloads.length | number }}
</td>
<td class="auto">
<i class="fas fa-download" *ngIf="torrent.autoDownload" title="Auto download"></i>
<i class="fas fa-box-open" *ngIf="torrent.autoUnpack" title="Auto unpack"></i>
<i class="fas fa-trash" *ngIf="torrent.autoDelete" title="Auto delete"></i>
</td>
<td>

View file

@ -31,27 +31,32 @@ export class TorrentService {
return this.http.get<Torrent[]>(`/Api/Torrents`);
}
public uploadMagnet(
magnetLink: string,
autoDownload: boolean,
autoUnpack: boolean,
autoDelete: boolean
): Observable<void> {
public uploadMagnet(magnetLink: string, autoDelete: boolean): Observable<void> {
return this.http.post<void>(`/Api/Torrents/UploadMagnet`, {
magnetLink,
autoDownload,
autoUnpack,
autoDelete,
});
}
public uploadFile(file: File, autoDownload: boolean, autoUnpack: boolean, autoDelete: boolean): Observable<void> {
public uploadFile(file: File, autoDelete: boolean): Observable<void> {
const formData: FormData = new FormData();
formData.append('file', file);
formData.append('formData', JSON.stringify({ autoDownload, autoUnpack, autoDelete }));
formData.append('formData', JSON.stringify({ autoDelete }));
return this.http.post<void>(`/Api/Torrents/UploadFile`, formData);
}
public checkFilesMagnet(magnetLink: string): Observable<string[]> {
return this.http.post<string[]>(`/Api/Torrents/CheckFilesMagnet`, {
magnetLink,
});
}
public checkFiles(file: File): Observable<string[]> {
const formData: FormData = new FormData();
formData.append('file', file);
return this.http.post<string[]>(`/Api/Torrents/CheckFiles`, formData);
}
public download(torrentId: string): Observable<void> {
return this.http.get<void>(`/Api/Torrents/Download/${torrentId}`);
}

View file

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using RdtClient.Data.Models.Data;
using Download = RdtClient.Data.Models.Data.Download;
namespace RdtClient.Data.Data
{
@ -12,7 +12,8 @@ namespace RdtClient.Data.Data
Task<IList<Download>> Get();
Task<IList<Download>> GetForTorrent(Guid torrentId);
Task<Download> GetById(Guid downloadId);
Task<Download> Add(Guid torrentId, String link);
Task<Download> Add(Guid torrentId, String path);
Task UpdateUnrestrictedLink(Guid downloadId, String unrestrictedLink);
Task UpdateDownloadStarted(Guid downloadId, DateTimeOffset? dateTime);
Task UpdateDownloadFinished(Guid downloadId, DateTimeOffset? dateTime);
Task UpdateUnpackingQueued(Guid downloadId, DateTimeOffset? dateTime);
@ -56,13 +57,13 @@ namespace RdtClient.Data.Data
.FirstOrDefaultAsync(m => m.DownloadId == downloadId);
}
public async Task<Download> Add(Guid torrentId, String link)
public async Task<Download> Add(Guid torrentId, String path)
{
var download = new Download
{
DownloadId = Guid.NewGuid(),
TorrentId = torrentId,
Link = link,
Path = path,
Added = DateTimeOffset.UtcNow,
DownloadQueued = DateTimeOffset.UtcNow
};
@ -73,7 +74,17 @@ namespace RdtClient.Data.Data
return download;
}
public async Task UpdateUnrestrictedLink(Guid downloadId, String unrestrictedLink)
{
var dbDownload = await _dataContext.Downloads
.FirstOrDefaultAsync(m => m.DownloadId == downloadId);
dbDownload.Link = unrestrictedLink;
await _dataContext.SaveChangesAsync();
}
public async Task UpdateDownloadStarted(Guid downloadId, DateTimeOffset? dateTime)
{
var dbDownload = await _dataContext.Downloads

View file

@ -12,7 +12,7 @@ namespace RdtClient.Data.Data
Task<IList<Torrent>> Get();
Task<Torrent> GetById(Guid torrentId);
Task<Torrent> GetByHash(String hash);
Task<Torrent> Add(String realDebridId, String hash, String category, Boolean autoDownload, Boolean autoUnpack, Boolean autoDelete);
Task<Torrent> Add(String realDebridId, String hash, String category, Boolean autoDelete);
Task UpdateRdData(Torrent torrent);
Task UpdateCategory(Guid torrentId, String category);
Task UpdateComplete(Guid torrentId, DateTimeOffset datetime);
@ -78,7 +78,7 @@ namespace RdtClient.Data.Data
return dbTorrent;
}
public async Task<Torrent> Add(String realDebridId, String hash, String category, Boolean autoDownload, Boolean autoUnpack, Boolean autoDelete)
public async Task<Torrent> Add(String realDebridId, String hash, String category, Boolean autoDelete)
{
var torrent = new Torrent
{
@ -87,8 +87,6 @@ namespace RdtClient.Data.Data
RdId = realDebridId,
Hash = hash.ToLower(),
Category = category,
AutoDownload = autoDownload,
AutoUnpack = autoUnpack,
AutoDelete = autoDelete
};

View file

@ -0,0 +1,418 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using RdtClient.Data.Data;
namespace RdtClient.Data.Migrations
{
[DbContext(typeof(DataContext))]
[Migration("20210311002748_Downloads_Add_Path")]
partial class Downloads_Add_Path
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.3");
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("RdtClient.Data.Models.Data.Download", b =>
{
b.Property<Guid>("DownloadId")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("Added")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("Completed")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("DownloadFinished")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("DownloadQueued")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("DownloadStarted")
.HasColumnType("TEXT");
b.Property<string>("Error")
.HasColumnType("TEXT");
b.Property<string>("Link")
.HasColumnType("TEXT");
b.Property<string>("Path")
.HasColumnType("TEXT");
b.Property<Guid>("TorrentId")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("UnpackingFinished")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("UnpackingQueued")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("UnpackingStarted")
.HasColumnType("TEXT");
b.HasKey("DownloadId");
b.HasIndex("TorrentId");
b.ToTable("Downloads");
});
modelBuilder.Entity("RdtClient.Data.Models.Data.Setting", b =>
{
b.Property<string>("SettingId")
.HasColumnType("TEXT");
b.Property<string>("Type")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("SettingId");
b.ToTable("Settings");
});
modelBuilder.Entity("RdtClient.Data.Models.Data.Torrent", b =>
{
b.Property<Guid>("TorrentId")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("Added")
.HasColumnType("TEXT");
b.Property<bool>("AutoDelete")
.HasColumnType("INTEGER");
b.Property<bool>("AutoDownload")
.HasColumnType("INTEGER");
b.Property<bool>("AutoUnpack")
.HasColumnType("INTEGER");
b.Property<string>("Category")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("Completed")
.HasColumnType("TEXT");
b.Property<string>("Hash")
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("RdAdded")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("RdEnded")
.HasColumnType("TEXT");
b.Property<string>("RdFiles")
.HasColumnType("TEXT");
b.Property<string>("RdHost")
.HasColumnType("TEXT");
b.Property<string>("RdId")
.HasColumnType("TEXT");
b.Property<string>("RdName")
.HasColumnType("TEXT");
b.Property<long>("RdProgress")
.HasColumnType("INTEGER");
b.Property<long?>("RdSeeders")
.HasColumnType("INTEGER");
b.Property<long>("RdSize")
.HasColumnType("INTEGER");
b.Property<long?>("RdSpeed")
.HasColumnType("INTEGER");
b.Property<long>("RdSplit")
.HasColumnType("INTEGER");
b.Property<int>("RdStatus")
.HasColumnType("INTEGER");
b.Property<string>("RdStatusRaw")
.HasColumnType("TEXT");
b.HasKey("TorrentId");
b.ToTable("Torrents");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("RdtClient.Data.Models.Data.Download", b =>
{
b.HasOne("RdtClient.Data.Models.Data.Torrent", "Torrent")
.WithMany("Downloads")
.HasForeignKey("TorrentId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Torrent");
});
modelBuilder.Entity("RdtClient.Data.Models.Data.Torrent", b =>
{
b.Navigation("Downloads");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace RdtClient.Data.Migrations
{
public partial class Downloads_Add_Path : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Path",
table: "Downloads",
type: "TEXT",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Path",
table: "Downloads");
}
}
}

View file

@ -0,0 +1,412 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using RdtClient.Data.Data;
namespace RdtClient.Data.Migrations
{
[DbContext(typeof(DataContext))]
[Migration("20210311005539_Torrents_Removed_Auto")]
partial class Torrents_Removed_Auto
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.3");
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<int>("AccessFailedCount")
.HasColumnType("INTEGER");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("TEXT");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<bool>("EmailConfirmed")
.HasColumnType("INTEGER");
b.Property<bool>("LockoutEnabled")
.HasColumnType("INTEGER");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("TEXT");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<string>("PasswordHash")
.HasColumnType("TEXT");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("INTEGER");
b.Property<string>("SecurityStamp")
.HasColumnType("TEXT");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("INTEGER");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("ClaimType")
.HasColumnType("TEXT");
b.Property<string>("ClaimValue")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("TEXT");
b.Property<string>("ProviderKey")
.HasColumnType("TEXT");
b.Property<string>("ProviderDisplayName")
.HasColumnType("TEXT");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("RoleId")
.HasColumnType("TEXT");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId")
.HasColumnType("TEXT");
b.Property<string>("LoginProvider")
.HasColumnType("TEXT");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("RdtClient.Data.Models.Data.Download", b =>
{
b.Property<Guid>("DownloadId")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("Added")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("Completed")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("DownloadFinished")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("DownloadQueued")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("DownloadStarted")
.HasColumnType("TEXT");
b.Property<string>("Error")
.HasColumnType("TEXT");
b.Property<string>("Link")
.HasColumnType("TEXT");
b.Property<string>("Path")
.HasColumnType("TEXT");
b.Property<Guid>("TorrentId")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("UnpackingFinished")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("UnpackingQueued")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("UnpackingStarted")
.HasColumnType("TEXT");
b.HasKey("DownloadId");
b.HasIndex("TorrentId");
b.ToTable("Downloads");
});
modelBuilder.Entity("RdtClient.Data.Models.Data.Setting", b =>
{
b.Property<string>("SettingId")
.HasColumnType("TEXT");
b.Property<string>("Type")
.HasColumnType("TEXT");
b.Property<string>("Value")
.HasColumnType("TEXT");
b.HasKey("SettingId");
b.ToTable("Settings");
});
modelBuilder.Entity("RdtClient.Data.Models.Data.Torrent", b =>
{
b.Property<Guid>("TorrentId")
.ValueGeneratedOnAdd()
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("Added")
.HasColumnType("TEXT");
b.Property<bool>("AutoDelete")
.HasColumnType("INTEGER");
b.Property<string>("Category")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("Completed")
.HasColumnType("TEXT");
b.Property<string>("Hash")
.HasColumnType("TEXT");
b.Property<DateTimeOffset>("RdAdded")
.HasColumnType("TEXT");
b.Property<DateTimeOffset?>("RdEnded")
.HasColumnType("TEXT");
b.Property<string>("RdFiles")
.HasColumnType("TEXT");
b.Property<string>("RdHost")
.HasColumnType("TEXT");
b.Property<string>("RdId")
.HasColumnType("TEXT");
b.Property<string>("RdName")
.HasColumnType("TEXT");
b.Property<long>("RdProgress")
.HasColumnType("INTEGER");
b.Property<long?>("RdSeeders")
.HasColumnType("INTEGER");
b.Property<long>("RdSize")
.HasColumnType("INTEGER");
b.Property<long?>("RdSpeed")
.HasColumnType("INTEGER");
b.Property<long>("RdSplit")
.HasColumnType("INTEGER");
b.Property<int>("RdStatus")
.HasColumnType("INTEGER");
b.Property<string>("RdStatusRaw")
.HasColumnType("TEXT");
b.HasKey("TorrentId");
b.ToTable("Torrents");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("RdtClient.Data.Models.Data.Download", b =>
{
b.HasOne("RdtClient.Data.Models.Data.Torrent", "Torrent")
.WithMany("Downloads")
.HasForeignKey("TorrentId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.Navigation("Torrent");
});
modelBuilder.Entity("RdtClient.Data.Models.Data.Torrent", b =>
{
b.Navigation("Downloads");
});
#pragma warning restore 612, 618
}
}
}

View file

@ -0,0 +1,35 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace RdtClient.Data.Migrations
{
public partial class Torrents_Removed_Auto : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AutoDownload",
table: "Torrents");
migrationBuilder.DropColumn(
name: "AutoUnpack",
table: "Torrents");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "AutoDownload",
table: "Torrents",
type: "INTEGER",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "AutoUnpack",
table: "Torrents",
type: "INTEGER",
nullable: false,
defaultValue: false);
}
}
}

View file

@ -14,7 +14,7 @@ namespace RdtClient.Data.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "5.0.1");
.HasAnnotation("ProductVersion", "5.0.3");
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
@ -235,6 +235,9 @@ namespace RdtClient.Data.Migrations
b.Property<string>("Link")
.HasColumnType("TEXT");
b.Property<string>("Path")
.HasColumnType("TEXT");
b.Property<Guid>("TorrentId")
.HasColumnType("TEXT");
@ -282,12 +285,6 @@ namespace RdtClient.Data.Migrations
b.Property<bool>("AutoDelete")
.HasColumnType("INTEGER");
b.Property<bool>("AutoDownload")
.HasColumnType("INTEGER");
b.Property<bool>("AutoUnpack")
.HasColumnType("INTEGER");
b.Property<string>("Category")
.HasColumnType("TEXT");

View file

@ -11,6 +11,8 @@ namespace RdtClient.Data.Models.Data
public Guid TorrentId { get; set; }
public String Path { get; set; }
public String Link { get; set; }
public DateTimeOffset Added { get; set; }

View file

@ -20,8 +20,6 @@ namespace RdtClient.Data.Models.Data
public DateTimeOffset Added { get; set; }
public DateTimeOffset? Completed { get; set; }
public Boolean AutoDownload { get; set; }
public Boolean AutoUnpack { get; set; }
public Boolean AutoDelete { get; set; }
[InverseProperty("Torrent")]

View file

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using RdtClient.Data.Data;
using RdtClient.Data.Models.Data;
using Download = RdtClient.Data.Models.Data.Download;
namespace RdtClient.Service.Services
{
@ -12,6 +12,7 @@ namespace RdtClient.Service.Services
Task<IList<Download>> GetForTorrent(Guid torrentId);
Task<Download> GetById(Guid downloadId);
Task<Download> Add(Guid torrentId, String link);
Task UpdateUnrestrictedLink(Guid downloadId, String unrestrictedLink);
Task UpdateDownloadStarted(Guid downloadId, DateTimeOffset? dateTime);
Task UpdateDownloadFinished(Guid downloadId, DateTimeOffset? dateTime);
Task UpdateUnpackingQueued(Guid downloadId, DateTimeOffset? dateTime);
@ -51,6 +52,11 @@ namespace RdtClient.Service.Services
return await _downloadData.Add(torrentId, link);
}
public async Task UpdateUnrestrictedLink(Guid downloadId, String unrestrictedLink)
{
await _downloadData.UpdateUnrestrictedLink(downloadId, unrestrictedLink);
}
public async Task UpdateDownloadStarted(Guid downloadId, DateTimeOffset? dateTime)
{
await _downloadData.UpdateDownloadStarted(downloadId, dateTime);

View file

@ -18,8 +18,8 @@ namespace RdtClient.Service.Services
Task<IList<TorrentFileItem>> TorrentFileContents(String hash);
Task<TorrentProperties> TorrentProperties(String hash);
Task TorrentsDelete(String hash, Boolean deleteFiles);
Task TorrentsAddMagnet(String magnetLink, String category, Boolean autoDownload, Boolean autoUnpack, Boolean autoDelete);
Task TorrentsAddFile(Byte[] fileBytes, String category, Boolean autoDownload, Boolean autoUnpack, Boolean autoDelete);
Task TorrentsAddMagnet(String magnetLink, String category, Boolean autoDelete);
Task TorrentsAddFile(Byte[] fileBytes, String category, Boolean autoDelete);
Task TorrentsSetCategory(String hash, String category);
Task<IDictionary<String, TorrentCategory>> TorrentsCategories();
}
@ -424,14 +424,14 @@ namespace RdtClient.Service.Services
await _torrents.Delete(torrent.TorrentId, true, true, deleteFiles);
}
public async Task TorrentsAddMagnet(String magnetLink, String category, Boolean autoDownload, Boolean autoUnpack, Boolean autoDelete)
public async Task TorrentsAddMagnet(String magnetLink, String category, Boolean autoDelete)
{
await _torrents.UploadMagnet(magnetLink, category, autoDownload, autoUnpack, autoDelete);
await _torrents.UploadMagnet(magnetLink, category, autoDelete);
}
public async Task TorrentsAddFile(Byte[] fileBytes, String category,Boolean autoDownload, Boolean autoUnpack, Boolean autoDelete)
public async Task TorrentsAddFile(Byte[] fileBytes, String category, Boolean autoDelete)
{
await _torrents.UploadFile(fileBytes, category, autoDownload, autoUnpack, autoDelete);
await _torrents.UploadFile(fileBytes, category, autoDelete);
}
public async Task TorrentsSetCategory(String hash, String category)

View file

@ -219,6 +219,9 @@ namespace RdtClient.Service.Services
continue;
}
var downloadLink = await _torrents.UnrestrictLink(download.DownloadId);
download.Link = downloadLink;
download.DownloadStarted = DateTime.UtcNow;
await _downloads.UpdateDownloadStarted(download.DownloadId, download.DownloadStarted);
@ -332,7 +335,7 @@ namespace RdtClient.Service.Services
}
// RealDebrid is waiting for file selection, select which files to download.
if (torrent.AutoDownload && torrent.RdStatus == RealDebridStatus.WaitingForFileSelection)
if (torrent.RdStatus == RealDebridStatus.WaitingForFileSelection)
{
Log.Debug($"Torrent {torrent.RdId} selecting files");
@ -374,7 +377,7 @@ namespace RdtClient.Service.Services
Log.Debug($"Selecting files for torrent {torrent.RdId}: {String.Join(", ", fileIds)}");
await _torrents.SelectFiles(torrent.RdId, fileIds);
await _torrents.SelectFiles(torrent.TorrentId, fileIds);
}
// If the torrent doesn't have any files at this point, don't process it further.
@ -385,25 +388,16 @@ namespace RdtClient.Service.Services
}
// RealDebrid finished downloading the torrent, process the file to host.
if (torrent.AutoDownload && torrent.RdStatus == RealDebridStatus.Finished)
if (torrent.RdStatus == RealDebridStatus.Finished)
{
Log.Debug($"Torrent {torrent.RdId} completed, download starting");
// If the torrent doesn't have any Downloads, unrestrict the links and add them to the database.
if (torrent.Downloads.Count == 0)
{
Log.Debug($"Torrent {torrent.RdId} unrestricting links");
await _torrents.Unrestrict(torrent.TorrentId);
continue;
}
// If the torrent has any files that need starting to be downloaded, download them.
var downloadsPending = torrent.Downloads
.Where(m => m.Completed == null &&
m.DownloadStarted == null &&
m.DownloadFinished == null)
.OrderBy(m => m.Added)
.ToList();
Log.Debug($"Torrent {torrent.RdId} found {downloadsPending.Count} downloads pending");
@ -421,7 +415,7 @@ namespace RdtClient.Service.Services
}
}
if (torrent.AutoUnpack && torrent.RdStatus == RealDebridStatus.Finished)
if (torrent.RdStatus == RealDebridStatus.Finished)
{
Log.Debug($"Torrent {torrent.RdId} completed, unpack starting");

View file

@ -20,12 +20,12 @@ namespace RdtClient.Service.Services
Task<Torrent> GetById(Guid torrentId);
Task<Torrent> GetByHash(String hash);
Task UpdateCategory(String hash, String category);
Task UploadMagnet(String magnetLink, String category, Boolean autoDownload, Boolean autoUnpack, Boolean autoDelete);
Task UploadFile(Byte[] bytes, String category, Boolean autoDownload, Boolean autoUnpack, Boolean autoDelete);
Task UploadMagnet(String magnetLink, String category, Boolean autoDelete);
Task UploadFile(Byte[] bytes, String category, Boolean autoDelete);
Task<List<String>> GetAvailableFiles(String hash);
Task SelectFiles(String torrentId, IList<String> fileIds);
Task SelectFiles(Guid torrentId, IList<String> fileIds);
Task Delete(Guid torrentId, Boolean deleteData, Boolean deleteRdTorrent, Boolean deleteLocalFiles);
Task Unrestrict(Guid torrentId);
Task<String> UnrestrictLink(Guid downloadId);
Task Download(Guid downloadId);
Task Unpack(Guid downloadId);
void Reset();
@ -135,22 +135,22 @@ namespace RdtClient.Service.Services
await _torrentData.UpdateCategory(torrent.TorrentId, category);
}
public async Task UploadMagnet(String magnetLink, String category, Boolean autoDownload, Boolean autoUnpack, Boolean autoDelete)
public async Task UploadMagnet(String magnetLink, String category, Boolean autoDelete)
{
var magnet = MagnetLink.Parse(magnetLink);
var rdTorrent = await GetRdNetClient().AddTorrentMagnetAsync(magnetLink);
await Add(rdTorrent.Id, magnet.InfoHash.ToHex(), category, autoDownload, autoUnpack, autoDelete);
await Add(rdTorrent.Id, magnet.InfoHash.ToHex(), category, autoDelete);
}
public async Task UploadFile(Byte[] bytes, String category, Boolean autoDownload, Boolean autoUnpack, Boolean autoDelete)
public async Task UploadFile(Byte[] bytes, String category, Boolean autoDelete)
{
var torrent = await MonoTorrent.Torrent.LoadAsync(bytes);
var rdTorrent = await GetRdNetClient().AddTorrentFileAsync(bytes);
await Add(rdTorrent.Id, torrent.InfoHash.ToHex(), category, autoDownload, autoUnpack, autoDelete);
await Add(rdTorrent.Id, torrent.InfoHash.ToHex(), category, autoDelete);
}
public async Task<List<String>> GetAvailableFiles(String hash)
@ -164,9 +164,18 @@ namespace RdtClient.Service.Services
return groups.Select(m => m.Key).ToList();
}
public async Task SelectFiles(String torrentId, IList<String> fileIds)
public async Task SelectFiles(Guid torrentId, IList<String> fileIds)
{
await GetRdNetClient().SelectTorrentFilesAsync(torrentId, fileIds.ToArray());
var torrent = await GetById(torrentId);
await GetRdNetClient().SelectTorrentFilesAsync(torrent.RdId, fileIds.ToArray());
var rdTorrent = await GetRdNetClient().GetTorrentInfoAsync(torrent.RdId);
foreach (var file in rdTorrent.Links)
{
await _downloads.Add(torrent.TorrentId, file);
}
}
public async Task Delete(Guid torrentId, Boolean deleteData, Boolean deleteRdTorrent, Boolean deleteLocalFiles)
@ -212,23 +221,15 @@ namespace RdtClient.Service.Services
}
}
public async Task Unrestrict(Guid torrentId)
public async Task<String> UnrestrictLink(Guid downloadId)
{
var torrent = await _torrentData.GetById(torrentId);
var download = await _downloads.GetById(downloadId);
var rdTorrent = await GetRdNetClient().GetTorrentInfoAsync(torrent.RdId);
var unrestrictedLink = await GetRdNetClient().UnrestrictLinkAsync(download.Path);
foreach (var link in rdTorrent.Links)
{
var unrestrictedLink = await GetRdNetClient().UnrestrictLinkAsync(link);
await _downloads.UpdateUnrestrictedLink(downloadId, unrestrictedLink.Download);
if (torrent.Downloads.Any(m => m.Link == unrestrictedLink.Download))
{
continue;
}
await _downloads.Add(torrent.TorrentId, unrestrictedLink.Download);
}
return unrestrictedLink.Download;
}
public async Task Download(Guid downloadId)
@ -269,7 +270,7 @@ namespace RdtClient.Service.Services
return profile;
}
private async Task Add(String rdTorrentId, String infoHash, String category, Boolean autoDownload, Boolean autoUnpack, Boolean autoDelete)
private async Task Add(String rdTorrentId, String infoHash, String category, Boolean autoDelete)
{
var w = await SemaphoreSlim.WaitAsync(60000);
if (!w)
@ -286,7 +287,7 @@ namespace RdtClient.Service.Services
return;
}
var newTorrent = await _torrentData.Add(rdTorrentId, infoHash, category, autoDownload, autoUnpack, autoDelete);
var newTorrent = await _torrentData.Add(rdTorrentId, infoHash, category, autoDelete);
var rdTorrent = await GetRdNetClient().GetTorrentInfoAsync(rdTorrentId);

View file

@ -245,7 +245,7 @@ namespace RdtClient.Web.Controllers
foreach (var url in urls)
{
await _qBittorrent.TorrentsAddMagnet(url.Trim(), request.Category, true, true, false);
await _qBittorrent.TorrentsAddMagnet(url.Trim(), request.Category, false);
}
return Ok();
@ -265,7 +265,7 @@ namespace RdtClient.Web.Controllers
await file.CopyToAsync(target);
var fileBytes = target.ToArray();
await _qBittorrent.TorrentsAddFile(fileBytes, request.Category, true, true, false);
await _qBittorrent.TorrentsAddFile(fileBytes, request.Category, false);
}
}

View file

@ -6,9 +6,10 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using RdtClient.Data.Models.Data;
using MonoTorrent;
using RdtClient.Service.Helpers;
using RdtClient.Service.Services;
using Torrent = RdtClient.Data.Models.Data.Torrent;
namespace RdtClient.Web.Controllers
{
@ -74,7 +75,7 @@ namespace RdtClient.Web.Controllers
var bytes = memoryStream.ToArray();
await _torrents.UploadFile(bytes, null, formData.AutoDownload, formData.AutoUnpack, formData.AutoDelete);
await _torrents.UploadFile(bytes, null, formData.AutoDelete);
return Ok();
}
@ -83,10 +84,45 @@ namespace RdtClient.Web.Controllers
[Route("UploadMagnet")]
public async Task<ActionResult> UploadMagnet([FromBody] TorrentControllerUploadMagnetRequest request)
{
await _torrents.UploadMagnet(request.MagnetLink, null, request.AutoDownload, request.AutoUnpack, request.AutoDelete);
await _torrents.UploadMagnet(request.MagnetLink, null, request.AutoDelete);
return Ok();
}
[HttpPost]
[Route("CheckFiles")]
public async Task<ActionResult> CheckFiles([FromForm] IFormFile file)
{
if (file == null || file.Length <= 0)
{
throw new Exception("Invalid torrent file");
}
var fileStream = file.OpenReadStream();
await using var memoryStream = new MemoryStream();
await fileStream.CopyToAsync(memoryStream);
var bytes = memoryStream.ToArray();
var torrent = await MonoTorrent.Torrent.LoadAsync(bytes);
var result = await _torrents.GetAvailableFiles(torrent.InfoHash.ToHex());
return Ok(result);
}
[HttpPost]
[Route("CheckFilesMagnet")]
public async Task<ActionResult> CheckFilesMagnet([FromBody] TorrentControllerCheckFilesRequest request)
{
var magnet = MagnetLink.Parse(request.MagnetLink);
var result = await _torrents.GetAvailableFiles(magnet.InfoHash.ToHex());
return Ok(result);
}
[HttpPost]
[Route("Delete/{id}")]
@ -101,7 +137,13 @@ namespace RdtClient.Web.Controllers
[Route("Download/{id}")]
public async Task<ActionResult> Download(Guid id)
{
await _torrents.Unrestrict(id);
var torrent = await _torrents.GetById(id);
foreach (var link in torrent.Files.Where(m => m.Selected))
{
await _downloads.Add(id, link.Path);
await _torrents.UnrestrictLink(id);
}
return Ok();
}
@ -123,16 +165,12 @@ namespace RdtClient.Web.Controllers
public class TorrentControllerUploadFileRequest
{
public Boolean AutoDownload { get; set; }
public Boolean AutoUnpack { get; set; }
public Boolean AutoDelete { get; set; }
}
public class TorrentControllerUploadMagnetRequest
{
public String MagnetLink { get; set; }
public Boolean AutoDownload { get; set; }
public Boolean AutoUnpack { get; set; }
public Boolean AutoDelete { get; set; }
}
@ -142,4 +180,9 @@ namespace RdtClient.Web.Controllers
public Boolean DeleteRdTorrent { get; set; }
public Boolean DeleteLocalFiles { get; set; }
}
public class TorrentControllerCheckFilesRequest
{
public String MagnetLink { get; set; }
}
}