diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..f34ede58
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,40 @@
+---
+name: Bug report
+about: Create a report to help us improve
+
+---
+
+**Before creating issue**
+Put `x` marks below to validate what you've done before posting issue.
+
+[ ] I've checked [FAQ](https://github.com/a-legotin/InstaSharper/wiki/FAQ)
+[ ] I've checked [wiki page](https://github.com/a-legotin/InstaSharper/wiki)
+[ ] I've examined [examples project](https://github.com/a-legotin/InstaSharper/tree/develop/InstaSharper.Examples)
+[ ] I've did search [existing issues](https://github.com/a-legotin/InstaSharper/issues) for similar problems
+[ ] I've understand that issue will be closed and locked if issue related to `checkpoint, challenge, feedback required` or `sentry_block` or `signup_block`- see [FAQ](https://github.com/a-legotin/InstaSharper/wiki/FAQ)
+
+## Be warned - issue will be closed if none from above is done before posting issue.
+
+**Describe the issue**
+A clear and concise description of what the issue is.
+Attach logs ([How to use logger to get logs](https://github.com/a-legotin/InstaSharper/blob/develop/InstaSharper.Examples/Program.cs)).
+ Provide state of [Info](https://github.com/a-legotin/InstaSharper/blob/develop/InstaSharper/Classes/ResultInfo.cs) property when you got [IResult response](https://github.com/a-legotin/InstaSharper/blob/develop/InstaSharper/Classes/Result.cs).
+
+**To Reproduce**
+How can I reproduce the problem:
+1. Attach code snippet
+2. Push sample project to github and add link here.
+3. What actions is causing issue.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Target (please complete the following information):**
+ - Platform: [e.g. Windows, Linux]
+ - Target framework [e.g. netstandard, net452]
+ - Version [e.g. 1.4.50]
+
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md
new file mode 100644
index 00000000..2e2b2883
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/question.md
@@ -0,0 +1,32 @@
+---
+name: Question
+about: Describe question here
+
+---
+
+**Before creating issue**
+Put `x` marks below to validate what you've done before posting issue.
+
+[ ] I've checked [FAQ](https://github.com/a-legotin/InstaSharper/wiki/FAQ)
+[ ] I've checked [wiki page](https://github.com/a-legotin/InstaSharper/wiki)
+[ ] I've examined [examples project](https://github.com/a-legotin/InstaSharper/tree/develop/InstaSharper.Examples)
+[ ] I've did search [existing issues](https://github.com/a-legotin/InstaSharper/issues) for similar problems
+[ ] I've understand that issue will be closed and locked if issue related to `checkpoint, challenge, feedback required` or `sentry_block` or `signup_block`- see [FAQ](https://github.com/a-legotin/InstaSharper/wiki/FAQ)
+
+## Be warned - issue will be closed if none from above is done before posting issue.
+
+**Describe the issue**
+A clear and concise description of your question
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Target (please complete the following information):**
+ - Platform: [e.g. Windows, Linux]
+ - Target framework [e.g. netstandard, net452]
+ - Version [e.g. 1.4.50]
+
+Add any other context about the problem here.
diff --git a/.gitignore b/.gitignore
index 4e1cd4a5..ec658c42 100644
--- a/.gitignore
+++ b/.gitignore
@@ -262,4 +262,8 @@ paket-files/
# Python Tools for Visual Studio (PTVS)
__pycache__/
-*.pyc
\ No newline at end of file
+*.pyc
+
+# binary files and texts notes
+**/*.bin
+**/*.txt
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 378c022b..0facdd32 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,12 +1,12 @@
language: csharp
-dist: trusty
+dist: bionic
language: csharp
mono: none
-dotnet: 2.0.0
+dotnet: 3.0.1
solution: InstaSharper.sln
script:
- cd InstaSharper
- dotnet --info
- dotnet restore
- - dotnet build --framework netstandard2.0
+ - dotnet build --framework netstandard2.1
diff --git a/InstaSharper.Examples/InstaSharper.Examples.csproj b/InstaSharper.Examples/InstaSharper.Examples.csproj
index 02341bb4..e3593096 100644
--- a/InstaSharper.Examples/InstaSharper.Examples.csproj
+++ b/InstaSharper.Examples/InstaSharper.Examples.csproj
@@ -34,10 +34,6 @@
4
-
- False
- ..\InstaSharper\bin\release\net452\InstaSharper.dll
-
packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll
@@ -52,10 +48,12 @@
+
+
@@ -67,6 +65,12 @@
+
+
+ {dada2751-e331-4231-9434-7141b6b2fe79}
+ InstaSharper
+
+
is succeed
+ /// TwoFactorRequired --> requires 2FA login.
+ /// BadPassword --> Password is wrong
+ /// InvalidUser --> User/phone number is wrong
+ /// Exception --> Something wrong happened
+ ///
+ Task> LoginAsync();
+
+ ///
+ /// Search Place
+ ///
+ Task> SearchPlace(string searchQuery, int count = 5);
+
+
+ ///
+ /// Reset challenge asynchronously
+ ///
+ Task> ResetChallenge();
+
+ ///
+ /// Get verify method asynchronously
+ ///
+ Task> GetVerifyStep();
+
+ ///
+ /// Choose verify method asynchronously
+ ///
+ Task> ChooseVerifyMethod(int choice);
+
+ ///
+ /// Send verify code asynchronously
+ ///
+ Task> SendVerifyCode(string securityCode);
+
+ ///
+ /// 2-Factor Authentication Login using a verification code
+ /// Before call this method, please run LoginAsync first.
+ ///
+ /// Verification Code sent to your phone number
+ ///
+ /// Success --> is succeed
+ /// InvalidCode --> The code is invalid
+ /// CodeExpired --> The code is expired, please request a new one.
+ /// Exception --> Something wrong happened
+ ///
+ Task> TwoFactorLoginAsync(string verificationCode);
+
+ ///
+ /// Get Two Factor Authentication details
+ ///
+ ///
+ /// An instance of TwoFactorLoginInfo if success.
+ /// A null reference if not success; in this case, do LoginAsync first and check if Two Factor Authentication is
+ /// required, if not, don't run this method
+ ///
+ Task> GetTwoFactorInfoAsync();
+
+ ///
+ /// Logout from instagram asynchronously
+ ///
+ /// True if logged out without errors
+ Task> LogoutAsync();
+
+ ///
+ /// Get user timeline feed (feed of recent posts from users you follow) asynchronously.
+ ///
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ Task> GetUserTimelineFeedAsync(PaginationParameters paginationParameters);
+
+ ///
+ /// Get user explore feed (Explore tab info) asynchronously
+ ///
+ /// Pagination parameters: next id and max amount of pages to load
+ /// >
+ Task> GetExploreFeedAsync(PaginationParameters paginationParameters);
+
+ ///
+ /// Get all user media by username asynchronously
+ ///
+ /// Username
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ Task> GetUserMediaAsync(string username, PaginationParameters paginationParameters);
+
+ ///
+ /// Get media by its id asynchronously
+ ///
+ /// Maximum count of pages to retrieve
+ ///
+ ///
+ ///
+ Task> GetMediaByIdAsync(string mediaId);
+
+ ///
+ /// Get user info by its user name asynchronously
+ ///
+ /// Username
+ ///
+ ///
+ ///
+ Task> GetUserAsync(string username);
+
+ ///
+ /// Search users asynchronously
+ ///
+ /// Search pattern e.g. part of username
+ ///
+ /// List of users matches pattern
+ ///
+ ///
+ Task> SearchUsersAsync(string searchPattern);
+
+ ///
+ /// Get currently logged in user info asynchronously
+ ///
+ ///
+ ///
+ ///
+ Task> GetCurrentUserAsync();
+
+ ///
+ /// Get tag feed by tag value asynchronously
+ ///
+ /// Tag value
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ Task> GetTagFeedAsync(string tag, PaginationParameters paginationParameters);
+
+ ///
+ /// Get followers list by username asynchronously
+ ///
+ /// Username
+ /// Pagination parameters: next id and max amount of pages to load
+ /// Search string to locate specific followers
+ ///
+ ///
+ ///
+ Task> GetUserFollowersAsync(string username,
+ PaginationParameters paginationParameters, string searchQuery = "");
+
+ ///
+ /// Get following list by username asynchronously
+ ///
+ /// Username
+ /// Pagination parameters: next id and max amount of pages to load
+ /// Search string to locate specific followings
+ ///
+ ///
+ ///
+ Task> GetUserFollowingAsync(string username,
+ PaginationParameters paginationParameters, string searchQuery = "");
+
+ ///
+ /// Get followers list for currently logged in user asynchronously
+ ///
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ Task> GetCurrentUserFollowersAsync(PaginationParameters paginationParameters);
+
+ ///
+ /// Get following list for currently logged in user asynchronously
+ ///
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ Task> GetCurrentUserFollowingAsync(PaginationParameters paginationParameters);
+
+ ///
+ /// Get user tags by username asynchronously
+ /// Returns media list containing tags
+ ///
+ /// Username
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ Task> GetUserTagsAsync(string username, PaginationParameters paginationParameters);
+
+ ///
+ /// Get direct inbox threads for current user asynchronously
+ ///
+ ///
+ ///
+ ///
+ Task> GetDirectInboxAsync();
+
+ ///
+ /// Get direct inbox thread by its id asynchronously
+ ///
+ /// Thread id
+ ///
+ ///
+ ///
+ Task> GetDirectInboxThreadAsync(string threadId);
+
+ ///
+ /// Send direct message to provided users and threads
+ ///
+ /// Comma-separated users PK
+ /// Message thread ids
+ /// Message text
+ /// List of threads
+ Task> SendDirectMessage(string recipients, string threadIds, string text);
+
+ ///
+ /// Get recent recipients (threads and users) asynchronously
+ ///
+ ///
+ ///
+ ///
+ Task> GetRecentRecipientsAsync();
+
+ ///
+ /// Get ranked recipients (threads and users) asynchronously
+ ///
+ ///
+ ///
+ ///
+ Task> GetRankedRecipientsAsync();
+
+ ///
+ /// Get recent activity info asynchronously
+ ///
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ Task> GetRecentActivityAsync(PaginationParameters paginationParameters);
+
+ ///
+ /// Get activity of following asynchronously
+ ///
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ Task> GetFollowingRecentActivityAsync(PaginationParameters paginationParameters);
+
+ ///
+ /// Like media (photo or video)
+ ///
+ /// Media id
+ Task> LikeMediaAsync(string mediaId);
+
+ ///
+ /// Remove like from media (photo or video)
+ ///
+ /// Media id
+ Task> UnLikeMediaAsync(string mediaId);
+
+ ///
+ /// Follow user
+ ///
+ /// User id
+ Task> FollowUserAsync(long userId);
+
+ ///
+ /// Stop follow user
+ ///
+ /// User id
+ Task> UnFollowUserAsync(long userId);
+
+ ///
+ /// Block user
+ ///
+ /// User id
+ Task> BlockUserAsync(long userId);
+
+ ///
+ /// Stop block user
+ ///
+ /// User id
+ Task> UnBlockUserAsync(long userId);
+
+ ///
+ /// Get media comments
+ ///
+ /// Media id
+ /// Pagination parameters: next id and max amount of pages to load
+ Task>
+ GetMediaCommentsAsync(string mediaId, PaginationParameters paginationParameters);
+
+ ///
+ /// Get users (short) who liked certain media. Normaly it return around 1000 last users.
+ ///
+ /// 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 video
+ ///
+ /// Video to upload
+ /// Image thumbnail
+ /// Caption
+ ///
+ Task> UploadVideoAsync(InstaVideo video, InstaImage imageThumbnail, string caption);
+
+ ///
+ /// Upload photo
+ ///
+ /// Photo to upload
+ /// Caption
+ Task> UploadPhotoAsync(InstaImage image, string caption);
+
+ ///
+ /// Upload photo
+ ///
+ /// Array of photos to upload
+ /// Caption
+ ///
+ Task> UploadPhotosAlbumAsync(InstaImage[] images, string caption);
+
+ ///
+ /// Configure photo
+ ///
+ /// Photo to configure
+ /// Upload id
+ /// Caption
+ ///
+ Task> ConfigurePhotoAsync(InstaImage image, string uploadId, string caption);
+
+ ///
+ /// Configure photos for Album
+ ///
+ /// Array of upload IDs to configure
+ /// ///
+ /// Caption
+ ///
+ Task> ConfigureAlbumAsync(string[] uploadId, string caption);
+
+ ///
+ /// Get user story feed (stories from users followed by current user).
+ ///
+ Task> GetStoryFeedAsync();
+
+ ///
+ /// Get the story by userId
+ ///
+ /// User Id
+ Task> GetUserStoryAsync(long userId);
+
+ ///
+ /// Upload story photo
+ ///
+ /// Photo to upload
+ /// Caption
+ Task> UploadStoryPhotoAsync(InstaImage image, string caption);
+
+ ///
+ /// Configure story photo
+ ///
+ /// Photo to configure
+ /// Upload id
+ /// Caption
+ ///
+ Task> ConfigureStoryPhotoAsync(InstaImage image, string uploadId, string caption);
+
+ ///
+ /// Change password
+ ///
+ /// The old password
+ ///
+ /// The new password (shouldn't be the same old password, and should be a password you never used
+ /// here)
+ ///
+ /// Return true if the password is changed
+ Task> ChangePasswordAsync(string oldPassword, string newPassword);
+
+ ///
+ /// Delete a media (photo or video)
+ ///
+ /// The media ID
+ /// The type of the media
+ /// Return true if the media is deleted
+ Task> DeleteMediaAsync(string mediaId, InstaMediaType mediaType);
+
+ ///
+ /// Edit the caption of the media (photo/video)
+ ///
+ /// The media ID
+ /// The new caption
+ /// Return true if everything is ok
+ Task> EditMediaAsync(string mediaId, string caption);
+
+ ///
+ /// Get feed of media your liked.
+ ///
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ Task> GetLikeFeedAsync(PaginationParameters paginationParameters);
+
+ ///
+ /// Get friendship status for given user id.
+ ///
+ /// User identifier (PK)
+ ///
+ ///
+ ///
+ Task> GetFriendshipStatusAsync(long userId);
+
+ ///
+ /// Get user story reel feed. Contains user info last story including all story items.
+ ///
+ /// User identifier (PK)
+ ///
+ Task> GetUserStoryFeedAsync(long userId);
+
+ ///
+ /// Get your collection for given collection id
+ ///
+ /// Collection ID
+ ///
+ ///
+ ///
+ Task> GetCollectionAsync(long collectionId);
+
+ ///
+ /// Get your collections
+ ///
+ ///
+ ///
+ ///
+ Task> GetCollectionsAsync();
+
+ ///
+ /// Create a new collection
+ ///
+ /// The name of the new collection
+ ///
+ ///
+ ///
+ Task> CreateCollectionAsync(string collectionName);
+
+ ///
+ /// Delete your collection for given collection id
+ ///
+ /// Collection ID to delete
+ /// true if succeed
+ Task> DeleteCollectionAsync(long collectionId);
+
+ ///
+ /// Get media ID from an url (got from "share link")
+ ///
+ /// Uri to get media ID
+ /// Media ID
+ Task> GetMediaIdFromUrlAsync(Uri uri);
+
+ ///
+ /// Get share link from media Id
+ ///
+ /// media ID
+ /// Share link as Uri
+ Task> GetShareLinkFromMediaIdAsync(string mediaId);
+
+ ///
+ /// Adds items to collection asynchronous.
+ ///
+ /// Collection identifier.
+ /// Media id list.
+ ///
+ Task> AddItemsToCollectionAsync(long collectionId, params string[] mediaIds);
+
+ ///
+ /// Searches for specific location by provided geo-data or search query.
+ ///
+ /// Latitude
+ /// Longitude
+ /// Search query
+ /// List of locations (short format)
+ Task> SearchLocation(double latitude, double longitude, string query);
+
+ ///
+ /// Gets the feed of particular location.
+ ///
+ /// Location identifier
+ /// Pagination parameters: next id and max amount of pages to load
+ /// Location feed
+ Task> GetLocationFeed(long locationId, PaginationParameters paginationParameters);
+
+ ///
+ /// Searches for specific hashtag by search query.
+ ///
+ /// Search query
+ ///
+ /// Array of numerical hashtag IDs (ie "17841562498105353") to exclude from the response,
+ /// allowing you to skip tags from a previous call to get more results
+ ///
+ /// The rank token from the previous page's response
+ /// List of hashtags
+ Task> SearchHashtag(string query, IEnumerable excludeList = null,
+ string rankToken = null);
+
+ ///
+ /// Gets the hashtag information by user tagname.
+ ///
+ /// Tagname
+ /// Hashtag information
+ Task> GetHashtagInfo(string tagname);
+
+ ///
+ /// Gets the user extended information (followers count, following count, bio, etc) by user identifier.
+ ///
+ /// User Id, like "123123123"
+ ///
+ Task> GetUserInfoByIdAsync(long pk);
+
+ ///
+ /// Gets the user extended information (followers count, following count, bio, etc) by username.
+ ///
+ /// Username, like "instagram"
+ ///
+ Task> GetUserInfoByUsernameAsync(string username);
+
+ ///
+ /// Send link as a message
+ ///
+ /// Direct message (link + description)
+ /// Array of recipients, user pk like "123123123"
+ /// Affected threads
+ Task> SendLinkMessage(InstaMessageLink message, params long[] recipients);
+
+ ///
+ /// Send link as a message
+ ///
+ /// Direct message (link + description)
+ /// Array of threads, thread id like "111182366841710300949128137443944311111"
+ /// Affected threads
+ Task> SendLinkMessage(InstaMessageLink message, params string[] threads);
+
+ ///
+ /// Send media as a message
+ ///
+ /// Media id, e.g. "1166111111128767752_1111111"
+ /// Type of media (photo/video)
+ /// Array of threads, thread id e.g. "111182366841710300949128137443944311111"
+ /// Affected threads
+ Task> ShareMedia(string mediaId, InstaMediaType mediaType,
+ params string[] threads);
+
+ ///
+ /// Decline ALL pending threads
+ ///
+ /// Status response
+ Task> DeclineAllPendingDirectThreads();
+
+ ///
+ /// Approve single thread by id
+ ///
+ /// Thread id, e.g. "111182366841710300949128137443944311111"
+ /// Status response
+ Task> ApprovePendingDirectThread(string threadId);
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/InstaSharper/API/InstaApi.cs b/InstaSharper/API/InstaApi.cs
index 0a041f74..e1dc3d91 100644
--- a/InstaSharper/API/InstaApi.cs
+++ b/InstaSharper/API/InstaApi.cs
@@ -1,1532 +1,1377 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Threading.Tasks;
-using InstaSharper.Classes;
-using InstaSharper.Classes.Android.DeviceInfo;
-using InstaSharper.Classes.Models;
-using InstaSharper.Classes.ResponseWrappers;
-using InstaSharper.Classes.ResponseWrappers.BaseResponse;
-using InstaSharper.Converters;
-using InstaSharper.Converters.Json;
-using InstaSharper.Helpers;
-using InstaSharper.Logger;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using InstaRecentActivityConverter = InstaSharper.Converters.Json.InstaRecentActivityConverter;
-
-namespace InstaSharper.API
-{
- internal class InstaApi : IInstaApi
- {
- private readonly IHttpRequestProcessor _httpRequestProcessor;
- private readonly IInstaLogger _logger;
- private AndroidDevice _deviceInfo;
- private UserSessionData _user;
-
- public InstaApi(UserSessionData user, IInstaLogger logger, AndroidDevice deviceInfo,
- IHttpRequestProcessor httpRequestProcessor)
- {
- _user = user;
- _logger = logger;
- _deviceInfo = deviceInfo;
- _httpRequestProcessor = httpRequestProcessor;
- }
-
- public bool IsUserAuthenticated { get; private set; }
-
- #region async part
-
- public async Task> LoginAsync()
- {
- ValidateUser();
- ValidateRequestMessage();
- try
- {
- var csrftoken = string.Empty;
- var firstResponse = await _httpRequestProcessor.GetAsync(_httpRequestProcessor.Client.BaseAddress);
- var cookies =
- _httpRequestProcessor.HttpHandler.CookieContainer.GetCookies(_httpRequestProcessor.Client
- .BaseAddress);
- _logger?.LogResponse(firstResponse);
- foreach (Cookie cookie in cookies)
- if (cookie.Name == InstaApiConstants.CSRFTOKEN) csrftoken = cookie.Value;
- _user.CsrfToken = csrftoken;
- var instaUri = UriCreator.GetLoginUri();
- var signature =
- $"{_httpRequestProcessor.RequestMessage.GenerateSignature()}.{_httpRequestProcessor.RequestMessage.GetMessageString()}";
- var fields = new Dictionary
- {
- {InstaApiConstants.HEADER_IG_SIGNATURE, signature},
- {InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION}
- };
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo);
- request.Content = new FormUrlEncodedContent(fields);
- 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 _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK) return Result.UnExpectedResponse(response, json);
- var loginInfo =
- JsonConvert.DeserializeObject(json);
- IsUserAuthenticated = loginInfo.User != null && loginInfo.User.UserName == _user.UserName;
- var converter = ConvertersFabric.GetUserShortConverter(loginInfo.User);
- _user.LoggedInUder = converter.Convert();
- _user.RankToken = $"{_user.LoggedInUder.Pk}_{_httpRequestProcessor.RequestMessage.phone_id}";
- return Result.Success(true);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, false);
- }
- }
-
- public async Task> LogoutAsync()
- {
- ValidateUser();
- ValidateLoggedIn();
- try
- {
- var instaUri = UriCreator.GetLogoutUri();
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK) return Result.UnExpectedResponse(response, json);
- var logoutInfo = JsonConvert.DeserializeObject(json);
- IsUserAuthenticated = logoutInfo.Status == "ok";
- return Result.Success(true);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, false);
- }
- }
-
- public async Task> GetUserTimelineFeedAsync(int maxPages = 0)
- {
- ValidateUser();
- ValidateLoggedIn();
- var userFeedUri = UriCreator.GetUserFeedUri();
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK) return Result.UnExpectedResponse(response, json);
- var feedResponse = JsonConvert.DeserializeObject(json,
- new InstaFeedResponseDataConverter());
- var converter = ConvertersFabric.GetFeedConverter(feedResponse);
- var feed = converter.Convert();
- var nextId = feedResponse.NextMaxId;
- var moreAvailable = feedResponse.MoreAvailable;
- while (moreAvailable && feed.Medias.Pages < maxPages)
- {
- if (string.IsNullOrEmpty(nextId)) break;
- var nextFeed = await GetUserFeedWithMaxIdAsync(nextId);
- if (!nextFeed.Succeeded) Result.Success($"Not all pages was downloaded: {nextFeed.Info.Message}", feed);
- nextId = nextFeed.Value.NextMaxId;
- moreAvailable = nextFeed.Value.MoreAvailable;
- feed.Medias.AddRange(
- nextFeed.Value.Items.Select(ConvertersFabric.GetSingleMediaConverter)
- .Select(conv => conv.Convert()));
- feed.Medias.Pages++;
- }
- return Result.Success(feed);
- }
-
- public async Task> GetUserStoryFeedAsync(long userId)
- {
- ValidateUser();
- ValidateLoggedIn();
- try
- {
- var userFeedUri = UriCreator.GetUserReelFeedUri(userId);
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK)
- return Result.UnExpectedResponse(response, json);
- var feedResponse = JsonConvert.DeserializeObject(json);
- var feed = ConvertersFabric.GetReelFeedConverter(feedResponse).Convert();
- return Result.Success(feed);
- }
- catch (Exception exception)
- {
- return Result.Fail(exception.Message, (InsteReelFeed) null);
- }
- }
-
- ///
- public Stream GetStateDataAsStream()
- {
- var state = new StateData
- {
- DeviceInfo = _deviceInfo,
- IsAuthenticated = IsUserAuthenticated,
- UserSession = _user,
- Cookies = _httpRequestProcessor.HttpHandler.CookieContainer
- };
- return SerializationHelper.SerializeToStream(state);
- }
-
- ///
- public void LoadStateDataFromStream(Stream stream)
- {
- var data = SerializationHelper.DeserializeFromStream(stream);
- _deviceInfo = data.DeviceInfo;
- _user = data.UserSession;
- IsUserAuthenticated = data.IsAuthenticated;
- _httpRequestProcessor.HttpHandler.CookieContainer = data.Cookies;
- }
-
- public async Task> GetExploreFeedAsync(int maxPages = 0)
- {
- ValidateUser();
- ValidateLoggedIn();
- try
- {
- if (maxPages == 0) maxPages = int.MaxValue;
- var exploreUri = UriCreator.GetExploreUri();
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, exploreUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaExploreFeed) null);
- var feedResponse = JsonConvert.DeserializeObject(json,
- new InstaExploreFeedDataConverter());
- var exploreFeed = ConvertersFabric.GetExploreFeedConverter(feedResponse).Convert();
- var nextId = feedResponse.Items.Medias.LastOrDefault(media => !string.IsNullOrEmpty(media.NextMaxId))
- ?.NextMaxId;
- while (!string.IsNullOrEmpty(nextId) && exploreFeed.Medias.Pages < maxPages)
- {
- var nextFeed = await GetExploreFeedAsync(nextId);
- if (!nextFeed.Succeeded)
- Result.Success($"Not all pages were downloaded: {nextFeed.Info.Message}", exploreFeed);
- nextId = feedResponse.Items.Medias.LastOrDefault(media => !string.IsNullOrEmpty(media.NextMaxId))
- ?.NextMaxId;
- exploreFeed.Medias.AddRange(
- nextFeed.Value.Items.Medias.Select(ConvertersFabric.GetSingleMediaConverter)
- .Select(conv => conv.Convert()));
- exploreFeed.Medias.Pages++;
- }
- return Result.Success(exploreFeed);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, (InstaExploreFeed) null);
- }
- }
-
- public async Task> GetUserMediaAsync(string username, int maxPages = 0)
- {
- ValidateUser();
- if (maxPages == 0) maxPages = int.MaxValue;
- var user = await GetUserAsync(username);
- if (!user.Succeeded) return Result.Fail("Unable to get current user");
- var instaUri = UriCreator.GetUserMediaListUri(user.Value.Pk);
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var mediaResponse = JsonConvert.DeserializeObject(json,
- new InstaMediaListDataConverter());
- var moreAvailable = mediaResponse.MoreAvailable;
- var converter = ConvertersFabric.GetMediaListConverter(mediaResponse);
- var mediaList = converter.Convert();
- mediaList.Pages++;
- var nextId = mediaResponse.NextMaxId;
- while (moreAvailable && mediaList.Pages < maxPages)
- {
- instaUri = UriCreator.GetMediaListWithMaxIdUri(user.Value.Pk, nextId);
- var nextMedia = await GetUserMediaListWithMaxIdAsync(instaUri);
- mediaList.Pages++;
- if (!nextMedia.Succeeded)
- Result.Success($"Not all pages were downloaded: {nextMedia.Info.Message}", mediaList);
- nextId = nextMedia.Value.NextMaxId;
- moreAvailable = nextMedia.Value.MoreAvailable;
- converter = ConvertersFabric.GetMediaListConverter(nextMedia.Value);
- mediaList.AddRange(converter.Convert());
- }
- return Result.Success(mediaList);
- }
- return Result.UnExpectedResponse(response, json);
- }
-
- public async Task> GetMediaByIdAsync(string mediaId)
- {
- ValidateUser();
- var mediaUri = UriCreator.GetMediaUri(mediaId);
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, mediaUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var mediaResponse = JsonConvert.DeserializeObject(json,
- new InstaMediaListDataConverter());
- if (mediaResponse.Medias?.Count != 1)
- {
- var errorMessage = $"Got wrong media count for request with media id={mediaId}";
- _logger?.LogInfo(errorMessage);
- return Result.Fail(errorMessage);
- }
- var converter = ConvertersFabric.GetSingleMediaConverter(mediaResponse.Medias.FirstOrDefault());
- return Result.Success(converter.Convert());
- }
- return Result.UnExpectedResponse(response, json);
- }
-
- public async Task> GetUserAsync(string username)
- {
- ValidateUser();
- var userUri = UriCreator.GetUserUri(username);
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo);
- request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE,
- InstaApiConstants.TIMEZONE_OFFSET.ToString()));
- request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_COUNT, "1"));
- request.Properties.Add(
- new KeyValuePair(InstaApiConstants.HEADER_RANK_TOKEN, _user.RankToken));
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var userInfo = JsonConvert.DeserializeObject(json);
- var user = userInfo.Users?.FirstOrDefault(u => u.UserName == username);
- if (user == null)
- {
- var errorMessage = $"Can't find this user: {username}";
- _logger?.LogInfo(errorMessage);
- return Result.Fail(errorMessage);
- }
- if (string.IsNullOrEmpty(user.Pk))
- Result.Fail("Pk is null");
- var converter = ConvertersFabric.GetUserConverter(user);
- return Result.Success(converter.Convert());
- }
- return Result.UnExpectedResponse(response, json);
- }
-
-
- public async Task> GetCurrentUserAsync()
- {
- ValidateUser();
- ValidateLoggedIn();
- var instaUri = UriCreator.GetCurrentUserUri();
- var fields = new Dictionary
- {
- {"_uuid", _deviceInfo.DeviceGuid.ToString()},
- {"_uid", _user.LoggedInUder.Pk},
- {"_csrftoken", _user.CsrfToken}
- };
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo);
- request.Content = new FormUrlEncodedContent(fields);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var user = JsonConvert.DeserializeObject(json,
- new InstaCurrentUserDataConverter());
- if (string.IsNullOrEmpty(user.Pk))
- Result.Fail("Pk is null");
- var converter = ConvertersFabric.GetCurrentUserConverter(user);
- var userConverted = converter.Convert();
- return Result.Success(userConverted);
- }
- return Result.UnExpectedResponse(response, json);
- }
-
- public async Task> GetTagFeedAsync(string tag, int maxPages = 0)
- {
- ValidateUser();
- ValidateLoggedIn();
- if (maxPages == 0) maxPages = int.MaxValue;
- var userFeedUri = UriCreator.GetTagFeedUri(tag);
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var feedResponse = JsonConvert.DeserializeObject(json,
- new InstaTagFeedDataConverter());
- var converter = ConvertersFabric.GetTagFeedConverter(feedResponse);
- var tagFeed = converter.Convert();
- tagFeed.Medias.Pages++;
- var nextId = feedResponse.NextMaxId;
- var moreAvailable = feedResponse.MoreAvailable;
- while (moreAvailable && tagFeed.Medias.Pages < maxPages)
- {
- var nextMedia = await GetTagFeedWithMaxIdAsync(tag, nextId);
- tagFeed.Medias.Pages++;
- if (!nextMedia.Succeeded)
- return Result.Success($"Not all pages was downloaded: {nextMedia.Info.Message}", tagFeed);
- nextId = nextMedia.Value.NextMaxId;
- moreAvailable = nextMedia.Value.MoreAvailable;
- tagFeed.Medias.AddRange(ConvertersFabric.GetMediaListConverter(nextMedia.Value).Convert());
- }
- return Result.Success(tagFeed);
- }
- return Result.UnExpectedResponse(response, json);
- }
-
- public async Task> GetUserFollowersAsync(string username, int maxPages = 0)
- {
- ValidateUser();
- ValidateLoggedIn();
- try
- {
- if (maxPages == 0) maxPages = int.MaxValue;
- var user = await GetUserAsync(username);
- var userFollowersUri = UriCreator.GetUserFollowersUri(user.Value.Pk, _user.RankToken);
- var followers = new InstaUserShortList();
- var followersResponse = await GetUserListByURIAsync(userFollowersUri);
- if (!followersResponse.Succeeded)
- Result.Fail(followersResponse.Info, (InstaUserList) null);
- followers.AddRange(
- followersResponse.Value.Items.Select(ConvertersFabric.GetUserShortConverter)
- .Select(converter => converter.Convert()));
- if (!followersResponse.Value.IsBigList) return Result.Success(followers);
- var pages = 1;
- while (!string.IsNullOrEmpty(followersResponse.Value.NextMaxId) && pages < maxPages)
- {
- var nextFollowersUri =
- UriCreator.GetUserFollowersUri(user.Value.Pk, _user.RankToken,
- followersResponse.Value.NextMaxId);
- followersResponse = await GetUserListByURIAsync(nextFollowersUri);
- if (!followersResponse.Succeeded)
- return Result.Success($"Not all pages was downloaded: {followersResponse.Info.Message}",
- followers);
- followers.AddRange(
- followersResponse.Value.Items.Select(ConvertersFabric.GetUserShortConverter)
- .Select(converter => converter.Convert()));
- pages++;
- }
- return Result.Success(followers);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, (InstaUserShortList) null);
- }
- }
-
- public async Task> GetUserFollowingAsync(string username, int maxPages = 0)
- {
- ValidateUser();
- ValidateLoggedIn();
- try
- {
- if (maxPages == 0) maxPages = int.MaxValue;
- var user = await GetUserAsync(username);
- var userFeedUri = UriCreator.GetUserFollowingUri(user.Value.Pk, _user.RankToken);
- var following = new InstaUserShortList();
- var userListResponse = await GetUserListByURIAsync(userFeedUri);
- if (!userListResponse.Succeeded)
- Result.Fail(userListResponse.Info, following);
- following.AddRange(
- userListResponse.Value.Items.Select(ConvertersFabric.GetUserShortConverter)
- .Select(converter => converter.Convert()));
- if (!userListResponse.Value.IsBigList) return Result.Success(following);
- var pages = 1;
- while (!string.IsNullOrEmpty(userListResponse.Value.NextMaxId) && pages < maxPages)
- {
- var nextUri =
- UriCreator.GetUserFollowingUri(user.Value.Pk, _user.RankToken,
- userListResponse.Value.NextMaxId);
- userListResponse = await GetUserListByURIAsync(nextUri);
- if (!userListResponse.Succeeded)
- return Result.Success($"Not all pages was downloaded: {userListResponse.Info.Message}",
- following);
- following.AddRange(
- userListResponse.Value.Items.Select(ConvertersFabric.GetUserShortConverter)
- .Select(converter => converter.Convert()));
- pages++;
- }
- return Result.Success(following);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, (InstaUserShortList) null);
- }
- }
-
-
- public async Task> GetCurrentUserFollowersAsync(int maxPages = 0)
- {
- ValidateUser();
- return await GetUserFollowersAsync(_user.UserName, maxPages);
- }
-
- public async Task> GetUserTagsAsync(string username, int maxPages = 0)
- {
- ValidateUser();
- ValidateLoggedIn();
- try
- {
- if (maxPages == 0) maxPages = int.MaxValue;
- var user = await GetUserAsync(username);
- if (!user.Succeeded || string.IsNullOrEmpty(user.Value.Pk))
- return Result.Fail($"Unable to get user {username}", (InstaMediaList) null);
- var uri = UriCreator.GetUserTagsUri(user.Value?.Pk, _user.RankToken);
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- var userTags = new InstaMediaList();
- if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaMediaList) null);
- var mediaResponse = JsonConvert.DeserializeObject(json,
- new InstaMediaListDataConverter());
- var nextId = mediaResponse.NextMaxId;
- userTags.AddRange(
- mediaResponse.Medias.Select(ConvertersFabric.GetSingleMediaConverter)
- .Select(converter => converter.Convert()));
- var pages = 1;
- while (!string.IsNullOrEmpty(nextId) && pages < maxPages)
- {
- uri = UriCreator.GetUserTagsUri(user.Value?.Pk, _user.RankToken, nextId);
- var nextMedia = await GetUserMediaListWithMaxIdAsync(uri);
- if (!nextMedia.Succeeded)
- Result.Success($"Not all pages was downloaded: {nextMedia.Info.Message}", userTags);
- nextId = nextMedia.Value.NextMaxId;
- userTags.AddRange(
- mediaResponse.Medias.Select(ConvertersFabric.GetSingleMediaConverter)
- .Select(converter => converter.Convert()));
- pages++;
- }
- return Result.Success(userTags);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, (InstaMediaList) null);
- }
- }
-
-
- public async Task> GetDirectInboxAsync()
- {
- ValidateUser();
- ValidateLoggedIn();
- try
- {
- var directInboxUri = UriCreator.GetDirectInboxUri();
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, directInboxUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaDirectInboxContainer) null);
- var inboxResponse = JsonConvert.DeserializeObject(json);
- var converter = ConvertersFabric.GetDirectInboxConverter(inboxResponse);
- return Result.Success(converter.Convert());
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception);
- }
- }
-
- public async Task> GetDirectInboxThreadAsync(string threadId)
- {
- ValidateUser();
- ValidateLoggedIn();
- try
- {
- var directInboxUri = UriCreator.GetDirectInboxThreadUri(threadId);
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, directInboxUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaDirectInboxThread) null);
- var threadResponse = JsonConvert.DeserializeObject(json,
- new InstaThreadDataConverter());
- var converter = ConvertersFabric.GetDirectThreadConverter(threadResponse);
- return Result.Success(converter.Convert());
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception);
- }
- }
-
- public async Task> SendDirectMessage(string recipients, string threadIds, string text)
- {
- ValidateUser();
- ValidateLoggedIn();
- try
- {
- var directSendMessageUri = UriCreator.GetDirectSendMessageUri();
-
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, directSendMessageUri, _deviceInfo);
-
- var fields = new Dictionary {{"text", text}};
-
- if (!string.IsNullOrEmpty(recipients))
- fields.Add("recipient_users", "[[" + recipients + "]]");
- else if (!string.IsNullOrEmpty(threadIds))
- fields.Add("thread_ids", "[" + threadIds + "]");
- else
- return Result.Fail("Please provide at least one recipient or thread.");
-
- request.Content = new FormUrlEncodedContent(fields);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK) return Result.UnExpectedResponse(response, json);
- var result = JsonConvert.DeserializeObject(json);
- return result.IsOk() ? Result.Success(true) : Result.Fail(result.Status);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception);
- }
- }
-
- public async Task> GetRecentRecipientsAsync()
- {
- ValidateUser();
- ValidateLoggedIn();
- var userUri = UriCreator.GetRecentRecipientsUri();
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
-
- if (response.StatusCode != HttpStatusCode.OK)
- return Result.UnExpectedResponse(response, json);
- var responseRecipients = JsonConvert.DeserializeObject(json);
- var converter = ConvertersFabric.GetRecipientsConverter(responseRecipients);
- return Result.Success(converter.Convert());
- }
-
- public async Task> GetRankedRecipientsAsync()
- {
- ValidateUser();
- ValidateLoggedIn();
- var userUri = UriCreator.GetRankedRecipientsUri();
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK)
- return Result.UnExpectedResponse(response, json);
- var responseRecipients = JsonConvert.DeserializeObject(json);
- var converter = ConvertersFabric.GetRecipientsConverter(responseRecipients);
- return Result.Success(converter.Convert());
- }
-
- public async Task> GetRecentActivityAsync(int maxPages = 0)
- {
- var uri = UriCreator.GetRecentActivityUri();
- return await GetRecentActivityInternalAsync(uri, maxPages);
- }
-
- public async Task> GetFollowingRecentActivityAsync(int maxPages = 0)
- {
- var uri = UriCreator.GetFollowingRecentActivityUri();
- return await GetRecentActivityInternalAsync(uri, maxPages);
- }
-
-
- public async Task> CheckpointAsync(string checkPointUrl)
- {
- if (string.IsNullOrEmpty(checkPointUrl)) return Result.Fail("Empty checkpoint URL", false);
- var instaUri = new Uri(checkPointUrl);
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK) return Result.Success(true);
- return Result.UnExpectedResponse(response, json);
- }
-
-
- 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 _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- return Result.Success(true);
- return Result.UnExpectedResponse(response, json);
- }
- catch (Exception exception)
- {
- LogException(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 _httpRequestProcessor.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)
- {
- LogException(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 _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK)
- return Result.UnExpectedResponse(response, json);
- var likers = new InstaLikersList();
- var mediaLikersResponse = JsonConvert.DeserializeObject(json);
- likers.UsersCount = mediaLikersResponse.UsersCount;
- if (mediaLikersResponse.UsersCount < 1) return Result.Success(likers);
- likers.AddRange(
- mediaLikersResponse.Users.Select(ConvertersFabric.GetUserShortConverter)
- .Select(converter => converter.Convert()));
- return Result.Success(likers);
- }
- catch (Exception exception)
- {
- LogException(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 _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var userInfoUpdated =
- JsonConvert.DeserializeObject(json, new InstaUserShortDataConverter());
- if (string.IsNullOrEmpty(userInfoUpdated.Pk))
- return Result.Fail("Pk is null or empty");
- var converter = ConvertersFabric.GetUserShortConverter(userInfoUpdated);
- return Result.Success(converter.Convert());
- }
- return Result.UnExpectedResponse(response, json);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, (InstaUserShort) 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 _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var userInfoUpdated =
- JsonConvert.DeserializeObject(json, new InstaUserShortDataConverter());
- if (string.IsNullOrEmpty(userInfoUpdated.Pk))
- return Result.Fail("Pk is null or empty");
- var converter = ConvertersFabric.GetUserShortConverter(userInfoUpdated);
- return Result.Success(converter.Convert());
- }
- return Result.UnExpectedResponse(response, json);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, (InstaUserShort) 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 _httpRequestProcessor.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());
- }
- return Result.UnExpectedResponse(response, json);
- }
- 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 _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- return Result.Success(true);
- return Result.UnExpectedResponse(response, json);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, false);
- }
- }
-
- public async Task> UploadPhotoAsync(InstaImage 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 _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.IsSuccessStatusCode)
- return await ConfigurePhotoAsync(image, uploadId, caption);
- return Result.UnExpectedResponse(response, json);
- }
- catch (Exception exception)
- {
- return Result.Fail(exception.Message, (InstaMedia) null);
- }
- }
-
- public async Task> ConfigurePhotoAsync(InstaImage 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 _httpRequestProcessor.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());
- }
- return Result.UnExpectedResponse(response, json);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, (InstaMedia) null);
- }
- }
-
-
- public async Task> GetStoryFeedAsync()
- {
- ValidateUser();
- ValidateLoggedIn();
-
- try
- {
- var storyFeedUri = UriCreator.GetStoryFeedUri();
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, storyFeedUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaStoryFeed) null);
- var storyFeedResponse = JsonConvert.DeserializeObject(json);
- var instaStoryFeed = ConvertersFabric.GetStoryFeedConverter(storyFeedResponse).Convert();
- return Result.Success(instaStoryFeed);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, (InstaStoryFeed) null);
- }
- }
-
- public async Task> GetUserStoryAsync(long userId)
- {
- ValidateUser();
- ValidateLoggedIn();
-
- try
- {
- var userStoryUri = UriCreator.GetUserStoryUri(userId);
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userStoryUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
-
- if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaStory) null);
- var userStory = new InstaStory();
- var userStoryResponse = JsonConvert.DeserializeObject(json);
-
- userStory = ConvertersFabric.GetStoryConverter(userStoryResponse).Convert();
-
- return Result.Success(userStory);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, (InstaStory) null);
- }
- }
-
- public async Task> UploadStoryPhotoAsync(InstaImage 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 _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.IsSuccessStatusCode)
- return await ConfigureStoryPhotoAsync(image, uploadId, caption);
- return Result.UnExpectedResponse(response, json);
- }
- catch (Exception exception)
- {
- return Result.Fail(exception.Message, (InstaStoryMedia) null);
- }
- }
-
- public async Task> ConfigureStoryPhotoAsync(InstaImage image, string uploadId,
- string caption)
- {
- ValidateUser();
- ValidateLoggedIn();
- try
- {
- var instaUri = UriCreator.GetStoryConfigureUri();
- var data = new JObject
- {
- {"_uuid", _deviceInfo.DeviceGuid.ToString()},
- {"_uid", _user.LoggedInUder.Pk},
- {"_csrftoken", _user.CsrfToken},
- {"source_type", "1"},
- {"caption", caption},
- {"upload_id", uploadId},
- {"edits", new JObject()},
- {"disable_comments", false},
- {"configure_mode", 1},
- {"camera_position", "unknown"}
- };
- var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, data);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.IsSuccessStatusCode)
- {
- var mediaResponse = JsonConvert.DeserializeObject(json);
- var converter = ConvertersFabric.GetStoryMediaConverter(mediaResponse);
- return Result.Success(converter.Convert());
- }
- return Result.UnExpectedResponse(response, json);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, (InstaStoryMedia) null);
- }
- }
-
- public async Task> ChangePasswordAsync(string oldPassword, string newPassword)
- {
- ValidateUser();
- ValidateLoggedIn();
-
- if (oldPassword == newPassword)
- return Result.Fail("The old password should not the same of the new password", false);
-
- try
- {
- var changePasswordUri = UriCreator.GetChangePasswordUri();
-
- var data = new JObject
- {
- {"_uuid", _deviceInfo.DeviceGuid.ToString()},
- {"_uid", _user.LoggedInUder.Pk},
- {"_csrftoken", _user.CsrfToken},
- {"old_password", oldPassword},
- {"new_password1", newPassword},
- {"new_password2", newPassword}
- };
-
- var request = HttpHelper.GetSignedRequest(HttpMethod.Get, changePasswordUri, _deviceInfo, data);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- return Result.Success(true); //If status code is OK, then the password is surely changed
- var error = JsonConvert.DeserializeObject(json);
- var errors = "";
- error.Message.Errors.ForEach(errorContent => errors += errorContent + "\n");
- return Result.Fail(errors, false);
- }
- catch (Exception exception)
- {
- return Result.Fail(exception.Message, false);
- }
- }
-
- public async Task> DeleteMediaAsync(string mediaId, InstaMediaType mediaType)
- {
- ValidateUser();
- ValidateLoggedIn();
-
- try
- {
- var deleteMediaUri = UriCreator.GetDeleteMediaUri(mediaId, mediaType);
-
- var data = new JObject
- {
- {"_uuid", _deviceInfo.DeviceGuid.ToString()},
- {"_uid", _user.LoggedInUder.Pk},
- {"_csrftoken", _user.CsrfToken},
- {"media_id", mediaId}
- };
-
- var request = HttpHelper.GetSignedRequest(HttpMethod.Get, deleteMediaUri, _deviceInfo, data);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var deletedResponse = JsonConvert.DeserializeObject(json);
- return Result.Success(deletedResponse.IsDeleted);
- }
- var error = JsonConvert.DeserializeObject(json);
- var errors = "";
- error.Message.Errors.ForEach(errorContent => errors += errorContent + "\n");
- return Result.Fail(errors, false);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, false);
- }
- }
-
- public async Task> EditMediaAsync(string mediaId, string caption)
- {
- ValidateUser();
- ValidateLoggedIn();
-
- try
- {
- var editMediaUri = UriCreator.GetEditMediaUri(mediaId);
-
- var data = new JObject
- {
- {"_uuid", _deviceInfo.DeviceGuid.ToString()},
- {"_uid", _user.LoggedInUder.Pk},
- {"_csrftoken", _user.CsrfToken},
- {"caption_text", caption}
- };
-
- var request = HttpHelper.GetSignedRequest(HttpMethod.Get, editMediaUri, _deviceInfo, data);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- return
- Result.Success(
- true); //Technically Instagram returns the InstaMediaItem, but it is useless in our case, at this time.
- var error = JsonConvert.DeserializeObject(json);
- return Result.Fail(error.Message, false);
- }
- catch (Exception exception)
- {
- return Result.Fail(exception.Message, false);
- }
- }
-
- public async Task> GetLikeFeedAsync(int maxPages = 0)
- {
- ValidateUser();
- if (maxPages == 0) maxPages = int.MaxValue;
- var instaUri = UriCreator.GetUserLikeFeedUri();
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var mediaResponse = JsonConvert.DeserializeObject(json,
- new InstaMediaListDataConverter());
- var moreAvailable = mediaResponse.MoreAvailable;
- var converter = ConvertersFabric.GetMediaListConverter(mediaResponse);
- var mediaList = converter.Convert();
- mediaList.Pages++;
- var nextId = mediaResponse.NextMaxId;
- while (moreAvailable && mediaList.Pages < maxPages)
- {
- var result = await GetLikeFeedInternal(nextId);
- if (!result.Succeeded)
- return Result.Fail(result.Info, mediaList);
- converter = ConvertersFabric.GetMediaListConverter(result.Value);
- mediaList.AddRange(converter.Convert());
- mediaList.Pages++;
- nextId = mediaResponse.NextMaxId;
- moreAvailable = result.Value.MoreAvailable;
- }
- return Result.Success(mediaList);
- }
- return Result.UnExpectedResponse(response, json);
- }
-
- public async Task> GetLikeFeedInternal(string maxId = "")
- {
- var instaUri = UriCreator.GetUserLikeFeedUri(maxId);
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK)
- return Result.UnExpectedResponse(response, json);
- var mediaResponse = JsonConvert.DeserializeObject(json,
- new InstaMediaListDataConverter());
- return Result.Success(mediaResponse);
- }
-
- public async Task> GetFriendshipStatusAsync(long userId)
- {
- ValidateUser();
- var userUri = UriCreator.GetUserFriendshipUri(userId);
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK)
- return Result.UnExpectedResponse(response, json);
- var friendshipStatusResponse = JsonConvert.DeserializeObject(json);
- var converter = ConvertersFabric.GetFriendShipStatusConverter(friendshipStatusResponse);
- return Result.Success(converter.Convert());
- }
-
- #endregion
-
- #region private part
-
- private void ValidateUser()
- {
- if (string.IsNullOrEmpty(_user.UserName) || string.IsNullOrEmpty(_user.Password))
- throw new ArgumentException("user name and password must be specified");
- }
-
- private void ValidateLoggedIn()
- {
- if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated");
- }
-
- private void ValidateRequestMessage()
- {
- if (_httpRequestProcessor.RequestMessage == null || _httpRequestProcessor.RequestMessage.IsEmpty())
- throw new ArgumentException("API request message null or empty");
- }
-
- private async Task> GetUserFeedWithMaxIdAsync(string maxId)
- {
- if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.TIMELINEFEED,
- out var instaUri))
- throw new Exception("Cant create search user URI");
- var userUriBuilder = new UriBuilder(instaUri) {Query = $"max_id={maxId}"};
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUriBuilder.Uri, _deviceInfo);
- request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_PHONE_ID,
- _httpRequestProcessor.RequestMessage.phone_id));
- request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE,
- InstaApiConstants.TIMEZONE_OFFSET.ToString()));
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var feedResponse = JsonConvert.DeserializeObject(json,
- new InstaFeedResponseDataConverter());
- return Result.Success(feedResponse);
- }
- return Result.UnExpectedResponse(response, json);
- }
-
- private async Task> GetFollowingActivityWithMaxIdAsync(string maxId)
- {
- var uri = UriCreator.GetFollowingRecentActivityUri(maxId);
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var followingActivity = JsonConvert.DeserializeObject(json,
- new InstaRecentActivityConverter());
- return Result.Success(followingActivity);
- }
- return Result.UnExpectedResponse(response, json);
- }
-
- private async Task> GetUserMediaListWithMaxIdAsync(Uri instaUri)
- {
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var mediaResponse = JsonConvert.DeserializeObject(json,
- new InstaMediaListDataConverter());
- return Result.Success(mediaResponse);
- }
- return Result.Fail("", (InstaMediaListResponse) null);
- }
-
- private async Task> GetUserListByURIAsync(Uri uri)
- {
- ValidateUser();
- try
- {
- if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated");
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var instaUserListResponse = JsonConvert.DeserializeObject(json);
- if (!instaUserListResponse.IsOk()) Result.Fail("", (InstaUserListShortResponse) null);
- return Result.Success(instaUserListResponse);
- }
- return Result.UnExpectedResponse(response, json);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, (InstaUserListShortResponse) null);
- }
- }
-
- private async Task> GetRecentActivityInternalAsync(Uri uri, int maxPages = 0)
- {
- ValidateLoggedIn();
- if (maxPages == 0) maxPages = int.MaxValue;
-
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request, HttpCompletionOption.ResponseContentRead);
- var activityFeed = new InstaActivityFeed();
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK)
- return Result.UnExpectedResponse(response, json);
- var feedPage = JsonConvert.DeserializeObject(json,
- new InstaRecentActivityConverter());
- activityFeed.IsOwnActivity = feedPage.IsOwnActivity;
- var nextId = feedPage.NextMaxId;
- activityFeed.Items.AddRange(
- feedPage.Stories.Select(ConvertersFabric.GetSingleRecentActivityConverter)
- .Select(converter => converter.Convert()));
- var pages = 1;
- while (!string.IsNullOrEmpty(nextId) && pages < maxPages)
- {
- var nextFollowingFeed = await GetFollowingActivityWithMaxIdAsync(nextId);
- if (!nextFollowingFeed.Succeeded)
- return Result.Success($"Not all pages was downloaded: {nextFollowingFeed.Info.Message}",
- activityFeed);
- nextId = nextFollowingFeed.Value.NextMaxId;
- activityFeed.Items.AddRange(
- feedPage.Stories.Select(ConvertersFabric.GetSingleRecentActivityConverter)
- .Select(converter => converter.Convert()));
- pages++;
- }
- return Result.Success(activityFeed);
- }
-
- private async Task> GetTagFeedWithMaxIdAsync(string tag, string nextId)
- {
- ValidateUser();
- ValidateLoggedIn();
- try
- {
- var instaUri = UriCreator.GetTagFeedUri(tag);
- instaUri = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}.Uri;
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var feedResponse = JsonConvert.DeserializeObject(json,
- new InstaMediaListDataConverter());
- return Result.Success(feedResponse);
- }
- return Result.UnExpectedResponse(response, json);
- }
- catch (Exception exception)
- {
- return Result.Fail(exception.Message, (InstaMediaListResponse) null);
- }
- }
-
- private async Task> GetCommentListWithMaxIdAsync(string mediaId,
- string nextId)
- {
- var commentsUri = UriCreator.GetMediaCommentsUri(mediaId);
- var commentsUriMaxId = new UriBuilder(commentsUri) {Query = $"max_id={nextId}"}.Uri;
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, commentsUriMaxId, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK)
- {
- var comments = JsonConvert.DeserializeObject(json);
- return Result.Success(comments);
- }
- return Result.Fail("", (InstaCommentListResponse) null);
- }
-
- private async Task> FollowUnfollowUserInternal(long userId, Uri instaUri)
- {
- ValidateUser();
- ValidateLoggedIn();
- try
- {
- var fields = new Dictionary
- {
- {"_uuid", _deviceInfo.DeviceGuid.ToString()},
- {"_uid", _user.LoggedInUder.Pk},
- {"_csrftoken", _user.CsrfToken},
- {"user_id", userId.ToString()},
- {"radio_type", "wifi-none"}
- };
- var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(json))
- {
- var friendshipStatus = JsonConvert.DeserializeObject(json,
- new InstaFriendShipDataConverter());
- var converter = ConvertersFabric.GetFriendShipStatusConverter(friendshipStatus);
- return Result.Success(converter.Convert());
- }
- return Result.UnExpectedResponse(response, json);
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, (InstaFriendshipStatus) null);
- }
- }
-
- private async Task> GetExploreFeedAsync(string maxId)
- {
- try
- {
- var exploreUri = UriCreator.GetExploreUri(maxId);
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, exploreUri, _deviceInfo);
- var response = await _httpRequestProcessor.SendAsync(request);
- var json = await response.Content.ReadAsStringAsync();
- if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaExploreFeedResponse) null);
- return Result.Success(
- JsonConvert.DeserializeObject(json, new InstaExploreFeedDataConverter()));
- }
- catch (Exception exception)
- {
- LogException(exception);
- return Result.Fail(exception.Message, (InstaExploreFeedResponse) null);
- }
- }
-
- private void LogException(Exception exception)
- {
- _logger?.LogException(exception);
- }
-
- #endregion
- }
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+using InstaSharper.API.Processors;
+using InstaSharper.Classes;
+using InstaSharper.Classes.Android.DeviceInfo;
+using InstaSharper.Classes.Models;
+using InstaSharper.Classes.ResponseWrappers;
+using InstaSharper.Classes.ResponseWrappers.BaseResponse;
+using InstaSharper.Converters;
+using InstaSharper.Helpers;
+using InstaSharper.Logger;
+using Newtonsoft.Json;
+
+namespace InstaSharper.API
+{
+ internal class InstaApi : IInstaApi
+ {
+ private readonly IHttpRequestProcessor _httpRequestProcessor;
+ private readonly IInstaLogger _logger;
+ private ICollectionProcessor _collectionProcessor;
+ private ICommentProcessor _commentProcessor;
+ private AndroidDevice _deviceInfo;
+ private IFeedProcessor _feedProcessor;
+
+ private IHashtagProcessor _hashtagProcessor;
+ private ILocationProcessor _locationProcessor;
+ private IMediaProcessor _mediaProcessor;
+ private IMessagingProcessor _messagingProcessor;
+ private IUserProfileProcessor _profileProcessor;
+ private IStoryProcessor _storyProcessor;
+
+ private TwoFactorLoginInfo _twoFactorInfo;
+ private InstaChallenge _challengeInfo;
+ private UserSessionData _user;
+ private IUserProcessor _userProcessor;
+
+ public InstaApi(UserSessionData user, IInstaLogger logger, AndroidDevice deviceInfo,
+ IHttpRequestProcessor httpRequestProcessor)
+ {
+ _user = user;
+ _logger = logger;
+ _deviceInfo = deviceInfo;
+ _httpRequestProcessor = httpRequestProcessor;
+ }
+
+ ///
+ /// Get user timeline feed (feed of recent posts from users you follow) asynchronously.
+ ///
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ public async Task> GetUserTimelineFeedAsync(PaginationParameters paginationParameters)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _feedProcessor.GetUserTimelineFeedAsync(paginationParameters);
+ }
+
+ ///
+ /// Get user story reel feed. Contains user info last story including all story items.
+ ///
+ /// User identifier (PK)
+ ///
+ public async Task> GetUserStoryFeedAsync(long userId)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _storyProcessor.GetUserStoryFeedAsync(userId);
+ }
+
+
+ ///
+ /// Get user explore feed (Explore tab info) asynchronously
+ ///
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ /// >
+ ///
+ public async Task> GetExploreFeedAsync(PaginationParameters paginationParameters)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _feedProcessor.GetExploreFeedAsync(paginationParameters);
+ }
+
+ ///
+ /// Get all user media by username asynchronously
+ ///
+ /// Username
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ public async Task> GetUserMediaAsync(string username,
+ PaginationParameters paginationParameters)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ var user = await GetUserAsync(username);
+ if (!user.Succeeded)
+ return Result.Fail("Unable to get user to load media");
+ return await _userProcessor.GetUserMediaAsync(user.Value.Pk, paginationParameters);
+ }
+
+ ///
+ /// Get media by its id asynchronously
+ ///
+ /// Maximum count of pages to retrieve
+ ///
+ ///
+ ///
+ public async Task> GetMediaByIdAsync(string mediaId)
+ {
+ ValidateUser();
+ return await _mediaProcessor.GetMediaByIdAsync(mediaId);
+ }
+
+ ///
+ /// Get user info by its user name asynchronously
+ ///
+ /// Username
+ ///
+ ///
+ ///
+ public async Task> GetUserAsync(string username)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _userProcessor.GetUserAsync(username);
+ }
+
+ ///
+ /// Search users asynchronously
+ ///
+ /// Search pattern e.g. part of username
+ ///
+ /// List of users matches pattern
+ ///
+ ///
+ public async Task> SearchUsersAsync(string searchPattern)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _userProcessor.SearchUsersAsync(searchPattern);
+ }
+
+
+ ///
+ /// Get currently logged in user info asynchronously
+ ///
+ ///
+ ///
+ ///
+ public async Task> GetCurrentUserAsync()
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _userProcessor.GetCurrentUserAsync();
+ }
+
+ ///
+ /// Get tag feed by tag value asynchronously
+ ///
+ /// Tag value
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ public async Task> GetTagFeedAsync(string tag, PaginationParameters paginationParameters)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _feedProcessor.GetTagFeedAsync(tag, paginationParameters);
+ }
+
+ ///
+ /// Get followers list by username asynchronously
+ ///
+ /// Username
+ /// Pagination parameters: next id and max amount of pages to load
+ /// Search string to locate specific followers
+ ///
+ ///
+ ///
+ public async Task> GetUserFollowersAsync(string username,
+ PaginationParameters paginationParameters, string searchQuery = "")
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _userProcessor.GetUserFollowersAsync(username, paginationParameters, searchQuery);
+ }
+
+ ///
+ /// Get following list by username asynchronously
+ ///
+ /// Username
+ /// Pagination parameters: next id and max amount of pages to load
+ /// Search string to locate specific followings
+ ///
+ ///
+ ///
+ public async Task> GetUserFollowingAsync(string username,
+ PaginationParameters paginationParameters, string searchQuery = "")
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _userProcessor.GetUserFollowingAsync(username, paginationParameters, searchQuery);
+ }
+
+ ///
+ /// Gets the user extended information (followers count, following count, bio, etc) by user identifier.
+ ///
+ /// User Id, like "123123123"
+ ///
+ public async Task> GetUserInfoByIdAsync(long pk)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _userProcessor.GetUserInfoByIdAsync(pk);
+ }
+
+ ///
+ /// Gets the user extended information (followers count, following count, bio, etc) by username.
+ ///
+ /// Username, like "instagram"
+ ///
+ public async Task> GetUserInfoByUsernameAsync(string username)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _userProcessor.GetUserInfoByUsernameAsync(username);
+ }
+
+ ///
+ /// Send link as a message
+ ///
+ /// Direct message (link + description)
+ /// Array of recipients, user pk like "123123123"
+ /// Affected threads
+ public async Task> SendLinkMessage(InstaMessageLink message,
+ params long[] recipients)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _messagingProcessor.SendLinkMessage(message, recipients);
+ }
+
+ ///
+ /// Send link as a message
+ ///
+ /// Direct message (link + description)
+ /// Array of threads, thread id like "111182366841710300949128137443944311111"
+ /// Affected threads
+ public async Task> SendLinkMessage(InstaMessageLink message,
+ params string[] threads)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _messagingProcessor.SendLinkMessage(message, threads);
+ }
+
+ ///
+ /// Send media as a message
+ ///
+ /// Media id, like "1166111111128767752_1111111"
+ /// Type of media (photo/video)
+ /// Array of threads, thread id like "111182366841710300949128137443944311111"
+ /// Affected threads
+ public async Task> ShareMedia(string mediaId, InstaMediaType mediaType,
+ params string[] threads)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _messagingProcessor.ShareMedia(mediaId, mediaType, threads);
+ }
+
+ ///
+ /// Decline ALL pending threads
+ ///
+ /// Status response
+ public async Task> DeclineAllPendingDirectThreads()
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _messagingProcessor.DeclineAllPendingDirectThreads();
+ }
+
+ ///
+ /// Approve single thread by id
+ ///
+ /// Thread id, e.g. "111182366841710300949128137443944311111"
+ /// Status response
+ public async Task> ApprovePendingDirectThread(string threadId)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _messagingProcessor.ApprovePendingDirectThread(threadId);
+ }
+
+ ///
+ /// Get followers list for currently logged in user asynchronously
+ ///
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ public async Task> GetCurrentUserFollowersAsync(
+ PaginationParameters paginationParameters)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _userProcessor.GetCurrentUserFollowersAsync(paginationParameters);
+ }
+
+ ///
+ /// Get following list for currently logged in user asynchronously
+ ///
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ public async Task> GetCurrentUserFollowingAsync(
+ PaginationParameters paginationParameters)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _userProcessor.GetCurrentUserFollowingAsync(paginationParameters);
+ }
+
+ ///
+ /// Get user tags by username asynchronously
+ /// Returns media list containing tags
+ ///
+ /// Username
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ public async Task> GetUserTagsAsync(string username,
+ PaginationParameters paginationParameters)
+ {
+ ValidateUser();
+ ValidateLoggedIn();
+ var user = await GetUserAsync(username);
+ if (!user.Succeeded)
+ return Result.Fail($"Unable to get user {username} to get tags", (InstaMediaList) null);
+ return await _userProcessor.GetUserTagsAsync(user.Value.Pk, paginationParameters);
+ }
+
+
+ ///
+ /// Get direct inbox threads for current user asynchronously
+ ///
+ ///
+ ///