using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using CodeHollow.FeedReader; using Serilog; using SharpRss.Models; using ToolQit.Extensions; namespace SharpRss.Services { /// /// Managing RSS feeds and groups. /// public class RssService : IDisposable { public RssService() { //SetupTestCategoriesAndFeedsAsync(); } private readonly DatabaseService _dbService = new DatabaseService(); public async Task> GetGroupsFeedsAsync() { HashSet items = new HashSet(); items.UnionWith(await GetGroupsAsync()); items.UnionWith(await GetUngroupedFeedsAsync()); return items; } public async Task CreateGroupAsync(GroupModel group) => await _dbService.SetGroupAsync(group); public async Task> GetGroupsAsync() => await _dbService.GetGroupsAsync(); public async Task AddFeed(string rssUrl, GroupModel? group = null) { bool result = false; Feed fetched = await FetchFeed(rssUrl); if (fetched == null) return result; FeedModel feedModel = new FeedModel(rssUrl) { Title = fetched.Title, GroupId = group?.Id ?? string.Empty, FeedType = fetched.Type.ToString(), Description = fetched.Description, Language = fetched.Language, Copyright = fetched.Copyright, DateAdded = DateTimeOffset.Now, LastUpdated = DateTimeOffset.Now, ImageUrl = fetched.ImageUrl, OriginalDocument = fetched.OriginalDocument }; result = await _dbService.SetFeedAsync(feedModel); if (!result) return result; if (await AddFeedItems(fetched.Items, feedModel) == 0) Log.Warning("No feed items added to feed: {FeedUrl}", feedModel.Url); return result; } public async Task> GetFeedsAsync(string? groupId = null) => await _dbService.GetFeedsAsync(groupId); public async Task> GetUngroupedFeedsAsync() => await _dbService.GetFeedsAsync(""); public async Task> GetFeedItemsAsync(string feedId, string? groupId = null) => await GetFeedItemsFromFeedsAsync(new[] { feedId }, groupId); public async Task> GetFeedItemsFromFeedsAsync(string[] feedIds, string? groupId = null) { var items = await _dbService.GetFeedItemsAsync(feedIds); GroupModel? group = null; if (groupId != null) { var model = await _dbService.GetGroupsAsync(groupId); if (model != null && model.Any()) group = model.FirstOrDefault(); } // Update the items with the group data if (group != null) { foreach (FeedItemModel feedItem in items) feedItem.HexColor = group.HexColor; } return items; } private async Task AddFeedItems(IList items, FeedModel feedModel) { int result = 0; if (!items.Any()) return result; HashSet itemModels = new HashSet(); foreach (FeedItem item in items) { itemModels.Add(new FeedItemModel() { Id = item.Id, FeedId = feedModel.Id, Title = item.Title, Description = item.Description, Link = item.Link, LastUpdated = DateTimeOffset.Now, PublishingDate = item.PublishingDate != null ? new DateTimeOffset((DateTime)item.PublishingDate) : null, Author = item.Author, Categories = item.Categories.ToArray(), Content = item.Content }); } result = await _dbService.SetFeedItemsAsync(itemModels); return result; } private async Task FetchFeed(string url) { var urls = await FeedReader.ParseFeedUrlsAsStringAsync(url); string feedurl = url; if (urls.Any()) feedurl = urls.First(); return await FeedReader.ReadAsync(feedurl); } private async void SetupTestCategoriesAndFeedsAsync() { var groupRes = await CreateGroupAsync(new GroupModel() { Name = "Test" }); groupRes = await CreateGroupAsync(new GroupModel() { Name = "News" }); groupRes = await CreateGroupAsync(new GroupModel() { Name = "Tech" }); groupRes = await CreateGroupAsync(new GroupModel() { Name = "Science" }); var groups = await GetGroupsAsync(); GroupModel testGroup = groups.Single(x => x.Name == "Test"); var res = await AddFeed("http://fedoramagazine.org/feed/", testGroup); res = await AddFeed("https://www.nasa.gov/rss/dyn/breaking_news.rss", testGroup); res = await AddFeed("https://journals.plos.org/plosone/feed/atom", testGroup); res = await AddFeed("https://itsfoss.com/feed", testGroup); } public void Dispose() { _dbService.Dispose(); } } }