mirror of
https://github.com/ckaczor/FeedCenter.git
synced 2026-02-16 10:58:31 -05:00
Start adding server support
This commit is contained in:
203
Application/Feeds/Account.cs
Normal file
203
Application/Feeds/Account.cs
Normal file
@@ -0,0 +1,203 @@
|
||||
using Realms;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace FeedCenter;
|
||||
|
||||
public class Account : RealmObject, INotifyDataErrorInfo
|
||||
{
|
||||
public const string DefaultName = "< Local >";
|
||||
|
||||
private readonly DataErrorDictionary _dataErrorDictionary;
|
||||
|
||||
public Account() : this(AccountType.Local)
|
||||
{
|
||||
}
|
||||
|
||||
public Account(AccountType type)
|
||||
{
|
||||
Type = type;
|
||||
|
||||
_dataErrorDictionary = new DataErrorDictionary();
|
||||
_dataErrorDictionary.ErrorsChanged += DataErrorDictionaryErrorsChanged;
|
||||
}
|
||||
|
||||
[PrimaryKey]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
public AccountType Type
|
||||
{
|
||||
get => Enum.TryParse(TypeRaw, out AccountType result) ? result : AccountType.Local;
|
||||
set => TypeRaw = value.ToString();
|
||||
}
|
||||
|
||||
public bool SupportsFeedEdit => Type switch
|
||||
{
|
||||
AccountType.Fever => false,
|
||||
AccountType.GoogleReader => false,
|
||||
AccountType.Local => true,
|
||||
_ => throw new NotSupportedException()
|
||||
};
|
||||
|
||||
public bool SupportsFeedDelete => Type switch
|
||||
{
|
||||
AccountType.Fever => false,
|
||||
AccountType.GoogleReader => false,
|
||||
AccountType.Local => true,
|
||||
_ => throw new NotSupportedException()
|
||||
};
|
||||
|
||||
private string TypeRaw { get; set; }
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => RawName;
|
||||
set
|
||||
{
|
||||
RawName = value;
|
||||
|
||||
ValidateString(nameof(Name), RawName);
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[MapTo("Name")]
|
||||
private string RawName { get; set; } = string.Empty;
|
||||
|
||||
public string Url
|
||||
{
|
||||
get => RawUrl;
|
||||
set
|
||||
{
|
||||
RawUrl = value;
|
||||
|
||||
ValidateString(nameof(Url), RawUrl);
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[MapTo("Url")]
|
||||
public string RawUrl { get; set; }
|
||||
|
||||
public string Username
|
||||
{
|
||||
get => RawUsername;
|
||||
set
|
||||
{
|
||||
RawUsername = value;
|
||||
|
||||
if (!Authenticate)
|
||||
{
|
||||
_dataErrorDictionary.ClearErrors(nameof(Username));
|
||||
return;
|
||||
}
|
||||
|
||||
ValidateString(nameof(Username), RawUsername);
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[MapTo("Username")]
|
||||
public string RawUsername { get; set; }
|
||||
|
||||
public string Password
|
||||
{
|
||||
get => RawPassword;
|
||||
set
|
||||
{
|
||||
RawPassword = value;
|
||||
|
||||
if (!Authenticate)
|
||||
{
|
||||
_dataErrorDictionary.ClearErrors(nameof(Password));
|
||||
return;
|
||||
}
|
||||
|
||||
ValidateString(nameof(Password), RawPassword);
|
||||
RaisePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
[MapTo("Password")]
|
||||
public string RawPassword { get; set; }
|
||||
|
||||
public bool Authenticate { get; set; }
|
||||
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
public int CheckInterval { get; set; } = 60;
|
||||
|
||||
public DateTimeOffset LastChecked { get; set; }
|
||||
|
||||
public bool HasErrors => _dataErrorDictionary.Any();
|
||||
|
||||
public IEnumerable GetErrors(string propertyName)
|
||||
{
|
||||
return _dataErrorDictionary.GetErrors(propertyName);
|
||||
}
|
||||
|
||||
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
|
||||
|
||||
private void DataErrorDictionaryErrorsChanged(object sender, DataErrorsChangedEventArgs e)
|
||||
{
|
||||
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(e.PropertyName));
|
||||
}
|
||||
|
||||
private void ValidateString(string propertyName, string value)
|
||||
{
|
||||
_dataErrorDictionary.ClearErrors(propertyName);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
_dataErrorDictionary.AddError(propertyName, $"{propertyName} cannot be empty");
|
||||
}
|
||||
|
||||
public static Account CreateDefault()
|
||||
{
|
||||
return new Account { Name = DefaultName, Type = AccountType.Local };
|
||||
}
|
||||
|
||||
public int GetProgressSteps(FeedCenterEntities entities)
|
||||
{
|
||||
var progressSteps = Type switch
|
||||
{
|
||||
// Delegate to the right reader based on the account type
|
||||
AccountType.Fever => new FeverReader().GetProgressSteps(entities),
|
||||
AccountType.GoogleReader => new GoogleReaderReader().GetProgressSteps(entities),
|
||||
AccountType.Local => new LocalReader().GetProgressSteps(entities),
|
||||
_ => throw new NotSupportedException()
|
||||
};
|
||||
|
||||
return progressSteps;
|
||||
}
|
||||
|
||||
public AccountReadResult Read(AccountReadInput accountReadInput)
|
||||
{
|
||||
// If not enabled then do nothing
|
||||
if (!Enabled)
|
||||
return AccountReadResult.NotEnabled;
|
||||
|
||||
// Check if we're forcing a read
|
||||
if (!accountReadInput.ForceRead)
|
||||
{
|
||||
// Figure out how long since we last checked
|
||||
var timeSpan = DateTimeOffset.Now - LastChecked;
|
||||
|
||||
// Check if we are due to read the feed
|
||||
if (timeSpan.TotalMinutes < CheckInterval)
|
||||
return AccountReadResult.NotDue;
|
||||
}
|
||||
|
||||
var accountReadResult = Type switch
|
||||
{
|
||||
// Delegate to the right reader based on the account type
|
||||
AccountType.Fever => new FeverReader().Read(this, accountReadInput),
|
||||
AccountType.GoogleReader => new GoogleReaderReader().Read(this, accountReadInput),
|
||||
AccountType.Local => new LocalReader().Read(this, accountReadInput),
|
||||
_ => throw new NotSupportedException()
|
||||
};
|
||||
|
||||
return accountReadResult;
|
||||
}
|
||||
}
|
||||
11
Application/Feeds/AccountReadInput.cs
Normal file
11
Application/Feeds/AccountReadInput.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace FeedCenter;
|
||||
|
||||
public class AccountReadInput(FeedCenterEntities entities, Guid? feedId, bool forceRead, Action incrementProgress)
|
||||
{
|
||||
public FeedCenterEntities Entities { get; set; } = entities;
|
||||
public Guid? FeedId { get; set; } = feedId;
|
||||
public bool ForceRead { get; set; } = forceRead;
|
||||
public Action IncrementProgress { get; private set; } = incrementProgress ?? throw new ArgumentNullException(nameof(incrementProgress));
|
||||
}
|
||||
8
Application/Feeds/AccountReadResult.cs
Normal file
8
Application/Feeds/AccountReadResult.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace FeedCenter;
|
||||
|
||||
public enum AccountReadResult
|
||||
{
|
||||
Success,
|
||||
NotDue,
|
||||
NotEnabled
|
||||
}
|
||||
8
Application/Feeds/AccountType.cs
Normal file
8
Application/Feeds/AccountType.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace FeedCenter;
|
||||
|
||||
public enum AccountType
|
||||
{
|
||||
Local,
|
||||
Fever,
|
||||
GoogleReader
|
||||
}
|
||||
@@ -22,6 +22,10 @@ public class Category : RealmObject, INotifyDataErrorInfo
|
||||
[PrimaryKey]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
public string RemoteId { get; set; }
|
||||
|
||||
public Account Account { get; set; }
|
||||
|
||||
public bool IsDefault { get; internal set; }
|
||||
|
||||
public string Name
|
||||
@@ -56,9 +60,9 @@ public class Category : RealmObject, INotifyDataErrorInfo
|
||||
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(e.PropertyName));
|
||||
}
|
||||
|
||||
public static Category CreateDefault()
|
||||
public static Category CreateDefault(Account account)
|
||||
{
|
||||
return new Category { Name = DefaultName, IsDefault = true };
|
||||
return new Category { Name = DefaultName, IsDefault = true, Account = account };
|
||||
}
|
||||
|
||||
private void ValidateName()
|
||||
|
||||
@@ -12,7 +12,6 @@ using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using ChrisKaczor.ApplicationUpdate;
|
||||
using FeedCenter.Data;
|
||||
using FeedCenter.FeedParsers;
|
||||
using FeedCenter.Properties;
|
||||
using FeedCenter.Xml;
|
||||
@@ -34,14 +33,16 @@ public partial class Feed : RealmObject, INotifyDataErrorInfo
|
||||
_dataErrorDictionary.ErrorsChanged += DataErrorDictionaryErrorsChanged;
|
||||
}
|
||||
|
||||
[PrimaryKey]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string RemoteId { get; set; }
|
||||
public bool Authenticate { get; set; }
|
||||
public Guid CategoryId { get; set; }
|
||||
public int CheckInterval { get; set; } = 60;
|
||||
public string Description { get; set; }
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
[PrimaryKey]
|
||||
public Guid Id { get; set; }
|
||||
public Account Account { get; set; }
|
||||
|
||||
[UsedImplicitly]
|
||||
public IList<FeedItem> Items { get; }
|
||||
@@ -171,9 +172,9 @@ public partial class Feed : RealmObject, INotifyDataErrorInfo
|
||||
|
||||
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
|
||||
|
||||
public static Feed Create()
|
||||
public static Feed Create(FeedCenterEntities entities)
|
||||
{
|
||||
return new Feed { Id = Guid.NewGuid(), CategoryId = Database.Entities.DefaultCategory.Id };
|
||||
return new Feed { Id = Guid.NewGuid(), CategoryId = entities.DefaultCategory.Id, Account = entities.LocalAccount };
|
||||
}
|
||||
|
||||
private void DataErrorDictionaryErrorsChanged(object sender, DataErrorsChangedEventArgs e)
|
||||
@@ -215,7 +216,7 @@ public partial class Feed : RealmObject, INotifyDataErrorInfo
|
||||
break;
|
||||
}
|
||||
|
||||
// If the feed was successfully read and we have no last update timestamp - set the last update timestamp to now
|
||||
// If the feed was successfully read, and we have no last update timestamp - set the last update timestamp to now
|
||||
if (result == FeedReadResult.Success && LastUpdated == default)
|
||||
LastUpdated = DateTimeOffset.Now;
|
||||
|
||||
|
||||
@@ -1,25 +1,28 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using FeedCenter.Options;
|
||||
using FeedCenter.Options;
|
||||
using Realms;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FeedCenter;
|
||||
|
||||
public partial class FeedItem : RealmObject
|
||||
{
|
||||
[PrimaryKey]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public bool BeenRead { get; set; }
|
||||
public string Description { get; set; }
|
||||
public Guid FeedId { get; set; }
|
||||
public string Guid { get; set; }
|
||||
|
||||
[PrimaryKey]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public DateTimeOffset LastFound { get; set; }
|
||||
public string Link { get; set; }
|
||||
public bool New { get; set; }
|
||||
public int Sequence { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string RemoteId { get; set; }
|
||||
|
||||
public static FeedItem Create()
|
||||
{
|
||||
@@ -42,7 +45,7 @@ public partial class FeedItem : RealmObject
|
||||
case MultipleLineDisplay.FirstLine:
|
||||
|
||||
// Find the first newline
|
||||
var newlineIndex = title.IndexOf("\n", StringComparison.Ordinal);
|
||||
var newlineIndex = title.IndexOf('\n', StringComparison.Ordinal);
|
||||
|
||||
// If a newline was found return everything before it
|
||||
if (newlineIndex > -1)
|
||||
@@ -70,6 +73,34 @@ public partial class FeedItem : RealmObject
|
||||
return title;
|
||||
}
|
||||
|
||||
public async Task MarkAsRead(FeedCenterEntities entities)
|
||||
{
|
||||
var feed = entities.Feeds.FirstOrDefault(f => f.Id == FeedId);
|
||||
|
||||
entities.SaveChanges(() =>
|
||||
{
|
||||
BeenRead = true;
|
||||
New = false;
|
||||
});
|
||||
|
||||
if (feed == null || feed.Account.Type == AccountType.Local)
|
||||
return;
|
||||
|
||||
switch (feed.Account.Type)
|
||||
{
|
||||
case AccountType.Fever:
|
||||
// Delegate to the right reader based on the account type
|
||||
await FeverReader.MarkFeedItemRead(feed.Account, RemoteId);
|
||||
|
||||
break;
|
||||
case AccountType.Local:
|
||||
break;
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[GeneratedRegex("\\n")]
|
||||
private static partial Regex NewlineRegex();
|
||||
|
||||
|
||||
145
Application/Feeds/FeverReader.cs
Normal file
145
Application/Feeds/FeverReader.cs
Normal file
@@ -0,0 +1,145 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ChrisKaczor.FeverClient;
|
||||
|
||||
namespace FeedCenter;
|
||||
|
||||
internal class FeverReader : IAccountReader
|
||||
{
|
||||
public int GetProgressSteps(FeedCenterEntities entities)
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
|
||||
public AccountReadResult Read(Account account, AccountReadInput accountReadInput)
|
||||
{
|
||||
var checkTime = DateTimeOffset.UtcNow;
|
||||
|
||||
var apiKey = account.Authenticate ? GetApiKey(account) : string.Empty;
|
||||
|
||||
var feverClient = new FeverClient(account.Url, apiKey);
|
||||
|
||||
accountReadInput.IncrementProgress();
|
||||
|
||||
var feverFeeds = feverClient.GetFeeds().Result.ToList();
|
||||
|
||||
accountReadInput.IncrementProgress();
|
||||
|
||||
var allFeverFeedItems = feverClient.GetAllFeedItems().Result.ToList();
|
||||
|
||||
accountReadInput.IncrementProgress();
|
||||
|
||||
var transaction = accountReadInput.Entities.BeginTransaction();
|
||||
|
||||
foreach (var feverFeed in feverFeeds)
|
||||
{
|
||||
var feed = accountReadInput.Entities.Feeds.FirstOrDefault(f => f.RemoteId == feverFeed.Id.ToString() && f.Account.Id == account.Id);
|
||||
|
||||
if (feed == null)
|
||||
{
|
||||
feed = new Feed
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
RemoteId = feverFeed.Id.ToString(),
|
||||
Title = feverFeed.Title,
|
||||
Source = feverFeed.Url,
|
||||
Link = feverFeed.SiteUrl,
|
||||
Account = account,
|
||||
Name = feverFeed.Title,
|
||||
CategoryId = accountReadInput.Entities.DefaultCategory.Id,
|
||||
Enabled = true,
|
||||
CheckInterval = 0,
|
||||
};
|
||||
|
||||
accountReadInput.Entities.Feeds.Add(feed);
|
||||
}
|
||||
|
||||
feed.Name = feverFeed.Title;
|
||||
feed.Title = feverFeed.Title;
|
||||
feed.Link = feverFeed.SiteUrl;
|
||||
feed.Source = feverFeed.Url;
|
||||
feed.LastReadResult = FeedReadResult.Success;
|
||||
feed.LastChecked = checkTime;
|
||||
|
||||
accountReadInput.IncrementProgress();
|
||||
|
||||
var feverFeedItems = allFeverFeedItems
|
||||
.Where(f => f.FeedId == feverFeed.Id)
|
||||
.OrderByDescending(fi => fi.CreatedOnTime).ToList();
|
||||
|
||||
var sequence = 1;
|
||||
|
||||
foreach (var feverFeedItem in feverFeedItems)
|
||||
{
|
||||
var feedItem = feed.Items.FirstOrDefault(f => f.RemoteId == feverFeedItem.Id.ToString());
|
||||
|
||||
if (feedItem == null)
|
||||
{
|
||||
feedItem = new FeedItem
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
RemoteId = feverFeedItem.Id.ToString(),
|
||||
Title = feverFeedItem.Title,
|
||||
Link = feverFeedItem.Url,
|
||||
Description = feverFeedItem.Html,
|
||||
BeenRead = feverFeedItem.IsRead,
|
||||
FeedId = feed.Id,
|
||||
Guid = Guid.NewGuid().ToString(),
|
||||
Sequence = sequence++,
|
||||
};
|
||||
|
||||
feed.Items.Add(feedItem);
|
||||
}
|
||||
|
||||
feedItem.LastFound = checkTime;
|
||||
feedItem.BeenRead = feverFeedItem.IsRead;
|
||||
feedItem.Sequence = sequence++;
|
||||
}
|
||||
|
||||
accountReadInput.IncrementProgress();
|
||||
|
||||
var feedItemsNotSeen = feed.Items.Where(fi => fi.LastFound != checkTime).ToList();
|
||||
|
||||
foreach (var feedItemNotSeen in feedItemsNotSeen)
|
||||
{
|
||||
feed.Items.Remove(feedItemNotSeen);
|
||||
}
|
||||
}
|
||||
|
||||
accountReadInput.IncrementProgress();
|
||||
|
||||
var feedsNotSeen = accountReadInput.Entities.Feeds.Where(f => f.Account.Id == account.Id && f.LastChecked != checkTime).ToList();
|
||||
|
||||
foreach (var feedNotSeen in feedsNotSeen)
|
||||
{
|
||||
accountReadInput.Entities.Feeds.Remove(feedNotSeen);
|
||||
}
|
||||
|
||||
account.LastChecked = checkTime;
|
||||
|
||||
transaction.Commit();
|
||||
|
||||
accountReadInput.IncrementProgress();
|
||||
|
||||
return AccountReadResult.Success;
|
||||
}
|
||||
|
||||
public static async Task MarkFeedItemRead(Account account, string feedItemId)
|
||||
{
|
||||
var apiKey = account.Authenticate ? GetApiKey(account) : string.Empty;
|
||||
|
||||
var feverClient = new FeverClient(account.Url, apiKey);
|
||||
|
||||
await feverClient.MarkFeedItemAsRead(int.Parse(feedItemId));
|
||||
}
|
||||
|
||||
private static string GetApiKey(Account account)
|
||||
{
|
||||
var input = $"{account.Username}:{account.Password}";
|
||||
var hash = MD5.HashData(Encoding.UTF8.GetBytes(input));
|
||||
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
144
Application/Feeds/GoogleReaderReader.cs
Normal file
144
Application/Feeds/GoogleReaderReader.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FeedCenter;
|
||||
|
||||
internal class GoogleReaderReader : IAccountReader
|
||||
{
|
||||
public int GetProgressSteps(FeedCenterEntities entities)
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
|
||||
public AccountReadResult Read(Account account, AccountReadInput accountReadInput)
|
||||
{
|
||||
var checkTime = DateTimeOffset.UtcNow;
|
||||
|
||||
//var apiKey = account.Authenticate ? GetApiKey(account) : string.Empty;
|
||||
|
||||
//var feverClient = new FeverClient.FeverClient(account.Url, apiKey);
|
||||
|
||||
//accountReadInput.IncrementProgress();
|
||||
|
||||
//var feverFeeds = feverClient.GetFeeds().Result.ToList();
|
||||
|
||||
//accountReadInput.IncrementProgress();
|
||||
|
||||
//var allFeverFeedItems = feverClient.GetAllFeedItems().Result.ToList();
|
||||
|
||||
//accountReadInput.IncrementProgress();
|
||||
|
||||
var transaction = accountReadInput.Entities.BeginTransaction();
|
||||
|
||||
//foreach (var feverFeed in feverFeeds)
|
||||
//{
|
||||
// var feed = accountReadInput.Entities.Feeds.FirstOrDefault(f => f.RemoteId == feverFeed.Id.ToString() && f.Account.Id == account.Id);
|
||||
|
||||
// if (feed == null)
|
||||
// {
|
||||
// feed = new Feed
|
||||
// {
|
||||
// Id = Guid.NewGuid(),
|
||||
// RemoteId = feverFeed.Id.ToString(),
|
||||
// Title = feverFeed.Title,
|
||||
// Source = feverFeed.Url,
|
||||
// Link = feverFeed.SiteUrl,
|
||||
// Account = account,
|
||||
// Name = feverFeed.Title,
|
||||
// CategoryId = accountReadInput.Entities.DefaultCategory.Id,
|
||||
// Enabled = true,
|
||||
// CheckInterval = 0,
|
||||
// };
|
||||
|
||||
// accountReadInput.Entities.Feeds.Add(feed);
|
||||
// }
|
||||
|
||||
// feed.Name = feverFeed.Title;
|
||||
// feed.Title = feverFeed.Title;
|
||||
// feed.Link = feverFeed.SiteUrl;
|
||||
// feed.Source = feverFeed.Url;
|
||||
// feed.LastReadResult = FeedReadResult.Success;
|
||||
// feed.LastChecked = checkTime;
|
||||
|
||||
// accountReadInput.IncrementProgress();
|
||||
|
||||
// var feverFeedItems = allFeverFeedItems
|
||||
// .Where(f => f.FeedId == feverFeed.Id)
|
||||
// .OrderByDescending(fi => fi.CreatedOnTime).ToList();
|
||||
|
||||
// var sequence = 1;
|
||||
|
||||
// foreach (var feverFeedItem in feverFeedItems)
|
||||
// {
|
||||
// var feedItem = feed.Items.FirstOrDefault(f => f.RemoteId == feverFeedItem.Id.ToString());
|
||||
|
||||
// if (feedItem == null)
|
||||
// {
|
||||
// feedItem = new FeedItem
|
||||
// {
|
||||
// Id = Guid.NewGuid(),
|
||||
// RemoteId = feverFeedItem.Id.ToString(),
|
||||
// Title = feverFeedItem.Title,
|
||||
// Link = feverFeedItem.Url,
|
||||
// Description = feverFeedItem.Html,
|
||||
// BeenRead = feverFeedItem.IsRead,
|
||||
// FeedId = feed.Id,
|
||||
// Guid = Guid.NewGuid().ToString(),
|
||||
// Sequence = sequence++,
|
||||
// };
|
||||
|
||||
// feed.Items.Add(feedItem);
|
||||
// }
|
||||
|
||||
// feedItem.LastFound = checkTime;
|
||||
// feedItem.BeenRead = feverFeedItem.IsRead;
|
||||
// feedItem.Sequence = sequence++;
|
||||
// }
|
||||
|
||||
// accountReadInput.IncrementProgress();
|
||||
|
||||
// var feedItemsNotSeen = feed.Items.Where(fi => fi.LastFound != checkTime).ToList();
|
||||
|
||||
// foreach (var feedItemNotSeen in feedItemsNotSeen)
|
||||
// {
|
||||
// feed.Items.Remove(feedItemNotSeen);
|
||||
// }
|
||||
//}
|
||||
|
||||
accountReadInput.IncrementProgress();
|
||||
|
||||
//var feedsNotSeen = accountReadInput.Entities.Feeds.Where(f => f.Account.Id == account.Id && f.LastChecked != checkTime).ToList();
|
||||
|
||||
//foreach (var feedNotSeen in feedsNotSeen)
|
||||
//{
|
||||
// accountReadInput.Entities.Feeds.Remove(feedNotSeen);
|
||||
//}
|
||||
|
||||
account.LastChecked = checkTime;
|
||||
|
||||
transaction.Commit();
|
||||
|
||||
accountReadInput.IncrementProgress();
|
||||
|
||||
return AccountReadResult.Success;
|
||||
}
|
||||
|
||||
public static async Task MarkFeedItemRead(Account account, string feedItemId)
|
||||
{
|
||||
//var apiKey = account.Authenticate ? GetApiKey(account) : string.Empty;
|
||||
|
||||
//var feverClient = new FeverClient.FeverClient(account.Url, apiKey);
|
||||
|
||||
//await feverClient.MarkFeedItemAsRead(int.Parse(feedItemId));
|
||||
}
|
||||
|
||||
//private static string GetApiKey(Account account)
|
||||
//{
|
||||
// var input = $"{account.Username}:{account.Password}";
|
||||
// var hash = MD5.HashData(Encoding.UTF8.GetBytes(input));
|
||||
// return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
|
||||
//}
|
||||
}
|
||||
7
Application/Feeds/IAccountReader.cs
Normal file
7
Application/Feeds/IAccountReader.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace FeedCenter;
|
||||
|
||||
public interface IAccountReader
|
||||
{
|
||||
public int GetProgressSteps(FeedCenterEntities entities);
|
||||
public AccountReadResult Read(Account account, AccountReadInput accountReadInput);
|
||||
}
|
||||
42
Application/Feeds/LocalReader.cs
Normal file
42
Application/Feeds/LocalReader.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace FeedCenter;
|
||||
|
||||
public class LocalReader : IAccountReader
|
||||
{
|
||||
public int GetProgressSteps(FeedCenterEntities entities)
|
||||
{
|
||||
var enabledFeedCount = entities.Feeds.Count(f => f.Account.Type == AccountType.Local && f.Enabled);
|
||||
|
||||
return enabledFeedCount;
|
||||
}
|
||||
|
||||
public AccountReadResult Read(Account account, AccountReadInput accountReadInput)
|
||||
{
|
||||
var checkTime = DateTimeOffset.UtcNow;
|
||||
|
||||
// Create the list of feeds to read
|
||||
var feedsToRead = new List<Feed>();
|
||||
|
||||
// If we have a single feed then add it to the list - otherwise add them all
|
||||
if (accountReadInput.FeedId != null)
|
||||
feedsToRead.Add(accountReadInput.Entities.Feeds.First(feed => feed.Id == accountReadInput.FeedId));
|
||||
else
|
||||
feedsToRead.AddRange(accountReadInput.Entities.Feeds.Where(f => f.Account.Type == AccountType.Local));
|
||||
|
||||
// Loop over each feed and read it
|
||||
foreach (var feed in feedsToRead)
|
||||
{
|
||||
// Read the feed
|
||||
accountReadInput.Entities.SaveChanges(() => feed.Read(accountReadInput.ForceRead));
|
||||
|
||||
accountReadInput.IncrementProgress();
|
||||
}
|
||||
|
||||
accountReadInput.Entities.SaveChanges(() => account.LastChecked = checkTime);
|
||||
|
||||
return AccountReadResult.Success;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user