sintonia/backend/Schedule.php
paul.baranowski 4a055dde50 Started integration of pypo with Campcaster. Refactored pypo so that
it can work with either OBP or Campcaster.  Added the liquidsoap
binary.  Started to add the PHP API scripts to send the correct data
to pypo (those these are not pretty - all one-off scripts for each
API command). Added Zend to the default path.
2010-11-08 16:54:54 -05:00

406 lines
No EOL
13 KiB
PHP

<?php
require_once("StoredFile.php");
require_once("BasicStor.php");
class ScheduleGroup {
private $groupId;
public function __construct($p_groupId = null) {
$this->groupId = $p_groupId;
}
/**
* Convert a date to an ID by stripping out all characters
* and padding with zeros.
*
* @param string $p_dateStr
*/
public static function dateToId($p_dateStr) {
$p_dateStr = str_replace(":", "", $p_dateStr);
$p_dateStr = str_replace(" ", "", $p_dateStr);
$p_dateStr = str_replace(".", "", $p_dateStr);
$p_dateStr = str_replace("-", "", $p_dateStr);
$p_dateStr = substr($p_dateStr, 0, 17);
$p_dateStr = str_pad($p_dateStr, 17, "0");
return $p_dateStr;
}
/**
* Add the two times together, return the result.
*
* @param string $p_baseTime
* Specified as YYYY-MM-DD HH:MM:SS
*
* @param string $p_addTime
* Specified as HH:MM:SS.nnnnnn
*
* @return string
* The end time, to the nearest second.
*/
// protected function calculateEndTime($p_startTime, $p_trackTime) {
// $p_trackTime = substr($p_startTime, 0, );
// $start = new DateTime();
// $interval = new DateInterval()
//
// }
/**
* Add a music clip or playlist to the schedule.
*
* @param $p_datetime
* In the format YYYY-MM-DD HH:MM:SS.mmmmmm
* @param $p_audioFileId
* (optional, either this or $p_playlistId must be set) DB ID of the audio file
* @param $p_playlistId
* (optional, either this of $p_audioFileId must be set) DB ID of the playlist
* @param $p_options
* Does nothing at the moment.
*
* @return int|PEAR_Error
* Return PEAR_Error if the item could not be added.
* Error code 555 is a scheduling conflict.
*/
public function add($p_datetime, $p_audioFileId = null, $p_playlistId = null, $p_options = null) {
global $CC_CONFIG, $CC_DBC;
if (!is_null($p_audioFileId)) {
// Schedule a single audio track
// Load existing track
$track = StoredFile::Recall($p_audioFileId);
if (is_null($track)) {
return new PEAR_Error("Could not find audio track.");
}
// Check if there are any conflicts with existing entries
$metadata = $track->getMetadata();
$length = trim($metadata["length"]);
if (empty($length)) {
return new PEAR_Error("Length is empty.");
}
if (!Schedule::isScheduleEmptyInRange($p_datetime, $length)) {
return new PEAR_Error("Schedule conflict.", 555);
}
// Insert into the table
$this->groupId = $CC_DBC->GetOne("SELECT nextval('schedule_group_id_seq')");
$id = $this->dateToId($p_datetime);
$sql = "INSERT INTO ".$CC_CONFIG["scheduleTable"]
." (id, playlist_id, starts, ends, clip_length, group_id, file_id)"
." VALUES ($id, 0, TIMESTAMP '$p_datetime', "
." (TIMESTAMP '$p_datetime' + INTERVAL '$length'),"
." '$length',"
." {$this->groupId}, $p_audioFileId)";
$result = $CC_DBC->query($sql);
if (PEAR::isError($result)) {
var_dump($sql);
return $result;
}
return $this->groupId;
} elseif (!is_null($p_playlistId)){
// Schedule a whole playlist
// Load existing playlist
$playlist = Playlist::Recall($p_playlistId);
if (is_null($playlist)) {
return new PEAR_Error("Could not find playlist.");
}
// Check if there are any conflicts with existing entries
$length = trim($playlist->getLength());
if (empty($length)) {
return new PEAR_Error("Length is empty.");
}
if (!Schedule::isScheduleEmptyInRange($p_datetime, $length)) {
return new PEAR_Error("Schedule conflict.", 555);
}
// Insert all items into the schedule
$this->groupId = $CC_DBC->GetOne("SELECT nextval('schedule_group_id_seq')");
$id = $this->dateToId($p_datetime);
$itemStartTime = $p_datetime;
$plItems = $playlist->getContents();
foreach ($plItems as $row) {
$trackLength = $row["cliplength"];
$sql = "INSERT INTO ".$CC_CONFIG["scheduleTable"]
." (id, playlist_id, starts, ends, group_id, file_id,"
." clip_length, cue_in, cue_out, fade_in, fade_out)"
." VALUES ($id, $p_playlistId, TIMESTAMP '$itemStartTime', "
." (TIMESTAMP '$itemStartTime' + INTERVAL '$trackLength'),"
." '{$this->groupId}', '{$row['file_id']}', '$trackLength', '{$row['cuein']}',"
." '{$row['cueout']}', '{$row['fadein']}','{$row['fadeout']}')";
$result = $CC_DBC->query($sql);
if (PEAR::isError($result)) {
var_dump($sql);
return $result;
}
$itemStartTime = $CC_DBC->getOne("SELECT TIMESTAMP '$itemStartTime' + INTERVAL '$trackLength'");
$id = $this->dateToId($itemStartTime);
}
return $this->groupId;
}
}
public function addAfter($p_groupId, $p_audioFileId) {
global $CC_CONFIG, $CC_DBC;
// Get the end time for the given entry
$sql = "SELECT ends FROM ".$CC_CONFIG["scheduleTable"]
." WHERE group_id=$p_groupId";
$startTime = $CC_DBC->GetOne($sql);
return $this->add($startTime, $p_audioFileId);
}
public function update() {
}
/**
* Remove the group from the schedule.
* Note: does not check if it is in the past, you can remove anything.
*
* @return boolean
* TRUE on success, false if there is no group ID defined.
*/
public function remove() {
global $CC_CONFIG, $CC_DBC;
if (is_null($this->groupId) || !is_numeric($this->groupId)) {
return false;
}
$sql = "DELETE FROM ".$CC_CONFIG["scheduleTable"]
." WHERE group_id = ".$this->groupId;
return $CC_DBC->query($sql);
}
/**
* Return the number of items in this group.
* @return string
*/
public function count() {
global $CC_CONFIG, $CC_DBC;
$sql = "SELECT COUNT(*) FROM {$CC_CONFIG['scheduleTable']}"
." WHERE group_id={$this->groupId}";
return $CC_DBC->GetOne($sql);
}
/*
* Return the list of items in this group as a 2D array.
* @return array
*/
public function getItems() {
global $CC_CONFIG, $CC_DBC;
$sql = "SELECT * FROM {$CC_CONFIG['scheduleTable']}"
." WHERE group_id={$this->groupId}";
return $CC_DBC->GetAll($sql);
}
public function reschedule($toDateTime) {
global $CC_CONFIG, $CC_DBC;
// $sql = "UPDATE ".$CC_CONFIG["scheduleTable"]. " SET id=, starts=,ends="
}
}
class Schedule {
function __construct() {
}
/**
* Return true if there is nothing in the schedule for the given times.
*
* @param string $p_datetime
* @param string $p_length
*
* @return boolean|PEAR_Error
*/
public static function isScheduleEmptyInRange($p_datetime, $p_length) {
global $CC_CONFIG, $CC_DBC;
if (empty($p_length)) {
return new PEAR_Error("Schedule::isSchedulerEmptyInRange: param p_length is empty.");
}
$sql = "SELECT COUNT(*) FROM ".$CC_CONFIG["scheduleTable"]
." WHERE (starts >= '$p_datetime') "
." AND (ends <= (TIMESTAMP '$p_datetime' + INTERVAL '$p_length'))";
//$_SESSION["debug"] = $sql;
$count = $CC_DBC->GetOne($sql);
return ($count == '0');
}
public function onAddTrackToPlaylist($playlistId, $audioTrackId) {
}
public function onRemoveTrackFromPlaylist($playlistId, $audioTrackId) {
}
/**
* Returns array indexed numberically of:
* "playlistId"/"playlist_id" (aliases to the same thing)
* "start"/"starts" (aliases to the same thing) as YYYY-MM-DD HH:MM:SS.nnnnnn
* "end"/"ends" (aliases to the same thing) as YYYY-MM-DD HH:MM:SS.nnnnnn
* "group_id"/"id" (aliases to the same thing)
* "clip_length" (for playlists only, this is the length of the entire playlist)
* "name" (playlist only)
* "creator" (playlist only)
* "file_id" (audioclip only)
* "count" (number of items in the playlist, always 1 for audioclips.
* Note that playlists with one item will also have count = 1.
*
* @param string $p_fromDateTime
* In the format YYYY-MM-DD HH:MM:SS.nnnnnn
* @param string $p_toDateTime
* In the format YYYY-MM-DD HH:MM:SS.nnnnnn
* @param boolean $p_playlistsOnly
* Retreive playlists as a single item.
* @return array
* Returns empty array if nothing found
*/
public static function GetItems($p_fromDateTime, $p_toDateTime, $p_playlistsOnly = true) {
global $CC_CONFIG, $CC_DBC;
$rows = array();
if (!$p_playlistsOnly) {
$sql = "SELECT * FROM ".$CC_CONFIG["scheduleTable"]
." WHERE (starts >= TIMESTAMP '$p_fromDateTime') "
." AND (ends <= TIMESTAMP '$p_toDateTime')";
$rows = $CC_DBC->GetAll($sql);
foreach ($rows as &$row) {
$row["count"] = "1";
$row["playlistId"] = $row["playlist_id"];
$row["start"] = $row["starts"];
$row["end"] = $row["ends"];
$row["id"] = $row["group_id"];
}
} else {
$sql = "SELECT MIN(name) AS name, MIN(creator) AS creator, group_id, "
." SUM(clip_length) AS clip_length,"
." MIN(file_id) AS file_id, COUNT(*) as count,"
." MIN(playlist_id) AS playlist_id, MIN(starts) AS starts, MAX(ends) AS ends"
." FROM ".$CC_CONFIG["scheduleTable"]
." LEFT JOIN ".$CC_CONFIG["playListTable"]." ON playlist_id = ".$CC_CONFIG["playListTable"].".id"
." WHERE (starts >= TIMESTAMP '$p_fromDateTime') AND (ends <= TIMESTAMP '$p_toDateTime')"
." GROUP BY group_id"
." ORDER BY starts";
//var_dump($sql);
$rows = $CC_DBC->GetAll($sql);
if (!PEAR::isError($rows)) {
foreach ($rows as &$row) {
$row["playlistId"] = $row["playlist_id"];
$row["start"] = $row["starts"];
$row["end"] = $row["ends"];
$row["id"] = $row["group_id"];
}
}
}
return $rows;
}
public function getSchedulerTime() {
}
public function getCurrentlyPlaying() {
}
public function getNextItem($nextCount = 1) {
}
public function getStatus() {
}
private static function CcTimeToPypoTime($p_time) {
$p_time = substr($p_time, 0, 19);
$p_time = str_replace(" ", "-", $p_time);
$p_time = str_replace(":", "-", $p_time);
return $p_time;
}
private static function PypoTimeToCcTime($p_time) {
$t = explode("-", $p_time);
return $t[0]."-".$t[1]."-".$t[2]." ".$t[3].":".$t[4].":00";
}
/**
* Export the schedule in json formatted for pypo (the liquidsoap scheduler)
*
* @param string $range
* In the format "YYYY-MM-DD HH:mm:ss"
* @param string $source
* In the format "YYYY-MM-DD HH:mm:ss"
*/
public static function ExportRangeAsJson($p_fromDateTime, $p_toDateTime)
{
global $CC_CONFIG, $CC_DBC;
$range_start = Schedule::PypoTimeToCcTime($p_fromDateTime);
$range_end = Schedule::PypoTimeToCcTime($p_toDateTime);
$range_dt = array('start' => $range_start, 'end' => $range_end);
//var_dump($range_dt);
// Scheduler wants everything in a playlist
$data = Schedule::GetItems($range_start, $range_end, true);
//echo "<pre>";var_dump($data);
$playlists = array();
if (is_array($data) && count($data) > 0)
{
foreach ($data as $dx)
{
// Is this the first item in the playlist?
$start = $dx['start'];
// chop off subseconds
$start = substr($start, 0, 19);
// Start time is the array key, needs to be in the format "YYYY-MM-DD-HH-mm-ss"
$pkey = Schedule::CcTimeToPypoTime($start);
$timestamp = strtotime($start);
$playlists[$pkey]['source'] = "PLAYLIST";
$playlists[$pkey]['x_ident'] = $dx["playlist_id"];
$playlists[$pkey]['subtype'] = '1'; // Just needs to be between 1 and 4 inclusive
$playlists[$pkey]['timestamp'] = $timestamp;
$playlists[$pkey]['duration'] = $dx['clip_length'];
$playlists[$pkey]['played'] = '0';
$playlists[$pkey]['schedule_id'] = $dx['group_id'];
}
}
foreach ($playlists as &$playlist)
{
$scheduleGroup = new ScheduleGroup($playlist["schedule_id"]);
$items = $scheduleGroup->getItems();
$medias = array();
$playlist['subtype'] = '1';
foreach ($items as $item)
{
$storedFile = StoredFile::Recall($item["file_id"]);
$uri = $storedFile->getFileUrl();
$medias[] = array(
'id' => $item["file_id"],
'uri' => $uri,
'fade_in' => $item["fade_in"],
'fade_out' => $item["fade_out"],
'fade_cross' => 0,
'cue_in' => $item["cue_in"],
'cue_out' => $item["cue_out"],
);
}
$playlist['medias'] = $medias;
}
$result = array();
$result['status'] = array('range' => $range_dt, 'version' => 0.2);
$result['playlists'] = $playlists;
$result['check'] = 1;
print json_encode($result);
}
}
?>