13 KiB
Podcast-Downloader
A bash script that automatically downloads videos from YouTube playlists using yt-dlp, maintains a local SQLite database of downloaded content, and prevents duplicate downloads. Supports multiple playlists with individual destination folders and cron job integration for automated scheduling.
Features
| Feature | Description |
|---|---|
| Multi-Playlist Support | Configure and download from multiple YouTube playlists simultaneously |
| Duplicate Prevention | SQLite database tracks all downloaded videos to prevent re-downloading |
| Individual Destinations | Assign a different destination folder for each playlist |
| Cron-Compatible | Run automatically on a schedule with proper logging |
| Download Sessions | Detailed statistics on each download run (downloaded, skipped, errors) |
| Database Statistics | View total videos downloaded, storage used, and per-playlist breakdowns |
| Configurable Format | Specify video format, download delays, and audio-only mode via config |
| Automatic Cleanup | Removes temporary download folders after successful transfers |
| Colored Output | Terminal-friendly logging (disabled in cron mode) |
Prerequisites
Before using this script, ensure you have the following tools installed:
Required
- bash (version 4.0 or higher)
- yt-dlp – YouTube video downloader (install)
- sqlite3 – Database management
- jq – JSON parser for config file handling
Installation
Ubuntu/Debian:
sudo apt-get update
sudo apt-get install yt-dlp sqlite3 jq
macOS:
brew install yt-dlp sqlite3 jq
Fedora/RHEL:
sudo dnf install yt-dlp sqlite3 jq
Installation
1. Clone or Download the Script
mkdir -p ~/.youtube_downloader
cd ~/.youtube_downloader
# Download or clone the script here
chmod +x youtube_downloader.sh
2. Create Configuration File
Create the config file at ~/.config/youtube_downloader/config.json:
mkdir -p ~/.config/youtube_downloader
Then create ~/.config/youtube_downloader/config.json with the following structure:
{
"general": {
"db_dir": "$HOME/.youtube_downloader",
"temp_download_dir": "/tmp/youtube_downloads",
"video_format": "best[ext=mp4]",
"output_template": "%(title)s.%(ext)s",
"audio_only": false,
"download_delay": 2,
"debug": false
},
"playlists": [
{
"name": "My Music Playlist",
"url": "https://www.youtube.com/playlist?list=PLAYLIST_ID_1",
"destination": "/home/user/Music/YouTubeDownloads",
"enabled": true
},
{
"name": "Tutorial Playlist",
"url": "https://www.youtube.com/playlist?list=PLAYLIST_ID_2",
"destination": "/home/user/Videos/Tutorials",
"enabled": true
},
{
"name": "Disabled Playlist",
"url": "https://www.youtube.com/playlist?list=PLAYLIST_ID_3",
"destination": "/home/user/Videos/Archive",
"enabled": false
}
]
}
3. Find Your Playlist IDs
To get a playlist ID:
- Go to a YouTube playlist
- Look at the URL:
https://www.youtube.com/playlist?list=PLAYLIST_ID_HERE - Copy the part after
list=
Configuration Guide
General Settings
| Setting | Description | Example |
|---|---|---|
db_dir |
Directory for database and logs | $HOME/.youtube_downloader |
temp_download_dir |
Temporary folder for downloads (cleaned up after) | /tmp/youtube_downloads |
video_format |
yt-dlp format specification | best[ext=mp4] or worst |
output_template |
Filename pattern (yt-dlp variables) | %(title)s.%(ext)s |
audio_only |
Download audio only (ignores video_format) | true or false |
download_delay |
Seconds between downloads (avoids rate-limiting) | 2 |
debug |
Enable debug logging | true or false |
Video Format Examples
"best[ext=mp4]" // Best quality MP4
"worst" // Lowest quality (smallest file)
"bestvideo+bestaudio" // Best video + best audio (merged)
"bestvideo[height<=720]" // Max 720p
Playlist Settings
| Setting | Description | Example |
|---|---|---|
name |
Display name for the playlist | "My Music Playlist" |
url |
Full YouTube playlist URL | https://www.youtube.com/playlist?list=... |
destination |
Where videos are saved | /home/user/Music/YouTubeDownloads |
enabled |
Enable/disable this playlist | true or false |
Usage
Interactive Usage
# Download all enabled playlists
./youtube_downloader.sh run
# Download a specific playlist
./youtube_downloader.sh run "My Music Playlist"
# View statistics
./youtube_downloader.sh stats
# List last 20 downloaded videos
./youtube_downloader.sh list 20
# Show all configured playlists
./youtube_downloader.sh playlists
# View help
./youtube_downloader.sh help
# Reset database (WARNING: deletes all download history)
./youtube_downloader.sh reset
Cron Job Usage
Run downloads automatically on a schedule. Use --cron flag to disable colors and log only to file.
Example Cron Jobs
Download all playlists daily at 2 AM:
0 2 * * * /home/user/.youtube_downloader/youtube_downloader.sh --cron run >> /home/user/.youtube_downloader/cron.log 2>&1
Download specific playlist every 6 hours:
0 */6 * * * /home/user/.youtube_downloader/youtube_downloader.sh --cron run "My Music Playlist"
Download all playlists every Sunday at midnight:
0 0 * * 0 /home/user/.youtube_downloader/youtube_downloader.sh --cron run
Setting Up Cron
-
Open cron editor:
crontab -e -
Add a cron job (example: daily at 2 AM):
0 2 * * * /home/user/.youtube_downloader/youtube_downloader.sh --cron run -
Save and exit (in nano:
Ctrl+X, thenY, thenEnter) -
Verify cron job:
crontab -l
Important Notes for Cron
- Use absolute paths – cron doesn't have the same environment as your shell
- Specify full path to the script:
/home/user/.youtube_downloader/youtube_downloader.sh - Colors are disabled automatically in cron mode (detected via
--cronflag) - All output logged to
$HOME/.youtube_downloader/downloader.log - Ensure permissions – make the script executable:
chmod +x youtube_downloader.sh
Database
The script maintains a SQLite database at ~/.youtube_downloader/downloads.db with the following tables:
downloaded_videos
Tracks all downloaded videos to prevent duplicates.
| Column | Type | Purpose |
|---|---|---|
id |
INTEGER | Unique record ID |
video_id |
TEXT | YouTube video ID (unique) |
title |
TEXT | Video title |
url |
TEXT | Full YouTube URL |
playlist_name |
TEXT | Which playlist it came from |
download_date |
TIMESTAMP | When it was downloaded |
file_path |
TEXT | Full path to saved file |
file_size |
INTEGER | File size in bytes |
status |
TEXT | Status (always 'completed' for valid downloads) |
download_sessions
Logs each download run with statistics.
| Column | Type | Purpose |
|---|---|---|
id |
INTEGER | Session ID |
playlist_name |
TEXT | Which playlist was downloaded |
playlist_url |
TEXT | Playlist URL |
session_start |
TIMESTAMP | When the session started |
session_end |
TIMESTAMP | When the session finished |
videos_downloaded |
INTEGER | Count of newly downloaded videos |
videos_skipped |
INTEGER | Count of already-downloaded videos |
errors |
INTEGER | Count of download failures |
Logs
All activity is logged to ~/.youtube_downloader/downloader.log
Log Levels
- [INFO] – General information (downloads, moves, session start/end)
- [ERROR] – Critical issues (failed downloads, missing directories)
- [WARNING] – Non-critical issues (missing destinations, disabled playlists)
- [DEBUG] – Detailed diagnostic info (only if
debug: truein config)
Viewing Logs
# View entire log
cat ~/.youtube_downloader/downloader.log
# View last 50 lines
tail -50 ~/.youtube_downloader/downloader.log
# Follow logs in real-time (while script is running)
tail -f ~/.youtube_downloader/downloader.log
# View errors only
grep "ERROR" ~/.youtube_downloader/downloader.log
Common Tasks
Add a New Playlist
- Get the playlist URL from YouTube
- Edit
~/.config/youtube_downloader/config.json - Add a new object to the
playlistsarray:
{
"name": "New Playlist Name",
"url": "https://www.youtube.com/playlist?list=PLAYLIST_ID",
"destination": "/path/to/save/videos",
"enabled": true
}
- Save and run:
./youtube_downloader.sh run "New Playlist Name"
Disable a Playlist Temporarily
Set "enabled": false for that playlist in config.json. The playlist will be skipped during automatic runs but can still be downloaded manually by name.
Change Download Location
Edit the destination field for a playlist in config.json. New videos will go to the new location; old videos remain where they were.
Download Audio Only
In config.json, set:
"audio_only": true,
"video_format": "best"
The script will extract audio only and save as MP3/M4A.
Reduce File Sizes
Change video_format to download lower quality:
"video_format": "worst[ext=mp4]"
Or cap at 720p:
"video_format": "bestvideo[height<=720]+bestaudio"
Clear Download History
WARNING: This is irreversible!
./youtube_downloader.sh reset
Then confirm with yes.
Troubleshooting
Issue: "Config file not found"
Solution: Ensure ~/.config/youtube_downloader/config.json exists and is readable:
ls -la ~/.config/youtube_downloader/config.json
Create it if missing (see Configuration Guide).
Issue: "jq is not installed"
Solution: Install jq:
# Ubuntu/Debian
sudo apt-get install jq
# macOS
brew install jq
# Fedora
sudo dnf install jq
Issue: "yt-dlp is not installed"
Solution: Install yt-dlp:
# Ubuntu/Debian
sudo apt-get install yt-dlp
# macOS
brew install yt-dlp
# Or via pip (any OS)
pip install yt-dlp
Issue: "Failed to fetch playlist"
Possible causes:
- Invalid playlist URL – Double-check the URL format
- Private/restricted playlist – YouTube playlists must be public
- Network issue – Check internet connection
- Rate-limited – Try again later
Check logs:
tail -20 ~/.youtube_downloader/downloader.log
Issue: Cron job not running
Debug steps:
-
Check cron is enabled:
sudo systemctl status cron -
Verify cron job exists:
crontab -l -
Check system mail for errors:
mail -
Test the script manually:
/home/user/.youtube_downloader/youtube_downloader.sh --cron run -
Add logging to cron job:
0 2 * * * /home/user/.youtube_downloader/youtube_downloader.sh --cron run >> /home/user/.youtube_downloader/cron.log 2>&1 -
Check permissions:
chmod +x /home/user/.youtube_downloader/youtube_downloader.sh
Issue: "Permission denied" when running script
Solution: Make the script executable:
chmod +x ~/.youtube_downloader/youtube_downloader.sh
Issue: Videos not moving to destination folder
Possible causes:
- Destination folder doesn't exist – Script will create it automatically
- Insufficient disk space – Check available space
- File permissions – Ensure write access to destination folder
Check permissions:
ls -la /path/to/destination/
Performance Tips
-
Increase download delay if hitting YouTube rate limits:
"download_delay": 5 -
Lower video quality to save bandwidth:
"video_format": "worst[ext=mp4]" -
Use audio-only mode if you only need audio:
"audio_only": true -
Schedule cron jobs during off-peak hours to avoid network congestion
-
Monitor database size – it grows with each download:
du -sh ~/.youtube_downloader/downloads.db
File Structure
~/Podcast-Pownloader/
├── podcast-downloader.sh # Main script
├── downloads.db # SQLite database
├── downloader.log # Activity log
├── cron.log # Cron job output (optional)
└── podcasts.json # Configuration file
License
This project is provided as-is for personal use. Please respect YouTube's Terms of Service and copyright laws when downloading content.
Contributing
Found a bug or have a feature request? Feel free to submit issues or improvements!
Disclaimer
This tool is for personal use only. Users are responsible for:
- Complying with YouTube's Terms of Service
- Respecting copyright and intellectual property rights
- Not using the tool to circumvent any protections or restrictions
- Ensuring all downloads comply with local laws
The authors assume no liability for misuse of this tool.