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