Initial Release of IGNCore version 2.5
This commit is contained in:
@@ -0,0 +1,291 @@
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
|
||||
from core.chat_blob import ChatBlob
|
||||
from core.command_param_types import Any, Int, NamedParameters
|
||||
from core.decorators import instance, command
|
||||
from core.logger import Logger
|
||||
|
||||
|
||||
@instance()
|
||||
class RecipeController:
|
||||
def __init__(self):
|
||||
self.logger = Logger(__name__)
|
||||
|
||||
self.recipe_name_regex = re.compile(r"(\d+)\.(txt|json)")
|
||||
self.recipe_item_regex = re.compile(r"#L \"([^\"]+)\" \"([\d+]+)\"")
|
||||
self.recipe_link_regex = re.compile(r"#L \"([^\"]+)\" \"([^\"]+)\"")
|
||||
|
||||
def inject(self, registry):
|
||||
self.db = registry.get_instance("db")
|
||||
self.text = registry.get_instance("text")
|
||||
self.items_controller = registry.get_instance("items_controller")
|
||||
self.command_alias_service = registry.get_instance("command_alias_service")
|
||||
|
||||
def start(self):
|
||||
self.command_alias_service.add_alias("r", "recipe")
|
||||
self.command_alias_service.add_alias("tradeskill", "recipe")
|
||||
|
||||
self.db.exec("CREATE TABLE IF NOT EXISTS recipe ("
|
||||
"id INT NOT NULL PRIMARY KEY, "
|
||||
"name VARCHAR(50) NOT NULL, "
|
||||
"author VARCHAR(50) NOT NULL, "
|
||||
"recipe TEXT NOT NULL, "
|
||||
"dt INT NOT NULL DEFAULT 0)")
|
||||
self.db.create_view("recipe")
|
||||
recipe_dir = os.path.dirname(os.path.realpath(__file__)) + "/recipes/"
|
||||
recipes = self.db.query("SELECT id, dt FROM recipe")
|
||||
|
||||
for file in os.listdir(recipe_dir):
|
||||
if file.startswith("_"):
|
||||
continue
|
||||
|
||||
m = self.recipe_name_regex.match(file)
|
||||
if m:
|
||||
recipe_id = m.group(1)
|
||||
file_type = m.group(2)
|
||||
dt = int(os.path.getmtime(recipe_dir + file))
|
||||
|
||||
recipe = self.find_recipe(recipe_id, recipes)
|
||||
if recipe:
|
||||
recipes.remove(recipe)
|
||||
if recipe.dt == dt:
|
||||
continue
|
||||
|
||||
self.update_recipe(recipe_dir, recipe_id, file_type, dt)
|
||||
else:
|
||||
raise Exception(f"Unknown recipe format for '{file}'")
|
||||
|
||||
@command(command="recipe", params=[Int("recipe_id")], access_level="member", description="Show a recipe")
|
||||
def recipe_show_cmd(self, _, recipe_id):
|
||||
recipe = self.get_recipe(recipe_id)
|
||||
if not recipe:
|
||||
return f"Could not find recipe with ID <highlight>{recipe_id:d}</highlight>."
|
||||
|
||||
return self.format_recipe(recipe)
|
||||
|
||||
@command(command="recipe",
|
||||
params=[Any("search"), NamedParameters(["page"])],
|
||||
access_level="member",
|
||||
description="Search for a recipe")
|
||||
def recipe_search_cmd(self, _, search, named_params):
|
||||
page = int(named_params.page or "1")
|
||||
page_size = 30
|
||||
offset = (page - 1) * page_size
|
||||
search = self.text.strip_html_tags(search)
|
||||
data = self.db.query("SELECT * FROM recipe "
|
||||
"WHERE name LIKE ? "
|
||||
"or recipe LIKE ? "
|
||||
"ORDER BY name",
|
||||
[f"%{search}%", f"%{search}%"])
|
||||
count = len(data)
|
||||
paged_data = data[offset:offset + page_size]
|
||||
if count == 1:
|
||||
return self.format_recipe(data[0])
|
||||
blob = ""
|
||||
|
||||
if count > page_size:
|
||||
if page > 1 and len(paged_data) > 0:
|
||||
blob += " " + self.text.make_chatcmd(f"«« Page {page - 1:d}", self.get_chat_command(search, page - 1))
|
||||
if offset + page_size < len(data):
|
||||
blob += " Page " + str(page)
|
||||
blob += " " + self.text.make_chatcmd(f"Page {page + 1:d} »»", self.get_chat_command(search, page + 1))
|
||||
blob += "\n\n"
|
||||
|
||||
for row in paged_data:
|
||||
blob += self.text.make_tellcmd(row.name, f"recipe {row.id:d}") + "\n"
|
||||
|
||||
return ChatBlob(
|
||||
f"Recipes Matching '{search}' ({offset + 1:d} - {min(offset + page_size, count):d} of {count:d})", blob)
|
||||
|
||||
def get_recipe(self, recipe_id):
|
||||
return self.db.query_single("SELECT * FROM recipe WHERE id = ?", [recipe_id])
|
||||
|
||||
def format_recipe(self, recipe):
|
||||
blob = f"Recipe ID: <highlight>{recipe.id:d}</highlight>\n"
|
||||
blob += f"Author: <highlight>{recipe.author or 'Unknown'}</highlight>\n\n"
|
||||
blob += self.format_recipe_text(recipe.recipe)
|
||||
|
||||
return ChatBlob(f"Recipe for '{recipe.name}'", blob)
|
||||
|
||||
def format_recipe_text(self, recipe_text):
|
||||
recipe_text = recipe_text.replace("\\n", "\n")
|
||||
recipe_text = self.recipe_item_regex.sub(self.lookup_item, recipe_text)
|
||||
recipe_text = self.recipe_link_regex.sub("<a href='chatcmd://\\2'>\\1</a>", recipe_text)
|
||||
return recipe_text
|
||||
|
||||
def lookup_item(self, m):
|
||||
name = m.group(1)
|
||||
item_id = m.group(2)
|
||||
|
||||
item = self.items_controller.get_by_item_id(item_id)
|
||||
if item:
|
||||
return self.text.make_item(item.lowid, item.highid, item.highql, item.name)
|
||||
else:
|
||||
return name
|
||||
|
||||
def get_chat_command(self, search, page):
|
||||
return f"/tell <myname> recipe {search} --page={page:d}"
|
||||
|
||||
def find_recipe(self, recipe_id, recipes):
|
||||
for row in recipes:
|
||||
if str(row.id) == recipe_id:
|
||||
return row
|
||||
return None
|
||||
|
||||
def update_recipe(self, recipe_dir, recipe_id, _, dt):
|
||||
with open(recipe_dir + recipe_id + ".json", mode="r", encoding="UTF-8") as f:
|
||||
recipe = json.load(f)
|
||||
|
||||
name = recipe["name"]
|
||||
author = recipe["author"]
|
||||
|
||||
if "raw" in recipe:
|
||||
content = recipe["raw"]
|
||||
else:
|
||||
content = self.format_json_recipe(recipe_id, recipe)
|
||||
self.db.exec("REPLACE INTO recipe (id, name, author, recipe, dt) "
|
||||
"VALUES (?, ?, ?, ?, ?)",
|
||||
[recipe_id, name, author, content, dt])
|
||||
|
||||
def format_json_recipe(self, recipe_id, recipe):
|
||||
items = {}
|
||||
for i in recipe["items"]:
|
||||
item = self.items_controller.get_by_item_id(i["item_id"], i.get("ql"))
|
||||
if not item:
|
||||
raise Exception(f"Could not find recipe item '{i['item_id']:d}' for recipe id {recipe_id}")
|
||||
|
||||
item.ql = i.get("ql") or (item.highql if i["item_id"] == item.highid else item.lowql)
|
||||
items[i["alias"]] = item
|
||||
|
||||
content = ""
|
||||
|
||||
ingredients = items.copy()
|
||||
for step in recipe["steps"]:
|
||||
del ingredients[step["result"]]
|
||||
|
||||
content += self.format_ingredients(ingredients.items())
|
||||
content += "\n"
|
||||
content += self.format_steps(items, recipe["steps"])
|
||||
|
||||
if "details" in recipe:
|
||||
content += self.format_details(recipe["details"])
|
||||
|
||||
return content
|
||||
|
||||
def format_ingredients(self, ingredients):
|
||||
content = "<font color=#FFFF00>------------------------------</font>\n"
|
||||
content += "<font color=#FF0000>Ingredients</font>\n"
|
||||
content += "<font color=#FFFF00>------------------------------</font>\n\n"
|
||||
|
||||
for _, ingredient in ingredients:
|
||||
content += self.text.make_image(ingredient["icon"]) + "<tab>"
|
||||
content += self.text.make_item(ingredient["lowid"], ingredient["highid"], ingredient["ql"],
|
||||
ingredient["name"]) + "\n"
|
||||
|
||||
return content
|
||||
|
||||
def format_steps(self, items, steps):
|
||||
content = ""
|
||||
content += "<font color=#FFFF00>------------------------------</font>\n"
|
||||
content += "<font color=#FF0000>Recipe</font>\n"
|
||||
content += "<font color=#FFFF00>------------------------------</font>\n\n"
|
||||
|
||||
for step in steps:
|
||||
source = items[step["source"]]
|
||||
target = items[step["target"]]
|
||||
result = items[step["result"]]
|
||||
content += f"<a href='itemref://{source['lowid']:d}/{source['highid']:d}/{source['ql']:d}'>" \
|
||||
f"{self.text.make_image(source['icon'])}</a>" + ""
|
||||
content += "<font color=#FFFFFF><tab>+<tab></font> "
|
||||
content += f"<a href='itemref://{target['lowid']:d}/{target['highid']:d}/{target['ql']:d}'>" \
|
||||
f"{self.text.make_image(target['icon'])}</a>" + ""
|
||||
content += "<font color=#FFFFFF><tab>=<tab></font> "
|
||||
content += f"<a href='itemref://{result['lowid']:d}/{result['highid']:d}/{result['ql']:d}'>" \
|
||||
f"{self.text.make_image(result['icon'])}</a>"
|
||||
content += "\n<tab><tab>" + self.text.make_item(source["lowid"],
|
||||
source["highid"], source["ql"], source["name"])
|
||||
content += "\n + <tab>" + self.text.make_item(target["lowid"],
|
||||
target["highid"], target["ql"], target["name"])
|
||||
content += "\n = <tab>" + self.text.make_item(result["lowid"],
|
||||
result["highid"], result["ql"], result["name"]) + "\n"
|
||||
|
||||
if "skills" in step:
|
||||
content += f"<font color=#FFFF00>Skills: | {step['skills']} |</font>\n"
|
||||
content += "\n\n"
|
||||
|
||||
return content
|
||||
|
||||
def format_details(self, details):
|
||||
content = ""
|
||||
content += "<font color=#FFFF00>------------------------------</font>\n"
|
||||
content += "<font color=#FF0000>Details</font>\n"
|
||||
content += "<font color=#FFFF00>------------------------------</font>\n\n"
|
||||
|
||||
last_type = ""
|
||||
for detail in details:
|
||||
if "item" in detail:
|
||||
last_type = "item"
|
||||
i = detail["item"]
|
||||
|
||||
if "ql" in i:
|
||||
item = self.items_controller.get_by_item_id(i["id"], i["ql"])
|
||||
else:
|
||||
item = self.items_controller.get_by_item_id(i["id"])
|
||||
item["ql"] = item["highql"]
|
||||
|
||||
content += "<font color=#009B00>%s</font>" % \
|
||||
self.text.make_item(item['lowid'],
|
||||
item['highid'],
|
||||
item['ql'],
|
||||
item['name'])
|
||||
|
||||
if "comment" in i:
|
||||
content += " - " + i["comment"]
|
||||
|
||||
content += "\n"
|
||||
|
||||
elif "text" in detail:
|
||||
if last_type == "item":
|
||||
content += "\n"
|
||||
|
||||
last_type = "text"
|
||||
content += f"<font color=#FFFFFF>{detail['text']}</font>\n"
|
||||
|
||||
return content
|
||||
|
||||
def convert_to_json(self, recipe_dir, recipe_id, file):
|
||||
with open(recipe_dir + file, mode="r", encoding="UTF-8") as f:
|
||||
lines = f.readlines()
|
||||
|
||||
recipe = {
|
||||
"name": lines.pop(0).strip()[6:],
|
||||
"author": lines.pop(0).strip()[8:],
|
||||
"items": list(),
|
||||
"steps": list(),
|
||||
"details": list(),
|
||||
"raw": None
|
||||
}
|
||||
|
||||
content = "".join(lines)
|
||||
items = {}
|
||||
|
||||
matches = self.recipe_item_regex.findall(content)
|
||||
for item_name, item_id in matches:
|
||||
item = self.items_controller.get_by_item_id(item_id)
|
||||
if not item:
|
||||
self.logger.warning(f"Could not find recipe item '{item_id} - {item_name}' for recipe id {recipe_id}")
|
||||
else:
|
||||
items[item.highid] = {"alias": item.name, "item_id": item.highid}
|
||||
|
||||
recipe["items"].extend(items.values())
|
||||
recipe["raw"] = content
|
||||
|
||||
with open(recipe_dir + recipe_id + ".json", mode="w", encoding="UTF-8") as f:
|
||||
f.write(json.dumps(recipe, indent=4))
|
||||
|
||||
# delete file
|
||||
os.remove(recipe_dir + file)
|
||||
|
||||
return True
|
||||
Reference in New Issue
Block a user