Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

SomaFM Player

A terminal-based music player for SomaFM internet radio stations, built with Rust and featuring a beautiful TUI (Terminal User Interface).

Features

  • 🎵 Stream SomaFM Radio Stations - Access all available SomaFM channels
  • 🖥️ Beautiful Terminal UI - Clean, intuitive TUI built with ratatui
  • 🎛️ Volume Control - Adjust volume with +/- keys (0-100%)
  • 📊 Live Spectrum Visualizer - Real-time audio frequency display with animated bars
  • ⏯️ Pause/Resume Playback - Control playback with P key
  • 💾 Persistent Configuration - Remembers your last channel and settings
  • 🎤 Real-time Metadata - Display current artist and track information

Quick Start

Install with a single command:

curl -sSL https://raw.githubusercontent.com/mpuccini/soma-play/main/install.sh | bash

Then run:

soma-player

Development Status

⚠️ This project is currently under active development and should be considered alpha software. While functional, you may encounter bugs, incomplete features, or breaking changes between versions.

Documentation Structure

This documentation is organized into several sections:

  • User Guide: Everything you need to know to install and use SomaFM Player
  • Developer Guide: Information for contributors and developers
  • Reference: Detailed reference materials

Installation

Install SomaFM Player with a single command:

Using curl

curl -sSL https://raw.githubusercontent.com/mpuccini/soma-play/main/install.sh | bash

Using wget

wget -qO- https://raw.githubusercontent.com/mpuccini/soma-play/main/install.sh | bash

This script will:

  • ✅ Automatically detect your platform (Linux x64 or macOS ARM64)
  • ✅ Download the latest release binary
  • ✅ Install to ~/.local/bin/soma-player
  • ✅ Make the binary executable
  • ✅ Verify the installation

Note: Make sure ~/.local/bin is in your PATH. If not, the installer will show you how to add it.

Manual Installation

Prerequisites

Linux only - Install audio dependencies:

# Ubuntu/Debian
sudo apt-get install libasound2-dev

# Fedora/CentOS/RHEL
sudo dnf install alsa-lib-devel

# Arch Linux
sudo pacman -S alsa-lib

Download and Install Binary

  1. Download the latest release:

    • Go to Releases
    • Download the appropriate archive for your platform:
      • soma-player-linux-x64.tar.gz (Linux x86_64)
      • soma-player-macos-arm64.tar.gz (macOS Apple Silicon)
  2. Extract and install:

    # Extract the archive
    tar -xzf soma-player-*.tar.gz
    
    # Move to a directory in your PATH
    mv soma-player ~/.local/bin/
    # or system-wide (requires sudo)
    sudo mv soma-player /usr/local/bin/
    
    # Make executable (if needed)
    chmod +x ~/.local/bin/soma-player
    
  3. Verify installation:

    soma-player --version
    

Build from Source

If you prefer to build from source or need to customize the build:

  1. Install Rust:

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    
  2. Install system dependencies (Linux only):

    # Ubuntu/Debian
    sudo apt-get install libasound2-dev pkg-config
    
    # Fedora/CentOS/RHEL
    sudo dnf install alsa-lib-devel pkg-config
    
    # Arch Linux
    sudo pacman -S alsa-lib pkg-config
    
  3. Clone and build:

    git clone https://github.com/mpuccini/soma-play.git
    cd soma-play
    cargo build --release
    
  4. Install the binary:

    # Copy to local bin directory
    cp target/release/soma-player ~/.local/bin/
    
    # Or system-wide (requires sudo)
    sudo cp target/release/soma-player /usr/local/bin/
    

Updating

To update SomaFM Player, simply run the installation command again:

curl -sSL https://raw.githubusercontent.com/mpuccini/soma-play/main/install.sh | bash

This will automatically download and install the latest version.

Usage

This guide covers how to use SomaFM Player effectively.

First Run

When you first run soma-player, you'll see the channel selection screen:

soma-player

The interface will show:

  • A list of available SomaFM channels
  • Channel descriptions and current listener counts
  • Navigation instructions at the bottom

Basic Controls

Channel Selection Screen

  • ↑/↓ Arrow Keys - Navigate through channels
  • Enter - Select and start playing a channel
  • Q - Quit the application

Playing Mode

Once a channel is selected and playing:

  • C - Change channel (opens overlay)
  • P - Pause/Resume playback
  • +/= - Increase volume by 5%
  • -/_ - Decrease volume by 5%
  • Q/Esc - Quit application

Channel Selection Overlay

While music is playing, press C to open the channel selection overlay:

  • ↑/↓ Arrow Keys - Navigate channels
  • Enter - Switch to selected channel
  • Esc - Cancel and return to playing mode
  • Q - Quit application

Interface Elements

Main Display

The playing interface shows:

  • Current Channel - Name and description
  • Now Playing - Artist and track information (when available)
  • Volume Level - Current volume percentage
  • Spectrum Visualizer - Real-time frequency visualization
  • Controls - Available keyboard shortcuts

Spectrum Visualizer

The built-in spectrum visualizer features:

  • Real-time Animation - Responds to music frequency data
  • Auto-scaling - Adapts to your terminal size
  • Color Gradient - Low frequencies (blue) to high frequencies (red)
  • Smart Pausing - Stops animating when playback is paused

Volume Control

Volume can be adjusted in 5% increments:

  • Range: 0% to 100%
  • Default: 50%
  • Persistence: Volume settings are automatically saved
  • Instant: Changes apply immediately

Some recommended SomaFM channels to try:

  • Groove Salad - Ambient/downtempo perfect for work
  • Secret Agent - Spy jazz and lounge music
  • Lush - Lush, gorgeous vocals
  • Drone Zone - Ambient space music for deep listening
  • Beat Blender - Electronic music

Tips for Best Experience

  1. Terminal Size: Use a terminal window at least 80x24 for optimal display
  2. Audio Quality: Ensure your system audio is properly configured
  3. Network: Stable internet connection recommended for uninterrupted streaming
  4. Colors: Enable 256-color support in your terminal for best visuals

Keyboard Shortcuts Quick Reference

KeyAction
↑/↓Navigate channels
EnterSelect/Switch channel
COpen channel selector
PPause/Resume
+/=Volume up
-/_Volume down
Q/EscQuit

Configuration

SomaFM Player uses a TOML configuration file to store settings and preferences.

Configuration File Location

The configuration file is automatically created at:

~/.config/soma-player/config.toml

On different systems:

  • Linux: ~/.config/soma-player/config.toml
  • macOS: ~/.config/soma-player/config.toml
  • Windows: %APPDATA%\soma-player\config.toml

Default Configuration

When you first run the application, it creates a default configuration:

last_channel_id = ""
volume = 50
auto_start = false

Configuration Options

last_channel_id

  • Type: String
  • Default: "" (empty)
  • Description: ID of the last played channel
  • Auto-saved: Yes, updated automatically when you change channels

Example:

last_channel_id = "groovesalad"

volume

  • Type: Integer
  • Range: 0-100
  • Default: 50
  • Description: Audio volume level as a percentage
  • Auto-saved: Yes, updated when you adjust volume with +/- keys

Example:

volume = 75

auto_start

  • Type: Boolean
  • Default: false
  • Description: Skip channel selection and automatically play the last channel
  • Behavior:
    • true: Starts playing last_channel_id immediately
    • false: Shows channel selection screen

Example:

auto_start = true

Complete Example Configuration

# Last played channel (auto-saved)
last_channel_id = "groovesalad"

# Volume level (0-100, auto-saved)
volume = 75

# Auto-start last channel on startup
auto_start = false

Logging Configuration

Logging behavior can be controlled via environment variables:

Log Levels

Set the RUST_LOG environment variable:

# Debug level (very verbose)
RUST_LOG=debug soma-player

# Info level (default)
RUST_LOG=info soma-player

# Warning level (minimal logging)
RUST_LOG=warn soma-player

Log Files

Log files are automatically created at:

~/.config/soma-player/logs/soma-player.log

Features:

  • Daily rotation: New log file each day
  • Automatic cleanup: Old logs are removed
  • Size management: Prevents excessive disk usage

Manual Configuration

You can manually edit the configuration file while the application is not running:

  1. Stop the application (if running)
  2. Edit the file:
    nano ~/.config/soma-player/config.toml
    
  3. Save and restart the application

Troubleshooting Configuration

Configuration Not Saving

  • Check file permissions for ~/.config/soma-player/
  • Ensure the directory is writable
  • Look for error messages in the logs

