def _send(message_list): from rsab.listenagain import config import email.Utils import smtplib if config.has_option('email', 'from'): email_from = config.get('email', 'from') else: email_from = DEFAULT_FROM if config.has_option('email', 'smtphost'): smtphost = config.get('email', 'smtphost') else: smtphost = '' if not smtphost: raise ListenAgainConfigError('[email]/smtphost not set') if config.has_option('email', 'smtpport'): smtpport = config.getint('email', 'smtpport') else: smtpport = None if not smtpport: smtpport = 25 if config.has_option('email', 'smtpusername'): smtpusername = config.get('email', 'smtpusername') else: smtpusername = '' if config.has_option('email', 'smtppassword'): smtppassword = config.get('email', 'smtppassword') else: smtppassword = '' sent = 0 smtp = smtplib.SMTP(smtphost, smtpport) if smtpusername: try: smtp.login(smtpusername, smtppassword) except smtplib.SMTPException, e: print 'ERROR: Could not log in to SMTP server.' print e return sent
def make_wav_files(bounds_and_files, schedule_list): import datetime import os import wave from rsab.listenagain import config, schedule, utils if config.has_option('main', 'wavs'): output_dir = config.get('main', 'wavs') else: output_dir = os.getcwd() if not os.path.exists(output_dir): os.makedirs(output_dir) if not bounds_and_files: return None wav_reader = wave.open(bounds_and_files[0][2], 'rb') output_wav_params = wav_reader.getparams() output_wav_params = list(output_wav_params) output_wav_params[3] = 0 output_wav_params = tuple(output_wav_params) wav_reader.close() frame_rate = output_wav_params[2] frame_size = output_wav_params[0] + output_wav_params[1] if config.has_option('main', 'framechunksize'): frame_chunk = config.getint('main', 'framechunksize') else: frame_chunk = 65536 print 'Reading audio data in chunks of', utils.format_large_number(frame_chunk), 'frames' print 'Output directory:', output_dir output_wav_files = [] bounds_and_files.sort() for details in schedule_list: if not details['record']: continue actual_time_start = utils.apply_padding(details['start'], details.get('pad_start', 0), subtract=True) actual_time_start = datetime.datetime.combine(details['date'], actual_time_start) actual_time_end = utils.apply_padding(details['end'], details.get('pad_end', 0), subtract=False) actual_time_end = datetime.datetime.combine(details['date'], actual_time_end) print print 'Schedule:', schedule.get_schedule_item_as_string(details) output_file_name = os.path.join(output_dir, make_output_file_name(details, 'wav')) print 'Output file:', os.path.split(output_file_name)[1] wav_writer = wave.open(output_file_name, 'wb') wav_writer.setparams(output_wav_params) for wav_file_start, wav_file_end, wav_file_path in bounds_and_files: if wav_file_start.date() != details['date'] \ or wav_file_end.date() != details['date'] \ or wav_file_end <= actual_time_start \ or wav_file_start >= actual_time_end: continue wav_reader = wave.open(wav_file_path, 'rb') start_frame = end_frame = None if wav_file_start < actual_time_start: start_frame = (actual_time_start - wav_file_start).seconds * frame_rate if wav_file_end > actual_time_end: end_frame = (actual_time_end - wav_file_start).seconds * frame_rate if start_frame is None: start_frame = 0 if end_frame is None: end_frame = wav_reader.getnframes() to_read = start_frame print 'Skipping', utils.format_large_number(to_read), 'frames in', os.path.split(wav_file_path)[1] while to_read > 0: data = wav_reader.readframes(min(to_read, frame_chunk)) if not data: break to_read -= (len(data) / frame_size) to_read = end_frame - start_frame print 'Copying', utils.format_large_number(to_read), 'frames from', os.path.split(wav_file_path)[1] while to_read > 0: data = wav_reader.readframes(min(to_read, frame_chunk)) if not data: break to_read -= (len(data) / frame_size) wav_writer.writeframes(data) wav_reader.close() wrote_frames = wav_writer.getnframes() wav_writer.close() if wrote_frames: print 'Wrote', utils.format_large_number(wrote_frames), 'frames' output_wav_files.append(output_file_name) else: print 'Wrote no frames; deleting empty file' os.unlink(output_file_name) return output_wav_files
def notify_all(uploaded_files): from rsab.listenagain import config import html import schedule from email.MIMEText import MIMEText import os import sets if uploaded_files is None: return mapping = { None: sets.Set(uploaded_files), } for fname in uploaded_files: details = schedule.schedule_from_audio_file_name(fname) for name in [details['show']] + details.get('presenters', []): if name not in mapping: mapping[name] = sets.Set() mapping[name].add(fname) config_sections = [ sname for sname in config.sections() if sname == 'notify' or sname.startswith('notify.') ] if config.has_option('ftp', 'keep_days'): keep_days = config.getint('ftp', 'keep_days') else: keep_days = 7 if config.has_option('main', 'userfacingserveraddress'): remote_server = config.get('main', 'userfacingserveraddress') else: remote_server = 'http://listenagain.rsab.org' if config.has_option('ftp', 'audio_path'): remote_path = config.get('ftp', 'audio_path') else: remote_path = '/audio' if config.has_option('email', 'from'): email_from = config.get('email', 'from') else: email_from = DEFAULT_FROM print print 'Notification emails:' messages = [] for section in config_sections: print print 'Section name:', section if config.has_option(section, 'email'): addresses = filter(None, [x.strip() for x in config.get(section, 'email').split(',')]) else: addresses = [] print 'Addresses:', (addresses and ', '.join(addresses) or '(none)') if not addresses: print 'Skipping' continue if config.has_option(section, 'match'): match_names = filter(None, [x.strip() for x in config.get(section, 'match').split(',')]) else: match_names = [] print 'Requested:', ('*' in match_names and '(all)' or ', '.join(match_names)) if '*' in match_names: notify_files = list(mapping[None]) elif match_names: notify_files = sets.Set() for name in match_names: notify_files.update(mapping.get(name, [])) notify_files = list(notify_files) else: notify_files = [] if not notify_files: print 'No files matched.' continue notify_files.sort() if config.has_option(section, 'subject'): subject = config.get(section, 'subject') else: subject = 'New files uploaded by Radio St Austell Bay' if config.has_option(section, 'template'): template_name = config.get(section, 'template') else: template_name = 'mail-notify-default.txt' template = html.Template(template_name) # Not actually HTML! template.keep_days = keep_days files_string = '\n'.join([ ' %s%s/%s' % ( remote_server, remote_path, os.path.split(fname)[1], ) for fname in notify_files ]) template.files = files_string print 'Files:' print files_string message = MIMEText(str(template)) message['Subject'] = subject message['From'] = email_from message['To'] = ', '.join(addresses) messages.append(message) print print 'Sending messages...' print sent = _send(messages) print print 'Done. Sent %s of %s messages' % (sent, len(messages))
def get_schedule(date, filter_items=None): import datetime import glob import os from rsab.listenagain import \ config, \ utils, \ ListenAgainConfigError schedules_folder = None if config.has_option('main', 'schedules'): schedules_folder = config.get('main', 'schedules') if not os.path.isdir(schedules_folder): raise ListenAgainConfigError('Cannot find schedules folder', schedules_folder) schedule_file_path = None require_dow = True override_file_path = os.path.join(schedules_folder, 'override', date.strftime('%Y-%m-%d.csv')) if os.path.isfile(override_file_path): schedule_file_path = override_file_path require_dow = False if schedule_file_path is None: override_file_path = os.path.join(schedules_folder, 'override', date.strftime('%Y-%m-%d.txt')) if os.path.isfile(override_file_path): schedule_file_path = override_file_path require_dow = False if schedule_file_path is None: schedule_files_by_date = [] for fname in glob.glob(os.path.join(schedules_folder, '*.csv')) + glob.glob(os.path.join(schedules_folder, '*.txt')): fname_base = os.path.splitext(os.path.split(fname)[1])[0] date_for_fname = utils.parse_date(fname_base) if date_for_fname is None: print 'schedule.get_schedule: Could not interpret filename as date:', fname continue schedule_files_by_date.append( (date_for_fname, fname) ) schedule_files_by_date.sort() schedule_file_path = None for date_for_fname, try_schedule_file_path in schedule_files_by_date: # Later date: don't change the file we've already remembered, as # it's the latest one before the current date. Break. if date_for_fname > date: break # The file's date is less than or equal to the date we want. Keep # this file as a candidate for the schedule. schedule_file_path = try_schedule_file_path # Exact date: keep the file and break. XXX I suspect we don't need # this clause as it will all work anyway, but let's be explicit... if date_for_fname == date: break if schedule_file_path is None: schedule_from_file = [] else: schedule_from_file = read_schedule_file( date, schedule_file_path, dow=date.weekday(), require_dow=require_dow, ) pad_start = pad_end = 0 if config.has_option('main', 'padstart'): pad_start = config.getint('main', 'padstart') if config.has_option('main', 'padend'): pad_end = config.getint('main', 'padend') schedule = [] for details in schedule_from_file: if filter_items: for filter_item in filter_items: if filter_item == details['show'] \ or filter_item in details.get('presenters', []): break else: continue if details.get('pad_start') is None: details['pad_start'] = pad_start if details.get('pad_end') is None: details['pad_end'] = pad_end schedule.append(details) return schedule