From 5421bb4592fd84b7bf51ba2ede85244cc6609b99 Mon Sep 17 00:00:00 2001 From: Austin Huang Date: Thu, 4 Mar 2021 12:33:59 -0500 Subject: [PATCH] fix story seen --- .../awais/instagrabber/asyncs/SeenAction.java | 51 ---------- .../fragments/HashTagFragment.java | 2 +- .../fragments/LocationFragment.java | 2 +- .../fragments/StoryListViewerFragment.java | 2 +- .../fragments/StoryViewerFragment.java | 82 ++++++++-------- .../fragments/main/FeedFragment.java | 2 +- .../fragments/main/ProfileFragment.java | 2 +- .../repositories/StoriesRepository.java | 4 + .../webservices/StoriesService.java | 95 ++++++++++++++----- 9 files changed, 119 insertions(+), 123 deletions(-) delete mode 100644 app/src/main/java/awais/instagrabber/asyncs/SeenAction.java diff --git a/app/src/main/java/awais/instagrabber/asyncs/SeenAction.java b/app/src/main/java/awais/instagrabber/asyncs/SeenAction.java deleted file mode 100644 index 7656369d..00000000 --- a/app/src/main/java/awais/instagrabber/asyncs/SeenAction.java +++ /dev/null @@ -1,51 +0,0 @@ -package awais.instagrabber.asyncs; - -import android.os.AsyncTask; -import android.util.Log; - -import java.io.DataOutputStream; -import java.net.HttpURLConnection; -import java.net.URL; - -import awais.instagrabber.models.StoryModel; -import awais.instagrabber.utils.NetworkUtils; - -public class SeenAction extends AsyncTask { - private static final String TAG = "SeenAction"; - - private final String cookie; - private final StoryModel storyModel; - - public SeenAction(final String cookie, final StoryModel storyModel) { - this.cookie = cookie; - this.storyModel = storyModel; - } - - protected Void doInBackground(Void... voids) { - final String url = "https://www.instagram.com/stories/reel/seen"; - try { - final String urlParameters = "reelMediaId=" + storyModel.getStoryMediaId().split("_")[0] - + "&reelMediaOwnerId=" + storyModel.getUserId() - + "&reelId=" + storyModel.getUserId() - + "&reelMediaTakenAt=" + storyModel.getTimestamp() - + "&viewSeenAt=" + storyModel.getTimestamp(); - final HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection(); - urlConnection.setRequestMethod("POST"); - urlConnection.setUseCaches(false); - urlConnection.setRequestProperty("x-csrftoken", cookie.split("csrftoken=")[1].split(";")[0]); - urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - urlConnection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length)); - urlConnection.setDoOutput(true); - DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream()); - wr.writeBytes(urlParameters); - wr.flush(); - wr.close(); - urlConnection.connect(); - Log.d(TAG, urlConnection.getResponseCode() + " " + NetworkUtils.readFromConnection(urlConnection)); - urlConnection.disconnect(); - } catch (Throwable ex) { - Log.e(TAG, "Error", ex); - } - return null; - } -} diff --git a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java index 12b9b413..550d43e1 100644 --- a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java @@ -276,7 +276,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe super.onCreate(savedInstanceState); fragmentActivity = (MainActivity) requireActivity(); tagsService = TagsService.getInstance(); - storiesService = StoriesService.getInstance(); + storiesService = StoriesService.getInstance(null, 0L, null); setHasOptionsMenu(true); } diff --git a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java index 49e23159..4c1c9618 100644 --- a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java @@ -270,7 +270,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); fragmentActivity = (MainActivity) requireActivity(); - storiesService = StoriesService.getInstance(); + storiesService = StoriesService.getInstance(null, 0L, null); setHasOptionsMenu(true); } diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java index 880af8f5..d71a7cfb 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryListViewerFragment.java @@ -119,7 +119,7 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr fragmentActivity = (AppCompatActivity) requireActivity(); context = getContext(); if (context == null) return; - storiesService = StoriesService.getInstance(); + storiesService = StoriesService.getInstance(null, 0L, null); } @NonNull diff --git a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java index ea38abe8..4a14927a 100644 --- a/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.java @@ -71,7 +71,6 @@ import awais.instagrabber.R; import awais.instagrabber.adapters.StoriesAdapter; import awais.instagrabber.asyncs.CreateThreadAction; import awais.instagrabber.asyncs.PostFetcher; -import awais.instagrabber.asyncs.SeenAction; import awais.instagrabber.customviews.helpers.SwipeGestureListener; import awais.instagrabber.databinding.FragmentStoryViewerBinding; import awais.instagrabber.fragments.main.ProfileFragmentDirections; @@ -151,17 +150,16 @@ public class StoryViewerFragment extends Fragment { private DirectMessagesService directMessagesService; private final String cookie = settingsHelper.getString(Constants.COOKIE); - private final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); - private final long userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie); - private final String deviceId = settingsHelper.getString(Constants.DEVICE_UUID); private StoryViewerOptions options; @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); + final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); + final long userIdFromCookie = CookieUtils.getUserIdFromCookie(cookie); + final String deviceId = settingsHelper.getString(Constants.DEVICE_UUID); fragmentActivity = (AppCompatActivity) requireActivity(); - storiesService = StoriesService.getInstance(); - if (csrfToken == null) return; + storiesService = StoriesService.getInstance(csrfToken, userIdFromCookie, deviceId); directMessagesService = DirectMessagesService.getInstance(csrfToken, userIdFromCookie, deviceId); setHasOptionsMenu(true); } @@ -478,36 +476,32 @@ public class StoryViewerFragment extends Fragment { poll.getLeftChoice() + " (" + poll.getLeftCount() + ")", poll.getRightChoice() + " (" + poll.getRightCount() + ")" }), (d, w) -> { - if (!TextUtils.isEmpty(cookie)) { - sticking = true; - storiesService.respondToPoll( - currentStory.getStoryMediaId().split("_")[0], - poll.getId(), - w, - userIdFromCookie, - csrfToken, - new ServiceCallback() { - @Override - public void onSuccess(final StoryStickerResponse result) { - sticking = false; - try { - poll.setMyChoice(w); - Toast.makeText(context, R.string.votef_story_poll, Toast.LENGTH_SHORT).show(); - } - catch (Exception ignored) {} + sticking = true; + storiesService.respondToPoll( + currentStory.getStoryMediaId().split("_")[0], + poll.getId(), + w, + new ServiceCallback() { + @Override + public void onSuccess(final StoryStickerResponse result) { + sticking = false; + try { + poll.setMyChoice(w); + Toast.makeText(context, R.string.votef_story_poll, Toast.LENGTH_SHORT).show(); } + catch (Exception ignored) {} + } - @Override - public void onFailure(final Throwable t) { - sticking = false; - Log.e(TAG, "Error responding", t); - try { - Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); - } - catch (Exception ignored) {} + @Override + public void onFailure(final Throwable t) { + sticking = false; + Log.e(TAG, "Error responding", t); + try { + Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); } - }); - } + catch (Exception ignored) {} + } + }); }) .setPositiveButton(R.string.cancel, null) .show(); @@ -525,8 +519,6 @@ public class StoryViewerFragment extends Fragment { currentStory.getStoryMediaId().split("_")[0], question.getId(), input.getText().toString(), - userIdFromCookie, - csrfToken, new ServiceCallback() { @Override public void onSuccess(final StoryStickerResponse result) { @@ -565,14 +557,12 @@ public class StoryViewerFragment extends Fragment { new AlertDialog.Builder(context) .setTitle(quiz.getMyChoice() > -1 ? getString(R.string.story_quizzed) : quiz.getQuestion()) .setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, choices), (d, w) -> { - if (quiz.getMyChoice() == -1 && !TextUtils.isEmpty(cookie)) { + if (quiz.getMyChoice() == -1) { sticking = true; storiesService.respondToQuiz( currentStory.getStoryMediaId().split("_")[0], quiz.getId(), w, - userIdFromCookie, - csrfToken, new ServiceCallback() { @Override public void onSuccess(final StoryStickerResponse result) { @@ -643,8 +633,6 @@ public class StoryViewerFragment extends Fragment { currentStory.getStoryMediaId().split("_")[0], slider.getId(), sliderValue, - userIdFromCookie, - csrfToken, new ServiceCallback() { @Override public void onSuccess(final StoryStickerResponse result) { @@ -868,7 +856,7 @@ public class StoryViewerFragment extends Fragment { binding.poll.setTag(poll); question = currentStory.getQuestion(); - binding.answer.setVisibility((question != null && !TextUtils.isEmpty(cookie)) ? View.VISIBLE : View.GONE); + binding.answer.setVisibility((question != null) ? View.VISIBLE : View.GONE); binding.answer.setTag(question); mentions = currentStory.getMentions(); @@ -909,7 +897,11 @@ public class StoryViewerFragment extends Fragment { actionBar.setSubtitle(Utils.datetimeParser.format(new Date(currentStory.getTimestamp() * 1000L))); } - if (settingsHelper.getBoolean(MARK_AS_SEEN)) new SeenAction(cookie, currentStory).execute(); + if (settingsHelper.getBoolean(MARK_AS_SEEN)) + storiesService.seen(currentStory.getStoryMediaId(), + currentStory.getTimestamp(), + System.currentTimeMillis() / 1000, + null); } private void downloadStory() { @@ -947,7 +939,7 @@ public class StoryViewerFragment extends Fragment { if (menuDownload != null) { menuDownload.setVisible(true); } - if (currentStory.canReply() && menuDm != null && !TextUtils.isEmpty(cookie)) { + if (currentStory.canReply() && menuDm != null) { menuDm.setVisible(true); } binding.progressView.setVisibility(View.GONE); @@ -980,7 +972,7 @@ public class StoryViewerFragment extends Fragment { @NonNull final LoadEventInfo loadEventInfo, @NonNull final MediaLoadData mediaLoadData) { if (menuDownload != null) menuDownload.setVisible(true); - if (currentStory.canReply() && menuDm != null && !TextUtils.isEmpty(cookie)) + if (currentStory.canReply() && menuDm != null) menuDm.setVisible(true); binding.progressView.setVisibility(View.GONE); } @@ -991,7 +983,7 @@ public class StoryViewerFragment extends Fragment { @NonNull final LoadEventInfo loadEventInfo, @NonNull final MediaLoadData mediaLoadData) { if (menuDownload != null) menuDownload.setVisible(true); - if (currentStory.canReply() && menuDm != null && !TextUtils.isEmpty(cookie)) + if (currentStory.canReply() && menuDm != null) menuDm.setVisible(true); binding.progressView.setVisibility(View.VISIBLE); } diff --git a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java index 54f6ea25..f4b8d47e 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/FeedFragment.java @@ -259,7 +259,7 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); fragmentActivity = (MainActivity) requireActivity(); - storiesService = StoriesService.getInstance(); + storiesService = StoriesService.getInstance(null, 0L, null); setHasOptionsMenu(true); } diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 3a7586ed..2ead6157 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -307,7 +307,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); fragmentActivity = (MainActivity) requireActivity(); friendshipService = isLoggedIn ? FriendshipService.getInstance(deviceUuid, csrfToken, userId) : null; - storiesService = isLoggedIn ? StoriesService.getInstance() : null; + storiesService = isLoggedIn ? StoriesService.getInstance(null, 0L, null) : null; mediaService = isLoggedIn ? MediaService.getInstance(null, null, 0) : null; accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext())); favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext())); diff --git a/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java b/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java index 6eaa83ba..766649c4 100644 --- a/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java +++ b/app/src/main/java/awais/instagrabber/repositories/StoriesRepository.java @@ -36,4 +36,8 @@ public interface StoriesRepository { @Path("action") String action, // story_poll_vote, story_question_response, story_slider_vote, story_quiz_answer @FieldMap Map form); + + @FormUrlEncoded + @POST("/api/v2/media/seen/") + Call seen(@QueryMap Map queryParams, @FieldMap Map form); } diff --git a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java index bc6ca65a..3f84226c 100644 --- a/app/src/main/java/awais/instagrabber/webservices/StoriesService.java +++ b/app/src/main/java/awais/instagrabber/webservices/StoriesService.java @@ -14,7 +14,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.TimeZone; +import java.util.Objects; import java.util.UUID; import awais.instagrabber.models.FeedStoryModel; @@ -37,20 +37,45 @@ import retrofit2.Retrofit; public class StoriesService extends BaseService { private static final String TAG = "StoriesService"; - private final StoriesRepository repository; - private static StoriesService instance; - private StoriesService() { + private final StoriesRepository repository; + private final String csrfToken; + private final long userId; + private final String deviceUuid; + + private StoriesService(@NonNull final String csrfToken, + final long userId, + @NonNull final String deviceUuid) { + this.csrfToken = csrfToken; + this.userId = userId; + this.deviceUuid = deviceUuid; final Retrofit retrofit = getRetrofitBuilder() .baseUrl("https://i.instagram.com") .build(); repository = retrofit.create(StoriesRepository.class); } - public static StoriesService getInstance() { - if (instance == null) { - instance = new StoriesService(); + public String getCsrfToken() { + return csrfToken; + } + + public long getUserId() { + return userId; + } + + public String getDeviceUuid() { + return deviceUuid; + } + + public static StoriesService getInstance(final String csrfToken, + final long userId, + final String deviceUuid) { + if (instance == null + || !Objects.equals(instance.getCsrfToken(), csrfToken) + || !Objects.equals(instance.getUserId(), userId) + || !Objects.equals(instance.getDeviceUuid(), deviceUuid)) { + instance = new StoriesService(csrfToken, userId, deviceUuid); } return instance; } @@ -391,13 +416,11 @@ public class StoriesService extends BaseService { final String action, final String arg1, final String arg2, - final long userId, - final String csrfToken, final ServiceCallback callback) { final Map form = new HashMap<>(); form.put("_csrftoken", csrfToken); form.put("_uid", userId); - form.put("_uuid", UUID.randomUUID().toString()); + form.put("_uuid", deviceUuid); form.put("mutation_token", UUID.randomUUID().toString()); form.put("client_context", UUID.randomUUID().toString()); form.put("radio_type", "wifi-none"); @@ -428,39 +451,67 @@ public class StoriesService extends BaseService { public void respondToQuestion(final String storyId, final String stickerId, final String answer, - final long userId, - final String csrfToken, final ServiceCallback callback) { - respondToSticker(storyId, stickerId, "story_question_response", "response", answer, userId, csrfToken, callback); + respondToSticker(storyId, stickerId, "story_question_response", "response", answer, callback); } // QuizAction.java public void respondToQuiz(final String storyId, final String stickerId, final int answer, - final long userId, - final String csrfToken, final ServiceCallback callback) { - respondToSticker(storyId, stickerId, "story_quiz_answer", "answer", String.valueOf(answer), userId, csrfToken, callback); + respondToSticker(storyId, stickerId, "story_quiz_answer", "answer", String.valueOf(answer), callback); } // VoteAction.java public void respondToPoll(final String storyId, final String stickerId, final int answer, - final long userId, - final String csrfToken, final ServiceCallback callback) { - respondToSticker(storyId, stickerId, "story_poll_vote", "vote", String.valueOf(answer), userId, csrfToken, callback); + respondToSticker(storyId, stickerId, "story_poll_vote", "vote", String.valueOf(answer), callback); } public void respondToSlider(final String storyId, final String stickerId, final double answer, - final long userId, - final String csrfToken, final ServiceCallback callback) { - respondToSticker(storyId, stickerId, "story_slider_vote", "vote", String.valueOf(answer), userId, csrfToken, callback); + respondToSticker(storyId, stickerId, "story_slider_vote", "vote", String.valueOf(answer), callback); + } + + public void seen(final String storyMediaId, + final long takenAt, + final long seenAt, + final ServiceCallback callback) { + final Map form = new HashMap<>(); + form.put("_csrftoken", csrfToken); + form.put("_uid", userId); + form.put("_uuid", deviceUuid); + form.put("container_module", "feed_timeline"); + final Map reelsForm = new HashMap<>(); + reelsForm.put(storyMediaId, Collections.singletonList(takenAt + "_" + seenAt)); + form.put("reels", reelsForm); + final Map signedForm = Utils.sign(form); + final Map queryMap = new HashMap<>(); + queryMap.put("reel", "1"); + queryMap.put("live_vod", "0"); + final Call request = repository.seen(queryMap, signedForm); + request.enqueue(new Callback() { + @Override + public void onResponse(@NonNull final Call call, + @NonNull final Response response) { + if (callback != null) { + callback.onSuccess(response.body()); + } + } + + @Override + public void onFailure(@NonNull final Call call, + @NonNull final Throwable t) { + if (callback != null) { + callback.onFailure(t); + } + } + }); } @Nullable