Merge branch 'devel' into mediamonitor2
Conflicts: python_apps/api_clients/api_client.py
This commit is contained in:
commit
20e32b98ba
31 changed files with 253 additions and 143 deletions
|
@ -39,7 +39,7 @@ def convert_dict_value_to_utf8(md):
|
|||
# Airtime API Client
|
||||
################################################################################
|
||||
|
||||
class AirTimeApiClient():
|
||||
class AirtimeApiClient():
|
||||
|
||||
def __init__(self, logger=None):
|
||||
if logger is None:
|
||||
|
@ -437,10 +437,14 @@ class AirTimeApiClient():
|
|||
response = self.get_response_from_server(url)
|
||||
response = json.loads(response)
|
||||
except Exception, e:
|
||||
response = None
|
||||
response = {}
|
||||
logger.error("Exception: %s", e)
|
||||
|
||||
return response
|
||||
try:
|
||||
return response["files"]
|
||||
except KeyError:
|
||||
self.logger.error("Could not find index 'files' in dictionary: %s", str(response))
|
||||
return []
|
||||
|
||||
def list_all_watched_dirs(self):
|
||||
logger = self.logger
|
||||
|
|
|
@ -40,8 +40,7 @@ class AirtimeMediaMonitorBootstrap():
|
|||
went offline.
|
||||
"""
|
||||
def scan(self):
|
||||
directories = self.get_list_of_watched_dirs();
|
||||
|
||||
directories = self.get_list_of_watched_dirs()
|
||||
self.logger.info("watched directories found: %s", directories)
|
||||
|
||||
for id, dir in directories.iteritems():
|
||||
|
@ -57,12 +56,21 @@ class AirtimeMediaMonitorBootstrap():
|
|||
return self.api_client.list_all_db_files(dir_id)
|
||||
|
||||
"""
|
||||
returns the path and the database row id for this path for all watched directories. Also
|
||||
returns the path and its corresponding database row idfor all watched directories. Also
|
||||
returns the Stor directory, which can be identified by its row id (always has value of "1")
|
||||
|
||||
Return type is a dictionary similar to:
|
||||
{"1":"/srv/airtime/stor/"}
|
||||
"""
|
||||
def get_list_of_watched_dirs(self):
|
||||
json = self.api_client.list_all_watched_dirs()
|
||||
return json["dirs"]
|
||||
|
||||
try:
|
||||
return json["dirs"]
|
||||
except KeyError as e:
|
||||
self.logger.error("Could not find index 'dirs' in dictionary: %s", str(json))
|
||||
self.logger.error(e)
|
||||
return {}
|
||||
|
||||
"""
|
||||
This function takes in a path name provided by the database (and its corresponding row id)
|
||||
|
@ -86,8 +94,9 @@ class AirtimeMediaMonitorBootstrap():
|
|||
|
||||
db_known_files_set = set()
|
||||
files = self.list_db_files(dir_id)
|
||||
for file in files['files']:
|
||||
db_known_files_set.add(file)
|
||||
|
||||
for f in files:
|
||||
db_known_files_set.add(f)
|
||||
|
||||
all_files = self.mmc.clean_dirty_file_paths( self.mmc.scan_dir_for_new_files(dir) )
|
||||
|
||||
|
@ -111,10 +120,9 @@ class AirtimeMediaMonitorBootstrap():
|
|||
stdout = self.mmc.exec_command(command)
|
||||
|
||||
if stdout is None:
|
||||
self.logger.error("Unrecoverable error when syncing db to filesystem.")
|
||||
return
|
||||
|
||||
new_files = self.mmc.clean_dirty_file_paths(stdout.splitlines())
|
||||
new_files = []
|
||||
else:
|
||||
new_files = stdout.splitlines()
|
||||
|
||||
new_and_modified_files = set()
|
||||
for file_path in new_files:
|
||||
|
|
|
@ -12,8 +12,17 @@ import traceback
|
|||
|
||||
"""
|
||||
list of supported easy tags in mutagen version 1.20
|
||||
['albumartistsort', 'musicbrainz_albumstatus', 'lyricist', 'releasecountry', 'date', 'performer', 'musicbrainz_albumartistid', 'composer', 'encodedby', 'tracknumber', 'musicbrainz_albumid', 'album', 'asin', 'musicbrainz_artistid', 'mood', 'copyright', 'author', 'media', 'length', 'version', 'artistsort', 'titlesort', 'discsubtitle', 'website', 'musicip_fingerprint', 'conductor', 'compilation', 'barcode', 'performer:*', 'composersort', 'musicbrainz_discid', 'musicbrainz_albumtype', 'genre', 'isrc', 'discnumber', 'musicbrainz_trmid', 'replaygain_*_gain', 'musicip_puid', 'artist', 'title', 'bpm', 'musicbrainz_trackid', 'arranger', 'albumsort', 'replaygain_*_peak', 'organization']
|
||||
['albumartistsort', 'musicbrainz_albumstatus', 'lyricist', 'releasecountry',
|
||||
'date', 'performer', 'musicbrainz_albumartistid', 'composer', 'encodedby',
|
||||
'tracknumber', 'musicbrainz_albumid', 'album', 'asin', 'musicbrainz_artistid',
|
||||
'mood', 'copyright', 'author', 'media', 'length', 'version', 'artistsort',
|
||||
'titlesort', 'discsubtitle', 'website', 'musicip_fingerprint', 'conductor',
|
||||
'compilation', 'barcode', 'performer:*', 'composersort', 'musicbrainz_discid',
|
||||
'musicbrainz_albumtype', 'genre', 'isrc', 'discnumber', 'musicbrainz_trmid',
|
||||
'replaygain_*_gain', 'musicip_puid', 'artist', 'title', 'bpm', 'musicbrainz_trackid',
|
||||
'arranger', 'albumsort', 'replaygain_*_peak', 'organization']
|
||||
"""
|
||||
|
||||
class AirtimeMetadata:
|
||||
|
||||
def __init__(self):
|
||||
|
@ -57,10 +66,17 @@ class AirtimeMetadata:
|
|||
self.logger = logging.getLogger()
|
||||
|
||||
def get_md5(self, filepath):
|
||||
f = open(filepath, 'rb')
|
||||
m = hashlib.md5()
|
||||
m.update(f.read())
|
||||
md5 = m.hexdigest()
|
||||
"""
|
||||
Returns an md5 of the file located at filepath. Returns an empty string
|
||||
if there was an error reading the file.
|
||||
"""
|
||||
try:
|
||||
f = open(filepath, 'rb')
|
||||
m = hashlib.md5()
|
||||
m.update(f.read())
|
||||
md5 = m.hexdigest()
|
||||
except Exception, e:
|
||||
return ""
|
||||
|
||||
return md5
|
||||
|
||||
|
@ -121,6 +137,10 @@ class AirtimeMetadata:
|
|||
return item
|
||||
|
||||
def get_md_from_file(self, filepath):
|
||||
"""
|
||||
Returns None if error retrieving metadata. Otherwise returns a dictionary
|
||||
representing the file's metadata
|
||||
"""
|
||||
|
||||
self.logger.info("getting info from filepath %s", filepath)
|
||||
|
||||
|
@ -136,7 +156,6 @@ class AirtimeMetadata:
|
|||
md['MDATA_KEY_MD5'] = md5
|
||||
|
||||
file_info = mutagen.File(filepath, easy=True)
|
||||
|
||||
except Exception, e:
|
||||
self.logger.error("failed getting metadata from %s", filepath)
|
||||
self.logger.error("Exception %s", e)
|
||||
|
@ -146,18 +165,16 @@ class AirtimeMetadata:
|
|||
#check if file has any metadata
|
||||
if file_info is None:
|
||||
return None
|
||||
#check if file has any metadata
|
||||
if file_info is not None:
|
||||
for key in file_info.keys() :
|
||||
if key in self.mutagen2airtime:
|
||||
val = file_info[key]
|
||||
try:
|
||||
if val is not None and len(val) > 0 and val[0] is not None and len(val[0]) > 0:
|
||||
md[self.mutagen2airtime[key]] = val[0]
|
||||
except Exception, e:
|
||||
self.logger.error('Exception: %s', e)
|
||||
self.logger.error("traceback: %s", traceback.format_exc())
|
||||
|
||||
for key in file_info.keys() :
|
||||
if key in self.mutagen2airtime:
|
||||
val = file_info[key]
|
||||
try:
|
||||
if val is not None and len(val) > 0 and val[0] is not None and len(val[0]) > 0:
|
||||
md[self.mutagen2airtime[key]] = val[0]
|
||||
except Exception, e:
|
||||
self.logger.error('Exception: %s', e)
|
||||
self.logger.error("traceback: %s", traceback.format_exc())
|
||||
if 'MDATA_KEY_TITLE' not in md:
|
||||
#get rid of file extension from original name, name might have more than 1 '.' in it.
|
||||
original_name = os.path.basename(filepath)
|
||||
|
@ -228,18 +245,24 @@ class AirtimeMetadata:
|
|||
md['MDATA_KEY_COPYRIGHT'] = self.truncate_to_length(md['MDATA_KEY_COPYRIGHT'], 512)
|
||||
#end of db truncation checks.
|
||||
|
||||
md['MDATA_KEY_BITRATE'] = getattr(file_info.info, "bitrate", None)
|
||||
md['MDATA_KEY_SAMPLERATE'] = getattr(file_info.info, "sample_rate", None)
|
||||
self.logger.info("Bitrate: %s , Samplerate: %s", md['MDATA_KEY_BITRATE'], md['MDATA_KEY_SAMPLERATE'])
|
||||
try: md['MDATA_KEY_DURATION'] = self.format_length(file_info.info.length)
|
||||
except Exception as e: self.logger.warn("File: '%s' raises: %s", filepath, str(e))
|
||||
|
||||
try: md['MDATA_KEY_MIME'] = file_info.mime[0]
|
||||
except Exception as e: self.logger.warn("File: '%s' has no mime type", filepath, str(e))
|
||||
try:
|
||||
md['MDATA_KEY_BITRATE'] = getattr(file_info.info, "bitrate", 0)
|
||||
md['MDATA_KEY_SAMPLERATE'] = getattr(file_info.info, "sample_rate", 0)
|
||||
|
||||
md['MDATA_KEY_DURATION'] = self.format_length(getattr(file_info.info, "length", 0.0))
|
||||
|
||||
md['MDATA_KEY_MIME'] = ""
|
||||
if len(file_info.mime) > 0:
|
||||
md['MDATA_KEY_MIME'] = file_info.mime[0]
|
||||
except Exception as e:
|
||||
self.logger.warn(e)
|
||||
|
||||
if "mp3" in md['MDATA_KEY_MIME']:
|
||||
md['MDATA_KEY_FTYPE'] = "audioclip"
|
||||
elif "vorbis" in md['MDATA_KEY_MIME']:
|
||||
md['MDATA_KEY_FTYPE'] = "audioclip"
|
||||
else:
|
||||
self.logger.error("File %s of mime type %s does not appear to be a valid vorbis or mp3 file." % (filepath, md['MDATA_KEY_MIME']))
|
||||
return None
|
||||
|
||||
return md
|
||||
|
|
|
@ -36,6 +36,11 @@ class AirtimeNotifier(Notifier):
|
|||
time.sleep(5)
|
||||
|
||||
def init_rabbit_mq(self):
|
||||
"""
|
||||
This function will attempt to connect to RabbitMQ Server and if successful
|
||||
return 'True'. Returns 'False' otherwise.
|
||||
"""
|
||||
|
||||
self.logger.info("Initializing RabbitMQ stuff")
|
||||
try:
|
||||
schedule_exchange = Exchange("airtime-media-monitor", "direct", durable=True, auto_delete=True)
|
||||
|
|
|
@ -291,7 +291,10 @@ class MediaMonitorCommon:
|
|||
self.logger.debug(command)
|
||||
stdout = self.exec_command(command)
|
||||
|
||||
return stdout.splitlines()
|
||||
if stdout is None:
|
||||
return []
|
||||
else:
|
||||
return stdout.splitlines()
|
||||
|
||||
def touch_index_file(self):
|
||||
dirname = os.path.dirname(self.timestamp_file)
|
||||
|
|
|
@ -80,7 +80,7 @@ try:
|
|||
configure_locale()
|
||||
|
||||
config = AirtimeMediaConfig(logger)
|
||||
api_client = apc.AirTimeApiClient()
|
||||
api_client = apc.AirtimeApiClient()
|
||||
api_client.register_component("media-monitor")
|
||||
|
||||
logger.info("Setting up monitor")
|
||||
|
|
|
@ -23,7 +23,7 @@ class ReplayGainUpdater(Thread):
|
|||
def __init__(self, logger):
|
||||
Thread.__init__(self)
|
||||
self.logger = logger
|
||||
self.api_client = api_client.AirTimeApiClient()
|
||||
self.api_client = api_client.AirtimeApiClient()
|
||||
|
||||
def main(self):
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ monit_restart() {
|
|||
start-stop-daemon --stop --oknodo --retry TERM/5/0/30 --quiet --pidfile $PIDFILE1
|
||||
rm -f $PIDFILE1
|
||||
|
||||
start-stop-daemon --start --background --quiet --chuid $USERID:$GROUPID --make-pidfile --pidfile $PIDFILE0 --startas $DAEMON0
|
||||
start-stop-daemon --start --background --quiet --chuid $ROOTUSERID:$ROOTUSERID --make-pidfile --pidfile $PIDFILE0 --startas $DAEMON0
|
||||
|
||||
start-stop-daemon --start --background --quiet --chuid $USERID:$GROUPID \
|
||||
--nicelevel -15 --make-pidfile --pidfile $PIDFILE1 --startas $DAEMON1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import logging
|
||||
import sys
|
||||
from api_clients import api_client
|
||||
from api_clients.api_client import AirtimeApiClient
|
||||
|
||||
def generate_liquidsoap_config(ss):
|
||||
data = ss['msg']
|
||||
|
@ -9,22 +9,22 @@ def generate_liquidsoap_config(ss):
|
|||
fh.write("# THIS FILE IS AUTO GENERATED. DO NOT CHANGE!! #\n")
|
||||
fh.write("################################################\n")
|
||||
for d in data:
|
||||
|
||||
key = d['keyname']
|
||||
|
||||
str_buffer = d[u'keyname'] + " = "
|
||||
if(d[u'type'] == 'string'):
|
||||
temp = d[u'value']
|
||||
str_buffer += '"%s"' % temp
|
||||
val = '"%s"' % d['value']
|
||||
else:
|
||||
temp = d[u'value']
|
||||
if(temp == ""):
|
||||
temp = "0"
|
||||
str_buffer += temp
|
||||
str_buffer += "\n"
|
||||
fh.write(api_client.encode_to(str_buffer))
|
||||
val = d[u'value']
|
||||
val = val if len(val) > 0 else "0"
|
||||
str_buffer = "%s = %s\n" % (key, val)
|
||||
fh.write(str_buffer.encode('utf-8'))
|
||||
fh.write('log_file = "/var/log/airtime/pypo-liquidsoap/<script>.log"\n')
|
||||
fh.close()
|
||||
|
||||
logging.basicConfig(format='%(message)s')
|
||||
ac = api_client(logging.getLogger())
|
||||
ac = AirtimeApiClient(logging.getLogger())
|
||||
ss = ac.get_stream_setting()
|
||||
|
||||
if ss is not None:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from api_clients import *
|
||||
import sys
|
||||
|
||||
api_clients = api_client.AirTimeApiClient()
|
||||
api_clients = api_client.AirtimeApiClient()
|
||||
|
||||
dj_type = sys.argv[1]
|
||||
username = sys.argv[2]
|
||||
|
|
|
@ -107,10 +107,10 @@ except Exception, e:
|
|||
|
||||
class Global:
|
||||
def __init__(self):
|
||||
self.api_client = api_client.AirTimeApiClient()
|
||||
self.api_client = api_client.AirtimeApiClient()
|
||||
|
||||
def selfcheck(self):
|
||||
self.api_client = api_client.AirTimeApiClient()
|
||||
self.api_client = api_client.AirtimeApiClient()
|
||||
return self.api_client.is_server_compatible()
|
||||
|
||||
def test_api(self):
|
||||
|
@ -172,7 +172,7 @@ if __name__ == '__main__':
|
|||
g.test_api()
|
||||
sys.exit()
|
||||
|
||||
api_client = api_client.AirTimeApiClient()
|
||||
api_client = api_client.AirtimeApiClient()
|
||||
api_client.register_component("pypo")
|
||||
|
||||
pypoFetch_q = Queue()
|
||||
|
|
|
@ -40,7 +40,7 @@ except Exception, e:
|
|||
class PypoFetch(Thread):
|
||||
def __init__(self, pypoFetch_q, pypoPush_q, media_q, telnet_lock):
|
||||
Thread.__init__(self)
|
||||
self.api_client = api_client.AirTimeApiClient()
|
||||
self.api_client = api_client.AirtimeApiClient()
|
||||
self.fetch_queue = pypoFetch_q
|
||||
self.push_queue = pypoPush_q
|
||||
self.media_prepare_queue = media_q
|
||||
|
|
|
@ -64,7 +64,7 @@ except Exception, e:
|
|||
|
||||
class Notify:
|
||||
def __init__(self):
|
||||
self.api_client = api_client.AirTimeApiClient()
|
||||
self.api_client = api_client.AirtimeApiClient()
|
||||
|
||||
def notify_media_start_playing(self, data, media_id):
|
||||
logger = logging.getLogger("notify")
|
||||
|
|
|
@ -42,7 +42,7 @@ except Exception, e:
|
|||
class PypoPush(Thread):
|
||||
def __init__(self, q, telnet_lock):
|
||||
Thread.__init__(self)
|
||||
self.api_client = api_client.AirTimeApiClient()
|
||||
self.api_client = api_client.AirtimeApiClient()
|
||||
self.queue = q
|
||||
|
||||
self.telnet_lock = telnet_lock
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue