Closed Moonbase59 closed 3 years ago
in line s = prepend(s, build_id_source(path=home^"/music/ids/"))
you don't have "immediately ready" source, because s = eat_blank(songs)
before
From reading the description of your needs, it's not clear to me that prepend
is the right operator. Why not a request.dynamic
or a queue of some sort, hooked to some external script of yours dealing with your scheduling logic?
Sorry for not reacting earlier, so much real life came between me and my hobby radio project …
@TrurlMcByte: leaving out s = eat_blank(songs)
didn’t help.
@dbaelde: I seem unable to get this request stuff working. The problem is, that I need the metadata for the upcoming (random) song FIRST so I can cleanup the filename and THEN start looking if an ID file for either the album or the artist even exists.
When using append
instead of prepend
everything works just fine (except of course the ID plays AFTER the song, and it needs to be played BEFORE the song).
Since all this seems to be a timing issue, I wonder if somehow LS could be made to look just a little earlier so it had time enough to prepare the prepended file … I do know that it starts processing other stuff well before the next song starts.
For all those search engines (and myself in 5 years …): Here’s a quite short example that works using opam-installed Liquidsoap 1.3.7 (it takes the next song to play from a script):
# test-04.liq: Use kPlaylist as input and prepend IDs
set("log.file.path", "/home/matthias/Musik/liquidsoap/test-04.log")
set("log.file",true)
set("log.stdout",false)
set("log.level",3)
set("server.telnet",true)
set("init.daemon.pidfile.path", "/home/matthias/Musik/liquidsoap/liquidsoap.pid")
def get_next() =
# Get the first line of my ices/kplaylist script’s output (the URI)
# (the 2nd line contains an optional stream title)
lines = get_process_lines("/home/matthias/Musik/ices/ices.sh")
uri = list.hd(default="", lines)
# create and return request using this URI
request.create(uri)
end
# Clean filename (no path)
# extension can be specified but is optional (specify as ".mp3", for instance)
def clean_filename(fn, ~ext="", ~allowtrailingdot=false) =
# the replacement character
r = "_"
fn = string.replace(pattern="[\\*/:<>?|\"]", (fun (s) -> r), string.replace(pattern="^\s+|\s+$", (fun (s) -> ""), fn))
fn = fn ^ ext
# Trim again because ext might be bad.
fn = string.replace(pattern="^\s+|\s+$", (fun (s) -> ""), fn)
# Windows won't have a "." at end (for folder names)
if allowtrailingdot == false then
string.replace(pattern="\.$", (fun (s) -> r), fn)
else
fn
end
end
# brute-force ID source generation
# Note: prepend() takes empty() and fail() as valid sources
# but will still complain.
# Note: IDs should also have ReplayGain meta data.
def build_id_source(m, ~path="/home/matthias/Musik/Other/IDs/") =
fn = path ^ clean_filename(m["artist"] ^ " - ID.flac")
if m["artist"] != "" and file.exists(fn) then
log(label="artist_id", "Prepending artist ID: #{fn}")
# make stereo to prevent errors if it was a mono recording
audio_to_stereo(single(fn))
else
log(label="artist_id", "No artist ID found")
fail()
end
end
# Add a skip function to a source
# when it does not have one by default
def add_skip_command(~command,s) =
# Register the command:
server.register(
usage="skip",
description="Skip the current song in source.",
command,
fun(_) -> begin source.skip(s) "Done!" end
)
end
# get next track from kPlaylist and
# trim silence (below -40 dB) at beginning and end of tracks
s = eat_blank(request.dynamic(id="s", get_next))
# Add a skip command for use via telnet or the nextsong.sh script
add_skip_command(command="skip", s)
# try to prepend a fitting artist ID, if we have one
s = prepend(s, build_id_source())
s = mksafe(s)
# Apply ReplayGain; this seems to work for MP3, Ogg and FLAC,
# WITHOUT writing anything like APE tags to the files.
s = amplify(1.,override="replaygain_track_gain",s)
s = smart_crossfade(s)
# output 256 kbit/s to the test stream
output.icecast(%mp3(bitrate=256),
host = "<redacted>", port = 8000,
password = "<redacted>", mount = "test.mp3",
s)
Hi, I'm still working on my radio script so many hours a day—Liquidsoap ain't as easy as I thought!
Our station gets introductory IDs from various bands, which shall be played just before one of their songs, often album-specific. So I came up with idea to name those according to an »Artist - Album« scheme in a separate »ids« folder like this:
These ID files cannot be prepared beforehand, because LS runs 24/7 and sometimes the file from a band comes quite late, and just gets uploaded via FTPES into the special »ids« folder. Also, the playlist is generated randomly from whatever is currently uploaded into the filesystem.
So we really need to insert a band ID on-the-fly, depending on whatever the next song to be played has in it's metadata.
Now, for prepend, the docs state something like »the source to be prepended must be immediately ready« and I actually get this error:
Has anyone please got an idea how prepend can be made to work? Or an easy way to circumvent this problem?
The logs show that the »file finding« works ok:
(In this example, the ID file Edguy.mp3 has been found, and we had no ID file(s) for Accept.)
Here is the script code (stripped down to make debugging easier):