using Cleanuparr.Domain.Entities; using Cleanuparr.Infrastructure.Extensions; using Cleanuparr.Infrastructure.Features.DownloadClient.UTorrent.Extensions; using Cleanuparr.Infrastructure.Services; using QBittorrent.Client; namespace Cleanuparr.Infrastructure.Features.DownloadClient.QBittorrent; /// /// Wrapper for QBittorrent TorrentInfo that implements ITorrentItem interface /// public sealed class QBitItemWrapper : ITorrentItemWrapper { private readonly IReadOnlyList _trackers; private readonly Lazy> _trackerDomains; public TorrentInfo Info { get; } public QBitItemWrapper(TorrentInfo torrentInfo, IReadOnlyList trackers, bool isPrivate) { Info = torrentInfo ?? throw new ArgumentNullException(nameof(torrentInfo)); _trackers = trackers ?? throw new ArgumentNullException(nameof(trackers)); IsPrivate = isPrivate; _trackerDomains = new Lazy>(() => _trackers .Select(t => UriService.GetDomain(t.Url)) .Where(d => d is not null) .Select(d => d!) .ToList() .AsReadOnly()); } public string Hash => Info.Hash ?? string.Empty; public string Name => Info.Name ?? string.Empty; public bool IsPrivate { get; } public long Size => Info.Size; public double CompletionPercentage => Info.Progress * 100.0; public long DownloadedBytes => Info.Downloaded ?? 0; public long DownloadSpeed => Info.DownloadSpeed; public double Ratio => Info.Ratio; public long Eta => Info.EstimatedTime?.TotalSeconds is { } eta ? (long)eta : 0; public long SeedingTimeSeconds => Info.SeedingTime?.TotalSeconds is { } seedTime ? (long)seedTime : 0; public string? Category { get => Info.Category; set => Info.Category = value; } public string SavePath => Info.SavePath ?? string.Empty; public IReadOnlyList TrackerDomains => _trackerDomains.Value; public IReadOnlyList Tags => Info.Tags?.ToList().AsReadOnly() ?? (IReadOnlyList)Array.Empty(); public bool IsDownloading() => Info.State is TorrentState.Downloading or TorrentState.ForcedDownload; public bool IsStalled() => Info.State is TorrentState.StalledDownload; public bool IsSeeding() => Info.State is TorrentState.Uploading or TorrentState.ForcedUpload or TorrentState.StalledUpload; public bool IsMetadataDownloading() => Info.State is TorrentState.FetchingMetadata or TorrentState.ForcedFetchingMetadata; public bool IsIgnored(IReadOnlyList ignoredDownloads) { if (ignoredDownloads.Count == 0) { return false; } foreach (string pattern in ignoredDownloads) { if (Hash.Equals(pattern, StringComparison.InvariantCultureIgnoreCase)) { return true; } if (Category?.Equals(pattern, StringComparison.InvariantCultureIgnoreCase) is true) { return true; } if (Info.Tags?.Contains(pattern, StringComparer.InvariantCultureIgnoreCase) is true) { return true; } if (_trackers.Any(tracker => tracker.ShouldIgnore(ignoredDownloads))) { return true; } } return false; } }