commit 82650f22099a0afd272532207ad1f48c31f7b15e
parent 65174f210d9ba5c3f74e6975fec36fc973bb5a95
Author: Kevin Corvisier <git@kevincorvisier.fr>
Date: Thu, 31 Oct 2024 10:15:16 +0900
Add possibility to save a card pool file containing all cards of decks
downloaded, even if they were not included in the final list of decks
Diffstat:
7 files changed, 120 insertions(+), 14 deletions(-)
diff --git a/src/main/java/fr/kevincorvisier/mtg/dd/Main.java b/src/main/java/fr/kevincorvisier/mtg/dd/Main.java
@@ -12,7 +12,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.core.io.support.ResourcePropertySource;
import org.springframework.stereotype.Service;
-import fr.kevincorvisier.mtg.dd.consumers.DecklistConsumer;
+import fr.kevincorvisier.mtg.dd.consumers.DecklistConsumersService;
import fr.kevincorvisier.mtg.dd.downloaders.DecklistDownloader;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -22,7 +22,7 @@ import lombok.extern.slf4j.Slf4j;
@RequiredArgsConstructor
public class Main
{
- private final DecklistConsumer consumer;
+ private final DecklistConsumersService consumers;
private final Collection<DecklistDownloader> downloaders;
@Value("#{'${sources}'.split('\\|')}")
@@ -46,7 +46,7 @@ public class Main
}
finally
{
- consumer.saveToFolder();
+ consumers.saveToFolder();
}
}
diff --git a/src/main/java/fr/kevincorvisier/mtg/dd/consumers/CardPoolConsumer.java b/src/main/java/fr/kevincorvisier/mtg/dd/consumers/CardPoolConsumer.java
@@ -0,0 +1,74 @@
+package fr.kevincorvisier.mtg.dd.consumers;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import fr.kevincorvisier.mtg.dd.model.Deck;
+import fr.kevincorvisier.mtg.dd.model.DeckMetadata;
+import fr.kevincorvisier.mtg.dd.validation.DeckValidator;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class CardPoolConsumer implements DecklistConsumer
+{
+ private final Collection<String> cardPool = new HashSet<>();
+ private final DeckValidator validator;
+
+ @Value("${card-pool.enabled}")
+ private final boolean enabled;
+ @Value("${card-pool.output-file}")
+ private final File outputFile;
+
+ @Override
+ public boolean accept(final DeckMetadata metadata)
+ {
+ return enabled;
+ }
+
+ @Override
+ public void consume(final Deck deck)
+ {
+ for (final String cardName : deck.getContent().getMain().keySet())
+ {
+ if (validator.validateCard(cardName))
+ cardPool.add(cardName);
+ }
+ }
+
+ @Override
+ public void saveToFolder() throws IOException
+ {
+ if (!enabled)
+ return;
+
+ final File folder = outputFile.getParentFile();
+ if (!folder.exists())
+ folder.mkdirs();
+
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile)))
+ {
+ for (final String cardName : cardPool)
+ {
+ writer.append(sanitizeCardName(cardName)).append('\n');
+ }
+ }
+
+ log.info("Saved {}", outputFile);
+ }
+
+ private static String sanitizeCardName(final String cardName)
+ {
+ final int indexOfSlash = cardName.indexOf("/");
+ return indexOfSlash != -1 ? cardName.substring(0, indexOfSlash) : cardName;
+ }
+}
diff --git a/src/main/java/fr/kevincorvisier/mtg/dd/consumers/DecklistConsumersService.java b/src/main/java/fr/kevincorvisier/mtg/dd/consumers/DecklistConsumersService.java
@@ -54,4 +54,19 @@ public class DecklistConsumersService
consumer.consume(new Deck(metadata, content));
}
}
+
+ public void saveToFolder()
+ {
+ for (final DecklistConsumer consumer : consumers)
+ {
+ try
+ {
+ consumer.saveToFolder();
+ }
+ catch (final IOException e)
+ {
+ log.error("saveToFolder: consumer={}", consumer, e);
+ }
+ }
+ }
}
diff --git a/src/main/java/fr/kevincorvisier/mtg/dd/consumers/DefaultDecklistConsumer.java b/src/main/java/fr/kevincorvisier/mtg/dd/consumers/DefaultDecklistConsumer.java
@@ -40,8 +40,6 @@ public class DefaultDecklistConsumer implements DecklistConsumer, StopCondition
private final DeckValidator validator;
- @Value("${only-ai-playable-cards}")
- private final boolean onlyAiPlayableCards;
@Value("${output-dir}")
private final File folder;
@Value("${ignore.players}")
@@ -98,7 +96,7 @@ public class DefaultDecklistConsumer implements DecklistConsumer, StopCondition
return;
}
- if (!validator.validate(deck, onlyAiPlayableCards))
+ if (!validator.validate(deck))
return;
downloadedByDeckNameByPlayerName.computeIfAbsent(deck.getMetadata().getPlayer().toLowerCase(), k -> new HashMap<>()) //
diff --git a/src/main/java/fr/kevincorvisier/mtg/dd/downloaders/HareruyaDecklistDownloader.java b/src/main/java/fr/kevincorvisier/mtg/dd/downloaders/HareruyaDecklistDownloader.java
@@ -9,6 +9,7 @@ import org.openqa.selenium.WebElement;
import org.springframework.stereotype.Service;
import fr.kevincorvisier.mtg.dd.Crawler;
+import fr.kevincorvisier.mtg.dd.StopCondition;
import fr.kevincorvisier.mtg.dd.consumers.DecklistConsumersService;
import fr.kevincorvisier.mtg.dd.model.DeckMetadata;
import fr.kevincorvisier.mtg.dd.model.DeckMetadataFactory;
@@ -23,6 +24,7 @@ public class HareruyaDecklistDownloader implements DecklistDownloader
private final Crawler crawler;
private final DeckMetadataFactory metadataFactory;
private final DecklistConsumersService consumers;
+ private final StopCondition stopCondition;
@Override
public boolean accept(final URL url)
@@ -41,6 +43,9 @@ public class HareruyaDecklistDownloader implements DecklistDownloader
{
final DeckMetadata deck = processDeckElement(element);
consumers.process(deck);
+
+ if (stopCondition.capacity() <= 0)
+ return;
}
catch (final IOException e)
{
diff --git a/src/main/java/fr/kevincorvisier/mtg/dd/validation/DeckValidator.java b/src/main/java/fr/kevincorvisier/mtg/dd/validation/DeckValidator.java
@@ -22,6 +22,9 @@ public class DeckValidator
private final Collection<String> banlist = new HashSet<>();
private final AiCards aiCards;
+ @Value("${only-ai-playable-cards}")
+ private final boolean onlyAiPlayableCards;
+
@Value("${banlists}")
public void setBanlistFileNames(final Collection<String> banlistFileNames) throws IOException
{
@@ -35,22 +38,17 @@ public class DeckValidator
}
}
- public boolean validate(final Deck deck, final boolean onlyAiPlayableCards)
+ public boolean validate(final Deck deck)
{
int cardCount = 0;
for (final Entry<String, Integer> card : deck.getContent().getMain().entrySet())
{
final String cardName = card.getKey();
- if (banlist.contains(cardName))
- {
- log.debug("validate: invalid deck: {} is banned: {}", cardName, deck);
- return false;
- }
- if (onlyAiPlayableCards && !aiCards.isPlayableByAi(cardName))
+ if (!validateCard(cardName))
{
- log.debug("validate: {} is not playable by AI: {}", cardName, deck);
+ log.debug("validate: {} is not valid: {}", cardName, deck);
return false;
}
@@ -66,6 +64,17 @@ public class DeckValidator
return true;
}
+ public boolean validateCard(final String name)
+ {
+ if (banlist.contains(name))
+ return false;
+
+ if (onlyAiPlayableCards && !aiCards.isPlayableByAi(name))
+ return false;
+
+ return true;
+ }
+
private void readBanlist(final String name) throws IOException
{
try (BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().getResourceAsStream(name))))
diff --git a/src/main/packaged-resources/cfg/application.properties b/src/main/packaged-resources/cfg/application.properties
@@ -22,3 +22,8 @@ only-ai-playable-cards=true
# Minimum number of players for a tournament from TCDecks to be taken into account, tournament with less players will be ignored
tcdecks.tournament.players.min=0
+# When enabled, a card pool is created containing cards from all decks that have been considered for inclusion
+card-pool.enabled=false
+# Name of the file to save the card pool to
+card-pool.output-file=
+