mirror of
https://github.com/ElvishArtisan/rivendell.git
synced 2025-10-30 17:23:53 +01:00
2018-12-07 Fred Gleason <fredg@paravelsystems.com>
* Changed the Python namespace of the PyPAD classes from 'rivendell.PyPAD' to 'PyPAD'. * Renamed the 'PyPAD.PyPADReceiver' class to 'PyPAD.Receiver'. * Renamed the 'PyPAD.PyPADUpdate' class to 'PyPAD.Update'. * Added a 'port' argument to the 'PyPAD.Receiver::start()' method. * Added an 'escaping' argument to the 'PyPAD.Update::padFields()' method. * Added support for the 'Encoding=' directive to the 'pypad_udp.py' script.
This commit is contained in:
@@ -20,9 +20,8 @@
|
||||
##
|
||||
## Use automake to process this into a Makefile.in
|
||||
|
||||
rivendelldir = $(pkgpyexecdir)
|
||||
rivendell_PYTHON = __init__.py\
|
||||
PyPAD.py
|
||||
rivendelldir = $(pyexecdir)
|
||||
rivendell_PYTHON = PyPAD.py
|
||||
|
||||
CLEANFILES = *~\
|
||||
*.idb\
|
||||
|
||||
@@ -23,31 +23,96 @@
|
||||
import socket
|
||||
import json
|
||||
|
||||
class PyPADUpdate(object):
|
||||
#
|
||||
# Enumerated Constants (sort of)
|
||||
#
|
||||
# Escape types
|
||||
#
|
||||
ESCAPE_NONE=0
|
||||
ESCAPE_XML=1
|
||||
ESCAPE_URL=2
|
||||
ESCAPE_JSON=3
|
||||
|
||||
#
|
||||
# Default TCP port for connecting to Rivendell's PAD service
|
||||
#
|
||||
PAD_TCP_PORT=34289
|
||||
|
||||
class Update(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,'')
|
||||
def __escapeXml(self,string):
|
||||
string=string.replace("&","&")
|
||||
string=string.replace("<","<")
|
||||
string=string.replace(">",">")
|
||||
string=string.replace("'","'")
|
||||
string=string.replace("\"",""")
|
||||
return string
|
||||
|
||||
def __escapeWeb(self,string):
|
||||
string=string.replace("%","%25")
|
||||
string=string.replace(" ","%20")
|
||||
string=string.replace("<","%3C")
|
||||
string=string.replace(">","%3E")
|
||||
string=string.replace("#","%23")
|
||||
string=string.replace("\"","%22")
|
||||
string=string.replace("{","%7B")
|
||||
string=string.replace("}","%7D")
|
||||
string=string.replace("|","%7C")
|
||||
string=string.replace("\\","%5C")
|
||||
string=string.replace("^","%5E")
|
||||
string=string.replace("[","%5B")
|
||||
string=string.replace("]","%5D")
|
||||
string=string.replace("`","%60")
|
||||
string=string.replace("\a","%07")
|
||||
string=string.replace("\b","%08")
|
||||
string=string.replace("\f","%0C")
|
||||
string=string.replace("\n","%0A")
|
||||
string=string.replace("\r","%0D")
|
||||
string=string.replace("\t","%09")
|
||||
string=string.replace("\v","%0B")
|
||||
return string
|
||||
|
||||
def __escapeJson(self,string):
|
||||
string=string.replace("\\","\\\\")
|
||||
string=string.replace("\"","\\\"")
|
||||
string=string.replace("/","\\/")
|
||||
string=string.replace("\b","\\b")
|
||||
string=string.replace("\f","\\f")
|
||||
string=string.replace("\n","\\n")
|
||||
string=string.replace("\r","\\r")
|
||||
string=string.replace("\t","\\t")
|
||||
return string
|
||||
|
||||
def __escape(self,string,escaping):
|
||||
if(escaping==0):
|
||||
return string
|
||||
if(escaping==1):
|
||||
return self.__escapeXml(string)
|
||||
if(escaping==2):
|
||||
return self.__escapeWeb(string)
|
||||
if(escaping==3):
|
||||
return self.__escapeJson(string)
|
||||
raise ValueError('invalid escaping value')
|
||||
|
||||
def __replaceWildcard(self,wildcard,sfield,stype,string,escaping):
|
||||
try:
|
||||
if isinstance(self.__fields['padUpdate'][stype][sfield],unicode):
|
||||
string=string.replace('%'+wildcard,self.__escape(self.__fields['padUpdate'][stype][sfield],escaping))
|
||||
else:
|
||||
string=string.replace('%'+wildcard,str(self.__fields['padUpdate'][stype][sfield]))
|
||||
except TypeError:
|
||||
string=string.replace('%'+wildcard,'')
|
||||
except KeyError:
|
||||
string=string.replace('%'+wildcard,'')
|
||||
return string
|
||||
|
||||
def __replaceWildcardPair(self,wildcard,sfield,string,escaping):
|
||||
string=self.__replaceWildcard(wildcard,sfield,'now',string,escaping);
|
||||
string=self.__replaceWildcard(wildcard.upper(),sfield,'next',string,escaping);
|
||||
return string;
|
||||
|
||||
def dateTime(self):
|
||||
"""
|
||||
Returns the date-time stamp of the update in RFC-822 format (string).
|
||||
@@ -113,21 +178,55 @@ class PyPADUpdate(object):
|
||||
"""
|
||||
return self.__fields['padUpdate']['log']['name']
|
||||
|
||||
def padFields(self,string):
|
||||
def padFields(self,string,escaping):
|
||||
"""
|
||||
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.
|
||||
Takes two arguments:
|
||||
|
||||
string - 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.
|
||||
|
||||
escaping - Character escaping to be applied to the PAD fields.
|
||||
Must be one of the following:
|
||||
|
||||
PyPAD.ESCAPE_NONE - No escaping
|
||||
PyPAD.ESCAPE_XML - "XML" escaping: Escape reserved
|
||||
characters as per XML-v1.0
|
||||
PyPAD.ESCAPE_URL - "URL" escaping: Escape reserved
|
||||
characters as per RFC 2396
|
||||
Section 2.4
|
||||
PyPAD.ESCAPE_JSON - "JSON" escaping: Escape reserved
|
||||
characters as per ECMA-404.
|
||||
"""
|
||||
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)
|
||||
string=self.__replaceWildcardPair('a','artist',string,escaping)
|
||||
string=self.__replaceWildcardPair('b','label',string,escaping)
|
||||
string=self.__replaceWildcardPair('c','client',string,escaping)
|
||||
# DateTime
|
||||
#string=self.__replaceWildcardPair('d',sfield,string,escaping)
|
||||
string=self.__replaceWildcardPair('e','agency',string,escaping)
|
||||
# Unassigned
|
||||
#string=self.__replaceWildcardPair('f',sfield,string,escaping) # Unassigned
|
||||
string=self.__replaceWildcardPair('g','groupName',string,escaping)
|
||||
string=self.__replaceWildcardPair('h','length',string,escaping)
|
||||
string=self.__replaceWildcardPair('i','description',string,escaping)
|
||||
string=self.__replaceWildcardPair('j','cutNumber',string,escaping)
|
||||
#string=self.__replaceWildcardPair('k',sfield,string,escaping) # Start time for rdimport
|
||||
string=self.__replaceWildcardPair('l','album',string,escaping)
|
||||
string=self.__replaceWildcardPair('m','composer',string,escaping)
|
||||
string=self.__replaceWildcardPair('n','cartNumber',string,escaping)
|
||||
string=self.__replaceWildcardPair('o','outcue',string,escaping)
|
||||
string=self.__replaceWildcardPair('p','publisher',string,escaping)
|
||||
#string=self.__replaceWildcardPair('q',sfield,string,escaping) # Start date for rdimport
|
||||
string=self.__replaceWildcardPair('r','conductor',string,escaping)
|
||||
string=self.__replaceWildcardPair('s','songId',string,escaping)
|
||||
string=self.__replaceWildcardPair('t','title',string,escaping)
|
||||
string=self.__replaceWildcardPair('u','userDefined',string,escaping)
|
||||
#string=self.__replaceWildcardPair('v',sfield,string,escaping) # Length, rounded down
|
||||
#string=self.__replaceWildcardPair('w',sfield,string,escaping) # Unassigned
|
||||
#string=self.__replaceWildcardPair('x',sfield,string,escaping) # Unassigned
|
||||
string=self.__replaceWildcardPair('y','year',string,escaping)
|
||||
#string=self.__replaceWildcardPair('z',sfield,string,escaping) # Unassigned
|
||||
string=string.replace('\\b','\b')
|
||||
string=string.replace('\\f','\f')
|
||||
string=string.replace('\\n','\n')
|
||||
@@ -154,7 +253,7 @@ class PyPADUpdate(object):
|
||||
return False;
|
||||
|
||||
|
||||
class PyPADReceiver(object):
|
||||
class Receiver(object):
|
||||
def __init__(self):
|
||||
self.__callback=None
|
||||
|
||||
@@ -167,17 +266,20 @@ class PyPADReceiver(object):
|
||||
"""
|
||||
self.__callback=cb
|
||||
|
||||
def start(self,hostname):
|
||||
def start(self,hostname,port):
|
||||
"""
|
||||
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:
|
||||
Takes the following arguments:
|
||||
|
||||
hostname: The hostname or IP address of the Rivendell system.
|
||||
hostname - The hostname or IP address of the Rivendell system.
|
||||
|
||||
port - The TCP port to connect to. For most cases, just use
|
||||
'PyPAD.PAD_TCP_PORT'.
|
||||
"""
|
||||
sock=socket.socket(socket.AF_INET)
|
||||
conn=sock.connect((hostname,34289))
|
||||
conn=sock.connect((hostname,port))
|
||||
c=""
|
||||
line=""
|
||||
msg=""
|
||||
@@ -188,7 +290,7 @@ class PyPADReceiver(object):
|
||||
if c[0]=="\n":
|
||||
msg+=line
|
||||
if line=="\r\n":
|
||||
self.__PyPAD_Process(PyPADUpdate(json.loads(msg)))
|
||||
self.__PyPAD_Process(Update(json.loads(msg)))
|
||||
msg=""
|
||||
line=""
|
||||
|
||||
|
||||
@@ -24,31 +24,31 @@
|
||||
# To see the full documentation of these classes, enter the following at
|
||||
# a python interactive prompt:
|
||||
#
|
||||
# import rivendell.PyPAD
|
||||
# help(rivendell.PyPAD)
|
||||
# import PyPAD
|
||||
# help(PyPAD)
|
||||
#
|
||||
import rivendell.PyPAD
|
||||
import PyPAD
|
||||
|
||||
#
|
||||
# First, we create a callback method, that will be called every time a
|
||||
# log machine updates its PAD. An instance of 'PyPADUpdate' that contains
|
||||
# log machine updates its PAD. An instance of 'PyPAD.Update' that contains
|
||||
# the PAD information is supplied as the single argument.
|
||||
#
|
||||
def ProcessPad(update):
|
||||
print
|
||||
if update.hasNowPad():
|
||||
print "Log %03d NOW: " % update.logMachine()+update.padFields("%a - %t")
|
||||
print "Log %03d NOW: " % update.logMachine()+update.padFields("%a - %t",PyPAD.ESCAPE_NONE)
|
||||
else:
|
||||
print "Log %03d NOW: [none]" % update.logMachine()
|
||||
if update.hasNextPad():
|
||||
print "Log %03d NEXT: " % update.logMachine()+update.padFields("%A - %T")
|
||||
print "Log %03d NEXT: " % update.logMachine()+update.padFields("%A - %T",PyPAD.ESCAPE_NONE)
|
||||
else:
|
||||
print "Log %03d NEXT: [none]" % update.logMachine()
|
||||
|
||||
#
|
||||
# Create an instance of 'PyPADReceiver'
|
||||
#
|
||||
rcvr=rivendell.PyPAD.PyPADReceiver()
|
||||
rcvr=PyPAD.Receiver()
|
||||
|
||||
#
|
||||
# Tell it to use the callback
|
||||
@@ -56,8 +56,8 @@ rcvr=rivendell.PyPAD.PyPADReceiver()
|
||||
rcvr.setCallback(ProcessPad)
|
||||
|
||||
#
|
||||
# Start the receiver, giving it the hostname or IP address of the target
|
||||
# Rivendell system. Once started, all further processing can only be done
|
||||
# in the callback method!
|
||||
# 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")
|
||||
rcvr.start("localhost",PyPAD.PAD_TCP_PORT)
|
||||
|
||||
@@ -25,7 +25,7 @@ from __future__ import print_function
|
||||
import sys
|
||||
import socket
|
||||
import ConfigParser
|
||||
import rivendell.PyPAD
|
||||
import PyPAD
|
||||
|
||||
def eprint(*args,**kwargs):
|
||||
print(*args,file=sys.stderr,**kwargs)
|
||||
@@ -36,7 +36,7 @@ def ProcessPad(update):
|
||||
section='Udp'+str(n)
|
||||
try:
|
||||
format=config.get(section,'FormatString')
|
||||
send_sock.sendto(update.padFields(format),
|
||||
send_sock.sendto(update.padFields(format,int(config.get(section,'Encoding'))),
|
||||
(config.get(section,'IpAddress'),int(config.get(section,'UdpPort'))))
|
||||
n=n+1
|
||||
except ConfigParser.NoSectionError:
|
||||
@@ -59,6 +59,6 @@ else:
|
||||
#
|
||||
send_sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
|
||||
|
||||
rcvr=rivendell.PyPAD.PyPADReceiver()
|
||||
rcvr=PyPAD.Receiver()
|
||||
rcvr.setCallback(ProcessPad)
|
||||
rcvr.start("localhost")
|
||||
rcvr.start("localhost",PyPAD.PAD_TCP_PORT)
|
||||
|
||||
Reference in New Issue
Block a user