Working on syndication manager, handling feed fetching

This commit is contained in:
Max 2023-06-04 02:16:47 +02:00
parent cb13ef54c1
commit 86337f92a2
10 changed files with 206 additions and 74 deletions

View File

@ -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())

View File

@ -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;
}
}

View File

@ -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;
}
}
}
}

View File

@ -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",

View File

@ -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;
}
}
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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();

View File

@ -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();