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

Merge remote-tracking branch 'origin/dm-notifications-enhancements' into dm-notifications-enhancements

This commit is contained in:
Ammar Githam 2021-01-13 22:25:01 +09:00
commit 3795ff2420
41 changed files with 429 additions and 231 deletions

View File

@ -10,8 +10,8 @@ android {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 29
versionCode 57 versionCode 58
versionName '19.0.5' versionName '19.1.0'
multiDexEnabled true multiDexEnabled true

View File

@ -12,11 +12,13 @@ import com.facebook.imagepipeline.core.ImagePipelineConfig;
import java.net.CookieHandler; import java.net.CookieHandler;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.LocaleUtils; import awais.instagrabber.utils.LocaleUtils;
import awais.instagrabber.utils.SettingsHelper; import awais.instagrabber.utils.SettingsHelper;
import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.UserAgentUtils;
import awaisomereport.CrashReporter; import awaisomereport.CrashReporter;
import awaisomereport.LogCollector; import awaisomereport.LogCollector;
@ -85,5 +87,15 @@ public final class InstaGrabberApplication extends Application {
if (TextUtils.isEmpty(settingsHelper.getString(Constants.DEVICE_UUID))) { if (TextUtils.isEmpty(settingsHelper.getString(Constants.DEVICE_UUID))) {
settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString()); settingsHelper.putString(Constants.DEVICE_UUID, UUID.randomUUID().toString());
} }
if (settingsHelper.getInteger(Constants.BROWSER_UA_CODE) == -1) {
int randomNum = ThreadLocalRandom.current().nextInt(0, UserAgentUtils.browsers.length);
settingsHelper.putInteger(Constants.BROWSER_UA_CODE, randomNum);
}
if (settingsHelper.getInteger(Constants.APP_UA_CODE) == -1) {
int randomNum = ThreadLocalRandom.current().nextInt(0, UserAgentUtils.devices.length);
settingsHelper.putInteger(Constants.APP_UA_CODE, randomNum);
}
} }
} }

View File

@ -0,0 +1,61 @@
package awais.instagrabber.animations;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.view.View;
// https://medium.com/better-programming/animated-fab-button-with-more-options-2dcf7118fff6
public class FabAnimation {
public static boolean rotateFab(final View v, boolean rotate) {
v.animate().setDuration(200)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
})
.rotation(rotate ? 135f : 0f);
return rotate;
}
public static void showIn(final View v) {
v.setVisibility(View.VISIBLE);
v.setAlpha(0f);
v.setTranslationY(v.getHeight());
v.animate()
.setDuration(200)
.translationY(0)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
})
.alpha(1f)
.start();
}
public static void showOut(final View v) {
v.setVisibility(View.VISIBLE);
v.setAlpha(1f);
v.setTranslationY(0);
v.animate()
.setDuration(200)
.translationY(v.getHeight())
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
v.setVisibility(View.GONE);
super.onAnimationEnd(animation);
}
}).alpha(0f)
.start();
}
public static void init(final View v) {
v.setVisibility(View.GONE);
v.setTranslationY(v.getHeight());
v.setAlpha(0f);
}
}

View File

