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

This commit is contained in:
Martin Konecny 2012-08-23 15:04:38 -04:00
commit a9cf597f14
16 changed files with 993 additions and 67 deletions

View File

@ -37,6 +37,7 @@ class LibraryController extends Zend_Controller_Action
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColVis.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColReorder.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.FixedColumns.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.columnFilter.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/buttons/buttons.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/utilities/utilities.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
@ -56,6 +57,7 @@ class LibraryController extends Zend_Controller_Action
$obj_sess = new Zend_Session_Namespace(UI_PLAYLISTCONTROLLER_OBJ_SESSNAME);
if (isset($obj_sess->id)) {
$objInfo = Application_Model_Library::getObjInfo($obj_sess->type);
Logging::info($obj_sess->id);
Logging::info($obj_sess->type);
$objInfo = Application_Model_Library::getObjInfo($obj_sess->type);

View File

@ -74,6 +74,7 @@ class ScheduleController extends Zend_Controller_Action
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColReorder.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.FixedColumns.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.TableTools.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.columnFilter.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/buttons/buttons.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($this->view->baseUrl('/js/airtime/library/events/library_showbuilder.js?'.$CC_CONFIG['airtime_version']),'text/javascript');

View File

@ -50,6 +50,7 @@ class ShowbuilderController extends Zend_Controller_Action
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColVis.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColReorder.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.FixedColumns.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.columnFilter.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/blockui/jquery.blockUI.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/buttons/buttons.js?'.$CC_CONFIG['airtime_version'],'text/javascript');

View File

@ -451,6 +451,10 @@ EOT;
$this->block->save($this->con);
$this->con->commit();
//check if block is in any playlists and update the playlist's length
Application_Model_Playlist::updatePlaylistsLengthWithBlock($this->id, $this->getLength());
} catch (Exception $e) {
$this->con->rollback();
throw $e;
@ -562,6 +566,11 @@ EOT;
$this->block->save($this->con);
$this->con->commit();
//check if block is in any playlists and update the playlist's length
Application_Model_Playlist::updatePlaylistsLengthWithBlock($this->id, $this->getLength());
} catch (Exception $e) {
$this->con->rollback();
throw $e;
@ -1166,6 +1175,9 @@ EOT;
// multiply 1000 because we store only number value
// e.g 192kps is stored as 192000
$spCriteriaValue = $criteria['value']*1000;
if (isset($criteria['extra'])) {
$criteria['extra'] *= 1000;
}
} else {
$spCriteriaValue = addslashes($criteria['value']);
}

View File

@ -2,12 +2,74 @@
class Application_Model_Datatables
{
private static function buildWhereClauseForAdvancedSearch($dbname2searchTerm)
{
$where = array();
foreach ($dbname2searchTerm as $dbname=>$term) {
$isRange = false;
if (strstr($term, '~')) {
$info = explode('~', $term);
$input1 = isset($info[0])?$info[0]:null;
$input2 = isset($info[1])?$info[1]:null;
$isRange = true;
} else {
$input1 = $term;
}
if ($isRange) {
$sub = array();
if ($input1 != null) {
$sub[] = $dbname." >= '".$input1."'";
}
if ($input2 != null) {
$sub[] = $dbname." <= '".$input2."'";
}
if (!empty($sub)) {
$where[] = "(".implode(' AND ', $sub).")";
}
} else {
if (trim($input1) !== "") {
$where[] = $dbname." ILIKE "."'%".$input1."%'";
}
}
}
return implode(" AND ", $where);
}
/*
* query used to return data for a paginated/searchable datatable.
*/
public static function findEntries($con, $displayColumns, $fromTable, $data, $dataProp = "aaData")
{
$librarySetting = Application_Model_Preference::getCurrentLibraryTableSetting();
// map that maps original column position to db name
$current2dbname = array();
// array of search terms
$orig2searchTerm= array();
foreach ($data as $key=>$d) {
if (strstr($key, "mDataProp_")) {
list($dump, $index) = explode("_", $key);
$current2dbname[$index] = $d;
} else if (strstr($key, "sSearch_")) {
list($dump, $index) = explode("_", $key);
$orig2searchTerm[$index] = $d;
}
}
// map that maps current column position to original position
$current2orig = $librarySetting['ColReorder'];
// map that maps dbname to searchTerm
$dbname2searchTerm = array();
foreach ($current2dbname as $currentPos=>$dbname) {
$dbname2searchTerm[$dbname] = $orig2searchTerm[$current2orig[$currentPos]];
}
$where = array();
$advancedWhere = self::buildWhereClauseForAdvancedSearch($dbname2searchTerm);
if ($advancedWhere != "") {
$where[] = $advancedWhere;
}
if ($data["sSearch"] !== "") {
$searchTerms = explode(" ", $data["sSearch"]);

View File

@ -913,6 +913,26 @@ SQL;
{
CcPlaylistcontentsQuery::create()->findByDbPlaylistId($this->id)->delete();
}
/**
* After items get deleted/added from/to a block
* this function updates the length of playlists
* that contain that block
*/
public static function updatePlaylistsLengthWithBlock($p_blockId, $p_blockLength) {
$playlists = CcPlaylistQuery::create()->find();
foreach ($playlists as $pl) {
$contents = CcPlaylistcontentsQuery::create()->findByDbPlaylistId($pl->getDbId());
//check if the block is in each playlist
foreach ($contents as $item) {
if ($item->getDbBlockId() == $p_blockId) {
$item->setDbCliplength($p_blockLength);
$con = Propel::getConnection(CcPlaylistPeer::DATABASE_NAME);
$item->save($con);
}
}
}
}
} // class Playlist

View File

@ -1099,4 +1099,8 @@ class Application_Model_Preference
return true;
}
}
public static function getCurrentLibraryTableSetting(){
return unserialize(self::getValue("library_datatable"));
}
}

