commit 32964d1d1f2df72abb3af05546ad4c0bc20b8c81 Author: archon0ne Date: Wed Jul 3 11:11:14 2024 +0200 first commit diff --git a/app.py b/app.py new file mode 100644 index 0000000..6204a3d --- /dev/null +++ b/app.py @@ -0,0 +1,227 @@ +from flask import Flask, render_template, request, redirect, url_for, jsonify +import json +import requests +import logging +import os +import traceback + +app = Flask(__name__) + +# Setup logging to file +logging.basicConfig(filename='log.log', level=logging.DEBUG, format='%(asctime)s %(levelname)s:%(message)s') + +# Load the assort data +ASSORT_FILE_PATH = 'assort.json' +QUEST_ASSORT_FILE_PATH = 'questassort.json' +CACHE_FILE_PATH = 'item_cache.json' +RUBLE_TPL_ID = '5449016a4bdc2d6f028b456f' + +try: + with open(ASSORT_FILE_PATH) as f: + assort_data = json.load(f) + logging.debug("Assort data loaded successfully") +except Exception as e: + logging.error(f"Error loading assort data: {e}") + logging.error(traceback.format_exc()) + +try: + with open(QUEST_ASSORT_FILE_PATH) as f: + quest_assort_data = json.load(f) + logging.debug("Quest assort data loaded successfully") +except Exception as e: + logging.error(f"Error loading quest assort data: {e}") + logging.error(traceback.format_exc()) + +# Load cache or initialize an empty dictionary +if os.path.exists(CACHE_FILE_PATH): + try: + with open(CACHE_FILE_PATH) as f: + item_cache = json.load(f) + logging.debug("Item cache loaded successfully") + except Exception as e: + logging.error(f"Error loading item cache: {e}") + logging.error(traceback.format_exc()) + item_cache = {} +else: + item_cache = {} + logging.debug("Initialized empty item cache") + +# Tarkov.dev API URL +TARKOV_API_URL = "https://api.tarkov.dev/graphql" + +def get_ruble_image(): + return get_item_details_cached(RUBLE_TPL_ID) + +@app.route('/') +def index(): + try: + items = get_main_items_with_details(assort_data) + ruble_image = get_ruble_image() + return render_template('index.html', items=items, ruble_image=ruble_image) + except Exception as e: + logging.error(f"Error in index route: {e}") + logging.error(traceback.format_exc()) + return "Error loading items", 500 + +def get_main_items_with_details(assort_data): + items = [] + for item in assort_data['items']: + if item['parentId'] == 'hideout': + item_copy = item.copy() # Create a copy of the item to avoid modifying the original + item_copy['details'] = get_item_details_cached(item_copy['_tpl']) + item_copy['parts'] = get_item_parts_with_details(item_copy['_id'], assort_data) + item_copy['barter_scheme'] = get_barter_scheme_with_details(item_copy['_id'], assort_data) + item_copy['quest_requirement'] = get_quest_requirement(item_copy['_id']) + item_copy['offer_name'] = item_copy['_id'] # Add offer name + items.append(item_copy) + logging.debug(f"Main items with details: {items}") + return items + +def get_item_details_cached(tpl): + if tpl in item_cache: + logging.debug(f"Cache hit for tpl {tpl}") + return item_cache[tpl] + else: + logging.debug(f"Cache miss for tpl {tpl}, fetching from API") + item_details = get_items_details([tpl]) + if tpl in item_details: + item_cache[tpl] = item_details[tpl] + save_item_cache() + return item_details.get(tpl, {}) + +def get_items_details(tpls): + queries = "\n".join([ + f'item{index}: item(id: "{tpl}") {{ id name shortName description basePrice image512pxLink wikiLink }}' + for index, tpl in enumerate(tpls) + ]) + query = f"{{ {queries} }}" + try: + response = requests.post(TARKOV_API_URL, json={'query': query}) + data = response.json() + logging.debug(f"Item details for tpls {tpls}: {data}") + return {tpl: data['data'][f'item{index}'] for index, tpl in enumerate(tpls)} + except Exception as e: + logging.error(f"Error fetching item details for tpls {tpls}: {e}") + logging.error(traceback.format_exc()) + return {} + +def get_item_parts_with_details(parent_id, assort_data): + parts = [] + def fetch_parts(parent_id): + sub_parts = [] + for item in assort_data['items']: + if item['parentId'] == parent_id: + part_copy = item.copy() # Create a copy of the part to avoid modifying the original + part_copy['details'] = get_item_details_cached(part_copy['_tpl']) + part_copy['parts'] = fetch_parts(part_copy['_id']) # Fetch sub-parts recursively + sub_parts.append(part_copy) + return sub_parts + parts = fetch_parts(parent_id) + logging.debug(f"Parts for parent_id {parent_id}: {parts}") + return parts + +def get_barter_scheme_with_details(item_id, assort_data): + barter_scheme = [] + if 'barter_scheme' in assort_data: + for scheme in assort_data['barter_scheme'].get(item_id, []): + scheme_details = [] + for req in scheme: + req_copy = req.copy() # Create a copy of the req to avoid modifying the original + req_details = get_item_details_cached(req_copy['_tpl']) + req_copy['details'] = req_details + scheme_details.append(req_copy) + barter_scheme.append(scheme_details) + logging.debug(f"Barter scheme for item_id {item_id}: {barter_scheme}") + return barter_scheme + +def get_quest_requirement(item_id): + for quest_type, quests in quest_assort_data.items(): + if item_id in quests: + return { + "type": quest_type, + "quest": quests[item_id] + } + return None + +@app.route('/edit/', methods=['GET', 'POST']) +def edit_item(item_id): + try: + if request.method == 'POST': + # Handle form submission + new_barter_scheme = [] + tpl_list = request.form.getlist('barter_tpl') + count_list = request.form.getlist('barter_count') + scheme = [] + for i in range(len(tpl_list)): + scheme.append({ + '_tpl': tpl_list[i], + 'count': int(count_list[i]) + }) + new_barter_scheme.append(scheme) + update_barter_scheme(item_id, new_barter_scheme) + return redirect(url_for('index')) + + item = next((item for item in assort_data['items'] if item['_id'] == item_id), None) + if item: + item_copy = item.copy() # Create a copy of the item to avoid modifying the original + item_copy['details'] = get_item_details_cached(item_copy['_tpl']) + item_copy['parts'] = get_item_parts_with_details(item_id, assort_data) + item_copy['barter_scheme'] = get_barter_scheme_with_details(item_id, assort_data) + item_copy['quest_requirement'] = get_quest_requirement(item_id) + ruble_image = get_ruble_image() + return render_template('edit.html', item=item_copy, ruble_image=ruble_image) + else: + return "Item not found", 404 + except Exception as e: + logging.error(f"Error in edit_item route: {e}") + logging.error(traceback.format_exc()) + return "Error editing item", 500 + +def update_barter_scheme(item_id, new_barter_scheme): + try: + assort_data['barter_scheme'][item_id] = new_barter_scheme + save_assort_data() + except Exception as e: + logging.error(f"Error updating barter scheme for item {item_id}: {e}") + logging.error(traceback.format_exc()) + +def save_assort_data(): + try: + # Deep copy the assort data and remove 'details' key before saving + cleaned_assort_data = json.loads(json.dumps(assort_data)) # Deep copy + + # Clean items + for item in cleaned_assort_data['items']: + if 'details' in item: + del item['details'] + + # Clean barter_scheme + for item_id, schemes in cleaned_assort_data.get('barter_scheme', {}).items(): + for scheme in schemes: + for part in scheme: + if 'details' in part: + del part['details'] + + with open(ASSORT_FILE_PATH, 'w') as f: + json.dump(cleaned_assort_data, f, indent=2) # Use 2 spaces for indentation + logging.debug("Assort data saved successfully") + except Exception as e: + logging.error(f"Error saving assort data: {e}") + logging.error(traceback.format_exc()) + +def save_item_cache(): + try: + with open(CACHE_FILE_PATH, 'w') as f: + json.dump(item_cache, f, indent=2) # Use 2 spaces for indentation + logging.debug("Item cache saved successfully") + except Exception as e: + logging.error(f"Error saving item cache: {e}") + logging.error(traceback.format_exc()) + +@app.route('/item_image/') +def item_image(tpl): + details = get_item_details_cached(tpl) + return jsonify({'image512pxLink': details.get('image512pxLink', ''), 'name': details.get('name', '')}) + +if __name__ == '__main__': + app.run(debug=True) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e484e85 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +Flask>=2.0.3 +requests>=2.26.0 \ No newline at end of file diff --git a/templates/edit.html b/templates/edit.html new file mode 100644 index 0000000..6dbbf1f --- /dev/null +++ b/templates/edit.html @@ -0,0 +1,179 @@ + + + + + Edit Item + + + + + +
+

