diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java index cafdc87e9f4..5871cd60da3 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java @@ -4,6 +4,8 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import mage.cards.ExpansionSet; +import mage.cards.Sets; import mage.client.util.CardLanguage; import org.apache.log4j.Logger; import org.mage.plugins.card.dl.DownloadServiceInfo; @@ -14,6 +16,7 @@ import java.io.InputStreamReader; import java.net.Proxy; import java.net.URL; import java.net.URLConnection; +import java.net.URLEncoder; import java.util.*; /** @@ -104,7 +107,7 @@ public enum ScryfallImageSource implements CardImageSource { // double faced card // the front face can be downloaded normally // the back face is prepared beforehand - if(baseUrl == null && card.isTwoFacedCard() && !card.isSecondSide()) { + if (baseUrl == null && card.isTwoFacedCard() && !card.isSecondSide()) { baseUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/" + card.getCollectorIdAsInt() + "/" + localizedCode + "?format=image"; alternativeUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/" @@ -123,11 +126,11 @@ public enum ScryfallImageSource implements CardImageSource { return new CardImageUrls(baseUrl, alternativeUrl); } - private String getFaceImageUrl(CardDownloadData card, boolean isToken, String localizationCode) throws Exception { + 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.getCollectorIdAsInt() % 1000) + "/" + localizationCode); - URLConnection request = cardUrl.openConnection(); + URLConnection request = proxy == null ? cardUrl.openConnection() : cardUrl.openConnection(proxy); request.connect(); // parse the response and return the image URI from the correct card face @@ -135,7 +138,7 @@ public enum ScryfallImageSource implements CardImageSource { JsonElement root = jp.parse(new InputStreamReader((InputStream) request.getContent())); JsonObject jsonCard = root.getAsJsonObject(); if (!jsonCard.has("card_faces")) { - throw new IllegalArgumentException("Couldn't find card_faces in Card JSON."); + throw new Exception("Couldn't find card_faces in Card JSON."); } JsonArray jsonCardFaces = jsonCard.getAsJsonArray("card_faces"); JsonObject jsonCardFace = jsonCardFaces.get(card.isSecondSide() ? 1 : 0).getAsJsonObject(); @@ -150,6 +153,9 @@ public enum ScryfallImageSource implements CardImageSource { Proxy proxy = downloadServiceInfo.getProxy(); preparedUrls.clear(); + + final List sixthEditionCards = Sets.findSet("6ED").getSetCardInfo(); + for (CardDownloadData card : downloadList) { // need cancel if (downloadServiceInfo.isNeedCancel()) { @@ -164,7 +170,39 @@ public enum ScryfallImageSource implements CardImageSource { String url = null; try { - url = getFaceImageUrl(card, card.isToken(), localizedCode); + url = getFaceImageUrl(proxy, card, card.isToken(), localizedCode); + } catch (Exception e) { + logger.warn("Failed to prepare image URL for " + card.getName() + " (" + card.getSet() + ") #" + card.getCollectorId()); + downloadServiceInfo.incErrorCount(); + continue; + } + + preparedUrls.put(card, url); + } + + // if a S00 card is in 6ED, it's actually a 6ED card + if (card.getSet().equals("S00") && sixthEditionCards.stream().anyMatch(sixthEditionCard -> sixthEditionCard.getName().equals(card.getName()))) { + String url = null; + + try { + url = searchCard(proxy, "6ED", card.getName()); + + } catch (Exception e) { + logger.warn("Failed to prepare image URL for " + card.getName() + " (" + card.getSet() + ") #" + card.getCollectorId()); + downloadServiceInfo.incErrorCount(); + continue; + } + + preparedUrls.put(card, url); + } + + // if an E01 card number is above 106, it's actually an AKH card + if (card.getSet().equals("E01") && card.getCollectorIdAsInt() > 106) { + String url = null; + + try { + url = searchCard(proxy, "AKH", card.getName()); + } catch (Exception e) { logger.warn("Failed to prepare image URL for " + card.getName() + " (" + card.getSet() + ") #" + card.getCollectorId()); downloadServiceInfo.incErrorCount(); @@ -181,6 +219,24 @@ public enum ScryfallImageSource implements CardImageSource { return true; } + private String searchCard(Proxy proxy, String set, String name) throws Exception { + final URL searchUrl = new URL("https://api.scryfall.com/cards/search?q=s:" + URLEncoder.encode(set + " " + name, "UTF-8")); + URLConnection request = proxy == null ? searchUrl.openConnection() : searchUrl.openConnection(proxy); + request.connect(); + + // parse the response and return the image URI from the correct card face + JsonParser jp = new JsonParser(); + JsonElement root = jp.parse(new InputStreamReader((InputStream) request.getContent())); + JsonObject searchResult = root.getAsJsonObject(); + if (searchResult.get("total_cards").getAsInt() != 1) { + throw new Exception("Card not found in Scryfall."); + } + JsonObject jsonCard = searchResult.getAsJsonArray("data").get(0).getAsJsonObject(); + JsonObject jsonImageUris = jsonCard.getAsJsonObject("image_uris"); + + return jsonImageUris.get("large").getAsString(); + } + @Override public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception { return innerGenerateURL(card, false); @@ -227,11 +283,6 @@ public enum ScryfallImageSource implements CardImageSource { return true; } - @Override - public void setCurrentLanguage(CardLanguage cardLanguage) { - this.currentLanguage = cardLanguage; - } - @Override public CardLanguage getCurrentLanguage() { return currentLanguage;