p2manager.js hinzugefügt
This commit is contained in:
289
p2manager.js
Normal file
289
p2manager.js
Normal file
@@ -0,0 +1,289 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* p2manager - Player2 Manager (Node.js Edition)
|
||||
* (C) 2025 Alex Mueller / OptimiDev
|
||||
*/
|
||||
|
||||
import fs from "fs";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
import { execSync } from "child_process";
|
||||
import inquirer from "inquirer";
|
||||
import chalk from "chalk";
|
||||
import fetch from "node-fetch";
|
||||
import { Command } from "commander";
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// Platform Detection
|
||||
// ─────────────────────────────────────────────
|
||||
const isMac = process.platform === "darwin";
|
||||
const isLinux = process.platform === "linux";
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// Paths and URLs
|
||||
// ─────────────────────────────────────────────
|
||||
const APP_DIR = isMac ? "/Applications/Player2.app" : "/opt/player2";
|
||||
const EXEC_PATH = isMac ? "/Applications/Player2.app/Contents/MacOS/Player2" : path.join(APP_DIR, "Player2.AppImage");
|
||||
const SYMLINK = isMac ? "/usr/local/bin/player2" : "/usr/bin/player2";
|
||||
const DESKTOP_FILE = isMac
|
||||
? path.join(os.homedir(), "Desktop/player2.desktop")
|
||||
: "/usr/share/applications/player2.desktop";
|
||||
|
||||
const LATEST_URL = isMac
|
||||
? "https://player2.game/mac-intel"
|
||||
: "https://player2.game/linux";
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// Warning
|
||||
// ─────────────────────────────────────────────
|
||||
console.log(chalk.bgYellow("!!WARNING!!"))
|
||||
console.log(chalk.bgYellow("This code is made to run Player2 on unsupported devices like Macs with Intel and Linux"))
|
||||
console.log(chalk.bgYellow("If you get any problems"), chalk.bgRed("DO NOT REPORT TO PLAYER2"))
|
||||
console.log(chalk.bgYellow("Report the issues on: https://git.optimihost.com/NaChlorid/p2manager/issues"))
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// Utils
|
||||
// ─────────────────────────────────────────────
|
||||
const log = (...args) => console.log(chalk.cyan("[P2Manager]"), ...args);
|
||||
const warn = (...args) => console.log(chalk.bgYellow("[warn]"), ...args);
|
||||
const error = (...args) => console.error(chalk.bgRed("[error]"), ...args);
|
||||
|
||||
function requireRoot() {
|
||||
if (isLinux && process.getuid() !== 0) {
|
||||
error("This command requires root privileges. Run with sudo.");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function ensureDir(dir) {
|
||||
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
|
||||
function safeExec(cmd) {
|
||||
try {
|
||||
execSync(cmd, { stdio: "ignore" });
|
||||
} catch {
|
||||
warn(`Command failed (ignored): ${cmd}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadFile(url, dest) {
|
||||
log(`Downloading: ${url}`);
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) throw new Error(`Download failed: ${res.statusText}`);
|
||||
const fileStream = fs.createWriteStream(dest);
|
||||
await new Promise((resolve, reject) => {
|
||||
res.body.pipe(fileStream);
|
||||
res.body.on("error", reject);
|
||||
fileStream.on("finish", resolve);
|
||||
});
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// Core Functions
|
||||
// ─────────────────────────────────────────────
|
||||
async function installPlayer2({ patches = true, monitor = false, noUI = false }) {
|
||||
requireRoot();
|
||||
|
||||
log(`Installing latest Player2 for ${isMac ? "macOS" : "Linux"}...`);
|
||||
|
||||
if (isMac) {
|
||||
const dmgPath = "/tmp/Player2.dmg";
|
||||
await downloadFile(LATEST_URL, dmgPath);
|
||||
log("Mounting DMG...");
|
||||
safeExec(`hdiutil attach "${dmgPath}" -nobrowse -quiet`);
|
||||
safeExec(`cp -R "/Volumes/Player2/Player2.app" /Applications/`);
|
||||
safeExec(`hdiutil detach "/Volumes/Player2" -quiet`);
|
||||
fs.unlinkSync(dmgPath);
|
||||
} else {
|
||||
ensureDir(APP_DIR);
|
||||
await downloadFile(LATEST_URL, EXEC_PATH);
|
||||
fs.chmodSync(EXEC_PATH, 0o755);
|
||||
}
|
||||
|
||||
try {
|
||||
fs.symlinkSync(EXEC_PATH, SYMLINK);
|
||||
} catch {
|
||||
warn("Symlink already exists or cannot be created. Skipping.");
|
||||
}
|
||||
|
||||
createDesktopFile();
|
||||
|
||||
if (patches && isLinux) applyPatches();
|
||||
if (monitor && isLinux) setupMonitor();
|
||||
|
||||
log(chalk.green("✅ Player2 installed successfully!"));
|
||||
}
|
||||
|
||||
function createDesktopFile() {
|
||||
const execCmd = isMac ? "/Applications/Player2.app/Contents/MacOS/Player2" : SYMLINK;
|
||||
const desktopEntry = `[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Player2
|
||||
Exec=${execCmd}
|
||||
Icon=player2
|
||||
Comment=Player2 Game Client
|
||||
Categories=Game;`;
|
||||
ensureDir(path.dirname(DESKTOP_FILE));
|
||||
fs.writeFileSync(DESKTOP_FILE, desktopEntry);
|
||||
log("Desktop entry created.");
|
||||
}
|
||||
|
||||
function applyPatches() {
|
||||
log("Applying WebKit patch...");
|
||||
ensureDir(APP_DIR);
|
||||
fs.writeFileSync(path.join(APP_DIR, "patch.env"), "WEBKIT_DISABLE_DMABUF_RENDERER=1\n");
|
||||
log("Patch file written.");
|
||||
}
|
||||
|
||||
function setupMonitor() {
|
||||
log("Setting up P2Monitor...");
|
||||
ensureDir("/etc/p2monitor");
|
||||
|
||||
fs.writeFileSync(
|
||||
"/etc/p2monitor/monitor.py",
|
||||
`#!/usr/bin/env python3
|
||||
import time
|
||||
while True:
|
||||
time.sleep(5)`
|
||||
);
|
||||
fs.chmodSync("/etc/p2monitor/monitor.py", 0o755);
|
||||
|
||||
fs.writeFileSync(
|
||||
"/etc/systemd/system/p2monitor.service",
|
||||
`[Unit]
|
||||
Description=Player2 Log Monitor
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/python3 /etc/p2monitor/monitor.py
|
||||
Restart=always
|
||||
User=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target`
|
||||
);
|
||||
|
||||
safeExec("systemctl daemon-reload");
|
||||
safeExec("systemctl enable p2monitor");
|
||||
safeExec("systemctl start p2monitor");
|
||||
log("P2Monitor service installed and started (Linux only).");
|
||||
}
|
||||
|
||||
function uninstallAll() {
|
||||
requireRoot();
|
||||
log("Uninstalling Player2 components...");
|
||||
const removeTargets = [
|
||||
APP_DIR,
|
||||
SYMLINK,
|
||||
DESKTOP_FILE,
|
||||
"/etc/p2monitor",
|
||||
"/etc/systemd/system/p2monitor.service"
|
||||
];
|
||||
removeTargets.forEach((p) => {
|
||||
if (fs.existsSync(p)) {
|
||||
fs.rmSync(p, { recursive: true, force: true });
|
||||
log(`Removed: ${p}`);
|
||||
}
|
||||
});
|
||||
safeExec("systemctl daemon-reload");
|
||||
log(chalk.green("✅ Uninstallation complete."));
|
||||
}
|
||||
|
||||
async function updatePlayer2() {
|
||||
requireRoot();
|
||||
if (!fs.existsSync(EXEC_PATH)) {
|
||||
error("Player2 is not installed. Run 'p2manager install' first.");
|
||||
process.exit(1);
|
||||
}
|
||||
log("Updating Player2...");
|
||||
await downloadFile(LATEST_URL, EXEC_PATH);
|
||||
fs.chmodSync(EXEC_PATH, 0o755);
|
||||
log(chalk.green("✅ Player2 updated successfully!"));
|
||||
}
|
||||
|
||||
function showStatus() {
|
||||
console.log(chalk.bold("\nPlayer2 Manager Status"));
|
||||
console.log("──────────────────────────────");
|
||||
console.log("Platform:", isMac ? "macOS" : "Linux");
|
||||
console.log("Installed:", fs.existsSync(EXEC_PATH) ? "✅ Yes" : "❌ No");
|
||||
console.log("Executable:", EXEC_PATH);
|
||||
console.log("Symlink:", fs.existsSync(SYMLINK) ? "✅ Present" : "❌ Missing");
|
||||
console.log("Desktop Entry:", fs.existsSync(DESKTOP_FILE) ? "✅ Present" : "❌ Missing");
|
||||
if (isLinux)
|
||||
console.log("Monitor Service:", fs.existsSync("/etc/p2monitor") ? "✅ Installed" : "❌ Not installed");
|
||||
console.log("");
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// Interactive UI
|
||||
// ─────────────────────────────────────────────
|
||||
async function interactiveInstall() {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "components",
|
||||
message: "Select components to install:",
|
||||
choices: [
|
||||
{ name: "Player2 Core", value: "core", checked: true },
|
||||
...(isLinux ? [{ name: "WebKit Patch", value: "patch", checked: true }] : []),
|
||||
...(isLinux ? [{ name: "P2Monitor (Linux only)", value: "monitor" }] : [])
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
await installPlayer2({
|
||||
patches: answers.components.includes("patch"),
|
||||
monitor: answers.components.includes("monitor")
|
||||
});
|
||||
}
|
||||
|
||||
async function interactiveUninstall() {
|
||||
await inquirer.prompt([
|
||||
{
|
||||
type: "checkbox",
|
||||
name: "remove",
|
||||
message: "Select components to uninstall:",
|
||||
choices: [
|
||||
{ name: "Player2 Core", value: "core", checked: true },
|
||||
...(isLinux ? [{ name: "Patches", value: "patch", checked: true }] : []),
|
||||
...(isLinux ? [{ name: "P2Monitor", value: "monitor" }] : [])
|
||||
]
|
||||
}
|
||||
]);
|
||||
uninstallAll();
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// CLI Entrypoint
|
||||
// ─────────────────────────────────────────────
|
||||
const program = new Command();
|
||||
|
||||
program
|
||||
.name("p2manager")
|
||||
.description("Manage Player2 installation, patches, and updates")
|
||||
.version("1.1");
|
||||
|
||||
program
|
||||
.command("install")
|
||||
.option("--no-ui", "Run without interactive UI")
|
||||
.action(async (opts) => {
|
||||
if (opts.noUi) {
|
||||
await installPlayer2({ patches: true, monitor: false, noUI: true });
|
||||
} else {
|
||||
await interactiveInstall();
|
||||
}
|
||||
});
|
||||
|
||||
program
|
||||
.command("uninstall")
|
||||
.option("--no-ui", "Run without interactive UI")
|
||||
.action(async (opts) => {
|
||||
if (opts.noUi) uninstallAll();
|
||||
else await interactiveUninstall();
|
||||
});
|
||||
|
||||
program.command("update").action(updatePlayer2);
|
||||
program.command("status").action(showStatus);
|
||||
program.parse();
|
||||
Reference in New Issue
Block a user