Save and reload a costume
This commit is contained in:
parent
0b0b67e473
commit
77301c9050
6 changed files with 225 additions and 0 deletions
150
costume.py
Executable file
150
costume.py
Executable file
|
|
@ -0,0 +1,150 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import requests
|
||||
|
||||
API_URL = "https://habitica.com/api/v3/user"
|
||||
|
||||
def get_habitica_headers():
|
||||
user_id = os.getenv("HABITICA_USER_ID")
|
||||
api_token = os.getenv("HABITICA_API_TOKEN")
|
||||
|
||||
if not user_id or not api_token:
|
||||
print("Error: Environment variables HABITICA_USER_ID and HABITICA_API_TOKEN must be set.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
return {
|
||||
"x-api-user": user_id,
|
||||
"x-api-key": api_token,
|
||||
"x-client": f"{user_id}-CustomizationScript"
|
||||
}
|
||||
|
||||
def fetch_habitica_gear():
|
||||
"""Fetches only the costume, background, pet, and mount from the user profile."""
|
||||
try:
|
||||
response = requests.get(API_URL, headers=get_habitica_headers())
|
||||
response.raise_for_status()
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"Error communicating with Habitica API: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
data = response.json().get("data", {})
|
||||
|
||||
# Extract specific fields
|
||||
items = data.get("items", {})
|
||||
gear = items.get("gear", {})
|
||||
costume = gear.get("costume", {})
|
||||
background = data.get("preferences", {}).get("background", "default")
|
||||
pet = items.get("currentPet", "")
|
||||
mount = items.get("currentMount", "")
|
||||
|
||||
customizations = {
|
||||
"costume": costume,
|
||||
"background": background,
|
||||
"pet": pet,
|
||||
"mount": mount
|
||||
}
|
||||
|
||||
print(customizations)
|
||||
return customizations
|
||||
|
||||
def save_costume(filename):
|
||||
# print("Fetching equipment and costume data from Habitica...")
|
||||
gear_data = fetch_habitica_gear()
|
||||
with open(filename, "w", encoding="utf-8") as f:
|
||||
json.dump(gear_data, f, indent=4)
|
||||
|
||||
|
||||
def equip(type, name):
|
||||
try:
|
||||
response = requests.post(f"{API_URL}/equip/{type}/{name}",
|
||||
headers=get_habitica_headers())
|
||||
response.raise_for_status()
|
||||
print(f"Successfully equiped '{name}'.")
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"Error communicating with Habitica API: {e}", file=sys.stderr)
|
||||
if hasattr(e, 'response') and e.response is not None:
|
||||
print(f"Server response: {e.response.text}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def set_background(name):
|
||||
bg_payload = {
|
||||
"preferences.background": name
|
||||
}
|
||||
try:
|
||||
res = requests.put(f"{API_URL}",
|
||||
headers=get_habitica_headers(), json=bg_payload)
|
||||
res.raise_for_status()
|
||||
print(f"Successfully set background to: {name}")
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"Error setting background: {e}", file=sys.stderr)
|
||||
if hasattr(e, 'response') and e.response is not None:
|
||||
print(f"Server response: {e.response.text}", file=sys.stderr)
|
||||
|
||||
def set_costume(data):
|
||||
for k,v in data.get("costume").items():
|
||||
if v and not v.endswith("base_0"):
|
||||
equip("costume", v)
|
||||
|
||||
if "pet" in data:
|
||||
equip("pet", data.get("pet"))
|
||||
|
||||
# if "mount" in data:
|
||||
# equip("mount", data.get("mount"))
|
||||
|
||||
# TODO: Not sure how to set the background!
|
||||
if "background" in data:
|
||||
set_background(data["background"])
|
||||
|
||||
def load_costume(filename):
|
||||
if os.path.exists(filename):
|
||||
with open(filename, "r", encoding="utf-8") as f:
|
||||
gear_data = json.load(f)
|
||||
# Update defaults with values from the file
|
||||
set_costume(gear_data)
|
||||
|
||||
def store_all(filename):
|
||||
try:
|
||||
response = requests.get(API_URL, headers=get_habitica_headers())
|
||||
response.raise_for_status()
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"Error communicating with Habitica API: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
data = response.json().get("data", {})
|
||||
with open(filename, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=4)
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description="Costume configuration script")
|
||||
parser.add_argument(
|
||||
"--load",
|
||||
type=str,
|
||||
help="Path to a JSON file containing saved costume values"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--save",
|
||||
type=str,
|
||||
help="Path to a JSON file to save your costume values"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a", "--all",
|
||||
action=argparse.BooleanOptionalAction,
|
||||
help="Download and store all data in 'all.json'"
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
def main():
|
||||
args = parse_arguments()
|
||||
|
||||
if args.save:
|
||||
save_costume(args.save)
|
||||
elif args.load:
|
||||
load_costume(args.load)
|
||||
elif args.all:
|
||||
store_all("all.json")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
15
costumes/autumn_wood_elf.json
Normal file
15
costumes/autumn_wood_elf.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"costume": {
|
||||
"weapon": "weapon_armoire_jeweledArcherBow",
|
||||
"armor": "armor_armoire_woodElfArmor",
|
||||
"head": "head_armoire_woodElfHelm",
|
||||
"shield": "shield_base_0",
|
||||
"back": "back_base_0",
|
||||
"headAccessory": "headAccessory_base_0",
|
||||
"eyewear": "eyewear_special_blackTopFrame",
|
||||
"body": "body_special_summerMage"
|
||||
},
|
||||
"background": "vegetable_garden",
|
||||
"pet": "",
|
||||
"mount": ""
|
||||
}
|
||||
15
costumes/beholder.json
Normal file
15
costumes/beholder.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"costume": {
|
||||
"weapon": "weapon_special_fall2022Healer",
|
||||
"armor": "armor_special_fall2022Healer",
|
||||
"head": "head_special_fall2022Healer",
|
||||
"shield": "shield_special_fall2022Healer",
|
||||
"back": "back_base_0",
|
||||
"headAccessory": "headAccessory_base_0",
|
||||
"eyewear": "eyewear_base_0",
|
||||
"body": "body_base_0"
|
||||
},
|
||||
"background": "magic_door_in_forest",
|
||||
"pet": "",
|
||||
"mount": ""
|
||||
}
|
||||
15
costumes/mystic_forest.json
Normal file
15
costumes/mystic_forest.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"costume": {
|
||||
"weapon": "weapon_special_spring2019Mage",
|
||||
"armor": "armor_special_spring2019Mage",
|
||||
"head": "head_special_spring2019Mage",
|
||||
"shield": "shield_base_0",
|
||||
"back": "back_base_0",
|
||||
"headAccessory": "headAccessory_base_0",
|
||||
"eyewear": "eyewear_special_redHalfMoon",
|
||||
"body": "body_base_0"
|
||||
},
|
||||
"background": "magic_door_in_forest",
|
||||
"pet": "",
|
||||
"mount": ""
|
||||
}
|
||||
15
costumes/on_the_streets.json
Normal file
15
costumes/on_the_streets.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"costume": {
|
||||
"weapon": "weapon_mystery_301404",
|
||||
"armor": "armor_armoire_plagueDoctorOvercoat",
|
||||
"head": "head_mystery_301405",
|
||||
"shield": "shield_base_0",
|
||||
"back": "back_base_0",
|
||||
"headAccessory": "headAccessory_base_0",
|
||||
"eyewear": "eyewear_special_blackTopFrame",
|
||||
"body": "body_armoire_cozyScarf"
|
||||
},
|
||||
"background": "sunny_street_with_shops",
|
||||
"pet": "Gryphon-Base",
|
||||
"mount": ""
|
||||
}
|
||||
15
costumes/the_reader.json
Normal file
15
costumes/the_reader.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"costume": {
|
||||
"weapon": "weapon_base_0",
|
||||
"armor": "armor_wizard_3",
|
||||
"head": "head_base_0",
|
||||
"shield": "shield_mystery_201709",
|
||||
"back": "back_mystery_201709",
|
||||
"headAccessory": "headAccessory_base_0",
|
||||
"eyewear": "eyewear_special_blackHalfMoon",
|
||||
"body": "body_special_summerMage"
|
||||
},
|
||||
"background": "cozy_library",
|
||||
"pet": "",
|
||||
"mount": ""
|
||||
}
|
||||
Loading…
Reference in a new issue