diff --git a/InstaSharper.Tests/Classes/AuthenticatedTestFixture.cs b/InstaSharper.Tests/Classes/AuthenticatedTestFixture.cs new file mode 100644 index 00000000..e4770b35 --- /dev/null +++ b/InstaSharper.Tests/Classes/AuthenticatedTestFixture.cs @@ -0,0 +1,46 @@ +using System; +using System.Threading.Tasks; +using InstaSharper.API; +using InstaSharper.Classes; +using InstaSharper.Tests.Utils; + +namespace InstaSharper.Tests.Classes +{ + public class AuthenticatedTestFixture : IDisposable + { + private readonly string _password = Environment.GetEnvironmentVariable("instaapiuserpassword"); + private readonly string _username = "alex_codegarage"; + + public AuthenticatedTestFixture() + { + ApiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData + { + UserName = _username, + Password = _password + }); + + var loginTask = Task.Run(ApiInstance.LoginAsync); + if (!loginTask.Wait(TimeSpan.FromSeconds(10))) + throw new Exception($"Unable to login, user: {_username}, password: {_password}."); + } + + public IInstaApi ApiInstance { get; } + + public void Dispose() + { + var logoutTask = Task.Run(ApiInstance.LogoutAsync); + if (!logoutTask.Wait(TimeSpan.FromSeconds(10))) + throw new Exception($"Not able to logout, user: {_username}, password: {_password}."); + } + + public string GetUsername() + { + return _username; + } + + public string GetPassword() + { + return _password; + } + } +} \ No newline at end of file diff --git a/InstaSharper.Tests/Utils/RunnableInDebugOnlyFact.cs b/InstaSharper.Tests/Classes/RunnableInDebugOnlyFact.cs similarity index 88% rename from InstaSharper.Tests/Utils/RunnableInDebugOnlyFact.cs rename to InstaSharper.Tests/Classes/RunnableInDebugOnlyFact.cs index d9a216e6..0105a82a 100644 --- a/InstaSharper.Tests/Utils/RunnableInDebugOnlyFact.cs +++ b/InstaSharper.Tests/Classes/RunnableInDebugOnlyFact.cs @@ -1,7 +1,7 @@ using System.Diagnostics; using Xunit; -namespace InstaSharper.Tests.Utils +namespace InstaSharper.Tests.Classes { public sealed class RunnableInDebugOnlyFact : FactAttribute { diff --git a/InstaSharper.Tests/Utils/RunnableInDebugOnlyTheory.cs b/InstaSharper.Tests/Classes/RunnableInDebugOnlyTheory.cs similarity index 88% rename from InstaSharper.Tests/Utils/RunnableInDebugOnlyTheory.cs rename to InstaSharper.Tests/Classes/RunnableInDebugOnlyTheory.cs index cf2d1ac6..878182e5 100644 --- a/InstaSharper.Tests/Utils/RunnableInDebugOnlyTheory.cs +++ b/InstaSharper.Tests/Classes/RunnableInDebugOnlyTheory.cs @@ -1,7 +1,7 @@ using System.Diagnostics; using Xunit; -namespace InstaSharper.Tests.Utils +namespace InstaSharper.Tests.Classes { public sealed class RunnableInDebugOnlyTheory : TheoryAttribute { diff --git a/InstaSharper.Tests/Classes/SkippableFact.cs b/InstaSharper.Tests/Classes/SkippableFact.cs new file mode 100644 index 00000000..2e942666 --- /dev/null +++ b/InstaSharper.Tests/Classes/SkippableFact.cs @@ -0,0 +1,12 @@ +using Xunit; + +namespace InstaSharper.Tests.Classes +{ + public sealed class SkippableFact : FactAttribute + { + public SkippableFact() + { + Skip = "This fact marked as skippable."; + } + } +} \ No newline at end of file diff --git a/InstaSharper.Tests/Endpoints/AuthTest.cs b/InstaSharper.Tests/Endpoints/AuthTest.cs index 76951171..4d0ffae4 100644 --- a/InstaSharper.Tests/Endpoints/AuthTest.cs +++ b/InstaSharper.Tests/Endpoints/AuthTest.cs @@ -9,18 +9,19 @@ namespace InstaSharper.Tests.Endpoints [Collection("Endpoints")] public class AuthTest { - private readonly ITestOutputHelper _output; - public AuthTest(ITestOutputHelper output) { _output = output; } - [RunnableInDebugOnlyFact] + private readonly ITestOutputHelper _output; + + [Fact] public async void UserLoginFailTest() { var username = "alex_codegarage"; var password = "boombaby!"; + var apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData { @@ -28,23 +29,25 @@ public async void UserLoginFailTest() Password = password }); _output.WriteLine("Got API instance"); + var loginResult = await apiInstance.LoginAsync(); Assert.False(loginResult.Succeeded); Assert.False(apiInstance.IsUserAuthenticated); } - [RunnableInDebugOnlyFact] + [Fact] public async void UserLoginSuccessTest() { var username = "alex_codegarage"; var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); + var apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData { UserName = username, Password = password }); - Assert.False(apiInstance.IsUserAuthenticated); + Assert.False(apiInstance.IsUserAuthenticated); var loginResult = await apiInstance.LoginAsync(); Assert.True(loginResult.Succeeded); Assert.True(apiInstance.IsUserAuthenticated); diff --git a/InstaSharper.Tests/Endpoints/DiscoverTest.cs b/InstaSharper.Tests/Endpoints/DiscoverTest.cs index 1db07aa6..aad1617e 100644 --- a/InstaSharper.Tests/Endpoints/DiscoverTest.cs +++ b/InstaSharper.Tests/Endpoints/DiscoverTest.cs @@ -1,37 +1,23 @@ -using System; -using InstaSharper.Classes; -using InstaSharper.Tests.Utils; +using InstaSharper.Tests.Classes; using Xunit; -using Xunit.Abstractions; namespace InstaSharper.Tests.Endpoints { - [Collection("Endpoints")] - public class DiscoverTest + [Trait("Category", "Endpoint")] + public class DiscoverTest : IClassFixture { - private readonly ITestOutputHelper _output; - private readonly string _password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - private readonly string _username = "alex_codegarage"; - - public DiscoverTest(ITestOutputHelper output) + public DiscoverTest(AuthenticatedTestFixture authInfo) { - _output = output; + _authInfo = authInfo; } - [RunnableInDebugOnlyFact] + private readonly AuthenticatedTestFixture _authInfo; + + [Fact] public async void ExploreTest() { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - var loginSucceed = TestHelpers.Login(apiInstance, _output); - Assert.True(loginSucceed); - var result = await apiInstance.GetExploreFeedAsync(0); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var result = await _authInfo.ApiInstance.GetExploreFeedAsync(2); var exploreGeed = result.Value; //assert Assert.True(result.Succeeded); diff --git a/InstaSharper.Tests/Endpoints/FeedTest.cs b/InstaSharper.Tests/Endpoints/FeedTest.cs index a4bbd0da..0aa1ab73 100644 --- a/InstaSharper.Tests/Endpoints/FeedTest.cs +++ b/InstaSharper.Tests/Endpoints/FeedTest.cs @@ -1,47 +1,26 @@ -using System; -using System.Linq; -using InstaSharper.Classes; -using InstaSharper.Tests.Utils; +using System.Linq; +using InstaSharper.Tests.Classes; using Xunit; -using Xunit.Abstractions; namespace InstaSharper.Tests.Endpoints { - [Collection("Endpoints")] - public class FeedTest + [Trait("Category", "Endpoint")] + public class FeedTest : IClassFixture { - private readonly ITestOutputHelper _output; - private readonly string _password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - private readonly string _username = "alex_codegarage"; - - public FeedTest(ITestOutputHelper output) + public FeedTest(AuthenticatedTestFixture authInfo) { - _output = output; + _authInfo = authInfo; } - [RunnableInDebugOnlyTheory] + private readonly AuthenticatedTestFixture _authInfo; + + [Theory] [InlineData("christmas")] public async void GetTagFeedTest(string tag) { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - var loginSucceed = await apiInstance.LoginAsync(); - //no need to perform test if account marked as unsafe - if (loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.RequestsLimit) - { - _output.WriteLine("Unable to login: limit reached or checkpoint required"); - return; - } - Assert.True(loginSucceed.Succeeded); - var result = await apiInstance.GetTagFeedAsync(tag, 10); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var result = await _authInfo.ApiInstance.GetTagFeedAsync(tag, 10); var tagFeed = result.Value; var anyMediaDuplicate = tagFeed.Medias.GroupBy(x => x.Code).Any(g => g.Count() > 1); var anyStoryDuplicate = tagFeed.Stories.GroupBy(x => x.Id).Any(g => g.Count() > 1); @@ -53,29 +32,13 @@ public async void GetTagFeedTest(string tag) } - [RunnableInDebugOnlyTheory] + [Theory] [InlineData("rock")] public async void GetUserTagFeedTest(string username) { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - var loginSucceed = await apiInstance.LoginAsync(); - //no need to perform test if account marked as unsafe - if (loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.RequestsLimit) - { - _output.WriteLine("Unable to login: limit reached or checkpoint required"); - return; - } - Assert.True(loginSucceed.Succeeded); - var result = await apiInstance.GetUserTagsAsync(username, 5); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var result = await _authInfo.ApiInstance.GetUserTagsAsync(username, 5); var tagFeed = result.Value; var anyMediaDuplicate = tagFeed.GroupBy(x => x.Code).Any(g => g.Count() > 1); //assert @@ -84,29 +47,12 @@ public async void GetUserTagFeedTest(string username) Assert.False(anyMediaDuplicate); } - [RunnableInDebugOnlyFact] + [Fact] public async void GetFollowingRecentActivityFeedTest() { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - //no need to perform test if account marked as unsafe - var loginSucceed = await apiInstance.LoginAsync(); - //no need to perform test if account marked as unsafe - if (loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.RequestsLimit) - { - _output.WriteLine("Unable to login: limit reached or checkpoint required"); - return; - } - Assert.True(loginSucceed.Succeeded); - var getFeedResult = await apiInstance.GetFollowingRecentActivityAsync(5); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var getFeedResult = await _authInfo.ApiInstance.GetFollowingRecentActivityAsync(5); var folloowingRecentFeed = getFeedResult.Value; //assert @@ -115,28 +61,12 @@ public async void GetFollowingRecentActivityFeedTest() Assert.True(!folloowingRecentFeed.IsOwnActivity); } - [RunnableInDebugOnlyFact] + [Fact] public async void GetRecentActivityFeedTest() { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - var loginSucceed = await apiInstance.LoginAsync(); - //no need to perform test if account marked as unsafe - if (loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.RequestsLimit) - { - _output.WriteLine("Unable to login: limit reached or checkpoint required"); - return; - } - Assert.True(loginSucceed.Succeeded); - var getFeedResult = await apiInstance.GetRecentActivityAsync(5); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var getFeedResult = await _authInfo.ApiInstance.GetRecentActivityAsync(5); var ownRecentFeed = getFeedResult.Value; //assert Assert.True(getFeedResult.Succeeded); @@ -144,28 +74,12 @@ public async void GetRecentActivityFeedTest() Assert.True(ownRecentFeed.IsOwnActivity); } - [RunnableInDebugOnlyFact] + [Fact] public async void GetUserFeedTest() { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - var loginSucceed = await apiInstance.LoginAsync(); - //no need to perform test if account marked as unsafe - if (loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.RequestsLimit) - { - _output.WriteLine("Unable to login: limit reached or checkpoint required"); - return; - } - Assert.True(loginSucceed.Succeeded); - var getFeedResult = await apiInstance.GetUserTimelineFeedAsync(5); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var getFeedResult = await _authInfo.ApiInstance.GetUserTimelineFeedAsync(5); var feed = getFeedResult.Value; var anyDuplicate = feed.Medias.GroupBy(x => x.Code).Any(g => g.Count() > 1); var anyStoryDuplicate = feed.Stories.GroupBy(x => x.Id).Any(g => g.Count() > 1); @@ -176,5 +90,20 @@ public async void GetUserFeedTest() Assert.False(anyDuplicate); Assert.False(anyStoryDuplicate); } + + [Fact] + public async void GetUserLikeFeedTest() + { + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var getFeedResult = await _authInfo.ApiInstance.GetLikeFeedAsync(2); + var feed = getFeedResult.Value; + var anyDuplicate = feed.GroupBy(x => x.Code).Any(g => g.Count() > 1); + + //assert + Assert.True(getFeedResult.Succeeded); + Assert.NotNull(feed); + Assert.False(anyDuplicate); + } } } \ No newline at end of file diff --git a/InstaSharper.Tests/Endpoints/FollowersTest.cs b/InstaSharper.Tests/Endpoints/FollowersTest.cs index f1201f79..89189a82 100644 --- a/InstaSharper.Tests/Endpoints/FollowersTest.cs +++ b/InstaSharper.Tests/Endpoints/FollowersTest.cs @@ -1,35 +1,26 @@ -using System; -using System.Linq; -using InstaSharper.Classes; -using InstaSharper.Tests.Utils; +using System.Linq; +using InstaSharper.Tests.Classes; using Xunit; -using Xunit.Abstractions; namespace InstaSharper.Tests.Endpoints { - [Collection("Endpoints")] - public class FollowersTest + [Trait("Category", "Endpoint")] + public class FollowersTest : IClassFixture { - private readonly ITestOutputHelper _output; - - public FollowersTest(ITestOutputHelper output) + public FollowersTest(AuthenticatedTestFixture authInfo) { - _output = output; + _authInfo = authInfo; } - [RunnableInDebugOnlyTheory] + private readonly AuthenticatedTestFixture _authInfo; + + [Theory] [InlineData("therock")] public async void GetUserFollowersTest(string username) { - 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); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var result = await _authInfo.ApiInstance.GetUserFollowersAsync(username, 10); var followers = result.Value; var anyDuplicate = followers.GroupBy(x => x.Pk).Any(g => g.Count() > 1); @@ -39,38 +30,30 @@ public async void GetUserFollowersTest(string username) Assert.False(anyDuplicate); } - [RunnableInDebugOnlyFact] - public async void GetCurrentUserFollwersTest() + [Theory] + [InlineData("therock")] + public async void GetUserFollowingTest(string username) { - 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; - var result = await apiInstance.GetCurrentUserFollowersAsync(); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var result = await _authInfo.ApiInstance.GetUserFollowingAsync(username, 10); var followers = result.Value; + var anyDuplicate = followers.GroupBy(x => x.Pk).Any(g => g.Count() > 1); + //assert Assert.True(result.Succeeded); Assert.NotNull(followers); + Assert.False(anyDuplicate); } - [RunnableInDebugOnlyTheory] + [Theory] [InlineData(196754384)] public async void FollowUnfollowUserTest(long userId) { - var currentUsername = "alex_codegarage"; - var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - var apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = currentUsername, - Password = password - }); - if (!TestHelpers.Login(apiInstance, _output)) throw new Exception("Not logged in"); - var followResult = await apiInstance.FollowUserAsync(userId); - var unFollowResult = await apiInstance.UnFollowUserAsync(userId); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var followResult = await _authInfo.ApiInstance.FollowUserAsync(userId); + var unFollowResult = await _authInfo.ApiInstance.UnFollowUserAsync(userId); //assert Assert.True(followResult.Succeeded); Assert.True(unFollowResult.Succeeded); @@ -78,5 +61,17 @@ public async void FollowUnfollowUserTest(long userId) Assert.True(followResult.Value.Following); Assert.False(unFollowResult.Value.Following); } + + [Fact] + public async void GetCurrentUserFollwersTest() + { + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var result = await _authInfo.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/Endpoints/LikesTest.cs b/InstaSharper.Tests/Endpoints/LikesTest.cs index 8dc02223..a0cf4fe3 100644 --- a/InstaSharper.Tests/Endpoints/LikesTest.cs +++ b/InstaSharper.Tests/Endpoints/LikesTest.cs @@ -1,38 +1,26 @@ -using System; -using InstaSharper.Classes; -using InstaSharper.Tests.Utils; +using InstaSharper.Tests.Classes; using Xunit; -using Xunit.Abstractions; namespace InstaSharper.Tests.Endpoints { - [Collection("Endpoints")] - public class LikesTest + [Trait("Category", "Endpoint")] + public class LikesTest : IClassFixture { - private readonly ITestOutputHelper _output; - private readonly string _password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - private readonly string _username = "alex_codegarage"; + private readonly AuthenticatedTestFixture _authInfo; - public LikesTest(ITestOutputHelper output) + public LikesTest(AuthenticatedTestFixture authInfo) { - _output = output; + _authInfo = authInfo; } - [RunnableInDebugOnlyTheory] + [Theory] [InlineData("1484832969772514291_196754384")] public async void LikeUnlikeTest(string mediaId) { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - if (!TestHelpers.Login(apiInstance, _output)) throw new Exception("Not logged in"); - //act - var likeResult = await apiInstance.LikeMediaAsync(mediaId); - var unLikeResult = await apiInstance.UnLikeMediaAsync(mediaId); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var likeResult = await _authInfo.ApiInstance.LikeMediaAsync(mediaId); + var unLikeResult = await _authInfo.ApiInstance.UnLikeMediaAsync(mediaId); //assert Assert.True(likeResult.Succeeded); Assert.True(unLikeResult.Succeeded); diff --git a/InstaSharper.Tests/Endpoints/MediaTest.cs b/InstaSharper.Tests/Endpoints/MediaTest.cs index ad9cd2d5..ab06ff21 100644 --- a/InstaSharper.Tests/Endpoints/MediaTest.cs +++ b/InstaSharper.Tests/Endpoints/MediaTest.cs @@ -1,140 +1,107 @@ using System; using System.Linq; -using InstaSharper.Classes; -using InstaSharper.Tests.Utils; +using InstaSharper.Classes.Models; +using InstaSharper.Tests.Classes; using Xunit; -using Xunit.Abstractions; namespace InstaSharper.Tests.Endpoints { - [Collection("Endpoints")] - public class MediaTest + [Trait("Category", "Endpoint")] + public class MediaTest : IClassFixture { - private readonly ITestOutputHelper _output; + private readonly AuthenticatedTestFixture _authInfo; - public MediaTest(ITestOutputHelper output) + public MediaTest(AuthenticatedTestFixture authInfo) { - _output = output; + _authInfo = authInfo; } - [RunnableInDebugOnlyTheory] + [Theory] [InlineData("1484832969772514291")] public async void GetMediaByIdTest(string mediaId) { - //arrange - 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}"); - var media = await apiInstance.GetMediaByIdAsync(mediaId); - //assert + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var media = await _authInfo.ApiInstance.GetMediaByIdAsync(mediaId); Assert.NotNull(media); } - [RunnableInDebugOnlyTheory] + [Theory] [InlineData("1379932752706850783")] public async void GetMediaLikersTest(string mediaId) { - //arrange - 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 [{mediaId}] likers"); - var likers = await apiInstance.GetMediaLikersAsync(mediaId); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var likers = await _authInfo.ApiInstance.GetMediaLikersAsync(mediaId); var anyDuplicate = likers.Value.GroupBy(x => x.Pk).Any(g => g.Count() > 1); - //assert Assert.NotNull(likers); Assert.False(anyDuplicate); } - [RunnableInDebugOnlyTheory] + [Theory] [InlineData("1379932752706850783")] public async void GetMediaCommentsTest(string mediaId) { - //arrange - 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 [{mediaId}] comments"); - var comments = await apiInstance.GetMediaCommentsAsync(mediaId, 0); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var comments = await _authInfo.ApiInstance.GetMediaCommentsAsync(mediaId, 3); + var anyDuplicate = comments.Value.Comments.GroupBy(x => x.Pk).Any(g => g.Count() > 1); - //assert + Assert.NotNull(comments); Assert.False(anyDuplicate); } - [RunnableInDebugOnlyTheory] + [Theory] [InlineData("alex_codegarage")] public async void GetUserMediaListTest(string userToFetch) { - //arrange - 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 = 5; - //act - _output.WriteLine($"Trying to login as user: {username}"); - if (!TestHelpers.Login(apiInstance, _output)) return; - _output.WriteLine($"Getting posts of user: {userToFetch}"); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var random = new Random(DateTime.Now.Millisecond); - var posts = await apiInstance.GetUserMediaAsync(userToFetch, pages); + var posts = await _authInfo.ApiInstance.GetUserMediaAsync(userToFetch, 3); var anyDuplicate = posts.Value.GroupBy(x => x.Code).Any(g => g.Count() > 1); - //assert Assert.NotNull(posts); Assert.Equal(userToFetch, posts.Value[random.Next(0, posts.Value.Count)].User.UserName); Assert.False(anyDuplicate); } - [RunnableInDebugOnlyTheory] + [Theory] [InlineData("1484832969772514291_196754384")] public async void PostDeleteCommentTest(string mediaId) { - //arrange - var username = "alex_codegarage"; - var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - var apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = username, - Password = password - }); - var text = "test comment"; - //act - if (!TestHelpers.Login(apiInstance, _output)) return; - - var postResult = await apiInstance.CommentMediaAsync(mediaId, text); - var delResult = await apiInstance.DeleteCommentAsync(mediaId, postResult.Value.Pk); - //assert + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var text = "Test comment"; + var postResult = await _authInfo.ApiInstance.CommentMediaAsync(mediaId, text); + var delResult = await _authInfo.ApiInstance.DeleteCommentAsync(mediaId, postResult.Value.Pk); Assert.True(postResult.Succeeded); Assert.Equal(text, postResult.Value.Text); Assert.True(delResult.Succeeded); + } + [Theory] + [InlineData("1510405963000000025_1414585238", InstaMediaType.Image)] + public async void DeleteMediaPhotoTest(string mediaId, InstaMediaType mediaType) + { + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var deleteMediaPhoto = await _authInfo.ApiInstance.DeleteMediaAsync(mediaId, mediaType); + Assert.False(deleteMediaPhoto.Value); + } + + [Theory] + [InlineData("1510414591769980888_1414585238", InstaMediaType.Video)] + public async void DeleteMediaVideoTest(string mediaId, InstaMediaType mediaType) + { + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var deleteMediaVideo = await _authInfo.ApiInstance.DeleteMediaAsync(mediaId, mediaType); + Assert.True(deleteMediaVideo.Value); + } + + [Theory] + [InlineData("1513736003209429255_1414585238", "Hello!")] + public async void EditMediaTest(string mediaId, string caption) + { + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var editMedia = await _authInfo.ApiInstance.EditMediaAsync(mediaId, caption); + Assert.True(editMedia.Value); } } } \ No newline at end of file diff --git a/InstaSharper.Tests/Endpoints/MessagingTest.cs b/InstaSharper.Tests/Endpoints/MessagingTest.cs index d8155395..3400d1ee 100644 --- a/InstaSharper.Tests/Endpoints/MessagingTest.cs +++ b/InstaSharper.Tests/Endpoints/MessagingTest.cs @@ -1,109 +1,52 @@ -using System; -using InstaSharper.Classes; -using InstaSharper.Tests.Utils; +using InstaSharper.Tests.Classes; using Xunit; -using Xunit.Abstractions; namespace InstaSharper.Tests.Endpoints { - [Collection("Endpoints")] - public class MessagingTest + [Trait("Category", "Endpoint")] + public class MessagingTest : IClassFixture { - private readonly ITestOutputHelper _output; - private readonly string _password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - private readonly string _username = "alex_codegarage"; - - public MessagingTest(ITestOutputHelper output) + public MessagingTest(AuthenticatedTestFixture authInfo) { - _output = output; + _authInfo = authInfo; } - [RunnableInDebugOnlyTheory] + private readonly AuthenticatedTestFixture _authInfo; + + [Theory] [InlineData("340282366841710300949128137443944319108")] public async void GetDirectInboxThreadByIdTest(string threadId) { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - if (!TestHelpers.Login(apiInstance, _output)) return; - var result = await apiInstance.GetDirectInboxThreadAsync(threadId); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var result = await _authInfo.ApiInstance.GetDirectInboxThreadAsync(threadId); var thread = result.Value; - //assert Assert.True(result.Succeeded); Assert.NotNull(thread); } - [RunnableInDebugOnlyFact] + [Fact] public async void GetDirectInboxTest() { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - if (!TestHelpers.Login(apiInstance, _output)) return; - var result = await apiInstance.GetDirectInboxAsync(); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var result = await _authInfo.ApiInstance.GetDirectInboxAsync(); var inbox = result.Value; - //assert Assert.True(result.Succeeded); Assert.NotNull(inbox); } - [RunnableInDebugOnlyFact] + [Fact] public async void GetRankedeRecipientsTest() { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - var loginSucceed = await apiInstance.LoginAsync(); - //no need to perform test if account marked as unsafe - if (loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.RequestsLimit) - { - _output.WriteLine("Unable to login: limit reached or checkpoint required"); - return; - } - var result = await apiInstance.GetRankedRecipientsAsync(); - //assert + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var result = await _authInfo.ApiInstance.GetRankedRecipientsAsync(); Assert.True(result.Succeeded); } - [RunnableInDebugOnlyFact] + [Fact] public async void GetRecentRecipientsTest() { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - var loginSucceed = await apiInstance.LoginAsync(); - //no need to perform test if account marked as unsafe - if (loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.LoginRequired - || loginSucceed.Info.ResponseType == ResponseType.RequestsLimit) - { - _output.WriteLine("Unable to login: limit reached or checkpoint required"); - return; - } - var result = await apiInstance.GetRecentRecipientsAsync(); - //assert + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var result = await _authInfo.ApiInstance.GetRecentRecipientsAsync(); Assert.True(result.Succeeded); } } diff --git a/InstaSharper.Tests/Endpoints/StoryTest.cs b/InstaSharper.Tests/Endpoints/StoryTest.cs new file mode 100644 index 00000000..b78415e9 --- /dev/null +++ b/InstaSharper.Tests/Endpoints/StoryTest.cs @@ -0,0 +1,56 @@ +using System; +using InstaSharper.Classes.Models; +using InstaSharper.Tests.Classes; +using Xunit; + +namespace InstaSharper.Tests.Endpoints +{ + [Trait("Category", "Endpoint")] + public class StoryTest : IClassFixture + { + public StoryTest(AuthenticatedTestFixture authInfo) + { + _authInfo = authInfo; + } + + private readonly AuthenticatedTestFixture _authInfo; + + [Theory] + [InlineData(1129166614)] + private async void GetUserStoryTest(long userId) + { + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var result = await _authInfo.ApiInstance.GetUserStoryAsync(userId); + var stories = result.Value; + Assert.True(result.Succeeded); + Assert.NotNull(stories); + } + + [Fact] + private async void GetStoryTrayTest() + { + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var result = await _authInfo.ApiInstance.GetStoryTrayAsync(); + var stories = result.Value; + Assert.True(result.Succeeded); + Assert.NotNull(stories); + } + + [Fact] + public async void UploadStoryImageTest() + { + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var mediaImage = new MediaImage + { + Height = 1200, + Width = 640, + URI = new Uri(@"C:\test.jpg", UriKind.Absolute).LocalPath + }; + var result = await _authInfo.ApiInstance.UploadStoryPhotoAsync(mediaImage, "Lake"); + + Assert.True(result.Succeeded); + Assert.NotNull(result.Value); + } + } +} \ No newline at end of file diff --git a/InstaSharper.Tests/Endpoints/UploadTest.cs b/InstaSharper.Tests/Endpoints/UploadTest.cs index 40712061..dcc7448f 100644 --- a/InstaSharper.Tests/Endpoints/UploadTest.cs +++ b/InstaSharper.Tests/Endpoints/UploadTest.cs @@ -1,48 +1,36 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using InstaSharper.Classes; using InstaSharper.Classes.Models; -using InstaSharper.Tests.Utils; +using InstaSharper.Tests.Classes; using Xunit; -using Xunit.Abstractions; namespace InstaSharper.Tests.Endpoints { - [Collection("Endpoints")] - public class UploadTest + [Trait("Category", "Endpoint")] + public class UploadTest : IClassFixture { - private readonly ITestOutputHelper _output; - - public UploadTest(ITestOutputHelper output) + public UploadTest(AuthenticatedTestFixture authInfo) { - _output = output; + _authInfo = authInfo; } - [RunnableInDebugOnlyFact] + private readonly AuthenticatedTestFixture _authInfo; + + [Fact] public async void UploadImage() { - var currentUsername = "alex_codegarage"; - var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - var apiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = currentUsername, - Password = password - }); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); - if (!TestHelpers.Login(apiInstance, _output)) return; var mediaImage = new MediaImage { Height = 1080, Width = 1080, URI = new Uri(@"D:\Dropbox\Public\Inspire.jpg", UriKind.Absolute).LocalPath }; - var result = await apiInstance.UploadPhotoAsync(mediaImage, "inspire"); - + var result = await _authInfo.ApiInstance.UploadPhotoAsync(mediaImage, "inspire"); + //assert Assert.True(result.Succeeded); Assert.NotNull(result.Value); } } -} +} \ No newline at end of file diff --git a/InstaSharper.Tests/Endpoints/UserInfoTest.cs b/InstaSharper.Tests/Endpoints/UserInfoTest.cs index c87d4820..bebec6a9 100644 --- a/InstaSharper.Tests/Endpoints/UserInfoTest.cs +++ b/InstaSharper.Tests/Endpoints/UserInfoTest.cs @@ -1,78 +1,65 @@ -using System; -using InstaSharper.Classes; -using InstaSharper.Tests.Utils; +using InstaSharper.Tests.Classes; using Xunit; -using Xunit.Abstractions; namespace InstaSharper.Tests.Endpoints { - [Collection("Endpoints")] - public class UserInfoTest + [Trait("Category", "Endpoint")] + public class UserInfoTest : IClassFixture { - private readonly ITestOutputHelper _output; - private readonly string _password = Environment.GetEnvironmentVariable("instaapiuserpassword"); - private readonly string _username = "alex_codegarage"; + public UserInfoTest(AuthenticatedTestFixture authInfo) + { + _authInfo = authInfo; + } + + private readonly AuthenticatedTestFixture _authInfo; - public UserInfoTest(ITestOutputHelper output) + [SkippableFact] + public async void ChangePasswordTest() { - _output = output; + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var password = _authInfo.GetPassword(); + + var resultChangePassword = await _authInfo.ApiInstance.ChangePasswordAsync(password, password); + + Assert.True(resultChangePassword.Succeeded); + Assert.NotNull(resultChangePassword.Value); } - [RunnableInDebugOnlyFact] + [Fact] public async void GetCurrentUserTest() { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - if (!TestHelpers.Login(apiInstance, _output)) return; - var getUserResult = await apiInstance.GetCurrentUserAsync(); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var getUserResult = await _authInfo.ApiInstance.GetCurrentUserAsync(); var user = getUserResult.Value; - //assert + Assert.True(getUserResult.Succeeded); Assert.NotNull(user); - Assert.Equal(user.UserName, _username); + Assert.Equal(user.UserName, _authInfo.GetUsername()); } - [RunnableInDebugOnlyFact] + [Fact] public async void GetUserTest() { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - if (!TestHelpers.Login(apiInstance, _output)) return; - var getUserResult = await apiInstance.GetUserAsync(_username); + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + var username = _authInfo.GetUsername(); + + var getUserResult = await _authInfo.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); } - [RunnableInDebugOnlyFact] + [Fact] public async void SetAccountPrivacyTest() { - //arrange - var apiInstance = - TestHelpers.GetDefaultInstaApiInstance(new UserSessionData - { - UserName = _username, - Password = _password - }); - //act - if (!TestHelpers.Login(apiInstance, _output)) return; - var resultSetPrivate = await apiInstance.SetAccountPrivateAsync(); - var resultSetPublic = await apiInstance.SetAccountPublicAsync(); - //assert + Assert.True(_authInfo.ApiInstance.IsUserAuthenticated); + + var resultSetPrivate = await _authInfo.ApiInstance.SetAccountPrivateAsync(); + var resultSetPublic = await _authInfo.ApiInstance.SetAccountPublicAsync(); + Assert.True(resultSetPrivate.Succeeded); Assert.NotNull(resultSetPrivate.Value); Assert.True(resultSetPublic.Succeeded); diff --git a/InstaSharper.Tests/Infrastructure/ApiInstanceBuilderTest.cs b/InstaSharper.Tests/Infrastructure/ApiInstanceBuilderTest.cs index f3832b6b..b0e4fc82 100644 --- a/InstaSharper.Tests/Infrastructure/ApiInstanceBuilderTest.cs +++ b/InstaSharper.Tests/Infrastructure/ApiInstanceBuilderTest.cs @@ -4,7 +4,7 @@ namespace InstaSharper.Tests.Infrastructure { - [Collection("Infrastructure")] + [Trait("Category", "Infrastructure")] public class ApiInstanceBuilderTest { [Fact] diff --git a/InstaSharper.Tests/InstaSharper.Tests.csproj b/InstaSharper.Tests/InstaSharper.Tests.csproj index 00906169..f81ce087 100644 --- a/InstaSharper.Tests/InstaSharper.Tests.csproj +++ b/InstaSharper.Tests/InstaSharper.Tests.csproj @@ -12,19 +12,19 @@ - + - - PreserveNewest - + - + + PreserveNewest + diff --git a/InstaSharper.Tests/Utils/TestHelpers.cs b/InstaSharper.Tests/Utils/TestHelpers.cs index 409e6f1a..df3f1157 100644 --- a/InstaSharper.Tests/Utils/TestHelpers.cs +++ b/InstaSharper.Tests/Utils/TestHelpers.cs @@ -1,6 +1,10 @@ -using InstaSharper.API; +using System.Net.Http; +using System.Threading.Tasks; +using InstaSharper.API; using InstaSharper.API.Builder; using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Helpers; using Xunit.Abstractions; namespace InstaSharper.Tests.Utils @@ -9,25 +13,41 @@ public class TestHelpers { public static IInstaApi GetDefaultInstaApiInstance(string username) { + var device = AndroidDeviceGenerator.GetByName(AndroidDevices.SAMSUNG_NOTE3); + var requestMessage = ApiRequestMessage.FromDevice(device); var apiInstance = new InstaApiBuilder() .SetUserName(username) .UseLogger(new TestLogger()) + .SetApiRequestMessage(requestMessage) .Build(); return apiInstance; } public static IInstaApi GetDefaultInstaApiInstance(UserSessionData user) { + var device = AndroidDeviceGenerator.GetByName(AndroidDevices.SAMSUNG_NOTE3); + var requestMessage = ApiRequestMessage.FromDevice(device); var apiInstance = new InstaApiBuilder() .SetUser(user) .UseLogger(new TestLogger()) + .SetApiRequestMessage(requestMessage) .Build(); return apiInstance; } - public static bool Login(IInstaApi apiInstance, ITestOutputHelper output) + public static IInstaApi GetProxifiedInstaApiInstance(UserSessionData user, InstaProxy proxy) { - var loginResult = apiInstance.Login(); + var handler = new HttpClientHandler {Proxy = proxy}; + var apiInstance = new InstaApiBuilder() + .UseHttpClientHandler(handler) + .SetUser(user) + .Build(); + return apiInstance; + } + + public static async Task Login(IInstaApi apiInstance, ITestOutputHelper output) + { + var loginResult = await apiInstance.LoginAsync(); if (!loginResult.Succeeded) { output.WriteLine($"Can't login: {loginResult.Info.Message}"); diff --git a/InstaSharper/API/Builder/IInstaApiBuilder.cs b/InstaSharper/API/Builder/IInstaApiBuilder.cs index 8f0b7f00..a2f067e7 100644 --- a/InstaSharper/API/Builder/IInstaApiBuilder.cs +++ b/InstaSharper/API/Builder/IInstaApiBuilder.cs @@ -1,5 +1,6 @@ using System.Net.Http; using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; using InstaSharper.Logger; namespace InstaSharper.API.Builder @@ -12,5 +13,6 @@ public interface IInstaApiBuilder IInstaApiBuilder UseHttpClientHandler(HttpClientHandler handler); IInstaApiBuilder SetUserName(string username); IInstaApiBuilder SetUser(UserSessionData user); + IInstaApiBuilder SetApiRequestMessage(ApiRequestMessage requestMessage); } } \ No newline at end of file diff --git a/InstaSharper/API/Builder/InstaApiBuilder.cs b/InstaSharper/API/Builder/InstaApiBuilder.cs index d260db4b..261dbab1 100644 --- a/InstaSharper/API/Builder/InstaApiBuilder.cs +++ b/InstaSharper/API/Builder/InstaApiBuilder.cs @@ -13,6 +13,7 @@ public class InstaApiBuilder : IInstaApiBuilder private ILogger _logger; private ApiRequestMessage _requestMessage; private UserSessionData _user; + private AndroidDevice device; public IInstaApi Build() { @@ -21,7 +22,6 @@ public IInstaApi Build() _httpClient = new HttpClient(_httpHandler); _httpClient.BaseAddress = new Uri(InstaApiConstants.INSTAGRAM_URL); } - AndroidDevice device = null; if (_requestMessage == null) { @@ -35,6 +35,12 @@ public IInstaApi Build() device_id = ApiRequestMessage.GenerateDeviceId() }; } + + if (string.IsNullOrEmpty(_requestMessage.password)) _requestMessage.password = _user?.Password; + if (string.IsNullOrEmpty(_requestMessage.username)) _requestMessage.username = _user?.UserName; + if (device == null && !string.IsNullOrEmpty(_requestMessage.device_id)) device = AndroidDeviceGenerator.GetById(_requestMessage.device_id); + if (device == null) AndroidDeviceGenerator.GetRandomAndroidDevice(); + var instaApi = new InstaApi(_user, _logger, _httpClient, _httpHandler, _requestMessage, device); return instaApi; } diff --git a/InstaSharper/API/IInstaApi.cs b/InstaSharper/API/IInstaApi.cs index c21e06bb..26d1f7e1 100644 --- a/InstaSharper/API/IInstaApi.cs +++ b/InstaSharper/API/IInstaApi.cs @@ -15,236 +15,6 @@ public interface IInstaApi #endregion - #region Sync Members - - /// - /// Login using given credentials - /// - /// True is succeed - IResult Login(); - - /// - /// Logout from instagram - /// - /// True if completed without errors - IResult Logout(); - - /// - /// Get user timeline feed - /// - /// Maximum count of pages to retrieve - /// - /// - /// - IResult GetUserTimelineFeed(int maxPages = 0); - - /// - /// Get user explore feed - /// - /// Maximum count of pages to retrieve - /// > - IResult GetExploreFeed(int maxPages = 0); - - /// - /// Get all user media by username - /// - /// Username - /// Maximum count of pages to retrieve - /// - /// - /// - IResult GetUserMedia(string username, int maxPages = 0); - - /// - /// Get media by its id (code) - /// - /// Maximum count of pages to retrieve - /// - /// - /// - IResult GetMediaById(string mediaId); - - /// - /// Get user info by its user name - /// - /// Username - /// - /// - /// - IResult GetUser(string username); - - /// - /// Get currently logged in user info - /// - /// - /// - /// - IResult GetCurrentUser(); - - /// - /// Get tag feed by tag value - /// - /// Tag value - /// Maximum count of pages to retrieve - /// - /// - /// - IResult GetTagFeed(string tag, int maxPages = 0); - - /// - /// Get followers list by username - /// - /// Username - /// Maximum count of pages to retrieve - /// - /// - /// - IResult GetUserFollowers(string username, int maxPages = 0); - - /// - /// Get followers list for currently logged in user - /// - /// Maximum count of pages to retrieve - /// - /// - /// - IResult GetCurentUserFollowers(int maxPages = 0); - - - /// - /// Get user tags by username - /// Returns media list containing tags - /// - /// Username - /// Maximum count of pages to retrieve - /// - /// - /// - IResult GetUserTags(string username, int maxPages = 0); - - - /// - /// Get direct inbox threads for current user - /// - /// - /// - /// - IResult GetDirectInbox(); - - /// - /// Get direct inbox thread by its id - /// - /// Thread id - /// - /// - /// - IResult GetDirectInboxThread(string threadId); - - /// - /// Get recent recipients (threads and users) - /// - /// - /// - /// - IResult GetRecentRecipients(); - - /// - /// Get ranked recipients (threads and users) - /// - /// - /// - /// - IResult GetRankedRecipients(); - - /// - /// Get recent activity info - /// - /// Maximum count of pages to retrieve - /// - /// - /// - IResult GetRecentActivity(int maxPages = 0); - - /// - /// Get activity of following - /// - /// Maximum count of pages to retrieve - /// - /// - /// - IResult GetFollowingRecentActivity(int maxPages = 0); - - /// - /// Like instagram media by id - /// - /// Media Id - /// True i success - IResult LikeMedia(string mediaId); - - /// - /// Like instagram media by id - /// - /// Media Id - /// True i success - IResult UnlikeMedia(string mediaId); - - /// - /// Follow user by its by id - /// - /// User Id - /// True i success - IResult FollowUser(long userId); - - /// - /// Stop follow user by its by id - /// - /// User Id - /// True i success - IResult UnFollowUser(long userId); - - /// - /// Set current account private - /// - IResult SetAccountPrivate(); - - /// - /// Set current account public - /// - IResult SetAccountPublic(); - - /// - /// Comment media - /// - /// Media id - /// Comment text - IResult CommentMedia(string mediaId, string text); - - /// - /// Delete comment from media - /// - /// Media id - /// Comment id - IResult DeleteComment(string mediaId, string commentId); - - /// - /// Uploads photo - /// - /// Photo - /// Caption - /// - IResult UploadPhoto(MediaImage image, string caption); - - /// - /// Configures photo - /// - /// Photo - /// Upload id - /// Caption - /// - IResult ConfigurePhoto(MediaImage image, string uploadId, string caption); - - #endregion - #region Async Members /// @@ -331,6 +101,16 @@ public interface IInstaApi /// Task> GetUserFollowersAsync(string username, int maxPages = 0); + /// + /// Get following list by username asynchronously + /// + /// Username + /// Maximum count of pages to retrieve + /// + /// + /// + Task> GetUserFollowingAsync(string username, int maxPages = 0); + /// /// Get followers list for currently logged in user asynchronously /// @@ -478,6 +258,69 @@ public interface IInstaApi /// Task> ConfigurePhotoAsync(MediaImage image, string uploadId, string caption); + /// + /// Get user's Story Tray + /// + Task> GetStoryTrayAsync(); + + /// + /// Get the story by userId + /// + /// User Id + Task> GetUserStoryAsync(long userId); + + /// + /// Upload story photo + /// + /// Photo to upload + /// Caption + Task> UploadStoryPhotoAsync(MediaImage image, string caption); + + /// + /// Configure story photo + /// + /// Photo to configure + /// Upload id + /// Caption + /// + Task> ConfigureStoryPhotoAsync(MediaImage image, string uploadId, string caption); + + /// + /// Change password + /// + /// The old password + /// + /// The new password (shouldn't be the same old password, and should be a password you never used + /// here) + /// + /// Return true if the password is changed + Task> ChangePasswordAsync(string oldPassword, string newPassword); + + /// + /// Delete a media (photo or video) + /// + /// The media ID + /// The type of the media + /// Return true if the media is deleted + Task> DeleteMediaAsync(string mediaId, InstaMediaType mediaType); + + /// + /// Edit the caption of the media (photo/video) + /// + /// The media ID + /// The new caption + /// Return true if everything is ok + Task> EditMediaAsync(string mediaId, string caption); + + /// + /// Get feed of media your liked. + /// + /// Maximum count of pages to retrieve + /// + /// + /// + Task> GetLikeFeedAsync(int maxPages = 0); + #endregion } } \ No newline at end of file diff --git a/InstaSharper/API/InstaApi.cs b/InstaSharper/API/InstaApi.cs index 4348acfa..a802cd7d 100644 --- a/InstaSharper/API/InstaApi.cs +++ b/InstaSharper/API/InstaApi.cs @@ -1,23 +1,22 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net; using System.Net.Http; -using System.Security.Cryptography; using System.Threading.Tasks; using InstaSharper.Classes; using InstaSharper.Classes.Android.DeviceInfo; using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; using InstaSharper.Converters; using InstaSharper.Converters.Json; using InstaSharper.Helpers; using InstaSharper.Logger; using Newtonsoft.Json; -using InstaRecentActivityConverter = InstaSharper.Converters.Json.InstaRecentActivityConverter; -using InstaSharper.Classes.ResponseWrappers; -using InstaSharper.Classes.ResponseWrappers.BaseResponse; using Newtonsoft.Json.Linq; -using System.IO; +using InstaRecentActivityConverter = InstaSharper.Converters.Json.InstaRecentActivityConverter; namespace InstaSharper.API { @@ -47,155 +46,6 @@ public InstaApi(UserSessionData user, public bool IsUserAuthenticated { get; private set; } - #region sync part - - public IResult Login() - { - return LoginAsync().Result; - } - - public IResult Logout() - { - return LogoutAsync().Result; - } - - public IResult GetMediaById(string mediaId) - { - return GetMediaByIdAsync(mediaId).Result; - } - - public IResult GetMediaByCode(string mediaCode) - { - return GetMediaByIdAsync(mediaCode).Result; - } - - public IResult GetUserTimelineFeed(int maxPages = 0) - { - return GetUserTimelineFeedAsync(maxPages).Result; - } - - public IResult GetUserMedia(string username, int maxPages = 0) - { - return GetUserMediaAsync(username, maxPages).Result; - } - - public IResult GetUser(string username) - { - return GetUserAsync(username).Result; - } - - public IResult GetCurrentUser() - { - return GetCurrentUserAsync().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; - } - - public IResult GetExploreFeed(int maxPages = 0) - { - return GetExploreFeedAsync(maxPages).Result; - } - - public IResult GetUserTags(string username, int maxPages = 0) - { - return GetUserTagsAsync(username, maxPages).Result; - } - - public IResult GetCurentUserFollowers(int maxPages = 0) - { - return GetCurrentUserFollowersAsync(maxPages).Result; - } - - public IResult GetDirectInbox() - { - return GetDirectInboxAsync().Result; - } - - public IResult GetDirectInboxThread(string threadId) - { - return GetDirectInboxThreadAsync(threadId).Result; - } - - public IResult GetRecentRecipients() - { - return GetRecentRecipientsAsync().Result; - } - - public IResult GetRankedRecipients() - { - return GetRankedRecipientsAsync().Result; - } - - public IResult GetRecentActivity(int maxPages = 0) - { - return GetRecentActivityAsync(maxPages).Result; - } - - public IResult GetFollowingRecentActivity(int maxPages = 0) - { - return GetFollowingRecentActivityAsync(maxPages).Result; - } - - public IResult LikeMedia(string mediaId) - { - return LikeMediaAsync(mediaId).Result; - } - - public IResult UnlikeMedia(string mediaId) - { - return UnLikeMediaAsync(mediaId).Result; - } - - public IResult FollowUser(long userId) - { - return FollowUserAsync(userId).Result; - } - - public IResult UnFollowUser(long userId) - { - return UnFollowUserAsync(userId).Result; - } - - public IResult SetAccountPrivate() - { - return SetAccountPrivateAsync().Result; - } - - public IResult SetAccountPublic() - { - return SetAccountPublicAsync().Result; - } - - public IResult CommentMedia(string mediaId, string text) - { - return CommentMediaAsync(mediaId, text).Result; - } - - public IResult DeleteComment(string mediaId, string commentId) - { - return DeleteCommentAsync(mediaId, commentId).Result; - } - - public IResult UploadPhoto(MediaImage image, string caption) - { - return UploadPhotoAsync(image, caption).Result; - } - - public IResult ConfigurePhoto(MediaImage image, string uploadId, string caption) - { - return ConfigurePhotoAsync(image, uploadId, caption).Result; - } - - #endregion - #region async part public async Task> LoginAsync() @@ -247,6 +97,8 @@ public async Task> LoginAsync() if (loginInfo.ErrorType == "Sorry, too many requests.Please try again later") return Result.Fail("Please try again later, maximum amount of requests reached", ResponseType.LoginRequired, false); + if (loginInfo.ErrorType == "sentry_block") + return Result.Fail("Sentry block. You got blocked by Instagram.", ResponseType.SentryBlock, false); return Result.Fail(loginInfo.Message, false); } } @@ -294,7 +146,7 @@ public async Task> GetUserTimelineFeedAsync(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); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeed)null); var feedResponse = JsonConvert.DeserializeObject(json, new InstaFeedResponseDataConverter()); var converter = ConvertersFabric.GetFeedConverter(feedResponse); @@ -329,7 +181,7 @@ public async Task> GetExploreFeedAsync(int maxPages = 0) 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); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaFeed)null); var mediaResponse = JsonConvert.DeserializeObject(json, new InstaMediaListDataConverter()); exploreFeed.Medias.AddRange( @@ -346,7 +198,7 @@ public async Task> GetExploreFeedAsync(int maxPages = 0) } catch (Exception exception) { - return Result.Fail(exception.Message, (InstaFeed) null); + return Result.Fail(exception.Message, (InstaFeed)null); } } @@ -354,8 +206,9 @@ public async Task> GetUserMediaAsync(string username, in { ValidateUser(); if (maxPages == 0) maxPages = int.MaxValue; - var user = GetUser(username).Value; - var instaUri = UriCreator.GetUserMediaListUri(user.Pk); + var user = await GetUserAsync(username); + if (!user.Succeeded) return Result.Fail("Unable to get current user"); + var instaUri = UriCreator.GetUserMediaListUri(user.Value.Pk); var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); @@ -370,7 +223,7 @@ public async Task> GetUserMediaAsync(string username, in var nextId = mediaResponse.NextMaxId; while (moreAvailable && mediaList.Pages < maxPages) { - instaUri = UriCreator.GetMediaListWithMaxIdUri(user.Pk, nextId); + instaUri = UriCreator.GetMediaListWithMaxIdUri(user.Value.Pk, nextId); var nextMedia = await GetUserMediaListWithMaxIdAsync(instaUri); mediaList.Pages++; if (!nextMedia.Succeeded) @@ -382,7 +235,7 @@ 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> GetMediaByIdAsync(string mediaId) @@ -405,7 +258,7 @@ public async Task> GetMediaByIdAsync(string mediaId) var converter = ConvertersFabric.GetSingleMediaConverter(mediaResponse.Medias.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) @@ -433,7 +286,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); } @@ -460,7 +313,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> GetTagFeedAsync(string tag, int maxPages = 0) @@ -495,7 +348,7 @@ public async Task> GetTagFeedAsync(string tag, int maxPages = } return Result.Success(tagFeed); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeed) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeed)null); } public async Task> GetUserFollowersAsync(string username, int maxPages = 0) @@ -506,29 +359,24 @@ public async Task> GetUserFollowersAsync(string username, { 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 userFollowersUri = UriCreator.GetUserFollowersUri(user.Value.Pk, _user.RankToken); var followers = new InstaUserList(); - 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); + var followersResponse = await GetUserListByURIAsync(userFollowersUri); + if (!followersResponse.Succeeded) + Result.Fail(followersResponse.Info, (InstaUserList)null); followers.AddRange( - followersResponse.Items.Select(ConvertersFabric.GetUserConverter) + followersResponse.Value.Items.Select(ConvertersFabric.GetUserConverter) .Select(converter => converter.Convert())); - if (!followersResponse.IsBigList) return Result.Success(followers); + if (!followersResponse.Value.IsBigList) return Result.Success(followers); var pages = 1; - while (!string.IsNullOrEmpty(followersResponse.NextMaxId) && pages < maxPages) + while (!string.IsNullOrEmpty(followersResponse.Value.NextMaxId) && pages < maxPages) { - var nextFollowers = Result.Success(followersResponse); - nextFollowers = await GetUserFollowersWithMaxIdAsync(username, nextFollowers.Value.NextMaxId); - if (!nextFollowers.Succeeded) - return Result.Success($"Not all pages was downloaded: {nextFollowers.Info.Message}", followers); - followersResponse = nextFollowers.Value; + var nextFollowersUri = UriCreator.GetUserFollowersUri(user.Value.Pk, _user.RankToken, followersResponse.Value.NextMaxId); + followersResponse = await GetUserListByURIAsync(nextFollowersUri); + if (!followersResponse.Succeeded) + return Result.Success($"Not all pages was downloaded: {followersResponse.Info.Message}", followers); followers.AddRange( - nextFollowers.Value.Items.Select(ConvertersFabric.GetUserConverter) + followersResponse.Value.Items.Select(ConvertersFabric.GetUserConverter) .Select(converter => converter.Convert())); pages++; } @@ -536,10 +384,48 @@ public async Task> GetUserFollowersAsync(string username, } catch (Exception exception) { - return Result.Fail(exception.Message, (InstaUserList) null); + return Result.Fail(exception.Message, (InstaUserList)null); + } + } + + public async Task> GetUserFollowingAsync(string username, int maxPages = 0) + { + ValidateUser(); + ValidateLoggedIn(); + try + { + if (maxPages == 0) maxPages = int.MaxValue; + var user = await GetUserAsync(username); + var userFeedUri = UriCreator.GetUserFollowingUri(user.Value.Pk, _user.RankToken); + var following = new InstaUserList(); + var userListResponse = await GetUserListByURIAsync(userFeedUri); + if (!userListResponse.Succeeded) + Result.Fail(userListResponse.Info, following); + following.AddRange( + userListResponse.Value.Items.Select(ConvertersFabric.GetUserConverter) + .Select(converter => converter.Convert())); + if (!userListResponse.Value.IsBigList) return Result.Success(following); + var pages = 1; + while (!string.IsNullOrEmpty(userListResponse.Value.NextMaxId) && pages < maxPages) + { + var nextUri = UriCreator.GetUserFollowingUri(user.Value.Pk, _user.RankToken, userListResponse.Value.NextMaxId); + userListResponse = await GetUserListByURIAsync(nextUri); + if (!userListResponse.Succeeded) + return Result.Success($"Not all pages was downloaded: {userListResponse.Info.Message}", following); + following.AddRange( + userListResponse.Value.Items.Select(ConvertersFabric.GetUserConverter) + .Select(converter => converter.Convert())); + pages++; + } + return Result.Success(following); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaUserList)null); } } + public async Task> GetCurrentUserFollowersAsync(int maxPages = 0) { ValidateUser(); @@ -555,13 +441,13 @@ public async Task> GetUserTagsAsync(string username, int 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); + 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); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaMediaList)null); var mediaResponse = JsonConvert.DeserializeObject(json, new InstaMediaListDataConverter()); var nextId = mediaResponse.NextMaxId; @@ -585,7 +471,7 @@ public async Task> GetUserTagsAsync(string username, int } catch (Exception exception) { - return Result.Fail(exception.Message, (InstaMediaList) null); + return Result.Fail(exception.Message, (InstaMediaList)null); } } @@ -600,7 +486,7 @@ public async Task> GetDirectInboxAsync() var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, directInboxUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaDirectInboxContainer) null); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaDirectInboxContainer)null); var inboxResponse = JsonConvert.DeserializeObject(json); var converter = ConvertersFabric.GetDirectInboxConverter(inboxResponse); return Result.Success(converter.Convert()); @@ -621,7 +507,7 @@ public async Task> GetDirectInboxThreadAsync(str var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, directInboxUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaDirectInboxThread) null); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaDirectInboxThread)null); var threadResponse = JsonConvert.DeserializeObject(json, new InstaThreadDataConverter()); var converter = ConvertersFabric.GetDirectThreadConverter(threadResponse); @@ -650,7 +536,7 @@ public async Task> GetRecentRecipientsAsync() var converter = ConvertersFabric.GetRecipientsConverter(responseRecipients); return Result.Success(converter.Convert()); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaRecipients) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaRecipients)null); } public async Task> GetRankedRecipientsAsync() @@ -668,7 +554,7 @@ public async Task> GetRankedRecipientsAsync() var converter = ConvertersFabric.GetRecipientsConverter(responseRecipients); return Result.Success(converter.Convert()); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaRecipients) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaRecipients)null); } public async Task> GetRecentActivityAsync(int maxPages = 0) @@ -746,7 +632,7 @@ public async Task> GetMediaCommentsAsync(string mediaI var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode != HttpStatusCode.OK) - return Result.Fail($"Unexpected response status: {response.StatusCode}", (InstaCommentList) null); + return Result.Fail($"Unexpected response status: {response.StatusCode}", (InstaCommentList)null); var commentListResponse = JsonConvert.DeserializeObject(json); var converter = ConvertersFabric.GetCommentListConverter(commentListResponse); var instaComments = converter.Convert(); @@ -783,7 +669,7 @@ public async Task> GetMediaLikersAsync(string mediaId) var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, likersUri, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaUserList) null); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaUserList)null); var instaUsers = new InstaUserList(); var mediaLikersResponse = JsonConvert.DeserializeObject(json); if (mediaLikersResponse.UsersCount < 1) return Result.Success(instaUsers); @@ -842,11 +728,11 @@ public async Task> SetAccountPrivateAsync() return Result.Success(converter.Convert()); } var status = GetBadStatusFromJsonString(json); - return Result.Fail(status.Message, (InstaUser) null); + return Result.Fail(status.Message, (InstaUser)null); } catch (Exception exception) { - return Result.Fail(exception.Message, (InstaUser) null); + return Result.Fail(exception.Message, (InstaUser)null); } } @@ -883,11 +769,11 @@ public async Task> SetAccountPublicAsync() return Result.Success(converter.Convert()); } var status = GetBadStatusFromJsonString(json); - return Result.Fail(status.Message, (InstaUser) null); + return Result.Fail(status.Message, (InstaUser)null); } catch (Exception exception) { - return Result.Fail(exception.Message, (InstaUser) null); + return Result.Fail(exception.Message, (InstaUser)null); } } @@ -922,11 +808,11 @@ public async Task> CommentMediaAsync(string mediaId, strin return Result.Success(converter.Convert()); } var status = GetBadStatusFromJsonString(json); - return Result.Fail(status.Message, (InstaComment) null); + return Result.Fail(status.Message, (InstaComment)null); } catch (Exception exception) { - return Result.Fail(exception.Message, (InstaComment) null); + return Result.Fail(exception.Message, (InstaComment)null); } } @@ -986,11 +872,11 @@ public async Task> UploadPhotoAsync(MediaImage image, string if (response.IsSuccessStatusCode) return await ConfigurePhotoAsync(image, uploadId, caption); var status = GetBadStatusFromJsonString(json); - return Result.Fail(status.Message, (InstaMedia) null); + return Result.Fail(status.Message, (InstaMedia)null); } catch (Exception exception) { - return Result.Fail(exception.Message, (InstaMedia) null); + return Result.Fail(exception.Message, (InstaMedia)null); } } @@ -1004,7 +890,7 @@ public async Task> ConfigurePhotoAsync(MediaImage image, str var androidVersion = AndroidVersion.FromString(_deviceInfo.FirmwareFingerprint.Split('/')[2].Split(':')[1]); if (androidVersion == null) - return Result.Fail("Unsupported android version", (InstaMedia) null); + return Result.Fail("Unsupported android version", (InstaMedia)null); var data = new JObject { {"_uuid", _deviceInfo.DeviceGuid.ToString()}, @@ -1049,14 +935,272 @@ public async Task> ConfigurePhotoAsync(MediaImage image, str return Result.Success(converter.Convert()); } var status = GetBadStatusFromJsonString(json); - return Result.Fail(status.Message, (InstaMedia) null); + return Result.Fail(status.Message, (InstaMedia)null); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaMedia)null); + } + } + + + public async Task> GetStoryTrayAsync() + { + ValidateUser(); + ValidateLoggedIn(); + + try + { + var storyTrayUri = UriCreator.GetStoryTray(); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, storyTrayUri, _deviceInfo); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaStoryTray)null); + var instaStoryTray = new InstaStoryTray(); + var instaStoryTrayResponse = JsonConvert.DeserializeObject(json); + + instaStoryTray = ConvertersFabric.GetStoryTrayConverter(instaStoryTrayResponse).Convert(); + + return Result.Success(instaStoryTray); } catch (Exception exception) { - return Result.Fail(exception.Message, (InstaMedia) null); + return Result.Fail(exception.Message, (InstaStoryTray)null); } } + public async Task> GetUserStoryAsync(long userId) + { + ValidateUser(); + ValidateLoggedIn(); + + try + { + var userStoryUri = UriCreator.GetUserStoryUri(userId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userStoryUri, _deviceInfo); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaStory)null); + var userStory = new InstaStory(); + var userStoryResponse = JsonConvert.DeserializeObject(json); + + userStory = ConvertersFabric.GetStoryConverter(userStoryResponse).Convert(); + + return Result.Success(userStory); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaStory)null); + } + } + + public async Task> UploadStoryPhotoAsync(MediaImage image, string caption) + { + ValidateUser(); + ValidateLoggedIn(); + try + { + var instaUri = UriCreator.GetUploadPhotoUri(); + var uploadId = ApiRequestMessage.GenerateUploadId(); + var requestContent = new MultipartFormDataContent(uploadId) + { + {new StringContent(uploadId), "\"upload_id\""}, + {new StringContent(_deviceInfo.DeviceGuid.ToString()), "\"_uuid\""}, + {new StringContent(_user.CsrfToken), "\"_csrftoken\""}, + { + new StringContent("{\"lib_name\":\"jt\",\"lib_version\":\"1.3.0\",\"quality\":\"87\"}"), + "\"image_compression\"" + } + }; + var imageContent = new ByteArrayContent(File.ReadAllBytes(image.URI)); + imageContent.Headers.Add("Content-Transfer-Encoding", "binary"); + imageContent.Headers.Add("Content-Type", "application/octet-stream"); + requestContent.Add(imageContent, "photo", $"pending_media_{ApiRequestMessage.GenerateUploadId()}.jpg"); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); + request.Content = requestContent; + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.IsSuccessStatusCode) + return await ConfigureStoryPhotoAsync(image, uploadId, caption); + var status = GetBadStatusFromJsonString(json); + return Result.Fail(status.Message, (InstaStoryMedia)null); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaStoryMedia)null); + } + } + + public async Task> ConfigureStoryPhotoAsync(MediaImage image, string uploadId, string caption) + { + ValidateUser(); + ValidateLoggedIn(); + try + { + var instaUri = UriCreator.GetStoryConfigureUri(); + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUder.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"source_type", "1"}, + {"caption", caption}, + {"upload_id", uploadId}, + {"edits", new JObject()}, + {"disable_comments", false}, + {"configure_mode", 1}, + {"camera_position", "unknown"} + }; + var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, data); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.IsSuccessStatusCode) + { + var mediaResponse = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.GetStoryMediaConverter(mediaResponse); + return Result.Success(converter.Convert()); + } + var status = GetBadStatusFromJsonString(json); + return Result.Fail(status.Message, (InstaStoryMedia)null); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaStoryMedia)null); + } + } + + public async Task> ChangePasswordAsync(string oldPassword, string newPassword) + { + ValidateUser(); + ValidateLoggedIn(); + + if (oldPassword == newPassword) + return Result.Fail("The old password should not the same of the new password", false); + + try + { + var changePasswordUri = UriCreator.GetChangePasswordUri(); + + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUder.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"old_password", oldPassword}, + {"new_password1", newPassword}, + {"new_password2", newPassword} + }; + + var request = HttpHelper.GetSignedRequest(HttpMethod.Get, changePasswordUri, _deviceInfo, data); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + return Result.Success(true); //If status code is OK, then the password is surely changed + var error = JsonConvert.DeserializeObject(json); + var errors = ""; + error.Message.Errors.ForEach(errorContent => errors += errorContent + "\n"); + return Result.Fail(errors, false); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, false); + } + } + + public async Task> DeleteMediaAsync(string mediaId, InstaMediaType mediaType) + { + ValidateUser(); + ValidateLoggedIn(); + + try + { + var deleteMediaUri = UriCreator.GetDeleteMediaUri(mediaId, mediaType); + + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUder.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"media_id", mediaId} + }; + + var request = HttpHelper.GetSignedRequest(HttpMethod.Get, deleteMediaUri, _deviceInfo, data); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + { + var deletedResponse = JsonConvert.DeserializeObject(json); + return Result.Success(deletedResponse.IsDeleted); + } + var error = JsonConvert.DeserializeObject(json); + var errors = ""; + error.Message.Errors.ForEach(errorContent => errors += errorContent + "\n"); + return Result.Fail(errors, false); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, false); + } + } + + public async Task> EditMediaAsync(string mediaId, string caption) + { + ValidateUser(); + ValidateLoggedIn(); + + try + { + var editMediaUri = UriCreator.GetEditMediaUri(mediaId); + + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUder.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"caption_text", caption} + }; + + var request = HttpHelper.GetSignedRequest(HttpMethod.Get, editMediaUri, _deviceInfo, data); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + return Result.Success(true); //Technically Instagram returns the InstaMediaItem, but it is useless in our case, at this time. + var error = JsonConvert.DeserializeObject(json); + return Result.Fail(error.Message, false); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, false); + } + } + + public async Task> GetLikeFeedAsync(int maxPages = 0) + { + ValidateUser(); + if (maxPages == 0) maxPages = int.MaxValue; + var instaUri = UriCreator.GetUserLikeFeedUri(); + 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, + new InstaMediaListDataConverter()); + var moreAvailable = mediaResponse.MoreAvailable; + var converter = ConvertersFabric.GetMediaListConverter(mediaResponse); + var mediaList = converter.Convert(); + mediaList.Pages++; + var nextId = mediaResponse.NextMaxId; + while (moreAvailable && mediaList.Pages < maxPages) + { + + } + return Result.Success(mediaList); + } + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaMediaList)null); + } + #endregion #region private part @@ -1099,7 +1243,7 @@ private async Task> GetUserFeedWithMaxIdAsync(string 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)); @@ -1113,7 +1257,7 @@ private async Task> GetUserFeedWithMaxIdAsync(string new InstaFeedResponseDataConverter()); return Result.Success(feedResponse); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeedResponse) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFeedResponse)null); } private async Task> GetFollowingActivityWithMaxIdAsync(string maxId) @@ -1128,7 +1272,7 @@ private async Task> GetFollowingActivityWit new InstaRecentActivityConverter()); return Result.Success(followingActivity); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaRecentActivityResponse) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaRecentActivityResponse)null); } private async Task> GetUserMediaListWithMaxIdAsync(Uri instaUri) @@ -1142,32 +1286,29 @@ private async Task> GetUserMediaListWithMaxIdAsy new InstaMediaListDataConverter()); return Result.Success(mediaResponse); } - return Result.Fail("", (InstaMediaListResponse) null); + return Result.Fail("", (InstaMediaListResponse)null); } - private async Task> GetUserFollowersWithMaxIdAsync(string username, - string maxId) + private async Task> GetUserListByURIAsync(Uri uri) { 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 request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _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); + var instaUserListResponse = JsonConvert.DeserializeObject(json); + if (!instaUserListResponse.IsOK()) Result.Fail("", (InstaUserListResponse)null); + return Result.Success(instaUserListResponse); } - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaFollowersResponse) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaUserListResponse)null); } catch (Exception exception) { - return Result.Fail(exception.Message, (InstaFollowersResponse) null); + return Result.Fail(exception.Message, (InstaUserListResponse)null); } } @@ -1181,7 +1322,7 @@ private async Task> GetRecentActivityInternalAsync(Ur var activityFeed = new InstaActivityFeed(); var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode != HttpStatusCode.OK) - return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaActivityFeed) null); + return Result.Fail(GetBadStatusFromJsonString(json).Message, (InstaActivityFeed)null); var feedPage = JsonConvert.DeserializeObject(json, new InstaRecentActivityConverter()); activityFeed.IsOwnActivity = feedPage.IsOwnActivity; @@ -1212,7 +1353,7 @@ private async Task> GetTagFeedWithMaxIdAsync(str 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(); @@ -1222,11 +1363,11 @@ private async Task> GetTagFeedWithMaxIdAsync(str new InstaMediaListDataConverter()); 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); + return Result.Fail(exception.Message, (InstaMediaListResponse)null); } } @@ -1234,7 +1375,7 @@ private async Task> GetCommentListWithMaxIdAsy string nextId) { var commentsUri = UriCreator.GetMediaCommentsUri(mediaId); - var commentsUriMaxId = new UriBuilder(commentsUri) {Query = $"max_id={nextId}"}.Uri; + var commentsUriMaxId = new UriBuilder(commentsUri) { Query = $"max_id={nextId}" }.Uri; var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, commentsUriMaxId, _deviceInfo); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); @@ -1243,7 +1384,7 @@ private async Task> GetCommentListWithMaxIdAsy var comments = JsonConvert.DeserializeObject(json); return Result.Success(comments); } - return Result.Fail("", (InstaCommentListResponse) null); + return Result.Fail("", (InstaCommentListResponse)null); } private async Task> FollowUnfollowUserInternal(long userId, Uri instaUri) @@ -1271,11 +1412,11 @@ private async Task> FollowUnfollowUserInternal(lo return Result.Success(converter.Convert()); } var status = GetBadStatusFromJsonString(json); - return Result.Fail(status.Message, (InstaFriendshipStatus) null); + return Result.Fail(status.Message, (InstaFriendshipStatus)null); } catch (Exception exception) { - return Result.Fail(exception.Message, (InstaFriendshipStatus) null); + return Result.Fail(exception.Message, (InstaFriendshipStatus)null); } } diff --git a/InstaSharper/API/InstaApiConstants.cs b/InstaSharper/API/InstaApiConstants.cs index 835714b0..881744c8 100644 --- a/InstaSharper/API/InstaApiConstants.cs +++ b/InstaSharper/API/InstaApiConstants.cs @@ -17,6 +17,7 @@ internal static class InstaApiConstants public const string API_SUFFIX = "/api"; public const string SEARCH_USERS = API_SUFFIX + "/v1/users/search"; public const string ACCOUNTS_LOGIN = API_SUFFIX + "/v1/accounts/login/"; + public const string CHANGE_PASSWORD = API_SUFFIX + "/v1/accounts/change_password/"; 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"; @@ -24,6 +25,7 @@ internal static class InstaApiConstants 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_USER_FOLLOWING = API_SUFFIX + "/v1/friendships/{0}/following/?rank_token={1}"; public const string GET_TAG_FEED = API_SUFFIX + "/v1/feed/tag/{0}"; public const string GET_RANKED_RECIPIENTS = API_SUFFIX + "/v1/direct_v2/ranked_recipients"; public const string GET_RECENT_RECIPIENTS = API_SUFFIX + "/v1/direct_share/recent_recipients/"; @@ -46,7 +48,13 @@ internal static class InstaApiConstants public const string DELETE_COMMENT = API_SUFFIX + "/v1/media/{0}/comment/{1}/delete/"; public const string UPLOAD_PHOTO = API_SUFFIX + "/v1/upload/photo/"; public const string MEDIA_CONFIGURE = API_SUFFIX + "/v1/media/configure/"; - + public const string DELETE_MEDIA = API_SUFFIX + "/v1/media/{0}/delete/?media_type={1}"; + public const string EDIT_MEDIA = API_SUFFIX + "/v1/media/{0}/edit_media/"; + public const string GET_STORY_TRAY = API_SUFFIX + "/v1/feed/reels_tray/"; + public const string GET_USER_STORY = API_SUFFIX + "/v1/feed/user/{0}/reel_media/"; + public const string STORY_CONFIGURE = API_SUFFIX + "/v1/media/configure_to_reel/"; + public const string LOCATION_SEARCH = API_SUFFIX + "/v1/location_search/"; + public static string LIKE_FEED = API_SUFFIX + "/v1/feed/liked/"; public const string HEADER_USER_AGENT = "User-Agent"; public const string USER_AGENT = @@ -56,7 +64,6 @@ internal static class InstaApiConstants 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 = "b03e0daaf2ab17cda2a569cace938d639d1288a1197f9ecf97efd0a4ec0874d7"; public const string HEADER_IG_SIGNATURE = "signed_body"; public const string IG_SIGNATURE_KEY_VERSION = "4"; @@ -74,7 +81,6 @@ internal static class InstaApiConstants public const string HEADER_TIMEZONE = "timezone_offset"; public const string HEADER_XGOOGLE_AD_IDE = "X-Google-AD-ID"; public const string COMMENT_BREADCRUMB_KEY = "iN4$aGr0m"; - public const int TIMEZONE_OFFSET = 43200; } } \ No newline at end of file diff --git a/InstaSharper/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs b/InstaSharper/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs index cbb50c8b..20f25eab 100644 --- a/InstaSharper/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs +++ b/InstaSharper/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; +using System.Linq; namespace InstaSharper.Classes.Android.DeviceInfo { - public class AndroidDeviceGenerator + public class AndroidDevices { public const string LG_OPTIMUS_G = "lg-optimus-g"; public const string NEXUS7_GEN2 = "nexus7gen2"; @@ -12,24 +13,27 @@ public class AndroidDeviceGenerator public const string GALAXY5 = "galaxy-s5-gold"; public const string LG_OPTIMUS_F6 = "lg-optimus-f6"; public const string GALAXY_TAB = "galaxy-tab-s84"; - public const string SAMSUNG_NOT3 = "note3"; + public const string SAMSUNG_NOTE3 = "note3"; public const string NEXUS4_CHROMA = "nexus4-chroma"; public const string SONY_Z3_COMPACT = "sony-z3-compact"; public const string XPERIA_Z5 = "xperia-z5"; + } + public class AndroidDeviceGenerator + { private static readonly List DevicesNames = new List { - LG_OPTIMUS_G, - NEXUS7_GEN2, - HTC10, - GALAXY6, - GALAXY5, - LG_OPTIMUS_F6, - GALAXY_TAB, - SAMSUNG_NOT3, - NEXUS4_CHROMA, - SONY_Z3_COMPACT, - XPERIA_Z5 + AndroidDevices.LG_OPTIMUS_G, + AndroidDevices.NEXUS7_GEN2, + AndroidDevices.HTC10, + AndroidDevices.GALAXY6, + AndroidDevices.GALAXY5, + AndroidDevices.LG_OPTIMUS_F6, + AndroidDevices.GALAXY_TAB, + AndroidDevices.SAMSUNG_NOTE3, + AndroidDevices.NEXUS4_CHROMA, + AndroidDevices.SONY_Z3_COMPACT, + AndroidDevices.XPERIA_Z5 }; public static Dictionary AndroidAndroidDeviceSets = new Dictionary @@ -323,7 +327,6 @@ public class AndroidDeviceGenerator AndroidBoardName = "hammerhead", AndroidBootloader = "HHZ20b", DeviceBrand = "google", - DeviceId = "8525f5d8201f78b5", DeviceModel = "Nexus 5", DeviceModelBoot = "qcom", DeviceModelIdentifier = "hammerhead", @@ -334,7 +337,8 @@ public class AndroidDeviceGenerator HardwareManufacturer = "LGE", HardwareModel = "Nexus 5", DeviceGuid = new Guid("dde2038c-4f1c-465a-982d-9c844fd2b80a"), - PhoneGuid = new Guid("d8d75d13-a124-4304-a935-0247ed1656cb") + PhoneGuid = new Guid("d8d75d13-a124-4304-a935-0247ed1656cb"), + DeviceId = ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("dde2038c-4f1c-465a-982d-9c844fd2b80a")) } }, { @@ -354,7 +358,8 @@ public class AndroidDeviceGenerator HardwareManufacturer = "samsung", HardwareModel = "SM-N915W8", DeviceGuid = new Guid("fe46d44b-e00c-4f1b-9718-7c4dae2160cc"), - PhoneGuid = new Guid("0bcbf7e0-a73f-4424-8c70-c2d38ae42d5d") + PhoneGuid = new Guid("0bcbf7e0-a73f-4424-8c70-c2d38ae42d5d"), + DeviceId = ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("fe46d44b-e00c-4f1b-9718-7c4dae2160cc")) } }, { @@ -374,12 +379,13 @@ public class AndroidDeviceGenerator HardwareManufacturer = "LGE", HardwareModel = "Nexus 4", DeviceGuid = new Guid("2c4ae214-c037-486c-a335-76a1f6973445"), - PhoneGuid = new Guid("7fb2eb38-04ab-4c51-bd0c-694c7da2187e") + PhoneGuid = new Guid("7fb2eb38-04ab-4c51-bd0c-694c7da2187e"), + DeviceId = ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("2c4ae214-c037-486c-a335-76a1f6973445")) } }, { - "note3", + AndroidDevices.SAMSUNG_NOTE3, new AndroidDevice { AndroidBoardName = "MSM8974", @@ -395,11 +401,12 @@ public class AndroidDeviceGenerator HardwareManufacturer = "samsung", HardwareModel = "SM-N900P", DeviceGuid = new Guid("7f585e77-becf-4137-bf1f-84ab72e35eb4"), - PhoneGuid = new Guid("28484284-e646-4a29-88fc-76c2666d5ab3") + PhoneGuid = new Guid("28484284-e646-4a29-88fc-76c2666d5ab3"), + DeviceId = ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("7f585e77-becf-4137-bf1f-84ab72e35eb4")) } }, { - "galaxy-tab-s84", + AndroidDevices.GALAXY_TAB, new AndroidDevice { AndroidBoardName = "universal5420", @@ -415,17 +422,28 @@ public class AndroidDeviceGenerator HardwareManufacturer = "samsung", HardwareModel = "SM-T705", DeviceGuid = new Guid("c319490f-6f09-467b-b2a5-6f1db13348e9"), - PhoneGuid = new Guid("849a7ae1-cf94-4dd5-a977-a2f3e8363e66") + PhoneGuid = new Guid("849a7ae1-cf94-4dd5-a977-a2f3e8363e66"), + DeviceId = ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("c319490f-6f09-467b-b2a5-6f1db13348e9")) } } }; public static AndroidDevice GetRandomAndroidDevice() { - var random = new Random(); + var random = new Random(DateTime.Now.Millisecond); var randmonDeviceIndex = random.Next(0, DevicesNames.Count); var randomDeviceName = DevicesNames[randmonDeviceIndex]; return AndroidAndroidDeviceSets[randomDeviceName]; } + + public static AndroidDevice GetByName(string name) + { + return AndroidAndroidDeviceSets[name]; + } + + public static AndroidDevice GetById(string deviceId) + { + return (from androidAndroidDeviceSet in AndroidAndroidDeviceSets where androidAndroidDeviceSet.Value.DeviceId == deviceId select androidAndroidDeviceSet.Value).FirstOrDefault(); + } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs b/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs index b682d9b9..ebd2afb6 100644 --- a/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs +++ b/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs @@ -35,8 +35,7 @@ internal bool IsEmpty() internal static string GenerateDeviceId() { - var hashedGuid = CryptoHelper.CalculateMd5(Guid.NewGuid().ToString()); - return $"android-{hashedGuid.Substring(0, 16)}"; + return GenerateDeviceIdFromGuid(Guid.NewGuid()); } internal static string GenerateUploadId() @@ -45,5 +44,22 @@ internal static string GenerateUploadId() var uploadId = (long) timeSpan.TotalSeconds; return uploadId.ToString(); } + + public static ApiRequestMessage FromDevice(AndroidDevice device) + { + var requestMessage = new ApiRequestMessage + { + phone_id = device.PhoneGuid.ToString(), + guid = device.DeviceGuid, + device_id = device.DeviceId + }; + return requestMessage; + } + + public static string GenerateDeviceIdFromGuid(Guid guid) + { + var hashedGuid = CryptoHelper.CalculateMd5(guid.ToString()); + return $"android-{hashedGuid.Substring(0, 16)}"; + } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Android/LoginInfoAndroid.cs b/InstaSharper/Classes/Android/LoginInfoAndroid.cs deleted file mode 100644 index 0d02205c..00000000 --- a/InstaSharper/Classes/Android/LoginInfoAndroid.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace InstaSharper.Classes.Android -{ - public class LoginInfoAndroid - { - } -} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaCarousel.cs b/InstaSharper/Classes/Models/InstaCarousel.cs index 9ccc1254..2b8605db 100644 --- a/InstaSharper/Classes/Models/InstaCarousel.cs +++ b/InstaSharper/Classes/Models/InstaCarousel.cs @@ -1,7 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Generic; namespace InstaSharper.Classes.Models { diff --git a/InstaSharper/Classes/Models/InstaMedia.cs b/InstaSharper/Classes/Models/InstaMedia.cs index 7a6fcc77..632faf45 100644 --- a/InstaSharper/Classes/Models/InstaMedia.cs +++ b/InstaSharper/Classes/Models/InstaMedia.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using InstaSharper.Converters; namespace InstaSharper.Classes.Models { diff --git a/InstaSharper/Classes/Models/InstaStory.cs b/InstaSharper/Classes/Models/InstaStory.cs index 73476248..edfe1a31 100644 --- a/InstaSharper/Classes/Models/InstaStory.cs +++ b/InstaSharper/Classes/Models/InstaStory.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace InstaSharper.Classes.Models { @@ -12,7 +13,7 @@ public class InstaStory public string SourceToken { get; set; } - public bool Seen { get; set; } + public double Seen { get; set; } public string LatestReelMedia { get; set; } @@ -20,6 +21,14 @@ public class InstaStory public int RankedPosition { get; set; } + public bool Muted { get; set; } + public int SeenRankedPosition { get; set; } + + public List Items { get; set; } = new List(); + + public int PrefetchCount { get; set; } + + public string SocialContext { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaStoryItem.cs b/InstaSharper/Classes/Models/InstaStoryItem.cs new file mode 100644 index 00000000..3591ec25 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaStoryItem.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; + +namespace InstaSharper.Classes.Models +{ + public class InstaStoryItem + { + public DateTime TakenAt { get; set; } + + public long Pk { get; set; } + + public string Id { get; set; } + + public InstaMediaType MediaType { get; set; } + + public string Code { get; set; } + + public string ClientCacheKey { get; set; } + + public int FilterType { get; set; } + + public List Images { get; set; } = new List(); + + public int OriginalWidth { get; set; } + + public int OriginalHeight { get; set; } + + public double CaptionPosition { get; set; } + + public InstaUser User { get; set; } + + public string TrackingToken { get; set; } + + public int LikeCount { get; set; } + + public InstaUserList Likers { get; set; } = new InstaUserList(); + + public bool HasLiked { get; set; } + + public bool HasMoreComments { get; set; } + + public int MaxNumVisiblePreviewComments { get; set; } + + //public InstaComment PreviewComments { get; set; } --- --- //I'll check what is. + + public int CommentCount { get; set; } + + public bool CommentsDisabled { get; set; } + + public InstaCaption Caption { get; set; } + + public List UserTags { get; set; } = new List(); + + public InstaCarousel CarouselMedia { get; set; } = new InstaCarousel(); + + public bool CaptionIsEdited { get; set; } //Visible only if the story is an image. + + public bool PhotoOfYou { get; set; } + + public bool CanViewerSave { get; set; } + + public DateTime ExpiringAt { get; set; } + + public bool IsReelMedia { get; set; } + + //public List ReelMentions { get; set; } --- --- //I'll do a test via Fiddler + + //public List StoryLocation { get; set; } + + //public List StoryHashtags { get; set; } //I'll do a test via Fiddler + + #region Video + + public List VideoVersions { get; set; } = new List(); //Visible only if the story is a video. + + public bool HasAudio { get; set; } //Visible only if the story is a video. + + public double VideoDuration { get; set; } //Visible only if the story is a video. + + #endregion + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaStoryMedia.cs b/InstaSharper/Classes/Models/InstaStoryMedia.cs new file mode 100644 index 00000000..de7f0c65 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaStoryMedia.cs @@ -0,0 +1,7 @@ +namespace InstaSharper.Classes.Models +{ + public class InstaStoryMedia + { + public InstaStoryItem Media { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaStoryTray.cs b/InstaSharper/Classes/Models/InstaStoryTray.cs new file mode 100644 index 00000000..2be9646c --- /dev/null +++ b/InstaSharper/Classes/Models/InstaStoryTray.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace InstaSharper.Classes.Models +{ + public class InstaStoryTray + { + public List Tray { get; set; } = new List(); + + public string StoryRankingToken { get; set; } + + //public List Broadcasts { get; set; } = new List(); //No info at this time... I'll check later with Fiddler + + public int StickerVersion { get; set; } + + public string Status { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/MediaVideo.cs b/InstaSharper/Classes/Models/MediaVideo.cs new file mode 100644 index 00000000..7cd4ad9e --- /dev/null +++ b/InstaSharper/Classes/Models/MediaVideo.cs @@ -0,0 +1,21 @@ +namespace InstaSharper.Classes.Models +{ + public class MediaVideo + { + public MediaVideo(string url, string width, string height, int type) + { + Url = url; + Width = width; + Height = height; + Type = type; + } + + public string Url { get; set; } + + public string Width { get; set; } + + public string Height { get; set; } + + public int Type { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseType.cs b/InstaSharper/Classes/ResponseType.cs index 5032efcc..bdd22d51 100644 --- a/InstaSharper/Classes/ResponseType.cs +++ b/InstaSharper/Classes/ResponseType.cs @@ -5,6 +5,8 @@ public enum ResponseType Unknown = 0, LoginRequired = 1, CheckPointRequired = 2, - RequestsLimit = 3 + RequestsLimit = 3, + SentryBlock = 4, + OK = 5 } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/BadStatusErrorsResponse.cs b/InstaSharper/Classes/ResponseWrappers/BadStatusErrorsResponse.cs new file mode 100644 index 00000000..59416f70 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/BadStatusErrorsResponse.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class BadStatusErrorsResponse : BaseStatusResponse + { + [JsonProperty("message")] + public MessageErrorsResponse Message { get; set; } + } + + public class MessageErrorsResponse + { + [JsonProperty("errors")] + public List Errors { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/DeleteResponse.cs b/InstaSharper/Classes/ResponseWrappers/DeleteResponse.cs new file mode 100644 index 00000000..05ed9e0a --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/DeleteResponse.cs @@ -0,0 +1,11 @@ +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + internal class DeleteResponse : BaseStatusResponse + { + [JsonProperty("did_delete")] + public bool IsDeleted { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/ImageResponse.cs b/InstaSharper/Classes/ResponseWrappers/ImageResponse.cs index e2aacfbe..c9a2a388 100644 --- a/InstaSharper/Classes/ResponseWrappers/ImageResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/ImageResponse.cs @@ -4,7 +4,7 @@ namespace InstaSharper.Classes.ResponseWrappers { internal class ImageResponse { - [JsonProperty("uri")] + [JsonProperty("url")] public string Url { get; set; } [JsonProperty("width")] diff --git a/InstaSharper/Classes/ResponseWrappers/InstaStoryItemResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaStoryItemResponse.cs new file mode 100644 index 00000000..c9c75fb2 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaStoryItemResponse.cs @@ -0,0 +1,119 @@ +using System.Collections.Generic; +using InstaSharper.Classes.Models; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + internal class InstaStoryItemResponse + { + [JsonProperty("taken_at")] + public long TakenAt { get; set; } + + [JsonProperty("pk")] + public long Pk { get; set; } + + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("device_timestamp")] + public long DeviceTimeStamp { get; set; } + + [JsonProperty("media_type")] + public InstaMediaType MediaType { get; set; } + + [JsonProperty("code")] + public string Code { get; set; } + + [JsonProperty("client_cache_key")] + public string ClientCacheKey { get; set; } + + [JsonProperty("filter_type")] + public int FilterType { get; set; } + + [JsonProperty("image_versions2")] + public InstaImageCandidatesResponse ImageVersions { get; set; } + + [JsonProperty("original_width")] + public int OriginalWidth { get; set; } + + [JsonProperty("original_height")] + public int OriginalHeight { get; set; } + + [JsonProperty("caption_position")] + public double CaptionPosition { get; set; } + + [JsonProperty("user")] + public InstaUserResponse User { get; set; } + + [JsonProperty("organic_tracking_token")] + public string TrackingToken { get; set; } + + [JsonProperty("like_count")] + public int LikeCount { get; set; } + + [JsonProperty("likers")] + public List Likers { get; set; } + + [JsonProperty("usertags")] + public InstaUserTagListResponse UserTags { get; set; } + + [JsonProperty("carousel_media")] + public InstaCarouselResponse CarouselMedia { get; set; } + + [JsonProperty("has_liked")] + public bool HasLiked { get; set; } + + [JsonProperty("has_more_comments")] + public bool HasMoreComments { get; set; } + + [JsonProperty("max_num_visible_preview_comments")] + public int MaxNumVisiblePreviewComments { get; set; } + + //public InstaComment PreviewComments { get; set; } --- --- //I'll check what is. + + [JsonProperty("comment_count")] + public int CommentCount { get; set; } + + [JsonProperty("comment_disabled")] + public bool CommentsDisabled { get; set; } + + [JsonProperty("caption")] + public InstaCaptionResponse Caption { get; set; } + + [JsonProperty("caption_is_edited")] + public bool CaptionIsEdited { get; set; } //Visible only if the story is an image. + + [JsonProperty("photo_of_you")] + public bool PhotoOfYou { get; set; } + + [JsonProperty("can_viewer_save")] + public bool CanViewerSave { get; set; } + + [JsonProperty("expiring_at")] + public long ExpiringAt { get; set; } + + [JsonProperty("is_reel_media")] + public bool IsReelMedia { get; set; } + + //public List ReelMentions { get; set; } --- --- //I'll do a test via Fiddler + + //[JsonProperty("story_locations")] + + //public List StoryLocation { get; set; } + + //public List StoryHashtags { get; set; } //I'll do a test via Fiddler + + #region Video + + [JsonProperty("video_versions")] + public InstaVideoCandidatesResponse VideoVersions { get; set; } //Visible only if the story is a video. + + [JsonProperty("has_audio")] + public bool HasAudio { get; set; } //Visible only if the story is a video. + + [JsonProperty("video_duration")] + public double VideoDuration { get; set; } //Visible only if the story is a video. + + #endregion + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaStoryMediaResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaStoryMediaResponse.cs new file mode 100644 index 00000000..34241572 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaStoryMediaResponse.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + internal class InstaStoryMediaResponse + { + [JsonProperty("media")] + public InstaStoryItemResponse Media { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaStoryResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaStoryResponse.cs index 1e31f442..e8bf718d 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaStoryResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaStoryResponse.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using Newtonsoft.Json; namespace InstaSharper.Classes.ResponseWrappers { @@ -8,7 +9,7 @@ internal class InstaStoryResponse public bool CanReply { get; set; } [JsonProperty("expiring_at")] - public string ExpiringAt { get; set; } + public long ExpiringAt { get; set; } [JsonProperty("user")] public InstaUserResponse User { get; set; } @@ -17,7 +18,7 @@ internal class InstaStoryResponse public string SourceToken { get; set; } [JsonProperty("seen")] - public bool Seen { get; set; } + public double Seen { get; set; } //Should be a DateTime [JsonProperty("latest_reel_media")] public string LatestReelMedia { get; set; } @@ -28,7 +29,19 @@ internal class InstaStoryResponse [JsonProperty("ranked_position")] public int RankedPosition { get; set; } + [JsonProperty("muted")] + public bool Muted { get; set; } + [JsonProperty("seen_ranked_position")] public int SeenRankedPosition { get; set; } + + [JsonProperty("items")] + public List Items { get; set; } + + [JsonProperty("prefetch_count")] + public int PrefetchCount { get; set; } + + [JsonProperty("social_context")] + public string SocialContext { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaStoryTrayResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaStoryTrayResponse.cs new file mode 100644 index 00000000..d1fa2656 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaStoryTrayResponse.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + internal class InstaStoryTrayResponse + { + [JsonProperty("tray")] + public List Tray { get; set; } + + [JsonProperty("story_ranking_token")] + public string StoryRankingToken { get; set; } + + //public List Broadcasts { get; set; } = new List(); //No info at this time... I'll check later with Fiddler + + [JsonProperty("sticker_version")] + public int StickerVersion { get; set; } + + [JsonProperty("status")] + public string Status { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaFollowersResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaUserListResponse.cs similarity index 91% rename from InstaSharper/Classes/ResponseWrappers/InstaFollowersResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaUserListResponse.cs index 80b9d086..809fce28 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaFollowersResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaUserListResponse.cs @@ -4,7 +4,7 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaFollowersResponse : BaseStatusResponse + internal class InstaUserListResponse : BaseStatusResponse { [JsonProperty("users")] public List Items { get; set; } diff --git a/InstaSharper/Classes/ResponseWrappers/InstaVideoCandidatesResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaVideoCandidatesResponse.cs new file mode 100644 index 00000000..3cb1cf0a --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaVideoCandidatesResponse.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; +using InstaSharper.Classes.Models; + +namespace InstaSharper.Classes.ResponseWrappers +{ + internal class InstaVideoCandidatesResponse : List + { + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Result.cs b/InstaSharper/Classes/Result.cs index be178deb..4c905662 100644 --- a/InstaSharper/Classes/Result.cs +++ b/InstaSharper/Classes/Result.cs @@ -31,21 +31,38 @@ public Result(bool succeeded, T value) public static class Result { public static IResult Success(T resValue) - => new Result(true, resValue); + { + return new Result(true, resValue, new ResultInfo(ResponseType.OK, "No errors detected")); + } public static IResult Success(string successMsg, T resValue) - => new Result(true, resValue, new ResultInfo(successMsg)); + { + return new Result(true, resValue, new ResultInfo(ResponseType.OK, successMsg)); + } public static IResult Fail(Exception exception) - => new Result(false, default(T), new ResultInfo(exception)); + { + return new Result(false, default(T), new ResultInfo(exception)); + } public static IResult Fail(string errMsg) - => new Result(false, default(T), new ResultInfo(errMsg)); + { + return new Result(false, default(T), new ResultInfo(errMsg)); + } public static IResult Fail(string errMsg, T resValue) - => new Result(false, resValue, new ResultInfo(errMsg)); + { + return new Result(false, resValue, new ResultInfo(errMsg)); + } + + public static IResult Fail(ResultInfo info, T resValue) + { + return new Result(false, resValue, info); + } public static IResult Fail(string errMsg, ResponseType responseType, T resValue) - => new Result(false, resValue, new ResultInfo(responseType)); + { + return new Result(false, resValue, new ResultInfo(responseType, errMsg)); + } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResultInfo.cs b/InstaSharper/Classes/ResultInfo.cs index 7cb8b268..88627acd 100644 --- a/InstaSharper/Classes/ResultInfo.cs +++ b/InstaSharper/Classes/ResultInfo.cs @@ -14,9 +14,10 @@ public ResultInfo(Exception exception) Exception = exception; } - public ResultInfo(ResponseType responseType) + public ResultInfo(ResponseType responseType, string errorMessage) { ResponseType = responseType; + Message = errorMessage; } public Exception Exception { get; } diff --git a/InstaSharper/Converters/ConvertersFabric.cs b/InstaSharper/Converters/ConvertersFabric.cs index 5b133326..4d98d2f9 100644 --- a/InstaSharper/Converters/ConvertersFabric.cs +++ b/InstaSharper/Converters/ConvertersFabric.cs @@ -110,5 +110,25 @@ public static IObjectConverter Get { return new InstaCarouselItemConverter {SourceObject = carouselItem}; } + + public static IObjectConverter GetStoryItemConverter(InstaStoryItemResponse storyItem) + { + return new InstaStoryItemConverter {SourceObject = storyItem}; + } + + public static IObjectConverter GetStoryConverter(InstaStoryResponse storyItem) + { + return new InstaStoryConverter {SourceObject = storyItem}; + } + + public static IObjectConverter GetStoryTrayConverter(InstaStoryTrayResponse storyTray) + { + return new InstaStoryTrayConverter {SourceObject = storyTray}; + } + + public static IObjectConverter GetStoryMediaConverter(InstaStoryMediaResponse storyMedia) + { + return new InstaStoryMediaConverter {SourceObject = storyMedia}; + } } } \ No newline at end of file diff --git a/InstaSharper/Converters/InstaStoryConverter.cs b/InstaSharper/Converters/InstaStoryConverter.cs index 710a729f..18525a4e 100644 --- a/InstaSharper/Converters/InstaStoryConverter.cs +++ b/InstaSharper/Converters/InstaStoryConverter.cs @@ -21,9 +21,19 @@ public InstaStory Convert() RankedPosition = SourceObject.RankedPosition, Seen = SourceObject.Seen, SeenRankedPosition = SourceObject.SeenRankedPosition, - SourceToken = SourceObject.SourceToken + Muted = SourceObject.Muted, + SourceToken = SourceObject.SourceToken, + PrefetchCount = SourceObject.PrefetchCount, + SocialContext = SourceObject.SocialContext }; - if (SourceObject.User != null) story.User = ConvertersFabric.GetUserConverter(SourceObject.User).Convert(); + + if (SourceObject.User != null) + story.User = ConvertersFabric.GetUserConverter(SourceObject.User).Convert(); + + if (SourceObject.Items?.Count > 0) + foreach (var InstaStory in SourceObject.Items) + story.Items.Add(ConvertersFabric.GetStoryItemConverter(InstaStory).Convert()); + return story; } } diff --git a/InstaSharper/Converters/InstaStoryItemConverter.cs b/InstaSharper/Converters/InstaStoryItemConverter.cs new file mode 100644 index 00000000..cf1e1d40 --- /dev/null +++ b/InstaSharper/Converters/InstaStoryItemConverter.cs @@ -0,0 +1,68 @@ +using System; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Helpers; + +namespace InstaSharper.Converters +{ + internal class InstaStoryItemConverter : IObjectConverter + { + public InstaStoryItemResponse SourceObject { get; set; } + + public InstaStoryItem Convert() + { + if (SourceObject == null) throw new ArgumentNullException($"Source object"); + var instaStory = new InstaStoryItem + { + CanViewerSave = SourceObject.CanViewerSave, + CaptionIsEdited = SourceObject.CaptionIsEdited, + CaptionPosition = SourceObject.CaptionPosition, + ClientCacheKey = SourceObject.ClientCacheKey, + Code = SourceObject.Code, + CommentCount = SourceObject.CommentCount, + CommentsDisabled = SourceObject.CommentsDisabled, + ExpiringAt = DateTimeHelper.UnixTimestampToDateTime(SourceObject.ExpiringAt), + FilterType = SourceObject.FilterType, + HasAudio = SourceObject.HasAudio, + HasLiked = SourceObject.HasLiked, + HasMoreComments = SourceObject.HasMoreComments, + Id = SourceObject.Id, + IsReelMedia = SourceObject.IsReelMedia, + LikeCount = SourceObject.LikeCount, + MaxNumVisiblePreviewComments = SourceObject.MaxNumVisiblePreviewComments, + MediaType = SourceObject.MediaType, + OriginalHeight = SourceObject.OriginalHeight, + OriginalWidth = SourceObject.OriginalWidth, + PhotoOfYou = SourceObject.PhotoOfYou, + Pk = SourceObject.Pk, + TakenAt = DateTimeHelper.UnixTimestampToDateTime(SourceObject.TakenAt), + TrackingToken = SourceObject.TrackingToken, + VideoDuration = SourceObject.VideoDuration, + VideoVersions = SourceObject.VideoVersions + }; + + if (SourceObject.User != null) + instaStory.User = ConvertersFabric.GetUserConverter(SourceObject.User).Convert(); + + if (SourceObject.Caption != null) + instaStory.Caption = ConvertersFabric.GetCaptionConverter(SourceObject.Caption).Convert(); + + if (SourceObject.Likers?.Count > 0) + foreach (var liker in SourceObject.Likers) + instaStory.Likers.Add(ConvertersFabric.GetUserConverter(liker).Convert()); + + if (SourceObject.CarouselMedia != null) + instaStory.CarouselMedia = ConvertersFabric.GetCarouselConverter(SourceObject.CarouselMedia).Convert(); + + if (SourceObject.UserTags?.In?.Count > 0) + foreach (var tag in SourceObject.UserTags.In) + instaStory.UserTags.Add(ConvertersFabric.GetUserTagConverter(tag).Convert()); + + if (SourceObject.ImageVersions?.Candidates != null) + foreach (var image in SourceObject.ImageVersions.Candidates) + instaStory.Images.Add(new MediaImage(image.Url, int.Parse(image.Width), int.Parse(image.Height))); + + return instaStory; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/InstaStoryMediaConverter.cs b/InstaSharper/Converters/InstaStoryMediaConverter.cs new file mode 100644 index 00000000..034b0f35 --- /dev/null +++ b/InstaSharper/Converters/InstaStoryMediaConverter.cs @@ -0,0 +1,20 @@ +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + internal class InstaStoryMediaConverter : IObjectConverter + { + public InstaStoryMediaResponse SourceObject { get; set; } + + public InstaStoryMedia Convert() + { + var instaStoryMedia = new InstaStoryMedia + { + Media = ConvertersFabric.GetStoryItemConverter(SourceObject.Media).Convert() + }; + + return instaStoryMedia; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/InstaStoryTrayConverter.cs b/InstaSharper/Converters/InstaStoryTrayConverter.cs new file mode 100644 index 00000000..cc74218d --- /dev/null +++ b/InstaSharper/Converters/InstaStoryTrayConverter.cs @@ -0,0 +1,29 @@ +using System; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + internal class InstaStoryTrayConverter : IObjectConverter + { + public InstaStoryTrayResponse SourceObject { get; set; } + + public InstaStoryTray Convert() + { + if (SourceObject == null) throw new ArgumentNullException($"Source object"); + + var storyTray = new InstaStoryTray + { + Status = SourceObject.Status, + StickerVersion = SourceObject.StickerVersion, + StoryRankingToken = SourceObject.StoryRankingToken + }; + + if (SourceObject.Tray.Count > 0) + foreach (var story in SourceObject.Tray) + storyTray.Tray.Add(ConvertersFabric.GetStoryConverter(story).Convert()); + + return storyTray; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/Json/InstaCommentDataConverter.cs b/InstaSharper/Converters/Json/InstaCommentDataConverter.cs index 5270e8d2..7a8b821f 100644 --- a/InstaSharper/Converters/Json/InstaCommentDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaCommentDataConverter.cs @@ -12,7 +12,9 @@ public override bool CanConvert(Type objectType) return objectType == typeof(InstaCommentResponse); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + public override object ReadJson(JsonReader reader, + Type objectType, + object existingValue, JsonSerializer serializer) { var root = JToken.Load(reader); diff --git a/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs b/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs index 12132afd..88466a8e 100644 --- a/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs @@ -13,7 +13,9 @@ public override bool CanConvert(Type objectType) return objectType == typeof(InstaFeedResponse); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + public override object ReadJson(JsonReader reader, + Type objectType, + object existingValue, JsonSerializer serializer) { var token = JToken.Load(reader); diff --git a/InstaSharper/Converters/Json/InstaFriendShipDataConverter.cs b/InstaSharper/Converters/Json/InstaFriendShipDataConverter.cs index 3a6f40a1..89ab49b5 100644 --- a/InstaSharper/Converters/Json/InstaFriendShipDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaFriendShipDataConverter.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using InstaSharper.Classes.ResponseWrappers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -15,7 +12,9 @@ public override bool CanConvert(Type objectType) return objectType == typeof(InstaFriendshipStatusResponse); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + public override object ReadJson(JsonReader reader, + Type objectType, + object existingValue, JsonSerializer serializer) { var root = JToken.Load(reader); diff --git a/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs b/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs index 0fcf6930..458135d7 100644 --- a/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs @@ -12,7 +12,9 @@ public override bool CanConvert(Type objectType) return objectType == typeof(InstaMediaListResponse); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + public override object ReadJson(JsonReader reader, + Type objectType, + object existingValue, JsonSerializer serializer) { var root = JToken.Load(reader); diff --git a/InstaSharper/Converters/Json/InstaRecentActivityConverter.cs b/InstaSharper/Converters/Json/InstaRecentActivityConverter.cs index f03a815d..b1856c3a 100644 --- a/InstaSharper/Converters/Json/InstaRecentActivityConverter.cs +++ b/InstaSharper/Converters/Json/InstaRecentActivityConverter.cs @@ -13,7 +13,9 @@ public override bool CanConvert(Type objectType) return objectType == typeof(InstaRecentActivityResponse); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + public override object ReadJson(JsonReader reader, + Type objectType, + object existingValue, JsonSerializer serializer) { var token = JToken.Load(reader); diff --git a/InstaSharper/Converters/Json/InstaRecipientsDataConverter.cs b/InstaSharper/Converters/Json/InstaRecipientsDataConverter.cs index a7e60279..affab5bb 100644 --- a/InstaSharper/Converters/Json/InstaRecipientsDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaRecipientsDataConverter.cs @@ -19,7 +19,9 @@ public override bool CanConvert(Type objectType) return objectType == typeof(InstaRecipientsResponse); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + public override object ReadJson(JsonReader reader, + Type objectType, + object existingValue, JsonSerializer serializer) { var root = JToken.Load(reader); diff --git a/InstaSharper/Converters/Json/InstaThreadDataConverter.cs b/InstaSharper/Converters/Json/InstaThreadDataConverter.cs index 6ebd27bf..b3469846 100644 --- a/InstaSharper/Converters/Json/InstaThreadDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaThreadDataConverter.cs @@ -12,7 +12,9 @@ public override bool CanConvert(Type objectType) return objectType == typeof(InstaDirectInboxThreadResponse); } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + public override object ReadJson(JsonReader reader, + Type objectType, + object existingValue, JsonSerializer serializer) { var token = JToken.Load(reader); diff --git a/InstaSharper/Helpers/HttpHelper.cs b/InstaSharper/Helpers/HttpHelper.cs index 37d4ccbe..7b4318d6 100644 --- a/InstaSharper/Helpers/HttpHelper.cs +++ b/InstaSharper/Helpers/HttpHelper.cs @@ -22,7 +22,9 @@ public static HttpRequestMessage GetDefaultRequest(HttpMethod method, Uri uri, A return request; } - public static HttpRequestMessage GetSignedRequest(HttpMethod method, Uri uri, AndroidDevice deviceInfo, + public static HttpRequestMessage GetSignedRequest(HttpMethod method, + Uri uri, + AndroidDevice deviceInfo, Dictionary data) { var hash = CryptoHelper.CalculateHash(InstaApiConstants.IG_SIGNATURE_KEY, @@ -43,7 +45,9 @@ public static HttpRequestMessage GetSignedRequest(HttpMethod method, Uri uri, An return request; } - public static HttpRequestMessage GetSignedRequest(HttpMethod method, Uri uri, AndroidDevice deviceInfo, + public static HttpRequestMessage GetSignedRequest(HttpMethod method, + Uri uri, + AndroidDevice deviceInfo, JObject data) { var hash = CryptoHelper.CalculateHash(InstaApiConstants.IG_SIGNATURE_KEY, diff --git a/InstaSharper/Helpers/InstaProxy.cs b/InstaSharper/Helpers/InstaProxy.cs new file mode 100644 index 00000000..098b1096 --- /dev/null +++ b/InstaSharper/Helpers/InstaProxy.cs @@ -0,0 +1,29 @@ +using System; +using System.Net; + +namespace InstaSharper.Helpers +{ + public class InstaProxy : IWebProxy + { + private readonly string ipaddress; + private readonly string port; + + public InstaProxy(string ipaddress, string port) + { + this.ipaddress = ipaddress; + this.port = port; + } + + public Uri GetProxy(Uri destination) + { + return new Uri($"http://{ipaddress}:{port}"); + } + + public bool IsBypassed(Uri host) + { + return false; + } + + public ICredentials Credentials { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Helpers/UriCreator.cs b/InstaSharper/Helpers/UriCreator.cs index 9ae6384d..9d8abbbc 100644 --- a/InstaSharper/Helpers/UriCreator.cs +++ b/InstaSharper/Helpers/UriCreator.cs @@ -1,5 +1,6 @@ using System; using InstaSharper.API; +using InstaSharper.Classes.Models; namespace InstaSharper.Helpers { @@ -20,7 +21,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; } @@ -53,7 +54,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; } @@ -63,7 +64,7 @@ public static Uri GetMediaListWithMaxIdUri(string userPk, string nextId) 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; } @@ -82,7 +83,18 @@ internal static Uri GetUserFollowersUri(string userPk, string rankToken, string !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; + } + + internal static Uri GetUserFollowingUri(string userPk, string rankToken, string maxId = "") + { + Uri instaUri; + if ( + !Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_FOLLOWING, userPk, rankToken), + out instaUri)) throw new Exception("Cant create URI for user following"); + if (string.IsNullOrEmpty(maxId)) return instaUri; + var uriBuilder = new UriBuilder(instaUri) { Query = $"max_id={maxId}" }; return uriBuilder.Uri; } @@ -142,7 +154,7 @@ public static Uri GetUserTagsUri(string userPk, string rankToken, string maxId = throw new Exception("Cant create URI for get user tags"); var query = $"rank_token={rankToken}&ranked_content=true"; if (!string.IsNullOrEmpty(maxId)) query += $"max_id={maxId}"; - var uriBuilder = new UriBuilder(instaUri) {Query = query}; + var uriBuilder = new UriBuilder(instaUri) { Query = query }; return uriBuilder.Uri; } @@ -168,7 +180,7 @@ public static Uri GetRecentActivityUri() if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.GET_RECENT_ACTIVITY, out instaUri)) throw new Exception("Cant create URI (get recent activity)"); var query = $"activity_module=all"; - var uriBuilder = new UriBuilder(instaUri) {Query = query}; + var uriBuilder = new UriBuilder(instaUri) { Query = query }; return uriBuilder.Uri; } @@ -179,7 +191,7 @@ public static Uri GetFollowingRecentActivityUri(string maxId = null) throw new Exception("Cant create URI (get following recent activity"); var query = string.Empty; if (!string.IsNullOrEmpty(maxId)) query += $"max_id={maxId}"; - var uriBuilder = new UriBuilder(instaUri) {Query = query}; + var uriBuilder = new UriBuilder(instaUri) { Query = query }; return uriBuilder.Uri; } @@ -303,5 +315,58 @@ public static Uri GetMediaConfigureUri() throw new Exception("Cant create URI for configuring media"); return instaUri; } + + public static Uri GetStoryTray() + { + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.GET_STORY_TRAY, out var instaUri)) + throw new Exception("Can't create URI for getting story tray"); + return instaUri; + } + + public static Uri GetUserStoryUri(long userId) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_STORY, userId), + out var instaUri)) + throw new Exception("Can't create URI for getting user's story"); + return instaUri; + } + + public static Uri GetStoryConfigureUri() + { + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.STORY_CONFIGURE, out var instaUri)) + throw new Exception("Can't create URI for configuring story media"); + return instaUri; + } + + public static Uri GetChangePasswordUri() + { + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.CHANGE_PASSWORD, out var instaUri)) + throw new Exception("Can't create URI for changing password"); + return instaUri; + } + + public static Uri GetDeleteMediaUri(string mediaId, InstaMediaType mediaType) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.DELETE_MEDIA, mediaId, (int)mediaType), out var instaUri)) + throw new Exception("Can't create URI for deleting media"); + return instaUri; + } + + public static Uri GetEditMediaUri(string mediaId) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.EDIT_MEDIA, mediaId), out var instaUri)) + throw new Exception("Can't create URI for editing media"); + return instaUri; + } + + public static Uri GetUserLikeFeedUri(string maxId = null) + { + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.LIKE_FEED, out var instaUri)) + throw new Exception("Can't create URI for getting like feed"); + var query = string.Empty; + 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/InstaSharper.csproj b/InstaSharper/InstaSharper.csproj index 1643dba4..8ef70459 100644 --- a/InstaSharper/InstaSharper.csproj +++ b/InstaSharper/InstaSharper.csproj @@ -3,7 +3,7 @@ 1.2.4 netstandard1.6;net452 - true + True InstaSharper InstaSharper 1.6.0 @@ -11,6 +11,12 @@ false false false + True + 1.2.5 + + + + diff --git a/README.md b/README.md index e7f5717d..d42772c7 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Note that: there is a simple [Instagram API](https://github.com/a-legotin/Instag [![Telegram chat](https://img.shields.io/badge/telegram-channel-blue.svg)](https://t.me/instasharper) [![GitHub stars](https://img.shields.io/github/stars/a-legotin/InstaSharper.svg)](https://github.com/a-legotin/InstaSharper/stargazers) -#### Current version: 1.2.4 [Stable], 1.2.5 [Under development] +#### Current version: 1.2.5 [Stable], 1.2.6 [Under development] ## Overview This project intends to provide all the features available in the Instagram API up to v10.3.2. It is being developed in C# for .NET Framework 4.5.2 and .NET Standart 1.6 @@ -61,23 +61,23 @@ Currently the library supports following coverage of the following Instagram API - [x] Send comment - [x] Delete comment - [x] Upload photo +- [x] Get followings list +- [x] Delete media (photo/video) +- [x] Upload story (photo) +- [x] Change password +- [x] Upload video -- [ ] Get followings list * Get user list autocomplete * Register new user * Get megaphone log * Explore feed -* Upload video -* Upload story * Get full account backup * Send direct message * Edit media -* Delete media * Share media -* Change password -######for more details please check [Project roadmap](https://github.com/a-legotin/InstaSharper/wiki/Project-roadmap/_edit) +###### 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: @@ -122,7 +122,7 @@ IResult feed = await api.GetUserFeedAsync(); IResult postResult = await apiInstance.CommentMediaAsync("1234567891234567891_123456789", "Hi there!"); ``` -#####for more samples you can look for [Examples folder](https://github.com/a-legotin/InstaSharper/tree/master/InstaSharper.Examples) +##### for more samples you can look at [Examples folder](https://github.com/a-legotin/InstaSharper/tree/master/InstaSharper.Examples) #### [Why two separate repos with same mission?](https://github.com/a-legotin/InstagramAPI-Web/wiki/Difference-between-API-Web-and-just-API-repositories) diff --git a/appveyor.yml b/appveyor.yml index 95e1e1f7..408b7f7b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.2.4.{build} +version: 1.2.5.{build} os: Visual Studio 2017 platform: Any CPU configuration: Release @@ -13,17 +13,15 @@ skip_commits: skip_tags: true build: - publish_nuget: true # package projects with .nuspec files and push to artifacts - publish_nuget_symbols: true # generate and publish NuGet symbol packages - include_nuget_references: true # add -IncludeReferencedProjects option while packaging NuGet artifacts + publish_nuget: false # package projects with .nuspec files and push to artifacts + publish_nuget_symbols: false # generate and publish NuGet symbol packages + include_nuget_references: false # add -IncludeReferencedProjects option while packaging NuGet artifacts build_script: - ps: nuget sources add -Name MyGetXunit -Source https://www.myget.org/F/xunit/api/v3/index.json - ps: dotnet --info - ps: dotnet restore - ps: dotnet build - - ps: cd InstaSharper - - ps: dotnet pack -o ../nugetpack -c release environment: instaapiuserpassword: