private api option for profilefetcher

This commit is contained in:
Austin Huang 2021-01-23 14:17:56 -05:00
parent 8dabf35146
commit 78e3ffe04a
No known key found for this signature in database
GPG Key ID: 84C23AA04587A91F
10 changed files with 214 additions and 115 deletions

View File

@ -5,131 +5,81 @@ import android.util.Log;
import androidx.annotation.Nullable;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.net.HttpURLConnection;
import java.net.URL;
import awais.instagrabber.BuildConfig;
import awais.instagrabber.interfaces.FetchListener;
import awais.instagrabber.repositories.responses.FriendshipStatus;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.CookieUtils;
import awais.instagrabber.utils.NetworkUtils;
import awais.instagrabber.utils.TextUtils;
import awaisomereport.LogCollector;
import awais.instagrabber.webservices.GraphQLService;
import awais.instagrabber.webservices.ServiceCallback;
import awais.instagrabber.webservices.UserService;
import static awais.instagrabber.utils.Utils.logCollector;
import static awais.instagrabber.utils.Utils.settingsHelper;
public final class ProfileFetcher extends AsyncTask<Void, Void, User> {
public final class ProfileFetcher extends AsyncTask<Void, Void, String> {
private static final String TAG = ProfileFetcher.class.getSimpleName();
private final UserService userService;
private final GraphQLService graphQLService;
private final FetchListener<User> fetchListener;
private final boolean isLoggedIn;
private final String userName;
public ProfileFetcher(String userName, FetchListener<User> fetchListener) {
public ProfileFetcher(final String userName,
final boolean isLoggedIn,
final FetchListener<User> fetchListener) {
this.userName = userName;
this.isLoggedIn = isLoggedIn;
this.fetchListener = fetchListener;
userService = isLoggedIn ? UserService.getInstance() : null;
graphQLService = isLoggedIn ? null : GraphQLService.getInstance();
}
@Nullable
@Override
protected User doInBackground(final Void... voids) {
User result = null;
protected String doInBackground(final Void... voids) {
if (isLoggedIn) {
userService.getUsernameInfo(userName, new ServiceCallback<User>() {
@Override
public void onSuccess(final User user) {
Log.d("austin_debug", user.getUsername() + " " + userName);
userService.getUserFriendship(user.getPk(), new ServiceCallback<FriendshipStatus>() {
@Override
public void onSuccess(final FriendshipStatus status) {
user.setFriendshipStatus(status);
fetchListener.onResult(user);
}
try {
final HttpURLConnection conn = (HttpURLConnection) new URL("https://www.instagram.com/" + userName + "/?__a=1").openConnection();
conn.setUseCaches(true);
conn.connect();
@Override
public void onFailure(final Throwable t) {
Log.e(TAG, "Error", t);
}
});
}
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
final String json = NetworkUtils.readFromConnection(conn);
// Log.d(TAG, "doInBackground: " + json);
final JSONObject userJson = new JSONObject(json).getJSONObject("graphql")
.getJSONObject(Constants.EXTRAS_USER);
final String cookie = settingsHelper.getString(Constants.COOKIE);
boolean isPrivate = userJson.getBoolean("is_private");
final long id = userJson.optLong(Constants.EXTRAS_ID, 0);
final long uid = CookieUtils.getUserIdFromCookie(cookie);
final JSONObject timelineMedia = userJson.getJSONObject("edge_owner_to_timeline_media");
// if (timelineMedia.has("edges")) {
// final JSONArray edges = timelineMedia.getJSONArray("edges");
// }
String url = userJson.optString("external_url");
if (TextUtils.isEmpty(url)) url = null;
return new User(
id,
userName,
userJson.getString("full_name"),
isPrivate,
userJson.getString("profile_pic_url_hd"),
null,
new FriendshipStatus(
userJson.optBoolean("followed_by_viewer"),
userJson.optBoolean("follows_viewer"),
userJson.optBoolean("blocked_by_viewer"),
false,
isPrivate,
userJson.optBoolean("has_requested_viewer"),
userJson.optBoolean("requested_by_viewer"),
false,
userJson.optBoolean("restricted_by_viewer"),
false
),
userJson.getBoolean("is_verified"),
false,
false,
false,
false,
null,
null,
timelineMedia.getLong("count"),
userJson.getJSONObject("edge_followed_by").getLong("count"),
userJson.getJSONObject("edge_follow").getLong("count"),
0,
userJson.getString("biography"),
url,
0,
null);
// result = new ProfileModel(isPrivate,
// !user.optBoolean("followed_by_viewer") && (id != uid && isPrivate),
// user.getBoolean("is_verified"),
// id,
// userName,
// user.getString("full_name"),
// user.getString("biography"),
// url,
// user.getString("profile_pic_url"),
// user.getString("profile_pic_url_hd"),
// timelineMedia.getLong("count"),
// user.getJSONObject("edge_followed_by").getLong("count"),
// user.getJSONObject("edge_follow").getLong("count"),
// user.optBoolean("followed_by_viewer"),
// user.optBoolean("follows_viewer"),
// user.optBoolean("restricted_by_viewer"),
// user.optBoolean("blocked_by_viewer"),
// user.optBoolean("requested_by_viewer"));
}
conn.disconnect();
} catch (final Exception e) {
if (logCollector != null)
logCollector.appendException(e, LogCollector.LogFile.ASYNC_PROFILE_FETCHER, "doInBackground");
if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e);
@Override
public void onFailure(final Throwable t) {
Log.e(TAG, "Error", t);
}
});
}
else {
graphQLService.fetchUser(userName, new ServiceCallback<User>() {
@Override
public void onSuccess(final User user) {
fetchListener.onResult(user);
}
return result;
@Override
public void onFailure(final Throwable t) {
Log.e(TAG, "Error", t);
}
});
}
return "yeah";
}
@Override
protected void onPostExecute(final User result) {
if (fetchListener != null) fetchListener.onResult(result);
protected void onPreExecute() {
if (fetchListener != null) fetchListener.doBefore();
}
}

View File

@ -538,7 +538,7 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe
private void fetchProfileDetails() {
if (TextUtils.isEmpty(username)) return;
new ProfileFetcher(username.trim().substring(1), profileModel -> {
new ProfileFetcher(username.trim().substring(1), isLoggedIn, profileModel -> {
if (getContext() == null) return;
this.profileModel = profileModel;
setProfileDetails();

View File

@ -4,9 +4,13 @@ import java.util.Map;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;
import retrofit2.http.QueryMap;
public interface GraphQLRepository {
@GET("/graphql/query/")
Call<String> fetch(@QueryMap(encoded = true) Map<String, String> queryParams);
@GET("/{username}/?__a=1")
Call<String> getUser(@Path("username") String username);
}

View File

@ -1,7 +1,8 @@
package awais.instagrabber.repositories;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.FriendshipStatus;
import awais.instagrabber.repositories.responses.UserSearchResponse;
import awais.instagrabber.repositories.responses.WrappedUser;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Path;
@ -10,7 +11,13 @@ import retrofit2.http.Query;
public interface UserRepository {
@GET("/api/v1/users/{uid}/info/")
Call<User> getUserInfo(@Path("uid") final long uid);
Call<WrappedUser> getUserInfo(@Path("uid") final long uid);
@GET("/api/v1/users/{username}/usernameinfo/")
Call<WrappedUser> getUsernameInfo(@Path("username") final String username);
@GET("/api/v1/friendships/show/{uid}/")
Call<FriendshipStatus> getUserFriendship(@Path("uid") final long uid);
@GET("/api/v1/users/search/")
Call<UserSearchResponse> search(@Query("timezone_offset") float timezoneOffset,

View File

@ -10,7 +10,7 @@ public class User implements Serializable {
private final boolean isPrivate;
private final String profilePicUrl;
private final String profilePicId;
private final FriendshipStatus friendshipStatus;
private FriendshipStatus friendshipStatus;
private final boolean isVerified;
private final boolean hasAnonymousProfilePicture;
private final boolean isUnpublished;
@ -102,6 +102,10 @@ public class User implements Serializable {
return friendshipStatus;
}
public void setFriendshipStatus(final FriendshipStatus friendshipStatus) {
this.friendshipStatus = friendshipStatus;
}
public boolean isVerified() {
return isVerified;
}

View File

@ -0,0 +1,13 @@
package awais.instagrabber.repositories.responses;
public class WrappedUser {
private final User user;
public WrappedUser(final User user) {
this.user = user;
}
public User getUser() {
return user;
}
}

View File

@ -102,8 +102,7 @@ public final class FlavorTown {
}
public static void changelogCheck(@NonNull final Context context) {
// if (settingsHelper.getInteger(Constants.PREV_INSTALL_VERSION) < BuildConfig.VERSION_CODE) {
if (true) {
if (settingsHelper.getInteger(Constants.PREV_INSTALL_VERSION) < BuildConfig.VERSION_CODE) {
final int appUaCode = settingsHelper.getInteger(Constants.APP_UA_CODE);
final String appUa = UserAgentUtils.generateAppUA(appUaCode, LocaleUtils.getCurrentLocale().getLanguage());
settingsHelper.putString(Constants.APP_UA, appUa);

View File

@ -83,6 +83,7 @@ public class AppStateViewModel extends AndroidViewModel {
if (TextUtils.isEmpty(username)) return;
new ProfileFetcher(
username.trim().substring(1),
true,
currentUser::postValue
).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}

View File

@ -271,4 +271,82 @@ public class GraphQLService extends BaseService {
}
});
}
public void fetchUser(final String username,
final ServiceCallback<User> callback) {
final Call<String> request = repository.getUser(username);
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 user of " + username);
callback.onSuccess(null);
return;
}
try {
final JSONObject body = new JSONObject(rawBody);
final JSONObject userJson = body.getJSONObject("graphql")
.getJSONObject(Constants.EXTRAS_USER);
boolean isPrivate = userJson.getBoolean("is_private");
final long id = userJson.optLong(Constants.EXTRAS_ID, 0);
final JSONObject timelineMedia = userJson.getJSONObject("edge_owner_to_timeline_media");
// if (timelineMedia.has("edges")) {
// final JSONArray edges = timelineMedia.getJSONArray("edges");
// }
String url = userJson.optString("external_url");
if (TextUtils.isEmpty(url)) url = null;
callback.onSuccess(new User(
id,
username,
userJson.getString("full_name"),
isPrivate,
userJson.getString("profile_pic_url_hd"),
null,
new FriendshipStatus(
userJson.optBoolean("followed_by_viewer"),
userJson.optBoolean("follows_viewer"),
userJson.optBoolean("blocked_by_viewer"),
false,
isPrivate,
userJson.optBoolean("has_requested_viewer"),
userJson.optBoolean("requested_by_viewer"),
false,
userJson.optBoolean("restricted_by_viewer"),
false
),
userJson.getBoolean("is_verified"),
false,
false,
false,
false,
null,
null,
timelineMedia.getLong("count"),
userJson.getJSONObject("edge_followed_by").getLong("count"),
userJson.getJSONObject("edge_follow").getLong("count"),
0,
userJson.getString("biography"),
url,
0,
null));
} 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);
}
}
});
}
}

View File

@ -5,8 +5,10 @@ import androidx.annotation.NonNull;
import java.util.TimeZone;
import awais.instagrabber.repositories.UserRepository;
import awais.instagrabber.repositories.responses.FriendshipStatus;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.UserSearchResponse;
import awais.instagrabber.repositories.responses.WrappedUser;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
@ -34,25 +36,66 @@ public class UserService extends BaseService {
}
public void getUserInfo(final long uid, final ServiceCallback<User> callback) {
final Call<User> request = repository.getUserInfo(uid);
request.enqueue(new Callback<User>() {
final Call<WrappedUser> request = repository.getUserInfo(uid);
request.enqueue(new Callback<WrappedUser>() {
@Override
public void onResponse(@NonNull final Call<User> call, @NonNull final Response<User> response) {
final User user = response.body();
public void onResponse(@NonNull final Call<WrappedUser> call, @NonNull final Response<WrappedUser> response) {
final WrappedUser user = response.body();
if (user == null) {
callback.onSuccess(null);
return;
}
callback.onSuccess(user);
callback.onSuccess(user.getUser());
}
@Override
public void onFailure(@NonNull final Call<User> call, @NonNull final Throwable t) {
public void onFailure(@NonNull final Call<WrappedUser> call, @NonNull final Throwable t) {
callback.onFailure(t);
}
});
}
public void getUsernameInfo(final String username, final ServiceCallback<User> callback) {
final Call<WrappedUser> request = repository.getUsernameInfo(username);
request.enqueue(new Callback<WrappedUser>() {
@Override
public void onResponse(@NonNull final Call<WrappedUser> call, @NonNull final Response<WrappedUser> response) {
final WrappedUser user = response.body();
if (user == null) {
callback.onSuccess(null);
return;
}
callback.onSuccess(user.getUser());
}
@Override
public void onFailure(@NonNull final Call<WrappedUser> call, @NonNull final Throwable t) {
callback.onFailure(t);
}
});
}
public void getUserFriendship(final long uid, final ServiceCallback<FriendshipStatus> callback) {
final Call<FriendshipStatus> request = repository.getUserFriendship(uid);
request.enqueue(new Callback<FriendshipStatus>() {
@Override
public void onResponse(@NonNull final Call<FriendshipStatus> call, @NonNull final Response<FriendshipStatus> response) {
final FriendshipStatus status = response.body();
if (status == null) {
callback.onSuccess(null);
return;
}
callback.onSuccess(status);
}
@Override
public void onFailure(@NonNull final Call<FriendshipStatus> call, @NonNull final Throwable t) {
callback.onFailure(t);
}
});
}
public Call<UserSearchResponse> search(final String query) {
final float timezoneOffset = (float) TimeZone.getDefault().getRawOffset() / 1000;
return repository.search(timezoneOffset, query);