mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-01 20:42:50 +08:00
feat: bundle FFmpeg via ffmpeg-static for one-click deployment
Users no longer need to install FFmpeg separately — it is now bundled as an npm dependency (ffmpeg-static). player.ts resolves the bundled binary automatically and falls back to system PATH. start.bat and a new setup.bat script handle dependency installation and project building. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
00231db0cb
commit
61d9bbe0b7
5 files changed
+1033
-17
No files matched your search
Generated
+897
File diff suppressed because it is too large.
Load diff
@@ -15,9 +15,16 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/opus": "^0.10.0",
|
"@discordjs/opus": "^0.10.0",
|
||||||
"@honeybbq/teamspeak-client": "^0.1.0",
|
"@honeybbq/teamspeak-client": "^0.1.0",
|
||||||
|
"@koa/router": "^15.4.0",
|
||||||
|
"@sansenjian/qq-music-api": "^2.2.9",
|
||||||
"axios": "^1.14.0",
|
"axios": "^1.14.0",
|
||||||
"better-sqlite3": "^12.8.0",
|
"better-sqlite3": "^12.8.0",
|
||||||
|
"chalk": "^5.6.2",
|
||||||
"express": "^5.2.1",
|
"express": "^5.2.1",
|
||||||
|
"ffmpeg-static": "^5.3.0",
|
||||||
|
"koa": "^3.2.0",
|
||||||
|
"koa-bodyparser": "^4.4.1",
|
||||||
|
"koa-static": "^5.0.0",
|
||||||
"NeteaseCloudMusicApi": "^4.30.0",
|
"NeteaseCloudMusicApi": "^4.30.0",
|
||||||
"pino": "^10.3.1",
|
"pino": "^10.3.1",
|
||||||
"ts3-nodejs-library": "^3.5.1",
|
"ts3-nodejs-library": "^3.5.1",
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
@echo off
|
||||||
|
title TSMusicBot Setup
|
||||||
|
echo ============================================
|
||||||
|
echo TSMusicBot - First-Time Setup (Windows)
|
||||||
|
echo ============================================
|
||||||
|
echo.
|
||||||
|
|
||||||
|
:: Resolve project root (one level up from scripts/)
|
||||||
|
cd /d "%~dp0.."
|
||||||
|
|
||||||
|
:: ---- Step 1: Check / install Node.js ----
|
||||||
|
where node >nul 2>&1
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo Node.js not found. Attempting automatic installation...
|
||||||
|
echo.
|
||||||
|
|
||||||
|
:: Try winget first (available on Windows 10 1709+ and Windows 11)
|
||||||
|
where winget >nul 2>&1
|
||||||
|
if %errorlevel% equ 0 (
|
||||||
|
echo Installing Node.js via winget...
|
||||||
|
winget install OpenJS.NodeJS.LTS --accept-source-agreements --accept-package-agreements
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo winget installation failed. Please install Node.js manually from https://nodejs.org
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
:: Refresh PATH so node is available in this session
|
||||||
|
call refreshenv >nul 2>&1
|
||||||
|
:: If refreshenv is not available, ask user to restart
|
||||||
|
where node >nul 2>&1
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo Node.js was installed but is not yet available in this terminal.
|
||||||
|
echo Please close this window and run setup.bat again.
|
||||||
|
pause
|
||||||
|
exit /b 0
|
||||||
|
)
|
||||||
|
) else (
|
||||||
|
echo winget is not available on this system.
|
||||||
|
echo Please install Node.js 20 LTS manually from https://nodejs.org
|
||||||
|
echo After installing, close this window and run setup.bat again.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
) else (
|
||||||
|
echo [OK] Node.js found.
|
||||||
|
node --version
|
||||||
|
)
|
||||||
|
echo.
|
||||||
|
|
||||||
|
:: ---- Step 2: Install npm dependencies ----
|
||||||
|
echo Installing dependencies (this may take a few minutes)...
|
||||||
|
call npm install
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo npm install failed. Check the error messages above.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
echo [OK] Dependencies installed.
|
||||||
|
echo.
|
||||||
|
|
||||||
|
:: ---- Step 3: Build the project ----
|
||||||
|
echo Building TypeScript project...
|
||||||
|
call npx tsc
|
||||||
|
if %errorlevel% neq 0 (
|
||||||
|
echo.
|
||||||
|
echo Build failed. Check the error messages above.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
echo [OK] Build succeeded.
|
||||||
|
echo.
|
||||||
|
|
||||||
|
:: ---- Step 4: Create default config if missing ----
|
||||||
|
if not exist "config.json" (
|
||||||
|
echo Creating default config.json...
|
||||||
|
echo Please edit config.json with your TeamSpeak server details before starting the bot.
|
||||||
|
) else (
|
||||||
|
echo [OK] config.json already exists.
|
||||||
|
)
|
||||||
|
echo.
|
||||||
|
|
||||||
|
:: ---- Done ----
|
||||||
|
echo ============================================
|
||||||
|
echo Setup complete!
|
||||||
|
echo ============================================
|
||||||
|
echo.
|
||||||
|
echo To start the bot, run: scripts\start.bat
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
+24
-16
@@ -6,34 +6,42 @@ echo.
|
|||||||
:: Check if node is available
|
:: Check if node is available
|
||||||
where node >nul 2>&1
|
where node >nul 2>&1
|
||||||
if %errorlevel% neq 0 (
|
if %errorlevel% neq 0 (
|
||||||
echo Node.js is not installed. Please install Node.js 20 LTS from https://nodejs.org
|
echo Node.js is not installed.
|
||||||
|
echo Run scripts\setup.bat for automatic installation, or install Node.js 20+ from https://nodejs.org
|
||||||
pause
|
pause
|
||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
|
||||||
:: Check if ffmpeg is available
|
:: Resolve project root (one level up from scripts/)
|
||||||
where ffmpeg >nul 2>&1
|
cd /d "%~dp0.."
|
||||||
if %errorlevel% neq 0 (
|
|
||||||
echo FFmpeg not found in PATH. Checking local directory...
|
:: Install dependencies if needed
|
||||||
if exist "%~dp0ffmpeg\ffmpeg.exe" (
|
if not exist "node_modules" (
|
||||||
set PATH=%~dp0ffmpeg;%PATH%
|
echo Installing dependencies...
|
||||||
echo Using bundled FFmpeg.
|
call npm install --production
|
||||||
) else (
|
if %errorlevel% neq 0 (
|
||||||
echo FFmpeg is required. Please install FFmpeg or place it in the ffmpeg\ directory.
|
echo Failed to install dependencies.
|
||||||
pause
|
pause
|
||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
:: Install dependencies if needed
|
:: Build if dist/ doesn't exist
|
||||||
if not exist "%~dp0node_modules" (
|
if not exist "dist" (
|
||||||
echo Installing dependencies...
|
echo Building project...
|
||||||
cd /d "%~dp0"
|
call npx tsc
|
||||||
call npm install --production
|
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
|
:: Start the application
|
||||||
cd /d "%~dp0"
|
|
||||||
node dist/index.js
|
node dist/index.js
|
||||||
|
|
||||||
pause
|
pause
|
||||||
+14
-1
@@ -1,8 +1,19 @@
|
|||||||
import { spawn, type ChildProcess } from "node:child_process";
|
import { spawn, type ChildProcess } from "node:child_process";
|
||||||
import { EventEmitter } from "node:events";
|
import { EventEmitter } from "node:events";
|
||||||
|
import { createRequire } from "node:module";
|
||||||
import { createOpusEncoder, PCM_FRAME_BYTES, type Encoder } from "./encoder.js";
|
import { createOpusEncoder, PCM_FRAME_BYTES, type Encoder } from "./encoder.js";
|
||||||
import type { Logger } from "../logger.js";
|
import type { Logger } from "../logger.js";
|
||||||
|
|
||||||
|
// ffmpeg-static is a CJS module that exports the path to the bundled ffmpeg binary.
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
const ffmpegPath: string | null = require("ffmpeg-static");
|
||||||
|
|
||||||
|
/** Resolve ffmpeg binary: prefer bundled ffmpeg-static, fall back to system PATH. */
|
||||||
|
function getFfmpegCommand(): string {
|
||||||
|
if (ffmpegPath) return ffmpegPath;
|
||||||
|
return "ffmpeg"; // fallback to system-installed ffmpeg
|
||||||
|
}
|
||||||
|
|
||||||
export interface PlayerEvents {
|
export interface PlayerEvents {
|
||||||
frame: (opusFrame: Buffer) => void;
|
frame: (opusFrame: Buffer) => void;
|
||||||
trackEnd: () => void;
|
trackEnd: () => void;
|
||||||
@@ -57,7 +68,9 @@ export class AudioPlayer extends EventEmitter {
|
|||||||
"-",
|
"-",
|
||||||
);
|
);
|
||||||
|
|
||||||
this.ffmpeg = spawn("ffmpeg", args, { stdio: ["ignore", "pipe", "pipe"] });
|
const ffmpegBin = getFfmpegCommand();
|
||||||
|
this.logger.debug({ ffmpeg: ffmpegBin }, "Using ffmpeg binary");
|
||||||
|
this.ffmpeg = spawn(ffmpegBin, args, { stdio: ["ignore", "pipe", "pipe"] });
|
||||||
|
|
||||||
this.ffmpeg.stderr!.on("data", () => {});
|
this.ffmpeg.stderr!.on("data", () => {});
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user