podcast manager
at main 162 lines 4.9 kB view raw
1#+TITLE: skypod 2#+AUTHOR: Jonathan Raphaelson 3#+EMAIL: jon@accidental.cc 4 5an offline-first RSS & podcast PWA application 6 7* what is skypod? 8 9- rss/podcast subscription management 10- offline first; cache audio locally, and p2p sync between devices 11- podcast playback with nice features; skip silence, volume 12 correction, etc. 13- fun to hack on 14 15* how does it work? 16 17- PWA stores and displays cached feeds, subscription, and listening 18 history data locally in IndexedDB 19- WebSocket signaling server for WebRTC peering, devices sync cached 20 data and play state using a hybrid logical clock for causal ordering 21- feed proxy server provides a nice API for fetching feeds and 22 extracting metadata 23 24* getting started with devenv 25 26this project uses [[https://devenv.sh][devenv.sh]] for reproducible development environments. 27 28if you have devenv installed: 29 30#+BEGIN_SRC bash 31 $ devenv shell 32 $ npm install 33 $ npm run dev 34#+END_SRC 35 36if you don't have devenv, you can install it from [[https://devenv.sh][devenv.sh]] or just 37use node v24+ directly. 38 39* development 40 41run the pwa+server with: 42 43#+BEGIN_SRC bash 44 $ npm install 45 $ npm run dev # lots of stuff concurrently with wireit 46#+END_SRC 47 48this starts: 49- vite dev server at ~http://127.0.0.1:4000~ (frontend) 50- backend server at ~http://127.0.0.1:4001~ (WebSocket + API) 51- live type-checking and linting in watch mode 52 53** technology stack 54 55*** common 56- typescript with strict mode 57- [[https://github.com/panva/jose][~jose~]] for cross-platform webcrypto and JWT management 58- [[https://zod.dev/][Zod]] describes schema and builds transformation pipelines 59 60*** backend 61- [[https://expressjs.com/][Express]] for HTTP and WebSocket servers 62- [[https://github.com/Level/level][Level]] for persistent realm kv storage 63 64*** frontend 65- [[https://vite.dev/][Vite]] for builds 66- [[https://preactjs.com/][Preact]] for UI 67- [[https://dexie.org/][Dexie]] for IndexedDB storage 68- [[https://github.com/feross/simple-peer][simple-peer]] for WebRTC 69 70*** build & dx 71- typescript for type-checking 72- [[https://github.com/google/wireit][Wireit]] does script dependencies and services 73- [[https://eslint.org][ESLint]] and prettier keep the code nice 74 75** scripts 76 77- ~npm run dev~ :: alias for ~npm run start:dev~ 78- ~npm run lint~ :: runs ~eslint~ 79- ~npm run types~ :: runs ~tsc~ (no emitting, just typechecking) 80- ~npm run build~ :: build production frontend 81- ~npm run test~ :: runs ~jest~ as a one-off 82- ~npm run start:tests~ :: runs ~jest~ in watch mode 83- ~npm run start:dev~ :: runs BE/FE with live type-checking and linting 84- ~npm run start:prod~ :: builds and runs everything in production mode 85 86** running tests 87 88There's not much here yet, I want to figure it out first. 89 90#+BEGIN_SRC bash 91 $ npm run test # run all tests once 92 $ npm run start:tests # run tests in watch mode 93#+END_SRC 94 95to run a single test file: 96 97#+BEGIN_SRC bash 98 $ npx jest src/path/to/file.spec.ts 99#+END_SRC 100 101** git hooks 102 103pre-commit hook runs type-checking and linting automatically. enable with: 104 105#+BEGIN_SRC bash 106 $ git config core.hooksPath .githooks 107#+END_SRC 108 109* architecture 110 111the codebase is organized into modules with path aliases: 112 113- ~#client/*~ (~src/client/~) - preact frontend application 114- ~#server/*~ (~src/server/~) - node.js express backend 115- ~#common/*~ (~src/common/~) - shared code (protocol, crypto, utilities) 116- ~#realm/*~ (~src/realm/~) - p2p connection and sync protocol 117- ~#skypod/*~ (~src/skypod/~) - domain-specific schemas and actions 118 119** key architectural components 120 121*** p2p synchronization 122 123uses a hybrid logical clock (HLC) for causal ordering of events across 124distributed peers. clients PULL complete action history when catching 125up, and PUSH tailored updates to each peer based on knowledge vectors. 126 127*** offline-first 128 129all user data lives in IndexedDB via dexie. the server is stateless 130regarding user data (only maintains ephemeral realm/peer state). 131 132*** webrtc for p2p 133 134peers communicate directly via WebRTC data channels. the WebSocket 135connection to the server is only used for signaling and as a fallback 136broadcast mechanism. 137 138*** realm system 139 140a realm is a collection of verified identities that can communicate 141securely. realms are not publicly routable; access requires the realm 142id and an invitation from an existing member. 143 144see [[./docs/readme-brainstorm.org]] for detailed architecture thoughts 145and connection flow diagrams. 146 147* contributing 148 149- run ~git config core.hooksPath .githooks~ to install pre-commit 150 hooks for lint/fmt 151- honestly, not really open to contributions right now, come back 152 later. 153 154* license & copyright 155 156copyright (C) 2025 jonathan raphaelson 157 158this program is free software: you can redistribute it and/or modify 159it under the terms of the **affero general public license version 3 or 160later** (AGPLv3+). 161 162see [[./readme-license.txt]] for a copy of the full license.