PodcastRSS.Episode (Podcast RSS v0.3.0)
View SourceRepresents a podcast episode with required and optional fields.
The Episode struct contains the core RSS 2.0 fields needed for podcast episodes. At least one of title or description must be present for a valid episode.
Summary
Functions
Add a chapter to the episode.
Add a custom field to the episode.
Set the episode description.
Set the episode duration.
Set the episode enclosure (media file).
Set the episode GUID (globally unique identifier).
Create a new empty episode.
Register a namespace for use in custom fields.
Set the episode title.
Types
@type enclosure() :: %{url: String.t(), length: non_neg_integer(), type: String.t()}
@type t() :: %PodcastRSS.Episode{ chapters: [chapter()], custom_fields: %{required(String.t()) => custom_field()}, description: String.t() | nil, duration: non_neg_integer() | nil, enclosure: enclosure() | nil, guid: String.t() | nil, namespaces: %{required(String.t()) => String.t()}, title: String.t() | nil }
Functions
Add a chapter to the episode.
Chapters are used for Podlove Simple Chapters (PSC) format. They will be automatically sorted by start_time when generating the XML output.
The start_time accepts various input formats:
- Integer: 1234 (seconds)
- Float: 123.456 (seconds with millisecond precision)
- String seconds: "1234" or "123.456"
- MM:SS format: "12:34"
- MM:SS.ms format: "12:34.567"
- HH:MM:SS format: "01:23:45"
- HH:MM:SS.ms format: "01:23:45.678"
Options
:image- URL to chapter-specific image (optional):url- Related url for the chapter (optional)
Examples
episode = Episode.new()
|> Episode.chapter(0, "Introduction")
|> Episode.chapter("03:00", "Main Topic", url: "https://example.com")
|> Episode.chapter(60.5, "Background") # Will be auto-sorted between first and second
|> Episode.chapter("01:23:45.678", "Chapter with precise timing", image: "https://example.com/img.jpg")
Add a custom field to the episode.
Namespace Handling
If the field name contains a colon (e.g., "itunes:duration"), the namespace prefix
must be registered first using register_namespace/3, or you can use the
:namespace_uri option for one-shot registration.
Options
:attributes- A map of XML attributes for the field (default: %{}):cdata- Whether to wrap content in CDATA (default: false):namespace_uri- URI for one-shot namespace registration (extracts prefix from field name)
Examples
# Method 1: Explicit registration (recommended for multiple fields)
episode = Episode.new()
|> Episode.register_namespace("itunes", "http://www.itunes.com/dtds/podcast-1.0.dtd")
|> Episode.custom_field("itunes:duration", "00:15:30")
|> Episode.custom_field("itunes:explicit", "no")
# Method 2: One-shot registration (convenient for single usage)
episode = Episode.new()
|> Episode.custom_field("itunes:duration", "00:15:30",
namespace_uri: "http://www.itunes.com/dtds/podcast-1.0.dtd")
|> Episode.custom_field("podcast:soundbite", "",
namespace_uri: "https://podcastindex.org/namespace/1.0",
attributes: %{"startTime" => "73.0", "duration" => "60.0"})
|> Episode.custom_field("itunes:explicit", "no") # Uses registered namespace
# Non-namespaced fields
episode
|> Episode.custom_field("author", "John Doe")
|> Episode.custom_field("season", "1", attributes: %{"number" => "1"})
Set the episode description.
Set the episode duration.
Accepts various input formats:
- Integer: 1234 (seconds)
- String seconds: "1234" (seconds)
- MM:SS format: "12:34"
- HH:MM:SS format: "01:23:45"
- HH:MM:SS.ms format: "01:23:45.678" (rounds up fractional seconds)
Returns the episode with the duration set, or raises an ArgumentError for invalid input.
Examples
iex> Episode.new() |> Episode.duration(1234)
%Episode{duration: 1234, ...}
iex> Episode.new() |> Episode.duration("01:23:45")
%Episode{duration: 5025, ...}
iex> Episode.new() |> Episode.duration("invalid")
** (ArgumentError) Invalid duration format: "invalid"
@spec enclosure(t(), String.t(), non_neg_integer(), String.t()) :: t()
Set the episode enclosure (media file).
Set the episode GUID (globally unique identifier).
@spec new() :: t()
Create a new empty episode.
Register a namespace for use in custom fields.
This allows you to use namespaced field names (e.g., "itunes:duration") without having to specify the namespace URI every time.
Examples
episode = Episode.new()
|> Episode.register_namespace("itunes", "http://www.itunes.com/dtds/podcast-1.0.dtd")
|> Episode.custom_field("itunes:duration", "00:15:30") # Uses registered namespace
|> Episode.custom_field("itunes:explicit", "no") # Uses registered namespace
Set the episode title.