This is the source code for a simple, easy to use podcatcher web application. You are free to use this source to host the app yourself. A Dockerfile is provided for production deployments.
Radiofeed requires the following basic dependencies to get started:
- Python 3.13
- uv
Note: if you don't have the right version of Python you can use uv python install 3.13.x
.
For ease of local development a docker-compose.yml
file is provided which includes Docker images:
- PostgreSQL
- Redis
- Mailpit (for local email testing)
You can use these images if you want, or use a local install of PostgreSQL or Redis.
Current tested versions are PostgreSQL 16 and Redis 7.
The justfile has some convenient shortcuts for local development, including:
just install
: download and install local dependenciesjust update
: update dependencies to latest available versionsjust clean
: remove all non-committed files and other artifactsjust serve
: run the development server and Tailwind JIT compilerjust shell
: open a shell in the development environmentjust test
: run unit testsjust check
: run unit tests and linters
The install command will also create a .env
file with default settings for local development, if one does not already exist.
The Radiofeed stack includes:
This stack was chosen for the following reasons:
- Locality of behavior: the behavior of a unit of code should be obvious from looking at the code.
- Performance: reduce the burden on end-user devices and bandwidth rampant with heavy SPA frameworks
- Batteries included: using popular, well-supported open source tools such as Django and PostgreSQL with a large number of features to avoid reinventing the wheel
The following environment variables should be set in your production installation (changing radiofeed.app for your domain).
ALLOWED_HOSTS=radiofeed.app
DATABASE_URL=<database-url>
REDIS_URL=<redis-url>
ADMIN_URL=<admin-url>
[email protected]
EMAIL_HOST=mg.radiofeed.app
MAILGUN_API_KEY=<mailgun_api_key>
SECRET_KEY=<secret>
SENTRY_URL=<sentry-url>
Some settings such as DATABASE_URL
may be set automatically by certain PAAS providers such as Heroku. Consult your provider documentation as required.
EMAIL_HOST
should be set to your Mailgun sender domain along with MAILGUN_API_KEY
if you are using Mailgun.
You should ensure the SECRET_KEY
is sufficiently random: run the generate_secret_key
custom Django command to create a suitable random string.
In some server configurations your load balancer (e.g. Nginx) may set the strict-transport-security
headers by default. If not, you can set the environment variable USE_HSTS=true
.
In production it's also a good idea to set ADMIN_URL
to something other than the default admin/. Make sure it ends in a forward slash, e.g. some-random-path/.
A Dockerfile is provided for standard container deployments which should also work on Heroku or another PAAS.
Once you have access to the Django Admin, you should configure the default Site instance with the correct production name and domain.
The ansible
directory contains full Playbooks for a multi-server deployment to a shared hosting provider such as Hetzner or Digital Ocean, this can be copied and modified for your particular use-case.
A full deployment guide for Hetzner Cloud is available. You should have a DNS domain set up using e.g. Hetzner DNS or Cloudflare.
- Create a new Hetzner Cloud project
- Go to Security > API Tokens and create a new token with read/write access
- Copy the token and add it to your environment as
HCLOUD_TOKEN
- Run
terraform -chdir=tf init
to download the Hetzner provider - Run
terraform -chdir=rf apply -var hcloud_token=$HCLOUD_TOKEN
to create the necessary resources - Change to the
ansible
directory and useansible-vault create hosts
to create a new inventory file and add the IP addresses of all the servers - Do the same for
vars/django.yml
,vars/postgres.yml
, andvars/site.yml
to create the necessary variables (see example vars files for guidance) - Run
ansible-playbook -i hosts site.yml
to deploy the application - In your DNS configuration, point your domain to the new load balancer IP address
In production you should set up the following cron jobs to run these Django commands (with suggested schedules and arguments):
*/6 * * * * python manage.py parse_feeds
15 6 * * * python manage.py create_recommendations
15 9 * * 1 python manage.py send_recommendations_emails
Note: ansible will set up these cron jobs for you if you use the provided Playbooks.