Convert YouTube channels/playlists into podcast RSS feeds. PodQueue is a lightweight, self-hosted service that automatically syncs video uploads to audio (M4A) podcast episodes, hosting them with range-request compatible feeds for seamless playback in any podcast player (such as Overcast, Pocket Casts, or Apple Podcasts).
Rebuilt from the ground up for maximum efficiency, it operates on a FastAPI asynchronous backend and a premium vanilla HTML/CSS/JS frontend, optimized to run within standard constraints (e.g. 1GB RAM on Oracle Cloud Always Free AMD).
- ⚡ Lightweight & Fast - Built on FastAPI (docs disabled in production for minimal memory usage).
- 🔄 Programmatic Downloader - Leverages
yt-dlpPython API (no external Bash/JQ dependency) with flat extraction pre-passes. - ⚙️ Optimized for 1 GB RAM - Sequential job runner (
filelock) and single-threadedffmpegprocessing keep resources bounded. - 📅 Built-in Scheduler - In-process scheduler (
APScheduler) manages periodic syncs and dailyyt-dlpupdates. - 📻 iTunes & Podlove Compatible - Feeds support standard iTunes authoring, custom artwork, and Simple Chapters (
psc:chapters). - 🔒 Secure Auth - Password-only admin login backed by cryptographic session cookies.
- 💻 Premium Single Page App - Modern, responsive dark UI built with pure CSS and vanilla JavaScript.
- 📡 Live Logs Console - Real-time job output streaming using Server-Sent Events (SSE) with reconnect safety.
podqueue/
├── podqueue/ # Python package
│ ├── api/ # FastAPI routers (auth, channels, jobs)
│ ├── core/ # Downloader, RSS Generator, Scheduler, Job Runner
│ └── utils/ # Media helpers, logging configuration
├── static/ # Frontend SPA files
├── data/ # Runtime data (gitignored)
│ ├── downloads/ # Downloaded audio episodes
│ ├── feeds/ # Generated podcast XML feeds
│ └── logs/ # App and job log rotation
├── .env.example # Environment template
├── cookies.txt # YouTube authentication cookies (gitignored)
├── requirements.txt # Python dependencies
├── setup.sh # Setup and systemd deployment script
└── README.md
Run the setup script from the root of the repository. It will create a Python virtual environment, generate a .env file, and prepare runtime directories:
./setup.shUpdate the .env configuration file created in your project root:
BASE_URL=http://YOUR_SERVER_IP # Public URL used in RSS feed links
ADMIN_PASSWORD=changeme # Plain text password for Web UI access
SESSION_SECRET=your_generated_secret # Cookie signature secret (generated by setup.sh)
PORT=8000 # Port to run the FastAPI app
HOST=0.0.0.0 # Bind addressYouTube heavily throttles or blocks unauthenticated requests. You should provide a cookies.txt file in the project root:
- Install the Get cookies.txt locally extension in your browser.
- Log into YouTube, export your cookies, and save them as
cookies.txtin the PodQueue root directory.
YouTube frequently updates its site with JavaScript-based signature and "n-parameter" decryption challenges. To download videos reliably without throttle/errors, yt-dlp requires a JavaScript runtime (preferably Deno) to solve these challenges using the built-in yt-dlp-ejs solver.
Install Deno globally on your host system:
- Linux/WSL/macOS:
curl -fsSL https://deno.land/install.sh | sh sudo ln -sf ~/.deno/bin/deno /usr/local/bin/deno
- Windows (PowerShell):
irm https://deno.land/install.ps1 | iex
Verify it is accessible by running deno --version.
YouTube heavily blocks or requires bot challenges (such as "Sign in to confirm you're not a bot") for requests originating from datacenter IP ranges (e.g., Oracle Cloud, AWS, DigitalOcean).
To bypass this reliably, you can route yt-dlp traffic through a proxy or VPN.
Cloudflare WARP runs locally and exposes a SOCKS5 proxy, routing traffic through Cloudflare's network which is generally not flagged by YouTube.
- Install Cloudflare WARP on your Linux host:
curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | sudo gpg --yes --dearmor -o /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg echo "deb [arch=amd64 signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflare-client.list sudo apt-get update && sudo apt-get install -y cloudflare-warp
- Register and configure WARP in SOCKS5 proxy mode:
warp-cli --accept-tos registration new warp-cli --accept-tos mode proxy warp-cli --accept-tos connect
- Verify it is running on SOCKS5 port 40000:
curl -s --proxy socks5://127.0.0.1:40000 https://ipinfo.io/ip
- Add the proxy setting to your
.envfile:YTDLP_PROXY=socks5://127.0.0.1:40000
If you have a paid proxy subscription, add it directly to .env:
YTDLP_PROXY=http://username:password@proxy-server.com:8080The setup.sh script can automatically register a systemd unit. If installed, you can start the service with:
sudo systemctl start podqueue
sudo systemctl status podqueueAlternatively, run the development server manually:
source venv/bin/activate
uvicorn podqueue.api.main:app --host 0.0.0.0 --port 8000GET /feeds/{feed_name}.xml- Serves the generated podcast RSS feed.GET /downloads/{channel_id}/{file_name}- Serves podcast audio files (supporting HTTP Range requests).GET /artwork/{channel_id}.jpg- Serves cached channel artwork.
POST /api/login- Authenticate using password.POST /api/logout- Invalidate current session.GET /api/me- Retrieve authentication status.GET /api/channels- List all subscribed channels and check statuses.POST /api/channels- Subscribe to a channel (converts@usernameURLs automatically).PUT /api/channels/{id}- Modify limit, interval, or SponsorBlock setting.DELETE /api/channels/{id}- Unsubscribe and delete all channel assets.POST /api/jobs/download- Trigger manual download/RSS sync pipeline.POST /api/jobs/rss- Regenerate RSS feeds XML manually.POST /api/jobs/update-ytdlp- Updateyt-dlpand restart process.GET /api/jobs/status- Get execution state of background runner.GET /api/jobs/logs/stream- SSE log viewer feed.