Configuration File Corrupted

If the configuration file becomes corrupted:

  1. Stop the application
  2. Remove the config file:
    rm ~/.config/soma-player/config.toml
    
  3. Restart the application - it will create a new default configuration

Reset to Defaults

To reset all settings to defaults:

# Remove the entire configuration directory
rm -rf ~/.config/soma-player/

# Restart the application
soma-player

Advanced Configuration

Multiple Profiles

While not built-in, you can use different config directories:

# Use a custom config directory
XDG_CONFIG_HOME=/path/to/custom/config soma-player

System-wide Configuration

For system-wide defaults, you could:

  1. Create a template configuration
  2. Copy it to user directories as needed
  3. Use deployment scripts for multiple users

Configuration Schema

The configuration follows this schema:

# String: Channel ID from SomaFM API
last_channel_id = "string"

# Integer: Volume level 0-100
volume = 50

# Boolean: Auto-start behavior
auto_start = false

Future Configuration Options

Planned configuration options for future releases:

  • theme - Color theme selection
  • keybindings - Custom keyboard shortcuts
  • network_timeout - Connection timeout settings
  • retry_attempts - Network retry configuration

Troubleshooting

Common issues and solutions for SomaFM Player.

Installation Issues

Binary Not Found

Problem: soma-player: command not found

Solutions:

  1. Check PATH: Ensure ~/.local/bin is in your PATH

    echo $PATH | grep -o ~/.local/bin
    
  2. Add to PATH (if missing):

    echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
    source ~/.bashrc
    
  3. Verify installation:

    ls -la ~/.local/bin/soma-player
    

Permission Denied

Problem: Permission denied when running

Solution:

chmod +x ~/.local/bin/soma-player

Audio Dependencies (Linux)

Problem: Audio playback fails on Linux

Solutions:

# Ubuntu/Debian
sudo apt-get install libasound2-dev

# Fedora/CentOS/RHEL
sudo dnf install alsa-lib-devel

# Arch Linux
sudo pacman -S alsa-lib

Playback Issues

No Audio Output

Symptoms: Player starts but no sound

Debugging Steps:

  1. Check system audio:

    # Test system audio
    speaker-test -t sine -f 1000 -l 1
    
  2. Check volume levels:

    • System volume is not muted
    • Player volume is above 0%
  3. Audio device selection:

    • Ensure correct audio output device is selected
    • Try switching audio devices in system settings

Stream Connection Fails

Symptoms: "Failed to connect to stream"

Solutions:

  1. Check internet connection:

    ping somafm.com
    
  2. Try different channel: Some channels may be temporarily unavailable

  3. Check firewall: Ensure outbound HTTP connections are allowed

  4. Restart application: Connection issues may be temporary

Stuttering Audio

Symptoms: Audio cuts out or stutters

Causes & Solutions:

  1. Network issues: Check internet stability
  2. High CPU usage: Close other applications
  3. Audio buffer issues: Restart the application
  4. System audio driver: Update audio drivers

Interface Issues

Display Problems

Problem: Interface looks corrupted or misaligned

Solutions:

  1. Terminal size: Ensure terminal is at least 80x24

    resize -s 24 80
    
  2. Terminal compatibility: Use a modern terminal emulator

    • ✅ Recommended: Alacritty, Kitty, iTerm2, Windows Terminal
    • ⚠️ May have issues: Old terminals, basic consoles
  3. Color support: Enable 256-color support

    echo $TERM  # Should show something like xterm-256color
    

Spectrum Visualizer Issues

Problem: Visualizer not showing or appears static

Solutions:

  1. Terminal size: Ensure sufficient space for visualizer
  2. Color support: Enable color in terminal
  3. Refresh rate: Try resizing terminal window

Keyboard Input Not Working

Problem: Keys don't respond

Solutions:

  1. Terminal focus: Ensure terminal window has focus
  2. Input capture: Some terminals may capture certain keys
  3. Restart: Try restarting the application

Configuration Issues

Settings Not Saving

Problem: Volume/channel changes don't persist

Debugging:

  1. Check permissions:

    ls -la ~/.config/soma-player/
    
  2. Create directory (if missing):

    mkdir -p ~/.config/soma-player
    
  3. Check disk space:

    df -h ~/.config
    

Configuration File Corrupted

Problem: Application fails to start with config error

Solution:

# Backup existing config
mv ~/.config/soma-player/config.toml ~/.config/soma-player/config.toml.backup

# Restart application (creates new default config)
soma-player

Performance Issues

High CPU Usage

Symptoms: System becomes slow while playing

Solutions:

  1. Check running processes:

    top | grep soma-player
    
  2. Reduce terminal effects: Use simpler terminal themes

  3. Update system: Ensure OS and drivers are current

Memory Usage

Symptoms: Memory usage grows over time

Solutions:

  1. Restart periodically: Long-running sessions may accumulate memory
  2. Check logs: Look for memory-related errors in logs
  3. Update: Ensure you're running the latest version

Network Issues

Proxy/Corporate Network

Problem: Cannot connect through corporate proxy

Solutions:

  1. HTTP proxy: Set proxy environment variables

    export http_proxy=http://proxy.company.com:8080
    export https_proxy=http://proxy.company.com:8080
    
  2. Direct connection: Try from personal network to isolate issue

Firewall Blocking

Problem: Connections blocked by firewall

Required access:

  • Outbound HTTP (port 80)
  • Outbound HTTPS (port 443)
  • Audio streams (various ports)

Logging and Debugging

Enable Debug Logging

RUST_LOG=debug soma-player

Check Log Files

# View recent logs
tail -f ~/.config/soma-player/logs/soma-player.log

# Search for errors
grep -i error ~/.config/soma-player/logs/soma-player.log

Collect Debug Information

For bug reports, collect:

  1. Version information:

    soma-player --version
    
  2. System information:

    uname -a
    
  3. Terminal information:

    echo $TERM
    tput colors
    
  4. Log excerpt (relevant error messages)

Getting Help

Before Reporting Issues

  1. Check this troubleshooting guide
  2. Search existing issues on GitHub
  3. Try with debug logging enabled
  4. Test basic functionality (can you run soma-player --version?)

Reporting Bugs

Include this information:

  • Exact error message
  • Steps to reproduce
  • System information (OS, terminal)
  • Log files (with debug enabled)
  • Expected vs actual behavior

Community Support

  • GitHub Issues: Technical problems and bugs
  • GitHub Discussions: General questions and usage help

Quick Fixes

Complete Reset

If all else fails, completely reset the application:

# Stop the application
# Remove all application data
rm -rf ~/.config/soma-player

# Reinstall (if using install script)
curl -sSL https://raw.githubusercontent.com/mpuccini/soma-play/main/install.sh | bash

# Or rebuild from source
git clone https://github.com/mpuccini/soma-play.git
cd soma-play
cargo build --release
cp target/release/soma-player ~/.local/bin/

Emergency Commands

If the interface becomes unresponsive:

  • Ctrl+C: Force quit (may leave terminal in bad state)
  • Ctrl+Z: Suspend (then fg to resume or kill %1 to terminate)
  • Close terminal: Last resort

Architecture

Technical overview of SomaFM Player's internal structure and design.

Project Structure

SomaFM Player follows a modular architecture with clear separation of concerns:

src/
├── main.rs           # Application entry point and CLI handling
├── lib.rs            # Module declarations and exports
├── api/              # SomaFM API integration
│   ├── mod.rs        # API module exports
│   ├── client.rs     # HTTP client for SomaFM API
│   └── channels.rs   # Channel data structures and parsing
├── audio/            # Audio playback engine
│   ├── mod.rs        # Audio module exports
│   ├── player.rs     # Main audio player implementation
│   ├── stream.rs     # Audio stream handling
│   └── commands.rs   # Player command definitions
├── config/           # Configuration management
│   ├── mod.rs        # Config module exports
│   ├── settings.rs   # Configuration data structures
│   └── file.rs       # File I/O operations
├── models/           # Data structures and types
│   ├── mod.rs        # Models module exports
│   ├── channel.rs    # Channel data model
│   ├── player.rs     # Player state model
│   ├── errors.rs     # Custom error types
│   └── spectrum.rs   # Spectrum visualizer data
└── ui/               # Terminal User Interface
    ├── mod.rs        # UI module exports
    ├── app.rs        # Main application state
    ├── player.rs     # Player interface screen
    ├── channels.rs   # Channel selection screen
    └── spectrum.rs   # Spectrum visualizer widget

