From 4129d95d55ed795a47d0fe1e920af3cccaeaf3ab Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Fri, 18 Nov 2016 16:27:10 +0300 Subject: [PATCH 01/23] readme update --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c5b9d69..76aebe3f 100644 --- a/README.md +++ b/README.md @@ -59,10 +59,11 @@ MIT # Terms and conditions +- Anyone who uses this wrapper MUST follow [Instagram Policy](https://www.instagram.com/about/legal/terms/api/) - Provided project MUST NOT be used for marketing purposes - I will not provide support to anyone who wants this API to send massive messages/likes/follows and so on - Use this API at your own risk ## Legal -This code is in no way affiliated with, authorized, maintained, sponsored or endorsed by Instagram or any of its affiliates or subsidiaries. This is an independent and unofficial API. +This code is in no way affiliated with, authorized, maintained, sponsored or endorsed by Instagram or any of its affiliates or subsidiaries. This is an independent and unofficial API wrapper. From 5d87bb01911ecfa417893de6ef4a34b4117077d9 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Fri, 18 Nov 2016 16:27:18 +0300 Subject: [PATCH 02/23] readme update From 958ec9ab1adec20391199928ed9507453e1ea225 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Sun, 27 Nov 2016 09:30:46 +0300 Subject: [PATCH 03/23] added - get current user folowers, get tag feed , get current user --- InstagramAPI.Tests/Tests/InstaApiTest.cs | 60 ++++++++++ InstagramAPI/API/IInstaApi.cs | 6 + InstagramAPI/API/InstaApi.cs | 107 ++++++++++++++++-- InstagramAPI/API/InstaApiConstants.cs | 8 +- InstagramAPI/Classes/UserCredentials.cs | 2 + InstagramAPI/Converters/InstaFeedConverter.cs | 2 +- .../Json/FeedResponseDataConverter.cs | 11 ++ InstagramAPI/Helpers/UriCreator.cs | 28 ++++- .../InstaCurrentUserResponse.cs | 15 +++ .../ResponseWrappers/InstaFeedResponse.cs | 45 +++++++- .../InstaFollowersResponse.cs | 26 +++++ .../ResponseWrappers/InstaTagFeedResponse.cs | 14 +++ 12 files changed, 304 insertions(+), 20 deletions(-) create mode 100644 InstagramAPI/Converters/Json/FeedResponseDataConverter.cs create mode 100644 InstagramAPI/ResponseWrappers/InstaCurrentUserResponse.cs create mode 100644 InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs create mode 100644 InstagramAPI/ResponseWrappers/InstaTagFeedResponse.cs diff --git a/InstagramAPI.Tests/Tests/InstaApiTest.cs b/InstagramAPI.Tests/Tests/InstaApiTest.cs index 1332b04a..a839ae68 100644 --- a/InstagramAPI.Tests/Tests/InstaApiTest.cs +++ b/InstagramAPI.Tests/Tests/InstaApiTest.cs @@ -55,5 +55,65 @@ public async void GetUserTest() Assert.NotNull(user); Assert.Equal(user.UserName, username); } + + [Fact] + public async void GetCurrentUserTest() + { + //arrange + var apiInstance = + TestHelpers.GetDefaultInstaApiInstance(new UserCredentials + { + UserName = username, + Password = password + }); + //act + if (!await TestHelpers.Login(apiInstance, output)) return; + var getUserResult = await apiInstance.GetCurrentUserAsync(); + var user = getUserResult.Value; + //assert + Assert.True(getUserResult.Succeeded); + Assert.NotNull(user); + Assert.Equal(user.UserName, username); + } + + [Fact] + public async void GetCurrentUserFollwersTest() + { + //arrange + var apiInstance = + TestHelpers.GetDefaultInstaApiInstance(new UserCredentials + { + UserName = username, + Password = password + }); + //act + if (!await TestHelpers.Login(apiInstance, output)) return; + var result = await apiInstance.GetCurrentUserFollowersAsync(); + var followers = result.Value; + //assert + Assert.True(result.Succeeded); + Assert.NotNull(followers); + } + + [Theory] + [InlineData("christmas")] + [InlineData("rock")] + public async void GetTagFeedTest(string tag) + { + //arrange + var apiInstance = + TestHelpers.GetDefaultInstaApiInstance(new UserCredentials + { + UserName = username, + Password = password + }); + //act + if (!await TestHelpers.Login(apiInstance, output)) return; + var result = await apiInstance.GetTagFeedAsync(tag); + var tagFeed = result.Value; + //assert + Assert.True(result.Succeeded); + Assert.NotNull(tagFeed); + } } } \ No newline at end of file diff --git a/InstagramAPI/API/IInstaApi.cs b/InstagramAPI/API/IInstaApi.cs index fdba9a06..258336b3 100644 --- a/InstagramAPI/API/IInstaApi.cs +++ b/InstagramAPI/API/IInstaApi.cs @@ -17,5 +17,11 @@ public interface IInstaApi Task> LoginAsync(); IResult GetUserFeed(int maxPages = 0); Task> GetUserFeedAsync(int maxPages = 0); + Task> GetCurrentUserAsync(); + IResult GetCurrentUser(); + IResult GetCurentUserFollowers(); + Task> GetCurrentUserFollowersAsync(); + IResult GetTagFeed(string tag); + Task> GetTagFeedAsync(string tag); } } \ No newline at end of file diff --git a/InstagramAPI/API/InstaApi.cs b/InstagramAPI/API/InstaApi.cs index 08e4c81b..5d824583 100644 --- a/InstagramAPI/API/InstaApi.cs +++ b/InstagramAPI/API/InstaApi.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Net; using System.Net.Http; +using System.Reflection; using System.Threading.Tasks; using InstagramAPI.Classes; using InstagramAPI.Classes.Android.DeviceInfo; @@ -12,6 +13,8 @@ using InstagramAPI.Logger; using InstagramAPI.ResponseWrappers; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; namespace InstagramAPI.API { @@ -67,7 +70,15 @@ public IResult Login() { return LoginAsync().Result; } + public IResult GetTagFeed(string tag) + { + return GetTagFeedAsync(tag).Result; + } + public IResult GetCurentUserFollowers() + { + return GetCurrentUserFollowersAsync().Result; + } #endregion #region async part @@ -125,19 +136,53 @@ public async Task> GetUserAsync(string username) } + public IResult GetCurrentUser() + { + return GetCurrentUserAsync().Result; + } + public async Task> GetCurrentUserAsync() + { + ValidateUser(); + if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); + var instaUri = UriCreator.GetCurrentUserUri(); + dynamic jsonObject = new JObject(); + jsonObject._uuid = _deviceInfo.DeviceGuid; + jsonObject._uid = _user.LoggedInUder.Pk; + jsonObject._csrftoken = _user.CsrfToken; + var fields = new Dictionary + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUder.Pk}, + { "_csrftoken", _user.CsrfToken} + }; + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri); + request.Content = new FormUrlEncodedContent(fields); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + { + var user = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.GetUserConverter(user.User); + var userConverted = converter.Convert(); + + return Result.Success(userConverted); + } + return Result.Fail("", (InstaUser)null); + } + public async Task> GetUserFeedAsync(int maxPages = 0) { ValidateUser(); if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); var userFeedUri = UriCreator.GetUserFeedUri(); var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri); - request.Headers.Add(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, _deviceInfo.GoogleAdId.ToString()); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, _deviceInfo.GoogleAdId.ToString())); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); var feed = new InstaFeed(); if (response.StatusCode == HttpStatusCode.OK) { - var feedResponse = JsonConvert.DeserializeObject(json); + var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); var converter = ConvertersFabric.GetFeedConverter(feedResponse); var feedConverted = converter.Convert(); feed.Items.AddRange(feedConverted.Items); @@ -153,7 +198,47 @@ public async Task> GetUserFeedAsync(int maxPages = 0) } return Result.Fail("", (InstaFeed)null); } + public async Task> GetCurrentUserFollowersAsync() + { + ValidateUser(); + if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); + var userFeedUri = UriCreator.GetUserFollowersUri(_user.LoggedInUder.Pk, _user.RankToken); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + var followers = new InstaUserList(); + if (response.StatusCode == HttpStatusCode.OK) + { + var followersResponse = JsonConvert.DeserializeObject(json); + if (!followersResponse.IsOK()) Result.Fail("", (InstaUserList)null); + foreach (var user in followersResponse.Items) + { + var converter = ConvertersFabric.GetUserConverter(user); + var userConverted = converter.Convert(); + followers.Add(userConverted); + } + return Result.Success(followers); + } + return Result.Fail("", (InstaUserList)null); + } + public async Task> GetTagFeedAsync(string tag) + { + ValidateUser(); + if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); + var userFeedUri = UriCreator.GetExploreUri(tag); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + { + var feedResponse = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.GetMediaListConverter(feedResponse); + var mediaList = converter.Convert(); + return Result.Success(mediaList); + } + return Result.Fail("", (InstaMediaList)null); + } public async Task> GetUserMediaAsync(string username, int maxPages = 0) { ValidateUser(); @@ -187,6 +272,11 @@ public async Task> LoginAsync() ValidateUser(); ValidateRequestMessage(); _httpClient.DefaultRequestHeaders.Add(InstaApiConstants.HEADER_USER_AGENT, InstaApiConstants.USER_AGENT); + var csrftoken = string.Empty; + var firstResponse = await _httpClient.GetAsync(_httpClient.BaseAddress); + var cookies = _httpHandler.CookieContainer.GetCookies(_httpClient.BaseAddress); + foreach (Cookie cookie in cookies) if (cookie.Name == InstaApiConstants.CSRFTOKEN) csrftoken = cookie.Value; + _user.CsrfToken = csrftoken; var instaUri = UriCreator.GetLogintUri(); var signature = $"{_requestMessage.GenerateSignature()}.{_requestMessage.GetMessageString()}"; var fields = new Dictionary @@ -210,7 +300,7 @@ public async Task> LoginAsync() IsUserAuthenticated = (loginInfo.User != null) && (loginInfo.User.UserName == _user.UserName); var converter = ConvertersFabric.GetUserConverter(loginInfo.User); _user.LoggedInUder = converter.Convert(); - _user.RankToken = $"{_user.LoggedInUder.Pk}_{Guid.NewGuid()}"; + _user.RankToken = $"{_user.LoggedInUder.Pk}_{_requestMessage.phone_id}"; return Result.Success(true); } else @@ -242,12 +332,12 @@ private InstaFeedResponse _getFeedResponseWithMaxId(string nextId) var userUriBuilder = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }; var request = new HttpRequestMessage(HttpMethod.Get, userUriBuilder.Uri); request.Headers.Clear(); - request.Headers.Add(InstaApiConstants.HEADER_PHONE_ID, _requestMessage.phone_id); - request.Headers.Add(InstaApiConstants.HEADER_TIMEZONE, InstaApiConstants.TIMEZONE_OFFSET.ToString()); - request.Headers.Add(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, _deviceInfo.GoogleAdId.ToString()); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_PHONE_ID, _requestMessage.phone_id)); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, InstaApiConstants.TIMEZONE_OFFSET.ToString())); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, _deviceInfo.GoogleAdId.ToString())); var response = _httpClient.SendAsync(request); var json = response.Result.Content.ReadAsStringAsync().Result; - if (response.Result.StatusCode == HttpStatusCode.OK) return JsonConvert.DeserializeObject(json); + if (response.Result.StatusCode == HttpStatusCode.OK) return JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); return null; } @@ -255,13 +345,12 @@ private InstaMediaListResponse _getMediaListResponseWithMaxId(string userPk, str { var instaUri = UriCreator.GetMediaListWithMaxIdUri(userPk, nextId); var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri); - request.Headers.Add(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, _deviceInfo.GoogleAdId.ToString()); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, _deviceInfo.GoogleAdId.ToString())); var response = _httpClient.SendAsync(request); var json = response.Result.Content.ReadAsStringAsync().Result; if (response.Result.StatusCode == HttpStatusCode.OK) return JsonConvert.DeserializeObject(json); return null; } - #endregion } } \ No newline at end of file diff --git a/InstagramAPI/API/InstaApiConstants.cs b/InstagramAPI/API/InstaApiConstants.cs index 5ec2a3c6..15e4a127 100644 --- a/InstagramAPI/API/InstaApiConstants.cs +++ b/InstagramAPI/API/InstaApiConstants.cs @@ -22,21 +22,21 @@ public static class InstaApiConstants public const string GET_MEDIA = API_SUFFIX + "/v1/media/{0}/info/"; public const string HEADER_USER_AGENT = "User-Agent"; - public const string USER_AGENT = "Instagram 8.0.0 Android (23/6.0.1; 640dpi; 1440x2560; samsung; SM-G935F; hero2lte; samsungexynos8890; en_NZ)"; + public const string USER_AGENT = "Instagram 9.7.0 Android (23/6.0.1; 640dpi; 1440x2560; samsung; SM-G935F; hero2lte; samsungexynos8890; en_NZ)"; public const string HEADER_QUERY = "q"; public const string HEADER_RANK_TOKEN = "rank_token"; public const string HEADER_COUNT = "count"; - public const string IG_SIGNATURE_KEY = "9b3b9e55988c954e51477da115c58ae82dcae7ac01c735b4443a3c5923cb593a"; + public const string IG_SIGNATURE_KEY = "2f6dcdf76deb0d3fd008886d032162a79b88052b5f50538c1ee93c4fe7d02e60"; public const string HEADER_IG_SIGNATURE = "signed_body"; public const string IG_SIGNATURE_KEY_VERSION = "4"; public const string HEADER_IG_SIGNATURE_KEY_VERSION = "ig_sig_key_version"; - public const string IG_CAPABILITIES = "3Q=="; + public const string IG_CAPABILITIES = "3Ro="; public const string HEADER_IG_CAPABILITIES = "X-IG-Capabilities"; public const string IG_CONNECTION_TYPE = "WIFI"; public const string HEADER_IG_CONNECTION_TYPE = "X-IG-Connection-Type"; - public const string ACCEPT_LANGUAGE = "en-NZ"; + public const string ACCEPT_LANGUAGE = "en-US"; public const string HEADER_ACCEPT_LANGUAGE = "Accept-Language"; public const string ACCEPT_ENCODING = "gzip, deflate, sdch"; public const string HEADER_ACCEPT_ENCODING = "gzip, deflate, sdch"; diff --git a/InstagramAPI/Classes/UserCredentials.cs b/InstagramAPI/Classes/UserCredentials.cs index cf6e894b..4a75233d 100644 --- a/InstagramAPI/Classes/UserCredentials.cs +++ b/InstagramAPI/Classes/UserCredentials.cs @@ -10,5 +10,7 @@ public class UserCredentials public InstaUser LoggedInUder { get; set; } public string RankToken { get; set; } + public string CsrfToken { get; set; } + } } \ No newline at end of file diff --git a/InstagramAPI/Converters/InstaFeedConverter.cs b/InstagramAPI/Converters/InstaFeedConverter.cs index 222718ae..f25e879d 100644 --- a/InstagramAPI/Converters/InstaFeedConverter.cs +++ b/InstagramAPI/Converters/InstaFeedConverter.cs @@ -13,7 +13,7 @@ public InstaFeed Convert() foreach (var instaUserFeedItemResponse in SourceObject.Items) { - if (instaUserFeedItemResponse.Type != 0) continue; + if (instaUserFeedItemResponse?.Type != 0) continue; var feedItem = ConvertersFabric.GetSingleMediaConverter(instaUserFeedItemResponse).Convert(); feed.Items.Add(feedItem); } diff --git a/InstagramAPI/Converters/Json/FeedResponseDataConverter.cs b/InstagramAPI/Converters/Json/FeedResponseDataConverter.cs new file mode 100644 index 00000000..ff4ee147 --- /dev/null +++ b/InstagramAPI/Converters/Json/FeedResponseDataConverter.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace InstagramAPI.Converters.Json +{ + public class FeedResponseDataConverter + { + } +} diff --git a/InstagramAPI/Helpers/UriCreator.cs b/InstagramAPI/Helpers/UriCreator.cs index 0b7b0f2d..d01a91bf 100644 --- a/InstagramAPI/Helpers/UriCreator.cs +++ b/InstagramAPI/Helpers/UriCreator.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using InstagramAPI.API; namespace InstagramAPI.Helpers @@ -17,7 +18,7 @@ public static Uri GetUserUri(string username) { Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.SEARCH_USERS, out instaUri)) throw new Exception("Cant create search user URI"); - var userUriBuilder = new UriBuilder(instaUri) {Query = $"q={username}"}; + var userUriBuilder = new UriBuilder(instaUri) { Query = $"q={username}" }; return userUriBuilder.Uri; } @@ -46,7 +47,7 @@ public static Uri GetTimelineWithMaxIdUri(string nextId) { Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search URI for timeline"); - var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}; + var uriBuilder = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }; return uriBuilder.Uri; } @@ -54,8 +55,29 @@ public static Uri GetMediaListWithMaxIdUri(string userPk, string nextId) { Uri instaUri; if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.USEREFEED + userPk + "/", out instaUri)) throw new Exception("Cant create URI for media list"); - var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}; + var uriBuilder = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }; return uriBuilder.Uri; } + + public static Uri GetCurrentUserUri() + { + Uri instaUri; + if (!Uri.TryCreate(BaseInstagramUri, @"/api/v1/accounts/current_user?edit=true", out instaUri)) throw new Exception("Cant create URI for user login"); + return instaUri; + } + + internal static Uri GetUserFollowersUri(string userPk, string rankToken) + { + Uri instaUri; + if (!Uri.TryCreate(BaseInstagramUri, $@"/api/v1/friendships/{userPk}/followers/?rank_token={rankToken}", out instaUri)) throw new Exception("Cant create URI for user followers"); + return instaUri; + } + + public static Uri GetExploreUri(string tag) + { + Uri instaUri; + if (!Uri.TryCreate(BaseInstagramUri, $@"/api/v1/feed/tag/{tag}/", out instaUri)) throw new Exception("Cant create URI for discover-explore"); + return instaUri; + } } } \ No newline at end of file diff --git a/InstagramAPI/ResponseWrappers/InstaCurrentUserResponse.cs b/InstagramAPI/ResponseWrappers/InstaCurrentUserResponse.cs new file mode 100644 index 00000000..fa4f5e65 --- /dev/null +++ b/InstagramAPI/ResponseWrappers/InstaCurrentUserResponse.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using InstagramAPI.ResponseWrappers.BaseResponse; +using Newtonsoft.Json; + +namespace InstagramAPI.ResponseWrappers +{ + public class InstaCurrentUserResponse : BaseStatusResponse + { + [JsonProperty("user")] + public InstaUserResponse User { get; set; } + } +} diff --git a/InstagramAPI/ResponseWrappers/InstaFeedResponse.cs b/InstagramAPI/ResponseWrappers/InstaFeedResponse.cs index b8379ca5..5b555373 100644 --- a/InstagramAPI/ResponseWrappers/InstaFeedResponse.cs +++ b/InstagramAPI/ResponseWrappers/InstaFeedResponse.cs @@ -1,6 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using InstagramAPI.ResponseWrappers.BaseResponse; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace InstagramAPI.ResponseWrappers { @@ -9,7 +11,44 @@ public class InstaFeedResponse : BaseLoadableResponse [JsonProperty("is_direct_v2_enabled")] public bool IsDirectV2Enabled { get; set; } - [JsonProperty("items")] - public List Items { get; set; } + [JsonProperty(TypeNameHandling = TypeNameHandling.Auto)] + public List Items { get; set; } = new List(); + } + + public class FeedResponseDataConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return (objectType == typeof(InstaFeedResponse)); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var token = JToken.Load(reader); + var feed = token.ToObject(); + var items = token["feed_items"]; + if (items != null) + { + foreach (var item in items) + { + var mediaOrAd = item["media_or_ad"]; + if (mediaOrAd == null) continue; + var media = mediaOrAd.ToObject(); + feed.Items.Add(media); + } + } + else + { + items = token["items"]; + feed.Items = items.ToObject>(); + } + + return feed; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value); + } } } \ No newline at end of file diff --git a/InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs b/InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs new file mode 100644 index 00000000..7949bef2 --- /dev/null +++ b/InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using InstagramAPI.ResponseWrappers.BaseResponse; +using Newtonsoft.Json; + +namespace InstagramAPI.ResponseWrappers +{ + public class InstaFollowersResponse : BaseStatusResponse + { + [JsonProperty("users")] + public List Items { get; set; } + + [JsonProperty("big_list")] + public bool IsBigList { get; set; } + + [JsonProperty("page_size")] + public int PageSize { get; set; } + + public bool IsOK() + { + return !string.IsNullOrEmpty(Status) && Status.ToLower() == "ok"; + } + } +} diff --git a/InstagramAPI/ResponseWrappers/InstaTagFeedResponse.cs b/InstagramAPI/ResponseWrappers/InstaTagFeedResponse.cs new file mode 100644 index 00000000..43b70bdd --- /dev/null +++ b/InstagramAPI/ResponseWrappers/InstaTagFeedResponse.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace InstagramAPI.ResponseWrappers +{ + public class InstaTagFeedResponse + { + [JsonProperty("ranked_items")] + public List Items { get; set; } + } +} From 1899f09cc4d603a9bcb9d7a36bdd7cc0c832ea28 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Sun, 27 Nov 2016 19:51:53 +0300 Subject: [PATCH 04/23] updated media and feed methods --- InstagramAPI.Tests/Tests/InstaApiTest.cs | 50 +++++----- InstagramAPI/API/IInstaApi.cs | 4 + InstagramAPI/API/InstaApi.cs | 96 ++++++++++++------- InstagramAPI/API/InstaApiConstants.cs | 4 +- InstagramAPI/Classes/Models/InstaUser.cs | 2 +- InstagramAPI/Classes/UserCredentials.cs | 1 - InstagramAPI/Converters/ConvertersFabric.cs | 12 +-- .../Json/FeedResponseDataConverter.cs | 43 ++++++++- InstagramAPI/Helpers/DateTimeHelper.cs | 3 +- InstagramAPI/Helpers/UriCreator.cs | 7 +- .../InstaCurrentUserResponse.cs | 8 +- .../ResponseWrappers/InstaFeedResponse.cs | 37 ------- .../InstaFollowersResponse.cs | 9 +- .../ResponseWrappers/InstaTagFeedResponse.cs | 7 +- 14 files changed, 152 insertions(+), 131 deletions(-) diff --git a/InstagramAPI.Tests/Tests/InstaApiTest.cs b/InstagramAPI.Tests/Tests/InstaApiTest.cs index a839ae68..ce6bbd70 100644 --- a/InstagramAPI.Tests/Tests/InstaApiTest.cs +++ b/InstagramAPI.Tests/Tests/InstaApiTest.cs @@ -17,8 +17,10 @@ public InstaApiTest(ITestOutputHelper output) private readonly string username = "alex_codegarage"; private readonly string password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - [Fact] - public async void GetUserFeedTest() + [Theory] + [InlineData("christmas")] + [InlineData("rock")] + public async void GetTagFeedTest(string tag) { //arrange var apiInstance = @@ -29,15 +31,15 @@ public async void GetUserFeedTest() }); //act if (!await TestHelpers.Login(apiInstance, output)) return; - var getFeedResult = await apiInstance.GetUserFeedAsync(5); - var feed = getFeedResult.Value; + var result = await apiInstance.GetTagFeedAsync(tag); + var tagFeed = result.Value; //assert - Assert.True(getFeedResult.Succeeded); - Assert.NotNull(feed); + Assert.True(result.Succeeded); + Assert.NotNull(tagFeed); } [Fact] - public async void GetUserTest() + public async void GetCurrentUserFollwersTest() { //arrange var apiInstance = @@ -48,12 +50,11 @@ public async void GetUserTest() }); //act if (!await TestHelpers.Login(apiInstance, output)) return; - var getUserResult = await apiInstance.GetUserAsync(username); - var user = getUserResult.Value; + var result = await apiInstance.GetCurrentUserFollowersAsync(); + var followers = result.Value; //assert - Assert.True(getUserResult.Succeeded); - Assert.NotNull(user); - Assert.Equal(user.UserName, username); + Assert.True(result.Succeeded); + Assert.NotNull(followers); } [Fact] @@ -77,7 +78,7 @@ public async void GetCurrentUserTest() } [Fact] - public async void GetCurrentUserFollwersTest() + public async void GetUserFeedTest() { //arrange var apiInstance = @@ -88,17 +89,15 @@ public async void GetCurrentUserFollwersTest() }); //act if (!await TestHelpers.Login(apiInstance, output)) return; - var result = await apiInstance.GetCurrentUserFollowersAsync(); - var followers = result.Value; + var getFeedResult = await apiInstance.GetUserFeedAsync(5); + var feed = getFeedResult.Value; //assert - Assert.True(result.Succeeded); - Assert.NotNull(followers); + Assert.True(getFeedResult.Succeeded); + Assert.NotNull(feed); } - [Theory] - [InlineData("christmas")] - [InlineData("rock")] - public async void GetTagFeedTest(string tag) + [Fact] + public async void GetUserTest() { //arrange var apiInstance = @@ -109,11 +108,12 @@ public async void GetTagFeedTest(string tag) }); //act if (!await TestHelpers.Login(apiInstance, output)) return; - var result = await apiInstance.GetTagFeedAsync(tag); - var tagFeed = result.Value; + var getUserResult = await apiInstance.GetUserAsync(username); + var user = getUserResult.Value; //assert - Assert.True(result.Succeeded); - Assert.NotNull(tagFeed); + Assert.True(getUserResult.Succeeded); + Assert.NotNull(user); + Assert.Equal(user.UserName, username); } } } \ No newline at end of file diff --git a/InstagramAPI/API/IInstaApi.cs b/InstagramAPI/API/IInstaApi.cs index 258336b3..f361cbe4 100644 --- a/InstagramAPI/API/IInstaApi.cs +++ b/InstagramAPI/API/IInstaApi.cs @@ -23,5 +23,9 @@ public interface IInstaApi Task> GetCurrentUserFollowersAsync(); IResult GetTagFeed(string tag); Task> GetTagFeedAsync(string tag); + Task> GetUserFeedWithMaxIdAsync(string nextId); + IResult GetUserFeedWithMaxId(string nextId); + Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId); + IResult GetUserMediaListWithMaxId(string userPk, string nextId); } } \ No newline at end of file diff --git a/InstagramAPI/API/InstaApi.cs b/InstagramAPI/API/InstaApi.cs index 5d824583..115d25ee 100644 --- a/InstagramAPI/API/InstaApi.cs +++ b/InstagramAPI/API/InstaApi.cs @@ -3,18 +3,17 @@ using System.Linq; using System.Net; using System.Net.Http; -using System.Reflection; using System.Threading.Tasks; using InstagramAPI.Classes; using InstagramAPI.Classes.Android.DeviceInfo; using InstagramAPI.Classes.Models; using InstagramAPI.Converters; +using InstagramAPI.Converters.Json; using InstagramAPI.Helpers; using InstagramAPI.Logger; using InstagramAPI.ResponseWrappers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Serialization; namespace InstagramAPI.API { @@ -70,6 +69,7 @@ public IResult Login() { return LoginAsync().Result; } + public IResult GetTagFeed(string tag) { return GetTagFeedAsync(tag).Result; @@ -79,6 +79,17 @@ public IResult GetCurentUserFollowers() { return GetCurrentUserFollowersAsync().Result; } + + public IResult GetUserFeedWithMaxId(string nextId) + { + return GetUserFeedWithMaxIdAsync(nextId).Result; + } + + public IResult GetUserMediaListWithMaxId(string userPk, string nextId) + { + return GetUserMediaListWithMaxIdAsync(userPk, nextId).Result; + } + #endregion #region async part @@ -133,13 +144,13 @@ public async Task> GetUserAsync(string username) var badRequest = JsonConvert.DeserializeObject(json); _logger.Write(badRequest.Message); return Result.Fail(badRequest.Message, (InstaUser)null); - } public IResult GetCurrentUser() { return GetCurrentUserAsync().Result; } + public async Task> GetCurrentUserAsync() { ValidateUser(); @@ -153,7 +164,7 @@ public async Task> GetCurrentUserAsync() { {"_uuid", _deviceInfo.DeviceGuid.ToString()}, {"_uid", _user.LoggedInUder.Pk}, - { "_csrftoken", _user.CsrfToken} + {"_csrftoken", _user.CsrfToken} }; var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri); request.Content = new FormUrlEncodedContent(fields); @@ -188,7 +199,7 @@ public async Task> GetUserFeedAsync(int maxPages = 0) feed.Items.AddRange(feedConverted.Items); while (feedResponse.MoreAvailable && (feed.Pages < maxPages)) { - feedResponse = _getFeedResponseWithMaxId(feedResponse.NextMaxId); + var nextFeed = await GetUserFeedWithMaxIdAsync(feedResponse.NextMaxId); converter = ConvertersFabric.GetFeedConverter(feedResponse); feedConverted = converter.Convert(); feed.Items.AddRange(feedConverted.Items); @@ -198,6 +209,7 @@ public async Task> GetUserFeedAsync(int maxPages = 0) } return Result.Fail("", (InstaFeed)null); } + public async Task> GetCurrentUserFollowersAsync() { ValidateUser(); @@ -239,6 +251,7 @@ public async Task> GetTagFeedAsync(string tag) } return Result.Fail("", (InstaMediaList)null); } + public async Task> GetUserMediaAsync(string username, int maxPages = 0) { ValidateUser(); @@ -255,8 +268,8 @@ public async Task> GetUserMediaAsync(string username, in var mediaList = converter.Convert(); while (mediaResponse.MoreAvailable && (mediaList.Pages < maxPages)) { - mediaResponse = _getMediaListResponseWithMaxId(user.Pk, mediaResponse.NextMaxId); - converter = ConvertersFabric.GetMediaListConverter(mediaResponse); + var nextMedia = await GetUserMediaListWithMaxIdAsync(user.Pk, mediaResponse.NextMaxId); + if (!nextMedia.Succeeded) continue; mediaList.AddRange(converter.Convert()); mediaList.Pages++; } @@ -267,6 +280,49 @@ public async Task> GetUserMediaAsync(string username, in return Result.Fail(badRequest.Message, (InstaMediaList)null); } + public async Task> GetUserFeedWithMaxIdAsync(string nextId) + { + Uri instaUri; + if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search user URI"); + var userUriBuilder = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }; + var request = new HttpRequestMessage(HttpMethod.Get, userUriBuilder.Uri); + request.Headers.Clear(); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_PHONE_ID, _requestMessage.phone_id)); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, InstaApiConstants.TIMEZONE_OFFSET.ToString())); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, _deviceInfo.GoogleAdId.ToString())); + + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + var feed = new InstaFeed(); + if (response.StatusCode == HttpStatusCode.OK) + { + var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); + var converter = ConvertersFabric.GetFeedConverter(feedResponse); + var feedConverted = converter.Convert(); + feed.Items.AddRange(feedConverted.Items); + return Result.Success(feed); + } + return Result.Fail("", (InstaFeed)null); + } + + public async Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId) + { + var instaUri = UriCreator.GetMediaListWithMaxIdUri(userPk, nextId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, _deviceInfo.GoogleAdId.ToString())); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + { + var mediaResponse = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.GetMediaListConverter(mediaResponse); + var mediaList = converter.Convert(); + return Result.Success(mediaList); + } + + return Result.Fail("", (InstaMediaList)null); + } + public async Task> LoginAsync() { ValidateUser(); @@ -325,32 +381,6 @@ private void ValidateRequestMessage() if ((_requestMessage == null) || _requestMessage.IsEmpty()) throw new ArgumentException("API request message null or empty"); } - private InstaFeedResponse _getFeedResponseWithMaxId(string nextId) - { - Uri instaUri; - if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search user URI"); - var userUriBuilder = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }; - var request = new HttpRequestMessage(HttpMethod.Get, userUriBuilder.Uri); - request.Headers.Clear(); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_PHONE_ID, _requestMessage.phone_id)); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, InstaApiConstants.TIMEZONE_OFFSET.ToString())); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, _deviceInfo.GoogleAdId.ToString())); - var response = _httpClient.SendAsync(request); - var json = response.Result.Content.ReadAsStringAsync().Result; - if (response.Result.StatusCode == HttpStatusCode.OK) return JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); - return null; - } - - private InstaMediaListResponse _getMediaListResponseWithMaxId(string userPk, string nextId) - { - var instaUri = UriCreator.GetMediaListWithMaxIdUri(userPk, nextId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, _deviceInfo.GoogleAdId.ToString())); - var response = _httpClient.SendAsync(request); - var json = response.Result.Content.ReadAsStringAsync().Result; - if (response.Result.StatusCode == HttpStatusCode.OK) return JsonConvert.DeserializeObject(json); - return null; - } #endregion } } \ No newline at end of file diff --git a/InstagramAPI/API/InstaApiConstants.cs b/InstagramAPI/API/InstaApiConstants.cs index 15e4a127..cc18eb0e 100644 --- a/InstagramAPI/API/InstaApiConstants.cs +++ b/InstagramAPI/API/InstaApiConstants.cs @@ -2,6 +2,7 @@ { public static class InstaApiConstants { + public const string CURRENTUSER = API_SUFFIX + "/v1/accounts/current_user?edit=true"; public const string MAX_MEDIA_ID_POSTFIX = "/media/?max_id="; public const string HEADER_MAX_ID = "max_id"; public const string MEDIA = "/media/"; @@ -20,7 +21,8 @@ public static class InstaApiConstants public const string TIMELINEFEED = API_SUFFIX + "/v1/feed/timeline/"; public const string USEREFEED = API_SUFFIX + "/v1/feed/user/"; public const string GET_MEDIA = API_SUFFIX + "/v1/media/{0}/info/"; - + public const string GET_USER_FOLLOWERS = API_SUFFIX + "/v1/friendships/{0}/followers/?rank_token={1}"; + public const string GET_TAG_FEED = API_SUFFIX + "/v1/feed/tag/{0}/"; public const string HEADER_USER_AGENT = "User-Agent"; public const string USER_AGENT = "Instagram 9.7.0 Android (23/6.0.1; 640dpi; 1440x2560; samsung; SM-G935F; hero2lte; samsungexynos8890; en_NZ)"; diff --git a/InstagramAPI/Classes/Models/InstaUser.cs b/InstagramAPI/Classes/Models/InstaUser.cs index 6506a129..5206e6a0 100644 --- a/InstagramAPI/Classes/Models/InstaUser.cs +++ b/InstagramAPI/Classes/Models/InstaUser.cs @@ -25,6 +25,6 @@ public class InstaUser public string Pk { get; set; } public string MutualFollowersCount { get; set; } - public static InstaUser Empty => new InstaUser { FullName = string.Empty, UserName = string.Empty }; + public static InstaUser Empty => new InstaUser {FullName = string.Empty, UserName = string.Empty}; } } \ No newline at end of file diff --git a/InstagramAPI/Classes/UserCredentials.cs b/InstagramAPI/Classes/UserCredentials.cs index 4a75233d..74f68a51 100644 --- a/InstagramAPI/Classes/UserCredentials.cs +++ b/InstagramAPI/Classes/UserCredentials.cs @@ -11,6 +11,5 @@ public class UserCredentials public string RankToken { get; set; } public string CsrfToken { get; set; } - } } \ No newline at end of file diff --git a/InstagramAPI/Converters/ConvertersFabric.cs b/InstagramAPI/Converters/ConvertersFabric.cs index e87939be..caf41877 100644 --- a/InstagramAPI/Converters/ConvertersFabric.cs +++ b/InstagramAPI/Converters/ConvertersFabric.cs @@ -7,34 +7,34 @@ internal class ConvertersFabric { internal static IObjectConverter GetUserConverter(InstaUserResponse instaresponse) { - return new InstaUsersConverter { SourceObject = instaresponse }; + return new InstaUsersConverter {SourceObject = instaresponse}; } public static IObjectConverter GetSingleMediaConverter( InstaMediaItemResponse responseMedia) { - return new InstaMediaConverter { SourceObject = responseMedia }; + return new InstaMediaConverter {SourceObject = responseMedia}; } internal static IObjectConverter GetFeedConverter( InstaFeedResponse feedResponse) { - return new InstaFeedConverter { SourceObject = feedResponse }; + return new InstaFeedConverter {SourceObject = feedResponse}; } public static IObjectConverter GetMediaListConverter(InstaMediaListResponse mediaResponse) { - return new InstaMediaListConverter { SourceObject = mediaResponse }; + return new InstaMediaListConverter {SourceObject = mediaResponse}; } public static IObjectConverter GetCaptionConverter(InstaCaptionResponse captionResponse) { - return new InstaCaptionConverter { SourceObject = captionResponse }; + return new InstaCaptionConverter {SourceObject = captionResponse}; } public static IObjectConverter GetFriendShipStatusConverter(InstaFriendshipStatusResponse friendshipStatusResponse) { - return new InstaFriendshipStatusConverter { SourceObject = friendshipStatusResponse }; + return new InstaFriendshipStatusConverter {SourceObject = friendshipStatusResponse}; } } } \ No newline at end of file diff --git a/InstagramAPI/Converters/Json/FeedResponseDataConverter.cs b/InstagramAPI/Converters/Json/FeedResponseDataConverter.cs index ff4ee147..a11f30a5 100644 --- a/InstagramAPI/Converters/Json/FeedResponseDataConverter.cs +++ b/InstagramAPI/Converters/Json/FeedResponseDataConverter.cs @@ -1,11 +1,46 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using InstagramAPI.ResponseWrappers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace InstagramAPI.Converters.Json { - public class FeedResponseDataConverter + + public class FeedResponseDataConverter : JsonConverter { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(InstaFeedResponse); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var token = JToken.Load(reader); + var feed = token.ToObject(); + var items = token["feed_items"]; + if (items != null) + { + foreach (var item in items) + { + var mediaOrAd = item["media_or_ad"]; + if (mediaOrAd == null) continue; + var media = mediaOrAd.ToObject(); + feed.Items.Add(media); + } + } + else + { + items = token["items"]; + feed.Items = items.ToObject>(); + } + + return feed; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value); + } } -} +} \ No newline at end of file diff --git a/InstagramAPI/Helpers/DateTimeHelper.cs b/InstagramAPI/Helpers/DateTimeHelper.cs index 9fe8318a..2c998a85 100644 --- a/InstagramAPI/Helpers/DateTimeHelper.cs +++ b/InstagramAPI/Helpers/DateTimeHelper.cs @@ -12,8 +12,7 @@ public static DateTime UnixTimestampToDateTime(double unixTime) dateTime = dateTime.AddSeconds(unixTime).ToUniversalTime(); return dateTime; } - catch (Exception) - { + catch (Exception) { return DateTime.MinValue; } } diff --git a/InstagramAPI/Helpers/UriCreator.cs b/InstagramAPI/Helpers/UriCreator.cs index d01a91bf..5012a7dd 100644 --- a/InstagramAPI/Helpers/UriCreator.cs +++ b/InstagramAPI/Helpers/UriCreator.cs @@ -1,5 +1,4 @@ using System; -using System.Globalization; using InstagramAPI.API; namespace InstagramAPI.Helpers @@ -62,21 +61,21 @@ public static Uri GetMediaListWithMaxIdUri(string userPk, string nextId) public static Uri GetCurrentUserUri() { Uri instaUri; - if (!Uri.TryCreate(BaseInstagramUri, @"/api/v1/accounts/current_user?edit=true", out instaUri)) throw new Exception("Cant create URI for user login"); + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.CURRENTUSER, out instaUri)) throw new Exception("Cant create URI for current user info"); return instaUri; } internal static Uri GetUserFollowersUri(string userPk, string rankToken) { Uri instaUri; - if (!Uri.TryCreate(BaseInstagramUri, $@"/api/v1/friendships/{userPk}/followers/?rank_token={rankToken}", out instaUri)) throw new Exception("Cant create URI for user followers"); + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_FOLLOWERS, userPk, rankToken), out instaUri)) throw new Exception("Cant create URI for user followers"); return instaUri; } public static Uri GetExploreUri(string tag) { Uri instaUri; - if (!Uri.TryCreate(BaseInstagramUri, $@"/api/v1/feed/tag/{tag}/", out instaUri)) throw new Exception("Cant create URI for discover-explore"); + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_TAG_FEED, tag), out instaUri)) throw new Exception("Cant create URI for discover tag feed"); return instaUri; } } diff --git a/InstagramAPI/ResponseWrappers/InstaCurrentUserResponse.cs b/InstagramAPI/ResponseWrappers/InstaCurrentUserResponse.cs index fa4f5e65..79d3f163 100644 --- a/InstagramAPI/ResponseWrappers/InstaCurrentUserResponse.cs +++ b/InstagramAPI/ResponseWrappers/InstaCurrentUserResponse.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using InstagramAPI.ResponseWrappers.BaseResponse; +using InstagramAPI.ResponseWrappers.BaseResponse; using Newtonsoft.Json; namespace InstagramAPI.ResponseWrappers @@ -12,4 +8,4 @@ public class InstaCurrentUserResponse : BaseStatusResponse [JsonProperty("user")] public InstaUserResponse User { get; set; } } -} +} \ No newline at end of file diff --git a/InstagramAPI/ResponseWrappers/InstaFeedResponse.cs b/InstagramAPI/ResponseWrappers/InstaFeedResponse.cs index 5b555373..f3f719bf 100644 --- a/InstagramAPI/ResponseWrappers/InstaFeedResponse.cs +++ b/InstagramAPI/ResponseWrappers/InstaFeedResponse.cs @@ -14,41 +14,4 @@ public class InstaFeedResponse : BaseLoadableResponse [JsonProperty(TypeNameHandling = TypeNameHandling.Auto)] public List Items { get; set; } = new List(); } - - public class FeedResponseDataConverter : JsonConverter - { - public override bool CanConvert(Type objectType) - { - return (objectType == typeof(InstaFeedResponse)); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var token = JToken.Load(reader); - var feed = token.ToObject(); - var items = token["feed_items"]; - if (items != null) - { - foreach (var item in items) - { - var mediaOrAd = item["media_or_ad"]; - if (mediaOrAd == null) continue; - var media = mediaOrAd.ToObject(); - feed.Items.Add(media); - } - } - else - { - items = token["items"]; - feed.Items = items.ToObject>(); - } - - return feed; - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - serializer.Serialize(writer, value); - } - } } \ No newline at end of file diff --git a/InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs b/InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs index 7949bef2..dcf59120 100644 --- a/InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs +++ b/InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; using InstagramAPI.ResponseWrappers.BaseResponse; using Newtonsoft.Json; @@ -20,7 +17,7 @@ public class InstaFollowersResponse : BaseStatusResponse public bool IsOK() { - return !string.IsNullOrEmpty(Status) && Status.ToLower() == "ok"; + return !string.IsNullOrEmpty(Status) && (Status.ToLower() == "ok"); } } -} +} \ No newline at end of file diff --git a/InstagramAPI/ResponseWrappers/InstaTagFeedResponse.cs b/InstagramAPI/ResponseWrappers/InstaTagFeedResponse.cs index 43b70bdd..1ee7e990 100644 --- a/InstagramAPI/ResponseWrappers/InstaTagFeedResponse.cs +++ b/InstagramAPI/ResponseWrappers/InstaTagFeedResponse.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; using Newtonsoft.Json; namespace InstagramAPI.ResponseWrappers @@ -11,4 +8,4 @@ public class InstaTagFeedResponse [JsonProperty("ranked_items")] public List Items { get; set; } } -} +} \ No newline at end of file From 6b0085f423bff485b0188834fb4f41b3310bfb62 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Sun, 27 Nov 2016 22:00:49 +0300 Subject: [PATCH 05/23] improvements in tests and some methods --- InstagramAPI.Tests/Tests/FeedTest.cs | 63 +++++++++ InstagramAPI.Tests/Tests/InstaApiTest.cs | 46 +------ InstagramAPI.Tests/Tests/LoginTest.cs | 4 +- .../Tests/{GetMediaTest.cs => MediaTest.cs} | 14 +- InstagramAPI.Tests/Utils/TestHelpers.cs | 2 +- InstagramAPI/API/Builder/IInstaApiBuilder.cs | 2 +- InstagramAPI/API/Builder/InstaApiBuilder.cs | 6 +- InstagramAPI/API/IInstaApi.cs | 8 +- InstagramAPI/API/InstaApi.cs | 120 ++++++++++++------ ...{UserCredentials.cs => UserSessionData.cs} | 2 +- InstagramAPI/Helpers/UriCreator.cs | 2 +- 11 files changed, 168 insertions(+), 101 deletions(-) create mode 100644 InstagramAPI.Tests/Tests/FeedTest.cs rename InstagramAPI.Tests/Tests/{GetMediaTest.cs => MediaTest.cs} (80%) rename InstagramAPI/Classes/{UserCredentials.cs => UserSessionData.cs} (90%) diff --git a/InstagramAPI.Tests/Tests/FeedTest.cs b/InstagramAPI.Tests/Tests/FeedTest.cs new file mode 100644 index 00000000..863c8ca5 --- /dev/null +++ b/InstagramAPI.Tests/Tests/FeedTest.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using InstagramAPI.Classes; +using InstagramAPI.Tests.Utils; +using Xunit; +using Xunit.Abstractions; + +namespace InstagramAPI.Tests.Tests +{ + public class FeedTest + { + public FeedTest(ITestOutputHelper output) + { + this._output = output; + } + + private readonly ITestOutputHelper _output; + private readonly string _username = "alex_codegarage"; + private readonly string _password = Environment.GetEnvironmentVariable("instaapiuserpassword"); + + [Theory] + [InlineData("christmas")] + [InlineData("rock")] + public async void GetTagFeedTest(string tag) + { + //arrange + var apiInstance = + TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = _username, + Password = _password + }); + //act + if (!await TestHelpers.Login(apiInstance, _output)) return; + var result = await apiInstance.GetTagFeedAsync(tag); + var tagFeed = result.Value; + //assert + Assert.True(result.Succeeded); + Assert.NotNull(tagFeed); + } + + [Fact] + public async void GetUserFeedTest() + { + //arrange + var apiInstance = + TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = _username, + Password = _password + }); + //act + if (!await TestHelpers.Login(apiInstance, _output)) return; + var getFeedResult = await apiInstance.GetUserFeedAsync(5); + var feed = getFeedResult.Value; + //assert + Assert.True(getFeedResult.Succeeded); + Assert.NotNull(feed); + } + } +} diff --git a/InstagramAPI.Tests/Tests/InstaApiTest.cs b/InstagramAPI.Tests/Tests/InstaApiTest.cs index ce6bbd70..0cc5dca8 100644 --- a/InstagramAPI.Tests/Tests/InstaApiTest.cs +++ b/InstagramAPI.Tests/Tests/InstaApiTest.cs @@ -17,33 +17,14 @@ public InstaApiTest(ITestOutputHelper output) private readonly string username = "alex_codegarage"; private readonly string password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - [Theory] - [InlineData("christmas")] - [InlineData("rock")] - public async void GetTagFeedTest(string tag) - { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserCredentials - { - UserName = username, - Password = password - }); - //act - if (!await TestHelpers.Login(apiInstance, output)) return; - var result = await apiInstance.GetTagFeedAsync(tag); - var tagFeed = result.Value; - //assert - Assert.True(result.Succeeded); - Assert.NotNull(tagFeed); - } + [Fact] public async void GetCurrentUserFollwersTest() { //arrange var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserCredentials + TestHelpers.GetDefaultInstaApiInstance(new UserSessionData { UserName = username, Password = password @@ -62,7 +43,7 @@ public async void GetCurrentUserTest() { //arrange var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserCredentials + TestHelpers.GetDefaultInstaApiInstance(new UserSessionData { UserName = username, Password = password @@ -77,31 +58,12 @@ public async void GetCurrentUserTest() Assert.Equal(user.UserName, username); } - [Fact] - public async void GetUserFeedTest() - { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserCredentials - { - UserName = username, - Password = password - }); - //act - if (!await TestHelpers.Login(apiInstance, output)) return; - var getFeedResult = await apiInstance.GetUserFeedAsync(5); - var feed = getFeedResult.Value; - //assert - Assert.True(getFeedResult.Succeeded); - Assert.NotNull(feed); - } - [Fact] public async void GetUserTest() { //arrange var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserCredentials + TestHelpers.GetDefaultInstaApiInstance(new UserSessionData { UserName = username, Password = password diff --git a/InstagramAPI.Tests/Tests/LoginTest.cs b/InstagramAPI.Tests/Tests/LoginTest.cs index 12bf81f5..52259e71 100644 --- a/InstagramAPI.Tests/Tests/LoginTest.cs +++ b/InstagramAPI.Tests/Tests/LoginTest.cs @@ -22,7 +22,7 @@ public async void UserLoginFailTest() var username = "alex_codegarage"; var password = "boombaby!"; var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserCredentials + TestHelpers.GetDefaultInstaApiInstance(new UserSessionData { UserName = username, Password = password @@ -42,7 +42,7 @@ public async void UserLoginSuccessTest() var username = "alex_codegarage"; var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserCredentials + TestHelpers.GetDefaultInstaApiInstance(new UserSessionData { UserName = username, Password = password diff --git a/InstagramAPI.Tests/Tests/GetMediaTest.cs b/InstagramAPI.Tests/Tests/MediaTest.cs similarity index 80% rename from InstagramAPI.Tests/Tests/GetMediaTest.cs rename to InstagramAPI.Tests/Tests/MediaTest.cs index 9f672f05..5e93e573 100644 --- a/InstagramAPI.Tests/Tests/GetMediaTest.cs +++ b/InstagramAPI.Tests/Tests/MediaTest.cs @@ -6,13 +6,13 @@ namespace InstagramAPI.Tests.Tests { - public class GetMediaTest + public class MediaTest { private readonly ITestOutputHelper output; private readonly string password = Environment.GetEnvironmentVariable("instaapiuserpassword"); private readonly string username = "alex_codegarage"; - public GetMediaTest(ITestOutputHelper output) + public MediaTest(ITestOutputHelper output) { this.output = output; } @@ -23,7 +23,7 @@ public async void GetMediaByCodeTest(string mediaId) { //arrange var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserCredentials + TestHelpers.GetDefaultInstaApiInstance(new UserSessionData { UserName = username, Password = password @@ -45,18 +45,22 @@ public async void GetUserMediaListTest(string userToFetch) { //arrange var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserCredentials + TestHelpers.GetDefaultInstaApiInstance(new UserSessionData { UserName = username, Password = password }); + var random = new Random(DateTime.Today.Millisecond); + var pages = random.Next(1, 10); //act output.WriteLine($"Trying to login as user: {username}"); if (!await TestHelpers.Login(apiInstance, output)) return; output.WriteLine($"Getting posts of user: {userToFetch}"); - var posts = await apiInstance.GetUserMediaAsync(userToFetch); + + var posts = await apiInstance.GetUserMediaAsync(userToFetch, pages); //assert Assert.NotNull(posts); + Assert.Equal(userToFetch, posts.Value[random.Next(0, posts.Value.Count)].User.UserName); } } } \ No newline at end of file diff --git a/InstagramAPI.Tests/Utils/TestHelpers.cs b/InstagramAPI.Tests/Utils/TestHelpers.cs index 3bcfdd61..86cbdecb 100644 --- a/InstagramAPI.Tests/Utils/TestHelpers.cs +++ b/InstagramAPI.Tests/Utils/TestHelpers.cs @@ -17,7 +17,7 @@ public static IInstaApi GetDefaultInstaApiInstance(string username) return apiInstance; } - public static IInstaApi GetDefaultInstaApiInstance(UserCredentials user) + public static IInstaApi GetDefaultInstaApiInstance(UserSessionData user) { var apiInstance = new InstaApiBuilder() .SetUser(user) diff --git a/InstagramAPI/API/Builder/IInstaApiBuilder.cs b/InstagramAPI/API/Builder/IInstaApiBuilder.cs index 1bf3ff99..4af495bb 100644 --- a/InstagramAPI/API/Builder/IInstaApiBuilder.cs +++ b/InstagramAPI/API/Builder/IInstaApiBuilder.cs @@ -11,6 +11,6 @@ public interface IInstaApiBuilder IInstaApiBuilder UseHttpClient(HttpClient httpClient); IInstaApiBuilder UseHttpClientHandler(HttpClientHandler handler); IInstaApiBuilder SetUserName(string username); - IInstaApiBuilder SetUser(UserCredentials user); + IInstaApiBuilder SetUser(UserSessionData user); } } \ No newline at end of file diff --git a/InstagramAPI/API/Builder/InstaApiBuilder.cs b/InstagramAPI/API/Builder/InstaApiBuilder.cs index 955f9bae..83e7386f 100644 --- a/InstagramAPI/API/Builder/InstaApiBuilder.cs +++ b/InstagramAPI/API/Builder/InstaApiBuilder.cs @@ -12,7 +12,7 @@ public class InstaApiBuilder : IInstaApiBuilder private HttpClientHandler _httpHandler = new HttpClientHandler(); private ILogger _logger; private ApiRequestMessage _requestMessage; - private UserCredentials _user; + private UserSessionData _user; public IInstaApi Build() { @@ -59,11 +59,11 @@ public IInstaApiBuilder UseHttpClientHandler(HttpClientHandler handler) public IInstaApiBuilder SetUserName(string username) { - _user = new UserCredentials {UserName = username}; + _user = new UserSessionData {UserName = username}; return this; } - public IInstaApiBuilder SetUser(UserCredentials user) + public IInstaApiBuilder SetUser(UserSessionData user) { _user = user; return this; diff --git a/InstagramAPI/API/IInstaApi.cs b/InstagramAPI/API/IInstaApi.cs index f361cbe4..cb90f478 100644 --- a/InstagramAPI/API/IInstaApi.cs +++ b/InstagramAPI/API/IInstaApi.cs @@ -19,10 +19,10 @@ public interface IInstaApi Task> GetUserFeedAsync(int maxPages = 0); Task> GetCurrentUserAsync(); IResult GetCurrentUser(); - IResult GetCurentUserFollowers(); - Task> GetCurrentUserFollowersAsync(); - IResult GetTagFeed(string tag); - Task> GetTagFeedAsync(string tag); + IResult GetCurentUserFollowers(int maxPages = 0); + Task> GetCurrentUserFollowersAsync(int maxPages = 0); + IResult GetTagFeed(string tag, int maxPages = 0); + Task> GetTagFeedAsync(string tag, int maxPages = 0); Task> GetUserFeedWithMaxIdAsync(string nextId); IResult GetUserFeedWithMaxId(string nextId); Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId); diff --git a/InstagramAPI/API/InstaApi.cs b/InstagramAPI/API/InstaApi.cs index 115d25ee..9a53d175 100644 --- a/InstagramAPI/API/InstaApi.cs +++ b/InstagramAPI/API/InstaApi.cs @@ -24,9 +24,9 @@ public class InstaApi : IInstaApi private readonly HttpClientHandler _httpHandler; private readonly ILogger _logger; private readonly ApiRequestMessage _requestMessage; - private readonly UserCredentials _user; + private readonly UserSessionData _user; - public InstaApi(UserCredentials user, + public InstaApi(UserSessionData user, ILogger logger, HttpClient httpClient, HttpClientHandler httpHandler, @@ -70,14 +70,14 @@ public IResult Login() return LoginAsync().Result; } - public IResult GetTagFeed(string tag) + public IResult GetTagFeed(string tag, int maxPages = 0) { - return GetTagFeedAsync(tag).Result; + return GetTagFeedAsync(tag, maxPages).Result; } - public IResult GetCurentUserFollowers() + public IResult GetCurentUserFollowers(int maxPages = 0) { - return GetCurrentUserFollowersAsync().Result; + return GetCurrentUserFollowersAsync(maxPages).Result; } public IResult GetUserFeedWithMaxId(string nextId) @@ -210,7 +210,7 @@ public async Task> GetUserFeedAsync(int maxPages = 0) return Result.Fail("", (InstaFeed)null); } - public async Task> GetCurrentUserFollowersAsync() + public async Task> GetCurrentUserFollowersAsync(int maxPages = 0) { ValidateUser(); if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); @@ -234,11 +234,11 @@ public async Task> GetCurrentUserFollowersAsync() return Result.Fail("", (InstaUserList)null); } - public async Task> GetTagFeedAsync(string tag) + public async Task> GetTagFeedAsync(string tag, int maxPages = 0) { ValidateUser(); if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); - var userFeedUri = UriCreator.GetExploreUri(tag); + var userFeedUri = UriCreator.GetTagFeedUri(tag); var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); @@ -247,11 +247,44 @@ public async Task> GetTagFeedAsync(string tag) var feedResponse = JsonConvert.DeserializeObject(json); var converter = ConvertersFabric.GetMediaListConverter(feedResponse); var mediaList = converter.Convert(); + while (feedResponse.MoreAvailable && (mediaList.Pages < maxPages)) + { + var nextMedia = await GetTagFeedWithMaxIdAsync(tag, feedResponse.NextMaxId); + if (!nextMedia.Succeeded) continue; + mediaList.AddRange(converter.Convert()); + mediaList.Pages++; + } return Result.Success(mediaList); } return Result.Fail("", (InstaMediaList)null); } + public async Task> GetTagFeedWithMaxIdAsync(string tag, string nextId) + { + ValidateUser(); + try + { + if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); + var instaUri = UriCreator.GetTagFeedUri(tag); + instaUri = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }.Uri; + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + { + var feedResponse = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.GetMediaListConverter(feedResponse); + var mediaList = converter.Convert(); + return Result.Success(mediaList); + } + return Result.Fail("", (InstaMediaList)null); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaMediaList)null); + } + + } public async Task> GetUserMediaAsync(string username, int maxPages = 0) { ValidateUser(); @@ -327,44 +360,49 @@ public async Task> LoginAsync() { ValidateUser(); ValidateRequestMessage(); - _httpClient.DefaultRequestHeaders.Add(InstaApiConstants.HEADER_USER_AGENT, InstaApiConstants.USER_AGENT); - var csrftoken = string.Empty; - var firstResponse = await _httpClient.GetAsync(_httpClient.BaseAddress); - var cookies = _httpHandler.CookieContainer.GetCookies(_httpClient.BaseAddress); - foreach (Cookie cookie in cookies) if (cookie.Name == InstaApiConstants.CSRFTOKEN) csrftoken = cookie.Value; - _user.CsrfToken = csrftoken; - var instaUri = UriCreator.GetLogintUri(); - var signature = $"{_requestMessage.GenerateSignature()}.{_requestMessage.GetMessageString()}"; - var fields = new Dictionary + try { - {InstaApiConstants.HEADER_IG_SIGNATURE, signature}, + _httpClient.DefaultRequestHeaders.Add(InstaApiConstants.HEADER_USER_AGENT, InstaApiConstants.USER_AGENT); + var csrftoken = string.Empty; + var firstResponse = await _httpClient.GetAsync(_httpClient.BaseAddress); + var cookies = _httpHandler.CookieContainer.GetCookies(_httpClient.BaseAddress); + foreach (Cookie cookie in cookies) if (cookie.Name == InstaApiConstants.CSRFTOKEN) csrftoken = cookie.Value; + _user.CsrfToken = csrftoken; + var instaUri = UriCreator.GetLogintUri(); + var signature = $"{_requestMessage.GenerateSignature()}.{_requestMessage.GetMessageString()}"; + var fields = new Dictionary { - InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, - InstaApiConstants.IG_SIGNATURE_KEY_VERSION + { InstaApiConstants.HEADER_IG_SIGNATURE, signature}, + { InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION } + }; + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri); + request.Content = new FormUrlEncodedContent(fields); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION); + var response = await _httpClient.SendAsync(request); + + if (response.StatusCode == HttpStatusCode.OK) + { + var loginInfo = + JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + IsUserAuthenticated = (loginInfo.User != null) && (loginInfo.User.UserName == _user.UserName); + var converter = ConvertersFabric.GetUserConverter(loginInfo.User); + _user.LoggedInUder = converter.Convert(); + _user.RankToken = $"{_user.LoggedInUder.Pk}_{_requestMessage.phone_id}"; + return Result.Success(true); + } + else + { + var loginInfo = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + _logger.Write(loginInfo.Message); + return Result.Fail(loginInfo.Message, false); } - }; - var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri); - request.Content = new FormUrlEncodedContent(fields); - request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); - request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION); - var response = await _httpClient.SendAsync(request); - - if (response.StatusCode == HttpStatusCode.OK) - { - var loginInfo = - JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - IsUserAuthenticated = (loginInfo.User != null) && (loginInfo.User.UserName == _user.UserName); - var converter = ConvertersFabric.GetUserConverter(loginInfo.User); - _user.LoggedInUder = converter.Convert(); - _user.RankToken = $"{_user.LoggedInUder.Pk}_{_requestMessage.phone_id}"; - return Result.Success(true); } - else + catch (Exception exception) { - var loginInfo = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - _logger.Write(loginInfo.Message); - return Result.Fail(loginInfo.Message, false); + return Result.Fail(exception.Message, false); } + } #endregion diff --git a/InstagramAPI/Classes/UserCredentials.cs b/InstagramAPI/Classes/UserSessionData.cs similarity index 90% rename from InstagramAPI/Classes/UserCredentials.cs rename to InstagramAPI/Classes/UserSessionData.cs index 74f68a51..719f680f 100644 --- a/InstagramAPI/Classes/UserCredentials.cs +++ b/InstagramAPI/Classes/UserSessionData.cs @@ -2,7 +2,7 @@ namespace InstagramAPI.Classes { - public class UserCredentials + public class UserSessionData { public string UserName { get; set; } public string Password { get; set; } diff --git a/InstagramAPI/Helpers/UriCreator.cs b/InstagramAPI/Helpers/UriCreator.cs index 5012a7dd..eee5bbe8 100644 --- a/InstagramAPI/Helpers/UriCreator.cs +++ b/InstagramAPI/Helpers/UriCreator.cs @@ -72,7 +72,7 @@ internal static Uri GetUserFollowersUri(string userPk, string rankToken) return instaUri; } - public static Uri GetExploreUri(string tag) + public static Uri GetTagFeedUri(string tag) { Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_TAG_FEED, tag), out instaUri)) throw new Exception("Cant create URI for discover tag feed"); From da5ce491577eaec9247979c5a0ca4dd994036e4f Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Wed, 30 Nov 2016 21:16:11 +0300 Subject: [PATCH 06/23] fixed multipage retrieval of feeds --- InstagramAPI.Tests/Tests/InstaApiTest.cs | 52 ++++-- InstagramAPI/API/IInstaApi.cs | 5 +- InstagramAPI/API/InstaApi.cs | 161 ++++++++++-------- InstagramAPI/Helpers/HttpHelper.cs | 14 +- InstagramAPI/Helpers/UriCreator.cs | 6 +- .../InstaFollowersResponse.cs | 3 + 6 files changed, 141 insertions(+), 100 deletions(-) diff --git a/InstagramAPI.Tests/Tests/InstaApiTest.cs b/InstagramAPI.Tests/Tests/InstaApiTest.cs index 0cc5dca8..21241d20 100644 --- a/InstagramAPI.Tests/Tests/InstaApiTest.cs +++ b/InstagramAPI.Tests/Tests/InstaApiTest.cs @@ -10,14 +10,32 @@ public class InstaApiTest { public InstaApiTest(ITestOutputHelper output) { - this.output = output; + this._output = output; } - private readonly ITestOutputHelper output; - private readonly string username = "alex_codegarage"; - private readonly string password = Environment.GetEnvironmentVariable("instaapiuserpassword"); + private readonly ITestOutputHelper _output; + private readonly string _username = "alex_codegarage"; + private readonly string _password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - + [Theory] + [InlineData("discovery")] + public async void GetUserFollowersTest(string username) + { + //arrange + var apiInstance = + TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = _username, + Password = _password + }); + //act + if (!await TestHelpers.Login(apiInstance, _output)) return; + var result = await apiInstance.GetUserFollowersAsync(username, 10); + var followers = result.Value; + //assert + Assert.True(result.Succeeded); + Assert.NotNull(followers); + } [Fact] public async void GetCurrentUserFollwersTest() @@ -26,11 +44,11 @@ public async void GetCurrentUserFollwersTest() var apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData { - UserName = username, - Password = password + UserName = _username, + Password = _password }); //act - if (!await TestHelpers.Login(apiInstance, output)) return; + if (!await TestHelpers.Login(apiInstance, _output)) return; var result = await apiInstance.GetCurrentUserFollowersAsync(); var followers = result.Value; //assert @@ -45,17 +63,17 @@ public async void GetCurrentUserTest() var apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData { - UserName = username, - Password = password + UserName = _username, + Password = _password }); //act - if (!await TestHelpers.Login(apiInstance, output)) return; + if (!await TestHelpers.Login(apiInstance, _output)) return; var getUserResult = await apiInstance.GetCurrentUserAsync(); var user = getUserResult.Value; //assert Assert.True(getUserResult.Succeeded); Assert.NotNull(user); - Assert.Equal(user.UserName, username); + Assert.Equal(user.UserName, _username); } [Fact] @@ -65,17 +83,17 @@ public async void GetUserTest() var apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData { - UserName = username, - Password = password + UserName = _username, + Password = _password }); //act - if (!await TestHelpers.Login(apiInstance, output)) return; - var getUserResult = await apiInstance.GetUserAsync(username); + if (!await TestHelpers.Login(apiInstance, _output)) return; + var getUserResult = await apiInstance.GetUserAsync(_username); var user = getUserResult.Value; //assert Assert.True(getUserResult.Succeeded); Assert.NotNull(user); - Assert.Equal(user.UserName, username); + Assert.Equal(user.UserName, _username); } } } \ No newline at end of file diff --git a/InstagramAPI/API/IInstaApi.cs b/InstagramAPI/API/IInstaApi.cs index cb90f478..a1d1825b 100644 --- a/InstagramAPI/API/IInstaApi.cs +++ b/InstagramAPI/API/IInstaApi.cs @@ -23,9 +23,6 @@ public interface IInstaApi Task> GetCurrentUserFollowersAsync(int maxPages = 0); IResult GetTagFeed(string tag, int maxPages = 0); Task> GetTagFeedAsync(string tag, int maxPages = 0); - Task> GetUserFeedWithMaxIdAsync(string nextId); - IResult GetUserFeedWithMaxId(string nextId); - Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId); - IResult GetUserMediaListWithMaxId(string userPk, string nextId); + Task> GetUserFollowersAsync(string username, int maxPages = 0); } } \ No newline at end of file diff --git a/InstagramAPI/API/InstaApi.cs b/InstagramAPI/API/InstaApi.cs index 9a53d175..787383b3 100644 --- a/InstagramAPI/API/InstaApi.cs +++ b/InstagramAPI/API/InstaApi.cs @@ -80,16 +80,6 @@ public IResult GetCurentUserFollowers(int maxPages = 0) return GetCurrentUserFollowersAsync(maxPages).Result; } - public IResult GetUserFeedWithMaxId(string nextId) - { - return GetUserFeedWithMaxIdAsync(nextId).Result; - } - - public IResult GetUserMediaListWithMaxId(string userPk, string nextId) - { - return GetUserMediaListWithMaxIdAsync(userPk, nextId).Result; - } - #endregion #region async part @@ -98,7 +88,7 @@ public async Task> GetMediaByCodeAsync(string postCode) { ValidateUser(); var mediaUri = UriCreator.GetMediaUri(postCode); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, mediaUri); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, mediaUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) @@ -122,7 +112,7 @@ public async Task> GetUserAsync(string username) { ValidateUser(); var userUri = UriCreator.GetUserUri(username); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, InstaApiConstants.TIMEZONE_OFFSET.ToString())); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_COUNT, "1")); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_RANK_TOKEN, _user.RankToken)); @@ -166,7 +156,7 @@ public async Task> GetCurrentUserAsync() {"_uid", _user.LoggedInUder.Pk}, {"_csrftoken", _user.CsrfToken} }; - var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); request.Content = new FormUrlEncodedContent(fields); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); @@ -186,52 +176,90 @@ public async Task> GetUserFeedAsync(int maxPages = 0) ValidateUser(); if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); var userFeedUri = UriCreator.GetUserFeedUri(); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, _deviceInfo.GoogleAdId.ToString())); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); var feed = new InstaFeed(); - if (response.StatusCode == HttpStatusCode.OK) + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaFeed)null); + var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); + var converter = ConvertersFabric.GetFeedConverter(feedResponse); + var feedConverted = converter.Convert(); + feed.Items.AddRange(feedConverted.Items); + while (feedResponse.MoreAvailable && (feed.Pages < maxPages)) { - var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); - var converter = ConvertersFabric.GetFeedConverter(feedResponse); - var feedConverted = converter.Convert(); - feed.Items.AddRange(feedConverted.Items); - while (feedResponse.MoreAvailable && (feed.Pages < maxPages)) - { - var nextFeed = await GetUserFeedWithMaxIdAsync(feedResponse.NextMaxId); - converter = ConvertersFabric.GetFeedConverter(feedResponse); - feedConverted = converter.Convert(); - feed.Items.AddRange(feedConverted.Items); - feed.Pages++; - } - return Result.Success(feed); + var nextFeed = await GetUserFeedWithMaxIdAsync(feedResponse.NextMaxId); + if (!nextFeed.Succeeded) continue; + feed.Items.AddRange(nextFeed.Value.Items.Select(ConvertersFabric.GetSingleMediaConverter).Select(conv => conv.Convert())); + feed.Pages++; } - return Result.Fail("", (InstaFeed)null); + return Result.Success(feed); } public async Task> GetCurrentUserFollowersAsync(int maxPages = 0) { ValidateUser(); - if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); - var userFeedUri = UriCreator.GetUserFollowersUri(_user.LoggedInUder.Pk, _user.RankToken); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri); - var response = await _httpClient.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - var followers = new InstaUserList(); - if (response.StatusCode == HttpStatusCode.OK) + return await GetUserFollowersAsync(_user.UserName, maxPages); + } + + public async Task> GetUserFollowersAsync(string username, int maxPages = 0) + { + ValidateUser(); + ValidateLoggedIn(); + try { + if (maxPages == 0) maxPages = Int32.MaxValue; + var user = await GetUserAsync(username); + var userFeedUri = UriCreator.GetUserFollowersUri(user.Value.Pk, _user.RankToken); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + var followers = new InstaUserList(); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaUserList)null); var followersResponse = JsonConvert.DeserializeObject(json); if (!followersResponse.IsOK()) Result.Fail("", (InstaUserList)null); - foreach (var user in followersResponse.Items) + followers.AddRange(followersResponse.Items.Select(ConvertersFabric.GetUserConverter).Select(converter => converter.Convert())); + if (!followersResponse.IsBigList) return Result.Success(followers); + var pages = 1; + while (!string.IsNullOrEmpty(followersResponse.NextMaxId) && (pages < maxPages)) { - var converter = ConvertersFabric.GetUserConverter(user); - var userConverted = converter.Convert(); - followers.Add(userConverted); + var nextFollowers = await GetUserFollowersWithMaxIdAsync(username, followersResponse.NextMaxId); + if (!nextFollowers.Succeeded) continue; + followers.AddRange(nextFollowers.Value.Items.Select(ConvertersFabric.GetUserConverter).Select(converter => converter.Convert())); + pages++; } return Result.Success(followers); } - return Result.Fail("", (InstaUserList)null); + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaUserList)null); + } + + } + + private async Task> GetUserFollowersWithMaxIdAsync(string username, string maxId) + { + ValidateUser(); + try + { + if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); + var user = await GetUserAsync(username); + var userFeedUri = UriCreator.GetUserFollowersUri(user.Value.Pk, _user.RankToken, maxId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + { + var followersResponse = JsonConvert.DeserializeObject(json); + if (!followersResponse.IsOK()) Result.Fail("", (InstaFollowersResponse)null); + return Result.Success(followersResponse); + } + return Result.Fail("", (InstaFollowersResponse)null); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaFollowersResponse)null); + } + } public async Task> GetTagFeedAsync(string tag, int maxPages = 0) @@ -239,7 +267,7 @@ public async Task> GetTagFeedAsync(string tag, int maxPa ValidateUser(); if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); var userFeedUri = UriCreator.GetTagFeedUri(tag); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) @@ -259,29 +287,27 @@ public async Task> GetTagFeedAsync(string tag, int maxPa return Result.Fail("", (InstaMediaList)null); } - public async Task> GetTagFeedWithMaxIdAsync(string tag, string nextId) + public async Task> GetTagFeedWithMaxIdAsync(string tag, string nextId) { ValidateUser(); try { - if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); + ValidateLoggedIn(); var instaUri = UriCreator.GetTagFeedUri(tag); instaUri = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }.Uri; - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) { var feedResponse = JsonConvert.DeserializeObject(json); - var converter = ConvertersFabric.GetMediaListConverter(feedResponse); - var mediaList = converter.Convert(); - return Result.Success(mediaList); + return Result.Success(feedResponse); } - return Result.Fail("", (InstaMediaList)null); + return Result.Fail("", (InstaMediaListResponse)null); } catch (Exception exception) { - return Result.Fail(exception.Message, (InstaMediaList)null); + return Result.Fail(exception.Message, (InstaMediaListResponse)null); } } @@ -291,7 +317,7 @@ public async Task> GetUserMediaAsync(string username, in if (maxPages == 0) maxPages = int.MaxValue; var user = GetUser(username).Value; var instaUri = UriCreator.GetUserMediaListUri(user.Pk); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) @@ -313,47 +339,38 @@ public async Task> GetUserMediaAsync(string username, in return Result.Fail(badRequest.Message, (InstaMediaList)null); } - public async Task> GetUserFeedWithMaxIdAsync(string nextId) + public async Task> GetUserFeedWithMaxIdAsync(string maxId) { Uri instaUri; if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search user URI"); - var userUriBuilder = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }; + var userUriBuilder = new UriBuilder(instaUri) { Query = $"max_id={maxId}" }; var request = new HttpRequestMessage(HttpMethod.Get, userUriBuilder.Uri); request.Headers.Clear(); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_PHONE_ID, _requestMessage.phone_id)); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, InstaApiConstants.TIMEZONE_OFFSET.ToString())); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, _deviceInfo.GoogleAdId.ToString())); - var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); var feed = new InstaFeed(); if (response.StatusCode == HttpStatusCode.OK) { var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); - var converter = ConvertersFabric.GetFeedConverter(feedResponse); - var feedConverted = converter.Convert(); - feed.Items.AddRange(feedConverted.Items); - return Result.Success(feed); + return Result.Success(feedResponse); } - return Result.Fail("", (InstaFeed)null); + return Result.Fail("", (InstaFeedResponse)null); } - public async Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId) + private async Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId) { var instaUri = UriCreator.GetMediaListWithMaxIdUri(userPk, nextId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, _deviceInfo.GoogleAdId.ToString())); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) { var mediaResponse = JsonConvert.DeserializeObject(json); - var converter = ConvertersFabric.GetMediaListConverter(mediaResponse); - var mediaList = converter.Convert(); - return Result.Success(mediaList); + return Result.Success(mediaResponse); } - - return Result.Fail("", (InstaMediaList)null); + return Result.Fail("", (InstaMediaListResponse)null); } public async Task> LoginAsync() @@ -375,7 +392,7 @@ public async Task> LoginAsync() { InstaApiConstants.HEADER_IG_SIGNATURE, signature}, { InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION } }; - var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); request.Content = new FormUrlEncodedContent(fields); request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION); @@ -414,6 +431,10 @@ private void ValidateUser() if (string.IsNullOrEmpty(_user.UserName) || string.IsNullOrEmpty(_user.Password)) throw new ArgumentException("user name and password must be specified"); } + private void ValidateLoggedIn() + { + if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); + } private void ValidateRequestMessage() { if ((_requestMessage == null) || _requestMessage.IsEmpty()) throw new ArgumentException("API request message null or empty"); diff --git a/InstagramAPI/Helpers/HttpHelper.cs b/InstagramAPI/Helpers/HttpHelper.cs index 9bea98ec..a30a4e4f 100644 --- a/InstagramAPI/Helpers/HttpHelper.cs +++ b/InstagramAPI/Helpers/HttpHelper.cs @@ -1,21 +1,21 @@ using System; +using System.Collections.Generic; using System.Net.Http; using InstagramAPI.API; +using InstagramAPI.Classes.Android.DeviceInfo; namespace InstagramAPI.Helpers { public class HttpHelper { - public static HttpRequestMessage GetDefaultRequest(HttpMethod method, Uri uri) + public static HttpRequestMessage GetDefaultRequest(HttpMethod method, Uri uri, AndroidDevice deviceInfo) { var request = new HttpRequestMessage(method, uri); - request.Headers.Add(InstaApiConstants.HEADER_ACCEPT_LANGUAGE, - InstaApiConstants.ACCEPT_LANGUAGE); - request.Headers.Add(InstaApiConstants.HEADER_IG_CAPABILITIES, - InstaApiConstants.IG_CAPABILITIES); - request.Headers.Add(InstaApiConstants.HEADER_IG_CONNECTION_TYPE, - InstaApiConstants.IG_CONNECTION_TYPE); + request.Headers.Add(InstaApiConstants.HEADER_ACCEPT_LANGUAGE, InstaApiConstants.ACCEPT_LANGUAGE); + request.Headers.Add(InstaApiConstants.HEADER_IG_CAPABILITIES, InstaApiConstants.IG_CAPABILITIES); + request.Headers.Add(InstaApiConstants.HEADER_IG_CONNECTION_TYPE, InstaApiConstants.IG_CONNECTION_TYPE); request.Headers.Add(InstaApiConstants.HEADER_USER_AGENT, InstaApiConstants.USER_AGENT); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_XGOOGLE_AD_IDE, deviceInfo.GoogleAdId.ToString())); return request; } } diff --git a/InstagramAPI/Helpers/UriCreator.cs b/InstagramAPI/Helpers/UriCreator.cs index eee5bbe8..9bab9513 100644 --- a/InstagramAPI/Helpers/UriCreator.cs +++ b/InstagramAPI/Helpers/UriCreator.cs @@ -65,11 +65,13 @@ public static Uri GetCurrentUserUri() return instaUri; } - internal static Uri GetUserFollowersUri(string userPk, string rankToken) + internal static Uri GetUserFollowersUri(string userPk, string rankToken, string maxId = "") { Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_FOLLOWERS, userPk, rankToken), out instaUri)) throw new Exception("Cant create URI for user followers"); - return instaUri; + if (string.IsNullOrEmpty(maxId)) return instaUri; + var uriBuilder = new UriBuilder(instaUri) { Query = $"max_id={maxId}" }; + return uriBuilder.Uri; } public static Uri GetTagFeedUri(string tag) diff --git a/InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs b/InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs index dcf59120..54e2a0e7 100644 --- a/InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs +++ b/InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs @@ -15,6 +15,9 @@ public class InstaFollowersResponse : BaseStatusResponse [JsonProperty("page_size")] public int PageSize { get; set; } + [JsonProperty("next_max_id")] + public string NextMaxId { get; set; } + public bool IsOK() { return !string.IsNullOrEmpty(Status) && (Status.ToLower() == "ok"); From bac222e25b5e4cdce92e688eb65d328ec7f7c40a Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Fri, 2 Dec 2016 15:26:25 +0300 Subject: [PATCH 07/23] readme update --- README.md | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 76aebe3f..eb641817 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,28 @@ -# InstagramApi +# InstagramApi [InstaSharper] Tokenless, butthurtless private API for Instagram. Get account information, media, explore tags and user feed without any applications and other crap. -This wrapper provides basic media from instagram, some of them even without authorization. + Note that: there is a simple [Instagram API](https://github.com/a-legotin/InstagramAPI-Web) based on web-version of Instagram. This repository based on Instagram API for mobile devices. [![Build status](https://ci.appveyor.com/api/projects/status/tgdu2w1xr2qmtmrh?svg=true)](https://ci.appveyor.com/project/a-legotin/instagramapi-xk3ds) [![Build Status](https://travis-ci.org/a-legotin/InstagramAPI.svg?branch=master)](https://travis-ci.org/a-legotin/InstagramAPI) -#### Current version: 1.0.0 [Under development] +#### Current version: 1.2.0 [Stable], 1.2.1 [Under development] -#### [Why two separate repos with same mission?](https://github.com/a-legotin/InstagramAPI-Web/wiki/Difference-between-API-Web-and-just-API-repositories) +## Overview +This project intends to provide all the features available in the Google Maps API up to v9.7.5. It is being developed in C# for .NET Framework 4.6 and .NET Standart 1.6 + +* Please note that this project is still in design and development phase; the libraries may suffer major changes even at the interface level, so don't rely (yet) in this software for production uses. * + +## API Support + +Currently the library supports following coverage of the following Instagram APIs: + * Login + * Logout + * Get user timeline feed + * Get user media + * Get media by its id + * Get tag feed -#### [Wiki](https://github.com/a-legotin/InstagramAPI/wiki/) ## Cross-platform by design Build with dotnet core. Can be used on Mac, Linux, Windows. @@ -28,6 +40,8 @@ var api = new InstaApiBuilder() .Build(); ``` ##### Note: every API method has Async implementation as well + +### Quick Examples #### Login ```c# bool loggedIn = api.Login(); @@ -53,6 +67,10 @@ InstaMedia mediaItem = api.GetMediaByCode(mediaCode); InstaFeed feed = api.GetUserFeed(); ``` +#### [Why two separate repos with same mission?](https://github.com/a-legotin/InstagramAPI-Web/wiki/Difference-between-API-Web-and-just-API-repositories) + +#### [Wiki](https://github.com/a-legotin/InstagramAPI/wiki/) + # License MIT From 984662c6badec799a631e8c662968df0759316fc Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Fri, 2 Dec 2016 15:30:29 +0300 Subject: [PATCH 08/23] readme update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb641817..2ca9fe4e 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Note that: there is a simple [Instagram API](https://github.com/a-legotin/Instag #### Current version: 1.2.0 [Stable], 1.2.1 [Under development] ## Overview -This project intends to provide all the features available in the Google Maps API up to v9.7.5. It is being developed in C# for .NET Framework 4.6 and .NET Standart 1.6 +This project intends to provide all the features available in the Instagram API up to v9.7.0. It is being developed in C# for .NET Framework 4.6 and .NET Standart 1.6 * Please note that this project is still in design and development phase; the libraries may suffer major changes even at the interface level, so don't rely (yet) in this software for production uses. * From fb968ef9fcceb4ee88feb57ffaeb51a24f110fd5 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Fri, 2 Dec 2016 18:50:11 +0300 Subject: [PATCH 09/23] re-branding :) --- .travis.yml | 6 +- .../InstaSharper.Tests.xproj | 2 +- .../Properties/AssemblyInfo.cs | 2 +- .../Tests/ApiInstanceBuilderTest.cs | 6 +- .../Tests/FeedTest.cs | 13 ++-- .../Tests/InstaApiTest.cs | 8 +- .../Tests/LoginTest.cs | 6 +- .../Tests/MediaTest.cs | 6 +- .../Utils/TestHelpers.cs | 8 +- .../Utils/TestLogger.cs | 4 +- .../project.json | 2 +- InstagramAPI.sln => InstaSharper.sln | 4 +- .../API/Builder/IInstaApiBuilder.cs | 6 +- .../API/Builder/InstaApiBuilder.cs | 8 +- .../API/IInstaApi.cs | 6 +- .../API/InstaApi.cs | 78 +++++++++---------- .../API/InstaApiConstants.cs | 2 +- .../Android/DeviceInfo/AndroidDevice.cs | 2 +- .../DeviceInfo/AndroidDeviceGenerator.cs | 2 +- .../Android/DeviceInfo/ApiRequestMessage.cs | 6 +- .../Classes/Android/LoginInfoAndroid.cs | 2 +- .../Classes/IResult.cs | 2 +- .../Classes/Models/Dimensions.cs | 2 +- .../Classes/Models/Image.cs | 2 +- .../Classes/Models/Images.cs | 2 +- .../Classes/Models/InstaCaption.cs | 2 +- .../Classes/Models/InstaFeed.cs | 2 +- .../Classes/Models/InstaFriendshipStatus.cs | 2 +- .../Classes/Models/InstaLocation.cs | 2 +- .../Classes/Models/InstaMedia.cs | 2 +- .../Classes/Models/InstaMediaList.cs | 2 +- .../Classes/Models/InstaMediaType.cs | 2 +- .../Classes/Models/InstaUser.cs | 2 +- .../Classes/Models/InstaUserList.cs | 2 +- .../Classes/Models/Likes.cs | 2 +- .../Classes/Result.cs | 2 +- .../Classes/UserSessionData.cs | 4 +- .../Converters/ConvertersFabric.cs | 6 +- .../Converters/IObjectConverter.cs | 2 +- .../Converters/InstaCaptionConverter.cs | 8 +- .../Converters/InstaFeedConverter.cs | 6 +- .../InstaFriendshipStatusConverter.cs | 6 +- .../Converters/InstaMediaConverter.cs | 8 +- .../Converters/InstaMediaListConverter.cs | 6 +- .../Converters/InstaUsersConverter.cs | 6 +- .../Json/FeedResponseDataConverter.cs | 5 +- .../Helpers/CryptoHelper.cs | 2 +- .../Helpers/DateTimeHelper.cs | 2 +- .../Helpers/HttpHelper.cs | 6 +- .../Helpers/UriCreator.cs | 12 +-- .../InstaSharper.xproj | 2 +- .../Logger/DebugLogger.cs | 2 +- .../Logger/ILogger.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- .../ResponseWrappers/BadStatusResponse.cs | 4 +- .../BaseResponse/BaseLoadableResponse.cs | 2 +- .../BaseResponse/BaseStatusResponse.cs | 2 +- .../ResponseWrappers/FollowedByResponse.cs | 2 +- .../ResponseWrappers/ImageResponse.cs | 2 +- .../ResponseWrappers/ImagesResponse.cs | 2 +- .../ResponseWrappers/InstaCaptionResponse.cs | 4 +- .../InstaCurrentUserResponse.cs | 4 +- .../ResponseWrappers/InstaFeedResponse.cs | 8 +- .../InstaFollowersResponse.cs | 4 +- .../InstaFriendshipStatusResponse.cs | 2 +- .../InstaImageCandidatesResponse.cs | 2 +- .../ResponseWrappers/InstaLoginResponse.cs | 2 +- .../InstaMediaItemResponse.cs | 4 +- .../InstaMediaListResponse.cs | 4 +- .../InstaSearchUserResponse.cs | 2 +- .../ResponseWrappers/InstaTagFeedResponse.cs | 2 +- .../ResponseWrappers/InstaUserResponse.cs | 2 +- {InstagramAPI => InstaSharper}/project.json | 0 appveyor.yml | 6 +- 74 files changed, 172 insertions(+), 184 deletions(-) rename InstagramAPI.Tests/InstagramAPI.Tests.xproj => InstaSharper.Tests/InstaSharper.Tests.xproj (95%) rename {InstagramAPI.Tests => InstaSharper.Tests}/Properties/AssemblyInfo.cs (93%) rename {InstagramAPI.Tests => InstaSharper.Tests}/Tests/ApiInstanceBuilderTest.cs (75%) rename {InstagramAPI.Tests => InstaSharper.Tests}/Tests/FeedTest.cs (88%) rename {InstagramAPI.Tests => InstaSharper.Tests}/Tests/InstaApiTest.cs (96%) rename {InstagramAPI.Tests => InstaSharper.Tests}/Tests/LoginTest.cs (94%) rename {InstagramAPI.Tests => InstaSharper.Tests}/Tests/MediaTest.cs (95%) rename {InstagramAPI.Tests => InstaSharper.Tests}/Utils/TestHelpers.cs (89%) rename {InstagramAPI.Tests => InstaSharper.Tests}/Utils/TestLogger.cs (65%) rename {InstagramAPI.Tests => InstaSharper.Tests}/project.json (92%) rename InstagramAPI.sln => InstaSharper.sln (82%) rename {InstagramAPI => InstaSharper}/API/Builder/IInstaApiBuilder.cs (81%) rename {InstagramAPI => InstaSharper}/API/Builder/InstaApiBuilder.cs (94%) rename {InstagramAPI => InstaSharper}/API/IInstaApi.cs (93%) rename {InstagramAPI => InstaSharper}/API/InstaApi.cs (92%) rename {InstagramAPI => InstaSharper}/API/InstaApiConstants.cs (99%) rename {InstagramAPI => InstaSharper}/Classes/Android/DeviceInfo/AndroidDevice.cs (94%) rename {InstagramAPI => InstaSharper}/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs (99%) rename {InstagramAPI => InstaSharper}/Classes/Android/DeviceInfo/ApiRequestMessage.cs (91%) rename {InstagramAPI => InstaSharper}/Classes/Android/LoginInfoAndroid.cs (53%) rename {InstagramAPI => InstaSharper}/Classes/IResult.cs (80%) rename {InstagramAPI => InstaSharper}/Classes/Models/Dimensions.cs (75%) rename {InstagramAPI => InstaSharper}/Classes/Models/Image.cs (88%) rename {InstagramAPI => InstaSharper}/Classes/Models/Images.cs (82%) rename {InstagramAPI => InstaSharper}/Classes/Models/InstaCaption.cs (90%) rename {InstagramAPI => InstaSharper}/Classes/Models/InstaFeed.cs (86%) rename {InstagramAPI => InstaSharper}/Classes/Models/InstaFriendshipStatus.cs (85%) rename {InstagramAPI => InstaSharper}/Classes/Models/InstaLocation.cs (67%) rename {InstagramAPI => InstaSharper}/Classes/Models/InstaMedia.cs (96%) rename {InstagramAPI => InstaSharper}/Classes/Models/InstaMediaList.cs (79%) rename {InstagramAPI => InstaSharper}/Classes/Models/InstaMediaType.cs (66%) rename {InstagramAPI => InstaSharper}/Classes/Models/InstaUser.cs (95%) rename {InstagramAPI => InstaSharper}/Classes/Models/InstaUserList.cs (72%) rename {InstagramAPI => InstaSharper}/Classes/Models/Likes.cs (77%) rename {InstagramAPI => InstaSharper}/Classes/Result.cs (98%) rename {InstagramAPI => InstaSharper}/Classes/UserSessionData.cs (80%) rename {InstagramAPI => InstaSharper}/Converters/ConvertersFabric.cs (93%) rename {InstagramAPI => InstaSharper}/Converters/IObjectConverter.cs (76%) rename {InstagramAPI => InstaSharper}/Converters/InstaCaptionConverter.cs (85%) rename {InstagramAPI => InstaSharper}/Converters/InstaFeedConverter.cs (84%) rename {InstagramAPI => InstaSharper}/Converters/InstaFriendshipStatusConverter.cs (86%) rename {InstagramAPI => InstaSharper}/Converters/InstaMediaConverter.cs (93%) rename {InstagramAPI => InstaSharper}/Converters/InstaMediaListConverter.cs (84%) rename {InstagramAPI => InstaSharper}/Converters/InstaUsersConverter.cs (93%) rename {InstagramAPI => InstaSharper}/Converters/Json/FeedResponseDataConverter.cs (94%) rename {InstagramAPI => InstaSharper}/Helpers/CryptoHelper.cs (98%) rename {InstagramAPI => InstaSharper}/Helpers/DateTimeHelper.cs (95%) rename {InstagramAPI => InstaSharper}/Helpers/HttpHelper.cs (90%) rename {InstagramAPI => InstaSharper}/Helpers/UriCreator.cs (88%) rename InstagramAPI/InstagramAPI.xproj => InstaSharper/InstaSharper.xproj (95%) rename {InstagramAPI => InstaSharper}/Logger/DebugLogger.cs (86%) rename {InstagramAPI => InstaSharper}/Logger/ILogger.cs (71%) rename {InstagramAPI => InstaSharper}/Properties/AssemblyInfo.cs (94%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/BadStatusResponse.cs (73%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs (89%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/BaseResponse/BaseStatusResponse.cs (74%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/FollowedByResponse.cs (78%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/ImageResponse.cs (88%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/ImagesResponse.cs (90%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/InstaCaptionResponse.cs (87%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/InstaCurrentUserResponse.cs (66%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/InstaFeedResponse.cs (68%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/InstaFollowersResponse.cs (86%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/InstaFriendshipStatusResponse.cs (91%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/InstaImageCandidatesResponse.cs (84%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/InstaLoginResponse.cs (85%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/InstaMediaItemResponse.cs (95%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/InstaMediaListResponse.cs (72%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/InstaSearchUserResponse.cs (90%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/InstaTagFeedResponse.cs (84%) rename {InstagramAPI => InstaSharper}/ResponseWrappers/InstaUserResponse.cs (96%) rename {InstagramAPI => InstaSharper}/project.json (100%) diff --git a/.travis.yml b/.travis.yml index 2b84fb67..13d544b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: csharp -solution: InstagramAPI.sln +solution: InstaSharper.sln dotnet: 1.0.0-preview2-003121 sudo: required os: linux @@ -10,9 +10,9 @@ script: - dotnet --info # Run dotnet new - dotnet restore - - cd InstagramAPI + - cd InstaSharper - dotnet --verbose build - - cd ../InstagramAPI.Tests + - cd ../InstaSharper.Tests - dotnet --verbose build - dotnet --verbose test \ No newline at end of file diff --git a/InstagramAPI.Tests/InstagramAPI.Tests.xproj b/InstaSharper.Tests/InstaSharper.Tests.xproj similarity index 95% rename from InstagramAPI.Tests/InstagramAPI.Tests.xproj rename to InstaSharper.Tests/InstaSharper.Tests.xproj index 9e8dbfaf..042194cb 100644 --- a/InstagramAPI.Tests/InstagramAPI.Tests.xproj +++ b/InstaSharper.Tests/InstaSharper.Tests.xproj @@ -7,7 +7,7 @@ dbe6fbb7-cde7-4cdf-ab08-989a43cc4d46 - InstagramAPI.Tests + InstaSharper.Tests .\obj .\bin\ v4.5.2 diff --git a/InstagramAPI.Tests/Properties/AssemblyInfo.cs b/InstaSharper.Tests/Properties/AssemblyInfo.cs similarity index 93% rename from InstagramAPI.Tests/Properties/AssemblyInfo.cs rename to InstaSharper.Tests/Properties/AssemblyInfo.cs index def343ae..9fcac688 100644 --- a/InstagramAPI.Tests/Properties/AssemblyInfo.cs +++ b/InstaSharper.Tests/Properties/AssemblyInfo.cs @@ -7,7 +7,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("InstagramApi.Tests")] +[assembly: AssemblyProduct("InstaSharper.Tests")] [assembly: AssemblyTrademark("")] // Setting ComVisible to false makes the types in this assembly not visible diff --git a/InstagramAPI.Tests/Tests/ApiInstanceBuilderTest.cs b/InstaSharper.Tests/Tests/ApiInstanceBuilderTest.cs similarity index 75% rename from InstagramAPI.Tests/Tests/ApiInstanceBuilderTest.cs rename to InstaSharper.Tests/Tests/ApiInstanceBuilderTest.cs index 74f9f3fa..7c4d6964 100644 --- a/InstagramAPI.Tests/Tests/ApiInstanceBuilderTest.cs +++ b/InstaSharper.Tests/Tests/ApiInstanceBuilderTest.cs @@ -1,8 +1,8 @@ -using InstagramAPI.API.Builder; -using InstagramAPI.Tests.Utils; +using InstaSharper.API.Builder; +using InstaSharper.Tests.Utils; using Xunit; -namespace InstagramAPI.Tests.Tests +namespace InstaSharper.Tests.Tests { public class ApiInstanceBuilderTest { diff --git a/InstagramAPI.Tests/Tests/FeedTest.cs b/InstaSharper.Tests/Tests/FeedTest.cs similarity index 88% rename from InstagramAPI.Tests/Tests/FeedTest.cs rename to InstaSharper.Tests/Tests/FeedTest.cs index 863c8ca5..f2c7637b 100644 --- a/InstagramAPI.Tests/Tests/FeedTest.cs +++ b/InstaSharper.Tests/Tests/FeedTest.cs @@ -1,19 +1,16 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using InstagramAPI.Classes; -using InstagramAPI.Tests.Utils; +using InstaSharper.Classes; +using InstaSharper.Tests.Utils; using Xunit; using Xunit.Abstractions; -namespace InstagramAPI.Tests.Tests +namespace InstaSharper.Tests.Tests { public class FeedTest { public FeedTest(ITestOutputHelper output) { - this._output = output; + _output = output; } private readonly ITestOutputHelper _output; @@ -60,4 +57,4 @@ public async void GetUserFeedTest() Assert.NotNull(feed); } } -} +} \ No newline at end of file diff --git a/InstagramAPI.Tests/Tests/InstaApiTest.cs b/InstaSharper.Tests/Tests/InstaApiTest.cs similarity index 96% rename from InstagramAPI.Tests/Tests/InstaApiTest.cs rename to InstaSharper.Tests/Tests/InstaApiTest.cs index 21241d20..3aaf2da9 100644 --- a/InstagramAPI.Tests/Tests/InstaApiTest.cs +++ b/InstaSharper.Tests/Tests/InstaApiTest.cs @@ -1,16 +1,16 @@ using System; -using InstagramAPI.Classes; -using InstagramAPI.Tests.Utils; +using InstaSharper.Classes; +using InstaSharper.Tests.Utils; using Xunit; using Xunit.Abstractions; -namespace InstagramAPI.Tests.Tests +namespace InstaSharper.Tests.Tests { public class InstaApiTest { public InstaApiTest(ITestOutputHelper output) { - this._output = output; + _output = output; } private readonly ITestOutputHelper _output; diff --git a/InstagramAPI.Tests/Tests/LoginTest.cs b/InstaSharper.Tests/Tests/LoginTest.cs similarity index 94% rename from InstagramAPI.Tests/Tests/LoginTest.cs rename to InstaSharper.Tests/Tests/LoginTest.cs index 52259e71..52b1fbc9 100644 --- a/InstagramAPI.Tests/Tests/LoginTest.cs +++ b/InstaSharper.Tests/Tests/LoginTest.cs @@ -1,10 +1,10 @@ using System; -using InstagramAPI.Classes; -using InstagramAPI.Tests.Utils; +using InstaSharper.Classes; +using InstaSharper.Tests.Utils; using Xunit; using Xunit.Abstractions; -namespace InstagramAPI.Tests.Tests +namespace InstaSharper.Tests.Tests { public class LoginTest { diff --git a/InstagramAPI.Tests/Tests/MediaTest.cs b/InstaSharper.Tests/Tests/MediaTest.cs similarity index 95% rename from InstagramAPI.Tests/Tests/MediaTest.cs rename to InstaSharper.Tests/Tests/MediaTest.cs index 5e93e573..5d6d9780 100644 --- a/InstagramAPI.Tests/Tests/MediaTest.cs +++ b/InstaSharper.Tests/Tests/MediaTest.cs @@ -1,10 +1,10 @@ using System; -using InstagramAPI.Classes; -using InstagramAPI.Tests.Utils; +using InstaSharper.Classes; +using InstaSharper.Tests.Utils; using Xunit; using Xunit.Abstractions; -namespace InstagramAPI.Tests.Tests +namespace InstaSharper.Tests.Tests { public class MediaTest { diff --git a/InstagramAPI.Tests/Utils/TestHelpers.cs b/InstaSharper.Tests/Utils/TestHelpers.cs similarity index 89% rename from InstagramAPI.Tests/Utils/TestHelpers.cs rename to InstaSharper.Tests/Utils/TestHelpers.cs index 86cbdecb..32b3ea3d 100644 --- a/InstagramAPI.Tests/Utils/TestHelpers.cs +++ b/InstaSharper.Tests/Utils/TestHelpers.cs @@ -1,10 +1,10 @@ using System.Threading.Tasks; -using InstagramAPI.API; -using InstagramAPI.API.Builder; -using InstagramAPI.Classes; +using InstaSharper.API; +using InstaSharper.API.Builder; +using InstaSharper.Classes; using Xunit.Abstractions; -namespace InstagramAPI.Tests.Utils +namespace InstaSharper.Tests.Utils { public class TestHelpers { diff --git a/InstagramAPI.Tests/Utils/TestLogger.cs b/InstaSharper.Tests/Utils/TestLogger.cs similarity index 65% rename from InstagramAPI.Tests/Utils/TestLogger.cs rename to InstaSharper.Tests/Utils/TestLogger.cs index bd2cba31..89c8fa92 100644 --- a/InstagramAPI.Tests/Utils/TestLogger.cs +++ b/InstaSharper.Tests/Utils/TestLogger.cs @@ -1,6 +1,6 @@ -using InstagramAPI.Logger; +using InstaSharper.Logger; -namespace InstagramAPI.Tests.Utils +namespace InstaSharper.Tests.Utils { internal class TestLogger : ILogger { diff --git a/InstagramAPI.Tests/project.json b/InstaSharper.Tests/project.json similarity index 92% rename from InstagramAPI.Tests/project.json rename to InstaSharper.Tests/project.json index 9722838a..5e4c3e27 100644 --- a/InstagramAPI.Tests/project.json +++ b/InstaSharper.Tests/project.json @@ -3,7 +3,7 @@ "testRunner": "xunit", "dependencies": { "xunit": "2.2.0-beta2-build3300", - "InstagramAPI": "1.2.0", + "InstaSharper": "1.2.0", "dotnet-test-xunit": "2.2.0-preview2-build1029" }, "frameworks": { diff --git a/InstagramAPI.sln b/InstaSharper.sln similarity index 82% rename from InstagramAPI.sln rename to InstaSharper.sln index c2aaeab9..bd2eb111 100644 --- a/InstagramAPI.sln +++ b/InstaSharper.sln @@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "InstagramAPI", "InstagramAPI\InstagramAPI.xproj", "{449A948D-CC65-4D1A-8159-6FA232F972D9}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "InstaSharper", "InstaSharper\InstaSharper.xproj", "{449A948D-CC65-4D1A-8159-6FA232F972D9}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "InstagramAPI.Tests", "InstagramAPI.Tests\InstagramAPI.Tests.xproj", "{DBE6FBB7-CDE7-4CDF-AB08-989A43CC4D46}" +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "InstaSharper.Tests", "InstaSharper.Tests\InstaSharper.Tests.xproj", "{DBE6FBB7-CDE7-4CDF-AB08-989A43CC4D46}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/InstagramAPI/API/Builder/IInstaApiBuilder.cs b/InstaSharper/API/Builder/IInstaApiBuilder.cs similarity index 81% rename from InstagramAPI/API/Builder/IInstaApiBuilder.cs rename to InstaSharper/API/Builder/IInstaApiBuilder.cs index 4af495bb..8f0b7f00 100644 --- a/InstagramAPI/API/Builder/IInstaApiBuilder.cs +++ b/InstaSharper/API/Builder/IInstaApiBuilder.cs @@ -1,8 +1,8 @@ using System.Net.Http; -using InstagramAPI.Classes; -using InstagramAPI.Logger; +using InstaSharper.Classes; +using InstaSharper.Logger; -namespace InstagramAPI.API.Builder +namespace InstaSharper.API.Builder { public interface IInstaApiBuilder { diff --git a/InstagramAPI/API/Builder/InstaApiBuilder.cs b/InstaSharper/API/Builder/InstaApiBuilder.cs similarity index 94% rename from InstagramAPI/API/Builder/InstaApiBuilder.cs rename to InstaSharper/API/Builder/InstaApiBuilder.cs index 83e7386f..d260db4b 100644 --- a/InstagramAPI/API/Builder/InstaApiBuilder.cs +++ b/InstaSharper/API/Builder/InstaApiBuilder.cs @@ -1,10 +1,10 @@ using System; using System.Net.Http; -using InstagramAPI.Classes; -using InstagramAPI.Classes.Android.DeviceInfo; -using InstagramAPI.Logger; +using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Logger; -namespace InstagramAPI.API.Builder +namespace InstaSharper.API.Builder { public class InstaApiBuilder : IInstaApiBuilder { diff --git a/InstagramAPI/API/IInstaApi.cs b/InstaSharper/API/IInstaApi.cs similarity index 93% rename from InstagramAPI/API/IInstaApi.cs rename to InstaSharper/API/IInstaApi.cs index a1d1825b..5dc68f5f 100644 --- a/InstagramAPI/API/IInstaApi.cs +++ b/InstaSharper/API/IInstaApi.cs @@ -1,8 +1,8 @@ using System.Threading.Tasks; -using InstagramAPI.Classes; -using InstagramAPI.Classes.Models; +using InstaSharper.Classes; +using InstaSharper.Classes.Models; -namespace InstagramAPI.API +namespace InstaSharper.API { public interface IInstaApi { diff --git a/InstagramAPI/API/InstaApi.cs b/InstaSharper/API/InstaApi.cs similarity index 92% rename from InstagramAPI/API/InstaApi.cs rename to InstaSharper/API/InstaApi.cs index 787383b3..f9de1a46 100644 --- a/InstagramAPI/API/InstaApi.cs +++ b/InstaSharper/API/InstaApi.cs @@ -4,18 +4,18 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; -using InstagramAPI.Classes; -using InstagramAPI.Classes.Android.DeviceInfo; -using InstagramAPI.Classes.Models; -using InstagramAPI.Converters; -using InstagramAPI.Converters.Json; -using InstagramAPI.Helpers; -using InstagramAPI.Logger; -using InstagramAPI.ResponseWrappers; +using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Classes.Models; +using InstaSharper.Converters; +using InstaSharper.Converters.Json; +using InstaSharper.Helpers; +using InstaSharper.Logger; +using InstaSharper.ResponseWrappers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace InstagramAPI.API +namespace InstaSharper.API { public class InstaApi : IInstaApi { @@ -105,7 +105,7 @@ public async Task> GetMediaByCodeAsync(string postCode) } var badRequest = JsonConvert.DeserializeObject(json); _logger.Write(badRequest.Message); - return Result.Fail(badRequest.Message, (InstaMedia)null); + return Result.Fail(badRequest.Message, (InstaMedia) null); } public async Task> GetUserAsync(string username) @@ -133,7 +133,7 @@ public async Task> GetUserAsync(string username) } var badRequest = JsonConvert.DeserializeObject(json); _logger.Write(badRequest.Message); - return Result.Fail(badRequest.Message, (InstaUser)null); + return Result.Fail(badRequest.Message, (InstaUser) null); } public IResult GetCurrentUser() @@ -168,7 +168,7 @@ public async Task> GetCurrentUserAsync() return Result.Success(userConverted); } - return Result.Fail("", (InstaUser)null); + return Result.Fail("", (InstaUser) null); } public async Task> GetUserFeedAsync(int maxPages = 0) @@ -180,7 +180,7 @@ public async Task> GetUserFeedAsync(int maxPages = 0) var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); var feed = new InstaFeed(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaFeed)null); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaFeed) null); var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); var converter = ConvertersFabric.GetFeedConverter(feedResponse); var feedConverted = converter.Convert(); @@ -207,16 +207,16 @@ public async Task> GetUserFollowersAsync(string username, ValidateLoggedIn(); try { - if (maxPages == 0) maxPages = Int32.MaxValue; + if (maxPages == 0) maxPages = int.MaxValue; var user = await GetUserAsync(username); var userFeedUri = UriCreator.GetUserFollowersUri(user.Value.Pk, _user.RankToken); var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); var followers = new InstaUserList(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaUserList)null); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaUserList) null); var followersResponse = JsonConvert.DeserializeObject(json); - if (!followersResponse.IsOK()) Result.Fail("", (InstaUserList)null); + if (!followersResponse.IsOK()) Result.Fail("", (InstaUserList) null); followers.AddRange(followersResponse.Items.Select(ConvertersFabric.GetUserConverter).Select(converter => converter.Convert())); if (!followersResponse.IsBigList) return Result.Success(followers); var pages = 1; @@ -229,11 +229,9 @@ public async Task> GetUserFollowersAsync(string username, } return Result.Success(followers); } - catch (Exception exception) - { - return Result.Fail(exception.Message, (InstaUserList)null); + catch (Exception exception) { + return Result.Fail(exception.Message, (InstaUserList) null); } - } private async Task> GetUserFollowersWithMaxIdAsync(string username, string maxId) @@ -250,16 +248,14 @@ private async Task> GetUserFollowersWithMaxIdAsy if (response.StatusCode == HttpStatusCode.OK) { var followersResponse = JsonConvert.DeserializeObject(json); - if (!followersResponse.IsOK()) Result.Fail("", (InstaFollowersResponse)null); + if (!followersResponse.IsOK()) Result.Fail("", (InstaFollowersResponse) null); return Result.Success(followersResponse); } - return Result.Fail("", (InstaFollowersResponse)null); + return Result.Fail("", (InstaFollowersResponse) null); } - catch (Exception exception) - { - return Result.Fail(exception.Message, (InstaFollowersResponse)null); + catch (Exception exception) { + return Result.Fail(exception.Message, (InstaFollowersResponse) null); } - } public async Task> GetTagFeedAsync(string tag, int maxPages = 0) @@ -284,7 +280,7 @@ public async Task> GetTagFeedAsync(string tag, int maxPa } return Result.Success(mediaList); } - return Result.Fail("", (InstaMediaList)null); + return Result.Fail("", (InstaMediaList) null); } public async Task> GetTagFeedWithMaxIdAsync(string tag, string nextId) @@ -294,7 +290,7 @@ public async Task> GetTagFeedWithMaxIdAsync(stri { ValidateLoggedIn(); var instaUri = UriCreator.GetTagFeedUri(tag); - instaUri = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }.Uri; + instaUri = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}.Uri; var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); @@ -303,14 +299,13 @@ public async Task> GetTagFeedWithMaxIdAsync(stri var feedResponse = JsonConvert.DeserializeObject(json); return Result.Success(feedResponse); } - return Result.Fail("", (InstaMediaListResponse)null); + return Result.Fail("", (InstaMediaListResponse) null); } - catch (Exception exception) - { - return Result.Fail(exception.Message, (InstaMediaListResponse)null); + catch (Exception exception) { + return Result.Fail(exception.Message, (InstaMediaListResponse) null); } - } + public async Task> GetUserMediaAsync(string username, int maxPages = 0) { ValidateUser(); @@ -336,14 +331,14 @@ public async Task> GetUserMediaAsync(string username, in } var badRequest = JsonConvert.DeserializeObject(json); _logger.Write(badRequest.Message); - return Result.Fail(badRequest.Message, (InstaMediaList)null); + return Result.Fail(badRequest.Message, (InstaMediaList) null); } public async Task> GetUserFeedWithMaxIdAsync(string maxId) { Uri instaUri; if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search user URI"); - var userUriBuilder = new UriBuilder(instaUri) { Query = $"max_id={maxId}" }; + var userUriBuilder = new UriBuilder(instaUri) {Query = $"max_id={maxId}"}; var request = new HttpRequestMessage(HttpMethod.Get, userUriBuilder.Uri); request.Headers.Clear(); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_PHONE_ID, _requestMessage.phone_id)); @@ -356,7 +351,7 @@ public async Task> GetUserFeedWithMaxIdAsync(string m var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); return Result.Success(feedResponse); } - return Result.Fail("", (InstaFeedResponse)null); + return Result.Fail("", (InstaFeedResponse) null); } private async Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId) @@ -370,7 +365,7 @@ private async Task> GetUserMediaListWithMaxIdAsy var mediaResponse = JsonConvert.DeserializeObject(json); return Result.Success(mediaResponse); } - return Result.Fail("", (InstaMediaListResponse)null); + return Result.Fail("", (InstaMediaListResponse) null); } public async Task> LoginAsync() @@ -389,8 +384,8 @@ public async Task> LoginAsync() var signature = $"{_requestMessage.GenerateSignature()}.{_requestMessage.GetMessageString()}"; var fields = new Dictionary { - { InstaApiConstants.HEADER_IG_SIGNATURE, signature}, - { InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION } + {InstaApiConstants.HEADER_IG_SIGNATURE, signature}, + {InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION} }; var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); request.Content = new FormUrlEncodedContent(fields); @@ -415,11 +410,9 @@ public async Task> LoginAsync() return Result.Fail(loginInfo.Message, false); } } - catch (Exception exception) - { + catch (Exception exception) { return Result.Fail(exception.Message, false); } - } #endregion @@ -435,6 +428,7 @@ private void ValidateLoggedIn() { if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); } + private void ValidateRequestMessage() { if ((_requestMessage == null) || _requestMessage.IsEmpty()) throw new ArgumentException("API request message null or empty"); diff --git a/InstagramAPI/API/InstaApiConstants.cs b/InstaSharper/API/InstaApiConstants.cs similarity index 99% rename from InstagramAPI/API/InstaApiConstants.cs rename to InstaSharper/API/InstaApiConstants.cs index cc18eb0e..6fb84b58 100644 --- a/InstagramAPI/API/InstaApiConstants.cs +++ b/InstaSharper/API/InstaApiConstants.cs @@ -1,4 +1,4 @@ -namespace InstagramAPI.API +namespace InstaSharper.API { public static class InstaApiConstants { diff --git a/InstagramAPI/Classes/Android/DeviceInfo/AndroidDevice.cs b/InstaSharper/Classes/Android/DeviceInfo/AndroidDevice.cs similarity index 94% rename from InstagramAPI/Classes/Android/DeviceInfo/AndroidDevice.cs rename to InstaSharper/Classes/Android/DeviceInfo/AndroidDevice.cs index c9b59e8f..f9e76ce1 100644 --- a/InstagramAPI/Classes/Android/DeviceInfo/AndroidDevice.cs +++ b/InstaSharper/Classes/Android/DeviceInfo/AndroidDevice.cs @@ -1,6 +1,6 @@ using System; -namespace InstagramAPI.Classes.Android.DeviceInfo +namespace InstaSharper.Classes.Android.DeviceInfo { public class AndroidDevice { diff --git a/InstagramAPI/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs b/InstaSharper/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs similarity index 99% rename from InstagramAPI/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs rename to InstaSharper/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs index d6ab237c..cbb50c8b 100644 --- a/InstagramAPI/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs +++ b/InstaSharper/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace InstagramAPI.Classes.Android.DeviceInfo +namespace InstaSharper.Classes.Android.DeviceInfo { public class AndroidDeviceGenerator { diff --git a/InstagramAPI/Classes/Android/DeviceInfo/ApiRequestMessage.cs b/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs similarity index 91% rename from InstagramAPI/Classes/Android/DeviceInfo/ApiRequestMessage.cs rename to InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs index d9c4ba72..fb8b0c07 100644 --- a/InstagramAPI/Classes/Android/DeviceInfo/ApiRequestMessage.cs +++ b/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs @@ -1,9 +1,9 @@ using System; -using InstagramAPI.API; -using InstagramAPI.Helpers; +using InstaSharper.API; +using InstaSharper.Helpers; using Newtonsoft.Json; -namespace InstagramAPI.Classes.Android.DeviceInfo +namespace InstaSharper.Classes.Android.DeviceInfo { public class ApiRequestMessage { diff --git a/InstagramAPI/Classes/Android/LoginInfoAndroid.cs b/InstaSharper/Classes/Android/LoginInfoAndroid.cs similarity index 53% rename from InstagramAPI/Classes/Android/LoginInfoAndroid.cs rename to InstaSharper/Classes/Android/LoginInfoAndroid.cs index 737dd938..0d02205c 100644 --- a/InstagramAPI/Classes/Android/LoginInfoAndroid.cs +++ b/InstaSharper/Classes/Android/LoginInfoAndroid.cs @@ -1,4 +1,4 @@ -namespace InstagramAPI.Classes.Android +namespace InstaSharper.Classes.Android { public class LoginInfoAndroid { diff --git a/InstagramAPI/Classes/IResult.cs b/InstaSharper/Classes/IResult.cs similarity index 80% rename from InstagramAPI/Classes/IResult.cs rename to InstaSharper/Classes/IResult.cs index eeb8af9a..e31a3bdd 100644 --- a/InstagramAPI/Classes/IResult.cs +++ b/InstaSharper/Classes/IResult.cs @@ -1,4 +1,4 @@ -namespace InstagramAPI.Classes +namespace InstaSharper.Classes { public interface IResult { diff --git a/InstagramAPI/Classes/Models/Dimensions.cs b/InstaSharper/Classes/Models/Dimensions.cs similarity index 75% rename from InstagramAPI/Classes/Models/Dimensions.cs rename to InstaSharper/Classes/Models/Dimensions.cs index ef9d3838..cc1baffc 100644 --- a/InstagramAPI/Classes/Models/Dimensions.cs +++ b/InstaSharper/Classes/Models/Dimensions.cs @@ -1,4 +1,4 @@ -namespace InstagramAPI.Classes.Models +namespace InstaSharper.Classes.Models { public class Dimensions { diff --git a/InstagramAPI/Classes/Models/Image.cs b/InstaSharper/Classes/Models/Image.cs similarity index 88% rename from InstagramAPI/Classes/Models/Image.cs rename to InstaSharper/Classes/Models/Image.cs index 1c421f6a..4ff173fd 100644 --- a/InstagramAPI/Classes/Models/Image.cs +++ b/InstaSharper/Classes/Models/Image.cs @@ -1,4 +1,4 @@ -namespace InstagramAPI.Classes.Models +namespace InstaSharper.Classes.Models { public class Image { diff --git a/InstagramAPI/Classes/Models/Images.cs b/InstaSharper/Classes/Models/Images.cs similarity index 82% rename from InstagramAPI/Classes/Models/Images.cs rename to InstaSharper/Classes/Models/Images.cs index fb775956..9bb22e44 100644 --- a/InstagramAPI/Classes/Models/Images.cs +++ b/InstaSharper/Classes/Models/Images.cs @@ -1,4 +1,4 @@ -namespace InstagramAPI.Classes.Models +namespace InstaSharper.Classes.Models { public class Images { diff --git a/InstagramAPI/Classes/Models/InstaCaption.cs b/InstaSharper/Classes/Models/InstaCaption.cs similarity index 90% rename from InstagramAPI/Classes/Models/InstaCaption.cs rename to InstaSharper/Classes/Models/InstaCaption.cs index c3fd59bc..6975e8b5 100644 --- a/InstagramAPI/Classes/Models/InstaCaption.cs +++ b/InstaSharper/Classes/Models/InstaCaption.cs @@ -1,6 +1,6 @@ using System; -namespace InstagramAPI.Classes.Models +namespace InstaSharper.Classes.Models { public class InstaCaption { diff --git a/InstagramAPI/Classes/Models/InstaFeed.cs b/InstaSharper/Classes/Models/InstaFeed.cs similarity index 86% rename from InstagramAPI/Classes/Models/InstaFeed.cs rename to InstaSharper/Classes/Models/InstaFeed.cs index 21fb18e1..6eaba0e3 100644 --- a/InstagramAPI/Classes/Models/InstaFeed.cs +++ b/InstaSharper/Classes/Models/InstaFeed.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace InstagramAPI.Classes.Models +namespace InstaSharper.Classes.Models { public class InstaFeed { diff --git a/InstagramAPI/Classes/Models/InstaFriendshipStatus.cs b/InstaSharper/Classes/Models/InstaFriendshipStatus.cs similarity index 85% rename from InstagramAPI/Classes/Models/InstaFriendshipStatus.cs rename to InstaSharper/Classes/Models/InstaFriendshipStatus.cs index f30dcd16..afad47fc 100644 --- a/InstagramAPI/Classes/Models/InstaFriendshipStatus.cs +++ b/InstaSharper/Classes/Models/InstaFriendshipStatus.cs @@ -1,4 +1,4 @@ -namespace InstagramAPI.Classes.Models +namespace InstaSharper.Classes.Models { public class InstaFriendshipStatus { diff --git a/InstagramAPI/Classes/Models/InstaLocation.cs b/InstaSharper/Classes/Models/InstaLocation.cs similarity index 67% rename from InstagramAPI/Classes/Models/InstaLocation.cs rename to InstaSharper/Classes/Models/InstaLocation.cs index edf27f8e..df10dde8 100644 --- a/InstagramAPI/Classes/Models/InstaLocation.cs +++ b/InstaSharper/Classes/Models/InstaLocation.cs @@ -1,4 +1,4 @@ -namespace InstagramAPI.Classes.Models +namespace InstaSharper.Classes.Models { public class InstaLocation { diff --git a/InstagramAPI/Classes/Models/InstaMedia.cs b/InstaSharper/Classes/Models/InstaMedia.cs similarity index 96% rename from InstagramAPI/Classes/Models/InstaMedia.cs rename to InstaSharper/Classes/Models/InstaMedia.cs index c168e7fc..77f2c4a7 100644 --- a/InstagramAPI/Classes/Models/InstaMedia.cs +++ b/InstaSharper/Classes/Models/InstaMedia.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace InstagramAPI.Classes.Models +namespace InstaSharper.Classes.Models { public class InstaMedia { diff --git a/InstagramAPI/Classes/Models/InstaMediaList.cs b/InstaSharper/Classes/Models/InstaMediaList.cs similarity index 79% rename from InstagramAPI/Classes/Models/InstaMediaList.cs rename to InstaSharper/Classes/Models/InstaMediaList.cs index e01b8dc0..3dc9dcf2 100644 --- a/InstagramAPI/Classes/Models/InstaMediaList.cs +++ b/InstaSharper/Classes/Models/InstaMediaList.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace InstagramAPI.Classes.Models +namespace InstaSharper.Classes.Models { public class InstaMediaList : List { diff --git a/InstagramAPI/Classes/Models/InstaMediaType.cs b/InstaSharper/Classes/Models/InstaMediaType.cs similarity index 66% rename from InstagramAPI/Classes/Models/InstaMediaType.cs rename to InstaSharper/Classes/Models/InstaMediaType.cs index 517fd1af..21437613 100644 --- a/InstagramAPI/Classes/Models/InstaMediaType.cs +++ b/InstaSharper/Classes/Models/InstaMediaType.cs @@ -1,4 +1,4 @@ -namespace InstagramAPI.Classes.Models +namespace InstaSharper.Classes.Models { public enum InstaMediaType { diff --git a/InstagramAPI/Classes/Models/InstaUser.cs b/InstaSharper/Classes/Models/InstaUser.cs similarity index 95% rename from InstagramAPI/Classes/Models/InstaUser.cs rename to InstaSharper/Classes/Models/InstaUser.cs index 5206e6a0..7d41819b 100644 --- a/InstagramAPI/Classes/Models/InstaUser.cs +++ b/InstaSharper/Classes/Models/InstaUser.cs @@ -1,4 +1,4 @@ -namespace InstagramAPI.Classes.Models +namespace InstaSharper.Classes.Models { public class InstaUser { diff --git a/InstagramAPI/Classes/Models/InstaUserList.cs b/InstaSharper/Classes/Models/InstaUserList.cs similarity index 72% rename from InstagramAPI/Classes/Models/InstaUserList.cs rename to InstaSharper/Classes/Models/InstaUserList.cs index 7c1a87ba..7709edd4 100644 --- a/InstagramAPI/Classes/Models/InstaUserList.cs +++ b/InstaSharper/Classes/Models/InstaUserList.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace InstagramAPI.Classes.Models +namespace InstaSharper.Classes.Models { public class InstaUserList : List { diff --git a/InstagramAPI/Classes/Models/Likes.cs b/InstaSharper/Classes/Models/Likes.cs similarity index 77% rename from InstagramAPI/Classes/Models/Likes.cs rename to InstaSharper/Classes/Models/Likes.cs index 22db287c..6df7e061 100644 --- a/InstagramAPI/Classes/Models/Likes.cs +++ b/InstaSharper/Classes/Models/Likes.cs @@ -1,4 +1,4 @@ -namespace InstagramAPI.Classes.Models +namespace InstaSharper.Classes.Models { public class Likes { diff --git a/InstagramAPI/Classes/Result.cs b/InstaSharper/Classes/Result.cs similarity index 98% rename from InstagramAPI/Classes/Result.cs rename to InstaSharper/Classes/Result.cs index 4943137e..d6a6fd2f 100644 --- a/InstagramAPI/Classes/Result.cs +++ b/InstaSharper/Classes/Result.cs @@ -1,6 +1,6 @@ using System; -namespace InstagramAPI.Classes +namespace InstaSharper.Classes { public static class Result { diff --git a/InstagramAPI/Classes/UserSessionData.cs b/InstaSharper/Classes/UserSessionData.cs similarity index 80% rename from InstagramAPI/Classes/UserSessionData.cs rename to InstaSharper/Classes/UserSessionData.cs index 719f680f..1a059db2 100644 --- a/InstagramAPI/Classes/UserSessionData.cs +++ b/InstaSharper/Classes/UserSessionData.cs @@ -1,6 +1,6 @@ -using InstagramAPI.Classes.Models; +using InstaSharper.Classes.Models; -namespace InstagramAPI.Classes +namespace InstaSharper.Classes { public class UserSessionData { diff --git a/InstagramAPI/Converters/ConvertersFabric.cs b/InstaSharper/Converters/ConvertersFabric.cs similarity index 93% rename from InstagramAPI/Converters/ConvertersFabric.cs rename to InstaSharper/Converters/ConvertersFabric.cs index caf41877..15566e1a 100644 --- a/InstagramAPI/Converters/ConvertersFabric.cs +++ b/InstaSharper/Converters/ConvertersFabric.cs @@ -1,7 +1,7 @@ -using InstagramAPI.Classes.Models; -using InstagramAPI.ResponseWrappers; +using InstaSharper.Classes.Models; +using InstaSharper.ResponseWrappers; -namespace InstagramAPI.Converters +namespace InstaSharper.Converters { internal class ConvertersFabric { diff --git a/InstagramAPI/Converters/IObjectConverter.cs b/InstaSharper/Converters/IObjectConverter.cs similarity index 76% rename from InstagramAPI/Converters/IObjectConverter.cs rename to InstaSharper/Converters/IObjectConverter.cs index 1f2d8834..ba4da960 100644 --- a/InstagramAPI/Converters/IObjectConverter.cs +++ b/InstaSharper/Converters/IObjectConverter.cs @@ -1,4 +1,4 @@ -namespace InstagramAPI.Converters +namespace InstaSharper.Converters { internal interface IObjectConverter { diff --git a/InstagramAPI/Converters/InstaCaptionConverter.cs b/InstaSharper/Converters/InstaCaptionConverter.cs similarity index 85% rename from InstagramAPI/Converters/InstaCaptionConverter.cs rename to InstaSharper/Converters/InstaCaptionConverter.cs index 9d80a4d0..ad7381b3 100644 --- a/InstagramAPI/Converters/InstaCaptionConverter.cs +++ b/InstaSharper/Converters/InstaCaptionConverter.cs @@ -1,8 +1,8 @@ -using InstagramAPI.Classes.Models; -using InstagramAPI.Helpers; -using InstagramAPI.ResponseWrappers; +using InstaSharper.Classes.Models; +using InstaSharper.Helpers; +using InstaSharper.ResponseWrappers; -namespace InstagramAPI.Converters +namespace InstaSharper.Converters { public class InstaCaptionConverter : IObjectConverter { diff --git a/InstagramAPI/Converters/InstaFeedConverter.cs b/InstaSharper/Converters/InstaFeedConverter.cs similarity index 84% rename from InstagramAPI/Converters/InstaFeedConverter.cs rename to InstaSharper/Converters/InstaFeedConverter.cs index f25e879d..acf91f29 100644 --- a/InstagramAPI/Converters/InstaFeedConverter.cs +++ b/InstaSharper/Converters/InstaFeedConverter.cs @@ -1,7 +1,7 @@ -using InstagramAPI.Classes.Models; -using InstagramAPI.ResponseWrappers; +using InstaSharper.Classes.Models; +using InstaSharper.ResponseWrappers; -namespace InstagramAPI.Converters +namespace InstaSharper.Converters { internal class InstaFeedConverter : IObjectConverter { diff --git a/InstagramAPI/Converters/InstaFriendshipStatusConverter.cs b/InstaSharper/Converters/InstaFriendshipStatusConverter.cs similarity index 86% rename from InstagramAPI/Converters/InstaFriendshipStatusConverter.cs rename to InstaSharper/Converters/InstaFriendshipStatusConverter.cs index 4176ea4d..cac3c6fc 100644 --- a/InstagramAPI/Converters/InstaFriendshipStatusConverter.cs +++ b/InstaSharper/Converters/InstaFriendshipStatusConverter.cs @@ -1,7 +1,7 @@ -using InstagramAPI.Classes.Models; -using InstagramAPI.ResponseWrappers; +using InstaSharper.Classes.Models; +using InstaSharper.ResponseWrappers; -namespace InstagramAPI.Converters +namespace InstaSharper.Converters { public class InstaFriendshipStatusConverter : IObjectConverter { diff --git a/InstagramAPI/Converters/InstaMediaConverter.cs b/InstaSharper/Converters/InstaMediaConverter.cs similarity index 93% rename from InstagramAPI/Converters/InstaMediaConverter.cs rename to InstaSharper/Converters/InstaMediaConverter.cs index c3dca404..aeacde67 100644 --- a/InstagramAPI/Converters/InstaMediaConverter.cs +++ b/InstaSharper/Converters/InstaMediaConverter.cs @@ -1,9 +1,9 @@ using System; -using InstagramAPI.Classes.Models; -using InstagramAPI.Helpers; -using InstagramAPI.ResponseWrappers; +using InstaSharper.Classes.Models; +using InstaSharper.Helpers; +using InstaSharper.ResponseWrappers; -namespace InstagramAPI.Converters +namespace InstaSharper.Converters { public class InstaMediaConverter : IObjectConverter { diff --git a/InstagramAPI/Converters/InstaMediaListConverter.cs b/InstaSharper/Converters/InstaMediaListConverter.cs similarity index 84% rename from InstagramAPI/Converters/InstaMediaListConverter.cs rename to InstaSharper/Converters/InstaMediaListConverter.cs index a563bc7e..d20e6bd0 100644 --- a/InstagramAPI/Converters/InstaMediaListConverter.cs +++ b/InstaSharper/Converters/InstaMediaListConverter.cs @@ -1,9 +1,9 @@ using System; using System.Linq; -using InstagramAPI.Classes.Models; -using InstagramAPI.ResponseWrappers; +using InstaSharper.Classes.Models; +using InstaSharper.ResponseWrappers; -namespace InstagramAPI.Converters +namespace InstaSharper.Converters { internal class InstaMediaListConverter : IObjectConverter { diff --git a/InstagramAPI/Converters/InstaUsersConverter.cs b/InstaSharper/Converters/InstaUsersConverter.cs similarity index 93% rename from InstagramAPI/Converters/InstaUsersConverter.cs rename to InstaSharper/Converters/InstaUsersConverter.cs index 74e4c505..80e42e28 100644 --- a/InstagramAPI/Converters/InstaUsersConverter.cs +++ b/InstaSharper/Converters/InstaUsersConverter.cs @@ -1,8 +1,8 @@ using System; -using InstagramAPI.Classes.Models; -using InstagramAPI.ResponseWrappers; +using InstaSharper.Classes.Models; +using InstaSharper.ResponseWrappers; -namespace InstagramAPI.Converters +namespace InstaSharper.Converters { internal class InstaUsersConverter : IObjectConverter { diff --git a/InstagramAPI/Converters/Json/FeedResponseDataConverter.cs b/InstaSharper/Converters/Json/FeedResponseDataConverter.cs similarity index 94% rename from InstagramAPI/Converters/Json/FeedResponseDataConverter.cs rename to InstaSharper/Converters/Json/FeedResponseDataConverter.cs index a11f30a5..f479c354 100644 --- a/InstagramAPI/Converters/Json/FeedResponseDataConverter.cs +++ b/InstaSharper/Converters/Json/FeedResponseDataConverter.cs @@ -1,12 +1,11 @@ using System; using System.Collections.Generic; -using InstagramAPI.ResponseWrappers; +using InstaSharper.ResponseWrappers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace InstagramAPI.Converters.Json +namespace InstaSharper.Converters.Json { - public class FeedResponseDataConverter : JsonConverter { public override bool CanConvert(Type objectType) diff --git a/InstagramAPI/Helpers/CryptoHelper.cs b/InstaSharper/Helpers/CryptoHelper.cs similarity index 98% rename from InstagramAPI/Helpers/CryptoHelper.cs rename to InstaSharper/Helpers/CryptoHelper.cs index 6f6d4e8d..00b5ec90 100644 --- a/InstagramAPI/Helpers/CryptoHelper.cs +++ b/InstaSharper/Helpers/CryptoHelper.cs @@ -3,7 +3,7 @@ using System.Security.Cryptography; using System.Text; -namespace InstagramAPI.Helpers +namespace InstaSharper.Helpers { public class CryptoHelper { diff --git a/InstagramAPI/Helpers/DateTimeHelper.cs b/InstaSharper/Helpers/DateTimeHelper.cs similarity index 95% rename from InstagramAPI/Helpers/DateTimeHelper.cs rename to InstaSharper/Helpers/DateTimeHelper.cs index 2c998a85..580263ee 100644 --- a/InstagramAPI/Helpers/DateTimeHelper.cs +++ b/InstaSharper/Helpers/DateTimeHelper.cs @@ -1,6 +1,6 @@ using System; -namespace InstagramAPI.Helpers +namespace InstaSharper.Helpers { public static class DateTimeHelper { diff --git a/InstagramAPI/Helpers/HttpHelper.cs b/InstaSharper/Helpers/HttpHelper.cs similarity index 90% rename from InstagramAPI/Helpers/HttpHelper.cs rename to InstaSharper/Helpers/HttpHelper.cs index a30a4e4f..95d1f4ab 100644 --- a/InstagramAPI/Helpers/HttpHelper.cs +++ b/InstaSharper/Helpers/HttpHelper.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using System.Net.Http; -using InstagramAPI.API; -using InstagramAPI.Classes.Android.DeviceInfo; +using InstaSharper.API; +using InstaSharper.Classes.Android.DeviceInfo; -namespace InstagramAPI.Helpers +namespace InstaSharper.Helpers { public class HttpHelper { diff --git a/InstagramAPI/Helpers/UriCreator.cs b/InstaSharper/Helpers/UriCreator.cs similarity index 88% rename from InstagramAPI/Helpers/UriCreator.cs rename to InstaSharper/Helpers/UriCreator.cs index 9bab9513..5ffbc1db 100644 --- a/InstagramAPI/Helpers/UriCreator.cs +++ b/InstaSharper/Helpers/UriCreator.cs @@ -1,7 +1,7 @@ using System; -using InstagramAPI.API; +using InstaSharper.API; -namespace InstagramAPI.Helpers +namespace InstaSharper.Helpers { public class UriCreator { @@ -17,7 +17,7 @@ public static Uri GetUserUri(string username) { Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.SEARCH_USERS, out instaUri)) throw new Exception("Cant create search user URI"); - var userUriBuilder = new UriBuilder(instaUri) { Query = $"q={username}" }; + var userUriBuilder = new UriBuilder(instaUri) {Query = $"q={username}"}; return userUriBuilder.Uri; } @@ -46,7 +46,7 @@ public static Uri GetTimelineWithMaxIdUri(string nextId) { Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search URI for timeline"); - var uriBuilder = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }; + var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}; return uriBuilder.Uri; } @@ -54,7 +54,7 @@ public static Uri GetMediaListWithMaxIdUri(string userPk, string nextId) { Uri instaUri; if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.USEREFEED + userPk + "/", out instaUri)) throw new Exception("Cant create URI for media list"); - var uriBuilder = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }; + var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}; return uriBuilder.Uri; } @@ -70,7 +70,7 @@ internal static Uri GetUserFollowersUri(string userPk, string rankToken, string Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_FOLLOWERS, userPk, rankToken), out instaUri)) throw new Exception("Cant create URI for user followers"); if (string.IsNullOrEmpty(maxId)) return instaUri; - var uriBuilder = new UriBuilder(instaUri) { Query = $"max_id={maxId}" }; + var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={maxId}"}; return uriBuilder.Uri; } diff --git a/InstagramAPI/InstagramAPI.xproj b/InstaSharper/InstaSharper.xproj similarity index 95% rename from InstagramAPI/InstagramAPI.xproj rename to InstaSharper/InstaSharper.xproj index 81bd4037..d167e9b1 100644 --- a/InstagramAPI/InstagramAPI.xproj +++ b/InstaSharper/InstaSharper.xproj @@ -8,7 +8,7 @@ 449a948d-cc65-4d1a-8159-6fa232f972d9 - InstagramAPI + InstaSharper .\obj .\bin\ v4.5.2 diff --git a/InstagramAPI/Logger/DebugLogger.cs b/InstaSharper/Logger/DebugLogger.cs similarity index 86% rename from InstagramAPI/Logger/DebugLogger.cs rename to InstaSharper/Logger/DebugLogger.cs index 2171a008..6ed0e99e 100644 --- a/InstagramAPI/Logger/DebugLogger.cs +++ b/InstaSharper/Logger/DebugLogger.cs @@ -1,6 +1,6 @@ using System; -namespace InstagramAPI.Logger +namespace InstaSharper.Logger { public class DebugLogger : ILogger { diff --git a/InstagramAPI/Logger/ILogger.cs b/InstaSharper/Logger/ILogger.cs similarity index 71% rename from InstagramAPI/Logger/ILogger.cs rename to InstaSharper/Logger/ILogger.cs index f65cd95a..3ca0f377 100644 --- a/InstagramAPI/Logger/ILogger.cs +++ b/InstaSharper/Logger/ILogger.cs @@ -1,4 +1,4 @@ -namespace InstagramAPI.Logger +namespace InstaSharper.Logger { public interface ILogger { diff --git a/InstagramAPI/Properties/AssemblyInfo.cs b/InstaSharper/Properties/AssemblyInfo.cs similarity index 94% rename from InstagramAPI/Properties/AssemblyInfo.cs rename to InstaSharper/Properties/AssemblyInfo.cs index e6114e8b..686b5a22 100644 --- a/InstagramAPI/Properties/AssemblyInfo.cs +++ b/InstaSharper/Properties/AssemblyInfo.cs @@ -7,7 +7,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("InstagramApi")] +[assembly: AssemblyProduct("InstaSharper")] [assembly: AssemblyTrademark("")] // Setting ComVisible to false makes the types in this assembly not visible diff --git a/InstagramAPI/ResponseWrappers/BadStatusResponse.cs b/InstaSharper/ResponseWrappers/BadStatusResponse.cs similarity index 73% rename from InstagramAPI/ResponseWrappers/BadStatusResponse.cs rename to InstaSharper/ResponseWrappers/BadStatusResponse.cs index d449e039..d7e0d82e 100644 --- a/InstagramAPI/ResponseWrappers/BadStatusResponse.cs +++ b/InstaSharper/ResponseWrappers/BadStatusResponse.cs @@ -1,7 +1,7 @@ -using InstagramAPI.ResponseWrappers.BaseResponse; +using InstaSharper.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class BadStatusResponse : BaseStatusResponse { diff --git a/InstagramAPI/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs b/InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs similarity index 89% rename from InstagramAPI/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs rename to InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs index 02cbcbe4..12bc254e 100644 --- a/InstagramAPI/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs +++ b/InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers.BaseResponse +namespace InstaSharper.ResponseWrappers.BaseResponse { public class BaseLoadableResponse : BaseStatusResponse { diff --git a/InstagramAPI/ResponseWrappers/BaseResponse/BaseStatusResponse.cs b/InstaSharper/ResponseWrappers/BaseResponse/BaseStatusResponse.cs similarity index 74% rename from InstagramAPI/ResponseWrappers/BaseResponse/BaseStatusResponse.cs rename to InstaSharper/ResponseWrappers/BaseResponse/BaseStatusResponse.cs index 58032787..637ca188 100644 --- a/InstagramAPI/ResponseWrappers/BaseResponse/BaseStatusResponse.cs +++ b/InstaSharper/ResponseWrappers/BaseResponse/BaseStatusResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers.BaseResponse +namespace InstaSharper.ResponseWrappers.BaseResponse { public class BaseStatusResponse { diff --git a/InstagramAPI/ResponseWrappers/FollowedByResponse.cs b/InstaSharper/ResponseWrappers/FollowedByResponse.cs similarity index 78% rename from InstagramAPI/ResponseWrappers/FollowedByResponse.cs rename to InstaSharper/ResponseWrappers/FollowedByResponse.cs index cf88efca..96e04f42 100644 --- a/InstagramAPI/ResponseWrappers/FollowedByResponse.cs +++ b/InstaSharper/ResponseWrappers/FollowedByResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class FollowedByResponse { diff --git a/InstagramAPI/ResponseWrappers/ImageResponse.cs b/InstaSharper/ResponseWrappers/ImageResponse.cs similarity index 88% rename from InstagramAPI/ResponseWrappers/ImageResponse.cs rename to InstaSharper/ResponseWrappers/ImageResponse.cs index f6a3ede1..9148207f 100644 --- a/InstagramAPI/ResponseWrappers/ImageResponse.cs +++ b/InstaSharper/ResponseWrappers/ImageResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class ImageResponse { diff --git a/InstagramAPI/ResponseWrappers/ImagesResponse.cs b/InstaSharper/ResponseWrappers/ImagesResponse.cs similarity index 90% rename from InstagramAPI/ResponseWrappers/ImagesResponse.cs rename to InstaSharper/ResponseWrappers/ImagesResponse.cs index c80a9752..5b98eb24 100644 --- a/InstagramAPI/ResponseWrappers/ImagesResponse.cs +++ b/InstaSharper/ResponseWrappers/ImagesResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class ImagesResponse { diff --git a/InstagramAPI/ResponseWrappers/InstaCaptionResponse.cs b/InstaSharper/ResponseWrappers/InstaCaptionResponse.cs similarity index 87% rename from InstagramAPI/ResponseWrappers/InstaCaptionResponse.cs rename to InstaSharper/ResponseWrappers/InstaCaptionResponse.cs index 535c3bba..9f965693 100644 --- a/InstagramAPI/ResponseWrappers/InstaCaptionResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaCaptionResponse.cs @@ -1,7 +1,7 @@ -using InstagramAPI.ResponseWrappers.BaseResponse; +using InstaSharper.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class InstaCaptionResponse : BaseStatusResponse { diff --git a/InstagramAPI/ResponseWrappers/InstaCurrentUserResponse.cs b/InstaSharper/ResponseWrappers/InstaCurrentUserResponse.cs similarity index 66% rename from InstagramAPI/ResponseWrappers/InstaCurrentUserResponse.cs rename to InstaSharper/ResponseWrappers/InstaCurrentUserResponse.cs index 79d3f163..5de73ec5 100644 --- a/InstagramAPI/ResponseWrappers/InstaCurrentUserResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaCurrentUserResponse.cs @@ -1,7 +1,7 @@ -using InstagramAPI.ResponseWrappers.BaseResponse; +using InstaSharper.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class InstaCurrentUserResponse : BaseStatusResponse { diff --git a/InstagramAPI/ResponseWrappers/InstaFeedResponse.cs b/InstaSharper/ResponseWrappers/InstaFeedResponse.cs similarity index 68% rename from InstagramAPI/ResponseWrappers/InstaFeedResponse.cs rename to InstaSharper/ResponseWrappers/InstaFeedResponse.cs index f3f719bf..5b73db82 100644 --- a/InstagramAPI/ResponseWrappers/InstaFeedResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaFeedResponse.cs @@ -1,10 +1,8 @@ -using System; -using System.Collections.Generic; -using InstagramAPI.ResponseWrappers.BaseResponse; +using System.Collections.Generic; +using InstaSharper.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class InstaFeedResponse : BaseLoadableResponse { diff --git a/InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs b/InstaSharper/ResponseWrappers/InstaFollowersResponse.cs similarity index 86% rename from InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs rename to InstaSharper/ResponseWrappers/InstaFollowersResponse.cs index 54e2a0e7..6cba830c 100644 --- a/InstagramAPI/ResponseWrappers/InstaFollowersResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaFollowersResponse.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; -using InstagramAPI.ResponseWrappers.BaseResponse; +using InstaSharper.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class InstaFollowersResponse : BaseStatusResponse { diff --git a/InstagramAPI/ResponseWrappers/InstaFriendshipStatusResponse.cs b/InstaSharper/ResponseWrappers/InstaFriendshipStatusResponse.cs similarity index 91% rename from InstagramAPI/ResponseWrappers/InstaFriendshipStatusResponse.cs rename to InstaSharper/ResponseWrappers/InstaFriendshipStatusResponse.cs index 9aff97cb..b4cd7d3c 100644 --- a/InstagramAPI/ResponseWrappers/InstaFriendshipStatusResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaFriendshipStatusResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class InstaFriendshipStatusResponse { diff --git a/InstagramAPI/ResponseWrappers/InstaImageCandidatesResponse.cs b/InstaSharper/ResponseWrappers/InstaImageCandidatesResponse.cs similarity index 84% rename from InstagramAPI/ResponseWrappers/InstaImageCandidatesResponse.cs rename to InstaSharper/ResponseWrappers/InstaImageCandidatesResponse.cs index c26a6b93..2364a12b 100644 --- a/InstagramAPI/ResponseWrappers/InstaImageCandidatesResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaImageCandidatesResponse.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class InstaImageCandidatesResponse { diff --git a/InstagramAPI/ResponseWrappers/InstaLoginResponse.cs b/InstaSharper/ResponseWrappers/InstaLoginResponse.cs similarity index 85% rename from InstagramAPI/ResponseWrappers/InstaLoginResponse.cs rename to InstaSharper/ResponseWrappers/InstaLoginResponse.cs index 0cb47d32..daf2f195 100644 --- a/InstagramAPI/ResponseWrappers/InstaLoginResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaLoginResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class InstaLoginResponse { diff --git a/InstagramAPI/ResponseWrappers/InstaMediaItemResponse.cs b/InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs similarity index 95% rename from InstagramAPI/ResponseWrappers/InstaMediaItemResponse.cs rename to InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs index f08f2544..a9ef3089 100644 --- a/InstagramAPI/ResponseWrappers/InstaMediaItemResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs @@ -1,7 +1,7 @@ -using InstagramAPI.Classes.Models; +using InstaSharper.Classes.Models; using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class InstaMediaItemResponse { diff --git a/InstagramAPI/ResponseWrappers/InstaMediaListResponse.cs b/InstaSharper/ResponseWrappers/InstaMediaListResponse.cs similarity index 72% rename from InstagramAPI/ResponseWrappers/InstaMediaListResponse.cs rename to InstaSharper/ResponseWrappers/InstaMediaListResponse.cs index bb3abf2a..efa4cf20 100644 --- a/InstagramAPI/ResponseWrappers/InstaMediaListResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaMediaListResponse.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; -using InstagramAPI.ResponseWrappers.BaseResponse; +using InstaSharper.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class InstaMediaListResponse : BaseLoadableResponse { diff --git a/InstagramAPI/ResponseWrappers/InstaSearchUserResponse.cs b/InstaSharper/ResponseWrappers/InstaSearchUserResponse.cs similarity index 90% rename from InstagramAPI/ResponseWrappers/InstaSearchUserResponse.cs rename to InstaSharper/ResponseWrappers/InstaSearchUserResponse.cs index fcd57f79..6b7fbf52 100644 --- a/InstagramAPI/ResponseWrappers/InstaSearchUserResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaSearchUserResponse.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class InstaSearchUserResponse { diff --git a/InstagramAPI/ResponseWrappers/InstaTagFeedResponse.cs b/InstaSharper/ResponseWrappers/InstaTagFeedResponse.cs similarity index 84% rename from InstagramAPI/ResponseWrappers/InstaTagFeedResponse.cs rename to InstaSharper/ResponseWrappers/InstaTagFeedResponse.cs index 1ee7e990..133f19bd 100644 --- a/InstagramAPI/ResponseWrappers/InstaTagFeedResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaTagFeedResponse.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class InstaTagFeedResponse { diff --git a/InstagramAPI/ResponseWrappers/InstaUserResponse.cs b/InstaSharper/ResponseWrappers/InstaUserResponse.cs similarity index 96% rename from InstagramAPI/ResponseWrappers/InstaUserResponse.cs rename to InstaSharper/ResponseWrappers/InstaUserResponse.cs index ffd5122d..699422d3 100644 --- a/InstagramAPI/ResponseWrappers/InstaUserResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaUserResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstagramAPI.ResponseWrappers +namespace InstaSharper.ResponseWrappers { public class InstaUserResponse { diff --git a/InstagramAPI/project.json b/InstaSharper/project.json similarity index 100% rename from InstagramAPI/project.json rename to InstaSharper/project.json diff --git a/appveyor.yml b/appveyor.yml index c5dd9ebf..d799f4fb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -18,10 +18,10 @@ build: build_script: - ps: dotnet --info - ps: dotnet restore - - ps: cd InstagramAPI + - ps: cd InstaSharper - ps: dotnet --verbose build - ps: dotnet --verbose pack -o ../nugetpack -c release - - ps: cd ../InstagramAPI.Tests + - ps: cd ../InstaSharper.Tests - ps: dotnet restore - ps: dotnet --verbose build - ps: dotnet --verbose test @@ -40,7 +40,7 @@ environment: artifacts: - - path: InstagramAPI\bin\$(configuration)\netstandard1.6\*.dll + - path: InstaSharper\bin\$(configuration)\netstandard1.6\*.dll name: dlls - path: '**\*.nupkg' From 7db71f6fe27b17a768d697b8ed561d00f54fec69 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Fri, 2 Dec 2016 18:53:49 +0300 Subject: [PATCH 10/23] build statuses updated --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2ca9fe4e..8c9e4853 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ Tokenless, butthurtless private API for Instagram. Get account information, medi Note that: there is a simple [Instagram API](https://github.com/a-legotin/InstagramAPI-Web) based on web-version of Instagram. This repository based on Instagram API for mobile devices. -[![Build status](https://ci.appveyor.com/api/projects/status/tgdu2w1xr2qmtmrh?svg=true)](https://ci.appveyor.com/project/a-legotin/instagramapi-xk3ds) -[![Build Status](https://travis-ci.org/a-legotin/InstagramAPI.svg?branch=master)](https://travis-ci.org/a-legotin/InstagramAPI) +[![Build status](https://ci.appveyor.com/api/projects/status/6os0fhi1awbplbka?svg=true)](https://ci.appveyor.com/project/a-legotin/instasharper) +[![Build Status](https://travis-ci.org/a-legotin/InstaSharper.svg?branch=master)](https://travis-ci.org/a-legotin/InstaSharper) #### Current version: 1.2.0 [Stable], 1.2.1 [Under development] From ef135fa03578f362027fc6170797b6c861f0efcb Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Fri, 2 Dec 2016 19:23:13 +0300 Subject: [PATCH 11/23] Logout implemented --- .../Tests/{LoginTest.cs => AuthTest.cs} | 47 ++++---- InstaSharper/API/IInstaApi.cs | 1 + InstaSharper/API/InstaApi.cs | 100 ++++++++++++------ InstaSharper/API/InstaApiConstants.cs | 1 + InstaSharper/Helpers/UriCreator.cs | 16 ++- 5 files changed, 105 insertions(+), 60 deletions(-) rename InstaSharper.Tests/Tests/{LoginTest.cs => AuthTest.cs} (57%) diff --git a/InstaSharper.Tests/Tests/LoginTest.cs b/InstaSharper.Tests/Tests/AuthTest.cs similarity index 57% rename from InstaSharper.Tests/Tests/LoginTest.cs rename to InstaSharper.Tests/Tests/AuthTest.cs index 52b1fbc9..f45405bc 100644 --- a/InstaSharper.Tests/Tests/LoginTest.cs +++ b/InstaSharper.Tests/Tests/AuthTest.cs @@ -1,4 +1,5 @@ using System; +using InstaSharper.API; using InstaSharper.Classes; using InstaSharper.Tests.Utils; using Xunit; @@ -6,19 +7,28 @@ namespace InstaSharper.Tests.Tests { - public class LoginTest + public class AuthTest : IDisposable { - public LoginTest(ITestOutputHelper output) + private readonly ITestOutputHelper _output; + private readonly IInstaApi _apiInstance; + + public AuthTest(ITestOutputHelper output) { - this.output = output; + _output = output; + var username = "alex_codegarage"; + var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); + _apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = username, + Password = password + }); } - private readonly ITestOutputHelper output; + [Fact] public async void UserLoginFailTest() { - //arrange var username = "alex_codegarage"; var password = "boombaby!"; var apiInstance = @@ -27,10 +37,8 @@ public async void UserLoginFailTest() UserName = username, Password = password }); - output.WriteLine("Got API instance"); - //act + _output.WriteLine("Got API instance"); var loginResult = await apiInstance.LoginAsync(); - //assert Assert.False(loginResult.Succeeded); Assert.False(apiInstance.IsUserAuthenticated); } @@ -38,21 +46,16 @@ public async void UserLoginFailTest() [Fact] public async void UserLoginSuccessTest() { - //arrange - var username = "alex_codegarage"; - var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = username, - Password = password - }); - output.WriteLine("Got API instance"); - //act - var loginResult = await apiInstance.LoginAsync(); - //assert + + Assert.False(_apiInstance.IsUserAuthenticated); + var loginResult = await _apiInstance.LoginAsync(); Assert.True(loginResult.Succeeded); - Assert.True(apiInstance.IsUserAuthenticated); + Assert.True(_apiInstance.IsUserAuthenticated); + } + + public void Dispose() + { + _apiInstance.LogoutAsync(); } } } \ No newline at end of file diff --git a/InstaSharper/API/IInstaApi.cs b/InstaSharper/API/IInstaApi.cs index 5dc68f5f..5dec5fab 100644 --- a/InstaSharper/API/IInstaApi.cs +++ b/InstaSharper/API/IInstaApi.cs @@ -15,6 +15,7 @@ public interface IInstaApi Task> GetMediaByCodeAsync(string postCode); IResult Login(); Task> LoginAsync(); + Task> LogoutAsync(); IResult GetUserFeed(int maxPages = 0); Task> GetUserFeedAsync(int maxPages = 0); Task> GetCurrentUserAsync(); diff --git a/InstaSharper/API/InstaApi.cs b/InstaSharper/API/InstaApi.cs index f9de1a46..7da48bfe 100644 --- a/InstaSharper/API/InstaApi.cs +++ b/InstaSharper/API/InstaApi.cs @@ -12,6 +12,7 @@ using InstaSharper.Helpers; using InstaSharper.Logger; using InstaSharper.ResponseWrappers; +using InstaSharper.ResponseWrappers.BaseResponse; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -105,7 +106,7 @@ public async Task> GetMediaByCodeAsync(string postCode) } var badRequest = JsonConvert.DeserializeObject(json); _logger.Write(badRequest.Message); - return Result.Fail(badRequest.Message, (InstaMedia) null); + return Result.Fail(badRequest.Message, (InstaMedia)null); } public async Task> GetUserAsync(string username) @@ -133,7 +134,7 @@ public async Task> GetUserAsync(string username) } var badRequest = JsonConvert.DeserializeObject(json); _logger.Write(badRequest.Message); - return Result.Fail(badRequest.Message, (InstaUser) null); + return Result.Fail(badRequest.Message, (InstaUser)null); } public IResult GetCurrentUser() @@ -144,7 +145,7 @@ public IResult GetCurrentUser() public async Task> GetCurrentUserAsync() { ValidateUser(); - if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); + ValidateLoggedIn(); var instaUri = UriCreator.GetCurrentUserUri(); dynamic jsonObject = new JObject(); jsonObject._uuid = _deviceInfo.DeviceGuid; @@ -168,19 +169,19 @@ public async Task> GetCurrentUserAsync() return Result.Success(userConverted); } - return Result.Fail("", (InstaUser) null); + return Result.Fail("", (InstaUser)null); } public async Task> GetUserFeedAsync(int maxPages = 0) { ValidateUser(); - if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); + ValidateLoggedIn(); var userFeedUri = UriCreator.GetUserFeedUri(); var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); var feed = new InstaFeed(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaFeed) null); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaFeed)null); var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); var converter = ConvertersFabric.GetFeedConverter(feedResponse); var feedConverted = converter.Convert(); @@ -207,16 +208,16 @@ public async Task> GetUserFollowersAsync(string username, ValidateLoggedIn(); try { - if (maxPages == 0) maxPages = int.MaxValue; + if (maxPages == 0) maxPages = Int32.MaxValue; var user = await GetUserAsync(username); var userFeedUri = UriCreator.GetUserFollowersUri(user.Value.Pk, _user.RankToken); var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); var followers = new InstaUserList(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaUserList) null); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaUserList)null); var followersResponse = JsonConvert.DeserializeObject(json); - if (!followersResponse.IsOK()) Result.Fail("", (InstaUserList) null); + if (!followersResponse.IsOK()) Result.Fail("", (InstaUserList)null); followers.AddRange(followersResponse.Items.Select(ConvertersFabric.GetUserConverter).Select(converter => converter.Convert())); if (!followersResponse.IsBigList) return Result.Success(followers); var pages = 1; @@ -229,9 +230,11 @@ public async Task> GetUserFollowersAsync(string username, } return Result.Success(followers); } - catch (Exception exception) { - return Result.Fail(exception.Message, (InstaUserList) null); + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaUserList)null); } + } private async Task> GetUserFollowersWithMaxIdAsync(string username, string maxId) @@ -248,20 +251,22 @@ private async Task> GetUserFollowersWithMaxIdAsy if (response.StatusCode == HttpStatusCode.OK) { var followersResponse = JsonConvert.DeserializeObject(json); - if (!followersResponse.IsOK()) Result.Fail("", (InstaFollowersResponse) null); + if (!followersResponse.IsOK()) Result.Fail("", (InstaFollowersResponse)null); return Result.Success(followersResponse); } - return Result.Fail("", (InstaFollowersResponse) null); + return Result.Fail("", (InstaFollowersResponse)null); } - catch (Exception exception) { - return Result.Fail(exception.Message, (InstaFollowersResponse) null); + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaFollowersResponse)null); } + } public async Task> GetTagFeedAsync(string tag, int maxPages = 0) { ValidateUser(); - if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); + ValidateLoggedIn(); var userFeedUri = UriCreator.GetTagFeedUri(tag); var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); var response = await _httpClient.SendAsync(request); @@ -280,17 +285,17 @@ public async Task> GetTagFeedAsync(string tag, int maxPa } return Result.Success(mediaList); } - return Result.Fail("", (InstaMediaList) null); + return Result.Fail("", (InstaMediaList)null); } public async Task> GetTagFeedWithMaxIdAsync(string tag, string nextId) { ValidateUser(); + ValidateLoggedIn(); try { - ValidateLoggedIn(); var instaUri = UriCreator.GetTagFeedUri(tag); - instaUri = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}.Uri; + instaUri = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }.Uri; var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); @@ -299,13 +304,14 @@ public async Task> GetTagFeedWithMaxIdAsync(stri var feedResponse = JsonConvert.DeserializeObject(json); return Result.Success(feedResponse); } - return Result.Fail("", (InstaMediaListResponse) null); + return Result.Fail("", (InstaMediaListResponse)null); } - catch (Exception exception) { - return Result.Fail(exception.Message, (InstaMediaListResponse) null); + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaMediaListResponse)null); } - } + } public async Task> GetUserMediaAsync(string username, int maxPages = 0) { ValidateUser(); @@ -331,14 +337,14 @@ public async Task> GetUserMediaAsync(string username, in } var badRequest = JsonConvert.DeserializeObject(json); _logger.Write(badRequest.Message); - return Result.Fail(badRequest.Message, (InstaMediaList) null); + return Result.Fail(badRequest.Message, (InstaMediaList)null); } public async Task> GetUserFeedWithMaxIdAsync(string maxId) { Uri instaUri; if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search user URI"); - var userUriBuilder = new UriBuilder(instaUri) {Query = $"max_id={maxId}"}; + var userUriBuilder = new UriBuilder(instaUri) { Query = $"max_id={maxId}" }; var request = new HttpRequestMessage(HttpMethod.Get, userUriBuilder.Uri); request.Headers.Clear(); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_PHONE_ID, _requestMessage.phone_id)); @@ -351,7 +357,7 @@ public async Task> GetUserFeedWithMaxIdAsync(string m var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); return Result.Success(feedResponse); } - return Result.Fail("", (InstaFeedResponse) null); + return Result.Fail("", (InstaFeedResponse)null); } private async Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId) @@ -365,7 +371,7 @@ private async Task> GetUserMediaListWithMaxIdAsy var mediaResponse = JsonConvert.DeserializeObject(json); return Result.Success(mediaResponse); } - return Result.Fail("", (InstaMediaListResponse) null); + return Result.Fail("", (InstaMediaListResponse)null); } public async Task> LoginAsync() @@ -374,18 +380,17 @@ public async Task> LoginAsync() ValidateRequestMessage(); try { - _httpClient.DefaultRequestHeaders.Add(InstaApiConstants.HEADER_USER_AGENT, InstaApiConstants.USER_AGENT); var csrftoken = string.Empty; var firstResponse = await _httpClient.GetAsync(_httpClient.BaseAddress); var cookies = _httpHandler.CookieContainer.GetCookies(_httpClient.BaseAddress); foreach (Cookie cookie in cookies) if (cookie.Name == InstaApiConstants.CSRFTOKEN) csrftoken = cookie.Value; _user.CsrfToken = csrftoken; - var instaUri = UriCreator.GetLogintUri(); + var instaUri = UriCreator.GetLoginUri(); var signature = $"{_requestMessage.GenerateSignature()}.{_requestMessage.GetMessageString()}"; var fields = new Dictionary { - {InstaApiConstants.HEADER_IG_SIGNATURE, signature}, - {InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION} + { InstaApiConstants.HEADER_IG_SIGNATURE, signature}, + { InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION } }; var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); request.Content = new FormUrlEncodedContent(fields); @@ -410,9 +415,39 @@ public async Task> LoginAsync() return Result.Fail(loginInfo.Message, false); } } - catch (Exception exception) { + catch (Exception exception) + { + return Result.Fail(exception.Message, false); + } + + } + public async Task> LogoutAsync() + { + ValidateUser(); + ValidateLoggedIn(); + try + { + var instaUri = UriCreator.GetLogoutUri(); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); + var response = await _httpClient.SendAsync(request); + if (response.StatusCode == HttpStatusCode.OK) + { + var loginInfo = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + IsUserAuthenticated = loginInfo.Status == "ok"; + return Result.Success(true); + } + else + { + var loginInfo = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + _logger.Write(loginInfo.Message); + return Result.Fail(loginInfo.Message, false); + } + } + catch (Exception exception) + { return Result.Fail(exception.Message, false); } + } #endregion @@ -428,7 +463,6 @@ private void ValidateLoggedIn() { if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); } - private void ValidateRequestMessage() { if ((_requestMessage == null) || _requestMessage.IsEmpty()) throw new ArgumentException("API request message null or empty"); diff --git a/InstaSharper/API/InstaApiConstants.cs b/InstaSharper/API/InstaApiConstants.cs index 6fb84b58..d6bac752 100644 --- a/InstaSharper/API/InstaApiConstants.cs +++ b/InstaSharper/API/InstaApiConstants.cs @@ -18,6 +18,7 @@ public static class InstaApiConstants public const string GET_USER = API_SUFFIX + "/v1/accounts/login/"; public const string SEARCH_USERS = API_SUFFIX + "/v1/users/search"; public const string ACCOUNTS_LOGIN = API_SUFFIX + "/v1/accounts/login/"; + public const string ACCOUNTS_LOGOUT = API_SUFFIX + "/v1/accounts/logout/"; public const string TIMELINEFEED = API_SUFFIX + "/v1/feed/timeline/"; public const string USEREFEED = API_SUFFIX + "/v1/feed/user/"; public const string GET_MEDIA = API_SUFFIX + "/v1/media/{0}/info/"; diff --git a/InstaSharper/Helpers/UriCreator.cs b/InstaSharper/Helpers/UriCreator.cs index 5ffbc1db..470496f2 100644 --- a/InstaSharper/Helpers/UriCreator.cs +++ b/InstaSharper/Helpers/UriCreator.cs @@ -17,7 +17,7 @@ public static Uri GetUserUri(string username) { Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.SEARCH_USERS, out instaUri)) throw new Exception("Cant create search user URI"); - var userUriBuilder = new UriBuilder(instaUri) {Query = $"q={username}"}; + var userUriBuilder = new UriBuilder(instaUri) { Query = $"q={username}" }; return userUriBuilder.Uri; } @@ -35,7 +35,7 @@ public static Uri GetUserMediaListUri(string userPk) return instaUri; } - public static Uri GetLogintUri() + public static Uri GetLoginUri() { Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.ACCOUNTS_LOGIN, out instaUri)) throw new Exception("Cant create URI for user login"); @@ -46,7 +46,7 @@ public static Uri GetTimelineWithMaxIdUri(string nextId) { Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search URI for timeline"); - var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}; + var uriBuilder = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }; return uriBuilder.Uri; } @@ -54,7 +54,7 @@ public static Uri GetMediaListWithMaxIdUri(string userPk, string nextId) { Uri instaUri; if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.USEREFEED + userPk + "/", out instaUri)) throw new Exception("Cant create URI for media list"); - var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}; + var uriBuilder = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }; return uriBuilder.Uri; } @@ -70,7 +70,7 @@ internal static Uri GetUserFollowersUri(string userPk, string rankToken, string Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_FOLLOWERS, userPk, rankToken), out instaUri)) throw new Exception("Cant create URI for user followers"); if (string.IsNullOrEmpty(maxId)) return instaUri; - var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={maxId}"}; + var uriBuilder = new UriBuilder(instaUri) { Query = $"max_id={maxId}" }; return uriBuilder.Uri; } @@ -80,5 +80,11 @@ public static Uri GetTagFeedUri(string tag) if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_TAG_FEED, tag), out instaUri)) throw new Exception("Cant create URI for discover tag feed"); return instaUri; } + public static Uri GetLogoutUri() + { + Uri instaUri; + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.ACCOUNTS_LOGOUT, out instaUri)) throw new Exception("Cant create URI for user logout"); + return instaUri; + } } } \ No newline at end of file From 892a28d3e925c019fa891576be498627d746b177 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Fri, 2 Dec 2016 19:54:24 +0300 Subject: [PATCH 12/23] readme update --- README.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8c9e4853..5a2a254f 100644 --- a/README.md +++ b/README.md @@ -13,22 +13,26 @@ This project intends to provide all the features available in the Instagram API * Please note that this project is still in design and development phase; the libraries may suffer major changes even at the interface level, so don't rely (yet) in this software for production uses. * -## API Support +## Cross-platform by design +Build with dotnet core. Can be used on Mac, Linux, Windows. + +## Easy to install +Use library as dll, reference from nuget or clone source code. + +##Features -Currently the library supports following coverage of the following Instagram APIs: +Currently the library supports following coverage of the following Instagram APIs: * Login * Logout * Get user timeline feed - * Get user media + * Get current logged in user media + * Get user media by username * Get media by its id * Get tag feed + * Get user by its user name + * Get current user - -## Cross-platform by design -Build with dotnet core. Can be used on Mac, Linux, Windows. - -## Easy to install -Use library as dll, reference from nuget or clone source code. +######for more details please check [Project roadmap](https://github.com/a-legotin/InstaSharper/wiki/Project-roadmap/_edit) ## Easy to use #### Use builder to get Insta API instance: From abf139108f23f96eedb634ecacea9beb2daa5821 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Fri, 2 Dec 2016 21:43:41 +0300 Subject: [PATCH 13/23] improved tests and followers retrieval --- InstaSharper.Tests/Tests/AuthTest.cs | 16 +++--- InstaSharper.Tests/Tests/BaseInstaApiTest.cs | 31 +++++++++++ InstaSharper.Tests/Tests/FeedTest.cs | 4 +- InstaSharper.Tests/Tests/FollowersTest.cs | 54 +++++++++++++++++++ InstaSharper.Tests/Tests/MediaTest.cs | 4 +- .../{InstaApiTest.cs => UserInfoTest.cs} | 47 ++-------------- InstaSharper.Tests/Utils/TestHelpers.cs | 7 ++- InstaSharper/API/InstaApi.cs | 21 ++++---- InstaSharper/Helpers/UriCreator.cs | 1 + 9 files changed, 114 insertions(+), 71 deletions(-) create mode 100644 InstaSharper.Tests/Tests/BaseInstaApiTest.cs create mode 100644 InstaSharper.Tests/Tests/FollowersTest.cs rename InstaSharper.Tests/Tests/{InstaApiTest.cs => UserInfoTest.cs} (51%) diff --git a/InstaSharper.Tests/Tests/AuthTest.cs b/InstaSharper.Tests/Tests/AuthTest.cs index f45405bc..0408eba4 100644 --- a/InstaSharper.Tests/Tests/AuthTest.cs +++ b/InstaSharper.Tests/Tests/AuthTest.cs @@ -9,9 +9,6 @@ namespace InstaSharper.Tests.Tests { public class AuthTest : IDisposable { - private readonly ITestOutputHelper _output; - private readonly IInstaApi _apiInstance; - public AuthTest(ITestOutputHelper output) { _output = output; @@ -24,6 +21,13 @@ public AuthTest(ITestOutputHelper output) }); } + public void Dispose() + { + _apiInstance.LogoutAsync(); + } + + private readonly ITestOutputHelper _output; + private readonly IInstaApi _apiInstance; [Fact] @@ -46,16 +50,10 @@ public async void UserLoginFailTest() [Fact] public async void UserLoginSuccessTest() { - Assert.False(_apiInstance.IsUserAuthenticated); var loginResult = await _apiInstance.LoginAsync(); Assert.True(loginResult.Succeeded); Assert.True(_apiInstance.IsUserAuthenticated); } - - public void Dispose() - { - _apiInstance.LogoutAsync(); - } } } \ No newline at end of file diff --git a/InstaSharper.Tests/Tests/BaseInstaApiTest.cs b/InstaSharper.Tests/Tests/BaseInstaApiTest.cs new file mode 100644 index 00000000..c8820ba6 --- /dev/null +++ b/InstaSharper.Tests/Tests/BaseInstaApiTest.cs @@ -0,0 +1,31 @@ +using System; +using InstaSharper.API; +using InstaSharper.Classes; +using InstaSharper.Tests.Utils; +using Xunit.Abstractions; + +namespace InstaSharper.Tests.Tests +{ + public class BaseInstaApiTest : IDisposable + { + private readonly IInstaApi _apiInstance; + private readonly ITestOutputHelper _output; + + public BaseInstaApiTest(ITestOutputHelper output) + { + _output = output; + var username = "alex_codegarage"; + var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); + _apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = username, + Password = password + }); + } + + public void Dispose() + { + _apiInstance.LogoutAsync(); + } + } +} \ No newline at end of file diff --git a/InstaSharper.Tests/Tests/FeedTest.cs b/InstaSharper.Tests/Tests/FeedTest.cs index f2c7637b..0477abab 100644 --- a/InstaSharper.Tests/Tests/FeedTest.cs +++ b/InstaSharper.Tests/Tests/FeedTest.cs @@ -30,7 +30,7 @@ public async void GetTagFeedTest(string tag) Password = _password }); //act - if (!await TestHelpers.Login(apiInstance, _output)) return; + if (!TestHelpers.Login(apiInstance, _output)) return; var result = await apiInstance.GetTagFeedAsync(tag); var tagFeed = result.Value; //assert @@ -49,7 +49,7 @@ public async void GetUserFeedTest() Password = _password }); //act - if (!await TestHelpers.Login(apiInstance, _output)) return; + if (!TestHelpers.Login(apiInstance, _output)) return; var getFeedResult = await apiInstance.GetUserFeedAsync(5); var feed = getFeedResult.Value; //assert diff --git a/InstaSharper.Tests/Tests/FollowersTest.cs b/InstaSharper.Tests/Tests/FollowersTest.cs new file mode 100644 index 00000000..e90fb130 --- /dev/null +++ b/InstaSharper.Tests/Tests/FollowersTest.cs @@ -0,0 +1,54 @@ +using System; +using InstaSharper.API; +using InstaSharper.Classes; +using InstaSharper.Tests.Utils; +using Xunit; +using Xunit.Abstractions; + +namespace InstaSharper.Tests.Tests +{ + public class FollowersTest : IDisposable + { + public FollowersTest(ITestOutputHelper output) + { + _output = output; + var username = "alex_codegarage"; + var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); + _apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = username, + Password = password + }); + TestHelpers.Login(_apiInstance, _output); + } + + public void Dispose() + { + _apiInstance.LogoutAsync(); + } + + private readonly ITestOutputHelper _output; + private readonly IInstaApi _apiInstance; + + [Theory] + [InlineData("discovery")] + public async void GetUserFollowersTest(string username) + { + var result = await _apiInstance.GetUserFollowersAsync(username, 10); + var followers = result.Value; + //assert + Assert.True(result.Succeeded); + Assert.NotNull(followers); + } + + [Fact] + public async void GetCurrentUserFollwersTest() + { + var result = await _apiInstance.GetCurrentUserFollowersAsync(); + var followers = result.Value; + //assert + Assert.True(result.Succeeded); + Assert.NotNull(followers); + } + } +} \ No newline at end of file diff --git a/InstaSharper.Tests/Tests/MediaTest.cs b/InstaSharper.Tests/Tests/MediaTest.cs index 5d6d9780..8149125c 100644 --- a/InstaSharper.Tests/Tests/MediaTest.cs +++ b/InstaSharper.Tests/Tests/MediaTest.cs @@ -30,7 +30,7 @@ public async void GetMediaByCodeTest(string mediaId) }); //act output.WriteLine($"Trying to login as user: {username}"); - if (!await TestHelpers.Login(apiInstance, output)) return; + if (!TestHelpers.Login(apiInstance, output)) return; output.WriteLine($"Getting media by ID: {mediaId}"); var media = await apiInstance.GetMediaByCodeAsync(mediaId); //assert @@ -54,7 +54,7 @@ public async void GetUserMediaListTest(string userToFetch) var pages = random.Next(1, 10); //act output.WriteLine($"Trying to login as user: {username}"); - if (!await TestHelpers.Login(apiInstance, output)) return; + if (!TestHelpers.Login(apiInstance, output)) return; output.WriteLine($"Getting posts of user: {userToFetch}"); var posts = await apiInstance.GetUserMediaAsync(userToFetch, pages); diff --git a/InstaSharper.Tests/Tests/InstaApiTest.cs b/InstaSharper.Tests/Tests/UserInfoTest.cs similarity index 51% rename from InstaSharper.Tests/Tests/InstaApiTest.cs rename to InstaSharper.Tests/Tests/UserInfoTest.cs index 3aaf2da9..06415e6b 100644 --- a/InstaSharper.Tests/Tests/InstaApiTest.cs +++ b/InstaSharper.Tests/Tests/UserInfoTest.cs @@ -6,9 +6,9 @@ namespace InstaSharper.Tests.Tests { - public class InstaApiTest + public class UserInfoTest { - public InstaApiTest(ITestOutputHelper output) + public UserInfoTest(ITestOutputHelper output) { _output = output; } @@ -17,45 +17,6 @@ public InstaApiTest(ITestOutputHelper output) private readonly string _username = "alex_codegarage"; private readonly string _password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - [Theory] - [InlineData("discovery")] - public async void GetUserFollowersTest(string username) - { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - if (!await TestHelpers.Login(apiInstance, _output)) return; - var result = await apiInstance.GetUserFollowersAsync(username, 10); - var followers = result.Value; - //assert - Assert.True(result.Succeeded); - Assert.NotNull(followers); - } - - [Fact] - public async void GetCurrentUserFollwersTest() - { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - if (!await TestHelpers.Login(apiInstance, _output)) return; - var result = await apiInstance.GetCurrentUserFollowersAsync(); - var followers = result.Value; - //assert - Assert.True(result.Succeeded); - Assert.NotNull(followers); - } - [Fact] public async void GetCurrentUserTest() { @@ -67,7 +28,7 @@ public async void GetCurrentUserTest() Password = _password }); //act - if (!await TestHelpers.Login(apiInstance, _output)) return; + if (!TestHelpers.Login(apiInstance, _output)) return; var getUserResult = await apiInstance.GetCurrentUserAsync(); var user = getUserResult.Value; //assert @@ -87,7 +48,7 @@ public async void GetUserTest() Password = _password }); //act - if (!await TestHelpers.Login(apiInstance, _output)) return; + if (!TestHelpers.Login(apiInstance, _output)) return; var getUserResult = await apiInstance.GetUserAsync(_username); var user = getUserResult.Value; //assert diff --git a/InstaSharper.Tests/Utils/TestHelpers.cs b/InstaSharper.Tests/Utils/TestHelpers.cs index 32b3ea3d..e38f6448 100644 --- a/InstaSharper.Tests/Utils/TestHelpers.cs +++ b/InstaSharper.Tests/Utils/TestHelpers.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using InstaSharper.API; +using InstaSharper.API; using InstaSharper.API.Builder; using InstaSharper.Classes; using Xunit.Abstractions; @@ -26,9 +25,9 @@ public static IInstaApi GetDefaultInstaApiInstance(UserSessionData user) return apiInstance; } - public static async Task Login(IInstaApi apiInstance, ITestOutputHelper output) + public static bool Login(IInstaApi apiInstance, ITestOutputHelper output) { - var loginResult = await apiInstance.LoginAsync(); + var loginResult = apiInstance.Login(); if (!loginResult.Succeeded) { output.WriteLine($"Can't login: {loginResult.Message}"); diff --git a/InstaSharper/API/InstaApi.cs b/InstaSharper/API/InstaApi.cs index 7da48bfe..1fdc7f0a 100644 --- a/InstaSharper/API/InstaApi.cs +++ b/InstaSharper/API/InstaApi.cs @@ -189,7 +189,7 @@ public async Task> GetUserFeedAsync(int maxPages = 0) while (feedResponse.MoreAvailable && (feed.Pages < maxPages)) { var nextFeed = await GetUserFeedWithMaxIdAsync(feedResponse.NextMaxId); - if (!nextFeed.Succeeded) continue; + if (!nextFeed.Succeeded) break; feed.Items.AddRange(nextFeed.Value.Items.Select(ConvertersFabric.GetSingleMediaConverter).Select(conv => conv.Convert())); feed.Pages++; } @@ -208,7 +208,7 @@ public async Task> GetUserFollowersAsync(string username, ValidateLoggedIn(); try { - if (maxPages == 0) maxPages = Int32.MaxValue; + if (maxPages == 0) maxPages = int.MaxValue; var user = await GetUserAsync(username); var userFeedUri = UriCreator.GetUserFollowersUri(user.Value.Pk, _user.RankToken); var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); @@ -223,8 +223,9 @@ public async Task> GetUserFollowersAsync(string username, var pages = 1; while (!string.IsNullOrEmpty(followersResponse.NextMaxId) && (pages < maxPages)) { - var nextFollowers = await GetUserFollowersWithMaxIdAsync(username, followersResponse.NextMaxId); - if (!nextFollowers.Succeeded) continue; + var nextFollowers = Result.Success(followersResponse); + nextFollowers = await GetUserFollowersWithMaxIdAsync(username, nextFollowers.Value.NextMaxId); + if (!nextFollowers.Succeeded) break; followers.AddRange(nextFollowers.Value.Items.Select(ConvertersFabric.GetUserConverter).Select(converter => converter.Convert())); pages++; } @@ -234,7 +235,6 @@ public async Task> GetUserFollowersAsync(string username, { return Result.Fail(exception.Message, (InstaUserList)null); } - } private async Task> GetUserFollowersWithMaxIdAsync(string username, string maxId) @@ -260,7 +260,6 @@ private async Task> GetUserFollowersWithMaxIdAsy { return Result.Fail(exception.Message, (InstaFollowersResponse)null); } - } public async Task> GetTagFeedAsync(string tag, int maxPages = 0) @@ -310,8 +309,8 @@ public async Task> GetTagFeedWithMaxIdAsync(stri { return Result.Fail(exception.Message, (InstaMediaListResponse)null); } - } + public async Task> GetUserMediaAsync(string username, int maxPages = 0) { ValidateUser(); @@ -389,8 +388,8 @@ public async Task> LoginAsync() var signature = $"{_requestMessage.GenerateSignature()}.{_requestMessage.GetMessageString()}"; var fields = new Dictionary { - { InstaApiConstants.HEADER_IG_SIGNATURE, signature}, - { InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION } + {InstaApiConstants.HEADER_IG_SIGNATURE, signature}, + {InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION} }; var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); request.Content = new FormUrlEncodedContent(fields); @@ -419,8 +418,8 @@ public async Task> LoginAsync() { return Result.Fail(exception.Message, false); } - } + public async Task> LogoutAsync() { ValidateUser(); @@ -447,7 +446,6 @@ public async Task> LogoutAsync() { return Result.Fail(exception.Message, false); } - } #endregion @@ -463,6 +461,7 @@ private void ValidateLoggedIn() { if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); } + private void ValidateRequestMessage() { if ((_requestMessage == null) || _requestMessage.IsEmpty()) throw new ArgumentException("API request message null or empty"); diff --git a/InstaSharper/Helpers/UriCreator.cs b/InstaSharper/Helpers/UriCreator.cs index 470496f2..d4b3c425 100644 --- a/InstaSharper/Helpers/UriCreator.cs +++ b/InstaSharper/Helpers/UriCreator.cs @@ -80,6 +80,7 @@ public static Uri GetTagFeedUri(string tag) if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_TAG_FEED, tag), out instaUri)) throw new Exception("Cant create URI for discover tag feed"); return instaUri; } + public static Uri GetLogoutUri() { Uri instaUri; From 2af2dca11241bbe9888614248ff03dd5ff66fe4d Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Sun, 4 Dec 2016 14:48:32 +0300 Subject: [PATCH 14/23] added examples and some cleanup of API --- InstaSharper.Examples/App.config | 7 ++ .../InstaSharper.Examples.csproj | 63 ++++++++++++ .../InstaSharper.Examples.sln | 22 +++++ InstaSharper.Examples/InstaSharperExamples.cs | 78 +++++++++++++++ .../Properties/AssemblyInfo.cs | 39 ++++++++ InstaSharper/API/IInstaApi.cs | 27 ++++- InstaSharper/API/InstaApi.cs | 99 +++++++++++-------- InstaSharper/API/InstaApiConstants.cs | 7 +- InstaSharper/Classes/Result.cs | 3 + InstaSharper/Helpers/UriCreator.cs | 10 +- InstaSharper/project.json | 3 + 11 files changed, 306 insertions(+), 52 deletions(-) create mode 100644 InstaSharper.Examples/App.config create mode 100644 InstaSharper.Examples/InstaSharper.Examples.csproj create mode 100644 InstaSharper.Examples/InstaSharper.Examples.sln create mode 100644 InstaSharper.Examples/InstaSharperExamples.cs create mode 100644 InstaSharper.Examples/Properties/AssemblyInfo.cs diff --git a/InstaSharper.Examples/App.config b/InstaSharper.Examples/App.config new file mode 100644 index 00000000..51fffc74 --- /dev/null +++ b/InstaSharper.Examples/App.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/InstaSharper.Examples/InstaSharper.Examples.csproj b/InstaSharper.Examples/InstaSharper.Examples.csproj new file mode 100644 index 00000000..efe30f26 --- /dev/null +++ b/InstaSharper.Examples/InstaSharper.Examples.csproj @@ -0,0 +1,63 @@ + + + + + Debug + AnyCPU + {620D3DB5-5636-4A54-A7D7-600C6518C20E} + Exe + Properties + InstaSharper.Examples + InstaSharper.Examples + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\InstaSharper\bin\Debug\net452\InstaSharper.dll + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/InstaSharper.Examples/InstaSharper.Examples.sln b/InstaSharper.Examples/InstaSharper.Examples.sln new file mode 100644 index 00000000..fe06e8f5 --- /dev/null +++ b/InstaSharper.Examples/InstaSharper.Examples.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InstaSharper.Examples", "InstaSharper.Examples.csproj", "{620D3DB5-5636-4A54-A7D7-600C6518C20E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {620D3DB5-5636-4A54-A7D7-600C6518C20E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {620D3DB5-5636-4A54-A7D7-600C6518C20E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {620D3DB5-5636-4A54-A7D7-600C6518C20E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {620D3DB5-5636-4A54-A7D7-600C6518C20E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/InstaSharper.Examples/InstaSharperExamples.cs b/InstaSharper.Examples/InstaSharperExamples.cs new file mode 100644 index 00000000..f42723c6 --- /dev/null +++ b/InstaSharper.Examples/InstaSharperExamples.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using InstaSharper.API; +using InstaSharper.API.Builder; +using InstaSharper.Classes; + +namespace InstaSharper.Examples +{ + class InstaSharperExamples + { + private static IInstaApi _instaApi; + static void Main(string[] args) + { + // create user session data and provide login details + var userSession = new UserSessionData + { + UserName = "alex_codegarage", + Password = "3591957P@R" + }; + // create new InstaApi instance using Builder + _instaApi = new InstaApiBuilder() + .SetUser(userSession) + .Build(); + // login + var logInResult = _instaApi.Login(); + if (!logInResult.Succeeded) + { + Console.WriteLine($"Unable to login: {logInResult.Message}"); + } + else + { + // get currently logged in user + var currentUser = _instaApi.GetCurrentUser().Value; + Console.WriteLine($"Logged in: username - {currentUser.UserName}, full name - {currentUser.FullName}"); + // get followers + var followers = _instaApi.GetUserFollowersAsync(currentUser.UserName, 5).Result.Value; + Console.WriteLine($"There are (is) {followers.Count} followers for user {currentUser.UserName}"); + // get user's media + var currentUserMedia = _instaApi.GetUserMedia(currentUser.UserName, 5); + if (currentUserMedia.Succeeded) + { + Console.WriteLine($"There are (is) {currentUserMedia.Value.Count} media for user {currentUser.UserName}"); + foreach (var media in currentUserMedia.Value) + { + Console.WriteLine($"Media: {media.Caption.Text}, {media.Code}, likes: {media.LikesCount}, image link: {media.Images.LastOrDefault()?.Url}"); + } + } + + //get user feed, first 5 pages + var userFeed = _instaApi.GetUserFeed(5); + if (userFeed.Succeeded) + { + Console.WriteLine($"There are {userFeed.Value.Items.Count} feed items in {userFeed.Value.Pages} pages for user {currentUser.UserName}"); + foreach (var media in userFeed.Value.Items) + { + Console.WriteLine($"Feed item - code:{media.Code}, likes: {media.LikesCount}"); + } + } + // get tag feed, first 5 pages + var tagFeed = _instaApi.GetTagFeed("gm", 5); + if (userFeed.Succeeded) + { + Console.WriteLine($"There are {tagFeed.Value.Count} tag feed items in {tagFeed.Value.Pages} pages for user {currentUser.UserName}"); + foreach (var media in tagFeed.Value) + { + Console.WriteLine($"Tag feed item - code: {media.Code}, likes: {media.LikesCount}"); + } + } + var logoutResult = _instaApi.Logout(); + if (logoutResult.Value) Console.WriteLine("Logout succeed"); + } + Console.ReadKey(); + } + } +} diff --git a/InstaSharper.Examples/Properties/AssemblyInfo.cs b/InstaSharper.Examples/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..b094a7c8 --- /dev/null +++ b/InstaSharper.Examples/Properties/AssemblyInfo.cs @@ -0,0 +1,39 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. + +[assembly: AssemblyTitle("InstaSharper.Examples")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("InstaSharper.Examples")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. + +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM + +[assembly: Guid("620d3db5-5636-4a54-a7d7-600c6518c20e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/InstaSharper/API/IInstaApi.cs b/InstaSharper/API/IInstaApi.cs index 5dec5fab..7b8129a9 100644 --- a/InstaSharper/API/IInstaApi.cs +++ b/InstaSharper/API/IInstaApi.cs @@ -6,7 +6,14 @@ namespace InstaSharper.API { public interface IInstaApi { + #region Properties + bool IsUserAuthenticated { get; } + + #endregion + + #region Sync Members + IResult GetUser(string username); Task> GetUserAsync(string username); IResult GetUserMedia(string username, int maxPages = 0); @@ -14,16 +21,28 @@ public interface IInstaApi IResult GetMediaByCode(string postCode); Task> GetMediaByCodeAsync(string postCode); IResult Login(); + IResult Logout(); + + IResult GetCurrentUser(); + IResult GetCurentUserFollowers(int maxPages = 0); + IResult GetUserFollowers(string username, int maxPages = 0); + + IResult GetTagFeed(string tag, int maxPages = 0); + + #endregion + + #region Async Members + Task> LoginAsync(); Task> LogoutAsync(); IResult GetUserFeed(int maxPages = 0); Task> GetUserFeedAsync(int maxPages = 0); Task> GetCurrentUserAsync(); - IResult GetCurrentUser(); - IResult GetCurentUserFollowers(int maxPages = 0); - Task> GetCurrentUserFollowersAsync(int maxPages = 0); - IResult GetTagFeed(string tag, int maxPages = 0); + Task> GetTagFeedAsync(string tag, int maxPages = 0); Task> GetUserFollowersAsync(string username, int maxPages = 0); + Task> GetCurrentUserFollowersAsync(int maxPages = 0); + + #endregion } } \ No newline at end of file diff --git a/InstaSharper/API/InstaApi.cs b/InstaSharper/API/InstaApi.cs index 1fdc7f0a..8da995f4 100644 --- a/InstaSharper/API/InstaApi.cs +++ b/InstaSharper/API/InstaApi.cs @@ -71,6 +71,16 @@ public IResult Login() return LoginAsync().Result; } + public IResult Logout() + { + return LogoutAsync().Result; + } + + public IResult GetUserFollowers(string username, int maxPages = 0) + { + return GetUserFollowersAsync(username, maxPages).Result; + } + public IResult GetTagFeed(string tag, int maxPages = 0) { return GetTagFeedAsync(tag, maxPages).Result; @@ -104,9 +114,7 @@ public async Task> GetMediaByCodeAsync(string postCode) var converter = ConvertersFabric.GetSingleMediaConverter(mediaResponse.Items.FirstOrDefault()); return Result.Success(converter.Convert()); } - var badRequest = JsonConvert.DeserializeObject(json); - _logger.Write(badRequest.Message); - return Result.Fail(badRequest.Message, (InstaMedia)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMedia)null); } public async Task> GetUserAsync(string username) @@ -132,9 +140,7 @@ public async Task> GetUserAsync(string username) var converter = ConvertersFabric.GetUserConverter(user); return Result.Success(converter.Convert()); } - var badRequest = JsonConvert.DeserializeObject(json); - _logger.Write(badRequest.Message); - return Result.Fail(badRequest.Message, (InstaUser)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUser)null); } public IResult GetCurrentUser() @@ -169,7 +175,7 @@ public async Task> GetCurrentUserAsync() return Result.Success(userConverted); } - return Result.Fail("", (InstaUser)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUser)null); } public async Task> GetUserFeedAsync(int maxPages = 0) @@ -181,15 +187,17 @@ public async Task> GetUserFeedAsync(int maxPages = 0) var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); var feed = new InstaFeed(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaFeed)null); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeed)null); var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); var converter = ConvertersFabric.GetFeedConverter(feedResponse); var feedConverted = converter.Convert(); feed.Items.AddRange(feedConverted.Items); + var nextId = feedResponse.NextMaxId; while (feedResponse.MoreAvailable && (feed.Pages < maxPages)) { - var nextFeed = await GetUserFeedWithMaxIdAsync(feedResponse.NextMaxId); - if (!nextFeed.Succeeded) break; + var nextFeed = await GetUserFeedWithMaxIdAsync(nextId); + if (!nextFeed.Succeeded) Result.Success($"Not all pages was downloaded: {nextFeed.Message}", feed); + nextId = nextFeed.Value.NextMaxId; feed.Items.AddRange(nextFeed.Value.Items.Select(ConvertersFabric.GetSingleMediaConverter).Select(conv => conv.Convert())); feed.Pages++; } @@ -217,7 +225,7 @@ public async Task> GetUserFollowersAsync(string username, var followers = new InstaUserList(); if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaUserList)null); var followersResponse = JsonConvert.DeserializeObject(json); - if (!followersResponse.IsOK()) Result.Fail("", (InstaUserList)null); + if (!followersResponse.IsOK()) Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUserList)null); followers.AddRange(followersResponse.Items.Select(ConvertersFabric.GetUserConverter).Select(converter => converter.Convert())); if (!followersResponse.IsBigList) return Result.Success(followers); var pages = 1; @@ -225,7 +233,7 @@ public async Task> GetUserFollowersAsync(string username, { var nextFollowers = Result.Success(followersResponse); nextFollowers = await GetUserFollowersWithMaxIdAsync(username, nextFollowers.Value.NextMaxId); - if (!nextFollowers.Succeeded) break; + if (!nextFollowers.Succeeded) Result.Success($"Not all pages was downloaded: {nextFollowers.Message}", followers); followers.AddRange(nextFollowers.Value.Items.Select(ConvertersFabric.GetUserConverter).Select(converter => converter.Convert())); pages++; } @@ -254,7 +262,7 @@ private async Task> GetUserFollowersWithMaxIdAsy if (!followersResponse.IsOK()) Result.Fail("", (InstaFollowersResponse)null); return Result.Success(followersResponse); } - return Result.Fail("", (InstaFollowersResponse)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFollowersResponse)null); } catch (Exception exception) { @@ -274,17 +282,20 @@ public async Task> GetTagFeedAsync(string tag, int maxPa { var feedResponse = JsonConvert.DeserializeObject(json); var converter = ConvertersFabric.GetMediaListConverter(feedResponse); - var mediaList = converter.Convert(); - while (feedResponse.MoreAvailable && (mediaList.Pages < maxPages)) + var tagFeed = converter.Convert(); + var nextId = feedResponse.NextMaxId; + while (feedResponse.MoreAvailable && (tagFeed.Pages < maxPages)) { - var nextMedia = await GetTagFeedWithMaxIdAsync(tag, feedResponse.NextMaxId); - if (!nextMedia.Succeeded) continue; - mediaList.AddRange(converter.Convert()); - mediaList.Pages++; + var nextMedia = await GetTagFeedWithMaxIdAsync(tag, nextId); + if (!nextMedia.Succeeded) Result.Success($"Not all pages was downloaded: {nextMedia.Message}", tagFeed); + nextId = nextMedia.Value.NextMaxId; + converter = ConvertersFabric.GetMediaListConverter(nextMedia.Value); + tagFeed.AddRange(converter.Convert()); + tagFeed.Pages++; } - return Result.Success(mediaList); + return Result.Success(tagFeed); } - return Result.Fail("", (InstaMediaList)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaList)null); } public async Task> GetTagFeedWithMaxIdAsync(string tag, string nextId) @@ -303,7 +314,7 @@ public async Task> GetTagFeedWithMaxIdAsync(stri var feedResponse = JsonConvert.DeserializeObject(json); return Result.Success(feedResponse); } - return Result.Fail("", (InstaMediaListResponse)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaListResponse)null); } catch (Exception exception) { @@ -325,18 +336,18 @@ public async Task> GetUserMediaAsync(string username, in var mediaResponse = JsonConvert.DeserializeObject(json); var converter = ConvertersFabric.GetMediaListConverter(mediaResponse); var mediaList = converter.Convert(); + var nextId = mediaResponse.NextMaxId; while (mediaResponse.MoreAvailable && (mediaList.Pages < maxPages)) { - var nextMedia = await GetUserMediaListWithMaxIdAsync(user.Pk, mediaResponse.NextMaxId); - if (!nextMedia.Succeeded) continue; + var nextMedia = await GetUserMediaListWithMaxIdAsync(user.Pk, nextId); + if (!nextMedia.Succeeded) Result.Success($"Not all pages was downloaded: {nextMedia.Message}", mediaList); + nextId = nextMedia.Value.NextMaxId; mediaList.AddRange(converter.Convert()); mediaList.Pages++; } return Result.Success(mediaList); } - var badRequest = JsonConvert.DeserializeObject(json); - _logger.Write(badRequest.Message); - return Result.Fail(badRequest.Message, (InstaMediaList)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaList)null); } public async Task> GetUserFeedWithMaxIdAsync(string maxId) @@ -344,19 +355,17 @@ public async Task> GetUserFeedWithMaxIdAsync(string m Uri instaUri; if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search user URI"); var userUriBuilder = new UriBuilder(instaUri) { Query = $"max_id={maxId}" }; - var request = new HttpRequestMessage(HttpMethod.Get, userUriBuilder.Uri); - request.Headers.Clear(); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUriBuilder.Uri, _deviceInfo); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_PHONE_ID, _requestMessage.phone_id)); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, InstaApiConstants.TIMEZONE_OFFSET.ToString())); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); - var feed = new InstaFeed(); if (response.StatusCode == HttpStatusCode.OK) { var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); return Result.Success(feedResponse); } - return Result.Fail("", (InstaFeedResponse)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeedResponse)null); } private async Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId) @@ -396,11 +405,11 @@ public async Task> LoginAsync() request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION); var response = await _httpClient.SendAsync(request); - + var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) { var loginInfo = - JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + JsonConvert.DeserializeObject(json); IsUserAuthenticated = (loginInfo.User != null) && (loginInfo.User.UserName == _user.UserName); var converter = ConvertersFabric.GetUserConverter(loginInfo.User); _user.LoggedInUder = converter.Convert(); @@ -409,7 +418,7 @@ public async Task> LoginAsync() } else { - var loginInfo = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + var loginInfo = GetBadStatusFromJsonString(json); _logger.Write(loginInfo.Message); return Result.Fail(loginInfo.Message, false); } @@ -429,17 +438,18 @@ public async Task> LogoutAsync() var instaUri = UriCreator.GetLogoutUri(); var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) { - var loginInfo = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - IsUserAuthenticated = loginInfo.Status == "ok"; + var logoutInfo = JsonConvert.DeserializeObject(json); + IsUserAuthenticated = logoutInfo.Status == "ok"; return Result.Success(true); } else { - var loginInfo = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - _logger.Write(loginInfo.Message); - return Result.Fail(loginInfo.Message, false); + var logoutInfo = GetBadStatusFromJsonString(json); + _logger.Write(logoutInfo.Message); + return Result.Fail(logoutInfo.Message, false); } } catch (Exception exception) @@ -467,6 +477,17 @@ private void ValidateRequestMessage() if ((_requestMessage == null) || _requestMessage.IsEmpty()) throw new ArgumentException("API request message null or empty"); } + private BadStatusResponse GetBadStatusFromJsonString(string json) + { + var badStatus = new BadStatusResponse(); + try { badStatus = JsonConvert.DeserializeObject(json); } + catch (Exception ex) + { + badStatus.Message = ex.Message; + } + return badStatus; + } + #endregion } } \ No newline at end of file diff --git a/InstaSharper/API/InstaApiConstants.cs b/InstaSharper/API/InstaApiConstants.cs index d6bac752..2c381bcf 100644 --- a/InstaSharper/API/InstaApiConstants.cs +++ b/InstaSharper/API/InstaApiConstants.cs @@ -1,6 +1,6 @@ namespace InstaSharper.API { - public static class InstaApiConstants + internal static class InstaApiConstants { public const string CURRENTUSER = API_SUFFIX + "/v1/accounts/current_user?edit=true"; public const string MAX_MEDIA_ID_POSTFIX = "/media/?max_id="; @@ -15,15 +15,14 @@ public static class InstaApiConstants public const string HEADER_XML_HTTP_REQUEST = "XMLHttpRequest"; public const string INSTAGRAM_URL = "https://i.instagram.com"; public const string API_SUFFIX = "/api"; - public const string GET_USER = API_SUFFIX + "/v1/accounts/login/"; public const string SEARCH_USERS = API_SUFFIX + "/v1/users/search"; public const string ACCOUNTS_LOGIN = API_SUFFIX + "/v1/accounts/login/"; public const string ACCOUNTS_LOGOUT = API_SUFFIX + "/v1/accounts/logout/"; - public const string TIMELINEFEED = API_SUFFIX + "/v1/feed/timeline/"; + public const string TIMELINEFEED = API_SUFFIX + "/v1/feed/timeline"; public const string USEREFEED = API_SUFFIX + "/v1/feed/user/"; public const string GET_MEDIA = API_SUFFIX + "/v1/media/{0}/info/"; public const string GET_USER_FOLLOWERS = API_SUFFIX + "/v1/friendships/{0}/followers/?rank_token={1}"; - public const string GET_TAG_FEED = API_SUFFIX + "/v1/feed/tag/{0}/"; + public const string GET_TAG_FEED = API_SUFFIX + "/v1/feed/tag/{0}"; public const string HEADER_USER_AGENT = "User-Agent"; public const string USER_AGENT = "Instagram 9.7.0 Android (23/6.0.1; 640dpi; 1440x2560; samsung; SM-G935F; hero2lte; samsungexynos8890; en_NZ)"; diff --git a/InstaSharper/Classes/Result.cs b/InstaSharper/Classes/Result.cs index d6a6fd2f..a6bf6109 100644 --- a/InstaSharper/Classes/Result.cs +++ b/InstaSharper/Classes/Result.cs @@ -7,6 +7,9 @@ public static class Result public static IResult Success(T resValue) => new Result(true, string.Empty, resValue); + public static IResult Success(string successMsg, T resValue) + => new Result(true, successMsg, resValue); + public static IResult Fail() => new Result(false, string.Empty, default(object)); diff --git a/InstaSharper/Helpers/UriCreator.cs b/InstaSharper/Helpers/UriCreator.cs index d4b3c425..7bb00472 100644 --- a/InstaSharper/Helpers/UriCreator.cs +++ b/InstaSharper/Helpers/UriCreator.cs @@ -3,7 +3,7 @@ namespace InstaSharper.Helpers { - public class UriCreator + internal class UriCreator { private static readonly Uri BaseInstagramUri = new Uri(InstaApiConstants.INSTAGRAM_URL); @@ -17,7 +17,7 @@ public static Uri GetUserUri(string username) { Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.SEARCH_USERS, out instaUri)) throw new Exception("Cant create search user URI"); - var userUriBuilder = new UriBuilder(instaUri) { Query = $"q={username}" }; + var userUriBuilder = new UriBuilder(instaUri) {Query = $"q={username}"}; return userUriBuilder.Uri; } @@ -46,7 +46,7 @@ public static Uri GetTimelineWithMaxIdUri(string nextId) { Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search URI for timeline"); - var uriBuilder = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }; + var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}; return uriBuilder.Uri; } @@ -54,7 +54,7 @@ public static Uri GetMediaListWithMaxIdUri(string userPk, string nextId) { Uri instaUri; if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.USEREFEED + userPk + "/", out instaUri)) throw new Exception("Cant create URI for media list"); - var uriBuilder = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }; + var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}; return uriBuilder.Uri; } @@ -70,7 +70,7 @@ internal static Uri GetUserFollowersUri(string userPk, string rankToken, string Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_FOLLOWERS, userPk, rankToken), out instaUri)) throw new Exception("Cant create URI for user followers"); if (string.IsNullOrEmpty(maxId)) return instaUri; - var uriBuilder = new UriBuilder(instaUri) { Query = $"max_id={maxId}" }; + var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={maxId}"}; return uriBuilder.Uri; } diff --git a/InstaSharper/project.json b/InstaSharper/project.json index 9408a848..e2cd5866 100644 --- a/InstaSharper/project.json +++ b/InstaSharper/project.json @@ -9,6 +9,9 @@ "frameworks": { "netstandard1.6": { "imports": "dnxcore50" + }, + "net452": { + } } } From 3e5675057d17db55e01a8919ab69d5729c113963 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Sun, 4 Dec 2016 18:51:10 +0300 Subject: [PATCH 15/23] ci build fix and tests --- .travis.yml | 2 +- InstaSharper.Examples/InstaSharperExamples.cs | 38 +++++-------- InstaSharper.Tests/Tests/AuthTest.cs | 31 +++++------ InstaSharper.Tests/Tests/BaseInstaApiTest.cs | 31 ----------- InstaSharper.Tests/Tests/FollowersTest.cs | 38 ++++++------- InstaSharper.Tests/Tests/MediaTest.cs | 44 +++++++-------- InstaSharper/API/InstaApi.cs | 54 +++++++++---------- appveyor.yml | 4 +- 8 files changed, 94 insertions(+), 148 deletions(-) delete mode 100644 InstaSharper.Tests/Tests/BaseInstaApiTest.cs diff --git a/.travis.yml b/.travis.yml index 13d544b3..ea0943ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,5 +14,5 @@ script: - dotnet --verbose build - cd ../InstaSharper.Tests - dotnet --verbose build - - dotnet --verbose test + - dotnet --verbose test -parallel none \ No newline at end of file diff --git a/InstaSharper.Examples/InstaSharperExamples.cs b/InstaSharper.Examples/InstaSharperExamples.cs index f42723c6..58cd2c7f 100644 --- a/InstaSharper.Examples/InstaSharperExamples.cs +++ b/InstaSharper.Examples/InstaSharperExamples.cs @@ -1,18 +1,16 @@ using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; using InstaSharper.API; using InstaSharper.API.Builder; using InstaSharper.Classes; namespace InstaSharper.Examples { - class InstaSharperExamples + internal class InstaSharperExamples { private static IInstaApi _instaApi; - static void Main(string[] args) + + private static void Main(string[] args) { // create user session data and provide login details var userSession = new UserSessionData @@ -26,10 +24,7 @@ static void Main(string[] args) .Build(); // login var logInResult = _instaApi.Login(); - if (!logInResult.Succeeded) - { - Console.WriteLine($"Unable to login: {logInResult.Message}"); - } + if (!logInResult.Succeeded) { Console.WriteLine($"Unable to login: {logInResult.Message}"); } else { // get currently logged in user @@ -37,37 +32,28 @@ static void Main(string[] args) Console.WriteLine($"Logged in: username - {currentUser.UserName}, full name - {currentUser.FullName}"); // get followers var followers = _instaApi.GetUserFollowersAsync(currentUser.UserName, 5).Result.Value; - Console.WriteLine($"There are (is) {followers.Count} followers for user {currentUser.UserName}"); + Console.WriteLine($"Count of followers [{currentUser.UserName}]:{followers.Count}"); // get user's media var currentUserMedia = _instaApi.GetUserMedia(currentUser.UserName, 5); if (currentUserMedia.Succeeded) { - Console.WriteLine($"There are (is) {currentUserMedia.Value.Count} media for user {currentUser.UserName}"); - foreach (var media in currentUserMedia.Value) - { - Console.WriteLine($"Media: {media.Caption.Text}, {media.Code}, likes: {media.LikesCount}, image link: {media.Images.LastOrDefault()?.Url}"); - } + Console.WriteLine($"Media count [{currentUser.UserName}]: {currentUserMedia.Value.Count}"); + foreach (var media in currentUserMedia.Value) Console.WriteLine($"Media [{currentUser.UserName}]: {media.Caption.Text}, {media.Code}, likes: {media.LikesCount}, image link: {media.Images.LastOrDefault()?.Url}"); } //get user feed, first 5 pages var userFeed = _instaApi.GetUserFeed(5); if (userFeed.Succeeded) { - Console.WriteLine($"There are {userFeed.Value.Items.Count} feed items in {userFeed.Value.Pages} pages for user {currentUser.UserName}"); - foreach (var media in userFeed.Value.Items) - { - Console.WriteLine($"Feed item - code:{media.Code}, likes: {media.LikesCount}"); - } + Console.WriteLine($"Feed items (in {userFeed.Value.Pages} pages) [{currentUser.UserName}]: {userFeed.Value.Items.Count}"); + foreach (var media in userFeed.Value.Items) Console.WriteLine($"Feed item - code:{media.Code}, likes: {media.LikesCount}"); } // get tag feed, first 5 pages var tagFeed = _instaApi.GetTagFeed("gm", 5); if (userFeed.Succeeded) { - Console.WriteLine($"There are {tagFeed.Value.Count} tag feed items in {tagFeed.Value.Pages} pages for user {currentUser.UserName}"); - foreach (var media in tagFeed.Value) - { - Console.WriteLine($"Tag feed item - code: {media.Code}, likes: {media.LikesCount}"); - } + Console.WriteLine($"Tag feed items (in {tagFeed.Value.Pages} pages) [{currentUser.UserName}]: {tagFeed.Value.Count}"); + foreach (var media in tagFeed.Value) Console.WriteLine($"Tag feed item - code: {media.Code}, likes: {media.LikesCount}"); } var logoutResult = _instaApi.Logout(); if (logoutResult.Value) Console.WriteLine("Logout succeed"); @@ -75,4 +61,4 @@ static void Main(string[] args) Console.ReadKey(); } } -} +} \ No newline at end of file diff --git a/InstaSharper.Tests/Tests/AuthTest.cs b/InstaSharper.Tests/Tests/AuthTest.cs index 0408eba4..45359d1c 100644 --- a/InstaSharper.Tests/Tests/AuthTest.cs +++ b/InstaSharper.Tests/Tests/AuthTest.cs @@ -1,5 +1,4 @@ using System; -using InstaSharper.API; using InstaSharper.Classes; using InstaSharper.Tests.Utils; using Xunit; @@ -7,28 +6,14 @@ namespace InstaSharper.Tests.Tests { - public class AuthTest : IDisposable + public class AuthTest { public AuthTest(ITestOutputHelper output) { _output = output; - var username = "alex_codegarage"; - var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - _apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = username, - Password = password - }); - } - - public void Dispose() - { - _apiInstance.LogoutAsync(); } private readonly ITestOutputHelper _output; - private readonly IInstaApi _apiInstance; - [Fact] public async void UserLoginFailTest() @@ -50,10 +35,18 @@ public async void UserLoginFailTest() [Fact] public async void UserLoginSuccessTest() { - Assert.False(_apiInstance.IsUserAuthenticated); - var loginResult = await _apiInstance.LoginAsync(); + var username = "alex_codegarage"; + var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); + var apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = username, + Password = password + }); + Assert.False(apiInstance.IsUserAuthenticated); + + var loginResult = await apiInstance.LoginAsync(); Assert.True(loginResult.Succeeded); - Assert.True(_apiInstance.IsUserAuthenticated); + Assert.True(apiInstance.IsUserAuthenticated); } } } \ No newline at end of file diff --git a/InstaSharper.Tests/Tests/BaseInstaApiTest.cs b/InstaSharper.Tests/Tests/BaseInstaApiTest.cs deleted file mode 100644 index c8820ba6..00000000 --- a/InstaSharper.Tests/Tests/BaseInstaApiTest.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using InstaSharper.API; -using InstaSharper.Classes; -using InstaSharper.Tests.Utils; -using Xunit.Abstractions; - -namespace InstaSharper.Tests.Tests -{ - public class BaseInstaApiTest : IDisposable - { - private readonly IInstaApi _apiInstance; - private readonly ITestOutputHelper _output; - - public BaseInstaApiTest(ITestOutputHelper output) - { - _output = output; - var username = "alex_codegarage"; - var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - _apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = username, - Password = password - }); - } - - public void Dispose() - { - _apiInstance.LogoutAsync(); - } - } -} \ No newline at end of file diff --git a/InstaSharper.Tests/Tests/FollowersTest.cs b/InstaSharper.Tests/Tests/FollowersTest.cs index e90fb130..8e6813d8 100644 --- a/InstaSharper.Tests/Tests/FollowersTest.cs +++ b/InstaSharper.Tests/Tests/FollowersTest.cs @@ -1,5 +1,4 @@ using System; -using InstaSharper.API; using InstaSharper.Classes; using InstaSharper.Tests.Utils; using Xunit; @@ -7,34 +6,28 @@ namespace InstaSharper.Tests.Tests { - public class FollowersTest : IDisposable + public class FollowersTest { public FollowersTest(ITestOutputHelper output) { _output = output; - var username = "alex_codegarage"; - var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - _apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = username, - Password = password - }); - TestHelpers.Login(_apiInstance, _output); - } - - public void Dispose() - { - _apiInstance.LogoutAsync(); } private readonly ITestOutputHelper _output; - private readonly IInstaApi _apiInstance; [Theory] [InlineData("discovery")] public async void GetUserFollowersTest(string username) { - var result = await _apiInstance.GetUserFollowersAsync(username, 10); + var currentUsername = "alex_codegarage"; + var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); + var apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = currentUsername, + Password = password + }); + if (!TestHelpers.Login(apiInstance, _output)) return; + var result = await apiInstance.GetUserFollowersAsync(username, 10); var followers = result.Value; //assert Assert.True(result.Succeeded); @@ -44,7 +37,16 @@ public async void GetUserFollowersTest(string username) [Fact] public async void GetCurrentUserFollwersTest() { - var result = await _apiInstance.GetCurrentUserFollowersAsync(); + var username = "alex_codegarage"; + var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); + var apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = username, + Password = password + }); + if (!TestHelpers.Login(apiInstance, _output)) return; + if (!TestHelpers.Login(apiInstance, _output)) return; + var result = await apiInstance.GetCurrentUserFollowersAsync(); var followers = result.Value; //assert Assert.True(result.Succeeded); diff --git a/InstaSharper.Tests/Tests/MediaTest.cs b/InstaSharper.Tests/Tests/MediaTest.cs index 8149125c..0f1deb0f 100644 --- a/InstaSharper.Tests/Tests/MediaTest.cs +++ b/InstaSharper.Tests/Tests/MediaTest.cs @@ -8,13 +8,11 @@ namespace InstaSharper.Tests.Tests { public class MediaTest { - private readonly ITestOutputHelper output; - private readonly string password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - private readonly string username = "alex_codegarage"; + private readonly ITestOutputHelper _output; public MediaTest(ITestOutputHelper output) { - this.output = output; + _output = output; } [Theory] @@ -22,16 +20,17 @@ public MediaTest(ITestOutputHelper output) public async void GetMediaByCodeTest(string mediaId) { //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = username, - Password = password - }); + var username = "alex_codegarage"; + var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); + var apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = username, + Password = password + }); //act - output.WriteLine($"Trying to login as user: {username}"); - if (!TestHelpers.Login(apiInstance, output)) return; - output.WriteLine($"Getting media by ID: {mediaId}"); + _output.WriteLine($"Trying to login as user: {username}"); + if (!TestHelpers.Login(apiInstance, _output)) return; + _output.WriteLine($"Getting media by ID: {mediaId}"); var media = await apiInstance.GetMediaByCodeAsync(mediaId); //assert Assert.NotNull(media); @@ -44,18 +43,19 @@ public async void GetMediaByCodeTest(string mediaId) public async void GetUserMediaListTest(string userToFetch) { //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = username, - Password = password - }); + var username = "alex_codegarage"; + var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); + var apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = username, + Password = password + }); var random = new Random(DateTime.Today.Millisecond); var pages = random.Next(1, 10); //act - output.WriteLine($"Trying to login as user: {username}"); - if (!TestHelpers.Login(apiInstance, output)) return; - output.WriteLine($"Getting posts of user: {userToFetch}"); + _output.WriteLine($"Trying to login as user: {username}"); + if (!TestHelpers.Login(apiInstance, _output)) return; + _output.WriteLine($"Getting posts of user: {userToFetch}"); var posts = await apiInstance.GetUserMediaAsync(userToFetch, pages); //assert diff --git a/InstaSharper/API/InstaApi.cs b/InstaSharper/API/InstaApi.cs index 8da995f4..b60e3169 100644 --- a/InstaSharper/API/InstaApi.cs +++ b/InstaSharper/API/InstaApi.cs @@ -114,7 +114,7 @@ public async Task> GetMediaByCodeAsync(string postCode) var converter = ConvertersFabric.GetSingleMediaConverter(mediaResponse.Items.FirstOrDefault()); return Result.Success(converter.Convert()); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMedia)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMedia) null); } public async Task> GetUserAsync(string username) @@ -140,7 +140,7 @@ public async Task> GetUserAsync(string username) var converter = ConvertersFabric.GetUserConverter(user); return Result.Success(converter.Convert()); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUser)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUser) null); } public IResult GetCurrentUser() @@ -175,7 +175,7 @@ public async Task> GetCurrentUserAsync() return Result.Success(userConverted); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUser)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUser) null); } public async Task> GetUserFeedAsync(int maxPages = 0) @@ -187,7 +187,7 @@ public async Task> GetUserFeedAsync(int maxPages = 0) var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); var feed = new InstaFeed(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeed)null); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeed) null); var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); var converter = ConvertersFabric.GetFeedConverter(feedResponse); var feedConverted = converter.Convert(); @@ -223,9 +223,9 @@ public async Task> GetUserFollowersAsync(string username, var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); var followers = new InstaUserList(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaUserList)null); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaUserList) null); var followersResponse = JsonConvert.DeserializeObject(json); - if (!followersResponse.IsOK()) Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUserList)null); + if (!followersResponse.IsOK()) Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUserList) null); followers.AddRange(followersResponse.Items.Select(ConvertersFabric.GetUserConverter).Select(converter => converter.Convert())); if (!followersResponse.IsBigList) return Result.Success(followers); var pages = 1; @@ -239,9 +239,8 @@ public async Task> GetUserFollowersAsync(string username, } return Result.Success(followers); } - catch (Exception exception) - { - return Result.Fail(exception.Message, (InstaUserList)null); + catch (Exception exception) { + return Result.Fail(exception.Message, (InstaUserList) null); } } @@ -259,14 +258,13 @@ private async Task> GetUserFollowersWithMaxIdAsy if (response.StatusCode == HttpStatusCode.OK) { var followersResponse = JsonConvert.DeserializeObject(json); - if (!followersResponse.IsOK()) Result.Fail("", (InstaFollowersResponse)null); + if (!followersResponse.IsOK()) Result.Fail("", (InstaFollowersResponse) null); return Result.Success(followersResponse); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFollowersResponse)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFollowersResponse) null); } - catch (Exception exception) - { - return Result.Fail(exception.Message, (InstaFollowersResponse)null); + catch (Exception exception) { + return Result.Fail(exception.Message, (InstaFollowersResponse) null); } } @@ -295,7 +293,7 @@ public async Task> GetTagFeedAsync(string tag, int maxPa } return Result.Success(tagFeed); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaList)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaList) null); } public async Task> GetTagFeedWithMaxIdAsync(string tag, string nextId) @@ -305,7 +303,7 @@ public async Task> GetTagFeedWithMaxIdAsync(stri try { var instaUri = UriCreator.GetTagFeedUri(tag); - instaUri = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }.Uri; + instaUri = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}.Uri; var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); @@ -314,11 +312,10 @@ public async Task> GetTagFeedWithMaxIdAsync(stri var feedResponse = JsonConvert.DeserializeObject(json); return Result.Success(feedResponse); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaListResponse)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaListResponse) null); } - catch (Exception exception) - { - return Result.Fail(exception.Message, (InstaMediaListResponse)null); + catch (Exception exception) { + return Result.Fail(exception.Message, (InstaMediaListResponse) null); } } @@ -347,14 +344,14 @@ public async Task> GetUserMediaAsync(string username, in } return Result.Success(mediaList); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaList)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaList) null); } public async Task> GetUserFeedWithMaxIdAsync(string maxId) { Uri instaUri; if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search user URI"); - var userUriBuilder = new UriBuilder(instaUri) { Query = $"max_id={maxId}" }; + var userUriBuilder = new UriBuilder(instaUri) {Query = $"max_id={maxId}"}; var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUriBuilder.Uri, _deviceInfo); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_PHONE_ID, _requestMessage.phone_id)); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, InstaApiConstants.TIMEZONE_OFFSET.ToString())); @@ -365,7 +362,7 @@ public async Task> GetUserFeedWithMaxIdAsync(string m var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); return Result.Success(feedResponse); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeedResponse)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeedResponse) null); } private async Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId) @@ -379,7 +376,7 @@ private async Task> GetUserMediaListWithMaxIdAsy var mediaResponse = JsonConvert.DeserializeObject(json); return Result.Success(mediaResponse); } - return Result.Fail("", (InstaMediaListResponse)null); + return Result.Fail("", (InstaMediaListResponse) null); } public async Task> LoginAsync() @@ -423,8 +420,7 @@ public async Task> LoginAsync() return Result.Fail(loginInfo.Message, false); } } - catch (Exception exception) - { + catch (Exception exception) { return Result.Fail(exception.Message, false); } } @@ -452,8 +448,7 @@ public async Task> LogoutAsync() return Result.Fail(logoutInfo.Message, false); } } - catch (Exception exception) - { + catch (Exception exception) { return Result.Fail(exception.Message, false); } } @@ -481,8 +476,7 @@ private BadStatusResponse GetBadStatusFromJsonString(string json) { var badStatus = new BadStatusResponse(); try { badStatus = JsonConvert.DeserializeObject(json); } - catch (Exception ex) - { + catch (Exception ex) { badStatus.Message = ex.Message; } return badStatus; diff --git a/appveyor.yml b/appveyor.yml index d799f4fb..46915bd3 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,8 @@ branches: only: - release - master +skip_commits: + message: /skip ci/ # Regex for matching commit message skip_tags: true @@ -24,7 +26,7 @@ build_script: - ps: cd ../InstaSharper.Tests - ps: dotnet restore - ps: dotnet --verbose build - - ps: dotnet --verbose test + - ps: dotnet --verbose test -parallel none - ps: cd .. assembly_info: From 99991e0e3abe6d6a3cf2ea969aa0492afdaecc16 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Mon, 5 Dec 2016 20:11:11 +0300 Subject: [PATCH 16/23] [skip ci] code cleanup and checkpoint --- InstaSharper/API/InstaApi.cs | 73 ++++++++++++------- InstaSharper/Classes/Models/CheckPointType.cs | 7 ++ .../ResponseWrappers/BadStatusResponse.cs | 3 + 3 files changed, 57 insertions(+), 26 deletions(-) create mode 100644 InstaSharper/Classes/Models/CheckPointType.cs diff --git a/InstaSharper/API/InstaApi.cs b/InstaSharper/API/InstaApi.cs index b60e3169..eb25bf49 100644 --- a/InstaSharper/API/InstaApi.cs +++ b/InstaSharper/API/InstaApi.cs @@ -114,7 +114,7 @@ public async Task> GetMediaByCodeAsync(string postCode) var converter = ConvertersFabric.GetSingleMediaConverter(mediaResponse.Items.FirstOrDefault()); return Result.Success(converter.Convert()); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMedia) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMedia)null); } public async Task> GetUserAsync(string username) @@ -140,7 +140,7 @@ public async Task> GetUserAsync(string username) var converter = ConvertersFabric.GetUserConverter(user); return Result.Success(converter.Convert()); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUser) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUser)null); } public IResult GetCurrentUser() @@ -175,7 +175,7 @@ public async Task> GetCurrentUserAsync() return Result.Success(userConverted); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUser) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUser)null); } public async Task> GetUserFeedAsync(int maxPages = 0) @@ -187,7 +187,7 @@ public async Task> GetUserFeedAsync(int maxPages = 0) var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); var feed = new InstaFeed(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeed) null); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeed)null); var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); var converter = ConvertersFabric.GetFeedConverter(feedResponse); var feedConverted = converter.Convert(); @@ -223,9 +223,9 @@ public async Task> GetUserFollowersAsync(string username, var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); var followers = new InstaUserList(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaUserList) null); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaUserList)null); var followersResponse = JsonConvert.DeserializeObject(json); - if (!followersResponse.IsOK()) Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUserList) null); + if (!followersResponse.IsOK()) Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUserList)null); followers.AddRange(followersResponse.Items.Select(ConvertersFabric.GetUserConverter).Select(converter => converter.Convert())); if (!followersResponse.IsBigList) return Result.Success(followers); var pages = 1; @@ -239,8 +239,9 @@ public async Task> GetUserFollowersAsync(string username, } return Result.Success(followers); } - catch (Exception exception) { - return Result.Fail(exception.Message, (InstaUserList) null); + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaUserList)null); } } @@ -258,16 +259,28 @@ private async Task> GetUserFollowersWithMaxIdAsy if (response.StatusCode == HttpStatusCode.OK) { var followersResponse = JsonConvert.DeserializeObject(json); - if (!followersResponse.IsOK()) Result.Fail("", (InstaFollowersResponse) null); + if (!followersResponse.IsOK()) Result.Fail("", (InstaFollowersResponse)null); return Result.Success(followersResponse); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFollowersResponse) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFollowersResponse)null); } - catch (Exception exception) { - return Result.Fail(exception.Message, (InstaFollowersResponse) null); + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaFollowersResponse)null); } } + public async Task> CheckpointAsync(string checkPointUrl) + { + if (string.IsNullOrEmpty(checkPointUrl)) return Result.Fail("Empty checkpoint URL", false); + var instaUri = new Uri(checkPointUrl); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) return Result.Success(true); + return Result.Fail(GetBadStatusFromJsonString(json).Message, false); + } + public async Task> GetTagFeedAsync(string tag, int maxPages = 0) { ValidateUser(); @@ -293,7 +306,7 @@ public async Task> GetTagFeedAsync(string tag, int maxPa } return Result.Success(tagFeed); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaList) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaList)null); } public async Task> GetTagFeedWithMaxIdAsync(string tag, string nextId) @@ -303,7 +316,7 @@ public async Task> GetTagFeedWithMaxIdAsync(stri try { var instaUri = UriCreator.GetTagFeedUri(tag); - instaUri = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}.Uri; + instaUri = new UriBuilder(instaUri) { Query = $"max_id={nextId}" }.Uri; var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); @@ -312,10 +325,11 @@ public async Task> GetTagFeedWithMaxIdAsync(stri var feedResponse = JsonConvert.DeserializeObject(json); return Result.Success(feedResponse); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaListResponse) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaListResponse)null); } - catch (Exception exception) { - return Result.Fail(exception.Message, (InstaMediaListResponse) null); + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaMediaListResponse)null); } } @@ -344,14 +358,14 @@ public async Task> GetUserMediaAsync(string username, in } return Result.Success(mediaList); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaList) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaList)null); } public async Task> GetUserFeedWithMaxIdAsync(string maxId) { Uri instaUri; if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search user URI"); - var userUriBuilder = new UriBuilder(instaUri) {Query = $"max_id={maxId}"}; + var userUriBuilder = new UriBuilder(instaUri) { Query = $"max_id={maxId}" }; var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUriBuilder.Uri, _deviceInfo); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_PHONE_ID, _requestMessage.phone_id)); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, InstaApiConstants.TIMEZONE_OFFSET.ToString())); @@ -362,7 +376,7 @@ public async Task> GetUserFeedWithMaxIdAsync(string m var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); return Result.Success(feedResponse); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeedResponse) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeedResponse)null); } private async Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId) @@ -376,7 +390,7 @@ private async Task> GetUserMediaListWithMaxIdAsy var mediaResponse = JsonConvert.DeserializeObject(json); return Result.Success(mediaResponse); } - return Result.Fail("", (InstaMediaListResponse) null); + return Result.Fail("", (InstaMediaListResponse)null); } public async Task> LoginAsync() @@ -416,11 +430,17 @@ public async Task> LoginAsync() else { var loginInfo = GetBadStatusFromJsonString(json); - _logger.Write(loginInfo.Message); + if (loginInfo.ErrorType == "checkpoint_logged_out") + { + var checkPointResult = await CheckpointAsync(loginInfo.CheckPointUrl); + IsUserAuthenticated = checkPointResult.Succeeded; + return Result.Success(checkPointResult.Value); + } return Result.Fail(loginInfo.Message, false); } } - catch (Exception exception) { + catch (Exception exception) + { return Result.Fail(exception.Message, false); } } @@ -444,11 +464,11 @@ public async Task> LogoutAsync() else { var logoutInfo = GetBadStatusFromJsonString(json); - _logger.Write(logoutInfo.Message); return Result.Fail(logoutInfo.Message, false); } } - catch (Exception exception) { + catch (Exception exception) + { return Result.Fail(exception.Message, false); } } @@ -476,7 +496,8 @@ private BadStatusResponse GetBadStatusFromJsonString(string json) { var badStatus = new BadStatusResponse(); try { badStatus = JsonConvert.DeserializeObject(json); } - catch (Exception ex) { + catch (Exception ex) + { badStatus.Message = ex.Message; } return badStatus; diff --git a/InstaSharper/Classes/Models/CheckPointType.cs b/InstaSharper/Classes/Models/CheckPointType.cs new file mode 100644 index 00000000..9df708ce --- /dev/null +++ b/InstaSharper/Classes/Models/CheckPointType.cs @@ -0,0 +1,7 @@ +namespace InstaSharper.Classes.Models +{ + public enum CheckPointType + { + CheckpointLoggedOut = 0 + } +} \ No newline at end of file diff --git a/InstaSharper/ResponseWrappers/BadStatusResponse.cs b/InstaSharper/ResponseWrappers/BadStatusResponse.cs index d7e0d82e..3946d591 100644 --- a/InstaSharper/ResponseWrappers/BadStatusResponse.cs +++ b/InstaSharper/ResponseWrappers/BadStatusResponse.cs @@ -10,5 +10,8 @@ public class BadStatusResponse : BaseStatusResponse [JsonProperty("error_type")] public string ErrorType { get; set; } + + [JsonProperty("checkpoint_url")] + public string CheckPointUrl { get; set; } } } \ No newline at end of file From 65d3c49698faa2513f0d938a60ef52ed80330020 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Wed, 7 Dec 2016 11:56:57 +0300 Subject: [PATCH 17/23] added explore feed --- InstaSharper.Examples/InstaSharperExamples.cs | 4 +- InstaSharper.Tests/Tests/DiscoverTest.cs | 39 ++++++ InstaSharper/API/IInstaApi.cs | 10 +- InstaSharper/API/InstaApi.cs | 129 ++++++++++++------ InstaSharper/API/InstaApiConstants.cs | 1 + InstaSharper/Classes/Models/InstaFeed.cs | 8 +- InstaSharper/Classes/Models/InstaMediaList.cs | 2 +- InstaSharper/Classes/Models/InstaStory.cs | 25 ++++ InstaSharper/Converters/ConvertersFabric.cs | 5 + .../Converters/InstaCaptionConverter.cs | 2 +- InstaSharper/Converters/InstaFeedConverter.cs | 2 +- .../InstaFriendshipStatusConverter.cs | 2 +- .../Converters/InstaMediaConverter.cs | 2 +- .../Converters/InstaMediaListConverter.cs | 2 +- .../Converters/InstaStoryConverter.cs | 30 ++++ .../Json/InstaExploreFeedDataConverter.cs | 45 ++++++ ...r.cs => InstaFeedResponseDataConverter.cs} | 2 +- InstaSharper/Helpers/CryptoHelper.cs | 2 +- InstaSharper/Helpers/DateTimeHelper.cs | 2 +- InstaSharper/Helpers/HttpHelper.cs | 2 +- InstaSharper/Helpers/UriCreator.cs | 7 + InstaSharper/Logger/DebugLogger.cs | 7 +- .../ResponseWrappers/BadStatusResponse.cs | 2 +- .../BaseResponse/BaseLoadableResponse.cs | 2 +- .../BaseResponse/BaseStatusResponse.cs | 2 +- .../ResponseWrappers/FollowedByResponse.cs | 2 +- .../ResponseWrappers/ImageResponse.cs | 2 +- .../ResponseWrappers/ImagesResponse.cs | 2 +- .../ResponseWrappers/InstaCaptionResponse.cs | 2 +- .../InstaCurrentUserResponse.cs | 2 +- .../ResponseWrappers/InstaFeedResponse.cs | 2 +- .../InstaFollowersResponse.cs | 2 +- .../InstaFriendshipStatusResponse.cs | 2 +- .../InstaImageCandidatesResponse.cs | 2 +- .../ResponseWrappers/InstaLoginResponse.cs | 2 +- .../InstaMediaItemResponse.cs | 2 +- .../InstaMediaListResponse.cs | 6 +- .../InstaSearchUserResponse.cs | 2 +- .../ResponseWrappers/InstaStoryResponse.cs | 34 +++++ .../ResponseWrappers/InstaTagFeedResponse.cs | 2 +- .../ResponseWrappers/InstaUserResponse.cs | 2 +- 41 files changed, 322 insertions(+), 82 deletions(-) create mode 100644 InstaSharper.Tests/Tests/DiscoverTest.cs create mode 100644 InstaSharper/Classes/Models/InstaStory.cs create mode 100644 InstaSharper/Converters/InstaStoryConverter.cs create mode 100644 InstaSharper/Converters/Json/InstaExploreFeedDataConverter.cs rename InstaSharper/Converters/Json/{FeedResponseDataConverter.cs => InstaFeedResponseDataConverter.cs} (95%) create mode 100644 InstaSharper/ResponseWrappers/InstaStoryResponse.cs diff --git a/InstaSharper.Examples/InstaSharperExamples.cs b/InstaSharper.Examples/InstaSharperExamples.cs index 58cd2c7f..44b815fd 100644 --- a/InstaSharper.Examples/InstaSharperExamples.cs +++ b/InstaSharper.Examples/InstaSharperExamples.cs @@ -15,8 +15,8 @@ private static void Main(string[] args) // create user session data and provide login details var userSession = new UserSessionData { - UserName = "alex_codegarage", - Password = "3591957P@R" + UserName = "username", + Password = "password" }; // create new InstaApi instance using Builder _instaApi = new InstaApiBuilder() diff --git a/InstaSharper.Tests/Tests/DiscoverTest.cs b/InstaSharper.Tests/Tests/DiscoverTest.cs new file mode 100644 index 00000000..c577ca87 --- /dev/null +++ b/InstaSharper.Tests/Tests/DiscoverTest.cs @@ -0,0 +1,39 @@ +using System; +using InstaSharper.Classes; +using InstaSharper.Tests.Utils; +using Xunit; +using Xunit.Abstractions; + +namespace InstaSharper.Tests.Tests +{ + public class DiscoverTest + { + public DiscoverTest(ITestOutputHelper output) + { + _output = output; + } + + private readonly ITestOutputHelper _output; + private readonly string _username = "alex_codegarage"; + private readonly string _password = Environment.GetEnvironmentVariable("instaapiuserpassword"); + + [Fact] + public async void ExploreTest() + { + //arrange + var apiInstance = + TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = _username, + Password = _password + }); + //act + if (!TestHelpers.Login(apiInstance, _output)) return; + var result = await apiInstance.GetExploreFeedAsync(0); + var exploreGeed = result.Value; + //assert + Assert.True(result.Succeeded); + Assert.NotNull(exploreGeed); + } + } +} \ No newline at end of file diff --git a/InstaSharper/API/IInstaApi.cs b/InstaSharper/API/IInstaApi.cs index 7b8129a9..1fd8761a 100644 --- a/InstaSharper/API/IInstaApi.cs +++ b/InstaSharper/API/IInstaApi.cs @@ -27,7 +27,10 @@ public interface IInstaApi IResult GetCurentUserFollowers(int maxPages = 0); IResult GetUserFollowers(string username, int maxPages = 0); - IResult GetTagFeed(string tag, int maxPages = 0); + IResult GetTagFeed(string tag, int maxPages = 0); + + IResult Expole(int maxPages = 0); + IResult GetUserTags(int maxPages = 0); #endregion @@ -39,10 +42,13 @@ public interface IInstaApi Task> GetUserFeedAsync(int maxPages = 0); Task> GetCurrentUserAsync(); - Task> GetTagFeedAsync(string tag, int maxPages = 0); + Task> GetTagFeedAsync(string tag, int maxPages = 0); Task> GetUserFollowersAsync(string username, int maxPages = 0); Task> GetCurrentUserFollowersAsync(int maxPages = 0); + Task> GetExploreFeedAsync(int maxPages = 0); + Task> GetUserTagsAsync(int maxPages = 0); + #endregion } } \ No newline at end of file diff --git a/InstaSharper/API/InstaApi.cs b/InstaSharper/API/InstaApi.cs index eb25bf49..a9dd79d1 100644 --- a/InstaSharper/API/InstaApi.cs +++ b/InstaSharper/API/InstaApi.cs @@ -81,11 +81,21 @@ public IResult GetUserFollowers(string username, int maxPages = 0 return GetUserFollowersAsync(username, maxPages).Result; } - public IResult GetTagFeed(string tag, int maxPages = 0) + public IResult GetTagFeed(string tag, int maxPages = 0) { return GetTagFeedAsync(tag, maxPages).Result; } + public IResult Expole(int maxPages = 0) + { + throw new NotImplementedException(); + } + + public IResult GetUserTags(int maxPages = 0) + { + throw new NotImplementedException(); + } + public IResult GetCurentUserFollowers(int maxPages = 0) { return GetCurrentUserFollowersAsync(maxPages).Result; @@ -105,13 +115,13 @@ public async Task> GetMediaByCodeAsync(string postCode) if (response.StatusCode == HttpStatusCode.OK) { var mediaResponse = JsonConvert.DeserializeObject(json); - if (mediaResponse.Items?.Count != 1) + if (mediaResponse.Medias?.Count != 1) { string errorMessage = $"Got wrong media count for request with media id={postCode}"; _logger.Write(errorMessage); return Result.Fail(errorMessage); } - var converter = ConvertersFabric.GetSingleMediaConverter(mediaResponse.Items.FirstOrDefault()); + var converter = ConvertersFabric.GetSingleMediaConverter(mediaResponse.Medias.FirstOrDefault()); return Result.Success(converter.Convert()); } return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMedia)null); @@ -188,17 +198,18 @@ public async Task> GetUserFeedAsync(int maxPages = 0) var json = await response.Content.ReadAsStringAsync(); var feed = new InstaFeed(); if (response.StatusCode != HttpStatusCode.OK) return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeed)null); - var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); + var feedResponse = JsonConvert.DeserializeObject(json, new InstaFeedResponseDataConverter()); var converter = ConvertersFabric.GetFeedConverter(feedResponse); var feedConverted = converter.Convert(); - feed.Items.AddRange(feedConverted.Items); + feed.Medias.AddRange(feedConverted.Medias); var nextId = feedResponse.NextMaxId; while (feedResponse.MoreAvailable && (feed.Pages < maxPages)) { + if (string.IsNullOrEmpty(nextId)) break; var nextFeed = await GetUserFeedWithMaxIdAsync(nextId); if (!nextFeed.Succeeded) Result.Success($"Not all pages was downloaded: {nextFeed.Message}", feed); nextId = nextFeed.Value.NextMaxId; - feed.Items.AddRange(nextFeed.Value.Items.Select(ConvertersFabric.GetSingleMediaConverter).Select(conv => conv.Convert())); + feed.Medias.AddRange(nextFeed.Value.Items.Select(ConvertersFabric.GetSingleMediaConverter).Select(conv => conv.Convert())); feed.Pages++; } return Result.Success(feed); @@ -210,6 +221,38 @@ public async Task> GetCurrentUserFollowersAsync(int maxPa return await GetUserFollowersAsync(_user.UserName, maxPages); } + public async Task> GetExploreFeedAsync(int maxPages = 0) + { + ValidateUser(); + ValidateLoggedIn(); + try + { + if (maxPages == 0) maxPages = int.MaxValue; + var exploreUri = UriCreator.GetExploreUri(); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, exploreUri, _deviceInfo); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + var exploreFeed = new InstaFeed(); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaFeed)null); + var mediaResponse = JsonConvert.DeserializeObject(json, new InstaExploreFeedDataConverter()); + exploreFeed.Medias.AddRange(mediaResponse.Medias.Select(ConvertersFabric.GetSingleMediaConverter).Select(converter => converter.Convert())); + exploreFeed.Stories.AddRange(mediaResponse.Stories.Select(ConvertersFabric.GetSingleStoryConverter).Select(converter => converter.Convert())); + var pages = 1; + var nextId = mediaResponse.NextMaxId; + while (!string.IsNullOrEmpty(nextId) && (pages < maxPages)) if (string.IsNullOrEmpty(nextId) || (nextId == "0")) break; + return Result.Success(exploreFeed); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaFeed)null); + } + } + + public Task> GetUserTagsAsync(int maxPages = 0) + { + throw new NotImplementedException(); + } + public async Task> GetUserFollowersAsync(string username, int maxPages = 0) { ValidateUser(); @@ -281,7 +324,7 @@ public async Task> CheckpointAsync(string checkPointUrl) return Result.Fail(GetBadStatusFromJsonString(json).Message, false); } - public async Task> GetTagFeedAsync(string tag, int maxPages = 0) + public async Task> GetTagFeedAsync(string tag, int maxPages = 0) { ValidateUser(); ValidateLoggedIn(); @@ -293,7 +336,8 @@ public async Task> GetTagFeedAsync(string tag, int maxPa { var feedResponse = JsonConvert.DeserializeObject(json); var converter = ConvertersFabric.GetMediaListConverter(feedResponse); - var tagFeed = converter.Convert(); + var tagFeed = new InstaFeed(); + tagFeed.Medias.AddRange(converter.Convert()); var nextId = feedResponse.NextMaxId; while (feedResponse.MoreAvailable && (tagFeed.Pages < maxPages)) { @@ -301,15 +345,15 @@ public async Task> GetTagFeedAsync(string tag, int maxPa if (!nextMedia.Succeeded) Result.Success($"Not all pages was downloaded: {nextMedia.Message}", tagFeed); nextId = nextMedia.Value.NextMaxId; converter = ConvertersFabric.GetMediaListConverter(nextMedia.Value); - tagFeed.AddRange(converter.Convert()); + tagFeed.Medias.AddRange(converter.Convert()); tagFeed.Pages++; } return Result.Success(tagFeed); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaList)null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeed)null); } - public async Task> GetTagFeedWithMaxIdAsync(string tag, string nextId) + private async Task> GetTagFeedWithMaxIdAsync(string tag, string nextId) { ValidateUser(); ValidateLoggedIn(); @@ -361,37 +405,6 @@ public async Task> GetUserMediaAsync(string username, in return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaList)null); } - public async Task> GetUserFeedWithMaxIdAsync(string maxId) - { - Uri instaUri; - if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search user URI"); - var userUriBuilder = new UriBuilder(instaUri) { Query = $"max_id={maxId}" }; - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUriBuilder.Uri, _deviceInfo); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_PHONE_ID, _requestMessage.phone_id)); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, InstaApiConstants.TIMEZONE_OFFSET.ToString())); - var response = await _httpClient.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var feedResponse = JsonConvert.DeserializeObject(json, new FeedResponseDataConverter()); - return Result.Success(feedResponse); - } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeedResponse)null); - } - - private async Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId) - { - var instaUri = UriCreator.GetMediaListWithMaxIdUri(userPk, nextId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); - var response = await _httpClient.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var mediaResponse = JsonConvert.DeserializeObject(json); - return Result.Success(mediaResponse); - } - return Result.Fail("", (InstaMediaListResponse)null); - } public async Task> LoginAsync() { @@ -503,6 +516,38 @@ private BadStatusResponse GetBadStatusFromJsonString(string json) return badStatus; } + private async Task> GetUserFeedWithMaxIdAsync(string maxId) + { + Uri instaUri; + if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.TIMELINEFEED, out instaUri)) throw new Exception("Cant create search user URI"); + var userUriBuilder = new UriBuilder(instaUri) { Query = $"max_id={maxId}" }; + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUriBuilder.Uri, _deviceInfo); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_PHONE_ID, _requestMessage.phone_id)); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, InstaApiConstants.TIMEZONE_OFFSET.ToString())); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + { + var feedResponse = JsonConvert.DeserializeObject(json, new InstaFeedResponseDataConverter()); + return Result.Success(feedResponse); + } + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeedResponse)null); + } + + private async Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId) + { + var instaUri = UriCreator.GetMediaListWithMaxIdUri(userPk, nextId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + { + var mediaResponse = JsonConvert.DeserializeObject(json); + return Result.Success(mediaResponse); + } + return Result.Fail("", (InstaMediaListResponse)null); + } + #endregion } } \ No newline at end of file diff --git a/InstaSharper/API/InstaApiConstants.cs b/InstaSharper/API/InstaApiConstants.cs index 2c381bcf..6a2394a1 100644 --- a/InstaSharper/API/InstaApiConstants.cs +++ b/InstaSharper/API/InstaApiConstants.cs @@ -18,6 +18,7 @@ internal static class InstaApiConstants public const string SEARCH_USERS = API_SUFFIX + "/v1/users/search"; public const string ACCOUNTS_LOGIN = API_SUFFIX + "/v1/accounts/login/"; public const string ACCOUNTS_LOGOUT = API_SUFFIX + "/v1/accounts/logout/"; + public const string EXPLORE = API_SUFFIX + "/v1/discover/explore/"; public const string TIMELINEFEED = API_SUFFIX + "/v1/feed/timeline"; public const string USEREFEED = API_SUFFIX + "/v1/feed/user/"; public const string GET_MEDIA = API_SUFFIX + "/v1/media/{0}/info/"; diff --git a/InstaSharper/Classes/Models/InstaFeed.cs b/InstaSharper/Classes/Models/InstaFeed.cs index 6eaba0e3..180ef4f9 100644 --- a/InstaSharper/Classes/Models/InstaFeed.cs +++ b/InstaSharper/Classes/Models/InstaFeed.cs @@ -4,8 +4,12 @@ namespace InstaSharper.Classes.Models { public class InstaFeed { - public int FeedItemsCount => Items.Count; - public List Items { get; set; } = new List(); + public int MediaItemsCount => Medias.Count; + public int StoriesItemsCount => Stories.Count; + + public List Medias { get; set; } = new List(); + public List Stories { get; set; } = new List(); + public int Pages { get; set; } = 1; } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaMediaList.cs b/InstaSharper/Classes/Models/InstaMediaList.cs index 3dc9dcf2..fe026ac2 100644 --- a/InstaSharper/Classes/Models/InstaMediaList.cs +++ b/InstaSharper/Classes/Models/InstaMediaList.cs @@ -4,6 +4,6 @@ namespace InstaSharper.Classes.Models { public class InstaMediaList : List { - public int Pages { get; set; } + public int Pages { get; set; } = -1; } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaStory.cs b/InstaSharper/Classes/Models/InstaStory.cs new file mode 100644 index 00000000..73476248 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaStory.cs @@ -0,0 +1,25 @@ +using System; + +namespace InstaSharper.Classes.Models +{ + public class InstaStory + { + public bool CanReply { get; set; } + + public DateTime ExpiringAt { get; set; } + + public InstaUser User { get; set; } + + public string SourceToken { get; set; } + + public bool Seen { get; set; } + + public string LatestReelMedia { get; set; } + + public string Id { get; set; } + + public int RankedPosition { get; set; } + + public int SeenRankedPosition { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/ConvertersFabric.cs b/InstaSharper/Converters/ConvertersFabric.cs index 15566e1a..6d8f8ef7 100644 --- a/InstaSharper/Converters/ConvertersFabric.cs +++ b/InstaSharper/Converters/ConvertersFabric.cs @@ -36,5 +36,10 @@ public static IObjectConverter GetSingleStoryConverter(InstaStoryResponse storyResponse) + { + return new InstaStoryConverter {SourceObject = storyResponse}; + } } } \ No newline at end of file diff --git a/InstaSharper/Converters/InstaCaptionConverter.cs b/InstaSharper/Converters/InstaCaptionConverter.cs index ad7381b3..1d205963 100644 --- a/InstaSharper/Converters/InstaCaptionConverter.cs +++ b/InstaSharper/Converters/InstaCaptionConverter.cs @@ -4,7 +4,7 @@ namespace InstaSharper.Converters { - public class InstaCaptionConverter : IObjectConverter + internal class InstaCaptionConverter : IObjectConverter { public InstaCaptionResponse SourceObject { get; set; } diff --git a/InstaSharper/Converters/InstaFeedConverter.cs b/InstaSharper/Converters/InstaFeedConverter.cs index acf91f29..910064ca 100644 --- a/InstaSharper/Converters/InstaFeedConverter.cs +++ b/InstaSharper/Converters/InstaFeedConverter.cs @@ -15,7 +15,7 @@ public InstaFeed Convert() { if (instaUserFeedItemResponse?.Type != 0) continue; var feedItem = ConvertersFabric.GetSingleMediaConverter(instaUserFeedItemResponse).Convert(); - feed.Items.Add(feedItem); + feed.Medias.Add(feedItem); } return feed; } diff --git a/InstaSharper/Converters/InstaFriendshipStatusConverter.cs b/InstaSharper/Converters/InstaFriendshipStatusConverter.cs index cac3c6fc..5fa8b250 100644 --- a/InstaSharper/Converters/InstaFriendshipStatusConverter.cs +++ b/InstaSharper/Converters/InstaFriendshipStatusConverter.cs @@ -3,7 +3,7 @@ namespace InstaSharper.Converters { - public class InstaFriendshipStatusConverter : IObjectConverter + internal class InstaFriendshipStatusConverter : IObjectConverter { public InstaFriendshipStatusResponse SourceObject { get; set; } diff --git a/InstaSharper/Converters/InstaMediaConverter.cs b/InstaSharper/Converters/InstaMediaConverter.cs index aeacde67..39cc3713 100644 --- a/InstaSharper/Converters/InstaMediaConverter.cs +++ b/InstaSharper/Converters/InstaMediaConverter.cs @@ -5,7 +5,7 @@ namespace InstaSharper.Converters { - public class InstaMediaConverter : IObjectConverter + internal class InstaMediaConverter : IObjectConverter { public InstaMediaItemResponse SourceObject { get; set; } diff --git a/InstaSharper/Converters/InstaMediaListConverter.cs b/InstaSharper/Converters/InstaMediaListConverter.cs index d20e6bd0..5dcadfa4 100644 --- a/InstaSharper/Converters/InstaMediaListConverter.cs +++ b/InstaSharper/Converters/InstaMediaListConverter.cs @@ -13,7 +13,7 @@ public InstaMediaList Convert() { if (SourceObject == null) throw new ArgumentNullException($"Source object"); var mediaList = new InstaMediaList(); - mediaList.AddRange(SourceObject.Items.Select(ConvertersFabric.GetSingleMediaConverter).Select(converter => converter.Convert())); + mediaList.AddRange(SourceObject.Medias.Select(ConvertersFabric.GetSingleMediaConverter).Select(converter => converter.Convert())); return mediaList; } } diff --git a/InstaSharper/Converters/InstaStoryConverter.cs b/InstaSharper/Converters/InstaStoryConverter.cs new file mode 100644 index 00000000..1c498677 --- /dev/null +++ b/InstaSharper/Converters/InstaStoryConverter.cs @@ -0,0 +1,30 @@ +using System; +using InstaSharper.Classes.Models; +using InstaSharper.Helpers; +using InstaSharper.ResponseWrappers; + +namespace InstaSharper.Converters +{ + internal class InstaStoryConverter : IObjectConverter + { + public InstaStoryResponse SourceObject { get; set; } + + public InstaStory Convert() + { + if (SourceObject == null) throw new ArgumentNullException($"Source object"); + var story = new InstaStory + { + CanReply = SourceObject.CanReply, + ExpiringAt = DateTimeHelper.UnixTimestampToDateTime(SourceObject.ExpiringAt), + Id = SourceObject.Id, + LatestReelMedia = SourceObject.LatestReelMedia, + RankedPosition = SourceObject.RankedPosition, + Seen = SourceObject.Seen, + SeenRankedPosition = SourceObject.SeenRankedPosition, + SourceToken = SourceObject.SourceToken + }; + if (SourceObject.User != null) story.User = ConvertersFabric.GetUserConverter(SourceObject.User).Convert(); + return story; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/Json/InstaExploreFeedDataConverter.cs b/InstaSharper/Converters/Json/InstaExploreFeedDataConverter.cs new file mode 100644 index 00000000..2d60b988 --- /dev/null +++ b/InstaSharper/Converters/Json/InstaExploreFeedDataConverter.cs @@ -0,0 +1,45 @@ +using System; +using InstaSharper.ResponseWrappers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace InstaSharper.Converters.Json +{ + public class InstaExploreFeedDataConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(InstaMediaListResponse); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var root = JToken.Load(reader); + var feed = root.ToObject(); + feed.Medias.Clear(); + feed.Stories.Clear(); + var items = root.SelectToken("items"); + var storiesTray = root.SelectToken("items[0].stories.tray"); + foreach (var item in items) + { + var media = item["media"]; + if (media == null) continue; + feed.Medias.Add(media.ToObject()); + } + if (storiesTray == null) return feed; + foreach (var storyItem in storiesTray) + { + var story = storyItem.ToObject(); + if (story == null) continue; + feed.Stories.Add(story); + } + + return feed; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value); + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/Json/FeedResponseDataConverter.cs b/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs similarity index 95% rename from InstaSharper/Converters/Json/FeedResponseDataConverter.cs rename to InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs index f479c354..39cfa3d4 100644 --- a/InstaSharper/Converters/Json/FeedResponseDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs @@ -6,7 +6,7 @@ namespace InstaSharper.Converters.Json { - public class FeedResponseDataConverter : JsonConverter + internal class InstaFeedResponseDataConverter : JsonConverter { public override bool CanConvert(Type objectType) { diff --git a/InstaSharper/Helpers/CryptoHelper.cs b/InstaSharper/Helpers/CryptoHelper.cs index 00b5ec90..b43de7d4 100644 --- a/InstaSharper/Helpers/CryptoHelper.cs +++ b/InstaSharper/Helpers/CryptoHelper.cs @@ -5,7 +5,7 @@ namespace InstaSharper.Helpers { - public class CryptoHelper + internal class CryptoHelper { public static string CalculateMD5(string message) { diff --git a/InstaSharper/Helpers/DateTimeHelper.cs b/InstaSharper/Helpers/DateTimeHelper.cs index 580263ee..a7f9affc 100644 --- a/InstaSharper/Helpers/DateTimeHelper.cs +++ b/InstaSharper/Helpers/DateTimeHelper.cs @@ -2,7 +2,7 @@ namespace InstaSharper.Helpers { - public static class DateTimeHelper + internal static class DateTimeHelper { public static DateTime UnixTimestampToDateTime(double unixTime) { diff --git a/InstaSharper/Helpers/HttpHelper.cs b/InstaSharper/Helpers/HttpHelper.cs index 95d1f4ab..f2a84c0e 100644 --- a/InstaSharper/Helpers/HttpHelper.cs +++ b/InstaSharper/Helpers/HttpHelper.cs @@ -6,7 +6,7 @@ namespace InstaSharper.Helpers { - public class HttpHelper + internal class HttpHelper { public static HttpRequestMessage GetDefaultRequest(HttpMethod method, Uri uri, AndroidDevice deviceInfo) { diff --git a/InstaSharper/Helpers/UriCreator.cs b/InstaSharper/Helpers/UriCreator.cs index 7bb00472..9ad969ed 100644 --- a/InstaSharper/Helpers/UriCreator.cs +++ b/InstaSharper/Helpers/UriCreator.cs @@ -87,5 +87,12 @@ public static Uri GetLogoutUri() if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.ACCOUNTS_LOGOUT, out instaUri)) throw new Exception("Cant create URI for user logout"); return instaUri; } + + public static Uri GetExploreUri() + { + Uri instaUri; + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.EXPLORE, out instaUri)) throw new Exception("Cant create URI for explore posts"); + return instaUri; + } } } \ No newline at end of file diff --git a/InstaSharper/Logger/DebugLogger.cs b/InstaSharper/Logger/DebugLogger.cs index 6ed0e99e..f7f782e4 100644 --- a/InstaSharper/Logger/DebugLogger.cs +++ b/InstaSharper/Logger/DebugLogger.cs @@ -1,12 +1,9 @@ -using System; - -namespace InstaSharper.Logger +namespace InstaSharper.Logger { - public class DebugLogger : ILogger + internal class DebugLogger : ILogger { public void Write(string logMessage) { - throw new NotImplementedException(); } } } \ No newline at end of file diff --git a/InstaSharper/ResponseWrappers/BadStatusResponse.cs b/InstaSharper/ResponseWrappers/BadStatusResponse.cs index 3946d591..2645cc9c 100644 --- a/InstaSharper/ResponseWrappers/BadStatusResponse.cs +++ b/InstaSharper/ResponseWrappers/BadStatusResponse.cs @@ -3,7 +3,7 @@ namespace InstaSharper.ResponseWrappers { - public class BadStatusResponse : BaseStatusResponse + internal class BadStatusResponse : BaseStatusResponse { [JsonProperty("message")] public string Message { get; set; } diff --git a/InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs b/InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs index 12bc254e..a1d0cd3d 100644 --- a/InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs +++ b/InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs @@ -2,7 +2,7 @@ namespace InstaSharper.ResponseWrappers.BaseResponse { - public class BaseLoadableResponse : BaseStatusResponse + internal class BaseLoadableResponse : BaseStatusResponse { [JsonProperty("more_available")] public bool MoreAvailable { get; set; } diff --git a/InstaSharper/ResponseWrappers/BaseResponse/BaseStatusResponse.cs b/InstaSharper/ResponseWrappers/BaseResponse/BaseStatusResponse.cs index 637ca188..5c667347 100644 --- a/InstaSharper/ResponseWrappers/BaseResponse/BaseStatusResponse.cs +++ b/InstaSharper/ResponseWrappers/BaseResponse/BaseStatusResponse.cs @@ -2,7 +2,7 @@ namespace InstaSharper.ResponseWrappers.BaseResponse { - public class BaseStatusResponse + internal class BaseStatusResponse { [JsonProperty("status")] public string Status { get; set; } diff --git a/InstaSharper/ResponseWrappers/FollowedByResponse.cs b/InstaSharper/ResponseWrappers/FollowedByResponse.cs index 96e04f42..66a38e40 100644 --- a/InstaSharper/ResponseWrappers/FollowedByResponse.cs +++ b/InstaSharper/ResponseWrappers/FollowedByResponse.cs @@ -2,7 +2,7 @@ namespace InstaSharper.ResponseWrappers { - public class FollowedByResponse + internal class FollowedByResponse { [JsonProperty("count")] public int Count { get; set; } diff --git a/InstaSharper/ResponseWrappers/ImageResponse.cs b/InstaSharper/ResponseWrappers/ImageResponse.cs index 9148207f..efa259dd 100644 --- a/InstaSharper/ResponseWrappers/ImageResponse.cs +++ b/InstaSharper/ResponseWrappers/ImageResponse.cs @@ -2,7 +2,7 @@ namespace InstaSharper.ResponseWrappers { - public class ImageResponse + internal class ImageResponse { [JsonProperty("url")] public string Url { get; set; } diff --git a/InstaSharper/ResponseWrappers/ImagesResponse.cs b/InstaSharper/ResponseWrappers/ImagesResponse.cs index 5b98eb24..4dfd6b7c 100644 --- a/InstaSharper/ResponseWrappers/ImagesResponse.cs +++ b/InstaSharper/ResponseWrappers/ImagesResponse.cs @@ -2,7 +2,7 @@ namespace InstaSharper.ResponseWrappers { - public class ImagesResponse + internal class ImagesResponse { [JsonProperty("low_resolution")] public ImageResponse LowResolution { get; set; } diff --git a/InstaSharper/ResponseWrappers/InstaCaptionResponse.cs b/InstaSharper/ResponseWrappers/InstaCaptionResponse.cs index 9f965693..bb01f4b4 100644 --- a/InstaSharper/ResponseWrappers/InstaCaptionResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaCaptionResponse.cs @@ -3,7 +3,7 @@ namespace InstaSharper.ResponseWrappers { - public class InstaCaptionResponse : BaseStatusResponse + internal class InstaCaptionResponse : BaseStatusResponse { [JsonProperty("user_id")] public long UserId { get; set; } diff --git a/InstaSharper/ResponseWrappers/InstaCurrentUserResponse.cs b/InstaSharper/ResponseWrappers/InstaCurrentUserResponse.cs index 5de73ec5..d980e0f3 100644 --- a/InstaSharper/ResponseWrappers/InstaCurrentUserResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaCurrentUserResponse.cs @@ -3,7 +3,7 @@ namespace InstaSharper.ResponseWrappers { - public class InstaCurrentUserResponse : BaseStatusResponse + internal class InstaCurrentUserResponse : BaseStatusResponse { [JsonProperty("user")] public InstaUserResponse User { get; set; } diff --git a/InstaSharper/ResponseWrappers/InstaFeedResponse.cs b/InstaSharper/ResponseWrappers/InstaFeedResponse.cs index 5b73db82..6965f268 100644 --- a/InstaSharper/ResponseWrappers/InstaFeedResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaFeedResponse.cs @@ -4,7 +4,7 @@ namespace InstaSharper.ResponseWrappers { - public class InstaFeedResponse : BaseLoadableResponse + internal class InstaFeedResponse : BaseLoadableResponse { [JsonProperty("is_direct_v2_enabled")] public bool IsDirectV2Enabled { get; set; } diff --git a/InstaSharper/ResponseWrappers/InstaFollowersResponse.cs b/InstaSharper/ResponseWrappers/InstaFollowersResponse.cs index 6cba830c..03cc43c0 100644 --- a/InstaSharper/ResponseWrappers/InstaFollowersResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaFollowersResponse.cs @@ -4,7 +4,7 @@ namespace InstaSharper.ResponseWrappers { - public class InstaFollowersResponse : BaseStatusResponse + internal class InstaFollowersResponse : BaseStatusResponse { [JsonProperty("users")] public List Items { get; set; } diff --git a/InstaSharper/ResponseWrappers/InstaFriendshipStatusResponse.cs b/InstaSharper/ResponseWrappers/InstaFriendshipStatusResponse.cs index b4cd7d3c..d719235f 100644 --- a/InstaSharper/ResponseWrappers/InstaFriendshipStatusResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaFriendshipStatusResponse.cs @@ -2,7 +2,7 @@ namespace InstaSharper.ResponseWrappers { - public class InstaFriendshipStatusResponse + internal class InstaFriendshipStatusResponse { [JsonProperty("following")] public bool Foolowing { get; set; } diff --git a/InstaSharper/ResponseWrappers/InstaImageCandidatesResponse.cs b/InstaSharper/ResponseWrappers/InstaImageCandidatesResponse.cs index 2364a12b..42f2257a 100644 --- a/InstaSharper/ResponseWrappers/InstaImageCandidatesResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaImageCandidatesResponse.cs @@ -3,7 +3,7 @@ namespace InstaSharper.ResponseWrappers { - public class InstaImageCandidatesResponse + internal class InstaImageCandidatesResponse { [JsonProperty("candidates")] public List Candidates { get; set; } diff --git a/InstaSharper/ResponseWrappers/InstaLoginResponse.cs b/InstaSharper/ResponseWrappers/InstaLoginResponse.cs index daf2f195..be5aeab5 100644 --- a/InstaSharper/ResponseWrappers/InstaLoginResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaLoginResponse.cs @@ -2,7 +2,7 @@ namespace InstaSharper.ResponseWrappers { - public class InstaLoginResponse + internal class InstaLoginResponse { [JsonProperty("status")] public string Status { get; set; } diff --git a/InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs b/InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs index a9ef3089..e417f641 100644 --- a/InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs @@ -3,7 +3,7 @@ namespace InstaSharper.ResponseWrappers { - public class InstaMediaItemResponse + internal class InstaMediaItemResponse { [JsonProperty("taken_at")] public string TakenAtUnixLike { get; set; } diff --git a/InstaSharper/ResponseWrappers/InstaMediaListResponse.cs b/InstaSharper/ResponseWrappers/InstaMediaListResponse.cs index efa4cf20..4d116b8a 100644 --- a/InstaSharper/ResponseWrappers/InstaMediaListResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaMediaListResponse.cs @@ -4,9 +4,11 @@ namespace InstaSharper.ResponseWrappers { - public class InstaMediaListResponse : BaseLoadableResponse + internal class InstaMediaListResponse : BaseLoadableResponse { [JsonProperty("items")] - public List Items { get; set; } + public List Medias { get; set; } = new List(); + + public List Stories { get; set; } = new List(); } } \ No newline at end of file diff --git a/InstaSharper/ResponseWrappers/InstaSearchUserResponse.cs b/InstaSharper/ResponseWrappers/InstaSearchUserResponse.cs index 6b7fbf52..c5535369 100644 --- a/InstaSharper/ResponseWrappers/InstaSearchUserResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaSearchUserResponse.cs @@ -3,7 +3,7 @@ namespace InstaSharper.ResponseWrappers { - public class InstaSearchUserResponse + internal class InstaSearchUserResponse { [JsonProperty("has_more")] public bool MoreAvailable { get; set; } diff --git a/InstaSharper/ResponseWrappers/InstaStoryResponse.cs b/InstaSharper/ResponseWrappers/InstaStoryResponse.cs new file mode 100644 index 00000000..c211f3c1 --- /dev/null +++ b/InstaSharper/ResponseWrappers/InstaStoryResponse.cs @@ -0,0 +1,34 @@ +using Newtonsoft.Json; + +namespace InstaSharper.ResponseWrappers +{ + internal class InstaStoryResponse + { + [JsonProperty("can_reply")] + public bool CanReply { get; set; } + + [JsonProperty("expiring_at")] + public string ExpiringAt { get; set; } + + [JsonProperty("user")] + public InstaUserResponse User { get; set; } + + [JsonProperty("source_token")] + public string SourceToken { get; set; } + + [JsonProperty("seen")] + public bool Seen { get; set; } + + [JsonProperty("latest_reel_media")] + public string LatestReelMedia { get; set; } + + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("ranked_position")] + public int RankedPosition { get; set; } + + [JsonProperty("seen_ranked_position")] + public int SeenRankedPosition { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/ResponseWrappers/InstaTagFeedResponse.cs b/InstaSharper/ResponseWrappers/InstaTagFeedResponse.cs index 133f19bd..788af637 100644 --- a/InstaSharper/ResponseWrappers/InstaTagFeedResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaTagFeedResponse.cs @@ -3,7 +3,7 @@ namespace InstaSharper.ResponseWrappers { - public class InstaTagFeedResponse + internal class InstaTagFeedResponse { [JsonProperty("ranked_items")] public List Items { get; set; } diff --git a/InstaSharper/ResponseWrappers/InstaUserResponse.cs b/InstaSharper/ResponseWrappers/InstaUserResponse.cs index 699422d3..a676069a 100644 --- a/InstaSharper/ResponseWrappers/InstaUserResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaUserResponse.cs @@ -2,7 +2,7 @@ namespace InstaSharper.ResponseWrappers { - public class InstaUserResponse + internal class InstaUserResponse { [JsonProperty("username")] public string UserName { get; set; } From 74961eb7ea1186018d94a1c9e1979cfe5544ae17 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Wed, 7 Dec 2016 12:01:57 +0300 Subject: [PATCH 18/23] removed travis build --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 5a2a254f..8aff9a41 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ Tokenless, butthurtless private API for Instagram. Get account information, medi Note that: there is a simple [Instagram API](https://github.com/a-legotin/InstagramAPI-Web) based on web-version of Instagram. This repository based on Instagram API for mobile devices. [![Build status](https://ci.appveyor.com/api/projects/status/6os0fhi1awbplbka?svg=true)](https://ci.appveyor.com/project/a-legotin/instasharper) -[![Build Status](https://travis-ci.org/a-legotin/InstaSharper.svg?branch=master)](https://travis-ci.org/a-legotin/InstaSharper) #### Current version: 1.2.0 [Stable], 1.2.1 [Under development] From 1b6bb33504a23af01ebdb0d83be9899f4b3f3d1b Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Wed, 7 Dec 2016 12:06:09 +0300 Subject: [PATCH 19/23] updated ci stuf --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 46915bd3..858690e4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -38,7 +38,7 @@ assembly_info: environment: instaapiuserpassword: - secure: 2DmbP+MHwes0M3ahyTWDkA== + secure: 7eAl+O5i5BxXWexd26z+wg== artifacts: From 52e89c069da8dc4530390e9b1235328caa758f22 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Wed, 7 Dec 2016 18:58:42 +0300 Subject: [PATCH 20/23] why ci not working --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 858690e4..f6b09888 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -39,7 +39,7 @@ assembly_info: environment: instaapiuserpassword: secure: 7eAl+O5i5BxXWexd26z+wg== - + artifacts: - path: InstaSharper\bin\$(configuration)\netstandard1.6\*.dll From d038c1c8d6c98b6f5e60a9fae3f2b75dd4b0c2df Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Sat, 10 Dec 2016 17:07:53 +0300 Subject: [PATCH 21/23] added user tags and likers in media --- InstaSharper.Tests/Properties/AssemblyInfo.cs | 3 + .../Tests/ApiInstanceBuilderTest.cs | 1 + InstaSharper.Tests/Tests/AuthTest.cs | 1 + InstaSharper.Tests/Tests/DiscoverTest.cs | 1 + InstaSharper.Tests/Tests/FeedTest.cs | 22 +++++++ InstaSharper.Tests/Tests/FollowersTest.cs | 1 + InstaSharper.Tests/Tests/MediaTest.cs | 1 + InstaSharper.Tests/Tests/UserInfoTest.cs | 1 + InstaSharper/API/IInstaApi.cs | 6 +- InstaSharper/API/InstaApi.cs | 61 ++++++++++++++----- InstaSharper/API/InstaApiConstants.cs | 1 + InstaSharper/Classes/Models/InstaMedia.cs | 4 ++ InstaSharper/Classes/Models/InstaPosition.cs | 14 +++++ InstaSharper/Classes/Models/InstaUserTag.cs | 11 ++++ InstaSharper/Converters/ConvertersFabric.cs | 5 ++ .../Converters/InstaMediaConverter.cs | 2 + .../Converters/InstaUserTagConverter.cs | 21 +++++++ ...rter.cs => InstaMediaListDataConverter.cs} | 8 +-- InstaSharper/Helpers/UriCreator.cs | 10 +++ .../BaseResponse/BaseLoadableResponse.cs | 3 + .../InstaMediaItemResponse.cs | 9 ++- .../InstaUserTagListResponse.cs | 11 ++++ .../ResponseWrappers/InstaUserTagResponse.cs | 16 +++++ 23 files changed, 190 insertions(+), 23 deletions(-) create mode 100644 InstaSharper/Classes/Models/InstaPosition.cs create mode 100644 InstaSharper/Classes/Models/InstaUserTag.cs create mode 100644 InstaSharper/Converters/InstaUserTagConverter.cs rename InstaSharper/Converters/Json/{InstaExploreFeedDataConverter.cs => InstaMediaListDataConverter.cs} (83%) create mode 100644 InstaSharper/ResponseWrappers/InstaUserTagListResponse.cs create mode 100644 InstaSharper/ResponseWrappers/InstaUserTagResponse.cs diff --git a/InstaSharper.Tests/Properties/AssemblyInfo.cs b/InstaSharper.Tests/Properties/AssemblyInfo.cs index 9fcac688..6ce07dda 100644 --- a/InstaSharper.Tests/Properties/AssemblyInfo.cs +++ b/InstaSharper.Tests/Properties/AssemblyInfo.cs @@ -1,5 +1,6 @@ using System.Reflection; using System.Runtime.InteropServices; +using Xunit; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information @@ -9,6 +10,8 @@ [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("InstaSharper.Tests")] [assembly: AssemblyTrademark("")] +[assembly: CollectionBehavior(DisableTestParallelization = true)] + // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from diff --git a/InstaSharper.Tests/Tests/ApiInstanceBuilderTest.cs b/InstaSharper.Tests/Tests/ApiInstanceBuilderTest.cs index 7c4d6964..82e45152 100644 --- a/InstaSharper.Tests/Tests/ApiInstanceBuilderTest.cs +++ b/InstaSharper.Tests/Tests/ApiInstanceBuilderTest.cs @@ -4,6 +4,7 @@ namespace InstaSharper.Tests.Tests { + [Collection("InstaSharper Tests")] public class ApiInstanceBuilderTest { [Fact] diff --git a/InstaSharper.Tests/Tests/AuthTest.cs b/InstaSharper.Tests/Tests/AuthTest.cs index 45359d1c..a631a4a1 100644 --- a/InstaSharper.Tests/Tests/AuthTest.cs +++ b/InstaSharper.Tests/Tests/AuthTest.cs @@ -6,6 +6,7 @@ namespace InstaSharper.Tests.Tests { + [Collection("InstaSharper Tests")] public class AuthTest { public AuthTest(ITestOutputHelper output) diff --git a/InstaSharper.Tests/Tests/DiscoverTest.cs b/InstaSharper.Tests/Tests/DiscoverTest.cs index c577ca87..c9c3acd0 100644 --- a/InstaSharper.Tests/Tests/DiscoverTest.cs +++ b/InstaSharper.Tests/Tests/DiscoverTest.cs @@ -6,6 +6,7 @@ namespace InstaSharper.Tests.Tests { + [Collection("InstaSharper Tests")] public class DiscoverTest { public DiscoverTest(ITestOutputHelper output) diff --git a/InstaSharper.Tests/Tests/FeedTest.cs b/InstaSharper.Tests/Tests/FeedTest.cs index 0477abab..b0dc4588 100644 --- a/InstaSharper.Tests/Tests/FeedTest.cs +++ b/InstaSharper.Tests/Tests/FeedTest.cs @@ -6,6 +6,7 @@ namespace InstaSharper.Tests.Tests { + [Collection("InstaSharper Tests")] public class FeedTest { public FeedTest(ITestOutputHelper output) @@ -38,6 +39,27 @@ public async void GetTagFeedTest(string tag) Assert.NotNull(tagFeed); } + + [Theory] + [InlineData("rock")] + public async void GetUserTagFeedTest(string username) + { + //arrange + var apiInstance = + TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = _username, + Password = _password + }); + //act + if (!TestHelpers.Login(apiInstance, _output)) return; + var result = await apiInstance.GetUserTagsAsync(username, 5); + var tagFeed = result.Value; + //assert + Assert.True(result.Succeeded); + Assert.NotNull(tagFeed); + } + [Fact] public async void GetUserFeedTest() { diff --git a/InstaSharper.Tests/Tests/FollowersTest.cs b/InstaSharper.Tests/Tests/FollowersTest.cs index 8e6813d8..679000a7 100644 --- a/InstaSharper.Tests/Tests/FollowersTest.cs +++ b/InstaSharper.Tests/Tests/FollowersTest.cs @@ -6,6 +6,7 @@ namespace InstaSharper.Tests.Tests { + [Collection("InstaSharper Tests")] public class FollowersTest { public FollowersTest(ITestOutputHelper output) diff --git a/InstaSharper.Tests/Tests/MediaTest.cs b/InstaSharper.Tests/Tests/MediaTest.cs index 0f1deb0f..ea791835 100644 --- a/InstaSharper.Tests/Tests/MediaTest.cs +++ b/InstaSharper.Tests/Tests/MediaTest.cs @@ -6,6 +6,7 @@ namespace InstaSharper.Tests.Tests { + [Collection("InstaSharper Tests")] public class MediaTest { private readonly ITestOutputHelper _output; diff --git a/InstaSharper.Tests/Tests/UserInfoTest.cs b/InstaSharper.Tests/Tests/UserInfoTest.cs index 06415e6b..c5ee9869 100644 --- a/InstaSharper.Tests/Tests/UserInfoTest.cs +++ b/InstaSharper.Tests/Tests/UserInfoTest.cs @@ -6,6 +6,7 @@ namespace InstaSharper.Tests.Tests { + [Collection("InstaSharper Tests")] public class UserInfoTest { public UserInfoTest(ITestOutputHelper output) diff --git a/InstaSharper/API/IInstaApi.cs b/InstaSharper/API/IInstaApi.cs index 1fd8761a..e31e28b6 100644 --- a/InstaSharper/API/IInstaApi.cs +++ b/InstaSharper/API/IInstaApi.cs @@ -29,8 +29,8 @@ public interface IInstaApi IResult GetTagFeed(string tag, int maxPages = 0); - IResult Expole(int maxPages = 0); - IResult GetUserTags(int maxPages = 0); + IResult GetExploreFeed(int maxPages = 0); + IResult GetUserTags(string username, int maxPages = 0); #endregion @@ -47,7 +47,7 @@ public interface IInstaApi Task> GetCurrentUserFollowersAsync(int maxPages = 0); Task> GetExploreFeedAsync(int maxPages = 0); - Task> GetUserTagsAsync(int maxPages = 0); + Task> GetUserTagsAsync(string username, int maxPages = 0); #endregion } diff --git a/InstaSharper/API/InstaApi.cs b/InstaSharper/API/InstaApi.cs index a9dd79d1..ac1b7f0d 100644 --- a/InstaSharper/API/InstaApi.cs +++ b/InstaSharper/API/InstaApi.cs @@ -86,14 +86,14 @@ public IResult GetTagFeed(string tag, int maxPages = 0) return GetTagFeedAsync(tag, maxPages).Result; } - public IResult Expole(int maxPages = 0) + public IResult GetExploreFeed(int maxPages = 0) { - throw new NotImplementedException(); + return GetExploreFeedAsync(maxPages).Result; } - public IResult GetUserTags(int maxPages = 0) + public IResult GetUserTags(string username, int maxPages = 0) { - throw new NotImplementedException(); + return GetUserTagsAsync(username, maxPages).Result; } public IResult GetCurentUserFollowers(int maxPages = 0) @@ -114,7 +114,7 @@ public async Task> GetMediaByCodeAsync(string postCode) var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) { - var mediaResponse = JsonConvert.DeserializeObject(json); + var mediaResponse = JsonConvert.DeserializeObject(json, new InstaMediaListDataConverter()); if (mediaResponse.Medias?.Count != 1) { string errorMessage = $"Got wrong media count for request with media id={postCode}"; @@ -234,7 +234,7 @@ public async Task> GetExploreFeedAsync(int maxPages = 0) var json = await response.Content.ReadAsStringAsync(); var exploreFeed = new InstaFeed(); if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaFeed)null); - var mediaResponse = JsonConvert.DeserializeObject(json, new InstaExploreFeedDataConverter()); + var mediaResponse = JsonConvert.DeserializeObject(json, new InstaMediaListDataConverter()); exploreFeed.Medias.AddRange(mediaResponse.Medias.Select(ConvertersFabric.GetSingleMediaConverter).Select(converter => converter.Convert())); exploreFeed.Stories.AddRange(mediaResponse.Stories.Select(ConvertersFabric.GetSingleStoryConverter).Select(converter => converter.Convert())); var pages = 1; @@ -248,9 +248,40 @@ public async Task> GetExploreFeedAsync(int maxPages = 0) } } - public Task> GetUserTagsAsync(int maxPages = 0) + public async Task> GetUserTagsAsync(string username, int maxPages = 0) { - throw new NotImplementedException(); + ValidateUser(); + ValidateLoggedIn(); + try + { + if (maxPages == 0) maxPages = int.MaxValue; + var user = await GetUserAsync(username); + if (!user.Succeeded || string.IsNullOrEmpty(user.Value.Pk)) return Result.Fail($"Unable to get user {username}", (InstaMediaList)null); + var uri = UriCreator.GetUserTagsUri(user.Value?.Pk, _user.RankToken); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + var userTags = new InstaMediaList(); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaMediaList)null); + var mediaResponse = JsonConvert.DeserializeObject(json, new InstaMediaListDataConverter()); + var nextId = mediaResponse.NextMaxId; + userTags.AddRange(mediaResponse.Medias.Select(ConvertersFabric.GetSingleMediaConverter).Select(converter => converter.Convert())); + var pages = 1; + while (!string.IsNullOrEmpty(nextId) && (pages < maxPages)) + { + uri = UriCreator.GetUserTagsUri(user.Value?.Pk, _user.RankToken, nextId); + var nextMedia = await GetUserMediaListWithMaxIdAsync(uri); + if (!nextMedia.Succeeded) Result.Success($"Not all pages was downloaded: {nextMedia.Message}", userTags); + nextId = nextMedia.Value.NextMaxId; + userTags.AddRange(mediaResponse.Medias.Select(ConvertersFabric.GetSingleMediaConverter).Select(converter => converter.Convert())); + pages++; + } + return Result.Success(userTags); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaMediaList)null); + } } public async Task> GetUserFollowersAsync(string username, int maxPages = 0) @@ -334,7 +365,7 @@ public async Task> GetTagFeedAsync(string tag, int maxPages = var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) { - var feedResponse = JsonConvert.DeserializeObject(json); + var feedResponse = JsonConvert.DeserializeObject(json, new InstaMediaListDataConverter()); var converter = ConvertersFabric.GetMediaListConverter(feedResponse); var tagFeed = new InstaFeed(); tagFeed.Medias.AddRange(converter.Convert()); @@ -366,7 +397,7 @@ private async Task> GetTagFeedWithMaxIdAsync(str var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) { - var feedResponse = JsonConvert.DeserializeObject(json); + var feedResponse = JsonConvert.DeserializeObject(json, new InstaMediaListDataConverter()); return Result.Success(feedResponse); } return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaListResponse)null); @@ -388,13 +419,14 @@ public async Task> GetUserMediaAsync(string username, in var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) { - var mediaResponse = JsonConvert.DeserializeObject(json); + var mediaResponse = JsonConvert.DeserializeObject(json, new InstaMediaListDataConverter()); var converter = ConvertersFabric.GetMediaListConverter(mediaResponse); var mediaList = converter.Convert(); var nextId = mediaResponse.NextMaxId; while (mediaResponse.MoreAvailable && (mediaList.Pages < maxPages)) { - var nextMedia = await GetUserMediaListWithMaxIdAsync(user.Pk, nextId); + instaUri = UriCreator.GetMediaListWithMaxIdUri(user.Pk, nextId); + var nextMedia = await GetUserMediaListWithMaxIdAsync(instaUri); if (!nextMedia.Succeeded) Result.Success($"Not all pages was downloaded: {nextMedia.Message}", mediaList); nextId = nextMedia.Value.NextMaxId; mediaList.AddRange(converter.Convert()); @@ -534,15 +566,14 @@ private async Task> GetUserFeedWithMaxIdAsync(string return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeedResponse)null); } - private async Task> GetUserMediaListWithMaxIdAsync(string userPk, string nextId) + private async Task> GetUserMediaListWithMaxIdAsync(Uri instaUri) { - var instaUri = UriCreator.GetMediaListWithMaxIdUri(userPk, nextId); var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) { - var mediaResponse = JsonConvert.DeserializeObject(json); + var mediaResponse = JsonConvert.DeserializeObject(json, new InstaMediaListDataConverter()); return Result.Success(mediaResponse); } return Result.Fail("", (InstaMediaListResponse)null); diff --git a/InstaSharper/API/InstaApiConstants.cs b/InstaSharper/API/InstaApiConstants.cs index 6a2394a1..e4efd530 100644 --- a/InstaSharper/API/InstaApiConstants.cs +++ b/InstaSharper/API/InstaApiConstants.cs @@ -21,6 +21,7 @@ internal static class InstaApiConstants public const string EXPLORE = API_SUFFIX + "/v1/discover/explore/"; public const string TIMELINEFEED = API_SUFFIX + "/v1/feed/timeline"; public const string USEREFEED = API_SUFFIX + "/v1/feed/user/"; + public const string GET_USER_TAGS = API_SUFFIX + "/v1/usertags/{0}/feed/"; public const string GET_MEDIA = API_SUFFIX + "/v1/media/{0}/info/"; public const string GET_USER_FOLLOWERS = API_SUFFIX + "/v1/friendships/{0}/followers/?rank_token={1}"; public const string GET_TAG_FEED = API_SUFFIX + "/v1/feed/tag/{0}"; diff --git a/InstaSharper/Classes/Models/InstaMedia.cs b/InstaSharper/Classes/Models/InstaMedia.cs index 77f2c4a7..5ec85af7 100644 --- a/InstaSharper/Classes/Models/InstaMedia.cs +++ b/InstaSharper/Classes/Models/InstaMedia.cs @@ -46,5 +46,9 @@ public class InstaMedia public bool PhotoOfYou { get; set; } public bool HasLiked { get; set; } + + public List Tags { get; set; } = new List(); + + public InstaUserList Likers { get; set; } = new InstaUserList(); } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaPosition.cs b/InstaSharper/Classes/Models/InstaPosition.cs new file mode 100644 index 00000000..cfaf062a --- /dev/null +++ b/InstaSharper/Classes/Models/InstaPosition.cs @@ -0,0 +1,14 @@ +namespace InstaSharper.Classes.Models +{ + public class InstaPosition + { + public InstaPosition(double x, double y) + { + X = x; + Y = y; + } + + public double X { get; set; } + public double Y { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaUserTag.cs b/InstaSharper/Classes/Models/InstaUserTag.cs new file mode 100644 index 00000000..8f04d1cb --- /dev/null +++ b/InstaSharper/Classes/Models/InstaUserTag.cs @@ -0,0 +1,11 @@ +namespace InstaSharper.Classes.Models +{ + public class InstaUserTag + { + public InstaPosition Position { get; set; } + + public string TimeInVideo { get; set; } + + public InstaUser User { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/ConvertersFabric.cs b/InstaSharper/Converters/ConvertersFabric.cs index 6d8f8ef7..db360755 100644 --- a/InstaSharper/Converters/ConvertersFabric.cs +++ b/InstaSharper/Converters/ConvertersFabric.cs @@ -41,5 +41,10 @@ public static IObjectConverter GetSingleStoryCon { return new InstaStoryConverter {SourceObject = storyResponse}; } + + public static IObjectConverter GetUserTagConverter(InstaUserTagResponse tag) + { + return new InstaUserTagConverter {SourceObject = tag}; + } } } \ No newline at end of file diff --git a/InstaSharper/Converters/InstaMediaConverter.cs b/InstaSharper/Converters/InstaMediaConverter.cs index 39cc3713..f8f5aa3b 100644 --- a/InstaSharper/Converters/InstaMediaConverter.cs +++ b/InstaSharper/Converters/InstaMediaConverter.cs @@ -33,6 +33,8 @@ public InstaMedia Convert() if (SourceObject.User != null) media.User = ConvertersFabric.GetUserConverter(SourceObject.User).Convert(); if (SourceObject.Caption != null) media.Caption = ConvertersFabric.GetCaptionConverter(SourceObject.Caption).Convert(); if (SourceObject.NextMaxId != null) media.NextMaxId = SourceObject.NextMaxId; + if (SourceObject.Likers?.Count > 0) foreach (var liker in SourceObject.Likers) media.Likers.Add(ConvertersFabric.GetUserConverter(liker).Convert()); + if (SourceObject.UserTagList?.In?.Count > 0) foreach (var tag in SourceObject.UserTagList.In) media.Tags.Add(ConvertersFabric.GetUserTagConverter(tag).Convert()); if (SourceObject.Images?.Candidates == null) return media; foreach (var image in SourceObject.Images.Candidates) media.Images.Add(new Image(image.Url, image.Width, image.Height)); return media; diff --git a/InstaSharper/Converters/InstaUserTagConverter.cs b/InstaSharper/Converters/InstaUserTagConverter.cs new file mode 100644 index 00000000..8b01604e --- /dev/null +++ b/InstaSharper/Converters/InstaUserTagConverter.cs @@ -0,0 +1,21 @@ +using System; +using InstaSharper.Classes.Models; +using InstaSharper.ResponseWrappers; + +namespace InstaSharper.Converters +{ + internal class InstaUserTagConverter : IObjectConverter + { + public InstaUserTagResponse SourceObject { get; set; } + + public InstaUserTag Convert() + { + if (SourceObject == null) throw new ArgumentNullException($"Source object"); + var userTag = new InstaUserTag(); + if (SourceObject.Position?.Length == 2) userTag.Position = new InstaPosition(SourceObject.Position[0], SourceObject.Position[1]); + userTag.TimeInVideo = SourceObject.TimeInVideo; + if (SourceObject.User != null) userTag.User = ConvertersFabric.GetUserConverter(SourceObject.User).Convert(); + return userTag; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/Json/InstaExploreFeedDataConverter.cs b/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs similarity index 83% rename from InstaSharper/Converters/Json/InstaExploreFeedDataConverter.cs rename to InstaSharper/Converters/Json/InstaMediaListDataConverter.cs index 2d60b988..8c76c840 100644 --- a/InstaSharper/Converters/Json/InstaExploreFeedDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs @@ -5,7 +5,7 @@ namespace InstaSharper.Converters.Json { - public class InstaExploreFeedDataConverter : JsonConverter + public class InstaMediaListDataConverter : JsonConverter { public override bool CanConvert(Type objectType) { @@ -22,9 +22,9 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist var storiesTray = root.SelectToken("items[0].stories.tray"); foreach (var item in items) { - var media = item["media"]; - if (media == null) continue; - feed.Medias.Add(media.ToObject()); + var media = item["media"]?.ToObject(); + if (media == null) media = item.ToObject(); + feed.Medias.Add(media); } if (storiesTray == null) return feed; foreach (var storyItem in storiesTray) diff --git a/InstaSharper/Helpers/UriCreator.cs b/InstaSharper/Helpers/UriCreator.cs index 9ad969ed..07abdf98 100644 --- a/InstaSharper/Helpers/UriCreator.cs +++ b/InstaSharper/Helpers/UriCreator.cs @@ -94,5 +94,15 @@ public static Uri GetExploreUri() if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.EXPLORE, out instaUri)) throw new Exception("Cant create URI for explore posts"); return instaUri; } + + public static Uri GetUserTagsUri(string userPk, string rankToken, string maxId = null) + { + Uri instaUri; + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_TAGS, userPk), out instaUri)) throw new Exception("Cant create URI for get user tags"); + string query = $"rank_token={rankToken}&ranked_content=true"; + if (!string.IsNullOrEmpty(maxId)) query += $"max_id={maxId}"; + var uriBuilder = new UriBuilder(instaUri) {Query = query}; + return uriBuilder.Uri; + } } } \ No newline at end of file diff --git a/InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs b/InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs index a1d0cd3d..42c73d3a 100644 --- a/InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs +++ b/InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs @@ -10,6 +10,9 @@ internal class BaseLoadableResponse : BaseStatusResponse [JsonProperty("num_results")] public int ResultsCount { get; set; } + [JsonProperty("total_count")] + public int TotalCount { get; set; } + [JsonProperty("auto_load_more_enabled")] public bool AutoLoadMoreEnabled { get; set; } diff --git a/InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs b/InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs index e417f641..79cea2f4 100644 --- a/InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs +++ b/InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs @@ -1,4 +1,5 @@ -using InstaSharper.Classes.Models; +using System.Collections.Generic; +using InstaSharper.Classes.Models; using Newtonsoft.Json; namespace InstaSharper.ResponseWrappers @@ -65,5 +66,11 @@ internal class InstaMediaItemResponse [JsonProperty("type")] public int Type { get; set; } + + [JsonProperty("usertags")] + public InstaUserTagListResponse UserTagList { get; set; } + + [JsonProperty("likers")] + public List Likers { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/ResponseWrappers/InstaUserTagListResponse.cs b/InstaSharper/ResponseWrappers/InstaUserTagListResponse.cs new file mode 100644 index 00000000..ff3eadcf --- /dev/null +++ b/InstaSharper/ResponseWrappers/InstaUserTagListResponse.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace InstaSharper.ResponseWrappers +{ + internal class InstaUserTagListResponse + { + [JsonProperty("in")] + public List In { get; set; } = new List(); + } +} \ No newline at end of file diff --git a/InstaSharper/ResponseWrappers/InstaUserTagResponse.cs b/InstaSharper/ResponseWrappers/InstaUserTagResponse.cs new file mode 100644 index 00000000..54d3105e --- /dev/null +++ b/InstaSharper/ResponseWrappers/InstaUserTagResponse.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace InstaSharper.ResponseWrappers +{ + internal class InstaUserTagResponse + { + [JsonProperty("position")] + public double[] Position { get; set; } + + [JsonProperty("time_in_video")] + public string TimeInVideo { get; set; } + + [JsonProperty("user")] + public InstaUserResponse User { get; set; } + } +} \ No newline at end of file From 3e61fe672575622ae46fdc8e7a0ebd9a3c51eafa Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Sat, 10 Dec 2016 17:42:21 +0300 Subject: [PATCH 22/23] version 1.2.1 --- InstaSharper.Tests/project.json | 2 +- InstaSharper/project.json | 4 ++-- appveyor.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/InstaSharper.Tests/project.json b/InstaSharper.Tests/project.json index 5e4c3e27..abf9906b 100644 --- a/InstaSharper.Tests/project.json +++ b/InstaSharper.Tests/project.json @@ -3,7 +3,7 @@ "testRunner": "xunit", "dependencies": { "xunit": "2.2.0-beta2-build3300", - "InstaSharper": "1.2.0", + "InstaSharper": "1.2.1", "dotnet-test-xunit": "2.2.0-preview2-build1029" }, "frameworks": { diff --git a/InstaSharper/project.json b/InstaSharper/project.json index e2cd5866..e6e1665c 100644 --- a/InstaSharper/project.json +++ b/InstaSharper/project.json @@ -1,5 +1,5 @@ { - "version": "1.2.0", + "version": "1.2.1", "dependencies": { "NETStandard.Library": "1.6.0", @@ -11,7 +11,7 @@ "imports": "dnxcore50" }, "net452": { - + } } } diff --git a/appveyor.yml b/appveyor.yml index f6b09888..149f889e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.1.{build} +version: 1.2.1 ({build}) os: Visual Studio 2015 platform: Any CPU configuration: Release From 861493ae25ea14dd4ab4e952944e7a7979a10391 Mon Sep 17 00:00:00 2001 From: Alexander Legotin Date: Sat, 10 Dec 2016 17:44:40 +0300 Subject: [PATCH 23/23] ci build --- appveyor.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 149f889e..5502ff8a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -29,13 +29,6 @@ build_script: - ps: dotnet --verbose test -parallel none - ps: cd .. -assembly_info: - patch: true - file: project.json - assembly_version: "{version}" - assembly_file_version: "{version}" - assembly_informational_version: "{version}" - environment: instaapiuserpassword: secure: 7eAl+O5i5BxXWexd26z+wg==