diff --git a/.travis.yml b/.travis.yml index 26eea1c3..f7132f6b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,11 @@ language: csharp -solution: InstaSharper.sln -dotnet: 1.0.0-preview2-003121 -sudo: required -os: linux dist: trusty +dotnet: 1.0.1 +mono: none +solution: InstaSharper.sln script: - # dotnet info + - cd InstaSharper - dotnet --info - # Run dotnet new - dotnet restore - - cd InstaSharper - - dotnet build - - cd ../InstaSharper.Tests - - dotnet build - - dotnet test -parallel none \ No newline at end of file + - dotnet build --framework netstandard1.6 \ No newline at end of file diff --git a/InstaSharper.Examples/InstaSharper.Examples.csproj b/InstaSharper.Examples/InstaSharper.Examples.csproj index efe30f26..d6720a57 100644 --- a/InstaSharper.Examples/InstaSharper.Examples.csproj +++ b/InstaSharper.Examples/InstaSharper.Examples.csproj @@ -46,8 +46,13 @@ - + + + + + + diff --git a/InstaSharper.Examples/InstaSharperExamples.cs b/InstaSharper.Examples/InstaSharperExamples.cs deleted file mode 100644 index dff2c68a..00000000 --- a/InstaSharper.Examples/InstaSharperExamples.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Linq; -using InstaSharper.API; -using InstaSharper.API.Builder; -using InstaSharper.Classes; - -namespace InstaSharper.Examples -{ - internal class InstaSharperExamples - { - private static IInstaApi _instaApi; - - private static void Main(string[] args) - { - // create user session data and provide login details - var userSession = new UserSessionData - { - UserName = "username", - Password = "password" - }; - // create new InstaApi instance using Builder - _instaApi = new InstaApiBuilder() - .SetUser(userSession) - .Build(); - // login - var logInResult = _instaApi.Login(); - if (!logInResult.Succeeded) { Console.WriteLine($"Unable to login: {logInResult.Info.Message}"); } - else - { - // get currently logged in user - var currentUser = _instaApi.GetCurrentUser().Value; - Console.WriteLine($"Logged in: username - {currentUser.UserName}, full name - {currentUser.FullName}"); - // get followers - var followers = _instaApi.GetUserFollowersAsync(currentUser.UserName, 5).Result.Value; - Console.WriteLine($"Count of followers [{currentUser.UserName}]:{followers.Count}"); - // get user's media - var currentUserMedia = _instaApi.GetUserMedia(currentUser.UserName, 5); - if (currentUserMedia.Succeeded) - { - Console.WriteLine($"Media count [{currentUser.UserName}]: {currentUserMedia.Value.Count}"); - foreach (var media in currentUserMedia.Value) Console.WriteLine($"Media [{currentUser.UserName}]: {media.Caption.Text}, {media.Code}, likes: {media.LikesCount}, image link: {media.Images.LastOrDefault()?.Url}"); - } - - //get user feed, first 5 pages - var userFeed = _instaApi.GetExploreFeed(5); - if (userFeed.Succeeded) - { - Console.WriteLine($"Feed items (in {userFeed.Value.Pages} pages) [{currentUser.UserName}]: {userFeed.Value.Medias.Count}"); - foreach (var media in userFeed.Value.Medias) Console.WriteLine($"Feed item - code:{media.Code}, likes: {media.LikesCount}"); - } - // get tag feed, first 5 pages - var tagFeed = _instaApi.GetTagFeed("gm", 5); - if (userFeed.Succeeded) - { - Console.WriteLine($"Tag feed items (in {tagFeed.Value.Pages} pages) [{currentUser.UserName}]: {tagFeed.Value.Medias.Count}"); - foreach (var media in tagFeed.Value.Medias) Console.WriteLine($"Tag feed item - code: {media.Code}, likes: {media.LikesCount}"); - } - var logoutResult = _instaApi.Logout(); - if (logoutResult.Value) Console.WriteLine("Logout succeed"); - } - Console.ReadKey(); - } - } -} \ No newline at end of file diff --git a/InstaSharper.Examples/Program.cs b/InstaSharper.Examples/Program.cs new file mode 100644 index 00000000..3e4530a2 --- /dev/null +++ b/InstaSharper.Examples/Program.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using InstaSharper.API; +using InstaSharper.API.Builder; +using InstaSharper.Classes; +using InstaSharper.Examples.Samples; + +namespace InstaSharper.Examples +{ + public class Program + { + /// + /// Api instance (one instance per Instagram user) + /// + private static IInstaApi _instaApi; + + private static void Main(string[] args) + { + Console.WriteLine("Starting demo of InstaSharper project"); + // create user session data and provide login details + var userSession = new UserSessionData + { + UserName = "username", + Password = "password" + }; + // create new InstaApi instance using Builder + _instaApi = new InstaApiBuilder() + .SetUser(userSession) + .Build(); + // login + var logInResult = _instaApi.Login(); + if (!logInResult.Succeeded) + { + Console.WriteLine($"Unable to login: {logInResult.Info.Message}"); + } + else + { + Console.WriteLine("Press 1 to start basic demo samples"); + Console.WriteLine("Press 2 to start upload photo demo sample"); + Console.WriteLine("Press 3 to start comment media demo sample"); + + var key = Console.ReadKey(); + switch (key.Key) + { + case ConsoleKey.D1: + new Basics(_instaApi).DoShow(); + break; + case ConsoleKey.D2: + new UploadPhoto(_instaApi).DoShow(); + break; + case ConsoleKey.D3: + new CommentMedia(_instaApi).DoShow(); + break; + default: + break; + } + var logoutResult = _instaApi.Logout(); + if (logoutResult.Value) Console.WriteLine("Logout succeed"); + } + Console.ReadKey(); + } + } +} \ No newline at end of file diff --git a/InstaSharper.Examples/Samples/Basics.cs b/InstaSharper.Examples/Samples/Basics.cs new file mode 100644 index 00000000..f933dd71 --- /dev/null +++ b/InstaSharper.Examples/Samples/Basics.cs @@ -0,0 +1,69 @@ +using System; +using System.Linq; +using InstaSharper.API; +using InstaSharper.Examples.Utils; + +namespace InstaSharper.Examples.Samples +{ + internal class Basics + { + /// + /// Config values + /// + private static readonly int _maxDescriptionLength = 20; + + private readonly IInstaApi _instaApi; + + public Basics(IInstaApi instaApi) + { + _instaApi = instaApi; + } + + public void DoShow() + { + // get currently logged in user + var currentUser = _instaApi.GetCurrentUser().Value; + Console.WriteLine($"Logged in: username - {currentUser.UserName}, full name - {currentUser.FullName}"); + + // get self followers + var followers = _instaApi.GetUserFollowersAsync(currentUser.UserName, 5).Result.Value; + Console.WriteLine($"Count of followers [{currentUser.UserName}]:{followers.Count}"); + + // get self user's media, latest 5 pages + var currentUserMedia = _instaApi.GetUserMedia(currentUser.UserName, 5); + if (currentUserMedia.Succeeded) + { + Console.WriteLine($"Media count [{currentUser.UserName}]: {currentUserMedia.Value.Count}"); + foreach (var media in currentUserMedia.Value) + ConsoleUtils.PrintMedia("Self media", media, _maxDescriptionLength); + } + + //get user time line feed, latest 5 pages + var userFeed = _instaApi.GetUserTimelineFeed(5); + if (userFeed.Succeeded) + { + Console.WriteLine( + $"Feed items (in {userFeed.Value.Pages} pages) [{currentUser.UserName}]: {userFeed.Value.Medias.Count}"); + foreach (var media in userFeed.Value.Medias) + ConsoleUtils.PrintMedia("Feed media", media, _maxDescriptionLength); + //like first 10 medias from user timeline feed + foreach (var media in userFeed.Value.Medias.Take(10)) + { + var likeResult = _instaApi.LikeMedia(media.InstaIdentifier); + var resultString = likeResult.Value ? "liked" : "not liked"; + Console.WriteLine($"Media {media.Code} {resultString}"); + } + } + + // get tag feed, latest 5 pages + var tagFeed = _instaApi.GetTagFeed("quadcopter", 5); + if (tagFeed.Succeeded) + { + Console.WriteLine( + $"Tag feed items (in {tagFeed.Value.Pages} pages) [{currentUser.UserName}]: {tagFeed.Value.Medias.Count}"); + foreach (var media in tagFeed.Value.Medias) + ConsoleUtils.PrintMedia("Tag feed", media, _maxDescriptionLength); + } + } + } +} \ No newline at end of file diff --git a/InstaSharper.Examples/Samples/CommentMedia.cs b/InstaSharper.Examples/Samples/CommentMedia.cs new file mode 100644 index 00000000..b8e1c038 --- /dev/null +++ b/InstaSharper.Examples/Samples/CommentMedia.cs @@ -0,0 +1,23 @@ +using System; +using InstaSharper.API; + +namespace InstaSharper.Examples.Samples +{ + internal class CommentMedia + { + private readonly IInstaApi _instaApi; + + public CommentMedia(IInstaApi instaApi) + { + _instaApi = instaApi; + } + + public void DoShow() + { + var commentResult = _instaApi.CommentMedia("", "Hi there!"); + Console.WriteLine(commentResult.Succeeded + ? $"Comment created: {commentResult.Value.Pk}, text: {commentResult.Value.Text}" + : $"Unable to create comment: {commentResult.Info.Message}"); + } + } +} \ No newline at end of file diff --git a/InstaSharper.Examples/Samples/UploadPhoto.cs b/InstaSharper.Examples/Samples/UploadPhoto.cs new file mode 100644 index 00000000..b11915ca --- /dev/null +++ b/InstaSharper.Examples/Samples/UploadPhoto.cs @@ -0,0 +1,31 @@ +using System; +using System.IO; +using InstaSharper.API; +using InstaSharper.Classes.Models; + +namespace InstaSharper.Examples.Samples +{ + internal class UploadPhoto + { + private readonly IInstaApi _instaApi; + + public UploadPhoto(IInstaApi instaApi) + { + _instaApi = instaApi; + } + + public void DoShow() + { + var mediaImage = new MediaImage + { + Height = 1080, + Width = 1080, + URI = new Uri(Path.GetFullPath(@"c:\someawesomepicture.jpg"), UriKind.Absolute).LocalPath + }; + var result = _instaApi.UploadPhoto(mediaImage, "someawesomepicture"); + Console.WriteLine(result.Succeeded + ? $"Media created: {result.Value.Pk}, {result.Value.Caption}" + : $"Unable to upload photo: {result.Info.Message}"); + } + } +} \ No newline at end of file diff --git a/InstaSharper.Examples/Utils/ConsoleUtils.cs b/InstaSharper.Examples/Utils/ConsoleUtils.cs new file mode 100644 index 00000000..173f5476 --- /dev/null +++ b/InstaSharper.Examples/Utils/ConsoleUtils.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using InstaSharper.Classes.Models; + +namespace InstaSharper.Examples.Utils +{ + public static class ConsoleUtils + { + public static void PrintMedia(string header, InstaMedia media, int maxDescriptionLength) + { + Console.WriteLine( + $"{header} [{media.User.UserName}]: {media.Caption?.Text.Truncate(maxDescriptionLength)}, {media.Code}, likes: {media.LikesCount}, multipost: {media.IsMultiPost}"); + } + } +} \ No newline at end of file diff --git a/InstaSharper.Examples/Utils/StringExtensions.cs b/InstaSharper.Examples/Utils/StringExtensions.cs new file mode 100644 index 00000000..b8cad66f --- /dev/null +++ b/InstaSharper.Examples/Utils/StringExtensions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace InstaSharper.Examples.Utils +{ + public static class StringExtensions + { + public static string Truncate(this string value, int maxChars) + { + return value.Length <= maxChars ? value : value.Substring(0, maxChars) + "..."; + } + } +} \ No newline at end of file diff --git a/InstaSharper.Tests/Endpoints/FollowersTest.cs b/InstaSharper.Tests/Endpoints/FollowersTest.cs index 75994640..f1201f79 100644 --- a/InstaSharper.Tests/Endpoints/FollowersTest.cs +++ b/InstaSharper.Tests/Endpoints/FollowersTest.cs @@ -50,7 +50,6 @@ public async void GetCurrentUserFollwersTest() Password = password }); if (!TestHelpers.Login(apiInstance, _output)) return; - if (!TestHelpers.Login(apiInstance, _output)) return; var result = await apiInstance.GetCurrentUserFollowersAsync(); var followers = result.Value; //assert @@ -60,7 +59,7 @@ public async void GetCurrentUserFollwersTest() [RunnableInDebugOnlyTheory] [InlineData(196754384)] - public async void FollowUserTest(long userId) + public async void FollowUnfollowUserTest(long userId) { var currentUsername = "alex_codegarage"; var password = Environment.GetEnvironmentVariable("instaapiuserpassword"); @@ -69,12 +68,15 @@ public async void FollowUserTest(long userId) UserName = currentUsername, Password = password }); - if (!TestHelpers.Login(apiInstance, _output)) return; - var result = await apiInstance.FollowUserAsync(userId); - var followers = result.Value; + if (!TestHelpers.Login(apiInstance, _output)) throw new Exception("Not logged in"); + var followResult = await apiInstance.FollowUserAsync(userId); + var unFollowResult = await apiInstance.UnFollowUserAsync(userId); //assert - Assert.True(result.Succeeded); - Assert.NotNull(followers); + Assert.True(followResult.Succeeded); + Assert.True(unFollowResult.Succeeded); + + Assert.True(followResult.Value.Following); + Assert.False(unFollowResult.Value.Following); } } } \ No newline at end of file diff --git a/InstaSharper.Tests/Endpoints/LikesTest.cs b/InstaSharper.Tests/Endpoints/LikesTest.cs index e54a68b6..8dc02223 100644 --- a/InstaSharper.Tests/Endpoints/LikesTest.cs +++ b/InstaSharper.Tests/Endpoints/LikesTest.cs @@ -20,7 +20,7 @@ public LikesTest(ITestOutputHelper output) [RunnableInDebugOnlyTheory] [InlineData("1484832969772514291_196754384")] - public async void LikeTest(string mediaId) + public async void LikeUnlikeTest(string mediaId) { //arrange var apiInstance = @@ -29,35 +29,13 @@ public async void LikeTest(string mediaId) UserName = _username, Password = _password }); + if (!TestHelpers.Login(apiInstance, _output)) throw new Exception("Not logged in"); //act - var loginSucceed = TestHelpers.Login(apiInstance, _output); - Assert.True(loginSucceed); - var result = await apiInstance.LikeMediaAsync(mediaId); - var exploreGeed = result.Value; + var likeResult = await apiInstance.LikeMediaAsync(mediaId); + var unLikeResult = await apiInstance.UnLikeMediaAsync(mediaId); //assert - Assert.True(result.Succeeded); - Assert.NotNull(exploreGeed); - } - - [RunnableInDebugOnlyTheory] - [InlineData("1484832969772514291_196754384")] - public async void UnLikeTest(string mediaId) - { - //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.UnLikeMediaAsync(mediaId); - var exploreGeed = result.Value; - //assert - Assert.True(result.Succeeded); - Assert.NotNull(exploreGeed); + Assert.True(likeResult.Succeeded); + Assert.True(unLikeResult.Succeeded); } } } \ No newline at end of file diff --git a/InstaSharper.Tests/Endpoints/MediaTest.cs b/InstaSharper.Tests/Endpoints/MediaTest.cs index 8c9e67fa..ad9cd2d5 100644 --- a/InstaSharper.Tests/Endpoints/MediaTest.cs +++ b/InstaSharper.Tests/Endpoints/MediaTest.cs @@ -85,7 +85,7 @@ public async void GetMediaCommentsTest(string mediaId) } [RunnableInDebugOnlyTheory] - [InlineData("mohammadq74")] + [InlineData("alex_codegarage")] public async void GetUserMediaListTest(string userToFetch) { //arrange @@ -109,8 +109,32 @@ public async void GetUserMediaListTest(string userToFetch) //assert Assert.NotNull(posts); Assert.Equal(userToFetch, posts.Value[random.Next(0, posts.Value.Count)].User.UserName); - Assert.Equal(pages, posts.Value.Pages); Assert.False(anyDuplicate); } + + [RunnableInDebugOnlyTheory] + [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(postResult.Succeeded); + Assert.Equal(text, postResult.Value.Text); + Assert.True(delResult.Succeeded); + + } } } \ No newline at end of file diff --git a/InstaSharper.Tests/Endpoints/UploadTest.cs b/InstaSharper.Tests/Endpoints/UploadTest.cs new file mode 100644 index 00000000..40712061 --- /dev/null +++ b/InstaSharper.Tests/Endpoints/UploadTest.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using InstaSharper.Classes; +using InstaSharper.Classes.Models; +using InstaSharper.Tests.Utils; +using Xunit; +using Xunit.Abstractions; + +namespace InstaSharper.Tests.Endpoints +{ + [Collection("Endpoints")] + public class UploadTest + { + private readonly ITestOutputHelper _output; + + public UploadTest(ITestOutputHelper output) + { + _output = output; + } + + [RunnableInDebugOnlyFact] + public async void UploadImage() + { + 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 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"); + + //assert + Assert.True(result.Succeeded); + Assert.NotNull(result.Value); + } + } +} diff --git a/InstaSharper.Tests/Endpoints/UserInfoTest.cs b/InstaSharper.Tests/Endpoints/UserInfoTest.cs index 9db4d3f7..c87d4820 100644 --- a/InstaSharper.Tests/Endpoints/UserInfoTest.cs +++ b/InstaSharper.Tests/Endpoints/UserInfoTest.cs @@ -57,5 +57,26 @@ public async void GetUserTest() Assert.NotNull(user); Assert.Equal(user.UserName, _username); } + + [RunnableInDebugOnlyFact] + 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(resultSetPrivate.Succeeded); + Assert.NotNull(resultSetPrivate.Value); + Assert.True(resultSetPublic.Succeeded); + Assert.NotNull(resultSetPrivate.Value); + } } } \ No newline at end of file diff --git a/InstaSharper.Tests/InstaSharper.Tests.csproj b/InstaSharper.Tests/InstaSharper.Tests.csproj new file mode 100644 index 00000000..00906169 --- /dev/null +++ b/InstaSharper.Tests/InstaSharper.Tests.csproj @@ -0,0 +1,34 @@ + + + + netcoreapp1.0 + InstaSharper.Tests + InstaSharper.Tests + true + 1.0.4 + false + false + false + + + + + + + + + + + PreserveNewest + + + + + + + + + + + + diff --git a/InstaSharper.Tests/InstaSharper.Tests.xproj b/InstaSharper.Tests/InstaSharper.Tests.xproj deleted file mode 100644 index 042194cb..00000000 --- a/InstaSharper.Tests/InstaSharper.Tests.xproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - dbe6fbb7-cde7-4cdf-ab08-989a43cc4d46 - InstaSharper.Tests - .\obj - .\bin\ - v4.5.2 - - - 2.0 - - - - - - - \ No newline at end of file diff --git a/InstaSharper.Tests/project.json b/InstaSharper.Tests/project.json deleted file mode 100644 index a17d8d36..00000000 --- a/InstaSharper.Tests/project.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "version": "1.0.0-*", - "testRunner": "xunit", - "dependencies": { - "xunit": "2.2.0-beta2-build3300", - "InstaSharper": "1.2.3", - "dotnet-test-xunit": "2.2.0-preview2-build1029" - }, - "frameworks": { - "netcoreapp1.0": { - "dependencies": { - "Microsoft.NETCore.App": { - "type": "platform", - "version": "1.0.0" - } - } - } - }, - "buildOptions": { - "copyToOutput": { - "include": ["xunit.runner.json"] - } - } -} \ No newline at end of file diff --git a/InstaSharper.sln b/InstaSharper.sln index bd2eb111..5434cb35 100644 --- a/InstaSharper.sln +++ b/InstaSharper.sln @@ -1,11 +1,11 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.26114.2 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "InstaSharper", "InstaSharper\InstaSharper.xproj", "{449A948D-CC65-4D1A-8159-6FA232F972D9}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InstaSharper", "InstaSharper\InstaSharper.csproj", "{449A948D-CC65-4D1A-8159-6FA232F972D9}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "InstaSharper.Tests", "InstaSharper.Tests\InstaSharper.Tests.xproj", "{DBE6FBB7-CDE7-4CDF-AB08-989A43CC4D46}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InstaSharper.Tests", "InstaSharper.Tests\InstaSharper.Tests.csproj", "{DBE6FBB7-CDE7-4CDF-AB08-989A43CC4D46}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/InstaSharper/API/IInstaApi.cs b/InstaSharper/API/IInstaApi.cs index 4b35c87f..c21e06bb 100644 --- a/InstaSharper/API/IInstaApi.cs +++ b/InstaSharper/API/IInstaApi.cs @@ -58,11 +58,11 @@ public interface IInstaApi /// /// Get media by its id (code) /// - /// Maximum count of pages to retrieve + /// Maximum count of pages to retrieve /// /// /// - IResult GetMediaByCode(string mediaCode); + IResult GetMediaById(string mediaId); /// /// Get user info by its user name @@ -193,7 +193,55 @@ public interface IInstaApi /// /// User Id /// True i success - IResult FollowUser(long userId); + 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 @@ -221,7 +269,7 @@ public interface IInstaApi Task> GetUserTimelineFeedAsync(int maxPages = 0); /// - /// Get user explore feed asynchronously + /// Get user explore feed asynchronously (Explore tab info) /// /// Maximum count of pages to retrieve /// > @@ -370,7 +418,13 @@ public interface IInstaApi /// Follow user /// /// User id - Task> FollowUserAsync(long userId); + Task> FollowUserAsync(long userId); + + /// + /// Stop follow user + /// + /// User id + Task> UnFollowUserAsync(long userId); /// /// Get media comments @@ -384,6 +438,46 @@ public interface IInstaApi /// Media id Task> GetMediaLikersAsync(string mediaId); + /// + /// Set current account private + /// + Task> SetAccountPrivateAsync(); + + /// + /// Set current account public + /// + Task> SetAccountPublicAsync(); + + /// + /// Comment media + /// + /// Media id + /// Comment text + Task> CommentMediaAsync(string mediaId, string text); + + /// + /// Delete comment from media + /// + /// Media id + /// Comment id + Task> DeleteCommentAsync(string mediaId, string commentId); + + /// + /// Upload photo + /// + /// Photo to upload + /// Caption + Task> UploadPhotoAsync(MediaImage image, string caption); + + /// + /// Configure photo + /// + /// Photo to configure + /// Upload id + /// Caption + /// + Task> ConfigurePhotoAsync(MediaImage image, string uploadId, string caption); + #endregion } } \ No newline at end of file diff --git a/InstaSharper/API/InstaApi.cs b/InstaSharper/API/InstaApi.cs index 848405ed..4348acfa 100644 --- a/InstaSharper/API/InstaApi.cs +++ b/InstaSharper/API/InstaApi.cs @@ -3,6 +3,7 @@ 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; @@ -11,12 +12,12 @@ using InstaSharper.Converters.Json; using InstaSharper.Helpers; using InstaSharper.Logger; -using InstaSharper.ResponseWrappers; -using InstaSharper.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using InstaRecentActivityConverter = InstaSharper.Converters.Json.InstaRecentActivityConverter; -using System.Text; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using Newtonsoft.Json.Linq; +using System.IO; namespace InstaSharper.API { @@ -58,12 +59,16 @@ 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; @@ -149,11 +154,46 @@ public IResult UnlikeMedia(string mediaId) return UnLikeMediaAsync(mediaId).Result; } - public IResult FollowUser(long userId) + 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 @@ -270,7 +310,8 @@ public async Task> GetUserTimelineFeedAsync(int maxPages = 0) nextId = nextFeed.Value.NextMaxId; moreAvailable = nextFeed.Value.MoreAvailable; feed.Medias.AddRange( - nextFeed.Value.Items.Select(ConvertersFabric.GetSingleMediaConverter).Select(conv => conv.Convert())); + nextFeed.Value.Items.Select(ConvertersFabric.GetSingleMediaConverter) + .Select(conv => conv.Convert())); feed.Pages++; } return Result.Success(feed); @@ -357,7 +398,7 @@ public async Task> GetMediaByIdAsync(string mediaId) new InstaMediaListDataConverter()); if (mediaResponse.Medias?.Count != 1) { - string errorMessage = $"Got wrong media count for request with media id={mediaId}"; + var errorMessage = $"Got wrong media count for request with media id={mediaId}"; _logger.Write(errorMessage); return Result.Fail(errorMessage); } @@ -375,7 +416,8 @@ public async Task> GetUserAsync(string username) request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, InstaApiConstants.TIMEZONE_OFFSET.ToString())); request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_COUNT, "1")); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_RANK_TOKEN, _user.RankToken)); + request.Properties.Add( + new KeyValuePair(InstaApiConstants.HEADER_RANK_TOKEN, _user.RankToken)); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) @@ -384,7 +426,7 @@ public async Task> GetUserAsync(string username) var user = userInfo.Users?.FirstOrDefault(u => u.UserName == username); if (user == null) { - string errorMessage = $"Can't find this user: {username}"; + var errorMessage = $"Can't find this user: {username}"; _logger.Write(errorMessage); return Result.Fail(errorMessage); } @@ -653,6 +695,368 @@ public async Task> CheckpointAsync(string checkPointUrl) return Result.Fail(GetBadStatusFromJsonString(json).Message, false); } + + public async Task> LikeMediaAsync(string mediaId) + { + return await LikeUnlikeMediaInternal(mediaId, UriCreator.GetLikeMediaUri(mediaId)); + } + + public async Task> UnLikeMediaAsync(string mediaId) + { + return await LikeUnlikeMediaInternal(mediaId, UriCreator.GetUnLikeMediaUri(mediaId)); + } + + + public async Task> LikeUnlikeMediaInternal(string mediaId, Uri instaUri) + { + ValidateUser(); + ValidateLoggedIn(); + try + { + var fields = new Dictionary + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUder.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"media_id", mediaId} + }; + var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + return Result.Success(true); + var status = GetBadStatusFromJsonString(json); + return Result.Fail(status.Message, false); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, false); + } + } + + public async Task> GetMediaCommentsAsync(string mediaId, int maxPages = 0) + { + ValidateUser(); + ValidateLoggedIn(); + try + { + if (maxPages == 0) maxPages = int.MaxValue; + var commentsUri = UriCreator.GetMediaCommentsUri(mediaId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, commentsUri, _deviceInfo); + 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); + var commentListResponse = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.GetCommentListConverter(commentListResponse); + var instaComments = converter.Convert(); + instaComments.Pages++; + var nextId = commentListResponse.NextMaxId; + var moreAvailable = commentListResponse.MoreComentsAvailable; + while (moreAvailable && instaComments.Pages < maxPages) + { + if (string.IsNullOrEmpty(nextId)) break; + var nextComments = await GetCommentListWithMaxIdAsync(mediaId, nextId); + if (!nextComments.Succeeded) + Result.Success($"Not all pages was downloaded: {nextComments.Info.Message}", instaComments); + nextId = nextComments.Value.NextMaxId; + moreAvailable = nextComments.Value.MoreComentsAvailable; + converter = ConvertersFabric.GetCommentListConverter(nextComments.Value); + instaComments.Comments.AddRange(converter.Convert().Comments); + instaComments.Pages++; + } + return Result.Success(instaComments); + } + catch (Exception exception) + { + return Result.Fail(exception); + } + } + + public async Task> GetMediaLikersAsync(string mediaId) + { + ValidateUser(); + ValidateLoggedIn(); + try + { + var likersUri = UriCreator.GetMediaLikersUri(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); + var instaUsers = new InstaUserList(); + var mediaLikersResponse = JsonConvert.DeserializeObject(json); + if (mediaLikersResponse.UsersCount < 1) return Result.Success(instaUsers); + instaUsers.AddRange( + mediaLikersResponse.Users.Select(ConvertersFabric.GetUserConverter) + .Select(converter => converter.Convert())); + return Result.Success(instaUsers); + } + catch (Exception exception) + { + return Result.Fail(exception); + } + } + + public async Task> FollowUserAsync(long userId) + { + return await FollowUnfollowUserInternal(userId, UriCreator.GetFollowUserUri(userId)); + } + + public async Task> UnFollowUserAsync(long userId) + { + return await FollowUnfollowUserInternal(userId, UriCreator.GetUnFollowUserUri(userId)); + } + + + public async Task> SetAccountPrivateAsync() + { + ValidateUser(); + ValidateLoggedIn(); + try + { + var instaUri = UriCreator.GetUriSetAccountPrivate(); + var fields = new Dictionary + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUder.Pk}, + {"_csrftoken", _user.CsrfToken} + }; + var hash = CryptoHelper.CalculateHash(InstaApiConstants.IG_SIGNATURE_KEY, + JsonConvert.SerializeObject(fields)); + var payload = JsonConvert.SerializeObject(fields); + var signature = $"{hash}.{Uri.EscapeDataString(payload)}"; + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); + request.Content = new FormUrlEncodedContent(fields); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, + InstaApiConstants.IG_SIGNATURE_KEY_VERSION); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + { + var userInfoUpdated = JsonConvert.DeserializeObject(json); + if (!userInfoUpdated.IsOk()) + return Result.Fail(GetBadStatusFromJsonString(json).Message); + var converter = ConvertersFabric.GetUserConverter(userInfoUpdated); + return Result.Success(converter.Convert()); + } + var status = GetBadStatusFromJsonString(json); + return Result.Fail(status.Message, (InstaUser) null); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaUser) null); + } + } + + public async Task> SetAccountPublicAsync() + { + ValidateUser(); + ValidateLoggedIn(); + try + { + var instaUri = UriCreator.GetUriSetAccountPublic(); + var fields = new Dictionary + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUder.Pk}, + {"_csrftoken", _user.CsrfToken} + }; + var hash = CryptoHelper.CalculateHash(InstaApiConstants.IG_SIGNATURE_KEY, + JsonConvert.SerializeObject(fields)); + var payload = JsonConvert.SerializeObject(fields); + var signature = $"{hash}.{Uri.EscapeDataString(payload)}"; + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); + request.Content = new FormUrlEncodedContent(fields); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, + InstaApiConstants.IG_SIGNATURE_KEY_VERSION); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + { + var userInfoUpdated = JsonConvert.DeserializeObject(json); + if (!userInfoUpdated.IsOk()) + return Result.Fail(GetBadStatusFromJsonString(json).Message); + var converter = ConvertersFabric.GetUserConverter(userInfoUpdated); + return Result.Success(converter.Convert()); + } + var status = GetBadStatusFromJsonString(json); + return Result.Fail(status.Message, (InstaUser) null); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaUser) null); + } + } + + + public async Task> CommentMediaAsync(string mediaId, string text) + { + ValidateUser(); + ValidateLoggedIn(); + try + { + var instaUri = UriCreator.GetPostCommetUri(mediaId); + var breadcrumb = CryptoHelper.GetCommentBreadCrumbEncoded(text); + var fields = new Dictionary + { + {"user_breadcrumb", breadcrumb}, + {"idempotence_token", Guid.NewGuid().ToString()}, + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUder.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"comment_text", text}, + {"containermodule", "comments_feed_timeline"}, + {"radio_type", "wifi-none"} + }; + var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + { + var commentResponse = JsonConvert.DeserializeObject(json, + new InstaCommentDataConverter()); + var converter = ConvertersFabric.GetCommentConverter(commentResponse); + return Result.Success(converter.Convert()); + } + var status = GetBadStatusFromJsonString(json); + return Result.Fail(status.Message, (InstaComment) null); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaComment) null); + } + } + + public async Task> DeleteCommentAsync(string mediaId, string commentId) + { + ValidateUser(); + ValidateLoggedIn(); + try + { + var instaUri = UriCreator.GetDeleteCommetUri(mediaId, commentId); + var fields = new Dictionary + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUder.Pk}, + {"_csrftoken", _user.CsrfToken} + }; + var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields); + var response = await _httpClient.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + return Result.Success(true); + var status = GetBadStatusFromJsonString(json); + return Result.Fail(status.Message, false); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, false); + } + } + + public async Task> UploadPhotoAsync(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 ConfigurePhotoAsync(image, uploadId, caption); + var status = GetBadStatusFromJsonString(json); + return Result.Fail(status.Message, (InstaMedia) null); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaMedia) null); + } + } + + public async Task> ConfigurePhotoAsync(MediaImage image, string uploadId, string caption) + { + ValidateUser(); + ValidateLoggedIn(); + try + { + var instaUri = UriCreator.GetMediaConfigureUri(); + var androidVersion = + AndroidVersion.FromString(_deviceInfo.FirmwareFingerprint.Split('/')[2].Split(':')[1]); + if (androidVersion == null) + return Result.Fail("Unsupported android version", (InstaMedia) null); + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUder.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"media_folder", "Camera"}, + {"source_type", "4"}, + {"caption", caption}, + {"upload_id", uploadId}, + { + "device", new JObject + { + {"manufacturer", _deviceInfo.HardwareManufacturer}, + {"model", _deviceInfo.HardwareModel}, + {"android_version", androidVersion.VersionNumber}, + {"android_release", androidVersion.APILevel} + } + }, + { + "edits", new JObject + { + {"crop_original_size", new JArray {image.Width, image.Height}}, + {"crop_center", new JArray {0.0, -0.0}}, + {"crop_zoom", 1} + } + }, + { + "extra", new JObject + { + {"source_width", image.Width}, + {"source_height", image.Height} + } + } + }; + 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.GetSingleMediaConverter(mediaResponse); + return Result.Success(converter.Convert()); + } + var status = GetBadStatusFromJsonString(json); + return Result.Fail(status.Message, (InstaMedia) null); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, (InstaMedia) null); + } + } + #endregion #region private part @@ -679,7 +1083,9 @@ private BadStatusResponse GetBadStatusFromJsonString(string json) var badStatus = new BadStatusResponse(); try { - badStatus = JsonConvert.DeserializeObject(json); + if (json == "Oops, an error occurred\n") + badStatus.Message = json; + else badStatus = JsonConvert.DeserializeObject(json); } catch (Exception ex) { @@ -739,7 +1145,8 @@ private async Task> GetUserMediaListWithMaxIdAsy return Result.Fail("", (InstaMediaListResponse) null); } - private async Task> GetUserFollowersWithMaxIdAsync(string username, string maxId) + private async Task> GetUserFollowersWithMaxIdAsync(string username, + string maxId) { ValidateUser(); try @@ -823,7 +1230,8 @@ private async Task> GetTagFeedWithMaxIdAsync(str } } - private async Task> GetCommentListWithMaxIdAsync(string mediaId, string nextId) + private async Task> GetCommentListWithMaxIdAsync(string mediaId, + string nextId) { var commentsUri = UriCreator.GetMediaCommentsUri(mediaId); var commentsUriMaxId = new UriBuilder(commentsUri) {Query = $"max_id={nextId}"}.Uri; @@ -838,139 +1246,39 @@ private async Task> GetCommentListWithMaxIdAsy return Result.Fail("", (InstaCommentListResponse) null); } - public async Task> LikeMediaAsync(string mediaId) + private async Task> FollowUnfollowUserInternal(long userId, Uri instaUri) { ValidateUser(); ValidateLoggedIn(); try { - var instaUri = UriCreator.GetLikeMediaUri(mediaId); - var signature = $"{_requestMessage.GenerateSignature()}.{_requestMessage.GetMessageString()}"; var fields = new Dictionary { - {InstaApiConstants.HEADER_IG_SIGNATURE, signature}, - {InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION} + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUder.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"user_id", userId.ToString()}, + {"radio_type", "wifi-none"} }; - var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); - request.Content = new FormUrlEncodedContent(fields); - request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); - request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, - InstaApiConstants.IG_SIGNATURE_KEY_VERSION); + var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields); var response = await _httpClient.SendAsync(request); var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) + if (response.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(json)) { - return Result.Success(true); + var friendshipStatus = JsonConvert.DeserializeObject(json, + new InstaFriendShipDataConverter()); + var converter = ConvertersFabric.GetFriendShipStatusConverter(friendshipStatus); + return Result.Success(converter.Convert()); } - var loginInfo = GetBadStatusFromJsonString(json); - return Result.Fail(loginInfo.Message, false); + var status = GetBadStatusFromJsonString(json); + return Result.Fail(status.Message, (InstaFriendshipStatus) null); } catch (Exception exception) { - return Result.Fail(exception.Message, false); + return Result.Fail(exception.Message, (InstaFriendshipStatus) null); } } - public async Task> UnLikeMediaAsync(string mediaId) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var signature = $"{_requestMessage.GenerateSignature()}.{_requestMessage.GetMessageString()}"; - var fields = new Dictionary - { - {InstaApiConstants.HEADER_IG_SIGNATURE, signature}, - {InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION} - }; - var instaUri = UriCreator.GetUnLikeMediaUri(mediaId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); - request.Content = new FormUrlEncodedContent(fields); - request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); - request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, - InstaApiConstants.IG_SIGNATURE_KEY_VERSION); - var response = await _httpClient.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - return Result.Success(true); - var loginInfo = GetBadStatusFromJsonString(json); - return Result.Fail(loginInfo.Message, false); - } - catch (Exception exception) - { - return Result.Fail(exception.Message, false); - } - } - - public async Task> GetMediaCommentsAsync(string mediaId, int maxPages = 0) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - if (maxPages == 0) maxPages = int.MaxValue; - var commentsUri = UriCreator.GetMediaCommentsUri(mediaId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, commentsUri, _deviceInfo); - 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); - var commentListResponse = JsonConvert.DeserializeObject(json); - var converter = ConvertersFabric.GetCommentListConverter(commentListResponse); - var instaComments = converter.Convert(); - instaComments.Pages++; - var nextId = commentListResponse.NextMaxId; - var moreAvailable = commentListResponse.MoreComentsAvailable; - while (moreAvailable && instaComments.Pages < maxPages) - { - if (string.IsNullOrEmpty(nextId)) break; - var nextComments = await GetCommentListWithMaxIdAsync(mediaId, nextId); - if (!nextComments.Succeeded) - Result.Success($"Not all pages was downloaded: {nextComments.Info.Message}", instaComments); - nextId = nextComments.Value.NextMaxId; - moreAvailable = nextComments.Value.MoreComentsAvailable; - converter = ConvertersFabric.GetCommentListConverter(nextComments.Value); - instaComments.Comments.AddRange(converter.Convert().Comments); - instaComments.Pages++; - } - return Result.Success(instaComments); - } - catch (Exception exception) - { - return Result.Fail(exception); - } - } - - public async Task> GetMediaLikersAsync(string mediaId) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var likersUri = UriCreator.GetMediaLikersUri(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); - var instaUsers = new InstaUserList(); - var mediaLikersResponse = JsonConvert.DeserializeObject(json); - if (mediaLikersResponse.UsersCount < 1) return Result.Success(instaUsers); - instaUsers.AddRange( - mediaLikersResponse.Users.Select(ConvertersFabric.GetUserConverter) - .Select(converter => converter.Convert())); - return Result.Success(instaUsers); - } - catch (Exception exception) - { - return Result.Fail(exception); - } - } - - public async Task> FollowUserAsync(long userId) - { - throw new NotImplementedException(); - } - #endregion } } \ No newline at end of file diff --git a/InstaSharper/API/InstaApiConstants.cs b/InstaSharper/API/InstaApiConstants.cs index 5cc71972..835714b0 100644 --- a/InstaSharper/API/InstaApiConstants.cs +++ b/InstaSharper/API/InstaApiConstants.cs @@ -37,22 +37,31 @@ internal static class InstaApiConstants public const string MEDIA_COMMENTS = API_SUFFIX + "/v1/media/{0}/comments/"; public const string MEDIA_LIKERS = API_SUFFIX + "/v1/media/{0}/likers/"; public const string FOLLOW_USER = API_SUFFIX + "/v1/friendships/create/{0}/"; - + public const string UNFOLLOW_USER = API_SUFFIX + "/v1/friendships/destroy/{0}/"; + public const string SET_ACCOUNT_PRIVATE = API_SUFFIX + "/v1/accounts/set_private/"; + public const string SET_ACCOUNT_PUBLIC = API_SUFFIX + "/v1/accounts/set_public/"; + public const string POST_COMMENT = API_SUFFIX + "/v1/media/{0}/comment/"; + public const string ALLOW_MEDIA_COMMENTS = API_SUFFIX + "/v1/media/{0}/enable_comments/"; + public const string DISABLE_MEDIA_COMMENTS = API_SUFFIX + "/v1/media/{0}/disable_comments/"; + 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 HEADER_USER_AGENT = "User-Agent"; public const string USER_AGENT = - "Instagram 10.8.0 Android (23/6.0.1; 640dpi; 1440x2560; samsung; SM-G935F; hero2lte; samsungexynos8890; en_NZ)"; + "Instagram 10.15.0 Android (23/6.0.1; 640dpi; 1440x2560; samsung; SM-G935F; hero2lte; samsungexynos8890; en_NZ)" + ; public const string HEADER_QUERY = "q"; public const string HEADER_RANK_TOKEN = "rank_token"; public const string HEADER_COUNT = "count"; - public const string IG_SIGNATURE_KEY = "68a04945eb02970e2e8d15266fc256f7295da123e123f44b88f09d594a5902df"; + public const string IG_SIGNATURE_KEY = "b03e0daaf2ab17cda2a569cace938d639d1288a1197f9ecf97efd0a4ec0874d7"; public const string HEADER_IG_SIGNATURE = "signed_body"; public const string IG_SIGNATURE_KEY_VERSION = "4"; public const string HEADER_IG_SIGNATURE_KEY_VERSION = "ig_sig_key_version"; - public const string IG_CAPABILITIES = "3ToAAA=="; + public const string IG_CAPABILITIES = "3boBAA=="; public const string HEADER_IG_CAPABILITIES = "X-IG-Capabilities"; public const string IG_CONNECTION_TYPE = "WIFI"; public const string HEADER_IG_CONNECTION_TYPE = "X-IG-Connection-Type"; @@ -64,6 +73,7 @@ internal static class InstaApiConstants public const string HEADER_PHONE_ID = "phone_id"; 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; } diff --git a/InstaSharper/Classes/Android/DeviceInfo/AndroidVersion.cs b/InstaSharper/Classes/Android/DeviceInfo/AndroidVersion.cs new file mode 100644 index 00000000..796e4fcb --- /dev/null +++ b/InstaSharper/Classes/Android/DeviceInfo/AndroidVersion.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace InstaSharper.Classes.Android.DeviceInfo +{ + public class AndroidVersion + { + public static readonly List AndroidVersions = new List + { + new AndroidVersion + { + Codename = "Ice Cream Sandwich", + VersionNumber = "4.0", + APILevel = "14" + }, + new AndroidVersion + { + Codename = "Ice Cream Sandwich", + VersionNumber = "4.0.3", + APILevel = "15" + }, + new AndroidVersion + { + Codename = "Jelly Bean", + VersionNumber = "4.1", + APILevel = "16" + }, + new AndroidVersion + { + Codename = "Jelly Bean", + VersionNumber = "4.2", + APILevel = "17" + }, + new AndroidVersion + { + Codename = "Jelly Bean", + VersionNumber = "4.3", + APILevel = "18" + }, + new AndroidVersion + { + Codename = "KitKat", + VersionNumber = "4.4", + APILevel = "19" + }, + new AndroidVersion + { + Codename = "KitKat", + VersionNumber = "5.0", + APILevel = "21" + }, + new AndroidVersion + { + Codename = "Lollipop", + VersionNumber = "5.1", + APILevel = "22" + }, + new AndroidVersion + { + Codename = "Marshmallow", + VersionNumber = "6.0", + APILevel = "23" + }, + new AndroidVersion + { + Codename = "Nougat", + VersionNumber = "7.0", + APILevel = "23" + }, + new AndroidVersion + { + Codename = "Nougat", + VersionNumber = "7.1", + APILevel = "25" + } + }; + + private AndroidVersion() + { + } + + public string Codename { get; set; } + public string VersionNumber { get; set; } + public string APILevel { get; set; } + + public static AndroidVersion FromString(string versionString) + { + var version = new Version(versionString); + foreach (var androidVersion in AndroidVersions) + if (version.CompareTo(new Version(androidVersion.VersionNumber)) == 0 || + version.CompareTo(new Version(androidVersion.VersionNumber)) > 0 && + androidVersion != AndroidVersions.Last() && + version.CompareTo(new Version(AndroidVersions[AndroidVersions.IndexOf(androidVersion) + 1] + .VersionNumber)) < 0) + return androidVersion; + return null; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs b/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs index fb8b0c07..b682d9b9 100644 --- a/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs +++ b/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs @@ -35,8 +35,15 @@ internal bool IsEmpty() internal static string GenerateDeviceId() { - var hashedGuid = CryptoHelper.CalculateMD5(Guid.NewGuid().ToString()); + var hashedGuid = CryptoHelper.CalculateMd5(Guid.NewGuid().ToString()); return $"android-{hashedGuid.Substring(0, 16)}"; } + + internal static string GenerateUploadId() + { + var timeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0); + var uploadId = (long) timeSpan.TotalSeconds; + return uploadId.ToString(); + } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/Image.cs b/InstaSharper/Classes/Models/Image.cs deleted file mode 100644 index 4ff173fd..00000000 --- a/InstaSharper/Classes/Models/Image.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace InstaSharper.Classes.Models -{ - public class Image - { - public Image(string url, string width, string height) - { - Url = url; - Width = width; - Height = height; - } - - public string Url { get; set; } - - public string Width { get; set; } - - public string Height { get; set; } - } -} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/Images.cs b/InstaSharper/Classes/Models/Images.cs index 9bb22e44..2e00813e 100644 --- a/InstaSharper/Classes/Models/Images.cs +++ b/InstaSharper/Classes/Models/Images.cs @@ -2,10 +2,10 @@ { public class Images { - public Image LowResolution { get; set; } + public MediaImage LowResolution { get; set; } - public Image Thumbnail { get; set; } + public MediaImage Thumbnail { get; set; } - public Image StandartResolution { get; set; } + public MediaImage StandartResolution { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaCarousel.cs b/InstaSharper/Classes/Models/InstaCarousel.cs new file mode 100644 index 00000000..9ccc1254 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaCarousel.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace InstaSharper.Classes.Models +{ + public class InstaCarousel : List + { + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaCarouselItem.cs b/InstaSharper/Classes/Models/InstaCarouselItem.cs new file mode 100644 index 00000000..830fd254 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaCarouselItem.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace InstaSharper.Classes.Models +{ + public class InstaCarouselItem + { + public string InstaIdentifier { get; set; } + + public InstaMediaType MediaType { get; set; } + + public List Images { get; set; } = new List(); + + public int Width { get; set; } + + public int Height { get; set; } + + public string Pk { get; set; } + + public string CarouselParentId { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaFriendshipStatus.cs b/InstaSharper/Classes/Models/InstaFriendshipStatus.cs index afad47fc..1fa869fe 100644 --- a/InstaSharper/Classes/Models/InstaFriendshipStatus.cs +++ b/InstaSharper/Classes/Models/InstaFriendshipStatus.cs @@ -2,9 +2,10 @@ { public class InstaFriendshipStatus { - public bool Foolowing { get; set; } + public bool Following { get; set; } public bool IsPrivate { get; set; } - + public bool FollowedBy { get; set; } + public bool Blocking { get; set; } public bool IncomingRequest { get; set; } public bool OutgoingRequest { get; set; } diff --git a/InstaSharper/Classes/Models/InstaMedia.cs b/InstaSharper/Classes/Models/InstaMedia.cs index 5ec85af7..7a6fcc77 100644 --- a/InstaSharper/Classes/Models/InstaMedia.cs +++ b/InstaSharper/Classes/Models/InstaMedia.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using InstaSharper.Converters; namespace InstaSharper.Classes.Models { @@ -19,7 +20,7 @@ public class InstaMedia public string FilterType { get; set; } - public List Images { get; set; } = new List(); + public List Images { get; set; } = new List(); public int Width { get; set; } @@ -50,5 +51,12 @@ public class InstaMedia public List Tags { get; set; } = new List(); public InstaUserList Likers { get; set; } = new InstaUserList(); + public InstaCarousel Carousel { get; set; } + + public int ViewCount { get; set; } + + public bool HasAudio { get; set; } + + public bool IsMultiPost => Carousel != null; } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaRecipients.cs b/InstaSharper/Classes/Models/InstaRecipients.cs index e4d1f34b..a252c4e0 100644 --- a/InstaSharper/Classes/Models/InstaRecipients.cs +++ b/InstaSharper/Classes/Models/InstaRecipients.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using InstaSharper.ResponseWrappers.BaseResponse; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; namespace InstaSharper.Classes.Models { diff --git a/InstaSharper/Classes/Models/MediaImage.cs b/InstaSharper/Classes/Models/MediaImage.cs new file mode 100644 index 00000000..2e2606e6 --- /dev/null +++ b/InstaSharper/Classes/Models/MediaImage.cs @@ -0,0 +1,22 @@ +namespace InstaSharper.Classes.Models +{ + public class MediaImage + { + public MediaImage(string uri, int width, int height) + { + URI = uri; + Width = width; + Height = height; + } + + public MediaImage() + { + } + + public string URI { get; set; } + + public int Width { get; set; } + + public int Height { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseType.cs b/InstaSharper/Classes/ResponseType.cs new file mode 100644 index 00000000..5032efcc --- /dev/null +++ b/InstaSharper/Classes/ResponseType.cs @@ -0,0 +1,10 @@ +namespace InstaSharper.Classes +{ + public enum ResponseType + { + Unknown = 0, + LoginRequired = 1, + CheckPointRequired = 2, + RequestsLimit = 3 + } +} \ No newline at end of file diff --git a/InstaSharper/ResponseWrappers/BadStatusResponse.cs b/InstaSharper/Classes/ResponseWrappers/BadStatusResponse.cs similarity index 76% rename from InstaSharper/ResponseWrappers/BadStatusResponse.cs rename to InstaSharper/Classes/ResponseWrappers/BadStatusResponse.cs index 2645cc9c..a37c8d75 100644 --- a/InstaSharper/ResponseWrappers/BadStatusResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/BadStatusResponse.cs @@ -1,7 +1,7 @@ -using InstaSharper.ResponseWrappers.BaseResponse; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class BadStatusResponse : BaseStatusResponse { diff --git a/InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs b/InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs similarity index 90% rename from InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs rename to InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs index 42c73d3a..8f39ac44 100644 --- a/InstaSharper/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers.BaseResponse +namespace InstaSharper.Classes.ResponseWrappers.BaseResponse { internal class BaseLoadableResponse : BaseStatusResponse { diff --git a/InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseStatusResponse.cs b/InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseStatusResponse.cs new file mode 100644 index 00000000..c8be7159 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseStatusResponse.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers.BaseResponse +{ + public class BaseStatusResponse + { + [JsonProperty("status")] + public string Status { get; set; } + + public bool IsOk() + { + return !string.IsNullOrEmpty(Status) && Status.ToLower() == "ok"; + } + + public bool IsFail() + { + return !string.IsNullOrEmpty(Status) && Status.ToLower() == "fail"; + } + } +} \ No newline at end of file diff --git a/InstaSharper/ResponseWrappers/FollowedByResponse.cs b/InstaSharper/Classes/ResponseWrappers/FollowedByResponse.cs similarity index 75% rename from InstaSharper/ResponseWrappers/FollowedByResponse.cs rename to InstaSharper/Classes/ResponseWrappers/FollowedByResponse.cs index 66a38e40..3b07d147 100644 --- a/InstaSharper/ResponseWrappers/FollowedByResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/FollowedByResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class FollowedByResponse { diff --git a/InstaSharper/ResponseWrappers/ImageResponse.cs b/InstaSharper/Classes/ResponseWrappers/ImageResponse.cs similarity index 77% rename from InstaSharper/ResponseWrappers/ImageResponse.cs rename to InstaSharper/Classes/ResponseWrappers/ImageResponse.cs index efa259dd..e2aacfbe 100644 --- a/InstaSharper/ResponseWrappers/ImageResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/ImageResponse.cs @@ -1,10 +1,10 @@ using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class ImageResponse { - [JsonProperty("url")] + [JsonProperty("uri")] public string Url { get; set; } [JsonProperty("width")] diff --git a/InstaSharper/ResponseWrappers/ImagesResponse.cs b/InstaSharper/Classes/ResponseWrappers/ImagesResponse.cs similarity index 88% rename from InstaSharper/ResponseWrappers/ImagesResponse.cs rename to InstaSharper/Classes/ResponseWrappers/ImagesResponse.cs index 4dfd6b7c..a091cebf 100644 --- a/InstaSharper/ResponseWrappers/ImagesResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/ImagesResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class ImagesResponse { diff --git a/InstaSharper/ResponseWrappers/InstaCaptionResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCaptionResponse.cs similarity index 87% rename from InstaSharper/ResponseWrappers/InstaCaptionResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaCaptionResponse.cs index 33b83865..0a988a37 100644 --- a/InstaSharper/ResponseWrappers/InstaCaptionResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaCaptionResponse.cs @@ -1,7 +1,7 @@ -using InstaSharper.ResponseWrappers.BaseResponse; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaCaptionResponse : BaseStatusResponse { diff --git a/InstaSharper/Classes/ResponseWrappers/InstaCarouselItemResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCarouselItemResponse.cs new file mode 100644 index 00000000..f9c4fac4 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaCarouselItemResponse.cs @@ -0,0 +1,29 @@ +using InstaSharper.Classes.Models; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + internal class InstaCarouselItemResponse + { + [JsonProperty("id")] + public string InstaIdentifier { get; set; } + + [JsonProperty("media_type")] + public InstaMediaType MediaType { get; set; } + + [JsonProperty("image_versions2")] + public InstaImageCandidatesResponse Images { get; set; } + + [JsonProperty("original_width")] + public string Width { get; set; } + + [JsonProperty("original_height")] + public string Height { get; set; } + + [JsonProperty("pk")] + public string Pk { get; set; } + + [JsonProperty("carousel_parent_id")] + public string CarouselParentId { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaCarouselResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCarouselResponse.cs new file mode 100644 index 00000000..70803cd4 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaCarouselResponse.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace InstaSharper.Classes.ResponseWrappers +{ + internal class InstaCarouselResponse : List + { + } +} \ No newline at end of file diff --git a/InstaSharper/ResponseWrappers/InstaCommentListResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCommentListResponse.cs similarity index 89% rename from InstaSharper/ResponseWrappers/InstaCommentListResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaCommentListResponse.cs index 0dd2f3d3..0c25e21e 100644 --- a/InstaSharper/ResponseWrappers/InstaCommentListResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaCommentListResponse.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; -using InstaSharper.ResponseWrappers.BaseResponse; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaCommentListResponse : BaseStatusResponse { diff --git a/InstaSharper/ResponseWrappers/InstaCommentResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCommentResponse.cs similarity index 95% rename from InstaSharper/ResponseWrappers/InstaCommentResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaCommentResponse.cs index 394764a8..bd95700c 100644 --- a/InstaSharper/ResponseWrappers/InstaCommentResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaCommentResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaCommentResponse { diff --git a/InstaSharper/ResponseWrappers/InstaCurrentUserResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCurrentUserResponse.cs similarity index 63% rename from InstaSharper/ResponseWrappers/InstaCurrentUserResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaCurrentUserResponse.cs index d980e0f3..92c94638 100644 --- a/InstaSharper/ResponseWrappers/InstaCurrentUserResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaCurrentUserResponse.cs @@ -1,7 +1,7 @@ -using InstaSharper.ResponseWrappers.BaseResponse; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaCurrentUserResponse : BaseStatusResponse { diff --git a/InstaSharper/ResponseWrappers/InstaDirectInboxContainerResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxContainerResponse.cs similarity index 86% rename from InstaSharper/ResponseWrappers/InstaDirectInboxContainerResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaDirectInboxContainerResponse.cs index a2d3e440..8c18b544 100644 --- a/InstaSharper/ResponseWrappers/InstaDirectInboxContainerResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxContainerResponse.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; -using InstaSharper.ResponseWrappers.BaseResponse; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaDirectInboxContainerResponse : BaseStatusResponse { diff --git a/InstaSharper/ResponseWrappers/InstaDirectInboxItemResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxItemResponse.cs similarity index 86% rename from InstaSharper/ResponseWrappers/InstaDirectInboxItemResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaDirectInboxItemResponse.cs index 33417575..28d81abb 100644 --- a/InstaSharper/ResponseWrappers/InstaDirectInboxItemResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxItemResponse.cs @@ -1,8 +1,8 @@ using System; -using InstaSharper.ResponseWrappers.BaseResponse; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaDirectInboxItemResponse : BaseStatusResponse { diff --git a/InstaSharper/ResponseWrappers/InstaDirectInboxResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxResponse.cs similarity index 90% rename from InstaSharper/ResponseWrappers/InstaDirectInboxResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaDirectInboxResponse.cs index 6c2e8756..51c17d8f 100644 --- a/InstaSharper/ResponseWrappers/InstaDirectInboxResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxResponse.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaDirectInboxResponse { diff --git a/InstaSharper/ResponseWrappers/InstaDirectInboxSubscriptionResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxSubscriptionResponse.cs similarity index 89% rename from InstaSharper/ResponseWrappers/InstaDirectInboxSubscriptionResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaDirectInboxSubscriptionResponse.cs index 78c93e62..5a9573c7 100644 --- a/InstaSharper/ResponseWrappers/InstaDirectInboxSubscriptionResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxSubscriptionResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaDirectInboxSubscriptionResponse { diff --git a/InstaSharper/ResponseWrappers/InstaDirectInboxThreadResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxThreadResponse.cs similarity index 93% rename from InstaSharper/ResponseWrappers/InstaDirectInboxThreadResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaDirectInboxThreadResponse.cs index 1eabbdfe..65d97e7d 100644 --- a/InstaSharper/ResponseWrappers/InstaDirectInboxThreadResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxThreadResponse.cs @@ -1,9 +1,9 @@ using System.Collections.Generic; using InstaSharper.Classes.Models; -using InstaSharper.ResponseWrappers.BaseResponse; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaDirectInboxThreadResponse : BaseStatusResponse { diff --git a/InstaSharper/ResponseWrappers/InstaFeedResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaFeedResponse.cs similarity index 79% rename from InstaSharper/ResponseWrappers/InstaFeedResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaFeedResponse.cs index 6965f268..99fd4063 100644 --- a/InstaSharper/ResponseWrappers/InstaFeedResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaFeedResponse.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; -using InstaSharper.ResponseWrappers.BaseResponse; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaFeedResponse : BaseLoadableResponse { diff --git a/InstaSharper/ResponseWrappers/InstaFollowersResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaFollowersResponse.cs similarity index 84% rename from InstaSharper/ResponseWrappers/InstaFollowersResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaFollowersResponse.cs index 3f4da6eb..80b9d086 100644 --- a/InstaSharper/ResponseWrappers/InstaFollowersResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaFollowersResponse.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; -using InstaSharper.ResponseWrappers.BaseResponse; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaFollowersResponse : BaseStatusResponse { diff --git a/InstaSharper/Classes/ResponseWrappers/InstaFriendshipStatusResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaFriendshipStatusResponse.cs new file mode 100644 index 00000000..116dce27 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaFriendshipStatusResponse.cs @@ -0,0 +1,26 @@ +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + internal class InstaFriendshipStatusResponse : BaseStatusResponse + { + [JsonProperty("following")] + public bool Following { get; set; } + + [JsonProperty("followed_by")] + public bool FollowedBy { get; set; } + + [JsonProperty("blocking")] + public bool Blocking { get; set; } + + [JsonProperty("is_private")] + public bool IsPrivate { get; set; } + + [JsonProperty("incoming_request")] + public bool IncomingRequest { get; set; } + + [JsonProperty("outgoing_request")] + public bool OutgoingRequest { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/ResponseWrappers/InstaImageCandidatesResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaImageCandidatesResponse.cs similarity index 82% rename from InstaSharper/ResponseWrappers/InstaImageCandidatesResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaImageCandidatesResponse.cs index 42f2257a..19ea185f 100644 --- a/InstaSharper/ResponseWrappers/InstaImageCandidatesResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaImageCandidatesResponse.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaImageCandidatesResponse { diff --git a/InstaSharper/ResponseWrappers/InstaInlineFollowResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaInlineFollowResponse.cs similarity index 88% rename from InstaSharper/ResponseWrappers/InstaInlineFollowResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaInlineFollowResponse.cs index b132d067..26f6f2f6 100644 --- a/InstaSharper/ResponseWrappers/InstaInlineFollowResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaInlineFollowResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaInlineFollowResponse { diff --git a/InstaSharper/ResponseWrappers/InstaLinkResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaLinkResponse.cs similarity index 88% rename from InstaSharper/ResponseWrappers/InstaLinkResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaLinkResponse.cs index 82710099..b4aa1b3e 100644 --- a/InstaSharper/ResponseWrappers/InstaLinkResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaLinkResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaLinkResponse { diff --git a/InstaSharper/ResponseWrappers/InstaLoginResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaLoginResponse.cs similarity index 83% rename from InstaSharper/ResponseWrappers/InstaLoginResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaLoginResponse.cs index be5aeab5..4dc07064 100644 --- a/InstaSharper/ResponseWrappers/InstaLoginResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaLoginResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaLoginResponse { diff --git a/InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaMediaItemResponse.cs similarity index 86% rename from InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaMediaItemResponse.cs index 79cea2f4..55ab423e 100644 --- a/InstaSharper/ResponseWrappers/InstaMediaItemResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaMediaItemResponse.cs @@ -2,7 +2,7 @@ using InstaSharper.Classes.Models; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaMediaItemResponse { @@ -67,10 +67,19 @@ internal class InstaMediaItemResponse [JsonProperty("type")] public int Type { get; set; } + [JsonProperty("view_count")] + public double ViewCount { get; set; } + + [JsonProperty("has_audio")] + public bool HasAudio { get; set; } + [JsonProperty("usertags")] public InstaUserTagListResponse UserTagList { get; set; } [JsonProperty("likers")] public List Likers { get; set; } + + [JsonProperty("carousel_media")] + public InstaCarouselResponse CarouselMedia { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/ResponseWrappers/InstaMediaLikersResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaMediaLikersResponse.cs similarity index 86% rename from InstaSharper/ResponseWrappers/InstaMediaLikersResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaMediaLikersResponse.cs index 761116a1..6940903e 100644 --- a/InstaSharper/ResponseWrappers/InstaMediaLikersResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaMediaLikersResponse.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaMediaLikersResponse : BadStatusResponse { diff --git a/InstaSharper/ResponseWrappers/InstaMediaListResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaMediaListResponse.cs similarity index 77% rename from InstaSharper/ResponseWrappers/InstaMediaListResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaMediaListResponse.cs index 4d116b8a..47d5a147 100644 --- a/InstaSharper/ResponseWrappers/InstaMediaListResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaMediaListResponse.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; -using InstaSharper.ResponseWrappers.BaseResponse; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaMediaListResponse : BaseLoadableResponse { diff --git a/InstaSharper/ResponseWrappers/InstaRecentActivityFeedResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityFeedResponse.cs similarity index 87% rename from InstaSharper/ResponseWrappers/InstaRecentActivityFeedResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaRecentActivityFeedResponse.cs index 899fb34d..9d7b357a 100644 --- a/InstaSharper/ResponseWrappers/InstaRecentActivityFeedResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityFeedResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaRecentActivityFeedResponse { diff --git a/InstaSharper/ResponseWrappers/InstaRecentActivityResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityResponse.cs similarity index 77% rename from InstaSharper/ResponseWrappers/InstaRecentActivityResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaRecentActivityResponse.cs index 76b37a43..18fb5a23 100644 --- a/InstaSharper/ResponseWrappers/InstaRecentActivityResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityResponse.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; -using InstaSharper.ResponseWrappers.BaseResponse; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaRecentActivityResponse : BaseLoadableResponse { diff --git a/InstaSharper/ResponseWrappers/InstaRecentActivityStoryItemResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityStoryItemResponse.cs similarity index 93% rename from InstaSharper/ResponseWrappers/InstaRecentActivityStoryItemResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaRecentActivityStoryItemResponse.cs index 795c529f..dabe325d 100644 --- a/InstaSharper/ResponseWrappers/InstaRecentActivityStoryItemResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityStoryItemResponse.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaRecentActivityStoryItemResponse { diff --git a/InstaSharper/ResponseWrappers/InstaRecipientsResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaRecipientsResponse.cs similarity index 75% rename from InstaSharper/ResponseWrappers/InstaRecipientsResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaRecipientsResponse.cs index 79cb9355..12e3d603 100644 --- a/InstaSharper/ResponseWrappers/InstaRecipientsResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaRecipientsResponse.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; -using InstaSharper.ResponseWrappers.BaseResponse; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaRecipientsResponse : BaseStatusResponse { diff --git a/InstaSharper/ResponseWrappers/InstaSearchUserResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaSearchUserResponse.cs similarity index 88% rename from InstaSharper/ResponseWrappers/InstaSearchUserResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaSearchUserResponse.cs index c5535369..fd478469 100644 --- a/InstaSharper/ResponseWrappers/InstaSearchUserResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaSearchUserResponse.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaSearchUserResponse { diff --git a/InstaSharper/ResponseWrappers/InstaStoryResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaStoryResponse.cs similarity index 94% rename from InstaSharper/ResponseWrappers/InstaStoryResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaStoryResponse.cs index c211f3c1..1e31f442 100644 --- a/InstaSharper/ResponseWrappers/InstaStoryResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaStoryResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaStoryResponse { diff --git a/InstaSharper/ResponseWrappers/InstaTagFeedResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaTagFeedResponse.cs similarity index 82% rename from InstaSharper/ResponseWrappers/InstaTagFeedResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaTagFeedResponse.cs index 788af637..24b50e8d 100644 --- a/InstaSharper/ResponseWrappers/InstaTagFeedResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaTagFeedResponse.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaTagFeedResponse { diff --git a/InstaSharper/ResponseWrappers/InstaUserResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaUserResponse.cs similarity index 92% rename from InstaSharper/ResponseWrappers/InstaUserResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaUserResponse.cs index a676069a..814579ed 100644 --- a/InstaSharper/ResponseWrappers/InstaUserResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaUserResponse.cs @@ -1,8 +1,8 @@ using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaUserResponse + internal class InstaUserResponse : BadStatusResponse { [JsonProperty("username")] public string UserName { get; set; } diff --git a/InstaSharper/ResponseWrappers/InstaUserTagListResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaUserTagListResponse.cs similarity index 83% rename from InstaSharper/ResponseWrappers/InstaUserTagListResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaUserTagListResponse.cs index ff3eadcf..a5c0ffc1 100644 --- a/InstaSharper/ResponseWrappers/InstaUserTagListResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaUserTagListResponse.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaUserTagListResponse { diff --git a/InstaSharper/ResponseWrappers/InstaUserTagResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaUserTagResponse.cs similarity index 87% rename from InstaSharper/ResponseWrappers/InstaUserTagResponse.cs rename to InstaSharper/Classes/ResponseWrappers/InstaUserTagResponse.cs index 54d3105e..4bbdbfec 100644 --- a/InstaSharper/ResponseWrappers/InstaUserTagResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaUserTagResponse.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json; -namespace InstaSharper.ResponseWrappers +namespace InstaSharper.Classes.ResponseWrappers { internal class InstaUserTagResponse { diff --git a/InstaSharper/Classes/Result.cs b/InstaSharper/Classes/Result.cs index ab5cc5b3..be178deb 100644 --- a/InstaSharper/Classes/Result.cs +++ b/InstaSharper/Classes/Result.cs @@ -28,38 +28,6 @@ public Result(bool succeeded, T value) public ResultInfo Info { get; } = new ResultInfo(""); } - public class ResultInfo - { - public ResultInfo(string message) - { - Message = message; - } - - public ResultInfo(Exception exception) - { - Exception = exception; - } - - public ResultInfo(ResponseType responseType) - { - ResponseType = responseType; - } - - public Exception Exception { get; } - - public string Message { get; } - - public ResponseType ResponseType { get; } - } - - public enum ResponseType - { - Unknown = 0, - LoginRequired = 1, - CheckPointRequired = 2, - RequestsLimit = 3 - } - public static class Result { public static IResult Success(T resValue) diff --git a/InstaSharper/Classes/ResultInfo.cs b/InstaSharper/Classes/ResultInfo.cs new file mode 100644 index 00000000..7cb8b268 --- /dev/null +++ b/InstaSharper/Classes/ResultInfo.cs @@ -0,0 +1,28 @@ +using System; + +namespace InstaSharper.Classes +{ + public class ResultInfo + { + public ResultInfo(string message) + { + Message = message; + } + + public ResultInfo(Exception exception) + { + Exception = exception; + } + + public ResultInfo(ResponseType responseType) + { + ResponseType = responseType; + } + + public Exception Exception { get; } + + public string Message { get; } + + public ResponseType ResponseType { get; } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/ConvertersFabric.cs b/InstaSharper/Converters/ConvertersFabric.cs index 086d1997..5b133326 100644 --- a/InstaSharper/Converters/ConvertersFabric.cs +++ b/InstaSharper/Converters/ConvertersFabric.cs @@ -1,5 +1,5 @@ using InstaSharper.Classes.Models; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; namespace InstaSharper.Converters { @@ -98,5 +98,17 @@ public static IObjectConverter GetCo { return new InstaCommentListConverter {SourceObject = commentList}; } + + public static IObjectConverter GetCarouselConverter( + InstaCarouselResponse carousel) + { + return new InstaCarouselConverter {SourceObject = carousel}; + } + + public static IObjectConverter GetCarouselItemConverter( + InstaCarouselItemResponse carouselItem) + { + return new InstaCarouselItemConverter {SourceObject = carouselItem}; + } } } \ No newline at end of file diff --git a/InstaSharper/Converters/InstaCaptionConverter.cs b/InstaSharper/Converters/InstaCaptionConverter.cs index 1d205963..ac91c897 100644 --- a/InstaSharper/Converters/InstaCaptionConverter.cs +++ b/InstaSharper/Converters/InstaCaptionConverter.cs @@ -1,6 +1,6 @@ using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; using InstaSharper.Helpers; -using InstaSharper.ResponseWrappers; namespace InstaSharper.Converters { diff --git a/InstaSharper/Converters/InstaCarouselConverter.cs b/InstaSharper/Converters/InstaCarouselConverter.cs new file mode 100644 index 00000000..4c71c3e0 --- /dev/null +++ b/InstaSharper/Converters/InstaCarouselConverter.cs @@ -0,0 +1,23 @@ +using System; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + internal class InstaCarouselConverter : IObjectConverter + { + public InstaCarouselResponse SourceObject { get; set; } + + public InstaCarousel Convert() + { + var carousel = new InstaCarousel(); + if (SourceObject == null) throw new ArgumentNullException($"Source object"); + foreach (var item in SourceObject) + { + var carouselItem = ConvertersFabric.GetCarouselItemConverter(item); + carousel.Add(carouselItem.Convert()); + } + return carousel; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/InstaCarouselItemConverter.cs b/InstaSharper/Converters/InstaCarouselItemConverter.cs new file mode 100644 index 00000000..2f817f45 --- /dev/null +++ b/InstaSharper/Converters/InstaCarouselItemConverter.cs @@ -0,0 +1,25 @@ +using System; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + internal class InstaCarouselItemConverter : IObjectConverter + { + public InstaCarouselItemResponse SourceObject { get; set; } + + public InstaCarouselItem Convert() + { + if (SourceObject == null) throw new ArgumentNullException($"Source object"); + var carouselItem = new InstaCarouselItem + { + CarouselParentId = SourceObject.CarouselParentId, + Height = int.Parse(SourceObject.Height), + Width = int.Parse(SourceObject.Width) + }; + foreach (var image in SourceObject.Images.Candidates) + carouselItem.Images.Add(new MediaImage(image.Url, int.Parse(image.Width), int.Parse(image.Height))); + return carouselItem; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/InstaCommentConverter.cs b/InstaSharper/Converters/InstaCommentConverter.cs index 0655854f..b1bcf502 100644 --- a/InstaSharper/Converters/InstaCommentConverter.cs +++ b/InstaSharper/Converters/InstaCommentConverter.cs @@ -1,7 +1,7 @@ using System; using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; using InstaSharper.Helpers; -using InstaSharper.ResponseWrappers; namespace InstaSharper.Converters { diff --git a/InstaSharper/Converters/InstaCommentListConverter.cs b/InstaSharper/Converters/InstaCommentListConverter.cs index c4418435..f6363094 100644 --- a/InstaSharper/Converters/InstaCommentListConverter.cs +++ b/InstaSharper/Converters/InstaCommentListConverter.cs @@ -1,5 +1,5 @@ using InstaSharper.Classes.Models; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; namespace InstaSharper.Converters { diff --git a/InstaSharper/Converters/InstaDirectInboxConverter.cs b/InstaSharper/Converters/InstaDirectInboxConverter.cs index cd4930e3..c4ad0a3d 100644 --- a/InstaSharper/Converters/InstaDirectInboxConverter.cs +++ b/InstaSharper/Converters/InstaDirectInboxConverter.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using InstaSharper.Classes.Models; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; namespace InstaSharper.Converters { diff --git a/InstaSharper/Converters/InstaDirectInboxSubscriptionConverter.cs b/InstaSharper/Converters/InstaDirectInboxSubscriptionConverter.cs index ddf5df31..ba02e301 100644 --- a/InstaSharper/Converters/InstaDirectInboxSubscriptionConverter.cs +++ b/InstaSharper/Converters/InstaDirectInboxSubscriptionConverter.cs @@ -1,5 +1,5 @@ using InstaSharper.Classes.Models; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; namespace InstaSharper.Converters { diff --git a/InstaSharper/Converters/InstaDirectThreadConverter.cs b/InstaSharper/Converters/InstaDirectThreadConverter.cs index 143b4b63..070a34c8 100644 --- a/InstaSharper/Converters/InstaDirectThreadConverter.cs +++ b/InstaSharper/Converters/InstaDirectThreadConverter.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; using InstaSharper.Helpers; -using InstaSharper.ResponseWrappers; namespace InstaSharper.Converters { diff --git a/InstaSharper/Converters/InstaDirectThreadItemConverter.cs b/InstaSharper/Converters/InstaDirectThreadItemConverter.cs index 1aaeb57c..b23fc091 100644 --- a/InstaSharper/Converters/InstaDirectThreadItemConverter.cs +++ b/InstaSharper/Converters/InstaDirectThreadItemConverter.cs @@ -1,6 +1,6 @@ using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; using InstaSharper.Helpers; -using InstaSharper.ResponseWrappers; namespace InstaSharper.Converters { diff --git a/InstaSharper/Converters/InstaFeedConverter.cs b/InstaSharper/Converters/InstaFeedConverter.cs index 910064ca..e1ce9405 100644 --- a/InstaSharper/Converters/InstaFeedConverter.cs +++ b/InstaSharper/Converters/InstaFeedConverter.cs @@ -1,5 +1,5 @@ using InstaSharper.Classes.Models; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; namespace InstaSharper.Converters { diff --git a/InstaSharper/Converters/InstaFriendshipStatusConverter.cs b/InstaSharper/Converters/InstaFriendshipStatusConverter.cs index 1a8055fb..22520854 100644 --- a/InstaSharper/Converters/InstaFriendshipStatusConverter.cs +++ b/InstaSharper/Converters/InstaFriendshipStatusConverter.cs @@ -1,5 +1,5 @@ using InstaSharper.Classes.Models; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; namespace InstaSharper.Converters { @@ -10,10 +10,14 @@ internal class InstaFriendshipStatusConverter : public InstaFriendshipStatus Convert() { - var friendShip = new InstaFriendshipStatus(); - friendShip.Foolowing = SourceObject.Foolowing; - friendShip.IncomingRequest = SourceObject.IncomingRequest; - friendShip.OutgoingRequest = SourceObject.OutgoingRequest; + var friendShip = new InstaFriendshipStatus + { + Following = SourceObject.Following, + Blocking = SourceObject.Blocking, + FollowedBy = SourceObject.FollowedBy, + IncomingRequest = SourceObject.IncomingRequest, + OutgoingRequest = SourceObject.OutgoingRequest + }; friendShip.IncomingRequest = SourceObject.IncomingRequest; friendShip.IsPrivate = SourceObject.IsPrivate; return friendShip; diff --git a/InstaSharper/Converters/InstaMediaConverter.cs b/InstaSharper/Converters/InstaMediaConverter.cs index 05c77887..e0ac89cb 100644 --- a/InstaSharper/Converters/InstaMediaConverter.cs +++ b/InstaSharper/Converters/InstaMediaConverter.cs @@ -1,7 +1,8 @@ using System; +using System.Globalization; using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; using InstaSharper.Helpers; -using InstaSharper.ResponseWrappers; namespace InstaSharper.Converters { @@ -28,8 +29,12 @@ public InstaMedia Convert() LikesCount = SourceObject.LikesCount, MediaType = SourceObject.MediaType, FilterType = SourceObject.FilterType, - Width = SourceObject.Width + Width = SourceObject.Width, + HasAudio = SourceObject.HasAudio, + ViewCount = int.Parse(SourceObject.ViewCount.ToString(CultureInfo.InvariantCulture)) }; + if (SourceObject.CarouselMedia != null) + media.Carousel = ConvertersFabric.GetCarouselConverter(SourceObject.CarouselMedia).Convert(); if (SourceObject.User != null) media.User = ConvertersFabric.GetUserConverter(SourceObject.User).Convert(); if (SourceObject.Caption != null) media.Caption = ConvertersFabric.GetCaptionConverter(SourceObject.Caption).Convert(); @@ -42,7 +47,7 @@ public InstaMedia Convert() media.Tags.Add(ConvertersFabric.GetUserTagConverter(tag).Convert()); if (SourceObject.Images?.Candidates == null) return media; foreach (var image in SourceObject.Images.Candidates) - media.Images.Add(new Image(image.Url, image.Width, image.Height)); + media.Images.Add(new MediaImage(image.Url, int.Parse(image.Width), int.Parse(image.Height))); return media; } } diff --git a/InstaSharper/Converters/InstaMediaListConverter.cs b/InstaSharper/Converters/InstaMediaListConverter.cs index 2749f6e2..f6036476 100644 --- a/InstaSharper/Converters/InstaMediaListConverter.cs +++ b/InstaSharper/Converters/InstaMediaListConverter.cs @@ -1,7 +1,7 @@ using System; using System.Linq; using InstaSharper.Classes.Models; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; namespace InstaSharper.Converters { diff --git a/InstaSharper/Converters/InstaRecentActivityConverter.cs b/InstaSharper/Converters/InstaRecentActivityConverter.cs index 78eb8e8b..184aa11a 100644 --- a/InstaSharper/Converters/InstaRecentActivityConverter.cs +++ b/InstaSharper/Converters/InstaRecentActivityConverter.cs @@ -1,6 +1,6 @@ using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; using InstaSharper.Helpers; -using InstaSharper.ResponseWrappers; namespace InstaSharper.Converters { diff --git a/InstaSharper/Converters/InstaRecipientsConverter.cs b/InstaSharper/Converters/InstaRecipientsConverter.cs index 9f20cd51..46e461bc 100644 --- a/InstaSharper/Converters/InstaRecipientsConverter.cs +++ b/InstaSharper/Converters/InstaRecipientsConverter.cs @@ -1,5 +1,5 @@ using InstaSharper.Classes.Models; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; namespace InstaSharper.Converters { diff --git a/InstaSharper/Converters/InstaStoryConverter.cs b/InstaSharper/Converters/InstaStoryConverter.cs index 1c498677..710a729f 100644 --- a/InstaSharper/Converters/InstaStoryConverter.cs +++ b/InstaSharper/Converters/InstaStoryConverter.cs @@ -1,7 +1,7 @@ using System; using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; using InstaSharper.Helpers; -using InstaSharper.ResponseWrappers; namespace InstaSharper.Converters { diff --git a/InstaSharper/Converters/InstaUserTagConverter.cs b/InstaSharper/Converters/InstaUserTagConverter.cs index eeac6b22..5c002384 100644 --- a/InstaSharper/Converters/InstaUserTagConverter.cs +++ b/InstaSharper/Converters/InstaUserTagConverter.cs @@ -1,6 +1,6 @@ using System; using InstaSharper.Classes.Models; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; namespace InstaSharper.Converters { diff --git a/InstaSharper/Converters/InstaUsersConverter.cs b/InstaSharper/Converters/InstaUsersConverter.cs index 874bfe77..31789d73 100644 --- a/InstaSharper/Converters/InstaUsersConverter.cs +++ b/InstaSharper/Converters/InstaUsersConverter.cs @@ -1,6 +1,6 @@ using System; using InstaSharper.Classes.Models; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; namespace InstaSharper.Converters { @@ -20,7 +20,8 @@ public InstaUser Convert() if (!string.IsNullOrEmpty(SourceObject.UserName)) user.UserName = SourceObject.UserName; if (!string.IsNullOrEmpty(SourceObject.Pk)) user.Pk = SourceObject.Pk; if (SourceObject.Friendship != null) - user.FriendshipStatus = ConvertersFabric.GetFriendShipStatusConverter(SourceObject.Friendship).Convert(); + user.FriendshipStatus = ConvertersFabric.GetFriendShipStatusConverter(SourceObject.Friendship) + .Convert(); user.HasAnonymousProfilePicture = SourceObject.HasAnonymousProfilePicture; user.ProfilePictureId = SourceObject.ProfilePictureId; user.IsVerified = SourceObject.IsVerified; diff --git a/InstaSharper/Converters/Json/InstaCommentDataConverter.cs b/InstaSharper/Converters/Json/InstaCommentDataConverter.cs new file mode 100644 index 00000000..5270e8d2 --- /dev/null +++ b/InstaSharper/Converters/Json/InstaCommentDataConverter.cs @@ -0,0 +1,30 @@ +using System; +using InstaSharper.Classes.ResponseWrappers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace InstaSharper.Converters.Json +{ + public class InstaCommentDataConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(InstaCommentResponse); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + JsonSerializer serializer) + { + var root = JToken.Load(reader); + var commentContainer = root["comment"]; + return commentContainer == null + ? root.ToObject() + : commentContainer.ToObject(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value); + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs b/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs index 6c1017f5..12132afd 100644 --- a/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; diff --git a/InstaSharper/Converters/Json/InstaFriendShipDataConverter.cs b/InstaSharper/Converters/Json/InstaFriendShipDataConverter.cs new file mode 100644 index 00000000..3a6f40a1 --- /dev/null +++ b/InstaSharper/Converters/Json/InstaFriendShipDataConverter.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using InstaSharper.Classes.ResponseWrappers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace InstaSharper.Converters.Json +{ + public class InstaFriendShipDataConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(InstaFriendshipStatusResponse); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + JsonSerializer serializer) + { + var root = JToken.Load(reader); + var statusSubContainer = root["friendship_status"]; + return statusSubContainer == null + ? root.ToObject() + : statusSubContainer.ToObject(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value); + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs b/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs index ddf5d88b..0fcf6930 100644 --- a/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs @@ -1,5 +1,5 @@ using System; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; diff --git a/InstaSharper/Converters/Json/InstaRecentActivityConverter.cs b/InstaSharper/Converters/Json/InstaRecentActivityConverter.cs index 957b463e..f03a815d 100644 --- a/InstaSharper/Converters/Json/InstaRecentActivityConverter.cs +++ b/InstaSharper/Converters/Json/InstaRecentActivityConverter.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; diff --git a/InstaSharper/Converters/Json/InstaRecipientsDataConverter.cs b/InstaSharper/Converters/Json/InstaRecipientsDataConverter.cs index 9c9f51bb..a7e60279 100644 --- a/InstaSharper/Converters/Json/InstaRecipientsDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaRecipientsDataConverter.cs @@ -1,5 +1,5 @@ using System; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; diff --git a/InstaSharper/Converters/Json/InstaThreadDataConverter.cs b/InstaSharper/Converters/Json/InstaThreadDataConverter.cs index 39e76d2f..6ebd27bf 100644 --- a/InstaSharper/Converters/Json/InstaThreadDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaThreadDataConverter.cs @@ -1,5 +1,5 @@ using System; -using InstaSharper.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; diff --git a/InstaSharper/Helpers/CryptoHelper.cs b/InstaSharper/Helpers/CryptoHelper.cs index 79d8819c..02ef71d6 100644 --- a/InstaSharper/Helpers/CryptoHelper.cs +++ b/InstaSharper/Helpers/CryptoHelper.cs @@ -2,12 +2,30 @@ using System.Linq; using System.Security.Cryptography; using System.Text; +using InstaSharper.API; namespace InstaSharper.Helpers { internal class CryptoHelper { - public static string CalculateMD5(string message) + public static string ByteToString(byte[] buff) + { + return buff.Aggregate("", (current, item) => current + item.ToString("X2")); + } + + public static string Base64Encode(string plainText) + { + var plainTextBytes = Encoding.UTF8.GetBytes(plainText); + return Convert.ToBase64String(plainTextBytes); + } + + public static string Base64Decode(string base64EncodedData) + { + var base64EncodedBytes = Convert.FromBase64String(base64EncodedData); + return Encoding.UTF8.GetString(base64EncodedBytes); + } + + public static string CalculateMd5(string message) { var encoding = Encoding.UTF8; @@ -80,5 +98,27 @@ public static byte[] ByteConcat(byte[] left, byte[] right) return newBytes; } + + public static string GetCommentBreadCrumbEncoded(string text) + { + const string key = InstaApiConstants.COMMENT_BREADCRUMB_KEY; + + var date = Convert.ToInt64(DateTimeHelper.GetUnixTimestampMilliseconds(DateTime.Now)); + var rnd = new Random(DateTime.Now.Millisecond); + var msgSize = text.Length; + var term = rnd.Next(2, 3) * 1000 + msgSize * rnd.Next(15, 20) * 100; + var textChangeDeviceEventCount = Math.Round((decimal) (msgSize / rnd.Next(2, 3)), 0); + if (textChangeDeviceEventCount == 0) textChangeDeviceEventCount = 1; + var data = $"{msgSize} {term} {textChangeDeviceEventCount} {date}"; + + var keyByte = Encoding.UTF8.GetBytes(key); + string dataEncoded; + using (var hmacsha256 = new HMACSHA256(keyByte)) + { + dataEncoded = ByteToString(hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(data))); + } + + return $"{Base64Encode(dataEncoded)}\n{Base64Encode(data)}\n"; + } } } \ No newline at end of file diff --git a/InstaSharper/Helpers/DateTimeHelper.cs b/InstaSharper/Helpers/DateTimeHelper.cs index 972990fd..f7332585 100644 --- a/InstaSharper/Helpers/DateTimeHelper.cs +++ b/InstaSharper/Helpers/DateTimeHelper.cs @@ -4,6 +4,14 @@ namespace InstaSharper.Helpers { internal static class DateTimeHelper { + private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1); + + public static double GetUnixTimestampMilliseconds(DateTime dt) + { + var span = dt - UnixEpoch; + return span.TotalMilliseconds; + } + public static DateTime UnixTimestampToDateTime(double unixTime) { var time = (long) unixTime; @@ -26,8 +34,7 @@ public static DateTime FromUnixTimeSeconds(this long unixTime) { try { - var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - return epoch.AddSeconds(unixTime); + return UnixEpoch.AddSeconds(unixTime); } catch { @@ -39,8 +46,7 @@ public static DateTime FromUnixTimeMiliSeconds(this long unixTime) { try { - var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - return epoch.AddMilliseconds(unixTime); + return UnixEpoch.AddMilliseconds(unixTime); } catch { @@ -52,8 +58,7 @@ public static long ToUnixTime(this DateTime date) { try { - var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - return Convert.ToInt64((date - epoch).TotalSeconds); + return Convert.ToInt64((date - UnixEpoch).TotalSeconds); } catch { diff --git a/InstaSharper/Helpers/HttpHelper.cs b/InstaSharper/Helpers/HttpHelper.cs index c4301cb0..37d4ccbe 100644 --- a/InstaSharper/Helpers/HttpHelper.cs +++ b/InstaSharper/Helpers/HttpHelper.cs @@ -3,6 +3,8 @@ using System.Net.Http; using InstaSharper.API; using InstaSharper.Classes.Android.DeviceInfo; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace InstaSharper.Helpers { @@ -19,5 +21,47 @@ public static HttpRequestMessage GetDefaultRequest(HttpMethod method, Uri uri, A deviceInfo.GoogleAdId.ToString())); return request; } + + public static HttpRequestMessage GetSignedRequest(HttpMethod method, Uri uri, AndroidDevice deviceInfo, + Dictionary data) + { + var hash = CryptoHelper.CalculateHash(InstaApiConstants.IG_SIGNATURE_KEY, + JsonConvert.SerializeObject(data)); + var payload = JsonConvert.SerializeObject(data); + var signature = $"{hash}.{payload}"; + + var fields = new Dictionary + { + {InstaApiConstants.HEADER_IG_SIGNATURE, signature}, + {InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION} + }; + var request = GetDefaultRequest(HttpMethod.Post, uri, deviceInfo); + request.Content = new FormUrlEncodedContent(fields); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, + InstaApiConstants.IG_SIGNATURE_KEY_VERSION); + return request; + } + + public static HttpRequestMessage GetSignedRequest(HttpMethod method, Uri uri, AndroidDevice deviceInfo, + JObject data) + { + var hash = CryptoHelper.CalculateHash(InstaApiConstants.IG_SIGNATURE_KEY, + data.ToString(Formatting.None)); + var payload = data.ToString(Formatting.None); + var signature = $"{hash}.{payload}"; + + var fields = new Dictionary + { + {InstaApiConstants.HEADER_IG_SIGNATURE, signature}, + {InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION} + }; + var request = GetDefaultRequest(HttpMethod.Post, uri, deviceInfo); + request.Content = new FormUrlEncodedContent(fields); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, + InstaApiConstants.IG_SIGNATURE_KEY_VERSION); + return request; + } } } \ No newline at end of file diff --git a/InstaSharper/Helpers/UriCreator.cs b/InstaSharper/Helpers/UriCreator.cs index d8b30253..9ae6384d 100644 --- a/InstaSharper/Helpers/UriCreator.cs +++ b/InstaSharper/Helpers/UriCreator.cs @@ -140,7 +140,7 @@ public static Uri GetUserTagsUri(string userPk, string rankToken, string maxId = Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_TAGS, userPk), out instaUri)) throw new Exception("Cant create URI for get user tags"); - string query = $"rank_token={rankToken}&ranked_content=true"; + var query = $"rank_token={rankToken}&ranked_content=true"; if (!string.IsNullOrEmpty(maxId)) query += $"max_id={maxId}"; var uriBuilder = new UriBuilder(instaUri) {Query = query}; return uriBuilder.Uri; @@ -167,7 +167,7 @@ public static Uri GetRecentActivityUri() Uri instaUri; if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.GET_RECENT_ACTIVITY, out instaUri)) throw new Exception("Cant create URI (get recent activity)"); - string query = $"activity_module=all"; + var query = $"activity_module=all"; var uriBuilder = new UriBuilder(instaUri) {Query = query}; return uriBuilder.Uri; } @@ -202,7 +202,8 @@ public static Uri GetLikeMediaUri(string mediaId) public static Uri GetMediaCommentsUri(string mediaId) { Uri instaUri; - if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.MEDIA_COMMENTS, mediaId), out instaUri)) + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.MEDIA_COMMENTS, mediaId), + out instaUri)) throw new Exception("Cant create URI for getting media comments"); return instaUri; } @@ -222,5 +223,85 @@ public static Uri GetFollowUserUri(long userId) throw new Exception("Cant create URI for getting media likers"); return instaUri; } + + public static Uri GetUnFollowUserUri(long userId) + { + Uri instaUri; + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.UNFOLLOW_USER, userId), out instaUri)) + throw new Exception("Cant create URI for getting media likers"); + return instaUri; + } + + public static Uri GetUriSetAccountPrivate() + { + Uri instaUri; + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.SET_ACCOUNT_PRIVATE, out instaUri)) + throw new Exception("Cant create URI for set account private"); + return instaUri; + } + + public static Uri GetUriSetAccountPublic() + { + Uri instaUri; + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.SET_ACCOUNT_PUBLIC, out instaUri)) + throw new Exception("Cant create URI for set account public"); + return instaUri; + } + + public static Uri GetPostCommetUri(string mediaId) + { + Uri instaUri; + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.POST_COMMENT, mediaId), out instaUri)) + throw new Exception("Cant create URI for posting comment"); + return instaUri; + } + + public static Uri GetAllowMediaCommetsUri(string mediaId) + { + Uri instaUri; + if ( + !Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.ALLOW_MEDIA_COMMENTS, mediaId), + out instaUri)) + throw new Exception("Cant create URI to allow comments on media"); + return instaUri; + } + + public static Uri GetDisableMediaCommetsUri(string mediaId) + { + Uri instaUri; + if ( + !Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.DISABLE_MEDIA_COMMENTS, mediaId), + out instaUri)) + throw new Exception("Cant create URI to disable comments on media"); + return instaUri; + } + + public static Uri GetDeleteCommetUri(string mediaId, string commentId) + { + Uri instaUri; + if ( + !Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.DELETE_COMMENT, mediaId, commentId), + out instaUri)) + throw new Exception("Cant create URI for delete comment"); + return instaUri; + } + + public static Uri GetUploadPhotoUri() + { + Uri instaUri; + if ( + !Uri.TryCreate(BaseInstagramUri, InstaApiConstants.UPLOAD_PHOTO, out instaUri)) + throw new Exception("Cant create URI for upload photo"); + return instaUri; + } + + public static Uri GetMediaConfigureUri() + { + Uri instaUri; + if ( + !Uri.TryCreate(BaseInstagramUri, InstaApiConstants.MEDIA_CONFIGURE, out instaUri)) + throw new Exception("Cant create URI for configuring media"); + return instaUri; + } } } \ No newline at end of file diff --git a/InstaSharper/InstaSharper.csproj b/InstaSharper/InstaSharper.csproj new file mode 100644 index 00000000..1643dba4 --- /dev/null +++ b/InstaSharper/InstaSharper.csproj @@ -0,0 +1,30 @@ + + + + 1.2.4 + netstandard1.6;net452 + true + InstaSharper + InstaSharper + 1.6.0 + $(PackageTargetFallback);dnxcore50 + false + false + false + + + + + + + + + + + + + + + + + diff --git a/InstaSharper/InstaSharper.xproj b/InstaSharper/InstaSharper.xproj deleted file mode 100644 index d167e9b1..00000000 --- a/InstaSharper/InstaSharper.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - 449a948d-cc65-4d1a-8159-6fa232f972d9 - InstaSharper - .\obj - .\bin\ - v4.5.2 - - - - 2.0 - - - diff --git a/InstaSharper/ResponseWrappers/BaseResponse/BaseStatusResponse.cs b/InstaSharper/ResponseWrappers/BaseResponse/BaseStatusResponse.cs deleted file mode 100644 index 637ca188..00000000 --- a/InstaSharper/ResponseWrappers/BaseResponse/BaseStatusResponse.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace InstaSharper.ResponseWrappers.BaseResponse -{ - public class BaseStatusResponse - { - [JsonProperty("status")] - public string Status { get; set; } - } -} \ No newline at end of file diff --git a/InstaSharper/ResponseWrappers/InstaFriendshipStatusResponse.cs b/InstaSharper/ResponseWrappers/InstaFriendshipStatusResponse.cs deleted file mode 100644 index d719235f..00000000 --- a/InstaSharper/ResponseWrappers/InstaFriendshipStatusResponse.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Newtonsoft.Json; - -namespace InstaSharper.ResponseWrappers -{ - internal class InstaFriendshipStatusResponse - { - [JsonProperty("following")] - public bool Foolowing { get; set; } - - [JsonProperty("is_private")] - public bool IsPrivate { get; set; } - - [JsonProperty("incoming_request")] - public bool IncomingRequest { get; set; } - - [JsonProperty("outgoing_request")] - public bool OutgoingRequest { get; set; } - } -} \ No newline at end of file diff --git a/InstaSharper/project.json b/InstaSharper/project.json deleted file mode 100644 index 95046439..00000000 --- a/InstaSharper/project.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "version": "1.2.3", - - "dependencies": { - "NETStandard.Library": "1.6.0", - "Newtonsoft.Json": "9.0.1" - }, - - "frameworks": { - "netstandard1.6": { - "imports": "dnxcore50" - }, - "net452": { - - } - } -} diff --git a/README.md b/README.md index 647bb983..e7f5717d 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.3 [Stable], 1.2.4 [Under development] +#### Current version: 1.2.4 [Stable], 1.2.5 [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 @@ -52,20 +52,22 @@ Currently the library supports following coverage of the following Instagram API - [x] Get inbox thread - [x] Get recent activity - [x] Get recent following activity -- [x] Get followings list - [x] Like media - [x] Unlike media -- [ ] Follow user -- [ ] Unfollow user -- [ ] Send comment -- [ ] Edit comment -- [ ] Delete comment +- [x] Follow user +- [x] Unfollow user +- [x] Set account private +- [x] Set account public +- [x] Send comment +- [x] Delete comment +- [x] Upload photo + +- [ ] Get followings list * Get user list autocomplete * Register new user * Get megaphone log * Explore feed -* Upload photo * Upload video * Upload story * Get full account backup @@ -107,14 +109,20 @@ IResult media = await api.GetUserMediaAsync(); #### Get media by its code: ```c# -IResult mediaItem = await api.GetMediaByCodeAsync(mediaCode); +IResult mediaItem = await api.GetMediaByIdAsync("1234567891234567891_123456789); ``` #### Get user timeline feed: ```c# IResult feed = await api.GetUserFeedAsync(); ``` -######for more samples you can look for [Examples folder](https://github.com/a-legotin/InstaSharper/tree/master/InstaSharper.Examples) + +#### Comment post: +```c# +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) #### [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 85a67dd7..95e1e1f7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,11 +1,11 @@ -version: 1.2.1 ({build}) -os: Visual Studio 2015 +version: 1.2.4.{build} +os: Visual Studio 2017 platform: Any CPU configuration: Release branches: only: - - release + - develop - master skip_commits: message: /skip ci/ # Regex for matching commit message @@ -18,16 +18,12 @@ build: include_nuget_references: true # 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: cd InstaSharper - ps: dotnet build + - ps: cd InstaSharper - ps: dotnet pack -o ../nugetpack -c release - - ps: cd ../InstaSharper.Tests - - ps: dotnet restore - - ps: dotnet build - - ps: dotnet test -parallel none - - ps: cd .. environment: instaapiuserpassword: