AzuraCast / AzuraCast

A self-hosted web radio management suite, including turnkey installer tools for the full radio software stack and a modern, easy-to-use web app to manage your stations.
https://www.azuracast.com/
GNU Affero General Public License v3.0
3.06k stars 568 forks source link

LiquidSoap error : That source is fallible #2858

Closed dbeiner closed 4 years ago

dbeiner commented 4 years ago

Ubuntu 18.04.2 LTS, Docker

At line 208, char 8-43: Error 7: Invalid value: That source is fallible

I already run the update script many times...

Here is my liquidsoap.liq :

set("init.daemon", false)
set("init.daemon.pidfile.path","/var/azuracast/stations/skullfm/config/liquidsoap.pid")
set("log.stdout", true)
set("log.file", false)
set("server.telnet",true)
set("server.telnet.bind_addr","0.0.0.0")
set("server.telnet.port", 8004)
set("harbor.bind_addrs",["0.0.0.0"])

set("tag.encodings",["UTF-8","ISO-8859-1"])
set("encoder.encoder.export",["artist","title","album","song"])

setenv("TZ", "Europe/Zurich")

playlist_eol = playlist(id="playlist_eol",mode="randomize",reload_mode="watch",conservative=true,default_duration=10.,length=20.,"/var/azuracast/stations/skullfm/playlists/playlist_eol.m3u")
playlist_eol = audio_to_stereo(id="stereo_playlist_eol", playlist_eol)
playlist_eol = cue_cut(id="cue_playlist_eol", playlist_eol)

playlist_gold = playlist(id="playlist_gold",mode="randomize",reload_mode="watch",conservative=true,default_duration=10.,length=20.,"/var/azuracast/stations/skullfm/playlists/playlist_gold.m3u")
playlist_gold = audio_to_stereo(id="stereo_playlist_gold", playlist_gold)
playlist_gold = cue_cut(id="cue_playlist_gold", playlist_gold)

playlist_jingle_new = playlist(id="playlist_jingle_new",mode="random",reload_mode="watch",conservative=true,default_duration=10.,length=20.,"/var/azuracast/stations/skullfm/playlists/playlist_jingle_new.m3u")
playlist_jingle_new = audio_to_stereo(id="stereo_playlist_jingle_new", playlist_jingle_new)
playlist_jingle_new = cue_cut(id="cue_playlist_jingle_new", playlist_jingle_new)
playlist_jingle_new = drop_metadata(playlist_jingle_new)

playlist_new = playlist(id="playlist_new",mode="randomize",reload_mode="watch",conservative=true,default_duration=10.,length=20.,"/var/azuracast/stations/skullfm/playlists/playlist_new.m3u")
playlist_new = audio_to_stereo(id="stereo_playlist_new", playlist_new)
playlist_new = cue_cut(id="cue_playlist_new", playlist_new)

playlist_swiss = playlist(id="playlist_swiss",mode="randomize",reload_mode="watch",conservative=true,default_duration=10.,length=20.,"/var/azuracast/stations/skullfm/playlists/playlist_swiss.m3u")
playlist_swiss = audio_to_stereo(id="stereo_playlist_swiss", playlist_swiss)
playlist_swiss = cue_cut(id="cue_playlist_swiss", playlist_swiss)

playlist_jingle_general = playlist(id="playlist_jingle_general",mode="random",reload_mode="watch",conservative=true,default_duration=10.,length=20.,"/var/azuracast/stations/skullfm/playlists/playlist_jingle_general.m3u")
playlist_jingle_general = audio_to_stereo(id="stereo_playlist_jingle_general", playlist_jingle_general)
playlist_jingle_general = cue_cut(id="cue_playlist_jingle_general", playlist_jingle_general)
playlist_jingle_general = drop_metadata(playlist_jingle_general)

playlist_repliques = playlist(id="playlist_repliques",mode="randomize",reload_mode="watch",conservative=true,default_duration=10.,length=20.,"/var/azuracast/stations/skullfm/playlists/playlist_repliques.m3u")
playlist_repliques = audio_to_stereo(id="stereo_playlist_repliques", playlist_repliques)
playlist_repliques = cue_cut(id="cue_playlist_repliques", playlist_repliques)
playlist_repliques = drop_metadata(playlist_repliques)

playlist_current = playlist(id="playlist_current",mode="randomize",reload_mode="watch",conservative=true,default_duration=10.,length=20.,"/var/azuracast/stations/skullfm/playlists/playlist_current.m3u")
playlist_current = audio_to_stereo(id="stereo_playlist_current", playlist_current)
playlist_current = cue_cut(id="cue_playlist_current", playlist_current)

