using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.ServiceModel.Syndication; using System.Xml; using System.Xml.Linq; namespace ChadSoft.Edificator { internal class SyndicatedFeedWisdomGenerator : IWisdomGenerator { private const int MaxSummaryCharacterCount = 4000; private static readonly SyndicationPerson UnknownAuthor = new SyndicationPerson(string.Empty, "Unknown Author", string.Empty); private readonly string _feedLocation; private readonly string _category; private readonly Random _randomizer; protected SyndicationFeed Feed { get { if (_feed == null || IsFeedStale()) LoadSyndicationFeed(); return _feed; } set { _feed = value; } } private SyndicationFeed _feed; public SyndicatedFeedWisdomGenerator(string feedLocation, string category) { _feedLocation = feedLocation; _category = category; _randomizer = new Random(); } public WisdomBit GetMostRecentlyAddedBitOfWisdom() { SyndicationItem feedItem = Feed.Items.OrderByDescending(x => x.PublishDate.DateTime).FirstOrDefault(); return Project(feedItem); } public virtual WisdomBit GenerateRandomBitOfWisdom() { IEnumerable bitsOfWisdom = Feed.Items; if (!string.IsNullOrEmpty(_category)) bitsOfWisdom = bitsOfWisdom.Where(x => x.Categories.Select(cat => cat.Name).Contains(_category)); int feedItemIndex = _randomizer.Next(0, bitsOfWisdom.Count()); SyndicationItem feedItem = bitsOfWisdom.Skip(feedItemIndex).FirstOrDefault(); return Project(feedItem); } public WisdomBit GetSpecificBitOfWisdom(string identifier) { SyndicationItem bitOfWisdom = Feed.Items.FirstOrDefault(x => GetUri(x).AbsoluteUri.Equals(identifier, StringComparison.OrdinalIgnoreCase)); if(bitOfWisdom == null) throw new ApplicationException("Couldn't locate identifier " + identifier); return Project(bitOfWisdom); } protected static WisdomBit Project(SyndicationItem feedItem) { if(feedItem == null) return null; return new WisdomBit() { CreateDate = feedItem.PublishDate.Date, Author = GetAuthor(feedItem), Title = feedItem.Title.Text, Summary = GetSummary(feedItem), Content = GetContent(feedItem), Uri = GetUri(feedItem) }; } private static string GetSummary(SyndicationItem feedItem) { string summary = (feedItem.Summary ?? new TextSyndicationContent(string.Empty)).Text; if (!string.IsNullOrEmpty(summary) && summary.Length > MaxSummaryCharacterCount) summary = summary.Substring(0, MaxSummaryCharacterCount) + " [...]"; return summary; } private static string GetContent(SyndicationItem feedItem) { string content = GetExtensionElementValue(feedItem, "encoded"); if (string.IsNullOrEmpty(content)) content = feedItem.Summary.Text; return content; // return HttpUtility.HtmlDecode(content); } private static Uri GetUri(SyndicationItem feedItem) { Uri uri = null; string link = GetExtensionElementValue(feedItem, "origLink"); if (string.IsNullOrEmpty(link)) { var firstLink = feedItem.Links.FirstOrDefault(); if(firstLink != null) uri = firstLink.GetAbsoluteUri(); } else { uri = new Uri(link); } return uri; } private static string GetAuthor(SyndicationItem feedItem) { string author = GetExtensionElementValue(feedItem, "creator"); if (string.IsNullOrEmpty(author)) author = (feedItem.Authors.FirstOrDefault() ?? UnknownAuthor).Name; return author; } private static string GetExtensionElementValue(SyndicationItem feedItem, string elementName) { SyndicationElementExtension element = feedItem.ElementExtensions.FirstOrDefault(x => x.OuterName == elementName); if (element != null) return element.GetObject().Value; else return string.Empty; } protected virtual bool IsFeedStale() { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_feedLocation); using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) return response.LastModified > _feed.LastUpdatedTime; } private void LoadSyndicationFeed() { using (var feedReader = XmlReader.Create(_feedLocation)) { _feed = SyndicationFeed.Load(feedReader); } } } }