Browse Source
Merge branch 'master' of https://github.com/austinhuang0131/instagrabber
renovate/org.robolectric-robolectric-4.x
Merge branch 'master' of https://github.com/austinhuang0131/instagrabber
renovate/org.robolectric-robolectric-4.x
Austin Huang
4 years ago
No known key found for this signature in database
GPG Key ID: 84C23AA04587A91F
25 changed files with 337 additions and 137 deletions
-
3app/src/main/java/awais/instagrabber/InstaGrabberApplication.java
-
7app/src/main/java/awais/instagrabber/activities/MainActivity.java
-
1app/src/main/java/awais/instagrabber/utils/Constants.java
-
2app/src/main/java/awais/instagrabber/utils/MediaUploader.java
-
42app/src/main/java/awais/instagrabber/webservices/BaseService.java
-
12app/src/main/java/awais/instagrabber/webservices/CollectionService.java
-
8app/src/main/java/awais/instagrabber/webservices/DirectMessagesService.java
-
8app/src/main/java/awais/instagrabber/webservices/DiscoverService.java
-
8app/src/main/java/awais/instagrabber/webservices/FeedService.java
-
8app/src/main/java/awais/instagrabber/webservices/FriendshipService.java
-
8app/src/main/java/awais/instagrabber/webservices/GifService.java
-
8app/src/main/java/awais/instagrabber/webservices/GraphQLService.java
-
8app/src/main/java/awais/instagrabber/webservices/LocationService.java
-
8app/src/main/java/awais/instagrabber/webservices/MediaService.java
-
15app/src/main/java/awais/instagrabber/webservices/NewsService.java
-
8app/src/main/java/awais/instagrabber/webservices/ProfileService.java
-
112app/src/main/java/awais/instagrabber/webservices/RetrofitFactory.java
-
8app/src/main/java/awais/instagrabber/webservices/SearchService.java
-
8app/src/main/java/awais/instagrabber/webservices/StoriesService.java
-
8app/src/main/java/awais/instagrabber/webservices/TagsService.java
-
8app/src/main/java/awais/instagrabber/webservices/UserService.java
-
2app/src/main/java/awais/instagrabber/webservices/interceptors/AddCookiesInterceptor.java
-
136app/src/main/java/awais/instagrabber/webservices/interceptors/IgErrorsInterceptor.java
-
2app/src/main/java/awais/instagrabber/webservices/interceptors/LoggingInterceptor.java
-
8app/src/main/res/values/strings.xml
@ -0,0 +1,112 @@ |
|||||
|
package awais.instagrabber.webservices; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
|
||||
|
import com.google.gson.FieldNamingPolicy; |
||||
|
import com.google.gson.Gson; |
||||
|
import com.google.gson.GsonBuilder; |
||||
|
|
||||
|
import java.io.File; |
||||
|
|
||||
|
import awais.instagrabber.BuildConfig; |
||||
|
import awais.instagrabber.activities.MainActivity; |
||||
|
import awais.instagrabber.repositories.responses.Caption; |
||||
|
import awais.instagrabber.utils.Utils; |
||||
|
import awais.instagrabber.webservices.interceptors.AddCookiesInterceptor; |
||||
|
import awais.instagrabber.webservices.interceptors.IgErrorsInterceptor; |
||||
|
import okhttp3.Cache; |
||||
|
import okhttp3.OkHttpClient; |
||||
|
import retrofit2.Retrofit; |
||||
|
import retrofit2.converter.gson.GsonConverterFactory; |
||||
|
import retrofit2.converter.scalars.ScalarsConverterFactory; |
||||
|
|
||||
|
public final class RetrofitFactory { |
||||
|
private static final Object LOCK = new Object(); |
||||
|
|
||||
|
private static RetrofitFactory instance; |
||||
|
|
||||
|
private final int cacheSize = 10 * 1024 * 1024; // 10 MB |
||||
|
private final Cache cache = new Cache(new File(Utils.cacheDir), cacheSize); |
||||
|
|
||||
|
private IgErrorsInterceptor igErrorsInterceptor; |
||||
|
private MainActivity mainActivity; |
||||
|
private Retrofit.Builder builder; |
||||
|
private Retrofit retrofit; |
||||
|
private Retrofit retrofitWeb; |
||||
|
|
||||
|
public static void setup(@NonNull final MainActivity mainActivity) { |
||||
|
if (instance == null) { |
||||
|
synchronized (LOCK) { |
||||
|
if (instance == null) { |
||||
|
instance = new RetrofitFactory(mainActivity); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static RetrofitFactory getInstance() { |
||||
|
if (instance == null) { |
||||
|
throw new RuntimeException("Setup not done!"); |
||||
|
} |
||||
|
return instance; |
||||
|
} |
||||
|
|
||||
|
private RetrofitFactory(@NonNull final MainActivity mainActivity) { |
||||
|
this.mainActivity = mainActivity; |
||||
|
} |
||||
|
|
||||
|
private Retrofit.Builder getRetrofitBuilder() { |
||||
|
if (builder == null) { |
||||
|
igErrorsInterceptor = new IgErrorsInterceptor(mainActivity); |
||||
|
final OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder() |
||||
|
.followRedirects(false) |
||||
|
.followSslRedirects(false) |
||||
|
.cache(cache); |
||||
|
if (BuildConfig.DEBUG) { |
||||
|
// clientBuilder.addInterceptor(new LoggingInterceptor()); |
||||
|
} |
||||
|
clientBuilder.addInterceptor(new AddCookiesInterceptor()) |
||||
|
.addInterceptor(igErrorsInterceptor); |
||||
|
final Gson gson = new GsonBuilder() |
||||
|
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) |
||||
|
.registerTypeAdapter(Caption.class, new Caption.CaptionDeserializer()) |
||||
|
.setLenient() |
||||
|
.create(); |
||||
|
builder = new Retrofit.Builder() |
||||
|
.addConverterFactory(ScalarsConverterFactory.create()) |
||||
|
.addConverterFactory(GsonConverterFactory.create(gson)) |
||||
|
.client(clientBuilder.build()); |
||||
|
} |
||||
|
return builder; |
||||
|
} |
||||
|
|
||||
|
public Retrofit getRetrofit() { |
||||
|
if (retrofit == null) { |
||||
|
retrofit = getRetrofitBuilder() |
||||
|
.baseUrl("https://i.instagram.com") |
||||
|
.build(); |
||||
|
} |
||||
|
return retrofit; |
||||
|
} |
||||
|
|
||||
|
public Retrofit getRetrofitWeb() { |
||||
|
if (retrofitWeb == null) { |
||||
|
retrofitWeb = getRetrofitBuilder() |
||||
|
.baseUrl("https://www.instagram.com") |
||||
|
.build(); |
||||
|
} |
||||
|
return retrofitWeb; |
||||
|
} |
||||
|
|
||||
|
public void destroy() { |
||||
|
if (igErrorsInterceptor != null) { |
||||
|
igErrorsInterceptor.destroy(); |
||||
|
} |
||||
|
igErrorsInterceptor = null; |
||||
|
mainActivity = null; |
||||
|
retrofit = null; |
||||
|
retrofitWeb = null; |
||||
|
builder = null; |
||||
|
instance = null; |
||||
|
} |
||||
|
} |
@ -1,4 +1,4 @@ |
|||||
package awais.instagrabber.webservices; |
|
||||
|
package awais.instagrabber.webservices.interceptors; |
||||
|
|
||||
import androidx.annotation.NonNull; |
import androidx.annotation.NonNull; |
||||
|
|
@ -0,0 +1,136 @@ |
|||||
|
package awais.instagrabber.webservices.interceptors; |
||||
|
|
||||
|
import android.util.Log; |
||||
|
import android.view.View; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
import androidx.annotation.StringRes; |
||||
|
|
||||
|
import com.google.android.material.snackbar.Snackbar; |
||||
|
|
||||
|
import org.json.JSONObject; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
|
||||
|
import awais.instagrabber.R; |
||||
|
import awais.instagrabber.activities.MainActivity; |
||||
|
import awais.instagrabber.dialogs.ConfirmDialogFragment; |
||||
|
import awais.instagrabber.utils.Constants; |
||||
|
import awais.instagrabber.utils.TextUtils; |
||||
|
import okhttp3.Interceptor; |
||||
|
import okhttp3.Request; |
||||
|
import okhttp3.Response; |
||||
|
import okhttp3.ResponseBody; |
||||
|
|
||||
|
public class IgErrorsInterceptor implements Interceptor { |
||||
|
private static final String TAG = IgErrorsInterceptor.class.getSimpleName(); |
||||
|
|
||||
|
private MainActivity mainActivity; |
||||
|
|
||||
|
public IgErrorsInterceptor(@NonNull final MainActivity mainActivity) { |
||||
|
this.mainActivity = mainActivity; |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
@Override |
||||
|
public Response intercept(@NonNull final Chain chain) throws IOException { |
||||
|
final Request request = chain.request(); |
||||
|
final Response response = chain.proceed(request); |
||||
|
if (response.isSuccessful()) { |
||||
|
return response; |
||||
|
} |
||||
|
checkError(response); |
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
private void checkError(@NonNull final Response response) { |
||||
|
final int errorCode = response.code(); |
||||
|
switch (errorCode) { |
||||
|
case 429: // "429 Too Many Requests" |
||||
|
// ('Throttled by Instagram because of too many API requests.'); |
||||
|
showErrorDialog(R.string.throttle_error); |
||||
|
return; |
||||
|
case 431: // "431 Request Header Fields Too Large" |
||||
|
// show dialog? |
||||
|
Log.e(TAG, "Network error: " + getMessage(errorCode, "The request start-line and/or headers are too large to process.")); |
||||
|
return; |
||||
|
case 404: |
||||
|
showErrorDialog(R.string.not_found); |
||||
|
return; |
||||
|
case 302: // redirect |
||||
|
final String location = response.header("location"); |
||||
|
if (location.equals("https://www.instagram.com/accounts/login/")) { |
||||
|
// rate limited |
||||
|
showErrorDialog(R.string.rate_limit); |
||||
|
} |
||||
|
return; |
||||
|
} |
||||
|
final ResponseBody body = response.body(); |
||||
|
if (body == null) return; |
||||
|
try { |
||||
|
final String bodyString = body.string(); |
||||
|
final JSONObject jsonObject = new JSONObject(bodyString); |
||||
|
String message = jsonObject.optString("message", null); |
||||
|
if (!TextUtils.isEmpty(message)) { |
||||
|
message = message.toLowerCase(); |
||||
|
switch (message) { |
||||
|
case "user_has_logged_out": |
||||
|
showErrorDialog(R.string.account_logged_out); |
||||
|
return; |
||||
|
case "login_required": |
||||
|
showErrorDialog(R.string.login_required); |
||||
|
return; |
||||
|
case "execution failure": |
||||
|
showSnackbar(message); |
||||
|
return; |
||||
|
case "not authorized to view user": // Do we handle this in profile view fragment? |
||||
|
case "challenge_required": // Since we make users login using browser, we should not be getting this error in api requests |
||||
|
default: |
||||
|
showSnackbar(message); |
||||
|
Log.e(TAG, "checkError: " + bodyString); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
final String errorType = jsonObject.optString("error_type", null); |
||||
|
if (TextUtils.isEmpty(errorType)) return; |
||||
|
if (errorType.equals("sentry_block")) { |
||||
|
showErrorDialog(R.string.sentry_block); |
||||
|
return; |
||||
|
} |
||||
|
if (errorType.equals("inactive user")) { |
||||
|
showErrorDialog(R.string.inactive_user); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "checkError: ", e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void showSnackbar(final String message) { |
||||
|
final View view = mainActivity.getRootView(); |
||||
|
if (view == null) return; |
||||
|
Snackbar.make(view, message, Snackbar.LENGTH_LONG).show(); |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
private String getMessage(final int errorCode, final String message) { |
||||
|
return String.format("code: %s, internalMessage: %s", errorCode, message); |
||||
|
} |
||||
|
|
||||
|
private void showErrorDialog(@StringRes final int messageResId) { |
||||
|
if (mainActivity == null) return; |
||||
|
if (messageResId == 0) return; |
||||
|
final ConfirmDialogFragment dialogFragment = ConfirmDialogFragment.newInstance( |
||||
|
Constants.GLOBAL_NETWORK_ERROR_DIALOG_REQUEST_CODE, |
||||
|
R.string.error, |
||||
|
messageResId, |
||||
|
R.string.ok, |
||||
|
0, |
||||
|
0 |
||||
|
); |
||||
|
dialogFragment.show(mainActivity.getSupportFragmentManager(), "network_error_dialog"); |
||||
|
} |
||||
|
|
||||
|
public void destroy() { |
||||
|
mainActivity = null; |
||||
|
} |
||||
|
} |
@ -1,4 +1,4 @@ |
|||||
package awais.instagrabber.webservices; |
|
||||
|
package awais.instagrabber.webservices.interceptors; |
||||
|
|
||||
import android.util.Log; |
import android.util.Log; |
||||
|
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue