mirror of
https://github.com/ElvishArtisan/rivendell.git
synced 2025-04-14 08:39:31 +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>
|
||||
* Added a set of enclosing '{}' braces around the JSON-formatted PAD
|
||||
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
|
||||
|
||||
SUBDIRS = rivwebcapi\
|
||||
SUBDIRS = PyPAD\
|
||||
rivwebcapi\
|
||||
rlm
|
||||
|
||||
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 ***])])
|
||||
|
||||
#
|
||||
# Check for Python
|
||||
#
|
||||
AM_PATH_PYTHON([2.7])
|
||||
|
||||
#
|
||||
# Check for FLAC
|
||||
#
|
||||
@ -462,6 +467,9 @@ AC_CONFIG_FILES([rivendell.spec \
|
||||
icons/Makefile \
|
||||
helpers/Makefile \
|
||||
apis/Makefile \
|
||||
apis/PyPAD/Makefile \
|
||||
apis/PyPAD/api/Makefile \
|
||||
apis/PyPAD/examples/Makefile \
|
||||
apis/rivwebcapi/Makefile \
|
||||
apis/rivwebcapi/rivwebcapi.pc \
|
||||
apis/rivwebcapi/rivwebcapi/Makefile \
|
||||
|
@ -991,7 +991,15 @@ int RDTimeZoneOffset()
|
||||
tm=gmtime(&t);
|
||||
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(" \"padUpdate\": {\r\n").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("logMode",RDAirPlayConf::logModeText(play_op_mode),8));
|
||||
|
||||
|
@ -1213,7 +1213,7 @@ QString RDWebDateTime(const QDateTime &datetime)
|
||||
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