cromulant/cromulant/utils.py

212 lines
5.7 KiB
Python

from __future__ import annotations
import random
import colorsys
import time
from datetime import datetime
from typing import ClassVar
from wonderwords import RandomWord, RandomSentence # type: ignore
from fontTools.ttLib import TTFont # type: ignore
from .config import Config
class Utils:
names: ClassVar[list[str]] = []
countries: ClassVar[list[str]] = []
rand_word: RandomWord
rand_sentence: RandomSentence
vowels = "aeiou"
consonants = "bcdfghjklmnpqrstvwxyz"
@staticmethod
def prepare() -> None:
from .storage import Storage
Utils.names = Storage.get_names()
Utils.countries = Storage.get_countries()
Utils.rand_word = RandomWord()
Utils.rand_sentence = RandomSentence()
@staticmethod
def now() -> int:
return int(time.time())
@staticmethod
def singular_or_plural(num: float, singular: str, plural: str) -> str:
if num == 1:
return singular
return plural
@staticmethod
def time_ago(start_time: float, end_time: float) -> str:
diff = end_time - start_time
seconds = int(diff)
if seconds < 60:
word = Utils.singular_or_plural(seconds, "second", "seconds")
return f"{seconds} {word} ago"
minutes = seconds // 60
if minutes < 60:
word = Utils.singular_or_plural(minutes, "minute", "minutes")
return f"{minutes} {word} ago"
hours = minutes / 60
if hours < 24:
word = Utils.singular_or_plural(hours, "hour", "hours")
return f"{hours:.1f} {word} ago"
days = hours / 24
if days < 30:
word = Utils.singular_or_plural(days, "day", "days")
return f"{days:.1f} {word} ago"
months = days / 30
if months < 12:
word = Utils.singular_or_plural(months, "month", "months")
return f"{months:.1f} {word} ago"
years = months / 12
word = Utils.singular_or_plural(years, "year", "years")
return f"{years:.1f} {word} ago"
@staticmethod
def print(text: str) -> None:
print(text) # noqa: T201
@staticmethod
def random_color(seed: str) -> tuple[int, int, int]:
seed_int = hash(seed)
random.seed(seed_int)
h, s, l = (
random.random(),
0.5 + random.random() / 2.0,
0.4 + random.random() / 5.0,
)
r, g, b = (int(256 * i) for i in colorsys.hls_to_rgb(h, l, s))
return r, g, b
@staticmethod
def random_name(ignore: list[str], include: list[str] | None = None) -> str:
names = Utils.names
if include:
for name in include:
if name not in names:
names.append(name)
filtered = [name for name in Utils.names if name not in ignore]
if not filtered:
return Utils.make_name()
return random.choice(filtered)
@staticmethod
def get_rgb(color: tuple[int, int, int]) -> str:
return f"rgb{color}"
@staticmethod
def random_character(font_path: str, num: int) -> str:
font = TTFont(font_path)
cmap = font["cmap"]
unicode_map = cmap.getBestCmap()
characters = [chr(code_point) for code_point in unicode_map]
for _ in range(10): # Try up to 10 times
selected = random.sample(characters, num)
if all((char.isprintable() and not char.isspace()) for char in selected):
return " ".join(selected)
return ""
@staticmethod
def random_emoji(num: int) -> str:
return Utils.random_character(str(Config.emoji_font_path), num)
@staticmethod
def to_date(timestamp: float) -> str:
dt_object = datetime.fromtimestamp(timestamp)
hour = dt_object.strftime("%I").lstrip("0")
return dt_object.strftime(f"%b %d %Y - {hour}:%M %p")
@staticmethod
def get_seconds(msecs: int) -> str:
seconds = msecs // 1000
if seconds < 60:
return f"{seconds} seconds"
minutes = seconds // 60
if minutes == 1:
return "1 minute"
return f"{minutes} minutes"
@staticmethod
def random_country(ignore: list[str]) -> str:
filtered = [country for country in Utils.countries if country not in ignore]
return random.choice(filtered)
@staticmethod
def random_word() -> str:
word = Utils.rand_word.word(
include_parts_of_speech=["nouns", "adjectives"], word_max_length=8
)
return str(word)
@staticmethod
def random_words(num: int = 1) -> list[str]:
return [Utils.random_word() for _ in range(num)]
@staticmethod
def capitalize(word: str) -> str:
return word[0].upper() + word[1:]
@staticmethod
def words_1() -> str:
return str(Utils.rand_sentence.simple_sentence())
@staticmethod
def words_2() -> str:
return str(Utils.rand_sentence.bare_bone_sentence())
@staticmethod
def words_3() -> str:
return str(Utils.rand_sentence.bare_bone_with_adjective())
@staticmethod
def words_4() -> str:
return str(Utils.rand_sentence.sentence())
@staticmethod
def make_word() -> str:
name = ""
name += random.choice(Utils.consonants)
name += random.choice(Utils.vowels)
name += random.choice(Utils.consonants)
name += random.choice(Utils.vowels)
return name
@staticmethod
def make_words(num: int = 1) -> list[str]:
return [Utils.make_word() for _ in range(num)]
@staticmethod
def make_name() -> str:
words = Utils.make_words(2)
words = [word.capitalize() for word in words]
return " ".join(words)