mirror of
https://github.com/seanbetts/steam-hardware-watch.git
synced 2026-10-06 01:00:18 +02:00
165 lines
5.5 KiB
Bash
Executable File
165 lines
5.5 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
|
|
if [ "$#" -lt 1 ]; then
|
|
echo "usage: $0 RUN_DIR" >&2
|
|
exit 1
|
|
fi
|
|
|
|
RUN_DIR="$1"
|
|
OUT_DIR="$RUN_DIR/api/valve"
|
|
REPORT_DIR="$RUN_DIR/reports"
|
|
mkdir -p "$OUT_DIR" "$REPORT_DIR"
|
|
|
|
ERROR_FILE="$REPORT_DIR/valve-errors.txt"
|
|
: > "$ERROR_FILE"
|
|
: > "$REPORT_DIR/valve-key-lines.txt"
|
|
: > "$REPORT_DIR/valve-reservation-packages.tsv"
|
|
|
|
fetch_page() {
|
|
name="$1"
|
|
url="$2"
|
|
if ! curl -A 'Mozilla/5.0' --retry 2 --retry-delay 2 --max-time 45 -fsSL "$url" > "$OUT_DIR/$name.html" 2>/dev/null; then
|
|
printf '%s\n' "failed to fetch $url" >> "$ERROR_FILE"
|
|
rm -f "$OUT_DIR/$name.html"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
fetch_json() {
|
|
name="$1"
|
|
url="$2"
|
|
if ! curl -A 'Mozilla/5.0' --retry 2 --retry-delay 2 --max-time 45 -fsSL "$url" > "$OUT_DIR/$name.json" 2>/dev/null; then
|
|
printf '%s\n' "failed to fetch $url" >> "$ERROR_FILE"
|
|
rm -f "$OUT_DIR/$name.json"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
fetch_page "steamdeck-site" "https://www.steamdeck.com/" || true
|
|
fetch_page "steam-support-deck" "https://help.steampowered.com/en/wizard/HelpWithSteamDeck" || true
|
|
fetch_page "steam-controller-store" "https://store.steampowered.com/app/4165870/" || true
|
|
fetch_page "steam-hardware-root" "https://steampowered.com/hardware" || true
|
|
|
|
for appid in 4165870 4165890 4165910; do
|
|
fetch_json "appdetails-$appid-us" "https://store.steampowered.com/api/appdetails?appids=$appid&cc=us&l=en" || true
|
|
done
|
|
|
|
for packageid in 1558609 1629446 1629447 1629458 1629460 1629484 1629486; do
|
|
fetch_json "packagedetails-$packageid-us" "https://store.steampowered.com/api/packagedetails?packageids=$packageid&cc=us&l=en" || true
|
|
done
|
|
|
|
python3 - "$OUT_DIR" "$REPORT_DIR/valve-reservation-packages.tsv" <<'PY'
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
out_dir = Path(sys.argv[1])
|
|
report_path = Path(sys.argv[2])
|
|
|
|
apps = {
|
|
"4165870": "Steam Controller",
|
|
"4165890": "Steam Frame",
|
|
"4165910": "Steam Machine",
|
|
}
|
|
packages = {
|
|
"1558609": "Steam Controller",
|
|
"1629446": "Steam Machine",
|
|
"1629447": "Steam Machine",
|
|
"1629458": "Steam Machine",
|
|
"1629460": "Steam Machine",
|
|
"1629484": "Steam Frame",
|
|
"1629486": "Steam Frame",
|
|
}
|
|
|
|
|
|
def clean(value):
|
|
if value is None:
|
|
return ""
|
|
return str(value).replace("\t", " ").replace("\n", " ").strip()
|
|
|
|
|
|
def read_json(path):
|
|
if not path.exists():
|
|
return None, "missing"
|
|
try:
|
|
return json.loads(path.read_text(encoding="utf-8")), ""
|
|
except Exception as exc:
|
|
return None, f"invalid json: {exc}"
|
|
|
|
|
|
rows = [["type", "product", "id", "status", "name", "release_or_price", "details"]]
|
|
|
|
for appid, product in apps.items():
|
|
payload, error = read_json(out_dir / f"appdetails-{appid}-us.json")
|
|
entry = payload.get(appid, {}) if isinstance(payload, dict) else {}
|
|
success = entry.get("success") is True
|
|
data = entry.get("data") if isinstance(entry.get("data"), dict) else {}
|
|
status = "public" if success else "unavailable"
|
|
if error:
|
|
status = error
|
|
name = data.get("name", "")
|
|
price = ""
|
|
price_overview = data.get("price_overview")
|
|
if isinstance(price_overview, dict):
|
|
price = price_overview.get("final_formatted", "")
|
|
release_date = data.get("release_date")
|
|
release_or_price = price
|
|
coming_soon = ""
|
|
if isinstance(release_date, dict):
|
|
release_or_price = release_or_price or release_date.get("date", "")
|
|
coming_soon = release_date.get("coming_soon", "")
|
|
package_ids = data.get("packages") if isinstance(data.get("packages"), list) else []
|
|
package_groups = data.get("package_groups") if isinstance(data.get("package_groups"), list) else []
|
|
details = (
|
|
f"packages={','.join(str(package_id) for package_id in package_ids)}; "
|
|
f"package_groups={len(package_groups)}; "
|
|
f"coming_soon={coming_soon}; "
|
|
f"price={price}"
|
|
)
|
|
rows.append(["app", product, appid, status, name, release_or_price, details])
|
|
|
|
for packageid, product in packages.items():
|
|
payload, error = read_json(out_dir / f"packagedetails-{packageid}-us.json")
|
|
entry = payload.get(packageid, {}) if isinstance(payload, dict) else {}
|
|
success = entry.get("success") is True
|
|
status = "public" if success else "private"
|
|
if error:
|
|
status = error
|
|
data = entry.get("data") if isinstance(entry.get("data"), dict) else {}
|
|
name = data.get("name", "")
|
|
price = ""
|
|
package_price = data.get("price")
|
|
if isinstance(package_price, dict):
|
|
price = package_price.get("final_formatted", "")
|
|
apps_detail = []
|
|
for app in data.get("apps", []) if isinstance(data.get("apps"), list) else []:
|
|
if isinstance(app, dict):
|
|
app_id = app.get("id", "")
|
|
app_name = app.get("name", "")
|
|
apps_detail.append(f"{app_id}:{app_name}")
|
|
details = f"apps={','.join(apps_detail)}" if success else "packagedetails success:false"
|
|
rows.append(["package", product, packageid, status, name, price, details])
|
|
|
|
report_path.write_text(
|
|
"\n".join("\t".join(clean(value) for value in row) for row in rows) + "\n",
|
|
encoding="utf-8",
|
|
)
|
|
PY
|
|
|
|
{
|
|
printf '%s\n' "Reservation package API snapshot:"
|
|
sed -n '1,40p' "$REPORT_DIR/valve-reservation-packages.tsv"
|
|
printf '\n%s\n' "HTML key matches:"
|
|
} > "$REPORT_DIR/valve-key-lines.txt"
|
|
|
|
rg -n -o -g '*.html' "Steam Controller|Steam Machine|Steam Frame|coming soon|manual|safety|warranty|preorder|release" \
|
|
"$OUT_DIR" | sort -u \
|
|
>> "$REPORT_DIR/valve-key-lines.txt" || true
|
|
|
|
printf '%s\n' \
|
|
"Saved Valve pages to $OUT_DIR" \
|
|
"Saved matching lines to $REPORT_DIR/valve-key-lines.txt" \
|
|
"Saved reservation package report to $REPORT_DIR/valve-reservation-packages.tsv"
|