Merge branch 'devel' of dev.sourcefabric.org:airtime into devel

This commit is contained in:
martin 2011-05-17 11:55:27 -04:00
commit 9afab251c5
9 changed files with 233 additions and 96 deletions

View File

@ -5,8 +5,8 @@
* /etc/airtime/pypo.cfg
* /etc/airtime/recorder.cfg
*/
define('AIRTIME_VERSION', '1.9.0-devel');
define('AIRTIME_VERSION', '1.8.2');
define('AIRTIME_COPYRIGHT_DATE', '2010-2011');
define('AIRTIME_REST_VERSION', '1.1');

View File

@ -107,8 +107,8 @@ system("python ".__DIR__."/../python_apps/pypo/install/pypo-install.py");
echo PHP_EOL."*** Recorder Installation ***".PHP_EOL;
system("python ".__DIR__."/../python_apps/show-recorder/install/recorder-install.py");
echo PHP_EOL."*** Media Monitor Installation ***".PHP_EOL;
system("python ".__DIR__."/../python_apps/pytag-fs/install/media-monitor-install.py");
//echo PHP_EOL."*** Media Monitor Installation ***".PHP_EOL;
//system("python ".__DIR__."/../python_apps/pytag-fs/install/media-monitor-install.py");
AirtimeInstall::SetAirtimeVersion(AIRTIME_VERSION);

View File

@ -88,9 +88,9 @@ echo PHP_EOL."*** Uninstalling Show Recorder ***".PHP_EOL;
$command = "python ".__DIR__."/../python_apps/show-recorder/install/recorder-uninstall.py";
system($command);
echo PHP_EOL."*** Uninstalling Media Monitor ***".PHP_EOL;
$command = "python ".__DIR__."/../python_apps/pytag-fs/install/media-monitor-uninstall.py";
system($command);
//echo PHP_EOL."*** Uninstalling Media Monitor ***".PHP_EOL;
//$command = "python ".__DIR__."/../python_apps/pytag-fs/install/media-monitor-uninstall.py";
//system($command);
#Disabled as this should be a manual process
#AirtimeIni::RemoveIniFiles();

View File

