from flask_nav.renderers import Renderer, SimpleRenderer from dominate import tags import asteval import operator as op import textwrap import math import sys import random import string from functools import wraps from urllib.request import urlopen from io import BytesIO import subprocess as SP import shlex import json import os from PIL import Image from PIL import ImageFont from PIL import ImageDraw def handle_config(cfg=None): if cfg is None: if os.path.isfile("config.json"): with open("config.json") as fh: return json.load(fh) with open("config.json", "w") as fh: cfg = json.dump(cfg, fh, indent=4) return def with_application_context(app): def inner(func): @wraps(func) def wrapper(*args, **kwargs): with app.app_context(): return func(*args, **kwargs) return wrapper return inner def getsize(text, font_size): font = ImageFont.truetype("arial.ttf", font_size) return font.getsize_multiline(text) def does_text_fit(text, width, height, font_size): w, h = getsize(text, font_size) return w < width and h < height def make_placeholder_image(text, width, height, poster=None, wrap=0): width = int(width) height = int(height) wrap = int(wrap) font_size = 1 bounds = (0, 1) if wrap: text = textwrap.fill(text, wrap) while True: if not does_text_fit(text, width, height, bounds[1]): break bounds = (bounds[1], bounds[1] * 2) prev_bounds = None while True: if does_text_fit(text, width, height, bounds[1]): bounds = (int(round(sum(bounds) / 2, 0)), bounds[1]) else: bounds = (bounds[0], int(round(sum(bounds) / 2, 0))) if prev_bounds == bounds: break prev_bounds = bounds font_size = bounds[0] io = BytesIO() im = Image.new("RGBA", (width, height), "#222") draw = ImageDraw.Draw(im) font = ImageFont.truetype("arial.ttf", font_size) w, h = getsize(text, font_size) if poster: try: with urlopen(poster) as fh: poster = Image.open(fh) except Exception as e: poster = None else: poster_size = poster.size factor = width / poster_size[0] new_size = ( math.ceil(poster_size[0] * factor), math.ceil(poster_size[1] * factor), ) poster = poster.resize(new_size) mid = -int((poster.size[1] - height) / 2) im.paste(poster, (0, mid)) draw.text(((width - w) / 2, (height - h) / 2), text, fill="#eee", font=font) im.save(io, "PNG") io.seek(0) return io def make_tree(files, child_key="children"): tree = {} for file in files: root = tree parts = file["name"].split("/") for item in parts: if item not in root: root[item] = {} prev_root = root root = root[item] prev_root[item] = {"__info__": file} return tree class BootsrapRenderer(Renderer): def visit_Navbar(self, node): sub = [] for item in node.items: sub.append(self.visit(item)) ret = tags.ul(sub, cls="navbar-nav mr-auto") return ret def visit_View(self, node): classes = ["nav-link"] if node.active: classes.append("active") return tags.li( tags.a(node.text, href=node.get_url(), cls=" ".join(classes)), cls="nav-item", ) def visit_Subgroup(self, node): url = "#" classes = [] child_active = False if node.title == "": active = False for item in node.items: if item.active: classes.append("active") break node, *children = node.items for c in children: if c.active: child_active = True break node.items = children node.title = node.text url = node.get_url() dropdown = tags.ul( [ tags.li( tags.a( item.text, href=item.get_url(), cls="nav-link active" if item.active else "nav-link", style="", ), cls="nav-item", ) for item in node.items ], cls="dropdown-menu ", ) link = tags.a( node.title, href=url, cls="nav-link active" if node.active else "nav-link", style="", ) toggle = tags.a( [], cls="dropdown-toggle nav-link active" if child_active else "dropdown-toggle nav-link", data_toggle="dropdown", href="#", style="padding-left: 0px; padding-top: 10px", ) # almost the same as visit_Navbar, but written a bit more concise return [link, tags.li([toggle, dropdown], cls="dropdown nav-item")] def eval_expr(expr, ctx=None): aeval = asteval.Interpreter(minimal=True, use_numpy=False, symtable=ctx) return aeval(expr) def sort_by(values, expr): return sorted(value, key=lambda v: eval_expr(expr, v)) def genpw(num=20): return "".join(random.choice(string.ascii_lowercase+string.ascii_uppercase+string.digits) for _ in range(num))