Files
my-botty/scripts/make_traderie_csv.py
T

115 lines
3.9 KiB
Python

# Convert the stash sale list into the CSV that tools/traderie_lister.py expects.
#
# python scripts/make_traderie_csv.py # everything sellable
# python scripts/make_traderie_csv.py --runes # runes only
#
# Writes traderie_items.csv, then:
# python tools/traderie_lister.py --csv traderie_items.csv --dry-run
import csv
import os
import re
import sys
_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
os.chdir(_root)
SRC = "stash_sale_list.csv"
OUT = "traderie_items.csv"
COLUMNS = ["name", "qty", "base_tier", "base_item", "ring_variant",
"amulet_variant", "ethereal", "pricing", "price_amount",
"price_currency"]
# Runewords need a "Base Item" field. "No base" is the lister's own escape
# hatch for when the socketed base does not matter to the listing.
RUNEWORDS = {"spirit", "insight", "stealth", "lore", "smoke", "rhyme",
"ancients pledge", "leaf", "malice", "steel", "zephyr", "king's grace",
"edge", "harmony", "white", "peace", "myth", "black", "honor"}
# Not tradeable / not worth a listing. Potions are consumables; sub-perfect gems
# were already dropped upstream but are re-checked here so this script is safe to
# run against any sale list.
SKIP_WORDS = ("rejuvenation potion", "scroll of", "tome of", "key of",
"chipped", "flawed", "flawless")
def title_case(name: str) -> str:
"""Stash tooltips are ALL CAPS; Traderie searches title case.
Apostrophes matter: "TAL RASHA'S" must become "Tal Rasha's", not
"Tal Rasha'S", or the dropdown search misses.
"""
out = []
for word in name.lower().split():
if "'" in word:
head, _, tail = word.partition("'")
out.append(head.capitalize() + "'" + tail)
else:
out.append(word.capitalize())
return " ".join(out)
def main():
runes_only = "--runes" in sys.argv
with open(SRC, encoding="utf-8") as f:
rows = list(csv.DictReader(f))
seen: dict[str, dict] = {}
skipped = 0
for r in rows:
raw = (r["name"] or "").strip()
low = raw.lower()
if not raw or any(w in low for w in SKIP_WORDS):
skipped += 1
continue
if runes_only and not low.endswith("rune"):
continue
name = title_case(raw)
qty = r.get("qty") or "1"
try:
qty = int(qty)
except ValueError:
qty = 1
# The same item can sit in several cells (2x TARNHELM, 4x SMALL CHARM OF
# INERTIA). Traderie wants one listing with a quantity, not N listings.
if name in seen:
seen[name]["qty"] += qty
continue
base_item = "No base" if name.lower() in RUNEWORDS else ""
seen[name] = {
"name": name,
"qty": qty,
"base_tier": "",
"base_item": base_item,
"ring_variant": "",
"amulet_variant": "",
"ethereal": "",
# You said you would set prices yourself — ask_for_offers means the
# listing goes up without committing to a number.
"pricing": "ask_for_offers",
"price_amount": "",
"price_currency": "",
}
out = sorted(seen.values(), key=lambda r: (not r["name"].endswith("Rune"), r["name"]))
with open(OUT, "w", newline="", encoding="utf-8") as f:
w = csv.DictWriter(f, fieldnames=COLUMNS)
w.writeheader()
w.writerows(out)
print(f"wrote {OUT}: {len(out)} listings ({skipped} skipped as untradeable)")
runes = [r for r in out if r["name"].endswith("Rune")]
print(f" runes: {len(runes)} other: {len(out) - len(runes)}")
needs_base = [r["name"] for r in out if r["base_item"]]
if needs_base:
print(f" runewords given base_item='No base': {', '.join(needs_base)}")
print("\nnext:")
print(f" python tools/traderie_lister.py --csv {OUT} --dry-run")
if __name__ == "__main__":
main()