user info and channel list

This commit is contained in:
Diego 2026-04-11 12:39:11 -07:00
commit f734201242

125
r2chat.py
View file

@ -27,7 +27,10 @@ except:
CHANNEL = 'chat'
CHANCHAN = 'chat'
CHAT_FILE = ROOT / "r2chat" / f"{CHANNEL}.txt"
CHANNELS_DIR = ROOT / "r2chat"
CHAT_FILE = CHANNELS_DIR / f"{CHANNEL}.txt"
INSTANCE_DIR = CHANNELS_DIR / "instance"
os.makedirs(INSTANCE_DIR, exist_ok=True)
CONFIG_FILE = Path.home() / "r2chat.config.json"
os.makedirs(os.path.dirname(CHAT_FILE), exist_ok=True)
@ -36,6 +39,8 @@ COLOR_PATTERN = re.compile(r"\(\((#[0-9a-fA-F]{6})\s*\|\s*([^)]+)\)\)")
status = "online"
username = getpass.getuser()
USERFILE = INSTANCE_DIR / f"{username}.json"
media.mixer.init()
DEFAULT_CONFIG = {
@ -80,6 +85,13 @@ class r2chat:
bg_color = self.cfg["bg_color"]
fg_color = self.cfg["fg_color"]
self.user_data = self.load_userdata()
if CHANNEL not in self.user_data["channels"]:
self.user_data["channels"].append(CHANNEL)
self.user_data["status"] = status
self.save_userdata(self.user_data)
# menubar
self.menubar = tk.Menu(root)
self.root.config(menu=self.menubar)
@ -87,8 +99,9 @@ class r2chat:
## chat menu
self.chatmenu = tk.Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label="Chat", menu=self.chatmenu)
self.chatmenu.add_command(label="Registered users", command=lambda: print(""))
self.chatmenu.add_command(label="Leave", command=lambda: self.on_close())
self.chatmenu.add_command(label="Registered users", command=lambda: self.show_users())
self.chatmenu.add_command(label="Channel list", command=lambda: self.show_channels())
self.chatmenu.add_command(label="Leave channel", command=lambda: self.on_close())
## insert menu
self.chatmenu = tk.Menu(self.menubar, tearoff=0)
@ -126,6 +139,13 @@ class r2chat:
def on_close(self):
self.write_system_message(f'{self.cfg["status_leave"]}')
if CHANNEL in self.user_data["channels"]:
self.user_data["channels"].remove(CHANNEL)
if not self.user_data["channels"]:
self.user_data["status"] = "offline"
self.save_userdata(self.user_data)
self.root.destroy()
def write_system_message(self, msg):
@ -137,11 +157,7 @@ class r2chat:
msg = self.entry.get().strip()
if msg and msg.startswith("/join #"):
channel = msg[7:len(msg)]
self.write_system_message(f"{username} is chatting in {channel}.")
if sys.platform == "win32":
subprocess.Popen(f'pythonw "{os.path.abspath(__file__)}" "{channel}"', shell=True)
else:
subprocess.Popen(f'python "{os.path.abspath(__file__)}" "{channel}"', shell=True)
self.open_channel(channel)
msg = ''
self.entry.delete(0, tk.END)
if msg:
@ -172,6 +188,99 @@ class r2chat:
elif status == "busy":
self.write_system_message(msg=f'{self.cfg["status_busy"]}')
self.user_data["status"] = status
self.save_userdata(self.user_data)
def load_userdata(self):
path = USERFILE
if path.exists():
try:
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
except:
pass
return {
"username": username,
"status": "online",
"channels": [],
"last_seen": time.time()
}
def save_userdata(self, data):
data["last_seen"] = time.time()
with open(USERFILE, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
def show_users(self):
win = tk.Toplevel(self.root)
win.title("Registered users")
win.geometry("420x320")
tree = ttk.Treeview(win, columns=("user", "status", "channels", "last_seen"), show="headings")
tree.heading("user", text="User")
tree.heading("status", text="Status")
tree.heading("channels", text="Channels")
tree.heading("last_seen", text="Last seen")
tree.column("user", width=80)
tree.column("status", width=60, anchor="center")
tree.column("channels", width=140)
tree.column("last_seen", width=120, anchor="e")
tree.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
for file in INSTANCE_DIR.glob("*.json"):
try:
with open(file, "r", encoding="utf-8") as f:
data = json.load(f)
last_seen = time.strftime("%H:%M:%S", time.localtime(data.get("last_seen", 0)))
channels = ", ".join(data.get("channels", []))
tree.insert("", tk.END, values=(
file.stem,
data.get("status", "?"),
channels,
last_seen
))
except Exception as e:
print(":( user read error:", e)
def show_channels(self):
win = tk.Toplevel(self.root)
win.title("Channel list")
win.geometry("200x320")
tree = ttk.Treeview(win, columns=("channel"), show="headings")
tree.heading("channel", text="Channels")
tree.column("channel", width=100)
tree.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
for file in CHANNELS_DIR.glob("*.txt"):
try:
tree.insert("", tk.END, values=(
file.stem.replace("chat_", "")
))
except Exception as e:
print(":( instance read error:", e)
def on_select(event):
selected = tree.focus()
if selected:
channel = tree.item(selected)["values"][0]
win.destroy()
self.open_channel(channel)
tree.bind("<Double-1>", on_select)
def open_channel(self, channel):
self.write_system_message(f"{username} is chatting in {channel}.")
if sys.platform == "win32":
subprocess.Popen(f'pythonw "{os.path.abspath(__file__)}" "{channel}"', shell=True)
else:
subprocess.Popen(f'python "{os.path.abspath(__file__)}" "{channel}"', shell=True)
def openprefs(self):
PreferencesWindow(self.root, self.cfg, self.save_prefs)