mirror of
https://github.com/mxpv/podsync.git
synced 2024-05-11 05:55:04 +00:00
Move feed management to separate service, update RSS contracts
This commit is contained in:
@@ -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<IActionResult> 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");
|
||||
}
|
||||
}
|
||||
}
|
@@ -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<Feed.Rss> Query(FeedMetadata feed)
|
||||
public override Task<Contracts.Feed> Query(FeedMetadata feed)
|
||||
{
|
||||
try
|
||||
{
|
@@ -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<Feed.Rss> Query(string feedId)
|
||||
public async Task<Contracts.Feed> Query(string feedId)
|
||||
{
|
||||
var metadata = await _storageService.Load(feedId);
|
||||
|
||||
return await Query(metadata);
|
||||
}
|
||||
|
||||
public abstract Task<Feed.Rss> Query(FeedMetadata metadata);
|
||||
public abstract Task<Contracts.Feed> Query(FeedMetadata metadata);
|
||||
}
|
||||
}
|
@@ -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<Feed.Rss> Query(FeedMetadata metadata)
|
||||
public override async Task<Feed> 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 }
|
||||
};
|
@@ -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<Feed.Rss> Query(FeedMetadata metadata)
|
||||
public override async Task<Feed> 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 }
|
||||
};
|
@@ -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
|
@@ -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<Channel> Channels { get; set; }
|
||||
|
||||
public Rss()
|
||||
public Feed()
|
||||
{
|
||||
Channels = Enumerable.Empty<Channel>();
|
||||
}
|
||||
@@ -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())
|
@@ -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
|
@@ -1,4 +1,4 @@
|
||||
namespace Podsync.Services.Rss.Feed
|
||||
namespace Podsync.Services.Rss.Contracts
|
||||
{
|
||||
public static class Namespaces
|
||||
{
|
37
src/Podsync/Services/Rss/FeedService.cs
Normal file
37
src/Podsync/Services/Rss/FeedService.cs
Normal file
@@ -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<string> 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<Contracts.Feed> Get(string id)
|
||||
{
|
||||
return _rssBuilder.Query(id);
|
||||
}
|
||||
}
|
||||
}
|
12
src/Podsync/Services/Rss/IFeedService.cs
Normal file
12
src/Podsync/Services/Rss/IFeedService.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.Threading.Tasks;
|
||||
using Podsync.Services.Storage;
|
||||
|
||||
namespace Podsync.Services.Rss
|
||||
{
|
||||
public interface IFeedService
|
||||
{
|
||||
Task<string> Create(FeedMetadata metadata);
|
||||
|
||||
Task<Contracts.Feed> Get(string id);
|
||||
}
|
||||
}
|
@@ -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<Feed.Rss> Query(string feedId);
|
||||
Task<Feed> Query(string feedId);
|
||||
|
||||
Task<Feed.Rss> Query(FeedMetadata metadata);
|
||||
Task<Feed> Query(FeedMetadata metadata);
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Podsync.Services.Rss.Feed.Internal
|
||||
namespace Podsync.Services.Rss
|
||||
{
|
||||
public class Utf8StringWriter : StringWriter
|
||||
{
|
@@ -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<IStorageService, RedisStorage>();
|
||||
services.AddSingleton<IRssBuilder, CompositeRssBuilder>();
|
||||
services.AddSingleton<IPatreonApi, PatreonApi>();
|
||||
services.AddSingleton<IFeedService, FeedService>();
|
||||
|
||||
// Add authentication services
|
||||
services.AddAuthentication(config => config.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
|
@@ -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())
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user