Merge branch 'devel' of dev.sourcefabric.org:airtime into devel

This commit is contained in:
James 2012-03-26 15:09:56 -04:00
commit 375be99fbd
4 changed files with 282 additions and 300 deletions

View File

@ -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");
}
}

View File

@ -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;

View File

@ -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();

View File

@ -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)