SAAS-1184 - bugfixes and polish
This commit is contained in:
parent
f352b61707
commit
bb7f8c1ed3
10 changed files with 105 additions and 24 deletions
|
@ -14,6 +14,7 @@ class FileDataHelper {
|
||||||
"audio/aac" => "aac",
|
"audio/aac" => "aac",
|
||||||
"audio/aacp" => "aac",
|
"audio/aacp" => "aac",
|
||||||
"audio/mp4" => "m4a",
|
"audio/mp4" => "m4a",
|
||||||
|
"video/mp4" => "mp4",
|
||||||
"audio/x-flac" => "flac",
|
"audio/x-flac" => "flac",
|
||||||
"audio/wav" => "wav",
|
"audio/wav" => "wav",
|
||||||
"audio/x-wav" => "wav",
|
"audio/x-wav" => "wav",
|
||||||
|
|
|
@ -40,6 +40,7 @@ class Application_Form_SoundcloudPreferences extends Zend_Form_SubForm
|
||||||
|
|
||||||
$this->addElement('image', 'SoundCloudConnect', array(
|
$this->addElement('image', 'SoundCloudConnect', array(
|
||||||
'src' => 'http://connect.soundcloud.com/2/btn-connect-sc-l.png',
|
'src' => 'http://connect.soundcloud.com/2/btn-connect-sc-l.png',
|
||||||
|
'target' => '_blank',
|
||||||
'decorators' => array(
|
'decorators' => array(
|
||||||
'ViewHelper'
|
'ViewHelper'
|
||||||
)
|
)
|
||||||
|
@ -47,6 +48,7 @@ class Application_Form_SoundcloudPreferences extends Zend_Form_SubForm
|
||||||
|
|
||||||
$this->addElement('image', 'SoundCloudDisconnect', array(
|
$this->addElement('image', 'SoundCloudDisconnect', array(
|
||||||
'src' => 'http://connect.soundcloud.com/2/btn-disconnect-l.png',
|
'src' => 'http://connect.soundcloud.com/2/btn-disconnect-l.png',
|
||||||
|
'target' => '_blank',
|
||||||
'decorators' => array(
|
'decorators' => array(
|
||||||
'ViewHelper'
|
'ViewHelper'
|
||||||
)
|
)
|
||||||
|
|
|
@ -80,6 +80,12 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<?php $subnavPrefix = "/showbuilder"; require_once APPLICATION_PATH . "views/scripts/partialviews/dashboard-sub-nav.php"; ?>
|
<?php $subnavPrefix = "/showbuilder"; require_once APPLICATION_PATH . "views/scripts/partialviews/dashboard-sub-nav.php"; ?>
|
||||||
|
<div class="media_type_selector dashboard_sub_nav" data-selection-id="<?php echo MediaType::PODCAST ?>">
|
||||||
|
<a href="<?php echo $subnavPrefix; ?>#podcasts">
|
||||||
|
<i class='icon-headphones icon-white'></i>
|
||||||
|
<span class="selector-name"><?php echo _("Podcasts") ?></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<hr style="margin-left: 5px; margin-right: 5px">
|
<hr style="margin-left: 5px; margin-right: 5px">
|
||||||
<div id="nav">
|
<div id="nav">
|
||||||
|
|
|
@ -267,6 +267,13 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir
|
||||||
: $this->_getImportedPodcastEpisodeArray($podcast, $episodes);
|
: $this->_getImportedPodcastEpisodeArray($podcast, $episodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an array of PodcastEpisodes objects from the Station Podcast,
|
||||||
|
* convert the episode data into array form
|
||||||
|
*
|
||||||
|
* @param array $episodes array of PodcastEpisodes to convert
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
private function _getStationPodcastEpisodeArray($episodes) {
|
private function _getStationPodcastEpisodeArray($episodes) {
|
||||||
$episodesArray = array();
|
$episodesArray = array();
|
||||||
foreach ($episodes as $episode) {
|
foreach ($episodes as $episode) {
|
||||||
|
@ -277,28 +284,42 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir
|
||||||
return $episodesArray;
|
return $episodesArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an ImportedPodcast object and an array of stored PodcastEpisodes objects,
|
||||||
|
* fetch all episodes from the podcast RSS feed, and serialize them in a readable form
|
||||||
|
*
|
||||||
|
* TODO: there's definitely a better approach than this... we should be trying to create
|
||||||
|
* PodcastEpisdoes objects instead of our own arrays
|
||||||
|
*
|
||||||
|
* @param ImportedPodcast $podcast Podcast object to fetch the episodes for
|
||||||
|
* @param array $episodes array of PodcastEpisodes objects to
|
||||||
|
*
|
||||||
|
* @return array array of episode data
|
||||||
|
*
|
||||||
|
* @throws CcFiles/FileNotFoundException
|
||||||
|
*/
|
||||||
public function _getImportedPodcastEpisodeArray($podcast, $episodes) {
|
public function _getImportedPodcastEpisodeArray($podcast, $episodes) {
|
||||||
$rss = Application_Service_PodcastService::getPodcastFeed($podcast->getDbUrl());
|
$rss = Application_Service_PodcastService::getPodcastFeed($podcast->getDbUrl());
|
||||||
$episodeIds = array();
|
$episodeIds = array();
|
||||||
$episodeFiles = array();
|
$episodeFiles = array();
|
||||||
foreach ($episodes as $e) {
|
foreach ($episodes as $e) {
|
||||||
|
/** @var PodcastEpisodes $e */
|
||||||
array_push($episodeIds, $e->getDbEpisodeGuid());
|
array_push($episodeIds, $e->getDbEpisodeGuid());
|
||||||
$episodeFiles[$e->getDbEpisodeGuid()] = $e->getDbFileId();
|
$episodeFiles[$e->getDbEpisodeGuid()] = $e->getDbFileId();
|
||||||
}
|
}
|
||||||
|
|
||||||
$episodesArray = array();
|
$episodesArray = array();
|
||||||
foreach ($rss->get_items() as $item) {
|
foreach ($rss->get_items() as $item) {
|
||||||
// If the enclosure is empty, this isn't a podcast episode
|
/** @var SimplePie_Item $item */
|
||||||
|
// If the enclosure is empty or has not URL, this isn't a podcast episode (there's no audio data)
|
||||||
$enclosure = $item->get_enclosure();
|
$enclosure = $item->get_enclosure();
|
||||||
$url = $enclosure instanceof SimplePie_Enclosure ? $enclosure->get_link() : $enclosure["link"];
|
$url = $enclosure instanceof SimplePie_Enclosure ? $enclosure->get_link() : $enclosure["link"];
|
||||||
if (empty($url)) {
|
if (empty($url)) { continue; }
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$itemId = $item->get_id();
|
$itemId = $item->get_id();
|
||||||
$ingested = in_array($itemId, $episodeIds) ? (empty($episodeFiles[$itemId]) ? -1 : 1) : 0;
|
$ingested = in_array($itemId, $episodeIds) ? (empty($episodeFiles[$itemId]) ? -1 : 1) : 0;
|
||||||
$file = $ingested > 0 && !empty($episodeFiles[$itemId]) ?
|
$file = $ingested > 0 && !empty($episodeFiles[$itemId]) ?
|
||||||
CcFiles::getSanitizedFileById($episodeFiles[$itemId]) : array();
|
CcFiles::getSanitizedFileById($episodeFiles[$itemId]) : array();
|
||||||
/** @var SimplePie_Item $item */
|
|
||||||
array_push($episodesArray, array(
|
array_push($episodesArray, array(
|
||||||
"podcast_id" => $podcast->getDbId(),
|
"podcast_id" => $podcast->getDbId(),
|
||||||
"guid" => $itemId,
|
"guid" => $itemId,
|
||||||
|
@ -306,7 +327,7 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir
|
||||||
"title" => $item->get_title(),
|
"title" => $item->get_title(),
|
||||||
// From the RSS spec best practices:
|
// From the RSS spec best practices:
|
||||||
// 'An item's author element provides the e-mail address of the person who wrote the item'
|
// 'An item's author element provides the e-mail address of the person who wrote the item'
|
||||||
"author" => $item->get_author()->get_email(),
|
"author" => $this->_buildAuthorString($item),
|
||||||
"description" => htmlspecialchars($item->get_description()),
|
"description" => htmlspecialchars($item->get_description()),
|
||||||
"pub_date" => $item->get_gmdate(),
|
"pub_date" => $item->get_gmdate(),
|
||||||
"link" => $item->get_link(),
|
"link" => $item->get_link(),
|
||||||
|
@ -318,6 +339,23 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir
|
||||||
return $episodesArray;
|
return $episodesArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a string representation of the author fields of a SimplePie_Item object
|
||||||
|
*
|
||||||
|
* @param SimplePie_Item $item the SimplePie_Item to extract the author data from
|
||||||
|
*
|
||||||
|
* @return string the string representation of the author data
|
||||||
|
*/
|
||||||
|
private function _buildAuthorString(SimplePie_Item $item) {
|
||||||
|
$authorString = $author = $item->get_author();
|
||||||
|
if (!empty($author)) {
|
||||||
|
$authorString = $author->get_email();
|
||||||
|
$authorString = empty($authorString) ? $author->get_name() : $authorString;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $authorString;
|
||||||
|
}
|
||||||
|
|
||||||
public function deletePodcastEpisodeById($episodeId)
|
public function deletePodcastEpisodeById($episodeId)
|
||||||
{
|
{
|
||||||
$episode = PodcastEpisodesQuery::create()->findByDbId($episodeId);
|
$episode = PodcastEpisodesQuery::create()->findByDbId($episodeId);
|
||||||
|
|
|
@ -22,9 +22,3 @@
|
||||||
<span class="selector-name"><?php echo _("Webstreams") ?></span>
|
<span class="selector-name"><?php echo _("Webstreams") ?></span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="media_type_selector dashboard_sub_nav" data-selection-id="<?php echo MediaType::PODCAST ?>">
|
|
||||||
<a href="<?php echo $subnavPrefix; ?>#podcasts">
|
|
||||||
<i class='icon-headphones icon-white'></i>
|
|
||||||
<span class="selector-name"><?php echo _("Podcasts") ?></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
|
@ -1255,7 +1255,9 @@ var AIRTIME = (function(AIRTIME) {
|
||||||
* @param table the table to show
|
* @param table the table to show
|
||||||
*/
|
*/
|
||||||
mod.setCurrentTable = function (table) {
|
mod.setCurrentTable = function (table) {
|
||||||
if (oTable) oTable.fnClearTable();
|
if (oTable && oTable === $datatables[mod.DataTableTypeEnum.PODCAST_EPISODES]) {
|
||||||
|
oTable.fnClearTable();
|
||||||
|
}
|
||||||
var dt = $datatables[table],
|
var dt = $datatables[table],
|
||||||
wrapper = $(dt).closest(".dataTables_wrapper");
|
wrapper = $(dt).closest(".dataTables_wrapper");
|
||||||
$("#library_content").find(".dataTables_wrapper").hide();
|
$("#library_content").find(".dataTables_wrapper").hide();
|
||||||
|
@ -1718,8 +1720,9 @@ var validationTypes = {
|
||||||
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
if (window.location.href.indexOf("showbuilder") > -1) {
|
||||||
AIRTIME.library.initPodcastDatatable();
|
AIRTIME.library.initPodcastDatatable();
|
||||||
|
}
|
||||||
|
|
||||||
$("#advanced-options").on("click", function() {
|
$("#advanced-options").on("click", function() {
|
||||||
resizeAdvancedSearch();
|
resizeAdvancedSearch();
|
||||||
|
|
|
@ -146,10 +146,21 @@ var AIRTIME = (function (AIRTIME) {
|
||||||
* Sets up the internal datatable.
|
* Sets up the internal datatable.
|
||||||
*/
|
*/
|
||||||
PodcastController.prototype.initialize = function() {
|
PodcastController.prototype.initialize = function() {
|
||||||
|
var self = this;
|
||||||
// TODO: this solves a race condition, but we should look for the root cause
|
// TODO: this solves a race condition, but we should look for the root cause
|
||||||
AIRTIME.tabs.onResize();
|
AIRTIME.tabs.onResize();
|
||||||
this.$scope.tab.setName(this.$scope.podcast.title);
|
self.$scope.tab.setName(self.$scope.podcast.title);
|
||||||
this._initTable();
|
self._initTable();
|
||||||
|
// Add an onclose hook to the tab to remove the table object and the
|
||||||
|
// import listener so we don't cause memory leaks.
|
||||||
|
if (self.episodeTable) {
|
||||||
|
self.$scope.tab.assignOnCloseHandler(function () {
|
||||||
|
self.episodeTable.destroy();
|
||||||
|
self.episodeTable = null;
|
||||||
|
self.$scope.tab = null;
|
||||||
|
self.$scope.$destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -444,6 +455,7 @@ var AIRTIME = (function (AIRTIME) {
|
||||||
self.importListener = setInterval(function () {
|
self.importListener = setInterval(function () {
|
||||||
var podcastId = self.config.podcastId, pendingRows = [];
|
var podcastId = self.config.podcastId, pendingRows = [];
|
||||||
if (!podcastId) return false;
|
if (!podcastId) return false;
|
||||||
|
console.log(self);
|
||||||
var dt = self.getDatatable(), data = dt.fnGetData();
|
var dt = self.getDatatable(), data = dt.fnGetData();
|
||||||
// Iterate over the table data to check for any rows pending import
|
// Iterate over the table data to check for any rows pending import
|
||||||
$.each(data, function () {
|
$.each(data, function () {
|
||||||
|
@ -475,6 +487,13 @@ var AIRTIME = (function (AIRTIME) {
|
||||||
}
|
}
|
||||||
}, 10000); // Run every 10 seconds
|
}, 10000); // Run every 10 seconds
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explicit destructor
|
||||||
|
*/
|
||||||
|
PodcastEpisodeTable.prototype.destroy = function () {
|
||||||
|
clearInterval(this.importListener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -552,9 +571,9 @@ var AIRTIME = (function (AIRTIME) {
|
||||||
*/
|
*/
|
||||||
mod.editSelectedEpisodes = function (episodes) {
|
mod.editSelectedEpisodes = function (episodes) {
|
||||||
$.each(episodes, function () {
|
$.each(episodes, function () {
|
||||||
if (!Object.keys(this.file).length > 0) return false;
|
if (this.file && !Object.keys(this.file).length > 0) return false;
|
||||||
var uid = AIRTIME.library.MediaTypeStringEnum.FILE + "_" + this.file.id;
|
var fileId = this.file_id || this.file.id, uid = AIRTIME.library.MediaTypeStringEnum.FILE + "_" + fileId;
|
||||||
$.get(baseUrl + "library/edit-file-md/id/" + this.file.id, {format: "json"}, function (json) {
|
$.get(baseUrl + "library/edit-file-md/id/" + fileId, {format: "json"}, function (json) {
|
||||||
AIRTIME.playlist.fileMdEdit(json, uid);
|
AIRTIME.playlist.fileMdEdit(json, uid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -568,7 +587,7 @@ var AIRTIME = (function (AIRTIME) {
|
||||||
*/
|
*/
|
||||||
mod.importSelectedEpisodes = function (episodes, dt) {
|
mod.importSelectedEpisodes = function (episodes, dt) {
|
||||||
$.each(episodes, function () {
|
$.each(episodes, function () {
|
||||||
if (Object.keys(this.file).length > 0) return false;
|
if (this.file && Object.keys(this.file).length > 0) return false;
|
||||||
var podcastId = this.podcast_id;
|
var podcastId = this.podcast_id;
|
||||||
$.post(endpoint + podcastId + '/episodes', JSON.stringify({
|
$.post(endpoint + podcastId + '/episodes', JSON.stringify({
|
||||||
csrf_token: $("#csrf").val(),
|
csrf_token: $("#csrf").val(),
|
||||||
|
|
|
@ -59,7 +59,7 @@ var AIRTIME = (function (AIRTIME) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Object.keys(data).length > 0) {
|
if (data && Object.keys(data).length > 0) {
|
||||||
$http.put(endpoint + mediaId + '/publish', {csrf_token: jQuery("#csrf").val(), sources: data})
|
$http.put(endpoint + mediaId + '/publish', {csrf_token: jQuery("#csrf").val(), sources: data})
|
||||||
.success(function () {
|
.success(function () {
|
||||||
init();
|
init();
|
||||||
|
|
|
@ -216,7 +216,7 @@ function buildScheduleDialog (json, instance_id) {
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
text: $.i18n._("Ok"),
|
text: $.i18n._("Ok"),
|
||||||
"class": "btn",
|
class: "btn",
|
||||||
click: function() {
|
click: function() {
|
||||||
$(this).dialog("close");
|
$(this).dialog("close");
|
||||||
//getUsabilityHint();
|
//getUsabilityHint();
|
||||||
|
|
|
@ -136,6 +136,13 @@ var AIRTIME = (function(AIRTIME){
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal destructor. Can be assigned via assignOnCloseHandler
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Tab.prototype._destroy = function () {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign the given function f as the click handler for the tab
|
* Assign the given function f as the click handler for the tab
|
||||||
*
|
*
|
||||||
|
@ -164,6 +171,15 @@ var AIRTIME = (function(AIRTIME){
|
||||||
this.tab.find(".lib_pl_close").unbind("click").click(f);
|
this.tab.find(".lib_pl_close").unbind("click").click(f);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assign an implicit destructor
|
||||||
|
*
|
||||||
|
* @param {function} fn function to run when this Tab is destroyed
|
||||||
|
*/
|
||||||
|
Tab.prototype.assignOnCloseHandler = function (fn) {
|
||||||
|
this._destroy = fn;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open this tab in the right-hand pane and set it as the currently active tab
|
* Open this tab in the right-hand pane and set it as the currently active tab
|
||||||
*/
|
*/
|
||||||
|
@ -205,6 +221,8 @@ var AIRTIME = (function(AIRTIME){
|
||||||
} else {
|
} else {
|
||||||
mod.onResize();
|
mod.onResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self._destroy();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue