-
Notifications
You must be signed in to change notification settings - Fork 15
Support Tokens Mapping of Actual Products #369
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
ZeldaZach
commented
Oct 2, 2025
- Starts with TCGPlayer only
- Creates a mapping main repo can import into new field
- Generates on a daily cadence with update tracking
- Starts with TCGPlayer only - Creates a mapping main repo can import into new field - Generates on a daily cadence with update tracking
a598514 to
abe6753
Compare
scripts/tokens/main.py
Outdated
| tcgplayer_token_face_details[tcgplayer_token_face_index]["uuid"] = ( | ||
| mtgjson_token["uuid"] | ||
| ) | ||
| break |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be solved to be an O1 lookup if you build a map. I generated this with GPT
from typing import Dict, List, Any, Tuple, DefaultDict
from collections import defaultdict
def build_uuid_indexes(
mtgjson_tokens: Dict[str, List[Dict[str, Any]]]
) -> Tuple[Dict[Tuple[str, str], str], Dict[str, List[str]]]:
by_name_number: Dict[Tuple[str, str], str] = {}
by_face_name: DefaultDict[str, List[str]] = defaultdict(list)
for _, token_list in mtgjson_tokens.items():
for t in token_list:
name = (t.get("name") or "").strip()
number = str(t.get("number") or "").strip()
face_name = (t.get("faceName") or "").strip()
uuid = t["uuid"]
if name and number:
by_name_number[(name, number)] = uuid
if face_name:
by_face_name[face_name].append(uuid)
return by_name_number, by_face_name
def add_mtgjson_uuids_to_tcgplayer_token_face_details(
mtgjson_tokens: Dict[str, List[Dict[str, Any]]],
tcgplayer_token_face_details: List[Dict[str, Any]],
) -> None:
by_name_number, by_face_name = build_uuid_indexes(mtgjson_tokens)
for face in tcgplayer_token_face_details:
face_name = (face.get("faceName") or "").strip()
face_id = str(face.get("faceId") or "").strip()
# 1) Exact (name, number) match
uuid = by_name_number.get((face_name, face_id))
if not uuid:
# 2) Fallback: faceName match (handles Punchcard // Punchcard, etc.)
uuids = by_face_name.get(face_name, [])
uuid = uuids[0] if uuids else None
if uuid:
face["uuid"] = uuid
def filter_tokens_with_uuids(
output_tokens: List[Dict[str, Any]],
) -> Dict[str, List[Dict[str, Any]]]:
# Map each MTGJSON uuid → list of token product entries that reference it
out: DefaultDict[str, List[Dict[str, Any]]] = defaultdict(list)
for ot in output_tokens:
for part in ot["tokenParts"]: # <-- fixed key to match builder
if "uuid" in part:
out[part["uuid"]].append(ot)
return out
def build_tokens_mapping(
mtgjson_tokens: Dict[str, List[Dict[str, Any]]],
tcgplayer_tokens: List[Dict[str, Any]],
tcgplayer_token_parser: TcgplayerTokenParser,
):
output_tokens: List[Dict[str, Any]] = []
for tcgplayer_token in tcgplayer_tokens:
faces = tcgplayer_token_parser.split_tcgplayer_token_faces_details(tcgplayer_token)
add_mtgjson_uuids_to_tcgplayer_token_face_details(mtgjson_tokens, faces)
output_tokens.append({
**tcgplayer_token_to_mtgjson_token_products_entry(tcgplayer_token),
"tokenParts": faces, # consistently camelCase everywhere
})
return filter_tokens_with_uuids(output_tokens)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
personally, I'd take more readable (albeit potentally slower) code than ai slop (I'm sure the code you posted works, but it'd take me far longer to parse and understand than @ZeldaZach's code)
also the size of these arrays is pretty small (like 20 items or less), I really don't think the extra optimization is worth the extra code
| def __init__(self) -> None: | ||
| self.__emblem_regex = re.compile(r"Emblem - (.*)") | ||
| self.__get_all_face_names_regex = re.compile( | ||
| r"^(.*?)(?: \(.*?\))? // (.*?)(?: \(.*?\))? Double[- ]Sided Token.*" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works fine as is, but regex makes the parsing logic a little hard to read and kind of brittle if TCGPlayer tweaks their formats to respond to a weird UB token / new mechanic.
One idea would be to make this more rule-based instead of regex-driven. Something like:
def __get_token_face_names(self, token_name: str) -> List[str]:
if token_name.startswith("Emblem - "):
return [token_name.split("Emblem - ", 1)[1] + " Emblem"]
if token_name.lower().startswith(("punch card", "punchcard")):
return ["Punchcard", "Punchcard"]
if " // " in token_name and "Double" in token_name:
faces, *_ = token_name.split(" Double", 1)
left, right = [part.split(" (")[0] for part in faces.split(" // ")]
return [left.strip(), right.strip()]
return [token_name.split(" Token")[0]]Same end result a little more verbose, but IMO a bit easier to follow.
Another option would be to throw this into a little grammar with something like lark, but that’s probably overkill unless we start running into a lot more weird formats.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call out, I think I'll make a tweak to support this instead
|
as long as the new fields are added on top of the existing token card objects (which the sample code I've seen seem to do) i'm happy with this change |
b2a19bd to
d927ce9
Compare