Implenting rssservice

This commit is contained in:
Max Holleman 2023-05-22 15:55:21 +02:00
parent f83b4451a7
commit 29f9abd5de
8 changed files with 119 additions and 92 deletions

View File

@ -4,12 +4,7 @@ namespace SharpRss.Models
{
public class FeedItemModel
{
public FeedItemModel()
{
Id = Guid.NewGuid().ToString();
LastUpdated = DateTime.Now;
}
public string Id { get; set; }
public string Id { get; set; } = string.Empty;
public string? FeedId { get; set; }
public bool Read { get; set; }
public string Type { get; set; } = string.Empty;

View File

@ -4,20 +4,23 @@ namespace SharpRss.Models
{
public class FeedModel
{
public FeedModel() { }
public FeedModel(string rssUrl)
{
Id = Guid.NewGuid().ToString();
Url = rssUrl;
Id = Guid.NewGuid().ToString();
Copyright = "EMPTY";
ImageUrl = "EMPTY";
}
public string Id { get; set; }
public string Url { get; set; }
public string Id { get; set; } = string.Empty;
public string Url { get; set; } = string.Empty;
public string? GroupId { get; set; }
public string FeedType { 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 string Copyright { get; set; } = "EMPTY";
public DateTimeOffset DateAdded { get; set; }
public DateTimeOffset LastUpdated { get; set; }
public string ImageUrl { get; set; } = string.Empty;
public string ImageUrl { get; set; } = "EMPTY";
}
}

View File

@ -23,8 +23,8 @@ namespace SharpRss.Services
private readonly string _feedTable = "feed_data";
private readonly string _feedItemTable = "feed_item_data";
// Group
public async Task<HashSet<GroupModel?>> GetGroupsAsync(string? groupName = null)
// Groups
public async Task<HashSet<GroupModel>> GetGroupsAsync(string? groupName = null)
{
_sqlConn.Open();
using SqliteCommand cmd = new SqliteCommand(groupName != null ? $"SELECT * FROM {_groupTable} WHERE name=@name;" : $"SELECT * FROM {_groupTable}", _sqlConn)
@ -35,7 +35,7 @@ namespace SharpRss.Services
}
};
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
HashSet<GroupModel?> groups = new HashSet<GroupModel?>();
HashSet<GroupModel> groups = new HashSet<GroupModel>();
while (reader.Read())
{
groups.Add(new GroupModel()
@ -51,7 +51,7 @@ namespace SharpRss.Services
}
/// <summary>
/// Creates a group if not exists else will update the group.
/// Creates a group if not exists then update the group.
/// </summary>
/// <param name="groupModel"></param>
/// <returns></returns>
@ -94,20 +94,35 @@ namespace SharpRss.Services
_sqlConn.Close();
return result;
}
// Feed
public async Task<HashSet<FeedModel>> GetFeedsAsync(string? feedName = null)
// Feeds
public async Task<HashSet<FeedModel>> GetFeedsAsync(GroupModel? group = null)
{
HashSet<FeedModel> feeds = new HashSet<FeedModel>();
_sqlConn.Open();
using SqliteCommand cmd = new SqliteCommand(feedName != null ? $"SELECT * FROM {_feedTable} WHERE name=@name" : $"SELECT * FROM {_feedTable}", _sqlConn)
using SqliteCommand cmd = new SqliteCommand(group != null ? $"SELECT * FROM {_feedTable} WHERE group_id=@groupid" : $"SELECT * FROM {_feedTable}", _sqlConn)
{
Parameters =
{
new SqliteParameter("name", feedName)
new SqliteParameter("groupId", group?.Id == string.Empty ? null : group?.Id)
}
};
int affected = await cmd.ExecuteNonQueryAsync();
Log.Verbose("{FeedAmount} feeds found!", affected);
await using SqliteDataReader reader = await cmd.ExecuteReaderAsync();
while (reader.Read())
{
feeds.Add(new FeedModel()
{
Id = reader["id"].ToString(),
Url = reader["url"].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),
LastUpdated = DateTimeOffset.FromUnixTimeMilliseconds(long.TryParse(reader["last_updated"].ToString(), out long lastUpdated) ? lastUpdated : 0),
ImageUrl = reader["image_url"].ToString()
});
}
_sqlConn.Close();
return feeds;
}
@ -116,8 +131,7 @@ namespace SharpRss.Services
{
bool result = false;
_sqlConn.Open();
using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {_feedTable} (id, url, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url)" +
$"VALUES (IFNULL((SELECT id FROM {_feedTable} WHERE url=@url), @id), @url, @groupId, @feedType, @description, @language, @copyright, @dateAdded, @lastUpdated, @imageUrl)", _sqlConn)
using SqliteCommand cmd = new SqliteCommand($"INSERT OR REPLACE INTO {_feedTable} (id, url, group_id, feed_type, description, language, copyright, date_added, last_updated, image_url) VALUES (IFNULL((SELECT id FROM {_feedTable} WHERE url=@url), @id), @url, @groupId, @feedType, @description, @language, @copyright, @dateAdded, @lastUpdated, @imageUrl)", _sqlConn)
{
Parameters =
{
@ -127,10 +141,10 @@ namespace SharpRss.Services
new SqliteParameter("feedType", feedModel.FeedType),
new SqliteParameter("description", feedModel.Description),
new SqliteParameter("language", feedModel.Language),
new SqliteParameter("copyright", feedModel.Copyright),
new SqliteParameter("copyright", "EMPTY"),
new SqliteParameter("dateAdded", feedModel.DateAdded.ToUnixTimeMilliseconds()),
new SqliteParameter("lastUpdated", feedModel.LastUpdated.ToUnixTimeMilliseconds()),
new SqliteParameter("imageUrl", feedModel.ImageUrl)
new SqliteParameter("imageUrl", "EMPTY")
}
};
int affected = await cmd.ExecuteNonQueryAsync();
@ -156,7 +170,7 @@ namespace SharpRss.Services
_sqlConn.Close();
return result;
}
// Feed item
// Feed items
public async Task<HashSet<FeedItemModel>> GetFeedItemsAsync()
{
HashSet<FeedItemModel> feeditems = new HashSet<FeedItemModel> ();

View File

@ -3,24 +3,95 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using CodeHollow.FeedReader;
using Serilog;
using SharpRss.Models;
using ToolQit.Extensions;
namespace SharpRss.Services
{
/// <summary>
/// Managing RSS feeds and categories.
/// Managing RSS feeds and groups.
/// </summary>
public class RssService : IDisposable
{
public RssService()
{
SetupTestCategoriesAndFeedsAsync();
SetupTestCategoriesAndFeedsAsync();
}
private readonly DatabaseService _dbService = new DatabaseService();
public async Task<bool> CreateGroupAsync(GroupModel group) => await _dbService.SetGroupAsync(group);
public async Task<HashSet<GroupModel>> GetGroupsAsync() => await _dbService.GetGroupsAsync();
public async Task<bool> AddFeed(string rssUrl, GroupModel? group = null)
{
bool result = false;
Feed fetched = await FetchFeed(rssUrl);
if (fetched == null)
return result;
FeedModel feedModel = new FeedModel(rssUrl)
{
GroupId = group?.Id,
FeedType = fetched.Type.ToString(),
Description = fetched.Description,
Language = fetched.Language,
Copyright = fetched.Copyright,
DateAdded = DateTimeOffset.Now,
LastUpdated = DateTimeOffset.Now,
ImageUrl = fetched.ImageUrl,
};
result = await _dbService.SetFeedAsync(feedModel);
if (!result)
return result;
if (await AddFeedItems(fetched.Items, feedModel) == 0)
Log.Warning($"No feed items added to feed: {feedModel.Url}");
return result;
}
public async Task<HashSet<FeedModel>> GetFeedsAsync(GroupModel? group = null) => await _dbService.GetFeedsAsync(group);
public async Task<HashSet<FeedModel>> GetUngroupedFeedsAsync() => await _dbService.GetFeedsAsync(new GroupModel() { Id = "" });
private async Task<int> AddFeedItems(IList<FeedItem> items, FeedModel feedModel)
{
int result = 0;
if (!items.Any())
return result;
HashSet<FeedItemModel> itemModels = new HashSet<FeedItemModel>();
foreach (FeedItem item in items)
{
itemModels.Add(new FeedItemModel()
{
Id = item.Id,
FeedId = feedModel.Id,
Title = item.Title,
Description = item.Description,
Link = item.Link,
LastUpdated = DateTimeOffset.Now,
PublishingDate = item.PublishingDate != null ? new DateTimeOffset((DateTime)item.PublishingDate) : null,
Author = item.Author,
Categories = item.Categories.ToArray(),
Content = item.Content
});
}
result = await _dbService.SetFeedItemsAsync(itemModels);
return result;
}
private async Task<Feed> FetchFeed(string url)
{
var urls = await FeedReader.ParseFeedUrlsAsStringAsync(url);
string feedurl = url;
if (urls.Any())
feedurl = urls.First();
return await FeedReader.ReadAsync(feedurl);
}
private async void SetupTestCategoriesAndFeedsAsync()
{
var groups = await GetGroupsAsync();
GroupModel testGroup = groups.Single(x => x.Name == "Test");
var res = await AddFeed("http://fedoramagazine.org/feed/", testGroup);
res = await AddFeed("https://www.nasa.gov/rss/dyn/breaking_news.rss", testGroup);
res = await AddFeed("https://journals.plos.org/plosone/feed/atom", testGroup);
res = await AddFeed("https://itsfoss.com/feed", testGroup);
/*bool result = await _dbService.SetGroupAsync(new GroupModel() { Name = "News" });
result = await _dbService.SetGroupAsync(new GroupModel() { Name = "Tech" });
result = await _dbService.SetGroupAsync(new GroupModel() { Name = "Science" });

@ -1 +1 @@
Subproject commit af3abae0445b30c3ef58579a18e6e179eaea5986
Subproject commit 0f3a3fb0f9145aad31a44eb25159d0f2a5a1c7fd

View File

@ -9,21 +9,17 @@ namespace WebSharpRSS.Models
{
_service = rssService;
CategoryModel = catModel;
Initialize();
}
public TreeItemData(FeedModel feedModel, RssService rssService)
{
_service = rssService;
FeedModel = feedModel;
Initialize();
}
private readonly RssService _service;
public readonly GroupModel? CategoryModel;
public readonly FeedModel? FeedModel;
//private HashSet<FeedModel> _feedModels;
public string Title { get; set; } = string.Empty;
public bool IsSelected { get; set; }
@ -33,57 +29,5 @@ namespace WebSharpRSS.Models
// Category
public bool HasChild { get; set; }
public bool IsExpanded { get; set; }
//public HashSet<TreeItemData>? Feeds { get; set; }
// Feed
//public Feed? Feed { get; private set; }
/*public int FeeditemCount
{
get
{
if (CategoryModel != null && Feeds != null)
{
int feedsCount = 0;
foreach (var item in Feeds)
{
if (item.Feed != null)
feedsCount += item.FeeditemCount;
}
return feedsCount;
}
else if (Feed != null)
return Feed.Items.Count;
return 0;
}
}*/
private async void Initialize()
{
/*if (CategoryModel != null)
{
Title = CategoryModel.Name;
Icon = Icons.Material.Filled.Category;
/*_feedModels = await _service.GetFeedsAsync(CategoryModel);
if (_feedModels.Any())
Feeds = _feedModels.Select(x => new TreeItemData(x, _service)).OrderBy(x => x.Title).ToHashSet();#1#
}
if (FeedModel != null)
{
try
{
//Feed = await _service.GetFeedAsync(FeedModel.FeedUrl);
}
catch (Exception e)
{
Log.Error(e, "Error fetching feed: {FeedUrl}", FeedModel.FeedUrl);
Feed = null;
return;
}
Icon = Icons.Material.Filled.RssFeed;
Title = Feed.Title;
string faviconAddress = Feed.Link.Remove(Feed.Link.IndexOf("http", StringComparison.Ordinal), Feed.Link.IndexOf("://", StringComparison.Ordinal) + 3);
FaviconUrl = string.Format(Caretaker.Settings["Paths"].GetString("FaviconResolveUrl"), faviconAddress);
}*/
}
}
}

View File

@ -9,9 +9,9 @@
@inject FeedStateContainer _stateContainer;
@inject RssService _rssService
<MudStack Spacing="2">
@*<MudTreeView Items="_guideItems" @bind-SelectedValue="SelectedItem" Hover="true">
$1$<ItemTemplate>
@*<MudStack Spacing="2">
<MudTreeView Items="_guideItems" @bind-SelectedValue="SelectedItem" Hover="true">
<ItemTemplate>
<MudTreeViewItem @bind-Expanded="@context.IsExpanded" Items="@context.Feeds" Value="@context" CanExpand="@context.HasChild" @onclick="ItemClicked">
<Content>
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
@ -33,13 +33,13 @@
</div>
</Content>
</MudTreeViewItem>
</ItemTemplate>#1#
</MudTreeView>*@
</MudStack>
</ItemTemplate>
</MudTreeView>
</MudStack>*@
@code {
private MudTheme Theme = new MudTheme();
//private readonly HashSet<TreeItemData> _guideItems = new HashSet<TreeItemData>();
private readonly HashSet<TreeItemData> _guideItems = new HashSet<TreeItemData>();
/*private TreeItemData? _selectedItem;
private TreeItemData? SelectedItem
{

Binary file not shown.