540 lines
13 KiB
Markdown
540 lines
13 KiB
Markdown
# 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](https://github.com/yt-dlp/yt-dlp#installation))
|
||
- **sqlite3** – Database management
|
||
- **jq** – JSON parser for config file handling
|
||
|
||
### Installation
|
||
|
||
**Ubuntu/Debian:**
|
||
```bash
|
||
sudo apt-get update
|
||
sudo apt-get install yt-dlp sqlite3 jq
|
||
```
|
||
|
||
**macOS:**
|
||
```bash
|
||
brew install yt-dlp sqlite3 jq
|
||
```
|
||
|
||
**Fedora/RHEL:**
|
||
```bash
|
||
sudo dnf install yt-dlp sqlite3 jq
|
||
```
|
||
|
||
---
|
||
|
||
## Installation
|
||
|
||
### 1. Clone or Download the Script
|
||
|
||
```bash
|
||
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`:
|
||
|
||
```bash
|
||
mkdir -p ~/.config/youtube_downloader
|
||
```
|
||
|
||
Then create `~/.config/youtube_downloader/config.json` with the following structure:
|
||
|
||
```json
|
||
{
|
||
"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:
|
||
1. Go to a YouTube playlist
|
||
2. Look at the URL: `https://www.youtube.com/playlist?list=PLAYLIST_ID_HERE`
|
||
3. 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
|
||
|
||
```json
|
||
"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
|
||
|
||
```bash
|
||
# 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:**
|
||
```bash
|
||
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:**
|
||
```bash
|
||
0 */6 * * * /home/user/.youtube_downloader/youtube_downloader.sh --cron run "My Music Playlist"
|
||
```
|
||
|
||
**Download all playlists every Sunday at midnight:**
|
||
```bash
|
||
0 0 * * 0 /home/user/.youtube_downloader/youtube_downloader.sh --cron run
|
||
```
|
||
|
||
#### Setting Up Cron
|
||
|
||
1. **Open cron editor:**
|
||
```bash
|
||
crontab -e
|
||
```
|
||
|
||
2. **Add a cron job** (example: daily at 2 AM):
|
||
```bash
|
||
0 2 * * * /home/user/.youtube_downloader/youtube_downloader.sh --cron run
|
||
```
|
||
|
||
3. **Save and exit** (in nano: `Ctrl+X`, then `Y`, then `Enter`)
|
||
|
||
4. **Verify cron job:**
|
||
```bash
|
||
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 `--cron` flag)
|
||
- **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: true` in config)
|
||
|
||
### Viewing Logs
|
||
|
||
```bash
|
||
# 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
|
||
|
||
1. Get the playlist URL from YouTube
|
||
2. Edit `~/.config/youtube_downloader/config.json`
|
||
3. Add a new object to the `playlists` array:
|
||
|
||
```json
|
||
{
|
||
"name": "New Playlist Name",
|
||
"url": "https://www.youtube.com/playlist?list=PLAYLIST_ID",
|
||
"destination": "/path/to/save/videos",
|
||
"enabled": true
|
||
}
|
||
```
|
||
|
||
4. 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:
|
||
```json
|
||
"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:
|
||
```json
|
||
"video_format": "worst[ext=mp4]"
|
||
```
|
||
|
||
Or cap at 720p:
|
||
```json
|
||
"video_format": "bestvideo[height<=720]+bestaudio"
|
||
```
|
||
|
||
### Clear Download History
|
||
|
||
**WARNING: This is irreversible!**
|
||
|
||
```bash
|
||
./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:
|
||
|
||
```bash
|
||
ls -la ~/.config/youtube_downloader/config.json
|
||
```
|
||
|
||
Create it if missing (see [Configuration Guide](#configuration-guide)).
|
||
|
||
---
|
||
|
||
### Issue: "jq is not installed"
|
||
|
||
**Solution:** Install jq:
|
||
|
||
```bash
|
||
# 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:
|
||
|
||
```bash
|
||
# 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:**
|
||
```bash
|
||
tail -20 ~/.youtube_downloader/downloader.log
|
||
```
|
||
|
||
---
|
||
|
||
### Issue: Cron job not running
|
||
|
||
**Debug steps:**
|
||
|
||
1. **Check cron is enabled:**
|
||
```bash
|
||
sudo systemctl status cron
|
||
```
|
||
|
||
2. **Verify cron job exists:**
|
||
```bash
|
||
crontab -l
|
||
```
|
||
|
||
3. **Check system mail for errors:**
|
||
```bash
|
||
mail
|
||
```
|
||
|
||
4. **Test the script manually:**
|
||
```bash
|
||
/home/user/.youtube_downloader/youtube_downloader.sh --cron run
|
||
```
|
||
|
||
5. **Add logging to cron job:**
|
||
```bash
|
||
0 2 * * * /home/user/.youtube_downloader/youtube_downloader.sh --cron run >> /home/user/.youtube_downloader/cron.log 2>&1
|
||
```
|
||
|
||
6. **Check permissions:**
|
||
```bash
|
||
chmod +x /home/user/.youtube_downloader/youtube_downloader.sh
|
||
```
|
||
|
||
---
|
||
|
||
### Issue: "Permission denied" when running script
|
||
|
||
**Solution:** Make the script executable:
|
||
|
||
```bash
|
||
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:**
|
||
```bash
|
||
ls -la /path/to/destination/
|
||
```
|
||
|
||
---
|
||
|
||
## Performance Tips
|
||
|
||
1. **Increase download delay** if hitting YouTube rate limits:
|
||
```json
|
||
"download_delay": 5
|
||
```
|
||
|
||
2. **Lower video quality** to save bandwidth:
|
||
```json
|
||
"video_format": "worst[ext=mp4]"
|
||
```
|
||
|
||
3. **Use audio-only mode** if you only need audio:
|
||
```json
|
||
"audio_only": true
|
||
```
|
||
|
||
4. **Schedule cron jobs during off-peak hours** to avoid network congestion
|
||
|
||
5. **Monitor database size** – it grows with each download:
|
||
```bash
|
||
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.
|