From c043053407dc4daaf8b8b6eb046d00b145b64408 Mon Sep 17 00:00:00 2001
From: Martin Konecny <martin.konecny@gmail.com>
Date: Fri, 31 Aug 2012 12:18:37 -0400
Subject: [PATCH] CC-4321: NowPlaying: Cancelling Webstream has no effect and
 results in OnAir being grayed out

-fixed
---
 airtime_mvc/application/models/Schedule.php  |  7 +--
 airtime_mvc/application/models/Scheduler.php | 10 +++-
 python_apps/pypo/pypopush.py                 | 58 +++++++++++---------
 3 files changed, 43 insertions(+), 32 deletions(-)

diff --git a/airtime_mvc/application/models/Schedule.php b/airtime_mvc/application/models/Schedule.php
index fdbec24b7..176c88f3c 100644
--- a/airtime_mvc/application/models/Schedule.php
+++ b/airtime_mvc/application/models/Schedule.php
@@ -14,11 +14,8 @@ class Application_Model_Schedule
         $sql = "SELECT COUNT(*) FROM ".$CC_CONFIG["scheduleTable"]
         ." WHERE file_id = {$p_fileId} AND ends > NOW() AT TIME ZONE 'UTC'";
         $count = $con->query($sql)->fetchColumn(0);
