Compare commits
3 Commits
1cb9ff63e7
...
31e57da117
| Author | SHA1 | Date | |
|---|---|---|---|
| 31e57da117 | |||
| 2baa43db20 | |||
| 3e2c481f6f |
@@ -3,6 +3,7 @@ from flask import Flask, redirect, abort, render_template, request
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import shutil
|
import shutil
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import json
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
from d2warehouse.item import Item, Quality, lookup_basetype
|
from d2warehouse.item import Item, Quality, lookup_basetype
|
||||||
@@ -14,6 +15,7 @@ import re
|
|||||||
|
|
||||||
from d2warehouse.stash import StashFullError
|
from d2warehouse.stash import StashFullError
|
||||||
|
|
||||||
|
|
||||||
STASH_FILES = {
|
STASH_FILES = {
|
||||||
"softcore": "SharedStashSoftCoreV2.d2i",
|
"softcore": "SharedStashSoftCoreV2.d2i",
|
||||||
"hardcore": "SharedStashHardCoreV2.d2i",
|
"hardcore": "SharedStashHardCoreV2.d2i",
|
||||||
@@ -271,6 +273,7 @@ def list_storage_category(stash_name: str, category: str):
|
|||||||
"list_storage.html",
|
"list_storage.html",
|
||||||
stash_name=stash_name,
|
stash_name=stash_name,
|
||||||
storage_items=items,
|
storage_items=items,
|
||||||
|
category=category,
|
||||||
storage_count=lambda x: storage_count(x, stash_name),
|
storage_count=lambda x: storage_count(x, stash_name),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -345,7 +348,7 @@ def storage_currency_counts(item_codes: list[str], stash_name: str) -> dict:
|
|||||||
return currencies
|
return currencies
|
||||||
|
|
||||||
|
|
||||||
@app.route("/storage/<stash_name>/currency")
|
@app.route("/currency/<stash_name>")
|
||||||
def storage_currency(stash_name: str):
|
def storage_currency(stash_name: str):
|
||||||
if stash_name not in DB_FILES:
|
if stash_name not in DB_FILES:
|
||||||
abort(404)
|
abort(404)
|
||||||
@@ -356,3 +359,86 @@ def storage_currency(stash_name: str):
|
|||||||
return render_template(
|
return render_template(
|
||||||
"currency.html", runes=runes, gems=gems, keys=keys, essences=essences
|
"currency.html", runes=runes, gems=gems, keys=keys, essences=essences
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def load_uniques_data():
|
||||||
|
"""Return a sorted dictionary of unique item ids indexed by names."""
|
||||||
|
uniques_path = Path(__file__).resolve().parent.parent / "data/uniques.json"
|
||||||
|
with uniques_path.open() as f:
|
||||||
|
data = json.load(f)
|
||||||
|
name_to_id = {v["name"]: int(k) for k, v in data.items()}
|
||||||
|
del name_to_id["Amulet of the Viper"]
|
||||||
|
del name_to_id["Staff of Kings"]
|
||||||
|
del name_to_id["Horadric Staff"]
|
||||||
|
del name_to_id["Khalim's Flail"]
|
||||||
|
del name_to_id["Khalim's Will"]
|
||||||
|
del name_to_id["Hell Forge Hammer"]
|
||||||
|
return {name: name_to_id[name] for name in sorted(name_to_id.keys())}
|
||||||
|
|
||||||
|
|
||||||
|
def load_sets_data():
|
||||||
|
"""Return a sorted dictionary of unique item ids indexed by names."""
|
||||||
|
uniques_path = Path(__file__).resolve().parent.parent / "data/sets.json"
|
||||||
|
with uniques_path.open() as f:
|
||||||
|
data = json.load(f)
|
||||||
|
name_to_id = {v["name"]: int(k) for k, v in data.items()}
|
||||||
|
return {name: name_to_id[name] for name in sorted(name_to_id.keys())}
|
||||||
|
|
||||||
|
|
||||||
|
all_uniques = load_uniques_data()
|
||||||
|
all_sets = load_sets_data()
|
||||||
|
|
||||||
|
|
||||||
|
def get_found_uniques(db):
|
||||||
|
rows = db.execute(
|
||||||
|
"SELECT DISTINCT unique_id "
|
||||||
|
"FROM item INNER JOIN item_extra ON id = item_id "
|
||||||
|
"WHERE quality = 7 AND deleted IS NULL AND socketed_into IS NULL",
|
||||||
|
).fetchall()
|
||||||
|
return {row["unique_id"]: True for row in rows}
|
||||||
|
|
||||||
|
|
||||||
|
def get_found_sets(db):
|
||||||
|
rows = db.execute(
|
||||||
|
"SELECT DISTINCT set_id "
|
||||||
|
"FROM item INNER JOIN item_extra ON id = item_id "
|
||||||
|
"WHERE quality = 5 AND deleted IS NULL AND socketed_into IS NULL",
|
||||||
|
).fetchall()
|
||||||
|
return {row["set_id"]: True for row in rows}
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/grail/<stash_name>")
|
||||||
|
def storage_grail(stash_name: str):
|
||||||
|
if stash_name not in DB_FILES:
|
||||||
|
abort(404)
|
||||||
|
db = get_stash_db(stash_name)
|
||||||
|
|
||||||
|
# Unique progress
|
||||||
|
found = get_found_uniques(db)
|
||||||
|
items = {name: found.get(id, False) for name, id in all_uniques.items()}
|
||||||
|
count = len(found)
|
||||||
|
total = len(all_uniques)
|
||||||
|
uniques = {
|
||||||
|
"list": items,
|
||||||
|
"count": count,
|
||||||
|
"total": total,
|
||||||
|
"progress": count / total * 100,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set progress
|
||||||
|
found = get_found_sets(db)
|
||||||
|
items = {name: found.get(id, False) for name, id in all_sets.items()}
|
||||||
|
count = len(found)
|
||||||
|
total = len(all_sets)
|
||||||
|
sets = {
|
||||||
|
"list": items,
|
||||||
|
"count": count,
|
||||||
|
"total": total,
|
||||||
|
"progress": count / total * 100,
|
||||||
|
}
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
"grail.html",
|
||||||
|
uniques=uniques,
|
||||||
|
sets=sets,
|
||||||
|
)
|
||||||
|
|||||||
@@ -11,3 +11,10 @@ function toggleSelectAll(tabIndex) {
|
|||||||
cb.checked = !allSelected;
|
cb.checked = !allSelected;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleCollected() {
|
||||||
|
const collected = document.querySelectorAll('.collected');
|
||||||
|
collected.forEach(item => {
|
||||||
|
item.classList.toggle('hidden');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,25 @@ body {
|
|||||||
color: rgb(240, 240, 240);
|
color: rgb(240, 240, 240);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nav ul {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
background-color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a {
|
||||||
|
display: block;
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
text-decoration: none;
|
||||||
|
color: rgb(240, 240, 240);
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a:hover {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
.stash-tab {
|
.stash-tab {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(5, 1fr);
|
grid-template-columns: repeat(5, 1fr);
|
||||||
@@ -104,3 +123,28 @@ input[type="checkbox"]:checked + label {
|
|||||||
background-color: #444;
|
background-color: #444;
|
||||||
color: rgb(240, 240, 240);
|
color: rgb(240, 240, 240);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul.grail {
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5rem 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.grail li {
|
||||||
|
flex: 0 0 15rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
width: 15rem;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collected {
|
||||||
|
background-color: #343;
|
||||||
|
}
|
||||||
|
.uncollected {
|
||||||
|
background-color: #433;
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,10 +2,19 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Shared Stash</title>
|
<title>Currency</title>
|
||||||
<link rel="stylesheet" href="/static/style.css" />
|
<link rel="stylesheet" href="/static/style.css" />
|
||||||
<head>
|
<head>
|
||||||
<body>
|
<body>
|
||||||
|
{% include "menu.html" %}
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/storage/{{stash_name or 'softcore'}}">All</a></li>
|
||||||
|
<li><a href="/storage/{{stash_name or 'softcore'}}/uniques">Uniques</a></li>
|
||||||
|
<li><a href="/storage/{{stash_name or 'softcore'}}/sets">Sets</a></li>
|
||||||
|
<li><a href="/storage/{{stash_name or 'softcore'}}/currency">Currency</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
<div class="currencies">
|
<div class="currencies">
|
||||||
<div>
|
<div>
|
||||||
<table>
|
<table>
|
||||||
|
|||||||
28
d2warehouse/app/templates/grail.html
Normal file
28
d2warehouse/app/templates/grail.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Grail</title>
|
||||||
|
<link rel="stylesheet" href="/static/style.css" />
|
||||||
|
<script src="/static/helpers.js"></script>
|
||||||
|
<head>
|
||||||
|
<body>
|
||||||
|
{% include "menu.html" %}
|
||||||
|
<button type="button" onclick="toggleCollected()">Toggle collected</button>
|
||||||
|
<h1>Unique Items</h1>
|
||||||
|
Progress: {{uniques.count}}/{{uniques.total}} ({{uniques.progress | round(1)}}%)
|
||||||
|
<ul class="grail">
|
||||||
|
{% for name,collected in uniques.list.items() %}
|
||||||
|
<li class="{{ 'collected' if collected else 'uncollected' }}">{{name}}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<h1>Set Items</h1>
|
||||||
|
Progress: {{sets.count}}/{{sets.total}} ({{sets.progress | round(1)}}%)
|
||||||
|
<ul class="grail">
|
||||||
|
{% for name,collected in sets.list.items() %}
|
||||||
|
<li class="{{ 'collected' if collected else 'uncollected' }}">{{name}}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
<script src="/static/helpers.js"></script>
|
<script src="/static/helpers.js"></script>
|
||||||
<head>
|
<head>
|
||||||
<body>
|
<body>
|
||||||
|
{% include "menu.html" %}
|
||||||
<form action="/stash/{{stash_name}}/store" method="POST">
|
<form action="/stash/{{stash_name}}/store" method="POST">
|
||||||
{% for tab in stash.tabs %}
|
{% for tab in stash.tabs %}
|
||||||
{% set tabloop = loop %}
|
{% set tabloop = loop %}
|
||||||
|
|||||||
@@ -2,13 +2,23 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Storage</title>
|
<title>Storage - {{category or 'all'}}</title>
|
||||||
<link rel="stylesheet" href="/static/style.css" />
|
<link rel="stylesheet" href="/static/style.css" />
|
||||||
<head>
|
<head>
|
||||||
<body>
|
<body>
|
||||||
|
{% include "menu.html" %}
|
||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/storage/{{stash_name or 'softcore'}}">All</a></li>
|
||||||
|
<li><a href="/storage/{{stash_name or 'softcore'}}/uniques">Uniques</a></li>
|
||||||
|
<li><a href="/storage/{{stash_name or 'softcore'}}/sets">Sets</a></li>
|
||||||
|
<li><a href="/storage/{{stash_name or 'softcore'}}/misc">Misc</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
<form action="/storage/{{stash_name}}/take" method="POST">
|
<form action="/storage/{{stash_name}}/take" method="POST">
|
||||||
<div>
|
<div>
|
||||||
<!-- TODO: Include item.html -->
|
<!-- TODO: Include item.html -->
|
||||||
|
There are {{ storage_items | length }} items.
|
||||||
{% for db_id, item in storage_items.items() %}
|
{% for db_id, item in storage_items.items() %}
|
||||||
<div class="storage-item-entry">
|
<div class="storage-item-entry">
|
||||||
<input type="checkbox" name="item_{{db_id}}" id="item_{{db_id}}" value="take" />
|
<input type="checkbox" name="item_{{db_id}}" id="item_{{db_id}}" value="take" />
|
||||||
|
|||||||
8
d2warehouse/app/templates/menu.html
Normal file
8
d2warehouse/app/templates/menu.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/stash/{{stash_name or 'softcore'}}">Stash</a></li>
|
||||||
|
<li><a href="/storage/{{stash_name or 'softcore'}}">Storage</a></li>
|
||||||
|
<li><a href="/grail/{{stash_name or 'softcore'}}">Grail</a></li>
|
||||||
|
<li><a href="/currency/{{stash_name or 'softcore'}}">Currency</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
Reference in New Issue
Block a user