From dd94169c9a13d4172309ac2cb33adfbdcd8dd51e Mon Sep 17 00:00:00 2001 From: Chris H Date: Tue, 22 Apr 2025 20:33:35 -0400 Subject: [PATCH] Download token images when token collector numbers are defined --- .../src/main/java/forge/card/CardEdition.java | 19 ++--- .../src/main/java/forge/util/ImageUtil.java | 7 ++ .../editions/Duskmourn House of Horror.txt | 30 ++++---- forge-gui/res/editions/Tarkir Dragonstorm.txt | 1 + .../main/java/forge/util/ImageFetcher.java | 69 +++++++++++-------- 5 files changed, 71 insertions(+), 55 deletions(-) diff --git a/forge-core/src/main/java/forge/card/CardEdition.java b/forge-core/src/main/java/forge/card/CardEdition.java index 938a3695704..cb39af313ba 100644 --- a/forge-core/src/main/java/forge/card/CardEdition.java +++ b/forge-core/src/main/java/forge/card/CardEdition.java @@ -309,6 +309,7 @@ public final class CardEdition implements Comparable { private String code; private String code2; private String scryfallCode; + private String tokensCode; private String cardsLanguage; private Type type; private String name; @@ -403,6 +404,7 @@ public final class CardEdition implements Comparable { public String getCode() { return code; } public String getCode2() { return code2; } public String getScryfallCode() { return scryfallCode.toLowerCase(); } + public String getTokensCode() { return tokensCode.toLowerCase(); } public String getCardsLangCode() { return cardsLanguage.toLowerCase(); } public Type getType() { return type; } public String getName() { return name; } @@ -713,19 +715,10 @@ public final class CardEdition implements Comparable { res.name = metadata.get("name"); res.date = parseDate(metadata.get("date")); res.code = metadata.get("code"); - res.code2 = metadata.get("code2"); - if (res.code2 == null) { - res.code2 = res.code; - } - res.scryfallCode = metadata.get("ScryfallCode"); - if (res.scryfallCode == null) { - res.scryfallCode = res.code; - } - res.cardsLanguage = metadata.get("CardLang"); - if (res.cardsLanguage == null) { - res.cardsLanguage = "en"; - } - + res.code2 = metadata.get("code2", res.code); + res.scryfallCode = metadata.get("ScryfallCode", res.code); + res.tokensCode = metadata.get("TokensCode", "T" + res.scryfallCode); + res.cardsLanguage = metadata.get("CardLang", "en"); res.boosterArts = metadata.getInt("BoosterCovers", 1); String boosterDesc = metadata.get("Booster"); diff --git a/forge-core/src/main/java/forge/util/ImageUtil.java b/forge-core/src/main/java/forge/util/ImageUtil.java index 9c4f9d0b5bb..44f29b34c66 100644 --- a/forge-core/src/main/java/forge/util/ImageUtil.java +++ b/forge-core/src/main/java/forge/util/ImageUtil.java @@ -197,6 +197,13 @@ public class ImageUtil { langCode, versionParam, faceParam); } + public static String getScryfallTokenDownloadUrl(String collectorNumber, String setCode, String langCode) { + String versionParam = "normal"; + String faceParam = ""; + return String.format("%s/%s/%s?format=image&version=%s%s", setCode, collectorNumber, + langCode, versionParam, faceParam); + } + public static String toMWSFilename(String in) { in = StringUtils.stripAccents(in); final StringBuilder out = new StringBuilder(); diff --git a/forge-gui/res/editions/Duskmourn House of Horror.txt b/forge-gui/res/editions/Duskmourn House of Horror.txt index b69df6e27ea..c288f9534f0 100644 --- a/forge-gui/res/editions/Duskmourn House of Horror.txt +++ b/forge-gui/res/editions/Duskmourn House of Horror.txt @@ -502,18 +502,18 @@ A143 R A-Leyline of Resonance @Sergey Glushakov 1 Strangled Cemetery|DSK [tokens] -b_2_2_e_horror -b_6_6_demon_flying -bg_1_1_insect_flying -c_a_treasure_sac -c_e_shard_draw -everywhere -g_2_2_spider_reach -primo_the_indivisible -r_1_1_gremlin -u_x_x_spirit_flying -w_1_1_a_toy -w_1_1_e_glimmer -w_2_1_insect_flying -w_3_1_spirit_flying -w_4_4_beast_lonely +2 c_e_shard_draw +3 w_4_4_beast_lonely +4 w_1_1_e_glimmer +5 w_2_1_insect_flying +6 w_3_1_spirit_flying +7 w_1_1_a_toy +8 u_x_x_spirit_flying +9 b_6_6_demon_flying +10 b_2_2_e_horror +11 r_1_1_gremlin +12 g_2_2_spider_reach +13 bg_1_1_insect_flying +14 primo_the_indivisible +15 c_a_treasure_sac +16 everywhere diff --git a/forge-gui/res/editions/Tarkir Dragonstorm.txt b/forge-gui/res/editions/Tarkir Dragonstorm.txt index b5a6ebacdea..77143ca4067 100644 --- a/forge-gui/res/editions/Tarkir Dragonstorm.txt +++ b/forge-gui/res/editions/Tarkir Dragonstorm.txt @@ -4,6 +4,7 @@ Date=2025-04-11 Name=Tarkir: Dragonstorm Type=Expansion ScryfallCode=TDM +TokensCode=TTDM # https://mtgscribe.com/2025/03/20/play-booster-fact-sheet-dragonstorm/ BoosterSlots=Common,Common-Guest,Uncommon,RareMythic,AnyLand,Wildcard,FoilWildcard Booster=6 Common, 1 Common-Guest, 3 Uncommon, 1 RareMythic, 1 AnyLand, 1 Wildcard, 1 FoilWildcard diff --git a/forge-gui/src/main/java/forge/util/ImageFetcher.java b/forge-gui/src/main/java/forge/util/ImageFetcher.java index 4cd1cd04666..9006010217a 100644 --- a/forge-gui/src/main/java/forge/util/ImageFetcher.java +++ b/forge-gui/src/main/java/forge/util/ImageFetcher.java @@ -9,13 +9,9 @@ import forge.item.PaperCard; import forge.localinstance.properties.ForgeConstants; import forge.localinstance.properties.ForgePreferences; import forge.model.FModel; -import org.apache.commons.lang3.tuple.Pair; import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; +import java.util.*; import java.util.concurrent.RejectedExecutionException; public abstract class ImageFetcher { @@ -232,33 +228,52 @@ public abstract class ImageFetcher { this.getScryfallDownloadURL(paperCard, face, useArtCrop, hasSetLookup, filename, downloadUrls); } } else if (prefix.equals(ImageKeys.TOKEN_PREFIX)) { - if (tokenImages == null) { - tokenImages = new HashMap<>(); - for (Pair nameUrlPair : FileUtil - .readNameUrlFile(ForgeConstants.IMAGE_LIST_TOKENS_FILE)) { - tokenImages.put(nameUrlPair.getLeft(), nameUrlPair.getRight()); - } - } final String filename = imageKey.substring(2) + ".jpg"; - String tokenUrl = tokenImages.get(filename); - if (tokenUrl == null) { - String[] tempdata = imageKey.split("[_](?=[^_]*$)"); //We want to check the edition first. - if (tempdata.length == 2) { - CardEdition E = StaticData.instance().getEditions().get(tempdata[1]); - if (E != null && E.getType() == CardEdition.Type.CUSTOM_SET) return; //Custom set token, skip fetching. - } - if (filename.equalsIgnoreCase("null.jpg")) - return; + if (ImageKeys.missingCards.contains(filename)) + return; - if (ImageKeys.missingCards.contains(filename)) - return; + if (filename.equalsIgnoreCase("null.jpg")) + return; - ImageKeys.missingCards.add(filename); - System.err.println("No specified file for '" + filename + "'.. Attempting to download from default Url"); - tokenUrl = String.format("%s%s", ForgeConstants.URL_TOKEN_DOWNLOAD, filename); + String[] tempdata = imageKey.substring(2).split("[_](?=[^_]*$)"); //We want to check the edition first. + if (tempdata.length < 2) { + System.err.println("Token image key is malformed: " + imageKey); + return; } + + String tokenName = tempdata[0]; + String setCode = tempdata[1]; + + // Load the paper token from filename + edition + CardEdition edition = StaticData.instance().getEditions().get(setCode); + if (edition == null || edition.getType() == CardEdition.Type.CUSTOM_SET) return; //Custom set token, skip fetching. + + //PaperToken pt = StaticData.instance().getAllTokens().getToken(tokenName, setCode); + Collection allTokens = edition.getTokens().get(tokenName); + + if (!allTokens.isEmpty()) { + // This loop is going to try to download all the arts until it finds one + // This is a bit wrong since it _should_ just be trying to get the one with the appropriate collector number + // Since we don't have that for tokens, we'll just take the first one + // Ideally we would have some mapping for generating card to determine which art indexed/collector number to try to fetch + // Token art we're downloading and which location we're storing it in. + // Once we're pulling from PaperTokens this section will change a bit + Iterator it = allTokens.iterator(); + CardEdition.TokenInSet tis; + while(it.hasNext()) { + tis = it.next(); + String tokenCode = edition.getTokensCode(); + String langCode = edition.getCardsLangCode(); + if (tis.collectorNumber.isEmpty()) { + continue; + } + + downloadUrls.add(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + ImageUtil.getScryfallTokenDownloadUrl(tis.collectorNumber, tokenCode, langCode)); + } + } + + ImageKeys.missingCards.add(filename); destFile = new File(ForgeConstants.CACHE_TOKEN_PICS_DIR, filename); - downloadUrls.add(tokenUrl); } if (downloadUrls.isEmpty()) {