[Card] Import Scryfall Tagger tags from MTGJson

This commit is contained in:
Lukas Brübach 2026-09-21 13:20:25 +02:00
parent 7a2492ac67
commit 1803fce56c
3 changed files with 85 additions and 0 deletions

View file

@ -28,6 +28,7 @@ QString const PowTough("pt");
QString const Side("side");
QString const Layout("layout");
QString const ColorIdentity("coloridentity");
QString const Tags("tags");
inline static const QString getNicePropertyName(QString key)
{
@ -61,6 +62,9 @@ inline static const QString getNicePropertyName(QString key)
if (key == ColorIdentity) {
return QCoreApplication::translate("Mtg", "Color Identity");
}
if (key == Tags) {
return QCoreApplication::translate("Mtg", "Tags");
}
return key;
}
} // namespace Mtg

View file

@ -505,6 +505,21 @@ int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet, const QJson
properties.insert("coloridentity", colorIdentity);
}
// Scryfall Tagger tags (resolved by MTGJSON into the `tags` array).
// Stored space-separated so the `tags:` search can match each slug as a
// discrete token; slugs never contain whitespace.
QStringList tags;
for (const QJsonValue &tag : card.value("tags").toArray()) {
const QString tagSlug = tag.toString().trimmed().toLower();
if (!tagSlug.isEmpty() && !tags.contains(tagSlug)) {
tags.append(tagSlug);
}
}
if (!tags.isEmpty()) {
tags.sort();
properties.insert("tags", tags.join(" "));
}
const auto &mainCardType = getMainCardType(card.value("types").toVariant().toStringList());
if (mainCardType.isEmpty()) {
qDebug() << "warning: no mainCardType for card:" << name;
@ -651,6 +666,14 @@ int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet, const QJson
if (newPriority >= 0 && (currentPriority < 0 || newPriority < currentPriority)) {
properties.insert(prop, thisCardPropertyValue);
}
} else if (prop == "tags") {
// Tags are oracle-level: union both faces instead of
// concatenating them with the split-card separator.
QStringList merged =
(originalPropertyValue + " " + thisCardPropertyValue).split(" ", Qt::SkipEmptyParts);
merged.removeDuplicates();
merged.sort();
properties.insert(prop, merged.join(" "));
} else {
properties.insert(prop,
originalPropertyValue + splitCardPropSeparator + thisCardPropertyValue);

View file

@ -523,6 +523,64 @@ TEST_F(OracleImporterTest, LegacyConvertedManaCostCoercedToCmc)
ASSERT_EQ(result->getProperty("cmc"), "3");
}
// ============================================================================
// Scryfall Tagger tag tests
// ============================================================================
TEST_F(OracleImporterTest, ImportsScryfallTags)
{
QJsonObject card = makeCard("Ramp Card");
card["tags"] = QJsonArray{"ramp", "removal"};
QJsonArray cards{card};
importer->importCardsFromSet(set, cards);
auto result = importer->getCardList().value("Ramp Card");
ASSERT_FALSE(result.isNull());
ASSERT_EQ(result->getProperty("tags"), "ramp removal");
}
TEST_F(OracleImporterTest, TagsAreNormalizedDedupedAndSorted)
{
QJsonObject card = makeCard("Messy Tags");
card["tags"] = QJsonArray{"Ramp", " removal ", "ramp", ""};
QJsonArray cards{card};
importer->importCardsFromSet(set, cards);
auto result = importer->getCardList().value("Messy Tags");
ASSERT_FALSE(result.isNull());
ASSERT_EQ(result->getProperty("tags"), "ramp removal");
}
TEST_F(OracleImporterTest, CardsWithoutTagsHaveNoTagsProperty)
{
QJsonArray cards{makeCard("Untagged Card")};
importer->importCardsFromSet(set, cards);
auto result = importer->getCardList().value("Untagged Card");
ASSERT_FALSE(result.isNull());
ASSERT_FALSE(result->hasProperty("tags"));
}
TEST_F(OracleImporterTest, SplitCardTagsAreUnioned)
{
QJsonObject face1 = makeCard("Fire // Ice");
face1["layout"] = "split";
face1["side"] = "a";
face1["faceName"] = "Fire";
face1["tags"] = QJsonArray{"removal"};
QJsonObject face2 = makeCard("Fire // Ice");
face2["layout"] = "split";
face2["side"] = "b";
face2["faceName"] = "Ice";
face2["tags"] = QJsonArray{"card-advantage", "removal"};
QJsonArray cards{face1, face2};
importer->importCardsFromSet(set, cards);
auto result = importer->getCardList().value("Fire // Ice");
ASSERT_FALSE(result.isNull());
ASSERT_EQ(result->getProperty("tags"), "card-advantage removal");
}
// ============================================================================
// Card deduplication tests
// ============================================================================