#!/usr/bin/env python3 from bottle import route, run, static_file, template from os import listdir, sysconf from os.path import join as pathjoin from random import random, choice from mcrcon import MCRcon import configparser import platform import requests import hashlib import base64 import json import re # echo -n "["; ls | xargs -I{} echo -n \"{}\",; echo "]" BG_IMAGES = listdir("./static/img/background") @route("/") def index(): print(server_details()) players = currentPlayerData() return template("html/index.html", **{"player_count": players["count"]["current"] , "max_players": players["count"]["max"], "news": news(), "donations": donations(), "server_details": server_details()}) @route("/getPlayerSkins") def getPlayerSkins(): players = currentPlayerData() skins = [] for p in players["players"]: hash = fetchSkin(p["uuid"]) skins.append(hash) return {"skins": skins} @route("/img/bg.png") def random_bg_image(): bg_file = choice(BG_IMAGES) print(bg_file) response = static_file(bg_file, root="static/img/background") response.set_header("Cache-Control", "no-cache") response.set_header("Cache-Control", "no-store") response.set_header("Pragma-Directive", "no-cache") response.set_header("Cache-Directive", "no-cache") response.set_header("Pragma", "no-cache") response.set_header("Expires", "0") return response @route("/") def callback(path): return static_file(path, root="static") def currentPlayerData(): player = {} with MCRcon(CONFIG["mcrcon"]["host"], CONFIG["mcrcon"]["password"], port=int(CONFIG["mcrcon"]["port"])) as mcr: resp = mcr.command("list uuids") resp = resp.split(":") player_string = resp[1].strip() if player_string != "": player_list = player_string.split(",") else: player_list = [] player_list = list(map(lambda x: x.strip(), player_list)) count_regex = re.match("There are ([0-9]+) of a max of ([0-9]+) players online", resp[0]) num_players = count_regex.group(1) max_players = count_regex.group(2) player["count"] = {} player["count"]["current"] = num_players player["count"]["max"] = max_players player["players"] = [] for p in player_list: data = p.split(" ") name = data[0].strip() uuid = data[1].strip().replace("(", "").replace(")", "") player["players"].append({"name": name, "uuid": uuid}) return player def fetchSkin(uuid): profile = requests.get("https://sessionserver.mojang.com/session/minecraft/profile/{}".format(uuid)).json() properties = profile.get("properties") skin = list(filter(lambda x: x.get("name", "") == "textures", properties))[0] skin_json = json.loads(base64.b64decode(skin.get("value"))) skin_url = skin_json.get("textures").get("SKIN").get("url") skin_req = requests.get(skin_url) player_hash = hashlib.sha256(uuid.encode()).hexdigest() with open('./static/img/skins/{}'.format(player_hash), 'wb') as f: f.write(skin_req.content) return player_hash def parseConfig(): config = configparser.ConfigParser() config.read("config.ini") return config def donations(): with open("donations.txt", "r") as donation_file: donations = donation_file.read() return donations def news(): with open("news.txt", "r") as news_file: news = news_file.read() def hardware_info(): processor = platform.processor() mem_bytes = sysconf('SC_PAGE_SIZE') * sysconf('SC_PHYS_PAGES') mem_gib = mem_bytes/(1024.**3) mem_pretty = round(mem_gib, 1) return {"cpu": processor, "ram": mem_pretty} def paper_version(): with MCRcon(CONFIG["mcrcon"]["host"], CONFIG["mcrcon"]["password"], port=int(CONFIG["mcrcon"]["port"])) as mcr: for i in range(0, 10): resp = mcr.command("version") if not "please wait" in resp: break match = re.match(".*(This server is running Paper version )(.*) \((.*)\) \(Implementing API version (.*)\).*", resp) paper_version = match.group(2) mc_version = match.group(3) mc_version = mc_version.split(":")[1].strip() api_version = match.group(4) return {"paper": paper_version, "minecraft": mc_version, "api": api_version} def datapack_info(): with MCRcon(CONFIG["mcrcon"]["host"], CONFIG["mcrcon"]["password"], port=int(CONFIG["mcrcon"]["port"])) as mcr: resp = mcr.command("datapack list") match = re.match("There are [0-9]* data packs enabled: (\[.*\])*.*", resp) datapacks = [] datapacks_string = match.group(1) for datapack in datapacks_string.split(","): match = re.match("\[(.*)\(.*\)\]", datapack.strip()) datapack_name = match.group(1) datapack_name = datapack_name.strip() datapack_name = datapack_name.replace("file/", "") datapack_name = datapack_name.replace(".zip", "") if not datapack_name in ["vanilla", "bukkit"]: datapacks.append(datapack_name) return datapacks def server_details(): hardware = hardware_info() versions = paper_version() datapacks = datapack_info() return {"hardware": hardware, "versions": versions, "datapacks": datapacks} CONFIG = parseConfig() run(host="localhost", port=8080)