update r2chat

This commit is contained in:
win7he 2026-04-18 01:50:27 -05:00
commit 78d1fbffd1

109
r2chat.py
View file

@ -1,15 +1,14 @@
import tkinter as tk
from tkinter import scrolledtext, messagebox
from tkinter import ttk, colorchooser, font as tkfont
import os, sys, json
import os, sys, json, time, getpass, webbrowser, re, subprocess
from pathlib import Path
import time
import getpass
from plyer import notification
import pygame as media
import webbrowser
import re
import subprocess
from random import randint
import wlang
wlang.setlangfile('assets/internal/lang.json')
if sys.platform == "win32":
ROOT = Path("C:/Users/Public")
@ -18,8 +17,8 @@ else:
try:
if sys.argv[1]!='chat':
CHANCHAN = sys.argv[1].replace(' ','_').replace('.','-')
CHANNEL = 'chat_'+CHANCHAN
CHANCHAN = sys.argv[1].replace(' ','_').replace('.','-').replace('\\','/').replace(':','/')
CHANNEL = 'chat_'+CHANCHAN.replace('/','#')
else:
CHANNEL = 'chat'
CHANCHAN = 'chat'
@ -49,11 +48,12 @@ DEFAULT_CONFIG = {
"border_width": 2,
"bg_color": "#f0f0f0",
"fg_color": "#1e1e1e",
"user_color": "#0000ff",
"user_color": f"#{['0000ff','af0000','00af00','ffaf00','ff00ff','00ffff','7f00ff','ff7f00','00ff7f','007fff'][randint(0,9)]}",
"status_join": "{username} is now online.",
"status_leave": "{username} is now offline.",
"status_inactive": "{username} will be right back.",
"status_busy": "{username} is busy."
"status_busy": "{username} is busy.",
"language": "en"
}
def load_config():
@ -76,8 +76,8 @@ class r2chat:
def __init__(self, root):
self.root = root
self.cfg = load_config()
self.root.title(f"r2chat :: {username} / #{CHANCHAN}")
self.root.title(f"r2chat :: {username} / #{CHANCHAN.replace('#','/')}")
wlang.setlang(self.cfg['language'])
self.last_size = 0
# configs
@ -98,28 +98,29 @@ 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: 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())
self.menubar.add_cascade(label=wlang.getobj('chat'), menu=self.chatmenu)
self.chatmenu.add_command(label=wlang.getobj('regusers'), command=lambda: self.show_users())
self.chatmenu.add_command(label=wlang.getobj('chlist'), command=lambda: self.show_channels())
self.chatmenu.add_command(label=wlang.getobj('lchan'), command=lambda: self.on_close())
## insert menu
self.chatmenu = tk.Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label="Insert", menu=self.chatmenu)
self.chatmenu.add_command(label="Emoticon", command=lambda: print(""))
self.chatmenu.add_command(label="GIF", command=lambda: print(""))
self.menubar.add_cascade(label=wlang.getobj('insert'), menu=self.chatmenu)
self.chatmenu.add_command(label=wlang.getobj('emoticon'), command=lambda: print(""))
## its pronounced jif
self.chatmenu.add_command(label=wlang.getobj('gif'), command=lambda: print(""))
## status menu
self.chatmenu = tk.Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label="Status", menu=self.chatmenu)
self.chatmenu.add_command(label="Online (All notifs)", command=lambda: self.setstatus("online"))
self.chatmenu.add_command(label="Inactive (Pings only)", command=lambda: self.setstatus("inactive"))
self.chatmenu.add_command(label="Busy (No notifs)", command=lambda: self.setstatus("busy"))
self.chatmenu.add_command(label="Appear offline", command=lambda: self.setstatus("offline"))
self.menubar.add_cascade(label=wlang.getobj('status'), menu=self.chatmenu)
self.chatmenu.add_command(label=wlang.getobj('onlinestat'), command=lambda: self.setstatus("online"))
self.chatmenu.add_command(label=wlang.getobj('inactstat'), command=lambda: self.setstatus("inactive"))
self.chatmenu.add_command(label=wlang.getobj('busystat'), command=lambda: self.setstatus("busy"))
self.chatmenu.add_command(label=wlang.getobj('offlinestat'), command=lambda: self.setstatus("offline"))
## menu buttons
self.menubar.add_command(label="Preferences", command=lambda: self.openprefs())
self.menubar.add_command(label="Help", command=lambda: webbrowser.open_new_tab("https://forgejo.nishi.boats/Dogo6647/r2chat"))
self.menubar.add_command(label=wlang.getobj('pref'), command=lambda: self.openprefs())
self.menubar.add_command(label=wlang.getobj('help'), command=lambda: webbrowser.open_new_tab("https://forgejo.nishi.boats/Dogo6647/r2chat"))
# MAIN MENU STUFFS
self.entry = tk.Entry(root, relief='sunken', borderwidth=self.cfg["border_width"])
@ -135,7 +136,7 @@ class r2chat:
open(CHAT_FILE, "a").close()
self.update_chat()
self.write_system_message(f' {self.cfg["status_join"]}')
self.write_system_message(f'((#00af00 | ◉)) {self.cfg["status_join"]}')
def on_close(self):
self.write_system_message(f'{self.cfg["status_leave"]}')
@ -180,13 +181,13 @@ class r2chat:
status = new_status
if status == "online":
self.write_system_message(msg=f' {self.cfg["status_join"]}')
self.write_system_message(msg=f'((#00af00 | ◉)) {self.cfg["status_join"]}')
elif status == "offline":
self.write_system_message(msg=f'{self.cfg["status_leave"]}')
elif status == "inactive":
self.write_system_message(msg=f' {self.cfg["status_inactive"]}')
self.write_system_message(msg=f'((#ffaf00 | ◍)) {self.cfg["status_inactive"]}')
elif status == "busy":
self.write_system_message(msg=f' {self.cfg["status_busy"]}')
self.write_system_message(msg=f'((#af0000 | ◎)) {self.cfg["status_busy"]}')
self.user_data["status"] = status
self.save_userdata(self.user_data)
@ -213,15 +214,15 @@ class r2chat:
def show_users(self):
win = tk.Toplevel(self.root)
win.title("Registered users")
win.title(wlang.getobj('regusers'))
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.heading("user", text=wlang.getobj('user'))
tree.heading("status", text=wlang.getobj('status'))
tree.heading("channels", text=wlang.getobj('chans'))
tree.heading("last_seen", text=wlang.getobj('lseen'))
tree.column("user", width=80)
tree.column("status", width=60, anchor="center")
@ -250,7 +251,7 @@ class r2chat:
def show_channels(self):
win = tk.Toplevel(self.root)
win.title("Channel list")
win.geometry("200x320")
win.geometry("600x320")
tree = ttk.Treeview(win, columns=("channel"), show="headings")
tree.heading("channel", text="Channels")
@ -275,7 +276,7 @@ class r2chat:
tree.bind("<Double-1>", on_select)
def open_channel(self, channel):
self.write_system_message(f" {username} is chatting in {channel}.")
self.write_system_message(f"((#006fff | ⇄)) {username} is chatting in {channel.replace('#','/')}.")
if sys.platform == "win32":
subprocess.Popen(f'pythonw "{os.path.abspath(__file__)}" "{channel}"', shell=True)
else:
@ -317,7 +318,7 @@ class r2chat:
try:
current_size = os.path.getsize(CHAT_FILE)
if current_size > self.last_size:
if current_size != self.last_size:
with open(CHAT_FILE, "r", encoding="utf-8") as f:
f.seek(self.last_size)
new_data = f.read()
@ -326,7 +327,7 @@ class r2chat:
self.chat_area.config(state='normal')
if f"@{username} " in new_data and not "---" in new_data and not status == "busy" and not status == "offline":
media.mixer.Sound("assets/internal/ping.ogg").play()
messagebox.showinfo("Important message!", new_data)
messagebox.showinfo(wlang.getobj('impmes'), new_data)
if self.root.wm_state() == 'iconic':
if not f"@{username} " in new_data and not status == "busy" and not status == "inactive":
notification.notify(title="r2chat", message=new_data)
@ -347,7 +348,7 @@ class PreferencesWindow:
self.on_save = on_save
self.win = tk.Toplevel(parent)
self.win.title("r2chat prefs")
self.win.title(f"r2chat {wlang.getobj('prefl')}")
self.win.geometry("420x520")
self.win.resizable(False, False)
self.win.transient(parent)
@ -366,16 +367,16 @@ class PreferencesWindow:
btn_frame = tk.Frame(self.win)
btn_frame.pack(fill=tk.X, padx=10, pady=(0, 10))
tk.Button(btn_frame, text="Save", width=10, command=self._save).pack(side=tk.RIGHT, padx=(4, 0))
tk.Button(btn_frame, text="Cancel", width=10, command=self.win.destroy).pack(side=tk.RIGHT)
tk.Button(btn_frame, text="Back to defaults", command=self._reset).pack(side=tk.LEFT)
tk.Button(btn_frame, text=wlang.getobj('save'), width=10, command=self._save).pack(side=tk.RIGHT, padx=(4, 0))
tk.Button(btn_frame, text=wlang.getobj('cancel'), width=10, command=self.win.destroy).pack(side=tk.RIGHT)
tk.Button(btn_frame, text=wlang.getobj('btodef'), command=self._reset).pack(side=tk.LEFT)
def _build_appearance_tab(self, notebook):
frame = tk.Frame(notebook)
notebook.add(frame, text="Interface")
notebook.add(frame, text=wlang.getobj('interface'))
# font family
self._row(frame, 0, "Font family")
self._row(frame, 0, wlang.getobj('ffam'))
font_var = tk.StringVar(value=self.cfg["font_family"])
self.vars["font_family"] = font_var
families = sorted(tkfont.families())
@ -383,34 +384,34 @@ class PreferencesWindow:
font_combo.grid(row=0, column=1, padx=10, pady=6, sticky=tk.W)
# font size
self._row(frame, 1, "Font size")
self._row(frame, 1, wlang.getobj('fsiz'))
size_var = tk.IntVar(value=self.cfg["font_size"])
self.vars["font_size"] = size_var
tk.Spinbox(frame, from_=7, to=24, textvariable=size_var, width=6).grid(row=1, column=1, padx=10, pady=6, sticky=tk.W)
# border width
self._row(frame, 2, "Frame thickness")
self._row(frame, 2, wlang.getobj('fthi'))
bw_var = tk.IntVar(value=self.cfg["border_width"])
self.vars["border_width"] = bw_var
tk.Spinbox(frame, from_=0, to=6, textvariable=bw_var, width=6).grid(row=2, column=1, padx=10, pady=6, sticky=tk.W)
# color pickers
for i, (key, label) in enumerate([
("bg_color", "Background color"),
("fg_color", "Text color"),
("user_color", "Username color"),
("bg_color", wlang.getobj('backc')),
("fg_color", wlang.getobj('textc')),
("user_color", wlang.getobj('userc')),
], start=3):
self._row(frame, i, label)
self._color_picker_row(frame, i, key)
def _build_status_messages_tab(self, notebook):
frame = tk.Frame(notebook)
notebook.add(frame, text="Status messages")
notebook.add(frame, text=wlang.getobj('statmes'))
tk.Label(frame, text="Use {username} where you want your username to be.", fg="gray", font=("Lucida Console", 9)).grid(
tk.Label(frame, text=wlang.getobj('usernh'), fg="gray", font=("Lucida Console", 9)).grid(
row=0, column=0, columnspan=2, padx=10, pady=(10, 4), sticky=tk.W)
for i, (key, label) in enumerate([("status_join", "Join message"),("status_leave", "Leave message"),("status_inactive", "Inactive message"),("status_busy", "Busy message")], start=1):
for i, (key, label) in enumerate([("status_join", wlang.getobj('joinm')),("status_leave", wlang.getobj('leavm')),("status_inactive", wlang.getobj('inacm')),("status_busy", wlang.getobj('busym'))], start=1):
self._row(frame, i, label)
var = tk.StringVar(value=self.cfg[key])
self.vars[key] = var
@ -432,7 +433,7 @@ class PreferencesWindow:
v.set(result[1])
p.config(bg=result[1])
tk.Button(frame, text="Choose…", command=pick, width=8).grid(row=row, column=1, padx=(44, 0), pady=6, sticky=tk.W)
tk.Button(frame, text=wlang.getobj('choose'), command=pick, width=8).grid(row=row, column=1, padx=(44, 0), pady=6, sticky=tk.W)
def _save(self):
for key, var in self.vars.items():