Scryfall small images download (#12282)

- Add new option for downloading small images from scryfall

- Refactor/simplify CardImageUrls

---------

Co-authored-by: xenohedron <xenohedron@users.noreply.github.com>
This commit is contained in:
tiera3 2024-06-01 15:09:02 +10:00 committed by GitHub
parent af59ff2c5c
commit f253777f7c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 122 additions and 75 deletions

View file

@ -1,80 +1,45 @@
package org.mage.plugins.card.dl.sources;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
/**
* @author JayDi85
*/
public class CardImageUrls {
public String baseUrl;
public List<String> alternativeUrls;
public CardImageUrls() {
this.baseUrl = null;
this.alternativeUrls = new ArrayList<>();
}
private final List<String> urls = new ArrayList<>();
public CardImageUrls(String baseUrl) {
this(baseUrl, null);
addUrl(baseUrl);
}
public CardImageUrls(String baseUrl, String alternativeUrl) {
this();
this.baseUrl = baseUrl;
if (alternativeUrl != null
&& !alternativeUrl.isEmpty()
&& !Objects.equals(baseUrl, alternativeUrl)) {
this.alternativeUrls.add(alternativeUrl);
public CardImageUrls(String... urls) {
for (String url : urls) {
addUrl(url);
}
}
public CardImageUrls(String baseUrl, String alternativeUrl , String nextaltUrl) {
this();
this.baseUrl = baseUrl;
if (alternativeUrl != null
&& !alternativeUrl.isEmpty()
&& !Objects.equals(baseUrl, alternativeUrl)) {
this.alternativeUrls.add(alternativeUrl);
}
if (nextaltUrl != null
&& !nextaltUrl.isEmpty()
&& !Objects.equals(baseUrl, nextaltUrl)) {
this.alternativeUrls.add(nextaltUrl);
public CardImageUrls(Collection<String> urls) {
for (String url : urls) {
addUrl(url);
}
}
public List<String> getDownloadList() {
List<String> downloadUrls = new ArrayList<>();
if (this.baseUrl != null && !this.baseUrl.isEmpty()) {
downloadUrls.add(this.baseUrl);
}
// no needs in base url duplicate
if (this.alternativeUrls != null) {
for (String url : this.alternativeUrls) {
if (!url.equals(this.baseUrl)) {
downloadUrls.add(url);
}
}
}
return downloadUrls;
return urls;
}
public void addAlternativeUrl(String url) {
if (url != null && !url.isEmpty()) {
this.alternativeUrls.add(url);
} else {
throw new IllegalArgumentException();
// for tests
public String getBaseUrl() {
return urls.stream().findFirst().orElse(null);
}
public void addUrl(String url) {
// ignore nulls and duplicates
if (url != null && !url.isEmpty() && !urls.contains(url)) {
this.urls.add(url);
}
}
}

View file

@ -21,16 +21,20 @@ import java.util.*;
/**
* @author JayDi85
*/
public enum ScryfallImageSource implements CardImageSource {
public class ScryfallImageSource implements CardImageSource {
instance;
private static final ScryfallImageSource instance = new ScryfallImageSource();
private static final Logger logger = Logger.getLogger(ScryfallImageSource.class);
private final Map<CardLanguage, String> languageAliases;
private CardLanguage currentLanguage = CardLanguage.ENGLISH; // working language
private final Map<CardDownloadData, String> preparedUrls = new HashMap<>();
private final int DOWNLOAD_TIMEOUT_MS = 100;
private static final int DOWNLOAD_TIMEOUT_MS = 100;
public static ScryfallImageSource getInstance() {
return instance;
}
ScryfallImageSource() {
// LANGUAGES
@ -52,7 +56,7 @@ public enum ScryfallImageSource implements CardImageSource {
private CardImageUrls innerGenerateURL(CardDownloadData card, boolean isToken) {
String prepared = preparedUrls.getOrDefault(card, null);
if (prepared != null) {
return new CardImageUrls(prepared, null);
return new CardImageUrls(prepared);
}
String defaultCode = CardLanguage.ENGLISH.getCode();
@ -144,11 +148,11 @@ public enum ScryfallImageSource implements CardImageSource {
String apiUrl = ScryfallImageSupportCards.findDirectDownloadLink(card.getSet(), card.getName(), card.getCollectorId());
if (apiUrl != null) {
if (apiUrl.endsWith("*/")) {
apiUrl = apiUrl.substring(0 , apiUrl.length() -2) + "★/" ;
apiUrl = apiUrl.substring(0 , apiUrl.length() - 2) + "★/" ;
} else if (apiUrl.endsWith("+/")) {
apiUrl = apiUrl.substring(0 , apiUrl.length() -2) + "†/" ;
apiUrl = apiUrl.substring(0 , apiUrl.length() - 2) + "†/" ;
} else if (apiUrl.endsWith("Ph/")) {
apiUrl = apiUrl.substring(0 , apiUrl.length() -3) + "Φ/" ;
apiUrl = apiUrl.substring(0 , apiUrl.length() - 3) + "Φ/" ;
}
// BY DIRECT URL
// direct links via hardcoded API path. Used for cards with non-ASCII collector numbers

View file

@ -0,0 +1,45 @@
package org.mage.plugins.card.dl.sources;
import org.mage.plugins.card.images.CardDownloadData;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author tiera3
*/
public class ScryfallImageSourceSmall extends ScryfallImageSource {
private static final ScryfallImageSourceSmall instanceSmall = new ScryfallImageSourceSmall();
public static ScryfallImageSource getInstance() {
return instanceSmall;
}
private static String innerModifyUrlString(String oneUrl) {
return oneUrl.replaceFirst("/large/","/small/").replaceFirst("format=image","format=image&version=small");
}
private static CardImageUrls innerModifyUrl(CardImageUrls cardUrls) {
List<String> downloadUrls = cardUrls.getDownloadList().stream()
.map(ScryfallImageSourceSmall::innerModifyUrlString)
.collect(Collectors.toList());
return new CardImageUrls(downloadUrls);
}
@Override
public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception {
return innerModifyUrl(super.generateCardUrl(card));
}
@Override
public CardImageUrls generateTokenUrl(CardDownloadData card) throws Exception {
return innerModifyUrl(super.generateTokenUrl(card));
}
@Override
public float getAverageSize() {
return 13; // initial estimate - TODO calculate a more accurate number
}
}

View file

@ -76,7 +76,8 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
enum DownloadSources {
WIZARDS("1. wizards.com - low quality CARDS, multi-language, slow download", WizardCardsImageSource.instance),
TOKENS("2. tokens.mtg.onl - high quality TOKENS", TokensMtgImageSource.instance),
SCRYFALL("3. scryfall.com - high quality CARDS and TOKENS, multi-language", ScryfallImageSource.instance),
SCRYFALL("3. scryfall.com - high quality CARDS and TOKENS, multi-language", ScryfallImageSource.getInstance()),
SCRYFALL_SMALL("3a. scryfall.com small images - low quality CARDS and TOKENS, multi-language", ScryfallImageSourceSmall.getInstance()),
MAGIDEX("4. magidex.com - high quality CARDS", MagidexImageSource.instance),
GRAB_BAG("5. GrabBag - STAR WARS cards and tokens", GrabbagImageSource.instance),
MYTHICSPOILER("6. mythicspoiler.com", MythicspoilerComSource.instance),
@ -164,7 +165,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
// SOURCES - scryfall is default source
uiDialog.getSourcesCombo().setModel(new DefaultComboBoxModel(DownloadSources.values()));
uiDialog.getSourcesCombo().setSelectedItem(DownloadSources.SCRYFALL);
selectedSource = ScryfallImageSource.instance;
selectedSource = ScryfallImageSource.getInstance();
uiDialog.getSourcesCombo().addItemListener((ItemEvent event) -> {
if (event.getStateChange() == ItemEvent.SELECTED) {
comboboxSourceSelected(event);
@ -729,7 +730,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
DownloadTask(CardDownloadData card, String baseUrl, String actualFilename, int count) {
this.card = card;
this.urls = new CardImageUrls(baseUrl, null);
this.urls = new CardImageUrls(baseUrl);
this.count = count;
this.actualFilename = actualFilename;
this.useSpecifiedPaths = true;