BarInsta/app/src/main/java/awais/instagrabber/webservices/StoriesService.java

341 lines
15 KiB
Java
Raw Normal View History

package awais.instagrabber.webservices;
2020-08-29 08:01:42 +00:00
import android.util.Log;
import androidx.annotation.NonNull;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
2020-08-29 08:01:42 +00:00
import awais.instagrabber.models.FeedStoryModel;
2020-12-20 18:35:16 +00:00
import awais.instagrabber.models.HighlightModel;
2020-08-29 08:01:42 +00:00
import awais.instagrabber.models.ProfileModel;
import awais.instagrabber.models.StoryModel;
import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.models.stickers.PollModel;
import awais.instagrabber.models.stickers.QuestionModel;
import awais.instagrabber.models.stickers.QuizModel;
import awais.instagrabber.models.stickers.SliderModel;
import awais.instagrabber.models.stickers.SwipeUpModel;
2020-08-29 08:01:42 +00:00
import awais.instagrabber.repositories.StoriesRepository;
import awais.instagrabber.repositories.responses.StoryStickerResponse;
2020-08-29 08:01:42 +00:00
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.ResponseBodyUtils;
2020-12-20 18:35:16 +00:00
import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils;
2020-08-29 08:01:42 +00:00
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
public class StoriesService extends BaseService {
private static final String TAG = "StoriesService";
2020-10-17 10:07:03 +00:00
private static final boolean loadFromMock = false;
2020-08-29 08:01:42 +00:00
private final StoriesRepository repository;
private static StoriesService instance;
private StoriesService() {
final Retrofit retrofit = getRetrofitBuilder()
.baseUrl("https://i.instagram.com")
2020-08-29 08:01:42 +00:00
.build();
repository = retrofit.create(StoriesRepository.class);
}
public static StoriesService getInstance() {
if (instance == null) {
instance = new StoriesService();
}
return instance;
}
public void fetch(final String mediaId,
final ServiceCallback<StoryModel> callback) {
final Call<String> request = repository.fetch(mediaId);
request.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull final Call<String> call,
@NonNull final Response<String> response) {
if (callback == null) return;
final String body = response.body();
if (body == null) {
callback.onSuccess(null);
return;
}
try {
final JSONObject itemJson = new JSONObject(body).getJSONArray("items").getJSONObject(0);
callback.onSuccess(ResponseBodyUtils.parseStoryItem(itemJson, false, false, null));
} catch (JSONException e) {
callback.onFailure(e);
}
}
@Override
public void onFailure(@NonNull final Call<String> call,
@NonNull final Throwable t) {
if (callback != null) {
callback.onFailure(t);
}
}
});
}
public void getFeedStories(final String csrfToken, final ServiceCallback<List<FeedStoryModel>> callback) {
final Map<String, Object> form = new HashMap<>(4);
form.put("reason", "cold_start");
form.put("_csrftoken", csrfToken);
form.put("_uuid", UUID.randomUUID().toString());
form.put("supported_capabilities_new", Constants.SUPPORTED_CAPABILITIES);
final Map<String, String> signedForm = Utils.sign(form);
2020-12-20 18:35:16 +00:00
final Call<String> response = repository.getFeedStories(Constants.I_USER_AGENT, signedForm);
2020-08-29 08:01:42 +00:00
response.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
final String body = response.body();
if (body == null) {
Log.e(TAG, "getFeedStories: body is empty");
return;
}
2020-10-17 10:07:03 +00:00
parseStoriesBody(body, callback);
2020-08-29 08:01:42 +00:00
}
@Override
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
callback.onFailure(t);
}
});
}
2020-10-17 10:07:03 +00:00
private void parseStoriesBody(final String body, final ServiceCallback<List<FeedStoryModel>> callback) {
try {
final List<FeedStoryModel> feedStoryModels = new ArrayList<>();
final JSONArray feedStoriesReel = new JSONObject(body).getJSONArray("tray");
2020-10-17 10:07:03 +00:00
for (int i = 0; i < feedStoriesReel.length(); ++i) {
final JSONObject node = feedStoriesReel.getJSONObject(i);
2020-10-17 10:07:03 +00:00
final JSONObject user = node.getJSONObject(node.has("user") ? "user" : "owner");
final ProfileModel profileModel = new ProfileModel(false, false, false,
user.getString("pk"),
2020-10-17 10:07:03 +00:00
user.getString("username"),
null, null, null,
user.getString("profile_pic_url"),
null, 0, 0, 0, false, false, false, false, false);
2020-10-17 10:07:03 +00:00
final String id = node.getString("id");
final boolean fullyRead = !node.isNull("seen") && node.getLong("seen") == node.getLong("latest_reel_media");
feedStoryModels.add(new FeedStoryModel(id, profileModel, fullyRead));
}
callback.onSuccess(feedStoryModels);
} catch (JSONException e) {
Log.e(TAG, "Error parsing json", e);
}
}
2020-12-20 18:35:16 +00:00
public void fetchHighlights(final String profileId,
final ServiceCallback<List<HighlightModel>> callback) {
final Call<String> request = repository.fetchHighlights(profileId);
request.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
try {
if (callback == null) {
return;
}
final String body = response.body();
if (TextUtils.isEmpty(body)) {
callback.onSuccess(null);
return;
}
final JSONArray highlightsReel = new JSONObject(body).getJSONArray("tray");
final int length = highlightsReel.length();
final List<HighlightModel> highlightModels = new ArrayList<>();
// final String[] highlightIds = new String[length];
for (int i = 0; i < length; ++i) {
final JSONObject highlightNode = highlightsReel.getJSONObject(i);
highlightModels.add(new HighlightModel(
highlightNode.getString("title"),
highlightNode.getString(Constants.EXTRAS_ID),
highlightNode.getJSONObject("cover_media")
.getJSONObject("cropped_image_version")
.getString("url")
));
}
callback.onSuccess(highlightModels);
} catch (JSONException e) {
Log.e(TAG, "onResponse", e);
callback.onFailure(e);
}
}
@Override
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
if (callback != null) {
callback.onFailure(t);
}
}
});
}
2020-08-29 08:01:42 +00:00
public void getUserStory(final String id,
final String username,
final boolean isLoc,
final boolean isHashtag,
final boolean highlight,
final ServiceCallback<List<StoryModel>> callback) {
2020-09-21 02:36:23 +00:00
final String url = buildUrl(id, isLoc, isHashtag, highlight);
final Call<String> userStoryCall = repository.getUserStory(Constants.I_USER_AGENT, url);
2020-08-29 08:01:42 +00:00
userStoryCall.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
JSONObject data;
String localUsername = username;
try {
final String body = response.body();
if (body == null) {
Log.e(TAG, "body is null");
return;
}
data = new JSONObject(body);
2020-09-21 02:36:23 +00:00
if (!highlight)
2020-08-29 08:01:42 +00:00
data = data.optJSONObject((isLoc || isHashtag) ? "story" : "reel");
else if (highlight) data = data.getJSONObject("reels").optJSONObject(id);
if (data != null
&& localUsername == null
&& !isLoc
&& !isHashtag)
localUsername = data.getJSONObject("user").getString("username");
JSONArray media;
if (data != null
&& (media = data.optJSONArray("items")) != null
&& media.length() > 0 && media.optJSONObject(0) != null) {
final int mediaLen = media.length();
final List<StoryModel> models = new ArrayList<>();
for (int i = 0; i < mediaLen; ++i) {
data = media.getJSONObject(i);
models.add(ResponseBodyUtils.parseStoryItem(data, isLoc, isHashtag, localUsername));
2020-08-29 08:01:42 +00:00
}
callback.onSuccess(models);
2020-10-17 10:07:03 +00:00
} else {
2020-09-26 00:15:46 +00:00
callback.onSuccess(null);
}
2020-08-29 08:01:42 +00:00
} catch (JSONException e) {
Log.e(TAG, "Error parsing string");
}
}
@Override
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
callback.onFailure(t);
}
});
}
private void respondToSticker(final String storyId,
final String stickerId,
final String action,
final String arg1,
final String arg2,
final String userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) {
final Map<String, Object> form = new HashMap<>();
form.put("_csrftoken", csrfToken);
form.put("_uid", userId);
form.put("_uuid", UUID.randomUUID().toString());
form.put("mutation_token", UUID.randomUUID().toString());
form.put("client_context", UUID.randomUUID().toString());
form.put("radio_type", "wifi-none");
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);
request.enqueue(new Callback<StoryStickerResponse>() {
@Override
public void onResponse(@NonNull final Call<StoryStickerResponse> call,
@NonNull final Response<StoryStickerResponse> response) {
if (callback != null) {
callback.onSuccess(response.body());
}
}
@Override
public void onFailure(@NonNull final Call<StoryStickerResponse> call,
@NonNull final Throwable t) {
if (callback != null) {
callback.onFailure(t);
}
}
});
}
// RespondAction.java
public void respondToQuestion(final String storyId,
final String stickerId,
final String answer,
final String userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) {
respondToSticker(storyId, stickerId, "story_question_response", "response", answer, userId, csrfToken, callback);
}
// QuizAction.java
public void respondToQuiz(final String storyId,
final String stickerId,
final int answer,
final String userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) {
respondToSticker(storyId, stickerId, "story_quiz_answer", "answer", String.valueOf(answer), userId, csrfToken, callback);
}
// VoteAction.java
public void respondToPoll(final String storyId,
final String stickerId,
final int answer,
final String userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) {
respondToSticker(storyId, stickerId, "story_poll_vote", "vote", String.valueOf(answer), userId, csrfToken, callback);
}
public void respondToSlider(final String storyId,
final String stickerId,
final double answer,
final String userId,
final String csrfToken,
final ServiceCallback<StoryStickerResponse> callback) {
respondToSticker(storyId, stickerId, "story_slider_vote", "vote", String.valueOf(answer), userId, csrfToken, callback);
}
2020-09-21 02:36:23 +00:00
private String buildUrl(final String id, final boolean isLoc, final boolean isHashtag, final boolean highlight) {
2020-08-29 08:01:42 +00:00
final String userId = id.replace(":", "%3A");
final StringBuilder builder = new StringBuilder();
2020-09-21 02:36:23 +00:00
builder.append("https://i.instagram.com/api/v1/");
2020-08-29 08:01:42 +00:00
if (isLoc) {
builder.append("locations/");
2020-10-17 10:07:03 +00:00
} else if (isHashtag) {
2020-08-29 08:01:42 +00:00
builder.append("tags/");
2020-10-17 10:07:03 +00:00
} else if (highlight) {
builder.append("feed/reels_media/?user_ids=");
2020-10-17 10:07:03 +00:00
} else {
2020-08-29 08:01:42 +00:00
builder.append("feed/user/");
}
builder.append(userId);
if (!highlight) {
2020-09-21 02:36:23 +00:00
builder.append("/story/");
2020-08-29 08:01:42 +00:00
}
return builder.toString();
}
}