diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index 1684e9b1d..4925d7ab5 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -34,6 +34,7 @@ class ApiController extends Zend_Controller_Action ->addActionContext('get-bootstrap-info', 'json') ->addActionContext('get-files-without-replay-gain', 'json') ->addActionContext('reload-metadata-group', 'json') + ->addActionContext('notify-webstream-data', 'json') ->initContext(); } @@ -349,12 +350,15 @@ class ApiController extends Zend_Controller_Action //set a 'last played' timestamp for media item //needed for smart playlists - try{ + try { $file_id = Application_Model_Schedule::GetFileId($media_id); - $file = Application_Model_StoredFile::Recall($file_id); - $now = new DateTime("now", new DateTimeZone("UTC")); - $file->setLastPlayedTime($now); - }catch(Exception $e){ + if (!is_null($file_id)) { + //we are dealing with a file not a stream + $file = Application_Model_StoredFile::Recall($file_id); + $now = new DateTime("now", new DateTimeZone("UTC")); + $file->setLastPlayedTime($now); + } + } catch (Exception $e) { Logging::log($e); } @@ -368,9 +372,11 @@ class ApiController extends Zend_Controller_Action $end_timestamp = $now->add(new DateInterval("PT2H")); $end_timestamp = $end_timestamp->format("Y-m-d H:i:s"); - $this->view->shows = Application_Model_Show::getShows(Application_Common_DateHelper::ConvertToUtcDateTime($today_timestamp, date_default_timezone_get()), - Application_Common_DateHelper::ConvertToUtcDateTime($end_timestamp, date_default_timezone_get()), - $excludeInstance=NULL, $onlyRecord=TRUE); + $this->view->shows = + Application_Model_Show::getShows( + Application_Common_DateHelper::ConvertToUtcDateTime($today_timestamp, date_default_timezone_get()), + Application_Common_DateHelper::ConvertToUtcDateTime($end_timestamp, date_default_timezone_get()), + $excludeInstance = null, $onlyRecord = true); $this->view->is_recording = false; @@ -394,11 +400,12 @@ class ApiController extends Zend_Controller_Action $result = Application_Model_StoredFile::copyFileToStor($upload_dir, $fileName, $tempFileName); if (!is_null($result)) { - die('{"jsonrpc" : "2.0", "error" : {"code": '.$result[code].', "message" : "'.$result[message].'"}}'); + die('{"jsonrpc" : "2.0", "error" : {"code": '.$result['code'].', "message" : "'.$result['message'].'"}}'); } } - public function uploadRecordedAction() { + public function uploadRecordedAction() + { $show_instance_id = $this->_getParam('showinstanceid'); $file_id = $this->_getParam('fileid'); $this->view->fileid = $file_id; @@ -422,7 +429,7 @@ class ApiController extends Zend_Controller_Action $show_genre = $show_inst->getGenre(); $show_start_time = Application_Common_DateHelper::ConvertToLocalDateTimeString($show_inst->getShowInstanceStart()); - } catch (Exception $e) { + } catch (Exception $e) { //we've reached here probably because the show was //cancelled, and therefore the show instance does not //exist anymore (ShowInstance constructor threw this error). @@ -1015,4 +1022,34 @@ class ApiController extends Zend_Controller_Action $file->save(); } } + + public function notifyWebstreamDataAction() + { + $request = $this->getRequest(); + $data = $request->getParam("data"); + $media_id = $request->getParam("media_id"); + + $schedule = CcScheduleQuery::create()->findPK($media_id); + $stream_id = $schedule->getDbStreamId(); + + if (!is_null($stream_id)) { + $webstream = CcWebstreamQuery::create()->findPK($stream_id); + if (strlen($data) <= 1024) { + $data_arr = json_decode($data); + if (isset($data_arr->title)) { + $webstream->setDbLiquidsoapData($data_arr->title); + } else { + $webstream->setDbLiquidsoapData(''); + } + $webstream->save(); + } + } else { + throw new Error("Unexpected error. media_id $media_id has a null stream value in cc_schedule!"); + } + + Logging::log(json_decode($data)); + $this->view->response = $data; + $this->view->media_id = $media_id; + } + } diff --git a/airtime_mvc/application/controllers/AudiopreviewController.php b/airtime_mvc/application/controllers/AudiopreviewController.php index e32ba730a..320921444 100644 --- a/airtime_mvc/application/controllers/AudiopreviewController.php +++ b/airtime_mvc/application/controllers/AudiopreviewController.php @@ -191,8 +191,14 @@ class AudiopreviewController extends Zend_Controller_Action 'element_id' => isset($track['id'])?$track['id']:"", 'element_position' => isset($track['position'])?$track['position']:"", ); - - + + /* If the track type is static we know it must be + * a track because static blocks can only contain + * tracks + */ + if ($track['type'] == 'static') { + $track['type'] = 0; + } $elementMap['type'] = $track['type']; if ($track['type'] == 0) { diff --git a/airtime_mvc/application/models/Block.php b/airtime_mvc/application/models/Block.php index 617f53265..d8f75fcb0 100644 --- a/airtime_mvc/application/models/Block.php +++ b/airtime_mvc/application/models/Block.php @@ -1160,12 +1160,13 @@ EOT; } else if ($spCriteriaModifier == "is in the range") { $spCriteriaValue = "$spCriteria > '$spCriteriaValue' AND $spCriteria < '$criteria[extra]'"; } + $spCriteriaModifier = self::$modifier2CriteriaMap[$spCriteriaModifier]; try{ if ($i > 0) { - $qry->addOr($spCriteria, $spCriteriaValue, $spCriteriaModifier); + $qry->addOr($spCriteria, addslashes($spCriteriaValue), $spCriteriaModifier); } else { - $qry->add($spCriteria, $spCriteriaValue, $spCriteriaModifier); + $qry->add($spCriteria, addslashes($spCriteriaValue), $spCriteriaModifier); } }catch (Exception $e){ Logging::log($e); diff --git a/airtime_mvc/application/models/Datatables.php b/airtime_mvc/application/models/Datatables.php index 01971a139..66737b7d9 100644 --- a/airtime_mvc/application/models/Datatables.php +++ b/airtime_mvc/application/models/Datatables.php @@ -95,6 +95,11 @@ class Application_Model_Datatables $r['length'] = $pl->getLength(); } else if ($r['ftype'] == "block") { $bl = new Application_Model_Block($r['id']); + if ($bl->isStatic()) { + $r['bl_type'] = 'static'; + } else { + $r['bl_type'] = 'dynamic'; + } $r['length'] = $bl->getLength(); } } diff --git a/airtime_mvc/application/models/Schedule.php b/airtime_mvc/application/models/Schedule.php index c09eef089..863417751 100644 --- a/airtime_mvc/application/models/Schedule.php +++ b/airtime_mvc/application/models/Schedule.php @@ -80,12 +80,10 @@ class Application_Model_Schedule %%tables%% WHERE "; $fileColumns = "ft.artist_name, ft.track_title, "; - //$fileJoin = "cc_files ft ON st.file_id = ft.id"; $fileJoin = "FROM cc_schedule st JOIN cc_files ft ON st.file_id = ft.id LEFT JOIN cc_show_instances si ON st.instance_id = si.id"; - $streamColumns = "sub.login as artist_name, ws.name as track_title, "; - //$streamJoin = "cc_webstream ws ON st.stream_id = ws.id"; + $streamColumns = "ws.name as artist_name, ws.liquidsoap_data as track_title, "; $streamJoin = "FROM cc_schedule st JOIN cc_webstream ws ON st.stream_id = ws.id LEFT JOIN cc_show_instances si ON st.instance_id = si.id LEFT JOIN cc_subjs as sub on sub.id = ws.creator_id"; diff --git a/airtime_mvc/application/models/airtime/map/CcWebstreamTableMap.php b/airtime_mvc/application/models/airtime/map/CcWebstreamTableMap.php index 5121aa39b..d48953ae6 100644 --- a/airtime_mvc/application/models/airtime/map/CcWebstreamTableMap.php +++ b/airtime_mvc/application/models/airtime/map/CcWebstreamTableMap.php @@ -47,6 +47,7 @@ class CcWebstreamTableMap extends TableMap { $this->addColumn('MTIME', 'DbMtime', 'TIMESTAMP', true, 6, null); $this->addColumn('UTIME', 'DbUtime', 'TIMESTAMP', true, 6, null); $this->addColumn('MIME', 'DbMime', 'VARCHAR', false, 255, null); + $this->addColumn('LIQUIDSOAP_DATA', 'DbLiquidsoapData', 'VARCHAR', false, 1024, null); // validators } // initialize() diff --git a/airtime_mvc/application/models/airtime/om/BaseCcWebstream.php b/airtime_mvc/application/models/airtime/om/BaseCcWebstream.php index e5faf12fd..c8a8e8be9 100644 --- a/airtime_mvc/application/models/airtime/om/BaseCcWebstream.php +++ b/airtime_mvc/application/models/airtime/om/BaseCcWebstream.php @@ -79,6 +79,12 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent */ protected $mime; + /** + * The value for the liquidsoap_data field. + * @var string + */ + protected $liquidsoap_data; + /** * @var array CcSchedule[] Collection to store aggregation of CcSchedule objects. */ @@ -255,6 +261,16 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent return $this->mime; } + /** + * Get the [liquidsoap_data] column value. + * + * @return string + */ + public function getDbLiquidsoapData() + { + return $this->liquidsoap_data; + } + /** * Set the value of [id] column. * @@ -493,6 +509,26 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent return $this; } // setDbMime() + /** + * Set the value of [liquidsoap_data] column. + * + * @param string $v new value + * @return CcWebstream The current object (for fluent API support) + */ + public function setDbLiquidsoapData($v) + { + if ($v !== null) { + $v = (string) $v; + } + + if ($this->liquidsoap_data !== $v) { + $this->liquidsoap_data = $v; + $this->modifiedColumns[] = CcWebstreamPeer::LIQUIDSOAP_DATA; + } + + return $this; + } // setDbLiquidsoapData() + /** * Indicates whether the columns in this object are only set to default values. * @@ -538,6 +574,7 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent $this->mtime = ($row[$startcol + 6] !== null) ? (string) $row[$startcol + 6] : null; $this->utime = ($row[$startcol + 7] !== null) ? (string) $row[$startcol + 7] : null; $this->mime = ($row[$startcol + 8] !== null) ? (string) $row[$startcol + 8] : null; + $this->liquidsoap_data = ($row[$startcol + 9] !== null) ? (string) $row[$startcol + 9] : null; $this->resetModified(); $this->setNew(false); @@ -546,7 +583,7 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent $this->ensureConsistency(); } - return $startcol + 9; // 9 = CcWebstreamPeer::NUM_COLUMNS - CcWebstreamPeer::NUM_LAZY_LOAD_COLUMNS). + return $startcol + 10; // 10 = CcWebstreamPeer::NUM_COLUMNS - CcWebstreamPeer::NUM_LAZY_LOAD_COLUMNS). } catch (Exception $e) { throw new PropelException("Error populating CcWebstream object", $e); @@ -890,6 +927,9 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent case 8: return $this->getDbMime(); break; + case 9: + return $this->getDbLiquidsoapData(); + break; default: return null; break; @@ -922,6 +962,7 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent $keys[6] => $this->getDbMtime(), $keys[7] => $this->getDbUtime(), $keys[8] => $this->getDbMime(), + $keys[9] => $this->getDbLiquidsoapData(), ); return $result; } @@ -980,6 +1021,9 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent case 8: $this->setDbMime($value); break; + case 9: + $this->setDbLiquidsoapData($value); + break; } // switch() } @@ -1013,6 +1057,7 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent if (array_key_exists($keys[6], $arr)) $this->setDbMtime($arr[$keys[6]]); if (array_key_exists($keys[7], $arr)) $this->setDbUtime($arr[$keys[7]]); if (array_key_exists($keys[8], $arr)) $this->setDbMime($arr[$keys[8]]); + if (array_key_exists($keys[9], $arr)) $this->setDbLiquidsoapData($arr[$keys[9]]); } /** @@ -1033,6 +1078,7 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent if ($this->isColumnModified(CcWebstreamPeer::MTIME)) $criteria->add(CcWebstreamPeer::MTIME, $this->mtime); if ($this->isColumnModified(CcWebstreamPeer::UTIME)) $criteria->add(CcWebstreamPeer::UTIME, $this->utime); if ($this->isColumnModified(CcWebstreamPeer::MIME)) $criteria->add(CcWebstreamPeer::MIME, $this->mime); + if ($this->isColumnModified(CcWebstreamPeer::LIQUIDSOAP_DATA)) $criteria->add(CcWebstreamPeer::LIQUIDSOAP_DATA, $this->liquidsoap_data); return $criteria; } @@ -1102,6 +1148,7 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent $copyObj->setDbMtime($this->mtime); $copyObj->setDbUtime($this->utime); $copyObj->setDbMime($this->mime); + $copyObj->setDbLiquidsoapData($this->liquidsoap_data); if ($deepCopy) { // important: temporarily setNew(false) because this affects the behavior of @@ -1332,6 +1379,7 @@ abstract class BaseCcWebstream extends BaseObject implements Persistent $this->mtime = null; $this->utime = null; $this->mime = null; + $this->liquidsoap_data = null; $this->alreadyInSave = false; $this->alreadyInValidation = false; $this->clearAllReferences(); diff --git a/airtime_mvc/application/models/airtime/om/BaseCcWebstreamPeer.php b/airtime_mvc/application/models/airtime/om/BaseCcWebstreamPeer.php index 4ec74befd..abf506bdd 100644 --- a/airtime_mvc/application/models/airtime/om/BaseCcWebstreamPeer.php +++ b/airtime_mvc/application/models/airtime/om/BaseCcWebstreamPeer.php @@ -26,7 +26,7 @@ abstract class BaseCcWebstreamPeer { const TM_CLASS = 'CcWebstreamTableMap'; /** The total number of columns. */ - const NUM_COLUMNS = 9; + const NUM_COLUMNS = 10; /** The number of lazy-loaded columns. */ const NUM_LAZY_LOAD_COLUMNS = 0; @@ -58,6 +58,9 @@ abstract class BaseCcWebstreamPeer { /** the column name for the MIME field */ const MIME = 'cc_webstream.MIME'; + /** the column name for the LIQUIDSOAP_DATA field */ + const LIQUIDSOAP_DATA = 'cc_webstream.LIQUIDSOAP_DATA'; + /** * An identiy map to hold any loaded instances of CcWebstream objects. * This must be public so that other peer classes can access this when hydrating from JOIN @@ -74,12 +77,12 @@ abstract class BaseCcWebstreamPeer { * e.g. self::$fieldNames[self::TYPE_PHPNAME][0] = 'Id' */ private static $fieldNames = array ( - BasePeer::TYPE_PHPNAME => array ('DbId', 'DbName', 'DbDescription', 'DbUrl', 'DbLength', 'DbCreatorId', 'DbMtime', 'DbUtime', 'DbMime', ), - BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbName', 'dbDescription', 'dbUrl', 'dbLength', 'dbCreatorId', 'dbMtime', 'dbUtime', 'dbMime', ), - BasePeer::TYPE_COLNAME => array (self::ID, self::NAME, self::DESCRIPTION, self::URL, self::LENGTH, self::CREATOR_ID, self::MTIME, self::UTIME, self::MIME, ), - BasePeer::TYPE_RAW_COLNAME => array ('ID', 'NAME', 'DESCRIPTION', 'URL', 'LENGTH', 'CREATOR_ID', 'MTIME', 'UTIME', 'MIME', ), - BasePeer::TYPE_FIELDNAME => array ('id', 'name', 'description', 'url', 'length', 'creator_id', 'mtime', 'utime', 'mime', ), - BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, ) + BasePeer::TYPE_PHPNAME => array ('DbId', 'DbName', 'DbDescription', 'DbUrl', 'DbLength', 'DbCreatorId', 'DbMtime', 'DbUtime', 'DbMime', 'DbLiquidsoapData', ), + BasePeer::TYPE_STUDLYPHPNAME => array ('dbId', 'dbName', 'dbDescription', 'dbUrl', 'dbLength', 'dbCreatorId', 'dbMtime', 'dbUtime', 'dbMime', 'dbLiquidsoapData', ), + BasePeer::TYPE_COLNAME => array (self::ID, self::NAME, self::DESCRIPTION, self::URL, self::LENGTH, self::CREATOR_ID, self::MTIME, self::UTIME, self::MIME, self::LIQUIDSOAP_DATA, ), + BasePeer::TYPE_RAW_COLNAME => array ('ID', 'NAME', 'DESCRIPTION', 'URL', 'LENGTH', 'CREATOR_ID', 'MTIME', 'UTIME', 'MIME', 'LIQUIDSOAP_DATA', ), + BasePeer::TYPE_FIELDNAME => array ('id', 'name', 'description', 'url', 'length', 'creator_id', 'mtime', 'utime', 'mime', 'liquidsoap_data', ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ) ); /** @@ -89,12 +92,12 @@ abstract class BaseCcWebstreamPeer { * e.g. self::$fieldNames[BasePeer::TYPE_PHPNAME]['Id'] = 0 */ private static $fieldKeys = array ( - BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbName' => 1, 'DbDescription' => 2, 'DbUrl' => 3, 'DbLength' => 4, 'DbCreatorId' => 5, 'DbMtime' => 6, 'DbUtime' => 7, 'DbMime' => 8, ), - BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbName' => 1, 'dbDescription' => 2, 'dbUrl' => 3, 'dbLength' => 4, 'dbCreatorId' => 5, 'dbMtime' => 6, 'dbUtime' => 7, 'dbMime' => 8, ), - BasePeer::TYPE_COLNAME => array (self::ID => 0, self::NAME => 1, self::DESCRIPTION => 2, self::URL => 3, self::LENGTH => 4, self::CREATOR_ID => 5, self::MTIME => 6, self::UTIME => 7, self::MIME => 8, ), - BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'NAME' => 1, 'DESCRIPTION' => 2, 'URL' => 3, 'LENGTH' => 4, 'CREATOR_ID' => 5, 'MTIME' => 6, 'UTIME' => 7, 'MIME' => 8, ), - BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, 'description' => 2, 'url' => 3, 'length' => 4, 'creator_id' => 5, 'mtime' => 6, 'utime' => 7, 'mime' => 8, ), - BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, ) + BasePeer::TYPE_PHPNAME => array ('DbId' => 0, 'DbName' => 1, 'DbDescription' => 2, 'DbUrl' => 3, 'DbLength' => 4, 'DbCreatorId' => 5, 'DbMtime' => 6, 'DbUtime' => 7, 'DbMime' => 8, 'DbLiquidsoapData' => 9, ), + BasePeer::TYPE_STUDLYPHPNAME => array ('dbId' => 0, 'dbName' => 1, 'dbDescription' => 2, 'dbUrl' => 3, 'dbLength' => 4, 'dbCreatorId' => 5, 'dbMtime' => 6, 'dbUtime' => 7, 'dbMime' => 8, 'dbLiquidsoapData' => 9, ), + BasePeer::TYPE_COLNAME => array (self::ID => 0, self::NAME => 1, self::DESCRIPTION => 2, self::URL => 3, self::LENGTH => 4, self::CREATOR_ID => 5, self::MTIME => 6, self::UTIME => 7, self::MIME => 8, self::LIQUIDSOAP_DATA => 9, ), + BasePeer::TYPE_RAW_COLNAME => array ('ID' => 0, 'NAME' => 1, 'DESCRIPTION' => 2, 'URL' => 3, 'LENGTH' => 4, 'CREATOR_ID' => 5, 'MTIME' => 6, 'UTIME' => 7, 'MIME' => 8, 'LIQUIDSOAP_DATA' => 9, ), + BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, 'description' => 2, 'url' => 3, 'length' => 4, 'creator_id' => 5, 'mtime' => 6, 'utime' => 7, 'mime' => 8, 'liquidsoap_data' => 9, ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ) ); /** @@ -175,6 +178,7 @@ abstract class BaseCcWebstreamPeer { $criteria->addSelectColumn(CcWebstreamPeer::MTIME); $criteria->addSelectColumn(CcWebstreamPeer::UTIME); $criteria->addSelectColumn(CcWebstreamPeer::MIME); + $criteria->addSelectColumn(CcWebstreamPeer::LIQUIDSOAP_DATA); } else { $criteria->addSelectColumn($alias . '.ID'); $criteria->addSelectColumn($alias . '.NAME'); @@ -185,6 +189,7 @@ abstract class BaseCcWebstreamPeer { $criteria->addSelectColumn($alias . '.MTIME'); $criteria->addSelectColumn($alias . '.UTIME'); $criteria->addSelectColumn($alias . '.MIME'); + $criteria->addSelectColumn($alias . '.LIQUIDSOAP_DATA'); } } diff --git a/airtime_mvc/application/models/airtime/om/BaseCcWebstreamQuery.php b/airtime_mvc/application/models/airtime/om/BaseCcWebstreamQuery.php index 101bbfbd1..3cc30c03f 100644 --- a/airtime_mvc/application/models/airtime/om/BaseCcWebstreamQuery.php +++ b/airtime_mvc/application/models/airtime/om/BaseCcWebstreamQuery.php @@ -15,6 +15,7 @@ * @method CcWebstreamQuery orderByDbMtime($order = Criteria::ASC) Order by the mtime column * @method CcWebstreamQuery orderByDbUtime($order = Criteria::ASC) Order by the utime column * @method CcWebstreamQuery orderByDbMime($order = Criteria::ASC) Order by the mime column + * @method CcWebstreamQuery orderByDbLiquidsoapData($order = Criteria::ASC) Order by the liquidsoap_data column * * @method CcWebstreamQuery groupByDbId() Group by the id column * @method CcWebstreamQuery groupByDbName() Group by the name column @@ -25,6 +26,7 @@ * @method CcWebstreamQuery groupByDbMtime() Group by the mtime column * @method CcWebstreamQuery groupByDbUtime() Group by the utime column * @method CcWebstreamQuery groupByDbMime() Group by the mime column + * @method CcWebstreamQuery groupByDbLiquidsoapData() Group by the liquidsoap_data column * * @method CcWebstreamQuery leftJoin($relation) Adds a LEFT JOIN clause to the query * @method CcWebstreamQuery rightJoin($relation) Adds a RIGHT JOIN clause to the query @@ -46,6 +48,7 @@ * @method CcWebstream findOneByDbMtime(string $mtime) Return the first CcWebstream filtered by the mtime column * @method CcWebstream findOneByDbUtime(string $utime) Return the first CcWebstream filtered by the utime column * @method CcWebstream findOneByDbMime(string $mime) Return the first CcWebstream filtered by the mime column + * @method CcWebstream findOneByDbLiquidsoapData(string $liquidsoap_data) Return the first CcWebstream filtered by the liquidsoap_data column * * @method array findByDbId(int $id) Return CcWebstream objects filtered by the id column * @method array findByDbName(string $name) Return CcWebstream objects filtered by the name column @@ -56,6 +59,7 @@ * @method array findByDbMtime(string $mtime) Return CcWebstream objects filtered by the mtime column * @method array findByDbUtime(string $utime) Return CcWebstream objects filtered by the utime column * @method array findByDbMime(string $mime) Return CcWebstream objects filtered by the mime column + * @method array findByDbLiquidsoapData(string $liquidsoap_data) Return CcWebstream objects filtered by the liquidsoap_data column * * @package propel.generator.airtime.om */ @@ -385,6 +389,28 @@ abstract class BaseCcWebstreamQuery extends ModelCriteria return $this->addUsingAlias(CcWebstreamPeer::MIME, $dbMime, $comparison); } + /** + * Filter the query on the liquidsoap_data column + * + * @param string $dbLiquidsoapData The value to use as filter. + * Accepts wildcards (* and % trigger a LIKE) + * @param string $comparison Operator to use for the column comparison, defaults to Criteria::EQUAL + * + * @return CcWebstreamQuery The current query, for fluid interface + */ + public function filterByDbLiquidsoapData($dbLiquidsoapData = null, $comparison = null) + { + if (null === $comparison) { + if (is_array($dbLiquidsoapData)) { + $comparison = Criteria::IN; + } elseif (preg_match('/[\%\*]/', $dbLiquidsoapData)) { + $dbLiquidsoapData = str_replace('*', '%', $dbLiquidsoapData); + $comparison = Criteria::LIKE; + } + } + return $this->addUsingAlias(CcWebstreamPeer::LIQUIDSOAP_DATA, $dbLiquidsoapData, $comparison); + } + /** * Filter the query by a related CcSchedule object * diff --git a/airtime_mvc/application/models/formatters/BitrateFormatter.php b/airtime_mvc/application/models/formatters/BitrateFormatter.php index 00828a672..db64a4048 100644 --- a/airtime_mvc/application/models/formatters/BitrateFormatter.php +++ b/airtime_mvc/application/models/formatters/BitrateFormatter.php @@ -19,6 +19,10 @@ class BitrateFormatter { { $Kbps = bcdiv($this->_bitrate, 1000, 0); - return "{$Kbps} Kbps"; + if($Kbps == 0) { + return ""; + } else { + return "{$Kbps} Kbps"; + } } -} \ No newline at end of file +} diff --git a/airtime_mvc/build/schema.xml b/airtime_mvc/build/schema.xml index 0773a2675..6486208ed 100644 --- a/airtime_mvc/build/schema.xml +++ b/airtime_mvc/build/schema.xml @@ -423,5 +423,6 @@ + diff --git a/airtime_mvc/build/sql/schema.sql b/airtime_mvc/build/sql/schema.sql index 6fe02acf3..421b4cff4 100644 --- a/airtime_mvc/build/sql/schema.sql +++ b/airtime_mvc/build/sql/schema.sql @@ -639,6 +639,7 @@ CREATE TABLE "cc_webstream" "mtime" TIMESTAMP(6) NOT NULL, "utime" TIMESTAMP(6) NOT NULL, "mime" VARCHAR(255), + "liquidsoap_data" VARCHAR(1024), PRIMARY KEY ("id") ); diff --git a/airtime_mvc/public/js/airtime/library/events/library_playlistbuilder.js b/airtime_mvc/public/js/airtime/library/events/library_playlistbuilder.js index dcb63f8af..f2eff7739 100644 --- a/airtime_mvc/public/js/airtime/library/events/library_playlistbuilder.js +++ b/airtime_mvc/public/js/airtime/library/events/library_playlistbuilder.js @@ -40,6 +40,10 @@ var AIRTIME = (function(AIRTIME){ $nRow.attr("id", aData["tr_id"]) .data("aData", aData) .data("screen", "playlist"); + + if (aData["bl_type"] !== undefined) { + $nRow.attr("bl_type", aData["bl_type"]); + } }; mod.fnDrawCallback = function() { diff --git a/airtime_mvc/public/js/airtime/library/library.js b/airtime_mvc/public/js/airtime/library/library.js index 3d58b9bcd..bcd364d5f 100644 --- a/airtime_mvc/public/js/airtime/library/library.js +++ b/airtime_mvc/public/js/airtime/library/library.js @@ -426,6 +426,9 @@ var AIRTIME = (function(AIRTIME) { open_audio_preview(aData.ftype, aData.audioFile, aData.track_title, aData.artist_name); } else if (aData.ftype == 'stream') { open_audio_preview(aData.ftype, aData.audioFile, aData.track_title, aData.artist_name); + } else if (aData.ftype == 'block' && aData.bl_type == 'static') { + blockIndex = $(this).parent().attr('id').substring(3); //remove the bl_ + open_block_preview(blockIndex, 0); } return false; }); diff --git a/airtime_mvc/public/js/airtime/playlist/smart_playlistbuilder.js b/airtime_mvc/public/js/airtime/playlist/smart_playlistbuilder.js index 8c275ee02..f4931e1df 100644 --- a/airtime_mvc/public/js/airtime/playlist/smart_playlistbuilder.js +++ b/airtime_mvc/public/js/airtime/playlist/smart_playlistbuilder.js @@ -414,7 +414,8 @@ function sizeTextBoxes(ele, classToRemove, classToAdd) { function populateModifierSelect(e) { var criteria_type = getCriteriaOptionType(e), index = getRowIndex($(e).parent()), - divs = $(e).parents().find('select[id^="sp_criteria_modifier_'+index+'"]'); + critIndex = index.substring(0, 1), + divs = $(e).parents().find('select[id^="sp_criteria_modifier_'+critIndex+'"]'); $.each(divs, function(i, div){ $(div).children().remove(); diff --git a/python_apps/api_clients/api_client.cfg b/python_apps/api_clients/api_client.cfg index 83ebb9210..2e0e938e8 100644 --- a/python_apps/api_clients/api_client.cfg +++ b/python_apps/api_clients/api_client.cfg @@ -115,3 +115,5 @@ get_bootstrap_info = 'get-bootstrap-info/format/json/api_key/%%api_key%%' get_files_without_replay_gain = 'get-files-without-replay-gain/api_key/%%api_key%%/dir_id/%%dir_id%%' update_replay_gain_value = 'update-replay-gain-value/api_key/%%api_key%%' + +notify_webstream_data = 'notify-webstream-data/api_key/%%api_key%%/media_id/%%media_id%%/format/json' diff --git a/python_apps/api_clients/api_client.py b/python_apps/api_clients/api_client.py index a4088062b..268898973 100644 --- a/python_apps/api_clients/api_client.py +++ b/python_apps/api_clients/api_client.py @@ -81,9 +81,17 @@ class AirtimeApiClient(): successful_response = True except IOError, e: logger.error('Error Authenticating with remote server: %s', e) + if isinstance(url, urllib2.Request): + logger.debug(url.get_full_url()) + else: + logger.debug(url) except Exception, e: logger.error('Couldn\'t connect to remote server. Is it running?') logger.error("%s" % e) + if isinstance(url, urllib2.Request): + logger.debug(url.get_full_url()) + else: + logger.debug(url) if not successful_response: logger.error("Error connecting to server, waiting 5 seconds and trying again.") @@ -684,7 +692,25 @@ class AirtimeApiClient(): data = urllib.urlencode({'data': json.dumps(pairs)}) request = urllib2.Request(url, data) - self.get_response_from_server(request) + self.logger.debug(self.get_response_from_server(request)) except Exception, e: self.logger.error("Exception: %s", e) raise + + + def notify_webstream_data(self, data, media_id): + """ + Update the server with the latest metadata we've received from the + external webstream + """ + try: + url = "http://%(base_url)s:%(base_port)s/%(api_base)s/%(notify_webstream_data)s/" % (self.config) + url = url.replace("%%media_id%%", str(media_id)) + url = url.replace("%%api_key%%", self.config["api_key"]) + data = urllib.urlencode({'data': data}) + self.logger.debug(url) + request = urllib2.Request(url, data) + + self.logger.info(self.get_response_from_server(request)) + except Exception, e: + self.logger.error("Exception: %s", e) diff --git a/python_apps/media-monitor2/media/monitor/config.py b/python_apps/media-monitor2/media/monitor/config.py index 0669800b3..c11158574 100644 --- a/python_apps/media-monitor2/media/monitor/config.py +++ b/python_apps/media-monitor2/media/monitor/config.py @@ -8,8 +8,7 @@ import media.monitor.pure as mmp class MMConfig(object): def __init__(self, path): - if not os.path.exists(path): - raise NoConfigFile(path) + if not os.path.exists(path): raise NoConfigFile(path) self.cfg = ConfigObj(path) def __getitem__(self, key): @@ -29,6 +28,10 @@ class MMConfig(object): def save(self): self.cfg.write() def last_ran(self): + """ + Returns the last time media monitor was ran by looking at the time when + the file at 'index_path' was modified + """ return mmp.last_modified(self.cfg['index_path']) # Remove this after debugging... diff --git a/python_apps/media-monitor2/media/monitor/eventcontractor.py b/python_apps/media-monitor2/media/monitor/eventcontractor.py index 0ac0e3278..cbc1f5c90 100644 --- a/python_apps/media-monitor2/media/monitor/eventcontractor.py +++ b/python_apps/media-monitor2/media/monitor/eventcontractor.py @@ -46,7 +46,6 @@ class EventContractor(Loggable): self.store[ evt.path ] = evt return True # We actually added something, hence we return true. - # events are unregistered automatically no need to screw around with them def __unregister(self, evt): try: del self.store[evt.path] except Exception as e: self.unexpected_exception(e) diff --git a/python_apps/media-monitor2/media/monitor/metadata.py b/python_apps/media-monitor2/media/monitor/metadata.py index d1d35a99e..931ab52da 100644 --- a/python_apps/media-monitor2/media/monitor/metadata.py +++ b/python_apps/media-monitor2/media/monitor/metadata.py @@ -51,7 +51,7 @@ airtime_special = { "MDATA_KEY_DURATION" : lambda m: format_length(getattr(m.info, u'length', 0.0)), "MDATA_KEY_BITRATE" : - lambda m: getattr(m.info, "bitrate", 0), + lambda m: getattr(m.info, "bitrate", ''), "MDATA_KEY_SAMPLERATE" : lambda m: getattr(m.info, u'sample_rate', 0), "MDATA_KEY_MIME" : @@ -110,8 +110,7 @@ class Metadata(Loggable): """ Writes 'md' metadata into 'path' through mutagen """ - if not os.path.exists(path): - raise BadSongFile(path) + if not os.path.exists(path): raise BadSongFile(path) song_file = mutagen.File(path, easy=True) for airtime_k, airtime_v in md.iteritems(): if airtime_k in airtime2mutagen: @@ -120,7 +119,6 @@ class Metadata(Loggable): song_file[ airtime2mutagen[airtime_k] ] = unicode(airtime_v) song_file.save() - def __init__(self, fpath): # Forcing the unicode through try: fpath = fpath.decode("utf-8") diff --git a/python_apps/media-monitor2/media/monitor/organizer.py b/python_apps/media-monitor2/media/monitor/organizer.py index 011383c39..e5d0247de 100644 --- a/python_apps/media-monitor2/media/monitor/organizer.py +++ b/python_apps/media-monitor2/media/monitor/organizer.py @@ -18,8 +18,8 @@ class Organizer(ReportHandler,Loggable): _instance = None def __new__(cls, channel, target_path, recorded_path): if cls._instance: - cls._instance.channel = channel - cls._instance.target_path = target_path + cls._instance.channel = channel + cls._instance.target_path = target_path cls._instance.recorded_path = recorded_path else: cls._instance = super(Organizer, cls).__new__( cls, channel, @@ -27,8 +27,8 @@ class Organizer(ReportHandler,Loggable): return cls._instance def __init__(self, channel, target_path, recorded_path): - self.channel = channel - self.target_path = target_path + self.channel = channel + self.target_path = target_path self.recorded_path = recorded_path super(Organizer, self).__init__(signal=self.channel, weak=False) diff --git a/python_apps/media-monitor2/media/monitor/pure.py b/python_apps/media-monitor2/media/monitor/pure.py index ceb37cd6c..8bc1639c0 100644 --- a/python_apps/media-monitor2/media/monitor/pure.py +++ b/python_apps/media-monitor2/media/monitor/pure.py @@ -17,6 +17,9 @@ supported_extensions = [u"mp3", u"ogg", u"oga"] #supported_extensions = [u"mp3", u"ogg", u"oga", u"flac", u"aac", u"bwf"] unicode_unknown = u'unknown' +path_md = ['MDATA_KEY_TITLE', 'MDATA_KEY_CREATOR', 'MDATA_KEY_SOURCE', + 'MDATA_KEY_TRACKNUMBER', 'MDATA_KEY_BITRATE'] + class LazyProperty(object): """ meant to be used for lazy evaluation of an object attribute. @@ -59,7 +62,7 @@ def partition(f, alist): Partition is very similar to filter except that it also returns the elements for which f return false but in a tuple. >>> partition(lambda x : x > 3, [1,2,3,4,5,6]) - [4,5,6],[1,2,3] + ([4, 5, 6], [1, 2, 3]) """ return (filter(f, alist), filter(lambda x: not f(x), alist)) @@ -101,6 +104,8 @@ def extension(path): I.e. interpreter won't enforce None checks on the programmer >>> extension("testing.php") 'php' + >>> extension("a.b.c.d.php") + 'php' >>> extension('/no/extension') '' >>> extension('/path/extension.ml') @@ -114,15 +119,17 @@ def no_extension_basename(path): """ returns the extensionsless basename of a filepath >>> no_extension_basename("/home/test.mp3") - 'test' + u'test' >>> no_extension_basename("/home/test") - 'test' + u'test' >>> no_extension_basename('blah.ml') - 'blah' + u'blah' + >>> no_extension_basename('a.b.c.d.mp3') + u'a.b.c.d' """ base = unicode(os.path.basename(path)) if extension(base) == "": return base - else: return base.split(".")[-2] + else: return '.'.join(base.split(".")[0:-1]) def walk_supported(directory, clean_empties=False): """ @@ -163,15 +170,23 @@ def apply_rules_dict(d, rules): if k in d: new_d[k] = rule(d[k]) return new_d +def default_to_f(dictionary, keys, default, condition): + new_d = copy.deepcopy(dictionary) + for k in keys: + if condition(dictionary=new_d, key=k): new_d[k] = default + return new_d + def default_to(dictionary, keys, default): """ Checks if the list of keys 'keys' exists in 'dictionary'. If not then it returns a new dictionary with all those missing keys defaults to 'default' """ - new_d = copy.deepcopy(dictionary) - for k in keys: - if not (k in new_d): new_d[k] = default - return new_d + cnd = lambda dictionary, key: key not in dictionary + return default_to_f(dictionary, keys, default, cnd) + #new_d = copy.deepcopy(dictionary) + #for k in keys: + #if not (k in new_d): new_d[k] = default + #return new_d def remove_whitespace(dictionary): """ @@ -192,16 +207,16 @@ def parse_int(s): Tries very hard to get some sort of integer result from s. Defaults to 0 when it failes >>> parse_int("123") - 123 + '123' >>> parse_int("123saf") - 123 + '123' >>> parse_int("asdf") - 0 + '' """ if s.isdigit(): return s else: - try : return reduce(op.add, takewhile(lambda x: x.isdigit(), s)) - except: return 0 + try : return str(reduce(op.add, takewhile(lambda x: x.isdigit(), s))) + except: return '' def normalized_metadata(md, original_path): """ @@ -223,20 +238,18 @@ def normalized_metadata(md, original_path): 'MDATA_KEY_MIME' : lambda x: x.replace('-','/'), 'MDATA_KEY_BPM' : lambda x: x[0:8], } - path_md = ['MDATA_KEY_TITLE', 'MDATA_KEY_CREATOR', 'MDATA_KEY_SOURCE', - 'MDATA_KEY_TRACKNUMBER', 'MDATA_KEY_BITRATE'] # note that we could have saved a bit of code by rewriting new_md using # defaultdict(lambda x: "unknown"). But it seems to be too implicit and # could possibly lead to subtle bugs down the road. Plus the following # approach gives us the flexibility to use different defaults for different # attributes + new_md = remove_whitespace(new_md) new_md = apply_rules_dict(new_md, format_rules) new_md = default_to(dictionary=new_md, keys=['MDATA_KEY_TITLE'], - default=no_extension_basename(original_path)) - new_md = default_to(dictionary=new_md, keys=path_md, - default=unicode_unknown) + default=no_extension_basename(original_path)) + new_md = default_to(dictionary=new_md, keys=path_md, default=u'') new_md = default_to(dictionary=new_md, keys=['MDATA_KEY_FTYPE'], - default=u'audioclip') + default=u'audioclip') # In the case where the creator is 'Airtime Show Recorder' we would like to # format the MDATA_KEY_TITLE slightly differently # Note: I don't know why I'm doing a unicode string comparison here @@ -251,13 +264,13 @@ def normalized_metadata(md, original_path): # be set to the original path of the file for airtime recorded shows # (before it was "organized"). We will skip this procedure for now # because it's not clear why it was done - return remove_whitespace(new_md) + return new_md -def organized_path(old_path, root_path, normal_md): +def organized_path(old_path, root_path, orig_md): """ old_path - path where file is store at the moment <= maybe not necessary? root_path - the parent directory where all organized files go - normal_md - original meta data of the file as given by mutagen AFTER being + orig_md - original meta data of the file as given by mutagen AFTER being normalized return value: new file path """ @@ -265,6 +278,8 @@ def organized_path(old_path, root_path, normal_md): ext = extension(old_path) # The blocks for each if statement look awfully similar. Perhaps there is a # way to simplify this code + normal_md = default_to_f(orig_md, path_md, unicode_unknown, + lambda dictionary, key: len(dictionary[key]) == 0) if is_airtime_recorded(normal_md): fname = u'%s-%s-%s.%s' % ( normal_md['MDATA_KEY_YEAR'], normal_md['MDATA_KEY_TITLE'], @@ -321,8 +336,7 @@ def get_system_locale(locale_path='/etc/default/locale'): try: config = ConfigObj(locale_path) return config - except Exception as e: - raise FailedToSetLocale(locale_path,cause=e) + except Exception as e: raise FailedToSetLocale(locale_path,cause=e) else: raise ValueError("locale path '%s' does not exist. \ permissions issue?" % locale_path) @@ -336,8 +350,7 @@ def configure_locale(config): if default_locale[1] is None: lang = config.get('LANG') new_locale = lang - else: - new_locale = default_locale + else: new_locale = default_locale locale.setlocale(locale.LC_ALL, new_locale) reload(sys) sys.setdefaultencoding("UTF-8") @@ -394,7 +407,7 @@ def sub_path(directory,f): the paths. """ normalized = normpath(directory) - common = os.path.commonprefix([ directory, normpath(f) ]) + common = os.path.commonprefix([ normalized, normpath(f) ]) return common == normalized if __name__ == '__main__': diff --git a/python_apps/media-monitor2/media/monitor/watchersyncer.py b/python_apps/media-monitor2/media/monitor/watchersyncer.py index faea2600d..c400ad6d5 100644 --- a/python_apps/media-monitor2/media/monitor/watchersyncer.py +++ b/python_apps/media-monitor2/media/monitor/watchersyncer.py @@ -2,7 +2,6 @@ import threading import time import copy -import traceback from media.monitor.handler import ReportHandler from media.monitor.log import Loggable @@ -47,9 +46,7 @@ class RequestSync(threading.Thread,Loggable): except BadSongFile as e: self.logger.info("This should never occur anymore!!!") self.logger.info("Bad song file: '%s'" % e.path) - except Exception as e: - self.logger.info("An evil exception occured") - self.logger.error( traceback.format_exc() ) + except Exception as e: self.unexpected_exception( e ) def make_req(): self.apiclient.send_media_monitor_requests( packed_requests ) for try_index in range(0,self.retries): @@ -102,16 +99,14 @@ class TimeoutWatcher(threading.Thread,Loggable): class WatchSyncer(ReportHandler,Loggable): def __init__(self, signal, chunking_number = 100, timeout=15): - self.timeout = float(timeout) - self.chunking_number = int(chunking_number) - self.__reset_queue() - # Even though we are not blocking on the http requests, we are still - # trying to send the http requests in order - self.__requests = [] - self.request_running = False - # we don't actually use this "private" instance variable anywhere + self.timeout = float(timeout) + self.chunking_number = int(chunking_number) + self.request_running = False self.__current_thread = None - self.contractor = EventContractor() + self.__requests = [] + self.contractor = EventContractor() + self.__reset_queue() + tc = TimeoutWatcher(self, self.timeout) tc.daemon = True tc.start() diff --git a/python_apps/media-monitor2/mm2.py b/python_apps/media-monitor2/mm2.py index a8a3dfb26..849d7ae6b 100644 --- a/python_apps/media-monitor2/mm2.py +++ b/python_apps/media-monitor2/mm2.py @@ -122,6 +122,8 @@ def main(global_config, api_client_config, log_config, # Launch the toucher that updates the last time when the script was # ran every n seconds. + # TODO : verify that this does not interfere with bootstrapping because the + # toucher thread might update the last_ran variable too fast tt = ToucherThread(path=config['index_path'], interval=int(config['touch_interval'])) diff --git a/python_apps/media-monitor2/tests/test_pure.py b/python_apps/media-monitor2/tests/test_pure.py index 02e753c8d..81918fd10 100644 --- a/python_apps/media-monitor2/tests/test_pure.py +++ b/python_apps/media-monitor2/tests/test_pure.py @@ -60,4 +60,16 @@ class TestMMP(unittest.TestCase): self.assertRaises( ValueError, lambda : mmp.file_md5('/bull/shit/path') ) self.assertTrue( m1 == mmp.file_md5(p) ) + def test_sub_path(self): + f1 = "/home/testing/123.mp3" + d1 = "/home/testing" + d2 = "/home/testing/" + self.assertTrue( mmp.sub_path(d1, f1) ) + self.assertTrue( mmp.sub_path(d2, f1) ) + + def test_parse_int(self): + self.assertEqual( mmp.parse_int("123"), "123" ) + self.assertEqual( mmp.parse_int("123asf"), "123" ) + self.assertEqual( mmp.parse_int("asdf"), "" ) + if __name__ == '__main__': unittest.main() diff --git a/python_apps/pypo/liquidsoap_scripts/ls_lib.liq b/python_apps/pypo/liquidsoap_scripts/ls_lib.liq index c007cd504..ed5085e12 100644 --- a/python_apps/pypo/liquidsoap_scripts/ls_lib.liq +++ b/python_apps/pypo/liquidsoap_scripts/ls_lib.liq @@ -1,11 +1,15 @@ def notify(m) - log("/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --data='#{!pypo_data}' --media-id=#{m['schedule_table_id']} &") - system("/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --data='#{!pypo_data}' --media-id=#{m['schedule_table_id']} &") + current_media_id := string_of(m['schedule_table_id']) + command = "/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --data='#{!pypo_data}' --media-id=#{m['schedule_table_id']} &" + log(command) + system(command) end def notify_stream(m) - log("/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --stream --uri=#{base64.encode(m['uri'])} --title=#{base64.encode(m['title'])} &") - #system("/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --stream --uri=#{base64.encode(m['uri'])} --title=#{base64.encode(m['title'])} &") + json_str = string.replace(pattern="\n",(fun (s) -> ""), json_of(m)) + command = "/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --webstream='#{json_str}' --media-id=#{!current_media_id} &" + log(command) + system(command) end # A function applied to each metadata chunk diff --git a/python_apps/pypo/liquidsoap_scripts/ls_script.liq b/python_apps/pypo/liquidsoap_scripts/ls_script.liq index 2009d62bf..540bd29fa 100644 --- a/python_apps/pypo/liquidsoap_scripts/ls_script.liq +++ b/python_apps/pypo/liquidsoap_scripts/ls_script.liq @@ -27,6 +27,7 @@ stream_metadata_type = ref 0 default_dj_fade = ref 0. station_name = ref '' show_name = ref '' +current_media_id = ref '' s1_connected = ref '' s2_connected = ref '' diff --git a/python_apps/pypo/pyponotify.py b/python_apps/pypo/pyponotify.py index e0cb835ba..7b1d5ffd2 100644 --- a/python_apps/pypo/pyponotify.py +++ b/python_apps/pypo/pyponotify.py @@ -6,10 +6,10 @@ Python part of radio playout (pypo) This function acts as a gateway between liquidsoap and the server API. Mainly used to tell the platform what pypo/liquidsoap does. -Main case: +Main case: - whenever LS starts playing a new track, its on_metadata callback calls a function in ls (notify(m)) which then calls the python script here - with the currently starting filename as parameter + with the currently starting filename as parameter - this python script takes this parameter, tries to extract the actual media id from it, and then calls back to the API to tell about it about it. @@ -33,14 +33,15 @@ usage = "%prog [options]" + " - notification gateway" parser = OptionParser(usage=usage) # 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("-m", "--media-id", help="ID of the file that is currently playing.", metavar="media_id") -parser.add_option("-e", "--error", action="store", dest="error", type="string", help="liquidsoap error msg.", metavar="error_msg") +parser.add_option("-e", "--error", action="store", dest="error", type="string", help="Liquidsoap error msg.", metavar="error_msg") parser.add_option("-s", "--stream-id", help="ID stream", metavar="stream_id") -parser.add_option("-c", "--connect", help="liquidsoap connected", action="store_true", metavar="connect") -parser.add_option("-t", "--time", help="liquidsoap boot up time", action="store", dest="time", metavar="time", type="string") +parser.add_option("-c", "--connect", help="Liquidsoap connected", action="store_true", metavar="connect") +parser.add_option("-t", "--time", help="Liquidsoap boot up time", action="store", dest="time", metavar="time", type="string") parser.add_option("-x", "--source-name", help="source connection name", metavar="source_name") -parser.add_option("-y", "--source-status", help="source connection stauts", metavar="source_status") +parser.add_option("-y", "--source-status", help="source connection status", metavar="source_status") +parser.add_option("-w", "--webstream", help="JSON metadata associated with webstream", metavar="json_data") # parse options (options, args) = parser.parse_args() @@ -97,6 +98,15 @@ class Notify: response = self.api_client.notify_source_status(source_name, status) logger.debug("Response: " + json.dumps(response)) + def notify_webstream_data(self, data, media_id): + logger = logging.getLogger("notify") + logger.debug('#################################################') + logger.debug('# Calling server to update webstream data #') + logger.debug('#################################################') + response = self.api_client.notify_webstream_data(data, media_id) + + pass + if __name__ == '__main__': print print '#########################################' @@ -124,6 +134,12 @@ if __name__ == '__main__': n.notify_source_status(options.source_name, options.source_status) except Exception, e: print e + elif options.webstream: + try: + n = Notify() + n.notify_webstream_data(options.webstream, options.media_id) + except Exception, e: + print e else: if not options.data: print "NOTICE: 'data' command-line argument not given."