diff --git a/src/Podsync/Controllers/FeedController.cs b/src/Podsync/Controllers/FeedController.cs index 337965a..0218237 100644 --- a/src/Podsync/Controllers/FeedController.cs +++ b/src/Podsync/Controllers/FeedController.cs @@ -10,7 +10,7 @@ using Podsync.Services; using Podsync.Services.Links; using Podsync.Services.Resolver; using Podsync.Services.Rss; -using Podsync.Services.Rss.Feed; +using Podsync.Services.Rss.Contracts; using Podsync.Services.Storage; using Shared; @@ -26,15 +26,13 @@ namespace Podsync.Controllers ["audio/mp4"] = "m4a" }; - private readonly IRssBuilder _rssBuilder; private readonly ILinkService _linkService; - private readonly IStorageService _storageService; + private readonly IFeedService _feedService; - public FeedController(IRssBuilder rssBuilder, ILinkService linkService, IStorageService storageService) + public FeedController(IRssBuilder rssBuilder, ILinkService linkService, IStorageService storageService, IFeedService feedService) { - _rssBuilder = rssBuilder; _linkService = linkService; - _storageService = storageService; + _feedService = feedService; } [HttpPost] @@ -44,11 +42,6 @@ namespace Podsync.Controllers { var linkInfo = _linkService.Parse(new Uri(request.Url)); - if (linkInfo.Provider != Provider.YouTube && request.Quality.HasValue && request.Quality.Value.IsAudio()) - { - throw new ArgumentException("Only YouTube supports audio feeds"); - } - var feed = new FeedMetadata { Provider = linkInfo.Provider, @@ -69,9 +62,7 @@ namespace Podsync.Controllers feed.Quality = ResolveFormat.VideoHigh; } - feed.PageSize = Constants.DefaultPageSize; - - var feedId = await _storageService.Save(feed); + var feedId = await _feedService.Create(feed); var url = _linkService.Feed(Request.GetBaseUrl(), feedId); return url; @@ -82,11 +73,11 @@ namespace Podsync.Controllers [ValidateModelState] public async Task Feed([Required] string feedId) { - Rss rss; + Feed feed; try { - rss = await _rssBuilder.Query(feedId); + feed = await _feedService.Get(feedId); } catch (KeyNotFoundException) { @@ -98,16 +89,16 @@ namespace Podsync.Controllers // Set atom link to this feed // See https://validator.w3.org/feed/docs/warning/MissingAtomSelfLink.html var selfLink = new Uri(selfHost, Request.Path); - rss.Channels.ForEach(x => x.AtomLink = selfLink); + feed.Channels.ForEach(x => x.AtomLink = selfLink); // No magic here, just make download links to DownloadController.Download - rss.Channels.SelectMany(x => x.Items).ForEach(item => + feed.Channels.SelectMany(x => x.Items).ForEach(item => { var ext = Extensions[item.ContentType]; item.DownloadLink = new Uri(selfHost, $"download/{feedId}/{item.Id}.{ext}"); }); - return Content(rss.ToString(), "application/rss+xml; charset=UTF-8"); + return Content(feed.ToString(), "application/rss+xml; charset=UTF-8"); } } } \ No newline at end of file diff --git a/src/Podsync/Services/Rss/CompositeRssBuilder.cs b/src/Podsync/Services/Rss/Builders/CompositeRssBuilder.cs similarity index 94% rename from src/Podsync/Services/Rss/CompositeRssBuilder.cs rename to src/Podsync/Services/Rss/Builders/CompositeRssBuilder.cs index 287c0ce..1ef41cf 100644 --- a/src/Podsync/Services/Rss/CompositeRssBuilder.cs +++ b/src/Podsync/Services/Rss/Builders/CompositeRssBuilder.cs @@ -9,7 +9,7 @@ using Podsync.Services.Links; using Podsync.Services.Storage; using Shared; -namespace Podsync.Services.Rss +namespace Podsync.Services.Rss.Builders { // ReSharper disable once ClassNeverInstantiated.Global public class CompositeRssBuilder : RssBuilderBase @@ -34,7 +34,7 @@ namespace Podsync.Services.Rss get { throw new NotSupportedException(); } } - public override Task Query(FeedMetadata feed) + public override Task Query(FeedMetadata feed) { try { diff --git a/src/Podsync/Services/Rss/RssBuilderBase.cs b/src/Podsync/Services/Rss/Builders/RssBuilderBase.cs similarity index 74% rename from src/Podsync/Services/Rss/RssBuilderBase.cs rename to src/Podsync/Services/Rss/Builders/RssBuilderBase.cs index 548119d..3ac6bbc 100644 --- a/src/Podsync/Services/Rss/RssBuilderBase.cs +++ b/src/Podsync/Services/Rss/Builders/RssBuilderBase.cs @@ -2,7 +2,7 @@ using Podsync.Services.Links; using Podsync.Services.Storage; -namespace Podsync.Services.Rss +namespace Podsync.Services.Rss.Builders { public abstract class RssBuilderBase : IRssBuilder { @@ -15,13 +15,13 @@ namespace Podsync.Services.Rss public abstract Provider Provider { get; } - public async Task Query(string feedId) + public async Task Query(string feedId) { var metadata = await _storageService.Load(feedId); return await Query(metadata); } - public abstract Task Query(FeedMetadata metadata); + public abstract Task Query(FeedMetadata metadata); } } \ No newline at end of file diff --git a/src/Podsync/Services/Rss/VimeoRssBuilder.cs b/src/Podsync/Services/Rss/Builders/VimeoRssBuilder.cs similarity index 94% rename from src/Podsync/Services/Rss/VimeoRssBuilder.cs rename to src/Podsync/Services/Rss/Builders/VimeoRssBuilder.cs index 928d0e0..6e33548 100644 --- a/src/Podsync/Services/Rss/VimeoRssBuilder.cs +++ b/src/Podsync/Services/Rss/Builders/VimeoRssBuilder.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Podsync.Services.Links; -using Podsync.Services.Rss.Feed; +using Podsync.Services.Rss.Contracts; using Podsync.Services.Storage; using Podsync.Services.Videos.Vimeo; -namespace Podsync.Services.Rss +namespace Podsync.Services.Rss.Builders { // ReSharper disable once ClassNeverInstantiated.Global public class VimeoRssBuilder : RssBuilderBase @@ -21,7 +21,7 @@ namespace Podsync.Services.Rss public override Provider Provider { get; } = Provider.Vimeo; - public override async Task Query(FeedMetadata metadata) + public override async Task Query(FeedMetadata metadata) { var linkType = metadata.LinkType; @@ -54,7 +54,7 @@ namespace Podsync.Services.Rss throw new NotSupportedException("URL type is not supported"); } - var rss = new Feed.Rss + var rss = new Feed { Channels = new[] { channel } }; diff --git a/src/Podsync/Services/Rss/YouTubeRssBuilder.cs b/src/Podsync/Services/Rss/Builders/YouTubeRssBuilder.cs similarity index 94% rename from src/Podsync/Services/Rss/YouTubeRssBuilder.cs rename to src/Podsync/Services/Rss/Builders/YouTubeRssBuilder.cs index 8bb3033..0c9eca9 100644 --- a/src/Podsync/Services/Rss/YouTubeRssBuilder.cs +++ b/src/Podsync/Services/Rss/Builders/YouTubeRssBuilder.cs @@ -3,13 +3,13 @@ using System.Linq; using System.Threading.Tasks; using Podsync.Services.Links; using Podsync.Services.Resolver; -using Podsync.Services.Rss.Feed; +using Podsync.Services.Rss.Contracts; using Podsync.Services.Storage; using Podsync.Services.Videos.YouTube; -using Channel = Podsync.Services.Rss.Feed.Channel; +using Channel = Podsync.Services.Rss.Contracts.Channel; using Video = Podsync.Services.Videos.YouTube.Video; -namespace Podsync.Services.Rss +namespace Podsync.Services.Rss.Builders { public class YouTubeRssBuilder : RssBuilderBase { @@ -22,7 +22,7 @@ namespace Podsync.Services.Rss public override Provider Provider { get; } = Provider.YouTube; - public override async Task Query(FeedMetadata metadata) + public override async Task Query(FeedMetadata metadata) { if (metadata.Provider != Provider.YouTube) { @@ -57,7 +57,7 @@ namespace Podsync.Services.Rss channel.Items = videos.Select(youtubeVideo => MakeItem(youtubeVideo, metadata)).ToArray(); - var rss = new Feed.Rss + var rss = new Feed { Channels = new[] { channel } }; diff --git a/src/Podsync/Services/Rss/Feed/Channel.cs b/src/Podsync/Services/Rss/Contracts/Channel.cs similarity index 98% rename from src/Podsync/Services/Rss/Feed/Channel.cs rename to src/Podsync/Services/Rss/Contracts/Channel.cs index caa1865..4e71930 100644 --- a/src/Podsync/Services/Rss/Feed/Channel.cs +++ b/src/Podsync/Services/Rss/Contracts/Channel.cs @@ -4,7 +4,7 @@ using System.Xml.Schema; using System.Xml.Serialization; using Shared; -namespace Podsync.Services.Rss.Feed +namespace Podsync.Services.Rss.Contracts { [XmlRoot("channel")] public class Channel : IXmlSerializable diff --git a/src/Podsync/Services/Rss/Feed/Rss.cs b/src/Podsync/Services/Rss/Contracts/Feed.cs similarity index 88% rename from src/Podsync/Services/Rss/Feed/Rss.cs rename to src/Podsync/Services/Rss/Contracts/Feed.cs index 61c9eca..2847abc 100644 --- a/src/Podsync/Services/Rss/Feed/Rss.cs +++ b/src/Podsync/Services/Rss/Contracts/Feed.cs @@ -4,19 +4,18 @@ using System.Linq; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; -using Podsync.Services.Rss.Feed.Internal; using Shared; -namespace Podsync.Services.Rss.Feed +namespace Podsync.Services.Rss.Contracts { [XmlRoot("rss")] - public class Rss : IXmlSerializable + public class Feed : IXmlSerializable { public const string Version = "2.0"; public IEnumerable Channels { get; set; } - public Rss() + public Feed() { Channels = Enumerable.Empty(); } @@ -47,7 +46,7 @@ namespace Podsync.Services.Rss.Feed public override string ToString() { - var serializer = new XmlSerializer(typeof(Rss)); + var serializer = new XmlSerializer(typeof(Feed)); // Serialize feed to XML string using (var writer = new Utf8StringWriter()) diff --git a/src/Podsync/Services/Rss/Feed/Item.cs b/src/Podsync/Services/Rss/Contracts/Item.cs similarity index 98% rename from src/Podsync/Services/Rss/Feed/Item.cs rename to src/Podsync/Services/Rss/Contracts/Item.cs index 434c4fb..037306f 100644 --- a/src/Podsync/Services/Rss/Feed/Item.cs +++ b/src/Podsync/Services/Rss/Contracts/Item.cs @@ -4,7 +4,7 @@ using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; -namespace Podsync.Services.Rss.Feed +namespace Podsync.Services.Rss.Contracts { [XmlRoot("item")] public class Item : IXmlSerializable diff --git a/src/Podsync/Services/Rss/Feed/Namespaces.cs b/src/Podsync/Services/Rss/Contracts/Namespaces.cs similarity index 90% rename from src/Podsync/Services/Rss/Feed/Namespaces.cs rename to src/Podsync/Services/Rss/Contracts/Namespaces.cs index f5928cc..6ce723f 100644 --- a/src/Podsync/Services/Rss/Feed/Namespaces.cs +++ b/src/Podsync/Services/Rss/Contracts/Namespaces.cs @@ -1,4 +1,4 @@ -namespace Podsync.Services.Rss.Feed +namespace Podsync.Services.Rss.Contracts { public static class Namespaces { diff --git a/src/Podsync/Services/Rss/FeedService.cs b/src/Podsync/Services/Rss/FeedService.cs new file mode 100644 index 0000000..68746e0 --- /dev/null +++ b/src/Podsync/Services/Rss/FeedService.cs @@ -0,0 +1,37 @@ +using System; +using System.Threading.Tasks; +using Podsync.Helpers; +using Podsync.Services.Links; +using Podsync.Services.Storage; + +namespace Podsync.Services.Rss +{ + public class FeedService : IFeedService + { + private readonly IStorageService _storageService; + private readonly IRssBuilder _rssBuilder; + + public FeedService(IStorageService storageService, IRssBuilder rssBuilder) + { + _storageService = storageService; + _rssBuilder = rssBuilder; + } + + public Task Create(FeedMetadata metadata) + { + if (metadata.Provider != Provider.YouTube && metadata.Quality.IsAudio()) + { + throw new ArgumentException("Only YouTube supports audio feeds"); + } + + metadata.PageSize = Constants.DefaultPageSize; + + return _storageService.Save(metadata); + } + + public Task Get(string id) + { + return _rssBuilder.Query(id); + } + } +} \ No newline at end of file diff --git a/src/Podsync/Services/Rss/IFeedService.cs b/src/Podsync/Services/Rss/IFeedService.cs new file mode 100644 index 0000000..c7a013d --- /dev/null +++ b/src/Podsync/Services/Rss/IFeedService.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; +using Podsync.Services.Storage; + +namespace Podsync.Services.Rss +{ + public interface IFeedService + { + Task Create(FeedMetadata metadata); + + Task Get(string id); + } +} \ No newline at end of file diff --git a/src/Podsync/Services/Rss/IRssBuilder.cs b/src/Podsync/Services/Rss/IRssBuilder.cs index 08974b7..c97fdb9 100644 --- a/src/Podsync/Services/Rss/IRssBuilder.cs +++ b/src/Podsync/Services/Rss/IRssBuilder.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Podsync.Services.Links; +using Podsync.Services.Rss.Contracts; using Podsync.Services.Storage; namespace Podsync.Services.Rss @@ -8,8 +9,8 @@ namespace Podsync.Services.Rss { Provider Provider { get; } - Task Query(string feedId); + Task Query(string feedId); - Task Query(FeedMetadata metadata); + Task Query(FeedMetadata metadata); } } \ No newline at end of file diff --git a/src/Podsync/Services/Rss/Feed/Internal/Utf8StringWriter.cs b/src/Podsync/Services/Rss/Utf8StringWriter.cs similarity index 78% rename from src/Podsync/Services/Rss/Feed/Internal/Utf8StringWriter.cs rename to src/Podsync/Services/Rss/Utf8StringWriter.cs index d3ba8b6..2c80d87 100644 --- a/src/Podsync/Services/Rss/Feed/Internal/Utf8StringWriter.cs +++ b/src/Podsync/Services/Rss/Utf8StringWriter.cs @@ -1,7 +1,7 @@ using System.IO; using System.Text; -namespace Podsync.Services.Rss.Feed.Internal +namespace Podsync.Services.Rss { public class Utf8StringWriter : StringWriter { diff --git a/src/Podsync/Startup.cs b/src/Podsync/Startup.cs index ea91f38..bde5058 100644 --- a/src/Podsync/Startup.cs +++ b/src/Podsync/Startup.cs @@ -15,6 +15,7 @@ using Podsync.Services.Links; using Podsync.Services.Patreon; using Podsync.Services.Resolver; using Podsync.Services.Rss; +using Podsync.Services.Rss.Builders; using Podsync.Services.Storage; using Podsync.Services.Videos.Vimeo; using Podsync.Services.Videos.YouTube; @@ -55,6 +56,7 @@ namespace Podsync services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); // Add authentication services services.AddAuthentication(config => config.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme); diff --git a/test/Podsync.Tests/Services/Rss/Feed/FeedSerializationTests.cs b/test/Podsync.Tests/Services/Rss/Contracts/FeedSerializationTests.cs similarity index 94% rename from test/Podsync.Tests/Services/Rss/Feed/FeedSerializationTests.cs rename to test/Podsync.Tests/Services/Rss/Contracts/FeedSerializationTests.cs index ea3edaa..c19a45b 100644 --- a/test/Podsync.Tests/Services/Rss/Feed/FeedSerializationTests.cs +++ b/test/Podsync.Tests/Services/Rss/Contracts/FeedSerializationTests.cs @@ -1,10 +1,10 @@ using System; using System.IO; using System.Xml.Serialization; -using Podsync.Services.Rss.Feed; +using Podsync.Services.Rss.Contracts; using Xunit; -namespace Podsync.Tests.Services.Rss.Feed +namespace Podsync.Tests.Services.Rss.Contracts { public class FeedSerializationTests { @@ -13,7 +13,7 @@ namespace Podsync.Tests.Services.Rss.Feed [Fact] public void SerializeFeedTest() { - var feed = new Podsync.Services.Rss.Feed.Rss(); + var feed = new Feed(); var item = new Item { @@ -50,7 +50,7 @@ namespace Podsync.Tests.Services.Rss.Feed channel }; - var serializer = new XmlSerializer(typeof(Podsync.Services.Rss.Feed.Rss)); + var serializer = new XmlSerializer(typeof(Feed)); string body; using (var writer = new StringWriter()) diff --git a/test/Podsync.Tests/Services/Rss/VimeoRssBuilderTests.cs b/test/Podsync.Tests/Services/Rss/VimeoRssBuilderTests.cs index b4480e4..6cede11 100644 --- a/test/Podsync.Tests/Services/Rss/VimeoRssBuilderTests.cs +++ b/test/Podsync.Tests/Services/Rss/VimeoRssBuilderTests.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Moq; using Podsync.Services.Links; -using Podsync.Services.Rss; +using Podsync.Services.Rss.Builders; using Podsync.Services.Storage; using Podsync.Services.Videos.Vimeo; using Xunit; diff --git a/test/Podsync.Tests/Services/Rss/YouTubeRssBuilderTests.cs b/test/Podsync.Tests/Services/Rss/YouTubeRssBuilderTests.cs index a2fcb87..3373fd5 100644 --- a/test/Podsync.Tests/Services/Rss/YouTubeRssBuilderTests.cs +++ b/test/Podsync.Tests/Services/Rss/YouTubeRssBuilderTests.cs @@ -3,7 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Moq; using Podsync.Services.Links; -using Podsync.Services.Rss; +using Podsync.Services.Rss.Builders; using Podsync.Services.Storage; using Podsync.Services.Videos.YouTube; using Xunit;