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

202 lines
6 KiB
Text
Raw Permalink Normal View History

2018-10-12 16:17:17 +02:00
#!/usr/bin/env python3
#-*- coding: utf-8 -*-
"""
2018-10-12 20:19:23 +02:00
Get a fortune from a JSON file and say it.
2018-10-12 16:17:17 +02:00
File is under EUPL1.2
Author: kujiu
"""
import json
import argparse
import logging
2018-10-12 20:19:23 +02:00
import threading
2018-10-12 16:17:17 +02:00
import sys
import os.path
2018-10-19 18:49:48 +02:00
import secrets
2018-10-12 20:19:23 +02:00
try:
import speechd
except ImportError:
speechd = None
2018-10-12 16:17:17 +02:00
logger = logging.getLogger(__name__)
2018-10-12 20:19:23 +02:00
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)
2018-10-19 18:49:48 +02:00
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]
]
)
2018-10-12 20:19:23 +02:00
def get_quote(self):
"""
Get a quote, returns (quote, lang, author)
"""
2018-10-19 18:49:48 +02:00
by_category = getattr(options, 'by_category', False)
2018-10-12 20:19:23 +02:00
quote = ""
author = ""
lang = ""
2018-10-12 20:19:23 +02:00
count = 0
while not quote and count < 50:
count += 1
2018-10-19 18:49:48 +02:00
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])
2018-10-12 20:19:23 +02:00
return (quote, lang, author)
2018-10-19 18:49:48 +02:00
def say_quote(self, callback=None):
2018-10-12 20:19:23 +02:00
"""
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)
2018-10-19 18:49:48 +02:00
speech_client.set_synthesis_voice(secrets.choice(voices))
2018-10-12 20:19:23 +02:00
logger.info("Say: %s", quote)
2018-10-19 18:49:48 +02:00
speech_client.speak(quote, callback)
2018-10-12 20:19:23 +02:00
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:
2018-10-19 18:49:48 +02:00
self.say_quote(self.run if self.cycle else None)
2018-10-12 20:19:23 +02:00
else:
self.print_quote()
if self.cycle:
threading.Timer(self.timer, self.run).start()
2018-10-12 16:17:17 +02:00
if __name__ == '__main__':
2018-10-12 20:19:23 +02:00
parser = argparse.ArgumentParser(description="Print/say a quote from JSON file.")
2018-10-12 16:17:17 +02:00
parser.add_argument(
'-s', '--source', default='~/.local/share/json-fortune/fortunes.json',
2018-10-12 16:17:17 +02:00
help='JSON file with quotes')
2018-10-19 18:49:48 +02:00
parser.add_argument(
'-b', '--by_category', default=False, action='store_true',
help='Each category has the same weight')
2018-10-12 20:19:23 +02:00
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(
2018-10-19 18:49:48 +02:00
'-r', '--rate', default=15,
2018-10-12 20:19:23 +02:00
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)
2018-10-12 16:17:17 +02:00
options = parser.parse_args()
source = os.path.expanduser(
os.path.expandvars(options.source)
)
2018-10-12 20:19:23 +02:00
speak = getattr(options, 'speak', False)
module = getattr(options, 'module', None)
2018-10-19 18:49:48 +02:00
rate = getattr(options, 'rate', 15)
2018-10-12 20:19:23 +02:00
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()