English | Japanese
A Nostr/Bluesky/Misskey.io/Discord client that reads out posts using text-to-speech.
- Enable and configure your platforms:
- Nostr: Use NIP-07 extension (nos2x for Chrome, nos2x-fox for Firefox) or enter pubkey manually
- Bluesky: Settings > Privacy and Security > App Passwords > Enter handle and app password
- Misskey.io: Settings > Service integration > Generate access token
- Discord: Create a Discord Bot (see discord-bot/README.md) > Launch the bot with your token and channel ID > Enter WebSocket URL in yomi settings
cd discord-bot npm install node bot.cjs --token <BOT_TOKEN> --channel <CHANNEL_ID>
- Open yomi in your browser
- Click the gear icon to open the config dialog
- Click "Start" to begin reading posts from your follows
- A modern browser (Chrome, Firefox, Safari, Edge)
- A modern browser with Web Speech API support
- Speech synthesis voices installed:
Ubuntu/Debian:
sudo apt install speech-dispatcher speech-dispatcher-espeak-ng espeak-ngArch:
sudo pacman -S speech-dispatcher espeak-ng| OS | Browser | Foreground Playback | Background Playback | Bluetooth Playback | Speech Recognition (on device) | Speech Recognition (Bluetooth) |
|---|---|---|---|---|---|---|
| Windows 11 25H2 | Chrome 143.0.7499.194 | ✔ | ✔ | ✔ | ✔ | ✔ |
| iOS 26.2 | Safari 26.6 | ✔ | ✔ | ✔ | ||
| Android 13 | Chrome 143.0.7499.194 | ✔ | ✔ | ✔ | ✔ | |
| Android 13 | Firefox Nightly 149.0a1 | ✔ | ✔ | ✔ |
Available languages for text-to-speech depend on your browser and OS. Below are commonly supported languages:
| Code | Language | Windows | Mac | Android | iOS |
|---|---|---|---|---|---|
| en | English | ✓ | ✓ | ✓ | ✓ |
| ja | 日本語 | ✓ | ✓ | ✓ | ✓ |
| zh | 中文 | ✓ | ✓ | ✓ | ✓ |
| ko | 한국어 | ✓ | ✓ | ✓ | ✓ |
| es | Español | ✓ | ✓ | ✓ | ✓ |
| fr | Français | ✓ | ✓ | ✓ | ✓ |
| de | Deutsch | ✓ | ✓ | ✓ | ✓ |
| it | Italiano | ✓ | ✓ | ✓ | ✓ |
| pt | Português | ✓ | ✓ | ✓ | ✓ |
| ru | Русский | ✓ | ✓ | ✓ | ✓ |
| ar | العربية | ✓ | ✓ | ✓ | ✓ |
| hi | हिन्दी | ✓ | ✓ | ✓ | ✓ |
| th | ไทย | ✓ | ✓ | ✓ | ✓ |
| vi | Tiếng Việt | ✓ | ✓ | ||
| nl | Nederlands | ✓ | ✓ | ✓ | ✓ |
| pl | Polski | ✓ | ✓ | ✓ | ✓ |
| tr | Türkçe | ✓ | ✓ | ✓ | ✓ |
| uk | Українська | ✓ | ✓ |
Note: On Linux, available languages depend on what espeak-ng supports. You can install additional language packs to extend support.
The "Auto detect by author" and "Auto detect by note" features use franc-min for language detection. franc-min supports the following 82 languages:
| Code | Language | Code | Language | Code | Language |
|---|---|---|---|---|---|
| amh | አማርኛ | arb | العربية | azj | Azərbaycan |
| bel | Беларуская | ben | বাংলা | bho | भोजपुरी |
| bos | Bosanski | bul | Български | ceb | Cebuano |
| ces | Čeština | ckb | کوردی | cmn | 中文 |
| deu | Deutsch | ell | Ελληνικά | eng | English |
| fra | Français | fuv | Fulfulde | guj | ગુજરાતી |
| hau | Hausa | hin | हिन्दी | hms | 苗语 |
| hnj | Hmong | hrv | Hrvatski | hun | Magyar |
| ibo | Igbo | ilo | Ilokano | ind | Indonesia |
| ita | Italiano | jav | Jawa | jpn | 日本語 |
| kan | ಕನ್ನಡ | kaz | Қазақ | kin | Kinyarwanda |
| koi | Коми | kor | 한국어 | lin | Lingála |
| mad | Madura | mag | मगही | mai | मैथिली |
| mal | മലയാളം | mar | मराठी | mya | မြန်မာ |
| nld | Nederlands | npi | नेपाली | nya | Chichewa |
| pan | ਪੰਜਾਬੀ | pbu | پښتو | pes | فارسی |
| plt | Malagasy | pol | Polski | por | Português |
| qug | Kichwa | ron | Română | run | Kirundi |
| rus | Русский | sin | සිංහල | skr | سرائیکی |
| som | Soomaali | spa | Español | srp | Српски |
| sun | Sunda | swe | Svenska | swh | Kiswahili |
| tam | தமிழ் | tel | తెలుగు | tgl | Tagalog |
| tha | ไทย | tur | Türkçe | ukr | Українська |
| urd | اردو | uzn | Oʻzbek | vie | Tiếng Việt |
| yor | Yorùbá | zlm | Melayu | zul | isiZulu |
| zyb | 壮语 |
Note: For auto language detection to work correctly, the detected language must also be supported by TTS.
- Node.js 18+
- npm
npm install
npm run buildnpm run devOpen http://localhost:5173 in your browser.
Flow from fetching posts to speech synthesis:
flowchart TB
subgraph Sources["Post Fetching"]
Nostr["Nostr<br/>subscribeToNotes()"]
Bluesky["Bluesky<br/>getTimeline()"]
Misskey["Misskey<br/>subscribeToTimeline()"]
Discord["Discord<br/>connectStream()"]
Test["Test<br/>window.testpost()"]
end
subgraph Queue["Queue Management"]
NoteWithRead["NoteWithRead<br/>{id, pubkey, content,<br/>created_at, read, source}"]
NotesRef["notesRef / setNotes"]
end
subgraph Processing["Reading Process (processNextNote)"]
FindUnread["Find oldest unread note"]
MarkRead["Mark as read: true"]
FormatAuthor["Format author name<br/>(remove emoji, etc.)"]
ProcessText["processTextForSpeech()<br/>(handle emoji/URL/Nostr address)"]
BuildText["fullText =<br/>authorName + content"]
end
subgraph Speech["Speech Synthesis"]
SpeechManager["speechManager.speak()"]
WebSpeechAPI["Web Speech API"]
end
Nostr --> NoteWithRead
Bluesky --> NoteWithRead
Misskey --> NoteWithRead
Discord --> NoteWithRead
Test --> NoteWithRead
NoteWithRead --> NotesRef
NotesRef --> FindUnread
FindUnread --> MarkRead
MarkRead --> FormatAuthor
FormatAuthor --> ProcessText
ProcessText --> BuildText
BuildText --> SpeechManager
SpeechManager --> WebSpeechAPI
WebSpeechAPI -->|onEnd| FindUnread
Forward all console output to a WebSocket server for remote debugging.
- Start the WebSocket server:
node tools/wsserver.cjs > console-log.txt- Open the app with
?ws=host:portparameter:
http://localhost:5173/?ws=localhost:8080
- This project: MIT License
- Third-party libraries: THIRD_PARTY_LICENSES.md