PortCast

Open protocol · v0.1.0 draft

Take your podcast
listening history with you.

PortCast is a small, open JSON protocol for exporting and importing a listener’s podcast subscriptions, play state, queue, bookmarks, and preferences — so changing apps doesn’t mean starting over.

Created by Trimplayer. Free for anyone to implement.

One file. Everything that matters.

Subscriptions

Feeds with tags, identifiers, follow dates — identified by <podcast:guid> when available.

Episode state

unplayed · in_progress · completed · archived, plus position, play count, ratings, stars.

Playback events

Optional event log — play, pause, seek, speed change — so apps can reconstruct how an episode was actually consumed.

Queue

Ordered “up next” that survives switching apps.

Bookmarks & clips

Time-stamped notes inside an episode. Promote to a clip with an end timestamp.

Preferences

Global and per-feed: playback rate, skip intro/outro, trim silence, auto-download policy.

Why a new protocol?

OPML rescues your subscriptions, and nothing else. Per-app exports (Apple, Spotify, Pocket Casts) ship in different, mostly-private shapes. There is no neutral, listener-owned format for the rest of the relationship a listener builds with their podcasts.

PortCast aims to be:

  • Vendor-neutral. No central server, no required account. The user owns the file.
  • Identity-correct. Matches podcasts by the podcast:guid standard, with feedUrl fallback. Matches episodes by RSS item <guid>, with enclosureUrl fallback.
  • Lossless within scope, extensible outside it. Anything outside the spec lives under a reverse-DNS-keyed extensions block that every consumer must preserve.
  • Tiny. One JSON file. One schema. No required dependency on any podcast directory.
{
  "portcast": "0.1.0",
  "generatedAt": "2026-05-26T14:00:00Z",
  "generator": { "name": "Trimplayer", "version": "3.4.1" },
  "subscriptions": [
    {
      "subscriptionId": "01HXYZ...",
      "feedUrl": "https://feeds.example.com/pl.xml",
      "podcastGuid": "917393e3-1b1e-5cef-ace4-edaa54e1f810",
      "title": "Portable Listening Weekly",
      "tags": ["tech"],
      "updatedAt": "2026-05-26T14:00:00Z"
    }
  ],
  "episodes": [
    {
      "subscriptionRef": { "podcastGuid": "917393e3-..." },
      "guid": "https://feeds.example.com/pl/ep/42",
      "status": "in_progress",
      "positionSeconds": 1245.2,
      "lastPlayedAt": "2026-05-25T08:11:00Z",
      "updatedAt": "2026-05-25T08:11:00Z"
    }
  ]
}

Spec & schema

The protocol is defined in SPECIFICATION.md and machine-validated by a JSON Schema (draft 2020-12). A realistic sample document ships in the repo. The spec is published under CC BY 4.0; the reference code under MIT.

Implement it

A Python reference implementation lives in reference/: dataclass models, schema-driven validator, OPML ↔ PortCast bridge, and a CLI.

git clone https://github.com/Trim-Player/PortCast.git
cd PortCast/reference
pip install -e ".[dev]"

portcast validate              ../examples/sample-export.portcast.json
portcast opml-to-portcast      my-subs.opml -o my.portcast.json
portcast inspect               my.portcast.json

Building an importer or exporter for another podcast app, or an implementation in another language? Open an issue — we’d like to link your work here.