Radio
자체 호스팅 라디오 방송국입니다. Icecast가 MP3를 스트리밍하고, Liquidsoap이 음악을 순환하며, Rust CLI가 이를 관리하고, 가벼운 웹페이지에서 사람들이 들을 수 있게 합니다. 이 페이지는 아이보리(ivory), 차콜(charcoal), 그리고 번트 오렌지(burnt orange) 색상을 사용합니다. 프론트엔드 빌드 단계가 필요 없습니다.
시작하기 (Start)
Docker를 Compose v2(up --wait 지원) 및 Rust와 함께 설치한 후, 이 디렉토리에서 실행합니다:
cargo install --path . --locked
radio init
radio add /path/to/music/
...
**http://localhost:8080**을 엽니다. 직접적인 MP3 스트림은 **http://localhost:8080/radio.mp3**입니다. 라이브러리가 비어 있으면 침묵이 방송됩니다. 방송할 권한이 있는 음악만 스트리밍하십시오.
CLI를 설치하고 싶지 않다면, cargo run -- <command>를 사용하십시오. 이 프로젝트 디렉토리에서 명령을 계속 실행하십시오.
라이브 재생 관리 (Manage live playback)
radio list
radio add '/path/to/Another Track.flac'
radio queue 'Another Track.flac'
...
.liq 스크립트는 노래별로 생성되는 스크립트가 아니라 안정적인 오디오 엔진입니다. Rust는 전체 트랙을 music/에 복사하고, 해당 컨테이너 경로를 music/playlist.m3u에 추가하며, Liquidsoap은 라이브 변경 사항을 감지하기 위해 이 플레이리스트를 모니터링합니다. 큐(Queue)에 추가된 트랙이 셔플된 라이브러리보다 우선권을 가집니다. 건너뛰기 및 다시 로드 기능은 공개 관리 포트 없이 docker compose exec을 통해 Liquidsoap의 커맨드 소켓을 사용합니다. 트랙 변경 시 스트림이 재시작되지 않습니다.
가져오기(Imports)는 MP3, Ogg, FLAC, WAV, M4A, AAC를 지원합니다. 실제 디코딩은 파일의 코덱에 따라 달라집니다. 파일, 디렉토리 또는 셸 확장 와일드카드를 전달하십시오:
radio add /path/to/music/
radio add /path/to/*
지원되지 않는 파일 및 심볼릭 링크 디렉터리는 건너뜁니다. 가져오기(Imports)는 music/ 폴더로 평탄화됩니다: 파일은 이동되는 것이 아니라 복사되며, 이름이 중복된 경우 덮어쓰지 않고 거부됩니다. 중복되거나 I/O 오류가 발생하면 가져오기가 중단되고, 이미 가져온 트랙은 유지됩니다. 한 번에 하나의 CLI 가져오기 도구만 사용하십시오. 디스크 또는 플레이리스트 쓰기에 실패할 경우, 복사된 파일은 삭제되는 대신 수동 복구를 위해 보존됩니다. 순환(rotation)을 편집하려면 music/playlist.m3u 파일을 편집하고 radio reload를 실행하십시오. 이 파일에는 라인별로 /music/filename 경로가 포함되어 있습니다. 고급 오디오 동작을 위해서는 docker/radio.liq도 편집할 수 있으며, 그 후 radio restart를 실행하십시오.
징글 (Jingles)
radio init
radio jingles add /path/to/jingles/
radio jingles list
...
징글은 노래와 마찬가지로 자체 music/jingles/playlist.m3u를 사용하며, 여기에는 재귀적 가져오기 및 중복 방지 기능이 적용됩니다. every 0을 설정하면 징글이 비활성화됩니다(기본값). 간격은 music/jingles/every.txt에 저장되며, 다시 시작할 필요 없이 radio jingles every N으로 실시간 변경할 수 있습니다. 가져온 징글은 실시간으로 감지됩니다. 일반 노래와 대기 중인 노래 모두 카운트하며, 건너뛰거나 중단된 노래는 한 번의 순환(turn)으로 계산됩니다. 재생 중인 징글이 끝나야 대기 중인 노래가 시작됩니다. 누락된 징글은 건너뛰어지며, 준비된 노래가 없으면 스트림은 무음 상태를 유지합니다. 순환 카운터는 다시 시작 시 초기화되며, 간격 변경 사항은 이후 트랙 경계에서 적용됩니다.
스테이션 설정 (Station settings)
radio init을 실행하면 세 개의 독립적인 임의 비밀번호가 포함된 .env 파일이 생성됩니다. 이 파일은 기존 구성이나 음악을 절대 덮어쓰지 않습니다. Unix 환경에서 .env는 소유자 전용(owner-only)이며, Git에 의해 무시되고 Docker 빌드 컨텍스트에서도 제외됩니다. .env와 music/ 폴더를 사적으로 백업하십시오.
변경 사항을 적용하려면 .env 파일을 편집한 후 radio restart를 실행하십시오:
STATION_NAME=My Radio
RADIO_BIND=127.0.0.1
RADIO_PORT=8080
...
생성된 비밀번호 줄은 유지하세요. 비밀번호를 교체할 경우, 최소 24개의 영숫자 문자를 사용해야 합니다. XML 특수 문자는 의도적으로 거부됩니다. 리스너 페이지는 Icecast로부터 방송국 이름, 현재 트랙, 그리고 청취자 수를 가져옵니다. 스트림 및 상태 요청은 동일 출처(same origin)를 사용합니다.
Icecast의 관리자 페이지는 사용자 이름이 admin이고, 비밀번호가 .env 파일의 ICECAST_ADMIN_PASSWORD인 **http://localhost:8000/admin/**입니다. 이 포트는 localhost에만 바인딩됩니다. 웹페이지는 스트림과 공개 상태(public status)만을 프록시하며, 관리자 엔드포인트는 프록시하지 않습니다.
공개 방송국 (Public station)
기본 설정은 웹사이트를 localhost에 바인딩합니다. 다른 장치에서 수신할 수 있도록 하려면, RADIO_BIND=0.0.0.0으로 설정하고 radio restart를 실행하세요. 인터넷 접속을 위해서는 포트 8080 앞에 HTTPS 리버스 프록시(reverse proxy)를 배치하고, DNS 및 방화벽 규칙을 구성하며, Icecast의 관리자 포트와 Docker 소켓은 비공개로 유지해야 합니다. 포함된 스택에는 도메인이나 TLS 인증서가 제공되지 않습니다. Icecast는 기본적으로 100명의 리스너를 지원하며, 더 많은 인원이 필요하면 docker/icecast.sh과 사용 가능한 대역폭을 조정하세요.
모든 서비스는 자동으로 재시작되며 상태 확인(health check) 기능이 있습니다. 오디오 서비스는 읽기 전용 파일 시스템과 임시 쓰기 공간을 가진 비루트 사용자(non-root user)로 실행됩니다. 컨테이너를 중지하거나 다시 생성해도 음악이나 설정은 삭제되지 않습니다.
확인 사항 (Checks)
cargo test
cargo clippy --all-targets -- -D warnings
cargo fmt --check
...
스트림을 위한 curl은 일반적으로 타임아웃 코드 28로 종료됩니다. 라이브 스트림은 끝나지 않기 때문입니다. 오디오 바이트를 수신했는지 확인하세요. 디코더 또는 연결 오류는 radio logs를 사용하세요. web/의 프론트엔드 파일을 직접 편집하면 되며, 재빌드는 필요 없고 브라우저 새로고침만 하면 됩니다.