From d2255b5951a45965cc64e9fec950ed610b7858e9 Mon Sep 17 00:00:00 2001 From: auto-bot Date: Sat, 13 Jun 2026 17:11:28 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=AB=AF=E5=8F=A3=E6=94=B9=E4=B8=BA=20?= =?UTF-8?q?1219=EF=BC=8Cinstall.sh=20=E6=94=AF=E6=8C=81=20systemd=20?= =?UTF-8?q?=E5=90=8E=E5=8F=B0=E9=83=A8=E7=BD=B2=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E9=9D=9E=20git=20=E4=BB=93=E5=BA=93=E6=97=B6?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=87=8D=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +- deploy.sh | 4 +- install.sh | 218 +++++++++++++++++++++++++++++--------------- package.json | 2 +- qzmusic-web.service | 18 ++++ server.cjs | 142 +++++++++++++++++++---------- start.sh | 6 +- uninstall.sh | 125 +++++++++++++------------ vite.config.ts | 2 +- 9 files changed, 334 insertions(+), 193 deletions(-) create mode 100644 qzmusic-web.service diff --git a/README.md b/README.md index 20d0d3b..c566cc7 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ QZMusic 网页版,基于 Vue 3 + TypeScript + Vite 构建的音乐播放器, - 📊 音频可视化(基于 Web Audio API) - 🔍 搜索功能 - 🔌 **插件系统** - 支持通过插件获取音乐资源 -- 🌐 默认端口:10096 +- 🌐 默认端口:1219 ## 快速开始 @@ -62,7 +62,7 @@ bash uninstall.sh 卸载将删除: - 安装目录(`/opt/QZMusic-Web`) -- 端口 10096 上的所有进程 +- 端口 1219 上的所有进程 - Systemd 服务(如有) - npm 全局包(如有) - 相关缓存文件 @@ -81,7 +81,7 @@ npm install npm run dev ``` -服务器将在 http://localhost:10096 启动 +服务器将在 http://localhost:1219 启动 ### 构建生产版本 @@ -101,9 +101,9 @@ npm run preview | 命令 | 说明 | |------|------| -| `npm run dev` | 启动开发服务器(端口 10096) | +| `npm run dev` | 启动开发服务器(端口 1219) | | `npm run build` | 构建生产版本 | -| `npm run preview` | 预览生产构建(端口 10096) | +| `npm run preview` | 预览生产构建(端口 1219) | | `npm run deploy` | 一键部署(安装依赖 + 构建) | | `npm run start` | 一键启动(自动安装依赖 + 启动) | | `npm run install-app` | 一键安装(从仓库安装到 /opt) | diff --git a/deploy.sh b/deploy.sh index 422bf73..23fceca 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,7 +1,7 @@ #!/bin/bash # QZMusic-Web 一键部署脚本 -# 端口:10096 +# 端口:1219 echo "==========================================" echo " QZMusic-Web 一键部署" @@ -59,5 +59,5 @@ echo "🚀 启动方式:" echo " 开发模式: npm run dev" echo " 预览模式: npm run preview" echo "" -echo "🌐 访问地址: http://localhost:10096" +echo "🌐 访问地址: http://localhost:1219" echo "" diff --git a/install.sh b/install.sh index 3586491..adace32 100755 --- a/install.sh +++ b/install.sh @@ -1,138 +1,206 @@ #!/bin/bash # QZMusic-Web 一键安装脚本 -# 从Gitea仓库获取并自动部署 -# 使用方法: bash <(curl -sL http://171.80.3.149:4321/miao-moe/QZMusic-Web/raw/branch/master/install.sh) -# 或者直接运行此脚本 +# 从 Gitea 仓库获取并自动部署,安装后以 systemd 服务对外暴露 1219 端口 +# 使用方法: +# bash <(curl -sL http://171.80.3.149:4321/miao-moe/QZMusic-Web/raw/branch/master/install.sh) +# 或直接在项目目录运行: ./install.sh set -e echo "==========================================" -echo " QZMusic-Web 一键安装" +echo " QZMusic-Web 一键安装 (systemd)" echo "==========================================" echo "" -# 配置 +# ========= 配置 ========= REPO_URL="http://171.80.3.149:4321/miao-moe/QZMusic-Web.git" INSTALL_DIR="/opt/QZMusic-Web" -PORT=10096 +PORT=1219 +SERVICE_NAME="qzmusic-web" +BRANCH="master" -# 颜色定义 +# ========= 颜色 ========= GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' -NC='\033[0m' # No Color +NC='\033[0m' -log_info() { - echo -e "${GREEN}[INFO]${NC} $1" -} +log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } +log_error() { echo -e "${RED}[ERROR]${NC} $1"; } -log_warn() { - echo -e "${YELLOW}[WARN]${NC} $1" -} - -log_error() { - echo -e "${RED}[ERROR]${NC} $1" -} - -# 检查是否以root运行 +# ========= 权限 ========= +SUDO="" if [ "$EUID" -ne 0 ]; then - log_warn "建议使用 root 权限运行以获得最佳体验" + SUDO="sudo" + log_warn "当前非 root,将使用 sudo 执行系统级操作。" fi -# 检查Node.js +# ========= Node.js 检查 ========= if ! command -v node &> /dev/null; then - log_error "Node.js 未安装!请先安装 Node.js" - echo "安装 Node.js:" - echo " Ubuntu/Debian: sudo apt-get install nodejs npm" - echo " CentOS/RHEL: sudo yum install nodejs npm" - echo " 或访问: https://nodejs.org/" + log_error "Node.js 未安装!请先安装 Node.js (推荐 v18+)" + echo " Ubuntu/Debian: curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - && sudo apt-get install -y nodejs" + echo " CentOS/RHEL: curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash - && sudo yum install -y nodejs" exit 1 fi - log_info "Node.js 版本: $(node -v)" log_info "npm 版本: $(npm -v)" echo "" -# 检查是否已存在安装目录 +# ========= 克隆/拉取代码 ========= if [ -d "$INSTALL_DIR" ]; then - log_warn "检测到已存在的安装目录: $INSTALL_DIR" - read -p "是否更新到最新版本?(y/n): " update_choice - if [ "$update_choice" != "y" ] && [ "$update_choice" != "Y" ]; then - log_info "取消安装" - exit 0 - fi - - log_info "正在更新到最新版本..." - cd "$INSTALL_DIR" - git pull origin master - if [ $? -ne 0 ]; then - log_error "更新失败!" - exit 1 + if [ -d "$INSTALL_DIR/.git" ]; then + log_info "检测到已有 git 仓库,正在更新到最新版本..." + cd "$INSTALL_DIR" + git fetch origin "$BRANCH" + git reset --hard "origin/$BRANCH" + if [ $? -ne 0 ]; then + log_error "更新失败!" + exit 1 + fi + else + log_warn "目录 $INSTALL_DIR 已存在但不是 git 仓库,将清理后重新克隆..." + $SUDO rm -rf "$INSTALL_DIR" + log_info "正在从仓库获取代码 ($REPO_URL)..." + $SUDO git clone -b "$BRANCH" "$REPO_URL" "$INSTALL_DIR" + $SUDO chown -R "$(whoami)" "$INSTALL_DIR" 2>/dev/null || true fi else - # 创建安装目录 log_info "正在创建安装目录: $INSTALL_DIR" - sudo mkdir -p "$INSTALL_DIR" - - # 克隆仓库 - log_info "正在从仓库获取代码..." - if ! git clone "$REPO_URL" "$INSTALL_DIR"; then - log_error "克隆仓库失败!" - exit 1 - fi + $SUDO mkdir -p "$(dirname "$INSTALL_DIR")" + log_info "正在从仓库获取代码 ($REPO_URL)..." + $SUDO git clone -b "$BRANCH" "$REPO_URL" "$INSTALL_DIR" + $SUDO chown -R "$(whoami)" "$INSTALL_DIR" 2>/dev/null || true fi +cd "$INSTALL_DIR" echo "" -# 进入安装目录 -cd "$INSTALL_DIR" - -# 安装依赖 -log_info "正在安装依赖..." -npm install --registry=https://registry.npmmirror.com - +# ========= 安装依赖 ========= +log_info "正在安装依赖 (使用淘宝镜像加速)..." +npm install --registry=https://registry.npmmirror.com --loglevel=error if [ $? -ne 0 ]; then log_error "依赖安装失败!" exit 1 fi - log_info "依赖安装成功!" echo "" -# 构建项目 +# ========= 构建 ========= log_info "正在构建项目..." npm run build - if [ $? -ne 0 ]; then log_error "构建失败!" exit 1 fi - log_info "项目构建成功!" echo "" -# 检查端口占用 -if lsof -Pi :$PORT -sTCP:LISTEN -t >/dev/null 2>&1; then - log_warn "端口 $PORT 已被占用,尝试停止现有进程..." - PID=$(lsof -ti:$PORT) - kill $PID 2>/dev/null || true - sleep 2 +# ========= 部署 systemd 服务 ========= +log_info "正在部署 systemd 服务: $SERVICE_NAME" + +SERVICE_FILE="/etc/systemd/system/$SERVICE_NAME.service" + +# 停止旧的监听(以防之前有进程占端口) +if command -v lsof &> /dev/null; then + OLD_PID=$(lsof -ti:$PORT 2>/dev/null || true) + if [ -n "$OLD_PID" ]; then + log_warn "端口 $PORT 已被占用 (PID: $OLD_PID),正在清理..." + $SUDO kill $OLD_PID 2>/dev/null || true + sleep 2 + fi fi +# 如果之前有同名服务,先停掉 +if systemctl list-unit-files 2>/dev/null | grep -q "$SERVICE_NAME.service"; then + $SUDO systemctl stop "$SERVICE_NAME" 2>/dev/null || true + $SUDO systemctl disable "$SERVICE_NAME" 2>/dev/null || true +fi + +# 写入服务文件 +$SUDO tee "$SERVICE_FILE" > /dev/null < /dev/null && systemctl is-active --quiet firewalld 2>/dev/null; then + $SUDO firewall-cmd --permanent --add-port=${PORT}/tcp >/dev/null + $SUDO firewall-cmd --reload >/dev/null + log_info "firewalld: 已放行 $PORT/tcp" +elif command -v ufw &> /dev/null && systemctl is-active --quiet ufw 2>/dev/null; then + $SUDO ufw allow ${PORT}/tcp >/dev/null + log_info "ufw: 已放行 $PORT/tcp" +else + log_warn "未检测到活动的 firewalld/ufw,跳过防火墙配置。如有其他防火墙请手动放行 $PORT/tcp。" +fi + +# ========= 云服务器安全组提醒 ========= +log_info "已处理系统防火墙。如果你的机器是云服务器,请记得在云厂商控制台的『安全组』也放行 $PORT/tcp。" +echo "" + +# ========= 验证 ========= +log_info "等待服务启动..." +for i in 1 2 3 4 5; do + if curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:$PORT/" 2>/dev/null | grep -q "200"; then + break + fi + sleep 1 +done + +HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://127.0.0.1:$PORT/" 2>/dev/null || echo "000") +STATUS=$($SUDO systemctl is-active "$SERVICE_NAME" 2>/dev/null || echo "unknown") + +# 获取本机公网/局域网 IP +LAN_IP=$(hostname -I 2>/dev/null | awk '{print $1}') +WAN_IP=$(curl -s --max-time 5 https://ifconfig.me 2>/dev/null || curl -s --max-time 5 https://api.ipify.org 2>/dev/null || echo "") + echo "" echo "==========================================" echo " 🎉 安装完成!" echo "==========================================" echo "" echo "📂 安装目录: $INSTALL_DIR" -echo "🌐 访问地址: http://localhost:$PORT" -echo "" -echo "启动服务:" -echo " 开发模式: cd $INSTALL_DIR && npm run dev" -echo " 生产模式: cd $INSTALL_DIR && npm run preview" +echo "🖥 服务状态: $STATUS" +echo "🌐 本地访问: http://127.0.0.1:$PORT (HTTP $HTTP_CODE)" +if [ -n "$LAN_IP" ]; then + echo "🏠 局域网: http://$LAN_IP:$PORT" +fi +if [ -n "$WAN_IP" ]; then + echo "🌍 公网: http://$WAN_IP:$PORT" +fi echo "" echo "管理命令:" -echo " 更新: cd $INSTALL_DIR && git pull" -echo " 卸载: cd $INSTALL_DIR && npm run uninstall" +echo " 查看日志: sudo journalctl -u $SERVICE_NAME -f --since \"5 min ago\"" +echo " 启动服务: sudo systemctl start $SERVICE_NAME" +echo " 停止服务: sudo systemctl stop $SERVICE_NAME" +echo " 重启服务: sudo systemctl restart $SERVICE_NAME" +echo " 开机自启: sudo systemctl enable $SERVICE_NAME" +echo " 更新代码: cd $INSTALL_DIR && git pull && npm run build && sudo systemctl restart $SERVICE_NAME" +echo "" +echo "卸载/清除所有部署: bash $INSTALL_DIR/uninstall.sh" echo "" diff --git a/package.json b/package.json index 2bb9211..aa29eab 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "scripts": { "dev": "vite", "build": "vue-tsc && vite build", - "preview": "vite preview --port 10096 --host", + "preview": "vite preview --port 1219 --host", "serve": "node server.cjs", "deploy": "./deploy.sh", "start": "./start.sh", diff --git a/qzmusic-web.service b/qzmusic-web.service new file mode 100644 index 0000000..516f2ed --- /dev/null +++ b/qzmusic-web.service @@ -0,0 +1,18 @@ +[Unit] +Description=QZMusic Web Server +After=network.target + +[Service] +Type=simple +WorkingDirectory=/opt/QZMusic-Web +ExecStart=/usr/bin/env node server.cjs +Restart=always +RestartSec=3 +Environment=NODE_ENV=production +Environment=QZMUSIC_PORT=1219 +Environment=QZMUSIC_HOST=0.0.0.0 +StandardOutput=journal +StandardError=journal + +[Install] +WantedBy=multi-user.target diff --git a/server.cjs b/server.cjs index decb2f4..1e57678 100644 --- a/server.cjs +++ b/server.cjs @@ -1,69 +1,119 @@ /** - * QZMusic Web 静态文件服务器 - * 外网访问支持 + * QZMusic Web 静态文件服务器(生产用) + * 监听 0.0.0.0:1219,支持公网访问 */ const http = require('http'); const fs = require('fs'); const path = require('path'); +const url = require('url'); -const PORT = 10096; +const PORT = parseInt(process.env.QZMUSIC_PORT || '1219', 10); +const HOST = process.env.QZMUSIC_HOST || '0.0.0.0'; const ROOT = path.join(__dirname, 'dist'); const mimeTypes = { - '.html': 'text/html', - '.js': 'text/javascript', - '.css': 'text/css', - '.json': 'application/json', - '.png': 'image/png', - '.jpg': 'image/jpg', - '.gif': 'image/gif', - '.svg': 'image/svg+xml', - '.ico': 'image/x-icon', - '.ttf': 'font/ttf', + '.html': 'text/html; charset=utf-8', + '.htm': 'text/html; charset=utf-8', + '.js': 'application/javascript; charset=utf-8', + '.mjs': 'application/javascript; charset=utf-8', + '.css': 'text/css; charset=utf-8', + '.json': 'application/json; charset=utf-8', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.gif': 'image/gif', + '.webp': 'image/webp', + '.svg': 'image/svg+xml', + '.ico': 'image/x-icon', + '.ttf': 'font/ttf', '.woff': 'font/woff', - '.woff2': 'font/woff2' + '.woff2':'font/woff2', + '.map': 'application/json; charset=utf-8', + '.txt': 'text/plain; charset=utf-8' }; +function log(...args) { + const ts = new Date().toISOString().replace('T', ' ').substring(0, 19); + console.log(`[${ts}]`, ...args); +} + const server = http.createServer((req, res) => { - let filePath = path.join(ROOT, req.url === '/' ? 'index.html' : req.url); - - const extname = String(path.extname(filePath)).toLowerCase(); - const contentType = mimeTypes[extname] || 'application/octet-stream'; - - if (!extname && !fs.existsSync(filePath)) { - filePath = path.join(ROOT, 'index.html'); + const parsed = url.parse(req.url); + let pathname = decodeURIComponent(parsed.pathname || '/'); + if (pathname === '/') pathname = '/index.html'; + + let filePath = path.join(ROOT, pathname); + + // 防止路径穿越 + if (!filePath.startsWith(ROOT)) { + res.writeHead(403); + res.end('Forbidden'); + return; } - fs.readFile(filePath, (error, content) => { - if (error) { - if (error.code === 'ENOENT') { - fs.readFile(path.join(ROOT, 'index.html'), (err, html) => { - res.writeHead(200, { 'Content-Type': 'text/html' }); - res.end(html, 'utf-8'); + const extname = String(path.extname(filePath)).toLowerCase(); + const contentType = mimeTypes[extname] || 'application/octet-stream'; + + // SPA 路由:如果不是带扩展名的文件且文件不存在,则回退到 index.html + const tryStatic = (cb) => { + fs.stat(filePath, (err, stat) => { + if (!err && stat.isDirectory()) { + filePath = path.join(filePath, 'index.html'); + return fs.stat(filePath, (e2, s2) => { + if (!e2 && s2.isFile()) return cb(true); + return cb(false); }); - } else { - res.writeHead(500); - res.end('Sorry, check with the site admin for error: ' + error.code + ' ..\n'); } - } else { - res.writeHead(200, { 'Content-Type': contentType }); - res.end(content, 'utf-8'); + if (!err && stat.isFile()) return cb(true); + return cb(false); + }); + }; + + tryStatic((found) => { + if (!found) { + filePath = path.join(ROOT, 'index.html'); } + fs.readFile(filePath, (error, content) => { + if (error) { + log(`${req.method} ${req.url} -> 500 (${error.code})`); + res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' }); + res.end('Server Error: ' + error.code); + } else { + const finalType = found ? contentType : 'text/html; charset=utf-8'; + res.writeHead(200, { + 'Content-Type': finalType, + 'Cache-Control': extname === '.html' || extname === '.htm' + ? 'no-cache, no-store, must-revalidate' + : 'public, max-age=3600' + }); + res.end(content); + log(`${req.method} ${req.url} -> 200 (${pathname})`); + } + }); }); }); -server.listen(PORT, '0.0.0.0', () => { - console.log(` -╔═══════════════════════════════════════════════════════════════════════╗ -║ ║ -║ QZMusic Web Server 启动成功! ║ -║ ║ -║ 本地访问:http://localhost:${PORT} ║ -║ 局域网访问:http://[你的IP]:${PORT} ║ -║ ║ -║ 外网访问:请配置端口转发/公网IP访问 ║ -║ ║ -╚═══════════════════════════════════════════════════════════════════════╝ - `); +server.listen(PORT, HOST, () => { + const banner = ` +╔══════════════════════════════════════════════════════════════╗ +║ ║ +║ QZMusic Web Server 启动成功! ║ +║ ║ +║ 监听地址: http://${HOST}:${PORT} ║ +║ 本地访问: http://localhost:${PORT} ║ +║ 公网访问: http://[你的公网IP]:${PORT} ║ +║ ║ +╚══════════════════════════════════════════════════════════════╝ +`; + console.log(banner); +}); + +process.on('SIGINT', () => { + log('收到 SIGINT,正在关闭服务器...'); + server.close(() => process.exit(0)); +}); +process.on('SIGTERM', () => { + log('收到 SIGTERM,正在关闭服务器...'); + server.close(() => process.exit(0)); }); diff --git a/start.sh b/start.sh index adc56d1..c9c8a2a 100755 --- a/start.sh +++ b/start.sh @@ -1,7 +1,7 @@ #!/bin/bash # QZMusic-Web 启动脚本 -# 端口:10096 +# 端口:1219 echo "==========================================" echo " 启动 QZMusic-Web" @@ -28,7 +28,7 @@ case ${choice:-2} in 1) echo "" echo "🚀 正在启动开发服务器..." - echo "🌐 访问地址: http://localhost:10096" + echo "🌐 访问地址: http://localhost:1219" echo "" echo "按 Ctrl+C 停止服务器" echo "" @@ -46,7 +46,7 @@ case ${choice:-2} in fi echo "" echo "🚀 正在启动生产服务器..." - echo "🌐 访问地址: http://[你的IP]:10096" + echo "🌐 访问地址: http://[你的IP]:1219" echo "" echo "按 Ctrl+C 停止服务器" echo "" diff --git a/uninstall.sh b/uninstall.sh index 0da0788..2fba8e3 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -1,109 +1,114 @@ #!/bin/bash -# QZMusic-Web 卸载脚本 -# 完全删除所有QZMusic部署文件和配置 +# QZMusic-Web 卸载脚本 - 完全停止并删除所有 QZMusic-Web 部署 set -e echo "==========================================" -echo " QZMusic-Web 卸载工具" +echo " QZMusic-Web 完全卸载" echo "==========================================" echo "" -# 配置 +# ========= 配置 ========= INSTALL_DIR="/opt/QZMusic-Web" -PORT=10096 +PORT=1219 SERVICE_NAME="qzmusic-web" -# 颜色定义 GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' -log_info() { - echo -e "${GREEN}[INFO]${NC} $1" -} +log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } +log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } +log_error() { echo -e "${RED}[ERROR]${NC} $1"; } -log_warn() { - echo -e "${YELLOW}[WARN]${NC} $1" -} +SUDO="" +if [ "$EUID" -ne 0 ]; then + SUDO="sudo" +fi -log_error() { - echo -e "${RED}[ERROR]${NC} $1" -} - -# 确认卸载 +# ========= 确认 ========= echo "⚠️ 即将卸载 QZMusic-Web" echo "" -read -p "确定要删除所有相关文件吗?(yes/no): " confirm - +echo "将执行以下操作:" +echo " - 停止并禁用 systemd 服务 $SERVICE_NAME" +echo " - 删除服务文件 /etc/systemd/system/$SERVICE_NAME.service" +echo " - 杀掉占用 $PORT 端口的进程" +echo " - 删除目录 $INSTALL_DIR" +echo " - 关闭防火墙 $PORT/tcp 放行" +echo "" +read -p "确认删除?输入 yes 继续: " confirm if [ "$confirm" != "yes" ]; then log_info "取消卸载" exit 0 fi - echo "" -# 停止服务 -log_info "正在停止服务..." - -# 停止开发服务器 -PID=$(lsof -ti:$PORT 2>/dev/null || true) -if [ -n "$PID" ]; then - log_info "停止进程 (PID: $PID)..." - kill $PID 2>/dev/null || true - sleep 1 +# ========= 停止服务 ========= +log_info "停止 systemd 服务..." +if systemctl list-unit-files 2>/dev/null | grep -q "$SERVICE_NAME.service"; then + $SUDO systemctl stop "$SERVICE_NAME" 2>/dev/null || true + $SUDO systemctl disable "$SERVICE_NAME" 2>/dev/null || true + log_info "服务已停止 & 禁用" +else + log_warn "未检测到 systemd 服务 $SERVICE_NAME,跳过" fi -# 停止Systemd服务(如果存在) -if systemctl is-active --quiet $SERVICE_NAME 2>/dev/null; then - log_info "停止 Systemd 服务..." - sudo systemctl stop $SERVICE_NAME - sudo systemctl disable $SERVICE_NAME +# ========= 删除服务文件 ========= +SERVICE_FILE="/etc/systemd/system/$SERVICE_NAME.service" +if [ -f "$SERVICE_FILE" ]; then + $SUDO rm -f "$SERVICE_FILE" + $SUDO systemctl daemon-reload + log_info "已删除服务文件: $SERVICE_FILE" fi -# 删除Systemd服务文件 -if [ -f "/etc/systemd/system/$SERVICE_NAME.service" ]; then - log_info "删除 Systemd 服务文件..." - sudo rm -f /etc/systemd/system/$SERVICE_NAME.service - sudo systemctl daemon-reload +# ========= 杀端口 ========= +if command -v lsof &> /dev/null; then + OLD_PID=$(lsof -ti:$PORT 2>/dev/null || true) + if [ -n "$OLD_PID" ]; then + log_info "杀掉占用 $PORT 的进程: $OLD_PID" + $SUDO kill $OLD_PID 2>/dev/null || true + fi fi -echo "" - -# 删除安装目录 +# ========= 删除目录 ========= if [ -d "$INSTALL_DIR" ]; then - log_info "删除安装目录: $INSTALL_DIR" - sudo rm -rf "$INSTALL_DIR" + log_info "删除目录: $INSTALL_DIR" + $SUDO rm -rf "$INSTALL_DIR" +else + log_warn "目录不存在: $INSTALL_DIR" fi -# 删除npm全局链接(如果有) -if npm list -g --depth=0 2>/dev/null | grep -q "qzmusic-web"; then - log_info "删除 npm 全局包..." - sudo npm uninstall -g qzmusic-web 2>/dev/null || true +# ========= 关闭防火墙端口 ========= +log_info "关闭防火墙 $PORT/tcp 放行..." +if command -v firewall-cmd &> /dev/null && systemctl is-active --quiet firewalld 2>/dev/null; then + $SUDO firewall-cmd --permanent --remove-port=${PORT}/tcp >/dev/null 2>&1 || true + $SUDO firewall-cmd --reload >/dev/null + log_info "firewalld: 已关闭 $PORT/tcp" +elif command -v ufw &> /dev/null && systemctl is-active --quiet ufw 2>/dev/null; then + $SUDO ufw delete allow ${PORT}/tcp >/dev/null 2>&1 || true + log_info "ufw: 已关闭 $PORT/tcp" +else + log_warn "未检测到活动的 firewalld/ufw,跳过防火墙配置。" fi -# 删除相关缓存 -log_info "清理缓存..." - -# 删除npm缓存 +# ========= 清理缓存 ========= +log_info "清理 npm 缓存..." if [ -d "$HOME/.npm/_cacache" ]; then - npm cache clean --force 2>/dev/null || true + npm cache clean --force >/dev/null 2>&1 || true fi - -# 删除可能的临时文件 -sudo rm -rf /tmp/QZMusic* 2>/dev/null || true -sudo rm -rf /var/tmp/QZMusic* 2>/dev/null || true +$SUDO rm -rf /tmp/QZMusic* /var/tmp/QZMusic* 2>/dev/null || true echo "" echo "==========================================" echo " ✅ 卸载完成!" echo "==========================================" echo "" -echo "已删除:" -echo " - 安装目录: $INSTALL_DIR" -echo " - 服务端口: $PORT" +echo "已清理:" +echo " - 目录: $INSTALL_DIR" +echo " - systemd 服务: $SERVICE_NAME" +echo " - 端口: $PORT" echo " - 相关缓存" echo "" echo "如需重新安装,请运行:" diff --git a/vite.config.ts b/vite.config.ts index 9884252..2ccfbae 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -21,7 +21,7 @@ export default defineConfig({ } }, server: { - port: 10096, + port: 1219, host: '0.0.0.0', open: false },