A REST API that simulates radio channels by providing information about the currently playing song from Plex playlists based on the time of day. Each channel generates a daily shuffled playlist and calculates which song should be playing at any given moment.
- Time-based playback simulation: Calculates what song should be playing based on current time
- Multiple radio channels: Support for multiple configured channels/playlists
- Flexible playback modes: Choose between sequential or shuffle playback for each channel
- Daily playlist generation: Creates 24-hour playlists for each channel with configurable playback order
- Current and next song info: Returns both current and upcoming track details
- YAML configuration: Easy configuration of Plex server and channels
- Direct media links: Provides direct URLs to media files for playback
Returns the current song information from the default channel (channel 0).
Response Example:
{
"status": "success",
"data": {
"title": "Song Title",
"start_time": 45,
"media_link": "http://192.168.0.1:32400/library/parts/12345/file.mp3",
"duration": 180.5,
"artist": "Artist Name",
"album": "Album Name",
"next_song": {
"title": "Next Song Title",
"start_time": 0,
"media_link": "http://192.168.0.1:32400/library/parts/12346/file.mp3",
"duration": 210.3,
"artist": "Next Artist",
"album": "Next Album"
}
},
"timestamp": "2025-08-25T10:30:00.123456"
}
Returns the current song information from a specific channel by number (0-based index).
Parameters:
channel_number
: Integer representing the channel index (0, 1, 2, etc.)
Response Example:
{
"status": "success",
"data": {
"title": "Jazz Song Title",
"start_time": 23,
"media_link": "http://192.168.0.1:32400/library/parts/12347/file.mp3",
"duration": 245.7,
"artist": "Jazz Artist",
"album": "Jazz Album",
"next_song": {
"title": "Next Jazz Song",
"start_time": 0,
"media_link": "http://192.168.0.1:32400/library/parts/12348/file.mp3",
"duration": 198.2,
"artist": "Next Jazz Artist",
"album": "Next Jazz Album"
}
},
"timestamp": "2025-08-25T10:30:00.123456",
"channel": {
"name": "Jazz Radio",
"playlist": "Jazz Radio",
"playback": "shuffle"
}
}
Lists all configured radio channels.
Response Example:
{
"status": "success",
"data": [
{
"name": "Jazz Radio",
"playlist": "Jazz Radio",
"playback": "shuffle"
},
{
"name": "Rock Radio",
"playlist": "Rock Radio",
"playback": "sequential"
}
],
"count": 2
}
Health check endpoint to verify API and Plex server connectivity.
Response Example:
{
"status": "healthy",
"plex_server": "http://192.168.0.1:32400",
"timestamp": "2025-08-25T10:30:00.123456"
}
-
Clone or download the project
-
Create a virtual environment:
python -m venv .venv source .venv/bin/activate # On Linux/Mac # or on Windows .venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
-
Configure your setup:
# Copy the example configuration cp server/configuration/example_plex_radio_config.yaml server/configuration/plex_radio_config.yaml # Edit the configuration file nano server/configuration/plex_radio_config.yaml
Update the configuration with your Plex server details:
plex: host: "http://your-plex-server-ip:32400" token: "your-plex-token" channels: - name: "Jazz Radio" playlist: "Your Jazz Playlist Name" playback: "shuffle" # Optional: "shuffle" (default) or "sequential" - name: "Rock Radio" playlist: "Your Rock Playlist Name" playback: "sequential" # Play songs in playlist order
The API uses a YAML configuration file located at server/configuration/plex_radio_config.yaml
.
To find your Plex authentication token:
- Log into your Plex account at https://app.plex.tv
- Open browser developer tools (F12)
- Go to any Plex page and look for the
X-Plex-Token
in the network requests - Alternatively, use the PlexAPI documentation for token generation
plex:
host: "http://192.168.1.100:32400" # Your Plex server URL
token: "your-plex-token-here" # Your Plex authentication token
channels:
- name: "Jazz Radio" # Display name for the channel
playlist: "Jazz Favorites" # Exact name of your Plex playlist
playback: "shuffle" # Optional: "shuffle" (default) or "sequential"
- name: "Rock Radio"
playlist: "Rock Classics"
playback: "sequential" # Play songs in playlist order
- name: "Pop Radio" # playback field is optional
playlist: "Pop Hits" # Defaults to "shuffle" if playback not specified
- shuffle (default): Songs are shuffled daily, creating a random order each day
- sequential: Songs play in their original playlist order, allowing you to listen through albums or curated sequences
-
Navigate to the server directory and start the API:
cd server python plex_radio_api.py
-
The API will be available at
http://localhost:5000
-
Make sure you have your configuration file set up:
cp server/configuration/example_plex_radio_config.yaml server/configuration/plex_radio_config.yaml # Edit the configuration with your Plex details nano server/configuration/plex_radio_config.yaml
-
Build and run with Docker Compose:
docker-compose up -d
-
Or build and run with Docker directly:
# Build the image docker build -t plex-radio-api . # Run the container docker run -d \ --name plex-radio-api \ -p 5000:5000 \ -v $(pwd)/server/configuration:/app/server/configuration:ro \ plex-radio-api
-
Check the logs:
docker-compose logs -f # For docker-compose docker logs -f plex-radio-api # For direct docker run
-
Stop the service:
docker-compose down # For docker-compose docker stop plex-radio-api && docker rm plex-radio-api # For direct docker run
Once running (either method), test the endpoints:
# Get current song from default channel (channel 0)
curl http://localhost:5000/current-song
# Get current song from specific channel (by number)
curl http://localhost:5000/current-song/1
# List all configured channels
curl http://localhost:5000/channels
# Health check
curl http://localhost:5000/health
The API simulates radio stations by:
- Daily Playlist Generation: At startup, it creates 24-hour playlists for each configured channel, either shuffled or in sequential order based on the
playback
setting - Time-based Calculation: Uses current time of day (seconds since midnight) to determine position in the playlist
- Song Position: Calculates exactly where within a song playback should start
- Seamless Playback: Provides both current song and next song information for gapless transitions
- At 10:30 AM, if the playlist has been playing since midnight
- Calculate total seconds since midnight: 37,800 seconds
- Find which song should be playing at that time offset
- Return the song with exact start position within that track
# Get current song info
response=$(curl -s http://localhost:5000/current-song)
# Extract media link and start time (requires jq)
media_link=$(echo $response | jq -r '.data.media_link')
start_time=$(echo $response | jq -r '.data.start_time')
# Play with ffplay
ffplay -ss $start_time -i "$media_link" -nodisp -autoexit
vlc --start-time=$start_time "$media_link" --intf dummy --play-and-exit
plex-radio/
├── .venv/ # Virtual environment
├── server/ # Main application directory
│ ├── plex_radio_api.py # Main API server
│ ├── config.py # Configuration loader
│ ├── daily_playlist.py # Daily playlist generator
│ └── configuration/ # Configuration files
│ ├── example_plex_radio_config.yaml # Example configuration
│ └── plex_radio_config.yaml # Your actual configuration
├── requirements.txt # Python dependencies
├── Dockerfile # Docker container definition
├── docker-compose.yml # Docker Compose configuration
├── .dockerignore # Docker ignore rules
├── README.md # This file
└── .gitignore # Git ignore rules
The project includes Docker support for easy deployment:
- Multi-stage build for optimized image size
- Non-root user for security
- Health checks for container monitoring
- Production-ready Flask configuration
- Volume mounting for configuration files
- Automatic restart on failure
- Health monitoring with built-in checks
- Volume mapping for easy configuration updates
- Network isolation for security
You can override configuration using environment variables:
FLASK_ENV
: Set toproduction
for production deploymentPYTHONUNBUFFERED
: Ensures Python output is not buffered
The API includes comprehensive error handling for:
- Plex server connectivity issues
- Missing or invalid playlists
- Invalid channel numbers
- YAML configuration errors
- Network timeouts
- Invalid requests
- Flask: Web framework for the REST API
- PlexAPI: Python library for Plex server communication
- PyYAML: YAML configuration file parsing
- Python 3.7+: Required Python version
- Docker (optional): For containerized deployment
- The configuration file
plex_radio_config.yaml
is gitignored for security - Use the
example_plex_radio_config.yaml
as a template - Each channel generates a new playlist daily at startup (shuffled or sequential based on configuration)
- Start times are calculated as seconds into the current song
- The API runs in debug mode by default (disable for production)
- Docker deployment automatically runs in production mode
- Sequential playback preserves original playlist order, perfect for concept albums or DJ mixes
- Shuffle mode provides variety while maintaining the radio experience