diff --git a/airtime_mvc/application/models/DateHelper.php b/airtime_mvc/application/models/DateHelper.php index 7f574cbbc..504ad9e9e 100644 --- a/airtime_mvc/application/models/DateHelper.php +++ b/airtime_mvc/application/models/DateHelper.php @@ -292,5 +292,17 @@ class Application_Model_DateHelper return $p_dateString; return self::ConvertToUtcDateTime($p_dateString)->format($p_format); } + + /* + * Example input: "00:02:32.746562". Output is a DateInterval object + * representing that 2 minute, 32.746562 second interval. + * + */ + public static function getDateIntervalFromString($p_interval){ + list($hour_min_sec, $subsec) = explode(".", $p_interval); + list($hour, $min, $sec) = explode(":", $hour_min_sec); + + return new DateInterval("PT{$hour}H{$min}M{$sec}S"); + } } diff --git a/airtime_mvc/application/models/Schedule.php b/airtime_mvc/application/models/Schedule.php index 5a1a304a9..e65774c18 100644 --- a/airtime_mvc/application/models/Schedule.php +++ b/airtime_mvc/application/models/Schedule.php @@ -645,16 +645,19 @@ class Application_Model_Schedule { $uri = $storedFile->getFilePath(); $showEndDateTime = new DateTime($item["show_end"], $utcTimeZone); + $trackStartDateTime = new DateTime($item["start"], $utcTimeZone); $trackEndDateTime = new DateTime($item["end"], $utcTimeZone); /* Note: cue_out and end are always the same. */ /* TODO: Not all tracks will have "show_end" */ if ($trackEndDateTime->getTimestamp() > $showEndDateTime->getTimestamp()){ - $diff = $trackEndDateTime->getTimestamp() - $showEndDateTime->getTimestamp(); - //assuming ends takes cue_out into assumption - $item["cue_out"] = $item["cue_out"] - $diff; + $di = $trackStartDateTime->diff($showEndDateTime); + + $item["cue_out"] = $di->format("%H:%i:%s").".000"; } + + $start = Application_Model_Schedule::AirtimeTimeToPypoTime($item["start"]); $data["media"][$start] = array( @@ -673,102 +676,6 @@ class Application_Model_Schedule { return $data; } - /** - * Export the schedule in json formatted for pypo (the liquidsoap scheduler) - * - * @param string $p_fromDateTime - * In the format "YYYY-MM-DD-HH-mm-SS" - * @param string $p_toDateTime - * In the format "YYYY-MM-DD-HH-mm-SS" - */ - public static function GetScheduledPlaylistsOld($p_fromDateTime = null, $p_toDateTime = null) - { - global $CC_CONFIG, $CC_DBC; - - if (is_null($p_fromDateTime)) { - $t1 = new DateTime("@".time()); - $range_start = $t1->format("Y-m-d H:i:s"); - } else { - $range_start = Application_Model_Schedule::PypoTimeToAirtimeTime($p_fromDateTime); - } - if (is_null($p_fromDateTime)) { - $t2 = new DateTime("@".time()); - $t2->add(new DateInterval("PT24H")); - $range_end = $t2->format("Y-m-d H:i:s"); - } else { - $range_end = Application_Model_Schedule::PypoTimeToAirtimeTime($p_toDateTime); - } - - // Scheduler wants everything in a playlist - $data = Application_Model_Schedule::GetItems($range_start, $range_end, true); - $playlists = array(); - - if (is_array($data)){ - foreach ($data as $dx){ - $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 = Application_Model_Schedule::AirtimeTimeToPypoTime($start); - $timestamp = strtotime($start); - $playlists[$pkey]['source'] = "PLAYLIST"; - $playlists[$pkey]['x_ident'] = $dx['group_id']; - $playlists[$pkey]['timestamp'] = $timestamp; - $playlists[$pkey]['duration'] = $dx['clip_length']; - $playlists[$pkey]['played'] = '0'; - $playlists[$pkey]['schedule_id'] = $dx['group_id']; - $playlists[$pkey]['show_name'] = $dx['show_name']; - $playlists[$pkey]['show_start'] = Application_Model_Schedule::AirtimeTimeToPypoTime($dx['show_start']); - $playlists[$pkey]['show_end'] = Application_Model_Schedule::AirtimeTimeToPypoTime($dx['show_end']); - $playlists[$pkey]['user_id'] = 0; - $playlists[$pkey]['id'] = $dx['group_id']; - $playlists[$pkey]['start'] = Application_Model_Schedule::AirtimeTimeToPypoTime($dx["start"]); - $playlists[$pkey]['end'] = Application_Model_Schedule::AirtimeTimeToPypoTime($dx["end"]); - } - } - ksort($playlists); - - foreach ($playlists as &$playlist) - { - $scheduleGroup = new Application_Model_ScheduleGroup($playlist["schedule_id"]); - $items = $scheduleGroup->getItems(); - $medias = array(); - foreach ($items as $item) - { - $storedFile = Application_Model_StoredFile::Recall($item["file_id"]); - $uri = $storedFile->getFileUrlUsingConfigAddress(); - - $starts = Application_Model_Schedule::AirtimeTimeToPypoTime($item["starts"]); - $medias[$starts] = array( - 'id' => $storedFile->getGunid(), - 'uri' => $uri, - 'fade_in' => Application_Model_Schedule::WallTimeToMillisecs($item["fade_in"]), - 'fade_out' => Application_Model_Schedule::WallTimeToMillisecs($item["fade_out"]), - 'fade_cross' => 0, - 'cue_in' => Application_Model_DateHelper::CalculateLengthInSeconds($item["cue_in"]), - 'cue_out' => Application_Model_DateHelper::CalculateLengthInSeconds($item["cue_out"]), - 'start' => $starts, - 'end' => Application_Model_Schedule::AirtimeTimeToPypoTime($item["ends"]) - ); - } - ksort($medias); - $playlist['medias'] = $medias; - } - - $result = array(); - $result['status'] = array('range' => array('start' => $range_start, 'end' => $range_end), - 'version' => AIRTIME_REST_VERSION); - $result['playlists'] = $playlists; - $result['check'] = 1; - $result['stream_metadata'] = array(); - $result['stream_metadata']['format'] = Application_Model_Preference::GetStreamLabelFormat(); - $result['stream_metadata']['station_name'] = Application_Model_Preference::GetStationName(); - - return $result; - } - public static function deleteAll() { global $CC_CONFIG, $CC_DBC; diff --git a/dev_tools/auto_schedule_show.php b/dev_tools/auto_schedule_show.php index dee0aa7d1..d9f47bc44 100644 --- a/dev_tools/auto_schedule_show.php +++ b/dev_tools/auto_schedule_show.php @@ -24,21 +24,21 @@ function query($conn, $query){ } function getFileFromCcFiles($conn){ - $query = "SELECT * from cc_files LIMIT 1"; + $query = "SELECT * from cc_files LIMIT 2"; $result = query($conn, $query); - $file = null; + $files = array(); while ($row = pg_fetch_array($result)) { - $file = $row; + $files[] = $row; } - if (is_null($file)){ + if (count($files) == 0){ echo "Library is empty. Could not choose random file."; exit(1); } - return $file; + return $files; } function insertIntoCcShow($conn){ @@ -64,7 +64,7 @@ function insertIntoCcShow($conn){ return $show_id; } -function insertIntoCcShowInstances($conn, $show_id, $starts, $ends, $file){ +function insertIntoCcShowInstances($conn, $show_id, $starts, $ends, $files){ /* Step 2: * Create a show instance. * Column values: @@ -75,9 +75,8 @@ function insertIntoCcShowInstances($conn, $show_id, $starts, $ends, $file){ $now = $nowDateTime->format("Y-m-d H:i:s"); - $columns = "(starts, ends, show_id, record, rebroadcast, instance_id, file_id, time_filled, last_scheduled, modified_instance)"; - $values = "('$starts', '$ends', $show_id, 0, 0, NULL, NULL, '$file[length]', '$now', 'f')"; + $values = "('$starts', '$ends', $show_id, 0, 0, NULL, NULL, TIMESTAMP '$ends' - TIMESTAMP '$starts', '$now', 'f')"; $query = "INSERT INTO cc_show_instances $columns values $values "; echo $query.PHP_EOL; @@ -101,13 +100,39 @@ function insertIntoCcShowInstances($conn, $show_id, $starts, $ends, $file){ * id | starts | ends | file_id | clip_length| fade_in | fade_out | cue_in | cue_out | media_item_played | instance_id * 1 | 2012-02-29 23:25:00 | 2012-02-29 23:30:05.037166 | 1 | 00:05:05.037166 | 00:00:00 | 00:00:00 | 00:00:00 | 00:05:05.037166 | f | 5 */ -function insertIntoCcSchedule($conn, $file, $show_instance_id, $starts, $ends){ +function insertIntoCcSchedule($conn, $files, $show_instance_id, $p_starts, $p_ends){ $columns = "(starts, ends, file_id, clip_length, fade_in, fade_out, cue_in, cue_out, media_item_played, instance_id)"; - $values = "('$starts', '$ends', $file[id], '$file[length]', '00:00:00', '00:00:00', '00:00:00', '$file[length]', 'f', $show_instance_id)"; - $query = "INSERT INTO cc_schedule $columns VALUES $values"; - echo $query.PHP_EOL; - $result = query($conn, $query); + $starts = $p_starts; + + foreach($files as $file){ + + $endsDateTime = new DateTime($starts, new DateTimeZone("UTC")); + $lengthDateInterval = getDateInterval($file["length"]); + $endsDateTime->add($lengthDateInterval); + $ends = $endsDateTime->format("Y-m-d H:i:s"); + + $values = "('$starts', '$ends', $file[id], '$file[length]', '00:00:00', '00:00:00', '00:00:00', '$file[length]', 'f', $show_instance_id)"; + $query = "INSERT INTO cc_schedule $columns VALUES $values"; + echo $query.PHP_EOL; + + $starts = $ends; + $result = query($conn, $query); + } +} + +function getDateInterval($interval){ + list($length,) = explode(".", $interval); + list($hour, $min, $sec) = explode(":", $length); + return new DateInterval("PT{$hour}H{$min}M{$sec}S"); +} + +function getEndTime($startDateTime, $p_files){ + foreach ($p_files as $file){ + $startDateTime->add(getDateInterval($file['length'])); + } + + return $startDateTime; } function rabbitMqNotify(){ @@ -149,14 +174,18 @@ EOD; } $startDateTime = new DateTime("now + 30sec", new DateTimeZone("UTC")); -$endDateTime = new DateTime("now + 1min 30sec", new DateTimeZone("UTC")); +//$endDateTime = new DateTime("now + 1min 30sec", new DateTimeZone("UTC")); $starts = $startDateTime->format("Y-m-d H:i:s"); +//$ends = $endDateTime->format("Y-m-d H:i:s"); + +$files = getFileFromCcFiles($conn); +$show_id = insertIntoCcShow($conn); + +$endDateTime = getEndTime(clone $startDateTime, $files); $ends = $endDateTime->format("Y-m-d H:i:s"); -$file = getFileFromCcFiles($conn); -$show_id = insertIntoCcShow($conn); -$show_instance_id = insertIntoCcShowInstances($conn, $show_id, $starts, $ends, $file); -insertIntoCcSchedule($conn, $file, $show_instance_id, $starts, $ends); +$show_instance_id = insertIntoCcShowInstances($conn, $show_id, $starts, $ends, $files); +insertIntoCcSchedule($conn, $files, $show_instance_id, $starts, $ends); rabbitMqNotify(); diff --git a/python_apps/pypo/pypopush.py b/python_apps/pypo/pypopush.py index ac3f99d9e..aa7b113ff 100644 --- a/python_apps/pypo/pypopush.py +++ b/python_apps/pypo/pypopush.py @@ -45,122 +45,79 @@ class PypoPush(Thread): self.push_ahead = 5 self.last_end_time = 0 - + self.pushed_objects = {} self.logger = logging.getLogger('push') - def push(self): - """ - The Push Loop - the push loop periodically checks if there is a playlist - that should be scheduled at the current time. - If yes, the current liquidsoap playlist gets replaced with the corresponding one, - then liquidsoap is asked (via telnet) to reload and immediately play it. - """ - liquidsoap_queue_approx = self.get_queue_items_from_liquidsoap() + def main(self): + loops = 0 + heartbeat_period = math.floor(30/PUSH_INTERVAL) - try: - self.media = self.queue.get(block=True, timeout=PUSH_INTERVAL) - if not self.queue.empty(): - while not self.queue.empty(): - self.media = self.queue.get() - self.logger.debug("Received data from pypo-fetch") - self.logger.debug('media %s' % json.dumps(self.media)) - self.handle_new_media(self.media, liquidsoap_queue_approx) - except Empty, e: - pass + next_media_item_chain = None + media_schedule = None + time_until_next_play = None + + while True: + try: + if time_until_next_play is None: + media_schedule = self.queue.get(block=True) + else: + media_schedule = self.queue.get(block=True, timeout=time_until_next_play) + + #We get to the following lines only if a schedule was received. + liquidsoap_queue_approx = self.get_queue_items_from_liquidsoap() - media = self.media - if len(liquidsoap_queue_approx) < MAX_LIQUIDSOAP_QUEUE_LENGTH: - if media: + chains = self.get_all_chains(media_schedule) + current_chain = self.get_current_chain(chains) + if len(current_chain) > 0 and len(liquidsoap_queue_approx) == 0: + #Something is scheduled but Liquidsoap is not playing anything! + #Need to schedule it immediately + self.modify_cue_point_of_first_link(current_chain) + next_media_item_chain = current_chain + time_until_next_play = 0 + else: + self.handle_new_media_schedule(media_schedule, liquidsoap_queue_approx) + chains = self.get_all_chains(media_schedule) + next_media_item_chain = self.get_next_schedule_chain(chains) + self.logger.debug("Next schedule chain: %s", next_media_item_chain) + if next_media_item_chain is not None: + tnow = datetime.utcnow() + chain_start = datetime.strptime(next_media_item_chain[0]['start'], "%Y-%m-%d-%H-%M-%S") + time_until_next_play = self.date_interval_to_seconds(chain_start - tnow) + self.logger.debug("Blocking %s seconds until show start", time_until_next_play) + else: + self.logger.debug("Blocking indefinitely since no show scheduled") + time_until_next_play = None + except Empty, e: + #We only get here when a new chain of tracks are ready to be played. + self.push_to_liquidsoap(next_media_item_chain) - tnow = datetime.utcnow() - tcoming = tnow + timedelta(seconds=self.push_ahead) - - for key in media.keys(): - media_item = media[key] - - item_start = datetime.strptime(media_item['start'][0:19], "%Y-%m-%d-%H-%M-%S") - item_end = datetime.strptime(media_item['end'][0:19], "%Y-%m-%d-%H-%M-%S") - - if len(liquidsoap_queue_approx) == 0 and item_start <= tnow and tnow < item_end: - """ - Something is scheduled now, but Liquidsoap is not playing anything! Let's play the current media_item - """ - - self.logger.debug("Found media_item that should be playing! Starting...") - - adjusted_cue_in = tnow - item_start - adjusted_cue_in_seconds = self.date_interval_to_seconds(adjusted_cue_in) - - self.logger.debug("Found media_item that should be playing! Adjust cue point by %ss" % adjusted_cue_in_seconds) - self.push_to_liquidsoap(media_item, adjusted_cue_in_seconds) - - elif tnow <= item_start and item_start < tcoming: - """ - If the media item starts in the next 10 seconds, push it to the queue. - """ - self.logger.debug('Preparing to push media item scheduled at: %s', key) - - if self.push_to_liquidsoap(media_item, None): - self.logger.debug("Pushed to liquidsoap, updating 'played' status.") - - """ - Temporary solution to make sure we don't push the same track multiple times. Not a full solution because if we - get a new schedule, the key becomes available again. - """ - #TODO - del media[key] - - def date_interval_to_seconds(self, interval): - return (interval.microseconds + (interval.seconds + interval.days * 24 * 3600) * 10**6) / 10**6 - - def push_to_liquidsoap(self, media_item, adjusted_cue_in=None): - """ - This function looks at the media item, and either pushes it to the Liquidsoap - queue immediately, or if the queue is empty - waits until the start time of the - media item before pushing it. - """ - - if adjusted_cue_in is not None: - media_item["cue_in"] = adjusted_cue_in + float(media_item["cue_in"]) - - - try: - if media_item["start"] == self.last_end_time: - """ - this media item is attached to the end of the last - track, so let's push it now so that Liquidsoap can start playing - it immediately after (and prepare crossfades if need be). - """ - self.logger.debug("Push track immediately.") - self.telnet_to_liquidsoap(media_item) - self.last_end_time = media_item["end"] - else: - """ - this media item does not start right after a current playing track. - We need to sleep, and then wake up when this track starts. - """ - self.logger.debug("sleep until track start.") - self.sleep_until_start(media_item) + #TODO + time.sleep(2) - self.telnet_to_liquidsoap(media_item) - self.last_end_time = media_item["end"] - except Exception, e: - self.logger.error('Pypo Push Exception: %s', e) - return False - - return True - - + chains = self.get_all_chains(media_schedule) + next_media_item_chain = self.get_next_schedule_chain(chains) + if next_media_item_chain is not None: + tnow = datetime.utcnow() + chain_start = datetime.strptime(next_media_item_chain[0]['start'], "%Y-%m-%d-%H-%M-%S") + time_until_next_play = self.date_interval_to_seconds(chain_start - tnow) + self.logger.debug("Blocking %s seconds until show start", time_until_next_play) + else: + self.logger.debug("Blocking indefinitely since no show scheduled next") + time_until_next_play = None + + if loops % heartbeat_period == 0: + self.logger.info("heartbeat") + loops = 0 + loops += 1 + def get_queue_items_from_liquidsoap(self): """ This function connects to Liquidsoap to find what media items are in its queue. """ - - try: self.telnet_lock.acquire() tn = telnetlib.Telnet(LS_HOST, LS_PORT) @@ -196,9 +153,8 @@ class PypoPush(Thread): break return liquidsoap_queue_approx - - - def handle_new_media(self, media, liquidsoap_queue_approx): + + def handle_new_media_schedule(self, media_schedule, liquidsoap_queue_approx): """ This function's purpose is to gracefully handle situations where Liquidsoap already has a track in its queue, but the schedule @@ -206,49 +162,132 @@ class PypoPush(Thread): call other functions that will connect to Liquidsoap and alter its queue. """ - - if len(liquidsoap_queue_approx) == 0: - """ - liquidsoap doesn't have anything in its queue, so we have nothing - to worry about. Life is good. - """ - pass - elif len(liquidsoap_queue_approx) == 1: - queue_item_0_start = liquidsoap_queue_approx[0]['start'] - try: - if liquidsoap_queue_approx[0]['id'] != media[queue_item_0_start]['id']: - """ - liquidsoap's queue does not match the schedule we just received from the Airtime server. - The queue is only of length 1 which means the item in the queue is playing. - Need to do source.skip. - - Since only one item, we don't have to worry about the current item ending and us calling - source.skip unintentionally on the next item (there is no next item). - """ - - self.logger.debug("%s from ls does not exist in queue new schedule. Removing" % liquidsoap_queue_approx[0]['id'], media) - self.remove_from_liquidsoap_queue(liquidsoap_queue_approx[0]) - except KeyError, k: - self.logger.debug("%s from ls does not exist in queue schedule: %s Removing" % (queue_item_0_start, media)) - self.remove_from_liquidsoap_queue(liquidsoap_queue_approx[0]) - - - elif len(liquidsoap_queue_approx) == 2: - queue_item_0_start = liquidsoap_queue_approx[0]['start'] - queue_item_1_start = liquidsoap_queue_approx[1]['start'] + + #iterate through the items we got from the liquidsoap queue and + #see if they are the same as the newly received schedule + iteration = 0 + problem_at_iteration = None + for queue_item in liquidsoap_queue_approx: + + if queue_item['start'] in media_schedule.keys(): + if queue_item['id'] == media_schedule[queue_item['start']]['id']: + #Everything OK for this iteration. + pass + else: + #A different item has been scheduled at the same time! Need to remove + #all tracks from the Liquidsoap queue starting at this point, and re-add + #them. + problem_at_iteration = iteration + break + else: + #There are no more items scheduled for this time! The user has shortened + #the playlist, so we simply need to remove tracks from the queue. + problem_at_iteration = iteration + break + iteration+=1 + + + if problem_at_iteration is not None: + #The first item in the Liquidsoap queue (the one that is currently playing) + #has changed or been removed from the schedule. We need to clear the entire + #queue, and push the new schedule + self.logger.debug("Problem at iteration %s", problem_at_iteration) + self.remove_from_liquidsoap_queue(problem_at_iteration, liquidsoap_queue_approx) + + + def get_all_chains(self, media_schedule): + chains = [] + + current_chain = [] + + sorted_keys = sorted(media_schedule.keys()) + + for mkey in sorted_keys: + media_item = media_schedule[mkey] + if len(current_chain) == 0: + current_chain.append(media_item) + elif media_item['start'] == current_chain[-1]['end']: + current_chain.append(media_item) + else: + #current item is not a continuation of the chain. + #Start a new one instead + chains.append(current_chain) + current_chain = [media_item] + + if len(current_chain) > 0: + chains.append(current_chain) - if queue_item_1_start in media.keys(): - if liquidsoap_queue_approx[1]['id'] != media[queue_item_1_start]['id']: - self.remove_from_liquidsoap_queue(liquidsoap_queue_approx[1]) - else: - self.remove_from_liquidsoap_queue(liquidsoap_queue_approx[1]) + return chains + + def modify_cue_point_of_first_link(self, chain): + tnow = datetime.utcnow() + link = chain[0] + + link_start = datetime.strptime(link['start'], "%Y-%m-%d-%H-%M-%S") + + diff_td = tnow - link_start + + self.logger.debug("media item was supposed to start %s ago. Preparing to start..", diff_td) + original_cue_in_td = timedelta(seconds=float(link['cue_in'])) + link['cue_in'] = self.convert_timedelta_to_seconds(original_cue_in_td + diff_td) + + + def convert_timedelta_to_seconds(self, td): + return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6 + + + def get_current_chain(self, chains): + tnow = datetime.utcnow() + current_chain = [] + + + for chain in chains: + iteration = 0 + for link in chain: + link_start = datetime.strptime(link['start'], "%Y-%m-%d-%H-%M-%S") + link_end = datetime.strptime(link['end'], "%Y-%m-%d-%H-%M-%S") - if queue_item_0_start in media.keys(): - if liquidsoap_queue_approx[0]['id'] != media[queue_item_0_start]['id']: - self.remove_from_liquidsoap_queue(liquidsoap_queue_approx[0]) - else: - self.remove_from_liquidsoap_queue(liquidsoap_queue_approx[0]) + self.logger.debug("tnow %s, chain_start %s", tnow, link_start) + if link_start <= tnow and tnow < link_end: + current_chain = chain[iteration:] + break + iteration += 1 + return current_chain + + """ + The purpose of this function is to take a look at the last received schedule from + pypo-fetch and return the next chain of media_items. A chain is defined as a sequence + of media_items where the end time of media_item 'n' is the start time of media_item + 'n+1' + """ + def get_next_schedule_chain(self, chains): + #all media_items are now divided into chains. Let's find the one that + #starts closest in the future. + tnow = datetime.utcnow() + closest_start = None + closest_chain = None + for chain in chains: + chain_start = datetime.strptime(chain[0]['start'], "%Y-%m-%d-%H-%M-%S") + self.logger.debug("tnow %s, chain_start %s", tnow, chain_start) + if (closest_start == None or chain_start < closest_start) and chain_start > tnow: + closest_start = chain_start + closest_chain = chain + + return closest_chain + + + def date_interval_to_seconds(self, interval): + return (interval.microseconds + (interval.seconds + interval.days * 24 * 3600) * 10**6) / 10**6 + + def push_to_liquidsoap(self, media_item_chain): + + try: + for media_item in media_item_chain: + self.telnet_to_liquidsoap(media_item) + except Exception, e: + self.logger.error('Pypo Push Exception: %s', e) + def clear_liquidsoap_queue(self): self.logger.debug("Clearing Liquidsoap queue") try: @@ -263,38 +302,38 @@ class PypoPush(Thread): finally: self.telnet_lock.release() - def remove_from_liquidsoap_queue(self, media_item, do_only_source_skip=False): - if 'queue_id' in media_item: - queue_id = media_item['queue_id'] + def remove_from_liquidsoap_queue(self, problem_at_iteration, liquidsoap_queue_approx): + iteration = 0 + + try: + self.telnet_lock.acquire() + tn = telnetlib.Telnet(LS_HOST, LS_PORT) - - try: - self.telnet_lock.acquire() - tn = telnetlib.Telnet(LS_HOST, LS_PORT) - msg = "queue.remove %s\n" % queue_id - self.logger.debug(msg) - tn.write(msg) - response = tn.read_until("\r\n").strip("\r\n") - - if "No such request in my queue" in response: - """ - Cannot remove because Liquidsoap started playing the item. Need - to use source.skip instead - """ - msg = "source.skip\n" + for queue_item in liquidsoap_queue_approx: + if iteration >= problem_at_iteration: + + msg = "queue.remove %s\n" % queue_item['queue_id'] self.logger.debug(msg) tn.write(msg) + response = tn.read_until("\r\n").strip("\r\n") - tn.write("exit\n") - tn.read_all() - except Exception, e: - self.logger.error(str(e)) - finally: - self.telnet_lock.release() + if "No such request in my queue" in response: + """ + Cannot remove because Liquidsoap started playing the item. Need + to use source.skip instead + """ + msg = "source.skip\n" + self.logger.debug(msg) + tn.write(msg) + iteration += 1 + + tn.write("exit\n") + tn.read_all() + except Exception, e: + self.logger.error(str(e)) + finally: + self.telnet_lock.release() - else: - self.logger.error("'queue_id' key doesn't exist in media_item dict()") - def sleep_until_start(self, media_item): """ The purpose of this function is to look at the difference between @@ -363,14 +402,9 @@ class PypoPush(Thread): % (media['id'], float(media['cue_in']), float(media['cue_out']), media['row_id'], media['dst']) def run(self): - loops = 0 - heartbeat_period = math.floor(30/PUSH_INTERVAL) - - while True: - if loops % heartbeat_period == 0: - self.logger.info("heartbeat") - loops = 0 - try: self.push() - except Exception, e: - self.logger.error('Pypo Push Exception: %s', e) - loops += 1 + try: self.main() + except Exception, e: + import traceback + top = traceback.format_exc() + self.logger.error('Pypo Push Exception: %s', top) +