View File

@ -853,58 +853,55 @@ class Application_Model_StoredFile
{
$audio_file = $p_targetDir . DIRECTORY_SEPARATOR . $tempname;
Logging::info('copyFileToStor: moving file '.$audio_file);
$md5 = md5_file($audio_file);
$duplicate = Application_Model_StoredFile::RecallByMd5($md5, true);
$result = null;
if ($duplicate) {
if (file_exists($duplicate->getFilePath())) {
$duplicateName = $duplicate->getMetadataValue('MDATA_KEY_TITLE');
$result = array( "code" => 106, "message" => "An identical audioclip named '$duplicateName' already exists on the server.");
$storDir = Application_Model_MusicDir::getStorDir();
$stor = $storDir->getDirectory();
// check if "organize" dir exists and if not create one
if (!file_exists($stor."/organize")) {
if (!mkdir($stor."/organize", 0777)) {
return array(
"code" => 109,
"message" => "Failed to create 'organize' directory.");
}
}
if (!isset($result)) {//The file has no duplicate, so proceed to copy.
$storDir = Application_Model_MusicDir::getStorDir();
$stor = $storDir->getDirectory();
// check if "organize" dir exists and if not create one
if (!file_exists($stor."/organize")) {
if (!mkdir($stor."/organize", 0777)) {
$result = array("code" => 109, "message" => "Failed to create 'organize' directory.");
return $result;
}
}
if (chmod($audio_file, 0644) === false) {
Logging::info("Warning: couldn't change permissions of $audio_file to 0644");
}
//check to see if there is enough space in $stor to continue.
if (self::isEnoughDiskSpaceToCopy($stor, $audio_file)) {
$audio_stor = Application_Common_OsPath::join($stor, "organize", $fileName);
if (self::liquidsoapFilePlayabilityTest($audio_file)) {
Logging::info("copyFileToStor: moving file $audio_file to $audio_stor");
//Martin K.: changed to rename: Much less load + quicker since this is an atomic operation
if (@rename($audio_file, $audio_stor) === false) {
#something went wrong likely there wasn't enough space in the audio_stor to move the file too.
#warn the user that the file wasn't uploaded and they should check if there is enough disk space.
unlink($audio_file);//remove the file after failed rename
$result = array("code" => 108, "message" => "The file was not uploaded, this error can occur if the computer hard drive does not have enough disk space or the stor directory does not have correct write permissions.");
}
} else {
$result = array("code" => 110, "message" => "This file appears to be corrupted and will not be added to media library.");
}
} else {
$result = array("code" => 107, "message" => "The file was not uploaded, there is ".$freeSpace."MB of disk space left and the file you are uploading has a size of ".$fileSize."MB.");
}
if (chmod($audio_file, 0644) === false) {
Logging::info("Warning: couldn't change permissions of $audio_file to 0644");
}
return $result;
// Check if we have enough space before copying
if(!self::isEnoughDiskSpaceToCopy($stor, $audio_file)) {
$freeSpace = disk_free_space($stor);
return array("code" => 107,
"message" => "The file was not uploaded, there is
".$freeSpace."MB of disk space left and the file you are
uploading has a size of ".$fileSize."MB.");
}
// Check if liquidsoap can play this file
if(!self::liquidsoapFilePlayabilityTest($audio_file)) {
return array(
"code" => 110,
"message" => "This file appears to be corrupted and will not
be added to media library.");
}
// Did all the checks for realz, now trying to copy
$audio_stor = Application_Common_OsPath::join($stor, "organize", $fileName);
Logging::info("copyFileToStor: moving file $audio_file to $audio_stor");
//Martin K.: changed to rename: Much less load + quicker since this is an atomic operation
if (@rename($audio_file, $audio_stor) === false) {
#something went wrong likely there wasn't enough space in the audio_stor to move the file too.
#warn the user that the file wasn't uploaded and they should check if there is enough disk space.
unlink($audio_file);//remove the file after failed rename
return array(
"code" => 108,
"message" => "
The file was not uploaded, this error can occur if the computer
hard drive does not have enough disk space or the stor
directory does not have correct write permissions. ");
}
return null;
}
/*

View File

@ -5,7 +5,7 @@
<tr><td>Album:</td><td><?php echo ($this->md["MDATA_KEY_SOURCE"]);?></td></tr>
<tr><td>Track:</td><td><?php echo ($this->md["MDATA_KEY_TRACKNUMBER"]);?></td></tr>
<tr><td>Length:</td><td><?php echo ($this->md["MDATA_KEY_DURATION"]);?></td></tr>
<tr><td>Sample Rate:</td><td><?php echo ($this->md["MDATA_KEY_SAMPLERATE"]);?></td></tr>
<tr><td class='file-md-qtip-nowrap'>Sample Rate:</td><td><?php echo ($this->md["MDATA_KEY_SAMPLERATE"]);?></td></tr>
<tr><td>Bit Rate:</td><td><?php echo ($this->md["MDATA_KEY_BITRATE"]);?></td></tr>
<tr><td>Mood:</td><td><?php echo ($this->md["MDATA_KEY_MOOD"]);?></td></tr>
<tr><td>Genre:</td><td><?php echo ($this->md["MDATA_KEY_GENRE"]);?></td></tr>

View File

@ -1,2 +1,5 @@
<div id="import_status" class="library_import" style="display:none">File import in progress... <img src="/css/images/file_import_loader.gif"></img></div>
<table id="library_display" cellpadding="0" cellspacing="0" class="datatable"></table>
<div id="advanced_search">
</div>
<table id="library_display" cellpadding="0" cellspacing="0" class="datatable">
</table>

View File

@ -24,6 +24,10 @@ if ($item['type'] == 2) {
<div class="big_play ui-state-hover" blockId="<?php echo $item["item_id"]; ?>">
<span class="ui-icon ui-icon-alert"></span>
</div>
<?php else:?>
<div class="big_play ui-state-hover">
<span class="ui-icon ui-icon-alert"></span>
</div>
<?php endif; ?>
<div class="text-row top">
<span class="spl_playlength"><?php echo $item["length"] ?></span>

View File

@ -8,6 +8,35 @@ var AIRTIME = (function(AIRTIME) {
chosenItems = {},
visibleChosenItems = {};
var criteriaTypes = {
0 : "",
"album_title" : "s",
"artist_name" : "s",
"bit_rate" : "n",
"bpm" : "n",
"comments" : "s",
"composer" : "s",
"conductor" : "s",
"utime" : "n",
"mtime" : "n",
"lptime" : "n",
"disc_number" : "n",
"genre" : "s",
"isrc_number" : "s",
"label" : "s",
"language" : "s",
"length" : "n",
"lyricist" : "s",
"mood" : "s",
"name" : "s",
"orchestra" : "s",
"rating" : "n",
"sample_rate" : "n",
"track_title" : "s",
"track_num" : "n",
"year" : "n"
};
if (AIRTIME.library === undefined) {
AIRTIME.library = {};
}
@ -303,11 +332,57 @@ var AIRTIME = (function(AIRTIME) {
$el.removeClass("ui-state-hover");
}
});
var colReorderMap = new Array();
$libTable = $libContent.find("table");
var tableHeight = $libContent.height() - 130;
function setColumnFilter(oTable){
var aoCols = oTable.fnSettings().aoColumns;
var colsForAdvancedSearch = new Array();
var advanceSearchDiv = $("div#advanced_search");
advanceSearchDiv.empty();
$.each(aoCols, function(i,ele){
if (ele.bSearchable) {
var currentColId = ele._ColReorder_iOrigCol;
if (ele.bVisible) {
advanceSearchDiv.append("<div id='advanced_search_col_"+currentColId+"'><span>"+ele.sTitle+"</span> : <span id='"+ele.mDataProp+"'></span></div>");
} else {
advanceSearchDiv.append("<div id='advanced_search_col_"+currentColId+"' style='display:none;'><span>"+ele.sTitle+"</span> : <span id='"+ele.mDataProp+"'></span></div>");
}
if (criteriaTypes[ele.mDataProp] == "s") {
var obj = { sSelector: "#"+ele.mDataProp }
} else {
var obj = { sSelector: "#"+ele.mDataProp, type: "number-range" }
}
colsForAdvancedSearch.push(obj);
} else {
colsForAdvancedSearch.push(null);
}
});
oTable.columnFilter({
aoColumns: colsForAdvancedSearch,
bUseColVis: true,
sPlaceHolder: "head:before"
}
);
}
function setFilterElement(iColumn, bVisible){
var actualId = colReorderMap[iColumn];
var selector = "div#advanced_search_col_"+actualId;
if (bVisible) {
$(selector).show();
} else {
$(selector).hide();
}
}
var currentColOrder = new Array();
oTable = $libTable.dataTable( {
//put hidden columns at the top to insure they can never be visible on the table through column reordering.
@ -323,19 +398,19 @@ var AIRTIME = (function(AIRTIME) {
/* Length */ {"sTitle": "Length", "mDataProp": "length", "sClass": "library_length", "sWidth": "80px"},
/* Upload Time */ {"sTitle": "Uploaded", "mDataProp": "utime", "sClass": "library_upload_time", "sWidth": "125px"},
/* Last Modified */ {"sTitle": "Last Modified", "mDataProp": "mtime", "bVisible": false, "sClass": "library_modified_time", "sWidth": "125px"},
/* Track Number */ {"sTitle": "Track", "mDataProp": "track_number", "bSearchable": false, "bVisible": false, "sClass": "library_track", "sWidth": "65px"},
/* Mood */ {"sTitle": "Mood", "mDataProp": "mood", "bSearchable": false, "bVisible": false, "sClass": "library_mood", "sWidth": "70px"},
/* BPM */ {"sTitle": "BPM", "mDataProp": "bpm", "bSearchable": false, "bVisible": false, "sClass": "library_bpm", "sWidth": "50px"},
/* Composer */ {"sTitle": "Composer", "mDataProp": "composer", "bSearchable": false, "bVisible": false, "sClass": "library_composer", "sWidth": "150px"},
/* Website */ {"sTitle": "Website", "mDataProp": "info_url", "bSearchable": false, "bVisible": false, "sClass": "library_url", "sWidth": "150px"},
/* Bit Rate */ {"sTitle": "Bit Rate", "mDataProp": "bit_rate", "bSearchable": false, "bVisible": false, "sClass": "library_bitrate", "sWidth": "80px"},
/* Sample Rate */ {"sTitle": "Sample", "mDataProp": "sample_rate", "bSearchable": false, "bVisible": false, "sClass": "library_sr", "sWidth": "80px"},
/* ISRC Number */ {"sTitle": "ISRC", "mDataProp": "isrc_number", "bSearchable": false, "bVisible": false, "sClass": "library_isrc", "sWidth": "150px"},
/* Encoded */ {"sTitle": "Encoded", "mDataProp": "encoded_by", "bSearchable": false, "bVisible": false, "sClass": "library_encoded", "sWidth": "150px"},
/* Label */ {"sTitle": "Label", "mDataProp": "label", "bSearchable": false, "bVisible": false, "sClass": "library_label", "sWidth": "125px"},
/* Copyright */ {"sTitle": "Copyright", "mDataProp": "copyright", "bSearchable": false, "bVisible": false, "sClass": "library_copyright", "sWidth": "125px"},
/* Mime */ {"sTitle": "Mime", "mDataProp": "mime", "bSearchable": false, "bVisible": false, "sClass": "library_mime", "sWidth": "80px"},
/* Language */ {"sTitle": "Language", "mDataProp": "language", "bSearchable": false, "bVisible": false, "sClass": "library_language", "sWidth": "125px"}
/* Track Number */ {"sTitle": "Track", "mDataProp": "track_number", "bVisible": false, "sClass": "library_track", "sWidth": "65px"},
/* Mood */ {"sTitle": "Mood", "mDataProp": "mood", "bVisible": false, "sClass": "library_mood", "sWidth": "70px"},
/* BPM */ {"sTitle": "BPM", "mDataProp": "bpm", "bVisible": false, "sClass": "library_bpm", "sWidth": "50px"},
/* Composer */ {"sTitle": "Composer", "mDataProp": "composer", "bVisible": false, "sClass": "library_composer", "sWidth": "150px"},
/* Website */ {"sTitle": "Website", "mDataProp": "info_url", "bVisible": false, "sClass": "library_url", "sWidth": "150px"},
/* Bit Rate */ {"sTitle": "Bit Rate", "mDataProp": "bit_rate", "bVisible": false, "sClass": "library_bitrate", "sWidth": "80px"},
/* Sample Rate */ {"sTitle": "Sample", "mDataProp": "sample_rate", "bVisible": false, "sClass": "library_sr", "sWidth": "80px"},
/* ISRC Number */ {"sTitle": "ISRC", "mDataProp": "isrc_number", "bVisible": false, "sClass": "library_isrc", "sWidth": "150px"},
/* Encoded */ {"sTitle": "Encoded", "mDataProp": "encoded_by", "bVisible": false, "sClass": "library_encoded", "sWidth": "150px"},
/* Label */ {"sTitle": "Label", "mDataProp": "label", "bVisible": false, "sClass": "library_label", "sWidth": "125px"},
/* Copyright */ {"sTitle": "Copyright", "mDataProp": "copyright", "bVisible": false, "sClass": "library_copyright", "sWidth": "125px"},
/* Mime */ {"sTitle": "Mime", "mDataProp": "mime", "bVisible": false, "sClass": "library_mime", "sWidth": "80px"},
/* Language */ {"sTitle": "Language", "mDataProp": "language", "bVisible": false, "sClass": "library_language", "sWidth": "125px"}
],
"bProcessing": true,
@ -350,15 +425,15 @@ var AIRTIME = (function(AIRTIME) {
delete oData.aoSearchCols;
},
"fnStateSave": function (oSettings, oData) {
localStorage.setItem('datatables-library', JSON.stringify(oData));
$.ajax({
url: "/usersettings/set-library-datatable",
type: "POST",
data: {settings : oData, format: "json"},
dataType: "json"
});
colReorderMap = oData.ColReorder;
},
"fnStateLoad": function fnLibStateLoad(oSettings) {
var settings = localStorage.getItem('datatables-library');
@ -371,7 +446,7 @@ var AIRTIME = (function(AIRTIME) {
var i,
length,
a = oData.abVisCols;
//putting serialized data back into the correct js type to make
//sure everything works properly.
for (i = 0, length = a.length; i < length; i++) {
@ -386,7 +461,7 @@ var AIRTIME = (function(AIRTIME) {
a[i] = parseInt(a[i], 10);
}
}
oData.iEnd = parseInt(oData.iEnd, 10);
oData.iLength = parseInt(oData.iLength, 10);
oData.iStart = parseInt(oData.iStart, 10);
@ -526,7 +601,8 @@ var AIRTIME = (function(AIRTIME) {
"oColVis": {
"sAlign": "right",
"aiExclude": [0, 1, 2],
"sSize": "css"
"sSize": "css",
"fnStateChange": setFilterElement
},
"oColReorder": {
@ -534,6 +610,7 @@ var AIRTIME = (function(AIRTIME) {
}
});
setColumnFilter(oTable);
oTable.fnSetFilteringDelay(350);
$libContent.find(".dataTables_scrolling").css("max-height", tableHeight);

View File

@ -0,0 +1,733 @@
/*
* File: jquery.dataTables.columnFilter.js
* Version: 1.4.8.
* Author: Jovan Popovic
*
* Copyright 2011-2012 Jovan Popovic, all rights reserved.
*
* This source file is free software, under either the GPL v2 license or a
* BSD style license, as supplied with this software.
*
* This source file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.
*
* Parameters:"
* @sPlaceHolder String Place where inline filtering function should be placed ("tfoot", "thead:before", "thead:after"). Default is "tfoot"
* @sRangeSeparator String Separator that will be used when range values are sent to the server-side. Default value is "~".
* @sRangeFormat string Default format of the From ... to ... range inputs. Default is From {from} to {to}
* @aoColumns Array Array of the filter settings that will be applied on the columns
*/
(function ($) {
$.fn.columnFilter = function (options) {
var asInitVals, i, label, th;
//var sTableId = "table";
var sRangeFormat = "From {from} to {to}";
//Array of the functions that will override sSearch_ parameters
var afnSearch_ = new Array();
var aiCustomSearch_Indexes = new Array();
var oFunctionTimeout = null;
var fnOnFiltered = function () { };
function _fnGetColumnValues(oSettings, iColumn, bUnique, bFiltered, bIgnoreEmpty) {
///<summary>
///Return values in the column
///</summary>
///<param name="oSettings" type="Object">DataTables settings</param>
///<param name="iColumn" type="int">Id of the column</param>
///<param name="bUnique" type="bool">Return only distinct values</param>
///<param name="bFiltered" type="bool">Return values only from the filtered rows</param>
///<param name="bIgnoreEmpty" type="bool">Ignore empty cells</param>
// check that we have a column id
if (typeof iColumn == "undefined") return new Array();
// by default we only wany unique data
if (typeof bUnique == "undefined") bUnique = true;
// by default we do want to only look at filtered data
if (typeof bFiltered == "undefined") bFiltered = true;
// by default we do not wany to include empty values
if (typeof bIgnoreEmpty == "undefined") bIgnoreEmpty = true;
// list of rows which we're going to loop through
var aiRows;
// use only filtered rows
if (bFiltered == true) aiRows = oSettings.aiDisplay;
// use all rows
else aiRows = oSettings.aiDisplayMaster; // all row numbers
// set up data array
var asResultData = new Array();
for (var i = 0, c = aiRows.length; i < c; i++) {
iRow = aiRows[i];
var aData = oTable.fnGetData(iRow);
var sValue = aData[iColumn];
// ignore empty values?
if (bIgnoreEmpty == true && sValue.length == 0) continue;
// ignore unique values?
else if (bUnique == true && jQuery.inArray(sValue, asResultData) > -1) continue;
// else push the value onto the result data array
else asResultData.push(sValue);
}
return asResultData.sort();
}
function _fnColumnIndex(iColumnIndex) {
if (properties.bUseColVis)
return iColumnIndex;
else
return oTable.fnSettings().oApi._fnVisibleToColumnIndex(oTable.fnSettings(), iColumnIndex);
//return iColumnIndex;
//return oTable.fnSettings().oApi._fnColumnIndexToVisible(oTable.fnSettings(), iColumnIndex);
}
function fnCreateInput(oTable, regex, smart, bIsNumber, iFilterLength, iMaxLenght) {
var sCSSClass = "text_filter";
if (bIsNumber)
sCSSClass = "number_filter";
label = label.replace(/(^\s*)|(\s*$)/g, "");
var currentFilter = oTable.fnSettings().aoPreSearchCols[i].sSearch;
var search_init = 'search_init ';
var inputvalue = label;
if (currentFilter != '' && currentFilter != '^') {
if (bIsNumber && currentFilter.charAt(0) == '^')
inputvalue = currentFilter.substr(1); //ignore trailing ^
else
inputvalue = currentFilter;
search_init = '';
}
var input = $('<input type="text" class="' + search_init + sCSSClass + '" value="' + inputvalue + '"/>');
if (iMaxLenght != undefined && iMaxLenght != -1) {
input.attr('maxlength', iMaxLenght);
}
th.html(input);
if (bIsNumber)
th.wrapInner('<span class="filter_column filter_number" />');
else
th.wrapInner('<span class="filter_column filter_text" />');
asInitVals[i] = label;
var index = i;
if (bIsNumber && !oTable.fnSettings().oFeatures.bServerSide) {
input.keyup(function () {
/* Filter on the column all numbers that starts with the entered value */
oTable.fnFilter('^' + this.value, _fnColumnIndex(index), true, false); //Issue 37
fnOnFiltered();
});
} else {
input.keyup(function () {
if (oTable.fnSettings().oFeatures.bServerSide && iFilterLength != 0) {
//If filter length is set in the server-side processing mode
//Check has the user entered at least iFilterLength new characters
var currentFilter = oTable.fnSettings().aoPreSearchCols[index].sSearch;
var iLastFilterLength = $(this).data("dt-iLastFilterLength");
if (typeof iLastFilterLength == "undefined")
iLastFilterLength = 0;
var iCurrentFilterLength = this.value.length;
if (Math.abs(iCurrentFilterLength - iLastFilterLength) < iFilterLength
//&& currentFilter.length == 0 //Why this?
) {
//Cancel the filtering
return;
}
else {
//Remember the current filter length
$(this).data("dt-iLastFilterLength", iCurrentFilterLength);
}
}
/* Filter on the column (the index) of this element */
oTable.fnFilter(this.value, _fnColumnIndex(index), regex, smart); //Issue 37
fnOnFiltered();
});
}
input.focus(function () {
if ($(this).hasClass("search_init")) {
$(this).removeClass("search_init");
this.value = "";
}
});
input.blur(function () {
if (this.value == "") {
$(this).addClass("search_init");
this.value = asInitVals[index];
}
});
}
function fnCreateRangeInput(oTable) {
//var currentFilter = oTable.fnSettings().aoPreSearchCols[i].sSearch;
th.html(_fnRangeLabelPart(0));
var sFromId = oTable.attr("id") + '_range_from_' + i;
var from = $('<input type="text" class="number_range_filter" id="' + sFromId + '" rel="' + i + '"/>');
th.append(from);
th.append(_fnRangeLabelPart(1));
var sToId = oTable.attr("id") + '_range_to_' + i;
var to = $('<input type="text" class="number_range_filter" id="' + sToId + '" rel="' + i + '"/>');
th.append(to);
th.append(_fnRangeLabelPart(2));
th.wrapInner('<span class="filterColumn filter_number_range" />');
var index = i;
aiCustomSearch_Indexes.push(i);
//------------start range filtering function
/* Custom filtering function which will filter data in column four between two values
* Author: Allan Jardine, Modified by Jovan Popovic
*/
//$.fn.dataTableExt.afnFiltering.push(
oTable.dataTableExt.afnFiltering.push(
function (oSettings, aData, iDataIndex) {
if (oTable.attr("id") != oSettings.sTableId)
return true;
// Try to handle missing nodes more gracefully
if (document.getElementById(sFromId) == null)
return true;
var iMin = document.getElementById(sFromId).value * 1;
var iMax = document.getElementById(sToId).value * 1;
var iValue = aData[_fnColumnIndex(index)] == "-" ? 0 : aData[_fnColumnIndex(index)] * 1;
if (iMin == "" && iMax == "") {
return true;
}
else if (iMin == "" && iValue <= iMax) {
return true;
}
else if (iMin <= iValue && "" == iMax) {
return true;
}
else if (iMin <= iValue && iValue <= iMax) {
return true;
}
return false;
}
);
//------------end range filtering function
$('#' + sFromId + ',#' + sToId, th).keyup(function () {
var iMin = document.getElementById(sFromId).value * 1;
var iMax = document.getElementById(sToId).value * 1;
if (iMin != 0 && iMax != 0 && iMin > iMax)
return;
oTable.fnDraw();
fnOnFiltered();
});
}
function fnCreateDateRangeInput(oTable) {
th.html(_fnRangeLabelPart(0));
var sFromId = oTable.attr("id") + '_range_from_' + i;
var from = $('<input type="text" class="date_range_filter" id="' + sFromId + '" rel="' + i + '"/>');
from.datepicker();
th.append(from);
th.append(_fnRangeLabelPart(1));
var sToId = oTable.attr("id") + '_range_to_' + i;
var to = $('<input type="text" class="date_range_filter" id="' + sToId + '" rel="' + i + '"/>');
th.append(to);
th.append(_fnRangeLabelPart(2));
th.wrapInner('<span class="filterColumn filter_date_range" />');
to.datepicker();
var index = i;
aiCustomSearch_Indexes.push(i);
//------------start date range filtering function
//$.fn.dataTableExt.afnFiltering.push(
oTable.dataTableExt.afnFiltering.push(
function (oSettings, aData, iDataIndex) {
if (oTable.attr("id") != oSettings.sTableId)
return true;
var dStartDate = from.datepicker("getDate");
var dEndDate = to.datepicker("getDate");
if (dStartDate == null && dEndDate == null) {
return true;
}
var dCellDate = null;
try {
if (aData[_fnColumnIndex(index)] == null || aData[_fnColumnIndex(index)] == "")
return false;
dCellDate = $.datepicker.parseDate($.datepicker.regional[""].dateFormat, aData[_fnColumnIndex(index)]);
} catch (ex) {
return false;
}
if (dCellDate == null)
return false;
if (dStartDate == null && dCellDate <= dEndDate) {
return true;
}
else if (dStartDate <= dCellDate && dEndDate == null) {
return true;
}
else if (dStartDate <= dCellDate && dCellDate <= dEndDate) {
return true;
}
return false;
}
);
//------------end date range filtering function
$('#' + sFromId + ',#' + sToId, th).change(function () {
oTable.fnDraw();
fnOnFiltered();
});
}
function fnCreateColumnSelect(oTable, aData, iColumn, nTh, sLabel, bRegex) {
if (aData == null)
aData = _fnGetColumnValues(oTable.fnSettings(), iColumn, true, false, true);
var index = iColumn;
var currentFilter = oTable.fnSettings().aoPreSearchCols[i].sSearch;
var r = '<select class="search_init select_filter"><option value="" class="search_init">' + sLabel + '</option>';
var j = 0;
var iLen = aData.length;
for (j = 0; j < iLen; j++) {
if (typeof (aData[j]) != 'object') {
var selected = '';
if (escape(aData[j]) == currentFilter || escape(aData[j]) == escape(currentFilter)) selected = 'selected '
r += '<option ' + selected + ' value="' + escape(aData[j]) + '">' + aData[j] + '</option>';
}
else {
var selected = '';
if (bRegex) {
//Do not escape values if they are explicitely set to avoid escaping special characters in the regexp
if (aData[j].value == currentFilter) selected = 'selected ';
r += '<option ' + selected + 'value="' + aData[j].value + '">' + aData[j].label + '</option>';
} else {
if (escape(aData[j].value) == currentFilter) selected = 'selected ';
r += '<option ' + selected + 'value="' + escape(aData[j].value) + '">' + aData[j].label + '</option>';
}
}
}
var select = $(r + '</select>');
nTh.html(select);
nTh.wrapInner('<span class="filterColumn filter_select" />');
select.change(function () {
//var val = $(this).val();
if ($(this).val() != "") {
$(this).removeClass("search_init");
} else {
$(this).addClass("search_init");
}
if (bRegex)
oTable.fnFilter($(this).val(), iColumn, bRegex); //Issue 41
else
oTable.fnFilter(unescape($(this).val()), iColumn); //Issue 25
fnOnFiltered();
});
}
function fnCreateSelect(oTable, aData, bRegex) {
var oSettings = oTable.fnSettings();
if (aData == null && oSettings.sAjaxSource != "" && !oSettings.oFeatures.bServerSide) {
// Add a function to the draw callback, which will check for the Ajax data having
// been loaded. Use a closure for the individual column elements that are used to
// built the column filter, since 'i' and 'th' (etc) are locally "global".
oSettings.aoDrawCallback.push({
"fn": (function (iColumn, nTh, sLabel) {
return function () {
// Only rebuild the select on the second draw - i.e. when the Ajax
// data has been loaded.
if (oSettings.iDraw == 2 && oSettings.sAjaxSource != null && oSettings.sAjaxSource != "" && !oSettings.oFeatures.bServerSide) {
return fnCreateColumnSelect(oTable, null, _fnColumnIndex(iColumn), nTh, sLabel, bRegex); //Issue 37
}
};
})(i, th, label),
"sName": "column_filter_" + i
});
}
// Regardless of the Ajax state, build the select on first pass
fnCreateColumnSelect(oTable, aData, _fnColumnIndex(i), th, label, bRegex); //Issue 37
}
function fnCreateCheckbox(oTable, aData) {
if (aData == null)
aData = _fnGetColumnValues(oTable.fnSettings(), i, true, true, true);
var index = i;
var r = '', j, iLen = aData.length;
//clean the string
var localLabel = label.replace('%', 'Perc').replace("&", "AND").replace("$", "DOL").replace("£", "STERL").replace("@", "AT").replace(/\s/g, "_");
localLabel = localLabel.replace(/[^a-zA-Z 0-9]+/g, '');
//clean the string
//button label override
if (properties.sFilterButtonText != null || properties.sFilterButtonText != undefined) {
labelBtn = properties.sFilterButtonText;
} else {
labelBtn = label;
}
var relativeDivWidthToggleSize = 10;
var numRow = 12; //numero di checkbox per colonna
var numCol = Math.floor(iLen / numRow);
if (iLen % numRow > 0) {
numCol = numCol + 1;
};
//count how many column should be generated and split the div size
var divWidth = 100 / numCol - 2;
var divWidthToggle = relativeDivWidthToggleSize * numCol;
if (numCol == 1) {
divWidth = 20;
}
var divRowDef = '<div style="float:left; min-width: ' + divWidth + '%; " >';
var divClose = '</div>';
var uniqueId = oTable.attr("id") + localLabel;
var buttonId = "chkBtnOpen" + uniqueId;
var checkToggleDiv = uniqueId + "-flt-toggle";
r += '<button id="' + buttonId + '" class="checkbox_filter" > ' + labelBtn + '</button>'; //filter button witch open dialog
r += '<div id="' + checkToggleDiv + '" '
+ 'title="' + label + '" '
+ 'class="toggle-check ui-widget-content ui-corner-all" style="width: ' + (divWidthToggle) + '%; " >'; //dialog div
//r+= '<div align="center" style="margin-top: 5px; "> <button id="'+buttonId+'Reset" class="checkbox_filter" > reset </button> </div>'; //reset button and its div
r += divRowDef;
for (j = 0; j < iLen; j++) {
//if last check close div
if (j % numRow == 0 && j != 0) {
r += divClose + divRowDef;
}
//check button
r += '<input class="search_init checkbox_filter" type="checkbox" id= "' + aData[j] + '" name= "' + localLabel + '" value="' + aData[j] + '" >' + aData[j] + '<br/>';
var checkbox = $(r);
th.html(checkbox);
th.wrapInner('<span class="filterColumn filter_checkbox" />');
//on every checkbox selection
checkbox.change(function () {
var search = '';
var or = '|'; //var for select checks in 'or' into the regex
var resSize = $('input:checkbox[name="' + localLabel + '"]:checked').size();
$('input:checkbox[name="' + localLabel + '"]:checked').each(function (index) {
//search = search + ' ' + $(this).val();
//concatenation for selected checks in or
if ((index == 0 && resSize == 1)
|| (index != 0 && index == resSize - 1)) {
or = '';
}
//trim
search = search.replace(/^\s+|\s+$/g, "");
search = search + $(this).val() + or;
or = '|';
});
for (var jj = 0; jj < iLen; jj++) {
if (search != "") {
$('#' + aData[jj]).removeClass("search_init");
} else {
$('#' + aData[jj]).addClass("search_init");
}
}
//execute search
oTable.fnFilter(search, index, true, false);
fnOnFiltered();
});
}
//filter button
$('#' + buttonId).button();
//dialog
$('#' + checkToggleDiv).dialog({
//height: 140,
autoOpen: false,
//show: "blind",
hide: "blind",
buttons: [{
text: "Reset",
click: function () {
//$('#'+buttonId).removeClass("filter_selected"); //LM remove border if filter selected
$('input:checkbox[name="' + localLabel + '"]:checked').each(function (index3) {
$(this).attr('checked', false);
$(this).addClass("search_init");
});
oTable.fnFilter('', index, true, false);
fnOnFiltered();
return false;
}
},
{
text: "Close",
click: function () { $(this).dialog("close"); }
}
]
});
$('#' + buttonId).click(function () {
$('#' + checkToggleDiv).dialog('open');
var target = $(this);
$('#' + checkToggleDiv).dialog("widget").position({ my: 'top',
at: 'bottom',
of: target
});
return false;
});
var fnOnFilteredCurrent = fnOnFiltered;
fnOnFiltered = function () {
var target = $('#' + buttonId);
$('#' + checkToggleDiv).dialog("widget").position({ my: 'top',
at: 'bottom',
of: target
});
fnOnFilteredCurrent();
};
//reset
/*
$('#'+buttonId+"Reset").button();
$('#'+buttonId+"Reset").click(function(){
$('#'+buttonId).removeClass("filter_selected"); //LM remove border if filter selected
$('input:checkbox[name="'+localLabel+'"]:checked').each(function(index3) {
$(this).attr('checked', false);
$(this).addClass("search_init");
});
oTable.fnFilter('', index, true, false);
return false;
});
*/
}
function _fnRangeLabelPart(iPlace) {
switch (iPlace) {
case 0:
return sRangeFormat.substring(0, sRangeFormat.indexOf("{from}"));
case 1:
return sRangeFormat.substring(sRangeFormat.indexOf("{from}") + 6, sRangeFormat.indexOf("{to}"));
default:
return sRangeFormat.substring(sRangeFormat.indexOf("{to}") + 4);
}
}
oTable = this;
var defaults = {
sPlaceHolder: "foot",
sRangeSeparator: "~",
iFilteringDelay: 500,
aoColumns: null,
sRangeFormat: "From {from} to {to}"
};
properties = $.extend(defaults, options);
return this.each(function () {
if (!oTable.fnSettings().oFeatures.bFilter)
return;
asInitVals = new Array();
aoFilterCells = oTable.fnSettings().aoFooter[0];
var oHost = oTable.fnSettings().nTFoot; //Before fix for ColVis
var sFilterRow = "tr"; //Before fix for ColVis
if (properties.sPlaceHolder == "head:after") {
var tr = $("tr:first", oTable.fnSettings().nTHead).detach();
//tr.appendTo($(oTable.fnSettings().nTHead));
if (oTable.fnSettings().bSortCellsTop) {
tr.prependTo($(oTable.fnSettings().nTHead));
//tr.appendTo($("thead", oTable));
aoFilterCells = oTable.fnSettings().aoHeader[1];
}
else {
tr.appendTo($(oTable.fnSettings().nTHead));
//tr.prependTo($("thead", oTable));
aoFilterCells = oTable.fnSettings().aoHeader[0];
}
sFilterRow = "tr:last";
oHost = oTable.fnSettings().nTHead;
} else if (properties.sPlaceHolder == "head:before") {
if (oTable.fnSettings().bSortCellsTop) {
var tr = $("tr:first", oTable.fnSettings().nTHead).detach();
tr.appendTo($(oTable.fnSettings().nTHead));
aoFilterCells = oTable.fnSettings().aoHeader[1];
} else {
aoFilterCells = oTable.fnSettings().aoHeader[0];
}
/*else {
//tr.prependTo($("thead", oTable));
sFilterRow = "tr:first";
}*/
sFilterRow = "tr:first";
oHost = oTable.fnSettings().nTHead;
}
//$(sFilterRow + " th", oHost).each(function (index) {//bug with ColVis
$(aoFilterCells).each(function (index) {//fix for ColVis
i = index;
var aoColumn = { type: "text",
bRegex: false,
bSmart: true,
iMaxLenght: -1,
iFilterLength: 0
};
if (properties.aoColumns != null) {
if (properties.aoColumns.length < i || properties.aoColumns[i] == null)
return;
aoColumn = properties.aoColumns[i];
}
//label = $(this).text(); //Before fix for ColVis
label = $($(this)[0].cell).text(); //Fix for ColVis
if (aoColumn.sSelector == null) {
//th = $($(this)[0]);//Before fix for ColVis
th = $($(this)[0].cell); //Fix for ColVis
}
else {
th = $(aoColumn.sSelector);
if (th.length == 0)
th = $($(this)[0].cell);
}
if (aoColumn != null) {
if (aoColumn.sRangeFormat != null)
sRangeFormat = aoColumn.sRangeFormat;
else
sRangeFormat = properties.sRangeFormat;
switch (aoColumn.type) {
case "null":
break;
case "number":
fnCreateInput(oTable, true, false, true, aoColumn.iFilterLength, aoColumn.iMaxLenght);
break;
case "select":
if (aoColumn.bRegex != true)
aoColumn.bRegex = false;
fnCreateSelect(oTable, aoColumn.values, aoColumn.bRegex);
break;
case "number-range":
fnCreateRangeInput(oTable);
break;
case "date-range":
fnCreateDateRangeInput(oTable);
break;
case "checkbox":
fnCreateCheckbox(oTable, aoColumn.values);
break;
case "text":
default:
bRegex = (aoColumn.bRegex == null ? false : aoColumn.bRegex);
bSmart = (aoColumn.bSmart == null ? false : aoColumn.bSmart);
fnCreateInput(oTable, bRegex, bSmart, false, aoColumn.iFilterLength, aoColumn.iMaxLenght);
break;
}
}
});
for (j = 0; j < aiCustomSearch_Indexes.length; j++) {
//var index = aiCustomSearch_Indexes[j];
var fnSearch_ = function () {
var id = oTable.attr("id");
return $("#" + id + "_range_from_" + aiCustomSearch_Indexes[j]).val() + properties.sRangeSeparator + $("#" + id + "_range_to_" + aiCustomSearch_Indexes[j]).val()
}
afnSearch_.push(fnSearch_);
}
if (oTable.fnSettings().oFeatures.bServerSide) {
var fnServerDataOriginal = oTable.fnSettings().fnServerData;
oTable.fnSettings().fnServerData = function (sSource, aoData, fnCallback) {
for (j = 0; j < aiCustomSearch_Indexes.length; j++) {
var index = aiCustomSearch_Indexes[j];
for (k = 0; k < aoData.length; k++) {
if (aoData[k].name == "sSearch_" + index)
aoData[k].value = afnSearch_[j]();
}
}
aoData.push({ "name": "sRangeSeparator", "value": properties.sRangeSeparator });
if (fnServerDataOriginal != null) {
try {
fnServerDataOriginal(sSource, aoData, fnCallback, oTable.fnSettings()); //TODO: See Issue 18
} catch (ex) {
fnServerDataOriginal(sSource, aoData, fnCallback);
}
}
else {
$.getJSON(sSource, aoData, function (json) {
fnCallback(json)
});
}
};
}
});
};
})(jQuery);

View File

@ -0,0 +1,2 @@
DELETE FROM cc_pref WHERE keystr = 'system_version';
INSERT INTO cc_pref (keystr, valstr) VALUES ('system_version', '2.2.0');

View File

@ -57,4 +57,7 @@ class EventContractor(Loggable):
def __unregister(self, evt):
try: del self.store[evt.path]
except KeyError as e:
self.logger.info("Contractor failed to unrecord event: '%s'" \
% evt.path)
except Exception as e: self.unexpected_exception(e)

View File

@ -154,6 +154,11 @@ class Metadata(Loggable):
try : full_mutagen = mutagen.File(fpath, easy=True)
except Exception : raise BadSongFile(fpath)
self.path = fpath
if not os.path.exists(self.path):
self.logger.info("Attempting to read metadata of file \
that does not exist. Setting metadata to {}")
self.__metadata = {}
return
# TODO : Simplify the way all of these rules are handled right not it's
# extremely unclear and needs to be refactored.
self.__metadata = Metadata.airtime_dict(full_mutagen)