Created
April 28, 2024 21:22
-
-
Save thisisignitedoreo/3212cd92016ba03fca86412bb134734e to your computer and use it in GitHub Desktop.
little game timer program
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
| #!/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