A free, no-account podcast player. Search Apple Podcasts or paste any RSS feed URL — stream, resume, queue and download episodes for offline listening. Vite + strict TypeScript frontend, optional Cloudflare Worker backend, installable as a PWA / Microsoft Store / Google Play app.
"Sinyal" design — warm charcoal surfaces, an amber "radio dial glow" accent, and a signature frequency-line waveform motif. Navigation is a bottom tab bar (mobile) / left sidebar (desktop) across four sections — Home (continue-listening + subscriptions), Search, Library (subscriptions/downloads) and Settings — with a full-screen Now Playing sheet for transport, sleep timer, speed and queue access.
Live: https://iacbi.github.io/seseri/ · Windows app: download the installer
Language / Dil: English · Türkçe
| Podcast search | by name, Apple Podcasts link, or a direct RSS feed URL — or start from one of eight topics |
| The whole archive | episode lists come from the show's own feed, so they are the complete back catalogue, not the 200 most recent episodes Apple returns. Parsing happens in the Worker when one is configured (The Daily: 19.95 MB of XML in, 2.28 MB of JSON out) and on the device when it is not |
| Played state | finishing an episode marks it, or mark it yourself; filter a list to All, Unplayed, In progress or Downloaded. Marking an episode unplayed clears its saved position |
| New episodes | what has appeared across every show you follow since you last looked, on the home screen, with an app badge where the platform has one |
| Chapters & transcripts | Podcasting 2.0 chapters as a list plus markers on the scrubber, and VTT/SRT transcripts cue by cue with the playing line highlighted and every line seekable. Both fetched only when opened |
| Offline episodes | downloads live in the Cache API and play (and seek) with no connection, showing a real percentage and cancellable while they run; feeds are cached in IndexedDB, bounded (anything over 30 days old goes, then the oldest until the cache is back under 80 MB, never below five feeds) and refreshed in the background (stale-while-revalidate) |
| Automatic downloads | optionally fetch new episodes of the shows you follow in the background, and optionally delete a download once the episode is finished — finished only, so nothing you are part-way through is removed |
| Play queue | queue any episode as "up next" — the queue wins over list order; own page under Queue |
| Mini transport | leaving a feed keeps playing; the persistent dock carries skip/play controls (plus prev/next & speed on wide screens) and a seekable progress line — the chevron expands the full Now Playing sheet. A title too long for the dock drifts end to end instead of ending in an ellipsis |
| Frequency-line scrubber | signature waveform motif — drag-to-seek hero scrubber in Now Playing, animated line on the mini player while playing |
| Now Playing sheet | full-screen at every size: play/pause, prev/next, skip, speed 0.5×–2.5×, volume, sleep timer, resume position, episode notes |
| Episode links | share a link that opens on that episode, and from Now Playing at the moment you are at |
| Per-show speed | a show can play at its own speed instead of the default; Settings lists the ones that do and resets them |
| Sleep timer | presets or any duration, or stop at the end of the episode; live countdown, +5 min, gentle fade-out, pauses with playback and survives a reload |
| Sharp artwork | the right rendition is requested per surface, so covers are never upscaled from a thumbnail; the Now Playing background can pick up the cover's dominant colour (toggle in Settings → Appearance) |
| Volume | a slider in Now Playing on every device, and in the dock from 1024px up; mute keeps the level you chose. Hidden on iOS, where the page is not allowed to set it and the hardware buttons are the control |
| Desktop layout | ≥900px swaps the tab bar for a persistent left sidebar (Home/Search/Library/Settings). Collapse it to an icon rail from the toggle beside the wordmark or with [; pointing at the rail peeks it open over the page, clicking it pins it open. The language switcher sits in the window's own top corner |
| Subscriptions | star podcasts; live in Library; OPML import/export + JSON backup |
| Themes | Auto (system), Dark, Light, OLED Black; 7 accent colors (amber "dial glow" default) |
| Multilingual | TR / EN / DE / FR / ES / AR / JA / RU (incl. RTL) |
| Installable | PWA with maskable/monochrome icons, shortcuts, store screenshots |
| Accessible | keyboard-operable views, aria-live status/busy states, focus management on navigation, prefers-reduced-motion. A long episode list is one tab stop with arrow-key movement between rows and across each row's buttons, not 2 973 tab stops |
| Private by construction | no analytics, no accounts, and no third-party request to render the interface — the typefaces are served from the app's own origin, so font-src is 'self' alone |
| Recoverable | if start-up fails the app says so, with a reload button and a two-tap data wipe, instead of a blank page. Settings can copy a diagnostics report to the clipboard, which is sent nowhere |
Never while typing in a field. The transport keys follow whatever is playing,
so they work from any view; [, Esc and ? are always live.
| Key | Action |
|---|---|
Space |
Play / pause |
← / → |
Seek back / forward |
↑ / ↓ |
Previous / next episode |
Home / End |
Jump to the start / end of the episode |
[ |
Collapse or expand the sidebar (desktop) |
Esc |
Close the Now Playing sheet |
? |
Show the shortcut list |
↑ / ↓ in a list |
Move between episode rows (← / → for a row's own buttons) |
Optional, off until you turn it on, and account-free. One device generates a pairing code in Settings → Cross-device sync; type it into the other and they share resume positions, the last-played episode per feed, subscriptions and the queue.
The payload is encrypted on the device. Two independent values are derived from the code with HKDF-SHA256 — the id the server stores a row under, and the AES-GCM key — so the backend holds bytes it cannot read.
- Settings are not synced: font size, theme and volume belong to the device.
- A write on each device within a minute of the other is treated as concurrent, and the further position wins.
- Unlinking stops syncing on that device and keeps everything it already has. "Delete server data" removes the stored copy for every device.
- Keep the code. It is the only credential, and losing it loses the synced copy — each device keeps its own data either way.
Requires the Worker (VITE_API_BASE) plus VITE_SYNC=1 at build time. The two
flags are separate on purpose: sync can be switched off without disabling the
feed and iTunes proxies.
npm install # once
npm run dev # http://localhost:5199
# optional backend (feed/iTunes proxy)
npm --prefix worker install # once
npm run worker:dev # http://127.0.0.1:8787The client tries the Worker first (VITE_API_BASE, see .env.development).
Falling back to public CORS proxies is opt-in (Settings → Privacy, off by
default): those operators would see every feed URL opened, and the app races
three of them and parses whichever answers first.
| Script | What it does |
|---|---|
npm run dev / build / preview |
Vite dev server / production build / serve dist |
npm test |
Vitest unit suites (parser, OPML, i18n completeness, proxy chain, formatters) |
npm run lint / typecheck / format |
ESLint · tsc --noEmit · Prettier |
npm run worker:dev / worker:test |
wrangler dev · Worker handler tests |
npm run verify |
lint + typecheck + tests + build + worker typecheck/tests |
npm run smoke |
the seven headless browser smokes CI runs, in order |
node scripts/smoke-shell.cjs |
smoke: boot, navigation, theme and language |
node scripts/smoke-p3-offline.cjs |
smoke: download → offline reload → playback |
node scripts/smoke-p4-worker.cjs |
smoke: real RSS through the local Worker (needs worker:dev) |
node scripts/smoke-p5-mini.cjs |
smoke: mini player, queue, back-navigation |
node scripts/smoke-chapters.cjs |
smoke: chapter list, scrubber markers, transcript cues |
node scripts/smoke-longlist.cjs |
smoke: the render window over a 900-episode archive |
node scripts/smoke-migrate.cjs |
smoke: Apple ids → feed ids, with a real download, queue entry and position |
node scripts/smoke-p6-sync.cjs |
smoke: two devices pairing and converging |
node scripts/smoke-live.cjs [url] |
smoke against the deployed site: search, feed, playback, download from the podcast's own CDN, CSP violations |
node scripts/icons.cjs |
regenerate all PNG icons from public/icons/seseri.svg |
node scripts/store-shots.cjs |
regenerate manifest/store screenshots |
node scripts/shot.cjs [dir] |
regenerate the reference screenshots in docs/screens-v4/ |
.
├── index.html # Vite entry (CSP, meta, manifest link)
├── src/
│ ├── app.ts # boot & wiring
│ ├── lib/ # format helpers, safe DOM/text utils, artwork rendition URLs (art.ts)
│ ├── feeds/ # iTunes / RSS / input parsing / proxy chain / resolveFeed /
│ │ # rss-scan.ts (DOM-free feed scanner, shared with the Worker),
│ │ # archive.ts (Apple→feed id remap), inbox.ts (new episodes),
│ │ # show notes (HTML→text), credential-URL guard for private feeds
│ ├── player/ # audio engine, media session, sleep timer, offline downloads,
│ │ # chapters, transcripts, download jobs, prefetch
│ ├── state/ # signals: settings, queue, now-playing, sleep timer
│ ├── storage/ # localStorage (legacy keys), IndexedDB, OPML
│ ├── ui/
│ │ ├── playback-controller.ts # headless playback session, shared by every view
│ │ ├── views/ # home, search, library, podcast, queue, settings, now-playing
│ │ ├── views.ts # view registry (show/hide, focus hand-off)
│ │ ├── nav.ts # tab bar / sidebar controller
│ │ ├── router.ts # ?podcast= / ?rss= / ?view= ↔ history
│ │ └── shell.ts, theme.ts, mini-player.ts, waveform.ts, art-tile.ts, ambient.ts,
│ │ sleep-control.ts, volume-control.ts, marquee.ts, fit-select.ts,
│ │ shortcuts.ts, number-prompt.ts, toast.ts, confirm.ts, …
│ ├── i18n/ # 8 languages, compile-time key completeness
│ ├── styles/
│ │ ├── fonts.css, fonts/ # the three typefaces, self-hosted
│ │ ├── tokens.css, themes.css, base.css, layout.css, controls.css,
│ │ │ overlays.css, signal-line.css # design-system layers
│ │ ├── views/ # one stylesheet per view (home, search, library, podcast,
│ │ │ # queue, settings, now-playing)
│ │ └── index.css # barrel import
│ └── sw.ts # service worker (injectManifest)
├── worker/ # Cloudflare Worker API (Hono): /v1/feed /v1/parse /v1/itunes /v1/sync
├── public/ # manifest, icons (incl. maskable/monochrome), screenshots,
│ # privacy-policy, 404
├── scripts/ # icon/screenshot generators + headless smoke tests
└── docs/ # TESTPLAN, STORE guide, reference screenshots
worker/ is a Cloudflare Worker (free tier friendly): RSS/iTunes proxying with
edge caching and SSRF guards. Deploy with npx wrangler deploy,
then set VITE_API_BASE to the workers.dev URL at build time. See
docs/STORE.md for the full release pipeline.
- Windows: a Tauri v2 shell (
desktop/) wraps the live site in WebView2 — a ~1.8 MB NSIS installer published on GitHub Releases; the app updates itself with every web deploy. - Google Play: TWA package produced from the live PWA with PWABuilder.
- Step-by-step release guide: docs/STORE.md.
No analytics, no accounts. Settings/progress stay in localStorage; downloads
stay in your browser's Cache API. Feed URLs that carry a private/subscriber
token (Patreon, Memberful, Substack-style) are never sent to the public CORS
proxies — they only go through the app's own Worker, and fail with a clear
message if none is configured; ordinary public feeds are unaffected. See
public/privacy-policy.html.
𝓐.𝓒.𝓑 — bozdogancanahmet@gmail.com · MIT © 2026
Ücretsiz, üyeliksiz podcast dinleyici. Apple Podcasts'te ara veya RSS linki yapıştır — çal, kaldığın yerden devam et, kuyruğa ekle, bölümleri çevrimdışı dinlemek için indir. Vite + strict TypeScript ön yüz, isteğe bağlı Cloudflare Worker arka ucu; PWA / Microsoft Store / Google Play uygulaması olarak kurulabilir.
"Sinyal" tasarımı — sıcak antrasit yüzeyler, kehribar "radyo kadranı" vurgusu ve imza niteliğindeki frekans-çizgisi dalga-form motifi. Gezinme; alttan sekme çubuğu (mobil) / soldan kenar çubuğu (masaüstü) olmak üzere dört bölümden oluşur — Ana Sayfa (kaldığın yerden devam et + abonelikler), Ara, Kütüphane (abonelikler/indirilenler) ve Ayarlar — ayrıca oynatma, uyku zamanlayıcısı, hız ve kuyruğa erişim için tam ekran Şimdi Çalıyor paneli.
Canlı: https://iacbi.github.io/seseri/ · Windows uygulaması: kurulumu indir
| Podcast arama | isim, Apple Podcasts linki veya doğrudan RSS URL'si — ya da sekiz konu başlığından biriyle başla |
| Arşivin tamamı | bölüm listeleri yayının kendi feed'inden gelir, yani Apple'ın döndürdüğü son 200 bölüm değil, arşivin tümü. Worker yapılandırılmışsa ayrıştırma orada olur (The Daily: 19,95 MB XML girer, 2,28 MB JSON çıkar), yapılandırılmamışsa cihazda |
| Dinlendi durumu | bölümü bitirmek işaretler, istersen kendin de işaretlersin; liste Tümü, Dinlenmemiş, Devam eden veya İndirilenler olarak süzülür. Bir bölümü dinlenmedi işaretlemek kayıtlı konumunu da siler |
| Yeni bölümler | takip ettiğin yayınlarda en son baktığından bu yana ne çıktıysa ana sayfada toplanır, platform destekliyorsa uygulama nişanıyla |
| Bölüm işaretleri & konuşma metni | Podcasting 2.0 bölüm işaretleri liste olarak, ayrıca sarma çizgisinde işaretlerle; VTT/SRT konuşma metni satır satır, çalan satır vurgulu ve her satır sarılabilir. İkisi de ancak açtığında indirilir |
| Çevrimdışı bölümler | indirilenler Cache API'de yaşar, bağlantısız çalar ve sarar; inerken gerçek yüzde gösterir ve iptal edilebilir. Feed'ler IndexedDB'de önbelleklenir ve sınırlıdır (30 günden eskiler atılır, sonra 80 MB'ın altına düşene kadar en eskiler — ama hiçbir zaman beş feed'in altına inmez); arka planda tazelenir |
| Otomatik indirme | takip ettiğin yayınların yeni bölümleri istersen arka planda indirilir; istersen bölüm bitince indirilen kopya silinir — yalnızca bitenler, yarısında bıraktığın hiçbir şey kaldırılmaz |
| Kuyruk | bölümü "sıradaki" olarak işaretle — kuyruk, liste sırasından önce gelir; kendi sayfası Kuyruk görünümünde |
| Mini transport | feed'den çıkınca çalma sürer; kalıcı dock üzerinde atlama/oynat kontrolleri (geniş ekranda önceki/sonraki ve hız) ve dokunarak sarılabilir ilerleme çizgisi — ok simgesi tam Şimdi Çalıyor panelini açar. Dock'a sığmayan başlık üç nokta ile kesilmek yerine baştan sona kayar |
| Frekans-çizgisi dalga-form | imza motif — Şimdi Çalıyor panelinde sürüklenebilir kahraman dalga-form, çalarken mini oynatıcıda animasyonlu çizgi |
| Şimdi Çalıyor paneli | her ekran boyutunda tam ekran: oynat/duraklat, önceki/sonraki, atlama, 0.5×–2.5× hız, ses düzeyi, uyku zamanlayıcısı, kaldığın yerden devam etme, bölüm notları |
| Bölüm linkleri | o bölümü açan bir link paylaş; Şimdi Çalıyor panelinden paylaşırsan bulunduğun andan açılır |
| Yayın başına hız | bir yayın varsayılan hız yerine kendi hızıyla çalabilir; Ayarlar bunları listeler ve sıfırlar |
| Uyku zamanlayıcısı | hazır süreler veya istediğin süre, ya da bölüm sonunda dur; canlı geri sayım, +5 dk, yumuşak sesle kısılma, duraklatınca durur ve sayfa yenilenince kaybolmaz |
| Net kapak görselleri | her yüzey için doğru çözünürlük istenir, kapaklar küçük bir görselden büyütülmez; Şimdi Çalıyor arka planı kapağın baskın rengini alabilir (Ayarlar → Görünüm'den kapatılabilir) |
| Ses düzeyi | her cihazda Şimdi Çalıyor panelinde, 1024px'ten itibaren dock'ta da bir sürgü; sessize alma seçtiğin seviyeyi korur. iOS'ta gizlenir — orada sayfanın ses düzeyini ayarlamasına izin verilmez, kontrol donanım tuşlarındadır |
| Masaüstü düzeni | ≥900px'te sekme çubuğu yerini kalıcı soldan kenar çubuğuna bırakır (Ana Sayfa/Ara/Kütüphane/Ayarlar). Kelime markasının yanındaki düğmeyle ya da [ tuşuyla simge şeridine daraltılır; şeridin üzerine gelince sayfanın üstünde geçici olarak açılır, tıklayınca açık kalır. Dil seçici pencerenin kendi üst köşesinde durur |
| Abonelikler | yıldızla; Kütüphane'de yaşar; OPML içe/dışa aktarma + JSON yedek |
| Temalar | Otomatik (sistem), Koyu, Açık, OLED Siyah; 7 vurgu rengi (varsayılan kehribar "kadran ışıltısı") |
| Çok dilli | TR / EN / DE / FR / ES / AR / JA / RU (RTL dahil) |
| Kurulabilir | maskable/monochrome ikonlu PWA, kısayollar, mağaza görselleri |
| Erişilebilir | klavyeyle kullanılabilir görünümler, aria-live durum/busy, gezinmede odak yönetimi, prefers-reduced-motion. Uzun bir bölüm listesi 2 973 sekme durağı değil, tek durak: satırlar arasında ve satırın düğmeleri arasında ok tuşlarıyla gezilir |
| Yapısı gereği özel | analitik yok, hesap yok, arayüzü çizmek için üçüncü taraf isteği de yok — yazı tipleri uygulamanın kendi origin'inden gelir, yani font-src yalnızca 'self' |
| Kendini kurtarabilir | açılış başarısız olursa uygulama boş sayfa yerine bunu söyler: yeniden yükleme düğmesi ve iki dokunuşluk veri silme. Ayarlar bir tanılama raporunu panoya kopyalayabilir, rapor hiçbir yere gönderilmez |
Bir alana yazarken hiçbiri çalışmaz. Transport tuşları o an çalan şeyi takip
eder, yani her görünümde iş görür; [, Esc ve ? her zaman etkindir.
| Tuş | İşlev |
|---|---|
Space |
Oynat / duraklat |
← / → |
Geri / ileri sar |
↑ / ↓ |
Önceki / sonraki bölüm |
Home / End |
Bölümün başına / sonuna git |
[ |
Kenar çubuğunu daralt veya genişlet (masaüstü) |
Esc |
Şimdi Çalıyor panelini kapat |
? |
Kısayol listesini göster |
Listede ↑ / ↓ |
Bölüm satırları arasında gezin (← / → satırın kendi düğmeleri) |
İsteğe bağlı, siz açana kadar kapalı ve hesapsız. Bir cihaz Ayarlar → Cihazlar Arası Eşitleme'de bir eşleştirme kodu üretir; kodu diğerine yazdığınızda kaldığınız konum, her yayında en son dinlenen bölüm, abonelikler ve kuyruk ortak olur.
Veri cihazda şifrelenir. Koddan HKDF-SHA256 ile birbirinden bağımsız iki değer türetilir — sunucunun satırı sakladığı kimlik ve AES-GCM anahtarı — yani arka uç okuyamadığı baytları tutar.
- Ayarlar eşitlenmez: yazı boyutu, tema ve ses seviyesi cihaza aittir.
- İki cihazın bir dakika içindeki yazmaları eşzamanlı sayılır ve daha ileri konum kazanır.
- Bağlantıyı kesmek yalnızca o cihazda eşitlemeyi durdurur, verisine dokunmaz. "Sunucudaki veriyi sil" ise saklanan kopyayı tüm cihazlar için kaldırır.
- Kodu saklayın. Tek kimlik bilgisi odur; kaybederseniz eşitlenen kopya geri gelmez — her cihazdaki veri yerinde kalır.
Worker (VITE_API_BASE) ve derleme sırasında VITE_SYNC=1 gerektirir. İki
bayrak bilerek ayrıdır: eşitleme kapatılırken feed ve iTunes proxy'leri ayakta
kalır.
npm install # bir kez
npm run dev # http://localhost:5199
# isteğe bağlı arka uç (feed/iTunes proxy)
npm --prefix worker install # bir kez
npm run worker:dev # http://127.0.0.1:8787İstemci önce Worker'ı dener (VITE_API_BASE, bkz. .env.development),
ulaşamazsa halka açık CORS proxy'lerine düşmek isteğe bağlıdır (Ayarlar →
Gizlilik, varsayılan kapalı): bu operatörler açılan her feed adresini görür ve
uygulama üçünü yarıştırıp ilk cevabı ayrıştırır.
- Windows:
desktop/altındaki Tauri v2 kabuğu canlı siteyi WebView2 içinde açar — ~1,8 MB'lık NSIS kurulumu GitHub Releases'te; uygulama her web dağıtımıyla kendini günceller. - Google Play: canlı PWA'dan PWABuilder ile TWA paketi.
- Adım adım rehber: docs/STORE.md.
Analitik yok, hesap yok. Ayarlar/ilerleme localStorage'da, indirilenler
tarayıcının Cache API'sinde kalır. Patreon / Memberful / Substack tarzı özel/
abone anahtarı taşıyan feed URL'leri herkese açık CORS proxy'lerine asla
gönderilmez — yalnızca uygulamanın kendi Worker'ı üzerinden geçer; Worker
yapılandırılmamışsa net bir hata mesajıyla başarısız olur. Sıradan herkese
açık feed'ler bundan etkilenmez. Bkz.
public/privacy-policy.html.
𝓐.𝓒.𝓑 — bozdogancanahmet@gmail.com · MIT © 2026