Skip to content

Commit

Permalink
Merge pull request #4 from jonsagara/feature/itunes
Browse files Browse the repository at this point in the history
Update iTunes code to match Apple Podcasts RSS requirements
  • Loading branch information
jonsagara committed Jan 10, 2024
2 parents c350a8c + 187c591 commit 288d529
Show file tree
Hide file tree
Showing 65 changed files with 968 additions and 735 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<Nullable>enable</Nullable>

<!-- NuGet -->
<Version>1.0.0-alpha1</Version>
<Version>1.0.0-alpha2</Version>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<Authors>Armin Reiter; Jon Sagara</Authors>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ public void GlobalCleanup()
}


[Benchmark(Baseline = true)]
public async Task GetEncodingFromXDocument()
{
_xDocumentStream.Position = 0L;
await FeedParser.GetFeedFromStreamAsync_EncodingFromXDocument(_xDocumentStream);
}
// 2024-01-06: This method no longer exists.
//[Benchmark(Baseline = true)]
//public async Task GetEncodingFromXDocument()
//{
// _xDocumentStream.Position = 0L;
// await FeedParser.GetFeedFromStreamAsync_EncodingFromXDocument(_xDocumentStream);
//}

// This performs better when the encoding is NOT UTF-8 because it doesn't have to call
// XDocument.Parse twice. However, it performs worse in the common case where the encoding
Expand Down
2 changes: 1 addition & 1 deletion src/Sagara.FeedReader.ConsoleSample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
feedUrl = feedUrlsFromPage.ElementAt(index).Url;
}

var feed = await feedReaderSvc.ReadAsync(feedUrl);
var feed = await feedReaderSvc.ReadFromUrlAsync(feedUrl);