-        if (is_numeric($count) && ($count != '0')) {
-            return TRUE;
-        } else {
-            return FALSE;
-        }
+
+        return (is_numeric($count) && ($count != '0'));
     }
 
     /**
diff --git a/airtime_mvc/application/models/Scheduler.php b/airtime_mvc/application/models/Scheduler.php
index 1944cbd58..68e8bf8ad 100644
--- a/airtime_mvc/application/models/Scheduler.php
+++ b/airtime_mvc/application/models/Scheduler.php
@@ -24,7 +24,11 @@ class Application_Model_Scheduler
     {
         $this->con = Propel::getConnection(CcSchedulePeer::DATABASE_NAME);
 
-        $this->epochNow = microtime(true);
+        //subtracting one because sometimes when we cancel a track, we set its end time
+        //to epochNow and then send the new schedule to pypo. Sometimes the currently cancelled
+        //track can still be included in the new schedule because it may have a few ms left to play.
+        //subtracting 1 second from epochNow resolves this issue.
+        $this->epochNow = microtime(true)-1;
         $this->nowDT = DateTime::createFromFormat("U.u", $this->epochNow, new DateTimeZone("UTC"));
 
         if ($this->nowDT === false) {
@@ -324,6 +328,8 @@ class Application_Model_Scheduler
      * @param int $showInstance
     * @param array $exclude
     *   ids of sched items to remove from the calulation.
+    *   This function squeezes all items of a show together so that
+    *   there are no gaps between them.
     */
     private function removeGaps($showInstance, $exclude=null)
     {
@@ -665,7 +671,7 @@ class Application_Model_Scheduler
                     //playing.
                     $removedItem->setDbCueOut($cueout)
                         ->setDbClipLength($cliplength)
-                        ->setDbEnds($this->nowDT->sub(new DateInteval("PT1S")))
+                        ->setDbEnds($this->nowDT)
                         ->save($this->con);
                 } else {
                     $removedItem->delete($this->con);
diff --git a/python_apps/pypo/pypopush.py b/python_apps/pypo/pypopush.py
index 87e651fab..f57a8c468 100644
--- a/python_apps/pypo/pypopush.py
+++ b/python_apps/pypo/pypopush.py
@@ -81,27 +81,29 @@ class PypoPush(Thread):
                         chains.remove(original_chain)
                     except ValueError, e:
                         self.logger.error(str(e))
-                    if len(liquidsoap_queue_approx) == 0 and current_event_chain[0]['type'] == 'file':
-                        #Something is scheduled but Liquidsoap is not playing anything!
-                        #Need to schedule it immediately..this might happen if Liquidsoap crashed.
-                        self.modify_cue_point(current_event_chain[0])
-                        next_media_item_chain = current_event_chain
-                        time_until_next_play = 0
-                        #sleep for 0.2 seconds to give pypo-file time to copy.
-                        time.sleep(0.2)
-                        continue
-                    if not self.current_stream_info and current_event_chain[0]['type'] == 'stream':
-                        #a stream is schedule but Liquidsoap is not playing it. Need to start it.
-                        next_media_item_chain = current_event_chain
-                        time_until_next_play = 0
-                        continue
+
+                    if len(liquidsoap_queue_approx) == 0 and not self.current_stream_info:
+                        #Nothing is currently being playing by Liquidsoap
+                        if current_event_chain[0]['type'] == 'file':
+                            #Something is scheduled but Liquidsoap is not playing anything!
+                            #Need to schedule it immediately..this might happen if Liquidsoap crashed.
+                            self.modify_cue_point(current_event_chain[0])
+                            next_media_item_chain = current_event_chain
+                            time_until_next_play = 0
+                            #sleep for 0.2 seconds to give pypo-file time to copy.
+                            time.sleep(0.2)
+                            continue
+                        if current_event_chain[0]['type'] == 'stream':
+                            #a stream is schedule but Liquidsoap is not playing it. Need to start it.
+                            next_media_item_chain = current_event_chain
+                            time_until_next_play = 0
+                            continue
 
                 #At this point we know that Liquidsoap is playing something, and that something
                 #is scheduled. We need to verify whether the schedule we just received matches
                 #what Liquidsoap is playing, and if not, correct it.
-                media_chain = filter(lambda item: (item["type"] == "file"), current_event_chain)
-                stream_chain = filter(lambda item: (item["type"] == "stream"), current_event_chain)
-                self.handle_new_schedule(media_schedule, liquidsoap_queue_approx, media_chain, stream_chain)
+
+                self.handle_new_schedule(media_schedule, liquidsoap_queue_approx, current_event_chain)
 
 
                 #At this point everything in the present has been taken care of and Liquidsoap
@@ -184,7 +186,7 @@ class PypoPush(Thread):
 
         return liquidsoap_queue_approx
 
-    def handle_new_schedule(self, media_schedule, liquidsoap_queue_approx, media_chain, stream_chain):
+    def handle_new_schedule(self, media_schedule, liquidsoap_queue_approx, current_event_chain):
         """
         This function's purpose is to gracefully handle situations where
         Liquidsoap already has a track in its queue, but the schedule
@@ -192,18 +194,24 @@ class PypoPush(Thread):
         call other functions that will connect to Liquidsoap and alter its
         queue.
         """
+        media_chain = filter(lambda item: (item["type"] == "file"), current_event_chain)
+        stream_chain = filter(lambda item: (item["type"] == "stream"), current_event_chain)
+
+        self.logger.debug(self.current_stream_info)
+        self.logger.debug(current_event_chain)
+
 
         if self.current_stream_info:
-            if len(stream_chain) == 0:
+            if current_event_chain[0]['type'] == "stream":
+                if self.current_stream_info['uri'] != stream_chain[0]['uri']:
+                    #Liquidsoap is rebroadcasting a webstream and a webstream is scheduled
+                    #to play, but they are not the same!
+                    self.stop_web_stream(self.current_stream_info)
+                    self.start_web_stream(stream_chain[0])
+            else:
                 #Liquidsoap is rebroadcasting a webstream, but there is no stream
                 #in the schedule. Let's stop streaming.
                 self.stop_web_stream(self.current_stream_info)
-            elif self.current_stream_info['uri'] != stream_chain[0]['uri']:
-                #Liquidsoap is rebroadcasting a webstream and a webstream is scheduled
-                #to play, but they are not the same!
-                self.stop_web_stream(self.current_stream_info)
-                self.start_web_stream(stream_chain[0])
-
 
         problem_at_iteration = self.find_removed_items(media_schedule, liquidsoap_queue_approx)