Add first Aria2c support.
This commit is contained in:
parent
b8b50ca55a
commit
c728e17bb3
23 changed files with 940 additions and 195 deletions
|
|
@ -105,6 +105,15 @@ It has the following options:
|
|||
- Parallel connections per download: This number indicates how many threads/connections/parts/chunks it will use per download. This can increase speed, recommended is no more than 8.
|
||||
- Download speed (in MB/s): This number indicates the speed in MB/s per download. If you set this to 10 and `Maximum parallel downloads` to 2, you can download with a maximum of 20MB/s.
|
||||
|
||||
#### Aria2c downloader
|
||||
|
||||
This will use an external Aria2c downloader client. You will need to install this client yourself on your host, it is not included in the docker image.
|
||||
|
||||
It has the following options:
|
||||
|
||||
- Url: The full URL to your Aria2c service. This must end in /jsonrpc. A standard path is `http://192.168.10.2:6800/jsonrpc`.
|
||||
- Secret: Optional secret to connecto to your Aria2c service.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
- If you forgot your logins simply delete the `rdtclient.db` and restart the service.
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@
|
|||
<select [(ngModel)]="settingDownloadClient">
|
||||
<option value="Simple">Simple Downloader</option>
|
||||
<option value="MultiPart">Multi Part Downloader</option>
|
||||
<option value="Aria2c">Aria2c</option>
|
||||
</select>
|
||||
</div>
|
||||
<p class="help">
|
||||
|
|
@ -112,6 +113,7 @@
|
|||
parallel downloading will be done.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="field" *ngIf="settingDownloadClient === 'MultiPart'">
|
||||
<label class="label">Download speed (in MB/s)</label>
|
||||
<div class="control">
|
||||
|
|
@ -119,6 +121,7 @@
|
|||
</div>
|
||||
<p class="help">Maximum download speed in Megabytes per second. When set to 0 unlimited speed is used.</p>
|
||||
</div>
|
||||
|
||||
<div class="field" *ngIf="settingDownloadClient === 'MultiPart'">
|
||||
<label class="label">Proxy Server</label>
|
||||
<div class="control">
|
||||
|
|
@ -126,6 +129,27 @@
|
|||
</div>
|
||||
<p class="help">Address of a proxy server.</p>
|
||||
</div>
|
||||
|
||||
<div class="field" *ngIf="settingDownloadClient === 'Aria2c'">
|
||||
<label class="label">Aria2c URL</label>
|
||||
<div class="control">
|
||||
<input class="input" type="text" maxlength="1000" [(ngModel)]="aria2cUrl" />
|
||||
</div>
|
||||
<p class="help">
|
||||
This is the URL to your Aria2c instance. It must end in /jsonrpc. A common URL is
|
||||
http://192.168.10.2:6800/jsonrpc.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="field" *ngIf="settingDownloadClient === 'Aria2c'">
|
||||
<label class="label">Aria2c Secret</label>
|
||||
<div class="control">
|
||||
<input class="input" type="text" maxlength="1000" [(ngModel)]="aria2cSecret" />
|
||||
</div>
|
||||
<p class="help">
|
||||
The secret of your Aria2c instance. Optional.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="activeTab === 2">
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ export class SettingsComponent implements OnInit {
|
|||
public settingOnlyDownloadAvailableFiles: boolean;
|
||||
public settingProxyServer: string;
|
||||
|
||||
public aria2cUrl: string;
|
||||
public aria2cSecret: string;
|
||||
|
||||
constructor(private settingsService: SettingsService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
|
@ -61,6 +64,8 @@ export class SettingsComponent implements OnInit {
|
|||
this.settingMinFileSize = parseInt(this.getSetting(results, 'MinFileSize'), 10);
|
||||
this.settingOnlyDownloadAvailableFiles = this.getSetting(results, 'OnlyDownloadAvailableFiles') === '1';
|
||||
this.settingProxyServer = this.getSetting(results, 'ProxyServer');
|
||||
this.aria2cUrl = this.getSetting(results, 'Aria2cUrl');
|
||||
this.aria2cSecret = this.getSetting(results, 'Aria2cSecret');
|
||||
},
|
||||
(err) => {
|
||||
this.error = err.error;
|
||||
|
|
@ -125,6 +130,14 @@ export class SettingsComponent implements OnInit {
|
|||
settingId: 'ProxyServer',
|
||||
value: this.settingProxyServer,
|
||||
},
|
||||
{
|
||||
settingId: 'Aria2cUrl',
|
||||
value: this.aria2cUrl,
|
||||
},
|
||||
{
|
||||
settingId: 'Aria2cSecret',
|
||||
value: this.aria2cSecret,
|
||||
},
|
||||
];
|
||||
|
||||
this.settingsService.update(settings).subscribe(
|
||||
|
|
|
|||
|
|
@ -135,6 +135,18 @@ namespace RdtClient.Data.Data
|
|||
SettingId = "Categories",
|
||||
Type = "String",
|
||||
Value = ""
|
||||
},
|
||||
new Setting
|
||||
{
|
||||
SettingId = "Aria2cUrl",
|
||||
Type = "String",
|
||||
Value = "http://127.0.0.1:6800/jsonrpc"
|
||||
},
|
||||
new Setting
|
||||
{
|
||||
SettingId = "Aria2cSecret",
|
||||
Type = "String",
|
||||
Value = ""
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -164,6 +164,16 @@ namespace RdtClient.Data.Data
|
|||
await TorrentData.VoidCache();
|
||||
}
|
||||
|
||||
public async Task UpdateRemoteId(Guid downloadId, String remoteId)
|
||||
{
|
||||
var dbDownload = await _dataContext.Downloads
|
||||
.FirstOrDefaultAsync(m => m.DownloadId == downloadId);
|
||||
|
||||
dbDownload.RemoteId = remoteId;
|
||||
|
||||
await _dataContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteForTorrent(Guid torrentId)
|
||||
{
|
||||
var downloads = await _dataContext.Downloads
|
||||
|
|
|
|||
|
|
@ -44,7 +44,9 @@ namespace RdtClient.Data.Data
|
|||
DownloadMaxSpeed = GetInt32("DownloadMaxSpeed"),
|
||||
ProxyServer = GetString("ProxyServer"),
|
||||
LogLevel = GetString("LogLevel"),
|
||||
Categories = GetString("Categories")
|
||||
Categories = GetString("Categories"),
|
||||
Aria2cUrl = GetString("Aria2cUrl"),
|
||||
Aria2cSecret = GetString("Aria2cSecret"),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
436
server/RdtClient.Data/Migrations/20211009221133_Downloads_Add_RemoteId.Designer.cs
generated
Normal file
436
server/RdtClient.Data/Migrations/20211009221133_Downloads_Add_RemoteId.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
// <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("20211009221133_Downloads_Add_RemoteId")]
|
||||
partial class Downloads_Add_RemoteId
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "5.0.10");
|
||||
|
||||
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<string>("RemoteId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
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<string>("Category")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("Completed")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("DownloadAction")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("DownloadManualFiles")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("DownloadMinSize")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("FileOrMagnet")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTimeOffset?>("FilesSelected")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("FinishedAction")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Hash")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsFile")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace RdtClient.Data.Migrations
|
||||
{
|
||||
public partial class Downloads_Add_RemoteId : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "RemoteId",
|
||||
table: "Downloads",
|
||||
type: "TEXT",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "RemoteId",
|
||||
table: "Downloads");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ namespace RdtClient.Data.Migrations
|
|||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "5.0.8");
|
||||
.HasAnnotation("ProductVersion", "5.0.10");
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
|
||||
{
|
||||
|
|
@ -238,6 +238,9 @@ namespace RdtClient.Data.Migrations
|
|||
b.Property<string>("Path")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RemoteId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("RetryCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ namespace RdtClient.Data.Models.Data
|
|||
|
||||
public String Error { get; set; }
|
||||
|
||||
public String RemoteId { get; set; }
|
||||
|
||||
[ForeignKey("TorrentId")]
|
||||
public Torrent Torrent { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -18,5 +18,7 @@ namespace RdtClient.Data.Models.Internal
|
|||
public String ProxyServer { get; set; }
|
||||
public String LogLevel { get; set; }
|
||||
public String Categories { get; set; }
|
||||
public String Aria2cUrl { get; set; }
|
||||
public String Aria2cSecret { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aria2.NET" Version="1.0.1" />
|
||||
<PackageReference Include="Downloader" Version="2.2.9" />
|
||||
<PackageReference Include="MonoTorrent" Version="2.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Downloader;
|
||||
using RdtClient.Data.Models.Data;
|
||||
using RdtClient.Data.Models.Internal;
|
||||
using RdtClient.Service.Helpers;
|
||||
using RdtClient.Service.Services.Downloaders;
|
||||
|
||||
namespace RdtClient.Service.Services
|
||||
{
|
||||
|
|
@ -16,8 +15,7 @@ namespace RdtClient.Service.Services
|
|||
private readonly Download _download;
|
||||
private readonly Torrent _torrent;
|
||||
|
||||
private DownloadService _downloader;
|
||||
private SimpleDownloader _simpleDownloader;
|
||||
private IDownloader _downloader;
|
||||
|
||||
public DownloadClient(Download download, Torrent torrent, String destinationPath)
|
||||
{
|
||||
|
|
@ -34,7 +32,7 @@ namespace RdtClient.Service.Services
|
|||
public Int64 BytesTotal { get; private set; }
|
||||
public Int64 BytesDone { get; private set; }
|
||||
|
||||
public async Task Start(DbSettings settings)
|
||||
public async Task<String> Start(DbSettings settings)
|
||||
{
|
||||
BytesDone = 0;
|
||||
BytesTotal = 0;
|
||||
|
|
@ -54,159 +52,41 @@ namespace RdtClient.Service.Services
|
|||
File.Delete(filePath);
|
||||
}
|
||||
|
||||
var uri = new Uri(_download.Link);
|
||||
_downloader = settings.DownloadClient switch
|
||||
{
|
||||
"Simple" => new SimpleDownloader(_download.Link, filePath),
|
||||
"MultiPart" => new MultiDownloader(_download.Link, filePath, settings),
|
||||
"Aria2c" => new Aria2cDownloader(_download.RemoteId, _download.Link, filePath, settings),
|
||||
_ => throw new Exception($"Unknown download client {settings.DownloadClient}")
|
||||
};
|
||||
|
||||
#pragma warning disable 4014
|
||||
Task.Run(async delegate
|
||||
#pragma warning restore 4014
|
||||
{
|
||||
switch (settings.DownloadClient)
|
||||
{
|
||||
case "Simple":
|
||||
await DownloadSimple(uri, filePath);
|
||||
break;
|
||||
case "MultiPart":
|
||||
await DownloadMultiPart(filePath, settings);
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Unknown download client {settings.DownloadClient}");
|
||||
}
|
||||
});
|
||||
_downloader.DownloadComplete += (_, args) =>
|
||||
{
|
||||
Finished = true;
|
||||
Error = args.Error;
|
||||
};
|
||||
|
||||
_downloader.DownloadProgress += (_, args) =>
|
||||
{
|
||||
Speed = args.Speed;
|
||||
BytesDone = args.BytesDone;
|
||||
BytesTotal = args.BytesTotal;
|
||||
};
|
||||
|
||||
return await _downloader.Download();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Error = $"An unexpected error occurred preparing download {_download.Link} for torrent {_torrent.RdName}: {ex.Message}";
|
||||
Finished = true;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
_downloader?.CancelAsync();
|
||||
_simpleDownloader?.Cancel();
|
||||
}
|
||||
|
||||
private async Task DownloadSimple(Uri uri, String filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
_simpleDownloader = new SimpleDownloader();
|
||||
|
||||
_simpleDownloader.DownloadProgressChanged += (_, args) =>
|
||||
{
|
||||
Speed = (Int64) args.BytesPerSecondSpeed;
|
||||
BytesDone = args.ReceivedBytesSize;
|
||||
BytesTotal = args.TotalBytesToReceive;
|
||||
};
|
||||
|
||||
_simpleDownloader.DownloadFileCompleted += (_, args) =>
|
||||
{
|
||||
if (args.Cancelled)
|
||||
{
|
||||
Error = $"The download was cancelled";
|
||||
}
|
||||
else if (args.Error != null)
|
||||
{
|
||||
Error = args.Error.Message;
|
||||
}
|
||||
|
||||
Finished = true;
|
||||
};
|
||||
|
||||
Speed = 0;
|
||||
BytesDone = 0;
|
||||
BytesTotal = 0;
|
||||
|
||||
await _simpleDownloader.Download(uri, filePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Error = $"An unexpected error occurred downloading {_download.Link} for torrent {_torrent.RdName}: {ex.Message}";
|
||||
Finished = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DownloadMultiPart(String filePath, DbSettings settings)
|
||||
{
|
||||
try
|
||||
{
|
||||
var settingTempPath = settings.TempPath;
|
||||
if (String.IsNullOrWhiteSpace(settingTempPath))
|
||||
{
|
||||
settingTempPath = Path.GetTempPath();
|
||||
}
|
||||
|
||||
var settingDownloadChunkCount = settings.DownloadChunkCount;
|
||||
if (settingDownloadChunkCount <= 0)
|
||||
{
|
||||
settingDownloadChunkCount = 1;
|
||||
}
|
||||
|
||||
var settingDownloadMaxSpeed = settings.DownloadMaxSpeed;
|
||||
if (settingDownloadMaxSpeed <= 0)
|
||||
{
|
||||
settingDownloadMaxSpeed = 0;
|
||||
}
|
||||
settingDownloadMaxSpeed = settingDownloadMaxSpeed * 1024 * 1024;
|
||||
|
||||
var settingProxyServer = settings.ProxyServer;
|
||||
|
||||
var downloadOpt = new DownloadConfiguration
|
||||
{
|
||||
MaxTryAgainOnFailover = Int32.MaxValue,
|
||||
ParallelDownload = settingDownloadChunkCount > 1,
|
||||
ChunkCount = settingDownloadChunkCount,
|
||||
Timeout = 1000,
|
||||
OnTheFlyDownload = false,
|
||||
BufferBlockSize = 1024 * 8,
|
||||
MaximumBytesPerSecond = settingDownloadMaxSpeed,
|
||||
TempDirectory = settingTempPath,
|
||||
RequestConfiguration =
|
||||
{
|
||||
Accept = "*/*",
|
||||
UserAgent = $"rdt-client",
|
||||
ProtocolVersion = HttpVersion.Version11,
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
|
||||
KeepAlive = true,
|
||||
UseDefaultCredentials = false
|
||||
}
|
||||
};
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(settingProxyServer))
|
||||
{
|
||||
downloadOpt.RequestConfiguration.Proxy = new WebProxy(new Uri(settingProxyServer), false);
|
||||
}
|
||||
|
||||
_downloader = new DownloadService(downloadOpt);
|
||||
|
||||
_downloader.DownloadProgressChanged += (_, args) =>
|
||||
{
|
||||
Speed = (Int64) args.BytesPerSecondSpeed;
|
||||
BytesDone = args.ReceivedBytesSize;
|
||||
BytesTotal = args.TotalBytesToReceive;
|
||||
};
|
||||
|
||||
_downloader.DownloadFileCompleted += (_, args) =>
|
||||
{
|
||||
if (args.Cancelled)
|
||||
{
|
||||
Error = $"The download was cancelled";
|
||||
}
|
||||
else if (args.Error != null)
|
||||
{
|
||||
Error = args.Error.Message;
|
||||
}
|
||||
|
||||
Finished = true;
|
||||
};
|
||||
|
||||
await _downloader.DownloadFileTaskAsync(_download.Link, filePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Error = $"An unexpected error occurred downloading {_download.Link} for torrent {_torrent.RdName}: {ex.Message}";
|
||||
Finished = true;
|
||||
}
|
||||
_downloader?.Cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,146 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using Aria2NET;
|
||||
using RdtClient.Data.Models.Internal;
|
||||
|
||||
namespace RdtClient.Service.Services.Downloaders
|
||||
{
|
||||
public class Aria2cDownloader : IDownloader
|
||||
{
|
||||
public event EventHandler<DownloadCompleteEventArgs> DownloadComplete;
|
||||
public event EventHandler<DownloadProgressEventArgs> DownloadProgress;
|
||||
|
||||
private readonly String _uri;
|
||||
private readonly String _filePath;
|
||||
|
||||
private readonly Aria2NetClient _aria2NetClient;
|
||||
private readonly Timer _timer;
|
||||
|
||||
private String _gid;
|
||||
|
||||
public Aria2cDownloader(String gid, String uri, String filePath, DbSettings settings)
|
||||
{
|
||||
_gid = gid;
|
||||
_uri = uri;
|
||||
_filePath = filePath;
|
||||
|
||||
_aria2NetClient = new Aria2NetClient(settings.Aria2cUrl, settings.Aria2cSecret);
|
||||
|
||||
_timer = new Timer();
|
||||
|
||||
_timer.Elapsed += OnTimedEvent;
|
||||
|
||||
_timer.Interval = 1000;
|
||||
_timer.Enabled = false;
|
||||
}
|
||||
|
||||
public async Task<String> Download()
|
||||
{
|
||||
var path = Path.GetDirectoryName(_filePath);
|
||||
var fileName = Path.GetFileName(_filePath);
|
||||
|
||||
if (_gid != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _aria2NetClient.TellStatus(_gid);
|
||||
}
|
||||
catch
|
||||
{
|
||||
_gid = null;
|
||||
}
|
||||
}
|
||||
|
||||
_gid ??= await _aria2NetClient.AddUri(new List<String>
|
||||
{
|
||||
_uri
|
||||
},
|
||||
new Dictionary<String, Object>
|
||||
{
|
||||
{
|
||||
"dir", path
|
||||
},
|
||||
{
|
||||
"out", fileName
|
||||
}
|
||||
});
|
||||
|
||||
_timer.Start();
|
||||
|
||||
return _gid;
|
||||
}
|
||||
|
||||
public async Task Cancel()
|
||||
{
|
||||
_timer.Stop();
|
||||
|
||||
if (String.IsNullOrWhiteSpace(_gid))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _aria2NetClient.ForceRemove(_gid);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _aria2NetClient.RemoveDownloadResult(_gid);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnTimedEvent(Object source, ElapsedEventArgs e)
|
||||
{
|
||||
if (_gid == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var status = await _aria2NetClient.TellStatus(_gid);
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(status.ErrorMessage) || status.Status == "error")
|
||||
{
|
||||
await Cancel();
|
||||
DownloadComplete?.Invoke(this, new DownloadCompleteEventArgs
|
||||
{
|
||||
Error = $"{status.ErrorCode}: {status.ErrorMessage}"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (status.Status == "complete" || status.Status == "removed")
|
||||
{
|
||||
await Cancel();
|
||||
DownloadComplete?.Invoke(this, new DownloadCompleteEventArgs());
|
||||
return;
|
||||
}
|
||||
|
||||
DownloadProgress?.Invoke(this, new DownloadProgressEventArgs
|
||||
{
|
||||
BytesDone = status.CompletedLength,
|
||||
BytesTotal = status.TotalLength,
|
||||
Speed = status.DownloadSpeed
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
await Cancel();
|
||||
DownloadComplete?.Invoke(this, new DownloadCompleteEventArgs());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
server/RdtClient.Service/Services/Downloaders/IDownloader.cs
Normal file
25
server/RdtClient.Service/Services/Downloaders/IDownloader.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace RdtClient.Service.Services.Downloaders
|
||||
{
|
||||
public class DownloadCompleteEventArgs
|
||||
{
|
||||
public String Error { get; set; }
|
||||
}
|
||||
|
||||
public class DownloadProgressEventArgs
|
||||
{
|
||||
public Int64 Speed { get; set; }
|
||||
public Int64 BytesDone { get; set; }
|
||||
public Int64 BytesTotal { get; set; }
|
||||
}
|
||||
|
||||
public interface IDownloader
|
||||
{
|
||||
event EventHandler<DownloadCompleteEventArgs> DownloadComplete;
|
||||
event EventHandler<DownloadProgressEventArgs> DownloadProgress;
|
||||
Task<String> Download();
|
||||
Task Cancel();
|
||||
}
|
||||
}
|
||||
128
server/RdtClient.Service/Services/Downloaders/MultiDownloader.cs
Normal file
128
server/RdtClient.Service/Services/Downloaders/MultiDownloader.cs
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Downloader;
|
||||
using RdtClient.Data.Models.Internal;
|
||||
|
||||
namespace RdtClient.Service.Services.Downloaders
|
||||
{
|
||||
public class MultiDownloader : IDownloader
|
||||
{
|
||||
public event EventHandler<DownloadCompleteEventArgs> DownloadComplete;
|
||||
public event EventHandler<DownloadProgressEventArgs> DownloadProgress;
|
||||
|
||||
private readonly DownloadService _downloadService;
|
||||
private readonly String _filePath;
|
||||
private readonly String _uri;
|
||||
|
||||
public MultiDownloader(String uri, String filePath, DbSettings settings)
|
||||
{
|
||||
_uri = uri;
|
||||
_filePath = filePath;
|
||||
|
||||
var settingTempPath = settings.TempPath;
|
||||
|
||||
if (String.IsNullOrWhiteSpace(settingTempPath))
|
||||
{
|
||||
settingTempPath = Path.GetTempPath();
|
||||
}
|
||||
|
||||
var settingDownloadChunkCount = settings.DownloadChunkCount;
|
||||
|
||||
if (settingDownloadChunkCount <= 0)
|
||||
{
|
||||
settingDownloadChunkCount = 1;
|
||||
}
|
||||
|
||||
var settingDownloadMaxSpeed = settings.DownloadMaxSpeed;
|
||||
|
||||
if (settingDownloadMaxSpeed <= 0)
|
||||
{
|
||||
settingDownloadMaxSpeed = 0;
|
||||
}
|
||||
|
||||
settingDownloadMaxSpeed = settingDownloadMaxSpeed * 1024 * 1024;
|
||||
|
||||
var settingProxyServer = settings.ProxyServer;
|
||||
|
||||
var downloadOpt = new DownloadConfiguration
|
||||
{
|
||||
MaxTryAgainOnFailover = Int32.MaxValue,
|
||||
ParallelDownload = settingDownloadChunkCount > 1,
|
||||
ChunkCount = settingDownloadChunkCount,
|
||||
Timeout = 1000,
|
||||
OnTheFlyDownload = false,
|
||||
BufferBlockSize = 1024 * 8,
|
||||
MaximumBytesPerSecond = settingDownloadMaxSpeed,
|
||||
TempDirectory = settingTempPath,
|
||||
RequestConfiguration =
|
||||
{
|
||||
Accept = "*/*",
|
||||
UserAgent = $"rdt-client",
|
||||
ProtocolVersion = HttpVersion.Version11,
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
|
||||
KeepAlive = true,
|
||||
UseDefaultCredentials = false
|
||||
}
|
||||
};
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(settingProxyServer))
|
||||
{
|
||||
downloadOpt.RequestConfiguration.Proxy = new WebProxy(new Uri(settingProxyServer), false);
|
||||
}
|
||||
|
||||
_downloadService = new DownloadService(downloadOpt);
|
||||
|
||||
_downloadService.DownloadProgressChanged += (_, args) =>
|
||||
{
|
||||
if (DownloadProgress == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DownloadProgress?.Invoke(this,
|
||||
new DownloadProgressEventArgs
|
||||
{
|
||||
Speed = (Int64)args.BytesPerSecondSpeed,
|
||||
BytesDone = args.ReceivedBytesSize,
|
||||
BytesTotal = args.TotalBytesToReceive
|
||||
});
|
||||
};
|
||||
|
||||
_downloadService.DownloadFileCompleted += (_, args) =>
|
||||
{
|
||||
String error = null;
|
||||
|
||||
if (args.Cancelled)
|
||||
{
|
||||
error = $"The download was cancelled";
|
||||
}
|
||||
else if (args.Error != null)
|
||||
{
|
||||
error = args.Error.Message;
|
||||
}
|
||||
|
||||
DownloadComplete?.Invoke(this,
|
||||
new DownloadCompleteEventArgs
|
||||
{
|
||||
Error = error
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<String> Download()
|
||||
{
|
||||
await _downloadService.DownloadFileTaskAsync(_uri, _filePath);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Task Cancel()
|
||||
{
|
||||
_downloadService.CancelAsync();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +1,51 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using DownloadProgressChangedEventArgs = Downloader.DownloadProgressChangedEventArgs;
|
||||
|
||||
namespace RdtClient.Service.Services
|
||||
namespace RdtClient.Service.Services.Downloaders
|
||||
{
|
||||
public class SimpleDownloader
|
||||
public class SimpleDownloader : IDownloader
|
||||
{
|
||||
public Int64 Speed { get; private set; }
|
||||
public Int64 BytesTotal { get; private set; }
|
||||
public Int64 BytesDone { get; private set; }
|
||||
public event EventHandler<DownloadCompleteEventArgs> DownloadComplete;
|
||||
public event EventHandler<DownloadProgressEventArgs> DownloadProgress;
|
||||
|
||||
public event EventHandler<AsyncCompletedEventArgs> DownloadFileCompleted;
|
||||
public event EventHandler<DownloadProgressChangedEventArgs> DownloadProgressChanged;
|
||||
private readonly String _uri;
|
||||
private readonly String _filePath;
|
||||
|
||||
private Boolean _cancelled = false;
|
||||
private Int64 Speed { get; set; }
|
||||
private Int64 BytesTotal { get; set; }
|
||||
private Int64 BytesDone { get; set; }
|
||||
|
||||
private Boolean _cancelled;
|
||||
|
||||
private Int64 _bytesLastUpdate;
|
||||
private DateTime _nextUpdate;
|
||||
|
||||
public async Task Download(Uri uri, String filePath)
|
||||
public SimpleDownloader(String uri, String filePath)
|
||||
{
|
||||
_uri = uri;
|
||||
_filePath = filePath;
|
||||
}
|
||||
|
||||
public Task<String> Download()
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await StartDownloadTask();
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Task Cancel()
|
||||
{
|
||||
_cancelled = true;
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task StartDownloadTask()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -29,7 +53,7 @@ namespace RdtClient.Service.Services
|
|||
_nextUpdate = DateTime.UtcNow.AddSeconds(1);
|
||||
|
||||
// Determine the file size
|
||||
var webRequest = WebRequest.Create(uri);
|
||||
var webRequest = WebRequest.Create(_uri);
|
||||
webRequest.Method = "HEAD";
|
||||
webRequest.Timeout = 5000;
|
||||
Int64 responseLength;
|
||||
|
|
@ -45,7 +69,7 @@ namespace RdtClient.Service.Services
|
|||
{
|
||||
try
|
||||
{
|
||||
var request = WebRequest.Create(uri);
|
||||
var request = WebRequest.Create(_uri);
|
||||
using var response = await request.GetResponseAsync();
|
||||
|
||||
await using var stream = response.GetResponseStream();
|
||||
|
|
@ -55,7 +79,7 @@ namespace RdtClient.Service.Services
|
|||
throw new IOException("No stream");
|
||||
}
|
||||
|
||||
await using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write);
|
||||
await using var fileStream = new FileStream(_filePath, FileMode.Create, FileAccess.Write, FileShare.Write);
|
||||
var buffer = new Byte[64 * 1024];
|
||||
|
||||
while (fileStream.Length < response.ContentLength && !_cancelled)
|
||||
|
|
@ -78,13 +102,11 @@ namespace RdtClient.Service.Services
|
|||
|
||||
timeout = DateTimeOffset.UtcNow.AddHours(1);
|
||||
|
||||
DownloadProgressChanged?.Invoke(this, new DownloadProgressChangedEventArgs(null)
|
||||
DownloadProgress?.Invoke(this, new DownloadProgressEventArgs
|
||||
{
|
||||
BytesPerSecondSpeed = Speed,
|
||||
ProgressedByteSize = _bytesLastUpdate,
|
||||
TotalBytesToReceive = BytesTotal,
|
||||
AverageBytesPerSecondSpeed = Speed,
|
||||
ReceivedBytesSize = BytesDone,
|
||||
Speed = Speed,
|
||||
BytesDone = BytesDone,
|
||||
BytesTotal = BytesTotal
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -111,17 +133,15 @@ namespace RdtClient.Service.Services
|
|||
throw new Exception($"Download timed out");
|
||||
}
|
||||
|
||||
DownloadFileCompleted?.Invoke(this, new AsyncCompletedEventArgs(null, false, null));
|
||||
DownloadComplete?.Invoke(this, new DownloadCompleteEventArgs());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DownloadFileCompleted?.Invoke(this, new AsyncCompletedEventArgs(ex, false, null));
|
||||
DownloadComplete?.Invoke(this, new DownloadCompleteEventArgs
|
||||
{
|
||||
Error = ex.Message
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
_cancelled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -74,6 +74,11 @@ namespace RdtClient.Service.Services
|
|||
await _downloadData.UpdateRetryCount(downloadId, retryCount);
|
||||
}
|
||||
|
||||
public async Task UpdateRemoteId(Guid downloadId, String remoteId)
|
||||
{
|
||||
await _downloadData.UpdateRemoteId(downloadId, remoteId);
|
||||
}
|
||||
|
||||
public async Task DeleteForTorrent(Guid torrentId)
|
||||
{
|
||||
await _downloadData.DeleteForTorrent(torrentId);
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ namespace RdtClient.Service.Services
|
|||
|
||||
var downloadClient = new DownloadClient(download, download.Torrent, downloadPath);
|
||||
|
||||
await downloadClient.Start(Get);
|
||||
downloadClient.Start(Get);
|
||||
|
||||
while (!downloadClient.Finished)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -249,7 +249,14 @@ namespace RdtClient.Service.Services
|
|||
{
|
||||
Log.Debug($"Added download {download.DownloadId} to active downloads");
|
||||
|
||||
await downloadClient.Start(Settings.Get);
|
||||
var remoteId = await downloadClient.Start(Settings.Get);
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(remoteId) && download.RemoteId != remoteId)
|
||||
{
|
||||
Log.Debug($"Received ID {remoteId} for download {download.DownloadId}");
|
||||
|
||||
await _downloads.UpdateRemoteId(download.DownloadId, remoteId);
|
||||
}
|
||||
|
||||
Log.Debug($"Download {download.DownloadId} started");
|
||||
}
|
||||
|
|
@ -335,7 +342,7 @@ namespace RdtClient.Service.Services
|
|||
{
|
||||
Log.Debug($"Added unpack {download.DownloadId} to active unpacks");
|
||||
|
||||
await unpackClient.Start();
|
||||
unpackClient.Start();
|
||||
|
||||
Log.Debug($"Unpack {download.DownloadId} started");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -514,6 +514,18 @@ namespace RdtClient.Service.Services
|
|||
return torrent;
|
||||
}
|
||||
|
||||
private static String DownloadPath(Torrent torrent)
|
||||
{
|
||||
var settingDownloadPath = Settings.Get.DownloadPath;
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(torrent.Category))
|
||||
{
|
||||
settingDownloadPath = Path.Combine(settingDownloadPath, torrent.Category);
|
||||
}
|
||||
|
||||
return settingDownloadPath;
|
||||
}
|
||||
|
||||
private async Task Add(String rdTorrentId,
|
||||
String infoHash,
|
||||
String category,
|
||||
|
|
@ -553,18 +565,6 @@ namespace RdtClient.Service.Services
|
|||
}
|
||||
}
|
||||
|
||||
private String DownloadPath(Torrent torrent)
|
||||
{
|
||||
var settingDownloadPath = Settings.Get.DownloadPath;
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(torrent.Category))
|
||||
{
|
||||
settingDownloadPath = Path.Combine(settingDownloadPath, torrent.Category);
|
||||
}
|
||||
|
||||
return settingDownloadPath;
|
||||
}
|
||||
|
||||
private async Task Update(Torrent torrent)
|
||||
{
|
||||
var originalTorrent = JsonConvert.SerializeObject(torrent,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace RdtClient.Service.Services
|
|||
_torrent = download.Torrent;
|
||||
}
|
||||
|
||||
public async Task Start()
|
||||
public void Start()
|
||||
{
|
||||
BytesDone = 0;
|
||||
BytesTotal = 0;
|
||||
|
|
@ -50,9 +50,7 @@ namespace RdtClient.Service.Services
|
|||
throw new Exception("Invalid download path");
|
||||
}
|
||||
|
||||
#pragma warning disable 4014
|
||||
Task.Run(async delegate
|
||||
#pragma warning restore 4014
|
||||
{
|
||||
if (!_cancelled)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aria2.NET" Version="1.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="5.0.10" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.10" />
|
||||
|
|
|
|||
Loading…
Reference in a new issue