feat(catalog): add scripts/catalog-sync.ts CLI + interactive menu
CI / check (push) Successful in 32s
CI / tests-integration (push) Successful in 1m55s
CI / tests-unit (push) Successful in 2m1s
CI / tests-imaging-browsers (push) Successful in 2m7s
CI / tests-ui (push) Successful in 2m44s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 1m46s
CI / deploy (push) Successful in 3m28s
CI / check (push) Successful in 32s
CI / tests-integration (push) Successful in 1m55s
CI / tests-unit (push) Successful in 2m1s
CI / tests-imaging-browsers (push) Successful in 2m7s
CI / tests-ui (push) Successful in 2m44s
CI / preflight (push) Skipped
CI / tests-quality (push) Successful in 1m46s
CI / deploy (push) Successful in 3m28s
Updating the catalog was only possible from the admin "Catalog audit" page, which streams `runCatalogAudit` over SSE and always compares against every enabled clone source. This adds the same engine to the terminal so it can be run by hand or from cron: - `scripts/catalog-sync.ts` — CLI driver around `runCatalogAudit`. Prints the live progress, the per-source "on the source but not in this hotel" counts and a summary block; generated catalog SQL is saved to `storage/catalog-sync/*.sql` (gitignored). Supports `--list-sources`, `--sources=<a,b>`, `--icons`, `--nitros`, `--furnidata`, `--structure`, `--check-ids`, `--sql`, `--apply-sql`, `--organize-sql`, `--all`, `--json` and `--fail-on-errors`. - `scripts/catalog-sync.sh` — interactive menu (`pnpm catalog:sync`). Lists the configured sources (so the menu always matches `clone_sources`), lets Habbo (COM) be taken with Enter, and offers audit-only through full repair + applying the catalog SQL, each with a distinct confirmation. With no arguments it needs a terminal; with any flag it passes straight through to the CLI. - `runCatalogAudit` gains `sourceIds` to restrict which sites are compared; omitting it keeps the previous "compare against everything enabled" behaviour. An audit writes nothing, and `--apply-sql` is the only flag that changes the catalog. Verified against the live DB: 16370 items_base rows, 16479 catalog items, 2871 Habbo (COM) entries missing from this hotel.
This commit is contained in:
1 parent
61107848f8
commit
4b575d3a1d
7 files changed
+739
-1
No files matched your search
Executable
+157
@@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env bash
|
||||
# Update the hotel catalog from a clone source (Habbo, retros, …).
|
||||
#
|
||||
# Two ways to use it:
|
||||
# ./scripts/catalog-sync.sh interactive menu
|
||||
# ./scripts/catalog-sync.sh --all --sql same flags as the CLI, no menu
|
||||
#
|
||||
# The menu asks which sites to compare (Habbo is the preset) and what may be
|
||||
# written. An audit is read-only; only a repair option touches the catalog, and
|
||||
# applying the generated catalog SQL always needs its own choice.
|
||||
|
||||
cd "$(dirname "$0")/.." || exit 1
|
||||
CLI="scripts/catalog-sync.ts"
|
||||
# The react-server export condition resolves `server-only` to its no-op build,
|
||||
# exactly like `pnpm jobs:worker` — the audit engine imports server modules.
|
||||
RUN=(node --conditions=react-server --import tsx "$CLI")
|
||||
|
||||
# Any flag passed straight through means "no menu", so the same entry point
|
||||
# works for cron/CI where only the flag path is safe.
|
||||
if [ $# -gt 0 ]; then
|
||||
exec "${RUN[@]}" "$@"
|
||||
fi
|
||||
|
||||
if [ ! -t 0 ]; then
|
||||
echo "Not a terminal. Use the non-interactive form, e.g.:" >&2
|
||||
echo " $0 --all --sources=default-habbo-com" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== Catalog sync ==="
|
||||
echo
|
||||
|
||||
# ── Step 1: which sites to compare ───────────────────────────────────────────
|
||||
# Ask the CLI for the configured sources so the menu always matches the live
|
||||
# `clone_sources` setting (and its defaults) instead of a hardcoded list.
|
||||
mapfile -t SOURCE_ROWS < <("${RUN[@]}" --list-sources --tsv)
|
||||
if [ "${#SOURCE_ROWS[@]}" -eq 0 ]; then
|
||||
echo "No clone sources are configured." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IDS=()
|
||||
NAMES=()
|
||||
echo "Compare this catalog against:"
|
||||
for i in "${!SOURCE_ROWS[@]}"; do
|
||||
IFS=$'\t' read -r SOURCE_ID SOURCE_NAME _SOURCE_URL <<<"${SOURCE_ROWS[$i]}"
|
||||
IDS+=("$SOURCE_ID")
|
||||
NAMES+=("$SOURCE_NAME")
|
||||
printf " %2d) %-24s %s\n" "$((i + 1))" "$SOURCE_NAME" "$SOURCE_ID"
|
||||
done
|
||||
echo
|
||||
echo " a) all sources above"
|
||||
echo " Enter) preset: ${NAMES[0]}"
|
||||
|
||||
read -r -p "Sources [a, 1-${#IDS[@]}, Enter]: " SOURCE_CHOICE
|
||||
|
||||
SELECTED_FLAG=""
|
||||
case "$SOURCE_CHOICE" in
|
||||
"" | "Habbo" | "habbo" | "habbo.com")
|
||||
# Habbo is the first default preset (Habbo (COM)).
|
||||
SELECTED_FLAG="--sources=${IDS[0]}"
|
||||
SOURCE_LABEL="${NAMES[0]}"
|
||||
;;
|
||||
a | A | all)
|
||||
SOURCE_LABEL="all sources"
|
||||
;;
|
||||
*)
|
||||
SELECTED_IDS=()
|
||||
IFS=', ' read -r -a CHOICES <<<"$SOURCE_CHOICE"
|
||||
for CHOICE in "${CHOICES[@]}"; do
|
||||
[ -z "$CHOICE" ] && continue
|
||||
case "$CHOICE" in
|
||||
*[!0-9]* | "")
|
||||
echo "Invalid choice: '$CHOICE'" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
if [ "$CHOICE" -lt 1 ] || [ "$CHOICE" -gt "${#IDS[@]}" ]; then
|
||||
echo "Out of range: $CHOICE" >&2
|
||||
exit 1
|
||||
fi
|
||||
SELECTED_IDS+=("${IDS[$((CHOICE - 1))]}")
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ "${#SELECTED_IDS[@]}" -eq 0 ]; then
|
||||
echo "No sources selected." >&2
|
||||
exit 1
|
||||
fi
|
||||
SELECTED_FLAG="--sources=$(IFS=,; echo "${SELECTED_IDS[*]}")"
|
||||
SOURCE_LABEL="${#SELECTED_IDS[@]} source(s)"
|
||||
;;
|
||||
esac
|
||||
|
||||
# ── Step 2: what may be changed ──────────────────────────────────────────────
|
||||
cat <<EOF
|
||||
|
||||
What should be done? (comparing with: $SOURCE_LABEL)
|
||||
1) Audit only — nothing is written
|
||||
2) Repair furniture icons + nitro bundles
|
||||
3) 2 + FurnitureData.json + catalog structure
|
||||
4) 3 + generate the catalog SQL (saved, not applied)
|
||||
5) 4 + APPLY the catalog SQL to the catalog
|
||||
q) Cancel
|
||||
EOF
|
||||
|
||||
read -r -p "Action [1]: " ACTION_CHOICE
|
||||
ACTION_CHOICE="${ACTION_CHOICE:-1}"
|
||||
|
||||
ACTIONS=(audit)
|
||||
CONFIRM=""
|
||||
# Empty for the audit-only branch on purpose: no repair flags are passed.
|
||||
ACTION_FLAGS=()
|
||||
case "$ACTION_CHOICE" in
|
||||
1)
|
||||
ACTIONS=(audit "[nothing written]")
|
||||
;;
|
||||
2)
|
||||
ACTIONS=(audit "icons + nitro bundles downloaded")
|
||||
ACTION_FLAGS=(--icons --nitros)
|
||||
;;
|
||||
3)
|
||||
ACTIONS=(audit "icons + nitro bundles + FurnitureData.json + structure")
|
||||
ACTION_FLAGS=(--all)
|
||||
;;
|
||||
4)
|
||||
ACTIONS=(audit "everything + catalog SQL generated")
|
||||
ACTION_FLAGS=(--all --sql)
|
||||
;;
|
||||
5)
|
||||
ACTIONS=(audit "everything + catalog SQL APPLIED")
|
||||
ACTION_FLAGS=(--all --sql --apply-sql)
|
||||
CONFIRM="This writes to the catalog. Continue? [y/N]: "
|
||||
;;
|
||||
q | Q)
|
||||
echo "Cancelled."
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Invalid action: '$ACTION_CHOICE'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo
|
||||
printf 'Running: %s against %s\n' "${ACTIONS[1]}" "$SOURCE_LABEL"
|
||||
if [ -n "$CONFIRM" ]; then
|
||||
read -r -p "$CONFIRM" REPLY
|
||||
if [ "$REPLY" != "y" ] && [ "$REPLY" != "Y" ]; then
|
||||
echo "Cancelled."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
# shellcheck disable=SC2086
|
||||
"${RUN[@]}" $SELECTED_FLAG "${ACTION_FLAGS[@]}"
|
||||
Reference in new issue
Block a user