hachem.wtf
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2025-10-12 15:45:04 +0200
committerhachem <im@hachem.wtf>2025-10-12 15:45:04 +0200
commitcc3dfce7dfbbeda9934892be631decb79a26dd28 (patch)
tree88c173266f7de5fe78d0a9a04bdb5a886de9d6db
parentace016c0c58abbdafd74f116175a3675a370fce6 (diff)
[add]: updater
-rw-r--r--.gitignore1
-rw-r--r--bot/app.js (renamed from src/app.js)0
-rw-r--r--package.json2
-rw-r--r--updater/updater.py171
4 files changed, 173 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index 26dfd2a..0b238f8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
config/api.json
cache/
+server/
# Logs
logs
diff --git a/src/app.js b/bot/app.js
index d25b3b6..d25b3b6 100644
--- a/src/app.js
+++ b/bot/app.js
diff --git a/package.json b/package.json
index 4b64e2a..58653f4 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,7 @@
"license": "Apache-2.0",
"author": "hachem",
"type": "commonjs",
- "main": "src/app.js",
+ "main": "updater/app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
diff --git a/updater/updater.py b/updater/updater.py
new file mode 100644
index 0000000..7f065eb
--- /dev/null
+++ b/updater/updater.py
@@ -0,0 +1,171 @@
+from typing import List
+import os
+import httpx
+import shutil
+import asyncio
+import subprocess
+import json
+
+server_dir = "server"
+mods_dir = f"{server_dir}/mods"
+os.makedirs(server_dir, exist_ok=True)
+os.makedirs(mods_dir, exist_ok=True)
+
+delete_list = [
+ "audioplayer_uploads/",
+ "config/",
+ "cache/",
+ "world/",
+ "logs/",
+
+ "banned-players.json",
+ "server.properties",
+ "banned-ips.json",
+ "usercache.json",
+ "whitelist.json",
+ "ops.json",
+ "eula.txt",
+]
+
+with open("config/config.json", "r") as f:
+ config = json.load(f)
+
+mc_version = config.get("minecraft_version", "1.21.10")
+fabric_loader_version = config.get("fabric_loader_version", "0.17.3")
+loader_meta_version = config.get("loader_meta_version", "1.1.0")
+modrinth_mods = config.get("modrinth_mods", [])
+
+async def download_modrinth(mod_list: List[str], mc_ver: str):
+ downloaded_files = []
+ failed_mods = []
+ async with httpx.AsyncClient(timeout=60) as client:
+ for slug in mod_list:
+ try:
+ versions_url = f"https://api.modrinth.com/v2/project/{slug}/version"
+ resp = await client.get(versions_url)
+ if resp.status_code != 200:
+ print(f"[Modrinth] Could not get versions for {slug}")
+ failed_mods.append(slug)
+ continue
+
+ versions = resp.json()
+ compatible_versions = [
+ v for v in versions
+ if "fabric" in v.get("loaders", []) and mc_ver in v.get("game_versions", [])
+ ]
+
+ if not compatible_versions:
+ print(f"[Modrinth] No Fabric versions found for {slug} on MC {mc_ver}")
+ failed_mods.append(slug)
+ continue
+
+ latest = max(compatible_versions, key=lambda v: v["date_published"])
+ file_info = latest.get("files", [])[0]
+ jar_url = file_info["url"]
+ filename = file_info["filename"]
+
+ print(f"[Modrinth] Downloading {slug} -> {filename} ...")
+ jar_resp = await client.get(jar_url)
+ if jar_resp.status_code != 200:
+ print(f"[Modrinth] Couldn't download jar for {slug}")
+ failed_mods.append(slug)
+ continue
+
+ path = os.path.join(mods_dir, filename)
+ with open(path, "wb") as f:
+ f.write(jar_resp.content)
+
+ downloaded_files.append(path)
+ print(f"[Modrinth] Successfully downloaded: {filename}")
+
+ except Exception as e:
+ print(f"[Modrinth] Error downloading {slug}: {e}")
+ failed_mods.append(slug)
+
+ return downloaded_files, failed_mods
+
+async def download_fabric_server(mc_ver: str, loader_ver: str, meta_ver: str):
+ url = f"https://meta.fabricmc.net/v2/versions/loader/{mc_ver}/{loader_ver}/{meta_ver}/server/jar"
+ filename = "server.jar"
+ path = os.path.join(server_dir, filename)
+
+ async with httpx.AsyncClient(timeout=60) as client:
+ try:
+ print(f"[Fabric] Downloading Fabric server for MC {mc_ver} ...")
+ resp = await client.get(url)
+ if resp.status_code != 200:
+ print(f"[Fabric] Failed to download Fabric server JAR: {resp.status_code}")
+ return None
+
+ with open(path, "wb") as f:
+ f.write(resp.content)
+
+ print(f"[Fabric] Successfully downloaded Fabric server: {filename}")
+ return path
+ except Exception as e:
+ print(f"[Fabric] Error downloading Fabric server: {e}")
+ return None
+
+async def run_fabric_server():
+ jar_path = os.path.join(server_dir, "server.jar")
+
+ if not os.path.exists(jar_path):
+ print("[Server] Server JAR not found, cannot start server.")
+ return
+
+ eula_path = os.path.join(server_dir, "eula.txt")
+ if not os.path.exists(eula_path):
+ print("[Server] Accepting EULA automatically...")
+ with open(eula_path, "w") as f:
+ f.write("eula=true\n")
+
+ print(f"[Server] Starting Fabric server from {jar_path} ...")
+
+ process = subprocess.Popen(
+ ["java", "-jar", "server.jar", "nogui"],
+ cwd=server_dir
+ )
+ process.wait()
+ print("[Server] Fabric server stopped.")
+
+def cleanup_server(delete_list: List[str]):
+ print("[Cleanup] Cleaning up server files...")
+ for item in delete_list:
+ path = os.path.join(server_dir, item)
+ if os.path.exists(path):
+ try:
+ if os.path.isdir(path):
+ shutil.rmtree(path)
+ print(f"[Cleanup] Removed folder: {item}")
+ else:
+ os.remove(path)
+ print(f"[Cleanup] Removed file: {item}")
+ except Exception as e:
+ print(f"[Cleanup] Failed to remove {item}: {e}")
+ else:
+ print(f"[Cleanup] {item} does not exist, skipping.")
+ print("[Cleanup] Cleanup complete.")
+
+async def main():
+ print(f"Starting Benson Mod Updater for Fabric MC {mc_version}...\n")
+ files, failed_mods = await download_modrinth(modrinth_mods, mc_version)
+ server_file = await download_fabric_server(mc_version, fabric_loader_version, loader_meta_version)
+
+ print("\nAll downloads complete!")
+ print(f"Downloaded {len(files)} mods:")
+ for f in files:
+ print(f" - {f}")
+
+ if failed_mods:
+ print("\nThe following mods failed to download:")
+ for mod in failed_mods:
+ print(f" - {mod}")
+ else:
+ print("\nAll mods downloaded successfully!")
+
+ if server_file:
+ await run_fabric_server()
+ cleanup_server(delete_list)
+
+if __name__ == "__main__":
+ asyncio.run(main())