diff --git a/.dockerignore b/.dockerignore index 72db9e2b..b7827bb4 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,88 @@ -# Ignore git +# Git .github -.git \ No newline at end of file +.git +.gitignore + +# Documentation +docs/ +README.md +LICENSE + +# Development files +.pylintrc +*.pyc +__pycache__/ +*.pyo +*.pyd +.Python +*.so +.pytest_cache/ +.coverage +htmlcov/ +.tox/ +.nox/ +.hypothesis/ +.mypy_cache/ +.dmypy.json +dmypy.json + +# Virtual environments +venv/ +env/ +ENV/ +env.bak/ +venv.bak/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Logs +*.log +logs/ + +# Temporary files +*.tmp +*.temp +tmp/ +temp/ + +# Database +*.db +*.sqlite +*.sqlite3 + +# Config files that should be mounted +config/ +database/ + +# Test files +tests/ +test_* +*_test.py + +# Build artifacts +build/ +dist/ +*.egg-info/ + +# Docker +Dockerfile* +docker-compose* +.dockerignore + +# Other +app.ico +frozen.spec \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile index a663b995..105c16a8 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -7,8 +7,11 @@ ENV LANG="C.UTF-8" \ DISPLAY=:987 \ PUID=0 \ PGID=0 \ - UMASK=000 + UMASK=000 \ + VENV_PATH="/opt/venv" WORKDIR "/app" + +# 安装系统依赖 RUN apt-get update -y \ && apt-get upgrade -y \ && apt-get -y install \ @@ -28,6 +31,7 @@ RUN apt-get update -y \ rsync \ ffmpeg \ nano \ + build-essential \ && dpkg-reconfigure --frontend noninteractive tzdata \ && \ if [ "$(uname -m)" = "x86_64" ]; \ @@ -43,13 +47,16 @@ RUN apt-get update -y \ /moviepilot/.cache \ /var/lib/apt/lists/* \ /var/tmp/* + +# 创建虚拟环境 +RUN python3 -m venv ${VENV_PATH} \ + && ${VENV_PATH}/bin/pip install --upgrade pip \ + && ${VENV_PATH}/bin/pip install Cython pip-tools + +# 复制依赖文件并安装到虚拟环境 COPY ../requirements.in requirements.in -RUN apt-get update -y \ - && apt-get install -y build-essential \ - && pip install --upgrade pip \ - && pip install Cython pip-tools \ - && pip-compile requirements.in \ - && pip install -r requirements.txt \ +RUN ${VENV_PATH}/bin/pip-compile requirements.in \ + && ${VENV_PATH}/bin/pip install -r requirements.txt \ && playwright install-deps chromium \ && apt-get remove -y build-essential \ && apt-get autoremove -y \ @@ -59,7 +66,11 @@ RUN apt-get update -y \ /moviepilot/.cache \ /var/lib/apt/lists/* \ /var/tmp/* + +# 复制应用代码 COPY .. . + +# 配置nginx和其他文件 RUN cp -f /app/docker/nginx.common.conf /etc/nginx/common.conf \ && cp -f /app/docker/nginx.template.conf /etc/nginx/nginx.template.conf \ && cp -f /app/docker/update.sh /usr/local/bin/mp_update.sh \ @@ -84,6 +95,7 @@ RUN cp -f /app/docker/nginx.common.conf /etc/nginx/common.conf \ && curl -sL "https://github.com/jxxghp/MoviePilot-Resources/archive/refs/heads/main.zip" | busybox unzip -d /tmp - \ && mv -f /tmp/MoviePilot-Resources-main/resources.v2/* /app/app/helper/ \ && rm -rf /tmp/* + EXPOSE 3000 VOLUME [ "${CONFIG_DIR}" ] ENTRYPOINT [ "/entrypoint.sh" ] diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 84ba23cf..53d65ff0 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -20,6 +20,10 @@ function WARN() { echo -e "${WARN} ${1}" } +# 设置虚拟环境路径 +VENV_PATH="${VENV_PATH:-/opt/venv}" +export PATH="${VENV_PATH}/bin:$PATH" + # 校正设置目录 CONFIG_DIR="${CONFIG_DIR:-/config}" @@ -222,7 +226,8 @@ chown -R moviepilot:moviepilot \ /public \ "${CONFIG_DIR}" \ /var/lib/nginx \ - /var/log/nginx + /var/log/nginx \ + "${VENV_PATH}" chown moviepilot:moviepilot /etc/hosts /tmp # 下载浏览器内核 @@ -270,4 +275,4 @@ fi # 启动后端服务 INFO "→ 启动后端服务..." -exec dumb-init gosu moviepilot:moviepilot python3 app/main.py +exec dumb-init gosu moviepilot:moviepilot ${VENV_PATH}/bin/python3 app/main.py diff --git a/docker/update.sh b/docker/update.sh index f463c867..3ffa814c 100644 --- a/docker/update.sh +++ b/docker/update.sh @@ -20,6 +20,10 @@ function WARN() { echo -e "${WARN} ${1}" } +# 设置虚拟环境路径 +VENV_PATH="${VENV_PATH:-/opt/venv}" +export PATH="${VENV_PATH}/bin:$PATH" + # 下载及解压 function download_and_unzip() { local retries=0 @@ -54,16 +58,36 @@ function install_backend_and_download_resources() { return 1 fi INFO "后端程序下载成功" - INFO "→ 正在安装依赖..." - if ! pip install ${PIP_OPTIONS} --upgrade --root-user-action=ignore pip > /dev/null; then - ERROR "pip 更新失败,请重新拉取镜像" - return 1 + + # 检查依赖是否有变化 + INFO "→ 检查依赖变化..." + if [ -f "${TMP_PATH}/App/requirements.in" ]; then + if ! cmp -s /app/requirements.in "${TMP_PATH}/App/requirements.in"; then + INFO "检测到依赖变化,正在更新虚拟环境..." + # 备份当前requirements.txt + cp /app/requirements.txt /tmp/requirements.txt.backup + # 复制新的requirements.in + cp "${TMP_PATH}/App/requirements.in" /app/requirements.in + # 重新编译依赖 + if ! ${VENV_PATH}/bin/pip-compile /app/requirements.in; then + ERROR "依赖编译失败,恢复原依赖" + cp /tmp/requirements.txt.backup /app/requirements.txt + return 1 + fi + # 安装新依赖 + if ! ${VENV_PATH}/bin/pip install ${PIP_OPTIONS} --root-user-action=ignore -r /app/requirements.txt; then + ERROR "依赖安装失败,恢复原依赖" + cp /tmp/requirements.txt.backup /app/requirements.txt + return 1 + fi + INFO "依赖更新成功" + else + INFO "依赖无变化,跳过依赖更新" + fi + else + WARN "未找到requirements.in文件,跳过依赖检查" fi - if ! pip install ${PIP_OPTIONS} --root-user-action=ignore -r ${TMP_PATH}/App/requirements.txt > /dev/null; then - ERROR "依赖安装失败,请重新拉取镜像" - return 1 - fi - INFO "依赖安装成功" + # 如果是"heads/v2.zip",则查找v2开头的最新版本号 if [[ "${1}" == "heads/v2.zip" ]]; then INFO "→ 正在获取前端最新版本号..." @@ -98,6 +122,7 @@ function install_backend_and_download_resources() { rm -rf /plugins mkdir -p /plugins cp -a /app/app/plugins/* /plugins/ + cp -a /app/app/plugins/* /plugins/ rm -f /plugins/__init__.py # 备份站点资源 INFO "→ 正在备份站点资源目录..." @@ -134,11 +159,11 @@ function install_backend_and_download_resources() { } function test_connectivity_pip() { - pip uninstall -y pip-hello-world > /dev/null 2>&1 + ${VENV_PATH}/bin/pip uninstall -y pip-hello-world > /dev/null 2>&1 case "$1" in 0) if [[ -n "${PIP_PROXY}" ]]; then - if pip install -i ${PIP_PROXY} pip-hello-world > /dev/null 2>&1; then + if ${VENV_PATH}/bin/pip install -i ${PIP_PROXY} pip-hello-world > /dev/null 2>&1; then PIP_OPTIONS="-i ${PIP_PROXY}" PIP_LOG="镜像代理模式" return 0 @@ -148,7 +173,7 @@ function test_connectivity_pip() { ;; 1) if [[ -n "${PROXY_HOST}" ]]; then - if pip install --proxy=${PROXY_HOST} pip-hello-world > /dev/null 2>&1; then + if ${VENV_PATH}/bin/pip install --proxy=${PROXY_HOST} pip-hello-world > /dev/null 2>&1; then PIP_OPTIONS="--proxy=${PROXY_HOST}" PIP_LOG="全局代理模式" return 0