2018-12-20 Fred Gleason <fredg@paravelsystems.com>

* Added a 'PyPAD.Update::startDateTimeString()' method.
	* Added a 'pypad_spinitron.py' PyPAD script.
	* Removed the 'rlm_spinitron_plus' RLM.
This commit is contained in:
Fred Gleason
2018-12-20 10:29:56 -05:00
parent eae618e464
commit 3bf849a8a1
7 changed files with 285 additions and 659 deletions

View File

@@ -26,6 +26,10 @@ install-exec-am:
cp pypad_filewrite.exemplar $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_filewrite.exemplar
../../../helpers/install_python.sh pypad_live365.py $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_live365.py
cp pypad_live365.exemplar $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_live365.exemplar
../../../helpers/install_python.sh pypad_spinitron.py $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_spinitron.py
cp pypad_spinitron.exemplar $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_spinitron.exemplar
../../../helpers/install_python.sh pypad_udp.py $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_udp.py
cp pypad_udp.exemplar $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_udp.exemplar
../../../helpers/install_python.sh pypad_urlwrite.py $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_urlwrite.py
@@ -38,6 +42,8 @@ uninstall-local:
rm -f $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_filewrite.py
rm -f $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_live365.exemplar
rm -f $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_live365.py
rm -f $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_spinitron.exemplar
rm -f $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_spinitron.py
rm -f $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_udp.exemplar
rm -f $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_udp.py
rm -f $(DESTDIR)$(prefix)/@RD_LIB_PATH@/rivendell/PyPAD/pypad_urlwrite.exemplar
@@ -49,6 +55,8 @@ EXTRA_DIST = pypad_filewrite.exemplar\
pypad_filewrite.py\
pypad_live365.exemplar\
pypad_live365.py\
pypad_spinitron.exemplar\
pypad_spinitron.py\
pypad_udp.exemplar\
pypad_udp.py\
pypad_urlwrite.exemplar\

View File

