ytdl-sub: Advanced YouTube Downloading that's Worth the Effort

What is ytdl-sub?
ytdl-sub is a Python-based command-line tool that's specifically designed for downloading videos from YouTube and other popular video sites using the yt-dlp library. What really sets it apart, though, is its clever ability to generate metadata for media players like Kodi, Jellyfin, Plex, and Emby, making it easy to get your downloads up and running with minimal fuss all while giving you that traditional TV show feeling.

Why download YouTube Videos?
Convenience: With ytdl-sub, users can easily download YouTube videos and playlists directly to their computer or device, without having to manually copy and paste links or navigate through the YouTube website.
Offline access: By downloading videos with ytdl-sub, users can enjoy their favorite content offline, whether they're on a plane, in an area with poor internet connectivity, or just want to reduce their data usage.
Easier playlist management: ytdl-sub allows users to download entire playlists at once, making it easy to manage and organize their favorite videos in one place.
No ads: By downloading videos directly, users can avoid watching ads and enjoy their content without interruptions.
Support for multiple formats: ytdl-sub often supports the ability to download videos in various formats (e.g. MP4, WEBM, etc.), giving users more flexibility when it comes to playing back their downloaded content.
Install YTDL-Sub on Linux
Today's focus will be on installing ytdl-sub directly on Linux, using a Debian-based system like Ubuntu. We've had success with this method and found it to work better than using Docker for our specific use case, the additional control over cron jobs was particularly beneficial.
To get started with ytdl-sub, you'll need to have FFmpeg installed on your system. Simply run apt install ffmpeg
in the terminal to get it set up. You should also be comfortable using basic Linux commands and navigating the terminal environment, especially when working with crontab. Don't worry if that sounds like a lot, I'll walk you through each step of the process here.
Navigate to the directory where you'd like to store the project files. For example, I keep mine in /mnt/utilities/ytdl-sub
. From there, use curl
to download the file, set its permissions accordingly, and then test the script to ensure everything is working as expected
curl -L -o ytdl-sub https://github.com/jmbannon/ytdl-sub/releases/latest/download/ytdl-sub
chmod +x ytdl-sub
./ytdl-sub -h
You should now see the ytdl-sub file when using the ls
command.
Now we need to create two files. The configuration file and the subscriptions YAML files.
Type nano config.yaml
and paste the following:
curl -L -o ytdl-sub https://github.com/jmbannon/ytdl-sub/releases/latest/download/ytdl-sub 2. chmod +x ytdl-sub 3. ./ytdl-sub -h
You should now see the ytdl-sub file when using the ls
command.
Now we need to create two files. The configuration file and the subscriptions YAML files.
Type nano config.yaml
and paste the following:
configuration:
working_directory: '.working_directory'
Press Ctrl X
then Y
then Enter
to save the file.
This config.yaml file tells ytdl-sub that we are storing files temporarily in this directory. All videos, metadata and images will be temporarily stored here until later transferred to your desired tv_show_directory
seen in the subscriptions file below.
Type nano subscriptions.yaml
and paste the following:
__preset__:
overrides:
# Root folder of all ytdl-sub TV Shows
tv_show_directory: "/tv_shows"
# Set the default date_range to 2 months
overrides:
only_recent_date_range: "2months"
only_recent_max_files: 10
# Pass any arg directly to yt-dlp's Python API
ytdl_options:
break_on_existing: False
###################################################################
# Subscriptions nested under this will use the
# `Plex TV Show by Date` preset.
#
# Can choose between:
# - Plex TV Show by Date:
# - Jellyfin TV Show by Date:
# - Kodi TV Show by Date:
Jellyfin TV Show by Date | max_1080p:
# Sets genre tag to "Documentaries"
= Youtube | Only Recent:
"SelfNoted": "https://www.youtube.com/@selfnoted"
Press Ctrl X
then Y
then Enter
to save the file.
This subscriptions.yaml tells ytdl-sub to fetch the latest 5 YouTube videos from my channel, covering a time frame of up to 2 months back, in 1080p MP4 format and store them in /mnt/media/Youtube/Jeremy
. The metadata is also being formatted with Jellyfin TV Show by Date
, which will allow the video content to be displayed and organized just like a traditional TV show on both Jellyfin or Emby.
You'll want to customize the file and add your favorite channels. You can do so by modifying the configuration file or subscriptions file. For more advanced modifications, however, I recommend checking out the not-so-comprehensive documentation provided in ytdl-sub's advanced guide!
How it works: The script begins by loading any custom settings from the config file, allowing users to tailor the behavior of ytdl-sub to their specific needs. Next, it consults the subscription file, where it checks for override settings that might supersede those specified in the config file. I'm aware that this can be a bit confusing, and the documentation could certainly benefit from more clarity on this point.
You may need to grant permissions to your ytdl-sub directory or other directories where files might be transferred to.
Let's try running a dry run on our subscription file to see if everything checks out. inside the ytdl-sub directory run the following command:
./ytdl-sub -d sub subscriptions.yaml
This will preview what a download would output but does not perform any video downloads or writes to output directories.

Given that I hadn't uploaded a new video in over a year, there were no recent videos for ytdl-sub to download. This is because I told the script to only look for videos up to 2 months back using only_recent_date_range: "2months"
However, the script executed successfully, indicating that it's working as intended even without any new content.
Want to download the files for real now? Here's what you need to do. Simply run the command again without the -d
flag as follows:
./ytdl-sub sub subscriptions.yaml
And just so you know, you don't have to name the file subscriptions.yaml. In-fact, you can name it whatever you want. I created 2 files. One for me and one for my son. Each one downloads videos we like and sends them to different directories to be served up on Emby. I named them jeremy.yaml and elijah.yaml so when I run the command I just call that file instead of subscriptions.yaml.
Not so painful, right? If you want to automate the download process, rather than running it manually each time, we can set up a simple schedule using crontab. Specifically, we'll use crontab -e
to create and edit a new cron job that will run ytdl-sub at regular intervals.
You may need to use sudo or sudo su for this but go ahead and type crontab -e
and hit Enter
. If it's your first time using crontab it may ask if you want to use nano or vim. I prefer nano so I chose that option. After choosing, you will see something like this but without the cron command. Yours may be empty other than the default commented out directions.

Arrow down to the bottom of the file and paste the cron command.
0 */3 * * * cd /mnt/utilities/ytdl-sub && ./ytdl-sub sub subscriptions.yaml
Don't forget to press Ctrl X
, Y
then Enter
to save the cron job! It's a good idea to launch crontab -e
again to double check that it did save.
This line tells the system to run the specified command every 3 hours. Simply adjust the time interval as needed, such as changing '3' to '6' for every 6 hours. The cron job will then execute the ytdl-sub script to look for new videos based on your subscriptions file. If you want to temporarily pause or stop the cron from running, just add a #
symbol at the beginning of the command, which will render it inactive. You'll notice the text will change color to indicate this. Again, don't forget to save the file before exiting!
Installing YTDL-Sub Using Docker Compose
This is an update. I am now running YTDL Sub with Docker Compose and this is how I set it up. First I will show the compose stack I am using. It is very simple except for one addition which is the cron scheduler.
services:
ytdl-sub:
image: ghcr.io/jmbannon/ytdl-sub-gui:latest
container_name: ytdl-sub
environment:
- CRON_SCHEDULE="0 */1 * * *"
- CRON_RUN_ON_START=true
- TZ=America/Chicago
volumes:
- /docker/ytdl-sub:/config
- /mnt/media/Youtube/:/tv_shows
ports:
- 8443:8443
restart: unless-stopped