Revert "Update client.py"
This reverts commit cfd13cfad8.
Dear WHE Team. Your commits are sucks + it looks like AI slop.
This commit is contained in:
parent
d99563dc73
commit
5190492f1a
417
TUI.py
417
TUI.py
|
|
@ -13,18 +13,28 @@ def auto_install_deps():
|
||||||
__import__(import_name)
|
__import__(import_name)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
missing_packages.append(pip_name)
|
missing_packages.append(pip_name)
|
||||||
|
|
||||||
if not missing_packages:
|
if not missing_packages:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
print("[Auto-Installer] Installing client dependencies:", ", ".join(missing_packages))
|
||||||
cmd = [sys.executable, "-m", "pip", "install"] + missing_packages
|
cmd = [sys.executable, "-m", "pip", "install"] + missing_packages
|
||||||
result = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
|
result = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
|
||||||
|
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
stderr_output = result.stderr.decode('utf-8', errors='ignore')
|
stderr_output = result.stderr.decode('utf-8', errors='ignore')
|
||||||
if "externally-managed-environment" in stderr_output.lower():
|
if "externally-managed-environment" in stderr_output.lower():
|
||||||
force_cmd = cmd + ["--break-system-packages"]
|
print("\n" + "!"*50)
|
||||||
force_result = subprocess.run(force_cmd)
|
print("[Warning] OS blocks global package installation via pip.")
|
||||||
if force_result.returncode == 0:
|
print("!"*50 + "\n")
|
||||||
sys.exit(0)
|
choice = input("Use --break-system-packages flag? (y/n): ").strip().lower()
|
||||||
sys.exit(1)
|
if choice == 'y':
|
||||||
|
force_cmd = cmd + ["--break-system-packages"]
|
||||||
|
force_result = subprocess.run(force_cmd)
|
||||||
|
if force_result.returncode == 0:
|
||||||
|
print("[Success] Restart the script!")
|
||||||
|
sys.exit(0)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -54,7 +64,19 @@ try:
|
||||||
except:
|
except:
|
||||||
auto_install_deps()
|
auto_install_deps()
|
||||||
|
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
import socket_manager
|
import socket_manager
|
||||||
|
=======
|
||||||
|
from prompt_toolkit.application import Application
|
||||||
|
from prompt_toolkit.key_binding import KeyBindings
|
||||||
|
from prompt_toolkit.layout.containers import HSplit, VSplit, Window
|
||||||
|
from prompt_toolkit.layout.controls import FormattedTextControl
|
||||||
|
from prompt_toolkit.layout.layout import Layout
|
||||||
|
from prompt_toolkit.widgets import TextArea, Frame
|
||||||
|
from prompt_toolkit.styles import Style
|
||||||
|
from prompt_toolkit.application.current import get_app
|
||||||
|
from prompt_toolkit.filters import has_focus
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
|
|
||||||
CONFIG_FILE = "settings.json"
|
CONFIG_FILE = "settings.json"
|
||||||
WIKI_URL = "https://git.idkmail.ru/lohrrrr/TyChat-Client/wiki"
|
WIKI_URL = "https://git.idkmail.ru/lohrrrr/TyChat-Client/wiki"
|
||||||
|
|
@ -71,6 +93,7 @@ ASCII_ART = r"""
|
||||||
|___/
|
|___/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
class CommandCompleter(Completer):
|
class CommandCompleter(Completer):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.completions = {
|
self.completions = {
|
||||||
|
|
@ -148,6 +171,9 @@ class PluginManager:
|
||||||
proto["failed"] = True
|
proto["failed"] = True
|
||||||
proto["enabled"] = False
|
proto["enabled"] = False
|
||||||
return None
|
return None
|
||||||
|
=======
|
||||||
|
sio = socketio.Client()
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
|
|
||||||
class TyClient:
|
class TyClient:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
@ -156,20 +182,12 @@ class TyClient:
|
||||||
self.uin = ""
|
self.uin = ""
|
||||||
self.password = ""
|
self.password = ""
|
||||||
self.contacts = {}
|
self.contacts = {}
|
||||||
self.groups = {}
|
|
||||||
self.history = {}
|
self.history = {}
|
||||||
self.preserved = {}
|
self.preserved = {}
|
||||||
self.blocklist = []
|
self.active_chat = None
|
||||||
self.active_chat = None
|
|
||||||
self.app = None
|
self.app = None
|
||||||
self.loop_running = True
|
self.loop_running = True
|
||||||
self.selected_contact_idx = 0
|
self.selected_contact_idx = 0
|
||||||
|
|
||||||
self.is_busy = False
|
|
||||||
self.dialing_uin = None
|
|
||||||
self.pending_requests = []
|
|
||||||
self.pending_windows = []
|
|
||||||
self.show_welcome_popup = False
|
|
||||||
|
|
||||||
self.current_tab = "chat"
|
self.current_tab = "chat"
|
||||||
self.settings_cursor = 0
|
self.settings_cursor = 0
|
||||||
|
|
@ -190,9 +208,9 @@ class TyClient:
|
||||||
self.uin = cfg.get("uin", "")
|
self.uin = cfg.get("uin", "")
|
||||||
self.password = cfg.get("password", "")
|
self.password = cfg.get("password", "")
|
||||||
self.contacts = cfg.get("contacts", {})
|
self.contacts = cfg.get("contacts", {})
|
||||||
self.groups = cfg.get("groups", {})
|
|
||||||
self.history = cfg.get("history", {})
|
self.history = cfg.get("history", {})
|
||||||
self.preserved = cfg.get("preserved", {})
|
self.preserved = cfg.get("preserved", {})
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
self.blocklist = cfg.get("blocklist", [])
|
self.blocklist = cfg.get("blocklist", [])
|
||||||
|
|
||||||
self.primary_protocol = cfg.get("primary_protocol", "")
|
self.primary_protocol = cfg.get("primary_protocol", "")
|
||||||
|
|
@ -212,6 +230,8 @@ class TyClient:
|
||||||
self.primary_protocol = list(self.plugin_manager.protocols.keys())[0]
|
self.primary_protocol = list(self.plugin_manager.protocols.keys())[0]
|
||||||
if not self.primary_transport and self.plugin_manager.transports:
|
if not self.primary_transport and self.plugin_manager.transports:
|
||||||
self.primary_transport = list(self.plugin_manager.transports.keys())[0]
|
self.primary_transport = list(self.plugin_manager.transports.keys())[0]
|
||||||
|
=======
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
return True
|
return True
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
@ -226,18 +246,22 @@ class TyClient:
|
||||||
"uin": self.uin,
|
"uin": self.uin,
|
||||||
"password": self.password,
|
"password": self.password,
|
||||||
"contacts": self.contacts,
|
"contacts": self.contacts,
|
||||||
"groups": self.groups,
|
|
||||||
"history": self.history,
|
"history": self.history,
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
"preserved": self.preserved,
|
"preserved": self.preserved,
|
||||||
"blocklist": self.blocklist,
|
"blocklist": self.blocklist,
|
||||||
"primary_protocol": self.primary_protocol,
|
"primary_protocol": self.primary_protocol,
|
||||||
"primary_transport": self.primary_transport,
|
"primary_transport": self.primary_transport,
|
||||||
"enabled_protocols": enabled_protos,
|
"enabled_protocols": enabled_protos,
|
||||||
"enabled_transports": enabled_trans
|
"enabled_transports": enabled_trans
|
||||||
|
=======
|
||||||
|
"preserved": self.preserved
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
}
|
}
|
||||||
with open(CONFIG_FILE, "w", encoding="utf-8") as f:
|
with open(CONFIG_FILE, "w", encoding="utf-8") as f:
|
||||||
json.dump(cfg, f, indent=4, ensure_ascii=False)
|
json.dump(cfg, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
def play_dial_tones(self, target_uin):
|
def play_dial_tones(self, target_uin):
|
||||||
self.dialing_uin = target_uin
|
self.dialing_uin = target_uin
|
||||||
while self.dialing_uin == target_uin and self.loop_running:
|
while self.dialing_uin == target_uin and self.loop_running:
|
||||||
|
|
@ -249,6 +273,20 @@ class TyClient:
|
||||||
if self.dialing_uin != target_uin or not self.loop_running:
|
if self.dialing_uin != target_uin or not self.loop_running:
|
||||||
break
|
break
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
=======
|
||||||
|
def text_to_audio(self, text):
|
||||||
|
audio_signals = []
|
||||||
|
t_start = np.linspace(0, 0.3, int(SAMPLE_RATE * 0.3), False)
|
||||||
|
audio_signals.append(np.sin(1000 * t_start * 2 * np.pi))
|
||||||
|
for char in text:
|
||||||
|
freq = BASE_FREQ + ord(char) * FREQ_STEP
|
||||||
|
t = np.linspace(0, TONE_DURATION, int(SAMPLE_RATE * TONE_DURATION), False)
|
||||||
|
audio_signals.append(np.sin(freq * t * 2 * np.pi))
|
||||||
|
full_audio = np.concatenate(audio_signals).astype(np.float32)
|
||||||
|
if np.max(np.abs(full_audio)) > 0:
|
||||||
|
full_audio = full_audio / np.max(np.abs(full_audio))
|
||||||
|
return full_audio.tobytes()
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
|
|
||||||
def play_and_decode(self, audio_bytes, sender_uin):
|
def play_and_decode(self, audio_bytes, sender_uin):
|
||||||
audio_data = np.frombuffer(audio_bytes, dtype=np.float32)
|
audio_data = np.frombuffer(audio_bytes, dtype=np.float32)
|
||||||
|
|
@ -265,24 +303,37 @@ class TyClient:
|
||||||
self.history[sender_uin].append(msg_buffer)
|
self.history[sender_uin].append(msg_buffer)
|
||||||
self.refresh_ui()
|
self.refresh_ui()
|
||||||
|
|
||||||
|
full_text_received = ""
|
||||||
while current_sample < len(audio_data) and self.loop_running:
|
while current_sample < len(audio_data) and self.loop_running:
|
||||||
chunk = audio_data[current_sample : current_sample + samples_per_tone]
|
chunk = audio_data[current_sample : current_sample + samples_per_tone]
|
||||||
if len(chunk) < samples_per_tone:
|
if len(chunk) < samples_per_tone:
|
||||||
break
|
break
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
window_data = np.hanning(len(chunk))
|
window_data = np.hanning(len(chunk))
|
||||||
fft_data = np.abs(np.fft.rfft(chunk * window_data))
|
fft_data = np.abs(np.fft.rfft(chunk * window_data))
|
||||||
frequencies = np.fft.rfftfreq(len(chunk), d=1/44100)
|
frequencies = np.fft.rfftfreq(len(chunk), d=1/44100)
|
||||||
|
=======
|
||||||
|
window = np.hanning(len(chunk))
|
||||||
|
fft_data = np.abs(np.fft.rfft(chunk * window))
|
||||||
|
frequencies = np.fft.rfftfreq(len(chunk), d=1/SAMPLE_RATE)
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
detected_freq = frequencies[np.argmax(fft_data)]
|
detected_freq = frequencies[np.argmax(fft_data)]
|
||||||
ascii_code = int(round((detected_freq - 600) / 25))
|
ascii_code = int(round((detected_freq - 600) / 25))
|
||||||
if 0 <= ascii_code < 65535:
|
if 0 <= ascii_code < 65535:
|
||||||
try:
|
try:
|
||||||
char = chr(ascii_code)
|
char = chr(ascii_code)
|
||||||
self.history[sender_uin][-1] += char
|
self.history[sender_uin][-1] += char
|
||||||
|
full_text_received += char
|
||||||
self.refresh_ui()
|
self.refresh_ui()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
current_sample += samples_per_tone
|
current_sample += samples_per_tone
|
||||||
|
|
||||||
|
if "ALARM! URGENT CALL!" in full_text_received:
|
||||||
|
client.contacts[sender_uin]["attention"] = True
|
||||||
|
self.refresh_ui()
|
||||||
|
|
||||||
sd.wait()
|
sd.wait()
|
||||||
self.save_config()
|
self.save_config()
|
||||||
|
|
||||||
|
|
@ -293,6 +344,7 @@ class TyClient:
|
||||||
self.refresh_ui()
|
self.refresh_ui()
|
||||||
self.save_config()
|
self.save_config()
|
||||||
|
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
def send_sys_packet(self, to_uin, cmd):
|
def send_sys_packet(self, to_uin, cmd):
|
||||||
text_payload = f"SYS:{cmd}"
|
text_payload = f"SYS:{cmd}"
|
||||||
proto_order = []
|
proto_order = []
|
||||||
|
|
@ -327,12 +379,51 @@ class TyClient:
|
||||||
socket_manager.sio.emit("relay_packet", {"to_uin": to_uin, "payload": base64.b64encode(wrapped).decode('utf-8')})
|
socket_manager.sio.emit("relay_packet", {"to_uin": to_uin, "payload": base64.b64encode(wrapped).decode('utf-8')})
|
||||||
return
|
return
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
def refresh_ui(self):
|
def refresh_ui(self):
|
||||||
if self.app:
|
if self.app:
|
||||||
self.app.invalidate()
|
self.app.invalidate()
|
||||||
|
|
||||||
client = TyClient()
|
client = TyClient()
|
||||||
|
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
|
=======
|
||||||
|
@sio.event
|
||||||
|
def incoming_packet(data):
|
||||||
|
from_uin = data["from_uin"]
|
||||||
|
payload_base64 = data["payload"]
|
||||||
|
try:
|
||||||
|
audio_bytes = base64.b64decode(payload_base64.encode('utf-8'))
|
||||||
|
if from_uin not in client.contacts:
|
||||||
|
client.contacts[from_uin] = {"status": "offline", "unread": 0, "attention": False}
|
||||||
|
if client.active_chat != from_uin:
|
||||||
|
client.contacts[from_uin]["unread"] += 1
|
||||||
|
threading.Thread(target=client.play_and_decode, args=(audio_bytes, from_uin), daemon=True).start()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@sio.event
|
||||||
|
def online_statuses_response(data):
|
||||||
|
for uin, status in data.items():
|
||||||
|
if uin in client.contacts:
|
||||||
|
client.contacts[uin]["status"] = status
|
||||||
|
client.refresh_ui()
|
||||||
|
|
||||||
|
@sio.event
|
||||||
|
def error(data):
|
||||||
|
msg = data.get("message")
|
||||||
|
target = data.get("target_uin")
|
||||||
|
if msg == "offline" and target:
|
||||||
|
if target in client.contacts:
|
||||||
|
client.contacts[target]["status"] = "offline"
|
||||||
|
client.add_to_history(target, f"[SYSTEM]: They went offline. Everything that you will send now will be sent if they will back online while your client opened.")
|
||||||
|
if target in client.preserved:
|
||||||
|
if len(client.preserved[target]) > 0:
|
||||||
|
last_p = client.preserved[target][-1]
|
||||||
|
client.add_to_history(target, f"[You]: {last_p} (Preserved)")
|
||||||
|
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
def status_checker_thread():
|
def status_checker_thread():
|
||||||
while client.loop_running:
|
while client.loop_running:
|
||||||
if socket_manager.sio.connected and client.contacts:
|
if socket_manager.sio.connected and client.contacts:
|
||||||
|
|
@ -371,10 +462,15 @@ def make_layout():
|
||||||
tokens = []
|
tokens = []
|
||||||
for idx, (uin, info) in enumerate(client.contacts.items()):
|
for idx, (uin, info) in enumerate(client.contacts.items()):
|
||||||
status_str = ""
|
status_str = ""
|
||||||
if info.get("attention"): status_str = " [!]"
|
if info.get("attention"):
|
||||||
elif info.get("unread", 0) > 0: status_str = f" ({info['unread']})"
|
status_str = " [!]"
|
||||||
elif info.get("status") == "online": status_str = " *"
|
elif info.get("unread", 0) > 0:
|
||||||
|
status_str = f" ({info['unread']})"
|
||||||
|
elif info.get("status") == "online":
|
||||||
|
status_str = " *"
|
||||||
|
|
||||||
content = f" {uin}{status_str}"
|
content = f" {uin}{status_str}"
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
if client.active_chat == uin and client.current_tab == "chat": style = "class:contact-active"
|
if client.active_chat == uin and client.current_tab == "chat": style = "class:contact-active"
|
||||||
elif idx == client.selected_contact_idx and get_app().layout.has_focus(sidebar_window) and client.current_tab == "chat": style = "class:contact-focused"
|
elif idx == client.selected_contact_idx and get_app().layout.has_focus(sidebar_window) and client.current_tab == "chat": style = "class:contact-focused"
|
||||||
else: style = "class:contact"
|
else: style = "class:contact"
|
||||||
|
|
@ -385,6 +481,19 @@ def make_layout():
|
||||||
if client.active_chat == g_id and client.current_tab == "chat": style = "class:contact-active"
|
if client.active_chat == g_id and client.current_tab == "chat": style = "class:contact-active"
|
||||||
else: style = "class:contact"
|
else: style = "class:contact"
|
||||||
tokens.extend([(style, f"{content}\n")])
|
tokens.extend([(style, f"{content}\n")])
|
||||||
|
=======
|
||||||
|
|
||||||
|
if client.active_chat == uin:
|
||||||
|
style = "class:contact-active"
|
||||||
|
elif idx == client.selected_contact_idx and get_app().layout.has_focus(sidebar_window):
|
||||||
|
style = "class:contact-focused"
|
||||||
|
else:
|
||||||
|
style = "class:contact"
|
||||||
|
|
||||||
|
tokens.extend([
|
||||||
|
(style, f"{content}\n"),
|
||||||
|
])
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
def get_main_text():
|
def get_main_text():
|
||||||
|
|
@ -397,15 +506,14 @@ def make_layout():
|
||||||
("class:desc", "Messenger on custom protocol named\n"),
|
("class:desc", "Messenger on custom protocol named\n"),
|
||||||
("class:desc", "AcoustiOverSocket inspired by rtty\n"),
|
("class:desc", "AcoustiOverSocket inspired by rtty\n"),
|
||||||
("", "\n"),
|
("", "\n"),
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
("class:help-tip", "Type / to trigger interactive command menu | F2: Settings Panel\n"),
|
("class:help-tip", "Type / to trigger interactive command menu | F2: Settings Panel\n"),
|
||||||
|
=======
|
||||||
|
("class:help-tip", "Type /help to open project Wiki\n"),
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
("", "\n" * 2),
|
("", "\n" * 2),
|
||||||
("class:help-tip", f"{DEV_SIGNATURE}\n")
|
("class:help-tip", f"{DEV_SIGNATURE}\n")
|
||||||
])
|
])
|
||||||
if client.dialing_uin:
|
|
||||||
tokens.extend([
|
|
||||||
("", "\n" * 2),
|
|
||||||
("class:system", f"Dialing UIN {client.dialing_uin}... Waiting for accept.\n")
|
|
||||||
])
|
|
||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
tokens = []
|
tokens = []
|
||||||
|
|
@ -419,6 +527,7 @@ def make_layout():
|
||||||
tokens.append(("", line + "\n"))
|
tokens.append(("", line + "\n"))
|
||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
def get_settings_text():
|
def get_settings_text():
|
||||||
tokens = [("class:popup-title", " === SETTINGS & PLUGINS PANEL ===\n\n")]
|
tokens = [("class:popup-title", " === SETTINGS & PLUGINS PANEL ===\n\n")]
|
||||||
|
|
||||||
|
|
@ -463,17 +572,19 @@ def make_layout():
|
||||||
newlines = text.count('\n')
|
newlines = text.count('\n')
|
||||||
return Point(0, max(0, newlines - 1))
|
return Point(0, max(0, newlines - 1))
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
sidebar_control = FormattedTextControl(get_sidebar_text, focusable=True)
|
sidebar_control = FormattedTextControl(get_sidebar_text, focusable=True)
|
||||||
sidebar_window = Frame(Window(content=sidebar_control, width=25), title="chats", style="class:border")
|
sidebar_window = Frame(Window(content=sidebar_control, width=25), title="chats", style="class:border")
|
||||||
main_control = FormattedTextControl(get_main_text, get_cursor_position=get_cursor_pos)
|
|
||||||
|
main_control = FormattedTextControl(get_main_text)
|
||||||
|
|
||||||
def get_main_title():
|
def get_main_title():
|
||||||
base_title = f"TyChat | You: {client.username} ({client.uin})"
|
if client.active_chat:
|
||||||
if client.is_busy: base_title += " [DND/BUSY]"
|
return f"TyChat | You: {client.username} ({client.uin}) | Chat with UIN: {client.active_chat}"
|
||||||
if client.active_chat: return f"{base_title} | Chat: {client.active_chat}"
|
return f"TyChat | You: {client.username} ({client.uin})"
|
||||||
return base_title
|
|
||||||
|
|
||||||
main_window = Frame(Window(content=main_control, wrap_lines=True), title=get_main_title, style="class:border")
|
main_window = Frame(Window(content=main_control), title=get_main_title, style="class:border")
|
||||||
|
|
||||||
settings_control = FormattedTextControl(get_settings_text, focusable=True)
|
settings_control = FormattedTextControl(get_settings_text, focusable=True)
|
||||||
settings_window = Frame(Window(content=settings_control, wrap_lines=True), title="Settings Router", style="class:border")
|
settings_window = Frame(Window(content=settings_control, wrap_lines=True), title="Settings Router", style="class:border")
|
||||||
|
|
@ -482,15 +593,15 @@ def make_layout():
|
||||||
height=3,
|
height=3,
|
||||||
prompt="> ",
|
prompt="> ",
|
||||||
multiline=False,
|
multiline=False,
|
||||||
wrap_lines=True,
|
wrap_lines=True
|
||||||
completer=CommandCompleter(),
|
|
||||||
complete_while_typing=True
|
|
||||||
)
|
)
|
||||||
input_window = Frame(input_field, title="Input")
|
|
||||||
|
input_window = Frame(input_field, title="Type message and press Enter (/exit to quit)")
|
||||||
|
|
||||||
def accept_handler(buff):
|
def accept_handler(buff):
|
||||||
text = input_field.text.strip()
|
text = input_field.text.strip()
|
||||||
if not text: return
|
if not text:
|
||||||
|
return
|
||||||
|
|
||||||
if text.lower() == "/exit":
|
if text.lower() == "/exit":
|
||||||
client.loop_running = False
|
client.loop_running = False
|
||||||
|
|
@ -499,66 +610,29 @@ def make_layout():
|
||||||
return
|
return
|
||||||
|
|
||||||
if text.lower() == "/help":
|
if text.lower() == "/help":
|
||||||
try: webbrowser.open(WIKI_URL)
|
try:
|
||||||
except: pass
|
webbrowser.open(WIKI_URL)
|
||||||
input_field.text = ""
|
if client.active_chat:
|
||||||
return
|
client.add_to_history(client.active_chat, "[SYSTEM]: Wiki link opened in browser.")
|
||||||
|
except:
|
||||||
if text.lower() == "/busy":
|
if client.active_chat:
|
||||||
client.is_busy = not client.is_busy
|
client.add_to_history(client.active_chat, f"[SYSTEM]: Failed to open browser. Wiki: {WIKI_URL}")
|
||||||
if client.active_chat:
|
|
||||||
status_msg = "enabled" if client.is_busy else "disabled"
|
|
||||||
client.add_to_history(client.active_chat, f"[SYSTEM]: DND Mode {status_msg}.")
|
|
||||||
input_field.text = ""
|
input_field.text = ""
|
||||||
client.refresh_ui()
|
client.refresh_ui()
|
||||||
return
|
return
|
||||||
|
|
||||||
if text.lower().startswith("/add "):
|
if text.lower().startswith("/add "):
|
||||||
new_uin = text.split(" ", 1)[1].strip()
|
new_uin = text.split(" ", 1)[1].strip()
|
||||||
if not new_uin: return
|
if new_uin and new_uin not in client.contacts:
|
||||||
if new_uin in client.contacts:
|
client.contacts[new_uin] = {"status": "offline", "unread": 0, "attention": False}
|
||||||
client.active_chat = new_uin
|
client.history[new_uin] = []
|
||||||
input_field.text = ""
|
client.save_config()
|
||||||
client.refresh_ui()
|
|
||||||
return
|
|
||||||
client.active_chat = None
|
|
||||||
threading.Thread(target=client.play_dial_tones, args=(new_uin,), daemon=True).start()
|
|
||||||
client.send_sys_packet(new_uin, "REQ_ADD")
|
|
||||||
input_field.text = ""
|
input_field.text = ""
|
||||||
client.refresh_ui()
|
client.refresh_ui()
|
||||||
return
|
return
|
||||||
|
|
||||||
if text.lower().startswith("/room create "):
|
|
||||||
match = re.match(r'^/room create "([^"]+)"$', text, re.IGNORECASE)
|
|
||||||
if match:
|
|
||||||
r_name = match.group(1)
|
|
||||||
r_id = f"ROOM:{client.uin}:{r_name}"
|
|
||||||
client.groups[r_id] = {"title": r_name, "owner": client.uin, "members": [client.uin]}
|
|
||||||
client.history[r_id] = [f"[SYSTEM]: Room \"{r_name}\" created successfully. Local GUID: {r_id}"]
|
|
||||||
client.active_chat = r_id
|
|
||||||
client.save_config()
|
|
||||||
client.refresh_ui()
|
|
||||||
input_field.text = ""
|
|
||||||
return
|
|
||||||
|
|
||||||
if text.lower().startswith("/room join "):
|
|
||||||
match = re.match(r'^/room join ([0-9]+):"([^"]+)"$', text, re.IGNORECASE)
|
|
||||||
if match:
|
|
||||||
r_owner = match.group(1)
|
|
||||||
r_name = match.group(2)
|
|
||||||
r_id = f"ROOM:{r_owner}:{r_name}"
|
|
||||||
if r_owner not in client.contacts and r_owner != client.uin:
|
|
||||||
client.contacts[r_owner] = {"status": "offline", "unread": 0, "attention": False}
|
|
||||||
client.groups[r_id] = {"title": r_name, "owner": r_owner, "members": list(set([client.uin, r_owner]))}
|
|
||||||
client.history[r_id] = [f"[SYSTEM]: Joined room \"{r_name}\". Local GUID: {r_id}"]
|
|
||||||
client.active_chat = r_id
|
|
||||||
client.save_config()
|
|
||||||
client.refresh_ui()
|
|
||||||
client.send_sys_packet(r_owner, f"REQ_JOIN_ROOM:{r_name}")
|
|
||||||
input_field.text = ""
|
|
||||||
return
|
|
||||||
|
|
||||||
if client.active_chat:
|
if client.active_chat:
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
if client.active_chat.startswith("ROOM:"):
|
if client.active_chat.startswith("ROOM:"):
|
||||||
group = client.groups[client.active_chat]
|
group = client.groups[client.active_chat]
|
||||||
owner_uin = group["owner"]
|
owner_uin = group["owner"]
|
||||||
|
|
@ -602,10 +676,14 @@ def make_layout():
|
||||||
input_field.text = ""
|
input_field.text = ""
|
||||||
return
|
return
|
||||||
if len(text) > 300:
|
if len(text) > 300:
|
||||||
|
=======
|
||||||
|
if len(text) > 100:
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
client.add_to_history(client.active_chat, f"[SYSTEM]: Message too long!")
|
client.add_to_history(client.active_chat, f"[SYSTEM]: Message too long!")
|
||||||
input_field.text = ""
|
input_field.text = ""
|
||||||
return
|
return
|
||||||
|
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
proto_to_use = client.peer_session_protocols.get(client.active_chat, client.primary_protocol)
|
proto_to_use = client.peer_session_protocols.get(client.active_chat, client.primary_protocol)
|
||||||
encoded = client.plugin_manager.safe_encode(proto_to_use, text)
|
encoded = client.plugin_manager.safe_encode(proto_to_use, text)
|
||||||
|
|
||||||
|
|
@ -648,18 +726,52 @@ def make_layout():
|
||||||
ConditionalContainer(content=settings_window, filter=is_settings_panel),
|
ConditionalContainer(content=settings_window, filter=is_settings_panel),
|
||||||
input_window
|
input_window
|
||||||
])
|
])
|
||||||
|
=======
|
||||||
|
match = re.match(r'^s/([^/]+)/([^/]*)/?$', text)
|
||||||
|
if match:
|
||||||
|
search_str, replace_str = match.groups()
|
||||||
|
lines = client.history.get(client.active_chat, [])
|
||||||
|
edited = False
|
||||||
|
for i in range(len(lines) - 1, -1, -1):
|
||||||
|
if lines[i].startswith(f"[{client.username}]:") or lines[i].startswith("[You]:"):
|
||||||
|
if search_str in lines[i]:
|
||||||
|
lines[i] = lines[i].replace(search_str, replace_str)
|
||||||
|
edited = True
|
||||||
|
break
|
||||||
|
if edited:
|
||||||
|
client.refresh_ui()
|
||||||
|
client.save_config()
|
||||||
|
input_field.text = ""
|
||||||
|
return
|
||||||
|
|
||||||
def get_popup_text():
|
if text.startswith("/alert"):
|
||||||
if not client.pending_requests: return []
|
text = "ALARM! URGENT CALL!"
|
||||||
req_uin = client.pending_requests[0]
|
client.contacts[client.active_chat]["attention"] = True
|
||||||
return [
|
|
||||||
("class:popup-title", f" Incoming Handshake Request \n"),
|
|
||||||
("class:popup-title", f" UIN: {req_uin} \n\n"),
|
|
||||||
("", " Do you want to add them to contacts?\n\n"),
|
|
||||||
("class:popup-keys", " [Y]es [N]o N[e]ver ")
|
|
||||||
]
|
|
||||||
popup_window = Frame(Window(FormattedTextControl(get_popup_text), align=WindowAlign.CENTER, width=42, height=6), style="class:popup-border")
|
|
||||||
|
|
||||||
|
audio_b = client.text_to_audio(text)
|
||||||
|
p_b64 = base64.b64encode(audio_b).decode('utf-8')
|
||||||
|
|
||||||
|
if client.contacts[client.active_chat]["status"] == "online":
|
||||||
|
sio.emit("relay_packet", {"to_uin": client.active_chat, "payload": p_b64})
|
||||||
|
client.add_to_history(client.active_chat, f"[You]: {text}")
|
||||||
|
else:
|
||||||
|
if client.active_chat not in client.preserved:
|
||||||
|
client.preserved[client.active_chat] = []
|
||||||
|
client.preserved[client.active_chat].append(text)
|
||||||
|
client.add_to_history(client.active_chat, f"[You]: {text} (Preserved)")
|
||||||
|
client.save_config()
|
||||||
|
|
||||||
|
input_field.text = ""
|
||||||
|
|
||||||
|
input_field.accept_handler = accept_handler
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
|
|
||||||
|
right_side = HSplit([
|
||||||
|
main_window,
|
||||||
|
input_window
|
||||||
|
])
|
||||||
|
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
def get_signal_popup_text():
|
def get_signal_popup_text():
|
||||||
if not client.pending_windows: return []
|
if not client.pending_windows: return []
|
||||||
win_info = client.pending_windows[0]
|
win_info = client.pending_windows[0]
|
||||||
|
|
@ -768,34 +880,51 @@ def make_layout():
|
||||||
client.refresh_ui()
|
client.refresh_ui()
|
||||||
|
|
||||||
@kb.add('tab', filter=~has_pending_request & ~has_pending_window & ~has_welcome_popup & is_chat_panel)
|
@kb.add('tab', filter=~has_pending_request & ~has_pending_window & ~has_welcome_popup & is_chat_panel)
|
||||||
def _(event):
|
=======
|
||||||
if event.app.layout.has_focus(input_field): event.app.layout.focus(sidebar_window)
|
root_container = VSplit([
|
||||||
else: event.app.layout.focus(input_field)
|
sidebar_window,
|
||||||
|
right_side
|
||||||
|
])
|
||||||
|
|
||||||
|
kb = KeyBindings()
|
||||||
|
|
||||||
|
@kb.add('tab')
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
|
def _(event):
|
||||||
|
if event.app.layout.has_focus(input_field):
|
||||||
|
event.app.layout.focus(sidebar_window)
|
||||||
|
else:
|
||||||
|
event.app.layout.focus(input_field)
|
||||||
|
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
@kb.add('up', filter=has_focus(sidebar_window) & ~has_pending_request & ~has_pending_window & ~has_welcome_popup & is_chat_panel)
|
@kb.add('up', filter=has_focus(sidebar_window) & ~has_pending_request & ~has_pending_window & ~has_welcome_popup & is_chat_panel)
|
||||||
|
=======
|
||||||
|
@kb.add('up', filter=has_focus(sidebar_window))
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
def _(event):
|
def _(event):
|
||||||
all_chats = list(client.contacts.keys()) + list(client.groups.keys())
|
if client.contacts:
|
||||||
if all_chats:
|
client.selected_contact_idx = (client.selected_contact_idx - 1) % len(client.contacts)
|
||||||
client.selected_contact_idx = (client.selected_contact_idx - 1) % len(all_chats)
|
target_uin = list(client.contacts.keys())[client.selected_contact_idx]
|
||||||
target = all_chats[client.selected_contact_idx]
|
client.active_chat = target_uin
|
||||||
client.active_chat = target
|
client.contacts[target_uin]["unread"] = 0
|
||||||
if target in client.contacts:
|
client.contacts[target_uin]["attention"] = False
|
||||||
client.contacts[target]["unread"] = 0
|
|
||||||
client.contacts[target]["attention"] = False
|
|
||||||
client.refresh_ui()
|
client.refresh_ui()
|
||||||
|
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
@kb.add('down', filter=has_focus(sidebar_window) & ~has_pending_request & ~has_pending_window & ~has_welcome_popup & is_chat_panel)
|
@kb.add('down', filter=has_focus(sidebar_window) & ~has_pending_request & ~has_pending_window & ~has_welcome_popup & is_chat_panel)
|
||||||
|
=======
|
||||||
|
@kb.add('down', filter=has_focus(sidebar_window))
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
def _(event):
|
def _(event):
|
||||||
all_chats = list(client.contacts.keys()) + list(client.groups.keys())
|
if client.contacts:
|
||||||
if all_chats:
|
client.selected_contact_idx = (client.selected_contact_idx + 1) % len(client.contacts)
|
||||||
client.selected_contact_idx = (client.selected_contact_idx + 1) % len(all_chats)
|
target_uin = list(client.contacts.keys())[client.selected_contact_idx]
|
||||||
target = all_chats[client.selected_contact_idx]
|
client.active_chat = target_uin
|
||||||
client.active_chat = target
|
client.contacts[target_uin]["unread"] = 0
|
||||||
if target in client.contacts:
|
client.contacts[target_uin]["attention"] = False
|
||||||
client.contacts[target]["unread"] = 0
|
|
||||||
client.contacts[target]["attention"] = False
|
|
||||||
client.refresh_ui()
|
client.refresh_ui()
|
||||||
|
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
@kb.add('y', filter=has_welcome_popup)
|
@kb.add('y', filter=has_welcome_popup)
|
||||||
@kb.add('Y', filter=has_welcome_popup)
|
@kb.add('Y', filter=has_welcome_popup)
|
||||||
def _(event):
|
def _(event):
|
||||||
|
|
@ -854,6 +983,8 @@ def make_layout():
|
||||||
client.send_sys_packet(req_uin, "RES_DEC")
|
client.send_sys_packet(req_uin, "RES_DEC")
|
||||||
client.refresh_ui()
|
client.refresh_ui()
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
@kb.add('c-c')
|
@kb.add('c-c')
|
||||||
def _(event):
|
def _(event):
|
||||||
client.loop_running = False
|
client.loop_running = False
|
||||||
|
|
@ -873,13 +1004,6 @@ ui_style = Style.from_dict({
|
||||||
'system': '#ff0000 bold',
|
'system': '#ff0000 bold',
|
||||||
'border': '#00ff00',
|
'border': '#00ff00',
|
||||||
'frame.border': '#00ff00',
|
'frame.border': '#00ff00',
|
||||||
'popup-title': '#ffffff bold',
|
|
||||||
'popup-keys': '#00ff00 bold',
|
|
||||||
'popup-border': '#ff0000 bold',
|
|
||||||
'query-title': '#00ffff bold',
|
|
||||||
'alert-title': '#ff0000 bold',
|
|
||||||
'completion-menu.completion': 'bg:#00ffff #000000',
|
|
||||||
'completion-menu.completion.current': 'bg:#00aa00 #ffffff bold'
|
|
||||||
})
|
})
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
@ -888,38 +1012,54 @@ def main():
|
||||||
try:
|
try:
|
||||||
kernel32 = ctypes.windll.kernel32
|
kernel32 = ctypes.windll.kernel32
|
||||||
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
|
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
is_new_registration = False
|
is_new_registration = False
|
||||||
socket_manager.init_network(client)
|
socket_manager.init_network(client)
|
||||||
|
=======
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
|
|
||||||
if not client.load_config():
|
if not client.load_config():
|
||||||
print("!" * 60)
|
print("!" * 60)
|
||||||
print("WARNING: All data is local.")
|
print("WARNING:")
|
||||||
|
print("You will receive new messages only when you are online.")
|
||||||
|
print("All history is stored locally in settings.json.")
|
||||||
|
print("Anyone who knows your UIN can message you.")
|
||||||
|
print("This software uses loud sounds, adjust your client volume beforehand!")
|
||||||
print("!" * 60 + "\n")
|
print("!" * 60 + "\n")
|
||||||
|
|
||||||
client.server_url = input("Enter server URL: ").strip()
|
client.server_url = input("Enter server URL (e.g., http://localhost:5000): ").strip()
|
||||||
if not client.server_url.startswith("http://") and not client.server_url.startswith("https://"):
|
if not client.server_url.startswith("http://") and not client.server_url.startswith("https://"):
|
||||||
client.server_url = "http://" + client.server_url
|
client.server_url = "http://" + client.server_url
|
||||||
|
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
try: socket_manager.sio.connect(client.server_url, transports=['websocket'])
|
try: socket_manager.sio.connect(client.server_url, transports=['websocket'])
|
||||||
except Exception as e: return
|
except Exception as e: return
|
||||||
|
=======
|
||||||
|
try:
|
||||||
|
sio.connect(client.server_url, transports=['websocket'])
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to connect to server: {e}")
|
||||||
|
return
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
|
|
||||||
print("\n1. Register\n2. Login")
|
print("\n1. Register\n2. Login")
|
||||||
mode = input("> ")
|
mode = input("> ")
|
||||||
username_or_uin = input("UIN/Username: ").strip()
|
username_or_uin = input("Enter Username (for reg) or UIN (for login): ").strip()
|
||||||
password = input("Password: ").strip()
|
password = input("Enter password: ").strip()
|
||||||
|
|
||||||
event_wait = threading.Event()
|
event_wait = threading.Event()
|
||||||
|
|
||||||
@socket_manager.sio.event
|
@socket_manager.sio.event
|
||||||
def register_response(data):
|
def register_response(data):
|
||||||
nonlocal is_new_registration
|
|
||||||
if data["status"] == "success":
|
if data["status"] == "success":
|
||||||
client.uin = data['uin']
|
client.uin = data['uin']
|
||||||
client.username = username_or_uin
|
client.username = username_or_uin
|
||||||
client.password = password
|
client.password = password
|
||||||
is_new_registration = True
|
print(f"\nSuccess! Your UIN: {client.uin}")
|
||||||
event_wait.set()
|
event_wait.set()
|
||||||
|
|
||||||
@socket_manager.sio.event
|
@socket_manager.sio.event
|
||||||
|
|
@ -928,25 +1068,47 @@ def main():
|
||||||
client.uin = username_or_uin
|
client.uin = username_or_uin
|
||||||
client.username = data["username"]
|
client.username = data["username"]
|
||||||
client.password = password
|
client.password = password
|
||||||
|
print(f"\nHello, {client.username}! Logged in successfully.")
|
||||||
event_wait.set()
|
event_wait.set()
|
||||||
|
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
if mode == "1": socket_manager.sio.emit("register", {"username": username_or_uin, "password": password})
|
if mode == "1": socket_manager.sio.emit("register", {"username": username_or_uin, "password": password})
|
||||||
else: socket_manager.sio.emit("login", {"uin": username_or_uin, "password": password})
|
else: socket_manager.sio.emit("login", {"uin": username_or_uin, "password": password})
|
||||||
event_wait.wait()
|
event_wait.wait()
|
||||||
|
=======
|
||||||
|
if mode == "1":
|
||||||
|
sio.emit("register", {"username": username_or_uin, "password": password})
|
||||||
|
event_wait.wait()
|
||||||
|
else:
|
||||||
|
sio.emit("login", {"uin": username_or_uin, "password": password})
|
||||||
|
event_wait.wait()
|
||||||
|
|
||||||
|
if not client.uin:
|
||||||
|
print("Auth error.")
|
||||||
|
return
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
|
|
||||||
if not client.uin: return
|
|
||||||
client.save_config()
|
client.save_config()
|
||||||
|
print("\nYou can change configurations inside settings.json.")
|
||||||
input("Press Enter to open TUI...")
|
input("Press Enter to open TUI...")
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
<<<<<<< HEAD:TUI.py
|
||||||
socket_manager.sio.connect(client.server_url, transports=['websocket'])
|
socket_manager.sio.connect(client.server_url, transports=['websocket'])
|
||||||
socket_manager.sio.emit("login", {"uin": client.uin, "password": client.password})
|
socket_manager.sio.emit("login", {"uin": client.uin, "password": client.password})
|
||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
if is_new_registration:
|
if is_new_registration:
|
||||||
client.show_welcome_popup = True
|
client.show_welcome_popup = True
|
||||||
|
=======
|
||||||
|
sio.connect(client.server_url, transports=['websocket'])
|
||||||
|
sio.emit("login", {"uin": client.uin, "password": client.password})
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
>>>>>>> parent of cfd13cf (Update client.py):client.py
|
||||||
|
|
||||||
threading.Thread(target=status_checker_thread, daemon=True).start()
|
threading.Thread(target=status_checker_thread, daemon=True).start()
|
||||||
|
|
||||||
layout, bindings = make_layout()
|
layout, bindings = make_layout()
|
||||||
|
|
||||||
client.app = Application(
|
client.app = Application(
|
||||||
|
|
@ -956,6 +1118,7 @@ def main():
|
||||||
full_screen=True,
|
full_screen=True,
|
||||||
enable_page_navigation_bindings=True
|
enable_page_navigation_bindings=True
|
||||||
)
|
)
|
||||||
|
|
||||||
client.app.run()
|
client.app.run()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
||||||
Reference in a new issue