fix story seen

This commit is contained in:
Austin Huang 2021-03-04 12:33:59 -05:00
parent de86668caf
commit 5421bb4592
No known key found for this signature in database
GPG Key ID: 84C23AA04587A91F
9 changed files with 119 additions and 123 deletions

View File

@ -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<Void, Void, Void> {
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;
}
}

View File

@ -276,7 +276,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
fragmentActivity = (MainActivity) requireActivity(); fragmentActivity = (MainActivity) requireActivity();
tagsService = TagsService.getInstance(); tagsService = TagsService.getInstance();
storiesService = StoriesService.getInstance(); storiesService = StoriesService.getInstance(null, 0L, null);
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }

View File

@ -270,7 +270,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR
public void onCreate(@Nullable final Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
fragmentActivity = (MainActivity) requireActivity(); fragmentActivity = (MainActivity) requireActivity();
storiesService = StoriesService.getInstance(); storiesService = StoriesService.getInstance(null, 0L, null);
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }

View File

@ -119,7 +119,7 @@ public final class StoryListViewerFragment extends Fragment implements SwipeRefr
fragmentActivity = (AppCompatActivity) requireActivity(); fragmentActivity = (AppCompatActivity) requireActivity();
context = getContext(); context = getContext();
if (context == null) return; if (context == null) return;
storiesService = StoriesService.getInstance(); storiesService = StoriesService.getInstance(null, 0L, null);
} }
@NonNull @NonNull

View File

