mirror of
https://github.com/mxpv/podsync.git
synced 2024-05-11 05:55:04 +00:00
Implement link service
This commit is contained in:
@@ -16,6 +16,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D94416F2-3
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Podsync.Tests", "test\Podsync.Tests\Podsync.Tests.xproj", "{990B29B3-C581-4D60-A34B-36499E2849BA}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{35F181BF-B2AD-42AB-BB11-DC66D57E6514}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
src\Shared\EnumerableExtensions.cs = src\Shared\EnumerableExtensions.cs
|
||||
src\Shared\ListExtensions.cs = src\Shared\ListExtensions.cs
|
||||
src\Shared\StringExtensions.cs = src\Shared\StringExtensions.cs
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -37,5 +44,6 @@ Global
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{C9283472-E95E-4517-AE3B-3E276B9851E4} = {3EF2294C-C807-46F3-B3F4-98B7F30688D0}
|
||||
{990B29B3-C581-4D60-A34B-36499E2849BA} = {D94416F2-31EA-4D38-A3D0-BB74180687D4}
|
||||
{35F181BF-B2AD-42AB-BB11-DC66D57E6514} = {3EF2294C-C807-46F3-B3F4-98B7F30688D0}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
11
src/Podsync/Services/Links/ILinkService.cs
Normal file
11
src/Podsync/Services/Links/ILinkService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Podsync.Services.Links
|
||||
{
|
||||
public interface ILinkService
|
||||
{
|
||||
LinkInfo Parse(Uri link);
|
||||
|
||||
Uri Make(LinkInfo info);
|
||||
}
|
||||
}
|
||||
11
src/Podsync/Services/Links/LinkInfo.cs
Normal file
11
src/Podsync/Services/Links/LinkInfo.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Podsync.Services.Links
|
||||
{
|
||||
public struct LinkInfo
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public LinkType LinkType { get; set; }
|
||||
|
||||
public Provider Provider { get; set; }
|
||||
}
|
||||
}
|
||||
197
src/Podsync/Services/Links/LinkService.cs
Normal file
197
src/Podsync/Services/Links/LinkService.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Shared;
|
||||
|
||||
namespace Podsync.Services.Links
|
||||
{
|
||||
public class LinkService : ILinkService
|
||||
{
|
||||
private static readonly IDictionary<Provider, IDictionary<LinkType, string>> LinkFormats = new Dictionary<Provider, IDictionary<LinkType, string>>
|
||||
{
|
||||
[Provider.YouTube] = new Dictionary<LinkType, string>
|
||||
{
|
||||
[LinkType.Video] = "https://youtube.com/watch?v={0}",
|
||||
[LinkType.Channel] = "https://youtube.com/channel/{0}",
|
||||
[LinkType.Playlist] = "https://youtube.com/playlist?list={0}",
|
||||
[LinkType.Info] = "https://youtube.com/get_video_info?video_id={0}"
|
||||
},
|
||||
|
||||
[Provider.Vimeo] = new Dictionary<LinkType, string>
|
||||
{
|
||||
[LinkType.Category] = "https://vimeo.com/categories/{0}",
|
||||
[LinkType.Channel] = "https://vimeo.com/channels/{0}",
|
||||
[LinkType.Group] = "https://vimeo.com/groups/{0}",
|
||||
[LinkType.User] = "https://vimeo.com/{0}",
|
||||
[LinkType.Info] = "https://player.vimeo.com/video/{0}/config"
|
||||
}
|
||||
};
|
||||
|
||||
public LinkInfo Parse(Uri link)
|
||||
{
|
||||
if (link == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(link), "Link can't be null");
|
||||
}
|
||||
|
||||
var provider = Provider.Unknown;
|
||||
var linkType = LinkType.Unknown;
|
||||
|
||||
var id = string.Empty;
|
||||
|
||||
var segments = link.Segments
|
||||
.Select(x => x.TrimEnd('/'))
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||
.ToArray();
|
||||
|
||||
var host = link.Host.ToLowerInvariant().TrimStart("www.");
|
||||
|
||||
if (host == "youtu.be")
|
||||
{
|
||||
provider = Provider.YouTube;
|
||||
|
||||
if (segments.Length == 1)
|
||||
{
|
||||
// https://youtu.be/AAAAAAAAA01
|
||||
// https://www.youtu.be/AAAAAAAAA08
|
||||
|
||||
linkType = LinkType.Video;
|
||||
id = segments.Single();
|
||||
}
|
||||
}
|
||||
else if (host == "youtube.com")
|
||||
{
|
||||
provider = Provider.YouTube;
|
||||
|
||||
var query = QueryHelpers.ParseQuery(link.Query);
|
||||
|
||||
if (segments.Length >= 2 && segments[0] == "user")
|
||||
{
|
||||
linkType = LinkType.User;
|
||||
id = segments[1];
|
||||
}
|
||||
else if (segments.Length == 2)
|
||||
{
|
||||
if (string.Equals(segments[0], "embed"))
|
||||
{
|
||||
linkType = LinkType.Video;
|
||||
|
||||
if (string.Equals(segments[1], "watch"))
|
||||
{
|
||||
// http://www.youtube.com/embed/watch?feature=player_embedded&v=AAAAAAAAA02
|
||||
// http://www.youtube.com/embed/watch?v=AAAAAAAAA03
|
||||
|
||||
id = query["v"];
|
||||
}
|
||||
else if (segments[1].StartsWith("v="))
|
||||
{
|
||||
// http://www.youtube.com/embed/v=AAAAAAAAA04
|
||||
|
||||
id = segments[1].TrimStart("v=");
|
||||
}
|
||||
}
|
||||
else if (string.Equals(segments[0], "watch"))
|
||||
{
|
||||
// http://www.youtube.com/watch/jMeC7JFQ6811
|
||||
|
||||
linkType = LinkType.Video;
|
||||
id = segments[1];
|
||||
}
|
||||
else if (string.Equals(segments[0], "v"))
|
||||
{
|
||||
// http://www.youtube.com/v/jMeC7JFQ6812
|
||||
// http://www.youtube.com/v/A-AAAAAAA18?fs=1&rel=0
|
||||
|
||||
linkType = LinkType.Video;
|
||||
id = segments[1];
|
||||
}
|
||||
else if (string.Equals(segments[0], "channel"))
|
||||
{
|
||||
// https://www.youtube.com/channel/UC5XPnUk8Vvv_pWslhwom6Og
|
||||
|
||||
linkType = LinkType.Channel;
|
||||
id = segments[1];
|
||||
}
|
||||
}
|
||||
|
||||
else if (segments.Length == 1)
|
||||
{
|
||||
if (string.Equals(segments[0], "watch"))
|
||||
{
|
||||
if (query.ContainsKey("list"))
|
||||
{
|
||||
// https://www.youtube.com/watch?v=otm9NaT9OWU&list=PLCB9F975ECF01953C
|
||||
|
||||
linkType = LinkType.Playlist;
|
||||
id = query["list"];
|
||||
}
|
||||
else
|
||||
{
|
||||
// http://www.youtube.com/watch?v=AAAAAAAAA06
|
||||
// http://www.youtube.com/watch?feature=player_embedded&v=AAAAAAAAA05
|
||||
|
||||
linkType = LinkType.Video;
|
||||
id = query["v"];
|
||||
}
|
||||
}
|
||||
else if (string.Equals(segments[0], "attribution_link"))
|
||||
{
|
||||
// http://www.youtube.com/attribution_link?u=/watch?v=jMeC7JFQ6815&feature=share&a=9QlmP1yvjcllp0h3l0NwuA
|
||||
// http://www.youtube.com/attribution_link?a=fF1CWYwxCQ4&u=/watch?v=jMeC7JFQ6816&feature=em-uploademail
|
||||
// http://www.youtube.com/attribution_link?a=fF1CWYwxCQ4&feature=em-uploademail&u=/watch?v=jMeC7JFQ6817
|
||||
|
||||
string u = query["u"];
|
||||
|
||||
var pos = u?.IndexOf("?", StringComparison.OrdinalIgnoreCase) ?? -1;
|
||||
if (pos != -1)
|
||||
{
|
||||
// ReSharper disable once PossibleNullReferenceException
|
||||
var attrQueryParams = QueryHelpers.ParseQuery(u.Substring(pos));
|
||||
|
||||
linkType = LinkType.Video;
|
||||
id = attrQueryParams["v"];
|
||||
}
|
||||
}
|
||||
else if (string.Equals(segments[0], "playlist"))
|
||||
{
|
||||
// https://www.youtube.com/playlist?list=PLCB9F975ECF01953C
|
||||
|
||||
linkType = LinkType.Playlist;
|
||||
id = query["list"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(id) || linkType == LinkType.Unknown || provider == Provider.Unknown)
|
||||
{
|
||||
throw new ArgumentException("Failed to parse URL");
|
||||
}
|
||||
|
||||
return new LinkInfo
|
||||
{
|
||||
Id = id,
|
||||
LinkType = linkType,
|
||||
Provider = provider
|
||||
};
|
||||
}
|
||||
|
||||
public Uri Make(LinkInfo info)
|
||||
{
|
||||
if (info.Id == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info.Id), "Id can't be empty");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var format = LinkFormats[info.Provider][info.LinkType];
|
||||
return new Uri(string.Format(format, info.Id));
|
||||
}
|
||||
catch (KeyNotFoundException ex)
|
||||
{
|
||||
throw new ArgumentException("Unsupported provider or link type", nameof(info), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
14
src/Podsync/Services/Links/LinkType.cs
Normal file
14
src/Podsync/Services/Links/LinkType.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Podsync.Services.Links
|
||||
{
|
||||
public enum LinkType
|
||||
{
|
||||
Unknown = 0,
|
||||
Video,
|
||||
Playlist,
|
||||
User,
|
||||
Channel,
|
||||
Info,
|
||||
Category,
|
||||
Group
|
||||
}
|
||||
}
|
||||
9
src/Podsync/Services/Links/Provider.cs
Normal file
9
src/Podsync/Services/Links/Provider.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Podsync.Services.Links
|
||||
{
|
||||
public enum Provider
|
||||
{
|
||||
Unknown = 0,
|
||||
YouTube,
|
||||
Vimeo,
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Podsync.Services.Links;
|
||||
|
||||
namespace Podsync
|
||||
{
|
||||
@@ -27,6 +24,9 @@ namespace Podsync
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Register core services
|
||||
services.AddSingleton<ILinkService, LinkService>();
|
||||
|
||||
// Add framework services.
|
||||
services.AddMvc();
|
||||
}
|
||||
|
||||
@@ -1,65 +1,68 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0",
|
||||
"type": "platform"
|
||||
{
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0",
|
||||
"type": "platform"
|
||||
},
|
||||
"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.Extensions.Configuration.EnvironmentVariables": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.Json": "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.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
|
||||
"Microsoft.AspNetCore.WebUtilities": "1.0.0"
|
||||
},
|
||||
"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.Extensions.Configuration.EnvironmentVariables": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.Json": "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.VisualStudio.Web.BrowserLink.Loader": "14.0.0"
|
||||
},
|
||||
|
||||
"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"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"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%" ]
|
||||
}
|
||||
},
|
||||
|
||||
"buildOptions": {
|
||||
"emitEntryPoint": true,
|
||||
"preserveCompilationContext": true
|
||||
},
|
||||
|
||||
"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%" ]
|
||||
}
|
||||
}
|
||||
|
||||
71
src/Shared/EnumerableExtensions.cs
Normal file
71
src/Shared/EnumerableExtensions.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Shared
|
||||
{
|
||||
internal static class EnumerableExtensions
|
||||
{
|
||||
public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunkSize)
|
||||
{
|
||||
if (chunkSize < 1)
|
||||
{
|
||||
throw new ArgumentException("Chunk size must be positive", nameof(chunkSize));
|
||||
}
|
||||
|
||||
while (source.Any())
|
||||
{
|
||||
yield return source.Take(chunkSize);
|
||||
source = source.Skip(chunkSize);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool SafeAny<T>(this IEnumerable<T> source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (source.Any())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in source)
|
||||
{
|
||||
action(item);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SafeForEach<T>(this IEnumerable<T> source, Action<T> action)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var item in source)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(item);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/Shared/ListExtensions.cs
Normal file
20
src/Shared/ListExtensions.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Shared
|
||||
{
|
||||
internal static class ListExtensions
|
||||
{
|
||||
public static void AddRange<T>(this IList<T> source, T[] elements)
|
||||
{
|
||||
if (source == null || elements == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var element in elements)
|
||||
{
|
||||
source.Add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
60
src/Shared/StringExtensions.cs
Normal file
60
src/Shared/StringExtensions.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Shared
|
||||
{
|
||||
internal static class StringExtensions
|
||||
{
|
||||
public static string TrimEnd(this string value, string word)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value) || string.IsNullOrWhiteSpace(word) || !value.EndsWith(word, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return value.Substring(0, value.Length - word.Length);
|
||||
}
|
||||
|
||||
public static string TrimStart(this string value, string word, StringComparison comparison = StringComparison.Ordinal)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
string result = value;
|
||||
while (result.StartsWith(word, comparison))
|
||||
{
|
||||
result = result.Substring(word.Length);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string RemoveChars(this string value, char[] list)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return string.Concat(value.Split(list, StringSplitOptions.RemoveEmptyEntries));
|
||||
}
|
||||
|
||||
public static string FirstCharToUpperInvariant(this string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
var first = value.First();
|
||||
if (char.IsUpper(first))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return first.ToString().ToUpperInvariant() + value.Substring(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NuGet.Packaging;
|
||||
using Xunit;
|
||||
|
||||
namespace Podsync.Tests
|
||||
{
|
||||
public class Class1
|
||||
{
|
||||
public Class1()
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PassingTest()
|
||||
{
|
||||
Assert.True(true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FailingTest()
|
||||
{
|
||||
Assert.False(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
73
test/Podsync.Tests/Services/Links/LinkServiceTests.cs
Normal file
73
test/Podsync.Tests/Services/Links/LinkServiceTests.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using Podsync.Services.Links;
|
||||
using Xunit;
|
||||
|
||||
namespace Podsync.Tests.Services.Links
|
||||
{
|
||||
public class LinkServiceTests
|
||||
{
|
||||
private readonly ILinkService _linkService = new LinkService();
|
||||
|
||||
[Theory]
|
||||
[InlineData("http://youtu.be/jMeC7JFQ6801", Provider.YouTube, LinkType.Video, "jMeC7JFQ6801")]
|
||||
[InlineData("http://www.youtube.com/embed/watch?feature=player_embedded&v=jMeC7JFQ6802", Provider.YouTube, LinkType.Video, "jMeC7JFQ6802")]
|
||||
[InlineData("http://www.youtube.com/embed/watch?v=jMeC7JFQ6803", Provider.YouTube, LinkType.Video, "jMeC7JFQ6803")]
|
||||
[InlineData("http://www.youtube.com/embed/v=jMeC7JFQ6804", Provider.YouTube, LinkType.Video, "jMeC7JFQ6804")]
|
||||
[InlineData("http://www.youtube.com/watch?v=jMeC7JFQ6806", Provider.YouTube, LinkType.Video, "jMeC7JFQ6806")]
|
||||
[InlineData("http://www.youtube.com/watch?v=jMeC7JFQ6807", Provider.YouTube, LinkType.Video, "jMeC7JFQ6807")]
|
||||
[InlineData("http://www.youtu.be/jMeC7JFQ6808", Provider.YouTube, LinkType.Video, "jMeC7JFQ6808")]
|
||||
[InlineData("http://youtu.be/jMeC7JFQ6809", Provider.YouTube, LinkType.Video, "jMeC7JFQ6809")]
|
||||
[InlineData("http://www.youtube.com/watch?feature=player_embedded&v=jMeC7JFQ6805", Provider.YouTube, LinkType.Video, "jMeC7JFQ6805")]
|
||||
[InlineData("http://www.youtube.com/attribution_link?u=/watch?v=jMeC7JFQ6815&feature=share&a=9QlmP1yvjcllp0h3l0NwuA", Provider.YouTube, LinkType.Video, "jMeC7JFQ6815")]
|
||||
[InlineData("http://www.youtube.com/attribution_link?a=fF1CWYwxCQ4&u=/watch?v=jMeC7JFQ6816&feature=em-uploademail", Provider.YouTube, LinkType.Video, "jMeC7JFQ6816")]
|
||||
[InlineData("http://www.youtube.com/attribution_link?a=fF1CWYwxCQ4&feature=em-uploademail&u=/watch?v=jMeC7JFQ6817", Provider.YouTube, LinkType.Video, "jMeC7JFQ6817")]
|
||||
[InlineData("http://youtube.com/watch?v=jMeC7JFQ6810", Provider.YouTube, LinkType.Video, "jMeC7JFQ6810")]
|
||||
[InlineData("http://www.youtube.com/watch/jMeC7JFQ6811", Provider.YouTube, LinkType.Video, "jMeC7JFQ6811")]
|
||||
[InlineData("http://www.youtube.com/v/jMeC7JFQ6812", Provider.YouTube, LinkType.Video, "jMeC7JFQ6812")]
|
||||
[InlineData("http://WWW.YOUTUBE.COM/v/jMeC7JFQ6812", Provider.YouTube, LinkType.Video, "jMeC7JFQ6812")]
|
||||
[InlineData("https://www.youtube.com/playlist?list=PLCB9F975ECF01953C", Provider.YouTube, LinkType.Playlist, "PLCB9F975ECF01953C")]
|
||||
[InlineData("https://www.youtube.com/watch?v=otm9NaT9OWU&list=PLCB9F975ECF01953C", Provider.YouTube, LinkType.Playlist, "PLCB9F975ECF01953C")]
|
||||
[InlineData("https://www.youtube.com/channel/UC5XPnUk8Vvv_pWslhwom6Og", Provider.YouTube, LinkType.Channel, "UC5XPnUk8Vvv_pWslhwom6Og")]
|
||||
[InlineData("https://www.youtube.com/user/UC5XPnUk8Vvv_pWslhwom6Og", Provider.YouTube, LinkType.User, "UC5XPnUk8Vvv_pWslhwom6Og")]
|
||||
[InlineData("https://www.youtube.com/user/ComboBreakerVideo/videos", Provider.YouTube, LinkType.User, "ComboBreakerVideo")]
|
||||
[InlineData("https://www.youtube.com/user/UC5XPnUk8Vvv_pWslhwom6Og/playlists", Provider.YouTube, LinkType.User, "UC5XPnUk8Vvv_pWslhwom6Og")]
|
||||
public void ParseLinkTest(string link, Provider provider, LinkType linkType, string id)
|
||||
{
|
||||
var info = _linkService.Parse(new Uri(link));
|
||||
|
||||
Assert.Equal(info.Id, id);
|
||||
Assert.Equal(info.LinkType, linkType);
|
||||
Assert.Equal(info.Provider, provider);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseInvalidLinkTest()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => _linkService.Parse(null));
|
||||
Assert.Throws<ArgumentException>(() => _linkService.Parse(new Uri("http://www.apple.com")));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(Provider.YouTube, LinkType.Channel, "123", "https://youtube.com/channel/123")]
|
||||
[InlineData(Provider.YouTube, LinkType.Playlist, "213", "https://youtube.com/playlist?list=213")]
|
||||
[InlineData(Provider.YouTube, LinkType.Video, "321", "https://youtube.com/watch?v=321")]
|
||||
[InlineData(Provider.YouTube, LinkType.Info, "111", "https://youtube.com/get_video_info?video_id=111")]
|
||||
[InlineData(Provider.Vimeo, LinkType.Category, "xyz", "https://vimeo.com/categories/xyz")]
|
||||
[InlineData(Provider.Vimeo, LinkType.Channel, "yzx", "https://vimeo.com/channels/yzx")]
|
||||
[InlineData(Provider.Vimeo, LinkType.Group, "zyd", "https://vimeo.com/groups/zyd")]
|
||||
[InlineData(Provider.Vimeo, LinkType.User, "dfz", "https://vimeo.com/dfz")]
|
||||
[InlineData(Provider.Vimeo, LinkType.Info, "xgd", "https://player.vimeo.com/video/xgd/config")]
|
||||
public void MakeLinkTest(Provider provider, LinkType linkType, string id, string expected)
|
||||
{
|
||||
var info = new LinkInfo
|
||||
{
|
||||
Id = id,
|
||||
LinkType = linkType,
|
||||
Provider = provider,
|
||||
};
|
||||
|
||||
var link = _linkService.Make(info);
|
||||
Assert.Equal(expected, link.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
{
|
||||
"version": "1.0.0-*",
|
||||
"testRunner": "xunit",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"version": "1.0.0",
|
||||
"type": "platform"
|
||||
},
|
||||
"Podsync": "1.0.0-*",
|
||||
"xunit": "2.2.0-beta2-build3300"
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user