From 387cbad1b052d4c01bbf3d6161f3a29e06cd8df5 Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Mon, 10 Dec 2018 11:07:07 -0500 Subject: [PATCH 1/8] 2018-12-10 Fred Gleason * Changed the name of the JSON PAD field 'logMachine' to 'machine'. * Changed the name of the 'PyPAD.Update::logMachine()' method to 'PyPAD.Update::machine()'. * Changed the name of the JSON PAD field 'logMode' to 'mode'. * Added a 'PyPAD.Update::mode()' method. * Added a 'cutNumber' field to the JSON PAD 'now' and 'next' objects. * Added a 'PyPAD.FIELD_CUT_NUMBER' define. * Added 'api/PyPAD/examples/pypad_test.py'. --- ChangeLog | 9 ++ apis/PyPAD/api/PyPAD.py | 16 ++- apis/PyPAD/examples/Makefile.am | 1 + apis/PyPAD/examples/now_and_next.py | 8 +- apis/PyPAD/examples/pypad_test.py | 145 ++++++++++++++++++++++++++++ lib/rdlogplay.cpp | 10 +- 6 files changed, 180 insertions(+), 9 deletions(-) create mode 100755 apis/PyPAD/examples/pypad_test.py diff --git a/ChangeLog b/ChangeLog index 94615112..44829f2b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18141,3 +18141,12 @@ 'PyPAD.Update::resolvePadFields()'. * Added a 'PyPAD.Update::padField()' method. * Added a 'PyPAD.Update::escape()' method. +2018-12-10 Fred Gleason + * Changed the name of the JSON PAD field 'logMachine' to 'machine'. + * Changed the name of the 'PyPAD.Update::logMachine()' method to + 'PyPAD.Update::machine()'. + * Changed the name of the JSON PAD field 'logMode' to 'mode'. + * Added a 'PyPAD.Update::mode()' method. + * Added a 'cutNumber' field to the JSON PAD 'now' and 'next' objects. + * Added a 'PyPAD.FIELD_CUT_NUMBER' define. + * Added 'api/PyPAD/examples/pypad_test.py'. diff --git a/apis/PyPAD/api/PyPAD.py b/apis/PyPAD/api/PyPAD.py index 2ca84962..42615e7d 100644 --- a/apis/PyPAD/api/PyPAD.py +++ b/apis/PyPAD/api/PyPAD.py @@ -46,6 +46,7 @@ TYPE_NEXT='next' FIELD_START_DATETIME='startDateTime' FIELD_CART_NUMBER='cartNumber' FIELD_CART_TYPE='cartType' +FIELD_CUT_NUMBER='cutNumber' FIELD_LENGTH='length' FIELD_YEAR='year' FIELD_GROUP_NAME='groupName' @@ -226,7 +227,7 @@ class Update(object): """ Returns the date-time of the PAD update (datetime) """ - return self.__fromIso8601(pad_data['padUpdate']['dateTime']) + return self.__fromIso8601(self.__fields['padUpdate']['dateTime']) def escape(self,string,esc): """ @@ -252,12 +253,19 @@ class Update(object): return self.__escapeJson(string) raise ValueError('invalid esc value') - def logMachine(self): + def machine(self): """ Returns the log machine number to which this update pertains (integer). """ - return self.__fields['padUpdate']['logMachine'] + return self.__fields['padUpdate']['machine'] + + def mode(self): + """ + Returns the operating mode of the host log machine to which + this update pertains (string). + """ + return self.__fields['padUpdate']['mode'] def onairFlag(self): """ @@ -411,6 +419,8 @@ class Update(object): PyPAD.FIELD_CLIENT - The 'Client' field (string) PyPAD.FIELD_COMPOSER - The 'Composer' field (string) PyPAD.FIELD_CONDUCTOR - The 'Conductor' field (string) + PyPAD.FIELD_CUT_NUMER - The 'Cut Number' field + (integer) PyPAD.FIELD_DESCRIPTION - The 'Description' field (string) PyPAD.FIELD_EXTERNAL_ANNC_TYPE - The 'EXT_ANNC_TYPE' diff --git a/apis/PyPAD/examples/Makefile.am b/apis/PyPAD/examples/Makefile.am index f6efe3a3..2d61a9c9 100644 --- a/apis/PyPAD/examples/Makefile.am +++ b/apis/PyPAD/examples/Makefile.am @@ -21,6 +21,7 @@ ## Use automake to process this into a Makefile.in EXTRA_DIST = now_and_next.py\ + pypad_test.py\ pypad_udp.py CLEANFILES = *~\ diff --git a/apis/PyPAD/examples/now_and_next.py b/apis/PyPAD/examples/now_and_next.py index 3859b000..f0a174c1 100755 --- a/apis/PyPAD/examples/now_and_next.py +++ b/apis/PyPAD/examples/now_and_next.py @@ -37,13 +37,13 @@ import PyPAD def ProcessPad(update): print if update.hasPadType(PyPAD.TYPE_NOW): - print "Log %03d NOW: " % update.logMachine()+update.resolvePadFields("%a - %t",PyPAD.ESCAPE_NONE) + print "Log %03d NOW: " % update.machine()+update.resolvePadFields("%a - %t",PyPAD.ESCAPE_NONE) else: - print "Log %03d NOW: [none]" % update.logMachine() + print "Log %03d NOW: [none]" % update.machine() if update.hasPadType(PyPAD.TYPE_NEXT): - print "Log %03d NEXT: " % update.logMachine()+update.resolvePadFields("%A - %T",PyPAD.ESCAPE_NONE) + print "Log %03d NEXT: " % update.machine()+update.resolvePadFields("%A - %T",PyPAD.ESCAPE_NONE) else: - print "Log %03d NEXT: [none]" % update.logMachine() + print "Log %03d NEXT: [none]" % update.machine() # # Create an instance of 'PyPADReceiver' diff --git a/apis/PyPAD/examples/pypad_test.py b/apis/PyPAD/examples/pypad_test.py new file mode 100755 index 00000000..a9444663 --- /dev/null +++ b/apis/PyPAD/examples/pypad_test.py @@ -0,0 +1,145 @@ +#!/usr/bin/python + +# pypad_test.py +# +# PyPAD regression test script for Rivendell +# +# Exercise every method of 'PyPAD.Update' for each update. +# +# (C) Copyright 2018 Fred Gleason +# +# 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 PyPAD + +def ProcessPad(update): + print + print '*** Log %03d Update ***********************************************' % update.machine() + print '** HEADER INFO **' + print ' dateTime(): '+update.dateTime().isoformat(' ') + print ' machine(): %d' % update.machine() + print ' mode(): '+update.mode() + print ' onairFlag(): '+str(update.onairFlag()) + print + if update.hasLog(): + print '** LOG INFO **' + print ' logName(): '+update.logName() + print + else: + print '**NO LOG INFO PRESENT**' + print + + if update.hasService(): + print '** SERVICE INFO **' + print ' serviceName(): '+update.serviceName() + print 'serviceDescription(): '+update.serviceDescription() + print 'serviceProgramCode(): '+update.serviceProgramCode() + print + else: + print '** NO SERVICE INFO PRESENT **' + print + + if update.hasPadType(PyPAD.TYPE_NOW): + print '** NOW PLAYING INFO **' + try: + print ' startDateTime(): '+update.startDateTime(PyPAD.TYPE_NOW).isoformat(' ') + except AttributeError: + print ' startDateTime(): None' + print ' cartType(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CART_TYPE) + print ' cartNumber(): %u / ' % update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CART_NUMBER)+update.resolvePadFields("%n",PyPAD.ESCAPE_NONE) + print ' cutNumber(): %u / ' % update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CUT_NUMBER)+update.resolvePadFields("%j",PyPAD.ESCAPE_NONE) + print ' length(): %u / ' % update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_LENGTH)+update.resolvePadFields("%h",PyPAD.ESCAPE_NONE) + try: + print ' year(): %u / ' % update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_YEAR)+update.resolvePadFields("%y",PyPAD.ESCAPE_NONE) + except TypeError: + print ' year(): None / '+update.resolvePadFields("%Y",PyPAD.ESCAPE_NONE) + print ' groupName(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_GROUP_NAME)+' / '+update.resolvePadFields('%g',PyPAD.ESCAPE_NONE) + print ' title(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_TITLE)+' / '+update.resolvePadFields('%t',PyPAD.ESCAPE_NONE) + print ' artist(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_ARTIST)+' / '+update.resolvePadFields('%a',PyPAD.ESCAPE_NONE) + print ' publisher(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_PUBLISHER)+' / '+update.resolvePadFields('%p',PyPAD.ESCAPE_NONE) + print ' composer(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_COMPOSER)+' / '+update.resolvePadFields('%m',PyPAD.ESCAPE_NONE) + print ' album(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_ALBUM)+' / '+update.resolvePadFields('%l',PyPAD.ESCAPE_NONE) + print ' label(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_LABEL)+' / '+update.resolvePadFields('%b',PyPAD.ESCAPE_NONE) + print ' client(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CLIENT)+' / '+update.resolvePadFields('%c',PyPAD.ESCAPE_NONE) + print ' agency(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_AGENCY)+' / '+update.resolvePadFields('%e',PyPAD.ESCAPE_NONE) + print ' conductor(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CONDUCTOR)+' / '+update.resolvePadFields('%r',PyPAD.ESCAPE_NONE) + print ' userDefined(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_USER_DEFINED)+' / '+update.resolvePadFields('%u',PyPAD.ESCAPE_NONE) + print ' songId(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_SONG_ID)+' / '+update.resolvePadFields('%s',PyPAD.ESCAPE_NONE) + print ' outcue(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_OUTCUE)+' / '+update.resolvePadFields('%o',PyPAD.ESCAPE_NONE) + print ' description(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_DESCRIPTION)+' / '+update.resolvePadFields('%i',PyPAD.ESCAPE_NONE) + print ' externalEventId(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_EXTERNAL_EVENT_ID) + print ' externalData(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_EXTERNAL_DATA) + print ' externalAnncType(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_EXTERNAL_EVENT_ID) + print + + else: + print '** NO NOW PLAYING INFO **' + print + + if update.hasPadType(PyPAD.TYPE_NEXT): + print '** NEXT PLAYING INFO **' + try: + print ' startDateTime(): '+update.startDateTime(PyPAD.TYPE_NEXT).isoformat(' ') + except AttributeError: + print ' startDateTime(): None' + print ' cartType(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CART_TYPE) + print ' cartNumber(): %u / ' % update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CART_NUMBER)+update.resolvePadFields("%N",PyPAD.ESCAPE_NONE) + print ' cutNumber(): %u / ' % update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CUT_NUMBER)+update.resolvePadFields("%J",PyPAD.ESCAPE_NONE) + print ' length(): %u / ' % update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_LENGTH)+update.resolvePadFields("%H",PyPAD.ESCAPE_NONE) + try: + print ' year(): %u / ' % update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_YEAR)+update.resolvePadFields("%Y",PyPAD.ESCAPE_NONE) + except TypeError: + print ' year(): None / '+update.resolvePadFields("%Y",PyPAD.ESCAPE_NONE) + print ' groupName(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_GROUP_NAME)+' / '+update.resolvePadFields('%G',PyPAD.ESCAPE_NONE) + print ' title(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_TITLE)+' / '+update.resolvePadFields('%T',PyPAD.ESCAPE_NONE) + print ' artist(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_ARTIST)+' / '+update.resolvePadFields('%A',PyPAD.ESCAPE_NONE) + print ' publisher(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_PUBLISHER)+' / '+update.resolvePadFields('%P',PyPAD.ESCAPE_NONE) + print ' composer(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_COMPOSER)+' / '+update.resolvePadFields('%M',PyPAD.ESCAPE_NONE) + print ' album(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_ALBUM)+' / '+update.resolvePadFields('%L',PyPAD.ESCAPE_NONE) + print ' label(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_LABEL)+' / '+update.resolvePadFields('%B',PyPAD.ESCAPE_NONE) + print ' client(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CLIENT)+' / '+update.resolvePadFields('%C',PyPAD.ESCAPE_NONE) + print ' agency(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_AGENCY)+' / '+update.resolvePadFields('%E',PyPAD.ESCAPE_NONE) + print ' conductor(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CONDUCTOR)+' / '+update.resolvePadFields('%R',PyPAD.ESCAPE_NONE) + print ' userDefined(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_USER_DEFINED)+' / '+update.resolvePadFields('%U',PyPAD.ESCAPE_NONE) + print ' songId(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_SONG_ID)+' / '+update.resolvePadFields('%S',PyPAD.ESCAPE_NONE) + print ' outcue(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_OUTCUE)+' / '+update.resolvePadFields('%O',PyPAD.ESCAPE_NONE) + print ' description(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_DESCRIPTION)+' / '+update.resolvePadFields('%I',PyPAD.ESCAPE_NONE) + print ' externalEventId(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_EXTERNAL_EVENT_ID) + print ' externalData(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_EXTERNAL_DATA) + print ' externalAnncType(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_EXTERNAL_EVENT_ID) + print + + else: + print '** NO NEXT PLAYING INFO **' + print + + print '******************************************************************' + +# +# Create an instance of 'PyPADReceiver' +# +rcvr=PyPAD.Receiver() + +# +# Tell it to use the callback +# +rcvr.setCallback(ProcessPad) + +# +# Start the receiver, giving it the hostname or IP address and TCP port of +# the target Rivendell system. Once started, all further processing can only +# be done in the callback method! +# +rcvr.start("localhost",PyPAD.PAD_TCP_PORT) diff --git a/lib/rdlogplay.cpp b/lib/rdlogplay.cpp index 16229541..a903a817 100644 --- a/lib/rdlogplay.cpp +++ b/lib/rdlogplay.cpp @@ -2964,9 +2964,9 @@ 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+1,8)); + play_pad_socket->write(RDJsonField("machine",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)); + play_pad_socket->write(RDJsonField("mode",RDAirPlayConf::logModeText(play_op_mode),8)); // // Service @@ -3065,6 +3065,12 @@ QString RDLogPlay::GetPadJson(const QString &name,RDLogLine *ll, } ret+=RDJsonField("cartNumber",ll->cartNumber(),4+padding); ret+=RDJsonField("cartType",RDCart::typeText(ll->cartType()),4+padding); + if(ll->cartType()==RDCart::Audio) { + ret+=RDJsonField("cutNumber",ll->cutNumber(),4+padding); + } + else { + ret+=RDJsonNullField("cutNumber",4+padding); + } ret+=RDJsonField("length",ll->forcedLength(),4+padding); if(ll->year().isValid()) { ret+=RDJsonField("year",ll->year().year(),4+padding); From b693555c877ad01b54357a038a8ae94107978e91 Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Mon, 10 Dec 2018 12:44:10 -0500 Subject: [PATCH 2/8] 2018-12-10 Fred Gleason * Fixed a bug in 'PyPAD.Update::resolvePadFields()' that caused incorrect rendering of 'dddd' placeholders when processing '%d(
)' wildcards. --- ChangeLog | 4 ++++ apis/PyPAD/api/PyPAD.py | 33 ++++++++++++++++++++------------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 44829f2b..566c306f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18150,3 +18150,7 @@ * Added a 'cutNumber' field to the JSON PAD 'now' and 'next' objects. * Added a 'PyPAD.FIELD_CUT_NUMBER' define. * Added 'api/PyPAD/examples/pypad_test.py'. +2018-12-10 Fred Gleason + * Fixed a bug in 'PyPAD.Update::resolvePadFields()' that caused + incorrect rendering of 'dddd' placeholders when processing '%d(
)' + wildcards. diff --git a/apis/PyPAD/api/PyPAD.py b/apis/PyPAD/api/PyPAD.py index 42615e7d..df3c134f 100644 --- a/apis/PyPAD/api/PyPAD.py +++ b/apis/PyPAD/api/PyPAD.py @@ -165,19 +165,9 @@ class Update(object): dt_pattern=pattern[3:-1] try: - dt_pattern=dt_pattern.replace('dddd',dt.strftime('%A')) - dt_pattern=dt_pattern.replace('ddd',dt.strftime('%a')) - dt_pattern=dt_pattern.replace('dd',dt.strftime('%d')) - dt_pattern=dt_pattern.replace('d',str(dt.day)) - - dt_pattern=dt_pattern.replace('MMMM',dt.strftime('%B')) - dt_pattern=dt_pattern.replace('MMM',dt.strftime('%b')) - dt_pattern=dt_pattern.replace('MM',dt.strftime('%m')) - dt_pattern=dt_pattern.replace('M',str(dt.month)) - - dt_pattern=dt_pattern.replace('yyyy',dt.strftime('%Y')) - dt_pattern=dt_pattern.replace('yy',dt.strftime('%y')) - + # + # Process Times + # miltime=(dt_pattern.find('ap')<0)and(dt_pattern.find('AP')<0) if not miltime: if dt.hour<13: @@ -201,6 +191,23 @@ class Update(object): dt_pattern=dt_pattern.replace('ss',dt.strftime('%S')) dt_pattern=dt_pattern.replace('s',str(dt.second)) + + # + # Process Dates + # + dt_pattern=dt_pattern.replace('MMMM',dt.strftime('%B')) + dt_pattern=dt_pattern.replace('MMM',dt.strftime('%b')) + dt_pattern=dt_pattern.replace('MM',dt.strftime('%m')) + dt_pattern=dt_pattern.replace('M',str(dt.month)) + + dt_pattern=dt_pattern.replace('dddd',dt.strftime('%A')) + dt_pattern=dt_pattern.replace('ddd',dt.strftime('%a')) + dt_pattern=dt_pattern.replace('dd',dt.strftime('%d')) + dt_pattern=dt_pattern.replace('d',str(dt.day)) + + dt_pattern=dt_pattern.replace('yyyy',dt.strftime('%Y')) + dt_pattern=dt_pattern.replace('yy',dt.strftime('%y')) + except AttributeError: string=string.replace(pattern,'') return string From 66d0d465c1fbc12262542329da40d6e2fd0cc314 Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Mon, 10 Dec 2018 13:30:49 -0500 Subject: [PATCH 3/8] 2018-12-10 Fred Gleason * Added support for the 'ProcessNullUpdates=' directive in the 'pypad_udp.py' script. * Added support for the log selection directives in the 'pypad_udp.py' script. --- ChangeLog | 5 +++++ apis/PyPAD/examples/pypad_udp.py | 30 +++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 566c306f..2a74270b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18154,3 +18154,8 @@ * Fixed a bug in 'PyPAD.Update::resolvePadFields()' that caused incorrect rendering of 'dddd' placeholders when processing '%d(
)' wildcards. +2018-12-10 Fred Gleason + * Added support for the 'ProcessNullUpdates=' directive in the + 'pypad_udp.py' script. + * Added support for the log selection directives in the + 'pypad_udp.py' script. diff --git a/apis/PyPAD/examples/pypad_udp.py b/apis/PyPAD/examples/pypad_udp.py index e8ae425a..067b67f0 100755 --- a/apis/PyPAD/examples/pypad_udp.py +++ b/apis/PyPAD/examples/pypad_udp.py @@ -30,14 +30,38 @@ import PyPAD def eprint(*args,**kwargs): print(*args,file=sys.stderr,**kwargs) +def processUpdate(update,section): + if config.get(section,'ProcessNullUpdates')=='0': + return True + if config.get(section,'ProcessNullUpdates')=='1': + return update.hasPadType(PyPAD.TYPE_NOW) + if config.get(section,'ProcessNullUpdates')=='2': + return update.hasPadType(PyPAD.TYPE_NEXT) + if config.get(section,'ProcessNullUpdates')=='3': + return update.hasPadType(PyPAD.TYPE_NOW) and update.hasPadType(PyPAD.TYPE_NEXT) + + log_dict={1: 'MasterLog',2: 'Aux1Log',3: 'Aux2Log', + 101: 'VLog101',102: 'VLog102',103: 'VLog103',104: 'VLog104', + 105: 'VLog105',106: 'VLog106',107: 'VLog107',108: 'VLog108', + 109: 'VLog109',110: 'VLog110',111: 'VLog111',112: 'VLog112', + 113: 'VLog113',114: 'VLog114',115: 'VLog115',116: 'VLog116', + 117: 'VLog117',118: 'VLog118',119: 'VLog119',120: 'VLog120'} + if config.get(section,log_dict[update.machine()]).lower()=='yes': + return True + if config.get(section,log_dict[update.machine()]).lower()=='no': + return False + if config.get(section,log_dict[update.machine()]).lower()=='onair': + return update.onairFlag() + def ProcessPad(update): n=1 while(True): section='Udp'+str(n) try: - fmtstr=config.get(section,'FormatString') - send_sock.sendto(update.resolvePadFields(fmtstr,int(config.get(section,'Encoding'))), - (config.get(section,'IpAddress'),int(config.get(section,'UdpPort')))) + if processUpdate(update,section): + fmtstr=config.get(section,'FormatString') + send_sock.sendto(update.resolvePadFields(fmtstr,int(config.get(section,'Encoding'))), + (config.get(section,'IpAddress'),int(config.get(section,'UdpPort')))) n=n+1 except ConfigParser.NoSectionError: return From e2a313a07d9069fe00abfd64cdf664574406f85f Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Mon, 10 Dec 2018 14:09:33 -0500 Subject: [PATCH 4/8] 2018-12-10 Fred Gleason * Fixed a bug in the 'pypad_udp.py' script that threw an exception when processing multi-byte UTF-8 characters. --- ChangeLog | 3 +++ apis/PyPAD/examples/pypad_udp.py | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2a74270b..35669ee8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18159,3 +18159,6 @@ 'pypad_udp.py' script. * Added support for the log selection directives in the 'pypad_udp.py' script. +2018-12-10 Fred Gleason + * Fixed a bug in the 'pypad_udp.py' script that threw an exception + when processing multi-byte UTF-8 characters. diff --git a/apis/PyPAD/examples/pypad_udp.py b/apis/PyPAD/examples/pypad_udp.py index 067b67f0..21bf6df4 100755 --- a/apis/PyPAD/examples/pypad_udp.py +++ b/apis/PyPAD/examples/pypad_udp.py @@ -20,15 +20,15 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # -from __future__ import print_function +#from __future__ import print_function import sys import socket import ConfigParser import PyPAD -def eprint(*args,**kwargs): - print(*args,file=sys.stderr,**kwargs) +#def eprint(*args,**kwargs): +# print(*args,file=sys.stderr,**kwargs) def processUpdate(update,section): if config.get(section,'ProcessNullUpdates')=='0': @@ -60,7 +60,7 @@ def ProcessPad(update): try: if processUpdate(update,section): fmtstr=config.get(section,'FormatString') - send_sock.sendto(update.resolvePadFields(fmtstr,int(config.get(section,'Encoding'))), + send_sock.sendto(update.resolvePadFields(fmtstr,int(config.get(section,'Encoding'))).encode('utf-8'), (config.get(section,'IpAddress'),int(config.get(section,'UdpPort')))) n=n+1 except ConfigParser.NoSectionError: From e6b46cca76523a74885f8bceba0e50c7d4a5f58d Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Tue, 11 Dec 2018 16:50:28 -0500 Subject: [PATCH 5/8] 2018-12-11 Fred Gleason * Renamed 'apis/PyPAD/examples/pypad_test.py' to 'apisPyPAD/tests/pad_test.py'. * Added a 'hostName' field to the JSON PAD 'padUpdate' object. * Added a 'PyPAD.Update::hostName()' method. * Added a 'shortHostName' field to the JSON PAD 'padUpdate' object. * Added a 'PyPAD.Update::shortHostName()' method. * Added a 'PyPAD.Update::resolveFilepath()' method. * Added 'apis/PyPAD/tests/filepath_test.py. * Added 'api/PyPAD/examples/pypad_filewrite.py'. --- ChangeLog | 10 + apis/PyPAD/Makefile.am | 3 +- apis/PyPAD/api/PyPAD.py | 203 ++++++++++++++++++ apis/PyPAD/examples/Makefile.am | 2 +- apis/PyPAD/examples/now_and_next.py | 2 + apis/PyPAD/examples/pypad_filewrite.py | 90 ++++++++ apis/PyPAD/tests/Makefile.am | 39 ++++ apis/PyPAD/tests/filepath_test.py | 78 +++++++ .../pypad_test.py => tests/pad_test.py} | 6 +- configure.ac | 1 + lib/rdlogplay.cpp | 7 +- 11 files changed, 436 insertions(+), 5 deletions(-) create mode 100755 apis/PyPAD/examples/pypad_filewrite.py create mode 100644 apis/PyPAD/tests/Makefile.am create mode 100755 apis/PyPAD/tests/filepath_test.py rename apis/PyPAD/{examples/pypad_test.py => tests/pad_test.py} (97%) diff --git a/ChangeLog b/ChangeLog index 35669ee8..b5645db0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18162,3 +18162,13 @@ 2018-12-10 Fred Gleason * Fixed a bug in the 'pypad_udp.py' script that threw an exception when processing multi-byte UTF-8 characters. +2018-12-11 Fred Gleason + * Renamed 'apis/PyPAD/examples/pypad_test.py' to + 'apisPyPAD/tests/pad_test.py'. + * Added a 'hostName' field to the JSON PAD 'padUpdate' object. + * Added a 'PyPAD.Update::hostName()' method. + * Added a 'shortHostName' field to the JSON PAD 'padUpdate' object. + * Added a 'PyPAD.Update::shortHostName()' method. + * Added a 'PyPAD.Update::resolveFilepath()' method. + * Added 'apis/PyPAD/tests/filepath_test.py. + * Added 'api/PyPAD/examples/pypad_filewrite.py'. diff --git a/apis/PyPAD/Makefile.am b/apis/PyPAD/Makefile.am index a2c95b53..4e5f15c1 100644 --- a/apis/PyPAD/Makefile.am +++ b/apis/PyPAD/Makefile.am @@ -21,7 +21,8 @@ ## Use automake to process this into a Makefile.in SUBDIRS = api\ - examples + examples\ + tests CLEANFILES = *~\ *.idb\ diff --git a/apis/PyPAD/api/PyPAD.py b/apis/PyPAD/api/PyPAD.py index df3c134f..00e8c175 100644 --- a/apis/PyPAD/api/PyPAD.py +++ b/apis/PyPAD/api/PyPAD.py @@ -260,6 +260,20 @@ class Update(object): return self.__escapeJson(string) raise ValueError('invalid esc value') + def hostName(self): + """ + Returns the host name of the machine whence this PAD update + originated (string). + """ + return self.__fields['padUpdate']['hostName'] + + def shortHostName(self): + """ + Returns the short host name of the machine whence this PAD update + originated (string). + """ + return self.__fields['padUpdate']['shortHostName'] + def machine(self): """ Returns the log machine number to which this update pertains @@ -454,8 +468,197 @@ class Update(object): """ return self.__fields['padUpdate'][pad_type][pad_field] + def resolveFilepath(self,string,dt): + """ + Returns a string with any Rivendell Filepath wildcards resolved + (See Appdendix C of the Rivendell Operations Guide for a list). + Takes two arguments: + + string - The string to resolve. + dt - A Python 'datetime' object to use for the resolution. + """ + ret='' + upper_case=False + initial_case=False + offset=0 + i=0 + while i12: + hour=hour-12 + if hour==0: + hour=12 + field='%2d' % hour + found=True + + if string[i]=='J': # Hour, unpadded, 12 hour + hour=dt.hour + if hour>12: + hour=hour-12 + if hour==0: + hour=12 + field=str(hour) + found=True + + if string[i]=='j': # Day of year + field=dt.strftime('%j') + found=True + + if string[i]=='k': # Hour, space padded, 24 hour + field=dt.strftime('%k') + found=True + + if string[i]=='M': # Minute, zero padded + field=dt.strftime('%M') + found=True + + if string[i]=='m': # Month (01 - 12) + field=dt.strftime('%m') + found=True + + if string[i]=='p': # AM/PM string + field=dt.strftime('%p') + found=True + + if string[i]=='r': # Rivendell host name + field=self.hostName() + found=True + + if string[i]=='R': # Rivendell short host name + field=self.shortHostName() + found=True + + if string[i]=='S': # Second (SS) + field=dt.strftime('%S') + found=True + + if string[i]=='s': # Rivendell service name + if self.hasService(): + field=self.serviceName() + else: + field='' + found=True + + if string[i]=='u': # Day of week (numeric, 1..7, 1=Monday) + field=dt.strftime('%u') + found=True + + if (string[i]=='V') or (string[i]=='W'): # Week # (as per ISO 8601) + field=dt.strftime('%V') + found=True + + if string[i]=='w': # Day of week (numeric, 0..6, 0=Sunday) + field=dt.strftime('%w') + found=True + + if string[i]=='y': # Year (yy) + field=dt.strftime('%y') + found=True + + if string[i]=='Y': # Year (yyyy) + field=dt.strftime('%Y') + found=True + + if string[i]=='%': + field='%' + found=True + + if not found: # No recognized wildcard, rollback! + i=-offset + field=string[i] + + if upper_case: + field=field.upper(); + if initial_case: + field=field[0].upper()+field[1::] + ret+=field + upper_case=False + initial_case=False + i=i+1 + + return ret + class Receiver(object): def __init__(self): diff --git a/apis/PyPAD/examples/Makefile.am b/apis/PyPAD/examples/Makefile.am index 2d61a9c9..b4275c20 100644 --- a/apis/PyPAD/examples/Makefile.am +++ b/apis/PyPAD/examples/Makefile.am @@ -21,7 +21,7 @@ ## Use automake to process this into a Makefile.in EXTRA_DIST = now_and_next.py\ - pypad_test.py\ + pypad_filewrite.py\ pypad_udp.py CLEANFILES = *~\ diff --git a/apis/PyPAD/examples/now_and_next.py b/apis/PyPAD/examples/now_and_next.py index f0a174c1..8b1df372 100755 --- a/apis/PyPAD/examples/now_and_next.py +++ b/apis/PyPAD/examples/now_and_next.py @@ -36,6 +36,8 @@ import PyPAD # def ProcessPad(update): print + print 'Filepath: '+update.resolveFilepath('string %$a',update.dateTime()) + if update.hasPadType(PyPAD.TYPE_NOW): print "Log %03d NOW: " % update.machine()+update.resolvePadFields("%a - %t",PyPAD.ESCAPE_NONE) else: diff --git a/apis/PyPAD/examples/pypad_filewrite.py b/apis/PyPAD/examples/pypad_filewrite.py new file mode 100755 index 00000000..6673b9c2 --- /dev/null +++ b/apis/PyPAD/examples/pypad_filewrite.py @@ -0,0 +1,90 @@ +#!/usr/bin/python + +# pypad_filewrite.py +# +# Write PAD updates to files +# +# (C) Copyright 2018 Fred Gleason +# +# 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. +# + +#from __future__ import print_function + +import sys +import ConfigParser +import PyPAD + +#def eprint(*args,**kwargs): +# print(*args,file=sys.stderr,**kwargs) + +def processUpdate(update,section): + try: + if config.get(section,'ProcessNullUpdates')=='0': + return True + if config.get(section,'ProcessNullUpdates')=='1': + return update.hasPadType(PyPAD.TYPE_NOW) + if config.get(section,'ProcessNullUpdates')=='2': + return update.hasPadType(PyPAD.TYPE_NEXT) + if config.get(section,'ProcessNullUpdates')=='3': + return update.hasPadType(PyPAD.TYPE_NOW) and update.hasPadType(PyPAD.TYPE_NEXT) + except ConfigParser.NoOptionError: + return True + + log_dict={1: 'MasterLog',2: 'Aux1Log',3: 'Aux2Log', + 101: 'VLog101',102: 'VLog102',103: 'VLog103',104: 'VLog104', + 105: 'VLog105',106: 'VLog106',107: 'VLog107',108: 'VLog108', + 109: 'VLog109',110: 'VLog110',111: 'VLog111',112: 'VLog112', + 113: 'VLog113',114: 'VLog114',115: 'VLog115',116: 'VLog116', + 117: 'VLog117',118: 'VLog118',119: 'VLog119',120: 'VLog120'} + if config.get(section,log_dict[update.machine()]).lower()=='yes': + return True + if config.get(section,log_dict[update.machine()]).lower()=='no': + return False + if config.get(section,log_dict[update.machine()]).lower()=='onair': + return update.onairFlag() + +def ProcessPad(update): + n=1 + try: + while(True): + section='File'+str(n) + if processUpdate(update,section): + fmtstr=config.get(section,'FormatString') + mode='w' + if config.get(section,'Append')=='1': + mode='a' + f=open(update.resolveFilepath(config.get(section,'Filename'),update.dateTime()),mode) + f.write(update.resolvePadFields(fmtstr,int(config.get(section,'Encoding'))).encode('utf-8')) + f.close() + n=n+1 + + except ConfigParser.NoSectionError: + return + +# +# Read Configuration +# +if len(sys.argv)>=2: + fp=open(sys.argv[1]) + config=ConfigParser.ConfigParser() + config.readfp(fp) + fp.close() +else: + eprint('pypad_filewrite.py: you must specify a configuration file') + sys.exit(1) + +rcvr=PyPAD.Receiver() +rcvr.setCallback(ProcessPad) +rcvr.start("localhost",PyPAD.PAD_TCP_PORT) diff --git a/apis/PyPAD/tests/Makefile.am b/apis/PyPAD/tests/Makefile.am new file mode 100644 index 00000000..cf90181d --- /dev/null +++ b/apis/PyPAD/tests/Makefile.am @@ -0,0 +1,39 @@ +## automake.am +## +## Automake.am for Rivendell PyPAD/tests +## +## (C) Copyright 2018 Fred Gleason +## +## 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 = filepath_test.py + pad_test.py + +CLEANFILES = *~\ + *.idb\ + *ilk\ + *.obj\ + *.pdb\ + *.qm\ + moc_* + +MAINTAINERCLEANFILES = *~\ + *.tar.gz\ + aclocal.m4\ + configure\ + Makefile.in\ + moc_* diff --git a/apis/PyPAD/tests/filepath_test.py b/apis/PyPAD/tests/filepath_test.py new file mode 100755 index 00000000..d7c7c955 --- /dev/null +++ b/apis/PyPAD/tests/filepath_test.py @@ -0,0 +1,78 @@ +#!/usr/bin/python + +# filepath_test.py +# +# PyPAD regression test script for Rivendell +# +# Exercise every filepath wildcard in 'PyPAD.Update::resolveFilepath()' +# +# (C) Copyright 2018 Fred Gleason +# +# 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 PyPAD + +def ProcessPad(update): + print + print 'DateTime: '+update.dateTime().isoformat(' ') + print + print 'Abbreviated weekday name [%a | %$a | %^a]: '+update.resolveFilepath('%a | %$a | %^a',update.dateTime()) + print 'Full weekday name [%A | %$A | %^A]: '+update.resolveFilepath('%A | %$A | %^A',update.dateTime()) + print 'Abbreviated month name [%b | %$b | %^b]: '+update.resolveFilepath('%b | %$b | %^b',update.dateTime()) + print 'Full month name [%B | %$B | %^B]: '+update.resolveFilepath('%B | %$B | %^B',update.dateTime()) + print 'Century [%C | %$C | %^C]: '+update.resolveFilepath('%C | %$C | %^C',update.dateTime()) + print 'Day of the month, zero padded [01 - 31] [%d | %$d | %^d]: '+update.resolveFilepath('%d | %$d | %^d',update.dateTime()) + print 'Date (mm-dd-yy) [%D | %$D | %^D]: '+update.resolveFilepath('%D | %$D | %^D',update.dateTime()) + print 'Day of the month, space padded [ 1 - 31] [%e | %$e | %^e]: '+update.resolveFilepath('%e | %$e | %^e',update.dateTime()) + print 'Day of the month, unpadded [ 1 - 31] [%E | %$E | %^E]: '+update.resolveFilepath('%E | %$E | %^E',update.dateTime()) + print 'Date (yyyy-mm-dd) [%F | %$F | %^F]: '+update.resolveFilepath('%F | %$F | %^F',update.dateTime()) + print 'Two digit year [%g | %$g | %^g]: '+update.resolveFilepath('%g | %$g | %^g',update.dateTime()) + print 'Four digit year [%G | %$G | %^G]: '+update.resolveFilepath('%G | %$G | %^G',update.dateTime()) + print 'Abbreviated month name [%h | %$h | %^h]: '+update.resolveFilepath('%h | %$h | %^h',update.dateTime()) + print 'Hour, 24 hour, zero padded [00 - 23] [%H | %$H | %^H]: '+update.resolveFilepath('%H | %$H | %^H',update.dateTime()) + print 'Hour, 12 hour, space padded [00 - 23] [%i | %$i | %^i]: '+update.resolveFilepath('%i | %$i | %^i',update.dateTime()) + print 'Hour, 12 hour, zero padded [00 - 23] [%I | %$I | %^I]: '+update.resolveFilepath('%I | %$I | %^I',update.dateTime()) + print 'Day of year, zero padded [%j | %$j | %^j]: '+update.resolveFilepath('%j | %$j | %^j',update.dateTime()) + print 'Hour, 12 hour, unpadded [00 - 23] [%J | %$J | %^J]: '+update.resolveFilepath('%J | %$J | %^J',update.dateTime()) + print 'Hour, 24 hour, space padded [%k | %$k | %^k]: '+update.resolveFilepath('%k | %$k | %^k',update.dateTime()) + print 'Month, zero padded (01 - 12) [%m | %$m | %^m]: '+update.resolveFilepath('%m | %$m | %^m',update.dateTime()) + print 'Minute, zero padded (00 - 59) [%M | %$M | %^M]: '+update.resolveFilepath('%M | %$M | %^M',update.dateTime()) + print 'AM/PM string [%p | %$p | %^p]: '+update.resolveFilepath('%p | %$p | %^p',update.dateTime()) + print 'Rivendell host name [%r | %$r | %^r]: '+update.resolveFilepath('%r | %$r | %^r',update.dateTime()) + print 'Rivendell short host name [%R | %$R | %^R]: '+update.resolveFilepath('%R | %$R | %^R',update.dateTime()) + print 'Rivendell service name [%s | %$s | %^s]: '+update.resolveFilepath('%s | %$s | %^s',update.dateTime()) + print 'Seconds, zero padded (SS) [%S | %$S | %^S]: '+update.resolveFilepath('%S | %$S | %^S',update.dateTime()) + print 'Day of the week, numeric, 1=Monday, 7=Sunday [%u | %$u | %^u]: '+update.resolveFilepath('%u | %$u | %^u',update.dateTime()) + print 'Week number, as per ISO 8601 [00 - 23] [%V | %$V | %^V]: '+update.resolveFilepath('%V | %$V | %^V',update.dateTime()) + print 'Two digit year [%y | %$y | %^y]: '+update.resolveFilepath('%y | %$y | %^y',update.dateTime()) + print 'Four digit year [00 - 23] [%Y | %$Y | %^Y]: '+update.resolveFilepath('%Y | %$Y | %^Y',update.dateTime()) + print "Literal '%' [%%]: "+update.resolveFilepath('%%',update.dateTime()) + +# +# Create an instance of 'PyPADReceiver' +# +rcvr=PyPAD.Receiver() + +# +# Tell it to use the callback +# +rcvr.setCallback(ProcessPad) + +# +# Start the receiver, giving it the hostname or IP address and TCP port of +# the target Rivendell system. Once started, all further processing can only +# be done in the callback method! +# +rcvr.start("localhost",PyPAD.PAD_TCP_PORT) diff --git a/apis/PyPAD/examples/pypad_test.py b/apis/PyPAD/tests/pad_test.py similarity index 97% rename from apis/PyPAD/examples/pypad_test.py rename to apis/PyPAD/tests/pad_test.py index a9444663..91c25ccd 100755 --- a/apis/PyPAD/examples/pypad_test.py +++ b/apis/PyPAD/tests/pad_test.py @@ -1,10 +1,10 @@ #!/usr/bin/python -# pypad_test.py +# pad_test.py # # PyPAD regression test script for Rivendell # -# Exercise every method of 'PyPAD.Update' for each update. +# Exercise every PAD accessor method of 'PyPAD.Update' for each update. # # (C) Copyright 2018 Fred Gleason # @@ -29,6 +29,8 @@ def ProcessPad(update): print '*** Log %03d Update ***********************************************' % update.machine() print '** HEADER INFO **' print ' dateTime(): '+update.dateTime().isoformat(' ') + print ' hostName(): '+update.hostName() + print ' shortHostName(): '+update.shortHostName() print ' machine(): %d' % update.machine() print ' mode(): '+update.mode() print ' onairFlag(): '+str(update.onairFlag()) diff --git a/configure.ac b/configure.ac index 4e7273fe..a8ae77ca 100644 --- a/configure.ac +++ b/configure.ac @@ -470,6 +470,7 @@ AC_CONFIG_FILES([rivendell.spec \ apis/PyPAD/Makefile \ apis/PyPAD/api/Makefile \ apis/PyPAD/examples/Makefile \ + apis/PyPAD/tests/Makefile \ apis/rivwebcapi/Makefile \ apis/rivwebcapi/rivwebcapi.pc \ apis/rivwebcapi/rivwebcapi/Makefile \ diff --git a/lib/rdlogplay.cpp b/lib/rdlogplay.cpp index a903a817..9d1c0804 100644 --- a/lib/rdlogplay.cpp +++ b/lib/rdlogplay.cpp @@ -2963,7 +2963,12 @@ 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("dateTime",QDateTime::currentDateTime(),8). + toUtf8()); + play_pad_socket->write(RDJsonField("hostName", + rda->station()->name(),8).toUtf8()); + play_pad_socket->write(RDJsonField("shortHostName", + rda->station()->shortName(),8).toUtf8()); play_pad_socket->write(RDJsonField("machine",play_id+1,8)); play_pad_socket->write(RDJsonField("onairFlag",play_onair_flag,8)); play_pad_socket->write(RDJsonField("mode",RDAirPlayConf::logModeText(play_op_mode),8)); From 0302445c0b7934df196c8b9a4e4cf14e43725b3b Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Wed, 12 Dec 2018 13:20:24 -0500 Subject: [PATCH 6/8] 2018-12-11 Fred Gleason * Renamed 'apis/PyPAD/examples/pypad_test.py' to 'apisPyPAD/tests/pad_test.py'. * Added a 'hostName' field to the JSON PAD 'padUpdate' object. * Added a 'PyPAD.Update::hostName()' method. * Added a 'shortHostName' field to the JSON PAD 'padUpdate' object. * Added a 'PyPAD.Update::shortHostName()' method. * Added a 'PyPAD.Update::resolveFilepath()' method. * Added 'apis/PyPAD/tests/filepath_test.py. * Added 'api/PyPAD/examples/pypad_filewrite.py'. --- .gitignore | 1 + ChangeLog | 2 + apis/PyPAD/api/Makefile.am | 4 + apis/PyPAD/api/PyPAD.py | 16 ++- apis/PyPAD/examples/now_and_next.py | 12 +- apis/PyPAD/examples/pypad_filewrite.py | 20 ++- apis/PyPAD/examples/pypad_udp.py | 14 +-- apis/PyPAD/tests/filepath_test.py | 72 +++++------ apis/PyPAD/tests/pad_test.py | 162 ++++++++++++------------- configure.ac | 5 +- helpers/Makefile.am | 6 +- helpers/install_python.sh.in | 24 ++++ 12 files changed, 184 insertions(+), 154 deletions(-) create mode 100644 helpers/install_python.sh.in diff --git a/.gitignore b/.gitignore index 2403beda..9f410229 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ docs/rivwebcapi/*.html docs/rivwebcapi/*.pdf helpers/cwrap helpers/docbook +helpers/install_python.sh helpers/jsmin importers/nexgen_filter importers/panel_copy diff --git a/ChangeLog b/ChangeLog index b5645db0..57416de5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18172,3 +18172,5 @@ * Added a 'PyPAD.Update::resolveFilepath()' method. * Added 'apis/PyPAD/tests/filepath_test.py. * Added 'api/PyPAD/examples/pypad_filewrite.py'. +2018-12-12 Fred Gleason + * Updated the PyPAD classes and scripts to use Python 3. diff --git a/apis/PyPAD/api/Makefile.am b/apis/PyPAD/api/Makefile.am index 94181f77..b31af24f 100644 --- a/apis/PyPAD/api/Makefile.am +++ b/apis/PyPAD/api/Makefile.am @@ -23,6 +23,10 @@ rivendelldir = $(pyexecdir) rivendell_PYTHON = PyPAD.py +##install-exec-am: +## ../../../helpers/install_python.sh PyPAD.py $(pyexecdir)/PyPAD.py +##EXTRA_DIST = PyPAD.py + CLEANFILES = *~\ *.idb\ *ilk\ diff --git a/apis/PyPAD/api/PyPAD.py b/apis/PyPAD/api/PyPAD.py index 00e8c175..4992ac1a 100644 --- a/apis/PyPAD/api/PyPAD.py +++ b/apis/PyPAD/api/PyPAD.py @@ -1,5 +1,3 @@ -#!/usr/bin/python - # PyPAD.py # # PAD processor for Rivendell @@ -129,7 +127,7 @@ class Update(object): def __replaceWildcard(self,wildcard,sfield,stype,string,esc): try: - if isinstance(self.__fields['padUpdate'][stype][sfield],unicode): + if isinstance(self.__fields['padUpdate'][stype][sfield],str): string=string.replace('%'+wildcard,self.escape(self.__fields['padUpdate'][stype][sfield],esc)) else: string=string.replace('%'+wildcard,str(self.__fields['padUpdate'][stype][sfield])) @@ -687,18 +685,18 @@ class Receiver(object): """ sock=socket.socket(socket.AF_INET) conn=sock.connect((hostname,port)) - c="" - line="" + c=bytes() + line=bytes() msg="" while 1<2: c=sock.recv(1) line+=c - if c[0]=="\n": - msg+=line - if line=="\r\n": + if c[0]==10: + msg+=line.decode('utf-8') + if line.decode('utf-8')=="\r\n": self.__PyPAD_Process(Update(json.loads(msg))) msg="" - line="" + line=bytes() diff --git a/apis/PyPAD/examples/now_and_next.py b/apis/PyPAD/examples/now_and_next.py index 8b1df372..e690e02c 100755 --- a/apis/PyPAD/examples/now_and_next.py +++ b/apis/PyPAD/examples/now_and_next.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#%PYTHON_BANGPATH% # now_and_next.py # @@ -36,16 +36,16 @@ import PyPAD # def ProcessPad(update): print - print 'Filepath: '+update.resolveFilepath('string %$a',update.dateTime()) + print('Filepath: '+update.resolveFilepath('string %$a',update.dateTime())) if update.hasPadType(PyPAD.TYPE_NOW): - print "Log %03d NOW: " % update.machine()+update.resolvePadFields("%a - %t",PyPAD.ESCAPE_NONE) + print("Log %03d NOW: " % update.machine()+update.resolvePadFields("%a - %t",PyPAD.ESCAPE_NONE)) else: - print "Log %03d NOW: [none]" % update.machine() + print("Log %03d NOW: [none]" % update.machine()) if update.hasPadType(PyPAD.TYPE_NEXT): - print "Log %03d NEXT: " % update.machine()+update.resolvePadFields("%A - %T",PyPAD.ESCAPE_NONE) + print("Log %03d NEXT: " % update.machine()+update.resolvePadFields("%A - %T",PyPAD.ESCAPE_NONE)) else: - print "Log %03d NEXT: [none]" % update.machine() + print("Log %03d NEXT: [none]" % update.machine()) # # Create an instance of 'PyPADReceiver' diff --git a/apis/PyPAD/examples/pypad_filewrite.py b/apis/PyPAD/examples/pypad_filewrite.py index 6673b9c2..5519cf93 100755 --- a/apis/PyPAD/examples/pypad_filewrite.py +++ b/apis/PyPAD/examples/pypad_filewrite.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#%PYTHON_BANGPATH% # pypad_filewrite.py # @@ -20,14 +20,12 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # -#from __future__ import print_function - import sys -import ConfigParser +import configparser import PyPAD -#def eprint(*args,**kwargs): -# print(*args,file=sys.stderr,**kwargs) +def eprint(*args,**kwargs): + print(*args,file=sys.stderr,**kwargs) def processUpdate(update,section): try: @@ -39,7 +37,7 @@ def processUpdate(update,section): return update.hasPadType(PyPAD.TYPE_NEXT) if config.get(section,'ProcessNullUpdates')=='3': return update.hasPadType(PyPAD.TYPE_NOW) and update.hasPadType(PyPAD.TYPE_NEXT) - except ConfigParser.NoOptionError: + except configparser.NoOptionError: return True log_dict={1: 'MasterLog',2: 'Aux1Log',3: 'Aux2Log', @@ -66,11 +64,11 @@ def ProcessPad(update): if config.get(section,'Append')=='1': mode='a' f=open(update.resolveFilepath(config.get(section,'Filename'),update.dateTime()),mode) - f.write(update.resolvePadFields(fmtstr,int(config.get(section,'Encoding'))).encode('utf-8')) + f.write(update.resolvePadFields(fmtstr,int(config.get(section,'Encoding')))) f.close() n=n+1 - except ConfigParser.NoSectionError: + except configparser.NoSectionError: return # @@ -78,7 +76,7 @@ def ProcessPad(update): # if len(sys.argv)>=2: fp=open(sys.argv[1]) - config=ConfigParser.ConfigParser() + config=configparser.ConfigParser(interpolation=None) config.readfp(fp) fp.close() else: @@ -87,4 +85,4 @@ else: rcvr=PyPAD.Receiver() rcvr.setCallback(ProcessPad) -rcvr.start("localhost",PyPAD.PAD_TCP_PORT) +rcvr.start('localhost',PyPAD.PAD_TCP_PORT) diff --git a/apis/PyPAD/examples/pypad_udp.py b/apis/PyPAD/examples/pypad_udp.py index 21bf6df4..c4c9fca1 100755 --- a/apis/PyPAD/examples/pypad_udp.py +++ b/apis/PyPAD/examples/pypad_udp.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#%PYTHON_BANGPATH% # pypad_udp.py # @@ -20,15 +20,13 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # -#from __future__ import print_function - import sys import socket -import ConfigParser +import configparser import PyPAD -#def eprint(*args,**kwargs): -# print(*args,file=sys.stderr,**kwargs) +def eprint(*args,**kwargs): + print(*args,file=sys.stderr,**kwargs) def processUpdate(update,section): if config.get(section,'ProcessNullUpdates')=='0': @@ -63,7 +61,7 @@ def ProcessPad(update): send_sock.sendto(update.resolvePadFields(fmtstr,int(config.get(section,'Encoding'))).encode('utf-8'), (config.get(section,'IpAddress'),int(config.get(section,'UdpPort')))) n=n+1 - except ConfigParser.NoSectionError: + except configparser.NoSectionError: return # @@ -71,7 +69,7 @@ def ProcessPad(update): # if len(sys.argv)>=2: fp=open(sys.argv[1]) - config=ConfigParser.ConfigParser() + config=configparser.ConfigParser(interpolation=None) config.readfp(fp) fp.close() else: diff --git a/apis/PyPAD/tests/filepath_test.py b/apis/PyPAD/tests/filepath_test.py index d7c7c955..69910f34 100755 --- a/apis/PyPAD/tests/filepath_test.py +++ b/apis/PyPAD/tests/filepath_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#%PYTHON_BANGPATH% # filepath_test.py # @@ -25,40 +25,40 @@ import PyPAD def ProcessPad(update): - print - print 'DateTime: '+update.dateTime().isoformat(' ') - print - print 'Abbreviated weekday name [%a | %$a | %^a]: '+update.resolveFilepath('%a | %$a | %^a',update.dateTime()) - print 'Full weekday name [%A | %$A | %^A]: '+update.resolveFilepath('%A | %$A | %^A',update.dateTime()) - print 'Abbreviated month name [%b | %$b | %^b]: '+update.resolveFilepath('%b | %$b | %^b',update.dateTime()) - print 'Full month name [%B | %$B | %^B]: '+update.resolveFilepath('%B | %$B | %^B',update.dateTime()) - print 'Century [%C | %$C | %^C]: '+update.resolveFilepath('%C | %$C | %^C',update.dateTime()) - print 'Day of the month, zero padded [01 - 31] [%d | %$d | %^d]: '+update.resolveFilepath('%d | %$d | %^d',update.dateTime()) - print 'Date (mm-dd-yy) [%D | %$D | %^D]: '+update.resolveFilepath('%D | %$D | %^D',update.dateTime()) - print 'Day of the month, space padded [ 1 - 31] [%e | %$e | %^e]: '+update.resolveFilepath('%e | %$e | %^e',update.dateTime()) - print 'Day of the month, unpadded [ 1 - 31] [%E | %$E | %^E]: '+update.resolveFilepath('%E | %$E | %^E',update.dateTime()) - print 'Date (yyyy-mm-dd) [%F | %$F | %^F]: '+update.resolveFilepath('%F | %$F | %^F',update.dateTime()) - print 'Two digit year [%g | %$g | %^g]: '+update.resolveFilepath('%g | %$g | %^g',update.dateTime()) - print 'Four digit year [%G | %$G | %^G]: '+update.resolveFilepath('%G | %$G | %^G',update.dateTime()) - print 'Abbreviated month name [%h | %$h | %^h]: '+update.resolveFilepath('%h | %$h | %^h',update.dateTime()) - print 'Hour, 24 hour, zero padded [00 - 23] [%H | %$H | %^H]: '+update.resolveFilepath('%H | %$H | %^H',update.dateTime()) - print 'Hour, 12 hour, space padded [00 - 23] [%i | %$i | %^i]: '+update.resolveFilepath('%i | %$i | %^i',update.dateTime()) - print 'Hour, 12 hour, zero padded [00 - 23] [%I | %$I | %^I]: '+update.resolveFilepath('%I | %$I | %^I',update.dateTime()) - print 'Day of year, zero padded [%j | %$j | %^j]: '+update.resolveFilepath('%j | %$j | %^j',update.dateTime()) - print 'Hour, 12 hour, unpadded [00 - 23] [%J | %$J | %^J]: '+update.resolveFilepath('%J | %$J | %^J',update.dateTime()) - print 'Hour, 24 hour, space padded [%k | %$k | %^k]: '+update.resolveFilepath('%k | %$k | %^k',update.dateTime()) - print 'Month, zero padded (01 - 12) [%m | %$m | %^m]: '+update.resolveFilepath('%m | %$m | %^m',update.dateTime()) - print 'Minute, zero padded (00 - 59) [%M | %$M | %^M]: '+update.resolveFilepath('%M | %$M | %^M',update.dateTime()) - print 'AM/PM string [%p | %$p | %^p]: '+update.resolveFilepath('%p | %$p | %^p',update.dateTime()) - print 'Rivendell host name [%r | %$r | %^r]: '+update.resolveFilepath('%r | %$r | %^r',update.dateTime()) - print 'Rivendell short host name [%R | %$R | %^R]: '+update.resolveFilepath('%R | %$R | %^R',update.dateTime()) - print 'Rivendell service name [%s | %$s | %^s]: '+update.resolveFilepath('%s | %$s | %^s',update.dateTime()) - print 'Seconds, zero padded (SS) [%S | %$S | %^S]: '+update.resolveFilepath('%S | %$S | %^S',update.dateTime()) - print 'Day of the week, numeric, 1=Monday, 7=Sunday [%u | %$u | %^u]: '+update.resolveFilepath('%u | %$u | %^u',update.dateTime()) - print 'Week number, as per ISO 8601 [00 - 23] [%V | %$V | %^V]: '+update.resolveFilepath('%V | %$V | %^V',update.dateTime()) - print 'Two digit year [%y | %$y | %^y]: '+update.resolveFilepath('%y | %$y | %^y',update.dateTime()) - print 'Four digit year [00 - 23] [%Y | %$Y | %^Y]: '+update.resolveFilepath('%Y | %$Y | %^Y',update.dateTime()) - print "Literal '%' [%%]: "+update.resolveFilepath('%%',update.dateTime()) + print() + print('DateTime: '+update.dateTime().isoformat(' ')) + print() + print('Abbreviated weekday name [%a | %$a | %^a]: '+update.resolveFilepath('%a | %$a | %^a',update.dateTime())) + print('Full weekday name [%A | %$A | %^A]: '+update.resolveFilepath('%A | %$A | %^A',update.dateTime())) + print('Abbreviated month name [%b | %$b | %^b]: '+update.resolveFilepath('%b | %$b | %^b',update.dateTime())) + print('Full month name [%B | %$B | %^B]: '+update.resolveFilepath('%B | %$B | %^B',update.dateTime())) + print('Century [%C | %$C | %^C]: '+update.resolveFilepath('%C | %$C | %^C',update.dateTime())) + print('Day of the month, zero padded [01 - 31] [%d | %$d | %^d]: '+update.resolveFilepath('%d | %$d | %^d',update.dateTime())) + print('Date (mm-dd-yy) [%D | %$D | %^D]: '+update.resolveFilepath('%D | %$D | %^D',update.dateTime())) + print('Day of the month, space padded [ 1 - 31] [%e | %$e | %^e]: '+update.resolveFilepath('%e | %$e | %^e',update.dateTime())) + print('Day of the month, unpadded [ 1 - 31] [%E | %$E | %^E]: '+update.resolveFilepath('%E | %$E | %^E',update.dateTime())) + print('Date (yyyy-mm-dd) [%F | %$F | %^F]: '+update.resolveFilepath('%F | %$F | %^F',update.dateTime())) + print('Two digit year [%g | %$g | %^g]: '+update.resolveFilepath('%g | %$g | %^g',update.dateTime())) + print('Four digit year [%G | %$G | %^G]: '+update.resolveFilepath('%G | %$G | %^G',update.dateTime())) + print('Abbreviated month name [%h | %$h | %^h]: '+update.resolveFilepath('%h | %$h | %^h',update.dateTime())) + print('Hour, 24 hour, zero padded [00 - 23] [%H | %$H | %^H]: '+update.resolveFilepath('%H | %$H | %^H',update.dateTime())) + print('Hour, 12 hour, space padded [00 - 23] [%i | %$i | %^i]: '+update.resolveFilepath('%i | %$i | %^i',update.dateTime())) + print('Hour, 12 hour, zero padded [00 - 23] [%I | %$I | %^I]: '+update.resolveFilepath('%I | %$I | %^I',update.dateTime())) + print('Day of year, zero padded [%j | %$j | %^j]: '+update.resolveFilepath('%j | %$j | %^j',update.dateTime())) + print('Hour, 12 hour, unpadded [00 - 23] [%J | %$J | %^J]: '+update.resolveFilepath('%J | %$J | %^J',update.dateTime())) + print('Hour, 24 hour, space padded [%k | %$k | %^k]: '+update.resolveFilepath('%k | %$k | %^k',update.dateTime())) + print('Month, zero padded (01 - 12) [%m | %$m | %^m]: '+update.resolveFilepath('%m | %$m | %^m',update.dateTime())) + print('Minute, zero padded (00 - 59) [%M | %$M | %^M]: '+update.resolveFilepath('%M | %$M | %^M',update.dateTime())) + print('AM/PM string [%p | %$p | %^p]: '+update.resolveFilepath('%p | %$p | %^p',update.dateTime())) + print('Rivendell host name [%r | %$r | %^r]: '+update.resolveFilepath('%r | %$r | %^r',update.dateTime())) + print('Rivendell short host name [%R | %$R | %^R]: '+update.resolveFilepath('%R | %$R | %^R',update.dateTime())) + print('Rivendell service name [%s | %$s | %^s]: '+update.resolveFilepath('%s | %$s | %^s',update.dateTime())) + print('Seconds, zero padded (SS) [%S | %$S | %^S]: '+update.resolveFilepath('%S | %$S | %^S',update.dateTime())) + print('Day of the week, numeric, 1=Monday, 7=Sunday [%u | %$u | %^u]: '+update.resolveFilepath('%u | %$u | %^u',update.dateTime())) + print('Week number, as per ISO 8601 [00 - 23] [%V | %$V | %^V]: '+update.resolveFilepath('%V | %$V | %^V',update.dateTime())) + print('Two digit year [%y | %$y | %^y]: '+update.resolveFilepath('%y | %$y | %^y',update.dateTime())) + print('Four digit year [00 - 23] [%Y | %$Y | %^Y]: '+update.resolveFilepath('%Y | %$Y | %^Y',update.dateTime())) + print("Literal '%' [%%]: "+update.resolveFilepath('%%',update.dateTime())) # # Create an instance of 'PyPADReceiver' @@ -75,4 +75,4 @@ rcvr.setCallback(ProcessPad) # the target Rivendell system. Once started, all further processing can only # be done in the callback method! # -rcvr.start("localhost",PyPAD.PAD_TCP_PORT) +rcvr.start(localhost',PyPAD.PAD_TCP_PORT) diff --git a/apis/PyPAD/tests/pad_test.py b/apis/PyPAD/tests/pad_test.py index 91c25ccd..1ebca6ca 100755 --- a/apis/PyPAD/tests/pad_test.py +++ b/apis/PyPAD/tests/pad_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#%PYTHON_BANGPATH% # pad_test.py # @@ -26,108 +26,108 @@ import PyPAD def ProcessPad(update): print - print '*** Log %03d Update ***********************************************' % update.machine() - print '** HEADER INFO **' - print ' dateTime(): '+update.dateTime().isoformat(' ') - print ' hostName(): '+update.hostName() - print ' shortHostName(): '+update.shortHostName() - print ' machine(): %d' % update.machine() - print ' mode(): '+update.mode() - print ' onairFlag(): '+str(update.onairFlag()) + print('*** Log %03d Update ***********************************************' % update.machine()) + print('** HEADER INFO **') + print(' dateTime(): '+update.dateTime().isoformat(' ')) + print(' hostName(): '+update.hostName()) + print(' shortHostName(): '+update.shortHostName()) + print(' machine(): %d' % update.machine()) + print( ' mode(): '+update.mode()) + print(' onairFlag(): '+str(update.onairFlag())) print if update.hasLog(): - print '** LOG INFO **' - print ' logName(): '+update.logName() - print + print('** LOG INFO **') + print(' logName(): '+update.logName()) + print() else: - print '**NO LOG INFO PRESENT**' - print + print('**NO LOG INFO PRESENT**') + print() if update.hasService(): - print '** SERVICE INFO **' - print ' serviceName(): '+update.serviceName() - print 'serviceDescription(): '+update.serviceDescription() - print 'serviceProgramCode(): '+update.serviceProgramCode() - print + print('** SERVICE INFO **') + print(' serviceName(): '+update.serviceName()) + print('serviceDescription(): '+update.serviceDescription()) + print('serviceProgramCode(): '+update.serviceProgramCode()) + print() else: - print '** NO SERVICE INFO PRESENT **' - print + print('** NO SERVICE INFO PRESENT **') + print() if update.hasPadType(PyPAD.TYPE_NOW): - print '** NOW PLAYING INFO **' + print('** NOW PLAYING INFO **') try: - print ' startDateTime(): '+update.startDateTime(PyPAD.TYPE_NOW).isoformat(' ') + print(' startDateTime(): '+update.startDateTime(PyPAD.TYPE_NOW).isoformat(' ')) except AttributeError: - print ' startDateTime(): None' - print ' cartType(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CART_TYPE) - print ' cartNumber(): %u / ' % update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CART_NUMBER)+update.resolvePadFields("%n",PyPAD.ESCAPE_NONE) - print ' cutNumber(): %u / ' % update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CUT_NUMBER)+update.resolvePadFields("%j",PyPAD.ESCAPE_NONE) - print ' length(): %u / ' % update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_LENGTH)+update.resolvePadFields("%h",PyPAD.ESCAPE_NONE) + print(' startDateTime(): None') + print(' cartType(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CART_TYPE)) + print(' cartNumber(): %u / ' % update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CART_NUMBER)+update.resolvePadFields("%n",PyPAD.ESCAPE_NONE)) + print(' cutNumber(): %u / ' % update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CUT_NUMBER)+update.resolvePadFields("%j",PyPAD.ESCAPE_NONE)) + print(' length(): %u / ' % update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_LENGTH)+update.resolvePadFields("%h",PyPAD.ESCAPE_NONE)) try: - print ' year(): %u / ' % update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_YEAR)+update.resolvePadFields("%y",PyPAD.ESCAPE_NONE) + print(' year(): %u / ' % update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_YEAR)+update.resolvePadFields("%y",PyPAD.ESCAPE_NONE)) except TypeError: - print ' year(): None / '+update.resolvePadFields("%Y",PyPAD.ESCAPE_NONE) - print ' groupName(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_GROUP_NAME)+' / '+update.resolvePadFields('%g',PyPAD.ESCAPE_NONE) - print ' title(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_TITLE)+' / '+update.resolvePadFields('%t',PyPAD.ESCAPE_NONE) - print ' artist(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_ARTIST)+' / '+update.resolvePadFields('%a',PyPAD.ESCAPE_NONE) - print ' publisher(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_PUBLISHER)+' / '+update.resolvePadFields('%p',PyPAD.ESCAPE_NONE) - print ' composer(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_COMPOSER)+' / '+update.resolvePadFields('%m',PyPAD.ESCAPE_NONE) - print ' album(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_ALBUM)+' / '+update.resolvePadFields('%l',PyPAD.ESCAPE_NONE) - print ' label(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_LABEL)+' / '+update.resolvePadFields('%b',PyPAD.ESCAPE_NONE) - print ' client(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CLIENT)+' / '+update.resolvePadFields('%c',PyPAD.ESCAPE_NONE) - print ' agency(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_AGENCY)+' / '+update.resolvePadFields('%e',PyPAD.ESCAPE_NONE) - print ' conductor(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CONDUCTOR)+' / '+update.resolvePadFields('%r',PyPAD.ESCAPE_NONE) - print ' userDefined(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_USER_DEFINED)+' / '+update.resolvePadFields('%u',PyPAD.ESCAPE_NONE) - print ' songId(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_SONG_ID)+' / '+update.resolvePadFields('%s',PyPAD.ESCAPE_NONE) - print ' outcue(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_OUTCUE)+' / '+update.resolvePadFields('%o',PyPAD.ESCAPE_NONE) - print ' description(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_DESCRIPTION)+' / '+update.resolvePadFields('%i',PyPAD.ESCAPE_NONE) - print ' externalEventId(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_EXTERNAL_EVENT_ID) - print ' externalData(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_EXTERNAL_DATA) - print ' externalAnncType(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_EXTERNAL_EVENT_ID) - print + print(' year(): None / '+update.resolvePadFields("%Y",PyPAD.ESCAPE_NONE)) + print(' groupName(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_GROUP_NAME)+' / '+update.resolvePadFields('%g',PyPAD.ESCAPE_NONE)) + print(' title(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_TITLE)+' / '+update.resolvePadFields('%t',PyPAD.ESCAPE_NONE)) + print(' artist(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_ARTIST)+' / '+update.resolvePadFields('%a',PyPAD.ESCAPE_NONE)) + print(' publisher(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_PUBLISHER)+' / '+update.resolvePadFields('%p',PyPAD.ESCAPE_NONE)) + print(' composer(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_COMPOSER)+' / '+update.resolvePadFields('%m',PyPAD.ESCAPE_NONE)) + print(' album(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_ALBUM)+' / '+update.resolvePadFields('%l',PyPAD.ESCAPE_NONE)) + print(' label(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_LABEL)+' / '+update.resolvePadFields('%b',PyPAD.ESCAPE_NONE)) + print(' client(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CLIENT)+' / '+update.resolvePadFields('%c',PyPAD.ESCAPE_NONE)) + print(' agency(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_AGENCY)+' / '+update.resolvePadFields('%e',PyPAD.ESCAPE_NONE)) + print(' conductor(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_CONDUCTOR)+' / '+update.resolvePadFields('%r',PyPAD.ESCAPE_NONE)) + print(' userDefined(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_USER_DEFINED)+' / '+update.resolvePadFields('%u',PyPAD.ESCAPE_NONE)) + print(' songId(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_SONG_ID)+' / '+update.resolvePadFields('%s',PyPAD.ESCAPE_NONE)) + print(' outcue(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_OUTCUE)+' / '+update.resolvePadFields('%o',PyPAD.ESCAPE_NONE)) + print(' description(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_DESCRIPTION)+' / '+update.resolvePadFields('%i',PyPAD.ESCAPE_NONE)) + print(' externalEventId(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_EXTERNAL_EVENT_ID)) + print(' externalData(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_EXTERNAL_DATA)) + print(' externalAnncType(): '+update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_EXTERNAL_EVENT_ID)) + print() else: - print '** NO NOW PLAYING INFO **' - print + print('** NO NOW PLAYING INFO **') + print() if update.hasPadType(PyPAD.TYPE_NEXT): - print '** NEXT PLAYING INFO **' + print('** NEXT PLAYING INFO **') try: - print ' startDateTime(): '+update.startDateTime(PyPAD.TYPE_NEXT).isoformat(' ') + print(' startDateTime(): '+update.startDateTime(PyPAD.TYPE_NEXT).isoformat(' ')) except AttributeError: - print ' startDateTime(): None' - print ' cartType(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CART_TYPE) - print ' cartNumber(): %u / ' % update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CART_NUMBER)+update.resolvePadFields("%N",PyPAD.ESCAPE_NONE) - print ' cutNumber(): %u / ' % update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CUT_NUMBER)+update.resolvePadFields("%J",PyPAD.ESCAPE_NONE) - print ' length(): %u / ' % update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_LENGTH)+update.resolvePadFields("%H",PyPAD.ESCAPE_NONE) + print(' startDateTime(): None') + print(' cartType(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CART_TYPE)) + print(' cartNumber(): %u / ' % update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CART_NUMBER)+update.resolvePadFields("%N",PyPAD.ESCAPE_NONE)) + print(' cutNumber(): %u / ' % update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CUT_NUMBER)+update.resolvePadFields("%J",PyPAD.ESCAPE_NONE)) + print(' length(): %u / ' % update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_LENGTH)+update.resolvePadFields("%H",PyPAD.ESCAPE_NONE)) try: - print ' year(): %u / ' % update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_YEAR)+update.resolvePadFields("%Y",PyPAD.ESCAPE_NONE) + print(' year(): %u / ' % update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_YEAR)+update.resolvePadFields("%Y",PyPAD.ESCAPE_NONE)) except TypeError: - print ' year(): None / '+update.resolvePadFields("%Y",PyPAD.ESCAPE_NONE) - print ' groupName(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_GROUP_NAME)+' / '+update.resolvePadFields('%G',PyPAD.ESCAPE_NONE) - print ' title(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_TITLE)+' / '+update.resolvePadFields('%T',PyPAD.ESCAPE_NONE) - print ' artist(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_ARTIST)+' / '+update.resolvePadFields('%A',PyPAD.ESCAPE_NONE) - print ' publisher(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_PUBLISHER)+' / '+update.resolvePadFields('%P',PyPAD.ESCAPE_NONE) - print ' composer(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_COMPOSER)+' / '+update.resolvePadFields('%M',PyPAD.ESCAPE_NONE) - print ' album(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_ALBUM)+' / '+update.resolvePadFields('%L',PyPAD.ESCAPE_NONE) - print ' label(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_LABEL)+' / '+update.resolvePadFields('%B',PyPAD.ESCAPE_NONE) - print ' client(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CLIENT)+' / '+update.resolvePadFields('%C',PyPAD.ESCAPE_NONE) - print ' agency(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_AGENCY)+' / '+update.resolvePadFields('%E',PyPAD.ESCAPE_NONE) - print ' conductor(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CONDUCTOR)+' / '+update.resolvePadFields('%R',PyPAD.ESCAPE_NONE) - print ' userDefined(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_USER_DEFINED)+' / '+update.resolvePadFields('%U',PyPAD.ESCAPE_NONE) - print ' songId(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_SONG_ID)+' / '+update.resolvePadFields('%S',PyPAD.ESCAPE_NONE) - print ' outcue(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_OUTCUE)+' / '+update.resolvePadFields('%O',PyPAD.ESCAPE_NONE) - print ' description(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_DESCRIPTION)+' / '+update.resolvePadFields('%I',PyPAD.ESCAPE_NONE) - print ' externalEventId(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_EXTERNAL_EVENT_ID) - print ' externalData(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_EXTERNAL_DATA) - print ' externalAnncType(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_EXTERNAL_EVENT_ID) - print + print(' year(): None / '+update.resolvePadFields("%Y",PyPAD.ESCAPE_NONE)) + print(' groupName(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_GROUP_NAME)+' / '+update.resolvePadFields('%G',PyPAD.ESCAPE_NONE)) + print(' title(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_TITLE)+' / '+update.resolvePadFields('%T',PyPAD.ESCAPE_NONE)) + print(' artist(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_ARTIST)+' / '+update.resolvePadFields('%A',PyPAD.ESCAPE_NONE)) + print(' publisher(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_PUBLISHER)+' / '+update.resolvePadFields('%P',PyPAD.ESCAPE_NONE)) + print(' composer(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_COMPOSER)+' / '+update.resolvePadFields('%M',PyPAD.ESCAPE_NONE)) + print(' album(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_ALBUM)+' / '+update.resolvePadFields('%L',PyPAD.ESCAPE_NONE)) + print(' label(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_LABEL)+' / '+update.resolvePadFields('%B',PyPAD.ESCAPE_NONE)) + print(' client(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CLIENT)+' / '+update.resolvePadFields('%C',PyPAD.ESCAPE_NONE)) + print(' agency(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_AGENCY)+' / '+update.resolvePadFields('%E',PyPAD.ESCAPE_NONE)) + print(' conductor(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_CONDUCTOR)+' / '+update.resolvePadFields('%R',PyPAD.ESCAPE_NONE)) + print(' userDefined(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_USER_DEFINED)+' / '+update.resolvePadFields('%U',PyPAD.ESCAPE_NONE)) + print(' songId(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_SONG_ID)+' / '+update.resolvePadFields('%S',PyPAD.ESCAPE_NONE)) + print(' outcue(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_OUTCUE)+' / '+update.resolvePadFields('%O',PyPAD.ESCAPE_NONE)) + print(' description(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_DESCRIPTION)+' / '+update.resolvePadFields('%I',PyPAD.ESCAPE_NONE)) + print(' externalEventId(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_EXTERNAL_EVENT_ID)) + print(' externalData(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_EXTERNAL_DATA)) + print(' externalAnncType(): '+update.padField(PyPAD.TYPE_NEXT,PyPAD.FIELD_EXTERNAL_EVENT_ID)) + print() else: - print '** NO NEXT PLAYING INFO **' - print + print('** NO NEXT PLAYING INFO **') + print() - print '******************************************************************' + print ('******************************************************************') # # Create an instance of 'PyPADReceiver' @@ -144,4 +144,4 @@ rcvr.setCallback(ProcessPad) # the target Rivendell system. Once started, all further processing can only # be done in the callback method! # -rcvr.start("localhost",PyPAD.PAD_TCP_PORT) +rcvr.start('localhost',PyPAD.PAD_TCP_PORT) diff --git a/configure.ac b/configure.ac index a8ae77ca..1c3e0905 100644 --- a/configure.ac +++ b/configure.ac @@ -250,7 +250,7 @@ AC_CHECK_HEADER(soundtouch/SoundTouch.h,[],[AC_MSG_ERROR([*** SoundTouch not fou # # Check for Python # -AM_PATH_PYTHON([2.7]) +AM_PATH_PYTHON([3]) # # Check for FLAC @@ -466,6 +466,7 @@ AC_CONFIG_FILES([rivendell.spec \ conf/rd-bin.conf \ icons/Makefile \ helpers/Makefile \ + helpers/install_python.sh \ apis/Makefile \ apis/PyPAD/Makefile \ apis/PyPAD/api/Makefile \ @@ -553,6 +554,8 @@ AC_CONFIG_FILES([rivendell.spec \ ]) AC_OUTPUT() +chmod 755 helpers/install_python.sh + # # Create symlinks in 'utils/rdselect_helper/' # diff --git a/helpers/Makefile.am b/helpers/Makefile.am index 848c2334..6bf42a7d 100644 --- a/helpers/Makefile.am +++ b/helpers/Makefile.am @@ -33,7 +33,8 @@ dist_cwrap_SOURCES = cwrap.cpp cwrap.h dist_jsmin_SOURCES = jsmin.c -EXTRA_DIST = rdpack.sh\ +EXTRA_DIST = install_python.sh.in\ + rdpack.sh\ rdtrans.sh\ rdtransgui.sh\ setenvvar.sh @@ -42,7 +43,8 @@ CLEANFILES = *~\ *.tar.gz\ moc_* -DISTCLEANFILES = docbook +DISTCLEANFILES = docbook\ + install_python.sh MAINTAINERCLEANFILES = *~\ *.tar.gz\ diff --git a/helpers/install_python.sh.in b/helpers/install_python.sh.in new file mode 100644 index 00000000..f063376d --- /dev/null +++ b/helpers/install_python.sh.in @@ -0,0 +1,24 @@ +#!/bin/sh + +# install_python.sh +# +# (C) Copyright 2018 Fred Gleason +# +# 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. +# + +cat $1 | sed -e s^%PYTHON_BANGPATH%^@PYTHON@^ > $2 +chmod 755 $2 + + From 7d2ec28205b960d45cc8c2e2394ca176e02ce105 Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Wed, 12 Dec 2018 13:26:51 -0500 Subject: [PATCH 7/8] 2018-12-12 Fred Gleason * Documented the Python 3.4 dependency in 'INSTALL'. --- ChangeLog | 2 ++ INSTALL | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 57416de5..d9f7c825 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18174,3 +18174,5 @@ * Added 'api/PyPAD/examples/pypad_filewrite.py'. 2018-12-12 Fred Gleason * Updated the PyPAD classes and scripts to use Python 3. +2018-12-12 Fred Gleason + * Documented the Python 3.4 dependency in 'INSTALL'. diff --git a/INSTALL b/INSTALL index a367da3c..55292014 100644 --- a/INSTALL +++ b/INSTALL @@ -42,6 +42,10 @@ OggVorbis - Open Source Audio Coding Library. Needed for OggVorbis importing and exporting. Included with most distros, or available at: http://www.xiph.org/. +Python, v3.4 or later +Open source scripting language. Included with most distros, or available at: +https://www.python.org/. + Qt Toolkit, v4.6 or better Most modern Linux distros include this. It's typically installed as part of the KDE Desktop Environment, although KDE is by no means required. From 24e408810e7549c9ff65d3993bd71e9dd5ed5dc0 Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Wed, 12 Dec 2018 14:21:56 -0500 Subject: [PATCH 8/8] 2018-12-12 Fred Gleason * Renamed rdrlmd(8) to rdpadd(8). --- .gitignore | 2 +- ChangeLog | 2 + Makefile.am | 2 +- configure.ac | 2 +- {rdrlmd => rdpadd}/Makefile.am | 10 +-- rdrlmd/rdrlmd.cpp => rdpadd/rdpadd.cpp | 90 +++++++++++++------------- rdrlmd/rdrlmd.h => rdpadd/rdpadd.h | 26 ++++---- rdservice/rdservice.h | 2 +- rdservice/startup.cpp | 16 ++--- 9 files changed, 77 insertions(+), 75 deletions(-) rename {rdrlmd => rdpadd}/Makefile.am (85%) rename rdrlmd/rdrlmd.cpp => rdpadd/rdpadd.cpp (55%) rename rdrlmd/rdrlmd.h => rdpadd/rdpadd.h (77%) diff --git a/.gitignore b/.gitignore index 9f410229..c4401246 100644 --- a/.gitignore +++ b/.gitignore @@ -82,10 +82,10 @@ rdlogedit/rdlogedit rdlogin/rdlogin rdlogmanager/rdlogmanager rdmonitor/rdmonitor +rdpadd/rdpadd rdpanel/rdpanel rdrepld/rdrepld rdrepld-suse -rdrlmd/rdrlmd rdselect/rdselect rdservice/rdservice rdvairplayd/rdvairplayd diff --git a/ChangeLog b/ChangeLog index d9f7c825..884ea1b4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18176,3 +18176,5 @@ * Updated the PyPAD classes and scripts to use Python 3. 2018-12-12 Fred Gleason * Documented the Python 3.4 dependency in 'INSTALL'. +2018-12-12 Fred Gleason + * Renamed rdrlmd(8) to rdpadd(8). diff --git a/Makefile.am b/Makefile.am index 7b6b06d4..52ec5d5c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,7 +50,7 @@ SUBDIRS = icons\ rdmonitor\ rdpanel\ rdrepld\ - rdrlmd\ + rdpadd\ rdselect\ rdservice\ rdvairplayd\ diff --git a/configure.ac b/configure.ac index 1c3e0905..f77c20d7 100644 --- a/configure.ac +++ b/configure.ac @@ -517,7 +517,7 @@ AC_CONFIG_FILES([rivendell.spec \ rdmonitor/Makefile \ rdpanel/Makefile \ rdrepld/Makefile \ - rdrlmd/Makefile \ + rdpadd/Makefile \ rdselect/Makefile \ rdservice/Makefile \ rdvairplayd/Makefile \ diff --git a/rdrlmd/Makefile.am b/rdpadd/Makefile.am similarity index 85% rename from rdrlmd/Makefile.am rename to rdpadd/Makefile.am index a2e9a9c6..d29f9018 100644 --- a/rdrlmd/Makefile.am +++ b/rdpadd/Makefile.am @@ -1,6 +1,6 @@ ## Makefile.am ## -## Rivendell RLM Consolidation Server +## Rivendell PAD Consolidation Server ## ## (C) Copyright 2018 Fred Gleason ## @@ -29,13 +29,13 @@ moc_%.cpp: %.h $(MOC) $< -o $@ -sbin_PROGRAMS = rdrlmd +sbin_PROGRAMS = rdpadd -dist_rdrlmd_SOURCES = rdrlmd.cpp rdrlmd.h +dist_rdpadd_SOURCES = rdpadd.cpp rdpadd.h -nodist_rdrlmd_SOURCES = moc_rdrlmd.cpp +nodist_rdpadd_SOURCES = moc_rdpadd.cpp -rdrlmd_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT4_LIBS@ -lQt3Support +rdpadd_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT4_LIBS@ -lQt3Support CLEANFILES = *~\ *.idb\ diff --git a/rdrlmd/rdrlmd.cpp b/rdpadd/rdpadd.cpp similarity index 55% rename from rdrlmd/rdrlmd.cpp rename to rdpadd/rdpadd.cpp index a65ea06f..d6010b9b 100644 --- a/rdrlmd/rdrlmd.cpp +++ b/rdpadd/rdpadd.cpp @@ -1,6 +1,6 @@ -// rdrlmd.cpp +// rdpadd.cpp // -// Rivendell RLM Consolidation Server +// Rivendell PAD Consolidation Server // // (C) Copyright 2018 Fred Gleason // @@ -27,7 +27,7 @@ #include #include -#include "rdrlmd.h" +#include "rdpadd.h" MetadataSource::MetadataSource(QTcpSocket *sock) { @@ -73,20 +73,20 @@ QTcpSocket *MetadataSource::socket() const MainObject::MainObject(QObject *parent) : QObject(parent) { - new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdrlmd",RDRLMD_USAGE); + new RDCmdSwitch(qApp->argc(),qApp->argv(),"rdpadd",RDPADD_USAGE); // // Client Server // - rlm_client_disconnect_mapper=new QSignalMapper(this); - connect(rlm_client_disconnect_mapper,SIGNAL(mapped(int)), + pad_client_disconnect_mapper=new QSignalMapper(this); + connect(pad_client_disconnect_mapper,SIGNAL(mapped(int)), this,SLOT(clientDisconnected(int))); - rlm_client_server=new QTcpServer(this); - connect(rlm_client_server,SIGNAL(newConnection()), + pad_client_server=new QTcpServer(this); + connect(pad_client_server,SIGNAL(newConnection()), this,SLOT(newClientConnectionData())); - if(!rlm_client_server->listen(QHostAddress::Any,RD_RLM2_CLIENT_TCP_PORT)) { - fprintf(stderr,"rdrlmd: unable to bind client port %d\n", + if(!pad_client_server->listen(QHostAddress::Any,RD_RLM2_CLIENT_TCP_PORT)) { + fprintf(stderr,"rdpadd: unable to bind client port %d\n", RD_RLM2_CLIENT_TCP_PORT); exit(1); } @@ -94,20 +94,20 @@ MainObject::MainObject(QObject *parent) // // Source Server // - rlm_source_ready_mapper=new QSignalMapper(this); - connect(rlm_source_ready_mapper,SIGNAL(mapped(int)), + pad_source_ready_mapper=new QSignalMapper(this); + connect(pad_source_ready_mapper,SIGNAL(mapped(int)), this,SLOT(sourceReadyReadData(int))); - rlm_source_disconnect_mapper=new QSignalMapper(this); - connect(rlm_source_disconnect_mapper,SIGNAL(mapped(int)), + pad_source_disconnect_mapper=new QSignalMapper(this); + connect(pad_source_disconnect_mapper,SIGNAL(mapped(int)), this,SLOT(sourceDisconnected(int))); - rlm_source_server=new RDUnixServer(this); - connect(rlm_source_server,SIGNAL(newConnection()), + pad_source_server=new RDUnixServer(this); + connect(pad_source_server,SIGNAL(newConnection()), this,SLOT(newSourceConnectionData())); - if(!rlm_source_server->listenToAbstract(RD_RLM2_SOURCE_UNIX_ADDRESS)) { - fprintf(stderr,"rdrlmd: unable to bind source socket [%s]\n", - (const char *)rlm_source_server->errorString().toUtf8()); + if(!pad_source_server->listenToAbstract(RD_RLM2_SOURCE_UNIX_ADDRESS)) { + fprintf(stderr,"rdpadd: unable to bind source socket [%s]\n", + (const char *)pad_source_server->errorString().toUtf8()); exit(1); } } @@ -115,10 +115,10 @@ MainObject::MainObject(QObject *parent) void MainObject::newClientConnectionData() { - QTcpSocket *sock=rlm_client_server->nextPendingConnection(); - connect(sock,SIGNAL(disconnected()),rlm_client_disconnect_mapper,SLOT(map())); - rlm_client_disconnect_mapper->setMapping(sock,sock->socketDescriptor()); - rlm_client_sockets[sock->socketDescriptor()]=sock; + QTcpSocket *sock=pad_client_server->nextPendingConnection(); + connect(sock,SIGNAL(disconnected()),pad_client_disconnect_mapper,SLOT(map())); + pad_client_disconnect_mapper->setMapping(sock,sock->socketDescriptor()); + pad_client_sockets[sock->socketDescriptor()]=sock; SendState(sock->socketDescriptor()); // printf("client connection %d opened\n",sock->socketDescriptor()); @@ -129,9 +129,9 @@ void MainObject::clientDisconnected(int id) { QTcpSocket *sock=NULL; - if((sock=rlm_client_sockets.value(id))!=NULL) { + if((sock=pad_client_sockets.value(id))!=NULL) { sock->deleteLater(); - rlm_client_sockets.remove(id); + pad_client_sockets.remove(id); // printf("client connection %d closed\n",id); } else { @@ -142,19 +142,19 @@ void MainObject::clientDisconnected(int id) void MainObject::newSourceConnectionData() { - QTcpSocket *sock=rlm_source_server->nextPendingConnection(); + QTcpSocket *sock=pad_source_server->nextPendingConnection(); if(sock==NULL) { - fprintf(stderr,"rdrlmd: UNIX socket error [%s]\n", - (const char *)rlm_source_server->errorString().toUtf8()); + fprintf(stderr,"rdpadd: UNIX socket error [%s]\n", + (const char *)pad_source_server->errorString().toUtf8()); exit(1); } - connect(sock,SIGNAL(readyRead()),rlm_source_ready_mapper,SLOT(map())); - rlm_source_ready_mapper->setMapping(sock,sock->socketDescriptor()); + connect(sock,SIGNAL(readyRead()),pad_source_ready_mapper,SLOT(map())); + pad_source_ready_mapper->setMapping(sock,sock->socketDescriptor()); - connect(sock,SIGNAL(disconnected()),rlm_source_disconnect_mapper,SLOT(map())); - rlm_source_disconnect_mapper->setMapping(sock,sock->socketDescriptor()); + connect(sock,SIGNAL(disconnected()),pad_source_disconnect_mapper,SLOT(map())); + pad_source_disconnect_mapper->setMapping(sock,sock->socketDescriptor()); - rlm_sources[sock->socketDescriptor()]=new MetadataSource(sock); + pad_sources[sock->socketDescriptor()]=new MetadataSource(sock); // printf("source connection %d opened\n",sock->socketDescriptor()); } @@ -162,11 +162,11 @@ void MainObject::newSourceConnectionData() void MainObject::sourceReadyReadData(int id) { - if(rlm_sources[id]!=NULL) { - if(rlm_sources[id]->appendBuffer(rlm_sources[id]->socket()->readAll())) { - for(QMap::const_iterator it=rlm_client_sockets.begin(); - it!=rlm_client_sockets.end();it++) { - it.value()->write(rlm_sources[id]->buffer()); + if(pad_sources[id]!=NULL) { + if(pad_sources[id]->appendBuffer(pad_sources[id]->socket()->readAll())) { + for(QMap::const_iterator it=pad_client_sockets.begin(); + it!=pad_client_sockets.end();it++) { + it.value()->write(pad_sources[id]->buffer()); } } } @@ -175,10 +175,10 @@ void MainObject::sourceReadyReadData(int id) void MainObject::sourceDisconnected(int id) { - if(rlm_sources.value(id)!=NULL) { - rlm_sources.value(id)->socket()->deleteLater(); - delete rlm_sources.value(id); - rlm_sources.remove(id); + if(pad_sources.value(id)!=NULL) { + pad_sources.value(id)->socket()->deleteLater(); + delete pad_sources.value(id); + pad_sources.remove(id); // printf("source connection %d closed\n",id); } else { @@ -189,10 +189,10 @@ void MainObject::sourceDisconnected(int id) void MainObject::SendState(int id) { - for(QMap::const_iterator it=rlm_sources.begin(); - it!=rlm_sources.end();it++) { + for(QMap::const_iterator it=pad_sources.begin(); + it!=pad_sources.end();it++) { if(it.value()->isCommitted()) { - rlm_client_sockets.value(id)->write(it.value()->buffer()); + pad_client_sockets.value(id)->write(it.value()->buffer()); } } } diff --git a/rdrlmd/rdrlmd.h b/rdpadd/rdpadd.h similarity index 77% rename from rdrlmd/rdrlmd.h rename to rdpadd/rdpadd.h index 11a046c6..cf4d03df 100644 --- a/rdrlmd/rdrlmd.h +++ b/rdpadd/rdpadd.h @@ -1,6 +1,6 @@ -// rdrlmd.h +// rdpadd.h // -// Rivendell RLM Consolidation Server +// Rivendell PAD Consolidation Server // // (C) Copyright 2018 Fred Gleason // @@ -18,8 +18,8 @@ // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // -#ifndef RDRLMD_H -#define RDRLMD_H +#ifndef RDPADD_H +#define RDPADD_H #include #include @@ -29,7 +29,7 @@ #include -#define RDRLMD_USAGE "\n\n" +#define RDPADD_USAGE "\n\n" class MetadataSource { @@ -64,15 +64,15 @@ class MainObject : public QObject private: void SendState(int id); - QSignalMapper *rlm_client_disconnect_mapper; - QTcpServer *rlm_client_server; - QMap rlm_client_sockets; + QSignalMapper *pad_client_disconnect_mapper; + QTcpServer *pad_client_server; + QMap pad_client_sockets; - QSignalMapper *rlm_source_ready_mapper; - QSignalMapper *rlm_source_disconnect_mapper; - RDUnixServer *rlm_source_server; - QMap rlm_sources; + QSignalMapper *pad_source_ready_mapper; + QSignalMapper *pad_source_disconnect_mapper; + RDUnixServer *pad_source_server; + QMap pad_sources; }; -#endif // RDRLMD_H +#endif // RDPADD_H diff --git a/rdservice/rdservice.h b/rdservice/rdservice.h index d07400b8..5359dfb3 100644 --- a/rdservice/rdservice.h +++ b/rdservice/rdservice.h @@ -31,7 +31,7 @@ #define RDSERVICE_CAED_ID 0 #define RDSERVICE_RIPCD_ID 1 #define RDSERVICE_RDCATCHD_ID 2 -#define RDSERVICE_RDRLMD_ID 3 +#define RDSERVICE_RDPADD_ID 3 #define RDSERVICE_RDVAIRPLAYD_ID 4 #define RDSERVICE_RDREPLD_ID 5 #define RDSERVICE_LOCALMAINT_ID 6 diff --git a/rdservice/startup.cpp b/rdservice/startup.cpp index e76448cc..f56bedf3 100644 --- a/rdservice/startup.cpp +++ b/rdservice/startup.cpp @@ -41,7 +41,7 @@ bool MainObject::Startup(QString *err_msg) // KillProgram("rdrepld"); KillProgram("rdvairplayd"); - KillProgram("rdrlmd"); + KillProgram("rdpadd"); KillProgram("rdcatchd"); KillProgram("ripcd"); KillProgram("caed"); @@ -85,15 +85,15 @@ bool MainObject::Startup(QString *err_msg) } // - // rdrlmd(8) + // rdpadd(8) // - svc_processes[RDSERVICE_RDRLMD_ID]=new Process(RDSERVICE_RDRLMD_ID,this); + svc_processes[RDSERVICE_RDPADD_ID]=new Process(RDSERVICE_RDPADD_ID,this); args.clear(); - svc_processes[RDSERVICE_RDRLMD_ID]-> - start(QString(RD_PREFIX)+"/sbin/rdrlmd",args); - if(!svc_processes[RDSERVICE_RDRLMD_ID]->process()->waitForStarted(-1)) { - *err_msg=tr("unable to start rdrlmd(8)")+": "+ - svc_processes[RDSERVICE_RDRLMD_ID]->errorText(); + svc_processes[RDSERVICE_RDPADD_ID]-> + start(QString(RD_PREFIX)+"/sbin/rdpadd",args); + if(!svc_processes[RDSERVICE_RDPADD_ID]->process()->waitForStarted(-1)) { + *err_msg=tr("unable to start rdpadd(8)")+": "+ + svc_processes[RDSERVICE_RDPADD_ID]->errorText(); return false; }