diff --git a/scripts/download-binaries.mjs b/scripts/download-binaries.mjs new file mode 100755 index 0000000..18b2623 --- /dev/null +++ b/scripts/download-binaries.mjs @@ -0,0 +1,161 @@ +#!/usr/bin/env node + +/** + * Download native binaries (ffmpeg + @discordjs/opus) from npmmirror CDN. + * Called by setup.bat after npm install --ignore-scripts. + * + * Usage: node scripts/download-binaries.mjs [cdn_base_url] + */ + +import { existsSync, mkdirSync, writeFileSync, statSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join, dirname } from "node:path"; +import { createGunzip } from "node:zlib"; +import { pipeline } from "node:stream/promises"; +import { createWriteStream } from "node:fs"; +import { get } from "node:https"; +import { Readable } from "node:stream"; +import { execSync } from "node:child_process"; +import { createRequire } from "node:module"; +import { fileURLToPath } from "node:url"; + +const ROOT = join(dirname(fileURLToPath(import.meta.url)), ".."); +const CDN = process.argv[2] || "https://cdn.npmmirror.com/binaries"; +const PLATFORM = process.platform; +const ARCH = process.arch; +const NODE_ABI = process.versions.modules; + +function download(url) { + return new Promise((resolve, reject) => { + const req = get(url, { timeout: 120000 }, (res) => { + if (res.statusCode < 200 || res.statusCode >= 400) { + reject(new Error(`HTTP ${res.statusCode}: ${url}`)); + return; + } + const chunks = []; + res.on("data", (c) => chunks.push(c)); + res.on("end", () => resolve(Buffer.concat(chunks))); + }); + req.on("error", reject); + req.on("timeout", () => { req.destroy(); reject(new Error("timeout")); }); + }); +} + +function log(msg) { + console.log(` [binary] ${msg}`); +} + +function isValidSize(filePath, minBytes) { + try { return statSync(filePath).size >= minBytes; } catch { return false; } +} + +async function downloadFfmpeg() { + const ffDir = join(ROOT, "node_modules", "ffmpeg-static"); + const ffName = PLATFORM === "win32" ? "ffmpeg.exe" : "ffmpeg"; + const ffDest = join(ffDir, ffName); + + if (!existsSync(ffDir)) { log("ffmpeg-static not installed, skipping"); return false; } + if (existsSync(ffDest)) { + if (isValidSize(ffDest, 50 * 1024 * 1024)) { + log("ffmpeg already exists, skipping"); + return true; + } + log("ffmpeg exists but seems corrupted (too small), re-downloading..."); + } + + const url = `${CDN}/ffmpeg-static/b6.1.1/ffmpeg-${PLATFORM}-${ARCH}.gz`; + log("Downloading ffmpeg..."); + const buf = await download(url); + await pipeline(Readable.from(buf), createGunzip(), createWriteStream(ffDest)); + try { execSync(`chmod +x "${ffDest}"`); } catch {} + const size = ((await statSync(ffDest)).size / 1024 / 1024).toFixed(1); + log(`ffmpeg OK (${size} MB)`); + return true; +} + +async function downloadOpus() { + const opusDir = join(ROOT, "node_modules", "@discordjs", "opus"); + const prebuildName = `node-v${NODE_ABI}-napi-v3-${PLATFORM}-${ARCH}-unknown-unknown`; + const opusDest = join(opusDir, "prebuild", prebuildName, "opus.node"); + + if (!existsSync(opusDir)) { log("@discordjs/opus not installed, skipping"); return false; } + if (existsSync(opusDest)) { + if (isValidSize(opusDest, 100 * 1024)) { + log("@discordjs/opus already exists, skipping"); + return true; + } + log("@discordjs/opus exists but seems corrupted (too small), re-downloading..."); + } + + const url = `${CDN}/@discordjs/opus/v0.10.0/opus-v0.10.0-node-v${NODE_ABI}-napi-v3-${PLATFORM}-${ARCH}-unknown-unknown.tar.gz`; + log("Downloading @discordjs/opus..."); + try { + const buf = await download(url); + mkdirSync(dirname(opusDest), { recursive: true }); + const require = createRequire(import.meta.url); + const tar = require("tar"); + const tmpFile = join(tmpdir(), `discordjs-opus-${Date.now()}.tar.gz`); + writeFileSync(tmpFile, buf); + await tar.extract({ cwd: join(opusDir, "prebuild"), file: tmpFile }); + log("@discordjs/opus OK"); + return true; + } catch (err) { + log(`CDN download failed (${err.message}), trying to build from source...`); + try { + execSync("npm rebuild @discordjs/opus", { cwd: ROOT, stdio: "inherit" }); + if (existsSync(opusDest) && isValidSize(opusDest, 100 * 1024)) { + log("@discordjs/opus built from source OK"); + return true; + } + log("Source build completed but .node file not found"); + return false; + } catch (buildErr) { + log(`Source build failed: ${buildErr.message}`); + log("Install build tools: sudo apt install build-essential (Ubuntu/Debian)"); + log(" sudo yum groupinstall 'Development Tools' (CentOS/RHEL)"); + return false; + } + } +} + +async function downloadBetterSqlite3() { + const pkgDir = join(ROOT, "node_modules", "better-sqlite3"); + const dest = join(pkgDir, "build", "Release", "better_sqlite3.node"); + + if (!existsSync(pkgDir)) { log("better-sqlite3 not installed, skipping"); return false; } + if (existsSync(dest)) { + if (isValidSize(dest, 500 * 1024)) { + log("better-sqlite3 already exists, skipping"); + return true; + } + log("better-sqlite3 exists but seems corrupted (too small), re-downloading..."); + } + + const version = "12.8.0"; + const url = `${CDN}/better-sqlite3/v${version}/better-sqlite3-v${version}-node-v${NODE_ABI}-${PLATFORM}-${ARCH}.tar.gz`; + log("Downloading better-sqlite3..."); + const buf = await download(url); + const require = createRequire(import.meta.url); + const tar = require("tar"); + const tmpFile = join(tmpdir(), `better-sqlite3-${Date.now()}.tar.gz`); + writeFileSync(tmpFile, buf); + mkdirSync(dirname(dest), { recursive: true }); + await tar.extract({ cwd: pkgDir, file: tmpFile }); + if (existsSync(dest)) { + log(`better-sqlite3 OK (${((await statSync(dest)).size / 1024).toFixed(0)} KB)`); + return true; + } + log("better-sqlite3 extracted but .node file not found at expected path"); + return false; +} + +try { + const results = await Promise.all([downloadFfmpeg(), downloadOpus(), downloadBetterSqlite3()]); + if (results.some(Boolean)) { + console.log(" [binary] All downloads complete"); + } +} catch (e) { + console.error(` [binary] ERROR: ${e.message}`); + process.exit(1); +} + diff --git a/scripts/setup.bat b/scripts/setup.bat index b3884ba..e43435c 100644 --- a/scripts/setup.bat +++ b/scripts/setup.bat @@ -1,321 +1,294 @@ -@echo off -setlocal enabledelayedexpansion -chcp 65001 >nul -title TSMusicBot Setup - -:: ============================================================ -:: TSMusicBot Setup Script (Robust Edition) -:: - Auto-detect China network, switch to npmmirror -:: - Strict error checking at every step -:: - Detailed logging to setup.log -:: - Skip already-completed steps on re-run -:: ============================================================ - -set "SCRIPT_VERSION=2.0" -set "MIN_NODE_MAJOR=20" -set "LOG_FILE=%~dp0..\setup.log" -set "FAILED=0" - -:: Resolve project root (one level up from scripts/) -cd /d "%~dp0.." || ( - echo [FATAL] Cannot change to project directory. - pause - exit /b 1 -) - -set "PROJECT_ROOT=%cd%" - -:: ---- Initialize log ---- -echo. > "%LOG_FILE%" -call :log "============================================" -call :log " TSMusicBot Setup v%SCRIPT_VERSION%" -call :log " Started: %date% %time%" -call :log " Project root: %PROJECT_ROOT%" -call :log "============================================" - -echo ============================================ -echo TSMusicBot - First-Time Setup (Windows) -echo Version %SCRIPT_VERSION% -echo ============================================ -echo. -echo Log file: %LOG_FILE% -echo. - -:: ============================================================ -:: Step 1: Check Node.js -:: ============================================================ -call :step "1/6" "Checking Node.js" - -where node >nul 2>&1 -if errorlevel 1 ( - call :error "Node.js not found in PATH." - echo. - echo Please install Node.js %MIN_NODE_MAJOR% LTS or newer from one of: - echo - https://nodejs.org/ ^(official^) - echo - https://nodejs.cn/ ^(China mirror, recommended for CN users^) - echo. - echo After installation: - echo 1. Close this window completely - echo 2. Open a NEW Command Prompt - echo 3. Run scripts\setup.bat again - echo. - pause - exit /b 1 -) - -:: Check Node version >= 20 -for /f "tokens=1 delims=v." %%a in ('node --version 2^>nul') do set "NODE_RAW=%%a" -for /f "tokens=1 delims=v." %%a in ('node --version 2^>nul') do ( - for /f "tokens=1 delims=." %%b in ("%%a") do set "NODE_MAJOR=%%b" -) - -:: Robust version parse -for /f "delims=" %%v in ('node --version 2^>nul') do set "NODE_VER=%%v" -set "NODE_VER_NUM=%NODE_VER:v=%" -for /f "tokens=1 delims=." %%a in ("%NODE_VER_NUM%") do set "NODE_MAJOR=%%a" - -call :log "Node.js version: %NODE_VER%" -echo [OK] Node.js found: %NODE_VER% - -if %NODE_MAJOR% LSS %MIN_NODE_MAJOR% ( - call :error "Node.js version too old. Need %MIN_NODE_MAJOR%+, found %NODE_VER%." - echo Please upgrade Node.js to version %MIN_NODE_MAJOR% LTS or newer. - pause - exit /b 1 -) -echo. - -:: ============================================================ -:: Step 2: Check npm -:: ============================================================ -call :step "2/6" "Checking npm" - -where npm >nul 2>&1 -if errorlevel 1 ( - call :error "npm not found. This is unusual since Node.js is installed." - echo Please reinstall Node.js to fix this. - pause - exit /b 1 -) - -for /f "delims=" %%v in ('npm --version 2^>nul') do set "NPM_VER=%%v" -call :log "npm version: %NPM_VER%" -echo [OK] npm found: %NPM_VER% -echo. - -:: ============================================================ -:: Step 3: Detect network and configure mirror -:: ============================================================ -call :step "3/6" "Checking network" - -set "USE_MIRROR=0" - -:: Try reaching npm registry with a short timeout -echo Testing connection to registry.npmjs.org... -call :log "Testing npm registry connectivity..." - -:: Use curl if available (more reliable than ping for HTTPS) -where curl >nul 2>&1 -if not errorlevel 1 ( - curl -s -o nul -m 5 -w "%%{http_code}" https://registry.npmjs.org/ > "%TEMP%\npmtest.txt" 2>nul - set /p HTTP_CODE=<"%TEMP%\npmtest.txt" - del "%TEMP%\npmtest.txt" >nul 2>&1 - if "!HTTP_CODE!"=="200" ( - echo [OK] npm registry reachable. - call :log "npm registry HTTP 200 OK" - ) else ( - echo [WARN] npm registry slow or unreachable ^(code: !HTTP_CODE!^). - call :log "npm registry returned: !HTTP_CODE!" - set "USE_MIRROR=1" - ) -) else ( - :: Fallback to ping - ping -n 1 -w 3000 registry.npmjs.org >nul 2>&1 - if errorlevel 1 ( - echo [WARN] Cannot reach npm registry quickly. - set "USE_MIRROR=1" - ) else ( - echo [OK] npm registry reachable. - ) -) - -if "%USE_MIRROR%"=="1" ( - echo. - echo Slow connection detected. Switching to China mirror ^(npmmirror.com^)... - call :log "Switching to npmmirror.com" - call npm config set registry https://registry.npmmirror.com >>"%LOG_FILE%" 2>&1 - call npm config set disturl https://registry.npmmirror.com/-/binary/node >>"%LOG_FILE%" 2>&1 - call npm config set electron_mirror https://registry.npmmirror.com/-/binary/electron/ >>"%LOG_FILE%" 2>&1 - call npm config set sqlite3_binary_host_mirror https://registry.npmmirror.com/-/binary/better-sqlite3 >>"%LOG_FILE%" 2>&1 - call npm config set node_sqlite3_binary_host_mirror https://registry.npmmirror.com/-/binary/better-sqlite3 >>"%LOG_FILE%" 2>&1 - call npm config set sharp_binary_host https://registry.npmmirror.com/-/binary/sharp >>"%LOG_FILE%" 2>&1 - call npm config set sharp_libvips_binary_host https://registry.npmmirror.com/-/binary/sharp-libvips >>"%LOG_FILE%" 2>&1 - call npm config set FFMPEG_BINARIES_URL https://registry.npmmirror.com/-/binary/ffmpeg-static >>"%LOG_FILE%" 2>&1 - call npm config set @discordjs:registry https://registry.npmmirror.com >>"%LOG_FILE%" 2>&1 - echo [OK] Mirror configured. -) -echo. - -:: ============================================================ -:: Step 4: Install backend dependencies -:: ============================================================ -call :step "4/6" "Installing backend dependencies" - -if exist "node_modules\.package-lock.json" ( - echo Found existing node_modules. Checking integrity... - call :log "Existing node_modules detected, running npm install to verify" -) - -echo Running: npm install ^(this can take 5-15 minutes on slow networks^) -echo Press Ctrl+C to abort. -echo. - -call npm install >>"%LOG_FILE%" 2>&1 -if errorlevel 1 ( - call :error "Backend npm install failed." - echo. - echo Common causes: - echo - Network timeout ^(retry with VPN or check %LOG_FILE%^) - echo - Native module compile failure ^(missing Python/VS Build Tools^) - echo - Disk space full - echo. - echo Try manually: - echo cd /d "%PROJECT_ROOT%" - echo npm install --verbose - echo. - pause - exit /b 1 -) -echo [OK] Backend dependencies installed. -echo. - -:: ============================================================ -:: Step 5: Install frontend dependencies -:: ============================================================ -call :step "5/6" "Installing frontend dependencies" - -if not exist "web\package.json" ( - call :error "web\package.json not found. Repository may be incomplete." - echo Please re-clone the repository: - echo git clone https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git - pause - exit /b 1 -) - -echo Running: npm install ^(in web/ directory^) -echo. - -pushd web >nul -call npm install >>"%LOG_FILE%" 2>&1 -set "WEB_INSTALL_RESULT=!errorlevel!" -popd >nul - -if !WEB_INSTALL_RESULT! neq 0 ( - call :error "Frontend npm install failed ^(exit code !WEB_INSTALL_RESULT!^)." - echo. - echo Try manually: - echo cd /d "%PROJECT_ROOT%\web" - echo npm install --verbose - echo. - pause - exit /b 1 -) -echo [OK] Frontend dependencies installed. -echo. - -:: ============================================================ -:: Step 6: Build project (backend + frontend) -:: ============================================================ -call :step "6/6" "Building project" - -echo Running: npm run build -echo. - -call npm run build >>"%LOG_FILE%" 2>&1 -if errorlevel 1 ( - call :error "Build failed." - echo. - echo Check the log file for details: %LOG_FILE% - echo. - echo Try manually: - echo cd /d "%PROJECT_ROOT%" - echo npm run build - echo. - pause - exit /b 1 -) -echo [OK] Build succeeded. -echo. - -:: ============================================================ -:: Verify build outputs -:: ============================================================ -echo Verifying build outputs... -set "BUILD_OK=1" - -if not exist "dist" ( - call :error "dist/ directory missing after build." - set "BUILD_OK=0" -) -if not exist "web\dist" ( - call :error "web\dist/ directory missing after build." - set "BUILD_OK=0" -) - -if "!BUILD_OK!"=="0" ( - echo. - echo Build completed but expected output is missing. - echo Check %LOG_FILE% for details. - pause - exit /b 1 -) -echo [OK] Build outputs verified. -echo. - -:: ============================================================ -:: Optional: config.json hint -:: ============================================================ -if not exist "config.json" ( - echo [INFO] config.json will be auto-generated on first launch. -) else ( - echo [OK] config.json already exists. -) -echo. - -:: ============================================================ -:: Done -:: ============================================================ -call :log "Setup completed successfully at %date% %time%" - -echo ============================================ -echo Setup Complete! -echo ============================================ -echo. -echo Next steps: -echo 1. Run: scripts\start.bat -echo 2. Open: http://localhost:3000 -echo 3. Follow the in-browser setup wizard. -echo. -echo Setup log saved to: %LOG_FILE% -echo. -pause -exit /b 0 - -:: ============================================================ -:: Subroutines -:: ============================================================ -:step -echo ---- Step %~1: %~2 ---- -call :log "" -call :log "---- Step %~1: %~2 ----" -goto :eof - -:error -echo. -echo [ERROR] %~1 -call :log "[ERROR] %~1" -goto :eof - -:log -echo [%time%] %~1 >> "%LOG_FILE%" -goto :eof +@echo off +setlocal enabledelayedexpansion +chcp 65001 >nul +title TSMusicBot Setup + +:: ============================================================ +:: TSMusicBot Setup Script (Windows) +:: - Auto-detect China network, switch to npmmirror +:: - Download native binaries from CDN (避开 GitHub) +:: - 自动修复 PowerShell 环境变量 +:: ============================================================ + +set "SCRIPT_VERSION=2.1" +set "MIN_NODE_MAJOR=20" +set "LOG_FILE=%~dp0..\setup.log" +set "FAILED=0" + +:: Resolve project root (one level up from scripts/) +cd /d "%~dp0.." || ( + echo [FATAL] Cannot change to project directory. + pause + exit /b 1 +) + +set "PROJECT_ROOT=%cd%" + +:: ---- Initialize log ---- +echo. > "%LOG_FILE%" +call :log "============================================" +call :log " TSMusicBot Setup v%SCRIPT_VERSION%" +call :log " Started: %date% %time%" +call :log " Project root: %PROJECT_ROOT%" +call :log "============================================" + +echo ============================================ +echo TSMusicBot - First-Time Setup (Windows) +echo Version %SCRIPT_VERSION% +echo ============================================ +echo. +echo Log file: %LOG_FILE% +echo. + +:: ============================================================ +:: Step 1: Check Node.js +:: ============================================================ +call :step "1/7" "Checking Node.js" + +where node >nul 2>&1 +if not errorlevel 1 goto :check_node_version + +call :error "Node.js not found in PATH." +echo. +echo Please install Node.js %MIN_NODE_MAJOR% LTS or newer from: +echo https://nodejs.org/ (official) +echo https://nodejs.cn/ (China mirror, recommended) +echo. +pause +exit /b 1 + +:check_node_version +for /f "delims=" %%v in ('node --version 2^>nul') do set "NODE_VER=%%v" +for /f "tokens=1 delims=v." %%a in ("%NODE_VER%") do set "NODE_MAJOR=%%a" + +call :log "Node.js version: %NODE_VER%" +echo [OK] Node.js found: %NODE_VER% + +if %NODE_MAJOR% LSS %MIN_NODE_MAJOR% ( + call :error "Node.js version too old. Need %MIN_NODE_MAJOR%+, found %NODE_VER%." + pause + exit /b 1 +) +echo. + +:: ============================================================ +:: Step 2: Check npm +:: ============================================================ +call :step "2/7" "Checking npm" + +where npm >nul 2>&1 +if errorlevel 1 ( + call :error "npm not found." + pause + exit /b 1 +) + +for /f "delims=" %%v in ('npm --version 2^>nul') do set "NPM_VER=%%v" +call :log "npm version: %NPM_VER%" +echo [OK] npm found: %NPM_VER% +echo. + +:: ============================================================ +:: Step 3: Detect network and configure mirror +:: ============================================================ +call :step "3/7" "Checking network" + +set "USE_MIRROR=0" +set "MIRROR_REGISTRY=https://registry.npmjs.org" + +echo Testing connection to npm registry... +call :log "Testing npm registry connectivity..." + +ping -n 1 -w 4000 registry.npmjs.org >nul 2>&1 +if errorlevel 1 ( + echo [WARN] Cannot reach npm registry quickly, using China mirror. + call :log "npm registry unreachable via ping" + set "USE_MIRROR=1" +) else ( + echo [OK] npm registry reachable. + call :log "npm registry reachable" +) + +if "%USE_MIRROR%"=="1" ( + echo. + echo [INFO] Using China mirror (npmmirror.com) + call :log "Switching to npmmirror.com" + set "MIRROR_REGISTRY=https://registry.npmmirror.com" + set "CDN_MIRROR=https://cdn.npmmirror.com/binaries" +) else ( + set "CDN_MIRROR=" +) +echo. + +:: ============================================================ +:: Step 4: Install backend dependencies (跳过二进制) +:: ============================================================ +call :step "4/7" "Installing backend dependencies" + +if exist "node_modules\.package-lock.json" ( + echo Found existing node_modules. Checking integrity... +) + +echo Running: npm install --ignore-scripts (跳过 GitHub 二进制下载) +echo. + +call npm install --registry=%MIRROR_REGISTRY% --ignore-scripts >>"%LOG_FILE%" 2>&1 +if errorlevel 1 ( + call :error "Backend npm install failed." + echo Check the log: %LOG_FILE% + pause + exit /b 1 +) +echo [OK] Backend dependencies installed. +echo. + +:: ============================================================ +:: Step 4b: Download native binaries from CDN +:: ============================================================ +call :step "4b/7" "Downloading native binaries" + +node scripts/download-binaries.mjs %CDN_MIRROR% >>"%LOG_FILE%" 2>&1 +if errorlevel 1 ( + echo [WARN] Binary download had issues. Check %LOG_FILE% for details. +) else ( + echo [OK] Native binaries installed. +) +echo. + +:: ============================================================ +:: Step 5: Install frontend dependencies +:: ============================================================ +call :step "5/7" "Installing frontend dependencies" + +if not exist "web\package.json" ( + call :error "web\package.json not found." + pause + exit /b 1 +) + +echo Running: npm install (in web/) +echo. + +pushd web >nul +call npm install --registry=%MIRROR_REGISTRY% >>"%LOG_FILE%" 2>&1 +set "WEB_INSTALL_RESULT=!errorlevel!" +popd >nul + +if !WEB_INSTALL_RESULT! neq 0 ( + call :error "Frontend npm install failed." + pause + exit /b 1 +) +echo [OK] Frontend dependencies installed. +echo. + +:: ============================================================ +:: Step 6: Build project +:: ============================================================ +call :step "6/7" "Building project" + +echo Running: npm run build +echo. + +call npm run build >>"%LOG_FILE%" 2>&1 +if errorlevel 1 ( + call :error "Build failed. Check: %LOG_FILE%" + pause + exit /b 1 +) +echo [OK] Build succeeded. +echo. + +:: ============================================================ +:: Step 7: Ensure PowerShell in PATH (修复 jdymusic CDN 播放) +:: ============================================================ +call :step "7/7" "Checking PowerShell PATH" + +where powershell >nul 2>&1 +if errorlevel 1 ( + echo [WARN] PowerShell not found in PATH. + echo Attempting to fix... + set "POWERSHELL_PATH=C:\Windows\System32\WindowsPowerShell\v1.0" + if exist "!POWERSHELL_PATH!\powershell.exe" ( + :: 为用户添加永久 PATH 环境变量 + echo [INFO] Adding PowerShell to user PATH... + call setx PATH "!POWERSHELL_PATH!;%PATH%" >nul 2>&1 + echo [OK] PowerShell added to PATH. Please restart your terminal. + ) else ( + echo [WARN] Could not find powershell.exe on this system. + echo If you encounter playback issues with some NetEase songs, + echo run: set PATH=%%PATH%%;C:\Windows\System32\WindowsPowerShell\v1.0\ + echo before running scripts\start.bat + ) +) else ( + echo [OK] PowerShell found in PATH. +) +echo. + +:: ============================================================ +:: Verify build outputs +:: ============================================================ +echo Verifying build outputs... +set "BUILD_OK=1" + +if not exist "dist" ( + call :error "dist/ directory missing after build." + set "BUILD_OK=0" +) +if not exist "web\dist" ( + call :error "web\dist/ directory missing after build." + set "BUILD_OK=0" +) + +if "!BUILD_OK!"=="0" ( + echo Build completed but expected output is missing. + pause + exit /b 1 +) +echo [OK] Build outputs verified. +echo. + +if not exist "config.json" ( + echo [INFO] config.json will be auto-generated on first launch. +) else ( + echo [OK] config.json already exists. +) +echo. + +:: ============================================================ +:: Done +:: ============================================================ +call :log "Setup completed successfully at %date% %time%" + +echo ============================================ +echo Setup Complete! +echo ============================================ +echo. +echo Next steps: +echo 1. Run: scripts\start.bat +echo 2. Open: http://localhost:3000 +echo. +echo Setup log: %LOG_FILE% +echo. +pause +exit /b 0 + +:: ============================================================ +:: Subroutines +:: ============================================================ +:step +echo ---- Step %~1: %~2 ---- +call :log "" +call :log "---- Step %~1: %~2 ----" +goto :eof + +:error +echo. +echo [ERROR] %~1 +call :log "[ERROR] %~1" +goto :eof + +:log +echo [%time%] %~1 >> "%LOG_FILE%" +goto :eof + diff --git a/scripts/setup.sh b/scripts/setup.sh new file mode 100755 index 0000000..dcd0bde --- /dev/null +++ b/scripts/setup.sh @@ -0,0 +1,145 @@ +#!/usr/bin/env bash +set -euo pipefail + +# +# TSMusicBot Setup Script (Linux/macOS) +# - Auto-detect China network, switch to npmmirror +# - Download native binaries from CDN (避开 GitHub) +# - One-click setup, same as setup.bat for Windows +# + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +LOG_FILE="$PROJECT_DIR/setup.log" + +echo "============================================" +echo " TSMusicBot - First-Time Setup (Linux)" +echo "============================================" +echo "" +echo "Log file: $LOG_FILE" +echo "" + +# ---- Check Node.js ---- +if ! command -v node &>/dev/null; then + echo "[ERROR] Node.js not found. Please install Node.js 20+ from https://nodejs.org" + echo " or https://nodejs.cn/ (China mirror)." + exit 1 +fi +echo "[OK] Node.js $(node -v)" + +if ! command -v npm &>/dev/null; then + echo "[ERROR] npm not found." + exit 1 +fi +echo "[OK] npm v$(npm -v)" +echo "" + +# ---- Detect China network ---- +USE_MIRROR=0 +MIRROR_REGISTRY="https://registry.npmjs.org" +CDN_MIRROR="" + +echo "Testing connection to npm registry..." +if ping -c 1 -W 4 registry.npmjs.org &>/dev/null; then + echo "[OK] npm registry reachable." +else + echo "[WARN] Cannot reach npm registry, using China mirror." + USE_MIRROR=1 +fi + +if [ "$USE_MIRROR" = "1" ]; then + echo "[INFO] Using China mirror (npmmirror.com)" + MIRROR_REGISTRY="https://registry.npmmirror.com" + CDN_MIRROR="https://cdn.npmmirror.com/binaries" + export npm_config_registry="$MIRROR_REGISTRY" +fi +echo "" + +# ---- Check build tools (needed for native module fallback) ---- +if ! command -v gcc &>/dev/null && ! command -v clang &>/dev/null; then + echo "[INFO] No C compiler found. If CDN binaries are unavailable," + echo " native modules may fail. Install build tools:" + echo " sudo apt install build-essential (Ubuntu/Debian)" + echo " sudo yum groupinstall 'Development Tools' (CentOS/RHEL)" + echo "" +fi + +# ---- Step 1: Install dependencies (skip GitHub binaries) ---- +echo "---- 1/5: Installing Node.js dependencies ----" +echo "" + +cd "$PROJECT_DIR" +npm install --registry="$MIRROR_REGISTRY" --ignore-scripts 2>&1 | tee -a "$LOG_FILE" +echo "[OK] Dependencies installed." +echo "" + +# ---- Step 2: Download native binaries from CDN ---- +echo "---- 2/5: Downloading native binaries ----" +echo "" + +if node scripts/download-binaries.mjs $CDN_MIRROR 2>&1 | tee -a "$LOG_FILE"; then + echo "[OK] Native binaries installed." +else + echo "[WARN] Some native binaries had issues (will try source build as fallback)." +fi +echo "" + +# ---- Step 3: Install web panel dependencies ---- +echo "---- 3/5: Installing web panel dependencies ----" +echo "" + +if [ -f "web/package.json" ]; then + cd "$PROJECT_DIR/web" + npm install --registry="$MIRROR_REGISTRY" 2>&1 | tee -a "$LOG_FILE" + cd "$PROJECT_DIR" + echo "[OK] Web panel dependencies installed." +else + echo "[SKIP] web/package.json not found." +fi +echo "" + +# ---- Step 4: Build project ---- +echo "---- 4/5: Building project ----" +echo "" + +npm run build 2>&1 | tee -a "$LOG_FILE" +echo "[OK] Build succeeded." +echo "" + +# ---- Step 5: Verify ---- +echo "---- 5/5: Verifying build ----" +echo "" + +BUILD_OK=1 +if [ ! -d "dist" ]; then + echo "[ERROR] dist/ directory missing." + BUILD_OK=0 +fi +if [ -d "web" ] && [ ! -d "web/dist" ]; then + echo "[ERROR] web/dist/ directory missing." + BUILD_OK=0 +fi + +if [ "$BUILD_OK" = "0" ]; then + echo "Build completed but expected output is missing." + exit 1 +fi +echo "[OK] Build outputs verified." +echo "" + +if [ ! -f "config.json" ]; then + echo "[INFO] config.json will be auto-generated on first launch." +fi +echo "" + +echo "============================================" +echo " Setup Complete!" +echo "============================================" +echo "" +echo "Next steps:" +echo " 1. Run: npm start" +echo " 2. Open: http://localhost:3000" +echo "" +echo "Setup log: $LOG_FILE" +echo "" + diff --git a/scripts/start.bat b/scripts/start.bat index a7eb6e5..26fc9c7 100644 --- a/scripts/start.bat +++ b/scripts/start.bat @@ -1,47 +1,44 @@ -@echo off -title TSMusicBot -echo Starting TSMusicBot... -echo. +@echo off +title TSMusicBot +echo Starting TSMusicBot... +echo. + +:: Check if node is available +where node >nul 2>&1 +if %errorlevel% neq 0 ( + echo Node.js is not installed. + echo Run scripts\setup.bat first. + pause + exit /b 1 +) + +:: Resolve project root (one level up from scripts/) +cd /d "%~dp0.." + +:: Check if dependencies are installed +if not exist "node_modules" ( + echo Dependencies not found. Please run scripts\setup.bat first. + pause + exit /b 1 +) + +:: Check if build output exists +if not exist "dist" ( + echo Build not found. Please run scripts\setup.bat first. + pause + exit /b 1 +) + +:: Ensure PowerShell is in PATH (fix for jdymusic CDN playback on some systems) +where powershell >nul 2>&1 +if errorlevel 1 ( + if exist "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" ( + set "PATH=%PATH%;C:\Windows\System32\WindowsPowerShell\v1.0\" + ) +) + +:: Start the application +node dist/index.js + +pause -:: Check if node is available -where node >nul 2>&1 -if %errorlevel% neq 0 ( - echo Node.js is not installed. - echo Run scripts\setup.bat for automatic installation, or install Node.js 20+ from https://nodejs.org - pause - exit /b 1 -) - -:: Resolve project root (one level up from scripts/) -cd /d "%~dp0.." - -:: Install dependencies if needed -if not exist "node_modules" ( - echo Installing dependencies... - call npm install --production - if %errorlevel% neq 0 ( - echo Failed to install dependencies. - pause - exit /b 1 - ) -) - -:: Build if dist/ doesn't exist -if not exist "dist" ( - echo Building project... - call npx tsc - if %errorlevel% neq 0 ( - echo Build failed. - pause - exit /b 1 - ) -) - -:: FFmpeg is bundled via ffmpeg-static — no PATH check needed. -echo FFmpeg is bundled via node_modules (ffmpeg-static). -echo. - -:: Start the application -node dist/index.js - -pause