Merge pull request #9651 from osmandapp/Fix_9585
Fix #9585 (Show photos from Wikimedia Commons)
This commit is contained in:
commit
50fdbf741c
4 changed files with 140 additions and 59 deletions
|
@ -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";
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,63 +23,111 @@ 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 = sendWikipediaApiRequest(url, WikidataResponse.class);
|
||||||
String error = NetworkUtils.sendGetRequest(url, null, rawResponse);
|
if (response != null) {
|
||||||
if (error == null) {
|
for (P18 p18 : response.claims.p18) {
|
||||||
try {
|
String imageFileName = p18.mainsnak.datavalue.value;
|
||||||
Gson gson = new Gson();
|
if (imageFileName != null) {
|
||||||
WikipediaResponse response = gson.fromJson(rawResponse.toString(), WikipediaResponse.class);
|
addImageCard(mapActivity, imageCards, imageFileName);
|
||||||
for (WikiImage img : getImageData(response)) {
|
|
||||||
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 = sendWikipediaApiRequest(url, WikimediaResponse.class);
|
||||||
imageName = imageName.substring(0, imageName.lastIndexOf("."));
|
if (response != null) {
|
||||||
String[] urlHashParts = getHash(imageFileName);
|
List<String> subCategories = new ArrayList<>();
|
||||||
|
for (Categorymember cm : response.query.categorymembers) {
|
||||||
String imageHiResUrl = IMAGE_BASE_URL +
|
String memberTitle = cm.title;
|
||||||
urlHashParts[0] + "/" + urlHashParts[1] + "/" +
|
if (memberTitle != null) {
|
||||||
imageFileName;
|
if (memberTitle.startsWith(WIKIMEDIA_CATEGORY)) {
|
||||||
String imageStubUrl = IMAGE_BASE_URL + "thumb/" +
|
subCategories.add(memberTitle);
|
||||||
urlHashParts[0] + "/" + urlHashParts[1] + "/" +
|
} else {
|
||||||
imageFileName + "/" + THUMB_SIZE + "px-" +
|
addWikimediaImageCards(mapActivity, memberTitle, imageCards);
|
||||||
imageFileName;
|
}
|
||||||
images.add(new WikiImage(imageName, imageStubUrl, imageHiResUrl));
|
}
|
||||||
|
}
|
||||||
} catch (UnsupportedEncodingException e) {
|
for (String subCategory : subCategories) {
|
||||||
LOG.error(e.getLocalizedMessage());
|
addWikimediaImageCards(mapActivity, subCategory, imageCards);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
LOG.error("Wrong Wikimedia category member");
|
||||||
}
|
}
|
||||||
return images;
|
}
|
||||||
|
|
||||||
|
private static <T> T sendWikipediaApiRequest(@NonNull String url, @NonNull Class<T> 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 +136,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 +164,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")
|
private static class WikimediaResponse {
|
||||||
|
@SerializedName("query")
|
||||||
@Expose
|
@Expose
|
||||||
private Claims claims;
|
private Query query;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Query {
|
||||||
|
@SerializedName("categorymembers")
|
||||||
|
@Expose
|
||||||
|
private List<Categorymember> categorymembers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Categorymember {
|
||||||
|
@SerializedName("title")
|
||||||
|
@Expose
|
||||||
|
private String title;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue