diff --git a/spradio.liq b/spradio.liq new file mode 100644 index 0000000..a323ecc --- /dev/null +++ b/spradio.liq @@ -0,0 +1,135 @@ +%include "secrets.liq" + +set("log.file", true) +set("log.file.path", "/home/liquidsoap/spradio.log") +set("log.stdout", true) +set("log.level", 4) + +set("server.telnet", false) + +set("scheduler.generic_queues", 5) +set("scheduler.fast_queues", 3) +set("scheduler.non_blocking_queues", 3) + +set("audio.converter.samplerate.libsamplerate.quality", "best") + +security = single(id="default", fallback_audio) + +# Tweaked custom crossfade to deal with jingles.. +def smart_cross(~start_next=5.,~fade_in=3.,~fade_out=3., + ~default=(fun (a,b) -> sequence([a, b])), + ~high=-15., ~medium=-32., ~margin=4., + ~width=2.,~conservative=false,s) + fade.out = fade.out(type="sin", duration=fade_out) + fade.in = fade.in(type="sin", duration=fade_in) + add = fun (a,b) -> add(normalize=false, [b, a]) + log = log(label="smart_cross") + + def transition(a,b,ma,mb,sa,sb) + list.iter(fun(x)-> log(level=4, "Before: #{x}"), ma) + list.iter(fun(x)-> log(level=4, "After : #{x}"), mb) + + if ma["type"] == "J" or mb["type"] == "J" then + log("Old or new file is a jingle: sequenced transition.") + sequence([sa, sb]) + elsif + # Do not fade if it's already very low. + b >= a + margin and a <= medium and b <= high + then + log("new >= old + margin, old <= medium and new <= high.") + log("Do not fade if it's already very low.") + log("Transition: crossed, no fade.") + add(sa, sb) + + # What to do with a loud end and a quiet beginning ? + # A good idea is to use a jingle to separate the two tracks, + # but that's another story. + else + # Otherwise, A and B are just too loud to overlap nicely, + # or the difference between them is too large and overlapping would + # completely mask one of them. + # log("No transition: using default.") + # default(sa, sb) + log("Transition: crossed, fade-in, fade-out.") + add(fade.out(sa), fade.in(sb)) + end + end + + cross(width=width, duration=start_next, + conservative=conservative, transition,s) +end + +def next_song() = + log = log(label="next_song") + + let (status, _, data) = http.get(headers=api_headers_next, url_next) + let (_, status_code, _) = status + + log(data) + + if status_code == 200 then + request.create(data) + else + request.create(fallback_annotate) + end +end + +def change_meta(m) = + log = log(label="change_meta") + + artist = m["artist"] + game = m["game"] + title = m["title"] + + log("Request ID: "^string.quote(m["req_id"])) + log("Artist: #{artist} -- Game: #{game} -- Title: #{title}") + + [("artist","#{artist}"), + ("title","#{title} [#{game}]"), + ("req_id",m["req_id"]), + ("type",m["type"]), + ("game",m["game"]), + ("replay_gain",m["replay_gain"])] +end + +def just_played(m) = + log = log(label="just_played") + + if m["req_id"] != "" then + log("Just played request ID: "^quote(m["req_id"])) + played_song = json_of(compact=true, [("song_request", int_of_string(m["req_id"]))]) + let (status, _, data) = http.post(headers=api_headers_played, data=played_song, url_played) + let (_, status_code, _) = status + + if status_code == 204 then + log('Successfully reported that the song was played.') + else + log('Error while reporting the song was played: #{data}') + end + else + log("No request ID! Stream just started or there are other problems.") + end +end + +radio = request.dynamic(id="main", default_duration=120., length=60., next_song) +radio = fallback(track_sensitive=false, [radio, security]) +radio = map_metadata(update=false, change_meta, radio) +radio = on_metadata(id="main", just_played, radio) +radio = amplify(1., override="replay_gain", radio) +radio = smart_cross(radio) + +output.icecast(%mp3, + encoding="UTF-8", protocol="http", + name=radio_name, description=radio_description, genre=radio_genre, url=radio_url_main, + host=stream_address, port=stream_port, password=stream_password, mount="stream128.mp3", + radio) +output.icecast(%vorbis(samplerate=44100, channels=2, quality=0.4), + encoding="UTF-8", protocol="http", + name=radio_name, description=radio_description, genre=radio_genre, url=radio_url_main, + host=stream_address, port=stream_port, password=stream_password, mount="stream128.ogg", + radio) +output.icecast(%vorbis(samplerate=44100, channels=2, quality=0.0), + encoding="UTF-8", protocol="http", + name=radio_name, description=radio_description, genre=radio_genre, url=radio_url_main, + host=stream_address, port=stream_port, password=stream_password, mount="stream64.ogg", + radio)