diff --git a/OF DL/Extension.props b/OF DL/Extension.props new file mode 100644 index 0000000..d182524 --- /dev/null +++ b/OF DL/Extension.props @@ -0,0 +1,5 @@ + + + + + diff --git a/OF DL/Helpers/APIHelper.cs b/OF DL/Helpers/APIHelper.cs index d82be2f..ed812f8 100644 --- a/OF DL/Helpers/APIHelper.cs +++ b/OF DL/Helpers/APIHelper.cs @@ -2873,4 +2873,81 @@ public class APIHelper : IAPIHelper } return null; } + + public async Task?> GetActiveSubscribed(string endpoint, bool includeRestricted, IDownloadConfig config) + { + Dictionary getParams = new() + { + { "offset", "0" }, + { "limit", "50" }, + { "type", "active" }, + { "format", "infinite"} + }; + + return await GetSubscriptions(getParams, endpoint, includeRestricted, config); + } + + public async Task?> GetSubscriptions(Dictionary getParams, string endpoint, bool includeRestricted, IDownloadConfig config) + { + try + { + Dictionary users = new(); + Subscriptions subscriptions = new(); + + Log.Debug("Calling GetAllSubscrptions"); + + string? body = await BuildHeaderAndExecuteRequests(getParams, endpoint, new HttpClient()); + + subscriptions = JsonConvert.DeserializeObject(body); + if (subscriptions != null && subscriptions.hasMore) + { + getParams["offset"] = subscriptions.list.Count.ToString(); + + while (true) + { + Subscriptions newSubscriptions = new(); + string? loopbody = await BuildHeaderAndExecuteRequests(getParams, endpoint, new HttpClient()); + + if (!string.IsNullOrEmpty(loopbody) && (!loopbody.Contains("[]") || loopbody.Trim() != "[]")) + { + newSubscriptions = JsonConvert.DeserializeObject(loopbody, m_JsonSerializerSettings); + } + else + { + break; + } + + subscriptions.list.AddRange(newSubscriptions.list); + if (!newSubscriptions.hasMore) + { + break; + } + getParams["offset"] = subscriptions.list.Count.ToString(); + } + } + + foreach (Subscriptions.List subscription in subscriptions.list) + { + if ((!(subscription.isRestricted ?? false) || ((subscription.isRestricted ?? false) && includeRestricted)) + && !users.ContainsKey(subscription.username)) + { + users.Add(subscription.username, subscription); + } + } + + return users; + } + catch (Exception ex) + { + Console.WriteLine("Exception caught: {0}\n\nStackTrace: {1}", ex.Message, ex.StackTrace); + Log.Error("Exception caught: {0}\n\nStackTrace: {1}", ex.Message, ex.StackTrace); + if (ex.InnerException != null) + { + Console.WriteLine("\nInner Exception:"); + Console.WriteLine("Exception caught: {0}\n\nStackTrace: {1}", ex.InnerException.Message, ex.InnerException.StackTrace); + Log.Error("Inner Exception: {0}\n\nStackTrace: {1}", ex.InnerException.Message, ex.InnerException.StackTrace); + } + } + return null; + } } diff --git a/OF DL/OF DL.csproj b/OF DL/OF DL.csproj index 20dc207..f14d2e6 100644 --- a/OF DL/OF DL.csproj +++ b/OF DL/OF DL.csproj @@ -1,49 +1,50 @@  - - Exe - net8.0 - OF_DL - enable - enable - Icon\download.ico - + + Exe + net8.0 + OF_DL + enable + enable + Icon\download.ico + - - - + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - References\Spectre.Console.dll - - + + + References\Spectre.Console.dll + + - - - Always - - - Always - - - Always - - + + + Always + + + Always + + + Always + + + diff --git a/OF DL/Program.cs b/OF DL/Program.cs index b47be8c..55316fd 100644 --- a/OF DL/Program.cs +++ b/OF DL/Program.cs @@ -844,9 +844,17 @@ public class Program { DateTime startTime = DateTime.Now; Dictionary users = new(); - Dictionary activeSubs = await m_ApiHelper.GetActiveSubscriptions("/subscriptions/subscribes", Config.IncludeRestrictedSubscriptions, Config); - - Log.Debug("Subscriptions: "); + var activeSubbed = await m_ApiHelper.GetActiveSubscribed("/subscriptions/subscribes", Config.IncludeRestrictedSubscriptions, Config); + var activeSubs = activeSubbed?.ToDictionary(e => e.Key, e => e.Value.id); + { + if (Directory.Exists(Config.DownloadPath) && activeSubbed != null) + { + var reportPath = Path.Combine(Config.DownloadPath, "Report.csv"); + var report = new Reporting(activeSubbed?.Values); + report.GenerateReport(reportPath); + } + } + Log.Debug("Subscriptions: "); foreach (KeyValuePair activeSub in activeSubs) { diff --git a/OF DL/Reporting.cs b/OF DL/Reporting.cs new file mode 100644 index 0000000..a37bc8d --- /dev/null +++ b/OF DL/Reporting.cs @@ -0,0 +1,106 @@ +using CsvHelper; +using CsvHelper.Configuration; +using System.Formats.Asn1; +using System.Globalization; +using System.Runtime.CompilerServices; + +namespace OF_DL; + +internal class Reporting(IEnumerable subscribedUsers) +{ + public void GenerateReport(string reportPath) + { + using var fileStream = File.Open(reportPath, FileMode.Create); + using var streamWriter = new StreamWriter(fileStream); + using var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture); + + csvWriter.Context.RegisterClassMap(); + csvWriter.WriteRecords(subscribedUsers.Select(user => new UserReportViewModel(user)).OrderByDescending(e => e.category).ThenBy(e => e.currentTotal)); + } +} + +internal class UserReportViewModel +{ + private readonly Entities.Subscriptions.List source; + + public const long YoursId = 817758071L; + public const long MineId = 817758033L; + public const decimal tax = 0.2m; + + private Lazy _category; + private Lazy _currentPrice; + private Lazy _nextPrice; + + public UserReportViewModel(Entities.Subscriptions.List source) + { + this.source = source; + _category = new Lazy(GetCategory); + _currentPrice = new Lazy(() => decimal.TryParse(source.subscribedByData.price, out var price) ? price : null); + _nextPrice = new Lazy(() => decimal.TryParse(source.subscribedByData.regularPrice, out var price) ? price : null); + } + + public string name => source.name; + + public string username => source.username; + + public string category => GetCategory(); + + public string status => GetStatus(); + + public DateTime? until => source.subscribedByData.expiredAt; + + public decimal? currentPrice => _currentPrice.Value; + + public decimal? currentTax => currentPrice * tax; + + public decimal? currentTotal => currentPrice + currentTax; + + public decimal? renewPrice => _nextPrice.Value; + + public decimal? renewTax => renewPrice * tax; + + public decimal? renewTotal => renewPrice + renewTax; + + public string GetCategory() + { + if (source.listsStates.SingleOrDefault(l => l.id is long intId && intId == YoursId && l.hasUser == true) is { } yours) + { + return yours.name; + } + if (source.listsStates.SingleOrDefault(l => l.id is long intId && intId == MineId && l.hasUser == true) is { } mine) + { + return mine.name; + } + return "None"; + } + + public string GetStatus() + { + if (source.subscribedByData is { } subData) + { + if (!string.IsNullOrEmpty(subData.status)) return subData.status; + return "Subscribed"; + } + return "API Error"; + } + +} + +internal class UserReportViewModelClassMap : ClassMap +{ + public UserReportViewModelClassMap() + { + var index = 0; + Map(m => m.name).Index(index++).Name("Name"); + Map(m => m.username).Index(index++).Name("Username"); + Map(m => m.category).Index(index++).Name("Category"); + Map(m => m.status).Index(index++).Name("Status"); + Map(m => m.until).Index(index++).Name("Until"); + Map(m => m.currentPrice).Index(index++).Name("Price"); + Map(m => m.currentTax).Index(index++).Name("Tax"); + Map(m => m.currentTotal).Index(index++).Name("Total"); + Map(m => m.renewPrice).Index(index++).Name("Price"); + Map(m => m.renewTax).Index(index++).Name("Tax"); + Map(m => m.renewTotal).Index(index++).Name("Total"); + } +}