diff --git a/.dockerignore b/.dockerignore index 590e766..a72e77b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,13 +1,40 @@ .git .github + build dist KindleComicConverter.egg-info + .dockerignore .gitignore .travis.yml + Dockerfile venv +.venv +__pycache__/ +*/__pycache__/ +*.pyc + *.md -LICENSE.txt +*.txt +!requirements-docker.txt MANIFEST.in + +*.yml +*.spec + +*.svg +*.jpg +*.json + +gen_ui_files.bat +gen_ui_files.sh + +gui/ +icons/ + +kindlecomicconverter/KCC_gui.py +kindlecomicconverter/KCC_rc.py +kindlecomicconverter/KCC_ui_editor.py +kindlecomicconverter/KCC_ui.py diff --git a/.github/workflows/docker-base-publish.yml b/.github/workflows/docker-base-publish.yml index 7c692a4..ffb77c4 100644 --- a/.github/workflows/docker-base-publish.yml +++ b/.github/workflows/docker-base-publish.yml @@ -1,34 +1,45 @@ -name: Docker base +name: Build and Publish Base Docker Image on: workflow_dispatch: push: - tags: [ 'docker-base-*' ] - - # Don't trigger if it's just a documentation update - paths-ignore: - - '**.md' - - '**.MD' - - '**.yml' - - 'docs/**' - - 'LICENSE' - - '.gitattributes' - - '.gitignore' - - '.dockerignore' + branches: + - master + paths: + - 'requirements-docker.txt' + - 'Dockerfile-base' jobs: - build_and_push: - uses: sdr-enthusiasts/common-github-workflows/.github/workflows/build_and_push_image.yml@main - with: - docker_build_file: ./Dockerfile-base - platform_linux_arm32v7_enabled: true - platform_linux_arm64v8_enabled: true - platform_linux_amd64_enabled: true - push_enabled: true - build_nohealthcheck: false - ghcr_repo_owner: ${{ github.repository_owner }} - ghcr_repo: ${{ github.repository }} - build_latest: false - secrets: - ghcr_token: ${{ secrets.GITHUB_TOKEN }} + build_and_publish_base_image: + runs-on: ubuntu-latest + steps: + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Set Release Date + id: release_date + run: | + echo "release_date=$(date --rfc-3339=date)" >> $GITHUB_OUTPUT + + - name: Build and push + uses: docker/build-push-action@v6 + with: + platforms: linux/amd64,linux/arm64,linux/arm/v7 + file: Dockerfile-base + push: true + tags: | + ghcr.io/${{ github.repository_owner }}/kcc:base-latest + ghcr.io/${{ github.repository_owner }}/kcc:base-${{ steps.release_date.outputs.release_date }} + cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/kcc:base-cache + cache-to: type=registry,ref=ghcr.io/${{ github.repository_owner }}/kcc:base-cache,mode=max diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index be58fd2..1d7af6a 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -1,12 +1,12 @@ -name: Docker +name: Build and publish final image on: workflow_dispatch: push: - # Publish semver tags as releases. - tags: [ 'v*.*.*' ] + tags: + - 'v*.*.*' - # Don't trigger if it's just a documentation update + # Don't trigger if it's just a documentation update or a base image update paths-ignore: - '**.md' - '**.MD' @@ -15,19 +15,37 @@ on: - 'LICENSE' - '.gitattributes' - '.gitignore' - - '.dockerignore' - + - 'requirements-docker.txt' + - 'Dockerfile-base' jobs: - build_and_push: - uses: sdr-enthusiasts/common-github-workflows/.github/workflows/build_and_push_image.yml@main - with: - platform_linux_arm32v7_enabled: true - platform_linux_arm64v8_enabled: true - platform_linux_amd64_enabled: true - push_enabled: true - build_nohealthcheck: false - ghcr_repo_owner: ${{ github.repository_owner }} - ghcr_repo: ${{ github.repository }} - secrets: - ghcr_token: ${{ secrets.GITHUB_TOKEN }} + build_and_publish_image: + runs-on: ubuntu-latest + steps: + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository_owner }}/kcc + + - name: Build and push + uses: docker/build-push-action@v6 + with: + platforms: linux/amd64,linux/arm64,linux/arm/v7 + push: true + tags: ${{ steps.meta.outputs.tags }} + cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/kcc:final-cache + cache-to: type=registry,ref=ghcr.io/${{ github.repository_owner }}/kcc:final-cache,mode=max diff --git a/Dockerfile b/Dockerfile index e9581fe..8bf7cac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,19 +1,20 @@ -# Select final stage based on TARGETARCH ARG -FROM ghcr.io/ciromattia/kcc:docker-base-20241116 -LABEL com.kcc.name="Kindle Comic Converter" -LABEL com.kcc.author="Ciro Mattia Gonano, Paweł Jastrzębski and Darodi" -LABEL org.opencontainers.image.description='Kindle Comic Converter' -LABEL org.opencontainers.image.documentation='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.source='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.authors='darodi' -LABEL org.opencontainers.image.url='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.documentation='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.vendor='ciromattia' -LABEL org.opencontainers.image.licenses='ISC' -LABEL org.opencontainers.image.title="Kindle Comic Converter" +FROM ghcr.io/ciromattia/kcc:base-latest -COPY . /opt/kcc -RUN cat /opt/kcc/kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/'//g" > /IMAGE_VERSION +COPY . /opt/kcc/ -ENTRYPOINT ["/opt/kcc/kcc-c2e.py"] -CMD ["-h"] +# Setup executable and version file +RUN \ + chmod +x /opt/kcc/entrypoint.sh && \ + ln -s /opt/kcc/kcc-c2e.py /usr/local/bin/c2e && \ + ln -s /opt/kcc/kcc-c2p.py /usr/local/bin/c2p && \ + ln -s /opt/kcc/entrypoint.sh /usr/local/bin/entrypoint && \ + cat /opt/kcc/kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/'//g" > /IMAGE_VERSION + +LABEL com.kcc.name="Kindle Comic Converter" \ + com.kcc.author="Ciro Mattia Gonano, Paweł Jastrzębski and Darodi" \ + org.opencontainers.image.description='Kindle Comic Converter' \ + org.opencontainers.image.source='https://github.com/ciromattia/kcc' \ + org.opencontainers.image.title="Kindle Comic Converter" + +ENTRYPOINT ["entrypoint"] +CMD ["-h"] \ No newline at end of file diff --git a/Dockerfile-base b/Dockerfile-base index cb73e60..8dab1e2 100644 --- a/Dockerfile-base +++ b/Dockerfile-base @@ -1,164 +1,44 @@ -FROM --platform=linux/amd64 python:3.13-slim-bullseye as compile-amd64 -ARG TARGETOS +# STAGE 1: BUILDER +# Contains all build tools and dev dependencies, will be discarded +FROM python:3.13-slim-bullseye AS builder + ARG TARGETARCH -ARG TARGETVARIANT -RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT" - - -COPY requirements.txt /opt/kcc/ -ENV PATH="/opt/venv/bin:$PATH" -RUN DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \ - apt-get install -y libpng-dev libjpeg-dev p7zip-full unrar-free libgl1 && \ - python -m pip install --upgrade pip && \ - python -m venv /opt/venv && \ - python -m pip install -r /opt/kcc/requirements.txt - - -###################################################################################### - -FROM --platform=linux/arm64 python:3.13-slim-bullseye as compile-arm64 -ARG TARGETOS -ARG TARGETARCH -ARG TARGETVARIANT -RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT" - -ENV LC_ALL=C.UTF-8 \ - LANG=C.UTF-8 \ - LANGUAGE=en_US:en - -SHELL ["/bin/bash", "-o", "pipefail", "-c"] - -COPY requirements.txt /opt/kcc/ -ENV PATH="/opt/venv/bin:$PATH" +# Install system dependencies RUN set -x && \ - TEMP_PACKAGES=() && \ - KEPT_PACKAGES=() && \ - # Packages only required during build - TEMP_PACKAGES+=(build-essential) && \ - TEMP_PACKAGES+=(cmake) && \ - TEMP_PACKAGES+=(libfreetype6-dev) && \ - TEMP_PACKAGES+=(libfontconfig1-dev) && \ - TEMP_PACKAGES+=(libpng-dev) && \ - TEMP_PACKAGES+=(libjpeg-dev) && \ - TEMP_PACKAGES+=(libssl-dev) && \ - TEMP_PACKAGES+=(libxft-dev) && \ - TEMP_PACKAGES+=(make) && \ - TEMP_PACKAGES+=(python3-dev) && \ - TEMP_PACKAGES+=(python3-setuptools) && \ - TEMP_PACKAGES+=(python3-wheel) && \ - # Packages kept in the image - KEPT_PACKAGES+=(bash) && \ - KEPT_PACKAGES+=(ca-certificates) && \ - KEPT_PACKAGES+=(chrpath) && \ - KEPT_PACKAGES+=(locales) && \ - KEPT_PACKAGES+=(locales-all) && \ - KEPT_PACKAGES+=(libfreetype6) && \ - KEPT_PACKAGES+=(libfontconfig1) && \ - KEPT_PACKAGES+=(p7zip-full) && \ - KEPT_PACKAGES+=(python3) && \ - KEPT_PACKAGES+=(python3-pip) && \ - KEPT_PACKAGES+=(unrar-free) && \ - # Install packages - DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - ${KEPT_PACKAGES[@]} \ - ${TEMP_PACKAGES[@]} \ - && \ - # Install required python modules - python -m pip install --upgrade pip && \ + BUILD_DEPS="build-essential cmake libffi-dev libfreetype6-dev libfontconfig1-dev libpng-dev libjpeg-dev libssl-dev libxft-dev make python3-dev python3-setuptools python3-wheel" && \ + RUNTIME_DEPS="bash ca-certificates chrpath locales locales-all libfreetype6 libfontconfig1 p7zip-full python3 python3-pip unrar-free libgl1" && \ + DEBIAN_FRONTEND=noninteractive apt-get update -y && \ + apt-get install -y --no-install-recommends ${BUILD_DEPS} ${RUNTIME_DEPS} + +# Install Python dependencies using virtual environment +COPY requirements-docker.txt . +RUN \ + set -x && \ python -m venv /opt/venv && \ - python -m pip install -r /opt/kcc/requirements.txt + . /opt/venv/bin/activate && \ + pip install --upgrade pip && \ + pip install --no-cache-dir -r requirements-docker.txt +# STAGE 2: FINAL +# Clean, small and secure image with only runtime dependencies +FROM python:3.13-slim-bullseye -###################################################################################### +# Install runtime dependencies only +RUN \ + set -x && \ + DEBIAN_FRONTEND=noninteractive apt-get update -y && \ + apt-get install -y --no-install-recommends p7zip-full unrar-free && \ + rm -rf /var/lib/apt/lists/* -FROM --platform=linux/arm/v7 python:3.13-slim-bullseye as compile-armv7 -ARG TARGETOS -ARG TARGETARCH -ARG TARGETVARIANT -RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT" +# Copy artifacts from builder +COPY --from=builder /opt/venv /opt/venv -ENV LC_ALL=C.UTF-8 \ - LANG=C.UTF-8 \ - LANGUAGE=en_US:en - -SHELL ["/bin/bash", "-o", "pipefail", "-c"] - -COPY requirements.txt /opt/kcc/ +WORKDIR /opt/kcc ENV PATH="/opt/venv/bin:$PATH" -RUN set -x && \ - TEMP_PACKAGES=() && \ - KEPT_PACKAGES=() && \ - # Packages only required during build - TEMP_PACKAGES+=(build-essential) && \ - TEMP_PACKAGES+=(cmake) && \ - TEMP_PACKAGES+=(libffi-dev) && \ - TEMP_PACKAGES+=(libfreetype6-dev) && \ - TEMP_PACKAGES+=(libfontconfig1-dev) && \ - TEMP_PACKAGES+=(libpng-dev) && \ - TEMP_PACKAGES+=(libjpeg-dev) && \ - TEMP_PACKAGES+=(libssl-dev) && \ - TEMP_PACKAGES+=(libxft-dev) && \ - TEMP_PACKAGES+=(make) && \ - TEMP_PACKAGES+=(python3-dev) && \ - TEMP_PACKAGES+=(python3-setuptools) && \ - TEMP_PACKAGES+=(python3-wheel) && \ - # Packages kept in the image - KEPT_PACKAGES+=(bash) && \ - KEPT_PACKAGES+=(ca-certificates) && \ - KEPT_PACKAGES+=(chrpath) && \ - KEPT_PACKAGES+=(locales) && \ - KEPT_PACKAGES+=(locales-all) && \ - KEPT_PACKAGES+=(libfreetype6) && \ - KEPT_PACKAGES+=(libfontconfig1) && \ - KEPT_PACKAGES+=(p7zip-full) && \ - KEPT_PACKAGES+=(python3) && \ - KEPT_PACKAGES+=(python3-pip) && \ - KEPT_PACKAGES+=(unrar-free) && \ - # Install packages - DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - ${KEPT_PACKAGES[@]} \ - ${TEMP_PACKAGES[@]} \ - && \ - # Install required python modules - python -m pip install --upgrade pip && \ - python -m venv /opt/venv && \ - python -m pip install --upgrade pillow psutil requests python-slugify raven packaging mozjpeg-lossless-optimization natsort distro numpy pymupdf - - -###################################################################################### -FROM --platform=linux/amd64 python:3.13-slim-bullseye as build-amd64 -COPY --from=compile-amd64 /opt/venv /opt/venv - -FROM --platform=linux/arm64 python:3.13-slim-bullseye as build-arm64 -COPY --from=compile-arm64 /opt/venv /opt/venv - -FROM --platform=linux/arm/v7 python:3.13-slim-bullseye as build-armv7 -COPY --from=compile-armv7 /opt/venv /opt/venv -###################################################################################### - -# Select final stage based on TARGETARCH ARG -FROM build-${TARGETARCH}${TARGETVARIANT} -LABEL com.kcc.name="Kindle Comic Converter base image" -LABEL com.kcc.author="Ciro Mattia Gonano, Paweł Jastrzębski and Darodi" -LABEL org.opencontainers.image.description='Kindle Comic Converter base image' -LABEL org.opencontainers.image.documentation='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.source='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.authors='darodi' -LABEL org.opencontainers.image.url='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.documentation='https://github.com/ciromattia/kcc' -LABEL org.opencontainers.image.vendor='ciromattia' -LABEL org.opencontainers.image.licenses='ISC' -LABEL org.opencontainers.image.title="Kindle Comic Converter" - - -ENV PATH="/opt/venv/bin:$PATH" -WORKDIR /app -RUN DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \ - apt-get install -y p7zip-full unrar-free && \ - ln -s /app/kindlegen /bin/kindlegen && \ - echo docker-base-20241116 > /IMAGE_VERSION - +LABEL com.kcc.name="Kindle Comic Converter" \ + com.kcc.author="Ciro Mattia Gonano, Paweł Jastrzębski and Darodi" \ + org.opencontainers.image.description='Kindle Comic Converter Base Image' \ + org.opencontainers.image.source='https://github.com/ciromattia/kcc' \ + org.opencontainers.image.title="Kindle Comic Converter Base Image" diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..27aada1 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +set -e + +MODE=${KCC_MODE:-c2e} + +case "$MODE" in + "c2e") + echo "Starting C2E..." + exec c2e "$@" + ;; + + "c2p") + echo "Starting C2P..." + exec c2p "$@" + ;; + + *) + echo "Error: Unknown mode '$MODE'" >&2 + exit 1 + ;; +esac \ No newline at end of file diff --git a/requirements-docker.txt b/requirements-docker.txt new file mode 100644 index 0000000..1072b23 --- /dev/null +++ b/requirements-docker.txt @@ -0,0 +1,10 @@ +Pillow>=11.3.0 +psutil>=5.9.5 +requests>=2.31.0 +python-slugify>=1.2.1 +packaging>=23.2 +mozjpeg-lossless-optimization>=1.2.0 +natsort>=8.4.0 +distro>=1.8.0 +numpy>=1.22.4 +PyMuPDF>=1.18.0