1
0
Fork 0
mirror of https://github.com/YunoHost/apps.git synced 2024-09-03 20:06:07 +02:00
apps/store/utils.py

199 lines
5.7 KiB
Python

#!/usr/bin/env python3
import base64
import json
import os
import subprocess
import time
from hashlib import md5
from pathlib import Path
import pycmarkgfm
import tomlkit
from emoji import emojize
from flask import request
TRANSLATIONS_DIR = Path(__file__).parent / "translations"
AVAILABLE_LANGUAGES = ["en"] + [str(d) for d in TRANSLATIONS_DIR.glob("*/")]
def get_locale():
# try to guess the language from the user accept
# The best match wins.
return request.accept_languages.best_match(AVAILABLE_LANGUAGES) or "en"
def get_catalog():
path = Path("../builds/default/v3/apps.json").resolve()
mtime = path.stat().st_mtime
if get_catalog.mtime_catalog != mtime:
get_catalog.mtime_catalog = mtime
catalog = json.load(path.open())
catalog["categories"] = {c["id"]: c for c in catalog["categories"]}
catalog["antifeatures"] = {c["id"]: c for c in catalog["antifeatures"]}
category_color = {
"synchronization": "sky",
"publishing": "yellow",
"communication": "amber",
"office": "lime",
"productivity_and_management": "purple",
"small_utilities": "black",
"reading": "emerald",
"multimedia": "fuchsia",
"social_media": "rose",
"games": "violet",
"dev": "stone",
"system_tools": "black",
"iot": "orange",
"wat": "teal",
}
for id_, category in catalog["categories"].items():
category["color"] = category_color[id_]
get_catalog.cache_catalog = catalog
return get_catalog.cache_catalog
get_catalog.mtime_catalog = None
get_catalog()
def get_wishlist():
path = Path("../wishlist.toml").resolve()
mtime = path.stat().st_mtime
if get_wishlist.mtime_wishlist != mtime:
get_wishlist.mtime_wishlist = mtime
get_wishlist.cache_wishlist = tomlkit.load(path.open())
return get_wishlist.cache_wishlist
get_wishlist.mtime_wishlist = None
get_wishlist()
def get_stars():
checksum = (
subprocess.check_output("find . -type f -printf '%T@,' | md5sum", shell=True)
.decode()
.split()[0]
)
if get_stars.cache_checksum != checksum:
stars = {}
for folder, _, files in os.walk(".stars/"):
app_id = folder.split("/")[-1]
if not app_id:
continue
stars[app_id] = set(files)
get_stars.cache_stars = stars
get_stars.cache_checksum = checksum
return get_stars.cache_stars
get_stars.cache_checksum = None
get_stars()
def check_wishlist_submit_ratelimit(user):
dir_ = Path(".wishlist_ratelimit").resolve()
dir_.mkdir(exist_ok=True)
f = dir_ / md5(user.encode()).hexdigest()
return not f.exists() or (time.time() - f.stat().st_mtime) > (
15 * 24 * 3600
) # 15 days
def save_wishlist_submit_for_ratelimit(user):
dir_ = Path(".wishlist_ratelimit").resolve()
dir_.mkdir(exist_ok=True)
f = dir_ / md5(user.encode()).hexdigest()
f.touch()
def human_to_binary(size: str) -> int:
symbols = ("K", "M", "G", "T", "P", "E", "Z", "Y")
factor = {}
for i, s in enumerate(symbols):
factor[s] = 1 << (i + 1) * 10
suffix = size[-1]
size = size[:-1]
if suffix not in symbols:
raise Exception(f"Invalid size suffix '{suffix}', expected one of {symbols}")
try:
size_ = float(size)
except Exception:
raise Exception(f"Failed to convert size {size} to float") # noqa: B904
return int(size_ * factor[suffix])
def get_app_md_and_screenshots(app_folder, infos):
locale = get_locale()
description_path_localized = app_folder / "doc" / f"DESCRIPTION_{locale}.md"
description_path_generic = app_folder / "doc" / "DESCRIPTION.md"
if locale != "en" and description_path_localized.exists():
description_path = description_path_localized
elif description_path_generic.exists():
description_path = description_path_generic
else:
description_path = None
if description_path:
with description_path.open() as f:
infos["full_description_html"] = emojize(
pycmarkgfm.gfm_to_html(f.read()), language="alias"
)
else:
infos["full_description_html"] = infos["manifest"]["description"][locale]
preinstall_path_localized = app_folder / "doc" / f"PRE_INSTALL_{locale}.md"
preinstall_path_generic = app_folder / "doc" / "PRE_INSTALL.md"
if locale != "en" and preinstall_path_localized.exists():
pre_install_path = preinstall_path_localized
elif preinstall_path_generic.exists():
pre_install_path = preinstall_path_generic
else:
pre_install_path = None
if pre_install_path:
with pre_install_path.open() as f:
infos["pre_install_html"] = emojize(
pycmarkgfm.gfm_to_html(f.read()), language="alias"
)
infos["screenshot"] = None
screenshots_folder = app_folder / "doc" / "screenshots"
if screenshots_folder.exists():
with screenshots_folder.iterdir() as it:
for entry in it:
ext = entry.suffix.lower()
if entry.is_file() and ext in ("png", "jpg", "jpeg", "webp", "gif"):
with entry.open("rb") as img_file:
data = base64.b64encode(img_file.read()).decode("utf-8")
infos["screenshot"] = (
f"data:image/{ext};charset=utf-8;base64,{data}"
)
break
ram_build_requirement = infos["manifest"]["integration"]["ram"]["build"]
infos["manifest"]["integration"]["ram"]["build_binary"] = human_to_binary(
ram_build_requirement
)