Created
April 28, 2025 16:41
-
-
Save AlphaGameDeveloper/ae5fba1704e05b69a6966eb8789e7808 to your computer and use it in GitHub Desktop.
San Marin High School bell schedule CLI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import datetime | |
import sys | |
import argparse | |
import json | |
def time_until_next_bell(schedule, current_time): | |
verbose(f"Calculating time until next bell from {current_time}") | |
for i, period in enumerate(schedule): | |
if len(period) == 2: # Only the name and start time | |
bell_time = datetime.datetime.strptime(period[1], "%H:%M").time() | |
else: # Name, start time, and end time | |
bell_time = datetime.datetime.strptime(period[1], "%H:%M").time() | |
verbose(f"Checking bell time {bell_time} for period {period[0]}") | |
if current_time < bell_time: | |
time_diff = (datetime.datetime.combine(date, bell_time) - datetime.datetime.combine(date, current_time)).total_seconds() / 60 | |
verbose(f"Next bell is for {period[0]} at {bell_time}, in {time_diff:.0f} minutes") | |
return time_diff, period, i | |
verbose("No more bells found for today") | |
return None, None, None | |
def load_fancy_names(writeIfNotFound=False): | |
config_file = "/opt/smhs-bell.json" | |
verbose("Checking for configuration file '" + config_file + "'") | |
default = { | |
"Period 1": "Period 1", | |
"Period 2": "Period 2", | |
"Period 3": "Period 3", | |
"Period 4": "Period 4", | |
"Period 5": "Period 5", | |
"Period 6": "Period 6", | |
"Period 7": "Period 7", | |
"Warning Bell": "Warning Bell", | |
"Break": "Break", | |
"Lunch": "Lunch", | |
"Access": "Access", | |
"Rally": "Rally" | |
} | |
try: | |
with open(config_file, "r") as f: | |
fancy_names = json.load(f) | |
verbose("Fancy names loaded successfully") | |
except FileNotFoundError: | |
verbose("Configuration file not found, using default names") | |
if writeIfNotFound: | |
verbose("Creating default configuration file") | |
with open(config_file, "w") as f: | |
json.dump(default, f, indent=4) | |
fancy_names = default | |
else: | |
verbose("Default names will be used") | |
fancy_names = default | |
fancy_names = {} | |
except json.JSONDecodeError: | |
verbose("Error decoding JSON from configuration file, using default names") | |
fancy_names = {} | |
except Exception as e: | |
verbose(f"Unexpected error: {e}") | |
fancy_names = {} | |
return fancy_names | |
def verbose(message): | |
"""Prints a message if verbose mode is enabled.""" | |
if args.verbose: | |
print("Verbose: ", message) | |
if __name__ == "__main__": | |
# Set up argument parser | |
parser = argparse.ArgumentParser(description="Bell schedule for San Marin High School.") | |
parser.add_argument("-d", "--date", type=str, help="Date in YYYY-MM-DD format") | |
parser.add_argument("-t", "--time", type=str, help="Time in HH:MM format") | |
parser.add_argument("-r", "--rally", action="store_true", help="Rally day schedule") | |
parser.add_argument("-m", "--minimum", action="store_true", help="Minimum day schedule") | |
parser.add_argument("-v", "--verbose", action="store_true", help="Verbose output") | |
parser.add_argument("-c", "--config", action="store_true", help="Create default configuration file if not found") | |
args = parser.parse_args() | |
verbose("Arguments parsed") | |
# Get the current date and time if not provided | |
if args.date: | |
date = datetime.datetime.strptime(args.date, "%Y-%m-%d").date() | |
verbose(f"Using provided date: {date}") | |
else: | |
date = datetime.date.today() | |
verbose(f"Using current date: {date}") | |
if args.time: | |
time = datetime.datetime.strptime(args.time, "%H:%M").time() | |
verbose(f"Using provided time: {time}") | |
else: | |
time = datetime.datetime.now().time() | |
verbose(f"Using current time: {time}") | |
# Get the day of the week (0=Monday, 6=Sunday) | |
day_of_week = date.weekday() | |
verbose(f"Day of week: {day_of_week} ({date.strftime('%A')})") | |
# store the bell schedule in a dictionary | |
verbose("Loading bell schedule") | |
bell_schedule = { | |
"Monday": [ | |
("Warning Bell", "08:25"), | |
("Period 1", "08:30", "09:20"), | |
("Period 2", "09:25", "10:15"), | |
("Break", "10:15", "10:25"), | |
("Period 3", "10:30", "11:20"), | |
("Period 4", "11:25", "12:20"), | |
("Lunch", "12:20", "12:55"), | |
("Period 5", "13:00", "13:50"), | |
("Period 6", "13:55", "14:45"), | |
("Period 7", "14:50", "15:40") | |
], | |
"Tuesday": [ | |
("Warning Bell", "08:25"), | |
("Period 1", "08:30", "10:00"), | |
("Break", "10:00", "10:10"), | |
("Period 3", "10:15", "11:45"), | |
("Lunch", "11:45", "12:20"), | |
("Period 5", "12:25", "13:55"), | |
("Break", "13:55", "14:05"), | |
("Period 7", "14:10", "15:40") | |
], | |
"Wednesday": [ | |
("Warning Bell", "08:25"), | |
("Period 2", "08:30", "10:00"), | |
("Access", "10:05", "10:55"), | |
("Break", "10:55", "11:05"), | |
("Period 4", "11:10", "12:40"), | |
("Lunch", "12:40", "13:15"), | |
("Period 6", "13:20", "14:50"), | |
("Staff Meetings", "15:00", "15:45") | |
], | |
"Thursday": [ | |
("Warning Bell", "08:25"), | |
("Period 1", "08:30", "09:20"), | |
("Period 2", "09:25", "10:15"), | |
("Break", "10:15", "10:25"), | |
("Period 3", "10:30", "11:20"), | |
("Period 4", "11:25", "12:20"), | |
("Lunch", "12:20", "12:55"), | |
("Period 5", "13:00", "13:50"), | |
("Period 6", "13:55", "14:45"), | |
("Period 7", "14:50", "15:40") | |
], | |
"Friday": [ | |
("Warning Bell", "08:25"), | |
("Period 1", "08:30", "09:20"), | |
("Period 2", "09:25", "10:15"), | |
("Break", "10:15", "10:25"), | |
("Period 3", "10:30", "11:20"), | |
("Period 4", "11:25", "12:20"), | |
("Lunch", "12:20", "12:55"), | |
("Period 5", "13:00", "13:50"), | |
("Period 6", "13:55", "14:45"), | |
("Period 7", "14:50", "15:40") | |
], | |
"Saturday": [], | |
"Sunday": [], | |
# Rally | |
"Rally": [ | |
("Warning Bell", "08:25"), | |
("Period 1", "08:30", "09:10"), | |
("Period 2", "09:15", "09:55"), | |
("Break", "09:55", "10:05"), | |
("Period 3", "10:10", "10:50"), | |
("Period 4", "10:55", "11:35"), | |
("Rally", "11:40", "12:25"), | |
("Lunch", "12:25", "13:00"), | |
("Period 5", "13:05", "13:45"), | |
("Period 6", "13:50", "14:30"), | |
("Period 7", "14:35", "15:15") | |
], | |
# Minimum | |
"Minimum": [ | |
("Warning Bell", "08:25"), | |
("Period 1", "08:30", "09:05"), | |
("Period 2", "09:10", "09:45"), | |
("Period 3", "09:50", "10:25"), | |
("Period 4", "10:30", "11:05"), | |
("Break", "11:05", "11:15"), | |
("Period 5", "11:20", "11:55"), | |
("Period 6", "12:00", "12:35"), | |
("Period 7", "12:40", "13:15") | |
] | |
} | |
verbose("Bell schedule loaded") | |
# get the schedule for the day | |
verbose("Determining schedule type for the day") | |
if args.rally: | |
schedule = bell_schedule["Rally"] | |
verbose("Using rally day schedule") | |
elif args.minimum: | |
schedule = bell_schedule["Minimum"] | |
verbose("Using minimum day schedule") | |
else: | |
schedule = bell_schedule.get(date.strftime("%A"), None) | |
verbose(f"Using {date.strftime('%A')} schedule") | |
if not schedule: | |
verbose("No schedule found for this day") | |
print("No schedule available for this day.") | |
sys.exit(1) | |
verbose(f"Schedule has {len(schedule)} periods/events") | |
# Check if the current time is within the schedule | |
current_time = datetime.datetime.combine(date, time).time() | |
verbose(f"Checking current time: {current_time}") | |
next_bell, next_period, period_index = time_until_next_bell(schedule, current_time) | |
fancy = load_fancy_names(args.config) | |
fancy_next_period = fancy.get(next_period[0], next_period[0]) | |
if next_bell is not None: | |
verbose(f"Next bell in {next_bell:.0f} minutes") | |
print(f"Next bell in {next_bell:.0f} minutes. You then will have {fancy_next_period} at {next_period[1]}.") | |
else: | |
verbose("No more bells for today") | |
print("No more bells for today.") | |
sys.exit(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment