don't add torrents straight to debrid provider, add to queue first, dequeue in TorrentRunner

This commit is contained in:
Cucumberrbob 2025-03-21 13:08:51 +00:00
parent aa6e6c7df5
commit 74e6d2cf95
No known key found for this signature in database
GPG key ID: 2B935C47401C3614
11 changed files with 139 additions and 53 deletions

View file

@ -62,6 +62,7 @@ export class TorrentFileAvailability {
}
export enum RealDebridStatus {
NotYetAdded = -1,
Processing = 0,
WaitingForFileSelection = 1,
Downloading = 2,

View file

@ -87,6 +87,8 @@ export class TorrentStatusPipe implements PipeTransform {
}
switch (torrent.rdStatus) {
case RealDebridStatus.NotYetAdded:
return "Not Yet Added to Provider"
case RealDebridStatus.Downloading:
if (torrent.rdSeeders < 1) {
return `Torrent stalled`;

View file

@ -9,7 +9,7 @@ public interface ITorrentData
Task<Torrent?> GetById(Guid torrentId);
Task<Torrent?> GetByHash(String hash);
Task<Torrent> Add(String rdId,
Task<Torrent> Add(String? rdId,
String hash,
String? fileOrMagnetContents,
Boolean isFile,
@ -17,6 +17,7 @@ public interface ITorrentData
Torrent torrent);
Task UpdateRdData(Torrent torrent);
Task UpdateRdId(Torrent torrent, String rdId);
Task Update(Torrent torrent);
Task UpdateCategory(Guid torrentId, String? category);
Task UpdateComplete(Guid torrentId, String? error, DateTimeOffset? datetime, Boolean retry);

View file

@ -71,7 +71,7 @@ public class TorrentData(DataContext dataContext) : ITorrentData
return dbTorrent;
}
public async Task<Torrent> Add(String rdId,
public async Task<Torrent> Add(String? rdId,
String hash,
String? fileOrMagnetContents,
Boolean isFile,
@ -99,7 +99,9 @@ public class TorrentData(DataContext dataContext) : ITorrentData
TorrentRetryAttempts = torrent.TorrentRetryAttempts,
DownloadRetryAttempts = torrent.DownloadRetryAttempts,
DeleteOnError = torrent.DeleteOnError,
Lifetime = torrent.Lifetime
Lifetime = torrent.Lifetime,
RdStatus = torrent.RdStatus,
RdName = torrent.RdName
};
await dataContext.Torrents.AddAsync(newTorrent);
@ -138,6 +140,22 @@ public class TorrentData(DataContext dataContext) : ITorrentData
await VoidCache();
}
public async Task UpdateRdId(Torrent torrent, String rdId)
{
var dbTorrent = await dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrent.TorrentId);
if (dbTorrent == null)
{
return;
}
dbTorrent.RdId = rdId;
await dataContext.SaveChangesAsync();
await VoidCache();
}
public async Task Update(Torrent torrent)
{
var dbTorrent = await dataContext.Torrents.FirstOrDefaultAsync(m => m.TorrentId == torrent.TorrentId);

View file

@ -2,6 +2,8 @@
public enum TorrentStatus
{
NotYetAdded = -1,
Processing = 0,
WaitingForFileSelection = 1,
Downloading = 2,

View file

@ -193,6 +193,10 @@ or
[Description("The interval to check the torrents info on the providers API. Minumum is 3 seconds. When there are no active downloads this limit is increased * 3.")]
public Int32 CheckInterval { get; set; } = 10;
[DisplayName("Max parallel downloads")]
[Description("Limits the number of torrents that will be sent for downloading on the debrid provider at the same time. If set to 0, all downloads will be sent immediately without queuing.")]
public Int32 MaxParallelDownloads { get; set; } = 0;
[DisplayName("Auto Import Defaults")]
public DbSettingsDefaultsWithCategory Default { get; set; } = new();
}

View file

@ -99,12 +99,12 @@ public class WatchFolderChecker(ILogger<WatchFolderChecker> logger, IServiceProv
if (fileInfo.Extension == ".torrent")
{
var torrentFileContents = await File.ReadAllBytesAsync(torrentFile, stoppingToken);
await torrentService.UploadFile(torrentFileContents, torrent);
await torrentService.AddFileToDebridQueue(torrentFileContents, torrent);
}
else if (fileInfo.Extension == ".magnet")
{
var magnetLink = await File.ReadAllTextAsync(torrentFile, stoppingToken);
await torrentService.UploadMagnet(magnetLink, torrent);
await torrentService.AddMagnetToDebridQueue(magnetLink, torrent);
}
if (!Directory.Exists(processedStorePath))

View file

@ -474,7 +474,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
Priority = priority ?? (Settings.Get.Integrations.Default.Priority > 0 ? Settings.Get.Integrations.Default.Priority : null)
};
await torrents.UploadMagnet(magnetLink, torrent);
await torrents.AddMagnetToDebridQueue(magnetLink, torrent);
}
public async Task TorrentsAddFile(Byte[] fileBytes, String? category, Int32? priority)
@ -498,7 +498,7 @@ public class QBittorrent(ILogger<QBittorrent> logger, Settings settings, Authent
Priority = priority ?? (Settings.Get.Integrations.Default.Priority > 0 ? Settings.Get.Integrations.Default.Priority : null)
};
await torrents.UploadFile(fileBytes, torrent);
await torrents.AddFileToDebridQueue(fileBytes, torrent);
}
public async Task TorrentsSetCategory(String hash, String? category)

View file

@ -314,6 +314,29 @@ public class TorrentRunner(ILogger<TorrentRunner> logger, Torrents torrents, Dow
await torrents.UpdateComplete(torrent.TorrentId, $"Torrent lifetime of {torrent.Lifetime} minutes reached", DateTimeOffset.UtcNow, false);
}
// Process torrents in DebridQueue
var torrentsToAddToProvider = allTorrents.Where(m => m.RdId == null && m.RdAdded == null && m.FileOrMagnet != null && m.RdStatus == TorrentStatus.NotYetAdded)
.ToList();
if (torrentsToAddToProvider.Count != 0)
{
var downloadingTorrentsCount = allTorrents.Count(m => m.RdStatus is not (TorrentStatus.NotYetAdded or TorrentStatus.Finished or TorrentStatus.Error));
var maxParallelDownloads = Settings.Get.Provider.MaxParallelDownloads;
logger.LogDebug("Currently downloading {downloadingTorrentCount}/{maxParallelDownloads} torrents, {queuedCount} queued.",
downloadingTorrentsCount,
maxParallelDownloads,
torrentsToAddToProvider.Count);
var dequeueCount = maxParallelDownloads == 0 ? torrentsToAddToProvider.Count : maxParallelDownloads - downloadingTorrentsCount;
foreach (var torrent in torrentsToAddToProvider.Take(dequeueCount))
{
await torrents.DequeueFromDebridQueue(torrent);
}
}
allTorrents = await torrents.Get();
allTorrents = allTorrents.Where(m => m.Completed == null).ToList();

View file

@ -107,7 +107,7 @@ public class Torrents(
await torrentData.UpdateCategory(torrent.TorrentId, category);
}
public async Task<Torrent> UploadMagnet(String magnetLink, Torrent torrent)
public async Task<Torrent> AddMagnetToDebridQueue(String magnetLink, Torrent torrent)
{
MagnetLink magnet;
@ -121,42 +121,21 @@ public class Torrents(
throw new($"{ex.Message}, trying to parse {magnetLink}");
}
var id = await TorrentClient.AddMagnet(magnetLink);
torrent.RdStatus = TorrentStatus.NotYetAdded;
torrent.RdName = magnet.Name;
var hash = magnet.InfoHashes.V1OrV2.ToHex();
var newTorrent = await Add(id, hash, magnetLink, false, torrent);
var newTorrent = await AddQueued(hash, magnetLink, false, torrent);
Log($"Adding {hash} magnet link {magnetLink}", newTorrent);
Log($"Adding {hash} (magnet link) to queue", newTorrent);
if (!String.IsNullOrWhiteSpace(Settings.Get.General.CopyAddedTorrents))
{
try
{
if (!Directory.Exists(Settings.Get.General.CopyAddedTorrents))
{
Directory.CreateDirectory(Settings.Get.General.CopyAddedTorrents);
}
var copyFileName = Path.Combine(Settings.Get.General.CopyAddedTorrents, $"{FileHelper.RemoveInvalidFileNameChars(magnet.Name!)}.magnet");
if (File.Exists(copyFileName))
{
File.Delete(copyFileName);
}
await File.WriteAllTextAsync(copyFileName, magnetLink);
}
catch (Exception ex)
{
logger.LogError(ex, $"Unable to create torrent blackhole directory: {Settings.Get.General.CopyAddedTorrents}: {ex.Message}");
}
}
await CopyAddedTorrent(magnet.Name!, magnetLink);
return newTorrent;
}
public async Task<Torrent> UploadFile(Byte[] bytes, Torrent torrent)
public async Task<Torrent> AddFileToDebridQueue(Byte[] bytes, Torrent torrent)
{
MonoTorrent.Torrent monoTorrent;
@ -172,14 +151,22 @@ public class Torrents(
throw new($"{ex.Message}, trying to parse {fileAsBase64}");
}
var id = await TorrentClient.AddFile(bytes);
torrent.RdStatus = TorrentStatus.NotYetAdded;
torrent.RdName = monoTorrent.Name;
var hash = monoTorrent.InfoHashes.V1OrV2.ToHex();
var newTorrent = await Add(id, hash, fileAsBase64, true, torrent);
var newTorrent = await AddQueued(hash, fileAsBase64, true, torrent);
Log($"Adding {hash} torrent file", newTorrent);
Log($"Adding {hash} (torrent file) to queue", newTorrent);
await CopyAddedTorrent(monoTorrent.Name, bytes);
return newTorrent;
}
private async Task CopyAddedTorrent(String torrentName, Object fileOrMagnet)
{
if (!String.IsNullOrWhiteSpace(Settings.Get.General.CopyAddedTorrents))
{
try
@ -189,22 +176,73 @@ public class Torrents(
Directory.CreateDirectory(Settings.Get.General.CopyAddedTorrents);
}
var copyFileName = Path.Combine(Settings.Get.General.CopyAddedTorrents, $"{FileHelper.RemoveInvalidFileNameChars(monoTorrent.Name)}.torrent");
var copyFileName = Path.Combine(Settings.Get.General.CopyAddedTorrents, FileHelper.RemoveInvalidFileNameChars(torrentName));
switch (fileOrMagnet)
{
case String:
copyFileName = $"{copyFileName}.magnet";
break;
case Byte[]:
copyFileName = $"{copyFileName}.torrent";
break;
default:
throw new ArgumentException("Unexpected type for fileOrMagnet");
}
if (File.Exists(copyFileName))
{
File.Delete(copyFileName);
}
await File.WriteAllBytesAsync(copyFileName, bytes);
switch (fileOrMagnet)
{
case String magnetLink:
await File.WriteAllTextAsync(copyFileName, magnetLink);
break;
case Byte[] torrentFile:
await File.WriteAllBytesAsync(copyFileName, torrentFile);
break;
}
}
catch (Exception ex)
{
logger.LogError(ex, $"Unable to create torrent blackhole directory: {Settings.Get.General.CopyAddedTorrents}: {ex.Message}");
}
}
}
return newTorrent;
/// <summary>
/// Adds torrent in database to debrid provider and updates database accordingly.
/// </summary>
/// <param name="torrent">The torrent from the database to upload to the debrid provider</param>
/// <returns>Updated torrent</returns>
/// <exception cref="Exception">When RdId is not null or FileOrMagnet is null.</exception>
public async Task<Torrent> DequeueFromDebridQueue(Torrent torrent)
{
if (torrent.RdId != null)
{
throw new("Torrent already added to debrid provider, cannot dequeue");
}
if (torrent.FileOrMagnet == null)
{
throw new("Torrent has no torrent file or magnet link");
}
logger.LogDebug("Adding {hash} to debrid provider {torrentInfo}", torrent.Hash, torrent.ToLog());
var id = (torrent.IsFile) switch
{
true => await TorrentClient.AddFile(Convert.FromBase64String(torrent.FileOrMagnet)),
false => await TorrentClient.AddMagnet(torrent.FileOrMagnet)
};
await torrentData.UpdateRdId(torrent, id);
await UpdateTorrentClientData(torrent);
return torrent;
}
public async Task<IList<TorrentClientAvailableFile>> GetAvailableFiles(String hash)
@ -538,11 +576,11 @@ public class Torrents(
{
var bytes = Convert.FromBase64String(torrent.FileOrMagnet);
newTorrent = await UploadFile(bytes, torrent);
newTorrent = await AddFileToDebridQueue(bytes, torrent);
}
else
{
newTorrent = await UploadMagnet(torrent.FileOrMagnet, torrent);
newTorrent = await AddMagnetToDebridQueue(torrent.FileOrMagnet, torrent);
}
await torrentData.UpdateRetry(newTorrent.TorrentId, null, retryCount);
@ -670,11 +708,10 @@ public class Torrents(
return settingDownloadPath;
}
private async Task<Torrent> Add(String rdTorrentId,
String infoHash,
String fileOrMagnetContents,
Boolean isFile,
Torrent torrent)
private async Task<Torrent> AddQueued(String infoHash,
String fileOrMagnetContents,
Boolean isFile,
Torrent torrent)
{
await RealDebridUpdateLock.WaitAsync();
@ -687,15 +724,13 @@ public class Torrents(
return existingTorrent;
}
var newTorrent = await torrentData.Add(rdTorrentId,
var newTorrent = await torrentData.Add(null,
infoHash,
fileOrMagnetContents,
isFile,
torrent.DownloadClient,
torrent);
await UpdateTorrentClientData(newTorrent);
return newTorrent;
}
finally

View file

@ -84,7 +84,7 @@ public class TorrentsController(ILogger<TorrentsController> logger, Torrents tor
var bytes = memoryStream.ToArray();
await torrents.UploadFile(bytes, formData.Torrent);
await torrents.AddFileToDebridQueue(bytes, formData.Torrent);
return Ok();
}
@ -110,7 +110,7 @@ public class TorrentsController(ILogger<TorrentsController> logger, Torrents tor
logger.LogDebug($"Add magnet");
await torrents.UploadMagnet(request.MagnetLink, request.Torrent);
await torrents.AddMagnetToDebridQueue(request.MagnetLink, request.Torrent);
return Ok();
}