├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug-report.yml │ ├── config.yml │ └── feature-request.yml └── workflows │ ├── build-image.yml │ └── build-nightly-image.yml ├── DOCKERHUB.md ├── Dockerfile ├── LICENSE ├── README.md ├── appdefs.yml ├── rootfs ├── defaults │ ├── hooks │ │ ├── post_conversion.sh.example │ │ ├── post_watch_folder_processing.sh.example │ │ └── pre_conversion.sh.example │ └── preferences.json ├── etc │ ├── cont-env.d │ │ ├── INSTALL_PACKAGES_INTERNAL │ │ └── SUP_GROUP_IDS_INTERNAL │ ├── cont-init.d │ │ ├── 54-check-optical-drive.sh │ │ ├── 54-check-qsv.sh │ │ ├── 54-check-trash-dir.sh │ │ └── 55-handbrake.sh │ ├── ld-musl-x86_64.path │ ├── machine-id │ ├── openbox │ │ └── main-window-selection.xml │ └── services.d │ │ ├── app │ │ └── disabled │ │ ├── autovideoconverter │ │ ├── disabled │ │ ├── priority │ │ ├── respawn │ │ ├── run │ │ ├── sgid │ │ └── umask │ │ └── default │ │ └── autovideoconverter.dep ├── startapp.sh └── trash │ └── .not_mapped └── src ├── cpu_features └── build.sh └── handbrake ├── build.sh ├── cross-compile-fix.patch ├── gmmlib-compile-fix.patch ├── intel-media-driver-compile-fix.patch ├── intel-media-sdk-compile-fix.patch ├── intel-media-sdk-debug-no-assert.patch └── maximized-window.patch /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: jlesage 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ["https://paypal.me/JocelynLeSage", "https://www.tesla.com/referral/jocelyn4590"] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | name: Bug report 2 | description: File a bug report. 3 | title: "[Bug] Provide a short description of the bug here" 4 | labels: ["bug"] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for taking the time to fill out this bug report! 10 | - type: textarea 11 | attributes: 12 | label: Current Behavior 13 | description: A concise description of what you're experiencing. 14 | validations: 15 | required: true 16 | - type: textarea 17 | attributes: 18 | label: Expected Behavior 19 | description: A concise description of what you expected to happen. 20 | validations: 21 | required: false 22 | - type: textarea 23 | attributes: 24 | label: Steps To Reproduce 25 | description: Steps to reproduce the behavior. 26 | validations: 27 | required: false 28 | - type: textarea 29 | attributes: 30 | label: Environment 31 | description: | 32 | Provide details about the host running the container. 33 | Examples: 34 | - Operating system (e.g. Ubuntu, Windows, TrueNAS, openmediavault, unRAID, etc). 35 | - Version of the operating system. 36 | - CPU architecture (x86-64, arm, arm64, etc). 37 | - Model of the device, if applicable (e.g. Raspberry Pi 4B, Synology DS418, QNAP TS-364, etc). 38 | - The Docker version (output of `docker version`). 39 | - Anything else specific to your environment. Examples: 40 | - Network share (NFS, CIFS) mapped to the container. 41 | - Docker running in LXC container. 42 | - etc. 43 | - If applicable, how the UI provided by the container is access: 44 | - Browser (Chrome, Firefox, Edge, etc). 45 | - Version of the browser. 46 | - OS of the browser. 47 | - Is the container accessed through a reverse proxy. 48 | - etc. 49 | value: | 50 | - OS: 51 | - OS version: 52 | - CPU: 53 | - Docker version: 54 | - Device model: 55 | - Browser/OS: 56 | validations: 57 | required: false 58 | - type: textarea 59 | attributes: 60 | label: Container creation 61 | description: | 62 | How did you create the container ? 63 | Examples: 64 | - The `docker run` command used. 65 | - The compose file used. 66 | - Screenshots of the management tool UI (e.g. Portainer, unRAID, etc) showing container settings. 67 | validations: 68 | required: true 69 | - type: textarea 70 | attributes: 71 | label: Container log 72 | description: Please copy/paste the output of `docker logs `. 73 | render: text 74 | validations: 75 | required: true 76 | - type: textarea 77 | attributes: 78 | label: Container inspect 79 | description: | 80 | If the container is running, please provide the output of `docker inspect `. 81 | **Attention**: If you defined passwords, secrets or any sensitive information via environment variables, make sure to remove them from the output. 82 | render: text 83 | validations: 84 | required: false 85 | - type: textarea 86 | attributes: 87 | label: Anything else? 88 | description: | 89 | Anything that will give more context about the issue you are encountering. 90 | 91 | Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. 92 | validations: 93 | required: false 94 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask a question, discuss 4 | url: https://github.com/jlesage/docker-handbrake/discussions 5 | about: Get help using this Docker container. 6 | - name: Documentation 7 | url: https://github.com/jlesage/docker-handbrake#readme 8 | about: Documentation about this Docker container. 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea for this project. 3 | title: "[Feature request] Provide a short description of the feature here" 4 | labels: ["enhancement"] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thank you for suggesting an idea to make this project better. 10 | - type: textarea 11 | attributes: 12 | label: Idea 13 | description: | 14 | Please describe the desired behavior, pitch your idea, or suggest improvements. 15 | validations: 16 | required: true 17 | -------------------------------------------------------------------------------- /.github/workflows/build-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker image CI/CD 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | env: 8 | DOCKER_IMAGE_NAME: jlesage/handbrake 9 | PLATFORMS: linux/amd64 10 | 11 | on: 12 | push: 13 | branches: 14 | - '*' 15 | - '!nightly' 16 | tags: 17 | - v[0-9][0-9].[0-9][0-9].[0-9]+ 18 | - v[0-9][0-9].[0-9][0-9].[0-9]+-pre.[0-9]+ 19 | pull_request: 20 | 21 | jobs: 22 | build: 23 | name: Build image 24 | runs-on: ubuntu-22.04 25 | 26 | steps: 27 | - name: Free disk space 28 | uses: jlumbroso/free-disk-space@main 29 | with: 30 | tool-cache: true 31 | android: true 32 | dotnet: true 33 | haskell: true 34 | large-packages: true 35 | docker-images: true 36 | swap-storage: false 37 | 38 | - name: Prepare 39 | id: prep 40 | run: | 41 | # Determine the Docker container version. 42 | VERSION=unknown 43 | if [[ $GITHUB_REF =~ refs/tags/* ]]; then 44 | # Git tag pushed: use tag as the version. 45 | VERSION=${GITHUB_REF#refs/tags/} 46 | elif [[ $GITHUB_REF =~ refs/heads/* ]]; then 47 | # Git commit pushed: use the commit SHA as the version. 48 | VERSION=${GITHUB_SHA::8} 49 | elif [[ $GITHUB_REF =~ refs/pull/* ]]; then 50 | # Pull request: use PR number as the version. 51 | VERSION=pr-${{ github.event.number }} 52 | else 53 | echo "::error::Unexpected GITHUB_REF: $GITHUB_REF" 54 | exit 1 55 | fi 56 | # Determine the version to put in container label. 57 | LABEL_VERSION=${VERSION} 58 | if [[ $GITHUB_REF =~ refs/tags/* ]]; then 59 | # Do not include the starting 'v' of the version. 60 | LABEL_VERSION=${VERSION:1} 61 | fi 62 | # Determine the Docker container tags. 63 | TAGS="${{ env.DOCKER_IMAGE_NAME }}:${VERSION}" 64 | if [[ $GITHUB_REF =~ refs/tags/* ]]; then 65 | TAGS="$TAGS,${{ env.DOCKER_IMAGE_NAME }}:latest" 66 | fi 67 | TAGS="$TAGS,$(echo $TAGS | tr ',' '\n' | sed 's|^|ghcr.io/|' | tr '\n' ',')" 68 | # Determine the release type. 69 | if [[ $GITHUB_REF =~ refs/tags/* ]]; then 70 | IS_RELEASE=yes 71 | if [[ $GITHUB_REF =~ -pre\.[0-9]+ ]]; then 72 | RELEASE_TYPE="pre" 73 | else 74 | RELEASE_TYPE="standard" 75 | fi 76 | else 77 | IS_RELEASE=no 78 | RELEASE_TYPE="n/a" 79 | fi 80 | # Print results. 81 | echo "::group::Results" 82 | echo "Github reference: $GITHUB_REF" 83 | echo "Release: $IS_RELEASE" 84 | echo "Release type: $RELEASE_TYPE" 85 | echo "Docker container version: $VERSION" 86 | echo "Docker container version label: $LABEL_VERSION" 87 | echo "Docker container tag(s): $TAGS" 88 | echo "::endgroup::" 89 | # Export outputs. 90 | echo "is_release=${IS_RELEASE}" >> $GITHUB_OUTPUT 91 | echo "release_type=${RELEASE_TYPE}" >> $GITHUB_OUTPUT 92 | echo "version=${VERSION}" >> $GITHUB_OUTPUT 93 | echo "label_version=${LABEL_VERSION}" >> $GITHUB_OUTPUT 94 | echo "tags=${TAGS}" >> $GITHUB_OUTPUT 95 | #echo "build_date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT 96 | 97 | - name: Setup QEMU 98 | uses: docker/setup-qemu-action@v3 99 | with: 100 | platforms: arm,arm64,ppc64le,mips64,s390x 101 | 102 | - name: Setup Docker Buildx 103 | uses: docker/setup-buildx-action@v3 104 | 105 | - name: Login to DockerHub 106 | if: ${{ steps.prep.outputs.is_release == 'yes' }} 107 | uses: docker/login-action@v3 108 | with: 109 | username: ${{ secrets.DOCKERHUB_USERNAME }} 110 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 111 | 112 | - name: Login to GitHub Container Registry 113 | if: ${{ steps.prep.outputs.is_release == 'yes' }} 114 | uses: docker/login-action@v3 115 | with: 116 | registry: ghcr.io 117 | username: ${{ github.repository_owner }} 118 | password: ${{ secrets.GITHUB_TOKEN }} 119 | 120 | - name: Build and push 121 | uses: docker/build-push-action@v6 122 | with: 123 | push: ${{ steps.prep.outputs.is_release == 'yes' }} 124 | provenance: false 125 | platforms: ${{ env.PLATFORMS }} 126 | tags: ${{ steps.prep.outputs.tags }} 127 | build-args: | 128 | DOCKER_IMAGE_VERSION=${{ steps.prep.outputs.label_version }} 129 | cache-from: type=gha,scope=${{ env.DOCKER_IMAGE_NAME }} 130 | cache-to: type=gha,mode=max,scope=${{ env.DOCKER_IMAGE_NAME }} 131 | 132 | - name: Build and push (debug version) 133 | uses: docker/build-push-action@v4 134 | with: 135 | push: ${{ steps.prep.outputs.is_release == 'yes' }} 136 | provenance: false 137 | platforms: ${{ env.PLATFORMS }} 138 | tags: ${{ env.DOCKER_IMAGE_NAME }}:${{ steps.prep.outputs.version }}-debug 139 | build-args: | 140 | DOCKER_IMAGE_VERSION=${{ steps.prep.outputs.label_version }}-debug 141 | HANDBRAKE_DEBUG_MODE=max 142 | cache-from: type=gha,scope=${{ env.DOCKER_IMAGE_NAME }} 143 | cache-to: type=gha,mode=max,scope=${{ env.DOCKER_IMAGE_NAME }} 144 | 145 | - name: Inspect 146 | if: ${{ steps.prep.outputs.is_release == 'yes' }} 147 | run: | 148 | docker buildx imagetools inspect ${{ env.DOCKER_IMAGE_NAME }}:${{ steps.prep.outputs.version }} 149 | 150 | - name: Inspect (debug version) 151 | if: ${{ steps.prep.outputs.is_release == 'yes' }} 152 | run: | 153 | docker buildx imagetools inspect ${{ env.DOCKER_IMAGE_NAME }}:${{ steps.prep.outputs.version }}-debug 154 | 155 | - name: Checkout 156 | uses: actions/checkout@v4 157 | if: ${{ steps.prep.outputs.release_type == 'standard' }} 158 | 159 | - name: Dockerhub description 160 | if: ${{ steps.prep.outputs.release_type == 'standard' }} 161 | uses: peter-evans/dockerhub-description@v4 162 | with: 163 | username: ${{ secrets.DOCKERHUB_USERNAME }} 164 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 165 | repository: ${{ env.DOCKER_IMAGE_NAME }} 166 | readme-filepath: DOCKERHUB.md 167 | 168 | notification: 169 | name: Notification 170 | needs: [ build ] 171 | runs-on: ubuntu-22.04 172 | if: ${{ always() && github.event_name != 'pull_request' }} 173 | 174 | steps: 175 | - name: Pushover notification 176 | uses: desiderati/github-action-pushover@v1 177 | with: 178 | job-status: ${{ needs.build.result }} 179 | pushover-api-token: ${{ secrets.PUSHOVER_API_TOKEN }} 180 | pushover-user-key: ${{ secrets.PUSHOVER_USER_KEY }} 181 | -------------------------------------------------------------------------------- /.github/workflows/build-nightly-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker nightly image CI/CD 2 | 3 | concurrency: 4 | group: nightly-build 5 | cancel-in-progress: true 6 | 7 | env: 8 | DOCKER_IMAGE_NAME: jlesage/handbrake 9 | PLATFORMS: linux/amd64 10 | 11 | on: 12 | # Run this workflow once a day. 13 | schedule: 14 | - cron: '0 0 * * *' 15 | 16 | # Allows to run this workflow manually from the Actions tab. 17 | workflow_dispatch: 18 | 19 | jobs: 20 | prepare: 21 | name: Prepare 22 | runs-on: ubuntu-22.04 23 | 24 | # Map a step output to a job output. 25 | outputs: 26 | handbrake_version: ${{ steps.prep.outputs.handbrake_version }} 27 | version: ${{ steps.prep.outputs.version }} 28 | label_version: ${{ steps.prep.outputs.label_version }} 29 | tags: ${{ steps.prep.outputs.tags }} 30 | build_needed: ${{ steps.prep.outputs.build_needed }} 31 | 32 | steps: 33 | - name: Prepare 34 | id: prep 35 | run: | 36 | # Get info about the last HandBrake commit. 37 | HANDBRAKE_LAST_COMMIT="$(curl -s "https://api.github.com/repos/HandBrake/HandBrake/commits?page=1&per_page=1" | jq -r '.[0] | .commit.committer.date + " " + .sha')" 38 | HANDBRAKE_LAST_COMMIT_SHORT_HASH="$(echo "$HANDBRAKE_LAST_COMMIT" | awk '{print substr($2,0,10)}')" 39 | HANDBRAKE_LAST_COMMIT_DATE="$(env TZ=UTC date -d"$(echo "$HANDBRAKE_LAST_COMMIT" | awk '{print $1}')" +%Y%m%d%H%M%S)" 40 | # Determine the HandBrake version. 41 | HANDBRAKE_VERSION="nightly-${HANDBRAKE_LAST_COMMIT_DATE}-${HANDBRAKE_LAST_COMMIT_SHORT_HASH}" 42 | # Determine the Docker nightly image version. 43 | # NOTE: The image version is the same as the HandBrake version. 44 | VERSION="$HANDBRAKE_VERSION" 45 | # Determine the version to put in container label. 46 | LABEL_VERSION="$VERSION" 47 | # Determine the Docker container tags. 48 | TAGS="${{ env.DOCKER_IMAGE_NAME }}:${VERSION},${{ env.DOCKER_IMAGE_NAME }}:nightly-latest" 49 | # Determine if a build is needed. 50 | if curl --silent -f "https://hub.docker.com/v2/repositories/${{ env.DOCKER_IMAGE_NAME }}/tags/${VERSION}/" > /dev/null 51 | then 52 | BUILD_NEEDED=no 53 | else 54 | BUILD_NEEDED=yes 55 | fi 56 | # Print results. 57 | echo "::group::Results" 58 | echo "HandBrake last commit hash: $HANDBRAKE_LAST_COMMIT_SHORT_HASH" 59 | echo "HandBrake last commit date: $HANDBRAKE_LAST_COMMIT_DATE" 60 | echo "HandBrake version: $HANDBRAKE_VERSION" 61 | echo "Docker nightly image version: $VERSION" 62 | echo "Docker nightly image version label: $LABEL_VERSION" 63 | echo "Docker nightly image tag(s): $TAGS" 64 | echo "Build needed: $BUILD_NEEDED" 65 | echo "::endgroup::" 66 | # Export outputs. 67 | echo "handbrake_version=${HANDBRAKE_VERSION}" >> $GITHUB_OUTPUT 68 | echo "version=${VERSION}" >> $GITHUB_OUTPUT 69 | echo "label_version=${LABEL_VERSION}" >> $GITHUB_OUTPUT 70 | echo "tags=${TAGS}" >> $GITHUB_OUTPUT 71 | echo "build_needed=${BUILD_NEEDED}" >> $GITHUB_OUTPUT 72 | 73 | build: 74 | name: Build image 75 | runs-on: ubuntu-22.04 76 | needs: prepare 77 | if: ${{ needs.prepare.outputs.build_needed == 'yes' }} 78 | 79 | steps: 80 | - name: Free disk space 81 | run: | 82 | # Free disk space. 83 | echo "::group::Before" 84 | df -h / 85 | echo "::endgroup::" 86 | echo "::group::Removing unneeded softwares and files..." 87 | for DIR in /usr/local/lib/android /usr/share/dotnet /opt/ghc 88 | do 89 | if [ -d "$DIR" ]; then 90 | echo "Removing $DIR..." 91 | sudo rm -r "$DIR" 92 | fi 93 | done 94 | echo "::endgroup::" 95 | echo "::group::After" 96 | df -h / 97 | echo "::endgroup::" 98 | 99 | - name: Checkout 100 | uses: actions/checkout@v3 101 | with: 102 | ref: nightly 103 | 104 | - name: Setup QEMU 105 | uses: docker/setup-qemu-action@v2 106 | with: 107 | platforms: arm,arm64,ppc64le,mips64,s390x 108 | 109 | - name: Setup Docker Buildx 110 | uses: docker/setup-buildx-action@v2 111 | 112 | - name: Login to DockerHub 113 | uses: docker/login-action@v2 114 | with: 115 | username: ${{ secrets.DOCKERHUB_USERNAME }} 116 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 117 | 118 | - name: Build and push 119 | uses: docker/build-push-action@v4 120 | with: 121 | context: . 122 | push: true 123 | platforms: ${{ env.PLATFORMS }} 124 | tags: ${{ needs.prepare.outputs.tags }} 125 | build-args: | 126 | DOCKER_IMAGE_VERSION=${{ needs.prepare.outputs.label_version }} 127 | HANDBRAKE_VERSION=${{ needs.prepare.outputs.handbrake_version }} 128 | HANDBRAKE_URL=https://github.com/HandBrake/HandBrake.git 129 | HANDBRAKE_DEBUG_MODE=max 130 | cache-from: type=gha,scope=${{ env.DOCKER_IMAGE_NAME }}-nightly 131 | cache-to: type=gha,mode=max,scope=${{ env.DOCKER_IMAGE_NAME }}-nightly 132 | 133 | - name: Inspect 134 | run: | 135 | docker buildx imagetools inspect ${{ env.DOCKER_IMAGE_NAME }}:${{ needs.prepare.outputs.version }} 136 | 137 | notification: 138 | name: Notification 139 | needs: [ prepare, build ] 140 | runs-on: ubuntu-22.04 141 | if: ${{ always() && needs.prepare.outputs.build_needed == 'yes' }} 142 | 143 | steps: 144 | - name: Pushover notification 145 | uses: desiderati/github-action-pushover@v1 146 | with: 147 | job-status: ${{ needs.build.result }} 148 | pushover-api-token: ${{ secrets.PUSHOVER_API_TOKEN }} 149 | pushover-user-key: ${{ secrets.PUSHOVER_USER_KEY }} 150 | -------------------------------------------------------------------------------- /DOCKERHUB.md: -------------------------------------------------------------------------------- 1 | # Docker container for HandBrake 2 | [![Release](https://img.shields.io/github/release/jlesage/docker-handbrake.svg?logo=github&style=for-the-badge)](https://github.com/jlesage/docker-handbrake/releases/latest) 3 | [![Docker Image Size](https://img.shields.io/docker/image-size/jlesage/handbrake/latest?logo=docker&style=for-the-badge)](https://hub.docker.com/r/jlesage/handbrake/tags) 4 | [![Docker Pulls](https://img.shields.io/docker/pulls/jlesage/handbrake?label=Pulls&logo=docker&style=for-the-badge)](https://hub.docker.com/r/jlesage/handbrake) 5 | [![Docker Stars](https://img.shields.io/docker/stars/jlesage/handbrake?label=Stars&logo=docker&style=for-the-badge)](https://hub.docker.com/r/jlesage/handbrake) 6 | [![Build Status](https://img.shields.io/github/actions/workflow/status/jlesage/docker-handbrake/build-image.yml?logo=github&branch=master&style=for-the-badge)](https://github.com/jlesage/docker-handbrake/actions/workflows/build-image.yml) 7 | [![Source](https://img.shields.io/badge/Source-GitHub-blue?logo=github&style=for-the-badge)](https://github.com/jlesage/docker-handbrake) 8 | [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg?style=for-the-badge)](https://paypal.me/JocelynLeSage) 9 | 10 | This is a Docker container for [HandBrake](https://handbrake.fr). 11 | 12 | The GUI of the application is accessed through a modern web browser (no 13 | installation or configuration needed on the client side) or via any VNC client. 14 | 15 | A fully automated mode is also available: drop files into a watch folder and let 16 | HandBrake process them without any user interaction. 17 | 18 | --- 19 | 20 | [![HandBrake logo](https://images.weserv.nl/?url=raw.githubusercontent.com/jlesage/docker-templates/master/jlesage/images/handbrake-icon.png&w=110)](https://handbrake.fr)[![HandBrake](https://images.placeholders.dev/?width=288&height=110&fontFamily=monospace&fontWeight=400&fontSize=52&text=HandBrake&bgColor=rgba(0,0,0,0.0)&textColor=rgba(121,121,121,1))](https://handbrake.fr) 21 | 22 | HandBrake is a tool for converting video from nearly any format to a selection 23 | of modern, widely supported codecs. 24 | 25 | --- 26 | 27 | ## Quick Start 28 | 29 | **NOTE**: 30 | The Docker command provided in this quick start is given as an example 31 | and parameters should be adjusted to your need. 32 | 33 | Launch the HandBrake docker container with the following command: 34 | ```shell 35 | docker run -d \ 36 | --name=handbrake \ 37 | -p 5800:5800 \ 38 | -v /docker/appdata/handbrake:/config:rw \ 39 | -v /home/user:/storage:ro \ 40 | -v /home/user/HandBrake/watch:/watch:rw \ 41 | -v /home/user/HandBrake/output:/output:rw \ 42 | jlesage/handbrake 43 | ``` 44 | 45 | Where: 46 | 47 | - `/docker/appdata/handbrake`: This is where the application stores its configuration, states, log and any files needing persistency. 48 | - `/home/user`: This location contains files from your host that need to be accessible to the application. 49 | - `/home/user/HandBrake/watch`: This is where videos to be automatically converted are located 50 | - `/home/user/HandBrake/output`: This is where automatically converted video files are written. 51 | 52 | Browse to `http://your-host-ip:5800` to access the HandBrake GUI. 53 | Files from the host appear under the `/storage` folder in the container. 54 | 55 | ## Documentation 56 | 57 | Full documentation is available at https://github.com/jlesage/docker-handbrake. 58 | 59 | ## Support or Contact 60 | 61 | Having troubles with the container or have questions? Please 62 | [create a new issue]. 63 | 64 | For other great Dockerized applications, see https://jlesage.github.io/docker-apps. 65 | 66 | [create a new issue]: https://github.com/jlesage/docker-handbrake/issues 67 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # handbrake Dockerfile 3 | # 4 | # https://github.com/jlesage/docker-handbrake 5 | # 6 | 7 | # Docker image version is provided via build arg. 8 | ARG DOCKER_IMAGE_VERSION= 9 | 10 | # Define software versions. 11 | ARG HANDBRAKE_VERSION=1.9.2 12 | ARG LIBVA_VERSION=2.22.0 13 | ARG INTEL_VAAPI_DRIVER_VERSION=2.4.1 14 | ARG GMMLIB_VERSION=22.7.1 15 | ARG INTEL_MEDIA_DRIVER_VERSION=25.1.4 16 | ARG INTEL_MEDIA_SDK_VERSION=23.2.2 17 | ARG INTEL_ONEVPL_GPU_RUNTIME_VERSION=25.1.4 18 | ARG CPU_FEATURES_VERSION=0.9.0 19 | 20 | # Define software download URLs. 21 | ARG HANDBRAKE_URL=https://github.com/HandBrake/HandBrake/releases/download/${HANDBRAKE_VERSION}/HandBrake-${HANDBRAKE_VERSION}-source.tar.bz2 22 | ARG LIBVA_URL=https://github.com/intel/libva/releases/download/${LIBVA_VERSION}/libva-${LIBVA_VERSION}.tar.bz2 23 | ARG INTEL_VAAPI_DRIVER_URL=https://github.com/intel/intel-vaapi-driver/releases/download/${INTEL_VAAPI_DRIVER_VERSION}/intel-vaapi-driver-${INTEL_VAAPI_DRIVER_VERSION}.tar.bz2 24 | ARG GMMLIB_URL=https://github.com/intel/gmmlib/archive/intel-gmmlib-${GMMLIB_VERSION}.tar.gz 25 | ARG INTEL_MEDIA_DRIVER_URL=https://github.com/intel/media-driver/archive/intel-media-${INTEL_MEDIA_DRIVER_VERSION}.tar.gz 26 | ARG INTEL_MEDIA_SDK_URL=https://github.com/Intel-Media-SDK/MediaSDK/archive/intel-mediasdk-${INTEL_MEDIA_SDK_VERSION}.tar.gz 27 | ARG INTEL_ONEVPL_GPU_RUNTIME_URL=https://github.com/oneapi-src/oneVPL-intel-gpu/archive/refs/tags/intel-onevpl-${INTEL_ONEVPL_GPU_RUNTIME_VERSION}.tar.gz 28 | ARG CPU_FEATURES_URL=https://github.com/google/cpu_features/archive/refs/tags/v${CPU_FEATURES_VERSION}.tar.gz 29 | 30 | # Set to 'max' to keep debug symbols. 31 | ARG HANDBRAKE_DEBUG_MODE=none 32 | 33 | # Get Dockerfile cross-compilation helpers. 34 | FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx 35 | 36 | # Build HandBrake. 37 | FROM --platform=$BUILDPLATFORM alpine:3.19 AS handbrake 38 | ARG TARGETPLATFORM 39 | ARG HANDBRAKE_VERSION 40 | ARG HANDBRAKE_URL 41 | ARG HANDBRAKE_DEBUG_MODE 42 | ARG LIBVA_URL 43 | ARG INTEL_VAAPI_DRIVER_URL 44 | ARG GMMLIB_URL 45 | ARG INTEL_MEDIA_DRIVER_URL 46 | ARG INTEL_MEDIA_SDK_URL 47 | ARG INTEL_ONEVPL_GPU_RUNTIME_URL 48 | COPY --from=xx / / 49 | COPY src/handbrake /build 50 | RUN /build/build.sh \ 51 | "$HANDBRAKE_VERSION" \ 52 | "$HANDBRAKE_URL" \ 53 | "$HANDBRAKE_DEBUG_MODE" \ 54 | "$LIBVA_URL" \ 55 | "$INTEL_VAAPI_DRIVER_URL" \ 56 | "$GMMLIB_URL" \ 57 | "$INTEL_MEDIA_DRIVER_URL" \ 58 | "$INTEL_MEDIA_SDK_URL" \ 59 | "$INTEL_ONEVPL_GPU_RUNTIME_URL" 60 | RUN xx-verify \ 61 | /tmp/handbrake-install/usr/bin/ghb \ 62 | /tmp/handbrake-install/usr/bin/HandBrakeCLI 63 | 64 | # Build cpu_features. 65 | FROM --platform=$BUILDPLATFORM alpine:3.19 AS cpu_features 66 | ARG TARGETPLATFORM 67 | ARG CPU_FEATURES_URL 68 | COPY --from=xx / / 69 | COPY src/cpu_features /build 70 | RUN /build/build.sh "$CPU_FEATURES_URL" 71 | RUN xx-verify /tmp/cpu_features-install/bin/list_cpu_features 72 | 73 | # Pull base image. 74 | FROM jlesage/baseimage-gui:alpine-3.19-v4.7.1 75 | 76 | ARG HANDBRAKE_VERSION 77 | ARG DOCKER_IMAGE_VERSION 78 | 79 | # Define working directory. 80 | WORKDIR /tmp 81 | 82 | # Install dependencies. 83 | RUN \ 84 | add-pkg \ 85 | libstdc++ \ 86 | gtk4.0 \ 87 | gst-plugins-good \ 88 | gst-libav \ 89 | libgudev \ 90 | libnotify \ 91 | libsamplerate \ 92 | libass \ 93 | libdrm \ 94 | jansson \ 95 | xz \ 96 | numactl \ 97 | libturbojpeg \ 98 | # Media codecs: 99 | libtheora \ 100 | lame-libs \ 101 | opus \ 102 | libvorbis \ 103 | speex \ 104 | libvpx \ 105 | x264-libs \ 106 | # For QSV detection 107 | pciutils \ 108 | # To read encrypted DVDs 109 | libdvdcss \ 110 | # A font is needed. 111 | font-cantarell \ 112 | # For main, big icons: 113 | librsvg \ 114 | # For all other small icons: 115 | adwaita-icon-theme \ 116 | # For optical drive listing: 117 | lsscsi \ 118 | # For watchfolder 119 | bash \ 120 | coreutils \ 121 | findutils \ 122 | expect 123 | 124 | # && \ 125 | # # Save some space by removing unused DRI drivers. 126 | # find /usr/lib/xorg/modules/dri/ -type f ! -name swrast_dri.so ! -name libgallium_dri.so -exec echo "Removing {}..." ';' -delete 127 | 128 | # Generate and install favicons. 129 | RUN \ 130 | APP_ICON_URL=https://raw.githubusercontent.com/jlesage/docker-templates/master/jlesage/images/handbrake-icon.png && \ 131 | install_app_icon.sh "$APP_ICON_URL" 132 | 133 | # Add files. 134 | COPY rootfs/ / 135 | COPY --from=handbrake /tmp/handbrake-install / 136 | COPY --from=cpu_features /tmp/cpu_features-install/bin/list_cpu_features /usr/bin/ 137 | 138 | # Set internal environment variables. 139 | RUN \ 140 | set-cont-env APP_NAME "HandBrake" && \ 141 | set-cont-env APP_VERSION "$HANDBRAKE_VERSION" && \ 142 | set-cont-env DOCKER_IMAGE_VERSION "$DOCKER_IMAGE_VERSION" && \ 143 | true 144 | 145 | # Set public environment variables. 146 | ENV \ 147 | HANDBRAKE_DEBUG=0 \ 148 | HANDBRAKE_GUI=1 \ 149 | HANDBRAKE_GUI_QUEUE_STARTUP_ACTION=NONE \ 150 | AUTOMATED_CONVERSION=1 \ 151 | AUTOMATED_CONVERSION_PRESET="General/Very Fast 1080p30" \ 152 | AUTOMATED_CONVERSION_FORMAT=mp4 \ 153 | AUTOMATED_CONVERSION_SOURCE_STABLE_TIME=5 \ 154 | AUTOMATED_CONVERSION_SOURCE_MIN_DURATION=10 \ 155 | AUTOMATED_CONVERSION_SOURCE_MAIN_TITLE_DETECTION=0 \ 156 | AUTOMATED_CONVERSION_KEEP_SOURCE=1 \ 157 | AUTOMATED_CONVERSION_OUTPUT_DIR=/output \ 158 | AUTOMATED_CONVERSION_OUTPUT_SUBDIR= \ 159 | AUTOMATED_CONVERSION_OVERWRITE_OUTPUT=0 \ 160 | AUTOMATED_CONVERSION_VIDEO_FILE_EXTENSIONS= \ 161 | AUTOMATED_CONVERSION_NON_VIDEO_FILE_ACTION=ignore \ 162 | AUTOMATED_CONVERSION_NON_VIDEO_FILE_EXTENSIONS="jpg jpeg bmp png gif txt nfo" \ 163 | AUTOMATED_CONVERSION_MAX_WATCH_FOLDERS=5 \ 164 | AUTOMATED_CONVERSION_CHECK_INTERVAL=5 \ 165 | AUTOMATED_CONVERSION_HANDBRAKE_CUSTOM_ARGS= \ 166 | AUTOMATED_CONVERSION_INSTALL_PKGS= \ 167 | AUTOMATED_CONVERSION_NO_GUI_PROGRESS=0 \ 168 | AUTOMATED_CONVERSION_USE_TRASH=0 169 | 170 | # Define mountable directories. 171 | VOLUME ["/storage"] 172 | VOLUME ["/output"] 173 | VOLUME ["/watch"] 174 | VOLUME ["/trash"] 175 | 176 | # Metadata. 177 | LABEL \ 178 | org.label-schema.name="handbrake" \ 179 | org.label-schema.description="Docker container for HandBrake" \ 180 | org.label-schema.version="${DOCKER_IMAGE_VERSION:-}" \ 181 | org.label-schema.vcs-url="https://github.com/jlesage/docker-handbrake" \ 182 | org.label-schema.schema-version="1.0" 183 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Jocelyn Le Sage 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker container for HandBrake 2 | [![Release](https://img.shields.io/github/release/jlesage/docker-handbrake.svg?logo=github&style=for-the-badge)](https://github.com/jlesage/docker-handbrake/releases/latest) 3 | [![Docker Image Size](https://img.shields.io/docker/image-size/jlesage/handbrake/latest?logo=docker&style=for-the-badge)](https://hub.docker.com/r/jlesage/handbrake/tags) 4 | [![Docker Pulls](https://img.shields.io/docker/pulls/jlesage/handbrake?label=Pulls&logo=docker&style=for-the-badge)](https://hub.docker.com/r/jlesage/handbrake) 5 | [![Docker Stars](https://img.shields.io/docker/stars/jlesage/handbrake?label=Stars&logo=docker&style=for-the-badge)](https://hub.docker.com/r/jlesage/handbrake) 6 | [![Build Status](https://img.shields.io/github/actions/workflow/status/jlesage/docker-handbrake/build-image.yml?logo=github&branch=master&style=for-the-badge)](https://github.com/jlesage/docker-handbrake/actions/workflows/build-image.yml) 7 | [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg?style=for-the-badge)](https://paypal.me/JocelynLeSage) 8 | 9 | This project implements a Docker container for [HandBrake](https://handbrake.fr). 10 | 11 | The GUI of the application is accessed through a modern web browser (no 12 | installation or configuration needed on the client side) or via any VNC client. 13 | 14 | A fully automated mode is also available: drop files into a watch folder and let 15 | HandBrake process them without any user interaction. 16 | 17 | --- 18 | 19 | [![HandBrake logo](https://images.weserv.nl/?url=raw.githubusercontent.com/jlesage/docker-templates/master/jlesage/images/handbrake-icon.png&w=110)](https://handbrake.fr)[![HandBrake](https://images.placeholders.dev/?width=288&height=110&fontFamily=monospace&fontWeight=400&fontSize=52&text=HandBrake&bgColor=rgba(0,0,0,0.0)&textColor=rgba(121,121,121,1))](https://handbrake.fr) 20 | 21 | HandBrake is a tool for converting video from nearly any format to a selection 22 | of modern, widely supported codecs. 23 | 24 | --- 25 | 26 | ## Table of Content 27 | 28 | * [Quick Start](#quick-start) 29 | * [Usage](#usage) 30 | * [Environment Variables](#environment-variables) 31 | * [Deployment Considerations](#deployment-considerations) 32 | * [Data Volumes](#data-volumes) 33 | * [Ports](#ports) 34 | * [Changing Parameters of a Running Container](#changing-parameters-of-a-running-container) 35 | * [Docker Compose File](#docker-compose-file) 36 | * [Docker Image Versioning](#docker-image-versioning) 37 | * [Docker Image Update](#docker-image-update) 38 | * [Synology](#synology) 39 | * [unRAID](#unraid) 40 | * [User/Group IDs](#usergroup-ids) 41 | * [Accessing the GUI](#accessing-the-gui) 42 | * [Security](#security) 43 | * [SSVNC](#ssvnc) 44 | * [Certificates](#certificates) 45 | * [VNC Password](#vnc-password) 46 | * [Web Authentication](#web-authentication) 47 | * [Configuring Users Credentials](#configuring-users-credentials) 48 | * [Reverse Proxy](#reverse-proxy) 49 | * [Routing Based on Hostname](#routing-based-on-hostname) 50 | * [Routing Based on URL Path](#routing-based-on-url-path) 51 | * [Shell Access](#shell-access) 52 | * [Access to Optical Drive(s)](#access-to-optical-drives) 53 | * [Automatic Video Conversion](#automatic-video-conversion) 54 | * [Multiple Watch Folders](#multiple-watch-folders) 55 | * [Video Discs](#video-discs) 56 | * [Hooks](#hooks) 57 | * [Temporary Conversion Directory](#temporary-conversion-directory) 58 | * [Intel Quick Sync Video](#intel-quick-sync-video) 59 | * [unRAID](#unraid-1) 60 | * [Nightly Builds](#nightly-builds) 61 | * [Debug Builds](#debug-builds) 62 | * [unRAID](#unraid-2) 63 | * [Support or Contact](#support-or-contact) 64 | 65 | ## Quick Start 66 | 67 | > [!IMPORTANT] 68 | > The Docker command provided in this quick start is given as an example and 69 | > parameters should be adjusted to your need. 70 | 71 | Launch the HandBrake docker container with the following command: 72 | ```shell 73 | docker run -d \ 74 | --name=handbrake \ 75 | -p 5800:5800 \ 76 | -v /docker/appdata/handbrake:/config:rw \ 77 | -v /home/user:/storage:ro \ 78 | -v /home/user/HandBrake/watch:/watch:rw \ 79 | -v /home/user/HandBrake/output:/output:rw \ 80 | jlesage/handbrake 81 | ``` 82 | 83 | Where: 84 | 85 | - `/docker/appdata/handbrake`: This is where the application stores its configuration, states, log and any files needing persistency. 86 | - `/home/user`: This location contains files from your host that need to be accessible to the application. 87 | - `/home/user/HandBrake/watch`: This is where videos to be automatically converted are located 88 | - `/home/user/HandBrake/output`: This is where automatically converted video files are written. 89 | 90 | Browse to `http://your-host-ip:5800` to access the HandBrake GUI. 91 | Files from the host appear under the `/storage` folder in the container. 92 | 93 | ## Usage 94 | 95 | ```shell 96 | docker run [-d] \ 97 | --name=handbrake \ 98 | [-e =]... \ 99 | [-v :[:PERMISSIONS]]... \ 100 | [-p :]... \ 101 | jlesage/handbrake 102 | ``` 103 | 104 | | Parameter | Description | 105 | |-----------|-------------| 106 | | -d | Run the container in the background. If not set, the container runs in the foreground. | 107 | | -e | Pass an environment variable to the container. See the [Environment Variables](#environment-variables) section for more details. | 108 | | -v | Set a volume mapping (allows to share a folder/file between the host and the container). See the [Data Volumes](#data-volumes) section for more details. | 109 | | -p | Set a network port mapping (exposes an internal container port to the host). See the [Ports](#ports) section for more details. | 110 | 111 | ### Environment Variables 112 | 113 | To customize some properties of the container, the following environment 114 | variables can be passed via the `-e` parameter (one for each variable). Value 115 | of this parameter has the format `=`. 116 | 117 | | Variable | Description | Default | 118 | |----------------|----------------------------------------------|---------| 119 | |`USER_ID`| ID of the user the application runs as. See [User/Group IDs](#usergroup-ids) to better understand when this should be set. | `1000` | 120 | |`GROUP_ID`| ID of the group the application runs as. See [User/Group IDs](#usergroup-ids) to better understand when this should be set. | `1000` | 121 | |`SUP_GROUP_IDS`| Comma-separated list of supplementary group IDs of the application. | (no value) | 122 | |`UMASK`| Mask that controls how permissions are set for newly created files and folders. The value of the mask is in octal notation. By default, the default umask value is `0022`, meaning that newly created files and folders are readable by everyone, but only writable by the owner. See the online umask calculator at http://wintelguy.com/umask-calc.pl. | `0022` | 123 | |`LANG`| Set the [locale](https://en.wikipedia.org/wiki/Locale_(computer_software)), which defines the application's language, **if supported**. Format of the locale is `language[_territory][.codeset]`, where language is an [ISO 639 language code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes), territory is an [ISO 3166 country code](https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes) and codeset is a character set, like `UTF-8`. For example, Australian English using the UTF-8 encoding is `en_AU.UTF-8`. | `en_US.UTF-8` | 124 | |`TZ`| [TimeZone](http://en.wikipedia.org/wiki/List_of_tz_database_time_zones) used by the container. Timezone can also be set by mapping `/etc/localtime` between the host and the container. | `Etc/UTC` | 125 | |`KEEP_APP_RUNNING`| When set to `1`, the application will be automatically restarted when it crashes or terminates. | `0` | 126 | |`APP_NICENESS`| Priority at which the application should run. A niceness value of -20 is the highest priority and 19 is the lowest priority. The default niceness value is 0. **NOTE**: A negative niceness (priority increase) requires additional permissions. In this case, the container should be run with the docker option `--cap-add=SYS_NICE`. | `0` | 127 | |`INSTALL_PACKAGES`| Space-separated list of packages to install during the startup of the container. List of available packages can be found at https://pkgs.alpinelinux.org. **ATTENTION**: Container functionality can be affected when installing a package that overrides existing container files (e.g. binaries). | (no value) | 128 | |`PACKAGES_MIRROR`| Mirror of the repository to use when installing packages. List of mirrors is available at https://mirrors.alpinelinux.org. | (no value) | 129 | |`CONTAINER_DEBUG`| Set to `1` to enable debug logging. | `0` | 130 | |`DISPLAY_WIDTH`| Width (in pixels) of the application's window. | `1920` | 131 | |`DISPLAY_HEIGHT`| Height (in pixels) of the application's window. | `1080` | 132 | |`DARK_MODE`| When set to `1`, dark mode is enabled for the application. | `0` | 133 | |`WEB_AUDIO`| When set to `1`, audio support is enabled, meaning that any audio produced by the application is played through the browser. Note that audio is not supported for VNC clients. | `0` | 134 | |`WEB_AUTHENTICATION`| When set to `1`, the application's GUI is protected via a login page when accessed via a web browser. Access is allowed only when providing valid credentials. **NOTE**: This feature requires secure connection (`SECURE_CONNECTION` environment variable) to be enabled. | `0` | 135 | |`WEB_AUTHENTICATION_TOKEN_VALIDITY_TIME`| The lifetime of a token, in hours. A token is attributed to the user after a successful login. As long as the token is valid, user can access the application's GUI without having to log in again. Once the token expires, the login page is prompted again. | `24` | 136 | |`WEB_AUTHENTICATION_USERNAME`| Optional username to configure for the web authentication. This is a quick and easy way to configure credentials for a single user. To configure credentials in a more secure way, or to add more users, see the [Web Authentication](#web-authentication) section. | (no value) | 137 | |`WEB_AUTHENTICATION_PASSWORD`| Optional password to configure for the web authentication. This is a quick and easy way to configure credentials for a single user. To configure credentials in a more secure way, or to add more users, see the [Web Authentication](#web-authentication) section. | (no value) | 138 | |`SECURE_CONNECTION`| When set to `1`, an encrypted connection is used to access the application's GUI (either via a web browser or VNC client). See the [Security](#security) section for more details. | `0` | 139 | |`SECURE_CONNECTION_VNC_METHOD`| Method used to perform the secure VNC connection. Possible values are `SSL` or `TLS`. See the [Security](#security) section for more details. | `SSL` | 140 | |`SECURE_CONNECTION_CERTS_CHECK_INTERVAL`| Interval, in seconds, at which the system verifies if web or VNC certificates have changed. When a change is detected, the affected services are automatically restarted. A value of `0` disables the check. | `60` | 141 | |`WEB_LISTENING_PORT`| Port used by the web server to serve the UI of the application. This port is used internally by the container and it is usually not required to be changed. By default, a container is created with the default bridge network, meaning that, to be accessible, each internal container port must be mapped to an external port (using the `-p` or `--publish` argument). However, if the container is created with another network type, changing the port used by the container might be useful to prevent conflict with other services/containers. **NOTE**: a value of `-1` disables listening, meaning that the application's UI won't be accessible over HTTP/HTTPs. | `5800` | 142 | |`VNC_LISTENING_PORT`| Port used by the VNC server to serve the UI of the application. This port is used internally by the container and it is usually not required to be changed. By default, a container is created with the default bridge network, meaning that, to be accessible, each internal container port must be mapped to an external port (using the `-p` or `--publish` argument). However, if the container is created with another network type, changing the port used by the container might be useful to prevent conflict with other services/containers. **NOTE**: a value of `-1` disables listening, meaning that the application's UI won't be accessible over VNC. | `5900` | 143 | |`VNC_PASSWORD`| Password needed to connect to the application's GUI. See the [VNC Password](#vnc-password) section for more details. | (no value) | 144 | |`ENABLE_CJK_FONT`| When set to `1`, open-source computer font `WenQuanYi Zen Hei` is installed. This font contains a large range of Chinese/Japanese/Korean characters. | `0` | 145 | |`HANDBRAKE_DEBUG`| Setting this to `1` enables HandBrake debug logging for both the GUI and the automatic video converter. For the latter, the increased verbosity is reflected in `/config/log/hb/conversion.log` (container path). For the GUI, log messages are sent to `/config/log/hb/handbrake.debug.log` (container path). **NOTE**: When enabled, a lot of information is generated and the log file will grow quickly. Make sure to enable this temporarily and only when needed. | `0` | 146 | |`HANDBRAKE_GUI`| Setting this to `1` enables the HandBrake GUI, `0` disables it. | `1` | 147 | |`HANDBRAKE_GUI_QUEUE_STARTUP_ACTION`| Action to be taken on the queue of HandBrake (GUI) when it starts. When set to `PROCESS`, HandBrake automatically starts encoding elements present in the queue. When set to `CLEAR`, the content of the queue is cleared. With any other value, no action is taken on the queue. | `NONE` | 148 | |`AUTOMATED_CONVERSION`| Setting this to `1` enables the automatic video converter, `0` disables it. | `1` | 149 | |`AUTOMATED_CONVERSION_PRESET`| HandBrake preset used by the automatic video converter. Identification of a preset must follow the format `/`. See the [Automatic Video Conversion](#automatic-video-conversion) section for more details. | `General/Very Fast 1080p30` | 150 | |`AUTOMATED_CONVERSION_FORMAT`| Video container format used by the automatic video converter for output files. This is typically the video filename extension. See the [Automatic Video Conversion](#automatic-video-conversion) section for more details. | `mp4` | 151 | |`AUTOMATED_CONVERSION_KEEP_SOURCE`| When set to `0`, a video that has been successfully converted is removed from the watch folder. | `1` | 152 | |`AUTOMATED_CONVERSION_VIDEO_FILE_EXTENSIONS`| Space-separated list of file extensions to be considered as video files. By default, this list is empty, meaning that the automatic video converter will let HandBrake automatically detects if a file, no matter its extension, is a video or not (note that extensions defined by the `AUTOMATED_CONVERSION_NON_VIDEO_FILE_EXTENSIONS` environment variable are always considered as non-video files). Normally, this variable doesn't need to be set. Usage of this variable is useful when only specific video files need to converted. | (no value) | 153 | |`AUTOMATED_CONVERSION_NON_VIDEO_FILE_ACTION`| When set to `ignore`, a non-video file found in the watch folder is ignored. If set to `copy`, a non-video file is copied as-is to the output folder. | `ignore` | 154 | |`AUTOMATED_CONVERSION_NON_VIDEO_FILE_EXTENSIONS`| Space-separated list of file extensions to be considered as not being videos. Most non-video files are properly rejected by HandBrake. However, some files, like images, are convertible by HandBrake even if they are not video files. | `jpg jpeg bmp png gif txt nfo` | 155 | |`AUTOMATED_CONVERSION_OUTPUT_DIR`| Root directory, inside the container, where converted videos should be written. **NOTE**: Make sure a volume mapping for this directory is defined when creating the container. | `/output` | 156 | |`AUTOMATED_CONVERSION_OUTPUT_SUBDIR`| Subdirectory of the output folder into which converted videos should be written. By default, this variable is not set, meaning that videos are saved directly into `/output/`. If `Home/Movies` is set, converted videos will be written to `/output/Home/Movies`. Use the special value `SAME_AS_SRC` to use the same subfolder as the source. For example, if the video source file is `/watch/Movies/mymovie.mkv`, the converted video will be written to `/output/Movies/`. | (no value) | 157 | |`AUTOMATED_CONVERSION_OVERWRITE_OUTPUT`| Setting this to `1` allows the final destination file to be overwritten if it already exists. | `0` | 158 | |`AUTOMATED_CONVERSION_SOURCE_STABLE_TIME`| Time (in seconds) during which properties (e.g. size, time, etc) of a video file in the watch folder need to remain the same. This is to avoid processing a file that is being copied. | `5` | 159 | |`AUTOMATED_CONVERSION_SOURCE_MIN_DURATION`| Minimum title duration (in seconds). Shorter titles will be ignored. This applies only to video disc sources (ISO file, `VIDEO_TS` folder or `BDMV` folder). | `10` | 160 | |`AUTOMATED_CONVERSION_SOURCE_MAIN_TITLE_DETECTION`| Setting this to `1` enables HandBrake main feature title detection to try to guess and select the main title. | `0` | 161 | |`AUTOMATED_CONVERSION_CHECK_INTERVAL`| Interval (in seconds) at which the automatic video converter checks for new files. | `5` | 162 | |`AUTOMATED_CONVERSION_MAX_WATCH_FOLDERS`| Maximum number of watch folders handled by the automatic video converter. | `5` | 163 | |`AUTOMATED_CONVERSION_NO_GUI_PROGRESS`| When set to `1`, progress of videos converted by the automatic video converter is not shown in the HandBrake GUI. | `0` | 164 | |`AUTOMATED_CONVERSION_HANDBRAKE_CUSTOM_ARGS`| Custom arguments to pass to HandBrake when performing a conversion. | (no value) | 165 | |`AUTOMATED_CONVERSION_INSTALL_PKGS`| Space-separated list of Alpine Linux packages to install. This is useful when the automatic video converter's hooks require tools not available in the container image. See https://pkgs.alpinelinux.org for the list of available Alpine Linux packages. | (no value) | 166 | |`AUTOMATED_CONVERSION_USE_TRASH`| When set to `1`, the automatic video converter uses the trash directory. So when the automatic video converter is configured to *not* keep sources, it will move them to the trash directory (`/trash` inside the container) instead of deleting them. | `0` | 167 | 168 | #### Deployment Considerations 169 | 170 | Many tools used to manage Docker containers extract environment variables 171 | defined by the Docker image and use them to create/deploy the container. For 172 | example, this is done by: 173 | - The Docker application on Synology NAS 174 | - The Container Station on QNAP NAS 175 | - Portainer 176 | - etc. 177 | 178 | While this can be useful for the user to adjust the value of environment 179 | variables to fit its needs, it can also be confusing and dangerous to keep all 180 | of them. 181 | 182 | A good practice is to set/keep only the variables that are needed for the 183 | container to behave as desired in a specific setup. If the value of variable is 184 | kept to its default value, it means that it can be removed. Keep in mind that 185 | all variables are optional, meaning that none of them is required for the 186 | container to start. 187 | 188 | Removing environment variables that are not needed provides some advantages: 189 | 190 | - Prevents keeping variables that are no longer used by the container. Over 191 | time, with image updates, some variables might be removed. 192 | - Allows the Docker image to change/fix a default value. Again, with image 193 | updates, the default value of a variable might be changed to fix an issue, 194 | or to better support a new feature. 195 | - Prevents changes to a variable that might affect the correct function of 196 | the container. Some undocumented variables, like `PATH` or `ENV`, are 197 | required to be exposed, but are not meant to be changed by users. However, 198 | container management tools still show these variables to users. 199 | - There is a bug with the Container Station on QNAP and the Docker application 200 | on Synology, where an environment variable without value might not be 201 | allowed. This behavior is wrong: it's absolutely fine to have a variable 202 | without value. In fact, this container does have variables without value by 203 | default. Thus, removing unneeded variables is a good way to prevent 204 | deployment issue on these devices. 205 | 206 | ### Data Volumes 207 | 208 | The following table describes data volumes used by the container. The mappings 209 | are set via the `-v` parameter. Each mapping is specified with the following 210 | format: `:[:PERMISSIONS]`. 211 | 212 | | Container path | Permissions | Description | 213 | |-----------------|-------------|-------------| 214 | |`/config`| rw | This is where the application stores its configuration, states, log and any files needing persistency. | 215 | |`/storage`| ro | This location contains files from your host that need to be accessible to the application. | 216 | |`/watch`| rw | This is where videos to be automatically converted are located | 217 | |`/output`| rw | This is where automatically converted video files are written. | 218 | |`/trash`| rw | When trash usage is enabled, this is where the automatic video converter moves converted files instead of deleting them. | 219 | 220 | ### Ports 221 | 222 | Here is the list of ports used by the container. 223 | 224 | When using the default bridge network, ports can be mapped to the host via the 225 | `-p` parameter (one per port mapping). Each mapping is defined with the 226 | following format: `:`. The port number used inside 227 | the container might not be changeable, but you are free to use any port on the 228 | host side. 229 | 230 | See the [Docker Container Networking](https://docs.docker.com/config/containers/container-networking) 231 | documentation for more details. 232 | 233 | | Port | Protocol | Mapping to host | Description | 234 | |------|----------|-----------------|-------------| 235 | | 5800 | TCP | Optional | Port to access the application's GUI via the web interface. Mapping to the host is optional if access through the web interface is not wanted. For a container not using the default bridge network, the port can be changed with the `WEB_LISTENING_PORT` environment variable. | 236 | | 5900 | TCP | Optional | Port to access the application's GUI via the VNC protocol. Mapping to the host is optional if access through the VNC protocol is not wanted. For a container not using the default bridge network, the port can be changed with the `VNC_LISTENING_PORT` environment variable. | 237 | 238 | ### Changing Parameters of a Running Container 239 | 240 | As can be seen, environment variables, volume and port mappings are all specified 241 | while creating the container. 242 | 243 | The following steps describe the method used to add, remove or update 244 | parameter(s) of an existing container. The general idea is to destroy and 245 | re-create the container: 246 | 247 | 1. Stop the container (if it is running): 248 | ```shell 249 | docker stop handbrake 250 | ``` 251 | 252 | 2. Remove the container: 253 | ```shell 254 | docker rm handbrake 255 | ``` 256 | 257 | 3. Create/start the container using the `docker run` command, by adjusting 258 | parameters as needed. 259 | 260 | > [!NOTE] 261 | > Since all application's data is saved under the `/config` container folder, 262 | > destroying and re-creating a container is not a problem: nothing is lost and 263 | > the application comes back with the same state (as long as the mapping of the 264 | > `/config` folder remains the same). 265 | 266 | ## Docker Compose File 267 | 268 | Here is an example of a `docker-compose.yml` file that can be used with 269 | [Docker Compose](https://docs.docker.com/compose/overview/). 270 | 271 | Make sure to adjust according to your needs. Note that only mandatory network 272 | ports are part of the example. 273 | 274 | ```yaml 275 | version: '3' 276 | services: 277 | handbrake: 278 | image: jlesage/handbrake 279 | ports: 280 | - "5800:5800" 281 | volumes: 282 | - "/docker/appdata/handbrake:/config:rw" 283 | - "/home/user:/storage:ro" 284 | - "/home/user/HandBrake/watch:/watch:rw" 285 | - "/home/user/HandBrake/output:/output:rw" 286 | ``` 287 | 288 | ## Docker Image Versioning 289 | 290 | Each release of a Docker image is versioned. Prior to october 2022, the 291 | [semantic versioning](https://semver.org) was used as the versioning scheme. 292 | 293 | Since then, versioning scheme changed to 294 | [calendar versioning](https://calver.org). The format used is `YY.MM.SEQUENCE`, 295 | where: 296 | - `YY` is the zero-padded year (relative to year 2000). 297 | - `MM` is the zero-padded month. 298 | - `SEQUENCE` is the incremental release number within the month (first release 299 | is 1, second is 2, etc). 300 | 301 | ## Docker Image Update 302 | 303 | Because features are added, issues are fixed, or simply because a new version 304 | of the containerized application is integrated, the Docker image is regularly 305 | updated. Different methods can be used to update the Docker image. 306 | 307 | The system used to run the container may have a built-in way to update 308 | containers. If so, this could be your primary way to update Docker images. 309 | 310 | An other way is to have the image be automatically updated with [Watchtower]. 311 | Watchtower is a container-based solution for automating Docker image updates. 312 | This is a "set and forget" type of solution: once a new image is available, 313 | Watchtower will seamlessly perform the necessary steps to update the container. 314 | 315 | Finally, the Docker image can be manually updated with these steps: 316 | 317 | 1. Fetch the latest image: 318 | ```shell 319 | docker pull jlesage/handbrake 320 | ``` 321 | 322 | 2. Stop the container: 323 | ```shell 324 | docker stop handbrake 325 | ``` 326 | 327 | 3. Remove the container: 328 | ```shell 329 | docker rm handbrake 330 | ``` 331 | 332 | 4. Create and start the container using the `docker run` command, with the 333 | the same parameters that were used when it was deployed initially. 334 | 335 | [Watchtower]: https://github.com/containrrr/watchtower 336 | 337 | ### Synology 338 | 339 | For owners of a Synology NAS, the following steps can be used to update a 340 | container image. 341 | 342 | 1. Open the *Docker* application. 343 | 2. Click on *Registry* in the left pane. 344 | 3. In the search bar, type the name of the container (`jlesage/handbrake`). 345 | 4. Select the image, click *Download* and then choose the `latest` tag. 346 | 5. Wait for the download to complete. A notification will appear once done. 347 | 6. Click on *Container* in the left pane. 348 | 7. Select your HandBrake container. 349 | 8. Stop it by clicking *Action*->*Stop*. 350 | 9. Clear the container by clicking *Action*->*Reset* (or *Action*->*Clear* if 351 | you don't have the latest *Docker* application). This removes the 352 | container while keeping its configuration. 353 | 10. Start the container again by clicking *Action*->*Start*. **NOTE**: The 354 | container may temporarily disappear from the list while it is re-created. 355 | 356 | ### unRAID 357 | 358 | For unRAID, a container image can be updated by following these steps: 359 | 360 | 1. Select the *Docker* tab. 361 | 2. Click the *Check for Updates* button at the bottom of the page. 362 | 3. Click the *update ready* link of the container to be updated. 363 | 364 | ## User/Group IDs 365 | 366 | When using data volumes (`-v` flags), permissions issues can occur between the 367 | host and the container. For example, the user within the container may not 368 | exist on the host. This could prevent the host from properly accessing files 369 | and folders on the shared volume. 370 | 371 | To avoid any problem, you can specify the user the application should run as. 372 | 373 | This is done by passing the user ID and group ID to the container via the 374 | `USER_ID` and `GROUP_ID` environment variables. 375 | 376 | To find the right IDs to use, issue the following command on the host, with the 377 | user owning the data volume on the host: 378 | 379 | id 380 | 381 | Which gives an output like this one: 382 | ```text 383 | uid=1000(myuser) gid=1000(myuser) groups=1000(myuser),4(adm),24(cdrom),27(sudo),46(plugdev),113(lpadmin) 384 | ``` 385 | 386 | The value of `uid` (user ID) and `gid` (group ID) are the ones that you should 387 | be given the container. 388 | 389 | ## Accessing the GUI 390 | 391 | Assuming that container's ports are mapped to the same host's ports, the 392 | graphical interface of the application can be accessed via: 393 | 394 | * A web browser: 395 | 396 | ```text 397 | http://:5800 398 | ``` 399 | 400 | * Any VNC client: 401 | 402 | ```text 403 | :5900 404 | ``` 405 | 406 | ## Security 407 | 408 | By default, access to the application's GUI is done over an unencrypted 409 | connection (HTTP or VNC). 410 | 411 | Secure connection can be enabled via the `SECURE_CONNECTION` environment 412 | variable. See the [Environment Variables](#environment-variables) section for 413 | more details on how to set an environment variable. 414 | 415 | When enabled, application's GUI is performed over an HTTPs connection when 416 | accessed with a browser. All HTTP accesses are automatically redirected to 417 | HTTPs. 418 | 419 | When using a VNC client, the VNC connection is performed over SSL. Note that 420 | few VNC clients support this method. [SSVNC] is one of them. 421 | 422 | [SSVNC]: http://www.karlrunge.com/x11vnc/ssvnc.html 423 | 424 | ### SSVNC 425 | 426 | [SSVNC] is a VNC viewer that adds encryption security to VNC connections. 427 | 428 | While the Linux version of [SSVNC] works well, the Windows version has some 429 | issues. At the time of writing, the latest version `1.0.30` is not functional, 430 | as a connection fails with the following error: 431 | ```text 432 | ReadExact: Socket error while reading 433 | ``` 434 | However, for your convenience, an unofficial and working version is provided 435 | here: 436 | 437 | https://github.com/jlesage/docker-baseimage-gui/raw/master/tools/ssvnc_windows_only-1.0.30-r1.zip 438 | 439 | The only difference with the official package is that the bundled version of 440 | `stunnel` has been upgraded to version `5.49`, which fixes the connection 441 | problems. 442 | 443 | ### Certificates 444 | 445 | Here are the certificate files needed by the container. By default, when they 446 | are missing, self-signed certificates are generated and used. All files have 447 | PEM encoded, x509 certificates. 448 | 449 | | Container Path | Purpose | Content | 450 | |---------------------------------|----------------------------|---------| 451 | |`/config/certs/vnc-server.pem` |VNC connection encryption. |VNC server's private key and certificate, bundled with any root and intermediate certificates.| 452 | |`/config/certs/web-privkey.pem` |HTTPs connection encryption.|Web server's private key.| 453 | |`/config/certs/web-fullchain.pem`|HTTPs connection encryption.|Web server's certificate, bundled with any root and intermediate certificates.| 454 | 455 | > [!TIP] 456 | > To prevent any certificate validity warnings/errors from the browser or VNC 457 | > client, make sure to supply your own valid certificates. 458 | 459 | > [!NOTE] 460 | > Certificate files are monitored and relevant daemons are automatically 461 | > restarted when changes are detected. 462 | 463 | ### VNC Password 464 | 465 | To restrict access to your application, a password can be specified. This can 466 | be done via two methods: 467 | * By using the `VNC_PASSWORD` environment variable. 468 | * By creating a `.vncpass_clear` file at the root of the `/config` volume. 469 | This file should contain the password in clear-text. During the container 470 | startup, content of the file is obfuscated and moved to `.vncpass`. 471 | 472 | The level of security provided by the VNC password depends on two things: 473 | * The type of communication channel (encrypted/unencrypted). 474 | * How secure the access to the host is. 475 | 476 | When using a VNC password, it is highly desirable to enable the secure 477 | connection to prevent sending the password in clear over an unencrypted channel. 478 | 479 | > [!CAUTION] 480 | > Password is limited to 8 characters. This limitation comes from the Remote 481 | > Framebuffer Protocol [RFC](https://tools.ietf.org/html/rfc6143) (see section 482 | > [7.2.2](https://tools.ietf.org/html/rfc6143#section-7.2.2)). Any characters 483 | > beyond the limit are ignored. 484 | 485 | ### Web Authentication 486 | 487 | Access to the application's GUI via a web browser can be protected with a login 488 | page. When web authentication is enabled, users have to provide valid 489 | credentials, otherwise access is denied. 490 | 491 | Web authentication can be enabled by setting the `WEB_AUTHENTICATION` 492 | environment variable to `1`. 493 | 494 | See the [Environment Variables](#environment-variables) section for more details 495 | on how to set an environment variable. 496 | 497 | > [!IMPORTANT] 498 | > Secure connection must also be enabled to use web authentication. 499 | > See the [Security](#security) section for more details. 500 | 501 | #### Configuring Users Credentials 502 | 503 | Two methods can be used to configure users credentials: 504 | 505 | 1. Via container environment variables. 506 | 2. Via password database. 507 | 508 | Containers environment variables can be used to quickly and easily configure 509 | a single user. Username and pasword are defined via the following environment 510 | variables: 511 | - `WEB_AUTHENTICATION_USERNAME` 512 | - `WEB_AUTHENTICATION_PASSWORD` 513 | 514 | See the [Environment Variables](#environment-variables) section for more details 515 | on how to set an environment variable. 516 | 517 | The second method is more secure and allows multiple users to be configured. 518 | The usernames and password hashes are saved into a password database, located at 519 | `/config/webauth-htpasswd` inside the container. This database file has the 520 | same format as htpasswd files of the Apache HTTP server. Note that password 521 | themselves are not saved into the database, but only their hash. The bcrypt 522 | password hashing function is used to generate hashes. 523 | 524 | Users are managed via the `webauth-user` tool included in the container: 525 | - To add a user password: `docker exec -ti webauth-user add `. 526 | - To update a user password: `docker exec -ti webauth-user update `. 527 | - To remove a user: `docker exec webauth-user del `. 528 | - To list users: `docker exec webauth-user user`. 529 | 530 | ## Reverse Proxy 531 | 532 | The following sections contain NGINX configurations that need to be added in 533 | order to reverse proxy to this container. 534 | 535 | A reverse proxy server can route HTTP requests based on the hostname or the URL 536 | path. 537 | 538 | ### Routing Based on Hostname 539 | 540 | In this scenario, each hostname is routed to a different application/container. 541 | 542 | For example, let's say the reverse proxy server is running on the same machine 543 | as this container. The server would proxy all HTTP requests sent to 544 | `handbrake.domain.tld` to the container at `127.0.0.1:5800`. 545 | 546 | Here are the relevant configuration elements that would be added to the NGINX 547 | configuration: 548 | 549 | ```nginx 550 | map $http_upgrade $connection_upgrade { 551 | default upgrade; 552 | '' close; 553 | } 554 | 555 | upstream docker-handbrake { 556 | # If the reverse proxy server is not running on the same machine as the 557 | # Docker container, use the IP of the Docker host here. 558 | # Make sure to adjust the port according to how port 5800 of the 559 | # container has been mapped on the host. 560 | server 127.0.0.1:5800; 561 | } 562 | 563 | server { 564 | [...] 565 | 566 | server_name handbrake.domain.tld; 567 | 568 | location / { 569 | proxy_pass http://docker-handbrake; 570 | } 571 | 572 | location /websockify { 573 | proxy_pass http://docker-handbrake; 574 | proxy_http_version 1.1; 575 | proxy_set_header Upgrade $http_upgrade; 576 | proxy_set_header Connection $connection_upgrade; 577 | proxy_read_timeout 86400; 578 | } 579 | 580 | # Needed when audio support is enabled. 581 | location /websockify-audio { 582 | proxy_pass http://docker-handbrake; 583 | proxy_http_version 1.1; 584 | proxy_set_header Upgrade $http_upgrade; 585 | proxy_set_header Connection $connection_upgrade; 586 | proxy_read_timeout 86400; 587 | } 588 | } 589 | 590 | ``` 591 | 592 | ### Routing Based on URL Path 593 | 594 | In this scenario, the hostname is the same, but different URL paths are used to 595 | route to different applications/containers. 596 | 597 | For example, let's say the reverse proxy server is running on the same machine 598 | as this container. The server would proxy all HTTP requests for 599 | `server.domain.tld/handbrake` to the container at `127.0.0.1:5800`. 600 | 601 | Here are the relevant configuration elements that would be added to the NGINX 602 | configuration: 603 | 604 | ```nginx 605 | map $http_upgrade $connection_upgrade { 606 | default upgrade; 607 | '' close; 608 | } 609 | 610 | upstream docker-handbrake { 611 | # If the reverse proxy server is not running on the same machine as the 612 | # Docker container, use the IP of the Docker host here. 613 | # Make sure to adjust the port according to how port 5800 of the 614 | # container has been mapped on the host. 615 | server 127.0.0.1:5800; 616 | } 617 | 618 | server { 619 | [...] 620 | 621 | location = /handbrake {return 301 $scheme://$http_host/handbrake/;} 622 | location /handbrake/ { 623 | proxy_pass http://docker-handbrake/; 624 | # Uncomment the following line if your Nginx server runs on a port that 625 | # differs from the one seen by external clients. 626 | #port_in_redirect off; 627 | location /handbrake/websockify { 628 | proxy_pass http://docker-handbrake/websockify/; 629 | proxy_http_version 1.1; 630 | proxy_set_header Upgrade $http_upgrade; 631 | proxy_set_header Connection $connection_upgrade; 632 | proxy_read_timeout 86400; 633 | } 634 | } 635 | } 636 | 637 | ``` 638 | ## Shell Access 639 | 640 | To get shell access to the running container, execute the following command: 641 | 642 | ```shell 643 | docker exec -ti CONTAINER sh 644 | ``` 645 | 646 | Where `CONTAINER` is the ID or the name of the container used during its 647 | creation. 648 | 649 | ## Access to Optical Drive(s) 650 | 651 | By default, a Docker container doesn't have access to host's devices. However, 652 | access to one or more devices can be granted with the `--device DEV` parameter 653 | of the `docker run` command. 654 | 655 | In the Linux world, optical drives are represented by device files named 656 | `/dev/srX`, where `X` is a number. The first drive is `/dev/sr0`, the second 657 | is `/dev/sr1` and so on. To allow HandBrake to access the first drive, 658 | the following parameter is needed: 659 | ``` 660 | --device /dev/sr0 661 | ``` 662 | 663 | The easiest way to determine the correct Linux devices to expose is to run the 664 | container and look at its log. During the startup, messages similar to these 665 | ones are outputed: 666 | ``` 667 | [cont-init ] 54-check-optical-drive.sh: looking for usable optical drives... 668 | [cont-init ] 54-check-optical-drive.sh: found optical drive 'hp HLDS DVDRW GUD1N LD02' [/dev/sr0] 669 | [cont-init ] 54-check-optical-drive.sh: [ OK ] associated SCSI CD-ROM (sr) device detected: /dev/sr0. 670 | [cont-init ] 54-check-optical-drive.sh: [ ERR ] the host device /dev/sr0 is not exposed to the container. 671 | [cont-init ] 54-check-optical-drive.sh: no usable optical drives found. 672 | ``` 673 | 674 | In this case, it's clearly indicated that `/dev/sr0` needs to be exposed to the 675 | container. 676 | 677 | > [!NOTE] 678 | > The container's log can be viewed by running the command 679 | > `docker logs `. 680 | 681 | Alternatively, Linux devices can be found by executing the following command on 682 | the **host**: 683 | 684 | ``` 685 | lsscsi -k 686 | ``` 687 | 688 | From the command's output, the last column associated to an optical drive 689 | indicates the Linux device that should be exposed to the container. In the 690 | following output example, `/dev/sr0` would be exposed: 691 | 692 | ``` 693 | [0:0:0:0] disk ATA SanDisk SSD PLUS 9100 /dev/sda 694 | [1:0:0:0] disk ATA SanDisk SSD PLUS 9100 /dev/sdb 695 | [2:0:0:0] disk ATA ST3500418AS HP34 /dev/sdc 696 | [4:0:0:0] cd/dvd hp HLDS DVDRW GUD1N LD02 /dev/sr0 697 | ``` 698 | 699 | Since HandBrake can decrypt DVD video discs, their conversion can be performed 700 | directly from the optical device. From the graphical interface, click the 701 | `Open Source` button and browse through the file system to find your optical 702 | drive device (e.g. `/dev/sr0`). 703 | 704 | ## Automatic Video Conversion 705 | 706 | This container has an automatic video converter built-in. This is useful to 707 | batch-convert videos without user interaction. 708 | 709 | Basically, files copied to the `/watch` container folder are automatically 710 | converted by HandBrake to a pre-defined video format according to a pre-defined 711 | preset. 712 | 713 | All configuration parameters of the automatic video converter are 714 | defined via environment variables. See the 715 | [Environment Variables](#environment-variables) section for the list of 716 | available variables. The ones having their name starting with 717 | `AUTOMATED_CONVERSION_` apply to the automatic video converter. 718 | 719 | **NOTE**: A preset is identified by its category and its name. 720 | 721 | **NOTE**: All default presets, along with personalized/custom ones, can be seen 722 | and edited with the HandBrake GUI. 723 | 724 | **NOTE**: Converted videos are stored, by default, to the `/output` folder of 725 | the container. 726 | 727 | **NOTE**: The status and progression of conversions performed by the automatic 728 | video converter can be seen from both the GUI and the container's log. 729 | Container's log can be obtained by executing the command 730 | `docker logs handbrake`, where `handbrake` is the name of the container. Also, 731 | full details about the conversion are stored in `/config/log/hb/conversion.log` 732 | (container path). 733 | 734 | ### Multiple Watch Folders 735 | 736 | If needed, additionnal watch folders can be used: 737 | - `/watch2` 738 | - `/watch3` 739 | - `/watch4` 740 | - `/watch5` 741 | - etc. 742 | 743 | This is useful for scenarios where videos need to be converted by different 744 | presets. For example, one could use a watch folder for movies and another watch 745 | folder for TV shows, both having different encoding quality requirements. 746 | 747 | By default, additional watch folders inherits the same settings has the main one 748 | (`/watch`). A setting for a particular watch folder can be overriden by adding 749 | its index to the corresponding environment variable name. 750 | 751 | For example, to set the HandBrake preset used to convert videos in `/watch2`, 752 | the environment variable `AUTOMATED_CONVERSION_PRESET_2` is used. 753 | `AUTOMATED_CONVERSION_PRESET_3` is used for `/watch3`, and so on. 754 | 755 | All settings related to the automatic video converter (environment variables 756 | with name prefixed with `AUTOMATED_CONVERSION_`) can be overriden for each 757 | additional watch folder. 758 | 759 | The maximum number of watch folders handled by the automatic video converter 760 | is defined by the `AUTOMATED_CONVERSION_MAX_WATCH_FOLDERS` environment variable. 761 | 762 | **NOTE**: Each additional watch folder must be mapped to a folder on the host by 763 | adding a volume mapping during the creation of the container. 764 | 765 | **NOTE**: Each output folder defined via the `AUTOMATED_CONVERSION_OUTPUT_DIR` 766 | environment variable must be mapped to a folder on the host by adding a volume 767 | mapping during the creation of the container. 768 | 769 | ### Video Discs 770 | 771 | The automatic video converter supports video discs, in the following format: 772 | - ISO image file. 773 | - DVD video disc folder containing the `VIDEO_TS` folder. 774 | - Blu-ray video disc folder containing the `BDMV` folder. 775 | 776 | Note that folder names are case sensitive. For example, `video_ts`, `Video_Ts` 777 | or `Bdmv` won't be treated as discs, but as normal directories. 778 | 779 | When the source is a disc folder, the name of the converted video file will 780 | match to one of its folder. For example, `/watch/MyMovie/VIDEO_TS` will produce 781 | a video file with name `MyMovie.mp4`. 782 | 783 | Video discs can have multiple titles (the main movie, previews, extras, etc). 784 | In a such case, each title is converted to its own file. These files have the 785 | suffix `.title-XX`, where `XX` is the title number. For example, if the file 786 | `MyMovie.iso` has 2 titles, the following files would be generated: 787 | - `MyMovie.title-1.mp4` 788 | - `MyMovie.title-2.mp4` 789 | 790 | It is possible to ignore titles shorted than a specific amount of time. By 791 | default, only titles longer than 10 seconds are processed. This duration can be 792 | adjusted via the `AUTOMATED_CONVERSION_SOURCE_MIN_DURATION` environment 793 | variable. See the [Environment Variables](#environment-variables) section for 794 | details about setting environment variables. 795 | 796 | ### Hooks 797 | 798 | Custom actions can be performed using hooks. Hooks are shell scripts executed 799 | by the automatic video converter. 800 | 801 | **NOTE**: Hooks are always invoked via `/bin/sh`, ignoring any shebang the 802 | script may have. 803 | 804 | Hooks are optional and by default, no one is defined. A hook is defined and 805 | executed when the script is found at a specific location. 806 | 807 | The following table describe available hooks: 808 | 809 | | Container location | Description | Parameter(s) | 810 | |--------------------|-------------|--------------| 811 | | `/config/hooks/pre_conversion.sh` | Hook executed before the beginning of a video conversion. | The first argument is the path of the converted video. The second argument is the path to the source file. Finally, the third argument is the name of the Handbrake preset that will be used to convert the video. | 812 | | `/config/hooks/post_conversion.sh` | Hook executed when the conversion of a video file is terminated. | The first parameter is the status of the conversion. A value of `0` indicates that the conversion terminated successfuly. Any other value represent a failure. The second argument is the path to the converted video (the output). The third argument is the path to the source file. Finally, the fourth argument is the name of the Handbrake preset used to convert the video. | 813 | | `/config/hooks/post_watch_folder_processing.sh` | Hook executed after all videos in the watch folder have been processed. | The path of the watch folder. | 814 | 815 | During the first start of the container, example hooks are installed in 816 | `/config/hooks/`. Example scripts have the suffix `.example`. For example, 817 | you can use `/config/hooks/post_conversion.sh.example` as a starting point. 818 | 819 | **NOTE**: Keep in mind that this container has the minimal set of packages 820 | required to run HandBrake. This may limit actions that can be performed in 821 | hooks. 822 | 823 | ### Temporary Conversion Directory 824 | 825 | A video being converted is written in a hidden, temporary directory under the 826 | root of the output directory (`/output` by default). Once a conversion 827 | successfully terminates, the video file is moved to its final location. 828 | 829 | This feature can be useful for scenarios where the output folder is monitored 830 | by another application: with proper configuration, one can make sure this 831 | application only "sees" the final, converted video file and not the transient 832 | versions. 833 | 834 | If the monitoring application ignores hidden directories, then nothing special 835 | is required and the application should always see the final file. 836 | 837 | However, if the monitoring application handles hidden directories, the automatic 838 | video converter should be configured with the 839 | `AUTOMATED_CONVERSION_OUTPUT_SUBDIR` environment variable sets to a 840 | subdirectory. The application can then be configured to monitor this 841 | subdirectory. For example, if `AUTOMATED_CONVERSION_OUTPUT_SUBDIR` is set to 842 | `TV Shows` and `/output` is mapped to `/home/user/appvolumes/HandBrake` on the 843 | host, `/home/user/appvolumes/HandBrake/TV Shows` should be monitored by the 844 | application. 845 | 846 | ## Intel Quick Sync Video 847 | 848 | Intel Quick Sync Video is Intel's brand for its dedicated video encoding and 849 | decoding hardware core. It is a technology that is capable of offloading video 850 | decoding and encoding task to the integrated GPU, thus saving the CPU usage to 851 | do other tasks. As a specialized hardware core on the processor die, Quick Sync 852 | offers a much more power efficient video processing which is much superior to 853 | video encoding on a CPU. 854 | 855 | For HandBrake to be able to use hardware-accelerated encoding, the following are 856 | required: 857 | 858 | - Have a compatible Intel processor. To determine if your CPU has the Quick 859 | Sync Video hardware, consult this [list] from the [Intel Ark] website. The 860 | model name of your processor is printed to the container's log during its 861 | startup. Look for a message like this: 862 | ``` 863 | [cont-init.d] 95-check-qsv.sh: Processor: Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz 864 | ``` 865 | - The Intel i915 graphic driver must be loaded on the **host**. 866 | - The `/dev/dri` device must be exposed to the container. This is done by 867 | adding the `--device /dev/dri` parameter to the `docker run` command. 868 | 869 | When Intel Quick Sync Video is properly enabled, HandBrake offers the following 870 | video encoder: 871 | ``` 872 | H.264 (Intel QSV) 873 | ``` 874 | 875 | If this encoder is not part of the list, something is wrong and looking at the 876 | container's log can give more details about the issue. 877 | 878 | **NOTE**: In most cases, HandBrake can successfully access the `/dev/dri` device 879 | without changing anything on the host side. This is possible because the user 880 | under which the container is running is automatically added to the group owning 881 | the `/dev/dri` device. However, this method doesn't work if the device is owned 882 | by the group `root`. The problem can be fixed using one of the following 883 | methods: 884 | - Running the container as root (`USER_ID=0`). 885 | - Adding, on the host, read/write permissions for all to the `/dev/dri` 886 | device: 887 | ``` 888 | sudo chmod a+wr /dev/dri/* 889 | ``` 890 | - Changing, on the host, the group owning the `/dev/dri` device. For example, 891 | to change the group to `video`: 892 | ``` 893 | sudo chown root:video /dev/dri/* 894 | ``` 895 | 896 | [list]: https://ark.intel.com/Search/FeatureFilter?productType=873&0_QuickSyncVideo=True 897 | [Intel Ark]: https://ark.intel.com 898 | 899 | ### unRAID 900 | 901 | With recent versions of unRAID, the Intel i915 driver is already included in the 902 | distribution and is automatically loaded. 903 | 904 | With older versions, the following lines might need to be added to 905 | `/boot/config/go` for the driver to be loaded during the startup of unRAID: 906 | ``` 907 | # Load the i915 driver. 908 | modprobe i915 909 | ``` 910 | 911 | ## Nightly Builds 912 | 913 | Nightly builds are based on the latest HandBrake development code. 914 | This means that they may have bugs, crashes and instabilities. 915 | 916 | Nightly builds are available through Docker image tags. These tags have the 917 | following format: 918 | ``` 919 | nightly-- 920 | ``` 921 | 922 | Where: 923 | - `COMMIT_DATE` is the date (in `YYMMDDHHMMSS` format) of the latest commit 924 | from the HandBrake [Git repository]. 925 | - `COMMIT_HASH` is the short hash of the latest commit from the HandBrake 926 | [Git repository]. 927 | 928 | The latest nightly build is available through the `nightly-latest` Docker image 929 | tag. The list of available tags are available on [Docker Hub]. 930 | 931 | To use a Docker image tag, it has to be appended to the name of the Docker image 932 | during the creation of the container. Here is an example: 933 | ``` 934 | docker run [OPTIONS..] jlesage/handbrake:nightly-latest 935 | ``` 936 | 937 | [Git repository]: https://github.com/HandBrake/HandBrake 938 | [Docker Hub]: https://hub.docker.com/r/jlesage/handbrake/tags/ 939 | 940 | ## Debug Builds 941 | 942 | Debug builds can be used to better investigate problems that can occur with 943 | HandBrake. These builds have HandBrake 944 | compiled in debug mode and all symbols are kept. 945 | 946 | The main use case of debug builds is debugging a crash. To do this, a core dump 947 | needs to be generated when HandBrake crashes. To make sure 948 | this core dump is properly generated, two things are required: 949 | 950 | 1. Core dumps must be enabled. This is done by setting the maximum size of 951 | cores via the `--ulimit core=-1` parameter of the `docker run` command. 952 | A value of `-1` mean "unlimited". 953 | 2. Location of the cores must be set. This can be done by executing the 954 | following command on the **host**: 955 | ``` 956 | echo 'CORE_PATTERN' | sudo tee /proc/sys/kernel/core_pattern 957 | ``` 958 | Where `CORE_PATTERN` is the template that defines the naming of core dump 959 | files. For example, to set the files in the configuration volume of the 960 | container (for easy retrieval from the host), use the pattern 961 | `/config/core.%e.%t`. 962 | 963 | **NOTE**: Because a core file contains the complete memory layout of an 964 | application, it is created with restrictive permissions. If another user 965 | other than the one used to run HandBrake needs to access 966 | the core file, permissions must be changed by executing 967 | `chmod a+r CORE`, where `CORE` is the path to the core file. 968 | 969 | **NOTE**: Since the core dump files pattern is shared between the host and 970 | the container, you may want to revert to the original pattern once 971 | done. 972 | 973 | **NOTE**: The current value of the pattern can be obtained by executing 974 | `cat /proc/sys/kernel/core_pattern`. 975 | 976 | Debug builds are available by using Docker image tags with the `debug` suffix. 977 | Make sure to look at available [tags on Docker Hub]. 978 | 979 | When creating the container, the tag needs to be appended to the name of the 980 | Docker image, like this: 981 | ``` 982 | docker run [OPTIONS..] jlesage/handbrake:v1.14.3-debug 983 | ``` 984 | 985 | [tags on Docker Hub]: https://hub.docker.com/r/jlesage/handbrake/tags/ 986 | 987 | ### unRAID 988 | 989 | On systems running unRAID, the `--ulimit core=-1` parameter can be added to the 990 | `Extra Parameters` field of the container settings. 991 | 992 | ## Support or Contact 993 | 994 | Having troubles with the container or have questions? Please 995 | [create a new issue]. 996 | 997 | For other great Dockerized applications, see https://jlesage.github.io/docker-apps. 998 | 999 | [create a new issue]: https://github.com/jlesage/docker-handbrake/issues 1000 | -------------------------------------------------------------------------------- /appdefs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # 4 | # Definitions for HandBrake docker container. 5 | # 6 | # This file is used as data source to generate README.md and unRAID template files 7 | # from Jinja2 templates. 8 | # 9 | 10 | app: 11 | id: 3 12 | name: handbrake 13 | friendly_name: HandBrake 14 | gui_type: x11 15 | base_os: alpine 16 | project: 17 | description: |- 18 | HandBrake is a tool for converting video from nearly any format to a selection 19 | of modern, widely supported codecs. 20 | url: https://handbrake.fr 21 | unraid: 22 | support_url: https://forums.unraid.net/topic/57420-support-handbrake/ 23 | category: "MediaApp:Video" 24 | documentation: 25 | overview: |- 26 | A fully automated mode is also available: drop files into a watch folder and let 27 | {{ app.friendly_name }} process them without any user interaction. 28 | sections: 29 | - title: Access to Optical Drive(s) 30 | level: 2 31 | content: |- 32 | By default, a Docker container doesn't have access to host's devices. However, 33 | access to one or more devices can be granted with the `--device DEV` parameter 34 | of the `docker run` command. 35 | 36 | In the Linux world, optical drives are represented by device files named 37 | `/dev/srX`, where `X` is a number. The first drive is `/dev/sr0`, the second 38 | is `/dev/sr1` and so on. To allow {{ app.friendly_name }} to access the first drive, 39 | the following parameter is needed: 40 | ``` 41 | --device /dev/sr0 42 | ``` 43 | 44 | The easiest way to determine the correct Linux devices to expose is to run the 45 | container and look at its log. During the startup, messages similar to these 46 | ones are outputed: 47 | ``` 48 | [cont-init ] 54-check-optical-drive.sh: looking for usable optical drives... 49 | [cont-init ] 54-check-optical-drive.sh: found optical drive 'hp HLDS DVDRW GUD1N LD02' [/dev/sr0] 50 | [cont-init ] 54-check-optical-drive.sh: [ OK ] associated SCSI CD-ROM (sr) device detected: /dev/sr0. 51 | [cont-init ] 54-check-optical-drive.sh: [ ERR ] the host device /dev/sr0 is not exposed to the container. 52 | [cont-init ] 54-check-optical-drive.sh: no usable optical drives found. 53 | ``` 54 | 55 | In this case, it's clearly indicated that `/dev/sr0` needs to be exposed to the 56 | container. 57 | 58 | > [!NOTE] 59 | > The container's log can be viewed by running the command 60 | > `docker logs `. 61 | 62 | Alternatively, Linux devices can be found by executing the following command on 63 | the **host**: 64 | 65 | ``` 66 | lsscsi -k 67 | ``` 68 | 69 | From the command's output, the last column associated to an optical drive 70 | indicates the Linux device that should be exposed to the container. In the 71 | following output example, `/dev/sr0` would be exposed: 72 | 73 | ``` 74 | [0:0:0:0] disk ATA SanDisk SSD PLUS 9100 /dev/sda 75 | [1:0:0:0] disk ATA SanDisk SSD PLUS 9100 /dev/sdb 76 | [2:0:0:0] disk ATA ST3500418AS HP34 /dev/sdc 77 | [4:0:0:0] cd/dvd hp HLDS DVDRW GUD1N LD02 /dev/sr0 78 | ``` 79 | 80 | Since HandBrake can decrypt DVD video discs, their conversion can be performed 81 | directly from the optical device. From the graphical interface, click the 82 | `Open Source` button and browse through the file system to find your optical 83 | drive device (e.g. `/dev/sr0`). 84 | - title: Automatic Video Conversion 85 | level: 2 86 | content: |- 87 | This container has an automatic video converter built-in. This is useful to 88 | batch-convert videos without user interaction. 89 | 90 | Basically, files copied to the `/watch` container folder are automatically 91 | converted by HandBrake to a pre-defined video format according to a pre-defined 92 | preset. 93 | 94 | All configuration parameters of the automatic video converter are 95 | defined via environment variables. See the 96 | [Environment Variables](#environment-variables) section for the list of 97 | available variables. The ones having their name starting with 98 | `AUTOMATED_CONVERSION_` apply to the automatic video converter. 99 | 100 | **NOTE**: A preset is identified by its category and its name. 101 | 102 | **NOTE**: All default presets, along with personalized/custom ones, can be seen 103 | and edited with the HandBrake GUI. 104 | 105 | **NOTE**: Converted videos are stored, by default, to the `/output` folder of 106 | the container. 107 | 108 | **NOTE**: The status and progression of conversions performed by the automatic 109 | video converter can be seen from both the GUI and the container's log. 110 | Container's log can be obtained by executing the command 111 | `docker logs handbrake`, where `handbrake` is the name of the container. Also, 112 | full details about the conversion are stored in `/config/log/hb/conversion.log` 113 | (container path). 114 | - title: Multiple Watch Folders 115 | level: 3 116 | content: |- 117 | If needed, additionnal watch folders can be used: 118 | - `/watch2` 119 | - `/watch3` 120 | - `/watch4` 121 | - `/watch5` 122 | - etc. 123 | 124 | This is useful for scenarios where videos need to be converted by different 125 | presets. For example, one could use a watch folder for movies and another watch 126 | folder for TV shows, both having different encoding quality requirements. 127 | 128 | By default, additional watch folders inherits the same settings has the main one 129 | (`/watch`). A setting for a particular watch folder can be overriden by adding 130 | its index to the corresponding environment variable name. 131 | 132 | For example, to set the HandBrake preset used to convert videos in `/watch2`, 133 | the environment variable `AUTOMATED_CONVERSION_PRESET_2` is used. 134 | `AUTOMATED_CONVERSION_PRESET_3` is used for `/watch3`, and so on. 135 | 136 | All settings related to the automatic video converter (environment variables 137 | with name prefixed with `AUTOMATED_CONVERSION_`) can be overriden for each 138 | additional watch folder. 139 | 140 | The maximum number of watch folders handled by the automatic video converter 141 | is defined by the `AUTOMATED_CONVERSION_MAX_WATCH_FOLDERS` environment variable. 142 | 143 | **NOTE**: Each additional watch folder must be mapped to a folder on the host by 144 | adding a volume mapping during the creation of the container. 145 | 146 | **NOTE**: Each output folder defined via the `AUTOMATED_CONVERSION_OUTPUT_DIR` 147 | environment variable must be mapped to a folder on the host by adding a volume 148 | mapping during the creation of the container. 149 | - title: Video Discs 150 | level: 3 151 | content: |- 152 | The automatic video converter supports video discs, in the following format: 153 | - ISO image file. 154 | - DVD video disc folder containing the `VIDEO_TS` folder. 155 | - Blu-ray video disc folder containing the `BDMV` folder. 156 | 157 | Note that folder names are case sensitive. For example, `video_ts`, `Video_Ts` 158 | or `Bdmv` won't be treated as discs, but as normal directories. 159 | 160 | When the source is a disc folder, the name of the converted video file will 161 | match to one of its folder. For example, `/watch/MyMovie/VIDEO_TS` will produce 162 | a video file with name `MyMovie.mp4`. 163 | 164 | Video discs can have multiple titles (the main movie, previews, extras, etc). 165 | In a such case, each title is converted to its own file. These files have the 166 | suffix `.title-XX`, where `XX` is the title number. For example, if the file 167 | `MyMovie.iso` has 2 titles, the following files would be generated: 168 | - `MyMovie.title-1.mp4` 169 | - `MyMovie.title-2.mp4` 170 | 171 | It is possible to ignore titles shorted than a specific amount of time. By 172 | default, only titles longer than 10 seconds are processed. This duration can be 173 | adjusted via the `AUTOMATED_CONVERSION_SOURCE_MIN_DURATION` environment 174 | variable. See the [Environment Variables](#environment-variables) section for 175 | details about setting environment variables. 176 | - title: Hooks 177 | level: 3 178 | content: |- 179 | Custom actions can be performed using hooks. Hooks are shell scripts executed 180 | by the automatic video converter. 181 | 182 | **NOTE**: Hooks are always invoked via `/bin/sh`, ignoring any shebang the 183 | script may have. 184 | 185 | Hooks are optional and by default, no one is defined. A hook is defined and 186 | executed when the script is found at a specific location. 187 | 188 | The following table describe available hooks: 189 | 190 | | Container location | Description | Parameter(s) | 191 | |--------------------|-------------|--------------| 192 | | `/config/hooks/pre_conversion.sh` | Hook executed before the beginning of a video conversion. | The first argument is the path of the converted video. The second argument is the path to the source file. Finally, the third argument is the name of the Handbrake preset that will be used to convert the video. | 193 | | `/config/hooks/post_conversion.sh` | Hook executed when the conversion of a video file is terminated. | The first parameter is the status of the conversion. A value of `0` indicates that the conversion terminated successfuly. Any other value represent a failure. The second argument is the path to the converted video (the output). The third argument is the path to the source file. Finally, the fourth argument is the name of the Handbrake preset used to convert the video. | 194 | | `/config/hooks/post_watch_folder_processing.sh` | Hook executed after all videos in the watch folder have been processed. | The path of the watch folder. | 195 | 196 | During the first start of the container, example hooks are installed in 197 | `/config/hooks/`. Example scripts have the suffix `.example`. For example, 198 | you can use `/config/hooks/post_conversion.sh.example` as a starting point. 199 | 200 | **NOTE**: Keep in mind that this container has the minimal set of packages 201 | required to run HandBrake. This may limit actions that can be performed in 202 | hooks. 203 | - title: Temporary Conversion Directory 204 | level: 3 205 | content: |- 206 | A video being converted is written in a hidden, temporary directory under the 207 | root of the output directory (`/output` by default). Once a conversion 208 | successfully terminates, the video file is moved to its final location. 209 | 210 | This feature can be useful for scenarios where the output folder is monitored 211 | by another application: with proper configuration, one can make sure this 212 | application only "sees" the final, converted video file and not the transient 213 | versions. 214 | 215 | If the monitoring application ignores hidden directories, then nothing special 216 | is required and the application should always see the final file. 217 | 218 | However, if the monitoring application handles hidden directories, the automatic 219 | video converter should be configured with the 220 | `AUTOMATED_CONVERSION_OUTPUT_SUBDIR` environment variable sets to a 221 | subdirectory. The application can then be configured to monitor this 222 | subdirectory. For example, if `AUTOMATED_CONVERSION_OUTPUT_SUBDIR` is set to 223 | `TV Shows` and `/output` is mapped to `/home/user/appvolumes/HandBrake` on the 224 | host, `/home/user/appvolumes/HandBrake/TV Shows` should be monitored by the 225 | application. 226 | - title: Intel Quick Sync Video 227 | level: 2 228 | content: |- 229 | Intel Quick Sync Video is Intel's brand for its dedicated video encoding and 230 | decoding hardware core. It is a technology that is capable of offloading video 231 | decoding and encoding task to the integrated GPU, thus saving the CPU usage to 232 | do other tasks. As a specialized hardware core on the processor die, Quick Sync 233 | offers a much more power efficient video processing which is much superior to 234 | video encoding on a CPU. 235 | 236 | For HandBrake to be able to use hardware-accelerated encoding, the following are 237 | required: 238 | 239 | - Have a compatible Intel processor. To determine if your CPU has the Quick 240 | Sync Video hardware, consult this [list] from the [Intel Ark] website. The 241 | model name of your processor is printed to the container's log during its 242 | startup. Look for a message like this: 243 | ``` 244 | [cont-init.d] 95-check-qsv.sh: Processor: Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz 245 | ``` 246 | - The Intel i915 graphic driver must be loaded on the **host**. 247 | - The `/dev/dri` device must be exposed to the container. This is done by 248 | adding the `--device /dev/dri` parameter to the `docker run` command. 249 | 250 | When Intel Quick Sync Video is properly enabled, HandBrake offers the following 251 | video encoder: 252 | ``` 253 | H.264 (Intel QSV) 254 | ``` 255 | 256 | If this encoder is not part of the list, something is wrong and looking at the 257 | container's log can give more details about the issue. 258 | 259 | **NOTE**: In most cases, HandBrake can successfully access the `/dev/dri` device 260 | without changing anything on the host side. This is possible because the user 261 | under which the container is running is automatically added to the group owning 262 | the `/dev/dri` device. However, this method doesn't work if the device is owned 263 | by the group `root`. The problem can be fixed using one of the following 264 | methods: 265 | - Running the container as root (`USER_ID=0`). 266 | - Adding, on the host, read/write permissions for all to the `/dev/dri` 267 | device: 268 | ``` 269 | sudo chmod a+wr /dev/dri/* 270 | ``` 271 | - Changing, on the host, the group owning the `/dev/dri` device. For example, 272 | to change the group to `video`: 273 | ``` 274 | sudo chown root:video /dev/dri/* 275 | ``` 276 | 277 | [list]: https://ark.intel.com/Search/FeatureFilter?productType=873&0_QuickSyncVideo=True 278 | [Intel Ark]: https://ark.intel.com 279 | - title: unRAID 280 | level: 3 281 | content: |- 282 | With recent versions of unRAID, the Intel i915 driver is already included in the 283 | distribution and is automatically loaded. 284 | 285 | With older versions, the following lines might need to be added to 286 | `/boot/config/go` for the driver to be loaded during the startup of unRAID: 287 | ``` 288 | # Load the i915 driver. 289 | modprobe i915 290 | ``` 291 | - title: Nightly Builds 292 | level: 2 293 | content: |- 294 | Nightly builds are based on the latest {{ app.friendly_name }} development code. 295 | This means that they may have bugs, crashes and instabilities. 296 | 297 | Nightly builds are available through Docker image tags. These tags have the 298 | following format: 299 | ``` 300 | nightly-- 301 | ``` 302 | 303 | Where: 304 | - `COMMIT_DATE` is the date (in `YYMMDDHHMMSS` format) of the latest commit 305 | from the {{ app.friendly_name }} [Git repository]. 306 | - `COMMIT_HASH` is the short hash of the latest commit from the {{ app.friendly_name }} 307 | [Git repository]. 308 | 309 | The latest nightly build is available through the `nightly-latest` Docker image 310 | tag. The list of available tags are available on [Docker Hub]. 311 | 312 | To use a Docker image tag, it has to be appended to the name of the Docker image 313 | during the creation of the container. Here is an example: 314 | ``` 315 | docker run [OPTIONS..] jlesage/{{ app.name }}:nightly-latest 316 | ``` 317 | 318 | [Git repository]: https://github.com/HandBrake/HandBrake 319 | [Docker Hub]: https://hub.docker.com/r/jlesage/{{ app.name }}/tags/ 320 | - title: Debug Builds 321 | level: 2 322 | content: |- 323 | Debug builds can be used to better investigate problems that can occur with 324 | {{ app.friendly_name }}. These builds have {{ app.friendly_name }} 325 | compiled in debug mode and all symbols are kept. 326 | 327 | The main use case of debug builds is debugging a crash. To do this, a core dump 328 | needs to be generated when {{ app.friendly_name }} crashes. To make sure 329 | this core dump is properly generated, two things are required: 330 | 331 | 1. Core dumps must be enabled. This is done by setting the maximum size of 332 | cores via the `--ulimit core=-1` parameter of the `docker run` command. 333 | A value of `-1` mean "unlimited". 334 | 2. Location of the cores must be set. This can be done by executing the 335 | following command on the **host**: 336 | ``` 337 | echo 'CORE_PATTERN' | sudo tee /proc/sys/kernel/core_pattern 338 | ``` 339 | Where `CORE_PATTERN` is the template that defines the naming of core dump 340 | files. For example, to set the files in the configuration volume of the 341 | container (for easy retrieval from the host), use the pattern 342 | `/config/core.%e.%t`. 343 | 344 | **NOTE**: Because a core file contains the complete memory layout of an 345 | application, it is created with restrictive permissions. If another user 346 | other than the one used to run {{ app.friendly_name }} needs to access 347 | the core file, permissions must be changed by executing 348 | `chmod a+r CORE`, where `CORE` is the path to the core file. 349 | 350 | **NOTE**: Since the core dump files pattern is shared between the host and 351 | the container, you may want to revert to the original pattern once 352 | done. 353 | 354 | **NOTE**: The current value of the pattern can be obtained by executing 355 | `cat /proc/sys/kernel/core_pattern`. 356 | 357 | Debug builds are available by using Docker image tags with the `debug` suffix. 358 | Make sure to look at available [tags on Docker Hub]. 359 | 360 | When creating the container, the tag needs to be appended to the name of the 361 | Docker image, like this: 362 | ``` 363 | docker run [OPTIONS..] jlesage/{{ app.name }}:v1.14.3-debug 364 | ``` 365 | 366 | [tags on Docker Hub]: https://hub.docker.com/r/jlesage/{{ app.name }}/tags/ 367 | - title: unRAID 368 | level: 3 369 | content: |- 370 | On systems running unRAID, the `--ulimit core=-1` parameter can be added to the 371 | `Extra Parameters` field of the container settings. 372 | changelog: 373 | - version: 25.02.3 374 | date: 2025-02-23 375 | changes: 376 | - 'Updated HandBrake to version 1.9.2.' 377 | - version: 25.02.2 378 | date: 2025-02-12 379 | changes: 380 | - 'Updated HandBrake to version 1.9.1.' 381 | - 'Updated Intel OneVPL GPU Runtime to version 24.4.4.' 382 | - 'Report the case where an optical drive cannot be used because of an improper user namespace configuration.' 383 | - version: 25.02.1 384 | date: 2025-02-09 385 | changes: 386 | - 'Updated gmmlib to version 22.6.0.' 387 | - 'Updated Intel Media Driver to version 24.4.4.0' 388 | - 'Improved detection of optical drive usability issues.' 389 | - 'Updated baseimage to version 4.7.1, which brings the following changes (since last used version):' 390 | - '2:Added environment variable that allows configuring the web authentication token lifetime.' 391 | - '2:Fixed compatibility issues that were introduced with support of GTK4 applications.' 392 | - '2:Increased the default service ready timeout from 5 seconds to 10 seconds and allow ^Cntime adjustment via environment variable.' 393 | - '2:Rebuild against latest distro images to get security fixes.' 394 | - version: 24.12.1 395 | date: 2024-12-07 396 | changes: 397 | - 'Updated HandBrake to version 1.9.0.' 398 | - 'Updated gmmlib to version 22.5.4.' 399 | - 'Updated Intel Media Driver to version 24.3.4.' 400 | - 'Updated Intel OneVPL GPU runtime to version 24.3.4.' 401 | - 'Updated baseimage to version 4.6.7, which brings the following changes:' 402 | - '2:Fixed web authentication feature with URL path-based reverse proxy.' 403 | - '2:Fixed web audio feature with URL path-based reverse proxy.' 404 | - '2:Fixed TLS secure connection method for VNC that was preventing web access.' 405 | - '2:Fixed CJK font installation.' 406 | - '2:Rebuild against latest distro images to get security fixes.' 407 | - version: 24.09.1 408 | date: 2024-09-14 409 | changes: 410 | - 'Updated HandBrake to version 1.8.2.' 411 | - 'Updated libva to version 2.22.0.' 412 | - 'Updated gmmlib to version 22.5.0.' 413 | - 'Updated Intel Media Driver to version 24.2.5.' 414 | - 'Updated Intel OneVPL GPU Runtime to version 24.2.5.' 415 | - 'Added environment variable to control the HandBrake GUI queue startup action.' 416 | - version: 24.06.1 417 | date: 2024-06-30 418 | changes: 419 | - 'Updated HandBrake to version 1.8.1.' 420 | - 'Updated libva to version 2.21.0.' 421 | - 'Updated gmmlib to version 22.4.0.' 422 | - 'Updated Intel Media Driver to version 24.1.5.' 423 | - 'Updated Intel OneVPL GPU runtime to version 24.1.5.' 424 | - 'Updated baseimage to version 4.6.3, which brings the following changes:' 425 | - '2:Audio support through web browser.' 426 | - '2:Web authentication support.' 427 | - '2:Better support of GTK4 applications.' 428 | - '2:Updated noVNC to version 1.5.0.' 429 | - '2:Updated web UI components (Bootstrap, Font Awesome).' 430 | - '2:When connecting, the control bar is now temporarily shown only once.' 431 | - '2:During package mirror setup, make sure to keep permissions of copied files.' 432 | - version: 24.03.1 433 | date: 2024-03-04 434 | changes: 435 | - 'Updated HandBrake to version 1.7.3.' 436 | - version: 24.01.2 437 | date: 2024-01-13 438 | changes: 439 | - 'Issue where Linux device of an optical drive could not be opened is now really fixed.' 440 | - version: 24.01.1 441 | date: 2024-01-12 442 | changes: 443 | - 'Fixed issue where Linux device of an optical drive could not be opened.' 444 | - 'Updated baseimage to version 4.5.3, which brings the following changes:' 445 | - '2:Disabled fullscreen support when page is loaded into an iFrame.' 446 | - '2:Rebuilt against latest distro images to get security fixes.' 447 | - version: 23.12.2 448 | date: 2023-12-24 449 | changes: 450 | - 'Updated HandBrake to version 1.7.2.' 451 | - version: 23.12.1 452 | date: 2023-12-17 453 | changes: 454 | - 'Adjusted QSV check script to handle Atom microarchitectures.' 455 | - 'Fixed issue with the automatic video converter where removing a video file could block.' 456 | - 'Enabled AVX-512 optimizations for SVT-AV1.' 457 | - version: 23.11.5 458 | date: 2023-11-30 459 | changes: 460 | - 'Fixed QSV issue caused by the oneVPL runtime implementation not being selected for Intel CPUs/GPUs requiring it.' 461 | - version: 23.11.4 462 | date: 2023-11-22 463 | changes: 464 | - 'Updated HandBrake to version 1.7.1.' 465 | - version: 23.11.3 466 | date: 2023-11-19 467 | changes: 468 | - 'Updated HandBrake to version 1.7.0.' 469 | - 'Improved QSV checks.' 470 | - 'Updated baseimage to version 4.5.2, which brings the following changes:' 471 | - '2:Fixed issue that would cause the helper that takes ownership of a directory to fail when using a very high user or group ID.' 472 | - version: 23.11.2 473 | date: 2023-11-11 474 | changes: 475 | - 'Updated Intel Media Driver to version 23.3.5.' 476 | - 'Updated Intel Media SDK to version 23.2.2.' 477 | - 'Updated Intel OneVPL GPU runtime to version 23.3.4.' 478 | - version: 23.11.1 479 | date: 2023-11-10 480 | changes: 481 | - 'Updated baseimage to version 4.5.1, which brings the following changes:' 482 | - '2:Mirror for packages installation can be set via the `PACKAGES_MIRROR` environment variable.' 483 | - '2:Improved the way the `take-ownership` script is working.' 484 | - '2:Readiness and minimum running time checks should not be done for a service defined with an interval.' 485 | - '2:Raise an error when a synched service fails to start.' 486 | - '2:Minimum running time check of a service was using an incorrect way to verify if process is still alive.' 487 | - '2:Fixed installation of CJK font.' 488 | - version: 23.10.1 489 | date: 2023-10-10 490 | changes: 491 | - 'Updated libva to version 2.20.0.' 492 | - 'Updated gmmlib to version 22.3.12.' 493 | - 'Updated Intel Media Driver to version 23.2.4.' 494 | - 'Updated Intel OneVPL GPU Runtime to version 23.2.4.' 495 | - version: 23.06.1 496 | date: 2023-06-08 497 | changes: 498 | - 'Updated libva to version 2.18.' 499 | - 'Updated gmmlib to version 22.3.5.' 500 | - 'Updated Intel Media Driver to version 23.1.6.' 501 | - 'Updated OneVPL GPU Runtime to version 23.1.5.' 502 | - 'Validate the output folder used by the Automatic Video Converter.' 503 | - 'Updated baseimage to version 4.4.2, which brings the following changes:' 504 | - '2:Rebuilt against latest distro images to get security fixes.' 505 | - '2:Updated X server to version 1.20.14.' 506 | - version: 23.04.1 507 | date: 2023-04-29 508 | changes: 509 | - 'Updated baseimage to version 4.4.1, which brings the following changes:' 510 | - '2:Updated TigerVNC to version 1.13.1.' 511 | - version: 23.03.2 512 | date: 2023-03-05 513 | changes: 514 | - 'Fixed issue where the Automatic Video Converter was not running with the correct supplementary groups.' 515 | - version: 23.03.1 516 | date: 2023-03-05 517 | changes: 518 | - 'Fixed `AUTOMATED_CONVERSION_NO_GUI_PROGRESS` environment variable not being handled.' 519 | - 'Make sure the Automatic Video Converter does not report conversion progress to GUI when it is disabled.' 520 | - 'Improved QSV checks by handling virtualized hosts.' 521 | - 'Updated baseimage to version 4.4.0, which brings the following changes:' 522 | - '2:Updated components providing access to application''s UI over web.' 523 | - '2:Improved web UI usage with touch devices.' 524 | - '2:Fixed issue with initialization of Linux users and groups when the `GROUP_ID` is also part of `SUP_GROUP_IDS`.' 525 | - version: 23.02.1 526 | date: 2023-02-26 527 | changes: 528 | - 'Updated HandBrake to version 1.6.1.' 529 | - 'Updated libva, gmmlib, Intel Media Driver, Intel Media SDK and Intel OneVPL.' 530 | - 'The Automatic Video Converter now has the ability to move source files to trash instead of removing them.' 531 | - 'Improved robustness of the Automatic Video Converter.' 532 | - 'Added the ability to disable the HandBrake GUI.' 533 | - 'Added the ability to disable the Automatic Video Converter.' 534 | - 'Versioning scheme of the Docker image changed to `YY.MM.SEQUENCE`.' 535 | - 'Update of the baseimage to version 4.3.6 brings the following new features:' 536 | - '2:Support for dark mode.' 537 | - '2:Support for remote window resize.' 538 | - '2:Updated the web UI with a new, simplified and less intrusive look.' 539 | - version: 1.25.1 540 | date: 2022-06-28 541 | changes: 542 | - 'Fixed the Automatic Video Converter not working due to usage of undefined variable.' 543 | - 'The Automatic Video Converter now correctly uses the main feature detection.' 544 | - version: 1.25.0 545 | date: 2022-06-27 546 | changes: 547 | - 'Updated HandBrake to version 1.5.1.' 548 | - 'Updated libva to version 2.14.0.' 549 | - 'Updated gmmlib to version 22.1.4.' 550 | - 'Updated Intel Media Driver to version 22.3.1.' 551 | - 'Updated Intel Media SDK to version 22.3.0.' 552 | - 'Updated x264 library to get support for the H.264 10bit encoder.' 553 | - 'Added the `AUTOMATED_CONVERSION_SOURCE_MAIN_TITLE_DETECTION` environment variable that enables main feature title detection of HandBrake.' 554 | - 'Now using baseimage version 3.5.8, based on Alpine Linux 3.14, which brings the following changes:' 555 | - '2:Updated installed packages to get latest security fixes.' 556 | - version: 1.24.2 557 | date: 2021-10-04 558 | changes: 559 | - 'Updated HandBrake to version 1.4.2.' 560 | - 'Updated Intel Media SDK to version 21.3.5.' 561 | - 'Updated gmmlib to version 21.3.1.' 562 | - version: 1.24.1 563 | date: 2021-08-21 564 | changes: 565 | - 'Updated Handbrake to version 1.4.1.' 566 | - version: 1.24.0 567 | date: 2021-07-19 568 | changes: 569 | - 'Updated Handbrake to version 1.4.0.' 570 | - 'Updated libva to version 2.12.0.' 571 | - 'Updated gmmlib to version 21.2.1.' 572 | - 'Updated Intel Media Driver to version 21.2.3.' 573 | - 'Updated Intel Media SDK to version 21.2.3.' 574 | - 'Now using baseimage version 3.5.7, which brings the following changes:' 575 | - '2:Updated installed packages to get latest security fixes.' 576 | - version: 1.23.2 577 | date: 2021-03-13 578 | changes: 579 | - 'Fixed issue where the wrong parameter was passed to the post watch folder processing hook.' 580 | - version: 1.23.1 581 | date: 2021-02-06 582 | changes: 583 | - 'Fixed an issue where the automatic video converter would not process Blu-ray video disc folder.' 584 | - version: 1.23.0 585 | date: 2021-01-01 586 | changes: 587 | - 'Added the ability to overwrite the output file if it exists.' 588 | - 'Added the ability to define the file extensions to be considered as video files.' 589 | - 'Updated libva to version 2.10.0.' 590 | - 'Updated gmmlib to version 20.4.1.' 591 | - 'Updated Intel Media Driver to version 20.4.5.' 592 | - 'Updated Intel Media SDK to version 20.5.1.' 593 | - 'Now using baseimage based on Alpine 3.12.' 594 | - version: 1.22.4 595 | date: 2020-08-05 596 | changes: 597 | - 'Upgraded libva to version 2.8.0.' 598 | - 'Upgraded Intel Media SDK to version 20.2.1.' 599 | - 'Upgraded Intel Media Driver to version 20.2.0.' 600 | - 'Fixed an issue where non-video files would fail to be copied.' 601 | - 'Now using baseimage version 3.5.6, which brings the following changes:' 602 | - '2:Other small adjustments for the YAD log monitor target.' 603 | - version: 1.22.3 604 | date: 2020-06-22 605 | changes: 606 | - 'Upgraded HandBrake to version 1.3.3.' 607 | - 'Upgraded Intel VAAPI driver to version 2.4.1.' 608 | - 'Now using Alpine 3.11 baseimage.' 609 | - version: 1.22.2 610 | date: 2020-05-26 611 | changes: 612 | - 'Fixed issue where Intel QSV H.265 encoding would fail.' 613 | - version: 1.22.1 614 | date: 2020-05-09 615 | changes: 616 | - 'Fixed the default preset used by the automatic video converter.' 617 | - 'Fixed an issue where progress of a multi-pass encoding done by the automatic video converter would not be displayed correctly in the UI.' 618 | - version: 1.22.0 619 | date: 2020-05-04 620 | changes: 621 | - 'Upgraded HandBrake to version 1.3.2.' 622 | - '2:NOTE: Presets are now identified with their category. This means that any preset configured for the automatic video converter needs to be adjusted.' 623 | - 'Upgraded libva to version 2.7.1.' 624 | - 'Upgraded Intel Media Driver to version 20.1.1.' 625 | - 'Upgraded Intel Media SDK to version 20.1.1.' 626 | - version: 1.21.0 627 | date: 2020-03-08 628 | changes: 629 | - 'Custom packages for the Automatic Video Converter can now be installed via the `AUTOMATED_CONVERSION_INSTALL_PKGS` environment variable.' 630 | - version: 1.20.0 631 | date: 2020-02-10 632 | changes: 633 | - 'Upgraded HandBrake to version 1.3.1.' 634 | - 'Upgraded libva to version 2.6.1.' 635 | - 'Upgraded Intel Media SDK to version 19.4.0.' 636 | - 'Upgraded Intel Media Driver to version 19.4.0.' 637 | - 'Upgraded Intel VAAPI driver to version 2.4.0.' 638 | - version: 1.19.0 639 | date: 2019-12-08 640 | changes: 641 | - 'Added the ability to set a list of file extensions to be considered as non-video files. This fixes an issue where the automatic video converter would successfully convert non-video files, like images.' 642 | - 'Added the ability to provide custom arguments to HandBrake when it is invoked by the automatic video converter.' 643 | - version: 1.18.0 644 | date: 2019-11-11 645 | changes: 646 | - 'Upgraded HandBrake to version 1.3.0.' 647 | - 'Action to take by the automatic video converter for non-video files is now configurable.' 648 | - 'The automatic video converter now fails the conversion if no title is found in video file.' 649 | - 'Now using baseimage v3.5.3, based on Alpine Liux 3.10, which brings the following changes:' 650 | - '2:Updated installed packages to get latest security fixes.' 651 | - '2:Make sure the tzdata is installed.' 652 | - version: 1.17.1 653 | date: 2019-05-04 654 | changes: 655 | - 'Fixed an issue where the progress output of the automatic video converter would hang.' 656 | - 'Enhanced the progress output of the automatic video converter by showing the path of the video being converted.' 657 | - 'Enhanced the progress output of the automatic video converter by adjusting the frequency of messages.' 658 | - version: 1.17.0 659 | date: 2019-04-26 660 | changes: 661 | - 'Progress of conversions performed by the automatic video converter can be seen in the HandBrake GUI.' 662 | - 'Fixed an issue where a video conversion failure would not be detected.' 663 | - 'Now using baseimage v3.5.2, which brings the following changes:' 664 | - '2:Updated installed packages to get latest security fixes.' 665 | - '2:Fixed issue where the container could have a zombie process.' 666 | - '2:Fixed issue where the password would not be submitted when pressing the enter key in the password modal.' 667 | - '2:Use relative path for favicon ressources to be more friendly with reverse proxy senarios.' 668 | - version: 1.16.0 669 | date: 2019-03-25 670 | changes: 671 | - 'Upgraded HandBrake to version 1.2.2.' 672 | - 'Upgraded libva to version 2.4.0.' 673 | - 'Upgraded Intel Media SDK to version 18.4.1.' 674 | - 'Upgraded Intel Media Driver to version 18.4.1.' 675 | - 'Use baseimage based on Alpine Linux 3.9.' 676 | - 'The number of watch folders is now configurable.' 677 | - 'The root output directory used by the automatic video converter is now configurable.' 678 | - 'Added hook invoked after all files in a watch folder are processed.' 679 | - version: 1.15.1 680 | date: 2019-02-12 681 | changes: 682 | - 'Fixed issue where Intel QSV would not be setup properly when its associated Linux devices where having different owners.' 683 | - version: 1.15.0 684 | date: 2019-01-14 685 | changes: 686 | - 'Upgraded HandBrake to version 1.2.0.' 687 | - 'The automatic video converter now creates the output folder just before moving the video.' 688 | - version: 1.14.11 689 | date: 2018-12-10 690 | changes: 691 | - 'Fixed issue where libraries required to use Intel QSV would not be found.' 692 | - version: 1.14.10 693 | date: 2018-12-10 694 | changes: 695 | - 'Fixed issues related to usage of QSV on recent processors:' 696 | - '2:Added Intel Media driver version 18.3.0.' 697 | - '2:Upgraded Intel VAAPI driver to version 2.3.0.' 698 | - '2:Upgraded to Intel Media SDK to version 18.3.1.' 699 | - '2:Upgraded libva to version 2.3.0.' 700 | - '2:By default, the new Intel Media driver is now used.' 701 | - '2:For processors not supported by the Intel Media driver, use the Intel VAAPI driver.' 702 | - version: 1.14.9 703 | date: 2018-11-12 704 | changes: 705 | - 'The automatic video converter now processes older files first.' 706 | - 'Fixed an issue where the automatic video converter would fail to start when `USER_ID` is set to `0`.' 707 | - 'Do not setup supplementary group if device for Intel QSV is already accessible.' 708 | - 'Added a new log message for a scenario where Intel QSV would not work.' 709 | - version: 1.14.8 710 | date: 2018-09-19 711 | changes: 712 | - 'Now using baseimage v3.5.1, which brings the following changes:' 713 | - '2:Updated installed packages to get latest security fixes.' 714 | - version: 1.14.7 715 | date: 2018-09-11 716 | changes: 717 | - 'Upgraded to HandBrake version 1.1.2.' 718 | - 'Fixes to the automatic video converter:' 719 | - '2:Gracefully handle the case where the pre-conversion hook removes the source video file.' 720 | - '2:Skip unreadable files.' 721 | - '2:Drop root privileges at start.' 722 | - '2:Better handling of unexisting cache files.' 723 | - version: 1.14.6 724 | date: 2018-07-30 725 | changes: 726 | - 'Fixed an issue where the automatic video converter would fail to convert video with multiple titles.' 727 | - 'Make sure to apply the `HANDBRAKE_DEBUG` environment variable to the automatic video converter.' 728 | - version: 1.14.5 729 | date: 2018-07-19 730 | changes: 731 | - 'A video being converted is now written to a temporary directory before being moved to its final location.' 732 | - version: 1.14.4 733 | date: 2018-07-17 734 | changes: 735 | - 'Fixed an issue where HandBrake could crash while encoding a video using x264.' 736 | - version: 1.14.3 737 | date: 2018-07-16 738 | changes: 739 | - 'Added support for debug images.' 740 | - version: 1.14.2 741 | date: 2018-07-13 742 | changes: 743 | - 'Upgraded HandBrake to version 1.1.1.' 744 | - 'Reduced the size of the container image.' 745 | - version: 1.14.1 746 | date: 2018-07-12 747 | changes: 748 | - 'Fixed an issue where the automatic video converter would not be able to access the device required to enable Intel Quick Sync Video hardware-accelerated encoding.' 749 | - version: 1.14.0 750 | date: 2018-07-09 751 | changes: 752 | - 'Added support for Intel Quick Sync Video hardware-accelerated encoding.' 753 | - 'Now using baseimage v3.4.0, which is based on Alpine Linux 3.8.' 754 | - 'Fixed issue where selecting a different video encoder would result in incorrect video preset selection.' 755 | - 'Fixed an issue where the automatic video converter would choose an incorrect output subfolder when `SAME_AS_SRC` is used.' 756 | - 'Fixed an issue where the automatic video converter, during source cleanup, would try to remove the watch folder itself.' 757 | - 'Fixed an issue where the automatic video converter would choose an incorrect output filename when the source is a DVD/Blu-Ray folder.' 758 | - version: 1.13.5 759 | date: 2018-06-18 760 | changes: 761 | - 'Fixed nightly build.' 762 | - version: 1.13.4 763 | date: 2018-06-11 764 | changes: 765 | - 'Fixed nightly build.' 766 | - version: 1.13.3 767 | date: 2018-05-21 768 | changes: 769 | - 'Moved the HandBrake debug log under the proper directory.' 770 | - 'Fixed the nightly build.' 771 | - version: 1.13.2 772 | date: 2018-05-09 773 | changes: 774 | - 'Fixed issue where handling DVD structure would cause a crash.' 775 | - version: 1.13.1 776 | date: 2018-04-26 777 | changes: 778 | - 'Improved fix for FLAC encoder crash.' 779 | - version: 1.13.0 780 | date: 2018-04-09 781 | changes: 782 | - 'Upgraded HandBrake to version 1.1.0.' 783 | - version: 1.12.0 784 | date: 2018-03-22 785 | changes: 786 | - 'Added pre-conversion hook for the automatic video converter.' 787 | - 'Added support for creation of image based on the latest HandBrake development code.' 788 | - 'Switched to a baseimage based on Alpine Linux 3.7.' 789 | - version: 1.11.5 790 | date: 2018-03-02 791 | changes: 792 | - 'Now using baseimage v3.3.4, which brings the following changes (since last used version):' 793 | - '2:Make sure the log monitor is started after the X server.' 794 | - '2:Fixed an issue where the log monitor `yad` target would use XDG folders of the application.' 795 | - '2:Fixed issue where log monitor states were not cleared during container startup.' 796 | - version: 1.11.4 797 | date: 2018-03-01 798 | changes: 799 | - 'Since HandBrake doesn''t work well with ffmpeg, reverted to libav.' 800 | - 'Thus, the FLAC encoder crash has been fixed in libav instead.' 801 | - 'Make sure the main window is always visible in background.' 802 | - version: 1.11.3 803 | date: 2018-02-13 804 | changes: 805 | - 'Fixed an issue where encoding audio to FLAC would cause a crash.' 806 | - 'Use AAC encoder from libavcodec.' 807 | - 'Fixed an issue where automatic conversion of a multi-titles medias would produce only the first one.' 808 | - 'Improved logging of the automatic video converter while processing multi-titles medias.' 809 | - version: 1.11.2 810 | date: 2018-02-03 811 | changes: 812 | - 'Now using baseimage v3.3.2, which brings the following changes:' 813 | - '2:Restored timezone support in Alpine Linux images with glibc.' 814 | - '2:Fixed issue in `add-pkg` helper where a package could be incorrectly detected as installed.' 815 | - version: 1.11.1 816 | date: 2018-01-30 817 | changes: 818 | - 'Now using baseimage v3.3.1, which brings the following changes:' 819 | - '2:Adjusted the way some ressources are accessed to better support reverse proxy to the container.' 820 | - version: 1.11.0 821 | date: 2018-01-22 822 | changes: 823 | - 'Now using baseimage v3.3.0, which brings the following changes (since last used version):' 824 | - '2:For Alpine Linux images with glibc, automatically update dynamic linker''s cache after new libraries are installed.' 825 | - '2:Fixed the LANG environment variable not being set properly.' 826 | - '2:Added the ability to automatically install a CJK (Chinese/Japanese/Korean) font.' 827 | - version: 1.10.0 828 | date: 2018-01-18 829 | changes: 830 | - 'Added support for multiple watch folders.' 831 | - 'Added environment variable to set the interval at which the automatic video converter checks for new files.' 832 | - 'Source file and HandBrake preset name are now passed to the post hook script.' 833 | - version: 1.9.4 834 | date: 2018-01-11 835 | changes: 836 | - 'Now using baseimage v3.2.2, which brings the following changes (since last used version):' 837 | - '2:Upgraded S6 overlay to version 1.21.2.2.' 838 | - '2:Upgraded glibc to version 2.26 (Alpine Linux glibc images).' 839 | - '2:Adjusted the way ownership of /config is taken to better support cases where the folder is mapped to a network share.' 840 | - 'Small adjustment to the way ownership of files are taken.' 841 | - version: 1.9.3 842 | date: 2017-12-12 843 | changes: 844 | - 'Now using baseimage v3.1.4, which brings the following changes:' 845 | - '2:Set 2 worker processes for nginx.' 846 | - version: 1.9.2 847 | date: 2017-11-20 848 | changes: 849 | - 'Now using baseimage v3.1.3, which brings the following changes:' 850 | - '2:Upgraded S6 overlay to version 1.21.2.1.' 851 | - 'Better output of automated conversions: encoding progress now seen in container''s log, while detailed output is redirected to a log file.' 852 | - version: 1.9.1 853 | date: 2017-11-07 854 | changes: 855 | - 'Now using baseimage v3.1.2, which brings the following changes (from last used version):' 856 | - '2:Fixed an issue where a self-disabled service could be restarted.' 857 | - '2:Upgraded S6 overlay to version 1.21.2.0.' 858 | - '2:Use a more efficient way to monitor status files.' 859 | - version: 1.9.0 860 | date: 2017-10-29 861 | changes: 862 | - 'Now using baseimage v3.1.0, which brings the following changes:' 863 | - '2:Upgraded S6 overlay to version 1.21.1.1.' 864 | - '2:Enhanced integration of service dependencies functionality.' 865 | - '2:Added a simple log monitor.' 866 | - '2:Fixed race condition where container''s exit code would not be the expected one.' 867 | - '2:Fixed issue where application''s GUI fails to displayed when accessing it through the web interface via standard ports 80/443.' 868 | - version: 1.8.0 869 | date: 2017-10-09 870 | changes: 871 | - 'Now using baseimage v3.0.2, which brings the following changes:' 872 | - '2:Better support for service dependencies.' 873 | - '2:Added support for secure access to the application''s GUI.' 874 | - version: 1.7.0 875 | date: 2017-09-18 876 | changes: 877 | - 'Added support for optical drive(s) access.' 878 | - 'Removed some useless shortcuts in the video source selection window.' 879 | - version: 1.6.1 880 | date: 2017-09-08 881 | changes: 882 | - 'Now using baseimage v2.0.8, which brings the following changes (from last used version):' 883 | - '2:Fixed timezone support on alpine-glibc images.' 884 | - '2:Fixed duplicated entries in /etc/passwd and /etc/group that were created after a restart of the container.' 885 | - version: 1.6.0 886 | date: 2017-08-16 887 | changes: 888 | - 'Added libdvdcss to allow reading of encrypted DVD video files.' 889 | - version: 1.5.9 890 | date: 2017-08-14 891 | changes: 892 | - 'Now using baseimage v2.0.6, which brings the following changes:' 893 | - '2:Upgraded S6 overlay to version 1.20.0.0.' 894 | - version: 1.5.8 895 | date: 2017-08-12 896 | changes: 897 | - 'Fixed conversion of videos containing multiple titles.' 898 | - version: 1.5.7 899 | date: 2017-07-31 900 | changes: 901 | - 'Now using baseimage v2.0.5, which brings the following changes (from last used version):' 902 | - '2:Clear the environment of the container during startup.' 903 | - '2:Clear the /tmp folder during startup.' 904 | - '2:Cleanly terminate the X server when container is restarted/stopped.' 905 | - '2:Improved robustness of X server starting process.' 906 | - '2:Removed unneeded files from the image.' 907 | - version: 1.5.6 908 | date: 2017-07-27 909 | changes: 910 | - 'Watch folder: recursively remove empty directories.' 911 | - version: 1.5.5 912 | date: 2017-07-27 913 | changes: 914 | - 'Now using baseimage v2.0.3, which brings the following changes:' 915 | - '2:Improved robustness of the X server starting process.' 916 | - version: 1.5.4 917 | date: 2017-07-26 918 | changes: 919 | - 'Watch folder: properly support video discs (ISO files, DVD/Blu-ray folders).' 920 | - 'Watch folder: when removing empty folders, ignore the watch folder itself.' 921 | - 'Watch folder: make sure to abort if destination file already exists.' 922 | - version: 1.5.3 923 | date: 2017-07-25 924 | changes: 925 | - 'Fixed HandBrake CLI crash that was occuring when working with ISO files or DVD folders.' 926 | - 'Small adjustments to the default configuration file.' 927 | - version: 1.5.2 928 | date: 2017-07-23 929 | changes: 930 | - 'Now using baseimage v2.0.2, which brings the following changes:' 931 | - '2:Proper VNC port is exposed.' 932 | - version: 1.5.1 933 | date: 2017-07-18 934 | changes: 935 | - 'Now using baseimage v2.0.1, which brings the following changes:' 936 | - '2:Internal enhancements.' 937 | - '2:Clean temporary files left by npm.' 938 | - version: 1.5.0 939 | date: 2017-07-17 940 | changes: 941 | - 'Now using baseimage v2.0.0, which brings the following changes:' 942 | - '2:Various internal enhancements.' 943 | - '2:Fixed the way a service waits for another one.' 944 | - 'Watch folder: ignore hidden files and folders.' 945 | - 'Watch folder: adjusted the way empty folders are removed.' 946 | - version: 1.4.0 947 | date: 2017-07-04 948 | changes: 949 | - 'Watch folder: Make sure to respect the configured umask.' 950 | - 'Now using baseimage v1.5.0, which brings the following changes:' 951 | - '2:Added the UMASK environment variable to control how file permissions are set for newly created files.' 952 | - '2:Added the X11VNC_EXTRA_OPTS environment variable used to pass additional arguments to the x11vnc server.' 953 | - '2:By default, activate auto-scaling of application''s window.' 954 | - '2:Applied latest Alpine Linux security updates.' 955 | - version: 1.3.3 956 | date: 2017-06-30 957 | changes: 958 | - 'Watch folder: Added handling of environment variable AUTOMATED_CONVERSION_OUTPUT_SUBDIR, which allows customization of the output location of automatically converted videos..' 959 | - 'The default source folder is now /storage.' 960 | - version: 1.3.2 961 | date: 2017-06-27 962 | changes: 963 | - 'Watch folder: also process files in subfolders.' 964 | - version: 1.3.1 965 | date: 2017-06-22 966 | changes: 967 | - 'Now using baseimage v1.4.3, which brings the following changes:' 968 | - '2:Updated Alpine Linux to version 3.6.2.' 969 | - version: 1.3.0 970 | date: 2017-06-21 971 | changes: 972 | - 'Now using baseimage v1.4.2, which brings the following changes (from last used version):' 973 | - '2:Switched to Alpine Linux 3.6.' 974 | - '2:Associate the application''s icon to a unique version to avoid browser cache issues.' 975 | - '2:Fixed prefix of some service related messages.' 976 | - '2:Added support for supplying supplementary groups of the application.' 977 | - '2:Improved process startup and shutdown.' 978 | - '2:When container is stopped or restarted, processes are now terminated gracefully and in proper order. This allow the GUI application to execute its termination routine.' 979 | - '2:No more error messages when container is stopped or restarted.' 980 | - version: 1.2.0 981 | date: 2017-05-31 982 | changes: 983 | - 'Added support for post-conversion hook.' 984 | - version: 1.1.4 985 | date: 2017-05-30 986 | changes: 987 | - 'Now using baseimage v1.3.2, which brings the following changes:' 988 | - '2:Fixed password modal window not showing up when required.' 989 | - version: 1.1.3 990 | date: 2017-05-26 991 | changes: 992 | - 'Watch folder: Fixed issue where, after a first successful conversion, conversion of next available video files would not start.' 993 | - 'Renamed the ''Watch Folder'' service to ''Automatic Video Converter''.' 994 | - version: 1.1.2 995 | date: 2017-05-24 996 | changes: 997 | - 'Watch folder: Changed the way files being transferred are detected. Method used previously was not working properly in all cases.' 998 | - version: 1.1.1 999 | date: 2017-05-24 1000 | changes: 1001 | - 'Watch folder: temporarily skip files being accessed/transferred.' 1002 | - 'Watch folder: improved robustness.' 1003 | - version: 1.1.0 1004 | date: 2017-05-23 1005 | changes: 1006 | - 'Watch folder: properly support filenames containing spaces.' 1007 | - 'Watch folder: added support for symbolic links.' 1008 | - 'HandBrake debug can now be enabled via the HANDBRAKE_DEBUG environment variable.' 1009 | - 'Take ownership of the `/output` folder.' 1010 | - 'Added the ability to remove video source files from the watch folder after successfully conversion.' 1011 | - version: 1.0.1 1012 | date: 2017-05-18 1013 | changes: 1014 | - 'The watch folder is now monitored without inotify for better compatibility.' 1015 | - version: 1.0.0 1016 | date: 2017-05-18 1017 | changes: 1018 | - 'Initial release.' 1019 | 1020 | container: 1021 | storage_permissions: ro 1022 | 1023 | # Environment variables. 1024 | environment_variables: 1025 | - name: HANDBRAKE_DEBUG 1026 | description: >- 1027 | Setting this to `1` enables HandBrake debug logging for both the GUI and 1028 | the automatic video converter. For the latter, the increased verbosity 1029 | is reflected in `/config/log/hb/conversion.log` (container path). For 1030 | the GUI, log messages are sent to `/config/log/hb/handbrake.debug.log` 1031 | (container path). **NOTE**: When enabled, a lot of information is 1032 | generated and the log file will grow quickly. Make sure to enable this 1033 | temporarily and only when needed. 1034 | type: public 1035 | default: 0 1036 | - name: HANDBRAKE_GUI 1037 | description: >- 1038 | Setting this to `1` enables the HandBrake GUI, `0` disables it. 1039 | type: public 1040 | default: 1 1041 | unraid_template: 1042 | title: "HandBrake GUI State" 1043 | description: >- 1044 | Setting this to 1 enables the HandBrake GUI, 0 disables it. 1045 | display: advanced 1046 | required: false 1047 | mask: false 1048 | - name: HANDBRAKE_GUI_QUEUE_STARTUP_ACTION 1049 | description: >- 1050 | Action to be taken on the queue of HandBrake (GUI) when it starts. When set to 1051 | `PROCESS`, HandBrake automatically starts encoding elements present in the queue. 1052 | When set to `CLEAR`, the content of the queue is cleared. With any other value, 1053 | no action is taken on the queue. 1054 | type: public 1055 | default: NONE 1056 | unraid_template: 1057 | title: "HandBrake GUI State" 1058 | description: >- 1059 | Action to be taken on the queue of HandBrake (GUI) when it starts. When set to 1060 | "PROCESS", HandBrake automatically starts encoding elements present in the 1061 | queue. When set to "CLEAR", the content of the queue is cleared. With any other 1062 | value, no action is taken on the queue. 1063 | display: advanced 1064 | required: false 1065 | mask: false 1066 | - name: AUTOMATED_CONVERSION 1067 | description: >- 1068 | Setting this to `1` enables the automatic video converter, `0` disables 1069 | it. 1070 | type: public 1071 | default: 1 1072 | unraid_template: 1073 | title: "Automatic Video Converter: State" 1074 | description: >- 1075 | Setting this to 1 enables the automatic video converter, 0 disables 1076 | it. 1077 | display: advanced 1078 | required: false 1079 | mask: false 1080 | - name: AUTOMATED_CONVERSION_PRESET 1081 | description: >- 1082 | HandBrake preset used by the automatic video converter. Identification 1083 | of a preset must follow the format `/`. See the 1084 | [Automatic Video Conversion](#automatic-video-conversion) section for 1085 | more details. 1086 | type: public 1087 | default: "General/Very Fast 1080p30" 1088 | unraid_template: 1089 | title: "Automatic Video Converter: Preset" 1090 | description: >- 1091 | Preset used by the automatic video converter. Identification of the 1092 | preset must follow the format 'CATEGORY/PRESET NAME'. Name of all 1093 | available presets can be seen via the HandBrake GUI. 1094 | display: always 1095 | required: false 1096 | mask: false 1097 | - name: AUTOMATED_CONVERSION_FORMAT 1098 | description: >- 1099 | Video container format used by the automatic video converter for output 1100 | files. This is typically the video filename extension. See the 1101 | [Automatic Video Conversion](#automatic-video-conversion) section for 1102 | more details. 1103 | type: public 1104 | default: mp4 1105 | unraid_template: 1106 | title: "Automatic Video Converter: Format" 1107 | description: >- 1108 | Video container format used by the automatic video converter for 1109 | output files. This is typically the video filename extension. 1110 | display: always 1111 | required: false 1112 | mask: false 1113 | - name: AUTOMATED_CONVERSION_KEEP_SOURCE 1114 | description: >- 1115 | When set to `0`, a video that has been successfully converted is removed 1116 | from the watch folder. 1117 | type: public 1118 | default: 1 1119 | unraid_template: 1120 | title: "Automatic Video Converter: Keep Source Files" 1121 | description: >- 1122 | Set to 0 to remove successfully converted videos from the watch folder, 1 to keep them. 1123 | display: always 1124 | required: false 1125 | mask: false 1126 | - name: AUTOMATED_CONVERSION_VIDEO_FILE_EXTENSIONS 1127 | description: >- 1128 | Space-separated list of file extensions to be considered as video files. 1129 | By default, this list is empty, meaning that the automatic video 1130 | converter will let HandBrake automatically detects if a file, no matter 1131 | its extension, is a video or not (note that extensions defined by the 1132 | `AUTOMATED_CONVERSION_NON_VIDEO_FILE_EXTENSIONS` environment variable 1133 | are always considered as non-video files). Normally, this variable 1134 | doesn't need to be set. Usage of this variable is useful when only 1135 | specific video files need to converted. 1136 | type: public 1137 | unraid_template: 1138 | title: "Automatic Video Converter: Video File Extensions" 1139 | description: >- 1140 | Space-separated list of file extensions to be considered as video 1141 | files. By default, this list is empty, meaning that the automatic 1142 | video converter will let HandBrake automatically detects if a file, 1143 | no matter its extension, is a video or not (note that extensions 1144 | defined by the Non-Video File Extensions list are always considered as 1145 | non-video files). Normally, this variable doesn't need to be set. 1146 | Usage of this variable is useful when only specific video files need 1147 | to converted. 1148 | display: advanced 1149 | required: false 1150 | mask: false 1151 | - name: AUTOMATED_CONVERSION_NON_VIDEO_FILE_ACTION 1152 | description: >- 1153 | When set to `ignore`, a non-video file found in the watch folder is 1154 | ignored. If set to `copy`, a non-video file is copied as-is to the 1155 | output folder. 1156 | type: public 1157 | default: ignore 1158 | unraid_template: 1159 | title: "Automatic Video Converter: Non-Video File Action" 1160 | description: >- 1161 | Set to "ignore" to ignore non-video files from the watch folder, or 1162 | set to "copy" to copy them as-is to the output folder. 1163 | display: always 1164 | required: false 1165 | mask: false 1166 | - name: AUTOMATED_CONVERSION_NON_VIDEO_FILE_EXTENSIONS 1167 | description: >- 1168 | Space-separated list of file extensions to be considered as not being 1169 | videos. Most non-video files are properly rejected by HandBrake. 1170 | However, some files, like images, are convertible by HandBrake even if 1171 | they are not video files. 1172 | type: public 1173 | default: jpg jpeg bmp png gif txt nfo 1174 | unraid_template: 1175 | title: "Automatic Video Converter: Non-Video File Extensions" 1176 | display: advanced 1177 | required: false 1178 | mask: false 1179 | - name: AUTOMATED_CONVERSION_OUTPUT_DIR 1180 | description: >- 1181 | Root directory, inside the container, where converted videos should be 1182 | written. **NOTE**: Make sure a volume mapping for this directory is 1183 | defined when creating the container. 1184 | type: public 1185 | default: /output 1186 | unraid_template: 1187 | title: "Automatic Video Converter: Output directory" 1188 | description: >- 1189 | Root directory, inside the container, where converted videos should be 1190 | written. 1191 | display: always 1192 | required: false 1193 | mask: false 1194 | - name: AUTOMATED_CONVERSION_OUTPUT_SUBDIR 1195 | description: >- 1196 | Subdirectory of the output folder into which converted videos should be 1197 | written. By default, this variable is not set, meaning that videos are 1198 | saved directly into `/output/`. If `Home/Movies` is set, converted 1199 | videos will be written to `/output/Home/Movies`. Use the special value 1200 | `SAME_AS_SRC` to use the same subfolder as the source. For example, if 1201 | the video source file is `/watch/Movies/mymovie.mkv`, the converted 1202 | video will be written to `/output/Movies/`. 1203 | type: public 1204 | unraid_template: 1205 | title: "Automatic Video Converter: Output Subdirectory" 1206 | description: >- 1207 | Subdirectory of the output folder into which converted videos should 1208 | be written. Leave value empty to save converted videos directly into 1209 | "/output/". Use the special value "SAME_AS_SRC" to use the same 1210 | subfolder as the source. For example, if the video source file is 1211 | "/watch/Movies/mymovie.mkv", the converted video will be written to 1212 | "/output/Movies/". Any other value is considered as the subfolder 1213 | name. For example, setting the value "Home/Movies" will make 1214 | converted videos to be written to "/output/Home/Movies". 1215 | display: always 1216 | required: false 1217 | mask: false 1218 | - name: AUTOMATED_CONVERSION_OVERWRITE_OUTPUT 1219 | description: >- 1220 | Setting this to `1` allows the final destination file to be overwritten if it already exists. 1221 | type: public 1222 | default: 0 1223 | unraid_template: 1224 | title: "Automatic Video Converter: Overwrite Destination" 1225 | description: >- 1226 | Setting this to 1 allows the final destination file to be overwritten if it already exists. 1227 | display: advanced 1228 | required: false 1229 | mask: false 1230 | - name: AUTOMATED_CONVERSION_SOURCE_STABLE_TIME 1231 | description: >- 1232 | Time (in seconds) during which properties (e.g. size, time, etc) of a 1233 | video file in the watch folder need to remain the same. This is to 1234 | avoid processing a file that is being copied. 1235 | type: public 1236 | default: 5 1237 | unraid_template: 1238 | title: "Automatic Video Converter: Source File Stable Time" 1239 | display: advanced 1240 | required: false 1241 | mask: false 1242 | - name: AUTOMATED_CONVERSION_SOURCE_MIN_DURATION 1243 | description: >- 1244 | Minimum title duration (in seconds). Shorter titles will be ignored. 1245 | This applies only to video disc sources (ISO file, `VIDEO_TS` folder 1246 | or `BDMV` folder). 1247 | type: public 1248 | default: 10 1249 | unraid_template: 1250 | title: "Automatic Video Converter: Minimum Title Duration" 1251 | description: >- 1252 | Minimum title duration (in seconds). Shorter titles will be ignored. 1253 | This applies only to video disc sources (ISO file, VIDEO_TS folder or 1254 | BDMV folder). 1255 | display: advanced 1256 | required: false 1257 | mask: false 1258 | - name: AUTOMATED_CONVERSION_SOURCE_MAIN_TITLE_DETECTION 1259 | description: >- 1260 | Setting this to `1` enables HandBrake main feature title detection to 1261 | try to guess and select the main title. 1262 | type: public 1263 | default: 0 1264 | unraid_template: 1265 | title: "Automatic Video Converter: Main Title Detection" 1266 | description: >- 1267 | Setting this to 1 enables HandBrake main feature title detection to 1268 | try to guess and select the main title. 1269 | display: advanced 1270 | required: false 1271 | mask: false 1272 | - name: AUTOMATED_CONVERSION_CHECK_INTERVAL 1273 | description: >- 1274 | Interval (in seconds) at which the automatic video converter checks for new files. 1275 | type: public 1276 | default: 5 1277 | unraid_template: 1278 | title: "Automatic Video Converter: Check Interval" 1279 | display: advanced 1280 | required: false 1281 | mask: false 1282 | - name: AUTOMATED_CONVERSION_MAX_WATCH_FOLDERS 1283 | description: >- 1284 | Maximum number of watch folders handled by the automatic video converter. 1285 | type: public 1286 | default: 5 1287 | unraid_template: 1288 | title: "Automatic Video Converter: Number of Watch Folders" 1289 | display: advanced 1290 | required: false 1291 | mask: false 1292 | - name: AUTOMATED_CONVERSION_NO_GUI_PROGRESS 1293 | description: >- 1294 | When set to `1`, progress of videos converted by the automatic video converter is not shown in the HandBrake GUI. 1295 | type: public 1296 | default: 0 1297 | unraid_template: 1298 | title: "Automatic Video Converter: Disable Progress in GUI" 1299 | description: >- 1300 | Set to 1 to disable display of the video conversion progress in HandBrake GUI. 1301 | display: advanced 1302 | required: false 1303 | mask: false 1304 | - name: AUTOMATED_CONVERSION_HANDBRAKE_CUSTOM_ARGS 1305 | description: >- 1306 | Custom arguments to pass to HandBrake when performing a conversion. 1307 | type: public 1308 | unraid_template: 1309 | title: "Automatic Video Converter: Custom HandBrake Arguments" 1310 | display: advanced 1311 | required: false 1312 | mask: false 1313 | - name: AUTOMATED_CONVERSION_INSTALL_PKGS 1314 | description: >- 1315 | Space-separated list of Alpine Linux packages to install. This is 1316 | useful when the automatic video converter's hooks require tools not 1317 | available in the container image. See https://pkgs.alpinelinux.org 1318 | for the list of available Alpine Linux packages. 1319 | type: public 1320 | unraid_template: 1321 | title: "Automatic Video Converter: Install Packages" 1322 | display: advanced 1323 | required: false 1324 | mask: false 1325 | - name: AUTOMATED_CONVERSION_USE_TRASH 1326 | description: >- 1327 | When set to `1`, the automatic video converter uses the trash directory. 1328 | So when the automatic video converter is configured to *not* keep 1329 | sources, it will move them to the trash directory (`/trash` inside the 1330 | container) instead of deleting them. 1331 | type: public 1332 | default: 0 1333 | unraid_template: 1334 | title: "Automatic Video Converter: Use Trash Directory" 1335 | description: >- 1336 | Set to 1 to enable usage of the trash directory. So when the automatic 1337 | video converter is configured to not keep sources, it will move files 1338 | to the trash directory (/trash inside the container) instead of 1339 | deleting them. 1340 | display: advanced 1341 | required: false 1342 | mask: false 1343 | 1344 | # Volumes 1345 | volumes: 1346 | - container_path: /watch 1347 | host_path_example: "/home/user/HandBrake/watch" 1348 | description: >- 1349 | This is where videos to be automatically converted are located 1350 | permissions: rw 1351 | include_in_quick_start: true 1352 | unraid_template: 1353 | title: Watch Directory 1354 | description: >- 1355 | This is the watch folder of the automatic video converter. Any video 1356 | copied into this folder will be automatically converted by HandBrake. 1357 | display: always 1358 | required: false 1359 | mask: false 1360 | - container_path: /output 1361 | host_path_example: "/home/user/HandBrake/output" 1362 | description: >- 1363 | This is where automatically converted video files are written. 1364 | permissions: rw 1365 | include_in_quick_start: true 1366 | unraid_template: 1367 | title: Output Directory 1368 | description: >- 1369 | This is the default output folder for converted videos. Also used by 1370 | the automatic video converter. 1371 | display: always 1372 | required: true 1373 | mask: false 1374 | - container_path: /trash 1375 | host_path_example: "/home/user/HandBrake/trash" 1376 | description: >- 1377 | When trash usage is enabled, this is where the automatic video converter moves 1378 | converted files instead of deleting them. 1379 | permissions: rw 1380 | unraid_template: 1381 | title: Trash Directory 1382 | display: advanced 1383 | required: false 1384 | mask: false 1385 | 1386 | # Network ports 1387 | ports: [] 1388 | 1389 | # Devices 1390 | devices: [] 1391 | -------------------------------------------------------------------------------- /rootfs/defaults/hooks/post_conversion.sh.example: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This is an example of a post-conversion hook. This script is always invoked 4 | # with /bin/sh (shebang ignored). 5 | # 6 | # The first parameter is the conversion status. A value of 0 indicates that 7 | # the video has been converted successfully. Else, conversion failed. 8 | # 9 | # The second parameter is the full path to the converted video (the output). 10 | # 11 | # The third parameter is the full path to the source file. 12 | # 13 | # The fourth argument is the name of the HandBrake preset used to convert the 14 | # video. 15 | # 16 | 17 | CONVERSION_STATUS=$1 18 | CONVERTED_FILE="$2" 19 | SOURCE_FILE="$3" 20 | PRESET="$4" 21 | 22 | echo "post-conversion: Status = $CONVERSION_STATUS" 23 | echo "post-conversion: Output File = $CONVERTED_FILE" 24 | echo "post-conversion: Source File = $SOURCE_FILE" 25 | echo "post-conversion: Preset = $PRESET" 26 | 27 | if [ "$CONVERSION_STATUS" -eq 0 ]; then 28 | # Successful conversion. 29 | 30 | # TODO: Do something useful. 31 | : 32 | else 33 | # Failed conversion. 34 | 35 | # TODO: Do something useful. 36 | : 37 | fi 38 | -------------------------------------------------------------------------------- /rootfs/defaults/hooks/post_watch_folder_processing.sh.example: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This is an example of a post watch folder processing hook. This script is 4 | # always invoked with /bin/sh (shebang ignored). 5 | # 6 | # The argument of the script is the path to the watch folder. 7 | # 8 | 9 | WATCH_FOLDER=$1 10 | 11 | echo "post-watch folder processing: Watch folder = $WATCH_FOLDER" 12 | 13 | # TODO: Do something useful. 14 | -------------------------------------------------------------------------------- /rootfs/defaults/hooks/pre_conversion.sh.example: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This is an example of a pre-conversion hook. This script is always invoked 4 | # with /bin/sh (shebang ignored). 5 | # 6 | # The first parameter is the full path where the video will be converted. 7 | # 8 | # The second parameter is the full path to the source file. 9 | # 10 | # The third argument is the name of the HandBrake preset that will be used to 11 | # convert the video. 12 | # 13 | 14 | CONVERTED_FILE="$1" 15 | SOURCE_FILE="$2" 16 | PRESET="$3" 17 | 18 | echo "pre-conversion: Output File = $CONVERTED_FILE" 19 | echo "pre-conversion: Source File = $SOURCE_FILE" 20 | echo "pre-conversion: Preset = $PRESET" 21 | 22 | # TODO: Do something useful. 23 | -------------------------------------------------------------------------------- /rootfs/defaults/preferences.json: -------------------------------------------------------------------------------- 1 | { 2 | "Preferences": { 3 | "AddCC": false, 4 | "AutoScan": false, 5 | "DiskFreeCheck": true, 6 | "DiskFreeLimit": 10000.0, 7 | "EncodeLogLocation": false, 8 | "ExportDirectory": "/output", 9 | "HideAdvancedVideoSettings": true, 10 | "LogLongevity": "month", 11 | "LoggingLevel": "1", 12 | "MinTitleDuration": 10, 13 | "PreferredLanguage": "und", 14 | "RemoveFinishedJobs": false, 15 | "SrtDir": ".", 16 | "SyncTitleSettings": true, 17 | "UseM4v": true, 18 | "VideoQualityGranularity": "1", 19 | "WhenComplete": "nothing", 20 | "allow_tweaks": false, 21 | "auto_name": true, 22 | "auto_name_template": "{source}", 23 | "check_updates": "weekly", 24 | "default_source": "/storage/dvd", 25 | "destination_dir": "/output", 26 | "hbfd": false, 27 | "hbfd_feature": false, 28 | "last_update_check": 0, 29 | "live_duration": 15, 30 | "preset_window_height": 1, 31 | "preset_window_width": 1, 32 | "preview_count": 10, 33 | "preview_show_crop": false, 34 | "preview_x": -1, 35 | "preview_y": -1, 36 | "reduce_hd_preview": true, 37 | "update_skip_version": 0, 38 | "use_dvdnav": true, 39 | "version": "0.1", 40 | "window_height": 767, 41 | "window_width": 1280 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /rootfs/etc/cont-env.d/INSTALL_PACKAGES_INTERNAL: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e # Exit immediately if a command exits with a non-zero status. 4 | set -u # Treat unset variables as an error. 5 | 6 | if [ -z "${INSTALL_PACKAGES:-}" ] && [ -n "${AUTOMATED_CONVERSION_INSTALL_PKGS:-}" ] 7 | then 8 | >&2 echo "Usage of AUTOMATED_CONVERSION_INSTALL_PKGS environment variable is deprecated. INSTALL_PACKAGES should be used instead." 9 | echo "$AUTOMATED_CONVERSION_INSTALL_PKGS" 10 | else 11 | exit 100 12 | fi 13 | 14 | # vim:ft=sh:ts=4:sw=4:et:sts=4 15 | -------------------------------------------------------------------------------- /rootfs/etc/cont-env.d/SUP_GROUP_IDS_INTERNAL: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e # Exit immediately if a command exits with a non-zero status. 4 | set -u # Treat unset variables as an error. 5 | 6 | GRPS=$(mktemp) 7 | 8 | # Get supplementary group(s) associated to optical drive(s). 9 | if true; then 10 | lsscsi -k | grep -w "cd/dvd" | tr -s ' ' | while read -r DRV 11 | do 12 | SR_DEV="$(echo "$DRV" | rev | awk '{print $1}' | rev)" 13 | 14 | # Save the associated group. 15 | if [ -e "$SR_DEV" ]; then 16 | # Save the associated group. 17 | G="$(stat -c "%g" "$SR_DEV")" 18 | [ "$G" -eq 0 ] || echo "$G" >> "$GRPS" 19 | fi 20 | done 21 | fi 22 | 23 | # Get supplementary group(s) associated to QSV device. 24 | if [ -d /dev/dri/ ]; then 25 | # Get group of devices under /dev/dri/. 26 | find /dev/dri/ -type c | while read DRI_DEV 27 | do 28 | G="$(stat -c "%g" "$DRI_DEV")" 29 | if [ "$G" -ne 0 ]; then 30 | echo "$G" >> "$GRPS" 31 | fi 32 | done 33 | fi 34 | 35 | # Print supplementary group IDs. 36 | if [ "$(cat "$GRPS")" != "" ]; then 37 | cat "$GRPS" | grep -v '^$' | grep -v '^0$' | sort -nub | tr '\n' ',' 38 | rm "$GRPS" 39 | else 40 | rm "$GRPS" 41 | exit 100 42 | fi 43 | 44 | # vim:ft=sh:ts=4:sw=4:et:sts=4 45 | -------------------------------------------------------------------------------- /rootfs/etc/cont-init.d/54-check-optical-drive.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Find and report issues with detected optical drives that would prevent them 4 | # to be used by MakeMKV. 5 | # 6 | 7 | set -e # Exit immediately if a command exits with a non-zero status. 8 | set -u # Treat unset variables as an error. 9 | 10 | permissions_ok() { 11 | DEV_UID="$(stat -c "%u" "$1")" 12 | DEV_GID="$(stat -c "%g" "$1")" 13 | 14 | DEV_PERM="$(stat -c "%a" "$1")" 15 | DEV_PERM_U="$(echo "$DEV_PERM" | head -c 1 | tail -c 1)" 16 | DEV_PERM_G="$(echo "$DEV_PERM" | head -c 2 | tail -c 1)" 17 | DEV_PERM_O="$(echo "$DEV_PERM" | head -c 3 | tail -c 1)" 18 | 19 | # NOTE: Write access to the device *is* required, otherwise MakeMKV will 20 | # complain. 21 | 22 | # OK: User permission of the device is R/W and the container runs as root. 23 | [ "$DEV_PERM_U" -ge 6 ] && [ "$USER_ID" = "0" ] && return 0 24 | 25 | # OK: User permission of the device is R/W and user matches the container 26 | # user. 27 | [ "$DEV_PERM_U" -ge 6 ] && [ "$DEV_UID" = "$USER_ID" ] && return 0 28 | 29 | # OK: The group permission of the device is R/W and group maches the 30 | # container group. 31 | [ "$DEV_PERM_G" -ge 6 ] && [ "$DEV_GID" = "$GROUP_ID" ] && return 0 32 | 33 | # OK: The group permission of the device is R/W and group is not root, 34 | # meaning that a supplementary group can be automatically added. 35 | [ "$DEV_PERM_G" -ge 6 ] && [ "$DEV_GID" != "0" ] && return 0 36 | 37 | # OK: The other permission of the device is R/W. 38 | [ "$DEV_PERM_O" -ge 6 ] && return 0 39 | 40 | return 1 41 | } 42 | 43 | write_access_test() { 44 | [ -e "$1" ] || return 1 45 | output="$(2>&1 >> "$1")" 46 | rc=$? 47 | if [ $rc -ne 0 ]; then 48 | if ! echo "$output" | grep -iq "permission denied"; then 49 | # We just want error related to the lack of write permission. 50 | rc=0 51 | fi 52 | fi 53 | return $rc 54 | } 55 | 56 | using_initial_user_namespace() { 57 | [ "$(cat /proc/self/uid_map | xargs)" = "0 0 4294967295" ] 58 | } 59 | 60 | echo "looking for usable optical drives..." 61 | 62 | USABLE_DRIVES_FOUND="$(mktemp)" 63 | echo 0 > "$USABLE_DRIVES_FOUND" 64 | 65 | lsscsi | grep -w "cd/dvd" | awk '{print $1}' | tr -d '[]' | while read -r DRV_ID 66 | do 67 | DRV="$(lsscsi -b -k "$DRV_ID" | tr -s ' ' | xargs)" 68 | DRV_NAME="$(lsscsi -c "$DRV_ID" | grep Vendor: | sed -r 's/(Vendor:|Model:|Rev:)//g' | tr -s ' ' | xargs)" 69 | 70 | SR_DEV="$(echo "$DRV" | awk '{print $2}')" 71 | 72 | echo "found optical drive '$DRV_NAME' [$SR_DEV]" 73 | if [ "$SR_DEV" = "-" ]; then 74 | echo " [ ERR ] no associated SCSI CD-ROM (sr) device detected." 75 | else 76 | echo " [ OK ] associated SCSI CD-ROM (sr) device detected: $SR_DEV." 77 | if [ -e "$SR_DEV" ]; then 78 | echo " [ OK ] the host device $SR_DEV is exposed to the container." 79 | if permissions_ok "$SR_DEV"; then 80 | echo " [ OK ] the device $SR_DEV has proper permissions." 81 | is-bool-val-false "${CONTAINER_DEBUG:-0}" || echo " permissions: $(ls -l "$SR_DEV" | awk '{print $1,$3,$4}')" 82 | if write_access_test "$SR_DEV"; then 83 | echo 1 > "$USABLE_DRIVES_FOUND" 84 | echo " [ OK ] the container can write to device $SR_DEV." 85 | else 86 | echo " [ ERR ] the container cannot write to device $SR_DEV." 87 | using_initial_user_namespace || echo " problem might be caused by improper user namespace configuration." 88 | fi 89 | else 90 | echo " [ ERR ] the device $SR_DEV does not have proper permissions." 91 | is-bool-val-false "${CONTAINER_DEBUG:-0}" || echo " permissions: $(ls -l "$SR_DEV" | awk '{print $1,$3,$4}')" 92 | fi 93 | else 94 | echo " [ ERR ] the host device $SR_DEV is not exposed to the container." 95 | fi 96 | fi 97 | done 98 | 99 | if [ "$(cat "$USABLE_DRIVES_FOUND")" -eq 0 ]; then 100 | echo "no usable optical drives found." 101 | fi 102 | rm "$USABLE_DRIVES_FOUND" 103 | 104 | # vim:ft=sh:ts=4:sw=4:et:sts=4 105 | -------------------------------------------------------------------------------- /rootfs/etc/cont-init.d/54-check-qsv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e # Exit immediately if a command exits with a non-zero status. 4 | set -u # Treat unset variables as an error. 5 | 6 | DRI_DIR="/dev/dri" 7 | DRI_DEV="$(ls "$DRI_DIR"/renderD* 2>/dev/null || true)" 8 | PROCESSOR_NAME="$(list_cpu_features | grep "^brand " | awk -F ':' '{ gsub(/^[ \t]+/,"",$2); print $2 }')" 9 | MICROARCHITECTURE="$(list_cpu_features | grep "^uarch " | awk -F ':' '{ gsub(/^[ \t]+/,"",$2); print $2 }')" 10 | 11 | CPU_QSV_CAPABLE=true 12 | CPU_SUPPORTED_BY_HB=true 13 | 14 | echo "Processor: $PROCESSOR_NAME" 15 | echo "Microarchitecture: $MICROARCHITECTURE" 16 | echo "Kernel: $(uname -r)" 17 | 18 | # 19 | # Determine if the microarchitecture supports QSV. If it does, verify if it is 20 | # supported by HandBrake. 21 | # 22 | # See the following references: 23 | # https://en.wikipedia.org/w/index.php?title=Intel_Quick_Sync_Video 24 | # https://en.wikipedia.org/wiki/List_of_Intel_CPU_microarchitectures 25 | # https://github.com/google/cpu_features/blob/main/include/cpuinfo_x86.h 26 | # https://handbrake.fr/docs/en/latest/technical/video-qsv.html 27 | # 28 | case "$MICROARCHITECTURE" in 29 | # QSV Version 1 30 | INTEL_SNB) # SANDYBRIDGE 31 | CPU_SUPPORTED_BY_HB=false 32 | ;; 33 | # QSV Version 2 34 | INTEL_IVB) # IVYBRIDGE 35 | CPU_SUPPORTED_BY_HB=false 36 | ;; 37 | # QSV Version 3 38 | INTEL_HSW) # HASWELL 39 | CPU_SUPPORTED_BY_HB=false 40 | ;; 41 | # QSV Version 4 42 | INTEL_BDW) # BROADWELL 43 | CPU_SUPPORTED_BY_HB=false 44 | ;; 45 | # QSV Version 5 46 | INTEL_SKL) ;; # SKYLAKE 47 | INTEL_ATOM_GMT) ;; # GOLDMONT 48 | INTEL_ATOM_GMT_PLUS) ;; # GOLDMONT+ 49 | # QSV Version 6 50 | INTEL_KBL) ;; # KABY LAKE 51 | INTEL_CFL) ;; # COFFEE LAKE 52 | INTEL_WHL) ;; # WHISKEY LAKE 53 | INTEL_CML) ;; # COMET LAKE 54 | # QSV Version 7 55 | INTEL_ICL) ;; # ICE LAKE 56 | # QSV Version 8 57 | INTEL_TGL) ;; # TIGER LAKE 58 | INTEL_RCL) ;; # ROCKET LAKE 59 | INTEL_ADL) ;; # ALDER LAKE 60 | INTEL_RPL) ;; # RAPTOR LAKE 61 | INTEL_ATOM_TMT) ;; # TREMONT 62 | # QSV Version 9 63 | # Only Intel ARC for now. 64 | # QSV not supported by the processor. 65 | *) 66 | CPU_QSV_CAPABLE=false 67 | ;; 68 | esac 69 | 70 | if [ ! -d "$DRI_DIR" ]; then 71 | echo "Intel Quick Sync Video not supported: device directory $DRI_DIR not exposed to the container." 72 | exit 0 73 | fi 74 | 75 | if [ -z "${DRI_DEV:-}" ]; then 76 | echo "Intel Quick Sync Video not supported: no Direct Rendering Manager (DRM) device found under $DRI_DIR." 77 | exit 0 78 | fi 79 | 80 | if ! lspci -k | grep -qw i915; then 81 | echo "Intel Quick Sync Video not supported: video adapter not using i915 driver." 82 | exit 0 83 | fi 84 | 85 | # Intel ARC is a discrete GPU that supports QSV. This means that QSV might be 86 | # usable even if CPU doesn't support it. 87 | if ! $CPU_QSV_CAPABLE; then 88 | echo "Intel Quick Sync Video may not be supported: processor not QSV capable." 89 | elif ! $CPU_SUPPORTED_BY_HB; then 90 | echo "Intel Quick Sync Video may not be supported: processor not supported by HandBrake." 91 | fi 92 | 93 | # Get group of devices under /dev/dri/. 94 | find /dev/dri/ -type c | while read DRI_DEV 95 | do 96 | G="$(stat -c "%g" "$DRI_DEV")" 97 | if [ "$G" -eq 0 ]; then 98 | # Device is owned by root. If the configured user doesn't have access 99 | # to it, then QSV won't work (setting the supplementary group to 0 100 | # doesn't work). 101 | if ! (su-exec "$USER_ID:$GROUP_ID" test -r "$DRI_DEV") || \ 102 | ! (su-exec "$USER_ID:$GROUP_ID" test -w "$DRI_DEV") 103 | then 104 | echo "Intel Quick Sync Video not supported: device $DRI_DEV owned" \ 105 | "by group 'root' and configured user doesn't have permissions" \ 106 | "to access it." 107 | break 108 | fi 109 | fi 110 | done 111 | 112 | # vim:ts=4:sw=4:et:sts=4 113 | -------------------------------------------------------------------------------- /rootfs/etc/cont-init.d/54-check-trash-dir.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Make sure the trash directory is properly mapped to the host. 4 | # 5 | 6 | set -e # Exit immediately if a command exits with a non-zero status. 7 | set -u # Treat unset variables as an error. 8 | 9 | if is-bool-val-true "${AUTOMATED_CONVERSION_USE_TRASH:-0}"; then 10 | if [ -f /trash/.not_mapped ]; then 11 | echo "ERROR: Trash usage is enabled, but trash directory not mapped to the host." 12 | exit 1 13 | fi 14 | 15 | set +e 16 | TMPFILE="$(su-exec "$USER_ID:$GROUP_ID" mktemp /trash/.test_XXXXXX)" 17 | RC=$? 18 | set -e 19 | if [ $RC -eq 0 ]; then 20 | # Success, we were able to write a file. 21 | su-exec "$USER_ID:$GROUP_ID" rm "$TMPFILE" 22 | else 23 | echo "ERROR: Trash usage is enabled, but no write permission on it." 24 | exit 1 25 | fi 26 | fi 27 | 28 | # vim:ts=4:sw=4:et:sts=4 29 | -------------------------------------------------------------------------------- /rootfs/etc/cont-init.d/55-handbrake.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e # Exit immediately if a command exits with a non-zero status. 4 | set -u # Treat unset variables as an error. 5 | 6 | # Generate machine id. 7 | if [ ! -f /config/machine-id ]; then 8 | echo "generating machine-id..." 9 | cat /proc/sys/kernel/random/uuid | tr -d '-' > /config/machine-id 10 | fi 11 | 12 | # Make sure mandatory directories exist. 13 | mkdir -p /config/ghb 14 | mkdir -p /config/hooks 15 | mkdir -p /config/log/hb 16 | ln -sf ghb /config/.ghb 17 | 18 | # Copy default configuration if needed. 19 | if [ ! -f /config/ghb/preferences.json ]; then 20 | cp /defaults/preferences.json /config/ghb/preferences.json 21 | fi 22 | 23 | # Copy example hooks if needed. 24 | for hook in pre_conversion.sh post_conversion.sh post_watch_folder_processing.sh 25 | do 26 | [ ! -f /config/hooks/$hook ] || continue 27 | [ ! -f /config/hooks/$hook.example ] || continue 28 | cp /defaults/hooks/$hook.example /config/hooks/ 29 | done 30 | 31 | # Make sure the debug log is under the proper directory. 32 | [ ! -f /config/handbrake.debug.log ] || mv /config/handbrake.debug.log /config/log/hb/handbrake.debug.log 33 | 34 | # Clear the fstab file to make sure its content is not displayed in HandBrake 35 | # when opening the source video. 36 | echo > /etc/fstab 37 | 38 | # Print the core dump info. 39 | echo "core dump file location: $(cat /proc/sys/kernel/core_pattern)" 40 | echo "core dump file size: $(ulimit -a | grep "core file size" | awk '{print $NF}') (blocks)" 41 | 42 | # Take ownership of the output directory. 43 | for i in $(seq 1 ${AUTOMATED_CONVERSION_MAX_WATCH_FOLDERS:-5}); do 44 | eval "DIR=\"\${AUTOMATED_CONVERSION_OUTPUT_DIR_$i:-/output}\"" 45 | 46 | if [ ! -d "$DIR" ]; then 47 | log "ERROR: Output folder '$DIR' doesn't exist." 48 | exit 1 49 | fi 50 | take-ownership --not-recursive "$DIR" 51 | done 52 | 53 | # vim:ts=4:sw=4:et:sts=4 54 | -------------------------------------------------------------------------------- /rootfs/etc/ld-musl-x86_64.path: -------------------------------------------------------------------------------- 1 | /lib 2 | /usr/lib 3 | /usr/local/lib 4 | /opt/intel/mediasdk/lib64 5 | -------------------------------------------------------------------------------- /rootfs/etc/machine-id: -------------------------------------------------------------------------------- 1 | /config/machine-id -------------------------------------------------------------------------------- /rootfs/etc/openbox/main-window-selection.xml: -------------------------------------------------------------------------------- 1 | normal 2 | HandBrake 3 | -------------------------------------------------------------------------------- /rootfs/etc/services.d/app/disabled: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e # Exit immediately if a command exits with a non-zero status. 4 | set -u # Treat unset variables as an error. 5 | 6 | if is-bool-val-true "${HANDBRAKE_GUI:-1}"; then 7 | echo "false" 8 | else 9 | echo "true" 10 | fi 11 | 12 | # vim:ft=sh:ts=4:sw=4:et:sts=4 13 | -------------------------------------------------------------------------------- /rootfs/etc/services.d/autovideoconverter/disabled: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e # Exit immediately if a command exits with a non-zero status. 4 | set -u # Treat unset variables as an error. 5 | 6 | if is-bool-val-true "${AUTOMATED_CONVERSION:-1}"; then 7 | echo "false" 8 | else 9 | echo "true" 10 | fi 11 | 12 | # vim:ft=sh:ts=4:sw=4:et:sts=4 13 | -------------------------------------------------------------------------------- /rootfs/etc/services.d/autovideoconverter/priority: -------------------------------------------------------------------------------- 1 | /defaults/service/priority -------------------------------------------------------------------------------- /rootfs/etc/services.d/autovideoconverter/respawn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlesage/docker-handbrake/61f9f72f8392d95c10f56f0401fa836e057d1657/rootfs/etc/services.d/autovideoconverter/respawn -------------------------------------------------------------------------------- /rootfs/etc/services.d/autovideoconverter/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -u # Treat unset variables as an error. 4 | 5 | FAILED_CONVERSIONS="/config/failed_conversions" 6 | SUCCESSFUL_CONVERSIONS="/config/successful_conversions" 7 | 8 | HANDBRAKE_CLI="/usr/bin/HandBrakeCLI --preset-import-file /config/ghb/presets.json" 9 | 10 | # https://gist.github.com/aaomidi/0a3b5c9bd563c9e012518b495410dc0e 11 | VIDEO_FILE_EXTENSIONS_INTERNAL_LIST="\ 12 | webm mkv flv vob ogv ogg rrc gifv mng mov avi qt wmv yuv rm asf amv mp4 \ 13 | m4p m4v mpg mp2 mpeg mpe mpv m4v svi 3gp 3g2 mxf roq nsv flv f4v f4p f4a \ 14 | f4b mod" 15 | 16 | if [ "${HANDBRAKE_DEBUG:-0}" -eq 1 ]; then 17 | HANDBRAKE_CLI="$HANDBRAKE_CLI --verbose=3" 18 | fi 19 | 20 | # QSV decoding can crash with x264 8-bit files. 21 | # https://github.com/jlesage/docker-handbrake/issues/347 22 | if HandBrakeCLI --help 2>/dev/null | grep -q disable-qsv-decoding 23 | then 24 | HANDBRAKE_CLI="$HANDBRAKE_CLI --disable-qsv-decoding" 25 | fi 26 | 27 | WATCHDIR_HASH="$(mktemp -d)" 28 | 29 | OUTPUT_DIR_TMP="" 30 | 31 | clean_exit() { 32 | rm -rf "$WATCHDIR_HASH" 33 | killall HandBrakeCLI 2>/dev/null 34 | killall yad 2>/dev/null 35 | if [ -n "${OUTPUT_DIR_TMP:-}" ]; then 36 | rm -rf "$OUTPUT_DIR_TMP" 37 | fi 38 | } 39 | trap "clean_exit" EXIT 40 | 41 | log() { 42 | echo "$*" 43 | } 44 | 45 | log_hb_encode_progress() { 46 | while read OUTPUT; do 47 | echo "Encoding $video: $OUTPUT" 48 | done | awk 'NR % 12 == 0' 49 | } 50 | 51 | log_hb_encode_progress_yad() { 52 | # Ignore the output if GUI progress or HandBrake GUI are disabled. 53 | if is-bool-val-true "$AC_NO_GUI_PROGRESS" || is-bool-val-false "${HANDBRAKE_GUI:-1}" 54 | then 55 | while read OUTPUT; do 56 | # Do nothing with the output. 57 | : 58 | done 59 | return 60 | fi 61 | 62 | ( 63 | while read OUTPUT; do 64 | # This control the progress bar. 65 | echo "$OUTPUT" | cut -d',' -f2- | cut -d' ' -f2 2>/dev/null 66 | # This put the text inside the progress bar. 67 | echo "# $OUTPUT" 2>/dev/null 68 | done 69 | ) | /opt/base/bin/yad \ 70 | --fixed \ 71 | --width=384 \ 72 | --posx=$(expr $DISPLAY_WIDTH / 2 - 384 / 2) \ 73 | --posy=5 \ 74 | --title "Automatic Video Converter" \ 75 | --window-icon /opt/novnc/images/icons/master_icon.png \ 76 | --borders 10 \ 77 | --text "Encoding $(echo "$video" | sed 's/&/&/g')..." \ 78 | --no-buttons \ 79 | --progress \ 80 | 2>/dev/null 81 | } 82 | 83 | WATCHDIR_HASH_calculate() { 84 | WATCHDIR="$1" 85 | find "$WATCHDIR" -follow -type f -not -path '*/\.*' -printf '%T@:%s:%p:%m\n' | md5sum | cut -d' ' -f1 86 | } 87 | 88 | WATCHDIR_HASH_isset() { 89 | WATCHDIR="$1" 90 | [ -f "$WATCHDIR_HASH/$WATCHDIR/hash" ] 91 | } 92 | 93 | WATCHDIR_HASH_update() { 94 | WATCHDIR="$1" 95 | mkdir -p "$WATCHDIR_HASH/$WATCHDIR" 96 | WATCHDIR_HASH_calculate "$WATCHDIR" > "$WATCHDIR_HASH/$WATCHDIR/hash" 97 | } 98 | 99 | WATCHDIR_HASH_changed() { 100 | WATCHDIR="$1" 101 | [ ! -f "$WATCHDIR_HASH/$WATCHDIR/hash" ] || \ 102 | [ "$(cat "$WATCHDIR_HASH/$WATCHDIR/hash")" != "$(WATCHDIR_HASH_calculate "$WATCHDIR")" ] 103 | } 104 | 105 | get_video_hash() { 106 | video="$1" 107 | if [ -f "$video" ]; then 108 | stat -c '%n %s %Y' "$video" | md5sum | cut -d' ' -f1 109 | else 110 | find "$video" -type f -exec stat -c '%n %s %Y' {} \; | md5sum | cut -d' ' -f1 111 | fi 112 | } 113 | 114 | get_video_titles() { 115 | video="$1" 116 | 117 | $HANDBRAKE_CLI -i "$video" \ 118 | -t0 \ 119 | --min-duration $AC_SOURCE_MIN_DURATION 2>&1 | 120 | grep "^+ title " | sed 's/^+ title \([0-9]\+\):$/\1/' 121 | return ${PIPESTATUS[0]} 122 | } 123 | 124 | process_video() { 125 | video="$1" 126 | wf="$2" 127 | 128 | # Skip video if it doesn't exists (may have been removed while processing 129 | # the watch directory). 130 | if [ ! -f "$video" ] && [ ! -d "$video" ]; then 131 | log "Skipping '$video': no longer exists." 132 | return 133 | fi 134 | 135 | # Get hash of the video from its properties. 136 | hash="$(get_video_hash "$video")" 137 | 138 | # Skip video if it has been already successfully processed. 139 | if [ -f "$SUCCESSFUL_CONVERSIONS" ] && grep -q -w "$hash" "$SUCCESSFUL_CONVERSIONS"; then 140 | log "Skipping video '$video' ($hash): already processed successfully." 141 | return 142 | fi 143 | 144 | # Skip video if we already failed to process it. 145 | if [ -f "$FAILED_CONVERSIONS" ] && grep -q -w "$hash" "$FAILED_CONVERSIONS"; then 146 | log "Skipping '$video' ($hash): already processed with failure." 147 | return 148 | fi 149 | 150 | # Skip video if it is not stable. 151 | log "Waiting $AC_SOURCE_STABLE_TIME seconds before processing '$video'..." 152 | sleep $AC_SOURCE_STABLE_TIME 153 | if [ "$hash" != "$(get_video_hash "$video")" ]; then 154 | log "Skipping '$video': currently being copied." 155 | return 156 | fi 157 | 158 | # Skip video if it is not readable. 159 | if [ ! -r "$video" ]; then 160 | log "Skipping '$video': not readable, check permissions." 161 | return 162 | fi 163 | 164 | # Set the output directory. 165 | case "$AC_OUTPUT_SUBDIR" in 166 | UNSET) 167 | OUTPUT_DIR="$AC_OUTPUT_DIR" 168 | ;; 169 | SAME_AS_SRC) 170 | dirname="$(dirname "$video" | sed "s|^$wf||")" 171 | OUTPUT_DIR="$AC_OUTPUT_DIR/$dirname" 172 | ;; 173 | *) 174 | OUTPUT_DIR="$AC_OUTPUT_DIR/$AC_OUTPUT_SUBDIR" 175 | ;; 176 | esac 177 | OUTPUT_DIR="$(echo "$OUTPUT_DIR" | sed 's|/\+|/|g' | sed 's|/\+$||')" 178 | 179 | # Get the file extension. 180 | VIDEO_FILE_EXT="${video##*.}" 181 | 182 | # Determine if the extension is in the list of video file extensions. 183 | if echo "$AC_VIDEO_FILE_EXTENSIONS" | grep -iwq "$VIDEO_FILE_EXT"; then 184 | FILE_EXT_IN_VIDEO_LIST=true 185 | else 186 | FILE_EXT_IN_VIDEO_LIST=false 187 | fi 188 | 189 | # Determine if the extension is in the list of non-video file extensions. 190 | if echo "$AC_NON_VIDEO_FILE_EXTENSIONS" | grep -iwq "$VIDEO_FILE_EXT"; then 191 | FILE_EXT_IN_NON_VIDEO_LIST=true 192 | else 193 | FILE_EXT_IN_NON_VIDEO_LIST=false 194 | fi 195 | 196 | # Get video titles. 197 | if $FILE_EXT_IN_VIDEO_LIST && $FILE_EXT_IN_NON_VIDEO_LIST; then 198 | log "ERROR: File '${video}' (${hash}) has an extension defined as both a video and non-video file." 199 | return 200 | elif [ -n "$AC_VIDEO_FILE_EXTENSIONS" ] && ! $FILE_EXT_IN_VIDEO_LIST; then 201 | log "File '${video}' (${hash}) has an extension not part of the inclusion list." 202 | VIDEO_TITLES=UNSET 203 | VIDEO_TITLES_RETVAL=1 204 | elif $FILE_EXT_IN_NON_VIDEO_LIST; then 205 | log "File '${video}' (${hash}) has an extension part of the exclusion list." 206 | VIDEO_TITLES=UNSET 207 | VIDEO_TITLES_RETVAL=1 208 | else 209 | # Let Handbrake detects if the file is a video or not. 210 | VIDEO_TITLES="$(get_video_titles "$video")" 211 | VIDEO_TITLES_RETVAL=$? 212 | if [ "$VIDEO_TITLES_RETVAL" -ne 0 ]; then 213 | # File is not a video. 214 | VIDEO_TITLES=UNSET 215 | 216 | if $FILE_EXT_IN_VIDEO_LIST; then 217 | # The file extension is part of the video file extension list. 218 | # Make sure to fail the conversion and not consider the file 219 | # as a non-video. 220 | VIDEO_TITLES_RETVAL=0 221 | elif echo "$VIDEO_FILE_EXTENSIONS_INTERNAL_LIST" | grep -iwq "$VIDEO_FILE_EXT"; then 222 | # The file extension is part of our internal list. Make sure to 223 | # fail the conversion and not consider the file as a non-video. 224 | # This is a protection against Handbrake not correctly detecting 225 | # a video because of a bug, crash, missing support, etc. 226 | VIDEO_TITLES_RETVAL=0 227 | fi 228 | fi 229 | fi 230 | 231 | hb_rc=0 232 | 233 | VIDEO_TITLES="${VIDEO_TITLES:-UNSET}" 234 | if [ "$VIDEO_TITLES" != "UNSET" ]; then 235 | NUM_VIDEO_TITLES="$(echo "$VIDEO_TITLES" | wc -l)" 236 | else 237 | NUM_VIDEO_TITLES="0" 238 | fi 239 | 240 | if [ "$VIDEO_TITLES_RETVAL" -gt 0 ] && [ "$AC_NON_VIDEO_FILE_ACTION" = "copy" ]; then 241 | log "File '$video' ($hash) is not a video, copying (unchanged) to output..." 242 | mkdir -p "$OUTPUT_DIR" 243 | cp -p "${video}" "${OUTPUT_DIR}/$(basename "${video}")" # "-p" maintains permissions, times etc... 244 | elif [ "$VIDEO_TITLES_RETVAL" -gt 0 ]; then 245 | log "File '$video' ($hash) is not a video, ignoring..." 246 | elif [ "$NUM_VIDEO_TITLES" -eq 0 ]; then 247 | log "ERROR: Could not identify titles in '${video}' (${hash})." 248 | hb_rc=1 249 | else 250 | # If main title detection is enabled, force the number of titles to 1. 251 | if [ "$AC_SOURCE_MAIN_TITLE_DETECTION" != "0" ]; then 252 | NUM_VIDEO_TITLES="1" 253 | fi 254 | 255 | log "Starting conversion of '${video}' (${hash}) using preset '${AC_PRESET}'..." 256 | log "${NUM_VIDEO_TITLES} title(s) to process." 257 | fi 258 | 259 | CUR_VIDEO_TITLE=0 260 | 261 | for TITLE in $VIDEO_TITLES; do 262 | [ "$TITLE" != "UNSET" ] || continue 263 | 264 | CUR_VIDEO_TITLE="$(expr $CUR_VIDEO_TITLE + 1)" 265 | [ "$NUM_VIDEO_TITLES" -eq 1 ] || log "Processing title $TITLE ($CUR_VIDEO_TITLE/$NUM_VIDEO_TITLES)..." 266 | 267 | # Get the output file basename: start with the one of the input file. 268 | basename="$(basename "$video" | sed 's/\.[^.]*$//')" 269 | # If multiple titles, add the '.title-XX' suffix. 270 | [ "$NUM_VIDEO_TITLES" -eq 1 ] || basename="$basename.title-$TITLE" 271 | 272 | # Now set the final output filename by adding the extension. 273 | OUTPUT_FILE="$OUTPUT_DIR/$basename.$AC_FORMAT" 274 | 275 | # Call pre conversion hook. 276 | if [ -f /config/hooks/pre_conversion.sh ]; then 277 | log "Executing pre-conversion hook..." 278 | /bin/sh /config/hooks/pre_conversion.sh "$OUTPUT_FILE" "$video" "$AC_PRESET" 279 | log "Pre-conversion hook exited with $?" 280 | fi 281 | 282 | # Skip video if it doesn't exists (may have been removed by the 283 | # pre-conversion hook). 284 | if [ ! -f "$video" ] && [ ! -d "$video" ]; then 285 | log "Skipping '$video': no longer exists." 286 | continue 287 | fi 288 | 289 | # Check whether destination already exists 290 | if [ -f "$OUTPUT_FILE" ] && is-bool-val-false "$AC_OVERWRITE_OUTPUT"; then 291 | hb_rc=1 292 | log "ERROR: Destination file '$OUTPUT_FILE' already exists." 293 | break 294 | elif [ -f "$OUTPUT_FILE" ] && [ "$AC_OVERWRITE_OUTPUT" == "1" ]; then 295 | log "WARNING: Overwriting '$OUTPUT_FILE'" 296 | fi 297 | 298 | # Set the temporary output directory: this is where the video will be 299 | # actually written before being moved its final location once conversion is 300 | # terminated. 301 | OUTPUT_DIR_TMP="$(mktemp -d "$AC_OUTPUT_DIR/.XXXXXX")" 302 | if [ ! -d "$OUTPUT_DIR_TMP" ]; then 303 | hb_rc=1 304 | log "ERROR: Failed to create temporary directory under '$AC_OUTPUT_DIR'." 305 | break 306 | fi 307 | 308 | # Set the temporary output filename. 309 | OUTPUT_FILE_TMP="$OUTPUT_DIR_TMP/$basename.$AC_FORMAT" 310 | 311 | TITLE_ARG="" 312 | if [ "$AC_SOURCE_MAIN_TITLE_DETECTION" == "0" ]; then 313 | TITLE_ARG="--title $TITLE" 314 | else 315 | TITLE_ARG="--main-feature" 316 | fi 317 | 318 | # Invoke HandBrake. 319 | echo "------- CONVERSION OUTPUT $(date) -------" >> \ 320 | /config/log/hb/conversion.log 321 | $HANDBRAKE_CLI -i "$video" \ 322 | -o "$OUTPUT_FILE_TMP" \ 323 | $TITLE_ARG \ 324 | --preset "$AC_PRESET" \ 325 | $AC_HANDBRAKE_CUSTOM_ARGS 2>> \ 326 | /config/log/hb/conversion.log | \ 327 | /usr/bin/unbuffer -p grep "^Encoding" | \ 328 | stdbuf -oL cut -d' ' -f2- | \ 329 | tee >(log_hb_encode_progress) >(log_hb_encode_progress_yad) > /dev/null 330 | hb_rc=$? 331 | 332 | # Close YAD window. 333 | killall -SIGUSR1 yad 2> /dev/null 334 | 335 | # Make sure the output file has been generated. 336 | if [ $hb_rc -eq 0 ] && [ ! -f "$OUTPUT_FILE_TMP" ]; then 337 | hb_rc=1 338 | fi 339 | 340 | # Move the file to its final location if conversion terminated 341 | # successfully. 342 | if [ $hb_rc -eq 0 ]; then 343 | mkdir -p "$OUTPUT_DIR" 344 | mv -f "$OUTPUT_FILE_TMP" "$OUTPUT_FILE" 345 | fi 346 | rm -rf "$OUTPUT_DIR_TMP" 347 | OUTPUT_DIR_TMP="" 348 | 349 | # Call post conversion hook. 350 | if [ -f /config/hooks/post_conversion.sh ]; then 351 | log "Executing post-conversion hook..." 352 | /bin/sh /config/hooks/post_conversion.sh $hb_rc "$OUTPUT_FILE" "$video" "$AC_PRESET" 353 | log "Post-conversion hook exited with $?" 354 | fi 355 | 356 | [ $hb_rc -eq 0 ] || break 357 | done 358 | 359 | NUM_PROCESSED_FILES="$(expr $NUM_PROCESSED_FILES + 1)" 360 | 361 | if [ $hb_rc -eq 0 ]; then 362 | log "Conversion ended successfully." 363 | echo "$video $hash" >> "$SUCCESSFUL_CONVERSIONS" 364 | if is-bool-val-false "$AC_KEEP_SOURCE"; then 365 | if is-bool-val-false "${AUTOMATED_CONVERSION_USE_TRASH:-0}"; then 366 | log "Removing '$video'..." 367 | rm -rf "$video" 368 | if [ $? -eq 0 ]; then 369 | log "Removed '$video'." 370 | else 371 | log "ERROR: Could not remove '$video'." 372 | fi 373 | else 374 | VIDEO_TRASH_PATH="/trash/${video#"$wf"}" 375 | mkdir -p "$(dirname "$VIDEO_TRASH_PATH")" 376 | log "Moving '$video' to trash directory..." 377 | mv "$video" "$VIDEO_TRASH_PATH" 378 | if [ $? -eq 0 ]; then 379 | log "Moved '$video' to trash directory." 380 | else 381 | log "ERROR: Could not move '$video' to trash directory." 382 | fi 383 | fi 384 | # Remove directory if empty (hidden files/folders are ignored). 385 | videodir="$(dirname "$video")" 386 | while [ "$videodir" != "$wf" ] && [ -z "$(ls "$videodir")" ]; do 387 | rm -rf "$videodir" 388 | if [ $? -eq 0 ]; then 389 | log "Removed directory '$videodir'." 390 | else 391 | log "ERROR: Could not remove directory '$videodir'." 392 | fi 393 | videodir="$(dirname "$videodir")" 394 | done 395 | fi 396 | else 397 | log "Conversion failed." 398 | log "For more details about the failure, see /config/log/hb/conversion.log." 399 | if ! echo "$AC_PRESET" | grep -q "/"; then 400 | log "NOTE: The configured preset doesn't seem to include its category. A preset must" 401 | log " must now be identified using the following format: '/'." 402 | log " This may be the cause of the current failure." 403 | fi 404 | echo "$video $hash" >> "$FAILED_CONVERSIONS" 405 | fi 406 | } 407 | 408 | process_watch_folder() { 409 | WF="$1" 410 | 411 | NUM_PROCESSED_FILES=0 412 | 413 | [ -d "$WF" ] || return 414 | WATCHDIR_HASH_changed "$WF" || return 415 | 416 | # Make sure the output directory is properly setup. 417 | if [ ! -d "$AC_OUTPUT_DIR" ]; then 418 | log "ERROR: Cannot process watch folder '$WF', because the associated output directory '$AC_OUTPUT_DIR' doesn't exist." 419 | return 420 | else 421 | TMPFILE="$(mktemp "$AC_OUTPUT_DIR"/.test_XXXXXX 2>/dev/null)" 422 | RC=$? 423 | if [ "$RC" -eq 0 ]; then 424 | rm "$TMPFILE" 425 | else 426 | log "ERROR: Cannot process watch folder '$WF', because the associated output directory '$AC_OUTPUT_DIR' is not writable." 427 | return 428 | fi 429 | fi 430 | 431 | if WATCHDIR_HASH_isset "$WF"; then 432 | log "Change detected in watch folder '$WF'." 433 | fi 434 | 435 | # Make sure to update the watch directory hash before processing it. 436 | # This is to make sure we catch, on the next round, changes occuring 437 | # during the processing. 438 | WATCHDIR_HASH_update "$WF" 439 | 440 | log "Processing watch folder '$WF'..." 441 | FILELIST1="$(mktemp)" 442 | FILELIST2="$(mktemp)" 443 | 444 | # First, get the list of files in the watch folder, filtering all files 445 | # files under VIDEO_TS or BDMV and keeping only their parent directory. 446 | find "$WF" -follow -type f -not -path '*/\.*' -printf "%T@ %p\n" | \ 447 | sort -n | \ 448 | cut -d' ' -f2- | \ 449 | sed 's|/\([^/]*\)/VIDEO_TS/.*$|/\1|g' | \ 450 | sed 's|/\([^/]*\)/BDMV/.*$|/\1|g' | \ 451 | uniq > "$FILELIST1" 452 | cp "$FILELIST1" "$FILELIST2" 453 | 454 | # Then, remove all files under directories part of the list. The 455 | # directories from the list are video discs and their individual files 456 | # should not be processed. 457 | while read -u 3 FILE 458 | do 459 | if [ -d "$FILE" ]; then 460 | sed -i "s|$FILE/.*|$FILE|g" "$FILELIST2" 461 | fi 462 | done 3<"$FILELIST1" 463 | cat "$FILELIST2" | uniq > "$FILELIST1" 464 | 465 | # Warn user if video disc folder structure is found at the root of the watch 466 | # folder. 467 | for DIR in "$WF/VIDEO_TS" "$WF/BDMV" 468 | do 469 | if [ -d "$DIR" ]; then 470 | log "Skipping '$DIR': video disc folder structure should not be placed at the root of the watch folder." 471 | fi 472 | done 473 | 474 | # Process videos files. 475 | while read -u 3 FILE 476 | do 477 | if [ "$FILE" = "$WF" ]; then 478 | continue 479 | fi 480 | process_video "$FILE" "$WF" 481 | done 3<"$FILELIST1" 482 | rm "$FILELIST1" 483 | rm "$FILELIST2" 484 | log "Watch folder '$WF' processing terminated." 485 | 486 | # Call watch folder done hook. 487 | if [ -f /config/hooks/post_watch_folder_processing.sh ] && [ "$NUM_PROCESSED_FILES" -gt 0 ]; then 488 | log "Executing post watch folder processing hook..." 489 | /bin/sh /config/hooks/post_watch_folder_processing.sh "$WF" 490 | log "Post watch folder processing hook exited with $?" 491 | fi 492 | } 493 | 494 | [ -f "$FAILED_CONVERSIONS" ] || touch "$FAILED_CONVERSIONS" 495 | [ -f "$SUCCESSFUL_CONVERSIONS" ] || touch "$SUCCESSFUL_CONVERSIONS" 496 | 497 | while true; do 498 | for i in $(seq 1 ${AUTOMATED_CONVERSION_MAX_WATCH_FOLDERS:-5}); do 499 | DIR="/watch$i" 500 | if [ "$i" -eq 1 ]; then 501 | DIR="/watch" 502 | fi 503 | 504 | # Set default settings. 505 | AC_PRESET="${AUTOMATED_CONVERSION_PRESET:-Very Fast 1080p30}" 506 | AC_FORMAT="${AUTOMATED_CONVERSION_FORMAT:-mp4}" 507 | AC_SOURCE_STABLE_TIME="${AUTOMATED_CONVERSION_SOURCE_STABLE_TIME:-5}" 508 | AC_SOURCE_MIN_DURATION="${AUTOMATED_CONVERSION_SOURCE_MIN_DURATION:-10}" 509 | AC_SOURCE_MAIN_TITLE_DETECTION="${AUTOMATED_CONVERSION_SOURCE_MAIN_TITLE_DETECTION:-0}" 510 | AC_OUTPUT_DIR="${AUTOMATED_CONVERSION_OUTPUT_DIR:-/output}" 511 | AC_OUTPUT_SUBDIR="${AUTOMATED_CONVERSION_OUTPUT_SUBDIR:-UNSET}" 512 | AC_KEEP_SOURCE="${AUTOMATED_CONVERSION_KEEP_SOURCE:-1}" 513 | AC_VIDEO_FILE_EXTENSIONS="${AUTOMATED_CONVERSION_VIDEO_FILE_EXTENSIONS:-}" 514 | AC_NON_VIDEO_FILE_ACTION="${AUTOMATED_CONVERSION_NON_VIDEO_FILE_ACTION:-ignore}" 515 | AC_NON_VIDEO_FILE_EXTENSIONS="${AUTOMATED_CONVERSION_NON_VIDEO_FILE_EXTENSIONS:-jpg jpeg bmp png gif txt nfo}" 516 | AC_NO_GUI_PROGRESS="${AUTOMATED_CONVERSION_NO_GUI_PROGRESS:-0}" 517 | AC_HANDBRAKE_CUSTOM_ARGS="${AUTOMATED_CONVERSION_HANDBRAKE_CUSTOM_ARGS:-}" 518 | AC_OVERWRITE_OUTPUT="${AUTOMATED_CONVERSION_OVERWRITE_OUTPUT:-0}" 519 | 520 | # Apply per-watch folder settings. 521 | if [ -n "${DIR#*/watch}" ]; then 522 | for VAR in PRESET FORMAT SOURCE_STABLE_TIME SOURCE_MIN_DURATION SOURCE_MAIN_TITLE_DETECTION OUTPUT_DIR OUTPUT_SUBDIR KEEP_SOURCE VIDEO_FILE_EXTENSIONS NON_VIDEO_FILE_ACTION NON_VIDEO_FILE_EXTENSIONS NO_GUI_PROGRESS HANDBRAKE_CUSTOM_ARGS OVERWRITE_OUTPUT 523 | do 524 | eval "AC_$VAR=\"\${AUTOMATED_CONVERSION_${VAR}_${DIR#*/watch}:-\$AC_$VAR}\"" 525 | done 526 | fi 527 | 528 | # Process watch folder. 529 | process_watch_folder "$DIR" 530 | done 531 | 532 | sleep "${AUTOMATED_CONVERSION_CHECK_INTERVAL:-5}" 533 | done 534 | 535 | # vim:ft=sh:ts=4:sw=4:et:sts=4 536 | -------------------------------------------------------------------------------- /rootfs/etc/services.d/autovideoconverter/sgid: -------------------------------------------------------------------------------- 1 | /defaults/service/sgid -------------------------------------------------------------------------------- /rootfs/etc/services.d/autovideoconverter/umask: -------------------------------------------------------------------------------- 1 | /defaults/service/umask -------------------------------------------------------------------------------- /rootfs/etc/services.d/default/autovideoconverter.dep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlesage/docker-handbrake/61f9f72f8392d95c10f56f0401fa836e057d1657/rootfs/etc/services.d/default/autovideoconverter.dep -------------------------------------------------------------------------------- /rootfs/startapp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export HOME=/config 4 | export GTK_A11Y=none 5 | export LIBGL_ALWAYS_SOFTWARE=true 6 | 7 | COMMON_ARGS="--config /config" 8 | 9 | case "$(echo "${HANDBRAKE_GUI_QUEUE_STARTUP_ACTION:-NONE}" | tr '[:upper:]' '[:lower:]')" in 10 | process) COMMON_ARGS="$COMMON_ARGS --auto-start-queue" ;; 11 | clear) COMMON_ARGS="$COMMON_ARGS --clear-queue" ;; 12 | esac 13 | 14 | cd /storage 15 | if [ "${HANDBRAKE_DEBUG:-0}" -eq 1 ]; then 16 | exec /usr/bin/ghb $COMMON_ARGS --debug >> /config/log/hb/handbrake.debug.log 17 | else 18 | exec /usr/bin/ghb $COMMON_ARGS 19 | fi 20 | 21 | # vim:ft=sh:ts=4:sw=4:et:sts=4 22 | -------------------------------------------------------------------------------- /rootfs/trash/.not_mapped: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlesage/docker-handbrake/61f9f72f8392d95c10f56f0401fa836e057d1657/rootfs/trash/.not_mapped -------------------------------------------------------------------------------- /src/cpu_features/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e # Exit immediately if a command exits with a non-zero status. 4 | set -u # Treat unset variables as an error. 5 | 6 | # Set same default compilation flags as abuild. 7 | export CFLAGS="-fomit-frame-pointer" 8 | export CXXFLAGS="$CFLAGS" 9 | export CPPFLAGS="$CFLAGS" 10 | export LDFLAGS="-Wl,--strip-all -Wl,--as-needed" 11 | 12 | export CC=xx-clang 13 | export CXX=xx-clang++ 14 | 15 | SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" 16 | 17 | function log { 18 | echo ">>> $*" 19 | } 20 | 21 | CPU_FEATURES_URL="${1:-}" 22 | 23 | if [ -z "$CPU_FEATURES_URL" ]; then 24 | log "ERROR: URL missing." 25 | exit 1 26 | fi 27 | 28 | # 29 | # Install required packages. 30 | # 31 | apk --no-cache add \ 32 | curl \ 33 | clang17 \ 34 | make \ 35 | cmake \ 36 | 37 | # binutils \ 38 | # git \ 39 | # llvm15 \ 40 | # pkgconf \ 41 | # autoconf \ 42 | # automake \ 43 | # libtool \ 44 | # yasm \ 45 | # m4 \ 46 | # patch \ 47 | # coreutils \ 48 | # tar \ 49 | # file \ 50 | # pythonispython3 \ 51 | # intltool \ 52 | # diffutils \ 53 | # bash \ 54 | # nasm \ 55 | # meson \ 56 | # cargo \ 57 | # cargo-c \ 58 | # gettext-dev \ 59 | # glib-dev \ 60 | 61 | xx-apk --no-cache --no-scripts add \ 62 | musl-dev \ 63 | gcc \ 64 | 65 | # g++ \ 66 | # linux-headers \ 67 | 68 | # 69 | # Download sources. 70 | # 71 | 72 | #log "Downloading x264 sources..." 73 | #mkdir /tmp/x264 74 | #curl -# -L -f ${X264_URL} | tar xz --strip 1 -C /tmp/x264 75 | 76 | log "Downloading cpu_features sources..." 77 | mkdir /tmp/cpu_features 78 | curl -# -L -f ${CPU_FEATURES_URL} | tar xz --strip 1 -C /tmp/cpu_features 79 | 80 | # 81 | # Compile cpu_features. 82 | # 83 | 84 | log "Configuring cpu_features..." 85 | ( 86 | mkdir /tmp/cpu_features/build && \ 87 | cd /tmp/cpu_features/build && cmake \ 88 | $(xx-clang --print-cmake-defines) \ 89 | -DCMAKE_FIND_ROOT_PATH=$(xx-info sysroot) \ 90 | -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \ 91 | -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ 92 | -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY \ 93 | -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \ 94 | -DCMAKE_INSTALL_PREFIX=/tmp/cpu_features-install \ 95 | -DCMAKE_BUILD_TYPE=Release \ 96 | -DBUILD_TESTING=OFF \ 97 | -DENABLE_INSTALL=ON \ 98 | -DBUILD_SHARED_LIBS=OFF \ 99 | -DBUILD_EXECUTABLE=ON \ 100 | ../ 101 | ) 102 | 103 | log "Compiling cpu_features..." 104 | make -C /tmp/cpu_features/build -j$(nproc) 105 | 106 | log "Installing cpu_features..." 107 | make -C /tmp/cpu_features/build install 108 | -------------------------------------------------------------------------------- /src/handbrake/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Script to build HandBrake. 4 | # 5 | # Support for QSV requires multiple components: 6 | # 7 | # - libva: implementation for VA-API (Video Acceleration API), an open-source 8 | # library and API specification, which provides access to graphics hardware 9 | # acceleration capabilities for video processing. It consists of a main 10 | # library and driver-specific acceleration backends for each supported 11 | # hardware vendor (aka drivers for libva). 12 | # 13 | # - Intel VAAPI driver 14 | # - Driver for libva. 15 | # - Used for older Intel generation CPUs. 16 | # - Provides `i965_drv_video.so` (under `/usr/lib/dri/`). 17 | # 18 | # - Intel Media Driver 19 | # - Driver for libva. 20 | # - Used for newer Intel generation CPUs. 21 | # - Provides `iHD_drv_video.so` (under `/usr/lib/dri/`). 22 | # - Depends on gmmlib. 23 | # 24 | # - Intel Media SDK 25 | # - High level library that provides API to access hardware-accelerated video 26 | # decode, encode and filtering on Intel graphics hardware platforms. 27 | # - Discontinued. 28 | # - Depends on libva. 29 | # - Provides `libmfx.so`, the dispatcher used to select the runtime 30 | # implementation to use (`libmfxhw64.so` or `libmfx-gen.so) depending on the 31 | # CPU. 32 | # - It is not used by HandBrake. 33 | # - HandBrake has an embedded version of the oneVPL dispatcher (libvpl.so), 34 | # statically linked. 35 | # - Provides `libmfxhw64.so`, a runtime implementation for older Intel CPUs. 36 | # It also includes its plugins (under `/usr/lib/mfx/`): 37 | # - `plugins/libmfx_hevce_hw64.so` 38 | # - `plugins/libmfx_hevc_fei_hw64.so` 39 | # - `plugins/libmfx_vp9e_hw64.so` 40 | # - `plugins/libmfx_h264la_hw64.so` 41 | # - `plugins/libmfx_hevcd_hw64.so` 42 | # - `plugins/libmfx_hevcd_hw64.so` 43 | # - `plugins/libmfx_vp8d_hw64.so` 44 | # - `plugins/libmfx_vp9d_hw64.so` 45 | # 46 | # - libvpl 47 | # - Implementation of the Intel oneAPI Video Processing Library (oneVPL). 48 | # oneVPL is the new name of Intel Media SDK. It is the 2.x API continuation 49 | # of Intel Media SDK API. 50 | # - HandBrake has its embedded version of the oneVPL dispatcher (libvpl.so), 51 | # statically linked. 52 | # - The dispatcher supports runtime implementations from both the Media SDK 53 | # (`libmfxhw64.so`) and oneVPL (`libmfx-gen.so`). 54 | # - This library is not compiled by this script. 55 | # 56 | # - oneVPL GPU Runtime 57 | # - Provides `libmfx-gen.so` (under `/usr/lib/`), a runtime implementation 58 | # for latest Intel CPUs. 59 | # - Can be used by the Media SDK and oneVPL dispatchers. 60 | # - Successor of the Media SDK's runtime implementation. 61 | # 62 | # Some interesting links: 63 | # - https://trac.ffmpeg.org/wiki/Hardware/QuickSync 64 | # 65 | 66 | set -e # Exit immediately if a command exits with a non-zero status. 67 | set -u # Treat unset variables as an error. 68 | 69 | # Set same default compilation flags as abuild. 70 | export CFLAGS="-fomit-frame-pointer" 71 | export CXXFLAGS="$CFLAGS" 72 | export CPPFLAGS="$CFLAGS" 73 | export LDFLAGS="-Wl,--strip-all -Wl,--as-needed" 74 | 75 | export CC=xx-clang 76 | export CXX=xx-clang++ 77 | 78 | SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" 79 | 80 | function log { 81 | echo ">>> $*" 82 | } 83 | 84 | HANDBRAKE_VERSION="${1:-}" 85 | HANDBRAKE_URL="${2:-}" 86 | HANDBRAKE_DEBUG_MODE="${3:-}" 87 | LIBVA_URL="${4:-}" 88 | INTEL_VAAPI_DRIVER_URL="${5:-}" 89 | GMMLIB_URL="${6:-}" 90 | INTEL_MEDIA_DRIVER_URL="${7:-}" 91 | INTEL_MEDIA_SDK_URL="${8:-}" 92 | INTEL_ONEVPL_GPU_RUNTIME_URL="${9:-}" 93 | 94 | if [ -z "$HANDBRAKE_VERSION" ]; then 95 | log "ERROR: HandBrake version missing." 96 | exit 1 97 | fi 98 | 99 | if [ -z "$HANDBRAKE_URL" ]; then 100 | log "ERROR: HandBrake URL missing." 101 | exit 1 102 | fi 103 | 104 | if [ -z "$HANDBRAKE_DEBUG_MODE" ]; then 105 | log "ERROR: HandBrake debug mode missing." 106 | exit 1 107 | fi 108 | 109 | #if [ -z "$X264_URL" ]; then 110 | # log "ERROR: x264 URL missing." 111 | # exit 1 112 | #fi 113 | 114 | if [ -z "$LIBVA_URL" ]; then 115 | log "ERROR: libva URL missing." 116 | exit 1 117 | fi 118 | 119 | if [ -z "$INTEL_VAAPI_DRIVER_URL" ]; then 120 | log "ERROR: Intel VAAPI driver URL missing." 121 | exit 1 122 | fi 123 | 124 | if [ -z "$GMMLIB_URL" ]; then 125 | log "ERROR: gmmlib URL missing." 126 | exit 1 127 | fi 128 | 129 | if [ -z "$INTEL_MEDIA_DRIVER_URL" ]; then 130 | log "ERROR: Intel Media driver URL missing." 131 | exit 1 132 | fi 133 | 134 | if [ -z "$INTEL_MEDIA_SDK_URL" ]; then 135 | log "ERROR: Intel Media SDK URL missing." 136 | exit 1 137 | fi 138 | 139 | if [ -z "$INTEL_ONEVPL_GPU_RUNTIME_URL" ]; then 140 | log "ERROR: Intel OneVPL GPU Runtime URL missing." 141 | exit 1 142 | fi 143 | 144 | # 145 | # Install required packages. 146 | # 147 | apk --no-cache add \ 148 | curl \ 149 | binutils \ 150 | git \ 151 | clang17 \ 152 | llvm17 \ 153 | make \ 154 | cmake \ 155 | pkgconf \ 156 | autoconf \ 157 | automake \ 158 | libtool \ 159 | yasm \ 160 | m4 \ 161 | patch \ 162 | coreutils \ 163 | tar \ 164 | file \ 165 | pythonispython3 \ 166 | intltool \ 167 | diffutils \ 168 | bash \ 169 | nasm \ 170 | meson \ 171 | cargo-c \ 172 | gettext-dev \ 173 | glib-dev \ 174 | 175 | xx-apk --no-cache --no-scripts add \ 176 | musl-dev \ 177 | gcc \ 178 | g++ \ 179 | linux-headers \ 180 | 181 | # misc libraries 182 | xx-apk --no-cache --no-scripts add \ 183 | jansson-dev \ 184 | libxml2-dev \ 185 | libpciaccess-dev \ 186 | xz-dev \ 187 | numactl-dev \ 188 | libjpeg-turbo-dev \ 189 | 190 | # media libraries 191 | xx-apk --no-cache --no-scripts add \ 192 | libsamplerate-dev \ 193 | libass-dev \ 194 | 195 | # media codecs 196 | xx-apk --no-cache --no-scripts add \ 197 | x264-dev \ 198 | libtheora-dev \ 199 | lame-dev \ 200 | opus-dev \ 201 | libvorbis-dev \ 202 | speex-dev \ 203 | libvpx-dev \ 204 | 205 | # gtk 206 | xx-apk --no-cache --no-scripts add \ 207 | gtk4.0-dev \ 208 | dbus-glib-dev \ 209 | libnotify-dev \ 210 | libgudev-dev \ 211 | 212 | # Install Rust. 213 | USE_RUST_FROM_ALPINE_REPO=false 214 | if $USE_RUST_FROM_ALPINE_REPO; then 215 | apk --no-cache add \ 216 | cargo 217 | else 218 | apk --no-cache add \ 219 | gcc \ 220 | musl-dev 221 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y 222 | source /root/.cargo/env 223 | 224 | # NOTE: When not installing Rust from the Alpine repository, we must compile 225 | # with `RUSTFLAGS="-C target-feature=-crt-static"` to avoid crash 226 | # during GTK initialization. 227 | # See https://github.com/qarmin/czkawka/issues/416. 228 | export RUSTFLAGS="-C target-feature=-crt-static" 229 | fi 230 | 231 | # 232 | # Download sources. 233 | # 234 | 235 | #log "Downloading x264 sources..." 236 | #mkdir /tmp/x264 237 | #curl -# -L -f ${X264_URL} | tar xz --strip 1 -C /tmp/x264 238 | 239 | log "Downloading libva sources..." 240 | mkdir /tmp/libva 241 | curl -# -L -f ${LIBVA_URL} | tar xj --strip 1 -C /tmp/libva 242 | 243 | if [ "$(xx-info arch)" = "amd64" ]; then 244 | log "Downloading Intel VAAPI driver sources..." 245 | mkdir /tmp/intel-vaapi-driver 246 | curl -# -L -f ${INTEL_VAAPI_DRIVER_URL} | tar xj --strip 1 -C /tmp/intel-vaapi-driver 247 | 248 | log "Downloading gmmlib sources..." 249 | mkdir /tmp/gmmlib 250 | curl -# -L -f ${GMMLIB_URL} | tar xz --strip 1 -C /tmp/gmmlib 251 | 252 | log "Downloading Intel Media driver sources..." 253 | mkdir /tmp/intel-media-driver 254 | curl -# -L -f ${INTEL_MEDIA_DRIVER_URL} | tar xz --strip 1 -C /tmp/intel-media-driver 255 | 256 | log "Downloading Intel Media SDK sources..." 257 | mkdir /tmp/MediaSDK 258 | curl -# -L -f ${INTEL_MEDIA_SDK_URL} | tar xz --strip 1 -C /tmp/MediaSDK 259 | 260 | log "Downloading Intel OneVPL GPU Runtime sources..." 261 | mkdir /tmp/oneVPL-intel-gpu 262 | curl -# -L -f ${INTEL_ONEVPL_GPU_RUNTIME_URL} | tar xz --strip 1 -C /tmp/oneVPL-intel-gpu 263 | fi 264 | 265 | log "Downloading HandBrake sources..." 266 | if echo "${HANDBRAKE_URL}" | grep -q '\.git$'; then 267 | # Sources from git for nightly builds. 268 | git clone ${HANDBRAKE_URL} /tmp/handbrake 269 | # HANDBRAKE_VERSION is in the format "nightly--". 270 | git -C /tmp/handbrake checkout "$(echo "${HANDBRAKE_VERSION}" | cut -d'-' -f3)" 271 | else 272 | mkdir /tmp/handbrake 273 | curl -# -L -f ${HANDBRAKE_URL} | tar xj --strip 1 -C /tmp/handbrake 274 | fi 275 | 276 | # 277 | # Compile HandBrake. 278 | # 279 | 280 | if [ "${HANDBRAKE_DEBUG_MODE}" = "none" ]; then 281 | CMAKE_BUILD_TYPE=Release 282 | else 283 | CMAKE_BUILD_TYPE=Debug 284 | # Do not strip symbols. 285 | LDFLAGS= 286 | fi 287 | 288 | #log "Configuring x264..." 289 | #if [ "${HANDBRAKE_DEBUG_MODE}" = "none" ]; then 290 | # X264_CMAKE_OPTS=--enable-strip 291 | #else 292 | # X264_CMAKE_OPTS=--enable-debug 293 | #fi 294 | #( 295 | # cd /tmp/x264 && CFLAGS="${CFLAGS/-Os/}" ./configure \ 296 | # --build=$(TARGETPLATFORM= xx-clang --print-target-triple) \ 297 | # --host=$(xx-clang --print-target-triple) \ 298 | # --prefix=/usr \ 299 | # --enable-shared \ 300 | # --disable-static \ 301 | # --enable-pic \ 302 | # --disable-cli \ 303 | # --extra-cflags=-fno-aggressive-loop-optimizations \ 304 | # $X264_CMAKE_OPTS \ 305 | #) 306 | 307 | #log "Compiling x264..." 308 | #make -C /tmp/x264 -j$(nproc) 309 | # 310 | #log "Installing x264..." 311 | #make -C /tmp/x264 install 312 | 313 | log "Configuring libva..." 314 | ( 315 | cd /tmp/libva && ./configure \ 316 | --build=$(TARGETPLATFORM= xx-clang --print-target-triple) \ 317 | --host=$(xx-clang --print-target-triple) \ 318 | --prefix=/usr \ 319 | --localstatedir=/var \ 320 | --enable-x11 \ 321 | --disable-glx \ 322 | --disable-wayland \ 323 | --disable-static \ 324 | --enable-shared \ 325 | ) 326 | 327 | log "Compiling libva..." 328 | make -C /tmp/libva -j$(nproc) 329 | 330 | log "Installing libva..." 331 | make -C /tmp/libva install 332 | make DESTDIR=/tmp/handbrake-install -C /tmp/libva install 333 | 334 | if [ "$(xx-info arch)" = "amd64" ]; then 335 | log "Configuring Intel VAAPI driver..." 336 | ( 337 | cd /tmp/intel-vaapi-driver && ./configure \ 338 | --build=$(TARGETPLATFORM= xx-clang --print-target-triple) \ 339 | --host=$(xx-clang --print-target-triple) \ 340 | ) 341 | 342 | log "Compiling Intel VAAPI driver..." 343 | make -C /tmp/intel-vaapi-driver -j$(nproc) 344 | 345 | log "Installing Intel VAAPI driver..." 346 | make DESTDIR=/tmp/handbrake-install -C /tmp/intel-vaapi-driver install 347 | fi 348 | 349 | if [ "$(xx-info arch)" = "amd64" ]; then 350 | log "Patching Intel Media Driver..." 351 | patch -d /tmp/intel-media-driver -p1 < "$SCRIPT_DIR"/intel-media-driver-compile-fix.patch 352 | patch -d /tmp/gmmlib -p1 < "$SCRIPT_DIR"/gmmlib-compile-fix.patch 353 | rm -rf /tmp/intel-media-driver/media_driver/*/ult 354 | 355 | log "Configuring Intel Media driver..." 356 | ( 357 | mkdir /tmp/intel-media-driver/build && \ 358 | cd /tmp/intel-media-driver/build && cmake \ 359 | $(xx-clang --print-cmake-defines) \ 360 | -DCMAKE_FIND_ROOT_PATH=$(xx-info sysroot) \ 361 | -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \ 362 | -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ 363 | -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY \ 364 | -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \ 365 | -DCMAKE_INSTALL_PREFIX=/usr \ 366 | -DCMAKE_BUILD_TYPE=Release \ 367 | -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ 368 | -Wno-dev \ 369 | -DBUILD_TYPE=Release \ 370 | -DINSTALL_DRIVER_SYSCONF=OFF \ 371 | -DMEDIA_RUN_TEST_SUITE=OFF \ 372 | -DSKIP_GMM_CHECK=ON \ 373 | ../ 374 | ) 375 | 376 | log "Compiling Intel Media driver..." 377 | make VERBOSE=0 -C /tmp/intel-media-driver/build -j$(nproc) 378 | 379 | log "Installing Intel Media driver..." 380 | make DESTDIR=/tmp/handbrake-install -C /tmp/intel-media-driver/build install 381 | fi 382 | 383 | if [ "$(xx-info arch)" = "amd64" ]; then 384 | if [ "${HANDBRAKE_DEBUG_MODE}" = "none" ]; then 385 | INTEL_MEDIA_SDK_BUILD_TYPE=RELEASE 386 | else \ 387 | INTEL_MEDIA_SDK_BUILD_TYPE=DEBUG 388 | fi 389 | 390 | log "Patching Intel Media SDK..." 391 | patch -d /tmp/MediaSDK -p1 < "$SCRIPT_DIR"/intel-media-sdk-debug-no-assert.patch 392 | patch -d /tmp/MediaSDK -p1 < "$SCRIPT_DIR"/intel-media-sdk-compile-fix.patch 393 | 394 | log "Configuring Intel Media SDK..." 395 | ( 396 | mkdir /tmp/MediaSDK/build && \ 397 | cd /tmp/MediaSDK/build && cmake \ 398 | $(xx-clang --print-cmake-defines) \ 399 | -DCMAKE_FIND_ROOT_PATH=$(xx-info sysroot) \ 400 | -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \ 401 | -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ 402 | -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY \ 403 | -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \ 404 | -DCMAKE_INSTALL_PREFIX=/usr \ 405 | -DCMAKE_BUILD_TYPE=$INTEL_MEDIA_SDK_BUILD_TYPE \ 406 | -DENABLE_OPENCL=OFF \ 407 | -DENABLE_X11_DRI3=OFF \ 408 | -DENABLE_WAYLAND=OFF \ 409 | -DBUILD_DISPATCHER=ON \ 410 | -DENABLE_ITT=OFF \ 411 | -DENABLE_TEXTLOG=OFF \ 412 | -DENABLE_STAT=OFF \ 413 | -DBUILD_SAMPLES=OFF \ 414 | ../ 415 | ) 416 | 417 | log "Compiling Intel Media SDK..." 418 | make -C /tmp/MediaSDK/build -j$(nproc) 419 | 420 | log "Installing Intel Media SDK..." 421 | make DESTDIR=/tmp/handbrake-install -C /tmp/MediaSDK/build install 422 | fi 423 | 424 | if [ "$(xx-info arch)" = "amd64" ]; then 425 | log "Configuring Intel oneVPL GPU Runtime..." 426 | ( 427 | mkdir /tmp/oneVPL-intel-gpu/build && \ 428 | cd /tmp/oneVPL-intel-gpu/build && cmake \ 429 | $(xx-clang --print-cmake-defines) \ 430 | -DCMAKE_FIND_ROOT_PATH=$(xx-info sysroot) \ 431 | -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \ 432 | -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \ 433 | -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY \ 434 | -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \ 435 | -DCMAKE_BUILD_TYPE=Release \ 436 | -DCMAKE_INSTALL_PREFIX=/usr \ 437 | -DCMAKE_INSTALL_LIBDIR=lib \ 438 | ../ 439 | ) 440 | 441 | log "Compiling Intel oneVPL GPU Runtime..." 442 | make -C /tmp/oneVPL-intel-gpu/build -j$(nproc) 443 | 444 | log "Installing Intel oneVPL GPU Runtime..." 445 | make DESTDIR=/tmp/handbrake-install -C /tmp/oneVPL-intel-gpu/build install 446 | fi 447 | 448 | log "Patching HandBrake..." 449 | if xx-info is-cross; then 450 | patch -d /tmp/handbrake -p1 < "$SCRIPT_DIR"/cross-compile-fix.patch 451 | fi 452 | patch -d /tmp/handbrake -p1 < "$SCRIPT_DIR"/maximized-window.patch 453 | 454 | # Create the meson cross compile config file. 455 | if xx-info is-cross; then 456 | cat << EOF > /tmp/handbrake/contrib/cross-config.meson 457 | [binaries] 458 | pkgconfig = '$(xx-info)-pkg-config' 459 | 460 | [properties] 461 | sys_root = '$(xx-info sysroot)' 462 | pkg_config_libdir = '$(xx-info sysroot)/usr/lib/pkgconfig' 463 | 464 | [host_machine] 465 | system = 'linux' 466 | cpu_family = '$(xx-info arch)' 467 | cpu = '$(xx-info arch)' 468 | endian = 'little' 469 | EOF 470 | fi 471 | 472 | log "Configuring HandBrake..." 473 | ( 474 | if [ "$(xx-info arch)" = "amd64" ]; then 475 | CONF_FLAGS="--enable-qsv" 476 | else 477 | CONF_FLAGS="--disable-qsv --disable-nvenc" 478 | fi 479 | 480 | if xx-info is-cross; then 481 | CONF_FLAGS="$CONF_FLAGS --cross $(xx-info)" 482 | fi 483 | 484 | cd /tmp/handbrake && ./configure \ 485 | --verbose \ 486 | --prefix=/usr \ 487 | --build=build \ 488 | --debug=$HANDBRAKE_DEBUG_MODE \ 489 | --enable-fdk-aac \ 490 | --enable-x265 \ 491 | --enable-libdovi \ 492 | $CONF_FLAGS \ 493 | ) 494 | 495 | log "Compiling HandBrake..." 496 | make -C /tmp/handbrake/build -j$(nproc) 497 | 498 | log "Installing HandBrake..." 499 | make DESTDIR=/tmp/handbrake-install -C /tmp/handbrake/build -j1 install 500 | make DESTDIR=/tmp/handbrake-install -C /tmp/libva install 501 | 502 | # Remove uneeded installed files. 503 | if [ "$(xx-info arch)" = "amd64" ]; then 504 | rm -r \ 505 | /tmp/handbrake-install/usr/include \ 506 | /tmp/handbrake-install/usr/lib/*.la \ 507 | /tmp/handbrake-install/usr/lib/libmfx.* \ 508 | /tmp/handbrake-install/usr/lib/libigfxcmrt.so* \ 509 | /tmp/handbrake-install/usr/lib/dri/*.la \ 510 | /tmp/handbrake-install/usr/lib/pkgconfig \ 511 | /tmp/handbrake-install/usr/share/metainfo \ 512 | /tmp/handbrake-install/usr/share/applications \ 513 | 514 | fi 515 | 516 | log "Handbrake install content:" 517 | find /tmp/handbrake-install 518 | -------------------------------------------------------------------------------- /src/handbrake/cross-compile-fix.patch: -------------------------------------------------------------------------------- 1 | --- a/make/configure.py 2022-12-11 10:57:06.787237866 -0500 2 | +++ b/make/configure.py 2022-12-11 10:57:35.153607258 -0500 3 | @@ -1680,7 +1680,7 @@ 4 | 5 | ## re-run tools with cross-compilation needs 6 | if cross: 7 | - for tool in ( Tools.ar, Tools.gcc, Tools.ranlib, Tools.strip ): 8 | + for tool in ( Tools.ar, Tools.ranlib, Tools.strip ): 9 | tool.__init__( tool.var, tool.option, '%s-%s' % (cross,tool.name), **tool.kwargs ) 10 | tool.run() 11 | 12 | --- a/contrib/libdav1d/module.defs 2022-12-11 11:36:19.717065419 -0500 13 | +++ b/contrib/libdav1d/module.defs 2022-12-11 11:37:13.449448699 -0500 14 | @@ -37,6 +37,10 @@ 15 | LIBDAV1D.CONFIGURE.extra += --cross-file=$(call fn.ABSOLUTE,$(LIBDAV1D.EXTRACT.dir/))$(HOST.machine)-w64-mingw32.meson 16 | endif 17 | 18 | +ifeq (1,$(HOST.cross)) 19 | + LIBDAV1D.CONFIGURE.extra += --cross-file=/tmp/handbrake/contrib/cross-config.meson 20 | +endif 21 | + 22 | LIBDAV1D.BUILD.make = $(NINJA.exe) 23 | LIBDAV1D.BUILD.extra = -v 24 | 25 | --- a/contrib/ffmpeg/module.defs 2022-12-11 12:20:04.458408092 -0500 26 | +++ b/contrib/ffmpeg/module.defs 2022-12-11 13:23:06.567257688 -0500 27 | @@ -88,6 +88,13 @@ 28 | --enable-muxer=psp \ 29 | --enable-muxer=ipod 30 | 31 | +ifeq (1,$(HOST.cross)) 32 | + FFMPEG.CONFIGURE.extra += \ 33 | + --enable-cross-compile \ 34 | + --pkg-config=$(shell xx-info)-pkg-config \ 35 | + --arch=$(HOST.arch) 36 | +endif 37 | + 38 | ifeq (darwin,$(HOST.system)) 39 | FFMPEG.CONFIGURE.extra += --disable-audiotoolbox --disable-coreimage 40 | 41 | --- a/contrib/x265_8bit/module.defs 2022-12-11 14:47:12.661354528 -0500 42 | +++ b/contrib/x265_8bit/module.defs 2022-12-11 14:50:45.117909888 -0500 43 | @@ -40,7 +40,7 @@ 44 | X265_8.CONFIGURE.extra += -DCMAKE_CXX_FLAGS=-flax-vector-conversions 45 | endif 46 | 47 | -X265_8.CONFIGURE.args.host = -DCMAKE_HOST_SYSTEM="$(X265_8.CONFIGURE.host)" 48 | +X265_8.CONFIGURE.args.host = -DCMAKE_SYSTEM="$(X265_8.CONFIGURE.host)" 49 | ifeq (1,$(HOST.cross)) 50 | ifeq (mingw,$(HOST.system)) 51 | X265_8.CONFIGURE.extra += -DWIN32=ON 52 | --- a/contrib/x265/module.defs 2022-12-20 11:22:38.811766296 -0500 53 | +++ b/contrib/x265/module.defs 2022-12-20 11:23:58.528126775 -0500 54 | @@ -40,7 +40,7 @@ 55 | $(X265.BUILD.dir)/10bit/libx265_main10.a \ 56 | $(X265.BUILD.dir)/12bit/libx265_main12.a 57 | 58 | -ifeq (1-mingw,$(HOST.cross)-$(HOST.system)) 59 | +ifeq (1,$(HOST.cross)) 60 | X265.O.ext = .obj 61 | else 62 | X265.O.ext = .o 63 | --- a/libhb/module.defs 2022-12-20 12:24:16.998534733 -0500 64 | +++ b/libhb/module.defs 2022-12-20 12:24:59.808744271 -0500 65 | @@ -63,7 +63,7 @@ 66 | LIBHB.libxml2 := $(patsubst -I%,%,$(LIBHB.libxml2)) 67 | LIBHB.GCC.I += $(LIBHB.libxml2) 68 | else 69 | - LIBHB.GCC.I += /usr/include/libxml2 70 | + LIBHB.GCC.I += $(shell xx-info sysroot)usr/include/libxml2 71 | endif 72 | endif 73 | 74 | --- a/gtk/module.defs 2022-12-20 13:24:04.292339625 -0500 75 | +++ b/gtk/module.defs 2022-12-20 13:24:30.542950711 -0500 76 | @@ -18,7 +18,7 @@ 77 | 78 | ############################################################################### 79 | 80 | -ifeq (1-mingw,$(HOST.cross)-$(HOST.system)) 81 | +ifeq (1,$(HOST.cross))) 82 | GTK.CONFIGURE.extra += --host=$(HOST.spec) 83 | ifeq ($(HAS.dlfcn),1) 84 | GTK.CONFIGURE.extra += --enable-dl 85 | --- a/gtk/module.rules 2022-12-20 14:31:04.399112898 -0500 86 | +++ b/gtk/module.rules 2022-12-20 15:04:12.463047834 -0500 87 | @@ -16,7 +16,7 @@ 88 | set -e; cd $(GTK.src/); NOCONFIGURE=1 autoreconf -fiv 89 | set -e; cd $(GTK.build/); $(call fn.ABSOLUTE,$(GTK.src/))configure \ 90 | $(GTK.CONFIGURE.extra) \ 91 | - PKG_CONFIG_PATH=$(BUILD/)contrib/lib/pkgconfig:$(PKG_CONFIG_PATH) \ 92 | + PKG_CONFIG_PATH=$(BUILD/)contrib/lib/pkgconfig:/$(shell xx-info)/usr/share/pkgconfig:$(PKG_CONFIG_PATH) \ 93 | CC="$(GCC.gcc)" \ 94 | CXX="$(GCC.gxx)" \ 95 | CFLAGS="$(call fn.ARGS,GTK.GCC,.g .O *D *W ?extra)" \ 96 | -------------------------------------------------------------------------------- /src/handbrake/gmmlib-compile-fix.patch: -------------------------------------------------------------------------------- 1 | # Use the same C++ version as Intel Media Driver. 2 | --- a/Source/GmmLib/Linux.cmake 2024-08-26 19:18:50.798504950 -0400 3 | +++ b/Source/GmmLib/Linux.cmake 2024-08-26 19:18:55.078570496 -0400 4 | @@ -130,7 +130,7 @@ 5 | -fno-rtti 6 | -fexceptions 7 | -fcheck-new 8 | - -std=c++11 9 | + -std=c++14 10 | -pthread 11 | -Werror=non-virtual-dtor 12 | ) 13 | -------------------------------------------------------------------------------- /src/handbrake/intel-media-driver-compile-fix.patch: -------------------------------------------------------------------------------- 1 | --- a/media_driver/cmake/linux/media_compile_flags_linux.cmake 2023-11-10 16:00:32.182289902 -0500 2 | +++ b/media_driver/cmake/linux/media_compile_flags_linux.cmake 2023-11-10 16:01:23.034436228 -0500 3 | @@ -51,8 +51,6 @@ 4 | -ffunction-sections 5 | -Wl,--gc-sections 6 | 7 | - # Enable c++14 features 8 | - -std=c++14 9 | # -m32 or -m64 10 | -m${ARCH} 11 | 12 | @@ -110,6 +108,8 @@ 13 | -fexceptions 14 | -fpermissive 15 | -fcheck-new 16 | + # Enable c++14 features 17 | + -std=c++14 18 | ) 19 | 20 | if(NOT ${PLATFORM} STREQUAL "android") 21 | @@ -112,13 +112,6 @@ 22 | -fcheck-new 23 | ) 24 | 25 | -if(NOT ${PLATFORM} STREQUAL "android") 26 | - set(MEDIA_COMPILER_CXX_FLAGS_COMMON 27 | - ${MEDIA_COMPILER_CXX_FLAGS_COMMON} 28 | - -std=c++1y 29 | - ) 30 | -endif() 31 | - 32 | set(MEDIA_COMPILER_FLAGS_RELEASE "") 33 | 34 | if(${UFO_VARIANT} STREQUAL "default") 35 | --- a/Tools/bldsys/include/utils.cmakeg 2024-08-26 21:05:30.979553316 -0400 36 | +++ b/Tools/bldsys/include/utils.cmake 2024-08-26 21:05:41.891712443 -0400 37 | @@ -55,7 +55,7 @@ 38 | endif (${PLATFORM} STREQUAL "ghs") 39 | 40 | if(NOT ${PLATFORM} STREQUAL "qnx") 41 | - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 42 | + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") 43 | endif() 44 | 45 | if (${PLATFORM} STREQUAL linux) 46 | --- a/cmrtlib/linux/CMakeLists.txt 2024-08-26 20:27:26.697618847 -0400 47 | +++ b/cmrtlib/linux/CMakeLists.txt 2024-06-10 11:47:55.000000000 -0400 48 | @@ -28,7 +28,7 @@ 49 | if (LATEST_CPP_NEEDED) 50 | set(CPP_STANDARD_OPTION -std=c++17) 51 | else() 52 | - set(CPP_STANDARD_OPTION -std=c++11) 53 | + set(CPP_STANDARD_OPTION -std=c++14) 54 | endif() 55 | 56 | # Set up compile options that will be used for the Linux build 57 | -------------------------------------------------------------------------------- /src/handbrake/intel-media-sdk-compile-fix.patch: -------------------------------------------------------------------------------- 1 | --- a/api/mfx_dispatch/linux/mfxparser.cpp 2024-05-13 19:26:39.409018293 -0400 2 | +++ b/api/mfx_dispatch/linux/mfxparser.cpp 2024-05-13 19:26:59.205040655 -0400 3 | @@ -22,6 +22,7 @@ 4 | #include 5 | #include 6 | #include 7 | +#include 8 | 9 | #include 10 | 11 | -------------------------------------------------------------------------------- /src/handbrake/intel-media-sdk-debug-no-assert.patch: -------------------------------------------------------------------------------- 1 | --- a/builder/FindGlobals.cmake 2 | +++ b/builder/FindGlobals.cmake 3 | @@ -100,9 +100,9 @@ 4 | # CACHE + FORCE should be used only here to make sure that this parameters applied globally 5 | # End user is responsible to adjust configuration parameters further if needed. Here 6 | # we se only minimal parameters which are really required for the proper configuration build. 7 | - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG" CACHE STRING "" FORCE) 8 | + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG -DNDEBUG" CACHE STRING "" FORCE) 9 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}" CACHE STRING "" FORCE) 10 | - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG" CACHE STRING "" FORCE) 11 | + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG -DNDEBUG" CACHE STRING "" FORCE) 12 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}" CACHE STRING "" FORCE) 13 | 14 | if ( Darwin ) 15 | -------------------------------------------------------------------------------- /src/handbrake/maximized-window.patch: -------------------------------------------------------------------------------- 1 | diff --git a/gtk/src/ui/ghb.ui b/gtk/src/ui/ghb.ui 2 | index 4cf7371cf..627169643 100644 3 | --- a/gtk/src/ui/ghb.ui 4 | +++ b/gtk/src/ui/ghb.ui 5 | @@ -1336,6 +1336,7 @@ Van Jacobson 6 | 400 7 | fr.handbrake.ghb 8 | True 9 | + true 10 | 11 | 12 | 13 | --------------------------------------------------------------------------------