CC-84: Smart Playlists
- introducing smart-block
This commit is contained in:
parent
722e470f6f
commit
1f3cbd8aba
56 changed files with 12502 additions and 734 deletions
|
@ -45,48 +45,6 @@ class Application_Model_Playlist
|
|||
"dc:description" => "Description",
|
||||
"dcterms:extent" => "Length"
|
||||
);
|
||||
|
||||
private static $modifier2CriteriaMap = array(
|
||||
"contains" => Criteria::ILIKE,
|
||||
"does not contain" => Criteria::NOT_ILIKE,
|
||||
"is" => Criteria::EQUAL,
|
||||
"is not" => Criteria::NOT_EQUAL,
|
||||
"starts with" => Criteria::ILIKE,
|
||||
"ends with" => Criteria::ILIKE,
|
||||
"is greater than" => Criteria::GREATER_THAN,
|
||||
"is less than" => Criteria::LESS_THAN,
|
||||
"is in the range" => Criteria::CUSTOM);
|
||||
|
||||
private static $criteria2PeerMap = array(
|
||||
0 => "Select criteria",
|
||||
"album_title" => "DbAlbumTitle",
|
||||
"artist_name" => "DbArtistName",
|
||||
"bit_rate" => "DbBitRate",
|
||||
"bpm" => "DbBpm",
|
||||
"comments" => "DbComments",
|
||||
"composer" => "DbComposer",
|
||||
"conductor" => "DbConductor",
|
||||
"utime" => "DbUtime",
|
||||
"mtime" => "DbMtime",
|
||||
"lptime" => "DbLPtime",
|
||||
"disc_number" => "DbDiscNumber",
|
||||
"genre" => "DbGenre",
|
||||
"isrc_number" => "DbIsrcNumber",
|
||||
"label" => "DbLabel",
|
||||
"language" => "DbLanguage",
|
||||
"length" => "DbLength",
|
||||
"lyricist" => "DbLyricist",
|
||||
"mood" => "DbMood",
|
||||
"name" => "DbName",
|
||||
"orchestra" => "DbOrchestra",
|
||||
"radio_station_name" => "DbRadioStation",
|
||||
"rating" => "DbRating",
|
||||
"sample_rate" => "DbSampleRate",
|
||||
"track_title" => "DbTrackTitle",
|
||||
"track_num" => "DbTrackNum",
|
||||
"year" => "DbYear"
|
||||
);
|
||||
|
||||
|
||||
public function __construct($id=null, $con=null)
|
||||
{
|
||||
|
@ -214,9 +172,9 @@ class Application_Model_Playlist
|
|||
$files[$i] = $row->toArray(BasePeer::TYPE_FIELDNAME, true, true);
|
||||
|
||||
|
||||
$clipSec = Application_Model_Playlist::playlistTimeToSeconds($files[$i]['cliplength']);
|
||||
$clipSec = Application_Common_DateHelper::playlistTimeToSeconds($files[$i]['cliplength']);
|
||||
$offset += $clipSec;
|
||||
$offset_cliplength = Application_Model_Playlist::secondsToPlaylistTime($offset);
|
||||
$offset_cliplength = Application_Common_DateHelper::secondsToPlaylistTime($offset);
|
||||
|
||||
//format the length for UI.
|
||||
$formatter = new LengthFormatter($files[$i]['cliplength']);
|
||||
|
@ -297,14 +255,6 @@ class Application_Model_Playlist
|
|||
throw new Exception("trying to add a file that does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
public function isStatic(){
|
||||
if ($this->pl->getDbType() == "static") {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @param array $p_items
|
||||
|
@ -781,58 +731,6 @@ class Application_Model_Playlist
|
|||
$this->$method($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used for calculations! Don't modify for display purposes!
|
||||
*
|
||||
* Convert playlist time value to float seconds
|
||||
*
|
||||
* @param string $plt
|
||||
* playlist interval value (HH:mm:ss.dddddd)
|
||||
* @return int
|
||||
* seconds
|
||||
*/
|
||||
public static function playlistTimeToSeconds($plt)
|
||||
{
|
||||
$arr = preg_split('/:/', $plt);
|
||||
if (isset($arr[2])) {
|
||||
return (intval($arr[0])*60 + intval($arr[1]))*60 + floatval($arr[2]);
|
||||
}
|
||||
if (isset($arr[1])) {
|
||||
return intval($arr[0])*60 + floatval($arr[1]);
|
||||
}
|
||||
|
||||
return floatval($arr[0]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function is used for calculations! Don't modify for display purposes!
|
||||
*
|
||||
* Convert float seconds value to playlist time format
|
||||
*
|
||||
* @param float $seconds
|
||||
* @return string
|
||||
* interval in playlist time format (HH:mm:ss.d)
|
||||
*/
|
||||
public static function secondsToPlaylistTime($p_seconds)
|
||||
{
|
||||
$info = explode('.', $p_seconds);
|
||||
$seconds = $info[0];
|
||||
if (!isset($info[1])) {
|
||||
$milliStr = 0;
|
||||
} else {
|
||||
$milliStr = $info[1];
|
||||
}
|
||||
$hours = floor($seconds / 3600);
|
||||
$seconds -= $hours * 3600;
|
||||
$minutes = floor($seconds / 60);
|
||||
$seconds -= $minutes * 60;
|
||||
|
||||
$res = sprintf("%02d:%02d:%02d.%s", $hours, $minutes, $seconds, $milliStr);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public static function getPlaylistCount()
|
||||
{
|
||||
global $CC_CONFIG;
|
||||
|
@ -888,291 +786,6 @@ class Application_Model_Playlist
|
|||
{
|
||||
CcPlaylistcontentsQuery::create()->findByDbPlaylistId($this->id)->delete();
|
||||
}
|
||||
|
||||
|
||||
// smart playlist functions start
|
||||
public function shuffleSmartPlaylist(){
|
||||
// if it here that means it's static pl
|
||||
$this->saveType("static");
|
||||
$contents = CcPlaylistcontentsQuery::create()
|
||||
->filterByDbPlaylistId($this->id)
|
||||
->orderByDbPosition()
|
||||
->find();
|
||||
$shuffledPos = range(0, count($contents)-1);
|
||||
shuffle($shuffledPos);
|
||||
$temp = new CcPlaylist();
|
||||
foreach ($contents as $item) {
|
||||
$item->setDbPosition(array_shift($shuffledPos));
|
||||
$item->save();
|
||||
}
|
||||
return array("result"=>0);
|
||||
}
|
||||
|
||||
public function saveType($p_playlistType)
|
||||
{
|
||||
// saving dynamic/static flag
|
||||
CcPlaylistQuery::create()->findPk($this->id)->setDbType($p_playlistType)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves smart playlist criteria
|
||||
* @param array $p_criteria
|
||||
*/
|
||||
public function saveSmartPlaylistCriteria($p_criteria)
|
||||
{
|
||||
$data = $this->organizeSmartPlyalistCriteria($p_criteria);
|
||||
// things we need to check
|
||||
// 1. limit value shouldn't be empty and has upperbound of 24 hrs
|
||||
// 2. sp_criteria or sp_criteria_modifier shouldn't be 0
|
||||
// 3. validate formate according to DB column type
|
||||
$multiplier = 1;
|
||||
$result = 0;
|
||||
$errors = array();
|
||||
$error = array();
|
||||
|
||||
// saving dynamic/static flag
|
||||
$playlistType = $data['etc']['sp_type'] == 0 ? 'static':'dynamic';
|
||||
$this->saveType($playlistType);
|
||||
|
||||
// validation start
|
||||
if ($data['etc']['sp_limit_options'] == 'hours') {
|
||||
$multiplier = 60;
|
||||
}
|
||||
if ($data['etc']['sp_limit_options'] == 'hours' || $data['etc']['sp_limit_options'] == 'mins') {
|
||||
if ($data['etc']['sp_limit_value'] == "" || floatval($data['etc']['sp_limit_value']) <= 0) {
|
||||
$error[] = "Limit cannot be empty or smaller than 0";
|
||||
} else {
|
||||
$mins = $data['etc']['sp_limit_value'] * $multiplier;
|
||||
if ($mins > 14400) {
|
||||
$error[] = "Limit cannot be more than 24 hrs";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($data['etc']['sp_limit_value'] == "" || floatval($data['etc']['sp_limit_value']) <= 0) {
|
||||
$error[] = "Limit cannot be empty or smaller than 0";
|
||||
} else if (floatval($data['etc']['sp_limit_value']) < 1) {
|
||||
$error[] = "The value should be an integer";
|
||||
}
|
||||
}
|
||||
|
||||
if (count($error) > 0){
|
||||
$errors[] = array("element"=>"sp_limit_value", "msg"=>$error);
|
||||
}
|
||||
|
||||
foreach ($data['criteria'] as $key=>$d){
|
||||
$error = array();
|
||||
$column = CcFilesPeer::getTableMap()->getColumnByPhpName(self::$criteria2PeerMap[$d['sp_criteria_field']]);
|
||||
// check for not selected select box
|
||||
if ($d['sp_criteria_field'] == "0" || $d['sp_criteria_modifier'] == "0"){
|
||||
$error[] = "You must select Criteria and Modifier";
|
||||
} else {
|
||||
// validation on type of column
|
||||
if ($d['sp_criteria_field'] == 'length') {
|
||||
if (!preg_match("/(\d{2}):(\d{2}):(\d{2})/", $d['sp_criteria_value'])) {
|
||||
$error[] = "'Length' should be in '00:00:00' format";
|
||||
}
|
||||
} else if ($column->getType() == PropelColumnTypes::TIMESTAMP) {
|
||||
if (!preg_match("/(\d{4})-(\d{2})-(\d{2})/", $d['sp_criteria_value'])) {
|
||||
$error[] = "The value should be in timestamp format(eg. 0000-00-00 or 00-00-00 00:00:00";
|
||||
} else if (!Application_Common_DateHelper::checkDateTimeRangeForSQL($d['sp_criteria_value'])) {
|
||||
// check for if it is in valid range( 1753-01-01 ~ 12/31/9999 )
|
||||
$error[] = "$d[sp_criteria_value] is not a valid date/time string";
|
||||
}
|
||||
|
||||
if (isset($d['sp_criteria_extra'])) {
|
||||
if (!preg_match("/(\d{4})-(\d{2})-(\d{2})/", $d['sp_criteria_extra'])) {
|
||||
$error[] = "The value should be in timestamp format(eg. 0000-00-00 or 00-00-00 00:00:00";
|
||||
} else if (!Application_Common_DateHelper::checkDateTimeRangeForSQL($d['sp_criteria_extra'])) {
|
||||
// check for if it is in valid range( 1753-01-01 ~ 12/31/9999 )
|
||||
$error[] = "$d[sp_criteria_extra] is not a valid date/time string";
|
||||
}
|
||||
}
|
||||
} else if ($column->getType() == PropelColumnTypes::INTEGER) {
|
||||
if (!is_numeric($d['sp_criteria_value'])) {
|
||||
$error[] = "The value has to be numeric";
|
||||
}
|
||||
// length check
|
||||
if (intval($d['sp_criteria_value']) >= pow(2,31)) {
|
||||
$error[] = "The value should be less then 2147483648";
|
||||
}
|
||||
} else if ($column->getType() == PropelColumnTypes::VARCHAR) {
|
||||
if (strlen($d['sp_criteria_value']) > $column->getSize()) {
|
||||
$error[] = "The value should be less ".$column->getSize()." characters";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($d['sp_criteria_value'] == "") {
|
||||
$error[] = "Value cannot be empty";
|
||||
}
|
||||
if(count($error) > 0){
|
||||
$errors[] = array("element"=>"sp_criteria_field_".$key, "msg"=>$error);
|
||||
}
|
||||
}
|
||||
$result = count($errors) > 0 ? 1 :0;
|
||||
if ($result == 0) {
|
||||
$this->storeCriteriaIntoDb($data);
|
||||
}
|
||||
|
||||
//get number of files that meet the criteria
|
||||
$files = $this->getListofFilesMeetCriteria();
|
||||
|
||||
return array("result"=>$result, "errors"=>$errors, "poolCount"=>$files["count"]);
|
||||
}
|
||||
|
||||
public function storeCriteriaIntoDb($p_criteriaData){
|
||||
// delete criteria under $p_playlistId
|
||||
CcPlaylistcriteriaQuery::create()->findByDbPlaylistId($this->id)->delete();
|
||||
|
||||
foreach( $p_criteriaData['criteria'] as $d){
|
||||
$qry = new CcPlaylistcriteria();
|
||||
$qry->setDbCriteria($d['sp_criteria_field'])
|
||||
->setDbModifier($d['sp_criteria_modifier'])
|
||||
->setDbValue($d['sp_criteria_value'])
|
||||
->setDbPlaylistId($this->id);
|
||||
|
||||
if (isset($d['sp_criteria_extra'])) {
|
||||
$qry->setDbExtra($d['sp_criteria_extra']);
|
||||
}
|
||||
$qry->save();
|
||||
}
|
||||
|
||||
// insert limit info
|
||||
$qry = new CcPlaylistcriteria();
|
||||
$qry->setDbCriteria("limit")
|
||||
->setDbModifier($p_criteriaData['etc']['sp_limit_options'])
|
||||
->setDbValue($p_criteriaData['etc']['sp_limit_value'])
|
||||
->setDbPlaylistId($this->id)
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* generate list of tracks. This function saves creiteria and generate
|
||||
* tracks.
|
||||
* @param array $p_criteria
|
||||
*/
|
||||
public function generateSmartPlaylist($p_criteria, $returnList=false)
|
||||
{
|
||||
$result = $this->saveSmartPlaylistCriteria($p_criteria);
|
||||
if ($result['result'] != 0) {
|
||||
return $result;
|
||||
} else {
|
||||
$insertList = $this->getListOfFilesUnderLimit();
|
||||
$this->deleteAllFilesFromPlaylist();
|
||||
$this->addAudioClips(array_keys($insertList));
|
||||
return array("result"=>0);
|
||||
}
|
||||
}
|
||||
|
||||
public function getListOfFilesUnderLimit()
|
||||
{
|
||||
$info = $this->getListofFilesMeetCriteria();
|
||||
$files = $info['files'];
|
||||
$limit = $info['limit'];
|
||||
|
||||
$insertList = array();
|
||||
$totalTime = 0;
|
||||
|
||||
// this moves the pointer to the first element in the collection
|
||||
$files->getFirst();
|
||||
$iterator = $files->getIterator();
|
||||
while ($iterator->valid() && $totalTime < $limit['time']) {
|
||||
$id = $iterator->current()->getDbId();
|
||||
$length = Application_Common_DateHelper::calculateLengthInSeconds($iterator->current()->getDbLength());
|
||||
$insertList[$id] = $length;
|
||||
$totalTime += $length;
|
||||
if ( !is_null($limit['items']) && $limit['items'] == count($insertList)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$iterator->next();
|
||||
}
|
||||
return $insertList;
|
||||
}
|
||||
|
||||
// this function return list of propel object
|
||||
public function getListofFilesMeetCriteria()
|
||||
{
|
||||
$out = CcPlaylistcriteriaQuery::create()->findByDbPlaylistId($this->id);
|
||||
$storedCrit = array();
|
||||
foreach ($out as $crit) {
|
||||
$criteria = $crit->getDbCriteria();
|
||||
$modifier = $crit->getDbModifier();
|
||||
$value = $crit->getDbValue();
|
||||
$extra = $crit->getDbExtra();
|
||||
|
||||
if($criteria == "limit"){
|
||||
$storedCrit["limit"] = array("value"=>$value, "modifier"=>$modifier);
|
||||
}else{
|
||||
$storedCrit["crit"][] = array("criteria"=>$criteria, "value"=>$value, "modifier"=>$modifier, "extra"=>$extra);
|
||||
}
|
||||
}
|
||||
|
||||
$qry = CcFilesQuery::create();
|
||||
|
||||
if (isset($storedCrit["crit"])) {
|
||||
foreach ($storedCrit["crit"] as $criteria) {
|
||||
$spCriteriaPhpName = self::$criteria2PeerMap[$criteria['criteria']];
|
||||
$spCriteria = $criteria['criteria'];
|
||||
|
||||
$spCriteriaModifier = $criteria['modifier'];
|
||||
$spCriteriaValue = $criteria['value'];
|
||||
if ($spCriteriaModifier == "starts with") {
|
||||
$spCriteriaValue = "$spCriteriaValue%";
|
||||
} else if ($spCriteriaModifier == "ends with") {
|
||||
$spCriteriaValue = "%$spCriteriaValue";
|
||||
} else if ($spCriteriaModifier == "contains" || $spCriteriaModifier == "does not contain") {
|
||||
$spCriteriaValue = "%$spCriteriaValue%";
|
||||
} else if ($spCriteriaModifier == "is in the range") {
|
||||
$spCriteriaValue = "$spCriteria > '$spCriteriaValue' AND $spCriteria < '$criteria[extra]'";
|
||||
}
|
||||
$spCriteriaModifier = self::$modifier2CriteriaMap[$spCriteriaModifier];
|
||||
try{
|
||||
$qry->filterBy($spCriteriaPhpName, $spCriteriaValue, $spCriteriaModifier);
|
||||
$qry->addAscendingOrderByColumn('random()');
|
||||
}catch (Exception $e){
|
||||
Logging::log($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
// construct limit restriction
|
||||
$limits = array();
|
||||
if (isset($storedCrit['limit'])) {
|
||||
if ($storedCrit['limit']['modifier'] == "items") {
|
||||
$limits['time'] = 1440 * 60;
|
||||
$limits['items'] = $storedCrit['limit']['value'];
|
||||
} else {
|
||||
$limits['time'] = $storedCrit['limit']['modifier'] == "hours" ? intval($storedCrit['limit']['value']) * 60 * 60 : intval($storedCrit['limit']['value'] * 60);
|
||||
$limits['items'] = null;
|
||||
}
|
||||
}
|
||||
try{
|
||||
$out = $qry->setFormatter(ModelCriteria::FORMAT_ON_DEMAND)->find();
|
||||
return array("files"=>$out, "limit"=>$limits, "count"=>$out->count());
|
||||
}catch(Exception $e){
|
||||
Logging::log($e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static function organizeSmartPlyalistCriteria($p_criteria)
|
||||
{
|
||||
$fieldNames = array('sp_criteria_field', 'sp_criteria_modifier', 'sp_criteria_value', 'sp_criteria_extra');
|
||||
$output = array();
|
||||
foreach ($p_criteria as $ele) {
|
||||
$index = strrpos($ele['name'], '_');
|
||||
$fieldName = substr($ele['name'], 0, $index);
|
||||
if (in_array($fieldName, $fieldNames)) {
|
||||
$rowNum = intval(substr($ele['name'], $index+1));
|
||||
$output['criteria'][$rowNum][$fieldName] = trim($ele['value']);
|
||||
}else{
|
||||
$output['etc'][$ele['name']] = $ele['value'];
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
// smart playlist functions end
|
||||
|
||||
} // class Playlist
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue