Skip to content

CMolG/pulse-radio

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

23 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Next.js 16 React 19 TypeScript 5 Tailwind CSS 4 Apache 2.0 License PRs Welcome

πŸ“» Pulse Radio

A modern, feature-rich internet radio player built with Next.js 16 and React 19. Stream 40,000+ stations with real-time lyrics, audio visualizers, a 5-band equalizer, podcast support, and audiobooks β€” all in your browser.

Features β€’ Getting Started β€’ Architecture β€’ Contributing β€’ Roadmap


✨ Features

🎡 Core Playback

  • 40,000+ stations from Radio Browser API β€” browse by genre, country, trending, or local
  • ICY metadata extraction β€” real-time "Now Playing" track info from stream headers
  • Station queue β€” queue up stations and move between them seamlessly
  • Stall recovery β€” automatic retry logic when streams buffer or drop
  • Media Session API β€” OS-level controls (lock screen, headphone buttons, media keys)
  • Wake Lock β€” prevents screen from sleeping during playback
  • Sleep timer β€” auto-stop playback after a configurable duration

🎨 Visual Experience

  • Album artwork β€” automatic lookup via iTunes Search API with strict Jaro-distance matching and graceful fallback
  • Audio visualizers β€” ferrofluid, spiral, and circular renderers using Web Audio FFT analysis
  • Audio-reactive background β€” dynamic background that pulses with the music (works with or without audio effects enabled β€” uses a synthesized ambient pulse as fallback)
  • Theater mode β€” immersive full-screen playback with parallax album art background
  • Concert ticker β€” animated scrolling banner showing upcoming Bandsintown shows in theater mode
  • Liquid Glass UI β€” Aerolab-inspired liquid glass buttons with SVG distortion filter, specular lighting, and frosted tint layers on play controls and language selector
  • Glassmorphism UI β€” macOS-inspired dark theme with frosted glass surfaces

πŸŽ›οΈ Audio Control

  • 5-band parametric equalizer β€” Low (60Hz), Lo-Mid (230Hz), Mid (910Hz), Hi-Mid (3.6kHz), High (14kHz)
  • 8 built-in presets β€” Flat, Bass Boost, Treble, V-Shape, Vocal, Rock, Electronic, Acoustic
  • Custom presets β€” save and name your own EQ configurations
  • Persistent EQ preset β€” selected preset name persists across sessions
  • Seamless effects toggle β€” enable/disable audio enhancements without stream interruption (always-proxy architecture)
  • Volume control with mute toggle

πŸ“ Lyrics

  • Synced lyrics (LRC format) with auto-scrolling and highlighted current line
  • Plain text lyrics fallback when synced version unavailable
  • Realtime STT lyrics sync β€” on-device speech recognition aligns lyrics in real time when timestamps are unavailable
  • Local caching for instant re-display on revisit
  • Powered by LrcLib API

🌍 Internationalization

  • Multi-language UI β€” locale-aware routing via [countryCode] segments
  • Language selector β€” switch UI language in-app
  • Country-based defaults β€” auto-detects preferred stations and language from locale

πŸ“š Library Management

  • Favorites β€” star stations for quick access
  • Favorite songs β€” bookmark tracks you love
  • Recent stations β€” last 15 played stations
  • Play history β€” up to 100 entries with artist, track, and artwork
  • Artist detail modal β€” view artist biography, upcoming Bandsintown concerts, and lyrics from history/favorites
  • Social share β€” share current station or track via Web Share API (or clipboard fallback) from cards, detail modals, theater mode, and the now-playing bar
  • Uniform card layout β€” all cards share the same height with station name anchored at the bottom
  • Group by artist/album β€” horizontal scrollable thumbnail row for grouped tracks

πŸ“± Responsive Design

  • Adapts from desktop (sidebar + main) to tablet and mobile layouts
  • Touch-friendly controls throughout
  • Mobile lyrics reel β€” swipeable lyrics experience on small screens
  • Single-row genre/country chips β€” horizontally scrollable with a dropdown to access all genres and countries
  • Desktop stats modal β€” floating centered dialog instead of bottom sheet on desktop viewports
  • Dev API console β€” in-browser scrollable log of all ICY, iTunes, Lyrics, and Bandsintown API requests (development mode only, visible in theater mode)

πŸš€ Getting Started

Prerequisites

  • Node.js 18.17 or later
  • npm, yarn, pnpm, or bun

Installation

# Clone the repository
git clone https://github.com/CMolG/pulse-radio.git
cd pulse-radio

# Install dependencies
npm install

# Start the development server
npm run dev

Open http://localhost:3000 to start listening.

Production Build

npm run build
npm start

Environment Setup

cp .env.example .env.local
Variable Required Description
CRON_SECRET Yes (prod) Secures /api/cron/sync endpoint. Generate with openssl rand -hex 32
BANDSINTOWN_APP_ID No Bandsintown API key for concert data. Falls back to demo key
NODE_ENV Auto Set by Next.js (development / production / test)

πŸ—οΈ Architecture

