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\*!
|
||||
* Like/bookmark posts\*!
|
||||
* Follow/restrict/block people\*!
|
||||
* 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.
|
||||
* **Compare** follower/following list<sup>2</sup>!
|
||||
* Searching usernames and hashtags.
|
||||
|
@ -54,6 +54,7 @@ import awais.instagrabber.adapters.PostsAdapter;
|
||||
import awais.instagrabber.asyncs.DiscoverFetcher;
|
||||
import awais.instagrabber.asyncs.FeedFetcher;
|
||||
import awais.instagrabber.asyncs.FeedStoriesFetcher;
|
||||
import awais.instagrabber.asyncs.HashtagFetcher;
|
||||
import awais.instagrabber.asyncs.HighlightsFetcher;
|
||||
import awais.instagrabber.asyncs.PostsFetcher;
|
||||
import awais.instagrabber.asyncs.ProfileFetcher;
|
||||
@ -70,12 +71,14 @@ import awais.instagrabber.models.BasePostModel;
|
||||
import awais.instagrabber.models.DiscoverItemModel;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.models.FeedStoryModel;
|
||||
import awais.instagrabber.models.HashtagModel;
|
||||
import awais.instagrabber.models.IntentModel;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
import awais.instagrabber.models.StoryModel;
|
||||
import awais.instagrabber.models.enums.IntentModelType;
|
||||
import awais.instagrabber.models.enums.ItemGetType;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
import awais.instagrabber.utils.DataBox;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
import awaisomereport.LogCollector;
|
||||
|
||||
@ -115,7 +118,7 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
final PostModel model = result[result.length - 1];
|
||||
@ -138,8 +141,10 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
||||
if ((autoloadPosts && hasNextPage) && !isHashtag)
|
||||
currentlyExecuting = new PostsFetcher(main.profileModel.getId(), endCursor, this)
|
||||
.setUsername(main.profileModel.getUsername()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
else
|
||||
else {
|
||||
main.mainBinding.swipeRefreshLayout.setRefreshing(false);
|
||||
main.mainBinding.tagToolbar.setVisibility(View.VISIBLE);
|
||||
}
|
||||
model.setPageCursor(false, null);
|
||||
}
|
||||
}
|
||||
@ -253,6 +258,7 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
||||
private RecyclerLazyLoader feedLazyLoader, discoverLazyLoader;
|
||||
private DiscoverAdapter discoverAdapter;
|
||||
public SimpleExoPlayer currentFeedPlayer; // hack for remix drawer layout
|
||||
final boolean isLoggedIn = !Utils.isEmpty(Utils.settingsHelper.getString(Constants.COOKIE));
|
||||
|
||||
public MainHelper(@NonNull final Main main) {
|
||||
stopCurrentExecutor();
|
||||
@ -264,8 +270,6 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
||||
main.mainBinding.swipeRefreshLayout.setOnRefreshListener(this);
|
||||
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 ImageView iconFeed = (ImageView) iconSlider.getChildAt(0);
|
||||
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());
|
||||
}
|
||||
|
||||
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.addItemDecoration(new GridSpacingItemDecoration(Utils.convertDpToPx(4)));
|
||||
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.privatePage.setVisibility(View.GONE);
|
||||
main.mainBinding.mainProfileImage.setImageBitmap(null);
|
||||
main.mainBinding.mainHashtagImage.setImageBitmap(null);
|
||||
main.mainBinding.mainUrl.setText(null);
|
||||
main.mainBinding.mainFullName.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.setEnabled(false);
|
||||
main.mainBinding.mainProfileImage.setEnabled(false);
|
||||
main.mainBinding.mainHashtagImage.setEnabled(false);
|
||||
main.mainBinding.mainBiography.setMentionClickListener(null);
|
||||
main.mainBinding.mainUrl.setVisibility(View.GONE);
|
||||
main.mainBinding.mainTagPostCount.setVisibility(View.GONE);
|
||||
main.mainBinding.isVerified.setVisibility(View.GONE);
|
||||
main.mainBinding.btnFollow.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);
|
||||
|
||||
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.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 {
|
||||
main.hashtagModel = null;
|
||||
main.mainBinding.tagInfoContainer.setVisibility(View.GONE);
|
||||
main.mainBinding.toolbar.toolbar.setTitle(main.userQuery);
|
||||
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 boolean isLoggedIn = !Utils.isEmpty(cookie);
|
||||
if (isLoggedIn) {
|
||||
new StoryStatusFetcher(profileId, result -> {
|
||||
new StoryStatusFetcher(profileId, "", result -> {
|
||||
main.storyModels = result;
|
||||
if (result != null && result.length > 0) main.mainBinding.mainProfileImage.setStoriesBorder();
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
@ -682,6 +755,7 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
||||
main.mainBinding.highlightsList.setVisibility(View.VISIBLE);
|
||||
main.highlightsAdapter.setData(result);
|
||||
}
|
||||
else main.mainBinding.highlightsList.setVisibility(View.GONE);
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
@ -932,7 +1019,9 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
||||
|
||||
protected Void doInBackground(Void... voids) {
|
||||
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) {
|
||||
Log.e("austin_debug", "bitmap: " + ex);
|
||||
}
|
||||
@ -941,19 +1030,29 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
||||
|
||||
@Override
|
||||
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() {
|
||||
@Override
|
||||
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");
|
||||
} else if (v == main.mainBinding.btnRestrict) {
|
||||
new ProfileAction().execute("restrict");
|
||||
} else if (v == main.mainBinding.btnBlock) {
|
||||
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) {
|
||||
action = rawAction[0];
|
||||
final String url = "https://www.instagram.com/web/"+
|
||||
(action == "restrict" ? "restrict_action" : ("friendships/"+main.profileModel.getId()))+"/"+
|
||||
(action == "follow" ?
|
||||
((action == "followtag" && main.hashtagModel != null) ? ("tags/"+
|
||||
(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() == false && main.profileModel.getRequested() == true))
|
||||
? "unfollow/" : "follow/") :
|
||||
(action == "restrict" ?
|
||||
((action == "restrict" && main.profileModel != null) ?
|
||||
(main.profileModel.getRestricted() == true ? "unrestrict/" : "restrict/") :
|
||||
(main.profileModel.getBlocked() == true ? "unblock/" : "block/")));
|
||||
final String urlParameters = "target_user_id="+main.profileModel.getId();
|
||||
(main.profileModel.getBlocked() == true ? "unblock/" : "block/")))));
|
||||
try {
|
||||
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
@ -982,6 +1082,7 @@ public final class MainHelper implements SwipeRefreshLayout.OnRefreshListener {
|
||||
urlConnection.setRequestProperty("x-csrftoken",
|
||||
Utils.settingsHelper.getString(Constants.COOKIE).split("csrftoken=")[1].split(";")[0]);
|
||||
if (action == "restrict") {
|
||||
final String urlParameters = "target_user_id="+main.profileModel.getId();
|
||||
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
urlConnection.setRequestProperty("Content-Length", "" +
|
||||
Integer.toString(urlParameters.getBytes().length));
|
||||
|
@ -133,7 +133,9 @@ public final class DirectMessagesUserInbox extends AppCompatActivity {
|
||||
directItemModel.getReelShare().getReelId(),
|
||||
directItemModel.getReelShare().getMedia().getVideoUrl(),
|
||||
directItemModel.getReelShare().getMedia().getMediaType(),
|
||||
directItemModel.getTimestamp()
|
||||
directItemModel.getTimestamp(),
|
||||
directItemModel.getReelShare().getReelOwnerName()
|
||||
|
||||
);
|
||||
sm.setVideoUrl(directItemModel.getReelShare().getMedia().getVideoUrl());
|
||||
StoryModel[] sms = {sm};
|
||||
|
@ -41,6 +41,7 @@ import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.interfaces.ItemGetter;
|
||||
import awais.instagrabber.models.DiscoverItemModel;
|
||||
import awais.instagrabber.models.FeedModel;
|
||||
import awais.instagrabber.models.HashtagModel;
|
||||
import awais.instagrabber.models.HighlightModel;
|
||||
import awais.instagrabber.models.PostModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
@ -89,6 +90,7 @@ public final class Main extends BaseLanguageActivity {
|
||||
public String userQuery = null;
|
||||
public MainHelper mainHelper;
|
||||
public ProfileModel profileModel;
|
||||
public HashtagModel hashtagModel;
|
||||
private AutoCompleteTextView searchAutoComplete;
|
||||
private ArrayAdapter<String> profileDialogAdapter;
|
||||
private DialogInterface.OnClickListener profileDialogListener;
|
||||
@ -112,6 +114,9 @@ public final class Main extends BaseLanguageActivity {
|
||||
final String uid = Utils.getUserIdFromCookie(cookie);
|
||||
Utils.setupCookies(cookie);
|
||||
|
||||
if (settingsHelper.getInteger(Constants.PROFILE_FETCH_MODE) == 2)
|
||||
settingsHelper.putInteger(Constants.PROFILE_FETCH_MODE, 1);
|
||||
|
||||
MainHelper.stopCurrentExecutor();
|
||||
mainHelper = new MainHelper(this);
|
||||
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)});
|
||||
profileDialogListener = (dialog, which) -> {
|
||||
final Intent intent;
|
||||
if (which == 0 || storyModels == null || storyModels.length < 1)
|
||||
intent = new Intent(this, ProfileViewer.class).putExtra(Constants.EXTRAS_PROFILE, profileModel);
|
||||
if (which == 0 || storyModels == null || storyModels.length < 1) {
|
||||
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)
|
||||
.putExtra(Constants.EXTRAS_STORIES, storyModels);
|
||||
.putExtra(Constants.EXTRAS_STORIES, storyModels)
|
||||
.putExtra(Constants.EXTRAS_HASHTAG, (hashtagModel != null));
|
||||
startActivity(intent);
|
||||
};
|
||||
|
||||
final View.OnClickListener onClickListener = v -> {
|
||||
if (v == mainBinding.mainBiography) {
|
||||
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) {
|
||||
profileDialogListener.onClick(null, 0);
|
||||
} else {
|
||||
@ -208,9 +217,11 @@ public final class Main extends BaseLanguageActivity {
|
||||
|
||||
mainBinding.mainBiography.setOnClickListener(onClickListener);
|
||||
mainBinding.mainProfileImage.setOnClickListener(onClickListener);
|
||||
mainBinding.mainHashtagImage.setOnClickListener(onClickListener);
|
||||
|
||||
mainBinding.mainBiography.setEnabled(false);
|
||||
mainBinding.mainProfileImage.setEnabled(false);
|
||||
mainBinding.mainHashtagImage.setEnabled(false);
|
||||
|
||||
final boolean isQueryNull = userQuery == null;
|
||||
if (isQueryNull) allItems.clear();
|
||||
|
@ -134,13 +134,13 @@ public final class PostViewer extends BaseLanguageActivity {
|
||||
final LinearLayout topPanelRoot = viewerBinding.topPanel.getRoot();
|
||||
final int iconRes;
|
||||
|
||||
if (containerLayoutParams.height == 0) {
|
||||
containerLayoutParams.height = LinearLayout.LayoutParams.MATCH_PARENT;
|
||||
if (containerLayoutParams.weight != 3.3f) {
|
||||
containerLayoutParams.weight = 3.3f;
|
||||
iconRes = R.drawable.ic_fullscreen_exit;
|
||||
topPanelRoot.setVisibility(View.GONE);
|
||||
viewerBinding.btnDownload.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
containerLayoutParams.height = 0;
|
||||
containerLayoutParams.weight = (viewerBinding.mediaList.getVisibility() == View.VISIBLE) ? 1.35f : 1.9f;
|
||||
iconRes = R.drawable.ic_fullscreen;
|
||||
topPanelRoot.setVisibility(View.VISIBLE);
|
||||
viewerBinding.btnDownload.setVisibility(View.GONE);
|
||||
@ -324,6 +324,11 @@ public final class PostViewer extends BaseLanguageActivity {
|
||||
|
||||
mediaAdapter.setData(result);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -604,7 +609,7 @@ public final class PostViewer extends BaseLanguageActivity {
|
||||
url = viewerPostModel.getDisplayUrl();
|
||||
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();
|
||||
else setupImage();
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import awais.instagrabber.asyncs.ProfilePictureFetcher;
|
||||
import awais.instagrabber.databinding.ActivityProfileBinding;
|
||||
import awais.instagrabber.dialogs.ProfileSettingsDialog;
|
||||
import awais.instagrabber.interfaces.FetchListener;
|
||||
import awais.instagrabber.models.HashtagModel;
|
||||
import awais.instagrabber.models.ProfileModel;
|
||||
import awais.instagrabber.models.enums.ProfilePictureFetchMode;
|
||||
import awais.instagrabber.utils.Constants;
|
||||
@ -41,11 +42,11 @@ import static awais.instagrabber.utils.Constants.PROFILE_FETCH_MODE;
|
||||
public final class ProfileViewer extends BaseLanguageActivity {
|
||||
private final ProfilePictureFetchMode[] fetchModes = {
|
||||
ProfilePictureFetchMode.INSTADP,
|
||||
ProfilePictureFetchMode.INSTA_STALKER,
|
||||
ProfilePictureFetchMode.INSTAFULLSIZE,
|
||||
ProfilePictureFetchMode.INSTAFULLSIZE
|
||||
};
|
||||
private ActivityProfileBinding profileBinding;
|
||||
private ProfileModel profileModel;
|
||||
private HashtagModel hashtagModel;
|
||||
private MenuItem menuItemDownload;
|
||||
private String profilePicUrl;
|
||||
private FragmentManager fragmentManager;
|
||||
@ -63,16 +64,17 @@ public final class ProfileViewer extends BaseLanguageActivity {
|
||||
setSupportActionBar(profileBinding.toolbar.toolbar);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
if (intent == null || !intent.hasExtra(Constants.EXTRAS_PROFILE)
|
||||
|| (profileModel = (ProfileModel) intent.getSerializableExtra(Constants.EXTRAS_PROFILE)) == null) {
|
||||
if (intent == null || (!intent.hasExtra(Constants.EXTRAS_PROFILE) && !intent.hasExtra(Constants.EXTRAS_HASHTAG))
|
||||
|| ((profileModel = (ProfileModel) intent.getSerializableExtra(Constants.EXTRAS_PROFILE)) == null
|
||||
&& (hashtagModel = (HashtagModel) intent.getSerializableExtra(Constants.EXTRAS_HASHTAG)) == null)) {
|
||||
Utils.errorFinish(this);
|
||||
return;
|
||||
}
|
||||
|
||||
fragmentManager = getSupportFragmentManager();
|
||||
|
||||
final String id = profileModel.getId();
|
||||
final String username = profileModel.getUsername();
|
||||
final String id = hashtagModel != null ? hashtagModel.getId() : profileModel.getId();
|
||||
final String username = hashtagModel != null ? hashtagModel.getName() : profileModel.getUsername();
|
||||
|
||||
profileBinding.toolbar.toolbar.setTitle(username);
|
||||
|
||||
@ -91,12 +93,12 @@ public final class ProfileViewer extends BaseLanguageActivity {
|
||||
|
||||
if (!fallbackToProfile && Utils.isEmpty(profilePicUrl)) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (errorHandled && fallbackToProfile || Utils.isEmpty(profilePicUrl))
|
||||
profilePicUrl = profileModel.getHdProfilePic();
|
||||
profilePicUrl = hashtagModel != null ? hashtagModel.getSdProfilePic() : profileModel.getHdProfilePic();
|
||||
|
||||
if (destroyed == true) return;
|
||||
|
||||
@ -108,10 +110,10 @@ public final class ProfileViewer extends BaseLanguageActivity {
|
||||
fallbackToProfile = true;
|
||||
if (!errorHandled) {
|
||||
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);
|
||||
} else {
|
||||
glideRequestManager.load(profileModel.getHdProfilePic()).into(profileBinding.imageViewer);
|
||||
glideRequestManager.load(profilePicUrl).into(profileBinding.imageViewer);
|
||||
showImageInfo();
|
||||
}
|
||||
profileBinding.progressView.setVisibility(View.GONE);
|
||||
@ -163,7 +165,8 @@ public final class ProfileViewer extends BaseLanguageActivity {
|
||||
}).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() {
|
||||
|
@ -368,6 +368,13 @@ public final class StoryViewer extends BaseLanguageActivity {
|
||||
storyViewerBinding.viewStoryPost.setTag(shortCode);
|
||||
|
||||
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();
|
||||
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;
|
||||
if (isHashTag)
|
||||
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
|
||||
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> {
|
||||
private final FetchListener<String> fetchListener;
|
||||
private final String userName, userId;
|
||||
private final ProfilePictureFetchMode fetchMode;
|
||||
private final String userName, userId, picUrl;
|
||||
private final boolean isHashtag;
|
||||
private ProfilePictureFetchMode fetchMode;
|
||||
|
||||
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.fetchMode = fetchMode;
|
||||
this.userName = userName;
|
||||
this.userId = userId;
|
||||
this.picUrl = picUrl;
|
||||
this.isHashtag = isHashtag;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(final Void... voids) {
|
||||
String out = null;
|
||||
try {
|
||||
String out = picUrl;
|
||||
if (!isHashtag) try {
|
||||
if (fetchMode == ProfilePictureFetchMode.INSTA_STALKER) fetchMode = ProfilePictureFetchMode.INSTADP;
|
||||
final String url;
|
||||
|
||||
if (fetchMode == ProfilePictureFetchMode.INSTADP)
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
} 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) {
|
||||
|
@ -20,11 +20,12 @@ import awaisomereport.LogCollector;
|
||||
import static awais.instagrabber.utils.Utils.logCollector;
|
||||
|
||||
public final class StoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[]> {
|
||||
private final String id;
|
||||
private final String id, hashtag;
|
||||
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.hashtag = hashtag;
|
||||
this.fetchListener = fetchListener;
|
||||
}
|
||||
|
||||
@ -32,7 +33,8 @@ public final class StoryStatusFetcher extends AsyncTask<Void, Void, StoryModel[]
|
||||
protected StoryModel[] doInBackground(final Void... voids) {
|
||||
StoryModel[] result = null;
|
||||
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 {
|
||||
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),
|
||||
data.getString("display_url"),
|
||||
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");
|
||||
if (isVideo && videoResources != null)
|
||||
|
@ -28,7 +28,7 @@ public class GridAutofitLayoutManager extends GridLayoutManager {
|
||||
final int totalSpace = getOrientation() == VERTICAL ? width - getPaddingRight() - getPaddingLeft()
|
||||
: height - getPaddingTop() - getPaddingBottom();
|
||||
|
||||
setSpanCount(Math.max(1, totalSpace / mColumnWidth));
|
||||
setSpanCount(Math.max(1, Math.min(totalSpace / mColumnWidth, 3)));
|
||||
|
||||
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;
|
||||
|
||||
public final class StoryModel implements Serializable {
|
||||
private final String storyMediaId, storyUrl;
|
||||
private final String storyMediaId, storyUrl, username;
|
||||
private final MediaItemType itemType;
|
||||
private final long timestamp;
|
||||
private String videoUrl, tappableShortCode;
|
||||
private int position;
|
||||
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.storyUrl = storyUrl;
|
||||
this.itemType = itemType;
|
||||
this.timestamp = timestamp;
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getStoryUrl() {
|
||||
@ -66,4 +67,8 @@ public final class StoryModel implements Serializable {
|
||||
public boolean isCurrentSlide() {
|
||||
return isCurrentSlide;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
}
|
@ -2,6 +2,6 @@ package awais.instagrabber.models.enums;
|
||||
|
||||
public enum ProfilePictureFetchMode {
|
||||
INSTADP,
|
||||
INSTA_STALKER,
|
||||
INSTAFULLSIZE,
|
||||
INSTA_STALKER,
|
||||
}
|
@ -25,6 +25,7 @@ public final class Constants {
|
||||
public static final String SHOW_QUICK_ACCESS_DIALOG = "show_quick_dlg";
|
||||
//////////////////////// EXTRAS ////////////////////////
|
||||
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_ID = "id";
|
||||
public static final String EXTRAS_POST = "post";
|
||||
|
@ -46,7 +46,7 @@ public final class DataBox extends SQLiteOpenHelper {
|
||||
@Override
|
||||
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) {
|
||||
final String query = favoriteModel.getQuery();
|
||||
if (!Utils.isEmpty(query)) {
|
||||
@ -114,6 +114,20 @@ public final class DataBox extends SQLiteOpenHelper {
|
||||
|
||||
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 /////////////////////////////////////
|
||||
|
@ -17,6 +17,7 @@ import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import awais.instagrabber.BuildConfig;
|
||||
import awais.instagrabber.R;
|
||||
@ -26,15 +27,29 @@ import static awais.instagrabber.utils.Utils.settingsHelper;
|
||||
|
||||
public final class FlavorTown {
|
||||
public static void updateCheck(@NonNull final Context context) {
|
||||
new UpdateChecker(versionUrl -> {
|
||||
new AlertDialog.Builder(context).setTitle(R.string.update_available).setNegativeButton(R.string.cancel, null)
|
||||
.setPositiveButton(R.string.action_download, (dialog, which) -> {
|
||||
Resources res = context.getResources();
|
||||
new UpdateChecker(version -> {
|
||||
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 {
|
||||
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) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ import awais.instagrabber.interfaces.FetchListener;
|
||||
|
||||
public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
|
||||
private final FetchListener<String> fetchListener;
|
||||
private String versionUrl;
|
||||
private String version;
|
||||
|
||||
public UpdateChecker(final FetchListener<String> fetchListener) {
|
||||
this.fetchListener = fetchListener;
|
||||
@ -22,17 +22,17 @@ public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
|
||||
@NonNull
|
||||
@Override
|
||||
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 int index = versionName.indexOf('.');
|
||||
|
||||
try {
|
||||
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
|
||||
HttpURLConnection conn = (HttpURLConnection) new URL(versionUrl).openConnection();
|
||||
HttpURLConnection conn = (HttpURLConnection) new URL(UPDATE_BASE_URL + version).openConnection();
|
||||
conn.setUseCaches(false);
|
||||
conn.setRequestMethod("HEAD");
|
||||
conn.connect();
|
||||
@ -46,10 +46,10 @@ public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
|
||||
final int verMinor = Integer.parseInt(substring) + 1;
|
||||
|
||||
for (int i = verMinor; i < 10; ++i) {
|
||||
versionUrl = UPDATE_BASE_URL + verMajor + '.' + i;
|
||||
version = "v" + verMajor + '.' + i;
|
||||
conn.disconnect();
|
||||
|
||||
conn = (HttpURLConnection) new URL(versionUrl).openConnection();
|
||||
conn = (HttpURLConnection) new URL(UPDATE_BASE_URL + version).openConnection();
|
||||
conn.setUseCaches(false);
|
||||
conn.setRequestMethod("HEAD");
|
||||
conn.connect();
|
||||
@ -70,6 +70,6 @@ public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
|
||||
@Override
|
||||
protected void onPostExecute(final Boolean result) {
|
||||
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"),
|
||||
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"))
|
||||
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_POST_FETCHER("async-single-post-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_PICTURE_FETCHER("async-pfp-fetcher.txt"),
|
||||
ASYNC_STORY_STATUS_FETCHER("async-story-status-fetcher.txt"),
|
||||
|
@ -227,6 +227,63 @@
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</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>
|
||||
|
||||
<FrameLayout
|
||||
|
@ -4,6 +4,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:weightSum="3.2"
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical"
|
||||
tools:context=".activities.PostViewer">
|
||||
@ -27,7 +28,7 @@
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.6">
|
||||
android:layout_weight="1.9">
|
||||
|
||||
<com.google.android.exoplayer2.ui.PlayerView
|
||||
android:id="@+id/playerView"
|
||||
@ -81,7 +82,7 @@
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/mediaList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="5dp"
|
||||
@ -95,12 +96,12 @@
|
||||
layout="@layout/item_feed_bottom"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.4" />
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="0.26"
|
||||
android:layout_weight="0.3"
|
||||
android:background="#0000"
|
||||
android:weightSum="2"
|
||||
android:layout_alignParentBottom="true">
|
||||
@ -119,6 +120,7 @@
|
||||
|
||||
<androidx.appcompat.widget.AppCompatButton
|
||||
android:id="@+id/btnBookmark"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8dp"
|
||||
|
@ -25,7 +25,6 @@
|
||||
</string-array>
|
||||
<string-array name="profile_fetch_modes">
|
||||
<item>Instadp</item>
|
||||
<item>Insta-Stalker</item>
|
||||
<item>Instafullsize</item>
|
||||
</string-array>
|
||||
<string-array name="date_presets">
|
||||
|
@ -26,7 +26,6 @@
|
||||
<string name="title_favorites">Favoritos</string>
|
||||
<string name="title_discover">Explorar</string>
|
||||
<string name="title_comments">Comentarios</string>
|
||||
<string name="title_hashtag_prefix">Hashtag: </string>
|
||||
<string name="title_highlight">Resaltado: %s</string>
|
||||
<string name="title_user_story">Historia de usuario</string>
|
||||
<string name="title_changelog">Lista de cambios</string>
|
||||
|
@ -25,7 +25,6 @@
|
||||
</string-array>
|
||||
<string-array name="profile_fetch_modes">
|
||||
<item>Instadp</item>
|
||||
<item>Insta-Stalker</item>
|
||||
<item>Instafullsize</item>
|
||||
</string-array>
|
||||
<string-array name="date_presets">
|
||||
|
@ -26,7 +26,6 @@
|
||||
<string name="title_favorites">Favoris</string>
|
||||
<string name="title_discover">Découvrir</string>
|
||||
<string name="title_comments">Commentaires</string>
|
||||
<string name="title_hashtag_prefix">Hashtag: </string>
|
||||
<string name="title_highlight">Highlight: %s</string>
|
||||
<string name="title_user_story">Stories de l\'utilisateur</string>
|
||||
<string name="title_changelog">Journal des changements</string>
|
||||
|
@ -25,7 +25,6 @@
|
||||
</string-array>
|
||||
<string-array name="profile_fetch_modes">
|
||||
<item>Instadp</item>
|
||||
<item>Insta-Stalker</item>
|
||||
<item>Instafullsize</item>
|
||||
</string-array>
|
||||
<string-array name="date_presets">
|
||||
|
@ -26,7 +26,6 @@
|
||||
<string name="title_favorites">Favorit</string>
|
||||
<string name="title_discover">Temukan</string>
|
||||
<string name="title_comments">Komentar</string>
|
||||
<string name="title_hashtag_prefix">Hashtag: </string>
|
||||
<string name="title_highlight">Sorotan: %s</string>
|
||||
<string name="title_user_story">Story</string>
|
||||
<string name="title_changelog">Catatan Perubahan</string>
|
||||
|
@ -25,7 +25,6 @@
|
||||
</string-array>
|
||||
<string-array name="profile_fetch_modes">
|
||||
<item>Instadp</item>
|
||||
<item>Insta-Stalker</item>
|
||||
<item>Instafullsize</item>
|
||||
</string-array>
|
||||
<string-array name="date_presets">
|
||||
|
@ -26,7 +26,6 @@
|
||||
<string name="title_favorites">Favoriti</string>
|
||||
<string name="title_discover">Scopri</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_user_story">Storia Utente</string>
|
||||
<string name="title_changelog">Changelog</string>
|
||||
|
@ -25,7 +25,6 @@
|
||||
</string-array>
|
||||
<string-array name="profile_fetch_modes">
|
||||
<item>Instadp</item>
|
||||
<item>Insta-Stalker</item>
|
||||
<item>Instafullsize</item>
|
||||
</string-array>
|
||||
<string-array name="date_presets">
|
||||
|
@ -26,7 +26,6 @@
|
||||
<string name="title_favorites">最爱</string>
|
||||
<string name="title_discover">发现</string>
|
||||
<string name="title_comments">留言</string>
|
||||
<string name="title_hashtag_prefix">标签: </string>
|
||||
<string name="title_highlight">精彩:%s</string>
|
||||
<string name="title_user_story">用户快拍</string>
|
||||
<string name="title_changelog">日志</string>
|
||||
@ -106,7 +105,7 @@
|
||||
<string name="quick_access_confirm_delete">你真的要删除 %s?</string>
|
||||
<string name="profile_viewer_imageinfo">宽: %d\n高: %d</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="view_pfp">查看头像</string>
|
||||
<string name="direct_messages_you">你</string>
|
||||
|
@ -28,7 +28,6 @@
|
||||
|
||||
<string-array name="profile_fetch_modes">
|
||||
<item>Instadp</item>
|
||||
<item>Insta-Stalker</item>
|
||||
<item>Instafullsize</item>
|
||||
</string-array>
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
<string name="action_setting">Settings (v%s)</string>
|
||||
<string name="action_settings">Settings</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_compare">Compare</string>
|
||||
|
||||
@ -31,7 +33,6 @@
|
||||
<string name="title_favorites">Favorites</string>
|
||||
<string name="title_discover">Discover</string>
|
||||
<string name="title_comments">Comments</string>
|
||||
<string name="title_hashtag_prefix">Hashtag: </string>
|
||||
<string name="title_highlight">Highlight: %s</string>
|
||||
<string name="title_user_story">User Story</string>
|
||||
<string name="title_changelog">Changelog</string>
|
||||
@ -88,6 +89,10 @@
|
||||
|
||||
<string name="follow">Follow</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="unblock">Unblock</string>
|
||||
<string name="restrict">Restrict</string>
|
||||
@ -124,7 +129,7 @@
|
||||
|
||||
<string name="profile_viewer_imageinfo">Width: %d\nHeight: %d</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="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="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="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>
|
||||
|
@ -1,5 +1,3 @@
|
||||
v16.7 build 32:
|
||||
|
||||
* You can now (un)follow/restrict/block people
|
||||
* 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)
|
||||
|
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,6 +3,7 @@ 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\*!
|
||||
* Like/bookmark posts\*!
|
||||
* 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.
|
||||
* **Compare** follower/following list!
|
||||
* Searching usernames and hashtags.
|
||||
@ -10,3 +11,5 @@ InstaGrabber is an app that allows...
|
||||
<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.
|
||||
|
||||
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