* Images: added localized card images download from scryfall source;

This commit is contained in:
Oleg Agafonov 2018-06-23 16:27:34 +04:00
parent 39075e000f
commit 6c20ee4a74
14 changed files with 230 additions and 93 deletions

View file

@ -8,7 +8,6 @@ import java.io.IOException;
import java.util.HashMap;
/**
*
* @author spjspj
*/
public enum AltMtgOnlTokensImageSource implements CardImageSource {
@ -60,7 +59,7 @@ public enum AltMtgOnlTokensImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
return null;
}
@ -122,7 +121,7 @@ public enum AltMtgOnlTokensImageSource implements CardImageSource {
}
@Override
public String generateTokenUrl(CardDownloadData card) throws IOException {
public CardImageUrls generateTokenUrl(CardDownloadData card) throws IOException {
if (copyUrlToImage == null) {
setupLinks();
}

View file

@ -9,9 +9,9 @@ import org.mage.plugins.card.images.CardDownloadData;
*/
public interface CardImageSource {
String generateURL(CardDownloadData card) throws Exception;
CardImageUrls generateURL(CardDownloadData card) throws Exception;
String generateTokenUrl(CardDownloadData card) throws Exception;
CardImageUrls generateTokenUrl(CardDownloadData card) throws Exception;
String getNextHttpImageUrl();

View file

@ -0,0 +1,59 @@
package org.mage.plugins.card.dl.sources;
import java.util.ArrayList;
import java.util.List;
/**
* @author JayDi85
*/
public class CardImageUrls {
public String baseUrl;
public List<String> alternativeUrls;
public CardImageUrls() {
this.baseUrl = null;
this.alternativeUrls = new ArrayList<>();
}
public CardImageUrls(String baseUrl) {
this(baseUrl, null);
}
public CardImageUrls(String baseUrl, String alternativeUrl) {
this();
this.baseUrl = baseUrl;
if (alternativeUrl != null && !alternativeUrl.isEmpty()) {
this.alternativeUrls.add(alternativeUrl);
}
}
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;
}
public void addAlternativeUrl(String url) {
if (url != null && !url.isEmpty()) {
this.alternativeUrls.add(url);
} else {
throw new IllegalArgumentException();
}
}
}

View file

@ -8,11 +8,11 @@ import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.apache.log4j.Logger;
import org.mage.plugins.card.images.CardDownloadData;
/**
*
* @author spjspj
*/
public enum GrabbagImageSource implements CardImageSource {
@ -48,7 +48,7 @@ public enum GrabbagImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
if (singleLinks == null) {
setupLinks();
}
@ -63,7 +63,7 @@ public enum GrabbagImageSource implements CardImageSource {
}
if (url != null) {
return getSourceName(card, url) + url;
return new CardImageUrls(getSourceName(card, url) + url);
}
return null;
}
@ -375,7 +375,7 @@ public enum GrabbagImageSource implements CardImageSource {
}
@Override
public String generateTokenUrl(CardDownloadData card) throws IOException {
public CardImageUrls generateTokenUrl(CardDownloadData card) throws IOException {
try {
return generateURL(card);
} catch (Exception ex) {

View file

@ -6,12 +6,12 @@ import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import mage.client.dialog.PreferencesDialog;
import org.mage.plugins.card.images.CardDownloadData;
import org.mage.plugins.card.utils.CardImageUtils;
/**
*
* @author North
*/
public enum MagicCardsImageSource implements CardImageSource {
@ -342,6 +342,7 @@ public enum MagicCardsImageSource implements CardImageSource {
put("WWK", "worldwake");
put("ZEN", "zendikar");
}
private static final long serialVersionUID = 1L;
};
@ -361,7 +362,7 @@ public enum MagicCardsImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
String collectorId = card.getCollectorId();
String cardSet = card.getSet();
if (collectorId == null || cardSet == null) {
@ -389,11 +390,11 @@ public enum MagicCardsImageSource implements CardImageSource {
}
url.append(".jpg");
return url.toString();
return new CardImageUrls(url.toString());
}
@Override
public String generateTokenUrl(CardDownloadData card) {
public CardImageUrls generateTokenUrl(CardDownloadData card) {
String name = card.getName();
// add type to name if it's not 0
if (card.getType() > 0) {
@ -406,7 +407,7 @@ public enum MagicCardsImageSource implements CardImageSource {
} else {
set += '-' + card.getSet();
}
return "http://magiccards.info/extras/token/" + set + '/' + name + ".jpg";
return new CardImageUrls("http://magiccards.info/extras/token/" + set + '/' + name + ".jpg");
}
@Override

View file

@ -8,10 +8,10 @@ import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.mage.plugins.card.images.CardDownloadData;
/**
*
* @author Pete Rossi
*/
public enum MagidexImageSource implements CardImageSource {
@ -233,7 +233,7 @@ public enum MagidexImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
String cardDownloadName = card.getDownloadName().toLowerCase(Locale.ENGLISH);
String cardSet = card.getSet();
@ -247,7 +247,7 @@ public enum MagidexImageSource implements CardImageSource {
// This will properly escape the url
URI uri = new URI("http", "magidex.com", "/extstatic/card/" + formatSetName(cardSet) + '/' + cardDownloadName + ".jpg", null, null);
return uri.toASCIIString();
return new CardImageUrls(uri.toASCIIString());
}
private String formatSetName(String setName) {
@ -264,7 +264,7 @@ public enum MagidexImageSource implements CardImageSource {
};
@Override
public String generateTokenUrl(CardDownloadData card) {
public CardImageUrls generateTokenUrl(CardDownloadData card) {
return null;
}

View file

@ -2,14 +2,12 @@
package org.mage.plugins.card.dl.sources;
import java.util.Locale;
import org.mage.plugins.card.images.CardDownloadData;
/**
* Site was shutdown by wizards Feb. 2015
*
*
*
*
* @author LevelX2
*/
public enum MtgImageSource implements CardImageSource {
@ -32,7 +30,7 @@ public enum MtgImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
String collectorId = card.getCollectorId();
String cardSet = card.getSet();
if (collectorId == null || cardSet == null) {
@ -59,11 +57,11 @@ public enum MtgImageSource implements CardImageSource {
}
url.append(".jpg");
return url.toString();
return new CardImageUrls(url.toString());
}
@Override
public String generateTokenUrl(CardDownloadData card) {
public CardImageUrls generateTokenUrl(CardDownloadData card) {
return null;
}

View file

@ -3,11 +3,11 @@ package org.mage.plugins.card.dl.sources;
import java.io.IOException;
import java.util.HashMap;
import org.apache.log4j.Logger;
import org.mage.plugins.card.images.CardDownloadData;
/**
*
* @author spjspj
*/
public enum MtgOnlTokensImageSource implements CardImageSource {
@ -59,7 +59,7 @@ public enum MtgOnlTokensImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
return null;
}
@ -324,7 +324,7 @@ public enum MtgOnlTokensImageSource implements CardImageSource {
}
@Override
public String generateTokenUrl(CardDownloadData card) throws IOException {
public CardImageUrls generateTokenUrl(CardDownloadData card) throws IOException {
if (copyUrlToImage == null) {
setupLinks();
}

View file

@ -18,6 +18,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.prefs.Preferences;
import mage.client.MageFrame;
import mage.remote.Connection;
import mage.remote.Connection.ProxyType;
@ -28,7 +29,6 @@ import org.jsoup.select.Elements;
import org.mage.plugins.card.images.CardDownloadData;
/**
*
* @author LevelX2
*/
public enum MythicspoilerComSource implements CardImageSource {
@ -391,7 +391,7 @@ public enum MythicspoilerComSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
String collectorId = card.getCollectorId();
String cardSet = card.getSet();
if (collectorId == null || cardSet == null) {
@ -410,11 +410,11 @@ public enum MythicspoilerComSource implements CardImageSource {
.replaceAll(",", "")
.replaceAll("/", "");
String link = setLinks.get(searchName);
return link;
return new CardImageUrls(link);
}
@Override
public String generateTokenUrl(CardDownloadData card
public CardImageUrls generateTokenUrl(CardDownloadData card
) {
return null;
}

View file

@ -6,19 +6,34 @@ import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import mage.client.dialog.PreferencesDialog;
import org.mage.plugins.card.images.CardDownloadData;
/**
* @author Quercitron, JayDi85
*
*/
public enum ScryfallImageSource implements CardImageSource {
instance;
private final Set<String> supportedSets;
private final Map<String, String> languageAliases;
ScryfallImageSource() {
// https://scryfall.com/docs/api/languages
languageAliases = new HashMap<>();
languageAliases.put("en", "en");
languageAliases.put("es", "es");
languageAliases.put("jp", "ja");
languageAliases.put("it", "it");
languageAliases.put("fr", "fr");
languageAliases.put("cn", "zhs"); // Simplified Chinese
languageAliases.put("de", "de");
languageAliases.put("ko", "ko");
languageAliases.put("pt", "pt");
languageAliases.put("ru", "ru");
supportedSets = new LinkedHashSet<>();
// supportedSets.add("PTC"); //
supportedSets.add("LEA");
@ -214,33 +229,52 @@ public enum ScryfallImageSource implements CardImageSource {
supportedSets.add("BBD");
// supportedSets.add("CM2");
supportedSets.add("M19");
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
String preferredLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en");
String defaultCode = "en";
String localizedCode = languageAliases.getOrDefault(preferredLanguage, defaultCode);
// loc example: https://api.scryfall.com/cards/xln/121/ru?format=image
// TODO: do not use API at all? It's can help with scryfall request limits (1 request instead 2)
String baseUrl = null;
String alternativeUrl = null;
// special card number like "103a" already compatible
if (card.isCollectorIdWithStr()) {
return "https://img.scryfall.com/cards/large/en/" + formatSetName(card.getSet()) + "/"
if (baseUrl == null && card.isCollectorIdWithStr()) {
baseUrl = "https://img.scryfall.com/cards/large/" + localizedCode + "/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + ".jpg";
alternativeUrl = "https://img.scryfall.com/cards/large/" + defaultCode + "/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + ".jpg";
}
// double faced cards do not supporte by API (need direct link for img)
// double faced cards do not supports by API (need direct link for img)
// example: https://img.scryfall.com/cards/large/en/xln/173b.jpg
if (card.isTwoFacedCard()) {
return "https://img.scryfall.com/cards/large/en/" + formatSetName(card.getSet()) + "/"
if (baseUrl == null && card.isTwoFacedCard()) {
baseUrl = "https://img.scryfall.com/cards/large/" + localizedCode + "/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + (card.isSecondSide() ? "b" : "a") + ".jpg";
alternativeUrl = "https://img.scryfall.com/cards/large/" + defaultCode + "/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + (card.isSecondSide() ? "b" : "a") + ".jpg";
}
// basic cards by api call (redirect to img link)
// example: https://api.scryfall.com/cards/xln/121?format=image
return "https://api.scryfall.com/cards/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + "?format=image";
// example: https://api.scryfall.com/cards/xln/121/en?format=image
if (baseUrl == null) {
baseUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + "/" + localizedCode + "?format=image";
alternativeUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + "/" + defaultCode + "?format=image";
}
return new CardImageUrls(baseUrl, alternativeUrl);
}
@Override
public String generateTokenUrl(CardDownloadData card) throws Exception {
public CardImageUrls generateTokenUrl(CardDownloadData card) throws Exception {
return null;
}

View file

@ -16,6 +16,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import mage.constants.SubType;
import org.apache.log4j.Logger;
import org.mage.plugins.card.images.CardDownloadData;
@ -23,7 +24,6 @@ import org.mage.plugins.card.images.DownloadPictures;
import org.mage.plugins.card.utils.CardImageUtils;
/**
*
* @author Quercitron
*/
public enum TokensMtgImageSource implements CardImageSource {
@ -58,7 +58,7 @@ public enum TokensMtgImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
return null;
}
@ -80,7 +80,7 @@ public enum TokensMtgImageSource implements CardImageSource {
}
@Override
public String generateTokenUrl(CardDownloadData card) throws IOException {
public CardImageUrls generateTokenUrl(CardDownloadData card) throws IOException {
String name = card.getName();
String set = card.getSet();
int type = card.getType();
@ -125,7 +125,7 @@ public enum TokensMtgImageSource implements CardImageSource {
String url = "http://tokens.mtg.onl/tokens/" + tokenData.getExpansionSetCode().trim() + '_'
+ tokenData.getNumber().trim() + '-' + tokenData.getName().trim() + ".jpg";
url = url.replace(' ', '-');
return url;
return new CardImageUrls(url);
}
@Override

View file

@ -20,6 +20,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.prefs.Preferences;
import mage.cards.Sets;
import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
@ -462,7 +463,7 @@ public enum WizardCardsImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
String collectorId = card.getCollectorId();
String cardSet = card.getSet();
if (collectorId == null || cardSet == null) {
@ -495,7 +496,7 @@ public enum WizardCardsImageSource implements CardImageSource {
List<String> l = new ArrayList<>(setLinks.values());
if (l.size() >= number) {
link = l.get(number - 1);
} else {;
} else {
link = l.get(number - 21);
if (link != null) {
link = link.replace(Integer.toString(number - 20), (Integer.toString(number - 20) + 'a'));
@ -508,8 +509,12 @@ public enum WizardCardsImageSource implements CardImageSource {
if (link != null && !link.startsWith("http://")) {
link = "http://gatherer.wizards.com" + link;
}
return link;
if (link != null) {
return new CardImageUrls(link);
} else {
return null;
}
}
private Map<String, String> getSetLinks(String cardSet) {
@ -703,7 +708,7 @@ public enum WizardCardsImageSource implements CardImageSource {
}
@Override
public String generateTokenUrl(CardDownloadData card) {
public CardImageUrls generateTokenUrl(CardDownloadData card) {
return null;
}

View file

@ -15,6 +15,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.repository.CardCriteria;
@ -33,6 +34,7 @@ import org.apache.log4j.Logger;
import org.mage.plugins.card.dl.sources.*;
import org.mage.plugins.card.properties.SettingsManager;
import org.mage.plugins.card.utils.CardImageUtils;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
public class DownloadPictures extends DefaultBoundedRangeModel implements Runnable {
@ -597,25 +599,25 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
logger.debug("Downloading image: " + card.getName() + " (" + card.getSet() + ')');
String url;
CardImageUrls urls;
if (ignoreUrls.contains(card.getSet()) || card.isToken()) {
if (!"0".equals(card.getCollectorId())) {
continue;
}
url = cardImageSource.generateTokenUrl(card);
urls = cardImageSource.generateTokenUrl(card);
} else {
url = cardImageSource.generateURL(card);
urls = cardImageSource.generateURL(card);
}
if (url == null) {
if (urls == null) {
String imageRef = cardImageSource.getNextHttpImageUrl();
String fileName = cardImageSource.getFileForHttpImage(imageRef);
if (imageRef != null && fileName != null) {
imageRef = cardImageSource.getSourceName() + imageRef;
try {
URL imageUrl = new URL(imageRef);
card.setToken(cardImageSource.isTokenSource());
Runnable task = new DownloadTask(card, imageUrl, fileName, cardImageSource.getTotalImages());
Runnable task = new DownloadTask(card, imageRef, fileName, cardImageSource.getTotalImages());
executor.execute(task);
} catch (Exception ex) {
}
@ -626,7 +628,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
}
}
} else {
Runnable task = new DownloadTask(card, new URL(url), cardsToDownload.size());
Runnable task = new DownloadTask(card, urls, cardsToDownload.size());
executor.execute(task);
}
@ -662,22 +664,26 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
private final class DownloadTask implements Runnable {
private final CardDownloadData card;
private final URL url;
private final CardImageUrls urls;
private final int count;
private final String actualFilename;
private final boolean useSpecifiedPaths;
DownloadTask(CardDownloadData card, URL url, int count) {
DownloadTask(CardDownloadData card, String baseUrl, int count) {
this(card, new CardImageUrls(baseUrl, null), count);
}
DownloadTask(CardDownloadData card, CardImageUrls urls, int count) {
this.card = card;
this.url = url;
this.urls = urls;
this.count = count;
this.actualFilename = "";
useSpecifiedPaths = false;
}
DownloadTask(CardDownloadData card, URL url, String actualFilename, int count) {
DownloadTask(CardDownloadData card, String baseUrl, String actualFilename, int count) {
this.card = card;
this.url = url;
this.urls = new CardImageUrls(baseUrl, null);
this.count = count;
this.actualFilename = actualFilename;
useSpecifiedPaths = true;
@ -751,14 +757,55 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
}
}
// can download images from many alternative urls
List<String> downloadUrls;
if (this.urls != null) {
downloadUrls = this.urls.getDownloadList();
} else {
downloadUrls = new ArrayList<>();
}
boolean isDownloadOK = false;
URLConnection httpConn = null;
List<String> errorsList = new ArrayList<>();
for (String currentUrl : downloadUrls) {
URL url = new URL(currentUrl);
// on download cancel need to stop
if (cancel) {
return;
}
// download
cardImageSource.doPause(url.getPath());
URLConnection httpConn = url.openConnection(p);
httpConn = url.openConnection(p);
httpConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2");
httpConn.connect();
int responseCode = ((HttpURLConnection) httpConn).getResponseCode();
if (responseCode == 200) {
// download OK
// check result
if (responseCode != 200) {
// show errors only on full fail (all urls were not work)
errorsList.add("Image download for " + card.getName()
+ (!card.getDownloadName().equals(card.getName()) ? " downloadname: " + card.getDownloadName() : "")
+ " (" + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString());
if (logger.isDebugEnabled()) {
// Shows the returned html from the request to the web server
logger.debug("Returned HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream()));
}
// go to next try
continue;
} else {
// all fine
isDownloadOK = true;
break;
}
}
// can save result
if (isDownloadOK & httpConn != null) {
// save data to temp
OutputStream out = null;
OutputStream tfileout = null;
@ -792,8 +839,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
}
out.write(buf, 0, len);
}
}
finally {
} finally {
StreamUtils.closeQuietly(in);
StreamUtils.closeQuietly(out);
StreamUtils.closeQuietly(tfileout);
@ -815,15 +861,9 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
}
} else {
// download ERROR
logger.warn("Image download for " + card.getName()
+ (!card.getDownloadName().equals(card.getName()) ? " downloadname: " + card.getDownloadName() : "")
+ " (" + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString()
);
if (logger.isDebugEnabled()) {
// Shows the returned html from the request to the web server
logger.debug("Returned HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream()));
// download errors
for (String err : errorsList) {
logger.warn(err);
}
}

View file

@ -4,11 +4,11 @@ import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.plugins.card.dl.sources.CardImageSource;
import org.mage.plugins.card.dl.sources.CardImageUrls;
import org.mage.plugins.card.dl.sources.TokensMtgImageSource;
import org.mage.plugins.card.images.CardDownloadData;
/**
*
* @author Quercitron
*/
@Ignore
@ -18,15 +18,16 @@ public class TokensMtgImageSourceTest {
public void generateTokenUrlTest() throws Exception {
CardImageSource imageSource = TokensMtgImageSource.instance;
String url = imageSource.generateTokenUrl(new CardDownloadData("Thopter", "ORI", "0", false, 1, "ORI", ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_010-Thopter.jpg", url);
CardImageUrls url = imageSource.generateTokenUrl(new CardDownloadData("Thopter", "ORI", "0", false, 1, "ORI", ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_010-Thopter.jpg", url.baseUrl);
url = imageSource.generateTokenUrl(new CardDownloadData("Thopter", "ORI", "0", false, 2, "ORI", ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_011-Thopter.jpg", url);
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_011-Thopter.jpg", url.baseUrl);
url = imageSource.generateTokenUrl(new CardDownloadData("Ashaya, the Awoken World", "ORI", "0", false, 0, "ORI", ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_007-Ashaya,-the-Awoken-World.jpg", url);
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_007-Ashaya,-the-Awoken-World.jpg", url.baseUrl);
url = imageSource.generateTokenUrl(new CardDownloadData("Emblem Gideon, Ally of Zendikar", "BFZ", "0", false, 0, null, ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/BFZ_012-Gideon-Emblem.jpg", url);
Assert.assertEquals("http://tokens.mtg.onl/tokens/BFZ_012-Gideon-Emblem.jpg", url.baseUrl);
}
}