mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 04:08:01 +00:00
Merge branch 'add-mobile-art-download' into 'master'
Add option to download missing card art on the fly See merge request core-developers/forge!1049
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
package forge.interfaces;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public interface IDeviceAdapter {
|
||||
boolean isConnectedToInternet();
|
||||
boolean isConnectedToWifi();
|
||||
@@ -10,4 +14,5 @@ public interface IDeviceAdapter {
|
||||
void preventSystemSleep(boolean preventSleep);
|
||||
void restart();
|
||||
void exit();
|
||||
void convertToJPEG(InputStream input, OutputStream output) throws IOException;
|
||||
}
|
||||
|
||||
@@ -16,12 +16,14 @@ import forge.match.HostedMatch;
|
||||
import forge.sound.IAudioClip;
|
||||
import forge.sound.IAudioMusic;
|
||||
import forge.util.Callback;
|
||||
import forge.util.ImageFetcher;
|
||||
|
||||
public interface IGuiBase {
|
||||
boolean isRunningOnDesktop();
|
||||
boolean isLibgdxPort();
|
||||
String getCurrentVersion();
|
||||
String getAssetsDir();
|
||||
ImageFetcher getImageFetcher();
|
||||
void invokeInEdtNow(Runnable runnable);
|
||||
void invokeInEdtLater(Runnable runnable);
|
||||
void invokeInEdtAndWait(Runnable proc);
|
||||
|
||||
124
forge-gui/src/main/java/forge/util/ImageFetcher.java
Normal file
124
forge-gui/src/main/java/forge/util/ImageFetcher.java
Normal file
@@ -0,0 +1,124 @@
|
||||
package forge.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import forge.FThreads;
|
||||
import forge.ImageKeys;
|
||||
import forge.StaticData;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import forge.item.PaperCard;
|
||||
import forge.model.FModel;
|
||||
import forge.properties.ForgeConstants;
|
||||
import forge.properties.ForgePreferences;
|
||||
|
||||
public abstract class ImageFetcher {
|
||||
private static final ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
private HashMap<String, HashSet<Callback>> currentFetches = new HashMap<>();
|
||||
private HashMap<String, String> tokenImages;
|
||||
|
||||
public void fetchImage(final String imageKey, final Callback callback) {
|
||||
FThreads.assertExecutedByEdt(true);
|
||||
|
||||
if (!FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ENABLE_ONLINE_IMAGE_FETCHER))
|
||||
return;
|
||||
|
||||
// Fake card (like the ante prompt) trying to be "fetched"
|
||||
if (imageKey.length() < 2)
|
||||
return;
|
||||
|
||||
final String prefix = imageKey.substring(0, 2);
|
||||
final ArrayList<String> downloadUrls = new ArrayList<>();
|
||||
File destFile = null;
|
||||
if (prefix.equals(ImageKeys.CARD_PREFIX)) {
|
||||
PaperCard paperCard = ImageUtil.getPaperCardFromImageKey(imageKey);
|
||||
if (paperCard == null) {
|
||||
System.err.println("Paper card not found for: " + imageKey);
|
||||
return;
|
||||
}
|
||||
final boolean backFace = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX);
|
||||
final String filename = ImageUtil.getImageKey(paperCard, backFace, true);
|
||||
destFile = new File(ForgeConstants.CACHE_CARD_PICS_DIR + "/" + filename + ".jpg");
|
||||
|
||||
// First try to download the LQ Set URL, then fetch from scryfall/magiccards.info
|
||||
StringBuilder setDownload = new StringBuilder(ForgeConstants.URL_PIC_DOWNLOAD);
|
||||
setDownload.append(ImageUtil.getDownloadUrl(paperCard, backFace));
|
||||
downloadUrls.add(setDownload.toString());
|
||||
|
||||
final StaticData data = StaticData.instance();
|
||||
final int cardNum = data.getCommonCards().getCardCollectorNumber(paperCard.getName(), paperCard.getEdition());
|
||||
if (cardNum != -1) {
|
||||
String suffix = "";
|
||||
if (paperCard.getRules().getOtherPart() != null) {
|
||||
suffix = (backFace ? "b" : "a");
|
||||
}
|
||||
final String editionMciCode = data.getEditions().getMciCodeByCode(paperCard.getEdition());
|
||||
downloadUrls.add(String.format("https://img.scryfall.com/cards/normal/en/%s/%d%s.jpg", editionMciCode, cardNum, suffix));
|
||||
downloadUrls.add(String.format("https://magiccards.info/scans/en/%s/%d%s.jpg", editionMciCode, cardNum, suffix));
|
||||
}
|
||||
} else if (prefix.equals(ImageKeys.TOKEN_PREFIX)) {
|
||||
if (tokenImages == null) {
|
||||
tokenImages = new HashMap<>();
|
||||
for (Pair<String, String> 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) {
|
||||
System.err.println("No specified file.. Attempting to download from default Url");
|
||||
tokenUrl = String.format("%s%s", ForgeConstants.URL_TOKEN_DOWNLOAD, filename);
|
||||
}
|
||||
destFile = new File(ForgeConstants.CACHE_TOKEN_PICS_DIR, filename);
|
||||
downloadUrls.add(tokenUrl);
|
||||
}
|
||||
|
||||
if (downloadUrls.isEmpty()) {
|
||||
System.err.println("No download URLs for: " + imageKey);
|
||||
return;
|
||||
}
|
||||
|
||||
if (destFile.exists()) {
|
||||
// TODO: Figure out why this codepath gets reached. Ideally, fetchImage() wouldn't
|
||||
// be called if we already have the image.
|
||||
return;
|
||||
}
|
||||
final String destPath = destFile.getAbsolutePath();
|
||||
|
||||
// Note: No synchronization is needed here because this is executed on
|
||||
// EDT thread (see assert on top) and so is the notification of observers.
|
||||
HashSet<Callback> observers = currentFetches.get(destPath);
|
||||
if (observers != null) {
|
||||
// Already in the queue, simply add the new observer.
|
||||
observers.add(callback);
|
||||
return;
|
||||
}
|
||||
|
||||
observers = new HashSet<>();
|
||||
observers.add(callback);
|
||||
currentFetches.put(destPath, observers);
|
||||
|
||||
final Runnable notifyObservers = new Runnable() {
|
||||
public void run() {
|
||||
FThreads.assertExecutedByEdt(true);
|
||||
|
||||
for (Callback o : currentFetches.get(destPath)) {
|
||||
o.onImageFetched();
|
||||
}
|
||||
currentFetches.remove(destPath);
|
||||
}
|
||||
};
|
||||
threadPool.submit(getDownloadTask(downloadUrls.toArray(new String[0]), destPath, notifyObservers));
|
||||
}
|
||||
|
||||
protected abstract Runnable getDownloadTask(String[] toArray, String destPath, Runnable notifyObservers);
|
||||
|
||||
public static interface Callback {
|
||||
public void onImageFetched();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user