v16.8
This commit is contained in:
parent
51c4da8dce
commit
1827ed85ee
@ -6,8 +6,8 @@ InstaGrabber is an app that allows...
|
|||||||
|
|
||||||
* Viewing **and downloading** Instagram posts, stories (including highlights)\*, DM\*, and profile pictures, **without** letting people know you viewed it<sup>1</sup>! Works for followed private accounts\*!
|
* Viewing **and downloading** Instagram posts, stories (including highlights)\*, DM\*, and profile pictures, **without** letting people know you viewed it<sup>1</sup>! Works for followed private accounts\*!
|
||||||
* Like/bookmark posts\*!
|
* Like/bookmark posts\*!
|
||||||
* Follow/restrict/block people\*!
|
|
||||||
* Downloading multiple posts at once (hold & select)!
|
* Downloading multiple posts at once (hold & select)!
|
||||||
|
* (Un)follow/restrict/block people\*, and (un)follow hashtags\*! (Or you can add shortcuts to them, without logging in!)
|
||||||
* **Copy** post captions, comments, DM messages\*, and profile bios.
|
* **Copy** post captions, comments, DM messages\*, and profile bios.
|
||||||
* **Compare** follower/following list<sup>2</sup>!
|
* **Compare** follower/following list<sup>2</sup>!
|
||||||
* Searching usernames and hashtags.
|
* Searching usernames and hashtags.
|
||||||
|
@ -54,6 +54,7 @@ import awais.instagrabber.adapters.PostsAdapter;
|
|||||||
import awais.instagrabber.asyncs.DiscoverFetcher;
|
import awais.instagrabber.asyncs.DiscoverFetcher;
|
||||||
import awais.instagrabber.asyncs.FeedFetcher;
|
import awais.instagrabber.asyncs.FeedFetcher;
|
||||||
import awais.instagrabber.asyncs.FeedStoriesFetcher;
|
import awais.instagrabber.asyncs.FeedStoriesFetcher;
|
||||||
|
import awais.instagrabber.asyncs.HashtagFetcher;
|
||||||
import awais.instagrabber.asyncs.HighlightsFetcher;
|
import awais.instagrabber.asyncs.HighlightsFetcher;
|
||||||
import awais.instagrabber.asyncs.PostsFetcher;
|
import awais.instagrabber.asyncs.PostsFetcher;
|
||||||
import awais.instagrabber.asyncs.ProfileFetcher;
|
import awais.instagrabber.asyncs.ProfileFetcher;
|
||||||
@ -70,12 +71,14 @@ import awais.instagrabber.models.BasePostModel;
|
|||||||
import awais.instagrabber.models.DiscoverItemModel;
|
import awais.instagrabber.models.DiscoverItemModel;
|
||||||
import awais.instagrabber.models.FeedModel;
|
import awais.instagrabber.models.FeedModel;
|
||||||
import awais.instagrabber.models.FeedStoryModel;
|
import awais.instagrabber.models.FeedStoryModel;
|
||||||
|
import awais.instagrabber.models.HashtagModel;
|
||||||
import awais.instagrabber.models.IntentModel;
|
import awais.instagrabber.models.IntentModel;
|
||||||
import awais.instagrabber.models.PostModel;
|
import awais.instagrabber.models.PostModel;
|
||||||
import awais.instagrabber.models.StoryModel;
|
import awais.instagrabber.models.StoryModel;
|
||||||
import awais.instagrabber.models.enums.IntentModelType;
|
import awais.instagrabber.models.enums.IntentModelType;
|
||||||
import awais.instagrabber.models.enums.ItemGetType;
|
import awais.instagrabber.models.enums.ItemGetType;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
|
import awais.instagrabber.utils.DataBox;
|
||||||
import awais.instagrabber.utils.Utils;
|
import awais.instagrabber.utils.Utils;
|
||||||
import awaisomereport.LogCollector;
|
import awaisomereport.LogCollector;
|
||||||
|
|
||||||
@ -115,7 +118,7 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isHashtag)
|
if (isHashtag)
|
||||||
main.mainBinding.toolbar.toolbar.setTitle(main.getString(R.string.title_hashtag_prefix) + main.userQuery);
|
main.mainBinding.toolbar.toolbar.setTitle(main.userQuery);
|
||||||
else main.mainBinding.toolbar.toolbar.setTitle(username + " (" + main.allItems.size() + postFix);
|
else main.mainBinding.toolbar.toolbar.setTitle(username + " (" + main.allItems.size() + postFix);
|
||||||
|
|
||||||
final PostModel model = result[result.length - 1];
|
final PostModel model = result[result.length - 1];
|
||||||
@ -138,8 +141,10 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
if ((autoloadPosts && hasNextPage) && !isHashtag)
|
if ((autoloadPosts && hasNextPage) && !isHashtag)
|
||||||
currentlyExecuting = new PostsFetcher(main.profileModel.getId(), endCursor, this)
|
currentlyExecuting = new PostsFetcher(main.profileModel.getId(), endCursor, this)
|
||||||
.setUsername(main.profileModel.getUsername()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
.setUsername(main.profileModel.getUsername()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
else
|
else {
|
||||||
main.mainBinding.swipeRefreshLayout.setRefreshing(false);
|
main.mainBinding.swipeRefreshLayout.setRefreshing(false);
|
||||||
|
main.mainBinding.tagToolbar.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
model.setPageCursor(false, null);
|
model.setPageCursor(false, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -253,6 +258,7 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
private RecyclerLazyLoader feedLazyLoader, discoverLazyLoader;
|
private RecyclerLazyLoader feedLazyLoader, discoverLazyLoader;
|
||||||
private DiscoverAdapter discoverAdapter;
|
private DiscoverAdapter discoverAdapter;
|
||||||
public SimpleExoPlayer currentFeedPlayer; // hack for remix drawer layout
|
public SimpleExoPlayer currentFeedPlayer; // hack for remix drawer layout
|
||||||
|
final boolean isLoggedIn = !Utils.isEmpty(Utils.settingsHelper.getString(Constants.COOKIE));
|
||||||
|
|
||||||
public MainHelper(@NonNull final Main main) {
|
public MainHelper(@NonNull final Main main) {
|
||||||
stopCurrentExecutor();
|
stopCurrentExecutor();
|
||||||
@ -264,8 +270,6 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
main.mainBinding.swipeRefreshLayout.setOnRefreshListener(this);
|
main.mainBinding.swipeRefreshLayout.setOnRefreshListener(this);
|
||||||
main.mainBinding.mainUrl.setMovementMethod(new LinkMovementMethod());
|
main.mainBinding.mainUrl.setMovementMethod(new LinkMovementMethod());
|
||||||
|
|
||||||
final boolean isLoggedIn = !Utils.isEmpty(Utils.settingsHelper.getString(Constants.COOKIE));
|
|
||||||
|
|
||||||
final LinearLayout iconSlider = main.findViewById(R.id.iconSlider);
|
final LinearLayout iconSlider = main.findViewById(R.id.iconSlider);
|
||||||
final ImageView iconFeed = (ImageView) iconSlider.getChildAt(0);
|
final ImageView iconFeed = (ImageView) iconSlider.getChildAt(0);
|
||||||
final ImageView iconProfile = (ImageView) iconSlider.getChildAt(1);
|
final ImageView iconProfile = (ImageView) iconSlider.getChildAt(1);
|
||||||
@ -426,7 +430,8 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
linearLayout.addView(main.mainBinding.toolbar.toolbar, linearLayout.getChildCount());
|
linearLayout.addView(main.mainBinding.toolbar.toolbar, linearLayout.getChildCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
final GridAutofitLayoutManager layoutManager = new GridAutofitLayoutManager(main, Utils.convertDpToPx(130));
|
// change the next number to adjust grid
|
||||||
|
final GridAutofitLayoutManager layoutManager = new GridAutofitLayoutManager(main, Utils.convertDpToPx(110));
|
||||||
main.mainBinding.mainPosts.setLayoutManager(layoutManager);
|
main.mainBinding.mainPosts.setLayoutManager(layoutManager);
|
||||||
main.mainBinding.mainPosts.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(4)));
|
main.mainBinding.mainPosts.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(4)));
|
||||||
main.mainBinding.mainPosts.setAdapter(postsAdapter = new PostsAdapter(main.allItems, v -> {
|
main.mainBinding.mainPosts.setAdapter(postsAdapter = new PostsAdapter(main.allItems, v -> {
|
||||||
@ -617,6 +622,7 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
main.mainBinding.appBarLayout.setExpanded(true, true);
|
main.mainBinding.appBarLayout.setExpanded(true, true);
|
||||||
main.mainBinding.privatePage.setVisibility(View.GONE);
|
main.mainBinding.privatePage.setVisibility(View.GONE);
|
||||||
main.mainBinding.mainProfileImage.setImageBitmap(null);
|
main.mainBinding.mainProfileImage.setImageBitmap(null);
|
||||||
|
main.mainBinding.mainHashtagImage.setImageBitmap(null);
|
||||||
main.mainBinding.mainUrl.setText(null);
|
main.mainBinding.mainUrl.setText(null);
|
||||||
main.mainBinding.mainFullName.setText(null);
|
main.mainBinding.mainFullName.setText(null);
|
||||||
main.mainBinding.mainPostCount.setText(null);
|
main.mainBinding.mainPostCount.setText(null);
|
||||||
@ -625,8 +631,10 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
main.mainBinding.mainBiography.setText(null);
|
main.mainBinding.mainBiography.setText(null);
|
||||||
main.mainBinding.mainBiography.setEnabled(false);
|
main.mainBinding.mainBiography.setEnabled(false);
|
||||||
main.mainBinding.mainProfileImage.setEnabled(false);
|
main.mainBinding.mainProfileImage.setEnabled(false);
|
||||||
|
main.mainBinding.mainHashtagImage.setEnabled(false);
|
||||||
main.mainBinding.mainBiography.setMentionClickListener(null);
|
main.mainBinding.mainBiography.setMentionClickListener(null);
|
||||||
main.mainBinding.mainUrl.setVisibility(View.GONE);
|
main.mainBinding.mainUrl.setVisibility(View.GONE);
|
||||||
|
main.mainBinding.mainTagPostCount.setVisibility(View.GONE);
|
||||||
main.mainBinding.isVerified.setVisibility(View.GONE);
|
main.mainBinding.isVerified.setVisibility(View.GONE);
|
||||||
main.mainBinding.btnFollow.setVisibility(View.GONE);
|
main.mainBinding.btnFollow.setVisibility(View.GONE);
|
||||||
main.mainBinding.btnRestrict.setVisibility(View.GONE);
|
main.mainBinding.btnRestrict.setVisibility(View.GONE);
|
||||||
@ -647,12 +655,77 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
collapsingToolbar.setVisibility(isHashtag ? View.GONE : View.VISIBLE);
|
collapsingToolbar.setVisibility(isHashtag ? View.GONE : View.VISIBLE);
|
||||||
|
|
||||||
if (isHashtag) {
|
if (isHashtag) {
|
||||||
main.mainBinding.toolbar.toolbar.setTitle(resources.getString(R.string.title_hashtag_prefix) + main.userQuery);
|
main.profileModel = null;
|
||||||
|
main.mainBinding.toolbar.toolbar.setTitle(main.userQuery);
|
||||||
main.mainBinding.infoContainer.setVisibility(View.GONE);
|
main.mainBinding.infoContainer.setVisibility(View.GONE);
|
||||||
|
main.mainBinding.tagInfoContainer.setVisibility(View.VISIBLE);
|
||||||
|
main.mainBinding.btnFollowTag.setVisibility(View.GONE);
|
||||||
|
|
||||||
currentlyExecuting = new PostsFetcher(main.userQuery, postsFetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
currentlyExecuting = new HashtagFetcher(main.userQuery.substring(1), hashtagModel -> {
|
||||||
|
main.hashtagModel = hashtagModel;
|
||||||
|
|
||||||
|
if (hashtagModel == null) {
|
||||||
|
main.mainBinding.swipeRefreshLayout.setRefreshing(false);
|
||||||
|
Toast.makeText(main, R.string.error_loading_profile, Toast.LENGTH_SHORT).show();
|
||||||
|
main.mainBinding.toolbar.toolbar.setTitle(R.string.app_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String profileId = hashtagModel.getId();
|
||||||
|
|
||||||
|
final String cookie = Utils.settingsHelper.getString(Constants.COOKIE);
|
||||||
|
final boolean isLoggedIn = !Utils.isEmpty(cookie);
|
||||||
|
|
||||||
|
currentlyExecuting = new PostsFetcher(main.userQuery, postsFetchListener)
|
||||||
|
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
|
||||||
|
main.mainBinding.btnFollowTag.setVisibility(View.VISIBLE);
|
||||||
|
main.mainBinding.btnFollowTag.setOnClickListener(profileActionListener);
|
||||||
|
|
||||||
|
if (isLoggedIn) {
|
||||||
|
new StoryStatusFetcher(profileId, hashtagModel.getName(), result -> {
|
||||||
|
main.storyModels = result;
|
||||||
|
if (result != null && result.length > 0) main.mainBinding.mainHashtagImage.setStoriesBorder();
|
||||||
|
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
|
||||||
|
if (hashtagModel.getFollowing() == true) {
|
||||||
|
main.mainBinding.btnFollowTag.setText(R.string.unfollow);
|
||||||
|
main.mainBinding.btnFollowTag.setBackgroundTintList(ColorStateList.valueOf(resources.getColor(
|
||||||
|
R.color.btn_purple_background, null)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
main.mainBinding.btnFollowTag.setText(R.string.follow);
|
||||||
|
main.mainBinding.btnFollowTag.setBackgroundTintList(ColorStateList.valueOf(resources.getColor(
|
||||||
|
R.color.btn_pink_background, null)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Utils.dataBox.getFavorite(main.userQuery) != null) {
|
||||||
|
main.mainBinding.btnFollowTag.setText(R.string.unfavorite_short);
|
||||||
|
main.mainBinding.btnFollowTag.setBackgroundTintList(ColorStateList.valueOf(resources.getColor(
|
||||||
|
R.color.btn_purple_background, null)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
main.mainBinding.btnFollowTag.setText(R.string.favorite_short);
|
||||||
|
main.mainBinding.btnFollowTag.setBackgroundTintList(ColorStateList.valueOf(resources.getColor(
|
||||||
|
R.color.btn_pink_background, null)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main.mainBinding.mainHashtagImage.setEnabled(false);
|
||||||
|
new MyTask().execute();
|
||||||
|
main.mainBinding.mainHashtagImage.setEnabled(true);
|
||||||
|
|
||||||
|
final String postCount = String.valueOf(hashtagModel.getPostCount());
|
||||||
|
|
||||||
|
SpannableStringBuilder span = new SpannableStringBuilder(resources.getString(R.string.main_posts_count, postCount));
|
||||||
|
span.setSpan(new RelativeSizeSpan(1.2f), 0, postCount.length(), 0);
|
||||||
|
span.setSpan(new StyleSpan(Typeface.BOLD), 0, postCount.length(), 0);
|
||||||
|
main.mainBinding.mainTagPostCount.setText(span);
|
||||||
|
main.mainBinding.mainTagPostCount.setVisibility(View.VISIBLE);
|
||||||
|
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
} else {
|
} else {
|
||||||
|
main.hashtagModel = null;
|
||||||
|
main.mainBinding.tagInfoContainer.setVisibility(View.GONE);
|
||||||
main.mainBinding.toolbar.toolbar.setTitle(main.userQuery);
|
main.mainBinding.toolbar.toolbar.setTitle(main.userQuery);
|
||||||
main.mainBinding.infoContainer.setVisibility(View.VISIBLE);
|
main.mainBinding.infoContainer.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
@ -672,7 +745,7 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
final String cookie = Utils.settingsHelper.getString(Constants.COOKIE);
|
final String cookie = Utils.settingsHelper.getString(Constants.COOKIE);
|
||||||
final boolean isLoggedIn = !Utils.isEmpty(cookie);
|
final boolean isLoggedIn = !Utils.isEmpty(cookie);
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
new StoryStatusFetcher(profileId, result -> {
|
new StoryStatusFetcher(profileId, "", result -> {
|
||||||
main.storyModels = result;
|
main.storyModels = result;
|
||||||
if (result != null && result.length > 0) main.mainBinding.mainProfileImage.setStoriesBorder();
|
if (result != null && result.length > 0) main.mainBinding.mainProfileImage.setStoriesBorder();
|
||||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
@ -682,6 +755,7 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
main.mainBinding.highlightsList.setVisibility(View.VISIBLE);
|
main.mainBinding.highlightsList.setVisibility(View.VISIBLE);
|
||||||
main.highlightsAdapter.setData(result);
|
main.highlightsAdapter.setData(result);
|
||||||
}
|
}
|
||||||
|
else main.mainBinding.highlightsList.setVisibility(View.GONE);
|
||||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
|
||||||
final String myId = Utils.getUserIdFromCookie(Utils.settingsHelper.getString(Constants.COOKIE));
|
final String myId = Utils.getUserIdFromCookie(Utils.settingsHelper.getString(Constants.COOKIE));
|
||||||
@ -728,6 +802,19 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
R.color.btn_red_background, null)));
|
R.color.btn_red_background, null)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (Utils.dataBox.getFavorite(main.userQuery) != null) {
|
||||||
|
main.mainBinding.btnFollow.setText(R.string.unfavorite);
|
||||||
|
main.mainBinding.btnFollow.setBackgroundTintList(ColorStateList.valueOf(resources.getColor(
|
||||||
|
R.color.btn_purple_background, null)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
main.mainBinding.btnFollow.setText(R.string.favorite);
|
||||||
|
main.mainBinding.btnFollow.setBackgroundTintList(ColorStateList.valueOf(resources.getColor(
|
||||||
|
R.color.btn_pink_background, null)));
|
||||||
|
}
|
||||||
|
main.mainBinding.btnFollow.setOnClickListener(profileActionListener);
|
||||||
|
main.mainBinding.btnFollow.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
main.mainBinding.mainProfileImage.setEnabled(false);
|
main.mainBinding.mainProfileImage.setEnabled(false);
|
||||||
@ -932,7 +1019,9 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
|
|
||||||
protected Void doInBackground(Void... voids) {
|
protected Void doInBackground(Void... voids) {
|
||||||
try {
|
try {
|
||||||
mIcon_val = BitmapFactory.decodeStream((InputStream) new URL(main.profileModel.getSdProfilePic()).getContent());
|
mIcon_val = BitmapFactory.decodeStream((InputStream) new URL(
|
||||||
|
(main.hashtagModel != null) ? main.hashtagModel.getSdProfilePic() : main.profileModel.getSdProfilePic()
|
||||||
|
).getContent());
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
Log.e("austin_debug", "bitmap: " + ex);
|
Log.e("austin_debug", "bitmap: " + ex);
|
||||||
}
|
}
|
||||||
@ -941,19 +1030,29 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Void result) {
|
protected void onPostExecute(Void result) {
|
||||||
main.mainBinding.mainProfileImage.setImageBitmap(mIcon_val);
|
if (main.hashtagModel != null) main.mainBinding.mainHashtagImage.setImageBitmap(mIcon_val);
|
||||||
|
else main.mainBinding.mainProfileImage.setImageBitmap(mIcon_val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final View.OnClickListener profileActionListener = new View.OnClickListener() {
|
private final View.OnClickListener profileActionListener = new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(final View v) {
|
public void onClick(final View v) {
|
||||||
if (v == main.mainBinding.btnFollow) {
|
if (!isLoggedIn && Utils.dataBox.getFavorite(main.userQuery) != null) {
|
||||||
|
Utils.dataBox.delFavorite(new DataBox.FavoriteModel(main.userQuery,
|
||||||
|
Long.parseLong(Utils.dataBox.getFavorite(main.userQuery).split("/")[1])));
|
||||||
|
onRefresh();
|
||||||
|
} else if (!isLoggedIn) {
|
||||||
|
Utils.dataBox.addFavorite(new DataBox.FavoriteModel(main.userQuery, System.currentTimeMillis()));
|
||||||
|
onRefresh();
|
||||||
|
} else if (v == main.mainBinding.btnFollow) {
|
||||||
new ProfileAction().execute("follow");
|
new ProfileAction().execute("follow");
|
||||||
} else if (v == main.mainBinding.btnRestrict) {
|
} else if (v == main.mainBinding.btnRestrict) {
|
||||||
new ProfileAction().execute("restrict");
|
new ProfileAction().execute("restrict");
|
||||||
} else if (v == main.mainBinding.btnBlock) {
|
} else if (v == main.mainBinding.btnBlock) {
|
||||||
new ProfileAction().execute("block");
|
new ProfileAction().execute("block");
|
||||||
|
} else if (v == main.mainBinding.btnFollowTag) {
|
||||||
|
new ProfileAction().execute("followtag");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -965,15 +1064,16 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
protected Void doInBackground(String... rawAction) {
|
protected Void doInBackground(String... rawAction) {
|
||||||
action = rawAction[0];
|
action = rawAction[0];
|
||||||
final String url = "https://www.instagram.com/web/"+
|
final String url = "https://www.instagram.com/web/"+
|
||||||
(action == "restrict" ? "restrict_action" : ("friendships/"+main.profileModel.getId()))+"/"+
|
((action == "followtag" && main.hashtagModel != null) ? ("tags/"+
|
||||||
(action == "follow" ?
|
(main.hashtagModel.getFollowing() == true ? "unfollow/" : "follow/")+main.hashtagModel.getName()+"/") : (
|
||||||
|
((action == "restrict" && main.profileModel != null) ? "restrict_action" : ("friendships/"+main.profileModel.getId()))+"/"+
|
||||||
|
((action == "follow" && main.profileModel != null) ?
|
||||||
((main.profileModel.getFollowing() == true ||
|
((main.profileModel.getFollowing() == true ||
|
||||||
(main.profileModel.getFollowing() == false && main.profileModel.getRequested() == true))
|
(main.profileModel.getFollowing() == false && main.profileModel.getRequested() == true))
|
||||||
? "unfollow/" : "follow/") :
|
? "unfollow/" : "follow/") :
|
||||||
(action == "restrict" ?
|
((action == "restrict" && main.profileModel != null) ?
|
||||||
(main.profileModel.getRestricted() == true ? "unrestrict/" : "restrict/") :
|
(main.profileModel.getRestricted() == true ? "unrestrict/" : "restrict/") :
|
||||||
(main.profileModel.getBlocked() == true ? "unblock/" : "block/")));
|
(main.profileModel.getBlocked() == true ? "unblock/" : "block/")))));
|
||||||
final String urlParameters = "target_user_id="+main.profileModel.getId();
|
|
||||||
try {
|
try {
|
||||||
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||||
urlConnection.setRequestMethod("POST");
|
urlConnection.setRequestMethod("POST");
|
||||||
@ -982,6 +1082,7 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
|||||||
urlConnection.setRequestProperty("x-csrftoken",
|
urlConnection.setRequestProperty("x-csrftoken",
|
||||||
Utils.settingsHelper.getString(Constants.COOKIE).split("csrftoken=")[1].split(";")[0]);
|
Utils.settingsHelper.getString(Constants.COOKIE).split("csrftoken=")[1].split(";")[0]);
|
||||||
if (action == "restrict") {
|
if (action == "restrict") {
|
||||||
|
final String urlParameters = "target_user_id="+main.profileModel.getId();
|
||||||
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||||
urlConnection.setRequestProperty("Content-Length", "" +
|
urlConnection.setRequestProperty("Content-Length", "" +
|
||||||
Integer.toString(urlParameters.getBytes().length));
|
Integer.toString(urlParameters.getBytes().length));
|
||||||
|
@ -133,7 +133,9 @@ public final class DirectMessagesUserInbox extends AppCompatActivity {
|
|||||||
directItemModel.getReelShare().getReelId(),
|
directItemModel.getReelShare().getReelId(),
|
||||||
directItemModel.getReelShare().getMedia().getVideoUrl(),
|
directItemModel.getReelShare().getMedia().getVideoUrl(),
|
||||||
directItemModel.getReelShare().getMedia().getMediaType(),
|
directItemModel.getReelShare().getMedia().getMediaType(),
|
||||||
directItemModel.getTimestamp()
|
directItemModel.getTimestamp(),
|
||||||
|
directItemModel.getReelShare().getReelOwnerName()
|
||||||
|
|
||||||
);
|
);
|
||||||
sm.setVideoUrl(directItemModel.getReelShare().getMedia().getVideoUrl());
|
sm.setVideoUrl(directItemModel.getReelShare().getMedia().getVideoUrl());
|
||||||
StoryModel[] sms = {sm};
|
StoryModel[] sms = {sm};
|
||||||
|
@ -41,6 +41,7 @@ import awais.instagrabber.interfaces.FetchListener;
|
|||||||
import awais.instagrabber.interfaces.ItemGetter;
|
import awais.instagrabber.interfaces.ItemGetter;
|
||||||
import awais.instagrabber.models.DiscoverItemModel;
|
import awais.instagrabber.models.DiscoverItemModel;
|
||||||
import awais.instagrabber.models.FeedModel;
|
import awais.instagrabber.models.FeedModel;
|
||||||
|
import awais.instagrabber.models.HashtagModel;
|
||||||
import awais.instagrabber.models.HighlightModel;
|
import awais.instagrabber.models.HighlightModel;
|
||||||
import awais.instagrabber.models.PostModel;
|
import awais.instagrabber.models.PostModel;
|
||||||
import awais.instagrabber.models.ProfileModel;
|
import awais.instagrabber.models.ProfileModel;
|
||||||
@ -89,6 +90,7 @@ public final class Main extends BaseLanguageActivity {
|
|||||||
public String userQuery = null;
|
public String userQuery = null;
|
||||||
public MainHelper mainHelper;
|
public MainHelper mainHelper;
|
||||||
public ProfileModel profileModel;
|
public ProfileModel profileModel;
|
||||||
|
public HashtagModel hashtagModel;
|
||||||
private AutoCompleteTextView searchAutoComplete;
|
private AutoCompleteTextView searchAutoComplete;
|
||||||
private ArrayAdapter<String> profileDialogAdapter;
|
private ArrayAdapter<String> profileDialogAdapter;
|
||||||
private DialogInterface.OnClickListener profileDialogListener;
|
private DialogInterface.OnClickListener profileDialogListener;
|
||||||
@ -112,6 +114,9 @@ public final class Main extends BaseLanguageActivity {
|
|||||||
final String uid = Utils.getUserIdFromCookie(cookie);
|
final String uid = Utils.getUserIdFromCookie(cookie);
|
||||||
Utils.setupCookies(cookie);
|
Utils.setupCookies(cookie);
|
||||||
|
|
||||||
|
if (settingsHelper.getInteger(Constants.PROFILE_FETCH_MODE) == 2)
|
||||||
|
settingsHelper.putInteger(Constants.PROFILE_FETCH_MODE, 1);
|
||||||
|
|
||||||
MainHelper.stopCurrentExecutor();
|
MainHelper.stopCurrentExecutor();
|
||||||
mainHelper = new MainHelper(this);
|
mainHelper = new MainHelper(this);
|
||||||
if (bundle == null) {
|
if (bundle == null) {
|
||||||
@ -185,17 +190,21 @@ public final class Main extends BaseLanguageActivity {
|
|||||||
new String[]{resources.getString(R.string.view_pfp), resources.getString(R.string.show_stories)});
|
new String[]{resources.getString(R.string.view_pfp), resources.getString(R.string.show_stories)});
|
||||||
profileDialogListener = (dialog, which) -> {
|
profileDialogListener = (dialog, which) -> {
|
||||||
final Intent intent;
|
final Intent intent;
|
||||||
if (which == 0 || storyModels == null || storyModels.length < 1)
|
if (which == 0 || storyModels == null || storyModels.length < 1) {
|
||||||
intent = new Intent(this, ProfileViewer.class).putExtra(Constants.EXTRAS_PROFILE, profileModel);
|
intent = new Intent(this, ProfileViewer.class).putExtra(
|
||||||
|
((hashtagModel != null) ? Constants.EXTRAS_HASHTAG : Constants.EXTRAS_PROFILE),
|
||||||
|
((hashtagModel != null) ? hashtagModel : profileModel));
|
||||||
|
}
|
||||||
else intent = new Intent(this, StoryViewer.class).putExtra(Constants.EXTRAS_USERNAME, userQuery)
|
else intent = new Intent(this, StoryViewer.class).putExtra(Constants.EXTRAS_USERNAME, userQuery)
|
||||||
.putExtra(Constants.EXTRAS_STORIES, storyModels);
|
.putExtra(Constants.EXTRAS_STORIES, storyModels)
|
||||||
|
.putExtra(Constants.EXTRAS_HASHTAG, (hashtagModel != null));
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
};
|
};
|
||||||
|
|
||||||
final View.OnClickListener onClickListener = v -> {
|
final View.OnClickListener onClickListener = v -> {
|
||||||
if (v == mainBinding.mainBiography) {
|
if (v == mainBinding.mainBiography) {
|
||||||
Utils.copyText(this, mainBinding.mainBiography.getText().toString());
|
Utils.copyText(this, mainBinding.mainBiography.getText().toString());
|
||||||
} else if (v == mainBinding.mainProfileImage) {
|
} else if (v == mainBinding.mainProfileImage || v == mainBinding.mainHashtagImage) {
|
||||||
if (storyModels == null || storyModels.length <= 0) {
|
if (storyModels == null || storyModels.length <= 0) {
|
||||||
profileDialogListener.onClick(null, 0);
|
profileDialogListener.onClick(null, 0);
|
||||||
} else {
|
} else {
|
||||||
@ -208,9 +217,11 @@ public final class Main extends BaseLanguageActivity {
|
|||||||
|
|
||||||
mainBinding.mainBiography.setOnClickListener(onClickListener);
|
mainBinding.mainBiography.setOnClickListener(onClickListener);
|
||||||
mainBinding.mainProfileImage.setOnClickListener(onClickListener);
|
mainBinding.mainProfileImage.setOnClickListener(onClickListener);
|
||||||
|
mainBinding.mainHashtagImage.setOnClickListener(onClickListener);
|
||||||
|
|
||||||
mainBinding.mainBiography.setEnabled(false);
|
mainBinding.mainBiography.setEnabled(false);
|
||||||
mainBinding.mainProfileImage.setEnabled(false);
|
mainBinding.mainProfileImage.setEnabled(false);
|
||||||
|
mainBinding.mainHashtagImage.setEnabled(false);
|
||||||
|
|
||||||
final boolean isQueryNull = userQuery == null;
|
final boolean isQueryNull = userQuery == null;
|
||||||
if (isQueryNull) allItems.clear();
|
if (isQueryNull) allItems.clear();
|
||||||
|
@ -134,13 +134,13 @@ public final class PostViewer extends BaseLanguageActivity {
|
|||||||
final LinearLayout topPanelRoot = viewerBinding.topPanel.getRoot();
|
final LinearLayout topPanelRoot = viewerBinding.topPanel.getRoot();
|
||||||
final int iconRes;
|
final int iconRes;
|
||||||
|
|
||||||
if (containerLayoutParams.height == 0) {
|
if (containerLayoutParams.weight != 3.3f) {
|
||||||
containerLayoutParams.height = LinearLayout.LayoutParams.MATCH_PARENT;
|
containerLayoutParams.weight = 3.3f;
|
||||||
iconRes = R.drawable.ic_fullscreen_exit;
|
iconRes = R.drawable.ic_fullscreen_exit;
|
||||||
topPanelRoot.setVisibility(View.GONE);
|
topPanelRoot.setVisibility(View.GONE);
|
||||||
viewerBinding.btnDownload.setVisibility(View.VISIBLE);
|
viewerBinding.btnDownload.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
containerLayoutParams.height = 0;
|
containerLayoutParams.weight = (viewerBinding.mediaList.getVisibility() == View.VISIBLE) ? 1.35f : 1.9f;
|
||||||
iconRes = R.drawable.ic_fullscreen;
|
iconRes = R.drawable.ic_fullscreen;
|
||||||
topPanelRoot.setVisibility(View.VISIBLE);
|
topPanelRoot.setVisibility(View.VISIBLE);
|
||||||
viewerBinding.btnDownload.setVisibility(View.GONE);
|
viewerBinding.btnDownload.setVisibility(View.GONE);
|
||||||
@ -324,6 +324,11 @@ public final class PostViewer extends BaseLanguageActivity {
|
|||||||
|
|
||||||
mediaAdapter.setData(result);
|
mediaAdapter.setData(result);
|
||||||
if (result.length > 1) {
|
if (result.length > 1) {
|
||||||
|
viewerBinding.mediaList.setLayoutParams(new LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.MATCH_PARENT, 0, 0.55f
|
||||||
|
));
|
||||||
|
containerLayoutParams.weight = 1.35f;
|
||||||
|
viewerBinding.container.setLayoutParams(containerLayoutParams);
|
||||||
viewerBinding.mediaList.setVisibility(View.VISIBLE);
|
viewerBinding.mediaList.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -604,7 +609,7 @@ public final class PostViewer extends BaseLanguageActivity {
|
|||||||
url = viewerPostModel.getDisplayUrl();
|
url = viewerPostModel.getDisplayUrl();
|
||||||
releasePlayer();
|
releasePlayer();
|
||||||
|
|
||||||
viewerBinding.btnDownload.setVisibility(containerLayoutParams.height == 0 ? View.GONE : View.VISIBLE);
|
viewerBinding.btnDownload.setVisibility(containerLayoutParams.weight == 3.3f ? View.GONE : View.VISIBLE);
|
||||||
if (viewerPostModel.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) setupVideo();
|
if (viewerPostModel.getItemType() == MediaItemType.MEDIA_TYPE_VIDEO) setupVideo();
|
||||||
else setupImage();
|
else setupImage();
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import awais.instagrabber.asyncs.ProfilePictureFetcher;
|
|||||||
import awais.instagrabber.databinding.ActivityProfileBinding;
|
import awais.instagrabber.databinding.ActivityProfileBinding;
|
||||||
import awais.instagrabber.dialogs.ProfileSettingsDialog;
|
import awais.instagrabber.dialogs.ProfileSettingsDialog;
|
||||||
import awais.instagrabber.interfaces.FetchListener;
|
import awais.instagrabber.interfaces.FetchListener;
|
||||||
|
import awais.instagrabber.models.HashtagModel;
|
||||||
import awais.instagrabber.models.ProfileModel;
|
import awais.instagrabber.models.ProfileModel;
|
||||||
import awais.instagrabber.models.enums.ProfilePictureFetchMode;
|
import awais.instagrabber.models.enums.ProfilePictureFetchMode;
|
||||||
import awais.instagrabber.utils.Constants;
|
import awais.instagrabber.utils.Constants;
|
||||||
@ -41,11 +42,11 @@ import static awais.instagrabber.utils.Constants.PROFILE_FETCH_MODE;
|
|||||||
public final class ProfileViewer extends BaseLanguageActivity {
|
public final class ProfileViewer extends BaseLanguageActivity {
|
||||||
private final ProfilePictureFetchMode[] fetchModes = {
|
private final ProfilePictureFetchMode[] fetchModes = {
|
||||||
ProfilePictureFetchMode.INSTADP,
|
ProfilePictureFetchMode.INSTADP,
|
||||||
ProfilePictureFetchMode.INSTA_STALKER,
|
ProfilePictureFetchMode.INSTAFULLSIZE
|
||||||
ProfilePictureFetchMode.INSTAFULLSIZE,
|
|
||||||
};
|
};
|
||||||
private ActivityProfileBinding profileBinding;
|
private ActivityProfileBinding profileBinding;
|
||||||
private ProfileModel profileModel;
|
private ProfileModel profileModel;
|
||||||
|
private HashtagModel hashtagModel;
|
||||||
private MenuItem menuItemDownload;
|
private MenuItem menuItemDownload;
|
||||||
private String profilePicUrl;
|
private String profilePicUrl;
|
||||||
private FragmentManager fragmentManager;
|
private FragmentManager fragmentManager;
|
||||||
@ -63,16 +64,17 @@ public final class ProfileViewer extends BaseLanguageActivity {
|
|||||||
setSupportActionBar(profileBinding.toolbar.toolbar);
|
setSupportActionBar(profileBinding.toolbar.toolbar);
|
||||||
|
|
||||||
final Intent intent = getIntent();
|
final Intent intent = getIntent();
|
||||||
if (intent == null || !intent.hasExtra(Constants.EXTRAS_PROFILE)
|
if (intent == null || (!intent.hasExtra(Constants.EXTRAS_PROFILE) && !intent.hasExtra(Constants.EXTRAS_HASHTAG))
|
||||||
|| (profileModel = (ProfileModel) intent.getSerializableExtra(Constants.EXTRAS_PROFILE)) == null) {
|
|| ((profileModel = (ProfileModel) intent.getSerializableExtra(Constants.EXTRAS_PROFILE)) == null
|
||||||
|
&& (hashtagModel = (HashtagModel) intent.getSerializableExtra(Constants.EXTRAS_HASHTAG)) == null)) {
|
||||||
Utils.errorFinish(this);
|
Utils.errorFinish(this);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fragmentManager = getSupportFragmentManager();
|
fragmentManager = getSupportFragmentManager();
|
||||||
|
|
||||||
final String id = profileModel.getId();
|
final String id = hashtagModel != null ? hashtagModel.getId() : profileModel.getId();
|
||||||
final String username = profileModel.getUsername();
|
final String username = hashtagModel != null ? hashtagModel.getName() : profileModel.getUsername();
|
||||||
|
|
||||||
profileBinding.toolbar.toolbar.setTitle(username);
|
profileBinding.toolbar.toolbar.setTitle(username);
|
||||||
|
|
||||||
@ -91,12 +93,12 @@ public final class ProfileViewer extends BaseLanguageActivity {
|
|||||||
|
|
||||||
if (!fallbackToProfile && Utils.isEmpty(profilePicUrl)) {
|
if (!fallbackToProfile && Utils.isEmpty(profilePicUrl)) {
|
||||||
fallbackToProfile = true;
|
fallbackToProfile = true;
|
||||||
new ProfilePictureFetcher(username, id, fetchListener, fetchMode).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
new ProfilePictureFetcher(username, id, fetchListener, fetchMode, profilePicUrl, hashtagModel != null).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorHandled && fallbackToProfile || Utils.isEmpty(profilePicUrl))
|
if (errorHandled && fallbackToProfile || Utils.isEmpty(profilePicUrl))
|
||||||
profilePicUrl = profileModel.getHdProfilePic();
|
profilePicUrl = hashtagModel != null ? hashtagModel.getSdProfilePic() : profileModel.getHdProfilePic();
|
||||||
|
|
||||||
if (destroyed == true) return;
|
if (destroyed == true) return;
|
||||||
|
|
||||||
@ -108,10 +110,10 @@ public final class ProfileViewer extends BaseLanguageActivity {
|
|||||||
fallbackToProfile = true;
|
fallbackToProfile = true;
|
||||||
if (!errorHandled) {
|
if (!errorHandled) {
|
||||||
errorHandled = true;
|
errorHandled = true;
|
||||||
new ProfilePictureFetcher(username, id, fetchListener, fetchModes[Math.min(2, Math.max(0, fetchIndex + 1))])
|
new ProfilePictureFetcher(username, id, fetchListener, fetchModes[Math.min(2, Math.max(0, fetchIndex + 1))], profilePicUrl, hashtagModel != null)
|
||||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
} else {
|
} else {
|
||||||
glideRequestManager.load(profileModel.getHdProfilePic()).into(profileBinding.imageViewer);
|
glideRequestManager.load(profilePicUrl).into(profileBinding.imageViewer);
|
||||||
showImageInfo();
|
showImageInfo();
|
||||||
}
|
}
|
||||||
profileBinding.progressView.setVisibility(View.GONE);
|
profileBinding.progressView.setVisibility(View.GONE);
|
||||||
@ -163,7 +165,8 @@ public final class ProfileViewer extends BaseLanguageActivity {
|
|||||||
}).into(profileBinding.imageViewer);
|
}).into(profileBinding.imageViewer);
|
||||||
};
|
};
|
||||||
|
|
||||||
new ProfilePictureFetcher(username, id, fetchListener, fetchMode).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
new ProfilePictureFetcher(username, id, fetchListener, fetchMode, profilePicUrl, hashtagModel != null)
|
||||||
|
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void downloadProfilePicture() {
|
private void downloadProfilePicture() {
|
||||||
|
@ -368,6 +368,13 @@ public final class StoryViewer extends BaseLanguageActivity {
|
|||||||
storyViewerBinding.viewStoryPost.setTag(shortCode);
|
storyViewerBinding.viewStoryPost.setTag(shortCode);
|
||||||
|
|
||||||
releasePlayer();
|
releasePlayer();
|
||||||
|
final Intent intent = getIntent();
|
||||||
|
if (intent.hasExtra(Constants.EXTRAS_HASHTAG)) {
|
||||||
|
storyViewerBinding.toolbar.toolbar.setTitle(currentStory.getUsername() + " (" + intent.getStringExtra(Constants.EXTRAS_USERNAME) + ")");
|
||||||
|
storyViewerBinding.toolbar.toolbar.setOnClickListener(v -> {
|
||||||
|
searchUsername(currentStory.getUsername());
|
||||||
|
});
|
||||||
|
}
|
||||||
if (itemType == MediaItemType.MEDIA_TYPE_VIDEO) setupVideo();
|
if (itemType == MediaItemType.MEDIA_TYPE_VIDEO) setupVideo();
|
||||||
else setupImage();
|
else setupImage();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
package awais.instagrabber.asyncs;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import awais.instagrabber.BuildConfig;
|
||||||
|
import awais.instagrabber.interfaces.FetchListener;
|
||||||
|
import awais.instagrabber.models.HashtagModel;
|
||||||
|
import awais.instagrabber.utils.Constants;
|
||||||
|
import awais.instagrabber.utils.Utils;
|
||||||
|
import awaisomereport.LogCollector;
|
||||||
|
|
||||||
|
import static awais.instagrabber.utils.Utils.logCollector;
|
||||||
|
|
||||||
|
public final class HashtagFetcher extends AsyncTask<Void, Void, HashtagModel> {
|
||||||
|
private final FetchListener<HashtagModel> fetchListener;
|
||||||
|
private final String hashtag;
|
||||||
|
|
||||||
|
public HashtagFetcher(String hashtag, FetchListener<HashtagModel> fetchListener) {
|
||||||
|
this.hashtag = hashtag;
|
||||||
|
this.fetchListener = fetchListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected HashtagModel doInBackground(final Void... voids) {
|
||||||
|
HashtagModel result = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final HttpURLConnection conn = (HttpURLConnection) new URL("https://www.instagram.com/explore/tags/" + hashtag + "/?__a=1").openConnection();
|
||||||
|
conn.setUseCaches(true);
|
||||||
|
conn.connect();
|
||||||
|
|
||||||
|
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
|
||||||
|
final JSONObject user = new JSONObject(Utils.readFromConnection(conn)).getJSONObject("graphql").getJSONObject(Constants.EXTRAS_HASHTAG);
|
||||||
|
|
||||||
|
final JSONObject timelineMedia = user.getJSONObject("edge_hashtag_to_media");
|
||||||
|
if (timelineMedia.has("edges")) {
|
||||||
|
final JSONArray edges = timelineMedia.getJSONArray("edges");
|
||||||
|
}
|
||||||
|
|
||||||
|
result = new HashtagModel(
|
||||||
|
user.getString(Constants.EXTRAS_ID),
|
||||||
|
user.getString("name"),
|
||||||
|
user.getString("profile_pic_url"),
|
||||||
|
timelineMedia.getLong("count"),
|
||||||
|
user.optBoolean("is_following"));
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.disconnect();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
if (logCollector != null)
|
||||||
|
logCollector.appendException(e, LogCollector.LogFile.ASYNC_HASHTAG_FETCHER, "doInBackground");
|
||||||
|
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(final HashtagModel result) {
|
||||||
|
if (fetchListener != null) fetchListener.onResult(result);
|
||||||
|
}
|
||||||
|
}
|
@ -53,7 +53,7 @@ public final class PostsFetcher extends AsyncTask<Void, Void, PostModel[]> {
|
|||||||
final String url;
|
final String url;
|
||||||
if (isHashTag)
|
if (isHashTag)
|
||||||
url = "https://www.instagram.com/graphql/query/?query_hash=ded47faa9a1aaded10161a2ff32abb6b&variables=" +
|
url = "https://www.instagram.com/graphql/query/?query_hash=ded47faa9a1aaded10161a2ff32abb6b&variables=" +
|
||||||
"{\"tag_name\":\"" + id.substring(1) + "\",\"first\":150,\"after\":\"" + endCursor + "\"}";
|
"{\"tag_name\":\"" + id.substring(1).toLowerCase() + "\",\"first\":150,\"after\":\"" + endCursor + "\"}";
|
||||||
else
|
else
|
||||||
url = "https://www.instagram.com/graphql/query/?query_id=17880160963012870&id=" + id + "&first=50&after=" + endCursor;
|
url = "https://www.instagram.com/graphql/query/?query_id=17880160963012870&id=" + id + "&first=50&after=" + endCursor;
|
||||||
|
|
||||||
|
@ -22,27 +22,29 @@ import static awais.instagrabber.utils.Utils.logCollector;
|
|||||||
|
|
||||||
public final class ProfilePictureFetcher extends AsyncTask<Void, Void, String> {
|
public final class ProfilePictureFetcher extends AsyncTask<Void, Void, String> {
|
||||||
private final FetchListener<String> fetchListener;
|
private final FetchListener<String> fetchListener;
|
||||||
private final String userName, userId;
|
private final String userName, userId, picUrl;
|
||||||
private final ProfilePictureFetchMode fetchMode;
|
private final boolean isHashtag;
|
||||||
|
private ProfilePictureFetchMode fetchMode;
|
||||||
|
|
||||||
public ProfilePictureFetcher(final String userName, final String userId, final FetchListener<String> fetchListener,
|
public ProfilePictureFetcher(final String userName, final String userId, final FetchListener<String> fetchListener,
|
||||||
final ProfilePictureFetchMode fetchMode) {
|
final ProfilePictureFetchMode fetchMode, final String picUrl, final boolean isHashtag) {
|
||||||
this.fetchListener = fetchListener;
|
this.fetchListener = fetchListener;
|
||||||
this.fetchMode = fetchMode;
|
this.fetchMode = fetchMode;
|
||||||
this.userName = userName;
|
this.userName = userName;
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
|
this.picUrl = picUrl;
|
||||||
|
this.isHashtag = isHashtag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String doInBackground(final Void... voids) {
|
protected String doInBackground(final Void... voids) {
|
||||||
String out = null;
|
String out = picUrl;
|
||||||
try {
|
if (!isHashtag) try {
|
||||||
|
if (fetchMode == ProfilePictureFetchMode.INSTA_STALKER) fetchMode = ProfilePictureFetchMode.INSTADP;
|
||||||
final String url;
|
final String url;
|
||||||
|
|
||||||
if (fetchMode == ProfilePictureFetchMode.INSTADP)
|
if (fetchMode == ProfilePictureFetchMode.INSTADP)
|
||||||
url = "https://instadp.com/fullsize/" + userName;
|
url = "https://instadp.com/fullsize/" + userName;
|
||||||
else if (fetchMode == ProfilePictureFetchMode.INSTA_STALKER)
|
|
||||||
url = "https://insta-stalker.co/instadp_fullsize/?id=" + userName;
|
|
||||||
else // select from s1, s2, s3 but s1 works fine
|
else // select from s1, s2, s3 but s1 works fine
|
||||||
url = "https://instafullsize.com/ifsapi/ig/photo/s1/" + userName + "?igid=" + userId;
|
url = "https://instafullsize.com/ifsapi/ig/photo/s1/" + userName + "?igid=" + userId;
|
||||||
|
|
||||||
@ -84,10 +86,6 @@ public final class ProfilePictureFetcher extends AsyncTask<Void, Void, String> {
|
|||||||
fallback = true;
|
fallback = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
final Elements elements = doc.select("img[data-src]");
|
|
||||||
if (elements.size() > 0) out = elements.get(0).attr("data-src");
|
|
||||||
else fallback = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fallback) {
|
if (fallback) {
|
||||||
|
@ -20,11 +20,12 @@ import awaisomereport.LogCollector;
|
|||||||
import static awais.instagrabber.utils.Utils.logCollector;
|
import static awais.instagrabber.utils.Utils.logCollector;
|
||||||
|
|
||||||
public final class StoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[]> {
|
public final class StoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[]> {
|
||||||
private final String id;
|
private final String id, hashtag;
|
||||||
private final FetchListener<StoryModel[]> fetchListener;
|
private final FetchListener<StoryModel[]> fetchListener;
|
||||||
|
|
||||||
public StoryStatusFetcher(final String id, final FetchListener<StoryModel[]> fetchListener) {
|
public StoryStatusFetcher(final String id, final String hashtag, final FetchListener<StoryModel[]> fetchListener) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
this.hashtag = hashtag;
|
||||||
this.fetchListener = fetchListener;
|
this.fetchListener = fetchListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +33,8 @@ public final class StoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[]
|
|||||||
protected StoryModel[] doInBackground(final Void... voids) {
|
protected StoryModel[] doInBackground(final Void... voids) {
|
||||||
StoryModel[] result = null;
|
StoryModel[] result = null;
|
||||||
final String url = "https://www.instagram.com/graphql/query/?query_hash=52a36e788a02a3c612742ed5146f1676&variables=" +
|
final String url = "https://www.instagram.com/graphql/query/?query_hash=52a36e788a02a3c612742ed5146f1676&variables=" +
|
||||||
"{\"precomposed_overlay\":false,\"reel_ids\":[\"" + id + "\"]}";
|
"{\"precomposed_overlay\":false,\"reel_ids\":[\"" + id + "\"]"
|
||||||
|
+(!Utils.isEmpty(hashtag) ? (",\"tag_names\":\""+hashtag+"\"") : "")+"}";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||||
@ -61,7 +63,8 @@ public final class StoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[]
|
|||||||
models[i] = new StoryModel(data.getString(Constants.EXTRAS_ID),
|
models[i] = new StoryModel(data.getString(Constants.EXTRAS_ID),
|
||||||
data.getString("display_url"),
|
data.getString("display_url"),
|
||||||
isVideo ? MediaItemType.MEDIA_TYPE_VIDEO : MediaItemType.MEDIA_TYPE_IMAGE,
|
isVideo ? MediaItemType.MEDIA_TYPE_VIDEO : MediaItemType.MEDIA_TYPE_IMAGE,
|
||||||
data.optLong("taken_at_timestamp", 0));
|
data.optLong("taken_at_timestamp", 0),
|
||||||
|
data.getJSONObject("owner").getString("username"));
|
||||||
|
|
||||||
final JSONArray videoResources = data.optJSONArray("video_resources");
|
final JSONArray videoResources = data.optJSONArray("video_resources");
|
||||||
if (isVideo && videoResources != null)
|
if (isVideo && videoResources != null)
|
||||||
|
@ -28,7 +28,7 @@ public class GridAutofitLayoutManager extends GridLayoutManager {
|
|||||||
final int totalSpace = getOrientation() == VERTICAL ? width - getPaddingRight() - getPaddingLeft()
|
final int totalSpace = getOrientation() == VERTICAL ? width - getPaddingRight() - getPaddingLeft()
|
||||||
: height - getPaddingTop() - getPaddingBottom();
|
: height - getPaddingTop() - getPaddingBottom();
|
||||||
|
|
||||||
setSpanCount(Math.max(1, totalSpace / mColumnWidth));
|
setSpanCount(Math.max(1, Math.min(totalSpace / mColumnWidth, 3)));
|
||||||
|
|
||||||
mColumnWidthChanged = false;
|
mColumnWidthChanged = false;
|
||||||
}
|
}
|
||||||
|
33
app/src/main/java/awais/instagrabber/models/HashtagModel.java
Executable file
33
app/src/main/java/awais/instagrabber/models/HashtagModel.java
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
package awais.instagrabber.models;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public final class HashtagModel implements Serializable {
|
||||||
|
private final boolean following;
|
||||||
|
private final long postCount;
|
||||||
|
private final String id, name, sdProfilePic;
|
||||||
|
|
||||||
|
public HashtagModel(final String id, final String name, final String sdProfilePic, final long postCount, final boolean following) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.sdProfilePic = sdProfilePic;
|
||||||
|
this.postCount = postCount;
|
||||||
|
this.following = following;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSdProfilePic() {
|
||||||
|
return sdProfilePic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPostCount() { return postCount; }
|
||||||
|
|
||||||
|
public boolean getFollowing() { return following; }
|
||||||
|
}
|
@ -5,18 +5,19 @@ import java.io.Serializable;
|
|||||||
import awais.instagrabber.models.enums.MediaItemType;
|
import awais.instagrabber.models.enums.MediaItemType;
|
||||||
|
|
||||||
public final class StoryModel implements Serializable {
|
public final class StoryModel implements Serializable {
|
||||||
private final String storyMediaId, storyUrl;
|
private final String storyMediaId, storyUrl, username;
|
||||||
private final MediaItemType itemType;
|
private final MediaItemType itemType;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private String videoUrl, tappableShortCode;
|
private String videoUrl, tappableShortCode;
|
||||||
private int position;
|
private int position;
|
||||||
private boolean isCurrentSlide = false;
|
private boolean isCurrentSlide = false;
|
||||||
|
|
||||||
public StoryModel(final String storyMediaId, final String storyUrl, final MediaItemType itemType, final long timestamp) {
|
public StoryModel(final String storyMediaId, final String storyUrl, final MediaItemType itemType, final long timestamp, final String username) {
|
||||||
this.storyMediaId = storyMediaId;
|
this.storyMediaId = storyMediaId;
|
||||||
this.storyUrl = storyUrl;
|
this.storyUrl = storyUrl;
|
||||||
this.itemType = itemType;
|
this.itemType = itemType;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
|
this.username = username;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStoryUrl() {
|
public String getStoryUrl() {
|
||||||
@ -66,4 +67,8 @@ public final class StoryModel implements Serializable {
|
|||||||
public boolean isCurrentSlide() {
|
public boolean isCurrentSlide() {
|
||||||
return isCurrentSlide;
|
return isCurrentSlide;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,6 +2,6 @@ package awais.instagrabber.models.enums;
|
|||||||
|
|
||||||
public enum ProfilePictureFetchMode {
|
public enum ProfilePictureFetchMode {
|
||||||
INSTADP,
|
INSTADP,
|
||||||
INSTA_STALKER,
|
|
||||||
INSTAFULLSIZE,
|
INSTAFULLSIZE,
|
||||||
|
INSTA_STALKER,
|
||||||
}
|
}
|
@ -25,6 +25,7 @@ public final class Constants {
|
|||||||
public static final String SHOW_QUICK_ACCESS_DIALOG = "show_quick_dlg";
|
public static final String SHOW_QUICK_ACCESS_DIALOG = "show_quick_dlg";
|
||||||
//////////////////////// EXTRAS ////////////////////////
|
//////////////////////// EXTRAS ////////////////////////
|
||||||
public static final String EXTRAS_USER = "user";
|
public static final String EXTRAS_USER = "user";
|
||||||
|
public static final String EXTRAS_HASHTAG = "hashtag";
|
||||||
public static final String EXTRAS_USERNAME = "username";
|
public static final String EXTRAS_USERNAME = "username";
|
||||||
public static final String EXTRAS_ID = "id";
|
public static final String EXTRAS_ID = "id";
|
||||||
public static final String EXTRAS_POST = "post";
|
public static final String EXTRAS_POST = "post";
|
||||||
|
@ -46,7 +46,7 @@ public final class DataBox extends SQLiteOpenHelper {
|
|||||||
@Override
|
@Override
|
||||||
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { }
|
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { }
|
||||||
|
|
||||||
///////////////////////////////////////// YOUR WEIRD FETIS-FAVORITES! HERE /////////////////////////////////////////
|
///////////////////////////////////////// YOUR FAVORITES! HERE /////////////////////////////////////////
|
||||||
public final void addFavorite(@NonNull final FavoriteModel favoriteModel) {
|
public final void addFavorite(@NonNull final FavoriteModel favoriteModel) {
|
||||||
final String query = favoriteModel.getQuery();
|
final String query = favoriteModel.getQuery();
|
||||||
if (!Utils.isEmpty(query)) {
|
if (!Utils.isEmpty(query)) {
|
||||||
@ -114,6 +114,20 @@ public final class DataBox extends SQLiteOpenHelper {
|
|||||||
|
|
||||||
return favorites;
|
return favorites;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final String getFavorite(@NonNull final String query) {
|
||||||
|
ArrayList<FavoriteModel> favorites = null;
|
||||||
|
|
||||||
|
try (final SQLiteDatabase db = getReadableDatabase();
|
||||||
|
final Cursor cursor = db.rawQuery("SELECT query_text, date_added FROM favorites WHERE "
|
||||||
|
+KEY_QUERY_TEXT+"='"+query+"' ORDER BY date_added DESC", null)) {
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
return cursor.getString(0) + "/" + String.valueOf(cursor.getLong(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
///////////////////////////////////// YOUR COOKIES FOR COOKIE MONSTER ARE HERE /////////////////////////////////////
|
///////////////////////////////////// YOUR COOKIES FOR COOKIE MONSTER ARE HERE /////////////////////////////////////
|
||||||
|
@ -17,6 +17,7 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import awais.instagrabber.BuildConfig;
|
import awais.instagrabber.BuildConfig;
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
@ -26,15 +27,29 @@ import static awais.instagrabber.utils.Utils.settingsHelper;
|
|||||||
|
|
||||||
public final class FlavorTown {
|
public final class FlavorTown {
|
||||||
public static void updateCheck(@NonNull final Context context) {
|
public static void updateCheck(@NonNull final Context context) {
|
||||||
new UpdateChecker(versionUrl -> {
|
Resources res = context.getResources();
|
||||||
new AlertDialog.Builder(context).setTitle(R.string.update_available).setNegativeButton(R.string.cancel, null)
|
new UpdateChecker(version -> {
|
||||||
.setPositiveButton(R.string.action_download, (dialog, which) -> {
|
new AlertDialog.Builder(context)
|
||||||
|
.setTitle(res.getString(R.string.update_available) + " (" + version + ")")
|
||||||
|
.setMessage(R.string.update_notice)
|
||||||
|
.setNeutralButton(R.string.cancel, null)
|
||||||
|
.setNegativeButton(R.string.action_github, (dialog, which) -> {
|
||||||
try {
|
try {
|
||||||
context.startActivity(new Intent(Intent.ACTION_VIEW).setData(Uri.parse(versionUrl)));
|
context.startActivity(new Intent(Intent.ACTION_VIEW).setData(
|
||||||
|
Uri.parse("https://github.com/austinhuang0131/instagrabber/releases/tag/" + version)));
|
||||||
} catch (final ActivityNotFoundException e) {
|
} catch (final ActivityNotFoundException e) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
}).show();
|
})
|
||||||
|
.setPositiveButton(R.string.action_fdroid, (dialog, which) -> {
|
||||||
|
try {
|
||||||
|
context.startActivity(new Intent(Intent.ACTION_VIEW).setData(
|
||||||
|
Uri.parse("https://f-droid.org/packages/me.austinhuang.instagrabber/")));
|
||||||
|
} catch (final ActivityNotFoundException e) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import awais.instagrabber.interfaces.FetchListener;
|
|||||||
|
|
||||||
public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
|
public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
|
||||||
private final FetchListener<String> fetchListener;
|
private final FetchListener<String> fetchListener;
|
||||||
private String versionUrl;
|
private String version;
|
||||||
|
|
||||||
public UpdateChecker(final FetchListener<String> fetchListener) {
|
public UpdateChecker(final FetchListener<String> fetchListener) {
|
||||||
this.fetchListener = fetchListener;
|
this.fetchListener = fetchListener;
|
||||||
@ -22,17 +22,17 @@ public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(final Void... voids) {
|
protected Boolean doInBackground(final Void... voids) {
|
||||||
final String UPDATE_BASE_URL = "https://github.com/austinhuang0131/instagrabber/releases/tag/v";
|
final String UPDATE_BASE_URL = "https://github.com/austinhuang0131/instagrabber/releases/tag/";
|
||||||
final String versionName = BuildConfig.VERSION_NAME;
|
final String versionName = BuildConfig.VERSION_NAME;
|
||||||
final int index = versionName.indexOf('.');
|
final int index = versionName.indexOf('.');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final int verMajor = Integer.parseInt(versionName.substring(0, index));
|
final int verMajor = Integer.parseInt(versionName.substring(0, index));
|
||||||
|
|
||||||
versionUrl = UPDATE_BASE_URL + (verMajor + 1) + ".0";
|
version = "v" + (verMajor + 1) + ".0";
|
||||||
|
|
||||||
// check major version first
|
// check major version first
|
||||||
HttpURLConnection conn = (HttpURLConnection) new URL(versionUrl).openConnection();
|
HttpURLConnection conn = (HttpURLConnection) new URL(UPDATE_BASE_URL + version).openConnection();
|
||||||
conn.setUseCaches(false);
|
conn.setUseCaches(false);
|
||||||
conn.setRequestMethod("HEAD");
|
conn.setRequestMethod("HEAD");
|
||||||
conn.connect();
|
conn.connect();
|
||||||
@ -46,10 +46,10 @@ public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
|
|||||||
final int verMinor = Integer.parseInt(substring) + 1;
|
final int verMinor = Integer.parseInt(substring) + 1;
|
||||||
|
|
||||||
for (int i = verMinor; i < 10; ++i) {
|
for (int i = verMinor; i < 10; ++i) {
|
||||||
versionUrl = UPDATE_BASE_URL + verMajor + '.' + i;
|
version = "v" + verMajor + '.' + i;
|
||||||
conn.disconnect();
|
conn.disconnect();
|
||||||
|
|
||||||
conn = (HttpURLConnection) new URL(versionUrl).openConnection();
|
conn = (HttpURLConnection) new URL(UPDATE_BASE_URL + version).openConnection();
|
||||||
conn.setUseCaches(false);
|
conn.setUseCaches(false);
|
||||||
conn.setRequestMethod("HEAD");
|
conn.setRequestMethod("HEAD");
|
||||||
conn.connect();
|
conn.connect();
|
||||||
@ -70,6 +70,6 @@ public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
|
|||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(final Boolean result) {
|
protected void onPostExecute(final Boolean result) {
|
||||||
if (result != null && result && fetchListener != null)
|
if (result != null && result && fetchListener != null)
|
||||||
fetchListener.onResult(versionUrl);
|
fetchListener.onResult(version);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1155,7 +1155,7 @@ public final class Utils {
|
|||||||
|
|
||||||
storyModels[j] = new StoryModel(data.getString(Constants.EXTRAS_ID), data.getString("display_url"),
|
storyModels[j] = new StoryModel(data.getString(Constants.EXTRAS_ID), data.getString("display_url"),
|
||||||
isVideo ? MediaItemType.MEDIA_TYPE_VIDEO : MediaItemType.MEDIA_TYPE_IMAGE,
|
isVideo ? MediaItemType.MEDIA_TYPE_VIDEO : MediaItemType.MEDIA_TYPE_IMAGE,
|
||||||
data.getLong("taken_at_timestamp"));
|
data.getLong("taken_at_timestamp"), data.getJSONObject("owner").getString("username"));
|
||||||
|
|
||||||
if (isVideo && data.has("video_resources"))
|
if (isVideo && data.has("video_resources"))
|
||||||
storyModels[j].setVideoUrl(Utils.getHighQualityPost(data.getJSONArray("video_resources"), true));
|
storyModels[j].setVideoUrl(Utils.getHighQualityPost(data.getJSONArray("video_resources"), true));
|
||||||
|
@ -106,6 +106,7 @@ public final class LogCollector {
|
|||||||
ASYNC_MAIN_POSTS_FETCHER("async-main-posts-fetcher.txt"),
|
ASYNC_MAIN_POSTS_FETCHER("async-main-posts-fetcher.txt"),
|
||||||
ASYNC_POST_FETCHER("async-single-post-fetcher.txt"),
|
ASYNC_POST_FETCHER("async-single-post-fetcher.txt"),
|
||||||
ASYNC_FEED_FETCHER("async-feed-fetcher.txt"),
|
ASYNC_FEED_FETCHER("async-feed-fetcher.txt"),
|
||||||
|
ASYNC_HASHTAG_FETCHER("async-hashtag-fetcher.txt"),
|
||||||
ASYNC_PROFILE_FETCHER("async-profile-fetcher.txt"),
|
ASYNC_PROFILE_FETCHER("async-profile-fetcher.txt"),
|
||||||
ASYNC_PROFILE_PICTURE_FETCHER("async-pfp-fetcher.txt"),
|
ASYNC_PROFILE_PICTURE_FETCHER("async-pfp-fetcher.txt"),
|
||||||
ASYNC_STORY_STATUS_FETCHER("async-story-status-fetcher.txt"),
|
ASYNC_STORY_STATUS_FETCHER("async-story-status-fetcher.txt"),
|
||||||
|
@ -227,6 +227,63 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||||
|
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||||
|
android:id="@+id/tagToolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_scrollFlags="scroll|exitUntilCollapsed"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/tagInfoContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
|
android:background="@null"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="5dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/hashtagInfo"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="@dimen/profile_info_container_bottom_space">
|
||||||
|
|
||||||
|
<awais.instagrabber.customviews.CircularImageView
|
||||||
|
android:id="@+id/mainHashtagImage"
|
||||||
|
android:layout_width="@dimen/profile_picture_size"
|
||||||
|
android:layout_height="@dimen/profile_picture_size"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:background="?selectableItemBackgroundBorderless" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
|
android:id="@+id/mainTagPostCount"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:layout_marginRight="12dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:text="35\nPosts" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatButton
|
||||||
|
android:id="@+id/btnFollowTag"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_weight="2"
|
||||||
|
android:text="@string/follow"
|
||||||
|
android:textColor="@color/btn_pink_text_color"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:backgroundTint="@color/btn_pink_background" />
|
||||||
|
</LinearLayout>
|
||||||
|
</RelativeLayout>
|
||||||
|
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:weightSum="3.2"
|
||||||
android:animateLayoutChanges="true"
|
android:animateLayoutChanges="true"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
tools:context=".activities.PostViewer">
|
tools:context=".activities.PostViewer">
|
||||||
@ -27,7 +28,7 @@
|
|||||||
android:id="@+id/container"
|
android:id="@+id/container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1.6">
|
android:layout_weight="1.9">
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.PlayerView
|
<com.google.android.exoplayer2.ui.PlayerView
|
||||||
android:id="@+id/playerView"
|
android:id="@+id/playerView"
|
||||||
@ -81,7 +82,7 @@
|
|||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/mediaList"
|
android:id="@+id/mediaList"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingStart="5dp"
|
android:paddingStart="5dp"
|
||||||
@ -95,12 +96,12 @@
|
|||||||
layout="@layout/item_feed_bottom"
|
layout="@layout/item_feed_bottom"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1.4" />
|
android:layout_weight="1"/>
|
||||||
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="0.26"
|
android:layout_weight="0.3"
|
||||||
android:background="#0000"
|
android:background="#0000"
|
||||||
android:weightSum="2"
|
android:weightSum="2"
|
||||||
android:layout_alignParentBottom="true">
|
android:layout_alignParentBottom="true">
|
||||||
@ -119,6 +120,7 @@
|
|||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatButton
|
<androidx.appcompat.widget.AppCompatButton
|
||||||
android:id="@+id/btnBookmark"
|
android:id="@+id/btnBookmark"
|
||||||
|
android:layout_alignParentBottom="true"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="8dp"
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="profile_fetch_modes">
|
<string-array name="profile_fetch_modes">
|
||||||
<item>Instadp</item>
|
<item>Instadp</item>
|
||||||
<item>Insta-Stalker</item>
|
|
||||||
<item>Instafullsize</item>
|
<item>Instafullsize</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="date_presets">
|
<string-array name="date_presets">
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
<string name="title_favorites">Favoritos</string>
|
<string name="title_favorites">Favoritos</string>
|
||||||
<string name="title_discover">Explorar</string>
|
<string name="title_discover">Explorar</string>
|
||||||
<string name="title_comments">Comentarios</string>
|
<string name="title_comments">Comentarios</string>
|
||||||
<string name="title_hashtag_prefix">Hashtag: </string>
|
|
||||||
<string name="title_highlight">Resaltado: %s</string>
|
<string name="title_highlight">Resaltado: %s</string>
|
||||||
<string name="title_user_story">Historia de usuario</string>
|
<string name="title_user_story">Historia de usuario</string>
|
||||||
<string name="title_changelog">Lista de cambios</string>
|
<string name="title_changelog">Lista de cambios</string>
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="profile_fetch_modes">
|
<string-array name="profile_fetch_modes">
|
||||||
<item>Instadp</item>
|
<item>Instadp</item>
|
||||||
<item>Insta-Stalker</item>
|
|
||||||
<item>Instafullsize</item>
|
<item>Instafullsize</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="date_presets">
|
<string-array name="date_presets">
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
<string name="title_favorites">Favoris</string>
|
<string name="title_favorites">Favoris</string>
|
||||||
<string name="title_discover">Découvrir</string>
|
<string name="title_discover">Découvrir</string>
|
||||||
<string name="title_comments">Commentaires</string>
|
<string name="title_comments">Commentaires</string>
|
||||||
<string name="title_hashtag_prefix">Hashtag: </string>
|
|
||||||
<string name="title_highlight">Highlight: %s</string>
|
<string name="title_highlight">Highlight: %s</string>
|
||||||
<string name="title_user_story">Stories de l\'utilisateur</string>
|
<string name="title_user_story">Stories de l\'utilisateur</string>
|
||||||
<string name="title_changelog">Journal des changements</string>
|
<string name="title_changelog">Journal des changements</string>
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="profile_fetch_modes">
|
<string-array name="profile_fetch_modes">
|
||||||
<item>Instadp</item>
|
<item>Instadp</item>
|
||||||
<item>Insta-Stalker</item>
|
|
||||||
<item>Instafullsize</item>
|
<item>Instafullsize</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="date_presets">
|
<string-array name="date_presets">
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
<string name="title_favorites">Favorit</string>
|
<string name="title_favorites">Favorit</string>
|
||||||
<string name="title_discover">Temukan</string>
|
<string name="title_discover">Temukan</string>
|
||||||
<string name="title_comments">Komentar</string>
|
<string name="title_comments">Komentar</string>
|
||||||
<string name="title_hashtag_prefix">Hashtag: </string>
|
|
||||||
<string name="title_highlight">Sorotan: %s</string>
|
<string name="title_highlight">Sorotan: %s</string>
|
||||||
<string name="title_user_story">Story</string>
|
<string name="title_user_story">Story</string>
|
||||||
<string name="title_changelog">Catatan Perubahan</string>
|
<string name="title_changelog">Catatan Perubahan</string>
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="profile_fetch_modes">
|
<string-array name="profile_fetch_modes">
|
||||||
<item>Instadp</item>
|
<item>Instadp</item>
|
||||||
<item>Insta-Stalker</item>
|
|
||||||
<item>Instafullsize</item>
|
<item>Instafullsize</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="date_presets">
|
<string-array name="date_presets">
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
<string name="title_favorites">Favoriti</string>
|
<string name="title_favorites">Favoriti</string>
|
||||||
<string name="title_discover">Scopri</string>
|
<string name="title_discover">Scopri</string>
|
||||||
<string name="title_comments">Commenti</string>
|
<string name="title_comments">Commenti</string>
|
||||||
<string name="title_hashtag_prefix">Hashtag: </string>
|
|
||||||
<string name="title_highlight">Contenuto in evidenza: %s</string>
|
<string name="title_highlight">Contenuto in evidenza: %s</string>
|
||||||
<string name="title_user_story">Storia Utente</string>
|
<string name="title_user_story">Storia Utente</string>
|
||||||
<string name="title_changelog">Changelog</string>
|
<string name="title_changelog">Changelog</string>
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="profile_fetch_modes">
|
<string-array name="profile_fetch_modes">
|
||||||
<item>Instadp</item>
|
<item>Instadp</item>
|
||||||
<item>Insta-Stalker</item>
|
|
||||||
<item>Instafullsize</item>
|
<item>Instafullsize</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="date_presets">
|
<string-array name="date_presets">
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
<string name="title_favorites">最爱</string>
|
<string name="title_favorites">最爱</string>
|
||||||
<string name="title_discover">发现</string>
|
<string name="title_discover">发现</string>
|
||||||
<string name="title_comments">留言</string>
|
<string name="title_comments">留言</string>
|
||||||
<string name="title_hashtag_prefix">标签: </string>
|
|
||||||
<string name="title_highlight">精彩:%s</string>
|
<string name="title_highlight">精彩:%s</string>
|
||||||
<string name="title_user_story">用户快拍</string>
|
<string name="title_user_story">用户快拍</string>
|
||||||
<string name="title_changelog">日志</string>
|
<string name="title_changelog">日志</string>
|
||||||
@ -106,7 +105,7 @@
|
|||||||
<string name="quick_access_confirm_delete">你真的要删除 %s?</string>
|
<string name="quick_access_confirm_delete">你真的要删除 %s?</string>
|
||||||
<string name="profile_viewer_imageinfo">宽: %d\n高: %d</string>
|
<string name="profile_viewer_imageinfo">宽: %d\n高: %d</string>
|
||||||
<string name="profile_viewer_colordepth_prefix">\n色深:</string>
|
<string name="profile_viewer_colordepth_prefix">\n色深:</string>
|
||||||
<string name="profile_endpoint">选择头像服务</string>
|
<string name="profile_endpoint">选择头像服务\n(不影响#标签)</string>
|
||||||
<string name="open_profile">打开主页</string>
|
<string name="open_profile">打开主页</string>
|
||||||
<string name="view_pfp">查看头像</string>
|
<string name="view_pfp">查看头像</string>
|
||||||
<string name="direct_messages_you">你</string>
|
<string name="direct_messages_you">你</string>
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
|
|
||||||
<string-array name="profile_fetch_modes">
|
<string-array name="profile_fetch_modes">
|
||||||
<item>Instadp</item>
|
<item>Instadp</item>
|
||||||
<item>Insta-Stalker</item>
|
|
||||||
<item>Instafullsize</item>
|
<item>Instafullsize</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
<string name="action_setting">Settings (v%s)</string>
|
<string name="action_setting">Settings (v%s)</string>
|
||||||
<string name="action_settings">Settings</string>
|
<string name="action_settings">Settings</string>
|
||||||
<string name="action_download">Download</string>
|
<string name="action_download">Download</string>
|
||||||
|
<string name="action_github" translatable="false">GitHub</string>
|
||||||
|
<string name="action_fdroid" translatable="false">F-Droid</string>
|
||||||
<string name="action_search">Search username…</string>
|
<string name="action_search">Search username…</string>
|
||||||
<string name="action_compare">Compare</string>
|
<string name="action_compare">Compare</string>
|
||||||
|
|
||||||
@ -31,7 +33,6 @@
|
|||||||
<string name="title_favorites">Favorites</string>
|
<string name="title_favorites">Favorites</string>
|
||||||
<string name="title_discover">Discover</string>
|
<string name="title_discover">Discover</string>
|
||||||
<string name="title_comments">Comments</string>
|
<string name="title_comments">Comments</string>
|
||||||
<string name="title_hashtag_prefix">Hashtag: </string>
|
|
||||||
<string name="title_highlight">Highlight: %s</string>
|
<string name="title_highlight">Highlight: %s</string>
|
||||||
<string name="title_user_story">User Story</string>
|
<string name="title_user_story">User Story</string>
|
||||||
<string name="title_changelog">Changelog</string>
|
<string name="title_changelog">Changelog</string>
|
||||||
@ -88,6 +89,10 @@
|
|||||||
|
|
||||||
<string name="follow">Follow</string>
|
<string name="follow">Follow</string>
|
||||||
<string name="unfollow">Unfollow</string>
|
<string name="unfollow">Unfollow</string>
|
||||||
|
<string name="favorite">Add to Favorites</string>
|
||||||
|
<string name="unfavorite">Remove from Favorites</string>
|
||||||
|
<string name="favorite_short">Favorite</string>
|
||||||
|
<string name="unfavorite_short">Unfavorite</string>
|
||||||
<string name="block">Block</string>
|
<string name="block">Block</string>
|
||||||
<string name="unblock">Unblock</string>
|
<string name="unblock">Unblock</string>
|
||||||
<string name="restrict">Restrict</string>
|
<string name="restrict">Restrict</string>
|
||||||
@ -124,7 +129,7 @@
|
|||||||
|
|
||||||
<string name="profile_viewer_imageinfo">Width: %d\nHeight: %d</string>
|
<string name="profile_viewer_imageinfo">Width: %d\nHeight: %d</string>
|
||||||
<string name="profile_viewer_colordepth_prefix">\nColor depth:</string>
|
<string name="profile_viewer_colordepth_prefix">\nColor depth:</string>
|
||||||
<string name="profile_endpoint">Select profile picture endpoint</string>
|
<string name="profile_endpoint">Select profile picture endpoint\n(Does not affect hashtags)</string>
|
||||||
<string name="open_profile">Open profile</string>
|
<string name="open_profile">Open profile</string>
|
||||||
<string name="view_pfp">View profile picture</string>
|
<string name="view_pfp">View profile picture</string>
|
||||||
|
|
||||||
@ -182,6 +187,7 @@
|
|||||||
<string name="login_success_loading_cookies">Successfully loaded cookies!\nIf you still can\'t open private pages/posts, re-login!</string>
|
<string name="login_success_loading_cookies">Successfully loaded cookies!\nIf you still can\'t open private pages/posts, re-login!</string>
|
||||||
|
|
||||||
<string name="update_available">An update is available!</string>
|
<string name="update_available">An update is available!</string>
|
||||||
|
<string name="update_notice">Reminder: If you downloaded from F-Droid, you must update from it! Same applies for GitHub.</string>
|
||||||
<string name="updated">Thank you for updating InstaGrabber!</string>
|
<string name="updated">Thank you for updating InstaGrabber!</string>
|
||||||
<string name="crash_title">App crashed</string>
|
<string name="crash_title">App crashed</string>
|
||||||
<string name="crash_descr">Oops.. the app crashed, but don\'t worry you can send error report to the developer to help him fix the issue. (:</string>
|
<string name="crash_descr">Oops.. the app crashed, but don\'t worry you can send error report to the developer to help him fix the issue. (:</string>
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
v16.7 build 32:
|
|
||||||
|
|
||||||
* You can now (un)follow/restrict/block people
|
* You can now (un)follow/restrict/block people
|
||||||
* For this reason, "Open in Instagram" for following/follower list is removed
|
* For this reason, "Open in Instagram" for following/follower list is removed
|
||||||
* Link in bio is now under bio text (like the actual Instagram app)
|
* Link in bio is now under bio text (like the actual Instagram app)
|
||||||
|
9
fastlane/metadata/android/changelogs/33.txt
Normal file
9
fastlane/metadata/android/changelogs/33.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
* Full support on hashtags, including stories, "profile picture" (SD only), post count, and (un)following. Removed "Hashtag:" prefix.
|
||||||
|
* Non-logged-in users now have an "add/remove from favorites" button on the profile/hashtag page, alongside Quick Access.
|
||||||
|
* Update checker will now have a F-Droid button
|
||||||
|
* Updated Italian and Simplified Chinese translations
|
||||||
|
* Adjusted grid size threshold at popular request
|
||||||
|
* Adjusted post viewer component sizes (to prevent the buttons being squished downwards, but the exact outcome depends on device)
|
||||||
|
* Fixed a bug where highlights of the viewed user gets carried to other users
|
||||||
|
* Fixed a bug where mentions in feeds were parsed incorrectly
|
||||||
|
* Removed Insta-Stalker (defunct) as an HD profile picture provider, existing users are moved to Instafullsize upon first run.
|
@ -3,10 +3,13 @@ InstaGrabber is an app that allows...
|
|||||||
* Viewing **and downloading** Instagram posts, stories (including highlights)\*, DM\*, and profile pictures, **without** letting people know you viewed it! Works for followed private accounts\*!
|
* Viewing **and downloading** Instagram posts, stories (including highlights)\*, DM\*, and profile pictures, **without** letting people know you viewed it! Works for followed private accounts\*!
|
||||||
* Like/bookmark posts\*!
|
* Like/bookmark posts\*!
|
||||||
* Downloading multiple posts at once (hold & select)!
|
* Downloading multiple posts at once (hold & select)!
|
||||||
|
* (Un)follow/restrict/block people\*, and (un)follow hashtags\*! (Or you can add shortcuts to them, without logging in!)
|
||||||
* **Copy** post captions, comments, DM messages\*, and profile bios.
|
* **Copy** post captions, comments, DM messages\*, and profile bios.
|
||||||
* **Compare** follower/following list!
|
* **Compare** follower/following list!
|
||||||
* Searching usernames and hashtags.
|
* Searching usernames and hashtags.
|
||||||
|
|
||||||
<sub>* Requires [login](https://github.com/austinhuang0131/instagrabber/blob/master/README.md#how-to-log-in). You must be a current follower of the desired private accounts, this app cannot hack people (which I have to state despite the obvious)!</sub>
|
<sub>* Requires [login](https://github.com/austinhuang0131/instagrabber/blob/master/README.md#how-to-log-in). You must be a current follower of the desired private accounts, this app cannot hack people (which I have to state despite the obvious)!</sub>
|
||||||
|
|
||||||
It can be used as a drop-in replacement for read functionalities of the official Instagram app, with unnecessary components stripped.
|
It can be used as a drop-in replacement for read functionalities of the official Instagram app, with unnecessary components stripped.
|
||||||
|
|
||||||
|
Remember to read the [wiki](https://github.com/austinhuang0131/instagrabber/wiki) for more info!
|
Binary file not shown.
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 146 KiB |
BIN
fastlane/metadata/android/images/phoneScreenshots/4.jpg
Normal file
BIN
fastlane/metadata/android/images/phoneScreenshots/4.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 159 KiB |
@ -1 +1 @@
|
|||||||
A simple yet advanced viewer/downloader app for Instagram (+login support).
|
A simple yet advanced client for Instagram, with login support!
|
||||||
|
Loading…
Reference in New Issue
Block a user