/* * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.pump.provider; import android.net.Uri; import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import com.android.pump.util.Clog; import com.android.pump.util.Http; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @WorkerThread public final class Wikidata { private static final String TAG = Clog.tag(Wikidata.class); private Wikidata() { } public static void search(@NonNull Query query) throws IOException { search(query, 1); } public static void search(@NonNull Query query, int maxResults) throws IOException { Clog.i(TAG, "search(" + query + ", " + maxResults + ")"); getContentForResults(getSearchResults(getQueryString(query), maxResults)); } private static String getQueryString(Query query) { StringBuilder builder = new StringBuilder(); builder.append(query.getName()); if (query.hasYear()) { builder.append(' '); builder.append(query.getYear()); } if (query.isEpisode()) { builder.append(' '); builder.append('s'); builder.append(query.getSeason()); builder.append(' '); builder.append('e'); builder.append(query.getEpisode()); } return builder.toString(); } private static List getSearchResults(String search, int maxResults) throws IOException { String uri = getSearchUri(search, maxResults); Clog.i(TAG, uri); String result = new String(Http.get(uri), StandardCharsets.UTF_8); Clog.i(TAG, result); try { Object root = new JSONTokener(result).nextValue(); dumpJson(root); JSONObject resultRoot = (JSONObject) root; JSONArray resultArray = resultRoot.getJSONObject("query").getJSONArray("search"); List ids = new ArrayList<>(resultArray.length()); for (int i = 0; i < resultArray.length(); ++i) { ids.add(resultArray.getJSONObject(i).getString("title")); } return ids; } catch (JSONException e) { Clog.w(TAG, "Failed to parse search result", e); throw new IOException(e); } } private static void getContentForResults(List ids) throws IOException { /* String uri = getContentUri(ids); Clog.i(TAG, uri); String result = new String(Http.get(uri), StandardCharsets.UTF_8); //Clog.i(TAG, result); try { Object root = new JSONTokener(result).nextValue(); //dumpJson(root); JSONObject resultRoot = (JSONObject) root; } catch (JSONException e) { Clog.w(TAG, "Failed to parse data", e); throw new IOException(e); } */ getSparqlForResults(ids); } private static void getSparqlForResults(List ids) throws IOException { String uri = getSparqlUri(ids); Clog.i(TAG, uri); String result = new String(Http.get(uri), StandardCharsets.UTF_8); Clog.i(TAG, result); try { Object root = new JSONTokener(result).nextValue(); dumpJson(root); JSONObject resultRoot = (JSONObject) root; } catch (JSONException e) { Clog.w(TAG, "Failed to parse sparql", e); throw new IOException(e); } } private static String getSearchUri(String search, int maxResults) { Uri.Builder ub = new Uri.Builder(); ub.scheme("https"); ub.authority("www.wikidata.org"); ub.appendPath("w"); ub.appendPath("api.php"); ub.appendQueryParameter("action", "query"); ub.appendQueryParameter("list", "search"); ub.appendQueryParameter("format", "json"); ub.appendQueryParameter("formatversion", "2"); ub.appendQueryParameter("srsearch", search); ub.appendQueryParameter("srlimit", Integer.toString(maxResults)); ub.appendQueryParameter("srprop", ""); ub.appendQueryParameter("srinfo", ""); return ub.build().toString(); } /* */ // https://www.wikidata.org/wiki/Wikidata:SPARQL_query_service /* const endpointUrl = 'https://query.wikidata.org/sparql', sparqlQuery = `SELECT DISTINCT ?item ?itemLabel ?itemDescription WHERE { ?item wdt:P31/wdt:P279* wd:Q11424. SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en" } ?item wdt:P3383 ?itemPoster. }`, fullUrl = endpointUrl + '?query=' + encodeURIComponent( sparqlQuery ), headers = { 'Accept': 'application/sparql-results+json' }; fetch( fullUrl, { headers } ).then( body => body.json() ).then( json => { const { head: { vars }, results } = json; for ( const result of results.bindings ) { for ( const variable of vars ) { console.log( '%s: %o', variable, result[variable] ); } console.log( '---' ); } } ); */ // ?action=wbgetentities&ids=Q775450|Q3041294|Q646968|Q434841|Q11920&format=jsonfm&props=labels&languages=en|de|fr private static String getContentUri(List ids) { Uri.Builder ub = new Uri.Builder(); ub.scheme("https"); ub.authority("www.wikidata.org"); ub.appendPath("w"); ub.appendPath("api.php"); ub.appendQueryParameter("action", "wbgetentities"); ub.appendQueryParameter("props", "labels|descriptions"); ub.appendQueryParameter("format", "json"); ub.appendQueryParameter("formatversion", "2"); ub.appendQueryParameter("languages", "en"); ub.appendQueryParameter("languagefallback", ""); ub.appendQueryParameter("ids", TextUtils.join("|", ids)); return ub.build().toString(); } private static String getSparqlUri(List ids) { List dbIds = new ArrayList<>(ids.size()); for (String id : ids) { dbIds.add("wd:" + id); } String sparqlQuery = "" + "SELECT * WHERE {" + "VALUES ?item {" + TextUtils.join(" ", dbIds) + "}" + "FILTER EXISTS {?item wdt:P31/wdt:P279* wd:Q11424.}" + "OPTIONAL {?item wdt:P3383 ?poster.}" + "?item rdfs:label ?title FILTER (lang(?title) = 'en')." + "}"; Uri.Builder ub = new Uri.Builder(); ub.scheme("https"); ub.authority("query.wikidata.org"); ub.appendPath("sparql"); ub.appendQueryParameter("format", "json"); ub.appendQueryParameter("query", sparqlQuery); return ub.build().toString(); } private static void dumpJson(Object root) throws JSONException { dumpJson(null, "", root); } private static void dumpJson(String name, String indent, Object object) throws JSONException { name = name != null ? name + ": " : ""; if (object == JSONObject.NULL) { Clog.d(TAG, indent + name + "null"); } else if (object instanceof JSONObject) { Clog.d(TAG, indent + name + "{"); JSONObject jsonObject = (JSONObject) object; Iterator keys = jsonObject.keys(); while (keys.hasNext()) { String key = keys.next(); dumpJson(key, indent + " ", jsonObject.get(key)); } Clog.d(TAG, indent + "}"); } else if (object instanceof JSONArray) { Clog.d(TAG, indent + name + "["); JSONArray jsonArray = (JSONArray) object; for (int i = 0; i < jsonArray.length(); ++i) { dumpJson(null, indent + " ", jsonArray.get(i)); } Clog.d(TAG, indent + "]"); } else if (object instanceof String) { String jsonString = (String) object; Clog.d(TAG, indent + name + jsonString + " (string)"); } else if (object instanceof Boolean) { Boolean jsonBoolean = (Boolean) object; Clog.d(TAG, indent + name + jsonBoolean + " (boolean)"); } else if (object instanceof Integer) { Integer jsonInteger = (Integer) object; Clog.d(TAG, indent + name + jsonInteger + " (int)"); } else if (object instanceof Long) { Long jsonLong = (Long) object; Clog.d(TAG, indent + name + jsonLong + " (long)"); } else if (object instanceof Double) { Double jsonDouble = (Double) object; Clog.d(TAG, indent + name + jsonDouble + " (double)"); } } }