diff --git a/PocketSharp.Tests/GetTests.cs b/PocketSharp.Tests/GetTests.cs index fe8b2f9..b3fb0e5 100644 --- a/PocketSharp.Tests/GetTests.cs +++ b/PocketSharp.Tests/GetTests.cs @@ -33,23 +33,34 @@ namespace PocketSharp.Tests Assert.True(item.Uri == itemDuplicate.Uri); } -// [Fact] -// public async Task IsItemJsonPopulated() -// { -// List items = (await client.Get()).ToList(); -// string schemaJson = @"{ -// 'description': 'PocketItem', -// 'type': 'object' -// }"; -// JsonSchema schema = JsonSchema.Parse(schemaJson); -// foreach (var pocketItem in items) -// { -// Assert.True(!string.IsNullOrWhiteSpace(pocketItem.Json)); -// var jObject = JObject.Parse(pocketItem.Json); -// Assert.True(jObject.IsValid(schema)); -// } -// } + [Fact] + public async Task AreSuggestionsRetrieved() + { + var articles = await client.GetTrendingArticles(); + string itemId = articles.First().ID; + + List suggestions = (await client.GetSuggestions(itemId)).ToList(); + Assert.True(suggestions.Count > 0); + } + + // [Fact] + // public async Task IsItemJsonPopulated() + // { + // List items = (await client.Get()).ToList(); + // string schemaJson = @"{ + // 'description': 'PocketItem', + // 'type': 'object' + // }"; + + // JsonSchema schema = JsonSchema.Parse(schemaJson); + // foreach (var pocketItem in items) + // { + // Assert.True(!string.IsNullOrWhiteSpace(pocketItem.Json)); + // var jObject = JObject.Parse(pocketItem.Json); + // Assert.True(jObject.IsValid(schema)); + // } + // } [Fact] public async Task AreFilteredItemsRetrieved() diff --git a/PocketSharp.Tests/MiscTests.cs b/PocketSharp.Tests/MiscTests.cs index 60582e7..a0f822c 100644 --- a/PocketSharp.Tests/MiscTests.cs +++ b/PocketSharp.Tests/MiscTests.cs @@ -1,4 +1,4 @@ -using PocketSharp.Models; +using PocketSharp.Models; using System.Collections.Generic; using System.Threading.Tasks; using Xunit; @@ -10,8 +10,7 @@ namespace PocketSharp.Tests { private int Incrementor = 0; - public MiscTests() - : base() + public MiscTests() : base() { client.PreRequest = method => Incrementor++; } diff --git a/PocketSharp.Tests/TrendingTests.cs b/PocketSharp.Tests/TrendingTests.cs new file mode 100644 index 0000000..bc9281c --- /dev/null +++ b/PocketSharp.Tests/TrendingTests.cs @@ -0,0 +1,25 @@ +using PocketSharp.Models; +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace PocketSharp.Tests +{ + public class TrendingTests : TestsBase + { + [Fact] + public async Task AreTrendingArticlesReturned() + { + var articles = await client.GetTrendingArticles(); + Assert.NotEmpty(articles); + } + + + [Fact] + public async Task AreTrendingTopicsReturned() + { + var topics = await client.GetTrendingTopics(); + Assert.NotEmpty(topics); + } + } +} diff --git a/PocketSharp/Components/Get.cs b/PocketSharp/Components/Get.cs index 4058425..58c3a04 100644 --- a/PocketSharp/Components/Get.cs +++ b/PocketSharp/Components/Get.cs @@ -1,4 +1,4 @@ -using PocketSharp.Models; +using PocketSharp.Models; using System; using System.Collections.Generic; using System.Linq; @@ -55,7 +55,8 @@ namespace PocketSharp Domain = domain, Since = since.HasValue ? ((DateTime)since).ToUniversalTime() : since, Count = count, - Offset = offset + Offset = offset, + Version = 2 }; return (await Request("get", cancellationToken, parameters.Convert())).Items ?? new List(); @@ -224,6 +225,29 @@ namespace PocketSharp return await Request("", cancellationToken, parameters, false, true); } + + + /// + /// Get article suggestions for an existing Pocket item. + /// + /// Get suggestions based on this item. + /// Requested item count. + /// Two-letter language code for language-specific results. + /// The cancellation token. + /// + /// + public async Task> GetSuggestions(string itemId, int count = 3, string languageCode = "en", CancellationToken cancellationToken = default(CancellationToken)) + { + Dictionary parameters = new Dictionary() + { + { "resolved_id", itemId }, + { "version", "1" }, + { "locale_lang", languageCode }, + { "count", count.ToString() } + }; + + return (await Request("getSuggestedItems", cancellationToken, parameters)).Items ?? new List(); + } } diff --git a/PocketSharp/Components/Trending.cs b/PocketSharp/Components/Trending.cs new file mode 100644 index 0000000..a0c9b55 --- /dev/null +++ b/PocketSharp/Components/Trending.cs @@ -0,0 +1,48 @@ +using PocketSharp.Models; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace PocketSharp +{ + /// + /// PocketClient + /// + public partial class PocketClient + { + /// + /// Get trending articles on Pocket. + /// + /// Article count. + /// Two-letter language code for language-specific results. + /// The cancellation token. + /// + /// + public async Task> GetTrendingArticles(int count = 20, string languageCode = "en", CancellationToken cancellationToken = default(CancellationToken)) + { + return (await Request("getGlobalRecs", cancellationToken, new Dictionary() + { + { "locale_lang", languageCode }, + { "count", count.ToString() }, + { "version", "2" } + }, false)).Items ?? new List(); + } + + + /// + /// Get trending topics on Pocket. + /// + /// Two-letter language code for language-specific results. + /// The cancellation token. + /// + /// + public async Task> GetTrendingTopics(string languageCode = "en", CancellationToken cancellationToken = default(CancellationToken)) + { + return (await Request("getTrendingTopics", cancellationToken, new Dictionary() + { + { "locale_lang", languageCode }, + { "version", "2" } + }, false)).Items ?? new List(); + } + } +} diff --git a/PocketSharp/IPocketClient.cs b/PocketSharp/IPocketClient.cs index feb0b61..c6d021d 100644 --- a/PocketSharp/IPocketClient.cs +++ b/PocketSharp/IPocketClient.cs @@ -220,6 +220,17 @@ namespace PocketSharp /// /// Task GetArticle(Uri uri, bool includeImages = true, bool includeVideos = true, bool forceRefresh = false, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Get article suggestions for an existing Pocket item. + /// + /// Get suggestions based on this item. + /// Requested item count. + /// Two-letter language code for language-specific results. + /// The cancellation token. + /// + /// + Task> GetSuggestions(string itemId, int count = 3, string languageCode = "en", CancellationToken cancellationToken = default(CancellationToken)); #endregion #region modify methods @@ -465,6 +476,30 @@ namespace PocketSharp Task GetUsageLimits(CancellationToken cancellationToken = default(CancellationToken)); #endregion + #region trending methods + /// + /// Get trending articles on Pocket. + /// Requires an active GUID from GetGuid() and will therefore make two HTTP requests. + /// + /// Article count. + /// Two-letter language code for language-specific results. + /// The cancellation token. + /// + /// + Task> GetTrendingArticles(int count = 20, string languageCode = "en", CancellationToken cancellationToken = default(CancellationToken)); + + + /// + /// Get trending topics on Pocket. + /// Requires an active GUID from GetGuid() and will therefore make two HTTP requests. + /// + /// Two-letter language code for language-specific results. + /// The cancellation token. + /// + /// + Task> GetTrendingTopics(string languageCode = "en", CancellationToken cancellationToken = default(CancellationToken)); + #endregion + /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// diff --git a/PocketSharp/Models/Parameters/Parameters.cs b/PocketSharp/Models/Parameters/Parameters.cs index a8b11b1..2f05165 100644 --- a/PocketSharp/Models/Parameters/Parameters.cs +++ b/PocketSharp/Models/Parameters/Parameters.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Reflection; using System.Runtime.Serialization; @@ -74,4 +74,4 @@ namespace PocketSharp.Models return parameterDict; } } -} \ No newline at end of file +} diff --git a/PocketSharp/Models/Parameters/RetrieveParameters.cs b/PocketSharp/Models/Parameters/RetrieveParameters.cs index 8672323..7904cf3 100644 --- a/PocketSharp/Models/Parameters/RetrieveParameters.cs +++ b/PocketSharp/Models/Parameters/RetrieveParameters.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.Serialization; namespace PocketSharp.Models @@ -107,6 +107,15 @@ namespace PocketSharp.Models /// [DataMember(Name = "offset")] public int? Offset { get; set; } + + /// + /// Gets or sets the version. + /// + /// + /// The version. + /// + [DataMember(Name = "version")] + public int? Version { get; set; } } diff --git a/PocketSharp/Models/PocketItem.cs b/PocketSharp/Models/PocketItem.cs index ecfc6da..aff44ee 100644 --- a/PocketSharp/Models/PocketItem.cs +++ b/PocketSharp/Models/PocketItem.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Diagnostics; @@ -299,6 +299,15 @@ namespace PocketSharp.Models [JsonProperty("time_favorited")] public DateTime? FavoriteTime { get; set; } + /// + /// Gets or sets the published time. + /// + /// + /// The time when the article was published. + /// + [JsonProperty("date_published")] + public DateTime? PublishedTime { get; set; } + /// /// Gets or sets the tags as comma-separated strings. /// @@ -363,15 +372,6 @@ namespace PocketSharp.Models get { return Images != null && Images.Count() > 0 ? Images.First() : null; } } - /// - /// Gets and sets the JSON the model was deserialized from - /// - /// - /// Model's original JSON representation - /// - [JsonIgnore] - public string Json { get; set; } - /// /// Compares the current instance with another object of the same type and returns an integer that indicates whether the current instance precedes, follows, or occurs in the same position in the sort order as the other object. /// diff --git a/PocketSharp/Models/PocketTopic.cs b/PocketSharp/Models/PocketTopic.cs new file mode 100644 index 0000000..1c55413 --- /dev/null +++ b/PocketSharp/Models/PocketTopic.cs @@ -0,0 +1,39 @@ +using Newtonsoft.Json; +using System; + +namespace PocketSharp.Models +{ + /// + /// Topic + /// + [JsonObject] + public class PocketTopic + { + /// + /// Gets or sets the category. + /// + /// + /// The topic category. + /// + [JsonProperty("category")] + public string Category { get; set; } + + /// + /// Gets or sets the name. + /// + /// + /// The name of the topic. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the URI. + /// + /// + /// Link to the topic listing on Pocket. + /// + [JsonProperty("url")] + public Uri Uri { get; set; } + } +} diff --git a/PocketSharp/Models/Response/Topics.cs b/PocketSharp/Models/Response/Topics.cs new file mode 100644 index 0000000..bb1fa02 --- /dev/null +++ b/PocketSharp/Models/Response/Topics.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; + +namespace PocketSharp.Models +{ + /// + /// Topics Response + /// + [JsonObject] + internal class TopicsResponse : ResponseBase + { + /// + /// Gets the topics. + /// + /// + /// The topics. + /// + [JsonProperty("topics")] + public IEnumerable Items { get; set; } + } +} diff --git a/PocketSharp/PocketClient.cs b/PocketSharp/PocketClient.cs index a72f75f..6e987fc 100644 --- a/PocketSharp/PocketClient.cs +++ b/PocketSharp/PocketClient.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using PocketSharp.Models; using System; @@ -103,6 +103,14 @@ namespace PocketSharp /// public Action PreRequest { get; set; } + /// + /// Action which is executed after every request + /// + /// + /// The after request callback. + /// + public Action AfterRequest { get; set; } + /// /// Initializes a new instance of the class. @@ -233,10 +241,7 @@ namespace PocketSharp request.Content = new FormUrlEncodedContent(parameters); // call pre request action - if (PreRequest != null) - { - PreRequest(method); - } + PreRequest?.Invoke(method); // make async request try @@ -280,6 +285,9 @@ namespace PocketSharp } } + // call after request action + AfterRequest?.Invoke(responseString); + // cache response if (cacheHTTPResponseData) { diff --git a/PocketSharp/Utilities/JsonExtensions.cs b/PocketSharp/Utilities/JsonExtensions.cs index a9cfbfe..6481d18 100644 --- a/PocketSharp/Utilities/JsonExtensions.cs +++ b/PocketSharp/Utilities/JsonExtensions.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using System; @@ -51,7 +51,19 @@ namespace PocketSharp return null; } - return new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(Convert.ToDouble(reader.Value)); + double value; + if (!Double.TryParse(reader.Value.ToString(), out value)) + { + DateTime date; + if (DateTime.TryParse(reader.Value.ToString(), out date)) + { + return date; + } + + return null; + } + + return new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(value); } }