diff --git a/lib/src/main/java/com/fernandobarillas/albumparser/imgur/ImgurParser.java b/lib/src/main/java/com/fernandobarillas/albumparser/imgur/ImgurParser.java index ab5a2f0..89679e7 100644 --- a/lib/src/main/java/com/fernandobarillas/albumparser/imgur/ImgurParser.java +++ b/lib/src/main/java/com/fernandobarillas/albumparser/imgur/ImgurParser.java @@ -28,7 +28,7 @@ import com.fernandobarillas.albumparser.imgur.model.AlbumResponse; import com.fernandobarillas.albumparser.imgur.model.Image; import com.fernandobarillas.albumparser.imgur.model.ImgurApiError; -import com.fernandobarillas.albumparser.imgur.model.v3.AlbumResponseV3; +import com.fernandobarillas.albumparser.imgur.model.v3.GalleryResponseV3; import com.fernandobarillas.albumparser.imgur.model.v3.ImageResponseV3; import com.fernandobarillas.albumparser.media.IMedia; import com.fernandobarillas.albumparser.parser.AbstractApiParser; @@ -48,8 +48,8 @@ */ public class ImgurParser extends AbstractApiParser { - private static final int ALBUM_HASH_LENGTH = 5; // Most recent album hashes are exactly 5 chars - private static final int IMAGE_HASH_LENGTH = 7; // Most recent image hashes are exactly 7 chars + private static final int MIN_ALBUM_HASH_LENGTH = 5; // Album hashes are at least 5 chars + private static final int IMAGE_HASH_LENGTH = 7; // Image hashes are exactly 7 chars private static final String ALBUM_PATH = "a"; private static final String GALLERY_PATH = "gallery"; @@ -60,13 +60,10 @@ public class ImgurParser extends AbstractApiParser { private static final String HASH_PATTERN = "([^\\W_]{5}|[^\\W_]{7})"; // Regex patterns, pre-compiled for better performance - private static final Pattern GALLERY_PATTERN = - Pattern.compile("^/gallery/" + HASH_PATTERN + "(?:/.*?|)$"); - private static final Pattern ALBUM_PATTERN = Pattern.compile("/([^\\W_]{5})(?:/.*?|)$"); - private static final Pattern SUBREDDIT_PATTERN = - Pattern.compile("^/[rt]/\\w+/" + HASH_PATTERN + "(?:/.*?|)$"); - private static final Pattern NO_PREFIX_PATTERN = - Pattern.compile("^/" + HASH_PATTERN + "(?:/.*?|)$"); + private static final Pattern GALLERY_PATTERN = Pattern.compile("^/gallery/" + HASH_PATTERN + "(?:/.*?|)$"); + private static final Pattern ALBUM_PATTERN = Pattern.compile("/([^\\W_]{5,7})(?:/.*?|)$"); + private static final Pattern SUBREDDIT_PATTERN = Pattern.compile("^/[rt]/\\w+/" + HASH_PATTERN + "(?:/.*?|)$"); + private static final Pattern NO_PREFIX_PATTERN = Pattern.compile("^/" + HASH_PATTERN + "(?:/.*?|)$"); private static final Pattern DIRECT_MEDIA_PATTERN = Pattern.compile("/" + HASH_PATTERN + "(?:[sbtmlghr]|_d)?\\.[^\\W_]{3,4}/?$"); @@ -99,7 +96,7 @@ public String getBaseDomain() { @Override public String getHash(URL mediaUrl) throws InvalidMediaUrlException { if (!isValidDomain(mediaUrl)) { - throw new InvalidMediaUrlException(mediaUrl); // TODO: Add this instead of media == null check to other parsers + throw new InvalidMediaUrlException(mediaUrl); } String path = mediaUrl.getPath(); String firstSegment = ParseUtils.getFirstPathSegment(mediaUrl); @@ -135,8 +132,7 @@ public boolean isValidDomain(URL mediaUrl) { if (mediaUrl == null) return false; String domain = mediaUrl.getHost(); String baseDomain = getBaseDomain(); - return baseDomain.equalsIgnoreCase(domain) || ParseUtils.isDomainMatch(domain, - getValidDomains()); + return baseDomain.equalsIgnoreCase(domain) || ParseUtils.isDomainMatch(domain, getValidDomains()); } @Override @@ -154,44 +150,11 @@ public ParserResponse parse(URL mediaUrl) throws IOException, RuntimeException { } boolean hasApiKey = clientIdHeader != null; - boolean isAlbum = hash.length() == ALBUM_HASH_LENGTH; - boolean isOldUrl = isAlbum && ParseUtils.isDirectUrl(mediaUrl); // Direct URL, 5 char hash - - // Not an album, no API key set or this is a pre-API direct URL - if (!(isAlbum || hasApiKey) || isOldUrl) { - // Generate a new image object for the hash we got without making an API call at all. - // The extension is only guessed at if the original extension was null, so even though - // you might make a request for {hash}.jpg the Imgur servers might still return a GIF - // in the response - Image image = new Image(); - String ext = ParseUtils.getExtension(mediaUrl); - if (ext != null) { - image.ext = "." + ext; - } - image.hash = hash; - image.animated = - ParseUtils.isVideoExtension(mediaUrl) || ParseUtils.isGifExtension(mediaUrl); - image.setLowQuality(mLowQualitySize); - image.setPreviewQuality(mPreviewSize); - ParserResponse parserResponse = new ParserResponse(image); - parserResponse.setOriginalUrl(mediaUrl); - return parserResponse; - } + boolean isAlbum = isAlbumUrl(mediaUrl); ImgurApi service = getRetrofit().create(ImgurApi.class); - if (isAlbum) { - if (hasApiKey) { - // Use API v3 if the client ID is set - Response serviceResponse = - service.getV3Album(clientIdHeader, hash).execute(); - checkResponseSuccess(mediaUrl, serviceResponse); - AlbumResponseV3 apiResponse = serviceResponse.body(); - if (apiResponse != null) { - apiResponse.setLowQuality(mLowQualitySize); - apiResponse.setPreviewQuality(mPreviewSize); - return getParserResponse(mediaUrl, apiResponse, serviceResponse); - } - } else { + if (!hasApiKey) { + if (isAlbum) { // Make an API call to get the album images via the old API Response serviceResponse = service.getAlbumData(hash).execute(); checkResponseSuccess(mediaUrl, serviceResponse); @@ -199,50 +162,73 @@ public ParserResponse parse(URL mediaUrl) throws IOException, RuntimeException { if (apiResponse != null) { apiResponse.setLowQuality(mLowQualitySize); apiResponse.setPreviewQuality(mPreviewSize); - return getParserResponse(mediaUrl, apiResponse, serviceResponse); } + return getParserResponse(mediaUrl, apiResponse, serviceResponse); + } else { + // Generate a new image object for the hash we got without making an API call at all. + // The extension is only guessed at if the original extension was null, so even though + // you might make a request for {hash}.jpg the Imgur servers might still return a GIF + // in the response + Image image = new Image(); + String ext = ParseUtils.getExtension(mediaUrl); + if (ext != null) { + image.ext = "." + ext; + } + image.hash = hash; + image.animated = ParseUtils.isVideoExtension(mediaUrl) || ParseUtils.isGifExtension(mediaUrl); + image.setLowQuality(mLowQualitySize); + image.setPreviewQuality(mPreviewSize); + ParserResponse parserResponse = new ParserResponse(image); + parserResponse.setOriginalUrl(mediaUrl); + return parserResponse; } + } - // Is this a /a/{hash} URL? If so, don't attempt to parse as image below - if (ALBUM_PATH.equalsIgnoreCase(ParseUtils.getFirstPathSegment(mediaUrl))) { - throw new InvalidApiResponseException(mediaUrl, "Could not parse album URL"); + if (!isAlbum) { + Response imageServiceResponse = service.getV3Image(clientIdHeader, hash).execute(); + ImageResponseV3 imageResponse = imageServiceResponse.body(); + if (imageResponse != null) { + imageResponse.setLowQuality(mLowQualitySize); + imageResponse.setPreviewQuality(mPreviewSize); + return getParserResponse(mediaUrl, imageResponse, imageServiceResponse); + } else { } + + // If response was null, will attempt to run the hash as an album/gallery below } - // Album API call failed, this is probably an old API single image hash - Response serviceResponse = - service.getV3Image(clientIdHeader, hash).execute(); - ImageResponseV3 apiResponse = serviceResponse.body(); - if (apiResponse != null) { - apiResponse.setLowQuality(mLowQualitySize); - apiResponse.setPreviewQuality(mPreviewSize); + Response galleryServiceResponse = service.getV3Gallery(clientIdHeader, hash).execute(); + GalleryResponseV3 galleryResponse = galleryServiceResponse.body(); + if (galleryResponse != null) { + galleryResponse.setLowQuality(mLowQualitySize); + galleryResponse.setPreviewQuality(mPreviewSize); } - return getParserResponse(mediaUrl, apiResponse, serviceResponse); + + return getParserResponse(mediaUrl, galleryResponse, galleryServiceResponse); } /** - * Attempts to return a direct link to an image based on a hash alone, without doing an HTTP - * call to the Imgur API. This method might return an invalid URL since it attempts to make an - * educated guess at a URL. Some problematic hashes are for URLs that predate the Imgur API + * Attempts to return a direct link to an image based on a hash alone, without doing an HTTP call to the Imgur API. + * This method might return an invalid URL since it attempts to make an educated guess at a URL. Some problematic + * hashes are for URLs that predate the Imgur API * * @param hash The hash to get an image URL for - * @param quality The quality of the image you would like to use, for example {@link - * Image#HUGE_THUMBNAIL} or {@link Image#ORIGINAL} - * @param extension The extension to use for the URL. This should not have a prefixed period, - * Example: jpg not .jpg + * @param quality The quality of the image you would like to use, for example {@link Image#HUGE_THUMBNAIL} or + * {@link Image#ORIGINAL} + * @param extension The extension to use for the URL. This should not have a prefixed period, Example: jpg not .jpg * @return A URL to an image if the passed in hash was a valid non-album hash, null otherwise; */ public static String getImageUrl(String hash, String quality, String extension) { String newExt = (extension == null) ? IMedia.EXT_JPG : extension; if (hash == null) return null; - if (hash.length() < ALBUM_HASH_LENGTH || hash.length() > IMAGE_HASH_LENGTH) return null; + if (hash.length() < MIN_ALBUM_HASH_LENGTH || hash.length() > IMAGE_HASH_LENGTH) return null; return String.format("%s/%s%s.%s", ImgurApi.IMAGE_URL, hash, quality, newExt); } /** - * Attempts to return a direct link to an image based on a hash alone, without doing an HTTP - * call to the Imgur API. This method might return an invalid URL since it attempts to make an - * educated guess at a URL. Some problematic hashes are for URLs that predate the Imgur API + * Attempts to return a direct link to an image based on a hash alone, without doing an HTTP call to the Imgur API. + * This method might return an invalid URL since it attempts to make an educated guess at a URL. Some problematic + * hashes are for URLs that predate the Imgur API * * @param hash The hash to get an image URL for * @return A URL to an image if the passed in hash was a valid non-album hash, null otherwise; @@ -254,11 +240,10 @@ public static String getImageUrl(String hash) { /** * Sets the default size of the low quality URL imgur returns * - * @param lowQualitySize The default size of the low quality URL Imgur returns. Look at {@link - * Image} for available sizes. Examples: {@link Image#HUGE_THUMBNAIL}, - * {@link Image#GIANT_THUMBNAIL}. Notice, setting this to {@link - * Image#ORIGINAL} can return URLs that weren't intended, for example, an - * mp4 instead of a .jpg + * @param lowQualitySize The default size of the low quality URL Imgur returns. Look at {@link Image} for available + * sizes. Examples: {@link Image#HUGE_THUMBNAIL}, {@link Image#GIANT_THUMBNAIL}. Notice, + * setting this to {@link Image#ORIGINAL} can return URLs that weren't intended, for example, + * an mp4 instead of a .jpg */ public void setLowQualitySize(String lowQualitySize) { mLowQualitySize = lowQualitySize; @@ -267,21 +252,27 @@ public void setLowQualitySize(String lowQualitySize) { /** * Sets the default size of the preview URL imgur returns * - * @param previewSize The default size of the preview URL Imgur returns. Look at {@link Image} - * for available sizes. Examples: {@link Image#BIG_SQUARE}, {@link - * Image#MEDIUM_THUMBNAIL}. Notice, setting this to {@link Image#ORIGINAL} - * can return URLs that weren't intended, for example, an mp4 instead of a + * @param previewSize The default size of the preview URL Imgur returns. Look at {@link Image} for available sizes. + * Examples: {@link Image#BIG_SQUARE}, {@link Image#MEDIUM_THUMBNAIL}. Notice, setting this to + * {@link Image#ORIGINAL} can return URLs that weren't intended, for example, an mp4 instead of a * .jpg */ public void setPreviewSize(String previewSize) { mPreviewSize = previewSize; } - private void checkResponseSuccess(URL mediaUrl, Response serviceResponse) - throws InvalidApiResponseException { + private void checkResponseSuccess(URL mediaUrl, Response serviceResponse) throws InvalidApiResponseException { if (!serviceResponse.isSuccessful()) { ImgurApiError apiError = ErrorUtils.getApiError(getRetrofit(), serviceResponse); throw new InvalidApiResponseException(mediaUrl, apiError.getMessage()); } } + + private boolean isAlbumUrl(URL mediaUrl) throws InvalidMediaUrlException { + if (!isValidDomain(mediaUrl)) { + throw new InvalidMediaUrlException(mediaUrl); + } + String firstSegment = ParseUtils.getFirstPathSegment(mediaUrl); + return ALBUM_PATH.equalsIgnoreCase(firstSegment); + } } diff --git a/lib/src/main/java/com/fernandobarillas/albumparser/imgur/api/ImgurApi.java b/lib/src/main/java/com/fernandobarillas/albumparser/imgur/api/ImgurApi.java index 993abce..0982893 100644 --- a/lib/src/main/java/com/fernandobarillas/albumparser/imgur/api/ImgurApi.java +++ b/lib/src/main/java/com/fernandobarillas/albumparser/imgur/api/ImgurApi.java @@ -22,6 +22,7 @@ import com.fernandobarillas.albumparser.imgur.model.AlbumResponse; import com.fernandobarillas.albumparser.imgur.model.v3.AlbumResponseV3; +import com.fernandobarillas.albumparser.imgur.model.v3.GalleryResponseV3; import com.fernandobarillas.albumparser.imgur.model.v3.ImageResponseV3; import java.util.Arrays; @@ -69,4 +70,9 @@ Call getV3Album(@Header("Authorization") String authHeader, @GET(API_URL_V3 + "/image/{hash}") Call getV3Image(@Header("Authorization") String authHeader, @Path("hash") String hash); + + // https://api.imgur.com/3/image/{id} + @GET(API_URL_V3 + "/gallery/{hash}") + Call getV3Gallery(@Header("Authorization") String authHeader, + @Path("hash") String hash); } diff --git a/lib/src/main/java/com/fernandobarillas/albumparser/imgur/model/v3/GalleryDataV3.java b/lib/src/main/java/com/fernandobarillas/albumparser/imgur/model/v3/GalleryDataV3.java new file mode 100644 index 0000000..90ca26e --- /dev/null +++ b/lib/src/main/java/com/fernandobarillas/albumparser/imgur/model/v3/GalleryDataV3.java @@ -0,0 +1,105 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2016 Fernando Barillas (FBis251) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +package com.fernandobarillas.albumparser.imgur.model.v3; + + +import com.fernandobarillas.albumparser.media.BaseMediaAlbum; +import com.squareup.moshi.Json; + +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +public class GalleryDataV3 extends BaseMediaAlbum { + + @Json(name = "id") + public String id; + @Json(name = "title") + public String title; + @Json(name = "description") + public String description; + @Json(name = "is_album") + public Boolean isAlbum; + @Json(name = "images_count") + public Integer imagesCount; + @Json(name = "images") + public List images; + + private String mLowQuality; + private String mPreviewQuality; + private List mMediaList; + + @Override + public List getAlbumMedia() { + if (mMediaList == null) { + mMediaList = new ArrayList<>(); + for (ImageDataV3 image : images) { + if (mLowQuality != null) image.setLowQuality(mLowQuality); + if (mPreviewQuality != null) image.setPreviewQuality(mPreviewQuality); + mMediaList.add(image); + } + } + return mMediaList; + } + + @Override + public int getCount() { + return imagesCount; + } + + @Override + public URL getPreviewUrl() { + if (images != null && images.size() > 0) { + // Return the first image as the preview + return getAlbumMedia().get(0).getPreviewUrl(); + } + + return null; + } + + @Override + public String toString() { + return "AlbumDataV3{" + + "id='" + + id + + '\'' + + ", title='" + + title + + '\'' + + ", description='" + + description + + '\'' + + ", imagesCount=" + + imagesCount + + ", images=" + + images + + '}'; + } + + protected void setLowQuality(String lowQualitySize) { + mLowQuality = lowQualitySize; + } + + protected void setPreviewQuality(String previewSize) { + mPreviewQuality = previewSize; + } +} diff --git a/lib/src/main/java/com/fernandobarillas/albumparser/imgur/model/v3/GalleryResponseV3.java b/lib/src/main/java/com/fernandobarillas/albumparser/imgur/model/v3/GalleryResponseV3.java new file mode 100644 index 0000000..8e7e1d0 --- /dev/null +++ b/lib/src/main/java/com/fernandobarillas/albumparser/imgur/model/v3/GalleryResponseV3.java @@ -0,0 +1,80 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2016 Fernando Barillas (FBis251) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.fernandobarillas.albumparser.imgur.model.v3; + +import com.fernandobarillas.albumparser.media.BaseApiResponse; +import com.squareup.moshi.Json; + +import java.net.URL; + +public class GalleryResponseV3 extends BaseApiResponse { + + @Json(name = "data") + public AlbumDataV3 data; + @Json(name = "success") + public Boolean success; + @Json(name = "status") + public Integer status; + + @Override + public AlbumDataV3 getAlbum() { + return data; + } + + @Override + public URL getPreviewUrl() { + return (data != null) ? data.getPreviewUrl() : null; + } + + @Override + public boolean isAlbum() { + // This API call is for albums only + // TODO: Get from API response + return true; + } + + @Override + public boolean isSuccessful() { + return success != null && data != null && success; + } + + @Override + public String toString() { + return "GalleryResponseV3{" + + "data=" + + data + + ", success=" + + success + + ", status=" + + status + + '}'; + } + + public void setLowQuality(String lowQualitySize) { + if (data == null) return; + data.setLowQuality(lowQualitySize); + } + + public void setPreviewQuality(String previewSize) { + if (data == null) return; + data.setPreviewQuality(previewSize); + } +} diff --git a/lib/src/test/java/com/fernandobarillas/albumparser/parser/ImgurParserTest.java b/lib/src/test/java/com/fernandobarillas/albumparser/parser/ImgurParserTest.java index b0ea4bb..74f7e42 100644 --- a/lib/src/test/java/com/fernandobarillas/albumparser/parser/ImgurParserTest.java +++ b/lib/src/test/java/com/fernandobarillas/albumparser/parser/ImgurParserTest.java @@ -73,7 +73,7 @@ public ImgurParserTest() { @Test(expected = InvalidApiResponseException.class, timeout = API_CALL_TIMEOUT_MS) @Override public void testApi404Error() throws IOException, RuntimeException { - URL url = getUrlObject("https://imgur.com/a/ccccc"); + URL url = getUrlObject("https://imgur.com/a/abcdef"); assertNotNull(url); mImgurParser.parse(url); } @@ -90,54 +90,34 @@ public void testCanParseAndGetHash() { List validHashes = new ArrayList<>(); // Valid sub-domains - validHashes.add(new ExpectedHash("Htlsv6N", - "http://m.imgur.com/r/aww/Htlsv6N")); // subreddit mobile URL + validHashes.add(new ExpectedHash("Htlsv6N", "http://m.imgur.com/r/aww/Htlsv6N")); // subreddit mobile URL validHashes.add(new ExpectedHash("Htlsv6N", "http://m.imgur.com/Htlsv6N")); // mobile url - validHashes.add(new ExpectedHash("Htlsv6N", - "http://i.imgur.com/Htlsv6N.jpg")); // i subdomain - validHashes.add(new ExpectedHash("1w2MFRq", - "http://b.Bildgur.de/1w2MFRq.png")); // bildgur domain + validHashes.add(new ExpectedHash("Htlsv6N", "http://i.imgur.com/Htlsv6N.jpg")); // i subdomain + validHashes.add(new ExpectedHash("1w2MFRq", "http://b.Bildgur.de/1w2MFRq.png")); // bildgur domain // Albums - validHashes.add(new ExpectedHash("rROMo", - "http://imgur.com/rROMo")); // Album with no prefix - validHashes.add(new ExpectedHash("VhGBD", - "http://imgur.com/r/motivation/VhGBD")); // Album with /r/ prefix - validHashes.add(new ExpectedHash("VhGBD", - "http://imgur.com/t/motivation/VhGBD")); // Album with /t/ prefix - validHashes.add(new ExpectedHash("WKauF", - "https://imgur.com/gallery/WKauF")); // Album with gallery URL - validHashes.add(new ExpectedHash("cvehZ", - "http://www.imgur.com/a/cvehZ")); // /a/ prefix album, www domain + validHashes.add(new ExpectedHash("rROMo", "http://imgur.com/rROMo")); // Album with no prefix + validHashes.add(new ExpectedHash("VhGBD", "http://imgur.com/r/motivation/VhGBD")); // Album with /r/ prefix + validHashes.add(new ExpectedHash("VhGBD", "http://imgur.com/t/motivation/VhGBD")); // Album with /t/ prefix + validHashes.add(new ExpectedHash("WKauF", "https://imgur.com/gallery/WKauF")); // Album with gallery URL + validHashes.add(new ExpectedHash("cvehZ", "http://www.imgur.com/a/cvehZ")); // /a/ prefix album, www domain validHashes.add(new ExpectedHash("cvehZ", "http://imgur.com/a/cvehZ")); // /a/ prefix album - validHashes.add(new ExpectedHash("rROMo", - "https://bildgur.de/a/rROMo")); // /a/ prefix album, bildgur domain - validHashes.add(new ExpectedHash("zis2t", - "http://imgur.com/r/diy/zis2t")); // /r/ prefix album + validHashes.add(new ExpectedHash("rROMo", "https://bildgur.de/a/rROMo")); // /a/ prefix album, bildgur domain + validHashes.add(new ExpectedHash("zis2t", "http://imgur.com/r/diy/zis2t")); // /r/ prefix album // Images - validHashes.add(new ExpectedHash("0MlEZ", - "http://i.imgur.com/0MlEZ.jpg")); // Pre-API direct URL - validHashes.add(new ExpectedHash("awsGf9p", - "http://imgur.com/awsGf9p")); // No prefix image URL - validHashes.add(new ExpectedHash("sCjRLQG", - "http://i.imgur.com/sCjRLQG.jpg?1")); // Direct url with param - validHashes.add(new ExpectedHash("sCjRLQG", - "http://i.imgur.com//sCjRLQG.jpg")); // Direct url with extra slash - validHashes.add(new ExpectedHash("PBTrqAA", - "https://imgur.com/gallery/PBTrqAA")); // gallery prefix - validHashes.add(new ExpectedHash("mhcWa37", - "http://imgur.com/gallery/mhcWa37/new")); // Extra path after hash - validHashes.add(new ExpectedHash("SWSteYm", - "http://imgur.com/r/google/SWSteYm")); // /r/ prefix - - validHashes.add(new ExpectedHash("FGfBEqu", - "https://bildgur.de/FGfBEqu.png")); // Direct bildgur url - validHashes.add(new ExpectedHash("xvn42E1", - "http://b.bildgur.de/xvn42E1.jpg")); // Direct bildgur url + validHashes.add(new ExpectedHash("0MlEZ", "http://i.imgur.com/0MlEZ.jpg")); // Pre-API direct URL + validHashes.add(new ExpectedHash("awsGf9p", "http://imgur.com/awsGf9p")); // No prefix image URL + validHashes.add(new ExpectedHash("sCjRLQG", "http://i.imgur.com/sCjRLQG.jpg?1")); // Direct url with param + validHashes.add(new ExpectedHash("sCjRLQG", "http://i.imgur.com//sCjRLQG.jpg")); // Direct url with extra slash + validHashes.add(new ExpectedHash("PBTrqAA", "https://imgur.com/gallery/PBTrqAA")); // gallery prefix + validHashes.add(new ExpectedHash("mhcWa37", "http://imgur.com/gallery/mhcWa37/new")); // Extra path after hash + validHashes.add(new ExpectedHash("SWSteYm", "http://imgur.com/r/google/SWSteYm")); // /r/ prefix + + validHashes.add(new ExpectedHash("FGfBEqu", "https://bildgur.de/FGfBEqu.png")); // Direct bildgur url + validHashes.add(new ExpectedHash("xvn42E1", "http://b.bildgur.de/xvn42E1.jpg")); // Direct bildgur url validHashes.add(new ExpectedHash("FGfBEqu", "https://bildgur.de/FGfBEqu")); // bildgur url - validHashes.add(new ExpectedHash("1234567", - "http://i.imgur.com/1234567_d.jpg")); // _d suffix + validHashes.add(new ExpectedHash("1234567", "http://i.imgur.com/1234567_d.jpg")); // _d suffix // Synthetic URLs validHashes.add(new ExpectedHash("12345", "http://imgur.com/12345.jpg")); @@ -165,8 +145,12 @@ public void testCanParseAndGetHash() { validHashes.add(new ExpectedHash("12345", "http://imgur.com/gallery/12345")); validHashes.add(new ExpectedHash("abcde", "http://imgur.com/gallery/abcde")); + validHashes.add(new ExpectedHash("1234567", "http://imgur.com/1234567")); + validHashes.add(new ExpectedHash("abcdefg", "http://imgur.com/abcdefg")); validHashes.add(new ExpectedHash("1234567", "http://imgur.com/gallery/1234567")); validHashes.add(new ExpectedHash("abcdefg", "http://imgur.com/gallery/abcdefg")); + validHashes.add(new ExpectedHash("1234567", "http://imgur.com/a/1234567")); + validHashes.add(new ExpectedHash("abcdefg", "http://imgur.com/a/abcdefg")); validHashes.add(new ExpectedHash("12345", "http://imgur.com/a/test/12345")); validHashes.add(new ExpectedHash("abcde", "http://imgur.com/a/test/abcde")); @@ -177,6 +161,12 @@ public void testCanParseAndGetHash() { validHashes.add(new ExpectedHash("abcdefg", "http://imgur.com/r/test/abcdefg")); validHashes.add(new ExpectedHash("wi3Sl", "http://i.stack.imgur.com/wi3Sl.jpg")); + // Real urls + validHashes.add(new ExpectedHash("wspUqCv", "https://imgur.com/wspUqCv")); // Single image + validHashes.add(new ExpectedHash("3OMFeBx", "https://imgur.com/gallery/3OMFeBx")); // Album + validHashes.add(new ExpectedHash("3OMFeBx", "https://imgur.com/a/3OMFeBx")); // Album + validHashes.add(new ExpectedHash("mPqzVMZ", "https://imgur.com/gallery/mPqzVMZ")); // Single image + validateCanParseAndHashes(mImgurParser, validHashes, false); } @@ -190,8 +180,6 @@ public void testInvalidUrls() { invalidUrls.add("https://imgur.com/a/1234"); invalidUrls.add("https://imgur.com/a/1234_"); - invalidUrls.add("https://imgur.com/a/123456"); - invalidUrls.add("https://imgur.com/a/1234567"); invalidUrls.add("https://imgur.com/a/12345678"); invalidUrls.add("https://imgur.com/gallery/1234"); @@ -238,6 +226,46 @@ public void testInvalidUrls() { assertInvalidUrlsThrowException(mImgurParser, invalidUrls); } + // Tests a standard album URL with the old API call + @Test(timeout = API_CALL_TIMEOUT_MS) + public void testAlbumWithGalleryUrl() throws IOException, RuntimeException { + URL url = getUrlObject("https://imgur.com/gallery/3OMFeBx"); + String albumPreviewUrl = "https://i.imgur.com/wspUqCv" + mPreviewQuality + ".png"; + + ExpectedMedia image1 = new ExpectedMedia.Builder() + .setHighQualityUrl("https://i.imgur.com/wspUqCv.png") + .setLowQualityUrl("https://i.imgur.com/wspUqCvm.png") + .setPreviewUrl("https://i.imgur.com/wspUqCvs.png") + .setHighQualityByteSize(89154) + .setHighQualityWidth(268) + .setHighQualityHeight(315) + .setDescription("The Simpsons Family") + .build(); + ExpectedMedia image2 = new ExpectedMedia.Builder() + .setHighQualityUrl("https://i.imgur.com/grlYZVG.png") + .setLowQualityUrl("https://i.imgur.com/grlYZVGm.png") + .setPreviewUrl("https://i.imgur.com/grlYZVGs.png") + .setHighQualityByteSize(193905) + .setHighQualityWidth(533) + .setHighQualityHeight(187) + .setDescription("Simpsons Characters") + .build(); + List expectedMediaList = new ArrayList<>(); + expectedMediaList.add(image1); + expectedMediaList.add(image2); + + ExpectedAlbum expectedAlbum = new ExpectedAlbum.Builder() + .setCount(2) + .setPreviewUrl(albumPreviewUrl) + .setAlbumMedia(expectedMediaList) + .build(); + + ExpectedParserResponse expectedParserResponse = + new ExpectedParserResponse.Builder(url).setIsAlbum(true).setMediaAlbum(expectedAlbum).build(); + ParserResponse parserResponse = mImgurParser.parse(url); + compareParserResponse(url, expectedParserResponse, parserResponse); + } + // Tests a direct GIF URL with no API call @Test public void testGifWithNoApiCall() throws IOException { @@ -246,9 +274,7 @@ public void testGifWithNoApiCall() throws IOException { ExpectedMedia expectedMedia = getExpectedMediaBuilder(hash, true).build(); ExpectedParserResponse expectedParserResponse = - new ExpectedParserResponse.Builder(url).setIsSingleMedia(true) - .setMedia(expectedMedia) - .build(); + new ExpectedParserResponse.Builder(url).setIsSingleMedia(true).setMedia(expectedMedia).build(); ParserResponse parserResponse = mImgurParserNoApiKey.parse(url); compareParserResponse(url, expectedParserResponse, parserResponse); @@ -261,9 +287,7 @@ public void testGifWithUppercaseExtension() throws IOException { String hash = "M1ZXzzn"; ExpectedMedia expectedMedia = getExpectedMediaBuilder(hash, true).build(); ExpectedParserResponse expectedParserResponse = - new ExpectedParserResponse.Builder(url).setIsSingleMedia(true) - .setMedia(expectedMedia) - .build(); + new ExpectedParserResponse.Builder(url).setIsSingleMedia(true).setMedia(expectedMedia).build(); ParserResponse parserResponse = mImgurParserNoApiKey.parse(url); compareParserResponse(url, expectedParserResponse, parserResponse); @@ -276,9 +300,7 @@ public void testGifvWithNoApiCall() throws IOException { String hash = "aRadjBe"; ExpectedMedia expectedMedia = getExpectedMediaBuilder(hash, true).build(); ExpectedParserResponse expectedParserResponse = - new ExpectedParserResponse.Builder(url).setIsSingleMedia(true) - .setMedia(expectedMedia) - .build(); + new ExpectedParserResponse.Builder(url).setIsSingleMedia(true).setMedia(expectedMedia).build(); ParserResponse parserResponse = mImgurParserNoApiKey.parse(url); compareParserResponse(url, expectedParserResponse, parserResponse); @@ -299,9 +321,7 @@ public void testJpgThumbnailWithNoApiCall() throws IOException { String hash = "jIg2N6q"; ExpectedMedia expectedMedia = getExpectedMediaBuilder(hash, false).build(); ExpectedParserResponse expectedParserResponse = - new ExpectedParserResponse.Builder(url).setIsSingleMedia(true) - .setMedia(expectedMedia) - .build(); + new ExpectedParserResponse.Builder(url).setIsSingleMedia(true).setMedia(expectedMedia).build(); ParserResponse parserResponse = mImgurParserNoApiKey.parse(url); compareParserResponse(url, expectedParserResponse, parserResponse); @@ -314,9 +334,7 @@ public void testJpgWithNoApiCall() throws IOException { String hash = "zzaVA8m"; ExpectedMedia expectedMedia = getExpectedMediaBuilder(hash, false).build(); ExpectedParserResponse expectedParserResponse = - new ExpectedParserResponse.Builder(url).setIsSingleMedia(true) - .setMedia(expectedMedia) - .build(); + new ExpectedParserResponse.Builder(url).setIsSingleMedia(true).setMedia(expectedMedia).build(); ParserResponse parserResponse = mImgurParserNoApiKey.parse(url); compareParserResponse(url, expectedParserResponse, parserResponse); @@ -335,8 +353,8 @@ public void testNullJsonFields() throws IOException { @Test(timeout = API_CALL_TIMEOUT_MS) public void testOldApiAlbum() throws IOException, RuntimeException { URL url = getUrlObject("http://imgur.com/a/NzCBe"); - ExpectedParserResponse expectedParserResponse = - getV3AlbumExpectedParserResponse(url, false); + ExpectedParserResponse expectedParserResponse = getV3AlbumExpectedParserResponse(url, false); + ParserResponse parserResponse = mImgurParserNoApiKey.parse(url); compareParserResponse(url, expectedParserResponse, parserResponse); } @@ -348,11 +366,9 @@ public void testOldFormatJpgWithNoApiCall() throws IOException { String hash = "0MlEZ"; ExpectedMedia expectedMedia = getExpectedMediaBuilder(hash, false).build(); ExpectedParserResponse expectedParserResponse = - new ExpectedParserResponse.Builder(url).setIsSingleMedia(true) - .setMedia(expectedMedia) - .build(); + new ExpectedParserResponse.Builder(url).setIsSingleMedia(true).setMedia(expectedMedia).build(); - ParserResponse parserResponse = mImgurParser.parse(url); + ParserResponse parserResponse = mImgurParserNoApiKey.parse(url); compareParserResponse(url, expectedParserResponse, parserResponse); } @@ -365,6 +381,15 @@ public void testV3Album() throws IOException, RuntimeException { compareParserResponse(url, expectedParserResponse, parserResponse); } + // Tests a standard album URL with the old API call + @Test(timeout = API_CALL_TIMEOUT_MS) + public void testV3AlbumNew() throws IOException, RuntimeException { + URL url = getUrlObject("http://imgur.com/a/NzCBe"); + ExpectedParserResponse expectedParserResponse = getV3AlbumExpectedParserResponse(url, false); + ParserResponse parserResponse = mImgurParserNoApiKey.parse(url); + compareParserResponse(url, expectedParserResponse, parserResponse); + } + // Tests an album with a /gallery URL using the v3 API @Test(timeout = API_CALL_TIMEOUT_MS) public void testV3AlbumWithGalleryUrl() throws IOException, RuntimeException { @@ -387,50 +412,46 @@ public void testV3Image() throws IOException, RuntimeException { @Test(timeout = API_CALL_TIMEOUT_MS) public void testV3ImageWithShortHash() throws IOException, RuntimeException { URL url = getUrlObject("https://imgur.com/0MlEZ"); - ExpectedMedia expectedImage = - getExpectedMediaBuilder("0MlEZ", false).setHighQualityByteSize(126099) - .setHighQualityWidth(553) - .setHighQualityHeight(833) - .build(); + ExpectedMedia expectedImage = getExpectedMediaBuilder("0MlEZ", false) + .setHighQualityByteSize(126099) + .setHighQualityWidth(553) + .setHighQualityHeight(833) + .build(); ExpectedParserResponse expectedParserResponse = - new ExpectedParserResponse.Builder(url).setIsSingleMedia(true) - .setMedia(expectedImage) - .build(); + new ExpectedParserResponse.Builder(url).setIsSingleMedia(true).setMedia(expectedImage).build(); ParserResponse parserResponse = mImgurParser.parse(url); compareParserResponse(url, expectedParserResponse, parserResponse); } - private ExpectedMedia.Builder getExpectedMediaBuilder(final String hash, - final boolean isAnimated) { + private ExpectedMedia.Builder getExpectedMediaBuilder(final String hash, final boolean isAnimated) { String expectedExtension = isAnimated ? ".mp4" : ".jpg"; - return new ExpectedMedia.Builder().setPreviewUrl("https://i.imgur.com/" - + hash - + mPreviewQuality - + ".jpg") + return new ExpectedMedia.Builder() + .setPreviewUrl("https://i.imgur.com/" + hash + mPreviewQuality + ".jpg") .setHighQualityUrl("https://i.imgur.com/" + hash + expectedExtension) // No low quality URLs for animated results - .setLowQualityUrl( - !isAnimated ? "https://i.imgur.com/" + hash + mLowQuality + ".jpg" : null) + .setLowQualityUrl(!isAnimated ? "https://i.imgur.com/" + hash + mLowQuality + ".jpg" : null) .setIsVideo(isAnimated); } private ExpectedMedia getFbLogoExpectedMedia() { - return getExpectedMediaBuilder("P3Z2WfX", false).setHighQualityByteSize(4753) + return getExpectedMediaBuilder("P3Z2WfX", false) + .setHighQualityByteSize(4753) .setHighQualityWidth(256) .setHighQualityHeight(256) .setTitle("FB Logo") .setDescription("FB logo description") + .setHighQualityByteSize(4753) .build(); } private ExpectedMedia getSpiralAnimationExpectedMedia(final boolean isV3ApiCall) { - ExpectedMedia.Builder builder = - getExpectedMediaBuilder("Siit59R", true).setHighQualityWidth(347) - .setHighQualityHeight(326) - .setTitle("Spiral Animation") - .setDescription("Spiral animation description"); + ExpectedMedia.Builder builder = getExpectedMediaBuilder("Siit59R", true) + .setHighQualityWidth(347) + .setHighQualityHeight(326) + .setTitle("Spiral Animation") + .setDescription("Spiral animation description"); if (isV3ApiCall) { // Only the V3 API call supports MP4 file sizes @@ -440,24 +461,23 @@ private ExpectedMedia getSpiralAnimationExpectedMedia(final boolean isV3ApiCall) return builder.build(); } - private ExpectedParserResponse getV3AlbumExpectedParserResponse(final URL albumUrl, - final boolean isV3ApiCall) { + private ExpectedParserResponse getV3AlbumExpectedParserResponse(final URL albumUrl, final boolean isV3ApiCall) { String albumPreviewUrl = "https://i.imgur.com/P3Z2WfX" + mPreviewQuality + ".jpg"; List expectedMediaList = new ArrayList<>(); expectedMediaList.add(getFbLogoExpectedMedia()); expectedMediaList.add(getSpiralAnimationExpectedMedia(isV3ApiCall)); - ExpectedAlbum expectedAlbum = new ExpectedAlbum.Builder().setCount(2) + ExpectedAlbum expectedAlbum = new ExpectedAlbum.Builder() + .setCount(2) .setPreviewUrl(albumPreviewUrl) .setAlbumMedia(expectedMediaList) .build(); - return new ExpectedParserResponse.Builder(albumUrl).setIsAlbum(true) - .setMediaAlbum(expectedAlbum) - .build(); + return new ExpectedParserResponse.Builder(albumUrl).setIsAlbum(true).setMediaAlbum(expectedAlbum).build(); } private ExpectedParserResponse getV3ImageExpectedParserResponse(final URL imageUrl) { - return new ExpectedParserResponse.Builder(imageUrl).setIsSingleMedia(true) + return new ExpectedParserResponse.Builder(imageUrl) + .setIsSingleMedia(true) .setMedia(getFbLogoExpectedMedia()) .build(); }