Skip to content

Data Models

Data models used throughout the podcast_scraper codebase.

Overview

The models module defines core data structures:

  • RssFeed - Parsed RSS feed representation
  • Episode - Individual podcast episode
  • TranscriptionJob - Whisper transcription job

API Reference

RssFeed dataclass

RssFeed(title: str, items: List[Element], base_url: str, authors: List[str] = list())

Represents a parsed RSS feed with metadata and episode items.

This dataclass holds the parsed RSS feed information including the feed title, all episode items as XML elements, the base URL for resolving relative links, and a list of detected authors.

Attributes:

Name Type Description
title str

The podcast feed title (from element).</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.RssFeed.items">items</span></code></td> <td> <code><span title="typing.List">List</span>[<span title="xml.etree.ElementTree.Element">Element</span>]</code> </td> <td> <div class="doc-md-description"> <p>List of XML elements representing individual episodes (<item> elements).</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.RssFeed.base_url">base_url</span></code></td> <td> <code><span title="str">str</span></code> </td> <td> <div class="doc-md-description"> <p>Base URL of the RSS feed, used for resolving relative URLs.</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.RssFeed.authors">authors</span></code></td> <td> <code><span title="typing.List">List</span>[<span title="str">str</span>]</code> </td> <td> <div class="doc-md-description"> <p>List of author names extracted from the feed metadata.</p> </div> </td> </tr> </tbody> </table> <details class="example" open> <summary>Example</summary> <blockquote> <blockquote> <blockquote> <p>feed = RssFeed( ... title="My Podcast", ... items=[item1, item2], ... base_url="https://example.com/feed.xml", ... authors=["John Doe"] ... )</p> </blockquote> </blockquote> </blockquote> </details> <div class="doc doc-children"> </div> </div> </div> <div class="doc doc-object doc-class"> <h3 id="podcast_scraper.models.Episode" class="doc doc-heading"> <code class="doc-symbol doc-symbol-heading doc-symbol-class"></code> <span class="doc doc-object-name doc-class-name">Episode</span> <span class="doc doc-labels"> <small class="doc doc-label doc-label-dataclass"><code>dataclass</code></small> </span> <a href="#podcast_scraper.models.Episode" class="headerlink" title="Permanent link">¶</a></h3> <div class="doc-signature highlight"><pre><span></span><code><span class="nf">Episode</span><span class="p">(</span><span class="n">idx</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">title_safe</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">item</span><span class="p">:</span> <span class="n">Element</span><span class="p">,</span> <span class="n">transcript_urls</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]]],</span> <span class="n">media_url</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">media_type</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> </code></pre></div> <div class="doc doc-contents first"> <p>Represents a podcast episode with metadata and content URLs.</p> <p>This dataclass encapsulates all information about a single podcast episode, including its position in the feed, title information, transcript URLs, and media file details.</p> <p><span class="doc-section-title">Attributes:</span></p> <table> <thead> <tr> <th>Name</th> <th>Type</th> <th>Description</th> </tr> </thead> <tbody> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.Episode.idx">idx</span></code></td> <td> <code><span title="int">int</span></code> </td> <td> <div class="doc-md-description"> <p>Episode index in the feed (0-based, starting from most recent).</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.Episode.title">title</span></code></td> <td> <code><span title="str">str</span></code> </td> <td> <div class="doc-md-description"> <p>Original episode title from RSS feed.</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.Episode.title_safe">title_safe</span></code></td> <td> <code><span title="str">str</span></code> </td> <td> <div class="doc-md-description"> <p>Filesystem-safe version of the title for use in filenames.</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.Episode.item">item</span></code></td> <td> <code><span title="xml.etree.ElementTree.Element">Element</span></code> </td> <td> <div class="doc-md-description"> <p>Original XML element from the RSS feed containing all episode data.</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.Episode.transcript_urls">transcript_urls</span></code></td> <td> <code><span title="typing.List">List</span>[<span title="typing.Tuple">Tuple</span>[<span title="str">str</span>, <span title="typing.Optional">Optional</span>[<span title="str">str</span>]]]</code> </td> <td> <div class="doc-md-description"> <p>List of (url, mime_type) tuples for available transcripts.</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.Episode.media_url">media_url</span></code></td> <td> <code><span title="typing.Optional">Optional</span>[<span title="str">str</span>]</code> </td> <td> <div class="doc-md-description"> <p>URL of the podcast media file (audio/video). None if not available.</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.Episode.media_type">media_type</span></code></td> <td> <code><span title="typing.Optional">Optional</span>[<span title="str">str</span>]</code> </td> <td> <div class="doc-md-description"> <p>MIME type of the media file (e.g., "audio/mpeg"). None if not available.</p> </div> </td> </tr> </tbody> </table> <details class="example" open> <summary>Example</summary> <blockquote> <blockquote> <blockquote> <p>episode = Episode( ... idx=0, ... title="Episode 1: Introduction", ... title_safe="episode-1-introduction", ... item=xml_element, ... transcript_urls=[("https://example.com/transcript.vtt", "text/vtt")], ... media_url="https://example.com/audio.mp3", ... media_type="audio/mpeg" ... )</p> </blockquote> </blockquote> </blockquote> </details> <div class="doc doc-children"> </div> </div> </div> <div class="doc doc-object doc-class"> <h3 id="podcast_scraper.models.TranscriptionJob" class="doc doc-heading"> <code class="doc-symbol doc-symbol-heading doc-symbol-class"></code> <span class="doc doc-object-name doc-class-name">TranscriptionJob</span> <span class="doc doc-labels"> <small class="doc doc-label doc-label-dataclass"><code>dataclass</code></small> </span> <a href="#podcast_scraper.models.TranscriptionJob" class="headerlink" title="Permanent link">¶</a></h3> <div class="doc-signature highlight"><pre><span></span><code><span class="nf">TranscriptionJob</span><span class="p">(</span><span class="n">idx</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">ep_title</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">ep_title_safe</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">temp_media</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">detected_speaker_names</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">episode</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Episode</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">media_download_elapsed</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">float</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> </code></pre></div> <div class="doc doc-contents first"> <p>Represents a media transcription job for Whisper.</p> <p>This dataclass tracks information needed to transcribe a podcast episode's media file using Whisper. It includes episode metadata and paths to temporary media files, along with any detected speaker names for diarization.</p> <p><span class="doc-section-title">Attributes:</span></p> <table> <thead> <tr> <th>Name</th> <th>Type</th> <th>Description</th> </tr> </thead> <tbody> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.TranscriptionJob.idx">idx</span></code></td> <td> <code><span title="int">int</span></code> </td> <td> <div class="doc-md-description"> <p>Episode index in the feed (0-based, starting from most recent).</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.TranscriptionJob.ep_title">ep_title</span></code></td> <td> <code><span title="str">str</span></code> </td> <td> <div class="doc-md-description"> <p>Original episode title from RSS feed.</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.TranscriptionJob.ep_title_safe">ep_title_safe</span></code></td> <td> <code><span title="str">str</span></code> </td> <td> <div class="doc-md-description"> <p>Filesystem-safe version of the title for output filenames.</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.TranscriptionJob.temp_media">temp_media</span></code></td> <td> <code><span title="str">str</span></code> </td> <td> <div class="doc-md-description"> <p>Path to the temporary downloaded media file to transcribe.</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.TranscriptionJob.detected_speaker_names">detected_speaker_names</span></code></td> <td> <code><span title="typing.Optional">Optional</span>[<span title="typing.List">List</span>[<span title="str">str</span>]]</code> </td> <td> <div class="doc-md-description"> <p>Optional list of speaker names detected from episode metadata or show notes. Used for screenplay formatting if available.</p> </div> </td> </tr> <tr class="doc-section-item"> <td><code><span title="podcast_scraper.models.TranscriptionJob.episode">episode</span></code></td> <td> <code><span title="typing.Optional">Optional</span>[<a class="autorefs autorefs-internal" title=" Episode dataclass (podcast_scraper.models.entities.Episode)" href="#podcast_scraper.models.Episode">Episode</a>]</code> </td> <td> <div class="doc-md-description"> <p>Optional reference to the source Episode (for metrics and stable IDs).</p> </div> </td> </tr> </tbody> </table> <details class="example" open> <summary>Example</summary> <blockquote> <blockquote> <blockquote> <p>job = TranscriptionJob( ... idx=0, ... ep_title="Episode 1: Introduction", ... ep_title_safe="episode-1-introduction", ... temp_media="/tmp/episode-1.mp3", ... detected_speaker_names=["Alice", "Bob"] ... )</p> </blockquote> </blockquote> </blockquote> </details> <div class="doc doc-children"> </div> </div> </div><h2 id="usage-examples">Usage Examples<a class="headerlink" href="#usage-examples" title="Permanent link">¶</a></h2> <h3 id="working-with-episodes">Working with Episodes<a class="headerlink" href="#working-with-episodes" title="Permanent link">¶</a></h3> <div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">podcast_scraper.models</span> <span class="kn">import</span> <span class="n">Episode</span> <span class="n">episode</span> <span class="o">=</span> <span class="n">Episode</span><span class="p">(</span> <span class="n">number</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="s2">"Example Episode"</span><span class="p">,</span> <span class="n">link</span><span class="o">=</span><span class="s2">"https://example.com/episode-1"</span><span class="p">,</span> <span class="n">transcript_url</span><span class="o">=</span><span class="s2">"https://example.com/transcript.txt"</span><span class="p">,</span> <span class="n">media_url</span><span class="o">=</span><span class="s2">"https://example.com/audio.mp3"</span><span class="p">,</span> <span class="n">media_type</span><span class="o">=</span><span class="s2">"audio/mpeg"</span> <span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Episode </span><span class="si">{</span><span class="n">episode</span><span class="o">.</span><span class="n">number</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">episode</span><span class="o">.</span><span class="n">title</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Transcript: </span><span class="si">{</span><span class="n">episode</span><span class="o">.</span><span class="n">transcript_url</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> </code></pre></div> <h3 id="working-with-feeds">Working with Feeds<a class="headerlink" href="#working-with-feeds" title="Permanent link">¶</a></h3> <div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">podcast_scraper.models</span> <span class="kn">import</span> <span class="n">RssFeed</span><span class="p">,</span> <span class="n">Episode</span> <span class="c1"># Create episodes</span> <span class="n">ep1</span> <span class="o">=</span> <span class="n">Episode</span><span class="p">(</span><span class="n">number</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="s2">"Ep 1"</span><span class="p">,</span> <span class="n">link</span><span class="o">=</span><span class="s2">"..."</span><span class="p">,</span> <span class="n">media_url</span><span class="o">=</span><span class="s2">"..."</span><span class="p">)</span> <span class="n">ep2</span> <span class="o">=</span> <span class="n">Episode</span><span class="p">(</span><span class="n">number</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="s2">"Ep 2"</span><span class="p">,</span> <span class="n">link</span><span class="o">=</span><span class="s2">"..."</span><span class="p">,</span> <span class="n">media_url</span><span class="o">=</span><span class="s2">"..."</span><span class="p">)</span> <span class="c1"># Create feed</span> <span class="n">feed</span> <span class="o">=</span> <span class="n">RssFeed</span><span class="p">(</span> <span class="n">title</span><span class="o">=</span><span class="s2">"Example Podcast"</span><span class="p">,</span> <span class="n">description</span><span class="o">=</span><span class="s2">"A great podcast"</span><span class="p">,</span> <span class="n">link</span><span class="o">=</span><span class="s2">"https://example.com"</span><span class="p">,</span> <span class="n">episodes</span><span class="o">=</span><span class="p">[</span><span class="n">ep1</span><span class="p">,</span> <span class="n">ep2</span><span class="p">]</span> <span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Feed: </span><span class="si">{</span><span class="n">feed</span><span class="o">.</span><span class="n">title</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Episodes: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">feed</span><span class="o">.</span><span class="n">episodes</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> </code></pre></div> <h2 id="see-also">See Also<a class="headerlink" href="#see-also" title="Permanent link">¶</a></h2> <ul> <li><a href="../../architecture/ARCHITECTURE/">RSS Parser</a> - How these models are populated</li> <li><a href="../CORE/">Core API</a> - How to run the pipeline using these models</li> </ul> </article> </div> <script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script> </div> </main> <footer class="md-footer"> <div class="md-footer-meta md-typeset"> <div class="md-footer-meta__inner md-grid"> <div class="md-copyright"> Made with <a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener"> Material for MkDocs </a> </div> <div class="md-social"> <a href="https://github.com/chipi" target="_blank" rel="noopener" title="GitHub" class="md-social__link"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg> </a> </div> </div> </div> </footer> </div> <div class="md-dialog" data-md-component="dialog"> <div class="md-dialog__inner md-typeset"></div> </div> <script id="__config" type="application/json">{"annotate": null, "base": "../..", "features": ["navigation.instant", "navigation.tracking", "navigation.indexes", "content.code.copy", "toc.integrate"], "search": "../../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": {"id": "stable", "label": "v2.0.0", "provider": "manual"}}</script> <script src="../../assets/javascripts/bundle.79ae519e.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script> <script src="../../javascripts/mermaid.js"></script> <script src="../../javascripts/deploy-info.js"></script> </body> </html>