From c492218a8534cea1812f4535408e5b00f6a44d25 Mon Sep 17 00:00:00 2001 From: Baris Ceviz Date: Fri, 7 Jun 2019 10:46:52 +0300 Subject: [PATCH] Add get and load state as base64 --- InstaSharper/API/IInstaApi.cs | 1272 ++++----- InstaSharper/API/InstaApi.cs | 2754 ++++++++++--------- InstaSharper/Helpers/SerializationHelper.cs | 27 +- 3 files changed, 2061 insertions(+), 1992 deletions(-) diff --git a/InstaSharper/API/IInstaApi.cs b/InstaSharper/API/IInstaApi.cs index 536da5e7..5ac14e2e 100644 --- a/InstaSharper/API/IInstaApi.cs +++ b/InstaSharper/API/IInstaApi.cs @@ -1,631 +1,643 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using InstaSharper.Classes; -using InstaSharper.Classes.Models; -using InstaSharper.Classes.ResponseWrappers; -using InstaSharper.Classes.ResponseWrappers.BaseResponse; - -namespace InstaSharper.API -{ - public interface IInstaApi - { - #region Properties - - /// - /// Indicates whether user authenticated or not - /// - bool IsUserAuthenticated { get; } - - #endregion - - /// - /// Get current state info as Memory stream - /// - /// State data - Stream GetStateDataAsStream(); - - /// - /// Set state data from provided stream - /// - void LoadStateDataFromStream(Stream data); - - #region Async Members - - /// - /// Create a new instagram account - /// - /// Username - /// Password - /// Email - /// First name (optional) - /// - Task> CreateNewAccount(string username, string password, string email, - string firstName); - - /// - /// Login using given credentials asynchronously - /// - /// - /// Success --> 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 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 - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; + +namespace InstaSharper.API +{ + public interface IInstaApi + { + #region Properties + + /// + /// Indicates whether user authenticated or not + /// + bool IsUserAuthenticated { get; } + + #endregion + + /// + /// Get current state info as Memory stream + /// + /// State data + Stream GetStateDataAsStream(); + + /// + /// Get current state info as Base64 + /// + /// State data + string GetStateDataAsBase64(); + + /// + /// Set state data from provided stream + /// + void LoadStateDataFromStream(Stream data); + + /// + /// Loads the state data from Base64. + /// + /// The base64 string. + void LoadStateDataFromBase64(string base64); + + #region Async Members + + /// + /// Create a new instagram account + /// + /// Username + /// Password + /// Email + /// First name (optional) + /// + Task> CreateNewAccount(string username, string password, string email, + string firstName); + + /// + /// Login using given credentials asynchronously + /// + /// + /// Success --> 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 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 71b1dd47..9b5192b3 100644 --- a/InstaSharper/API/InstaApi.cs +++ b/InstaSharper/API/InstaApi.cs @@ -1,1362 +1,1394 @@ -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 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 - /// - /// - /// - /// - public async Task> GetDirectInboxAsync() - { - ValidateUser(); - ValidateLoggedIn(); - return await _messagingProcessor.GetDirectInboxAsync(); - } - - /// - /// Get direct inbox thread by its id asynchronously - /// - /// Thread id - /// - /// - /// - public async Task> GetDirectInboxThreadAsync(string threadId) - { - ValidateUser(); - ValidateLoggedIn(); - return await _messagingProcessor.GetDirectInboxThreadAsync(threadId); - } - - /// - /// Send direct message to provided users and threads - /// - /// Comma-separated users PK - /// Message thread ids - /// Message text - /// - /// List of threads - /// - public async Task> SendDirectMessage(string recipients, string threadIds, - string text) - { - ValidateUser(); - ValidateLoggedIn(); - return await _messagingProcessor.SendDirectMessage(recipients, threadIds, text); - } - - /// - /// Get recent recipients (threads and users) asynchronously - /// - /// - /// - /// - public async Task> GetRecentRecipientsAsync() - { - ValidateUser(); - ValidateLoggedIn(); - return await _messagingProcessor.GetRecentRecipientsAsync(); - } - - /// - /// Get ranked recipients (threads and users) asynchronously - /// - /// - /// - /// - public async Task> GetRankedRecipientsAsync() - { - ValidateUser(); - ValidateLoggedIn(); - return await _messagingProcessor.GetRankedRecipientsAsync(); - } - - /// - /// Get recent activity info asynchronously - /// - /// Pagination parameters: next id and max amount of pages to load - /// - /// - /// - public async Task> GetRecentActivityAsync(PaginationParameters paginationParameters) - { - return await _feedProcessor.GetRecentActivityFeedAsync(paginationParameters); - } - - /// - /// Get activity of following asynchronously - /// - /// - /// - /// - /// - public async Task> GetFollowingRecentActivityAsync( - PaginationParameters paginationParameters) - { - return await _feedProcessor.GetFollowingRecentActivityFeedAsync(paginationParameters); - } - - - /// - /// Like media (photo or video) - /// - /// Media id - /// - public async Task> LikeMediaAsync(string mediaId) - { - return await _mediaProcessor.LikeMediaAsync(mediaId); - } - - /// - /// Remove like from media (photo or video) - /// - /// Media id - /// - public async Task> UnLikeMediaAsync(string mediaId) - { - return await _mediaProcessor.UnLikeMediaAsync(mediaId); - } - - - /// - /// Get media comments - /// - /// Media id - /// Maximum amount of pages to load and start id - /// - public async Task> GetMediaCommentsAsync(string mediaId, - PaginationParameters paginationParameters) - { - ValidateUser(); - ValidateLoggedIn(); - - return await _commentProcessor.GetMediaCommentsAsync(mediaId, paginationParameters); - } - - /// - /// Get users (short) who liked certain media. Normaly it return around 1000 last users. - /// - /// Media id - /// - public async Task> GetMediaLikersAsync(string mediaId) - { - ValidateUser(); - ValidateLoggedIn(); - return await _mediaProcessor.GetMediaLikersAsync(mediaId); - } - - /// - /// Follow user - /// - /// User id - /// - public async Task> FollowUserAsync(long userId) - { - return await _userProcessor.FollowUserAsync(userId); - } - - /// - /// Stop follow user - /// - /// User id - /// - public async Task> UnFollowUserAsync(long userId) - { - return await _userProcessor.UnFollowUserAsync(userId); - } - - - /// - /// Block user - /// - /// User id - /// - public async Task> BlockUserAsync(long userId) - { - return await _userProcessor.BlockUserAsync(userId); - } - - /// - /// Stop Block user - /// - /// User id - /// - public async Task> UnBlockUserAsync(long userId) - { - return await _userProcessor.UnBlockUserAsync(userId); - } - - /// - /// Set current account private - /// - /// - public async Task> SetAccountPrivateAsync() - { - ValidateUser(); - ValidateLoggedIn(); - return await _profileProcessor.SetAccountPrivateAsync(); - } - - /// - /// Set current account public - /// - /// - public async Task> SetAccountPublicAsync() - { - ValidateUser(); - ValidateLoggedIn(); - return await _profileProcessor.SetAccountPublicAsync(); - } - - - /// - /// Comment media - /// - /// Media id - /// Comment text - /// - public async Task> CommentMediaAsync(string mediaId, string text) - { - ValidateUser(); - ValidateLoggedIn(); - return await _commentProcessor.CommentMediaAsync(mediaId, text); - } - - /// - /// Delete comment from media - /// - /// Media id - /// Comment id - /// - public async Task> DeleteCommentAsync(string mediaId, string commentId) - { - ValidateUser(); - ValidateLoggedIn(); - return await _commentProcessor.DeleteCommentAsync(mediaId, commentId); - } - - /// - /// Upload video - /// - /// Video to upload - /// Image thumbnail - /// Caption - /// - public async Task> UploadVideoAsync(InstaVideo video, InstaImage imageThumbnail, - string caption) - { - ValidateUser(); - ValidateLoggedIn(); - - return await _mediaProcessor.UploadVideoAsync(video, imageThumbnail, caption); - } - - /// - /// Upload photo - /// - /// Photo to upload - /// Caption - /// - public async Task> UploadPhotoAsync(InstaImage image, string caption) - { - ValidateUser(); - ValidateLoggedIn(); - return await _mediaProcessor.UploadPhotoAsync(image, caption); - } - - /// - /// Upload photo - /// - /// Array of photos to upload - /// Caption - /// - public async Task> UploadPhotosAlbumAsync(InstaImage[] images, string caption) - { - ValidateUser(); - ValidateLoggedIn(); - return await _mediaProcessor.UploadPhotosAlbumAsync(images, caption); - } - - /// - /// Configure photo - /// - /// Photo to configure - /// Upload id - /// Caption - /// - public async Task> ConfigurePhotoAsync(InstaImage image, string uploadId, string caption) - { - ValidateUser(); - ValidateLoggedIn(); - return await _mediaProcessor.ConfigurePhotoAsync(image, uploadId, caption); - } - - /// - /// Configure photos for Album - /// - /// Array of upload IDs to configure - /// /// - /// Caption - /// - public async Task> ConfigureAlbumAsync(string[] uploadIds, string caption) - { - ValidateUser(); - ValidateLoggedIn(); - return await _mediaProcessor.ConfigureAlbumAsync(uploadIds, caption); - } - - - /// - /// Get user story feed (stories from users followed by current user). - /// - /// - public async Task> GetStoryFeedAsync() - { - ValidateUser(); - ValidateLoggedIn(); - return await _storyProcessor.GetStoryFeedAsync(); - } - - /// - /// Get the story by userId - /// - /// User Id - /// - public async Task> GetUserStoryAsync(long userId) - { - ValidateUser(); - ValidateLoggedIn(); - return await _storyProcessor.GetUserStoryAsync(userId); - } - - /// - /// Upload story photo - /// - /// Photo to upload - /// Caption - /// - public async Task> UploadStoryPhotoAsync(InstaImage image, string caption) - { - ValidateUser(); - ValidateLoggedIn(); - return await _storyProcessor.UploadStoryPhotoAsync(image, caption); - } - - /// - /// Configure story photo - /// - /// Photo to configure - /// Upload id - /// Caption - /// - public async Task> ConfigureStoryPhotoAsync(InstaImage image, string uploadId, - string caption) - { - ValidateUser(); - ValidateLoggedIn(); - return await _storyProcessor.ConfigureStoryPhotoAsync(image, uploadId, 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 - /// - public async Task> ChangePasswordAsync(string oldPassword, string newPassword) - { - ValidateUser(); - ValidateLoggedIn(); - return await _profileProcessor.ChangePasswordAsync(oldPassword, newPassword); - } - - /// - /// Delete a media (photo or video) - /// - /// The media ID - /// The type of the media - /// - /// Return true if the media is deleted - /// - public async Task> DeleteMediaAsync(string mediaId, InstaMediaType mediaType) - { - ValidateUser(); - ValidateLoggedIn(); - return await _mediaProcessor.DeleteMediaAsync(mediaId, mediaType); - } - - /// - /// Edit the caption of the media (photo/video) - /// - /// The media ID - /// The new caption - /// - /// Return true if everything is ok - /// - public async Task> EditMediaAsync(string mediaId, string caption) - { - ValidateUser(); - ValidateLoggedIn(); - return await _mediaProcessor.EditMediaAsync(mediaId, caption); - } - - /// - /// Get feed of media your liked. - /// - /// Pagination parameters: next id and max amount of pages to load - /// - /// - /// - public async Task> GetLikeFeedAsync(PaginationParameters paginationParameters) - { - ValidateUser(); - return await _feedProcessor.GetLikeFeedAsync(paginationParameters); - } - - /// - /// Get friendship status for given user id. - /// - /// User identifier (PK) - /// - /// - /// - public async Task> GetFriendshipStatusAsync(long userId) - { - ValidateUser(); - ValidateLoggedIn(); - return await _userProcessor.GetFriendshipStatusAsync(userId); - } - - /// - /// Get your collection for given collection id - /// - /// Collection ID - /// - /// - /// - public async Task> GetCollectionAsync(long collectionId) - { - ValidateUser(); - ValidateLoggedIn(); - return await _collectionProcessor.GetCollectionAsync(collectionId); - } - - - /// - /// Get your collections - /// - /// - /// - /// - public async Task> GetCollectionsAsync() - { - ValidateUser(); - ValidateLoggedIn(); - return await _collectionProcessor.GetCollectionsAsync(); - } - - /// - /// Create a new collection - /// - /// The name of the new collection - /// - /// - /// - public async Task> CreateCollectionAsync(string collectionName) - { - ValidateUser(); - ValidateLoggedIn(); - return await _collectionProcessor.CreateCollectionAsync(collectionName); - } - - public async Task> AddItemsToCollectionAsync(long collectionId, - params string[] mediaIds) - { - ValidateUser(); - ValidateLoggedIn(); - return await _collectionProcessor.AddItemsToCollectionAsync(collectionId, mediaIds); - } - - /// - /// Delete your collection for given collection id - /// - /// Collection ID to delete - /// true if succeed - public async Task> DeleteCollectionAsync(long collectionId) - { - ValidateUser(); - ValidateLoggedIn(); - return await _collectionProcessor.DeleteCollectionAsync(collectionId); - } - - /// - /// Get media ID from an url (got from "share link") - /// - /// Uri to get media ID - /// Media ID - public async Task> GetMediaIdFromUrlAsync(Uri uri) - { - ValidateLoggedIn(); - ValidateRequestMessage(); - return await _mediaProcessor.GetMediaIdFromUrlAsync(uri); - } - - /// - /// Get share link from media Id - /// - /// media ID - /// Share link as Uri - public async Task> GetShareLinkFromMediaIdAsync(string mediaId) - { - return await _mediaProcessor.GetShareLinkFromMediaIdAsync(mediaId); - } - - /// - /// Searches for specific location by provided geo-data or search query. - /// - /// Latitude - /// Longitude - /// Search query - /// - /// List of locations (short format) - /// - public async Task> SearchLocation(double latitude, double longitude, - string query) - { - ValidateUser(); - ValidateLoggedIn(); - return await _locationProcessor.Search(latitude, longitude, query); - } - - /// - /// Gets the feed of particular location. - /// - /// Location identifier - /// Pagination parameters: next id and max amount of pages to load - /// - /// Location feed - /// - public async Task> GetLocationFeed(long locationId, - PaginationParameters paginationParameters) - { - ValidateUser(); - ValidateLoggedIn(); - return await _locationProcessor.GetFeed(locationId, 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 - /// - public async Task> SearchHashtag(string query, IEnumerable excludeList, - string rankToken) - { - ValidateUser(); - ValidateLoggedIn(); - return await _hashtagProcessor.Search(query, excludeList, rankToken); - } - - /// - /// Gets the hashtag information by user tagname. - /// - /// Tagname - /// Hashtag information - public async Task> GetHashtagInfo(string tagname) - { - ValidateUser(); - ValidateLoggedIn(); - return await _hashtagProcessor.GetHashtagInfo(tagname); - } - - #region Authentication/State data - - /// - /// Indicates whether user authenticated or not - /// - public bool IsUserAuthenticated { get; private set; } - - /// - /// Create a new instagram account - /// - /// Username - /// Password - /// Email - /// First name (optional) - /// - public async Task> CreateNewAccount(string username, string password, string email, - string firstName) - { - try - { - var postData = new Dictionary - { - {"email", email}, - {"username", username}, - {"password", password}, - {"device_id", ApiRequestMessage.GenerateDeviceId()}, - {"guid", _deviceInfo.DeviceGuid.ToString()}, - {"first_name", firstName} - }; - - var instaUri = UriCreator.GetCreateAccountUri(); - var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, postData); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - return response.StatusCode != HttpStatusCode.OK - ? Result.UnExpectedResponse(response, json) - : Result.Success(JsonConvert.DeserializeObject(json)); - } - catch (Exception exception) - { - _logger?.LogException(exception); - return Result.Fail(exception); - } - } - - /// - /// Login using given credentials asynchronously - /// - /// - /// Success --> is succeed - /// TwoFactorRequired --> requires 2FA login. - /// BadPassword --> Password is wrong - /// InvalidUser --> User/phone number is wrong - /// Exception --> Something wrong happened - /// - public async Task> LoginAsync() - { - ValidateUser(); - ValidateRequestMessage(); - try - { - var firstResponse = await _httpRequestProcessor.GetAsync(_httpRequestProcessor.Client.BaseAddress); - var cookies = - _httpRequestProcessor.HttpHandler.CookieContainer.GetCookies(_httpRequestProcessor.Client - .BaseAddress); - _logger?.LogResponse(firstResponse); - var csrftoken = cookies[InstaApiConstants.CSRFTOKEN]?.Value ?? string.Empty; - _user.CsrfToken = csrftoken; - var instaUri = UriCreator.GetLoginUri(); - var signature = - $"{_httpRequestProcessor.RequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}.{_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 - ) //If the password is correct BUT 2-Factor Authentication is enabled, it will still get a 400 error (bad request) - { - //Then check it - var loginFailReason = JsonConvert.DeserializeObject(json); - - if (loginFailReason.InvalidCredentials) - return Result.Fail("Invalid Credentials", - loginFailReason.ErrorType == "bad_password" - ? InstaLoginResult.BadPassword - : InstaLoginResult.InvalidUser); - if (loginFailReason.TwoFactorRequired) - { - _twoFactorInfo = loginFailReason.TwoFactorLoginInfo; - //2FA is required! - return Result.Fail("Two Factor Authentication is required", InstaLoginResult.TwoFactorRequired); - } - if (loginFailReason.ChallengeRequired) - { - _challengeInfo = loginFailReason.Challenge; - //Challenge is Required! - return Result.Fail("Challenge is required", InstaLoginResult.ChallengeRequired); - } - - return Result.UnExpectedResponse(response, json); - } - - var loginInfo = JsonConvert.DeserializeObject(json); - IsUserAuthenticated = loginInfo.User?.UserName.ToLower() == _user.UserName.ToLower(); - var converter = ConvertersFabric.Instance.GetUserShortConverter(loginInfo.User); - _user.LoggedInUder = converter.Convert(); - _user.RankToken = $"{_user.LoggedInUder.Pk}_{_httpRequestProcessor.RequestMessage.phone_id}"; - return Result.Success(InstaLoginResult.Success); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception, InstaLoginResult.Exception); - } - finally - { - InvalidateProcessors(); - } - } - - /// - /// Search Place - /// - public async Task> SearchPlace(string searchQuery, int count) - { - var signature = - $"{_httpRequestProcessor.RequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}" + - $".{_httpRequestProcessor.RequestMessage.GetMessageString()}"; - var fbSeachPlaceUri = UriCreator.GetFbSearchPlace(count, _user.RankToken, searchQuery); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, fbSeachPlaceUri, _deviceInfo); - 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(); - var fbSeachPlaceResponse = JsonConvert.DeserializeObject(json); - return Result.Success(fbSeachPlaceResponse); - } - - /// - /// Reset challenge asynchronously - /// - public async Task> ResetChallenge() - { - var signature = - $"{_httpRequestProcessor.RequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}" + - $".{_httpRequestProcessor.RequestMessage.GetMessageString()}"; - var fields = new Dictionary - { - {InstaApiConstants.HEADER_IG_SIGNATURE, signature}, - {InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION} - }; - var token = _challengeInfo.ApiPath.Substring(11); - var instaUri = UriCreator.GetResetChallengeUri(token); - 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(); - var resetChallengeResponse = JsonConvert.DeserializeObject(json); - return Result.Success(resetChallengeResponse); - } - - /// - /// Get verify method asynchronously - /// - public async Task> GetVerifyStep() - { - var signature = - $"{_httpRequestProcessor.RequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}" + - $".{_httpRequestProcessor.RequestMessage.GetMessageString()}"; - var token = _challengeInfo.ApiPath.Substring(11); - var instaUri = UriCreator.GetVerifyMethod(token); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); - 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(); - var resetChallengeResponse = JsonConvert.DeserializeObject(json); - return Result.Success(resetChallengeResponse); - } - - /// - /// Choose verify method asynchronously - /// - public async Task> ChooseVerifyMethod(int choice) - { - var signature = - $"{_httpRequestProcessor.RequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}" + - $".{_httpRequestProcessor.RequestMessage.GetMessageString()}"; - var fields = new Dictionary - { - {InstaApiConstants.VEFITY_CHOICE, choice.ToString()}, - }; - var token = _challengeInfo.ApiPath.Substring(11); - var instaUri = UriCreator.GetVerifyMethod(token); - 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(); - var resetChallengeResponse = JsonConvert.DeserializeObject(json); - return Result.Success(resetChallengeResponse); - } - - /// - /// Send verify code asynchronously - /// - public async Task> SendVerifyCode(string securityCode) - { - var signature = - $"{_httpRequestProcessor.RequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}" + - $".{_httpRequestProcessor.RequestMessage.GetMessageString()}"; - var fields = new Dictionary - { - {InstaApiConstants.SECURITY_CODE, securityCode.ToString()}, - }; - var token = _challengeInfo.ApiPath.Substring(11); - var instaUri = UriCreator.GetVerifyMethod(token); - 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.Fail("invalid verify code"); - } - var sendVerifyCodeResponse = JsonConvert.DeserializeObject(json); - IsUserAuthenticated = sendVerifyCodeResponse.LoggedInUser?.UserName.ToLower() == _user.UserName.ToLower(); - var converter = ConvertersFabric.Instance.GetUserShortConverter(sendVerifyCodeResponse.LoggedInUser); - _user.LoggedInUder = converter.Convert(); - _user.RankToken = $"{_user.LoggedInUder.Pk}_{_httpRequestProcessor.RequestMessage.phone_id}"; - return Result.Success(sendVerifyCodeResponse); - } - - /// - /// 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 - /// - public async Task> TwoFactorLoginAsync(string verificationCode) - { - if (_twoFactorInfo == null) - return Result.Fail("Run LoginAsync first"); - - try - { - var twoFactorRequestMessage = new ApiTwoFactorRequestMessage(verificationCode, - _httpRequestProcessor.RequestMessage.username, - _httpRequestProcessor.RequestMessage.device_id, - _twoFactorInfo.TwoFactorIdentifier); - - var instaUri = UriCreator.GetTwoFactorLoginUri(); - var signature = - $"{twoFactorRequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}.{twoFactorRequestMessage.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) - { - var loginInfo = - JsonConvert.DeserializeObject(json); - IsUserAuthenticated = IsUserAuthenticated = - loginInfo.User != null && loginInfo.User.UserName.ToLower() == _user.UserName.ToLower(); - var converter = ConvertersFabric.Instance.GetUserShortConverter(loginInfo.User); - _user.LoggedInUder = converter.Convert(); - _user.RankToken = $"{_user.LoggedInUder.Pk}_{_httpRequestProcessor.RequestMessage.phone_id}"; - - return Result.Success(InstaLoginTwoFactorResult.Success); - } - - var loginFailReason = JsonConvert.DeserializeObject(json); - - if (loginFailReason.ErrorType == "sms_code_validation_code_invalid") - return Result.Fail("Please check the security code.", InstaLoginTwoFactorResult.InvalidCode); - return Result.Fail("This code is no longer valid, please, call LoginAsync again to request a new one", - InstaLoginTwoFactorResult.CodeExpired); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception, InstaLoginTwoFactorResult.Exception); - } - } - - /// - /// Get Two Factor Authentication details - /// - /// - /// An instance of TwoFactorInfo 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 - /// - public async Task> GetTwoFactorInfoAsync() - { - return await Task.Run(() => - _twoFactorInfo != null - ? Result.Success(_twoFactorInfo) - : Result.Fail("No Two Factor info available.")); - } - - /// - /// Logout from instagram asynchronously - /// - /// - /// True if logged out without errors - /// - 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); - if (logoutInfo.Status == "ok") - IsUserAuthenticated = false; - return Result.Success(!IsUserAuthenticated); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception, false); - } - } - - /// - /// Get current state info as Memory stream - /// - /// - /// State data - /// - public Stream GetStateDataAsStream() - { - var state = new StateData - { - DeviceInfo = _deviceInfo, - IsAuthenticated = IsUserAuthenticated, - UserSession = _user, - Cookies = _httpRequestProcessor.HttpHandler.CookieContainer - }; - return SerializationHelper.SerializeToStream(state); - } - - /// - /// Loads the state data from stream. - /// - /// The stream. - public void LoadStateDataFromStream(Stream stream) - { - var data = SerializationHelper.DeserializeFromStream(stream); - _deviceInfo = data.DeviceInfo; - _user = data.UserSession; - _httpRequestProcessor.HttpHandler.CookieContainer = data.Cookies; - IsUserAuthenticated = data.IsAuthenticated; - InvalidateProcessors(); - } - - #endregion - - - #region private part - - private void InvalidateProcessors() - { - _hashtagProcessor = new HashtagProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); - _locationProcessor = new LocationProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); - _collectionProcessor = new CollectionProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); - _mediaProcessor = new MediaProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); - _userProcessor = new UserProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); - _storyProcessor = new StoryProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); - _commentProcessor = new CommentProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); - _profileProcessor = new UserProfileProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); - _messagingProcessor = new MessagingProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); - _feedProcessor = new FeedProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); - } - - 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 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 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 + /// + /// + /// + /// + public async Task> GetDirectInboxAsync() + { + ValidateUser(); + ValidateLoggedIn(); + return await _messagingProcessor.GetDirectInboxAsync(); + } + + /// + /// Get direct inbox thread by its id asynchronously + /// + /// Thread id + /// + /// + /// + public async Task> GetDirectInboxThreadAsync(string threadId) + { + ValidateUser(); + ValidateLoggedIn(); + return await _messagingProcessor.GetDirectInboxThreadAsync(threadId); + } + + /// + /// Send direct message to provided users and threads + /// + /// Comma-separated users PK + /// Message thread ids + /// Message text + /// + /// List of threads + /// + public async Task> SendDirectMessage(string recipients, string threadIds, + string text) + { + ValidateUser(); + ValidateLoggedIn(); + return await _messagingProcessor.SendDirectMessage(recipients, threadIds, text); + } + + /// + /// Get recent recipients (threads and users) asynchronously + /// + /// + /// + /// + public async Task> GetRecentRecipientsAsync() + { + ValidateUser(); + ValidateLoggedIn(); + return await _messagingProcessor.GetRecentRecipientsAsync(); + } + + /// + /// Get ranked recipients (threads and users) asynchronously + /// + /// + /// + /// + public async Task> GetRankedRecipientsAsync() + { + ValidateUser(); + ValidateLoggedIn(); + return await _messagingProcessor.GetRankedRecipientsAsync(); + } + + /// + /// Get recent activity info asynchronously + /// + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + public async Task> GetRecentActivityAsync(PaginationParameters paginationParameters) + { + return await _feedProcessor.GetRecentActivityFeedAsync(paginationParameters); + } + + /// + /// Get activity of following asynchronously + /// + /// + /// + /// + /// + public async Task> GetFollowingRecentActivityAsync( + PaginationParameters paginationParameters) + { + return await _feedProcessor.GetFollowingRecentActivityFeedAsync(paginationParameters); + } + + + /// + /// Like media (photo or video) + /// + /// Media id + /// + public async Task> LikeMediaAsync(string mediaId) + { + return await _mediaProcessor.LikeMediaAsync(mediaId); + } + + /// + /// Remove like from media (photo or video) + /// + /// Media id + /// + public async Task> UnLikeMediaAsync(string mediaId) + { + return await _mediaProcessor.UnLikeMediaAsync(mediaId); + } + + + /// + /// Get media comments + /// + /// Media id + /// Maximum amount of pages to load and start id + /// + public async Task> GetMediaCommentsAsync(string mediaId, + PaginationParameters paginationParameters) + { + ValidateUser(); + ValidateLoggedIn(); + + return await _commentProcessor.GetMediaCommentsAsync(mediaId, paginationParameters); + } + + /// + /// Get users (short) who liked certain media. Normaly it return around 1000 last users. + /// + /// Media id + /// + public async Task> GetMediaLikersAsync(string mediaId) + { + ValidateUser(); + ValidateLoggedIn(); + return await _mediaProcessor.GetMediaLikersAsync(mediaId); + } + + /// + /// Follow user + /// + /// User id + /// + public async Task> FollowUserAsync(long userId) + { + return await _userProcessor.FollowUserAsync(userId); + } + + /// + /// Stop follow user + /// + /// User id + /// + public async Task> UnFollowUserAsync(long userId) + { + return await _userProcessor.UnFollowUserAsync(userId); + } + + + /// + /// Block user + /// + /// User id + /// + public async Task> BlockUserAsync(long userId) + { + return await _userProcessor.BlockUserAsync(userId); + } + + /// + /// Stop Block user + /// + /// User id + /// + public async Task> UnBlockUserAsync(long userId) + { + return await _userProcessor.UnBlockUserAsync(userId); + } + + /// + /// Set current account private + /// + /// + public async Task> SetAccountPrivateAsync() + { + ValidateUser(); + ValidateLoggedIn(); + return await _profileProcessor.SetAccountPrivateAsync(); + } + + /// + /// Set current account public + /// + /// + public async Task> SetAccountPublicAsync() + { + ValidateUser(); + ValidateLoggedIn(); + return await _profileProcessor.SetAccountPublicAsync(); + } + + + /// + /// Comment media + /// + /// Media id + /// Comment text + /// + public async Task> CommentMediaAsync(string mediaId, string text) + { + ValidateUser(); + ValidateLoggedIn(); + return await _commentProcessor.CommentMediaAsync(mediaId, text); + } + + /// + /// Delete comment from media + /// + /// Media id + /// Comment id + /// + public async Task> DeleteCommentAsync(string mediaId, string commentId) + { + ValidateUser(); + ValidateLoggedIn(); + return await _commentProcessor.DeleteCommentAsync(mediaId, commentId); + } + + /// + /// Upload video + /// + /// Video to upload + /// Image thumbnail + /// Caption + /// + public async Task> UploadVideoAsync(InstaVideo video, InstaImage imageThumbnail, + string caption) + { + ValidateUser(); + ValidateLoggedIn(); + + return await _mediaProcessor.UploadVideoAsync(video, imageThumbnail, caption); + } + + /// + /// Upload photo + /// + /// Photo to upload + /// Caption + /// + public async Task> UploadPhotoAsync(InstaImage image, string caption) + { + ValidateUser(); + ValidateLoggedIn(); + return await _mediaProcessor.UploadPhotoAsync(image, caption); + } + + /// + /// Upload photo + /// + /// Array of photos to upload + /// Caption + /// + public async Task> UploadPhotosAlbumAsync(InstaImage[] images, string caption) + { + ValidateUser(); + ValidateLoggedIn(); + return await _mediaProcessor.UploadPhotosAlbumAsync(images, caption); + } + + /// + /// Configure photo + /// + /// Photo to configure + /// Upload id + /// Caption + /// + public async Task> ConfigurePhotoAsync(InstaImage image, string uploadId, string caption) + { + ValidateUser(); + ValidateLoggedIn(); + return await _mediaProcessor.ConfigurePhotoAsync(image, uploadId, caption); + } + + /// + /// Configure photos for Album + /// + /// Array of upload IDs to configure + /// /// + /// Caption + /// + public async Task> ConfigureAlbumAsync(string[] uploadIds, string caption) + { + ValidateUser(); + ValidateLoggedIn(); + return await _mediaProcessor.ConfigureAlbumAsync(uploadIds, caption); + } + + + /// + /// Get user story feed (stories from users followed by current user). + /// + /// + public async Task> GetStoryFeedAsync() + { + ValidateUser(); + ValidateLoggedIn(); + return await _storyProcessor.GetStoryFeedAsync(); + } + + /// + /// Get the story by userId + /// + /// User Id + /// + public async Task> GetUserStoryAsync(long userId) + { + ValidateUser(); + ValidateLoggedIn(); + return await _storyProcessor.GetUserStoryAsync(userId); + } + + /// + /// Upload story photo + /// + /// Photo to upload + /// Caption + /// + public async Task> UploadStoryPhotoAsync(InstaImage image, string caption) + { + ValidateUser(); + ValidateLoggedIn(); + return await _storyProcessor.UploadStoryPhotoAsync(image, caption); + } + + /// + /// Configure story photo + /// + /// Photo to configure + /// Upload id + /// Caption + /// + public async Task> ConfigureStoryPhotoAsync(InstaImage image, string uploadId, + string caption) + { + ValidateUser(); + ValidateLoggedIn(); + return await _storyProcessor.ConfigureStoryPhotoAsync(image, uploadId, 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 + /// + public async Task> ChangePasswordAsync(string oldPassword, string newPassword) + { + ValidateUser(); + ValidateLoggedIn(); + return await _profileProcessor.ChangePasswordAsync(oldPassword, newPassword); + } + + /// + /// Delete a media (photo or video) + /// + /// The media ID + /// The type of the media + /// + /// Return true if the media is deleted + /// + public async Task> DeleteMediaAsync(string mediaId, InstaMediaType mediaType) + { + ValidateUser(); + ValidateLoggedIn(); + return await _mediaProcessor.DeleteMediaAsync(mediaId, mediaType); + } + + /// + /// Edit the caption of the media (photo/video) + /// + /// The media ID + /// The new caption + /// + /// Return true if everything is ok + /// + public async Task> EditMediaAsync(string mediaId, string caption) + { + ValidateUser(); + ValidateLoggedIn(); + return await _mediaProcessor.EditMediaAsync(mediaId, caption); + } + + /// + /// Get feed of media your liked. + /// + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + public async Task> GetLikeFeedAsync(PaginationParameters paginationParameters) + { + ValidateUser(); + return await _feedProcessor.GetLikeFeedAsync(paginationParameters); + } + + /// + /// Get friendship status for given user id. + /// + /// User identifier (PK) + /// + /// + /// + public async Task> GetFriendshipStatusAsync(long userId) + { + ValidateUser(); + ValidateLoggedIn(); + return await _userProcessor.GetFriendshipStatusAsync(userId); + } + + /// + /// Get your collection for given collection id + /// + /// Collection ID + /// + /// + /// + public async Task> GetCollectionAsync(long collectionId) + { + ValidateUser(); + ValidateLoggedIn(); + return await _collectionProcessor.GetCollectionAsync(collectionId); + } + + + /// + /// Get your collections + /// + /// + /// + /// + public async Task> GetCollectionsAsync() + { + ValidateUser(); + ValidateLoggedIn(); + return await _collectionProcessor.GetCollectionsAsync(); + } + + /// + /// Create a new collection + /// + /// The name of the new collection + /// + /// + /// + public async Task> CreateCollectionAsync(string collectionName) + { + ValidateUser(); + ValidateLoggedIn(); + return await _collectionProcessor.CreateCollectionAsync(collectionName); + } + + public async Task> AddItemsToCollectionAsync(long collectionId, + params string[] mediaIds) + { + ValidateUser(); + ValidateLoggedIn(); + return await _collectionProcessor.AddItemsToCollectionAsync(collectionId, mediaIds); + } + + /// + /// Delete your collection for given collection id + /// + /// Collection ID to delete + /// true if succeed + public async Task> DeleteCollectionAsync(long collectionId) + { + ValidateUser(); + ValidateLoggedIn(); + return await _collectionProcessor.DeleteCollectionAsync(collectionId); + } + + /// + /// Get media ID from an url (got from "share link") + /// + /// Uri to get media ID + /// Media ID + public async Task> GetMediaIdFromUrlAsync(Uri uri) + { + ValidateLoggedIn(); + ValidateRequestMessage(); + return await _mediaProcessor.GetMediaIdFromUrlAsync(uri); + } + + /// + /// Get share link from media Id + /// + /// media ID + /// Share link as Uri + public async Task> GetShareLinkFromMediaIdAsync(string mediaId) + { + return await _mediaProcessor.GetShareLinkFromMediaIdAsync(mediaId); + } + + /// + /// Searches for specific location by provided geo-data or search query. + /// + /// Latitude + /// Longitude + /// Search query + /// + /// List of locations (short format) + /// + public async Task> SearchLocation(double latitude, double longitude, + string query) + { + ValidateUser(); + ValidateLoggedIn(); + return await _locationProcessor.Search(latitude, longitude, query); + } + + /// + /// Gets the feed of particular location. + /// + /// Location identifier + /// Pagination parameters: next id and max amount of pages to load + /// + /// Location feed + /// + public async Task> GetLocationFeed(long locationId, + PaginationParameters paginationParameters) + { + ValidateUser(); + ValidateLoggedIn(); + return await _locationProcessor.GetFeed(locationId, 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 + /// + public async Task> SearchHashtag(string query, IEnumerable excludeList, + string rankToken) + { + ValidateUser(); + ValidateLoggedIn(); + return await _hashtagProcessor.Search(query, excludeList, rankToken); + } + + /// + /// Gets the hashtag information by user tagname. + /// + /// Tagname + /// Hashtag information + public async Task> GetHashtagInfo(string tagname) + { + ValidateUser(); + ValidateLoggedIn(); + return await _hashtagProcessor.GetHashtagInfo(tagname); + } + + #region Authentication/State data + + /// + /// Indicates whether user authenticated or not + /// + public bool IsUserAuthenticated { get; private set; } + + /// + /// Create a new instagram account + /// + /// Username + /// Password + /// Email + /// First name (optional) + /// + public async Task> CreateNewAccount(string username, string password, string email, + string firstName) + { + try + { + var postData = new Dictionary + { + {"email", email}, + {"username", username}, + {"password", password}, + {"device_id", ApiRequestMessage.GenerateDeviceId()}, + {"guid", _deviceInfo.DeviceGuid.ToString()}, + {"first_name", firstName} + }; + + var instaUri = UriCreator.GetCreateAccountUri(); + var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, postData); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + return response.StatusCode != HttpStatusCode.OK + ? Result.UnExpectedResponse(response, json) + : Result.Success(JsonConvert.DeserializeObject(json)); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + /// + /// Login using given credentials asynchronously + /// + /// + /// Success --> is succeed + /// TwoFactorRequired --> requires 2FA login. + /// BadPassword --> Password is wrong + /// InvalidUser --> User/phone number is wrong + /// Exception --> Something wrong happened + /// + public async Task> LoginAsync() + { + ValidateUser(); + ValidateRequestMessage(); + try + { + var firstResponse = await _httpRequestProcessor.GetAsync(_httpRequestProcessor.Client.BaseAddress); + var cookies = + _httpRequestProcessor.HttpHandler.CookieContainer.GetCookies(_httpRequestProcessor.Client + .BaseAddress); + _logger?.LogResponse(firstResponse); + var csrftoken = cookies[InstaApiConstants.CSRFTOKEN]?.Value ?? string.Empty; + _user.CsrfToken = csrftoken; + var instaUri = UriCreator.GetLoginUri(); + var signature = + $"{_httpRequestProcessor.RequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}.{_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 + ) //If the password is correct BUT 2-Factor Authentication is enabled, it will still get a 400 error (bad request) + { + //Then check it + var loginFailReason = JsonConvert.DeserializeObject(json); + + if (loginFailReason.InvalidCredentials) + return Result.Fail("Invalid Credentials", + loginFailReason.ErrorType == "bad_password" + ? InstaLoginResult.BadPassword + : InstaLoginResult.InvalidUser); + if (loginFailReason.TwoFactorRequired) + { + _twoFactorInfo = loginFailReason.TwoFactorLoginInfo; + //2FA is required! + return Result.Fail("Two Factor Authentication is required", InstaLoginResult.TwoFactorRequired); + } + if (loginFailReason.ChallengeRequired) + { + _challengeInfo = loginFailReason.Challenge; + //Challenge is Required! + return Result.Fail("Challenge is required", InstaLoginResult.ChallengeRequired); + } + + return Result.UnExpectedResponse(response, json); + } + + var loginInfo = JsonConvert.DeserializeObject(json); + IsUserAuthenticated = loginInfo.User?.UserName.ToLower() == _user.UserName.ToLower(); + var converter = ConvertersFabric.Instance.GetUserShortConverter(loginInfo.User); + _user.LoggedInUder = converter.Convert(); + _user.RankToken = $"{_user.LoggedInUder.Pk}_{_httpRequestProcessor.RequestMessage.phone_id}"; + return Result.Success(InstaLoginResult.Success); + } + catch (Exception exception) + { + LogException(exception); + return Result.Fail(exception, InstaLoginResult.Exception); + } + finally + { + InvalidateProcessors(); + } + } + + /// + /// Search Place + /// + public async Task> SearchPlace(string searchQuery, int count) + { + var signature = + $"{_httpRequestProcessor.RequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}" + + $".{_httpRequestProcessor.RequestMessage.GetMessageString()}"; + var fbSeachPlaceUri = UriCreator.GetFbSearchPlace(count, _user.RankToken, searchQuery); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, fbSeachPlaceUri, _deviceInfo); + 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(); + var fbSeachPlaceResponse = JsonConvert.DeserializeObject(json); + return Result.Success(fbSeachPlaceResponse); + } + + /// + /// Reset challenge asynchronously + /// + public async Task> ResetChallenge() + { + var signature = + $"{_httpRequestProcessor.RequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}" + + $".{_httpRequestProcessor.RequestMessage.GetMessageString()}"; + var fields = new Dictionary + { + {InstaApiConstants.HEADER_IG_SIGNATURE, signature}, + {InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION} + }; + var token = _challengeInfo.ApiPath.Substring(11); + var instaUri = UriCreator.GetResetChallengeUri(token); + 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(); + var resetChallengeResponse = JsonConvert.DeserializeObject(json); + return Result.Success(resetChallengeResponse); + } + + /// + /// Get verify method asynchronously + /// + public async Task> GetVerifyStep() + { + var signature = + $"{_httpRequestProcessor.RequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}" + + $".{_httpRequestProcessor.RequestMessage.GetMessageString()}"; + var token = _challengeInfo.ApiPath.Substring(11); + var instaUri = UriCreator.GetVerifyMethod(token); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); + 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(); + var resetChallengeResponse = JsonConvert.DeserializeObject(json); + return Result.Success(resetChallengeResponse); + } + + /// + /// Choose verify method asynchronously + /// + public async Task> ChooseVerifyMethod(int choice) + { + var signature = + $"{_httpRequestProcessor.RequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}" + + $".{_httpRequestProcessor.RequestMessage.GetMessageString()}"; + var fields = new Dictionary + { + {InstaApiConstants.VEFITY_CHOICE, choice.ToString()}, + }; + var token = _challengeInfo.ApiPath.Substring(11); + var instaUri = UriCreator.GetVerifyMethod(token); + 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(); + var resetChallengeResponse = JsonConvert.DeserializeObject(json); + return Result.Success(resetChallengeResponse); + } + + /// + /// Send verify code asynchronously + /// + public async Task> SendVerifyCode(string securityCode) + { + var signature = + $"{_httpRequestProcessor.RequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}" + + $".{_httpRequestProcessor.RequestMessage.GetMessageString()}"; + var fields = new Dictionary + { + {InstaApiConstants.SECURITY_CODE, securityCode.ToString()}, + }; + var token = _challengeInfo.ApiPath.Substring(11); + var instaUri = UriCreator.GetVerifyMethod(token); + 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.Fail("invalid verify code"); + } + var sendVerifyCodeResponse = JsonConvert.DeserializeObject(json); + IsUserAuthenticated = sendVerifyCodeResponse.LoggedInUser?.UserName.ToLower() == _user.UserName.ToLower(); + var converter = ConvertersFabric.Instance.GetUserShortConverter(sendVerifyCodeResponse.LoggedInUser); + _user.LoggedInUder = converter.Convert(); + _user.RankToken = $"{_user.LoggedInUder.Pk}_{_httpRequestProcessor.RequestMessage.phone_id}"; + return Result.Success(sendVerifyCodeResponse); + } + + /// + /// 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 + /// + public async Task> TwoFactorLoginAsync(string verificationCode) + { + if (_twoFactorInfo == null) + return Result.Fail("Run LoginAsync first"); + + try + { + var twoFactorRequestMessage = new ApiTwoFactorRequestMessage(verificationCode, + _httpRequestProcessor.RequestMessage.username, + _httpRequestProcessor.RequestMessage.device_id, + _twoFactorInfo.TwoFactorIdentifier); + + var instaUri = UriCreator.GetTwoFactorLoginUri(); + var signature = + $"{twoFactorRequestMessage.GenerateSignature(InstaApiConstants.IG_SIGNATURE_KEY)}.{twoFactorRequestMessage.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) + { + var loginInfo = + JsonConvert.DeserializeObject(json); + IsUserAuthenticated = IsUserAuthenticated = + loginInfo.User != null && loginInfo.User.UserName.ToLower() == _user.UserName.ToLower(); + var converter = ConvertersFabric.Instance.GetUserShortConverter(loginInfo.User); + _user.LoggedInUder = converter.Convert(); + _user.RankToken = $"{_user.LoggedInUder.Pk}_{_httpRequestProcessor.RequestMessage.phone_id}"; + + return Result.Success(InstaLoginTwoFactorResult.Success); + } + + var loginFailReason = JsonConvert.DeserializeObject(json); + + if (loginFailReason.ErrorType == "sms_code_validation_code_invalid") + return Result.Fail("Please check the security code.", InstaLoginTwoFactorResult.InvalidCode); + return Result.Fail("This code is no longer valid, please, call LoginAsync again to request a new one", + InstaLoginTwoFactorResult.CodeExpired); + } + catch (Exception exception) + { + LogException(exception); + return Result.Fail(exception, InstaLoginTwoFactorResult.Exception); + } + } + + /// + /// Get Two Factor Authentication details + /// + /// + /// An instance of TwoFactorInfo 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 + /// + public async Task> GetTwoFactorInfoAsync() + { + return await Task.Run(() => + _twoFactorInfo != null + ? Result.Success(_twoFactorInfo) + : Result.Fail("No Two Factor info available.")); + } + + /// + /// Logout from instagram asynchronously + /// + /// + /// True if logged out without errors + /// + 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); + if (logoutInfo.Status == "ok") + IsUserAuthenticated = false; + return Result.Success(!IsUserAuthenticated); + } + catch (Exception exception) + { + LogException(exception); + return Result.Fail(exception, false); + } + } + + /// + /// Get current state info as Base64 + /// + /// + /// State data as string + /// + public string GetStateDataAsBase64() + { + var state = new StateData + { + DeviceInfo = _deviceInfo, + IsAuthenticated = IsUserAuthenticated, + UserSession = _user, + Cookies = _httpRequestProcessor.HttpHandler.CookieContainer + }; + return SerializationHelper.SerializeToBase64(state); + } + + /// + /// Get current state info as Memory stream + /// + /// + /// State data + /// + public Stream GetStateDataAsStream() + { + var state = new StateData + { + DeviceInfo = _deviceInfo, + IsAuthenticated = IsUserAuthenticated, + UserSession = _user, + Cookies = _httpRequestProcessor.HttpHandler.CookieContainer + }; + return SerializationHelper.SerializeToStream(state); + } + + /// + /// Loads the state data from stream. + /// + /// The stream. + public void LoadStateDataFromStream(Stream stream) + { + var data = SerializationHelper.DeserializeFromStream(stream); + _deviceInfo = data.DeviceInfo; + _user = data.UserSession; + _httpRequestProcessor.HttpHandler.CookieContainer = data.Cookies; + IsUserAuthenticated = data.IsAuthenticated; + InvalidateProcessors(); + } + + /// + /// Loads the state data from Base64. + /// + /// The base64 string. + public void LoadStateDataFromBase64(string base64) + { + var data = SerializationHelper.DeserializeFromBase64(base64); + _deviceInfo = data.DeviceInfo; + _user = data.UserSession; + _httpRequestProcessor.HttpHandler.CookieContainer = data.Cookies; + IsUserAuthenticated = data.IsAuthenticated; + InvalidateProcessors(); + } + + #endregion + + + #region private part + + private void InvalidateProcessors() + { + _hashtagProcessor = new HashtagProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); + _locationProcessor = new LocationProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); + _collectionProcessor = new CollectionProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); + _mediaProcessor = new MediaProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); + _userProcessor = new UserProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); + _storyProcessor = new StoryProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); + _commentProcessor = new CommentProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); + _profileProcessor = new UserProfileProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); + _messagingProcessor = new MessagingProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); + _feedProcessor = new FeedProcessor(_deviceInfo, _user, _httpRequestProcessor, _logger); + } + + 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 void LogException(Exception exception) + { + _logger?.LogException(exception); + } + + #endregion + } } \ No newline at end of file diff --git a/InstaSharper/Helpers/SerializationHelper.cs b/InstaSharper/Helpers/SerializationHelper.cs index d4deec2d..1c05c710 100644 --- a/InstaSharper/Helpers/SerializationHelper.cs +++ b/InstaSharper/Helpers/SerializationHelper.cs @@ -1,5 +1,7 @@ -using System.IO; +using System; +using System.IO; using System.Runtime.Serialization.Formatters.Binary; +using InstaSharper.Classes; namespace InstaSharper.Helpers { @@ -20,5 +22,28 @@ public static T DeserializeFromStream(Stream stream) var fromStream = formatter.Deserialize(stream); return (T) fromStream; } + + public static string SerializeToBase64(StateData o) + { + using (var stream = new MemoryStream()) + { + var formatter = new BinaryFormatter(); + formatter.Serialize(stream, o); + stream.Flush(); + stream.Position = 0; + return Convert.ToBase64String(stream.ToArray()); + } + } + + public static T DeserializeFromBase64(string base64) + { + byte[] b = Convert.FromBase64String(base64); + using (var stream = new MemoryStream(b)) + { + var formatter = new BinaryFormatter(); + stream.Seek(0, SeekOrigin.Begin); + return (T) formatter.Deserialize(stream); + } + } } } \ No newline at end of file