diff --git a/common/.local/bin/json-fortune b/common/.local/bin/json-fortune index 3d6f7d4..eb26742 100755 --- a/common/.local/bin/json-fortune +++ b/common/.local/bin/json-fortune @@ -2,7 +2,7 @@ #-*- coding: utf-8 -*- """ -Get a fortune from a JSON file. +Get a fortune from a JSON file and say it. File is under EUPL1.2 Author: kujiu @@ -11,51 +11,167 @@ 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__) -ch = logging.StreamHandler(sys.stderr) -ch.setLevel(logging.WARNING) -logger.addHandler(ch) -def get_quote(srcfile): - """ - Get a quote - """ - with open(srcfile) as fin: - quotes = json.load(fin) +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' - quote = "" - count = 0 - while not quote and count < 50: - count += 1 - lang = random.choice([lang for lang in quotes.keys()]) - category = random.choice([cat for cat in quotes[lang].keys()]) - if not quotes[lang][category]: - continue - author = random.choice( - [author for author in quotes[lang][category].keys()]) - if not quotes[lang][category][author]: - continue - quote = random.choice(quotes[lang][category][author]) - if quote: - quote += "\n-- %s" % author + with open(srcfile) as fin: + self.quotes = json.load(fin) - return quote + 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="Get a quote from JSON file.") + parser = argparse.ArgumentParser(description="Print/say a quote from JSON file.") parser.add_argument( - '--source', default='~/.fortunes.json', + '-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) ) - print(get_quote(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() diff --git a/common/.local/bin/update-quotes b/common/.local/bin/update-quotes index 731e0e4..70de335 100755 --- a/common/.local/bin/update-quotes +++ b/common/.local/bin/update-quotes @@ -19,6 +19,7 @@ import wikiquote logger = logging.getLogger(__name__) ch = logging.StreamHandler(sys.stderr) +ch.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s')) ch.setLevel(logging.WARNING) logger.addHandler(ch) @@ -79,15 +80,25 @@ Source file must be a JSON in this format:\n '-v', '--verbose', help="Verbose mode", action='store_true') options = parser.parse_args() + class VerboseFilter(logging.Filter): + def filter(self, rec): + return rec.levelno in (logging.DEBUG, logging.INFO) + if hasattr(options, 'debug') and options.debug: 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) - if hasattr(options, 'verbose') and options.verbose: + elif hasattr(options, 'verbose') and options.verbose: ch = logging.StreamHandler(sys.stdout) + ch.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s')) ch.setLevel(logging.INFO) + ch.addFilter(VerboseFilter()) logger.addHandler(ch) + logger.setLevel(logging.INFO) source = os.path.expanduser( os.path.expandvars(options.source)