Edit {{ item.details.name }}

+
+ +
+
+ + {{ item.details.name }} + +
+ +
+
+
+ RUB +
+ {{ item.details.basePrice }} RUB + Base Price (for reference) +
+
+ {% if item.parts|length > 0 %} +

+ +

+
+
    + {% include 'parts.html' with context %} +
+
+ {% endif %} +

Barter Scheme

+
+
+ {% for scheme in item.barter_scheme %} +
+ {% for req in scheme %} +
+
+ + {{ req.details.name }} + +
+ + +
+ +
+
+ {% endfor %} +
+ {% endfor %} +
+ + + Cancel +
+ {% if item.quest_requirement %} +

Quest Requirement

+

+ Quest Requirement: + {{ item.quest_requirement.quest }} + {% if item.quest_requirement.type == 'success' %} + + {% elif item.quest_requirement.type == 'fail' %} + + {% elif item.quest_requirement.type == 'started' %} + + {% endif %} +

+ {% endif %} +
+ + + + + + + diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..f3e60ab --- /dev/null +++ b/templates/index.html @@ -0,0 +1,142 @@ + + + + + Trader Assort + + + + + +
+

Trader Assort

+
+ {% for item in items %} +
+
+ {{ item.details.name }} + {{ item.details.name }} +
{{ item.offer_name }}
+
+
RUB{{ item.details.basePrice }} RUB
+ Base Price (for reference) +
+
+
+ Edit + + {% if item.parts|length > 0 %} +