@@ -0,0 +1,132 @@
; This is the configuration for the 'pypad_spinitron' script
; for Rivendell, which can be used log Now & Next data to the Spinitron
; online playlist service [http://www.spinitron.com].
; Section Header
;
; One section per Spinitron account is configured, starting with
; 'Spinitron1' and working up consecutively
[Spinitron1]
; APIKey
;
; API key for the Spinitron v2 account to which to log the play-out.
; (This setting is only needed for Spinitron major version 2).
APIKey=change_me_please
; PlaylistMode
;
; Set the Spinitron playlist mode to use when sending updates.
;
; (For a discussion of the implications of this setting on your
; Spinitron playlists, see Section 3.2 of the 'Spinitron Automation
; Integration' document, available from Spinitron).
;
; The following options are recognized:
;
; Full - Always use the Spinitron 'Full Automation' mode.
; Assist - Always use the Spinitron 'Live Assist' mode.
; Follow - Use the Spinitron 'Full Automation' mode when RDAirPlay
; is in Automatic, otherwise use the Spinitron 'Live Assist' mode.
PlaylistMode=Follow
; Title. The string to be sent as the 'Title' field for each update,
; including any wildcards as placeholders for metadata values. For the
; list of supported wildcards. see the 'Metadata Wildcards' section of the
; Rivendell Operations Guide.
Title=%t
; Artist. The string to be sent as the 'Artist' field for each update,
; including any wildcards as placeholders for metadata values.
Artist=%a
; Album. The string to be sent as the 'Album' field for each update,
; including any wildcards as placeholders for metadata values.
Album=%l
; Label. The string to be sent as the 'Label' field for each update,
; including any wildcards as placeholders for metadata values.
Label=%b
; Composer. The string to be sent as the 'Composer' field for each update,
; including any wildcards as placeholders for metadata values.
Composer=%m
; Conductor. The string to be sent as the 'Conductor' field for each update,
; including any wildcards as placeholders for metadata values.
Conductor=%r
; Notes. The string to be sent as the 'Notes' field for each update,
; including any wildcards as placeholders for metadata values.
Notes=%u
; Log Selection
;
; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether
; state changes on that log should be output to this account. If set
; to 'Onair', then output will be generated only if RDAirPlays OnAir flag
; is active.
MasterLog=Yes
Aux1Log=Yes
Aux2Log=Yes
VLog101=No
VLog102=No
VLog103=No
VLog104=No
VLog105=No
VLog106=No
VLog107=No
VLog108=No
VLog109=No
VLog110=No
VLog111=No
VLog112=No
VLog113=No
VLog114=No
VLog115=No
VLog116=No
VLog117=No
VLog118=No
VLog119=No
VLog120=No
; Additional Spinitron instances can be configured by adding new
; sections...
;
;[Spinitron2]
;MajorVersion=2
;Station=abcd
;Username=metoo
;Password=letmein
;APIKey=some_different_key
;Title=%t
;Artist=%a
;Album=%l
;Label=%b
;Composer=%m
;Conductor=%r
;Notes=%u
;MasterLog=Yes
;Aux1Log=No
;Aux2Log=Onair
;VLog101=No
;VLog102=No
;VLog103=No
;VLog104=No
;VLog105=No
;VLog106=No
;VLog107=No
;VLog108=No
;VLog109=No
;VLog110=No
;VLog111=No
;VLog112=No
;VLog113=No
;VLog114=No
;VLog115=No
;VLog116=No
;VLog117=No
;VLog118=No
;VLog119=No
;VLog120=No

View File

@@ -0,0 +1,128 @@
#!%PYTHON_BANGPATH%
# pypad_spinitron.py
#
# Write PAD updates to the Spinitron Playlist Service
#
# (C) Copyright 2018 Fred Gleason <fredg@paravelsystems.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import sys
import syslog
import configparser
import pycurl
import PyPAD
from io import BytesIO
last_updates={}
def eprint(*args,**kwargs):
print(*args,file=sys.stderr,**kwargs)
def JsonField(update,tag,value,is_last=False):
if (value==None) or (value==''):
ret=' "'+tag+'": null'
else:
ret=' "'+tag+'": "'+update.escape(value,PyPAD.ESCAPE_JSON)+'"'
if not is_last:
ret+=','
return ret+'\r\n'
def ProcessPad(update):
try:
last_updates[update.machine()]
except KeyError:
last_updates[update.machine()]=None
n=1
try:
while(True):
section='Spinitron'+str(n)
if update.shouldBeProcessed(section) and update.hasPadType(PyPAD.TYPE_NOW) and (last_updates[update.machine()] != update.startDateTimeString(PyPAD.TYPE_NOW)):
last_updates[update.machine()]=update.startDateTimeString(PyPAD.TYPE_NOW)
title=update.resolvePadFields(update.config().get(section,'Title'),PyPAD.ESCAPE_JSON)
artist=update.resolvePadFields(update.config().get(section,'Artist'),PyPAD.ESCAPE_JSON)
album=update.resolvePadFields(update.config().get(section,'Album'),PyPAD.ESCAPE_JSON)
label=update.resolvePadFields(update.config().get(section,'Label'),PyPAD.ESCAPE_JSON)
composer=update.resolvePadFields(update.config().get(section,'Composer'),PyPAD.ESCAPE_JSON)
conductor=update.resolvePadFields(update.config().get(section,'Conductor'),PyPAD.ESCAPE_JSON)
notes=update.resolvePadFields(update.config().get(section,'Notes'),PyPAD.ESCAPE_JSON)
json='{\r\n'
pmode=update.config().get(section,'PlaylistMode')
if pmode=='Full':
json+=' "live": false\r\n'
if pmode=='Assist':
json+=' "live:" true\r\n'
if pmode=='Follow':
if update.mode()=='Automatic':
json+=' "live": false,\r\n'
else:
json+=' "live": true,\r\n'
duration=str(update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_LENGTH)//1000)
year=update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_YEAR)
if year==None:
json+=' "released": null,\r\n'
else:
json+=' "released": '+str(year)+',\r\n'
json+=' "duration": '+duration+',\r\n'
json+=JsonField(update,'artist',artist)
json+=JsonField(update,'release',album)
json+=JsonField(update,'label',label)
json+=JsonField(update,'song',title)
json+=JsonField(update,'composer',composer)
json+=JsonField(update,'conductor',conductor)
json+=JsonField(update,'note',notes)
json+=JsonField(update,'isrc',update.padField(PyPAD.TYPE_NOW,PyPAD.FIELD_ISRC),True)
json+='}\r\n'
send_buf=BytesIO(json.encode('utf-8'))
recv_buf=BytesIO()
curl=pycurl.Curl()
curl.setopt(curl.URL,'https://spinitron.com/api/spins')
headers=[]
headers.append('Authorization: Bearer '+update.config().get(section,'APIKey'))
headers.append('Content-Type: application/json')
headers.append('Content-Length: '+str(len(json.encode('utf-8'))))
curl.setopt(curl.HTTPHEADER,headers);
curl.setopt(curl.POST,True)
curl.setopt(curl.READDATA,send_buf)
curl.setopt(curl.WRITEDATA,recv_buf)
try:
curl.perform()
code=curl.getinfo(pycurl.RESPONSE_CODE)
if (code<200) or (code>=300):
syslog.syslog(syslog.LOG_WARNING,'['+section+'] returned response code '+str(code))
except pycurl.error:
syslog.syslog(syslog.LOG_WARNING,'['+section+'] failed: '+curl.errstr())
curl.close()
n=n+1
except configparser.NoSectionError:
return
#
# 'Main' function
#
syslog.openlog(sys.argv[0].split('/')[-1])
rcvr=PyPAD.Receiver()
try:
rcvr.setConfigFile(sys.argv[3])
except IndexError:
eprint('pypad_spinitron.py: you must specify a configuration file')
sys.exit(1)
rcvr.setCallback(ProcessPad)
rcvr.start(sys.argv[1],int(sys.argv[2]))