Merge branch '2.2.x' of dev.sourcefabric.org:airtime into 2.2.x
This commit is contained in:
commit
02d02cd460
|
@ -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"]}
|
||||
|
|
|
@ -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() )
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue