mirror of
https://github.com/correl/mage.git
synced 2024-12-25 03:00:15 +00:00
commit
2ec3ebde4c
4 changed files with 518 additions and 1 deletions
|
@ -0,0 +1,255 @@
|
|||
package org.mage.plugins.card.dl.sources;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.swing.JOptionPane;
|
||||
import mage.cards.Sets;
|
||||
import org.mage.plugins.card.images.CardDownloadData;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public enum CopyPasteImageSource implements CardImageSource {
|
||||
|
||||
instance;
|
||||
|
||||
private Set<String> supportedSets = new LinkedHashSet<String>();
|
||||
private Set<String> missingCards = new LinkedHashSet<String>();
|
||||
HashMap<String, String> singleLinks = null;
|
||||
boolean loadedFromDialog = false;
|
||||
boolean viewMissingCards = true;
|
||||
HashMap<String, Integer> singleLinksDone = null;
|
||||
private static int maxTimes = 2;
|
||||
|
||||
@Override
|
||||
public String getSourceName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAverageSize() {
|
||||
return 260.7f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNextHttpImageUrl() {
|
||||
if (singleLinks == null) {
|
||||
setupLinks();
|
||||
}
|
||||
|
||||
for (String key : singleLinksDone.keySet()) {
|
||||
if (singleLinksDone.get(key) < maxTimes) {
|
||||
singleLinksDone.put(key, maxTimes);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
if (maxTimes < 2) {
|
||||
maxTimes++;
|
||||
}
|
||||
for (String key : singleLinksDone.keySet()) {
|
||||
if (singleLinksDone.get(key) < maxTimes) {
|
||||
singleLinksDone.put(key, maxTimes);
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileForHttpImage(String httpImageUrl) {
|
||||
String copy = httpImageUrl;
|
||||
if (copy != null) {
|
||||
return singleLinks.get(copy);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
|
||||
if (singleLinks == null) {
|
||||
setupLinks();
|
||||
}
|
||||
String url = singleLinks.get(card.getSet() + "/" + card.getName());
|
||||
if (url != null && url.length() > 0) {
|
||||
return new CardImageUrls(url);
|
||||
}
|
||||
url = singleLinks.get(card.getSet() + "/" + card.getName() + "." + card.getCollectorId());
|
||||
if (url != null && url.length() > 0) {
|
||||
return new CardImageUrls(url);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int ls_size_mc = 0;
|
||||
int ls_size_ss = 0;
|
||||
int ls_size_sl = 0;
|
||||
int num_nos = 0;
|
||||
|
||||
private boolean isDifferent() {
|
||||
boolean isdiff = false;
|
||||
if (ls_size_mc != missingCards.size()) {
|
||||
ls_size_mc = missingCards.size();
|
||||
isdiff = true;
|
||||
}
|
||||
if (ls_size_ss != supportedSets.size()) {
|
||||
ls_size_ss = supportedSets.size();
|
||||
isdiff = true;
|
||||
}
|
||||
if (ls_size_sl != singleLinks.size()) {
|
||||
ls_size_sl = singleLinks.size();
|
||||
isdiff = true;
|
||||
}
|
||||
num_nos++;
|
||||
if (num_nos > 2) {
|
||||
num_nos = 0;
|
||||
isdiff = true;
|
||||
}
|
||||
return isdiff;
|
||||
}
|
||||
|
||||
private void setupLinks() {
|
||||
if (singleLinks != null && loadedFromDialog) {
|
||||
if (!viewMissingCards) {
|
||||
if (isDifferent() && JOptionPane.showConfirmDialog(null,
|
||||
"View your missing cards and reset the list of card images to download again?",
|
||||
"View missing cards (found " + missingCards.size() + ") / Reset URLs to download ", JOptionPane.YES_NO_OPTION)
|
||||
== JOptionPane.YES_OPTION) {
|
||||
viewMissingCards = true;
|
||||
singleLinks.clear();
|
||||
loadedFromDialog = false;
|
||||
supportedSets.clear();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!(viewMissingCards && missingCards.size() > 0)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
singleLinks = new HashMap<>();
|
||||
loadedFromDialog = false;
|
||||
|
||||
final CopyPasteImageSourceDialog dialog = new CopyPasteImageSourceDialog();
|
||||
dialog.pack();
|
||||
int count = 0;
|
||||
if (viewMissingCards && missingCards.size() > 0 && singleLinks.size() == 0) {
|
||||
viewMissingCards = false;
|
||||
String displayMissingCardsStr = "Up to the first 20 cards are:\n";
|
||||
String missingCardsStr = "";
|
||||
if (this.missingCards != null) {
|
||||
for (String card : this.missingCards) {
|
||||
if (count < 20) {
|
||||
displayMissingCardsStr = displayMissingCardsStr + card + "\n";
|
||||
}
|
||||
missingCardsStr = missingCardsStr + card + "\n";
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
StringSelection stringSelection = new StringSelection(missingCardsStr);
|
||||
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
|
||||
clipboard.setContents(stringSelection, null);
|
||||
|
||||
if (isDifferent() && JOptionPane.showConfirmDialog(null,
|
||||
displayMissingCardsStr + "\n\nReset the list again?\n(NB: The full list has been copied to the clipboard)",
|
||||
"Your missing cards (found " + missingCards.size() + "): ", JOptionPane.YES_NO_OPTION)
|
||||
== JOptionPane.YES_OPTION) {
|
||||
viewMissingCards = true;
|
||||
singleLinks.clear();
|
||||
loadedFromDialog = false;
|
||||
supportedSets.clear();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
dialog.setVisible(true);
|
||||
String[] lines = dialog.getPastedData().split(System.getProperty("line.separator"));
|
||||
|
||||
for (String line : lines) {
|
||||
// Break into >> "\1", "\2"
|
||||
Pattern regex = Pattern.compile("\\s*\"(.*?)/(.*?)\"\\s*,\\s*\"(.*?)\"");
|
||||
Matcher regexMatcher = regex.matcher(line);
|
||||
while (regexMatcher.find()) {
|
||||
String setCode = regexMatcher.group(1);
|
||||
String cardName = regexMatcher.group(2);
|
||||
String imageURL = regexMatcher.group(3);
|
||||
supportedSets.add(setCode);
|
||||
singleLinks.put(setCode + "/" + cardName, imageURL);
|
||||
isDifferent();
|
||||
}
|
||||
}
|
||||
|
||||
loadedFromDialog = true;
|
||||
if (lines.length == 0) {
|
||||
loadedFromDialog = false;
|
||||
viewMissingCards = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CardImageUrls generateTokenUrl(CardDownloadData card) throws IOException {
|
||||
try {
|
||||
return generateURL(card);
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTotalImages() {
|
||||
if (singleLinks == null) {
|
||||
setupLinks();
|
||||
}
|
||||
if (singleLinks != null) {
|
||||
return singleLinks.size();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTokenSource() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<String> getSupportedSets() {
|
||||
setupLinks();
|
||||
ArrayList<String> supportedSetsCopy = new ArrayList<>();
|
||||
if (supportedSets.size() == 0) {
|
||||
for (String setCode : Sets.getInstance().keySet()) {
|
||||
supportedSets.add(setCode);
|
||||
}
|
||||
}
|
||||
|
||||
supportedSetsCopy.addAll(supportedSets);
|
||||
return supportedSetsCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPause(String httpImageUrl) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isImageProvided(String setCode, String cardName) {
|
||||
missingCards.add(setCode + "/" + cardName);
|
||||
|
||||
if (singleLinks != null) {
|
||||
return singleLinks.containsKey(setCode + "/" + cardName) || singleLinks.containsKey(setCode + "/" + cardName + "-a");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSetSupportedComplete(String setCode) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.mage.plugins.card.dl.sources.CopyPasteImageSourceDialog">
|
||||
<grid id="cbd77" binding="contentPane" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="10" left="10" bottom="10" right="10"/>
|
||||
<constraints>
|
||||
<xy x="48" y="54" width="540" height="500"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<minimumSize width="540" height="450"/>
|
||||
</properties>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<grid id="94766" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<hspacer id="98af6">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</hspacer>
|
||||
<grid id="9538f" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="true" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="e7465" class="javax.swing.JButton" binding="buttonOK">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Import"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="5723f" class="javax.swing.JButton" binding="buttonCancel">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Cancel"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
<grid id="e3588" layout-manager="FormLayout">
|
||||
<rowspec value="center:d:grow"/>
|
||||
<colspec value="fill:d:noGrow"/>
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="f8bac" class="javax.swing.JEditorPane" binding="txtDeckList">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="50"/>
|
||||
</grid>
|
||||
<forms defaultalign-horz="false" defaultalign-vert="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<minimumSize width="250" height="400"/>
|
||||
<preferredSize width="550" height="400"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
|
@ -0,0 +1,182 @@
|
|||
package org.mage.plugins.card.dl.sources;
|
||||
|
||||
import mage.util.StreamUtils;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import javax.swing.*;
|
||||
|
||||
public class CopyPasteImageSourceDialog extends JDialog {
|
||||
|
||||
private JPanel contentPane;
|
||||
private JButton buttonOK;
|
||||
private JButton buttonCancel;
|
||||
private JEditorPane txtDeckList;
|
||||
|
||||
private String tmpPath;
|
||||
|
||||
public CopyPasteImageSourceDialog() {
|
||||
initComponents();
|
||||
setContentPane(contentPane);
|
||||
setModal(true);
|
||||
getRootPane().setDefaultButton(buttonOK);
|
||||
|
||||
buttonOK.addActionListener(e -> onOK());
|
||||
buttonCancel.addActionListener(e -> onCancel());
|
||||
|
||||
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
||||
addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
onCancel();
|
||||
}
|
||||
});
|
||||
|
||||
// Close on "ESC"
|
||||
contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
||||
}
|
||||
|
||||
private void onOK() {
|
||||
BufferedWriter bw = null;
|
||||
try {
|
||||
File temp = File.createTempFile("import_images_from_url", ".txt");
|
||||
bw = new BufferedWriter(new FileWriter(temp));
|
||||
bw.write(txtDeckList.getText());
|
||||
tmpPath = temp.getPath();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
StreamUtils.closeQuietly(bw);
|
||||
}
|
||||
|
||||
dispose();
|
||||
}
|
||||
|
||||
private void onCancel() {
|
||||
dispose();
|
||||
}
|
||||
|
||||
public String getTmpPath() {
|
||||
return tmpPath;
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
contentPane = new JPanel();
|
||||
JPanel panel1 = new JPanel();
|
||||
JPanel panel2 = new JPanel();
|
||||
buttonOK = new JButton();
|
||||
buttonCancel = new JButton();
|
||||
JPanel panel3 = new JPanel();
|
||||
txtDeckList = new JEditorPane();
|
||||
|
||||
{
|
||||
contentPane.setMinimumSize(new Dimension(540, 450));
|
||||
|
||||
contentPane.setBorder(new javax.swing.border.CompoundBorder(
|
||||
new javax.swing.border.TitledBorder(new javax.swing.border.EmptyBorder(0, 0, 0, 0),
|
||||
"Download Images from Copy/Pasted Text", javax.swing.border.TitledBorder.CENTER,
|
||||
javax.swing.border.TitledBorder.TOP, new java.awt.Font("Dialog", java.awt.Font.PLAIN, 12),
|
||||
java.awt.Color.BLACK), contentPane.getBorder()));
|
||||
|
||||
contentPane.addPropertyChangeListener(e -> {
|
||||
if ("border".equals(e.getPropertyName())) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
});
|
||||
|
||||
contentPane.addPropertyChangeListener(e -> {
|
||||
if ("border".equals(e.getPropertyName())) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
});
|
||||
|
||||
contentPane.setLayout(new GridBagLayout());
|
||||
((GridBagLayout) contentPane.getLayout()).columnWidths = new int[]{0, 0};
|
||||
((GridBagLayout) contentPane.getLayout()).rowHeights = new int[]{0, 0, 0};
|
||||
((GridBagLayout) contentPane.getLayout()).columnWeights = new double[]{0.01, 1.0E-4};
|
||||
((GridBagLayout) contentPane.getLayout()).rowWeights = new double[]{0.01, 0.0, 1.0E-4};
|
||||
|
||||
{
|
||||
panel1.setLayout(new GridBagLayout());
|
||||
((GridBagLayout) panel1.getLayout()).columnWidths = new int[]{0, 0, 0};
|
||||
((GridBagLayout) panel1.getLayout()).rowHeights = new int[]{0, 0};
|
||||
((GridBagLayout) panel1.getLayout()).columnWeights = new double[]{0.0, 0.01, 1.0E-4};
|
||||
((GridBagLayout) panel1.getLayout()).rowWeights = new double[]{0.01, 1.0E-4};
|
||||
|
||||
{
|
||||
panel2.setLayout(new GridBagLayout());
|
||||
((GridBagLayout) panel2.getLayout()).columnWidths = new int[]{0, 4, 0, 0};
|
||||
((GridBagLayout) panel2.getLayout()).rowHeights = new int[]{0, 0};
|
||||
((GridBagLayout) panel2.getLayout()).columnWeights = new double[]{0.01, 0.0, 0.01, 1.0E-4};
|
||||
((GridBagLayout) panel2.getLayout()).rowWeights = new double[]{0.0, 1.0E-4};
|
||||
|
||||
//---- buttonOK ----
|
||||
buttonOK.setText("Download from URLs");
|
||||
panel2.add(buttonOK, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
|
||||
GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
|
||||
new Insets(0, 0, 0, 0), 0, 0));
|
||||
|
||||
//---- buttonCancel ----
|
||||
buttonCancel.setText("Cancel");
|
||||
panel2.add(buttonCancel, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0,
|
||||
GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
|
||||
new Insets(0, 0, 0, 0), 0, 0));
|
||||
}
|
||||
panel1.add(panel2, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0,
|
||||
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
|
||||
new Insets(0, 0, 0, 0), 0, 0));
|
||||
}
|
||||
contentPane.add(panel1, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
|
||||
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
|
||||
new Insets(0, 0, 0, 0), 0, 0));
|
||||
|
||||
{
|
||||
panel3.setLayout(new GridBagLayout());
|
||||
((GridBagLayout) panel3.getLayout()).columnWidths = new int[]{0, 0};
|
||||
((GridBagLayout) panel3.getLayout()).rowHeights = new int[]{0, 0};
|
||||
((GridBagLayout) panel3.getLayout()).columnWeights = new double[]{0.0, 1.0E-4};
|
||||
((GridBagLayout) panel3.getLayout()).rowWeights = new double[]{1.0, 1.0E-4};
|
||||
|
||||
txtDeckList.setMinimumSize(new Dimension(250, 400));
|
||||
txtDeckList.setPreferredSize(new Dimension(550, 400));
|
||||
|
||||
txtDeckList.setText("// Example follows. \nNB: **DELETE ALL TEXT AND GO SELECT THIS SOURCE AGAIN TO SEE THE NAMES CARDS YOU'RE MISSING IMAGES FOR!!!***\n\"SWS/Might of the Wild\", \"http://i.imgur.com/eNXOdxp.jpg\"\n\"PTC/Wolf of Devil's Breach\", \"https://img.scryfall.com/cards/large/en/psoi/192s.jpg\"\n\nExpected columns: Name of Card (Set Trigraph\\Name), URL of image\n\n\n");
|
||||
|
||||
JScrollPane txtScrollableDeckList = new JScrollPane(txtDeckList);
|
||||
panel3.add(txtScrollableDeckList, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0,
|
||||
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
|
||||
new Insets(0, 0, 0, 0), 0, 0));
|
||||
}
|
||||
contentPane.add(panel3, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
|
||||
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
|
||||
new Insets(0, 0, 5, 0), 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> missingCards = null;
|
||||
|
||||
public void addMissingCards(Set<String> missingCards) {
|
||||
this.missingCards = missingCards;
|
||||
String missingCardsStr = "";
|
||||
boolean found = false;
|
||||
if (this.missingCards != null) {
|
||||
for (String card : this.missingCards) {
|
||||
found = true;
|
||||
missingCardsStr = missingCardsStr + card + "\n";
|
||||
}
|
||||
}
|
||||
if (found == false) {
|
||||
missingCardsStr = "\n\nNote: Leave blank to see your missing card names!\n";
|
||||
}
|
||||
txtDeckList.setText(txtDeckList.getText() + "\n\nYour missing card images are:\n" + missingCardsStr);
|
||||
}
|
||||
|
||||
public String getPastedData() {
|
||||
return txtDeckList.getText();
|
||||
}
|
||||
}
|
|
@ -84,7 +84,8 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
|
|||
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),
|
||||
ALTERNATIVE("7. alternative.mtg.onl", AltMtgOnlTokensImageSource.instance);
|
||||
ALTERNATIVE("7. alternative.mtg.onl", AltMtgOnlTokensImageSource.instance),
|
||||
COPYPASTE("8. Copy and Paste Image URLs", CopyPasteImageSource.instance);
|
||||
// MTG_ONL("mtg.onl", MtgOnlTokensImageSource.instance), Not working correctly yet
|
||||
// MAGICCARDS("magiccards.info", MagicCardsImageSource.instance)
|
||||
|
||||
|
|
Loading…
Reference in a new issue