1
0
mirror of https://github.com/KokaKiwi/BarInsta synced 2024-11-22 14:47:29 +00:00

Merge branch 'master' into task/separate-dm-type-views

This commit is contained in:
Ammar Githam 2020-08-20 23:04:17 +09:00
commit 052402a974
11 changed files with 367 additions and 139 deletions

View File

@ -10,8 +10,8 @@ android {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 29 targetSdkVersion 29
versionCode 45 versionCode 46
versionName '17.9' versionName '18.0'
multiDexEnabled true multiDexEnabled true

View File

@ -1,5 +1,7 @@
package awais.instagrabber.activities; package awais.instagrabber.activities;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
@ -7,8 +9,10 @@ import android.content.res.Resources;
import android.database.MatrixCursor; import android.database.MatrixCursor;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.provider.BaseColumns; import android.provider.BaseColumns;
import android.text.TextUtils;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
@ -20,10 +24,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.SearchView; import androidx.appcompat.widget.SearchView;
import androidx.core.app.NotificationCompat;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.GridLayoutManager;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Stack; import java.util.Stack;
import awais.instagrabber.BuildConfig; import awais.instagrabber.BuildConfig;
@ -31,6 +37,7 @@ import awais.instagrabber.MainHelper;
import awais.instagrabber.R; import awais.instagrabber.R;
import awais.instagrabber.adapters.HighlightsAdapter; import awais.instagrabber.adapters.HighlightsAdapter;
import awais.instagrabber.adapters.SuggestionsAdapter; import awais.instagrabber.adapters.SuggestionsAdapter;
import awais.instagrabber.asyncs.GetActivityAsyncTask;
import awais.instagrabber.asyncs.SuggestionsFetcher; import awais.instagrabber.asyncs.SuggestionsFetcher;
import awais.instagrabber.asyncs.UsernameFetcher; import awais.instagrabber.asyncs.UsernameFetcher;
import awais.instagrabber.asyncs.i.iStoryStatusFetcher; import awais.instagrabber.asyncs.i.iStoryStatusFetcher;
@ -58,6 +65,8 @@ import awais.instagrabber.utils.DataBox;
import awais.instagrabber.utils.FlavorTown; import awais.instagrabber.utils.FlavorTown;
import awais.instagrabber.utils.Utils; import awais.instagrabber.utils.Utils;
import static awais.instagrabber.utils.Utils.CHANNEL_ID;
import static awais.instagrabber.utils.Utils.notificationManager;
import static awais.instagrabber.utils.Utils.settingsHelper; import static awais.instagrabber.utils.Utils.settingsHelper;
public final class Main extends BaseLanguageActivity { public final class Main extends BaseLanguageActivity {
@ -97,7 +106,7 @@ public final class Main extends BaseLanguageActivity {
public SearchView searchView; public SearchView searchView;
public MenuItem downloadAction, settingsAction, dmsAction, notifAction; public MenuItem downloadAction, settingsAction, dmsAction, notifAction;
public StoryModel[] storyModels; public StoryModel[] storyModels;
public String userQuery = null; public String userQuery = null, cookie, uid = null;
public MainHelper mainHelper; public MainHelper mainHelper;
public ProfileModel profileModel; public ProfileModel profileModel;
public HashtagModel hashtagModel; public HashtagModel hashtagModel;
@ -107,6 +116,7 @@ public final class Main extends BaseLanguageActivity {
private DialogInterface.OnClickListener profileDialogListener; private DialogInterface.OnClickListener profileDialogListener;
private Stack<String> queriesStack; private Stack<String> queriesStack;
private DataBox.CookieModel cookieModel; private DataBox.CookieModel cookieModel;
private Runnable runnable;
@Override @Override
protected void onCreate(@Nullable final Bundle bundle) { protected void onCreate(@Nullable final Bundle bundle) {
@ -117,8 +127,8 @@ public final class Main extends BaseLanguageActivity {
FlavorTown.updateCheck(this); FlavorTown.updateCheck(this);
FlavorTown.changelogCheck(this); FlavorTown.changelogCheck(this);
final String cookie = settingsHelper.getString(Constants.COOKIE); cookie = settingsHelper.getString(Constants.COOKIE);
final String uid = Utils.getUserIdFromCookie(cookie); uid = Utils.getUserIdFromCookie(cookie);
Utils.setupCookies(cookie); Utils.setupCookies(cookie);
MainHelper.stopCurrentExecutor(); MainHelper.stopCurrentExecutor();
@ -246,6 +256,56 @@ public final class Main extends BaseLanguageActivity {
mainHelper.onRefresh(); mainHelper.onRefresh();
mainHelper.onIntent(getIntent()); mainHelper.onIntent(getIntent());
final Handler handler = new Handler();
runnable = () -> {
final GetActivityAsyncTask activityAsyncTask = new GetActivityAsyncTask(uid, cookie, result -> {
if (result == null) {
if (!Utils.isEmpty(cookie)) {
Toast.makeText(Main.this, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
}
return;
}
if (notificationManager == null) {
return;
}
final List<String> list = new ArrayList<>();
if (result.getRelationshipsCount() != 0) {
list.add(getString(R.string.activity_count_relationship, result.getRelationshipsCount()));
}
if (result.getUserTagsCount() != 0) {
list.add(getString(R.string.activity_count_usertags, result.getUserTagsCount()));
}
if (result.getCommentsCount() != 0) {
list.add(getString(R.string.activity_count_comments, result.getCommentsCount()));
}
if (result.getCommentLikesCount() != 0) {
list.add(getString(R.string.activity_count_commentlikes, result.getCommentLikesCount()));
}
if (result.getLikesCount() != 0) {
list.add(getString(R.string.activity_count_likes, result.getLikesCount()));
}
if (list.isEmpty()) {
return;
}
final String join = TextUtils.join(", ", list);
final String notificationString = getString(R.string.activity_count_prefix) + " " + join + ".";
final Intent intent = new Intent(getApplicationContext(), NotificationsViewer.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
final Notification notification = new NotificationCompat.Builder(Main.this, CHANNEL_ID)
.setCategory(NotificationCompat.CATEGORY_STATUS)
.setSmallIcon(R.drawable.ic_notif)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setContentText(notificationString)
.setContentIntent(PendingIntent.getActivity(getApplicationContext(), 1738, intent, PendingIntent.FLAG_UPDATE_CURRENT))
.build();
notificationManager.cancel(1800000000);
notificationManager.notify(1800000000, notification);
});
activityAsyncTask.execute();
handler.postDelayed(runnable, 60000);
};
handler.postDelayed(runnable, 200);
} }
private void downloadSelectedItems() { private void downloadSelectedItems() {

View File

@ -35,8 +35,9 @@ import awais.instagrabber.models.ProfileModel;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.Utils; import awais.instagrabber.utils.Utils;
import static awais.instagrabber.utils.Utils.notificationManager;
public final class NotificationsViewer extends BaseLanguageActivity implements SwipeRefreshLayout.OnRefreshListener { public final class NotificationsViewer extends BaseLanguageActivity implements SwipeRefreshLayout.OnRefreshListener {
private NotificationsAdapter notificationsAdapter;
private NotificationModel notificationModel; private NotificationModel notificationModel;
private ActivityNotificationBinding notificationsBinding; private ActivityNotificationBinding notificationsBinding;
private ArrayAdapter<String> commmentDialogAdapter; private ArrayAdapter<String> commmentDialogAdapter;
@ -47,26 +48,18 @@ public final class NotificationsViewer extends BaseLanguageActivity implements S
@Override @Override
protected void onCreate(@Nullable final Bundle savedInstanceState) { protected void onCreate(@Nullable final Bundle savedInstanceState) {
notificationManager.cancel(1800000000);
if (Utils.isEmpty(cookie)) {
Toast.makeText(this, R.string.activity_notloggedin, Toast.LENGTH_SHORT).show();
}
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
notificationsBinding = ActivityNotificationBinding.inflate(getLayoutInflater()); notificationsBinding = ActivityNotificationBinding.inflate(getLayoutInflater());
setContentView(notificationsBinding.getRoot()); setContentView(notificationsBinding.getRoot());
notificationsBinding.swipeRefreshLayout.setOnRefreshListener(this); notificationsBinding.swipeRefreshLayout.setOnRefreshListener(this);
resources = getResources();
notificationsBinding.swipeRefreshLayout.setRefreshing(true);
setSupportActionBar(notificationsBinding.toolbar.toolbar); setSupportActionBar(notificationsBinding.toolbar.toolbar);
notificationsBinding.toolbar.toolbar.setTitle(R.string.action_notif); notificationsBinding.toolbar.toolbar.setTitle(R.string.action_notif);
onRefresh();
resources = getResources();
new NotificationsFetcher(new FetchListener<NotificationModel[]>() {
@Override
public void onResult(final NotificationModel[] notificationModels) {
notificationsAdapter = new NotificationsAdapter(notificationModels, clickListener, mentionClickListener);
notificationsBinding.rvComments.setAdapter(notificationsAdapter);
notificationsBinding.swipeRefreshLayout.setRefreshing(false);
}
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
@Override @Override
@ -75,11 +68,9 @@ public final class NotificationsViewer extends BaseLanguageActivity implements S
new NotificationsFetcher(new FetchListener<NotificationModel[]>() { new NotificationsFetcher(new FetchListener<NotificationModel[]>() {
@Override @Override
public void onResult(final NotificationModel[] notificationModels) { public void onResult(final NotificationModel[] notificationModels) {
notificationsBinding.rvComments.setAdapter(new NotificationsAdapter(notificationModels, clickListener, mentionClickListener));
notificationsBinding.swipeRefreshLayout.setRefreshing(false); notificationsBinding.swipeRefreshLayout.setRefreshing(false);
new SeenAction().execute();
notificationsAdapter = new NotificationsAdapter(notificationModels, clickListener, mentionClickListener);
notificationsBinding.rvComments.setAdapter(notificationsAdapter);
} }
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
@ -150,7 +141,8 @@ public final class NotificationsViewer extends BaseLanguageActivity implements S
urlConnection.setUseCaches(false); urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("User-Agent", Constants.USER_AGENT); urlConnection.setRequestProperty("User-Agent", Constants.USER_AGENT);
urlConnection.setRequestProperty("x-csrftoken", urlConnection.setRequestProperty("x-csrftoken",
Utils.settingsHelper.getString(Constants.COOKIE).split("csrftoken=")[1].split(";")[0]);urlConnection.connect(); Utils.settingsHelper.getString(Constants.COOKIE).split("csrftoken=")[1].split(";")[0]);
urlConnection.connect();
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
ok = true; ok = true;
} }
@ -169,4 +161,23 @@ public final class NotificationsViewer extends BaseLanguageActivity implements S
else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); else Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
} }
} }
class SeenAction extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... lmao) {
try {
final HttpURLConnection urlConnection =
(HttpURLConnection) new URL("https://www.instagram.com/web/activity/mark_checked/").openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("User-Agent", Constants.USER_AGENT);
urlConnection.setRequestProperty("x-csrftoken",
Utils.settingsHelper.getString(Constants.COOKIE).split("csrftoken=")[1].split(";")[0]);
urlConnection.connect();
urlConnection.disconnect();
} catch (Throwable ex) {
Log.e("austin_debug", "seen: " + ex);
}
return null;
}
}
} }

View File

@ -56,6 +56,7 @@ import awais.instagrabber.BuildConfig;
import awais.instagrabber.R; import awais.instagrabber.R;
import awais.instagrabber.adapters.StoriesAdapter; import awais.instagrabber.adapters.StoriesAdapter;
import awais.instagrabber.asyncs.DownloadAsync; import awais.instagrabber.asyncs.DownloadAsync;
import awais.instagrabber.asyncs.direct_messages.DirectThreadBroadcaster;
import awais.instagrabber.asyncs.i.iStoryStatusFetcher; import awais.instagrabber.asyncs.i.iStoryStatusFetcher;
import awais.instagrabber.customviews.helpers.SwipeGestureListener; import awais.instagrabber.customviews.helpers.SwipeGestureListener;
import awais.instagrabber.databinding.ActivityStoryViewerBinding; import awais.instagrabber.databinding.ActivityStoryViewerBinding;
@ -723,8 +724,6 @@ final String url = "https://i.instagram.com/api/v1/media/"+currentStory.getStory
} }
class CommentAction extends AsyncTask<String, Void, Void> { class CommentAction extends AsyncTask<String, Void, Void> {
boolean ok = false;
protected Void doInBackground(String... rawAction) { protected Void doInBackground(String... rawAction) {
final String action = rawAction[0]; final String action = rawAction[0];
final String url = "https://i.instagram.com/api/v1/direct_v2/create_group_thread/"; final String url = "https://i.instagram.com/api/v1/direct_v2/create_group_thread/";
@ -747,55 +746,27 @@ final String url = "https://i.instagram.com/api/v1/media/"+currentStory.getStory
wr.close(); wr.close();
urlConnection.connect(); urlConnection.connect();
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
try { final String threadid = new JSONObject(Utils.readFromConnection(urlConnection)).getString("thread_id");
final String threadid = new JSONObject(Utils.readFromConnection(urlConnection)).getString("thread_id"); final DirectThreadBroadcaster.StoryReplyBroadcastOptions options =
final String url2 = "https://i.instagram.com/api/v1/direct_v2/threads/broadcast/reel_share/"; new DirectThreadBroadcaster.StoryReplyBroadcastOptions(
final HttpURLConnection urlConnection2 = (HttpURLConnection) new URL(url2).openConnection(); action,
urlConnection2.setRequestMethod("POST"); currentStory.getStoryMediaId(),
urlConnection2.setRequestProperty("User-Agent", Constants.I_USER_AGENT); currentStory.getUserId()
urlConnection2.setUseCaches(false); );
final String commentText = URLEncoder.encode(action, "UTF-8") final DirectThreadBroadcaster broadcast = new DirectThreadBroadcaster(threadid);
.replaceAll("\\+", "%20").replaceAll("\\%21", "!").replaceAll("\\%27", "'") broadcast.setOnTaskCompleteListener(result -> {
.replaceAll("\\%28", "(").replaceAll("\\%29", ")").replaceAll("\\%7E", "~"); Toast.makeText(getApplicationContext(),
final String cc = UUID.randomUUID().toString(); result != null ? R.string.answered_story : R.string.downloader_unknown_error,
final String urlParameters2 = Utils.sign("{\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0] Toast.LENGTH_SHORT).show();
+"\",\"_uid\":\"" + Utils.getUserIdFromCookie(cookie) });
+"\",\"__uuid\":\"" + settingsHelper.getString(Constants.DEVICE_UUID) broadcast.execute(options);
+"\",\"client_context\":\"" + cc
+"\",\"mutation_token\":\"" + cc
+"\",\"text\":\"" + commentText
+"\",\"media_id\":\"" + currentStory.getStoryMediaId()
+"\",\"reel_id\":\"" + currentStory.getUserId()
+"\",\"thread_ids\":\"["+threadid
+"]\",\"action\":\"send_item\",\"entry\":\"reel\"}");
urlConnection2.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
urlConnection2.setRequestProperty("Content-Length", "" + Integer.toString(urlParameters2.getBytes().length));
urlConnection2.setDoOutput(true);
DataOutputStream wr2 = new DataOutputStream(urlConnection2.getOutputStream());
wr2.writeBytes(urlParameters2);
wr2.flush();
wr2.close();
urlConnection2.connect();
if (urlConnection2.getResponseCode() == HttpURLConnection.HTTP_OK) {
ok = true;
}
urlConnection2.disconnect();
} catch (Throwable ex) {
Log.e("austin_debug", "reply (B): " + ex);
}
} }
urlConnection.disconnect(); urlConnection.disconnect();
} catch (Throwable ex) { } catch (Throwable ex) {
Log.e("austin_debug", "reply (CT): " + ex); Log.e("austin_debug", "reply (CT): " + ex);
Toast.makeText(getApplicationContext(), R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
} }
return null; return null;
} }
@Override
protected void onPostExecute(Void result) {
Toast.makeText(getApplicationContext(),
ok ? R.string.answered_story : R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
}
} }
} }

View File

@ -0,0 +1,113 @@
package awais.instagrabber.asyncs;
import android.os.AsyncTask;
import android.util.Log;
import org.json.JSONObject;
import java.net.HttpURLConnection;
import java.net.URL;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.Utils;
public class GetActivityAsyncTask extends AsyncTask<Void, Void, GetActivityAsyncTask.NotificationCounts> {
private static final String TAG = "GetActivityAsyncTask";
private String uid;
private String cookie;
private OnTaskCompleteListener onTaskCompleteListener;
public GetActivityAsyncTask(final String uid, final String cookie, final OnTaskCompleteListener onTaskCompleteListener) {
this.uid = uid;
this.cookie = cookie;
this.onTaskCompleteListener = onTaskCompleteListener;
}
protected NotificationCounts doInBackground(Void... voids) {
if (Utils.isEmpty(cookie)) {
return null;
}
final String url = "https://www.instagram.com/graphql/query/?query_hash=0f318e8cfff9cc9ef09f88479ff571fb"
+ "&variables={\"id\":\"" + uid + "\"}";
HttpURLConnection urlConnection = null;
try {
urlConnection = (HttpURLConnection) new URL(url).openConnection();
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("User-Agent", Constants.USER_AGENT);
urlConnection.setRequestProperty("x-csrftoken", cookie.split("csrftoken=")[1].split(";")[0]);
urlConnection.connect();
if (urlConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
return null;
}
final JSONObject data = new JSONObject(Utils.readFromConnection(urlConnection)).getJSONObject("data")
.getJSONObject("user").getJSONObject("edge_activity_count").getJSONArray("edges").getJSONObject(0)
.getJSONObject("node");
return new NotificationCounts(
data.getInt("relationships"),
data.getInt("usertags"),
data.getInt("comments"),
data.getInt("comment_likes"),
data.getInt("likes")
);
} catch (Throwable ex) {
Log.e(TAG, "Error", ex);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return null;
}
@Override
protected void onPostExecute(final NotificationCounts result) {
if (onTaskCompleteListener == null) {
return;
}
onTaskCompleteListener.onTaskComplete(result);
}
public static class NotificationCounts {
private int relationshipsCount;
private int userTagsCount;
private int commentsCount;
private int commentLikesCount;
private int likesCount;
public NotificationCounts(final int relationshipsCount,
final int userTagsCount,
final int commentsCount,
final int commentLikesCount,
final int likesCount) {
this.relationshipsCount = relationshipsCount;
this.userTagsCount = userTagsCount;
this.commentsCount = commentsCount;
this.commentLikesCount = commentLikesCount;
this.likesCount = likesCount;
}
public int getRelationshipsCount() {
return relationshipsCount;
}
public int getUserTagsCount() {
return userTagsCount;
}
public int getCommentsCount() {
return commentsCount;
}
public int getCommentLikesCount() {
return commentLikesCount;
}
public int getLikesCount() {
return likesCount;
}
}
public interface OnTaskCompleteListener {
void onTaskComplete(final NotificationCounts result);
}
}

View File

@ -19,6 +19,7 @@ import awais.instagrabber.utils.Utils;
import awaisomereport.LogCollector; import awaisomereport.LogCollector;
import static awais.instagrabber.utils.Utils.logCollector; import static awais.instagrabber.utils.Utils.logCollector;
import static awais.instagrabber.utils.Utils.settingsHelper;
public final class NotificationsFetcher extends AsyncTask<Void, Void, NotificationModel[]> { public final class NotificationsFetcher extends AsyncTask<Void, Void, NotificationModel[]> {
private final FetchListener<NotificationModel[]> fetchListener; private final FetchListener<NotificationModel[]> fetchListener;
@ -31,6 +32,7 @@ public final class NotificationsFetcher extends AsyncTask<Void, Void, Notificati
protected NotificationModel[] doInBackground(final Void... voids) { protected NotificationModel[] doInBackground(final Void... voids) {
NotificationModel[] result = null; NotificationModel[] result = null;
final String url = "https://www.instagram.com/accounts/activity/?__a=1"; final String url = "https://www.instagram.com/accounts/activity/?__a=1";
Utils.setupCookies(settingsHelper.getString(Constants.COOKIE));
try { try {
final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); final HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();

View File

@ -126,6 +126,7 @@ public class DirectThreadBroadcaster extends AsyncTask<DirectThreadBroadcaster.B
public enum ItemType { public enum ItemType {
TEXT("text"), TEXT("text"),
REACTION("reaction"), REACTION("reaction"),
REELSHARE("reel_share"),
IMAGE("configure_photo"); IMAGE("configure_photo");
private final String value; private final String value;
@ -189,6 +190,29 @@ public class DirectThreadBroadcaster extends AsyncTask<DirectThreadBroadcaster.B
} }
} }
public static class StoryReplyBroadcastOptions extends BroadcastOptions {
private final String text, mediaId, reelId;
public StoryReplyBroadcastOptions(String text, String mediaId, String reelId) throws UnsupportedEncodingException {
super(ItemType.REELSHARE);
this.text = URLEncoder.encode(text, "UTF-8")
.replaceAll("\\+", "%20").replaceAll("%21", "!").replaceAll("%27", "'")
.replaceAll("%28", "(").replaceAll("%29", ")").replaceAll("%7E", "~");
this.mediaId = mediaId;
this.reelId = reelId; // or user id, usually same
}
@Override
Map<String, String> getFormMap() {
final Map<String, String> form = new HashMap<>();
form.put("text", text);
form.put("media_id", mediaId);
form.put("reel_id", reelId);
form.put("entry", "reel");
return form;
}
}
public static class ImageBroadcastOptions extends BroadcastOptions { public static class ImageBroadcastOptions extends BroadcastOptions {
final boolean allowFullAspectRatio; final boolean allowFullAspectRatio;
final String uploadId; final String uploadId;

View File

@ -31,15 +31,20 @@ import androidx.recyclerview.widget.RecyclerView;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.UUID;
import awais.instagrabber.R; import awais.instagrabber.R;
import awais.instagrabber.activities.PostViewer; import awais.instagrabber.activities.PostViewer;
@ -78,7 +83,7 @@ public class DirectMessageThreadFragment extends Fragment {
private DirectItemModelListViewModel listViewModel; private DirectItemModelListViewModel listViewModel;
private DirectItemModel directItemModel; private DirectItemModel directItemModel;
private RecyclerView messageList; private RecyclerView messageList;
private boolean hasSentSomething; private boolean hasSentSomething, hasDeletedSomething;
private boolean hasOlder = true; private boolean hasOlder = true;
private final ProfileModel myProfileHolder = ProfileModel.getDefaultProfileModel(); private final ProfileModel myProfileHolder = ProfileModel.getDefaultProfileModel();
@ -135,15 +140,16 @@ public class DirectMessageThreadFragment extends Fragment {
List<DirectItemModel> list = listViewModel.getList().getValue(); List<DirectItemModel> list = listViewModel.getList().getValue();
final List<DirectItemModel> newList = Arrays.asList(result.getItems()); final List<DirectItemModel> newList = Arrays.asList(result.getItems());
list = list != null ? new LinkedList<>(list) : new LinkedList<>(); list = list != null ? new LinkedList<>(list) : new LinkedList<>();
if (hasSentSomething) { if (hasSentSomething || hasDeletedSomething) {
list = newList; list = newList;
hasSentSomething = false;
final Handler handler = new Handler(); final Handler handler = new Handler();
handler.postDelayed(() -> { if (hasSentSomething) handler.postDelayed(() -> {
if (messageList != null) { if (messageList != null) {
messageList.smoothScrollToPosition(0); messageList.smoothScrollToPosition(0);
} }
}, 200); }, 200);
hasSentSomething = false;
hasDeletedSomething = false;
} else { } else {
list.addAll(newList); list.addAll(newList);
} }
@ -186,67 +192,64 @@ public class DirectMessageThreadFragment extends Fragment {
})); }));
final DialogInterface.OnClickListener onDialogListener = (dialogInterface, which) -> { final DialogInterface.OnClickListener onDialogListener = (dialogInterface, which) -> {
switch (which) { if (which == 0) {
case 0: final DirectItemType itemType = directItemModel.getItemType();
final DirectItemType itemType = directItemModel.getItemType(); switch (itemType) {
switch (itemType) { case MEDIA_SHARE:
case MEDIA_SHARE: startActivity(new Intent(requireContext(), PostViewer.class)
startActivity(new Intent(requireContext(), PostViewer.class) .putExtra(Constants.EXTRAS_POST, new PostModel(directItemModel.getMediaModel().getCode(), false)));
.putExtra(Constants.EXTRAS_POST, new PostModel(directItemModel.getMediaModel().getCode(), false))); break;
break; case LINK:
case LINK: Intent linkIntent = new Intent(Intent.ACTION_VIEW);
Intent linkIntent = new Intent(Intent.ACTION_VIEW); linkIntent.setData(Uri.parse(directItemModel.getLinkModel().getLinkContext().getLinkUrl()));
linkIntent.setData(Uri.parse(directItemModel.getLinkModel().getLinkContext().getLinkUrl())); startActivity(linkIntent);
startActivity(linkIntent); break;
break; case TEXT:
case TEXT: case REEL_SHARE:
case REEL_SHARE: Utils.copyText(requireContext(), directItemModel.getText());
Utils.copyText(requireContext(), directItemModel.getText()); Toast.makeText(requireContext(), R.string.clipboard_copied, Toast.LENGTH_SHORT).show();
Toast.makeText(requireContext(), R.string.clipboard_copied, Toast.LENGTH_SHORT).show(); break;
break; case RAVEN_MEDIA:
case RAVEN_MEDIA: case MEDIA:
case MEDIA: final ProfileModel user = getUser(directItemModel.getUserId());
final ProfileModel user = getUser(directItemModel.getUserId()); Utils.dmDownload(requireContext(), user.getUsername(), DownloadMethod.DOWNLOAD_DIRECT, Collections.singletonList(itemType == DirectItemType.MEDIA ? directItemModel.getMediaModel() : directItemModel.getRavenMediaModel().getMedia()));
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();
Toast.makeText(requireContext(), R.string.downloader_downloading_media, Toast.LENGTH_SHORT).show(); break;
break; case STORY_SHARE:
case STORY_SHARE: if (directItemModel.getReelShare() != null) {
if (directItemModel.getReelShare() != null) { StoryModel sm = new StoryModel(
StoryModel sm = new StoryModel( directItemModel.getReelShare().getReelId(),
directItemModel.getReelShare().getReelId(), directItemModel.getReelShare().getMedia().getVideoUrl(),
directItemModel.getReelShare().getMedia().getVideoUrl(), directItemModel.getReelShare().getMedia().getMediaType(),
directItemModel.getReelShare().getMedia().getMediaType(), directItemModel.getTimestamp(),
directItemModel.getTimestamp(), directItemModel.getReelShare().getReelOwnerName(),
directItemModel.getReelShare().getReelOwnerName(), String.valueOf(directItemModel.getReelShare().getReelOwnerId()),
String.valueOf(directItemModel.getReelShare().getReelOwnerId()), false
false );
); sm.setVideoUrl(directItemModel.getReelShare().getMedia().getVideoUrl());
sm.setVideoUrl(directItemModel.getReelShare().getMedia().getVideoUrl()); StoryModel[] sms = {sm};
StoryModel[] sms = {sm}; startActivity(new Intent(requireContext(), StoryViewer.class)
startActivity(new Intent(requireContext(), StoryViewer.class) .putExtra(Constants.EXTRAS_USERNAME, directItemModel.getReelShare().getReelOwnerName())
.putExtra(Constants.EXTRAS_USERNAME, directItemModel.getReelShare().getReelOwnerName()) .putExtra(Constants.EXTRAS_STORIES, sms)
.putExtra(Constants.EXTRAS_STORIES, sms) );
); } else if (directItemModel.getText() != null && directItemModel.getText().toString().contains("@")) {
} else if (directItemModel.getText() != null && directItemModel.getText().toString().contains("@")) { searchUsername(directItemModel.getText().toString().split("@")[1].split(" ")[0]);
searchUsername(directItemModel.getText().toString().split("@")[1].split(" ")[0]); }
} break;
break; case PLACEHOLDER:
case PLACEHOLDER: if (directItemModel.getText().toString().contains("@"))
if (directItemModel.getText().toString().contains("@")) searchUsername(directItemModel.getText().toString().split("@")[1].split(" ")[0]);
searchUsername(directItemModel.getText().toString().split("@")[1].split(" ")[0]); break;
break; default:
default: Log.d("austin_debug", "unsupported type " + itemType);
Log.d("austin_debug", "unsupported type " + itemType); }
} }
break; else if (which == 1) {
case 1: sendText(null, directItemModel.getItemId(), directItemModel.isLiked());
sendText(null, directItemModel.getItemId(), directItemModel.isLiked()); }
break; else if (which == 2) {
case 2: if (String.valueOf(directItemModel.getUserId()).equals(myId)) new Unsend().execute();
if (String.valueOf(directItemModel.getUserId()).equals(myId)) { else searchUsername(getUser(directItemModel.getUserId()).getUsername());
// unsend: https://www.instagram.com/direct_v2/web/threads/340282366841710300949128288687654467119/items/29473546990090204551245070881259520/delete/
} else searchUsername(getUser(directItemModel.getUserId()).getUsername());
break;
} }
}; };
final View.OnClickListener onClickListener = v -> { final View.OnClickListener onClickListener = v -> {
@ -427,4 +430,41 @@ public class DirectMessageThreadFragment extends Fragment {
return list; return list;
} }
} }
class Unsend extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... lmao) {
final String url = "https://i.instagram.com/api/v1/direct_v2/threads/"+threadId+"/items/"+directItemModel.getItemId()+"/delete/";
try {
String urlParameters = "_csrftoken=" + cookie.split("csrftoken=")[1].split(";")[0]
+"&_uuid=" + Utils.settingsHelper.getString(Constants.DEVICE_UUID);
final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT);
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
urlConnection.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
wr.close();
urlConnection.connect();
if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
hasDeletedSomething = true;
}
urlConnection.disconnect();
} catch (Throwable ex) {
Log.e("austin_debug", "unsend: " + ex);
}
return null;
}
@Override
protected void onPostExecute(Void result) {
if (hasDeletedSomething) {
directItemModel = null;
new DirectMessageInboxThreadFetcher(threadId, UserInboxDirection.OLDER, null, fetchListener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
}
} }

View File

@ -33,9 +33,9 @@ public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
conn.connect(); conn.connect();
final int responseCode = conn.getResponseCode(); final int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_MOVED_TEMP) { if (responseCode == HttpURLConnection.HTTP_MOVED_TEMP && !BuildConfig.DEBUG) {
version = conn.getHeaderField("Location").split("/v")[1]; version = conn.getHeaderField("Location").split("/v")[1];
return Float.parseFloat(version) > Float.parseFloat(BuildConfig.VERSION_NAME); return version != BuildConfig.VERSION_NAME;
} }
conn.disconnect(); conn.disconnect();

View File

@ -175,8 +175,8 @@ public final class Utils {
clipString = clipString.substring((isHttps ? 22 : 21) + wwwDel); clipString = clipString.substring((isHttps ? 22 : 21) + wwwDel);
final char firstChar = clipString.charAt(0); final char firstChar = clipString.charAt(0);
if (clipString.startsWith("p/") || clipString.startsWith("reel/")) { if (clipString.startsWith("p/") || clipString.startsWith("reel/") || clipString.startsWith("tv/")) {
clipString = clipString.substring(clipString.startsWith("p/") ? 2 : 5); clipString = clipString.substring(clipString.startsWith("p/") ? 2 : (clipString.startsWith("tv/") ? 3 : 5));
type = IntentModelType.POST; type = IntentModelType.POST;
} else if (clipString.startsWith("explore/tags/")) { } else if (clipString.startsWith("explore/tags/")) {
clipString = clipString.substring(13); clipString = clipString.substring(13);

View File

@ -222,4 +222,11 @@
<string name="license" translatable="false">InstaGrabber\nCopyright (C) 2019 AWAiS\nCopyright (C) 2020 Austin Huang, Ammar Githam\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. See https://www.gnu.org/licenses/.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR \'\'AS IS\'\' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nSee project page for third-party attributions.</string> <string name="license" translatable="false">InstaGrabber\nCopyright (C) 2019 AWAiS\nCopyright (C) 2020 Austin Huang, Ammar Githam\n\nThis program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. See https://www.gnu.org/licenses/.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR \'\'AS IS\'\' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nSee project page for third-party attributions.</string>
<string name="select_picture">Select Picture</string> <string name="select_picture">Select Picture</string>
<string name="uploading">Uploading...</string> <string name="uploading">Uploading...</string>
<string name="activity_count_prefix">You have:</string>
<string name="activity_count_relationship">%d follows</string>
<string name="activity_count_comments">%d comments</string>
<string name="activity_count_commentlikes">%d comment likes</string>
<string name="activity_count_usertags">%d usertags</string>
<string name="activity_count_likes">%d likes</string>
<string name="activity_notloggedin">You logged out before clicking this notification?!</string>
</resources> </resources>