using Microsoft.Extensions.Logging; using RdtClient.Data.Enums; using RdtClient.Data.Models.Data; using RdtClient.Data.Models.Internal; using RdtClient.Data.Models.Sabnzbd; using RdtClient.Service.Helpers; namespace RdtClient.Service.Services; public class Sabnzbd(ILogger logger, Torrents torrents, AppSettings appSettings) { public virtual async Task GetQueue() { var allTorrents = await torrents.Get(); var activeTorrents = allTorrents.Where(t => t.Type == DownloadType.Nzb && t.Completed == null).ToList(); var queue = new SabnzbdQueue { NoOfSlots = activeTorrents.Count, Slots = activeTorrents.Select((t, index) => { Double downloadProgress = 0; var rdProgress = Math.Clamp(t.RdProgress ?? 0.0, 0.0, 100.0) / 100.0; if (t.Downloads is { Count: > 0 }) { var bytesDone = t.Downloads.Sum(m => m.BytesDone); var bytesTotal = t.Downloads.Sum(m => m.BytesTotal); downloadProgress = bytesTotal > 0 ? Math.Clamp((Double)bytesDone / bytesTotal, 0.0, 1.0) : 0; } var progress = (rdProgress + downloadProgress) / 2.0; var timeLeft = "0:00:00"; var startTime = t.Retry > t.Added ? t.Retry.Value : t.Added; var elapsed = DateTimeOffset.UtcNow - startTime; if (progress is > 0 and < 1.0) { var totalEstimatedTime = TimeSpan.FromTicks((Int64)(elapsed.Ticks / progress)); var remaining = totalEstimatedTime - elapsed; if (remaining.TotalSeconds > 0) { timeLeft = $"{(Int32)remaining.TotalHours}:{remaining.Minutes:D2}:{remaining.Seconds:D2}"; } } return new SabnzbdQueueSlot { Index = index, NzoId = t.Hash, Filename = t.RdName ?? t.Hash, Size = FileSizeHelper.FormatSize(t.Downloads.Sum(d => d.BytesTotal)), SizeLeft = FileSizeHelper.FormatSize(t.Downloads.Sum(d => d.BytesTotal - d.BytesDone)), Percentage = (progress * 100.0).ToString("0"), Status = t.RdStatus switch { TorrentStatus.Processing => "Propagating", TorrentStatus.Finished => "Completed", TorrentStatus.Downloading => "Downloading", TorrentStatus.WaitingForFileSelection => "Propagating", TorrentStatus.Error => "Failed", TorrentStatus.Queued => "Queued", _ => "Downloading" }, Category = t.Category ?? "*", Priority = "Normal", TimeLeft = timeLeft }; }).ToList() }; return queue; } public virtual async Task GetHistory() { var allTorrents = await torrents.Get(); var completedTorrents = allTorrents.Where(t => t.Type == DownloadType.Nzb && t.Completed != null).ToList(); var savePath = Settings.AppDefaultSavePath; var history = new SabnzbdHistory { NoOfSlots = completedTorrents.Count, TotalSlots = completedTorrents.Count, Slots = completedTorrents.Select(t => { var path = savePath; if (!String.IsNullOrWhiteSpace(t.Category)) { path = Path.Combine(path, t.Category); } if (!String.IsNullOrWhiteSpace(t.RdName)) { path = Path.Combine(path, t.RdName); } return new SabnzbdHistorySlot { NzoId = t.Hash, Name = t.RdName ?? t.Hash, Size = FileSizeHelper.FormatSize(t.Downloads.Sum(d => d.BytesTotal)), Status = String.IsNullOrWhiteSpace(t.Error) ? "Completed" : "Failed", Category = t.Category ?? "Default", Path = path }; }).ToList() }; return history; } public virtual async Task AddFile(Byte[] fileBytes, String? fileName, String? category, Int32? priority) { logger.LogDebug($"Add file {category}"); var torrent = new Torrent { Category = category, DownloadClient = Settings.Get.DownloadClient.Client, HostDownloadAction = Settings.Get.Integrations.Default.HostDownloadAction, FinishedActionDelay = Settings.Get.Integrations.Default.FinishedActionDelay, DownloadAction = Settings.Get.Integrations.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll, FinishedAction = TorrentFinishedAction.None, DownloadMinSize = Settings.Get.Integrations.Default.MinFileSize, IncludeRegex = Settings.Get.Integrations.Default.IncludeRegex, ExcludeRegex = Settings.Get.Integrations.Default.ExcludeRegex, TorrentRetryAttempts = Settings.Get.Integrations.Default.TorrentRetryAttempts, DownloadRetryAttempts = Settings.Get.Integrations.Default.DownloadRetryAttempts, DeleteOnError = Settings.Get.Integrations.Default.DeleteOnError, Lifetime = Settings.Get.Integrations.Default.TorrentLifetime, Priority = (priority ?? Settings.Get.Integrations.Default.Priority) > 0 ? 1 : null }; var result = await torrents.AddNzbFileToDebridQueue(fileBytes, fileName, torrent); return result.Hash; } public virtual async Task AddUrl(String url, String? category, Int32? priority) { logger.LogDebug($"Add url {category}"); var torrent = new Torrent { Category = category, DownloadClient = Settings.Get.DownloadClient.Client, HostDownloadAction = Settings.Get.Integrations.Default.HostDownloadAction, FinishedActionDelay = Settings.Get.Integrations.Default.FinishedActionDelay, DownloadAction = Settings.Get.Integrations.Default.OnlyDownloadAvailableFiles ? TorrentDownloadAction.DownloadAvailableFiles : TorrentDownloadAction.DownloadAll, FinishedAction = TorrentFinishedAction.None, DownloadMinSize = Settings.Get.Integrations.Default.MinFileSize, IncludeRegex = Settings.Get.Integrations.Default.IncludeRegex, ExcludeRegex = Settings.Get.Integrations.Default.ExcludeRegex, TorrentRetryAttempts = Settings.Get.Integrations.Default.TorrentRetryAttempts, DownloadRetryAttempts = Settings.Get.Integrations.Default.DownloadRetryAttempts, DeleteOnError = Settings.Get.Integrations.Default.DeleteOnError, Lifetime = Settings.Get.Integrations.Default.TorrentLifetime, Priority = priority ?? (Settings.Get.Integrations.Default.Priority > 0 ? Settings.Get.Integrations.Default.Priority : null) }; var result = await torrents.AddNzbLinkToDebridQueue(url, torrent); return result.Hash; } public virtual async Task Delete(String hash) { var torrent = await torrents.GetByHash(hash); if (torrent != null) { await torrents.Delete(torrent.TorrentId, true, true, true); } } public virtual List GetCategories() { var categoryList = (Settings.Get.General.Categories ?? "") .Split(",", StringSplitOptions.RemoveEmptyEntries) .Select(m => m.Trim()) .Where(m => m != "*") .Distinct(StringComparer.CurrentCultureIgnoreCase) .ToList(); categoryList.Insert(0, "*"); return categoryList; } public virtual SabnzbdConfig GetConfig() { var savePath = Settings.AppDefaultSavePath; var categoryList = GetCategories(); var categories = categoryList.Select((c, i) => new SabnzbdCategory { Name = c, Order = i, Dir = c == "*" ? "" : Path.Combine(savePath, c) }).ToList(); var config = new SabnzbdConfig { Misc = new SabnzbdMisc { CompleteDir = savePath, DownloadDir = savePath, Port = appSettings.Port.ToString(), Version = "4.4.0" }, Categories = categories }; return config; } }