From 3b51c93766383f73b7193368e21ba1c99708014a Mon Sep 17 00:00:00 2001 From: Rudi Grinberg Date: Mon, 29 Oct 2012 11:25:05 -0400 Subject: [PATCH 1/5] Refactored pyponotify. Removed code duplication and made runner reusable by other scripts. --- python_apps/pypo/pyponotify.py | 61 +++++++++++++--------------------- 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/python_apps/pypo/pyponotify.py b/python_apps/pypo/pyponotify.py index 446da8d49..9c2f1688c 100644 --- a/python_apps/pypo/pyponotify.py +++ b/python_apps/pypo/pyponotify.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import traceback """ Python part of radio playout (pypo) @@ -102,6 +103,24 @@ class Notify: logger.debug('# Calling server to update webstream data #') logger.debug('#################################################') response = self.api_client.notify_webstream_data(data, media_id) + logger.debug("Response: " + json.dumps(response)) + + def run_with_options(self, options): + if options.error and options.stream_id: + self.notify_liquidsoap_status(options.error, options.stream_id, options.time) + elif options.connect and options.stream_id: + self.notify_liquidsoap_status("OK", options.stream_id, options.time) + elif options.source_name and options.source_status: + self.notify_source_status(options.source_name, options.source_status) + elif options.webstream: + self.notify_webstream_data(options.webstream, options.media_id) + elif options.media_id: + self.notify_media_start_playing(options.media_id) + elif options.liquidsoap_started: + self.notify_liquidsoap_started() + else: + logger.debug("Unrecognized option in options(%s). Doing nothing" \ + % str(options)) if __name__ == '__main__': @@ -112,41 +131,9 @@ if __name__ == '__main__': print '#########################################' # initialize - if options.error and options.stream_id: - try: - n = Notify() - n.notify_liquidsoap_status(options.error, options.stream_id, options.time) - except Exception, e: - print e - elif options.connect and options.stream_id: - try: - n = Notify() - n.notify_liquidsoap_status("OK", options.stream_id, options.time) - except Exception, e: - print e - elif options.source_name and options.source_status: - try: - n = Notify() - n.notify_source_status(options.source_name, options.source_status) - except Exception, e: - print e - elif options.webstream: - try: - n = Notify() - n.notify_webstream_data(options.webstream, options.media_id) - except Exception, e: - print e - elif options.media_id: - - try: - n = Notify() - n.notify_media_start_playing(options.media_id) - except Exception, e: - print e - elif options.liquidsoap_started: - try: - n = Notify() - n.notify_liquidsoap_started() - except Exception, e: - print e + try: + n = Notify() + n.run_with_options(options) + except Exception as e: + print( traceback.format_exc() ) From 35a9e77062c5400039ce224d7d01c928162d5163 Mon Sep 17 00:00:00 2001 From: Rudi Grinberg Date: Mon, 29 Oct 2012 11:40:23 -0400 Subject: [PATCH 2/5] Formatted spaces. --- utils/airtime-import/airtime-import.py | 34 +++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/utils/airtime-import/airtime-import.py b/utils/airtime-import/airtime-import.py index 5f1d305ca..408bd91ac 100644 --- a/utils/airtime-import/airtime-import.py +++ b/utils/airtime-import/airtime-import.py @@ -21,7 +21,7 @@ logger.addHandler(ch) if (os.geteuid() != 0): print 'Must be a root user.' sys.exit() - + # loading config file try: config = ConfigObj('/etc/airtime/media-monitor.cfg') @@ -66,12 +66,12 @@ def copy_or_move_files_to(paths, dest, flag): print "Cannot find file or path: %s" % path except Exception as e: print "Error: ", e - + def format_dir_string(path): if(path[-1] != '/'): path = path+'/' return path - + def helper_get_stor_dir(): res = api_client.list_all_watched_dirs() if(res is None): @@ -87,18 +87,18 @@ def checkOtherOption(args): for i in args: if(i[0] == '-'): return True - + def errorIfMultipleOption(args, msg=''): if(checkOtherOption(args)): if(msg != ''): raise OptionValueError(msg) else: raise OptionValueError("This option cannot be combined with other options") - + def printHelp(): storage_dir = helper_get_stor_dir() if(storage_dir is None): - storage_dir = "Unknown" + storage_dir = "Unknown" else: storage_dir += "imported/" print """ @@ -111,15 +111,15 @@ There are two ways to import audio files into Airtime: Copied or moved files will be placed into the folder: %s - + Files will be automatically organized into the structure "Artist/Album/TrackNumber-TrackName-Bitrate.file_extension". 2) Use airtime-import to add a folder to the Airtime library ("watch" a folder). - + All the files in the watched folder will be imported to Airtime and the folder will be monitored to automatically detect any changes. Hence any - changes done in the folder(add, delete, edit a file) will trigger + changes done in the folder(add, delete, edit a file) will trigger updates in Airtime library. """ % storage_dir parser.print_help() @@ -209,7 +209,7 @@ def WatchRemoveAction(option, opt, value, parser): print "Removing the watch folder failed: %s" % res['msg']['error'] else: print "The given path is not a directory: %s" % path - + def StorageSetAction(option, opt, value, parser): bypass = False isF = '-f' in parser.rargs @@ -231,12 +231,12 @@ def StorageSetAction(option, opt, value, parser): confirm = confirm or 'N' if(confirm == 'n' or confirm =='N'): sys.exit(1) - + if(len(parser.rargs) > 1): raise OptionValueError("Too many arguments. This option requires exactly one argument.") elif(len(parser.rargs) == 0 ): raise OptionValueError("No argument found. This option requires exactly one argument.") - + path = parser.rargs[0] if (path[0] == "/" or path[0] == "~"): path = os.path.realpath(path) @@ -254,17 +254,17 @@ def StorageSetAction(option, opt, value, parser): print "Setting storage folder failed: %s" % res['msg']['error'] else: print "The given path is not a directory: %s" % path - + def StorageGetAction(option, opt, value, parser): errorIfMultipleOption(parser.rargs) if(len(parser.rargs) > 0): raise OptionValueError("This option does not take any arguments.") print helper_get_stor_dir() - + class OptionValueError(RuntimeError): def __init__(self, msg): self.msg = msg - + usage = """[-c|--copy FILE/DIR [FILE/DIR...]] [-m|--move FILE/DIR [FILE/DIR...]] [--watch-add DIR] [--watch-list] [--watch-remove DIR] [--storage-dir-set DIR] [--storage-dir-get]""" @@ -293,7 +293,7 @@ if('-h' in sys.argv): if(len(sys.argv) == 1 or '-' not in sys.argv[1]): printHelp() sys.exit() - + try: (option, args) = parser.parse_args() except Exception, e: @@ -306,7 +306,7 @@ except Exception, e: except SystemExit: printHelp() sys.exit() - + if option.help: printHelp() sys.exit() From 31a7b8f94353f4d683276094b3c005eb0003f006 Mon Sep 17 00:00:00 2001 From: Rudi Grinberg Date: Mon, 29 Oct 2012 11:40:41 -0400 Subject: [PATCH 3/5] Removed usesless try catch from send_media_monitor_requests. --- python_apps/api_clients/api_client.py | 85 ++++++++++++--------------- 1 file changed, 39 insertions(+), 46 deletions(-) diff --git a/python_apps/api_clients/api_client.py b/python_apps/api_clients/api_client.py index 130724f66..5b855686a 100644 --- a/python_apps/api_clients/api_client.py +++ b/python_apps/api_clients/api_client.py @@ -422,53 +422,46 @@ class AirtimeApiClient(): def send_media_monitor_requests(self, action_list, dry=False): """ - Send a gang of media monitor events at a time. actions_list is a list - of dictionaries where every dictionary is representing an action. Every - action dict must contain a 'mode' key that says what kind of action it - is and an optional 'is_record' key that says whether the show was - recorded or not. The value of this key does not matter, only if it's - present or not. + Send a gang of media monitor events at a time. actions_list is a + list of dictionaries where every dictionary is representing an + action. Every action dict must contain a 'mode' key that says + what kind of action it is and an optional 'is_record' key that + says whether the show was recorded or not. The value of this key + does not matter, only if it's present or not. """ - logger = self.logger - try: - url = self.construct_url('reload_metadata_group') - # We are assuming that action_list is a list of dictionaries such - # that every dictionary represents the metadata of a file along - # with a special mode key that is the action to be executed by the - # controller. - valid_actions = [] - # We could get a list of valid_actions in a much shorter way using - # filter but here we prefer a little more verbosity to help - # debugging - for action in action_list: - if not 'mode' in action: - self.logger.debug("Warning: Trying to send a request element without a 'mode'") - self.logger.debug("Here is the the request: '%s'" % str(action) ) - else: - # We alias the value of is_record to true or false no - # matter what it is based on if it's absent in the action - if 'is_record' not in action: - action['is_record'] = 0 - valid_actions.append(action) - # Note that we must prefix every key with: mdX where x is a number - # Is there a way to format the next line a little better? The - # parenthesis make the code almost unreadable - md_list = dict((("md%d" % i), json.dumps(convert_dict_value_to_utf8(md))) \ - for i,md in enumerate(valid_actions)) - # For testing we add the following "dry" parameter to tell the - # controller not to actually do any changes - if dry: md_list['dry'] = 1 - self.logger.info("Pumping out %d requests..." % len(valid_actions)) - data = urllib.urlencode(md_list) - req = urllib2.Request(url, data) - response = self.get_response_from_server(req) - response = json.loads(response) - return response - except ValueError: raise - except Exception, e: - logger.error('Exception: %s', e) - logger.error("traceback: %s", traceback.format_exc()) - raise + url = self.construct_url('reload_metadata_group') + # We are assuming that action_list is a list of dictionaries such + # that every dictionary represents the metadata of a file along + # with a special mode key that is the action to be executed by the + # controller. + valid_actions = [] + # We could get a list of valid_actions in a much shorter way using + # filter but here we prefer a little more verbosity to help + # debugging + for action in action_list: + if not 'mode' in action: + self.logger.debug("Warning: Trying to send a request element without a 'mode'") + self.logger.debug("Here is the the request: '%s'" % str(action) ) + else: + # We alias the value of is_record to true or false no + # matter what it is based on if it's absent in the action + if 'is_record' not in action: + action['is_record'] = 0 + valid_actions.append(action) + # Note that we must prefix every key with: mdX where x is a number + # Is there a way to format the next line a little better? The + # parenthesis make the code almost unreadable + md_list = dict((("md%d" % i), json.dumps(convert_dict_value_to_utf8(md))) \ + for i,md in enumerate(valid_actions)) + # For testing we add the following "dry" parameter to tell the + # controller not to actually do any changes + if dry: md_list['dry'] = 1 + self.logger.info("Pumping out %d requests..." % len(valid_actions)) + data = urllib.urlencode(md_list) + req = urllib2.Request(url, data) + response = self.get_response_from_server(req) + response = json.loads(response) + return response #returns a list of all db files for a given directory in JSON format: #{"files":["path/to/file1", "path/to/file2"]} From 3cec987d100b14403ff8eb31dfee9946eaa7011d Mon Sep 17 00:00:00 2001 From: Rudi Grinberg Date: Mon, 29 Oct 2012 11:42:24 -0400 Subject: [PATCH 4/5] Added todo --- python_apps/api_clients/api_client.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python_apps/api_clients/api_client.py b/python_apps/api_clients/api_client.py index 5b855686a..9ef49618d 100644 --- a/python_apps/api_clients/api_client.py +++ b/python_apps/api_clients/api_client.py @@ -20,6 +20,11 @@ import traceback AIRTIME_VERSION = "2.2.0" + +# TODO : Place these functions in some common module. Right now, media +# monitor uses the same functions and it would be better to reuse them +# instead of copy pasting them around + def to_unicode(obj, encoding='utf-8'): if isinstance(obj, basestring): if not isinstance(obj, unicode): From bf5bc3a1166ca19dcc60d35cfe5026851f8209e8 Mon Sep 17 00:00:00 2001 From: Rudi Grinberg Date: Mon, 29 Oct 2012 11:43:39 -0400 Subject: [PATCH 5/5] Changed APC to new-style classes --- python_apps/api_clients/api_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python_apps/api_clients/api_client.py b/python_apps/api_clients/api_client.py index 9ef49618d..5ca176ec2 100644 --- a/python_apps/api_clients/api_client.py +++ b/python_apps/api_clients/api_client.py @@ -44,7 +44,7 @@ def convert_dict_value_to_utf8(md): # Airtime API Client ################################################################################ -class AirtimeApiClient(): +class AirtimeApiClient(object): # This is a little hacky fix so that I don't have to pass the config object # everywhere where AirtimeApiClient needs to be initialized