Fix #9585 (Show photos from Wikimedia Commons)

This commit is contained in:
Nazar-Kutz 2020-08-17 15:01:38 +03:00
parent 6ce4c12842
commit 30f245ce24
4 changed files with 142 additions and 59 deletions

View file

@ -39,6 +39,7 @@ public class Amenity extends MapObject {
public static final String CONTENT = "content"; public static final String CONTENT = "content";
public static final String CUISINE = "cuisine"; public static final String CUISINE = "cuisine";
public static final String WIKIDATA = "wikidata"; public static final String WIKIDATA = "wikidata";
public static final String WIKIMEDIA_COMMONS = "wikimedia_commons";
public static final String DISH = "dish"; public static final String DISH = "dish";
public static final String REF = "ref"; public static final String REF = "ref";
public static final String OSM_DELETE_VALUE = "delete"; public static final String OSM_DELETE_VALUE = "delete";

View file

@ -471,7 +471,9 @@ public class AmenityMenuBuilder extends MenuBuilder {
} }
textPrefix = app.getString(R.string.poi_cuisine); textPrefix = app.getString(R.string.poi_cuisine);
vl = sb.toString(); vl = sb.toString();
} else if (key.contains(Amenity.ROUTE) || key.equals(Amenity.WIKIDATA)) { } else if (key.contains(Amenity.ROUTE)
|| key.equals(Amenity.WIKIDATA)
|| key.equals(Amenity.WIKIMEDIA_COMMONS)) {
continue; continue;
} else { } else {
if (key.contains(Amenity.DESCRIPTION)) { if (key.contains(Amenity.DESCRIPTION)) {
@ -784,7 +786,8 @@ public class AmenityMenuBuilder extends MenuBuilder {
Map<String, String> additionalInfo = amenity.getAdditionalInfo(); Map<String, String> additionalInfo = amenity.getAdditionalInfo();
String imageValue = additionalInfo.get("image"); String imageValue = additionalInfo.get("image");
String mapillaryValue = additionalInfo.get("mapillary"); String mapillaryValue = additionalInfo.get("mapillary");
String wikidataValue = additionalInfo.get("wikidata"); String wikidataValue = additionalInfo.get(Amenity.WIKIDATA);
String wikimediaValue = additionalInfo.get(Amenity.WIKIMEDIA_COMMONS);
if (!Algorithms.isEmpty(imageValue)) { if (!Algorithms.isEmpty(imageValue)) {
params.put("osm_image", imageValue); params.put("osm_image", imageValue);
} }
@ -792,7 +795,10 @@ public class AmenityMenuBuilder extends MenuBuilder {
params.put("osm_mapillary_key", mapillaryValue); params.put("osm_mapillary_key", mapillaryValue);
} }
if (!Algorithms.isEmpty(wikidataValue)) { if (!Algorithms.isEmpty(wikidataValue)) {
params.put("wikidata_id", wikidataValue); params.put(Amenity.WIKIDATA, wikidataValue);
}
if (!Algorithms.isEmpty(wikimediaValue)) {
params.put(Amenity.WIKIMEDIA_COMMONS, wikimediaValue);
} }
return params; return params;
} }

View file

@ -17,6 +17,7 @@ import androidx.appcompat.widget.AppCompatButton;
import net.osmand.AndroidNetworkUtils; import net.osmand.AndroidNetworkUtils;
import net.osmand.AndroidUtils; import net.osmand.AndroidUtils;
import net.osmand.Location; import net.osmand.Location;
import net.osmand.data.Amenity;
import net.osmand.data.LatLon; import net.osmand.data.LatLon;
import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R; import net.osmand.plus.R;
@ -438,10 +439,15 @@ public abstract class ImageCard extends AbstractCard {
pms.put("lang", preferredLang); pms.put("lang", preferredLang);
} }
if (this.params != null) { if (this.params != null) {
String wikidataId = this.params.get("wikidata_id"); String wikidataId = this.params.get(Amenity.WIKIDATA);
if (wikidataId != null) { if (wikidataId != null) {
this.params.remove("wikidata_id"); this.params.remove(Amenity.WIKIDATA);
WikiImageHelper.fillWikiMediaCards(mapActivity, wikidataId, result); WikiImageHelper.addWikidataImageCards(mapActivity, wikidataId, result);
}
String wikimediaContent = this.params.get(Amenity.WIKIMEDIA_COMMONS);
if (wikimediaContent != null) {
this.params.remove(Amenity.WIKIMEDIA_COMMONS);
WikiImageHelper.addWikimediaImageCards(mapActivity, wikimediaContent, result);
} }
pms.putAll(this.params); pms.putAll(this.params);
} }