Core Components

1. Main Application (main.rs)

Responsibilities:

  • Command-line argument parsing
  • Logging initialization
  • Error handling setup
  • Application bootstrap

Key Features:

  • Early argument processing (--version, --help)
  • Color error reporting with color-eyre
  • Structured logging with tracing
// Simplified flow
fn main() -> Result<()> {
    // 1. Parse CLI args
    // 2. Setup logging
    // 3. Load configuration
    // 4. Initialize TUI
    // 5. Run main loop
}

2. API Layer (api/)

Purpose: Interface with SomaFM's public API and stream endpoints.

Components:

  • client.rs: HTTP client wrapper around reqwest
  • channels.rs: Channel data parsing and caching

Key Features:

  • Async HTTP requests with retry logic
  • Channel list caching
  • ICY metadata parsing for "now playing" info
  • Error handling for network issues
#![allow(unused)]
fn main() {
pub struct SomaClient {
    client: reqwest::Client,
    base_url: String,
}

impl SomaClient {
    pub async fn get_channels() -> Result<Vec<Channel>>;
    pub async fn get_stream_url(channel_id: &str) -> Result<String>;
}
}

3. Audio Engine (audio/)

Purpose: Handle audio streaming and playback control.

Components:

  • player.rs: Main audio player using rodio
  • stream.rs: Stream management and buffering
  • commands.rs: Command patterns for player control

Key Features:

  • Cross-platform audio output via rodio
  • Volume control with persistent settings
  • Pause/resume functionality
  • Stream reconnection handling
#![allow(unused)]
fn main() {
pub enum PlayerCommand {
    Play(String),      // Stream URL
    Pause,
    Resume,
    SetVolume(f32),
    Stop,
}

pub struct AudioPlayer {
    sink: Option<rodio::Sink>,
    volume: f32,
    state: PlayerState,
}
}

4. Configuration (config/)

Purpose: Manage application settings and persistence.

Components:

  • settings.rs: Configuration data structures
  • file.rs: TOML file I/O operations

Key Features:

  • TOML-based configuration
  • Automatic directory creation
  • Default value handling
  • Type-safe configuration access
#![allow(unused)]
fn main() {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Config {
    pub last_channel_id: Option<String>,
    pub volume: u8,
    pub auto_start: bool,
}
}

5. Data Models (models/)

Purpose: Define core data structures and business logic.

Components:

  • channel.rs: SomaFM channel representation
  • player.rs: Player state management
  • errors.rs: Custom error types with context
  • spectrum.rs: Spectrum analyzer data structures

Key Features:

  • Serde serialization support
  • Rich error types with stack traces
  • Type safety throughout the application
#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Channel {
    pub id: String,
    pub title: String,
    pub description: String,
    pub listeners: u32,
    pub genre: String,
}
}

6. User Interface (ui/)

Purpose: Terminal-based user interface using ratatui.

Components:

  • app.rs: Application state machine
  • player.rs: Main playback interface
  • channels.rs: Channel selection screens
  • spectrum.rs: Real-time spectrum visualizer

Key Features:

  • Event-driven architecture
  • Responsive layout system
  • Real-time spectrum visualization
  • Keyboard input handling
#![allow(unused)]
fn main() {
pub enum AppState {
    ChannelSelection,
    Playing,
    ChannelOverlay,
    Quitting,
}

pub struct App {
    pub state: AppState,
    pub channels: Vec<Channel>,
    pub selected_channel: Option<usize>,
    pub player_state: PlayerState,
}
}

Data Flow

Application Startup

  1. CLI Parsing → Parse command-line arguments
  2. Logging Setup → Initialize structured logging
  3. Config Loading → Load/create configuration file
  4. API Initialization → Fetch channel list from SomaFM
  5. UI Startup → Initialize terminal interface
  6. Event Loop → Start main application loop

Channel Selection Flow

  1. User Input → Keyboard navigation
  2. UI Update → Highlight selected channel
  3. Channel Selection → User presses Enter
  4. Stream Resolution → Get stream URL from API
  5. Audio Playback → Start audio player
  6. State Transition → Switch to playing mode

Audio Playback Flow

  1. Stream Request → HTTP request to stream URL
  2. Stream Decoding → Audio format detection and decoding
  3. Audio Output → Platform-specific audio output
  4. Metadata Parsing → Extract "now playing" information
  5. UI Updates → Display current track info
  6. Spectrum Analysis → Generate frequency data for visualizer

Threading Model

Main Thread

  • UI rendering and event handling
  • Configuration management
  • Application state coordination

Audio Thread (via rodio)

  • Audio decoding and playback
  • Stream buffering
  • Volume control

Network Thread (via tokio)

  • HTTP requests to SomaFM API
  • Stream data fetching
  • Metadata updates

Error Handling Strategy

Error Types

  • Network Errors: API timeouts, connection failures
  • Audio Errors: Codec issues, hardware problems
  • Configuration Errors: File I/O, parsing failures
  • UI Errors: Terminal capabilities, rendering issues

Error Propagation

#![allow(unused)]
fn main() {
// Custom Result type with context
pub type Result<T> = std::result::Result<T, SomaError>;

// Rich error context
#[derive(Debug, thiserror::Error)]
pub enum SomaError {
    #[error("Network error: {0}")]
    Network(#[from] reqwest::Error),
    
    #[error("Audio error: {0}")]
    Audio(String),
    
    #[error("Configuration error: {0}")]
    Config(#[from] toml::de::Error),
}
}

Performance Considerations

Memory Management

  • Channel List Caching: Avoid repeated API calls
  • Audio Buffering: Optimal buffer sizes for smooth playback
  • UI Rendering: Efficient terminal updates

Network Optimization

  • Connection Reuse: HTTP client connection pooling
  • Retry Logic: Exponential backoff for failed requests
  • Stream Recovery: Automatic reconnection on network issues

CPU Usage

  • Spectrum Analysis: Optimized FFT calculations
  • UI Updates: Minimal redraws, only when necessary
  • Event Processing: Efficient input handling

Dependencies

Core Dependencies

  • ratatui: Terminal UI framework
  • rodio: Cross-platform audio playback
  • reqwest: HTTP client with async support
  • tokio: Async runtime
  • serde: Serialization framework
  • toml: Configuration file format

Development Dependencies

  • tracing: Structured logging
  • color-eyre: Enhanced error reporting
  • tempfile: Testing utilities

Testing Strategy

Unit Tests

  • Configuration loading/saving
  • Error type conversions
  • Data model validation
  • API response parsing

Integration Tests

  • Audio playback scenarios
  • UI state transitions
  • Configuration persistence
  • Network error handling

Test Structure

tests/
├── integration/
│   ├── config_tests.rs
│   ├── audio_tests.rs
│   └── ui_tests.rs
└── common/
    └── test_helpers.rs

Future Architecture Considerations

Planned Enhancements

  1. Plugin System: Extensible architecture for additional features
  2. Themes Support: Customizable UI themes and colors
  3. Keyboard Customization: User-defined keybindings
  4. Multi-instance Support: Multiple concurrent streams
  5. Remote Control: HTTP API for external control

Scalability

  • Modular Design: Easy to add new features
  • Clear Interfaces: Well-defined module boundaries
  • Minimal Coupling: Loose dependencies between components
  • Testable Code: Architecture supports comprehensive testing

This architecture provides a solid foundation for a reliable, maintainable, and extensible audio streaming application.

API Reference

Developer reference for SomaFM Player's internal APIs and data structures.

Note: This page covers the internal Rust API. For the complete generated API documentation with full type information, see the API Documentation section.

Core Modules

soma_player::config

Configuration management for persistent settings.

Config

#![allow(unused)]
fn main() {
pub struct Config {
    pub last_channel_id: Option<String>,
    pub volume: u8,
    pub auto_start: bool,
}
}

Methods:

  • Config::load() -> Result<Config> - Load configuration from file
  • Config::save(&self) -> Result<()> - Save configuration to file
  • Config::default_path() -> PathBuf - Get default config file path

Example:

#![allow(unused)]
fn main() {
use soma_player::config::Config;

let mut config = Config::load()?;
config.volume = 75;
config.save()?;
}

soma_player::models

Core data structures and types.

Channel

#![allow(unused)]
fn main() {
pub struct Channel {
    pub id: String,
    pub title: String,
    pub description: String,
    pub listeners: u32,
    pub genre: String,
}
}

Represents a SomaFM radio channel with metadata.

PlayerState

#![allow(unused)]
fn main() {
pub enum PlayerState {
    Stopped,
    Playing,
    Paused,
    Buffering,
    Error(String),
}
}

Current state of the audio player.

SomaError

#![allow(unused)]
fn main() {
pub enum SomaError {
    Network(reqwest::Error),
    Audio(String),
    Config(toml::de::Error),
    Io(std::io::Error),
    Parse(String),
}
}

Comprehensive error types with context information.

soma_player::api

SomaFM API integration and HTTP client.

SomaClient

#![allow(unused)]
fn main() {
pub struct SomaClient {
    // Internal HTTP client
}
}

Methods:

  • SomaClient::new() -> Self - Create new API client
  • get_channels(&self) -> Result<Vec<Channel>> - Fetch available channels
  • get_stream_url(&self, channel_id: &str) -> Result<String> - Get stream URL

Example:

#![allow(unused)]
fn main() {
use soma_player::api::SomaClient;

let client = SomaClient::new();
let channels = client.get_channels().await?;
let stream_url = client.get_stream_url("groovesalad").await?;
}

soma_player::audio

Audio playback engine and controls.

AudioPlayer

#![allow(unused)]
fn main() {
pub struct AudioPlayer {
    // Audio sink and state
}
}

Methods:

  • AudioPlayer::new() -> Result<Self> - Create new audio player
  • play(&mut self, url: String) -> Result<()> - Start playing stream
  • pause(&mut self) -> Result<()> - Pause playback
  • resume(&mut self) -> Result<()> - Resume playback
  • set_volume(&mut self, volume: f32) -> Result<()> - Set volume (0.0-1.0)
  • stop(&mut self) -> Result<()> - Stop playback

PlayerCommand

#![allow(unused)]
fn main() {
pub enum PlayerCommand {
    Play(String),
    Pause,
    Resume,
    SetVolume(f32),
    Stop,
}
}

Commands for controlling audio playback.

Example:

#![allow(unused)]
fn main() {
use soma_player::audio::{AudioPlayer, PlayerCommand};

let mut player = AudioPlayer::new()?;
player.play("http://stream.url".to_string())?;
player.set_volume(0.75)?;
}

soma_player::ui

Terminal user interface components.

App

#![allow(unused)]
fn main() {
pub struct App {
    pub state: AppState,
    pub channels: Vec<Channel>,
    pub selected_channel: Option<usize>,
    // ... other fields
}
}

Main application state container.

AppState

#![allow(unused)]
fn main() {
pub enum AppState {
    ChannelSelection,
    Playing,
    ChannelOverlay,
    Quitting,
}
}

Current UI state for the application.

Methods:

  • App::new(channels: Vec<Channel>) -> Self - Create new app instance
  • handle_input(&mut self, event: KeyEvent) -> Result<()> - Process keyboard input
  • update(&mut self) -> Result<()> - Update application state
  • should_quit(&self) -> bool - Check if app should exit

Data Flow APIs

Configuration Flow

#![allow(unused)]
fn main() {
// Load configuration
let config = Config::load().unwrap_or_default();

// Use configuration
if config.auto_start {
    // Auto-start last channel
}

// Save changes
config.volume = new_volume;
config.save()?;
}

Channel Management

#![allow(unused)]
fn main() {
// Fetch channels from API
let client = SomaClient::new();
let channels = client.get_channels().await?;

// Select channel
let selected = &channels[index];
let stream_url = client.get_stream_url(&selected.id).await?;
}

Audio Control

#![allow(unused)]
fn main() {
// Initialize player
let mut player = AudioPlayer::new()?;

// Control playback
player.play(stream_url)?;
player.set_volume(0.8)?;
player.pause()?;
player.resume()?;
}

UI Event Handling

#![allow(unused)]
fn main() {
// Create app
let mut app = App::new(channels);

// Main event loop
loop {
    if let Ok(event) = event::read() {
        app.handle_input(event)?;
        app.update()?;
        
        if app.should_quit() {
            break;
        }
    }
}
}

Error Handling

Result Types

All fallible operations return Result<T, SomaError>:

#![allow(unused)]
fn main() {
pub type Result<T> = std::result::Result<T, SomaError>;
}

Error Context

Errors include rich context information:

#![allow(unused)]
fn main() {
use soma_player::Result;

fn example_function() -> Result<()> {
    config.load()
        .map_err(|e| SomaError::Config(e))?;
    Ok(())
}
}

Error Conversion

Automatic conversion from standard error types:

#![allow(unused)]
fn main() {
impl From<std::io::Error> for SomaError {
    fn from(err: std::io::Error) -> Self {
        SomaError::Io(err)
    }
}
}

Async Patterns

API Calls

use tokio;

#[tokio::main]
async fn main() -> Result<()> {
    let client = SomaClient::new();
    let channels = client.get_channels().await?;
    Ok(())
}

Non-blocking Operations

#![allow(unused)]
fn main() {
// Spawn background task for API calls
let handle = tokio::spawn(async move {
    client.get_channels().await
});

// Continue with UI work
// ...

// Get result when needed
let channels = handle.await??;
}

Testing APIs

Unit Testing

#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::tempdir;

    #[test]
    fn test_config_save_load() {
        let dir = tempdir().unwrap();
        let config_path = dir.path().join("config.toml");
        
        let config = Config {
            volume: 75,
            last_channel_id: Some("groovesalad".to_string()),
            auto_start: true,
        };
        
        config.save_to_path(&config_path).unwrap();
        let loaded = Config::load_from_path(&config_path).unwrap();
        
        assert_eq!(config.volume, loaded.volume);
    }
}
}

Mock Objects

#![allow(unused)]
fn main() {
// Mock API client for testing
pub struct MockSomaClient {
    channels: Vec<Channel>,
}

impl MockSomaClient {
    pub fn new(channels: Vec<Channel>) -> Self {
        Self { channels }
    }
}

#[async_trait]
impl ApiClient for MockSomaClient {
    async fn get_channels(&self) -> Result<Vec<Channel>> {
        Ok(self.channels.clone())
    }
}
}

Extension Points

Custom Audio Backends

#![allow(unused)]
fn main() {
pub trait AudioBackend {
    fn play(&mut self, url: String) -> Result<()>;
    fn pause(&mut self) -> Result<()>;
    fn set_volume(&mut self, volume: f32) -> Result<()>;
}

// Implement for different audio systems
impl AudioBackend for RodioBackend { /* ... */ }
impl AudioBackend for PulseAudioBackend { /* ... */ }
}

Custom UI Themes

#![allow(unused)]
fn main() {
pub struct Theme {
    pub primary_color: Color,
    pub secondary_color: Color,
    pub background_color: Color,
    pub accent_color: Color,
}

impl App {
    pub fn set_theme(&mut self, theme: Theme) {
        self.theme = theme;
    }
}
}

Performance APIs

Caching

#![allow(unused)]
fn main() {
use std::collections::HashMap;

pub struct ChannelCache {
    cache: HashMap<String, Vec<Channel>>,
    ttl: Duration,
}

impl ChannelCache {
    pub fn get_or_fetch(&mut self, key: &str) -> Result<Vec<Channel>> {
        // Return cached data or fetch new
    }
}
}

Metrics

#![allow(unused)]
fn main() {
pub struct Metrics {
    pub api_calls: u64,
    pub cache_hits: u64,
    pub audio_buffer_underruns: u64,
}

impl App {
    pub fn get_metrics(&self) -> Metrics {
        // Return current metrics
    }
}
}

Constants and Configuration

Default Values

#![allow(unused)]
fn main() {
pub const DEFAULT_VOLUME: u8 = 50;
pub const DEFAULT_CONFIG_DIR: &str = ".config/soma-player";
pub const API_BASE_URL: &str = "https://somafm.com";
pub const STREAM_TIMEOUT: Duration = Duration::from_secs(30);
}

Build Information

#![allow(unused)]
fn main() {
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const BUILD_TARGET: &str = env!("TARGET");
pub const BUILD_TIMESTAMP: &str = env!("BUILD_TIMESTAMP");
}

Feature Flags

Conditional Compilation

#![allow(unused)]
fn main() {
#[cfg(feature = "spectrum-analyzer")]
pub mod spectrum {
    // Spectrum analyzer functionality
}

#[cfg(not(feature = "spectrum-analyzer"))]
pub mod spectrum {
    // Stub implementation
}
}

This API reference provides the essential interfaces for working with SomaFM Player's codebase. For complete type information and implementation details, refer to the generated API Documentation.

Contributing

Welcome to SomaFM Player! We're excited to have you contribute to this project.

Getting Started

Prerequisites

Before you begin, ensure you have the following installed:

  1. Rust (1.70 or later)

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    
  2. System Dependencies (Linux only)

    # Ubuntu/Debian
    sudo apt-get install libasound2-dev pkg-config
    
    # Fedora/CentOS/RHEL
    sudo dnf install alsa-lib-devel pkg-config
    
    # Arch Linux
    sudo pacman -S alsa-lib pkg-config
    
  3. Git

    git --version
    

Development Setup

  1. Fork the repository on GitHub

  2. Clone your fork

    git clone https://github.com/yourusername/soma-play.git
    cd soma-play
    
  3. Add upstream remote

    git remote add upstream https://github.com/mpuccini/soma-play.git
    
  4. Install development tools

    # Code formatting
    rustup component add rustfmt
    
    # Linting
    rustup component add clippy
    
    # Documentation
    cargo install mdbook
    
    # Security auditing
    cargo install cargo-audit
    
    # Test coverage
    cargo install cargo-tarpaulin
    
  5. Build and test

    cargo build
    cargo test
    cargo run
    

Development Workflow

1. Create a Feature Branch

git checkout -b feature/your-feature-name

Branch Naming Conventions:

  • feature/ - New features
  • fix/ - Bug fixes
  • docs/ - Documentation updates
  • refactor/ - Code refactoring
  • test/ - Test improvements

2. Make Your Changes

Follow our coding standards and guidelines (see below).

3. Test Your Changes

# Run all tests
cargo test

# Run tests with output
cargo test -- --nocapture

# Run specific test module
cargo test config::tests

# Check code formatting
cargo fmt --check

# Run linter
cargo clippy -- -D warnings

# Generate test coverage
cargo tarpaulin --out Html

4. Commit Your Changes

Commit Message Format:

<type>(<scope>): <subject>

<body>

<footer>

Types:

  • feat - New feature
  • fix - Bug fix
  • docs - Documentation
  • style - Code style changes
  • refactor - Code refactoring
  • test - Test additions/improvements
  • chore - Maintenance tasks

Examples:

git commit -m "feat(audio): add volume fade transitions"
git commit -m "fix(ui): resolve channel list scrolling issue"
git commit -m "docs(api): update configuration examples"

5. Push and Create Pull Request

git push origin feature/your-feature-name

Then create a pull request on GitHub.

Coding Standards

Rust Code Style

  1. Use cargo fmt for consistent formatting

  2. Follow Rust naming conventions

    • snake_case for functions and variables
    • PascalCase for types and structs
    • SCREAMING_SNAKE_CASE for constants
  3. Add documentation comments

    #![allow(unused)]
    fn main() {
    /// Plays audio from the specified stream URL.
    ///
    /// # Arguments
    /// * `url` - The stream URL to play from
    ///
    /// # Examples
    /// ```
    /// let mut player = AudioPlayer::new()?;
    /// player.play("http://stream.somafm.com/groovesalad".to_string())?;
    /// ```
    pub fn play(&mut self, url: String) -> Result<()> {
        // Implementation
    }
    }
  4. Handle errors properly

    #![allow(unused)]
    fn main() {
    // Good: Use Result types and proper error handling
    fn load_config() -> Result<Config, ConfigError> {
        let content = fs::read_to_string(&path)
            .map_err(ConfigError::FileRead)?;
        toml::from_str(&content)
            .map_err(ConfigError::Parse)
    }
    
    // Avoid: Using unwrap() or expect() in library code
    }
  5. Use meaningful variable names

    #![allow(unused)]
    fn main() {
    // Good
    let selected_channel_index = 0;
    let stream_url = "http://...";
    
    // Avoid
    let i = 0;
    let url = "http://...";
    }

Module Organization

  1. Keep modules focused - Each module should have a single responsibility
  2. Use clear imports - Prefer explicit imports over glob imports
  3. Organize by feature - Group related functionality together
#![allow(unused)]
fn main() {
// Good: Explicit imports
use crate::config::Config;
use crate::models::{Channel, PlayerState};

// Avoid: Glob imports (in most cases)
use crate::models::*;
}

Error Handling

  1. Use custom error types with thiserror
  2. Provide context for errors
  3. Convert errors at module boundaries
#![allow(unused)]
fn main() {
#[derive(Debug, thiserror::Error)]
pub enum AudioError {
    #[error("Failed to initialize audio device: {0}")]
    DeviceInit(String),
    
    #[error("Stream error: {0}")]
    Stream(#[from] StreamError),
    
    #[error("Invalid volume level: {level} (must be 0-100)")]
    InvalidVolume { level: u8 },
}
}

Testing Guidelines

  1. Write unit tests for all public functions
  2. Use integration tests for complex workflows
  3. Mock external dependencies in tests
  4. Test error conditions as well as success cases
#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::tempdir;

    #[test]
    fn test_config_save_and_load() {
        let dir = tempdir().unwrap();
        let config_path = dir.path().join("config.toml");
        
        let original_config = Config {
            volume: 75,
            last_channel_id: Some("groovesalad".to_string()),
            auto_start: true,
        };
        
        // Test save
        original_config.save_to_path(&config_path).unwrap();
        
        // Test load
        let loaded_config = Config::load_from_path(&config_path).unwrap();
        
        assert_eq!(original_config.volume, loaded_config.volume);
        assert_eq!(original_config.last_channel_id, loaded_config.last_channel_id);
        assert_eq!(original_config.auto_start, loaded_config.auto_start);
    }
    
    #[test]
    fn test_invalid_volume_returns_error() {
        let mut player = AudioPlayer::new().unwrap();
        let result = player.set_volume(150); // Invalid volume > 100
        assert!(result.is_err());
    }
}
}

Documentation

Code Documentation

  1. Document all public APIs with examples
  2. Include usage examples in documentation
  3. Document error conditions and return types
  4. Keep documentation up to date with code changes

User Documentation

  1. Update relevant guide sections when adding features
  2. Include configuration examples for new settings
  3. Add troubleshooting entries for known issues
  4. Update the changelog with user-facing changes

Building Documentation

# Generate API documentation
cargo doc --open

# Build user guide
cd docs && mdbook serve --open

# Build all documentation
./build-docs.sh

Feature Development

Adding New Features

  1. Create an issue describing the feature
  2. Discuss the approach with maintainers
  3. Start with tests (TDD approach when possible)
  4. Implement incrementally with small, focused commits
  5. Update documentation before marking as complete

Feature Guidelines

  1. Maintain backward compatibility when possible
  2. Add configuration options for user preferences
  3. Consider performance impact of new features
  4. Ensure cross-platform compatibility

Example: Adding a New Feature

#![allow(unused)]
fn main() {
// 1. Define the feature interface
pub trait Equalizer {
    fn set_bands(&mut self, bands: Vec<f32>) -> Result<()>;
    fn get_bands(&self) -> Vec<f32>;
}

// 2. Add configuration support
#[derive(Serialize, Deserialize)]
pub struct EqualizerConfig {
    pub enabled: bool,
    pub bands: Vec<f32>,
}

// 3. Implement the feature
pub struct GraphicEqualizer {
    bands: Vec<f32>,
    enabled: bool,
}

// 4. Add tests
#[cfg(test)]
mod tests {
    #[test]
    fn test_equalizer_bands() {
        let mut eq = GraphicEqualizer::new();
        let bands = vec![0.0, 2.0, 4.0, 2.0, 0.0];
        eq.set_bands(bands.clone()).unwrap();
        assert_eq!(eq.get_bands(), bands);
    }
}

// 5. Update UI integration
impl App {
    pub fn toggle_equalizer(&mut self) -> Result<()> {
        // Implementation
    }
}
}

Bug Fixes

Finding and Reporting Bugs

  1. Search existing issues before creating new ones
  2. Provide detailed reproduction steps
  3. Include system information (OS, Rust version, etc.)
  4. Add logs or error messages when applicable

Fixing Bugs

  1. Write a test that reproduces the bug
  2. Fix the issue with minimal changes
  3. Verify the test passes with your fix
  4. Check for similar issues in related code

Performance Considerations

Optimization Guidelines

  1. Profile before optimizing - Measure, don't guess
  2. Focus on hot paths - Audio playback, UI rendering
  3. Consider memory usage - Avoid unnecessary allocations
  4. Benchmark changes - Ensure improvements are real

