Java tutorial
/** This file is released under the Apache License 2.0. See the LICENSE file for details. **/ package com.github.kskelm.baringo; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import com.github.kskelm.baringo.model.Image; import com.github.kskelm.baringo.model.ImgurResponseWrapper; import com.github.kskelm.baringo.util.BaringoApiException; import com.github.kskelm.baringo.util.BaringoAuthException; import com.google.gson.GsonBuilder; import com.squareup.okhttp.MediaType; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.RequestBody; import retrofit.Call; import retrofit.Response; /** * * Services related to manipulating images in Imgur (why we're here, assumedly) * @author Kevin Kelm (triggur@gmail.com) */ public class ImageService { /** * Given an image id, return info about the Image object for it. * <p> * <b>ACCESS: ANONYMOUS</b> * @param id the id of the image, for example "PgZtz0j". * If a user is logged in and this image is theirs, the * deleteHash property will be filled in. It will otherwise * be null * @return Image object * @throws BaringoApiException something went pear-shaped */ public Image getImageInfo(String id) throws BaringoApiException { Call<ImgurResponseWrapper<Image>> call = client.getApi().getImageInfo(id); try { Response<ImgurResponseWrapper<Image>> res = call.execute(); ImgurResponseWrapper<Image> out = res.body(); client.throwOnWrapperError(res); return out.getData(); } catch (IOException e) { throw new BaringoApiException(e.getMessage()); } // try-catch } /** * Upload an image to Imgur by pointing at a Url on the internet. * Must be available openly without authentication. * <p> * <b>ACCESS: ANONYMOUS</b> or <b>AUTHENTICATED USER</b> * @param Url the full URL of the image. * @param fileName original of the file being uploaded (pick something) * @param albumId the name of the album, the album's deleteHash if it's anonymous, or null if none * @param title title of image or null if none * @param description description of image or null if none * @return The new Image object. If this is anonymous, <i>hang on to the delete hash</i> or you won't be able to manipulate it in the future! * @throws BaringoApiException something terrible happened to Stuart! */ public Image uploadUrlImage(String Url, String fileName, String albumId, String title, String description) throws BaringoApiException { RequestBody body = RequestBody.create(MediaType.parse("text/plain"), Url); Call<ImgurResponseWrapper<Image>> call = client.getApi().uploadUrlImage(albumId, "URL", title, description, body); try { Response<ImgurResponseWrapper<Image>> res = call.execute(); ImgurResponseWrapper<Image> out = res.body(); client.throwOnWrapperError(res); return out.getData(); } catch (IOException e) { throw new BaringoApiException(e.getMessage()); } // try-catch } /** * Upload an image to Imgur as a stream from the local filesystem. * Use a buffered stream wherever possible! * <p> * <b>ACCESS: ANONYMOUS</b> or <b>AUTHENTICATED USER</b> * @param mimeType mime type like image/png. If null, Baringo will try to infer this from the fileName. * @param fileName name of the file being uploaded * @param albumId the name of the album, the album's deleteHash if it's anonymous, or null if none * @param title title of image or null if none * @param description description of image or null if none * @return The new Image object. If this is anonymous, <i>hang on to the delete hash</i> or you won't be able to manipulate it in the future! * @throws IOException Something was wrong with the file or streaming didn't work * @throws BaringoApiException que sera sera */ public Image uploadLocalImage(String mimeType, String fileName, String albumId, String title, String description) throws IOException, BaringoApiException { // can be null File file = new File(fileName); if (!file.exists()) { throw new FileNotFoundException("File not found: " + fileName); } // if if (!file.canRead()) { throw new IOException("Cannot access file " + fileName); } // if if (mimeType == null) { // infer from file prefix int dotAt = fileName.lastIndexOf('.'); if (dotAt == -1) { throw new BaringoApiException("Could not infer mime type" + " from file name; no extension"); } // if String ext = fileName.substring(dotAt + 1).toLowerCase(); mimeType = extensionToMimeType.get(ext); if (mimeType == null) { throw new BaringoApiException("Could not infer mime type" + " from extension '" + ext + "'"); } // if } // if // strip the directory hierarchy off the filename. Path path = Paths.get(fileName); fileName = path.getFileName().toString(); RequestBody body = RequestBody.create(MediaType.parse(mimeType), file); Call<ImgurResponseWrapper<Image>> call = client.getApi().uploadLocalImage(albumId, "file", title, description, fileName, body); try { Response<ImgurResponseWrapper<Image>> res = call.execute(); ImgurResponseWrapper<Image> out = res.body(); client.throwOnWrapperError(res); return out.getData(); } catch (IOException e) { throw new BaringoApiException(e.getMessage()); } // try-catch } /** * Given an image id and an output stream, download the image * and write it to the stream. It is the caller's responsibility * to close everything. * <p> * NOTE: This is synchronous. * <p> * <b>ACCESS: ANONYMOUS</b> * @param imageLink the image link to download (could be a thumb too) * @param outStream an output stream to write the data to * @return the number of bytes written * @throws IOException could be anything really * @throws BaringoApiException Imgur didn't like something */ public long downloadImage(String imageLink, OutputStream outStream) throws IOException, BaringoApiException { Request request = new Request.Builder().url(imageLink).build(); OkHttpClient client = new OkHttpClient(); com.squareup.okhttp.Response resp = client.newCall(request).execute(); if (resp.code() != 200 || !resp.isSuccessful()) { throw new BaringoApiException(request.urlString() + ": " + resp.message(), resp.code()); } // if if (resp.body() == null) { throw new BaringoApiException("No response body found"); } // if InputStream is = resp.body().byteStream(); BufferedInputStream input = new BufferedInputStream(is); byte[] data = new byte[8192]; // because powers of two are magic long total = 0; int count = 0; while ((count = input.read(data)) != -1) { total += count; outStream.write(data, 0, count); } // while return total; } /** * Given an image id and a file path to store it to, download * the image. File must be writeable and the path must exist. * <p> * NOTE: This is synchronous. * <p> * <b>ACCESS: ANONYMOUS</b> * @param imageLink the image link to download (could be a thumb too) * @param fileName name of the file to write to * @return the number of bytes written * @throws IOException myriad * @throws BaringoApiException Imgur didn't like something */ public long downloadImage(String imageLink, String fileName) throws IOException, BaringoApiException { OutputStream output = null; try { output = new BufferedOutputStream(new FileOutputStream(fileName)); return downloadImage(imageLink, output); } finally { output.close(); } // try-finally } /** * Updates an image with a new title and description * <p> * <b>ACCESS: ANONYMOUS</b> or AUTHENTICATED USER * @param idOrDeleteHash If the image is anonymous, this is the delete hash. If not then it's an imageId and the currently-authenticated account must own it. * @param title title of the image or null if none * @param description description of the image or null if none * @return true if it worked * @throws BaringoApiException C'est la vie */ public boolean updateImage(String idOrDeleteHash, String title, String description) throws BaringoApiException { Call<ImgurResponseWrapper<Boolean>> call = client.getApi().updateImageInfo(idOrDeleteHash, title, description); try { Response<ImgurResponseWrapper<Boolean>> res = call.execute(); ImgurResponseWrapper<Boolean> out = res.body(); client.throwOnWrapperError(res); return out.getData(); } catch (IOException e) { throw new BaringoApiException(e.getMessage()); } // try-catch } /** * Deletes an image * <p> * <b>ACCESS: ANONYMOUS</b> or <b>AUTHENTICATED USER</b> * @param idOrDeleteHash If the image is anonymous, this is the delete hash. If not then it's an imageId and the currently-authenticated account must own it. * @return true if it worked * @throws BaringoApiException C'est la vie */ public boolean deleteImage(String idOrDeleteHash) throws BaringoApiException { Call<ImgurResponseWrapper<Boolean>> call = client.getApi().deleteImage(idOrDeleteHash); try { Response<ImgurResponseWrapper<Boolean>> res = call.execute(); ImgurResponseWrapper<Boolean> out = res.body(); client.throwOnWrapperError(res); return out.getData(); } catch (IOException e) { throw new BaringoApiException(e.getMessage()); } // try-catch } /** * Marks the image as favorite for the currently-authenticated user. * Note that the Image object needs to be in sync with Imgur because * the site's API only acknowledges a toggle of the value. The image * object is updated with the new status. If the image is already * marked as a favorite, no action is taken. * <p> * NOTE: An account can't favorite its own images. * <p> * <b>ACCESS: AUTHENTICATED USER</b> * @param image the image to favorite. * @return the updated image object * @throws BaringoApiException argh */ public Image favoriteImage(Image image) throws BaringoApiException { if (!client.authService().isUserAuthenticated()) { throw new BaringoAuthException("No user logged in", 401); } // if if (image.isFavorite()) { return image; // already done } // if Call<ImgurResponseWrapper<Image>> call = client.getApi().toggleImageFavorite(image.getId()); try { Response<ImgurResponseWrapper<Image>> res = call.execute(); ImgurResponseWrapper<Image> out = res.body(); client.throwOnWrapperError(res); return out.getData(); } catch (IOException e) { throw new BaringoApiException(e.getMessage()); } } /** * Unfavorites the image for the currently-authenticated user. * Note that the Image object needs to be in sync with Imgur because * the site's API only acknowledges a toggle of the value. The image * object is updated with the new status. If the image is already * not favorited, no action is taken. * <p> * NOTE: An account can't unfavorite its own images. * <p> * <b>ACCESS: AUTHENTICATED USER</b> * @param image the image to favorite. * @return the updated image object * @throws BaringoApiException argh */ public Image unfavoriteImage(Image image) throws BaringoApiException { if (!client.authService().isUserAuthenticated()) { throw new BaringoAuthException("No user logged in", 401); } // if if (!image.isFavorite()) { return image; // already done } // if Call<ImgurResponseWrapper<Image>> call = client.getApi().toggleImageFavorite(image.getId()); try { Response<ImgurResponseWrapper<Image>> res = call.execute(); ImgurResponseWrapper<Image> out = res.body(); client.throwOnWrapperError(res); return out.getData(); } catch (IOException e) { throw new BaringoApiException(e.getMessage()); } } // ================================================ protected ImageService(BaringoClient imgurClient, GsonBuilder gsonBuilder) { this.client = imgurClient; extensionToMimeType.put("apng", "image/png"); extensionToMimeType.put("gif", "image/gif"); extensionToMimeType.put("jpeg", "image/jpeg"); extensionToMimeType.put("jpg", "image/jpeg"); extensionToMimeType.put("pdf", "application/pdf"); extensionToMimeType.put("png", "image/png"); extensionToMimeType.put("tif", "image/tiff"); extensionToMimeType.put("tiff", "image/tiff"); extensionToMimeType.put("xcf", "image/xcf"); } // constructor private BaringoClient client = null; private HashMap<String, String> extensionToMimeType = new HashMap<>(); } // class AccountService