Skip to content

Instantly share code, notes, and snippets.

@thisisignitedoreo
Created April 28, 2024 21:22
Show Gist options
  • Select an option

  • Save thisisignitedoreo/3212cd92016ba03fca86412bb134734e to your computer and use it in GitHub Desktop.

Select an option

Save thisisignitedoreo/3212cd92016ba03fca86412bb134734e to your computer and use it in GitHub Desktop.
little game timer program
#!/bin/env python3
# for timing for how long you have been playing some game.
# $ time.py add game-slug
# $ time.py time game-slug
# and woa-la!
import discordrpc as rpc
import subprocess
import json
import time
import sys
import os
if not os.path.isfile("time.json"):
json.dump({}, open("time.json", "w"))
data = json.load(open("time.json"))
def parse_time(time_secs):
s = time_secs % 60
m = time_secs // 60 % 60
h = time_secs // 60 ** 2 % 60 ** 2
return f"{h:0>2}:{m:0>2}:{s:0>2}"
def parse_time_minutes(time_secs):
m = time_secs // 60 % 60
h = time_secs // 60 ** 2 % 60 ** 2
if h == 0:
return f"{m} minutes"
else:
return f"{h} hours {m} minutes"
def start_timer(game, set_func, drpc, process):
global data
old_min = -1
session_time = 0
while True:
stime = time.perf_counter()
new_min = data[game]["timer"] // 60
if new_min != old_min and drpc is not None: set_func(drpc, session_time)
if process.poll() is not None: return
data[game]["timer"] += 1
session_time += 1
print(f"total {data[game]['name']} time: {parse_time(data[game]['timer'])}, session time: {parse_time(session_time)}", end="\r")
old_min = new_min
time.sleep(1 - (time.perf_counter() - stime))
def print_help(program):
print(f"usage: {program} <subcommand> [game] [options]")
print("\tsubcommands:")
print("\t\thelp - get help")
print("\t\tadd - add a game")
print("\t\tinfo - get elapsed time at the game")
print("\t\ttime - start timer for selected game")
print("\toptions:")
print("\t\t--no-rpc - forcefully disable discord rpc")
def hash_name(name):
hsh = 0
for k, i in enumerate(name):
hsh += (k+1)*ord(i)
return hsh
def print_all_games():
size = os.get_terminal_size().columns - 5
full = sum(map(lambda x: x["timer"], data.values()))
sizes = {}
for k, i in sorted(data.items(), key=lambda x: -x[1]["timer"]):
sizes[k] = round(i["timer"]/full*size)
perc = {}
for k, i in sorted(data.items(), key=lambda x: -x[1]["timer"]):
perc[k] = i["timer"]/full
char = "#@$%&"
for k, i in sorted(data.items(), key=lambda x: -x[1]["timer"]):
print(f"{char[hash_name(k)%len(char)]} ({perc[k]*100:0.2f}%) {i['name']}: {parse_time(i['timer'])}")
print("\n ", end="")
for k, i in sizes.items():
name = data[k]["name"]
if i < len(name):
if i < 3:
print("." * i, end="")
else: print("..." + " " * (i-3), end="")
else:
print(name + (" " * (i - len(name))), end="")
print("\n[ ", end="")
for k, i in sizes.items():
print(char[hash_name(k)%len(char)] * i, end="")
print(" ]")
def error(string):
print("error:", string)
sys.exit(1)
def parse_args(args):
program = args.pop(0)
if len(args) == 0:
print_all_games()
return None, None, set()
operation = args.pop(0)
if operation not in ("time", "info", "help", "add"):
print_help(program)
error(f"unknown operation: {operation}")
if operation == "help":
print_help(program)
sys.exit()
if len(args) == 0:
print_help(program)
error(f"operation {operation} expects a game slug")
game = args.pop(0)
opts = set()
for i in args:
if i == "--no-rpc":
opts.add("norpc")
else:
print_help(program)
error(f"unknown option {i}")
return operation, game, opts
if __name__ == "__main__":
operation, game, opts = parse_args(sys.argv)
if operation == "time":
if game not in data:
print("no such game; add with `add` subcommand")
sys.exit(1)
if "process" not in data[game]:
print("specify game executable to run")
a = input("$ ")
while not os.path.isfile(a):
a = input("$ ")
data[game]["process"] = a
discord_opened = "norpc" not in opts
if discord_opened:
assert False # make your own rpc app and paste id here, remove this when done
try: drpc = rpc.RPC(app_id=-1, output=False)
except rpc.exceptions.DiscordNotOpened: discord_opened = False
if discord_opened:
print("discord is opened, rpc started")
set_act = lambda rpc, st: rpc.set_activity(
details=f"{data[game]['name']} for {parse_time_minutes(data[game]['timer'])}",
state=f"Played for {parse_time_minutes(st)} in this session",
large_image=game,
large_text=data[game]['name'],
)
elif "norpc" in opts:
print("no rpc option is selected, running localy")
set_act = None
else:
print("discord is not opened, running localy")
set_act = None
proc = subprocess.Popen([data[game]["process"]])
try: start_timer(game, set_act, drpc if discord_opened else None, proc)
except KeyboardInterrupt: pass
print(f"\ntimer for {data[game]['name']} is interrupted")
json.dump(data, open("time.json", "w"))
if discord_opened:
drpc.disconnect()
elif operation == "info":
if game not in data:
print("no such game; add with `add` subcommand")
sys.exit(1)
print(f"{data[game]['name']} info:")
print(f"elapsed time: {parse_time(data[game]['timer'])}")
elif operation == "add":
name = input("full game name: ")
execpath = input("game executable path: ")
data[game] = {}
data[game]["name"] = name
data[game]["process"] = execpath
if "timer" not in data[game].keys(): data[game]["timer"] = 0
json.dump(data, open("time.json", "w"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment