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:
@@ -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; }
|
||||
|
19
src/Podsync/Services/Videos/Vimeo/Group.cs
Normal file
19
src/Podsync/Services/Videos/Vimeo/Group.cs
Normal 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; }
|
||||
}
|
||||
}
|
20
src/Podsync/Services/Videos/Vimeo/IVimeoClient.cs
Normal file
20
src/Podsync/Services/Videos/Vimeo/IVimeoClient.cs
Normal 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);
|
||||
}
|
||||
}
|
17
src/Podsync/Services/Videos/Vimeo/User.cs
Normal file
17
src/Podsync/Services/Videos/Vimeo/User.cs
Normal 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; }
|
||||
}
|
||||
}
|
21
src/Podsync/Services/Videos/Vimeo/Video.cs
Normal file
21
src/Podsync/Services/Videos/Vimeo/Video.cs
Normal 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; }
|
||||
}
|
||||
}
|
140
src/Podsync/Services/Videos/Vimeo/VimeoClient.cs
Normal file
140
src/Podsync/Services/Videos/Vimeo/VimeoClient.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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>();
|
||||
|
@@ -9,6 +9,7 @@
|
||||
},
|
||||
"Podsync": {
|
||||
"YouTubeApiKey": "",
|
||||
"VimeoApiKey": "",
|
||||
"RedisConnectionString": "localhost",
|
||||
"BaseUrl": "",
|
||||
"PatreonClientId": "",
|
||||
|
92
test/Podsync.Tests/Services/Videos/Vimeo/VimeoClientTests.cs
Normal file
92
test/Podsync.Tests/Services/Videos/Vimeo/VimeoClientTests.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user