using System; using System.Collections.Generic; using System.Threading.Tasks; using Argotic.Common; using Argotic.Syndication; using Serilog; using SharpRss.Models; namespace SharpRss.Services { /// /// Managing syndication feeds and categories. /// public class SyndicationService { public SyndicationService() { Log.Information("Constructing SyndicationService..."); Task.Run(async () => await SetupTestCategoriesAndFeedsAsync()); } public async Task> GetCategoriesAndSyndicationsAsync() { HashSet items = new HashSet(); items.UnionWith(await GetCategoriesAsync()); items.UnionWith(await GetUngroupedSyndicationsAsync()); return items; } public async Task CreateCategoryAsync(CategoryModel category) => await DbAccess.SetCategoryAsync(category); public async Task> GetCategoriesAsync() { HashSet categories = await DbAccess.GetCategoriesAsync(); foreach (CategoryModel catModel in categories) { catModel.Syndications = await DbAccess.GetSyndicationsAsync(new[] { catModel.Id }); } return categories; } private async void ForEachCategories(CategoryModel x) => x.Syndications = await DbAccess.GetSyndicationsAsync(new[] { x.Id }); public async Task AddSubscriptionAsync(string url, CategoryModel? category = null) { var syndication = SyndicationManager.CreateSyndication(url); if (!syndication.Fetched) { Log.Warning("Failed to fetch syndication feed!"); return false; } if (category != null) syndication.Category = category; try { await DbAccess.SetSyndicationAsync(syndication); } catch (Exception e) { Log.Error(e,"Error adding syndication: {FeedUrl} to database!", url); } return true; } public async Task UpdateFeeds() { Log.Information("Fetching..."); var feeds = await GetSyndicationsAsync(); } public async Task> GetSyndicationsAsync(string? categoryId = null) => await DbAccess.GetSyndicationsAsync(categoryId == null ? null : new[]{ categoryId }); public async Task> GetUngroupedSyndicationsAsync() => await DbAccess.GetSyndicationsAsync(new []{""}); public async Task> GetSyndicationItemsAsync(string feedId, string? groupId = null) => await GetSyndicationItemsFromSyndicationsAsync(new[] { feedId }, groupId); public async Task> GetSyndicationItemsFromSyndicationsAsync(string[] feedIds, string? categoryId = null) { var items = await DbAccess.GetSyndicationItemsAsync(feedIds); return items; } private static SyndicationModel FromResource(ISyndicationResource resource) { SyndicationModel model = new SyndicationModel(); switch (resource.Format) { case SyndicationContentFormat.Rss: RssFeed rssFeed = (RssFeed)resource; model.SyndicationType = rssFeed.Format.ToString(); model.Title = rssFeed.Channel.Title; model.Description = rssFeed.Channel.Description; model.Copyright = rssFeed.Channel.Copyright; model.EncodedUrl = rssFeed.Channel.SelfLink.ToString(); model.ImageUrl = rssFeed.Channel.Image?.Url.ToString() ?? string.Empty; model.Language = rssFeed.Channel.Language?.ToString(); break; case SyndicationContentFormat.Atom: AtomFeed atomFeed = (AtomFeed)resource; break; default: Log.Information("Syndication implementation missing!"); break; } return model; } private GenericSyndicationFeed? CreateSyndication(string url) { Uri feedUri = new Uri(url); Log.Verbose("Checking syndication: {FeedUrl}", feedUri.ToString()); if (!SyndicationDiscoveryUtility.UriExists(feedUri)) { Log.Warning("Syndication: {FeedUri} does not exists!", feedUri.ToString()); return null; } Log.Verbose("Fetching syndication: {FeedUrl}", feedUri.ToString()); return GenericSyndicationFeed.Create(new Uri(url)); } private async Task SetupTestCategoriesAndFeedsAsync() { Log.Information("Setting up test data..."); try { CategoryModel? newsCategory = await CreateCategoryAsync(new CategoryModel() { Name = "News", Icon = ""}); if (newsCategory != null) { await AddSubscriptionAsync("https://www.nu.nl/rss/Algemeen", newsCategory); await AddSubscriptionAsync("https://www.ad.nl/home/rss.xml", newsCategory); await AddSubscriptionAsync("https://www.nasa.gov/rss/dyn/breaking_news.rss", newsCategory); await AddSubscriptionAsync("http://news.google.com/?output=atom", newsCategory); } CategoryModel? techCategory = await CreateCategoryAsync(new CategoryModel() { Name = "Tech", Icon = ""}); if (techCategory != null) { await AddSubscriptionAsync("https://itsfoss.com/feed", techCategory); await AddSubscriptionAsync("http://fedoramagazine.org/feed/", techCategory); await AddSubscriptionAsync("https://arstechnica.com/feed/", techCategory); await AddSubscriptionAsync("https://feeds.arstechnica.com/arstechnica/gadgets", techCategory); } CategoryModel? youtubeCategory = await CreateCategoryAsync(new CategoryModel() { Name = "YouTube", Icon = ""}); if (youtubeCategory != null) { await AddSubscriptionAsync("https://www.youtube.com/feeds/videos.xml?channel_id=UCXuqSBlHAE6Xw-yeJA0Tunw", youtubeCategory); await AddSubscriptionAsync("https://www.youtube.com/feeds/videos.xml?channel_id=UC1Et9K-hHf-P_LzQkE_Q3Jw", youtubeCategory); await AddSubscriptionAsync("https://www.youtube.com/feeds/videos.xml?channel_id=UCsXVk37bltHxD1rDPwtNM8Q", youtubeCategory); } await AddSubscriptionAsync("http://www.digitaleoverheid.nl/feed/"); await AddSubscriptionAsync("http://www.digitaleoverheid.nl/agenda/feed/"); await AddSubscriptionAsync("https://feeds.rijksoverheid.nl/nieuws.rss"); await AddSubscriptionAsync("https://nl.wikipedia.org/w/index.php?title=Speciaal:RecenteWijzigingen&feed=atom"); await AddSubscriptionAsync("https://feeds.aivd.nl/nieuws.rss"); await AddSubscriptionAsync("https://blogs.microsoft.com/feed"); await AddSubscriptionAsync("https://www.europarl.europa.eu/rss/doc/top-stories/nl.xml"); } catch (Exception e) { Log.Error(e, "Exception!"); } } } }