mirror of
https://github.com/hmaxnl/SharpRSS.git
synced 2025-01-18 12:54:20 +01:00
Working on feed caching & models.
This commit is contained in:
parent
fcda58d30f
commit
87f46e2178
42
SharpRss/FeedCache.cs
Normal file
42
SharpRss/FeedCache.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CodeHollow.FeedReader;
|
||||
using Serilog;
|
||||
using ToolQit.Extensions;
|
||||
|
||||
namespace SharpRss
|
||||
{
|
||||
/// <summary>
|
||||
/// Global memory feed cache.
|
||||
/// </summary>
|
||||
public static class FeedCache
|
||||
{
|
||||
private static readonly Dictionary<string, Feed> CachedFeeds = new Dictionary<string, Feed>();
|
||||
|
||||
public static async Task<Feed> GetFeed(string urlKey)
|
||||
{
|
||||
Log.Verbose("Request for: {UrlKey}", urlKey);
|
||||
if (urlKey.IsNullEmptyWhiteSpace())
|
||||
{
|
||||
Log.Error("RSS Url is empty!");
|
||||
return new Feed();
|
||||
}
|
||||
|
||||
if (CachedFeeds.TryGetValue(urlKey, out Feed? fModel))
|
||||
return fModel;
|
||||
string feedUrl;
|
||||
var urls = await FeedReader.GetFeedUrlsFromUrlAsync(urlKey);
|
||||
if (!urls.Any())
|
||||
feedUrl = urlKey;
|
||||
else
|
||||
feedUrl = urls.First().Url;
|
||||
|
||||
Feed feed = await FeedReader.ReadAsync(feedUrl);
|
||||
if (feed == null)
|
||||
Log.Warning("Could not get feed: {FeedUrl}", feedUrl);
|
||||
CachedFeeds.Add(urlKey, feed);
|
||||
return feed;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SharpRss.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// To store and load data from file/database
|
||||
/// </summary>
|
||||
public class CategoryModel
|
||||
public class CategoryModel : IGuideItem
|
||||
{
|
||||
public CategoryModel(CategoryModel model)
|
||||
{
|
||||
Name = model.Name;
|
||||
Feeds = model.Feeds;
|
||||
}
|
||||
public CategoryModel(string name, HashSet<FeedModel> feeds)
|
||||
{
|
||||
Name = name;
|
||||
Feeds = feeds;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public HashSet<FeedModel> Feeds { get; set; }
|
||||
public bool IsSelected { get; set; }
|
||||
public bool IsExpanded { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,43 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CodeHollow.FeedReader;
|
||||
using Serilog;
|
||||
using ToolQit.Extensions;
|
||||
|
||||
namespace SharpRss.Models
|
||||
{
|
||||
public class FeedModel
|
||||
public class FeedModel : IGuideItem
|
||||
{
|
||||
public string Type { get; set; }
|
||||
public string Text { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string XmlUrl { get; set; }
|
||||
public string HtmlUrl { get; set; }
|
||||
public FeedModel(string rssUrl)
|
||||
{
|
||||
_rssUrl = rssUrl;
|
||||
Task.Run(async () => Base = await FeedCache.GetFeed(_rssUrl));
|
||||
}
|
||||
|
||||
public Feed Base { get; private set; }
|
||||
public bool IsSelected { get; set; }
|
||||
public bool IsExpanded { get; set; }
|
||||
public bool IsReady { get; private set; }
|
||||
private readonly string _rssUrl;
|
||||
/*public async void Load(bool reload = false)
|
||||
{
|
||||
if (Base != null && !reload || !IsReady) return;
|
||||
if (_rssUrl.IsNullEmptyWhiteSpace())
|
||||
{
|
||||
Log.Error("RSS Url is empty!");
|
||||
return;
|
||||
}
|
||||
IsReady = false;
|
||||
string feedUrl;
|
||||
var urls = await FeedReader.GetFeedUrlsFromUrlAsync(_rssUrl);
|
||||
if (!urls.Any())
|
||||
feedUrl = _rssUrl;
|
||||
else
|
||||
feedUrl = urls.First().Url;
|
||||
Log.Verbose("Creating feed: {FeedUrl}", feedUrl);
|
||||
Base = await FeedReader.ReadAsync(feedUrl);
|
||||
IsReady = true;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace WebSharpRSS.Models
|
||||
namespace SharpRss.Models
|
||||
{
|
||||
public interface ISelectableGuideItem
|
||||
public interface IGuideItem
|
||||
{
|
||||
public bool IsSelected { get; set; }
|
||||
public bool IsExpanded { get; set; }
|
|
@ -19,9 +19,27 @@ namespace SharpRss
|
|||
/// - Memory
|
||||
}
|
||||
|
||||
private static HashSet<FeedModel> feedSet = new HashSet<FeedModel>()
|
||||
{
|
||||
new FeedModel("http://fedoramagazine.org/feed/"),
|
||||
new FeedModel("https://www.nasa.gov/rss/dyn/breaking_news.rss")
|
||||
};
|
||||
private static HashSet<FeedModel> feedSet2 = new HashSet<FeedModel>()
|
||||
{
|
||||
new FeedModel("https://journals.plos.org/plosone/feed/atom"),
|
||||
new FeedModel("https://cyberciti.biz/feed"),
|
||||
new FeedModel("https://itsfoss.com/feed")
|
||||
};
|
||||
|
||||
HashSet<CategoryModel> set = new HashSet<CategoryModel>()
|
||||
{
|
||||
new CategoryModel("RSS", feedSet),
|
||||
new CategoryModel("Tech", feedSet2)
|
||||
};
|
||||
|
||||
public async Task<HashSet<CategoryModel>> GetCategories()
|
||||
{
|
||||
return new HashSet<CategoryModel>();
|
||||
return set;
|
||||
}
|
||||
|
||||
public async Task<HashSet<FeedModel>> GetAllFeeds()
|
||||
|
|
|
@ -11,8 +11,15 @@ namespace WebSharpRSS
|
|||
{
|
||||
public static void SetAppDefaultSettings(this DataContainer dataCon)
|
||||
{
|
||||
dataCon.Set("FaviconResolveUrl", "https://icons.duckduckgo.com/ip3/{0}.ico", false);
|
||||
dataCon.Set("LogPath", Path.Combine(Environment.CurrentDirectory, "logs", "log_.json"), false);
|
||||
var paths = dataCon["Paths"];
|
||||
paths.Set("FaviconResolveUrl", "https://icons.duckduckgo.com/ip3/{0}.ico", false);
|
||||
paths.Set("LogPath", Path.Combine(Environment.CurrentDirectory, "logs", "log_.json"), false);
|
||||
|
||||
var dbSql = dataCon["SQL"];
|
||||
dbSql.Set("Host", "localhost", false);
|
||||
dbSql.Set("Port", "6969", false);
|
||||
dbSql.Set("Username", "sharpUser", false);
|
||||
dbSql.Set("Password", "sh@rP@s$", false);
|
||||
}
|
||||
|
||||
private static LoggerConfiguration? _configuration;
|
||||
|
@ -21,8 +28,9 @@ namespace WebSharpRSS
|
|||
if (_configuration != null) return;
|
||||
_configuration = new LoggerConfiguration()
|
||||
.WriteTo.Console()
|
||||
.WriteTo.File(new JsonFormatter(), Caretaker.Settings.GetString("LogPath"), rollingInterval: RollingInterval.Day)
|
||||
.WriteTo.File(new JsonFormatter(), Caretaker.Settings["Paths"].GetString("LogPath"), rollingInterval: RollingInterval.Day)
|
||||
.MinimumLevel.Verbose();
|
||||
|
||||
Log.Logger = _configuration.CreateLogger();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using CodeHollow.FeedReader;
|
||||
|
||||
namespace WebSharpRSS.Models
|
||||
{
|
||||
public class CategoryGuideItem : ISelectableGuideItem
|
||||
{
|
||||
public string CategoryTitle { get; set; }
|
||||
public string CategoryIcon { get; set; }
|
||||
private string _hexColor;
|
||||
|
||||
public string CategoryHexColor
|
||||
{
|
||||
get => _hexColor;
|
||||
set => _hexColor = value.Insert(7, "80");
|
||||
}
|
||||
|
||||
public bool IsExpanded { get; set; }
|
||||
public bool IsSelected { get; set; }
|
||||
public HashSet<FeedGuideItem> FeedItems { get; set; } = new HashSet<FeedGuideItem>() { new FeedGuideItem(FeedReader.ReadAsync("http://fedoramagazine.org/feed/").Result) };
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using SharpRss.Models;
|
||||
|
||||
namespace WebSharpRSS.Models
|
||||
{
|
||||
public class CategoryItem : CategoryModel, ISelectableGuideItem
|
||||
{
|
||||
public CategoryItem(CategoryModel model)
|
||||
{
|
||||
Name = model.Name;
|
||||
Feeds = model.Feeds;
|
||||
}
|
||||
public bool IsSelected { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public bool IsExpanded { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using CodeHollow.FeedReader;
|
||||
|
||||
namespace WebSharpRSS.Models
|
||||
{
|
||||
public class FeedGuideItem : ISelectableGuideItem
|
||||
{
|
||||
public FeedGuideItem(Feed feed)
|
||||
{
|
||||
Feed = feed;
|
||||
}
|
||||
public readonly Feed Feed;
|
||||
public bool IsSelected { get; set; }
|
||||
public bool IsExpanded { get; set; }
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ using WebSharpRSS;
|
|||
|
||||
Caretaker.Settings.SetAppDefaultSettings();
|
||||
Bootstrapper.SetupLogging();
|
||||
Log.Information("Starting app....");
|
||||
Log.Information("Starting application....");
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Services.AddRazorPages();
|
||||
|
@ -18,7 +18,6 @@ builder.Services.AddServerSideBlazor();
|
|||
builder.Services.AddTransient<RssService>();
|
||||
builder.Services.AddMudServices(config =>
|
||||
{
|
||||
Log.Debug("Configuring MudServices");
|
||||
config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomRight;
|
||||
config.SnackbarConfiguration.PreventDuplicates = true;
|
||||
config.SnackbarConfiguration.ShowCloseIcon = true;
|
||||
|
|
12
WebSharpRSS/Settings.json
Normal file
12
WebSharpRSS/Settings.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"Paths": {
|
||||
"FaviconResolveUrl": "https://icons.duckduckgo.com/ip3/{0}.ico",
|
||||
"LogPath": "/home/max/GitHub/SharpRSS/WebSharpRSS/logs/log_.json"
|
||||
},
|
||||
"SQL": {
|
||||
"Host": "localhost",
|
||||
"Port": "6969",
|
||||
"Username": "sharpUser",
|
||||
"Password": "sh@rP@s$"
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
@using WebSharpRSS.Models
|
||||
@using CodeHollow.FeedReader
|
||||
@using SharpRss.Models
|
||||
@using ToolQit
|
||||
@using ToolQit.Containers
|
||||
@using ToolQit.Extensions
|
||||
<style>
|
||||
.cat-item {
|
||||
background: var(--background-color);
|
||||
|
@ -61,28 +64,37 @@
|
|||
|
||||
<div>
|
||||
<MudText>@HeaderText</MudText>
|
||||
@foreach (CategoryGuideItem catItem in Categories)
|
||||
@foreach (CategoryModel guideCategory in Categories)
|
||||
{
|
||||
<div>
|
||||
<div @onclick="@(() => ItemClicked(catItem))" class="cat-item mud-ripple" style="--hover-bg-color: @catItem.CategoryHexColor; --background-color: @(catItem.IsSelected ? catItem.CategoryHexColor : "transparent")">
|
||||
<div @onclick="@(() => ItemClicked(guideCategory))" class="cat-item mud-ripple" style="--hover-bg-color: @Colors.Blue.Accent1; --background-color: @(guideCategory.IsSelected ? Colors.Blue.Accent2 : "transparent")">
|
||||
<div class="cat-item-icon">
|
||||
<MudIcon Class="pointer-events-none" Icon="@catItem.CategoryIcon" Size="Size.Medium"/>
|
||||
<MudIcon Class="pointer-events-none" Icon="@Icons.Material.Filled.RssFeed" Size="Size.Medium"/>
|
||||
</div>
|
||||
<div class="cat-item-text">
|
||||
<MudText Class="pointer-events-none" Typo="Typo.subtitle1">@catItem.CategoryTitle</MudText>
|
||||
<MudText Class="pointer-events-none" Typo="Typo.subtitle1">@guideCategory.Name</MudText>
|
||||
</div>
|
||||
</div>
|
||||
@* Feeds *@
|
||||
@if (catItem.IsExpanded && catItem.FeedItems != null)
|
||||
@if (guideCategory.IsExpanded && guideCategory.Feeds != null)
|
||||
{
|
||||
foreach (FeedGuideItem feedItem in catItem.FeedItems)
|
||||
foreach (FeedModel feed in guideCategory.Feeds)
|
||||
{
|
||||
<div @onclick="() => ItemClicked(feedItem)" class="feed-item mud-ripple" style="--hover-bg-color: @catItem.CategoryHexColor; --background-color: @(feedItem.IsSelected ? catItem.CategoryHexColor : "transparent")">
|
||||
if (feed == null || feed.Base == null) continue;
|
||||
<div @onclick="() => ItemClicked(feed)" class="feed-item mud-ripple" style="--hover-bg-color: @Colors.Blue.Accent1; --background-color: @(feed.IsSelected ? Colors.Blue.Accent2 : "transparent")">
|
||||
<div class="feed-item-icon">
|
||||
<MudImage ObjectFit="ObjectFit.Contain" Src="http://www.google.com/s2/favicons?domain=wikipedia.com"/>
|
||||
@*@if (!guideFeed.FaviconUrl.IsNullEmptyWhiteSpace())
|
||||
{
|
||||
<MudImage ObjectFit="ObjectFit.ScaleDown" Src="@guideFeed.FaviconUrl"/>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudIcon Icon="@Icons.Material.Filled.RssFeed" Size="Size.Medium"/>
|
||||
}*@
|
||||
<MudIcon Icon="@Icons.Material.Filled.RssFeed" Size="Size.Medium"/>
|
||||
</div>
|
||||
<div class="feed-item-text">
|
||||
<MudText Class="pointer-events-none">@feedItem.Feed.Title</MudText>
|
||||
<MudText Class="pointer-events-none">@feed.Base.Title</MudText>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
@ -95,31 +107,31 @@
|
|||
[Parameter]
|
||||
public string HeaderText { get; set; }
|
||||
[Parameter]
|
||||
public HashSet<CategoryGuideItem> Categories { get; set; } = new HashSet<CategoryGuideItem>();
|
||||
public HashSet<CategoryModel> Categories { get; set; } = new HashSet<CategoryModel>();
|
||||
[Parameter]
|
||||
public Action<CategoryGuideItem>? CatItemClicked { get; set; }
|
||||
public Action<CategoryModel>? CatItemClicked { get; set; }
|
||||
[Parameter]
|
||||
public Action<FeedGuideItem>? FeedItemClicked { get; set; }
|
||||
public Action<FeedModel>? FeedItemClicked { get; set; }
|
||||
|
||||
IGuideItem? _selectedItem;
|
||||
|
||||
ISelectableGuideItem? _selectedCategory;
|
||||
|
||||
void ItemClicked(ISelectableGuideItem categoryItem)
|
||||
void ItemClicked(IGuideItem categoryItem)
|
||||
{
|
||||
categoryItem.IsExpanded = !categoryItem.IsExpanded;
|
||||
|
||||
if (_selectedCategory != categoryItem)
|
||||
if (_selectedItem != categoryItem)
|
||||
{
|
||||
if (_selectedCategory != null)
|
||||
_selectedCategory.IsSelected = false;
|
||||
_selectedCategory = categoryItem;
|
||||
_selectedCategory.IsSelected = true;
|
||||
if (_selectedItem != null)
|
||||
_selectedItem.IsSelected = false;
|
||||
_selectedItem = categoryItem;
|
||||
_selectedItem.IsSelected = true;
|
||||
}
|
||||
switch (categoryItem)
|
||||
{
|
||||
case CategoryGuideItem catGuideItem:
|
||||
case CategoryModel catGuideItem:
|
||||
CatItemClicked?.Invoke(catGuideItem);
|
||||
break;
|
||||
case FeedGuideItem feedGuideItem:
|
||||
case FeedModel feedGuideItem:
|
||||
FeedItemClicked?.Invoke(feedGuideItem);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
@using SharpRss.Models;
|
||||
@using WebSharpRSS.Models
|
||||
@using MudBlazor.Utilities
|
||||
@using CodeHollow.FeedReader
|
||||
@using Serilog
|
||||
|
@ -14,33 +13,34 @@
|
|||
</MudStack>
|
||||
|
||||
@code {
|
||||
public HashSet<CategoryGuideItem> Categories = new HashSet<CategoryGuideItem>();
|
||||
public HashSet<CategoryItem> Cats = new HashSet<CategoryItem>();
|
||||
public HashSet<CategoryModel> Categories = new HashSet<CategoryModel>();
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Log.Verbose("Setting up test data");
|
||||
Categories.Add(new CategoryGuideItem() { CategoryTitle = "Social", CategoryIcon = Icons.Material.Filled.People });
|
||||
Categories = _rssService.GetCategories().Result;
|
||||
/*Cats = _rssService.GetCategories().Result.Select(x => new GuideModel(x)).ToHashSet();*/
|
||||
/*Categories.Add(new CategoryGuideItem() { CategoryTitle = "Social", CategoryIcon = Icons.Material.Filled.People });
|
||||
Categories.Add(new CategoryGuideItem() { CategoryTitle = "Blogs", CategoryIcon = Icons.Material.Filled.RssFeed, CategoryHexColor = Colors.Green.Accent1 });
|
||||
Categories.Add(new CategoryGuideItem() { CategoryTitle = "Tech", CategoryIcon = Icons.Material.Filled.Computer, CategoryHexColor = Colors.Brown.Lighten1 });
|
||||
Categories.Add(new CategoryGuideItem() { CategoryTitle = "News", CategoryIcon = Icons.Material.Filled.Newspaper, CategoryHexColor = Colors.Red.Accent1 });
|
||||
Categories.Add(new CategoryGuideItem() { CategoryTitle = "News", CategoryIcon = Icons.Material.Filled.Newspaper, CategoryHexColor = Colors.Red.Accent1 });*/
|
||||
}
|
||||
|
||||
private void Callback(MudListItem obj)
|
||||
{
|
||||
switch (obj.Value)
|
||||
{
|
||||
case CategoryGuideItem catTreeItem:
|
||||
case CategoryModel catModel:
|
||||
break;
|
||||
case Feed feed:
|
||||
case FeedModel feedModel:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void CategoryClicked(CategoryGuideItem catItem)
|
||||
private void CategoryClicked(CategoryModel cat)
|
||||
{
|
||||
}
|
||||
|
||||
private void FeedClicked(FeedGuideItem feedItem)
|
||||
private void FeedClicked(FeedModel guideFeedItem)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -15,4 +15,9 @@
|
|||
<ProjectReference Include="..\SharpRss\SharpRss.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Core" />
|
||||
<Folder Include="Models" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
Loading…
Reference in New Issue
Block a user