@ -34,18 +34,24 @@ if(strcmp($version, "1.7.0") < 0) {
if(strcmp($version, "1.8.0") < 0) {
system("php ".__DIR__."/upgrades/airtime-1.8/airtime-upgrade.php");
}
if (strcmp($version, "1.9.0") < 0){
system("php ".__DIR__."/upgrades/airtime-1.9/airtime-upgrade.php");
if(strcmp($version, "1.8.1") < 0) {
system("php ".__DIR__."/upgrades/airtime-1.8.1/airtime-upgrade.php");
}
if(strcmp($version, "1.8.2") < 0) {
system("php ".__DIR__."/upgrades/airtime-1.8.2/airtime-upgrade.php");
}
//if (strcmp($version, "1.9.0") < 0){
//system("php ".__DIR__."/upgrades/airtime-1.9/airtime-upgrade.php");
//}
AirtimeInstall::SetAirtimeVersion(AIRTIME_VERSION);
echo PHP_EOL."*** Updating Pypo ***".PHP_EOL;
system("python ".__DIR__."/../python_apps/pypo/install/pypo-install.py");
echo PHP_EOL."*** Updating Recorder ***".PHP_EOL;
system("python ".__DIR__."/../python_apps/show-recorder/install/recorder-install.py");
echo PHP_EOL."*** Updating Pypo ***".PHP_EOL;
system("python ".__DIR__."/../python_apps/pypo/install/pypo-install.py");
echo "******************************* Update Complete *******************************".PHP_EOL;

View File

@ -184,4 +184,55 @@ class AirtimeIni
AirtimeIni::UpdateIniValue(AirtimeIni::CONF_FILE_MEDIAMONITOR, 'api_key', "'$api_key'");
AirtimeIni::UpdateIniValue(AirtimeInstall::CONF_DIR_WWW.'/build/build.properties', 'project.home', AirtimeInstall::CONF_DIR_WWW);
}
public static function ReadPythonConfig($p_filename)
{
$values = array();
$lines = file($p_filename);
$n=count($lines);
for ($i=0; $i<$n; $i++) {
if (strlen($lines[$i]) && !in_array(substr($lines[$i], 0, 1), array('#', PHP_EOL))){
$info = explode("=", $lines[$i]);
$values[trim($info[0])] = trim($info[1]);
}
}
return $values;
}
public static function MergeConfigFiles($configFiles, $suffix) {
foreach ($configFiles as $conf) {
if (file_exists("$conf$suffix.bak")) {
if($conf === CONF_FILE_AIRTIME) {
// Parse with sections
$newSettings = parse_ini_file($conf, true);
$oldSettings = parse_ini_file("$conf$suffix.bak", true);
}
else {
$newSettings = AirtimeIni::ReadPythonConfig($conf);
$oldSettings = AirtimeIni::ReadPythonConfig("$conf$suffix.bak");
}
$settings = array_keys($newSettings);
foreach($settings as $section) {
if(isset($oldSettings[$section])) {
if(is_array($oldSettings[$section])) {
$sectionKeys = array_keys($newSettings[$section]);
foreach($sectionKeys as $sectionKey) {
if(isset($oldSettings[$section][$sectionKey])) {
AirtimeIni::UpdateIniValue($conf, $sectionKey, $oldSettings[$section][$sectionKey]);
}
}
}
else {
AirtimeIni::UpdateIniValue($conf, $section, $oldSettings[$section]);
}
}
}
}
}
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* @package Airtime
* @subpackage StorageServer
* @copyright 2010 Sourcefabric O.P.S.
* @license http://www.gnu.org/licenses/gpl.txt
*/
set_include_path(__DIR__.'/../../../airtime_mvc/library' . PATH_SEPARATOR . get_include_path());
require_once __DIR__.'/../../../airtime_mvc/application/configs/conf.php';
require_once(dirname(__FILE__).'/../../include/AirtimeInstall.php');
require_once(dirname(__FILE__).'/../../include/AirtimeIni.php');
const CONF_FILE_AIRTIME = "/etc/airtime/airtime.conf";
const CONF_FILE_PYPO = "/etc/airtime/pypo.cfg";
const CONF_FILE_RECORDER = "/etc/airtime/recorder.cfg";
const CONF_FILE_LIQUIDSOAP = "/etc/airtime/liquidsoap.cfg";
$configFiles = array(CONF_FILE_AIRTIME,
CONF_FILE_PYPO,
CONF_FILE_RECORDER,
CONF_FILE_LIQUIDSOAP);
$suffix = date("Ymdhis");
foreach ($configFiles as $conf) {
if (file_exists($conf)) {
echo "Backing up $conf to $conf$suffix.bak".PHP_EOL;
exec("cp $conf $conf$suffix.bak");
}
}
AirtimeIni::CreateIniFiles();
echo "* Initializing INI files".PHP_EOL;
AirtimeIni::MergeConfigFiles($configFiles, $suffix);
global $CC_CONFIG;
$CC_CONFIG = Config::loadConfig($CC_CONFIG);
AirtimeInstall::InstallPhpCode();
AirtimeInstall::InstallBinaries();

View File

@ -0,0 +1,40 @@
<?php
/**
* @package Airtime
* @subpackage StorageServer
* @copyright 2010 Sourcefabric O.P.S.
* @license http://www.gnu.org/licenses/gpl.txt
*/
set_include_path(__DIR__.'/../../../airtime_mvc/library' . PATH_SEPARATOR . get_include_path());
require_once __DIR__.'/../../../airtime_mvc/application/configs/conf.php';
require_once(dirname(__FILE__).'/../../include/AirtimeInstall.php');
require_once(dirname(__FILE__).'/../../include/AirtimeIni.php');
const CONF_FILE_AIRTIME = "/etc/airtime/airtime.conf";
const CONF_FILE_PYPO = "/etc/airtime/pypo.cfg";
const CONF_FILE_RECORDER = "/etc/airtime/recorder.cfg";
const CONF_FILE_LIQUIDSOAP = "/etc/airtime/liquidsoap.cfg";
$configFiles = array(CONF_FILE_AIRTIME,
CONF_FILE_PYPO,
CONF_FILE_RECORDER,
CONF_FILE_LIQUIDSOAP);
$suffix = date("Ymdhis");
foreach ($configFiles as $conf) {
if (file_exists($conf)) {
echo "Backing up $conf to $conf$suffix.bak".PHP_EOL;
exec("cp $conf $conf$suffix.bak");
}
}
AirtimeIni::CreateIniFiles();
echo "* Initializing INI files".PHP_EOL;
AirtimeIni::MergeConfigFiles($configFiles, $suffix);
global $CC_CONFIG;
$CC_CONFIG = Config::loadConfig($CC_CONFIG);
AirtimeInstall::InstallPhpCode();
AirtimeInstall::InstallBinaries();

View File

@ -61,7 +61,8 @@ AirtimeInstall::InstallBinaries();
echo "* Initializing INI files".PHP_EOL;
AirtimeIni::UpdateIniFiles();
Config::loadConfig();
global $CC_CONFIG;
$CC_CONFIG = Config::loadConfig($CC_CONFIG);
echo "* Creating default storage directory".PHP_EOL;
AirtimeInstall::InstallStorageDirectory();

View File

@ -19,10 +19,10 @@ import json
import os
from urlparse import urlparse
AIRTIME_VERSION = "1.9.0"
AIRTIME_VERSION = "1.8.2"
def api_client_factory(config):
if config["api_client"] == "airtime":
if config["api_client"] == "airtime":
return AirTimeApiClient(config)
elif config["api_client"] == "obp":
return ObpApiClient(config)
@ -59,7 +59,7 @@ class ApiClientInterface:
# 3rd party software.
def is_server_compatible(self, verbose = True):
pass
# Implementation: Required
#
# Called from: fetch loop
@ -69,7 +69,7 @@ class ApiClientInterface:
# start and end are strings in the format YYYY-DD-MM-hh-mm-ss
def get_schedule(self, start=None, end=None):
return 0, []
# Implementation: Required
#
# Called from: fetch loop
@ -77,7 +77,7 @@ class ApiClientInterface:
# This downloads the media from the server.
def get_media(self, src, dst):
pass
# Implementation: optional
#
# Called from: push loop
@ -85,7 +85,7 @@ class ApiClientInterface:
# Tell server that the scheduled *playlist* has started.
def notify_scheduled_item_start_playing(self, pkey, schedule):
pass
# Implementation: optional
# You dont actually have to implement this function for the liquidsoap playout to work.
#
@ -96,7 +96,7 @@ class ApiClientInterface:
# liquidsoap in get_liquidsoap_data().
def notify_media_item_start_playing(self, data, media_id):
pass
# Implementation: optional
# You dont actually have to implement this function for the liquidsoap playout to work.
def generate_range_dp(self):
@ -119,12 +119,12 @@ class ApiClientInterface:
def update_media_metadata(self, md):
pass
# Put here whatever tests you want to run to make sure your API is working
def test(self):
pass
#def get_media_type(self, playlist):
# nil
@ -151,7 +151,7 @@ class AirTimeApiClient(ApiClientInterface):
logger.debug("Data: %s", data)
response_json = json.loads(data)
version = response_json['version']
logger.debug("Airtime Version %s detected", version)
logger.debug("Airtime Version %s detected", version)
except Exception, e:
if e[1] == 401:
if (verbose):
@ -195,30 +195,30 @@ class AirTimeApiClient(ApiClientInterface):
if (verbose):
print 'Unable to get Airtime version number.'
print
return False
elif (version[0:3] != AIRTIME_VERSION):
return False
elif (version[0:3] != AIRTIME_VERSION[0:3]):
if (verbose):
print 'Airtime version: ' + str(version)
print 'pypo not compatible with this version of Airtime.'
print 'Airtime version found: ' + str(version)
print 'pypo is at version ' +AIRTIME_VERSION+' and is not compatible with this version of Airtime.'
print
return False
return False
else:
if (verbose):
print 'Airtime version: ' + str(version)
print 'pypo is compatible with this version of Airtime.'
print 'pypo is at version ' +AIRTIME_VERSION+' and is compatible with this version of Airtime.'
print
return True
def get_schedule(self, start=None, end=None):
logger = logging.getLogger()
# Construct the URL
export_url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["export_url"])
logger.info("Fetching schedule from %s", export_url)
export_url = export_url.replace('%%api_key%%', self.config["api_key"])
response = ""
status = 0
try:
@ -233,7 +233,7 @@ class AirTimeApiClient(ApiClientInterface):
def get_media(self, uri, dst):
logger = logging.getLogger()
try:
src = uri + "/api_key/%%api_key%%"
logger.info("try to download from %s to %s", src, dst)
@ -251,24 +251,24 @@ class AirTimeApiClient(ApiClientInterface):
def notify_scheduled_item_start_playing(self, pkey, schedule):
logger = logging.getLogger()
playlist = schedule[pkey]
schedule_id = playlist["schedule_id"]
schedule_id = playlist["schedule_id"]
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["update_item_url"])
url = url.replace("%%schedule_id%%", str(schedule_id))
logger.debug(url)
url = url.replace("%%api_key%%", self.config["api_key"])
try:
response = urllib.urlopen(url)
response = json.loads(response.read())
logger.info("API-Status %s", response['status'])
logger.info("API-Message %s", response['message'])
except Exception, e:
logger.error("Unable to connect - %s", e)
return response
"""
This is a callback from liquidsoap, we use this to notify about the
@ -289,12 +289,12 @@ class AirTimeApiClient(ApiClientInterface):
response = json.loads(response.read())
logger.info("API-Status %s", response['status'])
logger.info("API-Message %s", response['message'])
except Exception, e:
logger.error("Exception: %s", e)
return response
def get_liquidsoap_data(self, pkey, schedule):
logger = logging.getLogger()
playlist = schedule[pkey]
@ -312,14 +312,14 @@ class AirTimeApiClient(ApiClientInterface):
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["show_schedule_url"])
logger.debug(url)
url = url.replace("%%api_key%%", self.config["api_key"])
response = urllib.urlopen(url)
response = json.loads(response.read())
logger.info("shows %s", response)
except Exception, e:
logger.error("Exception: %s", e)
return response
def upload_recorded_show(self, data, headers):
@ -337,13 +337,13 @@ class AirTimeApiClient(ApiClientInterface):
for i in range(0, retries):
logger.debug("Upload attempt: %s", i+1)
try:
try:
request = urllib2.Request(url, data, headers)
response = urllib2.urlopen(request).read().strip()
logger.info("uploaded show result %s", response)
break
except urllib2.HTTPError, e:
logger.error("Http error code: %s", e.code)
except urllib2.URLError, e:
@ -353,7 +353,7 @@ class AirTimeApiClient(ApiClientInterface):
#wait some time before next retry
time.sleep(retries_wait)
return response
def update_media_metadata(self, md):
@ -363,7 +363,7 @@ class AirTimeApiClient(ApiClientInterface):
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["update_media_url"])
logger.debug(url)
url = url.replace("%%api_key%%", self.config["api_key"])
data = recursive_urlencode(md)
req = urllib2.Request(url, data)
@ -373,11 +373,11 @@ class AirTimeApiClient(ApiClientInterface):
except Exception, e:
logger.error("Exception: %s", e)
return response
return response
################################################################################
# OpenBroadcast API Client
################################################################################
@ -385,16 +385,16 @@ class AirTimeApiClient(ApiClientInterface):
# https://lab.digris.ch/svn/elgg/trunk/unstable/mod/medialibrary/application/controllers/api/pypo.php
OBP_MIN_VERSION = 2010100101 # required obp version
class ObpApiClient():
def __init__(self, config):
self.config = config
self.api_auth = urllib.urlencode({'api_key': self.config["api_key"]})
def is_server_compatible(self, verbose = True):
obp_version = self.get_obp_version()
if obp_version == 0:
if (verbose):
print '#################################################'
@ -417,23 +417,23 @@ class ObpApiClient():
print 'pypo is compatible with this version of OBP'
print
return True
def get_obp_version(self):
logger = logging.getLogger()
# lookup OBP version
# lookup OBP version
#url = self.config["base_url"] + self.config["api_base"]+ self.config["version_url"]
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["version_url"])
try:
try:
logger.debug("Trying to contact %s", url)
response = urllib.urlopen(url, self.api_auth)
response_json = json.loads(response.read())
obp_version = int(response_json['version'])
logger.debug("OBP Version %s detected", obp_version)
except Exception, e:
try:
if e[1] == 401:
@ -442,10 +442,10 @@ class ObpApiClient():
print '# ' + self.config["api_auth"]
print '#####################################'
sys.exit()
except Exception, e:
pass
try:
if e[1] == 404:
print '#####################################'
@ -453,19 +453,19 @@ class ObpApiClient():
print '# ' + url
print '#####################################'
sys.exit()
except Exception, e:
pass
obp_version = 0
logger.error("Unable to detect OBP Version - %s", e)
return obp_version
def get_schedule(self, start=None, end=None):
logger = logging.getLogger()
"""
calculate start/end time range (format: YYYY-DD-MM-hh-mm-ss,YYYY-DD-MM-hh-mm-ss)
(seconds are ignored, just here for consistency)
@ -474,25 +474,25 @@ class ObpApiClient():
if (not start):
tstart = time.localtime(time.time() - 3600 * int(self.config["cache_for"]))
start = "%04d-%02d-%02d-%02d-%02d" % (tstart[0], tstart[1], tstart[2], tstart[3], tstart[4])
if (not end):
if (not end):
tend = time.localtime(time.time() + 3600 * int(self.config["prepare_ahead"]))
end = "%04d-%02d-%02d-%02d-%02d" % (tend[0], tend[1], tend[2], tend[3], tend[4])
range = {}
range['start'] = start
range['end'] = end
# Construct the URL
#export_url = self.config["base_url"] + self.config["api_base"] + self.config["export_url"]
export_url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["export_url"])
# Insert the start and end times into the URL
# Insert the start and end times into the URL
export_url = export_url.replace('%%api_key%%', self.config["api_key"])
export_url = export_url.replace('%%from%%', range['start'])
export_url = export_url.replace('%%to%%', range['end'])
logger.info("export from %s", export_url)
response = ""
status = 0
try:
@ -504,9 +504,9 @@ class ObpApiClient():
except Exception, e:
print e
return status, response
return status, response
def get_media(self, src, dest):
try:
print '** urllib auth with: ',
@ -527,75 +527,75 @@ class ObpApiClient():
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["update_item_url"])
url = url.replace("%%item_id%%", str(schedule[pkey]["id"]))
url = url.replace("%%played%%", "1")
try:
response = urllib.urlopen(url, self.api_auth)
response = json.loads(response.read())
logger.info("API-Status %s", response['status'])
logger.info("API-Message %s", response['message'])
except Exception, e:
print e
api_status = False
logger.error("Unable to connect to the OBP API - %s", e)
return response
"""
This is a callback from liquidsoap, we use this to notify about the
currently playing *song*. We get passed a JSON string which we handed to
liquidsoap in get_liquidsoap_data().
"""
def notify_media_item_start_playing(self, data, media_id):
def notify_media_item_start_playing(self, data, media_id):
# def update_start_playing(self, playlist_type, export_source, media_id, playlist_id, transmission_id):
logger = logging.getLogger()
playlist_type = data["playlist_type"]
export_source = data["export_source"]
playlist_id = data["playlist_id"]
transmission_id = data["transmission_id"]
#url = self.config["base_url"] + self.config["api_base"] + self.config["update_start_playing_url"]
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["update_start_playing_url"])
url = url.replace("%%playlist_type%%", str(playlist_type))
url = url.replace("%%export_source%%", str(export_source))
url = url.replace("%%media_id%%", str(media_id))
url = url.replace("%%playlist_id%%", str(playlist_id))
url = url.replace("%%transmission_id%%", str(transmission_id))
url = url.replace("%%transmission_id%%", str(transmission_id))
print url
try:
response = urllib.urlopen(url, self.api_auth)
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'])
except Exception, e:
print e
api_status = False
logger.error("Unable to connect to the OBP API - %s", e)
return response
def generate_range_dp(self):
logger = logging.getLogger()
#url = self.config["base_url"] + self.config["api_base"] + self.config["generate_range_url"]
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["generate_range_url"])
try:
response = urllib.urlopen(url, self.api_auth)
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'])
except Exception, e:
print e
api_status = False
logger.error("Unable to handle the OBP API request - %s", e)
return response
def get_liquidsoap_data(self, pkey, schedule):
@ -612,4 +612,4 @@ class ObpApiClient():
data["transmission_id"] = 0
data = json.dumps(data)
return data