🎙️ Blog2Podcasts
An AI-powered tool that converts any blog article into a podcast audio file with optional voice cloning from YouTube.
Features
- 🌐 Web Scraping: Extracts main content from any blog URL using trafilatura
- 🤖 AI Summarization: Converts articles into engaging podcast scripts using local LLMs (Ollama)
- 🎵 Text-to-Speech: Generates high-quality audio using Microsoft Edge TTS (free)
- 🎤 Voice Cloning: Clone voices from YouTube videos using Coqui TTS (XTTS-v2)
Installation
From PyPI
pip install blog2podcasts
From Source
git clone https://github.com/QuantBender/blog2podcasts.git
cd blog2podcasts
pip install -e .
With Voice Cloning Support
pip install blog2podcasts[voice-cloning]
Prerequisites
1. Install Ollama
# Linux
curl -fsSL https://ollama.ai/install.sh | sh
# macOS
brew install ollama
# Start Ollama service
ollama serve
2. Pull an LLM Model
# Recommended: Llama 3.2 (fast and capable)
ollama pull llama3.2
# Alternative options:
ollama pull mistral # Fast, good quality
ollama pull llama3.1 # More capable, slower
ollama pull phi3 # Small, fast
3. Install ffmpeg (for audio processing)
# Ubuntu/Debian
sudo apt install ffmpeg
# macOS
brew install ffmpeg
# Windows
# Download from https://ffmpeg.org/download.html
Usage
Command Line
# Convert a blog to podcast
blog2podcasts https://example.com/blog-article
# Use a different voice
blog2podcasts https://example.com/blog --voice en-GB-RyanNeural
# Use a different LLM model
blog2podcasts https://example.com/blog --model mistral
# Adjust script length (words)
blog2podcasts https://example.com/blog --length 1200
# Preview script without generating audio
blog2podcasts https://example.com/blog --preview
# List available voices
blog2podcasts --list-voices
# Custom output name
blog2podcasts https://example.com/blog -o my_podcast
# Adjust speech rate
blog2podcasts https://example.com/blog --rate "+10%"
🎤 Voice Cloning from YouTube
Clone any voice from YouTube videos and use it for your podcasts!
# Clone voice from a YouTube video
blog2podcasts --clone-voice "https://www.youtube.com/watch?v=VIDEO_ID" --voice-name "my_host"
# Generate podcast with cloned voice
blog2podcasts https://example.com/blog --use-cloned-voice my_host
Python API
from blog2podcasts import BlogScraper, ContentSummarizer, AudioGenerator
from blog2podcasts.cli import BlogToPodcastAgent, PodcastConfig
# Create agent with custom config
config = PodcastConfig(
voice="en-US-JennyNeural", # Female US voice
model="llama3.2", # Ollama model
script_length=1000, # Target words
output_dir="podcasts", # Output folder
)
agent = BlogToPodcastAgent(config)
# Convert blog to podcast
result = agent.convert("https://example.com/interesting-article")
print(f"Audio: {result['audio_path']}")
print(f"Script: {result['script_path']}")
Use Individual Components
from blog2podcasts import BlogScraper, ContentSummarizer, AudioGenerator
import asyncio
# Just scrape a blog
scraper = BlogScraper()
content = scraper.scrape("https://example.com/blog")
print(content.title, content.text)
# Just create a podcast script
summarizer = ContentSummarizer(model="llama3.2")
script = summarizer.generate_podcast_script(content.text, content.title)
# Just generate audio
generator = AudioGenerator(voice="en-US-GuyNeural")
asyncio.run(generator.generate_audio(script, "output.mp3"))
Available Voices
Recommended Podcast Voices
| Voice | ID | Style |
|---|---|---|
| 🇺🇸 Guy (Male) | en-US-GuyNeural |
Professional, clear |
| 🇺🇸 Jenny (Female) | en-US-JennyNeural |
Friendly, warm |
| 🇬🇧 Ryan (Male) | en-GB-RyanNeural |
British, authoritative |
| 🇬🇧 Sonia (Female) | en-GB-SoniaNeural |
British, professional |
| 🇦🇺 William (Male) | en-AU-WilliamNeural |
Australian, casual |
| 🇦🇺 Natasha (Female) | en-AU-NatashaNeural |
Australian, friendly |
Run blog2podcasts --list-voices to see all available voices.
Tech Stack
| Component | Tool | Why |
|---|---|---|
| Scraping | Trafilatura | Best-in-class article extraction |
| LLM | Ollama | Free, local, private LLM inference |
| TTS | Edge-TTS | High-quality, free Microsoft voices |
| Voice Cloning | Coqui TTS | Open-source XTTS-v2 voice cloning |
| YouTube Download | yt-dlp | Extract audio from YouTube videos |
Project Structure
blog2podcasts/
├── pyproject.toml # Package configuration
├── LICENSE # MIT License
├── README.md # This file
├── CHANGELOG.md # Version history
├── blog2podcasts/
│ ├── __init__.py # Package exports
│ ├── cli.py # Command-line interface
│ ├── scraper.py # Blog content extraction
│ ├── summarizer.py # LLM-based script generation
│ ├── audio_generator.py # Text-to-speech (Edge TTS)
│ └── voice_cloner.py # YouTube voice extraction & cloning
├── voices/ # Saved voice profiles
└── output/ # Generated podcasts
How It Works
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Blog URL │ -> │ Scraper │ -> │ Summarizer │ -> │ Edge TTS │
│ │ │ (trafilatura)│ │ (Ollama) │ │ │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
│ │ │
v v v
Blog Content Podcast Script Audio (.mp3)
Troubleshooting
"Ollama not available"
# Start Ollama service
ollama serve
# Check if running
curl http://localhost:11434/api/tags
"Model not found"
# Pull the model
ollama pull llama3.2
# List available models
ollama list
"Content extraction failed"
- Some sites block scraping - try a different blog
- Check if the URL is accessible
- The fallback scraper will try BeautifulSoup
License
MIT License - Use freely for personal and commercial projects.
Contributing
Pull requests welcome! See CONTRIBUTING.md for guidelines.
Links
Metadata
Release files for blog2podcasts 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| blog2podcasts-1.0.0.tar.gz | 20.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| blog2podcasts-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.3 kB
Release files / blog2podcasts-1.0.0.tar.gz
| Download URL | blog2podcasts-1.0.0.tar.gz |
|---|---|
| Size | 20.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7ed1cd12cff727a675adfe86f24d5a577de57f5c6b1d49997db3d9f986703f0b
|
|
BLAKE2b-256 checksum How to use checksums |
c126882527163e6b4f96febddabf0e91609b6ca3c317b450e5f84b3e113b7cbd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.11
|
Release files / blog2podcasts-1.0.0-py3-none-any.whl
| Download URL | blog2podcasts-1.0.0-py3-none-any.whl |
|---|---|
| Size | 20.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d5ff4dd8e4f24a14e7bba37de4ed89d024b82e2c80f8c8292948fc890a806eb3
|
|
BLAKE2b-256 checksum How to use checksums |
e2a6a5370f69fa606bcdaedee3067b8abab9a3794c4066c38324085c125e8a82
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.11
|