Performance Testing

# Run benchmarks (if available)
cargo bench

# Profile memory usage
cargo run --release -- --log-level=debug

# Monitor resource usage during development
htop  # or similar system monitor

Security

Security Guidelines

  1. Validate all inputs from external sources
  2. Use secure HTTP for API communications
  3. Handle credentials safely (if any)
  4. Audit dependencies regularly
# Run security audit
cargo audit

# Check for known vulnerabilities
cargo audit --database advisory

Release Process

Preparing a Release

  1. Update version numbers in Cargo.toml
  2. Update CHANGELOG.md with new features and fixes
  3. Run full test suite with cargo test
  4. Generate and review documentation
  5. Test on target platforms

Release Checklist

  • All tests pass
  • Documentation is up to date
  • Changelog is updated
  • Version numbers are bumped
  • No security vulnerabilities
  • Performance regressions checked
  • Cross-platform compatibility verified

Community Guidelines

Communication

  1. Be respectful and inclusive
  2. Ask questions when you're unsure
  3. Provide constructive feedback in reviews
  4. Help newcomers get started

Code Reviews

  1. Review for correctness and style
  2. Suggest improvements rather than just pointing out problems
  3. Acknowledge good work and clever solutions
  4. Be open to feedback on your own code

Issue Management

  1. Provide clear descriptions for issues and PRs
  2. Link related issues and PRs
  3. Update status as work progresses
  4. Close issues when resolved

Getting Help

Resources

  • Documentation: User Guide and API Reference
  • Source Code: Well-commented and documented
  • Issues: Check existing issues for similar problems
  • Discussions: GitHub Discussions for questions and ideas

Contact

  • GitHub Issues: For bugs and feature requests
  • GitHub Discussions: For questions and general discussion
  • Pull Requests: For code contributions and reviews

Thank you for contributing to SomaFM Player! Your efforts help make this project better for everyone. 🎵

Controls Reference

Complete keyboard controls for SomaFM Player.

Overview

SomaFM Player has three main interface modes, each with its own set of controls:

  1. Channel Selection Screen - Initial startup screen
  2. Playing Mode - Main playback interface
  3. Channel Selection Overlay - Quick channel switching while playing

Channel Selection Screen

This is the first screen you see when starting the application.

KeyActionDescription
Navigate UpMove selection to previous channel
Navigate DownMove selection to next channel
EnterSelect ChannelStart playing the selected channel
QQuitExit the application

Mouse Support

  • Scroll Wheel: Navigate through channels (if terminal supports it)
  • Click: Select channel (if terminal supports it)

Playing Mode

Once you've selected a channel and music is playing.

Playback Controls

KeyActionDescription
PPause/ResumeToggle playback state
QQuitExit the application
EscQuitAlternative quit key

Volume Controls

KeyActionDescription
+Volume UpIncrease volume by 5%
=Volume UpAlternative volume up key
-Volume DownDecrease volume by 5%
_Volume DownAlternative volume down key

Volume Range: 0% to 100%
Volume Step: 5% per key press
Auto-save: Volume changes are automatically saved

Channel Controls

KeyActionDescription
CChange ChannelOpen channel selection overlay

Channel Selection Overlay

Accessible by pressing C while in playing mode.

KeyActionDescription
Navigate UpMove selection to previous channel
Navigate DownMove selection to next channel
EnterSwitch ChannelChange to selected channel and close overlay
EscCancelClose overlay without changing channel
QQuitExit the application

Behavior Notes

  • Seamless switching: Audio continues playing while browsing
  • Instant change: New channel starts immediately when selected
  • Previous state: If cancelled, returns to current playing channel

Special Key Combinations

Force Quit

Key CombinationActionWhen to Use
Ctrl+CForce QuitIf application becomes unresponsive
Ctrl+ZSuspendPause process (use fg to resume)

⚠️ Note: Force quit may leave your terminal in an inconsistent state. Use normal quit (Q) when possible.

Universal Controls

These keys work in all modes:

KeyAvailable InAction
QAll modesQuit application
Ctrl+CAll modesForce quit

Key Behavior Details

  • Continuous scrolling: Hold arrow keys to scroll quickly
  • Wrap-around: Navigation wraps from bottom to top and vice versa
  • Visual feedback: Current selection is highlighted

Volume Keys

  • Immediate effect: Volume changes apply instantly
  • Visual feedback: Volume level displayed in interface
  • Bounds checking: Cannot go below 0% or above 100%
  • Persistence: Settings saved automatically

Response Time

  • Instant: All key presses register immediately
  • No delay: No artificial delays or key repeat issues
  • Reliable: Input processing is prioritized

Accessibility Features

Keyboard-Only Operation

  • No mouse required: Full functionality via keyboard
  • Clear navigation: Obvious visual indicators for current selection
  • Consistent patterns: Similar controls across all modes

Visual Indicators

  • Highlighted selection: Current item clearly marked
  • Status display: Current channel, volume, and playback state visible
  • Color coding: Different colors for different interface elements

Terminal Compatibility

  • Alacritty: Full compatibility
  • Kitty: Full compatibility
  • iTerm2 (macOS): Full compatibility
  • Windows Terminal: Full compatibility
  • GNOME Terminal: Full compatibility

Key Support Notes

  • Function keys: Not used (for maximum compatibility)
  • Alt combinations: Not used (may conflict with terminal)
  • Standard keys only: Uses only common, reliable key codes

Customization

Current Limitations

  • Fixed keybindings: Keys cannot be customized currently
  • Future feature: Customizable controls planned for future release

Workarounds

  • Terminal keybinding: Some terminals allow key remapping
  • Screen/tmux: Can provide additional key handling if needed

Quick Reference Card

Essential Keys

Playing Mode:
  P = Pause/Resume    C = Change Channel
  + = Volume Up       - = Volume Down
  Q = Quit

Channel Selection:
  ↑↓ = Navigate      Enter = Select
  Q = Quit

Channel Overlay:
  ↑↓ = Navigate      Enter = Switch
  Esc = Cancel       Q = Quit

Memory Tips

  • Pause for Playback control
  • Change for Channel selection
  • +/- for volume (like calculator)
  • Quit to Quit (universal)
  • Escape to cancel overlay

This control scheme is designed to be intuitive and memorable while providing full functionality through the keyboard interface.

Configuration Options

Complete reference for all configuration options in SomaFM Player.

Configuration File

Location

~/.config/soma-player/config.toml

Format

The configuration file uses TOML format for human-readable settings.

Example Configuration

# SomaFM Player Configuration

# Last played channel (auto-saved)
last_channel_id = "groovesalad"

# Audio volume (0-100)
volume = 75

# Skip channel selection on startup
auto_start = false

# Logging configuration
[logging]
level = "info"
file_rotation = true
max_files = 7

# User interface settings
[ui]
show_spectrum = true
spectrum_style = "bars"
color_scheme = "default"

# Audio settings
[audio]
buffer_size = 4096
sample_rate = 44100
reconnect_attempts = 3

Core Options

last_channel_id

Type: String (optional)
Default: None
Auto-managed: Yes

The ID of the last played channel. This is automatically saved when you switch channels and used to restore your session.

Valid Values:

  • Any valid SomaFM channel ID (e.g., "groovesalad", "dronezone", "lush")
  • null or empty for no default channel

Example:

last_channel_id = "groovesalad"

volume

Type: Integer
Default: 50
Range: 0-100
Auto-managed: Yes

Audio volume level as a percentage. Changes are automatically saved when you adjust volume during playback.

Example:

volume = 75

auto_start

Type: Boolean
Default: false

Skip the channel selection screen and automatically start playing the last channel on startup.

Behavior:

  • true: Immediately start playing last_channel_id (if set)
  • false: Show channel selection screen (default behavior)

Example:

auto_start = true

Logging Options

[logging] Section

Configure logging behavior and output.

level

Type: String
Default: "info"
Values: "error", "warn", "info", "debug", "trace"

Sets the minimum log level for file and console output.

Log Levels:

  • error: Only critical errors
  • warn: Warnings and errors
  • info: General information (recommended)
  • debug: Detailed debugging information
  • trace: Very verbose tracing (development only)

Example:

[logging]
level = "debug"

file_rotation

Type: Boolean
Default: true

Enable automatic log file rotation to prevent disk space issues.

