Merge branch 'master' of dev.sourcefabric.org:campcaster
This commit is contained in:
commit
42598d03b4
15 changed files with 148 additions and 2680 deletions
28
INSTALL
28
INSTALL
|
@ -1,29 +1,23 @@
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
Copyright (c) 2010 Sourcefabric O.P.S.
|
Copyright (c) 2010-2011 Sourcefabric O.P.S.
|
||||||
|
|
||||||
This file is part of the Airtime project.
|
This file is part of the Airtime project.
|
||||||
http://airtime.sourcefabric.org/
|
http://airtime.sourcefabric.org/
|
||||||
To report bugs, send an e-mail to contact@sourcefabric.org
|
|
||||||
|
To report bugs, visit our bug tracker at:
|
||||||
|
http://dev.sourcefabric.org/browse/CC
|
||||||
|
|
||||||
Airtime is free software; you can redistribute it and/or modify
|
Visit our community support forum here:
|
||||||
it under the terms of the GNU General Public License as published by
|
http://forum.sourcefabric.org/index.php/f/14/
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
For commercial support, see http://sourcefabric.org/en/services/about/347/Support.htm
|
||||||
|
or send an e-mail to contact@sourcefabric.org
|
||||||
Airtime 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 Airtime; if not, write to the Free Software
|
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
Please see this page for a typical user install:
|
Please see this page for install instructions:
|
||||||
http://www.sourcefabric.org/en/products/airtime_manuals/
|
http://wiki.sourcefabric.org/display/CC/Installing+Airtime+%28v1.6%29
|
||||||
|
|
||||||
If you are a developer, see this page:
|
If you are a developer, see this page:
|
||||||
http://wiki.sourcefabric.org/display/CC
|
http://wiki.sourcefabric.org/display/CC
|
||||||
|
|
|
@ -1,37 +1,72 @@
|
||||||
This application uses the following 3rd Party software:
|
This application uses the following 3rd Party software:
|
||||||
|
|
||||||
* Zend Framework
|
------------
|
||||||
|
Linked code:
|
||||||
|
------------
|
||||||
|
* Zend Framework 1.10.3
|
||||||
|
- Web site: http://framework.zend.com/
|
||||||
- License: New BSD license
|
- License: New BSD license
|
||||||
- Does this link with our code? Yes
|
|
||||||
- Compatible with GPLv3: Yes
|
- Compatible with GPLv3: Yes
|
||||||
|
|
||||||
* Liquidsoap
|
|
||||||
- License: GPLv2
|
|
||||||
- Does this link with our code? No, we only call this as an executable
|
|
||||||
|
|
||||||
* PEAR
|
* PEAR
|
||||||
- Notes: We only use the PEAR base class PEAR_Error, in the "PEAR" PEAR library.
|
- Notes: We only use the PEAR base class PEAR_Error, in the "PEAR" PEAR library.
|
||||||
- License: New BSD License
|
- License: New BSD License
|
||||||
- Does this link with our code? Yes
|
|
||||||
- Compatible with GPLv3? Yes.
|
- Compatible with GPLv3? Yes.
|
||||||
|
|
||||||
* GetID3
|
* GetID3
|
||||||
|
- Web site: http://getid3.sourceforge.net/
|
||||||
- License: GPLv2
|
- License: GPLv2
|
||||||
- Does this link with our code? Yes
|
|
||||||
- Compatible with GPLv3? Yes
|
- Compatible with GPLv3? Yes
|
||||||
|
|
||||||
* mp3cut from the package poc-streamer
|
|
||||||
- Does this link with our code? No, it is an externally called executable file.
|
|
||||||
|
|
||||||
* PHP
|
|
||||||
- Does this link with our code? No, it is the interpreter.
|
|
||||||
|
|
||||||
* Propel ORM
|
* Propel ORM
|
||||||
|
- Web site: http://www.propelorm.org/
|
||||||
- License: MIT/Expat License
|
- License: MIT/Expat License
|
||||||
- Does this link with our code? Yes
|
|
||||||
- Compatible with the GPL: Yes. See http://www.gnu.org/licenses/license-list.html
|
- Compatible with the GPL: Yes. See http://www.gnu.org/licenses/license-list.html
|
||||||
|
|
||||||
* Phing
|
* Phing
|
||||||
|
- Web site: http://phing.info/trac/
|
||||||
- Note: Only used for development, not needed to run Airtime.
|
- Note: Only used for development, not needed to run Airtime.
|
||||||
- License: LGPLv3
|
- License: LGPLv3
|
||||||
|
|
||||||
|
----------------
|
||||||
|
Non-linked code:
|
||||||
|
----------------
|
||||||
|
* Linux
|
||||||
|
|
||||||
|
* Apache Web Server 2.2
|
||||||
|
- Web site: http://httpd.apache.org/
|
||||||
|
|
||||||
|
* PostgreSQL 8.4
|
||||||
|
- Web site: http://www.postgresql.org/
|
||||||
|
- License: The PostgreSQL License. See http://www.opensource.org/licenses/postgresql
|
||||||
|
|
||||||
|
* PHP 5.3
|
||||||
|
- Web site: http://www.php.net/
|
||||||
|
- License: The PHP License. See http://www.php.net/license/3_01.txt
|
||||||
|
|
||||||
|
* Python 2.6
|
||||||
|
- Web site: http://www.python.org/
|
||||||
|
- License: PSF License. See http://docs.python.org/license.html
|
||||||
|
|
||||||
|
* Liquidsoap (pre-release of 1.0)
|
||||||
|
- Web site: http://savonet.sourceforge.net/
|
||||||
|
- License: GPLv2
|
||||||
|
|
||||||
|
* mp3cut from the package poc-streamer
|
||||||
|
|
||||||
|
* jQuery
|
||||||
|
- Web site: http://jquery.com/
|
||||||
|
- License: MIT and GPL. See http://jquery.org/license
|
||||||
|
|
||||||
|
- jQuery components used:
|
||||||
|
* Full Calendar
|
||||||
|
- Web site: http://arshaw.com/fullcalendar/
|
||||||
|
- License: Dual licensed under MIT and GPLv2
|
||||||
|
|
||||||
|
* Colorpicker
|
||||||
|
- Web site: http://www.eyecon.ro/colorpicker/
|
||||||
|
- License: Dual licensed under the MIT and GPL licenses.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import sys
|
||||||
import time
|
import time
|
||||||
import urllib
|
import urllib
|
||||||
import logging
|
import logging
|
||||||
from util import json
|
import json
|
||||||
import os
|
import os
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ class AirTimeApiClient(ApiClientInterface):
|
||||||
response = urllib.urlopen(url)
|
response = urllib.urlopen(url)
|
||||||
data = response.read()
|
data = response.read()
|
||||||
logger.debug("Data: %s", data)
|
logger.debug("Data: %s", data)
|
||||||
response_json = json.read(data)
|
response_json = json.loads(data)
|
||||||
version = response_json['version']
|
version = response_json['version']
|
||||||
logger.debug("Airtime Version %s detected", version)
|
logger.debug("Airtime Version %s detected", version)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
|
@ -223,7 +223,7 @@ class AirTimeApiClient(ApiClientInterface):
|
||||||
try:
|
try:
|
||||||
response_json = urllib.urlopen(export_url).read()
|
response_json = urllib.urlopen(export_url).read()
|
||||||
#logger.debug("%s", response_json)
|
#logger.debug("%s", response_json)
|
||||||
response = json.read(response_json)
|
response = json.loads(response_json)
|
||||||
#logger.info("export status %s", response['check'])
|
#logger.info("export status %s", response['check'])
|
||||||
status = response['check']
|
status = response['check']
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
|
@ -281,7 +281,7 @@ class AirTimeApiClient(ApiClientInterface):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = urllib.urlopen(url)
|
response = urllib.urlopen(url)
|
||||||
response = json.read(response.read())
|
response = json.loads(response.read())
|
||||||
logger.info("API-Status %s", response['status'])
|
logger.info("API-Status %s", response['status'])
|
||||||
logger.info("API-Message %s", response['message'])
|
logger.info("API-Message %s", response['message'])
|
||||||
|
|
||||||
|
@ -302,7 +302,7 @@ class AirTimeApiClient(ApiClientInterface):
|
||||||
if (data[0] != '{'):
|
if (data[0] != '{'):
|
||||||
return response
|
return response
|
||||||
try:
|
try:
|
||||||
data = json.read(data)
|
data = json.loads(data)
|
||||||
logger.debug(str(data))
|
logger.debug(str(data))
|
||||||
schedule_id = data["schedule_id"]
|
schedule_id = data["schedule_id"]
|
||||||
url = self.config["base_url"] + self.config["api_base"] + self.config["update_start_playing_url"]
|
url = self.config["base_url"] + self.config["api_base"] + self.config["update_start_playing_url"]
|
||||||
|
@ -311,7 +311,7 @@ class AirTimeApiClient(ApiClientInterface):
|
||||||
url = url.replace("%%api_key%%", self.config["api_key"])
|
url = url.replace("%%api_key%%", self.config["api_key"])
|
||||||
logger.debug(url)
|
logger.debug(url)
|
||||||
response = urllib.urlopen(url)
|
response = urllib.urlopen(url)
|
||||||
response = json.read(response.read())
|
response = json.loads(response.read())
|
||||||
logger.info("API-Status %s", response['status'])
|
logger.info("API-Status %s", response['status'])
|
||||||
logger.info("API-Message %s", response['message'])
|
logger.info("API-Message %s", response['message'])
|
||||||
|
|
||||||
|
@ -329,7 +329,7 @@ class AirTimeApiClient(ApiClientInterface):
|
||||||
#
|
#
|
||||||
#try:
|
#try:
|
||||||
# response = urllib.urlopen(url, self.api_auth)
|
# response = urllib.urlopen(url, self.api_auth)
|
||||||
# response = json.read(response.read())
|
# response = json.loads(response.read())
|
||||||
# logger.debug("Trying to contact %s", url)
|
# logger.debug("Trying to contact %s", url)
|
||||||
# logger.info("API-Status %s", response['status'])
|
# logger.info("API-Status %s", response['status'])
|
||||||
# logger.info("API-Message %s", response['message'])
|
# logger.info("API-Message %s", response['message'])
|
||||||
|
@ -349,7 +349,7 @@ class AirTimeApiClient(ApiClientInterface):
|
||||||
data["schedule_id"] = playlist['id']
|
data["schedule_id"] = playlist['id']
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
data["schedule_id"] = 0
|
data["schedule_id"] = 0
|
||||||
data = json.write(data)
|
data = json.dumps(data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
@ -404,7 +404,7 @@ class ObpApiClient():
|
||||||
try:
|
try:
|
||||||
logger.debug("Trying to contact %s", url)
|
logger.debug("Trying to contact %s", url)
|
||||||
response = urllib.urlopen(url, self.api_auth)
|
response = urllib.urlopen(url, self.api_auth)
|
||||||
response_json = json.read(response.read())
|
response_json = json.loads(response.read())
|
||||||
obp_version = int(response_json['version'])
|
obp_version = int(response_json['version'])
|
||||||
logger.debug("OBP Version %s detected", obp_version)
|
logger.debug("OBP Version %s detected", obp_version)
|
||||||
|
|
||||||
|
@ -471,7 +471,7 @@ class ObpApiClient():
|
||||||
try:
|
try:
|
||||||
response_json = urllib.urlopen(export_url).read()
|
response_json = urllib.urlopen(export_url).read()
|
||||||
logger.debug("%s", response_json)
|
logger.debug("%s", response_json)
|
||||||
response = json.read(response_json)
|
response = json.loads(response_json)
|
||||||
logger.info("export status %s", response['check'])
|
logger.info("export status %s", response['check'])
|
||||||
status = response['check']
|
status = response['check']
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
|
@ -502,7 +502,7 @@ class ObpApiClient():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = urllib.urlopen(url, self.api_auth)
|
response = urllib.urlopen(url, self.api_auth)
|
||||||
response = json.read(response.read())
|
response = json.loads(response.read())
|
||||||
logger.info("API-Status %s", response['status'])
|
logger.info("API-Status %s", response['status'])
|
||||||
logger.info("API-Message %s", response['message'])
|
logger.info("API-Message %s", response['message'])
|
||||||
|
|
||||||
|
@ -536,7 +536,7 @@ class ObpApiClient():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = urllib.urlopen(url, self.api_auth)
|
response = urllib.urlopen(url, self.api_auth)
|
||||||
response = json.read(response.read())
|
response = json.loads(response.read())
|
||||||
logger.info("API-Status %s", response['status'])
|
logger.info("API-Status %s", response['status'])
|
||||||
logger.info("API-Message %s", response['message'])
|
logger.info("API-Message %s", response['message'])
|
||||||
logger.info("TXT %s", response['str_dls'])
|
logger.info("TXT %s", response['str_dls'])
|
||||||
|
@ -556,7 +556,7 @@ class ObpApiClient():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = urllib.urlopen(url, self.api_auth)
|
response = urllib.urlopen(url, self.api_auth)
|
||||||
response = json.read(response.read())
|
response = json.loads(response.read())
|
||||||
logger.debug("Trying to contact %s", url)
|
logger.debug("Trying to contact %s", url)
|
||||||
logger.info("API-Status %s", response['status'])
|
logger.info("API-Status %s", response['status'])
|
||||||
logger.info("API-Message %s", response['message'])
|
logger.info("API-Message %s", response['message'])
|
||||||
|
@ -580,6 +580,6 @@ class ObpApiClient():
|
||||||
data["playlist_id"] = 0
|
data["playlist_id"] = 0
|
||||||
data["user_id"] = 0
|
data["user_id"] = 0
|
||||||
data["transmission_id"] = 0
|
data["transmission_id"] = 0
|
||||||
data = json.write(data)
|
data = json.dumps(data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@ import time
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from util import json
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
|
@ -87,4 +85,4 @@ class DlsClient():
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -62,8 +62,8 @@ def get_current_script_dir():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
current_script_dir = get_current_script_dir()
|
current_script_dir = get_current_script_dir()
|
||||||
print "Terminating any existing pypo processes"
|
print "Checking and removing any existing pypo processes"
|
||||||
os.system("python %s/pypo-stop.py"% current_script_dir)
|
os.system("python %s/pypo-uninstall.py 2>&1 1>/dev/null"% current_script_dir)
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
# Create users
|
# Create users
|
||||||
|
|
Binary file not shown.
Binary file not shown.
2053
pypo/ls_script.log
2053
pypo/ls_script.log
File diff suppressed because it is too large
Load diff
|
@ -19,12 +19,6 @@ Attention & ToDos
|
||||||
- liquidsoap does not like mono files! So we have to make sure that only files with
|
- liquidsoap does not like mono files! So we have to make sure that only files with
|
||||||
2 channels are fed to LiquidSoap
|
2 channels are fed to LiquidSoap
|
||||||
(solved: current = audio_to_stereo(current) - maybe not with ultimate performance)
|
(solved: current = audio_to_stereo(current) - maybe not with ultimate performance)
|
||||||
|
|
||||||
|
|
||||||
made for python version 2.5!!
|
|
||||||
should work with 2.6 as well with a bit of adaption. for
|
|
||||||
sure the json parsing has to be changed
|
|
||||||
(2.6 has an parser, pypo brings it's own -> util/json.py)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# python defaults (debian default)
|
# python defaults (debian default)
|
||||||
|
@ -296,17 +290,7 @@ class Playout:
|
||||||
|
|
||||||
elif int(playlist['subtype']) > 0 and int(playlist['subtype']) < 5:
|
elif int(playlist['subtype']) > 0 and int(playlist['subtype']) < 5:
|
||||||
ls_playlist = self.handle_media_file(playlist, pkey, ls_playlist)
|
ls_playlist = self.handle_media_file(playlist, pkey, ls_playlist)
|
||||||
|
|
||||||
"""
|
|
||||||
This is kind of hackish. We add a bunch of "silence" tracks to the end of each playlist.
|
|
||||||
So we can make sure the list does not get repeated just before a new one is called.
|
|
||||||
(or in case nothing is in the scheduler afterwards)
|
|
||||||
20 x silence = 10 hours
|
|
||||||
"""
|
|
||||||
for i in range (0, 1):
|
|
||||||
ls_playlist += self.silence_file + "\n"
|
|
||||||
print '',
|
|
||||||
|
|
||||||
# write playlist file
|
# write playlist file
|
||||||
plfile = open(self.cache_dir + str(pkey) + '/list.lsp', "w")
|
plfile = open(self.cache_dir + str(pkey) + '/list.lsp', "w")
|
||||||
plfile.write(ls_playlist)
|
plfile.write(ls_playlist)
|
||||||
|
@ -679,29 +663,12 @@ class Playout:
|
||||||
logger.debug('OK - Can read playlist file')
|
logger.debug('OK - Can read playlist file')
|
||||||
|
|
||||||
pl_file = open(src, "r")
|
pl_file = open(src, "r")
|
||||||
|
|
||||||
"""
|
|
||||||
i know this could be wrapped, maybe later..
|
|
||||||
"""
|
|
||||||
tn = telnetlib.Telnet(LS_HOST, 1234)
|
|
||||||
|
|
||||||
for line in pl_file.readlines():
|
|
||||||
line = line.strip()
|
|
||||||
logger.debug(line)
|
|
||||||
tn.write(self.export_source + '.push %s' % (line))
|
|
||||||
tn.write("\n")
|
|
||||||
|
|
||||||
tn.write("exit\n")
|
|
||||||
logger.debug(tn.read_all())
|
|
||||||
|
|
||||||
pattern = '%Y-%m-%d-%H-%M-%S'
|
|
||||||
|
|
||||||
#strptime returns struct_time in local time
|
#strptime returns struct_time in local time
|
||||||
#mktime takes a time_struct and returns a floating point
|
#mktime takes a time_struct and returns a floating point
|
||||||
#gmtime Convert a time expressed in seconds since the epoch to a struct_time in UTC
|
#gmtime Convert a time expressed in seconds since the epoch to a struct_time in UTC
|
||||||
|
|
||||||
#mktime: expresses the time in local time, not UTC. It returns a floating point number, for compatibility with time().
|
#mktime: expresses the time in local time, not UTC. It returns a floating point number, for compatibility with time().
|
||||||
epoch_start = calendar.timegm(time.gmtime(time.mktime(time.strptime(pkey, pattern))))
|
epoch_start = calendar.timegm(time.gmtime(time.mktime(time.strptime(pkey, '%Y-%m-%d-%H-%M-%S'))))
|
||||||
|
|
||||||
#Return the time as a floating point number expressed in seconds since the epoch, in UTC.
|
#Return the time as a floating point number expressed in seconds since the epoch, in UTC.
|
||||||
epoch_now = time.time()
|
epoch_now = time.time()
|
||||||
|
@ -717,8 +684,19 @@ class Playout:
|
||||||
|
|
||||||
logger.debug('sleeping for %s s' % (sleep_time))
|
logger.debug('sleeping for %s s' % (sleep_time))
|
||||||
time.sleep(sleep_time)
|
time.sleep(sleep_time)
|
||||||
|
|
||||||
|
tn = telnetlib.Telnet(LS_HOST, 1234)
|
||||||
|
|
||||||
|
for line in pl_file.readlines():
|
||||||
|
line = line.strip()
|
||||||
|
logger.debug(line)
|
||||||
|
tn.write('queue.push %s' % (line))
|
||||||
|
tn.write("\n")
|
||||||
|
|
||||||
|
tn.write("exit\n")
|
||||||
|
logger.debug(tn.read_all())
|
||||||
|
|
||||||
logger.debug('sending "flip"')
|
"""
|
||||||
tn = telnetlib.Telnet(LS_HOST, 1234)
|
tn = telnetlib.Telnet(LS_HOST, 1234)
|
||||||
|
|
||||||
# Get any extra information for liquidsoap (which will be sent back to us)
|
# Get any extra information for liquidsoap (which will be sent back to us)
|
||||||
|
@ -733,6 +711,7 @@ class Playout:
|
||||||
tn.write("exit\n")
|
tn.write("exit\n")
|
||||||
|
|
||||||
tn.read_all()
|
tn.read_all()
|
||||||
|
"""
|
||||||
status = 1
|
status = 1
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
logger.error('%s', e)
|
logger.error('%s', e)
|
||||||
|
|
|
@ -29,6 +29,7 @@ import logging.config
|
||||||
import urllib
|
import urllib
|
||||||
import urllib2
|
import urllib2
|
||||||
import string
|
import string
|
||||||
|
import json
|
||||||
|
|
||||||
# additional modules (should be checked)
|
# additional modules (should be checked)
|
||||||
from configobj import ConfigObj
|
from configobj import ConfigObj
|
||||||
|
@ -50,13 +51,7 @@ parser = OptionParser(usage=usage)
|
||||||
|
|
||||||
# Options
|
# Options
|
||||||
parser.add_option("-d", "--data", help="Pass JSON data from liquidsoap into this script.", metavar="data")
|
parser.add_option("-d", "--data", help="Pass JSON data from liquidsoap into this script.", metavar="data")
|
||||||
#parser.add_option("-p", "--playing", help="Tell server what is playing right now.", default=False, action="store_true", dest="playing")
|
|
||||||
#parser.add_option("-t", "--playlist-type", help="", metavar="playlist_type")
|
|
||||||
parser.add_option("-m", "--media-id", help="ID of the file that is currently playing.", metavar="media_id")
|
parser.add_option("-m", "--media-id", help="ID of the file that is currently playing.", metavar="media_id")
|
||||||
#parser.add_option("-U", "--user-id", help="", metavar="user_id")
|
|
||||||
#parser.add_option("-P", "--playlist-id", help="", metavar="playlist_id")
|
|
||||||
#parser.add_option("-T", "--transmission-id", help="", metavar="transmission_id")
|
|
||||||
#parser.add_option("-E", "--export-source", help="", metavar="export_source")
|
|
||||||
|
|
||||||
# parse options
|
# parse options
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
|
@ -72,135 +67,21 @@ except Exception, e:
|
||||||
print 'error: ', e
|
print 'error: ', e
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
class Global:
|
|
||||||
def __init__(self):
|
|
||||||
print
|
|
||||||
|
|
||||||
def selfcheck(self):
|
|
||||||
pass
|
|
||||||
#self.api_client = api_client.api_client_factory(config)
|
|
||||||
#self.api_client.check_version()
|
|
||||||
|
|
||||||
class Notify:
|
class Notify:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.api_client = api_client.api_client_factory(config)
|
self.api_client = api_client.api_client_factory(config)
|
||||||
#self.dls_client = DlsClient('127.0.0.128', 50008, 'myusername', 'mypass')
|
|
||||||
|
|
||||||
|
|
||||||
def notify_media_start_playing(self, data, media_id):
|
def notify_media_start_playing(self, data, media_id):
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
#tnow = time.localtime(time.time())
|
|
||||||
|
|
||||||
logger.debug('#################################################')
|
logger.debug('#################################################')
|
||||||
logger.debug('# Calling server to update about what\'s playing #')
|
logger.debug('# Calling server to update about what\'s playing #')
|
||||||
logger.debug('#################################################')
|
logger.debug('#################################################')
|
||||||
logger.debug('data = '+ str(data))
|
logger.debug('data = '+ str(data))
|
||||||
#print 'options.data = '+ options.data
|
|
||||||
#data = json.read(options.data)
|
|
||||||
response = self.api_client.notify_media_item_start_playing(data, media_id)
|
response = self.api_client.notify_media_item_start_playing(data, media_id)
|
||||||
logger.debug("Response: "+str(response))
|
logger.debug("Response: "+str(response))
|
||||||
|
|
||||||
#def start_playing(self, options):
|
|
||||||
# logger = logging.getLogger("start_playing")
|
|
||||||
# tnow = time.localtime(time.time())
|
|
||||||
#
|
|
||||||
# #print options
|
|
||||||
#
|
|
||||||
# logger.debug('#################################################')
|
|
||||||
# logger.debug('# Calling server to update about what\'s playing #')
|
|
||||||
# logger.debug('#################################################')
|
|
||||||
#
|
|
||||||
# if int(options.playlist_type) < 5:
|
|
||||||
# logger.debug('seems to be a playlist')
|
|
||||||
#
|
|
||||||
# try:
|
|
||||||
# media_id = int(options.media_id)
|
|
||||||
# except Exception, e:
|
|
||||||
# media_id = 0
|
|
||||||
#
|
|
||||||
# response = self.api_client.update_start_playing(options.playlist_type, options.export_source, media_id, options.playlist_id, options.transmission_id)
|
|
||||||
#
|
|
||||||
# logger.debug(response)
|
|
||||||
#
|
|
||||||
# if int(options.playlist_type) == 6:
|
|
||||||
# logger.debug('seems to be a couchcast')
|
|
||||||
#
|
|
||||||
# try:
|
|
||||||
# media_id = int(options.media_id)
|
|
||||||
# except Exception, e:
|
|
||||||
# media_id = 0
|
|
||||||
#
|
|
||||||
# response = self.api_client.update_start_playing(options.playlist_type, options.export_source, media_id, options.playlist_id, options.transmission_id)
|
|
||||||
#
|
|
||||||
# logger.debug(response)
|
|
||||||
#
|
|
||||||
# sys.exit()
|
|
||||||
|
|
||||||
#def start_playing_legacy(self, options):
|
|
||||||
# logger = logging.getLogger("start_playing")
|
|
||||||
# tnow = time.localtime(time.time())
|
|
||||||
#
|
|
||||||
# print '#################################################'
|
|
||||||
# print '# Calling server to update about what\'s playing #'
|
|
||||||
# print '#################################################'
|
|
||||||
#
|
|
||||||
# path = options
|
|
||||||
#
|
|
||||||
# print
|
|
||||||
# print path
|
|
||||||
# print
|
|
||||||
#
|
|
||||||
# if 'pl_id' in path:
|
|
||||||
# print 'seems to be a playlist'
|
|
||||||
# type = 'playlist'
|
|
||||||
# id = path[5:]
|
|
||||||
#
|
|
||||||
# elif 'text' in path:
|
|
||||||
# print 'seems to be a playlist'
|
|
||||||
# type = 'text'
|
|
||||||
# id = path[4:]
|
|
||||||
# print id
|
|
||||||
#
|
|
||||||
# else:
|
|
||||||
# print 'seems to be a single track (media)'
|
|
||||||
# type = 'media'
|
|
||||||
# try:
|
|
||||||
# file = path.split("/")[-1:][0]
|
|
||||||
# if file.find('_cue_') > 0:
|
|
||||||
# id = file.split("_cue_")[0]
|
|
||||||
# else:
|
|
||||||
# id = file.split(".")[-2:][0]
|
|
||||||
#
|
|
||||||
# except Exception, e:
|
|
||||||
# #print e
|
|
||||||
# id = False
|
|
||||||
#
|
|
||||||
# try:
|
|
||||||
# id = id
|
|
||||||
# except Exception, e:
|
|
||||||
# #print e
|
|
||||||
# id = False
|
|
||||||
#
|
|
||||||
# print
|
|
||||||
# print type + " id: ",
|
|
||||||
# print id
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# response = self.api_client.update_start_playing(type, id, self.export_source, path)
|
|
||||||
#
|
|
||||||
# print 'DONE'
|
|
||||||
#
|
|
||||||
# try:
|
|
||||||
# txt = response['txt']
|
|
||||||
# print '#######################################'
|
|
||||||
# print txt
|
|
||||||
# print '#######################################'
|
|
||||||
# #self.dls_client.set_txt(txt)
|
|
||||||
#
|
|
||||||
# except Exception, e:
|
|
||||||
# print e
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print
|
print
|
||||||
|
@ -210,13 +91,8 @@ if __name__ == '__main__':
|
||||||
print '#########################################'
|
print '#########################################'
|
||||||
|
|
||||||
# initialize
|
# initialize
|
||||||
g = Global()
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
#if options.playing:
|
|
||||||
# try: n.start_playing(options)
|
|
||||||
# except Exception, e:
|
|
||||||
# print e
|
|
||||||
# sys.exit()
|
|
||||||
if not options.data:
|
if not options.data:
|
||||||
print "NOTICE: 'data' command-line argument not given."
|
print "NOTICE: 'data' command-line argument not given."
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
@ -226,7 +102,6 @@ if __name__ == '__main__':
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
g.selfcheck()
|
|
||||||
n = Notify()
|
n = Notify()
|
||||||
n.notify_media_start_playing(options.data, options.media_id)
|
n.notify_media_start_playing(options.data, options.media_id)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
|
|
|
@ -28,7 +28,8 @@ icecast_port = 8000
|
||||||
icecast_pass = "hackme"
|
icecast_pass = "hackme"
|
||||||
|
|
||||||
# mountpoints
|
# mountpoints
|
||||||
mount_scheduler = "airtime.mp3"
|
mount_point_mp3 = "airtime.mp3"
|
||||||
|
mount_point_vorbis = "airtime.ogg"
|
||||||
|
|
||||||
# mount intra is used for scheduler >>> fallback stream
|
# mount intra is used for scheduler >>> fallback stream
|
||||||
mount_intra = "pypo_intra"
|
mount_intra = "pypo_intra"
|
||||||
|
@ -38,3 +39,10 @@ intra_host = "127.0.0.1"
|
||||||
intra_port = 9000
|
intra_port = 9000
|
||||||
intra_pass = "hackme"
|
intra_pass = "hackme"
|
||||||
|
|
||||||
|
icecast_url = "http://airtime.sourcefabric.org"
|
||||||
|
icecast_description = "Airtime Radio!"
|
||||||
|
icecast_genre = "genre"
|
||||||
|
|
||||||
|
output_sound_device = true
|
||||||
|
output_icecast_vorbis = true
|
||||||
|
output_icecast_mp3 = true
|
||||||
|
|
|
@ -5,42 +5,14 @@ set("log.file.path", log_file)
|
||||||
set("log.stdout", true)
|
set("log.stdout", true)
|
||||||
set("server.telnet", true)
|
set("server.telnet", true)
|
||||||
|
|
||||||
active_queue = ref 0
|
queue = request.queue(conservative=true,length=600.,id="queue")
|
||||||
|
queue = audio_to_stereo(queue)
|
||||||
scheduler_q0 = request.queue(conservative=true,length=600.,id="scheduler_q0")
|
|
||||||
scheduler_q1 = request.queue(conservative=true,length=600.,id="scheduler_q1")
|
|
||||||
|
|
||||||
scheduler_q0 = audio_to_stereo(scheduler_q0)
|
|
||||||
scheduler_q1 = audio_to_stereo(scheduler_q1)
|
|
||||||
|
|
||||||
pypo_data = ref '0'
|
pypo_data = ref '0'
|
||||||
|
|
||||||
# push function, enqueues file in inactive queue (does not start automatically)
|
#def notify(m)
|
||||||
def scheduler_push(s)
|
# print("./notify.sh --data='#{!pypo_data}' --media-id=#{m['media_id']}")
|
||||||
ignore(server.execute("scheduler_q#{!active_queue}.push #{s}"))
|
#end
|
||||||
print('push to #{!active_queue} - #{s}')
|
|
||||||
"Done"
|
|
||||||
end
|
|
||||||
|
|
||||||
# flips the queues
|
|
||||||
def scheduler_flip()
|
|
||||||
# get playing (active) queue and flush it
|
|
||||||
l = list.hd(server.execute("scheduler_q#{!active_queue}.queue"))
|
|
||||||
l = string.split(separator=" ",l)
|
|
||||||
list.iter(fun (rid) -> ignore(server.execute("scheduler_q#{!active_queue}.ignore #{rid}")), l)
|
|
||||||
|
|
||||||
# skip the playing item
|
|
||||||
source.skip(if !active_queue==0 then scheduler_q0 else scheduler_q1 end)
|
|
||||||
|
|
||||||
# flip variables
|
|
||||||
active_queue := 1-!active_queue
|
|
||||||
print('switch to active queue: #{!active_queue}')
|
|
||||||
"Done"
|
|
||||||
end
|
|
||||||
|
|
||||||
def notify(m)
|
|
||||||
print("./notify.sh --data='#{!pypo_data}' --media-id=#{m['media_id']}")
|
|
||||||
end
|
|
||||||
|
|
||||||
def crossfade(s)
|
def crossfade(s)
|
||||||
s = fade.in(type="log", s)
|
s = fade.in(type="log", s)
|
||||||
|
@ -49,23 +21,42 @@ def crossfade(s)
|
||||||
cross(fader,s)
|
cross(fader,s)
|
||||||
end
|
end
|
||||||
|
|
||||||
server.register(namespace="scheduler","push", scheduler_push)
|
|
||||||
server.register(namespace="scheduler","flip", fun (s) -> begin scheduler_flip() end)
|
|
||||||
server.register(namespace="vars", "pypo_data", fun (s) -> begin pypo_data := s "Done" end)
|
server.register(namespace="vars", "pypo_data", fun (s) -> begin pypo_data := s "Done" end)
|
||||||
|
|
||||||
default = single("/opt/pypo/files/basic/silence.mp3")
|
default = single("/opt/pypo/files/basic/silence.mp3")
|
||||||
radio = fallback(track_sensitive=false, [switch(track_sensitive=false, [(fun () -> !active_queue==1, scheduler_q0), (fun () -> !active_queue==0, scheduler_q1)]), default])
|
default = rewrite_metadata([("artist","Airtime"), ("title", "offline")],default)
|
||||||
|
|
||||||
#radio = on_metadata(notify, radio)
|
s = fallback(track_sensitive=false, [queue, default])
|
||||||
|
|
||||||
radio = crossfade(radio)
|
#s = on_metadata(notify, s)
|
||||||
|
s = crossfade(s)
|
||||||
|
|
||||||
out(radio)
|
if output_sound_device then
|
||||||
clock(id="clock_icecast",
|
out_device = out(s)
|
||||||
output.icecast(%mp3,
|
end
|
||||||
host = icecast_host, port = icecast_port,
|
|
||||||
password = icecast_pass, mount = mount_scheduler,
|
if output_icecast_mp3 then
|
||||||
fallible = true,
|
out_mp3 = output.icecast(%mp3,
|
||||||
restart = true,
|
host = icecast_host, port = icecast_port,
|
||||||
restart_delay = 5,
|
password = icecast_pass, mount = mount_point_mp3,
|
||||||
buffer(radio)))
|
fallible = true,
|
||||||
|
restart = true,
|
||||||
|
restart_delay = 5,
|
||||||
|
url = icecast_url,
|
||||||
|
description = icecast_description,
|
||||||
|
genre = icecast_genre,
|
||||||
|
s)
|
||||||
|
end
|
||||||
|
|
||||||
|
if output_icecast_vorbis then
|
||||||
|
out_vorbis = output.icecast(%vorbis,
|
||||||
|
host = icecast_host, port = icecast_port,
|
||||||
|
password = icecast_pass, mount = mount_point_vorbis,
|
||||||
|
fallible = true,
|
||||||
|
restart = true,
|
||||||
|
restart_delay = 5,
|
||||||
|
url = icecast_url,
|
||||||
|
description = icecast_description,
|
||||||
|
genre = icecast_genre,
|
||||||
|
s)
|
||||||
|
end
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
||||||
/opt/pypo/files/basic/silence.mp3
|
|
|
@ -1,310 +0,0 @@
|
||||||
import string
|
|
||||||
import types
|
|
||||||
|
|
||||||
## json.py implements a JSON (http://json.org) reader and writer.
|
|
||||||
## Copyright (C) 2005 Patrick D. Logan
|
|
||||||
## Contact mailto:patrickdlogan@stardecisions.com
|
|
||||||
##
|
|
||||||
## This library is free software; you can redistribute it and/or
|
|
||||||
## modify it under the terms of the GNU Lesser General Public
|
|
||||||
## License as published by the Free Software Foundation; either
|
|
||||||
## version 2.1 of the License, or (at your option) any later version.
|
|
||||||
##
|
|
||||||
## This library 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
|
|
||||||
## Lesser General Public License for more details.
|
|
||||||
##
|
|
||||||
## You should have received a copy of the GNU Lesser General Public
|
|
||||||
## License along with this library; if not, write to the Free Software
|
|
||||||
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
|
|
||||||
|
|
||||||
class _StringGenerator(object):
|
|
||||||
def __init__(self, string):
|
|
||||||
self.string = string
|
|
||||||
self.index = -1
|
|
||||||
def peek(self):
|
|
||||||
i = self.index + 1
|
|
||||||
if i < len(self.string):
|
|
||||||
return self.string[i]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
def next(self):
|
|
||||||
self.index += 1
|
|
||||||
if self.index < len(self.string):
|
|
||||||
return self.string[self.index]
|
|
||||||
else:
|
|
||||||
raise StopIteration
|
|
||||||
def all(self):
|
|
||||||
return self.string
|
|
||||||
|
|
||||||
class WriteException(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class ReadException(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class JsonReader(object):
|
|
||||||
hex_digits = {'A': 10,'B': 11,'C': 12,'D': 13,'E': 14,'F':15}
|
|
||||||
escapes = {'t':'\t','n':'\n','f':'\f','r':'\r','b':'\b'}
|
|
||||||
|
|
||||||
def read(self, s):
|
|
||||||
self._generator = _StringGenerator(s)
|
|
||||||
result = self._read()
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _read(self):
|
|
||||||
self._eatWhitespace()
|
|
||||||
peek = self._peek()
|
|
||||||
if peek is None:
|
|
||||||
raise ReadException, "Nothing to read: '%s'" % self._generator.all()
|
|
||||||
if peek == '{':
|
|
||||||
return self._readObject()
|
|
||||||
elif peek == '[':
|
|
||||||
return self._readArray()
|
|
||||||
elif peek == '"':
|
|
||||||
return self._readString()
|
|
||||||
elif peek == '-' or peek.isdigit():
|
|
||||||
return self._readNumber()
|
|
||||||
elif peek == 't':
|
|
||||||
return self._readTrue()
|
|
||||||
elif peek == 'f':
|
|
||||||
return self._readFalse()
|
|
||||||
elif peek == 'n':
|
|
||||||
return self._readNull()
|
|
||||||
elif peek == '/':
|
|
||||||
self._readComment()
|
|
||||||
return self._read()
|
|
||||||
else:
|
|
||||||
raise ReadException, "Input is not valid JSON: '%s'" % self._generator.all()
|
|
||||||
|
|
||||||
def _readTrue(self):
|
|
||||||
self._assertNext('t', "true")
|
|
||||||
self._assertNext('r', "true")
|
|
||||||
self._assertNext('u', "true")
|
|
||||||
self._assertNext('e', "true")
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _readFalse(self):
|
|
||||||
self._assertNext('f', "false")
|
|
||||||
self._assertNext('a', "false")
|
|
||||||
self._assertNext('l', "false")
|
|
||||||
self._assertNext('s', "false")
|
|
||||||
self._assertNext('e', "false")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _readNull(self):
|
|
||||||
self._assertNext('n', "null")
|
|
||||||
self._assertNext('u', "null")
|
|
||||||
self._assertNext('l', "null")
|
|
||||||
self._assertNext('l', "null")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _assertNext(self, ch, target):
|
|
||||||
if self._next() != ch:
|
|
||||||
raise ReadException, "Trying to read %s: '%s'" % (target, self._generator.all())
|
|
||||||
|
|
||||||
def _readNumber(self):
|
|
||||||
isfloat = False
|
|
||||||
result = self._next()
|
|
||||||
peek = self._peek()
|
|
||||||
while peek is not None and (peek.isdigit() or peek == "."):
|
|
||||||
isfloat = isfloat or peek == "."
|
|
||||||
result = result + self._next()
|
|
||||||
peek = self._peek()
|
|
||||||
try:
|
|
||||||
if isfloat:
|
|
||||||
return float(result)
|
|
||||||
else:
|
|
||||||
return int(result)
|
|
||||||
except ValueError:
|
|
||||||
raise ReadException, "Not a valid JSON number: '%s'" % result
|
|
||||||
|
|
||||||
def _readString(self):
|
|
||||||
result = ""
|
|
||||||
assert self._next() == '"'
|
|
||||||
try:
|
|
||||||
while self._peek() != '"':
|
|
||||||
ch = self._next()
|
|
||||||
if ch == "\\":
|
|
||||||
ch = self._next()
|
|
||||||
if ch in 'brnft':
|
|
||||||
ch = self.escapes[ch]
|
|
||||||
elif ch == "u":
|
|
||||||
ch4096 = self._next()
|
|
||||||
ch256 = self._next()
|
|
||||||
ch16 = self._next()
|
|
||||||
ch1 = self._next()
|
|
||||||
n = 4096 * self._hexDigitToInt(ch4096)
|
|
||||||
n += 256 * self._hexDigitToInt(ch256)
|
|
||||||
n += 16 * self._hexDigitToInt(ch16)
|
|
||||||
n += self._hexDigitToInt(ch1)
|
|
||||||
ch = unichr(n)
|
|
||||||
elif ch not in '"/\\':
|
|
||||||
raise ReadException, "Not a valid escaped JSON character: '%s' in %s" % (ch, self._generator.all())
|
|
||||||
result = result + ch
|
|
||||||
except StopIteration:
|
|
||||||
raise ReadException, "Not a valid JSON string: '%s'" % self._generator.all()
|
|
||||||
assert self._next() == '"'
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _hexDigitToInt(self, ch):
|
|
||||||
try:
|
|
||||||
result = self.hex_digits[ch.upper()]
|
|
||||||
except KeyError:
|
|
||||||
try:
|
|
||||||
result = int(ch)
|
|
||||||
except ValueError:
|
|
||||||
raise ReadException, "The character %s is not a hex digit." % ch
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _readComment(self):
|
|
||||||
assert self._next() == "/"
|
|
||||||
second = self._next()
|
|
||||||
if second == "/":
|
|
||||||
self._readDoubleSolidusComment()
|
|
||||||
elif second == '*':
|
|
||||||
self._readCStyleComment()
|
|
||||||
else:
|
|
||||||
raise ReadException, "Not a valid JSON comment: %s" % self._generator.all()
|
|
||||||
|
|
||||||
def _readCStyleComment(self):
|
|
||||||
try:
|
|
||||||
done = False
|
|
||||||
while not done:
|
|
||||||
ch = self._next()
|
|
||||||
done = (ch == "*" and self._peek() == "/")
|
|
||||||
if not done and ch == "/" and self._peek() == "*":
|
|
||||||
raise ReadException, "Not a valid JSON comment: %s, '/*' cannot be embedded in the comment." % self._generator.all()
|
|
||||||
self._next()
|
|
||||||
except StopIteration:
|
|
||||||
raise ReadException, "Not a valid JSON comment: %s, expected */" % self._generator.all()
|
|
||||||
|
|
||||||
def _readDoubleSolidusComment(self):
|
|
||||||
try:
|
|
||||||
ch = self._next()
|
|
||||||
while ch != "\r" and ch != "\n":
|
|
||||||
ch = self._next()
|
|
||||||
except StopIteration:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _readArray(self):
|
|
||||||
result = []
|
|
||||||
assert self._next() == '['
|
|
||||||
done = self._peek() == ']'
|
|
||||||
while not done:
|
|
||||||
item = self._read()
|
|
||||||
result.append(item)
|
|
||||||
self._eatWhitespace()
|
|
||||||
done = self._peek() == ']'
|
|
||||||
if not done:
|
|
||||||
ch = self._next()
|
|
||||||
if ch != ",":
|
|
||||||
raise ReadException, "Not a valid JSON array: '%s' due to: '%s'" % (self._generator.all(), ch)
|
|
||||||
assert ']' == self._next()
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _readObject(self):
|
|
||||||
result = {}
|
|
||||||
assert self._next() == '{'
|
|
||||||
done = self._peek() == '}'
|
|
||||||
while not done:
|
|
||||||
key = self._read()
|
|
||||||
if type(key) is not types.StringType:
|
|
||||||
raise ReadException, "Not a valid JSON object key (should be a string): %s" % key
|
|
||||||
self._eatWhitespace()
|
|
||||||
ch = self._next()
|
|
||||||
if ch != ":":
|
|
||||||
raise ReadException, "Not a valid JSON object: '%s' due to: '%s'" % (self._generator.all(), ch)
|
|
||||||
self._eatWhitespace()
|
|
||||||
val = self._read()
|
|
||||||
result[key] = val
|
|
||||||
self._eatWhitespace()
|
|
||||||
done = self._peek() == '}'
|
|
||||||
if not done:
|
|
||||||
ch = self._next()
|
|
||||||
if ch != ",":
|
|
||||||
raise ReadException, "Not a valid JSON array: '%s' due to: '%s'" % (self._generator.all(), ch)
|
|
||||||
assert self._next() == "}"
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _eatWhitespace(self):
|
|
||||||
p = self._peek()
|
|
||||||
while p is not None and p in string.whitespace or p == '/':
|
|
||||||
if p == '/':
|
|
||||||
self._readComment()
|
|
||||||
else:
|
|
||||||
self._next()
|
|
||||||
p = self._peek()
|
|
||||||
|
|
||||||
def _peek(self):
|
|
||||||
return self._generator.peek()
|
|
||||||
|
|
||||||
def _next(self):
|
|
||||||
return self._generator.next()
|
|
||||||
|
|
||||||
class JsonWriter(object):
|
|
||||||
|
|
||||||
def _append(self, s):
|
|
||||||
self._results.append(s)
|
|
||||||
|
|
||||||
def write(self, obj, escaped_forward_slash=False):
|
|
||||||
self._escaped_forward_slash = escaped_forward_slash
|
|
||||||
self._results = []
|
|
||||||
self._write(obj)
|
|
||||||
return "".join(self._results)
|
|
||||||
|
|
||||||
def _write(self, obj):
|
|
||||||
ty = type(obj)
|
|
||||||
if ty is types.DictType:
|
|
||||||
n = len(obj)
|
|
||||||
self._append("{")
|
|
||||||
for k, v in obj.items():
|
|
||||||
self._write(k)
|
|
||||||
self._append(":")
|
|
||||||
self._write(v)
|
|
||||||
n = n - 1
|
|
||||||
if n > 0:
|
|
||||||
self._append(",")
|
|
||||||
self._append("}")
|
|
||||||
elif ty is types.ListType or ty is types.TupleType:
|
|
||||||
n = len(obj)
|
|
||||||
self._append("[")
|
|
||||||
for item in obj:
|
|
||||||
self._write(item)
|
|
||||||
n = n - 1
|
|
||||||
if n > 0:
|
|
||||||
self._append(",")
|
|
||||||
self._append("]")
|
|
||||||
elif ty is types.StringType or ty is types.UnicodeType:
|
|
||||||
self._append('"')
|
|
||||||
obj = obj.replace('\\', r'\\')
|
|
||||||
if self._escaped_forward_slash:
|
|
||||||
obj = obj.replace('/', r'\/')
|
|
||||||
obj = obj.replace('"', r'\"')
|
|
||||||
obj = obj.replace('\b', r'\b')
|
|
||||||
obj = obj.replace('\f', r'\f')
|
|
||||||
obj = obj.replace('\n', r'\n')
|
|
||||||
obj = obj.replace('\r', r'\r')
|
|
||||||
obj = obj.replace('\t', r'\t')
|
|
||||||
self._append(obj)
|
|
||||||
self._append('"')
|
|
||||||
elif ty is types.IntType or ty is types.LongType:
|
|
||||||
self._append(str(obj))
|
|
||||||
elif ty is types.FloatType:
|
|
||||||
self._append("%f" % obj)
|
|
||||||
elif obj is True:
|
|
||||||
self._append("true")
|
|
||||||
elif obj is False:
|
|
||||||
self._append("false")
|
|
||||||
elif obj is None:
|
|
||||||
self._append("null")
|
|
||||||
else:
|
|
||||||
raise WriteException, "Cannot write in JSON: %s" % repr(obj)
|
|
||||||
|
|
||||||
def write(obj, escaped_forward_slash=False):
|
|
||||||
return JsonWriter().write(obj, escaped_forward_slash)
|
|
||||||
|
|
||||||
def read(s):
|
|
||||||
return JsonReader().read(s)
|
|
|
@ -7,8 +7,7 @@ import urllib
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import telnetlib
|
import telnetlib
|
||||||
|
import json
|
||||||
from util import json
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -26,7 +25,7 @@ class Status:
|
||||||
# lookup OBP version
|
# lookup OBP version
|
||||||
try:
|
try:
|
||||||
response = urllib.urlopen(self.status_url)
|
response = urllib.urlopen(self.status_url)
|
||||||
response_json = json.read(response.read())
|
response_json = json.loads(response.read())
|
||||||
obp_version = int(response_json['version'])
|
obp_version = int(response_json['version'])
|
||||||
logger.debug("OBP Version %s detected", obp_version)
|
logger.debug("OBP Version %s detected", obp_version)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue