From 52ce0ed7f70934d2ccc2fd21b36189d1104c5374 Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 20 Jul 2025 02:47:08 +0000 Subject: [PATCH] feat: add Dockerfile and GitHub Actions workflow for building and publishing Docker image --- .dockerignore | 62 +++++++++++++++++++++++ .github/workflows/docker.yml | 98 ++++++++++++++++++++++++++++++++++++ .gitignore | 1 - Dockerfile | 78 ++++++++++++++++++++++++++++ 4 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 .dockerignore create mode 100644 .github/workflows/docker.yml create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3bdadf2 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,62 @@ +# Logs and temporary files + +Logs/ +logs/ +temp/ +\*.log + +# Sensitive files + +key_vault.db +unshackle/WVDs/ +unshackle/PRDs/ +unshackle/cookies/ +_.prd +_.wvd + +# Cache directories + +unshackle/cache/ +**pycache**/ +_.pyc +_.pyo +\*.pyd +.Python + +# Development files + +.git/ +.gitignore +.vscode/ +.idea/ +_.swp +_.swo + +# Documentation and plans + +plan/ +CONTRIBUTING.md +CONFIG.md +AGENTS.md +OLD-CHANGELOG.md +cliff.toml + +# Installation scripts + +install.bat + +# Test files + +_test_ +_Test_ + +# Virtual environments + +venv/ +env/ +.venv/ + +# OS generated files + +.DS_Store +Thumbs.db diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..67f1003 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,98 @@ +name: Build and Publish Docker Image + +on: + push: + branches: + - main + - master + paths: + - "unshackle/core/__init__.py" + - "Dockerfile" + - "pyproject.toml" + - "uv.lock" + - ".github/workflows/docker.yml" + tags: + - "v*" + pull_request: + branches: + - main + - master + paths: + - "unshackle/core/__init__.py" + - "Dockerfile" + - "pyproject.toml" + - "uv.lock" + - ".github/workflows/docker.yml" + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Extract version from __init__.py + id: version + run: | + VERSION=$(grep -oP '__version__ = "\K[^"]+' unshackle/core/__init__.py) + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "major_minor=$(echo $VERSION | cut -d. -f1-2)" >> $GITHUB_OUTPUT + echo "major=$(echo $VERSION | cut -d. -f1)" >> $GITHUB_OUTPUT + echo "Extracted version: $VERSION" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=raw,value=latest,enable={{is_default_branch}} + type=raw,value=v${{ steps.version.outputs.version }},enable={{is_default_branch}} + type=raw,value=${{ steps.version.outputs.version }},enable={{is_default_branch}} + type=raw,value=${{ steps.version.outputs.major_minor }},enable={{is_default_branch}} + type=raw,value=${{ steps.version.outputs.major }},enable={{is_default_branch}} + + - name: Show planned tags + run: | + echo "Planning to create the following tags:" + echo "${{ steps.meta.outputs.tags }}" + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Test Docker image + if: github.event_name != 'pull_request' + run: | + docker run --rm ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest env check diff --git a/.gitignore b/.gitignore index 6ae91b6..8d23d5c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ # unshackle -.github/ unshackle.yaml unshackle.yml *.mkv diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..387248b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,78 @@ +FROM python:3.12-slim + +# Set environment variables to reduce image size +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + UV_CACHE_DIR=/tmp/uv-cache + +# Add container metadata +LABEL org.opencontainers.image.description="Docker image for Unshackle with all required dependencies for downloading media content" + +# Install base dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + wget \ + gnupg \ + git \ + curl \ + build-essential \ + cmake \ + pkg-config \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Set up repos for mkvtools and bullseye for ccextractor +RUN wget -O /etc/apt/keyrings/gpg-pub-moritzbunkus.gpg https://mkvtoolnix.download/gpg-pub-moritzbunkus.gpg \ + && echo "deb [signed-by=/etc/apt/keyrings/gpg-pub-moritzbunkus.gpg] https://mkvtoolnix.download/debian/ bookworm main" >> /etc/apt/sources.list \ + && echo "deb-src [signed-by=/etc/apt/keyrings/gpg-pub-moritzbunkus.gpg] https://mkvtoolnix.download/debian/ bookworm main" >> /etc/apt/sources.list \ + && echo "deb http://ftp.debian.org/debian bullseye main" >> /etc/apt/sources.list + +# Install all dependencies from apt +RUN apt-get update && apt-get install -y \ + ffmpeg \ + ccextractor \ + mkvtoolnix \ + aria2 \ + libmediainfo-dev \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Install shaka packager +RUN wget https://github.com/shaka-project/shaka-packager/releases/download/v3.4.1/packager-linux-x64 \ + && chmod +x packager-linux-x64 \ + && mv packager-linux-x64 /usr/local/bin/packager + +# Install N_m3u8DL-RE +RUN wget https://github.com/nilaoda/N_m3u8DL-RE/releases/download/v0.3.0-beta/N_m3u8DL-RE_v0.3.0-beta_linux-x64_20241203.tar.gz \ + && tar -xzf N_m3u8DL-RE_v0.3.0-beta_linux-x64_20241203.tar.gz \ + && mv N_m3u8DL-RE /usr/local/bin/ \ + && chmod +x /usr/local/bin/N_m3u8DL-RE \ + && rm N_m3u8DL-RE_v0.3.0-beta_linux-x64_20241203.tar.gz + +# Create binaries directory and add symlinks for all required executables +RUN mkdir -p /app/binaries && \ + ln -sf /usr/bin/ffprobe /app/binaries/ffprobe && \ + ln -sf /usr/bin/ffmpeg /app/binaries/ffmpeg && \ + ln -sf /usr/bin/mkvmerge /app/binaries/mkvmerge && \ + ln -sf /usr/local/bin/N_m3u8DL-RE /app/binaries/N_m3u8DL-RE && \ + ln -sf /usr/local/bin/packager /app/binaries/packager && \ + ln -sf /usr/local/bin/packager /usr/local/bin/shaka-packager && \ + ln -sf /usr/local/bin/packager /usr/local/bin/packager-linux-x64 + +# Install uv +RUN pip install --no-cache-dir uv + +# Set working directory +WORKDIR /app + +# Copy dependency files and README (required by pyproject.toml) +COPY pyproject.toml uv.lock README.md ./ + +# Copy source code first +COPY unshackle/ ./unshackle/ + +# Install dependencies with uv (including the project itself) +RUN uv sync --frozen --no-dev + +# Set entrypoint to allow passing commands directly to unshackle +ENTRYPOINT ["uv", "run", "unshackle"] +CMD ["-h"] \ No newline at end of file