@ -71,7 +71,6 @@ import awais.instagrabber.R;
import awais.instagrabber.adapters.StoriesAdapter; import awais.instagrabber.adapters.StoriesAdapter;
import awais.instagrabber.asyncs.CreateThreadAction; import awais.instagrabber.asyncs.CreateThreadAction;
import awais.instagrabber.asyncs.PostFetcher; import awais.instagrabber.asyncs.PostFetcher;
import awais.instagrabber.asyncs.SeenAction;
import awais.instagrabber.customviews.helpers.SwipeGestureListener; import awais.instagrabber.customviews.helpers.SwipeGestureListener;
import awais.instagrabber.databinding.FragmentStoryViewerBinding; import awais.instagrabber.databinding.FragmentStoryViewerBinding;
import awais.instagrabber.fragments.main.ProfileFragmentDirections; import awais.instagrabber.fragments.main.ProfileFragmentDirections;
@ -151,17 +150,16 @@ public class StoryViewerFragment extends Fragment {
private DirectMessagesService directMessagesService; private DirectMessagesService directMessagesService;
private final String cookie = settingsHelper.getString(Constants.COOKIE); 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; private StoryViewerOptions options;
@Override @Override
public void onCreate(@Nullable final Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(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(); fragmentActivity = (AppCompatActivity) requireActivity();
storiesService = StoriesService.getInstance(); storiesService = StoriesService.getInstance(csrfToken, userIdFromCookie, deviceId);
if (csrfToken == null) return;
directMessagesService = DirectMessagesService.getInstance(csrfToken, userIdFromCookie, deviceId); directMessagesService = DirectMessagesService.getInstance(csrfToken, userIdFromCookie, deviceId);
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
@ -478,36 +476,32 @@ public class StoryViewerFragment extends Fragment {
poll.getLeftChoice() + " (" + poll.getLeftCount() + ")", poll.getLeftChoice() + " (" + poll.getLeftCount() + ")",
poll.getRightChoice() + " (" + poll.getRightCount() + ")" poll.getRightChoice() + " (" + poll.getRightCount() + ")"
}), (d, w) -> { }), (d, w) -> {
if (!TextUtils.isEmpty(cookie)) { sticking = true;
sticking = true; storiesService.respondToPoll(
storiesService.respondToPoll( currentStory.getStoryMediaId().split("_")[0],
currentStory.getStoryMediaId().split("_")[0], poll.getId(),
poll.getId(), w,
w, new ServiceCallback<StoryStickerResponse>() {
userIdFromCookie, @Override
csrfToken, public void onSuccess(final StoryStickerResponse result) {
new ServiceCallback<StoryStickerResponse>() { sticking = false;
@Override try {
public void onSuccess(final StoryStickerResponse result) { poll.setMyChoice(w);
sticking = false; Toast.makeText(context, R.string.votef_story_poll, Toast.LENGTH_SHORT).show();
try {
poll.setMyChoice(w);
Toast.makeText(context, R.string.votef_story_poll, Toast.LENGTH_SHORT).show();
}
catch (Exception ignored) {}
} }
catch (Exception ignored) {}
}
@Override @Override
public void onFailure(final Throwable t) { public void onFailure(final Throwable t) {
sticking = false; sticking = false;
Log.e(TAG, "Error responding", t); Log.e(TAG, "Error responding", t);
try { try {
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show();
}
catch (Exception ignored) {}
} }
}); catch (Exception ignored) {}
} }
});
}) })
.setPositiveButton(R.string.cancel, null) .setPositiveButton(R.string.cancel, null)
.show(); .show();
@ -525,8 +519,6 @@ public class StoryViewerFragment extends Fragment {
currentStory.getStoryMediaId().split("_")[0], currentStory.getStoryMediaId().split("_")[0],
question.getId(), question.getId(),
input.getText().toString(), input.getText().toString(),
userIdFromCookie,
csrfToken,
new ServiceCallback<StoryStickerResponse>() { new ServiceCallback<StoryStickerResponse>() {
@Override @Override
public void onSuccess(final StoryStickerResponse result) { public void onSuccess(final StoryStickerResponse result) {
@ -565,14 +557,12 @@ public class StoryViewerFragment extends Fragment {
new AlertDialog.Builder(context) new AlertDialog.Builder(context)
.setTitle(quiz.getMyChoice() > -1 ? getString(R.string.story_quizzed) : quiz.getQuestion()) .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) -> { .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; sticking = true;
storiesService.respondToQuiz( storiesService.respondToQuiz(
currentStory.getStoryMediaId().split("_")[0], currentStory.getStoryMediaId().split("_")[0],
quiz.getId(), quiz.getId(),
w, w,
userIdFromCookie,
csrfToken,
new ServiceCallback<StoryStickerResponse>() { new ServiceCallback<StoryStickerResponse>() {
@Override @Override
public void onSuccess(final StoryStickerResponse result) { public void onSuccess(final StoryStickerResponse result) {
@ -643,8 +633,6 @@ public class StoryViewerFragment extends Fragment {
currentStory.getStoryMediaId().split("_")[0], currentStory.getStoryMediaId().split("_")[0],
slider.getId(), slider.getId(),
sliderValue, sliderValue,
userIdFromCookie,
csrfToken,
new ServiceCallback<StoryStickerResponse>() { new ServiceCallback<StoryStickerResponse>() {
@Override @Override
public void onSuccess(final StoryStickerResponse result) { public void onSuccess(final StoryStickerResponse result) {
@ -868,7 +856,7 @@ public class StoryViewerFragment extends Fragment {
binding.poll.setTag(poll); binding.poll.setTag(poll);
question = currentStory.getQuestion(); 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); binding.answer.setTag(question);
mentions = currentStory.getMentions(); mentions = currentStory.getMentions();
@ -909,7 +897,11 @@ public class StoryViewerFragment extends Fragment {
actionBar.setSubtitle(Utils.datetimeParser.format(new Date(currentStory.getTimestamp() * 1000L))); 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() { private void downloadStory() {
@ -947,7 +939,7 @@ public class StoryViewerFragment extends Fragment {
if (menuDownload != null) { if (menuDownload != null) {
menuDownload.setVisible(true); menuDownload.setVisible(true);
} }
if (currentStory.canReply() && menuDm != null && !TextUtils.isEmpty(cookie)) { if (currentStory.canReply() && menuDm != null) {
menuDm.setVisible(true); menuDm.setVisible(true);
} }
binding.progressView.setVisibility(View.GONE); binding.progressView.setVisibility(View.GONE);
@ -980,7 +972,7 @@ public class StoryViewerFragment extends Fragment {
@NonNull final LoadEventInfo loadEventInfo, @NonNull final LoadEventInfo loadEventInfo,
@NonNull final MediaLoadData mediaLoadData) { @NonNull final MediaLoadData mediaLoadData) {
if (menuDownload != null) menuDownload.setVisible(true); if (menuDownload != null) menuDownload.setVisible(true);
if (currentStory.canReply() && menuDm != null && !TextUtils.isEmpty(cookie)) if (currentStory.canReply() && menuDm != null)
menuDm.setVisible(true); menuDm.setVisible(true);
binding.progressView.setVisibility(View.GONE); binding.progressView.setVisibility(View.GONE);
} }
@ -991,7 +983,7 @@ public class StoryViewerFragment extends Fragment {
@NonNull final LoadEventInfo loadEventInfo, @NonNull final LoadEventInfo loadEventInfo,
@NonNull final MediaLoadData mediaLoadData) { @NonNull final MediaLoadData mediaLoadData) {
if (menuDownload != null) menuDownload.setVisible(true); if (menuDownload != null) menuDownload.setVisible(true);
if (currentStory.canReply() && menuDm != null && !TextUtils.isEmpty(cookie)) if (currentStory.canReply() && menuDm != null)
menuDm.setVisible(true); menuDm.setVisible(true);
binding.progressView.setVisibility(View.VISIBLE); binding.progressView.setVisibility(View.VISIBLE);
} }

View File

@ -259,7 +259,7 @@ public class FeedFragment extends Fragment implements SwipeRefreshLayout.OnRefre
public void onCreate(@Nullable final Bundle savedInstanceState) { public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
fragmentActivity = (MainActivity) requireActivity(); fragmentActivity = (MainActivity) requireActivity();
storiesService = StoriesService.getInstance(); storiesService = StoriesService.getInstance(null, 0L, null);
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }

View File

@ -307,7 +307,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie); final String csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
fragmentActivity = (MainActivity) requireActivity(); fragmentActivity = (MainActivity) requireActivity();
friendshipService = isLoggedIn ? FriendshipService.getInstance(deviceUuid, csrfToken, userId) : null; 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; mediaService = isLoggedIn ? MediaService.getInstance(null, null, 0) : null;
accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext())); accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext()));
favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext())); favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext()));

View File

@ -36,4 +36,8 @@ public interface StoriesRepository {
@Path("action") String action, @Path("action") String action,
// story_poll_vote, story_question_response, story_slider_vote, story_quiz_answer // story_poll_vote, story_question_response, story_slider_vote, story_quiz_answer
@FieldMap Map<String, String> form); @FieldMap Map<String, String> form);
@FormUrlEncoded
@POST("/api/v2/media/seen/")
Call<String> seen(@QueryMap Map<String, String> queryParams, @FieldMap Map<String, String> form);
} }

View File

@ -14,7 +14,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TimeZone; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import awais.instagrabber.models.FeedStoryModel; import awais.instagrabber.models.FeedStoryModel;
@ -37,20 +37,45 @@ import retrofit2.Retrofit;
public class StoriesService extends BaseService { public class StoriesService extends BaseService {
private static final String TAG = "StoriesService"; private static final String TAG = "StoriesService";
private final StoriesRepository repository;
private static StoriesService instance; 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() final Retrofit retrofit = getRetrofitBuilder()
.baseUrl("https://i.instagram.com") .baseUrl("https://i.instagram.com")
.build(); .build();
repository = retrofit.create(StoriesRepository.class); repository = retrofit.create(StoriesRepository.class);
} }
public static StoriesService getInstance() { public String getCsrfToken() {
if (instance == null) { return csrfToken;
instance = new StoriesService(); }
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; return instance;
} }
@ -391,13 +416,11 @@ public class StoriesService extends BaseService {
final String action, final String action,
final String arg1, final String arg1,
final String arg2, final String arg2,
final long userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) { final ServiceCallback<StoryStickerResponse> callback) {
final Map<String, Object> form = new HashMap<>(); final Map<String, Object> form = new HashMap<>();
form.put("_csrftoken", csrfToken); form.put("_csrftoken", csrfToken);
form.put("_uid", userId); form.put("_uid", userId);
form.put("_uuid", UUID.randomUUID().toString()); form.put("_uuid", deviceUuid);
form.put("mutation_token", UUID.randomUUID().toString()); form.put("mutation_token", UUID.randomUUID().toString());
form.put("client_context", UUID.randomUUID().toString()); form.put("client_context", UUID.randomUUID().toString());
form.put("radio_type", "wifi-none"); form.put("radio_type", "wifi-none");
@ -428,39 +451,67 @@ public class StoriesService extends BaseService {
public void respondToQuestion(final String storyId, public void respondToQuestion(final String storyId,
final String stickerId, final String stickerId,
final String answer, final String answer,
final long userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) { final ServiceCallback<StoryStickerResponse> callback) {
respondToSticker(storyId, stickerId, "story_question_response", "response", answer, userId, csrfToken, callback); respondToSticker(storyId, stickerId, "story_question_response", "response", answer, callback);
} }
// QuizAction.java // QuizAction.java
public void respondToQuiz(final String storyId, public void respondToQuiz(final String storyId,
final String stickerId, final String stickerId,
final int answer, final int answer,
final long userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) { final ServiceCallback<StoryStickerResponse> 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 // VoteAction.java
public void respondToPoll(final String storyId, public void respondToPoll(final String storyId,
final String stickerId, final String stickerId,
final int answer, final int answer,
final long userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) { final ServiceCallback<StoryStickerResponse> 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, public void respondToSlider(final String storyId,
final String stickerId, final String stickerId,
final double answer, final double answer,
final long userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) { final ServiceCallback<StoryStickerResponse> 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<String> callback) {
final Map<String, Object> form = new HashMap<>();
form.put("_csrftoken", csrfToken);
form.put("_uid", userId);
form.put("_uuid", deviceUuid);
form.put("container_module", "feed_timeline");
final Map<String, Object> reelsForm = new HashMap<>();
reelsForm.put(storyMediaId, Collections.singletonList(takenAt + "_" + seenAt));
form.put("reels", reelsForm);
final Map<String, String> signedForm = Utils.sign(form);
final Map<String, String> queryMap = new HashMap<>();
queryMap.put("reel", "1");
queryMap.put("live_vod", "0");
final Call<String> request = repository.seen(queryMap, signedForm);
request.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull final Call<String> call,
@NonNull final Response<String> response) {
if (callback != null) {
callback.onSuccess(response.body());
}
}
@Override
public void onFailure(@NonNull final Call<String> call,
@NonNull final Throwable t) {
if (callback != null) {
callback.onFailure(t);
}
}
});
} }
@Nullable @Nullable