- Python 100%
| .vscode | ||
| .gitignore | ||
| config.json | ||
| LICENSE | ||
| podcast_proxy.py | ||
| README.md | ||
| requirements.txt | ||
Podcast Proxy
A Python script that downloads and proxies podcast episodes from RSS feeds, caching media files locally and updating the feed URLs to point to the local cache. Supports processing multiple podcasts from a single configuration file.
Features
- Downloads podcast episodes from source RSS feeds
- Caches media files locally to reduce bandwidth and improve performance
- Updates RSS feed URLs to point to cached local files
- Supports multiple podcasts in a single configuration
- Supports multiple enclosure formats (standard, legacy, and custom)
- Configurable episode limits per podcast
- Comprehensive logging with multiple verbosity levels
- Dry-run mode for testing configurations
- Atomic file writes for reliability
- Automatic file permission setting
Requirements
- Python 3.6+
requestslibrary
Installation
-
Clone or download the repository:
git clone <repository-url> cd podcast-proxy -
Install dependencies:
pip3 install -r requirements.txt
Configuration
Create a JSON configuration file (e.g., config.json) with the following structure:
{
"podcasts": [
{
"original_feed_url": "https://example.com/podcast-feed.rss",
"base_podcast_url": "https://your-site.com/podcasts/",
"podcast_dir": "/path/to/local/podcast/directory",
"max_episodes": 10
},
{
"original_feed_url": "https://example2.com/podcast-feed.rss",
"base_podcast_url": "https://your-site.com/podcast2/",
"podcast_dir": "/path/to/local/podcast2/directory",
"max_episodes": 5
}
]
}
Configuration Parameters
Each podcast in the podcasts array requires the following parameters:
original_feed_url(string): URL of the source podcast RSS feedbase_podcast_url(string): Base URL where the proxied podcast will be servedpodcast_dir(string): Local directory path for storing cached podcast filesmax_episodes(integer): Maximum number of episodes to keep in the feed
Usage
Basic Usage
python3 podcast_proxy.py config.json
Command-Line Options
config_file: Path to the JSON configuration file (required)--dry-run,-d: Simulate the process without downloading or modifying files--verbose,-v: Enable verbose logging (conflicts with--quiet)--quiet,-q: Suppress all output except errors (conflicts with--verbose)--version: Show version information
Examples
Run with verbose output:
python3 podcast_proxy.py config.json --verbose
Test configuration without making changes:
python3 podcast_proxy.py config.json --dry-run
Run quietly (only errors shown):
python3 podcast_proxy.py config.json --quiet
How It Works
- Fetches the original RSS feed
- Parses the XML to find podcast episodes
- Downloads each episode's media file to the local cache directory
- Updates the RSS feed's enclosure URLs to point to the cached files
- Saves the modified RSS feed as
rss.xmlin the podcast directory - Sets appropriate file permissions on the output feed
File Structure
podcast-proxy/
├── podcast_proxy.py # Main script
├── config.json # Configuration file (example)
├── requirements.txt # Python dependencies
├── README.md # This file
└── .gitignore # Git ignore rules
Logging
The script uses Python's logging module with the following levels:
- ERROR: Only errors are shown (with
--quiet) - INFO: General information (default)
- DEBUG: Detailed debugging information (with
--verbose)
Error Handling
The script includes robust error handling for:
- Network request failures
- XML parsing errors
- File system operations
- Configuration validation
Security Considerations
- Downloaded files are stored with SHA256-based filenames
- File permissions are set to 0664 (rw-rw-r--)
- Input validation for URLs and configuration values
License
MIT License
Copyright (c) 2025 paulgit
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
Troubleshooting
Common Issues
- Permission denied: Ensure the podcast directory is writable
- Network errors: Check internet connection and source feed URL
- Invalid JSON: Validate your configuration file syntax
- Missing dependencies: Run
pip3 install -r requirements.txt
Debug Mode
Use --verbose to get detailed logging information for troubleshooting.
Changelog
Version 1.0.1
- Removed progress bars as they added little value consider this script is intended to be run in a cron job
Version 1.0.0
- Initial release with core podcast proxying functionality
- Support for multiple enclosure formats
- Configurable episode limits
- Progress bars and logging
- Dry-run mode