diff --git a/README.md b/README.md index 6476f52..9be61ee 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +## Archived. +### This repo was made to improve TenorSharp nad move it to V2. We decided to to simply rewrite our own wrapper with no dependencies instead. + # TenorSharp ![Build Status](https://img.shields.io/github/workflow/status/OmegaRogue/TenorSharp/.NET%20Core) [![GNU LGPL licensed](https://img.shields.io/github/license/OmegaRogue/TenorSharp)](COPYING.LESSER) diff --git a/TenorSharp.Tests/IntegrationTests.cs b/TenorSharp.Tests/IntegrationTests.cs index 1a3f023..502c093 100644 --- a/TenorSharp.Tests/IntegrationTests.cs +++ b/TenorSharp.Tests/IntegrationTests.cs @@ -1,464 +1,465 @@ -using System; -using System.Linq; -using System.Threading.Tasks; - -using TenorSharp.Enums; - -using Xunit; -using Xunit.Abstractions; - -using Type = TenorSharp.Enums.Type; - -namespace TenorSharp.Tests; - -public class IntegrationTests -{ - private const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - private static readonly Random Random = new(); - private static readonly string ApiKey = Environment.GetEnvironmentVariable("TENOR_TEST_API_KEY"); - private readonly TenorClient _client = new(ApiKey, mediaFilter: MediaFilter.basic); - - - private readonly ITestOutputHelper _testOutputHelper; - - public IntegrationTests(ITestOutputHelper testOutputHelper) => _testOutputHelper = testOutputHelper; - - private static string RndString(int len) - => new(Enumerable.Range(1, len).Select(_ => Chars[Random.Next(Chars.Length)]).ToArray()); - - private static string RndLenString() - { - var len = Random.Next(); - return RndString(len); - } - - [Fact] - public void TestSearch() - { - var anonId = RndString(18); - var q = RndString(10); - var limit = Random.Next(1, 50); - var pos = Random.Next(); - try - { - _client.NewSession(anonId); - _client.Search(q, limit, pos); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine($"anonId: {anonId}\n" + - $"q: {q}\n" + - $"limit: {limit}\n" + - $"pos: {pos}"); - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - [Fact] - public async Task TestSearchAsync() - { - var anonId = RndString(18); - var q = RndString(10); - var limit = Random.Next(1, 50); - var pos = Random.Next(); - try - { - _client.NewSession(anonId); - await _client.SearchAsync(q, limit, pos); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine($"anonId: {anonId}\n" + - $"q: {q}\n" + - $"limit: {limit}\n" + - $"pos: {pos}"); - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public void TestTrending() - { - try - { - _client.NewSession(RndString(18)); - _client.Trending(); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - [Fact] - public async Task TestTrendingAsync() - { - try - { - _client.NewSession(RndString(18)); - await _client.TrendingAsync(); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public void TestCategoriesEmoji() - { - try - { - _client.NewSession(RndString(18)); - _client.Categories(Type.emoji); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public async Task TestCategoriesEmojiAsync() - { - try - { - _client.NewSession(RndString(18)); - await _client.CategoriesAsync(Type.emoji); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public void TestCategoriesFeatured() - { - try - { - _client.NewSession(RndString(18)); - _client.Categories(); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public async Task TestCategoriesFeaturedAsync() - { - try - { - _client.NewSession(RndString(18)); - await _client.CategoriesAsync(); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public void TestCategoriesTrending() - { - try - { - _client.NewSession(RndString(18)); - _client.Categories(Type.trending); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public async Task TestCategoriesTrendingAsync() - { - try - { - _client.NewSession(RndString(18)); - await _client.CategoriesAsync(Type.trending); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public void TestAutoComplete() - { - try - { - _client.NewSession(RndString(18)); - _client.AutoComplete(RndString(10), Random.Next(50)); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public async Task TestAutoCompleteAsync() - { - try - { - _client.NewSession(RndString(18)); - await _client.AutoCompleteAsync(RndString(10), Random.Next(50)); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public void TestGetGifs() - { - var anonId = RndString(18); - var limit = Random.Next(1, 50); - var pos = Random.Next(10); - try - { - _client.NewSession(anonId); - var result = _client.Search("test", limit, pos); - - _client.GetGifs(limit, pos, result.GifResults.Select(o => o.Id).ToArray()); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public async Task TestGetGifsAsync() - { - var anonId = RndString(18); - var limit = Random.Next(1, 50); - var pos = Random.Next(10); - try - { - _client.NewSession(anonId); - var result = await _client.SearchAsync("test", limit, pos); - - await _client.GetGifsAsync(limit, pos, result.GifResults.Select(o => o.Id).ToArray()); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public void TestRegisterShare() - { - var anonId = RndString(18); - var limit = Random.Next(1, 50); - var pos = Random.Next(10); - try - { - _client.NewSession(anonId); - var result = _client.Search("test", limit, pos); - var id = result.GifResults.First().Id; - - _client.RegisterShare(id, "test"); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public async Task TestRegisterShareAsync() - { - var anonId = RndString(18); - var limit = Random.Next(1, 50); - var pos = Random.Next(10); - try - { - _client.NewSession(anonId); - var result = await _client.SearchAsync("test", limit, pos); - var id = result.GifResults.First().Id; - - await _client.RegisterShareAsync(id, "test"); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public void TestSearchSuggestions() - { - var anonId = RndString(18); - var q = RndString(10); - var limit = Random.Next(1, 50); - try - { - _client.NewSession(anonId); - - _client.SearchSuggestions(q, limit); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public async Task TestSearchSuggestionsAsync() - { - var anonId = RndString(18); - var q = RndString(10); - var limit = Random.Next(1, 50); - try - { - _client.NewSession(anonId); - - await _client.SearchSuggestionsAsync(q, limit); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public void TestTrendingTerms() - { - var anonId = RndString(18); - var limit = Random.Next(1, 50); - try - { - _client.NewSession(anonId); - - _client.TrendingTerms(limit); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine($"anonId: {anonId}\n" + - $"limit: {limit}"); - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public async Task TestTrendingTermsAsync() - { - var anonId = RndString(18); - var limit = Random.Next(1, 50); - try - { - _client.NewSession(anonId); - - await _client.TrendingTermsAsync(limit); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine($"anonId: {anonId}\n" + - $"limit: {limit}"); - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public void TestGetRandomGifs() - { - var anonId = RndString(18); - var q = RndString(10); - var limit = Random.Next(1, 50); - var pos = Random.Next(10); - try - { - _client.NewSession(anonId); - _client.GetRandomGifs(q, limit, pos); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine($"anonId: {anonId}\n" + - $"q: {q}\n" + - $"limit: {limit}\n" + - $"pos: {pos}"); - _testOutputHelper.WriteLine(e.ToString()); - - throw; - } - } - - [Fact] - public async Task TestGetRandomGifsAsync() - { - var anonId = RndString(18); - var q = RndString(10); - var limit = Random.Next(1, 50); - var pos = Random.Next(10); - try - { - _client.NewSession(anonId); - await _client.GetRandomGifsAsync(q, limit, pos); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine($"anonId: {anonId}\n" + - $"q: {q}\n" + - $"limit: {limit}\n" + - $"pos: {pos}"); - _testOutputHelper.WriteLine(e.ToString()); - - throw; - } - } - - [Fact] - public void TestGetNewAnonId() - { - try - { - _client.GetNewAnonId(); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } - - [Fact] - public async Task TestGetNewAnonIdAsync() - { - try - { - await _client.GetNewAnonIdAsync(); - } - catch (TenorException e) - { - _testOutputHelper.WriteLine(e.ToString()); - throw; - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +using TenorSharp.Enums; + +using Xunit; +using Xunit.Abstractions; + +using Type = TenorSharp.Enums.Type; + +namespace TenorSharp.Tests; + +public class IntegrationTests +{ + private const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static readonly Random Random = new(); + private static readonly string ApiKey = Environment.GetEnvironmentVariable("TENOR_TEST_API_KEY"); + private readonly TenorClient _client = new(ApiKey, mediaFilter: new List()); + + + private readonly ITestOutputHelper _testOutputHelper; + + public IntegrationTests(ITestOutputHelper testOutputHelper) => _testOutputHelper = testOutputHelper; + + private static string RndString(int len) + => new(Enumerable.Range(1, len).Select(_ => Chars[Random.Next(Chars.Length)]).ToArray()); + + private static string RndLenString() + { + var len = Random.Next(); + return RndString(len); + } + + [Fact] + public void TestSearch() + { + var anonId = RndString(18); + var q = RndString(10); + var limit = Random.Next(1, 50); + var pos = Random.Next(); + try + { + _client.NewSession(anonId); + _client.Search(q, limit, pos); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine($"anonId: {anonId}\n" + + $"q: {q}\n" + + $"limit: {limit}\n" + + $"pos: {pos}"); + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + [Fact] + public async Task TestSearchAsync() + { + var anonId = RndString(18); + var q = RndString(10); + var limit = Random.Next(1, 50); + var pos = Random.Next(); + try + { + _client.NewSession(anonId); + await _client.SearchAsync(q, limit, pos); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine($"anonId: {anonId}\n" + + $"q: {q}\n" + + $"limit: {limit}\n" + + $"pos: {pos}"); + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public void TestTrending() + { + try + { + _client.NewSession(RndString(18)); + _client.Trending(); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + [Fact] + public async Task TestTrendingAsync() + { + try + { + _client.NewSession(RndString(18)); + await _client.TrendingAsync(); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public void TestCategoriesEmoji() + { + try + { + _client.NewSession(RndString(18)); + _client.Categories(Type.emoji); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public async Task TestCategoriesEmojiAsync() + { + try + { + _client.NewSession(RndString(18)); + await _client.CategoriesAsync(Type.emoji); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public void TestCategoriesFeatured() + { + try + { + _client.NewSession(RndString(18)); + _client.Categories(); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public async Task TestCategoriesFeaturedAsync() + { + try + { + _client.NewSession(RndString(18)); + await _client.CategoriesAsync(); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public void TestCategoriesTrending() + { + try + { + _client.NewSession(RndString(18)); + _client.Categories(Type.trending); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public async Task TestCategoriesTrendingAsync() + { + try + { + _client.NewSession(RndString(18)); + await _client.CategoriesAsync(Type.trending); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public void TestAutoComplete() + { + try + { + _client.NewSession(RndString(18)); + _client.AutoComplete(RndString(10), Random.Next(50)); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public async Task TestAutoCompleteAsync() + { + try + { + _client.NewSession(RndString(18)); + await _client.AutoCompleteAsync(RndString(10), Random.Next(50)); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public void TestGetGifs() + { + var anonId = RndString(18); + var limit = Random.Next(1, 50); + var pos = Random.Next(10); + try + { + _client.NewSession(anonId); + var result = _client.Search("test", limit, pos); + + _client.GetGifs(limit, pos, result.GifResults.Select(o => o.Id).ToArray()); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public async Task TestGetGifsAsync() + { + var anonId = RndString(18); + var limit = Random.Next(1, 50); + var pos = Random.Next(10); + try + { + _client.NewSession(anonId); + var result = await _client.SearchAsync("test", limit, pos); + + await _client.GetGifsAsync(limit, pos, result.GifResults.Select(o => o.Id).ToArray()); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public void TestRegisterShare() + { + var anonId = RndString(18); + var limit = Random.Next(1, 50); + var pos = Random.Next(10); + try + { + _client.NewSession(anonId); + var result = _client.Search("test", limit, pos); + var id = result.GifResults.First().Id; + + _client.RegisterShare(id, "test"); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public async Task TestRegisterShareAsync() + { + var anonId = RndString(18); + var limit = Random.Next(1, 50); + var pos = Random.Next(10); + try + { + _client.NewSession(anonId); + var result = await _client.SearchAsync("test", limit, pos); + var id = result.GifResults.First().Id; + + await _client.RegisterShareAsync(id, "test"); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public void TestSearchSuggestions() + { + var anonId = RndString(18); + var q = RndString(10); + var limit = Random.Next(1, 50); + try + { + _client.NewSession(anonId); + + _client.SearchSuggestions(q, limit); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public async Task TestSearchSuggestionsAsync() + { + var anonId = RndString(18); + var q = RndString(10); + var limit = Random.Next(1, 50); + try + { + _client.NewSession(anonId); + + await _client.SearchSuggestionsAsync(q, limit); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public void TestTrendingTerms() + { + var anonId = RndString(18); + var limit = Random.Next(1, 50); + try + { + _client.NewSession(anonId); + + _client.TrendingTerms(limit); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine($"anonId: {anonId}\n" + + $"limit: {limit}"); + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public async Task TestTrendingTermsAsync() + { + var anonId = RndString(18); + var limit = Random.Next(1, 50); + try + { + _client.NewSession(anonId); + + await _client.TrendingTermsAsync(limit); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine($"anonId: {anonId}\n" + + $"limit: {limit}"); + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public void TestGetRandomGifs() + { + var anonId = RndString(18); + var q = RndString(10); + var limit = Random.Next(1, 50); + var pos = Random.Next(10); + try + { + _client.NewSession(anonId); + _client.GetRandomGifs(q, limit, pos); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine($"anonId: {anonId}\n" + + $"q: {q}\n" + + $"limit: {limit}\n" + + $"pos: {pos}"); + _testOutputHelper.WriteLine(e.ToString()); + + throw; + } + } + + [Fact] + public async Task TestGetRandomGifsAsync() + { + var anonId = RndString(18); + var q = RndString(10); + var limit = Random.Next(1, 50); + var pos = Random.Next(10); + try + { + _client.NewSession(anonId); + await _client.GetRandomGifsAsync(q, limit, pos); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine($"anonId: {anonId}\n" + + $"q: {q}\n" + + $"limit: {limit}\n" + + $"pos: {pos}"); + _testOutputHelper.WriteLine(e.ToString()); + + throw; + } + } + + [Fact] + public void TestGetNewAnonId() + { + try + { + _client.GetNewAnonId(); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } + + [Fact] + public async Task TestGetNewAnonIdAsync() + { + try + { + await _client.GetNewAnonIdAsync(); + } + catch (TenorException e) + { + _testOutputHelper.WriteLine(e.ToString()); + throw; + } + } } \ No newline at end of file diff --git a/TenorSharp/Endpoints.cs b/TenorSharp/Endpoints.cs index b526685..ebb79f7 100644 --- a/TenorSharp/Endpoints.cs +++ b/TenorSharp/Endpoints.cs @@ -1,72 +1,72 @@ -namespace TenorSharp; - -public static class Endpoints -{ - /// - /// Get a json object containing a list of the most relevant GIFs for a given search term(s), category(ies), emoji(s), - /// or any combination thereof. - /// - public const string Search = "search"; - - /// - /// Get a json object containing a list of the current global trending GIFs. The trending stream is updated regularly - /// throughout the day. - /// - public const string Trending = "trending"; - - /// - /// Get a json object containing a list of GIF categories associated with the provided type. - /// Each category will include a corresponding search URL to be used if the user clicks on the category. - /// The search URL will include the apikey, anonymous id, and locale that were used on the original call to the - /// categories endpoint. - /// Supported types: - /// featured (default) - The current featured emotional / reaction based GIF categories including a preview GIF for - /// each term. - /// emoji - The current featured emoji GIF categories - /// trending - The current trending search terms including a preview GIF for each term. - /// - public const string Categories = "categories"; - - /// - /// Get a json object containing a list of alternative search terms given a search term. - /// SearchAsync suggestions helps a user narrow their search or discover related search terms to find a more precise GIF. - /// Results are returned in order of what is most likely to drive a share for a given term, based on historic user - /// search and share behavior. - /// - public const string SearchSuggestions = "search_suggestions"; - - /// - /// Get a json object containing a list of completed search terms given a partial search term. - /// The list is sorted by Tenor’s AI and the number of results will decrease as Tenor’s AI becomes more certain. - /// - public const string Autocomplete = "autocomplete"; - - /// - /// Get a json object containing a list of the current trending search terms. - /// The list is updated Hourly by Tenor’s AI. - /// - public const string TrendingTerms = "trending_terms"; - - /// - /// Register a user’s sharing of a GIF. - /// - public const string RegisterShare = "registershare"; - - /// - /// Get the GIF(s) for the corresponding id(s) - /// - public const string Gifs = "gifs"; - - /// - /// Get an anonymous ID for a new user. - /// Store the ID in the client's cache for use on any additional API calls made by the user, either in this session or - /// any future sessions. - /// - public const string AnonId = "anonid"; - - /// - /// Get a randomized list of GIFs for a given search term. - /// This differs from the search endpoint which returns a rank ordered list of GIFs for a given search term. - /// - public const string Random = "random"; +namespace TenorSharp; + +public static class Endpoints +{ + /// + /// Get a json object containing a list of the most relevant GIFs for a given search term(s), category(ies), emoji(s), + /// or any combination thereof. + /// + public const string Search = "search"; + + /// + /// Get a json object containing a list of the current global trending GIFs. The trending stream is updated regularly + /// throughout the day. + /// + public const string Trending = "trending"; + + /// + /// Get a json object containing a list of GIF categories associated with the provided type. + /// Each category will include a corresponding search URL to be used if the user clicks on the category. + /// The search URL will include the apikey, anonymous id, and locale that were used on the original call to the + /// categories endpoint. + /// Supported types: + /// featured (default) - The current featured emotional / reaction based GIF categories including a preview GIF for + /// each term. + /// emoji - The current featured emoji GIF categories + /// trending - The current trending search terms including a preview GIF for each term. + /// + public const string Categories = "categories"; + + /// + /// Get a json object containing a list of alternative search terms given a search term. + /// SearchAsync suggestions helps a user narrow their search or discover related search terms to find a more precise GIF. + /// Results are returned in order of what is most likely to drive a share for a given term, based on historic user + /// search and share behavior. + /// + public const string SearchSuggestions = "search_suggestions"; + + /// + /// Get a json object containing a list of completed search terms given a partial search term. + /// The list is sorted by Tenor’s AI and the number of results will decrease as Tenor’s AI becomes more certain. + /// + public const string Autocomplete = "autocomplete"; + + /// + /// Get a json object containing a list of the current trending search terms. + /// The list is updated Hourly by Tenor’s AI. + /// + public const string TrendingTerms = "trending_terms"; + + /// + /// Register a user’s sharing of a GIF. + /// + public const string RegisterShare = "registershare"; + + /// + /// Get the GIF(s) for the corresponding id(s) + /// + public const string Gifs = "posts"; + + /// + /// Get an anonymous ID for a new user. + /// Store the ID in the client's cache for use on any additional API calls made by the user, either in this session or + /// any future sessions. + /// + public const string AnonId = "anonid"; + + /// + /// Get a randomized list of GIFs for a given search term. + /// This differs from the search endpoint which returns a rank ordered list of GIFs for a given search term. + /// + public const string Random = "random"; } \ No newline at end of file diff --git a/TenorSharp/Enums/GifFormat.cs b/TenorSharp/Enums/GifFormat.cs index d2ee664..0bac74f 100644 --- a/TenorSharp/Enums/GifFormat.cs +++ b/TenorSharp/Enums/GifFormat.cs @@ -1,142 +1,98 @@ -// ReSharper disable InconsistentNaming - -namespace TenorSharp.Enums; - -/// -/// Tenor’s API offers 3 different base formats -- GIF, MP4, and webm -- in a variety of sizes. -/// The MP4 and webm formats will play the clip once -- except for the loopedmp4, which will play the clip a few times. -/// The GIF format will play the clip on a continuous loop. -/// -public enum GifFormat -{ - /// - /// Resolution and size: High quality GIF format, largest file size available - /// Dimensions: Original upload dimensions (no limits) - /// Usage Notes: Use this size for GIF shares on desktop - /// Media Filters supported: default, basic, minimal - /// - gif, - /// - /// Resolution and size: High quality GIF sticker format, largest file size available - /// Dimensions: Original upload dimensions (no limits) - /// Usage Notes: Use this size for sticker shares for high bandwidth users - /// Media Filters supported: default - /// - gif_transparent, - - /// - /// Resolution and size: small reduction in size of the GIF format - /// Dimensions: Original upload dimensions (no limits) but much higher compression rate - /// Usage Notes: Use this size for GIF previews on desktop - /// Media Filters supported: default - /// - mediumgif, - - /// - /// Resolution and size: reduced size of the GIF format - /// Dimensions: Up to 220 pixels wide, Height scaled with aspect ratio preserved - /// Usage Notes: Use this size for GIF previews and shares on mobile - /// Media Filters supported: default, basic, minimal - /// - tinygif, - /// - /// Resolution and size: educed size of the GIF sticker format, max size of 500KB - /// Dimensions: Up to 220X220 pixels, height scaled with aspect ratio preserved - /// Usage Notes: Use this size for sticker previews for high bandwidth users and shares for low bandwidth users - /// Media Filters supported: default - /// - tinygif_transparent, - - /// - /// Resolution and size: smallest size of the GIF format - /// Dimensions: Up to 90 pixels tall, Width scaled with aspect ratio preserved - /// Usage Notes: Use this size for GIF previews on mobile - /// Media Filters supported: default, basic - /// - nanogif, - /// - /// Resolution and size: smallest size of the GIF sticker format, max size of 100KB - /// Dimensions: Up to 90X90 pixels, width scaled with aspect ratio preserved - /// Usage Notes: Use this size for sticker previews for low bandwidth users - /// Media Filters supported: default - /// - nanogif_transparent, - - /// - /// Resolution and size: High quality webp sticker format, largest file size available - /// Dimensions: Original upload dimensions (no limits) - /// Usage Notes: Use this size for sticker shares for high bandwidth users. - /// Media Filters supported: default - /// - webp_transparent, - /// - /// Resolution and size: reduced size of the webp sticker format, max size of 500KB - /// Dimensions: Up to 220X220 pixels, height scaled with aspect ratio preserved - /// Usage Notes: Use this size for sticker previews for high bandwidth users and shares for low bandwidth users - /// Media Filters supported: default - /// - tinywebp_transparent, - /// - /// Resolution and size: smallest size of the webp sticker format, max size of 100KB - /// Dimensions: Up to 90X90 pixels, width scaled with aspect ratio preserved - /// Usage Notes: Use this size for sticker previews for low bandwidth users - /// Media Filters supported: default - /// - nanowebp_transparent, - - /// - /// Resolution and size: highest quality video format, largest of the video formats, but smaller than GIF - /// Dimensions: Similar to gif, but padded to fit video container specifications (usually 8-pixel increments) - /// Usage Notes: Use this size for MP4 previews and shares on desktop - /// Media Filters supported: default, basic, minimal - /// - mp4, - - /// - /// Resolution and size: highest quality video format, larger in size than mp4 - /// Dimensions: Same as mp4 - /// Usage Notes: Use this size for mp4 shares if you want the video clip to run a few times rather than only once - /// Media Filters supported: default - /// - loopedmp4, - - /// - /// Resolution and size: reduced size of the mp4 format - /// Dimensions: Variable width and height, with maximum bounding box of 320x320 - /// Usage Notes: Use this size for mp4 previews and shares on mobile - /// Media Filters supported: default, basic - /// - tinymp4, - - /// - /// Resolution and size: smallest size of the mp4 format - /// Dimensions: Variable width and height, with maximum bounding box of 150x150 - /// Usage Notes: Use this size for mp4 previews on mobile - /// Media Filters supported: default, basic - /// - nanomp4, - - /// - /// Resolution and size: Lower quality video format, smaller in size than MP4 - /// Dimensions: Same as mp4 - /// Usage Notes: Use this size for webm previews and shares on desktop - /// Media Filters supported: default - /// - webm, - - /// - /// Resolution and size: reduced size of the webm format - /// Dimensions: Same as tinymp4 - /// Usage Notes: Use this size for GIF shares on mobile - /// Media Filters supported: default - /// - tinywebm, - - /// - /// Resolution and size: smallest size of the webm format - /// Dimensions: Same as nanomp4 - /// Usage Notes: Use this size for GIF previews on mobile - /// Media Filters supported: default - /// - nanowebm +// ReSharper disable InconsistentNaming + +namespace TenorSharp.Enums; + +/// +/// Tenor’s API offers 3 different base formats -- GIF, MP4, and webm -- in a variety of sizes. +/// The MP4 and webm formats will play the clip once -- except for the loopedmp4, which will play the clip a few times. +/// The GIF format will play the clip on a continuous loop. +/// +public enum GifFormat +{ + /// + /// Resolution and size: High quality GIF format, largest file size available + /// Dimensions: Original upload dimensions (no limits) + /// Usage Notes: Use this size for GIF shares on desktop + /// Media Filters supported: default, basic, minimal + /// + gif, + /// + /// Resolution and size: small reduction in size of the GIF format + /// Dimensions: Original upload dimensions (no limits) but much higher compression rate + /// Usage Notes: Use this size for GIF previews on desktop + /// Media Filters supported: default + /// + mediumgif, + + /// + /// Resolution and size: reduced size of the GIF format + /// Dimensions: Up to 220 pixels wide, Height scaled with aspect ratio preserved + /// Usage Notes: Use this size for GIF previews and shares on mobile + /// Media Filters supported: default, basic, minimal + /// + tinygif, + + /// + /// Resolution and size: smallest size of the GIF format + /// Dimensions: Up to 90 pixels tall, Width scaled with aspect ratio preserved + /// Usage Notes: Use this size for GIF previews on mobile + /// Media Filters supported: default, basic + /// + nanogif, + + /// + /// Resolution and size: highest quality video format, largest of the video formats, but smaller than GIF + /// Dimensions: Similar to gif, but padded to fit video container specifications (usually 8-pixel increments) + /// Usage Notes: Use this size for MP4 previews and shares on desktop + /// Media Filters supported: default, basic, minimal + /// + mp4, + + /// + /// Resolution and size: highest quality video format, larger in size than mp4 + /// Dimensions: Same as mp4 + /// Usage Notes: Use this size for mp4 shares if you want the video clip to run a few times rather than only once + /// Media Filters supported: default + /// + loopedmp4, + + /// + /// Resolution and size: reduced size of the mp4 format + /// Dimensions: Variable width and height, with maximum bounding box of 320x320 + /// Usage Notes: Use this size for mp4 previews and shares on mobile + /// Media Filters supported: default, basic + /// + tinymp4, + + /// + /// Resolution and size: smallest size of the mp4 format + /// Dimensions: Variable width and height, with maximum bounding box of 150x150 + /// Usage Notes: Use this size for mp4 previews on mobile + /// Media Filters supported: default, basic + /// + nanomp4, + + /// + /// Resolution and size: Lower quality video format, smaller in size than MP4 + /// Dimensions: Same as mp4 + /// Usage Notes: Use this size for webm previews and shares on desktop + /// Media Filters supported: default + /// + webm, + + /// + /// Resolution and size: reduced size of the webm format + /// Dimensions: Same as tinymp4 + /// Usage Notes: Use this size for GIF shares on mobile + /// Media Filters supported: default + /// + tinywebm, + + /// + /// Resolution and size: smallest size of the webm format + /// Dimensions: Same as nanomp4 + /// Usage Notes: Use this size for GIF previews on mobile + /// Media Filters supported: default + /// + nanowebm } \ No newline at end of file diff --git a/TenorSharp/Enums/MediaFilter.cs b/TenorSharp/Enums/MediaFilter.cs deleted file mode 100644 index a9286d3..0000000 --- a/TenorSharp/Enums/MediaFilter.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace TenorSharp.Enums; - -// ReSharper disable InconsistentNaming -/// -/// Reduce the Number of GIF formats returned in the GIF_OBJECT list. -/// -public enum MediaFilter -{ - /// - /// nanomp4, tinygif, tinymp4, gif, mp4, and nanogif - /// - basic, - - /// - /// tinygif, gif, and mp4 - /// - minimal, - - /// - /// the default value - /// - off -} \ No newline at end of file diff --git a/TenorSharp/ResponseObjects/CategoryObject.cs b/TenorSharp/ResponseObjects/CategoryObject.cs index 641b182..3bd2953 100644 --- a/TenorSharp/ResponseObjects/CategoryObject.cs +++ b/TenorSharp/ResponseObjects/CategoryObject.cs @@ -1,33 +1,35 @@ -using System; - -using Newtonsoft.Json; - -namespace TenorSharp.ResponseObjects; - -public class CategoryObject -{ - /// - /// a url to the media source for the category’s example GIF - /// - [JsonProperty("image")] - public Uri Image; - - /// - /// Category name to overlay over the image. The name will be translated to match the locale of the corresponding - /// request - /// - [JsonProperty("name")] - public string Name; - - /// - /// the search url to request if the user selects the category - /// - [JsonProperty("path")] - public Uri Path; - - /// - /// The english search term that corresponds to the category - /// - [JsonProperty("searchterm")] - public string SearchTerm; +using System; + +using System.Text.Json; +using System.Text.Json.Serialization; +using Newtonsoft.Json; + +namespace TenorSharp.ResponseObjects; + +public class CategoryObject +{ + /// + /// The english search term that corresponds to the category + /// + [JsonPropertyName("searchterm")] + public string SearchTerm { get; set; } + + /// + /// the search url to request if the user selects the category + /// + [JsonPropertyName("path")] + public string Path { get; set; } + + /// + /// a url to the media source for the category’s example GIF + /// + [JsonPropertyName("image")] + public string Image { get; set; } + + /// + /// Category name to overlay over the image. The name will be translated to match the locale of the corresponding + /// request + /// + [JsonPropertyName("name")] + public string Name { get; set; } } \ No newline at end of file diff --git a/TenorSharp/ResponseObjects/GifObject.cs b/TenorSharp/ResponseObjects/GifObject.cs index 696feaf..c28e306 100644 --- a/TenorSharp/ResponseObjects/GifObject.cs +++ b/TenorSharp/ResponseObjects/GifObject.cs @@ -1,72 +1,93 @@ -using System; -using System.Collections.Generic; - -using Newtonsoft.Json; - -using TenorSharp.Enums; - -namespace TenorSharp.ResponseObjects; - -public class GifObject -{ - /// - /// a unix timestamp representing when this post was created. - /// - [JsonProperty("created")] - public double Created; - - /// - /// true if this post contains audio (only video formats support audio, the gif image file format can not contain audio - /// information). - /// - [JsonProperty("hasaudio")] - public bool HasAudio; - - /// - /// true if this post contains captions - /// - [JsonProperty("hascaption")] - public bool HasCaption; - - /// - /// Tenor result identifier - /// - [JsonProperty("id")] - public string Id; - - /// - /// the full URL to view the post on tenor.com. - /// - [JsonProperty("itemurl")] - public Uri ItemUrl; - - /// - /// An array of dictionaries with GifFormat as the key and MediaObject as the value - /// - [JsonProperty("media")] - public Dictionary[] Media; - - /// - /// the amount of Shares the post has. - /// - [JsonProperty("shares")] - public int Shares; - - /// - /// an array of tags for the post - /// - [JsonProperty("tags")] - public string[] Tags; - - /// - /// the title of the post. - /// - [JsonProperty("title")] - public string Title; - - /// - /// a short URL to view the post on tenor.com. - /// - [JsonProperty("url")] - public Uri Url; +using System; +using System.Collections.Generic; + +using System.Text.Json; +using System.Text.Json.Serialization; +using TenorSharp.Enums; + +namespace TenorSharp.ResponseObjects; + +public class GifObject +{ + /// + /// Tenor result identifier + /// + [JsonPropertyName("id")] + public string Id { get; set; } + + /// + /// the title of the post. + /// + [JsonPropertyName("title")] + public string Title { get; set; } + + /// + /// An array of dictionaries with GifFormat as the key and MediaObject as the value + /// + [JsonPropertyName("media_formats")] + public Dictionary Media { get; set; } + + /// + /// a unix timestamp representing when this post was created. + /// + [JsonPropertyName("created")] + public float Created { get; set; } + + /// + /// true if this post contains audio (only video formats support audio, the gif image file format can not contain audio + /// information). + /// + [JsonPropertyName("hasaudio")] + public bool HasAudio { get; set; } + + /// + /// an array of tags for the post + /// + [JsonPropertyName("tags")] + public string[] Tags { get; set; } + + /// + /// the description of the post. + /// + [JsonPropertyName("content_description")] + public string Description { get; set; } + + /// + /// the full URL to view the post on tenor.com. + /// + [JsonPropertyName("itemurl")] + public string ItemUrl { get; set; } + + /// + /// returns true if this post contains captions. + /// + [JsonPropertyName("hascaption")] + public bool HasCaption { get; set; } + + /// + /// an array of flags for the post + /// + [JsonPropertyName("flags")] + public string[] Flags { get; set; } + + /// + /// the most common background pixel color of the content + /// + [JsonPropertyName("bg_color")] + public string BackgroundColor { get; set; } + + /// + /// a short URL to view the post on tenor.com. + /// + [JsonPropertyName("url")] + public string Url { get; set; } + + /// + /// Returns the media object for the given format + /// + public MediaObject GetMediaType(GifFormat format) + { + Media.TryGetValue(format.ToString(), out var media); + return media; + } } \ No newline at end of file diff --git a/TenorSharp/ResponseObjects/MediaObject.cs b/TenorSharp/ResponseObjects/MediaObject.cs index beb040d..da53ba8 100644 --- a/TenorSharp/ResponseObjects/MediaObject.cs +++ b/TenorSharp/ResponseObjects/MediaObject.cs @@ -1,32 +1,33 @@ -using System; - -using Newtonsoft.Json; - -namespace TenorSharp.ResponseObjects; - -public class MediaObject -{ - /// - /// width and height in pixels - /// - [JsonProperty("dims")] - public int[] Dims; - - /// - /// a url to a preview image of the media source - /// - [JsonProperty("preview")] - public string Preview; - - /// - /// size of file in bytes - /// - [JsonProperty("size")] - public int Size; - - /// - /// a url to the media source - /// - [JsonProperty("url")] - public Uri Url; +using System; + +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace TenorSharp.ResponseObjects; + +public class MediaObject +{ + /// + /// a url to a preview image of the media source + /// + [JsonPropertyName("preview")] + public string Preview { get; set; } + + /// + /// a url to the media source + /// + [JsonPropertyName("url")] + public string Url { get; set; } + + /// + /// width and height in pixels + /// + [JsonPropertyName("dims")] + public int[] Dims { get; set; } + + /// + /// size of file in bytes + /// + [JsonPropertyName("size")] + public int Size { get; set; } } \ No newline at end of file diff --git a/TenorSharp/SearchResults/Category.cs b/TenorSharp/SearchResults/Category.cs index c70b7fc..53ec288 100644 --- a/TenorSharp/SearchResults/Category.cs +++ b/TenorSharp/SearchResults/Category.cs @@ -1,14 +1,14 @@ -using Newtonsoft.Json; - -using TenorSharp.ResponseObjects; - -namespace TenorSharp.SearchResults; - -public class Category -{ - /// - /// an array of CategoryObjects where the “name” field has been translated to the passed in locale language. - /// - [JsonProperty("tags", Required = Required.Always)] - public CategoryObject[] Tags { get; set; } +using System.Text.Json.Serialization; + +using TenorSharp.ResponseObjects; + +namespace TenorSharp.SearchResults; + +public class Category +{ + /// + /// an array of CategoryObjects where the “name” field has been translated to the passed in locale language. + /// + [JsonPropertyName("tags")] + public CategoryObject[] Tags { get; set; } } \ No newline at end of file diff --git a/TenorSharp/SearchResults/Gif.cs b/TenorSharp/SearchResults/Gif.cs index 634f988..f007f06 100644 --- a/TenorSharp/SearchResults/Gif.cs +++ b/TenorSharp/SearchResults/Gif.cs @@ -1,51 +1,51 @@ -using System.Threading.Tasks; - -using Newtonsoft.Json; - -using TenorSharp.Enums; -using TenorSharp.ResponseObjects; - -namespace TenorSharp.SearchResults; - -public class Gif -{ - internal TenorClient Client; - internal int Count; - internal string[] Ids; - internal string Term; - - internal SearchTypes Type; - - /// - /// a position identifier to use with the next API query to retrieve the next set of results, or null if there are no - /// further results. - /// - [JsonProperty("next", Required = Required.Always)] - public string NextGifs { get; set; } - - /// - /// the most relevant GIFs for the requested search term - Sorted by relevancy Rank - /// - [JsonProperty("results", Required = Required.Always)] - public GifObject[] GifResults { get; set; } - - /// - /// returns the next set of GIFs for the used search term and result count - /// - /// the next set of GIFs - public async Task Next() => await Next(Count); - - /// - /// returns the next set of GIFs for the used search term and a different result count - /// - /// the new result count - /// the next set of GIFs - public async Task Next(int count) => Type switch - { - SearchTypes.search => await Client.SearchAsync(Term, count, NextGifs), - SearchTypes.trending => await Client.TrendingAsync(count, NextGifs), - SearchTypes.getGifs => await Client.GetGifsAsync(count, NextGifs, Ids), - SearchTypes.getRandom => await Client.GetRandomGifsAsync(Term, count, NextGifs), - var _ => null - }; +using System.Threading.Tasks; + +using System.Text.Json; +using System.Text.Json.Serialization; +using TenorSharp.Enums; +using TenorSharp.ResponseObjects; + +namespace TenorSharp.SearchResults; + +public class Gif +{ + internal TenorClient Client; + internal int Count; + internal string[] Ids; + internal string Term; + + internal SearchTypes Type; + + /// + /// the most relevant GIFs for the requested search term - Sorted by relevancy Rank + /// + [JsonPropertyName("results")] + public GifObject[] GifResults { get; set; } + + /// + /// a position identifier to use with the next API query to retrieve the next set of results, or null if there are no + /// further results. + /// + [JsonPropertyName("next")] + public string NextGifs { get; set; } + + /// + /// returns the next set of GIFs for the used search term and result count + /// + /// the next set of GIFs + public async Task Next() => await Next(Count); + + /// + /// returns the next set of GIFs for the used search term and a different result count + /// + /// the new result count + /// the next set of GIFs + public async Task Next(int count) => Type switch + { + SearchTypes.search => await Client.SearchAsync(Term, count, NextGifs), + SearchTypes.trending => await Client.TrendingAsync(count, NextGifs), + SearchTypes.getGifs => await Client.GetGifsAsync(count, NextGifs, Ids), + SearchTypes.getRandom => await Client.GetRandomGifsAsync(Term, count, NextGifs), + var _ => null + }; } \ No newline at end of file diff --git a/TenorSharp/SearchResults/Register.cs b/TenorSharp/SearchResults/Register.cs index 1e87fd1..9a8b767 100644 --- a/TenorSharp/SearchResults/Register.cs +++ b/TenorSharp/SearchResults/Register.cs @@ -1,12 +1,12 @@ -using Newtonsoft.Json; - -namespace TenorSharp.SearchResults; - -public class Register -{ - /// - /// set to “ok” if share registration was successful - /// - [JsonProperty("status", Required = Required.Always)] - public string ShareStatus { get; set; } +using System.Text.Json.Serialization; + +namespace TenorSharp.SearchResults; + +public class Register +{ + /// + /// set to “ok” if share registration was successful + /// + [JsonPropertyName("status")] + public string ShareStatus { get; set; } } \ No newline at end of file diff --git a/TenorSharp/SearchResults/Session.cs b/TenorSharp/SearchResults/Session.cs index 66dcd7c..fd79e32 100644 --- a/TenorSharp/SearchResults/Session.cs +++ b/TenorSharp/SearchResults/Session.cs @@ -1,13 +1,13 @@ -using Newtonsoft.Json; - -namespace TenorSharp.SearchResults; - -public class Session -{ - /// - /// an anonymous id used to represent a user. - /// This allows for tracking without the use of personally identifiable information - /// - [JsonProperty("anon_id", Required = Required.Always)] - public string AnonId { get; set; } +using System.Text.Json.Serialization; + +namespace TenorSharp.SearchResults; + +public class Session +{ + /// + /// an anonymous id used to represent a user. + /// This allows for tracking without the use of personally identifiable information + /// + [JsonPropertyName("anon_id")] + public string AnonId { get; set; } } \ No newline at end of file diff --git a/TenorSharp/SearchResults/Terms.cs b/TenorSharp/SearchResults/Terms.cs index 2e13580..96d72c3 100644 --- a/TenorSharp/SearchResults/Terms.cs +++ b/TenorSharp/SearchResults/Terms.cs @@ -1,12 +1,12 @@ -using Newtonsoft.Json; - -namespace TenorSharp.SearchResults; - -public class Terms -{ - /// - /// An array of suggested search terms. - /// - [JsonProperty("results", Required = Required.Always)] - public string[] SearchTerms; +using System.Text.Json.Serialization; + +namespace TenorSharp.SearchResults; + +public class Terms +{ + /// + /// An array of suggested search terms. + /// + [JsonPropertyName("results")] + public string[] SearchTerms { get; set; } } \ No newline at end of file diff --git a/TenorSharp/TenorClient.cs b/TenorSharp/TenorClient.cs index 6b34f54..97e6f4d 100644 --- a/TenorSharp/TenorClient.cs +++ b/TenorSharp/TenorClient.cs @@ -1,695 +1,717 @@ -using System; -using System.IO; -using System.Net; -using System.Threading.Tasks; - -using Newtonsoft.Json; - -using RestSharp; - -using TenorSharp.Enums; -using TenorSharp.ResponseObjects; -using TenorSharp.SearchResults; - -using Type = TenorSharp.Enums.Type; - -// ReSharper disable UnusedMember.Global -// ReSharper disable StringLiteralTypo - -namespace TenorSharp; - -public class TenorClient -{ - private const string BaseUri = "https://g.tenor.com/v1/"; - - private static readonly Locale DefaultLocale = new("en_US"); - - private readonly RestRequest _anonIdRequest = new(Endpoints.AnonId); - - /// - /// client key for privileged API access - /// - private readonly string _apiKey; - - - private readonly RestRequest _autocompleteRequest = - new(Endpoints.Autocomplete); - - private readonly RestRequest _categoryRequest = - new(Endpoints.Categories); - - private readonly RestClient _client; - - private readonly RestRequest _gifsRequest = new(Endpoints.Gifs); - - private readonly RestRequest _rndGifRequest = new(Endpoints.Random); - - private readonly RestRequest _searchRequest = new(Endpoints.Search); - - private readonly RestRequest _shareRequest = - new(Endpoints.RegisterShare); - - private readonly RestRequest _suggestionRequest = - new(Endpoints.SearchSuggestions); - - private readonly RestRequest _trendingRequest = - new(Endpoints.Trending); - - private readonly RestRequest _trendingTermsRequest = - new(Endpoints.TrendingTerms); - - /// - /// specify the anonymous_id tied to the given user - /// - private string _anonId; - - /// - /// Filter the response GIF_OBJECT list to only include GIFs with aspect ratios that fit with in the selected range. - /// - private AspectRatio _arRange; - - /// - /// specify the content safety filter level - /// - private ContentFilter _contentFilter; - - /// - /// specify default language to interpret search string - /// - private Locale _locale; - - /// - /// Reduce the Number of GIF formats returned in the GifObject list. - /// - private MediaFilter _mediaFilter; - - - public TenorClient( - string apiKey, - Locale locale = null, - AspectRatio arRange = AspectRatio.all, - ContentFilter contentFilter = ContentFilter.off, - MediaFilter mediaFilter = MediaFilter.off, - string anonId = null, - RestClient testClient = null - ) - { - _locale = locale ?? DefaultLocale; - _client = testClient ?? new RestClient(BaseUri); - - _arRange = arRange; - _contentFilter = contentFilter; - _mediaFilter = mediaFilter; - _apiKey = apiKey; - - _anonId = anonId; - - _client = _client.AddDefaultParameter("key", apiKey, ParameterType.QueryString); - } - - public TenorClient(TenorConfiguration configuration, RestClient testClient = null) : this(configuration.ApiKey, - configuration.Locale, - configuration.ArRange, - configuration - .ContentFilter, - configuration - .MediaFilter, - configuration.AnonId, - testClient) - { - } - - - /// - public Gif Search(string q, int limit = 20, int pos = 0) => Task.Run(() => SearchAsync(q, limit, pos)).GetAwaiter().GetResult(); - - /// - public async Task SearchAsync(string q, int limit = 20, int pos = 0) - => await SearchAsync(q, limit, pos.ToString()); - - /// - public Gif Search(string q, int limit = 20, string pos = "0") => Task.Run(() => SearchAsync(q, limit, pos)).GetAwaiter().GetResult(); - - //TODO: Add Sticker Search - /// - /// Get a json object containing a list of the most relevant GIFs for a given search term(s), category(ies), emoji(s), - /// or any combination thereof. - /// - /// a search string - /// fetch up to a specified number of results (max: 50). - /// - /// get results starting at position "value". - /// Use a non-zero "next" value returned by API results to get the next set of results. - /// pos is not an index and may be an integer, float, or string - /// - /// a Tenor Gif Response - /// thrown when the Tenor API returns an Error - public async Task SearchAsync(string q, int limit = 20, string pos = "0") - { - _searchRequest.AddOrUpdateParameter("q", q, ParameterType.QueryString) - .AddOrUpdateParameter("limit", limit, ParameterType.QueryString) - .AddOrUpdateParameter("pos", pos, ParameterType.QueryString) - .AddOrUpdateParameter("ar_range", _arRange, ParameterType.QueryString) - .AddOrUpdateParameter("contentfilter", _contentFilter, ParameterType.QueryString) - .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); - if (_anonId != null) - _searchRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); - if (_mediaFilter != MediaFilter.off) - _searchRequest.AddOrUpdateParameter("media_filter", _mediaFilter, ParameterType.QueryString); - - - var result = await _client.ExecuteAsync(_searchRequest); - var content = result.Content; - try - { - if (content == null) - throw new Exception("API Returned null"); - var res = JsonConvert.DeserializeObject(content); - if (res == null) - throw new Exception("API Returned null"); - res.Client = this; - res.Term = q; - res.Count = limit; - res.Type = SearchTypes.search; - return res; - } - catch (JsonException) - { - var error = JsonConvert.DeserializeObject(content!); - throw new TenorException(error!.Error, error.Code); - } - catch (Exception e) - { - throw new TenorException(e.Message, e, e.HResult); - } - } - - - /// - public Gif Trending(int limit = 20, string pos = "0") => Task.Run(() => TrendingAsync(limit, pos)).GetAwaiter().GetResult(); - - //TODO: Add Trending Stickers - /// - /// Get a json object containing a list of the current global trending GIFs. The trending stream is updated regularly - /// throughout the day. - /// - /// fetch up to a specified number of results (max: 50). - /// - /// get results starting at position "value". - /// Use a non-zero "next" value returned by API results to get the next set of results. - /// pos is not an index and may be an integer, float, or string - /// - /// a Tenor Gif Response - /// thrown when the Tenor API returns an Error - public async Task TrendingAsync(int limit = 20, string pos = "0") - { - _trendingRequest.AddOrUpdateParameter("limit", limit, ParameterType.QueryString) - .AddOrUpdateParameter("pos", pos, ParameterType.QueryString) - .AddOrUpdateParameter("ar_range", _arRange, ParameterType.QueryString) - .AddOrUpdateParameter("contentfilter", _contentFilter, ParameterType.QueryString) - .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); - if (_anonId != null) - _trendingRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); - if (_mediaFilter != MediaFilter.off) - _trendingRequest.AddOrUpdateParameter("media_filter", _mediaFilter, ParameterType.QueryString); - var result = await _client.ExecuteAsync(_trendingRequest); - var content = result.Content; - - try - { - if (content == null) - throw new Exception("API Returned null"); - var res = JsonConvert.DeserializeObject(content); - if (res == null) - throw new Exception("API Returned null"); - res.Client = this; - res.Count = limit; - res.Type = SearchTypes.trending; - return res; - } - catch (JsonException) - { - var error = JsonConvert.DeserializeObject(content!); - throw new TenorException(error!.Error, error.Code); - } - catch (Exception e) - { - throw new TenorException(e.Message, e, e.HResult); - } - } - - /// - public Category Categories(Type type = Type.featured) => Task.Run(() => CategoriesAsync(type)).GetAwaiter().GetResult(); - - /// - /// Get a json object containing a list of GIF categories associated with the provided type. - /// Each category will include a corresponding search URL to be used if the user clicks on the category. - /// The search URL will include the apikey, anonymous id, and locale that were used on the original call to the - /// categories endpoint. - /// - /// determines the type of categories returned - /// a Tenor Category Response - /// thrown when the Tenor API returns an Error - public async Task CategoriesAsync(Type type = Type.featured) - { - _categoryRequest.AddOrUpdateParameter("Type", type, ParameterType.QueryString) - .AddOrUpdateParameter("contentfilter", _contentFilter, ParameterType.QueryString) - .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); - if (_anonId != null) - _categoryRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); - - var result = await _client.ExecuteAsync(_categoryRequest); - var content = result.Content; - try - { - if (content == null) - throw new Exception("API Returned null"); - return JsonConvert.DeserializeObject(content); - } - catch (JsonException) - { - var error = JsonConvert.DeserializeObject(content!); - throw new TenorException(error!.Error, error.Code); - } - catch (Exception e) - { - throw new TenorException(e.Message, e, e.HResult); - } - } - - /// - public Terms SearchSuggestions(string q, int limit = 20) => Task.Run(() => SearchSuggestionsAsync(q, limit)).GetAwaiter().GetResult(); - - /// - /// Get a json object containing a list of alternative search terms given a search term. - /// SearchAsync suggestions helps a user narrow their search or discover related search terms to find a more precise GIF. - /// Results are returned in order of what is most likely to drive a share for a given term, based on historic user - /// search and share behavior. - /// - /// a search string - /// fetch up to a specified number of results (max: 50). - /// an Array of Search Terms - /// thrown when the Tenor API returns an Error - public async Task SearchSuggestionsAsync(string q, int limit = 20) - { - _suggestionRequest.AddOrUpdateParameter("q", q, ParameterType.QueryString) - .AddOrUpdateParameter("limit", limit, ParameterType.QueryString) - .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); - if (_anonId != null) - _suggestionRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); - if (_mediaFilter != MediaFilter.off) - _suggestionRequest.AddOrUpdateParameter("media_filter", _mediaFilter, ParameterType.QueryString); - - - var result = await _client.ExecuteAsync(_suggestionRequest); - var content = result.Content; - try - { - if (content == null) - throw new Exception("API Returned null"); - return JsonConvert.DeserializeObject(content); - } - catch (JsonException) - { - var error = JsonConvert.DeserializeObject(content!); - throw new TenorException(error!.Error, error!.Code); - } - catch (Exception e) - { - throw new TenorException(e.Message, e, e.HResult); - } - } - - /// - public Terms AutoComplete(string q, int limit = 20) => Task.Run(() => AutoCompleteAsync(q, limit)).GetAwaiter().GetResult(); - - /// - /// Get a json object containing a list of completed search terms given a partial search term. - /// The list is sorted by Tenor’s AI and the number of results will decrease as Tenor’s AI becomes more certain. - /// - /// a search string - /// fetch up to a specified number of results (max: 50). - /// an Array of Search Terms - /// thrown when the Tenor API returns an Error - public async Task AutoCompleteAsync(string q, int limit = 20) - { - _autocompleteRequest.AddOrUpdateParameter("q", q, ParameterType.QueryString) - .AddOrUpdateParameter("limit", limit, ParameterType.QueryString) - .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); - - if (_anonId != null) - _autocompleteRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); - - var result = await _client.ExecuteAsync(_autocompleteRequest); - var content = result.Content; - try - { - if (content == null) - throw new Exception("API Returned null"); - return JsonConvert.DeserializeObject(content); - } - catch (JsonException) - { - var error = JsonConvert.DeserializeObject(content!); - throw new TenorException(error!.Error, error!.Code); - } - catch (Exception e) - { - throw new TenorException(e.Message, e, e.HResult); - } - } - - /// - public Terms TrendingTerms(int limit = 20) => Task.Run(() => TrendingTermsAsync(limit)).GetAwaiter().GetResult(); - - /// - /// Get a json object containing a list of the current trending search terms. - /// The list is updated Hourly by Tenor’s AI. - /// - /// fetch up to a specified number of results (max: 50). - /// an Array of Search Terms - /// thrown when the Tenor API returns an Error - /// thrown when the Tenor API returns Invalid Data - public async Task TrendingTermsAsync(int limit = 20) - { - _trendingTermsRequest.AddOrUpdateParameter("limit", limit, ParameterType.QueryString) - .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); - - if (_anonId != null) - _trendingTermsRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); - - - var result = await _client.ExecuteAsync(_trendingTermsRequest); - var content = result.Content; - try - { - if (content == null) - throw new Exception("API Returned null"); - return JsonConvert.DeserializeObject(content); - } - catch (JsonException) - { - var error = JsonConvert.DeserializeObject(content!); - throw new TenorException(error!.Error, error!.Code); - } - catch (Exception e) - { - throw new TenorException(e.Message, e, e.HResult); - } - } - - /// - public string RegisterShare(string id, string q = null) - => Task.Run(() => RegisterShareAsync(id, q)).GetAwaiter().GetResult(); - - /// - /// Register a user’s sharing of a GIF. - /// - /// the “id” of a GIF_OBJECT - /// The search string that lead to this share - /// the Share Status - /// thrown when the Tenor API returns an Error - public async Task RegisterShareAsync(string id, string q = null) - { - _shareRequest.AddOrUpdateParameter("id", id) - .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); - - if (_anonId != null) - _shareRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); - - - if (q != null) - _shareRequest.AddOrUpdateParameter("q", q); - - var result = await _client.ExecuteAsync(_shareRequest); - var content = result.Content; - try - { - if (content == null) - throw new Exception("API Returned null"); - return JsonConvert.DeserializeObject(content)?.ShareStatus; - } - catch (JsonException) - { - var error = JsonConvert.DeserializeObject(content!); - throw new TenorException(error!.Error, error!.Code); - } - catch (Exception e) - { - throw new TenorException(e.Message, e, e.HResult); - } - } - - - /// - public Gif GetGifs( - int limit = 20, - int pos = 0, - params string[] ids - ) => Task.Run(() => GetGifsAsync(limit, pos, ids)).GetAwaiter().GetResult(); - - /// - public async Task GetGifsAsync( - int limit = 20, - int pos = 0, - params string[] ids - ) - => await GetGifsAsync(limit, pos.ToString(), ids); - - /// - public Gif GetGifs( - int limit = 20, - string pos = "0", - params string[] ids - ) => Task.Run(() => GetGifsAsync(limit, pos, ids)).GetAwaiter().GetResult(); - - /// - /// Get the GIF(s) for the corresponding id(s) - /// - /// fetch up to a specified number of results (max: 50). - /// - /// get results starting at position "value". - /// Use a non-zero "next" value returned by API results to get the next set of results. - /// pos is not an index and may be an integer, float, or string - /// - /// a comma separated list of GIF IDs (max: 50) - /// a Tenor Gif Response - /// thrown when the Tenor API returns an Error - public async Task GetGifsAsync( - int limit = 20, - string pos = "0", - params string[] ids - ) - { - _gifsRequest.AddOrUpdateParameter("ids", string.Join(',', ids), ParameterType.QueryString) - .AddOrUpdateParameter("limit", limit).AddOrUpdateParameter("pos", pos) - .AddOrUpdateParameter("ar_range", _arRange, ParameterType.QueryString) - .AddOrUpdateParameter("contentfilter", _contentFilter, ParameterType.QueryString) - .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); - if (_anonId != null) - _gifsRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); - if (_mediaFilter != MediaFilter.off) - _gifsRequest.AddOrUpdateParameter("media_filter", _mediaFilter, ParameterType.QueryString); - - - var result = await _client.ExecuteAsync(_gifsRequest); - var content = result.Content; - try - { - if (content == null) - throw new Exception("API Returned null"); - var res = JsonConvert.DeserializeObject(content); - if (res == null) - throw new Exception("API Returned null"); - res.Client = this; - res.Count = limit; - res.Ids = ids; - res.Type = SearchTypes.getGifs; - return res; - } - catch (JsonException) - { - var error = JsonConvert.DeserializeObject(content!); - throw new TenorException(error!.Error, error.Code); - } - catch (Exception e) - { - throw new TenorException(e.Message, e, e.HResult); - } - } - - - - - /// - public string GetNewAnonId() => Task.Run(GetNewAnonIdAsync).GetAwaiter().GetResult(); - - /// - /// Get an anonymous ID for a new user. - /// Store the ID in the client's cache for use on any additional API calls made by the user, either in this session or - /// any future sessions. - /// - /// a Random AnonId - /// thrown when the Tenor API returns an Error - public async Task GetNewAnonIdAsync() - { - var result = await _client.ExecuteAsync(_anonIdRequest); - var content = result.Content; - try - { - if (content == null) - throw new Exception("API Returned null"); - return JsonConvert.DeserializeObject(content)?.AnonId; - } - catch (JsonException) - { - var error = JsonConvert.DeserializeObject(content!); - throw new TenorException(error!.Error, error!.Code); - } - catch (Exception e) - { - throw new TenorException(e.Message, e, e.HResult); - } - } - - - /// - public Gif GetRandomGifs(string q, int limit = 20, int pos = 0) - => Task.Run(() => GetRandomGifsAsync(q, limit, pos)).GetAwaiter().GetResult(); - - /// - public async Task GetRandomGifsAsync(string q, int limit = 20, int pos = 0) - => await GetRandomGifsAsync(q, limit, pos.ToString()); - - /// - public Gif GetRandomGifs(string q, int limit = 20, string pos = "0") - => Task.Run(() => GetRandomGifsAsync(q, limit, pos)).GetAwaiter().GetResult(); - - /// - /// Get a randomized list of GIFs for a given search term. This differs from the search endpoint which returns a rank - /// ordered list of GIFs for a given search term. - /// - /// a search string - /// fetch up to a specified number of results (max: 50). - /// - /// get results starting at position "value". - /// Use a non-zero "next" value returned by API results to get the next set of results. - /// pos is not an index and may be an integer, float, or string - /// - /// a Tenor Gif Response - /// thrown when the Tenor API returns an Error - public async Task GetRandomGifsAsync(string q, int limit = 20, string pos = "0") - { - _rndGifRequest.AddOrUpdateParameter("q", q, ParameterType.QueryString).AddOrUpdateParameter("limit", limit) - .AddOrUpdateParameter("pos", pos) - .AddOrUpdateParameter("ar_range", _arRange, ParameterType.QueryString) - .AddOrUpdateParameter("contentfilter", _contentFilter, ParameterType.QueryString) - .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); - if (_mediaFilter != MediaFilter.off) - _rndGifRequest.AddOrUpdateParameter("media_filter", _mediaFilter, ParameterType.QueryString); - if (_anonId != null) - _rndGifRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); - - var result = await _client.ExecuteAsync(_rndGifRequest); - var content = result.Content; - - try - { - if (content == null) - throw new Exception("API Returned null"); - var res = JsonConvert.DeserializeObject(content); - if (res == null) - throw new Exception("API Returned null"); - res.Client = this; - res.Term = q; - res.Count = limit; - res.Type = SearchTypes.getRandom; - return res; - } - catch (JsonException e) - { - var error = JsonConvert.DeserializeObject(content!); - throw new TenorException(error!.Error, e, error!.Code); - } - catch (Exception e) - { - throw new TenorException(e.Message, e, e.HResult); - } - } - - - - - - /// - /// Start new Session with an Anonymous ID - /// - /// the Anonymous ID - /// Thrown when anonId is invalid - public void NewSession(string anonId) => _anonId = anonId.Length switch - { - >= 16 and <= 32 => anonId, - var _ => throw new TenorException("Anon_id must be between 16 and 32 characters.", 1) - }; - - public string GetSession() => _anonId; - - public void SetLocale(string locale) => Locale = new Locale(locale); - - - [Obsolete("SetLocale is deprecated, please use Locale instead.")] - public void SetLocale(Locale locale) => Locale = locale; - - [Obsolete("GetLocale is deprecated, please use Locale instead.")] - public Locale GetLocale() => Locale; - - public void ResetLocale() => Locale = DefaultLocale; - - public void ClearSession() => _anonId = null; - - [Obsolete("SetContentFilter is deprecated, please use ContentFilter instead.")] - public void SetContentFilter(ContentFilter filter) => ContentFilter = filter; - - - public Locale Locale { get; set; } - public ContentFilter ContentFilter { get; set; } - public MediaFilter MediaFilter { get; set; } - public AspectRatio AspectRatioRange { get; set; } - - [Obsolete("GetContentFilter is deprecated, please use ContentFilter instead.")] - public ContentFilter GetContentFilter() => ContentFilter; - - [Obsolete("SetMediaFilter is deprecated, please use MediaFilter instead.")] - public void SetMediaFilter(MediaFilter filter) => MediaFilter = filter; - - [Obsolete("GetMediaFilter is deprecated, please use MediaFilter instead.")] - public MediaFilter GetMediaFilter() => MediaFilter; - - [Obsolete("SetAspectRatioRange is deprecated, please use AspectRatioRange instead.")] - public void SetAspectRatioRange(AspectRatio ratio) => AspectRatioRange = ratio; - - [Obsolete("GetAspectRatioRange is deprecated, please use AspectRatioRange instead.")] - public AspectRatio GetAspectRatioRange() => AspectRatioRange; - - public string GetApiKey() => _apiKey; - - /// - /// Gets a File as a Stream from a URL - /// - /// the URL - /// the Stream - public static Stream GetMediaStream(Uri url) - { - var req = WebRequest.Create(url); - var stream = req.GetResponse().GetResponseStream(); - return stream; - } - - public static Stream GetMediaStream(string url) => GetMediaStream(new Uri(url)); - - - // .AddOrUpdateParameter("anon_id", null, ParameterType.QueryString) - // .AddOrUpdateParameter("ar_range", AspectRatio.all, ParameterType.QueryString) - // .AddOrUpdateParameter("contentfilter", ContentFilter.off, ParameterType.QueryString) - // .AddOrUpdateParameter("locale", DefaultLocale, ParameterType.QueryString) +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Threading.Tasks; + +using System.Text.Json; + +using RestSharp; + +using TenorSharp.Enums; +using TenorSharp.ResponseObjects; +using TenorSharp.SearchResults; + +using Type = TenorSharp.Enums.Type; + +// ReSharper disable UnusedMember.Global +// ReSharper disable StringLiteralTypo + +namespace TenorSharp; + +public class TenorClient +{ + private const string BaseUri = "https://tenor.googleapis.com/v2/"; + + private static readonly Locale DefaultLocale = new("en_US"); + + private readonly RestRequest _anonIdRequest = new(Endpoints.AnonId); + + /// + /// client key for privileged API access + /// + private readonly string _apiKey; + + + private readonly RestRequest _autocompleteRequest = + new(Endpoints.Autocomplete); + + private readonly RestRequest _categoryRequest = + new(Endpoints.Categories); + + private readonly RestClient _client; + + private readonly RestRequest _gifsRequest = new(Endpoints.Gifs); + + private readonly RestRequest _rndGifRequest = new(Endpoints.Random); + + private readonly RestRequest _searchRequest = new(Endpoints.Search); + + private readonly RestRequest _shareRequest = + new(Endpoints.RegisterShare); + + private readonly RestRequest _suggestionRequest = + new(Endpoints.SearchSuggestions); + + private readonly RestRequest _trendingRequest = + new(Endpoints.Trending); + + private readonly RestRequest _trendingTermsRequest = + new(Endpoints.TrendingTerms); + + /// + /// specify the anonymous_id tied to the given user + /// + private string _anonId; + + /// + /// Filter the response GIF_OBJECT list to only include GIFs with aspect ratios that fit with in the selected range. + /// + private AspectRatio _arRange; + + /// + /// specify the content safety filter level + /// + private ContentFilter _contentFilter; + + /// + /// specify default language to interpret search string + /// + private Locale _locale; + + /// + /// Reduce the Number of GIF formats returned in the GifObject list. + /// + private List _mediaFilter; + + + public TenorClient( + string apiKey, + Locale locale = null, + AspectRatio arRange = AspectRatio.all, + ContentFilter contentFilter = ContentFilter.off, + List mediaFilter = null, + string anonId = null, + RestClient testClient = null + ) + { + mediaFilter ??= new List(); + + _locale = locale ?? DefaultLocale; + _client = testClient ?? new RestClient(BaseUri); + + _arRange = arRange; + _contentFilter = contentFilter; + _apiKey = apiKey; + + _anonId = anonId; + + _client = _client.AddDefaultParameter("key", apiKey, ParameterType.QueryString); + } + + public TenorClient(TenorConfiguration configuration, RestClient testClient = null) : this(configuration.ApiKey, + configuration.Locale, + configuration.ArRange, + configuration + .ContentFilter, + configuration + .MediaFilter, + configuration.AnonId, + testClient) + { + } + + + /// + public Gif Search(string q, int limit = 20, int pos = 0) => Task.Run(() => SearchAsync(q, limit, pos)).GetAwaiter().GetResult(); + + /// + public async Task SearchAsync(string q, int limit = 20, int pos = 0) + => await SearchAsync(q, limit, pos.ToString()); + + /// + public Gif Search(string q, int limit = 20, string pos = "0") => Task.Run(() => SearchAsync(q, limit, pos)).GetAwaiter().GetResult(); + + //TODO: Add Sticker Search + /// + /// Get a json object containing a list of the most relevant GIFs for a given search term(s), category(ies), emoji(s), + /// or any combination thereof. + /// + /// a search string + /// fetch up to a specified number of results (max: 50). + /// + /// get results starting at position "value". + /// Use a non-zero "next" value returned by API results to get the next set of results. + /// pos is not an index and may be an integer, float, or string + /// + /// a Tenor Gif Response + /// thrown when the Tenor API returns an Error + public async Task SearchAsync(string q, int limit = 20, string pos = "0") + { + _searchRequest.AddOrUpdateParameter("q", q, ParameterType.QueryString) + .AddOrUpdateParameter("limit", limit, ParameterType.QueryString) + .AddOrUpdateParameter("pos", pos, ParameterType.QueryString) + .AddOrUpdateParameter("ar_range", _arRange, ParameterType.QueryString) + .AddOrUpdateParameter("contentfilter", _contentFilter, ParameterType.QueryString) + .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); + if (_anonId != null) + _searchRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); + + if (_mediaFilter.Count > 0) + { + var filter = string.Join(',', _mediaFilter.Select(x => x.ToString())); + _searchRequest.AddOrUpdateParameter("media_filter", filter, ParameterType.QueryString); + } + + var result = await _client.ExecuteAsync(_searchRequest); + var content = result.Content; + try + { + if (content == null) + throw new Exception("API Returned null"); + var res = JsonSerializer.Deserialize(content); + if (res == null) + throw new Exception("API Returned null"); + res.Client = this; + res.Term = q; + res.Count = limit; + res.Type = SearchTypes.search; + return res; + } + catch (JsonException) + { + var error = JsonSerializer.Deserialize(content!); + throw new TenorException(error!.Error, error.Code); + } + catch (Exception e) + { + throw new TenorException(e.Message, e, e.HResult); + } + } + + + /// + public Gif Trending(int limit = 20, string pos = "0") => Task.Run(() => TrendingAsync(limit, pos)).GetAwaiter().GetResult(); + + //TODO: Add Trending Stickers + /// + /// Get a json object containing a list of the current global trending GIFs. The trending stream is updated regularly + /// throughout the day. + /// + /// fetch up to a specified number of results (max: 50). + /// + /// get results starting at position "value". + /// Use a non-zero "next" value returned by API results to get the next set of results. + /// pos is not an index and may be an integer, float, or string + /// + /// a Tenor Gif Response + /// thrown when the Tenor API returns an Error + public async Task TrendingAsync(int limit = 20, string pos = "0") + { + _trendingRequest.AddOrUpdateParameter("limit", limit, ParameterType.QueryString) + .AddOrUpdateParameter("pos", pos, ParameterType.QueryString) + .AddOrUpdateParameter("ar_range", _arRange, ParameterType.QueryString) + .AddOrUpdateParameter("contentfilter", _contentFilter, ParameterType.QueryString) + .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); + if (_anonId != null) + _trendingRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); + + if (_mediaFilter.Count > 0) + { + var filter = string.Join(',', _mediaFilter.Select(x => x.ToString())); + _trendingRequest.AddOrUpdateParameter("media_filter", filter, ParameterType.QueryString); + } + + var result = await _client.ExecuteAsync(_trendingRequest); + var content = result.Content; + + try + { + if (content == null) + throw new Exception("API Returned null"); + var res = JsonSerializer.Deserialize(content); + if (res == null) + throw new Exception("API Returned null"); + res.Client = this; + res.Count = limit; + res.Type = SearchTypes.trending; + return res; + } + catch (JsonException) + { + var error = JsonSerializer.Deserialize(content!); + throw new TenorException(error!.Error, error.Code); + } + catch (Exception e) + { + throw new TenorException(e.Message, e, e.HResult); + } + } + + /// + public Category Categories(Type type = Type.featured) => Task.Run(() => CategoriesAsync(type)).GetAwaiter().GetResult(); + + /// + /// Get a json object containing a list of GIF categories associated with the provided type. + /// Each category will include a corresponding search URL to be used if the user clicks on the category. + /// The search URL will include the apikey, anonymous id, and locale that were used on the original call to the + /// categories endpoint. + /// + /// determines the type of categories returned + /// a Tenor Category Response + /// thrown when the Tenor API returns an Error + public async Task CategoriesAsync(Type type = Type.featured) + { + _categoryRequest.AddOrUpdateParameter("Type", type, ParameterType.QueryString) + .AddOrUpdateParameter("contentfilter", _contentFilter, ParameterType.QueryString) + .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); + if (_anonId != null) + _categoryRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); + + var result = await _client.ExecuteAsync(_categoryRequest); + var content = result.Content; + try + { + if (content == null) + throw new Exception("API Returned null"); + return JsonSerializer.Deserialize(content); + } + catch (JsonException) + { + var error = JsonSerializer.Deserialize(content!); + throw new TenorException(error!.Error, error.Code); + } + catch (Exception e) + { + throw new TenorException(e.Message, e, e.HResult); + } + } + + /// + public Terms SearchSuggestions(string q, int limit = 20) => Task.Run(() => SearchSuggestionsAsync(q, limit)).GetAwaiter().GetResult(); + + /// + /// Get a json object containing a list of alternative search terms given a search term. + /// SearchAsync suggestions helps a user narrow their search or discover related search terms to find a more precise GIF. + /// Results are returned in order of what is most likely to drive a share for a given term, based on historic user + /// search and share behavior. + /// + /// a search string + /// fetch up to a specified number of results (max: 50). + /// an Array of Search Terms + /// thrown when the Tenor API returns an Error + public async Task SearchSuggestionsAsync(string q, int limit = 20) + { + _suggestionRequest.AddOrUpdateParameter("q", q, ParameterType.QueryString) + .AddOrUpdateParameter("limit", limit, ParameterType.QueryString) + .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); + if (_anonId != null) + _suggestionRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); + + if (_mediaFilter.Count > 0) + { + var filter = string.Join(',', _mediaFilter.Select(x => x.ToString())); + _suggestionRequest.AddOrUpdateParameter("media_filter", filter, ParameterType.QueryString); + } + + var result = await _client.ExecuteAsync(_suggestionRequest); + var content = result.Content; + try + { + if (content == null) + throw new Exception("API Returned null"); + return JsonSerializer.Deserialize(content); + } + catch (JsonException) + { + var error = JsonSerializer.Deserialize(content!); + throw new TenorException(error!.Error, error!.Code); + } + catch (Exception e) + { + throw new TenorException(e.Message, e, e.HResult); + } + } + + /// + public Terms AutoComplete(string q, int limit = 20) => Task.Run(() => AutoCompleteAsync(q, limit)).GetAwaiter().GetResult(); + + /// + /// Get a json object containing a list of completed search terms given a partial search term. + /// The list is sorted by Tenor’s AI and the number of results will decrease as Tenor’s AI becomes more certain. + /// + /// a search string + /// fetch up to a specified number of results (max: 50). + /// an Array of Search Terms + /// thrown when the Tenor API returns an Error + public async Task AutoCompleteAsync(string q, int limit = 20) + { + _autocompleteRequest.AddOrUpdateParameter("q", q, ParameterType.QueryString) + .AddOrUpdateParameter("limit", limit, ParameterType.QueryString) + .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); + + if (_anonId != null) + _autocompleteRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); + + var result = await _client.ExecuteAsync(_autocompleteRequest); + var content = result.Content; + try + { + if (content == null) + throw new Exception("API Returned null"); + return JsonSerializer.Deserialize(content); + } + catch (JsonException) + { + var error = JsonSerializer.Deserialize(content!); + throw new TenorException(error!.Error, error!.Code); + } + catch (Exception e) + { + throw new TenorException(e.Message, e, e.HResult); + } + } + + /// + public Terms TrendingTerms(int limit = 20) => Task.Run(() => TrendingTermsAsync(limit)).GetAwaiter().GetResult(); + + /// + /// Get a json object containing a list of the current trending search terms. + /// The list is updated Hourly by Tenor’s AI. + /// + /// fetch up to a specified number of results (max: 50). + /// an Array of Search Terms + /// thrown when the Tenor API returns an Error + /// thrown when the Tenor API returns Invalid Data + public async Task TrendingTermsAsync(int limit = 20) + { + _trendingTermsRequest.AddOrUpdateParameter("limit", limit, ParameterType.QueryString) + .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); + + if (_anonId != null) + _trendingTermsRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); + + + var result = await _client.ExecuteAsync(_trendingTermsRequest); + var content = result.Content; + try + { + if (content == null) + throw new Exception("API Returned null"); + return JsonSerializer.Deserialize(content); + } + catch (JsonException) + { + var error = JsonSerializer.Deserialize(content!); + throw new TenorException(error!.Error, error!.Code); + } + catch (Exception e) + { + throw new TenorException(e.Message, e, e.HResult); + } + } + + /// + public string RegisterShare(string id, string q = null) + => Task.Run(() => RegisterShareAsync(id, q)).GetAwaiter().GetResult(); + + /// + /// Register a user’s sharing of a GIF. + /// + /// the “id” of a GIF_OBJECT + /// The search string that lead to this share + /// the Share Status + /// thrown when the Tenor API returns an Error + public async Task RegisterShareAsync(string id, string q = null) + { + _shareRequest.AddOrUpdateParameter("id", id) + .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); + + if (_anonId != null) + _shareRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); + + + if (q != null) + _shareRequest.AddOrUpdateParameter("q", q); + + var result = await _client.ExecuteAsync(_shareRequest); + var content = result.Content; + try + { + if (content == null) + throw new Exception("API Returned null"); + return JsonSerializer.Deserialize(content)?.ShareStatus; + } + catch (JsonException) + { + var error = JsonSerializer.Deserialize(content!); + throw new TenorException(error!.Error, error!.Code); + } + catch (Exception e) + { + throw new TenorException(e.Message, e, e.HResult); + } + } + + + /// + public Gif GetGifs( + int limit = 20, + int pos = 0, + params string[] ids + ) => Task.Run(() => GetGifsAsync(limit, pos, ids)).GetAwaiter().GetResult(); + + /// + public async Task GetGifsAsync( + int limit = 20, + int pos = 0, + params string[] ids + ) + => await GetGifsAsync(limit, pos.ToString(), ids); + + /// + public Gif GetGifs( + int limit = 20, + string pos = "0", + params string[] ids + ) => Task.Run(() => GetGifsAsync(limit, pos, ids)).GetAwaiter().GetResult(); + + /// + /// Get the GIF(s) for the corresponding id(s) + /// + /// fetch up to a specified number of results (max: 50). + /// + /// get results starting at position "value". + /// Use a non-zero "next" value returned by API results to get the next set of results. + /// pos is not an index and may be an integer, float, or string + /// + /// a comma separated list of GIF IDs (max: 50) + /// a Tenor Gif Response + /// thrown when the Tenor API returns an Error + public async Task GetGifsAsync( + int limit = 20, + string pos = "0", + params string[] ids + ) + { + _gifsRequest.AddOrUpdateParameter("ids", string.Join(',', ids), ParameterType.QueryString) + .AddOrUpdateParameter("limit", limit).AddOrUpdateParameter("pos", pos) + .AddOrUpdateParameter("ar_range", _arRange, ParameterType.QueryString) + .AddOrUpdateParameter("contentfilter", _contentFilter, ParameterType.QueryString) + .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); + if (_anonId != null) + _gifsRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); + + if (_mediaFilter.Count > 0) + { + var filter = string.Join(',', _mediaFilter.Select(x => x.ToString())); + _gifsRequest.AddOrUpdateParameter("media_filter", filter, ParameterType.QueryString); + } + + var result = await _client.ExecuteAsync(_gifsRequest); + var content = result.Content; + try + { + if (content == null) + throw new Exception("API Returned null"); + var res = JsonSerializer.Deserialize(content); + if (res == null) + throw new Exception("API Returned null"); + res.Client = this; + res.Count = limit; + res.Ids = ids; + res.Type = SearchTypes.getGifs; + return res; + } + catch (JsonException) + { + var error = JsonSerializer.Deserialize(content!); + throw new TenorException(error!.Error, error.Code); + } + catch (Exception e) + { + throw new TenorException(e.Message, e, e.HResult); + } + } + + + + + /// + public string GetNewAnonId() => Task.Run(GetNewAnonIdAsync).GetAwaiter().GetResult(); + + /// + /// Get an anonymous ID for a new user. + /// Store the ID in the client's cache for use on any additional API calls made by the user, either in this session or + /// any future sessions. + /// + /// a Random AnonId + /// thrown when the Tenor API returns an Error + public async Task GetNewAnonIdAsync() + { + var result = await _client.ExecuteAsync(_anonIdRequest); + var content = result.Content; + try + { + if (content == null) + throw new Exception("API Returned null"); + return JsonSerializer.Deserialize(content)?.AnonId; + } + catch (JsonException) + { + var error = JsonSerializer.Deserialize(content!); + throw new TenorException(error!.Error, error!.Code); + } + catch (Exception e) + { + throw new TenorException(e.Message, e, e.HResult); + } + } + + + /// + public Gif GetRandomGifs(string q, int limit = 20, int pos = 0) + => Task.Run(() => GetRandomGifsAsync(q, limit, pos)).GetAwaiter().GetResult(); + + /// + public async Task GetRandomGifsAsync(string q, int limit = 20, int pos = 0) + => await GetRandomGifsAsync(q, limit, pos.ToString()); + + /// + public Gif GetRandomGifs(string q, int limit = 20, string pos = "0") + => Task.Run(() => GetRandomGifsAsync(q, limit, pos)).GetAwaiter().GetResult(); + + /// + /// Get a randomized list of GIFs for a given search term. This differs from the search endpoint which returns a rank + /// ordered list of GIFs for a given search term. + /// + /// a search string + /// fetch up to a specified number of results (max: 50). + /// + /// get results starting at position "value". + /// Use a non-zero "next" value returned by API results to get the next set of results. + /// pos is not an index and may be an integer, float, or string + /// + /// a Tenor Gif Response + /// thrown when the Tenor API returns an Error + public async Task GetRandomGifsAsync(string q, int limit = 20, string pos = "0") + { + _rndGifRequest.AddOrUpdateParameter("q", q, ParameterType.QueryString).AddOrUpdateParameter("limit", limit) + .AddOrUpdateParameter("pos", pos) + .AddOrUpdateParameter("ar_range", _arRange, ParameterType.QueryString) + .AddOrUpdateParameter("contentfilter", _contentFilter, ParameterType.QueryString) + .AddOrUpdateParameter("locale", _locale, ParameterType.QueryString); + + if (_mediaFilter.Count > 0) + { + var filter = string.Join(',', _mediaFilter.Select(x => x.ToString())); + _rndGifRequest.AddOrUpdateParameter("media_filter", filter, ParameterType.QueryString); + } + + if (_anonId != null) + _rndGifRequest.AddOrUpdateParameter("anon_id", _anonId, ParameterType.QueryString); + + var result = await _client.ExecuteAsync(_rndGifRequest); + var content = result.Content; + + try + { + if (content == null) + throw new Exception("API Returned null"); + var res = JsonSerializer.Deserialize(content); + if (res == null) + throw new Exception("API Returned null"); + res.Client = this; + res.Term = q; + res.Count = limit; + res.Type = SearchTypes.getRandom; + return res; + } + catch (JsonException e) + { + var error = JsonSerializer.Deserialize(content!); + throw new TenorException(error!.Error, e, error!.Code); + } + catch (Exception e) + { + throw new TenorException(e.Message, e, e.HResult); + } + } + + + + + + /// + /// Start new Session with an Anonymous ID + /// + /// the Anonymous ID + /// Thrown when anonId is invalid + public void NewSession(string anonId) => _anonId = anonId.Length switch + { + >= 16 and <= 32 => anonId, + var _ => throw new TenorException("Anon_id must be between 16 and 32 characters.", 1) + }; + + public string GetSession() => _anonId; + + public void SetLocale(string locale) => Locale = new Locale(locale); + + + [Obsolete("SetLocale is deprecated, please use Locale instead.")] + public void SetLocale(Locale locale) => Locale = locale; + + [Obsolete("GetLocale is deprecated, please use Locale instead.")] + public Locale GetLocale() => Locale; + + public void ResetLocale() => Locale = DefaultLocale; + + public void ClearSession() => _anonId = null; + + [Obsolete("SetContentFilter is deprecated, please use ContentFilter instead.")] + public void SetContentFilter(ContentFilter filter) => ContentFilter = filter; + + + public Locale Locale { get; set; } + public ContentFilter ContentFilter { get; set; } + public List MediaFilter { get; set; } + public AspectRatio AspectRatioRange { get; set; } + + [Obsolete("GetContentFilter is deprecated, please use ContentFilter instead.")] + public ContentFilter GetContentFilter() => ContentFilter; + + [Obsolete("SetMediaFilter is deprecated, please use MediaFilter instead.")] + public void SetMediaFilter(List filter) => MediaFilter = filter; + + [Obsolete("GetMediaFilter is deprecated, please use MediaFilter instead.")] + public List GetMediaFilter() => MediaFilter; + + [Obsolete("SetAspectRatioRange is deprecated, please use AspectRatioRange instead.")] + public void SetAspectRatioRange(AspectRatio ratio) => AspectRatioRange = ratio; + + [Obsolete("GetAspectRatioRange is deprecated, please use AspectRatioRange instead.")] + public AspectRatio GetAspectRatioRange() => AspectRatioRange; + + public string GetApiKey() => _apiKey; + + /// + /// Gets a File as a Stream from a URL + /// + /// the URL + /// the Stream + public static Stream GetMediaStream(Uri url) + { + var req = WebRequest.Create(url); + var stream = req.GetResponse().GetResponseStream(); + return stream; + } + + public static Stream GetMediaStream(string url) => GetMediaStream(new Uri(url)); + + + // .AddOrUpdateParameter("anon_id", null, ParameterType.QueryString) + // .AddOrUpdateParameter("ar_range", AspectRatio.all, ParameterType.QueryString) + // .AddOrUpdateParameter("contentfilter", ContentFilter.off, ParameterType.QueryString) + // .AddOrUpdateParameter("locale", DefaultLocale, ParameterType.QueryString) } \ No newline at end of file diff --git a/TenorSharp/TenorConfiguration.cs b/TenorSharp/TenorConfiguration.cs index fa0c18a..cb2f3e0 100644 --- a/TenorSharp/TenorConfiguration.cs +++ b/TenorSharp/TenorConfiguration.cs @@ -1,13 +1,14 @@ -using TenorSharp.Enums; - -namespace TenorSharp; - -public class TenorConfiguration -{ - public string ApiKey { get; set; } - public string AnonId { get; set; } - public AspectRatio ArRange { get; set; } = AspectRatio.all; - public ContentFilter ContentFilter { get; set; } = ContentFilter.off; - public MediaFilter MediaFilter { get; set; } = MediaFilter.off; - public Locale Locale { get; set; } = new("en_US"); +using System.Collections.Generic; +using TenorSharp.Enums; + +namespace TenorSharp; + +public class TenorConfiguration +{ + public string ApiKey { get; set; } + public string AnonId { get; set; } + public AspectRatio ArRange { get; set; } = AspectRatio.all; + public ContentFilter ContentFilter { get; set; } = ContentFilter.off; + public List MediaFilter { get; set; } = new(); + public Locale Locale { get; set; } = new("en_US"); } \ No newline at end of file diff --git a/TenorSharp/TenorSharp.csproj b/TenorSharp/TenorSharp.csproj index 154a698..0047310 100644 --- a/TenorSharp/TenorSharp.csproj +++ b/TenorSharp/TenorSharp.csproj @@ -3,12 +3,12 @@ true TenorSharp - OmegaRogue + Vooper Media LLC, OmegaRogue a dotNet Library for Tenor written in C# - here is an Invite to the TenorSharp Discord Server: https://discord.gg/sWwzJeG + forked from https://github.com/OmegaRogue/TenorSharp OmegaRogue 2020 - https://github.com/OmegaRogue/TenorSharp + https://github.com/Vooper-Media-LLC/Valour.TenorSharp https://github.com/OmegaRogue/TenorSharp git Tenor, Tenor-API @@ -19,6 +19,8 @@ net5.0;net6.0 10 LGPL-3.0-or-later + 1.0.2 + Valour.TenorSharp @@ -26,12 +28,12 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - +