protected override async Task <IEnumerable <IDocument> > ExecuteInputAsync(IDocument input, IExecutionContext context) { string feed = input.GetString("Feed"); if (!string.IsNullOrEmpty(feed)) { try { // Download the feed context.LogInformation($"Getting feed for {feed}"); Uri website = null; string title = null; string author = null; string description = null; string image = null; List <ISyndicationItem> items = new List <ISyndicationItem>(); using (HttpClient httpClient = context.CreateHttpClient()) { httpClient.DefaultRequestHeaders.Add("User-Agent", "Wyam"); var response = await httpClient.GetAsync(feed); if (response.StatusCode == HttpStatusCode.Redirect || response.StatusCode == HttpStatusCode.MovedPermanently) { context.LogWarning($"Attempting to follow redirect for {feed}"); feed = response.Headers.Location.OriginalString; response = await httpClient.GetAsync(feed); } if (response.IsSuccessStatusCode) { using (Stream stream = await response.Content.ReadAsStreamAsync()) using (StreamReader streamReader = new XmlStreamReader(stream)) using (XmlReader xmlReader = XmlReader.Create(streamReader, new XmlReaderSettings { Async = true, DtdProcessing = DtdProcessing.Ignore })) { xmlReader.MoveToContent(); bool atom = xmlReader.Name == "feed"; context.LogInformation($"Reading {feed} as " + (atom ? "Atom" : "RSS")); XmlFeedReader feedReader = atom ? (XmlFeedReader) new AtomFeedReader(xmlReader, new FixedAtomParser()) : new RssFeedReader(xmlReader); while (await feedReader.Read()) { try { switch (feedReader.ElementType) { case SyndicationElementType.Person: ISyndicationPerson person = await feedReader.ReadPerson(); if (person.RelationshipType == "author") { author = person.Name ?? person.Email; } break; case SyndicationElementType.Image: ISyndicationImage img = await feedReader.ReadImage(); image = img.Url.ToString(); break; case SyndicationElementType.Link: ISyndicationLink link = await feedReader.ReadLink(); website = link.Uri; break; case SyndicationElementType.Item: ISyndicationItem item = await feedReader.ReadItem(); items.Add(item); break; case SyndicationElementType.None: break; default: ISyndicationContent content = await feedReader.ReadContent(); if (string.Equals(content.Name, "title", StringComparison.OrdinalIgnoreCase)) { title = content.Value; } else if (string.Equals(content.Name, "description", StringComparison.OrdinalIgnoreCase) || string.Equals(content.Name, "subtitle", StringComparison.OrdinalIgnoreCase)) { description = content.Value; } break; } } catch (Exception ex) { context.LogWarning($"Exception while processing {feedReader.ElementType} in {feed}: {ex.Message}"); } } } } // Get a new document with feed metadata MetadataItems metadata = new MetadataItems(); if (items.Count > 0) { BlogFeedItem[] feedItems = items .Select(x => new BlogFeedItem(x, _recent, website)) .OrderByDescending(x => x.Published) .Take(50) // Only take the 50 most recent items .ToArray(); metadata.Add(SiteKeys.BlogFeedItems, feedItems); return(input.Clone(metadata).Yield()); } } } catch (Exception ex) { context.LogWarning($"Error getting feed for {feed}: {ex.Message}"); } } else { var speaker = input.GetString("Title"); if (!string.IsNullOrWhiteSpace(speaker)) { context.LogWarning($"No RSS specified for {speaker}."); } else { context.LogWarning($"No RSS specified for unknown speaker."); } } return(input.Yield()); }
protected override async Task <IEnumerable <IDocument> > ExecuteInputAsync(IDocument input, IExecutionContext context) { // Don't get data if we're just validating if (context.Settings.GetBool(SiteKeys.Validate)) { return(null); } string feed = input.GetString(SiteKeys.Feed); if (!string.IsNullOrEmpty(feed)) { try { // Download the feed context.LogInformation($"Getting feed for {feed}"); Uri website = null; string title = null; string author = null; string description = null; string image = null; List <ISyndicationItem> items = new List <ISyndicationItem>(); using (HttpClient httpClient = context.CreateHttpClient()) { httpClient.DefaultRequestHeaders.Add("User-Agent", nameof(Statiq)); using (Stream stream = await httpClient.GetStreamAsync(feed)) { using (StreamReader streamReader = new XmlStreamReader(stream)) { using (XmlReader xmlReader = XmlReader.Create(streamReader, new XmlReaderSettings { Async = true, DtdProcessing = DtdProcessing.Ignore })) { xmlReader.MoveToContent(); bool atom = xmlReader.Name == "feed"; context.LogInformation($"Reading {feed} as " + (atom ? "Atom" : "RSS")); XmlFeedReader feedReader = atom ? (XmlFeedReader) new AtomFeedReader(xmlReader, new DiscoverAtomParser()) : new RssFeedReader(xmlReader); while (await feedReader.Read()) { try { switch (feedReader.ElementType) { case SyndicationElementType.Person: ISyndicationPerson person = await feedReader.ReadPerson(); if (person.RelationshipType == "author") { author = person.Name ?? person.Email; } break; case SyndicationElementType.Image: ISyndicationImage img = await feedReader.ReadImage(); image = img.Url.ToString(); break; case SyndicationElementType.Link: ISyndicationLink link = await feedReader.ReadLink(); website = link.Uri; break; case SyndicationElementType.Item: ISyndicationItem item = await feedReader.ReadItem(); items.Add(item); break; case SyndicationElementType.None: break; default: ISyndicationContent content = await feedReader.ReadContent(); if (string.Equals(content.Name, "title", StringComparison.OrdinalIgnoreCase)) { title = content.Value; } else if (string.Equals(content.Name, "description", StringComparison.OrdinalIgnoreCase) || string.Equals(content.Name, "subtitle", StringComparison.OrdinalIgnoreCase)) { description = content.Value; } break; } } catch (Exception ex) { context.LogWarning($"Exception while processing {feedReader.ElementType} in {feed}: {ex.Message}"); } } } } } } // Get a new document with feed metadata MetadataItems metadata = new MetadataItems(); if (items.Count > 0) { FeedItem[] feedItems = items .Select(x => new FeedItem(x, _recent, website, _truncateDescription, context)) .OrderByDescending(x => x.Published) .Take(50) // Only take the 50 most recent items .ToArray(); metadata.Add(SiteKeys.FeedItems, feedItems); metadata.Add(SiteKeys.LastPublished, feedItems.First().Published); metadata.Add(SiteKeys.NewestFeedItem, feedItems[0]); } if (!input.ContainsKey(SiteKeys.Website) && website != null) { metadata.Add(SiteKeys.Website, website.ToString()); } if (!input.ContainsKey(SiteKeys.Title)) { if (!string.IsNullOrEmpty(title)) { metadata.Add(SiteKeys.Title, title); } else { string generatedTitle = GenerateTitleFromFeedName(feed); metadata.Add(SiteKeys.Title, generatedTitle); } } if (!input.ContainsKey(SiteKeys.Author) && !string.IsNullOrEmpty(author)) { metadata.Add(SiteKeys.Author, author); } if (!input.ContainsKey(SiteKeys.Description) && !string.IsNullOrEmpty(description)) { metadata.Add(SiteKeys.Description, description); } if (!input.ContainsKey(SiteKeys.Image) && !string.IsNullOrEmpty(image)) { metadata.Add(SiteKeys.Image, image); } return(input.Clone(metadata).Yield()); } catch (Exception ex) { context.LogWarning($"Error getting feed for {feed}: {ex.Message}"); } } // Return null so this feed is not included return(null); }