Behavior:

  • true: Rotate logs daily, keep last 7 days
  • false: Single log file (grows indefinitely)

Example:

[logging]
file_rotation = true

max_files

Type: Integer
Default: 7
Range: 1-365

Number of rotated log files to keep when file_rotation is enabled.

Example:

[logging]
max_files = 14  # Keep 2 weeks of logs

User Interface Options

[ui] Section

Configure the terminal user interface appearance and behavior.

show_spectrum

Type: Boolean
Default: true

Enable or disable the spectrum visualizer display.

Example:

[ui]
show_spectrum = false

spectrum_style

Type: String
Default: "bars"
Values: "bars", "line", "minimal"

Visual style for the spectrum analyzer.

Styles:

  • bars: Vertical bars (default)
  • line: Connected line graph
  • minimal: Simple dots/characters

Example:

[ui]
spectrum_style = "line"

color_scheme

Type: String
Default: "default"
Values: "default", "dark", "light", "monochrome"

Color scheme for the user interface.

Schemes:

  • default: Standard colors
  • dark: Dark theme optimized for dark terminals
  • light: Light theme optimized for light terminals
  • monochrome: No colors (accessibility)

Example:

[ui]
color_scheme = "dark"

Audio Options

[audio] Section

Configure audio playback and streaming behavior.

buffer_size

Type: Integer
Default: 4096
Range: 1024-16384

Audio buffer size in samples. Larger buffers reduce skipping but increase latency.

Recommendations:

  • 1024-2048: Low latency, may skip on slow systems
  • 4096: Balanced (recommended)
  • 8192-16384: High latency, very stable

Example:

[audio]
buffer_size = 8192

sample_rate

Type: Integer
Default: 44100
Values: 22050, 44100, 48000

Preferred audio sample rate in Hz.

Common Rates:

  • 22050: Lower quality, lower bandwidth
  • 44100: CD quality (recommended)
  • 48000: Professional audio quality

Example:

[audio]
sample_rate = 48000

reconnect_attempts

Type: Integer
Default: 3
Range: 0-10

Number of automatic reconnection attempts when stream is lost.

Example:

[audio]
reconnect_attempts = 5

Network Options

[network] Section

Configure network and streaming behavior.

timeout

Type: Integer
Default: 30
Range: 5-300

Network timeout in seconds for API requests and stream connections.

Example:

[network]
timeout = 60

user_agent

Type: String
Default: "SomaFM-Player/{version}"

Custom User-Agent string for HTTP requests.

Example:

[network]
user_agent = "MyCustomPlayer/1.0"

proxy

Type: String (optional)
Default: None

HTTP proxy URL for network requests.

Example:

[network]
proxy = "http://proxy.example.com:8080"

Advanced Options

[advanced] Section

Advanced configuration options for power users.

config_reload_interval

Type: Integer
Default: 0
Range: 0-3600

Automatic configuration reload interval in seconds. 0 disables auto-reload.

Example:

[advanced]
config_reload_interval = 300  # Reload every 5 minutes

memory_limit

Type: Integer
Default: 100
Range: 50-1000

Memory usage limit in MB for caching and buffers.

Example:

[advanced]
memory_limit = 200

Environment Variable Overrides

Logging

  • RUST_LOG: Override log level (e.g., RUST_LOG=debug)
  • SOMA_LOG_FILE: Custom log file path

Configuration

  • SOMA_CONFIG_DIR: Custom configuration directory
  • SOMA_CONFIG_FILE: Custom configuration file path

Audio

  • SOMA_AUDIO_BACKEND: Force specific audio backend
  • SOMA_SAMPLE_RATE: Override sample rate

Examples

# Debug logging
RUST_LOG=debug soma-player

# Custom config location
SOMA_CONFIG_DIR=~/.soma soma-player

# Force sample rate
SOMA_SAMPLE_RATE=48000 soma-player

Configuration Validation

Automatic Validation

The application validates all configuration values on startup:

  • Range Checks: Numeric values within valid ranges
  • Type Validation: Correct data types for all options
  • Enum Validation: Valid choices for string options
  • Path Validation: Writeable paths for logs and cache

Error Handling

Invalid configuration values result in:

  1. Warning Message: Logged to console and file
  2. Default Fallback: Invalid values replaced with defaults
  3. Graceful Degradation: Application continues with valid settings

Example Validation Error

WARNING: Invalid volume value '150' (must be 0-100), using default: 50
WARNING: Unknown color_scheme 'rainbow', using default: 'default'

Configuration File Management

Automatic Creation

If no configuration file exists, one is created with default values on first run.

Backup and Restore

# Backup current configuration
cp ~/.config/soma-player/config.toml ~/.config/soma-player/config.toml.backup

# Restore from backup
cp ~/.config/soma-player/config.toml.backup ~/.config/soma-player/config.toml

# Reset to defaults (delete config file)
rm ~/.config/soma-player/config.toml

Migration

Configuration is automatically migrated when upgrading between versions:

  • Backward Compatibility: Old configurations continue to work
  • New Options: Added with default values
  • Deprecated Options: Ignored with warnings

Security Considerations

File Permissions

Configuration files are created with user-only permissions (600):

# Check permissions
ls -la ~/.config/soma-player/config.toml
# Should show: -rw------- (user read/write only)

Sensitive Data

The configuration file contains no sensitive information:

  • Safe: Volume levels, UI preferences, channel history
  • Never Stored: Passwords, tokens, personal data

Network Settings

When using proxy settings:

  • HTTP Proxies: Supported for SomaFM API requests
  • Authentication: Not currently supported in proxy URLs
  • HTTPS: All SomaFM communication uses HTTPS when available

Troubleshooting Configuration

Common Issues

Configuration Not Loading

# Check file exists
ls ~/.config/soma-player/config.toml

# Check file permissions
ls -la ~/.config/soma-player/config.toml

# Check syntax with TOML validator
python3 -c "import toml; toml.load(open('~/.config/soma-player/config.toml'))"

Settings Not Persisting

  1. Check directory permissions: ~/.config/soma-player/ must be writable
  2. Check disk space: Ensure sufficient space for config file
  3. Check file locks: No other processes accessing the file

Invalid Values Ignored

  • Check logs for validation warnings
  • Verify values are within valid ranges
  • Ensure correct TOML syntax and types

Reset Configuration

# Remove config file to reset to defaults
rm ~/.config/soma-player/config.toml

# Or rename to backup and recreate
mv ~/.config/soma-player/config.toml ~/.config/soma-player/config.toml.old

Configuration Examples

Minimal Configuration

# Basic setup - most users
volume = 70
auto_start = false

Power User Configuration

# Advanced setup with all options
last_channel_id = "dronezone"
volume = 80
auto_start = true

[logging]
level = "info"
file_rotation = true
max_files = 14

[ui]
show_spectrum = true
spectrum_style = "bars"
color_scheme = "dark"

[audio]
buffer_size = 8192
sample_rate = 48000
reconnect_attempts = 5

[network]
timeout = 45
user_agent = "SomaPlayer-Custom/1.0"

[advanced]
config_reload_interval = 300
memory_limit = 150

Development Configuration

# Setup for development and debugging
volume = 50
auto_start = false

[logging]
level = "debug"
file_rotation = false
max_files = 1

[ui]
show_spectrum = true
spectrum_style = "minimal"
color_scheme = "default"

[audio]
buffer_size = 2048
reconnect_attempts = 1

[advanced]
config_reload_interval = 60
memory_limit = 50

This comprehensive configuration reference covers all available options for customizing SomaFM Player to your preferences.

Command Line

Command-line interface and options for SomaFM Player.

Basic Usage

Start the Application

soma-player

This starts the application with the default terminal user interface.

Quick Help

soma-player --help

Version Information

soma-player --version

Command-Line Options

Global Options

--help, -h

Display help information and exit.

soma-player --help
soma-player -h

Output:

SomaFM Player 0.1.6
A terminal-based music player for SomaFM internet radio

USAGE:
    soma-player [OPTIONS] [COMMAND]

OPTIONS:
    -h, --help       Print help information
    -v, --version    Print version information
    -c, --config     Custom configuration file path
    -l, --log-level  Override log level [debug|info|warn|error]
    -q, --quiet      Suppress non-essential output
    -V, --verbose    Enable verbose output

COMMANDS:
    play     Start playing a specific channel
    list     List available channels
    config   Manage configuration
    help     Print this message or the help of a given subcommand

--version, -v

Display version information and build details.

soma-player --version

Output:

