""" Backup / Restore serwera Minecraft do Hugging Face Dataset. Usage: python3 sync_data.py restore python3 sync_data.py backup """ import os import sys import tarfile import shutil import tempfile from pathlib import Path from huggingface_hub import HfApi, hf_hub_download # ── configuration ──────────────────────────────────────────────────────────── DATASET_ID = os.environ.get("DATASET_ID", "natekkz/basketrush-data") HF_TOKEN = os.environ.get("HF_TOKEN", "") SERVER_DIR = Path("/home/user/minecraft/server") ARCHIVE_NAME = "server-backup.tar.gz" # Directories to back up (relative to SERVER_DIR) BACKUP_DIRS = [ "world", "plugins", "config", ] # Individual files to back up (relative to SERVER_DIR) BACKUP_FILES = [ "server.properties", "bukkit.yml", "spigot.yml", "commands.yml", "help.yml", "permissions.yml", "wepif.yml", "usercache.json", "whitelist.json", "banned-ips.json", "banned-players.json", "ops.json", "server-icon.png", "version_history.json", ] # playit.gg configuration (persisted across restarts) PLAYIT_TOML = Path.home() / ".config" / "playit" / "playit.toml" # ── restore ────────────────────────────────────────────────────────────────── def restore(): """Download and extract server backup from HF Dataset.""" if not HF_TOKEN: print("[sync] No HF_TOKEN set – skipping restore") return False print(f"[sync] Restoring from dataset {DATASET_ID}...") try: archive_path = hf_hub_download( repo_id=DATASET_ID, filename=ARCHIVE_NAME, repo_type="dataset", token=HF_TOKEN, ) except Exception as e: print(f"[sync] No backup found in dataset ({e}) – starting fresh") return False SERVER_DIR.mkdir(parents=True, exist_ok=True) # Safe extraction — validate paths with tarfile.open(archive_path, "r:gz") as tar: for member in tar.getmembers(): target = (SERVER_DIR / member.name).resolve() if not str(target).startswith(str(SERVER_DIR.resolve())): print(f"[sync] ⚠ Skipping unsafe path: {member.name}") continue tar.extract(member, path=SERVER_DIR) # Restore playit.gg config if present in backup playit_backup = SERVER_DIR / ".playit.toml" if playit_backup.exists(): PLAYIT_TOML.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(playit_backup, PLAYIT_TOML) print("[sync] Restored playit.toml") print("[sync] ✅ Restore complete") return True # ── backup ─────────────────────────────────────────────────────────────────── def backup(): """Create a tarball of server data and upload to HF Dataset.""" if not HF_TOKEN: print("[sync] No HF_TOKEN set – skipping backup") return False print(f"[sync] Backing up to dataset {DATASET_ID}...") with tempfile.TemporaryDirectory() as tmp: archive_path = Path(tmp) / ARCHIVE_NAME with tarfile.open(archive_path, "w:gz") as tar: # Add directories for d in BACKUP_DIRS: src = SERVER_DIR / d if src.exists(): tar.add(str(src), arcname=d) print(f" + {d}/") # Add individual files for f in BACKUP_FILES: src = SERVER_DIR / f if src.exists(): tar.add(str(src), arcname=f) print(f" + {f}") # Include playit.gg config if PLAYIT_TOML.exists(): tar.add(str(PLAYIT_TOML), arcname=".playit.toml") print(" + .playit.toml") # Upload api = HfApi(token=HF_TOKEN) api.upload_file( path_or_fileobj=str(archive_path), path_in_repo=ARCHIVE_NAME, repo_id=DATASET_ID, repo_type="dataset", ) print("[sync] ✅ Backup uploaded") return True # ── CLI ────────────────────────────────────────────────────────────────────── if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: python3 sync_data.py [restore|backup]") sys.exit(1) cmd = sys.argv[1].lower() if cmd == "restore": restore() elif cmd == "backup": backup() else: print(f"Unknown command: {cmd}") sys.exit(1)