Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search with thumbnails #5

Merged
merged 4 commits into from
Feb 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/Limbo.Integrations.Skyfish/Endpoints/SkyfishSearchEndpoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Limbo.Integrations.Skyfish.Options.Videos;
using Limbo.Integrations.Skyfish.Responses.Search;

namespace Limbo.Integrations.Skyfish.Endpoints {

public class SkyfishSearchEndpoint {

public SkyfishHttpService Service { get; }

public SkyfishSearchRawEndpoint Raw => Service.Client.Search;

public SkyfishSearchEndpoint(SkyfishHttpService service) {
Service = service;
}

public SkyfishSearchResponse Search(SkyfishSearchOptions options) {
return new(Raw.Search(options));
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using Limbo.Integrations.Skyfish.Http;
using Limbo.Integrations.Skyfish.Options.Videos;
using Skybrud.Essentials.Http;

namespace Limbo.Integrations.Skyfish.Endpoints {

public class SkyfishSearchRawEndpoint {

public SkyfishHttpClient Client { get; }

public SkyfishSearchRawEndpoint(SkyfishHttpClient client) {
Client = client;
}

#region Member methods

public IHttpResponse Search(SkyfishSearchOptions options) {
if (options == null) throw new ArgumentNullException(nameof(options));
return Client.GetResponse(options);
}

#endregion

}

}
75 changes: 41 additions & 34 deletions src/Limbo.Integrations.Skyfish/Http/SkyfishHttpClient.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System;
using System.Runtime.Caching;
using System.Threading;
using Limbo.Integrations.Skyfish.Endpoints;
using Limbo.Integrations.Skyfish.Models;
using Newtonsoft.Json.Linq;
using Skybrud.Essentials.Http;
using Skybrud.Essentials.Http.Client;
using Skybrud.Essentials.Json;
using Skybrud.Essentials.Json.Extensions;
using Skybrud.Essentials.Security;
using Skybrud.Essentials.Time.UnixTime;
Expand All @@ -22,15 +22,22 @@ public class SkyfishHttpClient : HttpClient {

public string Password { get; }

public SkyfishSearchRawEndpoint Search { get; }

private readonly string _token;

public SkyfishHttpClient() { }
public SkyfishHttpClient() {
Search = new SkyfishSearchRawEndpoint(this);
}

public SkyfishHttpClient(string apikey, string secretkey, string username, string password) {

ApiKey = apikey;
SecretKey = secretkey;
Username = username;
Password = password;

Search = new SkyfishSearchRawEndpoint(this);

_token = GetToken();
}
Expand Down Expand Up @@ -69,55 +76,55 @@ private string GetToken() {
return token;
}

public SkyfishVideo GetVideo(int videoId) {
SkyfishVideo video = GetSkyfishVideoData(videoId);
var videoStream = GetSkyfishVideo(video.VideoId);
public string GetEmbedUrl(int uniqueMediaId) {

IHttpResponse videoStreamUrl = GetSkyfishVideoStream(uniqueMediaId);
string response = "";

// if stream doesn't exist we generate it
if (videoStream.StatusCode != System.Net.HttpStatusCode.OK) {
CreateSkyfishStream(video.VideoId);
if (videoStreamUrl.StatusCode != System.Net.HttpStatusCode.OK) {
CreateSkyfishStream(uniqueMediaId);

// wait 1 sec then check if it's ready
Thread.Sleep(1000);
video = GetVideo(video);
} else {
video.EmbedUrl = "https://player.skyfish.com/?v=" + JObject.Parse(videoStream.Body).GetString("Stream") + "&media=" + video.VideoId;

// Call this method again
GetEmbedUrl(uniqueMediaId);
} else if (string.IsNullOrWhiteSpace(JObject.Parse(videoStreamUrl.Body).GetString("Stream"))) {
// for some reason they only return 404 if it's not currently generating, so any subsequent requests to see if its ready we need to parse the json body to see if it has the stream link

response = GetEmbedUrlWithRetries(uniqueMediaId, 0);
}

return video;
return response;
}

private string GetEmbedUrlWithRetries(int uniqueMediaId, int count) {
IHttpResponse videoStream = GetSkyfishVideoStream(uniqueMediaId);

private SkyfishVideo GetVideo(SkyfishVideo video) {
var videoStream = GetSkyfishVideo(video.VideoId);
// Exit condition? Only retry for 2 mins.
if (count >= 120) return null;

string response;

if (string.IsNullOrWhiteSpace(JObject.Parse(videoStream.Body).GetString("Stream"))) {
// for some reason they only return 404 if it's not currently generating, so any subsequent requests to see if its ready we need to parse the json body to see if it has the stream link

if (videoStream.StatusCode != System.Net.HttpStatusCode.OK) {
// if not ready yet, we wait 1s then query again - normally quite fast
Thread.Sleep(1000);
video = GetVideo(video);
count++;

response = GetEmbedUrlWithRetries(uniqueMediaId, count);
} else {
// for some reason they only return 404 if it's not currently generating, so any subsequent requests to see if its ready we need to parse the json body to see if it has the stream link
if (string.IsNullOrWhiteSpace(JObject.Parse(videoStream.Body).GetString("Stream"))) {
// if not ready yet, we wait 1s then query again - normally quite fast
Thread.Sleep(1000);
video = GetVideo(video);
} else {
video.EmbedUrl = "https://player.skyfish.com/?v=" + JObject.Parse(videoStream.Body).GetString("Stream") + "&media=" + video.VideoId;
}
response = "https://player.skyfish.com/?v=" + JObject.Parse(videoStream.Body).GetString("Stream") + "&media=" + uniqueMediaId;
}

return video;
}

private SkyfishVideo GetSkyfishVideoData(int videoId) {
var response = Get($"/search?media_id={videoId}&return_values=unique_media_id+height+width+title+description+thumbnail_url+thumbnail_url_ssl+filename+file_disksize+file_mimetype");
return JsonUtils.ParseJsonObject(response.Body, SkyfishVideo.Parse);
return response;
}

private void CreateSkyfishStream(int videoId) {
Post($"/media/{videoId}/stream");
private void CreateSkyfishStream(int uniqueMediaId) {
Post($"/media/{uniqueMediaId}/stream");
}

private IHttpResponse GetSkyfishVideo(int videoId) {
private IHttpResponse GetSkyfishVideoStream(int videoId) {
return Get($"/media/{videoId}/metadata/stream_url");
}

Expand Down
56 changes: 56 additions & 0 deletions src/Limbo.Integrations.Skyfish/Models/Media/SkyfishMediaItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Newtonsoft.Json.Linq;
using Skybrud.Essentials.Json;
using Skybrud.Essentials.Json.Extensions;

namespace Limbo.Integrations.Skyfish.Models.Media {

public class SkyfishMediaItem : JsonObjectBase {

#region Properties

public string[] Keywords { get; }

public int Height { get; }

public int Width { get; }

public int UniqueMediaId { get; }

public string Title { get; }

public string Description { get; }

public string ThumbnailUrl { get; }

public string ThumbnailUrlSsl { get; }

public string FileName { get; }

public string FileMimeType { get; }

public long FileDiskSize { get; }

#endregion

protected SkyfishMediaItem(JObject json) : base(json) {
Keywords = json.GetStringArray("keywords");
Height = json.GetInt32("height");
Width = json.GetInt32("width");
UniqueMediaId = json.GetInt32("unique_media_id");
Title = json.GetString("title");
Description = json.GetString("description");
ThumbnailUrl = json.GetString("thumbnail_url");
ThumbnailUrlSsl = json.GetString("thumbnail_url_ssl");
FileName = json.GetString("filename");
FileDiskSize = json.GetInt32("file_disksize");
FileMimeType = json.GetString("file_mimetype");
}

public static SkyfishMediaItem Parse(JObject json) {
return json == null ? null : new SkyfishMediaItem(json);

}

}

}
12 changes: 12 additions & 0 deletions src/Limbo.Integrations.Skyfish/Models/Media/SkyfishMediaType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Limbo.Integrations.Skyfish.Models.Media {

public enum SkyfishMediaType {
Unrecognized = -1,
Unspecified = 0,
Image,
Vector,
Video,
Generic,
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Limbo.Integrations.Skyfish.Models.Media;
using Newtonsoft.Json.Linq;
using Skybrud.Essentials.Json;
using Skybrud.Essentials.Json.Extensions;

namespace Limbo.Integrations.Skyfish.Models.Search {

public class SkyfishSearchResult : JsonObjectBase {

public int Hits { get; }

public SkyfishMediaItem[] Media { get; }

private SkyfishSearchResult(JObject json) : base(json) {
Hits = json.GetInt32("response.hits");
Media = json.GetArrayItems("response.media", SkyfishMediaItem.Parse);
}

public static SkyfishSearchResult Parse(JObject json) {
return json == null ? null : new SkyfishSearchResult(json);
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System.Collections.Generic;
using System.Linq;
using Limbo.Integrations.Skyfish.Models.Media;
using Skybrud.Essentials.Http;
using Skybrud.Essentials.Http.Collections;
using Skybrud.Essentials.Http.Options;
using Skybrud.Essentials.Strings.Extensions;

namespace Limbo.Integrations.Skyfish.Options.Videos {

/// <summary>
/// Class with options for getting a list of videos.
/// </summary>
public class SkyfishSearchOptions : IHttpRequestOptions {

#region Properties

/// <summary>
/// Gets or sets the ID of a specific media to be returned.
/// </summary>
public int MediaId { get; set; }

/// <summary>
/// Gets or sets the unique ID of a specific media to be returned.
/// </summary>
public int UniqueMediaId { get; set; }

/// <summary>
/// Gets or sets a list of values (field) to be returned for each media.
/// </summary>
public List<string> ReturnValues { get; set; }

/// <summary>
/// Gets or sets the media types to be returned.
/// </summary>
public List<SkyfishMediaType> MediaTypes { get; set; }

#endregion

#region Constructors

/// <summary>
/// Initializes a new instance with default options.
/// </summary>
public SkyfishSearchOptions() {

ReturnValues = new List<string> {
"unique_media_id",
"height",
"width",
"title",
"description",
"thumbnail_url",
"thumbnail_url_ssl",
"filename",
"file_disksize",
"file_mimetype"
};

MediaTypes = new List<SkyfishMediaType>();

}

#endregion

#region Member methods

/// <inheritdoc />
public IHttpRequest GetRequest() {

// Initialize the query string
IHttpQueryString query = new HttpQueryString();

// Append optional parameters if specified
if (MediaId > 0) query.Add("media_id", MediaId);
if (UniqueMediaId > 0) query.Add("unique_media_id", UniqueMediaId);

// The documentation says to split the values with +, but the API doesn't support URL encoded + chars
// Instead we can split by space and it turns into ASCII + chars ¯\(º_o)/¯
if (ReturnValues != null && ReturnValues.Count > 0) query.Add("return_values", string.Join(" ", ReturnValues));
if (MediaTypes != null && MediaTypes.Count > 0) query.Add("media_type", string.Join(" ", from type in MediaTypes select type.ToUnderscore()));

// Initialize a new GET request
return HttpRequest.Get("/search", query);

}

#endregion

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Skybrud.Essentials.Http;
using Limbo.Integrations.Skyfish.Models.Search;

namespace Limbo.Integrations.Skyfish.Responses.Search {

public class SkyfishSearchResponse : SkyfishResponse<SkyfishSearchResult> {

public SkyfishSearchResponse(IHttpResponse response) : base(response) {
Body = ParseJsonObject(response.Body, SkyfishSearchResult.Parse);
}

}

}
Loading