soma-player 0.1.6
Build: release
Target: x86_64-unknown-linux-gnu
Rustc: 1.75.0

--config, -c

Specify a custom configuration file path.

soma-player --config /path/to/custom/config.toml
soma-player -c ~/.config/soma-alt/config.toml

Default: ~/.config/soma-player/config.toml

--log-level, -l

Override the log level for this session.

soma-player --log-level debug
soma-player -l warn

Valid Levels: error, warn, info, debug, trace

--quiet, -q

Suppress non-essential output (warnings, info messages).

soma-player --quiet

Effect: Only errors are displayed to the console.

--verbose, -V

Enable verbose output for debugging.

soma-player --verbose

Effect: Equivalent to --log-level debug with additional startup information.

Subcommands

play - Direct Channel Playback

Start playing a specific channel immediately without the UI.

soma-player play <CHANNEL_ID>

Examples:

# Play Groove Salad
soma-player play groovesalad

# Play Drone Zone
soma-player play dronezone

# Play with custom volume
soma-player play groovesalad --volume 75

Options for play

--volume, -V

Set initial volume level (0-100).

soma-player play groovesalad --volume 80
soma-player play dronezone -V 60
--no-ui

Play without launching the terminal interface (headless mode).

soma-player play groovesalad --no-ui

Use Cases:

  • Background music in scripts
  • System service integration
  • Remote/headless servers
--duration, -d

Play for a specific duration then exit.

soma-player play groovesalad --duration 30m
soma-player play dronezone -d 1h

Time Formats:

  • 30s - 30 seconds
  • 5m - 5 minutes
  • 2h - 2 hours
  • 90 - 90 seconds (default unit)

list - Channel Information

Display available SomaFM channels.

soma-player list

Output:

Available SomaFM Channels:

groovesalad     Groove Salad              1,234 listeners
dronezone       Drone Zone                  987 listeners
lush            Lush                        756 listeners
folkfwd         Folk Forward                543 listeners
...

Options for list

--format, -f

Specify output format.

soma-player list --format json
soma-player list --format csv
soma-player list -f table

Formats:

  • table - Human-readable table (default)
  • json - JSON format for scripting
  • csv - CSV format for spreadsheets
  • simple - Simple list of channel IDs
--filter, -F

Filter channels by genre or keyword.

soma-player list --filter electronic
soma-player list --filter ambient
soma-player list -F jazz
--sort, -s

Sort channels by criteria.

soma-player list --sort listeners
soma-player list --sort name
soma-player list -s genre

Sort Options:

  • name - Alphabetical by channel name
  • listeners - By listener count (descending)
  • genre - By genre, then name
  • id - By channel ID

config - Configuration Management

Manage application configuration.

config show

Display current configuration.

soma-player config show

Output:

last_channel_id = "groovesalad"
volume = 75
auto_start = false

[logging]
level = "info"
file_rotation = true

config get

Get a specific configuration value.

soma-player config get volume
soma-player config get logging.level

config set

Set a configuration value.

soma-player config set volume 80
soma-player config set auto_start true
soma-player config set logging.level debug

config reset

Reset configuration to defaults.

# Reset all settings
soma-player config reset

# Reset specific section
soma-player config reset logging

# Reset specific key
soma-player config reset volume

config validate

Validate configuration file syntax and values.

soma-player config validate

Output on success:

Configuration is valid ✓

Output on errors:

Configuration errors:
- Invalid volume value '150' (must be 0-100)
- Unknown color_scheme 'rainbow'

config backup

Create a backup of the current configuration.

soma-player config backup
soma-player config backup --file /path/to/backup.toml

config restore

Restore configuration from a backup.

soma-player config restore
soma-player config restore --file /path/to/backup.toml

Environment Variables

Logging Control

RUST_LOG

Override log level and filtering.

# Debug level for all modules
RUST_LOG=debug soma-player

# Specific module debugging
RUST_LOG=soma_player::audio=debug soma-player

# Multiple modules
RUST_LOG=soma_player::audio=debug,soma_player::ui=info soma-player

SOMA_LOG_FILE

Custom log file location.

SOMA_LOG_FILE=/tmp/soma-debug.log soma-player

Configuration Override

SOMA_CONFIG_DIR

Custom configuration directory.

SOMA_CONFIG_DIR=~/.soma soma-player

SOMA_CONFIG_FILE

Custom configuration file.

SOMA_CONFIG_FILE=/etc/soma-player.toml soma-player

Audio Settings

SOMA_AUDIO_BACKEND

Force specific audio backend.

# Linux: Force ALSA
SOMA_AUDIO_BACKEND=alsa soma-player

# macOS: Force Core Audio
SOMA_AUDIO_BACKEND=coreaudio soma-player

SOMA_SAMPLE_RATE

Override audio sample rate.

SOMA_SAMPLE_RATE=48000 soma-player

Network Settings

SOMA_PROXY

HTTP proxy for all requests.

SOMA_PROXY=http://proxy.example.com:8080 soma-player

SOMA_TIMEOUT

Network timeout in seconds.

SOMA_TIMEOUT=60 soma-player

Exit Codes

Standard Exit Codes

CodeMeaningDescription
0SuccessNormal exit
1General ErrorUnspecified error
2Argument ErrorInvalid command-line arguments
3Config ErrorConfiguration file issues
4Network ErrorNetwork connectivity problems
5Audio ErrorAudio system issues
130InterruptedCtrl+C or SIGINT received

Examples

# Check exit code
soma-player play invalid_channel
echo $?  # Outputs: 4 (network error - channel not found)

# Use in scripts
if soma-player list --quiet; then
    echo "Channels available"
else
    echo "Failed to fetch channels"
fi

Scripting and Automation

Background Playback

# Start playing in background
nohup soma-player play groovesalad --no-ui > /dev/null 2>&1 &

# Save the process ID
echo $! > soma-player.pid

# Stop later
kill $(cat soma-player.pid)

System Service Integration

# systemd service example
[Unit]
Description=SomaFM Player
After=network.target

[Service]
Type=simple
User=music
ExecStart=/usr/local/bin/soma-player play groovesalad --no-ui
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Scheduled Playback

# cron job to play during work hours
# Play Mon-Fri 9 AM to 5 PM
0 9 * * 1-5 /usr/local/bin/soma-player play groovesalad --duration 8h --no-ui

Integration with Other Tools

i3/Polybar Integration

# Get current playing status
soma-player status --format=json | jq -r '.channel.title'

# Volume control
soma-player volume +5
soma-player volume -5

dmenu/rofi Channel Selection

# Channel selection menu
channel=$(soma-player list --format=simple | dmenu -p "Channel:")
if [ -n "$channel" ]; then
    soma-player play "$channel"
fi

Troubleshooting Command-Line Issues

Common Problems

Command Not Found

# Check if installed
which soma-player

# Check PATH
echo $PATH

# Add to PATH if needed
export PATH="$HOME/.local/bin:$PATH"

Permission Denied

# Check file permissions
ls -la $(which soma-player)

# Make executable if needed
chmod +x ~/.local/bin/soma-player

Configuration Errors

# Validate configuration
soma-player config validate

# Reset if corrupted
soma-player config reset

# Use custom config temporarily
soma-player --config /dev/null

Audio Issues

# Test audio system
soma-player play groovesalad --log-level debug

# Try different backend
SOMA_AUDIO_BACKEND=pulse soma-player

# Check audio permissions
groups $USER | grep -E "(audio|pulse-access)"

Debug Mode

# Full debug information
RUST_LOG=debug soma-player --verbose

# Save debug log
RUST_LOG=debug soma-player --verbose 2> debug.log

Integration Examples

Shell Functions

# Add to ~/.bashrc or ~/.zshrc

# Quick channel switching
soma() {
    if [ $# -eq 0 ]; then
        soma-player
    else
        soma-player play "$1"
    fi
}

# Channel search
soma-search() {
    soma-player list --filter "$1"
}

# Current status
soma-status() {
    soma-player status --format=simple
}

Fish Shell Completions

# ~/.config/fish/completions/soma-player.fish
complete -c soma-player -n '__fish_use_subcommand' -a 'play list config help'
complete -c soma-player -n '__fish_seen_subcommand_from play' -a '(soma-player list --format=simple)'

Zsh Completions

# Add to ~/.zshrc
compdef '_files -W ~/.config/soma-player' soma-player --config

This comprehensive command-line reference covers all aspects of using SomaFM Player from the terminal and in automated scenarios.