From 1c865fc3f1fde380171b331044ed599c9faf59f6 Mon Sep 17 00:00:00 2001 From: Rudi Grinberg Date: Fri, 17 Aug 2012 15:08:11 -0400 Subject: [PATCH 1/6] cc-4232: fixed some tests --- .../media-monitor2/media/monitor/metadata.py | 10 ++++++---- python_apps/media-monitor2/media/monitor/pure.py | 16 +++++++--------- python_apps/media-monitor2/tests/test_pure.py | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/python_apps/media-monitor2/media/monitor/metadata.py b/python_apps/media-monitor2/media/monitor/metadata.py index 931ab52da..a8c982b9a 100644 --- a/python_apps/media-monitor2/media/monitor/metadata.py +++ b/python_apps/media-monitor2/media/monitor/metadata.py @@ -121,10 +121,10 @@ class Metadata(Loggable): def __init__(self, fpath): # Forcing the unicode through - try: fpath = fpath.decode("utf-8") - except: pass - try: full_mutagen = mutagen.File(fpath, easy=True) - except Exception: raise BadSongFile(fpath) + try : fpath = fpath.decode("utf-8") + except : pass + try : full_mutagen = mutagen.File(fpath, easy=True) + except Exception : raise BadSongFile(fpath) self.path = fpath # TODO : Simplify the way all of these rules are handled right not it's # extremely unclear and needs to be refactored. @@ -162,6 +162,8 @@ class Metadata(Loggable): # Finally, we "normalize" all the metadata here: self.__metadata = mmp.normalized_metadata(self.__metadata, fpath) # Now we must load the md5: + # TODO : perhaps we shouldn't hard code how many bytes we're reading + # from the file? self.__metadata['MDATA_KEY_MD5'] = mmp.file_md5(fpath,max_length=100) def is_recorded(self): diff --git a/python_apps/media-monitor2/media/monitor/pure.py b/python_apps/media-monitor2/media/monitor/pure.py index 30742c236..1cf75544f 100644 --- a/python_apps/media-monitor2/media/monitor/pure.py +++ b/python_apps/media-monitor2/media/monitor/pure.py @@ -163,11 +163,13 @@ def apply_rules_dict(d, rules): """ Consumes a dictionary of rules that maps some keys to lambdas which it applies to every matching element in d and returns a new dictionary with - the rules applied + the rules applied. If a rule returns none then it's not applied """ new_d = copy.deepcopy(d) for k, rule in rules.iteritems(): - if k in d: new_d[k] = rule(d[k]) + if k in d: + new_val = rule(d[k]) + if new_val is not None: new_d[k] = new_val return new_d def default_to_f(dictionary, keys, default, condition): @@ -183,10 +185,6 @@ def default_to(dictionary, keys, default): """ cnd = lambda dictionary, key: key not in dictionary return default_to_f(dictionary, keys, default, cnd) - #new_d = copy.deepcopy(dictionary) - #for k in keys: - #if not (k in new_d): new_d[k] = default - #return new_d def remove_whitespace(dictionary): """ @@ -205,18 +203,18 @@ def remove_whitespace(dictionary): def parse_int(s): """ Tries very hard to get some sort of integer result from s. Defaults to 0 - when it failes + when it fails >>> parse_int("123") '123' >>> parse_int("123saf") '123' >>> parse_int("asdf") - '' + nothing """ if s.isdigit(): return s else: try : return str(reduce(op.add, takewhile(lambda x: x.isdigit(), s))) - except: return '' + except: return None def normalized_metadata(md, original_path): """ diff --git a/python_apps/media-monitor2/tests/test_pure.py b/python_apps/media-monitor2/tests/test_pure.py index 81918fd10..611c42f60 100644 --- a/python_apps/media-monitor2/tests/test_pure.py +++ b/python_apps/media-monitor2/tests/test_pure.py @@ -48,7 +48,7 @@ class TestMMP(unittest.TestCase): real_path1 = \ u'/home/rudi/throwaway/fucking_around/watch/unknown/unknown/ACDC_-_Back_In_Black-sample-64kbps-64kbps.ogg' self.assertTrue( 'unknown' in og, True ) - self.assertEqual( og, real_path1 ) + self.assertEqual( og, real_path1 ) # TODO : fix this failure # for recorded it should be something like this # ./recorded/2012/07/2012-07-09-17-55-00-Untitled Show-256kbps.ogg @@ -70,6 +70,6 @@ class TestMMP(unittest.TestCase): def test_parse_int(self): self.assertEqual( mmp.parse_int("123"), "123" ) self.assertEqual( mmp.parse_int("123asf"), "123" ) - self.assertEqual( mmp.parse_int("asdf"), "" ) + self.assertEqual( mmp.parse_int("asdf"), None ) if __name__ == '__main__': unittest.main() From efa4b12e3a41f99d654e40a3f58d011451a3ca70 Mon Sep 17 00:00:00 2001 From: Rudi Grinberg Date: Fri, 17 Aug 2012 15:18:40 -0400 Subject: [PATCH 2/6] cc-4232: fixed typo in doctest --- python_apps/media-monitor2/media/monitor/pure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python_apps/media-monitor2/media/monitor/pure.py b/python_apps/media-monitor2/media/monitor/pure.py index 1cf75544f..1836dc77f 100644 --- a/python_apps/media-monitor2/media/monitor/pure.py +++ b/python_apps/media-monitor2/media/monitor/pure.py @@ -209,7 +209,7 @@ def parse_int(s): >>> parse_int("123saf") '123' >>> parse_int("asdf") - nothing + None """ if s.isdigit(): return s else: From ecd7fe75768425a83482dececedf7e511389b3d0 Mon Sep 17 00:00:00 2001 From: Rudi Grinberg Date: Fri, 17 Aug 2012 15:36:33 -0400 Subject: [PATCH 3/6] cc-4232: fix this issue --- python_apps/media-monitor2/media/monitor/pure.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python_apps/media-monitor2/media/monitor/pure.py b/python_apps/media-monitor2/media/monitor/pure.py index 1836dc77f..70136f730 100644 --- a/python_apps/media-monitor2/media/monitor/pure.py +++ b/python_apps/media-monitor2/media/monitor/pure.py @@ -238,7 +238,8 @@ def normalized_metadata(md, original_path): new_md = apply_rules_dict(new_md, format_rules) new_md = default_to(dictionary=new_md, keys=['MDATA_KEY_TITLE'], default=no_extension_basename(original_path)) - new_md = default_to(dictionary=new_md, keys=path_md, default=u'') + new_md = default_to(dictionary=new_md, keys=['MDATA_KEY_CREATOR', + 'MDATA_KEY_SOURCE'], default=u'') new_md = default_to(dictionary=new_md, keys=['MDATA_KEY_FTYPE'], default=u'audioclip') # In the case where the creator is 'Airtime Show Recorder' we would like to From a08b31dd39d8d5a0e1edeb6f98d52fdcfda24707 Mon Sep 17 00:00:00 2001 From: Martin Konecny Date: Fri, 17 Aug 2012 15:38:24 -0400 Subject: [PATCH 4/6] CC-1665: Scheduled stream rebroadcasting and recording -ability to schedule streams without a 5 second pre-buffer --- python_apps/pypo/pypofetch.py | 5 ++++- python_apps/pypo/pypopush.py | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/python_apps/pypo/pypofetch.py b/python_apps/pypo/pypofetch.py index ed8189dd2..e6019ac53 100644 --- a/python_apps/pypo/pypofetch.py +++ b/python_apps/pypo/pypofetch.py @@ -430,12 +430,15 @@ class PypoFetch(Thread): u'cue_in': 0, u'start': u'2012-07-26-04-00-00', u'replay_gain': u'0', u'row_id': 16, u'cue_out': 300, u'type': u'stream', u'id': 1, u'fade_in': 500} """ - if(media_item['type'] == 'file'): + if (media_item['type'] == 'file'): fileExt = os.path.splitext(media_item['uri'])[1] dst = os.path.join(download_dir, unicode(media_item['id']) + fileExt) media_item['dst'] = dst media_item['file_ready'] = False media_filtered[key] = media_item + else if media_item['type'] == 'stream': + #flag to indicate whether the stream started prebuffering + media_item['prebuffer_start'] = False self.media_prepare_queue.put(copy.copy(media_filtered)) except Exception, e: self.logger.error("%s", e) diff --git a/python_apps/pypo/pypopush.py b/python_apps/pypo/pypopush.py index b04c60d82..a58fb4fcf 100644 --- a/python_apps/pypo/pypopush.py +++ b/python_apps/pypo/pypopush.py @@ -389,12 +389,17 @@ class PypoPush(Thread): elif media_item['type'] == 'stream_buffer_start': self.start_web_stream_buffer(media_item) elif media_item['type'] == "stream": + if not media_item['prebuffer_started']: + #this is called if the stream wasn't scheduled sufficiently ahead of time + #so that the prebuffering stage could take effect. Let's do the prebuffering now. + self.start_web_stream_buffer(media_item) self.start_web_stream(media_item) elif media_item['type'] == "stream_end": self.stop_web_stream(media_item) except Exception, e: self.logger.error('Pypo Push Exception: %s', e) + def start_web_stream_buffer(self, media_item): try: self.telnet_lock.acquire() @@ -410,6 +415,8 @@ class PypoPush(Thread): tn.write("exit\n") self.logger.debug(tn.read_all()) + + media_item['prebuffer_started'] = True except Exception, e: self.logger.error(str(e)) finally: @@ -425,6 +432,8 @@ class PypoPush(Thread): msg = 'streams.scheduled_play_start\n' tn.write(msg) + + msg = 'dynamic_source.output_start\n' self.logger.debug(msg) tn.write(msg) From e2425dd22f452fc74a86441b99924cf850da8f02 Mon Sep 17 00:00:00 2001 From: Martin Konecny Date: Fri, 17 Aug 2012 15:38:40 -0400 Subject: [PATCH 5/6] EOL vim fixes --- python_apps/pypo/pypofetch.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/python_apps/pypo/pypofetch.py b/python_apps/pypo/pypofetch.py index e6019ac53..079efe1f5 100644 --- a/python_apps/pypo/pypofetch.py +++ b/python_apps/pypo/pypofetch.py @@ -58,7 +58,7 @@ class PypoFetch(Thread): if not os.path.isdir(dir): """ We get here if path does not exist, or path does exist but - is a file. We are not handling the second case, but don't + is a file. We are not handling the second case, but don't think we actually care about handling it. """ self.logger.debug("Cache dir does not exist. Creating...") @@ -426,8 +426,8 @@ class PypoFetch(Thread): for key in media: media_item = media[key] """ - {u'end': u'2012-07-26-04-05-00', u'fade_out': 500, u'show_name': u'Untitled Show', u'uri': u'http://', - u'cue_in': 0, u'start': u'2012-07-26-04-00-00', u'replay_gain': u'0', u'row_id': 16, u'cue_out': 300, u'type': + {u'end': u'2012-07-26-04-05-00', u'fade_out': 500, u'show_name': u'Untitled Show', u'uri': u'http://', + u'cue_in': 0, u'start': u'2012-07-26-04-00-00', u'replay_gain': u'0', u'row_id': 16, u'cue_out': 300, u'type': u'stream', u'id': 1, u'fade_in': 500} """ if (media_item['type'] == 'file'): @@ -456,7 +456,7 @@ class PypoFetch(Thread): """ Get list of all files in the cache dir and remove them if they aren't being used anymore. Input dict() media, lists all files that are scheduled or currently playing. Not being in this - dict() means the file is safe to remove. + dict() means the file is safe to remove. """ cached_file_set = set(os.listdir(self.cache_dir)) scheduled_file_set = set() @@ -479,7 +479,7 @@ class PypoFetch(Thread): def main(self): # Bootstrap: since we are just starting up, we need to grab the - # most recent schedule. After that we can just wait for updates. + # most recent schedule. After that we can just wait for updates. success, self.schedule_data = self.api_client.get_schedule() if success: self.logger.info("Bootstrap schedule received: %s", self.schedule_data) @@ -493,14 +493,14 @@ class PypoFetch(Thread): """ our simple_queue.get() requires a timeout, in which case we fetch the Airtime schedule manually. It is important to fetch - the schedule periodically because if we didn't, we would only - get schedule updates via RabbitMq if the user was constantly - using the Airtime interface. - + the schedule periodically because if we didn't, we would only + get schedule updates via RabbitMq if the user was constantly + using the Airtime interface. + If the user is not using the interface, RabbitMq messages are not - sent, and we will have very stale (or non-existent!) data about the + sent, and we will have very stale (or non-existent!) data about the schedule. - + Currently we are checking every POLL_INTERVAL seconds """ From 86c0b7db376731db095923d3e23b1e13fb9d4b1f Mon Sep 17 00:00:00 2001 From: Martin Konecny Date: Fri, 17 Aug 2012 15:55:28 -0400 Subject: [PATCH 6/6] CC-1665: Scheduled stream rebroadcasting and recording -fix syntax error --- python_apps/pypo/pypofetch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python_apps/pypo/pypofetch.py b/python_apps/pypo/pypofetch.py index 079efe1f5..d2eb695b6 100644 --- a/python_apps/pypo/pypofetch.py +++ b/python_apps/pypo/pypofetch.py @@ -436,9 +436,9 @@ class PypoFetch(Thread): media_item['dst'] = dst media_item['file_ready'] = False media_filtered[key] = media_item - else if media_item['type'] == 'stream': + elif media_item['type'] == 'stream': #flag to indicate whether the stream started prebuffering - media_item['prebuffer_start'] = False + media_item['prebuffer_started'] = False self.media_prepare_queue.put(copy.copy(media_filtered)) except Exception, e: self.logger.error("%s", e)