diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..f34ede58 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,40 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Before creating issue** +Put `x` marks below to validate what you've done before posting issue. + +[ ] I've checked [FAQ](https://github.com/a-legotin/InstaSharper/wiki/FAQ) +[ ] I've checked [wiki page](https://github.com/a-legotin/InstaSharper/wiki) +[ ] I've examined [examples project](https://github.com/a-legotin/InstaSharper/tree/develop/InstaSharper.Examples) +[ ] I've did search [existing issues](https://github.com/a-legotin/InstaSharper/issues) for similar problems +[ ] I've understand that issue will be closed and locked if issue related to `checkpoint, challenge, feedback required` or `sentry_block` or `signup_block`- see [FAQ](https://github.com/a-legotin/InstaSharper/wiki/FAQ) + +## Be warned - issue will be closed if none from above is done before posting issue. + +**Describe the issue** +A clear and concise description of what the issue is. +Attach logs ([How to use logger to get logs](https://github.com/a-legotin/InstaSharper/blob/develop/InstaSharper.Examples/Program.cs)). + Provide state of [Info](https://github.com/a-legotin/InstaSharper/blob/develop/InstaSharper/Classes/ResultInfo.cs) property when you got [IResult response](https://github.com/a-legotin/InstaSharper/blob/develop/InstaSharper/Classes/Result.cs). + +**To Reproduce** +How can I reproduce the problem: +1. Attach code snippet +2. Push sample project to github and add link here. +3. What actions is causing issue. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Target (please complete the following information):** + - Platform: [e.g. Windows, Linux] + - Target framework [e.g. netstandard, net452] + - Version [e.g. 1.4.50] + +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 00000000..2e2b2883 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,32 @@ +--- +name: Question +about: Describe question here + +--- + +**Before creating issue** +Put `x` marks below to validate what you've done before posting issue. + +[ ] I've checked [FAQ](https://github.com/a-legotin/InstaSharper/wiki/FAQ) +[ ] I've checked [wiki page](https://github.com/a-legotin/InstaSharper/wiki) +[ ] I've examined [examples project](https://github.com/a-legotin/InstaSharper/tree/develop/InstaSharper.Examples) +[ ] I've did search [existing issues](https://github.com/a-legotin/InstaSharper/issues) for similar problems +[ ] I've understand that issue will be closed and locked if issue related to `checkpoint, challenge, feedback required` or `sentry_block` or `signup_block`- see [FAQ](https://github.com/a-legotin/InstaSharper/wiki/FAQ) + +## Be warned - issue will be closed if none from above is done before posting issue. + +**Describe the issue** +A clear and concise description of your question + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Target (please complete the following information):** + - Platform: [e.g. Windows, Linux] + - Target framework [e.g. netstandard, net452] + - Version [e.g. 1.4.50] + +Add any other context about the problem here. diff --git a/.gitignore b/.gitignore index 4e1cd4a5..ec658c42 100644 --- a/.gitignore +++ b/.gitignore @@ -262,4 +262,8 @@ paket-files/ # Python Tools for Visual Studio (PTVS) __pycache__/ -*.pyc \ No newline at end of file +*.pyc + +# binary files and texts notes +**/*.bin +**/*.txt \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 378c022b..0facdd32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,12 @@ language: csharp -dist: trusty +dist: bionic language: csharp mono: none -dotnet: 2.0.0 +dotnet: 3.0.1 solution: InstaSharper.sln script: - cd InstaSharper - dotnet --info - dotnet restore - - dotnet build --framework netstandard2.0 + - dotnet build --framework netstandard2.1 diff --git a/InstaSharper.Examples/InstaSharper.Examples.csproj b/InstaSharper.Examples/InstaSharper.Examples.csproj index 02341bb4..e3593096 100644 --- a/InstaSharper.Examples/InstaSharper.Examples.csproj +++ b/InstaSharper.Examples/InstaSharper.Examples.csproj @@ -34,10 +34,6 @@ 4 - - False - ..\InstaSharper\bin\release\net452\InstaSharper.dll - packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll @@ -52,10 +48,12 @@ + + @@ -67,6 +65,12 @@ + + + {dada2751-e331-4231-9434-7141b6b2fe79} + InstaSharper + + is succeed + /// TwoFactorRequired --> requires 2FA login. + /// BadPassword --> Password is wrong + /// InvalidUser --> User/phone number is wrong + /// Exception --> Something wrong happened + /// + Task> LoginAsync(); + + /// + /// Search Place + /// + Task> SearchPlace(string searchQuery, int count = 5); + + + /// + /// Reset challenge asynchronously + /// + Task> ResetChallenge(); + + /// + /// Get verify method asynchronously + /// + Task> GetVerifyStep(); + + /// + /// Choose verify method asynchronously + /// + Task> ChooseVerifyMethod(int choice); + + /// + /// Send verify code asynchronously + /// + Task> SendVerifyCode(string securityCode); + + /// + /// 2-Factor Authentication Login using a verification code + /// Before call this method, please run LoginAsync first. + /// + /// Verification Code sent to your phone number + /// + /// Success --> is succeed + /// InvalidCode --> The code is invalid + /// CodeExpired --> The code is expired, please request a new one. + /// Exception --> Something wrong happened + /// + Task> TwoFactorLoginAsync(string verificationCode); + + /// + /// Get Two Factor Authentication details + /// + /// + /// An instance of TwoFactorLoginInfo if success. + /// A null reference if not success; in this case, do LoginAsync first and check if Two Factor Authentication is + /// required, if not, don't run this method + /// + Task> GetTwoFactorInfoAsync(); + + /// + /// Logout from instagram asynchronously + /// + /// True if logged out without errors + Task> LogoutAsync(); + + /// + /// Get user timeline feed (feed of recent posts from users you follow) asynchronously. + /// + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + Task> GetUserTimelineFeedAsync(PaginationParameters paginationParameters); + + /// + /// Get user explore feed (Explore tab info) asynchronously + /// + /// Pagination parameters: next id and max amount of pages to load + /// > + Task> GetExploreFeedAsync(PaginationParameters paginationParameters); + + /// + /// Get all user media by username asynchronously + /// + /// Username + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + Task> GetUserMediaAsync(string username, PaginationParameters paginationParameters); + + /// + /// Get media by its id asynchronously + /// + /// Maximum count of pages to retrieve + /// + /// + /// + Task> GetMediaByIdAsync(string mediaId); + + /// + /// Get user info by its user name asynchronously + /// + /// Username + /// + /// + /// + Task> GetUserAsync(string username); + + /// + /// Search users asynchronously + /// + /// Search pattern e.g. part of username + /// + /// List of users matches pattern + /// + /// + Task> SearchUsersAsync(string searchPattern); + + /// + /// Get currently logged in user info asynchronously + /// + /// + /// + /// + Task> GetCurrentUserAsync(); + + /// + /// Get tag feed by tag value asynchronously + /// + /// Tag value + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + Task> GetTagFeedAsync(string tag, PaginationParameters paginationParameters); + + /// + /// Get followers list by username asynchronously + /// + /// Username + /// Pagination parameters: next id and max amount of pages to load + /// Search string to locate specific followers + /// + /// + /// + Task> GetUserFollowersAsync(string username, + PaginationParameters paginationParameters, string searchQuery = ""); + + /// + /// Get following list by username asynchronously + /// + /// Username + /// Pagination parameters: next id and max amount of pages to load + /// Search string to locate specific followings + /// + /// + /// + Task> GetUserFollowingAsync(string username, + PaginationParameters paginationParameters, string searchQuery = ""); + + /// + /// Get followers list for currently logged in user asynchronously + /// + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + Task> GetCurrentUserFollowersAsync(PaginationParameters paginationParameters); + + /// + /// Get following list for currently logged in user asynchronously + /// + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + Task> GetCurrentUserFollowingAsync(PaginationParameters paginationParameters); + + /// + /// Get user tags by username asynchronously + /// Returns media list containing tags + /// + /// Username + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + Task> GetUserTagsAsync(string username, PaginationParameters paginationParameters); + + /// + /// Get direct inbox threads for current user asynchronously + /// + /// + /// + /// + Task> GetDirectInboxAsync(); + + /// + /// Get direct inbox thread by its id asynchronously + /// + /// Thread id + /// + /// + /// + Task> GetDirectInboxThreadAsync(string threadId); + + /// + /// Send direct message to provided users and threads + /// + /// Comma-separated users PK + /// Message thread ids + /// Message text + /// List of threads + Task> SendDirectMessage(string recipients, string threadIds, string text); + + /// + /// Get recent recipients (threads and users) asynchronously + /// + /// + /// + /// + Task> GetRecentRecipientsAsync(); + + /// + /// Get ranked recipients (threads and users) asynchronously + /// + /// + /// + /// + Task> GetRankedRecipientsAsync(); + + /// + /// Get recent activity info asynchronously + /// + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + Task> GetRecentActivityAsync(PaginationParameters paginationParameters); + + /// + /// Get activity of following asynchronously + /// + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + Task> GetFollowingRecentActivityAsync(PaginationParameters paginationParameters); + + /// + /// Like media (photo or video) + /// + /// Media id + Task> LikeMediaAsync(string mediaId); + + /// + /// Remove like from media (photo or video) + /// + /// Media id + Task> UnLikeMediaAsync(string mediaId); + + /// + /// Follow user + /// + /// User id + Task> FollowUserAsync(long userId); + + /// + /// Stop follow user + /// + /// User id + Task> UnFollowUserAsync(long userId); + + /// + /// Block user + /// + /// User id + Task> BlockUserAsync(long userId); + + /// + /// Stop block user + /// + /// User id + Task> UnBlockUserAsync(long userId); + + /// + /// Get media comments + /// + /// Media id + /// Pagination parameters: next id and max amount of pages to load + Task> + GetMediaCommentsAsync(string mediaId, PaginationParameters paginationParameters); + + /// + /// Get users (short) who liked certain media. Normaly it return around 1000 last users. + /// + /// Media id + Task> GetMediaLikersAsync(string mediaId); + + /// + /// Set current account private + /// + Task> SetAccountPrivateAsync(); + + /// + /// Set current account public + /// + Task> SetAccountPublicAsync(); + + /// + /// Comment media + /// + /// Media id + /// Comment text + Task> CommentMediaAsync(string mediaId, string text); + + /// + /// Delete comment from media + /// + /// Media id + /// Comment id + Task> DeleteCommentAsync(string mediaId, string commentId); + + /// + /// Upload video + /// + /// Video to upload + /// Image thumbnail + /// Caption + /// + Task> UploadVideoAsync(InstaVideo video, InstaImage imageThumbnail, string caption); + + /// + /// Upload photo + /// + /// Photo to upload + /// Caption + Task> UploadPhotoAsync(InstaImage image, string caption); + + /// + /// Upload photo + /// + /// Array of photos to upload + /// Caption + /// + Task> UploadPhotosAlbumAsync(InstaImage[] images, string caption); + + /// + /// Configure photo + /// + /// Photo to configure + /// Upload id + /// Caption + /// + Task> ConfigurePhotoAsync(InstaImage image, string uploadId, string caption); + + /// + /// Configure photos for Album + /// + /// Array of upload IDs to configure + /// /// + /// Caption + /// + Task> ConfigureAlbumAsync(string[] uploadId, string caption); + + /// + /// Get user story feed (stories from users followed by current user). + /// + Task> GetStoryFeedAsync(); + + /// + /// Get the story by userId + /// + /// User Id + Task> GetUserStoryAsync(long userId); + + /// + /// Upload story photo + /// + /// Photo to upload + /// Caption + Task> UploadStoryPhotoAsync(InstaImage image, string caption); + + /// + /// Configure story photo + /// + /// Photo to configure + /// Upload id + /// Caption + /// + Task> ConfigureStoryPhotoAsync(InstaImage image, string uploadId, string caption); + + /// + /// Change password + /// + /// The old password + /// + /// The new password (shouldn't be the same old password, and should be a password you never used + /// here) + /// + /// Return true if the password is changed + Task> ChangePasswordAsync(string oldPassword, string newPassword); + + /// + /// Delete a media (photo or video) + /// + /// The media ID + /// The type of the media + /// Return true if the media is deleted + Task> DeleteMediaAsync(string mediaId, InstaMediaType mediaType); + + /// + /// Edit the caption of the media (photo/video) + /// + /// The media ID + /// The new caption + /// Return true if everything is ok + Task> EditMediaAsync(string mediaId, string caption); + + /// + /// Get feed of media your liked. + /// + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + Task> GetLikeFeedAsync(PaginationParameters paginationParameters); + + /// + /// Get friendship status for given user id. + /// + /// User identifier (PK) + /// + /// + /// + Task> GetFriendshipStatusAsync(long userId); + + /// + /// Get user story reel feed. Contains user info last story including all story items. + /// + /// User identifier (PK) + /// + Task> GetUserStoryFeedAsync(long userId); + + /// + /// Get your collection for given collection id + /// + /// Collection ID + /// + /// + /// + Task> GetCollectionAsync(long collectionId); + + /// + /// Get your collections + /// + /// + /// + /// + Task> GetCollectionsAsync(); + + /// + /// Create a new collection + /// + /// The name of the new collection + /// + /// + /// + Task> CreateCollectionAsync(string collectionName); + + /// + /// Delete your collection for given collection id + /// + /// Collection ID to delete + /// true if succeed + Task> DeleteCollectionAsync(long collectionId); + + /// + /// Get media ID from an url (got from "share link") + /// + /// Uri to get media ID + /// Media ID + Task> GetMediaIdFromUrlAsync(Uri uri); + + /// + /// Get share link from media Id + /// + /// media ID + /// Share link as Uri + Task> GetShareLinkFromMediaIdAsync(string mediaId); + + /// + /// Adds items to collection asynchronous. + /// + /// Collection identifier. + /// Media id list. + /// + Task> AddItemsToCollectionAsync(long collectionId, params string[] mediaIds); + + /// + /// Searches for specific location by provided geo-data or search query. + /// + /// Latitude + /// Longitude + /// Search query + /// List of locations (short format) + Task> SearchLocation(double latitude, double longitude, string query); + + /// + /// Gets the feed of particular location. + /// + /// Location identifier + /// Pagination parameters: next id and max amount of pages to load + /// Location feed + Task> GetLocationFeed(long locationId, PaginationParameters paginationParameters); + + /// + /// Searches for specific hashtag by search query. + /// + /// Search query + /// + /// Array of numerical hashtag IDs (ie "17841562498105353") to exclude from the response, + /// allowing you to skip tags from a previous call to get more results + /// + /// The rank token from the previous page's response + /// List of hashtags + Task> SearchHashtag(string query, IEnumerable excludeList = null, + string rankToken = null); + + /// + /// Gets the hashtag information by user tagname. + /// + /// Tagname + /// Hashtag information + Task> GetHashtagInfo(string tagname); + + /// + /// Gets the user extended information (followers count, following count, bio, etc) by user identifier. + /// + /// User Id, like "123123123" + /// + Task> GetUserInfoByIdAsync(long pk); + + /// + /// Gets the user extended information (followers count, following count, bio, etc) by username. + /// + /// Username, like "instagram" + /// + Task> GetUserInfoByUsernameAsync(string username); + + /// + /// Send link as a message + /// + /// Direct message (link + description) + /// Array of recipients, user pk like "123123123" + /// Affected threads + Task> SendLinkMessage(InstaMessageLink message, params long[] recipients); + + /// + /// Send link as a message + /// + /// Direct message (link + description) + /// Array of threads, thread id like "111182366841710300949128137443944311111" + /// Affected threads + Task> SendLinkMessage(InstaMessageLink message, params string[] threads); + + /// + /// Send media as a message + /// + /// Media id, e.g. "1166111111128767752_1111111" + /// Type of media (photo/video) + /// Array of threads, thread id e.g. "111182366841710300949128137443944311111" + /// Affected threads + Task> ShareMedia(string mediaId, InstaMediaType mediaType, + params string[] threads); + + /// + /// Decline ALL pending threads + /// + /// Status response + Task> DeclineAllPendingDirectThreads(); + + /// + /// Approve single thread by id + /// + /// Thread id, e.g. "111182366841710300949128137443944311111" + /// Status response + Task> ApprovePendingDirectThread(string threadId); + #endregion + } } \ No newline at end of file diff --git a/InstaSharper/API/InstaApi.cs b/InstaSharper/API/InstaApi.cs index 0a041f74..e1dc3d91 100644 --- a/InstaSharper/API/InstaApi.cs +++ b/InstaSharper/API/InstaApi.cs @@ -1,1532 +1,1377 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; -using InstaSharper.Classes; -using InstaSharper.Classes.Android.DeviceInfo; -using InstaSharper.Classes.Models; -using InstaSharper.Classes.ResponseWrappers; -using InstaSharper.Classes.ResponseWrappers.BaseResponse; -using InstaSharper.Converters; -using InstaSharper.Converters.Json; -using InstaSharper.Helpers; -using InstaSharper.Logger; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using InstaRecentActivityConverter = InstaSharper.Converters.Json.InstaRecentActivityConverter; - -namespace InstaSharper.API -{ - internal class InstaApi : IInstaApi - { - private readonly IHttpRequestProcessor _httpRequestProcessor; - private readonly IInstaLogger _logger; - private AndroidDevice _deviceInfo; - private UserSessionData _user; - - public InstaApi(UserSessionData user, IInstaLogger logger, AndroidDevice deviceInfo, - IHttpRequestProcessor httpRequestProcessor) - { - _user = user; - _logger = logger; - _deviceInfo = deviceInfo; - _httpRequestProcessor = httpRequestProcessor; - } - - public bool IsUserAuthenticated { get; private set; } - - #region async part - - public async Task> LoginAsync() - { - ValidateUser(); - ValidateRequestMessage(); - try - { - var csrftoken = string.Empty; - var firstResponse = await _httpRequestProcessor.GetAsync(_httpRequestProcessor.Client.BaseAddress); - var cookies = - _httpRequestProcessor.HttpHandler.CookieContainer.GetCookies(_httpRequestProcessor.Client - .BaseAddress); - _logger?.LogResponse(firstResponse); - foreach (Cookie cookie in cookies) - if (cookie.Name == InstaApiConstants.CSRFTOKEN) csrftoken = cookie.Value; - _user.CsrfToken = csrftoken; - var instaUri = UriCreator.GetLoginUri(); - var signature = - $"{_httpRequestProcessor.RequestMessage.GenerateSignature()}.{_httpRequestProcessor.RequestMessage.GetMessageString()}"; - var fields = new Dictionary - { - {InstaApiConstants.HEADER_IG_SIGNATURE, signature}, - {InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, InstaApiConstants.IG_SIGNATURE_KEY_VERSION} - }; - var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); - request.Content = new FormUrlEncodedContent(fields); - request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); - request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, - InstaApiConstants.IG_SIGNATURE_KEY_VERSION); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) return Result.UnExpectedResponse(response, json); - var loginInfo = - JsonConvert.DeserializeObject(json); - IsUserAuthenticated = loginInfo.User != null && loginInfo.User.UserName == _user.UserName; - var converter = ConvertersFabric.GetUserShortConverter(loginInfo.User); - _user.LoggedInUder = converter.Convert(); - _user.RankToken = $"{_user.LoggedInUder.Pk}_{_httpRequestProcessor.RequestMessage.phone_id}"; - return Result.Success(true); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, false); - } - } - - public async Task> LogoutAsync() - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var instaUri = UriCreator.GetLogoutUri(); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) return Result.UnExpectedResponse(response, json); - var logoutInfo = JsonConvert.DeserializeObject(json); - IsUserAuthenticated = logoutInfo.Status == "ok"; - return Result.Success(true); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, false); - } - } - - public async Task> GetUserTimelineFeedAsync(int maxPages = 0) - { - ValidateUser(); - ValidateLoggedIn(); - var userFeedUri = UriCreator.GetUserFeedUri(); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) return Result.UnExpectedResponse(response, json); - var feedResponse = JsonConvert.DeserializeObject(json, - new InstaFeedResponseDataConverter()); - var converter = ConvertersFabric.GetFeedConverter(feedResponse); - var feed = converter.Convert(); - var nextId = feedResponse.NextMaxId; - var moreAvailable = feedResponse.MoreAvailable; - while (moreAvailable && feed.Medias.Pages < maxPages) - { - if (string.IsNullOrEmpty(nextId)) break; - var nextFeed = await GetUserFeedWithMaxIdAsync(nextId); - if (!nextFeed.Succeeded) Result.Success($"Not all pages was downloaded: {nextFeed.Info.Message}", feed); - nextId = nextFeed.Value.NextMaxId; - moreAvailable = nextFeed.Value.MoreAvailable; - feed.Medias.AddRange( - nextFeed.Value.Items.Select(ConvertersFabric.GetSingleMediaConverter) - .Select(conv => conv.Convert())); - feed.Medias.Pages++; - } - return Result.Success(feed); - } - - public async Task> GetUserStoryFeedAsync(long userId) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var userFeedUri = UriCreator.GetUserReelFeedUri(userId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) - return Result.UnExpectedResponse(response, json); - var feedResponse = JsonConvert.DeserializeObject(json); - var feed = ConvertersFabric.GetReelFeedConverter(feedResponse).Convert(); - return Result.Success(feed); - } - catch (Exception exception) - { - return Result.Fail(exception.Message, (InsteReelFeed) null); - } - } - - /// - public Stream GetStateDataAsStream() - { - var state = new StateData - { - DeviceInfo = _deviceInfo, - IsAuthenticated = IsUserAuthenticated, - UserSession = _user, - Cookies = _httpRequestProcessor.HttpHandler.CookieContainer - }; - return SerializationHelper.SerializeToStream(state); - } - - /// - public void LoadStateDataFromStream(Stream stream) - { - var data = SerializationHelper.DeserializeFromStream(stream); - _deviceInfo = data.DeviceInfo; - _user = data.UserSession; - IsUserAuthenticated = data.IsAuthenticated; - _httpRequestProcessor.HttpHandler.CookieContainer = data.Cookies; - } - - public async Task> GetExploreFeedAsync(int maxPages = 0) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - if (maxPages == 0) maxPages = int.MaxValue; - var exploreUri = UriCreator.GetExploreUri(); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, exploreUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaExploreFeed) null); - var feedResponse = JsonConvert.DeserializeObject(json, - new InstaExploreFeedDataConverter()); - var exploreFeed = ConvertersFabric.GetExploreFeedConverter(feedResponse).Convert(); - var nextId = feedResponse.Items.Medias.LastOrDefault(media => !string.IsNullOrEmpty(media.NextMaxId)) - ?.NextMaxId; - while (!string.IsNullOrEmpty(nextId) && exploreFeed.Medias.Pages < maxPages) - { - var nextFeed = await GetExploreFeedAsync(nextId); - if (!nextFeed.Succeeded) - Result.Success($"Not all pages were downloaded: {nextFeed.Info.Message}", exploreFeed); - nextId = feedResponse.Items.Medias.LastOrDefault(media => !string.IsNullOrEmpty(media.NextMaxId)) - ?.NextMaxId; - exploreFeed.Medias.AddRange( - nextFeed.Value.Items.Medias.Select(ConvertersFabric.GetSingleMediaConverter) - .Select(conv => conv.Convert())); - exploreFeed.Medias.Pages++; - } - return Result.Success(exploreFeed); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, (InstaExploreFeed) null); - } - } - - public async Task> GetUserMediaAsync(string username, int maxPages = 0) - { - ValidateUser(); - if (maxPages == 0) maxPages = int.MaxValue; - var user = await GetUserAsync(username); - if (!user.Succeeded) return Result.Fail("Unable to get current user"); - var instaUri = UriCreator.GetUserMediaListUri(user.Value.Pk); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var mediaResponse = JsonConvert.DeserializeObject(json, - new InstaMediaListDataConverter()); - var moreAvailable = mediaResponse.MoreAvailable; - var converter = ConvertersFabric.GetMediaListConverter(mediaResponse); - var mediaList = converter.Convert(); - mediaList.Pages++; - var nextId = mediaResponse.NextMaxId; - while (moreAvailable && mediaList.Pages < maxPages) - { - instaUri = UriCreator.GetMediaListWithMaxIdUri(user.Value.Pk, nextId); - var nextMedia = await GetUserMediaListWithMaxIdAsync(instaUri); - mediaList.Pages++; - if (!nextMedia.Succeeded) - Result.Success($"Not all pages were downloaded: {nextMedia.Info.Message}", mediaList); - nextId = nextMedia.Value.NextMaxId; - moreAvailable = nextMedia.Value.MoreAvailable; - converter = ConvertersFabric.GetMediaListConverter(nextMedia.Value); - mediaList.AddRange(converter.Convert()); - } - return Result.Success(mediaList); - } - return Result.UnExpectedResponse(response, json); - } - - public async Task> GetMediaByIdAsync(string mediaId) - { - ValidateUser(); - var mediaUri = UriCreator.GetMediaUri(mediaId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, mediaUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var mediaResponse = JsonConvert.DeserializeObject(json, - new InstaMediaListDataConverter()); - if (mediaResponse.Medias?.Count != 1) - { - var errorMessage = $"Got wrong media count for request with media id={mediaId}"; - _logger?.LogInfo(errorMessage); - return Result.Fail(errorMessage); - } - var converter = ConvertersFabric.GetSingleMediaConverter(mediaResponse.Medias.FirstOrDefault()); - return Result.Success(converter.Convert()); - } - return Result.UnExpectedResponse(response, json); - } - - public async Task> GetUserAsync(string username) - { - ValidateUser(); - var userUri = UriCreator.GetUserUri(username); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, - InstaApiConstants.TIMEZONE_OFFSET.ToString())); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_COUNT, "1")); - request.Properties.Add( - new KeyValuePair(InstaApiConstants.HEADER_RANK_TOKEN, _user.RankToken)); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var userInfo = JsonConvert.DeserializeObject(json); - var user = userInfo.Users?.FirstOrDefault(u => u.UserName == username); - if (user == null) - { - var errorMessage = $"Can't find this user: {username}"; - _logger?.LogInfo(errorMessage); - return Result.Fail(errorMessage); - } - if (string.IsNullOrEmpty(user.Pk)) - Result.Fail("Pk is null"); - var converter = ConvertersFabric.GetUserConverter(user); - return Result.Success(converter.Convert()); - } - return Result.UnExpectedResponse(response, json); - } - - - public async Task> GetCurrentUserAsync() - { - ValidateUser(); - ValidateLoggedIn(); - var instaUri = UriCreator.GetCurrentUserUri(); - var fields = new Dictionary - { - {"_uuid", _deviceInfo.DeviceGuid.ToString()}, - {"_uid", _user.LoggedInUder.Pk}, - {"_csrftoken", _user.CsrfToken} - }; - var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); - request.Content = new FormUrlEncodedContent(fields); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var user = JsonConvert.DeserializeObject(json, - new InstaCurrentUserDataConverter()); - if (string.IsNullOrEmpty(user.Pk)) - Result.Fail("Pk is null"); - var converter = ConvertersFabric.GetCurrentUserConverter(user); - var userConverted = converter.Convert(); - return Result.Success(userConverted); - } - return Result.UnExpectedResponse(response, json); - } - - public async Task> GetTagFeedAsync(string tag, int maxPages = 0) - { - ValidateUser(); - ValidateLoggedIn(); - if (maxPages == 0) maxPages = int.MaxValue; - var userFeedUri = UriCreator.GetTagFeedUri(tag); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var feedResponse = JsonConvert.DeserializeObject(json, - new InstaTagFeedDataConverter()); - var converter = ConvertersFabric.GetTagFeedConverter(feedResponse); - var tagFeed = converter.Convert(); - tagFeed.Medias.Pages++; - var nextId = feedResponse.NextMaxId; - var moreAvailable = feedResponse.MoreAvailable; - while (moreAvailable && tagFeed.Medias.Pages < maxPages) - { - var nextMedia = await GetTagFeedWithMaxIdAsync(tag, nextId); - tagFeed.Medias.Pages++; - if (!nextMedia.Succeeded) - return Result.Success($"Not all pages was downloaded: {nextMedia.Info.Message}", tagFeed); - nextId = nextMedia.Value.NextMaxId; - moreAvailable = nextMedia.Value.MoreAvailable; - tagFeed.Medias.AddRange(ConvertersFabric.GetMediaListConverter(nextMedia.Value).Convert()); - } - return Result.Success(tagFeed); - } - return Result.UnExpectedResponse(response, json); - } - - public async Task> GetUserFollowersAsync(string username, int maxPages = 0) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - if (maxPages == 0) maxPages = int.MaxValue; - var user = await GetUserAsync(username); - var userFollowersUri = UriCreator.GetUserFollowersUri(user.Value.Pk, _user.RankToken); - var followers = new InstaUserShortList(); - var followersResponse = await GetUserListByURIAsync(userFollowersUri); - if (!followersResponse.Succeeded) - Result.Fail(followersResponse.Info, (InstaUserList) null); - followers.AddRange( - followersResponse.Value.Items.Select(ConvertersFabric.GetUserShortConverter) - .Select(converter => converter.Convert())); - if (!followersResponse.Value.IsBigList) return Result.Success(followers); - var pages = 1; - while (!string.IsNullOrEmpty(followersResponse.Value.NextMaxId) && pages < maxPages) - { - var nextFollowersUri = - UriCreator.GetUserFollowersUri(user.Value.Pk, _user.RankToken, - followersResponse.Value.NextMaxId); - followersResponse = await GetUserListByURIAsync(nextFollowersUri); - if (!followersResponse.Succeeded) - return Result.Success($"Not all pages was downloaded: {followersResponse.Info.Message}", - followers); - followers.AddRange( - followersResponse.Value.Items.Select(ConvertersFabric.GetUserShortConverter) - .Select(converter => converter.Convert())); - pages++; - } - return Result.Success(followers); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, (InstaUserShortList) null); - } - } - - public async Task> GetUserFollowingAsync(string username, int maxPages = 0) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - if (maxPages == 0) maxPages = int.MaxValue; - var user = await GetUserAsync(username); - var userFeedUri = UriCreator.GetUserFollowingUri(user.Value.Pk, _user.RankToken); - var following = new InstaUserShortList(); - var userListResponse = await GetUserListByURIAsync(userFeedUri); - if (!userListResponse.Succeeded) - Result.Fail(userListResponse.Info, following); - following.AddRange( - userListResponse.Value.Items.Select(ConvertersFabric.GetUserShortConverter) - .Select(converter => converter.Convert())); - if (!userListResponse.Value.IsBigList) return Result.Success(following); - var pages = 1; - while (!string.IsNullOrEmpty(userListResponse.Value.NextMaxId) && pages < maxPages) - { - var nextUri = - UriCreator.GetUserFollowingUri(user.Value.Pk, _user.RankToken, - userListResponse.Value.NextMaxId); - userListResponse = await GetUserListByURIAsync(nextUri); - if (!userListResponse.Succeeded) - return Result.Success($"Not all pages was downloaded: {userListResponse.Info.Message}", - following); - following.AddRange( - userListResponse.Value.Items.Select(ConvertersFabric.GetUserShortConverter) - .Select(converter => converter.Convert())); - pages++; - } - return Result.Success(following); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, (InstaUserShortList) null); - } - } - - - public async Task> GetCurrentUserFollowersAsync(int maxPages = 0) - { - ValidateUser(); - return await GetUserFollowersAsync(_user.UserName, maxPages); - } - - public async Task> GetUserTagsAsync(string username, int maxPages = 0) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - if (maxPages == 0) maxPages = int.MaxValue; - var user = await GetUserAsync(username); - if (!user.Succeeded || string.IsNullOrEmpty(user.Value.Pk)) - return Result.Fail($"Unable to get user {username}", (InstaMediaList) null); - var uri = UriCreator.GetUserTagsUri(user.Value?.Pk, _user.RankToken); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - var userTags = new InstaMediaList(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaMediaList) null); - var mediaResponse = JsonConvert.DeserializeObject(json, - new InstaMediaListDataConverter()); - var nextId = mediaResponse.NextMaxId; - userTags.AddRange( - mediaResponse.Medias.Select(ConvertersFabric.GetSingleMediaConverter) - .Select(converter => converter.Convert())); - var pages = 1; - while (!string.IsNullOrEmpty(nextId) && pages < maxPages) - { - uri = UriCreator.GetUserTagsUri(user.Value?.Pk, _user.RankToken, nextId); - var nextMedia = await GetUserMediaListWithMaxIdAsync(uri); - if (!nextMedia.Succeeded) - Result.Success($"Not all pages was downloaded: {nextMedia.Info.Message}", userTags); - nextId = nextMedia.Value.NextMaxId; - userTags.AddRange( - mediaResponse.Medias.Select(ConvertersFabric.GetSingleMediaConverter) - .Select(converter => converter.Convert())); - pages++; - } - return Result.Success(userTags); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, (InstaMediaList) null); - } - } - - - public async Task> GetDirectInboxAsync() - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var directInboxUri = UriCreator.GetDirectInboxUri(); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, directInboxUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaDirectInboxContainer) null); - var inboxResponse = JsonConvert.DeserializeObject(json); - var converter = ConvertersFabric.GetDirectInboxConverter(inboxResponse); - return Result.Success(converter.Convert()); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception); - } - } - - public async Task> GetDirectInboxThreadAsync(string threadId) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var directInboxUri = UriCreator.GetDirectInboxThreadUri(threadId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, directInboxUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaDirectInboxThread) null); - var threadResponse = JsonConvert.DeserializeObject(json, - new InstaThreadDataConverter()); - var converter = ConvertersFabric.GetDirectThreadConverter(threadResponse); - return Result.Success(converter.Convert()); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception); - } - } - - public async Task> SendDirectMessage(string recipients, string threadIds, string text) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var directSendMessageUri = UriCreator.GetDirectSendMessageUri(); - - var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, directSendMessageUri, _deviceInfo); - - var fields = new Dictionary {{"text", text}}; - - if (!string.IsNullOrEmpty(recipients)) - fields.Add("recipient_users", "[[" + recipients + "]]"); - else if (!string.IsNullOrEmpty(threadIds)) - fields.Add("thread_ids", "[" + threadIds + "]"); - else - return Result.Fail("Please provide at least one recipient or thread."); - - request.Content = new FormUrlEncodedContent(fields); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) return Result.UnExpectedResponse(response, json); - var result = JsonConvert.DeserializeObject(json); - return result.IsOk() ? Result.Success(true) : Result.Fail(result.Status); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception); - } - } - - public async Task> GetRecentRecipientsAsync() - { - ValidateUser(); - ValidateLoggedIn(); - var userUri = UriCreator.GetRecentRecipientsUri(); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - - if (response.StatusCode != HttpStatusCode.OK) - return Result.UnExpectedResponse(response, json); - var responseRecipients = JsonConvert.DeserializeObject(json); - var converter = ConvertersFabric.GetRecipientsConverter(responseRecipients); - return Result.Success(converter.Convert()); - } - - public async Task> GetRankedRecipientsAsync() - { - ValidateUser(); - ValidateLoggedIn(); - var userUri = UriCreator.GetRankedRecipientsUri(); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) - return Result.UnExpectedResponse(response, json); - var responseRecipients = JsonConvert.DeserializeObject(json); - var converter = ConvertersFabric.GetRecipientsConverter(responseRecipients); - return Result.Success(converter.Convert()); - } - - public async Task> GetRecentActivityAsync(int maxPages = 0) - { - var uri = UriCreator.GetRecentActivityUri(); - return await GetRecentActivityInternalAsync(uri, maxPages); - } - - public async Task> GetFollowingRecentActivityAsync(int maxPages = 0) - { - var uri = UriCreator.GetFollowingRecentActivityUri(); - return await GetRecentActivityInternalAsync(uri, maxPages); - } - - - public async Task> CheckpointAsync(string checkPointUrl) - { - if (string.IsNullOrEmpty(checkPointUrl)) return Result.Fail("Empty checkpoint URL", false); - var instaUri = new Uri(checkPointUrl); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) return Result.Success(true); - return Result.UnExpectedResponse(response, json); - } - - - public async Task> LikeMediaAsync(string mediaId) - { - return await LikeUnlikeMediaInternal(mediaId, UriCreator.GetLikeMediaUri(mediaId)); - } - - public async Task> UnLikeMediaAsync(string mediaId) - { - return await LikeUnlikeMediaInternal(mediaId, UriCreator.GetUnLikeMediaUri(mediaId)); - } - - - public async Task> LikeUnlikeMediaInternal(string mediaId, Uri instaUri) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var fields = new Dictionary - { - {"_uuid", _deviceInfo.DeviceGuid.ToString()}, - {"_uid", _user.LoggedInUder.Pk}, - {"_csrftoken", _user.CsrfToken}, - {"media_id", mediaId} - }; - var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - return Result.Success(true); - return Result.UnExpectedResponse(response, json); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, false); - } - } - - public async Task> GetMediaCommentsAsync(string mediaId, int maxPages = 0) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - if (maxPages == 0) maxPages = int.MaxValue; - var commentsUri = UriCreator.GetMediaCommentsUri(mediaId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, commentsUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) - return Result.Fail($"Unexpected response status: {response.StatusCode}", (InstaCommentList) null); - var commentListResponse = JsonConvert.DeserializeObject(json); - var converter = ConvertersFabric.GetCommentListConverter(commentListResponse); - var instaComments = converter.Convert(); - instaComments.Pages++; - var nextId = commentListResponse.NextMaxId; - var moreAvailable = commentListResponse.MoreComentsAvailable; - while (moreAvailable && instaComments.Pages < maxPages) - { - if (string.IsNullOrEmpty(nextId)) break; - var nextComments = await GetCommentListWithMaxIdAsync(mediaId, nextId); - if (!nextComments.Succeeded) - Result.Success($"Not all pages was downloaded: {nextComments.Info.Message}", instaComments); - nextId = nextComments.Value.NextMaxId; - moreAvailable = nextComments.Value.MoreComentsAvailable; - converter = ConvertersFabric.GetCommentListConverter(nextComments.Value); - instaComments.Comments.AddRange(converter.Convert().Comments); - instaComments.Pages++; - } - return Result.Success(instaComments); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception); - } - } - - public async Task> GetMediaLikersAsync(string mediaId) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var likersUri = UriCreator.GetMediaLikersUri(mediaId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, likersUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) - return Result.UnExpectedResponse(response, json); - var likers = new InstaLikersList(); - var mediaLikersResponse = JsonConvert.DeserializeObject(json); - likers.UsersCount = mediaLikersResponse.UsersCount; - if (mediaLikersResponse.UsersCount < 1) return Result.Success(likers); - likers.AddRange( - mediaLikersResponse.Users.Select(ConvertersFabric.GetUserShortConverter) - .Select(converter => converter.Convert())); - return Result.Success(likers); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception); - } - } - - public async Task> FollowUserAsync(long userId) - { - return await FollowUnfollowUserInternal(userId, UriCreator.GetFollowUserUri(userId)); - } - - public async Task> UnFollowUserAsync(long userId) - { - return await FollowUnfollowUserInternal(userId, UriCreator.GetUnFollowUserUri(userId)); - } - - - public async Task> SetAccountPrivateAsync() - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var instaUri = UriCreator.GetUriSetAccountPrivate(); - var fields = new Dictionary - { - {"_uuid", _deviceInfo.DeviceGuid.ToString()}, - {"_uid", _user.LoggedInUder.Pk}, - {"_csrftoken", _user.CsrfToken} - }; - var hash = CryptoHelper.CalculateHash(InstaApiConstants.IG_SIGNATURE_KEY, - JsonConvert.SerializeObject(fields)); - var payload = JsonConvert.SerializeObject(fields); - var signature = $"{hash}.{Uri.EscapeDataString(payload)}"; - var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); - request.Content = new FormUrlEncodedContent(fields); - request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); - request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, - InstaApiConstants.IG_SIGNATURE_KEY_VERSION); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var userInfoUpdated = - JsonConvert.DeserializeObject(json, new InstaUserShortDataConverter()); - if (string.IsNullOrEmpty(userInfoUpdated.Pk)) - return Result.Fail("Pk is null or empty"); - var converter = ConvertersFabric.GetUserShortConverter(userInfoUpdated); - return Result.Success(converter.Convert()); - } - return Result.UnExpectedResponse(response, json); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, (InstaUserShort) null); - } - } - - public async Task> SetAccountPublicAsync() - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var instaUri = UriCreator.GetUriSetAccountPublic(); - var fields = new Dictionary - { - {"_uuid", _deviceInfo.DeviceGuid.ToString()}, - {"_uid", _user.LoggedInUder.Pk}, - {"_csrftoken", _user.CsrfToken} - }; - var hash = CryptoHelper.CalculateHash(InstaApiConstants.IG_SIGNATURE_KEY, - JsonConvert.SerializeObject(fields)); - var payload = JsonConvert.SerializeObject(fields); - var signature = $"{hash}.{Uri.EscapeDataString(payload)}"; - var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); - request.Content = new FormUrlEncodedContent(fields); - request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); - request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, - InstaApiConstants.IG_SIGNATURE_KEY_VERSION); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var userInfoUpdated = - JsonConvert.DeserializeObject(json, new InstaUserShortDataConverter()); - if (string.IsNullOrEmpty(userInfoUpdated.Pk)) - return Result.Fail("Pk is null or empty"); - var converter = ConvertersFabric.GetUserShortConverter(userInfoUpdated); - return Result.Success(converter.Convert()); - } - return Result.UnExpectedResponse(response, json); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, (InstaUserShort) null); - } - } - - - public async Task> CommentMediaAsync(string mediaId, string text) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var instaUri = UriCreator.GetPostCommetUri(mediaId); - var breadcrumb = CryptoHelper.GetCommentBreadCrumbEncoded(text); - var fields = new Dictionary - { - {"user_breadcrumb", breadcrumb}, - {"idempotence_token", Guid.NewGuid().ToString()}, - {"_uuid", _deviceInfo.DeviceGuid.ToString()}, - {"_uid", _user.LoggedInUder.Pk}, - {"_csrftoken", _user.CsrfToken}, - {"comment_text", text}, - {"containermodule", "comments_feed_timeline"}, - {"radio_type", "wifi-none"} - }; - var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var commentResponse = JsonConvert.DeserializeObject(json, - new InstaCommentDataConverter()); - var converter = ConvertersFabric.GetCommentConverter(commentResponse); - return Result.Success(converter.Convert()); - } - return Result.UnExpectedResponse(response, json); - } - catch (Exception exception) - { - return Result.Fail(exception.Message, (InstaComment) null); - } - } - - public async Task> DeleteCommentAsync(string mediaId, string commentId) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var instaUri = UriCreator.GetDeleteCommetUri(mediaId, commentId); - var fields = new Dictionary - { - {"_uuid", _deviceInfo.DeviceGuid.ToString()}, - {"_uid", _user.LoggedInUder.Pk}, - {"_csrftoken", _user.CsrfToken} - }; - var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - return Result.Success(true); - return Result.UnExpectedResponse(response, json); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, false); - } - } - - public async Task> UploadPhotoAsync(InstaImage image, string caption) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var instaUri = UriCreator.GetUploadPhotoUri(); - var uploadId = ApiRequestMessage.GenerateUploadId(); - var requestContent = new MultipartFormDataContent(uploadId) - { - {new StringContent(uploadId), "\"upload_id\""}, - {new StringContent(_deviceInfo.DeviceGuid.ToString()), "\"_uuid\""}, - {new StringContent(_user.CsrfToken), "\"_csrftoken\""}, - { - new StringContent("{\"lib_name\":\"jt\",\"lib_version\":\"1.3.0\",\"quality\":\"87\"}"), - "\"image_compression\"" - } - }; - var imageContent = new ByteArrayContent(File.ReadAllBytes(image.URI)); - imageContent.Headers.Add("Content-Transfer-Encoding", "binary"); - imageContent.Headers.Add("Content-Type", "application/octet-stream"); - requestContent.Add(imageContent, "photo", $"pending_media_{ApiRequestMessage.GenerateUploadId()}.jpg"); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); - request.Content = requestContent; - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.IsSuccessStatusCode) - return await ConfigurePhotoAsync(image, uploadId, caption); - return Result.UnExpectedResponse(response, json); - } - catch (Exception exception) - { - return Result.Fail(exception.Message, (InstaMedia) null); - } - } - - public async Task> ConfigurePhotoAsync(InstaImage image, string uploadId, string caption) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var instaUri = UriCreator.GetMediaConfigureUri(); - var androidVersion = - AndroidVersion.FromString(_deviceInfo.FirmwareFingerprint.Split('/')[2].Split(':')[1]); - if (androidVersion == null) - return Result.Fail("Unsupported android version", (InstaMedia) null); - var data = new JObject - { - {"_uuid", _deviceInfo.DeviceGuid.ToString()}, - {"_uid", _user.LoggedInUder.Pk}, - {"_csrftoken", _user.CsrfToken}, - {"media_folder", "Camera"}, - {"source_type", "4"}, - {"caption", caption}, - {"upload_id", uploadId}, - { - "device", new JObject - { - {"manufacturer", _deviceInfo.HardwareManufacturer}, - {"model", _deviceInfo.HardwareModel}, - {"android_version", androidVersion.VersionNumber}, - {"android_release", androidVersion.APILevel} - } - }, - { - "edits", new JObject - { - {"crop_original_size", new JArray {image.Width, image.Height}}, - {"crop_center", new JArray {0.0, -0.0}}, - {"crop_zoom", 1} - } - }, - { - "extra", new JObject - { - {"source_width", image.Width}, - {"source_height", image.Height} - } - } - }; - var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, data); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.IsSuccessStatusCode) - { - var mediaResponse = JsonConvert.DeserializeObject(json); - var converter = ConvertersFabric.GetSingleMediaConverter(mediaResponse); - return Result.Success(converter.Convert()); - } - return Result.UnExpectedResponse(response, json); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, (InstaMedia) null); - } - } - - - public async Task> GetStoryFeedAsync() - { - ValidateUser(); - ValidateLoggedIn(); - - try - { - var storyFeedUri = UriCreator.GetStoryFeedUri(); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, storyFeedUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaStoryFeed) null); - var storyFeedResponse = JsonConvert.DeserializeObject(json); - var instaStoryFeed = ConvertersFabric.GetStoryFeedConverter(storyFeedResponse).Convert(); - return Result.Success(instaStoryFeed); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, (InstaStoryFeed) null); - } - } - - public async Task> GetUserStoryAsync(long userId) - { - ValidateUser(); - ValidateLoggedIn(); - - try - { - var userStoryUri = UriCreator.GetUserStoryUri(userId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userStoryUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaStory) null); - var userStory = new InstaStory(); - var userStoryResponse = JsonConvert.DeserializeObject(json); - - userStory = ConvertersFabric.GetStoryConverter(userStoryResponse).Convert(); - - return Result.Success(userStory); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, (InstaStory) null); - } - } - - public async Task> UploadStoryPhotoAsync(InstaImage image, string caption) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var instaUri = UriCreator.GetUploadPhotoUri(); - var uploadId = ApiRequestMessage.GenerateUploadId(); - var requestContent = new MultipartFormDataContent(uploadId) - { - {new StringContent(uploadId), "\"upload_id\""}, - {new StringContent(_deviceInfo.DeviceGuid.ToString()), "\"_uuid\""}, - {new StringContent(_user.CsrfToken), "\"_csrftoken\""}, - { - new StringContent("{\"lib_name\":\"jt\",\"lib_version\":\"1.3.0\",\"quality\":\"87\"}"), - "\"image_compression\"" - } - }; - var imageContent = new ByteArrayContent(File.ReadAllBytes(image.URI)); - imageContent.Headers.Add("Content-Transfer-Encoding", "binary"); - imageContent.Headers.Add("Content-Type", "application/octet-stream"); - requestContent.Add(imageContent, "photo", $"pending_media_{ApiRequestMessage.GenerateUploadId()}.jpg"); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); - request.Content = requestContent; - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.IsSuccessStatusCode) - return await ConfigureStoryPhotoAsync(image, uploadId, caption); - return Result.UnExpectedResponse(response, json); - } - catch (Exception exception) - { - return Result.Fail(exception.Message, (InstaStoryMedia) null); - } - } - - public async Task> ConfigureStoryPhotoAsync(InstaImage image, string uploadId, - string caption) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var instaUri = UriCreator.GetStoryConfigureUri(); - var data = new JObject - { - {"_uuid", _deviceInfo.DeviceGuid.ToString()}, - {"_uid", _user.LoggedInUder.Pk}, - {"_csrftoken", _user.CsrfToken}, - {"source_type", "1"}, - {"caption", caption}, - {"upload_id", uploadId}, - {"edits", new JObject()}, - {"disable_comments", false}, - {"configure_mode", 1}, - {"camera_position", "unknown"} - }; - var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, data); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.IsSuccessStatusCode) - { - var mediaResponse = JsonConvert.DeserializeObject(json); - var converter = ConvertersFabric.GetStoryMediaConverter(mediaResponse); - return Result.Success(converter.Convert()); - } - return Result.UnExpectedResponse(response, json); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, (InstaStoryMedia) null); - } - } - - public async Task> ChangePasswordAsync(string oldPassword, string newPassword) - { - ValidateUser(); - ValidateLoggedIn(); - - if (oldPassword == newPassword) - return Result.Fail("The old password should not the same of the new password", false); - - try - { - var changePasswordUri = UriCreator.GetChangePasswordUri(); - - var data = new JObject - { - {"_uuid", _deviceInfo.DeviceGuid.ToString()}, - {"_uid", _user.LoggedInUder.Pk}, - {"_csrftoken", _user.CsrfToken}, - {"old_password", oldPassword}, - {"new_password1", newPassword}, - {"new_password2", newPassword} - }; - - var request = HttpHelper.GetSignedRequest(HttpMethod.Get, changePasswordUri, _deviceInfo, data); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - return Result.Success(true); //If status code is OK, then the password is surely changed - var error = JsonConvert.DeserializeObject(json); - var errors = ""; - error.Message.Errors.ForEach(errorContent => errors += errorContent + "\n"); - return Result.Fail(errors, false); - } - catch (Exception exception) - { - return Result.Fail(exception.Message, false); - } - } - - public async Task> DeleteMediaAsync(string mediaId, InstaMediaType mediaType) - { - ValidateUser(); - ValidateLoggedIn(); - - try - { - var deleteMediaUri = UriCreator.GetDeleteMediaUri(mediaId, mediaType); - - var data = new JObject - { - {"_uuid", _deviceInfo.DeviceGuid.ToString()}, - {"_uid", _user.LoggedInUder.Pk}, - {"_csrftoken", _user.CsrfToken}, - {"media_id", mediaId} - }; - - var request = HttpHelper.GetSignedRequest(HttpMethod.Get, deleteMediaUri, _deviceInfo, data); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var deletedResponse = JsonConvert.DeserializeObject(json); - return Result.Success(deletedResponse.IsDeleted); - } - var error = JsonConvert.DeserializeObject(json); - var errors = ""; - error.Message.Errors.ForEach(errorContent => errors += errorContent + "\n"); - return Result.Fail(errors, false); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, false); - } - } - - public async Task> EditMediaAsync(string mediaId, string caption) - { - ValidateUser(); - ValidateLoggedIn(); - - try - { - var editMediaUri = UriCreator.GetEditMediaUri(mediaId); - - var data = new JObject - { - {"_uuid", _deviceInfo.DeviceGuid.ToString()}, - {"_uid", _user.LoggedInUder.Pk}, - {"_csrftoken", _user.CsrfToken}, - {"caption_text", caption} - }; - - var request = HttpHelper.GetSignedRequest(HttpMethod.Get, editMediaUri, _deviceInfo, data); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - return - Result.Success( - true); //Technically Instagram returns the InstaMediaItem, but it is useless in our case, at this time. - var error = JsonConvert.DeserializeObject(json); - return Result.Fail(error.Message, false); - } - catch (Exception exception) - { - return Result.Fail(exception.Message, false); - } - } - - public async Task> GetLikeFeedAsync(int maxPages = 0) - { - ValidateUser(); - if (maxPages == 0) maxPages = int.MaxValue; - var instaUri = UriCreator.GetUserLikeFeedUri(); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var mediaResponse = JsonConvert.DeserializeObject(json, - new InstaMediaListDataConverter()); - var moreAvailable = mediaResponse.MoreAvailable; - var converter = ConvertersFabric.GetMediaListConverter(mediaResponse); - var mediaList = converter.Convert(); - mediaList.Pages++; - var nextId = mediaResponse.NextMaxId; - while (moreAvailable && mediaList.Pages < maxPages) - { - var result = await GetLikeFeedInternal(nextId); - if (!result.Succeeded) - return Result.Fail(result.Info, mediaList); - converter = ConvertersFabric.GetMediaListConverter(result.Value); - mediaList.AddRange(converter.Convert()); - mediaList.Pages++; - nextId = mediaResponse.NextMaxId; - moreAvailable = result.Value.MoreAvailable; - } - return Result.Success(mediaList); - } - return Result.UnExpectedResponse(response, json); - } - - public async Task> GetLikeFeedInternal(string maxId = "") - { - var instaUri = UriCreator.GetUserLikeFeedUri(maxId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) - return Result.UnExpectedResponse(response, json); - var mediaResponse = JsonConvert.DeserializeObject(json, - new InstaMediaListDataConverter()); - return Result.Success(mediaResponse); - } - - public async Task> GetFriendshipStatusAsync(long userId) - { - ValidateUser(); - var userUri = UriCreator.GetUserFriendshipUri(userId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) - return Result.UnExpectedResponse(response, json); - var friendshipStatusResponse = JsonConvert.DeserializeObject(json); - var converter = ConvertersFabric.GetFriendShipStatusConverter(friendshipStatusResponse); - return Result.Success(converter.Convert()); - } - - #endregion - - #region private part - - private void ValidateUser() - { - if (string.IsNullOrEmpty(_user.UserName) || string.IsNullOrEmpty(_user.Password)) - throw new ArgumentException("user name and password must be specified"); - } - - private void ValidateLoggedIn() - { - if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); - } - - private void ValidateRequestMessage() - { - if (_httpRequestProcessor.RequestMessage == null || _httpRequestProcessor.RequestMessage.IsEmpty()) - throw new ArgumentException("API request message null or empty"); - } - - private async Task> GetUserFeedWithMaxIdAsync(string maxId) - { - if (!Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.TIMELINEFEED, - out var instaUri)) - throw new Exception("Cant create search user URI"); - var userUriBuilder = new UriBuilder(instaUri) {Query = $"max_id={maxId}"}; - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUriBuilder.Uri, _deviceInfo); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_PHONE_ID, - _httpRequestProcessor.RequestMessage.phone_id)); - request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, - InstaApiConstants.TIMEZONE_OFFSET.ToString())); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var feedResponse = JsonConvert.DeserializeObject(json, - new InstaFeedResponseDataConverter()); - return Result.Success(feedResponse); - } - return Result.UnExpectedResponse(response, json); - } - - private async Task> GetFollowingActivityWithMaxIdAsync(string maxId) - { - var uri = UriCreator.GetFollowingRecentActivityUri(maxId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var followingActivity = JsonConvert.DeserializeObject(json, - new InstaRecentActivityConverter()); - return Result.Success(followingActivity); - } - return Result.UnExpectedResponse(response, json); - } - - private async Task> GetUserMediaListWithMaxIdAsync(Uri instaUri) - { - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var mediaResponse = JsonConvert.DeserializeObject(json, - new InstaMediaListDataConverter()); - return Result.Success(mediaResponse); - } - return Result.Fail("", (InstaMediaListResponse) null); - } - - private async Task> GetUserListByURIAsync(Uri uri) - { - ValidateUser(); - try - { - if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated"); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var instaUserListResponse = JsonConvert.DeserializeObject(json); - if (!instaUserListResponse.IsOk()) Result.Fail("", (InstaUserListShortResponse) null); - return Result.Success(instaUserListResponse); - } - return Result.UnExpectedResponse(response, json); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, (InstaUserListShortResponse) null); - } - } - - private async Task> GetRecentActivityInternalAsync(Uri uri, int maxPages = 0) - { - ValidateLoggedIn(); - if (maxPages == 0) maxPages = int.MaxValue; - - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request, HttpCompletionOption.ResponseContentRead); - var activityFeed = new InstaActivityFeed(); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) - return Result.UnExpectedResponse(response, json); - var feedPage = JsonConvert.DeserializeObject(json, - new InstaRecentActivityConverter()); - activityFeed.IsOwnActivity = feedPage.IsOwnActivity; - var nextId = feedPage.NextMaxId; - activityFeed.Items.AddRange( - feedPage.Stories.Select(ConvertersFabric.GetSingleRecentActivityConverter) - .Select(converter => converter.Convert())); - var pages = 1; - while (!string.IsNullOrEmpty(nextId) && pages < maxPages) - { - var nextFollowingFeed = await GetFollowingActivityWithMaxIdAsync(nextId); - if (!nextFollowingFeed.Succeeded) - return Result.Success($"Not all pages was downloaded: {nextFollowingFeed.Info.Message}", - activityFeed); - nextId = nextFollowingFeed.Value.NextMaxId; - activityFeed.Items.AddRange( - feedPage.Stories.Select(ConvertersFabric.GetSingleRecentActivityConverter) - .Select(converter => converter.Convert())); - pages++; - } - return Result.Success(activityFeed); - } - - private async Task> GetTagFeedWithMaxIdAsync(string tag, string nextId) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var instaUri = UriCreator.GetTagFeedUri(tag); - instaUri = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}.Uri; - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var feedResponse = JsonConvert.DeserializeObject(json, - new InstaMediaListDataConverter()); - return Result.Success(feedResponse); - } - return Result.UnExpectedResponse(response, json); - } - catch (Exception exception) - { - return Result.Fail(exception.Message, (InstaMediaListResponse) null); - } - } - - private async Task> GetCommentListWithMaxIdAsync(string mediaId, - string nextId) - { - var commentsUri = UriCreator.GetMediaCommentsUri(mediaId); - var commentsUriMaxId = new UriBuilder(commentsUri) {Query = $"max_id={nextId}"}.Uri; - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, commentsUriMaxId, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - var comments = JsonConvert.DeserializeObject(json); - return Result.Success(comments); - } - return Result.Fail("", (InstaCommentListResponse) null); - } - - private async Task> FollowUnfollowUserInternal(long userId, Uri instaUri) - { - ValidateUser(); - ValidateLoggedIn(); - try - { - var fields = new Dictionary - { - {"_uuid", _deviceInfo.DeviceGuid.ToString()}, - {"_uid", _user.LoggedInUder.Pk}, - {"_csrftoken", _user.CsrfToken}, - {"user_id", userId.ToString()}, - {"radio_type", "wifi-none"} - }; - var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(json)) - { - var friendshipStatus = JsonConvert.DeserializeObject(json, - new InstaFriendShipDataConverter()); - var converter = ConvertersFabric.GetFriendShipStatusConverter(friendshipStatus); - return Result.Success(converter.Convert()); - } - return Result.UnExpectedResponse(response, json); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, (InstaFriendshipStatus) null); - } - } - - private async Task> GetExploreFeedAsync(string maxId) - { - try - { - var exploreUri = UriCreator.GetExploreUri(maxId); - var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, exploreUri, _deviceInfo); - var response = await _httpRequestProcessor.SendAsync(request); - var json = await response.Content.ReadAsStringAsync(); - if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaExploreFeedResponse) null); - return Result.Success( - JsonConvert.DeserializeObject(json, new InstaExploreFeedDataConverter())); - } - catch (Exception exception) - { - LogException(exception); - return Result.Fail(exception.Message, (InstaExploreFeedResponse) null); - } - } - - private void LogException(Exception exception) - { - _logger?.LogException(exception); - } - - #endregion - } +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using InstaSharper.API.Processors; +using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using InstaSharper.Converters; +using InstaSharper.Helpers; +using InstaSharper.Logger; +using Newtonsoft.Json; + +namespace InstaSharper.API +{ + internal class InstaApi : IInstaApi + { + private readonly IHttpRequestProcessor _httpRequestProcessor; + private readonly IInstaLogger _logger; + private ICollectionProcessor _collectionProcessor; + private ICommentProcessor _commentProcessor; + private AndroidDevice _deviceInfo; + private IFeedProcessor _feedProcessor; + + private IHashtagProcessor _hashtagProcessor; + private ILocationProcessor _locationProcessor; + private IMediaProcessor _mediaProcessor; + private IMessagingProcessor _messagingProcessor; + private IUserProfileProcessor _profileProcessor; + private IStoryProcessor _storyProcessor; + + private TwoFactorLoginInfo _twoFactorInfo; + private InstaChallenge _challengeInfo; + private UserSessionData _user; + private IUserProcessor _userProcessor; + + public InstaApi(UserSessionData user, IInstaLogger logger, AndroidDevice deviceInfo, + IHttpRequestProcessor httpRequestProcessor) + { + _user = user; + _logger = logger; + _deviceInfo = deviceInfo; + _httpRequestProcessor = httpRequestProcessor; + } + + /// + /// Get user timeline feed (feed of recent posts from users you follow) asynchronously. + /// + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + public async Task> GetUserTimelineFeedAsync(PaginationParameters paginationParameters) + { + ValidateUser(); + ValidateLoggedIn(); + return await _feedProcessor.GetUserTimelineFeedAsync(paginationParameters); + } + + /// + /// Get user story reel feed. Contains user info last story including all story items. + /// + /// User identifier (PK) + /// + public async Task> GetUserStoryFeedAsync(long userId) + { + ValidateUser(); + ValidateLoggedIn(); + return await _storyProcessor.GetUserStoryFeedAsync(userId); + } + + + /// + /// Get user explore feed (Explore tab info) asynchronously + /// + /// Pagination parameters: next id and max amount of pages to load + /// + /// > + /// + public async Task> GetExploreFeedAsync(PaginationParameters paginationParameters) + { + ValidateUser(); + ValidateLoggedIn(); + return await _feedProcessor.GetExploreFeedAsync(paginationParameters); + } + + /// + /// Get all user media by username asynchronously + /// + /// Username + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + public async Task> GetUserMediaAsync(string username, + PaginationParameters paginationParameters) + { + ValidateUser(); + ValidateLoggedIn(); + var user = await GetUserAsync(username); + if (!user.Succeeded) + return Result.Fail("Unable to get user to load media"); + return await _userProcessor.GetUserMediaAsync(user.Value.Pk, paginationParameters); + } + + /// + /// Get media by its id asynchronously + /// + /// Maximum count of pages to retrieve + /// + /// + /// + public async Task> GetMediaByIdAsync(string mediaId) + { + ValidateUser(); + return await _mediaProcessor.GetMediaByIdAsync(mediaId); + } + + /// + /// Get user info by its user name asynchronously + /// + /// Username + /// + /// + /// + public async Task> GetUserAsync(string username) + { + ValidateUser(); + ValidateLoggedIn(); + return await _userProcessor.GetUserAsync(username); + } + + /// + /// Search users asynchronously + /// + /// Search pattern e.g. part of username + /// + /// List of users matches pattern + /// + /// + public async Task> SearchUsersAsync(string searchPattern) + { + ValidateUser(); + ValidateLoggedIn(); + return await _userProcessor.SearchUsersAsync(searchPattern); + } + + + /// + /// Get currently logged in user info asynchronously + /// + /// + /// + /// + public async Task> GetCurrentUserAsync() + { + ValidateUser(); + ValidateLoggedIn(); + return await _userProcessor.GetCurrentUserAsync(); + } + + /// + /// Get tag feed by tag value asynchronously + /// + /// Tag value + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + public async Task> GetTagFeedAsync(string tag, PaginationParameters paginationParameters) + { + ValidateUser(); + ValidateLoggedIn(); + return await _feedProcessor.GetTagFeedAsync(tag, paginationParameters); + } + + /// + /// Get followers list by username asynchronously + /// + /// Username + /// Pagination parameters: next id and max amount of pages to load + /// Search string to locate specific followers + /// + /// + /// + public async Task> GetUserFollowersAsync(string username, + PaginationParameters paginationParameters, string searchQuery = "") + { + ValidateUser(); + ValidateLoggedIn(); + return await _userProcessor.GetUserFollowersAsync(username, paginationParameters, searchQuery); + } + + /// + /// Get following list by username asynchronously + /// + /// Username + /// Pagination parameters: next id and max amount of pages to load + /// Search string to locate specific followings + /// + /// + /// + public async Task> GetUserFollowingAsync(string username, + PaginationParameters paginationParameters, string searchQuery = "") + { + ValidateUser(); + ValidateLoggedIn(); + return await _userProcessor.GetUserFollowingAsync(username, paginationParameters, searchQuery); + } + + /// + /// Gets the user extended information (followers count, following count, bio, etc) by user identifier. + /// + /// User Id, like "123123123" + /// + public async Task> GetUserInfoByIdAsync(long pk) + { + ValidateUser(); + ValidateLoggedIn(); + return await _userProcessor.GetUserInfoByIdAsync(pk); + } + + /// + /// Gets the user extended information (followers count, following count, bio, etc) by username. + /// + /// Username, like "instagram" + /// + public async Task> GetUserInfoByUsernameAsync(string username) + { + ValidateUser(); + ValidateLoggedIn(); + return await _userProcessor.GetUserInfoByUsernameAsync(username); + } + + /// + /// Send link as a message + /// + /// Direct message (link + description) + /// Array of recipients, user pk like "123123123" + /// Affected threads + public async Task> SendLinkMessage(InstaMessageLink message, + params long[] recipients) + { + ValidateUser(); + ValidateLoggedIn(); + return await _messagingProcessor.SendLinkMessage(message, recipients); + } + + /// + /// Send link as a message + /// + /// Direct message (link + description) + /// Array of threads, thread id like "111182366841710300949128137443944311111" + /// Affected threads + public async Task> SendLinkMessage(InstaMessageLink message, + params string[] threads) + { + ValidateUser(); + ValidateLoggedIn(); + return await _messagingProcessor.SendLinkMessage(message, threads); + } + + /// + /// Send media as a message + /// + /// Media id, like "1166111111128767752_1111111" + /// Type of media (photo/video) + /// Array of threads, thread id like "111182366841710300949128137443944311111" + /// Affected threads + public async Task> ShareMedia(string mediaId, InstaMediaType mediaType, + params string[] threads) + { + ValidateUser(); + ValidateLoggedIn(); + return await _messagingProcessor.ShareMedia(mediaId, mediaType, threads); + } + + /// + /// Decline ALL pending threads + /// + /// Status response + public async Task> DeclineAllPendingDirectThreads() + { + ValidateUser(); + ValidateLoggedIn(); + return await _messagingProcessor.DeclineAllPendingDirectThreads(); + } + + /// + /// Approve single thread by id + /// + /// Thread id, e.g. "111182366841710300949128137443944311111" + /// Status response + public async Task> ApprovePendingDirectThread(string threadId) + { + ValidateUser(); + ValidateLoggedIn(); + return await _messagingProcessor.ApprovePendingDirectThread(threadId); + } + + /// + /// Get followers list for currently logged in user asynchronously + /// + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + public async Task> GetCurrentUserFollowersAsync( + PaginationParameters paginationParameters) + { + ValidateUser(); + ValidateLoggedIn(); + return await _userProcessor.GetCurrentUserFollowersAsync(paginationParameters); + } + + /// + /// Get following list for currently logged in user asynchronously + /// + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + public async Task> GetCurrentUserFollowingAsync( + PaginationParameters paginationParameters) + { + ValidateUser(); + ValidateLoggedIn(); + return await _userProcessor.GetCurrentUserFollowingAsync(paginationParameters); + } + + /// + /// Get user tags by username asynchronously + /// Returns media list containing tags + /// + /// Username + /// Pagination parameters: next id and max amount of pages to load + /// + /// + /// + public async Task> GetUserTagsAsync(string username, + PaginationParameters paginationParameters) + { + ValidateUser(); + ValidateLoggedIn(); + var user = await GetUserAsync(username); + if (!user.Succeeded) + return Result.Fail($"Unable to get user {username} to get tags", (InstaMediaList) null); + return await _userProcessor.GetUserTagsAsync(user.Value.Pk, paginationParameters); + } + + + /// + /// Get direct inbox threads for current user asynchronously + /// + /// + /// + /// + 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.LoggedInUser = converter.Convert(); + _user.RankToken = $"{_user.LoggedInUser.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.LoggedInUser = converter.Convert(); + _user.RankToken = $"{_user.LoggedInUser.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.LoggedInUser = converter.Convert(); + _user.RankToken = $"{_user.LoggedInUser.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 + } } \ No newline at end of file diff --git a/InstaSharper/API/InstaApiConstants.cs b/InstaSharper/API/InstaApiConstants.cs old mode 100644 new mode 100755 index 5613b3a3..d9ffca04 --- a/InstaSharper/API/InstaApiConstants.cs +++ b/InstaSharper/API/InstaApiConstants.cs @@ -1,4 +1,6 @@ -namespace InstaSharper.API +using System; + +namespace InstaSharper.API { internal static class InstaApiConstants { @@ -14,17 +16,23 @@ internal static class InstaApiConstants public const string HEADER_XML_HTTP_REQUEST = "XMLHttpRequest"; public const string USER_AGENT = - "Instagram 12.0.0.7.91 Android (23/6.0.1; 640dpi; 1440x2560; samsung; SM-G935F; hero2lte; samsungexynos8890; en_NZ)" - ; + "Instagram 109.0.0.18.124 Android (21/5.0.2; 480dpi; 1080x1776; Sony; C6603; C6603; qcom; ru_RU; 170693940)"; + + public const string HEADER_USER_AGENT = "User-Agent"; public const string HEADER_QUERY = "q"; public const string HEADER_RANK_TOKEN = "rank_token"; public const string HEADER_COUNT = "count"; - public const string IG_SIGNATURE_KEY = "b4946d296abf005163e72346a6d33dd083cadde638e6ad9c5eb92e381b35784a"; + public const string HEADER_EXCLUDE_LIST = "exclude_list"; + + public const string + IG_SIGNATURE_KEY = + "153cab3b94f8e6a1c0711202b5f1c7064e4718cad09a3004d5e57ef3d919012a"; + public const string HEADER_IG_SIGNATURE = "signed_body"; public const string IG_SIGNATURE_KEY_VERSION = "4"; public const string HEADER_IG_SIGNATURE_KEY_VERSION = "ig_sig_key_version"; - public const string IG_CAPABILITIES = "3boBAA=="; + public const string IG_CAPABILITIES = "3brTBw=="; public const string HEADER_IG_CAPABILITIES = "X-IG-Capabilities"; public const string IG_CONNECTION_TYPE = "WIFI"; public const string HEADER_IG_CONNECTION_TYPE = "X-IG-Connection-Type"; @@ -32,25 +40,35 @@ internal static class InstaApiConstants public const string HEADER_ACCEPT_LANGUAGE = "Accept-Language"; public const string ACCEPT_ENCODING = "gzip, deflate, sdch"; public const string HEADER_ACCEPT_ENCODING = "gzip, deflate, sdch"; - public const string TIMEZONE = "Pacific/Auckland"; public const string HEADER_PHONE_ID = "phone_id"; public const string HEADER_TIMEZONE = "timezone_offset"; public const string HEADER_XGOOGLE_AD_IDE = "X-Google-AD-ID"; public const string COMMENT_BREADCRUMB_KEY = "iN4$aGr0m"; - public const int TIMEZONE_OFFSET = 43200; - + public const int TIMEZONE_OFFSET = 3600; // GMT +1 + public const string VEFITY_CHOICE = "choice"; + public const string SECURITY_CODE = "security_code"; + + public const string INSTAGRAM_URL = "https://i.instagram.com"; public const string API = "/api"; public const string API_SUFFIX = API + API_VERSION; public const string API_VERSION = "/v1"; + public const string BASE_INSTAGRAM_API_URL = INSTAGRAM_URL + API_SUFFIX + "/"; + public const string CURRENTUSER = API_SUFFIX + "/accounts/current_user?edit=true"; + public const string SEARCH_TAGS = API_SUFFIX + "/tags/search/?q={0}&count={1}"; + public const string GET_TAG_INFO = API_SUFFIX + "/tags/{0}/info/"; public const string SEARCH_USERS = API_SUFFIX + "/users/search"; + public const string GET_USER_INFO_BY_ID = API_SUFFIX + "/users/{0}/info/"; + public const string GET_USER_INFO_BY_USERNAME = API_SUFFIX + "/users/{0}/usernameinfo/"; public const string ACCOUNTS_LOGIN = API_SUFFIX + "/accounts/login/"; + public const string ACCOUNTS_CREATE = API_SUFFIX + "/accounts/create/"; + public const string ACCOUNTS_2FA_LOGIN = API_SUFFIX + "/accounts/two_factor_login/"; public const string CHANGE_PASSWORD = API_SUFFIX + "/accounts/change_password/"; public const string ACCOUNTS_LOGOUT = API_SUFFIX + "/accounts/logout/"; public const string EXPLORE = API_SUFFIX + "/discover/explore/"; - public const string TIMELINEFEED = API_SUFFIX + "/feed/timeline"; + public const string TIMELINEFEED = API_SUFFIX + "/feed/timeline/"; public const string USEREFEED = API_SUFFIX + "/feed/user/"; public const string GET_USER_TAGS = API_SUFFIX + "/usertags/{0}/feed/"; public const string GET_MEDIA = API_SUFFIX + "/media/{0}/info/"; @@ -58,10 +76,29 @@ internal static class InstaApiConstants public const string GET_USER_FOLLOWING = API_SUFFIX + "/friendships/{0}/following/?rank_token={1}"; public const string GET_TAG_FEED = API_SUFFIX + "/feed/tag/{0}"; public const string GET_RANKED_RECIPIENTS = API_SUFFIX + "/direct_v2/ranked_recipients"; + public const string RESET_CHALLENGE = API_SUFFIX + "/challenge/reset/{0}"; + public const string VERIFY_METHOD = API_SUFFIX + "/challenge/{0}"; + public const string FB_SEARCH_PLACE = API_SUFFIX + "/fbsearch/places/?count={0}&query={1}&rank_token={2}"; + + public const string GET_LIST_COLLECTIONS = API_SUFFIX + "/collections/list/"; + public const string GET_COLLECTION = API_SUFFIX + "/feed/collection/{0}/"; + public const string CREATE_COLLECTION = API_SUFFIX + "/collections/create/"; + public const string EDIT_COLLECTION = API_SUFFIX + "/collections/{0}/edit/"; + public const string DELETE_COLLECTION = API_SUFFIX + "/collections/{0}/delete/"; + public const string COLLECTION_CREATE_MODULE = API_SUFFIX + "collection_create"; + public const string FEED_SAVED_ADD_TO_COLLECTION_MODULE = "feed_saved_add_to_collection"; + + public const string GET_MEDIAID = API_SUFFIX + "/oembed/?url={0}"; + public const string GET_SHARE_LINK = API_SUFFIX + "/media/{0}/permalink/"; + public const string GET_RECENT_RECIPIENTS = API_SUFFIX + "/direct_share/recent_recipients/"; public const string GET_DIRECT_THREAD = API_SUFFIX + "/direct_v2/threads/{0}"; public const string GET_DIRECT_INBOX = API_SUFFIX + "/direct_v2/inbox/"; public const string GET_DIRECT_TEXT_BROADCAST = API_SUFFIX + "/direct_v2/threads/broadcast/text/"; + public const string GET_DIRECT_LINK_BROADCAST = API_SUFFIX + "/direct_v2/threads/broadcast/link/"; + public const string GET_DIRECT_MEDIA_SHARE_BROADCAST = API_SUFFIX + "/direct_v2/threads/broadcast/media_share/"; + public const string GET_DIRECT_DECLINE_ALL = API_SUFFIX + "/direct_v2/threads/decline_all/"; + public const string GET_DIRECT_APPROVE_THREAD = API_SUFFIX + "/direct_v2/threads/{0}/approve/"; public const string GET_RECENT_ACTIVITY = API_SUFFIX + "/news/inbox/"; public const string GET_FOLLOWING_RECENT_ACTIVITY = API_SUFFIX + "/news/"; public const string LIKE_MEDIA = API_SUFFIX + "/media/{0}/like/"; @@ -70,6 +107,8 @@ internal static class InstaApiConstants public const string MEDIA_LIKERS = API_SUFFIX + "/media/{0}/likers/"; public const string FOLLOW_USER = API_SUFFIX + "/friendships/create/{0}/"; public const string UNFOLLOW_USER = API_SUFFIX + "/friendships/destroy/{0}/"; + public const string BLOCK_USER = API_SUFFIX + "/friendships/block/{0}/"; + public const string UNBLOCK_USER = API_SUFFIX + "/friendships/unblock/{0}/"; public const string SET_ACCOUNT_PRIVATE = API_SUFFIX + "/accounts/set_private/"; public const string SET_ACCOUNT_PUBLIC = API_SUFFIX + "/accounts/set_public/"; public const string POST_COMMENT = API_SUFFIX + "/media/{0}/comment/"; @@ -77,7 +116,9 @@ internal static class InstaApiConstants public const string DISABLE_MEDIA_COMMENTS = API_SUFFIX + "/media/{0}/disable_comments/"; public const string DELETE_COMMENT = API_SUFFIX + "/media/{0}/comment/{1}/delete/"; public const string UPLOAD_PHOTO = API_SUFFIX + "/upload/photo/"; + public const string UPLOAD_VIDEO = API_SUFFIX + "/upload/video/"; public const string MEDIA_CONFIGURE = API_SUFFIX + "/media/configure/"; + public const string MEDIA_ALBUM_CONFIGURE = API_SUFFIX + "/media/configure_sidecar/"; public const string DELETE_MEDIA = API_SUFFIX + "/media/{0}/delete/?media_type={1}"; public const string EDIT_MEDIA = API_SUFFIX + "/media/{0}/edit_media/"; public const string GET_STORY_TRAY = API_SUFFIX + "/feed/reels_tray/"; @@ -85,8 +126,8 @@ internal static class InstaApiConstants public const string STORY_CONFIGURE = API_SUFFIX + "/media/configure_to_reel/"; public const string LOCATION_SEARCH = API_SUFFIX + "/location_search/"; public const string FRIENDSHIPSTATUS = API_SUFFIX + "/friendships/show/"; - public const string HEADER_USER_AGENT = "User-Agent"; public const string LIKE_FEED = API_SUFFIX + "/feed/liked/"; public const string USER_REEL_FEED = API_SUFFIX + "/feed/user/{0}/reel_media/"; + public static readonly Uri BaseInstagramUri = new Uri(BASE_INSTAGRAM_API_URL); } } \ No newline at end of file diff --git a/InstaSharper/API/Processors/CollectionProcessor.cs b/InstaSharper/API/Processors/CollectionProcessor.cs new file mode 100644 index 00000000..9afbe473 --- /dev/null +++ b/InstaSharper/API/Processors/CollectionProcessor.cs @@ -0,0 +1,183 @@ +using System; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Converters; +using InstaSharper.Converters.Json; +using InstaSharper.Helpers; +using InstaSharper.Logger; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace InstaSharper.API.Processors +{ + public class CollectionProcessor : ICollectionProcessor + { + private readonly AndroidDevice _deviceInfo; + private readonly IHttpRequestProcessor _httpRequestProcessor; + private readonly IInstaLogger _logger; + private readonly UserSessionData _user; + + public CollectionProcessor(AndroidDevice deviceInfo, UserSessionData user, + IHttpRequestProcessor httpRequestProcessor, IInstaLogger logger) + { + _deviceInfo = deviceInfo; + _user = user; + _httpRequestProcessor = httpRequestProcessor; + _logger = logger; + } + + public async Task> GetCollectionAsync(long collectionId) + { + try + { + var collectionUri = UriCreator.GetCollectionUri(collectionId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, collectionUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + + var collectionsListResponse = + JsonConvert.DeserializeObject(json, + new InstaCollectionDataConverter()); + var converter = ConvertersFabric.Instance.GetCollectionConverter(collectionsListResponse); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + public async Task> GetCollectionsAsync() + { + try + { + var collectionUri = UriCreator.GetCollectionsUri(); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, collectionUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + + var collectionsResponse = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.Instance.GetCollectionsConverter(collectionsResponse); + + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + public async Task> CreateCollectionAsync(string collectionName) + { + try + { + var createCollectionUri = UriCreator.GetCreateCollectionUri(); + + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"name", collectionName}, + {"module_name", InstaApiConstants.COLLECTION_CREATE_MODULE} + }; + + var request = + HttpHelper.GetSignedRequest(HttpMethod.Get, createCollectionUri, _deviceInfo, data); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + + var newCollectionResponse = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.Instance.GetCollectionConverter(newCollectionResponse); + + return response.StatusCode != HttpStatusCode.OK + ? Result.UnExpectedResponse(response, json) + : Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + public async Task> DeleteCollectionAsync(long collectionId) + { + try + { + var createCollectionUri = UriCreator.GetDeleteCollectionUri(collectionId); + + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"module_name", "collection_editor"} + }; + + var request = + HttpHelper.GetSignedRequest(HttpMethod.Get, createCollectionUri, _deviceInfo, data); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + return Result.Success(true); + + var error = JsonConvert.DeserializeObject(json); + return Result.Fail(error.Message, false); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message, false); + } + } + + public async Task> AddItemsToCollectionAsync(long collectionId, + params string[] mediaIds) + { + try + { + if (mediaIds?.Length < 1) + return Result.Fail("Provide at least one media id to add to collection"); + var editCollectionUri = UriCreator.GetEditCollectionUri(collectionId); + + var data = new JObject + { + {"module_name", InstaApiConstants.FEED_SAVED_ADD_TO_COLLECTION_MODULE}, + {"added_media_ids", JsonConvert.SerializeObject(mediaIds)}, + {"radio_type", "wifi-none"}, + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk}, + {"_csrftoken", _user.CsrfToken} + }; + + var request = + HttpHelper.GetSignedRequest(HttpMethod.Get, editCollectionUri, _deviceInfo, data); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var newCollectionResponse = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.Instance.GetCollectionConverter(newCollectionResponse); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/CommentProcessor.cs b/InstaSharper/API/Processors/CommentProcessor.cs new file mode 100644 index 00000000..3480010f --- /dev/null +++ b/InstaSharper/API/Processors/CommentProcessor.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Converters; +using InstaSharper.Converters.Json; +using InstaSharper.Helpers; +using InstaSharper.Logger; +using Newtonsoft.Json; + +namespace InstaSharper.API.Processors +{ + public class CommentProcessor : ICommentProcessor + { + private readonly AndroidDevice _deviceInfo; + private readonly IHttpRequestProcessor _httpRequestProcessor; + private readonly IInstaLogger _logger; + private readonly UserSessionData _user; + + public CommentProcessor(AndroidDevice deviceInfo, UserSessionData user, + IHttpRequestProcessor httpRequestProcessor, IInstaLogger logger) + { + _deviceInfo = deviceInfo; + _user = user; + _httpRequestProcessor = httpRequestProcessor; + _logger = logger; + } + + public async Task> GetMediaCommentsAsync(string mediaId, + PaginationParameters paginationParameters) + { + try + { + var commentsUri = UriCreator.GetMediaCommentsUri(mediaId, paginationParameters.NextId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, commentsUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var commentListResponse = JsonConvert.DeserializeObject(json); + var pagesLoaded = 1; + + InstaCommentList Convert(InstaCommentListResponse commentsResponse) + { + return ConvertersFabric.Instance.GetCommentListConverter(commentsResponse).Convert(); + } + + while (commentListResponse.MoreComentsAvailable + && !string.IsNullOrEmpty(commentListResponse.NextMaxId) + && pagesLoaded < paginationParameters.MaximumPagesToLoad) + { + var nextComments = await GetCommentListWithMaxIdAsync(mediaId, commentListResponse.NextMaxId); + if (!nextComments.Succeeded) + return Result.Fail(nextComments.Info, Convert(commentListResponse)); + commentListResponse.NextMaxId = nextComments.Value.NextMaxId; + commentListResponse.MoreComentsAvailable = nextComments.Value.MoreComentsAvailable; + commentListResponse.Comments.AddRange(nextComments.Value.Comments); + pagesLoaded++; + } + + var converter = ConvertersFabric.Instance.GetCommentListConverter(commentListResponse); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> CommentMediaAsync(string mediaId, string text) + { + try + { + var instaUri = UriCreator.GetPostCommetUri(mediaId); + var breadcrumb = CryptoHelper.GetCommentBreadCrumbEncoded(text); + var fields = new Dictionary + { + {"user_breadcrumb", breadcrumb}, + {"idempotence_token", Guid.NewGuid().ToString()}, + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk.ToString()}, + {"_csrftoken", _user.CsrfToken}, + {"comment_text", text}, + {"containermodule", "comments_feed_timeline"}, + {"radio_type", "wifi-none"} + }; + var request = + HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var commentResponse = JsonConvert.DeserializeObject(json, + new InstaCommentDataConverter()); + var converter = ConvertersFabric.Instance.GetCommentConverter(commentResponse); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message, (InstaComment) null); + } + } + + public async Task> DeleteCommentAsync(string mediaId, string commentId) + { + try + { + var instaUri = UriCreator.GetDeleteCommetUri(mediaId, commentId); + var fields = new Dictionary + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk.ToString()}, + {"_csrftoken", _user.CsrfToken} + }; + var request = + HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + return response.StatusCode == HttpStatusCode.OK + ? Result.Success(true) + : Result.UnExpectedResponse(response, json); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message, false); + } + } + + private async Task> GetCommentListWithMaxIdAsync(string mediaId, + string nextId) + { + var commentsUri = UriCreator.GetMediaCommentsUri(mediaId, nextId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, commentsUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var comments = JsonConvert.DeserializeObject(json); + return Result.Success(comments); + } + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/FeedProcessor.cs b/InstaSharper/API/Processors/FeedProcessor.cs new file mode 100644 index 00000000..99a14121 --- /dev/null +++ b/InstaSharper/API/Processors/FeedProcessor.cs @@ -0,0 +1,252 @@ +using System; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Converters; +using InstaSharper.Converters.Json; +using InstaSharper.Helpers; +using InstaSharper.Logger; +using Newtonsoft.Json; +using InstaRecentActivityConverter = InstaSharper.Converters.Json.InstaRecentActivityConverter; + +namespace InstaSharper.API.Processors +{ + public class FeedProcessor : IFeedProcessor + { + private readonly AndroidDevice _deviceInfo; + private readonly IHttpRequestProcessor _httpRequestProcessor; + private readonly IInstaLogger _logger; + private readonly UserSessionData _user; + + public FeedProcessor(AndroidDevice deviceInfo, UserSessionData user, IHttpRequestProcessor httpRequestProcessor, + IInstaLogger logger) + { + _deviceInfo = deviceInfo; + _user = user; + _httpRequestProcessor = httpRequestProcessor; + _logger = logger; + } + + public async Task> GetTagFeedAsync(string tag, PaginationParameters paginationParameters) + { + var tagFeed = new InstaTagFeed(); + try + { + var userFeedUri = UriCreator.GetTagFeedUri(tag, paginationParameters.NextId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var feedResponse = JsonConvert.DeserializeObject(json, + new InstaTagFeedDataConverter()); + tagFeed = ConvertersFabric.Instance.GetTagFeedConverter(feedResponse).Convert(); + + paginationParameters.NextId = feedResponse.NextMaxId; + paginationParameters.PagesLoaded++; + + while (feedResponse.MoreAvailable + && !string.IsNullOrEmpty(paginationParameters.NextId) + && paginationParameters.PagesLoaded < paginationParameters.MaximumPagesToLoad) + { + var nextFeed = await GetTagFeedAsync(tag, paginationParameters); + if (!nextFeed.Succeeded) + return Result.Fail(nextFeed.Info, tagFeed); + tagFeed.NextId = paginationParameters.NextId = nextFeed.Value.NextId; + tagFeed.Medias.AddRange(nextFeed.Value.Medias); + tagFeed.Stories.AddRange(nextFeed.Value.Stories); + } + + return Result.Success(tagFeed); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception, tagFeed); + } + } + + public async Task> GetUserTimelineFeedAsync(PaginationParameters paginationParameters) + { + var feed = new InstaFeed(); + try + { + var userFeedUri = UriCreator.GetUserFeedUri(paginationParameters.NextId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, userFeedUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + + var feedResponse = JsonConvert.DeserializeObject(json, + new InstaFeedResponseDataConverter()); + feed = ConvertersFabric.Instance.GetFeedConverter(feedResponse).Convert(); + paginationParameters.NextId = feed.NextId; + paginationParameters.PagesLoaded++; + + while (feedResponse.MoreAvailable + && !string.IsNullOrEmpty(paginationParameters.NextId) + && paginationParameters.PagesLoaded < paginationParameters.MaximumPagesToLoad) + { + var nextFeed = await GetUserTimelineFeedAsync(paginationParameters); + if (!nextFeed.Succeeded) + return Result.Fail(nextFeed.Info, feed); + + feed.Medias.AddRange(nextFeed.Value.Medias); + feed.Stories.AddRange(nextFeed.Value.Stories); + + paginationParameters.NextId = nextFeed.Value.NextId; + paginationParameters.PagesLoaded++; + } + + return Result.Success(feed); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception, feed); + } + } + + public async Task> GetExploreFeedAsync(PaginationParameters paginationParameters) + { + var exploreFeed = new InstaExploreFeed(); + try + { + var exploreUri = UriCreator.GetExploreUri(paginationParameters.NextId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, exploreUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var feedResponse = JsonConvert.DeserializeObject(json, + new InstaExploreFeedDataConverter()); + exploreFeed = ConvertersFabric.Instance.GetExploreFeedConverter(feedResponse).Convert(); + var nextId = feedResponse.Items.Medias.LastOrDefault(media => !string.IsNullOrEmpty(media.NextMaxId)) + ?.NextMaxId; + exploreFeed.Medias.PageSize = feedResponse.ResultsCount; + paginationParameters.NextId = nextId; + exploreFeed.NextId = nextId; + while (feedResponse.MoreAvailable + && !string.IsNullOrEmpty(paginationParameters.NextId) + && paginationParameters.PagesLoaded < paginationParameters.MaximumPagesToLoad) + { + var nextFeed = await GetExploreFeedAsync(paginationParameters); + if (!nextFeed.Succeeded) + return Result.Fail(nextFeed.Info, exploreFeed); + nextId = feedResponse.Items.Medias.LastOrDefault(media => !string.IsNullOrEmpty(media.NextMaxId)) + ?.NextMaxId; + exploreFeed.NextId = paginationParameters.NextId = nextId; + paginationParameters.PagesLoaded++; + exploreFeed.Medias.AddRange(nextFeed.Value.Medias); + } + + exploreFeed.Medias.Pages = paginationParameters.PagesLoaded; + return Result.Success(exploreFeed); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception, exploreFeed); + } + } + + public async Task> GetFollowingRecentActivityFeedAsync( + PaginationParameters paginationParameters) + { + var uri = UriCreator.GetFollowingRecentActivityUri(); + return await GetRecentActivityInternalAsync(uri, paginationParameters); + } + + public async Task> GetRecentActivityFeedAsync( + PaginationParameters paginationParameters) + { + var uri = UriCreator.GetRecentActivityUri(); + return await GetRecentActivityInternalAsync(uri, paginationParameters); + } + + public async Task> GetLikeFeedAsync(PaginationParameters paginationParameters) + { + var instaUri = UriCreator.GetUserLikeFeedUri(paginationParameters.NextId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var mediaResponse = JsonConvert.DeserializeObject(json, + new InstaMediaListDataConverter()); + + var mediaList = ConvertersFabric.Instance.GetMediaListConverter(mediaResponse).Convert(); + mediaList.NextId = paginationParameters.NextId = mediaResponse.NextMaxId; + while (mediaResponse.MoreAvailable + && !string.IsNullOrEmpty(paginationParameters.NextId) + && paginationParameters.PagesLoaded < paginationParameters.MaximumPagesToLoad) + { + var result = await GetLikeFeedAsync(paginationParameters); + if (!result.Succeeded) + return Result.Fail(result.Info, mediaList); + + paginationParameters.PagesLoaded++; + mediaList.NextId = paginationParameters.NextId = result.Value.NextId; + mediaList.AddRange(result.Value); + } + + mediaList.PageSize = mediaResponse.ResultsCount; + mediaList.Pages = paginationParameters.PagesLoaded; + return Result.Success(mediaList); + } + + private async Task> GetFollowingActivityWithMaxIdAsync(string maxId) + { + var uri = UriCreator.GetFollowingRecentActivityUri(maxId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var followingActivity = JsonConvert.DeserializeObject(json, + new InstaRecentActivityConverter()); + return Result.Success(followingActivity); + } + + private async Task> GetRecentActivityInternalAsync(Uri uri, + PaginationParameters paginationParameters) + { + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request, HttpCompletionOption.ResponseContentRead); + var activityFeed = new InstaActivityFeed(); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var feedPage = JsonConvert.DeserializeObject(json, + new InstaRecentActivityConverter()); + activityFeed.IsOwnActivity = feedPage.IsOwnActivity; + var nextId = feedPage.NextMaxId; + activityFeed.Items.AddRange( + feedPage.Stories.Select(ConvertersFabric.Instance.GetSingleRecentActivityConverter) + .Select(converter => converter.Convert())); + paginationParameters.PagesLoaded++; + activityFeed.NextId = paginationParameters.NextId = feedPage.NextMaxId; + while (!string.IsNullOrEmpty(nextId) + && paginationParameters.PagesLoaded < paginationParameters.MaximumPagesToLoad) + { + var nextFollowingFeed = await GetFollowingActivityWithMaxIdAsync(nextId); + if (!nextFollowingFeed.Succeeded) + return Result.Fail(nextFollowingFeed.Info, activityFeed); + nextId = nextFollowingFeed.Value.NextMaxId; + activityFeed.Items.AddRange( + feedPage.Stories.Select(ConvertersFabric.Instance.GetSingleRecentActivityConverter) + .Select(converter => converter.Convert())); + paginationParameters.PagesLoaded++; + activityFeed.NextId = paginationParameters.NextId = nextId; + } + + return Result.Success(activityFeed); + } + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/HashtagProcessor.cs b/InstaSharper/API/Processors/HashtagProcessor.cs new file mode 100644 index 00000000..cf54aef1 --- /dev/null +++ b/InstaSharper/API/Processors/HashtagProcessor.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Converters; +using InstaSharper.Helpers; +using InstaSharper.Logger; +using Newtonsoft.Json; + +namespace InstaSharper.API.Processors +{ + public class HashtagProcessor : IHashtagProcessor + { + private readonly AndroidDevice _deviceInfo; + private readonly IHttpRequestProcessor _httpRequestProcessor; + private readonly IInstaLogger _logger; + private readonly UserSessionData _user; + + public HashtagProcessor(AndroidDevice deviceInfo, UserSessionData user, + IHttpRequestProcessor httpRequestProcessor, IInstaLogger logger) + { + _deviceInfo = deviceInfo; + _user = user; + _httpRequestProcessor = httpRequestProcessor; + _logger = logger; + } + + public async Task> Search(string query, IEnumerable excludeList, + string rankToken) + { + var RequestHeaderFieldsTooLarge = (HttpStatusCode) 431; + var count = 50; + var tags = new InstaHashtagSearch(); + + try + { + var userUri = UriCreator.GetSearchTagUri(query, count, excludeList, rankToken); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + + if (response.StatusCode == RequestHeaderFieldsTooLarge) + return Result.Success(tags); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + + var tagsResponse = JsonConvert.DeserializeObject(json); + tags = ConvertersFabric.Instance.GetHashTagsSearchConverter(tagsResponse).Convert(); + + if (tags.Any() && excludeList != null && excludeList.Contains(tags.First().Id)) + tags.RemoveAt(0); + if (!tags.Any()) + tags = new InstaHashtagSearch(); + + return Result.Success(tags); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception, tags); + } + } + + public async Task> GetHashtagInfo(string tagname) + { + try + { + var userUri = UriCreator.GetTagInfoUri(tagname); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + + var tagInfoResponse = JsonConvert.DeserializeObject(json); + var tagInfo = ConvertersFabric.Instance.GetHashTagConverter(tagInfoResponse).Convert(); + + return Result.Success(tagInfo); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/ICollectionProcessor.cs b/InstaSharper/API/Processors/ICollectionProcessor.cs new file mode 100644 index 00000000..0098fe15 --- /dev/null +++ b/InstaSharper/API/Processors/ICollectionProcessor.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Models; + +namespace InstaSharper.API.Processors +{ + public interface ICollectionProcessor + { + Task> GetCollectionAsync(long collectionId); + + Task> GetCollectionsAsync(); + + Task> CreateCollectionAsync(string collectionName); + + Task> DeleteCollectionAsync(long collectionId); + + Task> AddItemsToCollectionAsync(long collectionId, params string[] mediaIds); + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/ICommentProcessor.cs b/InstaSharper/API/Processors/ICommentProcessor.cs new file mode 100644 index 00000000..bee85b05 --- /dev/null +++ b/InstaSharper/API/Processors/ICommentProcessor.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Models; + +namespace InstaSharper.API.Processors +{ + public interface ICommentProcessor + { + Task> + GetMediaCommentsAsync(string mediaId, PaginationParameters paginationParameters); + + Task> CommentMediaAsync(string mediaId, string text); + Task> DeleteCommentAsync(string mediaId, string commentId); + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/IFeedProcessor.cs b/InstaSharper/API/Processors/IFeedProcessor.cs new file mode 100644 index 00000000..6bbd780a --- /dev/null +++ b/InstaSharper/API/Processors/IFeedProcessor.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Models; + +namespace InstaSharper.API.Processors +{ + public interface IFeedProcessor + { + Task> GetTagFeedAsync(string tag, PaginationParameters paginationParameters); + Task> GetUserTimelineFeedAsync(PaginationParameters paginationParameters); + Task> GetExploreFeedAsync(PaginationParameters paginationParameters); + Task> GetFollowingRecentActivityFeedAsync(PaginationParameters paginationParameters); + Task> GetRecentActivityFeedAsync(PaginationParameters paginationParameters); + Task> GetLikeFeedAsync(PaginationParameters paginationParameters); + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/IHashtagProcessor.cs b/InstaSharper/API/Processors/IHashtagProcessor.cs new file mode 100644 index 00000000..3d223d69 --- /dev/null +++ b/InstaSharper/API/Processors/IHashtagProcessor.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Models; + +namespace InstaSharper.API.Processors +{ + public interface IHashtagProcessor + { + Task> Search(string query, IEnumerable excludeList = null, + string rankToken = null); + + Task> GetHashtagInfo(string tagname); + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/ILocationProcessor.cs b/InstaSharper/API/Processors/ILocationProcessor.cs new file mode 100644 index 00000000..36bc713e --- /dev/null +++ b/InstaSharper/API/Processors/ILocationProcessor.cs @@ -0,0 +1,13 @@ +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Models; + +namespace InstaSharper.API.Processors +{ + public interface ILocationProcessor + { + Task> Search(double latitude, double longitude, string query); + + Task> GetFeed(long locationId, PaginationParameters paginationParameters); + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/IMediaProcessor.cs b/InstaSharper/API/Processors/IMediaProcessor.cs new file mode 100644 index 00000000..64329c60 --- /dev/null +++ b/InstaSharper/API/Processors/IMediaProcessor.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Models; + +namespace InstaSharper.API.Processors +{ + public interface IMediaProcessor + { + Task> GetMediaIdFromUrlAsync(Uri uri); + + Task> DeleteMediaAsync(string mediaId, InstaMediaType mediaType); + + Task> EditMediaAsync(string mediaId, string caption); + + Task> UploadVideoAsync(InstaVideo video, InstaImage image, string caption); + + Task> UploadVideoThumbnailAsync(InstaImage image, string uploadId); + + Task> ConfigureVideoAsync(InstaVideo video, string uploadId, string caption); + + Task> ExposeVideoAsync(string uploadId); + + Task> UploadPhotoAsync(InstaImage image, string caption); + + Task> UploadPhotosAlbumAsync(InstaImage[] images, string caption); + + Task> ConfigurePhotoAsync(InstaImage image, string uploadId, string caption); + + Task> ConfigureAlbumAsync(string[] uploadId, string caption); + + Task> GetMediaLikersAsync(string mediaId); + + Task> LikeMediaAsync(string mediaId); + + Task> UnLikeMediaAsync(string mediaId); + + Task> GetMediaByIdAsync(string mediaId); + + Task> GetShareLinkFromMediaIdAsync(string mediaId); + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/IMessagingProcessor.cs b/InstaSharper/API/Processors/IMessagingProcessor.cs new file mode 100644 index 00000000..9a38651f --- /dev/null +++ b/InstaSharper/API/Processors/IMessagingProcessor.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; + +namespace InstaSharper.API.Processors +{ + public interface IMessagingProcessor + { + Task> GetDirectInboxAsync(); + Task> GetDirectInboxThreadAsync(string threadId); + Task> SendDirectMessage(string recipients, string threadIds, string text); + Task> GetRecentRecipientsAsync(); + Task> GetRankedRecipientsAsync(); + Task> SendLinkMessage(InstaMessageLink message, params long[] recipients); + Task> SendLinkMessage(InstaMessageLink message, params string[] threads); + Task> ShareMedia(string mediaId, InstaMediaType mediaType, params string[] threads); + Task> DeclineAllPendingDirectThreads(); + Task> ApprovePendingDirectThread(string threadId); + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/IStoryProcessor.cs b/InstaSharper/API/Processors/IStoryProcessor.cs new file mode 100644 index 00000000..8ed8ab00 --- /dev/null +++ b/InstaSharper/API/Processors/IStoryProcessor.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Models; + +namespace InstaSharper.API.Processors +{ + public interface IStoryProcessor + { + Task> GetStoryFeedAsync(); + Task> GetUserStoryAsync(long userId); + Task> UploadStoryPhotoAsync(InstaImage image, string caption); + Task> ConfigureStoryPhotoAsync(InstaImage image, string uploadId, string caption); + Task> GetUserStoryFeedAsync(long userId); + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/IUserProcessor.cs b/InstaSharper/API/Processors/IUserProcessor.cs new file mode 100644 index 00000000..7344ef3b --- /dev/null +++ b/InstaSharper/API/Processors/IUserProcessor.cs @@ -0,0 +1,31 @@ +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Models; + +namespace InstaSharper.API.Processors +{ + public interface IUserProcessor + { + Task> GetUserMediaAsync(long username, PaginationParameters paginationParameters); + Task> GetUserAsync(string username); + Task> SearchUsersAsync(string searchPattern); + Task> GetCurrentUserAsync(); + + Task> GetUserFollowersAsync(string username, + PaginationParameters paginationParameters, string searchQuery); + + Task> GetUserFollowingAsync(string username, + PaginationParameters paginationParameters, string searchQuery); + + Task> GetCurrentUserFollowersAsync(PaginationParameters paginationParameters); + Task> GetCurrentUserFollowingAsync(PaginationParameters paginationParameters); + Task> GetUserTagsAsync(long username, PaginationParameters paginationParameters); + Task> FollowUserAsync(long userId); + Task> UnFollowUserAsync(long userId); + Task> BlockUserAsync(long userId); + Task> UnBlockUserAsync(long userId); + Task> GetFriendshipStatusAsync(long userId); + Task> GetUserInfoByIdAsync(long pk); + Task> GetUserInfoByUsernameAsync(string username); + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/IUserProfileProcessor.cs b/InstaSharper/API/Processors/IUserProfileProcessor.cs new file mode 100644 index 00000000..e703f214 --- /dev/null +++ b/InstaSharper/API/Processors/IUserProfileProcessor.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Models; + +namespace InstaSharper.API.Processors +{ + public interface IUserProfileProcessor + { + Task> SetAccountPrivateAsync(); + + Task> SetAccountPublicAsync(); + + Task> ChangePasswordAsync(string oldPassword, string newPassword); + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/LocationProcessor.cs b/InstaSharper/API/Processors/LocationProcessor.cs new file mode 100644 index 00000000..81d18c4b --- /dev/null +++ b/InstaSharper/API/Processors/LocationProcessor.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using InstaSharper.API.UriCreators; +using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Converters; +using InstaSharper.Helpers; +using InstaSharper.Logger; +using Newtonsoft.Json; + +namespace InstaSharper.API.Processors +{ + internal class LocationProcessor : ILocationProcessor + { + private readonly AndroidDevice _deviceInfo; + private readonly IUriCreatorNextId _getFeedUriCreator = new GetLocationFeedUriCreator(); + private readonly IHttpRequestProcessor _httpRequestProcessor; + private readonly IInstaLogger _logger; + private readonly IUriCreator _searchLocationUriCreator = new SearchLocationUriCreator(); + private readonly UserSessionData _user; + + public LocationProcessor(AndroidDevice deviceInfo, UserSessionData user, + IHttpRequestProcessor httpRequestProcessor, IInstaLogger logger) + { + _deviceInfo = deviceInfo; + _user = user; + _httpRequestProcessor = httpRequestProcessor; + _logger = logger; + } + + public async Task> Search(double latitude, double longitude, string query) + { + try + { + var uri = _searchLocationUriCreator.GetUri(); + + var fields = new Dictionary + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk.ToString()}, + {"_csrftoken", _user.CsrfToken}, + {"latitude", latitude.ToString(CultureInfo.InvariantCulture)}, + {"longitude", longitude.ToString(CultureInfo.InvariantCulture)}, + {"rank_token", _user.RankToken} + }; + + if (!string.IsNullOrEmpty(query)) + fields.Add("search_query", query); + else + fields.Add("timestamp", DateTimeHelper.GetUnixTimestampSeconds().ToString()); + if (!Uri.TryCreate(uri, fields.AsQueryString(), out var newuri)) + return Result.Fail("Unable to create uri for location search"); + + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, newuri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var locations = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.Instance.GetLocationsSearchConverter(locations); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> GetFeed(long locationId, + PaginationParameters paginationParameters) + { + try + { + var uri = _getFeedUriCreator.GetUri(locationId, paginationParameters.NextId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + + var feedResponse = JsonConvert.DeserializeObject(json); + var feed = ConvertersFabric.Instance.GetLocationFeedConverter(feedResponse).Convert(); + paginationParameters.PagesLoaded++; + paginationParameters.NextId = feed.NextId; + + while (feedResponse.MoreAvailable + && !string.IsNullOrEmpty(paginationParameters.NextId) + && paginationParameters.PagesLoaded < paginationParameters.MaximumPagesToLoad) + { + var nextFeed = await GetFeed(locationId, paginationParameters); + if (!nextFeed.Succeeded) + return nextFeed; + paginationParameters.StartFromId(nextFeed.Value.NextId); + paginationParameters.PagesLoaded++; + feed.NextId = nextFeed.Value.NextId; + feed.Medias.AddRange(nextFeed.Value.Medias); + feed.RankedMedias.AddRange(nextFeed.Value.RankedMedias); + } + + return Result.Success(feed); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/MediaProcessor.cs b/InstaSharper/API/Processors/MediaProcessor.cs new file mode 100644 index 00000000..f571cb97 --- /dev/null +++ b/InstaSharper/API/Processors/MediaProcessor.cs @@ -0,0 +1,638 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using System.Web; +using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Converters; +using InstaSharper.Converters.Json; +using InstaSharper.Helpers; +using InstaSharper.Logger; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace InstaSharper.API.Processors +{ + internal class MediaProcessor : IMediaProcessor + { + private readonly AndroidDevice _deviceInfo; + private readonly IHttpRequestProcessor _httpRequestProcessor; + private readonly IInstaLogger _logger; + private readonly UserSessionData _user; + + public MediaProcessor(AndroidDevice deviceInfo, UserSessionData user, + IHttpRequestProcessor httpRequestProcessor, IInstaLogger logger) + { + _deviceInfo = deviceInfo; + _user = user; + _httpRequestProcessor = httpRequestProcessor; + _logger = logger; + } + + public async Task> GetMediaIdFromUrlAsync(Uri uri) + { + try + { + var collectionUri = UriCreator.GetMediaIdFromUrlUri(uri); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, collectionUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + + var data = JsonConvert.DeserializeObject(json); + return Result.Success(data.MediaId); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> DeleteMediaAsync(string mediaId, InstaMediaType mediaType) + { + try + { + var deleteMediaUri = UriCreator.GetDeleteMediaUri(mediaId, mediaType); + + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"media_id", mediaId} + }; + + var request = + HttpHelper.GetSignedRequest(HttpMethod.Get, deleteMediaUri, _deviceInfo, data); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + + var deletedResponse = JsonConvert.DeserializeObject(json); + return Result.Success(deletedResponse.IsDeleted); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> EditMediaAsync(string mediaId, string caption) + { + try + { + var editMediaUri = UriCreator.GetEditMediaUri(mediaId); + + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"caption_text", caption} + }; + + var request = HttpHelper.GetSignedRequest(HttpMethod.Get, editMediaUri, _deviceInfo, data); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + return Result.Success(true); + var error = JsonConvert.DeserializeObject(json); + return Result.Fail(error.Message, false); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> UploadVideoAsync(InstaVideo video, InstaImage imageThumbnail, + string caption) + { + try + { + var instaUri = UriCreator.GetUploadVideoUri(); + var uploadId = ApiRequestMessage.GenerateUploadId(); + var requestContent = new MultipartFormDataContent(uploadId) + { + {new StringContent("2"), "\"media_type\""}, + {new StringContent(uploadId), "\"upload_id\""}, + {new StringContent(_deviceInfo.DeviceGuid.ToString()), "\"_uuid\""}, + {new StringContent(_user.CsrfToken), "\"_csrftoken\""}, + { + new StringContent("{\"lib_name\":\"jt\",\"lib_version\":\"1.3.0\",\"quality\":\"87\"}"), + "\"image_compression\"" + } + }; + + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); + request.Content = requestContent; + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + + var videoResponse = JsonConvert.DeserializeObject(json); + if (videoResponse == null) + return Result.Fail("Failed to get response from instagram video upload endpoint"); + + var fileBytes = File.ReadAllBytes(video.Url); + var first = videoResponse.VideoUploadUrls[0]; + instaUri = new Uri(HttpUtility.UrlDecode(first.Url)); + + + requestContent = new MultipartFormDataContent(uploadId) + { + {new StringContent(_user.CsrfToken), "\"_csrftoken\""}, + { + new StringContent("{\"lib_name\":\"jt\",\"lib_version\":\"1.3.0\",\"quality\":\"87\"}"), + "\"image_compression\"" + } + }; + + + var videoContent = new ByteArrayContent(fileBytes); + videoContent.Headers.Add("Content-Transfer-Encoding", "binary"); + videoContent.Headers.Add("Content-Type", "application/octet-stream"); + videoContent.Headers.Add("Content-Disposition", + $"attachment; filename=\"{Path.GetFileName(video.Url)}\""); + requestContent.Add(videoContent); + request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); + request.Content = requestContent; + request.Headers.Host = "upload.instagram.com"; + request.Headers.Add("Cookie2", "$Version=1"); + request.Headers.Add("Session-ID", uploadId); + request.Headers.Add("job", first.Job); + response = await _httpRequestProcessor.SendAsync(request); + json = await response.Content.ReadAsStringAsync(); + + await UploadVideoThumbnailAsync(imageThumbnail, uploadId); + + return await ConfigureVideoAsync(video, uploadId, caption); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> UploadVideoThumbnailAsync(InstaImage image, string uploadId) + { + try + { + var instaUri = UriCreator.GetUploadPhotoUri(); + var requestContent = new MultipartFormDataContent(uploadId) + { + {new StringContent(uploadId), "\"upload_id\""}, + {new StringContent(_deviceInfo.DeviceGuid.ToString()), "\"_uuid\""}, + {new StringContent(_user.CsrfToken), "\"_csrftoken\""}, + { + new StringContent("{\"lib_name\":\"jt\",\"lib_version\":\"1.3.0\",\"quality\":\"87\"}"), + "\"image_compression\"" + } + }; + + var imageContent = new ByteArrayContent(File.ReadAllBytes(image.URI)); + imageContent.Headers.Add("Content-Transfer-Encoding", "binary"); + imageContent.Headers.Add("Content-Type", "application/octet-stream"); + requestContent.Add(imageContent, "photo", $"pending_media_{uploadId}.jpg"); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); + request.Content = requestContent; + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + var imgResp = JsonConvert.DeserializeObject(json); + if (imgResp.Status.ToLower() == "ok") + return Result.Success(true); + return Result.Fail("Could not upload thumbnail"); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> ConfigureVideoAsync(InstaVideo video, string uploadId, string caption) + { + try + { + var instaUri = UriCreator.GetMediaConfigureUri(); + var androidVersion = + AndroidVersion.FromString(_deviceInfo.FirmwareFingerprint.Split('/')[2].Split(':')[1]); + if (androidVersion == null) + return Result.Fail("Unsupported android version", (InstaMedia) null); + var data = new JObject + { + {"caption", caption}, + {"upload_id", uploadId}, + {"source_type", "3"}, + {"camera_position", "unknown"}, + { + "extra", new JObject + { + {"source_width", video.Width}, + {"source_height", video.Height} + } + }, + { + "clips", new JArray + { + new JObject + { + {"length", 10.0}, + {"creation_date", DateTime.Now.ToString("yyyy-dd-MMTh:mm:ss-0fff")}, + {"source_type", "3"}, + {"camera_position", "back"} + } + } + }, + {"poster_frame_index", 0}, + {"audio_muted", false}, + {"filter_type", "0"}, + {"video_result", "deprecated"}, + {"_csrftoken", _user.CsrfToken}, + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.UserName} + }; + + var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, data); + request.Headers.Host = "i.instagram.com"; + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (!response.IsSuccessStatusCode) + return Result.UnExpectedResponse(response, json); + + var success = await ExposeVideoAsync(uploadId); + if (success.Succeeded) + return Result.Success(success.Value); + return Result.Fail("Cannot expose media"); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> ExposeVideoAsync(string uploadId) + { + try + { + var instaUri = UriCreator.GetMediaConfigureUri(); + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"experiment", "ig_android_profile_contextual_feed"}, + {"id", _user.LoggedInUser.Pk}, + {"upload_id", uploadId} + }; + + var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, data); + request.Headers.Host = "i.instagram.com"; + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + var jObject = JsonConvert.DeserializeObject(json); + + if (jObject.Status.ToLower() == "ok") + { + var mediaResponse = JsonConvert.DeserializeObject(json, + new InstaMediaDataConverter()); + var converter = ConvertersFabric.Instance.GetSingleMediaConverter(mediaResponse); + return Result.Success(converter.Convert()); + } + + return Result.Fail(jObject.Status); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> UploadPhotoAsync(InstaImage image, string caption) + { + try + { + var instaUri = UriCreator.GetUploadPhotoUri(); + var uploadId = ApiRequestMessage.GenerateUploadId(); + var requestContent = new MultipartFormDataContent(uploadId) + { + {new StringContent(uploadId), "\"upload_id\""}, + {new StringContent(_deviceInfo.DeviceGuid.ToString()), "\"_uuid\""}, + {new StringContent(_user.CsrfToken), "\"_csrftoken\""}, + { + new StringContent("{\"lib_name\":\"jt\",\"lib_version\":\"1.3.0\",\"quality\":\"87\"}"), + "\"image_compression\"" + } + }; + var imageContent = new ByteArrayContent(File.ReadAllBytes(image.URI)); + imageContent.Headers.Add("Content-Transfer-Encoding", "binary"); + imageContent.Headers.Add("Content-Type", "application/octet-stream"); + requestContent.Add(imageContent, "photo", $"pending_media_{ApiRequestMessage.GenerateUploadId()}.jpg"); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); + request.Content = requestContent; + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.IsSuccessStatusCode) + return await ConfigurePhotoAsync(image, uploadId, caption); + return Result.UnExpectedResponse(response, json); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> UploadPhotosAlbumAsync(InstaImage[] images, string caption) + { + try + { + var uploadIds = new string[images.Length]; + var index = 0; + + foreach (var image in images) + { + var instaUri = UriCreator.GetUploadPhotoUri(); + var uploadId = ApiRequestMessage.GenerateUploadId(); + var requestContent = new MultipartFormDataContent(uploadId) + { + {new StringContent(uploadId), "\"upload_id\""}, + {new StringContent(_deviceInfo.DeviceGuid.ToString()), "\"_uuid\""}, + {new StringContent(_user.CsrfToken), "\"_csrftoken\""}, + { + new StringContent("{\"lib_name\":\"jt\",\"lib_version\":\"1.3.0\",\"quality\":\"87\"}"), + "\"image_compression\"" + }, + {new StringContent("1"), "\"is_sidecar\""} + }; + var imageContent = new ByteArrayContent(File.ReadAllBytes(image.URI)); + imageContent.Headers.Add("Content-Transfer-Encoding", "binary"); + imageContent.Headers.Add("Content-Type", "application/octet-stream"); + requestContent.Add(imageContent, "photo", + $"pending_media_{ApiRequestMessage.GenerateUploadId()}.jpg"); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); + request.Content = requestContent; + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.IsSuccessStatusCode) + uploadIds[index++] = uploadId; + else + return Result.UnExpectedResponse(response, json); + } + + return await ConfigureAlbumAsync(uploadIds, caption); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> ConfigurePhotoAsync(InstaImage image, string uploadId, string caption) + { + try + { + var instaUri = UriCreator.GetMediaConfigureUri(); + var androidVersion = + AndroidVersion.FromString(_deviceInfo.FirmwareFingerprint.Split('/')[2].Split(':')[1]); + if (androidVersion == null) + return Result.Fail("Unsupported android version", (InstaMedia) null); + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"media_folder", "Camera"}, + {"source_type", "4"}, + {"caption", caption}, + {"upload_id", uploadId}, + { + "device", new JObject + { + {"manufacturer", _deviceInfo.HardwareManufacturer}, + {"model", _deviceInfo.HardwareModel}, + {"android_version", androidVersion.VersionNumber}, + {"android_release", androidVersion.APILevel} + } + }, + { + "edits", new JObject + { + {"crop_original_size", new JArray {image.Width, image.Height}}, + {"crop_center", new JArray {0.0, -0.0}}, + {"crop_zoom", 1} + } + }, + { + "extra", new JObject + { + {"source_width", image.Width}, + {"source_height", image.Height} + } + } + }; + var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, data); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (!response.IsSuccessStatusCode) + return Result.UnExpectedResponse(response, json); + var mediaResponse = + JsonConvert.DeserializeObject(json, new InstaMediaDataConverter()); + var converter = ConvertersFabric.Instance.GetSingleMediaConverter(mediaResponse); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> ConfigureAlbumAsync(string[] uploadId, string caption) + { + try + { + var instaUri = UriCreator.GetMediaAlbumConfigureUri(); + var clientSidecarId = ApiRequestMessage.GenerateUploadId(); + + var childrenArray = new JArray(); + + foreach (var id in uploadId) + childrenArray.Add(new JObject + { + {"scene_capture_type", "standard"}, + {"mas_opt_in", "NOT_PROMPTED"}, + {"camera_position", "unknown"}, + {"allow_multi_configures", false}, + {"geotag_enabled", false}, + {"disable_comments", false}, + {"source_type", 0}, + {"upload_id", id} + }); + + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"caption", caption}, + {"client_sidecar_id", clientSidecarId}, + {"geotag_enabled", false}, + {"disable_comments", false}, + {"children_metadata", childrenArray} + }; + var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, data); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (!response.IsSuccessStatusCode) + return Result.UnExpectedResponse(response, json); + var mediaResponse = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.Instance.GetSingleMediaConverter(mediaResponse?.Media); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> GetMediaLikersAsync(string mediaId) + { + try + { + var likers = new InstaLikersList(); + var likersUri = UriCreator.GetMediaLikersUri(mediaId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, likersUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var mediaLikersResponse = JsonConvert.DeserializeObject(json); + likers.UsersCount = mediaLikersResponse.UsersCount; + if (mediaLikersResponse.UsersCount < 1) return Result.Success(likers); + likers.AddRange( + mediaLikersResponse.Users.Select(ConvertersFabric.Instance.GetUserShortConverter) + .Select(converter => converter.Convert())); + return Result.Success(likers); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> LikeMediaAsync(string mediaId) + { + try + { + return await LikeUnlikeMediaInternal(mediaId, UriCreator.GetLikeMediaUri(mediaId)); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> UnLikeMediaAsync(string mediaId) + { + try + { + return await LikeUnlikeMediaInternal(mediaId, UriCreator.GetUnLikeMediaUri(mediaId)); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> GetMediaByIdAsync(string mediaId) + { + try + { + var mediaUri = UriCreator.GetMediaUri(mediaId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, mediaUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var mediaResponse = JsonConvert.DeserializeObject(json, + new InstaMediaListDataConverter()); + if (mediaResponse.Medias?.Count > 1) + { + var errorMessage = $"Got wrong media count for request with media id={mediaId}"; + _logger?.LogInfo(errorMessage); + return Result.Fail(errorMessage); + } + + var converter = + ConvertersFabric.Instance.GetSingleMediaConverter(mediaResponse.Medias.FirstOrDefault()); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> GetShareLinkFromMediaIdAsync(string mediaId) + { + try + { + var collectionUri = UriCreator.GetShareLinkFromMediaId(mediaId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, collectionUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + + var data = JsonConvert.DeserializeObject(json); + return Result.Success(new Uri(data.Permalink)); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + private async Task> LikeUnlikeMediaInternal(string mediaId, Uri instaUri) + { + var fields = new Dictionary + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk.ToString()}, + {"_csrftoken", _user.CsrfToken}, + {"media_id", mediaId} + }; + var request = + HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + return response.StatusCode == HttpStatusCode.OK + ? Result.Success(true) + : Result.UnExpectedResponse(response, json); + } + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/MessagingProcessor.cs b/InstaSharper/API/Processors/MessagingProcessor.cs new file mode 100644 index 00000000..9a0aebb8 --- /dev/null +++ b/InstaSharper/API/Processors/MessagingProcessor.cs @@ -0,0 +1,314 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using InstaSharper.Converters; +using InstaSharper.Converters.Json; +using InstaSharper.Helpers; +using InstaSharper.Logger; +using Newtonsoft.Json; + +namespace InstaSharper.API.Processors +{ + public class MessagingProcessor : IMessagingProcessor + { + private readonly AndroidDevice _deviceInfo; + private readonly IHttpRequestProcessor _httpRequestProcessor; + private readonly IInstaLogger _logger; + private readonly UserSessionData _user; + + public MessagingProcessor(AndroidDevice deviceInfo, UserSessionData user, + IHttpRequestProcessor httpRequestProcessor, + IInstaLogger logger) + { + _deviceInfo = deviceInfo; + _user = user; + _httpRequestProcessor = httpRequestProcessor; + _logger = logger; + } + + public async Task> GetDirectInboxAsync() + { + try + { + var directInboxUri = UriCreator.GetDirectInboxUri(); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, directInboxUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var inboxResponse = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.Instance.GetDirectInboxConverter(inboxResponse); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + public async Task> GetDirectInboxThreadAsync(string threadId) + { + try + { + var directInboxUri = UriCreator.GetDirectInboxThreadUri(threadId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, directInboxUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var threadResponse = JsonConvert.DeserializeObject(json, + new InstaThreadDataConverter()); + var converter = ConvertersFabric.Instance.GetDirectThreadConverter(threadResponse); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + public async Task> SendLinkMessage(InstaMessageLink message, params long[] recipients) + { + var threads = new InstaDirectInboxThreadList(); + try + { + var directSendMessageUri = UriCreator.GetDirectSendLinkMessageUri(); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, directSendMessageUri, _deviceInfo); + var fields = new Dictionary + { + {"link_text", message.Text}, + {"link_urls", $"[\"{message.Url}\"]"}, + {"action", "send_item"} + }; + + if (recipients == null || recipients.Length < 1) + return Result.Fail("Please provide at least one recipient."); + + fields.Add("recipient_users", "[[" + string.Join(",", recipients) + "]]"); + request.Content = new FormUrlEncodedContent(fields); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var result = JsonConvert.DeserializeObject(json); + if (!result.IsOk()) return Result.Fail(result.Status); + threads.AddRange(result.Threads.Select(thread => + ConvertersFabric.Instance.GetDirectThreadConverter(thread).Convert())); + return Result.Success(threads); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> SendLinkMessage(InstaMessageLink message, params string[] threads) + { + var threadList = new InstaDirectInboxThreadList(); + try + { + var directSendMessageUri = UriCreator.GetDirectSendLinkMessageUri(); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, directSendMessageUri, _deviceInfo); + var fields = new Dictionary + { + {"link_text", message.Text}, + {"link_urls", $"[\"{message.Url}\"]"}, + {"action", "send_item"} + }; + + if (threads == null || threads.Length < 1) + return Result.Fail("Please provide at least one recipient."); + fields.Add("thread_ids", "[" + string.Join(",", threads) + "]"); + + request.Content = new FormUrlEncodedContent(fields); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var result = JsonConvert.DeserializeObject(json); + if (!result.IsOk()) return Result.Fail(result.Status); + threadList.AddRange(result.Threads.Select(thread => + ConvertersFabric.Instance.GetDirectThreadConverter(thread).Convert())); + return Result.Success(threadList); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> ShareMedia(string mediaId, InstaMediaType mediaType, + params string[] threads) + { + var threadList = new InstaDirectInboxThreadList(); + try + { + var directSendMessageUri = UriCreator.GetShareMediaUri(mediaType); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, directSendMessageUri, _deviceInfo); + var fields = new Dictionary + { + {"media_id", mediaId}, + {"unified_broadcast_format", "1"}, + {"action", "send_item"} + }; + + if (threads == null || threads.Length < 1) + return Result.Fail("Please provide at least one thread."); + fields.Add("thread_ids", "[" + string.Join(",", threads) + "]"); + + request.Content = new FormUrlEncodedContent(fields); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var result = JsonConvert.DeserializeObject(json); + if (!result.IsOk()) return Result.Fail(result.Status); + threadList.AddRange(result.Threads.Select(thread => + ConvertersFabric.Instance.GetDirectThreadConverter(thread).Convert())); + return Result.Success(threadList); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> SendDirectMessage(string recipients, string threadIds, + string text) + { + var threads = new InstaDirectInboxThreadList(); + try + { + var directSendMessageUri = UriCreator.GetDirectSendTextMessageUri(); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, directSendMessageUri, _deviceInfo); + var fields = new Dictionary + { + {"text", text}, + {"action", "send_item"} + }; + if (!string.IsNullOrEmpty(recipients)) + fields.Add("recipient_users", "[[" + recipients + "]]"); + else + return Result.Fail("Please provide at least one recipient."); + if (!string.IsNullOrEmpty(threadIds)) + fields.Add("thread_ids", "[" + threadIds + "]"); + + request.Content = new FormUrlEncodedContent(fields); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var result = JsonConvert.DeserializeObject(json); + if (!result.IsOk()) return Result.Fail(result.Status); + threads.AddRange(result.Threads.Select(thread => + ConvertersFabric.Instance.GetDirectThreadConverter(thread).Convert())); + return Result.Success(threads); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> DeclineAllPendingDirectThreads() + { + try + { + var uri = UriCreator.GetDeclineAllPendingThreadsUri(); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, uri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var result = JsonConvert.DeserializeObject(json); + return !result.IsOk() + ? Result.Fail(result.Status) + : Result.Success(result); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> ApprovePendingDirectThread(string threadId) + { + try + { + var uri = UriCreator.GetApproveThreadUri(threadId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, uri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var result = JsonConvert.DeserializeObject(json); + return !result.IsOk() + ? Result.Fail(result.Status) + : Result.Success(result); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception); + } + } + + public async Task> GetRecentRecipientsAsync() + { + try + { + var userUri = UriCreator.GetRecentRecipientsUri(); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var responseRecipients = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.Instance.GetRecipientsConverter(responseRecipients); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + public async Task> GetRankedRecipientsAsync() + { + try + { + var userUri = UriCreator.GetRankedRecipientsUri(); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var responseRecipients = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.Instance.GetRecipientsConverter(responseRecipients); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/StoryProcessor.cs b/InstaSharper/API/Processors/StoryProcessor.cs new file mode 100644 index 00000000..11abf493 --- /dev/null +++ b/InstaSharper/API/Processors/StoryProcessor.cs @@ -0,0 +1,170 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Converters; +using InstaSharper.Helpers; +using InstaSharper.Logger; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace InstaSharper.API.Processors +{ + public class StoryProcessor : IStoryProcessor + { + private readonly AndroidDevice _deviceInfo; + private readonly IHttpRequestProcessor _httpRequestProcessor; + private readonly IInstaLogger _logger; + private readonly UserSessionData _user; + + public StoryProcessor(AndroidDevice deviceInfo, UserSessionData user, + IHttpRequestProcessor httpRequestProcessor, IInstaLogger logger) + { + _deviceInfo = deviceInfo; + _user = user; + _httpRequestProcessor = httpRequestProcessor; + _logger = logger; + } + + public async Task> GetStoryFeedAsync() + { + try + { + var storyFeedUri = UriCreator.GetStoryFeedUri(); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, storyFeedUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaStoryFeed) null); + var storyFeedResponse = JsonConvert.DeserializeObject(json); + var instaStoryFeed = ConvertersFabric.Instance.GetStoryFeedConverter(storyFeedResponse).Convert(); + return Result.Success(instaStoryFeed); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + public async Task> GetUserStoryAsync(long userId) + { + try + { + var userStoryUri = UriCreator.GetUserStoryUri(userId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userStoryUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + + if (response.StatusCode != HttpStatusCode.OK) Result.UnExpectedResponse(response, json); + var userStoryResponse = JsonConvert.DeserializeObject(json); + var userStory = ConvertersFabric.Instance.GetStoryConverter(userStoryResponse).Convert(); + return Result.Success(userStory); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + public async Task> UploadStoryPhotoAsync(InstaImage image, string caption) + { + try + { + var instaUri = UriCreator.GetUploadPhotoUri(); + var uploadId = ApiRequestMessage.GenerateUploadId(); + var requestContent = new MultipartFormDataContent(uploadId) + { + {new StringContent(uploadId), "\"upload_id\""}, + {new StringContent(_deviceInfo.DeviceGuid.ToString()), "\"_uuid\""}, + {new StringContent(_user.CsrfToken), "\"_csrftoken\""}, + { + new StringContent("{\"lib_name\":\"jt\",\"lib_version\":\"1.3.0\",\"quality\":\"87\"}"), + "\"image_compression\"" + } + }; + var imageContent = new ByteArrayContent(File.ReadAllBytes(image.URI)); + imageContent.Headers.Add("Content-Transfer-Encoding", "binary"); + imageContent.Headers.Add("Content-Type", "application/octet-stream"); + requestContent.Add(imageContent, "photo", $"pending_media_{ApiRequestMessage.GenerateUploadId()}.jpg"); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); + request.Content = requestContent; + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.IsSuccessStatusCode) + return await ConfigureStoryPhotoAsync(image, uploadId, caption); + return Result.UnExpectedResponse(response, json); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + public async Task> ConfigureStoryPhotoAsync(InstaImage image, string uploadId, + string caption) + { + try + { + var instaUri = UriCreator.GetStoryConfigureUri(); + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"source_type", "1"}, + {"caption", caption}, + {"upload_id", uploadId}, + {"edits", new JObject()}, + {"disable_comments", false}, + {"configure_mode", 1}, + {"camera_position", "unknown"} + }; + var request = HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, data); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.IsSuccessStatusCode) + { + var mediaResponse = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.Instance.GetStoryMediaConverter(mediaResponse); + return Result.Success(converter.Convert()); + } + + return Result.UnExpectedResponse(response, json); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + public async Task> GetUserStoryFeedAsync(long userId) + { + var feed = new InstaReelFeed(); + try + { + var userFeedUri = UriCreator.GetUserReelFeedUri(userId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userFeedUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var feedResponse = JsonConvert.DeserializeObject(json); + feed = ConvertersFabric.Instance.GetReelFeedConverter(feedResponse).Convert(); + return Result.Success(feed); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message, feed); + } + } + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/UserProcessor.cs b/InstaSharper/API/Processors/UserProcessor.cs new file mode 100644 index 00000000..3ba27979 --- /dev/null +++ b/InstaSharper/API/Processors/UserProcessor.cs @@ -0,0 +1,469 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Converters; +using InstaSharper.Converters.Json; +using InstaSharper.Helpers; +using InstaSharper.Logger; +using Newtonsoft.Json; + +namespace InstaSharper.API.Processors +{ + public class UserProcessor : IUserProcessor + { + private readonly AndroidDevice _deviceInfo; + private readonly IHttpRequestProcessor _httpRequestProcessor; + private readonly IInstaLogger _logger; + private readonly UserSessionData _user; + + public UserProcessor(AndroidDevice deviceInfo, UserSessionData user, IHttpRequestProcessor httpRequestProcessor, + IInstaLogger logger) + { + _deviceInfo = deviceInfo; + _user = user; + _httpRequestProcessor = httpRequestProcessor; + _logger = logger; + } + + public async Task> GetUserMediaAsync(long userId, + PaginationParameters paginationParameters) + { + var mediaList = new InstaMediaList(); + try + { + var instaUri = UriCreator.GetUserMediaListUri(userId, paginationParameters.NextId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var mediaResponse = JsonConvert.DeserializeObject(json, + new InstaMediaListDataConverter()); + + mediaList = ConvertersFabric.Instance.GetMediaListConverter(mediaResponse).Convert(); + mediaList.NextId = paginationParameters.NextId = mediaResponse.NextMaxId; + paginationParameters.PagesLoaded++; + + while (mediaResponse.MoreAvailable + && !string.IsNullOrEmpty(paginationParameters.NextId) + && paginationParameters.PagesLoaded < paginationParameters.MaximumPagesToLoad) + { + var nextMedia = await GetUserMediaAsync(userId, paginationParameters); + if (!nextMedia.Succeeded) + return Result.Fail(nextMedia.Info, mediaList); + mediaList.NextId = paginationParameters.NextId = nextMedia.Value.NextId; + mediaList.AddRange(nextMedia.Value); + } + + mediaList.Pages = paginationParameters.PagesLoaded; + mediaList.PageSize = mediaResponse.ResultsCount; + return Result.Success(mediaList); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception, mediaList); + } + } + + public async Task> GetUserAsync(string username) + { + try + { + var userUri = UriCreator.GetUserUri(username); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_TIMEZONE, + InstaApiConstants.TIMEZONE_OFFSET.ToString())); + request.Properties.Add(new KeyValuePair(InstaApiConstants.HEADER_COUNT, "1")); + request.Properties.Add( + new KeyValuePair(InstaApiConstants.HEADER_RANK_TOKEN, _user.RankToken)); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var userInfo = JsonConvert.DeserializeObject(json); + var user = userInfo.Users?.FirstOrDefault(u => u.UserName == username); + if (user == null) + { + var errorMessage = $"Can't find this user: {username}"; + _logger?.LogInfo(errorMessage); + return Result.Fail(errorMessage); + } + + if (user.Pk < 1) + Result.Fail("Pk is incorrect"); + var converter = ConvertersFabric.Instance.GetUserConverter(user); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + + public async Task> SearchUsersAsync(string searchPattern) + { + try + { + var userUri = UriCreator.GetUserUri(searchPattern); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var userInfo = JsonConvert.DeserializeObject(json); + var userList = new InstaUserShortList(); + foreach (var userInfoItem in userInfo.Items) + userList.Add(ConvertersFabric.Instance.GetUserShortConverter(userInfoItem).Convert()); + return Result.Success(userList); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + + public async Task> GetUserInfoByIdAsync(long pk) + { + try + { + var userUri = UriCreator.GetUserInfoByIdUri(pk); + return await GetUserInfoAsync(userUri); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + public async Task> GetUserInfoByUsernameAsync(string username) + { + try + { + var userUri = UriCreator.GetUserInfoByUsernameUri(username); + return await GetUserInfoAsync(userUri); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + public async Task> GetCurrentUserAsync() + { + try + { + var instaUri = UriCreator.GetCurrentUserUri(); + var fields = new Dictionary + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk.ToString()}, + {"_csrftoken", _user.CsrfToken} + }; + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); + request.Content = new FormUrlEncodedContent(fields); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var user = JsonConvert.DeserializeObject(json, + new InstaCurrentUserDataConverter()); + if (user.Pk < 1) + Result.Fail("Pk is incorrect"); + var converter = ConvertersFabric.Instance.GetCurrentUserConverter(user); + var userConverted = converter.Convert(); + return Result.Success(userConverted); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + public async Task> GetUserFollowersAsync(string username, + PaginationParameters paginationParameters, string searchQuery) + { + var followers = new InstaUserShortList(); + try + { + var user = await GetUserAsync(username); + var userFollowersUri = + UriCreator.GetUserFollowersUri(user.Value.Pk, _user.RankToken, searchQuery, + paginationParameters.NextId); + var followersResponse = await GetUserListByUriAsync(userFollowersUri); + if (!followersResponse.Succeeded) + return Result.Fail(followersResponse.Info, (InstaUserShortList) null); + followers.AddRange( + followersResponse.Value.Items?.Select(ConvertersFabric.Instance.GetUserShortConverter) + .Select(converter => converter.Convert())); + followers.NextId = followersResponse.Value.NextMaxId; + + var pagesLoaded = 1; + while (!string.IsNullOrEmpty(followersResponse.Value.NextMaxId) + && pagesLoaded < paginationParameters.MaximumPagesToLoad) + { + var nextFollowersUri = + UriCreator.GetUserFollowersUri(user.Value.Pk, _user.RankToken, searchQuery, + followersResponse.Value.NextMaxId); + followersResponse = await GetUserListByUriAsync(nextFollowersUri); + if (!followersResponse.Succeeded) + return Result.Fail(followersResponse.Info, followers); + followers.AddRange( + followersResponse.Value.Items?.Select(ConvertersFabric.Instance.GetUserShortConverter) + .Select(converter => converter.Convert())); + pagesLoaded++; + followers.NextId = followersResponse.Value.NextMaxId; + } + + return Result.Success(followers); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception, followers); + } + } + + public async Task> GetUserFollowingAsync(string username, + PaginationParameters paginationParameters, string searchQuery) + { + var following = new InstaUserShortList(); + try + { + var user = await GetUserAsync(username); + var uri = UriCreator.GetUserFollowingUri(user.Value.Pk, _user.RankToken, searchQuery, + paginationParameters.NextId); + var userListResponse = await GetUserListByUriAsync(uri); + if (!userListResponse.Succeeded) + return Result.Fail(userListResponse.Info, (InstaUserShortList) null); + following.AddRange( + userListResponse.Value.Items.Select(ConvertersFabric.Instance.GetUserShortConverter) + .Select(converter => converter.Convert())); + following.NextId = userListResponse.Value.NextMaxId; + var pages = 1; + while (!string.IsNullOrEmpty(following.NextId) + && pages < paginationParameters.MaximumPagesToLoad) + { + var nextUri = + UriCreator.GetUserFollowingUri(user.Value.Pk, _user.RankToken, searchQuery, + userListResponse.Value.NextMaxId); + userListResponse = await GetUserListByUriAsync(nextUri); + if (!userListResponse.Succeeded) + return Result.Fail(userListResponse.Info, following); + following.AddRange( + userListResponse.Value.Items.Select(ConvertersFabric.Instance.GetUserShortConverter) + .Select(converter => converter.Convert())); + pages++; + following.NextId = userListResponse.Value.NextMaxId; + } + + return Result.Success(following); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception, following); + } + } + + public async Task> GetCurrentUserFollowersAsync( + PaginationParameters paginationParameters) + { + return await GetUserFollowersAsync(_user.UserName, paginationParameters, string.Empty); + } + + public async Task> GetCurrentUserFollowingAsync( + PaginationParameters paginationParameters) + { + return await GetUserFollowingAsync(_user.UserName, paginationParameters, string.Empty); + } + + public async Task> GetUserTagsAsync(long userId, + PaginationParameters paginationParameters) + { + var userTags = new InstaMediaList(); + try + { + var uri = UriCreator.GetUserTagsUri(userId, _user.RankToken, paginationParameters.NextId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) return Result.Fail("", (InstaMediaList) null); + var mediaResponse = JsonConvert.DeserializeObject(json, + new InstaMediaListDataConverter()); + userTags.AddRange( + mediaResponse.Medias.Select(ConvertersFabric.Instance.GetSingleMediaConverter) + .Select(converter => converter.Convert())); + userTags.NextId = paginationParameters.NextId = mediaResponse.NextMaxId; + paginationParameters.PagesLoaded++; + + while (mediaResponse.MoreAvailable + && !string.IsNullOrEmpty(paginationParameters.NextId) + && paginationParameters.PagesLoaded < paginationParameters.MaximumPagesToLoad) + { + var nextMedia = await GetUserTagsAsync(userId, paginationParameters); + if (!nextMedia.Succeeded) + return nextMedia; + + userTags.AddRange(nextMedia.Value); + userTags.NextId = paginationParameters.NextId = nextMedia.Value.NextId; + } + + return Result.Success(userTags); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception, userTags); + } + } + + public async Task> FollowUserAsync(long userId) + { + return await FollowUnfollowUserInternal(userId, UriCreator.GetFollowUserUri(userId)); + } + + public async Task> UnFollowUserAsync(long userId) + { + return await FollowUnfollowUserInternal(userId, UriCreator.GetUnFollowUserUri(userId)); + } + + public async Task> BlockUserAsync(long userId) + { + return await BlockUnblockUserInternal(userId, UriCreator.GetBlockUserUri(userId)); + } + + public async Task> UnBlockUserAsync(long userId) + { + return await BlockUnblockUserInternal(userId, UriCreator.GetUnBlockUserUri(userId)); + } + + public async Task> GetFriendshipStatusAsync(long userId) + { + try + { + var userUri = UriCreator.GetUserFriendshipUri(userId); + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var friendshipStatusResponse = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.Instance.GetFriendShipStatusConverter(friendshipStatusResponse); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + private async Task> GetUserInfoAsync(Uri userUri) + { + try + { + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, userUri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var userInfo = JsonConvert.DeserializeObject(json); + var converter = ConvertersFabric.Instance.GetUserInfoConverter(userInfo); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message); + } + } + + private async Task> FollowUnfollowUserInternal(long userId, Uri instaUri) + { + try + { + var fields = new Dictionary + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk.ToString()}, + {"_csrftoken", _user.CsrfToken}, + {"user_id", userId.ToString()}, + {"radio_type", "wifi-none"} + }; + var request = + HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK || string.IsNullOrEmpty(json)) + return Result.UnExpectedResponse(response, json); + var friendshipStatus = JsonConvert.DeserializeObject(json, + new InstaFriendShipDataConverter()); + var converter = ConvertersFabric.Instance.GetFriendShipStatusConverter(friendshipStatus); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message, (InstaFriendshipStatus) null); + } + } + + private async Task> BlockUnblockUserInternal(long userId, Uri instaUri) + { + try + { + var fields = new Dictionary + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk.ToString()}, + {"_csrftoken", _user.CsrfToken}, + {"user_id", userId.ToString()}, + {"radio_type", "wifi-none"} + }; + var request = + HttpHelper.GetSignedRequest(HttpMethod.Post, instaUri, _deviceInfo, fields); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK || string.IsNullOrEmpty(json)) + return Result.UnExpectedResponse(response, json); + var friendshipStatus = JsonConvert.DeserializeObject(json, + new InstaFriendShipDataConverter()); + var converter = ConvertersFabric.Instance.GetFriendShipStatusConverter(friendshipStatus); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message, (InstaFriendshipStatus) null); + } + } + + private async Task> GetUserListByUriAsync(Uri uri) + { + var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, uri, _deviceInfo); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var instaUserListResponse = JsonConvert.DeserializeObject(json); + if (instaUserListResponse.IsOk()) + return Result.Success(instaUserListResponse); + return Result.UnExpectedResponse(response, json); + } + } +} \ No newline at end of file diff --git a/InstaSharper/API/Processors/UserProfileProcessor.cs b/InstaSharper/API/Processors/UserProfileProcessor.cs new file mode 100644 index 00000000..70a6a061 --- /dev/null +++ b/InstaSharper/API/Processors/UserProfileProcessor.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using InstaSharper.Classes; +using InstaSharper.Classes.Android.DeviceInfo; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Converters; +using InstaSharper.Converters.Json; +using InstaSharper.Helpers; +using InstaSharper.Logger; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace InstaSharper.API.Processors +{ + public class UserProfileProcessor : IUserProfileProcessor + { + private readonly AndroidDevice _deviceInfo; + private readonly IHttpRequestProcessor _httpRequestProcessor; + private readonly IInstaLogger _logger; + private readonly UserSessionData _user; + + public UserProfileProcessor(AndroidDevice deviceInfo, UserSessionData user, + IHttpRequestProcessor httpRequestProcessor, IInstaLogger logger) + { + _deviceInfo = deviceInfo; + _user = user; + _httpRequestProcessor = httpRequestProcessor; + _logger = logger; + } + + public async Task> SetAccountPrivateAsync() + { + try + { + var instaUri = UriCreator.GetUriSetAccountPrivate(); + var fields = new Dictionary + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk.ToString()}, + {"_csrftoken", _user.CsrfToken} + }; + var hash = CryptoHelper.CalculateHash(InstaApiConstants.IG_SIGNATURE_KEY, + JsonConvert.SerializeObject(fields)); + var payload = JsonConvert.SerializeObject(fields); + var signature = $"{hash}.{Uri.EscapeDataString(payload)}"; + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); + request.Content = new FormUrlEncodedContent(fields); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, + InstaApiConstants.IG_SIGNATURE_KEY_VERSION); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode != HttpStatusCode.OK) + return Result.UnExpectedResponse(response, json); + var userInfoUpdated = + JsonConvert.DeserializeObject(json, new InstaUserShortDataConverter()); + if (userInfoUpdated.Pk < 1) + return Result.Fail("Pk is null or empty"); + var converter = ConvertersFabric.Instance.GetUserShortConverter(userInfoUpdated); + return Result.Success(converter.Convert()); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message, (InstaUserShort) null); + } + } + + public async Task> SetAccountPublicAsync() + { + try + { + var instaUri = UriCreator.GetUriSetAccountPublic(); + var fields = new Dictionary + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk.ToString()}, + {"_csrftoken", _user.CsrfToken} + }; + var hash = CryptoHelper.CalculateHash(InstaApiConstants.IG_SIGNATURE_KEY, + JsonConvert.SerializeObject(fields)); + var payload = JsonConvert.SerializeObject(fields); + var signature = $"{hash}.{Uri.EscapeDataString(payload)}"; + var request = HttpHelper.GetDefaultRequest(HttpMethod.Post, instaUri, _deviceInfo); + request.Content = new FormUrlEncodedContent(fields); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE, signature); + request.Properties.Add(InstaApiConstants.HEADER_IG_SIGNATURE_KEY_VERSION, + InstaApiConstants.IG_SIGNATURE_KEY_VERSION); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + { + var userInfoUpdated = + JsonConvert.DeserializeObject(json, new InstaUserShortDataConverter()); + if (userInfoUpdated.Pk < 1) + return Result.Fail("Pk is incorrect"); + var converter = ConvertersFabric.Instance.GetUserShortConverter(userInfoUpdated); + return Result.Success(converter.Convert()); + } + + return Result.UnExpectedResponse(response, json); + } + catch (Exception exception) + { + _logger?.LogException(exception); + return Result.Fail(exception.Message, (InstaUserShort) null); + } + } + + public async Task> ChangePasswordAsync(string oldPassword, string newPassword) + { + if (oldPassword == newPassword) + return Result.Fail("The old password should not the same of the new password", false); + + try + { + var changePasswordUri = UriCreator.GetChangePasswordUri(); + + var data = new JObject + { + {"_uuid", _deviceInfo.DeviceGuid.ToString()}, + {"_uid", _user.LoggedInUser.Pk}, + {"_csrftoken", _user.CsrfToken}, + {"old_password", oldPassword}, + {"new_password1", newPassword}, + {"new_password2", newPassword} + }; + + var request = HttpHelper.GetSignedRequest(HttpMethod.Get, changePasswordUri, _deviceInfo, data); + var response = await _httpRequestProcessor.SendAsync(request); + var json = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + return Result.Success(true); + var error = JsonConvert.DeserializeObject(json); + var errors = ""; + error.Message.Errors.ForEach(errorContent => errors += errorContent + "\n"); + return Result.Fail(errors, false); + } + catch (Exception exception) + { + return Result.Fail(exception.Message, false); + } + } + } +} \ No newline at end of file diff --git a/InstaSharper/API/UriCreators/GetLocationFeedUriCreator.cs b/InstaSharper/API/UriCreators/GetLocationFeedUriCreator.cs new file mode 100644 index 00000000..d9dc1b8a --- /dev/null +++ b/InstaSharper/API/UriCreators/GetLocationFeedUriCreator.cs @@ -0,0 +1,19 @@ +using System; + +namespace InstaSharper.API.UriCreators +{ + internal class GetLocationFeedUriCreator : IUriCreatorNextId + { + private const string LocationFeed = "feed/location/{0}/"; + + public Uri GetUri(long id, string nextId) + { + if (!Uri.TryCreate(InstaApiConstants.BaseInstagramUri, string.Format(LocationFeed, id), out var instaUri)) + throw new Exception("Can't create URI for getting location feed"); + var query = string.Empty; + if (!string.IsNullOrEmpty(nextId)) query += $"max_id={nextId}"; + var uriBuilder = new UriBuilder(instaUri) {Query = query}; + return uriBuilder.Uri; + } + } +} \ No newline at end of file diff --git a/InstaSharper/API/UriCreators/IUriCreator.cs b/InstaSharper/API/UriCreators/IUriCreator.cs new file mode 100644 index 00000000..0a3314f4 --- /dev/null +++ b/InstaSharper/API/UriCreators/IUriCreator.cs @@ -0,0 +1,9 @@ +using System; + +namespace InstaSharper.API.UriCreators +{ + public interface IUriCreator + { + Uri GetUri(); + } +} \ No newline at end of file diff --git a/InstaSharper/API/UriCreators/IUriCreatorNextId.cs b/InstaSharper/API/UriCreators/IUriCreatorNextId.cs new file mode 100644 index 00000000..e50f96e5 --- /dev/null +++ b/InstaSharper/API/UriCreators/IUriCreatorNextId.cs @@ -0,0 +1,9 @@ +using System; + +namespace InstaSharper.API.UriCreators +{ + public interface IUriCreatorNextId + { + Uri GetUri(long id, string nextId); + } +} \ No newline at end of file diff --git a/InstaSharper/API/UriCreators/SearchLocationUriCreator.cs b/InstaSharper/API/UriCreators/SearchLocationUriCreator.cs new file mode 100644 index 00000000..c85f5a6e --- /dev/null +++ b/InstaSharper/API/UriCreators/SearchLocationUriCreator.cs @@ -0,0 +1,16 @@ +using System; + +namespace InstaSharper.API.UriCreators +{ + internal class SearchLocationUriCreator : IUriCreator + { + private const string SearchLocation = "location_search"; + + public Uri GetUri() + { + if (!Uri.TryCreate(InstaApiConstants.BaseInstagramUri, SearchLocation, out var instaUri)) + throw new Exception("Can't create URI for searchiing location"); + return instaUri; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs b/InstaSharper/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs index 740102d4..812b0621 100644 --- a/InstaSharper/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs +++ b/InstaSharper/Classes/Android/DeviceInfo/AndroidDeviceGenerator.cs @@ -21,402 +21,403 @@ public class AndroidDeviceGenerator AndroidDevices.XPERIA_Z5 }; - public static Dictionary AndroidAndroidDeviceSets = new Dictionary - { + public static Dictionary AndroidAndroidDeviceSets = + new Dictionary { - "lg-optimus-g", - new AndroidDevice { - AndroidBoardName = "geehrc", - AndroidBootloader = "MAKOZ10f", - DeviceBrand = "LGE", - DeviceModel = "LG-LS970", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "cm_ls970", - FirmwareBrand = "cm_ls970", - FirmwareFingerprint = "google/occam/mako:4.2.2/JDQ39/573038:user/release-keys", - FirmwareTags = "test-keys", - FirmwareType = "userdebug", - HardwareManufacturer = "LGE", - HardwareModel = "LG-LS970", - DeviceGuid = new Guid("202d7022-3533-4450-91bd-0344112e0deb"), - PhoneGuid = new Guid("5b971484-ad0f-41fa-8886-313e9e91f5b9") - } - }, - { - "nexus7gen2", - new AndroidDevice + "lg-optimus-g", + new AndroidDevice + { + AndroidBoardName = "geehrc", + AndroidBootloader = "MAKOZ10f", + DeviceBrand = "LGE", + DeviceModel = "LG-LS970", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "cm_ls970", + FirmwareBrand = "cm_ls970", + FirmwareFingerprint = "google/occam/mako:4.2.2/JDQ39/573038:user/release-keys", + FirmwareTags = "test-keys", + FirmwareType = "userdebug", + HardwareManufacturer = "LGE", + HardwareModel = "LG-LS970", + DeviceGuid = new Guid("202d7022-3533-4450-91bd-0344112e0deb"), + PhoneGuid = new Guid("5b971484-ad0f-41fa-8886-313e9e91f5b9") + } + }, { - AndroidBoardName = "flo", - AndroidBootloader = "FLO-04.07", - DeviceBrand = "google", - DeviceModel = "Nexus 7", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "razor", - FirmwareBrand = "razor", - FirmwareFingerprint = "google/razor/flo:6.0.1/MOB30P/2960889:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "asus", - HardwareModel = "Nexus 7", - DeviceGuid = new Guid("82c2dbb7-35fc-4544-8b6f-4d8606ea1f7f"), - PhoneGuid = new Guid("97dd4f8a-af3f-4cfe-8be3-c34c38110346") - } - }, - { - "nexus7gen1", - new AndroidDevice + "nexus7gen2", + new AndroidDevice + { + AndroidBoardName = "flo", + AndroidBootloader = "FLO-04.07", + DeviceBrand = "google", + DeviceModel = "Nexus 7", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "razor", + FirmwareBrand = "razor", + FirmwareFingerprint = "google/razor/flo:6.0.1/MOB30P/2960889:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "asus", + HardwareModel = "Nexus 7", + DeviceGuid = new Guid("82c2dbb7-35fc-4544-8b6f-4d8606ea1f7f"), + PhoneGuid = new Guid("97dd4f8a-af3f-4cfe-8be3-c34c38110346") + } + }, { - AndroidBoardName = "grouper", - AndroidBootloader = "4.23", - DeviceBrand = "google", - DeviceModel = "Nexus 7", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "nakasi", - FirmwareBrand = "nakasi", - FirmwareFingerprint = "google/nakasi/grouper:5.1.1/LMY47V/1836172:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "asus", - HardwareModel = "Nexus 7", - DeviceGuid = new Guid("cf6e9c5f-5ad8-4507-8de5-958c4b398010"), - PhoneGuid = new Guid("e64b4dd2-0368-40f1-9168-723ddd7460c2") - } - }, - { - "htc10", - new AndroidDevice + "nexus7gen1", + new AndroidDevice + { + AndroidBoardName = "grouper", + AndroidBootloader = "4.23", + DeviceBrand = "google", + DeviceModel = "Nexus 7", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "nakasi", + FirmwareBrand = "nakasi", + FirmwareFingerprint = "google/nakasi/grouper:5.1.1/LMY47V/1836172:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "asus", + HardwareModel = "Nexus 7", + DeviceGuid = new Guid("cf6e9c5f-5ad8-4507-8de5-958c4b398010"), + PhoneGuid = new Guid("e64b4dd2-0368-40f1-9168-723ddd7460c2") + } + }, { - AndroidBoardName = "msm8996", - AndroidBootloader = "1.0.0.0000", - DeviceBrand = "HTC", - DeviceModel = "HTC 10", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "pmewl_00531", - FirmwareBrand = "pmewl_00531", - FirmwareFingerprint = "htc/pmewl_00531/htc_pmewl:6.0.1/MMB29M/770927.1:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "HTC", - HardwareModel = "HTC 10", - DeviceGuid = new Guid("a91cd29b-2070-4c4e-b4cb-35335b2a38dc"), - PhoneGuid = new Guid("3e90b5f5-23c3-4fd1-b9ba-8e090a1fa397") - } - }, - { - "galaxy6", - new AndroidDevice + "htc10", + new AndroidDevice + { + AndroidBoardName = "msm8996", + AndroidBootloader = "1.0.0.0000", + DeviceBrand = "HTC", + DeviceModel = "HTC 10", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "pmewl_00531", + FirmwareBrand = "pmewl_00531", + FirmwareFingerprint = "htc/pmewl_00531/htc_pmewl:6.0.1/MMB29M/770927.1:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "HTC", + HardwareModel = "HTC 10", + DeviceGuid = new Guid("a91cd29b-2070-4c4e-b4cb-35335b2a38dc"), + PhoneGuid = new Guid("3e90b5f5-23c3-4fd1-b9ba-8e090a1fa397") + } + }, { - AndroidBoardName = "universal7420", - AndroidBootloader = "G920FXXU3DPEK", - DeviceBrand = "samsung", - DeviceModel = "zeroflte", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "SM-G920F", - FirmwareBrand = "zerofltexx", - FirmwareFingerprint = "samsung/zerofltexx/zeroflte:6.0.1/MMB29K/G920FXXU3DPEK:user/release-keys", - FirmwareTags = "dev-keys", - FirmwareType = "user", - HardwareManufacturer = "samsung", - HardwareModel = "samsungexynos7420", - DeviceGuid = new Guid("505cbe9d-487c-49d4-8f2c-b1cc166d1094"), - PhoneGuid = new Guid("9ade42fb-09de-4931-8526-8f7c1bd3ce2a") - } - }, - { - "galaxy-s5-gold", - new AndroidDevice + "galaxy6", + new AndroidDevice + { + AndroidBoardName = "universal7420", + AndroidBootloader = "G920FXXU3DPEK", + DeviceBrand = "samsung", + DeviceModel = "zeroflte", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "SM-G920F", + FirmwareBrand = "zerofltexx", + FirmwareFingerprint = + "samsung/zerofltexx/zeroflte:6.0.1/MMB29K/G920FXXU3DPEK:user/release-keys", + FirmwareTags = "dev-keys", + FirmwareType = "user", + HardwareManufacturer = "samsung", + HardwareModel = "samsungexynos7420", + DeviceGuid = new Guid("505cbe9d-487c-49d4-8f2c-b1cc166d1094"), + PhoneGuid = new Guid("9ade42fb-09de-4931-8526-8f7c1bd3ce2a") + } + }, { - AndroidBoardName = "MSM8974", - AndroidBootloader = "G900FXXU1CPEH", - DeviceBrand = "samsung", - DeviceModel = "SM-G900F", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "kltexx", - FirmwareBrand = "kltexx", - FirmwareFingerprint = "samsung/kltexx/klte:6.0.1/MMB29M/G900FXXU1CPEH:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "samsung", - HardwareModel = "SM-G900F", - DeviceGuid = new Guid("d13d1596-0983-4e59-825f-bd7cd559106b"), - PhoneGuid = new Guid("141023a2-153b-4e92-ae64-893553eaa9db") - } - }, - { - "lg-optimus-f6", - new AndroidDevice + "galaxy-s5-gold", + new AndroidDevice + { + AndroidBoardName = "MSM8974", + AndroidBootloader = "G900FXXU1CPEH", + DeviceBrand = "samsung", + DeviceModel = "SM-G900F", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "kltexx", + FirmwareBrand = "kltexx", + FirmwareFingerprint = "samsung/kltexx/klte:6.0.1/MMB29M/G900FXXU1CPEH:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "samsung", + HardwareModel = "SM-G900F", + DeviceGuid = new Guid("d13d1596-0983-4e59-825f-bd7cd559106b"), + PhoneGuid = new Guid("141023a2-153b-4e92-ae64-893553eaa9db") + } + }, { - AndroidBoardName = "f6t", - AndroidBootloader = "1.0.0.0000", - DeviceBrand = "lge", - DeviceModel = "LG-D500", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "f6_tmo_us", - FirmwareBrand = "f6_tmo_us", - FirmwareFingerprint = "lge/f6_tmo_us/f6:4.1.2/JZO54K/D50010h.1384764249:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "LGE", - HardwareModel = "LG-D500", - DeviceGuid = new Guid("5ccdd80f-389e-4156-b070-fddab5fb7ed9"), - PhoneGuid = new Guid("17c27d7a-788d-4430-bcb0-6ae605ef0b01") - } - }, - { - "nexus-5x", - new AndroidDevice + "lg-optimus-f6", + new AndroidDevice + { + AndroidBoardName = "f6t", + AndroidBootloader = "1.0.0.0000", + DeviceBrand = "lge", + DeviceModel = "LG-D500", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "f6_tmo_us", + FirmwareBrand = "f6_tmo_us", + FirmwareFingerprint = "lge/f6_tmo_us/f6:4.1.2/JZO54K/D50010h.1384764249:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "LGE", + HardwareModel = "LG-D500", + DeviceGuid = new Guid("5ccdd80f-389e-4156-b070-fddab5fb7ed9"), + PhoneGuid = new Guid("17c27d7a-788d-4430-bcb0-6ae605ef0b01") + } + }, { - AndroidBoardName = "bullhead", - AndroidBootloader = "BHZ10k", - DeviceBrand = "google", - DeviceModel = "Nexus 5X", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "bullhead", - FirmwareBrand = "bullhead", - FirmwareFingerprint = "google/bullhead/bullhead:6.0.1/MTC19T/2741993:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "LGE", - HardwareModel = "Nexus 5X", - DeviceGuid = new Guid("7c020baa-3810-48a3-b991-35b83b2e1b31"), - PhoneGuid = new Guid("a115bd4b-e782-483b-96a8-157ec0f2803a") - } - }, - { - "galaxy-s7-edge", - new AndroidDevice + "nexus-5x", + new AndroidDevice + { + AndroidBoardName = "bullhead", + AndroidBootloader = "BHZ10k", + DeviceBrand = "google", + DeviceModel = "Nexus 5X", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "bullhead", + FirmwareBrand = "bullhead", + FirmwareFingerprint = "google/bullhead/bullhead:6.0.1/MTC19T/2741993:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "LGE", + HardwareModel = "Nexus 5X", + DeviceGuid = new Guid("7c020baa-3810-48a3-b991-35b83b2e1b31"), + PhoneGuid = new Guid("a115bd4b-e782-483b-96a8-157ec0f2803a") + } + }, { - AndroidBoardName = "msm8996", - AndroidBootloader = "G935TUVU3APG1", - DeviceBrand = "samsung", - DeviceModel = "SM-G935T", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "hero2qltetmo", - FirmwareBrand = "hero2qltetmo", - FirmwareFingerprint = - "samsung/hero2qltetmo/hero2qltetmo:6.0.1/MMB29M/G935TUVU3APG1:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "samsung", - HardwareModel = "SM-G935T", - DeviceGuid = new Guid("e428e21e-f105-4201-8287-b8bd9bd8727f"), - PhoneGuid = new Guid("2a6e43a7-0204-4b76-89a6-d7d17303e5f7") - } - }, - { - "xperia-z5", - new AndroidDevice + "galaxy-s7-edge", + new AndroidDevice + { + AndroidBoardName = "msm8996", + AndroidBootloader = "G935TUVU3APG1", + DeviceBrand = "samsung", + DeviceModel = "SM-G935T", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "hero2qltetmo", + FirmwareBrand = "hero2qltetmo", + FirmwareFingerprint = + "samsung/hero2qltetmo/hero2qltetmo:6.0.1/MMB29M/G935TUVU3APG1:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "samsung", + HardwareModel = "SM-G935T", + DeviceGuid = new Guid("e428e21e-f105-4201-8287-b8bd9bd8727f"), + PhoneGuid = new Guid("2a6e43a7-0204-4b76-89a6-d7d17303e5f7") + } + }, { - AndroidBoardName = "msm8994", - AndroidBootloader = "s1", - DeviceBrand = "Sony", - DeviceModel = "E6653", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "E6653", - FirmwareBrand = "E6653", - FirmwareFingerprint = "Sony/E6653/E6653:6.0.1/32.2.A.0.224/456768306:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "Sony", - HardwareModel = "E6653", - DeviceGuid = new Guid("78178fef-aa0c-4691-9c00-16482c25ce24"), - PhoneGuid = new Guid("aaeb4dfb-a93d-4bd6-9147-1a3aaee60510") - } - }, - { - "galaxy-s4", - new AndroidDevice + "xperia-z5", + new AndroidDevice + { + AndroidBoardName = "msm8994", + AndroidBootloader = "s1", + DeviceBrand = "Sony", + DeviceModel = "E6653", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "E6653", + FirmwareBrand = "E6653", + FirmwareFingerprint = "Sony/E6653/E6653:6.0.1/32.2.A.0.224/456768306:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "Sony", + HardwareModel = "E6653", + DeviceGuid = new Guid("78178fef-aa0c-4691-9c00-16482c25ce24"), + PhoneGuid = new Guid("aaeb4dfb-a93d-4bd6-9147-1a3aaee60510") + } + }, { - AndroidBoardName = "MSM8960", - AndroidBootloader = "I337MVLUGOH1", - DeviceBrand = "samsung", - DeviceModel = "SGH-I337M", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "jfltevl", - FirmwareBrand = "jfltevl", - FirmwareFingerprint = "samsung/jfltevl/jfltecan:5.0.1/LRX22C/I337MVLUGOH1:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "samsung", - HardwareModel = "SGH-I337M", - DeviceGuid = new Guid("d22d08e6-6856-4c6a-8748-124471796564"), - PhoneGuid = new Guid("36fe0448-6404-423b-a11f-95528f0f5120") - } - }, - { - "nexus-6p", - new AndroidDevice + "galaxy-s4", + new AndroidDevice + { + AndroidBoardName = "MSM8960", + AndroidBootloader = "I337MVLUGOH1", + DeviceBrand = "samsung", + DeviceModel = "SGH-I337M", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "jfltevl", + FirmwareBrand = "jfltevl", + FirmwareFingerprint = "samsung/jfltevl/jfltecan:5.0.1/LRX22C/I337MVLUGOH1:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "samsung", + HardwareModel = "SGH-I337M", + DeviceGuid = new Guid("d22d08e6-6856-4c6a-8748-124471796564"), + PhoneGuid = new Guid("36fe0448-6404-423b-a11f-95528f0f5120") + } + }, { - AndroidBoardName = "angler", - AndroidBootloader = "angler-03.52", - DeviceBrand = "google", - DeviceModel = "Nexus 6P", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "angler", - FirmwareBrand = "angler", - FirmwareFingerprint = "google/angler/angler:6.0.1/MTC19X/2960136:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "Huawei", - HardwareModel = "Nexus 6P", - DeviceGuid = new Guid("95363fcc-9b6d-4ef3-b7d7-9d4d1bf94602"), - PhoneGuid = new Guid("d685d651-082c-425b-872b-d0907604649a") - } - }, - { - "sony-z3-compact", - new AndroidDevice + "nexus-6p", + new AndroidDevice + { + AndroidBoardName = "angler", + AndroidBootloader = "angler-03.52", + DeviceBrand = "google", + DeviceModel = "Nexus 6P", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "angler", + FirmwareBrand = "angler", + FirmwareFingerprint = "google/angler/angler:6.0.1/MTC19X/2960136:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "Huawei", + HardwareModel = "Nexus 6P", + DeviceGuid = new Guid("95363fcc-9b6d-4ef3-b7d7-9d4d1bf94602"), + PhoneGuid = new Guid("d685d651-082c-425b-872b-d0907604649a") + } + }, { - AndroidBoardName = "MSM8974", - AndroidBootloader = "s1", - DeviceBrand = "docomo", - DeviceModel = "SO-02G", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "SO-02G", - FirmwareBrand = "SO-02G", - FirmwareFingerprint = "docomo/SO-02G/SO-02G:5.0.2/23.1.B.1.317/2161656255:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "Sony", - HardwareModel = "SO-02G", - DeviceGuid = new Guid("bccfcc1c-8188-42fa-a14e-e238c847c358"), - PhoneGuid = new Guid("8afad275-4fca-49e6-a5e0-3b2bbfe6e9f2") - } - }, - { - "galaxy-tab3", - new AndroidDevice + "sony-z3-compact", + new AndroidDevice + { + AndroidBoardName = "MSM8974", + AndroidBootloader = "s1", + DeviceBrand = "docomo", + DeviceModel = "SO-02G", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "SO-02G", + FirmwareBrand = "SO-02G", + FirmwareFingerprint = "docomo/SO-02G/SO-02G:5.0.2/23.1.B.1.317/2161656255:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "Sony", + HardwareModel = "SO-02G", + DeviceGuid = new Guid("bccfcc1c-8188-42fa-a14e-e238c847c358"), + PhoneGuid = new Guid("8afad275-4fca-49e6-a5e0-3b2bbfe6e9f2") + } + }, { - AndroidBoardName = "smdk4x12", - AndroidBootloader = "T310UEUCOI1", - DeviceBrand = "samsung", - DeviceId = "8525f5d8201f78b5", - DeviceModel = "SM-T310", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "lt01wifiue", - FirmwareBrand = "lt01wifiue", - FirmwareFingerprint = "samsung/lt01wifiue/lt01wifi:4.4.2/KOT49H/T310UEUCOI1:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "samsung", - HardwareModel = "SM-T310", - DeviceGuid = new Guid("6548b691-0b6f-4179-b9a8-d4ced7cc1708"), - PhoneGuid = new Guid("af872704-92d7-49c8-a5bf-41e5c65a07b4") - } - }, - { - "nexus5", - new AndroidDevice + "galaxy-tab3", + new AndroidDevice + { + AndroidBoardName = "smdk4x12", + AndroidBootloader = "T310UEUCOI1", + DeviceBrand = "samsung", + DeviceId = "8525f5d8201f78b5", + DeviceModel = "SM-T310", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "lt01wifiue", + FirmwareBrand = "lt01wifiue", + FirmwareFingerprint = "samsung/lt01wifiue/lt01wifi:4.4.2/KOT49H/T310UEUCOI1:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "samsung", + HardwareModel = "SM-T310", + DeviceGuid = new Guid("6548b691-0b6f-4179-b9a8-d4ced7cc1708"), + PhoneGuid = new Guid("af872704-92d7-49c8-a5bf-41e5c65a07b4") + } + }, { - AndroidBoardName = "hammerhead", - AndroidBootloader = "HHZ20b", - DeviceBrand = "google", - DeviceModel = "Nexus 5", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "hammerhead", - FirmwareBrand = "hammerhead", - FirmwareFingerprint = "google/hammerhead/hammerhead:6.0.1/MOB30M/2862625:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "LGE", - HardwareModel = "Nexus 5", - DeviceGuid = new Guid("dde2038c-4f1c-465a-982d-9c844fd2b80a"), - PhoneGuid = new Guid("d8d75d13-a124-4304-a935-0247ed1656cb"), - DeviceId = - ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("dde2038c-4f1c-465a-982d-9c844fd2b80a")) - } - }, - { - "galaxy-note-edge", - new AndroidDevice + "nexus5", + new AndroidDevice + { + AndroidBoardName = "hammerhead", + AndroidBootloader = "HHZ20b", + DeviceBrand = "google", + DeviceModel = "Nexus 5", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "hammerhead", + FirmwareBrand = "hammerhead", + FirmwareFingerprint = "google/hammerhead/hammerhead:6.0.1/MOB30M/2862625:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "LGE", + HardwareModel = "Nexus 5", + DeviceGuid = new Guid("dde2038c-4f1c-465a-982d-9c844fd2b80a"), + PhoneGuid = new Guid("d8d75d13-a124-4304-a935-0247ed1656cb"), + DeviceId = + ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("dde2038c-4f1c-465a-982d-9c844fd2b80a")) + } + }, { - AndroidBoardName = "APQ8084", - AndroidBootloader = "N915W8VLU1CPE2", - DeviceBrand = "samsung", - DeviceModel = "SM-N915W8", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "tbltecan", - FirmwareBrand = "tbltecan", - FirmwareFingerprint = "samsung/tbltecan/tbltecan:6.0.1/MMB29M/N915W8VLU1CPE2:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "samsung", - HardwareModel = "SM-N915W8", - DeviceGuid = new Guid("fe46d44b-e00c-4f1b-9718-7c4dae2160cc"), - PhoneGuid = new Guid("0bcbf7e0-a73f-4424-8c70-c2d38ae42d5d"), - DeviceId = - ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("fe46d44b-e00c-4f1b-9718-7c4dae2160cc")) - } - }, - { - "nexus4-chroma", - new AndroidDevice + "galaxy-note-edge", + new AndroidDevice + { + AndroidBoardName = "APQ8084", + AndroidBootloader = "N915W8VLU1CPE2", + DeviceBrand = "samsung", + DeviceModel = "SM-N915W8", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "tbltecan", + FirmwareBrand = "tbltecan", + FirmwareFingerprint = "samsung/tbltecan/tbltecan:6.0.1/MMB29M/N915W8VLU1CPE2:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "samsung", + HardwareModel = "SM-N915W8", + DeviceGuid = new Guid("fe46d44b-e00c-4f1b-9718-7c4dae2160cc"), + PhoneGuid = new Guid("0bcbf7e0-a73f-4424-8c70-c2d38ae42d5d"), + DeviceId = + ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("fe46d44b-e00c-4f1b-9718-7c4dae2160cc")) + } + }, { - AndroidBoardName = "MAKO", - AndroidBootloader = "MAKOZ30f", - DeviceBrand = "google", - DeviceModel = "Nexus 4", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "occam", - FirmwareBrand = "occam", - FirmwareFingerprint = "google/occam/mako:6.0.1/MOB30Y/3067468:user/release-keys", - FirmwareTags = "test-keys", - FirmwareType = "userdebug", - HardwareManufacturer = "LGE", - HardwareModel = "Nexus 4", - DeviceGuid = new Guid("2c4ae214-c037-486c-a335-76a1f6973445"), - PhoneGuid = new Guid("7fb2eb38-04ab-4c51-bd0c-694c7da2187e"), - DeviceId = - ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("2c4ae214-c037-486c-a335-76a1f6973445")) - } - }, - - { - AndroidDevices.SAMSUNG_NOTE3, - new AndroidDevice + "nexus4-chroma", + new AndroidDevice + { + AndroidBoardName = "MAKO", + AndroidBootloader = "MAKOZ30f", + DeviceBrand = "google", + DeviceModel = "Nexus 4", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "occam", + FirmwareBrand = "occam", + FirmwareFingerprint = "google/occam/mako:6.0.1/MOB30Y/3067468:user/release-keys", + FirmwareTags = "test-keys", + FirmwareType = "userdebug", + HardwareManufacturer = "LGE", + HardwareModel = "Nexus 4", + DeviceGuid = new Guid("2c4ae214-c037-486c-a335-76a1f6973445"), + PhoneGuid = new Guid("7fb2eb38-04ab-4c51-bd0c-694c7da2187e"), + DeviceId = + ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("2c4ae214-c037-486c-a335-76a1f6973445")) + } + }, { - AndroidBoardName = "MSM8974", - AndroidBootloader = "N900PVPUEOK2", - DeviceBrand = "samsung", - DeviceModel = "SM-N900P", - DeviceModelBoot = "qcom", - DeviceModelIdentifier = "cm_hltespr", - FirmwareBrand = "cm_hltespr", - FirmwareFingerprint = "samsung/hltespr/hltespr:5.0/LRX21V/N900PVPUEOH1:user/release-keys", - FirmwareTags = "test-keys", - FirmwareType = "user", - HardwareManufacturer = "samsung", - HardwareModel = "SM-N900P", - DeviceGuid = new Guid("7f585e77-becf-4137-bf1f-84ab72e35eb4"), - PhoneGuid = new Guid("28484284-e646-4a29-88fc-76c2666d5ab3"), - DeviceId = - ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("7f585e77-becf-4137-bf1f-84ab72e35eb4")) - } - }, - { - AndroidDevices.GALAXY_TAB, - new AndroidDevice + AndroidDevices.SAMSUNG_NOTE3, + new AndroidDevice + { + AndroidBoardName = "MSM8974", + AndroidBootloader = "N900PVPUEOK2", + DeviceBrand = "samsung", + DeviceModel = "SM-N900P", + DeviceModelBoot = "qcom", + DeviceModelIdentifier = "cm_hltespr", + FirmwareBrand = "cm_hltespr", + FirmwareFingerprint = "samsung/hltespr/hltespr:5.0/LRX21V/N900PVPUEOH1:user/release-keys", + FirmwareTags = "test-keys", + FirmwareType = "user", + HardwareManufacturer = "samsung", + HardwareModel = "SM-N900P", + DeviceGuid = new Guid("7f585e77-becf-4137-bf1f-84ab72e35eb4"), + PhoneGuid = new Guid("28484284-e646-4a29-88fc-76c2666d5ab3"), + DeviceId = + ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("7f585e77-becf-4137-bf1f-84ab72e35eb4")) + } + }, { - AndroidBoardName = "universal5420", - AndroidBootloader = "T705XXU1BOL2", - DeviceBrand = "samsung", - DeviceModel = "Samsung Galaxy Tab S 8.4 LTE", - DeviceModelBoot = "universal5420", - DeviceModelIdentifier = "LRX22G.T705XXU1BOL2", - FirmwareBrand = "Samsung Galaxy Tab S 8.4 LTE", - FirmwareFingerprint = "samsung/klimtltexx/klimtlte:5.0.2/LRX22G/T705XXU1BOL2:user/release-keys", - FirmwareTags = "release-keys", - FirmwareType = "user", - HardwareManufacturer = "samsung", - HardwareModel = "SM-T705", - DeviceGuid = new Guid("c319490f-6f09-467b-b2a5-6f1db13348e9"), - PhoneGuid = new Guid("849a7ae1-cf94-4dd5-a977-a2f3e8363e66"), - DeviceId = - ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("c319490f-6f09-467b-b2a5-6f1db13348e9")) + AndroidDevices.GALAXY_TAB, + new AndroidDevice + { + AndroidBoardName = "universal5420", + AndroidBootloader = "T705XXU1BOL2", + DeviceBrand = "samsung", + DeviceModel = "Samsung Galaxy Tab S 8.4 LTE", + DeviceModelBoot = "universal5420", + DeviceModelIdentifier = "LRX22G.T705XXU1BOL2", + FirmwareBrand = "Samsung Galaxy Tab S 8.4 LTE", + FirmwareFingerprint = "samsung/klimtltexx/klimtlte:5.0.2/LRX22G/T705XXU1BOL2:user/release-keys", + FirmwareTags = "release-keys", + FirmwareType = "user", + HardwareManufacturer = "samsung", + HardwareModel = "SM-T705", + DeviceGuid = new Guid("c319490f-6f09-467b-b2a5-6f1db13348e9"), + PhoneGuid = new Guid("849a7ae1-cf94-4dd5-a977-a2f3e8363e66"), + DeviceId = + ApiRequestMessage.GenerateDeviceIdFromGuid(new Guid("c319490f-6f09-467b-b2a5-6f1db13348e9")) + } } - } - }; + }; public static AndroidDevice GetRandomAndroidDevice() { diff --git a/InstaSharper/Classes/Android/DeviceInfo/AndroidVersion.cs b/InstaSharper/Classes/Android/DeviceInfo/AndroidVersion.cs index 796e4fcb..9c399bc5 100644 --- a/InstaSharper/Classes/Android/DeviceInfo/AndroidVersion.cs +++ b/InstaSharper/Classes/Android/DeviceInfo/AndroidVersion.cs @@ -77,8 +77,7 @@ public class AndroidVersion }; private AndroidVersion() - { - } + { } public string Codename { get; set; } public string VersionNumber { get; set; } diff --git a/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs b/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs index ebd2afb6..4f32aa87 100644 --- a/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs +++ b/InstaSharper/Classes/Android/DeviceInfo/ApiRequestMessage.cs @@ -19,9 +19,11 @@ internal string GetMessageString() return JsonConvert.SerializeObject(this); } - internal string GenerateSignature() + internal string GenerateSignature(string signatureKey) { - return CryptoHelper.CalculateHash(InstaApiConstants.IG_SIGNATURE_KEY, + if (string.IsNullOrEmpty(signatureKey)) + signatureKey = InstaApiConstants.IG_SIGNATURE_KEY; + return CryptoHelper.CalculateHash(signatureKey, JsonConvert.SerializeObject(this)); } diff --git a/InstaSharper/Classes/Android/DeviceInfo/ApiTwoFactorRequestMessage.cs b/InstaSharper/Classes/Android/DeviceInfo/ApiTwoFactorRequestMessage.cs new file mode 100644 index 00000000..38ec1058 --- /dev/null +++ b/InstaSharper/Classes/Android/DeviceInfo/ApiTwoFactorRequestMessage.cs @@ -0,0 +1,37 @@ +using InstaSharper.API; +using InstaSharper.Helpers; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.Android.DeviceInfo +{ + internal class ApiTwoFactorRequestMessage + { + internal ApiTwoFactorRequestMessage(string verificationCode, string username, string deviceId, + string twoFactorIdentifier) + { + verification_code = verificationCode; + this.username = username; + device_id = deviceId; + two_factor_identifier = twoFactorIdentifier; + } + + public string verification_code { get; set; } + public string username { get; set; } + public string device_id { get; set; } + public string two_factor_identifier { get; set; } + + + internal string GenerateSignature(string signatureKey) + { + if (string.IsNullOrEmpty(signatureKey)) + signatureKey = InstaApiConstants.IG_SIGNATURE_KEY; + return CryptoHelper.CalculateHash(signatureKey, + JsonConvert.SerializeObject(this)); + } + + internal string GetMessageString() + { + return JsonConvert.SerializeObject(this); + } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Comparer/CommentEqualityComparer.cs b/InstaSharper/Classes/Comparer/CommentEqualityComparer.cs new file mode 100644 index 00000000..79f050dc --- /dev/null +++ b/InstaSharper/Classes/Comparer/CommentEqualityComparer.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using InstaSharper.Classes.Models; + +namespace InstaSharper.Classes.Comparer +{ + internal class CommentEqualityComparer : IEqualityComparer + { + public bool Equals(InstaComment comment, InstaComment anotherComment) + { + return comment?.Pk == anotherComment?.Pk; + } + + public int GetHashCode(InstaComment comment) + { + return comment.Pk.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Comparer/UserEqualityComparer.cs b/InstaSharper/Classes/Comparer/UserEqualityComparer.cs new file mode 100644 index 00000000..2ed23f88 --- /dev/null +++ b/InstaSharper/Classes/Comparer/UserEqualityComparer.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using InstaSharper.Classes.Models; + +namespace InstaSharper.Classes.Comparer +{ + internal class UserEqualityComparer : IEqualityComparer + { + public bool Equals(InstaUserShort user, InstaUserShort anotherUser) + { + return user?.Pk == anotherUser?.Pk; + } + + public int GetHashCode(InstaUserShort user) + { + return user.Pk.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/CreationResponse.cs b/InstaSharper/Classes/CreationResponse.cs new file mode 100644 index 00000000..47025cff --- /dev/null +++ b/InstaSharper/Classes/CreationResponse.cs @@ -0,0 +1,14 @@ +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using Newtonsoft.Json; + +namespace InstaSharper.Classes +{ + public class CreationResponse : BaseStatusResponse + { + [JsonProperty("account_created")] + public bool AccountCreated { get; set; } + + [JsonProperty("error_type")] + public string ErrorType { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/HttpRequestProcessor.cs b/InstaSharper/Classes/HttpRequestProcessor.cs index abfc0b30..36d38f96 100644 --- a/InstaSharper/Classes/HttpRequestProcessor.cs +++ b/InstaSharper/Classes/HttpRequestProcessor.cs @@ -8,10 +8,10 @@ namespace InstaSharper.Classes { internal class HttpRequestProcessor : IHttpRequestProcessor { - private readonly TimeSpan _delay; + private readonly IRequestDelay _delay; private readonly IInstaLogger _logger; - public HttpRequestProcessor(TimeSpan delay, HttpClient httpClient, HttpClientHandler httpHandler, + public HttpRequestProcessor(IRequestDelay delay, HttpClient httpClient, HttpClientHandler httpHandler, ApiRequestMessage requestMessage, IInstaLogger logger) { _delay = delay; @@ -28,8 +28,8 @@ public HttpRequestProcessor(TimeSpan delay, HttpClient httpClient, HttpClientHan public async Task SendAsync(HttpRequestMessage requestMessage) { LogHttpRequest(requestMessage); - if (_delay > TimeSpan.Zero) - await Task.Delay(_delay); + if (_delay.Exist) + await Task.Delay(_delay.Value); var response = await Client.SendAsync(requestMessage); LogHttpResponse(response); return response; @@ -38,8 +38,8 @@ public async Task SendAsync(HttpRequestMessage requestMessa public async Task GetAsync(Uri requestUri) { _logger?.LogRequest(requestUri); - if (_delay > TimeSpan.Zero) - await Task.Delay(_delay); + if (_delay.Exist) + await Task.Delay(_delay.Value); var response = await Client.GetAsync(requestUri); LogHttpResponse(response); return response; @@ -49,8 +49,8 @@ public async Task SendAsync(HttpRequestMessage requestMessa HttpCompletionOption completionOption) { LogHttpRequest(requestMessage); - if (_delay > TimeSpan.Zero) - await Task.Delay(_delay); + if (_delay.Exist) + await Task.Delay(_delay.Value); var response = await Client.SendAsync(requestMessage, completionOption); LogHttpResponse(response); return response; @@ -60,8 +60,8 @@ public async Task SendAndGetJsonAsync(HttpRequestMessage requestMessage, HttpCompletionOption completionOption) { LogHttpRequest(requestMessage); - if (_delay > TimeSpan.Zero) - await Task.Delay(_delay); + if (_delay.Exist) + await Task.Delay(_delay.Value); var response = await Client.SendAsync(requestMessage, completionOption); LogHttpResponse(response); return await response.Content.ReadAsStringAsync(); @@ -70,8 +70,8 @@ public async Task SendAndGetJsonAsync(HttpRequestMessage requestMessage, public async Task GeJsonAsync(Uri requestUri) { _logger?.LogRequest(requestUri); - if (_delay > TimeSpan.Zero) - await Task.Delay(_delay); + if (_delay.Exist) + await Task.Delay(_delay.Value); var response = await Client.GetAsync(requestUri); LogHttpResponse(response); return await response.Content.ReadAsStringAsync(); diff --git a/InstaSharper/Classes/IRequestDelay.cs b/InstaSharper/Classes/IRequestDelay.cs new file mode 100644 index 00000000..5f01acbd --- /dev/null +++ b/InstaSharper/Classes/IRequestDelay.cs @@ -0,0 +1,12 @@ +using System; + +namespace InstaSharper.Classes +{ + public interface IRequestDelay + { + TimeSpan Value { get; } + bool Exist { get; } + void Enable(); + void Disable(); + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ImageThumbnailResponse.cs b/InstaSharper/Classes/ImageThumbnailResponse.cs new file mode 100644 index 00000000..327fdff6 --- /dev/null +++ b/InstaSharper/Classes/ImageThumbnailResponse.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes +{ + public class ImageThumbnailResponse + { + [JsonProperty("upload_id")] public string UploadId { get; set; } + + [JsonProperty("xsharing_nonces")] public object XSharingNonces { get; set; } + + [JsonProperty("status")] public string Status { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/InstaLoginBaseResponse.cs b/InstaSharper/Classes/InstaLoginBaseResponse.cs new file mode 100644 index 00000000..22846088 --- /dev/null +++ b/InstaSharper/Classes/InstaLoginBaseResponse.cs @@ -0,0 +1,32 @@ +using InstaSharper.Classes.ResponseWrappers; +using Newtonsoft.Json; + +namespace InstaSharper.Classes +{ + internal class InstaLoginBaseResponse + { + #region InvalidCredentials + + [JsonProperty("invalid_credentials")] public bool InvalidCredentials { get; set; } + + [JsonProperty("error_type")] public string ErrorType { get; set; } + + #endregion + + #region 2 Factor Authentication + + [JsonProperty("two_factor_required")] public bool TwoFactorRequired { get; set; } + + [JsonProperty("two_factor_info")] public TwoFactorLoginInfo TwoFactorLoginInfo { get; set; } + + #endregion + + #region Challenge Required + + [JsonIgnore] public bool ChallengeRequired => ErrorType == "checkpoint_challenge_required"; + + [JsonProperty("challenge")] public InstaChallenge Challenge { get; set; } + + #endregion + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/InstaLoginResult.cs b/InstaSharper/Classes/InstaLoginResult.cs new file mode 100644 index 00000000..965a334b --- /dev/null +++ b/InstaSharper/Classes/InstaLoginResult.cs @@ -0,0 +1,12 @@ +namespace InstaSharper.Classes +{ + public enum InstaLoginResult + { + Success, + BadPassword, + InvalidUser, + TwoFactorRequired, + ChallengeRequired, + Exception + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/InstaLoginTwoFactorBaseResponse.cs b/InstaSharper/Classes/InstaLoginTwoFactorBaseResponse.cs new file mode 100644 index 00000000..4631cb35 --- /dev/null +++ b/InstaSharper/Classes/InstaLoginTwoFactorBaseResponse.cs @@ -0,0 +1,11 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes +{ + internal class InstaLoginTwoFactorBaseResponse + { + [JsonProperty("message")] public string Message { get; set; } + + [JsonProperty("error_type")] public string ErrorType { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/InstaLoginTwoFactorResult.cs b/InstaSharper/Classes/InstaLoginTwoFactorResult.cs new file mode 100644 index 00000000..e67c3ccd --- /dev/null +++ b/InstaSharper/Classes/InstaLoginTwoFactorResult.cs @@ -0,0 +1,10 @@ +namespace InstaSharper.Classes +{ + public enum InstaLoginTwoFactorResult + { + Success, //Ok + InvalidCode, //sms_code_validation_code_invalid + CodeExpired, //invalid_nonce + Exception + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/IInstaBaseList.cs b/InstaSharper/Classes/Models/IInstaBaseList.cs new file mode 100644 index 00000000..4a9ea312 --- /dev/null +++ b/InstaSharper/Classes/Models/IInstaBaseList.cs @@ -0,0 +1,7 @@ +namespace InstaSharper.Classes.Models +{ + public interface IInstaBaseList + { + string NextId { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaActivityFeed.cs b/InstaSharper/Classes/Models/InstaActivityFeed.cs index e0f0768d..2f712939 100644 --- a/InstaSharper/Classes/Models/InstaActivityFeed.cs +++ b/InstaSharper/Classes/Models/InstaActivityFeed.cs @@ -2,9 +2,10 @@ namespace InstaSharper.Classes.Models { - public class InstaActivityFeed + public class InstaActivityFeed : IInstaBaseList { public bool IsOwnActivity { get; set; } = false; public List Items { get; set; } = new List(); + public string NextId { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaActivityFeedType.cs b/InstaSharper/Classes/Models/InstaActivityFeedType.cs new file mode 100644 index 00000000..0a7b7056 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaActivityFeedType.cs @@ -0,0 +1,11 @@ +namespace InstaSharper.Classes.Models +{ + public enum InstaActivityFeedType + { + Comment = 12, + Like = 60, + Follow = 101, + TaggedYou = 102, + SupportRequest = 119, + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaBaseFeed.cs b/InstaSharper/Classes/Models/InstaBaseFeed.cs new file mode 100644 index 00000000..a3b4e594 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaBaseFeed.cs @@ -0,0 +1,8 @@ +namespace InstaSharper.Classes.Models +{ + public class InstaBaseFeed : IInstaBaseList + { + public InstaMediaList Medias { get; set; } = new InstaMediaList(); + public string NextId { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaCarousel.cs b/InstaSharper/Classes/Models/InstaCarousel.cs index 2b8605db..13e72468 100644 --- a/InstaSharper/Classes/Models/InstaCarousel.cs +++ b/InstaSharper/Classes/Models/InstaCarousel.cs @@ -3,6 +3,5 @@ namespace InstaSharper.Classes.Models { public class InstaCarousel : List - { - } + { } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaCarouselItem.cs b/InstaSharper/Classes/Models/InstaCarouselItem.cs index 0b7c7824..88183862 100644 --- a/InstaSharper/Classes/Models/InstaCarouselItem.cs +++ b/InstaSharper/Classes/Models/InstaCarouselItem.cs @@ -10,6 +10,8 @@ public class InstaCarouselItem public List Images { get; set; } = new List(); + public List Videos { get; set; } = new List(); + public int Width { get; set; } public int Height { get; set; } diff --git a/InstaSharper/Classes/Models/InstaCollectionItem.cs b/InstaSharper/Classes/Models/InstaCollectionItem.cs new file mode 100644 index 00000000..a67da08b --- /dev/null +++ b/InstaSharper/Classes/Models/InstaCollectionItem.cs @@ -0,0 +1,15 @@ +namespace InstaSharper.Classes.Models +{ + public class InstaCollectionItem + { + public long CollectionId { get; set; } + + public string CollectionName { get; set; } + + public bool HasRelatedMedia { get; set; } + + public InstaMediaList Media { get; set; } + + public InstaCoverMedia CoverMedia { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaCollections.cs b/InstaSharper/Classes/Models/InstaCollections.cs new file mode 100644 index 00000000..a6b02f76 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaCollections.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace InstaSharper.Classes.Models +{ + public class InstaCollections + { + public bool MoreCollectionsAvailable { get; set; } + + public int Pages { get; set; } = 0; + + public List Items { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaComment.cs b/InstaSharper/Classes/Models/InstaComment.cs index 966377a5..949eb08a 100644 --- a/InstaSharper/Classes/Models/InstaComment.cs +++ b/InstaSharper/Classes/Models/InstaComment.cs @@ -20,7 +20,22 @@ public class InstaComment public InstaContentType ContentType { get; set; } public InstaUserShort User { get; set; } - public string Pk { get; set; } + public long Pk { get; set; } public string Text { get; set; } + + public bool Equals(InstaComment comment) + { + return Pk == comment?.Pk; + } + + public override bool Equals(object obj) + { + return Equals(obj as InstaComment); + } + + public override int GetHashCode() + { + return Pk.GetHashCode(); + } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaCommentList.cs b/InstaSharper/Classes/Models/InstaCommentList.cs index b2ff0f77..1f2d8592 100644 --- a/InstaSharper/Classes/Models/InstaCommentList.cs +++ b/InstaSharper/Classes/Models/InstaCommentList.cs @@ -2,10 +2,8 @@ namespace InstaSharper.Classes.Models { - public class InstaCommentList + public class InstaCommentList : IInstaBaseList { - public int CommentsCount { get; set; } - public bool LikesEnabled { get; set; } public bool CaptionIsEdited { get; set; } @@ -17,6 +15,7 @@ public class InstaCommentList public bool MoreComentsAvailable { get; set; } public List Comments { get; set; } = new List(); - public int Pages { get; set; } = 0; + + public string NextId { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaCoverMedia.cs b/InstaSharper/Classes/Models/InstaCoverMedia.cs new file mode 100644 index 00000000..f3753aaa --- /dev/null +++ b/InstaSharper/Classes/Models/InstaCoverMedia.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace InstaSharper.Classes.Models +{ + public class InstaCoverMedia + { + public long Id { get; set; } + + public List ImageVersions { get; set; } + + public int MediaType { get; set; } + + public int OriginalHeight { get; set; } + + public int OriginalWidth { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaDirectInboxItem.cs b/InstaSharper/Classes/Models/InstaDirectInboxItem.cs index d74ef3a6..2f9e1298 100644 --- a/InstaSharper/Classes/Models/InstaDirectInboxItem.cs +++ b/InstaSharper/Classes/Models/InstaDirectInboxItem.cs @@ -15,11 +15,12 @@ public class InstaDirectInboxItem public string ItemId { get; set; } - public InstaDirectThreadItemType ItemType { get; set; } + public InstaDirectThreadItemType ItemType { get; set; } = InstaDirectThreadItemType.Text; + public InstaInboxMedia Media { get; set; } public InstaMedia MediaShare { get; set; } - public Guid ClientContext { get; set; } + public string ClientContext { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaDirectInboxThread.cs b/InstaSharper/Classes/Models/InstaDirectInboxThread.cs index d9149971..a543bf2e 100644 --- a/InstaSharper/Classes/Models/InstaDirectInboxThread.cs +++ b/InstaSharper/Classes/Models/InstaDirectInboxThread.cs @@ -35,5 +35,7 @@ public class InstaDirectInboxThread public List Items { get; set; } + + public List LastSeen { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaDirectInboxThreadLastSeen.cs b/InstaSharper/Classes/Models/InstaDirectInboxThreadLastSeen.cs new file mode 100644 index 00000000..fa4dfb06 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaDirectInboxThreadLastSeen.cs @@ -0,0 +1,11 @@ +namespace InstaSharper.Classes.Models +{ + public class InstaDirectInboxThreadLastSeen + { + public long UserId { get; set; } + + public string TimeStamp { get; set; } + + public string ItemId { get; set; } + } +} diff --git a/InstaSharper/Classes/Models/InstaDirectInboxThreadList.cs b/InstaSharper/Classes/Models/InstaDirectInboxThreadList.cs new file mode 100644 index 00000000..493a550b --- /dev/null +++ b/InstaSharper/Classes/Models/InstaDirectInboxThreadList.cs @@ -0,0 +1,7 @@ +using System.Collections.Generic; + +namespace InstaSharper.Classes.Models +{ + public class InstaDirectInboxThreadList : List + { } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaDirectThreadItemType.cs b/InstaSharper/Classes/Models/InstaDirectThreadItemType.cs index 83610890..6a9a128e 100644 --- a/InstaSharper/Classes/Models/InstaDirectThreadItemType.cs +++ b/InstaSharper/Classes/Models/InstaDirectThreadItemType.cs @@ -3,6 +3,9 @@ public enum InstaDirectThreadItemType { Text = 0, - MediaShare = 1 + MediaShare = 1, + Like = 2, + Link = 3, + Media = 4 } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaExploreFeed.cs b/InstaSharper/Classes/Models/InstaExploreFeed.cs index 559c407c..ed121b3a 100644 --- a/InstaSharper/Classes/Models/InstaExploreFeed.cs +++ b/InstaSharper/Classes/Models/InstaExploreFeed.cs @@ -1,8 +1,7 @@ namespace InstaSharper.Classes.Models { - public class InstaExploreFeed + public class InstaExploreFeed : InstaBaseFeed { - public InstaMediaList Medias { get; set; } = new InstaMediaList(); public InstaStoryTray StoryTray { get; set; } = new InstaStoryTray(); public InstaChannel Channel { get; set; } = new InstaChannel(); } diff --git a/InstaSharper/Classes/Models/InstaFeed.cs b/InstaSharper/Classes/Models/InstaFeed.cs index f7f90549..b3ef644f 100644 --- a/InstaSharper/Classes/Models/InstaFeed.cs +++ b/InstaSharper/Classes/Models/InstaFeed.cs @@ -2,12 +2,13 @@ namespace InstaSharper.Classes.Models { - public class InstaFeed + public class InstaFeed : IInstaBaseList { public int MediaItemsCount => Medias.Count; public int StoriesItemsCount => Stories.Count; - public InstaMediaList Medias { get; set; } = new InstaMediaList(); + public List Medias { get; set; } = new List(); public List Stories { get; set; } = new List(); + public string NextId { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaHashtag.cs b/InstaSharper/Classes/Models/InstaHashtag.cs index c2e30b34..0cb4e642 100644 --- a/InstaSharper/Classes/Models/InstaHashtag.cs +++ b/InstaSharper/Classes/Models/InstaHashtag.cs @@ -4,5 +4,6 @@ public class InstaHashtag { public long Id { get; set; } public string Name { get; set; } + public long MediaCount { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaHashtagSearch.cs b/InstaSharper/Classes/Models/InstaHashtagSearch.cs new file mode 100644 index 00000000..49a9ec96 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaHashtagSearch.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace InstaSharper.Classes.Models +{ + public class InstaHashtagSearch : List + { + public bool MoreAvailable { get; set; } + + public string RankToken { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaImage.cs b/InstaSharper/Classes/Models/InstaImage.cs index 2b8bfa04..30e8c96d 100644 --- a/InstaSharper/Classes/Models/InstaImage.cs +++ b/InstaSharper/Classes/Models/InstaImage.cs @@ -10,8 +10,7 @@ public InstaImage(string uri, int width, int height) } public InstaImage() - { - } + { } public string URI { get; set; } diff --git a/InstaSharper/Classes/Models/InstaInboxMedia.cs b/InstaSharper/Classes/Models/InstaInboxMedia.cs new file mode 100644 index 00000000..6bf5ba6e --- /dev/null +++ b/InstaSharper/Classes/Models/InstaInboxMedia.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace InstaSharper.Classes.Models +{ + public class InstaInboxMedia + { + public List Images { get; set; } = new List(); + public long OriginalWidth { get; set; } + public long OriginalHeight { get; set; } + public InstaMediaType MediaType { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaLocation.cs b/InstaSharper/Classes/Models/InstaLocation.cs index 3fea0672..190bbecb 100644 --- a/InstaSharper/Classes/Models/InstaLocation.cs +++ b/InstaSharper/Classes/Models/InstaLocation.cs @@ -1,23 +1,13 @@ namespace InstaSharper.Classes.Models { - public class InstaLocation + public class InstaLocation : InstaLocationShort { public long FacebookPlacesId { get; set; } public string City { get; set; } - public string Address { get; set; } - - public string ExternalSource { get; set; } - - public double Lng { get; set; } - public long Pk { get; set; } - public double Lat { get; set; } - - public string Name { get; set; } - public string ShortName { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaLocationFeed.cs b/InstaSharper/Classes/Models/InstaLocationFeed.cs new file mode 100644 index 00000000..b57b1a46 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaLocationFeed.cs @@ -0,0 +1,11 @@ +namespace InstaSharper.Classes.Models +{ + public class InstaLocationFeed : InstaBaseFeed + { + public InstaMediaList RankedMedias { get; set; } = new InstaMediaList(); + public InstaStory Story { get; set; } + public InstaLocation Location { get; set; } + + public long MediaCount { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaLocationList.cs b/InstaSharper/Classes/Models/InstaLocationList.cs new file mode 100644 index 00000000..b5f53975 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaLocationList.cs @@ -0,0 +1,7 @@ +using System.Collections.Generic; + +namespace InstaSharper.Classes.Models +{ + public class InstaLocationList : List + { } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaLocationShort.cs b/InstaSharper/Classes/Models/InstaLocationShort.cs new file mode 100644 index 00000000..6d63a125 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaLocationShort.cs @@ -0,0 +1,17 @@ +namespace InstaSharper.Classes.Models +{ + public class InstaLocationShort + { + public string ExternalSource { get; set; } + + public string ExternalId { get; set; } + + public string Address { get; set; } + + public double Lng { get; set; } + + public double Lat { get; set; } + + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaLocationShortList.cs b/InstaSharper/Classes/Models/InstaLocationShortList.cs new file mode 100644 index 00000000..cb3cfa2a --- /dev/null +++ b/InstaSharper/Classes/Models/InstaLocationShortList.cs @@ -0,0 +1,7 @@ +using System.Collections.Generic; + +namespace InstaSharper.Classes.Models +{ + public class InstaLocationShortList : List + { } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaMedia.cs b/InstaSharper/Classes/Models/InstaMedia.cs index ca722eb5..0dfb21e1 100644 --- a/InstaSharper/Classes/Models/InstaMedia.cs +++ b/InstaSharper/Classes/Models/InstaMedia.cs @@ -10,7 +10,7 @@ public class InstaMedia public string InstaIdentifier { get; set; } - public DateTime DeviceTimeStap { get; set; } + public DateTime DeviceTimeStamp { get; set; } public InstaMediaType MediaType { get; set; } public string Code { get; set; } @@ -18,27 +18,20 @@ public class InstaMedia public string ClientCacheKey { get; set; } public string FilterType { get; set; } - public List Images { get; set; } = new List(); - + public List Videos { get; set; } = new List(); public int Width { get; set; } - - public string Height { get; set; } - public InstaUser User { get; set; } - public string TrakingToken { get; set; } - + public string TrackingToken { get; set; } public int LikesCount { get; set; } - public string NextMaxId { get; set; } - public InstaCaption Caption { get; set; } public string CommentsCount { get; set; } @@ -57,5 +50,7 @@ public class InstaMedia public bool HasAudio { get; set; } public bool IsMultiPost => Carousel != null; + public List PreviewComments { get; set; } = new List(); + public InstaLocation Location { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaMediaList.cs b/InstaSharper/Classes/Models/InstaMediaList.cs index 248887df..fb7a4f06 100644 --- a/InstaSharper/Classes/Models/InstaMediaList.cs +++ b/InstaSharper/Classes/Models/InstaMediaList.cs @@ -2,9 +2,10 @@ namespace InstaSharper.Classes.Models { - public class InstaMediaList : List + public class InstaMediaList : List, IInstaBaseList { public int Pages { get; set; } = 0; public int PageSize { get; set; } = 0; + public string NextId { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaMediaType.cs b/InstaSharper/Classes/Models/InstaMediaType.cs index 21437613..283642bc 100644 --- a/InstaSharper/Classes/Models/InstaMediaType.cs +++ b/InstaSharper/Classes/Models/InstaMediaType.cs @@ -3,6 +3,7 @@ public enum InstaMediaType { Image = 1, - Video = 2 + Video = 2, + Carousel = 8 } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaMessageLink.cs b/InstaSharper/Classes/Models/InstaMessageLink.cs new file mode 100644 index 00000000..6b3253eb --- /dev/null +++ b/InstaSharper/Classes/Models/InstaMessageLink.cs @@ -0,0 +1,8 @@ +namespace InstaSharper.Classes.Models +{ + public class InstaMessageLink + { + public string Url { get; set; } + public string Text { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaRecentActivityFeed.cs b/InstaSharper/Classes/Models/InstaRecentActivityFeed.cs index 11786cd7..ca54c906 100644 --- a/InstaSharper/Classes/Models/InstaRecentActivityFeed.cs +++ b/InstaSharper/Classes/Models/InstaRecentActivityFeed.cs @@ -5,8 +5,12 @@ namespace InstaSharper.Classes.Models { public class InstaRecentActivityFeed { + public string MediaId { get; set; } + public long ProfileId { get; set; } + public string ProfileName { get; set; } + public string ProfileImage { get; set; } public DateTime TimeStamp { get; set; } @@ -14,8 +18,10 @@ public class InstaRecentActivityFeed public string Text { get; set; } public List Links { get; set; } = new List(); + public InstaInlineFollow InlineFollow { get; set; } - public int Type { get; set; } + + public InstaActivityFeedType Type { get; set; } public string Pk { get; set; } } diff --git a/InstaSharper/Classes/Models/InstaRecipientThreads.cs b/InstaSharper/Classes/Models/InstaRecipients.cs similarity index 53% rename from InstaSharper/Classes/Models/InstaRecipientThreads.cs rename to InstaSharper/Classes/Models/InstaRecipients.cs index 8d3aa158..5f04aa69 100644 --- a/InstaSharper/Classes/Models/InstaRecipientThreads.cs +++ b/InstaSharper/Classes/Models/InstaRecipients.cs @@ -2,9 +2,12 @@ namespace InstaSharper.Classes.Models { - public class InstaRecipientThreads + public class InstaRecipients { - public List Items = new List(); + public List Threads { get; set; } = new List(); + + public List Users { get; set; } = new List(); + public long ExpiresIn { get; set; } public bool Filtered { get; set; } diff --git a/InstaSharper/Classes/Models/InsteReelFeed.cs b/InstaSharper/Classes/Models/InstaReelFeed.cs similarity index 95% rename from InstaSharper/Classes/Models/InsteReelFeed.cs rename to InstaSharper/Classes/Models/InstaReelFeed.cs index 5657d6ce..047cca41 100644 --- a/InstaSharper/Classes/Models/InsteReelFeed.cs +++ b/InstaSharper/Classes/Models/InstaReelFeed.cs @@ -3,7 +3,7 @@ namespace InstaSharper.Classes.Models { - public class InsteReelFeed + public class InstaReelFeed { public long HasBestiesMedia { get; set; } diff --git a/InstaSharper/Classes/Models/InstaStory.cs b/InstaSharper/Classes/Models/InstaStory.cs index 9521037d..73a1a648 100644 --- a/InstaSharper/Classes/Models/InstaStory.cs +++ b/InstaSharper/Classes/Models/InstaStory.cs @@ -7,11 +7,11 @@ public class InstaStory { public bool CanReply { get; set; } - public long ExpiringAt { get; set; } + public DateTime ExpiringAt { get; set; } public InstaUserShort User { get; set; } - public InstaOwner Owner { get; set; } + public InstaUserShort Owner { get; set; } public string SourceToken { get; set; } @@ -27,7 +27,7 @@ public class InstaStory public int SeenRankedPosition { get; set; } - public List Items { get; set; } + public List Items { get; set; } = new InstaMediaList(); public int PrefetchCount { get; set; } diff --git a/InstaSharper/Classes/Models/InstaStoryFeed.cs b/InstaSharper/Classes/Models/InstaStoryFeed.cs index 170b1bdf..86d6e15c 100644 --- a/InstaSharper/Classes/Models/InstaStoryFeed.cs +++ b/InstaSharper/Classes/Models/InstaStoryFeed.cs @@ -12,6 +12,6 @@ public class InstaStoryFeed public int StickerVersion { get; set; } - public List Items { get; set; } = new List(); + public List Items { get; set; } = new List(); } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaUserInfo.cs b/InstaSharper/Classes/Models/InstaUserInfo.cs new file mode 100644 index 00000000..0a9b1cf8 --- /dev/null +++ b/InstaSharper/Classes/Models/InstaUserInfo.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; + +namespace InstaSharper.Classes.Models +{ + public class InstaUserInfo + { + public long Pk { get; set; } + + public string Username { get; set; } + + public string FullName { get; set; } + + public bool IsPrivate { get; set; } + + public string ProfilePicUrl { get; set; } + + public bool IsVerified { get; set; } + + public bool HasAnonymousProfilePicture { get; set; } + + public long MediaCount { get; set; } + + public long GeoMediaCount { get; set; } + + public long FollowerCount { get; set; } + + public long FollowingCount { get; set; } + + public string Biography { get; set; } + + public string ExternalUrl { get; set; } + + public string ExternalLynxUrl { get; set; } + + public string ReelAutoArchive { get; set; } + + public long UsertagsCount { get; set; } + + public bool IsFavorite { get; set; } + + public bool HasChaining { get; set; } + + public string ProfileContext { get; set; } + + public List ProfileContextMutualFollowIds { get; set; } + + public bool IsBusiness { get; set; } + public bool IncludeDirectBlacklistStatus { get; set; } + public bool HasUnseenBestiesMedia { get; set; } + public bool AutoExpandChaining { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaUserList.cs b/InstaSharper/Classes/Models/InstaUserList.cs index 7709edd4..18531cc4 100644 --- a/InstaSharper/Classes/Models/InstaUserList.cs +++ b/InstaSharper/Classes/Models/InstaUserList.cs @@ -3,6 +3,5 @@ namespace InstaSharper.Classes.Models { public class InstaUserList : List - { - } + { } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaUserShort.cs b/InstaSharper/Classes/Models/InstaUserShort.cs index 6a51de42..0d2cba1a 100644 --- a/InstaSharper/Classes/Models/InstaUserShort.cs +++ b/InstaSharper/Classes/Models/InstaUserShort.cs @@ -7,12 +7,27 @@ public class InstaUserShort { public bool IsVerified { get; set; } public bool IsPrivate { get; set; } - public string Pk { get; set; } + public long Pk { get; set; } public string ProfilePicture { get; set; } public string ProfilePictureId { get; set; } = "unknown"; public string UserName { get; set; } public string FullName { get; set; } public static InstaUserShort Empty => new InstaUserShort {FullName = string.Empty, UserName = string.Empty}; + + public bool Equals(InstaUserShort user) + { + return Pk == user?.Pk; + } + + public override bool Equals(object obj) + { + return Equals(obj as InstaUserShort); + } + + public override int GetHashCode() + { + return Pk.GetHashCode(); + } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Models/InstaUserShortList.cs b/InstaSharper/Classes/Models/InstaUserShortList.cs index 3ce0e1f5..0c8adced 100644 --- a/InstaSharper/Classes/Models/InstaUserShortList.cs +++ b/InstaSharper/Classes/Models/InstaUserShortList.cs @@ -2,7 +2,8 @@ namespace InstaSharper.Classes.Models { - public class InstaUserShortList : List + public class InstaUserShortList : List, IInstaBaseList { + public string NextId { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/PaginationParameters.cs b/InstaSharper/Classes/PaginationParameters.cs new file mode 100644 index 00000000..503f4d2a --- /dev/null +++ b/InstaSharper/Classes/PaginationParameters.cs @@ -0,0 +1,26 @@ +namespace InstaSharper.Classes +{ + public class PaginationParameters + { + private PaginationParameters() + { } + + public string NextId { get; set; } = string.Empty; + public int MaximumPagesToLoad { get; private set; } + public int PagesLoaded { get; set; } + + public static PaginationParameters Empty => MaxPagesToLoad(int.MaxValue); + + public static PaginationParameters MaxPagesToLoad(int maxPagesToLoad) + { + return new PaginationParameters {MaximumPagesToLoad = maxPagesToLoad}; + } + + + public PaginationParameters StartFromId(string nextId) + { + NextId = nextId; + return this; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/PhoneVerificationSettings.cs b/InstaSharper/Classes/PhoneVerificationSettings.cs new file mode 100644 index 00000000..0469c814 --- /dev/null +++ b/InstaSharper/Classes/PhoneVerificationSettings.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes +{ + public class PhoneVerificationSettings + { + [JsonProperty("max_sms_count")] public short MaxSmsCount { get; set; } + + [JsonProperty("resend_sms_delay_sec")] public int ResendSmsDelaySeconds { get; set; } + + [JsonProperty("robocall_after_max_sms")] + public bool RobocallAfterMaxSms { get; set; } + + [JsonProperty("robocall_count_down_time")] + public int RobocallCountDownTime { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/RequestDelay.cs b/InstaSharper/Classes/RequestDelay.cs new file mode 100644 index 00000000..5b9f0942 --- /dev/null +++ b/InstaSharper/Classes/RequestDelay.cs @@ -0,0 +1,49 @@ +using System; + +namespace InstaSharper.Classes +{ + public class RequestDelay : IRequestDelay + { + private readonly int _maxSeconds; + private readonly int _minSeconds; + + private readonly Random _random; + private bool _isEnabled; + + private RequestDelay(int minSeconds, int maxSeconds) + { + _minSeconds = minSeconds; + _maxSeconds = maxSeconds; + _random = new Random(DateTime.Now.Millisecond); + _isEnabled = true; + } + + public TimeSpan Value => Exist ? TimeSpan.FromSeconds(_random.Next(_minSeconds, _maxSeconds)) : TimeSpan.Zero; + + public bool Exist => _isEnabled && _minSeconds != 0 && _maxSeconds != 0; + + public void Enable() + { + _isEnabled = true; + } + + public void Disable() + { + _isEnabled = false; + } + + public static IRequestDelay FromSeconds(int min, int max) + { + if (min > max) throw new ArgumentException("Value max should be bigger that value min"); + + if (max < 0) throw new ArgumentException("Both min and max values should be bigger than 0"); + + return new RequestDelay(min, max); + } + + public static IRequestDelay Empty() + { + return new RequestDelay(0, 0); + } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseType.cs b/InstaSharper/Classes/ResponseType.cs index 038b3140..7b5cde5c 100644 --- a/InstaSharper/Classes/ResponseType.cs +++ b/InstaSharper/Classes/ResponseType.cs @@ -10,6 +10,14 @@ public enum ResponseType OK = 5, WrongRequest = 6, SomePagesSkipped = 7, - UnExpectedResponse = 8 + UnExpectedResponse = 8, + InternalException = 9, + CheckPointChallengeRequired = 10, + Spam = 11, + ActionBlocked = 12, + DeletedPost = 13, + TemporarilyBlocked = 14, + CantLikeMedia = 15, + InvalidChallengeCode = 16, } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/BadStatusErrorsResponse.cs b/InstaSharper/Classes/ResponseWrappers/BadStatusErrorsResponse.cs index 2086c09c..484919a2 100644 --- a/InstaSharper/Classes/ResponseWrappers/BadStatusErrorsResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/BadStatusErrorsResponse.cs @@ -5,7 +5,6 @@ namespace InstaSharper.Classes.ResponseWrappers { public class BadStatusErrorsResponse : BaseStatusResponse { - [JsonProperty("message")] - public MessageErrorsResponse Message { get; set; } + [JsonProperty("message")] public MessageErrorsResponse Message { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/BadStatusResponse.cs b/InstaSharper/Classes/ResponseWrappers/BadStatusResponse.cs index a37c8d75..d31e659b 100644 --- a/InstaSharper/Classes/ResponseWrappers/BadStatusResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/BadStatusResponse.cs @@ -3,15 +3,24 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class BadStatusResponse : BaseStatusResponse + public class BadStatusResponse : BaseStatusResponse { - [JsonProperty("message")] - public string Message { get; set; } + [JsonProperty("message")] public string Message { get; set; } - [JsonProperty("error_type")] - public string ErrorType { get; set; } + [JsonProperty("error_type")] public string ErrorType { get; set; } = "unknown"; - [JsonProperty("checkpoint_url")] - public string CheckPointUrl { get; set; } + [JsonProperty("checkpoint_url")] public string CheckPointUrl { get; set; } + + [JsonProperty("spam")] public bool Spam { get; set; } + + [JsonProperty("feedback_title")] public string FeedbackTitle { get; set; } + + [JsonProperty("feedback_message")] public string FeedbackMessage { get; set; } + + [JsonProperty("feedback_appeal_label")] public string FeedbackAppealLabel { get; set; } + + [JsonProperty("feedback_action")] public string FeedbackAction { get; set; } + + [JsonProperty("feedback_ignore_label")] public string FeedbackIgnoreLabel { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs b/InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs index 36377921..b654d8c1 100644 --- a/InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseLoadableResponse.cs @@ -2,24 +2,19 @@ namespace InstaSharper.Classes.ResponseWrappers.BaseResponse { - internal class BaseLoadableResponse : BaseStatusResponse + public class BaseLoadableResponse : BaseStatusResponse { - [JsonProperty("more_available")] - public bool MoreAvailable { get; set; } + [JsonProperty("more_available")] public bool MoreAvailable { get; set; } - [JsonProperty("num_results")] - public int ResultsCount { get; set; } + [JsonProperty("num_results")] public int ResultsCount { get; set; } - [JsonProperty("total_count")] - public int TotalCount { get; set; } + [JsonProperty("total_count")] public int TotalCount { get; set; } [JsonProperty("auto_load_more_enabled")] public bool AutoLoadMoreEnabled { get; set; } - [JsonProperty("next_max_id")] - public string NextMaxId { get; set; } + [JsonProperty("next_max_id")] public string NextMaxId { get; set; } - [JsonProperty("rank_token")] - public string RankToken { get; set; } = "unknown"; + [JsonProperty("rank_token")] public string RankToken { get; set; } = "unknown"; } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseStatusResponse.cs b/InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseStatusResponse.cs index c8be7159..588ea823 100644 --- a/InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseStatusResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/BaseResponse/BaseStatusResponse.cs @@ -4,8 +4,7 @@ namespace InstaSharper.Classes.ResponseWrappers.BaseResponse { public class BaseStatusResponse { - [JsonProperty("status")] - public string Status { get; set; } + [JsonProperty("status")] public string Status { get; set; } public bool IsOk() { diff --git a/InstaSharper/Classes/ResponseWrappers/DeleteResponse.cs b/InstaSharper/Classes/ResponseWrappers/DeleteResponse.cs index 05ed9e0a..ff4151d7 100644 --- a/InstaSharper/Classes/ResponseWrappers/DeleteResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/DeleteResponse.cs @@ -3,9 +3,8 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class DeleteResponse : BaseStatusResponse + public class DeleteResponse : BaseStatusResponse { - [JsonProperty("did_delete")] - public bool IsDeleted { get; set; } + [JsonProperty("did_delete")] public bool IsDeleted { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/FbLocation.cs b/InstaSharper/Classes/ResponseWrappers/FbLocation.cs new file mode 100644 index 00000000..50ac5225 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/FbLocation.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class FbLocation + { + [JsonProperty("pk")] public long Pk { get; set; } + + [JsonProperty("name")] public string Name { get; set; } + + [JsonProperty("address")] public string Address { get; set; } + + [JsonProperty("city")] public string City { get; set; } + + [JsonProperty("short_name")] public string ShortName { get; set; } + + [JsonProperty("lng")] public double Lng { get; set; } + + [JsonProperty("lat")] public double Lat { get; set; } + + [JsonProperty("external_source")] public string ExternalSource { get; set; } + + [JsonProperty("facebook_places_id")] public object FacebookPlacesId { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/FbPlace.cs b/InstaSharper/Classes/ResponseWrappers/FbPlace.cs new file mode 100644 index 00000000..20edab2c --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/FbPlace.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class FbPlace + { + [JsonProperty("location")] + public FbLocation Location { get; set; } + + [JsonProperty("title")] + public string Title { get; set; } + + [JsonProperty("subtitle")] + public string Subtitle { get; set; } + + [JsonProperty("media_bundles")] + public IList MediaBundles { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/FbSearchPlaceResponse.cs b/InstaSharper/Classes/ResponseWrappers/FbSearchPlaceResponse.cs new file mode 100644 index 00000000..12e69cd9 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/FbSearchPlaceResponse.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class FbSearchPlaceResponse + { + [JsonProperty("items")] public IList Items { get; set; } + + [JsonProperty("has_more")] public bool HasMore { get; set; } + + [JsonProperty("rank_token")] public string RankToken { get; set; } + + [JsonProperty("status")] public string Status { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/FollowedByResponse.cs b/InstaSharper/Classes/ResponseWrappers/FollowedByResponse.cs index 3b07d147..fb4f7ccb 100644 --- a/InstaSharper/Classes/ResponseWrappers/FollowedByResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/FollowedByResponse.cs @@ -2,9 +2,8 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class FollowedByResponse + public class FollowedByResponse { - [JsonProperty("count")] - public int Count { get; set; } + [JsonProperty("count")] public int Count { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/IInstaRecipientsResponse.cs b/InstaSharper/Classes/ResponseWrappers/IInstaRecipientsResponse.cs index 16d48ebf..752e3b0c 100644 --- a/InstaSharper/Classes/ResponseWrappers/IInstaRecipientsResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/IInstaRecipientsResponse.cs @@ -1,6 +1,6 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal interface IInstaRecipientsResponse + public interface IInstaRecipientsResponse { long Expires { get; set; } diff --git a/InstaSharper/Classes/ResponseWrappers/ImageResponse.cs b/InstaSharper/Classes/ResponseWrappers/ImageResponse.cs index c9a2a388..85ecf42c 100644 --- a/InstaSharper/Classes/ResponseWrappers/ImageResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/ImageResponse.cs @@ -2,15 +2,12 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class ImageResponse + public class ImageResponse { - [JsonProperty("url")] - public string Url { get; set; } + [JsonProperty("url")] public string Url { get; set; } - [JsonProperty("width")] - public string Width { get; set; } + [JsonProperty("width")] public string Width { get; set; } - [JsonProperty("height")] - public string Height { get; set; } + [JsonProperty("height")] public string Height { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/ImagesResponse.cs b/InstaSharper/Classes/ResponseWrappers/ImagesResponse.cs index a091cebf..1d76138b 100644 --- a/InstaSharper/Classes/ResponseWrappers/ImagesResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/ImagesResponse.cs @@ -2,15 +2,12 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class ImagesResponse + public class ImagesResponse { - [JsonProperty("low_resolution")] - public ImageResponse LowResolution { get; set; } + [JsonProperty("low_resolution")] public ImageResponse LowResolution { get; set; } - [JsonProperty("thumbnail")] - public ImageResponse Thumbnail { get; set; } + [JsonProperty("thumbnail")] public ImageResponse Thumbnail { get; set; } - [JsonProperty("standard_resolution")] - public ImageResponse StandartResolution { get; set; } + [JsonProperty("standard_resolution")] public ImageResponse StandartResolution { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaCaptionResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCaptionResponse.cs index 234348af..55ce334c 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaCaptionResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaCaptionResponse.cs @@ -3,30 +3,22 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaCaptionResponse : BaseStatusResponse + public class InstaCaptionResponse : BaseStatusResponse { - [JsonProperty("user_id")] - public long UserId { get; set; } + [JsonProperty("user_id")] public long UserId { get; set; } - [JsonProperty("created_at_utc")] - public string CreatedAtUtcUnixLike { get; set; } + [JsonProperty("created_at_utc")] public string CreatedAtUtcUnixLike { get; set; } - [JsonProperty("created_at")] - public string CreatedAtUnixLike { get; set; } + [JsonProperty("created_at")] public string CreatedAtUnixLike { get; set; } - [JsonProperty("content_type")] - public string ContentType { get; set; } + [JsonProperty("content_type")] public string ContentType { get; set; } - [JsonProperty("user")] - public InstaUserShortResponse User { get; set; } + [JsonProperty("user")] public InstaUserShortResponse User { get; set; } - [JsonProperty("text")] - public string Text { get; set; } + [JsonProperty("text")] public string Text { get; set; } - [JsonProperty("media_id")] - public string MediaId { get; set; } + [JsonProperty("media_id")] public string MediaId { get; set; } - [JsonProperty("pk")] - public string Pk { get; set; } + [JsonProperty("pk")] public string Pk { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaCarouselItemResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCarouselItemResponse.cs index f9c4fac4..7d708ca0 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaCarouselItemResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaCarouselItemResponse.cs @@ -1,29 +1,25 @@ +using System.Collections.Generic; using InstaSharper.Classes.Models; using Newtonsoft.Json; namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaCarouselItemResponse + public class InstaCarouselItemResponse { - [JsonProperty("id")] - public string InstaIdentifier { get; set; } + [JsonProperty("id")] public string InstaIdentifier { get; set; } - [JsonProperty("media_type")] - public InstaMediaType MediaType { get; set; } + [JsonProperty("media_type")] public InstaMediaType MediaType { get; set; } - [JsonProperty("image_versions2")] - public InstaImageCandidatesResponse Images { get; set; } + [JsonProperty("image_versions2")] public InstaImageCandidatesResponse Images { get; set; } - [JsonProperty("original_width")] - public string Width { get; set; } + [JsonProperty("video_versions")] public List Videos { get; set; } - [JsonProperty("original_height")] - public string Height { get; set; } + [JsonProperty("original_width")] public string Width { get; set; } - [JsonProperty("pk")] - public string Pk { get; set; } + [JsonProperty("original_height")] public string Height { get; set; } - [JsonProperty("carousel_parent_id")] - public string CarouselParentId { get; set; } + [JsonProperty("pk")] public string Pk { get; set; } + + [JsonProperty("carousel_parent_id")] public string CarouselParentId { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaCarouselResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCarouselResponse.cs index 70803cd4..552dffc4 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaCarouselResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaCarouselResponse.cs @@ -2,7 +2,6 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaCarouselResponse : List - { - } + public class InstaCarouselResponse : List + { } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaChallenge.cs b/InstaSharper/Classes/ResponseWrappers/InstaChallenge.cs new file mode 100644 index 00000000..f43b0d4d --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaChallenge.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaChallenge + { + [JsonProperty("url")] public string Url { get; set; } + + [JsonProperty("api_path")] public string ApiPath { get; set; } + + [JsonProperty("hide_webview_header")] public bool HideWebviewHeader { get; set; } + + [JsonProperty("lock")] public bool Lock { get; set; } + + [JsonProperty("logout")] public bool Logout { get; set; } + + [JsonProperty("native_flow")] public bool NativeFlow { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaChannelResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaChannelResponse.cs index 2c4b3784..08801e32 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaChannelResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaChannelResponse.cs @@ -2,24 +2,18 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaChannelResponse + public class InstaChannelResponse { - [JsonProperty("title")] - public string Title { get; set; } + [JsonProperty("title")] public string Title { get; set; } - [JsonProperty("channel_id")] - public string ChannelId { get; set; } + [JsonProperty("channel_id")] public string ChannelId { get; set; } - [JsonProperty("channel_type")] - public string ChannelType { get; set; } + [JsonProperty("channel_type")] public string ChannelType { get; set; } - [JsonProperty("header")] - public string Header { get; set; } + [JsonProperty("header")] public string Header { get; set; } - [JsonProperty("context")] - public string Context { get; set; } + [JsonProperty("context")] public string Context { get; set; } - [JsonProperty("media")] - public InstaMediaItemResponse Media { get; set; } + [JsonProperty("media")] public InstaMediaItemResponse Media { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaCollectionItemResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCollectionItemResponse.cs new file mode 100644 index 00000000..e065039a --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaCollectionItemResponse.cs @@ -0,0 +1,18 @@ +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaCollectionItemResponse : BaseLoadableResponse + { + [JsonProperty("collection_id")] public long CollectionId { get; set; } + + [JsonProperty("collection_name")] public string CollectionName { get; set; } + + [JsonProperty("has_related_media")] public bool HasRelatedMedia { get; set; } + + [JsonProperty("cover_media")] public InstaCoverMediaResponse CoverMedia { get; set; } + + [JsonProperty("items")] public InstaMediaListResponse Media { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaCollectionsResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCollectionsResponse.cs new file mode 100644 index 00000000..b9b4af5e --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaCollectionsResponse.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaCollectionsResponse : BaseLoadableResponse + { + [JsonProperty("items")] public List Items { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaCommentListResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCommentListResponse.cs index 0c25e21e..619d617d 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaCommentListResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaCommentListResponse.cs @@ -4,30 +4,24 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaCommentListResponse : BaseStatusResponse + public class InstaCommentListResponse : BaseStatusResponse { - [JsonProperty("comment_count")] - public int CommentsCount { get; set; } + [JsonProperty("comment_count")] public int CommentsCount { get; set; } - [JsonProperty("next_max_id")] - public string NextMaxId { get; set; } + [JsonProperty("next_max_id")] public string NextMaxId { get; set; } [JsonProperty("comment_likes_enabled")] public bool LikesEnabled { get; set; } - [JsonProperty("caption_is_edited")] - public bool CaptionIsEdited { get; set; } + [JsonProperty("caption_is_edited")] public bool CaptionIsEdited { get; set; } [JsonProperty("has_more_headload_comments")] public bool MoreHeadLoadAvailable { get; set; } - [JsonProperty("caption")] - public InstaCaptionResponse Caption { get; set; } + [JsonProperty("caption")] public InstaCaptionResponse Caption { get; set; } - [JsonProperty("has_more_comments")] - public bool MoreComentsAvailable { get; set; } + [JsonProperty("has_more_comments")] public bool MoreComentsAvailable { get; set; } - [JsonProperty("comments")] - public List Comments { get; set; } + [JsonProperty("comments")] public List Comments { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaCommentResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCommentResponse.cs index cbbfbb05..0679016f 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaCommentResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaCommentResponse.cs @@ -2,39 +2,28 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaCommentResponse + public class InstaCommentResponse { - [JsonProperty("type")] - public int Type { get; set; } + [JsonProperty("type")] public int Type { get; set; } - [JsonProperty("bit_flags")] - public int BitFlags { get; set; } + [JsonProperty("bit_flags")] public int BitFlags { get; set; } - [JsonProperty("user_id")] - public long UserId { get; set; } + [JsonProperty("user_id")] public long UserId { get; set; } - [JsonProperty("status")] - public string Status { get; set; } + [JsonProperty("status")] public string Status { get; set; } - [JsonProperty("created_at_utc")] - public string CreatedAtUtc { get; set; } + [JsonProperty("created_at_utc")] public string CreatedAtUtc { get; set; } - [JsonProperty("comment_like_count")] - public int LikesCount { get; set; } + [JsonProperty("comment_like_count")] public int LikesCount { get; set; } - [JsonProperty("created_at")] - public string CreatedAt { get; set; } + [JsonProperty("created_at")] public string CreatedAt { get; set; } - [JsonProperty("content_type")] - public string ContentType { get; set; } + [JsonProperty("content_type")] public string ContentType { get; set; } - [JsonProperty("user")] - public InstaUserShortResponse User { get; set; } + [JsonProperty("user")] public InstaUserShortResponse User { get; set; } - [JsonProperty("pk")] - public string Pk { get; set; } + [JsonProperty("pk")] public long Pk { get; set; } - [JsonProperty("text")] - public string Text { get; set; } + [JsonProperty("text")] public string Text { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaCoverMediaResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCoverMediaResponse.cs new file mode 100644 index 00000000..baed28e1 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaCoverMediaResponse.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaCoverMediaResponse + { + [JsonProperty("id")] public long Id { get; set; } + + [JsonProperty("image_versions2")] public InstaImageCandidatesResponse ImageVersions { get; set; } + + [JsonProperty("media_type")] public int MediaType { get; set; } + + [JsonProperty("original_height")] public int OriginalHeight { get; set; } + + [JsonProperty("original_width")] public int OriginalWidth { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaCurrentUserResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaCurrentUserResponse.cs index c9f1a57e..4da52574 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaCurrentUserResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaCurrentUserResponse.cs @@ -2,7 +2,7 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaCurrentUserResponse : InstaUserShortResponse + public class InstaCurrentUserResponse : InstaUserShortResponse { [JsonProperty("has_anonymous_profile_picture")] public bool HasAnonymousProfilePicture { get; set; } @@ -10,26 +10,19 @@ internal class InstaCurrentUserResponse : InstaUserShortResponse [JsonProperty("show_conversion_edit_entry")] public bool ShowConversationEditEntry { get; set; } - [JsonProperty("birthday")] - public string Birthday { get; set; } + [JsonProperty("birthday")] public string Birthday { get; set; } - [JsonProperty("biography")] - public string Biography { get; set; } + [JsonProperty("biography")] public string Biography { get; set; } - [JsonProperty("phone_number")] - public string PhoneNumber { get; set; } + [JsonProperty("phone_number")] public string PhoneNumber { get; set; } - [JsonProperty("country_code")] - public int CountryCode { get; set; } + [JsonProperty("country_code")] public int CountryCode { get; set; } - [JsonProperty("national_number")] - public long NationalNumber { get; set; } + [JsonProperty("national_number")] public long NationalNumber { get; set; } - [JsonProperty("gender")] - public int Gender { get; set; } + [JsonProperty("gender")] public int Gender { get; set; } - [JsonProperty("email")] - public string Email { get; set; } + [JsonProperty("email")] public string Email { get; set; } [JsonProperty("hd_profile_pic_versions")] public ImageResponse[] HDProfilePicVersions { get; set; } @@ -37,7 +30,6 @@ internal class InstaCurrentUserResponse : InstaUserShortResponse [JsonProperty("hd_profile_pic_url_info")] public ImageResponse HDProfilePicture { get; set; } - [JsonProperty("external_url")] - public string ExternalURL { get; set; } + [JsonProperty("external_url")] public string ExternalURL { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxContainerResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxContainerResponse.cs index 51c353ba..af729258 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxContainerResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxContainerResponse.cs @@ -4,19 +4,16 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaDirectInboxContainerResponse : BaseStatusResponse + public class InstaDirectInboxContainerResponse : BaseStatusResponse { [JsonProperty("pending_requests_total")] public int PendingRequestsCount { get; set; } - [JsonProperty("seq_id")] - public int SeqId { get; set; } + [JsonProperty("seq_id")] public int SeqId { get; set; } - [JsonProperty("subscription")] - public InstaDirectInboxSubscriptionResponse Subscription { get; set; } + [JsonProperty("subscription")] public InstaDirectInboxSubscriptionResponse Subscription { get; set; } - [JsonProperty("inbox")] - public InstaDirectInboxResponse Inbox { get; set; } + [JsonProperty("inbox")] public InstaDirectInboxResponse Inbox { get; set; } [JsonProperty("pending_requests_users")] public List PendingUsers { get; set; } diff --git a/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxItemResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxItemResponse.cs index 28d81abb..4ad7a7ee 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxItemResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxItemResponse.cs @@ -4,27 +4,26 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaDirectInboxItemResponse : BaseStatusResponse + public class InstaDirectInboxItemResponse : BaseStatusResponse { - [JsonProperty("text")] - public string Text { get; set; } + [JsonProperty("text")] public string Text { get; set; } - [JsonProperty("user_id")] - public long UserId { get; set; } + [JsonProperty("like")] public string Like { get; set; } - [JsonProperty("timestamp")] - public string TimeStamp { get; set; } + [JsonProperty("user_id")] public long UserId { get; set; } - [JsonProperty("item_id")] - public string ItemId { get; set; } + [JsonProperty("timestamp")] public string TimeStamp { get; set; } - [JsonProperty("item_type")] - public string ItemType { get; set; } + [JsonProperty("item_id")] public string ItemId { get; set; } - [JsonProperty("media_share")] - public InstaMediaItemResponse MediaShare { get; set; } + [JsonProperty("item_type")] public string ItemType { get; set; } - [JsonProperty("client_context")] - public Guid ClientContext { get; set; } + [JsonProperty("media_share")] public InstaMediaItemResponse MediaShare { get; set; } + + [JsonProperty("media")] public InstaInboxMediaResponse Media { get; set; } + + [JsonProperty("link")] public InstaWebLinkResponse Link { get; set; } + + [JsonProperty("client_context")] public string ClientContext { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxResponse.cs index 51c17d8f..9948e9b0 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxResponse.cs @@ -3,18 +3,14 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaDirectInboxResponse + public class InstaDirectInboxResponse { - [JsonProperty("has_older")] - public bool HasOlder { get; set; } + [JsonProperty("has_older")] public bool HasOlder { get; set; } - [JsonProperty("unseen_count_ts")] - public long UnseenCountTs { get; set; } + [JsonProperty("unseen_count_ts")] public long UnseenCountTs { get; set; } - [JsonProperty("unseen_count")] - public long UnseenCount { get; set; } + [JsonProperty("unseen_count")] public long UnseenCount { get; set; } - [JsonProperty("threads")] - public List Threads { get; set; } + [JsonProperty("threads")] public List Threads { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxSubscriptionResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxSubscriptionResponse.cs index 5a9573c7..adbab234 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxSubscriptionResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxSubscriptionResponse.cs @@ -2,18 +2,14 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaDirectInboxSubscriptionResponse + public class InstaDirectInboxSubscriptionResponse { - [JsonProperty("topic")] - public string Topic { get; set; } + [JsonProperty("topic")] public string Topic { get; set; } - [JsonProperty("url")] - public string Url { get; set; } + [JsonProperty("url")] public string Url { get; set; } - [JsonProperty("auth")] - public string Auth { get; set; } + [JsonProperty("auth")] public string Auth { get; set; } - [JsonProperty("sequence")] - public string Sequence { get; set; } + [JsonProperty("sequence")] public string Sequence { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxThreadLastSeenResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxThreadLastSeenResponse.cs new file mode 100644 index 00000000..c8358f55 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxThreadLastSeenResponse.cs @@ -0,0 +1,14 @@ +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaDirectInboxThreadLastSeenResponse : BaseStatusResponse + { + [JsonProperty("user_id")] public long UserId { get; set; } + + [JsonProperty("timestamp")] public string TimeStamp { get; set; } + + [JsonProperty("item_id")] public string ItemId { get; set; } + } +} diff --git a/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxThreadResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxThreadResponse.cs index 21302911..64bf3a7b 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxThreadResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaDirectInboxThreadResponse.cs @@ -1,58 +1,47 @@ using System.Collections.Generic; using InstaSharper.Classes.Models; using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using InstaSharper.Converters.Json; using Newtonsoft.Json; namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaDirectInboxThreadResponse : BaseStatusResponse + public class InstaDirectInboxThreadResponse : BaseStatusResponse { - [JsonProperty("muted")] - public bool Muted { get; set; } + [JsonProperty("muted")] public bool Muted { get; set; } - [JsonProperty("users")] - public List Users { get; set; } + [JsonProperty("users")] public List Users { get; set; } - [JsonProperty("thread_title")] - public string Title { get; set; } + [JsonProperty("thread_title")] public string Title { get; set; } - [JsonProperty("oldest_cursor")] - public string OldestCursor { get; set; } + [JsonProperty("oldest_cursor")] public string OldestCursor { get; set; } - [JsonProperty("last_activity_at")] - public string LastActivity { get; set; } + [JsonProperty("last_activity_at")] public string LastActivity { get; set; } - [JsonProperty("viewer_id")] - public string VieweId { get; set; } + [JsonProperty("viewer_id")] public string VieweId { get; set; } - [JsonProperty("thread_id")] - public string ThreadId { get; set; } + [JsonProperty("thread_id")] public string ThreadId { get; set; } - [JsonProperty("has_older")] - public bool HasOlder { get; set; } + [JsonProperty("has_older")] public bool HasOlder { get; set; } - [JsonProperty("inviter")] - public InstaUserShortResponse Inviter { get; set; } + [JsonProperty("inviter")] public InstaUserShortResponse Inviter { get; set; } - [JsonProperty("named")] - public bool Named { get; set; } + [JsonProperty("named")] public bool Named { get; set; } - [JsonProperty("pending")] - public bool Pending { get; set; } + [JsonProperty("pending")] public bool Pending { get; set; } - [JsonProperty("canonical")] - public bool Canonical { get; set; } + [JsonProperty("canonical")] public bool Canonical { get; set; } - [JsonProperty("has_newer")] - public bool HasNewer { get; set; } + [JsonProperty("has_newer")] public bool HasNewer { get; set; } - [JsonProperty("is_spam")] - public bool IsSpam { get; set; } + [JsonProperty("is_spam")] public bool IsSpam { get; set; } - [JsonProperty("thread_type")] - public InstaDirectThreadType ThreadType { get; set; } + [JsonProperty("thread_type")] public InstaDirectThreadType ThreadType { get; set; } - [JsonProperty("items")] - public List Items { get; set; } + [JsonProperty("items")] public List Items { get; set; } + + [JsonProperty("last_seen_at")] + [JsonConverter(typeof(InstaInboxThreadLastSeenConverter))] + public List LastSeen { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaExploreFeedResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaExploreFeedResponse.cs index 4c6a41a7..9d3f65a2 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaExploreFeedResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaExploreFeedResponse.cs @@ -3,9 +3,8 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaExploreFeedResponse : BaseLoadableResponse + public class InstaExploreFeedResponse : BaseLoadableResponse { - [JsonIgnore] - public InstaExploreItemsResponse Items { get; set; } = new InstaExploreItemsResponse(); + [JsonIgnore] public InstaExploreItemsResponse Items { get; set; } = new InstaExploreItemsResponse(); } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaExploreItemsResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaExploreItemsResponse.cs index 5d104e58..2527439d 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaExploreItemsResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaExploreItemsResponse.cs @@ -4,15 +4,12 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaExploreItemsResponse : BaseLoadableResponse + public class InstaExploreItemsResponse : BaseLoadableResponse { - [JsonIgnore] - public InstaStoryTrayResponse StoryTray { get; set; } = new InstaStoryTrayResponse(); + [JsonIgnore] public InstaStoryTrayResponse StoryTray { get; set; } = new InstaStoryTrayResponse(); - [JsonIgnore] - public List Medias { get; set; } = new List(); + [JsonIgnore] public List Medias { get; set; } = new List(); - [JsonIgnore] - public InstaChannelResponse Channel { get; set; } + [JsonIgnore] public InstaChannelResponse Channel { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaFeedResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaFeedResponse.cs index 5f8e2c5e..d7a7c276 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaFeedResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaFeedResponse.cs @@ -4,10 +4,9 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaFeedResponse : BaseLoadableResponse + public class InstaFeedResponse : BaseLoadableResponse { - [JsonProperty("is_direct_v2_enabled")] - public bool IsDirectV2Enabled { get; set; } + [JsonProperty("is_direct_v2_enabled")] public bool IsDirectV2Enabled { get; set; } [JsonProperty(TypeNameHandling = TypeNameHandling.Auto)] public List Items { get; set; } = new List(); diff --git a/InstaSharper/Classes/ResponseWrappers/InstaFriendshipStatusResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaFriendshipStatusResponse.cs index 116dce27..4166a69f 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaFriendshipStatusResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaFriendshipStatusResponse.cs @@ -3,24 +3,18 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaFriendshipStatusResponse : BaseStatusResponse + public class InstaFriendshipStatusResponse : BaseStatusResponse { - [JsonProperty("following")] - public bool Following { get; set; } + [JsonProperty("following")] public bool Following { get; set; } - [JsonProperty("followed_by")] - public bool FollowedBy { get; set; } + [JsonProperty("followed_by")] public bool FollowedBy { get; set; } - [JsonProperty("blocking")] - public bool Blocking { get; set; } + [JsonProperty("blocking")] public bool Blocking { get; set; } - [JsonProperty("is_private")] - public bool IsPrivate { get; set; } + [JsonProperty("is_private")] public bool IsPrivate { get; set; } - [JsonProperty("incoming_request")] - public bool IncomingRequest { get; set; } + [JsonProperty("incoming_request")] public bool IncomingRequest { get; set; } - [JsonProperty("outgoing_request")] - public bool OutgoingRequest { get; set; } + [JsonProperty("outgoing_request")] public bool OutgoingRequest { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaHashtagResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaHashtagResponse.cs index b8955de3..562741fe 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaHashtagResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaHashtagResponse.cs @@ -2,12 +2,12 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaHashtagResponse + public class InstaHashtagResponse { - [JsonProperty("id")] - public long Id { get; set; } + [JsonProperty("id")] public long Id { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] public string Name { get; set; } + + [JsonProperty("media_count")] public long MediaCount { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaHashtagSearchResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaHashtagSearchResponse.cs new file mode 100644 index 00000000..35c0a261 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaHashtagSearchResponse.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaHashtagSearchResponse : BaseStatusResponse + { + [JsonProperty("results")] public List Tags { get; set; } + + [JsonProperty("has_more")] public bool? MoreAvailable { get; set; } + + [JsonProperty("rank_token")] public string RankToken { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaImageCandidatesResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaImageCandidatesResponse.cs index 19ea185f..3649cae9 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaImageCandidatesResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaImageCandidatesResponse.cs @@ -3,9 +3,8 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaImageCandidatesResponse + public class InstaImageCandidatesResponse { - [JsonProperty("candidates")] - public List Candidates { get; set; } + [JsonProperty("candidates")] public List Candidates { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaInboxMediaResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaInboxMediaResponse.cs new file mode 100644 index 00000000..6161c059 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaInboxMediaResponse.cs @@ -0,0 +1,16 @@ +using InstaSharper.Classes.Models; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaInboxMediaResponse + { + [JsonProperty("image_versions2")] public InstaImageCandidatesResponse ImageCandidates { get; set; } + + [JsonProperty("original_width")] public long OriginalWidth { get; set; } + + [JsonProperty("original_height")] public long OriginalHeight { get; set; } + + [JsonProperty("media_type")] public InstaMediaType MediaType { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaInlineFollowResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaInlineFollowResponse.cs index 5a15d3f7..ef41e17e 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaInlineFollowResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaInlineFollowResponse.cs @@ -2,15 +2,12 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaInlineFollowResponse + public class InstaInlineFollowResponse { - [JsonProperty("outgoing_request")] - public bool IsOutgoingRequest { get; set; } + [JsonProperty("outgoing_request")] public bool IsOutgoingRequest { get; set; } - [JsonProperty("following")] - public bool IsFollowing { get; set; } + [JsonProperty("following")] public bool IsFollowing { get; set; } - [JsonProperty("user_info")] - public InstaUserShortResponse UserInfo { get; set; } + [JsonProperty("user_info")] public InstaUserShortResponse UserInfo { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaLinkResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaLinkResponse.cs index b4aa1b3e..20e888e5 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaLinkResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaLinkResponse.cs @@ -2,18 +2,14 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaLinkResponse + public class InstaLinkResponse { - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] public string Type { get; set; } - [JsonProperty("start")] - public string Start { get; set; } + [JsonProperty("start")] public string Start { get; set; } - [JsonProperty("end")] - public string End { get; set; } + [JsonProperty("end")] public string End { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] public string Id { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaLocationFeedResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaLocationFeedResponse.cs new file mode 100644 index 00000000..b17f072c --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaLocationFeedResponse.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaLocationFeedResponse : BaseLoadableResponse + { + [JsonProperty("ranked_items")] + public List RankedItems { get; set; } = new List(); + + [JsonProperty("items")] + public List Items { get; set; } = new List(); + + [JsonProperty("story")] public InstaStoryResponse Story { get; set; } + + [JsonProperty("media_count")] public long MediaCount { get; set; } + + [JsonProperty("location")] public InstaLocationResponse Location { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaLocationResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaLocationResponse.cs index 0579684a..775b95d4 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaLocationResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaLocationResponse.cs @@ -2,33 +2,14 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaLocationResponse + public class InstaLocationResponse : InstaLocationShortResponse { - [JsonProperty("facebook_places_id")] - public long FacebookPlacesId { get; set; } + [JsonProperty("facebook_places_id")] public long FacebookPlacesId { get; set; } - [JsonProperty("city")] - public string City { get; set; } + [JsonProperty("city")] public string City { get; set; } - [JsonProperty("address")] - public string Address { get; set; } + [JsonProperty("pk")] public long Pk { get; set; } - [JsonProperty("external_source")] - public string ExternalSource { get; set; } - - [JsonProperty("lng")] - public double Lng { get; set; } - - [JsonProperty("pk")] - public long Pk { get; set; } - - [JsonProperty("lat")] - public double Lat { get; set; } - - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("short_name")] - public string ShortName { get; set; } + [JsonProperty("short_name")] public string ShortName { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaLocationSearchResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaLocationSearchResponse.cs new file mode 100644 index 00000000..f810254c --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaLocationSearchResponse.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaLocationSearchResponse + { + [JsonProperty("venues")] public List Locations { get; set; } + + [JsonProperty("request_id")] public string RequestId { get; set; } + + [JsonProperty("status")] public string Status { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaLocationShortResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaLocationShortResponse.cs new file mode 100644 index 00000000..35933bee --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaLocationShortResponse.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaLocationShortResponse + { + [JsonProperty("lat")] public double Lat { get; set; } + + [JsonProperty("lng")] public double Lng { get; set; } + + [JsonProperty("address")] public string Address { get; set; } + + [JsonProperty("external_id")] public string ExternalId { get; set; } + + [JsonProperty("external_id_source")] public string ExternalIdSource { get; set; } + + [JsonProperty("name")] public string Name { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaLoginResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaLoginResponse.cs index d86cac3d..33cb7f4f 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaLoginResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaLoginResponse.cs @@ -2,12 +2,10 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaLoginResponse + public class InstaLoginResponse { - [JsonProperty("status")] - public string Status { get; set; } + [JsonProperty("status")] public string Status { get; set; } - [JsonProperty("logged_in_user")] - public InstaUserShortResponse User { get; set; } + [JsonProperty("logged_in_user")] public InstaUserShortResponse User { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaMediaAlbumResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaMediaAlbumResponse.cs new file mode 100644 index 00000000..6b31a98a --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaMediaAlbumResponse.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaMediaAlbumResponse + { + [JsonProperty("media")] public InstaMediaItemResponse Media { get; set; } + + [JsonProperty("client_sidecar_id")] public string ClientSidecarId { get; set; } + + [JsonProperty("status")] public string Status { get; set; } + } +} diff --git a/InstaSharper/Classes/ResponseWrappers/InstaMediaItemResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaMediaItemResponse.cs index 122042a8..694260ef 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaMediaItemResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaMediaItemResponse.cs @@ -4,82 +4,63 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaMediaItemResponse + public class InstaMediaItemResponse { - [JsonProperty("taken_at")] - public string TakenAtUnixLike { get; set; } + [JsonProperty("taken_at")] public string TakenAtUnixLike { get; set; } - [JsonProperty("pk")] - public string Pk { get; set; } + [JsonProperty("pk")] public string Pk { get; set; } - [JsonProperty("id")] - public string InstaIdentifier { get; set; } + [JsonProperty("id")] public string InstaIdentifier { get; set; } - [JsonProperty("device_timestamp")] - public string DeviceTimeStapUnixLike { get; set; } + [JsonProperty("device_timestamp")] public string DeviceTimeStampUnixLike { get; set; } - [JsonProperty("media_type")] - public InstaMediaType MediaType { get; set; } + [JsonProperty("media_type")] public InstaMediaType MediaType { get; set; } + [JsonProperty("code")] public string Code { get; set; } - [JsonProperty("code")] - public string Code { get; set; } + [JsonProperty("client_cache_key")] public string ClientCacheKey { get; set; } - [JsonProperty("client_cache_key")] - public string ClientCacheKey { get; set; } + [JsonProperty("filter_type")] public string FilterType { get; set; } - [JsonProperty("filter_type")] - public string FilterType { get; set; } + [JsonProperty("image_versions2")] public InstaImageCandidatesResponse Images { get; set; } - [JsonProperty("image_versions2")] - public InstaImageCandidatesResponse Images { get; set; } + [JsonProperty("video_versions")] public List Videos { get; set; } - [JsonProperty("original_width")] - public int Width { get; set; } + [JsonProperty("original_width")] public int Width { get; set; } - [JsonProperty("original_height")] - public string Height { get; set; } + [JsonProperty("original_height")] public string Height { get; set; } - [JsonProperty("user")] - public InstaUserResponse User { get; set; } + [JsonProperty("user")] public InstaUserResponse User { get; set; } [JsonProperty("organic_tracking_token")] - public string TrakingToken { get; set; } + public string TrackingToken { get; set; } - [JsonProperty("like_count")] - public int LikesCount { get; set; } + [JsonProperty("like_count")] public int LikesCount { get; set; } - [JsonProperty("next_max_id")] - public string NextMaxId { get; set; } + [JsonProperty("next_max_id")] public string NextMaxId { get; set; } - [JsonProperty("caption")] - public InstaCaptionResponse Caption { get; set; } + [JsonProperty("caption")] public InstaCaptionResponse Caption { get; set; } - [JsonProperty("comment_count")] - public string CommentsCount { get; set; } + [JsonProperty("comment_count")] public string CommentsCount { get; set; } - [JsonProperty("photo_of_you")] - public bool PhotoOfYou { get; set; } + [JsonProperty("photo_of_you")] public bool PhotoOfYou { get; set; } - [JsonProperty("has_liked")] - public bool HasLiked { get; set; } + [JsonProperty("has_liked")] public bool HasLiked { get; set; } - [JsonProperty("type")] - public int Type { get; set; } + [JsonProperty("type")] public int Type { get; set; } - [JsonProperty("view_count")] - public double ViewCount { get; set; } + [JsonProperty("view_count")] public double ViewCount { get; set; } - [JsonProperty("has_audio")] - public bool HasAudio { get; set; } + [JsonProperty("has_audio")] public bool HasAudio { get; set; } - [JsonProperty("usertags")] - public InstaUserTagListResponse UserTagList { get; set; } + [JsonProperty("usertags")] public InstaUserTagListResponse UserTagList { get; set; } - [JsonProperty("likers")] - public List Likers { get; set; } + [JsonProperty("likers")] public List Likers { get; set; } - [JsonProperty("carousel_media")] - public InstaCarouselResponse CarouselMedia { get; set; } + [JsonProperty("carousel_media")] public InstaCarouselResponse CarouselMedia { get; set; } + + [JsonProperty("location")] public InstaLocationResponse Location { get; set; } + + [JsonProperty("preview_comments")] public List PreviewComments { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaMediaLikersResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaMediaLikersResponse.cs index 12062a7b..8312bdc3 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaMediaLikersResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaMediaLikersResponse.cs @@ -3,12 +3,10 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaMediaLikersResponse : BadStatusResponse + public class InstaMediaLikersResponse : BadStatusResponse { - [JsonProperty("users")] - public List Users { get; set; } + [JsonProperty("users")] public List Users { get; set; } - [JsonProperty("user_count")] - public int UsersCount { get; set; } + [JsonProperty("user_count")] public int UsersCount { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaMediaListResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaMediaListResponse.cs index 47d5a147..8d5192d3 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaMediaListResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaMediaListResponse.cs @@ -4,7 +4,7 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaMediaListResponse : BaseLoadableResponse + public class InstaMediaListResponse : BaseLoadableResponse { [JsonProperty("items")] public List Medias { get; set; } = new List(); diff --git a/InstaSharper/Classes/ResponseWrappers/InstaNametag.cs b/InstaSharper/Classes/ResponseWrappers/InstaNametag.cs new file mode 100644 index 00000000..17f4c0bb --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaNametag.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaNametag + { + + [JsonProperty("mode")] + public int Mode { get; set; } + + [JsonProperty("gradient")] + public int Gradient { get; set; } + + [JsonProperty("emoji")] + public string Emoji { get; set; } + + [JsonProperty("selfie_sticker")] + public int SelfieSticker { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaOembedUrlResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaOembedUrlResponse.cs new file mode 100644 index 00000000..4f910963 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaOembedUrlResponse.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaOembedUrlResponse + { + [JsonProperty("media_id")] //media_id is enough. + public string MediaId { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaOwnerResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaOwnerResponse.cs index ace6491b..bbdbf670 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaOwnerResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaOwnerResponse.cs @@ -4,28 +4,20 @@ namespace InstaSharper.Classes.ResponseWrappers { public class InstaOwnerResponse { - [JsonProperty("type")] - public string Type { get; set; } + [JsonProperty("type")] public string Type { get; set; } - [JsonProperty("pk")] - public long Pk { get; set; } + [JsonProperty("pk")] public long Pk { get; set; } - [JsonProperty("name")] - public string Name { get; set; } + [JsonProperty("name")] public string Name { get; set; } - [JsonProperty("profile_pic_url")] - public string ProfilePicUrl { get; set; } + [JsonProperty("profile_pic_url")] public string ProfilePicUrl { get; set; } - [JsonProperty("profile_pic_username")] - public string ProfilePicUsername { get; set; } + [JsonProperty("profile_pic_username")] public string ProfilePicUsername { get; set; } - [JsonProperty("short_name")] - public string ShortName { get; set; } + [JsonProperty("short_name")] public string ShortName { get; set; } - [JsonProperty("lng")] - public double Lng { get; set; } + [JsonProperty("lng")] public double Lng { get; set; } - [JsonProperty("lat")] - public double Lat { get; set; } + [JsonProperty("lat")] public double Lat { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaPermalinkResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaPermalinkResponse.cs new file mode 100644 index 00000000..32ad566c --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaPermalinkResponse.cs @@ -0,0 +1,10 @@ +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaPermalinkResponse : BaseStatusResponse + { + [JsonProperty("permalink")] public string Permalink { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaRankedRecipientsResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaRankedRecipientsResponse.cs index a46d7513..773523b0 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaRankedRecipientsResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaRankedRecipientsResponse.cs @@ -2,9 +2,8 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaRankedRecipientsResponse : InstaRecipientsResponse, IInstaRecipientsResponse + public class InstaRankedRecipientsResponse : InstaRecipientsResponse, IInstaRecipientsResponse { - [JsonProperty("ranked_recipients")] - public RankedRecipientResponse[] RankedRecipients { get; set; } + [JsonProperty("ranked_recipients")] public RankedRecipientResponse[] RankedRecipients { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityFeedResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityFeedResponse.cs index 9d7b357a..d1b29ea3 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityFeedResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityFeedResponse.cs @@ -2,15 +2,12 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaRecentActivityFeedResponse + public class InstaRecentActivityFeedResponse { - [JsonProperty("args")] - public InstaRecentActivityStoryItemResponse Args { get; set; } + [JsonProperty("args")] public InstaRecentActivityStoryItemResponse Args { get; set; } - [JsonProperty("type")] - public int Type { get; set; } + [JsonProperty("story_type")] public int Type { get; set; } - [JsonProperty("pk")] - public string Pk { get; set; } + [JsonProperty("pk")] public string Pk { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityResponse.cs index 18fb5a23..702d2270 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityResponse.cs @@ -4,7 +4,7 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaRecentActivityResponse : BaseLoadableResponse + public class InstaRecentActivityResponse : BaseLoadableResponse { public bool IsOwnActivity { get; set; } = false; diff --git a/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityStoryItemMediaResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityStoryItemMediaResponse.cs new file mode 100644 index 00000000..e3849385 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityStoryItemMediaResponse.cs @@ -0,0 +1,9 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaRecentActivityStoryItemMediaResponse + { + [JsonProperty("id")] public string MediaId { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityStoryItemResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityStoryItemResponse.cs index dabe325d..069ff12b 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityStoryItemResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaRecentActivityStoryItemResponse.cs @@ -3,24 +3,22 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaRecentActivityStoryItemResponse + public class InstaRecentActivityStoryItemResponse { - [JsonProperty("profile_id")] - public long ProfileId { get; set; } + [JsonProperty("profile_id")] public long ProfileId { get; set; } - [JsonProperty("profile_image")] - public string ProfileImage { get; set; } + [JsonProperty("profile_name")] public string ProfileName { get; set; } - [JsonProperty("timestamp")] - public string TimeStamp { get; set; } + [JsonProperty("profile_image")] public string ProfileImage { get; set; } - [JsonProperty("inline_follow")] - public InstaInlineFollowResponse InlineFollow { get; set; } + [JsonProperty("timestamp")] public string TimeStamp { get; set; } - [JsonProperty("text")] - public string Text { get; set; } + [JsonProperty("inline_follow")] public InstaInlineFollowResponse InlineFollow { get; set; } - [JsonProperty("links")] - public List Links { get; set; } + [JsonProperty("text")] public string Text { get; set; } + + [JsonProperty("links")] public List Links { get; set; } + + [JsonProperty("media")] public List Medias { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaRecentRecipientsResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaRecentRecipientsResponse.cs index af129245..86c359aa 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaRecentRecipientsResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaRecentRecipientsResponse.cs @@ -2,9 +2,8 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaRecentRecipientsResponse : InstaRecipientsResponse, IInstaRecipientsResponse + public class InstaRecentRecipientsResponse : InstaRecipientsResponse, IInstaRecipientsResponse { - [JsonProperty("recent_recipients")] - public RankedRecipientResponse[] RankedRecipients { get; set; } + [JsonProperty("recent_recipients")] public RankedRecipientResponse[] RankedRecipients { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaRecipientsResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaRecipientsResponse.cs index 6774a321..2a73a7f4 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaRecipientsResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaRecipientsResponse.cs @@ -3,18 +3,14 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaRecipientsResponse : BaseStatusResponse + public class InstaRecipientsResponse : BaseStatusResponse { - [JsonProperty("expires")] - public long Expires { get; set; } + [JsonProperty("expires")] public long Expires { get; set; } - [JsonProperty("filtered")] - public bool Filtered { get; set; } + [JsonProperty("filtered")] public bool Filtered { get; set; } - [JsonProperty("rank_token")] - public string RankToken { get; set; } + [JsonProperty("rank_token")] public string RankToken { get; set; } - [JsonProperty("request_id")] - public string RequestId { get; set; } + [JsonProperty("request_id")] public string RequestId { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaReelFeedResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaReelFeedResponse.cs new file mode 100644 index 00000000..7b869369 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaReelFeedResponse.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaReelFeedResponse + { + [JsonProperty("has_besties_media")] public long HasBestiesMedia { get; set; } + + [JsonProperty("prefetch_count")] public long PrefetchCount { get; set; } + + [JsonProperty("can_reshare")] public bool CanReshare { get; set; } + + [JsonProperty("can_reply")] public bool CanReply { get; set; } + + [JsonProperty("expiring_at")] public long ExpiringAt { get; set; } + + [JsonProperty("items")] public List Items { get; set; } + + [JsonProperty("id")] public long Id { get; set; } + + [JsonProperty("latest_reel_media")] public long? LatestReelMedia { get; set; } + + [JsonProperty("seen")] public long? Seen { get; set; } + + [JsonProperty("user")] public InstaUserShortResponse User { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaReelMentionResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaReelMentionResponse.cs index 2b54bf45..a311ecff 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaReelMentionResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaReelMentionResponse.cs @@ -2,30 +2,22 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaReelMentionResponse + public class InstaReelMentionResponse { - [JsonProperty("rotation")] - public double Rotation { get; set; } + [JsonProperty("rotation")] public double Rotation { get; set; } - [JsonProperty("height")] - public double Height { get; set; } + [JsonProperty("height")] public double Height { get; set; } - [JsonProperty("hashtag")] - public InstaHashtagResponse Hashtag { get; set; } + [JsonProperty("hashtag")] public InstaHashtagResponse Hashtag { get; set; } - [JsonProperty("is_pinned")] - public int IsPinned { get; set; } + [JsonProperty("is_pinned")] public int IsPinned { get; set; } - [JsonProperty("width")] - public double Width { get; set; } + [JsonProperty("width")] public double Width { get; set; } - [JsonProperty("user")] - public InstaUserShortResponse User { get; set; } + [JsonProperty("user")] public InstaUserShortResponse User { get; set; } - [JsonProperty("x")] - public double X { get; set; } + [JsonProperty("x")] public double X { get; set; } - [JsonProperty("y")] - public double Y { get; set; } + [JsonProperty("y")] public double Y { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaResetChallenge.cs b/InstaSharper/Classes/ResponseWrappers/InstaResetChallenge.cs new file mode 100644 index 00000000..63acf09c --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaResetChallenge.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaResetChallenge + { + [JsonProperty("step_name")] public string StepName { get; set; } + + [JsonProperty("step_data")] public InstaStepData StepData { get; set; } + + [JsonProperty("user_id")] public long UserId { get; set; } + + [JsonProperty("nonce_code")] public string NonceCode { get; set; } + + [JsonProperty("status")] public string Status { get; set; } + + [JsonProperty("logged_in_user")] public InstaUserResponse LoggedInUser { get; set; } + + [JsonProperty("action")] public string Action { get; set; } + + [JsonProperty("auto_login")] public bool AutoLogin { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaSearchUserResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaSearchUserResponse.cs index fd478469..eaee9f7a 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaSearchUserResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaSearchUserResponse.cs @@ -3,15 +3,12 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaSearchUserResponse + public class InstaSearchUserResponse { - [JsonProperty("has_more")] - public bool MoreAvailable { get; set; } + [JsonProperty("has_more")] public bool MoreAvailable { get; set; } - [JsonProperty("num_results")] - public bool ResultCount { get; set; } + [JsonProperty("num_results")] public bool ResultCount { get; set; } - [JsonProperty("users")] - public List Users { get; set; } + [JsonProperty("users")] public List Users { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaSendDirectMessageResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaSendDirectMessageResponse.cs index 7d75fccb..16049e7b 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaSendDirectMessageResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaSendDirectMessageResponse.cs @@ -3,7 +3,7 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaSendDirectMessageResponse : BaseStatusResponse + public class InstaSendDirectMessageResponse : BaseStatusResponse { public List Threads { get; set; } = new List(); } diff --git a/InstaSharper/Classes/ResponseWrappers/InstaStepData.cs b/InstaSharper/Classes/ResponseWrappers/InstaStepData.cs new file mode 100644 index 00000000..79cb8aa4 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaStepData.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaStepData + { + [JsonProperty("choice")] public string Choice { get; set; } + + [JsonProperty("fb_access_token")] public string FbAccessToken { get; set; } + + [JsonProperty("big_blue_token")] public string BigBlueToken { get; set; } + + [JsonProperty("google_oauth_token")] public string GoogleOauthToken { get; set; } + + [JsonProperty("email")] public string Email { get; set; } + + [JsonProperty("phone_number")] public string PhoneNumber { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaStoryFeedResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaStoryFeedResponse.cs index ac394b3c..5cb12c6a 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaStoryFeedResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaStoryFeedResponse.cs @@ -4,21 +4,17 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaStoryFeedResponse : BaseStatusResponse + public class InstaStoryFeedResponse : BaseStatusResponse { [JsonProperty("face_filter_nux_version")] public int FaceFilterNuxVersion { get; set; } - [JsonProperty("has_new_nux_story")] - public bool HasNewNuxStory { get; set; } + [JsonProperty("has_new_nux_story")] public bool HasNewNuxStory { get; set; } - [JsonProperty("story_ranking_token")] - public string StoryRankingToken { get; set; } + [JsonProperty("story_ranking_token")] public string StoryRankingToken { get; set; } - [JsonProperty("sticker_version")] - public int StickerVersion { get; set; } + [JsonProperty("sticker_version")] public int StickerVersion { get; set; } - [JsonProperty("tray")] - public List Tray { get; set; } + [JsonProperty("tray")] public List Tray { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaStoryItemResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaStoryItemResponse.cs index cc2a5ea0..fd2dfb18 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaStoryItemResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaStoryItemResponse.cs @@ -3,141 +3,101 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaStoryItemResponse + public class InstaStoryItemResponse { - [JsonProperty("has_liked")] - public bool HasLiked { get; set; } + [JsonProperty("has_liked")] public bool HasLiked { get; set; } - [JsonProperty("code")] - public string Code { get; set; } + [JsonProperty("code")] public string Code { get; set; } - [JsonProperty("caption")] - public InstaCaptionResponse Caption { get; set; } + [JsonProperty("caption")] public InstaCaptionResponse Caption { get; set; } - [JsonProperty("can_reshare")] - public bool CanReshare { get; set; } + [JsonProperty("can_reshare")] public bool CanReshare { get; set; } - [JsonProperty("ad_action")] - public string AdAction { get; set; } + [JsonProperty("ad_action")] public string AdAction { get; set; } - [JsonProperty("can_viewer_save")] - public bool CanViewerSave { get; set; } + [JsonProperty("can_viewer_save")] public bool CanViewerSave { get; set; } - [JsonProperty("caption_position")] - public long CaptionPosition { get; set; } + [JsonProperty("caption_position")] public long CaptionPosition { get; set; } - [JsonProperty("caption_is_edited")] - public bool CaptionIsEdited { get; set; } + [JsonProperty("caption_is_edited")] public bool CaptionIsEdited { get; set; } - [JsonProperty("client_cache_key")] - public string ClientCacheKey { get; set; } + [JsonProperty("client_cache_key")] public string ClientCacheKey { get; set; } - [JsonProperty("device_timestamp")] - public long DeviceTimestamp { get; set; } + [JsonProperty("device_timestamp")] public long DeviceTimestamp { get; set; } [JsonProperty("comment_likes_enabled")] public bool CommentLikesEnabled { get; set; } - [JsonProperty("comment_count")] - public long CommentCount { get; set; } + [JsonProperty("comment_count")] public long CommentCount { get; set; } [JsonProperty("comment_threading_enabled")] public bool CommentThreadingEnabled { get; set; } - [JsonProperty("filter_type")] - public long FilterType { get; set; } + [JsonProperty("filter_type")] public long FilterType { get; set; } - [JsonProperty("expiring_at")] - public long ExpiringAt { get; set; } + [JsonProperty("expiring_at")] public long ExpiringAt { get; set; } - [JsonProperty("has_audio")] - public bool? HasAudio { get; set; } + [JsonProperty("has_audio")] public bool? HasAudio { get; set; } - [JsonProperty("link_text")] - public string LinkText { get; set; } + [JsonProperty("link_text")] public string LinkText { get; set; } - [JsonProperty("pk")] - public long Pk { get; set; } + [JsonProperty("pk")] public long Pk { get; set; } - [JsonProperty("is_dash_eligible")] - public long? IsDashEligible { get; set; } + [JsonProperty("is_dash_eligible")] public long? IsDashEligible { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] public string Id { get; set; } - [JsonProperty("has_more_comments")] - public bool HasMoreComments { get; set; } + [JsonProperty("has_more_comments")] public bool HasMoreComments { get; set; } - [JsonProperty("image_versions2")] - public InstaImageCandidatesResponse Images { get; set; } + [JsonProperty("image_versions2")] public InstaImageCandidatesResponse Images { get; set; } - [JsonProperty("like_count")] - public long LikeCount { get; set; } + [JsonProperty("like_count")] public long LikeCount { get; set; } - [JsonProperty("is_reel_media")] - public bool IsReelMedia { get; set; } + [JsonProperty("is_reel_media")] public bool IsReelMedia { get; set; } - [JsonProperty("likers")] - public List Likers { get; set; } + [JsonProperty("likers")] public List Likers { get; set; } [JsonProperty("organic_tracking_token")] public string OrganicTrackingToken { get; set; } - [JsonProperty("media_type")] - public long MediaType { get; set; } + [JsonProperty("media_type")] public long MediaType { get; set; } [JsonProperty("max_num_visible_preview_comments")] public long MaxNumVisiblePreviewComments { get; set; } - [JsonProperty("number_of_qualities")] - public long? NumberOfQualities { get; set; } + [JsonProperty("number_of_qualities")] public long? NumberOfQualities { get; set; } - [JsonProperty("original_width")] - public long OriginalWidth { get; set; } + [JsonProperty("original_width")] public long OriginalWidth { get; set; } - [JsonProperty("original_height")] - public long OriginalHeight { get; set; } + [JsonProperty("original_height")] public long OriginalHeight { get; set; } - [JsonProperty("photo_of_you")] - public bool PhotoOfYou { get; set; } + [JsonProperty("photo_of_you")] public bool PhotoOfYou { get; set; } - [JsonProperty("story_events")] - public List StoryEvents { get; set; } + [JsonProperty("story_events")] public List StoryEvents { get; set; } - [JsonProperty("story_polls")] - public List StoryPolls { get; set; } + [JsonProperty("story_polls")] public List StoryPolls { get; set; } - [JsonProperty("reel_mentions")] - public List ReelMentions { get; set; } + [JsonProperty("reel_mentions")] public List ReelMentions { get; set; } - [JsonProperty("preview_comments")] - public List PreviewComments { get; set; } + [JsonProperty("preview_comments")] public List PreviewComments { get; set; } - [JsonProperty("story_hashtags")] - public List StoryHashtags { get; set; } + [JsonProperty("story_hashtags")] public List StoryHashtags { get; set; } - [JsonProperty("story_feed_media")] - public List StoryFeedMedia { get; set; } + [JsonProperty("story_feed_media")] public List StoryFeedMedia { get; set; } - [JsonProperty("story_locations")] - public List StoryLocations { get; set; } + [JsonProperty("story_locations")] public List StoryLocations { get; set; } - [JsonProperty("taken_at")] - public long TakenAt { get; set; } + [JsonProperty("taken_at")] public long TakenAt { get; set; } - [JsonProperty("video_dash_manifest")] - public string VideoDashManifest { get; set; } + [JsonProperty("video_dash_manifest")] public string VideoDashManifest { get; set; } [JsonProperty("supports_reel_reactions")] public bool SupportsReelReactions { get; set; } - [JsonProperty("user")] - public InstaUserShortResponse User { get; set; } + [JsonProperty("user")] public InstaUserShortResponse User { get; set; } - [JsonProperty("video_duration")] - public double? VideoDuration { get; set; } + [JsonProperty("video_duration")] public double? VideoDuration { get; set; } - [JsonProperty("video_versions")] - public List VideoVersions { get; set; } + [JsonProperty("video_versions")] public List VideoVersions { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaStoryLocationResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaStoryLocationResponse.cs index 3b46795b..e6141c42 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaStoryLocationResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaStoryLocationResponse.cs @@ -2,27 +2,20 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaStoryLocationResponse + public class InstaStoryLocationResponse { - [JsonProperty("rotation")] - public long Rotation { get; set; } + [JsonProperty("rotation")] public long Rotation { get; set; } - [JsonProperty("is_pinned")] - public long IsPinned { get; set; } + [JsonProperty("is_pinned")] public long IsPinned { get; set; } - [JsonProperty("height")] - public double Height { get; set; } + [JsonProperty("height")] public double Height { get; set; } - [JsonProperty("location")] - public InstaLocationResponse Location { get; set; } + [JsonProperty("location")] public InstaLocationResponse Location { get; set; } - [JsonProperty("x")] - public double X { get; set; } + [JsonProperty("x")] public double X { get; set; } - [JsonProperty("width")] - public double Width { get; set; } + [JsonProperty("width")] public double Width { get; set; } - [JsonProperty("y")] - public double Y { get; set; } + [JsonProperty("y")] public double Y { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaStoryMediaResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaStoryMediaResponse.cs index 34241572..75007afe 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaStoryMediaResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaStoryMediaResponse.cs @@ -2,9 +2,8 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaStoryMediaResponse + public class InstaStoryMediaResponse { - [JsonProperty("media")] - public InstaStoryItemResponse Media { get; set; } + [JsonProperty("media")] public InstaStoryItemResponse Media { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaStoryResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaStoryResponse.cs index e530b9be..db51db1c 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaStoryResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaStoryResponse.cs @@ -3,48 +3,34 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaStoryResponse + public class InstaStoryResponse { - [JsonProperty("can_reply")] - public bool CanReply { get; set; } + [JsonProperty("can_reply")] public bool CanReply { get; set; } - [JsonProperty("expiring_at")] - public long ExpiringAt { get; set; } + [JsonProperty("expiring_at")] public long ExpiringAt { get; set; } - [JsonProperty("user")] - public InstaUserShortResponse User { get; set; } + [JsonProperty("user")] public InstaUserShortResponse User { get; set; } - [JsonProperty("owner")] - public InstaOwnerResponse Owner { get; set; } + [JsonProperty("owner")] public InstaUserShortResponse Owner { get; set; } - [JsonProperty("source_token")] - public string SourceToken { get; set; } + [JsonProperty("source_token")] public string SourceToken { get; set; } - [JsonProperty("seen")] - public double? Seen { get; set; } + [JsonProperty("seen")] public long? Seen { get; set; } - [JsonProperty("latest_reel_media")] - public string LatestReelMedia { get; set; } + [JsonProperty("latest_reel_media")] public string LatestReelMedia { get; set; } - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] public string Id { get; set; } - [JsonProperty("ranked_position")] - public int RankedPosition { get; set; } + [JsonProperty("ranked_position")] public int RankedPosition { get; set; } - [JsonProperty("muted")] - public bool Muted { get; set; } + [JsonProperty("muted")] public bool Muted { get; set; } - [JsonProperty("seen_ranked_position")] - public int SeenRankedPosition { get; set; } + [JsonProperty("seen_ranked_position")] public int SeenRankedPosition { get; set; } - [JsonProperty("items")] - public List Items { get; set; } + [JsonProperty("items")] public List Items { get; set; } - [JsonProperty("prefetch_count")] - public int PrefetchCount { get; set; } + [JsonProperty("prefetch_count")] public int PrefetchCount { get; set; } - [JsonProperty("social_context")] - public string SocialContext { get; set; } + [JsonProperty("social_context")] public string SocialContext { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaStoryTrayResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaStoryTrayResponse.cs index b587a1ba..b6a13187 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaStoryTrayResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaStoryTrayResponse.cs @@ -3,18 +3,14 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaStoryTrayResponse + public class InstaStoryTrayResponse { - [JsonProperty("id")] - public long Id { get; set; } + [JsonProperty("id")] public long Id { get; set; } - [JsonProperty("top_live")] - public InstaTopLiveResponse TopLive { get; set; } = new InstaTopLiveResponse(); + [JsonProperty("top_live")] public InstaTopLiveResponse TopLive { get; set; } = new InstaTopLiveResponse(); - [JsonProperty("is_portrait")] - public bool IsPortrait { get; set; } + [JsonProperty("is_portrait")] public bool IsPortrait { get; set; } - [JsonProperty("tray")] - public List Tray { get; set; } + [JsonProperty("tray")] public List Tray { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaTagFeedResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaTagFeedResponse.cs index 69b0a65b..a861532d 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaTagFeedResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaTagFeedResponse.cs @@ -3,7 +3,7 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaTagFeedResponse : InstaMediaListResponse + public class InstaTagFeedResponse : InstaMediaListResponse { [JsonProperty("ranked_items")] public List RankedItems { get; set; } = new List(); diff --git a/InstaSharper/Classes/ResponseWrappers/InstaTopLiveResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaTopLiveResponse.cs index d76963bb..4ae512c0 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaTopLiveResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaTopLiveResponse.cs @@ -3,10 +3,9 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaTopLiveResponse + public class InstaTopLiveResponse { - [JsonProperty("ranked_position")] - public int RankedPosition { get; set; } + [JsonProperty("ranked_position")] public int RankedPosition { get; set; } [JsonProperty("broadcast_owners")] public List BroadcastOwners { get; set; } = new List(); diff --git a/InstaSharper/Classes/ResponseWrappers/InstaUserInfoContainerResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaUserInfoContainerResponse.cs new file mode 100644 index 00000000..389de09f --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaUserInfoContainerResponse.cs @@ -0,0 +1,10 @@ +using InstaSharper.Classes.ResponseWrappers.BaseResponse; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaUserInfoContainerResponse : BaseStatusResponse + { + [JsonProperty("user")] public InstaUserInfoResponse User { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaUserInfoResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaUserInfoResponse.cs new file mode 100644 index 00000000..160732b4 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaUserInfoResponse.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaUserInfoResponse + { + [JsonProperty("pk")] public long Pk { get; set; } + + [JsonProperty("username")] public string Username { get; set; } + + [JsonProperty("full_name")] public string FullName { get; set; } + + [JsonProperty("is_private")] public bool IsPrivate { get; set; } + + [JsonProperty("profile_pic_url")] public string ProfilePicUrl { get; set; } + + [JsonProperty("is_verified")] public bool IsVerified { get; set; } + + [JsonProperty("has_anonymous_profile_picture")] + public bool HasAnonymousProfilePicture { get; set; } + + [JsonProperty("media_count")] public long MediaCount { get; set; } + + [JsonProperty("geo_media_count")] public long GeoMediaCount { get; set; } + + [JsonProperty("follower_count")] public long FollowerCount { get; set; } + + [JsonProperty("following_count")] public long FollowingCount { get; set; } + + [JsonProperty("biography")] public string Biography { get; set; } + + [JsonProperty("external_url")] public string ExternalUrl { get; set; } + + [JsonProperty("external_lynx_url")] public string ExternalLynxUrl { get; set; } + + [JsonProperty("reel_auto_archive")] public string ReelAutoArchive { get; set; } + + [JsonProperty("usertags_count")] public long UsertagsCount { get; set; } + + [JsonProperty("is_favorite")] public bool IsFavorite { get; set; } + + [JsonProperty("has_chaining")] public bool HasChaining { get; set; } + + [JsonProperty("profile_context")] public string ProfileContext { get; set; } + + [JsonProperty("profile_context_mutual_follow_ids")] + public List ProfileContextMutualFollowIds { get; set; } + + [JsonProperty("is_business")] public bool IsBusiness { get; set; } + + [JsonProperty("include_direct_blacklist_status")] + public bool IncludeDirectBlacklistStatus { get; set; } + + [JsonProperty("has_unseen_besties_media")] + public bool HasUnseenBestiesMedia { get; set; } + + [JsonProperty("auto_expand_chaining")] public bool AutoExpandChaining { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaUserListResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaUserListResponse.cs index 5d096455..f6fe515f 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaUserListResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaUserListResponse.cs @@ -4,18 +4,14 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaUserListResponse : BaseStatusResponse + public class InstaUserListResponse : BaseStatusResponse { - [JsonProperty("users")] - public List Items { get; set; } + [JsonProperty("users")] public List Items { get; set; } - [JsonProperty("big_list")] - public bool IsBigList { get; set; } + [JsonProperty("big_list")] public bool IsBigList { get; set; } - [JsonProperty("page_size")] - public int PageSize { get; set; } + [JsonProperty("page_size")] public int PageSize { get; set; } - [JsonProperty("next_max_id")] - public string NextMaxId { get; set; } + [JsonProperty("next_max_id")] public string NextMaxId { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaUserListShortResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaUserListShortResponse.cs index 8a149baa..32a9bc01 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaUserListShortResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaUserListShortResponse.cs @@ -4,18 +4,14 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaUserListShortResponse : BaseStatusResponse + public class InstaUserListShortResponse : BaseStatusResponse { - [JsonProperty("users")] - public List Items { get; set; } + [JsonProperty("users")] public List Items { get; set; } - [JsonProperty("big_list")] - public bool IsBigList { get; set; } + [JsonProperty("big_list")] public bool IsBigList { get; set; } - [JsonProperty("page_size")] - public int PageSize { get; set; } + [JsonProperty("page_size")] public int PageSize { get; set; } - [JsonProperty("next_max_id")] - public string NextMaxId { get; set; } + [JsonProperty("next_max_id")] public string NextMaxId { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaUserResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaUserResponse.cs index 05a7abe8..3293662b 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaUserResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaUserResponse.cs @@ -2,30 +2,46 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaUserResponse : InstaUserShortResponse + public class InstaUserResponse : InstaUserShortResponse { - [JsonProperty("friendship_status")] - public InstaFriendshipStatusResponse FriendshipStatus { get; set; } + [JsonProperty("friendship_status")] public InstaFriendshipStatusResponse FriendshipStatus { get; set; } - [JsonProperty("has_anonymous_profile_picture")] - public bool HasAnonymousProfilePicture { get; set; } + [JsonProperty("has_anonymous_profile_picture")] public bool HasAnonymousProfilePicture { get; set; } - [JsonProperty("follower_count")] - public int FollowersCount { get; set; } + [JsonProperty("follower_count")] public int FollowersCount { get; set; } - [JsonProperty("byline")] - public string FollowersCountByLine { get; set; } + [JsonProperty("byline")] public string FollowersCountByLine { get; set; } - [JsonProperty("social_context")] - public string SocialContext { get; set; } + [JsonProperty("social_context")] public string SocialContext { get; set; } - [JsonProperty("search_social_context")] - public string SearchSocialContext { get; set; } + [JsonProperty("search_social_context")] public string SearchSocialContext { get; set; } - [JsonProperty("mutual_followers_count")] - public string MulualFollowersCount { get; set; } + [JsonProperty("mutual_followers_count")] public string MulualFollowersCount { get; set; } - [JsonProperty("unseen_count")] - public int UnseenCount { get; set; } + [JsonProperty("unseen_count")] public int UnseenCount { get; set; } + + [JsonProperty("can_boost_post")] public bool CanBoostPost { get; set; } + + [JsonProperty("show_insights_terms")] public bool ShowInsightsTerms { get; set; } + + [JsonProperty("is_business")] public bool IsBusiness { get; set; } + + [JsonProperty("nametag")] public InstaNametag Nametag { get; set; } + + [JsonProperty("has_placed_orders")] public bool HasPlacedOrders { get; set; } + + [JsonProperty("can_see_organic_insights")] public bool CanSeeOrganicInsights { get; set; } + + [JsonProperty("allowed_commenter_type")] public string AllowedCommEnterType { get; set; } + + [JsonProperty("reel_auto_archive")] public string ReelAutoArchive { get; set; } + + [JsonProperty("allow_contacts_sync")] public bool AllowContactsSync { get; set; } + + [JsonProperty("phone_number")] public string PhoneNumber { get; set; } + + [JsonProperty("country_code")] public int CountryCode { get; set; } + + [JsonProperty("national_number")] public long NationalNumber { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaUserShortResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaUserShortResponse.cs index ba330c27..6cef6eff 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaUserShortResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaUserShortResponse.cs @@ -3,27 +3,20 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaUserShortResponse : BaseStatusResponse + public class InstaUserShortResponse : BaseStatusResponse { - [JsonProperty("username")] - public string UserName { get; set; } + [JsonProperty("username")] public string UserName { get; set; } - [JsonProperty("profile_pic_url")] - public string ProfilePicture { get; set; } + [JsonProperty("profile_pic_url")] public string ProfilePicture { get; set; } - [JsonProperty("profile_pic_id")] - public string ProfilePictureId { get; set; } = "unknown"; + [JsonProperty("profile_pic_id")] public string ProfilePictureId { get; set; } = "unknown"; - [JsonProperty("full_name")] - public string FullName { get; set; } + [JsonProperty("full_name")] public string FullName { get; set; } - [JsonProperty("is_verified")] - public bool IsVerified { get; set; } + [JsonProperty("is_verified")] public bool IsVerified { get; set; } - [JsonProperty("is_private")] - public bool IsPrivate { get; set; } + [JsonProperty("is_private")] public bool IsPrivate { get; set; } - [JsonProperty("pk")] - public string Pk { get; set; } + [JsonProperty("pk")] public long Pk { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaUserTagListResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaUserTagListResponse.cs index a5c0ffc1..c10d0ff5 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaUserTagListResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaUserTagListResponse.cs @@ -3,9 +3,8 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaUserTagListResponse + public class InstaUserTagListResponse { - [JsonProperty("in")] - public List In { get; set; } = new List(); + [JsonProperty("in")] public List In { get; set; } = new List(); } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaUserTagResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaUserTagResponse.cs index 89006efe..9ffc74fe 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaUserTagResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaUserTagResponse.cs @@ -2,15 +2,12 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaUserTagResponse + public class InstaUserTagResponse { - [JsonProperty("position")] - public double[] Position { get; set; } + [JsonProperty("position")] public double[] Position { get; set; } - [JsonProperty("time_in_video")] - public string TimeInVideo { get; set; } + [JsonProperty("time_in_video")] public string TimeInVideo { get; set; } - [JsonProperty("user")] - public InstaUserShortResponse User { get; set; } + [JsonProperty("user")] public InstaUserShortResponse User { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaVideoResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaVideoResponse.cs index 483eeb0b..cd16a8a4 100644 --- a/InstaSharper/Classes/ResponseWrappers/InstaVideoResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/InstaVideoResponse.cs @@ -2,21 +2,16 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class InstaVideoResponse + public class InstaVideoResponse { - [JsonProperty("id")] - public string Id { get; set; } + [JsonProperty("id")] public string Id { get; set; } - [JsonProperty("url")] - public string Url { get; set; } + [JsonProperty("url")] public string Url { get; set; } - [JsonProperty("height")] - public string Height { get; set; } + [JsonProperty("height")] public string Height { get; set; } - [JsonProperty("type")] - public int Type { get; set; } + [JsonProperty("type")] public int Type { get; set; } - [JsonProperty("width")] - public string Width { get; set; } + [JsonProperty("width")] public string Width { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaWebLinkContextResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaWebLinkContextResponse.cs new file mode 100644 index 00000000..f37792e7 --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaWebLinkContextResponse.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaWebLinkContextResponse + { + [JsonProperty("link_url")] public string LinkUrl { get; set; } + + [JsonProperty("link_title")] public string LinkTitle { get; set; } + + [JsonProperty("link_summary")] public string LinkSummary { get; set; } + + [JsonProperty("link_image_url")] public string LinkImageUrl { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InstaWebLinkResponse.cs b/InstaSharper/Classes/ResponseWrappers/InstaWebLinkResponse.cs new file mode 100644 index 00000000..0506019f --- /dev/null +++ b/InstaSharper/Classes/ResponseWrappers/InstaWebLinkResponse.cs @@ -0,0 +1,11 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes.ResponseWrappers +{ + public class InstaWebLinkResponse + { + [JsonProperty("text")] public string Text { get; set; } + + [JsonProperty("link_context")] public InstaWebLinkContextResponse LinkContext { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/InsteReelFeedResponse.cs b/InstaSharper/Classes/ResponseWrappers/InsteReelFeedResponse.cs deleted file mode 100644 index 026de411..00000000 --- a/InstaSharper/Classes/ResponseWrappers/InsteReelFeedResponse.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace InstaSharper.Classes.ResponseWrappers -{ - internal class InsteReelFeedResponse - { - [JsonProperty("has_besties_media")] - public long HasBestiesMedia { get; set; } - - [JsonProperty("prefetch_count")] - public long PrefetchCount { get; set; } - - [JsonProperty("can_reshare")] - public bool CanReshare { get; set; } - - [JsonProperty("can_reply")] - public bool CanReply { get; set; } - - [JsonProperty("expiring_at")] - public long ExpiringAt { get; set; } - - [JsonProperty("items")] - public List Items { get; set; } - - [JsonProperty("id")] - public long Id { get; set; } - - [JsonProperty("latest_reel_media")] - public long? LatestReelMedia { get; set; } - - [JsonProperty("seen")] - public long? Seen { get; set; } - - [JsonProperty("user")] - public InstaUserShortResponse User { get; set; } - } -} \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/MessageErrorsResponse.cs b/InstaSharper/Classes/ResponseWrappers/MessageErrorsResponse.cs index 3f9ebada..061f33fd 100644 --- a/InstaSharper/Classes/ResponseWrappers/MessageErrorsResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/MessageErrorsResponse.cs @@ -5,7 +5,6 @@ namespace InstaSharper.Classes.ResponseWrappers { public class MessageErrorsResponse { - [JsonProperty("errors")] - public List Errors { get; set; } + [JsonProperty("errors")] public List Errors { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/RankedRecipientResponse.cs b/InstaSharper/Classes/ResponseWrappers/RankedRecipientResponse.cs index e0231ac2..b4998f92 100644 --- a/InstaSharper/Classes/ResponseWrappers/RankedRecipientResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/RankedRecipientResponse.cs @@ -2,9 +2,10 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class RankedRecipientResponse + public class RankedRecipientResponse { - [JsonProperty("thread")] - public RankedRecipientThreadResponse Thread { get; set; } + [JsonProperty("thread")] public RankedRecipientThreadResponse Thread { get; set; } + + [JsonProperty("user")] public InstaUserShortResponse User { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/ResponseWrappers/RankedRecipientThreadResponse.cs b/InstaSharper/Classes/ResponseWrappers/RankedRecipientThreadResponse.cs index e08b16fa..3f43632b 100644 --- a/InstaSharper/Classes/ResponseWrappers/RankedRecipientThreadResponse.cs +++ b/InstaSharper/Classes/ResponseWrappers/RankedRecipientThreadResponse.cs @@ -2,30 +2,22 @@ namespace InstaSharper.Classes.ResponseWrappers { - internal class RankedRecipientThreadResponse + public class RankedRecipientThreadResponse { - [JsonProperty("canonical")] - public bool Canonical { get; set; } + [JsonProperty("canonical")] public bool Canonical { get; set; } - [JsonProperty("named")] - public bool Named { get; set; } + [JsonProperty("named")] public bool Named { get; set; } - [JsonProperty("pending")] - public bool Pending { get; set; } + [JsonProperty("pending")] public bool Pending { get; set; } - [JsonProperty("thread_id")] - public string ThreadId { get; set; } + [JsonProperty("thread_id")] public string ThreadId { get; set; } - [JsonProperty("thread_title")] - public string ThreadTitle { get; set; } + [JsonProperty("thread_title")] public string ThreadTitle { get; set; } - [JsonProperty("thread_type")] - public string ThreadType { get; set; } + [JsonProperty("thread_type")] public string ThreadType { get; set; } - [JsonProperty("users")] - public InstaUserShortResponse[] Users { get; set; } + [JsonProperty("users")] public InstaUserShortResponse[] Users { get; set; } - [JsonProperty("viewer_id")] - public long ViewerId { get; set; } + [JsonProperty("viewer_id")] public long ViewerId { get; set; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/Result.cs b/InstaSharper/Classes/Result.cs index 4a3dbea1..a9aa7167 100644 --- a/InstaSharper/Classes/Result.cs +++ b/InstaSharper/Classes/Result.cs @@ -57,6 +57,11 @@ public static IResult Fail(string errMsg, T resValue) return new Result(false, resValue, new ResultInfo(errMsg)); } + public static IResult Fail(Exception exception, T resValue) + { + return new Result(false, resValue, new ResultInfo(exception)); + } + public static IResult Fail(ResultInfo info, T resValue) { return new Result(false, resValue, info); @@ -64,15 +69,14 @@ public static IResult Fail(ResultInfo info, T resValue) public static IResult Fail(string errMsg, ResponseType responseType, T resValue) { - return new Result(false, resValue, new ResultInfo(responseType, errMsg)); + return new Result(false, resValue, new ResultInfo(responseType, errMsg, String.Empty)); } public static IResult UnExpectedResponse(HttpResponseMessage response, string json) { if (string.IsNullOrEmpty(json)) { - var resultInfo = new ResultInfo(ResponseType.UnExpectedResponse, - $"Unexpected response status: {response.StatusCode}"); + var resultInfo = new ResultInfo(ResponseType.UnExpectedResponse, $"Unexpected response status: {response.StatusCode}", String.Empty); return new Result(false, default(T), resultInfo); } else @@ -93,8 +97,52 @@ public static IResult UnExpectedResponse(HttpResponseMessage response, str case "sentry_block": responseType = ResponseType.SentryBlock; break; + case "checkpoint_challenge_required": + responseType = ResponseType.CheckPointChallengeRequired; + break; + case "unknown": + responseType = ResponseType.Unknown; + break; } - var resultInfo = new ResultInfo(responseType, status.Message); + + if (status.Spam) responseType = ResponseType.Spam; + switch (status.FeedbackTitle) + { + // feedback_message: This action was blocked. Please try again later. + // We restrict certain content and actions to protect our community. + // Tell us if you think we made a mistake. + case "Action Blocked": + responseType = ResponseType.ActionBlocked; + break; + // feedback_message: It looks like you were misusing this feature by going too fast. + // You’ve been temporarily blocked from using it. We restrict certain content and actions + // to protect our community. Tell us if you think we made a mistake. + case "You’re Temporarily Blocked": + responseType = ResponseType.TemporarilyBlocked; + break; + } + + switch (status.FeedbackMessage) + { + case "The post you were viewing has been deleted.": + responseType = ResponseType.DeletedPost; + break; + } + + switch (status.Message) + { + case "Sorry, you cannot like this media": + responseType = ResponseType.CantLikeMedia; + break; + case "Please check the code we sent you and try again.": + responseType = ResponseType.InvalidChallengeCode; + break; + } + + if (!status.IsOk() && status.Message.Contains("wait a few minutes")) + responseType = ResponseType.RequestsLimit; + + var resultInfo = new ResultInfo(responseType, status.Message, json); return new Result(false, default(T), resultInfo); } } diff --git a/InstaSharper/Classes/ResultInfo.cs b/InstaSharper/Classes/ResultInfo.cs index 824afb52..ca09cb08 100644 --- a/InstaSharper/Classes/ResultInfo.cs +++ b/InstaSharper/Classes/ResultInfo.cs @@ -12,10 +12,20 @@ public ResultInfo(string message) public ResultInfo(Exception exception) { Exception = exception; + Message = exception?.Message; + ResponseType = ResponseType.InternalException; } public ResultInfo(ResponseType responseType, string errorMessage) { + ResponseRaw = string.Empty; + ResponseType = responseType; + Message = errorMessage; + } + + public ResultInfo(ResponseType responseType, string errorMessage, string responseRaw) + { + ResponseRaw = responseRaw; ResponseType = responseType; Message = errorMessage; } @@ -25,12 +35,12 @@ public ResultInfo(ResponseType responseType, string errorMessage) public string Message { get; } public ResponseType ResponseType { get; } + + public string ResponseRaw { get; } public override string ToString() { - var message = $"{ResponseType.ToString()}: {Message}."; - if (Exception != null) message += $"Exception: {Exception.Message}"; - return message; + return $"{ResponseType.ToString()}: {Message}."; } } } \ No newline at end of file diff --git a/InstaSharper/Classes/TwoFactorLoginInfo.cs b/InstaSharper/Classes/TwoFactorLoginInfo.cs new file mode 100644 index 00000000..b2fcc10c --- /dev/null +++ b/InstaSharper/Classes/TwoFactorLoginInfo.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; + +namespace InstaSharper.Classes +{ + public class TwoFactorLoginInfo + { + [JsonProperty("obfuscated_phone_number")] + public short ObfuscatedPhoneNumber { get; set; } + + [JsonProperty("show_messenger_code_option")] + public bool ShowMessengerCodeOption { get; set; } + + [JsonProperty("two_factor_identifier")] + public string TwoFactorIdentifier { get; set; } + + [JsonProperty("username")] public string Username { get; set; } + + [JsonProperty("phone_verification_settings")] + public PhoneVerificationSettings PhoneVerificationSettings { get; set; } + + public static TwoFactorLoginInfo Empty => new TwoFactorLoginInfo(); + } +} \ No newline at end of file diff --git a/InstaSharper/Classes/UserSessionData.cs b/InstaSharper/Classes/UserSessionData.cs index 5b11f2b8..6da3c4da 100644 --- a/InstaSharper/Classes/UserSessionData.cs +++ b/InstaSharper/Classes/UserSessionData.cs @@ -9,9 +9,22 @@ public class UserSessionData public string UserName { get; set; } public string Password { get; set; } - public InstaUserShort LoggedInUder { get; set; } + public InstaUserShort LoggedInUser { get; set; } public string RankToken { get; set; } public string CsrfToken { get; set; } + + public static UserSessionData Empty => new UserSessionData(); + + public static UserSessionData ForUsername(string username) + { + return new UserSessionData {UserName = username}; + } + + public UserSessionData WithPassword(string password) + { + Password = password; + return this; + } } } \ No newline at end of file diff --git a/InstaSharper/Classes/VideoUploadJobResponse.cs b/InstaSharper/Classes/VideoUploadJobResponse.cs new file mode 100644 index 00000000..3c9a1475 --- /dev/null +++ b/InstaSharper/Classes/VideoUploadJobResponse.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace InstaSharper.Classes +{ + public class VideoUploadJobResponse + { + [JsonProperty("video_upload_urls")] public List VideoUploadUrls { get; set; } + + [JsonProperty("upload_id")] public string UploadId { get; set; } + + [JsonProperty("xsharing_nonces")] public object XSharingNonces { get; set; } + + [JsonProperty("status")] public string Status { get; set; } + } + + public class VideoUploadUrl + { + [JsonProperty("url")] public string Url { get; set; } + + [JsonProperty("job")] public string Job { get; set; } + + [JsonProperty("expires")] public double Expires { get; set; } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/ConvertersFabric.cs b/InstaSharper/Converters/ConvertersFabric.cs index bf570967..45e1f35b 100644 --- a/InstaSharper/Converters/ConvertersFabric.cs +++ b/InstaSharper/Converters/ConvertersFabric.cs @@ -1,208 +1,274 @@ -using InstaSharper.Classes.Models; +using System; +using InstaSharper.Classes.Models; using InstaSharper.Classes.ResponseWrappers; namespace InstaSharper.Converters { - internal class ConvertersFabric + internal class ConvertersFabric : IConvertersFabric { - internal static IObjectConverter GetUserShortConverter( + private static readonly Lazy LazyInstance = + new Lazy(() => new ConvertersFabric()); + + public static ConvertersFabric Instance => LazyInstance.Value; + + public IObjectConverter GetUserShortConverter( InstaUserShortResponse instaresponse) { return new InstaUserShortConverter {SourceObject = instaresponse}; } - internal static IObjectConverter GetCurrentUserConverter( + public IObjectConverter GetCurrentUserConverter( InstaCurrentUserResponse instaresponse) { return new InstaCurrentUserConverter {SourceObject = instaresponse}; } - internal static IObjectConverter GetUserConverter(InstaUserResponse instaresponse) + public IObjectConverter GetUserConverter(InstaUserResponse instaresponse) { return new InstaUserConverter {SourceObject = instaresponse}; } - public static IObjectConverter GetSingleMediaConverter( + public IObjectConverter GetSingleMediaConverter( InstaMediaItemResponse responseMedia) { return new InstaMediaConverter {SourceObject = responseMedia}; } - internal static IObjectConverter GetFeedConverter( + public IObjectConverter GetFeedConverter( InstaFeedResponse feedResponse) { return new InstaFeedConverter {SourceObject = feedResponse}; } - internal static IObjectConverter GetTagFeedConverter( + public IObjectConverter GetTagFeedConverter( InstaTagFeedResponse feedResponse) { return new InstaTagFeedConverter {SourceObject = feedResponse}; } - public static IObjectConverter GetMediaListConverter( + public IObjectConverter GetMediaListConverter( InstaMediaListResponse mediaResponse) { return new InstaMediaListConverter {SourceObject = mediaResponse}; } - public static IObjectConverter GetCaptionConverter( + public IObjectConverter GetCaptionConverter( InstaCaptionResponse captionResponse) { return new InstaCaptionConverter {SourceObject = captionResponse}; } - public static IObjectConverter + public IObjectConverter GetFriendShipStatusConverter(InstaFriendshipStatusResponse friendshipStatusResponse) { return new InstaFriendshipStatusConverter {SourceObject = friendshipStatusResponse}; } - public static IObjectConverter GetSingleStoryConverter( + public IObjectConverter GetSingleStoryConverter( InstaStoryResponse storyResponse) { return new InstaStoryConverter {SourceObject = storyResponse}; } - public static IObjectConverter GetUserTagConverter(InstaUserTagResponse tag) + public IObjectConverter GetUserTagConverter(InstaUserTagResponse tag) { return new InstaUserTagConverter {SourceObject = tag}; } - public static IObjectConverter + public IObjectConverter GetDirectInboxConverter(InstaDirectInboxContainerResponse inbox) { return new InstaDirectInboxConverter {SourceObject = inbox}; } - public static IObjectConverter GetDirectThreadConverter( + public IObjectConverter GetDirectThreadConverter( InstaDirectInboxThreadResponse thread) { return new InstaDirectThreadConverter {SourceObject = thread}; } - public static IObjectConverter GetDirectThreadItemConverter( + public IObjectConverter GetDirectThreadItemConverter( InstaDirectInboxItemResponse threadItem) { return new InstaDirectThreadItemConverter {SourceObject = threadItem}; } - public static IObjectConverter + public IObjectConverter GetDirectSubscriptionConverter(InstaDirectInboxSubscriptionResponse subscription) { return new InstaDirectInboxSubscriptionConverter {SourceObject = subscription}; } - public static IObjectConverter + public IObjectConverter GetSingleRecentActivityConverter(InstaRecentActivityFeedResponse feedResponse) { return new InstaRecentActivityConverter {SourceObject = feedResponse}; } - public static IObjectConverter GetRecipientsConverter( + public IObjectConverter GetRecipientsConverter( IInstaRecipientsResponse recipients) { return new InstaRecipientsConverter {SourceObject = recipients}; } - public static IObjectConverter GetCommentConverter( + public IObjectConverter GetCommentConverter( InstaCommentResponse comment) { return new InstaCommentConverter {SourceObject = comment}; } - public static IObjectConverter GetCommentListConverter( + public IObjectConverter GetCommentListConverter( InstaCommentListResponse commentList) { return new InstaCommentListConverter {SourceObject = commentList}; } - public static IObjectConverter GetCarouselConverter( + public IObjectConverter GetCarouselConverter( InstaCarouselResponse carousel) { return new InstaCarouselConverter {SourceObject = carousel}; } - public static IObjectConverter GetCarouselItemConverter( + public IObjectConverter GetCarouselItemConverter( InstaCarouselItemResponse carouselItem) { return new InstaCarouselItemConverter {SourceObject = carouselItem}; } - public static IObjectConverter GetStoryItemConverter( + public IObjectConverter GetStoryItemConverter( InstaStoryItemResponse storyItem) { return new InstaStoryItemConverter {SourceObject = storyItem}; } - public static IObjectConverter GetStoryConverter(InstaStoryResponse storyItem) + public IObjectConverter GetStoryConverter(InstaStoryResponse storyItem) { return new InstaStoryConverter {SourceObject = storyItem}; } - public static IObjectConverter GetStoryTrayConverter( + public IObjectConverter GetStoryTrayConverter( InstaStoryTrayResponse storyTray) { return new InstaStoryTrayConverter {SourceObject = storyTray}; } - public static IObjectConverter GetStoryMediaConverter( + public IObjectConverter GetStoryMediaConverter( InstaStoryMediaResponse storyMedia) { return new InstaStoryMediaConverter {SourceObject = storyMedia}; } - public static IObjectConverter GetImageConverter(ImageResponse imageResponse) + public IObjectConverter GetImageConverter(ImageResponse imageResponse) { return new InstaMediaImageConverter {SourceObject = imageResponse}; } - public static IObjectConverter GetExploreFeedConverter( + public IObjectConverter GetExploreFeedConverter( InstaExploreFeedResponse feedResponse) { return new InstaExploreFeedConverter {SourceObject = feedResponse}; } - public static IObjectConverter GetChannelConverter( + public IObjectConverter GetChannelConverter( InstaChannelResponse response) { return new InstaChannelConverter {SourceObject = response}; } - public static IObjectConverter GetTopLiveConverter( + public IObjectConverter GetTopLiveConverter( InstaTopLiveResponse response) { return new InstaTopLiveConverter {SourceObject = response}; } - public static IObjectConverter GetReelFeedConverter( - InsteReelFeedResponse response) + public IObjectConverter GetReelFeedConverter( + InstaReelFeedResponse response) { - return new InsteReelFeedConverter {SourceObject = response}; + return new InstaReelFeedConverter {SourceObject = response}; } - public static IObjectConverter GetMentionConverter( + public IObjectConverter GetMentionConverter( InstaReelMentionResponse response) { return new InstaReelMentionConverter {SourceObject = response}; } - public static IObjectConverter GetLocationConverter( + public IObjectConverter GetLocationConverter( InstaLocationResponse response) { return new InstaLocationConverter {SourceObject = response}; } - public static IObjectConverter GetHashTagConverter( + public IObjectConverter GetHashTagsSearchConverter( + InstaHashtagSearchResponse response) + { + return new InstaHashtagSearchConverter {SourceObject = response}; + } + + public IObjectConverter GetHashTagConverter( InstaHashtagResponse response) { return new InstaHashtagConverter {SourceObject = response}; } - public static IObjectConverter GetStoryFeedConverter( + public IObjectConverter GetStoryFeedConverter( InstaStoryFeedResponse response) { return new InstaStoryFeedConverter {SourceObject = response}; } + + public IObjectConverter GetCollectionConverter( + InstaCollectionItemResponse response) + { + return new InstaCollectionConverter {SourceObject = response}; + } + + public IObjectConverter GetCollectionsConverter( + InstaCollectionsResponse response) + { + return new InstaCollectionsConverter {SourceObject = response}; + } + + public IObjectConverter GetCoverMediaConverter( + InstaCoverMediaResponse response) + { + return new InstaCoverMediaConverter {SourceObject = response}; + } + + public IObjectConverter GetInboxMediaConverter( + InstaInboxMediaResponse response) + { + return new InstaInboxMediaConverter {SourceObject = response}; + } + + public IObjectConverter GetLocationsSearchConverter( + InstaLocationSearchResponse response) + { + return new InstaLocationSearchConverter {SourceObject = response}; + } + + public IObjectConverter GetLocationShortConverter( + InstaLocationShortResponse response) + { + return new InstaLocationShortConverter {SourceObject = response}; + } + + public IObjectConverter GetLocationFeedConverter( + InstaLocationFeedResponse response) + { + return new InstaLocationFeedConverter {SourceObject = response}; + } + + public IObjectConverter GetUserInfoConverter( + InstaUserInfoContainerResponse response) + { + return new InstaUserInfoConverter {SourceObject = response}; + } + + public IObjectConverter GetThreadLastSeenConverter( + InstaDirectInboxThreadLastSeenResponse response) + { + return new InstaDirectInboxThreadLastSeenConverter() {SourceObject = response}; + } } } \ No newline at end of file diff --git a/InstaSharper/Converters/IConvertersFabric.cs b/InstaSharper/Converters/IConvertersFabric.cs new file mode 100644 index 00000000..057077bb --- /dev/null +++ b/InstaSharper/Converters/IConvertersFabric.cs @@ -0,0 +1,118 @@ +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + public interface IConvertersFabric + { + IObjectConverter GetUserShortConverter( + InstaUserShortResponse instaresponse); + + IObjectConverter GetCurrentUserConverter( + InstaCurrentUserResponse instaresponse); + + IObjectConverter GetUserConverter(InstaUserResponse instaresponse); + + IObjectConverter GetSingleMediaConverter( + InstaMediaItemResponse responseMedia); + + IObjectConverter GetFeedConverter( + InstaFeedResponse feedResponse); + + IObjectConverter GetTagFeedConverter( + InstaTagFeedResponse feedResponse); + + IObjectConverter GetMediaListConverter( + InstaMediaListResponse mediaResponse); + + IObjectConverter GetCaptionConverter( + InstaCaptionResponse captionResponse); + + IObjectConverter + GetFriendShipStatusConverter(InstaFriendshipStatusResponse friendshipStatusResponse); + + IObjectConverter GetSingleStoryConverter( + InstaStoryResponse storyResponse); + + IObjectConverter GetUserTagConverter(InstaUserTagResponse tag); + + IObjectConverter + GetDirectInboxConverter(InstaDirectInboxContainerResponse inbox); + + IObjectConverter GetDirectThreadConverter( + InstaDirectInboxThreadResponse thread); + + IObjectConverter GetDirectThreadItemConverter( + InstaDirectInboxItemResponse threadItem); + + IObjectConverter + GetDirectSubscriptionConverter(InstaDirectInboxSubscriptionResponse subscription); + + IObjectConverter + GetSingleRecentActivityConverter(InstaRecentActivityFeedResponse feedResponse); + + IObjectConverter GetRecipientsConverter( + IInstaRecipientsResponse recipients); + + IObjectConverter GetCommentConverter( + InstaCommentResponse comment); + + IObjectConverter GetCommentListConverter( + InstaCommentListResponse commentList); + + IObjectConverter GetCarouselConverter( + InstaCarouselResponse carousel); + + IObjectConverter GetCarouselItemConverter( + InstaCarouselItemResponse carouselItem); + + IObjectConverter GetStoryItemConverter( + InstaStoryItemResponse storyItem); + + IObjectConverter GetStoryConverter(InstaStoryResponse storyItem); + + IObjectConverter GetStoryTrayConverter( + InstaStoryTrayResponse storyTray); + + IObjectConverter GetStoryMediaConverter( + InstaStoryMediaResponse storyMedia); + + IObjectConverter GetImageConverter(ImageResponse imageResponse); + + IObjectConverter GetExploreFeedConverter( + InstaExploreFeedResponse feedResponse); + + IObjectConverter GetChannelConverter( + InstaChannelResponse response); + + IObjectConverter GetTopLiveConverter( + InstaTopLiveResponse response); + + IObjectConverter GetReelFeedConverter( + InstaReelFeedResponse response); + + IObjectConverter GetMentionConverter( + InstaReelMentionResponse response); + + IObjectConverter GetLocationConverter( + InstaLocationResponse response); + + IObjectConverter GetHashTagsSearchConverter( + InstaHashtagSearchResponse response); + + IObjectConverter GetHashTagConverter( + InstaHashtagResponse response); + + IObjectConverter GetStoryFeedConverter( + InstaStoryFeedResponse response); + + IObjectConverter GetCollectionConverter( + InstaCollectionItemResponse response); + + IObjectConverter GetCollectionsConverter( + InstaCollectionsResponse response); + + IObjectConverter GetCoverMediaConverter( + InstaCoverMediaResponse response); + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/IObjectConverter.cs b/InstaSharper/Converters/IObjectConverter.cs index 2d1b0319..121bd01e 100644 --- a/InstaSharper/Converters/IObjectConverter.cs +++ b/InstaSharper/Converters/IObjectConverter.cs @@ -1,6 +1,6 @@ namespace InstaSharper.Converters { - internal interface IObjectConverter + public interface IObjectConverter { TT SourceObject { get; set; } T Convert(); diff --git a/InstaSharper/Converters/InstaCaptionConverter.cs b/InstaSharper/Converters/InstaCaptionConverter.cs index 1c27aaba..e033a872 100644 --- a/InstaSharper/Converters/InstaCaptionConverter.cs +++ b/InstaSharper/Converters/InstaCaptionConverter.cs @@ -17,7 +17,7 @@ public InstaCaption Convert() CreatedAtUtc = DateTimeHelper.UnixTimestampToDateTime(SourceObject.CreatedAtUtcUnixLike), MediaId = SourceObject.MediaId, Text = SourceObject.Text, - User = ConvertersFabric.GetUserShortConverter(SourceObject.User).Convert(), + User = ConvertersFabric.Instance.GetUserShortConverter(SourceObject.User).Convert(), UserId = SourceObject.UserId }; return caption; diff --git a/InstaSharper/Converters/InstaCarouselConverter.cs b/InstaSharper/Converters/InstaCarouselConverter.cs index 4c71c3e0..a894b74e 100644 --- a/InstaSharper/Converters/InstaCarouselConverter.cs +++ b/InstaSharper/Converters/InstaCarouselConverter.cs @@ -14,9 +14,10 @@ public InstaCarousel Convert() if (SourceObject == null) throw new ArgumentNullException($"Source object"); foreach (var item in SourceObject) { - var carouselItem = ConvertersFabric.GetCarouselItemConverter(item); + var carouselItem = ConvertersFabric.Instance.GetCarouselItemConverter(item); carousel.Add(carouselItem.Convert()); } + return carousel; } } diff --git a/InstaSharper/Converters/InstaCarouselItemConverter.cs b/InstaSharper/Converters/InstaCarouselItemConverter.cs index ab6fb198..a15b846f 100644 --- a/InstaSharper/Converters/InstaCarouselItemConverter.cs +++ b/InstaSharper/Converters/InstaCarouselItemConverter.cs @@ -15,10 +15,19 @@ public InstaCarouselItem Convert() { CarouselParentId = SourceObject.CarouselParentId, Height = int.Parse(SourceObject.Height), - Width = int.Parse(SourceObject.Width) + Width = int.Parse(SourceObject.Width), + MediaType = SourceObject.MediaType, + InstaIdentifier = SourceObject.InstaIdentifier, + Pk = SourceObject.Pk }; - foreach (var image in SourceObject.Images.Candidates) - carouselItem.Images.Add(new InstaImage(image.Url, int.Parse(image.Width), int.Parse(image.Height))); + if (SourceObject?.Images?.Candidates != null) + foreach (var image in SourceObject.Images.Candidates) + carouselItem.Images.Add(new InstaImage(image.Url, int.Parse(image.Width), int.Parse(image.Height))); + if (SourceObject?.Videos != null) + foreach (var video in SourceObject.Videos) + carouselItem.Videos.Add(new InstaVideo(video.Url, int.Parse(video.Width), int.Parse(video.Height), + video.Type)); + return carouselItem; } } diff --git a/InstaSharper/Converters/InstaChannelConverter.cs b/InstaSharper/Converters/InstaChannelConverter.cs index 53007d1f..976120ca 100644 --- a/InstaSharper/Converters/InstaChannelConverter.cs +++ b/InstaSharper/Converters/InstaChannelConverter.cs @@ -17,9 +17,10 @@ public InstaChannel Convert() ChannelType = SourceObject.ChannelType, Context = SourceObject.Context, Header = SourceObject.Header, - Title = SourceObject.Title, - Media = ConvertersFabric.GetSingleMediaConverter(SourceObject.Media).Convert() + Title = SourceObject.Title }; + if (SourceObject.Media != null) + channel.Media = ConvertersFabric.Instance.GetSingleMediaConverter(SourceObject.Media).Convert(); return channel; } } diff --git a/InstaSharper/Converters/InstaCollectionConverter.cs b/InstaSharper/Converters/InstaCollectionConverter.cs new file mode 100644 index 00000000..c440007a --- /dev/null +++ b/InstaSharper/Converters/InstaCollectionConverter.cs @@ -0,0 +1,32 @@ +using System.Linq; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + internal class InstaCollectionConverter : IObjectConverter + { + public InstaCollectionItemResponse SourceObject { get; set; } + + public InstaCollectionItem Convert() + { + var instaMediaList = new InstaMediaList(); + + if (SourceObject.Media != null) + instaMediaList.AddRange(SourceObject.Media.Medias + .Select(ConvertersFabric.Instance.GetSingleMediaConverter) + .Select(converter => converter.Convert())); + + return new InstaCollectionItem + { + CollectionId = SourceObject.CollectionId, + CollectionName = SourceObject.CollectionName, + HasRelatedMedia = SourceObject.HasRelatedMedia, + Media = instaMediaList, + CoverMedia = SourceObject.CoverMedia != null + ? ConvertersFabric.Instance.GetCoverMediaConverter(SourceObject.CoverMedia).Convert() + : null + }; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/InstaCollectionsConverter.cs b/InstaSharper/Converters/InstaCollectionsConverter.cs new file mode 100644 index 00000000..2f81e73e --- /dev/null +++ b/InstaSharper/Converters/InstaCollectionsConverter.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.Linq; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + public class InstaCollectionsConverter : IObjectConverter + { + public InstaCollectionsResponse SourceObject { get; set; } + + public InstaCollections Convert() + { + var instaCollectionList = new List(); + instaCollectionList.AddRange(SourceObject.Items.Select(ConvertersFabric.Instance.GetCollectionConverter) + .Select(converter => converter.Convert())); + + return new InstaCollections + { + Items = instaCollectionList, + MoreCollectionsAvailable = SourceObject.MoreAvailable + }; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/InstaCommentConverter.cs b/InstaSharper/Converters/InstaCommentConverter.cs index ad7924df..c8de08a1 100644 --- a/InstaSharper/Converters/InstaCommentConverter.cs +++ b/InstaSharper/Converters/InstaCommentConverter.cs @@ -24,7 +24,7 @@ public InstaComment Convert() Text = SourceObject.Text, Type = SourceObject.Type, UserId = SourceObject.UserId, - User = ConvertersFabric.GetUserShortConverter(SourceObject.User).Convert() + User = ConvertersFabric.Instance.GetUserShortConverter(SourceObject.User).Convert() }; return comment; } diff --git a/InstaSharper/Converters/InstaCommentListConverter.cs b/InstaSharper/Converters/InstaCommentListConverter.cs index 80b5fc24..1a5ef03a 100644 --- a/InstaSharper/Converters/InstaCommentListConverter.cs +++ b/InstaSharper/Converters/InstaCommentListConverter.cs @@ -12,19 +12,21 @@ public InstaCommentList Convert() var commentList = new InstaCommentList { Caption = SourceObject.Caption != null - ? ConvertersFabric.GetCaptionConverter(SourceObject.Caption).Convert() + ? ConvertersFabric.Instance.GetCaptionConverter(SourceObject.Caption).Convert() : null, CaptionIsEdited = SourceObject.CaptionIsEdited, - CommentsCount = SourceObject.CommentsCount, LikesEnabled = SourceObject.LikesEnabled, MoreComentsAvailable = SourceObject.MoreComentsAvailable, - MoreHeadLoadAvailable = SourceObject.MoreHeadLoadAvailable + MoreHeadLoadAvailable = SourceObject.MoreHeadLoadAvailable, + NextId = SourceObject.NextMaxId }; + if (SourceObject.Comments == null || !(SourceObject?.Comments?.Count > 0)) return commentList; foreach (var commentResponse in SourceObject.Comments) { - var converter = ConvertersFabric.GetCommentConverter(commentResponse); + var converter = ConvertersFabric.Instance.GetCommentConverter(commentResponse); commentList.Comments.Add(converter.Convert()); } + return commentList; } } diff --git a/InstaSharper/Converters/InstaCoverMediaConverter.cs b/InstaSharper/Converters/InstaCoverMediaConverter.cs new file mode 100644 index 00000000..378897c1 --- /dev/null +++ b/InstaSharper/Converters/InstaCoverMediaConverter.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Linq; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + internal class InstaCoverMediaConverter : IObjectConverter + { + public InstaCoverMediaResponse SourceObject { get; set; } + + public InstaCoverMedia Convert() + { + var instaImageList = new List(); + + if (SourceObject.ImageVersions != null) + instaImageList.AddRange(SourceObject.ImageVersions.Candidates + .Select(ConvertersFabric.Instance.GetImageConverter).Select(converter => converter.Convert())); + + return new InstaCoverMedia + { + Id = SourceObject.Id, + ImageVersions = instaImageList, + MediaType = SourceObject.MediaType, + OriginalHeight = SourceObject.OriginalHeight, + OriginalWidth = SourceObject.OriginalWidth + }; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/InstaCurrentUserConverter.cs b/InstaSharper/Converters/InstaCurrentUserConverter.cs index 734251de..315949fb 100644 --- a/InstaSharper/Converters/InstaCurrentUserConverter.cs +++ b/InstaSharper/Converters/InstaCurrentUserConverter.cs @@ -11,7 +11,7 @@ internal class InstaCurrentUserConverter : IObjectConverter 0) foreach (var imageResponse in SourceObject.HDProfilePicVersions) { - var converter = ConvertersFabric.GetImageConverter(imageResponse); + var converter = ConvertersFabric.Instance.GetImageConverter(imageResponse); user.HdProfileImages.Add(converter.Convert()); } if (SourceObject.HDProfilePicture != null) { - var converter = ConvertersFabric.GetImageConverter(SourceObject.HDProfilePicture); + var converter = ConvertersFabric.Instance.GetImageConverter(SourceObject.HDProfilePicture); user.HdProfilePicture = converter.Convert(); } + return user; } } diff --git a/InstaSharper/Converters/InstaDirectInboxConverter.cs b/InstaSharper/Converters/InstaDirectInboxConverter.cs index 34163c34..1d8321af 100644 --- a/InstaSharper/Converters/InstaDirectInboxConverter.cs +++ b/InstaSharper/Converters/InstaDirectInboxConverter.cs @@ -18,9 +18,10 @@ public InstaDirectInboxContainer Convert() }; if (SourceObject.Subscription != null) { - var converter = ConvertersFabric.GetDirectSubscriptionConverter(SourceObject.Subscription); + var converter = ConvertersFabric.Instance.GetDirectSubscriptionConverter(SourceObject.Subscription); inbox.Subscription = converter.Convert(); } + if (SourceObject.Inbox != null) { inbox.Inbox = new InstaDirectInbox @@ -35,16 +36,17 @@ public InstaDirectInboxContainer Convert() inbox.Inbox.Threads = new List(); foreach (var inboxThread in SourceObject.Inbox.Threads) { - var converter = ConvertersFabric.GetDirectThreadConverter(inboxThread); + var converter = ConvertersFabric.Instance.GetDirectThreadConverter(inboxThread); inbox.Inbox.Threads.Add(converter.Convert()); } } } + if (SourceObject.PendingUsers == null || SourceObject.PendingUsers.Count <= 0) return inbox; { foreach (var user in SourceObject.PendingUsers) { - var converter = ConvertersFabric.GetUserShortConverter(user); + var converter = ConvertersFabric.Instance.GetUserShortConverter(user); inbox.PendingUsers.Add(converter.Convert()); } } diff --git a/InstaSharper/Converters/InstaDirectInboxThreadLastSeenConverter.cs b/InstaSharper/Converters/InstaDirectInboxThreadLastSeenConverter.cs new file mode 100644 index 00000000..bf38ecac --- /dev/null +++ b/InstaSharper/Converters/InstaDirectInboxThreadLastSeenConverter.cs @@ -0,0 +1,24 @@ +using System; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + public class InstaDirectInboxThreadLastSeenConverter : IObjectConverter + { + public InstaDirectInboxThreadLastSeenResponse SourceObject { get; set; } + + public InstaDirectInboxThreadLastSeen Convert() + { + if (SourceObject == null) + throw new NullReferenceException("Source Object is null"); + + return new InstaDirectInboxThreadLastSeen() + { + UserId = SourceObject.UserId, + ItemId = SourceObject.ItemId, + TimeStamp = SourceObject.TimeStamp + }; + } + } +} diff --git a/InstaSharper/Converters/InstaDirectThreadConverter.cs b/InstaSharper/Converters/InstaDirectThreadConverter.cs index 5c3f2be1..0e594f9a 100644 --- a/InstaSharper/Converters/InstaDirectThreadConverter.cs +++ b/InstaSharper/Converters/InstaDirectThreadConverter.cs @@ -29,27 +29,41 @@ public InstaDirectInboxThread Convert() thread.Title = SourceObject.Title; if (SourceObject.Inviter != null) { - var userConverter = ConvertersFabric.GetUserShortConverter(SourceObject.Inviter); + var userConverter = ConvertersFabric.Instance.GetUserShortConverter(SourceObject.Inviter); thread.Inviter = userConverter.Convert(); } + if (SourceObject.Items != null && SourceObject.Items.Count > 0) { thread.Items = new List(); foreach (var item in SourceObject.Items) { - var converter = ConvertersFabric.GetDirectThreadItemConverter(item); + var converter = ConvertersFabric.Instance.GetDirectThreadItemConverter(item); thread.Items.Add(converter.Convert()); } } + if (SourceObject.Users != null && SourceObject.Users.Count > 0) { thread.Users = new InstaUserShortList(); foreach (var user in SourceObject.Users) { - var converter = ConvertersFabric.GetUserShortConverter(user); + var converter = ConvertersFabric.Instance.GetUserShortConverter(user); thread.Users.Add(converter.Convert()); } } + + if (SourceObject.LastSeen != null && SourceObject.LastSeen.Count > 0) + { + thread.LastSeen = new List(); + + foreach (var ThreadLastSeen in SourceObject.LastSeen) + { + var converter = ConvertersFabric.Instance.GetThreadLastSeenConverter(ThreadLastSeen); + thread.LastSeen.Add(converter.Convert()); + } + } + return thread; } } diff --git a/InstaSharper/Converters/InstaDirectThreadItemConverter.cs b/InstaSharper/Converters/InstaDirectThreadItemConverter.cs index b23fc091..7a645e50 100644 --- a/InstaSharper/Converters/InstaDirectThreadItemConverter.cs +++ b/InstaSharper/Converters/InstaDirectThreadItemConverter.cs @@ -1,4 +1,5 @@ -using InstaSharper.Classes.Models; +using System; +using InstaSharper.Classes.Models; using InstaSharper.Classes.ResponseWrappers; using InstaSharper.Helpers; @@ -15,21 +16,39 @@ public InstaDirectInboxItem Convert() ClientContext = SourceObject.ClientContext, ItemId = SourceObject.ItemId }; - switch (SourceObject.ItemType) - { - case "text": - threadItem.ItemType = InstaDirectThreadItemType.Text; - break; - case "media_share": - threadItem.ItemType = InstaDirectThreadItemType.MediaShare; - break; - } - threadItem.Text = SourceObject.Text; + threadItem.TimeStamp = DateTimeHelper.UnixTimestampMilisecondsToDateTime(SourceObject.TimeStamp); threadItem.UserId = SourceObject.UserId; - if (SourceObject.MediaShare == null) return threadItem; - var converter = ConvertersFabric.GetSingleMediaConverter(SourceObject.MediaShare); - threadItem.MediaShare = converter.Convert(); + + var truncatedItemType = SourceObject.ItemType.Trim().Replace("_", ""); + if (Enum.TryParse(truncatedItemType, true, out InstaDirectThreadItemType type)) + threadItem.ItemType = type; + + if (threadItem.ItemType == InstaDirectThreadItemType.Link) + { + threadItem.Text = SourceObject.Link?.LinkContext?.LinkUrl; + } + else if (threadItem.ItemType == InstaDirectThreadItemType.Like) + { + threadItem.Text = SourceObject.Like; + } + else if (threadItem.ItemType == InstaDirectThreadItemType.Media + && SourceObject.Media != null) + { + var converter = ConvertersFabric.Instance.GetInboxMediaConverter(SourceObject.Media); + threadItem.Media = converter.Convert(); + } + else if (threadItem.ItemType == InstaDirectThreadItemType.MediaShare + && SourceObject.MediaShare != null) + { + var converter = ConvertersFabric.Instance.GetSingleMediaConverter(SourceObject.MediaShare); + threadItem.MediaShare = converter.Convert(); + } + else + { + threadItem.Text = SourceObject.Text; + } + return threadItem; } } diff --git a/InstaSharper/Converters/InstaExploreFeedConverter.cs b/InstaSharper/Converters/InstaExploreFeedConverter.cs index 9805288e..138c26ce 100644 --- a/InstaSharper/Converters/InstaExploreFeedConverter.cs +++ b/InstaSharper/Converters/InstaExploreFeedConverter.cs @@ -17,23 +17,30 @@ public InstaExploreFeed Convert() List ConvertMedia(List mediasResponse) { var medias = new List(); + if (mediasResponse == null) + return medias; foreach (var instaUserFeedItemResponse in mediasResponse) { if (instaUserFeedItemResponse?.Type != 0) continue; - var feedItem = ConvertersFabric.GetSingleMediaConverter(instaUserFeedItemResponse).Convert(); + var feedItem = ConvertersFabric.Instance.GetSingleMediaConverter(instaUserFeedItemResponse) + .Convert(); medias.Add(feedItem); } + return medias; } var feed = new InstaExploreFeed { - StoryTray = ConvertersFabric.GetStoryTrayConverter(SourceObject.Items.StoryTray).Convert(), - Channel = ConvertersFabric.GetChannelConverter(SourceObject.Items.Channel).Convert() + NextId = SourceObject.NextMaxId }; - feed.Medias.AddRange(ConvertMedia(SourceObject.Items.Medias)); - feed.Medias.PageSize = feed.Medias.Count; + if (SourceObject.Items?.StoryTray != null) + feed.StoryTray = ConvertersFabric.Instance.GetStoryTrayConverter(SourceObject.Items.StoryTray) + .Convert(); + if (SourceObject.Items?.Channel != null) + feed.Channel = ConvertersFabric.Instance.GetChannelConverter(SourceObject.Items.Channel).Convert(); + feed.Medias.AddRange(ConvertMedia(SourceObject.Items?.Medias)); return feed; } } diff --git a/InstaSharper/Converters/InstaFeedConverter.cs b/InstaSharper/Converters/InstaFeedConverter.cs index 105594aa..80cdc12f 100644 --- a/InstaSharper/Converters/InstaFeedConverter.cs +++ b/InstaSharper/Converters/InstaFeedConverter.cs @@ -16,10 +16,11 @@ public InstaFeed Convert() foreach (var instaUserFeedItemResponse in SourceObject.Items) { if (instaUserFeedItemResponse?.Type != 0) continue; - var feedItem = ConvertersFabric.GetSingleMediaConverter(instaUserFeedItemResponse).Convert(); + var feedItem = ConvertersFabric.Instance.GetSingleMediaConverter(instaUserFeedItemResponse).Convert(); feed.Medias.Add(feedItem); } - feed.Medias.PageSize = SourceObject.Items.Count; + + feed.NextId = SourceObject.NextMaxId; return feed; } } diff --git a/InstaSharper/Converters/InstaHashtagConverter.cs b/InstaSharper/Converters/InstaHashtagConverter.cs index 010720d8..67ac5a6d 100644 --- a/InstaSharper/Converters/InstaHashtagConverter.cs +++ b/InstaSharper/Converters/InstaHashtagConverter.cs @@ -14,7 +14,8 @@ public InstaHashtag Convert() var hashtag = new InstaHashtag { Id = SourceObject.Id, - Name = SourceObject.Name + Name = SourceObject.Name, + MediaCount = SourceObject.MediaCount }; return hashtag; } diff --git a/InstaSharper/Converters/InstaHashtagSearchConverter.cs b/InstaSharper/Converters/InstaHashtagSearchConverter.cs new file mode 100644 index 00000000..5e08f4a6 --- /dev/null +++ b/InstaSharper/Converters/InstaHashtagSearchConverter.cs @@ -0,0 +1,27 @@ +using System; +using System.Linq; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + internal class InstaHashtagSearchConverter : IObjectConverter + { + public InstaHashtagSearchResponse SourceObject { get; set; } + + public InstaHashtagSearch Convert() + { + if (SourceObject == null) + throw new ArgumentNullException($"Source object"); + + var tags = new InstaHashtagSearch(); + + tags.MoreAvailable = SourceObject.MoreAvailable.GetValueOrDefault(false); + tags.RankToken = SourceObject.RankToken; + tags.AddRange(SourceObject.Tags.Select(tag => + ConvertersFabric.Instance.GetHashTagConverter(tag).Convert())); + + return tags; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/InstaInboxMediaConverter.cs b/InstaSharper/Converters/InstaInboxMediaConverter.cs new file mode 100644 index 00000000..6c4e749b --- /dev/null +++ b/InstaSharper/Converters/InstaInboxMediaConverter.cs @@ -0,0 +1,26 @@ +using System; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + internal class InstaInboxMediaConverter : IObjectConverter + { + public InstaInboxMediaResponse SourceObject { get; set; } + + public InstaInboxMedia Convert() + { + if (SourceObject == null) throw new ArgumentNullException($"Source object"); + var inboxMedia = new InstaInboxMedia + { + MediaType = SourceObject.MediaType, + OriginalHeight = SourceObject.OriginalHeight, + OriginalWidth = SourceObject.OriginalWidth + }; + if (SourceObject?.ImageCandidates?.Candidates == null) return inboxMedia; + foreach (var image in SourceObject.ImageCandidates.Candidates) + inboxMedia.Images.Add(new InstaImage(image.Url, int.Parse(image.Width), int.Parse(image.Height))); + return inboxMedia; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/InstaLocationConverter.cs b/InstaSharper/Converters/InstaLocationConverter.cs index 8e048468..18685dd9 100644 --- a/InstaSharper/Converters/InstaLocationConverter.cs +++ b/InstaSharper/Converters/InstaLocationConverter.cs @@ -16,8 +16,8 @@ public InstaLocation Convert() Name = SourceObject.Name, Address = SourceObject.Address, City = SourceObject.City, - ExternalSource = SourceObject.ExternalSource, - FacebookPlacesId = SourceObject.FacebookPlacesId, + ExternalSource = SourceObject.ExternalIdSource, + ExternalId = SourceObject.ExternalId, Lat = SourceObject.Lat, Lng = SourceObject.Lng, Pk = SourceObject.Pk, diff --git a/InstaSharper/Converters/InstaLocationFeedConverter.cs b/InstaSharper/Converters/InstaLocationFeedConverter.cs new file mode 100644 index 00000000..f62e67eb --- /dev/null +++ b/InstaSharper/Converters/InstaLocationFeedConverter.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + internal class InstaLocationFeedConverter : IObjectConverter + { + public InstaLocationFeedResponse SourceObject { get; set; } + + public InstaLocationFeed Convert() + { + if (SourceObject == null) + throw new ArgumentNullException("SourceObject"); + + InstaMediaList ConvertMedia(List mediasResponse) + { + var medias = new InstaMediaList(); + if (mediasResponse == null) + return medias; + foreach (var instaUserFeedItemResponse in mediasResponse) + { + if (instaUserFeedItemResponse?.Type != 0) continue; + var feedItem = ConvertersFabric.Instance.GetSingleMediaConverter(instaUserFeedItemResponse) + .Convert(); + medias.Add(feedItem); + } + + return medias; + } + + var feed = new InstaLocationFeed + { + MediaCount = SourceObject.MediaCount, + NextId = SourceObject.NextMaxId, + Medias = ConvertMedia(SourceObject.Items), + RankedMedias = ConvertMedia(SourceObject.RankedItems), + Location = ConvertersFabric.Instance.GetLocationConverter(SourceObject.Location).Convert(), + Story = ConvertersFabric.Instance.GetStoryConverter(SourceObject.Story).Convert() + }; + return feed; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/InstaLocationSearchConverter.cs b/InstaSharper/Converters/InstaLocationSearchConverter.cs new file mode 100644 index 00000000..6112e377 --- /dev/null +++ b/InstaSharper/Converters/InstaLocationSearchConverter.cs @@ -0,0 +1,21 @@ +using System; +using System.Linq; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + internal class InstaLocationSearchConverter : IObjectConverter + { + public InstaLocationSearchResponse SourceObject { get; set; } + + public InstaLocationShortList Convert() + { + if (SourceObject == null) throw new ArgumentNullException($"Source object"); + var locations = new InstaLocationShortList(); + locations.AddRange(SourceObject.Locations.Select(location => + ConvertersFabric.Instance.GetLocationShortConverter(location).Convert())); + return locations; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/InstaLocationShortConverter.cs b/InstaSharper/Converters/InstaLocationShortConverter.cs new file mode 100644 index 00000000..1b7b237d --- /dev/null +++ b/InstaSharper/Converters/InstaLocationShortConverter.cs @@ -0,0 +1,26 @@ +using System; +using InstaSharper.Classes.Models; +using InstaSharper.Classes.ResponseWrappers; + +namespace InstaSharper.Converters +{ + internal class InstaLocationShortConverter : IObjectConverter + { + public InstaLocationShortResponse SourceObject { get; set; } + + public InstaLocationShort Convert() + { + if (SourceObject == null) throw new ArgumentNullException($"Source object"); + var location = new InstaLocationShort + { + Name = SourceObject.Name, + Address = SourceObject.Address, + ExternalSource = SourceObject.ExternalIdSource, + ExternalId = SourceObject.ExternalId, + Lat = SourceObject.Lat, + Lng = SourceObject.Lng + }; + return location; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/InstaMediaConverter.cs b/InstaSharper/Converters/InstaMediaConverter.cs index fa35d292..5af9e19d 100644 --- a/InstaSharper/Converters/InstaMediaConverter.cs +++ b/InstaSharper/Converters/InstaMediaConverter.cs @@ -20,10 +20,10 @@ public InstaMedia Convert() Pk = SourceObject.Pk, ClientCacheKey = SourceObject.ClientCacheKey, CommentsCount = SourceObject.CommentsCount, - DeviceTimeStap = DateTimeHelper.UnixTimestampToDateTime(SourceObject.DeviceTimeStapUnixLike), + DeviceTimeStamp = DateTimeHelper.UnixTimestampToDateTime(SourceObject.DeviceTimeStampUnixLike), HasLiked = SourceObject.HasLiked, PhotoOfYou = SourceObject.PhotoOfYou, - TrakingToken = SourceObject.TrakingToken, + TrackingToken = SourceObject.TrackingToken, TakenAt = DateTimeHelper.UnixTimestampToDateTime(SourceObject.TakenAtUnixLike), Height = SourceObject.Height, LikesCount = SourceObject.LikesCount, @@ -34,21 +34,30 @@ public InstaMedia Convert() ViewCount = int.Parse(SourceObject.ViewCount.ToString(CultureInfo.InvariantCulture)) }; if (SourceObject.CarouselMedia != null) - media.Carousel = ConvertersFabric.GetCarouselConverter(SourceObject.CarouselMedia).Convert(); + media.Carousel = ConvertersFabric.Instance.GetCarouselConverter(SourceObject.CarouselMedia).Convert(); if (SourceObject.User != null) - media.User = ConvertersFabric.GetUserConverter(SourceObject.User).Convert(); + media.User = ConvertersFabric.Instance.GetUserConverter(SourceObject.User).Convert(); if (SourceObject.Caption != null) - media.Caption = ConvertersFabric.GetCaptionConverter(SourceObject.Caption).Convert(); + media.Caption = ConvertersFabric.Instance.GetCaptionConverter(SourceObject.Caption).Convert(); if (SourceObject.NextMaxId != null) media.NextMaxId = SourceObject.NextMaxId; if (SourceObject.Likers != null && SourceObject.Likers?.Count > 0) foreach (var liker in SourceObject.Likers) - media.Likers.Add(ConvertersFabric.GetUserShortConverter(liker).Convert()); + media.Likers.Add(ConvertersFabric.Instance.GetUserShortConverter(liker).Convert()); if (SourceObject.UserTagList?.In != null && SourceObject.UserTagList?.In?.Count > 0) foreach (var tag in SourceObject.UserTagList.In) - media.Tags.Add(ConvertersFabric.GetUserTagConverter(tag).Convert()); + media.Tags.Add(ConvertersFabric.Instance.GetUserTagConverter(tag).Convert()); + if (SourceObject.PreviewComments != null) + foreach (var comment in SourceObject.PreviewComments) + media.PreviewComments.Add(ConvertersFabric.Instance.GetCommentConverter(comment).Convert()); + if (SourceObject.Location != null) + media.Location = ConvertersFabric.Instance.GetLocationConverter(SourceObject.Location).Convert(); if (SourceObject.Images?.Candidates == null) return media; foreach (var image in SourceObject.Images.Candidates) media.Images.Add(new InstaImage(image.Url, int.Parse(image.Width), int.Parse(image.Height))); + if (SourceObject.Videos == null) return media; + foreach (var video in SourceObject.Videos) + media.Videos.Add(new InstaVideo(video.Url, int.Parse(video.Width), int.Parse(video.Height), + video.Type)); return media; } } diff --git a/InstaSharper/Converters/InstaMediaListConverter.cs b/InstaSharper/Converters/InstaMediaListConverter.cs index f6036476..e23d6671 100644 --- a/InstaSharper/Converters/InstaMediaListConverter.cs +++ b/InstaSharper/Converters/InstaMediaListConverter.cs @@ -14,7 +14,7 @@ public InstaMediaList Convert() if (SourceObject == null) throw new ArgumentNullException($"Source object"); var mediaList = new InstaMediaList(); mediaList.AddRange( - SourceObject.Medias.Select(ConvertersFabric.GetSingleMediaConverter) + SourceObject.Medias.Select(ConvertersFabric.Instance.GetSingleMediaConverter) .Select(converter => converter.Convert())); mediaList.PageSize = SourceObject.ResultsCount; return mediaList; diff --git a/InstaSharper/Converters/InstaRecentActivityConverter.cs b/InstaSharper/Converters/InstaRecentActivityConverter.cs index 679baeea..cd9518ea 100644 --- a/InstaSharper/Converters/InstaRecentActivityConverter.cs +++ b/InstaSharper/Converters/InstaRecentActivityConverter.cs @@ -1,4 +1,5 @@ -using InstaSharper.Classes.Models; +using System.Linq; +using InstaSharper.Classes.Models; using InstaSharper.Classes.ResponseWrappers; using InstaSharper.Helpers; @@ -14,11 +15,13 @@ public InstaRecentActivityFeed Convert() var activityStory = new InstaRecentActivityFeed { Pk = SourceObject.Pk, - Type = SourceObject.Type, + Type = (InstaActivityFeedType) SourceObject.Type, ProfileId = SourceObject.Args.ProfileId, + ProfileName = SourceObject.Args.ProfileName, ProfileImage = SourceObject.Args.ProfileImage, Text = SourceObject.Args.Text, - TimeStamp = DateTimeHelper.UnixTimestampToDateTime(SourceObject.Args.TimeStamp) + MediaId = SourceObject.Args.Medias?.FirstOrDefault()?.MediaId, + TimeStamp = DateTimeHelper.UnixTimestampToDateTime(SourceObject.Args.TimeStamp.Split('.')[0]) }; if (SourceObject.Args.Links != null) foreach (var instaLinkResponse in SourceObject.Args.Links) @@ -38,8 +41,10 @@ public InstaRecentActivityFeed Convert() }; if (SourceObject.Args.InlineFollow.UserInfo != null) activityStory.InlineFollow.User = - ConvertersFabric.GetUserShortConverter(SourceObject.Args.InlineFollow.UserInfo).Convert(); + ConvertersFabric.Instance.GetUserShortConverter(SourceObject.Args.InlineFollow.UserInfo) + .Convert(); } + return activityStory; } } diff --git a/InstaSharper/Converters/InstaRecipientsConverter.cs b/InstaSharper/Converters/InstaRecipientsConverter.cs index e1eea11f..a60dd594 100644 --- a/InstaSharper/Converters/InstaRecipientsConverter.cs +++ b/InstaSharper/Converters/InstaRecipientsConverter.cs @@ -3,35 +3,47 @@ namespace InstaSharper.Converters { - internal class InstaRecipientsConverter : IObjectConverter + internal class InstaRecipientsConverter : IObjectConverter { public IInstaRecipientsResponse SourceObject { get; set; } - public InstaRecipientThreads Convert() + public InstaRecipients Convert() { - var recipients = new InstaRecipientThreads + var recipients = new InstaRecipients { ExpiresIn = SourceObject.Expires, Filtered = SourceObject.Filtered, RankToken = SourceObject.RankToken, RequestId = SourceObject.RequestId }; - foreach (var recipient in SourceObject.RankedRecipients) - { - var rankedThread = new InstaRankedRecipientThread + if (SourceObject?.RankedRecipients?.Length > 0) + foreach (var recipient in SourceObject.RankedRecipients) { - Canonical = recipient.Thread.Canonical, - Named = recipient.Thread.Named, - Pending = recipient.Thread.Pending, - ThreadId = recipient.Thread.ThreadId, - ThreadTitle = recipient.Thread.ThreadTitle, - ThreadType = recipient.Thread.ThreadType, - ViewerId = recipient.Thread.ViewerId - }; - foreach (var user in recipient.Thread.Users) - rankedThread.Users.Add(ConvertersFabric.GetUserShortConverter(user).Convert()); - recipients.Items.Add(rankedThread); - } + if (recipient == null) continue; + + if (recipient.Thread != null) + { + var rankedThread = new InstaRankedRecipientThread + { + Canonical = recipient.Thread.Canonical, + Named = recipient.Thread.Named, + Pending = recipient.Thread.Pending, + ThreadId = recipient.Thread.ThreadId, + ThreadTitle = recipient.Thread.ThreadTitle, + ThreadType = recipient.Thread.ThreadType, + ViewerId = recipient.Thread.ViewerId + }; + foreach (var user in recipient.Thread.Users) + rankedThread.Users.Add(ConvertersFabric.Instance.GetUserShortConverter(user).Convert()); + recipients.Threads.Add(rankedThread); + } + + if (recipient.User != null) + { + var user = ConvertersFabric.Instance.GetUserShortConverter(recipient.User).Convert(); + recipients.Users.Add(user); + } + } return recipients; } diff --git a/InstaSharper/Converters/InsteReelFeedConverter.cs b/InstaSharper/Converters/InstaReelFeedConverter.cs similarity index 59% rename from InstaSharper/Converters/InsteReelFeedConverter.cs rename to InstaSharper/Converters/InstaReelFeedConverter.cs index 15f9365d..f66be151 100644 --- a/InstaSharper/Converters/InsteReelFeedConverter.cs +++ b/InstaSharper/Converters/InstaReelFeedConverter.cs @@ -5,14 +5,14 @@ namespace InstaSharper.Converters { - internal class InsteReelFeedConverter : IObjectConverter + internal class InstaReelFeedConverter : IObjectConverter { - public InsteReelFeedResponse SourceObject { get; set; } + public InstaReelFeedResponse SourceObject { get; set; } - public InsteReelFeed Convert() + public InstaReelFeed Convert() { if (SourceObject == null) throw new ArgumentNullException($"Source object"); - var reelFeed = new InsteReelFeed + var reelFeed = new InstaReelFeed { CanReply = SourceObject.CanReply, CanReshare = SourceObject.CanReshare, @@ -22,11 +22,12 @@ public InsteReelFeed Convert() LatestReelMedia = SourceObject.LatestReelMedia ?? 0, PrefetchCount = SourceObject.PrefetchCount, Seen = SourceObject.Seen ?? 0, - User = ConvertersFabric.GetUserShortConverter(SourceObject.User).Convert() + User = ConvertersFabric.Instance.GetUserShortConverter(SourceObject.User).Convert() }; - foreach (var item in SourceObject.Items) - reelFeed.Items.Add(ConvertersFabric.GetStoryItemConverter(item).Convert()); + if (SourceObject.Items != null) + foreach (var item in SourceObject.Items) + reelFeed.Items.Add(ConvertersFabric.Instance.GetStoryItemConverter(item).Convert()); return reelFeed; } } diff --git a/InstaSharper/Converters/InstaReelMentionConverter.cs b/InstaSharper/Converters/InstaReelMentionConverter.cs index c2a4957e..f1234ef0 100644 --- a/InstaSharper/Converters/InstaReelMentionConverter.cs +++ b/InstaSharper/Converters/InstaReelMentionConverter.cs @@ -21,9 +21,9 @@ public InstaReelMention Convert() Y = SourceObject.Y }; if (SourceObject.Hashtag != null) - mention.Hashtag = ConvertersFabric.GetHashTagConverter(SourceObject.Hashtag).Convert(); + mention.Hashtag = ConvertersFabric.Instance.GetHashTagConverter(SourceObject.Hashtag).Convert(); if (SourceObject.User != null) - mention.User = ConvertersFabric.GetUserShortConverter(SourceObject.User).Convert(); + mention.User = ConvertersFabric.Instance.GetUserShortConverter(SourceObject.User).Convert(); return mention; } } diff --git a/InstaSharper/Converters/InstaStoryConverter.cs b/InstaSharper/Converters/InstaStoryConverter.cs index 60d16ed5..3aace862 100644 --- a/InstaSharper/Converters/InstaStoryConverter.cs +++ b/InstaSharper/Converters/InstaStoryConverter.cs @@ -1,6 +1,6 @@ -using System; -using InstaSharper.Classes.Models; +using InstaSharper.Classes.Models; using InstaSharper.Classes.ResponseWrappers; +using InstaSharper.Helpers; namespace InstaSharper.Converters { @@ -10,8 +10,30 @@ internal class InstaStoryConverter : IObjectConverter ConvertMedia(List mediasResponse) foreach (var instaUserFeedItemResponse in mediasResponse) { if (instaUserFeedItemResponse?.Type != 0) continue; - var feedItem = ConvertersFabric.GetSingleMediaConverter(instaUserFeedItemResponse).Convert(); + var feedItem = ConvertersFabric.Instance.GetSingleMediaConverter(instaUserFeedItemResponse) + .Convert(); medias.Add(feedItem); } + return medias; } feed.RankedMedias.AddRange(ConvertMedia(SourceObject.RankedItems)); feed.Medias.AddRange(ConvertMedia(SourceObject.Medias)); - feed.Medias.PageSize = feed.Medias.Count; + feed.NextId = SourceObject.NextMaxId; foreach (var story in SourceObject.Stories) { - var feedItem = ConvertersFabric.GetStoryConverter(story).Convert(); + var feedItem = ConvertersFabric.Instance.GetStoryConverter(story).Convert(); feed.Stories.Add(feedItem); } + return feed; } } diff --git a/InstaSharper/Converters/InstaTopLiveConverter.cs b/InstaSharper/Converters/InstaTopLiveConverter.cs index 589a0775..0b598bd7 100644 --- a/InstaSharper/Converters/InstaTopLiveConverter.cs +++ b/InstaSharper/Converters/InstaTopLiveConverter.cs @@ -14,9 +14,10 @@ public InstaTopLive Convert() var storyTray = new InstaTopLive {RankedPosition = SourceObject.RankedPosition}; foreach (var owner in SourceObject.BroadcastOwners) { - var userOwner = ConvertersFabric.GetUserShortConverter(owner).Convert(); + var userOwner = ConvertersFabric.Instance.GetUserShortConverter(owner).Convert(); storyTray.BroadcastOwners.Add(userOwner); } + return storyTray; } } diff --git a/InstaSharper/Converters/InstaUserConverter.cs b/InstaSharper/Converters/InstaUserConverter.cs index 59731f62..e4950ec4 100644 --- a/InstaSharper/Converters/InstaUserConverter.cs +++ b/InstaSharper/Converters/InstaUserConverter.cs @@ -11,22 +11,26 @@ internal class InstaUserConverter : IObjectConverter + { + public InstaUserInfoContainerResponse SourceObject { get; set; } + + public InstaUserInfo Convert() + { + if (SourceObject == null) + throw new ArgumentNullException("SourceObject"); + + var userInfo = new InstaUserInfo + { + Pk = SourceObject.User.Pk, + Username = SourceObject.User.Username, + FullName = SourceObject.User.FullName, + IsPrivate = SourceObject.User.IsPrivate, + ProfilePicUrl = SourceObject.User.ProfilePicUrl, + IsVerified = SourceObject.User.IsVerified, + HasAnonymousProfilePicture = SourceObject.User.HasAnonymousProfilePicture, + MediaCount = SourceObject.User.MediaCount, + GeoMediaCount = SourceObject.User.GeoMediaCount, + FollowerCount = SourceObject.User.FollowerCount, + FollowingCount = SourceObject.User.FollowingCount, + Biography = SourceObject.User.Biography, + ExternalUrl = SourceObject.User.ExternalUrl, + ExternalLynxUrl = SourceObject.User.ExternalLynxUrl, + ReelAutoArchive = SourceObject.User.ReelAutoArchive, + UsertagsCount = SourceObject.User.UsertagsCount, + IsFavorite = SourceObject.User.IsFavorite, + HasChaining = SourceObject.User.HasChaining, + ProfileContext = SourceObject.User.ProfileContext, + ProfileContextMutualFollowIds = SourceObject.User.ProfileContextMutualFollowIds, + IsBusiness = SourceObject.User.IsBusiness, + IncludeDirectBlacklistStatus = SourceObject.User.IncludeDirectBlacklistStatus, + HasUnseenBestiesMedia = SourceObject.User.HasUnseenBestiesMedia, + AutoExpandChaining = SourceObject.User.AutoExpandChaining + }; + return userInfo; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/InstaUserTagConverter.cs b/InstaSharper/Converters/InstaUserTagConverter.cs index 4df644dc..5227fade 100644 --- a/InstaSharper/Converters/InstaUserTagConverter.cs +++ b/InstaSharper/Converters/InstaUserTagConverter.cs @@ -16,7 +16,7 @@ public InstaUserTag Convert() userTag.Position = new InstaPosition(SourceObject.Position[0], SourceObject.Position[1]); userTag.TimeInVideo = SourceObject.TimeInVideo; if (SourceObject.User != null) - userTag.User = ConvertersFabric.GetUserShortConverter(SourceObject.User).Convert(); + userTag.User = ConvertersFabric.Instance.GetUserShortConverter(SourceObject.User).Convert(); return userTag; } } diff --git a/InstaSharper/Converters/Json/InstaCollectionDataConverter.cs b/InstaSharper/Converters/Json/InstaCollectionDataConverter.cs new file mode 100644 index 00000000..b93916f4 --- /dev/null +++ b/InstaSharper/Converters/Json/InstaCollectionDataConverter.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using InstaSharper.Classes.ResponseWrappers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace InstaSharper.Converters.Json +{ + internal class InstaCollectionDataConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(InstaMediaListResponse); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, + JsonSerializer serializer) + { + var root = JToken.Load(reader); + var feed = root.ToObject>(); + + var listMedia = new InstaMediaListResponse(); + feed.ForEach(item => listMedia.Medias.Add(item.Media)); + + return listMedia; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value); + } + + private class InstaCollectionItemsToMedia + { + [JsonProperty("media")] public InstaMediaItemResponse Media { get; set; } + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/Json/InstaExploreFeedDataConverter.cs b/InstaSharper/Converters/Json/InstaExploreFeedDataConverter.cs index c91f27b6..1965ee25 100644 --- a/InstaSharper/Converters/Json/InstaExploreFeedDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaExploreFeedDataConverter.cs @@ -31,18 +31,21 @@ public override object ReadJson(JsonReader reader, feed.Items.StoryTray = storyTray; continue; } + if (channelToken != null) { var channel = channelToken.ToObject(); feed.Items.Channel = channel; continue; } + if (mediaToken != null) { var media = mediaToken.ToObject(); feed.Items.Medias.Add(media); } } + return feed; } diff --git a/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs b/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs index 8020a520..59f111db 100644 --- a/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaFeedResponseDataConverter.cs @@ -36,6 +36,7 @@ public override object ReadJson(JsonReader reader, items = token["items"]; feed.Items = items.ToObject>(); } + var users = token["suggested_users"]?["suggestions"]; if (users != null) foreach (var user in users) @@ -44,6 +45,7 @@ public override object ReadJson(JsonReader reader, var usr = user.ToObject(); feed.SuggestedUsers.Add(usr); } + return feed; } diff --git a/InstaSharper/Converters/Json/InstaInboxThreadLastSeenConverter.cs b/InstaSharper/Converters/Json/InstaInboxThreadLastSeenConverter.cs new file mode 100644 index 00000000..ef47ae61 --- /dev/null +++ b/InstaSharper/Converters/Json/InstaInboxThreadLastSeenConverter.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using InstaSharper.Classes.ResponseWrappers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace InstaSharper.Converters.Json +{ + internal class InstaInboxThreadLastSeenConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var Result = new List(); + + var LastSeenJasonObject = JObject.Load(reader); + + foreach (var JObject in LastSeenJasonObject) + { + var ThreadLastSeen = + JsonConvert.DeserializeObject(JObject.Value.ToString()); + + ThreadLastSeen.UserId = Convert.ToInt64(JObject.Key); + + Result.Add(ThreadLastSeen); + } + + return Result; + } + + public override bool CanConvert(Type objectType) + { + return objectType == typeof(InstaDirectInboxThreadLastSeenResponse); + } + } +} diff --git a/InstaSharper/Converters/Json/InstaMediaDataConverter.cs b/InstaSharper/Converters/Json/InstaMediaDataConverter.cs new file mode 100644 index 00000000..c715c215 --- /dev/null +++ b/InstaSharper/Converters/Json/InstaMediaDataConverter.cs @@ -0,0 +1,32 @@ +using System; +using InstaSharper.Classes.ResponseWrappers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace InstaSharper.Converters.Json +{ + internal class InstaMediaDataConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(InstaMediaItemResponse); + } + + public override object ReadJson(JsonReader reader, + Type objectType, + object existingValue, + JsonSerializer serializer) + { + var root = JToken.Load(reader); + var media = root.ToObject(); + if (media?.Pk != null) return media; + var mediaToken = root.SelectToken("media"); + return mediaToken.ToObject(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + serializer.Serialize(writer, value); + } + } +} \ No newline at end of file diff --git a/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs b/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs index 8586f0bf..a427824c 100644 --- a/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaMediaListDataConverter.cs @@ -32,6 +32,7 @@ public override object ReadJson(JsonReader reader, if (string.IsNullOrEmpty(media?.Pk)) continue; feed.Medias.Add(media); } + if (storiesTray == null) return feed; foreach (var storyItem in storiesTray) { diff --git a/InstaSharper/Converters/Json/InstaRecentActivityConverter.cs b/InstaSharper/Converters/Json/InstaRecentActivityConverter.cs index 0145e7ba..9d3d2f14 100644 --- a/InstaSharper/Converters/Json/InstaRecentActivityConverter.cs +++ b/InstaSharper/Converters/Json/InstaRecentActivityConverter.cs @@ -31,6 +31,7 @@ public override object ReadJson(JsonReader reader, recentActivity.Stories.AddRange(oldStories); recentActivity.IsOwnActivity = true; } + return recentActivity; } diff --git a/InstaSharper/Converters/Json/InstaTagFeedDataConverter.cs b/InstaSharper/Converters/Json/InstaTagFeedDataConverter.cs index 81b68739..cf758c95 100644 --- a/InstaSharper/Converters/Json/InstaTagFeedDataConverter.cs +++ b/InstaSharper/Converters/Json/InstaTagFeedDataConverter.cs @@ -22,6 +22,7 @@ public override object ReadJson(JsonReader reader, var root = JToken.Load(reader); var feed = root.ToObject(); feed.Medias.Clear(); + feed.RankedItems.Clear(); feed.Stories.Clear(); var story = root.SelectToken("story"); var rankedItems = root.SelectToken("ranked_items"); @@ -34,8 +35,10 @@ List GetMedias(JToken token) .Where(media => !string.IsNullOrEmpty(media?.Pk)).ToList(); } - feed.Medias.AddRange(GetMedias(items)); - feed.RankedItems.AddRange(GetMedias(rankedItems)); + if (items != null) + feed.Medias.AddRange(GetMedias(items)); + if (rankedItems != null) + feed.RankedItems.AddRange(GetMedias(rankedItems)); if (storiesTray == null) return feed; foreach (var storyItem in storiesTray) { diff --git a/InstaSharper/Helpers/ConvertersHelper.cs b/InstaSharper/Helpers/ConvertersHelper.cs new file mode 100644 index 00000000..b89b2bdc --- /dev/null +++ b/InstaSharper/Helpers/ConvertersHelper.cs @@ -0,0 +1,12 @@ +using InstaSharper.Converters; + +namespace InstaSharper.Helpers +{ + public static class ConvertersHelper + { + public static IConvertersFabric GetDefaultFabric() + { + return ConvertersFabric.Instance; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Helpers/CryptoHelper.cs b/InstaSharper/Helpers/CryptoHelper.cs index e795c840..9d68df70 100644 --- a/InstaSharper/Helpers/CryptoHelper.cs +++ b/InstaSharper/Helpers/CryptoHelper.cs @@ -6,14 +6,14 @@ namespace InstaSharper.Helpers { - internal class CryptoHelper + internal static class CryptoHelper { - public static string ByteToString(byte[] buff) + private static string ByteToString(byte[] buff) { return buff.Aggregate("", (current, item) => current + item.ToString("X2")); } - public static string Base64Encode(string plainText) + private static string Base64Encode(string plainText) { var plainTextBytes = Encoding.UTF8.GetBytes(plainText); return Convert.ToBase64String(plainTextBytes); @@ -78,7 +78,7 @@ public static string CalculateHash(string key, string message) .Aggregate((a, b) => string.Format("{0}{1}", a, b)); } - public static byte[] GetHash(byte[] bytes) + private static byte[] GetHash(byte[] bytes) { using (var hash = SHA256.Create()) { @@ -86,7 +86,7 @@ public static byte[] GetHash(byte[] bytes) } } - public static byte[] ByteConcat(byte[] left, byte[] right) + private static byte[] ByteConcat(byte[] left, byte[] right) { if (null == left) return right; diff --git a/InstaSharper/Helpers/DateTimeHelper.cs b/InstaSharper/Helpers/DateTimeHelper.cs index f7332585..af08c90d 100644 --- a/InstaSharper/Helpers/DateTimeHelper.cs +++ b/InstaSharper/Helpers/DateTimeHelper.cs @@ -20,8 +20,13 @@ public static DateTime UnixTimestampToDateTime(double unixTime) public static DateTime UnixTimestampToDateTime(string unixTime) { - var time = (long) Convert.ToDouble(unixTime); - return time.FromUnixTimeSeconds(); + if (unixTime.Length <= 10) //1521208323 ( valid until 20-11-2286 @ 5:46pm (UTC)) + { + var time = (long) Convert.ToDouble(unixTime); + return time.FromUnixTimeSeconds(); + } + + return UnixTimestampMilisecondsToDateTime(unixTime); } public static DateTime UnixTimestampMilisecondsToDateTime(string unixTime) @@ -65,5 +70,11 @@ public static long ToUnixTime(this DateTime date) return 0; } } + + public static long GetUnixTimestampSeconds() + { + var timeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0); + return (long) timeSpan.TotalSeconds; + } } } \ No newline at end of file diff --git a/InstaSharper/Helpers/DictionaryExtensions.cs b/InstaSharper/Helpers/DictionaryExtensions.cs new file mode 100644 index 00000000..ae0658a1 --- /dev/null +++ b/InstaSharper/Helpers/DictionaryExtensions.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; + +namespace InstaSharper.Helpers +{ + internal static class DictionaryExtensions + { + public static string AsQueryString(this Dictionary parameters) + { + if (!parameters.Any()) + return ""; + + var builder = new StringBuilder("?"); + + var separator = ""; + foreach (var kvp in parameters.Where(kvp => kvp.Value != null)) + { + builder.AppendFormat("{0}{1}={2}", separator, WebUtility.UrlEncode(kvp.Key), + WebUtility.UrlEncode(kvp.Value)); + separator = "&"; + } + + return builder.ToString(); + } + } +} \ No newline at end of file diff --git a/InstaSharper/Helpers/ErrorHandlingHelper.cs b/InstaSharper/Helpers/ErrorHandlingHelper.cs index d0a84465..efb9786a 100644 --- a/InstaSharper/Helpers/ErrorHandlingHelper.cs +++ b/InstaSharper/Helpers/ErrorHandlingHelper.cs @@ -11,14 +11,23 @@ internal static BadStatusResponse GetBadStatusFromJsonString(string json) var badStatus = new BadStatusResponse(); try { - if (json == "Oops, an error occurred\n") + if (string.IsNullOrEmpty(json)) + { + badStatus.ErrorType = "Unknown"; + badStatus.Message = "No info about error received from IG"; + } + else if (json.Contains("Oops, an error occurred")) + { + badStatus.ErrorType = "IG server reported error"; badStatus.Message = json; + } else badStatus = JsonConvert.DeserializeObject(json); } catch (Exception ex) { badStatus.Message = ex.Message; } + return badStatus; } } diff --git a/InstaSharper/Helpers/HttpExtensions.cs b/InstaSharper/Helpers/HttpExtensions.cs new file mode 100644 index 00000000..08e7a929 --- /dev/null +++ b/InstaSharper/Helpers/HttpExtensions.cs @@ -0,0 +1,31 @@ +using System; +using System.Web; + +namespace InstaSharper.Helpers +{ + public static class HttpExtensions + { + public static Uri AddQueryParameter(this Uri uri, string name, string value) + { + var httpValueCollection = HttpUtility.ParseQueryString(uri.Query); + + httpValueCollection.Remove(name); + httpValueCollection.Add(name, value); + + var ub = new UriBuilder(uri) {Query = httpValueCollection.ToString()}; + return ub.Uri; + } + + public static Uri AddQueryParameterIfNotEmpty(this Uri uri, string name, string value) + { + if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value)) + return uri; + + var httpValueCollection = HttpUtility.ParseQueryString(uri.Query); + httpValueCollection.Remove(name); + httpValueCollection.Add(name, value); + var ub = new UriBuilder(uri) {Query = httpValueCollection.ToString()}; + return ub.Uri; + } + } +} \ No newline at end of file diff --git a/InstaSharper/Helpers/HttpHelper.cs b/InstaSharper/Helpers/HttpHelper.cs index 7b4318d6..a8c10b92 100644 --- a/InstaSharper/Helpers/HttpHelper.cs +++ b/InstaSharper/Helpers/HttpHelper.cs @@ -8,7 +8,7 @@ namespace InstaSharper.Helpers { - internal class HttpHelper + internal static class HttpHelper { public static HttpRequestMessage GetDefaultRequest(HttpMethod method, Uri uri, AndroidDevice deviceInfo) { diff --git a/InstaSharper/Helpers/InstaApiHelper.cs b/InstaSharper/Helpers/InstaApiHelper.cs index 2fc95bd9..dddf2561 100644 --- a/InstaSharper/Helpers/InstaApiHelper.cs +++ b/InstaSharper/Helpers/InstaApiHelper.cs @@ -12,6 +12,7 @@ public static string GetCodeFromId(long id) id = (id - remainder) / 64; code = alphabet[remainder] + code; } + return code; } } diff --git a/InstaSharper/Helpers/SerializationHelper.cs b/InstaSharper/Helpers/SerializationHelper.cs index 8907798d..d4deec2d 100644 --- a/InstaSharper/Helpers/SerializationHelper.cs +++ b/InstaSharper/Helpers/SerializationHelper.cs @@ -3,7 +3,7 @@ namespace InstaSharper.Helpers { - internal class SerializationHelper + internal static class SerializationHelper { public static MemoryStream SerializeToStream(object o) { diff --git a/InstaSharper/Helpers/UriCreator.cs b/InstaSharper/Helpers/UriCreator.cs index 91b23f16..87e04625 100644 --- a/InstaSharper/Helpers/UriCreator.cs +++ b/InstaSharper/Helpers/UriCreator.cs @@ -1,10 +1,12 @@ -using System; +using System; +using System.Collections.Generic; +using System.Threading; using InstaSharper.API; using InstaSharper.Classes.Models; namespace InstaSharper.Helpers { - internal class UriCreator + internal static class UriCreator { private static readonly Uri BaseInstagramUri = new Uri(InstaApiConstants.INSTAGRAM_URL); @@ -16,6 +18,26 @@ public static Uri GetMediaUri(string mediaId) : null; } + public static Uri GetSearchTagUri(string tag, int count, IEnumerable excludeList, string rankToken) + { + excludeList = excludeList ?? new List(); + var excludeListStr = $"[{string.Join(",", excludeList)}]"; + if (!Uri.TryCreate(BaseInstagramUri, + string.Format(InstaApiConstants.SEARCH_TAGS, tag, count), + out var instaUri)) + throw new Exception("Cant create search tag URI"); + return instaUri + .AddQueryParameter("exclude_list", excludeListStr) + .AddQueryParameter("rank_token", rankToken); + } + + public static Uri GetTagInfoUri(string tag) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_TAG_INFO, tag), out var instaUri)) + throw new Exception("Cant create tag info URI"); + return instaUri; + } + public static Uri GetUserUri(string username) { if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.SEARCH_USERS, out var instaUri)) @@ -24,17 +46,44 @@ public static Uri GetUserUri(string username) return userUriBuilder.Uri; } - public static Uri GetUserFeedUri() + public static Uri GetUserInfoByIdUri(long pk) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_INFO_BY_ID, pk), + out var instaUri)) + throw new Exception("Cant create user info by identifier URI"); + return instaUri; + } + + public static Uri GetUserInfoByUsernameUri(string username) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_INFO_BY_USERNAME, username), + out var instaUri)) + throw new Exception("Cant create user info by username URI"); + return instaUri; + } + + public static Uri GetUserFeedUri(string maxId = "") { if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.TIMELINEFEED, out var instaUri)) throw new Exception("Cant create timeline feed URI"); - return instaUri; + return !string.IsNullOrEmpty(maxId) + ? new UriBuilder(instaUri) {Query = $"max_id={maxId}"}.Uri + : instaUri; } - public static Uri GetUserMediaListUri(string userPk) + public static Uri GetUserMediaListUri(long userPk, string nextId = "") { if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.USEREFEED + userPk, out var instaUri)) throw new Exception("Cant create URI for user media retrieval"); + return !string.IsNullOrEmpty(nextId) + ? new UriBuilder(instaUri) {Query = $"max_id={nextId}"}.Uri + : instaUri; + } + + public static Uri GetCreateAccountUri() + { + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.ACCOUNTS_CREATE, out var instaUri)) + throw new Exception("Cant create URI for user creation"); return instaUri; } @@ -44,20 +93,39 @@ public static Uri GetLoginUri() throw new Exception("Cant create URI for user login"); return instaUri; } + + public static Uri GetResetChallengeUri(string token) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.RESET_CHALLENGE, token), out var instaUri)) + throw new Exception("Cant create URI for challenge reset"); + return instaUri; + } + + public static Uri GetVerifyMethod(string token) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.VERIFY_METHOD, token), out var instaUri)) + throw new Exception("Cant create URI for challenge verify method"); + return instaUri; + } + + public static Uri GetFbSearchPlace(int count, string rankToken, string searchQuery) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.FB_SEARCH_PLACE, count, searchQuery, rankToken), out var instaUri)) + throw new Exception("Cant create URI for fb search place"); + return instaUri; + } - public static Uri GetTimelineWithMaxIdUri(string nextId) + public static Uri GetTwoFactorLoginUri() { - if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.TIMELINEFEED, out var instaUri)) - throw new Exception("Cant create search URI for timeline"); - var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}; - return uriBuilder.Uri; + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.ACCOUNTS_2FA_LOGIN, out var instaUri)) + throw new Exception("Cant create URI for user 2FA login"); + return instaUri; } - public static Uri GetMediaListWithMaxIdUri(string userPk, string nextId) + public static Uri GetTimelineWithMaxIdUri(string nextId) { - if ( - !Uri.TryCreate(new Uri(InstaApiConstants.INSTAGRAM_URL), InstaApiConstants.USEREFEED + userPk, - out var instaUri)) throw new Exception("Cant create URI for media list"); + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.TIMELINEFEED, out var instaUri)) + throw new Exception("Cant create search URI for timeline"); var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}; return uriBuilder.Uri; } @@ -69,31 +137,33 @@ public static Uri GetCurrentUserUri() return instaUri; } - internal static Uri GetUserFollowersUri(string userPk, string rankToken, string maxId = "") + public static Uri GetUserFollowersUri(long userPk, string rankToken, string searchQuery, string maxId = "") { - if ( - !Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_FOLLOWERS, userPk, rankToken), - out var instaUri)) throw new Exception("Cant create URI for user followers"); - if (string.IsNullOrEmpty(maxId)) return instaUri; - var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={maxId}"}; - return uriBuilder.Uri; + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_FOLLOWERS, userPk, rankToken), + out var instaUri)) + throw new Exception("Cant create URI for user followers"); + return instaUri + .AddQueryParameterIfNotEmpty("max_id", maxId) + .AddQueryParameterIfNotEmpty("query", searchQuery); } - internal static Uri GetUserFollowingUri(string userPk, string rankToken, string maxId = "") + public static Uri GetUserFollowingUri(long userPk, string rankToken, string searchQuery, string maxId = "") { - if ( - !Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_FOLLOWING, userPk, rankToken), - out var instaUri)) throw new Exception("Cant create URI for user following"); - if (string.IsNullOrEmpty(maxId)) return instaUri; - var uriBuilder = new UriBuilder(instaUri) {Query = $"max_id={maxId}"}; - return uriBuilder.Uri; + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_FOLLOWING, userPk, rankToken), + out var instaUri)) + throw new Exception("Cant create URI for user following"); + return instaUri + .AddQueryParameterIfNotEmpty("max_id", maxId) + .AddQueryParameterIfNotEmpty("query", searchQuery); } - public static Uri GetTagFeedUri(string tag) + public static Uri GetTagFeedUri(string tag, string maxId = "") { if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_TAG_FEED, tag), out var instaUri)) throw new Exception("Cant create URI for discover tag feed"); - return instaUri; + return !string.IsNullOrEmpty(maxId) + ? new UriBuilder(instaUri) {Query = $"max_id={maxId}"}.Uri + : instaUri; } public static Uri GetLogoutUri() @@ -113,12 +183,43 @@ public static Uri GetExploreUri(string maxId = null) return uriBuilder.Uri; } - public static Uri GetDirectSendMessageUri() + public static Uri GetDirectSendTextMessageUri() { if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.GET_DIRECT_TEXT_BROADCAST, out var instaUri)) throw new Exception("Cant create URI for sending message"); return instaUri; } + + public static Uri GetDirectSendLinkMessageUri() + { + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.GET_DIRECT_LINK_BROADCAST, out var instaUri)) + throw new Exception("Cant create URI for sending link as a message"); + return instaUri; + } + + public static Uri GetShareMediaUri(InstaMediaType mediaType) + { + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.GET_DIRECT_MEDIA_SHARE_BROADCAST, out var instaUri)) + throw new Exception("Cant create URI for sending media share"); + var query = mediaType == InstaMediaType.Image ? "media_type=photo" : "media_type=video"; + var uriBuilder = new UriBuilder(instaUri) {Query = query}; + return uriBuilder.Uri; + } + + public static Uri GetApproveThreadUri(string threadId) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_DIRECT_APPROVE_THREAD, threadId), + out var instaUri)) + throw new Exception("Cant create URI for user following"); + return instaUri; + } + + public static Uri GetDeclineAllPendingThreadsUri() + { + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.GET_DIRECT_DECLINE_ALL, out var instaUri)) + throw new Exception("Cant create URI for get inbox"); + return instaUri; + } public static Uri GetDirectInboxUri() { @@ -135,13 +236,13 @@ public static Uri GetDirectInboxThreadUri(string threadId) return instaUri; } - public static Uri GetUserTagsUri(string userPk, string rankToken, string maxId = null) + public static Uri GetUserTagsUri(long userPk, string rankToken, string maxId = null) { if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_USER_TAGS, userPk), out var instaUri)) throw new Exception("Cant create URI for get user tags"); var query = $"rank_token={rankToken}&ranked_content=true"; - if (!string.IsNullOrEmpty(maxId)) query += $"max_id={maxId}"; + if (!string.IsNullOrEmpty(maxId)) query += $"&max_id={maxId}"; var uriBuilder = new UriBuilder(instaUri) {Query = query}; return uriBuilder.Uri; } @@ -195,12 +296,14 @@ public static Uri GetLikeMediaUri(string mediaId) return instaUri; } - public static Uri GetMediaCommentsUri(string mediaId) + public static Uri GetMediaCommentsUri(string mediaId, string nextId = "") { if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.MEDIA_COMMENTS, mediaId), out var instaUri)) throw new Exception("Cant create URI for getting media comments"); - return instaUri; + return !string.IsNullOrEmpty(nextId) + ? new UriBuilder(instaUri) {Query = $"max_id={nextId}"}.Uri + : instaUri; } public static Uri GetMediaLikersUri(string mediaId) @@ -227,6 +330,24 @@ public static Uri GetUnFollowUserUri(long userId) return instaUri; } + + public static Uri GetBlockUserUri(long userId) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.BLOCK_USER, userId), + out var instaUri)) + throw new Exception("Cant create URI for getting media likers"); + return instaUri; + } + + public static Uri GetUnBlockUserUri(long userId) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.UNBLOCK_USER, userId), + out var instaUri)) + throw new Exception("Cant create URI for getting media likers"); + return instaUri; + } + + public static Uri GetUriSetAccountPrivate() { if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.SET_ACCOUNT_PRIVATE, out var instaUri)) @@ -276,6 +397,14 @@ public static Uri GetDeleteCommetUri(string mediaId, string commentId) return instaUri; } + public static Uri GetUploadVideoUri() + { + if ( + !Uri.TryCreate(BaseInstagramUri, InstaApiConstants.UPLOAD_VIDEO, out var instaUri)) + throw new Exception("Cant create URI for upload video"); + return instaUri; + } + public static Uri GetUploadPhotoUri() { if ( @@ -292,6 +421,14 @@ public static Uri GetMediaConfigureUri() return instaUri; } + public static Uri GetMediaAlbumConfigureUri() + { + if ( + !Uri.TryCreate(BaseInstagramUri, InstaApiConstants.MEDIA_ALBUM_CONFIGURE, out var instaUri)) + throw new Exception("Cant create URI for configuring media album"); + return instaUri; + } + public static Uri GetStoryFeedUri() { if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.GET_STORY_TRAY, out var instaUri)) @@ -362,5 +499,61 @@ public static Uri GetUserReelFeedUri(long userId) throw new Exception("Can't create URI for getting user reel feed"); return instaUri; } + + public static Uri GetCollectionUri(long collectionId) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_COLLECTION, collectionId), + out var instaUri)) + throw new Exception("Can't create URI for getting collection"); + return instaUri; + } + + public static Uri GetEditCollectionUri(long collectionId) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.EDIT_COLLECTION, collectionId), + out var instaUri)) + throw new Exception("Can't create URI for editing collection"); + return instaUri; + } + + public static Uri GetCollectionsUri() + { + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.GET_LIST_COLLECTIONS, + out var instaUri)) + throw new Exception("Can't create URI for getting collections"); + return instaUri; + } + + public static Uri GetCreateCollectionUri() + { + if (!Uri.TryCreate(BaseInstagramUri, InstaApiConstants.CREATE_COLLECTION, + out var instaUri)) + throw new Exception("Can't create URI for creating collection"); + return instaUri; + } + + public static Uri GetDeleteCollectionUri(long collectionId) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.DELETE_COLLECTION, collectionId), + out var instaUri)) + throw new Exception("Can't create URI for deleting collection"); + return instaUri; + } + + public static Uri GetMediaIdFromUrlUri(Uri uri) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_MEDIAID, uri.AbsoluteUri), + out var instaUri)) + throw new Exception("Can't create URI for getting media id"); + return instaUri; + } + + public static Uri GetShareLinkFromMediaId(string mediaId) + { + if (!Uri.TryCreate(BaseInstagramUri, string.Format(InstaApiConstants.GET_SHARE_LINK, mediaId), + out var instaUri)) + throw new Exception("Can't create URI for getting share link"); + return instaUri; + } } } \ No newline at end of file diff --git a/InstaSharper/InstaSharper.csproj b/InstaSharper/InstaSharper.csproj index 315e2df4..07017d6f 100644 --- a/InstaSharper/InstaSharper.csproj +++ b/InstaSharper/InstaSharper.csproj @@ -2,39 +2,45 @@ 1.2.6 - netstandard2.0;net452 True InstaSharper InstaSharper - 2.0 + 2.1 false false false True - 1.3.0 - 1.3.0 - 1.3.0 + 1.4.0 + 1.4.0 + 1.4.0 Private API for Instagram + + + netstandard2.1 + + + netstandard2.1;net452;net472 + - + - + + - + + - - ..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Windows.Forms.dll - + diff --git a/InstaSharper/Logger/LogLevel.cs b/InstaSharper/Logger/LogLevel.cs index c1ba3284..d3eb77b5 100644 --- a/InstaSharper/Logger/LogLevel.cs +++ b/InstaSharper/Logger/LogLevel.cs @@ -2,10 +2,11 @@ { public enum LogLevel { - Exceptions = 0, - Info = 1, - Request = 2, - Response = 3, - All = 4 + None = 0, + Exceptions = 1, + Info = 2, + Request = 3, + Response = 4, + All = 5 } } \ No newline at end of file diff --git a/README.md b/README.md index d9891645..e1d3e8ed 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,23 @@ # InstagramApi [InstaSharper] Tokenless, butthurtless private API for Instagram. Get account information, media, explore tags and user feed without any applications and other crap. +## Development of this project postponed + +### Before posting new issues: [Demo samples](https://github.com/a-legotin/InstaSharper/tree/develop/InstaSharper.Examples), [Tests project](https://github.com/a-legotin/InstaSharper/tree/develop/InstaSharper.Tests/Endpoints) and [Wiki page](https://github.com/a-legotin/InstaSharper/wiki/How-to-use-library-features) + Note that: there is a simple [Instagram API](https://github.com/a-legotin/InstagramAPI-Web) based on web-version of Instagram. This repository based on Instagram API for mobile devices. [![Build status](https://ci.appveyor.com/api/projects/status/6os0fhi1awbplbka?svg=true)](https://ci.appveyor.com/project/a-legotin/instasharper) -[![Build Status](https://travis-ci.org/a-legotin/InstaSharper.svg?branch=master)](https://travis-ci.org/a-legotin/InstaSharper) -[![Telegram chat](https://img.shields.io/badge/telegram-channel-blue.svg)](https://t.me/instasharper) +[![Build status](https://travis-ci.org/a-legotin/InstaSharper.svg?branch=master)](https://travis-ci.org/a-legotin/InstaSharper) +[![NuGet](https://img.shields.io/nuget/v/InstaSharper.svg)](https://www.nuget.org/packages/InstaSharper/) +[![MyGet](https://img.shields.io/myget/a-legotin/v/instasharper-develop.svg)](https://www.myget.org/feed/Details/instasharper-develop) [![GitHub stars](https://img.shields.io/github/stars/a-legotin/InstaSharper.svg)](https://github.com/a-legotin/InstaSharper/stargazers) -#### Current version: 1.3.0 [Stable], 1.4.0 [Under development] +#### Current version: 1.4.0 [Stable], 1.5.0 [Under development] ## Overview -This project intends to provide all the features available in the Instagram API up to 12.0.0.7.91. It is being developed in C# for .NET Framework 4.5.2 and .NET Standart 2.0 +This project intends to provide all the features available in the Instagram API up to 12.0.0.7.91. It is being developed in C# for .NET Framework 4.5.2 and .NET Standard 2.0 + #### This repository is provided for reference purposes only. * Please note that this project is still in design and development phase; the libraries may suffer major changes even at the interface level, so don't rely (yet) in this software for production uses. * @@ -23,7 +29,7 @@ Build with dotnet core. Can be used on Mac, Linux, Windows. Use library as dll, reference from [nuget](https://www.nuget.org/packages/InstaSharper/) or clone source code. Pre-release version available at [myget feed](https://www.myget.org/feed/Details/instasharper-develop) together with [symbols](https://www.myget.org/F/instasharper-develop/symbols/) -##Features +## Features Currently the library supports following coverage of the following Instagram APIs: @@ -31,6 +37,7 @@ Currently the library supports following coverage of the following Instagram API - [x] Login - [x] Logout +- [x] Create new account - [x] Get user explore feed - [x] Get user timeline feed - [x] Get all user media by username @@ -58,13 +65,16 @@ Currently the library supports following coverage of the following Instagram API - [x] Send comment - [x] Delete comment - [x] Upload photo +- [x] Upload video - [x] Get followings list - [x] Delete media (photo/video) - [x] Upload story (photo) - [x] Change password - [x] Send direct message +- [x] Search location +- [x] Get location feed +- [x] Collection create/get by id/get all/add items -###### for more details please check [Project roadmap](https://github.com/a-legotin/InstaSharper/wiki/Project-roadmap/_edit) ## Easy to use #### Use builder to get Insta API instance: @@ -120,7 +130,13 @@ IResult postResult = await apiInstance.CommentMediaAsync("1234567891234567 [ADeltaX](https://github.com/ADeltaX) for contribution -[mgp25](https://github.com/mgp25) and his [php wrapper](https://github.com/mgp25/Instagram-API/) for providing us with device id +[vitalragaz](https://github.com/vitalragaz) for contribution + +[n0ise9914](https://github.com/n0ise9914) for contribution + +[Ramtinak](https://github.com/ramtinak) for contribution + +[mgp25](https://github.com/mgp25) and his [php wrapper](https://github.com/mgp25/Instagram-API/) # License diff --git a/appveyor.yml b/appveyor.yml index 9e35819e..7ba8b495 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ -version: 1.3.{build} -os: Previous Visual Studio 2017 +version: 1.4.{build} +os: Previous Visual Studio 2019 platform: Any CPU configuration: Release diff --git a/assets/.gitignore b/assets/.gitignore new file mode 100644 index 00000000..5a0279ee --- /dev/null +++ b/assets/.gitignore @@ -0,0 +1,3 @@ +* +*/ +!.gitignore* \ No newline at end of file diff --git a/assets/image.jpg b/assets/image.jpg new file mode 100644 index 00000000..d1ab539a Binary files /dev/null and b/assets/image.jpg differ diff --git a/assets/video.mp4 b/assets/video.mp4 new file mode 100644 index 00000000..09e3b80b Binary files /dev/null and b/assets/video.mp4 differ diff --git a/assets/video_image.jpg b/assets/video_image.jpg new file mode 100644 index 00000000..f8b6bb21 Binary files /dev/null and b/assets/video_image.jpg differ