{"id":14032441,"url":"https://github.com/TheNickOfTime/handbrake-web","last_synced_at":"2025-07-26T21:31:49.426Z","repository":{"id":241016717,"uuid":"804071387","full_name":"TheNickOfTime/handbrake-web","owner":"TheNickOfTime","description":"A self-hosted platform to use HandBrake on your headless devices via a bespoke web interface. Harness the processing power of multiple devices to work on a single queue.","archived":false,"fork":false,"pushed_at":"2024-11-26T21:20:54.000Z","size":3511,"stargazers_count":267,"open_issues_count":16,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-11-26T21:33:13.453Z","etag":null,"topics":["docker","foss","handbrake","nodejs","react","self-hosted","typescript","video-processing","video-transcoding"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TheNickOfTime.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"buy_me_a_coffee":"thenickoftime"}},"created_at":"2024-05-21T22:43:38.000Z","updated_at":"2024-11-26T21:20:54.000Z","dependencies_parsed_at":"2024-08-08T02:28:38.911Z","dependency_job_id":"a02b8db5-1dee-45ac-a848-b8efc2bdfcd4","html_url":"https://github.com/TheNickOfTime/handbrake-web","commit_stats":null,"previous_names":["thenickoftime/handbrake-web"],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheNickOfTime%2Fhandbrake-web","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheNickOfTime%2Fhandbrake-web/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheNickOfTime%2Fhandbrake-web/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TheNickOfTime%2Fhandbrake-web/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TheNickOfTime","download_url":"https://codeload.github.com/TheNickOfTime/handbrake-web/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227718677,"owners_count":17809257,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","foss","handbrake","nodejs","react","self-hosted","typescript","video-processing","video-transcoding"],"created_at":"2024-08-12T00:01:39.547Z","updated_at":"2024-12-02T11:31:12.469Z","avatar_url":"https://github.com/TheNickOfTime.png","language":"TypeScript","funding_links":["https://buymeacoffee.com/thenickoftime","https://buymeacoffee.com/thenickoftime'"],"categories":["Software","TypeScript","Encoding \u0026 Codecs"],"sub_categories":["Automation","Multi-CDN Management"],"readme":"\u003cdiv align='center'\u003e\n    \u003ch1 style='{text-decoration: none}'\u003eHandBrake Web\u003c/h1\u003e\n    \u003cdiv align='center'\u003e\n      \u003ca href='https://github.com/TheNickOfTime/handbrake-web/blob/main/LICENSE'\u003e\n        \u003cimg alt=\"GitHub License\" src=\"https://img.shields.io/github/license/thenickoftime/handbrake-web?style=flat-square\"\u003e\n      \u003c/a\u003e\n      \u003ca href='https://github.com/TheNickOfTime/handbrake-web/releases/latest'\u003e\n        \u003cimg alt=\"GitHub Release\" src=\"https://img.shields.io/github/v/release/thenickoftime/handbrake-web?style=flat-square\"\u003e\n      \u003c/a\u003e\n      \u003ca href='https://github.com/TheNickOfTime/handbrake-web/milestone/5'\u003e\n        \u003cimg alt=\"GitHub package.json version\" src=\"https://img.shields.io/github/package-json/v/thenickoftime/handbrake-web?filename=server%2Fpackage.json\u0026style=flat-square\u0026label=development\u0026color=goldenrod\"\u003e\n      \u003c/a\u003e\n      \u003ca href='https://github.com/TheNickOfTime/handbrake-web/milestone/5'\u003e\n        \u003cimg alt=\"GitHub milestone details\" src=\"https://img.shields.io/github/milestones/progress-percent/thenickoftime/handbrake-web/5?style=flat-square\u0026label=progress\u0026color=goldenrod\"\u003e\n      \u003c/a\u003e\n      \u003ca href='https://github.com/TheNickOfTime/handbrake-web/actions/workflows/docker-publish.yaml?query=branch%3Amain'\u003e\n        \u003cimg alt=\"GitHub Actions Workflow Status\" src=\"https://img.shields.io/github/actions/workflow/status/thenickoftime/handbrake-web/docker-publish.yaml?branch=main\u0026style=flat-square\"\u003e\n      \u003c/a\u003e\n      \u003ca href='https://buymeacoffee.com/thenickoftime'\u003e\n        \u003cimg alt=\"Static Badge\" src=\"https://img.shields.io/badge/support-buy_me_a_coffee-mediumseagreen?style=flat-square\"\u003e\n      \u003c/a\u003e\n    \u003c/div\u003e\n    \u003cdiv align='center'\u003e\n      \u003cstrong\u003eDisclaimer:\u003c/strong\u003e\n      \u003cem\u003eThis project is not related to or part of the official \u003ca href='https://github.com/HandBrake/HandBrake'\u003eHandBrake\u003c/a\u003e development. It simply uses the CLI component of HandBrake under the hood.\u003c/em\u003e\n    \u003c/div\u003e\n    \u003cimg src='client/public/handbrake-icon.png' height=256px\u003e\n\u003c/div\u003e\n\n\u003cdiv align='center' width=100%\u003e\n  \u003cdetails\u003e\n    \u003csummary\u003eScreenshots (click to expand)\u003c/summary\u003e\n    \u003cimg src='images/screenshots/screenshot-dashboard.png' width=90%\u003e\n    \u003cimg src='images/screenshots/screenshot-queue.png' width=90%\u003e\n    \u003cimg src='images/screenshots/screenshot-presets.png' width=90%\u003e\n    \u003cimg src='images/screenshots/screenshot-watchers.png' width=90%\u003e\n    \u003cimg src='images/screenshots/screenshot-workers.png' width=90%\u003e\n    \u003cimg src='images/screenshots/screenshot-settings.png' width=90%\u003e\n  \u003c/details\u003e\n\u003c/div\u003e\n\n## Summary\n\nHandBrake Web is a program for interfacing with handbrake across multiple machines via a web browser. It consists of two components: the **server** and one or more **worker**(s). **_Warning_** - This application is still under heavy development, use at your own risk, to learn more please see the [Known Issues \u0026 Limitations](#planned-features-not-yet-implemented) section.\n\n### Server\n\nThe server component primarily acts as a coordinator for the workers. Additionally it serves the client interface. **The work done by the server is not computationally expensive** - it can be run on low-end/low-power devices with no issue.\n\n### Worker(s)\n\nThe worker component does the heavy lifting via HandBrakeCLI. Jobs are sent to workers by the server, and the workers will process the provided media based on a provided HandBrake preset configuration. **The work done by the worker is very computationally expensive** - it is recommended that you **run a single worker instance per machine**, and that machine either have a high core-count CPU _or_ have GPU hardware transcoding features available to the worker.\n\n## Setup\n\nHandBrake Web is deployed via docker, and most easily via `docker compose`. The below setup will guide you to have the server and a single worker instance running on the same machine.\n\n### Docker Compose\n\n1. Copy the example docker compose\n\n```yaml\nservices:\n  handbrake-server:\n    image: ghcr.io/thenickoftime/handbrake-web-server:latest\n    container_name: handbrake-web-server\n    user: 1000:1000 # edit to run as user (uuid:guid) with permissions to access your media. 0:0 to run as root (not recommended).\n    ports:\n      - 9999:9999\n    volumes:\n      - /path/to/your/data:/data\n      - /path/to/your/media:/video # ensure this path is the same across all containers\n\n  handbrake-worker:\n    image: ghcr.io/thenickoftime/handbrake-web-worker:latest\n    container_name: handbrake-web-worker\n    user: 1000:1000 # edit to run as user (uuid:guid) with permissions to access your media. 0:0 to run as root (not recommended).\n    environment:\n      - WORKER_ID=handbrake-worker # give your worker a unique name\n      - SERVER_URL=handbrake-server # change if setting up a standalone worker, prefix with http(s):// if necessary\n      - SERVER_PORT=9999 # change if using a reverse proxy or the port is otherwise different than above\n    volumes:\n      - /path/to/your/media:/video # ensure this path is the same across all containers\n    depends_on:\n      - handbrake-server\n```\n\n2. Configure the following:\n   - **Server Port Mapping**: 9999 by default (change the lefthand side of `9999:9999` if you have a conflict)\n   - **User Mapping**: 1000:1000 by default (change to run as a user that will have adequate permissions to access the media directories that you map). 0:0 or removing this line will run the container as root - this is generally not recommended but will almost guarantee no permission issues.\n   - **Volume Mappings**: Importantly, the same media path must be mapped to `/video` across the server and _all_ worker instances.\n   - **Worker Environment Variables**: Tell your worker where to connect to the server via the `SERVER_URL` and `SERVER_PORT` environment variables. Ensure the port is set to the external mapping you set earlier.\n3. Run `docker compose up`.\n   - The client interface will be available at the address \u0026 port you configured.\n   - The worker(s) will automatically connect to the server and wait for jobs.\n\n#### Recommended Additional Steps\n\n- Use a reverse proxy (traefik, nginx, etc) to access your interface at a custom url over https.\n\n#### Hardware Transcoding Support (experimental)\n\n\u003e [!Warning]\n\u003e Hardware Transcoding will generally result in larger files with worse quality at the same settings as CPU Transcoding, with the advantage of transcoding (sometimes significantly) faster. If your goals are to produce the highest quality transcodes at the smallest file sizes, stick to CPU transcoding.\n\nCurrently NVENC and QSV hardware transcoding are supported, though the extent to which they work is experimental sdince my testing occurred on a very limited set of hardware available to me. Both of these require additional configuration. Please see the comments on [this issue](https://github.com/TheNickOfTime/handbrake-web/issues/88) for setup instructions while official documentation is being made.\n\n#### Additional Workers\n\nTo run additional workers, simply launch additional worker container instances on different machines by omitting the `handbrake-server` service from the example compose file. **Reminder** - It is recommended to run only one worker instance per machine, as a single worker will very likely push most CPUs to 100% utilization during transcoding.\n\nBecause of this, your server instance must be reachable outside of the machine it is running on. In most cases the port mapping should make this work, but if you are running an additional firewall, ets. please configure accordingly.\n\n## Usage\n\n### Presets\n\nHandBrake Web currently uses presets configured in the desktop application of HandBrake and\nexported to .json files to configure transcoding jobs. Exported presets can then be uploaded via the web interface in the 'Presets' section.\n\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003cth width=33% align='center'\u003eConfigure \u0026 Save Preset\u003c/th\u003e\n\t\t\t\u003cth width=33% align='center'\u003eExport Preset To File\u003c/th\u003e\n\t\t\t\u003cth width=33% align='center'\u003eUpload Preset to HandBrake Web\u003c/th\u003e\n\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e\u003cimg src='images/readme/readme-preset-save.png' width=100%\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003e\u003cimg src='images/readme/readme-preset-export.png' width=100%\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003e\u003cimg src='images/readme/readme-preset-upload.png' width=100%\u003e\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\n## Features\n\n### Current Features\n\n- Distributed Transcoding - leverage multiple devices to tackle transcoding as workers\n- Web Interface - Interact with HandBrake Web via your web browser\n- Transcode Queue - queue up multiple transcode jobs for your workers to tackle in order\n- Add Jobs Via Directory - bulk add videos to transcode\n- Preset Manager - Upload, Rename, and Delete HandBrake presets in the web interface\n- Directory Monitoring - for automatic job creation\n\n### Planned Features (not yet implemented)\n\n- Preset Creator - create presets directly in the web interface\n- User Sessions - logging in required to access the web interface\n\n## Known Issues \u0026 Current Limitations\n\n### Current Limitations\n\nPlease see the planned features section, as all of these are intended to be addressed.\n\n- Presets have to be created externally and uploaded to HandBrake Web\n- No security features on the client interface\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTheNickOfTime%2Fhandbrake-web","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FTheNickOfTime%2Fhandbrake-web","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FTheNickOfTime%2Fhandbrake-web/lists"}