Trees | Indices | Help |
|
---|
|
1 #!/usr/bin/python 2 # -*- coding: utf-8 -*- 3 # 4 # Copyright (C) 2006-2011 Guillaume Pellerin 5 6 # <yomguy@parisson.com> 7 8 # This software is a computer program whose purpose is to stream audio 9 # and video data through icecast2 servers. 10 11 # This software is governed by the CeCILL license under French law and 12 # abiding by the rules of distribution of free software. You can use, 13 # modify and/ or redistribute the software under the terms of the CeCILL 14 # license as circulated by CEA, CNRS and INRIA at the following URL 15 # "http://www.cecill.info". 16 17 # As a counterpart to the access to the source code and rights to copy, 18 # modify and redistribute granted by the license, users are provided only 19 # with a limited warranty and the software's author, the holder of the 20 # economic rights, and the successive licensors have only limited 21 # liability. 22 23 # In this respect, the user's attention is drawn to the risks associated 24 # with loading, using, modifying and/or developing or reproducing the 25 # software by the user in light of its specific status of free software, 26 # that may mean that it is complicated to manipulate, and that also 27 # therefore means that it is reserved for developers and experienced 28 # professionals having in-depth computer knowledge. Users are therefore 29 # encouraged to load and test the software's suitability as regards their 30 # requirements in conditions enabling the security of their systems and/or 31 # data to be ensured and, more generally, to use and operate it in the 32 # same conditions as regards security. 33 34 # The fact that you are presently reading this means that you have had 35 # knowledge of the CeCILL license and that you accept its terms. 36 37 # Author: Guillaume Pellerin <yomguy@parisson.com> 38 39 import os 40 import shout 41 import Queue 42 import datetime 43 import mimetypes 44 import hashlib 45 from threading import Thread 46 from deefuzzer.station import * 47 from deefuzzer.tools import * 48 49 mimetypes.add_type('application/x-yaml', '.yaml') 50 5153 """a DeeFuzzer diffuser""" 54 55 logger = None 56 m3u = None 57 rss = None 58 station_settings = [] 59 station_instances = {} 60 watchfolder = {} 61 logqueue = Queue.Queue() 62 mainLoop = False 63 ignoreErrors = False 64 maxretry = 0 65347 # end main loop 348 349 36367 Thread.__init__(self) 68 self.conf_file = conf_file 69 self.conf = get_conf_dict(self.conf_file) 70 71 if 'deefuzzer' not in self.conf: 72 return 73 74 # Get the log setting first (if possible) 75 log_file = str(self.conf['deefuzzer'].pop('log', '')) 76 self.log_dir = os.sep.join(log_file.split(os.sep)[:-1]) 77 if not os.path.exists(self.log_dir) and self.log_dir: 78 os.makedirs(self.log_dir) 79 self.logger = QueueLogger(log_file, self.logqueue) 80 self.logger.start() 81 82 for key in self.conf['deefuzzer'].keys(): 83 if key == 'm3u': 84 self.m3u = str(self.conf['deefuzzer'][key]) 85 86 elif key == 'ignoreerrors': 87 # Ignore errors and continue as long as possible 88 self.ignoreErrors = bool(self.conf['deefuzzer'][key]) 89 90 elif key == 'maxretry': 91 # Maximum number of attempts to restart the stations on crash. 92 self.maxretry = int(self.conf['deefuzzer'][key]) 93 94 elif key == 'station': 95 # Load station definitions from the main config file 96 if not isinstance(self.conf['deefuzzer'][key], list): 97 self.add_station(self.conf['deefuzzer'][key]) 98 else: 99 for s in self.conf['deefuzzer'][key]: 100 self.add_station(s) 101 102 elif key == 'stationconfig': 103 # Load additional station definitions from the requested folder 104 self.load_stations_fromconfig(self.conf['deefuzzer'][key]) 105 106 elif key == 'stationfolder': 107 # Create stations automagically from a folder structure 108 if isinstance(self.conf['deefuzzer'][key], dict): 109 self.watchfolder = self.conf['deefuzzer'][key] 110 else: 111 setattr(self, key, self.conf['deefuzzer'][key]) 112 113 # Set the deefuzzer logger 114 self._info('Starting DeeFuzzer') 115 self._info('Using libshout version %s' % shout.version()) 116 self._info('Number of stations : ' + str(len(self.station_settings)))117119 try: 120 obj = {'msg': 'Core: ' + str(msg), 'level': level} 121 self.logqueue.put(obj) 122 except: 123 pass124126 self._log('info', msg)127129 self._log('err', msg)130132 m3u_dir = os.sep.join(self.m3u.split(os.sep)[:-1]) 133 if not os.path.exists(m3u_dir) and m3u_dir: 134 os.makedirs(m3u_dir) 135 m3u = open(self.m3u, 'w') 136 m3u.write('#EXTM3U\n') 137 for k in self.station_instances.keys(): 138 s = self.station_instances[k] 139 m3u.write('#EXTINF:%s,%s - %s\n' % ('-1', s.short_name, s.channel.name)) 140 m3u.write('http://' + s.channel.host + ':' + str(s.channel.port) + s.channel.mount + '\n') 141 m3u.close() 142 self._info('Writing M3U file to : ' + self.m3u)143145 """Scan a folder for subfolders containing media, and make stations from them all.""" 146 147 options = self.watchfolder 148 if 'folder' not in options: 149 # We have no folder specified. Bail. 150 return 151 152 if self.mainLoop: 153 if 'livecreation' not in options: 154 # We have no folder specified. Bail. 155 return 156 157 if int(options['livecreation']) == 0: 158 # Livecreation not specified. Bail. 159 return 160 161 folder = str(options['folder']) 162 if not os.path.isdir(folder): 163 # The specified path is not a folder. Bail. 164 return 165 166 # This makes the log file a lot more verbose. Commented out since we report on new stations anyway. 167 # self._info('Scanning folder ' + folder + ' for stations') 168 169 if 'infos' not in options: 170 options['infos'] = {} 171 if 'short_name' not in options['infos']: 172 options['infos']['short_name'] = '[name]' 173 174 files = os.listdir(folder) 175 for file in files: 176 filepath = os.path.join(folder, file) 177 if os.path.isdir(filepath): 178 if folder_contains_music(filepath): 179 self.create_station(filepath, options)180182 try: 183 for s in self.station_settings: 184 if 'infos' not in s: 185 continue 186 if 'short_name' not in s['infos']: 187 continue 188 if s['infos']['short_name'] == name: 189 return True 190 return False 191 except: 192 pass 193 return True194196 """Create a station definition for a folder given the specified options.""" 197 198 s = {} 199 path, name = os.path.split(folder) 200 if self.station_exists(name): 201 return 202 self._info('Creating station for folder ' + folder) 203 d = dict(path=folder, name=name) 204 for i in options.keys(): 205 if 'folder' not in i: 206 s[i] = replace_all(options[i], d) 207 if 'media' not in s: 208 s['media'] = {} 209 s['media']['source'] = folder 210 211 self.add_station(s)212214 """Load one or more configuration files looking for stations.""" 215 216 if isinstance(folder, dict) or isinstance(folder, list): 217 # We were given a list or dictionary. Loop though it and load em all 218 for f in folder: 219 self.load_station_configs(f) 220 return 221 222 if os.path.isfile(folder): 223 # We have a file specified. Load just that file. 224 self.load_station_config(folder) 225 return 226 227 if not os.path.isdir(folder): 228 # Whatever we have, it's not either a file or folder. Bail. 229 return 230 231 self._info('Loading station config files in ' + folder) 232 files = os.listdir(folder) 233 for file in files: 234 filepath = os.path.join(folder, file) 235 if os.path.isfile(filepath): 236 self.load_station_config(filepath)237239 """Load station configuration(s) from a config file.""" 240 241 self._info('Loading station config file ' + file) 242 stationdef = get_conf_dict(file) 243 if isinstance(stationdef, dict): 244 if 'station' in stationdef: 245 if isinstance(stationdef['station'], dict): 246 self.add_station(stationdef['station']) 247 elif isinstance(stationdef['station'], list): 248 for s in stationdef['station']: 249 self.add_station(s)250252 """Adds a station configuration to the list of stations.""" 253 try: 254 # We should probably test to see if we're putting the same station in multiple times 255 # Same in this case probably means the same media folder, server, and mountpoint 256 self.station_settings.append(this_station) 257 except Exception: 258 return259261 q = Queue.Queue(1) 262 ns = 0 263 p = Producer(q) 264 p.start() 265 # Keep the Stations running 266 while True: 267 self.create_stations_fromfolder() 268 ns_new = len(self.station_settings) 269 if ns_new > ns: 270 self._info('Loading new stations') 271 272 for i in range(0, ns_new): 273 name = '' 274 try: 275 if 'station_name' in self.station_settings[i]: 276 name = self.station_settings[i]['station_name'] 277 278 if 'retries' not in self.station_settings[i]: 279 self.station_settings[i]['retries'] = 0 280 281 try: 282 if 'station_instance' in self.station_settings[i]: 283 # Check for station running here 284 if self.station_settings[i]['station_instance'].isAlive(): 285 # Station exists and is alive. Don't recreate. 286 self.station_settings[i]['retries'] = 0 287 continue 288 289 if self.maxretry >= 0 and self.station_settings[i]['retries'] <= self.maxretry: 290 # Station passed the max retries count is will not be reloaded 291 if 'station_stop_logged' not in self.station_settings[i]: 292 self._err('Station ' + name + ' is stopped and will not be restarted.') 293 self.station_settings[i]['station_stop_logged'] = True 294 continue 295 296 self.station_settings[i]['retries'] += 1 297 trynum = str(self.station_settings[i]['retries']) 298 self._info('Restarting station ' + name + ' (try ' + trynum + ')') 299 except Exception as e: 300 self._err('Error checking status for ' + name) 301 self._err(str(e)) 302 if not self.ignoreErrors: 303 raise 304 305 # Apply station defaults if they exist 306 if 'stationdefaults' in self.conf['deefuzzer']: 307 if isinstance(self.conf['deefuzzer']['stationdefaults'], dict): 308 self.station_settings[i] = merge_defaults( 309 self.station_settings[i], 310 self.conf['deefuzzer']['stationdefaults'] 311 ) 312 313 if name == '': 314 name = 'Station ' + str(i) 315 if 'info' in self.station_settings[i]: 316 if 'short_name' in self.station_settings[i]['infos']: 317 name = self.station_settings[i]['infos']['short_name'] 318 y = 1 319 while name in self.station_instances.keys(): 320 y += 1 321 name = self.station_settings[i]['infos']['short_name'] + " " + str(y) 322 323 self.station_settings[i]['station_name'] = name 324 namehash = hashlib.md5(name).hexdigest() 325 self.station_settings[i]['station_statusfile'] = os.sep.join([self.log_dir, namehash]) 326 327 new_station = Station(self.station_settings[i], q, self.logqueue, self.m3u) 328 if new_station.valid: 329 self.station_settings[i]['station_instance'] = new_station 330 self.station_settings[i]['station_instance'].start() 331 self._info('Started station ' + name) 332 else: 333 self._err('Error validating station ' + name) 334 except Exception: 335 self._err('Error initializing station ' + name) 336 if not self.ignoreErrors: 337 raise 338 continue 339 340 if self.m3u: 341 self.set_m3u_playlist() 342 343 ns = ns_new 344 self.mainLoop = True 345 346 time.sleep(5)
Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Sat Jan 31 00:38:02 2015 | http://epydoc.sourceforge.net |