1
0
mirror of https://github.com/mxpv/podsync.git synced 2024-05-11 05:55:04 +00:00

Implement Vimeo API client

This commit is contained in:
Maksym Pavlenko
2017-01-05 11:50:51 -08:00
parent 11003f4744
commit 0174a32602
9 changed files with 314 additions and 0 deletions

View File

@@ -6,6 +6,8 @@ namespace Podsync.Services
{
public string YouTubeApiKey { get; set; }
public string VimeoApiKey { get; set; }
public string RedisConnectionString { get; set; }
public string PatreonClientId { get; set; }

View File

@@ -0,0 +1,19 @@
using System;
namespace Podsync.Services.Videos.Vimeo
{
public class Group
{
public string Name { get; set; }
public string Description { get; set; }
public Uri Link { get; set; }
public DateTime CreatedAt { get; set; }
public Uri Thumbnail { get; set; }
public string Author { get; set; }
}
}

View File

@@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Podsync.Services.Videos.Vimeo
{
public interface IVimeoClient
{
Task<Group> Group(string id);
Task<Group> Channel(string id);
Task<User> User(string id);
Task<IEnumerable<Video>> GroupVideos(string id, int count);
Task<IEnumerable<Video>> UserVideos(string id, int count);
Task<IEnumerable<Video>> ChannelVideos(string id, int count);
}
}

View File

@@ -0,0 +1,17 @@
using System;
namespace Podsync.Services.Videos.Vimeo
{
public class User
{
public string Name { get; set; }
public string Bio { get; set; }
public DateTime CreatedAt { get; set; }
public Uri Link { get; set; }
public Uri Thumbnail { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
using System;
namespace Podsync.Services.Videos.Vimeo
{
public class Video
{
public string Title { get; set; }
public string Description { get; set; }
public Uri Link { get; set; }
public Uri Thumbnail { get; set; }
public DateTime CreatedAt { get; set; }
public long Size { get; set; }
public TimeSpan Duration { get; set; }
}
}

View File

@@ -0,0 +1,140 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
namespace Podsync.Services.Videos.Vimeo
{
// ReSharper disable once ClassNeverInstantiated.Global
public sealed class VimeoClient : IVimeoClient, IDisposable
{
private const int MaxPageSize = 100;
private readonly HttpClient _client = new HttpClient();
public VimeoClient(IOptions<PodsyncConfiguration> configuration)
{
_client.BaseAddress = new Uri("https://api.vimeo.com/");
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", configuration.Value.VimeoApiKey);
}
public Task<Group> Group(string id)
{
return QueryGroup($"groups/{id}");
}
public Task<Group> Channel(string id)
{
return QueryGroup($"channels/{id}");
}
public async Task<User> User(string id)
{
dynamic json = await QueryApi($"users/{id}");
return new User
{
Name = json.name,
Bio = json.bio,
Link = new Uri(json.link.ToString()),
Thumbnail = new Uri(json.pictures.sizes[0].link.ToString()),
CreatedAt = DateTime.Parse(json.created_time.ToString()),
};
}
public Task<IEnumerable<Video>> GroupVideos(string id, int count)
{
return QueryVideos($"groups/{id}/videos", count);
}
public Task<IEnumerable<Video>> UserVideos(string id, int count)
{
return QueryVideos($"users/{id}/videos", count);
}
public Task<IEnumerable<Video>> ChannelVideos(string id, int count)
{
return QueryVideos($"channels/{id}/videos", count);
}
public void Dispose()
{
_client.Dispose();
}
private async Task<IEnumerable<Video>> QueryVideos(string path, int count)
{
if (count <= 0)
{
throw new ArgumentException("Invalid item count", nameof(count));
}
var collection = new List<Video>(count);
var pageIndex = 1;
while (count > 0)
{
var pageSize = Math.Min(count, MaxPageSize);
await GetPage(path, pageIndex, pageSize, collection);
count -= pageSize;
pageIndex++;
}
return collection;
}
private async Task GetPage(string path, int pageIndex, int pageSize, List<Video> output)
{
dynamic resp = await QueryApi($"{path}?per_page={pageSize}&page={pageIndex}");
foreach (dynamic v in resp.data)
{
// Approximated file size
var size = Convert.ToInt64(
v.width.ToObject<long>() *
v.height.ToObject<long>() *
v.duration.ToObject<long>() *
0.38848958333);
var video = new Video
{
Title = v.name,
Description = v.description,
Link = new Uri(v.link?.ToString()),
Thumbnail = new Uri(v.pictures?.sizes[0]?.link?.ToString()),
CreatedAt = DateTime.Parse(v.created_time?.ToString()),
Duration = TimeSpan.FromSeconds(v.duration?.ToObject<int>()),
Size = size
};
output.Add(video);
}
}
private async Task<Group> QueryGroup(string path)
{
dynamic json = await QueryApi(path);
return new Group
{
Name = json.name,
Description = json.description,
Link = new Uri(json.link?.ToString()),
Thumbnail = new Uri(json.pictures?.sizes[0]?.link?.ToString()),
CreatedAt = DateTime.Parse(json.created_time?.ToString()),
Author = json.user.name,
};
}
private async Task<JObject> QueryApi(string path)
{
var json = await _client.GetStringAsync(path);
return JObject.Parse(json);
}
}
}

View File

@@ -17,6 +17,7 @@ using Podsync.Services.Links;
using Podsync.Services.Patreon;
using Podsync.Services.Resolver;
using Podsync.Services.Storage;
using Podsync.Services.Videos.Vimeo;
using Podsync.Services.Videos.YouTube;
namespace Podsync
@@ -51,6 +52,7 @@ namespace Podsync
// Register core services
services.AddSingleton<ILinkService, LinkService>();
services.AddSingleton<IYouTubeClient, YouTubeClient>();
services.AddSingleton<IVimeoClient, VimeoClient>();
services.AddSingleton<IResolverService, YtdlWrapper>();
services.AddSingleton<IStorageService, RedisStorage>();
services.AddSingleton<IRssBuilder, CompositeRssBuilder>();

View File

@@ -9,6 +9,7 @@
},
"Podsync": {
"YouTubeApiKey": "",
"VimeoApiKey": "",
"RedisConnectionString": "localhost",
"BaseUrl": "",
"PatreonClientId": "",

View File

@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Podsync.Services.Videos.Vimeo;
using Xunit;
// ReSharper disable PossibleMultipleEnumeration
namespace Podsync.Tests.Services.Videos.Vimeo
{
public class VimeoClientTests : TestBase, IDisposable
{
private readonly VimeoClient _client;
public VimeoClientTests()
{
_client = new VimeoClient(Options);
}
[Fact]
public async Task ChannelTest()
{
var channel = await _client.Channel("staffpicks");
Assert.Equal(new Uri("https://vimeo.com/channels/staffpicks"), channel.Link);
Assert.Equal("Vimeo Staff Picks", channel.Name);
Assert.Equal("Vimeo Curation", channel.Author);
Assert.False(string.IsNullOrWhiteSpace(channel.Description));
}
[Fact]
public async Task GroupTest()
{
var group = await _client.Group("motion");
Assert.Equal(new Uri("https://vimeo.com/groups/motion"), group.Link);
Assert.Equal("Motion Graphic Artists", group.Name);
Assert.Equal("Danny Garcia", group.Author);
Assert.False(string.IsNullOrWhiteSpace(group.Description));
}
[Fact]
public async Task UserTest()
{
var user = await _client.User("motionarray");
Assert.Equal("Motion Array", user.Name);
Assert.False(string.IsNullOrWhiteSpace(user.Bio));
Assert.Equal(new Uri("https://vimeo.com/motionarray"), user.Link);
}
[Fact]
public async Task GroupVideosTest()
{
var videos = await _client.GroupVideos("motion", 101);
Assert.Equal(101, videos.Count());
ValidateCollection(videos);
}
[Fact]
public async Task UserVideosTest()
{
var videos = await _client.UserVideos("motionarray", 7);
Assert.Equal(7, videos.Count());
ValidateCollection(videos);
}
[Fact]
public async Task ChannelVideosTest()
{
var videos = await _client.ChannelVideos("staffpicks", 44);
Assert.Equal(44, videos.Count());
ValidateCollection(videos);
}
public void Dispose()
{
_client.Dispose();
}
private void ValidateCollection(IEnumerable<Video> videos)
{
foreach (var video in videos)
{
Assert.False(string.IsNullOrWhiteSpace(video.Title));
Assert.True(video.Duration.TotalSeconds > 1);
Assert.True(video.Size > 0);
Assert.NotNull(video.Link);
}
}
}
}