playlist_jingle_swiss = playlist(id="playlist_jingle_swiss",mode="randomize",reload_mode="watch",conservative=true,default_duration=10.,length=20.,"/var/azuracast/stations/skullfm/playlists/playlist_jingle_swiss.m3u")
playlist_jingle_swiss = audio_to_stereo(id="stereo_playlist_jingle_swiss", playlist_jingle_swiss)
playlist_jingle_swiss = cue_cut(id="cue_playlist_jingle_swiss", playlist_jingle_swiss)
playlist_jingle_swiss = drop_metadata(playlist_jingle_swiss)

playlist_default = playlist(id="playlist_default",mode="randomize",reload_mode="watch",conservative=true,default_duration=10.,length=20.,"/var/azuracast/stations/skullfm/playlists/playlist_default.m3u")
playlist_default = audio_to_stereo(id="stereo_playlist_default", playlist_default)
playlist_default = cue_cut(id="cue_playlist_default", playlist_default)

Standard Playlists
radio = random(id="skullfm_standard_playlists", weights=[3], [playlist_default])

requests = request.queue(id="skullfm_requests")
requests = audio_to_stereo(id="skullfm_stereo_requests", requests)
requests = cue_cut(id="skullfm_cue_requests", requests)
radio = fallback(id="skullfm_requests_fallback", track_sensitive = true, [requests, radio])

add_skip_command(radio)

radio = fallback(id="skullfm_safe_fallback", track_sensitive = false, [radio, single(id="error_jingle", "/usr/local/share/icecast/web/error.mp3")])

DJ Authentication
live_enabled = ref false
last_authenticated_dj = ref ""
live_dj = ref ""

def dj_auth(auth_user,auth_pw) =
    user = ref ""
    password = ref ""

    if (auth_user == "source" or auth_user == "") and (string.match(pattern="(:|,)+", auth_pw)) then
        auth_string = string.split(separator="(:|,)", auth_pw)

        user := list.nth(default="", auth_string, 0)
        password := list.nth(default="", auth_string, 2)
    else
        user := auth_user
        password := auth_pw
    end

    log("Authenticating DJ: #{!user}")

    ret = list.hd(get_process_lines("curl -s --request POST --url http://web/api/internal/1/auth --form dj-user="^string.quote(!user)^" --form dj-password="^string.quote(!password)^" --form api_auth="^string.quote("(PASSWORD)")^""), default="")
    log("AzuraCast DJ Auth Response: #{ret}")

    authed = bool_of_string(ret)
    if (authed) then
        last_authenticated_dj := !user
    end

    authed
end

def live_connected(header) =
    dj = !last_authenticated_dj
    log("DJ Source connected! Last authenticated DJ: #{dj} - #{header}")

    live_enabled := true
    live_dj := dj

    ret = list.hd(get_process_lines("curl -s --request POST --url http://web/api/internal/1/djon --form dj-user="^string.quote(dj)^" --form api_auth="^string.quote("(PASSWORD)")^""), default="")
    log("AzuraCast Live Connected Response: #{ret}")
end

def live_disconnected() = 
    dj = !live_dj

    log("DJ Source disconnected! Current live DJ: #{dj}")

    ret = list.hd(get_process_lines("curl -s --request POST --url http://web/api/internal/1/djoff --form dj-user="^string.quote(dj)^" --form api_auth="^string.quote("(PASSWORD)")^""), default="")
    log("AzuraCast Live Disconnected Response: #{ret}")

    live_enabled := false
    last_authenticated_dj := ""
    live_dj := ""
end 

A Pre-DJ source of radio that can be broadcast if needed
radio_without_live = radio
ignore(radio_without_live)

Live Broadcasting
live = audio_to_stereo(input.harbor("/", id = "skullfm_input_streamer", port = 8005, auth = dj_auth, icy = true, icy_metadata_charset = "UTF-8", metadata_charset = "UTF-8", on_connect = live_connected, on_disconnect = live_disconnected, buffer = 15., max = 20.))
ignore(output.dummy(live, fallible=true))

radio = fallback(id="skullfm_live_fallback", replay_metadata=false, track_sensitive=false, [live, radio])

Record Live Broadcasts
stop_recording_f = ref (fun () -> ())

def start_recording(path) =
    output_live_recording = output.file(%mp3(samplerate=44100, stereo=true, bitrate=192, id3v2=true), fallible=true, reopen_on_metadata=false, "#{path}", live)
    stop_recording_f := fun () -> source.shutdown(output_live_recording)
end

def stop_recording() =
    f = !stop_recording_f
    f ()

    stop_recording_f := fun () -> ()
end

server.register(namespace="recording", description="Start recording.", usage="recording.start filename", "start", fun (s) -> begin start_recording(s) "Done!" end)
server.register(namespace="recording", description="Stop recording.", usage="recording.stop", "stop", fun (s) -> begin stop_recording() "Done!" end)

