diff --git a/.all-contributorsrc b/.all-contributorsrc
new file mode 100644
index 00000000..26f28f43
--- /dev/null
+++ b/.all-contributorsrc
@@ -0,0 +1,148 @@
+{
+ "files": [
+ "README.md"
+ ],
+ "imageSize": 100,
+ "commit": false,
+ "contributors": [
+ {
+ "login": "austinhuang0131",
+ "name": "Austin Huang",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/16656689",
+ "profile": "https://austinhuang.me",
+ "contributions": [
+ "code",
+ "doc",
+ "question",
+ "translation",
+ "ideas"
+ ]
+ },
+ {
+ "login": "ammargitham",
+ "name": "Ammar Githam",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/8017365",
+ "profile": "https://github.com/ammargitham",
+ "contributions": [
+ "code",
+ "design",
+ "ideas",
+ "maintenance",
+ "question"
+ ]
+ },
+ {
+ "login": "AwaisKing",
+ "name": "AWAiS",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/5278488",
+ "profile": "http://rerolledgeek.blogspot.com/",
+ "contributions": [
+ "code",
+ "ideas"
+ ]
+ },
+ {
+ "login": "Shadowspear123",
+ "name": "Shadowspear123",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/50462281",
+ "profile": "https://github.com/Shadowspear123",
+ "contributions": [
+ "blog",
+ "bug",
+ "ideas",
+ "question",
+ "userTesting"
+ ]
+ },
+ {
+ "login": "KevinNThomas",
+ "name": "Kevin Thomas",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/15370181",
+ "profile": "http://kevinthomas.dev",
+ "contributions": [
+ "financial"
+ ]
+ },
+ {
+ "login": "e-edgren",
+ "name": "Airikr",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/53869451",
+ "profile": "https://airikr.me/",
+ "contributions": [
+ "question",
+ "ideas"
+ ]
+ },
+ {
+ "login": "Galang23",
+ "name": "Galang23",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/13700948",
+ "profile": "https://github.com/Galang23",
+ "contributions": [
+ "question",
+ "translation"
+ ]
+ },
+ {
+ "login": "kernoeb",
+ "name": "kernoeb",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/24623168",
+ "profile": "https://becauseofprog.fr/",
+ "contributions": [
+ "translation"
+ ]
+ },
+ {
+ "login": "Lego8486",
+ "name": "Ten_Lego",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/47414485",
+ "profile": "https://github.com/Lego8486",
+ "contributions": [
+ "translation"
+ ]
+ },
+ {
+ "login": "MoaufmKlo",
+ "name": "MoaufmKlo",
+ "avatar_url": "https://avatars1.githubusercontent.com/u/45636897",
+ "profile": "https://github.com/MoaufmKlo",
+ "contributions": [
+ "translation"
+ ]
+ },
+ {
+ "login": "peterge1998",
+ "name": "peterge1998",
+ "avatar_url": "https://avatars2.githubusercontent.com/u/47355238",
+ "profile": "https://github.com/peterge1998",
+ "contributions": [
+ "translation"
+ ]
+ },
+ {
+ "login": "RAMAR-RAR",
+ "name": "RAMAR-RAR",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/47423745",
+ "profile": "https://github.com/RAMAR-RAR",
+ "contributions": [
+ "translation"
+ ]
+ },
+ {
+ "login": "wagnim",
+ "name": "wagnim",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/30241419",
+ "profile": "https://github.com/wagnim",
+ "contributions": [
+ "translation"
+ ]
+ }
+ ],
+ "contributorsPerLine": 6,
+ "projectName": "instagrabber",
+ "projectOwner": "austinhuang0131",
+ "repoType": "github",
+ "repoHost": "https://github.com",
+ "skipCi": true,
+ "commitConvention": "none"
+}
diff --git a/.bettercodehub.yml b/.bettercodehub.yml
deleted file mode 100644
index 745eb11f..00000000
--- a/.bettercodehub.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-component_depth: 7
-languages:
-- java
diff --git a/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md
similarity index 100%
rename from CODE_OF_CONDUCT.md
rename to .github/CODE_OF_CONDUCT.md
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 00000000..b126cbed
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,73 @@
+## WARNING
+
+* All forks must respect [GPLv3](https://www.gnu.org/licenses/gpl-3.0.html). Please report violations in Issues or [confidentially](https://austinhuang.me/#hey-you-look-cool).
+* Although publishing a fork is allowed by license, it is strongly discouraged to do so as it divides the effort and creates confusion. It is, therefore, recommended to send a pull request back to us, so that the larger community can enjoy your improvement. (This does not apply if you're adapting this app for a different platform other than Instagram.)
+
+## Contributing
+
+Thank you for your interest in InstaGrabber!
+
+Our vision of InstaGrabber is an open source true alternative of the official Instagram app. It is Austin's pursuit of a libre life that lead him to this app during its abandonment, and it was one unresolved bug that made him have the enthusiasm in implementing numerous features for this app, despite having 0 knowledge of Java beforehand.
+
+As we grow in popularity, it becomes apparent that we are short on hands. Every contribution counts!
+
+## I want to help coding it!
+
+Great!
+
+Generally, we want to imitate features in the actual Instagram app. There are many Instagram private API repositories on GitHub for you to refer to. Note that you should minimize POST: If a job should be done with GET, then there has to be a GET endpoint. (Indeed, sometimes you need multiple repositories for reference.)
+
+As long as you have tested your version (please indicate device and API version) and make sure it works, then you can submit a PR! Large UI changes have to be voted on by the community, so it would be helpful to upload some screenshots.
+
+Check errors are for reference only. Try to minimize them, but usually they don't make a big difference.
+
+**NEVER touch the l10n-master branch.** It's automatically managed by Crowdin.
+
+### Structure
+
+It is preferred that you read the scripts yourself, as my understanding (and presentation) may be basic.
+
+* `awais.instagrabber`
+ * `activities`: Scripts directly binding to each view. Assigns `adapters`.
+ * `adapters`: Scripts used to present a list of `models` from `asyncs` into `activities`.
+ * Those inside `viewholder` are for frontend, while others are for backend.
+ * `asyncs`: Scripts used to communicate with Instagram. Returns `models` which is sent to `adapters`.
+ * `asyncs.i`: Scripts that fetch data from `i.instagram.com`, except DM.
+ * `asyncs.direct_messages`: As the name suggests, communication scripts used for DM.
+ * `customviews`: Custom frontend components for this app.
+ * `dialogs`: Scripts directly binding to dialogs (i.e. those that are nested in the main view).
+ * `fragments.directmessages`: Scripts directly binding to each fragment ("small views") within `DirectMessageActivity` in `activities`.
+ * `interfaces`: Custom backend components for this app.
+ * `models`: Data structure for Instagram API responses from `asyncs`.
+ * `utils`: Various tools.
+ * `MainHelper.java` is basically an extension of `activities.main`.
+* `awaisomereport`: Crash reporter. Shouldn not require too much maintenance.
+* `thoughtbot.expandableadapter`: These are for the follower comparison view, which allows grouping users.
+
+### I can't code Java, but I want to!
+
+Fun fact: Austin took over this project and learned Java on the fly (I'm not joking, I only do JavaScript before taking this over).
+
+Even though Java is quite annoying, it is still possible to learn it by trying to understand what these code do (Easier if you have coding experience in other languages).
+
+If you have questions, don't be afraid to ask for help from any current maintainer!
+
+## I found a bug!
+
+**Please read [FAQ](https://instagrabber.austinhuang.me/faq) first.**
+
+Bugs are inevitable during active development, as nobody can cover all the possible test cases.
+
+You can either email your crash dump to `instagrabber@austinhuang.me` (The crash reporter will fill in this address for you) or create a GitHub issue. If you're on GitHub, please follow the template. If you're reporting by email, your email address will be published in the GitHub issue. You can contact me [privately](https://austinhuang.me/#hey-you-look-cool) or [through support channels](https://instagrabber.austinhuang.me/#what-can-i-do) to remove it.
+
+Generally, reporting bugs directly in support channels is not recommended, as they can be difficult to find.
+
+### I want to help... in some other way.
+
+You can...
+
+* translate it [![badge](https://badges.crowdin.net/instagrabber/localized.svg)](https://crowdin.com/project/instagrabber)
+* promote it (reddit [r/AndroidApps](https://www.reddit.com/r/androidapps/comments/i30tpp/instagrabber_an_open_source_instagram_client/), YouTube [HowToMen](https://www.youtube.com/watch?v=1Um2ZJG_mB4), [EkΕi SΓΆzlΓΌk](https://eksisozluk.com/instagrabber--6643143))
+* star it [![stars](https://img.shields.io/github/stars/austinhuang0131/instagrabber.svg?style=social&label=Star)](https://github.com/austinhuang0131/instagrabber/stargazers)
+
+Happy contributing!
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index b95b7b18..2c933b53 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -4,31 +4,27 @@ about: App crashing? You seeing a confusing error message? Report them here!
title: "[BUG]"
labels: bug
assignees: ''
-
---
+
+
- [ ] My app is on the latest version. I understand that any other version is not supported.
+- [ ] I have read [the FAQ](https://instagrabber.austinhuang.me/faq).
## Steps
-### Expected Behaviour
-
-## Screenshots
-
-
-
## Environment
- Device:
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index f0048e94..ce2afe9c 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -8,9 +8,9 @@ assignees: ''
---
**Is your feature request related to a problem? Please describe.**
@@ -19,8 +19,5 @@ A clear and concise description of what the problem is. Ex. I'm always frustrate
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
**Additional context**
Add any other context or screenshots about the feature request here.
diff --git a/README.md b/README.md
index feea5061..5e154de9 100755
--- a/README.md
+++ b/README.md
@@ -8,37 +8,20 @@
[![GPLv3 license](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE)
[![GitHub stars](https://img.shields.io/github/stars/austinhuang0131/instagrabber.svg?style=social&label=Star)](https://GitHub.com/austinhuang0131/instagrabber/stargazers/)
-*As featured on [HowToMen](https://youtu.be/1Um2ZJG_mB4) and [GitHub Trending](https://github.com/ifyour/github-trending-archive/blob/master/archives/2020-08-05.md)*
+For documentation, visit [InstaGrabber.AustinHuang.me](https://instagrabber.austinhuang.me).
### Download
-
+**By installing, you indicate your acceptance of [Disclosure and Privacy Policy](https://instagrabber.austinhuang.me/disclosure).**
-Or you can download from [GitHub releases](https://github.com/austinhuang0131/instagrabber/releases/latest). Expand "Assets" and download the APK file.
+Download from [GitHub releases](https://github.com/austinhuang0131/instagrabber/releases/latest) (recommended). Expand "Assets" and download the APK file. Or...
+
+
+
+(...[but they're slow.](https://instagrabber.austinhuang.me/faq#f-droid))
Version status: ![F-Droid](https://img.shields.io/f-droid/v/me.austinhuang.instagrabber.svg) vs. ![GitHub](https://img.shields.io/github/release/austinhuang0131/instagrabber.svg?logo=github)
-### Presentation
-
-InstaGrabber is an alternative Instagram client for Android. You can...
-
-* **Search**: Profile / Hashtag / Location
-* **Profile**: View posts (timeline & face-tagged), copy bio, view stories\* (Highlight & status), follow\*, restrict\*, block\*, compare following/followers\*,3
-* **Hashtag**: View posts (newest only), view stories\*, follow\*
-* **Location**: View posts (newest only), view stories\*, open map
-* **Post**: View, download (+ batch download selected posts), copy captions, like/save\*
-* **Story**: View (with [storiesig](https://storiesig.com) support1 and incognito mode2), download, interact with stickers\*, reply as DM\*
-* **Comment**: View (+ copy), write\*, reply\*, like\*, delete\*
-* **DM\***: View, download attachments, text reply
-* Viewing\* your own feed, discover, saved, and liked posts
-* Adding personal bookmarks to accounts/hashtags/locations locally
-
-We support private accounts!\*
-
-It can be used as a drop-in replacement for read (and some write) functionalities of the official Instagram app, with unnecessary components stripped.
-
-* Requires [login](#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)!
-
@@ -54,6 +37,43 @@ It can be used as a drop-in replacement for read (and some write) functionalitie
* Telegram: [@Grabber_App](https://t.me/grabber_app)
* Discord: [https://discord.gg/YtEDzN2](https://discord.gg/YtEDzN2)
+### Contributors
+
+
+[![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors-)
+
+
+Prominent contributors are listed here in the [all-contributors](https://allcontributors.org/) specifications. See [emoji key](https://allcontributors.org/docs/en/emoji-key).
+
+
+
+
+
+
+
+
+
+
### License
This app is originally made by [@AwaisKing](https://github.com/AwaisKing) on [GitLab](https://gitlab.com/AwaisKing/instagrabber).
@@ -79,9 +99,8 @@ This app is originally made by [@AwaisKing](https://github.com/AwaisKing) on [Gi
[![Snyk Vulnerabilities](https://img.shields.io/snyk/vulnerabilities/github/austinhuang0131/instagrabber)](https://snyk.io/test/github/austinhuang0131/instagrabber)
[![LGTM Alerts](https://img.shields.io/lgtm/alerts/github/austinhuang0131/instagrabber)](https://lgtm.com/projects/g/austinhuang0131/instagrabber)
[![LGTM Grade](https://img.shields.io/lgtm/grade/java/github/austinhuang0131/instagrabber)](https://lgtm.com/projects/g/austinhuang0131/instagrabber)
-[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f87cac1fbf674888b00bd91bc5eccce0)](https://app.codacy.com/manual/austinhuang0131/instagrabber)
+[![CodeFactor](https://www.codefactor.io/repository/github/austinhuang0131/instagrabber/badge)](https://www.codefactor.io/repository/github/austinhuang0131/instagrabber)
+[![Codacy Badge](https://app.codacy.com/project/badge/Grade/e9cfcb7733f8477d92e5c0f30cac137a)](https://www.codacy.com/manual/austinhuang0131/instagrabber)
[![Crowdin](https://badges.crowdin.net/instagrabber/localized.svg)](https://crowdin.com/project/instagrabber)
[![forthebadge](https://forthebadge.com/images/badges/made-with-java.svg)](https://forthebadge.com)[![forthebadge](https://forthebadge.com/images/badges/built-for-android.svg)](https://forthebadge.com) [![gplv3](https://www.gnu.org/graphics/gplv3-with-text-136x68.png)](https://www.gnu.org/licenses/gpl-3.0.html)
-
-1. For anonymous users only, does not apply to users already logged in, and must be explicitly enabled in Settings. 2. Default enabled, but can be disabled. 3. Shameless plug: If you do not have an Android device but wants to do that, read [this](https://austinhuang.me/instagram-compare).
diff --git a/app/src/main/java/awais/instagrabber/activities/CommentsViewer.java b/app/src/main/java/awais/instagrabber/activities/CommentsViewer.java
index 0a98cc01..73352b6b 100755
--- a/app/src/main/java/awais/instagrabber/activities/CommentsViewer.java
+++ b/app/src/main/java/awais/instagrabber/activities/CommentsViewer.java
@@ -119,21 +119,25 @@ public final class CommentsViewer extends BaseLanguageActivity implements SwipeR
} else if (which == 3) {
Utils.copyText(this, commentModel.getText().toString());
} else if (which == 4) {
- focus = commentsBinding.rvComments.findViewWithTag(commentModel);
- focus.setBackgroundColor(0x80888888);
- commentsBinding.commentCancelParent.setVisibility(View.VISIBLE);
- String mention = "@"+profileModel.getUsername()+" ";
- commentsBinding.commentText.setText(mention);
- commentsBinding.commentText.requestFocus();
- commentsBinding.commentText.setSelection(mention.length());
- commentsBinding.commentText.postDelayed(new Runnable(){
- @Override
- public void run(){
- imm = (InputMethodManager) getSystemService(getApplicationContext().INPUT_METHOD_SERVICE);
- imm.showSoftInput(commentsBinding.commentText, 0);
- }
+ if (commentModel == null) {
+ Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
+ }
+ else {
+ focus = commentsBinding.rvComments.findViewWithTag(commentModel);
+ focus.setBackgroundColor(0x80888888);
+ commentsBinding.commentCancelParent.setVisibility(View.VISIBLE);
+ String mention = "@" + profileModel.getUsername() + " ";
+ commentsBinding.commentText.setText(mention);
+ commentsBinding.commentText.requestFocus();
+ commentsBinding.commentText.setSelection(mention.length());
+ commentsBinding.commentText.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ imm = (InputMethodManager) getSystemService(getApplicationContext().INPUT_METHOD_SERVICE);
+ imm.showSoftInput(commentsBinding.commentText, 0);
+ }
+ }, 200);
}
- ,200);
} else if (which == 5) {
new CommentAction().execute((commentModel.getLiked() ? "unlike/" : "like/")+commentModel.getId());
} else if (which == 6) {
diff --git a/app/src/main/java/awais/instagrabber/activities/PostViewer.java b/app/src/main/java/awais/instagrabber/activities/PostViewer.java
index 2a7297b3..6412e7d8 100755
--- a/app/src/main/java/awais/instagrabber/activities/PostViewer.java
+++ b/app/src/main/java/awais/instagrabber/activities/PostViewer.java
@@ -222,11 +222,9 @@ public final class PostViewer extends BaseLanguageActivity {
viewerBinding.bottomPanel.commentsCount.setText(String.valueOf(commentsCount));
viewerBinding.bottomPanel.btnComments.setVisibility(View.VISIBLE);
- postShortCode = result[0].getShortCode();
-
viewerBinding.bottomPanel.btnComments.setOnClickListener(v ->
startActivityForResult(new Intent(this, CommentsViewer.class)
- .putExtra(Constants.EXTRAS_SHORTCODE, postShortCode)
+ .putExtra(Constants.EXTRAS_SHORTCODE, postModel.getShortCode())
.putExtra(Constants.EXTRAS_POST, viewerPostModel.getPostId())
.putExtra(Constants.EXTRAS_USER, postUserId), 6969));
viewerBinding.bottomPanel.btnComments.setClickable(true);
@@ -243,7 +241,8 @@ public final class PostViewer extends BaseLanguageActivity {
}
}
- setupPostInfoBar("@" + viewerPostModel.getUsername(), viewerPostModel.getItemType(), viewerPostModel.getLocation());
+ setupPostInfoBar("@" + viewerPostModel.getUsername(), viewerPostModel.getItemType(),
+ viewerPostModel.getLocationName(), viewerPostModel.getLocation());
postCaption = postModel.getPostCaption();
viewerCaptionParent.setVisibility(View.VISIBLE);
@@ -302,7 +301,7 @@ public final class PostViewer extends BaseLanguageActivity {
final boolean postIdNull = postModel.getPostId() == null;
if (!postIdNull)
- setupPostInfoBar(intent.getStringExtra(Constants.EXTRAS_USER), postModel.getItemType(), null);
+ setupPostInfoBar(intent.getStringExtra(Constants.EXTRAS_USER), postModel.getItemType(), null, null);
isFromShare = postModel.getPosition() == -1 || postIdNull;
@@ -583,9 +582,9 @@ public final class PostViewer extends BaseLanguageActivity {
viewerBinding.bottomPanel.viewerCaption.setMentionClickListener(null);
viewerBinding.bottomPanel.viewerCaption.setText(postCaption);
}
-
+
setupPostInfoBar("@" + viewerPostModel.getUsername(), viewerPostModel.getItemType(),
- viewerPostModel.getLocation());
+ viewerPostModel.getLocationName(), viewerPostModel.getLocation());
if (postModel instanceof PostModel) {
final PostModel postModel = (PostModel) this.postModel;
@@ -633,7 +632,7 @@ public final class PostViewer extends BaseLanguageActivity {
}
}
- private void setupPostInfoBar(final String from, final MediaItemType mediaItemType, final JSONObject location) {
+ private void setupPostInfoBar(final String from, final MediaItemType mediaItemType, final String locationName, final String location) {
if (prevUsername == null || !prevUsername.equals(from)) {
// viewerBinding.topPanel.ivProfilePic.setImageBitmap(null);
// viewerBinding.topPanel.ivProfilePic.setImageDrawable(null);
@@ -708,8 +707,8 @@ public final class PostViewer extends BaseLanguageActivity {
));
} else {
viewerBinding.topPanel.location.setVisibility(View.VISIBLE);
- viewerBinding.topPanel.location.setText(location.optString("name"));
- viewerBinding.topPanel.location.setOnClickListener(v -> searchUsername(location.optString("id") + "/" + location.optString("slug")));
+ viewerBinding.topPanel.location.setText(locationName);
+ viewerBinding.topPanel.location.setOnClickListener(v -> searchUsername(location));
viewerBinding.topPanel.title.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT
));
diff --git a/app/src/main/java/awais/instagrabber/adapters/DirectMessageItemsAdapter.java b/app/src/main/java/awais/instagrabber/adapters/DirectMessageItemsAdapter.java
index 8070aaf9..547f3cce 100644
--- a/app/src/main/java/awais/instagrabber/adapters/DirectMessageItemsAdapter.java
+++ b/app/src/main/java/awais/instagrabber/adapters/DirectMessageItemsAdapter.java
@@ -106,7 +106,8 @@ public final class DirectMessageItemsAdapter extends ListAdapter
String endCursor = "";
while (endCursor != null) {
- final String url = "https://www.instagram.com/graphql/query/?query_hash=97b41c52301f77ce508f55e66d17620e&variables=" +
+ final String url = "https://www.instagram.com/graphql/query/?query_hash=bc3296d1ce80a24b1b6e40b1e72903f5&variables=" +
"{\"shortcode\":\"" + shortCode + "\",\"first\":50,\"after\":\"" + endCursor + "\"}";
try {
diff --git a/app/src/main/java/awais/instagrabber/asyncs/FeedFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/FeedFetcher.java
index 2f6af28d..8fea1d51 100755
--- a/app/src/main/java/awais/instagrabber/asyncs/FeedFetcher.java
+++ b/app/src/main/java/awais/instagrabber/asyncs/FeedFetcher.java
@@ -164,7 +164,10 @@ public final class FeedFetcher extends AsyncTask {
null, null, null,
node.optLong("video_view_count", -1), -1, false, false,
feedItem.getJSONObject("edge_media_preview_like").getLong("count"),
- feedItem.optJSONObject("location"));
+ feedItem.isNull("location") ? null : feedItem.getJSONObject("location").optString("name"),
+ feedItem.isNull("location") ? null :
+ (feedItem.getJSONObject("location").optString("id") + "/" +
+ feedItem.getJSONObject("location").optString("slug")));
sliderItems[j].setSliderDisplayUrl(node.getString("display_url"));
}
diff --git a/app/src/main/java/awais/instagrabber/asyncs/PostFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/PostFetcher.java
index 528f2a76..38a6e0b0 100755
--- a/app/src/main/java/awais/instagrabber/asyncs/PostFetcher.java
+++ b/app/src/main/java/awais/instagrabber/asyncs/PostFetcher.java
@@ -95,7 +95,10 @@ public final class PostFetcher extends AsyncTask
isVideo && media.has("video_view_count") ? media.getLong("video_view_count") : -1,
timestamp, media.getBoolean("viewer_has_liked"), media.getBoolean("viewer_has_saved"),
media.getJSONObject("edge_media_preview_like").getLong("count"),
- media.optJSONObject("location"));
+ media.isNull("location") ? null : media.getJSONObject("location").optString("name"),
+ media.isNull("location") ? null :
+ (media.getJSONObject("location").optString("id") + "/" +
+ media.getJSONObject("location").optString("slug")));
postModel.setCommentsCount(commentsCount);
@@ -120,7 +123,10 @@ public final class PostFetcher extends AsyncTask
isChildVideo && node.has("video_view_count") ? node.getLong("video_view_count") : -1,
timestamp, media.getBoolean("viewer_has_liked"), media.getBoolean("viewer_has_saved"),
media.getJSONObject("edge_media_preview_like").getLong("count"),
- media.optJSONObject("location"));
+ media.isNull("location") ? null : media.getJSONObject("location").optString("name"),
+ media.isNull("location") ? null :
+ (media.getJSONObject("location").optString("id") + "/" +
+ media.getJSONObject("location").optString("slug")));
postModels[i].setSliderDisplayUrl(node.getString("display_url"));
Utils.checkExistence(downloadDir, customDir, true, postModels[i]);
diff --git a/app/src/main/java/awais/instagrabber/asyncs/i/iPostFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/i/iPostFetcher.java
index 3e6330d7..a2d4c4a2 100755
--- a/app/src/main/java/awais/instagrabber/asyncs/i/iPostFetcher.java
+++ b/app/src/main/java/awais/instagrabber/asyncs/i/iPostFetcher.java
@@ -87,7 +87,10 @@ public final class iPostFetcher extends AsyncTask
isVideo && media.has("view_count") ? media.getLong("view_count") : -1,
timestamp, media.optBoolean("has_liked"), media.optBoolean("has_viewer_saved"),
media.getLong("like_count"),
- media.optJSONObject("location"));
+ media.isNull("location") ? null : media.getJSONObject("location").optString("name"),
+ media.isNull("location") ? null :
+ (media.getJSONObject("location").optString("id") + "/" +
+ media.getJSONObject("location").optString("slug")));
postModel.setCommentsCount(commentsCount);
@@ -114,7 +117,10 @@ public final class iPostFetcher extends AsyncTask
-1,
timestamp, media.optBoolean("has_liked"), media.optBoolean("has_viewer_saved"),
media.getLong("like_count"),
- media.optJSONObject("location"));
+ media.isNull("location") ? null : media.getJSONObject("location").optString("name"),
+ media.isNull("location") ? null :
+ (media.getJSONObject("location").optString("id") + "/" +
+ media.getJSONObject("location").optString("slug")));
postModels[i].setSliderDisplayUrl(Utils.getHighQualityImage(node));
Utils.checkExistence(downloadDir, customDir, true, postModels[i]);
diff --git a/app/src/main/java/awais/instagrabber/asyncs/i/iStoryStatusFetcher.java b/app/src/main/java/awais/instagrabber/asyncs/i/iStoryStatusFetcher.java
index 12a713e7..f584df06 100755
--- a/app/src/main/java/awais/instagrabber/asyncs/i/iStoryStatusFetcher.java
+++ b/app/src/main/java/awais/instagrabber/asyncs/i/iStoryStatusFetcher.java
@@ -16,7 +16,9 @@ import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.models.stickers.PollModel;
import awais.instagrabber.models.stickers.QuestionModel;
import awais.instagrabber.models.stickers.QuizModel;
+import awais.instagrabber.models.stickers.SwipeUpModel;
import awais.instagrabber.utils.Constants;
+import awais.instagrabber.utils.LocaleUtils;
import awais.instagrabber.utils.Utils;
import awaisomereport.LogCollector;
@@ -84,6 +86,7 @@ public final class iStoryStatusFetcher extends AsyncTask currentlyRunning;
private InboxThreadModelListViewModel listViewModel;
- public static boolean afterLeave = false;
+ public static boolean refreshPlease = false;
private final FetchListener fetchListener = new FetchListener() {
@Override
@@ -121,9 +121,9 @@ public class DirectMessageInboxFragment extends Fragment implements SwipeRefresh
@Override
public void onResume() {
super.onResume();
- if (afterLeave) {
+ if (refreshPlease) {
onRefresh();
- afterLeave = false;
+ refreshPlease = false;
}
}
diff --git a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageSettingsFragment.java b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageSettingsFragment.java
index 9b2c642d..1f589a30 100644
--- a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageSettingsFragment.java
+++ b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageSettingsFragment.java
@@ -199,7 +199,7 @@ public class DirectMessageSettingsFragment extends Fragment implements SwipeRefr
titleText.clearFocus();
}
else if (action.equals("leave")) {
- DirectMessageInboxFragment.afterLeave = true;
+ DirectMessageInboxFragment.refreshPlease = true;
NavHostFragment.findNavController(DirectMessageSettingsFragment.this).popBackStack(R.id.directMessagesInboxFragment, false);
}
}
diff --git a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java
index 5ca4531e..f55a4776 100644
--- a/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java
+++ b/app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java
@@ -66,6 +66,7 @@ import awais.instagrabber.models.direct_messages.DirectItemModel;
import awais.instagrabber.models.direct_messages.InboxThreadModel;
import awais.instagrabber.models.enums.DirectItemType;
import awais.instagrabber.models.enums.DownloadMethod;
+import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.models.enums.UserInboxDirection;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.Utils;
@@ -208,6 +209,7 @@ public class DirectMessageThreadFragment extends Fragment {
final DirectItemType itemType = directItemModel.getItemType();
switch (itemType) {
case MEDIA_SHARE:
+ case CLIP:
startActivity(new Intent(requireContext(), PostViewer.class)
.putExtra(Constants.EXTRAS_POST, new PostModel(directItemModel.getMediaModel().getCode(), false)));
break;
@@ -224,8 +226,16 @@ public class DirectMessageThreadFragment extends Fragment {
case RAVEN_MEDIA:
case MEDIA:
final ProfileModel user = getUser(directItemModel.getUserId());
- Utils.dmDownload(requireContext(), user.getUsername(), DownloadMethod.DOWNLOAD_DIRECT, Collections.singletonList(itemType == DirectItemType.MEDIA ? directItemModel.getMediaModel() : directItemModel.getRavenMediaModel().getMedia()));
- Toast.makeText(requireContext(), R.string.downloader_downloading_media, Toast.LENGTH_SHORT).show();
+ final DirectItemModel.DirectItemMediaModel selectedItem =
+ itemType == DirectItemType.MEDIA ? directItemModel.getMediaModel() : directItemModel.getRavenMediaModel().getMedia();
+ final String url = selectedItem.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO ? selectedItem.getVideoUrl() : selectedItem.getThumbUrl();
+ if (url == null) {
+ Toast.makeText(requireContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
+ }
+ else {
+ Utils.dmDownload(requireContext(), user.getUsername(), DownloadMethod.DOWNLOAD_DIRECT, selectedItem);
+ Toast.makeText(requireContext(), R.string.downloader_downloading_media, Toast.LENGTH_SHORT).show();
+ }
break;
case STORY_SHARE:
if (directItemModel.getReelShare() != null) {
@@ -275,6 +285,7 @@ public class DirectMessageThreadFragment extends Fragment {
switch (itemType) {
case MEDIA_SHARE:
+ case CLIP:
firstOption = R.string.view_post;
break;
case LINK:
@@ -376,6 +387,7 @@ public class DirectMessageThreadFragment extends Fragment {
}
directItemModel.setLiked();
}
+ DirectMessageInboxFragment.refreshPlease = true;
hasSentSomething = true;
new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, null, fetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
});
diff --git a/app/src/main/java/awais/instagrabber/models/StoryModel.java b/app/src/main/java/awais/instagrabber/models/StoryModel.java
index 1e2256d6..a2962e2b 100755
--- a/app/src/main/java/awais/instagrabber/models/StoryModel.java
+++ b/app/src/main/java/awais/instagrabber/models/StoryModel.java
@@ -6,6 +6,7 @@ import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.models.stickers.PollModel;
import awais.instagrabber.models.stickers.QuestionModel;
import awais.instagrabber.models.stickers.QuizModel;
+import awais.instagrabber.models.stickers.SwipeUpModel;
public final class StoryModel implements Serializable {
private final String storyMediaId, storyUrl, username, userId;
@@ -15,6 +16,7 @@ public final class StoryModel implements Serializable {
private PollModel poll;
private QuestionModel question;
private QuizModel quiz;
+ private SwipeUpModel swipeUp;
private String[] mentions;
private int position;
private boolean isCurrentSlide = false, canReply = false;
@@ -66,6 +68,8 @@ public final class StoryModel implements Serializable {
return quiz;
}
+ public SwipeUpModel getSwipeUp() { return swipeUp;}
+
public String[] getMentions() {
return mentions;
}
@@ -106,6 +110,10 @@ public final class StoryModel implements Serializable {
this.mentions = mentions;
}
+ public void setSwipeUp(final SwipeUpModel swipeUp) {
+ this.swipeUp = swipeUp;
+ }
+
public void setPosition(final int position) {
this.position = position;
}
diff --git a/app/src/main/java/awais/instagrabber/models/ViewerPostModel.java b/app/src/main/java/awais/instagrabber/models/ViewerPostModel.java
index e4c1ec0d..fdc062e4 100755
--- a/app/src/main/java/awais/instagrabber/models/ViewerPostModel.java
+++ b/app/src/main/java/awais/instagrabber/models/ViewerPostModel.java
@@ -5,8 +5,7 @@ import org.json.JSONObject;
import awais.instagrabber.models.enums.MediaItemType;
public final class ViewerPostModel extends BasePostModel {
- protected final String username;
- protected final JSONObject location;
+ protected final String username, locationName, location;
protected final long videoViews;
protected String sliderDisplayUrl;
protected long commentsCount, likes;
@@ -14,7 +13,7 @@ public final class ViewerPostModel extends BasePostModel {
public ViewerPostModel(final MediaItemType itemType, final String postId, final String displayUrl, final String shortCode,
final String postCaption, final String username, final long videoViews, final long timestamp,
- boolean liked, boolean bookmarked, long likes, final JSONObject location) {
+ boolean liked, boolean bookmarked, long likes, final String locationName, final String location) {
this.itemType = itemType;
this.postId = postId;
this.displayUrl = displayUrl;
@@ -26,6 +25,7 @@ public final class ViewerPostModel extends BasePostModel {
this.liked = liked;
this.likes = likes;
this.bookmarked = bookmarked;
+ this.locationName = locationName;
this.location = location;
}
@@ -41,7 +41,11 @@ public final class ViewerPostModel extends BasePostModel {
return username;
}
- public JSONObject getLocation() {
+ public String getLocationName() {
+ return locationName;
+ }
+
+ public String getLocation() {
return location;
}
diff --git a/app/src/main/java/awais/instagrabber/models/enums/DirectItemType.java b/app/src/main/java/awais/instagrabber/models/enums/DirectItemType.java
index c4137f8a..deb29467 100755
--- a/app/src/main/java/awais/instagrabber/models/enums/DirectItemType.java
+++ b/app/src/main/java/awais/instagrabber/models/enums/DirectItemType.java
@@ -18,7 +18,8 @@ public enum DirectItemType implements Serializable {
REEL_SHARE(11),
ACTION_LOG(12),
PLACEHOLDER(13),
- STORY_SHARE(14);
+ STORY_SHARE(14),
+ CLIP(15); // clip is just media_share but reel
private final int id;
private static Map map = new HashMap<>();
diff --git a/app/src/main/java/awais/instagrabber/models/stickers/SwipeUpModel.java b/app/src/main/java/awais/instagrabber/models/stickers/SwipeUpModel.java
new file mode 100755
index 00000000..4007d9b1
--- /dev/null
+++ b/app/src/main/java/awais/instagrabber/models/stickers/SwipeUpModel.java
@@ -0,0 +1,20 @@
+package awais.instagrabber.models.stickers;
+
+import java.io.Serializable;
+
+public final class SwipeUpModel implements Serializable {
+ private final String url, text;
+
+ public SwipeUpModel(final String url, final String text) {
+ this.url = url;
+ this.text = text;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public String getText() {
+ return text;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java
index 8c60d98f..e294b420 100755
--- a/app/src/main/java/awais/instagrabber/utils/Utils.java
+++ b/app/src/main/java/awais/instagrabber/utils/Utils.java
@@ -144,10 +144,10 @@ public final class Utils {
final URI uri1 = new URI("https://instagram.com");
final URI uri2 = new URI("https://instagram.com/");
final URI uri3 = new URI("https://i.instagram.com/");
- for (final String cookie : cookieRaw.split(";")) {
+ for (final String cookie : cookieRaw.split("; ")) {
final String[] strings = cookie.split("=", 2);
final HttpCookie httpCookie = new HttpCookie(strings[0].trim(), strings[1].trim());
- httpCookie.setDomain("instagram.com");
+ httpCookie.setDomain(".instagram.com");
httpCookie.setPath("/");
httpCookie.setVersion(0);
cookieStore.add(uri1, httpCookie);
@@ -427,7 +427,7 @@ public final class Utils {
if (userObj != null) {
user = new ProfileModel(
userObj.getBoolean("is_private"),
- false, // temporary
+ false,
userObj.optBoolean("is_verified"),
String.valueOf(userObj.get("pk")),
userObj.getString("username"),
@@ -468,6 +468,7 @@ public final class Utils {
if ("animated_media".equals(itemType)) return DirectItemType.ANIMATED_MEDIA;
if ("voice_media".equals(itemType)) return DirectItemType.VOICE_MEDIA;
if ("story_share".equals(itemType)) return DirectItemType.STORY_SHARE;
+ if ("clip".equals(itemType)) return DirectItemType.CLIP;
return DirectItemType.TEXT;
}
@@ -708,6 +709,11 @@ public final class Utils {
directMedia = getDirectMediaModel(itemObject.getJSONObject("media_share"));
break;
+ case CLIP:
+ Log.d("austin_debug", "clip: "+itemObject.getJSONObject("clip").getJSONObject("clip"));
+ directMedia = getDirectMediaModel(itemObject.getJSONObject("clip").getJSONObject("clip"));
+ break;
+
case MEDIA:
directMedia = getDirectMediaModel(itemObject.optJSONObject("media"));
break;
@@ -999,10 +1005,10 @@ public final class Utils {
}
public static void dmDownload(@NonNull final Context context, @Nullable final String username, final DownloadMethod method,
- final List extends DirectItemMediaModel> itemsToDownload) {
+ final DirectItemMediaModel itemsToDownload) {
if (settingsHelper == null) settingsHelper = new SettingsHelper(context);
- if (itemsToDownload == null || itemsToDownload.size() < 1) return;
+ if (itemsToDownload == null) return;
if (ContextCompat.checkSelfPermission(context, Utils.PERMS[0]) == PackageManager.PERMISSION_GRANTED)
dmDownloadImpl(context, username, method, itemsToDownload);
@@ -1011,7 +1017,7 @@ public final class Utils {
}
private static void dmDownloadImpl(@NonNull final Context context, @Nullable final String username,
- final DownloadMethod method, final List extends DirectItemMediaModel> itemsToDownload) {
+ final DownloadMethod method, final DirectItemMediaModel selectedItem) {
File dir = new File(Environment.getExternalStorageDirectory(), "Download");
if (settingsHelper.getBoolean(FOLDER_SAVE_TO)) {
@@ -1023,22 +1029,11 @@ public final class Utils {
dir = new File(dir, username);
if (dir.exists() || dir.mkdirs()) {
- final MainActivity mainActivity = method != DownloadMethod.DOWNLOAD_FEED && context instanceof MainActivity ? (MainActivity) context : null;
-
- final int itemsToDownloadSize = itemsToDownload.size();
-
final File finalDir = dir;
- for (int i = itemsToDownloadSize - 1; i >= 0; i--) {
- final DirectItemMediaModel selectedItem = itemsToDownload.get(i);
-
- if (mainActivity == null) {
- new DownloadAsync(context,
- selectedItem.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO ? selectedItem.getVideoUrl() : selectedItem.getThumbUrl(),
- getDownloadSaveFileDm(finalDir, selectedItem, ""),
- null).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-
- }
- }
+ new DownloadAsync(context,
+ selectedItem.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO ? selectedItem.getVideoUrl() : selectedItem.getThumbUrl(),
+ getDownloadSaveFileDm(finalDir, selectedItem, ""),
+ null).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else
Toast.makeText(context, R.string.error_creating_folders, Toast.LENGTH_SHORT).show();
}
@@ -1256,7 +1251,7 @@ public final class Utils {
final int endIndex = (spaceIndex != -1 ? spaceIndex : length);
- final String extractUrl = url.substring(startIndex, Math.min(length, endIndex) - 1);
+ final String extractUrl = url.substring(startIndex, Math.min(length, endIndex));
final SpannableString spannableString = new SpannableString(url);
spannableString.setSpan(new URLSpan(extractUrl), startIndex, endIndex, 0);
diff --git a/app/src/main/res/layout/activity_story_viewer.xml b/app/src/main/res/layout/activity_story_viewer.xml
index b815b721..d666260f 100755
--- a/app/src/main/res/layout/activity_story_viewer.xml
+++ b/app/src/main/res/layout/activity_story_viewer.xml
@@ -85,6 +85,15 @@
android:visibility="gone"
app:backgroundTint="@color/btn_blue_background" />
+
tools:text="location" />