Add simple flask webapp to move items from the stash into the database

This commit is contained in:
2023-10-28 05:37:44 +02:00
parent 5026f58eb8
commit 0078b71389
7 changed files with 210 additions and 0 deletions

View File

@@ -0,0 +1 @@
from d2warehouse.app.main import app

22
d2warehouse/app/db.py Normal file
View 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
View 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)

View 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 },

View 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>

View 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>

View File

@@ -18,6 +18,7 @@ requires-python = ">=3.10"
license = {text = "GPLv3 License"} license = {text = "GPLv3 License"}
dependencies = [ dependencies = [
"bitarray", "bitarray",
"flask",
] ]
dynamic = ["version"] dynamic = ["version"]