Allow for Telnet-driven insertion of custom metadata.
radio = server.insert_metadata(id="custom_metadata", radio)

Apply amplification metadata (if supplied)
radio = amplify(override="liq_amplify", 1., radio)

Custom Configuration (Specified in Station Profile)
ignore(radio)

DEFINITION DES PLAYLISTS EN MKSAFE
new = mksafe(playlist_new)
jingle_new = mksafe(playlist_jingle_new)
jingle_general = mksafe(playlist_jingle_general)
jingle_swiss = mksafe(playlist_jingle_swiss)
current = mksafe(playlist_current)
repliques = mksafe(playlist_repliques)
swiss = mksafe(playlist_swiss)
gold = mksafe(playlist_gold)
eol = mksafe(playlist_eol)

ROTATION DES PLAYLISTS
radio = rotate(weights=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [jingle_new, new, current, repliques, jingle_general, current, jingle_new, new, jingle_swiss, swiss, current, jingle_general, gold, jingle_new, new, eol, jingle_swiss, swiss, current, repliques, current, jingle_general, current, jingle_swiss, swiss, eol])

SWITCH ENTRE RADIO (PLAYLISTS) ET LIVE 
radio = switch(id="SKULL_FM_live_switch", track_sensitive=false, [({!live_enabled}, live), ({true}, radio)])

Crossfade
radio = crossfade(fade_out=3.,fade_in=0.,radio)

Normalization and Compression for FM audio
radio = compress(radio, attack = 4.0, gain = 7.0, knee = 10.0, ratio = 5.0, release = 600.0, threshold = -18.0, window = 0.7)
radio = normalize(radio, target = -1.0, threshold = -65.0)
radio = limit(radio, threshold = -0.2, attack = 2.0, release = 25.0, window = 0.02)

Send metadata changes back to AzuraCast
def metadata_updated(m) =
    if (m["song_id"] != "") then
        ret = list.hd(get_process_lines("curl -s --request POST --url http://web/api/internal/1/feedback --form song="^string.quote(m["song_id"])^" --form media="^string.quote(m["media_id"])^" --form playlist="^string.quote(m["playlist_id"])^" --form api_auth="^string.quote("(PASSWORD)")^""), default="")
        log("AzuraCast Feedback Response: #{ret}")
    end
end

radio = on_metadata(metadata_updated,radio)

Local Broadcasts
output.icecast(%mp3(samplerate=44100, stereo=true, bitrate=192, id3v2=true), id="skullfm_local_1", host = "127.0.0.1", port = 8000, password = "(PASSWORD)", mount = "/live.mp3", name = "SKULL FM | Pop-Rock-Metal | www.skullfm.ch", description = "1ÈRE WEBRADIO POP-ROCK-METAL NEUCHÂTELOISE !", genre = "Pop, Rock, Metal", url = "https://www.skullfm.ch", public = true, encoding = "UTF-8", radio)
output.icecast(%mp3(samplerate=44100, stereo=true, bitrate=192, id3v2=true), id="skullfm_local_2", host = "127.0.0.1", port = 8000, password = "(PASSWORD)", mount = "/live2.mp3", name = "SKULL FM | Pop-Rock-Metal | www.skullfm.ch", description = "1ÈRE WEBRADIO POP-ROCK-METAL NEUCHÂTELOISE !", genre = "Pop, Rock, Metal", url = "https://www.skullfm.ch", public = false, encoding = "UTF-8", radio)
output.icecast(%mp3(samplerate=44100, stereo=true, bitrate=192, id3v2=true), id="skullfm_local_3", host = "127.0.0.1", port = 8000, password = "(PASSWORD)", mount = "/live3.mp3", name = "SKULL FM | Pop-Rock-Metal | www.skullfm.ch", description = "1ÈRE WEBRADIO POP-ROCK-METAL NEUCHÂTELOISE !", genre = "Pop, Rock, Metal", url = "https://www.skullfm.ch", public = false, encoding = "UTF-8", radio)

Remote Relays

Please help me !!! Thank you !

BusterNeece commented 4 years ago

@dbeiner The error lies in your custom configuration code. You use crossfade without providing a fallback afterwards, which is now considered a "fallible" source as of the latest update to Liquidsoap 1.4.2. See their release notes for more information: https://github.com/savonet/liquidsoap/releases/tag/v1.4.2

dbeiner commented 4 years ago

Hi @SlvrEagle23,

Thank you !

Solved by adding this under the #Crossfade into the custom LiquidSoap configuration :

radio = fallback(id="stationname_safe_fallback", track_sensitive = false, [radio, single(id="error_jingle", "/usr/local/share/icecast/web/error.mp3")])