src/
β”œβ”€β”€ app/                          # Next.js App Router
β”‚   β”œβ”€β”€ [countryCode]/            # Locale-aware routing
β”‚   β”‚   β”œβ”€β”€ layout.tsx
β”‚   β”‚   β”œβ”€β”€ page.tsx
β”‚   β”‚   β”œβ”€β”€ head.tsx
β”‚   β”‚   └── not-found.tsx
β”‚   β”œβ”€β”€ api/
β”‚   β”‚   β”œβ”€β”€ proxy-stream/         # CORS proxy for audio streams
β”‚   β”‚   β”œβ”€β”€ icy-meta/             # ICY metadata extraction endpoint
β”‚   β”‚   β”œβ”€β”€ itunes/               # Album artwork lookup proxy
β”‚   β”‚   β”œβ”€β”€ artist-info/          # Artist biography/info proxy
β”‚   β”‚   β”œβ”€β”€ concerts/             # Bandsintown concert data proxy
β”‚   β”‚   β”œβ”€β”€ lyrics/               # Lyrics fetching endpoint
β”‚   β”‚   β”œβ”€β”€ health/               # Health check endpoint
β”‚   β”‚   β”œβ”€β”€ analytics/            # Analytics endpoint
β”‚   β”‚   β”œβ”€β”€ cron/                 # Scheduled sync jobs
β”‚   β”‚   └── station-health/       # Station reliability scoring
β”‚   β”œβ”€β”€ layout.tsx                # Root layout (fonts, metadata)
β”‚   β”œβ”€β”€ page.tsx                  # Home page β†’ <Radio />
β”‚   β”œβ”€β”€ sitemap.ts                # Dynamic sitemap generation
β”‚   β”œβ”€β”€ ServiceWorkerRegistrar.tsx
β”‚   └── globals.css               # Tailwind + theme variables
β”‚
β”œβ”€β”€ components/radio/             # Main radio player
β”‚   β”œβ”€β”€ RadioShell.tsx            # Top-level container & layout
β”‚   β”œβ”€β”€ components/               # UI subcomponents
β”‚   β”‚   β”œβ”€β”€ StationCard.tsx       # Station list item
β”‚   β”‚   β”œβ”€β”€ NowPlayingBar.tsx     # Bottom playback bar
β”‚   β”‚   β”œβ”€β”€ NowPlayingHero.tsx    # Main "now playing" display
β”‚   β”‚   β”œβ”€β”€ BrowseView.tsx        # Genre/country browser
β”‚   β”‚   β”œβ”€β”€ EqPanel.tsx           # Equalizer interface
β”‚   β”‚   β”œβ”€β”€ LyricsPanel.tsx       # Lyrics display
β”‚   β”‚   β”œβ”€β”€ MobileLyricsReel.tsx  # Mobile lyrics experience
β”‚   β”‚   β”œβ”€β”€ LanguageSelector.tsx  # UI language switcher
β”‚   β”‚   β”œβ”€β”€ KeyboardShortcutsHelp.tsx
β”‚   β”‚   β”œβ”€β”€ Sidebar.tsx           # Navigation sidebar
β”‚   β”‚   └── TheaterView.tsx       # Full-screen theater mode
β”‚   β”œβ”€β”€ hooks/                    # Custom React hooks
β”‚   β”‚   β”œβ”€β”€ useRadio.ts           # Core playback engine
β”‚   β”‚   β”œβ”€β”€ useEqualizer.ts       # Web Audio API EQ chain
β”‚   β”‚   β”œβ”€β”€ useStationMeta.ts     # ICY metadata polling
β”‚   β”‚   β”œβ”€β”€ useLyrics.ts          # Lyrics fetching & caching
β”‚   β”‚   β”œβ”€β”€ useRealtimeLyricsSync.ts  # STT-based realtime lyrics sync
β”‚   β”‚   β”œβ”€β”€ useFavorites.ts       # Favorite stations (localStorage)
β”‚   β”‚   β”œβ”€β”€ useFavoriteSongs.ts   # Favorite songs (localStorage)
β”‚   β”‚   β”œβ”€β”€ useRecent.ts          # Recent stations
β”‚   β”‚   β”œβ”€β”€ useHistory.ts         # Play history tracker
β”‚   β”‚   β”œβ”€β”€ useMediaSession.ts    # Browser media session
β”‚   β”‚   β”œβ”€β”€ useStationQueue.ts    # Station queue management
β”‚   β”‚   β”œβ”€β”€ useSleepTimer.ts      # Auto-stop sleep timer
β”‚   β”‚   β”œβ”€β”€ useWakeLock.ts        # Screen wake lock
β”‚   β”‚   β”œβ”€β”€ usePlaybackPosition.ts
β”‚   β”‚   β”œβ”€β”€ useArtistInfo.ts      # Artist biography lookup
β”‚   β”‚   β”œβ”€β”€ useAudioReactiveBackground.ts
β”‚   β”‚   └── useParallaxBg.ts
β”‚   β”œβ”€β”€ services/                 # External API clients
β”‚   β”‚   β”œβ”€β”€ radioApi.ts           # Radio Browser API
β”‚   β”‚   β”œβ”€β”€ lyricsApi.ts          # LrcLib API
β”‚   β”‚   β”œβ”€β”€ lyricsAligner.ts      # Incremental lyrics alignment
β”‚   β”‚   β”œβ”€β”€ realtimeSpeechRecognition.ts  # STT engine wrapper
β”‚   β”‚   β”œβ”€β”€ realtimeLyricsTypes.ts
β”‚   β”‚   β”œβ”€β”€ archiveApi.ts         # Internet Archive API
β”‚   β”‚   β”œβ”€β”€ librivoxApi.ts        # LibriVox API
β”‚   β”‚   └── podcastApi.ts         # Podcast RSS parsing
β”‚   β”œβ”€β”€ types.ts                  # TypeScript type definitions
β”‚   β”œβ”€β”€ constants.ts              # Genres, EQ presets, storage keys
β”‚   β”œβ”€β”€ lrcParser.ts              # LRC lyrics format parser
β”‚   └── lyricsUtils.ts            # Lyrics utility functions
β”‚
β”œβ”€β”€ context/
β”‚   └── LocaleContext.tsx         # i18n locale provider
β”‚
└── lib/                          # Shared utilities
    β”œβ”€β”€ audio-visualizer/         # Canvas-based visualizations
    β”‚   β”œβ”€β”€ useAudioAnalyser.ts   # FFT frequency analysis hook
    β”‚   β”œβ”€β”€ useAlbumArt.ts        # iTunes artwork with Jaro-distance matching
    β”‚   β”œβ”€β”€ FerrofluidRenderer.tsx
    β”‚   β”œβ”€β”€ SpiralRenderer.tsx
    β”‚   └── CircularRenderer.tsx
    β”œβ”€β”€ i18n/                     # Internationalization
    β”‚   β”œβ”€β”€ locales.ts            # Supported locales
    β”‚   β”œβ”€β”€ messages.ts           # Translation strings
    β”‚   β”œβ”€β”€ countries.ts          # Country metadata
    β”‚   β”œβ”€β”€ countryChips.ts       # Country filter chips
    β”‚   β”œβ”€β”€ countryDefaults.ts    # Per-country defaults
    β”‚   β”œβ”€β”€ languageMap.ts        # Language β†’ locale mapping
    β”‚   └── localeStorage.ts      # Locale persistence
    β”œβ”€β”€ playbackStore.ts          # Zustand global state
    └── storageUtils.ts           # localStorage helpers

