2023-05-20 00:04:45 +02:00
|
|
|
using System;
|
2023-05-18 01:27:11 +02:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Threading.Tasks;
|
2023-05-29 18:02:24 +02:00
|
|
|
using Argotic.Common;
|
|
|
|
using Argotic.Syndication;
|
2023-05-22 15:55:21 +02:00
|
|
|
using Serilog;
|
2023-05-18 01:27:11 +02:00
|
|
|
using SharpRss.Models;
|
|
|
|
|
|
|
|
namespace SharpRss.Services
|
|
|
|
{
|
|
|
|
/// <summary>
|
2023-06-11 02:28:16 +02:00
|
|
|
/// Managing RSS feeds and categories.
|
2023-05-18 01:27:11 +02:00
|
|
|
/// </summary>
|
2023-06-04 19:00:46 +02:00
|
|
|
public class RssService
|
2023-05-18 01:27:11 +02:00
|
|
|
{
|
|
|
|
public RssService()
|
|
|
|
{
|
2023-06-11 02:28:16 +02:00
|
|
|
SetupTestCategoriesAndFeedsAsync();
|
2023-05-18 01:27:11 +02:00
|
|
|
}
|
2023-05-23 15:04:02 +02:00
|
|
|
|
2023-06-11 02:28:16 +02:00
|
|
|
public async Task<HashSet<object>> GetCategoriesAndFeedsAsync()
|
2023-05-23 15:04:02 +02:00
|
|
|
{
|
|
|
|
HashSet<object> items = new HashSet<object>();
|
2023-06-02 15:45:10 +02:00
|
|
|
items.UnionWith(await GetCategoriesAsync());
|
2023-05-23 15:04:02 +02:00
|
|
|
items.UnionWith(await GetUngroupedFeedsAsync());
|
|
|
|
return items;
|
|
|
|
}
|
2023-06-11 02:28:16 +02:00
|
|
|
|
|
|
|
public async Task<CategoryModel?> CreateCategoryAsync(CategoryModel category) =>
|
|
|
|
await DbAccess.SetCategoryAsync(category);
|
2023-06-04 19:00:46 +02:00
|
|
|
public async Task<HashSet<CategoryModel>> GetCategoriesAsync() => await DbAccess.GetCategoriesAsync();
|
|
|
|
public async Task<bool> AddSubscriptionAsync(string url, CategoryModel? category = null)
|
2023-05-22 15:55:21 +02:00
|
|
|
{
|
2023-06-04 19:00:46 +02:00
|
|
|
var syndication = SyndicationManager.CreateSyndication(url);
|
2023-06-11 02:28:16 +02:00
|
|
|
if (!syndication.Fetched)
|
|
|
|
{
|
|
|
|
Log.Debug("Failed to fetch syndication feed!");
|
|
|
|
return false;
|
|
|
|
}
|
2023-06-04 19:00:46 +02:00
|
|
|
if (category != null)
|
|
|
|
syndication.Category = category;
|
2023-06-11 02:28:16 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
await DbAccess.SetSyndicationAsync(syndication);
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
Log.Error(e,"Error adding feed: {FeedUrl} to database!", url);
|
|
|
|
}
|
2023-06-02 11:56:48 +02:00
|
|
|
return true;
|
2023-05-29 16:14:26 +02:00
|
|
|
}
|
2023-06-11 02:28:16 +02:00
|
|
|
public async Task UpdateFeeds()
|
|
|
|
{
|
|
|
|
Log.Verbose("Fetching feeds...");
|
|
|
|
var feeds = await GetFeedsAsync();
|
|
|
|
}
|
|
|
|
public async Task<HashSet<FeedModel>> GetFeedsAsync(string? categoryId = null) => await DbAccess.GetFeedsAsync(categoryId == null ? null : new[]{ categoryId });
|
|
|
|
public async Task<HashSet<FeedModel>> GetUngroupedFeedsAsync() => await DbAccess.GetFeedsAsync(new []{""});
|
|
|
|
public async Task<HashSet<FeedItemModel>> GetFeedItemsAsync(string feedId, string? groupId = null) => await GetFeedItemsFromFeedsAsync(new[] { feedId }, groupId);
|
|
|
|
public async Task<HashSet<FeedItemModel>> GetFeedItemsFromFeedsAsync(string[] feedIds, string? groupId = null)
|
|
|
|
{
|
|
|
|
var items = await DbAccess.GetFeedItemsAsync(feedIds);
|
|
|
|
return items;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-06-01 15:55:15 +02:00
|
|
|
private static FeedModel FromResource(ISyndicationResource resource)
|
|
|
|
{
|
2023-06-02 10:56:30 +02:00
|
|
|
FeedModel model = new FeedModel();
|
|
|
|
switch (resource.Format)
|
2023-06-01 15:55:15 +02:00
|
|
|
{
|
2023-06-02 10:56:30 +02:00
|
|
|
case SyndicationContentFormat.Rss:
|
|
|
|
RssFeed rssFeed = (RssFeed)resource;
|
2023-06-02 11:56:48 +02:00
|
|
|
model.FeedType = rssFeed.Format.ToString();
|
|
|
|
model.Title = rssFeed.Channel.Title;
|
|
|
|
model.Description = rssFeed.Channel.Description;
|
|
|
|
model.Copyright = rssFeed.Channel.Copyright;
|
2023-06-11 02:28:16 +02:00
|
|
|
model.EncodedUrl = rssFeed.Channel.SelfLink.ToString();
|
2023-06-04 19:00:46 +02:00
|
|
|
model.ImageUrl = rssFeed.Channel.Image?.Url.ToString() ?? string.Empty;
|
2023-06-02 11:56:48 +02:00
|
|
|
model.Language = rssFeed.Channel.Language?.ToString();
|
2023-06-02 10:56:30 +02:00
|
|
|
break;
|
|
|
|
case SyndicationContentFormat.Atom:
|
|
|
|
AtomFeed atomFeed = (AtomFeed)resource;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Log.Information("Feed implementation missing!");
|
2023-06-01 15:55:15 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return model;
|
|
|
|
}
|
2023-05-29 18:02:24 +02:00
|
|
|
private GenericSyndicationFeed? CreateFeed(string url)
|
2023-05-22 15:55:21 +02:00
|
|
|
{
|
2023-05-29 18:02:24 +02:00
|
|
|
Uri feedUri = new Uri(url);
|
|
|
|
Log.Verbose("Checking feed: {FeedUrl}", feedUri.ToString());
|
|
|
|
if (!SyndicationDiscoveryUtility.UriExists(feedUri))
|
|
|
|
{
|
|
|
|
Log.Warning("Feed: {FeedUri} does not exists!", feedUri.ToString());
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
Log.Verbose("Fetching feed: {FeedUrl}", feedUri.ToString());
|
|
|
|
return GenericSyndicationFeed.Create(new Uri(url));
|
2023-05-22 15:55:21 +02:00
|
|
|
}
|
2023-06-11 02:28:16 +02:00
|
|
|
private async void SetupTestCategoriesAndFeedsAsync()
|
2023-05-18 01:27:11 +02:00
|
|
|
{
|
2023-06-11 02:28:16 +02:00
|
|
|
/*CategoryModel? newsCategory = await CreateCategoryAsync(new CategoryModel() { Name = "News" });
|
|
|
|
if (newsCategory != null)
|
2023-05-25 21:51:05 +02:00
|
|
|
{
|
2023-06-11 02:28:16 +02:00
|
|
|
await AddSubscriptionAsync("https://www.nu.nl/rss/Algemeen", newsCategory);
|
2023-06-14 20:29:21 +02:00
|
|
|
await AddSubscriptionAsync("https://www.ad.nl/home/rss.xml", newsCategory);
|
2023-06-11 02:28:16 +02:00
|
|
|
await AddSubscriptionAsync("https://www.nasa.gov/rss/dyn/breaking_news.rss", newsCategory);
|
|
|
|
await AddSubscriptionAsync("http://news.google.com/?output=atom", newsCategory);
|
2023-06-14 20:29:21 +02:00
|
|
|
}*/
|
2023-06-11 02:28:16 +02:00
|
|
|
|
2023-06-14 20:29:21 +02:00
|
|
|
/*CategoryModel? techCategory = await CreateCategoryAsync(new CategoryModel() { Name = "Tech" });
|
2023-06-11 02:28:16 +02:00
|
|
|
if (techCategory != null)
|
2023-05-27 00:32:05 +02:00
|
|
|
{
|
2023-06-11 02:28:16 +02:00
|
|
|
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);
|
|
|
|
}
|
2023-06-04 19:00:46 +02:00
|
|
|
|
2023-06-11 02:28:16 +02:00
|
|
|
CategoryModel? youtubeCategory = await CreateCategoryAsync(new CategoryModel() { Name = "YouTube" });
|
|
|
|
if (youtubeCategory != null)
|
2023-05-29 18:02:24 +02:00
|
|
|
{
|
2023-06-11 02:28:16 +02:00
|
|
|
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");*/
|
2023-05-18 01:27:11 +02:00
|
|
|
}
|
2023-05-29 16:14:26 +02:00
|
|
|
}
|
2023-05-18 01:27:11 +02:00
|
|
|
}
|