foreach (var item in feed.Items)
{
Expand Down
38 changes: 19 additions & 19 deletions src/Sagara.FeedReader.Tests.Integration/FeedReaderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public async Task TestDownload400BadRequest()
public async Task TestAcceptHeaderForbiddenWithParsing()
{
// results in 403 Forbidden if webclient does not have the accept header set
var feed = await _feedReaderSvc.ReadAsync("http://www.girlsguidetopm.com/feed/");
var feed = await _feedReaderSvc.ReadFromUrlAsync("http://www.girlsguidetopm.com/feed/");
string? title = feed.Title;
Assert.True(feed.Items.Count > 2);
Assert.True(!string.IsNullOrEmpty(title));
Expand Down Expand Up @@ -121,15 +121,15 @@ public async Task TestParseAndAbsoluteUrlDerStandard1()
[Fact]
public async Task TestReadAdobeFeed()
{
var feed = await _feedReaderSvc.ReadAsync("https://blog.adobe.com/feed.xml");
var feed = await _feedReaderSvc.ReadFromUrlAsync("https://blog.adobe.com/feed.xml");
string? title = feed.Title;
Assert.Equal("Adobe Blog", title);
}

[Fact]
public async Task TestReadSimpleFeed()
{
var feed = await _feedReaderSvc.ReadAsync("https://arminreiter.com/feed");
var feed = await _feedReaderSvc.ReadFromUrlAsync("https://arminreiter.com/feed");
string? title = feed.Title;
Assert.Equal("arminreiter.com", title);
Assert.Equal(10, feed.Items.Count());
Expand All @@ -148,7 +148,7 @@ public async Task TestReadSimpleFeed()
[Fact]
public async Task TestReadRss10GermanFeed()
{
var feed = await _feedReaderSvc.ReadAsync("http://rss.orf.at/news.xml");
var feed = await _feedReaderSvc.ReadFromUrlAsync("http://rss.orf.at/news.xml");
string? title = feed.Title;
Assert.Equal("news.ORF.at", title);
Assert.True(feed.Items.Count > 10);
Expand All @@ -157,7 +157,7 @@ public async Task TestReadRss10GermanFeed()
[Fact]
public async Task TestReadAtomFeedHeise()
{
var feed = await _feedReaderSvc.ReadAsync("https://www.heise.de/newsticker/heise-atom.xml");
var feed = await _feedReaderSvc.ReadFromUrlAsync("https://www.heise.de/newsticker/heise-atom.xml");
Assert.True(!string.IsNullOrEmpty(feed.Title));
Assert.True(feed.Items.Count > 1);
}
Expand All @@ -167,7 +167,7 @@ public async Task TestReadAtomFeedGitHub()
{
try
{
var feed = await _feedReaderSvc.ReadAsync("http://github.com/codehollow/AzureBillingRateCardSample/commits/master.atom");
var feed = await _feedReaderSvc.ReadFromUrlAsync("http://github.com/codehollow/AzureBillingRateCardSample/commits/master.atom");
//Assert.True(!string.IsNullOrEmpty(feed.Title));
}
catch (Exception ex)
Expand All @@ -181,22 +181,22 @@ public async Task TestReadAtomFeedGitHub()
[Fact]
public async Task TestReadRss20GermanFeedPowershell()
{
var feed = await _feedReaderSvc.ReadAsync("http://www.powershell.co.at/feed/");
var feed = await _feedReaderSvc.ReadFromUrlAsync("http://www.powershell.co.at/feed/");
Assert.True(!string.IsNullOrEmpty(feed.Title));
Assert.True(feed.Items.Count > 0);
}

[Fact]
public async Task TestReadRss20FeedCharter97Handle403Forbidden()
{
var feed = await _feedReaderSvc.ReadAsync("charter97.org/rss.php");
var feed = await _feedReaderSvc.ReadFromUrlAsync("charter97.org/rss.php");
Assert.True(!string.IsNullOrEmpty(feed.Title));
}

[Fact]
public async Task TestReadRssScottHanselmanWeb()
{
var feed = await _feedReaderSvc.ReadAsync("http://feeds.hanselman.com/ScottHanselman");
var feed = await _feedReaderSvc.ReadFromUrlAsync("http://feeds.hanselman.com/ScottHanselman");
Assert.True(!string.IsNullOrEmpty(feed.Title));
Assert.True(feed.Items.Count > 0);
}
Expand All @@ -210,55 +210,55 @@ public async Task TestReadBuildAzure()
[Fact]
public async Task TestReadNoticiasCatolicas()
{
var feed = await _feedReaderSvc.ReadAsync("feeds.feedburner.com/NoticiasCatolicasAleteia");
var feed = await _feedReaderSvc.ReadFromUrlAsync("feeds.feedburner.com/NoticiasCatolicasAleteia");
Assert.Equal("Noticias Catolicas", feed.Title);
Assert.True(feed.Items.Count > 0);
}

[Fact]
public async Task TestReadTimeDoctor()
{
var feed = await _feedReaderSvc.ReadAsync("https://www.timedoctor.com/blog/feed/");
var feed = await _feedReaderSvc.ReadFromUrlAsync("https://www.timedoctor.com/blog/feed/");
Assert.Equal("Time Doctor Blog", feed.Title);
Assert.True(feed.Items.Count > 0);
}

[Fact]
public async Task TestReadMikeC()
{
var feed = await _feedReaderSvc.ReadAsync("https://mikeclayton.wordpress.com/feed/");
var feed = await _feedReaderSvc.ReadFromUrlAsync("https://mikeclayton.wordpress.com/feed/");
Assert.Equal("Shift Happens!", feed.Title);
Assert.True(feed.Items.Count > 0);
}

[Fact]
public async Task TestReadTheLPM()
{
var feed = await _feedReaderSvc.ReadAsync("https://thelazyprojectmanager.wordpress.com/feed/");
var feed = await _feedReaderSvc.ReadFromUrlAsync("https://thelazyprojectmanager.wordpress.com/feed/");
Assert.Equal("The Lazy Project Manager's Blog", feed.Title);
Assert.True(feed.Items.Count > 0);
}

[Fact]
public async Task TestReadTechRep()
{
var feed = await _feedReaderSvc.ReadAsync("https://www.techrepublic.com/rssfeeds/topic/project-management/");
var feed = await _feedReaderSvc.ReadFromUrlAsync("https://www.techrepublic.com/rssfeeds/topic/project-management/");
Assert.Equal("Project Management Articles & Tutorials | TechRepublic", feed.Title);
Assert.True(feed.Items.Count > 0);
}

[Fact]
public async Task TestReadAPOD()
{
var feed = await _feedReaderSvc.ReadAsync("https://apod.nasa.gov/apod.rss");
var feed = await _feedReaderSvc.ReadFromUrlAsync("https://apod.nasa.gov/apod.rss");
Assert.Equal("APOD", feed.Title);
Assert.True(feed.Items.Count > 0);
}

[Fact]
public async Task TestReadThaqafnafsak()
{
var feed = await _feedReaderSvc.ReadAsync("http://www.thaqafnafsak.com/feed");
var feed = await _feedReaderSvc.ReadFromUrlAsync("http://www.thaqafnafsak.com/feed");
Assert.Equal("ثقف نفسك", feed.Title);
Assert.True(feed.Items.Count > 0);
}
Expand All @@ -275,22 +275,22 @@ public async Task TestReadThaqafnafsak()
[Fact]
public async Task TestReadLiveBold()
{
var feed = await _feedReaderSvc.ReadAsync("http://feeds.feedburner.com/LiveBoldAndBloom");
var feed = await _feedReaderSvc.ReadFromUrlAsync("http://feeds.feedburner.com/LiveBoldAndBloom");
Assert.Equal("Live Bold and Bloom", feed.Title);
Assert.True(feed.Items.Count > 0);
}

[Fact]
public async Task TestSwedish_ISO8859_1()
{
var feed = await _feedReaderSvc.ReadAsync("https://www.retriever-info.com/feed/2004645/intranet30/index.xml");
var feed = await _feedReaderSvc.ReadFromUrlAsync("https://www.retriever-info.com/feed/2004645/intranet30/index.xml");
Assert.Equal("intranet30", feed.Title);
}

[Fact]
public async Task TestStadtfeuerwehrWeiz_ISO8859_1()
{
var feed = await _feedReaderSvc.ReadAsync("http://www.stadtfeuerwehr-weiz.at/rss/einsaetze.xml");
var feed = await _feedReaderSvc.ReadFromUrlAsync("http://www.stadtfeuerwehr-weiz.at/rss/einsaetze.xml");
Assert.Equal("Stadtfeuerwehr Weiz - Einsätze", feed.Title);
}
#endregion
Expand Down
10 changes: 5 additions & 5 deletions src/Sagara.FeedReader.Tests.Unit/FullParseTest.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Sagara.FeedReader.Feeds;
using Sagara.FeedReader.Feeds.Itunes;
using Sagara.FeedReader.Http;
using Sagara.FeedReader.Modules.ApplePodcasts;
using Sagara.FeedReader.Tests.Unit.Fixtures;
using Xunit;

Expand Down Expand Up @@ -387,7 +387,7 @@ public async Task TestAllFilesForException_Async()
Assert.True(!string.IsNullOrEmpty(feed.Link));
}

TestItunesParsingForException(feed);
TestApplePodastsParsingForException(feed);
}
}
}
Expand All @@ -397,13 +397,13 @@ public async Task TestAllFilesForException_Async()
// Private methods
//

private static void TestItunesParsingForException(Feed feed)
private static void TestApplePodastsParsingForException(Feed feed)
{
Assert.NotNull(feed.GetItunesChannel());
Assert.NotNull(feed.GetiTunesChannel());

foreach (var item in feed.Items)
{
Assert.NotNull(item.GetItunesItem());
Assert.NotNull(item.GetiTunesItem());
}
}
}
41 changes: 13 additions & 28 deletions src/Sagara.FeedReader.Tests.Unit/ItunesTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using Sagara.FeedReader.Feeds.Itunes;
using Sagara.FeedReader.Http;
using Sagara.FeedReader.Modules.ApplePodcasts;
using Sagara.FeedReader.Tests.Unit.Fixtures;
using Xunit;

