#!/usr/bin/env bash set -euo pipefail # openlist 一键安装脚本 # 用法示例:curl -fsSL "https://pan.shumengya.top/d/scripts/openlist/install_openlist.sh" | bash BASE_URL="https://pan.shumengya.top/d/scripts/openlist/openlist" INSTALL_DIR="/shumengya/bin/openlist" SERVICE_NAME="smy-openlist" SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" log() { printf '[openlist-安装] %s\n' "$*" >&2; } fail() { log "错误: $*" >&2; exit 1; } # 进度条函数 show_progress() { local pid=$1 local text=$2 local delay=0.1 local spin='-\|/' printf "[openlist-安装] %s... " "$text" >&2 while ps -p "$pid" > /dev/null 2>&1; do local temp=${spin#?} printf "\b%c" "$spin" >&2 local spin=$temp${spin%"$temp"} sleep $delay done printf "\b完成\n" >&2 } check_port() { # 检查端口占用并尝试清理 local port=5244 if lsof -i :$port >/dev/null 2>&1 || netstat -tunlp | grep -q ":$port "; then log "检测到端口 $port 被占用,尝试清理..." fuser -k -n tcp $port >/dev/null 2>&1 || true sleep 1 if lsof -i :$port >/dev/null 2>&1; then # 尝试查找占用进程并强制杀掉 local pid pid=$(lsof -t -i:$port 2>/dev/null || true) if [ -n "$pid" ]; then kill -9 "$pid" 2>/dev/null || true fi fi fi } require_root() { # 必须使用 root 权限执行 if [ "${EUID:-$(id -u)}" -ne 0 ]; then fail "请使用 root 权限运行 (sudo bash install_openlist.sh)" fi } detect_arch() { # 自动检测 CPU 架构,选择对应二进制 local machine machine=$(uname -m) case "$machine" in x86_64|amd64) echo "amd64" ;; aarch64|arm64) echo "arm64" ;; *) fail "不支持的架构: $machine" ;; esac } download_files() { # 下载对应架构的二进制包和 data 目录 local arch tmp_dir binary_url data_url arch="$1" tmp_dir=$(mktemp -d) # 只在 tmp_dir 存在时清理 trap 'if [ -n "${tmp_dir:-}" ] && [ -d "$tmp_dir" ]; then rm -rf "$tmp_dir"; fi' EXIT binary_url="${BASE_URL}/linux-${arch}.tar.gz" data_url="${BASE_URL}/data.tgz" # 后台下载并显示进度 curl -fsSL "$binary_url" -o "$tmp_dir/openlist.tar.gz" & show_progress $! "正在下载 ${arch} 架构的二进制文件" [ -f "$tmp_dir/openlist.tar.gz" ] || fail "下载二进制文件失败" # 检查 data 目录是否已存在,如果存在则跳过下载 if [ -d "$INSTALL_DIR/data" ]; then log "检测到已存在 data 目录,跳过下载以保护现有数据" else curl -fsSL "$data_url" -o "$tmp_dir/data.tgz" & show_progress $! "正在下载 data 配置文件" [ -f "$tmp_dir/data.tgz" ] || fail "下载 data 文件失败" fi echo "$tmp_dir" } install_binary_and_data() { # 解压并安装二进制文件和 data 目录 local tmp_dir extracted_dir bin_path tmp_dir="$1" log "正在安装 openlist 到 $INSTALL_DIR..." # 尝试停止服务 systemctl stop "$SERVICE_NAME" 2>/dev/null || true # 检查并清理端口 check_port mkdir -p "$INSTALL_DIR" # 只在下载了 data.tgz 时才解压 if [ -f "$tmp_dir/data.tgz" ]; then tar -xzf "$tmp_dir/data.tgz" -C "$INSTALL_DIR/" || fail "解压 data 目录失败" else log "保留现有 data 目录,不进行覆盖" fi # 解压二进制文件 extracted_dir=$(mktemp -d) trap 'if [ -n "${tmp_dir:-}" ] && [ -d "$tmp_dir" ]; then rm -rf "$tmp_dir"; fi; if [ -n "${extracted_dir:-}" ] && [ -d "$extracted_dir" ]; then rm -rf "$extracted_dir"; fi' EXIT tar -xzf "$tmp_dir/openlist.tar.gz" -C "$extracted_dir" || fail "解压二进制文件失败" bin_path=$(find "$extracted_dir" -maxdepth 2 -type f -name "openlist" -perm -111 | head -n 1) [ -n "$bin_path" ] || fail "未找到 openlist 可执行文件" cp "$bin_path" "$INSTALL_DIR/openlist" || fail "复制可执行文件失败" chmod +x "$INSTALL_DIR/openlist" log "文件安装完成" } write_service() { # 写入 systemd 服务文件,默认自启动并在失败时重启 log "正在配置 systemd 服务..." cat > "$SERVICE_FILE" <<'EOF' [Unit] Description=openlist After=network.target [Service] Type=simple User=root Group=root WorkingDirectory=/shumengya/bin/openlist ExecStart=/shumengya/bin/openlist/openlist server Restart=on-failure [Install] WantedBy=multi-user.target EOF } enable_service() { # 重新加载 systemd,设置开机自启并立即启动 log "正在启用并启动服务..." systemctl daemon-reload systemctl enable "$SERVICE_NAME" systemctl restart "$SERVICE_NAME" # 等待几秒钟以捕获立即崩溃的情况 sleep 3 } main() { require_root local arch tmp_dir="" arch=$(detect_arch) log "检测到系统架构: $arch" tmp_dir=$(download_files "$arch") install_binary_and_data "$tmp_dir" write_service enable_service log "==========================================" log "安装完成! openlist 已安装到: $INSTALL_DIR" log "服务已启动,查看状态: systemctl status $SERVICE_NAME" # 检查服务状态 if ! systemctl is-active --quiet "$SERVICE_NAME"; then log "警告: 服务未能正常启动" journalctl -u "$SERVICE_NAME" --no-pager -n 20 fi log "==========================================" } main "$@"