add stuffffffffff + kinda update it + legacy ver #2
3 changed files with 238 additions and 19 deletions
4
pathify.py
Normal file
4
pathify.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
def chn(a):
|
||||
return a.replace(' ','_').replace('.','-').replace('\\','/').replace(':','/')
|
||||
def dir(a)
|
||||
return a.replace('/','+')
|
||||
153
r2chat.py
153
r2chat.py
|
|
@ -10,6 +10,7 @@ import pygame as media
|
|||
import webbrowser
|
||||
import re
|
||||
import subprocess
|
||||
import pathify
|
||||
|
||||
if sys.platform == "win32":
|
||||
ROOT = Path("C:/Users/Public")
|
||||
|
|
@ -18,8 +19,8 @@ else:
|
|||
|
||||
try:
|
||||
if sys.argv[1]!='chat':
|
||||
CHANCHAN = sys.argv[1].replace(' ','_').replace('.','-')
|
||||
CHANNEL = 'chat_'+CHANCHAN
|
||||
CHANCHAN = pathify.chn(sys.argv[1])
|
||||
CHANNEL = 'chat_'+pathify.dir(CHANCHAN)
|
||||
else:
|
||||
CHANNEL = 'chat'
|
||||
CHANCHAN = 'chat'
|
||||
|
|
@ -27,7 +28,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 +40,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 = {
|
||||
|
|
@ -75,20 +81,28 @@ class r2chat:
|
|||
|
||||
self.last_size = 0
|
||||
|
||||
# configs
|
||||
# configs
|
||||
font = (self.cfg["font_family"], self.cfg["font_size"])
|
||||
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)
|
||||
|
||||
|
||||
## 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)
|
||||
|
|
@ -122,10 +136,17 @@ class r2chat:
|
|||
open(CHAT_FILE, "a").close()
|
||||
|
||||
self.update_chat()
|
||||
self.write_system_message(self.cfg["status_join"])
|
||||
self.write_system_message(f'◉ {self.cfg["status_join"]}')
|
||||
|
||||
def on_close(self):
|
||||
self.write_system_message(self.cfg["status_leave"])
|
||||
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):
|
||||
|
|
@ -136,7 +157,8 @@ class r2chat:
|
|||
def send_message(self, event=None):
|
||||
msg = self.entry.get().strip()
|
||||
if msg and msg.startswith("/join #"):
|
||||
subprocess.Popen(f'pythonw "{os.path.abspath(__file__)}" "{msg[7:len(msg)]}"', shell=True)
|
||||
channel = msg[7:len(msg)]
|
||||
self.open_channel(channel)
|
||||
msg = ''
|
||||
self.entry.delete(0, tk.END)
|
||||
if msg:
|
||||
|
|
@ -149,23 +171,116 @@ class r2chat:
|
|||
print("oh noes! ", e)
|
||||
|
||||
self.entry.delete(0, tk.END)
|
||||
|
||||
|
||||
def setstatus(self, new_status):
|
||||
global status
|
||||
|
||||
if status == new_status:
|
||||
return
|
||||
|
||||
|
||||
status = new_status
|
||||
|
||||
if status == "online":
|
||||
self.write_system_message(msg=self.cfg["status_join"])
|
||||
self.write_system_message(msg=f'((#00af00 | ◉)) {self.cfg["status_join"]}')
|
||||
elif status == "offline":
|
||||
self.write_system_message(msg=self.cfg["status_leave"])
|
||||
self.write_system_message(msg=f'((#000000 | ◌)) {self.cfg["status_leave"]}')
|
||||
elif status == "inactive":
|
||||
self.write_system_message(msg=self.cfg["status_inactive"])
|
||||
self.write_system_message(msg=f'((#ffaf00 | ◍)) {self.cfg["status_inactive"]}')
|
||||
elif status == "busy":
|
||||
self.write_system_message(msg=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)
|
||||
|
||||
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("600x320")
|
||||
|
||||
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"((#006fff | ⇄)) {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)
|
||||
|
|
@ -203,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()
|
||||
|
|
@ -337,6 +452,6 @@ if __name__ == "__main__":
|
|||
app = r2chat(root)
|
||||
root.geometry("500x520")
|
||||
root.minsize(360, 360)
|
||||
root.attributes('-topmost', True)
|
||||
#root.attributes('-topmost', True)
|
||||
root.protocol("WM_DELETE_WINDOW", app.on_close)
|
||||
root.mainloop()
|
||||
|
|
|
|||
100
r2chat_LEGACY.py
Normal file
100
r2chat_LEGACY.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import tkinter as tk
|
||||
from tkinter import scrolledtext
|
||||
import os
|
||||
import time
|
||||
import getpass
|
||||
from json import loads
|
||||
|
||||
CHAT_FILE = "C:/Users/Public/r2chat/chat.txt"
|
||||
REFRESH_INTERVAL = 1000
|
||||
|
||||
BORDER_WIDTH = 3
|
||||
THEMES = [['white','white','white','black','Basic'],['#000707','#002727','#001717','white','Aqua']]
|
||||
|
||||
username = getpass.getuser()
|
||||
CONFIG_FILE = f'C:/r2chat/legacy_config/{username}.r2cc'
|
||||
|
||||
if not os.path.exists(CONFIG_FILE):
|
||||
CFILE_C=open(CONFIG_FILE, "a")
|
||||
CFILE_C.write('0\n is now online.\n is now offline.')
|
||||
CFILE_C.close()
|
||||
|
||||
def conf_line(n):
|
||||
return((open(CONFIG_FILE).read()).split('\n')[n])
|
||||
|
||||
THEME = int(conf_line(0))
|
||||
JOIN_MESSAGE = conf_line(1)
|
||||
LEAVE_MESSAGE = conf_line(2)
|
||||
|
||||
class r2chat:
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
self.root.title(f"r2chat Legacy :: {username}")
|
||||
|
||||
self.last_size = 0
|
||||
|
||||
self.chat_area = scrolledtext.ScrolledText(root, wrap='word', font=("Lucida Console", 11), bg=THEMES[THEME][1], fg=THEMES[THEME][3], relief='groove', borderwidth=BORDER_WIDTH)
|
||||
self.chat_area.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)
|
||||
self.chat_area.bind("<Key>", lambda e: "break")
|
||||
|
||||
self.entry = tk.Entry(root, font=("Lucida Console", 11), bg=THEMES[THEME][2], fg=THEMES[THEME][3], relief='groove', borderwidth=BORDER_WIDTH)
|
||||
self.entry.pack(padx=10, pady=(0, 10), fill=tk.X)
|
||||
self.entry.bind("<Return>", self.send_message)
|
||||
|
||||
if not os.path.exists(CHAT_FILE):
|
||||
open(CHAT_FILE, "a").close()
|
||||
|
||||
self.update_chat()
|
||||
self.write_system_message(f"{username}{JOIN_MESSAGE}")
|
||||
|
||||
def on_close(self):
|
||||
self.write_system_message(f"{username}{LEAVE_MESSAGE}")
|
||||
self.root.destroy()
|
||||
|
||||
def write_system_message(self, msg):
|
||||
line = f"---- {msg} ----\n"
|
||||
with open(CHAT_FILE, "a", encoding="utf-8") as f:
|
||||
f.write(line)
|
||||
|
||||
def send_message(self, event=None):
|
||||
msg = self.entry.get().strip()
|
||||
if msg:
|
||||
timestamp = time.strftime("%y/%m/%d %H:%M")
|
||||
line = f"[{timestamp}] {username} (legacy): {msg}\n"
|
||||
try:
|
||||
with open(CHAT_FILE, "a", encoding="utf-8") as f:
|
||||
f.write(line)
|
||||
except Exception as e:
|
||||
print("oh noes! ", e)
|
||||
|
||||
self.entry.delete(0, tk.END)
|
||||
|
||||
def update_chat(self):
|
||||
try:
|
||||
current_size = os.path.getsize(CHAT_FILE)
|
||||
|
||||
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()
|
||||
self.last_size = current_size
|
||||
self.chat_area.config(state='normal')
|
||||
self.chat_area.insert(tk.END, new_data)
|
||||
self.chat_area.config(state='disabled')
|
||||
self.chat_area.yview(tk.END)
|
||||
|
||||
except Exception as e:
|
||||
print("oh noes! ", e)
|
||||
|
||||
self.root.after(REFRESH_INTERVAL, self.update_chat)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
root = tk.Tk()
|
||||
app = r2chat(root)
|
||||
root.geometry("500x520")
|
||||
root.minsize(360, 520)
|
||||
root.attributes('-topmost', True)
|
||||
root.protocol("WM_DELETE_WINDOW", app.on_close)
|
||||
root.configure(bg=THEMES[THEME][0])
|
||||
root.mainloop()
|
||||
Loading…
Add table
Add a link
Reference in a new issue