Add simple flask webapp to move items from the stash into the database
This commit is contained in:
1
d2warehouse/app/__init__.py
Normal file
1
d2warehouse/app/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from d2warehouse.app.main import app
|
||||
22
d2warehouse/app/db.py
Normal file
22
d2warehouse/app/db.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import sqlite3
|
||||
from flask import g
|
||||
import d2warehouse.db as base_db
|
||||
|
||||
|
||||
def get_db():
|
||||
if "db" not in g:
|
||||
print("\n==========\nDB PATH", base_db._path, "\n============\n")
|
||||
g.db = sqlite3.connect(
|
||||
base_db._path,
|
||||
detect_types=sqlite3.PARSE_DECLTYPES,
|
||||
)
|
||||
g.db.row_factory = sqlite3.Row
|
||||
|
||||
return g.db
|
||||
|
||||
|
||||
def close_db(e=None):
|
||||
db = g.pop("db", None)
|
||||
|
||||
if db is not None:
|
||||
db.close()
|
||||
88
d2warehouse/app/main.py
Normal file
88
d2warehouse/app/main.py
Normal file
@@ -0,0 +1,88 @@
|
||||
from flask import Flask, redirect, abort, render_template, request
|
||||
from pathlib import Path
|
||||
from d2warehouse.parser import parse_stash
|
||||
import d2warehouse.db as base_db
|
||||
from d2warehouse.app.db import get_db, close_db
|
||||
import os
|
||||
import re
|
||||
|
||||
STASH_FILES = {
|
||||
"softcore": "SharedStashSoftCoreV2.d2i",
|
||||
"hardcore": "SharedStashHardCoreV2.d2i",
|
||||
}
|
||||
|
||||
|
||||
def save_path() -> Path:
|
||||
if "D2SAVE_PATH" in os.environ:
|
||||
path = Path(os.environ["D2SAVE_PATH"])
|
||||
else:
|
||||
path = Path.home() / "Saved Games/Diablo II Resurrected"
|
||||
|
||||
if not path.exists():
|
||||
raise RuntimeError("Save path `{path}` does not exist")
|
||||
return path
|
||||
|
||||
|
||||
base_db.set_db_path(str(save_path() / "d2warehouse.sqlite3"))
|
||||
base_db.init_db()
|
||||
base_db.close_db()
|
||||
|
||||
app = Flask(__name__)
|
||||
app.teardown_appcontext(close_db)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def home():
|
||||
return redirect("/stash/softcore", code=302)
|
||||
|
||||
|
||||
@app.route("/stash/<stash_name>")
|
||||
def list_stash(stash_name: str):
|
||||
if stash_name not in STASH_FILES:
|
||||
abort(404)
|
||||
path = save_path() / STASH_FILES[stash_name]
|
||||
stash_data = path.read_bytes()
|
||||
stash = parse_stash(stash_data)
|
||||
return render_template("list_stash.html", stash_name=stash_name, stash=stash)
|
||||
|
||||
|
||||
@app.route("/stash/<stash_name>/remove", methods=["POST"])
|
||||
def stash_remove_items(stash_name: str):
|
||||
if stash_name not in STASH_FILES:
|
||||
abort(404)
|
||||
stash_path = save_path() / STASH_FILES[stash_name]
|
||||
tmp_path = save_path() / f"{STASH_FILES[stash_name]}.temp"
|
||||
if tmp_path.exists():
|
||||
# TODO: Handle this condition
|
||||
return "temp file exists (BAD)"
|
||||
return 500
|
||||
|
||||
stash_data = stash_path.read_bytes()
|
||||
stash = parse_stash(stash_data)
|
||||
|
||||
items = []
|
||||
for item_location in request.form.keys():
|
||||
match = re.match(r"(\d+)_(\d+)", item_location)
|
||||
if not match:
|
||||
# TODO: Handle this condition
|
||||
return "invalid position"
|
||||
tab_idx, item_idx = int(match.group(1)), int(match.group(2))
|
||||
if tab_idx > len(stash.tabs) or item_idx > len(stash.tabs[tab_idx].items):
|
||||
# TODO: Handle this condition
|
||||
return "invalid position (2)"
|
||||
item = stash.tabs[tab_idx].items[item_idx]
|
||||
items.append((tab_idx, item))
|
||||
|
||||
# TODO: create backups
|
||||
|
||||
for tab_idx, item in items:
|
||||
stash.tabs[tab_idx].remove(item)
|
||||
tmp_path.write_bytes(stash.raw())
|
||||
|
||||
db = get_db()
|
||||
for _, item in items:
|
||||
item.write_to_db(db=db)
|
||||
|
||||
tmp_path.replace(stash_path)
|
||||
|
||||
return redirect(f"/stash/{stash_name}", code=303)
|
||||
61
d2warehouse/app/static/style.css
Normal file
61
d2warehouse/app/static/style.css
Normal file
@@ -0,0 +1,61 @@
|
||||
body {
|
||||
background-color: #000;
|
||||
font-size: large;
|
||||
font-family: sans-serif;
|
||||
color: rgb(240, 240, 240);
|
||||
}
|
||||
|
||||
.item .name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.item {
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
.color-rare {
|
||||
color: rgb(255, 255, 100);
|
||||
}
|
||||
|
||||
.color-unique {
|
||||
color: rgb(199, 179, 119);
|
||||
}
|
||||
|
||||
.color-set {
|
||||
color: rgb(0, 252, 0);
|
||||
}
|
||||
|
||||
.color-runeword {
|
||||
color: rgb(199, 179, 119);
|
||||
}
|
||||
|
||||
|
||||
"FontColorWhite": { "r": 240, "g": 240, "b": 240, "a": 255 },
|
||||
"FontColorVeryLightGray": { "r": 240, "g": 240, "b": 240, "a": 255 },
|
||||
"FontColorBlack": { "r": 0, "g": 0, "b": 0, "a": 255 },
|
||||
"FontColorRed": { "r": 252, "g": 70, "b": 70, "a": 255 },
|
||||
"FontColorGreen": { "r": 0, "g": 252, "b": 0, "a": 255 },
|
||||
"FontColorBlue": { "r": 110, "g": 110, "b": 255, "a": 255 },
|
||||
"FontColorLightGold": { "r": 255, "g": 246, "b": 227, "a": 255 }, // usage: button text, setting text labels
|
||||
"FontColorGoldYellow" : { "r": 199, "g": 179, "b": 119, "a": 255 }, //Usage example: panel and option subtitles
|
||||
"FontColorCurrencyGold" : {"r": 209, "g": 195, "b": 120, "a": 255}, // Usage Example: Gold text
|
||||
"FontColorGold": "$FontColorGoldYellow",
|
||||
"FontColorDarkGold": { "r": 120, "g": 98, "b": 47, "a": 255 },
|
||||
"FontColorBeige" : { "r": 204, "g": 195, "b": 176, "a": 255 },
|
||||
"FontColorGray": { "r": 99, "g": 99, "b": 99, "a": 255 },
|
||||
"FontColorGrey": "$FontColorGray",
|
||||
"FontColorOrange": { "r": 255, "g": 168, "b": 0, "a": 255 },
|
||||
"FontColorDarkGreen": { "r": 0, "g": 128, "b": 0, "a": 255 },
|
||||
"FontColorYellow": { "r": 255, "g": 255, "b": 100, "a": 255 },
|
||||
"FontColorLightPurple": { "r": 192, "g": 128, "b": 242, "a": 255 },
|
||||
"FontColorLightTeal": { "r": 124, "g": 221, "b": 204, "a": 255 },
|
||||
"FontColorLightRed": { "r": 255, "g": 148, "b": 148, "a": 255 },
|
||||
"FontColorLightYellow": { "r": 255, "g": 235, "b": 164, "a": 255 },
|
||||
"FontColorLightBlue": { "r": 175, "g": 183, "b": 255, "a": 255 },
|
||||
"FontColorLightGray": { "r": 148, "g": 148, "b": 148, "a": 255 },
|
||||
"FontColorDarkGrayBlue": { "r": 125, "g": 141, "b": 144, "a": 255 },
|
||||
"FontColorDarkGrayGold" : { "r": 173, "g": 168, "b": 148, "a": 255 }, // Usage example: attribute points to spend
|
||||
"FontColorTransparent": { "r": 0, "g": 0, "b": 0, "a": 0 },
|
||||
"FontColorPartyOrange": { "r": 196, "g": 129, "b": 0, "a": 255 },
|
||||
"FontColorPartyGreen": {"r": 79, "g": 194, "b": 56, "a": 255 },
|
||||
|
||||
14
d2warehouse/app/templates/item.html
Normal file
14
d2warehouse/app/templates/item.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<div class="item">
|
||||
<input type="checkbox" name="{{tabloop.index0}}_{{itemloop.index0}}" value="remove" /> ({{tabloop.index0}}, {{itemloop.index0}})
|
||||
<ul>
|
||||
<li class="name color-{{item.color}}">{{item.name}}</li>
|
||||
{% if item.quality and item.quality >= 5 %}
|
||||
<li class="name color-{{item.color}}">{{item.basename}}</li>
|
||||
{% endif %}
|
||||
{% if item.stats %}
|
||||
{% for stat in item.stats %}
|
||||
<li>{{stat}}</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
23
d2warehouse/app/templates/list_stash.html
Normal file
23
d2warehouse/app/templates/list_stash.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Shared Stash</title>
|
||||
<link rel="stylesheet" href="/static/style.css" />
|
||||
<head>
|
||||
<body>
|
||||
<form action="/stash/{{stash_name}}/remove" method="POST">
|
||||
{% for tab in stash.tabs %}
|
||||
<div>
|
||||
{% set tabloop = loop %}
|
||||
<h2>Tab {{tabloop.index}}</h2>
|
||||
{% for item in tab.items %}
|
||||
{% set itemloop = loop %}
|
||||
{% include "item.html" %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<input type="submit" value="Remove items">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -18,6 +18,7 @@ requires-python = ">=3.10"
|
||||
license = {text = "GPLv3 License"}
|
||||
dependencies = [
|
||||
"bitarray",
|
||||
"flask",
|
||||
]
|
||||
dynamic = ["version"]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user