#!/bin/bash # QZMusic-Web 一键安装脚本 # 从 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 一键安装 (systemd)" echo "==========================================" echo "" # ========= 配置 ========= REPO_URL="http://171.80.3.149:4321/miao-moe/QZMusic-Web.git" INSTALL_DIR="/opt/QZMusic-Web" PORT=1219 SERVICE_NAME="qzmusic-web" BRANCH="master" # ========= 颜色 ========= GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } # ========= 权限 ========= SUDO="" if [ "$EUID" -ne 0 ]; then SUDO="sudo" log_warn "当前非 root,将使用 sudo 执行系统级操作。" fi # ========= Node.js 检查 ========= if ! command -v node &> /dev/null; then 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 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_error "目录 $INSTALL_DIR 已存在但不是 git 仓库,为避免误删数据,已中止安装。" echo "请手动处理该目录后重新执行脚本,或临时删除它:" echo " sudo rm -rf $INSTALL_DIR" exit 1 fi else log_info "正在创建安装目录: $INSTALL_DIR" $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 "" # ========= 安装依赖 ========= 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 "" # ========= 下载官方音源插件 (v3) ========= log_info "正在下载官方音源插件到 dist/plugins/..." PLUGIN_DIR="$INSTALL_DIR/dist/plugins" mkdir -p "$PLUGIN_DIR" FILE_SERVER="http://171.80.3.149:5244" SHARE_CODE="music" PLUGIN_FILES=( "zq_wy_v3.js" "zq_tx_v3-fix1.js" "zq_kw_v3-fix1.js" "zq_kg.js" "zq_mg_v3.js" ) DOWNLOADED=0 for fname in "${PLUGIN_FILES[@]}"; do target="$PLUGIN_DIR/$fname" # 通过 fs/get API 获取 raw_url (JSON 中 data.raw_url) api_resp=$(curl -s -X POST "$FILE_SERVER/api/fs/get" \ -H "Content-Type: application/json" \ -d "{\"path\":\"/@s/c6VNt7hG/音源/QZ-Music_v2/官方/v3/$fname\",\"password\":\"$SHARE_CODE\"}" \ --max-time 30 2>/dev/null || echo "") raw_url="" if [ -n "$api_resp" ]; then # 使用 python3 解析 JSON 取 data.raw_url;若失败则回退 sd 直链 raw_url=$(echo "$api_resp" | python3 -c "import sys,json; try: d=json.load(sys.stdin) print(d.get('data',{}).get('raw_url','')) except: print('')" 2>/dev/null) fi if [ -z "$raw_url" ]; then raw_url="$FILE_SERVER/sd/c6VNt7hG/音源/QZ-Music_v2/官方/v3/$fname?pwd=$SHARE_CODE" fi if curl -sL "$raw_url" --max-time 120 -o "$target" -w '%{http_code}' 2>/dev/null | grep -qE "^2"; then DOWNLOADED=$((DOWNLOADED + 1)) size=$(wc -c < "$target" 2>/dev/null | tr -d ' ') log_info " ✓ $fname ($size bytes)" else log_warn " ✗ $fname 下载失败" fi done log_info "音源插件下载完成: $DOWNLOADED/${#PLUGIN_FILES[@]}" echo "" # ========= 部署 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 "🖥 服务状态: $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 " 查看日志: 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 ""