Podcast App
If you need to download the starter files, you can do so here.
In completing this assignment, you'll get practice with:
- Reading & parsing simple XML files
- Writing your own classes
Summary of Deliverables
You will write two classes in podcast.py: Podcast and Episode. These are both short classes that come with a simple initializer along with one other method each used for helping to parse information from the internet. At the end of the assignment, your classes will be used to power a simple webapp that displays real-life podcast episodes discovered from the internet.
By the end of this, here's what you'll need to submit to Gradescope:
podcast.pytest_podcast.pyreadme_podcast.txt
0. Getting Started
Please make sure to read all of this section before proceeding to write any code. This section describes the assumptions and the design of the assignment in great detail. Instructions about code you need to write begin in section 1.
Background and Goals
Podcasts are extremely popular sources of entertainment. According to one source, 584 million people listened to a podcast each month in 2025. Chances are, you've heard/watched an episode of a podcast at some point in your life.
A common way of organizing your favorite podcast episodes is to use some kind of syndication app: Apple Podcasts, Google Podcasts, and Overcast are popular choices. Spotify also includes a podcast feed in its app.
Your job will be to implement logic that reads information about a podcast from its RSS feed and stores that information inside objects that you will create. If done correctly, you will be able to use a simple podcast app in the browser that displays information about podcasts and lets you actually play the episodes.
Podcast Data & RSS Feeds
Podcasts are hosted on the internet using an important standard called RSS, short for "Really Simple Syndication." RSS is actually just a specific subset of XML. Creators of podcasts share information about their podcasts and each episode at a link somewhere on the web. This link contains an RSS document that includes all the information: titles, descriptions, etc. There is a ton of information here, so we'll pause here and make sure that you can verify a few important details from an example RSS feed for a popular podcast called "The Daily".
- All RSS feeds have an
rsstag as the root. The first child of thersstag will be achanneltag, and all other tags will be a descendent of this one. Can you find those two tags? - Information about the podcast itself is usually grouped first inside of the channel. Can you infer from the example how the RSS feed represents the title of the podcast? The description? The URL for the "cover image" of the podcast?
- Some of the tags have the prefix
itunes:—can you identify some of those? (The reason for this pattern is that iTunes is the name of the old software that was the first popular tool for listening to podcasts.)- Any tag with an
itunes:prefix (or any prefix including a colon) can be searched for ignoring that prefix, meaning thatfind("x")would find both an<itunes:x>tag and an<x>tag.
- Any tag with an
- Each
channeltag contains one or moreitemtags. Anitemrefers to a single episode of the podcast. Can you identify which tags represent the title and duration of the only episode listed below? What are those tags, and what values do they store? - Each episode's audio link lives inside of an
enclosuretag with type"audio/mpeg". Verify that you can find the (rather long) URL that links to the podcast's audio. If you paste that link into your browser, do you hear the episode playing?
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:media="http://search.yahoo.com/mrss/" xmlns:podcast="https://podcastindex.org/namespace/1.0" version="2.0">
<channel>
<atom:link href="https://feeds.simplecast.com/Sl5CSM3S" rel="self" title="MP3 Audio" type="application/atom+xml"/>
<atom:link xmlns="http://www.w3.org/2005/Atom" href="https://simplecast.superfeedr.com" rel="hub"/>
<generator>https://simplecast.com</generator>
<title>The Daily</title>
<description>This is what the news should sound like. The biggest stories of our time, told by the best journalists in the world. Hosted by Michael Barbaro, Rachel Abrams and Natalie Kitroeff. Twenty minutes a day, six days a week, ready by 6 a.m. Subscribe today at nytimes.com/podcasts or on Apple Podcasts and Spotify. You can also subscribe via your favorite podcast app here https://www.nytimes.com/activate-access/audio?source=podcatcher.</description>
<copyright>© 2020-2021 THE NEW YORK TIMES COMPANY; The New York Times encourages the use of RSS feeds for personal use in a news reader or as part of a non-commercial blog, subject to your agreement to our Terms of Service.</copyright>
<language>en</language>
<pubDate>Tue, 17 Feb 2026 10:49:16 +0000</pubDate>
<lastBuildDate>Tue, 17 Feb 2026 17:07:18 +0000</lastBuildDate>
<image>
<link>https://www.nytimes.com/the-daily</link>
<title>The Daily</title>
<url>https://image.simplecastcdn.com/images/7f2f4c05-9c2f-4deb-82b7-b538062bc22d/73549bf1-94b3-40ff-8aeb-b4054848ec1b/3000x3000/the-daily-album-art-original.jpg?aid=rss_feed</url>
</image>
<link>https://www.nytimes.com/the-daily</link>
<itunes:type>episodic</itunes:type>
<itunes:summary>This is what the news should sound like. The biggest stories of our time, told by the best journalists in the world. Hosted by Michael Barbaro, Rachel Abrams and Natalie Kitroeff. Twenty minutes a day, six days a week, ready by 6 a.m. Subscribe today at nytimes.com/podcasts or on Apple Podcasts and Spotify. You can also subscribe via your favorite podcast app here https://www.nytimes.com/activate-access/audio?source=podcatcher.</itunes:summary>
<itunes:author>The New York Times</itunes:author>
<itunes:explicit>false</itunes:explicit>
<itunes:image href="https://image.simplecastcdn.com/images/7f2f4c05-9c2f-4deb-82b7-b538062bc22d/73549bf1-94b3-40ff-8aeb-b4054848ec1b/3000x3000/the-daily-album-art-original.jpg?aid=rss_feed"/>
<itunes:new-feed-url>https://feeds.simplecast.com/Sl5CSM3S</itunes:new-feed-url>
<itunes:owner>
<itunes:name>The New York Times</itunes:name>
<itunes:email>thedaily@nytimes.com</itunes:email>
</itunes:owner>
<itunes:category text="News">
<itunes:category text="Daily News"/>
</itunes:category>
<item>
<guid isPermaLink="false">b5e17eb0-7e44-4229-ade3-6b1d2bf9f925</guid>
<title>After Venezuela, Is Cuba Next?</title>
<description>
<![CDATA[ <p>For more than six decades, the United States has tried to topple the regime in Cuba. After ousting President Nicolás Maduro of Venezuela, who was one of Cuba’s closest allies, the Trump administration is closer than ever to forcing radical change on the island.</p><p>The New York Times reporters Frances Robles and Michael Crowley discuss how the latest escalation is pushing Cuba to the brink, and whether this time the United States will get what it wants. </p><p>Guest:</p><ul><li><a href="https://www.nytimes.com/by/frances-robles" target="_blank"><strong>Frances Robles</strong></a>, an international correspondent covering Latin America and the Caribbean for The New York Times.</li><li><a href="https://www.nytimes.com/by/michael-crowley" target="_blank"><strong>Michael Crowley</strong></a>, a reporter covering the State Department and U.S. foreign policy for The New York Times.</li></ul><p>Background reading: </p><ul><li>Cuba’s government has lasted 67 years. <a href="https://www.nytimes.com/2026/02/08/world/americas/cuba-communist-government-trump.html" target="_blank">Will it fall under Mr. Trump</a>?</li><li><a href="https://www.nytimes.com/2026/01/17/world/americas/cuba-venezuela-oil-power-blackouts.html" target="_blank">Can Cuba survive without Venezuela’s oil</a>?</li></ul><p>Photo: Yamil Lage/Agence France-Presse — Getty Images</p><p>For more information on today’s episode, visit <a href="http://nytimes.com/thedaily?smid=pc-thedaily"><strong>nytimes.com/thedaily</strong></a>. Transcripts of each episode will be made available by the next workday. </p> <p><p>Subscribe today at <a href="http://nytimes.com/podcasts">nytimes.com/podcasts</a> or on Apple Podcasts and Spotify. You can also subscribe via your favorite podcast app here <a href="https://www.nytimes.com/activate-access/audio?source=podcatcher">https://www.nytimes.com/activate-access/audio?source=podcatcher</a>. For more podcasts and narrated articles, download The New York Times app at nytimes.com/app.</p></p><br/> <p>Hosted by Simplecast, an AdsWizz company. See <a href="https://pcm.adswizz.com">pcm.adswizz.com</a> for information about our collection and use of personal data for advertising.</p> ]]>
</description>
<pubDate>Tue, 17 Feb 2026 10:49:16 +0000</pubDate>
<author>thedaily@nytimes.com (The New York Times)</author>
<link>https://www.nytimes.com/the-daily</link>
<media:thumbnail height="720" url="https://image.simplecastcdn.com/images/34e5431c-f7f7-4edd-9b5d-0277e197a71b/a1d5d9a6-5237-46e7-9e24-2ab4ad66ae43/00thedaily-youtube-20-18.jpg" width="1280"/>
<content:encoded>
<![CDATA[ <p>For more than six decades, the United States has tried to topple the regime in Cuba. After ousting President Nicolás Maduro of Venezuela, who was one of Cuba’s closest allies, the Trump administration is closer than ever to forcing radical change on the island.</p><p>The New York Times reporters Frances Robles and Michael Crowley discuss how the latest escalation is pushing Cuba to the brink, and whether this time the United States will get what it wants. </p><p>Guest:</p><ul><li><a href="https://www.nytimes.com/by/frances-robles" target="_blank"><strong>Frances Robles</strong></a>, an international correspondent covering Latin America and the Caribbean for The New York Times.</li><li><a href="https://www.nytimes.com/by/michael-crowley" target="_blank"><strong>Michael Crowley</strong></a>, a reporter covering the State Department and U.S. foreign policy for The New York Times.</li></ul><p>Background reading: </p><ul><li>Cuba’s government has lasted 67 years. <a href="https://www.nytimes.com/2026/02/08/world/americas/cuba-communist-government-trump.html" target="_blank">Will it fall under Mr. Trump</a>?</li><li><a href="https://www.nytimes.com/2026/01/17/world/americas/cuba-venezuela-oil-power-blackouts.html" target="_blank">Can Cuba survive without Venezuela’s oil</a>?</li></ul><p>Photo: Yamil Lage/Agence France-Presse — Getty Images</p><p>For more information on today’s episode, visit <a href="http://nytimes.com/thedaily?smid=pc-thedaily"><strong>nytimes.com/thedaily</strong></a>. Transcripts of each episode will be made available by the next workday. </p> <p><p>Subscribe today at <a href="http://nytimes.com/podcasts">nytimes.com/podcasts</a> or on Apple Podcasts and Spotify. You can also subscribe via your favorite podcast app here <a href="https://www.nytimes.com/activate-access/audio?source=podcatcher">https://www.nytimes.com/activate-access/audio?source=podcatcher</a>. For more podcasts and narrated articles, download The New York Times app at nytimes.com/app.</p></p><br/> <p>Hosted by Simplecast, an AdsWizz company. See <a href="https://pcm.adswizz.com">pcm.adswizz.com</a> for information about our collection and use of personal data for advertising.</p> ]]>
</content:encoded>
<enclosure length="30611077" type="audio/mpeg" url="https://dts.podtrac.com/redirect.mp3/pdst.fm/e/pfx.vpixl.com/6qj4J/pscrb.fm/rss/p/nyt.simplecastaudio.com/03d8b493-87fc-4bd1-931f-8a8e9b945d8a/episodes/955e65d2-cb38-481c-b264-f1330c0f7fb2/audio/128/default.mp3?aid=rss_feed&awCollectionId=03d8b493-87fc-4bd1-931f-8a8e9b945d8a&awEpisodeId=955e65d2-cb38-481c-b264-f1330c0f7fb2&feed=Sl5CSM3S"/>
<itunes:title>After Venezuela, Is Cuba Next?</itunes:title>
<itunes:author>The New York Times</itunes:author>
<itunes:image href="https://image.simplecastcdn.com/images/34e5431c-f7f7-4edd-9b5d-0277e197a71b/d1c302ff-2713-40e3-bc5a-86d8fe9cf1e2/3000x3000/00thedaily-applespotify-20-14.jpg?aid=rss_feed"/>
<itunes:duration>00:31:53</itunes:duration>
<itunes:summary>For more than six decades, the United States has tried to topple the regime in Cuba. After ousting President Nicolás Maduro of Venezuela, who was one of Cuba’s closest allies, the Trump administration is closer than ever to forcing radical change on the island. The New York Times reporters Frances Robles and Michael Crowley discuss how the latest escalation is pushing Cuba to the brink, and whether this time the United States will get what it wants.</itunes:summary>
<itunes:subtitle>For more than six decades, the United States has tried to topple the regime in Cuba. After ousting President Nicolás Maduro of Venezuela, who was one of Cuba’s closest allies, the Trump administration is closer than ever to forcing radical change on the island. The New York Times reporters Frances Robles and Michael Crowley discuss how the latest escalation is pushing Cuba to the brink, and whether this time the United States will get what it wants.</itunes:subtitle>
<itunes:explicit>false</itunes:explicit>
<itunes:episodeType>full</itunes:episodeType>
</item>
<!-- ... More items -->
</channel>
</rss>
Keep in mind your XML processing toolkit:
| Snippet | Purpose |
|---|---|
from bs4 import BeautifulSoup |
Import the library that stores all of the important XML parsing machinery |
soup = BeautifulSoup(rss_content, features="xml") |
Parses a string that contains XML data and parses it as a BeautifulSoup object |
elem.find_all(kind) |
Returns a list of all the direct descendants of the current elem that are examples of kind tags |
elem.find_all(kind, recursive=False) |
Returns a list of all the children of the current elem that are examples of kind tags |
elem.find_all(True) |
Returns a list of all the direct descendants of the current that are not just plain text. |
elem[attr_name] |
Returns the value of the attribute called attr_name that belongs to the Element elem. Note that this may be a list instead of a single value! |
1. Podcast and Episode
In this assignment, you'll write two short classes on your own. We provide the specification here, and it's up to you to decide how to implement them.
Important note: anywhere you are required to parse a string, you should make sure to call .strip() on that string. For example, when getting the information out of <title> The Daily </title>, you should simply store "The Daily".
Episode
Please read this entire subsection before trying to write any code.
This class will represent a single episode of a podcast. Episode objects must have the following four attributes:
title, the episode titledescription, a (potentially very long) summary of the episodeaudio_url, a string that contains the URL of the audio source for the podcast. (If you print this out, pasted it into your browser, and navigated to that site, your browser should start playing audio.)pub_date, a string representation of the date and time at which the episode was published.
You will either need to write a simple __init__ method to create and store these attributes or use the dataclass pattern. Which you choose is up to you. Make sure your initializer accepts these inputs in exactly this order.
Additionally, you need to implement a single required classmethod called from_item_tag. This method will accept a BeautifulSoup element (an <item> tag) representing a single episode as its only input. It will return an instance of an Episode. It must have the following signature (adding the decorator—the line with the @—as well):
@classmethod
def from_item_tag(cls, item_tag):
This is a class method, which is called from the class itself rather than any particular object. For example, we would call this method like Episode.from_item_tag(item_tag); like with self in methods, cls is a placeholder variable that refers to the name of the class itself.
This method is kind of like an initializer in the sense that it takes in some input and returns a new instance of an Episode. Instead of taking in parsed-out attribute values, it should take in an instance of a BeautifulSoup tag that contains all of this information. Leaving Episode.__init__() as a very simple initializer that assigns input arguments to attribute variables allows us to have a flexible way of creating Episode instances. Then, Episode.from_item_tag() will be used to do the work of parsing all of the important elements out of the RSS XML and then passing that in as an input to the initializer.
Try to write your Episode class now!
Podcast
Please read this entire subsection before trying to write any code.
This class will represent information about a podcast as a collection of Episode objects. Podcast objects must have the following four attributes:
title, the name of the podcastdescription, a (potentially very long) summary of the podcastimage_url, a string that contains the URL of the cover image for the podcast. (If you print this out, paste it into your browser, and navigate to that site, your browser should display the cover image.)episodes, a list of allEpisodeobjects as parsed out of the RSS.
As before, you will either need to write a simple __init__ method to create and store these attributes or use the dataclass pattern. Make sure your initializer accepts these inputs in exactly this order.
Additionally, you need to implement a single required classmethod called from_rss. It will return an instance of an Podcast. It must have the following signature (adding the decorator—the line with the @—as well).
@classmethod
def from_rss(cls, rss_url: str):
from_rss must make a request to the input URL and use BeautifulSoup to parse out the required attributes from the RSS that comes back as a response. This involves reading out the title, description, and image_url as well as iterating through all available tags representing individual episodes. To create an Episode from its tag, call the Episode.from_item_tag() method you created in the last section.
2. Test Your Code
We have hosted a dummy RSS feed at this link. You can also see it in your Codio workspace if you find that more convenient. Write at least five different tests subject to the following constraints:
- A test that verifies that you can correctly get the title of the dummy podcast
- A test that verifies that you can correctly get the description of the dummy podcast.
- A test that verifies that you can correctly get the image URL of the dummy podcast.
- A test that verifies that you can correctly get the number of episodes released for the dummy podcast.
- One or more tests that verify that you extracted the right information for one of the episodes released for the podcast (title, description, audio URL, and publication date).
You can run your tests with the following command:
python -m unittest test_podcast
You will submit these test cases in the file test_podcast.py. They must pass on a correct implementation in order for you to receive full credit.
3. Using the whole program
Once you’re done, you can run your podcast app in Codio by running python app.py in the terminal, then navigating to "Podcast Web App" in the top right.
Observe how the page loads from podcasts linked in the FEEDS list in app.py. You can find the RSS link for another podcast and put it in there to see those episodes populate as well!
4. Readme and Submission
A. Readme
Complete readme_podcast.txt in the same way that you have done for previous assignments.
B. Submission
Submit podcast.py, test_podcast.py, and readme_podcast.txt on Gradescope.
Your code will be tested for compilation and checkstyle errors upon submission.
Important: Don't forget to write comments for your function headers and test cases as mentioned earlier in the specifiaction.
Important: Remember to delete any print statements you added to your code before submitting.
If you encounter any autograder-related issues, please make a private post on Ed.