* Images: added download support of localized images for double faces cards;

* Images: fixed wrong second side image after localized images download (you must re-download KHM and ZNR sets to fix it);
This commit is contained in:
Oleg Agafonov 2021-02-11 09:15:55 +04:00
parent c9f4e949fa
commit f9b840e3b5
3 changed files with 50 additions and 28 deletions

View file

@ -27,7 +27,6 @@ public class CardImageUrls {
this.baseUrl = baseUrl;
if (alternativeUrl != null
&& alternativeUrl != null
&& !alternativeUrl.isEmpty()
&& !Objects.equals(baseUrl, alternativeUrl)) {
this.alternativeUrls.add(alternativeUrl);

View file

@ -4,11 +4,13 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import mage.MageException;
import mage.client.util.CardLanguage;
import org.apache.log4j.Logger;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.images.CardDownloadData;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Proxy;
@ -87,13 +89,15 @@ public enum ScryfallImageSource implements CardImageSource {
}
// double faced cards (modal double faces cards too)
// the front face can be downloaded normally
// the back face is prepared before hand
if (baseUrl == null && card.isTwoFacedCard() && !card.isSecondSide()) {
baseUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/"
+ card.getCollectorId() + "/" + localizedCode + "?format=image";
alternativeUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/"
+ card.getCollectorId() + "/" + defaultCode + "?format=image";
if (card.isTwoFacedCard()) {
if (card.isSecondSide()) {
// back face - must be prepared before
logger.warn("Can't find back face info in prepared list "
+ card.getName() + " (" + card.getSet() + ") #" + card.getCollectorId());
return new CardImageUrls(null, null);
} else {
// front face - can be downloaded normally as basic card
}
}
// basic cards by api call (redirect to img link)
@ -117,19 +121,46 @@ public enum ScryfallImageSource implements CardImageSource {
return new CardImageUrls(baseUrl, alternativeUrl);
}
private String getFaceImageUrl(Proxy proxy, CardDownloadData card, boolean isToken, String localizationCode) throws Exception {
// connect to Scryfall API
final URL cardUrl = new URL("https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/"
+ card.getCollectorId() + "/" + localizationCode);
URLConnection request = proxy == null ? cardUrl.openConnection() : cardUrl.openConnection(proxy);
request.connect();
private String getFaceImageUrl(Proxy proxy, CardDownloadData card, boolean isToken) throws Exception {
final String defaultCode = CardLanguage.ENGLISH.getCode();
final String localizedCode = languageAliases.getOrDefault(this.getCurrentLanguage(), defaultCode);
// parse the response and return the image URI from the correct card face
// licalized and default
List<String> needUrls = new ArrayList<>();
needUrls.add("https://api.scryfall.com/cards/"
+ formatSetName(card.getSet(), isToken) + "/" + card.getCollectorId() + "/" + localizedCode);
if (!localizedCode.equals(defaultCode)) {
needUrls.add("https://api.scryfall.com/cards/"
+ formatSetName(card.getSet(), isToken) + "/" + card.getCollectorId() + "/" + defaultCode);
}
InputStream jsonStream = null;
String jsonUrl = null;
for (String currentUrl : needUrls) {
// connect to Scryfall API
URL cardUrl = new URL(currentUrl);
URLConnection request = (proxy == null ? cardUrl.openConnection() : cardUrl.openConnection(proxy));
request.connect();
try {
jsonStream = (InputStream) request.getContent();
jsonUrl = currentUrl;
// found good url, can stop
break;
} catch (FileNotFoundException e) {
// localized image doesn't exists, try next url
}
}
if (jsonStream == null) {
throw new MageException("Couldn't find card's JSON data on the server");
}
// OK, found card data, parse it
JsonParser jp = new JsonParser();
JsonElement root = jp.parse(new InputStreamReader((InputStream) request.getContent()));
JsonElement root = jp.parse(new InputStreamReader(jsonStream));
JsonObject jsonCard = root.getAsJsonObject();
if (!jsonCard.has("card_faces")) {
throw new Exception("Couldn't find card_faces in Card JSON.: " + cardUrl.toString());
throw new MageException("Couldn't find card_faces in card's JSON data: " + jsonUrl);
}
JsonArray jsonCardFaces = jsonCard.getAsJsonArray("card_faces");
JsonObject jsonCardFace = jsonCardFaces.get(card.isSecondSide() ? 1 : 0).getAsJsonObject();
@ -164,13 +195,8 @@ public enum ScryfallImageSource implements CardImageSource {
// prepare the back face URL
if (card.isTwoFacedCard() && card.isSecondSide()) {
currentPrepareCount++;
final String defaultCode = CardLanguage.ENGLISH.getCode();
final String localizedCode = languageAliases.getOrDefault(this.getCurrentLanguage(), defaultCode);
String url = null;
try {
url = getFaceImageUrl(proxy, card, card.isToken(), localizedCode);
String url = getFaceImageUrl(proxy, card, card.isToken());
preparedUrls.put(card, url);
} catch (Exception e) {
logger.warn("Failed to prepare image URL (back face) for " + card.getName() + " (" + card.getSet() + ") #"
@ -180,9 +206,6 @@ public enum ScryfallImageSource implements CardImageSource {
updatePrepareStats(downloadServiceInfo, needPrepareCount, currentPrepareCount);
}
// inc error count to stop on too many errors
// downloadServiceInfo.incErrorCount();
}
return true;
@ -262,7 +285,7 @@ public enum ScryfallImageSource implements CardImageSource {
private String formatSetName(String setName, boolean isToken) {
if (isToken) {
// token uses direct link download, not set
// tokens uses xmage codes to find direct link download
return setName.toLowerCase(Locale.ENGLISH);
} else {
return ScryfallImageSupportCards.findScryfallSetCode(setName);

View file

@ -138,7 +138,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
this.errorCount = this.errorCount + 1;
if (this.errorCount == MAX_ERRORS_COUNT_BEFORE_CANCEL + 1) {
logger.warn("Too many errors (> " + MAX_ERRORS_COUNT_BEFORE_CANCEL + ") in images download");
logger.warn("Too many errors (> " + MAX_ERRORS_COUNT_BEFORE_CANCEL + ") in images download. Stop.");
}
}