A modern podcast transcript forum with a tech-forward UI for browsing, searching, and reading podcast transcripts. Features category/host filtering, fuzzy search, multi-language transcript support, and responsive cross-device design.
0
stars
101
commits
JavaScript
primary language
Apr 26, 2026
updated
A modern podcast transcript forum for browsing, searching, and contributing podcast transcripts across multiple languages.
| Dark | Light |
|---|---|
![]()
![]()
| Layer | Tech |
|---|---|
| Frontend | React 19, Vite 8, CSS Variables |
| Backend | Express 5, Node.js |
| Database | SQLite (better-sqlite3) with WAL mode, FTS5 trigram search |
| Testing | Jest, Supertest |
# Install dependencies
npm install
cd client && npm install && cd ..
# Seed the database (optional)
npm run seed
# Development (two terminals)
npm run dev:server # Express API on :4010
npm run dev:client # Vite dev server on :5173
# Production build
npm run build
npm start # Serves both API and built frontend on :4010
├── client/ # React frontend
│ ├── src/
│ │ ├── components/ # Header, Sidebar, MediaPlayer, TranscriptEditor, ...
│ │ ├── pages/ # Home, Episode, Podcast, Search, Upload
│ │ └── styles/ # Global CSS, theme variables
│ └── vite.config.js
├── server/ # Express backend
│ └── src/
│ ├── routes/ # podcasts, episodes, search, upload, revisions
│ ├── db.js # SQLite setup + FTS5 trigram migration
│ └── index.js # Express app
├── scripts/ # Utility scripts (seed, crawl, ASR, translation)
├── tests/ # API test suite
└── data/ # SQLite database (gitignored)
All endpoints are under /api.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/health | Health check |
| GET | /api/podcasts | List all podcasts |
| POST | /api/podcasts | Create a podcast |
| GET | /api/podcasts/:id | Get podcast with episodes |
| GET | /api/episodes/:id | Get episode with transcripts |
| GET | /api/search?q=...&type=... | Full-text search |
| POST | /api/upload | Anonymous upload (podcast + episode + transcript) |
| GET | /api/episodes/:id/revisions | Revision history |
| POST | /api/episodes/:id/revisions/:sha/restore | Restore a revision |
npm test
Runs the full API test suite (~50 test cases) covering CRUD operations, search, multi-language transcripts, revisions, uploads, and cascade deletes.
| Script | Description |
|---|---|
npm run seed | Seed database with sample data |
npm run crawl | Crawl podcast sources for episode inventory and RSS transcripts; YouTube episodes are queued for ASR-first processing |
node scripts/asr-zh.js | Local ASR pipeline for Chinese podcasts |
node scripts/translate-to-zh.js | Translate English transcripts to Chinese from ASR/polished English sources |
node scripts/batch-polish.js | LLM-powered transcript polishing |
python3 scripts/batch_transcribe.py --podcast 'Planet Money' --limit=5 | Batch transcribe missing audio-only episodes with GPU-to-CPU OOM fallback |
python3 scripts/batch_transcribe_youtube.py --podcast '不明白播客' --limit=5 | Batch transcribe missing YouTube episodes with ASR-first OOM-safe fallback |
npm run audit:podcast -- --podcast-id=23 | Audit one podcast for duplicate translations, speaker-label drift, and source-language mismatches |
node scripts/repair-podcast-23.js --episodes=... | Repair Dwarkesh Podcast batches by recovering sources, canonicalizing speaker labels, and deduplicating translations |
npm run audit:inline-speakers | Scan all polished transcripts for speaker tags that appear mid-paragraph instead of starting a new paragraph |
npm run fix:inline-speakers | Split inline speaker tags into proper paragraph starts across the transcript database |
node scripts/audit-english-transcripts.js | Audit all English podcasts for missing transcripts, asr-only episodes, malformed tags, and generic speaker labels |
node scripts/fix-english-polish-format.js --podcast-id=25 | Normalize malformed English llm_polish formatting such as broken timestamp-speaker lines |
node scripts/normalize-english-speakers.js --podcast-id=11 | Deterministically replace generic English speaker labels using host, title, and description hints |
This repo now includes repo-local Codex skills under .codex/skills for the two workflows that are most repetitive here:
podcast-transcript-pipeline for episode updates, ASR, repolish, postprocess, inline-speaker cleanup, and transcript QA.podcast-forum-deploy for main-repo builds, newserver deployment, restart, and verification.podcast-quality-repair for podcast-level audit and fast repair planning when speaker labels, transcript language, translation rows, or paragraph splits drift over time.Transcript policy: for YouTube episodes, start from ASR as the default source of truth. Legacy youtube_auto and youtube_manual rows can exist in old data, but new repair and ingestion flows should replace them instead of building on them.
ISC
101 commits
JavaScript
80.2%
CSS
13.0%
Python
6.0%
A modern podcast transcript forum with a tech-forward UI for browsing, searching, and reading podcast transcripts. Features category/host filtering, fuzzy search, multi-language transcript support, and responsive cross-device design.
0
stars
101
commits
JavaScript
primary language
Apr 26, 2026
updated
A modern podcast transcript forum for browsing, searching, and contributing podcast transcripts across multiple languages.
| Dark | Light |
|---|---|
![]()
![]()
| Layer | Tech |
|---|---|
| Frontend | React 19, Vite 8, CSS Variables |
| Backend | Express 5, Node.js |
| Database | SQLite (better-sqlite3) with WAL mode, FTS5 trigram search |
| Testing | Jest, Supertest |
# Install dependencies
npm install
cd client && npm install && cd ..
# Seed the database (optional)
npm run seed
# Development (two terminals)
npm run dev:server # Express API on :4010
npm run dev:client # Vite dev server on :5173
# Production build
npm run build
npm start # Serves both API and built frontend on :4010
├── client/ # React frontend
│ ├── src/
│ │ ├── components/ # Header, Sidebar, MediaPlayer, TranscriptEditor, ...
│ │ ├── pages/ # Home, Episode, Podcast, Search, Upload
│ │ └── styles/ # Global CSS, theme variables
│ └── vite.config.js
├── server/ # Express backend
│ └── src/
│ ├── routes/ # podcasts, episodes, search, upload, revisions
│ ├── db.js # SQLite setup + FTS5 trigram migration
│ └── index.js # Express app
├── scripts/ # Utility scripts (seed, crawl, ASR, translation)
├── tests/ # API test suite
└── data/ # SQLite database (gitignored)
All endpoints are under /api.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/health | Health check |
| GET | /api/podcasts | List all podcasts |
| POST | /api/podcasts | Create a podcast |
| GET | /api/podcasts/:id | Get podcast with episodes |
| GET | /api/episodes/:id | Get episode with transcripts |
| GET | /api/search?q=...&type=... | Full-text search |
| POST | /api/upload | Anonymous upload (podcast + episode + transcript) |
| GET | /api/episodes/:id/revisions | Revision history |
| POST | /api/episodes/:id/revisions/:sha/restore | Restore a revision |
npm test
Runs the full API test suite (~50 test cases) covering CRUD operations, search, multi-language transcripts, revisions, uploads, and cascade deletes.
| Script | Description |
|---|---|
npm run seed | Seed database with sample data |
npm run crawl | Crawl podcast sources for episode inventory and RSS transcripts; YouTube episodes are queued for ASR-first processing |
node scripts/asr-zh.js | Local ASR pipeline for Chinese podcasts |
node scripts/translate-to-zh.js | Translate English transcripts to Chinese from ASR/polished English sources |
node scripts/batch-polish.js | LLM-powered transcript polishing |
python3 scripts/batch_transcribe.py --podcast 'Planet Money' --limit=5 | Batch transcribe missing audio-only episodes with GPU-to-CPU OOM fallback |
python3 scripts/batch_transcribe_youtube.py --podcast '不明白播客' --limit=5 | Batch transcribe missing YouTube episodes with ASR-first OOM-safe fallback |
npm run audit:podcast -- --podcast-id=23 | Audit one podcast for duplicate translations, speaker-label drift, and source-language mismatches |
node scripts/repair-podcast-23.js --episodes=... | Repair Dwarkesh Podcast batches by recovering sources, canonicalizing speaker labels, and deduplicating translations |
npm run audit:inline-speakers | Scan all polished transcripts for speaker tags that appear mid-paragraph instead of starting a new paragraph |
npm run fix:inline-speakers | Split inline speaker tags into proper paragraph starts across the transcript database |
node scripts/audit-english-transcripts.js | Audit all English podcasts for missing transcripts, asr-only episodes, malformed tags, and generic speaker labels |
node scripts/fix-english-polish-format.js --podcast-id=25 | Normalize malformed English llm_polish formatting such as broken timestamp-speaker lines |
node scripts/normalize-english-speakers.js --podcast-id=11 | Deterministically replace generic English speaker labels using host, title, and description hints |
This repo now includes repo-local Codex skills under .codex/skills for the two workflows that are most repetitive here:
podcast-transcript-pipeline for episode updates, ASR, repolish, postprocess, inline-speaker cleanup, and transcript QA.podcast-forum-deploy for main-repo builds, newserver deployment, restart, and verification.podcast-quality-repair for podcast-level audit and fast repair planning when speaker labels, transcript language, translation rows, or paragraph splits drift over time.Transcript policy: for YouTube episodes, start from ASR as the default source of truth. Legacy youtube_auto and youtube_manual rows can exist in old data, but new repair and ingestion flows should replace them instead of building on them.
ISC
101 commits
JavaScript
80.2%
CSS
13.0%
Python
6.0%