2023-05-29 18:02:24 +02:00
|
|
|
using System;
|
2023-06-04 02:16:47 +02:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
|
|
|
using Argotic.Common;
|
|
|
|
using Argotic.Extensions.Core;
|
2023-05-29 18:02:24 +02:00
|
|
|
using Argotic.Syndication;
|
2023-06-04 02:16:47 +02:00
|
|
|
using Serilog;
|
|
|
|
using SharpRss.Models;
|
2023-05-29 18:02:24 +02:00
|
|
|
|
|
|
|
namespace SharpRss
|
|
|
|
{
|
2023-06-04 02:16:47 +02:00
|
|
|
/// <summary>
|
|
|
|
/// Struct that contains the necessary objects for adding/fetching feeds and items
|
|
|
|
/// </summary>
|
|
|
|
public struct SyndicationContainer
|
|
|
|
{
|
|
|
|
public GenericSyndicationFeed SyndicationFeed { get; set; }
|
|
|
|
public CategoryModel Category { get; set; }
|
|
|
|
public FeedModel FeedModel { get; set; }
|
|
|
|
public HashSet<FeedItemModel> FeedItems { get; set; }
|
|
|
|
}
|
2023-05-29 18:02:24 +02:00
|
|
|
public static class SyndicationManager
|
|
|
|
{
|
2023-06-04 02:16:47 +02:00
|
|
|
public static SyndicationContainer CreateSyndication(string feedUrl)
|
2023-05-29 18:02:24 +02:00
|
|
|
{
|
2023-06-04 02:16:47 +02:00
|
|
|
GenericSyndicationFeed? syndicationFeed = null;
|
2023-05-29 18:02:24 +02:00
|
|
|
Uri feedUri = new Uri(feedUrl);
|
2023-06-04 02:16:47 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
Log.Debug("Fetching feed: {FeedUri}", feedUri.ToString());
|
|
|
|
syndicationFeed = GenericSyndicationFeed.Create(feedUri);
|
|
|
|
}
|
|
|
|
catch (Exception e)
|
|
|
|
{
|
|
|
|
Log.Error(e,"Could not get feed: {FeedUrl}", feedUrl);
|
|
|
|
}
|
|
|
|
return ConstructSyndicationContainer(syndicationFeed);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Stream FeedToStream(GenericSyndicationFeed syndicationFeed)
|
|
|
|
{
|
|
|
|
MemoryStream memStream = new MemoryStream();
|
|
|
|
syndicationFeed.Resource.Save(memStream);
|
|
|
|
if (memStream.Length <= 0)
|
|
|
|
Log.Warning("Failed to serialize {FeedType} feed: {FeedUri}", syndicationFeed.Format.ToString(), syndicationFeed.Title);
|
|
|
|
memStream.Position = 0;
|
|
|
|
return memStream;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static SyndicationContainer ConstructSyndicationContainer(GenericSyndicationFeed? syndicationFeed)
|
|
|
|
{
|
|
|
|
SyndicationContainer container = new SyndicationContainer();
|
|
|
|
if (syndicationFeed == null)
|
|
|
|
{
|
|
|
|
Log.Error("Could not construct syndication container!");
|
|
|
|
return container;
|
|
|
|
}
|
|
|
|
container.SyndicationFeed = syndicationFeed;
|
|
|
|
container.FeedModel = new FeedModel();
|
|
|
|
container.FeedItems = new HashSet<FeedItemModel>();
|
|
|
|
switch (syndicationFeed.Resource.Format)
|
|
|
|
{
|
|
|
|
case SyndicationContentFormat.Rss:
|
|
|
|
RssFeed rssFeed = (RssFeed)container.SyndicationFeed.Resource;
|
|
|
|
container.FeedModel.OriginalUrl = rssFeed.Channel.SelfLink.ToString();
|
|
|
|
container.FeedModel.Title = rssFeed.Channel.Title;
|
|
|
|
container.FeedModel.FeedType = rssFeed.Format.ToString();
|
|
|
|
container.FeedModel.FeedVersion = rssFeed.Version.ToString();
|
|
|
|
container.FeedModel.Description = rssFeed.Channel.Description;
|
|
|
|
container.FeedModel.Language = rssFeed.Channel.Language?.ToString();
|
|
|
|
container.FeedModel.Copyright = rssFeed.Channel.Copyright;
|
|
|
|
container.FeedModel.PublicationDate = rssFeed.Channel.LastBuildDate.Ticks <= 0 ? DateTimeOffset.MinValue : new DateTimeOffset(rssFeed.Channel.LastBuildDate);
|
|
|
|
container.FeedModel.Categories = rssFeed.Channel.Categories.Select(x => x.Value).ToArray();
|
|
|
|
container.FeedModel.ImageUrl = rssFeed.Channel.Image?.Url.ToString() ?? string.Empty;
|
|
|
|
foreach (var rssItem in rssFeed.Channel.Items)
|
|
|
|
{
|
|
|
|
FeedItemModel itemModel = new FeedItemModel()
|
|
|
|
{
|
|
|
|
Id = rssItem.Link.ToString(),
|
|
|
|
FeedUrl = container.FeedModel.OriginalUrl,
|
|
|
|
Type = container.FeedModel.FeedType,
|
|
|
|
Title = rssItem.Title,
|
|
|
|
Description = rssItem.Description,
|
|
|
|
Link = rssItem.Link.ToString(),
|
|
|
|
PublishingDate = rssItem.PublicationDate.Ticks <= 0 ? DateTimeOffset.MinValue : new DateTimeOffset(rssItem.PublicationDate),
|
|
|
|
Authors = new []{ rssItem.Author },
|
|
|
|
Categories = rssItem.Categories.Select(x => x.Value).ToArray(),
|
|
|
|
Content = rssItem.Extensions.Where(x => x is SiteSummaryContentSyndicationExtension).Select(x => (x as SiteSummaryContentSyndicationExtension)?.Context.Encoded).First(),
|
|
|
|
CommentsUrl = rssItem.Extensions.Where(x => x is WellFormedWebCommentsSyndicationExtension).Select(x => (x as WellFormedWebCommentsSyndicationExtension)?.Context.CommentsFeed.ToString()).First()
|
|
|
|
};
|
|
|
|
container.FeedItems.Add(itemModel);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SyndicationContentFormat.Atom:
|
|
|
|
AtomFeed atomFeed = (AtomFeed)container.SyndicationFeed.Resource;
|
|
|
|
container.FeedModel.OriginalUrl = atomFeed.Id.Uri.ToString();
|
|
|
|
container.FeedModel.Title = atomFeed.Title.Content;
|
|
|
|
container.FeedModel.FeedType = atomFeed.Format.ToString();
|
|
|
|
container.FeedModel.FeedVersion = atomFeed.Version?.ToString();
|
|
|
|
container.FeedModel.Description = atomFeed.Subtitle?.Content;
|
|
|
|
container.FeedModel.Language = atomFeed.Language?.ToString();
|
|
|
|
container.FeedModel.Copyright = atomFeed.Rights?.Content;
|
|
|
|
container.FeedModel.PublicationDate = new DateTimeOffset(atomFeed.UpdatedOn);
|
|
|
|
container.FeedModel.Categories = atomFeed.Categories?.Select(x => x.Label).ToArray();
|
|
|
|
container.FeedModel.ImageUrl = atomFeed.Icon?.Uri.ToString() ?? string.Empty;
|
|
|
|
foreach (var entry in atomFeed.Entries)
|
|
|
|
{
|
|
|
|
FeedItemModel itemModel = new FeedItemModel()
|
|
|
|
{
|
|
|
|
Id = entry.Id.Uri.ToString(),
|
|
|
|
FeedUrl = container.FeedModel.OriginalUrl,
|
|
|
|
Type = container.FeedModel.FeedType,
|
|
|
|
Title = entry.Title.Content,
|
|
|
|
Description = entry.Summary.Content,
|
|
|
|
Link = entry.Id.Uri.ToString(),
|
|
|
|
LastUpdated = entry.UpdatedOn.Ticks <= 0 ? DateTimeOffset.MinValue : new DateTimeOffset(entry.UpdatedOn),
|
|
|
|
PublishingDate = entry.PublishedOn.Ticks <= 0 ? DateTimeOffset.MinValue : new DateTimeOffset(entry.PublishedOn),
|
|
|
|
Authors = entry.Authors.Select(auth => auth.Name).ToArray(),
|
|
|
|
Categories = entry.Categories.Select(cat => cat.Label).ToArray(),
|
|
|
|
Content = entry.Content?.Content
|
|
|
|
};
|
|
|
|
container.FeedItems.Add(itemModel);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Log.Warning("Feed implementation missing!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return container;
|
2023-05-29 18:02:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|