Spaces:
Paused
Paused
| print("STARTED") | |
| import gradio as gr | |
| import requests, os, time, threading, subprocess, shutil, tarfile, urllib.request | |
| from huggingface_hub import hf_hub_download, upload_file | |
| # ======================== | |
| # PATHS | |
| # ======================== | |
| ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) | |
| BASE_DIR = os.path.join(ROOT_DIR, "minecraft_server") | |
| os.makedirs(BASE_DIR, exist_ok=True) | |
| WORLD_PATH = os.path.join(BASE_DIR, "world") | |
| NETHER_PATH = os.path.join(BASE_DIR, "world_nether") | |
| END_PATH = os.path.join(BASE_DIR, "world_the_end") | |
| # ======================== | |
| # ENV | |
| # ======================== | |
| HF_TOKEN = os.environ.get("HF_TOKEN", "") | |
| PLAYIT_AUTH_KEY = os.environ.get("PLAYIT_AUTH_KEY", "") | |
| HF_REPO_ID = "Dalleon/McSaves" | |
| # ======================== | |
| # GLOBALS | |
| # ======================== | |
| SERVER_PROCESS = None | |
| TCP_PROCESS = None | |
| PUBLIC_TCP = None | |
| SERVER_ONLINE = False | |
| # ======================== | |
| # DOWNLOAD PAPER (1.20.6) | |
| # ======================== | |
| def download_paper(): | |
| jar_path = os.path.join(BASE_DIR, "server.jar") | |
| if os.path.exists(jar_path): | |
| print("[PAPER] already exists") | |
| return | |
| print("[PAPER] downloading 1.20.6...") | |
| url = "https://api.papermc.io/v2/projects/paper/versions/1.20.6/builds/latest/downloads/paper-1.20.6-latest.jar" | |
| urllib.request.urlretrieve(url, jar_path) | |
| # ======================== | |
| # READ OUTPUT | |
| # ======================== | |
| def read_output(): | |
| global SERVER_PROCESS | |
| while True: | |
| if SERVER_PROCESS and SERVER_PROCESS.stdout: | |
| line = SERVER_PROCESS.stdout.readline() | |
| if line: | |
| print("[MC]", line.strip()) | |
| time.sleep(0.1) | |
| # ======================== | |
| # LOAD WORLD | |
| # ======================== | |
| def load_world(): | |
| try: | |
| file_path = hf_hub_download( | |
| repo_id=HF_REPO_ID, | |
| filename="world.tar.gz", | |
| token=HF_TOKEN | |
| ) | |
| except: | |
| print("[LOAD] no backup") | |
| return | |
| if os.path.exists(WORLD_PATH): | |
| shutil.rmtree(WORLD_PATH) | |
| with tarfile.open(file_path, "r:gz") as tar: | |
| tar.extractall(BASE_DIR) | |
| # ======================== | |
| # PLAYIT | |
| # ======================== | |
| def start_tcp(): | |
| global PUBLIC_TCP, SERVER_ONLINE, TCP_PROCESS | |
| path = os.path.join(BASE_DIR, "playit") | |
| if not os.path.exists(path): | |
| print("[PLAYIT] downloading...") | |
| urllib.request.urlretrieve( | |
| "https://github.com/playit-cloud/playit-agent/releases/latest/download/playit-linux-amd64", | |
| path | |
| ) | |
| os.chmod(path, 0o755) | |
| TCP_PROCESS = subprocess.Popen( | |
| [path, "--secret", PLAYIT_AUTH_KEY], | |
| cwd=BASE_DIR, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.STDOUT, | |
| text=True | |
| ) | |
| timeout = time.time() + 20 | |
| while time.time() < timeout: | |
| line = TCP_PROCESS.stdout.readline() | |
| if line: | |
| print("[PLAYIT]", line.strip()) | |
| if "playit.gg" in line: | |
| for part in line.split(): | |
| if "playit.gg" in part: | |
| PUBLIC_TCP = part | |
| break | |
| if PUBLIC_TCP: | |
| break | |
| SERVER_ONLINE = True | |
| print("[PLAYIT] address:", PUBLIC_TCP) | |
| # ======================== | |
| # START SERVER | |
| # ======================== | |
| def start_server(): | |
| global SERVER_PROCESS | |
| print("[SERVER] starting...") | |
| load_world() | |
| download_paper() | |
| # accept eula | |
| with open(os.path.join(BASE_DIR, "eula.txt"), "w") as f: | |
| f.write("eula=true") | |
| SERVER_PROCESS = subprocess.Popen( | |
| [ | |
| "java", | |
| "-Xms512M", | |
| "-Xmx1G", | |
| "-jar", | |
| "server.jar", | |
| "--nogui" | |
| ], | |
| cwd=BASE_DIR, | |
| stdin=subprocess.PIPE, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.STDOUT, | |
| text=True | |
| ) | |
| threading.Thread(target=read_output, daemon=True).start() | |
| time.sleep(5) | |
| start_tcp() | |
| # ======================== | |
| # START BUTTON HANDLER | |
| # ======================== | |
| def start_background(): | |
| threading.Thread(target=start_server, daemon=True).start() | |
| return "Starting server..." | |
| # ======================== | |
| # GET ADDRESS | |
| # ======================== | |
| def get_address(): | |
| if not SERVER_ONLINE: | |
| return "Starting..." | |
| return PUBLIC_TCP or "No address yet" | |
| # ======================== | |
| # UI | |
| # ======================== | |
| with gr.Blocks() as app: | |
| gr.Markdown("## ⛏️ Minecraft Server") | |
| start_btn = gr.Button("Start Server") | |
| status = gr.Textbox(label="Status") | |
| addr_btn = gr.Button("Get Address") | |
| address = gr.Textbox(label="Server Address") | |
| start_btn.click(fn=start_background, outputs=status) | |
| addr_btn.click(fn=get_address, outputs=address) | |
| app.launch() |