Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for live master/show source metadata in Airtime #129

Closed
wants to merge 5 commits into from
Closed
Diff settings

Always

Just for now

@@ -1,6 +1,6 @@
<?php
// This file generated by Propel 1.7.0 convert-conf target
// from XML runtime conf file /home/sourcefabric/dev/Airtime/airtime_mvc/build/runtime-conf.xml
// from XML runtime conf file /home/asantoni/airtime/airtime_mvc/build/runtime-conf.xml
$conf = array (
'datasources' =>
array (
@@ -1280,10 +1280,11 @@ public function notifyWebstreamDataAction()
$data = $request->getParam("data");
$media_id = intval($request->getParam("media_id"));
$data_arr = json_decode($data);
//$media_id is -1 sometimes when a stream has stopped playing
if (!is_null($media_id) && $media_id > 0) {
if ((!is_null($media_id) && $media_id > 0) || Application_Model_Schedule::isLiveBroadcasterConnected()) {
//We log webstream and master/show source metadata to its own table.
if (isset($data_arr->title)) {
$data_title = substr($data_arr->title, 0, 1024);
@@ -0,0 +1,3 @@
UPDATE cc_webstream_metadata SET instance_id=-1 WHERE instance_id IS NULL;

ALTER TABLE cc_webstream_metadata ALTER COLUMN instance_id SET NOT NULL;
@@ -0,0 +1,5 @@
-----------------------------------------------------------------------
-- Allow webstream metadata to be stored without an associated scheduled track (for master/live source)
-----------------------------------------------------------------------

ALTER TABLE cc_webstream_metadata ALTER COLUMN instance_id DROP NOT NULL;
@@ -200,11 +200,19 @@ public static function getPreviousCurrentNextMedia($utcNow, $currentShowInstance
// track information to the current show values
if ($source != self::SCHEDULED_SOURCE_NAME) {
$show = Application_Model_Show::getCurrentShow();
$currentWebstream = CcWebstreamQuery::create()
->findOne();
$currentWebstreamMetadata = CcWebstreamMetadataQuery::create()
->orderByDbStartTime(Criteria::DESC)
->findOne();
$currentMediaName = $currentWebstream->getDbName();
$results["current"] = isset($show[0]) ? array(
"starts" => $show[0]["starts"],
"ends" => $show[0]["ends"],
"type" => _("livestream"),
"name" => $show[0]["name"] . " - " . _(self::LIVE_STREAM),
"name" => $currentWebstreamMetadata->getDbLiquidsoapData(),
"media_item_played" => false,
"record" => "0"
) : null;
@@ -335,6 +343,11 @@ private static function _getSource() {
return $source;
}
public static function isLiveBroadcasterConnected()
{
return (self::_getSource() == self::SHOW_SOURCE_NAME) || (self::_getSource() == self::MASTER_SOURCE_NAME);
}
public static function GetLastScheduleItem($p_timeNow)
{
$sql = <<<SQL
@@ -40,7 +40,7 @@ public function initialize()
$this->setPrimaryKeyMethodInfo('cc_webstream_metadata_id_seq');
// columns
$this->addPrimaryKey('id', 'DbId', 'INTEGER', true, null, null);
$this->addForeignKey('instance_id', 'DbInstanceId', 'INTEGER', 'cc_schedule', 'id', true, null, null);
$this->addForeignKey('instance_id', 'DbInstanceId', 'INTEGER', 'cc_schedule', 'id', false, null, null);
$this->addColumn('start_time', 'DbStartTime', 'TIMESTAMP', true, null, null);
$this->addColumn('liquidsoap_data', 'DbLiquidsoapData', 'VARCHAR', true, 1024, null);
// validators
@@ -2214,7 +2214,7 @@ public function removeCcWebstreamMetadata($ccWebstreamMetadata)
$this->ccWebstreamMetadatasScheduledForDeletion = clone $this->collCcWebstreamMetadatas;
$this->ccWebstreamMetadatasScheduledForDeletion->clear();
}
$this->ccWebstreamMetadatasScheduledForDeletion[]= clone $ccWebstreamMetadata;
$this->ccWebstreamMetadatasScheduledForDeletion[]= $ccWebstreamMetadata;
$ccWebstreamMetadata->setCcSchedule(null);
}
@@ -1133,7 +1133,7 @@ public function filterByCcWebstreamMetadata($ccWebstreamMetadata, $comparison =
*
* @return CcScheduleQuery The current query, for fluid interface
*/
public function joinCcWebstreamMetadata($relationAlias = null, $joinType = Criteria::INNER_JOIN)
public function joinCcWebstreamMetadata($relationAlias = null, $joinType = Criteria::LEFT_JOIN)
{
$tableMap = $this->getTableMap();
$relationMap = $tableMap->getRelation('CcWebstreamMetadata');
@@ -1168,7 +1168,7 @@ public function joinCcWebstreamMetadata($relationAlias = null, $joinType = Crite
*
* @return CcWebstreamMetadataQuery A secondary query class using the current class as primary query
*/
public function useCcWebstreamMetadataQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN)
public function useCcWebstreamMetadataQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN)
{
return $this
->joinCcWebstreamMetadata($relationAlias, $joinType)
@@ -423,7 +423,7 @@ public function filterByCcSchedule($ccSchedule, $comparison = null)
*
* @return CcWebstreamMetadataQuery The current query, for fluid interface
*/
public function joinCcSchedule($relationAlias = null, $joinType = Criteria::INNER_JOIN)
public function joinCcSchedule($relationAlias = null, $joinType = Criteria::LEFT_JOIN)
{
$tableMap = $this->getTableMap();
$relationMap = $tableMap->getRelation('CcSchedule');
@@ -458,7 +458,7 @@ public function joinCcSchedule($relationAlias = null, $joinType = Criteria::INNE
*
* @return CcScheduleQuery A secondary query class using the current class as primary query
*/
public function useCcScheduleQuery($relationAlias = null, $joinType = Criteria::INNER_JOIN)
public function useCcScheduleQuery($relationAlias = null, $joinType = Criteria::LEFT_JOIN)
{
return $this
->joinCcSchedule($relationAlias, $joinType)
@@ -526,29 +526,68 @@ public function insertWebstreamMetadata($schedId, $startDT, $data) {
try {
$item = CcScheduleQuery::create()->findPK($schedId, $this->con);
//TODO figure out how to combine these all into 1 query.
$showInstance = $item->getCcShowInstances($this->con);
$show = $showInstance->getCcShow($this->con);
$webstream = $item->getCcWebstream($this->con);
$metadata = array();
$metadata["showname"] = $show->getDbName();
$metadata[MDATA_KEY_TITLE] = $data->title;
$metadata[MDATA_KEY_CREATOR] = $webstream->getDbName();
$history = new CcPlayoutHistory();
$history->setDbStarts($startDT);
$history->setDbEnds(null);
$history->setDbInstanceId($item->getDbInstanceId());
foreach ($metadata as $key => $val) {
//Scheduled track/webstream
if ($item)
{
//TODO figure out how to combine these all into 1 query.
$showInstance = $item->getCcShowInstances($this->con);
$show = $showInstance->getCcShow($this->con);
$webstream = $item->getCcWebstream($this->con);
$metadata = array();
$metadata["showname"] = $show->getDbName();
$metadata[MDATA_KEY_TITLE] = $data->title;
$metadata[MDATA_KEY_CREATOR] = $webstream->getDbName();
$history = new CcPlayoutHistory();
$history->setDbStarts($startDT);
$history->setDbEnds(null);
$history->setDbInstanceId($item->getDbInstanceId());
foreach ($metadata as $key => $val) {
$meta = new CcPlayoutHistoryMetaData();
$meta->setDbKey($key);
$meta->setDbValue($val);
$history->addCcPlayoutHistoryMetaData($meta);
}
}
else { //$item will be null if we're on master/show source.
//Master/show source
$utcNow = new DateTime("now", new DateTimeZone("UTC"));
$end = new DateTime();
$end->add(new DateInterval("P2D")); // Add 2 days
$end->setTimezone(new DateTimeZone("UTC"));
$utcTimeEnd = $end->format(DEFAULT_TIMESTAMP_FORMAT);
$shows = Application_Model_Show::getPrevCurrentNext($utcNow, $utcTimeEnd, 1);
$currentShowID = count($shows['currentShow'])>0?$shows['currentShow']['instance_id']:null;
$metadata[MDATA_KEY_TITLE] = $data->title;
$history = new CcPlayoutHistory();
$history->setDbStarts($startDT);
$history->setDbEnds(null);
$history->setCcShowInstances(CcShowInstancesQuery::create()->findPK($currentShowID, $this->con));
foreach ($metadata as $key => $val) {
$meta = new CcPlayoutHistoryMetaData();
$meta->setDbKey($key);
$meta->setDbValue($val);
$history->addCcPlayoutHistoryMetaData($meta);
}
$meta = new CcPlayoutHistoryMetaData();
$meta->setDbKey($key);
$meta->setDbValue($val);
$artistFieldName = BasePeer::translateFieldname("CcFiles", CcFilesPeer::ARTIST_NAME, BasePeer::TYPE_COLNAME, BasePeer::TYPE_FIELDNAME);
$meta->setDbKey($artistFieldName);
$meta->setDbValue("Live DJ Broadcast");
$history->addCcPlayoutHistoryMetaData($meta);
}
$history->save($this->con);
@@ -506,3 +506,16 @@ public function getNewVersion() {
return '2.5.16';
}
}
class AirtimeUpgrader2517 extends AirtimeUpgrader
{
protected function getSupportedSchemaVersions() {
return array(
'2.5.16'
);
}
public function getNewVersion() {
return '2.5.17';
}
}
@@ -1,6 +1,6 @@
#Note: project.home is automatically generated by the propel-install script.
#Any manual changes to this value will be overwritten.
project.home = /home/sourcefabric/dev/Airtime/airtime_mvc
project.home = /home/asantoni/airtime/airtime_mvc
project.build = ${project.home}/build

#Database driver
Copy path View file
@@ -466,7 +466,7 @@
</table>
<table name="cc_webstream_metadata" phpName="CcWebstreamMetadata">
<column name="id" phpName="DbId" primaryKey="true" type="INTEGER" autoIncrement="true" required="true" />
<column name="instance_id" phpName="DbInstanceId" type="INTEGER" required="true"/>
<column name="instance_id" phpName="DbInstanceId" type="INTEGER" required="false"/>
<column name="start_time" phpName="DbStartTime" type="TIMESTAMP" required="true" />
<column name="liquidsoap_data" phpName="DbLiquidsoapData" type="VARCHAR" size="1024" required="true"/>
<foreign-key foreignTable="cc_schedule" name="cc_schedule_inst_fkey" onDelete="CASCADE">
@@ -561,7 +561,7 @@ DROP TABLE IF EXISTS "cc_webstream_metadata" CASCADE;
CREATE TABLE "cc_webstream_metadata"
(
"id" serial NOT NULL,
"instance_id" INTEGER NOT NULL,
"instance_id" INTEGER,
"start_time" TIMESTAMP NOT NULL,
"liquidsoap_data" VARCHAR(1024) NOT NULL,
PRIMARY KEY ("id")
@@ -127,25 +127,26 @@ function updatePlaybar(){

if (currentSong !== null && !master_dj_on_air && !live_dj_on_air){
if (currentSong.record == "1")
$('#current').html("<span style='color:red; font-weight:bold'>"+$.i18n._("Recording:")+"</span>"+currentSong.name+",");
$('#current').html("<span style='color:red; font-weight:bold'>"+$.i18n._("Recording:")+"</span>"+currentSong.name);
else
$('#current').text(currentSong.name+",");
$('#current').text(currentSong.name);
}else{
if (master_dj_on_air) {
if (showName) {
$('#current').html($.i18n._("Current")+": <span style='color:red; font-weight:bold'>"+showName+" - "+$.i18n._("Master Stream")+"</span>");
$('#current').html($.i18n._("Master Source")+": <span style='color:red; font-weight:bold'>"+currentSong["name"]+" - " + showName +"</span>");
} else {
$('#current').html($.i18n._("Current")+": <span style='color:red; font-weight:bold'>"+$.i18n._("Master Stream")+"</span>");
$('#current').html($.i18n._("Master Source")+": <span style='color:red; font-weight:bold'>"+currentSong["name"]+"</span>"); //$.i18n._("Master Stream")
}
} else if (live_dj_on_air) {
if (showName) {
$('#current').html($.i18n._("Current")+": <span style='color:red; font-weight:bold'>"+showName+" - "+$.i18n._("Live Stream")+"</span>");
$('#current').html($.i18n._("Show Source")+": <span style='color:red; font-weight:bold'>"+currentSong["name"]+" - " + showName +"</span>"); //$.i18n._("Live Stream")
} else {
$('#current').html($.i18n._("Current")+": <span style='color:red; font-weight:bold'>"+$.i18n._("Live Stream")+"</span>");
$('#current').html($.i18n._("Show Source")+": <span style='color:red; font-weight:bold'>"+currentSong["name"]+"</span>"); //$.i18n._("Live Stream")
}
} else {
$('#current').html($.i18n._("Current")+": <span style='color:red; font-weight:bold'>"+$.i18n._("Nothing Scheduled")+"</span>");
}

}

if (nextSong !== null){
@@ -16,8 +16,10 @@ def notify_stream(m)
#escaping the apostrophe, and then starting a new string right after it. This is why we use 3 apostrophes.
json_str = string.replace(pattern="'",(fun (s) -> "'\''"), json_str)
command = "timeout --signal=KILL 45 pyponotify --webstream='#{json_str}' --media-id=#{!current_dyn_id} &"

if !current_dyn_id != "-1" then

# If a master/show source are enable OR a webstream is playing, send the metadata back to Airtime.
# (The "!" is the derefence operator, not a logical NOT!)
if (!current_dyn_id != "-1" or (!master_dj_enabled) or (!live_dj_enabled)) then
log(command)
system(command)
end
@@ -35,6 +35,11 @@ s2_namespace = ref ''
s3_namespace = ref ''
just_switched = ref false

master_dj_enabled = ref false
live_dj_enabled = ref false
scheduled_play_enabled = ref false


%include "ls_lib.liq"

sources = ref []
@@ -159,10 +164,6 @@ end
default = rewrite_metadata([("title", !ref_off_air_meta)], default)
ignore(output.dummy(default, fallible=true))

master_dj_enabled = ref false
live_dj_enabled = ref false
scheduled_play_enabled = ref false

def make_master_dj_available()
master_dj_enabled := true
end
@@ -260,6 +261,13 @@ else
s
end

def print_metadata(m) =
title = m["title"]
artist = m["artist"]
print("Master/Show Source Now Playing: #{title} by #{artist}")
notify_stream(m)
end

s = if master_live_stream_port != 0 and master_live_stream_mp != "" then
master_dj =
audio_to_stereo(
@@ -273,6 +281,8 @@ s = if master_live_stream_port != 0 and master_live_stream_mp != "" then

ignore(output.dummy(master_dj, fallible=true))

master_dj = on_metadata(print_metadata, master_dj)

switch(id="master_show_schedule_noise_switch",
track_sensitive=false,
transitions=[transition, transition],
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.