1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.pump.provider; 18 19 import android.net.Uri; 20 21 import androidx.annotation.AnyThread; 22 import androidx.annotation.NonNull; 23 import androidx.annotation.WorkerThread; 24 25 import com.android.pump.db.Album; 26 import com.android.pump.db.Artist; 27 import com.android.pump.db.DataProvider; 28 import com.android.pump.db.Episode; 29 import com.android.pump.db.Movie; 30 import com.android.pump.db.Series; 31 import com.android.pump.util.Clog; 32 import com.android.pump.util.Http; 33 34 import org.json.JSONException; 35 import org.json.JSONObject; 36 import org.json.JSONTokener; 37 38 import java.io.IOException; 39 import java.nio.charset.StandardCharsets; 40 41 @WorkerThread 42 public final class OmdbApi implements DataProvider { 43 private static final String TAG = Clog.tag(OmdbApi.class); 44 45 private static final DataProvider INSTANCE = new OmdbApi(); 46 OmdbApi()47 private OmdbApi() { } 48 49 @AnyThread getInstance()50 public static @NonNull DataProvider getInstance() { 51 return INSTANCE; 52 } 53 54 @Override populateArtist(@onNull Artist artist)55 public boolean populateArtist(@NonNull Artist artist) throws IOException { 56 // NO-OP 57 return false; 58 } 59 60 @Override populateAlbum(@onNull Album album)61 public boolean populateAlbum(@NonNull Album album) throws IOException { 62 // NO-OP 63 return false; 64 } 65 66 @Override populateMovie(@onNull Movie movie)67 public boolean populateMovie(@NonNull Movie movie) throws IOException { 68 boolean updated = false; 69 try { 70 JSONObject root = (JSONObject) getContent(getContentUri(movie)); 71 updated |= movie.setPosterUri(getPosterUri(root.getString("imdbID"))); 72 updated |= movie.setSynopsis(root.getString("Plot")); 73 } catch (JSONException e) { 74 Clog.w(TAG, "Failed to parse search result", e); 75 throw new IOException(e); 76 } 77 return updated; 78 } 79 80 @Override populateSeries(@onNull Series series)81 public boolean populateSeries(@NonNull Series series) throws IOException { 82 boolean updated = false; 83 try { 84 JSONObject root = (JSONObject) getContent(getContentUri(series)); 85 updated |= series.setPosterUri(getPosterUri(root.getString("imdbID"))); 86 } catch (JSONException e) { 87 Clog.w(TAG, "Failed to parse search result", e); 88 throw new IOException(e); 89 } 90 return updated; 91 } 92 93 @Override populateEpisode(@onNull Episode episode)94 public boolean populateEpisode(@NonNull Episode episode) throws IOException { 95 boolean updated = false; 96 try { 97 JSONObject root = (JSONObject) getContent(getContentUri(episode)); 98 updated |= episode.setPosterUri(getPosterUri(root.getString("imdbID"))); 99 } catch (JSONException e) { 100 Clog.w(TAG, "Failed to parse search result", e); 101 throw new IOException(e); 102 } 103 return updated; 104 } 105 getContentUri(@onNull Movie movie)106 private static @NonNull Uri getContentUri(@NonNull Movie movie) { 107 Uri.Builder ub = getContentUri(movie.getTitle()); 108 if (movie.hasYear()) { 109 ub.appendQueryParameter("y", Integer.toString(movie.getYear())); 110 } 111 ub.appendQueryParameter("type", "movie"); 112 return ub.build(); 113 } 114 getContentUri(@onNull Series series)115 private static @NonNull Uri getContentUri(@NonNull Series series) { 116 Uri.Builder ub = getContentUri(series.getTitle()); 117 if (series.hasYear()) { 118 ub.appendQueryParameter("y", Integer.toString(series.getYear())); 119 } 120 ub.appendQueryParameter("type", "series"); 121 return ub.build(); 122 } 123 getContentUri(@onNull Episode episode)124 private static @NonNull Uri getContentUri(@NonNull Episode episode) { 125 Series series = episode.getSeries(); 126 Uri.Builder ub = getContentUri(series.getTitle()); 127 if (series.hasYear()) { 128 ub.appendQueryParameter("y", Integer.toString(series.getYear())); 129 } 130 ub.appendQueryParameter("Season", Integer.toString(episode.getSeason())); 131 ub.appendQueryParameter("Episode", Integer.toString(episode.getEpisode())); 132 ub.appendQueryParameter("type", "episode"); 133 return ub.build(); 134 } 135 getContentUri(@onNull String title)136 private static @NonNull Uri.Builder getContentUri(@NonNull String title) { 137 Uri.Builder ub = new Uri.Builder(); 138 ub.scheme("https"); 139 ub.authority("omdbapi.com"); 140 ub.appendQueryParameter("apikey", ApiKeys.OMDB_API); 141 ub.appendQueryParameter("t", title); 142 return ub; 143 } 144 getContent(@onNull Uri uri)145 private static @NonNull Object getContent(@NonNull Uri uri) throws IOException, JSONException { 146 return new JSONTokener(new String(Http.get(uri.toString()), StandardCharsets.UTF_8)) 147 .nextValue(); 148 } 149 getPosterUri(@onNull String imdbId)150 private static @NonNull Uri getPosterUri(@NonNull String imdbId) { 151 Uri.Builder ub = new Uri.Builder(); 152 ub.scheme("https"); 153 ub.authority("img.omdbapi.com"); 154 ub.appendQueryParameter("apikey", ApiKeys.OMDB_API); 155 ub.appendQueryParameter("i", imdbId); 156 return ub.build(); 157 } 158 } 159