From 2ee12261375931621bddee6035300054c9a7b9fa Mon Sep 17 00:00:00 2001 From: Lithiil <97366add6d29a582656459e3c16582d268d2739c> Date: Wed, 1 Apr 2020 20:44:12 +0300 Subject: [PATCH] first commit --- .env_example | 3 + .gitignore | 1 + Generator.py | 158 ++++++++++++++++++++++++++++++++++++++++ README.md | 39 ++++++++++ data/appearance.json | 6 ++ data/personalities.json | 4 + data/titles.json | 3 + example.py | 5 ++ requirements.txt | 2 + 9 files changed, 221 insertions(+) create mode 100644 .env_example create mode 100644 .gitignore create mode 100644 Generator.py create mode 100644 README.md create mode 100644 data/appearance.json create mode 100644 data/personalities.json create mode 100644 data/titles.json create mode 100644 example.py create mode 100644 requirements.txt diff --git a/.env_example b/.env_example new file mode 100644 index 0000000..574479f --- /dev/null +++ b/.env_example @@ -0,0 +1,3 @@ +APITOKEN = "Bearer your_api_key_here" +DATA_PATH = "data/" +API_URL = 'https://kanka.io/api/1.0/' \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env diff --git a/Generator.py b/Generator.py new file mode 100644 index 0000000..0128f94 --- /dev/null +++ b/Generator.py @@ -0,0 +1,158 @@ +import os +import requests +from dotenv import load_dotenv +import json +import sys +import random + + +class NpcGenerator: + """ + This class is made to create random NPCs into a specific kanka campaign + """ + + apiToken = None + apiBaseUrl = None + headers = None + campaign_id = None + dataPath = None + + """ + When instancing the class, the variables from the .env files are loaded and the following class variables are set: + apiToken, dataPath, apiBaseUrl and headers + """ + + def __init__(self): + + load_dotenv() + + self.apiToken = os.getenv("APITOKEN") + self.dataPath = os.getenv("DATA_PATH") + self.apiBaseUrl = os.getenv("API_URL") + self.headers = { + 'Authorization': self.apiToken, + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + + def get_campaigns(self): + """ + This method will get a list of all the campaigns created on the account belonging to the owner of the Token + via a HTTP get request and returns a JSON + :return: JSON + """ + campaigns = requests.get("{}campaigns".format(self.apiBaseUrl), headers=self.headers) + return json.loads(campaigns.content) + + def set_campaign_id(self, campaign_name): + """ + This method will parse the JSON generated by get_campaigns and set the campaignId with the id of the campaign + specified in the campaign_name parameter. If no campaign can be found with that name, it will raise an error + :type campaign_name: str + """ + campaigns = self.get_campaigns() + + for campaign in campaigns['data']: + if campaign['name'] == campaign_name: + print("Found the campaign that you are looking for with id:{}".format(campaign['id'])) + self.campaign_id = campaign['id'] + + if self.campaign_id is None: + sys.exit("ERROR: No campaign with that name found!") + + def load_charater_details(self): + """ + This method will load the three specified files from the location specified in dataPath and returns a dict + containing json objects + @:returns data: dict + """ + appearance_options = json.load(open('{}appearance.json'.format(self.dataPath))) + personality_options = json.load(open('{}personalities.json'.format(self.dataPath))) + title_options = json.load(open('{}titles.json'.format(self.dataPath))) + + data = { + 'appearance_options': appearance_options, + 'personality_options': personality_options, + 'title_options': title_options + } + + return data + + def genrate_npc_name(self, sex): + """ + Will get a name via http request from drycodes.com based on the sex specified + :type sex: str + :return name: str + """ + if sex is "Male": + get_male_name = requests.get( + 'http://names.drycodes.com/1?nameOptions=boy_names&format=text&separator=space') + name = get_male_name.text + else: + get_female_name = requests.get( + 'http://names.drycodes.com/1?nameOptions=girl_names&format=text&separator=space') + name = get_female_name.text + + return name + + def generate_npcs(self, times): + """ + Will generate a list of dicts, each dict representing a character. The character details are populated + from the data retrieved by load_character_details. The number of characters is decided by the times parameter + :type times: int + :return npcs: list + """ + npcs = [] + + data = self.load_charater_details() + + for x in range(times): + sex = random.choice(['Male', 'Female']) + name = self.genrate_npc_name(sex) + + character = { + 'name': name, + 'title': random.choice(data['title_options']['data']), + 'age': str(random.randrange(14, 100)), + 'sex': sex, + 'type': 'random_npc', + 'is_private': 'true', + 'personality_name': ['Goals', 'Fears'], + 'personality_entry': [random.choice(data['personality_options']['goals']), + random.choice(data['personality_options']['fears'])], + 'appearance_name': ['Hair', 'Eyes', 'Height', 'Marks'], + 'appearance_entry': [random.choice(data['appearance_options']['hair_type']), + random.choice(data['appearance_options']['eyes']), + str(round(random.uniform(4.1, 7.5), 1)) + " feet", + random.choice(data['appearance_options']['marks'])] + } + + npcs.append(character) + + return npcs + + def create_npcs(self, campaign_name=str, times=1): + """ + Will search for the specified campaign, generate the npcs and then create then on kanka via http post requests. + Please note that kanka has a limit of 30 calls per minute at this time + :type times: int + :type campaign_name: str + """ + self.set_campaign_id(campaign_name) + + npcs = self.generate_npcs(times) + + for npc in npcs: + + print('Posting character to kanka') + response = requests.post( + "{}campaigns/{}/characters".format(self.apiBaseUrl, self.campaign_id), + data=json.dumps(npc), + headers=self.headers) + + if response.status_code is 201: + print("Character named {} was created successfully!".format(npc['name'])) + else: + print( + "Character was not created because kanka threw an error, got status code {} with error {} ".format( + response.status_code, response.text)) diff --git a/README.md b/README.md new file mode 100644 index 0000000..a3f1edb --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# **Kanka Random NPC Creator** + +Hi, and thanks for taking the time to checkout this small project! + +This mini project basically allows you to create as many random npcs +as you want in your kanka campaign. + +# Setup: +1. [Install python 3.x](https://wiki.python.org/moin/BeginnersGuide/Download) +2. `pip install requirement.txt` +3. Create a Personal Access Token on your kanka account as described [here](https://kanka.io/en-US/docs/1.0/setup) +4. Create a .env file based on the .env_example . The only env variable that you will +probably want to modify is the *APITOKEN* +5. Create a python script that uses the Generator class as shown in the example.py +file + +Below is an example of how to create 5 random NPCs in the campaign called "My Cool Campaign": + +```python +from Generator import NpcGenerator + +gen = NpcGenerator() + +gen.create_npcs('My Cool Campaign', 5) +``` + +The characters created by this script have the "random_npc" type. So that +you can filter them out easily. + +The names for the NPCs are requested from names.drycodes.com while the +other details are randomly chosen from the JSONs found in the data folder. + +Feel free to add stuff to them OR use your own JSONs by pointing the DATA_PATH +env variable to their location (make sure that they are named like the ones +in the data folder tho!). + +If by any chance you want to update and/or enrich the existing JSONs, create a PR. + +Have a great time! \ No newline at end of file diff --git a/data/appearance.json b/data/appearance.json new file mode 100644 index 0000000..44b61d5 --- /dev/null +++ b/data/appearance.json @@ -0,0 +1,6 @@ +{ + "hair_type": ["straight", "wavy", "curly"], + "hair_color": ["brown", "white", "blond", "red", "black"], + "eyes": ["hazel", "blue", "green", "brown"], + "marks": ["Left cheek scar", "None", "Missing middle finger on right hand"] +} \ No newline at end of file diff --git a/data/personalities.json b/data/personalities.json new file mode 100644 index 0000000..c4f349d --- /dev/null +++ b/data/personalities.json @@ -0,0 +1,4 @@ +{ + "goals": ["To become King", "To slay a dragon"], + "fears": ["Cake","Spiders","Blue Eyes"] +} \ No newline at end of file diff --git a/data/titles.json b/data/titles.json new file mode 100644 index 0000000..6dcf9c9 --- /dev/null +++ b/data/titles.json @@ -0,0 +1,3 @@ +{ + "data":["The Noble", "The Peasant", "The Great", "The Dark", "The White", "The Strong"] +} \ No newline at end of file diff --git a/example.py b/example.py new file mode 100644 index 0000000..81aa6e2 --- /dev/null +++ b/example.py @@ -0,0 +1,5 @@ +from Generator import NpcGenerator + +gen = NpcGenerator() + +gen.create_npcs('Warhammer Fantasy', 5) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1c49fe1 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +python-dotenv==0.12.0 +requests==2.23.0