Merge branch 'master' of dev.sourcefabric.org:campcaster

This commit is contained in:
Naomi 2011-02-22 11:46:22 -05:00
commit 42598d03b4
15 changed files with 148 additions and 2680 deletions

24
INSTALL
View file

@ -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
Airtime is free software; you can redistribute it and/or modify To report bugs, visit our bug tracker at:
it under the terms of the GNU General Public License as published by http://dev.sourcefabric.org/browse/CC
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Airtime is distributed in the hope that it will be useful, Visit our community support forum here:
but WITHOUT ANY WARRANTY; without even the implied warranty of http://forum.sourcefabric.org/index.php/f/14/
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 For commercial support, see http://sourcefabric.org/en/services/about/347/Support.htm
along with Airtime; if not, write to the Free Software or send an e-mail to contact@sourcefabric.org
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

View file

@ -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.

View file

@ -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

View file

@ -8,8 +8,6 @@ import time
import logging import logging
from util import json
import os import os
import socket import socket

View file

@ -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.

File diff suppressed because it is too large Load diff

View file

@ -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)
@ -297,16 +291,6 @@ 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)
@ -680,28 +664,11 @@ class Playout:
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()
@ -718,7 +685,18 @@ 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)
logger.debug('sending "flip"') 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())
"""
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)

View file

@ -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()
@ -73,134 +68,20 @@ except Exception, 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:

View file

@ -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

View file

@ -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
if output_icecast_mp3 then
out_mp3 = output.icecast(%mp3,
host = icecast_host, port = icecast_port, host = icecast_host, port = icecast_port,
password = icecast_pass, mount = mount_scheduler, password = icecast_pass, mount = mount_point_mp3,
fallible = true, fallible = true,
restart = true, restart = true,
restart_delay = 5, restart_delay = 5,
buffer(radio))) 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

View file

@ -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

View file

@ -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)

View file

@ -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)