#!/usr/bin/env python3 #-*- coding: utf-8 -*- """ Get a fortune from a JSON file and say it. File is under EUPL1.2 Author: kujiu """ import json import argparse import logging import threading import sys import os.path import random try: import speechd except ImportError: speechd = None logger = logging.getLogger(__name__) class JsonFortune: def __init__(self, srcfile, speak, module, rate, cycle, timer): """ Fortune software """ self.speak = speak self.module = module self.rate = rate self.cycle = cycle self.timer = timer if not module: module = 'default' with open(srcfile) as fin: self.quotes = json.load(fin) def get_quote(self): """ Get a quote, returns (quote, lang, author) """ quote = "" count = 0 while not quote and count < 50: count += 1 lang = random.choice([lang for lang in self.quotes]) category = random.choice([cat for cat in self.quotes[lang]]) if not self.quotes[lang][category]: continue author = random.choice( [author for author in self.quotes[lang][category]]) if not self.quotes[lang][category][author]: continue quote = random.choice(self.quotes[lang][category][author]) return (quote, lang, author) def say_quote(self): """ Say a random quote """ quote, lang, author = self.get_quote() if not speechd: logger.error("Speech Dispatcher is not loaded.") return if not quote: logger.error("No quote found") return quote += "\n %s" % author speech_client = speechd.client.Client() speech_client.set_priority('important') speech_client.set_rate(self.rate) if self.module != 'default' and self.module: speech_client.set_output_module(self.module) voices = [ voice[0] for voice in speech_client.list_synthesis_voices() if voice[1] == lang] speech_client.set_language(lang) speech_client.set_synthesis_voice(random.choice(voices)) logger.info("Say: %s", quote) speech_client.say(quote) speech_client.close() def print_quote(self): """ Print a random quote. """ if self.cycle: print(chr(27) + "[2J") quote_dict = self.get_quote() if not quote_dict: logger.error("No quote found") return print(quote_dict[0] + "\n -- " + quote_dict[2]) def run(self): """ Run """ if self.speak: self.say_quote() else: self.print_quote() if self.cycle: threading.Timer(self.timer, self.run).start() if __name__ == '__main__': parser = argparse.ArgumentParser(description="Print/say a quote from JSON file.") parser.add_argument( '-s', '--source', default='~/.fortunes.json', help='JSON file with quotes') parser.add_argument( '-v', '--verbose', default=False, action='store_true', help='Verbose') parser.add_argument( '-k', '--speak', default=False, action='store_true', help='Say with Speech Dispatcher, otherwise print it') parser.add_argument( '-m', '--module', default='default', help='Speech Dispatcher output module') parser.add_argument( '-r', '--rate', default=20, help='Speech Dispatcher rate', type=int) parser.add_argument( '-c', '--cycle', default=False, action='store_true', help='Display/say fortunes in loop.') parser.add_argument( '-t', '--timer', default=60, help='Number of seconds between two quotes', type=int) options = parser.parse_args() source = os.path.expanduser( os.path.expandvars(options.source) ) speak = getattr(options, 'speak', False) module = getattr(options, 'module', None) rate = getattr(options, 'rate', 20) verbose = getattr(options, 'verbose', False) cycle = getattr(options, 'cycle', False) ch = logging.StreamHandler(sys.stderr) ch.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s')) ch.setLevel(logging.WARNING) logger.addHandler(ch) class VerboseFilter(logging.Filter): def filter(self, rec): return rec.levelno in (logging.DEBUG, logging.INFO) if verbose: ch = logging.StreamHandler(sys.stdout) ch.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s')) ch.setLevel(logging.DEBUG) ch.addFilter(VerboseFilter()) logger.addHandler(ch) logger.setLevel(logging.DEBUG) logger.addHandler(ch) fortune = JsonFortune(source, speak, module, rate, cycle, options.timer) fortune.run()