| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| defaults | ||
| meta | ||
| tasks | ||
| README.md | ||
ytptube
Deploy YTPTube, a web UI and
download manager for yt-dlp, via
its official ghcr.io/arabcoders/ytptube Docker image.
Requirements
community.dockercollection (needs thepython3-dockerapt package's bindings - this role installs it).
Role Variables
| Variable | Default | Description |
|---|---|---|
ytptube_config_dir |
~/local/ytptube/config |
Host directory mounted at /config (database, presets, tasks, cookies, logs). Created by this role. |
ytptube_downloads_dir |
~/local/ytptube/downloads |
Host directory mounted at /downloads; finished files in files/, in-progress in tmp/. Created by this role. |
ytptube_image |
ghcr.io/arabcoders/ytptube:latest |
Docker image. |
ytptube_uid / ytptube_gid |
1000 |
User the container runs as (docker --user; not a linuxserver.io image). |
ytptube_tz |
Etc/UTC |
Container timezone. |
ytptube_default_preset |
default |
Preset preselected for new downloads (YTP_DEFAULT_PRESET). Must name an existing preset. |
ytptube_presets |
[] |
Presets created/replaced through the API, matched by name (see below). |
ytptube_notifications |
[] |
Notification targets created/replaced through the API, matched by name (see below). |
ytptube_api_key |
"" |
API key (ytp_...), required when ytptube_presets or ytptube_notifications is set. |
ytptube_browser_control_enabled |
false |
Enables rename/move/delete in the web UI's Files section (YTP_BROWSER_CONTROL_ENABLED). |
ytptube_http_port |
8081 |
Host port for the web UI (container port is always 8081). |
Configuration
Only the download/temp paths, default preset, file controls and timezone are set by this role (as
YTP_* env vars). Everything else - presets, scheduled tasks,
conditions, notifications - is configured from the web UI and stored
under /config. Other YTP_* settings are listed in upstream's
FAQ.
Presets
Each ytptube_presets item has a name and any of description,
folder, template, cookies, cli (omitted fields are ""). A
missing preset is created, one whose fields differ is replaced with
PUT; presets not in the list (UI-made or built-in) are never touched
or deleted. Use the name as YTPTube stores it - lowercase, spaces as
_ - or the role fails rather than creating a duplicate every run.
This talks to the API, so it needs ytptube_api_key, which only exists
once the first account has been created in the web UI: on a fresh
install, leave ytptube_presets empty for the first run.
ytptube_default_preset: 720p_mp4
ytptube_presets:
- name: 720p_mp4
description: Best MP4 video + M4A audio, up to 720p.
cli: |-
--socket-timeout 30 --download-archive %(archive_file)s
--format 'bestvideo[height<=720][ext=mp4]+bestaudio[ext=m4a]/mp4[height<=720]/mp4'
Notifications
ytptube_notifications works the same way: a target is created if
missing and replaced with PUT if any given field differs; unlisted
targets are left alone. Fields: name, "on" (event names, [] = all;
quote it - a bare YAML on: key is the boolean true),
presets ([] = all), enabled (default true) and request
(url, plus type json/form, method POST/PUT, data_key,
headers for plain webhooks). A request.url that doesn't start with
http is sent through Apprise -
e.g. ntfy with an access token:
ytptube_notifications:
- name: ntfy
"on": [item_completed, log_error, task_error]
request:
url: "ntfys://{{ vault_ntfy_token }}@ntfy.example.com/ytdlp"
The URL usually carries a secret, so these tasks are no_log.
The upstream compose file's optional Chromium/CDP proxy and FlareSolverr sidecars are not deployed.
Queueing a URL
The easy way is ytptube-add,
which wraps the calls below (ytptube-add URL, ytptube-add -j -p audio_m4a URL from the WAN) and documents an iOS share-sheet
shortcut. The underlying API:
Besides the web UI (and its browser extensions/bookmarklet), URLs can be
queued with the API, authenticated with an API key (Settings -> API
keys). POST /api/history takes a JSON object (or an array of them)
with url and optionally preset, folder, template, cli and
auto_start (default true); without preset, the item uses
ytptube_default_preset. It answers 202 with
{"status": "accepted", ...}.
curl -sS -H "Authorization: Bearer $YTPTUBE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"url": "https://www.youtube.com/watch?v=...", "preset": "audio_m4a"}' \
"$YTPTUBE_URL/api/history"
$YTPTUBE_URL depends on where you are. In the sulaco homelab (API key
in pass personal/apikeys/ytptube/sulaco):
-
LAN or VPN:
https://ytdlp.home.provost.one(tightbeam's Caddy, local-CA certificate - the client must trust that CA, or add-k), orhttp://sulaco.local:8571directly. -
WAN, through the jumphost
ssh.home.provost.one(tightbeam): Caddy only answers LAN/VPN clients, so tunnel to sulaco's port through SSH and usehttp://localhost:8571:# The tunnel stays up for 10s, or until the last connection through it closes. ssh -f -o ExitOnForwardFailure=yes -L 8571:192.168.2.245:8571 ssh.home.provost.one sleep 10 YTPTUBE_URL=http://localhost:8571 # ...then the curl aboveThe same tunnel (with
-Ninstead of-f ... sleep 10, left running) also serves the web UI athttp://localhost:8571. If 8571 is taken locally, pick another local port:-L 18571:192.168.2.245:8571.
For a quick one-off without a JSON body there is also
GET /api/history/add?url=<url-encoded>&preset=<name> (same
Authorization header).
Example Playbook
- hosts: sulaco
vars:
ansible_python_interpreter: /usr/bin/python3
roles:
- role: ytptube
ytptube_config_dir: /mnt/disks/storage3/ytptube/config
ytptube_downloads_dir: /mnt/disks/storage3/ytptube/downloads
Notes
- On first visit, YTPTube asks you to create a local account. Do that before exposing the port anywhere: authenticated users are instance administrators and can pass arbitrary yt-dlp options, including ones that execute commands.
- Uses
ansible_python_interpreter: /usr/bin/python3in the example above for the same reason theslskd/sonarrroles do: Linuxbrew's Python (if present, earlier inPATH) doesn't havepython3-docker's bindings.