Tech Stack

Layer Technology
Framework Next.js 16 with React 19 & React Compiler
Language TypeScript 5 (strict mode)
Styling Tailwind CSS 4
State Zustand 5
Animation Motion (Framer Motion) 12
Audio Web Audio API (biquad filters, FFT analysis)
Speech Web Speech API (SpeechRecognition)
Icons Lucide React

External APIs

API Purpose
Radio Browser Station discovery (40K+ stations)
LrcLib Synced & plain text lyrics
iTunes Search Album artwork lookup
Bandsintown Upcoming concert/tour dates

🀝 Contributing

We welcome contributions of all kinds! See CONTRIBUTING.md for the full guide covering setup, testing, code style, and architecture.

Quick Start

  1. Fork the repository
  2. Create a feature branch: git checkout -b feat/my-feature
  3. Make your changes
  4. Test locally: npm run build && npx playwright test --project=mobile-chrome
  5. Lint: npm run lint
  6. Commit with a descriptive message: git commit -m "feat: add sleep timer"
  7. Push to your fork: git push origin feat/my-feature
  8. Open a Pull Request

Commit Convention

We use Conventional Commits:

feat:     New feature
fix:      Bug fix
docs:     Documentation only
style:    Formatting, no code change
refactor: Code change that neither fixes a bug nor adds a feature
perf:     Performance improvement
test:     Adding or updating tests
chore:    Build process or tooling changes

Good First Issues

Look for issues labeled good first issue β€” these are beginner-friendly tasks that are a great starting point.

Development Tips

  • The CORS proxy (/api/proxy-stream) is required because browsers block cross-origin audio streams for Web Audio API analysis
  • ICY metadata is extracted server-side since browsers can't read ICY headers directly
  • The equalizer uses a chain of BiquadFilterNodes in a Web Audio graph
  • Lyrics are cached in localStorage to avoid redundant API calls
  • The realtime STT engine resets its restart counter on every successful recognition result; MAX_RESTARTS means consecutive failures, not total restarts

πŸ—ΊοΈ Roadmap

  • Sleep timer
  • Keyboard shortcuts
  • i18n / localization
  • Realtime STT lyrics sync
  • Station queue
  • Bandsintown concert integration (theater mode ticker + artist detail modal)
  • Audio-reactive background (with analyser fallback)
  • Persistent EQ preset selection
  • Always-proxy audio pipeline (no stream interruptions)
  • Liquid Glass UI (Aerolab-style buttons)
  • Social share (Web Share API + clipboard fallback)
  • Dev API console (development mode)
  • Podcast support (search & RSS playback)
  • Audiobook support (LibriVox + Internet Archive)
  • Station search with fuzzy matching
  • Chromecast / AirPlay support
  • Shared playlists

πŸ“„ License

This project is licensed under the Apache License 2.0.


Built with ❀️ and way too many radio stations

About

An online radio, powered by lyrics, album information, audio improvements, wiki content about artists, even next concerts.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors