homes/common/.local/bin/json-fortune

201 lines
6 KiB
Python
Executable file

#!/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 secrets
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)
by_category = getattr(options, 'by_category', False)
if not by_category:
self.uncategorized_quotes = {}
for lang in self.quotes:
self.uncategorized_quotes.setdefault(lang, [])
for category in self.quotes[lang]:
for author in self.quotes[lang][category]:
self.uncategorized_quotes[lang].extend(
[
(quote, author)
for quote
in self.quotes[lang][category][author]
]
)
def get_quote(self):
"""
Get a quote, returns (quote, lang, author)
"""
by_category = getattr(options, 'by_category', False)
quote = ""
author = ""
lang = ""
count = 0
while not quote and count < 50:
count += 1
lang = secrets.choice([lang for lang in self.quotes])
if by_category:
category = secrets.choice([cat for cat in self.quotes[lang]])
if not self.quotes[lang][category]:
continue
author = secrets.choice(
[author for author in self.quotes[lang][category]])
if not self.quotes[lang][category][author]:
continue
quote = secrets.choice(self.quotes[lang][category][author])
else:
quote, author = secrets.choice(self.uncategorized_quotes[lang])
return (quote, lang, author)
def say_quote(self, callback=None):
"""
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(secrets.choice(voices))
logger.info("Say: %s", quote)
speech_client.speak(quote, callback)
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(self.run if self.cycle else None)
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='~/.local/share/json-fortune/fortunes.json',
help='JSON file with quotes')
parser.add_argument(
'-b', '--by_category', default=False, action='store_true',
help='Each category has the same weight')
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=15,
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', 15)
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()