mirror of
https://github.com/aclist/dztui.git
synced 2026-11-01 15:42:51 +01:00
feat: dzgui 7 alpha
This commit is contained in:
1 parent
1acdbd58c5
commit
2e5b771137
150 files changed
+10359
No files matched your search
Whitespace-only changes.
@@ -0,0 +1,72 @@
|
||||
import json
|
||||
import shlex
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
"""
|
||||
Convert legacy dztuirc to config.json
|
||||
"""
|
||||
|
||||
class UnsupportedKey(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def str2bool(string: str) -> bool:
|
||||
s = string.lower()
|
||||
match s:
|
||||
case "":
|
||||
return False
|
||||
case "0":
|
||||
return False
|
||||
case "1" | "2":
|
||||
return True
|
||||
case "false":
|
||||
return False
|
||||
case "true":
|
||||
return True
|
||||
case _:
|
||||
raise UnsupportedKey(f"The key {s} is not a valid config key.")
|
||||
|
||||
|
||||
def rc2json(file: Path) -> str:
|
||||
with open(file, "r") as f:
|
||||
lex = shlex.shlex(f.read())
|
||||
lex.whitespace += "="
|
||||
|
||||
d = {}
|
||||
ips: list[str] = []
|
||||
|
||||
toggles = ["auto_install", "debug", "fullscreen"]
|
||||
deprecated = ["staging_dir", "src_path", "steam_path"]
|
||||
|
||||
while True:
|
||||
tok = lex.get_token()
|
||||
ntok = lex.get_token()
|
||||
|
||||
if ntok is not None:
|
||||
ntok = ntok.strip('""')
|
||||
|
||||
if tok in deprecated:
|
||||
continue
|
||||
elif tok in toggles:
|
||||
ntok = str2bool(ntok)
|
||||
elif tok == "preferred_client":
|
||||
tok = "client"
|
||||
elif tok == "api_key":
|
||||
tok = "bm_api"
|
||||
elif tok == "ip_list":
|
||||
while True:
|
||||
ntok = lex.get_token().strip('""')
|
||||
if ntok == ")":
|
||||
break
|
||||
ips.append(ntok)
|
||||
continue
|
||||
|
||||
if not tok:
|
||||
break
|
||||
|
||||
d[tok] = ntok
|
||||
|
||||
d["ip_list"] = ips
|
||||
d["use_miles"] = False
|
||||
return json.dumps(d, indent=2)
|
||||
@@ -0,0 +1,42 @@
|
||||
import shutil
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def write_desktop_file(share_path: Path) -> None:
|
||||
template = f"""\
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Terminal=false
|
||||
Exec={share_path}/launch.sh
|
||||
Name=DZGUI
|
||||
Comment=dzgui
|
||||
Icon={share_path}/dzgui
|
||||
Categories=Game"""
|
||||
|
||||
file = share_path / "dzgui.desktop"
|
||||
file.write_text(textwrap.dedent(template))
|
||||
|
||||
|
||||
def write_shim_file(share_path: Path) -> None:
|
||||
# FIXME: expects sys.prefix to be a venv
|
||||
file = share_path / "launch.sh"
|
||||
template=f"""\
|
||||
source {venv}/bin/activate
|
||||
python3.13 dzgui
|
||||
"""
|
||||
try:
|
||||
file.write_text(textwrap.dedent(template))
|
||||
f.chmod(f.stat().st_mode | stat.S_IEXEC)
|
||||
except OSError:
|
||||
logger.critical(e)
|
||||
return
|
||||
clear_old_path()
|
||||
write_desktop_file(share_path)
|
||||
|
||||
|
||||
def clear_old_path() -> None:
|
||||
home = Path.home()
|
||||
path = home / ".local/share/dzgui"
|
||||
shutil.rmtree(path)
|
||||
@@ -0,0 +1,97 @@
|
||||
import gzip
|
||||
import logging
|
||||
import re
|
||||
import requests
|
||||
import shutil
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from dzgui.const.constants import REQUEST_TIMEOUT
|
||||
from dzgui.const.endpoints import DB_IP
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def find_download_url(url: str) -> str | None:
|
||||
res = requests.get(url, timeout=REQUEST_TIMEOUT)
|
||||
res.raise_for_status()
|
||||
reg = r'ref=[\'"]([^\'">]+.csv.gz)'
|
||||
urls = re.findall(reg, res.text)
|
||||
if len(urls) < 1:
|
||||
return None
|
||||
return str(urls[0])
|
||||
|
||||
def get_ipdb(ips_path: Path) -> None:
|
||||
url = find_download_url(DB_IP)
|
||||
if url is None:
|
||||
return
|
||||
|
||||
date = find_date(url)
|
||||
month_file = ips_path.parent / ".month"
|
||||
if month_file.exists() is True:
|
||||
old_date = month_file.read_text().rstrip("\n")
|
||||
if old_date == date:
|
||||
logger.info(f"IP DB date matches: {date}")
|
||||
return
|
||||
|
||||
# TODO: log additional output
|
||||
logger.info(f"Fetching IPDB for {date} from {url}")
|
||||
try:
|
||||
tmp = serialize(url)
|
||||
except Exception as e:
|
||||
logger.critical(e)
|
||||
return
|
||||
|
||||
logger.info(f"Extracting {tmp}")
|
||||
unzip(tmp, ips_path)
|
||||
|
||||
logger.info("Stripping IPv6 records")
|
||||
try:
|
||||
strip_ipv6(ips_path)
|
||||
except Exception as e:
|
||||
logger.critical(e)
|
||||
return
|
||||
|
||||
with open(month_file, "w") as f:
|
||||
f.write(date)
|
||||
logger.info(f"Wrote {date} to {month_file}")
|
||||
|
||||
|
||||
def find_date(url: str) -> str:
|
||||
date = re.sub(r"(dbip-city-lite-)(.*)(.csv.gz)", r"\2", url)
|
||||
date = date.split("/")[-1]
|
||||
return date
|
||||
|
||||
|
||||
def unzip(tmp: Path, ips_path: Path) -> None:
|
||||
with gzip.open(tmp, "rb") as f:
|
||||
with open(ips_path, "wb") as outfile:
|
||||
shutil.copyfileobj(f, outfile)
|
||||
tmp.unlink()
|
||||
|
||||
|
||||
def serialize(url: str) -> Path:
|
||||
with requests.get(url, stream=True) as r:
|
||||
r.raise_for_status()
|
||||
filename = "ips.csv.gz"
|
||||
tmp = Path("/tmp") / filename
|
||||
with open(tmp, "wb") as f:
|
||||
shutil.copyfileobj(r.raw, f)
|
||||
return tmp
|
||||
|
||||
|
||||
# TODO: optimize this function
|
||||
# consider using grep
|
||||
# cf. grep -vE "^[a-z0-9]{4}:" | grep -v "::" > "$ip_file"
|
||||
def strip_ipv6(path: Path) -> None:
|
||||
ips = []
|
||||
with open(path, "r") as f:
|
||||
s = f.read()
|
||||
|
||||
reg = r"^\d{1,3}\..*"
|
||||
ips = re.findall(reg, s, re.MULTILINE)
|
||||
assert ips[0].split(",")[0] == "0.0.0.0"
|
||||
assert ips[-1].split(",")[0] == "224.0.0.0"
|
||||
|
||||
with open(path, "w") as f:
|
||||
for ip in ips:
|
||||
f.write(ip + "\n")
|
||||
@@ -0,0 +1,60 @@
|
||||
from typing import Any
|
||||
from pathlib import Path
|
||||
|
||||
from dzgui.util._json import read_json
|
||||
|
||||
from dzgui.const.enum import Preferences
|
||||
from dzgui.const.constants import STEAM_CMD, FLATPAK_RUN_CMD, FLATPAK_SANDBOX
|
||||
|
||||
|
||||
class ConfigFileError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def lookup(path: Path, enum: Preferences) -> Any:
|
||||
if path.is_file() is False:
|
||||
raise ConfigFileError("Not a valid file")
|
||||
|
||||
key = enum_to_key(enum)
|
||||
config = get_config(path)
|
||||
try:
|
||||
return config[key]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
|
||||
def get_config(path: Path) -> dict:
|
||||
# TODO: is this being called twice?
|
||||
try:
|
||||
json = read_json(path)
|
||||
except Exception as e:
|
||||
raise e
|
||||
return json
|
||||
|
||||
|
||||
def get_favorites(path: Path) -> list[str]:
|
||||
try:
|
||||
conf = get_config(path)
|
||||
except Exception as e:
|
||||
pass
|
||||
return conf["ip_list"]
|
||||
|
||||
|
||||
def is_in_favs(record: str, path: Path) -> bool:
|
||||
favs = get_favorites(path)
|
||||
if record in favs:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def enum_to_key(enum: Preferences) -> str:
|
||||
return enum.dict["key"]
|
||||
|
||||
|
||||
def get_client_index(client: str) -> int:
|
||||
if client == STEAM_CMD:
|
||||
return 0
|
||||
elif client == FLATPAK_RUN_CMD:
|
||||
return 1
|
||||
else:
|
||||
return 2
|
||||
@@ -0,0 +1,10 @@
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
def uninstall(path: Path) -> None
|
||||
# TODO: use xdg object?
|
||||
# partial/full (keep config?)
|
||||
# -u removes state, log
|
||||
# XDG_SHARE_HOME/dzgui
|
||||
# XDG_STATE_HOME/dzgui
|
||||
# XDG_DATA_HOME/dzgui
|
||||
@@ -0,0 +1,25 @@
|
||||
from pathlib import Path
|
||||
|
||||
from dzgui.const.enum import Preferences
|
||||
from dzgui.config.query import get_config, enum_to_key
|
||||
from dzgui.util._json import write_json
|
||||
|
||||
# TEST: parametrize writing config values and checking config output in test
|
||||
def toggle_config(path: Path, key: Preferences) -> None:
|
||||
real_key = enum_to_key(key)
|
||||
try:
|
||||
conf = get_config(path)
|
||||
cur_val = conf[real_key]
|
||||
conf[real_key] = not cur_val
|
||||
write_json(conf, path)
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
def write_config(path: Path, key: Preferences, value: str) -> None:
|
||||
real_key = enum_to_key(key)
|
||||
try:
|
||||
conf = get_config(path)
|
||||
conf[real_key] = value
|
||||
write_json(conf, path)
|
||||
except Exception as e:
|
||||
raise e
|
||||
@@ -0,0 +1,12 @@
|
||||
from dataclasses import dataclass
|
||||
from dzgui.config.xdg import Xdg
|
||||
from dzgui.util.ip import Coords
|
||||
|
||||
@dataclass(slots=True, frozen=True)
|
||||
class UserPrefs:
|
||||
is_steam_deck: bool
|
||||
is_game_mode: bool
|
||||
coords: Coords | None
|
||||
version: str
|
||||
allow_updates: bool
|
||||
paths: Xdg
|
||||
@@ -0,0 +1,90 @@
|
||||
import os
|
||||
|
||||
from pathlib import Path
|
||||
from dataclasses import dataclass
|
||||
|
||||
from dzgui.const.constants import APP_NAME_LOWER, DEBUG_LOG, SYSTEM_LOG
|
||||
|
||||
@dataclass
|
||||
class Xdg:
|
||||
config: Path
|
||||
columns: Path
|
||||
notes: Path
|
||||
resolution: Path
|
||||
history: Path
|
||||
version: Path
|
||||
system: Path
|
||||
debug: Path
|
||||
ips: Path
|
||||
|
||||
|
||||
def is_writeable(path_str: str) -> bool:
|
||||
if path_str is None:
|
||||
return False
|
||||
|
||||
path = Path(path_str)
|
||||
|
||||
if not path.exists():
|
||||
try:
|
||||
path.mkdir(parents=True)
|
||||
except OSError:
|
||||
return False
|
||||
path.unlink()
|
||||
return True
|
||||
|
||||
try:
|
||||
file = Path(path / "temp")
|
||||
with open(file, "w") as f:
|
||||
f.write("")
|
||||
except Exception:
|
||||
return False
|
||||
file.unlink()
|
||||
return True
|
||||
|
||||
|
||||
def get_xdg_paths() -> dict:
|
||||
home = Path.home()
|
||||
xdg_paths = {
|
||||
"XDG_CONFIG_HOME": home / ".config",
|
||||
"XDG_STATE_HOME": home / ".local" / "state",
|
||||
"XDG_DATA_HOME": home / ".local" / "share",
|
||||
"XDG_CACHE_HOME": home / ".cache",
|
||||
}
|
||||
|
||||
resolved_paths = {}
|
||||
for path in xdg_paths:
|
||||
rp = os.environ.get(path)
|
||||
resolved_paths[path] = Path(rp) / APP_NAME_LOWER if is_writeable(rp) else xdg_paths[path] / APP_NAME_LOWER
|
||||
return resolved_paths
|
||||
|
||||
|
||||
def parse_filepaths(xdg: dict) -> Xdg:
|
||||
# cache = xdg["XDG_CACHE_HOME"]
|
||||
# data = xdg["XDG_DATA_HOME"]
|
||||
|
||||
config = xdg["XDG_CONFIG_HOME"]
|
||||
state = xdg["XDG_STATE_HOME"]
|
||||
|
||||
config = config / "config.json"
|
||||
|
||||
system = state / "logs" / SYSTEM_LOG
|
||||
debug = state / "logs" / DEBUG_LOG
|
||||
|
||||
columns = state / "dzg.cols.json"
|
||||
notes = state / "dzg.notes.json"
|
||||
resolution = state / "dzg.res.json"
|
||||
history = state / "dzg.history"
|
||||
versions = state / "dzg.versions"
|
||||
ips = state / "ips.csv"
|
||||
|
||||
return Xdg(
|
||||
config,
|
||||
columns,
|
||||
notes,
|
||||
resolution,
|
||||
history,
|
||||
versions,
|
||||
system,
|
||||
debug,
|
||||
ips,
|
||||
)
|
||||
Reference in new issue
Block a user