+ +

+
+
    + {% include 'parts.html' with context %} +
+
+ {% endif %} + + {% if item.barter_scheme|length > 0 %} +
Barter Requirements:
+
    + {% for scheme in item.barter_scheme %} + {% for req in scheme %} +
  • + {{ req.count }} × + {{ req.details.name }} +
  • + {% endfor %} + {% endfor %} +
+ {% endif %} + + {% if item.quest_requirement %} +

+ Quest Requirement: + {{ item.quest_requirement.quest }} + {% if item.quest_requirement.type == 'success' %} + + {% elif item.quest_requirement.type == 'fail' %} + + {% elif item.quest_requirement.type == 'started' %} + + {% endif %} +

+ {% endif %} +
+
+ {% endfor %} +
+
+ + + + + + diff --git a/templates/parts.html b/templates/parts.html new file mode 100644 index 0000000..a9be8a2 --- /dev/null +++ b/templates/parts.html @@ -0,0 +1,16 @@ +{% macro render_parts(parts) %} + {% for part in parts %} +
  • + {{ part.details.name }} +
    + {{ part.details.shortName }} + {% if part.parts|length > 0 %} +
      + {{ render_parts(part.parts) }} +
    + {% endif %} +
    +
  • + {% endfor %} +{% endmacro %} +{{ render_parts(item.parts) }}