mirror of
https://github.com/mxpv/podsync.git
synced 2024-05-11 05:55:04 +00:00
Add contracts for generating RSS feeds
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml.Serialization;
|
||||
using Shared;
|
||||
|
||||
namespace Podsync.Services.Feed
|
||||
{
|
||||
public class Channel : IXmlSerializable
|
||||
{
|
||||
private const string PodsyncGeneratorName = "Podsync Generator";
|
||||
|
||||
public Channel()
|
||||
{
|
||||
Items = Enumerable.Empty<Item>();
|
||||
}
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public string Link { get; set; }
|
||||
|
||||
public DateTime LastBuildDate { get; set; }
|
||||
|
||||
public DateTime PubDate { get; set; }
|
||||
|
||||
public string Subtitle { get; set; }
|
||||
|
||||
public string Summary { get; set; }
|
||||
|
||||
public string Category { get; set; }
|
||||
|
||||
public string Image { get; set; }
|
||||
|
||||
public string Thumbnail { get; set; }
|
||||
|
||||
public IEnumerable<Item> Items { get; set; }
|
||||
|
||||
public XmlSchema GetSchema()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ReadXml(XmlReader reader)
|
||||
{
|
||||
throw new NotSupportedException("Reading is not supported");
|
||||
}
|
||||
|
||||
public void WriteXml(XmlWriter writer)
|
||||
{
|
||||
writer.WriteElementString("title", Title);
|
||||
writer.WriteElementString("description", Description);
|
||||
writer.WriteElementString("link", Link);
|
||||
|
||||
writer.WriteElementString("generator", PodsyncGeneratorName);
|
||||
|
||||
writer.WriteElementString("lastBuildDate", LastBuildDate.ToString("R"));
|
||||
writer.WriteElementString("pubDate", PubDate.ToString("R"));
|
||||
|
||||
/*
|
||||
<itunes:subtitle>Laugh Factory</itunes:subtitle>
|
||||
<itunes:summary>The best stand up comedy clips online. That's it.</itunes:summary>
|
||||
*/
|
||||
|
||||
writer.WriteElementString("subtitle", Namespaces.Itunes, Title);
|
||||
writer.WriteElementString("summary", Namespaces.Itunes, Summary);
|
||||
|
||||
/*
|
||||
<itunes:category text="TV & Film"/>
|
||||
*/
|
||||
|
||||
writer.WriteStartElement("category", Namespaces.Itunes);
|
||||
writer.WriteAttributeString("text", Category);
|
||||
writer.WriteEndElement();
|
||||
|
||||
/*
|
||||
<itunes:image href="https://yt3.ggpht.com/photo.jpg"/>
|
||||
*/
|
||||
|
||||
writer.WriteStartElement("image", Namespaces.Itunes);
|
||||
writer.WriteAttributeString("href", Image);
|
||||
writer.WriteEndElement();
|
||||
|
||||
/*
|
||||
<media:thumbnail url="https://yt3.ggpht.com//photo.jpg"/>
|
||||
*/
|
||||
|
||||
writer.WriteStartElement("thumbnail", Namespaces.Media);
|
||||
writer.WriteAttributeString("url", Thumbnail);
|
||||
writer.WriteEndElement();
|
||||
|
||||
// Items
|
||||
var serializer = new XmlSerializer(typeof(Item));
|
||||
Items.ForEach(item => serializer.Serialize(writer, item));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
|
||||
using System;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Podsync.Services.Feed
|
||||
{
|
||||
public class Item : IXmlSerializable
|
||||
{
|
||||
public string Title { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public string Author { get; set; }
|
||||
|
||||
public string Link { get; set; }
|
||||
|
||||
public DateTime PubDate { get; set; }
|
||||
|
||||
public string Summary { get; set; }
|
||||
|
||||
public TimeSpan Duration { get; set; }
|
||||
|
||||
public MediaContent Content { get; set; }
|
||||
|
||||
public XmlSchema GetSchema()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ReadXml(XmlReader reader)
|
||||
{
|
||||
throw new NotSupportedException("Reading is not supported");
|
||||
}
|
||||
|
||||
public void WriteXml(XmlWriter writer)
|
||||
{
|
||||
writer.WriteElementString("title", Title);
|
||||
writer.WriteElementString("description", Description);
|
||||
writer.WriteElementString("link", Link);
|
||||
writer.WriteElementString("pubDate", PubDate.ToString("R"));
|
||||
writer.WriteElementString("author", Author);
|
||||
|
||||
/*
|
||||
<guid isPermaLink="true">https://youtube.com/watch?v=yp202t46OIE</guid>
|
||||
*/
|
||||
|
||||
writer.WriteStartElement("guid");
|
||||
writer.WriteAttributeString("isPermaLink", "true");
|
||||
writer.WriteString(Link);
|
||||
writer.WriteEndElement();
|
||||
|
||||
/*
|
||||
<enclosure url="http://podsync.net/download/youtube/yp202t46OIE.mp4" length="48300000" type="video/mp4"/>
|
||||
*/
|
||||
|
||||
writer.WriteStartElement("enclosure");
|
||||
writer.WriteAttributeString("url", Content.Url);
|
||||
writer.WriteAttributeString("length", Content.Length.ToString());
|
||||
writer.WriteAttributeString("type", Content.MediaType);
|
||||
writer.WriteEndElement();
|
||||
|
||||
/*
|
||||
<media:content url="http://podsync.net/download/youtube/yp202t46OIE.mp4" fileSize="48300000" type="video/mp4"/>
|
||||
*/
|
||||
|
||||
writer.WriteStartElement("content", Namespaces.Media);
|
||||
writer.WriteAttributeString("url", Content.Url);
|
||||
writer.WriteAttributeString("fileSize", Content.Length.ToString());
|
||||
writer.WriteAttributeString("type", Content.MediaType);
|
||||
writer.WriteEndElement();
|
||||
|
||||
/*
|
||||
<itunes:subtitle>Mike E. Winfield - Cheating (Stand up comedy)</itunes:subtitle>
|
||||
<itunes:summary>...</itunes:summary>
|
||||
<itunes:duration>00:02:18</itunes:duration>
|
||||
*/
|
||||
|
||||
writer.WriteElementString("subtitle", Namespaces.Itunes, Title);
|
||||
writer.WriteElementString("summary", Namespaces.Itunes, Summary);
|
||||
writer.WriteElementString("duration", Namespaces.Itunes, Duration.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Podsync.Services.Feed
|
||||
{
|
||||
public struct MediaContent
|
||||
{
|
||||
public string Url { get; set; }
|
||||
|
||||
public long Length { get; set; }
|
||||
|
||||
public string MediaType { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Podsync.Services.Feed
|
||||
{
|
||||
public static class Namespaces
|
||||
{
|
||||
public const string Itunes = "http://www.itunes.com/dtds/podcast-1.0.dtd";
|
||||
|
||||
public const string Media = "http://search.yahoo.com/mrss/";
|
||||
|
||||
public const string Atom = "http://www.w3.org/2005/Atom";
|
||||
|
||||
public const string Content = "http://purl.org/rss/1.0/modules/content/";
|
||||
|
||||
public const string Dc = "http://purl.org/dc/elements/1.1/";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml.Serialization;
|
||||
using Shared;
|
||||
|
||||
namespace Podsync.Services.Feed
|
||||
{
|
||||
public class Rss : IXmlSerializable
|
||||
{
|
||||
public const string Version = "2.0";
|
||||
|
||||
public IEnumerable<Channel> Channels { get; set; }
|
||||
|
||||
public Rss()
|
||||
{
|
||||
Channels = Enumerable.Empty<Channel>();
|
||||
}
|
||||
|
||||
public XmlSchema GetSchema()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ReadXml(XmlReader reader)
|
||||
{
|
||||
throw new NotSupportedException("Reading is not supported");
|
||||
}
|
||||
|
||||
public void WriteXml(XmlWriter writer)
|
||||
{
|
||||
writer.WriteStartElement("rss");
|
||||
|
||||
writer.WriteAttributeString("xmlns", "dc", null, Namespaces.Dc);
|
||||
writer.WriteAttributeString("xmlns", "content", null, Namespaces.Content);
|
||||
writer.WriteAttributeString("xmlns", "atom", null, Namespaces.Atom);
|
||||
writer.WriteAttributeString("xmlns", "itunes", null, Namespaces.Itunes);
|
||||
writer.WriteAttributeString("xmlns", "media", null, Namespaces.Media);
|
||||
|
||||
writer.WriteAttributeString("version", Version);
|
||||
|
||||
var serializer = new XmlSerializer(typeof(Channel));
|
||||
Channels.ForEach(channel => serializer.Serialize(writer, channel));
|
||||
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
+68
-70
@@ -1,72 +1,70 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"Google.Apis.YouTube.v3": "1.16.0.582",
|
||||
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
|
||||
"Microsoft.AspNetCore.Mvc": "1.0.0",
|
||||
"Microsoft.AspNetCore.Razor.Tools": {
|
||||
"version": "1.0.0-preview2-final",
|
||||
"type": "build"
|
||||
},
|
||||
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
|
||||
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
|
||||
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
|
||||
"Microsoft.AspNetCore.WebUtilities": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.Json": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.UserSecrets": "1.0.0",
|
||||
"Microsoft.Extensions.Logging": "1.0.0",
|
||||
"Microsoft.Extensions.Logging.Console": "1.0.0",
|
||||
"Microsoft.Extensions.Logging.Debug": "1.0.0",
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0",
|
||||
"type": "platform"
|
||||
},
|
||||
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0"
|
||||
{
|
||||
"dependencies": {
|
||||
"Google.Apis.YouTube.v3": "1.16.0.582",
|
||||
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
|
||||
"Microsoft.AspNetCore.Mvc": "1.0.0",
|
||||
"Microsoft.AspNetCore.Razor.Tools": {
|
||||
"version": "1.0.0-preview2-final",
|
||||
"type": "build"
|
||||
},
|
||||
|
||||
"tools": {
|
||||
"BundlerMinifier.Core": "2.0.238",
|
||||
"Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
|
||||
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
|
||||
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
|
||||
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
|
||||
"Microsoft.AspNetCore.StaticFiles": "1.0.0",
|
||||
"Microsoft.AspNetCore.WebUtilities": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.Json": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.UserSecrets": "1.0.0",
|
||||
"Microsoft.Extensions.Logging": "1.0.0",
|
||||
"Microsoft.Extensions.Logging.Console": "1.0.0",
|
||||
"Microsoft.Extensions.Logging.Debug": "1.0.0",
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0",
|
||||
"type": "platform"
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"imports": [
|
||||
"dotnet5.6",
|
||||
"portable-net45+win8"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"buildOptions": {
|
||||
"emitEntryPoint": true,
|
||||
"preserveCompilationContext": true,
|
||||
|
||||
"compile": "..\\Shared\\*.cs"
|
||||
},
|
||||
|
||||
"runtimeOptions": {
|
||||
"configProperties": {
|
||||
"System.GC.Server": true
|
||||
}
|
||||
},
|
||||
|
||||
"publishOptions": {
|
||||
"include": [
|
||||
"wwwroot",
|
||||
"Views",
|
||||
"Areas/**/Views",
|
||||
"appsettings.json",
|
||||
"web.config"
|
||||
]
|
||||
},
|
||||
|
||||
"scripts": {
|
||||
"prepublish": [ "bower install", "dotnet bundle" ],
|
||||
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
|
||||
},
|
||||
|
||||
"userSecretsId": "aspnet-Podsync-20161004104901"
|
||||
}
|
||||
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
|
||||
"System.Xml.XmlSerializer": "4.0.11"
|
||||
},
|
||||
"tools": {
|
||||
"BundlerMinifier.Core": "2.0.238",
|
||||
"Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
|
||||
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
|
||||
},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"imports": [
|
||||
"dotnet5.6",
|
||||
"portable-net45+win8"
|
||||
]
|
||||
}
|
||||
},
|
||||
"buildOptions": {
|
||||
"emitEntryPoint": true,
|
||||
"preserveCompilationContext": true,
|
||||
"compile": "..\\Shared\\*.cs"
|
||||
},
|
||||
"runtimeOptions": {
|
||||
"configProperties": {
|
||||
"System.GC.Server": true
|
||||
}
|
||||
},
|
||||
"publishOptions": {
|
||||
"include": [
|
||||
"wwwroot",
|
||||
"Views",
|
||||
"Areas/**/Views",
|
||||
"appsettings.json",
|
||||
"web.config"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish": [
|
||||
"bower install",
|
||||
"dotnet bundle"
|
||||
],
|
||||
"postpublish": [
|
||||
"dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%"
|
||||
]
|
||||
},
|
||||
"userSecretsId": "aspnet-Podsync-20161004104901"
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Xml.Serialization;
|
||||
using Podsync.Services.Feed;
|
||||
using Xunit;
|
||||
|
||||
namespace Podsync.Tests.Services.Feed
|
||||
{
|
||||
public class FeedSerializationTests
|
||||
{
|
||||
private const string ImageUrl = "https://yt3.ggpht.com/-OOqFwHRjeMQ/AAAAAAAAAAI/AAAAAAAAAAA/0XQZ2NeGp_0/s88-c-k-no-mo-rj-c0xffffff/photo.jpg";
|
||||
|
||||
[Fact]
|
||||
public void SerializeFeedTest()
|
||||
{
|
||||
var feed = new Rss();
|
||||
|
||||
var item = new Item
|
||||
{
|
||||
Title = "Steve Gillespie - Getting Arrested (Stand up Comedy)",
|
||||
Link = "https://youtube.com/watch?v=Jj22gfTnpAI",
|
||||
PubDate = DateTime.Parse("Mon, 07 Nov 2016 20:02:26 GMT"),
|
||||
Content = new MediaContent
|
||||
{
|
||||
Url = "http://podsync.net/download/youtube/Jj22gfTnpAI.mp4",
|
||||
Length = 52850000,
|
||||
MediaType = "video/mp4"
|
||||
},
|
||||
Duration = new TimeSpan(0, 0, 2, 31)
|
||||
};
|
||||
|
||||
var channel = new Channel
|
||||
{
|
||||
Title = "Laugh Factory",
|
||||
Description = "The best stand up comedy clips online. That's it.",
|
||||
Link = "https://youtube.com/channel/UCxyCzPY2pjAjrxoSYclpuLg",
|
||||
LastBuildDate = DateTime.Parse("Tue, 08 Nov 2016 05:55:25 GMT"),
|
||||
PubDate = DateTime.Parse("Mon, 31 Jul 2006 22:18:05 GMT"),
|
||||
Subtitle = "Laugh Factory",
|
||||
Summary = "The best stand up comedy clips online. That's it.",
|
||||
Category = "TV & Film",
|
||||
Image = ImageUrl,
|
||||
Thumbnail = ImageUrl,
|
||||
|
||||
Items = new[]
|
||||
{
|
||||
item
|
||||
}
|
||||
};
|
||||
|
||||
feed.Channels = new[]
|
||||
{
|
||||
channel
|
||||
};
|
||||
|
||||
var serializer = new XmlSerializer(typeof(Rss));
|
||||
|
||||
string body;
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
serializer.Serialize(writer, feed);
|
||||
body = writer.ToString();
|
||||
}
|
||||
|
||||
Assert.NotEmpty(body);
|
||||
|
||||
// Channel tests
|
||||
|
||||
Assert.Contains("<title>Laugh Factory</title>", body);
|
||||
Assert.Contains("<description>The best stand up comedy clips online. That's it.</description>", body);
|
||||
Assert.Contains("<link>https://youtube.com/channel/UCxyCzPY2pjAjrxoSYclpuLg</link>", body);
|
||||
Assert.Contains("<generator>Podsync Generator</generator>", body);
|
||||
|
||||
Assert.Contains("<itunes:subtitle>Laugh Factory</itunes:subtitle>", body);
|
||||
Assert.Contains("<itunes:summary>The best stand up comedy clips online. That's it.</itunes:summary>", body);
|
||||
Assert.Contains("<itunes:category text=\"TV & Film\" />", body);
|
||||
Assert.Contains($"<itunes:image href=\"{ImageUrl}\" />", body);
|
||||
Assert.Contains($"<media:thumbnail url=\"{ImageUrl}\" />", body);
|
||||
|
||||
// Items tests
|
||||
Assert.Contains("<title>Steve Gillespie - Getting Arrested (Stand up Comedy)</title>", body);
|
||||
Assert.Contains("<itunes:subtitle>Steve Gillespie - Getting Arrested (Stand up Comedy)</itunes:subtitle>", body);
|
||||
|
||||
Assert.Contains("<link>https://youtube.com/watch?v=Jj22gfTnpAI</link>", body);
|
||||
Assert.Contains("<guid isPermaLink=\"true\">https://youtube.com/watch?v=Jj22gfTnpAI</guid>", body);
|
||||
|
||||
Assert.Contains("<itunes:duration>00:02:31</itunes:duration>", body);
|
||||
|
||||
Assert.Contains("<enclosure url=\"http://podsync.net/download/youtube/Jj22gfTnpAI.mp4\" length=\"52850000\" type=\"video/mp4\" />", body);
|
||||
Assert.Contains("<media:content url=\"http://podsync.net/download/youtube/Jj22gfTnpAI.mp4\" fileSize=\"52850000\" type=\"video/mp4\" />", body);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
},
|
||||
"Moq": "4.6.38-alpha",
|
||||
"Podsync": "1.0.0-*",
|
||||
"System.Xml.XmlSerializer": "4.0.11",
|
||||
"xunit": "2.2.0-beta2-build3300"
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user