From b2699fa9145633f4af7bd3e559d55a9e46ac15bc Mon Sep 17 00:00:00 2001 From: denise Date: Mon, 3 Dec 2012 11:06:56 -0500 Subject: [PATCH] merge from devel --- VERSION | 2 +- airtime_mvc/application/common/DateHelper.php | 18 +++--- .../application/controllers/ApiController.php | 42 +++++++------- airtime_mvc/application/models/Block.php | 4 +- airtime_mvc/application/models/Schedule.php | 56 +++++++++++++++---- .../application/models/ShowBuilder.php | 8 ++- airtime_mvc/application/models/Webstream.php | 4 +- .../locale/en_CA/LC_MESSAGES/airtime.po | 12 ++-- .../locale/ko_KR/LC_MESSAGES/airtime.po | 18 +++--- .../airtime/audiopreview/preview_jplayer.js | 22 ++++++-- .../public/js/airtime/common/audioplaytest.js | 3 +- .../library/events/library_showbuilder.js | 4 ++ .../public/js/airtime/library/library.js | 2 +- install_minimal/include/airtime-constants.php | 2 +- install_minimal/include/airtime-upgrade.php | 4 ++ python_apps/api_clients/api_client.py | 2 +- .../pypo/liquidsoap_scripts/ls_script.liq | 24 ++++---- 17 files changed, 143 insertions(+), 84 deletions(-) diff --git a/VERSION b/VERSION index c7aac0e6d..491e6ae5c 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1,2 @@ PRODUCT_ID=Airtime -PRODUCT_RELEASE=2.2.0 +PRODUCT_RELEASE=2.2.1 diff --git a/airtime_mvc/application/common/DateHelper.php b/airtime_mvc/application/common/DateHelper.php index 123189231..cc02544cd 100644 --- a/airtime_mvc/application/common/DateHelper.php +++ b/airtime_mvc/application/common/DateHelper.php @@ -48,7 +48,7 @@ class Application_Common_DateHelper /** * Get the week start date of this week in the format * YYYY-MM-DD - * + * * @return String - week start date */ function getWeekStartDate() @@ -231,7 +231,7 @@ class Application_Common_DateHelper if (2 !== substr_count($p_time, ":")){ return FALSE; } - + if (1 === substr_count($p_time, ".")){ list($hhmmss, $ms) = explode(".", $p_time); } else { @@ -275,17 +275,17 @@ class Application_Common_DateHelper return $dateTime; } - /* Convenience method to return a date formatted into a String rather than a + /* Convenience method to return a date formatted into a String rather than a * DateTime object. Note that if an empty string is provided for $p_dateString - * then the current time is provided. - * + * then the current time is provided. + * * @param $p_dateString * Date string in UTC timezone. * @param $p_format * Format which the string should be returned in. - * - * @return string - * Date String in localtime + * + * @return string + * Date String in localtime * */ public static function ConvertToLocalDateTimeString($p_dateString, $p_format="Y-m-d H:i:s"){ if (is_null($p_dateString) || strlen($p_dateString) == 0) @@ -302,7 +302,7 @@ class Application_Common_DateHelper /* * Example input: "00:02:32.746562". Output is a DateInterval object * representing that 2 minute, 32.746562 second interval. - * + * */ public static function getDateIntervalFromString($p_interval){ list($hour_min_sec, $subsec) = explode(".", $p_interval); diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index 198d96351..63625335c 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -928,31 +928,33 @@ class ApiController extends Zend_Controller_Action $data_arr = json_decode($data); - if (!is_null($media_id) && isset($data_arr->title) && strlen($data_arr->title) < 1024) { + if (!is_null($media_id)) { + if (isset($data_arr->title) && + strlen($data_arr->title) < 1024) { - $previous_metadata = CcWebstreamMetadataQuery::create() - ->orderByDbStartTime('desc') - ->filterByDbInstanceId($media_id) - ->findOne(); + $previous_metadata = CcWebstreamMetadataQuery::create() + ->orderByDbStartTime('desc') + ->filterByDbInstanceId($media_id) + ->findOne(); - $do_insert = true; - if ($previous_metadata) { - if ($previous_metadata->getDbLiquidsoapData() == $data_arr->title) { - Logging::debug("Duplicate found: ".$data_arr->title); - $do_insert = false; + $do_insert = true; + if ($previous_metadata) { + if ($previous_metadata->getDbLiquidsoapData() == $data_arr->title) { + Logging::debug("Duplicate found: ".$data_arr->title); + $do_insert = false; + } + } + + if ($do_insert) { + $webstream_metadata = new CcWebstreamMetadata(); + $webstream_metadata->setDbInstanceId($media_id); + $webstream_metadata->setDbStartTime(new DateTime("now", new DateTimeZone("UTC"))); + $webstream_metadata->setDbLiquidsoapData($data_arr->title); + $webstream_metadata->save(); } } - - if ($do_insert) { - $webstream_metadata = new CcWebstreamMetadata(); - $webstream_metadata->setDbInstanceId($media_id); - $webstream_metadata->setDbStartTime(new DateTime("now", new DateTimeZone("UTC"))); - $webstream_metadata->setDbLiquidsoapData($data_arr->title); - $webstream_metadata->save(); - } - } else { - throw new Error("Unexpected error. media_id $media_id has a null stream value in cc_schedule!"); + throw new Exception("Null value of media_id"); } $this->view->response = $data; diff --git a/airtime_mvc/application/models/Block.php b/airtime_mvc/application/models/Block.php index a1b63055e..46e857e49 100644 --- a/airtime_mvc/application/models/Block.php +++ b/airtime_mvc/application/models/Block.php @@ -360,8 +360,10 @@ SQL; { $sql = <<$this->id), 'all', PDO::FETCH_NUM); return $result[0][0]; diff --git a/airtime_mvc/application/models/Schedule.php b/airtime_mvc/application/models/Schedule.php index f4acdf886..bc98168d3 100644 --- a/airtime_mvc/application/models/Schedule.php +++ b/airtime_mvc/application/models/Schedule.php @@ -833,26 +833,60 @@ SQL; } } + + /* Check if two events are less than or equal to 1 second apart + */ + public static function areEventsLinked($event1, $event2) { + $dt1 = DateTime::createFromFormat("Y-m-d-H-i-s", $event1['start']); + $dt2 = DateTime::createFromFormat("Y-m-d-H-i-s", $event2['start']); + + $seconds = $dt2->getTimestamp() - $dt1->getTimestamp(); + return $seconds <= 1; + } /** - * Purpose of this function is to iterate through the entire - * schedule array that was just built and fix the data up a bit. For - * example, if we have two consecutive webstreams, we don't need the - * first webstream to shutdown the output, when the second one will - * just switch it back on. Preventing this behaviour stops hiccups - * in output sound. + * Streams are a 4 stage process. + * 1) start buffering stream 5 seconds ahead of its start time + * 2) at the start time tell liquidsoap to switch to this source + * 3) at the end time, tell liquidsoap to stop reading this stream + * 4) at the end time, tell liquidsoap to switch away from input.http source. + * + * When we have two streams back-to-back, some of these steps are unnecessary + * for the second stream. Instead of sending commands 1,2,3,4,1,2,3,4 we should + * send 1,2,1,2,3,4 - We don't need to tell liquidsoap to stop reading (#3), because #1 + * of the next stream implies this when we pass in a new url. We also don't need #4. + * + * There's a special case here is well. When the back-to-back streams are the same, we + * can collapse the instructions 1,2,(3,4,1,2),3,4 to 1,2,3,4. We basically cut out the + * middle part. This function handles this. */ - private static function filterData(&$data) + private static function foldData(&$data) { $previous_key = null; $previous_val = null; + $previous_previous_key = null; + $previous_previous_val = null; + $previous_previous_previous_key = null; + $previous_previous_previous_val = null; foreach ($data as $k => $v) { - if ($v["type"] == "stream_buffer_start" - && !is_null($previous_val) - && $previous_val["type"] == "stream_output_end") { + if ($v["type"] == "stream_output_start" + && !is_null($previous_previous_val) + && $previous_previous_val["type"] == "stream_output_end" + && self::areEventsLinked($previous_previous_val, $v)) { + + unset($data[$previous_previous_previous_key]); + unset($data[$previous_previous_key]); unset($data[$previous_key]); + if ($previous_previous_val['uri'] == $v['uri']) { + unset($data[$k]); + } } + + $previous_previous_previous_key = $previous_previous_key; + $previous_previous_previous_val = $previous_previous_val; + $previous_previous_key = $previous_key; + $previous_previous_val = $previous_val; $previous_key = $k; $previous_val = $v; } @@ -870,7 +904,7 @@ SQL; self::createInputHarborKickTimes($data, $range_start, $range_end); self::createScheduledEvents($data, $range_start, $range_end); - self::filterData($data["media"]); + self::foldData($data["media"]); return $data; } diff --git a/airtime_mvc/application/models/ShowBuilder.php b/airtime_mvc/application/models/ShowBuilder.php index c9bd495ef..a04bb4c8a 100644 --- a/airtime_mvc/application/models/ShowBuilder.php +++ b/airtime_mvc/application/models/ShowBuilder.php @@ -266,8 +266,12 @@ class Application_Model_ShowBuilder $row["instance"] = intval($p_item["si_id"]); $row["starts"] = $schedStartDT->format("H:i:s"); $row["ends"] = $schedEndDT->format("H:i:s"); - - $formatter = new LengthFormatter($p_item['file_length']); + + $cue_out = Application_Common_DateHelper::calculateLengthInSeconds($p_item['cue_out']); + $cue_in = Application_Common_DateHelper::calculateLengthInSeconds($p_item['cue_in']); + $run_time = $cue_out-$cue_in; + + $formatter = new LengthFormatter(Application_Common_DateHelper::ConvertMSToHHMMSSmm($run_time*1000)); $row['runtime'] = $formatter->format(); $row["title"] = $p_item["file_track_title"]; diff --git a/airtime_mvc/application/models/Webstream.php b/airtime_mvc/application/models/Webstream.php index 9297cb1d9..18545af18 100644 --- a/airtime_mvc/application/models/Webstream.php +++ b/airtime_mvc/application/models/Webstream.php @@ -34,7 +34,7 @@ class Application_Model_Webstream implements Application_Model_LibraryEditable public function getCreatorId() { - return $this->Webstream->getCcSubjs()->getDbId(); + return $this->webstream->getDbCreatorId(); } public function getLastModified($p_type) @@ -51,7 +51,7 @@ class Application_Model_Webstream implements Application_Model_LibraryEditable $di = new DateInterval("PT{$hours}H{$min}M{$sec}S"); return $di->format("%Hh %Im"); - } + } return ""; } diff --git a/airtime_mvc/locale/en_CA/LC_MESSAGES/airtime.po b/airtime_mvc/locale/en_CA/LC_MESSAGES/airtime.po index bbbb7033c..7062255d6 100644 --- a/airtime_mvc/locale/en_CA/LC_MESSAGES/airtime.po +++ b/airtime_mvc/locale/en_CA/LC_MESSAGES/airtime.po @@ -1,16 +1,16 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. +# CANADIAN (en_CA) translation for Airtime. +# Copyright (C) 2012 Sourcefabric +# This file is distributed under the same license as the Airtime package. +# Sourcefabric , 2012. # msgid "" msgstr "" "Project-Id-Version: Airtime 2.3\n" -"Report-Msgid-Bugs-To: \n" +"Report-Msgid-Bugs-To: contact@sourcefabric.org\n" "POT-Creation-Date: 2012-11-28 16:00-0500\n" "PO-Revision-Date: 2012-11-29 11:31-0500\n" "Last-Translator: Denise Rigato \n" -"Language-Team: Airtime\n" +"Language-Team: Canadian Localization \n" "Language: en_CA\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/airtime_mvc/locale/ko_KR/LC_MESSAGES/airtime.po b/airtime_mvc/locale/ko_KR/LC_MESSAGES/airtime.po index f7fb0a98d..5036ea923 100644 --- a/airtime_mvc/locale/ko_KR/LC_MESSAGES/airtime.po +++ b/airtime_mvc/locale/ko_KR/LC_MESSAGES/airtime.po @@ -1,17 +1,17 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. +# KOREAN (ko_KR) translation for Airtime. +# Copyright (C) 2012 Sourcefabric +# This file is distributed under the same license as the Airtime package. +# Sourcefabric , 2012. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" +"Project-Id-Version: Airtime 2.3\n" +"Report-Msgid-Bugs-To: contact@sourcefabric.org\n" "POT-Creation-Date: 2012-11-26 14:16-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" +"PO-Revision-Date: 2012-11-26 14:16-0500\n" +"Last-Translator: James Moon \n" +"Language-Team: Korean Localization \n" "Language: ko_KR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/airtime_mvc/public/js/airtime/audiopreview/preview_jplayer.js b/airtime_mvc/public/js/airtime/audiopreview/preview_jplayer.js index a90f8d46f..b5669d17a 100644 --- a/airtime_mvc/public/js/airtime/audiopreview/preview_jplayer.js +++ b/airtime_mvc/public/js/airtime/audiopreview/preview_jplayer.js @@ -154,12 +154,24 @@ function buildplaylist(p_url, p_playIndex) { continue; } } else if (data[index]['type'] == 1) { - media = {title: data[index]['element_title'], - artist: data[index]['element_artist'], - mp3:data[index]['uri'] - }; + var mime = data[index]['mime']; + if (mime.search(/mp3/i) > 0 || mime.search(/mpeg/i) > 0) { + key = "mp3"; + } else if (mime.search(/og(g|a)/i) > 0 || mime.search(/vorbis/i) > 0) { + key = "oga"; + } else if (mime.search(/mp4/i) > 0) { + key = "m4a"; + } else if (mime.search(/wav/i) > 0) { + key = "wav"; + } + + if (key) { + media = {title: data[index]['element_title'], + artist: data[index]['element_artist'] + }; + media[key] = data[index]['uri'] + } } - console.log(data[index]); if (media && isAudioSupported(data[index]['mime'])) { // javascript doesn't support associative array with numeric key // so we need to remove the gap if we skip any of tracks due to diff --git a/airtime_mvc/public/js/airtime/common/audioplaytest.js b/airtime_mvc/public/js/airtime/common/audioplaytest.js index f96ad09af..078d8f1e4 100644 --- a/airtime_mvc/public/js/airtime/common/audioplaytest.js +++ b/airtime_mvc/public/js/airtime/common/audioplaytest.js @@ -15,5 +15,6 @@ function isAudioSupported(mime){ //is adding a javascript library to do the work for you, which seems like overkill.... return (!!audio.canPlayType && audio.canPlayType(bMime) != "") || (mime.indexOf("mp3") != -1 && navigator.mimeTypes ["application/x-shockwave-flash"] != undefined) || - (mime.indexOf("mp4") != -1 && navigator.mimeTypes ["application/x-shockwave-flash"] != undefined); + (mime.indexOf("mp4") != -1 && navigator.mimeTypes ["application/x-shockwave-flash"] != undefined) || + (mime.indexOf("mpeg") != -1 && navigator.mimeTypes ["application/x-shockwave-flash"] != undefined); } diff --git a/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js b/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js index 60958f9bd..0b7be3d57 100644 --- a/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js +++ b/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js @@ -81,6 +81,10 @@ var AIRTIME = (function(AIRTIME) { return container; }, cursor : 'pointer', + cursorAt: { + top: 30, + left: 100 + }, connectToSortable : '#show_builder_table' }); }; diff --git a/airtime_mvc/public/js/airtime/library/library.js b/airtime_mvc/public/js/airtime/library/library.js index e9ece9a37..3d5af4570 100644 --- a/airtime_mvc/public/js/airtime/library/library.js +++ b/airtime_mvc/public/js/airtime/library/library.js @@ -973,7 +973,6 @@ function addProgressIcon(id) { } function checkLibrarySCUploadStatus(){ - var url = baseUrl+'/Library/get-upload-to-soundcloud-status', span, id; @@ -1026,6 +1025,7 @@ function addQtipToSCIcons(){ }); } else if($(this).hasClass("soundcloud")){ + var sc_id = $(this).parent().parent().data("aData").soundcloud_id; $(this).qtip({ content: { text: $.i18n._("Retrieving data from the server..."), diff --git a/install_minimal/include/airtime-constants.php b/install_minimal/include/airtime-constants.php index 8d028ec63..2968cab36 100644 --- a/install_minimal/include/airtime-constants.php +++ b/install_minimal/include/airtime-constants.php @@ -1,3 +1,3 @@ begin log("dynamic_source.output_start") webstream_enabled := true "enabled" end) + fun (s) -> begin log("dynamic_source.output_start") + notify([("schedule_table_id", !current_dyn_id)]) + webstream_enabled := true "enabled" end) server.register(namespace="dynamic_source", description="Enable webstream output", usage='stop', @@ -229,6 +224,7 @@ end s = switch(id="default_switch", track_sensitive=false, transitions=[transition_default, transition], [({!scheduled_play_enabled}, stream_queue),({true},default)]) + s = append_dj_inputs(master_live_stream_port, master_live_stream_mp, dj_live_stream_port, dj_live_stream_mp, s)