diff --git a/airtime_mvc/application/models/Schedule.php b/airtime_mvc/application/models/Schedule.php index b668f13e5..58f7bbdba 100644 --- a/airtime_mvc/application/models/Schedule.php +++ b/airtime_mvc/application/models/Schedule.php @@ -268,7 +268,7 @@ SQL; //We need to search 24 hours before and after the show times so that that we - //capture all of the show's contents. + //capture all of the show's contents. $p_track_start= $p_start->sub(new DateInterval("PT24H"))->format("Y-m-d H:i:s"); $p_track_end = $p_end->add(new DateInterval("PT24H"))->format("Y-m-d H:i:s"); @@ -661,6 +661,7 @@ SQL; $data["media"][$switch_start]['start'] = $switch_start; $data["media"][$switch_start]['end'] = $switch_start; $data["media"][$switch_start]['event_type'] = "switch_off"; + $data["media"][$kick_start]['type'] = "event"; $data["media"][$switch_start]['independent_event'] = true; } } diff --git a/airtime_mvc/application/models/Soundcloud.php b/airtime_mvc/application/models/Soundcloud.php index 2b1068e57..70148c05c 100644 --- a/airtime_mvc/application/models/Soundcloud.php +++ b/airtime_mvc/application/models/Soundcloud.php @@ -25,66 +25,67 @@ class Application_Model_Soundcloud public function uploadTrack($filepath, $filename, $description, $tags=array(), $release=null, $genre=null) - { - if ($this->getToken()) { - if (count($tags)) { - $tags = join(" ", $tags); - $tags = $tags." ".Application_Model_Preference::GetSoundCloudTags(); - } else { - $tags = Application_Model_Preference::GetSoundCloudTags(); - } + { - $downloadable = Application_Model_Preference::GetSoundCloudDownloadbleOption() == '1'; - - $track_data = array( - 'track[sharing]' => 'private', - 'track[title]' => $filename, - 'track[asset_data]' => '@' . $filepath, - 'track[tag_list]' => $tags, - 'track[description]' => $description, - 'track[downloadable]' => $downloadable, - - ); - - if (isset($release)) { - $release = str_replace(" ", "-", $release); - $release = str_replace(":", "-", $release); - - //YYYY-MM-DD-HH-mm-SS - $release = explode("-", $release); - $track_data['track[release_year]'] = $release[0]; - $track_data['track[release_month]'] = $release[1]; - $track_data['track[release_day]'] = $release[2]; - } - - if (isset($genre) && $genre != "") { - $track_data['track[genre]'] = $genre; - } else { - $default_genre = Application_Model_Preference::GetSoundCloudGenre(); - if ($default_genre != "") { - $track_data['track[genre]'] = $default_genre; - } - } - - $track_type = Application_Model_Preference::GetSoundCloudTrackType(); - if ($track_type != "") { - $track_data['track[track_type]'] = $track_type; - } - - $license = Application_Model_Preference::GetSoundCloudLicense(); - if ($license != "") { - $track_data['track[license]'] = $license; - } - - $response = json_decode( - $this->_soundcloud->post('tracks', $track_data), - true - ); - - return $response; - } else { + if (!$this->getToken()) { throw new NoSoundCloundToken(); + } + if (count($tags)) { + $tags = join(" ", $tags); + $tags = $tags." ".Application_Model_Preference::GetSoundCloudTags(); + } else { + $tags = Application_Model_Preference::GetSoundCloudTags(); } + + $downloadable = Application_Model_Preference::GetSoundCloudDownloadbleOption() == '1'; + + $track_data = array( + 'track[sharing]' => 'private', + 'track[title]' => $filename, + 'track[asset_data]' => '@' . $filepath, + 'track[tag_list]' => $tags, + 'track[description]' => $description, + 'track[downloadable]' => $downloadable, + + ); + + if (isset($release)) { + $release = str_replace(" ", "-", $release); + $release = str_replace(":", "-", $release); + + //YYYY-MM-DD-HH-mm-SS + $release = explode("-", $release); + $track_data['track[release_year]'] = $release[0]; + $track_data['track[release_month]'] = $release[1]; + $track_data['track[release_day]'] = $release[2]; + } + + if (isset($genre) && $genre != "") { + $track_data['track[genre]'] = $genre; + } else { + $default_genre = Application_Model_Preference::GetSoundCloudGenre(); + if ($default_genre != "") { + $track_data['track[genre]'] = $default_genre; + } + } + + $track_type = Application_Model_Preference::GetSoundCloudTrackType(); + if ($track_type != "") { + $track_data['track[track_type]'] = $track_type; + } + + $license = Application_Model_Preference::GetSoundCloudLicense(); + if ($license != "") { + $track_data['track[license]'] = $license; + } + + $response = json_decode( + $this->_soundcloud->post('tracks', $track_data), + true + ); + + return $response; + } public static function uploadSoundcloud($id) diff --git a/airtime_mvc/application/views/scripts/playlist/update.phtml b/airtime_mvc/application/views/scripts/playlist/update.phtml index 70176ff9e..87cd0662f 100644 --- a/airtime_mvc/application/views/scripts/playlist/update.phtml +++ b/airtime_mvc/application/views/scripts/playlist/update.phtml @@ -92,5 +92,13 @@ if ($item['type'] == 2) { -
  • Empty playlist
  • +
  • +obj instanceof Application_Model_Block) { + echo 'Empty smart block'; + } else { + echo 'Empty playlist'; + } +?> +
  • diff --git a/airtime_mvc/public/js/airtime/showbuilder/builder.js b/airtime_mvc/public/js/airtime/showbuilder/builder.js index fc8463481..21d0b5c43 100644 --- a/airtime_mvc/public/js/airtime/showbuilder/builder.js +++ b/airtime_mvc/public/js/airtime/showbuilder/builder.js @@ -339,11 +339,23 @@ var AIRTIME = (function(AIRTIME){ }); }; + mod.jumpToCurrentTrack = function() { + var $scroll = $sbContent.find(".dataTables_scrolling"); + var scrolled = $scroll.scrollTop(); + var scrollingTop = $scroll.offset().top; + var oTable = $('#show_builder_table').dataTable(); + var current = $sbTable.find("."+NOW_PLAYING_CLASS); + var currentTop = current.offset().top; + + $scroll.scrollTop(currentTop - scrollingTop + scrolled); + } + mod.builderDataTable = function() { $sbContent = $('#show_builder'); $lib = $("#library_content"), $sbTable = $sbContent.find('table'); - + var isInitialized = false; + oSchedTable = $sbTable.dataTable( { "aoColumns": [ /* checkbox */ {"mDataProp": "allowed", "sTitle": "", "sWidth": "15px", "sClass": "sb-checkbox"}, @@ -636,6 +648,13 @@ var AIRTIME = (function(AIRTIME){ $("#draggingContainer").remove(); }, "fnDrawCallback": function fnBuilderDrawCallback(oSettings, json) { + if (!isInitialized) { + if ($(this).find("."+NOW_PLAYING_CLASS).length > 0) { + mod.jumpToCurrentTrack(); + } + } + + isInitialized = true; var wrapperDiv, markerDiv, $td, @@ -1021,7 +1040,7 @@ var AIRTIME = (function(AIRTIME){ if (AIRTIME.button.isDisabled('icon-step-forward', true) === true) { return; } - + /* var $scroll = $sbContent.find(".dataTables_scrolling"), scrolled = $scroll.scrollTop(), scrollingTop = $scroll.offset().top, @@ -1029,6 +1048,8 @@ var AIRTIME = (function(AIRTIME){ currentTop = current.offset().top; $scroll.scrollTop(currentTop - scrollingTop + scrolled); + */ + mod.jumpToCurrentTrack(); }); //delete overbooked tracks. @@ -1196,7 +1217,7 @@ var AIRTIME = (function(AIRTIME){ }; } - }); + }); }; return AIRTIME; diff --git a/airtime_mvc/public/js/airtime/showbuilder/main_builder.js b/airtime_mvc/public/js/airtime/showbuilder/main_builder.js index b640a2882..48e503ac6 100644 --- a/airtime_mvc/public/js/airtime/showbuilder/main_builder.js +++ b/airtime_mvc/public/js/airtime/showbuilder/main_builder.js @@ -113,174 +113,180 @@ AIRTIME = (function(AIRTIME) { } mod.onReady = function() { - //define module vars. - $lib = $("#library_content"); - $builder = $("#show_builder"); - $fs = $builder.find('fieldset'); - - /* - * Icon hover states for search. - */ - $builder.on("mouseenter", ".sb-timerange .ui-button", function(ev) { - $(this).addClass("ui-state-hover"); - }); - $builder.on("mouseleave", ".sb-timerange .ui-button", function(ev) { - $(this).removeClass("ui-state-hover"); - }); - - $builder.find(dateStartId).datepicker(oBaseDatePickerSettings); - $builder.find(timeStartId).timepicker(oBaseTimePickerSettings); - $builder.find(dateEndId).datepicker(oBaseDatePickerSettings); - $builder.find(timeEndId).timepicker(oBaseTimePickerSettings); - - oRange = AIRTIME.utilities.fnGetScheduleRange(dateStartId, timeStartId, dateEndId, timeEndId); - AIRTIME.showbuilder.fnServerData.start = oRange.start; - AIRTIME.showbuilder.fnServerData.end = oRange.end; + // define module vars. + $lib = $("#library_content"); + $builder = $("#show_builder"); + $fs = $builder.find('fieldset'); - AIRTIME.library.libraryInit(); - AIRTIME.showbuilder.builderDataTable(); - setWidgetSize(); - - $libWrapper = $lib.find("#library_display_wrapper"); - $libWrapper.prepend($libClose); - - $builder.find('.dataTables_scrolling').css("max-height", widgetHeight - 95); - - $builder.on("click", "#sb_submit", showSearchSubmit); + /* + * Icon hover states for search. + */ + $builder.on("mouseenter", ".sb-timerange .ui-button", function(ev) { + $(this).addClass("ui-state-hover"); + }); + $builder.on("mouseleave", ".sb-timerange .ui-button", function(ev) { + $(this).removeClass("ui-state-hover"); + }); - $builder.on("click","#sb_edit", function (ev){ - var schedTable = $("#show_builder_table").dataTable(); - - //reset timestamp to redraw the cursors. - AIRTIME.showbuilder.resetTimestamp(); - - $lib.show() - .width(Math.floor(screenWidth * 0.48)); - - $builder.width(Math.floor(screenWidth * 0.48)) - .find("#sb_edit") - .remove() - .end() - .find("#sb_date_start") - .css("margin-left", 0) - .end(); - - schedTable.fnDraw(); - - $.ajax({ - url: "/usersettings/set-now-playing-screen-settings", - type: "POST", - data: {settings : {library : true}, format: "json"}, - dataType: "json", - success: function(){} - }); - }); - - $lib.on("click", "#sb_lib_close", function() { - var schedTable = $("#show_builder_table").dataTable(); + $builder.find(dateStartId).datepicker(oBaseDatePickerSettings); + $builder.find(timeStartId).timepicker(oBaseTimePickerSettings); + $builder.find(dateEndId).datepicker(oBaseDatePickerSettings); + $builder.find(timeEndId).timepicker(oBaseTimePickerSettings); + + oRange = AIRTIME.utilities.fnGetScheduleRange(dateStartId, timeStartId, + dateEndId, timeEndId); + AIRTIME.showbuilder.fnServerData.start = oRange.start; + AIRTIME.showbuilder.fnServerData.end = oRange.end; + + AIRTIME.library.libraryInit(); + AIRTIME.showbuilder.builderDataTable(); + setWidgetSize(); + + $libWrapper = $lib.find("#library_display_wrapper"); + $libWrapper.prepend($libClose); + + $builder.find('.dataTables_scrolling').css("max-height", + widgetHeight - 95); + + $builder.on("click", "#sb_submit", showSearchSubmit); + + $builder.on("click", "#sb_edit", function(ev) { + var schedTable = $("#show_builder_table").dataTable(); + + // reset timestamp to redraw the cursors. + AIRTIME.showbuilder.resetTimestamp(); + + $lib.show().width(Math.floor(screenWidth * 0.48)); + + $builder.width(Math.floor(screenWidth * 0.48)).find("#sb_edit") + .remove().end().find("#sb_date_start") + .css("margin-left", 0).end(); + + schedTable.fnDraw(); + + $.ajax( { + url : "/usersettings/set-now-playing-screen-settings", + type : "POST", + data : { + settings : { + library : true + }, + format : "json" + }, + dataType : "json", + success : function() { + } + }); + }); + + $lib.on("click", "#sb_lib_close", function() { + var schedTable = $("#show_builder_table").dataTable(); + + $lib.hide(); + $builder.width(screenWidth).find(".sb-timerange").prepend( + $toggleLib).find("#sb_date_start").css("margin-left", 30) + .end().end(); + + $toggleLib.removeClass("ui-state-hover"); + schedTable.fnDraw(); + + $.ajax( { + url : "/usersettings/set-now-playing-screen-settings", + type : "POST", + data : { + settings : { + library : false + }, + format : "json" + }, + dataType : "json", + success : function() { + } + }); + }); + + $builder.find('legend').click( + function(ev, item) { + + if ($fs.hasClass("closed")) { + + $fs.removeClass("closed"); + $builder.find('.dataTables_scrolling').css( + "max-height", widgetHeight - 150); + } else { + $fs.addClass("closed"); + + // set defaults for the options. + $fs.find('select').val(0); + $fs.find('input[type="checkbox"]').attr("checked", + false); + $builder.find('.dataTables_scrolling').css( + "max-height", widgetHeight - 110); + } + }); + + // set click event for all my shows checkbox. + $builder.on("click", "#sb_my_shows", function(ev) { + + if ($(this).is(':checked')) { + $(ev.delegateTarget).find('#sb_show_filter').val(0); + } + + showSearchSubmit(); + }); + + //set select event for choosing a show. + $builder.on("change", '#sb_show_filter', function(ev) { + + if ($(this).val() !== 0) { + $(ev.delegateTarget).find('#sb_my_shows') + .attr("checked", false); + } + + showSearchSubmit(); + + }); + + function checkScheduleUpdates() { + var data = {}, oTable = $('#show_builder_table').dataTable(), fn = oTable + .fnSettings().fnServerData, start = fn.start, end = fn.end; + + data["format"] = "json"; + data["start"] = start; + data["end"] = end; + data["timestamp"] = AIRTIME.showbuilder.getTimestamp(); + data["instances"] = AIRTIME.showbuilder.getShowInstances(); + + if (fn.hasOwnProperty("ops")) { + data["myShows"] = fn.ops.myShows; + data["showFilter"] = fn.ops.showFilter; + } + + $.ajax( { + "dataType" : "json", + "type" : "GET", + "url" : "/showbuilder/check-builder-feed", + "data" : data, + "success" : function(json) { + if (json.update === true) { + oTable.fnDraw(); + } + } + }); + } + + //check if the timeline view needs updating. + setInterval(checkScheduleUpdates, 5 * 1000); //need refresh in milliseconds + }; + + mod.onResize = function() { + + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(setWidgetSize, 100); + }; + + return AIRTIME; - $lib.hide(); - $builder.width(screenWidth) - .find(".sb-timerange") - .prepend($toggleLib) - .find("#sb_date_start") - .css("margin-left", 30) - .end() - .end(); - - $toggleLib.removeClass("ui-state-hover"); - schedTable.fnDraw(); - - $.ajax({ - url: "/usersettings/set-now-playing-screen-settings", - type: "POST", - data: {settings : {library : false}, format: "json"}, - dataType: "json", - success: function(){} - }); - }); - - $builder.find('legend').click(function(ev, item){ - - if ($fs.hasClass("closed")) { - - $fs.removeClass("closed"); - $builder.find('.dataTables_scrolling').css("max-height", widgetHeight - 150); - } - else { - $fs.addClass("closed"); - - //set defaults for the options. - $fs.find('select').val(0); - $fs.find('input[type="checkbox"]').attr("checked", false); - $builder.find('.dataTables_scrolling').css("max-height", widgetHeight - 110); - } - }); - - //set click event for all my shows checkbox. - $builder.on("click", "#sb_my_shows", function(ev) { - - if ($(this).is(':checked')) { - $(ev.delegateTarget).find('#sb_show_filter').val(0); - } - - showSearchSubmit(); - }); - - //set select event for choosing a show. - $builder.on("change", '#sb_show_filter', function(ev) { - - if ($(this).val() !== 0) { - $(ev.delegateTarget).find('#sb_my_shows').attr("checked", false); - } - - showSearchSubmit(); - - }); - - function checkScheduleUpdates(){ - var data = {}, - oTable = $('#show_builder_table').dataTable(), - fn = oTable.fnSettings().fnServerData, - start = fn.start, - end = fn.end; - - data["format"] = "json"; - data["start"] = start; - data["end"] = end; - data["timestamp"] = AIRTIME.showbuilder.getTimestamp(); - data["instances"] = AIRTIME.showbuilder.getShowInstances(); - - if (fn.hasOwnProperty("ops")) { - data["myShows"] = fn.ops.myShows; - data["showFilter"] = fn.ops.showFilter; - } - - $.ajax( { - "dataType": "json", - "type": "GET", - "url": "/showbuilder/check-builder-feed", - "data": data, - "success": function(json) { - if (json.update === true) { - oTable.fnDraw(); - } - } - } ); - } - - //check if the timeline view needs updating. - setInterval(checkScheduleUpdates, 5 * 1000); //need refresh in milliseconds - }; - - mod.onResize = function() { - - clearTimeout(resizeTimeout); - resizeTimeout = setTimeout(setWidgetSize, 100); - }; - - return AIRTIME; - } (AIRTIME || {})); $(document).ready(AIRTIME.builderMain.onReady); diff --git a/python_apps/api_clients/api_client.py b/python_apps/api_clients/api_client.py index 130724f66..5ca176ec2 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): @@ -39,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 @@ -422,53 +427,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"]} 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() ) 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()