Skip to content

Commit

Permalink
Merge pull request #244 from kenellorando/interactive-config
Browse files Browse the repository at this point in the history
Interactive configuration script, safe 'example' files
  • Loading branch information
kenellorando authored Mar 11, 2023
2 parents cf28617 + b7f48da commit 2e9260c
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 56 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@

# Go workspace file
go.work

cadence.env
icecast.xml
liquidsoap.liq
nginx.conf
57 changes: 16 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# CadenceRadio

**Cadence** is an all-in-one web radio suite that lets you start a self-hosted radio website.
**Cadence** is an all-in-one suite that lets you start a self-hosted web radio website.

In minutes, you can create an internet audio broadcast complete with library search, song request, album artwork, and a browser UI with real-time stream information working out-of-the-box.

All components are mostly pre-configured so there is hardly any configuration required to get started. Simply provide target directory containing music files, set a few service passwords and hostnames, and deploy!
In minutes, create your internet broadcast with library search, song request, album artwork, and a browser UI with real-time stream information. All components are mostly pre-configured to work out-of-the-box. Simply run an interactive installation script and deploy!

**[See a live demo!](https://cadenceradio.com/)**

## 🖼️ Image Gallery
## 🖼️ Gallery
<details>
<summary>Browser UI Screenshot</summary>

Expand All @@ -23,47 +21,24 @@ All components are mostly pre-configured so there is hardly any configuration re

</details>

## 🏃 Get Started
## 🏃 Start Here

### Requirements
1. You must have [Docker](https://docs.docker.com/engine/install/) installed. If you are on a Linux server, additionally install the [Compose plugin](https://docs.docker.com/compose/install/linux/).
You must have [Docker](https://docs.docker.com/engine/install/) and [Docker Compose](https://docs.docker.com/compose/install/) installed.

### Installation
1. Edit `config/cadence.env`
1. Change all instances of `hackme` to a new password.
2. Set `CSERVER_MUSIC_DIR` to an absolute path which contains music files (`.mp3`, `.flac`) for play. The target is not recursively searched.
3. Set `CSERVER_REQRATELIMIT` to an integer that sets the song request cooldown period in seconds. Set this value to `0` to disable rate limiting.
2. Edit `config/icecast.xml`
1. Change all instances of `hackme` to a new password.
2. Set the `<hostname>` value to a URL you expect your audience to connect to. This value is what is set in the UI's stream source. This may be a DNS name or a public or private IP address. You can leave the default value `localhost` if your radio is meant to be accessible locally only.
3. Edit `config/liquidsoap.liq`
1. Change all instances of `hackme` to a new password.
2. If you changed `CSERVER_MUSIC_DIR` in step 1, change any instances of the default value `/music/` to match it here.
4. Edit `docker-compose.yml`
1. If you changed `CSERVER_MUSIC_DIR` in step 1, change any instances of the `Volumes` defined, replacing `/music:/music` with `/YOURDIR:/music`.
5. (_Optional_) Edit `config/nginx.conf`
1. For advanced users deploying Cadence to a server with DNS, Cadence ships with a reverse proxy that can forward requests based on domain-name to backend services. Simply configure the `server_name` values with your domain names. The stream server domain should match the value you set in step 2.
6. `docker compose up`

After configuration is initially completed, you may simply run `docker compose up` again in the future to start your station.

### Accessing Services

- Assuming you kept the default values above, Cadence will become accessible in a browser at `localhost:8080`.
- If you optionally followed step 4, open firewall port `80` and point DNS to your server.

## 👩‍💻 Developing

### Building the Stack
If you changed code or updated a container image, append the `--build` flag to rebuild exactly what you have.
```bash
chmod +x ./install.sh
./install.sh
```

1. `docker compose down; docker compose up --build`
You will be interactively prompted for a music directory path, a stream hostname, a rate limit timeout, a service password, and optional DNS. After the last prompt, the radio stack will automatically launch and Cadence's web UI will become accessible at `localhost:8080`.

### Enable Development API
Cadence provides an optionally-enabled API with special administrative controls that may be useful for testing. Don't enable development mode on a production server.
After initial installation, simply run `docker compose up` to start your station. Use `install.sh` again at any time to reconfigure inputs.

1. Edit `config/cadence.env`.
1. Set `CSERVER_DEVMODE` to `1` (enabled).
## 📚 Knowledge Base
Cadence's GitHub Wiki provides various resources to help you use, administrate, and develop for your station. If you need any further assistance, we warmly welcome you to [open an issue](https://github.com/kenellorando/cadence/issues).

### API Reference
[Cadence's API Reference](https://github.com/kenellorando/cadence/wiki/API-Reference) provides usage details and complete request/response examples.
- [API Reference](https://github.com/kenellorando/cadence/wiki/API-Reference)
- [Development and Code Style Guide](https://github.com/kenellorando/cadence/wiki/Development-and-Code-Style)
- [Installation Guide](https://github.com/kenellorando/cadence/wiki/Installation)
10 changes: 5 additions & 5 deletions config/cadence.env → config/cadence.env.example
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
CSERVER_MUSIC_DIR=/music/
CSERVER_REQRATELIMIT=180
POSTGRES_PASSWORD=hackme
CSERVER_MUSIC_DIR=CADENCE_PATH_EXAMPLE
CSERVER_REQRATELIMIT=CADENCE_RATE_EXAMPLE
POSTGRES_PASSWORD=CADENCE_PASS_EXAMPLE

# ####################################################
# If you are running Cadence through Docker simply as a user,
# you are unlikely to ever need to change anything below.

# Development
CSERVER_DEVMODE=0
CSERVER_VERSION=5.3.2
CSERVER_LOGLEVEL=4
CSERVER_VERSION=5.4.0-prototype
CSERVER_LOGLEVEL=5
CSERVER_ROOTPATH=/cadence/server/

# Service Addresses
Expand Down
12 changes: 6 additions & 6 deletions config/icecast.xml → config/icecast.xml.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<icecast>
<location>Chicago, United States of America</location>
<admin>Ken Ellorando (kenellorando.com)</admin>
<location>Internet</location>
<admin>Source: Cadence Radio (github.com/kenellorando/cadence)</admin>

<limits>
<clients>100</clients>
Expand All @@ -15,15 +15,15 @@

<authentication>
<!-- Sources log in with username 'source' -->
<source-password>hackme</source-password>
<source-password>CADENCE_PASS_EXAMPLE</source-password>
<!-- Relays log in username 'relay' -->
<relay-password>hackme</relay-password>
<relay-password>CADENCE_PASS_EXAMPLE</relay-password>
<!-- Admin logs in with the username given below -->
<admin-user>admin</admin-user>
<admin-password>hackme</admin-password>
<admin-password>CADENCE_PASS_EXAMPLE</admin-password>
</authentication>

<hostname>localhost:8000</hostname>
<hostname>CADENCE_HOST_EXAMPLE</hostname>

<listen-socket>
<port>8000</port>
Expand Down
4 changes: 2 additions & 2 deletions config/liquidsoap.liq → config/liquidsoap.liq.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ set("server.telnet", true)
set("server.telnet.bind_addr", "0.0.0.0")

# 1. Lowest priority: play all music in the target directory at random.
default = mksafe(playlist(mode="randomize", "/music/"))
default = mksafe(playlist(mode="randomize", "CADENCE_PATH_EXAMPLE"))
# 2. Next priority: play user requests first if there are any in the queue.
radio = fallback([ request.queue(id="request"), default])
# 3. Next priority: play live input stream if one is connected.
full = fallback(track_sensitive=false, [input.http("http://localhost:8000/live.ogg"), radio])

# Output the full stream in OGG
output.icecast(%vorbis.cbr(bitrate=192), host="icecast2",port=8000,password="hackme", mount="cadence1",full)
output.icecast(%vorbis.cbr(bitrate=192), host="icecast2",port=8000,password="CADENCE_PASS_EXAMPLE", mount="cadence1",full)
4 changes: 2 additions & 2 deletions config/nginx.conf → config/nginx.conf.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ http {
# This server forwards requests to the Icecast service.
server {
listen 80;
server_name stream.cadenceradio.com;
server_name CADENCE_STREAM_DNS_EXAMPLE;
access_log off;
location / {
proxy_pass http://icecast2:8000/;
Expand All @@ -16,7 +16,7 @@ http {
# This server forwards requests to the API/UI server.
server {
listen 80;
server_name cadenceradio.com;
server_name CADENCE_WEB_DNS_EXAMPLE;
access_log off;
# Server-sent event API needs special configuration to get through the proxy.
location /api/radiodata/sse {
Expand Down
94 changes: 94 additions & 0 deletions docker-compose.yml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
version: "3"
services:

redis:
image: redis/redis-stack-server:latest
container_name: redis
expose:
- 6379
networks:
internal_services:

postgres:
image: postgres:15-alpine
container_name: postgres
expose:
- 5432
env_file:
- ./config/cadence.env
networks:
internal_services:

icecast2:
build:
dockerfile: ./cadence/icecast2.Dockerfile
image: kenellorando/cadence_icecast2:latest
container_name: icecast2
restart: always
ports:
- 8000:8000
volumes:
- ./config/icecast.xml:/etc/icecast/cadence.xml
networks:
external_services:
stream_delivery:

liquidsoap:
build:
dockerfile: ./cadence/liquidsoap.Dockerfile
image: kenellorando/cadence_liquidsoap:latest
container_name: liquidsoap
restart: always
volumes:
- ./config/liquidsoap.liq:/etc/liquidsoap/cadence.liq
- CADENCE_PATH_EXAMPLE:CADENCE_PATH_EXAMPLE
depends_on:
- icecast2
expose:
- 1234
networks:
internal_services:
stream_delivery:

cadence:
build:
context: ./cadence
dockerfile: ./cadence.Dockerfile
image: kenellorando/cadence
container_name: cadence
restart: always
ports:
- 8080:8080
env_file:
- ./config/cadence.env
volumes:
- CADENCE_PATH_EXAMPLE:CADENCE_PATH_EXAMPLE
depends_on:
- icecast2
- liquidsoap
- redis
- postgres
networks:
internal_services:
external_services:

nginx:
image: nginx:latest
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf
container_name: nginx
restart: on-failure
ports:
- 80:80
depends_on:
- cadence
networks:
external_services:

networks:
external_services:
driver: bridge
internal_services:
driver: bridge
stream_delivery:
driver: bridge
66 changes: 66 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/bin/bash

echo "[1/5] Music Directory Target"
echo "Set the absolute path of a directory containing audio files (e.g. mp3, flac)"
echo "meant for radio play. Only files at the directory base will be seen, not those"
echo "in nested subdirectories."
echo "Example: /music/"
read -p " Music path: " CADENCE_PATH
echo "================================================================================"
echo "[2/5] Stream Host Address"
echo "Set the stream host address for Cadence Icecast. This may be a DNS name, public"
echo "IP, or private IP. Set this to localhost:8000 if your Cadence instance is meant"
echo "for local use only."
echo "Example: localhost:8000"
read -p " Stream address: " CADENCE_HOST
echo "================================================================================"
echo "[3/5] Rate Limiter Timeout"
echo "Set a rate limit timeout in integer seconds. This prevents the same listener"
echo "from requesting songs within the configured timeframe. Set to 0 to disable."
echo "Example: 180"
read -p " Rate limit: " CADENCE_RATE
echo "================================================================================"
echo "[4/5] Radio Service Password"
echo "Set a secure, unique service password. Input is hidden."
read -s -p " Password: " CADENCE_PASS
echo ""
echo "================================================================================"
echo "[5/5] Domain Names - LEAVE BLANK TO SKIP"
echo "OPTIONAL: if you are an advanced administrator routing DNS to your Cadence"
echo "stack, provide your domain names here. You will be prompted for two domains: one"
echo "for Cadence Icecast, one for Cadence web UI. Subdomains are acceptable."
read -p " Cadence Audio Stream Domain: " CADENCE_STREAM_DNS
read -p " Cadence Web UI Domain: " CADENCE_WEB_DNS

if [ -z "$CADENCE_STREAM_DNS" ]
then
CADENCE_STREAM_DNS=stream.cadenceradio.com
fi

if [ -z "$CADENCE_WEB_DNS" ]
then
CADENCE_WEB_DNS=cadenceradio.com
fi

cp ./config/cadence.env.example ./config/cadence.env
cp ./config/icecast.xml.example ./config/icecast.xml
cp ./config/liquidsoap.liq.example ./config/liquidsoap.liq
cp ./config/nginx.conf.example ./config/nginx.conf
cp ./docker-compose.yml.example ./docker-compose.yml

sed -i 's|CADENCE_PASS_EXAMPLE|'"$CADENCE_PASS"'|g' ./config/cadence.env
sed -i 's|CADENCE_PASS_EXAMPLE|'"$CADENCE_PASS"'|g' ./config/icecast.xml
sed -i 's|CADENCE_PASS_EXAMPLE|'"$CADENCE_PASS"'|g' ./config/liquidsoap.liq
sed -i 's|CADENCE_RATE_EXAMPLE|'"$CADENCE_RATE"'|g' ./config/cadence.env
sed -i 's|CADENCE_HOST_EXAMPLE|'"$CADENCE_HOST"'|g' ./config/icecast.xml
sed -i 's|CADENCE_PATH_EXAMPLE|'"$CADENCE_PATH"'|g' ./config/cadence.env
sed -i 's|CADENCE_PATH_EXAMPLE|'"$CADENCE_PATH"'|g' ./config/liquidsoap.liq
sed -i 's|CADENCE_STREAM_DNS_EXAMPLE|'"$CADENCE_STREAM_DNS"'|g' ./config/nginx.conf
sed -i 's|CADENCE_WEB_DNS_EXAMPLE|'"$CADENCE_WEB_DNS"'|g' ./config/nginx.conf
sed -i 's|CADENCE_PATH_EXAMPLE|'"$CADENCE_PATH"'|g' ./docker-compose.yml

echo "========================================="
echo "Configuration completed."
echo "If it does not begin automatically, run 'docker compose up' to start Cadence."
docker compose down
docker compose up

0 comments on commit 2e9260c

Please sign in to comment.