Scheduler.php 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257
  1. <?php
  2. class Application_Model_Scheduler
  3. {
  4. private $con;
  5. private $fileInfo = array(
  6. "id" => "",
  7. "cliplength" => "",
  8. "cuein" => "00:00:00",
  9. "cueout" => "00:00:00",
  10. "fadein" => "00:00:00",
  11. "fadeout" => "00:00:00",
  12. "sched_id" => null,
  13. "type" => 0 //default type of '0' to represent files. type '1' represents a webstream
  14. );
  15. private $epochNow;
  16. private $nowDT;
  17. private $user;
  18. private $crossfadeDuration;
  19. private $applyCrossfades = true;
  20. private $checkUserPermissions = true;
  21. public function __construct()
  22. {
  23. $this->con = Propel::getConnection(CcSchedulePeer::DATABASE_NAME);
  24. //subtracting one because sometimes when we cancel a track, we set its end time
  25. //to epochNow and then send the new schedule to pypo. Sometimes the currently cancelled
  26. //track can still be included in the new schedule because it may have a few ms left to play.
  27. //subtracting 1 second from epochNow resolves this issue.
  28. $this->epochNow = microtime(true)-1;
  29. $this->nowDT = DateTime::createFromFormat("U.u", $this->epochNow, new DateTimeZone("UTC"));
  30. if ($this->nowDT === false) {
  31. // DateTime::createFromFormat does not support millisecond string formatting in PHP 5.3.2 (Ubuntu 10.04).
  32. // In PHP 5.3.3 (Ubuntu 10.10), this has been fixed.
  33. $this->nowDT = DateTime::createFromFormat("U", time(), new DateTimeZone("UTC"));
  34. }
  35. $this->user = Application_Model_User::getCurrentUser();
  36. $this->crossfadeDuration = Application_Model_Preference::GetDefaultCrossfadeDuration();
  37. }
  38. public function setCheckUserPermissions($value)
  39. {
  40. $this->checkUserPermissions = $value;
  41. }
  42. private function validateItemMove($itemsToMove, $destination)
  43. {
  44. $destinationInstanceId = $destination["instance"];
  45. $destinationCcShowInstance = CcShowInstancesQuery::create()
  46. ->findPk($destinationInstanceId);
  47. $isDestinationLinked = $destinationCcShowInstance->getCcShow()->isLinked();
  48. foreach ($itemsToMove as $itemToMove) {
  49. $sourceInstanceId = $itemToMove["instance"];
  50. $ccShowInstance = CcShowInstancesQuery::create()
  51. ->findPk($sourceInstanceId);
  52. //does the item being moved belong to a linked show
  53. $isSourceLinked = $ccShowInstance->getCcShow()->isLinked();
  54. if ($isDestinationLinked && !$isSourceLinked) {
  55. throw new Exception("Cannot move items into linked shows");
  56. } elseif (!$isDestinationLinked && $isSourceLinked) {
  57. throw new Exception("Cannot move items out of linked shows");
  58. } elseif ($isSourceLinked && $sourceInstanceId != $destinationInstanceId) {
  59. throw new Exception(_("Cannot move items out of linked shows"));
  60. }
  61. }
  62. }
  63. /*
  64. * make sure any incoming requests for scheduling are ligit.
  65. *
  66. * @param array $items, an array containing pks of cc_schedule items.
  67. */
  68. private function validateRequest($items, $addAction=false)
  69. {
  70. //$items is where tracks get inserted (they are schedule locations)
  71. $nowEpoch = floatval($this->nowDT->format("U.u"));
  72. $schedInfo = array();
  73. $instanceInfo = array();
  74. for ($i = 0; $i < count($items); $i++) {
  75. $id = $items[$i]["id"];
  76. //could be added to the beginning of a show, which sends id = 0;
  77. if ($id > 0) {
  78. //schedule_id of where we are inserting after?
  79. $schedInfo[$id] = $items[$i]["instance"];
  80. }
  81. //format is instance_id => timestamp
  82. $instanceInfo[$items[$i]["instance"]] = $items[$i]["timestamp"];
  83. }
  84. if (count($instanceInfo) === 0) {
  85. throw new Exception("Invalid Request.");
  86. }
  87. $schedIds = array();
  88. if (count($schedInfo) > 0) {
  89. $schedIds = array_keys($schedInfo);
  90. }
  91. $schedItems = CcScheduleQuery::create()->findPKs($schedIds, $this->con);
  92. $instanceIds = array_keys($instanceInfo);
  93. $showInstances = CcShowInstancesQuery::create()->findPKs($instanceIds, $this->con);
  94. //an item has been deleted
  95. if (count($schedIds) !== count($schedItems)) {
  96. throw new OutDatedScheduleException(_("The schedule you're viewing is out of date! (sched mismatch)"));
  97. }
  98. //a show has been deleted
  99. if (count($instanceIds) !== count($showInstances)) {
  100. throw new OutDatedScheduleException(_("The schedule you're viewing is out of date! (instance mismatch)"));
  101. }
  102. foreach ($schedItems as $schedItem) {
  103. $id = $schedItem->getDbId();
  104. $instance = $schedItem->getCcShowInstances($this->con);
  105. if (intval($schedInfo[$id]) !== $instance->getDbId()) {
  106. throw new OutDatedScheduleException(_("The schedule you're viewing is out of date!"));
  107. }
  108. }
  109. foreach ($showInstances as $instance) {
  110. $id = $instance->getDbId();
  111. $show = $instance->getCcShow($this->con);
  112. if ($this->checkUserPermissions && $this->user->canSchedule($show->getDbId()) === false) {
  113. throw new Exception(sprintf(_("You are not allowed to schedule show %s."), $show->getDbName()));
  114. }
  115. if ($instance->getDbRecord()) {
  116. throw new Exception(_("You cannot add files to recording shows."));
  117. }
  118. $showEndEpoch = floatval($instance->getDbEnds("U.u"));
  119. if ($showEndEpoch < $nowEpoch) {
  120. throw new OutDatedScheduleException(sprintf(_("The show %s is over and cannot be scheduled."), $show->getDbName()));
  121. }
  122. $ts = intval($instanceInfo[$id]);
  123. $lastSchedTs = intval($instance->getDbLastScheduled("U")) ? : 0;
  124. if ($ts < $lastSchedTs) {
  125. Logging::info("ts {$ts} last sched {$lastSchedTs}");
  126. throw new OutDatedScheduleException(sprintf(_("The show %s has been previously updated!"), $show->getDbName()));
  127. }
  128. /*
  129. * Does the afterItem belong to a show that is linked AND
  130. * currently playing?
  131. * If yes, throw an exception
  132. */
  133. if ($addAction) {
  134. $ccShow = $instance->getCcShow();
  135. if ($ccShow->isLinked()) {
  136. //get all the linked shows instances and check if
  137. //any of them are currently playing
  138. $ccShowInstances = $ccShow->getCcShowInstancess();
  139. $timeNowUTC = gmdate("Y-m-d H:i:s");
  140. foreach ($ccShowInstances as $ccShowInstance) {
  141. if ($ccShowInstance->getDbStarts() <= $timeNowUTC &&
  142. $ccShowInstance->getDbEnds() > $timeNowUTC) {
  143. throw new Exception(_("Content in linked shows must be scheduled before or after any one is broadcasted"));
  144. }
  145. }
  146. }
  147. }
  148. }
  149. }
  150. private function validateMediaItems($mediaItems)
  151. {
  152. foreach ($mediaItems as $mediaItem)
  153. {
  154. $id = $mediaItem["id"];
  155. if ($mediaItem["type"] === "playlist")
  156. {
  157. $playlist = new Application_Model_Playlist($id, $this->con);
  158. if ($playlist->containsMissingFiles()) {
  159. throw new Exception(_("Cannot schedule a playlist that contains missing files."));
  160. }
  161. }
  162. }
  163. return true;
  164. }
  165. /*
  166. * @param $id
  167. * @param $type
  168. *
  169. * @return $files
  170. */
  171. private function retrieveMediaFiles($id, $type)
  172. {
  173. $files = array();
  174. if ($type === "audioclip") {
  175. $file = CcFilesQuery::create()->findPK($id, $this->con);
  176. if (is_null($file) || !$file->visible()) {
  177. throw new Exception(_("A selected File does not exist!"));
  178. } else {
  179. $data = $this->fileInfo;
  180. $data["id"] = $id;
  181. $cuein = Application_Common_DateHelper::playlistTimeToSeconds($file->getDbCuein());
  182. $cueout = Application_Common_DateHelper::playlistTimeToSeconds($file->getDbCueout());
  183. $row_length = Application_Common_DateHelper::secondsToPlaylistTime($cueout - $cuein);
  184. $data["cliplength"] = $row_length;
  185. $data["cuein"] = $file->getDbCuein();
  186. $data["cueout"] = $file->getDbCueout();
  187. //fade is in format SS.uuuuuu
  188. $data["fadein"] = Application_Model_Preference::GetDefaultFadeIn();
  189. $data["fadeout"] = Application_Model_Preference::GetDefaultFadeOut();
  190. $files[] = $data;
  191. }
  192. } elseif ($type === "playlist") {
  193. $pl = new Application_Model_Playlist($id);
  194. $contents = $pl->getContents();
  195. foreach ($contents as $plItem) {
  196. if ($plItem['type'] == 0) {
  197. $data["id"] = $plItem['item_id'];
  198. $data["cliplength"] = $plItem['length'];
  199. $data["cuein"] = $plItem['cuein'];
  200. $data["cueout"] = $plItem['cueout'];
  201. $data["fadein"] = $plItem['fadein'];
  202. $data["fadeout"] = $plItem['fadeout'];
  203. $data["type"] = 0;
  204. $files[] = $data;
  205. } elseif ($plItem['type'] == 1) {
  206. $data["id"] = $plItem['item_id'];
  207. $data["cliplength"] = $plItem['length'];
  208. $data["cuein"] = $plItem['cuein'];
  209. $data["cueout"] = $plItem['cueout'];
  210. $data["fadein"] = "00.500000";//$plItem['fadein'];
  211. $data["fadeout"] = "00.500000";//$plItem['fadeout'];
  212. $data["type"] = 1;
  213. $files[] = $data;
  214. } elseif ($plItem['type'] == 2) {
  215. // if it's a block
  216. $bl = new Application_Model_Block($plItem['item_id']);
  217. if ($bl->isStatic()) {
  218. foreach ($bl->getContents() as $track) {
  219. $data["id"] = $track['item_id'];
  220. $data["cliplength"] = $track['length'];
  221. $data["cuein"] = $track['cuein'];
  222. $data["cueout"] = $track['cueout'];
  223. $data["fadein"] = $track['fadein'];
  224. $data["fadeout"] = $track['fadeout'];
  225. $data["type"] = 0;
  226. $files[] = $data;
  227. }
  228. } else {
  229. $defaultFadeIn = Application_Model_Preference::GetDefaultFadeIn();
  230. $defaultFadeOut = Application_Model_Preference::GetDefaultFadeOut();
  231. $dynamicFiles = $bl->getListOfFilesUnderLimit();
  232. foreach ($dynamicFiles as $f) {
  233. $fileId = $f['id'];
  234. $file = CcFilesQuery::create()->findPk($fileId);
  235. if (isset($file) && $file->visible()) {
  236. $data["id"] = $file->getDbId();
  237. $data["cuein"] = $file->getDbCuein();
  238. $data["cueout"] = $file->getDbCueout();
  239. $cuein = Application_Common_DateHelper::calculateLengthInSeconds($data["cuein"]);
  240. $cueout = Application_Common_DateHelper::calculateLengthInSeconds($data["cueout"]);
  241. $data["cliplength"] = Application_Common_DateHelper::secondsToPlaylistTime($cueout - $cuein);
  242. //fade is in format SS.uuuuuu
  243. $data["fadein"] = $defaultFadeIn;
  244. $data["fadeout"] = $defaultFadeOut;
  245. $data["type"] = 0;
  246. $files[] = $data;
  247. }
  248. }
  249. }
  250. }
  251. }
  252. } elseif ($type == "stream") {
  253. //need to return
  254. $stream = CcWebstreamQuery::create()->findPK($id, $this->con);
  255. if (is_null($stream) /* || !$file->visible() */) {
  256. throw new Exception(_("A selected File does not exist!"));
  257. } else {
  258. $data = $this->fileInfo;
  259. $data["id"] = $id;
  260. $data["cliplength"] = $stream->getDbLength();
  261. $data["cueout"] = $stream->getDbLength();
  262. $data["type"] = 1;
  263. //fade is in format SS.uuuuuu
  264. $data["fadein"] = Application_Model_Preference::GetDefaultFadeIn();
  265. $data["fadeout"] = Application_Model_Preference::GetDefaultFadeOut();
  266. $files[] = $data;
  267. }
  268. } elseif ($type == "block") {
  269. $bl = new Application_Model_Block($id);
  270. if ($bl->isStatic()) {
  271. foreach ($bl->getContents() as $track) {
  272. $data["id"] = $track['item_id'];
  273. $data["cliplength"] = $track['length'];
  274. $data["cuein"] = $track['cuein'];
  275. $data["cueout"] = $track['cueout'];
  276. $data["fadein"] = $track['fadein'];
  277. $data["fadeout"] = $track['fadeout'];
  278. $data["type"] = 0;
  279. $files[] = $data;
  280. }
  281. } else {
  282. $defaultFadeIn = Application_Model_Preference::GetDefaultFadeIn();
  283. $defaultFadeOut = Application_Model_Preference::GetDefaultFadeOut();
  284. $dynamicFiles = $bl->getListOfFilesUnderLimit();
  285. foreach ($dynamicFiles as $f) {
  286. $fileId = $f['id'];
  287. $file = CcFilesQuery::create()->findPk($fileId);
  288. if (isset($file) && $file->visible()) {
  289. $data["id"] = $file->getDbId();
  290. $data["cuein"] = $file->getDbCuein();
  291. $data["cueout"] = $file->getDbCueout();
  292. $cuein = Application_Common_DateHelper::calculateLengthInSeconds($data["cuein"]);
  293. $cueout = Application_Common_DateHelper::calculateLengthInSeconds($data["cueout"]);
  294. $data["cliplength"] = Application_Common_DateHelper::secondsToPlaylistTime($cueout - $cuein);
  295. //fade is in format SS.uuuuuu
  296. $data["fadein"] = $defaultFadeIn;
  297. $data["fadeout"] = $defaultFadeOut;
  298. $data["type"] = 0;
  299. $files[] = $data;
  300. }
  301. }
  302. }
  303. }
  304. return $files;
  305. }
  306. /*
  307. * @param DateTime startDT in UTC
  308. * @param string duration
  309. * in format H:i:s.u (could be more that 24 hours)
  310. *
  311. * @return DateTime endDT in UTC
  312. */
  313. private function findTimeDifference($p_startDT, $p_seconds)
  314. {
  315. $startEpoch = $p_startDT->format("U.u");
  316. //add two float numbers to 6 subsecond precision
  317. //DateTime::createFromFormat("U.u") will have a problem if there is no decimal in the resulting number.
  318. $newEpoch = bcsub($startEpoch , (string) $p_seconds, 6);
  319. $dt = DateTime::createFromFormat("U.u", $newEpoch, new DateTimeZone("UTC"));
  320. if ($dt === false) {
  321. //PHP 5.3.2 problem
  322. $dt = DateTime::createFromFormat("U", intval($newEpoch), new DateTimeZone("UTC"));
  323. }
  324. return $dt;
  325. }
  326. /*
  327. * @param DateTime startDT in UTC
  328. * @param string duration
  329. * in format H:i:s.u (could be more that 24 hours)
  330. *
  331. * @return DateTime endDT in UTC
  332. */
  333. private function findEndTime($p_startDT, $p_duration)
  334. {
  335. $startEpoch = $p_startDT->format("U.u");
  336. $durationSeconds = Application_Common_DateHelper::playlistTimeToSeconds($p_duration);
  337. //add two float numbers to 6 subsecond precision
  338. //DateTime::createFromFormat("U.u") will have a problem if there is no decimal in the resulting number.
  339. $endEpoch = bcadd($startEpoch , (string) $durationSeconds, 6);
  340. $dt = DateTime::createFromFormat("U.u", $endEpoch, new DateTimeZone("UTC"));
  341. if ($dt === false) {
  342. //PHP 5.3.2 problem
  343. $dt = DateTime::createFromFormat("U", intval($endEpoch), new DateTimeZone("UTC"));
  344. }
  345. return $dt;
  346. }
  347. private function findNextStartTime($DT, $instanceId)
  348. {
  349. $sEpoch = $DT->format("U.u");
  350. $nEpoch = $this->epochNow;
  351. //check for if the show has started.
  352. if (bccomp( $nEpoch , $sEpoch , 6) === 1) {
  353. $this->applyCrossfades = false;
  354. //need some kind of placeholder for cc_schedule.
  355. //playout_status will be -1.
  356. $nextDT = $this->nowDT;
  357. $length = bcsub($nEpoch , $sEpoch , 6);
  358. $cliplength = Application_Common_DateHelper::secondsToPlaylistTime($length);
  359. //fillers are for only storing a chunk of time space that has already passed.
  360. $filler = new CcSchedule();
  361. $filler->setDbStarts($DT)
  362. ->setDbEnds($this->nowDT)
  363. ->setDbClipLength($cliplength)
  364. ->setDbCueIn('00:00:00')
  365. ->setDbCueOut('00:00:00')
  366. ->setDbPlayoutStatus(-1)
  367. ->setDbInstanceId($instanceId)
  368. ->save($this->con);
  369. } else {
  370. $nextDT = $DT;
  371. }
  372. return $nextDT;
  373. }
  374. /*
  375. * @param int $showInstance
  376. * This function recalculates the start/end times of items in a gapless show to
  377. * account for crossfade durations.
  378. */
  379. private function calculateCrossfades($instanceId)
  380. {
  381. Logging::info("adjusting start, end times of scheduled items to account for crossfades show instance #".$instanceId);
  382. $sql = "SELECT * FROM cc_show_instances ".
  383. "WHERE id = {$instanceId}";
  384. $instance = Application_Common_Database::prepareAndExecute(
  385. $sql, array(), Application_Common_Database::SINGLE);
  386. if (is_null($instance)) {
  387. throw new OutDatedScheduleException(_("The schedule you're viewing is out of date!"));
  388. }
  389. $itemStartDT = new DateTime($instance["starts"], new DateTimeZone("UTC"));
  390. $itemEndDT = null;
  391. $schedule_sql = "SELECT * FROM cc_schedule ".
  392. "WHERE instance_id = {$instanceId} ".
  393. "ORDER BY starts";
  394. $schedule = Application_Common_Database::prepareAndExecute($schedule_sql);
  395. foreach ($schedule as $item) {
  396. $itemEndDT = $this->findEndTime($itemStartDT, $item["clip_length"]);
  397. $update_sql = "UPDATE cc_schedule SET ".
  398. "starts = '{$itemStartDT->format("Y-m-d H:i:s.u")}', ".
  399. "ends = '{$itemEndDT->format("Y-m-d H:i:s.u")}' ".
  400. "WHERE id = {$item["id"]}";
  401. Application_Common_Database::prepareAndExecute(
  402. $update_sql, array(), Application_Common_Database::EXECUTE);
  403. $itemStartDT = $this->findTimeDifference($itemEndDT, $this->crossfadeDuration);
  404. }
  405. }
  406. /*
  407. * @param int $showInstance
  408. * @param array $exclude
  409. * ids of sched items to remove from the calulation.
  410. * This function squeezes all items of a show together so that
  411. * there are no gaps between them.
  412. */
  413. public function removeGaps($showInstance, $exclude=null)
  414. {
  415. Logging::info("removing gaps from show instance #".$showInstance);
  416. $instance = CcShowInstancesQuery::create()->findPK($showInstance, $this->con);
  417. if (is_null($instance)) {
  418. throw new OutDatedScheduleException(_("The schedule you're viewing is out of date!"));
  419. }
  420. $itemStartDT = $instance->getDbStarts(null);
  421. $schedule = CcScheduleQuery::create()
  422. ->filterByDbInstanceId($showInstance)
  423. ->filterByDbId($exclude, Criteria::NOT_IN)
  424. ->orderByDbStarts()
  425. ->find($this->con);
  426. foreach ($schedule as $item) {
  427. $itemEndDT = $this->findEndTime($itemStartDT, $item->getDbClipLength());
  428. $item->setDbStarts($itemStartDT)
  429. ->setDbEnds($itemEndDT);
  430. $itemStartDT = $itemEndDT;
  431. }
  432. $schedule->save($this->con);
  433. }
  434. /**
  435. *
  436. * Enter description here ...
  437. * @param $scheduleItems
  438. * cc_schedule items, where the items get inserted after
  439. * @param $filesToInsert
  440. * array of schedule item info, what gets inserted into cc_schedule
  441. * @param $adjustSched
  442. */
  443. private function insertAfter($scheduleItems, $mediaItems, $filesToInsert=null, $adjustSched=true, $moveAction=false)
  444. {
  445. try {
  446. // temporary fix for CC-5665
  447. set_time_limit(180);
  448. $affectedShowInstances = array();
  449. //dont want to recalculate times for moved items
  450. //only moved items have a sched_id
  451. $excludeIds = array();
  452. $startProfile = microtime(true);
  453. $temp = array();
  454. $instance = null;
  455. /* Items in shows are ordered by position number. We need to know
  456. * the position when adding/moving items in linked shows so they are
  457. * added or moved in the correct position
  458. */
  459. $pos = 0;
  460. $linked = false;
  461. foreach ($scheduleItems as $schedule) {
  462. //reset
  463. $this->applyCrossfades = true;
  464. $id = intval($schedule["id"]);
  465. /* Find out if the show where the cursor position (where an item will
  466. * be inserted) is located is linked or not. If the show is linked,
  467. * we need to make sure there isn't another cursor selection in one of it's
  468. * linked shows. If there is that will cause a duplication, in the least,
  469. * of inserted items
  470. */
  471. if ($id != 0) {
  472. $schedule_sql = "SELECT * FROM cc_schedule WHERE id = ".$id;
  473. $ccSchedule = Application_Common_Database::prepareAndExecute(
  474. $schedule_sql, array(), Application_Common_Database::SINGLE);
  475. $show_sql = "SELECT * FROM cc_show WHERE id IN (".
  476. "SELECT show_id FROM cc_show_instances WHERE id = ".$ccSchedule["instance_id"].")";
  477. $ccShow = Application_Common_Database::prepareAndExecute(
  478. $show_sql, array(), Application_Common_Database::SINGLE);
  479. $linked = $ccShow["linked"];
  480. if ($linked) {
  481. $unique = $ccShow["id"] . $ccSchedule["position"];
  482. if (!in_array($unique, $temp)) {
  483. $temp[] = $unique;
  484. } else {
  485. continue;
  486. }
  487. }
  488. } else {
  489. $show_sql = "SELECT * FROM cc_show WHERE id IN (".
  490. "SELECT show_id FROM cc_show_instances WHERE id = ".$schedule["instance"].")";
  491. $ccShow = Application_Common_Database::prepareAndExecute(
  492. $show_sql, array(), Application_Common_Database::SINGLE);
  493. $linked = $ccShow["linked"];
  494. if ($linked) {
  495. $unique = $ccShow["id"] . "a";
  496. if (!in_array($unique, $temp)) {
  497. $temp[] = $unique;
  498. } else {
  499. continue;
  500. }
  501. }
  502. }
  503. /* If the show where the cursor position is located is linked
  504. * we need to insert the items for each linked instance belonging
  505. * to that show
  506. */
  507. if ($linked) {
  508. $instances = CcShowInstancesQuery::create()
  509. ->filterByDbShowId($ccShow["id"])
  510. ->filterByDbStarts(gmdate("Y-m-d H:i:s"), Criteria::GREATER_THAN)
  511. ->find();
  512. } else {
  513. $instances = CcShowInstancesQuery::create()
  514. ->filterByDbId($schedule["instance"])
  515. ->find();
  516. }
  517. $excludePositions = array();
  518. foreach($instances as &$instance) {
  519. //reset
  520. $this->applyCrossfades = true;
  521. //$instanceId = $instance["id"];
  522. $instanceId = $instance->getDbId();
  523. if ($id !== 0) {
  524. /* We use the selected cursor's position to find the same
  525. * positions in every other linked instance
  526. */
  527. $pos = $ccSchedule["position"];
  528. $linkedItem_sql = "SELECT ends FROM cc_schedule ".
  529. "WHERE instance_id = {$instanceId} ".
  530. "AND position = {$pos} ".
  531. "AND playout_status != -1";
  532. $linkedItemEnds = Application_Common_Database::prepareAndExecute(
  533. $linkedItem_sql, array(), Application_Common_Database::COLUMN);
  534. if (!$linkedItemEnds) {
  535. //With dynamic smart blocks there may be different number of items in
  536. //each show. In case the position does not exist we need to select
  537. //the end time of the last position
  538. $maxPos_sql = "SELECT max(position) from cc_schedule ".
  539. "WHERE instance_id = {$instanceId}";
  540. $pos = Application_Common_Database::prepareAndExecute(
  541. $maxPos_sql, array(), Application_Common_Database::COLUMN);
  542. //show instance has no scheduled tracks
  543. if (empty($pos)) {
  544. $pos = 0;
  545. $nextStartDT = new DateTime($instance->getDbStarts(), new DateTimeZone("UTC"));
  546. } else {
  547. $linkedItem_sql = "SELECT ends FROM cc_schedule ".
  548. "WHERE instance_id = {$instanceId} ".
  549. "AND position = {$pos} ".
  550. "AND playout_status != -1";
  551. $linkedItemEnds = Application_Common_Database::prepareAndExecute(
  552. $linkedItem_sql, array(), Application_Common_Database::COLUMN);
  553. $nextStartDT = $this->findNextStartTime(
  554. new DateTime($linkedItemEnds, new DateTimeZone("UTC")),
  555. $instanceId);
  556. }
  557. } else {
  558. $nextStartDT = $this->findNextStartTime(
  559. new DateTime($linkedItemEnds, new DateTimeZone("UTC")),
  560. $instanceId);
  561. $pos++;
  562. }
  563. //$pos++;
  564. }
  565. //selected empty row to add after
  566. else {
  567. $showStartDT = new DateTime($instance->getDbStarts(), new DateTimeZone("UTC"));
  568. $nextStartDT = $this->findNextStartTime($showStartDT, $instanceId);
  569. //first item in show so start position counter at 0
  570. $pos = 0;
  571. /* Show is empty so we don't need to calculate crossfades
  572. * for the first inserted item
  573. */
  574. $this->applyCrossfades = false;
  575. }
  576. if (!in_array($instanceId, $affectedShowInstances)) {
  577. $affectedShowInstances[] = $instanceId;
  578. }
  579. /*
  580. * $adjustSched is true if there are schedule items
  581. * following the item just inserted, per show instance
  582. */
  583. if ($adjustSched === true) {
  584. $pstart = microtime(true);
  585. if ($this->applyCrossfades) {
  586. $initalStartDT = clone $this->findTimeDifference(
  587. $nextStartDT, $this->crossfadeDuration);
  588. } else {
  589. $initalStartDT = clone $nextStartDT;
  590. }
  591. $pend = microtime(true);
  592. Logging::debug("finding all following items.");
  593. Logging::debug(floatval($pend) - floatval($pstart));
  594. }
  595. if (is_null($filesToInsert)) {
  596. $filesToInsert = array();
  597. foreach ($mediaItems as $media) {
  598. $filesToInsert = array_merge($filesToInsert,
  599. $this->retrieveMediaFiles($media["id"], $media["type"]));
  600. }
  601. }
  602. $doInsert = false;
  603. $doUpdate = false;
  604. $values = array();
  605. //array that stores the cc_file ids so we can update the is_scheduled flag
  606. $fileIds = array();
  607. foreach ($filesToInsert as &$file) {
  608. //item existed previously and is being moved.
  609. //need to keep same id for resources if we want REST.
  610. if (isset($file['sched_id'])) {
  611. $adjustFromDT = clone $nextStartDT;
  612. $doUpdate = true;
  613. $movedItem_sql = "SELECT * FROM cc_schedule ".
  614. "WHERE id = ".$file["sched_id"];
  615. $sched = Application_Common_Database::prepareAndExecute(
  616. $movedItem_sql, array(), Application_Common_Database::SINGLE);
  617. /* We need to keep a record of the original positon a track
  618. * is being moved from so we can use it to retrieve the correct
  619. * items in linked instances
  620. */
  621. if (!isset($originalPosition)) {
  622. $originalPosition = $sched["position"];
  623. }
  624. /* If we are moving an item in a linked show we need to get
  625. * the relative item to move in each instance. We know what the
  626. * relative item is by its position
  627. */
  628. if ($linked) {
  629. $movedItem_sql = "SELECT * FROM cc_schedule ".
  630. "WHERE position = {$originalPosition} ".
  631. "AND instance_id = {$instanceId}";
  632. $sched = Application_Common_Database::prepareAndExecute(
  633. $movedItem_sql, array(), Application_Common_Database::SINGLE);
  634. }
  635. /* If we don't find a schedule item it means the linked
  636. * shows have a different amount of items (dyanmic block)
  637. * and we should skip the item move for this show instance
  638. */
  639. if (!$sched) {
  640. continue;
  641. }
  642. $excludeIds[] = intval($sched["id"]);
  643. $file["cliplength"] = $sched["clip_length"];
  644. $file["cuein"] = $sched["cue_in"];
  645. $file["cueout"] = $sched["cue_out"];
  646. $file["fadein"] = $sched["fade_in"];
  647. $file["fadeout"] = $sched["fade_out"];
  648. } else {
  649. $doInsert = true;
  650. }
  651. // default fades are in seconds
  652. // we need to convert to '00:00:00' format
  653. $file['fadein'] = Application_Common_DateHelper::secondsToPlaylistTime($file['fadein']);
  654. $file['fadeout'] = Application_Common_DateHelper::secondsToPlaylistTime($file['fadeout']);
  655. switch ($file["type"]) {
  656. case 0:
  657. $fileId = $file["id"];
  658. $streamId = "null";
  659. $fileIds[] = $fileId;
  660. break;
  661. case 1:
  662. $streamId = $file["id"];
  663. $fileId = "null";
  664. break;
  665. default: break;
  666. }
  667. if ($this->applyCrossfades) {
  668. $nextStartDT = $this->findTimeDifference($nextStartDT,
  669. $this->crossfadeDuration);
  670. $endTimeDT = $this->findEndTime($nextStartDT, $file['cliplength']);
  671. $endTimeDT = $this->findTimeDifference($endTimeDT, $this->crossfadeDuration);
  672. /* Set it to false because the rest of the crossfades
  673. * will be applied after we insert each item
  674. */
  675. $this->applyCrossfades = false;
  676. }
  677. $endTimeDT = $this->findEndTime($nextStartDT, $file['cliplength']);
  678. if ($doInsert) {
  679. $values[] = "(".
  680. "'{$nextStartDT->format("Y-m-d H:i:s.u")}', ".
  681. "'{$endTimeDT->format("Y-m-d H:i:s.u")}', ".
  682. "'{$file["cuein"]}', ".
  683. "'{$file["cueout"]}', ".
  684. "'{$file["fadein"]}', ".
  685. "'{$file["fadeout"]}', ".
  686. "'{$file["cliplength"]}', ".
  687. "{$pos}, ".
  688. "{$instanceId}, ".
  689. "{$fileId}, ".
  690. "{$streamId})";
  691. } elseif ($doUpdate) {
  692. $update_sql = "UPDATE cc_schedule SET ".
  693. "starts = '{$nextStartDT->format("Y-m-d H:i:s.u")}', ".
  694. "ends = '{$endTimeDT->format("Y-m-d H:i:s.u")}', ".
  695. "cue_in = '{$file["cuein"]}', ".
  696. "cue_out = '{$file["cueout"]}', ".
  697. "fade_in = '{$file["fadein"]}', ".
  698. "fade_out = '{$file["fadeout"]}', ".
  699. "clip_length = '{$file["cliplength"]}', ".
  700. "position = {$pos}, ".
  701. "instance_id = {$instanceId} ".
  702. "WHERE id = {$sched["id"]}";
  703. Application_Common_Database::prepareAndExecute(
  704. $update_sql, array(), Application_Common_Database::EXECUTE);
  705. }
  706. $nextStartDT = $this->findTimeDifference($endTimeDT, $this->crossfadeDuration);
  707. $pos++;
  708. }//all files have been inserted/moved
  709. if ($doInsert) {
  710. $insert_sql = "INSERT INTO cc_schedule ".
  711. "(starts, ends, cue_in, cue_out, fade_in, fade_out, ".
  712. "clip_length, position, instance_id, file_id, stream_id) VALUES ".
  713. implode($values, ",")." RETURNING id";
  714. $stmt = $this->con->prepare($insert_sql);
  715. if ($stmt->execute()) {
  716. foreach ($stmt->fetchAll() as $row) {
  717. $excludeIds[] = $row["id"];
  718. }
  719. };
  720. }
  721. $selectCriteria = new Criteria();
  722. $selectCriteria->add(CcFilesPeer::ID, $fileIds, Criteria::IN);
  723. $selectCriteria->addAnd(CcFilesPeer::IS_SCHEDULED, false);
  724. $updateCriteria = new Criteria();
  725. $updateCriteria->add(CcFilesPeer::IS_SCHEDULED, true);
  726. BasePeer::doUpdate($selectCriteria, $updateCriteria, $this->con);
  727. /* Reset files to insert so we can get a new set of files. We have
  728. * to do this in case we are inserting a dynamic block
  729. */
  730. if (!$moveAction) {
  731. $filesToInsert = null;
  732. }
  733. if ($adjustSched === true) {
  734. $followingItems_sql = "SELECT * FROM cc_schedule ".
  735. "WHERE starts >= '{$initalStartDT->format("Y-m-d H:i:s.u")}' ".
  736. "AND instance_id = {$instanceId} ";
  737. if (count($excludeIds) > 0) {
  738. $followingItems_sql .= "AND id NOT IN (". implode($excludeIds, ",").") ";
  739. }
  740. $followingItems_sql .= "ORDER BY starts";
  741. $followingSchedItems = Application_Common_Database::prepareAndExecute(
  742. $followingItems_sql);
  743. $pstart = microtime(true);
  744. //recalculate the start/end times after the inserted items.
  745. foreach ($followingSchedItems as $item) {
  746. $endTimeDT = $this->findEndTime($nextStartDT, $item["clip_length"]);
  747. $endTimeDT = $this->findTimeDifference($endTimeDT, $this->crossfadeDuration);
  748. $update_sql = "UPDATE cc_schedule SET ".
  749. "starts = '{$nextStartDT->format("Y-m-d H:i:s.u")}', ".
  750. "ends = '{$endTimeDT->format("Y-m-d H:i:s.u")}', ".
  751. "position = {$pos} ".
  752. "WHERE id = {$item["id"]}";
  753. Application_Common_Database::prepareAndExecute(
  754. $update_sql, array(), Application_Common_Database::EXECUTE);
  755. $nextStartDT = $this->findTimeDifference($endTimeDT, $this->crossfadeDuration);
  756. $pos++;
  757. }
  758. $pend = microtime(true);
  759. Logging::debug("adjusting all following items.");
  760. Logging::debug(floatval($pend) - floatval($pstart));
  761. }
  762. if ($moveAction) {
  763. $this->calculateCrossfades($instanceId);
  764. }
  765. }//for each instance
  766. }//for each schedule location
  767. $endProfile = microtime(true);
  768. Logging::debug("finished adding scheduled items.");
  769. Logging::debug(floatval($endProfile) - floatval($startProfile));
  770. //update the status flag in cc_schedule.
  771. $instances = CcShowInstancesQuery::create()
  772. ->filterByPrimaryKeys($affectedShowInstances)
  773. ->find($this->con);
  774. $startProfile = microtime(true);
  775. foreach ($instances as $instance) {
  776. $instance->updateScheduleStatus($this->con);
  777. }
  778. $endProfile = microtime(true);
  779. Logging::debug("updating show instances status.");
  780. Logging::debug(floatval($endProfile) - floatval($startProfile));
  781. $startProfile = microtime(true);
  782. //update the last scheduled timestamp.
  783. CcShowInstancesQuery::create()
  784. ->filterByPrimaryKeys($affectedShowInstances)
  785. ->update(array('DbLastScheduled' => new DateTime("now", new DateTimeZone("UTC"))), $this->con);
  786. $endProfile = microtime(true);
  787. Logging::debug("updating last scheduled timestamp.");
  788. Logging::debug(floatval($endProfile) - floatval($startProfile));
  789. } catch (Exception $e) {
  790. Logging::debug($e->getMessage());
  791. throw $e;
  792. }
  793. }
  794. private function updateMovedItem()
  795. {
  796. }
  797. private function getInstances($instanceId)
  798. {
  799. $ccShowInstance = CcShowInstancesQuery::create()->findPk($instanceId);
  800. $ccShow = $ccShowInstance->getCcShow();
  801. if ($ccShow->isLinked()) {
  802. return $ccShow->getFutureCcShowInstancess();
  803. } else {
  804. return array($ccShowInstance);
  805. }
  806. }
  807. /*
  808. * @param array $scheduleItems (schedule_id and instance_id it belongs to)
  809. * @param array $mediaItems (file|block|playlist|webstream)
  810. */
  811. public function scheduleAfter($scheduleItems, $mediaItems, $adjustSched = true)
  812. {
  813. $this->con->beginTransaction();
  814. try {
  815. $this->validateMediaItems($mediaItems); //Check for missing files, etc.
  816. $this->validateRequest($scheduleItems, true);
  817. /*
  818. * create array of arrays
  819. * array of schedule item info
  820. * (sched_id is the cc_schedule id and is set if an item is being
  821. * moved because it is already in cc_schedule)
  822. * [0] = Array(
  823. * id => 1,
  824. * cliplength => 00:04:32,
  825. * cuein => 00:00:00,
  826. * cueout => 00:04:32,
  827. * fadein => 00.5,
  828. * fadeout => 00.5,
  829. * sched_id => ,
  830. * type => 0)
  831. * [1] = Array(
  832. * id => 2,
  833. * cliplength => 00:05:07,
  834. * cuein => 00:00:00,
  835. * cueout => 00:05:07,
  836. * fadein => 00.5,
  837. * fadeout => 00.5,
  838. * sched_id => ,
  839. * type => 0)
  840. */
  841. $this->insertAfter($scheduleItems, $mediaItems, null, $adjustSched);
  842. $this->con->commit();
  843. Application_Model_RabbitMq::PushSchedule();
  844. } catch (Exception $e) {
  845. $this->con->rollback();
  846. throw $e;
  847. }
  848. }
  849. /*
  850. * @param array $selectedItem
  851. * @param array $afterItem
  852. */
  853. public function moveItem($selectedItems, $afterItems, $adjustSched = true)
  854. {
  855. $startProfile = microtime(true);
  856. $this->con->beginTransaction();
  857. $this->con->useDebug(true);
  858. try {
  859. $this->validateItemMove($selectedItems, $afterItems[0]);
  860. $this->validateRequest($selectedItems);
  861. $this->validateRequest($afterItems);
  862. $endProfile = microtime(true);
  863. Logging::debug("validating move request took:");
  864. Logging::debug(floatval($endProfile) - floatval($startProfile));
  865. $afterInstance = CcShowInstancesQuery::create()->findPK($afterItems[0]["instance"], $this->con);
  866. //map show instances to cc_schedule primary keys.
  867. $modifiedMap = array();
  868. $movedData = array();
  869. //prepare each of the selected items.
  870. for ($i = 0; $i < count($selectedItems); $i++) {
  871. $selected = CcScheduleQuery::create()->findPk($selectedItems[$i]["id"], $this->con);
  872. $selectedInstance = $selected->getCcShowInstances($this->con);
  873. $data = $this->fileInfo;
  874. $data["id"] = $selected->getDbFileId();
  875. $data["cliplength"] = $selected->getDbClipLength();
  876. $data["cuein"] = $selected->getDbCueIn();
  877. $data["cueout"] = $selected->getDbCueOut();
  878. $data["fadein"] = $selected->getDbFadeIn();
  879. $data["fadeout"] = $selected->getDbFadeOut();
  880. $data["sched_id"] = $selected->getDbId();
  881. $movedData[] = $data;
  882. //figure out which items must be removed from calculated show times.
  883. $showInstanceId = $selectedInstance->getDbId();
  884. $schedId = $selected->getDbId();
  885. if (isset($modifiedMap[$showInstanceId])) {
  886. array_push($modifiedMap[$showInstanceId], $schedId);
  887. } else {
  888. $modifiedMap[$showInstanceId] = array($schedId);
  889. }
  890. }
  891. //calculate times excluding the to be moved items.
  892. foreach ($modifiedMap as $instance => $schedIds) {
  893. $startProfile = microtime(true);
  894. $this->removeGaps($instance, $schedIds);
  895. $endProfile = microtime(true);
  896. Logging::debug("removing gaps from instance $instance:");
  897. Logging::debug(floatval($endProfile) - floatval($startProfile));
  898. }
  899. $startProfile = microtime(true);
  900. $this->insertAfter($afterItems, null, $movedData, $adjustSched, true);
  901. $endProfile = microtime(true);
  902. Logging::debug("inserting after removing gaps.");
  903. Logging::debug(floatval($endProfile) - floatval($startProfile));
  904. $modified = array_keys($modifiedMap);
  905. //need to adjust shows we have moved items from.
  906. foreach ($modified as $instanceId) {
  907. $instance = CcShowInstancesQuery::create()->findPK($instanceId, $this->con);
  908. $instance->updateScheduleStatus($this->con);
  909. }
  910. $this->con->useDebug(false);
  911. $this->con->commit();
  912. Application_Model_RabbitMq::PushSchedule();
  913. } catch (Exception $e) {
  914. $this->con->rollback();
  915. throw $e;
  916. }
  917. }
  918. public function removeItems($scheduledItems, $adjustSched = true, $cancelShow=false)
  919. {
  920. $showInstances = array();
  921. $this->con->beginTransaction();
  922. try {
  923. $this->validateRequest($scheduledItems);
  924. $scheduledIds = array();
  925. foreach ($scheduledItems as $item) {
  926. $scheduledIds[] = $item["id"];
  927. }
  928. $removedItems = CcScheduleQuery::create()->findPks($scheduledIds);
  929. // This array is used to keep track of every show instance that was
  930. // effected by the track deletion. It will be used later on to
  931. // remove gaps in the schedule and adjust crossfade times.
  932. $effectedInstanceIds = array();
  933. foreach ($removedItems as $removedItem) {
  934. $instance = $removedItem->getCcShowInstances($this->con);
  935. $effectedInstanceIds[] = $instance->getDbId();
  936. //check if instance is linked and if so get the schedule items
  937. //for all linked instances so we can delete them too
  938. if (!$cancelShow && $instance->getCcShow()->isLinked()) {
  939. //returns all linked instances if linked
  940. $ccShowInstances = $this->getInstances($instance->getDbId());
  941. $instanceIds = array();
  942. foreach ($ccShowInstances as $ccShowInstance) {
  943. $instanceIds[] = $ccShowInstance->getDbId();
  944. }
  945. $effectedInstanceIds = array_merge($effectedInstanceIds, $instanceIds);
  946. // Delete the same track, represented by $removedItem, in
  947. // each linked show instance.
  948. $itemsToDelete = CcScheduleQuery::create()
  949. ->filterByDbPosition($removedItem->getDbPosition())
  950. ->filterByDbInstanceId($instanceIds, Criteria::IN)
  951. ->filterByDbId($removedItem->getDbId(), Criteria::NOT_EQUAL)
  952. ->delete($this->con);
  953. }
  954. //check to truncate the currently playing item instead of deleting it.
  955. if ($removedItem->isCurrentItem($this->epochNow)) {
  956. $nEpoch = $this->epochNow;
  957. $sEpoch = $removedItem->getDbStarts('U.u');
  958. $length = bcsub($nEpoch , $sEpoch , 6);
  959. $cliplength = Application_Common_DateHelper::secondsToPlaylistTime($length);
  960. $cueinSec = Application_Common_DateHelper::playlistTimeToSeconds($removedItem->getDbCueIn());
  961. $cueOutSec = bcadd($cueinSec , $length, 6);
  962. $cueout = Application_Common_DateHelper::secondsToPlaylistTime($cueOutSec);
  963. //Set DbEnds - 1 second because otherwise there can be a timing issue
  964. //when sending the new schedule to Pypo where Pypo thinks the track is still
  965. //playing.
  966. $removedItem->setDbCueOut($cueout)
  967. ->setDbClipLength($cliplength)
  968. ->setDbEnds($this->nowDT)
  969. ->save($this->con);
  970. } else {
  971. $removedItem->delete($this->con);
  972. }
  973. }
  974. Application_Model_StoredFile::updatePastFilesIsScheduled();
  975. if ($adjustSched === true) {
  976. foreach ($effectedInstanceIds as $instance) {
  977. $this->removeGaps($instance);
  978. $this->calculateCrossfades($instance);
  979. }
  980. }
  981. //update the status flag in cc_schedule.
  982. $instances = CcShowInstancesQuery::create()
  983. ->filterByPrimaryKeys($effectedInstanceIds)
  984. ->find($this->con);
  985. foreach ($instances as $instance) {
  986. $instance->updateScheduleStatus($this->con);
  987. $instance->correctSchedulePositions();
  988. }
  989. //update the last scheduled timestamp.
  990. CcShowInstancesQuery::create()
  991. ->filterByPrimaryKeys($showInstances)
  992. ->update(array('DbLastScheduled' => new DateTime("now", new DateTimeZone("UTC"))), $this->con);
  993. $this->con->commit();
  994. Application_Model_RabbitMq::PushSchedule();
  995. } catch (Exception $e) {
  996. $this->con->rollback();
  997. throw $e;
  998. }
  999. }
  1000. /*
  1001. * Used for cancelling the current show instance.
  1002. *
  1003. * @param $p_id id of the show instance to cancel.
  1004. */
  1005. public function cancelShow($p_id)
  1006. {
  1007. $this->con->beginTransaction();
  1008. try {
  1009. $instance = CcShowInstancesQuery::create()->findPK($p_id);
  1010. if (!$instance->getDbRecord()) {
  1011. $items = CcScheduleQuery::create()
  1012. ->filterByDbInstanceId($p_id)
  1013. ->filterByDbEnds($this->nowDT, Criteria::GREATER_THAN)
  1014. ->find($this->con);
  1015. if (count($items) > 0) {
  1016. $remove = array();
  1017. $ts = $this->nowDT->format('U');
  1018. for ($i = 0; $i < count($items); $i++) {
  1019. $remove[$i]["instance"] = $p_id;
  1020. $remove[$i]["timestamp"] = $ts;
  1021. $remove[$i]["id"] = $items[$i]->getDbId();
  1022. }
  1023. $this->removeItems($remove, false, true);
  1024. }
  1025. } else {
  1026. $rebroadcasts = $instance->getCcShowInstancessRelatedByDbId(null, $this->con);
  1027. $rebroadcasts->delete($this->con);
  1028. }
  1029. $instance->setDbEnds($this->nowDT);
  1030. $instance->save($this->con);
  1031. $this->con->commit();
  1032. if ($instance->getDbRecord()) {
  1033. Application_Model_RabbitMq::SendMessageToShowRecorder("cancel_recording");
  1034. }
  1035. } catch (Exception $e) {
  1036. $this->con->rollback();
  1037. throw $e;
  1038. }
  1039. }
  1040. }
  1041. class OutDatedScheduleException extends Exception {}