Expand Down Expand Up @@ -32,11 +32,9 @@ public async Task TestItunesSampleFeed_Async()
{
var feed = await FeedReader.ReadFromFileAsync("Feeds/Rss20ItunesSample.xml");

var itunesChannel = feed.GetItunesChannel();
var itunesChannel = feed.GetiTunesChannel();

Assert.Equal("A show about everything", itunesChannel.Subtitle);
Assert.Equal("John Doe", itunesChannel.Author);
Assert.Equal("All About Everything is a show about everything. Each week we dive into any subject known to man and talk about it as much as we can. Look for our podcast in the Podcasts app or in the iTunes Store", itunesChannel.Summary);

Assert.NotNull(itunesChannel.Owner);
Assert.Equal("John Doe", itunesChannel.Owner!.Name);
Expand All @@ -46,55 +44,42 @@ public async Task TestItunesSampleFeed_Async()
Assert.NotNull(itunesChannel.Categories);

var itunesChannelCategories = itunesChannel.Categories.ToArray();
Assert.Equal("Technology", itunesChannelCategories[0].Text);
Assert.NotNull(itunesChannelCategories[0].Children);
Assert.Equal("Gadgets", itunesChannelCategories[0].Children.First().Text);
Assert.Equal("TV & Film", itunesChannelCategories[1].Text);
Assert.Equal("Arts", itunesChannelCategories[2].Text);
Assert.NotNull(itunesChannelCategories[2].Children);
Assert.Equal("Food", itunesChannelCategories[2].Children.First().Text);
Assert.Equal("Technology", itunesChannelCategories[0].CategoryText);
Assert.NotNull(itunesChannelCategories[0].SubcategoryText);
Assert.Equal("Gadgets", itunesChannelCategories[0].SubcategoryText);
Assert.Equal("TV & Film", itunesChannelCategories[1].CategoryText);
Assert.Equal("Arts", itunesChannelCategories[2].CategoryText);
Assert.NotNull(itunesChannelCategories[2].SubcategoryText);
Assert.Equal("Food", itunesChannelCategories[2].SubcategoryText);
Assert.False(itunesChannel.Explicit);


var item1 = feed.Items.ElementAt(0).GetItunesItem();
var item2 = feed.Items.ElementAt(1).GetItunesItem();
var item3 = feed.Items.ElementAt(2).GetItunesItem();
var item4 = feed.Items.ElementAt(3).GetItunesItem();
var item1 = feed.Items.ElementAt(0).GetiTunesItem();
var item2 = feed.Items.ElementAt(1).GetiTunesItem();
var item3 = feed.Items.ElementAt(2).GetiTunesItem();
var item4 = feed.Items.ElementAt(3).GetiTunesItem();

Assert.Equal("John Doe", item1.Author!);
Assert.Equal("A short primer on table spices", item1.Subtitle!);
Assert.Equal("This week we talk about <a href=\"https://itunes/apple.com/us/book/antique-trader-salt-pepper/id429691295?mt=11\">salt and pepper shakers</a>, comparing and contrasting pour rates, construction materials, and overall aesthetics. Come and join the party!", item1.Summary!);
Assert.NotNull(item1.Image);
Assert.Equal("http://example.com/podcasts/everything/AllAboutEverything/Episode1.jpg", item1.Image!.Href);
Assert.NotNull(item1.Duration);
Assert.Equal(4, item1.Duration!.Value.Seconds);
Assert.Equal(7, item1.Duration.Value.Minutes);
Assert.False(item1.Explicit);

Assert.Equal("Jane Doe", item2.Author!);
Assert.Equal("Comparing socket wrenches is fun!", item2.Subtitle!);
Assert.Equal("This week we talk about metric vs. Old English socket wrenches. Which one is better? Do you really need both? Get all of your answers here.", item2.Summary!);
Assert.NotNull(item2.Image);
Assert.Equal("http://example.com/podcasts/everything/AllAboutEverything/Episode2.jpg", item2.Image!.Href);
Assert.NotNull(item2.Duration);
Assert.Equal(34, item2.Duration!.Value.Seconds);
Assert.Equal(4, item2.Duration.Value.Minutes);
Assert.False(item2.Explicit);

Assert.Equal("Jane Doe", item3.Author!);
Assert.Equal("Jane and Eric", item3.Subtitle!);
Assert.Equal("This week we talk about the best Chili in the world. Which chili is better?", item3.Summary!);
Assert.NotNull(item3.Image);
Assert.Equal("http://example.com/podcasts/everything/AllAboutEverything/Episode3.jpg", item3.Image!.Href);
Assert.NotNull(item3.Duration);
Assert.Equal(34, item3.Duration!.Value.Seconds);
Assert.Equal(4, item3.Duration.Value.Minutes);
Assert.False(item3.Explicit);
Assert.True(item3.IsClosedCaptioned);

Assert.Equal("Various", item4.Author!);
Assert.Equal("Red + Blue != Purple", item4.Subtitle!);
Assert.Equal("This week we talk about surviving in a Red state if you are a Blue person. Or vice versa.", item4.Summary!);
Assert.NotNull(item4.Image);
Assert.Equal("http://example.com/podcasts/everything/AllAboutEverything/Episode4.jpg", item4.Image!.Href);
Assert.NotNull(item4.Duration);
Expand Down
21 changes: 21 additions & 0 deletions src/Sagara.FeedReader/Extensions/XDocumentExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Xml.Linq;

namespace Sagara.FeedReader.Extensions;

internal static class XDocumentExtensions
{
/// <summary>
/// Try to load an &quot;xmlns&quot; XML namespace declaration attribute from the root element.
/// </summary>
/// <param name="doc">The xml document.</param>
/// <param name="localName">The local name of the namespace declaration. For example, for attribute &quot;xmlns:itunes&quot;,
/// pass &quot;itunes&quot;.</param>
/// <returns>An XAttribute describing the namespace if found; otherwise, null.</returns>
internal static XAttribute? GetRootNamespaceDeclarationAttribute(this XDocument doc, string localName)
{
ArgumentNullException.ThrowIfNull(doc);
ArgumentException.ThrowIfNullOrWhiteSpace(localName);

return doc.Root!.Attribute(XName.Get(localName, XNamespace.Xmlns.NamespaceName));
}
}
Loading

0 comments on commit 288d529

Please sign in to comment.