Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
svenvNL committed Aug 3, 2018
0 parents commit 88b47a9
Show file tree
Hide file tree
Showing 16 changed files with 299 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Nuget Packages and compiled files
**/bin
**/obj

# Jetbrains Rider files
.idea
21 changes: 21 additions & 0 deletions Reader.Parser.Tests/OpmlParserTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Collections.Generic;
using Reader.Parser.Opml;
using Xunit;

namespace Reader.Parser.Tests
{
public class OpmlParserTests
{
[Fact]
public void GetFeeds_ValidInpunt_ReturnAllFeeds()
{
// TODO: write proper unit tests
var parser = new Reader.Parser.Opml.Parser("<rss></rss>");

var expected = new List<OpmlSubscription>();
var actual = parser.GetFeeds();

Assert.Equal(expected, actual);
}
}
}
17 changes: 17 additions & 0 deletions Reader.Parser.Tests/Reader.Parser.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<IsPackable>false</IsPackable>
<AssemblyName>Reader.Parser.Tests</AssemblyName>
<RootNamespace>Reader.Parser.Tests</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Reader.Parser\Reader.Parser.csproj" />
</ItemGroup>
</Project>
12 changes: 12 additions & 0 deletions Reader.Parser/Feed/Entry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace Reader.Parser.Feed
{
public class Entry
{
public string Title { get; set; }
public string Link { get; set; }
public string Description { get; set; }
public DateTime PubDate { get; set; }
}
}
21 changes: 21 additions & 0 deletions Reader.Parser/Feed/FeedParserFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Reader.Parser.Feed.Rss;

namespace Reader.Parser.Feed
{
public static class FeedParserFactory
{

public static IFeedParser GetParser(FeedType type)
{
switch (type)
{
case FeedType.Rss:
return new RssParser();
case FeedType.Atom:
return null;
default:
return null;
}
}
}
}
8 changes: 8 additions & 0 deletions Reader.Parser/Feed/FeedType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Reader.Parser.Feed
{
public enum FeedType
{
Rss,
Atom
}
}
11 changes: 11 additions & 0 deletions Reader.Parser/Feed/IFeedParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Collections.Generic;

namespace Reader.Parser.Feed
{
public interface IFeedParser
{
void Load(string feed);

List<Entry> GetEntries();
}
}
32 changes: 32 additions & 0 deletions Reader.Parser/Feed/Rss/RssParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace Reader.Parser.Feed.Rss
{
public class RssParser : IFeedParser
{
private XElement _document;

public void Load(string feed)
{
_document = XElement.Parse(feed);
}

public List<Entry> GetEntries()
{
var elements = _document.Elements();
var channel = elements.Where(node => node.Name == "channel");
var entries = channel.Elements().Where(node => node.Name == "item");
return entries.Select(entry => new Entry
{
Title = entry.Elements().First(node => node.Name == "title").Value,
Description = entry.Elements().First(node => node.Name == "description").Value,
Link = entry.Elements().First(node => node.Name == "link").Value,
PubDate = Convert.ToDateTime(entry.Elements().First(node => node.Name == "pubDate").Value)
})
.ToList();
}
}
}
12 changes: 12 additions & 0 deletions Reader.Parser/Opml/OpmlSubscription.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Reader.Parser.Feed;

namespace Reader.Parser.Opml
{
public class OpmlSubscription
{
public string Name { get; set; }
public string XMlUrl { get; set; }
public string HtmlUrl { get; set; }
public FeedType Type { get; set; }
}
}
35 changes: 35 additions & 0 deletions Reader.Parser/Opml/Parser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Reader.Parser.Feed;

