Files
minecraft-heatmap/mclog2mysql/main.py
2025-08-14 21:19:21 +02:00

84 lines
2.6 KiB
Python

#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p "python3.withPackages(ps: with ps; [ tqdm psycopg2-bin ])"
from tqdm import tqdm
from pprint import pprint
from pathlib import Path
from datetime import datetime, timedelta
from dataclasses import dataclass
import gzip
# Currently not mysql lol
import sqlite3
@dataclass
class LoginLogoutEvent:
username: str
timestamp: datetime
is_login: bool # if false, it is a logout event
def parse_login_logout_events_from_file(path: Path) -> list[LoginLogoutEvent]:
date = path.name[:10]
result = []
with gzip.open(path, 'r') as file:
for line in file:
if b'joined the game' in line or b'left the game' in line:
split = line.decode().split()
result.append(LoginLogoutEvent(
username = split[3],
is_login = split[4] == 'joined',
timestamp = datetime.fromisoformat(f"{date} {split[0][1:9]}"),
))
return result
@dataclass
class LoginSpan:
username: str
start_time: datetime
duration: int
def conjoin_sessions(event_log: list[LoginLogoutEvent]) -> list[LoginSpan]:
result = []
login_session_table = dict()
for e in event_log:
if e.is_login:
login_session_table[e.username] = e.timestamp
elif e.username in login_session_table:
result.append(LoginSpan(
username = e.username,
start_time = e.timestamp,
duration = (e.timestamp - login_session_table[e.username]).total_seconds(),
))
del login_session_table[e.username]
else:
print(f"warn: loose session found for {e.username} at {e.timestamp}")
return result
def insert_sessions_into_db(session_log: list[LoginSpan]) -> None:
con = sqlite3.connect("test.db")
cur = con.cursor()
cur.execute("DROP TABLE IF EXISTS minecraft_login_sessions")
cur.execute("""
CREATE TABLE minecraft_login_sessions(
username TEXT NOT NULL,
start DATETIME,
duration INTEGER
)
""")
cur.executemany(
"INSERT INTO minecraft_login_sessions(username, start, duration) VALUES(?, ?, ?)",
[(e.username, e.start_time, e.duration) for e in session_log],
)
con.commit()
if __name__ == "__main__":
event_log = []
files = list(Path(__file__).parent.glob(r"*.log.gz"))
for file in (pbar:=tqdm(files)):
pbar.set_postfix_str(str(file))
event_log += parse_login_logout_events_from_file(file)
session_log = conjoin_sessions(event_log)
insert_sessions_into_db(session_log)