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
targetSdkVersion 29
versionCode 57
versionName '19.0.5'
versionCode 58
versionName '19.1.0'
multiDexEnabled true

View File

@ -12,11 +12,13 @@ import com.facebook.imagepipeline.core.ImagePipelineConfig;
import java.net.CookieHandler;
import java.text.SimpleDateFormat;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.LocaleUtils;
import awais.instagrabber.utils.SettingsHelper;
import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.UserAgentUtils;
import awaisomereport.CrashReporter;
import awaisomereport.LogCollector;
@ -85,5 +87,15 @@ public final class InstaGrabberApplication extends Application {
if (TextUtils.isEmpty(settingsHelper.getString(Constants.DEVICE_UUID))) {
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 {
urlConnection = (HttpURLConnection) new URL(url).openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("User-Agent", Constants.I_USER_AGENT);
urlConnection.setRequestProperty("User-Agent", Utils.settingsHelper.getString(Constants.APP_UA));
urlConnection.setUseCaches(false);
final String urlParameters = Utils.sign("{\"_csrftoken\":\"" + cookie.split("csrftoken=")[1].split(";")[0]
+ "\",\"_uid\":\"" + CookieUtils.getUserIdFromCookie(cookie)

View File

@ -29,8 +29,9 @@ public class FeedPostFetchService implements PostFetcher.PostFetchService {
final List<Media> feedModels = new ArrayList<>();
final String cookie = settingsHelper.getString(Constants.COOKIE);
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
feedModels.clear();
feedService.fetch(csrfToken, nextCursor, new ServiceCallback<PostsFetchResponse>() {
feedService.fetch(csrfToken, deviceUuid, nextCursor, new ServiceCallback<PostsFetchResponse>() {
@Override
public void onSuccess(final PostsFetchResponse result) {
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.NetworkUtils;
import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils;
public class GetActivityAsyncTask extends AsyncTask<String, Void, GetActivityAsyncTask.NotificationCounts> {
private static final String TAG = "GetActivityAsyncTask";
@ -44,7 +45,7 @@ public class GetActivityAsyncTask extends AsyncTask<String, Void, GetActivityAsy
try {
urlConnection = (HttpURLConnection) new URL(url).openConnection();
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.connect();
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"),
false,
isPrivate,
false,
userJson.optBoolean("restricted_by_viewer"),
userJson.optBoolean("has_requested_viewer"),
userJson.optBoolean("requested_by_viewer"),
false,
userJson.optBoolean("restricted_by_viewer"),
false

View File

@ -14,6 +14,7 @@ import awais.instagrabber.BuildConfig;
import awais.instagrabber.interfaces.FetchListener;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.NetworkUtils;
import awais.instagrabber.utils.Utils;
public final class UsernameFetcher extends AsyncTask<Void, Void, String> {
private final FetchListener<String> fetchListener;
@ -31,7 +32,7 @@ public final class UsernameFetcher extends AsyncTask<Void, Void, String> {
try {
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);
final JSONObject user;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -172,6 +172,21 @@ public class DirectMessageThreadFragment extends Fragment {
@Override
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);
builder.build().show(getChildFragmentManager(), "post_view");
}

View File

@ -68,6 +68,7 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
private FragmentFeedBinding binding;
private StoriesService storiesService;
private boolean shouldRefresh = true;
private final boolean isRotate = false;
private FeedStoriesViewModel feedStoriesViewModel;
private boolean storiesFetching;
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) {
if (!shouldRefresh) return;
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();
setupFeed();
shouldRefresh = false;

View File

@ -99,7 +99,6 @@ import awais.instagrabber.webservices.StoriesService;
import static androidx.core.content.PermissionChecker.checkSelfPermission;
import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG;
import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;
import static awais.instagrabber.utils.Utils.settingsHelper;
public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = "ProfileFragment";
@ -300,10 +299,15 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
@Override
public void onCreate(@Nullable final Bundle 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();
friendshipService = FriendshipService.getInstance();
friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, userId);
storiesService = StoriesService.getInstance();
mediaService = MediaService.getInstance();
mediaService = MediaService.getInstance(null, null, 0);
accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext()));
favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext()));
setHasOptionsMenu(true);
@ -313,8 +317,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
public View onCreateView(@NonNull final LayoutInflater inflater,
final ViewGroup container,
final Bundle savedInstanceState) {
cookie = settingsHelper.getString(Constants.COOKIE);
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
if (root != null) {
if (getArguments() != null) {
final ProfileFragmentArgs fragmentArgs = ProfileFragmentArgs.fromBundle(getArguments());
@ -380,7 +382,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
friendshipService.toggleRestrict(
profileModel.getPk(),
!profileModel.getFriendshipStatus().isRestricted(),
CookieUtils.getCsrfTokenFromCookie(cookie),
new ServiceCallback<FriendshipRestrictResponse>() {
@Override
public void onSuccess(final FriendshipRestrictResponse result) {
@ -396,13 +397,10 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
return true;
}
if (item.getItemId() == R.id.block) {
final long userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie);
if (!isLoggedIn) return false;
if (profileModel.getFriendshipStatus().isBlocking()) {
friendshipService.unblock(
userIdFromCookie,
profileModel.getPk(),
CookieUtils.getCsrfTokenFromCookie(cookie),
new ServiceCallback<FriendshipChangeResponse>() {
@Override
public void onSuccess(final FriendshipChangeResponse result) {
@ -418,9 +416,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
return true;
}
friendshipService.block(
userIdFromCookie,
profileModel.getPk(),
CookieUtils.getCsrfTokenFromCookie(cookie),
new ServiceCallback<FriendshipChangeResponse>() {
@Override
public void onSuccess(final FriendshipChangeResponse result) {
@ -628,9 +624,9 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
), new RepositoryCallback<Void>() {
@Override
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);
showSnackbar(getString(R.string.added_to_favs));
showSnackbar(getString(R.string.added_to_favs_short));
}
@Override
@ -894,7 +890,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
private void setupCommonListeners() {
final Context context = getContext();
final long userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie);
profileDetailsBinding.btnFollow.setOnClickListener(v -> {
if (profileModel.getFriendshipStatus().isFollowing() && profileModel.isPrivate()) {
new AlertDialog.Builder(context)
@ -902,9 +897,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
.setMessage(R.string.priv_acc_confirm)
.setPositiveButton(R.string.confirm, (d, w) ->
friendshipService.unfollow(
userIdFromCookie,
profileModel.getPk(),
CookieUtils.getCsrfTokenFromCookie(cookie),
new ServiceCallback<FriendshipChangeResponse>() {
@Override
public void onSuccess(final FriendshipChangeResponse result) {
@ -919,11 +912,10 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
}))
.setNegativeButton(R.string.cancel, null)
.show();
} else if (profileModel.getFriendshipStatus().isFollowing() || profileModel.getFriendshipStatus().isOutgoingRequest()) {
}
else if (profileModel.getFriendshipStatus().isFollowing() || profileModel.getFriendshipStatus().isOutgoingRequest()) {
friendshipService.unfollow(
userIdFromCookie,
profileModel.getPk(),
CookieUtils.getCsrfTokenFromCookie(cookie),
new ServiceCallback<FriendshipChangeResponse>() {
@Override
public void onSuccess(final FriendshipChangeResponse result) {
@ -938,9 +930,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
});
} else {
friendshipService.follow(
userIdFromCookie,
profileModel.getPk(),
CookieUtils.getCsrfTokenFromCookie(cookie),
new ServiceCallback<FriendshipChangeResponse>() {
@Override
public void onSuccess(final FriendshipChangeResponse result) {
@ -1102,6 +1092,6 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
private boolean isReallyPrivate() {
final long myId = CookieUtils.getUserIdFromCookie(cookie);
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.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.QueryMap;
@ -17,20 +16,17 @@ public interface FriendshipRepository {
@FormUrlEncoded
@POST("/api/v1/friendships/{action}/{id}/")
Call<FriendshipChangeResponse> change(@Header("User-Agent") String userAgent,
@Path("action") String action,
Call<FriendshipChangeResponse> change(@Path("action") String action,
@Path("id") long id,
@FieldMap Map<String, String> form);
@FormUrlEncoded
@POST("/api/v1/restrict_action/{action}/")
Call<FriendshipRestrictResponse> toggleRestrict(@Header("User-Agent") String userAgent,
@Path("action") String action,
Call<FriendshipRestrictResponse> toggleRestrict(@Path("action") String action,
@FieldMap Map<String, String> form);
@GET("/api/v1/friendships/{userId}/{type}/")
Call<String> getList(@Header("User-Agent") String userAgent,
@Path("userId") long userId,
Call<String> getList(@Path("userId") long userId,
@Path("type") String type, // following or followers
@QueryMap(encoded = true) Map<String, String> queryParams);
}

View File

@ -2,28 +2,23 @@ package awais.instagrabber.repositories;
import java.util.Map;
import awais.instagrabber.utils.Constants;
import retrofit2.Call;
import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.Query;
public interface NewsRepository {
@Headers("User-Agent: " + Constants.USER_AGENT)
@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/")
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
@Headers("User-Agent: " + Constants.I_USER_AGENT)
@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.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.QueryMap;
@ -28,12 +27,11 @@ public interface StoriesRepository {
Call<String> fetchArchive(@QueryMap Map<String, String> queryParams);
@GET
Call<String> getUserStory(@Header("User-Agent") String userAgent, @Url String url);
Call<String> getUserStory(@Url String url);
@FormUrlEncoded
@POST("/api/v1/media/{storyId}/{stickerId}/{action}/")
Call<StoryStickerResponse> respondToSticker(@Header("User-Agent") String userAgent,
@Path("storyId") String storyId,
Call<StoryStickerResponse> respondToSticker(@Path("storyId") String storyId,
@Path("stickerId") String stickerId,
@Path("action") String action,
// 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 boolean canViewerReshare;
private final boolean commentLikesEnabled;
private final boolean commentsDisabled;
private final long nextMaxId;
private final long commentCount;
private final ImageVersions2 imageVersions2;
@ -56,6 +57,7 @@ public class Media implements Serializable {
final int originalHeight,
final MediaItemType mediaType,
final boolean commentLikesEnabled,
final boolean commentsDisabled,
final long nextMaxId,
final long commentCount,
final long likeCount,
@ -87,6 +89,7 @@ public class Media implements Serializable {
this.originalHeight = originalHeight;
this.mediaType = mediaType;
this.commentLikesEnabled = commentLikesEnabled;
this.commentsDisabled = commentsDisabled;
this.nextMaxId = nextMaxId;
this.commentCount = commentCount;
this.likeCount = likeCount;
@ -182,6 +185,10 @@ public class Media implements Serializable {
return commentLikesEnabled;
}
public boolean isCommentsDisabled() {
return commentsDisabled;
}
public long getNextMaxId() {
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_LANGUAGE = "app_language_v19";
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 BROWSER_UA_CODE = "browser_ua_code";
public static final String APP_UA_CODE = "app_ua_code";
// boolean prefs
public static final String DOWNLOAD_USER_FOLDER = "download_user_folder";
// 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 SHOW_QUICK_ACCESS_DIALOG = "show_quick_dlg";
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 ////////////////////////
public static final String EXTRAS_USER = "user";
public static final String EXTRAS_HASHTAG = "hashtag";
@ -54,13 +58,6 @@ public final class Constants {
// Notification ids
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
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," +

View File

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

View File

@ -343,6 +343,10 @@ public final class ExportImportUtils {
jsonObject.remove(Constants.COOKIE);
jsonObject.remove(Constants.DEVICE_UUID);
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;
} catch (Exception 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) {
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();
settingsHelper.putInteger(Constants.PREV_INSTALL_VERSION, BuildConfig.VERSION_CODE);
}

View File

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

View File

@ -857,6 +857,7 @@ public final class ResponseBodyUtils {
height,
mediaItemType,
false,
feedItem.optBoolean("comments_disabled"),
-1,
commentsCount,
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_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.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_UPDATES;
import static awais.instagrabber.utils.Constants.COOKIE;
@ -80,7 +84,7 @@ public final class SettingsHelper {
private int getIntegerDefault(@IntegerSettings final String key) {
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;
}
@ -121,10 +125,11 @@ public final class SettingsHelper {
}
@StringDef(
{APP_LANGUAGE, APP_THEME, COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION, CUSTOM_DATE_TIME_FORMAT,
DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME, PREF_POSTS_LAYOUT,
PREF_PROFILE_POSTS_LAYOUT, PREF_TOPIC_POSTS_LAYOUT, PREF_HASHTAG_POSTS_LAYOUT, PREF_LOCATION_POSTS_LAYOUT,
PREF_LIKED_POSTS_LAYOUT, PREF_TAGGED_POSTS_LAYOUT, PREF_SAVED_POSTS_LAYOUT, STORY_SORT, PREF_EMOJI_VARIANTS, PREF_REACTIONS})
{APP_LANGUAGE, APP_THEME, APP_UA, BROWSER_UA, COOKIE, FOLDER_PATH, DATE_TIME_FORMAT, DATE_TIME_SELECTION,
CUSTOM_DATE_TIME_FORMAT, DEVICE_UUID, SKIPPED_VERSION, DEFAULT_TAB, PREF_DARK_THEME, PREF_LIGHT_THEME,
PREF_POSTS_LAYOUT, PREF_PROFILE_POSTS_LAYOUT, PREF_TOPIC_POSTS_LAYOUT, PREF_HASHTAG_POSTS_LAYOUT,
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 {}
@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})
public @interface BooleanSettings {}
@StringDef({PREV_INSTALL_VERSION})
@StringDef({PREV_INSTALL_VERSION, BROWSER_UA_CODE, APP_UA_CODE})
public @interface IntegerSettings {}
}

View File

@ -30,7 +30,7 @@ public final class UpdateChecker extends AsyncTask<Void, Void, Boolean> {
HttpURLConnection conn =
(HttpURLConnection) new URL("https://f-droid.org/api/v1/packages/me.austinhuang.instagrabber").openConnection();
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();
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!");
}
directMessagesService = DirectMessagesService.getInstance(csrfToken, userId, deviceUuid);
friendshipService = FriendshipService.getInstance();
friendshipService = FriendshipService.getInstance(deviceUuid, csrfToken, userId);
resources = getApplication().getResources();
}
@ -264,7 +264,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
private LiveData<Resource<Object>> blockUser(final User user) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
friendshipService.block(userId, user.getPk(), csrfToken, new ServiceCallback<FriendshipChangeResponse>() {
friendshipService.block(user.getPk(), new ServiceCallback<FriendshipChangeResponse>() {
@Override
public void onSuccess(final FriendshipChangeResponse result) {
// refresh thread
@ -281,7 +281,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
private LiveData<Resource<Object>> unblockUser(final User user) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
friendshipService.unblock(userId, user.getPk(), csrfToken, new ServiceCallback<FriendshipChangeResponse>() {
friendshipService.unblock(user.getPk(), new ServiceCallback<FriendshipChangeResponse>() {
@Override
public void onSuccess(final FriendshipChangeResponse result) {
// refresh thread
@ -298,7 +298,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
private LiveData<Resource<Object>> restrictUser(final User user) {
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
public void onSuccess(final FriendshipRestrictResponse result) {
// refresh thread
@ -315,7 +315,7 @@ public class DirectSettingsViewModel extends AndroidViewModel {
private LiveData<Resource<Object>> unRestrictUser(final User user) {
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
public void onSuccess(final FriendshipRestrictResponse result) {
// refresh thread

View File

@ -103,7 +103,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
throw new IllegalArgumentException("User is not logged in!");
}
service = DirectMessagesService.getInstance(csrfToken, userId, deviceUuid);
mediaService = MediaService.getInstance();
mediaService = MediaService.getInstance(deviceUuid, csrfToken, userId);
contentResolver = application.getContentResolver();
recordingsDir = DirectoryUtils.getOutputMediaDirectory(application, "Recordings");
this.application = application;
@ -467,7 +467,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
.setUploadId(uploadDmVideoOptions.getUploadId())
.setSourceType("2")
.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>() {
@Override
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()
.setUploadId(uploadDmVoiceOptions.getUploadId())
.setSourceType("4");
final Call<String> uploadFinishRequest = mediaService.uploadFinish(userId, csrfToken, uploadFinishOptions);
final Call<String> uploadFinishRequest = mediaService.uploadFinish(uploadFinishOptions);
uploadFinishRequest.enqueue(new Callback<String>() {
@Override
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 MediaService mediaService;
private final long viewerId;
private final String csrfToken;
private final boolean isLoggedIn;
private Media media;
public PostViewV2ViewModel() {
mediaService = MediaService.getInstance();
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);
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
mediaService = MediaService.getInstance(deviceUuid, csrfToken, viewerId);
isLoggedIn = !TextUtils.isEmpty(cookie) && CookieUtils.getUserIdFromCookie(cookie) > 0;
}
@ -142,14 +142,14 @@ public class PostViewV2ViewModel extends ViewModel {
public LiveData<Resource<Object>> like() {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.loading(null));
mediaService.like(media.getPk(), viewerId, csrfToken, getLikeUnlikeCallback(data));
mediaService.like(media.getPk(), getLikeUnlikeCallback(data));
return data;
}
public LiveData<Resource<Object>> unlike() {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.loading(null));
mediaService.unlike(media.getPk(), viewerId, csrfToken, getLikeUnlikeCallback(data));
mediaService.unlike(media.getPk(), getLikeUnlikeCallback(data));
return data;
}
@ -196,14 +196,14 @@ public class PostViewV2ViewModel extends ViewModel {
public LiveData<Resource<Object>> save() {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.loading(null));
mediaService.save(media.getPk(), viewerId, csrfToken, getSaveUnsaveCallback(data));
mediaService.save(media.getPk(), getSaveUnsaveCallback(data));
return data;
}
public LiveData<Resource<Object>> unsave() {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.loading(null));
mediaService.unsave(media.getPk(), viewerId, csrfToken, getSaveUnsaveCallback(data));
mediaService.unsave(media.getPk(), getSaveUnsaveCallback(data));
return data;
}
@ -232,7 +232,7 @@ public class PostViewV2ViewModel extends ViewModel {
public LiveData<Resource<Object>> updateCaption(final String caption) {
final MutableLiveData<Resource<Object>> data = new MutableLiveData<>();
data.postValue(Resource.loading(null));
mediaService.editCaption(media.getPk(), viewerId, caption, csrfToken, new ServiceCallback<Boolean>() {
mediaService.editCaption(media.getPk(), caption, new ServiceCallback<Boolean>() {
@Override
public void onSuccess(final Boolean result) {
if (result) {

View File

@ -25,7 +25,7 @@ public class AddCookiesInterceptor implements Interceptor {
}
final String userAgentHeader = "User-Agent";
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";
if (request.header(languageHeader) == null) {

View File

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

View File

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

View File

@ -14,6 +14,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import awais.instagrabber.repositories.MediaRepository;
@ -34,19 +35,41 @@ public class MediaService extends BaseService {
private static final String TAG = "MediaService";
private final MediaRepository repository;
private final String deviceUuid, csrfToken;
private final long userId;
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()
.baseUrl("https://i.instagram.com")
.build();
repository = retrofit.create(MediaRepository.class);
}
public static MediaService getInstance() {
if (instance == null) {
instance = new MediaService();
public String getCsrfToken() {
return csrfToken;
}
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;
}
@ -78,43 +101,33 @@ public class MediaService extends BaseService {
}
public void like(final String mediaId,
final long userId,
final String csrfToken,
final ServiceCallback<Boolean> callback) {
action(mediaId, userId, "like", csrfToken, callback);
action(mediaId, "like", callback);
}
public void unlike(final String mediaId,
final long userId,
final String csrfToken,
final ServiceCallback<Boolean> callback) {
action(mediaId, userId, "unlike", csrfToken, callback);
action(mediaId, "unlike", callback);
}
public void save(final String mediaId,
final long userId,
final String csrfToken,
final ServiceCallback<Boolean> callback) {
action(mediaId, userId, "save", csrfToken, callback);
action(mediaId, "save", callback);
}
public void unsave(final String mediaId,
final long userId,
final String csrfToken,
final ServiceCallback<Boolean> callback) {
action(mediaId, userId, "unsave", csrfToken, callback);
action(mediaId, "unsave", callback);
}
private void action(final String mediaId,
final long userId,
final String action,
final String csrfToken,
final ServiceCallback<Boolean> callback) {
final Map<String, Object> form = new HashMap<>(4);
form.put("media_id", mediaId);
form.put("_csrftoken", csrfToken);
form.put("_uid", userId);
form.put("_uuid", UUID.randomUUID().toString());
form.put("_uuid", deviceUuid);
// form.put("radio_type", "wifi-none");
final Map<String, String> signedForm = Utils.sign(form);
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,
@NonNull final String comment,
final long userId,
final String replyToCommentId,
final String csrfToken,
@NonNull final ServiceCallback<Boolean> callback) {
final String module = "self_comments_v2";
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("_csrftoken", csrfToken);
form.put("_uid", userId);
form.put("_uuid", UUID.randomUUID().toString());
form.put("_uuid", deviceUuid);
form.put("comment_text", comment);
form.put("containermodule", module);
if (!TextUtils.isEmpty(replyToCommentId)) {
@ -194,23 +205,19 @@ public class MediaService extends BaseService {
}
public void deleteComment(final String mediaId,
final long userId,
final String commentId,
final String csrfToken,
@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,
final long userId,
final List<String> commentIds,
final String csrfToken,
@NonNull final ServiceCallback<Boolean> callback) {
final Map<String, Object> form = new HashMap<>();
form.put("comment_ids_to_delete", TextUtils.join(",", commentIds));
form.put("_csrftoken", csrfToken);
form.put("_uid", userId);
form.put("_uuid", UUID.randomUUID().toString());
form.put("_uuid", deviceUuid);
final Map<String, String> signedForm = Utils.sign(form);
final Call<String> bulkDeleteRequest = repository.commentsBulkDelete(mediaId, signedForm);
bulkDeleteRequest.enqueue(new Callback<String>() {
@ -241,12 +248,11 @@ public class MediaService extends BaseService {
}
public void commentLike(@NonNull final String commentId,
@NonNull final String csrfToken,
@NonNull final ServiceCallback<Boolean> callback) {
final Map<String, Object> form = new HashMap<>();
form.put("_csrftoken", csrfToken);
// form.put("_uid", userId);
// form.put("_uuid", UUID.randomUUID().toString());
// form.put("_uuid", deviceUuid);
final Map<String, String> signedForm = Utils.sign(form);
final Call<String> commentLikeRequest = repository.commentLike(commentId, signedForm);
commentLikeRequest.enqueue(new Callback<String>() {
@ -277,12 +283,11 @@ public class MediaService extends BaseService {
}
public void commentUnlike(final String commentId,
@NonNull final String csrfToken,
@NonNull final ServiceCallback<Boolean> callback) {
final Map<String, Object> form = new HashMap<>();
form.put("_csrftoken", csrfToken);
// form.put("_uid", userId);
// form.put("_uuid", UUID.randomUUID().toString());
// form.put("_uuid", deviceUuid);
final Map<String, String> signedForm = Utils.sign(form);
final Call<String> commentUnlikeRequest = repository.commentUnlike(commentId, signedForm);
commentUnlikeRequest.enqueue(new Callback<String>() {
@ -313,14 +318,12 @@ public class MediaService extends BaseService {
}
public void editCaption(final String postId,
final long userId,
final String newCaption,
@NonNull final String csrfToken,
@NonNull final ServiceCallback<Boolean> callback) {
final Map<String, Object> form = new HashMap<>();
form.put("_csrftoken", csrfToken);
form.put("_uid", userId);
form.put("_uuid", UUID.randomUUID().toString());
form.put("_uuid", deviceUuid);
form.put("igtv_feed_preview", "false");
form.put("media_id", postId);
form.put("caption_text", newCaption);
@ -411,9 +414,7 @@ public class MediaService extends BaseService {
});
}
public Call<String> uploadFinish(final long userId,
@NonNull final String csrfToken,
@NonNull final UploadFinishOptions options) {
public Call<String> uploadFinish(@NonNull final UploadFinishOptions options) {
if (options.getVideoOptions() != null) {
final UploadFinishOptions.VideoOptions videoOptions = options.getVideoOptions();
if (videoOptions.getClips() == null) {
@ -430,7 +431,7 @@ public class MediaService extends BaseService {
.put("_csrftoken", csrfToken)
.put("source_type", options.getSourceType())
.put("_uid", String.valueOf(userId))
.put("_uuid", UUID.randomUUID().toString())
.put("_uuid", deviceUuid)
.put("upload_id", options.getUploadId());
if (options.getVideoOptions() != null) {
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.repositories.NewsRepository;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.Utils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@ -32,6 +33,7 @@ public class NewsService extends BaseService {
private final NewsRepository repository;
private static NewsService instance;
private static String browserUa, appUa;
private NewsService() {
final Retrofit retrofit = getRetrofitBuilder()
@ -44,13 +46,15 @@ public class NewsService extends BaseService {
if (instance == null) {
instance = new NewsService();
}
appUa = Utils.settingsHelper.getString(Constants.APP_UA);
browserUa = Utils.settingsHelper.getString(Constants.BROWSER_UA);
return instance;
}
public void fetchAppInbox(final boolean markAsSeen,
final ServiceCallback<List<NotificationModel>> callback) {
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>() {
@Override
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,
final ServiceCallback<List<NotificationModel>> callback) {
final Call<String> request = repository.webInbox();
final Call<String> request = repository.webInbox(browserUa);
request.enqueue(new Callback<String>() {
@Override
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.getString("profile_name"),
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,
notificationType);
}
@ -206,7 +210,7 @@ public class NewsService extends BaseService {
form.put("device_id", UUID.randomUUID().toString());
form.put("module", "discover_people");
form.put("paginate", "false");
final Call<String> request = repository.getAyml(form);
final Call<String> request = repository.getAyml(appUa, form);
request.enqueue(new Callback<String>() {
@Override
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,
final ServiceCallback<List<StoryModel>> callback) {
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 isHashtag = options.getType() == StoryViewerOptions.Type.HASHTAG;
final boolean isHighlight = options.getType() == StoryViewerOptions.Type.HIGHLIGHT;
@ -400,7 +400,7 @@ public class StoriesService extends BaseService {
form.put(arg1, arg2);
final Map<String, String> signedForm = Utils.sign(form);
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>() {
@Override
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.responses.PostsFetchResponse;
import awais.instagrabber.repositories.responses.TagFeedResponse;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.TextUtils;
import retrofit2.Call;
import retrofit2.Callback;
@ -46,12 +45,11 @@ public class TagsService extends BaseService {
return instance;
}
public void follow(@NonNull final String tag,
public void follow(@NonNull final String ua,
@NonNull final String tag,
@NonNull final String csrfToken,
final ServiceCallback<Boolean> callback) {
final Call<String> request = webRepository.follow(Constants.USER_AGENT,
csrfToken,
tag);
final Call<String> request = webRepository.follow(ua, csrfToken, tag);
request.enqueue(new Callback<String>() {
@Override
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,
final ServiceCallback<Boolean> callback) {
final Call<String> request = webRepository.unfollow(Constants.USER_AGENT,
csrfToken,
tag);
final Call<String> request = webRepository.unfollow(ua, csrfToken, tag);
request.enqueue(new Callback<String>() {
@Override
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:paddingStart="0dp"
android:paddingEnd="8dp"
android:layout_margin="8dp"
app:layout_constraintBottom_toTopOf="@id/mute_mentions"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/title_edit_input_layout" />
@ -98,6 +99,7 @@
android:layout_height="wrap_content"
android:paddingStart="0dp"
android:paddingEnd="8dp"
android:layout_margin="8dp"
app:layout_constraintBottom_toTopOf="@id/leave"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/mute_messages" />