Storytel Player is an unofficial cross-platform desktop application for playing Storytel audiobooks, built with TypeScript, React, Fastify, and Electron.
- Frontend: React 18 + TypeScript + Tailwind CSS + Vite
- Backend: Fastify 5 + TypeScript
- Desktop: Electron 38+
- Internationalization: i18next (multi-language support)
- State Management: electron-store for persistent storage
- Build Tools: Vite, esbuild, electron-builder
storytel-player/
├── client/ # React frontend application
│ ├── src/
│ │ ├── components/ # React components
│ │ ├── hooks/ # Custom React hooks
│ │ ├── services/ # API services
│ │ ├── utils/ # Utility functions
│ │ └── i18n.ts # i18next configuration
│ └── package.json
├── server/ # Fastify backend server
│ ├── server.ts # Main server file
│ ├── storytelApi.ts # Storytel API integration
│ ├── locales/ # Translation files
│ └── package.json
├── src/ # Electron main process
│ ├── modules/ # Electron modules (IPC, window, tray, etc.)
│ ├── main.ts # Electron entry point
│ └── preload.ts # Electron preload script
└── package.json # Root package.json
- ALL documentation files (README, CONTRIBUTING, AGENTS.md, etc.) MUST be written in English
- ALL code comments MUST be written in English
- ALL commit messages MUST be written in English
- ALL variable names, function names, and identifiers MUST be in English
- ALL user-facing text (UI labels, messages, errors) MUST use the i18n translation system
- Never hardcode user-facing strings in components
- Always add new strings to translation files in
server/locales/
-
Location: Translation files are in
server/locales/server/locales/en.json- English translations (default)server/locales/it.json- Italian translations- Add more languages as needed
-
Usage in Frontend:
import { useTranslation } from 'react-i18next'; function MyComponent() { const { t } = useTranslation(); return <div>{t('key.name')}</div>; }
-
Usage in Backend:
// Server automatically provides translations via API // Use i18next instance configured in server
-
Adding New Translations:
- Add the key to
server/locales/en.json - Add translations to all other language files (
it.json, etc.) - Use the key in your component with
t('your.new.key')
- Add the key to
- TypeScript: Strict mode enabled, use proper typing
- React: Functional components with hooks
- CSS: Tailwind CSS utility classes
- Formatting: Follow existing code style in the project
- Use existing modal components as reference (see
client/src/components/*Modal.tsx) - Follow existing hook patterns (see
client/src/hooks/) - Maintain consistent UI/UX with Tailwind classes already in use
- Reuse common components when possible
- Local State: React hooks (useState, useEffect, etc.)
- Persistent Storage: Use
electron-storevia IPC for desktop persistence - API State: Direct API calls via Axios (see
client/src/utils/api.ts)
- Install dependencies:
npm run install-all - Development mode:
npm run dev(runs both client and server with hot reload) - Electron dev:
npm run electron:dev - Build:
npm run build(builds client and server) - Electron distribution:
npm run electron:dist(creates distributable packages)
- Manual testing in development mode
- Test across platforms (Windows, macOS, Linux)
- Verify i18n translations for all supported languages
- Test both online and offline modes
- Follow the pattern in existing modal components
- Use proper state management with hooks
- Include proper TypeScript interfaces
- Ensure proper i18n integration
- Use descriptive names for storage keys
- Document storage schema in code comments
- Use TypeScript interfaces for stored data structures
- Backend API calls go through
client/src/utils/api.ts - Storytel API integration is in
server/storytelApi.ts - Handle errors gracefully with user feedback
- Electron IPC handlers are in
src/modules/ipc.ts - Frontend uses
window.electronAPI (typed inclient/src/types/window.d.ts) - Always handle both success and error cases
- Security: This is a desktop app with persistent session storage
- Authentication: Session-based with secure storage via electron-store
- Single Instance: App uses single instance lock (one app instance at a time)
- Updates: Electron updater is integrated for auto-updates
- Offline Mode: Support for downloading audiobooks for offline playback
- Repository: https://github.com/debba/storytel-player
- Issues: https://github.com/debba/storytel-player/issues
- Releases: https://github.com/debba/storytel-player/releases
- Discord server for community discussions, feature requests, and support
- Link will be added once the welcome modal implementation is complete
MIT License - see LICENSE file for details
Remember:
- Documentation and code in English
- User-facing content via i18n system
- Follow existing patterns in the codebase
- Test thoroughly before committing