[Oracle] Load card tags from a tag database during import

Add a TagDatabase loader that understands Scryfall's Oracle Tags bulk data and user-supplied tag files (tag objects, flat oracle-id or name maps, optional manifest, JSON or JSONL, gzip/xz/zip). The importer joins the slugs on identifiers.scryfallOracleId while the identifiers are still available, falls back to the card name, and unions them with any tags the source already provides. Split-card faces merge through the existing tag union path.

This replaces oracle/scripts/inject_scryfall_tags.py, which patched AllPrintings.json before import. Loading during import keeps tags on by default for every source and lets users pair Oracle with any tag database.
This commit is contained in:
Lukas Brübach 2026-11-08 19:59:04 +01:00
parent 0f45dfa12a
commit 77179f913e
9 changed files with 1145 additions and 217 deletions

View file

@ -6,6 +6,7 @@
#include "libcockatrice/card/relation/card_relation_type.h"
#include "libcockatrice/interfaces/noop_card_set_priority_controller.h"
#include "parsehelpers.h"
#include "tag_database.h"
#include <QChar>
#include <QDebug>
@ -517,9 +518,11 @@ 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.
// Card tags: the source's own `tags` array is used when present (MTGJson
// may ship one eventually), then the configured tag database is joined in
// while the card's identifiers are still available. Stored space-separated
// so `tags:` 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();
@ -527,6 +530,14 @@ int OracleImporter::importCardsFromSet(const CardSetPtr &currentSet, const QJson
tags.append(tagSlug);
}
}
if (tagDatabase) {
const QString oracleId = getJsonString(identifiers, "scryfallOracleId");
for (const QString &tagSlug : tagDatabase->tagsForCard(oracleId, name)) {
if (!tags.contains(tagSlug)) {
tags.append(tagSlug);
}
}
}
if (!tags.isEmpty()) {
tags.sort();
properties.insert("tags", tags.join(" "));