2025-02-13 14:51:35 -05:00
|
|
|
import os
|
|
|
|
import logging
|
|
|
|
import traceback
|
|
|
|
import random
|
|
|
|
import datetime
|
|
|
|
import pytz
|
2025-03-12 09:37:44 -04:00
|
|
|
from typing import Optional, LiteralString, Union
|
2025-02-13 14:51:35 -05:00
|
|
|
import regex
|
|
|
|
import aiosqlite as sqlite3
|
|
|
|
from aiohttp import ClientSession, ClientTimeout
|
|
|
|
from bohancompliment import ComplimentGenerator
|
|
|
|
from discord import Embed
|
|
|
|
|
|
|
|
class Util:
|
|
|
|
"""Misc Utility"""
|
|
|
|
def __init__(self) -> None:
|
|
|
|
self.URL_URBANDICTIONARY: str = "http://api.urbandictionary.com/v0/define"
|
|
|
|
self.URL_INSULTAPI: str = "https://insult.mattbas.org/api/insult"
|
|
|
|
self.COMPLIMENT_GENERATOR = ComplimentGenerator()
|
2025-02-15 13:57:47 -05:00
|
|
|
self.dbs: dict[str, str|LiteralString] = {
|
2025-02-13 14:51:35 -05:00
|
|
|
'whisky': os.path.join("/usr/local/share",
|
|
|
|
"sqlite_dbs", "whiskey.db"),
|
|
|
|
'drinks': os.path.join("/usr/local/share",
|
|
|
|
"sqlite_dbs", "cocktails.db"),
|
|
|
|
'strains': os.path.join("/usr/local/share",
|
|
|
|
"sqlite_dbs", "strains.db"),
|
|
|
|
'qajoke': os.path.join("/usr/local/share",
|
|
|
|
"sqlite_dbs", "qajoke.db"),
|
|
|
|
'rjokes': os.path.join("/usr/local/share",
|
|
|
|
"sqlite_dbs", "rjokes.db"),
|
|
|
|
'randmsg': os.path.join("/usr/local/share",
|
|
|
|
"sqlite_dbs", "randmsg.db"),
|
|
|
|
'stats': os.path.join("/usr/local/share",
|
|
|
|
"sqlite_dbs", "havoc_stats.db"),
|
|
|
|
'cookies': os.path.join("/usr/local/share",
|
|
|
|
"sqlite_dbs", "cookies.db"),
|
|
|
|
}
|
|
|
|
self.COFFEES: list = ['a cup of french-pressed coffee', 'a cup of cold brew', 'a cup of flash brew',
|
|
|
|
'a cup of Turkish coffee', 'a cup of Moka', 'an espresso',
|
|
|
|
'a cup of Nescafe coffee',
|
|
|
|
'an iced coffee', 'a Frappé', 'a freddo cappuccino',
|
|
|
|
'a cup of Chock full o\'Nuts', 'a cup of Folgers', 'a cup of Lavazza',
|
|
|
|
'a cup of Maxwell House', 'a cup of Moccona', 'a cup of Mr. Brown Coffee',
|
|
|
|
'a cup of affogato al caffè',
|
|
|
|
'a cup of Caffè Medici', 'a cup of Café Touba',
|
|
|
|
'a double-double', 'an indian filter coffee', 'a cup of pocillo',
|
|
|
|
'a cup of caffè americano', 'a cup of caffè lungo', 'a latte', 'a manilo',
|
|
|
|
'a flat white', 'a cup of café cubano', 'a cup of caffè crema',
|
|
|
|
'a cup of cafe zorro', 'an espresso roberto', 'an espresso romano',
|
|
|
|
'an espresso sara', 'a guillermo', 'a ristretto', 'a cup of melya',
|
|
|
|
'a cup of caffè marocchino', 'a cup of café miel', 'a cup of café de olla',
|
|
|
|
'a Mazagran', 'a Palazzo', 'an ice shot']
|
|
|
|
self.LAST_5_COFFEES: list = []
|
|
|
|
|
|
|
|
|
|
|
|
def tdTuple(self, td:datetime.timedelta) -> tuple:
|
|
|
|
"""
|
|
|
|
Create TimeDelta Tuple
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
td (datetime.timedelta)
|
|
|
|
Returns:
|
|
|
|
tuple
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
def _t(t, n):
|
|
|
|
if t < n:
|
|
|
|
return (t, 0)
|
|
|
|
v = t//n
|
|
|
|
return (t - (v * n), v)
|
|
|
|
(s, h) = _t(td.seconds, 3600)
|
|
|
|
(s, m) = _t(s, 60)
|
|
|
|
(mics, mils) = _t(td.microseconds, 1000)
|
|
|
|
return (td.days, h, m, s, mics, mils)
|
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
async def get_counter(self, counter: Optional[str] = None) -> Optional[dict]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get Counter
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
counter (Optional[str])
|
|
|
|
Returns:
|
2025-02-15 13:57:47 -05:00
|
|
|
Optional[dict]
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
2025-02-15 13:57:47 -05:00
|
|
|
stats_db: str|LiteralString = self.dbs.get('stats', '')
|
|
|
|
if not stats_db:
|
|
|
|
return None
|
|
|
|
async with sqlite3.connect(stats_db,
|
2025-02-13 14:51:35 -05:00
|
|
|
timeout=3) as db_conn:
|
2025-02-15 13:57:47 -05:00
|
|
|
db_conn.row_factory = sqlite3.Row
|
2025-02-13 14:51:35 -05:00
|
|
|
query: str = "SELECT ? FROM stats LIMIT 1"
|
|
|
|
if not counter:
|
2025-02-15 13:57:47 -05:00
|
|
|
query = "SELECT * FROM stats LIMIT 1"
|
2025-02-13 14:51:35 -05:00
|
|
|
async with await db_conn.execute(query, (counter,) if counter else None) as db_cursor:
|
2025-02-15 13:57:47 -05:00
|
|
|
result = await db_cursor.fetchone()
|
2025-02-13 14:51:35 -05:00
|
|
|
return result
|
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
async def get_stats_embed(self) -> Optional[Embed]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get Stats Embed
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Returns:
|
2025-02-15 13:57:47 -05:00
|
|
|
Optional[Embed]
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
2025-02-15 13:57:47 -05:00
|
|
|
counters: Optional[dict] = await self.get_counter()
|
|
|
|
if not counters:
|
|
|
|
return None
|
2025-02-13 14:51:35 -05:00
|
|
|
embed: Embed = Embed(title="Stats")
|
|
|
|
counter_message: str = ""
|
|
|
|
counters_sorted: dict = dict(sorted(counters.items(),
|
|
|
|
key=lambda item: item[1], reverse=True))
|
|
|
|
for counter, value in counters_sorted.items():
|
2025-02-15 13:57:47 -05:00
|
|
|
counter = regex.sub(r'_', ' ',
|
2025-02-13 14:51:35 -05:00
|
|
|
counter.strip()).title()
|
|
|
|
counter_message += f"- {value} {counter}\n"
|
|
|
|
embed.description = counter_message.strip()
|
|
|
|
return embed
|
|
|
|
|
|
|
|
async def increment_counter(self, counter: str) -> bool:
|
|
|
|
"""
|
|
|
|
Increment Counter
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
counter (str)
|
|
|
|
Returns:
|
|
|
|
bool
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
2025-02-15 13:57:47 -05:00
|
|
|
stats_db: str|LiteralString = self.dbs.get('stats', '')
|
|
|
|
if not stats_db:
|
|
|
|
return False
|
|
|
|
async with sqlite3.connect(stats_db,
|
2025-02-13 14:51:35 -05:00
|
|
|
timeout=3) as db_conn:
|
|
|
|
async with await db_conn.execute(f"UPDATE stats SET {counter} = {counter} + 1") as db_cursor:
|
|
|
|
if db_cursor.rowcount < 0:
|
|
|
|
logging.critical("[karma::increment_counter] Fail! %s", db_cursor.rowcount)
|
|
|
|
return False
|
|
|
|
await db_conn.commit()
|
|
|
|
return True
|
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
async def get_ud_def(self, term: str) -> tuple[str, str]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get Definition from UD
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
2025-02-15 13:57:47 -05:00
|
|
|
term (str)
|
2025-02-13 14:51:35 -05:00
|
|
|
Returns:
|
|
|
|
tuple[str, str]
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
try:
|
|
|
|
async with ClientSession() as session:
|
|
|
|
async with await session.get(self.URL_URBANDICTIONARY,
|
|
|
|
params={
|
|
|
|
"term": term,
|
|
|
|
},
|
|
|
|
headers = {
|
|
|
|
'content-type': 'application/json; charset=utf-8',
|
|
|
|
}, timeout=ClientTimeout(connect=5, sock_read=5)) as request:
|
|
|
|
logging.debug("UD returned: %s",
|
|
|
|
await request.text())
|
|
|
|
data: dict = await request.json()
|
|
|
|
if "list" in data:
|
|
|
|
definitions: list[dict] = data["list"]
|
|
|
|
if definitions:
|
|
|
|
definition: dict = definitions[0]
|
|
|
|
definition_word: str = definition.get("word", "N/A")
|
|
|
|
definition_text: str = regex.sub(r'(\r|\n|\r\n)', ' ', definition["definition"].strip())
|
|
|
|
return (definition_word, definition_text) # Tuple: Returned word, returned definition
|
|
|
|
else:
|
|
|
|
return (term, "Not found!")
|
|
|
|
else:
|
|
|
|
return (term, "Error retrieving data from Urban Dictionary")
|
|
|
|
except Exception as e:
|
|
|
|
traceback.print_exc()
|
|
|
|
return (term, f"ERR: {str(e)}")
|
|
|
|
|
|
|
|
async def get_insult(self, recipient: str) -> str:
|
|
|
|
"""
|
|
|
|
Get Insult
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
recipient (str)
|
|
|
|
Returns:
|
|
|
|
str
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
async with ClientSession() as session:
|
|
|
|
async with await session.get(f"{self.URL_INSULTAPI}?who={recipient}") as request:
|
|
|
|
request.raise_for_status()
|
|
|
|
return await request.text()
|
|
|
|
|
|
|
|
|
|
|
|
async def get_compliment(self, subject: str,
|
|
|
|
language: Optional[str] = None) -> str:
|
|
|
|
"""
|
|
|
|
Get Compliment
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
subject (str)
|
|
|
|
language (Optional[str])
|
|
|
|
Returns:
|
|
|
|
str
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
if not language:
|
|
|
|
return self.COMPLIMENT_GENERATOR.compliment(subject)
|
|
|
|
return self.COMPLIMENT_GENERATOR.compliment_in_language(subject, language)
|
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
async def get_whisky(self) -> Optional[tuple]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get Whisky
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Returns:
|
2025-02-15 13:57:47 -05:00
|
|
|
Optional[tuple]
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
"""
|
|
|
|
whisky_db: str|LiteralString = self.dbs.get('whisky', '')
|
|
|
|
if not whisky_db:
|
|
|
|
return None
|
|
|
|
async with sqlite3.connect(database=whisky_db,
|
|
|
|
timeout=2) as db_conn:
|
|
|
|
db_query: str = "SELECT name, category, description FROM whiskeys ORDER BY random() LIMIT 1"
|
|
|
|
async with await db_conn.execute(db_query) as db_cursor:
|
|
|
|
db_result: Optional[Union[sqlite3.Row, tuple]] = await db_cursor.fetchone()
|
|
|
|
if not db_result:
|
|
|
|
return None
|
|
|
|
(name, category, description) = db_result
|
|
|
|
name = regex.sub(r'(^\p{White_Space}|\r|\n)', '',
|
2025-02-13 14:51:35 -05:00
|
|
|
regex.sub(r'\p{White_Space}{2,}', ' ',
|
2025-02-15 13:57:47 -05:00
|
|
|
name.strip()))
|
|
|
|
category = regex.sub(r'(^\p{White_Space}|\r|\n)', '',
|
|
|
|
regex.sub(r'\p{White_Space}{2,}', ' ',
|
|
|
|
category.strip()))
|
|
|
|
description = regex.sub(r'(^\p{White_Space}|\r|\n)', '',
|
|
|
|
regex.sub(r'\p{White_Space}{2,}', ' ',
|
|
|
|
description.strip()))
|
|
|
|
return (name, category, description)
|
2025-02-13 14:51:35 -05:00
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
async def get_drink(self) -> Optional[tuple]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get Drink
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Returns:
|
2025-02-15 13:57:47 -05:00
|
|
|
Optional[tuple]
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
"""
|
|
|
|
drinks_db: str|LiteralString = self.dbs.get('drinks', '')
|
|
|
|
if not drinks_db:
|
|
|
|
return None
|
|
|
|
async with sqlite3.connect(database=drinks_db,
|
|
|
|
timeout=2) as db_conn:
|
|
|
|
db_query: str = "SELECT name, ingredients FROM cocktails ORDER BY random() LIMIT 1"
|
|
|
|
async with await db_conn.execute(db_query) as db_cursor:
|
|
|
|
db_result: tuple = await db_cursor.fetchone()
|
|
|
|
|
|
|
|
(name, ingredients) = db_result
|
|
|
|
name = regex.sub(r'(^\p{White_Space}|\r|\n)', '', regex.sub(r'\p{White_Space}{2,}', ' ', name.strip()))
|
|
|
|
ingredients = regex.sub(r'(^\p{White_Space}|\r|\n)', '', regex.sub(r'\p{White_Space}{2,}', ' ', ingredients.strip()))
|
|
|
|
ingredients = regex.sub(r'\*', '\u2731', ingredients.strip())
|
|
|
|
return (name, ingredients)
|
2025-02-13 14:51:35 -05:00
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
async def get_strain(self, strain: Optional[str] = None) -> Optional[tuple]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get Strain
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
strain (Optional[str])
|
|
|
|
Returns:
|
2025-02-15 13:57:47 -05:00
|
|
|
Optional[tuple]
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
"""
|
|
|
|
strains_db: str|LiteralString = self.dbs.get('strains', '')
|
|
|
|
if not strains_db:
|
|
|
|
return None
|
|
|
|
async with sqlite3.connect(database=strains_db,
|
|
|
|
timeout=2) as db_conn:
|
|
|
|
db_params: Optional[tuple] = None
|
|
|
|
if not strain:
|
|
|
|
db_query: str = "SELECT name, description FROM strains_w_desc ORDER BY random() LIMIT 1"
|
|
|
|
else:
|
|
|
|
db_query = "SELECT name, description FROM strains_w_desc WHERE name LIKE ?"
|
|
|
|
db_params = (f"%{strain.strip()}%",)
|
|
|
|
async with await db_conn.execute(db_query, db_params) as db_cursor:
|
|
|
|
db_result: Optional[tuple] = await db_cursor.fetchone()
|
|
|
|
return db_result
|
2025-02-13 14:51:35 -05:00
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
async def get_qajoke(self) -> Optional[tuple]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get QA Joke
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Returns:
|
2025-02-15 13:57:47 -05:00
|
|
|
Optional[tuple]
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
"""
|
|
|
|
qajoke_db: str|LiteralString = self.dbs.get('qajoke', '')
|
|
|
|
if not qajoke_db:
|
|
|
|
return None
|
|
|
|
async with sqlite3.connect(database=qajoke_db,
|
|
|
|
timeout=2) as db_conn:
|
|
|
|
db_query: str = "SELECT question, answer FROM jokes ORDER BY RANDOM() LIMIT 1"
|
|
|
|
async with await db_conn.execute(db_query) as cursor:
|
2025-02-13 14:51:35 -05:00
|
|
|
(question, answer) = await cursor.fetchone()
|
|
|
|
return (question, answer)
|
|
|
|
return None
|
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
async def get_rjoke(self) -> Optional[tuple]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get r/joke Joke
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Returns:
|
2025-02-15 13:57:47 -05:00
|
|
|
Optional[tuple]
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
"""
|
|
|
|
rjokes_db: str|LiteralString = self.dbs.get('rjokes', '')
|
|
|
|
if not rjokes_db:
|
|
|
|
return None
|
|
|
|
async with sqlite3.connect(database=rjokes_db, timeout=2) as db_conn:
|
|
|
|
db_query: str = "SELECT title, body, score FROM jokes WHERE score >= 100 ORDER BY RANDOM() LIMIT 1'"
|
|
|
|
async with await db_conn.execute(db_query) as cursor:
|
2025-02-13 14:51:35 -05:00
|
|
|
(title, body, score) = await cursor.fetchone()
|
|
|
|
return (title, body, score)
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
async def get_random_fact(self) -> str:
|
|
|
|
"""
|
|
|
|
Get Random Fact
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Returns:
|
|
|
|
str
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
try:
|
|
|
|
facts_api_url: str = "https://uselessfacts.jsph.pl/api/v2/facts/random"
|
|
|
|
facts_backup_url: str = "https://cnichols1734.pythonanywhere.com/facts/random"
|
|
|
|
async with ClientSession() as client:
|
|
|
|
try:
|
|
|
|
async with await client.get(facts_api_url,
|
|
|
|
timeout=ClientTimeout(connect=5, sock_read=5)) as request:
|
2025-02-15 13:57:47 -05:00
|
|
|
_json: dict = await request.json()
|
|
|
|
fact: str = _json.get('text', None)
|
2025-02-13 14:51:35 -05:00
|
|
|
if not fact:
|
|
|
|
raise BaseException("RandFact Src 1 Failed")
|
|
|
|
return fact
|
|
|
|
except:
|
|
|
|
async with await client.get(facts_backup_url,
|
|
|
|
timeout=ClientTimeout(connect=5, sock_read=5)) as request:
|
2025-02-15 13:57:47 -05:00
|
|
|
_json = await request.json()
|
|
|
|
fact = _json.get('fact', None)
|
2025-02-13 14:51:35 -05:00
|
|
|
return fact
|
|
|
|
except Exception as e:
|
|
|
|
traceback.print_exc()
|
|
|
|
return f"Failed to get a random fact :( [{str(e)}]"
|
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
async def get_cookie(self) -> Optional[dict]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get Cookie
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Returns:
|
2025-02-15 13:57:47 -05:00
|
|
|
Optional[dict]
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
"""
|
|
|
|
cookies_db = self.dbs.get('cookies', '')
|
|
|
|
if not cookies_db:
|
|
|
|
return None
|
|
|
|
async with sqlite3.connect(cookies_db,
|
|
|
|
timeout=2) as db_conn:
|
|
|
|
db_query: str = "SELECT name, origin, image_url FROM cookies ORDER BY RANDOM() LIMIT 1"
|
|
|
|
async with await db_conn.execute(db_query) as db_cursor:
|
2025-02-13 14:51:35 -05:00
|
|
|
(name, origin, image_url) = await db_cursor.fetchone()
|
|
|
|
return {
|
|
|
|
'name': name,
|
|
|
|
'origin': origin,
|
|
|
|
'image_url': image_url
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2025-02-24 06:21:56 -05:00
|
|
|
def get_coffee(self,
|
|
|
|
recipient_allergic: Optional[bool] = False) -> Optional[str]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get Coffee
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-24 06:21:56 -05:00
|
|
|
Args:
|
|
|
|
recipient_allergic (bool): Is the recipient allergic? (so we know when to keep our nuts out of it)
|
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Returns:
|
|
|
|
str
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
try:
|
|
|
|
randomCoffee: str = random.choice(self.COFFEES)
|
2025-02-24 06:21:56 -05:00
|
|
|
if self.LAST_5_COFFEES and randomCoffee in self.LAST_5_COFFEES\
|
|
|
|
or (recipient_allergic and "nut" in randomCoffee.lower()):
|
2025-02-13 14:51:35 -05:00
|
|
|
return self.get_coffee() # Recurse
|
|
|
|
if len(self.LAST_5_COFFEES) >= 5:
|
|
|
|
self.LAST_5_COFFEES.pop() # Store no more than 5 of the last served coffees
|
|
|
|
self.LAST_5_COFFEES.append(randomCoffee)
|
|
|
|
return randomCoffee
|
|
|
|
except:
|
|
|
|
traceback.print_exc()
|
2025-02-15 13:57:47 -05:00
|
|
|
return None
|
2025-02-13 14:51:35 -05:00
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
def get_days_to_xmas(self) -> Optional[tuple]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get # of Days until Xmas
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Returns:
|
2025-02-15 13:57:47 -05:00
|
|
|
Optional[tuple]
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
2025-02-15 13:57:47 -05:00
|
|
|
today: datetime.datetime = datetime.datetime.now(tz=pytz.UTC)
|
|
|
|
xmas: datetime.datetime = datetime.datetime(
|
2025-02-13 14:51:35 -05:00
|
|
|
year=today.year,
|
|
|
|
month=12,
|
|
|
|
day=25,
|
|
|
|
tzinfo=pytz.UTC,
|
|
|
|
)
|
2025-03-12 09:37:44 -04:00
|
|
|
td: datetime.timedelta = (xmas - today)
|
2025-02-13 14:51:35 -05:00
|
|
|
days, hours, minutes, seconds, us, ms = self.tdTuple(td)
|
|
|
|
|
|
|
|
return (days, hours, minutes, seconds, ms, us)
|
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
async def get_randmsg(self) -> Optional[str]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get Random Message from randmsg.db
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Returns:
|
2025-02-15 13:57:47 -05:00
|
|
|
Optional[str]
|
2025-02-16 20:07:02 -05:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
2025-02-15 13:57:47 -05:00
|
|
|
randmsg_db: str|LiteralString = self.dbs.get('randmsg', '')
|
|
|
|
if not randmsg_db:
|
|
|
|
return None
|
2025-02-13 14:51:35 -05:00
|
|
|
async with sqlite3.connect(database=randmsg_db,
|
|
|
|
timeout=2) as db_conn:
|
2025-02-15 13:57:47 -05:00
|
|
|
db_query: str = "SELECT msg FROM msgs ORDER BY RANDOM() LIMIT 1"
|
|
|
|
async with await db_conn.execute(db_query) as db_cursor:
|
2025-02-13 14:51:35 -05:00
|
|
|
(result,) = await db_cursor.fetchone()
|
|
|
|
return result
|