class DeeFuzzer(Thread):
"""a DeeFuzzer diffuser"""
+ logger = None
m3u = None
rss = None
+ station = []
+ stations = []
def __init__(self, conf_file):
Thread.__init__(self)
self.conf_file = conf_file
self.conf = get_conf_dict(self.conf_file)
+
+ # Get the log setting first (if possible)
+ log_file = str(self.conf.pop('log', ''))
+ log_dir = os.sep.join(log_file.split(os.sep)[:-1])
+ if not os.path.exists(log_dir) and log_dir:
+ os.makedirs(m3u_dir)
+ self.logger = Logger(log_file)
+
for key in self.conf['deefuzzer'].keys():
- if key == 'log':
- log_file = self.conf['deefuzzer']['log']
- log_dir = os.sep.join(log_file.split(os.sep)[:-1])
- if not os.path.exists(log_dir) and log_dir:
- os.makedirs(m3u_dir)
- self.logger = Logger(log_file)
if key == 'm3u':
- self.m3u = self.conf['deefuzzer']['m3u']
+ self.m3u = str(self.conf['deefuzzer'][key])
+
+ elif key == 'station':
+ # Load station definitions from the main config file
+ if not isinstance(self.conf['deefuzzer'][key], list):
+ self.add_station(self.conf['deefuzzer'][key])
+ else:
+ for s in self.conf['deefuzzer'][key]:
+ self.add_station(s)
+
+ elif key == 'stationconfig':
+ # Load additional station definitions from the requested folder
+ self.load_stations_fromconfig(self.conf['deefuzzer'][key])
+
+ elif key == 'stationfolder':
+ # Create stations automagically from a folder structure
+ if isinstance(self.conf['deefuzzer'][key], dict):
+ self.create_stations_fromfolder(self.conf['deefuzzer'][key])
else:
setattr(self, key, self.conf['deefuzzer'][key])
- # Fix wrong type data from xmltodict when one station (*)
- if 'station' not in self.conf['deefuzzer']:
- self.conf['deefuzzer']['station'] = []
- else:
- if not isinstance(self.conf['deefuzzer']['station'], list):
- s = self.conf['deefuzzer']['station']
- self.conf['deefuzzer']['station'] = []
- self.conf['deefuzzer']['station'].append(s)
-
- # Load additional station definitions from the requested folder
- if 'stationconfig' in self.conf['deefuzzer']:
- self.load_stations(self.conf['deefuzzer']['stationconfig'])
-
- # Create stations automagically from a folder structure
- if 'stationfolder' in self.conf['deefuzzer'].keys() and isinstance(self.conf['deefuzzer']['stationfolder'], dict):
- self.create_stations_fromfolder(self.conf['deefuzzer']['stationfolder'])
-
- self.nb_stations = len(self.conf['deefuzzer']['station'])
-
# Set the deefuzzer logger
self.logger.write_info('Starting DeeFuzzer')
self.logger.write_info('Using libshout version %s' % shout.version())
+ self.logger.write_info('Number of stations : ' + str(len(self.station)))
- # Init all Stations
- self.stations = []
- self.logger.write_info('Number of stations : ' + str(self.nb_stations))
def set_m3u_playlist(self):
m3u_dir = os.sep.join(self.m3u.split(os.sep)[:-1])
self.logger.write_info('Writing M3U file to : ' + self.m3u)
def create_stations_fromfolder(self, options):
+ """Scan a folder for subfolders containing media, and make stations from them all."""
+
if not 'folder' in options.keys():
+ # We have no folder specified. Bail.
return
+
folder = str(options['folder'])
- self.logger.write_info('Scanning folder ' + folder + ' for stations...')
+ if not os.path.isdir(folder):
+ # The specified path is not a folder. Bail.
+ return
+
+ self.logger.write_info('Scanning folder ' + folder + ' for stations')
+
files = os.listdir(folder)
for file in files:
filepath = os.path.join(folder, file)
self.create_station(filepath, options)
def create_station(self, folder, options):
+ """Create a station definition for a folder given the specified options."""
+
self.logger.write_info('Creating station for folder ' + folder)
s = {}
path, name = os.path.split(folder)
if not 'media' in s.keys():
s['media'] = {}
s['media']['dir'] = folder
- self.conf['deefuzzer']['station'].append(s)
-
-
- def load_stations(self, folder):
- if isinstance(folder, dict):
+ self.add_station(s)
+
+ def load_stations_fromconfig(self, folder):
+ """Load one or more configuration files looking for stations."""
+
+ if isinstance(folder, dict) or isinstance(folder, list):
+ # We were given a list or dictionary. Loop though it and load em all
for f in folder:
- self.load_stations(f)
+ self.load_station_configs(f)
return
+ if os.path.isfile(folder):
+ # We have a file specified. Load just that file.
+ self.load_station_config(folder)
+ return
+
if not os.path.isdir(folder):
+ # Whatever we have, it's not either a file or folder. Bail.
return
-
+
self.logger.write_info('Loading station config files in ' + folder)
files = os.listdir(folder)
for file in files:
filepath = os.path.join(folder, file)
if os.path.isfile(filepath):
self.load_station_config(filepath)
-
+
def load_station_config(self, file):
+ """Load station configuration(s) from a config file."""
+
self.logger.write_info('Loading station config file ' + file)
stationdef = get_conf_dict(file)
if isinstance(stationdef, dict):
- if 'station' in stationdef.keys() and isinstance(stationdef['station'], dict):
- self.conf['deefuzzer']['station'].append(stationdef['station'])
+ if 'station' in stationdef.keys():
+ if isinstance(stationdef['station'], dict):
+ self.add_station(stationdef['station'])
+ elif isinstance(stationdef['station'], list):
+ for s in stationdef['station']:
+ self.add_station(s)
+
+ def add_station(self, this_station):
+ """Adds a station configuration to the list of stations."""
+ try:
+ # We should probably test to see if we're putting the same station in multiple times
+ # Same in this case probably means the same media folder, server, and mountpoint
+ self.station.append(this_station)
+ except Exception:
+ return
def run(self):
q = Queue.Queue(1)
- for i in range(0,self.nb_stations):
- station = self.conf['deefuzzer']['station'][i]
+ ns = len(self.station)
+ for i in range(0, ns):
+ try:
+ station = self.station[i]
- # Apply station defaults if they exist
- if 'stationdefaults' in self.conf['deefuzzer']:
- if isinstance(self.conf['deefuzzer']['stationdefaults'], dict):
- station = merge_defaults(station, self.conf['deefuzzer']['stationdefaults'])
- self.stations.append(Station(station, q, self.logger, self.m3u))
+ # Apply station defaults if they exist
+ if 'stationdefaults' in self.conf['deefuzzer']:
+ if isinstance(self.conf['deefuzzer']['stationdefaults'], dict):
+ station = merge_defaults(station, self.conf['deefuzzer']['stationdefaults'])
+ self.stations.append(Station(station, q, self.logger, self.m3u))
+ except Exception:
+ continue
if self.m3u:
self.set_m3u_playlist()
p = Producer(q)
p.start()
+ ns = len(self.stations)
# Start the Stations
- for i in range(0,self.nb_stations):
- self.stations[i].start()
+ for i in range(0, ns):
+ try:
+ self.stations[i].start()
+ except Exception:
+ continue
class Producer(Thread):
lp = 1
player_mode = 0
osc_control_mode = 0
+ osc_control_port = 16001
twitter_mode = 0
jingles_mode = 0
+ jingles_shuffle = 1
+ jingles_dir = ''
relay_mode = 0
+ relay_url = ''
+ relay_author = ''
record_mode = 0
+ record_dir = ''
run_mode = 1
station_dir = None
appendtype = 1
feeds_rss = 1
feeds_mode = 1
feeds_playlist = 1
+ media_dir = ''
+ m3u_playlist_file = []
+ mountpoint = 'default'
+ type = 'icecast'
+ feeds_media_url = ''
def __init__(self, station, q, logger, m3u):
Thread.__init__(self)
self.logger = logger
self.m3u = m3u
- if 'station_dir' in self.station:
- self.station_dir = self.station['station_dir']
-
- # Media
- self.media_dir = self.station['media']['dir']
- self.media_format = self.station['media']['format']
- self.shuffle_mode = int(self.station['media']['shuffle'])
- self.bitrate = self.station['media']['bitrate']
- self.ogg_quality = self.station['media']['ogg_quality']
- self.samplerate = self.station['media']['samplerate']
- self.voices = self.station['media']['voices']
- self.m3u_playlist_file = []
- if 'm3u' in self.station['media'].keys():
- self.m3u_playlist_file = self.station['media']['m3u']
-
- # Server
- if 'mountpoint' in self.station['server'].keys():
- self.mountpoint = self.station['server']['mountpoint']
- elif 'short_name' in self.station['infos'].keys():
- self.mountpoint = self.station['infos']['short_name']
- else:
- self.mountpoint = 'default'
+ # Port the feeds key into the rss key if it exists (for backwards compatibility)
+ if 'feeds' in self.station.keys():
+ self.station['rss'] = self.station['feeds']
+ self.station.pop('feeds')
+
+ # Get the mountpoint and short name first
+ if 'server' in self.station.keys():
+ # Try to get the mountpoint as defined by the server.mountpoint parameter
+ self.mountpoint = str(self.station['server'].pop('mountpoint',self.mountpoint))
+ self.appendtype = int(self.station['server'].pop('appendtype',self.appendtype))
+ self.type = str(self.station['server'].pop('type',self.type))
+
+ # Get our media format since we need to to define a stream object
+ if 'media' in self.station.keys():
+ self.media_format = str(self.station['media'].pop('format',self.media_format))
+
+ # We don't have a non-default mount point yet, so get info.short_name and try that
+ if self.mountpoint == 'default':
+ if 'infos' in self.station.keys():
+ self.mountpoint = str(self.station['infos'].pop('short_name','default'))
+ # Set the short name based on the mount point.
self.short_name = self.mountpoint
-
- if 'appendtype' in self.station['server'].keys():
- self.appendtype = self.station['server']['appendtype']
-
- if 'type' in self.station['server']:
- self.type = self.station['server']['type'] # 'icecast' | 'stream-m'
- else:
- self.type = 'icecast'
-
+
+ # Set up the stream channel
if 'stream-m' in self.type:
self.channel = HTTPStreamer()
self.channel.mount = '/publish/' + self.mountpoint
self.channel.mount = self.channel.mount + '.' + self.media_format
else:
sys.exit('Not a compatible server type. Choose "stream-m" or "icecast".')
-
- self.channel.url = self.station['infos']['url']
- self.channel.name = self.station['infos']['name']
- self.channel.genre = self.station['infos']['genre']
- self.channel.description = self.station['infos']['description']
+
+ # Apply defaults for the channel
self.channel.format = self.media_format
- self.channel.host = self.station['server']['host']
- self.channel.port = int(self.station['server']['port'])
self.channel.user = 'source'
- self.channel.password = self.station['server']['sourcepassword']
- self.channel.public = int(self.station['server']['public'])
- self.channel.genre = self.station['infos']['genre']
- self.channel.description = self.station['infos']['description']
+
+ # Parse the rest of the key structure
+ for key in self.station.keys():
+ if key == 'station_dir':
+ self.station_dir = self.station['station_dir']
+
+ if key == 'media':
+ # Media
+ for subkey in self.station[key].keys():
+ if subkey == 'dir':
+ self.media_dir = str(self.station[key][subkey])
+
+ elif subkey == 'shuffle':
+ self.shuffle_mode = int(self.station[key][subkey])
+
+ elif subkey == 'bitrate':
+ self.bitrate = int(self.station[key][subkey])
+
+ elif subkey == 'ogg_quality':
+ self.ogg_quality = int(self.station[key][subkey])
+
+ elif subkey == 'samplerate':
+ self.samplerate = int(self.station[key][subkey])
+
+ elif subkey == 'voices':
+ self.voices = int(self.station[key][subkey])
+
+ elif subkey == 'm3u':
+ self.m3u_playlist_file = self.station[key][subkey]
+
+ if key == 'infos':
+ # Stream Info
+ for subkey in self.station[key].keys():
+ if subkey == 'url':
+ self.channel.url = str(self.station[key][subkey])
+
+ elif subkey == 'name':
+ self.channel.name = str(self.station[key][subkey])
+
+ elif subkey == 'genre':
+ self.channel.genre = str(self.station[key][subkey])
+
+ elif subkey == 'description':
+ self.channel.description = str(self.station[key][subkey])
+
+ if key == 'server':
+ # Server Info
+ for subkey in self.station[key].keys():
+ if subkey == 'host':
+ self.channel.host = str(self.station[key][subkey])
+
+ elif subkey == 'port':
+ self.channel.port = str(self.station[key][subkey])
+
+ elif subkey == 'sourceuser':
+ self.channel.user = str(self.station[key][subkey])
+
+ elif subkey == 'sourcepassword':
+ self.channel.password = str(self.station[key][subkey])
+
+ elif subkey == 'public':
+ self.channel.public = str(self.station[key][subkey])
+
+ if key == 'rss':
+ # Server Info
+ for subkey in self.station[key].keys():
+ if subkey == 'mode':
+ self.feeds_mode = int(self.station[key][subkey])
+
+ elif subkey == 'dir':
+ self.feeds_dir = str(self.station[key][subkey])
+
+ elif subkey == 'enclosure':
+ self.feeds_enclosure = int(self.station[key][subkey])
+
+ elif subkey == 'json':
+ self.feeds_json = int(self.station[key][subkey])
+
+ elif subkey == 'rss':
+ self.feeds_rss = int(self.station[key][subkey])
+
+ elif subkey == 'playlist':
+ self.feeds_playlist = int(self.station[key][subkey])
+
+ elif subkey == 'media_url':
+ self.feeds_media_url = str(self.station[key][subkey])
+
+ if key == 'control':
+ # Server Info
+ for subkey in self.station[key].keys():
+ if subkey == 'mode':
+ self.osc_control_mode = int(self.station[key][subkey])
+
+ elif subkey == 'port':
+ self.osc_control_port = int(self.station[key][subkey])
+
+ if key == 'jingles':
+ # Server Info
+ for subkey in self.station[key].keys():
+ if subkey == 'mode':
+ self.jingles_mode = int(self.station[key][subkey])
+
+ elif subkey == 'shuffle':
+ self.jingles_shuffle = int(self.station[key][subkey])
+
+ elif subkey == 'dir':
+ self.jingles_dir = str(self.station[key][subkey])
+
+ if key == 'relay':
+ # Server Info
+ for subkey in self.station[key].keys():
+ if subkey == 'mode':
+ self.relay_mode = int(self.station[key][subkey])
+
+ elif subkey == 'url':
+ self.relay_url = str(self.station[key][subkey])
+
+ elif subkey == 'author':
+ self.relay_author = str(self.station[key][subkey])
+
+ if key == 'twitter':
+ # Server Info
+ for subkey in self.station[key].keys():
+ if subkey == 'mode':
+ self.twitter_mode = int(self.station[key][subkey])
+
+ elif subkey == 'key':
+ self.twitter_key = str(self.station[key][subkey])
+
+ elif subkey == 'secret':
+ self.twitter_secret = str(self.station[key][subkey])
+
+ elif subkey == 'tags':
+ self.twitter_tags = str(self.station[key][subkey]).split(' ')
+
+ elif subkey == 'messages':
+ self.twitter_messages = self.station[key][subkey]
+ if isinstance(self.twitter_messages, dict):
+ self.twitter_messages = list(self.twitter_messages)
+
+ if key == 'record':
+ # Server Info
+ for subkey in self.station[key].keys():
+ if subkey == 'mode':
+ self.record_mode = int(self.station[key][subkey])
+
+ elif subkey == 'dir':
+ self.record_dir = str(self.station[key][subkey])
+
+
+
if self.channel.format == 'mp3':
self.channel.audio_info = { 'bitrate': str(self.bitrate),
'samplerate': str(self.samplerate),
self.channel_url = self.server_url + self.channel.mount
# RSS
- if 'feeds' in self.station:
- self.station['rss'] = self.station['feeds']
-
- if 'rss' in self.station:
- if 'mode' in self.station['rss']:
- self.feeds_mode = int(self.station['rss']['mode'])
- self.feeds_dir = self.station['rss']['dir']
- self.feeds_enclosure = int(self.station['rss']['enclosure'])
- if 'json' in self.station['rss']:
- self.feeds_json = int(self.station['rss']['json'])
- if 'rss' in self.station['rss']:
- self.feeds_rss = int(self.station['rss']['rss'])
- if 'playlist' in self.station['rss']:
- self.feeds_playlist = int(self.station['rss']['playlist'])
-
+ if self.feeds_media_url == '':
self.feeds_media_url = self.channel.url + '/media/'
- if 'media_url' in self.station['rss']:
- if self.station['rss']['media_url']:
- self.feeds_media_url = self.station['rss']['media_url']
self.base_name = self.feeds_dir + os.sep + self.short_name + '_' + self.channel.format
- self.feeds_current_file = self.base_name + '_current.xml'
- self.feeds_playlist_file = self.base_name + '_playlist.xml'
+ self.feeds_current_file = self.base_name + '_current'
+ self.feeds_playlist_file = self.base_name + '_playlist'
# Logging
self.logger.write_info('Opening ' + self.short_name + ' - ' + self.channel.name + \
self.player = Player(self.type)
# OSCing
- # mode = 0 means Off, mode = 1 means On
- if 'control' in self.station:
- self.osc_control_mode = int(self.station['control']['mode'])
- if self.osc_control_mode:
- self.osc_port = self.station['control']['port']
- self.osc_controller = OSCController(self.osc_port)
- # OSC paths and callbacks
- self.osc_controller.add_method('/media/next', 'i', self.media_next_callback)
- self.osc_controller.add_method('/media/relay', 'i', self.relay_callback)
- self.osc_controller.add_method('/twitter', 'i', self.twitter_callback)
- self.osc_controller.add_method('/jingles', 'i', self.jingles_callback)
- self.osc_controller.add_method('/record', 'i', self.record_callback)
- self.osc_controller.add_method('/player', 'i', self.player_callback)
- self.osc_controller.add_method('/run', 'i', self.run_callback)
- self.osc_controller.start()
+ if self.osc_control_mode and self.osc_control_port:
+ self.osc_controller = OSCController(self.osc_control_port)
+ # OSC paths and callbacks
+ self.osc_controller.add_method('/media/next', 'i', self.media_next_callback)
+ self.osc_controller.add_method('/media/relay', 'i', self.relay_callback)
+ self.osc_controller.add_method('/twitter', 'i', self.twitter_callback)
+ self.osc_controller.add_method('/jingles', 'i', self.jingles_callback)
+ self.osc_controller.add_method('/record', 'i', self.record_callback)
+ self.osc_controller.add_method('/player', 'i', self.player_callback)
+ self.osc_controller.add_method('/run', 'i', self.run_callback)
+ self.osc_controller.start()
# Jingling between each media.
- if 'jingles' in self.station:
- self.jingles_mode = int(self.station['jingles']['mode'])
- self.jingles_shuffle = self.station['jingles']['shuffle']
- self.jingles_dir = self.station['jingles']['dir']
- if self.jingles_mode == 1:
- self.jingles_callback('/jingles', [1])
+ if self.jingles_mode:
+ self.jingles_callback('/jingles', [1])
# Relaying
- if 'relay' in self.station:
- self.relay_mode = int(self.station['relay']['mode'])
- self.relay_url = self.station['relay']['url']
- self.relay_author = self.station['relay']['author']
- if self.relay_mode == 1:
- self.relay_callback('/media/relay', [1])
+ if self.relay_mode:
+ self.relay_callback('/media/relay', [1])
# Twitting
- if 'twitter' in self.station:
- self.twitter_mode = int(self.station['twitter']['mode'])
- self.twitter_key = self.station['twitter']['key']
- self.twitter_secret = self.station['twitter']['secret']
- self.twitter_tags = self.station['twitter']['tags'].split(' ')
- try:
- self.twitter_messages = self.station['twitter']['message']
- if isinstance(self.twitter_messages, dict):
- self.twitter_messages = list(self.twitter_messages)
- except:
- pass
-
- if self.twitter_mode:
- self.twitter_callback('/twitter', [1])
+ if self.twitter_mode:
+ self.twitter_callback('/twitter', [1])
# Recording
- if 'record' in self.station:
- self.record_mode = int(self.station['record']['mode'])
- self.record_dir = self.station['record']['dir']
- if self.record_mode:
- self.record_callback('/record', [1])
+ if self.record_mode:
+ self.record_callback('/record', [1])
def run_callback(self, path, value):
value = value[0]
new_tracks = new_playlist_set - playlist_set
self.new_tracks = list(new_tracks.copy())
- if self.twitter_mode == 1 and self.counter:
+ if self.twitter_mode and self.counter:
self.tweet()
# Shake it, Fuzz it !
items = rss_item_list,)
if self.feeds_rss:
- f = open(rss_file, 'w')
+ f = open(rss_file + '.xml', 'w')
rss.write_xml(f, 'utf-8')
f.close()
if self.feeds_json:
- path, fn = os.path.split(rss_file)
- base, ext = os.path.splitext(fn)
- json_file = os.path.join(self.feeds_dir, base + '.json')
- f = open(json_file, 'w')
+ f = open(rss_file + '.json', 'w')
f.write(json.dumps(json_data, separators=(',',':')))
f.close()