mirror of
https://github.com/mxpv/podsync.git
synced 2024-05-11 05:55:04 +00:00
Implement YouTube API client
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
namespace Podsync.Services
|
||||
{
|
||||
public class PodsyncConfiguration
|
||||
{
|
||||
public string YouTubeApiKey { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Podsync.Services.Videos.YouTube
|
||||
{
|
||||
public class Channel : YouTubeItem
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Podsync.Services.Videos.YouTube
|
||||
{
|
||||
public struct ChannelQuery
|
||||
{
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
public string Username { get; set; }
|
||||
|
||||
public uint? Count { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Podsync.Services.Videos.YouTube
|
||||
{
|
||||
public interface IYouTubeClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a collection of zero or more channel resources that match the request criteria
|
||||
/// Cost: 5 (quota cost of 1 + id: 0, snippet: 2, contentDetails: 2)
|
||||
/// See https://developers.google.com/youtube/v3/docs/channels/list
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<Channel>> GetChannels(ChannelQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a collection of playlists that match the API request parameters
|
||||
/// Cost: 3 (quota cost of 1 + id: 0, snippet: 2)
|
||||
/// See https://developers.google.com/youtube/v3/docs/playlists/list
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<Playlist>> GetPlaylists(PlaylistQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of videos that match the API request parameters
|
||||
/// Cost: 5 (quota cost of 1 + id: 0, snippet: 2, contentDetails: 2)
|
||||
/// See https://developers.google.com/youtube/v3/docs/videos/list
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<Video>> GetVideos(VideoQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a collection of playlist items that match the API request parameters.
|
||||
/// You can retrieve all of the playlist items in a specified playlist or
|
||||
/// retrieve one or more playlist items by their unique IDs.
|
||||
/// Cost: 3 (quota cost of 1 + id: 0, snippet: 2)
|
||||
/// See https://developers.google.com/youtube/v3/docs/playlistItems/list
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<Video>> GetPlaylistItems(PlaylistItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Optimized version of GetPlaylistItems to query video IDs only
|
||||
/// Cost: 3 (quota cost of 1 + id: 0, snippet: 2)
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<string>> GetPlaylistItemIds(PlaylistItemsQuery query);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Podsync.Services.Videos.YouTube
|
||||
{
|
||||
public class Playlist : YouTubeItem
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Podsync.Services.Videos.YouTube
|
||||
{
|
||||
public struct PlaylistItemsQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// The id parameter specifies a comma-separated list of one or more unique playlist item IDs
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The playlistId parameter specifies the unique ID of the playlist for which you want to retrieve playlist items.
|
||||
/// Note that even though this is an optional parameter, every request to retrieve playlist items must specify
|
||||
/// a value for either the id parameter or the playlistId parameter.
|
||||
/// </summary>
|
||||
public string PlaylistId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The videoId parameter specifies that the request should return only the playlist items that contain the specified video
|
||||
/// </summary>
|
||||
public string VideoId { get; set; }
|
||||
|
||||
public uint? Count { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Podsync.Services.Videos.YouTube
|
||||
{
|
||||
public struct PlaylistQuery
|
||||
{
|
||||
public string PlaylistId { get; set; }
|
||||
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
public uint? Count { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Podsync.Services.Videos.YouTube
|
||||
{
|
||||
public class Video : YouTubeItem
|
||||
{
|
||||
public TimeSpan Duration { get; set; }
|
||||
|
||||
public long Size { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Podsync.Services.Videos.YouTube
|
||||
{
|
||||
public struct VideoQuery
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public uint? Count { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Google.Apis.Services;
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Podsync.Services.Links;
|
||||
|
||||
namespace Podsync.Services.Videos.YouTube
|
||||
{
|
||||
public sealed class YouTubeClient : IYouTubeClient, IDisposable
|
||||
{
|
||||
private const int MaxResults = 50;
|
||||
|
||||
private readonly ILinkService _linkService;
|
||||
private readonly YouTubeService _youtube;
|
||||
|
||||
public YouTubeClient(ILinkService linkService, IOptions<PodsyncConfiguration> configuration)
|
||||
{
|
||||
_linkService = linkService;
|
||||
_youtube = new YouTubeService(new BaseClientService.Initializer
|
||||
{
|
||||
ApplicationName = "Podsync",
|
||||
ApiKey = configuration.Value.YouTubeApiKey
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Channel>> GetChannels(ChannelQuery query)
|
||||
{
|
||||
var request = _youtube.Channels.List("id,snippet,contentDetails");
|
||||
|
||||
request.MaxResults = query.Count ?? MaxResults;
|
||||
request.Id = query.ChannelId;
|
||||
request.ForUsername = query.Username;
|
||||
|
||||
var response = await request.ExecuteAsync();
|
||||
|
||||
return response.Items.Select(ConvertChannel);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Playlist>> GetPlaylists(PlaylistQuery query)
|
||||
{
|
||||
var request = _youtube.Playlists.List("id,snippet");
|
||||
|
||||
request.MaxResults = query.Count ?? MaxResults;
|
||||
request.Id = query.PlaylistId;
|
||||
request.ChannelId = query.ChannelId;
|
||||
|
||||
var response = await request.ExecuteAsync();
|
||||
|
||||
return response.Items.Select(ConvertPlaylist);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Video>> GetVideos(VideoQuery query)
|
||||
{
|
||||
var request = _youtube.Videos.List("id,snippet,contentDetails");
|
||||
|
||||
request.MaxResults = query.Count ?? MaxResults;
|
||||
request.Id = query.Id;
|
||||
|
||||
var response = await request.ExecuteAsync();
|
||||
|
||||
return response.Items.Select(ConvertVideo);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Video>> GetPlaylistItems(PlaylistItemsQuery query)
|
||||
{
|
||||
var response = await QueryPlaylistItems(query);
|
||||
|
||||
return response.Items.Select(ConvertPlaylistItem);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<string>> GetPlaylistItemIds(PlaylistItemsQuery query)
|
||||
{
|
||||
var response = await QueryPlaylistItems(query);
|
||||
|
||||
return response.Items.Select(x => x.Snippet.ResourceId.VideoId);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_youtube.Dispose();
|
||||
}
|
||||
|
||||
private static long GetVideoSize(string definition, TimeSpan duration)
|
||||
{
|
||||
// Video size information requires 1 additional call for each video (1 feed = 50 videos = 50 calls),
|
||||
// which is too expensive, so get approximated size depending on duration and definition params
|
||||
|
||||
var totalSeconds = (long)duration.TotalSeconds;
|
||||
|
||||
const long hdBytesPerSecond = 350000;
|
||||
const long ldBytesPerSecond = 100000;
|
||||
|
||||
return totalSeconds * (definition == "hd" ? hdBytesPerSecond : ldBytesPerSecond);
|
||||
}
|
||||
|
||||
private Task<PlaylistItemListResponse> QueryPlaylistItems(PlaylistItemsQuery query)
|
||||
{
|
||||
var request = _youtube.PlaylistItems.List("id,snippet");
|
||||
|
||||
request.MaxResults = query.Count ?? MaxResults;
|
||||
request.Id = query.Id;
|
||||
request.PlaylistId = query.PlaylistId;
|
||||
request.VideoId = query.VideoId;
|
||||
|
||||
return request.ExecuteAsync();
|
||||
}
|
||||
|
||||
private Video ConvertVideo(Google.Apis.YouTube.v3.Data.Video item)
|
||||
{
|
||||
var snippet = item.Snippet;
|
||||
var details = item.ContentDetails;
|
||||
|
||||
var link = _linkService.Make(new LinkInfo
|
||||
{
|
||||
Id = item.Id,
|
||||
LinkType = LinkType.Video,
|
||||
Provider = Provider.YouTube
|
||||
});
|
||||
|
||||
var duration = XmlConvert.ToTimeSpan(details.Duration);
|
||||
var size = GetVideoSize(details.Definition, duration);
|
||||
|
||||
return new Video
|
||||
{
|
||||
VideoId = item.Id,
|
||||
ChannelId = snippet.ChannelId,
|
||||
Title = snippet.Title,
|
||||
Description = snippet.Description,
|
||||
PublishedAt = snippet.PublishedAt ?? DateTime.MinValue,
|
||||
Link = link,
|
||||
Duration = duration,
|
||||
Size = size,
|
||||
};
|
||||
}
|
||||
|
||||
private Video ConvertPlaylistItem(PlaylistItem item)
|
||||
{
|
||||
var snippet = item.Snippet;
|
||||
|
||||
var link = _linkService.Make(new LinkInfo
|
||||
{
|
||||
Id = item.Id,
|
||||
LinkType = LinkType.Video,
|
||||
Provider = Provider.YouTube
|
||||
});
|
||||
|
||||
return new Video
|
||||
{
|
||||
VideoId = snippet.ResourceId.VideoId,
|
||||
ChannelId = snippet.ChannelId,
|
||||
PlaylistId = snippet.PlaylistId,
|
||||
Link = link,
|
||||
Title = snippet.Title,
|
||||
Description = snippet.Description,
|
||||
PublishedAt = snippet.PublishedAt ?? DateTime.MinValue,
|
||||
Thumbnail = new Uri(snippet.Thumbnails.Default__.Url)
|
||||
};
|
||||
}
|
||||
|
||||
private Playlist ConvertPlaylist(Google.Apis.YouTube.v3.Data.Playlist item)
|
||||
{
|
||||
var link = _linkService.Make(new LinkInfo
|
||||
{
|
||||
Id = item.Id,
|
||||
LinkType = LinkType.Playlist,
|
||||
Provider = Provider.YouTube
|
||||
});
|
||||
|
||||
var snippet = item.Snippet;
|
||||
|
||||
return new Playlist
|
||||
{
|
||||
PlaylistId = item.Id,
|
||||
ChannelId = snippet.ChannelId,
|
||||
Link = link,
|
||||
Title = $"{snippet.ChannelTitle}: {snippet.Title}",
|
||||
Description = snippet.Description,
|
||||
PublishedAt = snippet.PublishedAt ?? DateTime.MinValue,
|
||||
Thumbnail = new Uri(snippet.Thumbnails.Default__.Url)
|
||||
};
|
||||
}
|
||||
|
||||
private Channel ConvertChannel(Google.Apis.YouTube.v3.Data.Channel item)
|
||||
{
|
||||
var link = _linkService.Make(new LinkInfo
|
||||
{
|
||||
Id = item.Id,
|
||||
LinkType = LinkType.Channel,
|
||||
Provider = Provider.YouTube
|
||||
});
|
||||
|
||||
var snippet = item.Snippet;
|
||||
|
||||
return new Channel
|
||||
{
|
||||
ChannelId = item.Id,
|
||||
PlaylistId = item.ContentDetails.RelatedPlaylists.Uploads,
|
||||
Link = link,
|
||||
Title = snippet.Title,
|
||||
Description = snippet.Description,
|
||||
PublishedAt = snippet.PublishedAt ?? DateTime.MinValue,
|
||||
Thumbnail = new Uri(snippet.Thumbnails.Default__.Url)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Podsync.Services.Videos.YouTube
|
||||
{
|
||||
public class YouTubeItem
|
||||
{
|
||||
public string VideoId { get; set; }
|
||||
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
public string PlaylistId { get; set; }
|
||||
|
||||
public Uri Link { get; set; }
|
||||
|
||||
public Uri Thumbnail { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public DateTime PublishedAt { get; set; }
|
||||
}
|
||||
}
|
||||
+12
-3
@@ -3,7 +3,9 @@ using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Podsync.Services;
|
||||
using Podsync.Services.Links;
|
||||
using Podsync.Services.Videos.YouTube;
|
||||
|
||||
namespace Podsync
|
||||
{
|
||||
@@ -16,6 +18,12 @@ namespace Podsync
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
|
||||
.AddEnvironmentVariables();
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
builder.AddUserSecrets();
|
||||
}
|
||||
|
||||
Configuration = builder.Build();
|
||||
}
|
||||
|
||||
@@ -24,8 +32,11 @@ namespace Podsync
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.Configure<PodsyncConfiguration>(Configuration.GetSection("Podsync"));
|
||||
|
||||
// Register core services
|
||||
services.AddSingleton<ILinkService, LinkService>();
|
||||
services.AddSingleton<IYouTubeClient, YouTubeClient>();
|
||||
|
||||
// Add framework services.
|
||||
services.AddMvc();
|
||||
@@ -51,9 +62,7 @@ namespace Podsync
|
||||
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute(
|
||||
name: "default",
|
||||
template: "{controller=Home}/{action=Index}/{id?}");
|
||||
routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
{
|
||||
"Logging": {
|
||||
"IncludeScopes": false,
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
}
|
||||
"Logging": {
|
||||
"IncludeScopes": false,
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
},
|
||||
|
||||
"Podsync": {
|
||||
"YouTubeApiKey": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0",
|
||||
"type": "platform"
|
||||
},
|
||||
"Google.Apis.YouTube.v3": "1.16.0.582",
|
||||
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
|
||||
"Microsoft.AspNetCore.Mvc": "1.0.0",
|
||||
"Microsoft.AspNetCore.Razor.Tools": {
|
||||
@@ -13,14 +10,19 @@
|
||||
"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.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
|
||||
"Microsoft.AspNetCore.WebUtilities": "1.0.0"
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0",
|
||||
"type": "platform"
|
||||
},
|
||||
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0"
|
||||
},
|
||||
|
||||
"tools": {
|
||||
@@ -64,5 +66,7 @@
|
||||
"scripts": {
|
||||
"prepublish": [ "bower install", "dotnet bundle" ],
|
||||
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
|
||||
}
|
||||
},
|
||||
|
||||
"userSecretsId": "aspnet-Podsync-20161004104901"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using Podsync.Services.Links;
|
||||
using Podsync.Services.Videos.YouTube;
|
||||
using Xunit;
|
||||
|
||||
namespace Podsync.Tests.Services.Videos.YouTube
|
||||
{
|
||||
public class YouTubeClientTests : TestBase, IDisposable
|
||||
{
|
||||
private readonly YouTubeClient _client;
|
||||
|
||||
public YouTubeClientTests()
|
||||
{
|
||||
_client = new YouTubeClient(new LinkService(), Options);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetChannelTest()
|
||||
{
|
||||
var query = new ChannelQuery
|
||||
{
|
||||
ChannelId = "UC0JB7TSe49lg56u6qH8y_MQ"
|
||||
};
|
||||
|
||||
var list = await _client.GetChannels(query);
|
||||
var channel = list.Single();
|
||||
|
||||
Assert.Equal(query.ChannelId, channel.ChannelId);
|
||||
Assert.Equal("GDC", channel.Title);
|
||||
Assert.False(string.IsNullOrEmpty(channel.Description));
|
||||
Assert.NotEqual(DateTime.MinValue, channel.PublishedAt);
|
||||
Assert.NotNull(channel.Thumbnail);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPlaylistsTest()
|
||||
{
|
||||
var query = new PlaylistQuery
|
||||
{
|
||||
PlaylistId = "PL2e4mYbwSTbbiX2uwspn0xiYb8_P_cTAr",
|
||||
Count = 1
|
||||
};
|
||||
|
||||
var list = await _client.GetPlaylists(query);
|
||||
var playlist = list.Single();
|
||||
|
||||
Assert.Equal("PL2e4mYbwSTbbiX2uwspn0xiYb8_P_cTAr", playlist.PlaylistId);
|
||||
Assert.Equal("UC0JB7TSe49lg56u6qH8y_MQ", playlist.ChannelId);
|
||||
Assert.Equal("GDC: Postmortems", playlist.Title);
|
||||
Assert.Equal(new Uri("https://youtube.com/playlist?list=PL2e4mYbwSTbbiX2uwspn0xiYb8_P_cTAr"), playlist.Link);
|
||||
Assert.NotNull(playlist.Thumbnail);
|
||||
Assert.Equal(new DateTime(2015, 06, 29, 16, 58, 34), playlist.PublishedAt);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetVideosTest()
|
||||
{
|
||||
var query = new VideoQuery
|
||||
{
|
||||
Id = "OlYH4gDi0Sk,kkcKnWrCZ7k"
|
||||
};
|
||||
|
||||
var response = await _client.GetVideos(query);
|
||||
var list = response as IList<Video> ?? response.ToList();
|
||||
|
||||
Assert.Equal(2, list.Count);
|
||||
|
||||
var last = list.Last();
|
||||
|
||||
Assert.Equal("kkcKnWrCZ7k", last.VideoId);
|
||||
Assert.Equal("UCS-aAvZsVegeMDfpdCPjWnA", last.ChannelId);
|
||||
Assert.Equal("Deus Ex: Mankind Divided - Full Soundtrack OST", last.Title);
|
||||
Assert.False(string.IsNullOrEmpty(last.Description));
|
||||
Assert.Equal(new TimeSpan(0, 1, 57, 28), last.Duration);
|
||||
Assert.Equal(new DateTime(2016, 8, 24, 16, 50, 34), last.PublishedAt);
|
||||
Assert.Equal(new Uri("https://youtube.com/watch?v=kkcKnWrCZ7k"), last.Link);
|
||||
Assert.True(last.Size > 0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPlaylistItemsTest()
|
||||
{
|
||||
var query = new PlaylistItemsQuery
|
||||
{
|
||||
PlaylistId = "PLWG9qzvMcoJGw9AS0XgLfrwDR2kcAMLhs",
|
||||
Count = 10
|
||||
};
|
||||
|
||||
var response = await _client.GetPlaylistItems(query);
|
||||
var list = response as IList<Video> ?? response.ToList();
|
||||
|
||||
Assert.Equal(4, list.Count);
|
||||
|
||||
foreach (var video in list)
|
||||
{
|
||||
Assert.False(string.IsNullOrEmpty(video.VideoId));
|
||||
Assert.False(string.IsNullOrEmpty(video.ChannelId));
|
||||
Assert.False(string.IsNullOrEmpty(video.PlaylistId));
|
||||
|
||||
Assert.False(string.IsNullOrEmpty(video.Title));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_client.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Podsync.Services;
|
||||
|
||||
namespace Podsync.Tests
|
||||
{
|
||||
public abstract class TestBase
|
||||
{
|
||||
private const string UserSecretsId = "aspnet-Podsync-20161004104901";
|
||||
|
||||
protected TestBase()
|
||||
{
|
||||
var configurationRoot = new ConfigurationBuilder()
|
||||
.AddUserSecrets(UserSecretsId)
|
||||
.Build();
|
||||
|
||||
var podsyncSection = configurationRoot.GetSection("Podsync");
|
||||
|
||||
var configuration = new PodsyncConfiguration();
|
||||
podsyncSection.Bind(configuration);
|
||||
|
||||
Options = new OptionsWrapper<PodsyncConfiguration>(configuration);
|
||||
}
|
||||
|
||||
protected IOptions<PodsyncConfiguration> Options { get; }
|
||||
|
||||
protected PodsyncConfiguration Configuration => Options.Value;
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,13 @@
|
||||
|
||||
"dependencies": {
|
||||
"dotnet-test-xunit": "2.2.0-preview2-build1029",
|
||||
"Microsoft.Extensions.Configuration.UserSecrets": "1.0.0",
|
||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0",
|
||||
"type": "platform"
|
||||
},
|
||||
"Moq": "4.6.38-alpha",
|
||||
"Podsync": "1.0.0-*",
|
||||
"xunit": "2.2.0-beta2-build3300"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user