Skip to content
Commits on Source (5)
1.3.4 (10-09-2018)
=====
New:
- Added `FFMPEG` decoder using the new `ocaml-ffmpeg` API. Thanks for @gndl for the hard work there.
- Added `"init.allow_root"` setting to allow running liquidsoap as root.
- Added `on_track` callback for playlists. Can be used to force a reload.
- Added `server.condition`, `server.wait`, `server.broadcast` and `server.signal`. Used to control server command execution.
- Added `server.write`, `server.read{chars,line}` to write interactive server commands in conjunction with the above functions. (#544, #568)
- Added `output.youtube.live` as a wrapper around `output.gstreamer.audio_video` to stream live to Youtube (#498)
- Added metadata extraction to `ffmpeg2wav` protocol (#623).
Changed:
- Depends on OCaml >= 4.03.0
- Depends on camomile > 1.0.0
- Use `http{s}.head` when available to fetch remote file's mime type. (win32 port)
- Better log messages for root exit and buffer override.
- Switch default log to stdout. Set to file when `log.file.path` is set (#612)
- Disabled Gstreamer stream decoder.
- Removed asynchronous mode for `output.gstreamer.audio_video`
- Reworked `smartcross` internal logic (#596)
- Enabled `replaygain` on `m4a` files, thanks to @gilou (#604)
- Added `encoding` parameter to `output.shoutcast` to allow alternative string encoding for metadata updates (#411)
- Deprecated `rewrite_metadata`
Fixed:
- Decouple dyntools compilation.
- Support for OCaml >= 4.06
- File descriptor leak in `output.icecast` (#548)
- Fixed URL regexp for `input.https` (#593)
- Multiple gstreamer fixes:
- File decoder with video.
- Memory leaks (#516, #511, #434, #318)
- Process freeze (#608, 278)
- Duppy crash on exit (#160)
- Fixed audio glitches when using the `pipe` operator (#614)
- Deadlock in external decoder. (#611)
1.3.3 (14-10-2017)
=====
......@@ -29,7 +93,7 @@ Fixed:
- Fixed `mutexify`
- Make sure that metadata are always passed in incresing position order in `map_metadata` (#469)
- Make sure that metadata are always passed in increasing position order in `map_metadata` (#469)
1.3.2 (02-09-2017)
=====
......@@ -56,6 +120,8 @@ Fixed:
- Fix compilation with osx-secure-transport enabled.
- Fix deadlock calling logging functions from within `Gc.finalise` (#609)
1.3.1 (28-05-2017)
=====
......
......@@ -11,42 +11,42 @@ liquidsoap-<version>-full.tar.bz2 tarballs for easier builds.
Libraries not developed by Savonet are:
ocaml-pcre, ocaml-magic, ocaml-sdl
camomile, json-wheel, camlimages, gd4o
camomile, yojson, camlimages, gd4o
Mandatory dependencies :
ocaml-dtools>=0.3.4
OCaml compiler >= 4.03.0
ocaml-dtools>=0.4.0
ocaml-duppy>=0.6.0
ocaml-mm>=0.2.1
ocaml-mm>=0.4.0
ocaml-pcre
base-bytes, for OCaml compilers < 4.02
Recommended dependencies :
camomile for charset recoding in metadata
camomile>=1.0.0 for charset recoding in metadata
ocaml-magic>=0.6 for file type detection
festival for speech synthesis
Optional dependencies :
ocaml-cry>=0.6.0 for sending to Shoutcast & Icecast
ocaml-ogg>=0.4.5 for Ogg codecs
ocaml-vorbis>=0.6.1 for Ogg/Vorbis codec
ocaml-opus>=0.1.0 for Ogg/Opus codec
ocaml-theora>=0.3.0 for Ogg/Theora codec
ocaml-speex>=0.2.0 for Ogg/Speex codec
ocaml-flac>=0.1.1 for Flac and Ogg/Flac codec
ocaml-ogg>=0.5.0 for Ogg codecs
ocaml-vorbis>=0.7.0 for Ogg/Vorbis codec
ocaml-opus>=0.1.1 for Ogg/Opus codec
ocaml-theora>=0.3.1 for Ogg/Theora codec
ocaml-speex>=0.2.1 for Ogg/Speex codec
ocaml-flac>=0.1.2 for Flac and Ogg/Flac codec
ocaml-mad>=0.4.4 for MP3 decoding
ocaml-lame>=0.3.2 for MP3 encoding
ocaml-shine>=0.1.0 for fixed-point MP3 encoding
ocaml-taglib>=0.3.1 for MP3ID3 metadata access
ocaml-faad>=0.3.2 for AAC stream decoding
ocaml-fdkaac>=0.1.0 for AAC(+) encoding
ocaml-shine>=0.2.0 for fixed-point MP3 encoding
ocaml-taglib>=0.3.0 for MP3ID3 metadata access
ocaml-faad>=0.4.0 for AAC stream decoding
ocaml-fdkaac>=0.2.1 for AAC(+) encoding
camlimages>=4.0.0 for image decoding
ocaml-sdl for display, font & image support
ocaml-gavl>=0.1.5 for video conversion using the gavl library
ocaml-ffmpeg>=0.1.0 for video conversion using the ffmpeg library
ocaml-samplerate>=0.1.2 for libsamplerate audio conversion
ocaml-gavl>=0.1.4 for video conversion using the gavl library
ocaml-ffmpeg>=0.2.0 for video conversion using the ffmpeg library
ocaml-samplerate>=0.1.1 for libsamplerate audio conversion
ocaml-lastfm>=0.3.0 for lastfm protocol support
ocaml-xmlplaylist>=0.1.3 for XML-based playlist formats
ocaml-dssi>=0.1.1 for DSSI sound synthesis
......@@ -58,12 +58,12 @@ Optional dependencies :
ocaml-alsa>=0.2.1 for ALSA I/O
ocaml-portaudio>=0.2.0 for Portaudio I/O
ocaml-pulseaudio>=0.1.2 for PulseAudio I/O
ocaml-bjack>=0.1.4 for Jack support
ocaml-gstreamer>=0.2.0 for GStreamer input, output and encoding/decoding
ocaml-bjack>=0.1.3 for Jack support
ocaml-gstreamer>=0.3.0 for GStreamer input, output and encoding/decoding
ocaml-inotify>=1.0 for reloading playlists when changed
ocaml-ssl>=0.5.0 for enabling SSL/https client connections
ocaml-ssl>=0.5.2 for enabling SSL/https client connections
osx-secure-transport for enabling SSL/https client connections via OSX's SecureTransport
json-wheel for parsing JSON data (of_json function)
yojson for parsing JSON data (of_json function)
gd4o for video.add_text() on servers without X
Runtime optional dependencies :
......
......@@ -43,6 +43,8 @@ else
@echo let \(\) = add_subst \"\<sysrundir\>\" \".\" >> src/configure.ml
@echo let \(\) = add_subst \"\<syslogdir\>\" \".\" >> src/configure.ml
endif
@echo let restart = ref false >> src/configure.ml
@echo let \(\) = init_dyntools plugins_dir >> src/configure.ml
@echo let display_types = ref false >> src/configure.ml
@echo let exe_ext = \"$(EXEEXT)\" >> src/configure.ml
@echo "let vendor = \
......
......@@ -34,7 +34,7 @@ EXEEXT = @EXEEXT@
CAMLP4O = @CAMLP4O@
liquidsoap_ocamlcflags= @liquidsoap_ocamlcflags@
liquidsoap_ocamllflags= @liquidsoap_ocamllflags@ -cc "$(CC)" -cclib "$(LDFLAGS)"
liquidsoap_ocamllflags= @liquidsoap_ocamllflags@ -cclib "$(LDFLAGS)"
_DEP_OPTS= @_DEP_OPTS@
# Make the building quiet
......
......@@ -11,10 +11,10 @@ more power than you need for creating or transforming streams. But liquidsoap is
still very light and easy to use, in the Unix tradition of simple strong
components working together.
Copyright 2003-2017 Savonet team
Copyright 2003-2018 Savonet team
* Email : savonet-users@lists.sourceforge.net
* Homepage : http://liquidsoap.fm
* Homepage : http://liquidsoap.info
* Bugreports: https://github.com/savonet/liquidsoap/issues
Installation
......@@ -25,7 +25,7 @@ See the [INSTALL](INSTALL) file.
Documentation
-------------
Some documentation is available on [our website](http://liquidsoap.fm) and HTML
Some documentation is available on [our website](http://liquidsoap.info) and HTML
documentation is included in the distribution: doc/html/index.html.
License
......
#!/bin/sh
#!/bin/sh -e
if [ -d m4 ]; then
OPTIONS="-I m4"
......
This diff is collapsed.
......@@ -7,9 +7,10 @@ dnl $libdir/liquidsoap/$libs_dir_version
# Remove +scm and set scm_snapshot to false before releasing
# Do not use $version below before the next line, since we grep
# for the literal version there
AC_INIT([liquidsoap],[1.3.3])
AC_INIT([liquidsoap],[1.3.4])
scm_snapshot=false
version=1.3.3
version=1.3.4
min_ocaml_version=4.03.0
if test $scm_snapshot != "false"; then
version="$version+scm"
......@@ -146,7 +147,12 @@ fi
AC_CHECK_OCAML_COMPILERS()
# Check for OS
OS_TYPE=`$OCAMLFIND ocamlc -config | grep os_type | tr -d ' ' | cut -d':' -f 2`
OCAMLC_SYSTEM=`$OCAMLFIND ocamlc -config | grep system | cut -d' ' -f 2`
if test "$OCAMLC_SYSTEM" = "mingw" -o "$OCAMLC_SYSTEM" = "mingw64"; then
OS_TYPE="Win32"
else
OS_TYPE="Unix"
fi
AC_SUBST(OS_TYPE)
# Add -fPIC to CFLAGS for compatibility with x86_64
......@@ -177,6 +183,11 @@ fi
liquidsoap_ocamlcflags="$OCAMLFLAGS -ccopt \"\$(CFLAGS)\""
liquidsoap_ocamllflags="-linkpkg -package unix -package threads -package str -package bigarray"
if test "$OS_TYPE" \!= "Win32" ; then
liquidsoap_ocamllflags="$liquidsoap_ocamllflags -cc \"\$(CC)\""
fi
requires="unix threads str"
if test "$enable_debugging" \!= "no" ; then
CFLAGS="$CFLAGS -g"
......@@ -241,6 +252,11 @@ AC_SUBST(OCAML_REVISION)
AC_MSG_CHECKING([for ocamlc version])
AC_MSG_RESULT([$OCAML_MAJOR.$OCAML_MINOR.$OCAML_REVISION])
AC_OCAML_COMPARE_VERSION([$OCAML_MAJOR.$OCAML_MINOR.$OCAML_REVISION],[$min_ocaml_version])
if test -z "${VERSION_OK}"; then
AC_MSG_ERROR([version 4.03.0 or more of the OCaml compiler is required to build liquidsoap])
fi
AC_SUBST(BYTE)
AC_ARG_ENABLE([custom-path],
......@@ -300,7 +316,7 @@ AC_CHECK_OCAML_BINDING([pcre],[],[],[1],[],[1])
# Dtools
#
AC_CHECK_OCAML_BINDING([dtools],[0.3.4],[],[1],[],[1])
AC_CHECK_OCAML_BINDING([dtools],[0.4.0],[],[1],[],[1])
#
# Duppy
......@@ -333,7 +349,7 @@ AC_CHECK_OCAML_BINDING([cry],[0.6.0])
# ocaml-mm
#
AC_CHECK_OCAML_BINDING([mm],[0.3.0],[],[1],[],[1])
AC_CHECK_OCAML_BINDING([mm],[0.4.0],[],[1],[],[1])
#
# xmlplaylist
......@@ -418,10 +434,17 @@ if test -z "${W_DYNLINK}"; then
AC_MSG_WARN([no dynlink module: liquidsoap will not be able to load dynamic plugins!])
cat >> src/configure.ml <<EOCONF
let dynlink = false
let load_plugins_dir = fun _ -> assert false
let init_dyntools = fun _ -> ()
EOCONF
else
cat >> src/configure.ml <<EOCONF
let dynlink = true
let load_plugins_dir = Dyntools.load_plugins_dir
let init_dyntools dir =
at_init (fun () ->
Dyntools.load_dynlinks ();
Dyntools.load_plugins_dir dir)
EOCONF
fi
......@@ -450,7 +473,7 @@ AC_CHECK_OCAML_BINDING([shine],[0.2.0])
# Gstreamer
#
AC_CHECK_OCAML_BINDING([gstreamer],[0.2.0])
AC_CHECK_OCAML_BINDING([gstreamer],[0.3.0])
#
# frei0r
......@@ -489,7 +512,7 @@ AC_CHECK_OCAML_BINDING([gavl],[0.1.4])
# FFMPEG
#
AC_CHECK_OCAML_BINDING([ffmpeg],[0.1.0])
AC_CHECK_OCAML_BINDING([ffmpeg],[0.2.0])
#
# Jack
......@@ -607,7 +630,7 @@ fi
AC_ARG_ENABLE([camomile],
AS_HELP_STRING([--disable-camomile],[don't use camomile (no charset detection and conversion)]))
AC_CHECK_OCAML_BINDING([camomile])
AC_CHECK_OCAML_BINDING([camomile],[1.0.0])
if test -z "$W_CAMOMILE" ; then
if test "x$enable_camomile" = "xno" ; then
......@@ -616,15 +639,7 @@ if test -z "$W_CAMOMILE" ; then
AC_MSG_ERROR([Camomile provides charset detection and conversions. It is strongly advised to enable those features. If you really don't want this, use --disable-camomile.])
fi
else
camdir=`$OCAMLFIND query camomile -l | \
grep location | tr -d ' ' | cut -d':' -f 2`
camencoding=Camomile.CharEncoding
# Use Camomile with environment variables if
# available
if test -f $camdir/camomileLibraryDyn.cmi ; then
if test -z "$w_CUSTOM_PATH"; then
camencoding=CamomileLibraryDyn.$camencoding
else
if test -n "$w_CUSTOM_PATH"; then
camencoding="CamomileLibrary.CharEncoding.Configure(CamomileConfig)"
cat >> src/configure.ml <<EOCONF
module CamomileConfig =
......@@ -635,14 +650,8 @@ struct
let unimapdir = Filename.concat (get_dir "camomile") "mappings"
end
EOCONF
fi
else
if test -n "$w_CUSTOM_PATH"; then
AC_MSG_ERROR([Your camomile module is too old to support loading from a custom path.. Please upgrade it or disable custom path loading.])
fi
if test -f $camdir/camomileLibrary.cmi ; then
camencoding=CamomileLibrary.Default.$camencoding
fi
camencoding=CamomileLibraryDefault.Camomile.CharEncoding
fi
cat >> src/configure.ml <<EOCONF
module C = $camencoding
......@@ -754,7 +763,7 @@ fi
# OCaml bindings
AC_CHECK_OCAML_BINDING([faad],[0.3.0])
AC_CHECK_OCAML_BINDING([faad],[0.4.0])
AC_CHECK_OCAML_BINDING([soundtouch],[0.1.7])
AC_CHECK_OCAML_BINDING([portaudio],[0.2.0])
AC_CHECK_OCAML_BINDING([pulseaudio],[0.1.2])
......@@ -931,6 +940,7 @@ cat <<EOMSG
- Flac (ogg) : $w_FLAC_OGG
- MP3 : $w_MAD
- AAC : $w_FAAD
- Avcodec (ffmpeg) : $w_FFMPEG
- XML playlists : $w_XMLPLAYLIST
- Lastfm : $w_LASTFM
......
liquidsoap (1.3.4-1) unstable; urgency=medium
* Remove /usr/share/liquidsoap on purge (Closes: #668751)
* New upstream version 1.3.4
* Bump camomile version
* Bump Standards-Version (no change)
-- Kyle Robbertze <krobbertze@gmail.com> Sun, 17 Feb 2019 17:35:44 +0200
liquidsoap (1.3.3-2) unstable; urgency=medium
* Fix build errors on armel and mips*
......
......@@ -16,7 +16,7 @@ Build-Depends:
libmad-ocaml-dev (>= 0.4.4),
libdtools-ocaml-dev (>= 0.3.4),
libtaglib-ocaml-dev (>= 0.3.0),
libcamomile-ocaml-dev,
libcamomile-ocaml-dev (>= 1.0.0),
festival,
fonts-liberation,
libxml-dom-perl,
......@@ -55,7 +55,7 @@ Build-Depends:
libgstreamer-ocaml-dev (>= 0.2.0),
libgd-ocaml-dev | libgd-gd2-noxpm-ocaml-dev,
fonts-liberation
Standards-Version: 4.2.1
Standards-Version: 4.3.0
Vcs-Git: https://salsa.debian.org/ocaml-team/liquidsoap.git
Vcs-Browser: https://salsa.debian.org/ocaml-team/liquidsoap
Homepage: http://savonet.sourceforge.net/
......@@ -68,7 +68,7 @@ Depends:
${ocaml:Depends},
${perl:Depends},
ocaml-base-nox,
libcamomile-ocaml-data (>= 0.8),
libcamomile-ocaml-data (>= 1.0.0),
wget,
sox,
adduser
......
......@@ -47,7 +47,7 @@ libraries:
* "ocamlfind":http://www.ocaml-programming.de/programming/findlib.html
* ocaml-dtools (>= 0.3.4)
* ocaml-duppy (>= 0.4.2)
* ocaml-mm (>= 0.2.1)
* ocaml-mm (>= 0.4.0)
* "ocaml-pcre":https://github.com/mmottl/pcre-ocaml
And also optional dependencies. For most of these, you also need
......
......@@ -62,7 +62,7 @@ h4@specific. Specific tutorials
* "Dynamic source creation":dynamic_sources.html: dynamically create sources using server requests.
* "Smart crossfading":smartcrossfade.html: define custom crossfade transitions.
* "Using in production":in_production.html: integrate liquidsoap scripts in a production environment.
* "Liquid Flows":flows.html: add your radio to the "webpage":http://flows.liquidsoap.fm/ of proud users.
* "Liquid Flows":flows.html: add your radio to the "webpage":http://flows.liquidsoap.info/ of proud users.
* "Videos streams":video.html: why restrict yourself to sound only?
h4@users. User scripts
......
......@@ -3,7 +3,7 @@ title: Flows
h3. Flows
We maintain a
"webpage of streams generated by Liquidsoap":http://flows.liquidsoap.fm/.
"webpage of streams generated by Liquidsoap":http://flows.liquidsoap.info/.
In order to register your radio on this page, a simple
operator called @register_flow@ is provided. If your stream is called @stream@,
just wrap it as follows before outputting it:
......@@ -51,7 +51,7 @@ A list of radios, encoded in JSON format, can be obtained by querying the
following url:
%%
http://flows.liquidsoap.fm/radios
http://flows.liquidsoap.info/radios
%%
Output is a JSON string like this:
......@@ -77,7 +77,7 @@ A single radio, encoded in JSON format, can be obtained by querying the
following url:
%%
http://flows.liquidsoap.fm/radio?name=foo&website=bar
http://flows.liquidsoap.info/radio?name=foo&website=bar
%%
All argument are optional and should be in UTF8 and properly encoded for a HTTP
......@@ -85,7 +85,7 @@ GET request.
A direct request using a radio's token can also be performed at this URL:
%%
http://flows.liquidsoap.fm/radio/:token
http://flows.liquidsoap.info/radio/:token
%%
Output is a JSON string like this:
......@@ -114,7 +114,7 @@ If you radio's token is @:token@ and has a stream of format @:format@, then the
following url will redirect any request to your stream's URL.
%%
http://flows.liquidsoap.fm/radio/:token/:format
http://flows.liquidsoap.info/radio/:token/:format
%%
h4. Playlist
......@@ -123,7 +123,7 @@ As for streams, if you radio's token is @:token@ then the following link will
return a "PLS":http://en.wikipedia.org/wiki/PLS_(file_format) playlist:
%%
http://flows.liquidsoap.fm/radio/:token.pls
http://flows.liquidsoap.info/radio/:token.pls
%%
h4. Real-time notifications
......@@ -140,9 +140,9 @@ Then, in your webpage's head, you need to add javascript code adapted from this
example:
%%html
<script src="http://flows.liquidsoap.fm/socket.io/socket.io.js"></script>
<script src="http://flows.liquidsoap.info/socket.io/socket.io.js"></script>
<script type="text/javascript">
var socket = io.connect("http://flows.liquidsoap.fm");
var socket = io.connect("http://flows.liquidsoap.info");
socket.emit('join', radio_token);
......@@ -191,7 +191,7 @@ First you issue a @HTTP@ @GET@ request, authenticated with your radio
credentials at this address:
%%
http://flows.liquidsoap.fm/radio/:token/twitter/auth?redirect_to=:link
http://flows.liquidsoap.info/radio/:token/twitter/auth?redirect_to=:link
%%
Then you should receive a response of the form:
......
......@@ -27,7 +27,7 @@ It guides you through these pages,
starting with the "quickstart tour":quick_start.html.
Liquidsoap is an open-source sofware
from the "Savonet":http://liquidsoap.fm project.
from the "Savonet":http://liquidsoap.info project.
h3. Features
......
......@@ -94,7 +94,7 @@ print(data["uri"]) # "https://..."
# Then key -> (key,value) list
hint = [("list",[("key","value")])]
data = of_json(default=hint,payload)
m = data["metadata"]
m = list.assoc(default=[],"metadata",data)
print(m["title"]) # "foo"
%%
......@@ -56,6 +56,7 @@ You can form expressions by using:
* Shorter definitions using the equality: <code>pi = 3.14</code>. This is never an assignment, only a new local definition!
* Conditionals @if expr then expr else expr end@, or more generally @if expr then expr (elsif expr then expr)* (else expr)? end@. The @else@ block can be omitted if the purpose of the conditional is not to compute a value (_e.g._ an integer or a list of strings) but only to have a side effect (_e.g._ printing something in one case, not doing anything in the other).
* Sequencing: expressions may be sequenced, just juxtapose them. Usually one puts one expression per line. Optionally, they can be separated by a semicolon. The evaluation of a sequence triggers that of all of its sub-expressions, its value is that of the last sub-expression. Accordingly, the type of a sequence is that of its last sub-expression.
* Variable references are defined as: @reference = ref "some string"@. New values can be set via: @reference := "new value"@
* Parenthesis can be used to delimit explicitly expressions. In some places where only expressions can be written, as opposed to sequences of expressions, the @begin .. end@ block can be used to explicitly form a simple expression from a sequence. This notably happens with the simple form of definitions without @def .. end@, and in the body of anonymous functions. For example <code>fun (x) -> f1(x) ; f2(x)</code> will be read as <code>(fun (x) -> f1(x)) ; f2(x)</code> not as <code>fun (x) -> begin f1(x) ; f2(x) end</code>.
* Code blocks: <code>{ expr }</code> is a shortcut for <code>fun () -> expr</code>.
......
......@@ -27,25 +27,6 @@ annotate:title="Title 2",artist="Artist 2":music2.mp3
the title metadata for file music1.mp3 will be overridden and changed to "Title
1" (and similarly for the artist).
h4. Rewrite metadata
<code>rewrite_metadata</code> rewrites metadata using a list of
(target,rules). The semantic for the replacement rules is that of the
<code>%</code> function. Namely, <code>(pattern % [...,(k,v),...])</code>
changes in @pattern@ occurences of:
* <code>'$(k)'</code> into <code>"v"</code>;
* <code>'$(if $(k2),"a","b")'</code> into <code>"a"</code> if <code>k2</code>
is found in the list, <code>"b"</code> otherwise.
A sample code using this operator can be:
%%(rewrite_metadata.liq)
# The 'display_artist' field is passed using annotate.
pattern =
'$(if $(display_artist),"$(display_artist)","$(artist)")'
rewrite_metadata([("artist",pattern)],source)
%%
h4. Map metadata
The <code>map_metadata</code> operator applies a specified function to transform
......@@ -76,47 +57,6 @@ remove any metadata (even empty one) using the @strip@ option.
See the documentation on @map_metadata@ for more details.
A more complex example is the <code>rewrite_metadata</code> operator, which is
implemented using @map_metadata@ as follows:
%%(lang_rewrite.liq)
# Rewrite metadata on the fly using a list of (target,rule).
# @category Source / Track Processing
# @param l List of (target,value) rewriting rules
# @param ~insert_missing \
# Treat track beginnings without metadata \
# as having empty ones.
def rewrite_metadata(l,~insert_missing=true,s)
def map(m)
def apply(x)
label = fst(x)
meta = snd(x)
if list.mem_assoc(label,l) then
pattern = l[label]
(label,pattern % m)
else
(label,meta)
end
end
m = list.map(apply,m)
def add(m,x)
label = fst(x)
pattern = snd(x)
# If m does not have (label,_), then it was
# not processed previously, we have to
# add it now..
if not list.mem_assoc(label,m) then
list.append(m,[(label,pattern % m)])
else
m
end
end
list.fold(add,m,l)
end
map_metadata(map,insert_missing=insert_missing,s)
end
%%
h4. Insert metadata
h5. Using the telnet server
......
......@@ -108,6 +108,151 @@ output.pulseaudio(s)
By default the source s1 is played. To switch to s2, you can connect on
the telnet server and type @var.set button = false@.
h4. Interactive commands
Starting with liquidsoap version @1.3.4@, you can register custom server commands
to interact with the client with applications such as implementing a @pub/sub@ mechanism.
There main commands are:
* @server.write@, @server.read@, @server.readchars@ and @server.readline@ to read and write interactively
* @server.condition@, @server.wait@, @server.signal@ and @server.broadcast@ to control the execution of the command
h5. Read/Write
Writing a partial response is done using the following syntactic sugar:
%%(server_write.liq)
server.write "string to write" then
log("string done writting!")
# Do more stuff then send the final response:
"Done!"
end
%%
Read a value can be done 3 different ways. Most simple one is @server.readline@:
%%(server_readline.liq)
server.readline ret then
log("Read line: #{ret}")
# Do more stuff then send the final response:
"Done!"
end
%%
Then you can read a fixed number of characters:
%%(server_readchars.liq)
server.readchars 15 : ret then
log("Read 15 characters: #{ret}")
# Do more stuff then send the final response:
"Done!"
end
%%
Finally, you can read until reaching a marker, which can be any string or regular expression:
%%(server_read.liq)
server.read "OVER[\r\n]+" : ret then
log("Read until OVER: #{ret}")
# Do more stuff then send the final response:
"Done!"
end
%%
h5. Control flow
You can pause and resume server commands using an API similar to Unix conditions:
* @server.condition()@ creates a condition variable
* @server.wait@ pauses a server command. See below for details
* @server.signal(c)@ resumes one waiting command
* @server.broadcast(c)@ resumes all waiting commands
@server.wait@ is used through a syntactic sugar:
%%(server_wait.liq)
server.wait c then
log("Command has resumed!")
# Do more stuff then send the final response:
"Done!"
end
%%
h5. Full example
In the following, we define two commands:
* @wait@: when executing the command, the client waits for a message. Message can be one of:
** @"exit"@: terminate command
** @"read"@: read one line from the client and print it back
** Otherwise, the client prints the received value
* @send <value>@: when executing this command, the client sends @<value>@ to all waiting clients.
%%(reader_writer.liq)
c = server.condition()
value = ref ""
def wait(_) =
def rec fn () =
server.write ">> " then
server.wait c then
value = !value
if value == "exit" then
"All done!"
elsif value == "read" then
server.write "Write me sumething mister..\n" then
server.readline ret then
server.write "Read: #{ret}\n" then
fn()
end
end
end
else
server.write "Received value: #{value}\n" then
fn()
end
end
end
end
end
fn ()
end
def send(v) =
value := v
server.signal(c)
"Ok!"
end
%%
Example of use:
@send@:
%%
Connected to localhost.
Escape character is '^]'.
send foo
Ok!
END
send read
Ok!
END
send exit
Ok!
END
%%
@wait@:
%%
Connected to localhost.
Escape character is '^]'.
wait
>> Received value: foo
>> Write me sumething mister..
Here's to you mon ami!
Read: Here's to you mon ami!
>> All done!
END
exit
Bye!
%%
h4. Securing the server
The command server provided by liquidsoap is very convenient for manipulating a
......
(*****************************************************************************
Liqi, a simple wiki-like langage
Copyright 2008-2017 Savonet team
Copyright 2008-2018 Savonet team
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......
(*****************************************************************************
Liqi, a simple wiki-like langage
Copyright 2008-2017 Savonet team
Copyright 2008-2018 Savonet team
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......