From 3dd1667e75f833db76e3c03ebd70793117220b59 Mon Sep 17 00:00:00 2001 From: mfgm2 Date: Wed, 6 May 2020 16:58:15 +0300 Subject: [PATCH 1/4] Update Imgur api endpoint (free) --- app/src/main/java/me/saket/dank/di/DankApi.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/me/saket/dank/di/DankApi.java b/app/src/main/java/me/saket/dank/di/DankApi.java index b096cf49d..19cf1901f 100644 --- a/app/src/main/java/me/saket/dank/di/DankApi.java +++ b/app/src/main/java/me/saket/dank/di/DankApi.java @@ -25,7 +25,6 @@ public interface DankApi { String HEADER_IMGUR_AUTH = "Authorization: Client-ID 87450e5590435e9"; - String HEADER_MASHAPE_KEY = "X-Mashape-Key: VOjpM0pXeAmshuRGE4Hhe6KY9Ouep1YCLx8jsnaivCFNYALpN5"; String HEADER_WHOLESOME_API_AUTH = "Authorization"; String WHOLESOME_API_HOST = "dank-wholesome.herokuapp.com"; String GIPHY_API_KEY = "SFGHZ6SYGn3AzZ07b2tNpENCEDdYTzpB"; @@ -37,8 +36,8 @@ public interface DankApi { * is wrapped in {@link Response} so that the headers can be extracted for checking Imgur rate-limits. */ @CheckResult - @GET("https://imgur-apiv3.p.mashape.com/3/album/{albumId}") - @Headers({ HEADER_IMGUR_AUTH, HEADER_MASHAPE_KEY }) + @GET("https://api.imgur.com/3/album/{albumId}") + @Headers({ HEADER_IMGUR_AUTH }) Single> imgurAlbum( @Path("albumId") String albumId ); @@ -47,16 +46,16 @@ Single> imgurAlbum( * Get an image's details from Imgur. This is also a paid API. */ @CheckResult - @GET("https://imgur-apiv3.p.mashape.com/3/image/{imageId}") - @Headers({ HEADER_IMGUR_AUTH, HEADER_MASHAPE_KEY }) + @GET("https://api.imgur.com/3/image/{imageId}") + @Headers({ HEADER_IMGUR_AUTH }) Single> imgurImage( @Path("imageId") String imageId ); @CheckResult @Multipart - @POST("https://imgur-apiv3.p.mashape.com/3/image") - @Headers({ HEADER_IMGUR_AUTH, HEADER_MASHAPE_KEY }) + @POST("https://api.imgur.com/3/image") + @Headers({ HEADER_IMGUR_AUTH }) Single> uploadToImgur( @Part MultipartBody.Part file, @Query("type") String fileType From f68ce64d146d534530bf9a9f3f75d7f58cf29396 Mon Sep 17 00:00:00 2001 From: mfgm2 Date: Wed, 6 May 2020 17:13:08 +0300 Subject: [PATCH 2/4] Don't update api limits if they're not present --- .../me/saket/dank/ui/media/ImgurRepository.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/me/saket/dank/ui/media/ImgurRepository.java b/app/src/main/java/me/saket/dank/ui/media/ImgurRepository.java index 17a08aa5f..1d48dac06 100644 --- a/app/src/main/java/me/saket/dank/ui/media/ImgurRepository.java +++ b/app/src/main/java/me/saket/dank/ui/media/ImgurRepository.java @@ -162,12 +162,14 @@ private Function, Response> throwIfHttpError() { private Consumer saveImgurApiRateLimits() { return response -> { Headers responseHeaders = response.headers(); - saveApiRequestLimit(parseInt(responseHeaders.get("X-RateLimit-Requests-Limit"))); - saveRemainingApiRequests(parseInt(responseHeaders.get("X-RateLimit-Requests-Remaining"))); - saveApiUploadLimit(parseInt(responseHeaders.get("X-RateLimit-Uploads-Limit"))); - saveRemainingApiUploads(parseInt(responseHeaders.get("X-RateLimit-Uploads-Remaining"))); - - saveRateLimitsLastCheckedAt(responseHeaders.getDate("Date").getTime()); + try { + saveApiRequestLimit(parseInt(responseHeaders.get("X-RateLimit-Requests-Limit"))); + saveRemainingApiRequests(parseInt(responseHeaders.get("X-RateLimit-Requests-Remaining"))); + saveApiUploadLimit(parseInt(responseHeaders.get("X-RateLimit-Uploads-Limit"))); + saveRemainingApiUploads(parseInt(responseHeaders.get("X-RateLimit-Uploads-Remaining"))); + + saveRateLimitsLastCheckedAt(responseHeaders.getDate("Date").getTime()); + } catch (NumberFormatException ignored) {} // Do not save rate limits if they're not present }; } From ee42c8b34a7fbcbc65be6a9e306474baf70a82d5 Mon Sep 17 00:00:00 2001 From: mfgm2 Date: Wed, 6 May 2020 19:15:40 +0300 Subject: [PATCH 3/4] Remove imgur rate-limiting code --- .../java/me/saket/dank/data/ErrorResolver.kt | 14 -- .../me/saket/dank/data/ResolvedError.java | 4 - ...urApiRequestRateLimitReachedException.java | 7 - ...gurApiUploadRateLimitReachedException.java | 7 - .../main/java/me/saket/dank/di/DankApi.java | 4 - .../dank/ui/compose/UploadImageDialog.java | 10 +- .../saket/dank/ui/media/ImgurRepository.java | 151 +----------------- .../ui/media/MediaAlbumViewerActivity.java | 1 - .../dank/ui/media/MediaHostRepository.java | 8 - .../ui/submission/SubmissionPageLayout.java | 13 +- app/src/main/res/values/strings.xml | 4 - 11 files changed, 13 insertions(+), 210 deletions(-) delete mode 100644 app/src/main/java/me/saket/dank/data/exceptions/ImgurApiRequestRateLimitReachedException.java delete mode 100644 app/src/main/java/me/saket/dank/data/exceptions/ImgurApiUploadRateLimitReachedException.java diff --git a/app/src/main/java/me/saket/dank/data/ErrorResolver.kt b/app/src/main/java/me/saket/dank/data/ErrorResolver.kt index f4641dae9..61d121c17 100644 --- a/app/src/main/java/me/saket/dank/data/ErrorResolver.kt +++ b/app/src/main/java/me/saket/dank/data/ErrorResolver.kt @@ -4,8 +4,6 @@ import com.bumptech.glide.load.engine.GlideException import io.reactivex.exceptions.CompositeException import io.reactivex.exceptions.UndeliverableException import me.saket.dank.R -import me.saket.dank.data.exceptions.ImgurApiRequestRateLimitReachedException -import me.saket.dank.data.exceptions.ImgurApiUploadRateLimitReachedException import okhttp3.internal.http2.ConnectionShutdownException import okhttp3.internal.http2.StreamResetException import retrofit2.HttpException @@ -57,18 +55,6 @@ constructor() { R.string.common_reddit_is_down_error_emoji, R.string.common_reddit_is_down_error_message) - } else if (actualError is ImgurApiRequestRateLimitReachedException) { - ResolvedError.create( - ResolvedError.Type.IMGUR_RATE_LIMIT_REACHED, - R.string.common_imgur_rate_limit_error_emoji, - R.string.common_imgur_request_rate_limit_error_message) - - } else if (actualError is ImgurApiUploadRateLimitReachedException) { - ResolvedError.create( - ResolvedError.Type.IMGUR_RATE_LIMIT_REACHED, - R.string.common_imgur_rate_limit_error_emoji, - R.string.common_imgur_upload_rate_limit_error_message) - } else if (actualError is CancellationException || actualError is InterruptedIOException || actualError is InterruptedException) { ResolvedError.create( ResolvedError.Type.CANCELATION, diff --git a/app/src/main/java/me/saket/dank/data/ResolvedError.java b/app/src/main/java/me/saket/dank/data/ResolvedError.java index 62a607da6..63c051900 100644 --- a/app/src/main/java/me/saket/dank/data/ResolvedError.java +++ b/app/src/main/java/me/saket/dank/data/ResolvedError.java @@ -47,10 +47,6 @@ public boolean isRedditServerError() { return type() == Type.REDDIT_IS_DOWN; } - public boolean isImgurRateLimitError() { - return type() == Type.IMGUR_RATE_LIMIT_REACHED; - } - public static ResolvedError create(Type type, @StringRes int errorEmoji, @StringRes int errorMessage) { return new AutoValue_ResolvedError(type, errorEmoji, errorMessage); } diff --git a/app/src/main/java/me/saket/dank/data/exceptions/ImgurApiRequestRateLimitReachedException.java b/app/src/main/java/me/saket/dank/data/exceptions/ImgurApiRequestRateLimitReachedException.java deleted file mode 100644 index 350ab70bb..000000000 --- a/app/src/main/java/me/saket/dank/data/exceptions/ImgurApiRequestRateLimitReachedException.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.saket.dank.data.exceptions; - -/** - * Thrown when Dank runs out Imgur rate limits, in order to avoid over-billing. - */ -public class ImgurApiRequestRateLimitReachedException extends RuntimeException { -} diff --git a/app/src/main/java/me/saket/dank/data/exceptions/ImgurApiUploadRateLimitReachedException.java b/app/src/main/java/me/saket/dank/data/exceptions/ImgurApiUploadRateLimitReachedException.java deleted file mode 100644 index 91358ce33..000000000 --- a/app/src/main/java/me/saket/dank/data/exceptions/ImgurApiUploadRateLimitReachedException.java +++ /dev/null @@ -1,7 +0,0 @@ -package me.saket.dank.data.exceptions; - -/** - * Thrown when Dank runs out Imgur rate limits, in order to avoid over-billing. - */ -public class ImgurApiUploadRateLimitReachedException extends RuntimeException { -} diff --git a/app/src/main/java/me/saket/dank/di/DankApi.java b/app/src/main/java/me/saket/dank/di/DankApi.java index 19cf1901f..a9b7fd736 100644 --- a/app/src/main/java/me/saket/dank/di/DankApi.java +++ b/app/src/main/java/me/saket/dank/di/DankApi.java @@ -31,10 +31,6 @@ public interface DankApi { // ======== IMGUR ======== // - /** - * Get images in an Imgur album. This is a paid API so we try to minimize its usage. The response - * is wrapped in {@link Response} so that the headers can be extracted for checking Imgur rate-limits. - */ @CheckResult @GET("https://api.imgur.com/3/album/{albumId}") @Headers({ HEADER_IMGUR_AUTH }) diff --git a/app/src/main/java/me/saket/dank/ui/compose/UploadImageDialog.java b/app/src/main/java/me/saket/dank/ui/compose/UploadImageDialog.java index 43cc0ea81..1e3d57fc4 100644 --- a/app/src/main/java/me/saket/dank/ui/compose/UploadImageDialog.java +++ b/app/src/main/java/me/saket/dank/ui/compose/UploadImageDialog.java @@ -236,13 +236,11 @@ private Function - * TODO: If needed, get the rate limits if they're not cached. - * Remember to handle {@link ImgurApiRequestRateLimitReachedException}. - * * @throws InvalidImgurAlbumException If an invalid Imgur link was found. Right now this happens only when no images are * returned by Imgur. - * @throws ImgurApiRequestRateLimitReachedException If Imgur's API limit is reached and no more API requests can be made till the next month. */ public Single gallery(ImgurAlbumUnresolvedLink imgurAlbumUnresolvedLink) { return dankApi.imgurAlbum(imgurAlbumUnresolvedLink.albumId()) .map(throwIfHttpError()) - .doOnSuccess(saveImgurApiRateLimits()) - .map(response -> response.body()) + .map(Response::body) .onErrorResumeNext(error -> { // Api returns a 404 when it was a single image and not an album. if (error instanceof HttpException && ((HttpException) error).code() == 404) { @@ -93,29 +63,16 @@ public Single gallery(ImgurAlbumUnresolvedLink imgurAlbumUnresolv } else { // Okay, let's check if it was a single image. return dankApi.imgurImage(imgurAlbumUnresolvedLink.albumId()) - .doOnSuccess(saveImgurApiRateLimits()) - .map(response -> response.body()); + .map(Response::body); } }) .doOnSuccess(albumResponse -> { if (!albumResponse.hasImages()) { throw new InvalidImgurAlbumException(); } - }) - .doOnSubscribe(o -> { - resetRateLimitsIfMonthChanged(); - - if (isApiRequestLimitReached()) { - throw new ImgurApiRequestRateLimitReachedException(); - } else { - Timber.i("Rate limits not reached"); - } }); } - /** - * Remember to handle {@link ImgurApiUploadRateLimitReachedException}. - */ @CheckResult public Observable> uploadImage(File imageFile, String mimeType) { Relay uploadProgressStream = BehaviorRelay.createDefault(0f); @@ -130,22 +87,12 @@ public Observable> uploadImage(File Observable> uploadStream = dankApi.uploadToImgur(multipartBodyPart, "file") .map(throwIfHttpError()) - .doOnSuccess(saveImgurApiRateLimits()) - .map(response -> response.body()) - .doOnSubscribe(o -> { - resetRateLimitsIfMonthChanged(); - - if (isApiUploadLimitReached()) { - throw new ImgurApiUploadRateLimitReachedException(); - } else { - Timber.i("Rate limits not reached"); - } - }) - .map(response -> FileUploadProgressEvent.createUploaded(response)) + .map(Response::body) + .map(FileUploadProgressEvent::createUploaded) .toObservable(); return uploadProgressStream - .map(progress -> FileUploadProgressEvent.createInFlight(progress)) + .map(FileUploadProgressEvent::createInFlight) .mergeWith(uploadStream); } @@ -159,90 +106,4 @@ private Function, Response> throwIfHttpError() { }; } - private Consumer saveImgurApiRateLimits() { - return response -> { - Headers responseHeaders = response.headers(); - try { - saveApiRequestLimit(parseInt(responseHeaders.get("X-RateLimit-Requests-Limit"))); - saveRemainingApiRequests(parseInt(responseHeaders.get("X-RateLimit-Requests-Remaining"))); - saveApiUploadLimit(parseInt(responseHeaders.get("X-RateLimit-Uploads-Limit"))); - saveRemainingApiUploads(parseInt(responseHeaders.get("X-RateLimit-Uploads-Remaining"))); - - saveRateLimitsLastCheckedAt(responseHeaders.getDate("Date").getTime()); - } catch (NumberFormatException ignored) {} // Do not save rate limits if they're not present - }; - } - - private void saveRateLimitsLastCheckedAt(long lastCheckedMillis) { - sharedPreferences.edit().putLong(KEY_RATE_LIMIT_LAST_CHECK, lastCheckedMillis).apply(); - } - - private long rateLimitsLastCheckedAtMillis(long valueIfEmpty) { - return sharedPreferences.getLong(KEY_RATE_LIMIT_LAST_CHECK, valueIfEmpty); - } - - private void resetRateLimitsIfMonthChanged() { - long lastCheckedMillis = rateLimitsLastCheckedAtMillis(-1); - if (lastCheckedMillis == -1) { - return; - } - - DateTime lastCheckedDateTime = DateTime.forInstant(lastCheckedMillis, TimeZone.getTimeZone("UTC")); - DateTime nowDateTime = DateTime.now(TimeZone.getTimeZone("UTC")); - - Timber.i("Now month: %s, Last checked month: %s", nowDateTime.getMonth(), lastCheckedDateTime.getMonth()); - - if (nowDateTime.getMonth() > lastCheckedDateTime.getMonth()) { - Timber.i("Months have changed. Resetting Imgur rate limit"); - - // Months have changed! Reset the limits. - sharedPreferences.edit().clear().apply(); - } - } - - private void saveRemainingApiRequests(int requestsRemaining) { - sharedPreferences.edit().putInt(KEY_REMAINING_REQUESTS, requestsRemaining).apply(); - } - - private void saveApiRequestLimit(int requestLimit) { - sharedPreferences.edit().putInt(KEY_REQUEST_LIMIT, requestLimit).apply(); - } - - private boolean isApiRequestLimitReached() { - if (sharedPreferences.contains(KEY_REMAINING_REQUESTS) && sharedPreferences.contains(KEY_REQUEST_LIMIT)) { - int remainingRequests = sharedPreferences.getInt(KEY_REMAINING_REQUESTS, 0); - int requestLimit = sharedPreferences.getInt(KEY_REQUEST_LIMIT, 0); - - Timber.i("remainingRequests: %s", remainingRequests); - Timber.i("requestLimit: %s", requestLimit); - - if (remainingRequests < requestLimit * LIMIT_THRESHOLD_FACTOR) { - Timber.w("Imgur api request limit reached :("); - return true; - } - } - return false; - } - - private void saveRemainingApiUploads(int uploadsRemaining) { - sharedPreferences.edit().putInt(KEY_REMAINING_UPLOADS, uploadsRemaining).apply(); - } - - private void saveApiUploadLimit(int uploadLimit) { - sharedPreferences.edit().putInt(KEY_UPLOAD_LIMIT, uploadLimit).apply(); - } - - private boolean isApiUploadLimitReached() { - if (sharedPreferences.contains(KEY_REMAINING_UPLOADS) && sharedPreferences.contains(KEY_UPLOAD_LIMIT)) { - int remainingUploads = sharedPreferences.getInt(KEY_REMAINING_UPLOADS, 0); - int uploadLimit = sharedPreferences.getInt(KEY_UPLOAD_LIMIT, 0); - - if (remainingUploads < uploadLimit * LIMIT_THRESHOLD_FACTOR) { - Timber.i("remainingUploads: %s", remainingUploads); - Timber.i("uploadLimit: %s", uploadLimit); - return true; - } - } - return false; - } } diff --git a/app/src/main/java/me/saket/dank/ui/media/MediaAlbumViewerActivity.java b/app/src/main/java/me/saket/dank/ui/media/MediaAlbumViewerActivity.java index df1ed8b7a..4681d166e 100644 --- a/app/src/main/java/me/saket/dank/ui/media/MediaAlbumViewerActivity.java +++ b/app/src/main/java/me/saket/dank/ui/media/MediaAlbumViewerActivity.java @@ -298,7 +298,6 @@ private void positionMediaControlsToAvoidOverlappingWithNavBar(WindowInsets inse private void resolveMediaLinkAndDisplayContent(MediaLink mediaLinkToDisplay) { mediaHostRepository.resolveActualLinkIfNeeded(mediaLinkToDisplay) - // TODO: Handle Imgur rate limit reached. .doOnNext(resolvedMediaLink -> this.resolvedMediaLink = resolvedMediaLink) .map(resolvedMediaLink -> { // Find all child images under an album. diff --git a/app/src/main/java/me/saket/dank/ui/media/MediaHostRepository.java b/app/src/main/java/me/saket/dank/ui/media/MediaHostRepository.java index a41b9f5bb..05e96b916 100644 --- a/app/src/main/java/me/saket/dank/ui/media/MediaHostRepository.java +++ b/app/src/main/java/me/saket/dank/ui/media/MediaHostRepository.java @@ -27,8 +27,6 @@ import me.saket.dank.cache.StoreFilePersister; import me.saket.dank.data.CachedResolvedLinkInfo; import me.saket.dank.data.FileUploadProgressEvent; -import me.saket.dank.data.exceptions.ImgurApiRequestRateLimitReachedException; -import me.saket.dank.data.exceptions.ImgurApiUploadRateLimitReachedException; import me.saket.dank.ui.giphy.GiphyGif; import me.saket.dank.ui.giphy.GiphyRepository; import me.saket.dank.ui.media.gfycat.GfycatRepository; @@ -154,9 +152,6 @@ public void flagLocalUrlParsingAsIncorrect(Link link) { .subscribe(); } - /** - * Remember to handle {@link ImgurApiRequestRateLimitReachedException}. - */ public Observable resolveActualLinkIfNeeded(MediaLink unresolvedLink) { return incorrectMediaUrlParsingData.get() .isFlagged(unresolvedLink) @@ -215,9 +210,6 @@ private List convertImgurImagesToImgurMediaLinks(List img return imgurImageLinks; } - /** - * Remember to handle {@link ImgurApiUploadRateLimitReachedException}. - */ @CheckResult public Observable> uploadImage(File image, String mimeType) { return imgurRepository.uploadImage(image, mimeType); diff --git a/app/src/main/java/me/saket/dank/ui/submission/SubmissionPageLayout.java b/app/src/main/java/me/saket/dank/ui/submission/SubmissionPageLayout.java index 974d92039..237a3b3c6 100644 --- a/app/src/main/java/me/saket/dank/ui/submission/SubmissionPageLayout.java +++ b/app/src/main/java/me/saket/dank/ui/submission/SubmissionPageLayout.java @@ -75,7 +75,6 @@ import me.saket.dank.data.ResolvedError; import me.saket.dank.data.StatusBarTint; import me.saket.dank.data.UserPreferences; -import me.saket.dank.data.exceptions.ImgurApiRequestRateLimitReachedException; import me.saket.dank.di.Dank; import me.saket.dank.reply.Reply; import me.saket.dank.reply.ReplyRepository; @@ -126,7 +125,6 @@ import me.saket.dank.ui.subreddit.events.SubmissionOpenInNewTabSwipeEvent; import me.saket.dank.ui.subreddit.events.SubmissionOptionSwipeEvent; import me.saket.dank.ui.user.UserSessionRepository; -import me.saket.dank.urlparser.ExternalLink; import me.saket.dank.urlparser.ImgurAlbumLink; import me.saket.dank.urlparser.Link; import me.saket.dank.urlparser.MediaLink; @@ -1377,14 +1375,9 @@ private void loadSubmissionContent(Submission submission) { }) .observeOn(mainThread()) .onErrorResumeNext(error -> { - // Open this album in browser if Imgur rate limits have reached. - if (error instanceof ImgurApiRequestRateLimitReachedException) { - return Observable.just(ExternalLink.create(parsedLink.unparsedUrl())); - } else { - uiEvents.accept(SubmissionContentResolvingFailed.create()); - showMediaLoadError(error); - return Observable.never(); - } + uiEvents.accept(SubmissionContentResolvingFailed.create()); + showMediaLoadError(error); + return Observable.never(); }); }) .flatMapSingle(link -> { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e12111545..964e36de3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -32,10 +32,6 @@ (ಥ_ಥ) You broke Reddit! It\'s under heavy load right now. - ಥ_ಥ - Dawn has reached its monthly limit of downloading images from Imgur. - Dawn has reached its monthly limit of uploading images to Imgur. - ( ͡° ͜ʖ ͡°) Something was intentionally canceled. The user should never see this. From abdf6da427f1b6a1d543470d60efc07d6fa2cba3 Mon Sep 17 00:00:00 2001 From: mfgm2 Date: Wed, 6 May 2020 19:20:39 +0300 Subject: [PATCH 4/4] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 189a2a5b1..4b88acc7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed ### Fixed +- Imgur images (up)loading ([#202](https://github.com/Tunous/Dawn/pull/202)) ## [0.9.1] - 2020-05-05 ### Fixed