mirror of
https://github.com/hmaxnl/SharpRSS.git
synced 2025-01-18 21:04:21 +01:00
Working on syndication manager, handling feed fetching
This commit is contained in:
parent
cb13ef54c1
commit
86337f92a2
|
@ -4,8 +4,6 @@ using System.Data;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
using Argotic.Syndication;
|
||||
using Dapper;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Serilog;
|
||||
|
@ -13,7 +11,7 @@ using SharpRss.Models;
|
|||
|
||||
namespace SharpRss
|
||||
{
|
||||
public static class DbAccess
|
||||
public static class DbAccess_Old
|
||||
{
|
||||
//TODO: Rename group => category.
|
||||
//TODO: Reworking feed => model/db implementation.
|
||||
|
@ -149,17 +147,16 @@ namespace SharpRss
|
|||
{
|
||||
Parameters =
|
||||
{
|
||||
new SqliteParameter("url", feedModel.Url ?? string.Empty),
|
||||
new SqliteParameter("url", feedModel.OriginalUrl ?? string.Empty),
|
||||
new SqliteParameter("title", feedModel.Title ?? string.Empty),
|
||||
new SqliteParameter("groupId", feedModel.GroupId ?? string.Empty),
|
||||
new SqliteParameter("feedType", feedModel.FeedType ?? string.Empty),
|
||||
new SqliteParameter("description", feedModel.Description ?? string.Empty),
|
||||
new SqliteParameter("language", feedModel.Language ?? string.Empty),
|
||||
new SqliteParameter("copyright", feedModel.Copyright ?? string.Empty),
|
||||
new SqliteParameter("dateAdded", feedModel.DateAdded?.ToUnixTimeMilliseconds() ?? 0),
|
||||
new SqliteParameter("dateAdded", feedModel.PublicationDate?.ToUnixTimeMilliseconds() ?? 0),
|
||||
new SqliteParameter("lastUpdated", feedModel.LastUpdated?.ToUnixTimeMilliseconds() ?? 0),
|
||||
new SqliteParameter("imageUrl", feedModel.ImageUrl ?? string.Empty),
|
||||
new SqliteParameter("originalDoc", feedModel.OriginalDocument ?? string.Empty)
|
||||
new SqliteParameter("imageUrl", feedModel.ImageUrl ?? string.Empty)
|
||||
}
|
||||
};
|
||||
try
|
||||
|
@ -230,8 +227,8 @@ namespace SharpRss
|
|||
HashSet<FeedItemModel> feedItems = new HashSet<FeedItemModel>();
|
||||
foreach (var dbFeed in dbFeeds)
|
||||
{
|
||||
GenericSyndicationFeed syndication = new GenericSyndicationFeed();
|
||||
syndication.Load(dbFeed.OriginalDocument);
|
||||
/*GenericSyndicationFeed syndication = new GenericSyndicationFeed();
|
||||
syndication.Load(dbFeed.OriginalDocument);*/
|
||||
//TODO: Get items and add to db
|
||||
}
|
||||
}
|
||||
|
@ -245,7 +242,7 @@ namespace SharpRss
|
|||
{
|
||||
Parameters =
|
||||
{
|
||||
new SqliteParameter("Url", feedModel.Url)
|
||||
new SqliteParameter("Url", feedModel.OriginalUrl)
|
||||
}
|
||||
};
|
||||
int affected = await cmd.ExecuteNonQueryAsync();
|
||||
|
@ -280,14 +277,14 @@ namespace SharpRss
|
|||
DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(reader["last_updated"].ToString())),
|
||||
PublishingDate =
|
||||
DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(reader["publishing_date"].ToString())),
|
||||
Author = reader["author"].ToString(),
|
||||
Authors = reader["authors"].ToString().ToString().Split(','),
|
||||
Categories = reader["categories"].ToString().Split(','),
|
||||
Content = reader["content"].ToString()
|
||||
};
|
||||
if (feedItemModel is { FeedId: { } })
|
||||
{
|
||||
FeedModel? feedModel = await GetFeedAsync(feedItemModel.FeedUrl);
|
||||
feedItemModel.Feed = feedModel;
|
||||
//feedItemModel.Feed = feedModel;
|
||||
}
|
||||
feedItems.Add(feedItemModel);
|
||||
}
|
||||
|
@ -300,8 +297,8 @@ namespace SharpRss
|
|||
await using SqliteConnection dbc = new SqliteConnection(ConnectionString);
|
||||
dbc.Open();
|
||||
await using SqliteTransaction transaction = dbc.BeginTransaction();
|
||||
await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {FeedItemTable} (id, feed_id, read, title, description, link, last_updated, publishing_date, author, categories, content)" +
|
||||
$"VALUES (IFNULL((SELECT id FROM {FeedItemTable} WHERE link=@link), @id), @feedId, @read, @title, @description, @link, @lastUpdated, @publishingDate, @author, @categories, @content)", dbc)
|
||||
await using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {FeedItemTable} (id, feed_url, read, title, description, link, last_updated, publishing_date, authors, categories, content)" +
|
||||
$"VALUES (IFNULL((SELECT id FROM {FeedItemTable} WHERE link=@link), @id), @feedUrl, @read, @title, @description, @link, @lastUpdated, @publishingDate, @authors, @categories, @content)", dbc)
|
||||
{
|
||||
Transaction = transaction
|
||||
};
|
||||
|
@ -309,7 +306,7 @@ namespace SharpRss
|
|||
{
|
||||
cmd.Parameters.Clear();
|
||||
cmd.Parameters.Add(new SqliteParameter("id", item.Id ?? string.Empty));
|
||||
cmd.Parameters.Add(new SqliteParameter("feedId", item.FeedId ?? string.Empty));
|
||||
cmd.Parameters.Add(new SqliteParameter("feedUrl", item.FeedUrl ?? string.Empty));
|
||||
cmd.Parameters.Add(new SqliteParameter("read", item.Read ? 1 : 0));
|
||||
cmd.Parameters.Add(new SqliteParameter("type", item.Type ?? string.Empty));
|
||||
cmd.Parameters.Add(new SqliteParameter("title", item.Title ?? string.Empty));
|
||||
|
@ -317,7 +314,7 @@ namespace SharpRss
|
|||
cmd.Parameters.Add(new SqliteParameter("link", item.Link ?? string.Empty));
|
||||
cmd.Parameters.Add(new SqliteParameter("lastUpdated", item.LastUpdated?.ToUnixTimeMilliseconds()));
|
||||
cmd.Parameters.Add(new SqliteParameter("publishingDate", item.PublishingDate?.ToUnixTimeMilliseconds() ?? 0));
|
||||
cmd.Parameters.Add(new SqliteParameter("author", item.Author ?? string.Empty));
|
||||
cmd.Parameters.Add(new SqliteParameter("authors", item.Authors != null ? string.Join(',', item.Authors) : string.Empty));
|
||||
cmd.Parameters.Add(new SqliteParameter("categories", item.Categories != null ? string.Join(',', item.Categories) : string.Empty));
|
||||
cmd.Parameters.Add(new SqliteParameter("content", item.Content ?? string.Empty));
|
||||
if (dbc.State != ConnectionState.Open)
|
||||
|
@ -372,17 +369,16 @@ namespace SharpRss
|
|||
{
|
||||
FeedModel fetchedFeed = new FeedModel()
|
||||
{
|
||||
Url = reader["url"].ToString(),
|
||||
OriginalUrl = reader["url"].ToString(),
|
||||
Title = reader["title"].ToString(),
|
||||
GroupId = reader["group_id"].ToString(),
|
||||
FeedType = reader["feed_type"].ToString(),
|
||||
Description = reader["description"].ToString(),
|
||||
Language = reader["language"].ToString(),
|
||||
Copyright = reader["copyright"].ToString(),
|
||||
DateAdded = DateTimeOffset.FromUnixTimeMilliseconds(long.TryParse(reader["date_added"].ToString(), out long parsedVal) ? parsedVal : 0),
|
||||
PublicationDate = DateTimeOffset.FromUnixTimeMilliseconds(long.TryParse(reader["date_added"].ToString(), out long parsedVal) ? parsedVal : 0),
|
||||
LastUpdated = DateTimeOffset.FromUnixTimeMilliseconds(long.TryParse(reader["last_updated"].ToString(), out long lastUpdated) ? lastUpdated : 0),
|
||||
ImageUrl = reader["image_url"].ToString(),
|
||||
OriginalDocument = reader["original_document"].ToString()
|
||||
ImageUrl = reader["image_url"].ToString()
|
||||
};
|
||||
//TODO: Set group on insert
|
||||
/*var groupFetch = await GetGroupsAsync(fetchedFeed.GroupId);
|
||||
|
@ -410,7 +406,7 @@ namespace SharpRss
|
|||
if (queryResponse.Any()) failed.Add("feed");
|
||||
|
||||
Log.Verbose("Checking table: {Table}", "feed_item");
|
||||
queryResponse = await dbc.QueryAsync($"CREATE TABLE IF NOT EXISTS feed_item (id STRING PRIMARY KEY, feed_id STRING, read INT, title STRING, description STRING, link STRING, last_updated INT, publishing_date INT, author STRING, categories STRING, content STRING)");
|
||||
queryResponse = await dbc.QueryAsync($"CREATE TABLE IF NOT EXISTS feed_item (id STRING PRIMARY KEY, feed_url STRING, read INT, title STRING, description STRING, link STRING, last_updated INT, publishing_date INT, authors STRING, categories STRING, content STRING)");
|
||||
if (queryResponse.Any()) failed.Add("feed_item");
|
||||
|
||||
if (failed.Any())
|
|
@ -4,7 +4,6 @@ namespace SharpRss.Models
|
|||
{
|
||||
public class FeedItemModel
|
||||
{
|
||||
public FeedModel? Feed { get; set; }
|
||||
public string? Id { get; set; } = string.Empty;
|
||||
// FeedId will be removed
|
||||
public string? FeedId { get; set; } = string.Empty;
|
||||
|
@ -16,9 +15,10 @@ namespace SharpRss.Models
|
|||
public string? Link { get; set; } = string.Empty;
|
||||
public DateTimeOffset? LastUpdated { get; set; }
|
||||
public DateTimeOffset? PublishingDate { get; set; }
|
||||
public string? Author { get; set; } = string.Empty;
|
||||
public string[]? Authors { get; set; }
|
||||
public string[]? Categories { get; set; }
|
||||
public string? Content { get; set; } = string.Empty;
|
||||
public string? HexColor => Feed?.Group?.HexColor;
|
||||
public string? CommentsUrl { get; set; } = string.Empty;
|
||||
public string? HexColor { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,37 @@
|
|||
using System;
|
||||
using ToolQit;
|
||||
using ToolQit.Extensions;
|
||||
|
||||
namespace SharpRss.Models
|
||||
{
|
||||
public class FeedModel
|
||||
{
|
||||
public FeedModel()
|
||||
{
|
||||
}
|
||||
public CategoryModel? Group { get; set; }
|
||||
public string Url { get; set; }
|
||||
public CategoryModel? Category { get; set; }
|
||||
public string OriginalUrl { get; set; } = string.Empty;
|
||||
public string? Title { get; set; } = string.Empty;
|
||||
public string? GroupId { get; set; } = string.Empty;
|
||||
public string? FeedType { get; set; } = string.Empty;
|
||||
public string? FeedVersion { get; set; } = string.Empty;
|
||||
public string? Description { get; set; } = string.Empty;
|
||||
public string? Language { get; set; } = string.Empty;
|
||||
public string? Copyright { get; set; } = string.Empty;
|
||||
public DateTimeOffset? DateAdded { get; set; }
|
||||
public DateTimeOffset? LastUpdated { get; set; }
|
||||
public string? ImageUrl { get; set; } = string.Empty;
|
||||
public string? OriginalDocument { get; set; } = string.Empty;
|
||||
public DateTimeOffset? PublicationDate { get; set; }
|
||||
public DateTimeOffset? LastUpdated { get; set; } = DateTimeOffset.Now;
|
||||
public string[]? Categories { get; set; }
|
||||
private string _imageUrl = string.Empty;
|
||||
public string ImageUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_imageUrl.IsNullEmptyWhiteSpace())
|
||||
_imageUrl = string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), new Uri(OriginalUrl).Host);
|
||||
return _imageUrl;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!value.IsNullEmptyWhiteSpace())
|
||||
_imageUrl = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Argotic.Common;
|
||||
using Argotic.Syndication;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Serilog;
|
||||
using SharpRss.Models;
|
||||
|
||||
|
@ -21,33 +18,33 @@ namespace SharpRss.Services
|
|||
SetupTestGroupsAndFeedsAsync();
|
||||
}
|
||||
|
||||
public async Task<HashSet<object>> GetGroupsFeedsAsync()
|
||||
public async Task<HashSet<object>> GetCategoriesFeedsAsync()
|
||||
{
|
||||
HashSet<object> items = new HashSet<object>();
|
||||
items.UnionWith(await GetCategoriesAsync());
|
||||
items.UnionWith(await GetUngroupedFeedsAsync());
|
||||
return items;
|
||||
}
|
||||
public async Task<bool> CreateGroupAsync(CategoryModel group) => await DbAccess.SetCategoryAsync(group);
|
||||
public async Task<HashSet<CategoryModel>> GetCategoriesAsync() => await DbAccess.GetCategoriesAsync();
|
||||
public async Task<bool> CreateGroupAsync(CategoryModel group) => await DbAccess_Old.SetCategoryAsync(group);
|
||||
public async Task<HashSet<CategoryModel>> GetCategoriesAsync() => await DbAccess_Old.GetCategoriesAsync();
|
||||
|
||||
//TODO: Rework this!
|
||||
// Subscribe to a feed.
|
||||
public async Task<bool> AddSubscriptionAsync(string url, CategoryModel? group = null)
|
||||
{
|
||||
// Check for valid feed url
|
||||
bool validate = SyndicationDiscoveryUtility.UriExists(new Uri(url));
|
||||
if (!validate) return false;
|
||||
/*if (!SyndicationManager.GetFeed(url, out GenericSyndicationFeed? genFeed)) return false;*/
|
||||
var feed = SyndicationManager.CreateSyndication(url);
|
||||
// Check if feed exists in db
|
||||
FeedModel? fModel = await DbAccess.GetFeedAsync(url);
|
||||
FeedModel? fModel = await DbAccess_Old.GetFeedAsync(url);
|
||||
// If not exists fetch feed & add.
|
||||
if (fModel == null)
|
||||
{
|
||||
GenericSyndicationFeed genFeed = GenericSyndicationFeed.Create(new Uri(url));
|
||||
/*if (!SyndicationManager.TryGetGenericFeed(url, out GenericSyndicationFeed? genFeed)) return false;*/
|
||||
/*if (genFeed == null) return false;
|
||||
fModel = FromResource(genFeed.Resource);
|
||||
fModel.GroupId = group?.Id;
|
||||
fModel.GroupId = group?.Id;*/
|
||||
// Add feed
|
||||
FeedModel? dbFeed = await DbAccess.SetFeedAsync(fModel);
|
||||
//FeedModel? dbFeed = await DbAccess.SetFeedAsync(fModel);
|
||||
// Update/fetch items
|
||||
//await DbAccess.FetchFeedItemsAsync(new string[] { fModel.Url });
|
||||
}
|
||||
|
@ -64,7 +61,7 @@ namespace SharpRss.Services
|
|||
model.Title = rssFeed.Channel.Title;
|
||||
model.Description = rssFeed.Channel.Description;
|
||||
model.Copyright = rssFeed.Channel.Copyright;
|
||||
model.Url = rssFeed.Channel.SelfLink.ToString();
|
||||
model.OriginalUrl = rssFeed.Channel.SelfLink.ToString();
|
||||
model.ImageUrl = rssFeed.Channel.Image?.Url.ToString();
|
||||
model.Language = rssFeed.Channel.Language?.ToString();
|
||||
break;
|
||||
|
@ -84,13 +81,13 @@ namespace SharpRss.Services
|
|||
var feeds = await GetFeedsAsync();
|
||||
}
|
||||
|
||||
public async Task<HashSet<FeedModel>> GetFeedsAsync(string? groupId = null) => await DbAccess.GetFeedsAsync(groupId);
|
||||
public async Task<HashSet<FeedModel>> GetUngroupedFeedsAsync() => await DbAccess.GetFeedsAsync("");
|
||||
public async Task<HashSet<FeedModel>> GetFeedsAsync(string? groupId = null) => await DbAccess_Old.GetFeedsAsync(groupId);
|
||||
public async Task<HashSet<FeedModel>> GetUngroupedFeedsAsync() => await DbAccess_Old.GetFeedsAsync("");
|
||||
|
||||
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);
|
||||
var items = await DbAccess_Old.GetFeedItemsAsync(feedIds);
|
||||
return items;
|
||||
}
|
||||
|
||||
|
@ -143,6 +140,7 @@ namespace SharpRss.Services
|
|||
}
|
||||
private async void SetupTestGroupsAndFeedsAsync()
|
||||
{
|
||||
await AddSubscriptionAsync("https://en.wikipedia.org/w/api.php?hidebots=1&hidecategorization=1&hideWikibase=1&urlversion=1&days=7&limit=50&action=feedrecentchanges&feedformat=atom");
|
||||
//TODO: Make multiple adding of feed to a transaction, now throws an exception.
|
||||
/*var groupRes = await CreateGroupAsync(new GroupModel() { Name = "Test" });
|
||||
groupRes = await CreateGroupAsync(new GroupModel() { Name = "News" });
|
||||
|
@ -165,8 +163,8 @@ namespace SharpRss.Services
|
|||
throw;
|
||||
}*/
|
||||
/*var groups = await GetGroupsAsync();
|
||||
CategoryModel testGroup = groups.Single(x => x.Name == "News");
|
||||
await AddSubscriptionAsync("https://www.nu.nl/rss/Algemeen", testGroup);*/
|
||||
CategoryModel testGroup = groups.Single(x => x.Name == "News");*/
|
||||
|
||||
/*await AddFeedsAsync(new[]
|
||||
{
|
||||
"https://www.nu.nl/rss/Algemeen",
|
||||
|
|
|
@ -1,16 +1,133 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Argotic.Common;
|
||||
using Argotic.Extensions.Core;
|
||||
using Argotic.Syndication;
|
||||
using Serilog;
|
||||
using SharpRss.Models;
|
||||
|
||||
namespace SharpRss
|
||||
{
|
||||
/// <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; }
|
||||
}
|
||||
public static class SyndicationManager
|
||||
{
|
||||
public static bool TryGetFeed(string feedUrl, out GenericSyndicationFeed? feed)
|
||||
public static SyndicationContainer CreateSyndication(string feedUrl)
|
||||
{
|
||||
feed = null;
|
||||
GenericSyndicationFeed? syndicationFeed = null;
|
||||
Uri feedUri = new Uri(feedUrl);
|
||||
feed = GenericSyndicationFeed.Create(feedUri);
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,32 +2,45 @@ using System;
|
|||
using System.IO;
|
||||
using Serilog;
|
||||
using Serilog.Formatting.Json;
|
||||
using Serilog.Sinks.SystemConsole.Themes;
|
||||
using SharpRss.Models;
|
||||
using SharpRss;
|
||||
using ToolQit;
|
||||
using ToolQit.Containers;
|
||||
using WebSharpRSS.Models;
|
||||
|
||||
namespace WebSharpRSS
|
||||
{
|
||||
public static class Bootstrapper
|
||||
{
|
||||
public static void SetAppDefaultSettings(this DataContainer dataCon)
|
||||
private static bool _defaultsSet;
|
||||
private static bool _bootstrapped;
|
||||
|
||||
public static void Bootstrap()
|
||||
{
|
||||
if (_bootstrapped) return;
|
||||
Caretaker.Settings.SetAppDefaultSettings();
|
||||
SetupLogging();
|
||||
Log.Information("Starting SharpRSS...");
|
||||
DbAccess_Old.Initialize();
|
||||
_bootstrapped = true;
|
||||
}
|
||||
|
||||
private static void SetAppDefaultSettings(this DataContainer dataCon)
|
||||
{
|
||||
var paths = dataCon["Paths"];
|
||||
//paths.Set("FaviconResolveUrl", "https://icons.duckduckgo.com/ip3/{0}.ico", false);
|
||||
paths.Set("FaviconResolveUrl", "http://www.google.com/s2/favicons?domain={0}", false);
|
||||
paths.Set("LogPath", Path.Combine(Environment.CurrentDirectory, "logs", "log_.json"), false);
|
||||
_defaultsSet = true;
|
||||
}
|
||||
|
||||
private static LoggerConfiguration? _configuration;
|
||||
public static void SetupLogging()
|
||||
private static void SetupLogging()
|
||||
{
|
||||
if (!_defaultsSet) throw new Exception("Bootstrapper defaults are not initialized!");
|
||||
if (_configuration != null) return;
|
||||
_configuration = new LoggerConfiguration()
|
||||
.WriteTo.Console()
|
||||
.WriteTo.File(new JsonFormatter(), Caretaker.Settings["Paths"].GetString("LogPath"), rollingInterval: RollingInterval.Day)
|
||||
.MinimumLevel.Verbose();
|
||||
.MinimumLevel.Verbose(); // ONLY FOR DEBUGGING!!!
|
||||
|
||||
Log.Logger = _configuration.CreateLogger();
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ namespace WebSharpRSS.Models
|
|||
{
|
||||
FeedModel = feedModel;
|
||||
Title = feedModel.Title ?? string.Empty;
|
||||
if (FeedModel.Url == null) return;
|
||||
FaviconUrl = string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), new Uri(FeedModel.Url).Host);
|
||||
if (FeedModel.OriginalUrl == null) return;
|
||||
FaviconUrl = string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), new Uri(FeedModel.OriginalUrl).Host);
|
||||
}
|
||||
public readonly CategoryModel? GroupModel;
|
||||
public readonly FeedModel? FeedModel;
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
else if (Gid != null)
|
||||
{
|
||||
var feeds = await _rssService.GetFeedsAsync(Gid);
|
||||
var feedIds = feeds.Select(x => x.Url);
|
||||
var feedIds = feeds.Select(x => x.OriginalUrl);
|
||||
var feedItems = await _rssService.GetFeedItemsFromFeedsAsync(feedIds.ToArray());
|
||||
items = feedItems.Select(x => FeedItemData.FromModel(x)).OrderBy(x => x.PublishingDate).Reverse().ToHashSet();
|
||||
}
|
||||
|
|
|
@ -3,17 +3,11 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
using Microsoft.Extensions.Hosting;
|
||||
using MudBlazor;
|
||||
using MudBlazor.Services;
|
||||
using Serilog;
|
||||
using SharpRss;
|
||||
using SharpRss.Services;
|
||||
using ToolQit;
|
||||
using WebSharpRSS;
|
||||
using WebSharpRSS.Models;
|
||||
|
||||
Caretaker.Settings.SetAppDefaultSettings();
|
||||
Bootstrapper.SetupLogging();
|
||||
Log.Information("Starting...");
|
||||
DbAccess.Initialize();
|
||||
Bootstrapper.Bootstrap();
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Services.AddRazorPages();
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
if (_selectedItem == null) return;
|
||||
if (_selectedItem.FeedModel != null)
|
||||
{
|
||||
_navigation.NavigateTo($"/list?fid={_selectedItem.FeedModel.Url}");
|
||||
_navigation.NavigateTo($"/list?fid={_selectedItem.FeedModel.OriginalUrl}");
|
||||
}
|
||||
else if (_selectedItem.GroupModel != null)
|
||||
{
|
||||
|
@ -70,7 +70,7 @@
|
|||
protected override async void OnInitialized()
|
||||
{
|
||||
Log.Verbose("Loading guide data...");
|
||||
HashSet<object> items = await _rssService.GetGroupsFeedsAsync();
|
||||
HashSet<object> items = await _rssService.GetCategoriesFeedsAsync();
|
||||
_guideItems.UnionWith(ModelToTreeItem(items));
|
||||
|
||||
StateHasChanged();
|
||||
|
|
Loading…
Reference in New Issue
Block a user