mirror of
https://github.com/ckaczor/FeedCenter.git
synced 2026-02-16 10:58:31 -05:00
Move application files to sub-folder
This commit is contained in:
22
Application/Feeds/Category.cs
Normal file
22
Application/Feeds/Category.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace FeedCenter
|
||||
{
|
||||
public partial class Category
|
||||
{
|
||||
public static Category Create()
|
||||
{
|
||||
return new Category { ID = Guid.NewGuid() };
|
||||
}
|
||||
|
||||
public bool IsDefault
|
||||
{
|
||||
get { return Name == "< default >"; }
|
||||
}
|
||||
|
||||
public int SortKey
|
||||
{
|
||||
get { return IsDefault ? 0 : 1; }
|
||||
}
|
||||
}
|
||||
}
|
||||
349
Application/Feeds/Feed.cs
Normal file
349
Application/Feeds/Feed.cs
Normal file
@@ -0,0 +1,349 @@
|
||||
using Common.Debug;
|
||||
using Common.Xml;
|
||||
using FeedCenter.FeedParsers;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace FeedCenter
|
||||
{
|
||||
#region Enumerations
|
||||
|
||||
public enum MultipleOpenAction
|
||||
{
|
||||
IndividualPages,
|
||||
SinglePage
|
||||
}
|
||||
|
||||
public enum FeedType
|
||||
{
|
||||
Unknown,
|
||||
Rss,
|
||||
Rdf,
|
||||
Atom
|
||||
}
|
||||
|
||||
public enum FeedItemComparison : byte
|
||||
{
|
||||
Default,
|
||||
Title
|
||||
}
|
||||
|
||||
public enum FeedReadResult
|
||||
{
|
||||
Success,
|
||||
NotModified,
|
||||
NotDue,
|
||||
UnknownError,
|
||||
InvalidXml,
|
||||
NotEnabled,
|
||||
Unauthorized,
|
||||
NoResponse,
|
||||
NotFound,
|
||||
Timeout,
|
||||
ConnectionFailed,
|
||||
ServerError
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[ValueConversion(typeof(int), typeof(MultipleOpenAction))]
|
||||
public class MultipleOpenActionConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return (MultipleOpenAction) value;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return (int) value;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class Feed
|
||||
{
|
||||
public static Feed Create()
|
||||
{
|
||||
return new Feed { ID = Guid.NewGuid() };
|
||||
}
|
||||
|
||||
#region Event delegates
|
||||
|
||||
public delegate void ErrorEventHandler(WebException webException);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Reading
|
||||
|
||||
public FeedReadResult Read(FeedCenterEntities database, bool forceRead = false)
|
||||
{
|
||||
Tracer.WriteLine("Reading feed: {0}", Source);
|
||||
Tracer.IncrementIndentLevel();
|
||||
|
||||
var result = ReadFeed(database, forceRead);
|
||||
|
||||
// Handle the result
|
||||
switch (result)
|
||||
{
|
||||
case FeedReadResult.NotDue:
|
||||
case FeedReadResult.NotEnabled:
|
||||
case FeedReadResult.NotModified:
|
||||
// Ignore
|
||||
break;
|
||||
|
||||
default:
|
||||
// Save as last result
|
||||
LastReadResult = result;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// 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 == Data.Extensions.SqlDateTimeZero.Value)
|
||||
LastUpdated = DateTime.Now;
|
||||
|
||||
Tracer.DecrementIndentLevel();
|
||||
Tracer.WriteLine("Done reading feed: {0}", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Tuple<FeedReadResult, string> RetrieveFeed()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create the web request
|
||||
var oRequest = WebRequest.Create(new Uri(Source));
|
||||
|
||||
// Attempt to cast to a web request
|
||||
var webRequest = oRequest as HttpWebRequest;
|
||||
|
||||
// If this is an http request set some special properties
|
||||
if (webRequest != null)
|
||||
{
|
||||
// Make sure to use HTTP version 1.1
|
||||
webRequest.ProtocolVersion = HttpVersion.Version11;
|
||||
|
||||
// Set that we'll accept compressed data
|
||||
webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
|
||||
|
||||
// Set a timeout
|
||||
webRequest.Timeout = 10000;
|
||||
|
||||
// If we need to authenticate then set the credentials
|
||||
if (Authenticate)
|
||||
webRequest.Credentials = new NetworkCredential(Username, Password, Domain);
|
||||
|
||||
// Set a user agent string
|
||||
webRequest.UserAgent = "FeedCenter 1.0 ALPHA";
|
||||
}
|
||||
|
||||
// Set the default encoding
|
||||
var encoding = Encoding.UTF8;
|
||||
|
||||
// Attempt to get the response
|
||||
var response = (HttpWebResponse) oRequest.GetResponse();
|
||||
|
||||
// If the response included an encoding then change the encoding
|
||||
if (response.ContentEncoding.Length > 0)
|
||||
encoding = Encoding.GetEncoding(response.ContentEncoding);
|
||||
|
||||
// Get the response stream
|
||||
var responseStream = response.GetResponseStream();
|
||||
|
||||
if (responseStream == null)
|
||||
return Tuple.Create(FeedReadResult.NoResponse, string.Empty);
|
||||
|
||||
// Create the text reader
|
||||
StreamReader textReader = new XmlSanitizingStream(responseStream, encoding);
|
||||
|
||||
// Get the feed text
|
||||
var feedText = textReader.ReadToEnd();
|
||||
|
||||
// Get rid of any leading and trailing whitespace
|
||||
feedText = feedText.Trim();
|
||||
|
||||
// Clean up common invalid XML characters
|
||||
feedText = feedText.Replace(" ", " ");
|
||||
|
||||
return Tuple.Create(FeedReadResult.Success, feedText);
|
||||
}
|
||||
catch (IOException ioException)
|
||||
{
|
||||
Tracer.WriteLine(ioException.Message);
|
||||
|
||||
return Tuple.Create(FeedReadResult.ConnectionFailed, string.Empty);
|
||||
}
|
||||
catch (WebException webException)
|
||||
{
|
||||
var result = FeedReadResult.UnknownError;
|
||||
|
||||
var errorResponse = webException.Response as HttpWebResponse;
|
||||
|
||||
if (errorResponse != null)
|
||||
{
|
||||
switch (errorResponse.StatusCode)
|
||||
{
|
||||
case HttpStatusCode.InternalServerError:
|
||||
return Tuple.Create(FeedReadResult.ServerError, string.Empty);
|
||||
|
||||
case HttpStatusCode.NotModified:
|
||||
return Tuple.Create(FeedReadResult.NotModified, string.Empty);
|
||||
|
||||
case HttpStatusCode.NotFound:
|
||||
return Tuple.Create(FeedReadResult.NotFound, string.Empty);
|
||||
|
||||
case HttpStatusCode.Unauthorized:
|
||||
case HttpStatusCode.Forbidden:
|
||||
return Tuple.Create(FeedReadResult.Unauthorized, string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
switch (webException.Status)
|
||||
{
|
||||
case WebExceptionStatus.ConnectFailure:
|
||||
case WebExceptionStatus.NameResolutionFailure:
|
||||
result = FeedReadResult.ConnectionFailed;
|
||||
break;
|
||||
|
||||
case WebExceptionStatus.Timeout:
|
||||
result = FeedReadResult.Timeout;
|
||||
break;
|
||||
}
|
||||
|
||||
Tracer.WriteException(webException);
|
||||
|
||||
if (result == FeedReadResult.UnknownError)
|
||||
Debug.Print("Unknown error");
|
||||
|
||||
return Tuple.Create(result, string.Empty);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Tracer.WriteLine(exception.Message);
|
||||
|
||||
return Tuple.Create(FeedReadResult.UnknownError, string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private FeedReadResult ReadFeed(FeedCenterEntities database, bool forceRead)
|
||||
{
|
||||
try
|
||||
{
|
||||
// If not enabled then do nothing
|
||||
if (!Enabled)
|
||||
return FeedReadResult.NotEnabled;
|
||||
|
||||
// Check if we're forcing a read
|
||||
if (!forceRead)
|
||||
{
|
||||
// Figure out how long since we last checked
|
||||
var timeSpan = DateTime.Now - LastChecked;
|
||||
|
||||
// Check if we are due to read the feed
|
||||
if (timeSpan.TotalMinutes < CheckInterval)
|
||||
return FeedReadResult.NotDue;
|
||||
}
|
||||
|
||||
// We're checking it now so update the time
|
||||
LastChecked = DateTime.Now;
|
||||
|
||||
// Read the feed text
|
||||
var retrieveResult = RetrieveFeed();
|
||||
|
||||
// Get the information out of the async result
|
||||
var result = retrieveResult.Item1;
|
||||
var feedText = retrieveResult.Item2;
|
||||
|
||||
// If we didn't successfully retrieve the feed then stop
|
||||
if (result != FeedReadResult.Success)
|
||||
return result;
|
||||
|
||||
// Create a new RSS parser
|
||||
var feedParser = FeedParserBase.CreateFeedParser(this, feedText);
|
||||
|
||||
// Parse the feed
|
||||
result = feedParser.ParseFeed(feedText);
|
||||
|
||||
// If we didn't successfully parse the feed then stop
|
||||
if (result != FeedReadResult.Success)
|
||||
return result;
|
||||
|
||||
// Create the removed items list - if an item wasn't seen during this check then remove it
|
||||
var removedItems = Items.Where(testItem => testItem.LastFound != LastChecked).ToList();
|
||||
|
||||
// If items were removed the feed was updated
|
||||
if (removedItems.Count > 0)
|
||||
LastUpdated = DateTime.Now;
|
||||
|
||||
// Loop over the items to be removed
|
||||
foreach (var itemToRemove in removedItems)
|
||||
{
|
||||
// Delete the item from the database
|
||||
database.FeedItems.Remove(itemToRemove);
|
||||
|
||||
// Remove the item from the list
|
||||
Items.Remove(itemToRemove);
|
||||
}
|
||||
|
||||
// Process actions on this feed
|
||||
ProcessActions();
|
||||
|
||||
return FeedReadResult.Success;
|
||||
}
|
||||
catch (InvalidFeedFormatException exception)
|
||||
{
|
||||
Tracer.WriteException(exception.InnerException);
|
||||
|
||||
return FeedReadResult.InvalidXml;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Tracer.WriteLine(exception.Message);
|
||||
|
||||
return FeedReadResult.UnknownError;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessActions()
|
||||
{
|
||||
var sortedActions = from action in Actions orderby action.Sequence ascending select action;
|
||||
|
||||
foreach (var feedAction in sortedActions)
|
||||
{
|
||||
switch (feedAction.Field)
|
||||
{
|
||||
case 0:
|
||||
Title = Title.Replace(feedAction.Search, feedAction.Replace);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public string LastReadResultDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
// Cast the last read result to the proper enum
|
||||
var lastReadResult = LastReadResult;
|
||||
|
||||
// Build the name of the resource using the enum name and the value
|
||||
var resourceName = string.Format("{0}_{1}", typeof(FeedReadResult).Name, lastReadResult);
|
||||
|
||||
// Try to get the value from the resources
|
||||
var resourceValue = Properties.Resources.ResourceManager.GetString(resourceName);
|
||||
|
||||
// Return the value or just the enum value if not found
|
||||
return resourceValue ?? lastReadResult.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Application/Feeds/FeedAction.cs
Normal file
25
Application/Feeds/FeedAction.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace FeedCenter
|
||||
{
|
||||
public partial class FeedAction
|
||||
{
|
||||
#region Constructor
|
||||
|
||||
public FeedAction()
|
||||
{
|
||||
ID = Guid.NewGuid();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(Properties.Resources.FeedActionDescription, Field, Search, Replace);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
70
Application/Feeds/FeedItem.cs
Normal file
70
Application/Feeds/FeedItem.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FeedCenter
|
||||
{
|
||||
public partial class FeedItem
|
||||
{
|
||||
public static FeedItem Create()
|
||||
{
|
||||
return new FeedItem { ID = System.Guid.NewGuid() };
|
||||
}
|
||||
|
||||
#region Methods
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string title = Title;
|
||||
|
||||
switch (Properties.Settings.Default.MultipleLineDisplay)
|
||||
{
|
||||
case Options.MultipleLineDisplay.SingleLine:
|
||||
|
||||
// Strip any newlines from the title
|
||||
title = Regex.Replace(title, @"\n", " ");
|
||||
|
||||
break;
|
||||
|
||||
case Options.MultipleLineDisplay.FirstLine:
|
||||
|
||||
// Find the first newline
|
||||
int newlineIndex = title.IndexOf("\n", StringComparison.Ordinal);
|
||||
|
||||
// If a newline was found return everything before it
|
||||
if (newlineIndex > -1)
|
||||
title = title.Substring(0, newlineIndex);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Condense multiple spaces to one space
|
||||
title = Regex.Replace(title, @"[ ]{2,}", " ");
|
||||
|
||||
// Condense tabs to one space
|
||||
title = Regex.Replace(title, @"\t", " ");
|
||||
|
||||
// If the title is blank then put in the "no title" title
|
||||
if (title.Length == 0)
|
||||
title = Properties.Resources.NoTitleText;
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
public void ProcessActions(IEnumerable<FeedAction> feedActions)
|
||||
{
|
||||
foreach (FeedAction feedAction in feedActions)
|
||||
{
|
||||
switch (feedAction.Field)
|
||||
{
|
||||
case 1:
|
||||
|
||||
Title = Regex.Replace(Title, feedAction.Search, feedAction.Replace);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user