#!/usr/bin/liquidsoap # Radio Bullshit - Liquidsoap Configuration # ============================================================================ # CONFIGURATION # ============================================================================ # Get environment variables with defaults hostname = environment.get(default="localhost", "HOSTNAME") port = int_of_string(environment.get(default="8000", "PORT")) folder_songs = "/songs" folder_jingles = "/jingles" folder_air_support = "/air-support" # Log configuration log.file.path := "/var/log/liquidsoap/radio-bullshit.log" log.level := 3 # ============================================================================ # SOURCES # ============================================================================ # Songs playlist - reload every 60 seconds to pick up new downloads songs = playlist( mode="randomize", reload=60, reload_mode="watch", "#{folder_songs}/playlist.pls" ) # Jingles playlist jingles = playlist( mode="randomize", reload=60, reload_mode="watch", "#{folder_jingles}/playlist.pls" ) # Air support (fallback audio when nothing else is available) air_support = mksafe( playlist( mode="randomize", reload_mode="watch", "#{folder_air_support}/playlist.pls" ) ) # ============================================================================ # METADATA UPDATE # ============================================================================ def enrich_metadata(folder, m) entry = process.read("/opt/met_extractor.py #{folder}/playlist.json '#{metadata.filename(m)}'") let json.parse (entry : { index: int?, file: string?, title: string?, duration: float? } ) = entry [("title", "#{entry.title}")] end songs = map_metadata( fun (m) -> begin enrich_metadata(folder_songs, m) end, songs ) jingles = map_metadata( fun (m) -> begin enrich_metadata(folder_jingles, m) end, jingles ) air_support = map_metadata( fun (m) -> begin enrich_metadata(folder_air_support, m) end, air_support ) # ============================================================================ # ALTERNATING LOGIC # ============================================================================ # Alternate between songs and jingles: play 1 jingle, then 4 songs # This creates a pattern: jingle, song, jingle, ... radio = rotate( weights=[1, 1], [jingles, songs] ) # Add fallback to air support in case of errors radio = fallback( track_sensitive=false, [radio, air_support] ) # Normalize audio levels for consistent volume # radio = normalize(radio) # ============================================================================ # OUTPUTS # ============================================================================ # Built-in HTTP server (replaces Icecast) # Serves the stream directly via Liquidsoap's Harbor server output.harbor( %mp3(bitrate=128, samplerate=44100), port=port, mount="/radio-bullshit", url="http://#{hostname}:#{port}", radio ) # Enable built-in HTTP server for stream and status settings.harbor.bind_addrs := ["0.0.0.0"] # Add static folder harbor.http.static( port=port, path="/static/", content_type= fun (path) -> begin file.mime.magic(path) end, "/var/www/static" ) # Add index file harbor.http.register( port=port, method="GET", "/", fun (_, response) -> begin response.html( file.contents("/var/www/index.html") ) end ) # Serve M3U playlist file harbor.http.register( port=port, method="GET", "/radio-bullshit.m3u", fun (_, response) -> begin m3u = "http://#{hostname}:#{port}/radio-bullshit" response.content_type("audio/x-mpegurl") response.data(m3u) end ) # Status endpoint (JSON) harbor.http.register( port=port, method="GET", "/status.json", fun (_, response) -> begin response.json(radio.last_metadata() ?? [("status", "down")]) end ) log("Radio Bullshit is now streaming on http://#{hostname}:#{port}/radio-bullshit")