View file

@ -23,63 +23,113 @@ import java.util.List;
public class WikiImageHelper { public class WikiImageHelper {
private static final String WIKIDATA_API_ENDPOINT = "https://www.wikidata.org/w/api.php"; private static final String WIKIDATA_API_ENDPOINT = "https://www.wikidata.org/w/api.php";
private static final String ACTION = "?action=wbgetclaims&property=P18&entity="; private static final String WIKIMEDIA_API_ENDPOINT = "https://commons.wikimedia.org/w/api.php";
private static final String WIKIDATA_ACTION = "?action=wbgetclaims&property=P18&entity=";
private static final String WIKIMEDIA_ACTION = "?action=query&list=categorymembers&cmtitle=";
private static final String CM_LIMIT = "&cmlimit=500";
private static final String FORMAT_JSON = "&format=json"; private static final String FORMAT_JSON = "&format=json";
private static final String IMAGE_BASE_URL = "https://upload.wikimedia.org/wikipedia/commons/"; private static final String IMAGE_BASE_URL = "https://upload.wikimedia.org/wikipedia/commons/";
private static final String WIKIDATA_PREFIX = "Q"; private static final String WIKIDATA_PREFIX = "Q";
private static final String WIKIMEDIA_FILE = "File:";
private static final String WIKIMEDIA_CATEGORY = "Category:";
private static final int THUMB_SIZE = 500; private static final int THUMB_SIZE = 500;
private static final Log LOG = PlatformUtil.getLog(WikiImageHelper.class); private static final Log LOG = PlatformUtil.getLog(WikiImageHelper.class);
public static void fillWikiMediaCards(@NonNull MapActivity mapActivity, @NonNull String wikidata, public static void addWikidataImageCards(@NonNull MapActivity mapActivity, @NonNull String wikidataId,
List<ImageCard> images) { @NonNull List<ImageCard> imageCards) {
if (wikidata.startsWith(WIKIDATA_PREFIX)) { if (wikidataId.startsWith(WIKIDATA_PREFIX)) {
StringBuilder rawResponse = new StringBuilder(); String url = WIKIDATA_API_ENDPOINT + WIKIDATA_ACTION + wikidataId + FORMAT_JSON;
String url = WIKIDATA_API_ENDPOINT + ACTION + wikidata + FORMAT_JSON; WikidataResponse response =
String error = NetworkUtils.sendGetRequest(url, null, rawResponse); (WikidataResponse) sendWikipediaApiRequest(url, WikidataResponse.class);
if (error == null) { if (response != null) {
try { for (P18 p18 : response.claims.p18) {
Gson gson = new Gson(); String imageFileName = p18.mainsnak.datavalue.value;
WikipediaResponse response = gson.fromJson(rawResponse.toString(), WikipediaResponse.class); if (imageFileName != null) {
for (WikiImage img : getImageData(response)) { addImageCard(mapActivity, imageCards, imageFileName);
images.add(new WikiImageCard(mapActivity, img));
} }
return;
} catch (JsonSyntaxException e) {
error = e.getLocalizedMessage();
} }
} }
LOG.error(error);
} else { } else {
LOG.error("Wrong WikiMedia ID"); LOG.error("Wrong Wikidata ID");
} }
} }
private static List<WikiImage> getImageData(WikipediaResponse response) { public static void addWikimediaImageCards(@NonNull MapActivity mapActivity, @NonNull String wikiMediaTagContent,
List<WikiImage> images = new ArrayList<>(); @NonNull List<ImageCard> imageCards) {
for (P18 p18 : response.claims.p18) { if (wikiMediaTagContent.startsWith(WIKIMEDIA_FILE)) {
String imageFileName = p18.mainsnak.datavalue.value; String fileName = wikiMediaTagContent.substring(WIKIMEDIA_FILE.length());
if (imageFileName != null) { addImageCard(mapActivity, imageCards, fileName);
try { } else if (wikiMediaTagContent.startsWith(WIKIMEDIA_CATEGORY)) {
String imageName = URLDecoder.decode(imageFileName, "UTF-8"); String url = WIKIMEDIA_API_ENDPOINT + WIKIMEDIA_ACTION + wikiMediaTagContent + CM_LIMIT + FORMAT_JSON;
imageFileName = imageName.replace(" ", "_"); WikimediaResponse response =
imageName = imageName.substring(0, imageName.lastIndexOf(".")); (WikimediaResponse) sendWikipediaApiRequest(url, WikimediaResponse.class);
String[] urlHashParts = getHash(imageFileName); if (response != null) {
List<String> subCategories = new ArrayList<>();
String imageHiResUrl = IMAGE_BASE_URL + for (Categorymember cm : response.query.categorymembers) {
urlHashParts[0] + "/" + urlHashParts[1] + "/" + String memberTitle = cm.title;
imageFileName; if (memberTitle != null) {
String imageStubUrl = IMAGE_BASE_URL + "thumb/" + if (memberTitle.startsWith(WIKIMEDIA_CATEGORY)) {
urlHashParts[0] + "/" + urlHashParts[1] + "/" + subCategories.add(memberTitle);
imageFileName + "/" + THUMB_SIZE + "px-" + } else {
imageFileName; addWikimediaImageCards(mapActivity, memberTitle, imageCards);
images.add(new WikiImage(imageName, imageStubUrl, imageHiResUrl)); }
}
} catch (UnsupportedEncodingException e) { }
LOG.error(e.getLocalizedMessage()); for (String subCategory : subCategories) {
addWikimediaImageCards(mapActivity, subCategory, imageCards);
} }
} }
} else {
LOG.error("Wrong Wikimedia category member");
} }
return images; }
private static Object sendWikipediaApiRequest(@NonNull String url, @NonNull Class responseClass) {
StringBuilder rawResponse = new StringBuilder();
String errorMessage = NetworkUtils.sendGetRequest(url, null, rawResponse);
if (errorMessage == null) {
try {
return new Gson().fromJson(rawResponse.toString(), responseClass);
} catch (JsonSyntaxException e) {
errorMessage = e.getLocalizedMessage();
}
}
LOG.error(errorMessage);
return null;
}
private static void addImageCard(@NonNull MapActivity mapActivity, @NonNull List<ImageCard> images,
@NonNull String fileName) {
WikiImage img = getImageData(fileName);
if (img != null) {
images.add(new WikiImageCard(mapActivity, img));
}
}
private static WikiImage getImageData(@NonNull String imageFileName) {
try {
String imageName = URLDecoder.decode(imageFileName, "UTF-8");
imageFileName = imageName.replace(" ", "_");
imageName = imageName.substring(0, imageName.lastIndexOf("."));
String[] urlHashParts = getHash(imageFileName);
String imageHiResUrl = IMAGE_BASE_URL +
urlHashParts[0] + "/" + urlHashParts[1] + "/" +
imageFileName;
String imageStubUrl = IMAGE_BASE_URL + "thumb/" +
urlHashParts[0] + "/" + urlHashParts[1] + "/" +
imageFileName + "/" + THUMB_SIZE + "px-" +
imageFileName;
return new WikiImage(imageName, imageStubUrl, imageHiResUrl);
} catch (UnsupportedEncodingException e) {
LOG.error(e.getLocalizedMessage());
}
return null;
} }
@NonNull @NonNull
@ -88,19 +138,23 @@ public class WikiImageHelper {
return new String[]{md5.substring(0, 1), md5.substring(0, 2)}; return new String[]{md5.substring(0, 1), md5.substring(0, 2)};
} }
// Wikidata response classes
private static class WikidataResponse {
@SerializedName("claims")
@Expose
private Claims claims;
}
private static class Claims { private static class Claims {
@SerializedName("P18") @SerializedName("P18")
@Expose @Expose
private List<P18> p18 = null; private List<P18> p18 = null;
} }
private static class Datavalue { private static class P18 {
@SerializedName("value") @SerializedName("mainsnak")
@Expose @Expose
private String value; private Mainsnak mainsnak;
@SerializedName("type")
@Expose
private String type;
} }
private static class Mainsnak { private static class Mainsnak {
@ -112,15 +166,31 @@ public class WikiImageHelper {
private String datatype; private String datatype;
} }
private static class P18 { private static class Datavalue {
@SerializedName("mainsnak") @SerializedName("value")
@Expose @Expose
private Mainsnak mainsnak; private String value;
@SerializedName("type")
@Expose
private String type;
} }
private static class WikipediaResponse { // Wikimedia response classes
@SerializedName("claims") public class WikimediaResponse {
@SerializedName("query")
@Expose @Expose
private Claims claims; private Query query;
}
public class Query {
@SerializedName("categorymembers")
@Expose
private List<Categorymember> categorymembers;
}
public class Categorymember {
@SerializedName("title")
@Expose
private String title;
} }
} }