namespace Reader.Parser.Opml
{
public class Parser
{
private readonly XElement _document;

public Parser(string opml)
{
_document = XElement.Parse(opml);
}

public List<OpmlSubscription> GetFeeds()
{
var elements = _document.Elements();
var body = elements.Where(node => node.Name == "body");
var categories = body.Elements().Where(node => node.Name == "outline" && node.HasElements);
var feeds = categories.Elements()
.Where(feed => feed.Name == "outline" && (string) feed.Attribute("type") == "rss");

return feeds.Select(feed => new OpmlSubscription
{
Name = feed.Attribute("title")?.Value,
HtmlUrl = feed.Attribute("htmlUrl")?.Value,
XMlUrl = feed.Attribute("xmlUrl")?.Value,
Type = FeedType.Rss
})
.ToList();
}
}
}
8 changes: 8 additions & 0 deletions Reader.Parser/Reader.Parser.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.3</TargetFramework>
<LangVersion>7.2</LangVersion>
<AssemblyName>Reader.Parser</AssemblyName>
<RootNamespace>Reader.Parser</RootNamespace>
</PropertyGroup>
</Project>
28 changes: 28 additions & 0 deletions Reader.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reader", "Reader\Reader.csproj", "{8AE72769-0EEF-42FB-AF4A-37C4FE5BCE36}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reader.Parser", "Reader.Parser\Reader.Parser.csproj", "{D48C357E-29DC-457B-967F-34BFB1C66408}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reader.Parser.Tests", "Reader.Parser.Tests\Reader.Parser.Tests.csproj", "{FD30BA95-C3DD-483E-9F98-9AEAC809DF32}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8AE72769-0EEF-42FB-AF4A-37C4FE5BCE36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8AE72769-0EEF-42FB-AF4A-37C4FE5BCE36}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8AE72769-0EEF-42FB-AF4A-37C4FE5BCE36}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8AE72769-0EEF-42FB-AF4A-37C4FE5BCE36}.Release|Any CPU.Build.0 = Release|Any CPU
{D48C357E-29DC-457B-967F-34BFB1C66408}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D48C357E-29DC-457B-967F-34BFB1C66408}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D48C357E-29DC-457B-967F-34BFB1C66408}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D48C357E-29DC-457B-967F-34BFB1C66408}.Release|Any CPU.Build.0 = Release|Any CPU
{FD30BA95-C3DD-483E-9F98-9AEAC809DF32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD30BA95-C3DD-483E-9F98-9AEAC809DF32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD30BA95-C3DD-483E-9F98-9AEAC809DF32}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD30BA95-C3DD-483E-9F98-9AEAC809DF32}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
14 changes: 14 additions & 0 deletions Reader/HttpClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;

namespace Reader
{
public static class HttpClient
{
private static System.Net.Http.HttpClient _instance;

public static System.Net.Http.HttpClient GetInstance()
{
return _instance ?? (_instance = new System.Net.Http.HttpClient());
}
}
}
26 changes: 26 additions & 0 deletions Reader/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Linq;
using System.Threading.Tasks;

namespace Reader
{
class Program
{
static async Task Main(string[] args)
{
var data = System.IO.File.ReadAllText("feed.xml");

var opmlParser = new Parser.Opml.Parser(data);
var feeds = opmlParser.GetFeeds();

var subscription = new Subscription();
var entries = await subscription.GetEntriesAsync(feeds);

foreach (var entry in entries.OrderByDescending(entry => entry.PubDate))
{
Console.WriteLine(
$"{entry.PubDate.ToLocalTime().ToShortDateString()} {entry.PubDate.ToLocalTime().ToShortTimeString()} - {entry.Title} {entry.Link}");
}
}
}
}
12 changes: 12 additions & 0 deletions Reader/Reader.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<LangVersion>7.2</LangVersion>
<AssemblyName>Reader</AssemblyName>
<RootNamespace>Reader</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Reader.Parser\Reader.Parser.csproj" />
</ItemGroup>
</Project>
36 changes: 36 additions & 0 deletions Reader/Subscription.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Reader.Parser.Feed;
using Reader.Parser.Opml;

namespace Reader
{
public class Subscription
{
public async Task<List<Entry>> GetEntriesAsync(List<OpmlSubscription> subscriptions)
{
var entries = new List<Entry>();
foreach (var feed in subscriptions)
{
try
{
var client = HttpClient.GetInstance();
var feedData = await client.GetAsync(feed.XMlUrl);
var body = await feedData.Content.ReadAsStringAsync();

var parser = FeedParserFactory.GetParser(feed.Type);
parser.Load(body);

parser.GetEntries().ForEach(entry => { entries.Add(entry); });
}
catch (Exception)
{
// ignored
}
}

return entries;
}
}
}

0 comments on commit 88b47a9

Please sign in to comment.