Merge branch 'master' of dev.sourcefabric.org:campcaster
This commit is contained in:
commit
42598d03b4
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.
|
||||
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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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
|
||||
Visit our community support forum here:
|
||||
http://forum.sourcefabric.org/index.php/f/14/
|
||||
|
||||
For commercial support, see http://sourcefabric.org/en/services/about/347/Support.htm
|
||||
or send an e-mail to contact@sourcefabric.org
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Please see this page for a typical user install:
|
||||
http://www.sourcefabric.org/en/products/airtime_manuals/
|
||||
Please see this page for install instructions:
|
||||
http://wiki.sourcefabric.org/display/CC/Installing+Airtime+%28v1.6%29
|
||||
|
||||
If you are a developer, see this page:
|
||||
http://wiki.sourcefabric.org/display/CC
|
||||
|
|
|
@ -1,37 +1,72 @@
|
|||
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
|
||||
- Does this link with our code? Yes
|
||||
- Compatible with GPLv3: Yes
|
||||
|
||||
* Liquidsoap
|
||||
- License: GPLv2
|
||||
- Does this link with our code? No, we only call this as an executable
|
||||
|
||||
* PEAR
|
||||
- Notes: We only use the PEAR base class PEAR_Error, in the "PEAR" PEAR library.
|
||||
- License: New BSD License
|
||||
- Does this link with our code? Yes
|
||||
- Compatible with GPLv3? Yes.
|
||||
|
||||
* GetID3
|
||||
* GetID3
|
||||
- Web site: http://getid3.sourceforge.net/
|
||||
- License: GPLv2
|
||||
- Does this link with our code? 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
|
||||
- Web site: http://www.propelorm.org/
|
||||
- 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
|
||||
|
||||
* Phing
|
||||
* Phing
|
||||
- Web site: http://phing.info/trac/
|
||||
- Note: Only used for development, not needed to run Airtime.
|
||||
- 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 urllib
|
||||
import logging
|
||||
from util import json
|
||||
import json
|
||||
import os
|
||||
from urlparse import urlparse
|
||||
|
||||
|
@ -118,7 +118,7 @@ class AirTimeApiClient(ApiClientInterface):
|
|||
response = urllib.urlopen(url)
|
||||
data = response.read()
|
||||
logger.debug("Data: %s", data)
|
||||
response_json = json.read(data)
|
||||
response_json = json.loads(data)
|
||||
version = response_json['version']
|
||||
logger.debug("Airtime Version %s detected", version)
|
||||
except Exception, e:
|
||||
|
@ -223,7 +223,7 @@ class AirTimeApiClient(ApiClientInterface):
|
|||
try:
|
||||
response_json = urllib.urlopen(export_url).read()
|
||||
#logger.debug("%s", response_json)
|
||||
response = json.read(response_json)
|
||||
response = json.loads(response_json)
|
||||
#logger.info("export status %s", response['check'])
|
||||
status = response['check']
|
||||
except Exception, e:
|
||||
|
@ -281,7 +281,7 @@ class AirTimeApiClient(ApiClientInterface):
|
|||
|
||||
try:
|
||||
response = urllib.urlopen(url)
|
||||
response = json.read(response.read())
|
||||
response = json.loads(response.read())
|
||||
logger.info("API-Status %s", response['status'])
|
||||
logger.info("API-Message %s", response['message'])
|
||||
|
||||
|
@ -302,7 +302,7 @@ class AirTimeApiClient(ApiClientInterface):
|
|||
if (data[0] != '{'):
|
||||
return response
|
||||
try:
|
||||
data = json.read(data)
|
||||
data = json.loads(data)
|
||||
logger.debug(str(data))
|
||||
schedule_id = data["schedule_id"]
|
||||
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"])
|
||||
logger.debug(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-Message %s", response['message'])
|
||||
|
||||
|
@ -329,7 +329,7 @@ class AirTimeApiClient(ApiClientInterface):
|
|||
#
|
||||
#try:
|
||||
# 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.info("API-Status %s", response['status'])
|
||||
# logger.info("API-Message %s", response['message'])
|
||||
|
@ -349,7 +349,7 @@ class AirTimeApiClient(ApiClientInterface):
|
|||
data["schedule_id"] = playlist['id']
|
||||
except Exception, e:
|
||||
data["schedule_id"] = 0
|
||||
data = json.write(data)
|
||||
data = json.dumps(data)
|
||||
return data
|
||||
|
||||
|
||||
|
@ -404,7 +404,7 @@ class ObpApiClient():
|
|||
try:
|
||||
logger.debug("Trying to contact %s", url)
|
||||
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'])
|
||||
logger.debug("OBP Version %s detected", obp_version)
|
||||
|
||||
|
@ -471,7 +471,7 @@ class ObpApiClient():
|
|||
try:
|
||||
response_json = urllib.urlopen(export_url).read()
|
||||
logger.debug("%s", response_json)
|
||||
response = json.read(response_json)
|
||||
response = json.loads(response_json)
|
||||
logger.info("export status %s", response['check'])
|
||||
status = response['check']
|
||||
except Exception, e:
|
||||
|
@ -502,7 +502,7 @@ class ObpApiClient():
|
|||
|
||||
try:
|
||||
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-Message %s", response['message'])
|
||||
|
||||
|
@ -536,7 +536,7 @@ class ObpApiClient():
|
|||
|
||||
try:
|
||||
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-Message %s", response['message'])
|
||||
logger.info("TXT %s", response['str_dls'])
|
||||
|
@ -556,7 +556,7 @@ class ObpApiClient():
|
|||
|
||||
try:
|
||||
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.info("API-Status %s", response['status'])
|
||||
logger.info("API-Message %s", response['message'])
|
||||
|
@ -580,6 +580,6 @@ class ObpApiClient():
|
|||
data["playlist_id"] = 0
|
||||
data["user_id"] = 0
|
||||
data["transmission_id"] = 0
|
||||
data = json.write(data)
|
||||
data = json.dumps(data)
|
||||
return data
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@ import time
|
|||
|
||||
import logging
|
||||
|
||||
from util import json
|
||||
|
||||
import os
|
||||
import socket
|
||||
|
||||
|
@ -87,4 +85,4 @@ class DlsClient():
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -62,8 +62,8 @@ def get_current_script_dir():
|
|||
|
||||
try:
|
||||
current_script_dir = get_current_script_dir()
|
||||
print "Terminating any existing pypo processes"
|
||||
os.system("python %s/pypo-stop.py"% current_script_dir)
|
||||
print "Checking and removing any existing pypo processes"
|
||||
os.system("python %s/pypo-uninstall.py 2>&1 1>/dev/null"% current_script_dir)
|
||||
time.sleep(5)
|
||||
|
||||
# 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
|
||||
2 channels are fed to LiquidSoap
|
||||
(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)
|
||||
|
@ -296,17 +290,7 @@ class Playout:
|
|||
|
||||
elif int(playlist['subtype']) > 0 and int(playlist['subtype']) < 5:
|
||||
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
|
||||
plfile = open(self.cache_dir + str(pkey) + '/list.lsp', "w")
|
||||
plfile.write(ls_playlist)
|
||||
|
@ -679,29 +663,12 @@ class Playout:
|
|||
logger.debug('OK - Can read playlist file')
|
||||
|
||||
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
|
||||
#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().
|
||||
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.
|
||||
epoch_now = time.time()
|
||||
|
@ -717,8 +684,19 @@ class Playout:
|
|||
|
||||
logger.debug('sleeping for %s s' % (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)
|
||||
|
||||
# Get any extra information for liquidsoap (which will be sent back to us)
|
||||
|
@ -733,6 +711,7 @@ class Playout:
|
|||
tn.write("exit\n")
|
||||
|
||||
tn.read_all()
|
||||
"""
|
||||
status = 1
|
||||
except Exception, e:
|
||||
logger.error('%s', e)
|
||||
|
|
|
@ -29,6 +29,7 @@ import logging.config
|
|||
import urllib
|
||||
import urllib2
|
||||
import string
|
||||
import json
|
||||
|
||||
# additional modules (should be checked)
|
||||
from configobj import ConfigObj
|
||||
|
@ -50,13 +51,7 @@ parser = OptionParser(usage=usage)
|
|||
|
||||
# Options
|
||||
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("-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
|
||||
(options, args) = parser.parse_args()
|
||||
|
@ -72,135 +67,21 @@ except Exception, e:
|
|||
print 'error: ', e
|
||||
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:
|
||||
def __init__(self):
|
||||
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):
|
||||
logger = logging.getLogger()
|
||||
#tnow = time.localtime(time.time())
|
||||
|
||||
logger.debug('#################################################')
|
||||
logger.debug('# Calling server to update about what\'s playing #')
|
||||
logger.debug('#################################################')
|
||||
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)
|
||||
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__':
|
||||
print
|
||||
|
@ -210,13 +91,8 @@ if __name__ == '__main__':
|
|||
print '#########################################'
|
||||
|
||||
# initialize
|
||||
g = Global()
|
||||
logger = logging.getLogger()
|
||||
#if options.playing:
|
||||
# try: n.start_playing(options)
|
||||
# except Exception, e:
|
||||
# print e
|
||||
# sys.exit()
|
||||
|
||||
if not options.data:
|
||||
print "NOTICE: 'data' command-line argument not given."
|
||||
sys.exit()
|
||||
|
@ -226,7 +102,6 @@ if __name__ == '__main__':
|
|||
sys.exit()
|
||||
|
||||
try:
|
||||
g.selfcheck()
|
||||
n = Notify()
|
||||
n.notify_media_start_playing(options.data, options.media_id)
|
||||
except Exception, e:
|
||||
|
|
|
@ -28,7 +28,8 @@ icecast_port = 8000
|
|||
icecast_pass = "hackme"
|
||||
|
||||
# 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 = "pypo_intra"
|
||||
|
@ -38,3 +39,10 @@ intra_host = "127.0.0.1"
|
|||
intra_port = 9000
|
||||
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("server.telnet", true)
|
||||
|
||||
active_queue = ref 0
|
||||
|
||||
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)
|
||||
queue = request.queue(conservative=true,length=600.,id="queue")
|
||||
queue = audio_to_stereo(queue)
|
||||
|
||||
pypo_data = ref '0'
|
||||
|
||||
# push function, enqueues file in inactive queue (does not start automatically)
|
||||
def scheduler_push(s)
|
||||
ignore(server.execute("scheduler_q#{!active_queue}.push #{s}"))
|
||||
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 notify(m)
|
||||
# print("./notify.sh --data='#{!pypo_data}' --media-id=#{m['media_id']}")
|
||||
#end
|
||||
|
||||
def crossfade(s)
|
||||
s = fade.in(type="log", s)
|
||||
|
@ -49,23 +21,42 @@ def crossfade(s)
|
|||
cross(fader,s)
|
||||
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)
|
||||
|
||||
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)
|
||||
clock(id="clock_icecast",
|
||||
output.icecast(%mp3,
|
||||
host = icecast_host, port = icecast_port,
|
||||
password = icecast_pass, mount = mount_scheduler,
|
||||
fallible = true,
|
||||
restart = true,
|
||||
restart_delay = 5,
|
||||
buffer(radio)))
|
||||
if output_sound_device then
|
||||
out_device = out(s)
|
||||
end
|
||||
|
||||
if output_icecast_mp3 then
|
||||
out_mp3 = output.icecast(%mp3,
|
||||
host = icecast_host, port = icecast_port,
|
||||
password = icecast_pass, mount = mount_point_mp3,
|
||||
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 telnetlib
|
||||
|
||||
from util import json
|
||||
import json
|
||||
|
||||
import os
|
||||
|
||||
|
@ -26,7 +25,7 @@ class Status:
|
|||
# lookup OBP version
|
||||
try:
|
||||
response = urllib.urlopen(self.status_url)
|
||||
response_json = json.read(response.read())
|
||||
response_json = json.loads(response.read())
|
||||
obp_version = int(response_json['version'])
|
||||
logger.debug("OBP Version %s detected", obp_version)
|
||||
|
||||
|
|
Loading…
Reference in New Issue