Images: added direct image links support in scryfall, added SLD's alternative images from second sides (example: Zndrsplt, Eye of Wisdom);

This commit is contained in:
Oleg Agafonov 2021-11-28 01:17:54 +04:00
parent 903a9215cc
commit a6b2bea8af
8 changed files with 105 additions and 45 deletions

View file

@ -74,16 +74,22 @@ public enum ScryfallImageSource implements CardImageSource {
// CARDS TRY
// direct links to images via hardcoded API path. Used for cards with non-ASCII collector numbers
// direct links to images via hardcoded API path
// used for cards with non-ASCII collector numbers or another use cases
if (baseUrl == null) {
String apiUrl = ScryfallImageSupportCards.findDirectDownloadLink(card.getSet(), card.getName(), card.getCollectorId());
if (apiUrl != null) {
baseUrl = apiUrl + localizedCode + "?format=image";
alternativeUrl = apiUrl + defaultCode + "?format=image";
// workaround to use cards without english images (some promos or special cards)
if (Objects.equals(baseUrl, alternativeUrl) && baseUrl.endsWith("/en?format=image")) {
alternativeUrl = alternativeUrl.replace("/en?format=image", "/?format=image");
String link = ScryfallImageSupportCards.findDirectDownloadLink(card.getSet(), card.getName(), card.getCollectorId());
if (link != null) {
if (ScryfallImageSupportCards.isApiLink(link)) {
// api
baseUrl = link + localizedCode + "?format=image";
alternativeUrl = link + defaultCode + "?format=image";
// workaround to use cards without english images (some promos or special cards)
if (Objects.equals(baseUrl, alternativeUrl) && baseUrl.endsWith("/en?format=image")) {
alternativeUrl = alternativeUrl.replace("/en?format=image", "/?format=image");
}
} else {
// image
baseUrl = link;
}
}
}
@ -103,18 +109,22 @@ public enum ScryfallImageSource implements CardImageSource {
// basic cards by api call (redirect to img link)
// example: https://api.scryfall.com/cards/xln/121/en?format=image
if (baseUrl == null) {
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";
baseUrl = String.format("https://api.scryfall.com/cards/%s/%s/%s?format=image",
formatSetName(card.getSet(), isToken),
card.getCollectorId(),
localizedCode);
alternativeUrl = String.format("https://api.scryfall.com/cards/%s/%s/%s?format=image",
formatSetName(card.getSet(), isToken),
card.getCollectorId(),
defaultCode);
// workaround to use cards without english images (some promos or special cards)
// bug: https://github.com/magefree/mage/issues/6829
// example: Mysterious Egg from IKO https://api.scryfall.com/cards/iko/385/?format=image
if (Objects.equals(baseUrl, alternativeUrl)) {
// without loc code scryfall must return first available image
alternativeUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/"
+ card.getCollectorId() + "/?format=image";
alternativeUrl = String.format("https://api.scryfall.com/cards/%s/%s/?format=image",
formatSetName(card.getSet(), isToken),
card.getCollectorId());
}
}
@ -126,6 +136,7 @@ public enum ScryfallImageSource implements CardImageSource {
final String localizedCode = languageAliases.getOrDefault(this.getCurrentLanguage(), defaultCode);
List<String> needUrls = new ArrayList<>();
int needFaceIndex = card.isSecondSide() ? 1 : 0;
String apiUrl = ScryfallImageSupportCards.findDirectDownloadLink(card.getSet(), card.getName(), card.getCollectorId());
if (apiUrl != null) {
@ -143,11 +154,15 @@ public enum ScryfallImageSource implements CardImageSource {
} else {
// BY CARD NUMBER
// localized and default
needUrls.add("https://api.scryfall.com/cards/"
+ formatSetName(card.getSet(), isToken) + "/" + card.getCollectorId() + "/" + localizedCode);
needUrls.add(String.format("https://api.scryfall.com/cards/%s/%s/%s",
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);
needUrls.add(String.format("https://api.scryfall.com/cards/%s/%s/%s",
formatSetName(card.getSet(), isToken),
card.getCollectorId(),
defaultCode));
}
}
@ -178,8 +193,11 @@ public enum ScryfallImageSource implements CardImageSource {
if (jsonFaces == null) {
throw new MageException("Couldn't find card_faces in card's JSON data: " + jsonUrl);
}
if (jsonFaces.size() < needFaceIndex + 1) {
throw new MageException("card_faces doesn't contains face index in card's JSON data: " + jsonUrl);
}
JsonObject jsonFace = jsonFaces.get(card.isSecondSide() ? 1 : 0).getAsJsonObject();
JsonObject jsonFace = jsonFaces.get(needFaceIndex).getAsJsonObject();
JsonObject jsonImages = JsonUtil.getAsObject(jsonFace, "image_uris");
if (jsonImages == null) {
throw new MageException("Couldn't find image_uris in card's JSON data: " + jsonUrl);

View file

@ -508,21 +508,23 @@ public class ScryfallImageSupportCards {
private static final Map<String, String> directDownloadLinks = new HashMap<String, String>() {
{
// xmage card -> api link:
// examples:
// api example: https://api.scryfall.com/cards/trix/6/
// api format is primary
// xmage card -> api or image link
// WARNING, try use api links as much as possible (it supports build-in translation)
//
// code form for one card:
// example:
// api link: https://api.scryfall.com/cards/trix/6/
// image link: https://c1.scryfall.com/file/scryfall-cards/large/back/d/5/d5dfd236-b1da-4552-b94f-ebf6bb9dafdf.jpg
//
// key for one card:
// set/card_name
//
// code form for same name cards (alternative images):
// set/card_name/card_number
// set/card_name/card_number
// key for same name cards (alternative images):
// set/card_name/card_number_1
// set/card_name/card_number_2
//
// Cards with non-ASCII collector numbers must use direct download (cause xmage uses different card number)
// Verify checks must check and show missing data from that list
// WARNING, must use as API link, not image
// 10E
put("10E/Air Elemental/64*", "https://api.scryfall.com/cards/10e/64★/");
put("10E/Anaba Bodyguard/187*", "https://api.scryfall.com/cards/10e/187★/");
@ -786,10 +788,6 @@ public class ScryfallImageSupportCards {
put("PM14/Hive Stirrings/21*", "https://api.scryfall.com/cards/pm14/21★/");
put("PM14/Megantic Sliver/185*", "https://api.scryfall.com/cards/pm14/185★/");
put("PM14/Ratchet Bomb/215*", "https://api.scryfall.com/cards/pm14/215★/");
// PROE
put("PROE/Emrakul, the Aeons Torn/4*", "https://api.scryfall.com/cards/proe/4★/");
put("PROE/Lord of Shatterskull Pass/156*", "https://api.scryfall.com/cards/proe/156★/");
//
// PMBS
put("PMBS/Glissa, the Traitor/96*", "https://api.scryfall.com/cards/pmbs/96★/");
put("PMBS/Hero of Bladehold/8*", "https://api.scryfall.com/cards/pmbs/8★/");
@ -948,6 +946,18 @@ public class ScryfallImageSupportCards {
put("WAR/Ugin, the Ineffable/2*", "https://api.scryfall.com/cards/war/2★/");
put("WAR/Vivien, Champion of the Wilds/180*", "https://api.scryfall.com/cards/war/180★/");
put("WAR/Vraska, Swarm's Eminence/236*", "https://api.scryfall.com/cards/war/236★/");
// SLD
// TODO: update direct image links in 2022 for HQ images
put("SLD/Zndrsplt, Eye of Wisdom/379", "https://api.scryfall.com/cards/sld/379/");
put("SLD/Zndrsplt, Eye of Wisdom/379b", "https://c1.scryfall.com/file/scryfall-cards/large/back/d/5/d5dfd236-b1da-4552-b94f-ebf6bb9dafdf.jpg");
put("SLD/Krark's Thumb/383", "https://api.scryfall.com/cards/sld/383/");
put("SLD/Krark's Thumb/383b", "https://c1.scryfall.com/file/scryfall-cards/large/back/9/f/9f63277b-e139-46c8-b9e3-0cfb647f44cc.jpg");
put("SLD/Okaun, Eye of Chaos/380", "https://api.scryfall.com/cards/sld/380/");
put("SLD/Okaun, Eye of Chaos/380b", "https://c1.scryfall.com/file/scryfall-cards/large/back/9/4/94eea6e3-20bc-4dab-90ba-3113c120fb90.jpg");
put("SLD/Propaganda/381", "https://api.scryfall.com/cards/sld/381/");
put("SLD/Propaganda/381b", "https://c1.scryfall.com/file/scryfall-cards/large/back/3/e/3e3f0bcd-0796-494d-bf51-94b33c1671e9.jpg");
put("SLD/Stitch in Time/382", "https://api.scryfall.com/cards/sld/382/");
put("SLD/Stitch in Time/382b", "https://c1.scryfall.com/file/scryfall-cards/large/back/0/8/087c3a0d-c710-4451-989e-596b55352184.jpg");
}
};
@ -1001,6 +1011,10 @@ public class ScryfallImageSupportCards {
return "";
}
public static boolean isApiLink(String link) {
return !link.endsWith(".jpg") && !link.endsWith(".png");
}
public static Map<String, String> getDirectDownloadLinks() {
return directDownloadLinks;
}

View file

@ -436,6 +436,8 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
String cardName = card.getName();
boolean isType2 = type2SetsFilter.contains(card.getSetCode());
CardDownloadData url = new CardDownloadData(cardName, card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), 0, "", "", false, card.isDoubleFaced(), card.isNightCard());
// variations must have diff file names with additional postfix
if (url.getUsesVariousArt()) {
url.setDownloadName(createDownloadName(card));
}
@ -444,7 +446,10 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
url.setSplitCard(card.isSplitCard());
url.setType2(isType2);
// main side
allCardsUrls.add(url);
// second side (xmage's set doesn't have info about it, so generate it here)
if (card.isDoubleFaced()) {
if (card.getSecondSideName() == null || card.getSecondSideName().trim().isEmpty()) {
throw new IllegalStateException("Second side card can't have empty name.");