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/InstaSharper.Examples/InstaSharper.Examples.csproj b/InstaSharper.Examples/InstaSharper.Examples.csproj
index 02341bb4..2cb95bf7 100644
--- a/InstaSharper.Examples/InstaSharper.Examples.csproj
+++ b/InstaSharper.Examples/InstaSharper.Examples.csproj
@@ -34,7 +34,7 @@
4
-
+
False
..\InstaSharper\bin\release\net452\InstaSharper.dll
@@ -52,10 +52,12 @@
+
+
diff --git a/InstaSharper.Examples/Program.cs b/InstaSharper.Examples/Program.cs
index 724504e0..b5c11fb3 100644
--- a/InstaSharper.Examples/Program.cs
+++ b/InstaSharper.Examples/Program.cs
@@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Threading.Tasks;
using InstaSharper.API;
using InstaSharper.API.Builder;
using InstaSharper.Classes;
-using InstaSharper.Classes.Android.DeviceInfo;
using InstaSharper.Examples.Samples;
using InstaSharper.Logger;
@@ -34,52 +34,79 @@ public static async Task MainAsync()
var userSession = new UserSessionData
{
UserName = "username",
- Password = "password"
+ Password = "password"
};
// create new InstaApi instance using Builder
- var device = AndroidDeviceGenerator.GetByName(AndroidDevices.SAMSUNG_NOTE3);
- var requestMessage = ApiRequestMessage.FromDevice(device);
_instaApi = InstaApiBuilder.CreateBuilder()
.SetUser(userSession)
- .SetApiRequestMessage(requestMessage)
- .UseLogger(new DebugLogger(LogLevel.Info)) // use logger for requests and debug messages
+ .UseLogger(new DebugLogger(LogLevel.Exceptions)) // use logger for requests and debug messages
.SetRequestDelay(TimeSpan.FromSeconds(2))
.Build();
- // login
- Console.WriteLine($"Logging in as {userSession.UserName}");
- var logInResult = await _instaApi.LoginAsync();
- if (!logInResult.Succeeded)
+
+ const string stateFile = "state.bin";
+ try
{
- Console.WriteLine($"Unable to login: {logInResult.Info.Message}");
+ if (File.Exists(stateFile))
+ {
+ Console.WriteLine("Loading state from file");
+ Stream fs = File.OpenRead(stateFile);
+ fs.Seek(0, SeekOrigin.Begin);
+ _instaApi.LoadStateDataFromStream(fs);
+ }
}
- else
+ catch (Exception e)
{
- Console.WriteLine("Press 1 to start basic demo samples");
- Console.WriteLine("Press 2 to start upload photo demo sample");
- Console.WriteLine("Press 3 to start comment media demo sample");
- Console.WriteLine("Press 4 to start stories demo sample");
- Console.WriteLine("Press 5 to start demo with saving state of API instance");
- Console.WriteLine("Press 6 to start messaging demo sample");
+ Console.WriteLine(e);
+ }
- var samplesMap = new Dictionary
+ if (!_instaApi.IsUserAuthenticated)
+ {
+ // login
+ Console.WriteLine($"Logging in as {userSession.UserName}");
+ var logInResult = await _instaApi.LoginAsync();
+ if (!logInResult.Succeeded)
{
- [ConsoleKey.D1] = new Basics(_instaApi),
- [ConsoleKey.D2] = new UploadPhoto(_instaApi),
- [ConsoleKey.D3] = new CommentMedia(_instaApi),
- [ConsoleKey.D4] = new Stories(_instaApi),
- [ConsoleKey.D5] = new SaveLoadState(_instaApi),
- [ConsoleKey.D6] = new Messaging(_instaApi)
- };
- var key = Console.ReadKey();
- Console.WriteLine(Environment.NewLine);
- if (samplesMap.ContainsKey(key.Key))
- await samplesMap[key.Key].DoShow();
- Console.WriteLine("Done. Press esc key to exit...");
-
- key = Console.ReadKey();
- return key.Key == ConsoleKey.Escape;
+ Console.WriteLine($"Unable to login: {logInResult.Info.Message}");
+ return false;
+ }
+ }
+ var state = _instaApi.GetStateDataAsStream();
+ using (var fileStream = File.Create(stateFile))
+ {
+ state.Seek(0, SeekOrigin.Begin);
+ state.CopyTo(fileStream);
}
+
+ Console.WriteLine("Press 1 to start basic demo samples");
+ Console.WriteLine("Press 2 to start upload photo demo sample");
+ Console.WriteLine("Press 3 to start comment media demo sample");
+ Console.WriteLine("Press 4 to start stories demo sample");
+ Console.WriteLine("Press 5 to start demo with saving state of API instance");
+ Console.WriteLine("Press 6 to start messaging demo sample");
+ Console.WriteLine("Press 7 to start location demo sample");
+ Console.WriteLine("Press 8 to start collections demo sample");
+
+ var samplesMap = new Dictionary
+ {
+ [ConsoleKey.D1] = new Basics(_instaApi),
+ [ConsoleKey.D2] = new UploadPhoto(_instaApi),
+ [ConsoleKey.D3] = new CommentMedia(_instaApi),
+ [ConsoleKey.D4] = new Stories(_instaApi),
+ [ConsoleKey.D5] = new SaveLoadState(_instaApi),
+ [ConsoleKey.D6] = new Messaging(_instaApi),
+ [ConsoleKey.D7] = new LocationSample(_instaApi),
+ [ConsoleKey.D8] = new CollectionSample(_instaApi)
+
+ };
+ var key = Console.ReadKey();
+ Console.WriteLine(Environment.NewLine);
+ if (samplesMap.ContainsKey(key.Key))
+ await samplesMap[key.Key].DoShow();
+ Console.WriteLine("Done. Press esc key to exit...");
+
+ key = Console.ReadKey();
+ return key.Key == ConsoleKey.Escape;
}
catch (Exception ex)
{
@@ -87,8 +114,9 @@ public static async Task MainAsync()
}
finally
{
- var logoutResult = Task.Run(() => _instaApi.LogoutAsync()).GetAwaiter().GetResult();
- if (logoutResult.Succeeded) Console.WriteLine("Logout succeed");
+ // perform that if user needs to logged out
+ // var logoutResult = Task.Run(() => _instaApi.LogoutAsync()).GetAwaiter().GetResult();
+ // if (logoutResult.Succeeded) Console.WriteLine("Logout succeed");
}
return false;
}
diff --git a/InstaSharper.Examples/Samples/Basics.cs b/InstaSharper.Examples/Samples/Basics.cs
index bcb21e24..a3624496 100644
--- a/InstaSharper.Examples/Samples/Basics.cs
+++ b/InstaSharper.Examples/Samples/Basics.cs
@@ -2,6 +2,7 @@
using System.Linq;
using System.Threading.Tasks;
using InstaSharper.API;
+using InstaSharper.Classes;
using InstaSharper.Examples.Utils;
namespace InstaSharper.Examples.Samples
@@ -27,16 +28,19 @@ public async Task DoShow()
Console.WriteLine(
$"Logged in: username - {currentUser.Value.UserName}, full name - {currentUser.Value.FullName}");
- // get self followers
- var followers = await _instaApi.GetUserFollowersAsync(currentUser.Value.UserName, 5);
- Console.WriteLine($"Count of followers [{currentUser.Value.UserName}]:{followers.Value.Count}");
+ // get followers of user 'elonmusk'
+ var followers = await _instaApi.GetUserFollowersAsync("elonmusk",
+ PaginationParameters.MaxPagesToLoad(5)
+ .StartFromId("AQAC8w90POWyM7zMjHWmO9vsZNL_TuLp6FR506_C_y3fUAjlCclrIDI2RdSGvur5UjLrq4Cq7NJN8QUhHG-vpbT6pCLB5X9crDxBOHUEuNJ4fA"));
+ Console.WriteLine($"Count of followers [elonmusk]:{followers.Value.Count}");
+ Console.WriteLine($"Next id will be: '{followers.Value.NextId}'");
// get self folling
- var following = await _instaApi.GetUserFollowingAsync(currentUser.Value.UserName, 5);
+ var following = await _instaApi.GetUserFollowingAsync(currentUser.Value.UserName, PaginationParameters.MaxPagesToLoad(5));
Console.WriteLine($"Count of following [{currentUser.Value.UserName}]:{following.Value.Count}");
// get self user's media, latest 5 pages
- var currentUserMedia = await _instaApi.GetUserMediaAsync(currentUser.Value.UserName, 5);
+ var currentUserMedia = await _instaApi.GetUserMediaAsync(currentUser.Value.UserName, PaginationParameters.MaxPagesToLoad(5));
if (currentUserMedia.Succeeded)
{
Console.WriteLine($"Media count [{currentUser.Value.UserName}]: {currentUserMedia.Value.Count}");
@@ -45,7 +49,7 @@ public async Task DoShow()
}
//get user time line feed, latest 5 pages
- var userFeed = await _instaApi.GetUserTimelineFeedAsync(5);
+ var userFeed = await _instaApi.GetUserTimelineFeedAsync(PaginationParameters.MaxPagesToLoad(5));
if (userFeed.Succeeded)
{
Console.WriteLine(
@@ -62,7 +66,7 @@ public async Task DoShow()
}
// get tag feed, latest 5 pages
- var tagFeed = await _instaApi.GetTagFeedAsync("quadcopter", 5);
+ var tagFeed = await _instaApi.GetTagFeedAsync("quadcopter", PaginationParameters.MaxPagesToLoad(5));
if (tagFeed.Succeeded)
{
Console.WriteLine(
diff --git a/InstaSharper.Examples/Samples/CollectionSample.cs b/InstaSharper.Examples/Samples/CollectionSample.cs
new file mode 100644
index 00000000..210f9fb1
--- /dev/null
+++ b/InstaSharper.Examples/Samples/CollectionSample.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Threading.Tasks;
+using InstaSharper.API;
+
+namespace InstaSharper.Examples.Samples
+{
+ internal class CollectionSample : IDemoSample
+ {
+ private readonly IInstaApi _instaApi;
+
+ public CollectionSample(IInstaApi instaApi)
+ {
+ _instaApi = instaApi;
+ }
+
+ public async Task DoShow()
+ {
+ // get all collections of current user
+ var collections = await _instaApi.GetCollectionsAsync();
+ Console.WriteLine($"Loaded {collections.Value.Items.Count} collections for current user");
+ foreach (var instaCollection in collections.Value.Items)
+ {
+ Console.WriteLine($"Collection: name={instaCollection.CollectionName}, id={instaCollection.CollectionId}");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/InstaSharper.Examples/Samples/LocationSample.cs b/InstaSharper.Examples/Samples/LocationSample.cs
new file mode 100644
index 00000000..ed67743e
--- /dev/null
+++ b/InstaSharper.Examples/Samples/LocationSample.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using InstaSharper.API;
+using InstaSharper.Classes;
+
+namespace InstaSharper.Examples.Samples
+{
+ internal class LocationSample : IDemoSample
+ {
+ private readonly IInstaApi _instaApi;
+
+ public LocationSample(IInstaApi instaApi)
+ {
+ _instaApi = instaApi;
+ }
+
+ public async Task DoShow()
+ {
+ // search for related locations near location with latitude = 55.753923, logitude = 37.620940
+ // additionaly you can specify search query or just empty string
+ var result = await _instaApi.SearchLocation(55.753923, 37.620940, "square");
+ Console.WriteLine($"Loaded {result.Value.Count} locations");
+ var firstLocation = result.Value?.FirstOrDefault();
+ if(firstLocation == null)
+ return;
+ Console.WriteLine($"Loading feed for location: name={firstLocation.Name}; id={firstLocation.ExternalId}.");
+
+ var locationFeed =
+ await _instaApi.GetLocationFeed(long.Parse(firstLocation.ExternalId), PaginationParameters.MaxPagesToLoad(5));
+
+ Console.WriteLine(locationFeed.Succeeded
+ ? $"Loaded {locationFeed.Value.Medias?.Count} medias for location, total location medias: {locationFeed.Value.MediaCount}"
+ : $"Unable to load location '{firstLocation.Name}' feed");
+ }
+ }
+}
\ No newline at end of file
diff --git a/InstaSharper.Examples/Samples/Messaging.cs b/InstaSharper.Examples/Samples/Messaging.cs
index ac68eb2c..d7d353a7 100644
--- a/InstaSharper.Examples/Samples/Messaging.cs
+++ b/InstaSharper.Examples/Samples/Messaging.cs
@@ -22,8 +22,8 @@ public async Task DoShow()
Console.WriteLine("Unable to get ranked recipients");
return;
}
- Console.WriteLine($"Got {recipientsResult.Value.Items.Count} ranked threads");
- foreach (var thread in recipientsResult.Value.Items)
+ Console.WriteLine($"Got {recipientsResult.Value.Threads.Count} ranked threads");
+ foreach (var thread in recipientsResult.Value.Threads)
Console.WriteLine($"Threadname: {thread.ThreadTitle}, users: {thread.Users.Count}");
var inboxThreads = await _instaApi.GetDirectInboxAsync();
@@ -36,9 +36,14 @@ public async Task DoShow()
foreach (var thread in inboxThreads.Value.Inbox.Threads)
Console.WriteLine($"Threadname: {thread.Title}, users: {thread.Users.Count}");
var firstThread = inboxThreads.Value.Inbox.Threads.FirstOrDefault();
+ // send message to specific thread
var sendMessageResult = await _instaApi.SendDirectMessage($"{firstThread.Users.FirstOrDefault()?.Pk}",
firstThread.ThreadId, "test");
Console.WriteLine(sendMessageResult.Succeeded ? "Message sent" : "Unable to send message");
+
+ // just send message to user (thread not specified)
+ sendMessageResult = await _instaApi.SendDirectMessage($"{firstThread.Users.FirstOrDefault()?.Pk}", string.Empty , "one more test");
+ Console.WriteLine(sendMessageResult.Succeeded ? "Message sent" : "Unable to send message");
}
}
}
\ No newline at end of file
diff --git a/InstaSharper.Examples/Samples/SaveLoadState.cs b/InstaSharper.Examples/Samples/SaveLoadState.cs
index 990da146..3430ed01 100644
--- a/InstaSharper.Examples/Samples/SaveLoadState.cs
+++ b/InstaSharper.Examples/Samples/SaveLoadState.cs
@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using InstaSharper.API;
using InstaSharper.API.Builder;
+using InstaSharper.Classes;
namespace InstaSharper.Examples.Samples
{
@@ -25,6 +26,7 @@ public async Task DoShow()
Console.WriteLine($"Got current user: {result.Value.UserName} using existing API instance");
var stream = _instaApi.GetStateDataAsStream();
var anotherInstance = InstaApiBuilder.CreateBuilder()
+ .SetUser(UserSessionData.Empty)
.SetRequestDelay(TimeSpan.FromSeconds(2))
.Build();
anotherInstance.LoadStateDataFromStream(stream);
diff --git a/InstaSharper.Tests/Classes/AuthenticatedTestFixture.cs b/InstaSharper.Tests/Classes/AuthenticatedTestFixture.cs
index e6a3cabd..5f85e717 100644
--- a/InstaSharper.Tests/Classes/AuthenticatedTestFixture.cs
+++ b/InstaSharper.Tests/Classes/AuthenticatedTestFixture.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
using System.Threading.Tasks;
using InstaSharper.API;
using InstaSharper.Classes;
@@ -6,33 +7,48 @@
namespace InstaSharper.Tests.Classes
{
- public class AuthenticatedTestFixture : IDisposable
+ public class AuthenticatedTestFixture
{
private readonly string _password = Environment.GetEnvironmentVariable("instaapiuserpassword");
private readonly string _username = "alex_codegarage";
public AuthenticatedTestFixture()
{
- ApiInstance = TestHelpers.GetDefaultInstaApiInstance(new UserSessionData
+ ApiInstance =
+ TestHelpers.GetDefaultInstaApiInstance(UserSessionData.ForUsername(_username).WithPassword(_password));
+ const string stateFile = "state.bin";
+ try
{
- UserName = _username,
- Password = _password
- });
+ if (File.Exists(stateFile))
+ {
+ Stream fs = File.OpenRead(stateFile);
+ fs.Seek(0, SeekOrigin.Begin);
+ ApiInstance.LoadStateDataFromStream(fs);
+ if (ApiInstance.IsUserAuthenticated)
+ return;
+ }
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
var loginTask = Task.Run(ApiInstance.LoginAsync);
+
if (!loginTask.Wait(TimeSpan.FromSeconds(30)))
throw new Exception($"Unable to login, user: {_username}, password: {_password}.");
+
+ if (!loginTask.Result.Succeeded) return;
+ var state = ApiInstance.GetStateDataAsStream();
+ using (var fileStream = File.Create(stateFile))
+ {
+ state.Seek(0, SeekOrigin.Begin);
+ state.CopyTo(fileStream);
+ }
}
public IInstaApi ApiInstance { get; }
- public void Dispose()
- {
- var logoutTask = Task.Run(ApiInstance.LogoutAsync);
- if (!logoutTask.Wait(TimeSpan.FromSeconds(10)))
- throw new Exception($"Not able to logout, user: {_username}, password: {_password}.");
- }
-
public string GetUsername()
{
return _username;
diff --git a/InstaSharper.Tests/Endpoints/CollectionTest.cs b/InstaSharper.Tests/Endpoints/CollectionTest.cs
new file mode 100644
index 00000000..d5cb2a5c
--- /dev/null
+++ b/InstaSharper.Tests/Endpoints/CollectionTest.cs
@@ -0,0 +1,68 @@
+using InstaSharper.Tests.Classes;
+using Xunit;
+
+namespace InstaSharper.Tests.Endpoints
+{
+ [Trait("Category", "Endpoint")]
+ public class CollectionTest : IClassFixture
+ {
+ public CollectionTest(AuthenticatedTestFixture authInfo)
+ {
+ _authInfo = authInfo;
+ }
+
+ private readonly AuthenticatedTestFixture _authInfo;
+
+ [Theory]
+ [InlineData(17913091552048277)]
+ public async void GetCollectionByIdTest(long collectionId)
+ {
+ Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
+ var media = await _authInfo.ApiInstance.GetCollectionAsync(collectionId);
+ Assert.NotNull(media);
+ }
+
+ [Theory]
+ [InlineData("New collection")]
+ public async void CreateCollectionTest(string collectionName)
+ {
+ Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
+ var newCollection = await _authInfo.ApiInstance.CreateCollectionAsync(collectionName);
+ var collectionList = await _authInfo.ApiInstance.GetCollectionsAsync();
+
+ Assert.NotNull(newCollection.Value);
+ Assert.True(newCollection.Value.CollectionName == collectionName);
+ Assert.NotNull(collectionList.Value);
+ }
+
+ [Theory]
+ [InlineData(17913091552048277)]
+ public async void AddItemsToCollectionTest(long collectionId)
+ {
+ Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
+ var mediaItems = new[] {"1658893120999767931"};
+ var result = await _authInfo.ApiInstance.AddItemsToCollectionAsync(collectionId, mediaItems);
+
+ Assert.True(result.Succeeded);
+ Assert.NotNull(result.Value);
+ Assert.Equal(result.Value.CollectionId, collectionId);
+ }
+
+ [Theory]
+ [InlineData(17913091552048277)]
+ public async void DeleteCollectionTest(long collectionId)
+ {
+ Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
+ var media = await _authInfo.ApiInstance.DeleteCollectionAsync(collectionId);
+ Assert.True(media.Succeeded);
+ }
+
+ [Fact]
+ public async void GetCollectionsTest()
+ {
+ Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
+ var collections = await _authInfo.ApiInstance.GetCollectionsAsync();
+ Assert.NotNull(collections);
+ }
+ }
+}
\ No newline at end of file
diff --git a/InstaSharper.Tests/Endpoints/FeedTest.cs b/InstaSharper.Tests/Endpoints/FeedTest.cs
index 7371f2be..b723aed6 100644
--- a/InstaSharper.Tests/Endpoints/FeedTest.cs
+++ b/InstaSharper.Tests/Endpoints/FeedTest.cs
@@ -1,4 +1,5 @@
using System.Linq;
+using InstaSharper.Classes;
using InstaSharper.Tests.Classes;
using Xunit;
@@ -20,7 +21,7 @@ public async void GetTagFeedTest(string tag)
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
- var result = await _authInfo.ApiInstance.GetTagFeedAsync(tag, 10);
+ var result = await _authInfo.ApiInstance.GetTagFeedAsync(tag, PaginationParameters.MaxPagesToLoad(10));
var tagFeed = result.Value;
var anyMediaDuplicate = tagFeed.Medias.GroupBy(x => x.Code).Any(g => g.Count() > 1);
var anyStoryDuplicate = tagFeed.Stories.GroupBy(x => x.Id).Any(g => g.Count() > 1);
@@ -38,7 +39,7 @@ public async void GetUserTagFeedTest(string username)
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
- var result = await _authInfo.ApiInstance.GetUserTagsAsync(username, 5);
+ var result = await _authInfo.ApiInstance.GetUserTagsAsync(username, PaginationParameters.MaxPagesToLoad(5));
var tagFeed = result.Value;
var anyMediaDuplicate = tagFeed.GroupBy(x => x.Code).Any(g => g.Count() > 1);
//assert
@@ -48,7 +49,6 @@ public async void GetUserTagFeedTest(string username)
}
[Theory]
- [InlineData(260955581)]
[InlineData(267685466)]
[InlineData(466579064)]
public async void GetUserReelFeedTest(long userPk)
@@ -66,7 +66,7 @@ public async void GetUserReelFeedTest(long userPk)
public async void ExploreTest()
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
- var result = await _authInfo.ApiInstance.GetExploreFeedAsync(3);
+ var result = await _authInfo.ApiInstance.GetExploreFeedAsync(PaginationParameters.MaxPagesToLoad(5));
var exploreGeed = result.Value;
var anyMediaDuplicate = exploreGeed.Medias.GroupBy(x => x.Code).Any(g => g.Count() > 1);
//assert
@@ -80,7 +80,8 @@ public async void GetFollowingRecentActivityFeedTest()
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
- var getFeedResult = await _authInfo.ApiInstance.GetFollowingRecentActivityAsync(5);
+ var getFeedResult =
+ await _authInfo.ApiInstance.GetFollowingRecentActivityAsync(PaginationParameters.MaxPagesToLoad(5));
var folloowingRecentFeed = getFeedResult.Value;
//assert
@@ -94,7 +95,8 @@ public async void GetRecentActivityFeedTest()
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
- var getFeedResult = await _authInfo.ApiInstance.GetRecentActivityAsync(5);
+ var getFeedResult =
+ await _authInfo.ApiInstance.GetRecentActivityAsync(PaginationParameters.MaxPagesToLoad(5));
var ownRecentFeed = getFeedResult.Value;
//assert
Assert.True(getFeedResult.Succeeded);
@@ -107,7 +109,8 @@ public async void GetUserFeedTest()
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
- var getFeedResult = await _authInfo.ApiInstance.GetUserTimelineFeedAsync(1);
+ var getFeedResult =
+ await _authInfo.ApiInstance.GetUserTimelineFeedAsync(PaginationParameters.MaxPagesToLoad(3));
var feed = getFeedResult.Value;
var anyDuplicate = feed.Medias.GroupBy(x => x.Code).Any(g => g.Count() > 1);
var anyStoryDuplicate = feed.Stories.GroupBy(x => x.Id).Any(g => g.Count() > 1);
@@ -124,7 +127,7 @@ public async void GetUserLikeFeedTest()
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
- var getFeedResult = await _authInfo.ApiInstance.GetLikeFeedAsync(2);
+ var getFeedResult = await _authInfo.ApiInstance.GetLikeFeedAsync(PaginationParameters.MaxPagesToLoad(5));
var feed = getFeedResult.Value;
var anyDuplicate = feed.GroupBy(x => x.Code).Any(g => g.Count() > 1);
diff --git a/InstaSharper.Tests/Endpoints/FollowersTest.cs b/InstaSharper.Tests/Endpoints/FollowersTest.cs
index 9eb78fcc..e108737c 100644
--- a/InstaSharper.Tests/Endpoints/FollowersTest.cs
+++ b/InstaSharper.Tests/Endpoints/FollowersTest.cs
@@ -1,4 +1,5 @@
using System.Linq;
+using InstaSharper.Classes;
using InstaSharper.Tests.Classes;
using Xunit;
@@ -20,7 +21,8 @@ public async void GetUserFollowersTest(string username)
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
- var result = await _authInfo.ApiInstance.GetUserFollowersAsync(username, 5);
+ var result =
+ await _authInfo.ApiInstance.GetUserFollowersAsync(username, PaginationParameters.MaxPagesToLoad(5));
var followers = result.Value;
var anyDuplicate = followers.GroupBy(x => x.Pk).Any(g => g.Count() > 1);
@@ -36,7 +38,8 @@ public async void GetUserFollowingTest(string username)
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
- var result = await _authInfo.ApiInstance.GetUserFollowingAsync(username, 10);
+ var result =
+ await _authInfo.ApiInstance.GetUserFollowingAsync(username, PaginationParameters.MaxPagesToLoad(5));
var followings = result.Value;
var anyDuplicate = followings.GroupBy(x => x.Pk).Any(g => g.Count() > 1);
@@ -62,12 +65,29 @@ public async void FollowUnfollowUserTest(long userId)
Assert.False(unFollowResult.Value.Following);
}
+ [Theory]
+ [InlineData(196754384)]
+ public async void BlockUnblockUserTest(long userId)
+ {
+ Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
+
+ var blockResult = await _authInfo.ApiInstance.BlockUserAsync(userId);
+ var unBlockResult = await _authInfo.ApiInstance.UnBlockUserAsync(userId);
+ //assert
+ Assert.True(blockResult.Succeeded);
+ Assert.True(unBlockResult.Succeeded);
+
+ Assert.True(blockResult.Value.Blocking);
+ Assert.False(unBlockResult.Value.Blocking);
+ }
+
[Fact]
public async void GetCurrentUserFollwersTest()
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
- var result = await _authInfo.ApiInstance.GetCurrentUserFollowersAsync();
+ var result =
+ await _authInfo.ApiInstance.GetCurrentUserFollowersAsync(PaginationParameters.MaxPagesToLoad(5));
var followers = result.Value;
//assert
Assert.True(result.Succeeded);
diff --git a/InstaSharper.Tests/Endpoints/LocationTest.cs b/InstaSharper.Tests/Endpoints/LocationTest.cs
new file mode 100644
index 00000000..703e9334
--- /dev/null
+++ b/InstaSharper.Tests/Endpoints/LocationTest.cs
@@ -0,0 +1,50 @@
+using System.Linq;
+using InstaSharper.Classes;
+using InstaSharper.Tests.Classes;
+using Xunit;
+
+namespace InstaSharper.Tests.Endpoints
+{
+ [Trait("Category", "Endpoint")]
+ public class LocationTest : IClassFixture
+ {
+ private readonly AuthenticatedTestFixture _authInfo;
+
+ public LocationTest(AuthenticatedTestFixture authInfo)
+ {
+ _authInfo = authInfo;
+ }
+
+ [Theory]
+ [InlineData("winter")]
+ public async void SearchLocation(string searchQuery)
+ {
+ Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
+
+ var result = await _authInfo.ApiInstance.SearchLocation(59.9384401, 30.3162374, searchQuery);
+
+ //assert
+ Assert.True(result.Succeeded);
+ Assert.NotNull(result.Value);
+ Assert.True(result.Value.Any(location => location.Name.ToLowerInvariant().Contains(searchQuery)));
+ }
+
+ [Theory]
+ [InlineData(109408589078990)]
+ public async void GetLocationFeed(long locationId)
+ {
+ Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
+
+ var result =
+ await _authInfo.ApiInstance.GetLocationFeed(locationId, PaginationParameters.MaxPagesToLoad(15));
+ var locationFeed = result.Value;
+ var anyMediaDuplicate = locationFeed.Medias.GroupBy(x => x.Code).Any(g => g.Count() > 1);
+ var anyRankedDuplicate = locationFeed.RankedMedias.GroupBy(x => x.Code).Any(g => g.Count() > 1);
+ //assert
+ Assert.True(result.Succeeded);
+ Assert.NotNull(result.Value);
+ Assert.False(anyMediaDuplicate);
+ Assert.False(anyRankedDuplicate);
+ }
+ }
+}
\ No newline at end of file
diff --git a/InstaSharper.Tests/Endpoints/MediaTest.cs b/InstaSharper.Tests/Endpoints/MediaTest.cs
index ee5d8fc2..9bda3b4e 100644
--- a/InstaSharper.Tests/Endpoints/MediaTest.cs
+++ b/InstaSharper.Tests/Endpoints/MediaTest.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
+using InstaSharper.Classes;
using InstaSharper.Classes.Models;
using InstaSharper.Tests.Classes;
using Xunit;
@@ -41,7 +42,8 @@ public async void GetMediaLikersTest(string mediaId)
public async void GetMediaCommentsTest(string mediaId)
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
- var comments = await _authInfo.ApiInstance.GetMediaCommentsAsync(mediaId, 3);
+ var comments =
+ await _authInfo.ApiInstance.GetMediaCommentsAsync(mediaId, PaginationParameters.MaxPagesToLoad(5));
var anyDuplicate = comments.Value.Comments.GroupBy(x => x.Pk).Any(g => g.Count() > 1);
@@ -50,13 +52,14 @@ public async void GetMediaCommentsTest(string mediaId)
}
[Theory]
- [InlineData("alex_codegarage")]
+ [InlineData("microsoftstore")]
public async void GetUserMediaListTest(string userToFetch)
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
var random = new Random(DateTime.Now.Millisecond);
- var posts = await _authInfo.ApiInstance.GetUserMediaAsync(userToFetch, 3);
+ var posts = await _authInfo.ApiInstance.GetUserMediaAsync(userToFetch,
+ PaginationParameters.MaxPagesToLoad(3));
var anyDuplicate = posts.Value.GroupBy(x => x.Code).Any(g => g.Count() > 1);
Assert.NotNull(posts);
@@ -103,5 +106,36 @@ public async void EditMediaTest(string mediaId, string caption)
var editMedia = await _authInfo.ApiInstance.EditMediaAsync(mediaId, caption);
Assert.True(editMedia.Value);
}
+
+ [Theory]
+ [InlineData("https://www.instagram.com/p/BbfsZ-3jbZF/")]
+ public async void GetMediaIdFromUrlTest(string url)
+ {
+ var uri = new Uri(url);
+
+ Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
+ var mediaId = await _authInfo.ApiInstance.GetMediaIdFromUrlAsync(uri);
+ Assert.True(mediaId.Succeeded);
+ }
+
+ [Theory]
+ [InlineData("https://www.instagramwrongurl.com/p/BbfsZ-3jbZF/")]
+ public async void GetMediaIdFromMalformedUrlTest(string url)
+ {
+ var uri = new Uri(url);
+
+ Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
+ var mediaId = await _authInfo.ApiInstance.GetMediaIdFromUrlAsync(uri);
+ Assert.False(mediaId.Succeeded);
+ }
+
+ [Theory]
+ [InlineData("1635541101392510862_25025320")]
+ public async void GetShareLinkFromMediaId(string mediaId)
+ {
+ Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
+ var url = await _authInfo.ApiInstance.GetShareLinkFromMediaIdAsync(mediaId);
+ Assert.True(url.Succeeded);
+ }
}
}
\ No newline at end of file
diff --git a/InstaSharper.Tests/Endpoints/MessagingTest.cs b/InstaSharper.Tests/Endpoints/MessagingTest.cs
index 0a84ce0f..d900703f 100644
--- a/InstaSharper.Tests/Endpoints/MessagingTest.cs
+++ b/InstaSharper.Tests/Endpoints/MessagingTest.cs
@@ -29,12 +29,12 @@ public async void GetDirectInboxThreadByIdTest(string threadId)
public async void SendDirectMessageTest(string user)
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
-
var text = "this is test";
var result =
- await _authInfo.ApiInstance.SendDirectMessage(user, "340282366841710300949128137443944319108", text);
-
+ await _authInfo.ApiInstance.SendDirectMessage(user, string.Empty, text);
Assert.True(result.Succeeded);
+ Assert.NotNull(result.Value);
+ Assert.True(result.Value.Count > 0);
}
[Fact]
diff --git a/InstaSharper.Tests/Endpoints/StoryTest.cs b/InstaSharper.Tests/Endpoints/StoryTest.cs
index 0cce1303..2860c550 100644
--- a/InstaSharper.Tests/Endpoints/StoryTest.cs
+++ b/InstaSharper.Tests/Endpoints/StoryTest.cs
@@ -16,14 +16,14 @@ public StoryTest(AuthenticatedTestFixture authInfo)
private readonly AuthenticatedTestFixture _authInfo;
[Theory]
- [InlineData(1129166614)]
+ [InlineData(267685466)]
private async void GetUserStoryTest(long userId)
{
Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
var result = await _authInfo.ApiInstance.GetUserStoryAsync(userId);
- var stories = result.Value;
+ var story = result.Value;
Assert.True(result.Succeeded);
- Assert.NotNull(stories);
+ Assert.NotNull(story);
}
[Fact]
diff --git a/InstaSharper.Tests/Endpoints/TwoFactorAuthTest.cs b/InstaSharper.Tests/Endpoints/TwoFactorAuthTest.cs
new file mode 100644
index 00000000..31ea9ae7
--- /dev/null
+++ b/InstaSharper.Tests/Endpoints/TwoFactorAuthTest.cs
@@ -0,0 +1,97 @@
+using System;
+using System.IO;
+using System.Threading;
+using InstaSharper.Classes;
+using InstaSharper.Tests.Utils;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace InstaSharper.Tests.Endpoints
+{
+ [Collection("Endpoints")]
+ public class TwoFactorAuthTest
+ {
+ public TwoFactorAuthTest(ITestOutputHelper output)
+ {
+ _output = output;
+ }
+
+ private readonly ITestOutputHelper _output;
+
+ [Fact]
+ public async void User2FaLoginFailTest()
+ {
+ var username = "thisasif";
+ var password = Environment.GetEnvironmentVariable("instaapiuserpassword");
+
+ var apiInstance =
+ TestHelpers.GetDefaultInstaApiInstance(new UserSessionData
+ {
+ UserName = username,
+ Password = password
+ });
+ _output.WriteLine("Got API instance");
+
+ var loginResult = await apiInstance.LoginAsync();
+ Assert.False(loginResult.Succeeded);
+ Assert.False(apiInstance.IsUserAuthenticated);
+
+ Assert.True(loginResult.Value == InstaLoginResult.TwoFactorRequired);
+
+ var login2FactorAuth = await apiInstance.TwoFactorLoginAsync("666666");
+
+ Assert.False(login2FactorAuth.Succeeded);
+ }
+
+ [Fact]
+ public async void User2FaLoginSuccessTest()
+ {
+ var username = "thisasif";
+ var password = Environment.GetEnvironmentVariable("instaapiuserpassword");
+
+ var apiInstance =
+ TestHelpers.GetDefaultInstaApiInstance(new UserSessionData
+ {
+ UserName = username,
+ Password = password
+ });
+ _output.WriteLine("Got API instance");
+
+ var loginResult = await apiInstance.LoginAsync();
+ Assert.False(loginResult.Succeeded);
+ Assert.False(apiInstance.IsUserAuthenticated);
+
+ Assert.True(loginResult.Value == InstaLoginResult.TwoFactorRequired);
+
+ Thread.Sleep(20000);
+
+ var content = File.ReadAllText(@"C:\tmp\codice.txt");
+
+ var login2FactorAuth = await apiInstance.TwoFactorLoginAsync(content);
+
+ Assert.True(login2FactorAuth.Succeeded);
+ Assert.True(apiInstance.IsUserAuthenticated);
+ }
+
+ [Fact]
+ public async void User2FaTest()
+ {
+ var username = "thisasif";
+ var password = Environment.GetEnvironmentVariable("instaapiuserpassword");
+
+ var apiInstance =
+ TestHelpers.GetDefaultInstaApiInstance(new UserSessionData
+ {
+ UserName = username,
+ Password = password
+ });
+ _output.WriteLine("Got API instance");
+
+ var loginResult = await apiInstance.LoginAsync();
+ Assert.False(loginResult.Succeeded);
+ Assert.False(apiInstance.IsUserAuthenticated);
+
+ Assert.True(loginResult.Value == InstaLoginResult.TwoFactorRequired);
+ }
+ }
+}
\ No newline at end of file
diff --git a/InstaSharper.Tests/Endpoints/UploadTest.cs b/InstaSharper.Tests/Endpoints/UploadTest.cs
index 10902083..2ed46520 100644
--- a/InstaSharper.Tests/Endpoints/UploadTest.cs
+++ b/InstaSharper.Tests/Endpoints/UploadTest.cs
@@ -32,5 +32,33 @@ public async void UploadImage()
Assert.True(result.Succeeded);
Assert.NotNull(result.Value);
}
+
+ [Fact]
+ public async void UploadImagesAsAlbumTest()
+ {
+ Assert.True(_authInfo.ApiInstance.IsUserAuthenticated);
+
+ var mediaImage = new InstaImage
+ {
+ Height = 512,
+ Width = 512,
+ URI = new Uri(@"C:\tmp\1.jpg", UriKind.Absolute).LocalPath
+ };
+
+ var mediaImage1 = new InstaImage
+ {
+ Height = 512,
+ Width = 512,
+ URI = new Uri(@"C:\tmp\2.jpg", UriKind.Absolute).LocalPath
+ };
+
+ var result =
+ await _authInfo.ApiInstance.UploadPhotosAlbumAsync(new[] {mediaImage, mediaImage1},
+ "Collection of design");
+
+ //assert
+ Assert.True(result.Succeeded);
+ Assert.NotNull(result.Value);
+ }
}
}
\ No newline at end of file
diff --git a/InstaSharper.Tests/Infrastructure/RankedRecipientsTest.cs b/InstaSharper.Tests/Infrastructure/RankedRecipientsTest.cs
new file mode 100644
index 00000000..d13503f8
--- /dev/null
+++ b/InstaSharper.Tests/Infrastructure/RankedRecipientsTest.cs
@@ -0,0 +1,438 @@
+using InstaSharper.Classes.ResponseWrappers;
+using InstaSharper.Helpers;
+using Newtonsoft.Json;
+using Xunit;
+
+namespace InstaSharper.Tests.Infrastructure
+{
+ [Trait("Category", "Infrastructure")]
+ public class RankedRecipientsTest
+ {
+ private const string testJson = @"{
+ ""ranked_recipients"": [{
+ ""thread"": {
+ ""thread_id"": ""340282366841710300949128128698734336052"",
+ ""users"": [{
+ ""pk"": 1635609778,
+ ""username"": ""alr_knight"",
+ ""full_name"": ""Knight"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/18160263_191502241369975_8628660834639282176_a.jpg"",
+ ""profile_pic_id"": ""1503031289182596054_1635609778"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false
+ }],
+ ""canonical"": true,
+ ""named"": false,
+ ""thread_title"": ""alr_knight"",
+ ""pending"": false,
+ ""thread_type"": ""private"",
+ ""viewer_id"": 1647718432
+ }
+ },
+ {
+ ""thread"": {
+ ""thread_id"": ""340282366841710300949128137502093309895"",
+ ""users"": [{
+ ""pk"": 1970280312,
+ ""username"": ""ali.enzo2003"",
+ ""full_name"": ""Ali akbar jokar"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/22221360_117045119049079_2160406946895626240_n.jpg"",
+ ""profile_pic_id"": ""1619200818765710419_1970280312"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false
+ }],
+ ""canonical"": true,
+ ""named"": false,
+ ""thread_title"": ""ali.enzo2003"",
+ ""pending"": false,
+ ""thread_type"": ""private"",
+ ""viewer_id"": 1647718432
+ }
+ },
+ {
+ ""thread"": {
+ ""thread_id"": ""340282366841710300949128176621874302520"",
+ ""users"": [{
+ ""pk"": 1083654223,
+ ""username"": ""hootanht"",
+ ""full_name"": ""Hootan HT"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23421265_159622818107137_4034734531750658048_n.jpg"",
+ ""profile_pic_id"": ""1645900906660662890_1083654223"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false
+ }],
+ ""canonical"": true,
+ ""named"": false,
+ ""thread_title"": ""hootanht"",
+ ""pending"": false,
+ ""thread_type"": ""private"",
+ ""viewer_id"": 1647718432
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 1693680351,
+ ""username"": ""farnaz.mzh20"",
+ ""full_name"": ""Farnaz Mozhgani\u2764\ud83d\udc69\u200d\ud83d\udcbb \u0641\u0631\u0646\u0627\u0632"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23507176_1824437314513972_7352310486865543168_n.jpg"",
+ ""profile_pic_id"": ""1648949686839436879_1693680351"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 1458048765,
+ ""username"": ""k.salamati"",
+ ""full_name"": ""kourosh salamati"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/22639548_744397965747635_470940668630401024_n.jpg"",
+ ""profile_pic_id"": ""1632272046988117813_1458048765"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 6288988520,
+ ""username"": ""miad.95879593"",
+ ""full_name"": ""miad.9587"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-mxp1-1.cdninstagram.com/t51.2885-19/11906329_960233084022564_1448528159_a.jpg"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": true,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 4700872585,
+ ""username"": ""amirali.life1997"",
+ ""full_name"": ""AMIR\u2764Ali"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/17332903_1356564087699739_7016453540491034624_a.jpg"",
+ ""profile_pic_id"": ""1472296969970953382_4700872585"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 5614099053,
+ ""username"": ""ese5973"",
+ ""full_name"": ""ese"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/22159207_785051548363223_2327166594125398016_n.jpg"",
+ ""profile_pic_id"": ""1618638727914373626_5614099053"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 5982940248,
+ ""username"": ""njd_mhmdmhmd"",
+ ""full_name"": ""\u0645\u062d\u0645\u062f \u0645\u062d\u0645\u062f \u0646\u0698\u0627\u062f"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-mxp1-1.cdninstagram.com/t51.2885-19/11906329_960233084022564_1448528159_a.jpg"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": true,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 5677513936,
+ ""username"": ""nilooofar.re"",
+ ""full_name"": ""Nilooofar.re"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/19535013_1592941304080493_2890533623230889984_a.jpg"",
+ ""profile_pic_id"": ""1550741736980990941_5677513936"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 5760970028,
+ ""username"": ""hsh_1993"",
+ ""full_name"": ""Hamed"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/20904862_116006422352140_4342957413729566720_a.jpg"",
+ ""profile_pic_id"": ""1585317022022179386_5760970028"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 1044853632,
+ ""username"": ""atn_1993"",
+ ""full_name"": ""ATN"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/20184492_1907934619457872_8098029874465210368_a.jpg"",
+ ""profile_pic_id"": ""1563642139068355862_1044853632"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 5717455301,
+ ""username"": ""8309kazeron"",
+ ""full_name"": ""Mohammad 8309kazeron"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/20479076_1391591357543894_7587999269659869184_a.jpg"",
+ ""profile_pic_id"": ""1571721063779623132_5717455301"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 5678455485,
+ ""username"": ""mstfy662"",
+ ""full_name"": ""\u0645\u0635\u0637\u0641\u06cc"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-mxp1-1.cdninstagram.com/t51.2885-19/11906329_960233084022564_1448528159_a.jpg"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": true,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 4776464077,
+ ""username"": ""rwin.ak"",
+ ""full_name"": ""Rwin"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/20482199_713939045481173_4217748736115212288_a.jpg"",
+ ""profile_pic_id"": ""1572672385144738831_4776464077"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 5561289395,
+ ""username"": ""sl_mayyy"",
+ ""full_name"": ""May"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23596152_306141666540750_2722580335870083072_n.jpg"",
+ ""profile_pic_id"": ""1648821021405184938_5561289395"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 1665097951,
+ ""username"": ""madt1375"",
+ ""full_name"": ""\u0026\u0026matin\u0026\u0026\ud83d\udc49 Hakina Matata"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/19985838_1493714687346911_6311131670384738304_a.jpg"",
+ ""profile_pic_id"": ""1559723410019089129_1665097951"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 4172003794,
+ ""username"": ""bahareh_malekpour"",
+ ""full_name"": ""Bahareh"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/15057170_1247864588617496_449409619618430976_a.jpg"",
+ ""profile_pic_id"": ""1387121674563167477_4172003794"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 1977441402,
+ ""username"": ""yousafriaz6"",
+ ""full_name"": ""Raja Yousaf Riaz"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/15625524_180356095772072_4276718035793870848_a.jpg"",
+ ""profile_pic_id"": ""1412858842651739747_1977441402"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 5360387201,
+ ""username"": ""ali.d2698"",
+ ""full_name"": ""Ali.D2698"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/18014047_117319205487829_6246258770654003200_a.jpg"",
+ ""profile_pic_id"": ""1497713138212502207_5360387201"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 1263972398,
+ ""username"": ""unknow0.o"",
+ ""full_name"": ""farZin0da"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/18380268_383330582067431_7009299585264779264_a.jpg"",
+ ""profile_pic_id"": ""1513241329025427304_1263972398"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 3917685878,
+ ""username"": ""azin_zahabi"",
+ ""full_name"": ""azinzahabi"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/15534828_351621061879017_1749654446712815616_a.jpg"",
+ ""profile_pic_id"": ""1411707140427458562_3917685878"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 1413636874,
+ ""username"": ""shahryar.ashtari"",
+ ""full_name"": ""shary famous"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/13388487_1727117410888429_587178138_a.jpg"",
+ ""profile_pic_id"": ""1281397482828254031_1413636874"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 890888289,
+ ""username"": ""ekhtad"",
+ ""full_name"": ""Mostafa Fakoori"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/1660619_178819552491836_2121922682_a.jpg"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 1504001049,
+ ""username"": ""saber_marandi"",
+ ""full_name"": ""saber"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23498266_143087636334813_3285276048702308352_n.jpg"",
+ ""profile_pic_id"": ""1646826333928264659_1504001049"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 3183327996,
+ ""username"": ""arash_doooonnnn"",
+ ""full_name"": ""arash \ud83d\udc97\ud83c\udd70\ud83d\udc97"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/17494568_1349544698446502_3670486137857638400_a.jpg"",
+ ""profile_pic_id"": ""1484548657205383055_3183327996"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 1177836418,
+ ""username"": ""bardiarya"",
+ ""full_name"": ""bardi.arya11"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/16229152_225821371157909_6646071452262989824_a.jpg"",
+ ""profile_pic_id"": ""1447028028453472548_1177836418"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 4069861549,
+ ""username"": ""shayan_behdinian"",
+ ""full_name"": ""Shayan Behdinian"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23279276_127835277902850_7169559637010677760_n.jpg"",
+ ""profile_pic_id"": ""1642356985624045981_4069861549"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 4051680176,
+ ""username"": ""aseman_sard"",
+ ""full_name"": ""Open Page:18/10/1395"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23594227_377303179371808_132910790926663680_n.jpg"",
+ ""profile_pic_id"": ""1649597462907807731_4051680176"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ },
+ {
+ ""user"": {
+ ""pk"": 315442394,
+ ""username"": ""arian_yeganegi"",
+ ""full_name"": ""Arian"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/21433649_146016685993808_8510183569073635328_a.jpg"",
+ ""profile_pic_id"": ""1600099344663909473_315442394"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""coeff_weight"": 0.0
+ }
+ }],
+ ""expires"": 7200,
+ ""filtered"": true,
+ ""request_id"": """",
+ ""rank_token"": ""69b1c5f4-91a3-4a07-b259-ff9b25ea52d1"",
+ ""status"": ""ok""
+}";
+
+ [Fact]
+ public void ConvertRankedRecipientsTest()
+ {
+ var responseRecipients = JsonConvert.DeserializeObject(testJson);
+ var fabric = ConvertersHelper.GetDefaultFabric();
+ var result = fabric.GetRecipientsConverter(responseRecipients).Convert();
+ Assert.NotNull(result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/InstaSharper.Tests/Infrastructure/RecipientsConverterTests.cs b/InstaSharper.Tests/Infrastructure/RecipientsConverterTests.cs
new file mode 100644
index 00000000..9ae28ad1
--- /dev/null
+++ b/InstaSharper.Tests/Infrastructure/RecipientsConverterTests.cs
@@ -0,0 +1,449 @@
+using InstaSharper.Classes.ResponseWrappers;
+using InstaSharper.Helpers;
+using Newtonsoft.Json;
+using Xunit;
+
+namespace InstaSharper.Tests.Infrastructure
+{
+ [Trait("Category", "Infrastructure")]
+ public class RecipientsConverterTests
+ {
+ private const string testJson = @"{
+ ""ranked_recipients"":[
+ {
+ ""thread"":{
+ ""thread_id"":""340282366841710300949128128698734336052"",
+ ""users"":[
+ {
+ ""pk"":1635609778,
+ ""username"":""alr_knight"",
+ ""full_name"":""Knight"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/18160263_191502241369975_8628660834639282176_a.jpg"",
+ ""profile_pic_id"":""1503031289182596054_1635609778"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false
+ }
+ ],
+ ""canonical"":true,
+ ""named"":false,
+ ""thread_title"":""alr_knight"",
+ ""pending"":false,
+ ""thread_type"":""private"",
+ ""viewer_id"":1647718432
+ }
+ },
+ {
+ ""thread"":{
+ ""thread_id"":""340282366841710300949128137502093309895"",
+ ""users"":[
+ {
+ ""pk"":1970280312,
+ ""username"":""ali.enzo2003"",
+ ""full_name"":""Ali akbar jokar"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/22221360_117045119049079_2160406946895626240_n.jpg"",
+ ""profile_pic_id"":""1619200818765710419_1970280312"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false
+ }
+ ],
+ ""canonical"":true,
+ ""named"":false,
+ ""thread_title"":""ali.enzo2003"",
+ ""pending"":false,
+ ""thread_type"":""private"",
+ ""viewer_id"":1647718432
+ }
+ },
+ {
+ ""thread"":{
+ ""thread_id"":""340282366841710300949128176621874302520"",
+ ""users"":[
+ {
+ ""pk"":1083654223,
+ ""username"":""hootanht"",
+ ""full_name"":""Hootan HT"",
+ ""is_private"":false,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23421265_159622818107137_4034734531750658048_n.jpg"",
+ ""profile_pic_id"":""1645900906660662890_1083654223"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false
+ }
+ ],
+ ""canonical"":true,
+ ""named"":false,
+ ""thread_title"":""hootanht"",
+ ""pending"":false,
+ ""thread_type"":""private"",
+ ""viewer_id"":1647718432
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":1693680351,
+ ""username"":""farnaz.mzh20"",
+ ""full_name"":""Farnaz Mozhgani\u2764\ud83d\udc69\u200d\ud83d\udcbb \u0641\u0631\u0646\u0627\u0632"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23507176_1824437314513972_7352310486865543168_n.jpg"",
+ ""profile_pic_id"":""1648949686839436879_1693680351"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":1458048765,
+ ""username"":""k.salamati"",
+ ""full_name"":""kourosh salamati"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/22639548_744397965747635_470940668630401024_n.jpg"",
+ ""profile_pic_id"":""1632272046988117813_1458048765"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":6288988520,
+ ""username"":""miad.95879593"",
+ ""full_name"":""miad.9587"",
+ ""is_private"":false,
+ ""profile_pic_url"":""https://scontent-mxp1-1.cdninstagram.com/t51.2885-19/11906329_960233084022564_1448528159_a.jpg"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":true,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":4700872585,
+ ""username"":""amirali.life1997"",
+ ""full_name"":""AMIR\u2764Ali"",
+ ""is_private"":false,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/17332903_1356564087699739_7016453540491034624_a.jpg"",
+ ""profile_pic_id"":""1472296969970953382_4700872585"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":5614099053,
+ ""username"":""ese5973"",
+ ""full_name"":""ese"",
+ ""is_private"":false,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/22159207_785051548363223_2327166594125398016_n.jpg"",
+ ""profile_pic_id"":""1618638727914373626_5614099053"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":5982940248,
+ ""username"":""njd_mhmdmhmd"",
+ ""full_name"":""\u0645\u062d\u0645\u062f \u0645\u062d\u0645\u062f \u0646\u0698\u0627\u062f"",
+ ""is_private"":false,
+ ""profile_pic_url"":""https://scontent-mxp1-1.cdninstagram.com/t51.2885-19/11906329_960233084022564_1448528159_a.jpg"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":true,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":5677513936,
+ ""username"":""nilooofar.re"",
+ ""full_name"":""Nilooofar.re"",
+ ""is_private"":false,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/19535013_1592941304080493_2890533623230889984_a.jpg"",
+ ""profile_pic_id"":""1550741736980990941_5677513936"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":5760970028,
+ ""username"":""hsh_1993"",
+ ""full_name"":""Hamed"",
+ ""is_private"":false,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/20904862_116006422352140_4342957413729566720_a.jpg"",
+ ""profile_pic_id"":""1585317022022179386_5760970028"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":1044853632,
+ ""username"":""atn_1993"",
+ ""full_name"":""ATN"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/20184492_1907934619457872_8098029874465210368_a.jpg"",
+ ""profile_pic_id"":""1563642139068355862_1044853632"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":5717455301,
+ ""username"":""8309kazeron"",
+ ""full_name"":""Mohammad 8309kazeron"",
+ ""is_private"":false,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/20479076_1391591357543894_7587999269659869184_a.jpg"",
+ ""profile_pic_id"":""1571721063779623132_5717455301"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":5678455485,
+ ""username"":""mstfy662"",
+ ""full_name"":""\u0645\u0635\u0637\u0641\u06cc"",
+ ""is_private"":false,
+ ""profile_pic_url"":""https://scontent-mxp1-1.cdninstagram.com/t51.2885-19/11906329_960233084022564_1448528159_a.jpg"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":true,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":4776464077,
+ ""username"":""rwin.ak"",
+ ""full_name"":""Rwin"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/20482199_713939045481173_4217748736115212288_a.jpg"",
+ ""profile_pic_id"":""1572672385144738831_4776464077"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":5561289395,
+ ""username"":""sl_mayyy"",
+ ""full_name"":""May"",
+ ""is_private"":false,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23596152_306141666540750_2722580335870083072_n.jpg"",
+ ""profile_pic_id"":""1648821021405184938_5561289395"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":1665097951,
+ ""username"":""madt1375"",
+ ""full_name"":""\u0026\u0026matin\u0026\u0026\ud83d\udc49 Hakina Matata"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/19985838_1493714687346911_6311131670384738304_a.jpg"",
+ ""profile_pic_id"":""1559723410019089129_1665097951"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":4172003794,
+ ""username"":""bahareh_malekpour"",
+ ""full_name"":""Bahareh"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/15057170_1247864588617496_449409619618430976_a.jpg"",
+ ""profile_pic_id"":""1387121674563167477_4172003794"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":1977441402,
+ ""username"":""yousafriaz6"",
+ ""full_name"":""Raja Yousaf Riaz"",
+ ""is_private"":false,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/15625524_180356095772072_4276718035793870848_a.jpg"",
+ ""profile_pic_id"":""1412858842651739747_1977441402"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":5360387201,
+ ""username"":""ali.d2698"",
+ ""full_name"":""Ali.D2698"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/18014047_117319205487829_6246258770654003200_a.jpg"",
+ ""profile_pic_id"":""1497713138212502207_5360387201"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":1263972398,
+ ""username"":""unknow0.o"",
+ ""full_name"":""farZin0da"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/18380268_383330582067431_7009299585264779264_a.jpg"",
+ ""profile_pic_id"":""1513241329025427304_1263972398"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":3917685878,
+ ""username"":""azin_zahabi"",
+ ""full_name"":""azinzahabi"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/15534828_351621061879017_1749654446712815616_a.jpg"",
+ ""profile_pic_id"":""1411707140427458562_3917685878"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":1413636874,
+ ""username"":""shahryar.ashtari"",
+ ""full_name"":""shary famous"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/13388487_1727117410888429_587178138_a.jpg"",
+ ""profile_pic_id"":""1281397482828254031_1413636874"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":890888289,
+ ""username"":""ekhtad"",
+ ""full_name"":""Mostafa Fakoori"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/1660619_178819552491836_2121922682_a.jpg"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":1504001049,
+ ""username"":""saber_marandi"",
+ ""full_name"":""saber"",
+ ""is_private"":false,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23498266_143087636334813_3285276048702308352_n.jpg"",
+ ""profile_pic_id"":""1646826333928264659_1504001049"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":3183327996,
+ ""username"":""arash_doooonnnn"",
+ ""full_name"":""arash \ud83d\udc97\ud83c\udd70\ud83d\udc97"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/17494568_1349544698446502_3670486137857638400_a.jpg"",
+ ""profile_pic_id"":""1484548657205383055_3183327996"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":1177836418,
+ ""username"":""bardiarya"",
+ ""full_name"":""bardi.arya11"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/16229152_225821371157909_6646071452262989824_a.jpg"",
+ ""profile_pic_id"":""1447028028453472548_1177836418"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":4069861549,
+ ""username"":""shayan_behdinian"",
+ ""full_name"":""Shayan Behdinian"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23279276_127835277902850_7169559637010677760_n.jpg"",
+ ""profile_pic_id"":""1642356985624045981_4069861549"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":4051680176,
+ ""username"":""aseman_sard"",
+ ""full_name"":""Open Page:18/10/1395"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23594227_377303179371808_132910790926663680_n.jpg"",
+ ""profile_pic_id"":""1649597462907807731_4051680176"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ },
+ {
+ ""user"":{
+ ""pk"":315442394,
+ ""username"":""arian_yeganegi"",
+ ""full_name"":""Arian"",
+ ""is_private"":true,
+ ""profile_pic_url"":""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/21433649_146016685993808_8510183569073635328_a.jpg"",
+ ""profile_pic_id"":""1600099344663909473_315442394"",
+ ""is_verified"":false,
+ ""has_anonymous_profile_picture"":false,
+ ""coeff_weight"":0.0
+ }
+ }
+ ],
+ ""expires"":7200,
+ ""filtered"":true,
+ ""request_id"":"""",
+ ""rank_token"":""69b1c5f4-91a3-4a07-b259-ff9b25ea52d1"",
+ ""status"":""ok""
+}";
+
+ [Fact]
+ public void RecipientsResponseConverterTests()
+ {
+ var responseRecipients = JsonConvert.DeserializeObject(testJson);
+ var fabric = ConvertersHelper.GetDefaultFabric();
+ var converter = fabric.GetRecipientsConverter(responseRecipients);
+ var result = converter.Convert();
+ Assert.NotNull(result);
+ Assert.True(result.Threads.Count == 3);
+ Assert.True(result.Users.Count == 27);
+ }
+ }
+}
\ No newline at end of file
diff --git a/InstaSharper.Tests/Infrastructure/StoryReelFeedTest.cs b/InstaSharper.Tests/Infrastructure/StoryReelFeedTest.cs
new file mode 100644
index 00000000..f3875fc8
--- /dev/null
+++ b/InstaSharper.Tests/Infrastructure/StoryReelFeedTest.cs
@@ -0,0 +1,989 @@
+using InstaSharper.Classes.ResponseWrappers;
+using InstaSharper.Helpers;
+using Newtonsoft.Json;
+using Xunit;
+
+namespace InstaSharper.Tests.Infrastructure
+{
+ [Trait("Category", "Infrastructure")]
+ public class StoryReelFeedTest
+ {
+ private const string testJson = @"{
+ ""tray"": [{
+ ""id"": 959317915,
+ ""latest_reel_media"": 1510854409,
+ ""expiring_at"": 1510940809,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 959317915,
+ ""username"": ""_.hadifaraji._"",
+ ""full_name"": ""\u202d10110010011010110101\u202c"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23348221_112308092876279_8403103806681776128_n.jpg"",
+ ""profile_pic_id"": ""1644487357511490058_959317915"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 1,
+ ""seen_ranked_position"": 1,
+ ""muted"": false,
+ ""prefetch_count"": 1,
+ ""has_besties_media"": false,
+ ""items"": [{
+ ""taken_at"": 1510854409,
+ ""pk"": 1649488959569722177,
+ ""id"": ""1649488959569722177_959317915"",
+ ""device_timestamp"": 1510854409,
+ ""media_type"": 1,
+ ""code"": ""BbkKXgoFPtB"",
+ ""client_cache_key"": ""MTY0OTQ4ODk1OTU2OTcyMjE3Nw==.2"",
+ ""filter_type"": 0,
+ ""image_versions2"": {
+ ""candidates"": [{
+ ""width"": 390,
+ ""height"": 640,
+ ""url"": ""https://scontent-cdg2-1.cdninstagram.com/vp/5b80afebea64bd895a658199f19f9869/5A1066B8/t58.9792-15/e35/12852417_1521254644618497_6599033683401768960_n.jpg?ig_cache_key=MTY0OTQ4ODk1OTU2OTcyMjE3Nw%3D%3D.2""
+ },
+ {
+ ""width"": 240,
+ ""height"": 393,
+ ""url"": ""https://scontent-cdg2-1.cdninstagram.com/vp/933128cc05a9be5c251f4c902173bc1a/5A108FFD/t58.9792-15/e35/p240x240/12852417_1521254644618497_6599033683401768960_n.jpg?ig_cache_key=MTY0OTQ4ODk1OTU2OTcyMjE3Nw%3D%3D.2""
+ }]
+ },
+ ""original_width"": 390,
+ ""original_height"": 640,
+ ""caption_position"": 0.0,
+ ""is_reel_media"": true,
+ ""user"": {
+ ""pk"": 959317915,
+ ""username"": ""_.hadifaraji._"",
+ ""full_name"": ""\u202d10110010011010110101\u202c"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23348221_112308092876279_8403103806681776128_n.jpg"",
+ ""profile_pic_id"": ""1644487357511490058_959317915"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""is_unpublished"": false,
+ ""is_favorite"": false
+ },
+ ""caption"": null,
+ ""caption_is_edited"": false,
+ ""photo_of_you"": false,
+ ""can_viewer_save"": true,
+ ""organic_tracking_token"": ""eyJ2ZXJzaW9uIjo1LCJwYXlsb2FkIjp7ImlzX2FuYWx5dGljc190cmFja2VkIjpmYWxzZSwidXVpZCI6IjVjOTRjZWY5MWFlYjQ2MDM5MzVhYWQzMTk0NjYzMjYzMTY0OTQ4ODk1OTU2OTcyMjE3NyIsInNlcnZlcl90b2tlbiI6IjE1MTA5MTczMTI0NjN8MTY0OTQ4ODk1OTU2OTcyMjE3N3wxNjQ3NzE4NDMyfDcwMjdmY2EyM2NhOTZkMmEzOTFiZGY4NWNhMzhkZmZjYmVlOGM0MTdkMGEzY2VkNzc3YTBmN2FkZWI5MjIxNTgifSwic2lnbmF0dXJlIjoiIn0="",
+ ""expiring_at"": 1510940809,
+ ""reel_mentions"": [],
+ ""story_locations"": [],
+ ""story_events"": [],
+ ""story_hashtags"": [],
+ ""story_polls"": [],
+ ""story_feed_media"": [],
+ ""can_reshare"": true,
+ ""supports_reel_reactions"": false
+ }]
+ },
+ {
+ ""id"": 1391943577,
+ ""latest_reel_media"": 1510906144,
+ ""expiring_at"": 1510992544,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 1391943577,
+ ""username"": ""m.tiger"",
+ ""full_name"": ""TIGER"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/19050833_1879222825660819_7733253637681446912_a.jpg"",
+ ""profile_pic_id"": ""1534651095636688138_1391943577"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 2,
+ ""seen_ranked_position"": 2,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false,
+ ""items"": [{
+ ""taken_at"": 1510906144,
+ ""pk"": 1649922808552366367,
+ ""id"": ""1649922808552366367_1391943577"",
+ ""device_timestamp"": 1510906144517,
+ ""media_type"": 1,
+ ""code"": ""BbltA1-lCEf"",
+ ""client_cache_key"": ""MTY0OTkyMjgwODU1MjM2NjM2Nw==.2"",
+ ""filter_type"": 0,
+ ""image_versions2"": {
+ ""candidates"": [{
+ ""width"": 1080,
+ ""height"": 1776,
+ ""url"": ""https://scontent-cdg2-1.cdninstagram.com/vp/f977e87ccecae5dbe607a57314dcc39d/5A1060C1/t58.9792-15/e35/16994222_160272154575559_6605841983955009536_n.jpg?se=7\u0026ig_cache_key=MTY0OTkyMjgwODU1MjM2NjM2Nw%3D%3D.2""
+ },
+ {
+ ""width"": 240,
+ ""height"": 394,
+ ""url"": ""https://scontent-cdg2-1.cdninstagram.com/vp/bcf53deeb7abb6a0043f558f2b607a64/5A105032/t58.9792-15/e35/p240x240/16994222_160272154575559_6605841983955009536_n.jpg?ig_cache_key=MTY0OTkyMjgwODU1MjM2NjM2Nw%3D%3D.2""
+ }]
+ },
+ ""original_width"": 1080,
+ ""original_height"": 1776,
+ ""caption_position"": 0.0,
+ ""is_reel_media"": true,
+ ""user"": {
+ ""pk"": 1391943577,
+ ""username"": ""m.tiger"",
+ ""full_name"": ""TIGER"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/19050833_1879222825660819_7733253637681446912_a.jpg"",
+ ""profile_pic_id"": ""1534651095636688138_1391943577"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""is_unpublished"": false,
+ ""is_favorite"": false
+ },
+ ""caption"": null,
+ ""caption_is_edited"": false,
+ ""photo_of_you"": false,
+ ""can_viewer_save"": true,
+ ""organic_tracking_token"": ""eyJ2ZXJzaW9uIjo1LCJwYXlsb2FkIjp7ImlzX2FuYWx5dGljc190cmFja2VkIjpmYWxzZSwidXVpZCI6IjVjOTRjZWY5MWFlYjQ2MDM5MzVhYWQzMTk0NjYzMjYzMTY0OTkyMjgwODU1MjM2NjM2NyIsInNlcnZlcl90b2tlbiI6IjE1MTA5MTczMTI0NjN8MTY0OTkyMjgwODU1MjM2NjM2N3wxNjQ3NzE4NDMyfDUwNjQxZDE5ODEwNGEwYzI4ZDEwMmE0NjdhYWM5MDU5ODg4MmNmYTUzZjdmYzMwNzFiMGVkNjA4ZTZmNWY3MzQifSwic2lnbmF0dXJlIjoiIn0="",
+ ""expiring_at"": 1510992544,
+ ""reel_mentions"": [],
+ ""story_locations"": [],
+ ""story_events"": [],
+ ""story_hashtags"": [],
+ ""story_polls"": [],
+ ""story_feed_media"": [],
+ ""can_reshare"": true,
+ ""supports_reel_reactions"": false
+ }]
+ },
+ {
+ ""id"": 3206926093,
+ ""latest_reel_media"": 1510908005,
+ ""expiring_at"": 1510994405,
+ ""seen"": 0.0,
+ ""can_reply"": false,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 3206926093,
+ ""username"": ""ho3in0272"",
+ ""full_name"": ""Ho3in"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/17817785_456510021347810_7510459570775392256_a.jpg"",
+ ""profile_pic_id"": ""1487521582481690239_3206926093"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 3,
+ ""seen_ranked_position"": 3,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false,
+ ""items"": [{
+ ""taken_at"": 1510908005,
+ ""pk"": 1649938507261317983,
+ ""id"": ""1649938507261317983_3206926093"",
+ ""device_timestamp"": 1510908005432,
+ ""media_type"": 1,
+ ""code"": ""BblwlSijJNf"",
+ ""client_cache_key"": ""MTY0OTkzODUwNzI2MTMxNzk4Mw==.2"",
+ ""filter_type"": 0,
+ ""image_versions2"": {
+ ""candidates"": [{
+ ""width"": 540,
+ ""height"": 960,
+ ""url"": ""https://scontent-cdg2-1.cdninstagram.com/vp/742a4dd0ccecdf63b33f2d76c9cfb19a/5A102C1B/t58.9792-15/e35/20775352_130201331028706_1523758292432584704_n.jpg?ig_cache_key=MTY0OTkzODUwNzI2MTMxNzk4Mw%3D%3D.2""
+ },
+ {
+ ""width"": 240,
+ ""height"": 426,
+ ""url"": ""https://scontent-cdg2-1.cdninstagram.com/vp/d5bca24e2f10ff54e883dbf9a353a49b/5A102D88/t58.9792-15/e35/p240x240/20775352_130201331028706_1523758292432584704_n.jpg?ig_cache_key=MTY0OTkzODUwNzI2MTMxNzk4Mw%3D%3D.2""
+ }]
+ },
+ ""original_width"": 540,
+ ""original_height"": 960,
+ ""caption_position"": 0.0,
+ ""is_reel_media"": true,
+ ""user"": {
+ ""pk"": 3206926093,
+ ""username"": ""ho3in0272"",
+ ""full_name"": ""Ho3in"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/17817785_456510021347810_7510459570775392256_a.jpg"",
+ ""profile_pic_id"": ""1487521582481690239_3206926093"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""is_unpublished"": false,
+ ""is_favorite"": false
+ },
+ ""caption"": null,
+ ""caption_is_edited"": false,
+ ""photo_of_you"": false,
+ ""can_viewer_save"": true,
+ ""organic_tracking_token"": ""eyJ2ZXJzaW9uIjo1LCJwYXlsb2FkIjp7ImlzX2FuYWx5dGljc190cmFja2VkIjpmYWxzZSwidXVpZCI6IjVjOTRjZWY5MWFlYjQ2MDM5MzVhYWQzMTk0NjYzMjYzMTY0OTkzODUwNzI2MTMxNzk4MyIsInNlcnZlcl90b2tlbiI6IjE1MTA5MTczMTI0NjN8MTY0OTkzODUwNzI2MTMxNzk4M3wxNjQ3NzE4NDMyfDVkMTU0MTNhODc4ZGY5ZWMyYmMxZWQwYmU0MWYyMTc5NjJmYzFjMzFlM2M2YjAzZjgxYzNhZDM0YTgxMjkzZjAifSwic2lnbmF0dXJlIjoiIn0="",
+ ""expiring_at"": 1510994405,
+ ""imported_taken_at"": 1510907979,
+ ""reel_mentions"": [],
+ ""story_locations"": [],
+ ""story_events"": [],
+ ""story_hashtags"": [],
+ ""story_polls"": [],
+ ""story_feed_media"": [],
+ ""can_reshare"": true,
+ ""supports_reel_reactions"": false
+ }]
+ },
+ {
+ ""id"": 2057461165,
+ ""latest_reel_media"": 1510862508,
+ ""expiring_at"": 1510948908,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 2057461165,
+ ""username"": ""ayria.b"",
+ ""full_name"": ""ayria"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/22157464_122412968458824_5056550025048358912_n.jpg"",
+ ""profile_pic_id"": ""1618215817073442624_2057461165"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 4,
+ ""seen_ranked_position"": 4,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false,
+ ""items"": [{
+ ""taken_at"": 1510862378,
+ ""pk"": 1649556176310660131,
+ ""id"": ""1649556176310660131_2057461165"",
+ ""device_timestamp"": 373165517843589,
+ ""media_type"": 1,
+ ""code"": ""BbkZppGDGwjoXRukhmmEIU0EAw4nI-qPUuHc780"",
+ ""client_cache_key"": ""MTY0OTU1NjE3NjMxMDY2MDEzMQ==.2"",
+ ""filter_type"": 0,
+ ""image_versions2"": {
+ ""candidates"": [{
+ ""width"": 1080,
+ ""height"": 1920,
+ ""url"": ""https://scontent-cdg2-1.cdninstagram.com/vp/31cffb90989f0ebc1027f1d7cf3dd0a0/5A105D39/t58.9792-15/e35/17568037_129576284428483_7628768821515386880_n.jpg?se=7\u0026ig_cache_key=MTY0OTU1NjE3NjMxMDY2MDEzMQ%3D%3D.2""
+ },
+ {
+ ""width"": 240,
+ ""height"": 426,
+ ""url"": ""https://scontent-cdg2-1.cdninstagram.com/vp/41c19e515b51c92502412ca69ef1519c/5A105322/t58.9792-15/e35/p240x240/17568037_129576284428483_7628768821515386880_n.jpg?ig_cache_key=MTY0OTU1NjE3NjMxMDY2MDEzMQ%3D%3D.2""
+ }]
+ },
+ ""original_width"": 1080,
+ ""original_height"": 1920,
+ ""caption_position"": 0.0,
+ ""is_reel_media"": true,
+ ""user"": {
+ ""pk"": 2057461165,
+ ""username"": ""ayria.b"",
+ ""full_name"": ""ayria"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/22157464_122412968458824_5056550025048358912_n.jpg"",
+ ""profile_pic_id"": ""1618215817073442624_2057461165"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""is_unpublished"": false,
+ ""is_favorite"": false
+ },
+ ""caption"": null,
+ ""caption_is_edited"": false,
+ ""photo_of_you"": false,
+ ""can_viewer_save"": true,
+ ""organic_tracking_token"": ""eyJ2ZXJzaW9uIjo1LCJwYXlsb2FkIjp7ImlzX2FuYWx5dGljc190cmFja2VkIjpmYWxzZSwidXVpZCI6IjVjOTRjZWY5MWFlYjQ2MDM5MzVhYWQzMTk0NjYzMjYzMTY0OTU1NjE3NjMxMDY2MDEzMSIsInNlcnZlcl90b2tlbiI6IjE1MTA5MTczMTI0NjN8MTY0OTU1NjE3NjMxMDY2MDEzMXwxNjQ3NzE4NDMyfDY5NTI1MGVkN2NhMWNmNWMyNWEwZGMxZTRmOTg4Y2MyZTVlYTIyNTc5N2I0OWE1NDNiZTZhOWUwM2QzOGQyZDQifSwic2lnbmF0dXJlIjoiIn0="",
+ ""expiring_at"": 1510948778,
+ ""imported_taken_at"": 1510862091,
+ ""reel_mentions"": [],
+ ""story_locations"": [],
+ ""story_events"": [],
+ ""story_hashtags"": [],
+ ""story_polls"": [],
+ ""story_feed_media"": [],
+ ""can_reshare"": true,
+ ""supports_reel_reactions"": false
+ },
+ {
+ ""taken_at"": 1510862508,
+ ""pk"": 1649556777279099195,
+ ""id"": ""1649556777279099195_2057461165"",
+ ""device_timestamp"": 373296285005034,
+ ""media_type"": 1,
+ ""code"": ""BbkZyYyjxE7yF9PECklEfkGDt6C3kodZ2Ss0Nc0"",
+ ""client_cache_key"": ""MTY0OTU1Njc3NzI3OTA5OTE5NQ==.2"",
+ ""filter_type"": 0,
+ ""image_versions2"": {
+ ""candidates"": [{
+ ""width"": 1080,
+ ""height"": 1920,
+ ""url"": ""https://scontent-cdg2-1.cdninstagram.com/vp/c70b71f1afd04a7016a0b06fe02af7a6/5A103CD4/t58.9792-15/e35/18448471_189954088227361_2974203919778971648_n.jpg?se=7\u0026ig_cache_key=MTY0OTU1Njc3NzI3OTA5OTE5NQ%3D%3D.2""
+ },
+ {
+ ""width"": 240,
+ ""height"": 426,
+ ""url"": ""https://scontent-cdg2-1.cdninstagram.com/vp/4d22109912171cdd294f38faaa0cc0d0/5A1081C3/t58.9792-15/e35/p240x240/18448471_189954088227361_2974203919778971648_n.jpg?ig_cache_key=MTY0OTU1Njc3NzI3OTA5OTE5NQ%3D%3D.2""
+ }]
+ },
+ ""original_width"": 1080,
+ ""original_height"": 1920,
+ ""caption_position"": 0.0,
+ ""is_reel_media"": true,
+ ""user"": {
+ ""pk"": 2057461165,
+ ""username"": ""ayria.b"",
+ ""full_name"": ""ayria"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/22157464_122412968458824_5056550025048358912_n.jpg"",
+ ""profile_pic_id"": ""1618215817073442624_2057461165"",
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""is_unpublished"": false,
+ ""is_favorite"": false
+ },
+ ""caption"": null,
+ ""caption_is_edited"": false,
+ ""photo_of_you"": false,
+ ""can_viewer_save"": true,
+ ""organic_tracking_token"": ""eyJ2ZXJzaW9uIjo1LCJwYXlsb2FkIjp7ImlzX2FuYWx5dGljc190cmFja2VkIjpmYWxzZSwidXVpZCI6IjVjOTRjZWY5MWFlYjQ2MDM5MzVhYWQzMTk0NjYzMjYzMTY0OTU1Njc3NzI3OTA5OTE5NSIsInNlcnZlcl90b2tlbiI6IjE1MTA5MTczMTI0NjN8MTY0OTU1Njc3NzI3OTA5OTE5NXwxNjQ3NzE4NDMyfDE4MmFmNTE5YWQ5ZmFhMjlmM2Q1ODliMjA0MThhZDRkYmJkNjcwM2IwMWMwOTY5N2Q0MGI4MGFiZjIzZmMwNmMifSwic2lnbmF0dXJlIjoiIn0="",
+ ""expiring_at"": 1510948908,
+ ""imported_taken_at"": 1510845400,
+ ""reel_mentions"": [],
+ ""story_locations"": [],
+ ""story_events"": [],
+ ""story_hashtags"": [],
+ ""story_polls"": [],
+ ""story_feed_media"": [],
+ ""can_reshare"": true,
+ ""supports_reel_reactions"": false
+ }]
+ },
+ {
+ ""id"": 1489869781,
+ ""latest_reel_media"": 1510903812,
+ ""expiring_at"": 1510990212,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 1489869781,
+ ""username"": ""ali_akbari_1994"",
+ ""full_name"": ""Ali Akbari"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/11008223_1642746932642809_2053218239_a.jpg"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 5,
+ ""seen_ranked_position"": 5,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 5482540873,
+ ""latest_reel_media"": 1510900559,
+ ""expiring_at"": 1510986959,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 5482540873,
+ ""username"": ""_kimixe"",
+ ""full_name"": ""\u269c\u06a9\u0640\u06cc\u0645\u06cc\u0640\u0627 \u062f\u0631\u064e\u062e\u0640\u0640\u0640\u0634\u0627\u0646\u06cc\ud83d\udc78\ud83c\udffb"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/21436207_272984799873060_3437969849836371968_a.jpg"",
+ ""profile_pic_id"": ""1600899676696408725_5482540873"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 6,
+ ""seen_ranked_position"": 6,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 3066946863,
+ ""latest_reel_media"": 1510831151,
+ ""expiring_at"": 1510917551,
+ ""seen"": 0.0,
+ ""can_reply"": false,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 3066946863,
+ ""username"": ""video__tanz"",
+ ""full_name"": ""\ud83d\ude02 Video Tanz \ud83d\ude02"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23279217_302064020275335_2450216195975020544_n.jpg"",
+ ""profile_pic_id"": ""1489831773834723134_3066946863"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 7,
+ ""seen_ranked_position"": 7,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 251137241,
+ ""latest_reel_media"": 1510847715,
+ ""expiring_at"": 1510934115,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 251137241,
+ ""username"": ""svetabily"",
+ ""full_name"": ""Sveta Bilyalova"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/20398229_871582456329183_4794696546299936768_a.jpg"",
+ ""profile_pic_id"": ""1566324341121474832_251137241"",
+ ""is_verified"": true
+ },
+ ""ranked_position"": 8,
+ ""seen_ranked_position"": 8,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 3405890655,
+ ""latest_reel_media"": 1510914372,
+ ""expiring_at"": 1511000772,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 3405890655,
+ ""username"": ""saburi_ali"",
+ ""full_name"": ""\u2604Ali\u26a1\ufe0fSaburi\ud83d\udd38"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/22637548_764050613801850_6552322718602100736_n.jpg"",
+ ""profile_pic_id"": ""1629689145662538438_3405890655"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 9,
+ ""seen_ranked_position"": 9,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 3551724865,
+ ""latest_reel_media"": 1510895779,
+ ""expiring_at"": 1510982179,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": false,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 3551724865,
+ ""username"": ""mehdi_shtoori"",
+ ""full_name"": ""mehdi_shatoori"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23594874_186693181881005_6648547247506063360_n.jpg"",
+ ""profile_pic_id"": ""1649578282054939172_3551724865"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 10,
+ ""seen_ranked_position"": 10,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 38334017,
+ ""latest_reel_media"": 1510852186,
+ ""expiring_at"": 1510938586,
+ ""seen"": 0.0,
+ ""can_reply"": false,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 38334017,
+ ""username"": ""tohi"",
+ ""full_name"": ""Tohi"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/22157401_1164828236984070_3300847736101797888_n.jpg"",
+ ""profile_pic_id"": ""1617773928800265440_38334017"",
+ ""is_verified"": true
+ },
+ ""ranked_position"": 11,
+ ""seen_ranked_position"": 11,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 271236276,
+ ""latest_reel_media"": 1510832936,
+ ""expiring_at"": 1510919336,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 271236276,
+ ""username"": ""donyadadrasan"",
+ ""full_name"": ""\u062f\u0646\u06cc\u0627"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23498668_1768894090082015_6493720728821563392_n.jpg"",
+ ""profile_pic_id"": ""1645538026368962501_271236276"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 12,
+ ""seen_ranked_position"": 12,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 1510966691,
+ ""latest_reel_media"": 1510916639,
+ ""expiring_at"": 1511003039,
+ ""seen"": 0.0,
+ ""can_reply"": false,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 1510966691,
+ ""username"": ""lisaandlena"",
+ ""full_name"": ""Lisa and Lena | Germany\u00ae"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/20184530_1714340778874426_8644379796467351552_a.jpg"",
+ ""profile_pic_id"": ""1564408562074097932_1510966691"",
+ ""is_verified"": true
+ },
+ ""ranked_position"": 13,
+ ""seen_ranked_position"": 13,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 3282438449,
+ ""latest_reel_media"": 1510914206,
+ ""expiring_at"": 1511000606,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 3282438449,
+ ""username"": ""sepehr.k.a.80"",
+ ""full_name"": ""sepehr.k.a.80"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/20759440_133387480611580_3356761454312161280_a.jpg"",
+ ""profile_pic_id"": ""1578253411031495954_3282438449"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 14,
+ ""seen_ranked_position"": 14,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 1561068104,
+ ""latest_reel_media"": 1510856008,
+ ""expiring_at"": 1510942408,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 1561068104,
+ ""username"": ""negin_xaniaristm"",
+ ""full_name"": ""\ud83d\udc8e\u06cc\u0647 \u0646\u06af\u06cc\u0640^\u2022^\u0640\u0646 \u062e\u0633\u0631\u0648\u06cc\u0633\u062a\u200c\u062a\u06cc\u200c\u0627\u0650\u0645\u06cc\ud83d\udc8e"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23507807_128028924552207_1606758449528438784_n.jpg"",
+ ""profile_pic_id"": ""1646591608245492499_1561068104"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 16,
+ ""seen_ranked_position"": 16,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 10245870,
+ ""latest_reel_media"": 1510907836,
+ ""expiring_at"": 1510994236,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 10245870,
+ ""username"": ""amandacerny"",
+ ""full_name"": ""Amanda Cerny"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/22637117_1696268193770897_1780284289452081152_n.jpg"",
+ ""profile_pic_id"": ""1628386071727763294_10245870"",
+ ""is_verified"": true
+ },
+ ""ranked_position"": 17,
+ ""seen_ranked_position"": 17,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 2244850095,
+ ""latest_reel_media"": 1510871575,
+ ""expiring_at"": 1510957975,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 2244850095,
+ ""username"": ""funtv_ir"",
+ ""full_name"": ""FunTV \u272a \u0641\u0627\u0646 \u062a\u06cc \u0648\u06cc"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/21827728_905466152934893_4542388546467528704_n.jpg"",
+ ""profile_pic_id"": ""1568133572379051405_2244850095"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 18,
+ ""seen_ranked_position"": 18,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 12299923,
+ ""latest_reel_media"": 1510877891,
+ ""expiring_at"": 1510964291,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 12299923,
+ ""username"": ""andreaespadatv"",
+ ""full_name"": ""\u15e9\u144e\u15ea\u1587E\u15e9 E\u1515\u146d\u15e9\u15ea\u15e9"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/20905332_1992303564377138_6941782205450420224_a.jpg"",
+ ""profile_pic_id"": ""1585831165661932658_12299923"",
+ ""is_verified"": true
+ },
+ ""ranked_position"": 19,
+ ""seen_ranked_position"": 19,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 1646749288,
+ ""latest_reel_media"": 1510906828,
+ ""expiring_at"": 1510993228,
+ ""seen"": 0.0,
+ ""can_reply"": false,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 1646749288,
+ ""username"": ""jazabtarin_cliphaa"",
+ ""full_name"": ""\ud83d\udd4b\u0628\u0633\u0645 \u0627\u0644\u0644\u0647 \u0627\u0644\u0631\u062d\u0645\u0646 \u0627\u0644\u0631\u062d\u06cc\u0645\ud83d\udd4b"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23347372_180675915816021_4310249219135897600_n.jpg"",
+ ""profile_pic_id"": ""1501663558492258008_1646749288"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 20,
+ ""seen_ranked_position"": 20,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 1259128889,
+ ""latest_reel_media"": 1510904116,
+ ""expiring_at"": 1510990516,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 1259128889,
+ ""username"": ""clipp_video"",
+ ""full_name"": ""\u06a9\u0644\u06cc\u067e \u0648\u06cc\u062f\u0626\u0648(\u062e\u0646\u062f\u0647 \u0641\u0627\u0646 \u0633\u0631\u06af\u0631\u0645\u06cc )"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/22429821_148439145763324_7717555759847833600_n.jpg"",
+ ""profile_pic_id"": ""1308169938154726997_1259128889"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 21,
+ ""seen_ranked_position"": 21,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 442625,
+ ""latest_reel_media"": 1510890967,
+ ""expiring_at"": 1510977367,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 442625,
+ ""username"": ""journeydan"",
+ ""full_name"": ""Daniel Bader"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/11348095_814564621974849_480326611_a.jpg"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 22,
+ ""seen_ranked_position"": 22,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 2437674150,
+ ""latest_reel_media"": 1510862618,
+ ""expiring_at"": 1510949018,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 2437674150,
+ ""username"": ""dubsmash_clip_ir"",
+ ""full_name"": ""\u062f\u0627\u0628\u0633\u0645\u0634_\u06a9\u0644\u06cc\u067e \u0627\u06cc\u0631\u0627\u0646\u06cc"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23507577_1989357354677188_6071511854348238848_n.jpg"",
+ ""profile_pic_id"": ""1565995338656106798_2437674150"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 23,
+ ""seen_ranked_position"": 23,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 1451667254,
+ ""latest_reel_media"": 1510907597,
+ ""expiring_at"": 1510993997,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 1451667254,
+ ""username"": ""ir___photographer"",
+ ""full_name"": ""Photography Ideas"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/20759619_110898839576437_1401961498183467008_a.jpg"",
+ ""profile_pic_id"": ""1579067129738486356_1451667254"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 24,
+ ""seen_ranked_position"": 24,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ },
+ {
+ ""id"": 1548541077,
+ ""latest_reel_media"": 1510845566,
+ ""expiring_at"": 1510931966,
+ ""seen"": 0.0,
+ ""can_reply"": true,
+ ""can_reshare"": true,
+ ""reel_type"": ""user_reel"",
+ ""user"": {
+ ""pk"": 1548541077,
+ ""username"": ""hanjare_talaei"",
+ ""full_name"": ""hanjare talaei \ud83c\udf99\u062d\u0646\u062c\u0631\u0647 \u0637\u0644\u0627\u064a\u0649"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/23101843_1849658215074801_563374214585778176_n.jpg"",
+ ""profile_pic_id"": ""1640555686213844652_1548541077"",
+ ""is_verified"": false
+ },
+ ""ranked_position"": 25,
+ ""seen_ranked_position"": 25,
+ ""muted"": false,
+ ""prefetch_count"": 0,
+ ""has_besties_media"": false
+ }],
+ ""post_live"": {
+ ""post_live_items"": [{
+ ""pk"": ""post_live_1383543459"",
+ ""user"": {
+ ""pk"": 1383543459,
+ ""username"": ""780ir"",
+ ""full_name"": ""\u0647\u0641\u0640 \u0647\u0634\u062a\u0627\u062f | #\u0667\u0668\u0660*"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/21980259_360063074444115_3710275616830914560_n.jpg"",
+ ""profile_pic_id"": ""1532382334209046138_1383543459"",
+ ""is_verified"": false
+ },
+ ""broadcasts"": [{
+ ""id"": 17908970164059694,
+ ""broadcast_status"": ""post_live"",
+ ""dash_manifest"": ""\u003cMPD xmlns=\""urn:mpeg:dash:schema:mpd:2011\"" minBufferTime=\""PT1.500S\"" type=\""static\"" mediaPresentationDuration=\""PT0H16M24.622S\"" maxSegmentDuration=\""PT0H0M2.000S\"" profiles=\""urn:mpeg:dash:profile:isoff-on-demand:2011,http://dashif.org/guidelines/dash264\""\u003e\u003cPeriod duration=\""PT0H16M24.622S\""\u003e\u003cAdaptationSet segmentAlignment=\""true\"" maxWidth=\""396\"" maxHeight=\""704\"" maxFrameRate=\""16000/544\"" par=\""396:704\"" lang=\""und\"" subsegmentAlignment=\""true\"" subsegmentStartsWithSAP=\""1\""\u003e\u003cRepresentation id=\""17895622549102837v\"" mimeType=\""video/mp4\"" codecs=\""avc1.4d401f\"" width=\""396\"" height=\""704\"" frameRate=\""16000/544\"" sar=\""1:1\"" startWithSAP=\""1\"" bandwidth=\""582064\"" FBQualityClass=\""sd\"" FBQualityLabel=\""396w\""\u003e\u003cBaseURL\u003ehttps://scontent-cdg2-1.cdninstagram.com/t72.12950-16/10000000_1740452772915569_6670090197872410624_n.mp4\u003c/BaseURL\u003e\u003cSegmentBase indexRangeExact=\""true\"" indexRange=\""899-6930\""\u003e\u003cInitialization range=\""0-898\""/\u003e\u003c/SegmentBase\u003e\u003c/Representation\u003e\u003c/AdaptationSet\u003e\u003cAdaptationSet segmentAlignment=\""true\"" lang=\""und\"" subsegmentAlignment=\""true\"" subsegmentStartsWithSAP=\""1\""\u003e\u003cRepresentation id=\""17895622549102837a\"" mimeType=\""audio/mp4\"" codecs=\""mp4a.40.2\"" audioSamplingRate=\""44100\"" startWithSAP=\""1\"" bandwidth=\""50283\""\u003e\u003cAudioChannelConfiguration schemeIdUri=\""urn:mpeg:dash:23003:3:audio_channel_configuration:2011\"" value=\""2\""/\u003e\u003cBaseURL\u003ehttps://scontent-cdg2-1.cdninstagram.com/t72.12950-16/23586292_132647884105636_1354989047184883712_n.mp4\u003c/BaseURL\u003e\u003cSegmentBase indexRangeExact=\""true\"" indexRange=\""835-6794\""\u003e\u003cInitialization range=\""0-834\""/\u003e\u003c/SegmentBase\u003e\u003c/Representation\u003e\u003c/AdaptationSet\u003e\u003c/Period\u003e\u003c/MPD\u003e"",
+ ""expire_at"": 1510939433,
+ ""encoding_tag"": ""instagram_dash_remuxed"",
+ ""internal_only"": false,
+ ""number_of_qualities"": 1,
+ ""cover_frame_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.9792-15/18979052_757168924407392_3730758058167500800_n.jpg"",
+ ""broadcast_owner"": {
+ ""pk"": 1383543459,
+ ""username"": ""780ir"",
+ ""full_name"": ""\u0647\u0641\u0640 \u0647\u0634\u062a\u0627\u062f | #\u0667\u0668\u0660*"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/21980259_360063074444115_3710275616830914560_n.jpg"",
+ ""profile_pic_id"": ""1532382334209046138_1383543459"",
+ ""friendship_status"": {
+ ""following"": true,
+ ""followed_by"": false,
+ ""blocking"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false
+ },
+ ""published_time"": 1510852005,
+ ""media_id"": ""1649468551528436844_1383543459"",
+ ""broadcast_message"": """",
+ ""organic_tracking_token"": ""eyJ2ZXJzaW9uIjo1LCJwYXlsb2FkIjp7ImlzX2FuYWx5dGljc190cmFja2VkIjp0cnVlLCJ1dWlkIjoiNWM5NGNlZjkxYWViNDYwMzkzNWFhZDMxOTQ2NjMyNjMxNjQ5NDY4NTUxNTI4NDM2ODQ0Iiwic2VydmVyX3Rva2VuIjoiMTUxMDkxNzMxMjM2OXwxNjQ5NDY4NTUxNTI4NDM2ODQ0fDE2NDc3MTg0MzJ8NjM2ODAyZmVjMzA5MDBjN2YzZDY3ZWQzZTgxODliYmM5M2ViZWI4MTFiYzIwNzdhMzM2ZjMxMDI4ZjIzYWJlMiJ9LCJzaWduYXR1cmUiOiIifQ==""
+ },
+ {
+ ""id"": 17883870826134571,
+ ""broadcast_status"": ""post_live"",
+ ""dash_manifest"": ""\u003cMPD xmlns=\""urn:mpeg:dash:schema:mpd:2011\"" minBufferTime=\""PT1.500S\"" type=\""static\"" mediaPresentationDuration=\""PT0H14M6.835S\"" maxSegmentDuration=\""PT0H0M2.000S\"" profiles=\""urn:mpeg:dash:profile:isoff-on-demand:2011,http://dashif.org/guidelines/dash264\""\u003e\u003cPeriod duration=\""PT0H14M6.835S\""\u003e\u003cAdaptationSet segmentAlignment=\""true\"" maxWidth=\""396\"" maxHeight=\""704\"" maxFrameRate=\""16000/528\"" par=\""396:704\"" lang=\""und\"" subsegmentAlignment=\""true\"" subsegmentStartsWithSAP=\""1\""\u003e\u003cRepresentation id=\""17892232666080922v\"" mimeType=\""video/mp4\"" codecs=\""avc1.4d401f\"" width=\""396\"" height=\""704\"" frameRate=\""16000/528\"" sar=\""1:1\"" startWithSAP=\""1\"" bandwidth=\""537007\"" FBQualityClass=\""sd\"" FBQualityLabel=\""396w\""\u003e\u003cBaseURL\u003ehttps://scontent-cdg2-1.cdninstagram.com/t72.12950-16/10000000_170347730220671_9006027248360226816_n.mp4\u003c/BaseURL\u003e\u003cSegmentBase indexRangeExact=\""true\"" indexRange=\""899-6054\""\u003e\u003cInitialization range=\""0-898\""/\u003e\u003c/SegmentBase\u003e\u003c/Representation\u003e\u003c/AdaptationSet\u003e\u003cAdaptationSet segmentAlignment=\""true\"" lang=\""und\"" subsegmentAlignment=\""true\"" subsegmentStartsWithSAP=\""1\""\u003e\u003cRepresentation id=\""17892232666080922a\"" mimeType=\""audio/mp4\"" codecs=\""mp4a.40.2\"" audioSamplingRate=\""44100\"" startWithSAP=\""1\"" bandwidth=\""50316\""\u003e\u003cAudioChannelConfiguration schemeIdUri=\""urn:mpeg:dash:23003:3:audio_channel_configuration:2011\"" value=\""2\""/\u003e\u003cBaseURL\u003ehttps://scontent-cdg2-1.cdninstagram.com/t72.12950-16/18743538_2044045792491235_3540743782959939584_n.mp4\u003c/BaseURL\u003e\u003cSegmentBase indexRangeExact=\""true\"" indexRange=\""835-5966\""\u003e\u003cInitialization range=\""0-834\""/\u003e\u003c/SegmentBase\u003e\u003c/Representation\u003e\u003c/AdaptationSet\u003e\u003c/Period\u003e\u003c/MPD\u003e"",
+ ""expire_at"": 1510945469,
+ ""encoding_tag"": ""instagram_dash_remuxed"",
+ ""internal_only"": false,
+ ""number_of_qualities"": 1,
+ ""cover_frame_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.9792-15/16751331_1936086796654040_1708202798216118272_n.jpg"",
+ ""broadcast_owner"": {
+ ""pk"": 1383543459,
+ ""username"": ""780ir"",
+ ""full_name"": ""\u0647\u0641\u0640 \u0647\u0634\u062a\u0627\u062f | #\u0667\u0668\u0660*"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/21980259_360063074444115_3710275616830914560_n.jpg"",
+ ""profile_pic_id"": ""1532382334209046138_1383543459"",
+ ""friendship_status"": {
+ ""following"": true,
+ ""followed_by"": false,
+ ""blocking"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false
+ },
+ ""published_time"": 1510858155,
+ ""media_id"": ""1649520175491644674_1383543459"",
+ ""broadcast_message"": """",
+ ""organic_tracking_token"": ""eyJ2ZXJzaW9uIjo1LCJwYXlsb2FkIjp7ImlzX2FuYWx5dGljc190cmFja2VkIjp0cnVlLCJ1dWlkIjoiNWM5NGNlZjkxYWViNDYwMzkzNWFhZDMxOTQ2NjMyNjMxNjQ5NTIwMTc1NDkxNjQ0Njc0Iiwic2VydmVyX3Rva2VuIjoiMTUxMDkxNzMxMjM3NnwxNjQ5NTIwMTc1NDkxNjQ0Njc0fDE2NDc3MTg0MzJ8MGE5OTlhNWY1NjM2ZDM2ZmMwNWYwZDFhYWNiMGUzY2QyNzhlOTY1NGE4YjY4MmQ0YzMwMGIyZWNkY2U0MDFmMiJ9LCJzaWduYXR1cmUiOiIifQ==""
+ },
+ {
+ ""id"": 17881002145166791,
+ ""broadcast_status"": ""post_live"",
+ ""dash_manifest"": ""\u003cMPD xmlns=\""urn:mpeg:dash:schema:mpd:2011\"" minBufferTime=\""PT1.500S\"" type=\""static\"" mediaPresentationDuration=\""PT0H14M30.033S\"" maxSegmentDuration=\""PT0H0M2.000S\"" profiles=\""urn:mpeg:dash:profile:isoff-on-demand:2011,http://dashif.org/guidelines/dash264\""\u003e\u003cPeriod duration=\""PT0H14M30.033S\""\u003e\u003cAdaptationSet segmentAlignment=\""true\"" maxWidth=\""396\"" maxHeight=\""704\"" maxFrameRate=\""16000/544\"" par=\""396:704\"" lang=\""und\"" subsegmentAlignment=\""true\"" subsegmentStartsWithSAP=\""1\""\u003e\u003cRepresentation id=\""17908553083038374v\"" mimeType=\""video/mp4\"" codecs=\""avc1.4d401f\"" width=\""396\"" height=\""704\"" frameRate=\""16000/544\"" sar=\""1:1\"" startWithSAP=\""1\"" bandwidth=\""772699\"" FBQualityClass=\""sd\"" FBQualityLabel=\""396w\""\u003e\u003cBaseURL\u003ehttps://scontent-cdg2-1.cdninstagram.com/t72.12950-16/10000000_1950041318580288_3640943338456088576_n.mp4\u003c/BaseURL\u003e\u003cSegmentBase indexRangeExact=\""true\"" indexRange=\""899-6174\""\u003e\u003cInitialization range=\""0-898\""/\u003e\u003c/SegmentBase\u003e\u003c/Representation\u003e\u003c/AdaptationSet\u003e\u003cAdaptationSet segmentAlignment=\""true\"" lang=\""und\"" subsegmentAlignment=\""true\"" subsegmentStartsWithSAP=\""1\""\u003e\u003cRepresentation id=\""17908553083038374a\"" mimeType=\""audio/mp4\"" codecs=\""mp4a.40.2\"" audioSamplingRate=\""44100\"" startWithSAP=\""1\"" bandwidth=\""50308\""\u003e\u003cAudioChannelConfiguration schemeIdUri=\""urn:mpeg:dash:23003:3:audio_channel_configuration:2011\"" value=\""2\""/\u003e\u003cBaseURL\u003ehttps://scontent-cdg2-1.cdninstagram.com/t72.12950-16/19097229_134461557323949_4728992527447752704_n.mp4\u003c/BaseURL\u003e\u003cSegmentBase indexRangeExact=\""true\"" indexRange=\""835-6098\""\u003e\u003cInitialization range=\""0-834\""/\u003e\u003c/SegmentBase\u003e\u003c/Representation\u003e\u003c/AdaptationSet\u003e\u003c/Period\u003e\u003c/MPD\u003e"",
+ ""expire_at"": 1510920674,
+ ""encoding_tag"": ""instagram_dash_remuxed"",
+ ""internal_only"": false,
+ ""number_of_qualities"": 1,
+ ""cover_frame_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.9792-15/14964412_932613113564850_5738793949246521344_n.jpg"",
+ ""broadcast_owner"": {
+ ""pk"": 1383543459,
+ ""username"": ""780ir"",
+ ""full_name"": ""\u0647\u0641\u0640 \u0647\u0634\u062a\u0627\u062f | #\u0667\u0668\u0660*"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/21980259_360063074444115_3710275616830914560_n.jpg"",
+ ""profile_pic_id"": ""1532382334209046138_1383543459"",
+ ""friendship_status"": {
+ ""following"": true,
+ ""followed_by"": false,
+ ""blocking"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false
+ },
+ ""published_time"": 1510833390,
+ ""media_id"": ""1649312402740902617_1383543459"",
+ ""broadcast_message"": """",
+ ""organic_tracking_token"": ""eyJ2ZXJzaW9uIjo1LCJwYXlsb2FkIjp7ImlzX2FuYWx5dGljc190cmFja2VkIjp0cnVlLCJ1dWlkIjoiNWM5NGNlZjkxYWViNDYwMzkzNWFhZDMxOTQ2NjMyNjMxNjQ5MzEyNDAyNzQwOTAyNjE3Iiwic2VydmVyX3Rva2VuIjoiMTUxMDkxNzMxMjM4NnwxNjQ5MzEyNDAyNzQwOTAyNjE3fDE2NDc3MTg0MzJ8ZmUwYWNiYjdiNmViOTViNWU3YThjYzVlNzMxMGQ5ZTY1ZTIzZWY0MWI2NTdmNWZkZDA5Yjg3NTQzMDI2MWY0ZCJ9LCJzaWduYXR1cmUiOiIifQ==""
+ },
+ {
+ ""id"": 17909222266016333,
+ ""broadcast_status"": ""post_live"",
+ ""dash_manifest"": ""\u003cMPD xmlns=\""urn:mpeg:dash:schema:mpd:2011\"" minBufferTime=\""PT1.500S\"" type=\""static\"" mediaPresentationDuration=\""PT0H8M20.366S\"" maxSegmentDuration=\""PT0H0M2.000S\"" profiles=\""urn:mpeg:dash:profile:isoff-on-demand:2011,http://dashif.org/guidelines/dash264\""\u003e\u003cPeriod duration=\""PT0H8M20.366S\""\u003e\u003cAdaptationSet segmentAlignment=\""true\"" maxWidth=\""396\"" maxHeight=\""704\"" maxFrameRate=\""16000/528\"" par=\""396:704\"" lang=\""und\"" subsegmentAlignment=\""true\"" subsegmentStartsWithSAP=\""1\""\u003e\u003cRepresentation id=\""17848696471221278v\"" mimeType=\""video/mp4\"" codecs=\""avc1.4d401f\"" width=\""396\"" height=\""704\"" frameRate=\""16000/528\"" sar=\""1:1\"" startWithSAP=\""1\"" bandwidth=\""766114\"" FBQualityClass=\""sd\"" FBQualityLabel=\""396w\""\u003e\u003cBaseURL\u003ehttps://scontent-cdg2-1.cdninstagram.com/t72.12950-16/10000000_130426674268267_3521803917782417408_n.mp4\u003c/BaseURL\u003e\u003cSegmentBase indexRangeExact=\""true\"" indexRange=\""899-4014\""\u003e\u003cInitialization range=\""0-898\""/\u003e\u003c/SegmentBase\u003e\u003c/Representation\u003e\u003c/AdaptationSet\u003e\u003cAdaptationSet segmentAlignment=\""true\"" lang=\""und\"" subsegmentAlignment=\""true\"" subsegmentStartsWithSAP=\""1\""\u003e\u003cRepresentation id=\""17848696471221278a\"" mimeType=\""audio/mp4\"" codecs=\""mp4a.40.2\"" audioSamplingRate=\""44100\"" startWithSAP=\""1\"" bandwidth=\""50493\""\u003e\u003cAudioChannelConfiguration schemeIdUri=\""urn:mpeg:dash:23003:3:audio_channel_configuration:2011\"" value=\""2\""/\u003e\u003cBaseURL\u003ehttps://scontent-cdg2-1.cdninstagram.com/t72.12950-16/19104379_545857249086594_8255680261132386304_n.mp4\u003c/BaseURL\u003e\u003cSegmentBase indexRangeExact=\""true\"" indexRange=\""835-3878\""\u003e\u003cInitialization range=\""0-834\""/\u003e\u003c/SegmentBase\u003e\u003c/Representation\u003e\u003c/AdaptationSet\u003e\u003c/Period\u003e\u003c/MPD\u003e"",
+ ""expire_at"": 1510987021,
+ ""encoding_tag"": ""instagram_dash_remuxed"",
+ ""internal_only"": false,
+ ""number_of_qualities"": 1,
+ ""cover_frame_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.9792-15/16994044_137486973681364_2459237027455959040_n.jpg"",
+ ""broadcast_owner"": {
+ ""pk"": 1383543459,
+ ""username"": ""780ir"",
+ ""full_name"": ""\u0647\u0641\u0640 \u0647\u0634\u062a\u0627\u062f | #\u0667\u0668\u0660*"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-cdg2-1.cdninstagram.com/t51.2885-19/s150x150/21980259_360063074444115_3710275616830914560_n.jpg"",
+ ""profile_pic_id"": ""1532382334209046138_1383543459"",
+ ""friendship_status"": {
+ ""following"": true,
+ ""followed_by"": false,
+ ""blocking"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false
+ },
+ ""published_time"": 1510900081,
+ ""media_id"": ""1649871864962943492_1383543459"",
+ ""broadcast_message"": """",
+ ""organic_tracking_token"": ""eyJ2ZXJzaW9uIjo1LCJwYXlsb2FkIjp7ImlzX2FuYWx5dGljc190cmFja2VkIjp0cnVlLCJ1dWlkIjoiNWM5NGNlZjkxYWViNDYwMzkzNWFhZDMxOTQ2NjMyNjMxNjQ5ODcxODY0OTYyOTQzNDkyIiwic2VydmVyX3Rva2VuIjoiMTUxMDkxNzMxMjM5M3wxNjQ5ODcxODY0OTYyOTQzNDkyfDE2NDc3MTg0MzJ8NTdlMThmMjZjZGZmZTE4ZTI4OGU1ODU3NDAzNzFkMzhmZmU1ZWMxYmI0NzYzOTcyMTYyNzM5YTBhMjczYTQ5YSJ9LCJzaWduYXR1cmUiOiIifQ==""
+ }],
+ ""last_seen_broadcast_ts"": 0,
+ ""ranked_position"": 15,
+ ""seen_ranked_position"": 0,
+ ""muted"": false,
+ ""can_reply"": false,
+ ""can_reshare"": false
+ }]
+ },
+ ""story_ranking_token"": ""6ed23f2e-b27b-4dc3-beba-a19a0439e384"",
+ ""broadcasts"": [],
+ ""face_filter_nux_version"": 4,
+ ""has_new_nux_story"": false,
+ ""status"": ""ok""
+}";
+
+ [Fact]
+ public void ConvertReelFeedTest()
+ {
+ var storyFeedResponse = JsonConvert.DeserializeObject(testJson);
+ var fabric = ConvertersHelper.GetDefaultFabric();
+ var result = fabric.GetStoryFeedConverter(storyFeedResponse).Convert();
+ Assert.NotNull(result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/InstaSharper.Tests/Infrastructure/UserConverterTest.cs b/InstaSharper.Tests/Infrastructure/UserConverterTest.cs
new file mode 100644
index 00000000..808d4b1c
--- /dev/null
+++ b/InstaSharper.Tests/Infrastructure/UserConverterTest.cs
@@ -0,0 +1,703 @@
+using System.Linq;
+using InstaSharper.Classes.ResponseWrappers;
+using InstaSharper.Helpers;
+using Newtonsoft.Json;
+using Xunit;
+
+namespace InstaSharper.Tests.Infrastructure
+{
+ [Trait("Category", "Infrastructure")]
+ public class UserConverterTest
+ {
+ private const string testJson = @"{
+ ""num_results"": 36,
+ ""users"": [{
+ ""pk"": 1816494776,
+ ""username"": ""codziennysuchar"",
+ ""full_name"": ""Codzienny Suchar Humor Memy"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/11244021_1016245205072659_328649662_a.jpg"",
+ ""friendship_status"": {
+ ""following"": true,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 463666,
+ ""byline"": ""463k followers"",
+ ""social_context"": ""Following"",
+ ""search_social_context"": ""Following"",
+ ""mutual_followers_count"": 8.0,
+ ""unseen_count"": 1
+ }, {
+ ""pk"": 4390037188,
+ ""username"": ""_najlepsze.suchary"",
+ ""full_name"": ""Codzienny_suchar"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/14582494_1641939916100038_3059248674581250048_n.jpg"",
+ ""profile_pic_id"": ""1423287750286768474_4390037188"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 3398,
+ ""byline"": ""3398 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 2071863124,
+ ""username"": ""codzienny_suchar"",
+ ""full_name"": ""codzienny suchar"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/10518138_478803852289501_1249129511_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 565,
+ ""byline"": ""565 followers"",
+ ""mutual_followers_count"": 4.23
+ }, {
+ ""pk"": 2292120036,
+ ""username"": ""codziennysuchar_"",
+ ""full_name"": ""CodziennySucharek\u00a2"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/12071063_791734954269121_1518685845_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 85,
+ ""byline"": ""85 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 4299660758,
+ ""username"": ""codziennysuchar143"",
+ ""full_name"": ""#codziennysuchar"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/14712311_1386416128048966_6072005659623161856_a.jpg"",
+ ""profile_pic_id"": ""1410766283506563741_4299660758"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 45,
+ ""byline"": ""45 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 6223038622,
+ ""username"": ""_codzienny_suchar_"",
+ ""full_name"": ""codzienny suchar"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/22580089_357978407993952_2464035214595194880_n.jpg"",
+ ""profile_pic_id"": ""1626063587179128120_6223038622"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 32,
+ ""byline"": ""32 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 3186683532,
+ ""username"": ""_codzienny_suchar._"",
+ ""full_name"": """",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/13129611_465250017018877_1876717231_a.jpg"",
+ ""profile_pic_id"": ""1239795253686777462_3186683532"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 40,
+ ""byline"": ""40 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 3479771356,
+ ""username"": ""_codziennysuchar_"",
+ ""full_name"": ""\ud83d\ude00 Codzienny suchar! \ud83d\ude00"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/13531793_1617545068557916_1945776659_a.jpg"",
+ ""profile_pic_id"": ""1283581678362859682_3479771356"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 19,
+ ""byline"": ""19 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 2969669697,
+ ""username"": ""codzienny__suchar"",
+ ""full_name"": ""codziennysuchar"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/11349423_955148704532172_366023392_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 49,
+ ""byline"": ""49 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 2267989776,
+ ""username"": ""codziennysuchar1"",
+ ""full_name"": ""codziennysuchar"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://instagram.ftxl1-1.fna.fbcdn.net/t51.2885-19/11906329_960233084022564_1448528159_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": true,
+ ""follower_count"": 10,
+ ""byline"": ""10 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 2365761043,
+ ""username"": ""codziennysuchareg"",
+ ""full_name"": ""codziennysuchareg"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/12353364_846217685497843_396153855_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 13,
+ ""byline"": ""13 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 4918495064,
+ ""username"": ""codziennysuchar10"",
+ ""full_name"": ""Codzienny Suchar"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/17265880_157360331452947_2547629150919720960_a.jpg"",
+ ""profile_pic_id"": ""1479246617067586083_4918495064"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 40,
+ ""byline"": ""40 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 2898853357,
+ ""username"": ""jdisowskyyx"",
+ ""full_name"": ""Codziennysuchar LOL\ud83d\ude1c\ud83d\ude04\ud83d\ude0e"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/13092489_1032479350180187_480622312_a.jpg"",
+ ""profile_pic_id"": ""1240517337186335492_2898853357"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": true,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 24,
+ ""byline"": ""24 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 2288964948,
+ ""username"": ""codzienny.suchar"",
+ ""full_name"": ""Suchar Codzienny"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/12269875_1617130481885815_92792324_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 64,
+ ""byline"": ""64 followers"",
+ ""mutual_followers_count"": ""wtf going on here 10""
+ }, {
+ ""pk"": 2869035614,
+ ""username"": ""codzienny.sucharek"",
+ ""full_name"": ""Codzienny.sucharek"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/12547256_584493841706454_1681254975_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 21,
+ ""byline"": ""21 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 4373567288,
+ ""username"": ""codzienny_suchar_dnia"",
+ ""full_name"": ""Klara"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/15803493_328997667500308_2950628599478091776_a.jpg"",
+ ""profile_pic_id"": ""1422395872512007684_4373567288"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 6,
+ ""byline"": ""6 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 3141115423,
+ ""username"": ""taylornator1989"",
+ ""full_name"": ""POLECAM codziennysuchar!!!"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/13187945_283320095335534_1866674286_a.jpg"",
+ ""profile_pic_id"": ""1260222356237230343_3141115423"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 35,
+ ""byline"": ""35 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 4670037348,
+ ""username"": ""codzienny___suchar"",
+ ""full_name"": ""Suchary i Memy"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/16465599_1842829409324069_1856675956463239168_a.jpg"",
+ ""profile_pic_id"": ""1453492070248861927_4670037348"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 10,
+ ""byline"": ""10 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 3593042169,
+ ""username"": ""_codziennysuchar"",
+ ""full_name"": ""_codziennysuchar"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/13767601_920771888051908_1782552445_a.jpg"",
+ ""profile_pic_id"": ""1303857380802939487_3593042169"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 16,
+ ""byline"": ""16 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 6021270917,
+ ""username"": ""codzienny_suchar2004"",
+ ""full_name"": "".."",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://instagram.ftxl1-1.fna.fbcdn.net/t51.2885-19/11906329_960233084022564_1448528159_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": true,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": true,
+ ""follower_count"": 10,
+ ""byline"": ""10 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 3431371153,
+ ""username"": ""codzienny.suchar_"",
+ ""full_name"": ""Codzienny Suchar"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/13385911_1737718929816684_1453121998_a.jpg"",
+ ""profile_pic_id"": ""1276045232836840047_3431371153"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 8,
+ ""byline"": ""8 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 2981506650,
+ ""username"": ""_codzienny_suchar"",
+ ""full_name"": """",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/10817631_479740075550561_1982476853_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 10,
+ ""byline"": ""10 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 5892966471,
+ ""username"": ""codzienny_suchareczek"",
+ ""full_name"": ""\ud83d\ude02codzinna dawka \u015bmiechu\ud83d\ude02"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/20904967_1343774645741537_2922481076037222400_a.jpg"",
+ ""profile_pic_id"": ""1583925224255829184_5892966471"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 18,
+ ""byline"": ""18 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 3015019252,
+ ""username"": ""codzienny__sucharek"",
+ ""full_name"": """",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/10632224_471179623073948_2122634524_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 4,
+ ""byline"": ""4 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 2141568556,
+ ""username"": ""codzienny_suchar_1"",
+ ""full_name"": ""codzienny Suchar"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/12276961_1527174690937301_745676031_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": true,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 64,
+ ""byline"": ""64 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 2248225276,
+ ""username"": ""codzienny_sucharek"",
+ ""full_name"": """",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/12338890_556623717824871_1971485021_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 88,
+ ""byline"": ""88 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 2182521594,
+ ""username"": ""codziennysucharek"",
+ ""full_name"": ""codziennysucharek"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/11950493_1021972774500543_1552776432_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 26,
+ ""byline"": ""26 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 2246594474,
+ ""username"": ""codzienny_suchar_"",
+ ""full_name"": ""suchar"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://instagram.ftxl1-1.fna.fbcdn.net/t51.2885-19/11906329_960233084022564_1448528159_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": true,
+ ""follower_count"": 6,
+ ""byline"": ""6 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 3030330532,
+ ""username"": ""_____codziennysuchar_____"",
+ ""full_name"": """",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://instagram.ftxl1-1.fna.fbcdn.net/t51.2885-19/11906329_960233084022564_1448528159_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": true,
+ ""follower_count"": 0,
+ ""byline"": ""0 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 3281163757,
+ ""username"": ""codziennysuchar2"",
+ ""full_name"": ""Suchar Codzienny"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/13258846_1692403691024457_272839865_a.jpg"",
+ ""profile_pic_id"": ""1261036094132762712_3281163757"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 1,
+ ""byline"": ""1 follower"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 3214950254,
+ ""username"": ""codziennysucharekkk"",
+ ""full_name"": ""codzienny-sucharek"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://instagram.ftxl1-1.fna.fbcdn.net/t51.2885-19/11906329_960233084022564_1448528159_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": true,
+ ""follower_count"": 0,
+ ""byline"": ""0 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 3698151442,
+ ""username"": ""codziennysuchar8"",
+ ""full_name"": ""Suchar Dnia"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/14073336_1683619201961289_1832154875_a.jpg"",
+ ""profile_pic_id"": ""1322280126667234202_3698151442"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 6,
+ ""byline"": ""6 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 5352527941,
+ ""username"": ""codzienny_suchar.pl"",
+ ""full_name"": ""Sucharek"",
+ ""is_private"": true,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/17934680_1433837510000277_1688326230736109568_a.jpg"",
+ ""profile_pic_id"": ""1496469540404649383_5352527941"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": true,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 0,
+ ""byline"": ""0 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 5612429408,
+ ""username"": ""codzienny_suchar1"",
+ ""full_name"": ""codzienny suchar"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://scontent-frt3-2.cdninstagram.com/t51.2885-19/s150x150/19227720_307764163005012_1840796191059607552_a.jpg"",
+ ""profile_pic_id"": ""1539108474653437325_5612429408"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": false,
+ ""follower_count"": 0,
+ ""byline"": ""0 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 5571319582,
+ ""username"": ""codzienny_sucharxddd"",
+ ""full_name"": ""Codzienny suchar"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://instagram.ftxl1-1.fna.fbcdn.net/t51.2885-19/11906329_960233084022564_1448528159_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": true,
+ ""follower_count"": 2,
+ ""byline"": ""2 followers"",
+ ""mutual_followers_count"": 0.0
+ }, {
+ ""pk"": 5867597536,
+ ""username"": ""codzienny_suchar_elo230"",
+ ""full_name"": ""myszka miki"",
+ ""is_private"": false,
+ ""profile_pic_url"": ""https://instagram.ftxl1-1.fna.fbcdn.net/t51.2885-19/11906329_960233084022564_1448528159_a.jpg"",
+ ""friendship_status"": {
+ ""following"": false,
+ ""is_private"": false,
+ ""incoming_request"": false,
+ ""outgoing_request"": false,
+ ""is_bestie"": false
+ },
+ ""is_verified"": false,
+ ""has_anonymous_profile_picture"": true,
+ ""follower_count"": 1,
+ ""byline"": ""1 follower"",
+ ""mutual_followers_count"": 0.0
+ }
+ ],
+ ""has_more"": false,
+ ""rank_token"": ""3b0955a3-c0b1-403a-942f-8965d0e96eaf"",
+ ""status"": ""ok""
+}";
+
+ [Theory]
+ [InlineData("codziennysuchar")]
+ [InlineData("codzienny_suchar")]
+ [InlineData("codzienny.suchar")]
+ public void UserResponseConverterTest(string username)
+ {
+ var response = JsonConvert.DeserializeObject(testJson);
+ var user = response.Users?.FirstOrDefault(u => u.UserName == username);
+ var fabric = ConvertersHelper.GetDefaultFabric();
+ var converter = fabric.GetUserConverter(user);
+ var result = converter.Convert();
+ Assert.NotNull(result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/InstaSharper.Tests/Utils/TestHelpers.cs b/InstaSharper.Tests/Utils/TestHelpers.cs
index 4586ac7b..3f226500 100644
--- a/InstaSharper.Tests/Utils/TestHelpers.cs
+++ b/InstaSharper.Tests/Utils/TestHelpers.cs
@@ -4,35 +4,18 @@
using InstaSharper.API;
using InstaSharper.API.Builder;
using InstaSharper.Classes;
-using InstaSharper.Classes.Android.DeviceInfo;
using InstaSharper.Helpers;
-using InstaSharper.Logger;
using Xunit.Abstractions;
namespace InstaSharper.Tests.Utils
{
public class TestHelpers
{
- public static IInstaApi GetDefaultInstaApiInstance(string username)
- {
- var device = AndroidDeviceGenerator.GetByName(AndroidDevices.SAMSUNG_NOTE3);
- var requestMessage = ApiRequestMessage.FromDevice(device);
- var apiInstance = InstaApiBuilder.CreateBuilder()
- .SetUserName(username)
- .UseLogger(new DebugLogger(LogLevel.All))
- .SetApiRequestMessage(requestMessage)
- .Build();
- return apiInstance;
- }
-
public static IInstaApi GetDefaultInstaApiInstance(UserSessionData user)
{
- var device = AndroidDeviceGenerator.GetByName(AndroidDevices.SAMSUNG_NOTE3);
- var requestMessage = ApiRequestMessage.FromDevice(device);
var apiInstance = InstaApiBuilder.CreateBuilder()
.SetUser(user)
- .SetApiRequestMessage(requestMessage)
- .SetRequestDelay(TimeSpan.FromSeconds(2))
+ .SetRequestDelay(TimeSpan.FromSeconds(5))
.Build();
return apiInstance;
}
@@ -50,12 +33,9 @@ public static IInstaApi GetProxifiedInstaApiInstance(UserSessionData user, Insta
public static async Task Login(IInstaApi apiInstance, ITestOutputHelper output)
{
var loginResult = await apiInstance.LoginAsync();
- if (!loginResult.Succeeded)
- {
- output.WriteLine($"Can't login: {loginResult.Info.Message}");
- return false;
- }
- return true;
+ if (loginResult.Succeeded) return true;
+ output.WriteLine($"Can't login: {loginResult.Info.Message}");
+ return false;
}
}
}
\ No newline at end of file
diff --git a/InstaSharper/API/Builder/IInstaApiBuilder.cs b/InstaSharper/API/Builder/IInstaApiBuilder.cs
index d4600539..02762f2f 100644
--- a/InstaSharper/API/Builder/IInstaApiBuilder.cs
+++ b/InstaSharper/API/Builder/IInstaApiBuilder.cs
@@ -8,13 +8,54 @@ namespace InstaSharper.API.Builder
{
public interface IInstaApiBuilder
{
+ ///
+ /// Create new API instance
+ ///
+ /// API instance
IInstaApi Build();
+
+ ///
+ /// Use custom logger
+ ///
+ /// IInstaLogger implementation
+ /// API Builder
IInstaApiBuilder UseLogger(IInstaLogger logger);
+
+ ///
+ /// Set specific HttpClient
+ ///
+ /// HttpClient
+ /// API Builder
IInstaApiBuilder UseHttpClient(HttpClient httpClient);
+
+ ///
+ /// Set custom HttpClientHandler to be able to use certain features, e.g Proxy and so on
+ ///
+ /// HttpClientHandler
+ /// API Builder
IInstaApiBuilder UseHttpClientHandler(HttpClientHandler handler);
- IInstaApiBuilder SetUserName(string username);
+
+
+ ///
+ /// Specify user login, password from here
+ ///
+ /// User auth data
+ /// API Builder
IInstaApiBuilder SetUser(UserSessionData user);
+
+ ///
+ /// Set custom request message. Used to be able to customize device info.
+ ///
+ /// Custom request message object
+ /// Please, do not use if you don't know what you are doing
+ /// API Builder
IInstaApiBuilder SetApiRequestMessage(ApiRequestMessage requestMessage);
+
+ ///
+ /// Set delay between requests. Useful when API supposed to be used for mass-bombing.
+ ///
+ /// Timespan delay
+ /// API Builder
IInstaApiBuilder SetRequestDelay(TimeSpan delay);
}
}
\ No newline at end of file
diff --git a/InstaSharper/API/Builder/InstaApiBuilder.cs b/InstaSharper/API/Builder/InstaApiBuilder.cs
index 48497026..0f412554 100644
--- a/InstaSharper/API/Builder/InstaApiBuilder.cs
+++ b/InstaSharper/API/Builder/InstaApiBuilder.cs
@@ -8,10 +8,7 @@ namespace InstaSharper.API.Builder
{
public class InstaApiBuilder : IInstaApiBuilder
{
- private static readonly Lazy LazyInstance =
- new Lazy(() => new InstaApiBuilder());
-
- private TimeSpan _delay;
+ private TimeSpan _delay = TimeSpan.Zero;
private AndroidDevice _device;
private HttpClient _httpClient;
private HttpClientHandler _httpHandler = new HttpClientHandler();
@@ -24,10 +21,17 @@ private InstaApiBuilder()
{
}
- public static InstaApiBuilder Instance => LazyInstance.Value;
-
+ ///
+ /// Create new API instance
+ ///
+ ///
+ /// API instance
+ ///
+ /// User auth data must be specified
public IInstaApi Build()
{
+ if (_user == null)
+ throw new ArgumentNullException("User auth data must be specified");
if (_httpClient == null)
_httpClient = new HttpClient(_httpHandler) {BaseAddress = new Uri(InstaApiConstants.INSTAGRAM_URL)};
@@ -47,6 +51,7 @@ public IInstaApi Build()
if (string.IsNullOrEmpty(_requestMessage.password)) _requestMessage.password = _user?.Password;
if (string.IsNullOrEmpty(_requestMessage.username)) _requestMessage.username = _user?.UserName;
+
if (_device == null && !string.IsNullOrEmpty(_requestMessage.device_id))
_device = AndroidDeviceGenerator.GetById(_requestMessage.device_id);
if (_device == null) AndroidDeviceGenerator.GetRandomAndroidDevice();
@@ -59,48 +64,91 @@ public IInstaApi Build()
return instaApi;
}
+ ///
+ /// Use custom logger
+ ///
+ /// IInstaLogger implementation
+ ///
+ /// API Builder
+ ///
public IInstaApiBuilder UseLogger(IInstaLogger logger)
{
_logger = logger;
return this;
}
+ ///
+ /// Set specific HttpClient
+ ///
+ /// HttpClient
+ ///
+ /// API Builder
+ ///
public IInstaApiBuilder UseHttpClient(HttpClient httpClient)
{
_httpClient = httpClient;
return this;
}
+ ///
+ /// Set custom HttpClientHandler to be able to use certain features, e.g Proxy and so on
+ ///
+ /// HttpClientHandler
+ ///
+ /// API Builder
+ ///
public IInstaApiBuilder UseHttpClientHandler(HttpClientHandler handler)
{
_httpHandler = handler;
return this;
}
- public IInstaApiBuilder SetUserName(string username)
- {
- _user = new UserSessionData {UserName = username};
- return this;
- }
-
+ ///
+ /// Specify user login, password from here
+ ///
+ /// User auth data
+ ///
+ /// API Builder
+ ///
public IInstaApiBuilder SetUser(UserSessionData user)
{
_user = user;
return this;
}
+ ///
+ /// Set custom request message. Used to be able to customize device info.
+ ///
+ /// Custom request message object
+ ///
+ /// API Builder
+ ///
+ ///
+ /// Please, do not use if you don't know what you are doing
+ ///
public IInstaApiBuilder SetApiRequestMessage(ApiRequestMessage requestMessage)
{
_requestMessage = requestMessage;
return this;
}
+ ///
+ /// Set delay between requests. Useful when API supposed to be used for mass-bombing.
+ ///
+ /// Timespan delay
+ ///
+ /// API Builder
+ ///
public IInstaApiBuilder SetRequestDelay(TimeSpan delay)
{
_delay = delay;
return this;
}
+ ///
+ /// Creates the builder.
+ ///
+ ///
public static IInstaApiBuilder CreateBuilder()
{
return new InstaApiBuilder();
diff --git a/InstaSharper/API/IInstaApi.cs b/InstaSharper/API/IInstaApi.cs
index 7ddfdbb5..d694b895 100644
--- a/InstaSharper/API/IInstaApi.cs
+++ b/InstaSharper/API/IInstaApi.cs
@@ -1,4 +1,5 @@
-using System.IO;
+using System;
+using System.IO;
using System.Threading.Tasks;
using InstaSharper.Classes;
using InstaSharper.Classes.Models;
@@ -32,40 +33,69 @@ public interface IInstaApi
///
/// Login using given credentials asynchronously
///
- /// True is succeed
- Task> LoginAsync();
+ ///
+ /// Success --> is succeed
+ /// TwoFactorRequired --> requires 2FA login.
+ /// BadPassword --> Password is wrong
+ /// InvalidUser --> User/phone number is wrong
+ /// Exception --> Something wrong happened
+ ///
+ Task> LoginAsync();
+
+ ///
+ /// 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 completed without errors
+ /// True if logged out without errors
Task> LogoutAsync();
///
/// Get user timeline feed (feed of recent posts from users you follow) asynchronously.
///
- /// Maximum count of pages to retrieve
+ /// Pagination parameters: next id and max amount of pages to load
///
///
///
- Task> GetUserTimelineFeedAsync(int maxPages = 0);
+ Task> GetUserTimelineFeedAsync(PaginationParameters paginationParameters);
///
/// Get user explore feed (Explore tab info) asynchronously
///
- /// Maximum count of pages to retrieve
+ /// Pagination parameters: next id and max amount of pages to load
/// >
- Task> GetExploreFeedAsync(int maxPages = 0);
+ Task> GetExploreFeedAsync(PaginationParameters paginationParameters);
///
/// Get all user media by username asynchronously
///
/// Username
- /// Maximum count of pages to retrieve
+ /// Pagination parameters: next id and max amount of pages to load
///
///
///
- Task> GetUserMediaAsync(string username, int maxPages = 0);
+ Task> GetUserMediaAsync(string username, PaginationParameters paginationParameters);
///
/// Get media by its id asynchronously
@@ -97,51 +127,53 @@ public interface IInstaApi
/// Get tag feed by tag value asynchronously
///
/// Tag value
- /// Maximum count of pages to retrieve
+ /// Pagination parameters: next id and max amount of pages to load
///
///
///
- Task> GetTagFeedAsync(string tag, int maxPages = 0);
+ Task> GetTagFeedAsync(string tag, PaginationParameters paginationParameters);
///
/// Get followers list by username asynchronously
///
/// Username
- /// Maximum count of pages to retrieve
+ /// Pagination parameters: next id and max amount of pages to load
///
///
///
- Task> GetUserFollowersAsync(string username, int maxPages = 0);
+ Task> GetUserFollowersAsync(string username,
+ PaginationParameters paginationParameters);
///
/// Get following list by username asynchronously
///
/// Username
- /// Maximum count of pages to retrieve
+ /// Pagination parameters: next id and max amount of pages to load
///
///
///
- Task> GetUserFollowingAsync(string username, int maxPages = 0);
+ Task> GetUserFollowingAsync(string username,
+ PaginationParameters paginationParameters);
///
/// Get followers list for currently logged in user asynchronously
///
- /// Maximum count of pages to retrieve
+ /// Pagination parameters: next id and max amount of pages to load
///
///
///
- Task> GetCurrentUserFollowersAsync(int maxPages = 0);
+ Task> GetCurrentUserFollowersAsync(PaginationParameters paginationParameters);
///
/// Get user tags by username asynchronously
/// Returns media list containing tags
///
/// Username
- /// Maximum count of pages to retrieve
+ /// Pagination parameters: next id and max amount of pages to load
///
///
///
- Task> GetUserTagsAsync(string username, int maxPages = 0);
+ Task> GetUserTagsAsync(string username, PaginationParameters paginationParameters);
///
/// Get direct inbox threads for current user asynchronously
@@ -166,42 +198,42 @@ public interface IInstaApi
/// Comma-separated users PK
/// Message thread ids
/// Message text
- ///
- Task> SendDirectMessage(string recipients, string threadIds, string text);
+ /// List of threads
+ Task> SendDirectMessage(string recipients, string threadIds, string text);
///
/// Get recent recipients (threads and users) asynchronously
///
///
- ///
+ ///
///
- Task> GetRecentRecipientsAsync();
+ Task> GetRecentRecipientsAsync();
///
/// Get ranked recipients (threads and users) asynchronously
///
///
- ///
+ ///
///
- Task> GetRankedRecipientsAsync();
+ Task> GetRankedRecipientsAsync();
///
/// Get recent activity info asynchronously
///
- /// Maximum count of pages to retrieve
+ /// Pagination parameters: next id and max amount of pages to load
///
///
///
- Task> GetRecentActivityAsync(int maxPages = 0);
+ Task> GetRecentActivityAsync(PaginationParameters paginationParameters);
///
/// Get activity of following asynchronously
///
- /// Maximum count of pages to retrieve
+ /// Pagination parameters: next id and max amount of pages to load
///
///
///
- Task> GetFollowingRecentActivityAsync(int maxPages = 0);
+ Task> GetFollowingRecentActivityAsync(PaginationParameters paginationParameters);
///
/// Like media (photo or video)
@@ -227,12 +259,26 @@ public interface IInstaApi
/// 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
- /// Maximum amount of pages to load
- Task> GetMediaCommentsAsync(string mediaId, int maxPages = 0);
+ /// 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.
@@ -271,6 +317,14 @@ public interface IInstaApi
/// Caption
Task> UploadPhotoAsync(InstaImage image, string caption);
+ ///
+ /// Upload photo
+ ///
+ /// Array of photos to upload
+ /// Caption
+ ///
+ Task> UploadPhotosAlbumAsync(InstaImage[] images, string caption);
+
///
/// Configure photo
///
@@ -280,6 +334,15 @@ public interface IInstaApi
///
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).
///
@@ -337,11 +400,11 @@ public interface IInstaApi
///
/// Get feed of media your liked.
///
- /// Maximum count of pages to retrieve
+ /// Pagination parameters: next id and max amount of pages to load
///
///
///
- Task> GetLikeFeedAsync(int maxPages = 0);
+ Task> GetLikeFeedAsync(PaginationParameters paginationParameters);
///
@@ -360,6 +423,78 @@ public interface IInstaApi
///
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);
+
#endregion
}
}
\ No newline at end of file
diff --git a/InstaSharper/API/InstaApi.cs b/InstaSharper/API/InstaApi.cs
index 0a041f74..e5faf3b8 100644
--- a/InstaSharper/API/InstaApi.cs
+++ b/InstaSharper/API/InstaApi.cs
@@ -1,22 +1,19 @@
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.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.Converters.Json;
using InstaSharper.Helpers;
using InstaSharper.Logger;
using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using InstaRecentActivityConverter = InstaSharper.Converters.Json.InstaRecentActivityConverter;
namespace InstaSharper.API
{
@@ -24,8 +21,20 @@ 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 ILocationProcessor _locationProcessor;
+ private IMediaProcessor _mediaProcessor;
+ private IMessagingProcessor _messagingProcessor;
+ private IUserProfileProcessor _profileProcessor;
+ private IStoryProcessor _storyProcessor;
+
+ private TwoFactorLoginInfo _twoFactorInfo;
private UserSessionData _user;
+ private IUserProcessor _userProcessor;
public InstaApi(UserSessionData user, IInstaLogger logger, AndroidDevice deviceInfo,
IHttpRequestProcessor httpRequestProcessor)
@@ -36,1492 +45,990 @@ public InstaApi(UserSessionData user, IInstaLogger logger, AndroidDevice deviceI
_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)
+ ///
+ /// 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();
- 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);
+ 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();
- 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);
+ return await _storyProcessor.GetUserStoryFeedAsync(userId);
}
- ///
- 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)
+ ///
+ /// 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();
- 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);
- }
+ return await _feedProcessor.GetExploreFeedAsync(paginationParameters);
}
- public async Task> GetUserMediaAsync(string username, int maxPages = 0)
+ ///
+ /// 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();
- if (maxPages == 0) maxPages = int.MaxValue;
+ ValidateLoggedIn();
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);
+ 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();
- 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);
+ return await _mediaProcessor.GetMediaByIdAsync(mediaId);
}
+ ///
+ /// Get user info by its user name asynchronously
+ ///
+ /// Username
+ ///
+ ///
+ ///
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);
+ ValidateLoggedIn();
+ return await _userProcessor.GetUserAsync(username);
}
+ ///
+ /// Get currently logged in user info asynchronously
+ ///
+ ///
+ ///
+ ///
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);
+ return await _userProcessor.GetCurrentUserAsync();
}
- public async Task> GetTagFeedAsync(string tag, int maxPages = 0)
+ ///
+ /// 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();
- 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);
+ return await _feedProcessor.GetTagFeedAsync(tag, paginationParameters);
}
- public async Task> GetUserFollowersAsync(string username, int maxPages = 0)
+ ///
+ /// Get followers list by username asynchronously
+ ///
+ /// Username
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ public async Task> GetUserFollowersAsync(string username,
+ PaginationParameters paginationParameters)
{
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);
- }
+ return await _userProcessor.GetUserFollowersAsync(username, paginationParameters);
}
- public async Task> GetUserFollowingAsync(string username, int maxPages = 0)
+ ///
+ /// Get following list by username asynchronously
+ ///
+ /// Username
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ public async Task> GetUserFollowingAsync(string username,
+ PaginationParameters paginationParameters)
{
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);
- }
+ return await _userProcessor.GetUserFollowingAsync(username, paginationParameters);
}
- public async Task> GetCurrentUserFollowersAsync(int maxPages = 0)
+ ///
+ /// 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();
- return await GetUserFollowersAsync(_user.UserName, maxPages);
+ ValidateLoggedIn();
+ return await _userProcessor.GetCurrentUserFollowersAsync(paginationParameters);
}
- public async Task> GetUserTagsAsync(string username, int maxPages = 0)
+ ///
+ /// 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();
- 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);
- }
+ 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();
- 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);
- }
+ return await _messagingProcessor.GetDirectInboxAsync();
}
+ ///
+ /// Get direct inbox thread by its id asynchronously
+ ///
+ /// Thread id
+ ///
+ ///
+ ///
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);
- }
+ return await _messagingProcessor.GetDirectInboxThreadAsync(threadId);
}
- public async Task> SendDirectMessage(string recipients, string threadIds, string text)
+ ///
+ /// 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();
- 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);
- }
+ return await _messagingProcessor.SendDirectMessage(recipients, threadIds, text);
}
- public async Task> GetRecentRecipientsAsync()
+ ///
+ /// Get recent recipients (threads and users) asynchronously
+ ///
+ ///
+ ///
+ ///
+ 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());
+ return await _messagingProcessor.GetRecentRecipientsAsync();
}
- public async Task> GetRankedRecipientsAsync()
+ ///
+ /// Get ranked recipients (threads and users) asynchronously
+ ///
+ ///
+ ///
+ ///
+ 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);
+ return await _messagingProcessor.GetRankedRecipientsAsync();
}
- public async Task> GetFollowingRecentActivityAsync(int maxPages = 0)
+ ///
+ /// Get recent activity info asynchronously
+ ///
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ public async Task> GetRecentActivityAsync(PaginationParameters paginationParameters)
{
- var uri = UriCreator.GetFollowingRecentActivityUri();
- return await GetRecentActivityInternalAsync(uri, maxPages);
+ return await _feedProcessor.GetRecentActivityFeedAsync(paginationParameters);
}
-
- public async Task> CheckpointAsync(string checkPointUrl)
+ ///
+ /// Get activity of following asynchronously
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task> GetFollowingRecentActivityAsync(
+ PaginationParameters paginationParameters)
{
- 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);
+ return await _feedProcessor.GetFollowingRecentActivityFeedAsync(paginationParameters);
}
+ ///
+ /// Like media (photo or video)
+ ///
+ /// Media id
+ ///
public async Task> LikeMediaAsync(string mediaId)
{
- return await LikeUnlikeMediaInternal(mediaId, UriCreator.GetLikeMediaUri(mediaId));
+ return await _mediaProcessor.LikeMediaAsync(mediaId);
}
+ ///
+ /// Remove like from media (photo or video)
+ ///
+ /// Media id
+ ///
public async Task> UnLikeMediaAsync(string mediaId)
{
- return await LikeUnlikeMediaInternal(mediaId, UriCreator.GetUnLikeMediaUri(mediaId));
+ return await _mediaProcessor.UnLikeMediaAsync(mediaId);
}
- public async Task> LikeUnlikeMediaInternal(string mediaId, Uri instaUri)
+ ///
+ /// Get media comments
+ ///
+ /// Media id
+ /// Maximum amount of pages to load and start id
+ ///
+ public async Task> GetMediaCommentsAsync(string mediaId,
+ PaginationParameters paginationParameters)
{
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);
- }
+ 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();
- 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);
- }
+ return await _mediaProcessor.GetMediaLikersAsync(mediaId);
}
+ ///
+ /// Follow user
+ ///
+ /// User id
+ ///
public async Task> FollowUserAsync(long userId)
{
- return await FollowUnfollowUserInternal(userId, UriCreator.GetFollowUserUri(userId));
+ return await _userProcessor.FollowUserAsync(userId);
}
+ ///
+ /// Stop follow user
+ ///
+ /// User id
+ ///
public async Task> UnFollowUserAsync(long userId)
{
- return await FollowUnfollowUserInternal(userId, UriCreator.GetUnFollowUserUri(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();
- 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);
- }
+ return await _profileProcessor.SetAccountPrivateAsync();
}
+ ///
+ /// Set current account public
+ ///
+ ///
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);
- }
+ return await _profileProcessor.SetAccountPublicAsync();
}
+ ///
+ /// Comment media
+ ///
+ /// Media id
+ /// Comment text
+ ///
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);
- }
+ return await _commentProcessor.CommentMediaAsync(mediaId, text);
}
+ ///
+ /// Delete comment from media
+ ///
+ /// Media id
+ /// Comment id
+ ///
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);
- }
+ return await _commentProcessor.DeleteCommentAsync(mediaId, commentId);
}
+ ///
+ /// Upload photo
+ ///
+ /// Photo to upload
+ /// Caption
+ ///
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);
- }
+ 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();
- 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);
- }
+ 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();
-
- 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);
- }
+ return await _storyProcessor.GetStoryFeedAsync();
}
+ ///
+ /// Get the story by userId
+ ///
+ /// User Id
+ ///
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);
- }
+ return await _storyProcessor.GetUserStoryAsync(userId);
}
+ ///
+ /// Upload story photo
+ ///
+ /// Photo to upload
+ /// Caption
+ ///
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);
- }
+ 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();
- 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);
- }
+ 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();
-
- 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);
- }
+ 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();
-
- 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);
- }
+ 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();
-
- 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);
- }
+ return await _mediaProcessor.EditMediaAsync(mediaId, caption);
}
- public async Task> GetLikeFeedAsync(int maxPages = 0)
+ ///
+ /// Get feed of media your liked.
+ ///
+ /// Pagination parameters: next id and max amount of pages to load
+ ///
+ ///
+ ///
+ public async Task> GetLikeFeedAsync(PaginationParameters paginationParameters)
{
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);
+ return await _feedProcessor.GetLikeFeedAsync(paginationParameters);
}
- public async Task> GetLikeFeedInternal(string maxId = "")
+ ///
+ /// Get friendship status for given user id.
+ ///
+ /// User identifier (PK)
+ ///
+ ///
+ ///
+ public async Task> GetFriendshipStatusAsync(long userId)
{
- 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);
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _userProcessor.GetFriendshipStatusAsync(userId);
}
- public async Task> GetFriendshipStatusAsync(long userId)
+ ///
+ /// Get your collection for given collection id
+ ///
+ /// Collection ID
+ ///
+ ///
+ ///
+ public async Task> GetCollectionAsync(long collectionId)
{
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());
+ ValidateLoggedIn();
+ return await _collectionProcessor.GetCollectionAsync(collectionId);
}
- #endregion
- #region private part
-
- private void ValidateUser()
+ ///
+ /// Get your collections
+ ///
+ ///
+ ///
+ ///
+ public async Task> GetCollectionsAsync()
{
- if (string.IsNullOrEmpty(_user.UserName) || string.IsNullOrEmpty(_user.Password))
- throw new ArgumentException("user name and password must be specified");
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _collectionProcessor.GetCollectionsAsync();
}
- private void ValidateLoggedIn()
+ ///
+ /// Create a new collection
+ ///
+ /// The name of the new collection
+ ///
+ ///
+ ///
+ public async Task> CreateCollectionAsync(string collectionName)
{
- if (!IsUserAuthenticated) throw new ArgumentException("user must be authenticated");
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _collectionProcessor.CreateCollectionAsync(collectionName);
}
- private void ValidateRequestMessage()
+ public async Task> AddItemsToCollectionAsync(long collectionId,
+ params string[] mediaIds)
{
- if (_httpRequestProcessor.RequestMessage == null || _httpRequestProcessor.RequestMessage.IsEmpty())
- throw new ArgumentException("API request message null or empty");
+ ValidateUser();
+ ValidateLoggedIn();
+ return await _collectionProcessor.AddItemsToCollectionAsync(collectionId, mediaIds);
}
- 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);
+ ///
+ /// 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);
}
- private async Task> GetFollowingActivityWithMaxIdAsync(string maxId)
+ ///
+ /// Get media ID from an url (got from "share link")
+ ///
+ /// Uri to get media ID
+ /// Media ID
+ public async Task> GetMediaIdFromUrlAsync(Uri uri)
{
- 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);
+ ValidateLoggedIn();
+ ValidateRequestMessage();
+ return await _mediaProcessor.GetMediaIdFromUrlAsync(uri);
}
- private async Task> GetUserMediaListWithMaxIdAsync(Uri instaUri)
+ ///
+ /// Get share link from media Id
+ ///
+ /// media ID
+ /// Share link as Uri
+ public async Task> GetShareLinkFromMediaIdAsync(string mediaId)
{
- 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);
+ return await _mediaProcessor.GetShareLinkFromMediaIdAsync(mediaId);
}
- private async Task> GetUserListByURIAsync(Uri uri)
+ ///
+ /// 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();
- 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);
- }
+ ValidateLoggedIn();
+ return await _locationProcessor.Search(latitude, longitude, query);
}
- private async Task> GetRecentActivityInternalAsync(Uri uri, int maxPages = 0)
+ ///
+ /// 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();
- 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);
+ return await _locationProcessor.GetFeed(locationId, paginationParameters);
}
- private async Task> GetTagFeedWithMaxIdAsync(string tag, string nextId)
+
+ #region Authentication/State data
+
+ ///
+ /// Indicates whether user authenticated or not
+ ///
+ public bool IsUserAuthenticated { get; private set; }
+
+ ///
+ /// 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();
- ValidateLoggedIn();
+ ValidateRequestMessage();
try
{
- var instaUri = UriCreator.GetTagFeedUri(tag);
- instaUri = new UriBuilder(instaUri) {Query = $"max_id={nextId}"}.Uri;
- var request = HttpHelper.GetDefaultRequest(HttpMethod.Get, instaUri, _deviceInfo);
+ 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(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 (response.StatusCode != HttpStatusCode.OK
+ ) //If the password is correct BUT 2-Factor Authentication is enabled, it will still get a 400 error (bad request)
{
- var feedResponse = JsonConvert.DeserializeObject(json,
- new InstaMediaListDataConverter());
- return Result.Success(feedResponse);
+ //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);
+ }
+
+ return Result.UnExpectedResponse(response, json);
}
- return Result.UnExpectedResponse(response, json);
+ var loginInfo =
+ JsonConvert.DeserializeObject(json);
+ IsUserAuthenticated = loginInfo.User != null &&
+ loginInfo.User.UserName.ToLower() == _user.UserName.ToLower();
+ var converter = ConvertersFabric.Instance.GetUserShortConverter(loginInfo.User);
+ _user.LoggedInUder = converter.Convert();
+ _user.RankToken = $"{_user.LoggedInUder.Pk}_{_httpRequestProcessor.RequestMessage.phone_id}";
+ return Result.Success(InstaLoginResult.Success);
}
catch (Exception exception)
{
- return Result.Fail(exception.Message, (InstaMediaListResponse) null);
+ LogException(exception);
+ return Result.Fail(exception, InstaLoginResult.Exception);
}
- }
-
- 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)
+ finally
{
- var comments = JsonConvert.DeserializeObject