#!/usr/bin/env bash set -euo pipefail show_help() { cat <<'EOF' Usage: moviepilot [BOOTSTRAP COMMAND] | [RUNTIME COMMAND] moviepilot help [COMMAND ...] moviepilot commands Bootstrap Commands: moviepilot install deps [--python PYTHON] [--venv PATH] [--recreate] [--config-dir PATH] moviepilot install frontend [--version latest] [--node-version 20.12.1] [--config-dir PATH] moviepilot install resources [--resources-repo PATH] [--resource-dir PATH] [--config-dir PATH] moviepilot init [--skip-resources] [--force-token] [--wizard] [--superuser NAME] [--superuser-password PASSWORD] [--config-dir PATH] moviepilot setup [--python PYTHON] [--venv PATH] [--recreate] [--frontend-version latest] [--node-version 20.12.1] [--wizard] [--superuser NAME] [--superuser-password PASSWORD] [--config-dir PATH] moviepilot uninstall [--venv PATH] [--config-dir PATH] moviepilot update {backend|frontend|all} [OPTIONS] moviepilot startup {enable|disable|status} [--venv PATH] [--config-dir PATH] moviepilot agent [OPTIONS] MESSAGE... Runtime Commands: moviepilot start|stop|restart|status|logs|version moviepilot config ... moviepilot tool ... moviepilot scheduler ... Discovery Commands: moviepilot help moviepilot help config moviepilot help install moviepilot help uninstall moviepilot help update moviepilot help startup moviepilot commands Examples: moviepilot install deps moviepilot install frontend moviepilot install resources moviepilot setup --wizard moviepilot uninstall moviepilot update all moviepilot startup enable moviepilot agent 帮我分析最近一次搜索失败 moviepilot help config moviepilot config keys moviepilot start moviepilot tool list EOF } show_commands() { cat <<'EOF' Bootstrap Commands install deps install frontend install resources init setup uninstall update backend update frontend update all startup enable startup disable startup status agent Runtime Commands start stop restart status logs version config path config list config get config set config keys config describe tool list tool show tool run scheduler list scheduler run Discovery Commands help commands EOF } show_install_help() { cat <<'EOF' Usage: moviepilot install deps [OPTIONS] moviepilot install frontend [OPTIONS] moviepilot install resources [OPTIONS] Options: deps: --python PYTHON 用于创建虚拟环境的 Python 解释器,默认自动选择本地 3.11+ 版本 --venv PATH 虚拟环境目录,默认 ./venv --recreate 删除并重建虚拟环境 --config-dir PATH 指定配置目录 frontend: --version TAG 前端版本,默认 latest --node-version VER 本地 Node 运行时版本,默认 20.12.1 --config-dir PATH 指定配置目录 resources: --resources-repo PATH 本地 MoviePilot-Resources 仓库路径 --resource-dir PATH 直接指定 resources.v2 目录 --config-dir PATH 指定配置目录 -h, --help 显示帮助 EOF } show_init_help() { cat <<'EOF' Usage: moviepilot init [OPTIONS] Options: --skip-resources 跳过资源同步 --force-token 强制重置 API_TOKEN --wizard 启动交互式初始化向导 --superuser NAME 预设超级管理员用户名 --superuser-password PWD 预设超级管理员密码 --config-dir PATH 指定配置目录 -h, --help 显示帮助 EOF } show_setup_help() { cat <<'EOF' Usage: moviepilot setup [OPTIONS] Options: --python PYTHON 用于创建虚拟环境的 Python 解释器,默认自动选择本地 3.11+ 版本 --venv PATH 虚拟环境目录,默认 ./venv --recreate 删除并重建虚拟环境 --frontend-version TAG 前端版本,默认 latest --node-version VER 本地 Node 运行时版本,默认 20.12.1 --skip-resources 跳过资源同步 --force-token 强制重置 API_TOKEN --wizard 安装完成后启动交互式初始化向导 --superuser NAME 预设超级管理员用户名 --superuser-password PWD 预设超级管理员密码 --config-dir PATH 指定配置目录 -h, --help 显示帮助 EOF } show_uninstall_help() { cat <<'EOF' Usage: moviepilot uninstall [OPTIONS] Options: --venv PATH 虚拟环境目录,默认 ./venv --config-dir PATH 指定配置目录,默认使用当前安装配置 -h, --help 显示帮助 说明: - 默认保留配置目录,过程中会询问是否删除 - 卸载时会进行两次确认 - 源码目录不会被删除 EOF } show_update_help() { cat <<'EOF' Usage: moviepilot update backend [OPTIONS] moviepilot update frontend [OPTIONS] moviepilot update all [OPTIONS] Options: --ref REF 后端 Git 版本,默认 latest --frontend-version TAG 前端版本,默认 latest --node-version VER 本地 Node 运行时版本,默认 20.12.1 --python PYTHON 用于安装后端依赖的 Python 解释器,默认自动选择本地 3.11+ 版本 --venv PATH 虚拟环境目录,默认 ./venv --recreate 删除并重建虚拟环境 --skip-resources 更新 all 时跳过资源同步 --config-dir PATH 指定配置目录 -h, --help 显示帮助 EOF } show_startup_help() { cat <<'EOF' Usage: moviepilot startup enable [OPTIONS] moviepilot startup disable [OPTIONS] moviepilot startup status [OPTIONS] Options: --venv PATH 虚拟环境目录,默认 ./venv --config-dir PATH 指定配置目录,默认使用当前安装配置 -h, --help 显示帮助 说明: - macOS 使用 LaunchAgent - Linux 优先使用 systemd --user,不可用时回退到 XDG autostart - Windows 使用当前用户的 Startup 启动目录 EOF } show_agent_help() { cat <<'EOF' Usage: moviepilot agent [OPTIONS] MESSAGE... Options: --session ID 指定会话 ID --new-session 强制创建新会话 --user-id ID 智能体上下文中的用户 ID,默认 cli --config-dir PATH 指定配置目录 -h, --help 显示帮助 EOF } python_version_ok() { local python_bin="$1" "$python_bin" - <<'PY' >/dev/null 2>&1 import sys raise SystemExit(0 if sys.version_info >= (3, 11) else 1) PY } try_python_candidate() { local candidate="$1" local python_path="" python_path="$(command -v "$candidate" 2>/dev/null || true)" if [ -n "$python_path" ] && python_version_ok "$python_path"; then printf '%s\n' "$python_path" return 0 fi return 1 } find_system_python() { local minor local uv_bin local uv_python for minor in 20 19 18 17 16 15 14 13 12 11; do if try_python_candidate "python3.$minor"; then return 0 fi done if try_python_candidate python3; then return 0 fi if try_python_candidate python; then return 0 fi for uv_bin in "$(command -v uv 2>/dev/null || true)" "$HOME/.local/bin/uv"; do if [ -n "$uv_bin" ] && [ -x "$uv_bin" ]; then for minor in 20 19 18 17 16 15 14 13 12 11; do uv_python="$("$uv_bin" python find "3.$minor" 2>/dev/null || true)" if [ -n "$uv_python" ] && python_version_ok "$uv_python"; then printf '%s\n' "$uv_python" return 0 fi done fi done return 1 } require_bootstrap_python() { if [ -n "$BOOTSTRAP_PYTHON" ]; then return 0 fi echo "未找到可用的 Python 3.11+ 解释器,请先安装 Python 3.11 或更高版本" >&2 exit 1 } default_config_dir() { case "$(uname -s)" in Darwin) printf '%s\n' "$HOME/Library/Application Support/MoviePilot" ;; *) printf '%s\n' "${XDG_CONFIG_HOME:-$HOME/.config}/moviepilot" ;; esac } legacy_config_exists() { local legacy_dir="$ROOT/config" [[ -f "$legacy_dir/app.env" ]] || [[ -f "$legacy_dir/user.db" ]] || [[ -d "$legacy_dir/logs" ]] || [[ -d "$legacy_dir/temp" ]] || [[ -d "$legacy_dir/cache" ]] || [[ -d "$legacy_dir/cookies" ]] || [[ -d "$legacy_dir/sites" ]] } run_runtime_cli() { if [ ! -x "$VENV_PYTHON" ]; then echo "未找到项目虚拟环境,请先执行 moviepilot install deps 或 moviepilot setup" >&2 exit 1 fi exec "$VENV_PYTHON" -m app.cli "$@" } show_command_help() { case "${1:-}" in ""|-h|--help|help) show_help exit 0 ;; install) shift case "${1:-}" in ""|deps|-h|--help) show_install_help exit 0 ;; frontend) show_install_help exit 0 ;; resources) show_install_help exit 0 ;; *) echo "仅支持:moviepilot help install、moviepilot help install deps、moviepilot help install frontend、moviepilot help install resources" >&2 exit 1 ;; esac ;; init) show_init_help exit 0 ;; setup) show_setup_help exit 0 ;; uninstall) show_uninstall_help exit 0 ;; agent) show_agent_help exit 0 ;; update) show_update_help exit 0 ;; startup) show_startup_help exit 0 ;; commands) show_commands exit 0 ;; *) run_runtime_cli "$@" --help ;; esac } SOURCE="${BASH_SOURCE[0]}" while [ -L "$SOURCE" ]; do SOURCE_DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)" SOURCE_TARGET="$(readlink "$SOURCE")" if [[ "$SOURCE_TARGET" != /* ]]; then SOURCE="$SOURCE_DIR/$SOURCE_TARGET" else SOURCE="$SOURCE_TARGET" fi done ROOT="$(cd -P "$(dirname "$SOURCE")" && pwd)" VENV_PYTHON="$ROOT/venv/bin/python" SETUP_SCRIPT="$ROOT/scripts/local_setup.py" if [ -z "${CONFIG_DIR:-}" ] && [ -f "$ROOT/.moviepilot.env" ]; then # shellcheck disable=SC1090 . "$ROOT/.moviepilot.env" fi if [ -z "${CONFIG_DIR:-}" ]; then if legacy_config_exists; then CONFIG_DIR="$ROOT/config" else CONFIG_DIR="$(default_config_dir)" fi fi export CONFIG_DIR BOOTSTRAP_PYTHON="" if [ -x "$VENV_PYTHON" ]; then BOOTSTRAP_PYTHON="$VENV_PYTHON" else BOOTSTRAP_PYTHON="$(find_system_python || true)" fi cd "$ROOT" case "${1:-}" in ""|-h|--help|help) if [ "${1:-}" = "help" ]; then shift show_command_help "$@" fi show_help exit 0 ;; commands) show_commands exit 0 ;; install) shift require_bootstrap_python case "${1:-}" in deps) shift exec "$BOOTSTRAP_PYTHON" "$SETUP_SCRIPT" install-deps "$@" ;; frontend) shift exec "$BOOTSTRAP_PYTHON" "$SETUP_SCRIPT" install-frontend "$@" ;; resources) shift exec "$BOOTSTRAP_PYTHON" "$SETUP_SCRIPT" install-resources "$@" ;; *) echo "支持的命令:moviepilot install deps|frontend|resources" >&2 exit 1 ;; esac ;; init) shift require_bootstrap_python exec "$BOOTSTRAP_PYTHON" "$SETUP_SCRIPT" init "$@" ;; setup) shift require_bootstrap_python exec "$BOOTSTRAP_PYTHON" "$SETUP_SCRIPT" setup "$@" ;; uninstall) shift require_bootstrap_python COMMAND_PATH="$(command -v moviepilot 2>/dev/null || true)" MOVIEPILOT_LAUNCH_PATH="$0" MOVIEPILOT_COMMAND_PATH="$COMMAND_PATH" exec "$BOOTSTRAP_PYTHON" "$SETUP_SCRIPT" uninstall "$@" ;; update) shift require_bootstrap_python exec "$BOOTSTRAP_PYTHON" "$SETUP_SCRIPT" update "$@" ;; startup) shift require_bootstrap_python exec "$BOOTSTRAP_PYTHON" "$SETUP_SCRIPT" startup "$@" ;; agent) shift require_bootstrap_python exec "$BOOTSTRAP_PYTHON" "$SETUP_SCRIPT" agent "$@" ;; esac if [ ! -x "$VENV_PYTHON" ]; then echo "未找到项目虚拟环境,请先执行 moviepilot install deps 或 moviepilot setup" >&2 exit 1 fi exec "$VENV_PYTHON" -m app.cli "$@"