@ -35,7 +35,7 @@ public class CreateThreadAction extends AsyncTask<Void, Void, String> {
try { try {
urlConnection = (HttpURLConnection) new URL(url).openConnection(); urlConnection = (HttpURLConnection) new URL(url).openConnection();
urlConnection.setRequestMethod("POST"); urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT); urlConnection.setRequestProperty("User-Agent", Utils.settingsHelper.getString(Constants.APP_UA));
urlConnection.setUseCaches(false); urlConnection.setUseCaches(false);
final String urlParameters = Utils.sign("{\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0] final String urlParameters = Utils.sign("{\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0]
+ "\",\"_uid\":\"" + CookieUtils.getUserIdFromCookie(cookie) + "\",\"_uid\":\"" + CookieUtils.getUserIdFromCookie(cookie)

View File

@ -29,8 +29,9 @@ public class FeedPostFetchService implements PostFetcher.PostFetchService {
final List<Media> feedModels = new ArrayList<>(); final List<Media> feedModels = new ArrayList<>();
final String cookie = settingsHelper.getString(Constants.COOKIE); final String cookie = settingsHelper.getString(Constants.COOKIE);
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
feedModels.clear(); feedModels.clear();
feedService.fetch(csrfToken, nextCursor, new ServiceCallback<PostsFetchResponse>() { feedService.fetch(csrfToken, deviceUuid, nextCursor, new ServiceCallback<PostsFetchResponse>() {
@Override @Override
public void onSuccess(final PostsFetchResponse result) { public void onSuccess(final PostsFetchResponse result) {
if (result == null && feedModels.size() > 0) { if (result == null && feedModels.size() > 0) {

View File

@ -14,6 +14,7 @@ import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.NetworkUtils; import awais.instagrabber.utils.NetworkUtils;
import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils;
public class GetActivityAsyncTask extends AsyncTask<String, Void, GetActivityAsyncTask.NotificationCounts> { public class GetActivityAsyncTask extends AsyncTask<String, Void, GetActivityAsyncTask.NotificationCounts> {
private static final String TAG = "GetActivityAsyncTask"; private static final String TAG = "GetActivityAsyncTask";
@ -44,7 +45,7 @@ public class GetActivityAsyncTask extends AsyncTask<String, Void, GetActivityAsy
try { try {
urlConnection = (HttpURLConnection) new URL(url).openConnection(); urlConnection = (HttpURLConnection) new URL(url).openConnection();
urlConnection.setUseCaches(false); urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("User-Agent", Constants.USER_AGENT); urlConnection.setRequestProperty("User-Agent", Utils.settingsHelper.getString(Constants.BROWSER_UA));
urlConnection.setRequestProperty("x-csrftoken", cookie.split("csrftoken=")[1].split(";")[0]); urlConnection.setRequestProperty("x-csrftoken", cookie.split("csrftoken=")[1].split(";")[0]);
urlConnection.connect(); urlConnection.connect();
if (urlConnection.getResponseCode() != HttpURLConnection.HTTP_OK) { if (urlConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {

View File

@ -76,8 +76,8 @@ public final class ProfileFetcher extends AsyncTask<Void, Void, User> {
userJson.optBoolean("blocked_by_viewer"), userJson.optBoolean("blocked_by_viewer"),
false, false,
isPrivate, isPrivate,
false, userJson.optBoolean("has_requested_viewer"),
userJson.optBoolean("restricted_by_viewer"), userJson.optBoolean("requested_by_viewer"),
false, false,
userJson.optBoolean("restricted_by_viewer"), userJson.optBoolean("restricted_by_viewer"),
false false

View File

@ -14,6 +14,7 @@ import awais.instagrabber.BuildConfig;
import awais.instagrabber.interfaces.FetchListener; import awais.instagrabber.interfaces.FetchListener;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.NetworkUtils; import awais.instagrabber.utils.NetworkUtils;
import awais.instagrabber.utils.Utils;
public final class UsernameFetcher extends AsyncTask<Void, Void, String> { public final class UsernameFetcher extends AsyncTask<Void, Void, String> {
private final FetchListener<String> fetchListener; private final FetchListener<String> fetchListener;
@ -31,7 +32,7 @@ public final class UsernameFetcher extends AsyncTask<Void, Void, String> {
try { try {
final HttpURLConnection conn = (HttpURLConnection) new URL("https://i.instagram.com/api/v1/users/" + uid + "/info/").openConnection(); final HttpURLConnection conn = (HttpURLConnection) new URL("https://i.instagram.com/api/v1/users/" + uid + "/info/").openConnection();
conn.setRequestProperty("User-Agent", Constants.USER_AGENT); conn.setRequestProperty("User-Agent", Utils.settingsHelper.getString(Constants.BROWSER_UA));
conn.setUseCaches(true); conn.setUseCaches(true);
final JSONObject user; final JSONObject user;

View File

@ -64,7 +64,7 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl
private LinearLayoutManager layoutManager; private LinearLayoutManager layoutManager;
private RecyclerLazyLoader lazyLoader; private RecyclerLazyLoader lazyLoader;
private String shortCode; private String shortCode;
private long userId; private long authorUserId, userIdFromCookie;
private String endCursor = null; private String endCursor = null;
private Resources resources; private Resources resources;
private InputMethodManager imm; private InputMethodManager imm;
@ -140,14 +140,13 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl
Toast.makeText(context, R.string.comment_send_empty_comment, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.comment_send_empty_comment, Toast.LENGTH_SHORT).show();
return; return;
} }
final long userId = CookieUtils.getUserIdFromCookie(cookie); if (userIdFromCookie == 0) return;
if (userId == 0) return;
String replyToId = null; String replyToId = null;
final CommentModel commentModel = commentsAdapter.getSelected(); final CommentModel commentModel = commentsAdapter.getSelected();
if (commentModel != null) { if (commentModel != null) {
replyToId = commentModel.getId(); replyToId = commentModel.getId();
} }
mediaService.comment(postId, text.toString(), userId, replyToId, CookieUtils.getCsrfTokenFromCookie(cookie), new ServiceCallback<Boolean>() { mediaService.comment(postId, text.toString(), replyToId, new ServiceCallback<Boolean>() {
@Override @Override
public void onSuccess(final Boolean result) { public void onSuccess(final Boolean result) {
commentsAdapter.clearSelection(); commentsAdapter.clearSelection();
@ -171,7 +170,10 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl
public void onCreate(@Nullable final Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
fragmentActivity = (AppCompatActivity) getActivity(); fragmentActivity = (AppCompatActivity) getActivity();
mediaService = MediaService.getInstance(); final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID);
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie);
mediaService = MediaService.getInstance(deviceUuid, csrfToken, userIdFromCookie);
// setHasOptionsMenu(true); // setHasOptionsMenu(true);
} }
@ -231,7 +233,7 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl
final CommentsViewerFragmentArgs fragmentArgs = CommentsViewerFragmentArgs.fromBundle(getArguments()); final CommentsViewerFragmentArgs fragmentArgs = CommentsViewerFragmentArgs.fromBundle(getArguments());
shortCode = fragmentArgs.getShortCode(); shortCode = fragmentArgs.getShortCode();
postId = fragmentArgs.getPostId(); postId = fragmentArgs.getPostId();
userId = fragmentArgs.getPostUserId(); authorUserId = fragmentArgs.getPostUserId();
// setTitle(); // setTitle();
binding.swipeRefreshLayout.setOnRefreshListener(this); binding.swipeRefreshLayout.setOnRefreshListener(this);
binding.swipeRefreshLayout.setRefreshing(true); binding.swipeRefreshLayout.setRefreshing(true);
@ -289,10 +291,9 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl
String[] commentDialogList; String[] commentDialogList;
final long userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie);
if (!TextUtils.isEmpty(cookie) if (!TextUtils.isEmpty(cookie)
&& userIdFromCookie != 0 && userIdFromCookie != 0
&& (userIdFromCookie == commentModel.getProfileModel().getPk() || userIdFromCookie == userId)) { && (userIdFromCookie == commentModel.getProfileModel().getPk() || userIdFromCookie == authorUserId)) {
commentDialogList = new String[]{ commentDialogList = new String[]{
resources.getString(R.string.open_profile), resources.getString(R.string.open_profile),
resources.getString(R.string.comment_viewer_copy_comment), resources.getString(R.string.comment_viewer_copy_comment),
@ -324,7 +325,6 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl
if (context == null) return; if (context == null) return;
final DialogInterface.OnClickListener profileDialogListener = (dialog, which) -> { final DialogInterface.OnClickListener profileDialogListener = (dialog, which) -> {
final User profileModel = commentModel.getProfileModel(); final User profileModel = commentModel.getProfileModel();
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
switch (which) { switch (which) {
case 0: // open profile case 0: // open profile
openProfile("@" + profileModel.getUsername()); openProfile("@" + profileModel.getUsername());
@ -354,11 +354,8 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl
}, 200); }, 200);
break; break;
case 4: // like/unlike comment case 4: // like/unlike comment
if (csrfToken == null) {
return;
}
if (!commentModel.getLiked()) { if (!commentModel.getLiked()) {
mediaService.commentLike(commentModel.getId(), csrfToken, new ServiceCallback<Boolean>() { mediaService.commentLike(commentModel.getId(), new ServiceCallback<Boolean>() {
@Override @Override
public void onSuccess(final Boolean result) { public void onSuccess(final Boolean result) {
if (!result) { if (!result) {
@ -376,7 +373,7 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl
}); });
return; return;
} }
mediaService.commentUnlike(commentModel.getId(), csrfToken, new ServiceCallback<Boolean>() { mediaService.commentUnlike(commentModel.getId(), new ServiceCallback<Boolean>() {
@Override @Override
public void onSuccess(final Boolean result) { public void onSuccess(final Boolean result) {
if (!result) { if (!result) {
@ -416,10 +413,9 @@ public final class CommentsViewerFragment extends BottomSheetDialogFragment impl
}); });
break; break;
case 6: // delete comment case 6: // delete comment
final long userId = CookieUtils.getUserIdFromCookie(cookie); if (userIdFromCookie == 0) return;
if (userId == 0) return;
mediaService.deleteComment( mediaService.deleteComment(
postId, userId, commentModel.getId(), csrfToken, postId, commentModel.getId(),
new ServiceCallback<Boolean>() { new ServiceCallback<Boolean>() {
@Override @Override
public void onSuccess(final Boolean result) { public void onSuccess(final Boolean result) {

View File

@ -118,7 +118,7 @@ public final class FollowViewerFragment extends Fragment implements SwipeRefresh
@Override @Override
public void onCreate(@Nullable final Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
friendshipService = FriendshipService.getInstance(); friendshipService = FriendshipService.getInstance(null, null, 0);
fragmentActivity = (AppCompatActivity) getActivity(); fragmentActivity = (AppCompatActivity) getActivity();
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }

View File

@ -414,10 +414,11 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
hashtagDetailsBinding.btnFollowTag.setOnClickListener(v -> { hashtagDetailsBinding.btnFollowTag.setOnClickListener(v -> {
final String cookie = settingsHelper.getString(Constants.COOKIE); final String cookie = settingsHelper.getString(Constants.COOKIE);
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
final String ua = settingsHelper.getString(Constants.BROWSER_UA);
if (csrfToken != null) { if (csrfToken != null) {
hashtagDetailsBinding.btnFollowTag.setClickable(false); hashtagDetailsBinding.btnFollowTag.setClickable(false);
if (!hashtagModel.getFollowing()) { if (!hashtagModel.getFollowing()) {
tagsService.follow(hashtag.substring(1), csrfToken, new ServiceCallback<Boolean>() { tagsService.follow(ua, hashtag.substring(1), csrfToken, new ServiceCallback<Boolean>() {
@Override @Override
public void onSuccess(final Boolean result) { public void onSuccess(final Boolean result) {
hashtagDetailsBinding.btnFollowTag.setClickable(true); hashtagDetailsBinding.btnFollowTag.setClickable(true);
@ -445,7 +446,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
}); });
return; return;
} }
tagsService.unfollow(hashtag.substring(1), csrfToken, new ServiceCallback<Boolean>() { tagsService.unfollow(ua, hashtag.substring(1), csrfToken, new ServiceCallback<Boolean>() {
@Override @Override
public void onSuccess(final Boolean result) { public void onSuccess(final Boolean result) {
hashtagDetailsBinding.btnFollowTag.setClickable(true); hashtagDetailsBinding.btnFollowTag.setClickable(true);

View File

@ -104,7 +104,7 @@ public final class LikesViewerFragment extends BottomSheetDialogFragment impleme
final String cookie = settingsHelper.getString(Constants.COOKIE); final String cookie = settingsHelper.getString(Constants.COOKIE);
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0; isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
// final AppCompatActivity fragmentActivity = (AppCompatActivity) getActivity(); // final AppCompatActivity fragmentActivity = (AppCompatActivity) getActivity();
mediaService = isLoggedIn ? MediaService.getInstance() : null; mediaService = isLoggedIn ? MediaService.getInstance(null, null, 0) : null;
graphQLService = isLoggedIn ? null : GraphQLService.getInstance(); graphQLService = isLoggedIn ? null : GraphQLService.getInstance();
// setHasOptionsMenu(true); // setHasOptionsMenu(true);
} }

View File

@ -60,7 +60,6 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
private NotificationViewModel notificationViewModel; private NotificationViewModel notificationViewModel;
private FriendshipService friendshipService; private FriendshipService friendshipService;
private MediaService mediaService; private MediaService mediaService;
private long userId;
private String csrfToken; private String csrfToken;
private String type; private String type;
private Context context; private Context context;
@ -133,7 +132,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
break; break;
case 1: case 1:
if (model.getType() == NotificationType.REQUEST) { if (model.getType() == NotificationType.REQUEST) {
friendshipService.approve(userId, model.getUserId(), csrfToken, new ServiceCallback<FriendshipChangeResponse>() { friendshipService.approve(model.getUserId(), new ServiceCallback<FriendshipChangeResponse>() {
@Override @Override
public void onSuccess(final FriendshipChangeResponse result) { public void onSuccess(final FriendshipChangeResponse result) {
onRefresh(); onRefresh();
@ -175,7 +174,7 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
}); });
break; break;
case 2: case 2:
friendshipService.ignore(userId, model.getUserId(), csrfToken, new ServiceCallback<FriendshipChangeResponse>() { friendshipService.ignore(model.getUserId(), new ServiceCallback<FriendshipChangeResponse>() {
@Override @Override
public void onSuccess(final FriendshipChangeResponse result) { public void onSuccess(final FriendshipChangeResponse result) {
onRefresh(); onRefresh();
@ -218,10 +217,11 @@ public final class NotificationsViewerFragment extends Fragment implements Swipe
if (TextUtils.isEmpty(cookie)) { if (TextUtils.isEmpty(cookie)) {
Toast.makeText(context, R.string.activity_notloggedin, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.activity_notloggedin, Toast.LENGTH_SHORT).show();
} }
friendshipService = FriendshipService.getInstance(); mediaService = MediaService.getInstance(null, null, 0);
mediaService = MediaService.getInstance(); final long userId = CookieUtils.getUserIdFromCookie(cookie);
userId = CookieUtils.getUserIdFromCookie(cookie); final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID);
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, userId);
} }
@NonNull @NonNull

View File

@ -465,16 +465,16 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
binding.date.setVisibility(View.VISIBLE); binding.date.setVisibility(View.VISIBLE);
binding.date.setText(date); binding.date.setText(date);
})); }));
if (viewModel.getMedia().isCommentLikesEnabled()) { viewModel.getLikeCount().observe(getViewLifecycleOwner(), count -> {
viewModel.getLikeCount().observe(getViewLifecycleOwner(), count -> { final long safeCount = getSafeCount(count);
final long safeCount = getSafeCount(count); final String likesString = getResources().getQuantityString(R.plurals.likes_count, (int) safeCount, safeCount);
final String likesString = getResources().getQuantityString(R.plurals.likes_count, (int) safeCount, safeCount); binding.likesCount.setText(likesString);
binding.likesCount.setText(likesString); });
}); if (!viewModel.getMedia().isCommentsDisabled()) {
viewModel.getCommentCount().observe(getViewLifecycleOwner(), count -> { viewModel.getCommentCount().observe(getViewLifecycleOwner(), count -> {
final long safeCount = getSafeCount(count); final long safeCount = getSafeCount(count);
final String likesString = getResources().getQuantityString(R.plurals.comments_count, (int) safeCount, safeCount); final String likesString = getResources().getQuantityString(R.plurals.comments_count, (int) safeCount, safeCount);
binding.likesCount.setText(likesString); binding.commentsCount.setText(likesString);
}); });
} }
viewModel.getViewCount().observe(getViewLifecycleOwner(), count -> { viewModel.getViewCount().observe(getViewLifecycleOwner(), count -> {
@ -538,7 +538,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
} }
private void setupComment() { private void setupComment() {
if (!viewModel.hasPk() || !viewModel.getMedia().isCommentLikesEnabled()) { if (!viewModel.hasPk() || viewModel.getMedia().isCommentsDisabled()) {
binding.comment.setVisibility(View.GONE); binding.comment.setVisibility(View.GONE);
binding.commentsCount.setVisibility(View.GONE); binding.commentsCount.setVisibility(View.GONE);
return; return;
@ -577,7 +577,7 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
} }
private void setupLike() { private void setupLike() {
final boolean likableMedia = viewModel.hasPk() && viewModel.getMedia().isCommentLikesEnabled(); final boolean likableMedia = viewModel.hasPk() /*&& viewModel.getMedia().isCommentLikesEnabled()*/;
if (!likableMedia) { if (!likableMedia) {
binding.like.setVisibility(View.GONE); binding.like.setVisibility(View.GONE);
binding.likesCount.setVisibility(View.GONE); binding.likesCount.setVisibility(View.GONE);
@ -1402,20 +1402,24 @@ public class PostViewV2Fragment extends SharedElementTransitionDialogFragment im
if (media.getLocation() != null) { if (media.getLocation() != null) {
binding.location.setVisibility(View.VISIBLE); binding.location.setVisibility(View.VISIBLE);
} }
binding.captionParent.setVisibility(View.VISIBLE);
binding.bottomBg.setVisibility(View.VISIBLE); binding.bottomBg.setVisibility(View.VISIBLE);
binding.likesCount.setVisibility(View.VISIBLE); if (viewModel.hasPk()) {
binding.commentsCount.setVisibility(View.VISIBLE); binding.likesCount.setVisibility(View.VISIBLE);
binding.date.setVisibility(View.VISIBLE); binding.date.setVisibility(View.VISIBLE);
binding.captionToggle.setVisibility(View.VISIBLE); binding.captionParent.setVisibility(View.VISIBLE);
binding.captionToggle.setVisibility(View.VISIBLE);
binding.share.setVisibility(View.VISIBLE);
}
if (viewModel.hasPk() && !viewModel.getMedia().isCommentsDisabled()) {
binding.comment.setVisibility(View.VISIBLE);
binding.commentsCount.setVisibility(View.VISIBLE);
}
binding.download.setVisibility(View.VISIBLE); binding.download.setVisibility(View.VISIBLE);
binding.share.setVisibility(View.VISIBLE);
binding.comment.setVisibility(View.VISIBLE);
final List<Integer> options = viewModel.getOptions().getValue(); final List<Integer> options = viewModel.getOptions().getValue();
if (options != null && !options.isEmpty()) { if (options != null && !options.isEmpty()) {
binding.options.setVisibility(View.VISIBLE); binding.options.setVisibility(View.VISIBLE);
} }
if (viewModel.isLoggedIn()) { if (viewModel.isLoggedIn() && viewModel.hasPk()) {
binding.like.setVisibility(View.VISIBLE); binding.like.setVisibility(View.VISIBLE);
binding.save.setVisibility(View.VISIBLE); binding.save.setVisibility(View.VISIBLE);
} }

View File

@ -172,6 +172,21 @@ public class DirectMessageThreadFragment extends Fragment {
@Override @Override
public void onMediaClick(final Media media) { public void onMediaClick(final Media media) {
if (media.isReelMedia()) {
final String pk = media.getPk();
try {
final long mediaId = Long.parseLong(pk);
final User user = media.getUser();
if (user == null) return;
final String username = user.getUsername();
final NavDirections action = DirectMessageThreadFragmentDirections
.actionThreadToStory(StoryViewerOptions.forStory(mediaId, username));
NavHostFragment.findNavController(DirectMessageThreadFragment.this).navigate(action);
} catch (NumberFormatException e) {
Log.e(TAG, "onMediaClick (story): ", e);
}
return;
}
final PostViewV2Fragment.Builder builder = PostViewV2Fragment.builder(media); final PostViewV2Fragment.Builder builder = PostViewV2Fragment.builder(media);
builder.build().show(getChildFragmentManager(), "post_view"); builder.build().show(getChildFragmentManager(), "post_view");
} }

View File

@ -68,6 +68,7 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
private FragmentFeedBinding binding; private FragmentFeedBinding binding;
private StoriesService storiesService; private StoriesService storiesService;
private boolean shouldRefresh = true; private boolean shouldRefresh = true;
private final boolean isRotate = false;
private FeedStoriesViewModel feedStoriesViewModel; private FeedStoriesViewModel feedStoriesViewModel;
private boolean storiesFetching; private boolean storiesFetching;
private ActionMode actionMode; private ActionMode actionMode;
@ -282,6 +283,24 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
if (!shouldRefresh) return; if (!shouldRefresh) return;
binding.feedSwipeRefreshLayout.setOnRefreshListener(this); binding.feedSwipeRefreshLayout.setOnRefreshListener(this);
/*
FabAnimation.init(binding.fabCamera);
FabAnimation.init(binding.fabStory);
binding.fabAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
isRotate = FabAnimation.rotateFab(v, !isRotate);
if (isRotate) {
FabAnimation.showIn(binding.fabCamera);
FabAnimation.showIn(binding.fabStory);
}
else {
FabAnimation.showOut(binding.fabCamera);
FabAnimation.showOut(binding.fabStory);
}
}
});
*/
setupFeedStories(); setupFeedStories();
setupFeed(); setupFeed();
shouldRefresh = false; shouldRefresh = false;

View File

@ -99,7 +99,6 @@ import awais.instagrabber.webservices.StoriesService;
import static androidx.core.content.PermissionChecker.checkSelfPermission; import static androidx.core.content.PermissionChecker.checkSelfPermission;
import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG; import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG;
import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION; import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;
import static awais.instagrabber.utils.Utils.settingsHelper;
public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = "ProfileFragment"; private static final String TAG = "ProfileFragment";
@ -300,10 +299,15 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
@Override @Override
public void onCreate(@Nullable final Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
cookie = Utils.settingsHelper.getString(Constants.COOKIE);
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
final long userId = CookieUtils.getUserIdFromCookie(cookie);
final String deviceUuid = Utils.settingsHelper.getString(Constants.DEVICE_UUID);
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
fragmentActivity = (MainActivity) requireActivity(); fragmentActivity = (MainActivity) requireActivity();
friendshipService = FriendshipService.getInstance(); friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, userId);
storiesService = StoriesService.getInstance(); storiesService = StoriesService.getInstance();
mediaService = MediaService.getInstance(); mediaService = MediaService.getInstance(null, null, 0);
accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext())); accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext()));
favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext())); favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext()));
setHasOptionsMenu(true); setHasOptionsMenu(true);
@ -313,8 +317,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
public View onCreateView(@NonNull final LayoutInflater inflater, public View onCreateView(@NonNull final LayoutInflater inflater,
final ViewGroup container, final ViewGroup container,
final Bundle savedInstanceState) { final Bundle savedInstanceState) {
cookie = settingsHelper.getString(Constants.COOKIE);
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
if (root != null) { if (root != null) {
if (getArguments() != null) { if (getArguments() != null) {
final ProfileFragmentArgs fragmentArgs = ProfileFragmentArgs.fromBundle(getArguments()); final ProfileFragmentArgs fragmentArgs = ProfileFragmentArgs.fromBundle(getArguments());
@ -380,7 +382,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
friendshipService.toggleRestrict( friendshipService.toggleRestrict(
profileModel.getPk(), profileModel.getPk(),
!profileModel.getFriendshipStatus().isRestricted(), !profileModel.getFriendshipStatus().isRestricted(),
CookieUtils.getCsrfTokenFromCookie(cookie),
new ServiceCallback<FriendshipRestrictResponse>() { new ServiceCallback<FriendshipRestrictResponse>() {
@Override @Override
public void onSuccess(final FriendshipRestrictResponse result) { public void onSuccess(final FriendshipRestrictResponse result) {
@ -396,13 +397,10 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
return true; return true;
} }
if (item.getItemId() == R.id.block) { if (item.getItemId() == R.id.block) {
final long userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie);
if (!isLoggedIn) return false; if (!isLoggedIn) return false;
if (profileModel.getFriendshipStatus().isBlocking()) { if (profileModel.getFriendshipStatus().isBlocking()) {
friendshipService.unblock( friendshipService.unblock(
userIdFromCookie,
profileModel.getPk(), profileModel.getPk(),
CookieUtils.getCsrfTokenFromCookie(cookie),
new ServiceCallback<FriendshipChangeResponse>() { new ServiceCallback<FriendshipChangeResponse>() {
@Override @Override
public void onSuccess(final FriendshipChangeResponse result) { public void onSuccess(final FriendshipChangeResponse result) {
@ -418,9 +416,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
return true; return true;
} }
friendshipService.block( friendshipService.block(
userIdFromCookie,
profileModel.getPk(), profileModel.getPk(),
CookieUtils.getCsrfTokenFromCookie(cookie),
new ServiceCallback<FriendshipChangeResponse>() { new ServiceCallback<FriendshipChangeResponse>() {
@Override @Override
public void onSuccess(final FriendshipChangeResponse result) { public void onSuccess(final FriendshipChangeResponse result) {
@ -628,9 +624,9 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
), new RepositoryCallback<Void>() { ), new RepositoryCallback<Void>() {
@Override @Override
public void onSuccess(final Void result) { public void onSuccess(final Void result) {
profileDetailsBinding.favChip.setText(R.string.added_to_favs); profileDetailsBinding.favChip.setText(R.string.added_to_favs_short);
profileDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24); profileDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24);
showSnackbar(getString(R.string.added_to_favs)); showSnackbar(getString(R.string.added_to_favs_short));
} }
@Override @Override
@ -894,7 +890,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
private void setupCommonListeners() { private void setupCommonListeners() {
final Context context = getContext(); final Context context = getContext();
final long userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie);
profileDetailsBinding.btnFollow.setOnClickListener(v -> { profileDetailsBinding.btnFollow.setOnClickListener(v -> {
if (profileModel.getFriendshipStatus().isFollowing() && profileModel.isPrivate()) { if (profileModel.getFriendshipStatus().isFollowing() && profileModel.isPrivate()) {
new AlertDialog.Builder(context) new AlertDialog.Builder(context)
@ -902,9 +897,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
.setMessage(R.string.priv_acc_confirm) .setMessage(R.string.priv_acc_confirm)
.setPositiveButton(R.string.confirm, (d, w) -> .setPositiveButton(R.string.confirm, (d, w) ->
friendshipService.unfollow( friendshipService.unfollow(
userIdFromCookie,
profileModel.getPk(), profileModel.getPk(),
CookieUtils.getCsrfTokenFromCookie(cookie),
new ServiceCallback<FriendshipChangeResponse>() { new ServiceCallback<FriendshipChangeResponse>() {
@Override @Override
public void onSuccess(final FriendshipChangeResponse result) { public void onSuccess(final FriendshipChangeResponse result) {
@ -919,11 +912,10 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
})) }))
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.show(); .show();
} else if (profileModel.getFriendshipStatus().isFollowing() || profileModel.getFriendshipStatus().isOutgoingRequest()) { }
else if (profileModel.getFriendshipStatus().isFollowing() || profileModel.getFriendshipStatus().isOutgoingRequest()) {
friendshipService.unfollow( friendshipService.unfollow(
userIdFromCookie,
profileModel.getPk(), profileModel.getPk(),
CookieUtils.getCsrfTokenFromCookie(cookie),
new ServiceCallback<FriendshipChangeResponse>() { new ServiceCallback<FriendshipChangeResponse>() {
@Override @Override
public void onSuccess(final FriendshipChangeResponse result) { public void onSuccess(final FriendshipChangeResponse result) {
@ -938,9 +930,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
}); });
} else { } else {
friendshipService.follow( friendshipService.follow(
userIdFromCookie,
profileModel.getPk(), profileModel.getPk(),
CookieUtils.getCsrfTokenFromCookie(cookie),
new ServiceCallback<FriendshipChangeResponse>() { new ServiceCallback<FriendshipChangeResponse>() {
@Override @Override
public void onSuccess(final FriendshipChangeResponse result) { public void onSuccess(final FriendshipChangeResponse result) {
@ -1102,6 +1092,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
private boolean isReallyPrivate() { private boolean isReallyPrivate() {
final long myId = CookieUtils.getUserIdFromCookie(cookie); final long myId = CookieUtils.getUserIdFromCookie(cookie);
final FriendshipStatus friendshipStatus = profileModel.getFriendshipStatus(); final FriendshipStatus friendshipStatus = profileModel.getFriendshipStatus();
return !friendshipStatus.isFollowedBy() && (profileModel.getPk() != myId) && profileModel.isPrivate(); return !friendshipStatus.isFollowing() && (profileModel.getPk() != myId) && profileModel.isPrivate();
} }
} }

View File

@ -8,7 +8,6 @@ import retrofit2.Call;
import retrofit2.http.FieldMap; import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded; import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET; import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.POST; import retrofit2.http.POST;
import retrofit2.http.Path; import retrofit2.http.Path;
import retrofit2.http.QueryMap; import retrofit2.http.QueryMap;
@ -17,20 +16,17 @@ public interface FriendshipRepository {
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/friendships/{action}/{id}/") @POST("/api/v1/friendships/{action}/{id}/")
Call<FriendshipChangeResponse> change(@Header("User-Agent") String userAgent, Call<FriendshipChangeResponse> change(@Path("action") String action,
@Path("action") String action,
@Path("id") long id, @Path("id") long id,
@FieldMap Map<String, String> form); @FieldMap Map<String, String> form);
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/restrict_action/{action}/") @POST("/api/v1/restrict_action/{action}/")
Call<FriendshipRestrictResponse> toggleRestrict(@Header("User-Agent") String userAgent, Call<FriendshipRestrictResponse> toggleRestrict(@Path("action") String action,
@Path("action") String action,
@FieldMap Map<String, String> form); @FieldMap Map<String, String> form);
@GET("/api/v1/friendships/{userId}/{type}/") @GET("/api/v1/friendships/{userId}/{type}/")
Call<String> getList(@Header("User-Agent") String userAgent, Call<String> getList(@Path("userId") long userId,
@Path("userId") long userId,
@Path("type") String type, // following or followers @Path("type") String type, // following or followers
@QueryMap(encoded = true) Map<String, String> queryParams); @QueryMap(encoded = true) Map<String, String> queryParams);
} }

View File

@ -2,28 +2,23 @@ package awais.instagrabber.repositories;
import java.util.Map; import java.util.Map;
import awais.instagrabber.utils.Constants;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.http.FieldMap; import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded; import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET; import retrofit2.http.GET;
import retrofit2.http.Header; import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.POST; import retrofit2.http.POST;
import retrofit2.http.Query; import retrofit2.http.Query;
public interface NewsRepository { public interface NewsRepository {
@Headers("User-Agent: " + Constants.USER_AGENT)
@GET("https://www.instagram.com/accounts/activity/?__a=1") @GET("https://www.instagram.com/accounts/activity/?__a=1")
Call<String> webInbox(); Call<String> webInbox(@Header("User-Agent") String userAgent);
@Headers("User-Agent: " + Constants.I_USER_AGENT)
@GET("/api/v1/news/inbox/") @GET("/api/v1/news/inbox/")
Call<String> appInbox(@Query(value = "mark_as_seen", encoded = true) boolean markAsSeen); Call<String> appInbox(@Header("User-Agent") String userAgent, @Query(value = "mark_as_seen", encoded = true) boolean markAsSeen);
@FormUrlEncoded @FormUrlEncoded
@Headers("User-Agent: " + Constants.I_USER_AGENT)
@POST("/api/v1/discover/ayml/") @POST("/api/v1/discover/ayml/")
Call<String> getAyml(@FieldMap final Map<String, String> form); Call<String> getAyml(@Header("User-Agent") String userAgent, @FieldMap final Map<String, String> form);
} }

View File

@ -7,7 +7,6 @@ import retrofit2.Call;
import retrofit2.http.FieldMap; import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded; import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET; import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.POST; import retrofit2.http.POST;
import retrofit2.http.Path; import retrofit2.http.Path;
import retrofit2.http.QueryMap; import retrofit2.http.QueryMap;
@ -28,12 +27,11 @@ public interface StoriesRepository {
Call<String> fetchArchive(@QueryMap Map<String, String> queryParams); Call<String> fetchArchive(@QueryMap Map<String, String> queryParams);
@GET @GET
Call<String> getUserStory(@Header("User-Agent") String userAgent, @Url String url); Call<String> getUserStory(@Url String url);
@FormUrlEncoded @FormUrlEncoded
@POST("/api/v1/media/{storyId}/{stickerId}/{action}/") @POST("/api/v1/media/{storyId}/{stickerId}/{action}/")
Call<StoryStickerResponse> respondToSticker(@Header("User-Agent") String userAgent, Call<StoryStickerResponse> respondToSticker(@Path("storyId") String storyId,
@Path("storyId") String storyId,
@Path("stickerId") String stickerId, @Path("stickerId") String stickerId,
@Path("action") String action, @Path("action") String action,
// story_poll_vote, story_question_response, story_slider_vote, story_quiz_answer // story_poll_vote, story_question_response, story_slider_vote, story_quiz_answer

View File

@ -19,6 +19,7 @@ public class Media implements Serializable {
private final MediaItemType mediaType; private final MediaItemType mediaType;
private final boolean canViewerReshare; private final boolean canViewerReshare;
private final boolean commentLikesEnabled; private final boolean commentLikesEnabled;
private final boolean commentsDisabled;
private final long nextMaxId; private final long nextMaxId;
private final long commentCount; private final long commentCount;
private final ImageVersions2 imageVersions2; private final ImageVersions2 imageVersions2;
@ -56,6 +57,7 @@ public class Media implements Serializable {
final int originalHeight, final int originalHeight,
final MediaItemType mediaType, final MediaItemType mediaType,
final boolean commentLikesEnabled, final boolean commentLikesEnabled,
final boolean commentsDisabled,
final long nextMaxId, final long nextMaxId,
final long commentCount, final long commentCount,
final long likeCount, final long likeCount,
@ -87,6 +89,7 @@ public class Media implements Serializable {
this.originalHeight = originalHeight; this.originalHeight = originalHeight;
this.mediaType = mediaType; this.mediaType = mediaType;
this.commentLikesEnabled = commentLikesEnabled; this.commentLikesEnabled = commentLikesEnabled;
this.commentsDisabled = commentsDisabled;
this.nextMaxId = nextMaxId; this.nextMaxId = nextMaxId;
this.commentCount = commentCount; this.commentCount = commentCount;
this.likeCount = likeCount; this.likeCount = likeCount;
@ -182,6 +185,10 @@ public class Media implements Serializable {
return commentLikesEnabled; return commentLikesEnabled;
} }
public boolean isCommentsDisabled() {
return commentsDisabled;
}
public long getNextMaxId() { public long getNextMaxId() {
return nextMaxId; return nextMaxId;
} }

View File

@ -9,8 +9,10 @@ public final class Constants {
public static final String APP_THEME = "app_theme_v19"; public static final String APP_THEME = "app_theme_v19";
public static final String APP_LANGUAGE = "app_language_v19"; public static final String APP_LANGUAGE = "app_language_v19";
public static final String STORY_SORT = "story_sort"; public static final String STORY_SORT = "story_sort";
// int prefs // int prefs, do not export
public static final String PREV_INSTALL_VERSION = "prevVersion"; public static final String PREV_INSTALL_VERSION = "prevVersion";
public static final String BROWSER_UA_CODE = "browser_ua_code";
public static final String APP_UA_CODE = "app_ua_code";
// boolean prefs // boolean prefs
public static final String DOWNLOAD_USER_FOLDER = "download_user_folder"; public static final String DOWNLOAD_USER_FOLDER = "download_user_folder";
// deprecated: public static final String BOTTOM_TOOLBAR = "bottom_toolbar"; // deprecated: public static final String BOTTOM_TOOLBAR = "bottom_toolbar";
@ -31,6 +33,8 @@ public final class Constants {
public static final String COOKIE = "cookie"; public static final String COOKIE = "cookie";
public static final String SHOW_QUICK_ACCESS_DIALOG = "show_quick_dlg"; public static final String SHOW_QUICK_ACCESS_DIALOG = "show_quick_dlg";
public static final String DEVICE_UUID = "device_uuid"; public static final String DEVICE_UUID = "device_uuid";
public static final String BROWSER_UA = "browser_ua";
public static final String APP_UA = "app_ua";
//////////////////////// EXTRAS //////////////////////// //////////////////////// EXTRAS ////////////////////////
public static final String EXTRAS_USER = "user"; public static final String EXTRAS_USER = "user";
public static final String EXTRAS_HASHTAG = "hashtag"; public static final String EXTRAS_HASHTAG = "hashtag";
@ -54,13 +58,6 @@ public final class Constants {
// Notification ids // Notification ids
public static final int ACTIVITY_NOTIFICATION_ID = 10; public static final int ACTIVITY_NOTIFICATION_ID = 10;
// spoof
public static final String USER_AGENT = "Mozilla/5.0 (Linux; Android 8.1.0; motorola one Build/OPKS28.63-18-3; wv) " +
"AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/70.0.3538.80 Mobile Safari/537.36 " +
"Instagram 169.1.0.29.135 Android (27/8.1.0; 320dpi; 720x1362; motorola; motorola one; deen_sprout; qcom; pt_BR; 262886998)";
public static final String I_USER_AGENT =
"Instagram 169.1.0.29.135 Android (27/8.1.0; 320dpi; 720x1362; motorola; motorola one; deen_sprout; qcom; pt_BR; 262886998)";
public static final String A_USER_AGENT = "https://Barinsta.AustinHuang.me / mailto:Barinsta@AustinHuang.me";
// see https://github.com/dilame/instagram-private-api/blob/master/src/core/constants.ts // see https://github.com/dilame/instagram-private-api/blob/master/src/core/constants.ts
public static final String SUPPORTED_CAPABILITIES = "[ { \"name\": \"SUPPORTED_SDK_VERSIONS\", \"value\":" + public static final String SUPPORTED_CAPABILITIES = "[ { \"name\": \"SUPPORTED_SDK_VERSIONS\", \"value\":" +
" \"13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0,28.0,29.0,30.0,31.0," + " \"13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0,28.0,29.0,30.0,31.0," +

View File

@ -81,6 +81,7 @@ public class DirectItemFactory {
height, height,
isVideo ? MediaItemType.MEDIA_TYPE_VIDEO : MediaItemType.MEDIA_TYPE_IMAGE, isVideo ? MediaItemType.MEDIA_TYPE_VIDEO : MediaItemType.MEDIA_TYPE_IMAGE,
false, false,
false,
-1, -1,
-1, -1,
-1, -1,
@ -156,6 +157,7 @@ public class DirectItemFactory {
0, 0,
MediaItemType.MEDIA_TYPE_VOICE, MediaItemType.MEDIA_TYPE_VOICE,
false, false,
false,
-1, -1,
0, 0,
0, 0,

View File

@ -343,6 +343,10 @@ public final class ExportImportUtils {
jsonObject.remove(Constants.COOKIE); jsonObject.remove(Constants.COOKIE);
jsonObject.remove(Constants.DEVICE_UUID); jsonObject.remove(Constants.DEVICE_UUID);
jsonObject.remove(Constants.PREV_INSTALL_VERSION); jsonObject.remove(Constants.PREV_INSTALL_VERSION);
jsonObject.remove(Constants.BROWSER_UA_CODE);
jsonObject.remove(Constants.BROWSER_UA);
jsonObject.remove(Constants.APP_UA_CODE);
jsonObject.remove(Constants.APP_UA);
return jsonObject; return jsonObject;
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Error exporting settings", e); Log.e(TAG, "Error exporting settings", e);

View File

@ -102,6 +102,14 @@ public final class FlavorTown {
public static void changelogCheck(@NonNull final Context context) { public static void changelogCheck(@NonNull final Context context) {
if (settingsHelper.getInteger(Constants.PREV_INSTALL_VERSION) < BuildConfig.VERSION_CODE) { if (settingsHelper.getInteger(Constants.PREV_INSTALL_VERSION) < BuildConfig.VERSION_CODE) {
final String langCode = settingsHelper.getString(Constants.APP_LANGUAGE);
final String lang = LocaleUtils.getCorrespondingLanguageCode(langCode);
final int appUaCode = settingsHelper.getInteger(Constants.APP_UA_CODE);
final String appUa = UserAgentUtils.generateAppUA(appUaCode, lang);
settingsHelper.putString(Constants.APP_UA, appUa);
final int browserUaCode = settingsHelper.getInteger(Constants.BROWSER_UA_CODE);
final String browserUa = UserAgentUtils.generateBrowserUA(browserUaCode);
settingsHelper.putString(Constants.BROWSER_UA, browserUa);
Toast.makeText(context, R.string.updated, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.updated, Toast.LENGTH_SHORT).show();
settingsHelper.putInteger(Constants.PREV_INSTALL_VERSION, BuildConfig.VERSION_CODE); settingsHelper.putInteger(Constants.PREV_INSTALL_VERSION, BuildConfig.VERSION_CODE);
} }

View File

@ -19,7 +19,11 @@ public final class LocaleUtils {
if (baseContext instanceof ContextThemeWrapper) if (baseContext instanceof ContextThemeWrapper)
baseContext = ((ContextThemeWrapper) baseContext).getBaseContext(); baseContext = ((ContextThemeWrapper) baseContext).getBaseContext();
final String lang = LocaleUtils.getCorrespondingLanguageCode(baseContext); if (Utils.settingsHelper == null)
Utils.settingsHelper = new SettingsHelper(baseContext);
final String appLanguageSettings = Utils.settingsHelper.getString(Constants.APP_LANGUAGE);
final String lang = TextUtils.isEmpty(appLanguageSettings) ? null : LocaleUtils.getCorrespondingLanguageCode(appLanguageSettings);
currentLocale = TextUtils.isEmpty(lang) ? defaultLocale : currentLocale = TextUtils.isEmpty(lang) ? defaultLocale :
(lang.contains("_") ? new Locale(lang.split("_")[0], lang.split("_")[1]) : new Locale(lang)); (lang.contains("_") ? new Locale(lang.split("_")[0], lang.split("_")[1]) : new Locale(lang));
@ -49,13 +53,7 @@ public final class LocaleUtils {
} }
@Nullable @Nullable
private static String getCorrespondingLanguageCode(final Context baseContext) { public static String getCorrespondingLanguageCode(final String appLanguageSettings) {
if (Utils.settingsHelper == null)
Utils.settingsHelper = new SettingsHelper(baseContext);
final String appLanguageSettings = Utils.settingsHelper.getString(Constants.APP_LANGUAGE);
if (TextUtils.isEmpty(appLanguageSettings)) return null;
final int appLanguageIndex = Integer.parseInt(appLanguageSettings); final int appLanguageIndex = Integer.parseInt(appLanguageSettings);
if (appLanguageIndex == 1) return "en"; if (appLanguageIndex == 1) return "en";
if (appLanguageIndex == 2) return "fr"; if (appLanguageIndex == 2) return "fr";

View File

@ -857,6 +857,7 @@ public final class ResponseBodyUtils {
height, height,
mediaItemType, mediaItemType,
false, false,
feedItem.optBoolean("comments_disabled"),
-1, -1,
commentsCount, commentsCount,
likesCount, likesCount,

View File

@ -10,7 +10,11 @@ import androidx.appcompat.app.AppCompatDelegate;
import static awais.instagrabber.utils.Constants.APP_LANGUAGE; import static awais.instagrabber.utils.Constants.APP_LANGUAGE;
import static awais.instagrabber.utils.Constants.APP_THEME; import static awais.instagrabber.utils.Constants.APP_THEME;
import static awais.instagrabber.utils.Constants.APP_UA;
import static awais.instagrabber.utils.Constants.APP_UA_CODE;
import static awais.instagrabber.utils.Constants.AUTOPLAY_VIDEOS; import static awais.instagrabber.utils.Constants.AUTOPLAY_VIDEOS;
import static awais.instagrabber.utils.Constants.BROWSER_UA;
import static awais.instagrabber.utils.Constants.BROWSER_UA_CODE;
import static awais.instagrabber.utils.Constants.CHECK_ACTIVITY; import static awais.instagrabber.utils.Constants.CHECK_ACTIVITY;
import static awais.instagrabber.utils.Constants.CHECK_UPDATES; import static awais.instagrabber.utils.Constants.CHECK_UPDATES;
import static awais.instagrabber.utils.Constants.COOKIE; import static awais.instagrabber.utils.Constants.COOKIE;
@ -80,7 +84,7 @@ public final class SettingsHelper {
private int getIntegerDefault(@IntegerSettings final String key) { private int getIntegerDefault(@IntegerSettings final String key) {
if (APP_THEME.equals(key)) return getThemeCode(true); if (APP_THEME.equals(key)) return getThemeCode(true);
if (PREV_INSTALL_VERSION.equals(key)) return -1; if (PREV_INSTALL_VERSION.equals(key) || APP_UA_CODE.equals(key) || BROWSER_UA_CODE.equals(key)) return -1;
return 0; return 0;
} }
@ -121,10 +125,11 @@ public final class SettingsHelper {
} }
@StringDef( @StringDef(
{APP_LANGUAGE, APP_THEME, COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION, CUSTOM_DATE_TIME_FORMAT, {APP_LANGUAGE, APP_THEME, APP_UA, BROWSER_UA, COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION,
DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME, PREF_POSTS_LAYOUT, CUSTOM_DATE_TIME_FORMAT, DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME,
PREF_PROFILE_POSTS_LAYOUT, PREF_TOPIC_POSTS_LAYOUT, PREF_HASHTAG_POSTS_LAYOUT, PREF_LOCATION_POSTS_LAYOUT, PREF_POSTS_LAYOUT, PREF_PROFILE_POSTS_LAYOUT, PREF_TOPIC_POSTS_LAYOUT, PREF_HASHTAG_POSTS_LAYOUT,
PREF_LIKED_POSTS_LAYOUT, PREF_TAGGED_POSTS_LAYOUT, PREF_SAVED_POSTS_LAYOUT, STORY_SORT, PREF_EMOJI_VARIANTS, PREF_REACTIONS}) PREF_LOCATION_POSTS_LAYOUT, PREF_LIKED_POSTS_LAYOUT, PREF_TAGGED_POSTS_LAYOUT, PREF_SAVED_POSTS_LAYOUT,
STORY_SORT, PREF_EMOJI_VARIANTS, PREF_REACTIONS})
public @interface StringSettings {} public @interface StringSettings {}
@StringDef({DOWNLOAD_USER_FOLDER, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS, @StringDef({DOWNLOAD_USER_FOLDER, FOLDER_SAVE_TO, AUTOPLAY_VIDEOS, SHOW_QUICK_ACCESS_DIALOG, MUTED_VIDEOS,
@ -132,6 +137,6 @@ public final class SettingsHelper {
CHECK_UPDATES, SWAP_DATE_TIME_FORMAT_ENABLED}) CHECK_UPDATES, SWAP_DATE_TIME_FORMAT_ENABLED})
public @interface BooleanSettings {} public @interface BooleanSettings {}
@StringDef({PREV_INSTALL_VERSION}) @StringDef({PREV_INSTALL_VERSION, BROWSER_UA_CODE, APP_UA_CODE})
public @interface IntegerSettings {} public @interface IntegerSettings {}
} }

View File

@ -30,7 +30,7 @@ public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
HttpURLConnection conn = HttpURLConnection conn =
(HttpURLConnection) new URL("https://f-droid.org/api/v1/packages/me.austinhuang.instagrabber").openConnection(); (HttpURLConnection) new URL("https://f-droid.org/api/v1/packages/me.austinhuang.instagrabber").openConnection();
conn.setUseCaches(false); conn.setUseCaches(false);
conn.setRequestProperty("User-Agent", Constants.A_USER_AGENT); conn.setRequestProperty("User-Agent", "https://Barinsta.AustinHuang.me / mailto:Barinsta@AustinHuang.me");
conn.connect(); conn.connect();
final int responseCode = conn.getResponseCode(); final int responseCode = conn.getResponseCode();

View File

@ -0,0 +1,77 @@
package awais.instagrabber.utils;
import androidx.annotation.NonNull;
public class UserAgentUtils {
/* GraphQL user agents (which are just standard browser UA's).
* Go to https://www.whatismybrowser.com/guides/the-latest-user-agent/ to update it
* Windows first (Assume win64 not wow64): Chrome, Firefox, Edge
* Then macOS: Chrome, Firefox, Safari
*/
public static final String[] browsers = {
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36 Edg/87.0.664.75",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11.1; rv:84.0) Gecko/20100101 Firefox/84.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15"
};
// use APKpure, assume x86
private static final String igVersion = "169.3.0.30.135";
private static final String igVersionCode = "264009054";
// https://github.com/dilame/instagram-private-api/blob/master/src/samples/devices.json
// presumed constant, so no need to update
public static final String[] devices = {
"25/7.1.1; 440dpi; 1080x1920; Xiaomi; Mi Note 3; jason; qcom",
"23/6.0.1; 480dpi; 1080x1920; Xiaomi; Redmi Note 3; kenzo; qcom",
"23/6.0; 480dpi; 1080x1920; Xiaomi; Redmi Note 4; nikel; mt6797",
"24/7.0; 480dpi; 1080x1920; Xiaomi/xiaomi; Redmi Note 4; mido; qcom",
"23/6.0; 480dpi; 1080x1920; Xiaomi; Redmi Note 4X; nikel; mt6797",
"27/8.1.0; 440dpi; 1080x2030; Xiaomi/xiaomi; Redmi Note 5; whyred; qcom",
"23/6.0.1; 480dpi; 1080x1920; Xiaomi; Redmi 4; markw; qcom",
"27/8.1.0; 440dpi; 1080x2030; Xiaomi/xiaomi; Redmi 5 Plus; vince; qcom",
"25/7.1.2; 440dpi; 1080x2030; Xiaomi/xiaomi; Redmi 5 Plus; vince; qcom",
"26/8.0.0; 480dpi; 1080x1920; Xiaomi; MI 5; gemini; qcom",
"27/8.1.0; 480dpi; 1080x1920; Xiaomi/xiaomi; Mi A1; tissot_sprout; qcom",
"26/8.0.0; 480dpi; 1080x1920; Xiaomi; MI 6; sagit; qcom",
"25/7.1.1; 440dpi; 1080x1920; Xiaomi; MI MAX 2; oxygen; qcom",
"24/7.0; 480dpi; 1080x1920; Xiaomi; MI 5s; capricorn; qcom",
"26/8.0.0; 480dpi; 1080x1920; samsung; SM-A520F; a5y17lte; samsungexynos7880",
"26/8.0.0; 480dpi; 1080x2076; samsung; SM-G950F; dreamlte; samsungexynos8895",
"26/8.0.0; 640dpi; 1440x2768; samsung; SM-G950F; dreamlte; samsungexynos8895",
"26/8.0.0; 420dpi; 1080x2094; samsung; SM-G955F; dream2lte; samsungexynos8895",
"26/8.0.0; 560dpi; 1440x2792; samsung; SM-G955F; dream2lte; samsungexynos8895",
"24/7.0; 480dpi; 1080x1920; samsung; SM-A510F; a5xelte; samsungexynos7580",
"26/8.0.0; 480dpi; 1080x1920; samsung; SM-G930F; herolte; samsungexynos8890",
"26/8.0.0; 480dpi; 1080x1920; samsung; SM-G935F; hero2lte; samsungexynos8890",
"26/8.0.0; 420dpi; 1080x2094; samsung; SM-G965F; star2lte; samsungexynos9810",
"26/8.0.0; 480dpi; 1080x2076; samsung; SM-A530F; jackpotlte; samsungexynos7885",
"24/7.0; 640dpi; 1440x2560; samsung; SM-G925F; zerolte; samsungexynos7420",
"26/8.0.0; 420dpi; 1080x1920; samsung; SM-A720F; a7y17lte; samsungexynos7880",
"24/7.0; 640dpi; 1440x2560; samsung; SM-G920F; zeroflte; samsungexynos7420",
"24/7.0; 420dpi; 1080x1920; samsung; SM-J730FM; j7y17lte; samsungexynos7870",
"26/8.0.0; 480dpi; 1080x2076; samsung; SM-G960F; starlte; samsungexynos9810",
"26/8.0.0; 420dpi; 1080x2094; samsung; SM-N950F; greatlte; samsungexynos8895",
"26/8.0.0; 420dpi; 1080x2094; samsung; SM-A730F; jackpot2lte; samsungexynos7885",
"26/8.0.0; 420dpi; 1080x2094; samsung; SM-A605FN; a6plte; qcom",
"26/8.0.0; 480dpi; 1080x1920; HUAWEI/HONOR; STF-L09; HWSTF; hi3660",
"27/8.1.0; 480dpi; 1080x2280; HUAWEI/HONOR; COL-L29; HWCOL; kirin970",
"26/8.0.0; 480dpi; 1080x2032; HUAWEI/HONOR; LLD-L31; HWLLD-H; hi6250",
"26/8.0.0; 480dpi; 1080x2150; HUAWEI; ANE-LX1; HWANE; hi6250",
"26/8.0.0; 480dpi; 1080x2032; HUAWEI; FIG-LX1; HWFIG-H; hi6250",
"27/8.1.0; 480dpi; 1080x2150; HUAWEI/HONOR; COL-L29; HWCOL; kirin970",
"26/8.0.0; 480dpi; 1080x2038; HUAWEI/HONOR; BND-L21; HWBND-H; hi6250",
"23/6.0.1; 420dpi; 1080x1920; LeMobile/LeEco; Le X527; le_s2_ww; qcom"
};
@NonNull
public static String generateBrowserUA(final int code) {
return browsers[code - 1];
}
@NonNull
public static String generateAppUA(final int code, final String lang) {
return "Instagram " + igVersion + " Android (" + devices[code] + "; " + lang + "; " + igVersionCode + ")";
}
}

View File

@ -79,7 +79,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
throw new IllegalArgumentException("User is not logged in!"); throw new IllegalArgumentException("User is not logged in!");
} }
directMessagesService = DirectMessagesService.getInstance(csrfToken, userId, deviceUuid); directMessagesService = DirectMessagesService.getInstance(csrfToken, userId, deviceUuid);
friendshipService = FriendshipService.getInstance(); friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, userId);
resources = getApplication().getResources(); resources = getApplication().getResources();
} }
@ -264,7 +264,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
private LiveData<Resource<Object>> blockUser(final User user) { private LiveData<Resource<Object>> blockUser(final User user) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
friendshipService.block(userId, user.getPk(), csrfToken, new ServiceCallback<FriendshipChangeResponse>() { friendshipService.block(user.getPk(), new ServiceCallback<FriendshipChangeResponse>() {
@Override @Override
public void onSuccess(final FriendshipChangeResponse result) { public void onSuccess(final FriendshipChangeResponse result) {
// refresh thread // refresh thread
@ -281,7 +281,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
private LiveData<Resource<Object>> unblockUser(final User user) { private LiveData<Resource<Object>> unblockUser(final User user) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
friendshipService.unblock(userId, user.getPk(), csrfToken, new ServiceCallback<FriendshipChangeResponse>() { friendshipService.unblock(user.getPk(), new ServiceCallback<FriendshipChangeResponse>() {
@Override @Override
public void onSuccess(final FriendshipChangeResponse result) { public void onSuccess(final FriendshipChangeResponse result) {
// refresh thread // refresh thread
@ -298,7 +298,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
private LiveData<Resource<Object>> restrictUser(final User user) { private LiveData<Resource<Object>> restrictUser(final User user) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
friendshipService.toggleRestrict(user.getPk(), true, csrfToken, new ServiceCallback<FriendshipRestrictResponse>() { friendshipService.toggleRestrict(user.getPk(), true, new ServiceCallback<FriendshipRestrictResponse>() {
@Override @Override
public void onSuccess(final FriendshipRestrictResponse result) { public void onSuccess(final FriendshipRestrictResponse result) {
// refresh thread // refresh thread
@ -315,7 +315,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
private LiveData<Resource<Object>> unRestrictUser(final User user) { private LiveData<Resource<Object>> unRestrictUser(final User user) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
friendshipService.toggleRestrict(user.getPk(), false, csrfToken, new ServiceCallback<FriendshipRestrictResponse>() { friendshipService.toggleRestrict(user.getPk(), false, new ServiceCallback<FriendshipRestrictResponse>() {
@Override @Override
public void onSuccess(final FriendshipRestrictResponse result) { public void onSuccess(final FriendshipRestrictResponse result) {
// refresh thread // refresh thread

View File

@ -103,7 +103,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
throw new IllegalArgumentException("User is not logged in!"); throw new IllegalArgumentException("User is not logged in!");
} }
service = DirectMessagesService.getInstance(csrfToken, userId, deviceUuid); service = DirectMessagesService.getInstance(csrfToken, userId, deviceUuid);
mediaService = MediaService.getInstance(); mediaService = MediaService.getInstance(deviceUuid, csrfToken, userId);
contentResolver = application.getContentResolver(); contentResolver = application.getContentResolver();
recordingsDir = DirectoryUtils.getOutputMediaDirectory(application, "Recordings"); recordingsDir = DirectoryUtils.getOutputMediaDirectory(application, "Recordings");
this.application = application; this.application = application;
@ -467,7 +467,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
.setUploadId(uploadDmVideoOptions.getUploadId()) .setUploadId(uploadDmVideoOptions.getUploadId())
.setSourceType("2") .setSourceType("2")
.setVideoOptions(new UploadFinishOptions.VideoOptions().setLength(duration / 1000f)); .setVideoOptions(new UploadFinishOptions.VideoOptions().setLength(duration / 1000f));
final Call<String> uploadFinishRequest = mediaService.uploadFinish(userId, csrfToken, uploadFinishOptions); final Call<String> uploadFinishRequest = mediaService.uploadFinish(uploadFinishOptions);
uploadFinishRequest.enqueue(new Callback<String>() { uploadFinishRequest.enqueue(new Callback<String>() {
@Override @Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
@ -584,7 +584,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
final UploadFinishOptions uploadFinishOptions = new UploadFinishOptions() final UploadFinishOptions uploadFinishOptions = new UploadFinishOptions()
.setUploadId(uploadDmVoiceOptions.getUploadId()) .setUploadId(uploadDmVoiceOptions.getUploadId())
.setSourceType("4"); .setSourceType("4");
final Call<String> uploadFinishRequest = mediaService.uploadFinish(userId, csrfToken, uploadFinishOptions); final Call<String> uploadFinishRequest = mediaService.uploadFinish(uploadFinishOptions);
uploadFinishRequest.enqueue(new Callback<String>() { uploadFinishRequest.enqueue(new Callback<String>() {
@Override @Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {

View File

@ -43,16 +43,16 @@ public class PostViewV2ViewModel extends ViewModel {
private final MutableLiveData<List<Integer>> options = new MutableLiveData<>(new ArrayList<>()); private final MutableLiveData<List<Integer>> options = new MutableLiveData<>(new ArrayList<>());
private final MediaService mediaService; private final MediaService mediaService;
private final long viewerId; private final long viewerId;
private final String csrfToken;
private final boolean isLoggedIn; private final boolean isLoggedIn;
private Media media; private Media media;
public PostViewV2ViewModel() { public PostViewV2ViewModel() {
mediaService = MediaService.getInstance();
final String cookie = settingsHelper.getString(Constants.COOKIE); final String cookie = settingsHelper.getString(Constants.COOKIE);
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
viewerId = CookieUtils.getUserIdFromCookie(cookie); viewerId = CookieUtils.getUserIdFromCookie(cookie);
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); mediaService = MediaService.getInstance(deviceUuid, csrfToken, viewerId);
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0; isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
} }
@ -142,14 +142,14 @@ public class PostViewV2ViewModel extends ViewModel {
public LiveData<Resource<Object>> like() { public LiveData<Resource<Object>> like() {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.loading(null)); data.postValue(Resource.loading(null));
mediaService.like(media.getPk(), viewerId, csrfToken, getLikeUnlikeCallback(data)); mediaService.like(media.getPk(), getLikeUnlikeCallback(data));
return data; return data;
} }
public LiveData<Resource<Object>> unlike() { public LiveData<Resource<Object>> unlike() {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.loading(null)); data.postValue(Resource.loading(null));
mediaService.unlike(media.getPk(), viewerId, csrfToken, getLikeUnlikeCallback(data)); mediaService.unlike(media.getPk(), getLikeUnlikeCallback(data));
return data; return data;
} }
@ -196,14 +196,14 @@ public class PostViewV2ViewModel extends ViewModel {
public LiveData<Resource<Object>> save() { public LiveData<Resource<Object>> save() {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.loading(null)); data.postValue(Resource.loading(null));
mediaService.save(media.getPk(), viewerId, csrfToken, getSaveUnsaveCallback(data)); mediaService.save(media.getPk(), getSaveUnsaveCallback(data));
return data; return data;
} }
public LiveData<Resource<Object>> unsave() { public LiveData<Resource<Object>> unsave() {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.loading(null)); data.postValue(Resource.loading(null));
mediaService.unsave(media.getPk(), viewerId, csrfToken, getSaveUnsaveCallback(data)); mediaService.unsave(media.getPk(), getSaveUnsaveCallback(data));
return data; return data;
} }
@ -232,7 +232,7 @@ public class PostViewV2ViewModel extends ViewModel {
public LiveData<Resource<Object>> updateCaption(final String caption) { public LiveData<Resource<Object>> updateCaption(final String caption) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>(); final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.loading(null)); data.postValue(Resource.loading(null));
mediaService.editCaption(media.getPk(), viewerId, caption, csrfToken, new ServiceCallback<Boolean>() { mediaService.editCaption(media.getPk(), caption, new ServiceCallback<Boolean>() {
@Override @Override
public void onSuccess(final Boolean result) { public void onSuccess(final Boolean result) {
if (result) { if (result) {

View File

@ -25,7 +25,7 @@ public class AddCookiesInterceptor implements Interceptor {
} }
final String userAgentHeader = "User-Agent"; final String userAgentHeader = "User-Agent";
if (request.header(userAgentHeader) == null) { if (request.header(userAgentHeader) == null) {
builder.addHeader(userAgentHeader, hasCookie ? Constants.I_USER_AGENT : Constants.USER_AGENT); builder.addHeader(userAgentHeader, Utils.settingsHelper.getString(hasCookie ? Constants.APP_UA : Constants.BROWSER_UA));
} }
final String languageHeader = "Accept-Language"; final String languageHeader = "Accept-Language";
if (request.header(languageHeader) == null) { if (request.header(languageHeader) == null) {

View File

@ -9,7 +9,6 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TimeZone;
import java.util.UUID; import java.util.UUID;
import awais.instagrabber.repositories.FeedRepository; import awais.instagrabber.repositories.FeedRepository;
@ -47,16 +46,16 @@ public class FeedService extends BaseService {
} }
public void fetch(final String csrfToken, public void fetch(final String csrfToken,
final String deviceUuid,
final String cursor, final String cursor,
final ServiceCallback<PostsFetchResponse> callback) { final ServiceCallback<PostsFetchResponse> callback) {
final Map<String, String> form = new HashMap<>(); final Map<String, String> form = new HashMap<>();
form.put("_uuid", UUID.randomUUID().toString()); form.put("_uuid", deviceUuid);
form.put("_csrftoken", csrfToken); form.put("_csrftoken", csrfToken);
form.put("phone_id", UUID.randomUUID().toString()); form.put("phone_id", UUID.randomUUID().toString());
form.put("device_id", UUID.randomUUID().toString()); form.put("device_id", UUID.randomUUID().toString());
form.put("client_session_id", UUID.randomUUID().toString()); form.put("client_session_id", UUID.randomUUID().toString());
form.put("is_prefetch", "0"); form.put("is_prefetch", "0");
form.put("timezone_offset", String.valueOf(TimeZone.getDefault().getRawOffset() / 1000));
if (!TextUtils.isEmpty(cursor)) { if (!TextUtils.isEmpty(cursor)) {
form.put("max_id", cursor); form.put("max_id", cursor);
form.put("reason", "pagination"); form.put("reason", "pagination");
@ -110,7 +109,7 @@ public class FeedService extends BaseService {
final List<Media> allPosts = new ArrayList<>(); final List<Media> allPosts = new ArrayList<>();
final List<Media> items = feedFetchResponse.getItems(); final List<Media> items = feedFetchResponse.getItems();
for (final Media media : items) { for (final Media media : items) {
if (media.isInjected() || media.getMediaType() == null) continue; if (media == null || media.isInjected() || (media.getMediaType() == null && media.getEndOfFeedDemarcator() == null)) continue;
if (needNewMaxId && media.getEndOfFeedDemarcator() != null) { if (needNewMaxId && media.getEndOfFeedDemarcator() != null) {
final EndOfFeedDemarcator endOfFeedDemarcator = media.getEndOfFeedDemarcator(); final EndOfFeedDemarcator endOfFeedDemarcator = media.getEndOfFeedDemarcator();
final EndOfFeedGroupSet groupSet = endOfFeedDemarcator.getGroupSet(); final EndOfFeedGroupSet groupSet = endOfFeedDemarcator.getGroupSet();
@ -123,7 +122,7 @@ public class FeedService extends BaseService {
nextMaxId = group.getNextMaxId(); nextMaxId = group.getNextMaxId();
final List<Media> feedItems = group.getFeedItems(); final List<Media> feedItems = group.getFeedItems();
for (final Media feedItem : feedItems) { for (final Media feedItem : feedItems) {
if (feedItem == null || feedItem.isInjected()) continue; if (feedItem == null || feedItem.isInjected() || feedItem.getMediaType() == null) continue;
allPosts.add(feedItem); allPosts.add(feedItem);
} }
} }

View File

@ -13,14 +13,13 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.Objects;
import awais.instagrabber.models.FollowModel; import awais.instagrabber.models.FollowModel;
import awais.instagrabber.repositories.FriendshipRepository; import awais.instagrabber.repositories.FriendshipRepository;
import awais.instagrabber.repositories.responses.FriendshipChangeResponse; import awais.instagrabber.repositories.responses.FriendshipChangeResponse;
import awais.instagrabber.repositories.responses.FriendshipListFetchResponse; import awais.instagrabber.repositories.responses.FriendshipListFetchResponse;
import awais.instagrabber.repositories.responses.FriendshipRestrictResponse; import awais.instagrabber.repositories.responses.FriendshipRestrictResponse;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils; import awais.instagrabber.utils.Utils;
import retrofit2.Call; import retrofit2.Call;
@ -32,61 +31,74 @@ public class FriendshipService extends BaseService {
private static final String TAG = "FriendshipService"; private static final String TAG = "FriendshipService";
private final FriendshipRepository repository; private final FriendshipRepository repository;
private final String deviceUuid, csrfToken;
private final long userId;
private static FriendshipService instance; private static FriendshipService instance;
private FriendshipService() { private FriendshipService(final String deviceUuid,
final String csrfToken,
final long userId) {
this.deviceUuid = deviceUuid;
this.csrfToken = csrfToken;
this.userId = userId;
final Retrofit retrofit = getRetrofitBuilder() final Retrofit retrofit = getRetrofitBuilder()
.baseUrl("https://i.instagram.com") .baseUrl("https://i.instagram.com")
.build(); .build();
repository = retrofit.create(FriendshipRepository.class); repository = retrofit.create(FriendshipRepository.class);
} }
public static FriendshipService getInstance() { public String getCsrfToken() {
if (instance == null) { return csrfToken;
instance = new FriendshipService(); }
public String getDeviceUuid() {
return deviceUuid;
}
public long getUserId() {
return userId;
}
public static FriendshipService getInstance(final String deviceUuid, final String csrfToken, final long userId) {
if (instance == null
|| !Objects.equals(instance.getCsrfToken(), csrfToken)
|| !Objects.equals(instance.getDeviceUuid(), deviceUuid)
|| !Objects.equals(instance.getUserId(), userId)) {
instance = new FriendshipService(deviceUuid, csrfToken, userId);
} }
return instance; return instance;
} }
public void follow(final long userId, public void follow(final long targetUserId,
final long targetUserId,
final String csrfToken,
final ServiceCallback<FriendshipChangeResponse> callback) { final ServiceCallback<FriendshipChangeResponse> callback) {
change("create", userId, targetUserId, csrfToken, callback); change("create", targetUserId, callback);
} }
public void unfollow(final long userId, public void unfollow(final long targetUserId,
final long targetUserId,
final String csrfToken,
final ServiceCallback<FriendshipChangeResponse> callback) { final ServiceCallback<FriendshipChangeResponse> callback) {
change("destroy", userId, targetUserId, csrfToken, callback); change("destroy", targetUserId, callback);
} }
public void block(final long userId, public void block(final long targetUserId,
final long targetUserId,
final String csrfToken,
final ServiceCallback<FriendshipChangeResponse> callback) { final ServiceCallback<FriendshipChangeResponse> callback) {
change("block", userId, targetUserId, csrfToken, callback); change("block", targetUserId, callback);
} }
public void unblock(final long userId, public void unblock(final long targetUserId,
final long targetUserId,
final String csrfToken,
final ServiceCallback<FriendshipChangeResponse> callback) { final ServiceCallback<FriendshipChangeResponse> callback) {
change("unblock", userId, targetUserId, csrfToken, callback); change("unblock", targetUserId, callback);
} }
public void toggleRestrict(final long targetUserId, public void toggleRestrict(final long targetUserId,
final boolean restrict, final boolean restrict,
final String csrfToken,
final ServiceCallback<FriendshipRestrictResponse> callback) { final ServiceCallback<FriendshipRestrictResponse> callback) {
final Map<String, String> form = new HashMap<>(3); final Map<String, String> form = new HashMap<>(3);
form.put("_csrftoken", csrfToken); form.put("_csrftoken", csrfToken);
form.put("_uuid", UUID.randomUUID().toString()); form.put("_uuid", deviceUuid);
form.put("target_user_id", String.valueOf(targetUserId)); form.put("target_user_id", String.valueOf(targetUserId));
final String action = restrict ? "restrict" : "unrestrict"; final String action = restrict ? "restrict" : "unrestrict";
final Call<FriendshipRestrictResponse> request = repository.toggleRestrict(Constants.I_USER_AGENT, action, form); final Call<FriendshipRestrictResponse> request = repository.toggleRestrict(action, form);
request.enqueue(new Callback<FriendshipRestrictResponse>() { request.enqueue(new Callback<FriendshipRestrictResponse>() {
@Override @Override
public void onResponse(@NonNull final Call<FriendshipRestrictResponse> call, public void onResponse(@NonNull final Call<FriendshipRestrictResponse> call,
@ -106,33 +118,27 @@ public class FriendshipService extends BaseService {
}); });
} }
public void approve(final long userId, public void approve(final long targetUserId,
final long targetUserId,
final String csrfToken,
final ServiceCallback<FriendshipChangeResponse> callback) { final ServiceCallback<FriendshipChangeResponse> callback) {
change("approve", userId, targetUserId, csrfToken, callback); change("approve", targetUserId, callback);
} }
public void ignore(final long userId, public void ignore(final long targetUserId,
final long targetUserId,
final String csrfToken,
final ServiceCallback<FriendshipChangeResponse> callback) { final ServiceCallback<FriendshipChangeResponse> callback) {
change("ignore", userId, targetUserId, csrfToken, callback); change("ignore", targetUserId, callback);
} }
private void change(final String action, private void change(final String action,
final long userId,
final long targetUserId, final long targetUserId,
final String csrfToken,
final ServiceCallback<FriendshipChangeResponse> callback) { final ServiceCallback<FriendshipChangeResponse> callback) {
final Map<String, Object> form = new HashMap<>(5); final Map<String, Object> form = new HashMap<>(5);
form.put("_csrftoken", csrfToken); form.put("_csrftoken", csrfToken);
form.put("_uid", userId); form.put("_uid", userId);
form.put("_uuid", UUID.randomUUID().toString()); form.put("_uuid", deviceUuid);
form.put("radio_type", "wifi-none"); form.put("radio_type", "wifi-none");
form.put("user_id", targetUserId); form.put("user_id", targetUserId);
final Map<String, String> signedForm = Utils.sign(form); final Map<String, String> signedForm = Utils.sign(form);
final Call<FriendshipChangeResponse> request = repository.change(Constants.I_USER_AGENT, action, targetUserId, signedForm); final Call<FriendshipChangeResponse> request = repository.change(action, targetUserId, signedForm);
request.enqueue(new Callback<FriendshipChangeResponse>() { request.enqueue(new Callback<FriendshipChangeResponse>() {
@Override @Override
public void onResponse(@NonNull final Call<FriendshipChangeResponse> call, public void onResponse(@NonNull final Call<FriendshipChangeResponse> call,
@ -158,8 +164,8 @@ public class FriendshipService extends BaseService {
final ServiceCallback<FriendshipListFetchResponse> callback) { final ServiceCallback<FriendshipListFetchResponse> callback) {
final Map<String, String> queryMap = new HashMap<>(); final Map<String, String> queryMap = new HashMap<>();
if (maxId != null) queryMap.put("max_id", maxId); if (maxId != null) queryMap.put("max_id", maxId);
final Call<String> request = repository.getList(Constants.I_USER_AGENT, final Call<String> request = repository.getList(
targetUserId, targetUserId,
follower ? "followers" : "following", follower ? "followers" : "following",
queryMap); queryMap);
request.enqueue(new Callback<String>() { request.enqueue(new Callback<String>() {

View File

@ -14,6 +14,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import awais.instagrabber.repositories.MediaRepository; import awais.instagrabber.repositories.MediaRepository;
@ -34,19 +35,41 @@ public class MediaService extends BaseService {
private static final String TAG = "MediaService"; private static final String TAG = "MediaService";
private final MediaRepository repository; private final MediaRepository repository;
private final String deviceUuid, csrfToken;
private final long userId;
private static MediaService instance; private static MediaService instance;
private MediaService() { private MediaService(final String deviceUuid,
final String csrfToken,
final long userId) {
this.deviceUuid = deviceUuid;
this.csrfToken = csrfToken;
this.userId = userId;
final Retrofit retrofit = getRetrofitBuilder() final Retrofit retrofit = getRetrofitBuilder()
.baseUrl("https://i.instagram.com") .baseUrl("https://i.instagram.com")
.build(); .build();
repository = retrofit.create(MediaRepository.class); repository = retrofit.create(MediaRepository.class);
} }
public static MediaService getInstance() { public String getCsrfToken() {
if (instance == null) { return csrfToken;
instance = new MediaService(); }
public String getDeviceUuid() {
return deviceUuid;
}
public long getUserId() {
return userId;
}
public static MediaService getInstance(final String deviceUuid, final String csrfToken, final long userId) {
if (instance == null
|| !Objects.equals(instance.getCsrfToken(), csrfToken)
|| !Objects.equals(instance.getDeviceUuid(), deviceUuid)
|| !Objects.equals(instance.getUserId(), userId)) {
instance = new MediaService(deviceUuid, csrfToken, userId);
} }
return instance; return instance;
} }
@ -78,43 +101,33 @@ public class MediaService extends BaseService {
} }
public void like(final String mediaId, public void like(final String mediaId,
final long userId,
final String csrfToken,
final ServiceCallback<Boolean> callback) { final ServiceCallback<Boolean> callback) {
action(mediaId, userId, "like", csrfToken, callback); action(mediaId, "like", callback);
} }
public void unlike(final String mediaId, public void unlike(final String mediaId,
final long userId,
final String csrfToken,
final ServiceCallback<Boolean> callback) { final ServiceCallback<Boolean> callback) {
action(mediaId, userId, "unlike", csrfToken, callback); action(mediaId, "unlike", callback);
} }
public void save(final String mediaId, public void save(final String mediaId,
final long userId,
final String csrfToken,
final ServiceCallback<Boolean> callback) { final ServiceCallback<Boolean> callback) {
action(mediaId, userId, "save", csrfToken, callback); action(mediaId, "save", callback);
} }
public void unsave(final String mediaId, public void unsave(final String mediaId,
final long userId,
final String csrfToken,
final ServiceCallback<Boolean> callback) { final ServiceCallback<Boolean> callback) {
action(mediaId, userId, "unsave", csrfToken, callback); action(mediaId, "unsave", callback);
} }
private void action(final String mediaId, private void action(final String mediaId,
final long userId,
final String action, final String action,
final String csrfToken,
final ServiceCallback<Boolean> callback) { final ServiceCallback<Boolean> callback) {
final Map<String, Object> form = new HashMap<>(4); final Map<String, Object> form = new HashMap<>(4);
form.put("media_id", mediaId); form.put("media_id", mediaId);
form.put("_csrftoken", csrfToken); form.put("_csrftoken", csrfToken);
form.put("_uid", userId); form.put("_uid", userId);
form.put("_uuid", UUID.randomUUID().toString()); form.put("_uuid", deviceUuid);
// form.put("radio_type", "wifi-none"); // form.put("radio_type", "wifi-none");
final Map<String, String> signedForm = Utils.sign(form); final Map<String, String> signedForm = Utils.sign(form);
final Call<String> request = repository.action(action, mediaId, signedForm); final Call<String> request = repository.action(action, mediaId, signedForm);
@ -149,9 +162,7 @@ public class MediaService extends BaseService {
public void comment(@NonNull final String mediaId, public void comment(@NonNull final String mediaId,
@NonNull final String comment, @NonNull final String comment,
final long userId,
final String replyToCommentId, final String replyToCommentId,
final String csrfToken,
@NonNull final ServiceCallback<Boolean> callback) { @NonNull final ServiceCallback<Boolean> callback) {
final String module = "self_comments_v2"; final String module = "self_comments_v2";
final Map<String, Object> form = new HashMap<>(); final Map<String, Object> form = new HashMap<>();
@ -159,7 +170,7 @@ public class MediaService extends BaseService {
form.put("idempotence_token", UUID.randomUUID().toString()); form.put("idempotence_token", UUID.randomUUID().toString());
form.put("_csrftoken", csrfToken); form.put("_csrftoken", csrfToken);
form.put("_uid", userId); form.put("_uid", userId);
form.put("_uuid", UUID.randomUUID().toString()); form.put("_uuid", deviceUuid);
form.put("comment_text", comment); form.put("comment_text", comment);
form.put("containermodule", module); form.put("containermodule", module);
if (!TextUtils.isEmpty(replyToCommentId)) { if (!TextUtils.isEmpty(replyToCommentId)) {
@ -194,23 +205,19 @@ public class MediaService extends BaseService {
} }
public void deleteComment(final String mediaId, public void deleteComment(final String mediaId,
final long userId,
final String commentId, final String commentId,
final String csrfToken,
@NonNull final ServiceCallback<Boolean> callback) { @NonNull final ServiceCallback<Boolean> callback) {
deleteComments(mediaId, userId, Collections.singletonList(commentId), csrfToken, callback); deleteComments(mediaId, Collections.singletonList(commentId), callback);
} }
public void deleteComments(final String mediaId, public void deleteComments(final String mediaId,
final long userId,
final List<String> commentIds, final List<String> commentIds,
final String csrfToken,
@NonNull final ServiceCallback<Boolean> callback) { @NonNull final ServiceCallback<Boolean> callback) {
final Map<String, Object> form = new HashMap<>(); final Map<String, Object> form = new HashMap<>();
form.put("comment_ids_to_delete", TextUtils.join(",", commentIds)); form.put("comment_ids_to_delete", TextUtils.join(",", commentIds));
form.put("_csrftoken", csrfToken); form.put("_csrftoken", csrfToken);
form.put("_uid", userId); form.put("_uid", userId);
form.put("_uuid", UUID.randomUUID().toString()); form.put("_uuid", deviceUuid);
final Map<String, String> signedForm = Utils.sign(form); final Map<String, String> signedForm = Utils.sign(form);
final Call<String> bulkDeleteRequest = repository.commentsBulkDelete(mediaId, signedForm); final Call<String> bulkDeleteRequest = repository.commentsBulkDelete(mediaId, signedForm);
bulkDeleteRequest.enqueue(new Callback<String>() { bulkDeleteRequest.enqueue(new Callback<String>() {
@ -241,12 +248,11 @@ public class MediaService extends BaseService {
} }
public void commentLike(@NonNull final String commentId, public void commentLike(@NonNull final String commentId,
@NonNull final String csrfToken,
@NonNull final ServiceCallback<Boolean> callback) { @NonNull final ServiceCallback<Boolean> callback) {
final Map<String, Object> form = new HashMap<>(); final Map<String, Object> form = new HashMap<>();
form.put("_csrftoken", csrfToken); form.put("_csrftoken", csrfToken);
// form.put("_uid", userId); // form.put("_uid", userId);
// form.put("_uuid", UUID.randomUUID().toString()); // form.put("_uuid", deviceUuid);
final Map<String, String> signedForm = Utils.sign(form); final Map<String, String> signedForm = Utils.sign(form);
final Call<String> commentLikeRequest = repository.commentLike(commentId, signedForm); final Call<String> commentLikeRequest = repository.commentLike(commentId, signedForm);
commentLikeRequest.enqueue(new Callback<String>() { commentLikeRequest.enqueue(new Callback<String>() {
@ -277,12 +283,11 @@ public class MediaService extends BaseService {
} }
public void commentUnlike(final String commentId, public void commentUnlike(final String commentId,
@NonNull final String csrfToken,
@NonNull final ServiceCallback<Boolean> callback) { @NonNull final ServiceCallback<Boolean> callback) {
final Map<String, Object> form = new HashMap<>(); final Map<String, Object> form = new HashMap<>();
form.put("_csrftoken", csrfToken); form.put("_csrftoken", csrfToken);
// form.put("_uid", userId); // form.put("_uid", userId);
// form.put("_uuid", UUID.randomUUID().toString()); // form.put("_uuid", deviceUuid);
final Map<String, String> signedForm = Utils.sign(form); final Map<String, String> signedForm = Utils.sign(form);
final Call<String> commentUnlikeRequest = repository.commentUnlike(commentId, signedForm); final Call<String> commentUnlikeRequest = repository.commentUnlike(commentId, signedForm);
commentUnlikeRequest.enqueue(new Callback<String>() { commentUnlikeRequest.enqueue(new Callback<String>() {
@ -313,14 +318,12 @@ public class MediaService extends BaseService {
} }
public void editCaption(final String postId, public void editCaption(final String postId,
final long userId,
final String newCaption, final String newCaption,
@NonNull final String csrfToken,
@NonNull final ServiceCallback<Boolean> callback) { @NonNull final ServiceCallback<Boolean> callback) {
final Map<String, Object> form = new HashMap<>(); final Map<String, Object> form = new HashMap<>();
form.put("_csrftoken", csrfToken); form.put("_csrftoken", csrfToken);
form.put("_uid", userId); form.put("_uid", userId);
form.put("_uuid", UUID.randomUUID().toString()); form.put("_uuid", deviceUuid);
form.put("igtv_feed_preview", "false"); form.put("igtv_feed_preview", "false");
form.put("media_id", postId); form.put("media_id", postId);
form.put("caption_text", newCaption); form.put("caption_text", newCaption);
@ -411,9 +414,7 @@ public class MediaService extends BaseService {
}); });
} }
public Call<String> uploadFinish(final long userId, public Call<String> uploadFinish(@NonNull final UploadFinishOptions options) {
@NonNull final String csrfToken,
@NonNull final UploadFinishOptions options) {
if (options.getVideoOptions() != null) { if (options.getVideoOptions() != null) {
final UploadFinishOptions.VideoOptions videoOptions = options.getVideoOptions(); final UploadFinishOptions.VideoOptions videoOptions = options.getVideoOptions();
if (videoOptions.getClips() == null) { if (videoOptions.getClips() == null) {
@ -430,7 +431,7 @@ public class MediaService extends BaseService {
.put("_csrftoken", csrfToken) .put("_csrftoken", csrfToken)
.put("source_type", options.getSourceType()) .put("source_type", options.getSourceType())
.put("_uid", String.valueOf(userId)) .put("_uid", String.valueOf(userId))
.put("_uuid", UUID.randomUUID().toString()) .put("_uuid", deviceUuid)
.put("upload_id", options.getUploadId()); .put("upload_id", options.getUploadId());
if (options.getVideoOptions() != null) { if (options.getVideoOptions() != null) {
formBuilder.putAll(options.getVideoOptions().getMap()); formBuilder.putAll(options.getVideoOptions().getMap());

View File

@ -21,6 +21,7 @@ import awais.instagrabber.models.NotificationModel;
import awais.instagrabber.models.enums.NotificationType; import awais.instagrabber.models.enums.NotificationType;
import awais.instagrabber.repositories.NewsRepository; import awais.instagrabber.repositories.NewsRepository;
import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.Utils;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
import retrofit2.Response; import retrofit2.Response;
@ -32,6 +33,7 @@ public class NewsService extends BaseService {
private final NewsRepository repository; private final NewsRepository repository;
private static NewsService instance; private static NewsService instance;
private static String browserUa, appUa;
private NewsService() { private NewsService() {
final Retrofit retrofit = getRetrofitBuilder() final Retrofit retrofit = getRetrofitBuilder()
@ -44,13 +46,15 @@ public class NewsService extends BaseService {
if (instance == null) { if (instance == null) {
instance = new NewsService(); instance = new NewsService();
} }
appUa = Utils.settingsHelper.getString(Constants.APP_UA);
browserUa = Utils.settingsHelper.getString(Constants.BROWSER_UA);
return instance; return instance;
} }
public void fetchAppInbox(final boolean markAsSeen, public void fetchAppInbox(final boolean markAsSeen,
final ServiceCallback<List<NotificationModel>> callback) { final ServiceCallback<List<NotificationModel>> callback) {
final List<NotificationModel> result = new ArrayList<>(); final List<NotificationModel> result = new ArrayList<>();
final Call<String> request = repository.appInbox(markAsSeen); final Call<String> request = repository.appInbox(appUa, markAsSeen);
request.enqueue(new Callback<String>() { request.enqueue(new Callback<String>() {
@Override @Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
@ -90,7 +94,7 @@ public class NewsService extends BaseService {
public void fetchWebInbox(final boolean markAsSeen, public void fetchWebInbox(final boolean markAsSeen,
final ServiceCallback<List<NotificationModel>> callback) { final ServiceCallback<List<NotificationModel>> callback) {
final Call<String> request = repository.webInbox(); final Call<String> request = repository.webInbox(browserUa);
request.enqueue(new Callback<String>() { request.enqueue(new Callback<String>() {
@Override @Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
@ -181,7 +185,7 @@ public class NewsService extends BaseService {
data.getLong("profile_id"), data.getLong("profile_id"),
data.getString("profile_name"), data.getString("profile_name"),
data.getString("profile_image"), data.getString("profile_image"),
!data.isNull("media") ? data.getJSONArray("media").getJSONObject(0).getLong("id") : 0, !data.isNull("media") ? Long.valueOf(data.getJSONArray("media").getJSONObject(0).getString("id").split("_")[0]) : 0,
!data.isNull("media") ? data.getJSONArray("media").getJSONObject(0).getString("image") : null, !data.isNull("media") ? data.getJSONArray("media").getJSONObject(0).getString("image") : null,
notificationType); notificationType);
} }
@ -206,7 +210,7 @@ public class NewsService extends BaseService {
form.put("device_id", UUID.randomUUID().toString()); form.put("device_id", UUID.randomUUID().toString());
form.put("module", "discover_people"); form.put("module", "discover_people");
form.put("paginate", "false"); form.put("paginate", "false");
final Call<String> request = repository.getAyml(form); final Call<String> request = repository.getAyml(appUa, form);
request.enqueue(new Callback<String>() { request.enqueue(new Callback<String>() {
@Override @Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {

View File

@ -325,7 +325,7 @@ public class StoriesService extends BaseService {
public void getUserStory(final StoryViewerOptions options, public void getUserStory(final StoryViewerOptions options,
final ServiceCallback<List<StoryModel>> callback) { final ServiceCallback<List<StoryModel>> callback) {
final String url = buildUrl(options); final String url = buildUrl(options);
final Call<String> userStoryCall = repository.getUserStory(Constants.I_USER_AGENT, url); final Call<String> userStoryCall = repository.getUserStory(url);
final boolean isLoc = options.getType() == StoryViewerOptions.Type.LOCATION; final boolean isLoc = options.getType() == StoryViewerOptions.Type.LOCATION;
final boolean isHashtag = options.getType() == StoryViewerOptions.Type.HASHTAG; final boolean isHashtag = options.getType() == StoryViewerOptions.Type.HASHTAG;
final boolean isHighlight = options.getType() == StoryViewerOptions.Type.HIGHLIGHT; final boolean isHighlight = options.getType() == StoryViewerOptions.Type.HIGHLIGHT;
@ -400,7 +400,7 @@ public class StoriesService extends BaseService {
form.put(arg1, arg2); form.put(arg1, arg2);
final Map<String, String> signedForm = Utils.sign(form); final Map<String, String> signedForm = Utils.sign(form);
final Call<StoryStickerResponse> request = final Call<StoryStickerResponse> request =
repository.respondToSticker(Constants.I_USER_AGENT, storyId, stickerId, action, signedForm); repository.respondToSticker(storyId, stickerId, action, signedForm);
request.enqueue(new Callback<StoryStickerResponse>() { request.enqueue(new Callback<StoryStickerResponse>() {
@Override @Override
public void onResponse(@NonNull final Call<StoryStickerResponse> call, public void onResponse(@NonNull final Call<StoryStickerResponse> call,

View File

@ -12,7 +12,6 @@ import org.json.JSONObject;
import awais.instagrabber.repositories.TagsRepository; import awais.instagrabber.repositories.TagsRepository;
import awais.instagrabber.repositories.responses.PostsFetchResponse; import awais.instagrabber.repositories.responses.PostsFetchResponse;
import awais.instagrabber.repositories.responses.TagFeedResponse; import awais.instagrabber.repositories.responses.TagFeedResponse;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.TextUtils; import awais.instagrabber.utils.TextUtils;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
@ -46,12 +45,11 @@ public class TagsService extends BaseService {
return instance; return instance;
} }
public void follow(@NonNull final String tag, public void follow(@NonNull final String ua,
@NonNull final String tag,
@NonNull final String csrfToken, @NonNull final String csrfToken,
final ServiceCallback<Boolean> callback) { final ServiceCallback<Boolean> callback) {
final Call<String> request = webRepository.follow(Constants.USER_AGENT, final Call<String> request = webRepository.follow(ua, csrfToken, tag);
csrfToken,
tag);
request.enqueue(new Callback<String>() { request.enqueue(new Callback<String>() {
@Override @Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
@ -77,12 +75,11 @@ public class TagsService extends BaseService {
}); });
} }
public void unfollow(@NonNull final String tag, public void unfollow(@NonNull final String ua,
@NonNull final String tag,
@NonNull final String csrfToken, @NonNull final String csrfToken,
final ServiceCallback<Boolean> callback) { final ServiceCallback<Boolean> callback) {
final Call<String> request = webRepository.unfollow(Constants.USER_AGENT, final Call<String> request = webRepository.unfollow(ua, csrfToken, tag);
csrfToken,
tag);
request.enqueue(new Callback<String>() { request.enqueue(new Callback<String>() {
@Override @Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) { public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {

View File

@ -72,6 +72,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingStart="0dp" android:paddingStart="0dp"
android:paddingEnd="8dp" android:paddingEnd="8dp"
android:layout_margin="8dp"
app:layout_constraintBottom_toTopOf="@id/mute_mentions" app:layout_constraintBottom_toTopOf="@id/mute_mentions"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/title_edit_input_layout" /> app:layout_constraintTop_toBottomOf="@id/title_edit_input_layout" />
@ -98,6 +99,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingStart="0dp" android:paddingStart="0dp"
android:paddingEnd="8dp" android:paddingEnd="8dp"
android:layout_margin="8dp"
app:layout_constraintBottom_toTopOf="@id/leave" app:layout_constraintBottom_toTopOf="@id/leave"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/mute_messages" /> app:layout_constraintTop_toBottomOf="@id/mute_messages" />