iArt.ai
AI motion graphics software — the After Effects alternative anyone can use. Create animations and explainer videos from a text prompt in minutes.
Every podcast with a feed — on any host. Self-hosted shows, every hosting platform, and the big network libraries.
MediaTypeScript · JavaScriptGitHub @profullstackOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Directory of independent, self-hosted podcasts — 22,386 shows on their own domains
Translation pending
Loading the full README.
Read the full README ↗Every podcast with a feed — on any host.
The live part of the Podcast Index (about 9% of its 4.7M feeds) plus the big network libraries that publish RSS: shows on their own domain, shows on Anchor, Buzzsprout, Libsyn and every other host, and TWiT, NPR, BBC, CBC, ABC Australia, PRX, Relay FM and the other networks. Hundreds of thousands of shows.
Any host qualifies. A feed is listed when it:
Near-identical copies of one feed on the same host are collapsed.
platform_hosts, measured
at every rebuild). It is a label on the show ("Hosted on Buzzsprout"), not a filter.
Until 2026-10 it was the filter: the directory listed only the shows below that line./self-hosted./networks groups the broadcasters and podcast networks whose whole library is RSS,
each at /networks/<slug>.93% of live feeds sit on a domain in the global top million, because they are on the same twenty platforms. Domain popularity measures the platform, never the show, and would bury every show on its own small domain. Shows are ordered by catalogue depth and longevity, weighted by recency.
Next.js (App Router) on Node, Postgres through
@profullstack/libsql-pg, which keeps the
@libsql/client surface the queries were written against. The schema is
db/schema.pg.sql. Search is a weighted tsvector expression index (p0d_search_vector);
raw input is tokenised before it reaches to_tsquery, which treats punctuation as query
syntax and would otherwise 500.
Every show page carries its full episode list, read live from the publisher's own feed
and cached for half an hour — nothing about episodes is stored here. Playing one hands it
to a player that lives in the root layout and keeps running while you move around the
site, which is why every internal link is a next/link: a plain <a href> reloads
the document and takes the audio with it.
About 8% of the directory still serves its mp3s over plain http, which a browser on an
https page refuses to play and no CSP can permit. Those go through /api/audio, which
streams them over TLS with Range passed through in both directions. The URL is
HMAC-signed with AUTH_SECRET so the route cannot be used as an open proxy.
A publisher's feed is the slowest thing on a show page, so the episode list is wrapped in
<Suspense> and streams in behind the rest of the page: first byte stays ~100ms whether
the feed answers in 200ms or nine seconds.
Emailed magic link plus passkeys, the house pattern — there is no password. Opening the
link is the registration, so an unknown address makes the account; /signup and
/login are the same component with different wording. The endpoint answers "if that
address can receive mail, a link is on its way" whether or not the address is known,
whether it was rate limited, and even when Resend is down, so it cannot be used to
enumerate who has an account.
Signed-in state is fetched from /api/me in the browser rather than read from cookies in
the root layout. A single cookies() call there would opt every show page out of
static rendering.
Every table is created by db/schema.pg.sql (idempotent; psql "$DATABASE_URL" -f db/schema.pg.sql). The account tables live in the same Postgres database as
podcasts but the directory rebuild never touches them, and
follows keys shows by slug — the reload reassigns podcasts.id, so a numeric key
would silently repoint everyone's follows at other shows.
| Variable | Needed for |
|---|---|
DATABASE_URL | the database, postgres://...; the app refuses to start on anything else (schema: db/schema.pg.sql) |
AUTH_SECRET | session and audio-proxy signing. Required in production |
RESEND_API_KEY | sending the magic link. Without it, outside production, the link is printed to the console instead |
SUBMIT_FORWARD_TO | where /api/submit also sends a listed feed. Defaults to https://rssamplifier.com in production; set it empty to stop forwarding |
ADMIN_EMAILS | comma-separated addresses that may review submissions at /admin/submissions and get an email per submission. Defaults to the operator's address in src/lib/review.ts |
CRAWLER_TOKENS | comma-separated name:token pairs for our own crawlers. A POST /api/submit with header x-crawler-token: <token> is recorded as submitted_by = crawler:<name>, skips the hourly per-address limit, and a feed that passes the rules is listed at once (no review queue, no admin email). Everything else still waits for review |
COINPAY_X402_KEY, CRAWL_PAY_TO | selling crawl access to AI training crawlers (see below). Until both are set, training crawlers get 402 with an empty offer: nothing is sold, nothing is given away |
python3 ../p0dcasters-data/export_indie.py # writes p0dcasters.db (the whole live catalogue, every host; the name is historical)
DATABASE_URL=postgres://... node scripts/load_directory.mjs
This is the beginning of the README. Read the rest at the original. Read the full README ↗