Here you go. Use it at your own risk.
#!/usr/bin/perl
# Plays a text-to-speech (TTS) alert on a Squeezebox, temporarily interrupting any music that's playing and then restoring
# An optional pre-chime doodle is played to first get our attention
# THIS VERSION ASSEMBLES/DISASSEMBLES TEMPORARY SYNCGROUPS FOR THE DURATION OF THE ALERT
# Author: philchillbill, 2017-2018
use JSON::RPC::Legacy::Client;
use JSON::XS;
no warnings 'uninitialized';
#use strict; use warnings;
# -----------------------------------------------------------------------------
# We call this perl script from the command line, passing 4 parameters to it:
# 1. 'players' is a string consisting of a "-" separated list of player names (no spaces!) in quotes.
# e.g. "kitchen" or "kitchen, livingroom, bedroom" but NOT "kitchen, living room, bedroom"
# 2. 'prechime' is the filename of the jingle to be played just prior to the spoken alert to grab our attention. e.g. 'Ring06.wav'.
# If no pre-chime is desired, use 'none'. The folder 'C:\Windows\media' has nice examples RingXX.wav.
# 3. 'ttsfile' is the filename of the spoken alert message. e.g. 'garageDoorOpen.mp3'
# 4. 'avol' is the volume the alert is to be played at and should be 0-100. In practice, values of 40-80 are realistic.
# Edit the following parameters to suit your setup:
# The mac addresses for all the squeezebox players that will use alerting
%uuids = (
bathroom => '00:04:20:xx:yy:zz',
kitchen => '00:04:20:xx:yy:zz',
livingroom => '00:04:20:xx:yy:zz'
);
# The full path to the directory where all the TTS mp3/wav files are stored. Please use the name 'alerts' somewhere in it.
%dir = (
alerts => 'file:///media/alerts'
);
# The URL for the LMS server instance, usually on port 9000 or 9002
%url = (
lms => '
http://aa.bb.cc.dd:9000/jsonrpc.js'
);
# -----------------------------------------------------------------------------
sub squeezeAlert {
($sbgroup, $prechime, $afile, $avol)=@_;
@players=@{$sbgroup};
$client=new JSON::RPC::Legacy::Client;
foreach $sb (@players) {
$playerid=$uuids{$sb};
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['serverstatus', 0, 64]] });
if($res->is_success) {
$jres = $res->jsontext;
$jdata=JSON::XS->new->allow_nonref->decode($jres);
$counter = 0;
while (defined($resultaat=$$jdata{result}{'players_loop'}[$counter]{'playerid'} )) {
$connected=$$jdata{result}{'players_loop'}[$counter]{'connected'};
if(($playerid eq $resultaat) & $connected == 1) {
push @players2, $sb;
# print "Player-name: $sb\n";
# print "Player online and connected: $resultaat\n";
}
$counter++;
}
} else { return }
}
#print "@players2\n";
# Get each player's present state so it can be restored later, but not if last-playing was an alert (path is checked)
foreach $sb (@players2) {
$playerid=$uuids{$sb};
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['playlist', 'path', '?'] ] });
if (!$res) { if (scalar(@players2)==1) { return } else { next } }; # player must be disconnected/offline so skip
if ($res->is_success) {
push(@alive, $sb); # add sb to the array of connected players
$jres=$res->jsontext; $jdata=JSON::XS->new->allow_nonref->decode($jres); $path=$$jdata{result}{_path} || 'empty';
$restore{$sb}=($path!~m/alerts|^empty$/) || 0;
if ($restore{$sb}) {
$res = ( $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['status', '-', '1', 'tags' ] ] }) ) || 0;
$jres = $res->jsontext; $jdata=JSON::XS->new->allow_nonref->decode($jres);
$repeat{$sb}=$$jdata{result}{'playlist repeat'};
$power{$sb}=$$jdata{result}{power};
$mode{$sb}=$$jdata{result}{mode}; $noplay{$sb}=($mode{$sb}!~m/play/) || 0;
$mvol{$sb}=$$jdata{result}{'mixer volume'};
$time{$sb}=$$jdata{result}{time};
if ($mode{$sb} eq 'play') { $res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['pause'] ] }); }
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['playlist', 'save', "nowplaying$sb", 'silent:1'] ] });
}}
# now we have the present state of the player, get ready to play the alert:
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['power', '1'] ] });
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['mixer', 'volume', $avol ] ] });
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['playlist', 'repeat', '0'] ] });
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['playlist', 'clear'] ] });
}
# replace the players-list by the list of verified connected players
@players2=@alive;
# build the sync group, if more than one player specified
$master=shift @players2;
foreach $sb (@players2) {
$res = $client->call($url{lms}, { method => 'slim.request', params => [ $uuids{$master}, ['sync', $uuids{$sb} ] ] });
}
# build prechime playlist and play the prechime first
$filetoplay="$dir{alerts}/$prechime";
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $uuids{$master}, ['playlist', 'add', "$filetoplay"] ] });
# now play the prechime-playlist
# $res = $client->call( $url{lms}, { method => 'slim.request', params => [ $uuids{$master}, ['play'] ] });
# build the alert playlist and play the alert second
$filetoplay="$dir{alerts}/$afile";
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $uuids{$master}, ['playlist', 'add', "$filetoplay"] ] });
# now play the alert
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $uuids{$master}, ['play'] ] });
# and wait for it to stop
do {
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $uuids{$master}, ['mode', '?'] ] });
$jres = $res->jsontext;
$jdata=JSON::XS->new->allow_nonref->decode($jres);
$mode=$$jdata{result}{_mode};
# sleep 5;
} until ($mode eq 'stop');
# ok, we are done playing so either restore the music playlist we interrupted, or power off if nothing was playing
foreach $sb ($master, @players2) {
$playerid=$uuids{$sb}; $res = $client->call($url{lms}, { method => 'slim.request', params => [ $playerid, ['sync', '-' ] ] });
if ($restore{$sb}) {
# Restore player to previous state
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['mixer', 'volume', $mvol{$sb} ] ] });
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['playlist', 'repeat', $repeat{$sb} ] ] });
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['playlist', 'resume', "nowplaying$sb", "noplay:$noplay{$sb}" ] ] }); ;
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['time', $time{$sb} ] ] });
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['power', $power{$sb}] ] });
}
else { # no restore, just clear and power-off
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['playlist', 'clear'] ] });
$res = $client->call( $url{lms}, { method => 'slim.request', params => [ $playerid, ['power', '0'] ] });
}
}
return;
}
($players, $prechime, $ttsfile, $avol)=@ARGV;
@players=split(/-\s?/, $players); # Use a - between players
&squeezeAlert( \@players, $prechime, $ttsfile, $avol );