#nullable enable using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; namespace TransmissionRssManager.Core { public class LogEntry { public int Id { get; set; } public DateTime Timestamp { get; set; } public string Level { get; set; } = string.Empty; public string Message { get; set; } = string.Empty; public string Context { get; set; } = string.Empty; public string Properties { get; set; } = string.Empty; } public class RssFeedItem { public string Id { get; set; } = string.Empty; public string Title { get; set; } = string.Empty; public string Link { get; set; } = string.Empty; public string Description { get; set; } = string.Empty; public DateTime PublishDate { get; set; } public string TorrentUrl { get; set; } = string.Empty; public bool IsDownloaded { get; set; } public bool IsMatched { get; set; } public string MatchedRule { get; set; } = string.Empty; public string FeedId { get; set; } = string.Empty; public string Category { get; set; } = string.Empty; public long Size { get; set; } public string Author { get; set; } = string.Empty; public List Categories { get; set; } = new List(); public Dictionary AdditionalMetadata { get; set; } = new Dictionary(); public DateTime? DownloadDate { get; set; } public int? TorrentId { get; set; } public string RejectionReason { get; set; } = string.Empty; public bool IsRejected => !string.IsNullOrEmpty(RejectionReason); } public class TorrentInfo { public int Id { get; set; } public string Name { get; set; } = string.Empty; public string Status { get; set; } = string.Empty; public double PercentDone { get; set; } public long TotalSize { get; set; } public string DownloadDir { get; set; } = string.Empty; public bool IsFinished => PercentDone >= 1.0; public DateTime? AddedDate { get; set; } public DateTime? CompletedDate { get; set; } public long DownloadedEver { get; set; } public long UploadedEver { get; set; } public int UploadRatio { get; set; } public string ErrorString { get; set; } = string.Empty; public bool IsError => !string.IsNullOrEmpty(ErrorString); public int Priority { get; set; } public string HashString { get; set; } = string.Empty; public int PeersConnected { get; set; } public double DownloadSpeed { get; set; } public double UploadSpeed { get; set; } public string Category { get; set; } = string.Empty; public bool HasMetadata { get; set; } public string TransmissionInstance { get; set; } = "default"; public string SourceFeedId { get; set; } = string.Empty; public bool IsPostProcessed { get; set; } } public class RssFeed { public string Id { get; set; } = string.Empty; public string Url { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; public List Rules { get; set; } = new List(); public List AdvancedRules { get; set; } = new List(); public bool AutoDownload { get; set; } public DateTime LastChecked { get; set; } public string TransmissionInstanceId { get; set; } = "default"; public string Schedule { get; set; } = "*/30 * * * *"; // Default is every 30 minutes (cron expression) public bool Enabled { get; set; } = true; public int MaxHistoryItems { get; set; } = 100; public string DefaultCategory { get; set; } = string.Empty; public int ErrorCount { get; set; } = 0; public DateTime? LastError { get; set; } public string LastErrorMessage { get; set; } = string.Empty; } public class AppConfig { public TransmissionConfig Transmission { get; set; } = new TransmissionConfig(); public Dictionary TransmissionInstances { get; set; } = new Dictionary(); public List Feeds { get; set; } = new List(); public bool AutoDownloadEnabled { get; set; } public int CheckIntervalMinutes { get; set; } = 30; public string DownloadDirectory { get; set; } = string.Empty; public string MediaLibraryPath { get; set; } = string.Empty; public PostProcessingConfig PostProcessing { get; set; } = new PostProcessingConfig(); public bool EnableDetailedLogging { get; set; } = false; public UserPreferences UserPreferences { get; set; } = new UserPreferences(); } public class TransmissionConfig { public string Host { get; set; } = "localhost"; public int Port { get; set; } = 9091; public string Username { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; public bool UseHttps { get; set; } = false; public string Url => $"{(UseHttps ? "https" : "http")}://{Host}:{Port}/transmission/rpc"; } public class RssFeedRule { public string Id { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; public string Pattern { get; set; } = string.Empty; public bool IsRegex { get; set; } = false; public bool IsEnabled { get; set; } = true; public bool IsCaseSensitive { get; set; } = false; public string Category { get; set; } = string.Empty; public int Priority { get; set; } = 0; public string Action { get; set; } = "download"; // download, notify, ignore public string DestinationFolder { get; set; } = string.Empty; } public class PostProcessingConfig { public bool Enabled { get; set; } = false; public bool ExtractArchives { get; set; } = true; public bool OrganizeMedia { get; set; } = true; public int MinimumSeedRatio { get; set; } = 1; public List MediaExtensions { get; set; } = new List { ".mp4", ".mkv", ".avi" }; public bool AutoOrganizeByMediaType { get; set; } = true; public bool RenameFiles { get; set; } = false; public bool CompressCompletedFiles { get; set; } = false; public int DeleteCompletedAfterDays { get; set; } = 0; // 0 = never delete } public class UserPreferences { public bool EnableDarkMode { get; set; } = false; public bool AutoRefreshUIEnabled { get; set; } = true; public int AutoRefreshIntervalSeconds { get; set; } = 30; public bool NotificationsEnabled { get; set; } = true; public List NotificationEvents { get; set; } = new List { "torrent-added", "torrent-completed", "torrent-error" }; public string DefaultView { get; set; } = "dashboard"; public bool ConfirmBeforeDelete { get; set; } = true; public int MaxItemsPerPage { get; set; } = 25; public string DateTimeFormat { get; set; } = "yyyy-MM-dd HH:mm:ss"; public bool ShowCompletedTorrents { get; set; } = true; public int KeepHistoryDays { get; set; } = 30; } public interface IConfigService { AppConfig GetConfiguration(); Task SaveConfigurationAsync(AppConfig config); } public interface ITransmissionClient { Task> GetTorrentsAsync(); Task AddTorrentAsync(string torrentUrl, string downloadDir); Task RemoveTorrentAsync(int id, bool deleteLocalData); Task StartTorrentAsync(int id); Task StopTorrentAsync(int id); } public interface IRssFeedManager { Task> GetAllItemsAsync(); Task> GetMatchedItemsAsync(); Task> GetFeedsAsync(); Task AddFeedAsync(RssFeed feed); Task RemoveFeedAsync(string feedId); Task UpdateFeedAsync(RssFeed feed); Task RefreshFeedsAsync(CancellationToken cancellationToken); Task RefreshFeedAsync(string feedId, CancellationToken cancellationToken); Task MarkItemAsDownloadedAsync(string itemId); } public interface IPostProcessor { Task ProcessCompletedDownloadsAsync(CancellationToken cancellationToken); Task ProcessTorrentAsync(TorrentInfo torrent); } }