mirror of
https://github.com/ElvishArtisan/rivendell.git
synced 2025-04-15 17:12:36 +02:00
2018-12-05 Fred Gleason <fredg@paravelsystems.com>
* Added a set of Python classes for processing PAD updates.
This commit is contained in:
parent
fc0023a0cd
commit
1d8e303101
@ -18100,3 +18100,5 @@
|
|||||||
2018-12-05 Fred Gleason <fredg@paravelsystems.com>
|
2018-12-05 Fred Gleason <fredg@paravelsystems.com>
|
||||||
* Added a set of enclosing '{}' braces around the JSON-formatted PAD
|
* Added a set of enclosing '{}' braces around the JSON-formatted PAD
|
||||||
output to make it well-formed.
|
output to make it well-formed.
|
||||||
|
2018-12-05 Fred Gleason <fredg@paravelsystems.com>
|
||||||
|
* Added a set of Python classes for processing PAD updates.
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
##
|
##
|
||||||
## Use automake to process this into a Makefile.in
|
## Use automake to process this into a Makefile.in
|
||||||
|
|
||||||
SUBDIRS = rivwebcapi\
|
SUBDIRS = PyPAD\
|
||||||
|
rivwebcapi\
|
||||||
rlm
|
rlm
|
||||||
|
|
||||||
CLEANFILES = *~\
|
CLEANFILES = *~\
|
||||||
|
39
apis/PyPAD/Makefile.am
Normal file
39
apis/PyPAD/Makefile.am
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
## automake.am
|
||||||
|
##
|
||||||
|
## Automake.am for Rivendell PyPAD
|
||||||
|
##
|
||||||
|
## (C) Copyright 2018 Fred Gleason <fredg@paravelsystems.com>
|
||||||
|
##
|
||||||
|
## 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 the Free Software Foundation; either version 2 of
|
||||||
|
## the License, or (at your option) any later version.
|
||||||
|
##
|
||||||
|
## This program is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public
|
||||||
|
## License along with this program; if not, write to the Free Software
|
||||||
|
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
##
|
||||||
|
## Use automake to process this into a Makefile.in
|
||||||
|
|
||||||
|
SUBDIRS = api\
|
||||||
|
examples
|
||||||
|
|
||||||
|
CLEANFILES = *~\
|
||||||
|
*.idb\
|
||||||
|
*ilk\
|
||||||
|
*.obj\
|
||||||
|
*.pdb\
|
||||||
|
*.qm\
|
||||||
|
moc_*
|
||||||
|
|
||||||
|
MAINTAINERCLEANFILES = *~\
|
||||||
|
*.tar.gz\
|
||||||
|
aclocal.m4\
|
||||||
|
configure\
|
||||||
|
Makefile.in\
|
||||||
|
moc_*
|
40
apis/PyPAD/api/Makefile.am
Normal file
40
apis/PyPAD/api/Makefile.am
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
## automake.am
|
||||||
|
##
|
||||||
|
## Automake.am for Rivendell PyPAD/api
|
||||||
|
##
|
||||||
|
## (C) Copyright 2018 Fred Gleason <fredg@paravelsystems.com>
|
||||||
|
##
|
||||||
|
## 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 the Free Software Foundation; either version 2 of
|
||||||
|
## the License, or (at your option) any later version.
|
||||||
|
##
|
||||||
|
## This program is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public
|
||||||
|
## License along with this program; if not, write to the Free Software
|
||||||
|
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
##
|
||||||
|
## Use automake to process this into a Makefile.in
|
||||||
|
|
||||||
|
rivendelldir = $(pkgpyexecdir)
|
||||||
|
rivendell_PYTHON = __init__.py\
|
||||||
|
PyPAD.py
|
||||||
|
|
||||||
|
CLEANFILES = *~\
|
||||||
|
*.idb\
|
||||||
|
*ilk\
|
||||||
|
*.obj\
|
||||||
|
*.pdb\
|
||||||
|
*.qm\
|
||||||
|
moc_*
|
||||||
|
|
||||||
|
MAINTAINERCLEANFILES = *~\
|
||||||
|
*.tar.gz\
|
||||||
|
aclocal.m4\
|
||||||
|
configure\
|
||||||
|
Makefile.in\
|
||||||
|
moc_*
|
198
apis/PyPAD/api/PyPAD.py
Normal file
198
apis/PyPAD/api/PyPAD.py
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# PyPAD.py
|
||||||
|
#
|
||||||
|
# PAD processor for Rivendell
|
||||||
|
#
|
||||||
|
# (C) Copyright 2018 Fred Gleason <fredg@paravelsystems.com>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License version 2 as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public
|
||||||
|
# License along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
#
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import json
|
||||||
|
|
||||||
|
class PyPADUpdate(object):
|
||||||
|
def __init__(self,pad_data):
|
||||||
|
self.__fields=pad_data;
|
||||||
|
|
||||||
|
def __replace(self,wildcard,string):
|
||||||
|
stype='now'
|
||||||
|
if wildcard[1].isupper():
|
||||||
|
stype='next'
|
||||||
|
sfields={'a':'artist','b':'label','c':'client','d':'','e':'agency',
|
||||||
|
'f':'','g':'groupName','h':'length','i':'description',
|
||||||
|
'j':'cutNumber','k':'','l':'album','m': 'composer',
|
||||||
|
'n':'cartNumber','o':'outcue','p':'publisher','q': '',
|
||||||
|
'r':'conductor','s':'songId','t':'title','u':'userDefined',
|
||||||
|
'v':'','w':'','x':'','y':'year',
|
||||||
|
'z':''}
|
||||||
|
sfield=sfields[wildcard[1].lower()]
|
||||||
|
|
||||||
|
try:
|
||||||
|
string=string.replace(wildcard,self.__fields['padUpdate'][stype][sfield])
|
||||||
|
except TypeError:
|
||||||
|
string=string.replace(wildcard,'')
|
||||||
|
except KeyError:
|
||||||
|
string=string.replace(wildcard,'')
|
||||||
|
return string
|
||||||
|
|
||||||
|
def dateTime(self):
|
||||||
|
"""
|
||||||
|
Returns the date-time stamp of the update in RFC-822 format (string).
|
||||||
|
"""
|
||||||
|
return self.__fields['padUpdate']['dateTime']
|
||||||
|
|
||||||
|
def logMachine(self):
|
||||||
|
"""
|
||||||
|
Returns the log machine number to which this update pertains
|
||||||
|
(integer).
|
||||||
|
"""
|
||||||
|
return self.__fields['padUpdate']['logMachine']
|
||||||
|
|
||||||
|
def onairFlag(self):
|
||||||
|
"""
|
||||||
|
Returns the state of the on-air flag (boolean).
|
||||||
|
"""
|
||||||
|
return self.__fields['padUpdate']['onairFlag']
|
||||||
|
|
||||||
|
def hasService(self):
|
||||||
|
"""
|
||||||
|
Indicates if service information is included with this update
|
||||||
|
(boolean).
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self.__fields['padUpdate']['service']!=None
|
||||||
|
except TypeError:
|
||||||
|
return False;
|
||||||
|
|
||||||
|
def serviceName(self):
|
||||||
|
"""
|
||||||
|
Returns the name of the service associated with this update (string).
|
||||||
|
"""
|
||||||
|
return self.__fields['padUpdate']['service']['name']
|
||||||
|
|
||||||
|
def serviceDescription(self):
|
||||||
|
"""
|
||||||
|
Returns the description of the service associated with this update
|
||||||
|
(string).
|
||||||
|
"""
|
||||||
|
return self.__fields['padUpdate']['service']['description']
|
||||||
|
|
||||||
|
def serviceProgramCode(self):
|
||||||
|
"""
|
||||||
|
Returns the Program Code of the service associated with this update
|
||||||
|
(string).
|
||||||
|
"""
|
||||||
|
return self.__fields['padUpdate']['service']['programCode']
|
||||||
|
|
||||||
|
def hasLog(self):
|
||||||
|
"""
|
||||||
|
Indicates if log information is included with this update
|
||||||
|
(boolean).
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self.__fields['padUpdate']['log']!=None
|
||||||
|
except TypeError:
|
||||||
|
return False;
|
||||||
|
|
||||||
|
def logName(self):
|
||||||
|
"""
|
||||||
|
Returns the name of the log associated with this update (string).
|
||||||
|
"""
|
||||||
|
return self.__fields['padUpdate']['log']['name']
|
||||||
|
|
||||||
|
def padFields(self,string):
|
||||||
|
"""
|
||||||
|
Takes an argument of a string containing one or more PAD wildcards,
|
||||||
|
which it will resolve into the appropriate values. See the
|
||||||
|
'Metadata Wildcards' section of the Rivendell Operations Guide
|
||||||
|
for a list of recognized wildcards.
|
||||||
|
"""
|
||||||
|
for i in range(65,68):
|
||||||
|
string=self.__replace('%'+chr(i),string)
|
||||||
|
for i in range(69,91):
|
||||||
|
string=self.__replace('%'+chr(i),string)
|
||||||
|
for i in range(97,100):
|
||||||
|
string=self.__replace('%'+chr(i),string)
|
||||||
|
for i in range(101,123):
|
||||||
|
string=self.__replace('%'+chr(i),string)
|
||||||
|
return string
|
||||||
|
|
||||||
|
def hasNowPad(self):
|
||||||
|
"""
|
||||||
|
Indicates if this update include 'Now' playing PAD.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self.__fields['padUpdate']['now']!=None
|
||||||
|
except TypeError:
|
||||||
|
return False;
|
||||||
|
|
||||||
|
def hasNextPad(self):
|
||||||
|
"""
|
||||||
|
Indicates if this update include 'Next' playing PAD.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self.__fields['padUpdate']['next']!=None
|
||||||
|
except TypeError:
|
||||||
|
return False;
|
||||||
|
|
||||||
|
|
||||||
|
class PyPADReceiver(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.__callback=None
|
||||||
|
self.__priv=None
|
||||||
|
|
||||||
|
def __PyPAD_Process(self,pad):
|
||||||
|
self.__callback(pad,self.__priv)
|
||||||
|
|
||||||
|
def setCallback(self,cb):
|
||||||
|
"""
|
||||||
|
Set the processing callback.
|
||||||
|
"""
|
||||||
|
self.__callback=cb
|
||||||
|
|
||||||
|
def setPrivateObject(self,obj):
|
||||||
|
"""
|
||||||
|
Set the 'private' object. This object will be passed to the
|
||||||
|
callback in its second argument.
|
||||||
|
"""
|
||||||
|
self.priv=obj
|
||||||
|
|
||||||
|
def start(self,hostname):
|
||||||
|
"""
|
||||||
|
Connect to a Rivendell system and begin processing PAD events.
|
||||||
|
Once started, a PyPAD object can be interacted with
|
||||||
|
only within one of its callback methods.
|
||||||
|
Takes the following argument:
|
||||||
|
|
||||||
|
hostname: The hostname or IP address of the Rivendell system.
|
||||||
|
"""
|
||||||
|
sock=socket.socket(socket.AF_INET)
|
||||||
|
conn=sock.connect((hostname,34289))
|
||||||
|
c=""
|
||||||
|
line=""
|
||||||
|
msg=""
|
||||||
|
|
||||||
|
while 1<2:
|
||||||
|
c=sock.recv(1)
|
||||||
|
line+=c
|
||||||
|
if c[0]=="\n":
|
||||||
|
msg+=line
|
||||||
|
if line=="\r\n":
|
||||||
|
self.__PyPAD_Process(PyPADUpdate(json.loads(msg)))
|
||||||
|
msg=""
|
||||||
|
line=""
|
||||||
|
|
||||||
|
|
0
apis/PyPAD/api/__init__.py
Normal file
0
apis/PyPAD/api/__init__.py
Normal file
38
apis/PyPAD/examples/Makefile.am
Normal file
38
apis/PyPAD/examples/Makefile.am
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
## automake.am
|
||||||
|
##
|
||||||
|
## Automake.am for Rivendell PyPAD/examples
|
||||||
|
##
|
||||||
|
## (C) Copyright 2018 Fred Gleason <fredg@paravelsystems.com>
|
||||||
|
##
|
||||||
|
## 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 the Free Software Foundation; either version 2 of
|
||||||
|
## the License, or (at your option) any later version.
|
||||||
|
##
|
||||||
|
## This program is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## You should have received a copy of the GNU General Public
|
||||||
|
## License along with this program; if not, write to the Free Software
|
||||||
|
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
##
|
||||||
|
## Use automake to process this into a Makefile.in
|
||||||
|
|
||||||
|
EXTRA_DIST = now_and_next.py
|
||||||
|
|
||||||
|
CLEANFILES = *~\
|
||||||
|
*.idb\
|
||||||
|
*ilk\
|
||||||
|
*.obj\
|
||||||
|
*.pdb\
|
||||||
|
*.qm\
|
||||||
|
moc_*
|
||||||
|
|
||||||
|
MAINTAINERCLEANFILES = *~\
|
||||||
|
*.tar.gz\
|
||||||
|
aclocal.m4\
|
||||||
|
configure\
|
||||||
|
Makefile.in\
|
||||||
|
moc_*
|
18
apis/PyPAD/examples/now_and_next.py
Executable file
18
apis/PyPAD/examples/now_and_next.py
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import rivendell.PyPAD
|
||||||
|
|
||||||
|
def ProcessPad(update,priv):
|
||||||
|
print
|
||||||
|
if update.hasNowPad():
|
||||||
|
print update.padFields("NOW: %a - %t")
|
||||||
|
else:
|
||||||
|
print "NOW: [none]"
|
||||||
|
if update.hasNextPad():
|
||||||
|
print update.padFields("NEXT: %A - %T")
|
||||||
|
else:
|
||||||
|
print "NEXT: [none]"
|
||||||
|
|
||||||
|
rcvr=rivendell.PyPAD.PyPADReceiver()
|
||||||
|
rcvr.setCallback(ProcessPad)
|
||||||
|
rcvr.start("localhost")
|
@ -247,6 +247,11 @@ AC_CHECK_HEADER(security/pam_appl.h,[],[AC_MSG_ERROR([*** PAM not found ***])])
|
|||||||
#
|
#
|
||||||
AC_CHECK_HEADER(soundtouch/SoundTouch.h,[],[AC_MSG_ERROR([*** SoundTouch not found ***])])
|
AC_CHECK_HEADER(soundtouch/SoundTouch.h,[],[AC_MSG_ERROR([*** SoundTouch not found ***])])
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check for Python
|
||||||
|
#
|
||||||
|
AM_PATH_PYTHON([2.7])
|
||||||
|
|
||||||
#
|
#
|
||||||
# Check for FLAC
|
# Check for FLAC
|
||||||
#
|
#
|
||||||
@ -462,6 +467,9 @@ AC_CONFIG_FILES([rivendell.spec \
|
|||||||
icons/Makefile \
|
icons/Makefile \
|
||||||
helpers/Makefile \
|
helpers/Makefile \
|
||||||
apis/Makefile \
|
apis/Makefile \
|
||||||
|
apis/PyPAD/Makefile \
|
||||||
|
apis/PyPAD/api/Makefile \
|
||||||
|
apis/PyPAD/examples/Makefile \
|
||||||
apis/rivwebcapi/Makefile \
|
apis/rivwebcapi/Makefile \
|
||||||
apis/rivwebcapi/rivwebcapi.pc \
|
apis/rivwebcapi/rivwebcapi.pc \
|
||||||
apis/rivwebcapi/rivwebcapi/Makefile \
|
apis/rivwebcapi/rivwebcapi/Makefile \
|
||||||
|
@ -991,7 +991,15 @@ int RDTimeZoneOffset()
|
|||||||
tm=gmtime(&t);
|
tm=gmtime(&t);
|
||||||
time_t gmt_time=3600*tm->tm_hour+60*tm->tm_min+tm->tm_sec;
|
time_t gmt_time=3600*tm->tm_hour+60*tm->tm_min+tm->tm_sec;
|
||||||
|
|
||||||
return gmt_time-local_time;
|
int offset=gmt_time-local_time;
|
||||||
|
if(offset>43200) {
|
||||||
|
offset=offset-86400;
|
||||||
|
}
|
||||||
|
if(offset<-43200) {
|
||||||
|
offset=offset+86400;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2964,7 +2964,7 @@ void RDLogPlay::SendNowNext()
|
|||||||
play_pad_socket->write(QString("{\r\n").toUtf8());
|
play_pad_socket->write(QString("{\r\n").toUtf8());
|
||||||
play_pad_socket->write(QString(" \"padUpdate\": {\r\n").toUtf8());
|
play_pad_socket->write(QString(" \"padUpdate\": {\r\n").toUtf8());
|
||||||
play_pad_socket->write(RDJsonField("dateTime",QDateTime::currentDateTime(),8).toUtf8());
|
play_pad_socket->write(RDJsonField("dateTime",QDateTime::currentDateTime(),8).toUtf8());
|
||||||
play_pad_socket->write(RDJsonField("logMachine",play_id,8));
|
play_pad_socket->write(RDJsonField("logMachine",play_id+1,8));
|
||||||
play_pad_socket->write(RDJsonField("onairFlag",play_onair_flag,8));
|
play_pad_socket->write(RDJsonField("onairFlag",play_onair_flag,8));
|
||||||
play_pad_socket->write(RDJsonField("logMode",RDAirPlayConf::logModeText(play_op_mode),8));
|
play_pad_socket->write(RDJsonField("logMode",RDAirPlayConf::logModeText(play_op_mode),8));
|
||||||
|
|
||||||
|
@ -1213,7 +1213,7 @@ QString RDWebDateTime(const QDateTime &datetime)
|
|||||||
tzstr="GMT";
|
tzstr="GMT";
|
||||||
}
|
}
|
||||||
|
|
||||||
return RDLocalToUtc(datetime).toString("ddd, dd MMM yyyy hh:mm:ss")+" "+tzstr;
|
return datetime.toString("ddd, dd MMM yyyy hh:mm:ss")+" "+tzstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user