This directory contains JSON fixture files for ad segment data used in the POC.
Each file is named after the episode key:
- GUID-based: If the episode has a
<guid>in its RSS feed, use that GUID (sanitized for filenames) - Hash-based: If no GUID, the filename will be the hash generated from
feedUrl + enclosureUrl + pubDate
Example filenames:
https___example_com_podcast_episode_123.json(GUID-based, sanitized)abc123def456.json(hash-based, hash prefix removed)
Each JSON file should have the following structure:
{
"episodeKey": "https://example.com/podcast/episode-123",
"feedUrl": "https://example.com/podcast/feed.xml",
"enclosureUrl": "http://localhost:3000/test-podcasts/episode1.mp3",
"adSegments": [
{
"id": "ad-001",
"startTime": 30,
"endTime": 60,
"description": "Pre-roll ad",
"taggerPubkey": "npub1test1abc..."
},
{
"id": "ad-002",
"startTime": 300,
"endTime": 330,
"description": "Mid-roll sponsor read",
"taggerPubkey": "npub1test2def..."
}
],
"chapters": [
{
"startTime": "00:00:00",
"title": "Introduction"
},
{
"startTime": "00:05:30",
"title": "Main Topic"
},
{
"startTime": "00:15:45",
"title": "Conclusion"
}
]
}episodeKey(string): The episode identifier (GUID or hash)adSegments(array): Array of ad segment objects
id(string): Unique identifier for this ad segmentstartTime(number): Start time in seconds (required)endTime(number): End time in seconds (required, must be > startTime)description(string, optional): Human-readable descriptiontaggerPubkey(string): Nostr public key of the tagger (required)taggedAt(number, optional): Unix timestamp when taggedconfidence(number, optional): Confidence score 0-100
feedUrl(string): Podcast RSS feed URL (for fallback hash generation)enclosureUrl(string): Episode media URL (for fallback hash generation)pubDate(string): Publication date (for fallback hash generation)chapters(array): Optional chapter data for POC test fixtures
startTime(number|string): Start time (supports both numeric seconds and "HH:MM:SS" strings)title(string): Chapter titleimg(string, optional): Chapter image URLurl(string, optional): Chapter link URLendTime(number|string, optional): End time (calculated from next chapter if missing)
- Place your test MP3 files in
public/test-podcasts/ - Listen to each MP3 file and note the start/end times of ad segments
- Edit the corresponding JSON file's
adSegmentsarray - Update
startTimeandendTimevalues (in seconds) - Save the file
- Add
episode1.mp3topublic/test-podcasts/ - Open the corresponding fixture file (e.g.,
test-episode-1.json) - Listen to the MP3 and find ads:
- Pre-roll ad: 0:00 - 0:30 (0 to 30 seconds)
- Mid-roll ad: 5:15 - 5:45 (315 to 345 seconds)
- Post-roll ad: 14:30 - 15:00 (870 to 900 seconds)
- Update the fixture:
{
"episodeKey": "test-episode-1",
"feedUrl": "http://localhost:3000/test-feed.xml",
"enclosureUrl": "http://localhost:3000/test-podcasts/episode1.mp3",
"adSegments": [
{
"id": "ad-001",
"startTime": 0,
"endTime": 30,
"description": "Pre-roll ad",
"taggerPubkey": "npub1tester1"
},
{
"id": "ad-002",
"startTime": 315,
"endTime": 345,
"description": "Mid-roll sponsor read",
"taggerPubkey": "npub1tester2"
},
{
"id": "ad-003",
"startTime": 870,
"endTime": 900,
"description": "Post-roll ad",
"taggerPubkey": "npub1tester1"
}
]
}- Reload the page and test the skip behavior
The following ad segments will be automatically dropped (logged as warnings):
- Missing
endTime endTime<=startTime(invalid range)- Negative
startTimeorendTime - Missing
taggerPubkey
Overlapping ad segments will be automatically merged into non-overlapping intervals.
These fixture files are POC-only. In production:
- Ad segments will be fetched from Nostr relays
- Taggers will be identified by their Nostr keys
- Profiles will come from NIP-01 kind 0 metadata events
- Zaps (NIP-57) will be used for validation/reputation