litime 0.8.2

A command line tool to display the current time ish with a literature quote
Documentation
import json
from collections import defaultdict
import datetime as dt
import html
import os

times = defaultdict(list)
# folder containing XX:XX.json files
path_to_files = "/tmp/literature-clock/docs/times"

TEMPLATE = """/// DO NOT MODIFY
/// THIS FILE IS GENERATED BY RUNNING ./script.py FROM REPO ROOT

use anyhow::{{bail, Context, Result}};
use rand::seq::SliceRandom;

pub struct Minute<'a> {{
    pub title: &'a str,
    pub author: &'a str,
    pub start: &'a str,
    pub time: &'a str,
    pub end: &'a str,
}}

{minutes}

pub fn get_minute<'a>(time: &str) -> Result<&'a Minute> {{
    #[rustfmt::skip]
    let options = match time {{
{matches}
        _ => bail!("Couldn't match timestamp!"),
    }};

    let quote = options.choose(&mut rand::thread_rng()).context("Unable to choose a random quote")?;

    Ok(quote)
}}
"""

REPLACES = [
    ('"', '\\"'),
    ("<br>", "\\n"),
    ("<br/>", "\\n"),
    ("<br />", "\\n"),
    ("\\n ", "\\n"),
]


def prep(section: str) -> str:
    value = html.unescape(section)
    for from_str, to_str in REPLACES:
        value = value.replace(from_str, to_str)

    return value


malformed_timestamps = []

for json_file in sorted(os.listdir(path_to_files)):
    with open(os.path.join(path_to_files, json_file), "r") as f:
        timestamp = json_file.split(".")[0].replace("_", ":")
        for d in json.load(f):
            if "|" in d["quote_last"]:
                print(f"{timestamp} has malformed quote last. skipping")
                continue
            try:
                times[timestamp].append(
                    {
                        "start": prep(d["quote_first"]),
                        "time": prep(d["quote_time_case"]),
                        "end": prep(d["quote_last"]),
                        "title": prep(d["title"]),
                        "author": prep(d["author"]),
                    }
                )
            except KeyError as e:
                print(f"{timestamp} missing key: {e}")
                print(d)


minutes = []
matches = []


def get_next_ts(ts: str) -> str:
    """Return a timestamp for minute later

    For example:
        00:13 -> 00:14
        00:59 -> 01:00
        23:59 -> 00:00
    """
    dummy_dt = dt.datetime.fromisoformat(f"2000-01-01T{ts}") + dt.timedelta(minutes=1)
    return dummy_dt.strftime("%H:%M")


for timestamp, quotes in times.items():
    var_names = []
    for idx, quote in enumerate(quotes):
        var_name = f"QUOTE_{timestamp.replace(':', '_')}_{idx}"
        var_names.append(f"&{var_name}")
        minutes.append(
            f"static {var_name}: Minute = Minute {{"
            f"title: \"{quote['title']}\", "
            f"author: \"{quote['author']}\", "
            f"start: \"{quote['start']}\", "
            f"time: \"{quote['time']}\", "
            f"end: \"{quote['end']}\""
            "};",
        )
    timestamps = [timestamp]
    # Check if we need to fill future gaps
    timestamp = get_next_ts(timestamp)
    while timestamp not in times:
        timestamps.append(timestamp)
        timestamp = get_next_ts(timestamp)

    joined_timestamps = '" | "'.join(timestamps)
    joined_varnames = ", ".join(var_names)

    matches.append(f'        "{joined_timestamps}" => vec![{joined_varnames}],')


with open("./src/minute.rs", "w") as f:
    f.write(TEMPLATE.format(minutes="\n".join(minutes), matches="\n".join(matches)))