async def open_link(self, num = None): def httpify(s): if s.startswith("http"): return s return f"https://{s}" if num is None: return message = self.dialogs[self.selected_chat]["messages"][num] if message.entities: links = [ text for (entity_type, text) in message.get_entities_text() if entity_type.to_dict()["_"] == "MessageEntityUrl" ] if len(links) == 1: # if there is a unique link to open, open it. link = links[0] debug(["xdg-open", f"{httpify(link)}"]) subprocess.Popen(["xdg-open", f"{httpify(link)}"], stdout = subprocess.DEVNULL, stderr = subprocess.DEVNULL) elif len(links) > 1: # user selects which link to open self.tab_selection = 0 async def handler(self, key): if key == "TAB": self.tab_selection = (self.tab_selection + 1) % len(links) self.popup[1] = f"Select link to open (TAB): {links[self.tab_selection]}" elif key == "ESCAPE": self.modestack.pop() elif key == "RETURN": link = links[self.tab_selection] debug(["xdg-open", f"{httpify(link)}"]) subprocess.Popen(["xdg-open", f"{httpify(link)}"], stdout = subprocess.DEVNULL, stderr = subprocess.DEVNULL) self.modestack.pop() self.spawn_popup(handler, f"Select link to open (TAB): {links[self.tab_selection]}")
async def ask_macro(self, key): if key in self.macros.keys(): macro = self.macros[key] debug(macro) for k in macro: await self.handle_key(k, redraw = False) else: self.popup_message(f"No such macro @{key}")
async def handler(self, key): if key == "TAB": self.tab_selection = (self.tab_selection + 1) % len(links) self.popup[1] = f"Select link to open (TAB): {links[self.tab_selection]}" elif key == "ESCAPE": self.modestack.pop() elif key == "RETURN": link = links[self.tab_selection] debug(["xdg-open", f"{httpify(link)}"]) subprocess.Popen(["xdg-open", f"{httpify(link)}"], stdout = subprocess.DEVNULL, stderr = subprocess.DEVNULL) self.modestack.pop()
async def run(self): await self.client.connect() self.stdscr.addstr("connected") self.auth = await self.client.is_user_authorized() draw_logo(self.stdscr) if not self.auth: while True: self.stdscr.addstr("Please enter your phone number: ") self.stdscr.refresh() self.phone = await self.textinput() self.phone = self.phone.replace("+", "00").replace(" ", "") try: response = await self.client.sign_in(phone=self.phone) debug(str(response)) break except telethon.errors.rpcerrorlist.FloodWaitError as err: self.stdscr.addstr( f"The telegram servers blocked you for too many retries ({err.seconds}s remaining). " ) self.stdscr.refresh() except telethon.errors.rpcerrorlist.PhoneNumberInvalidError as err: self.stdscr.addstr("Incorrect phone number. ") self.stdscr.refresh() except Exception as err: debug(f"Uncaught Error: {err}") self.stdscr.addstr(f"Uncaught Error: {err}") self.stdscr.refresh() self.stdscr.addstr( "Now authentificate with the code telegram sent to you.") self.stdscr.refresh() while True: done = False try: self.code = await self.textinput() await self.client.sign_in(code=self.code) done = True except telethon.errors.rpcerrorlist.PhoneCodeInvalidError: self.stdscr.addstr( "The authentification code was wrong. Please try again." ) self.stdscr.refresh() except telethon.errors.rpcerrorlist.SessionPasswordNeededError: self.showinput = False self.stdscr.addstr("A 2FA password is required to log in.") self.stdscr.refresh() while True: self.passwd = await self.textinput() try: await self.client.sign_in(password=self.passwd) done = True break except telethon.errors.PasswordHashInvalidError: self.stdscr.addstr( "Incorrect password. Try again.") self.stdscr.refresh() except Exception as err: debug(f"Uncaught Error: {err}") self.stdscr.addstr(f"Uncaught Error: {err}") self.stdscr.refresh() if done: break self.stdscr.addstr( "Authentification successfull. Please wait until the client has finished loading." ) self.stdscr.refresh()
def draw_text(self, format_dicts, y_off=0, x_off=0, screen=None, maxwidth=None, separator=" "): if maxwidth == None: maxwidth = sum(format_dict["width"] for format_dict in format_dicts) if screen == None: screen = self.stdscr left = [x for x in format_dicts if x["alignment"] == "left"] right = list( reversed([x for x in format_dicts if x["alignment"] == "right"])) center = [x for x in format_dicts if x["alignment"] == "center"] entries = [(x, "left") for x in left] + [(x, "right") for x in right] + [(x, "center") for x in center] x_left = 0 x_right = maxwidth - 1 for (format_dict, alignment) in entries: text = format_dict["text"] text = text.replace("\n", "") attributes = format_dict["attributes"] width = format_dict["width"] inner_alignment = format_dict["inner_alignment"] truncation = format_dict["truncation"] # TODO: make this split preferrably at spaces and not show linebreaks display_text = text.replace("\n", " ") #" ".join(text)#.split("\n")[0] debug(f"{text=}\n\t{width=}\n\t{display_text=}") if len(display_text) > width: if truncation: # TODO: make this split preferrably at spaces and not show linebreaks display_text = display_text[:width - len(truncation)] + truncation else: display_text = display_text[:width] rljust = " " * (width - len(display_text)) if alignment == "left": if inner_alignment == "left": screen.addstr(y_off, x_off + x_left, display_text, attributes) x_left += len(display_text) if rljust: screen.addstr(y_off, x_off + x_left, rljust) x_left += len(rljust) elif inner_alignment == "right": if rljust: screen.addstr(y_off, x_off + x_left, rljust) x_left += len(rljust) screen.addstr(y_off, x_off + x_left, display_text, attributes) x_left += len(display_text) if left and format_dict != left[-1]: screen.addstr(y_off, x_off + x_left, separator) x_left += len(separator) elif alignment == "right": if inner_alignment == "left": x_right -= len(text) self.stdscr.addstr(y_off, x_off + x_right, text, attributes) x_right -= len(rljust) self.stdscr.addstr(y_off, x_off + x_right, rljust) elif inner_alignment == "right": x_right -= len(rljust) self.stdscr.addstr(y_off, x_off + x_right, rljust) x_right -= len(text) self.stdscr.addstr(y_off, x_off + x_right, text, attributes) if right and format_dict != right[-1]: x_right -= len(separator) self.stdscr.addstr(y_off, x_off + x_right, separator) elif alignment == "center": self.stdscr.addstr(y_off, maxwidth // 2 - len(display_text) // 2, display_text, attributes)
def draw_chats(self): selected_chat_index = self.main_view.selected_chat - self.main_view.selected_chat_offset offset = self.main_view.selected_chat_offset try: self.draw_frame(0, 0, self.chats_height + 1, self.chats_width) index = 0 y = 1 chats_to_draw = self.chats_num while index < chats_to_draw: # only draw if messages are pinned and pins are viewable (at top) if index != 0 and index == self.main_view.num_pinned - offset: self.draw_text([ self.format("─" * (self.chats_width // 2 - 1), alignment="center"), ], y, 1, maxwidth=self.chats_width - 2) y += 2 dialog = self.main_view.dialogs[index + offset] if dialog["dialog"].archived: index += 1 chats_to_draw += 1 continue message = dialog["messages"][0] if len( dialog["messages"]) > 0 else dialog["dialog"].message message_string = message.text if message.text else "[Non-text object]" if self.main_view.text_emojis: message_string = emojis.decode(message_string) chat_name = get_display_name(dialog["dialog"].entity) if self.main_view.text_emojis: chat_name = emojis.decode(chat_name) from_string = get_display_name(message.sender) unread = dialog["unread_count"] unread_string = f"({unread} new)" if unread else "" date = dialog["dialog"].date date = date.astimezone() date_string = self._datestring(date) pinned = "* " if dialog["dialog"].pinned else " " selected = selected_chat_index == index self.draw_text([ self.format("o" if dialog["online"] else " ", attributes=self.main_view.colors["secondary"]), self.format( chat_name, attributes=self.main_view.colors["primary"] | curses.A_STANDOUT if selected else curses.A_BOLD, width=int(0.5 * self.chats_width)), self.format(f" {str(index)} " if self.show_indices else "", attributes=self.main_view.colors["standout"]), self.format(unread_string, attributes=self.main_view.colors["error"], alignment="right"), self.format(date_string, alignment="right", attributes=self.main_view.colors["primary"]), ], y, 2, maxwidth=self.chats_width - 2) debug(f"{self.chats_width=}") self.draw_text([ self.format(f"{from_string}:", width=min(self.chats_width // 2, len(from_string) + 1)), self.format(message_string, width=self.chats_width - min(self.chats_width // 2, len(f"{from_string}: ") + 1) - 3) ], y + 1, 2, maxwidth=self.chats_width - 2) y += 3 index += 1 except Exception: show_stacktrace()
async def _handle_key(self, key): debug("called") await self.main_view.toggle_pin()