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

244 lines
10 KiB
Java
Raw Normal View History

2020-10-17 10:07:03 +00:00
package awais.instagrabber.webservices;
import android.os.Handler;
import android.util.Log;
import androidx.annotation.NonNull;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import awais.instagrabber.models.FeedModel;
2020-12-26 18:14:08 +00:00
import awais.instagrabber.models.ProfileModel;
2020-12-20 18:35:16 +00:00
import awais.instagrabber.repositories.GraphQLRepository;
2020-12-26 18:14:08 +00:00
import awais.instagrabber.repositories.responses.GraphQLUserListFetchResponse;
import awais.instagrabber.repositories.responses.PostsFetchResponse;
2020-10-17 10:07:03 +00:00
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.ResponseBodyUtils;
import awais.instagrabber.utils.TextUtils;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
2020-12-20 18:35:16 +00:00
public class GraphQLService extends BaseService {
private static final String TAG = "GraphQLService";
2020-10-17 10:07:03 +00:00
private static final boolean loadFromMock = false;
2020-12-20 18:35:16 +00:00
private final GraphQLRepository repository;
2020-10-17 10:07:03 +00:00
2020-12-20 18:35:16 +00:00
private static GraphQLService instance;
2020-10-17 10:07:03 +00:00
2020-12-20 18:35:16 +00:00
private GraphQLService() {
2020-10-17 10:07:03 +00:00
final Retrofit retrofit = getRetrofitBuilder()
.baseUrl("https://www.instagram.com")
.build();
2020-12-20 18:35:16 +00:00
repository = retrofit.create(GraphQLRepository.class);
2020-10-17 10:07:03 +00:00
}
2020-12-20 18:35:16 +00:00
public static GraphQLService getInstance() {
2020-10-17 10:07:03 +00:00
if (instance == null) {
2020-12-20 18:35:16 +00:00
instance = new GraphQLService();
2020-10-17 10:07:03 +00:00
}
return instance;
}
2020-12-20 18:35:16 +00:00
private void fetch(final String queryHash,
final String variables,
final String arg1,
final String arg2,
final ServiceCallback<PostsFetchResponse> callback) {
2020-10-17 10:07:03 +00:00
final Map<String, String> queryMap = new HashMap<>();
2020-12-20 18:35:16 +00:00
queryMap.put("query_hash", queryHash);
queryMap.put("variables", variables);
2020-10-17 10:07:03 +00:00
final Call<String> request = repository.fetch(queryMap);
request.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
try {
// Log.d(TAG, "onResponse: body: " + response.body());
2020-12-20 18:35:16 +00:00
final PostsFetchResponse postsFetchResponse = parsePostResponse(response, arg1, arg2);
2020-10-17 10:07:03 +00:00
if (callback != null) {
callback.onSuccess(postsFetchResponse);
2020-10-17 10:07:03 +00:00
}
} catch (JSONException e) {
Log.e(TAG, "onResponse", e);
if (callback != null) {
callback.onFailure(e);
}
}
}
@Override
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
if (callback != null) {
callback.onFailure(t);
}
}
});
2020-12-20 18:35:16 +00:00
}
public void fetchLocationPosts(@NonNull final String locationId,
final String maxId,
final ServiceCallback<PostsFetchResponse> callback) {
fetch("36bd0f2bf5911908de389b8ceaa3be6d",
"{\"id\":\"" + locationId + "\"," +
"\"first\":25," +
"\"after\":\"" + (maxId == null ? "" : maxId) + "\"}",
Constants.EXTRAS_LOCATION,
"edge_location_to_media",
callback);
}
public void fetchHashtagPosts(@NonNull final String tag,
final String maxId,
final ServiceCallback<PostsFetchResponse> callback) {
fetch("9b498c08113f1e09617a1703c22b2f32",
"{\"tag_name\":\"" + tag + "\"," +
"\"first\":25," +
"\"after\":\"" + (maxId == null ? "" : maxId) + "\"}",
Constants.EXTRAS_HASHTAG,
"edge_hashtag_to_media",
callback);
}
public void fetchProfilePosts(@NonNull final String profileId,
final int postsPerPage,
final String maxId,
final ServiceCallback<PostsFetchResponse> callback) {
fetch("18a7b935ab438c4514b1f742d8fa07a7",
"{\"id\":\"" + profileId + "\"," +
"\"first\":" + postsPerPage + "," +
"\"after\":\"" + (maxId == null ? "" : maxId) + "\"}",
Constants.EXTRAS_USER,
"edge_owner_to_timeline_media",
callback);
}
2020-10-17 10:07:03 +00:00
2020-12-20 18:35:16 +00:00
public void fetchTaggedPosts(@NonNull final String profileId,
final int postsPerPage,
final String maxId,
final ServiceCallback<PostsFetchResponse> callback) {
fetch("31fe64d9463cbbe58319dced405c6206",
"{\"id\":\"" + profileId + "\"," +
"\"first\":" + postsPerPage + "," +
"\"after\":\"" + (maxId == null ? "" : maxId) + "\"}",
Constants.EXTRAS_USER,
"edge_user_to_photos_of_you",
callback);
2020-10-17 10:07:03 +00:00
}
@NonNull
2020-12-20 18:35:16 +00:00
private PostsFetchResponse parsePostResponse(@NonNull final Response<String> response, @NonNull final String arg1, @NonNull final String arg2) throws JSONException {
2020-10-17 10:07:03 +00:00
if (TextUtils.isEmpty(response.body())) {
Log.e(TAG, "parseResponse: feed response body is empty with status code: " + response.code());
return new PostsFetchResponse(Collections.emptyList(), false, null);
2020-10-17 10:07:03 +00:00
}
2020-12-20 18:35:16 +00:00
return parseResponseBody(response.body(), arg1, arg2);
2020-10-17 10:07:03 +00:00
}
@NonNull
2020-12-20 18:35:16 +00:00
private PostsFetchResponse parseResponseBody(@NonNull final String body, @NonNull final String arg1, @NonNull final String arg2)
2020-10-17 10:07:03 +00:00
throws JSONException {
final List<FeedModel> feedModels = new ArrayList<>();
final JSONObject timelineFeed = new JSONObject(body)
.getJSONObject("data")
2020-12-20 18:35:16 +00:00
.getJSONObject(arg1)
.getJSONObject(arg2);
2020-10-17 10:07:03 +00:00
final String endCursor;
final boolean hasNextPage;
final JSONObject pageInfo = timelineFeed.getJSONObject("page_info");
if (pageInfo.has("has_next_page")) {
hasNextPage = pageInfo.getBoolean("has_next_page");
endCursor = hasNextPage ? pageInfo.getString("end_cursor") : null;
} else {
hasNextPage = false;
endCursor = null;
}
final JSONArray feedItems = timelineFeed.getJSONArray("edges");
for (int i = 0; i < feedItems.length(); ++i) {
final JSONObject itemJson = feedItems.optJSONObject(i);
if (itemJson == null) {
2020-10-17 10:07:03 +00:00
continue;
}
2020-11-13 23:37:19 +00:00
final FeedModel feedModel = ResponseBodyUtils.parseGraphQLItem(itemJson);
if (feedModel != null) {
feedModels.add(feedModel);
}
2020-10-17 10:07:03 +00:00
}
return new PostsFetchResponse(feedModels, hasNextPage, endCursor);
2020-10-17 10:07:03 +00:00
}
2020-12-26 18:14:08 +00:00
public void fetchCommentLikers(final String commentId,
final String endCursor,
final ServiceCallback<GraphQLUserListFetchResponse> callback) {
final Map<String, String> queryMap = new HashMap<>();
queryMap.put("query_hash", "5f0b1f6281e72053cbc07909c8d154ae");
queryMap.put("variables", "{\"comment_id\":\"" + commentId + "\"," +
"\"first\":30," +
"\"after\":\"" + (endCursor == null ? "" : endCursor) + "\"}");
final Call<String> request = repository.fetch(queryMap);
request.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull final Call<String> call, @NonNull final Response<String> response) {
final String rawBody = response.body();
if (rawBody == null) {
Log.e(TAG, "Error occurred while fetching gql comment likes of "+commentId);
callback.onSuccess(null);
return;
}
try {
final JSONObject body = new JSONObject(rawBody);
final String status = body.getString("status");
final JSONObject data = body.getJSONObject("data").getJSONObject("comment").getJSONObject("edge_liked_by");
final JSONObject pageInfo = data.getJSONObject("page_info");
final String endCursor = pageInfo.getBoolean("has_next_page") ? pageInfo.getString("end_cursor") : null;
final JSONArray users = data.getJSONArray("edges");
final int usersLen = users.length();
final List<ProfileModel> userModels = new ArrayList<>();
for (int j = 0; j < usersLen; ++j) {
final JSONObject userObject = users.getJSONObject(j).getJSONObject("node");
userModels.add(new ProfileModel(userObject.optBoolean("is_private"),
false,
userObject.optBoolean("is_verified"),
userObject.getString("id"),
userObject.getString("username"),
userObject.optString("full_name"),
null, null,
userObject.getString("profile_pic_url"),
null, 0, 0, 0, false, false, false, false, false));
}
callback.onSuccess(new GraphQLUserListFetchResponse(endCursor, status, userModels));
} catch (JSONException e) {
Log.e(TAG, "onResponse", e);
if (callback != null) {
callback.onFailure(e);
}
}
}
@Override
public void onFailure(@NonNull final Call<String> call, @NonNull final Throwable t) {
if (callback != null) {
callback.onFailure(t);
}
}
});
}
2020-10-17 10:07:03 +00:00
}