In this modern era of on-demand content, podcasts have become a popular medium for storytelling, education, and entertainment.
To make it easier for users to discover and explore the vast world of podcasts, we will build a web application using Podcastindex.org excellent database.
This article will guide you through creating a podcast search web application using FastAPI, with Jinja2 templating for the UI and the Podcast Index API.
Example of the running web application:
If you prefer, you can follow along with the video version of this post:
Overview
This web application allows users to search for podcasts and view episodes of selected podcasts. The application integrates with the Podcast Index API to fetch podcast data and uses FastAPI to manage routes and render dynamic web pages.
This project consists of several key components:
- Environment configuration using
.env
files. - The main application script (
main.py
). - A wrapper for the Podcast Index API (
podcastindex_wrapper.py
). - HTML templates for rendering web pages.
Environment Configuration
To keep sensitive information secure, we use a .env
file to store environment variables such as API keys.
This file is loaded at runtime, ensuring that the credentials are not hardcoded into the application:
# PODCASTINDEX API
PODCAST_INDEX_API_KEY=<YOUR_PODCAST_INDEX_API_KEY>
PODCAST_INDEX_API_SECRET=<YOUR_PODCAST_INDEX_API_KEY>
You will need to obtain a free API key from Podcastindex.org by signing up here.
Get "Python's Magic Methods - Beyond __init__ and __str__"
Magic methods are not just syntactic sugar, they're powerful tools that can significantly improve the functionality and performance of your code. With this book, you'll learn how to use these tools correctly and unlock the full potential of Python.
Core Components
Let's now take a closer look at the core components of this application.
The Main Application Script
The main.py
file initializes the FastAPI app and defines the routes for handling incoming requests. Here is the code from main.py
:
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
from podcastindex_wrapper import search_podcasts, get_podcast_episodes
from datetime import datetime
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.on_event("startup")
def startup_event():
templates.env.filters['timestamp_to_date'] = lambda timestamp: datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d')
@app.get("/")
async def read_root(request: Request, q: str = ''):
results = []
if q:
results = search_podcasts(q)
return templates.TemplateResponse("index.html", {"request": request, "results": results, "query": q})
@app.get("/podcast/{podcast_id}/{q}")
async def podcast_episodes(request: Request, podcast_id: int, q: str = None):
episodes = get_podcast_episodes(podcast_id)
return templates.TemplateResponse("episodes.html", {"request": request, "episodes": episodes,
"query": q})
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
This code defines a web application using the FastAPI framework in Python. The application uses Jinja2 for templating and the podcastindex_wrapper
module (that we will see next) to search for podcasts and retrieve their episodes.
The startup_event
function is registered to run when the application starts up, and it adds a custom filter to the Jinja2 environment that converts a timestamp to a formatted date string.
The read_root
function is a route handler for the root URL of the application (/
). It takes an optional query parameter q
, searches for podcasts using the search_podcasts
function from podcastindex_wrapper
if q
is provided, and renders the index.html
template with the search results and query.
The podcast_episodes
function is a route handler for URLs in the format /podcast/{podcast_id}/{q}
, where podcast_id
is the ID of a podcast and q
is an optional query parameter. It retrieves the episodes for the specified podcast using the get_podcast_episodes
function from podcastindex_wrapper
, and renders the episodes.html
template with the episodes and query.
Finally, the code checks if the script is being run as the main module (__name__ == "__main__"
), and if so, start the FastAPI application using the uvicorn
server, listening on the host 0.0.0.0
and port 8000
.
The Podcast Index API Wrapper
This script abstracts the interaction with the Podcast Index API, providing simple functions to search for podcasts and fetch podcast episodes.
Hereβs the code from podcastindex_wrapper.py
:
import podcastindex
from decouple import config
# Load your Podcast Index API credentials from environment variables
PODCAST_INDEX_API_KEY = config("PODCAST_INDEX_API_KEY")
PODCAST_INDEX_API_SECRET = config("PODCAST_INDEX_API_SECRET")
config_index = {
"api_key": PODCAST_INDEX_API_KEY,
"api_secret": PODCAST_INDEX_API_SECRET
}
index = podcastindex.init(config_index)
def search_podcasts(query: str):
result = index.search(query, clean=True)
return result["feeds"]
def get_podcast_episodes(podcast_id: int):
result = index.episodesByFeedId(podcast_id)
return result["items"]
This code defines two functions, search_podcasts
and get_podcast_episodes
, that use the podcastindex
library to interact with the Podcast Index API.
The API credentials are loaded from environment variables using the decouple
library, and passed to the podcastindex.init
function to initialize an instance of the podcastindex
client.
The search_podcasts
function takes a query string as input, and calls the index.search
method of the podcastindex
client to search for podcasts matching the query. It returns the "feeds"
field of the search result, which contains a list of matching podcasts.
The get_podcast_episodes
function takes a podcast ID as input, and calls the index.episodesByFeedId
method of the podcastindex
client to retrieve a list of episodes for the specified podcast. It returns the "items"
field of the result, which contains a list of episode objects.
Dependencies
The requirements.txt
file lists the dependencies needed for the application. The dependencies include:
fastapi
: For building the web application.uvicorn
: For running the ASGI server.jinja2
: For templating renderingpython-decouple
: For managing environment variables.podcastindex-python
: The Python client for the Podcast Index API.
Don't forget to create the file or install the dependencies.
HTML Templates
The templates
directory will contain the Jinja2 templates that define the structure and layout of the web pages. These templates enable dynamic content rendering, making the application responsive to user inputs and API responses:
base.html
: The base HTML template that will be used by the other templatesindex.html
: The main template for displaying search results.episodes.html
: The template for displaying podcast episodes.
This article is for paid members only
To continue reading this article, upgrade your account to get full access.
Subscribe NowAlready have an account? Sign In