Beispiel #1
0
 def open_url(self) -> None:
     msg = MsgProxy(self.model.current_msg)
     if not msg.is_text:
         return self.present_error("Does not contain urls")
     text = msg["content"]["text"]["text"]
     urls = []
     for entity in msg["content"]["text"]["entities"]:
         _type = entity["type"]["@type"]
         if _type == "textEntityTypeUrl":
             offset = entity["offset"]
             length = entity["length"]
             url = text[offset:offset + length]
         elif _type == "textEntityTypeTextUrl":
             url = entity["type"]["url"]
         else:
             continue
         urls.append(url)
     if not urls:
         return self.present_error("No url to open")
     if len(urls) == 1:
         with suspend(self.view) as s:
             s.call(
                 config.DEFAULT_OPEN.format(file_path=shlex.quote(urls[0])))
         return
     with suspend(self.view) as s:
         s.run_with_input(config.URL_VIEW, "\n".join(urls))
Beispiel #2
0
    def choose_and_send_file(self) -> None:
        """Call file picker and send chosen file based on mimetype"""
        chat_id = self.model.chats.id_by_index(self.model.current_chat)
        file_path = None
        if not chat_id:
            return self.present_error("No chat selected")
        try:
            with NamedTemporaryFile("w") as f, suspend(self.view) as s:
                s.call(config.FILE_PICKER_CMD.format(file_path=f.name))
                with open(f.name) as f:
                    file_path = f.read().strip()
        except FileNotFoundError:
            pass
        if not file_path or not os.path.isfile(file_path):
            return self.present_error("No file was selected")
        mime_map = {
            "animation": self.tg.send_animation,
            "image": self.tg.send_photo,
            "audio": self.tg.send_audio,
            "video": self._send_video,
        }
        mime = get_mime(file_path)
        if mime in ("image", "video", "animation"):
            resp = self.view.status.get_input(
                f"Upload <{file_path}> compressed?[Y/n]")
            self.render_status()
            if resp is None:
                return self.present_info("Uploading cancelled")
            if not is_yes(resp):
                mime = ""

        fun = mime_map.get(mime, self.tg.send_doc)
        fun(file_path, chat_id)
Beispiel #3
0
    def record_voice(self):
        file_path = f"/tmp/voice-{datetime.now()}.oga"
        with suspend(self.view) as s:
            s.call(
                config.VOICE_RECORD_CMD.format(
                    file_path=shlex.quote(file_path)
                )
            )
        resp = self.view.status.get_input(
            f"Do you want to send recording: {file_path}? [Y/n]"
        )
        if not is_yes(resp):
            self.present_info("Voice message discarded")
            return

        if not os.path.isfile(file_path):
            self.present_info(f"Can't load recording file {file_path}")
            return

        chat_id = self.model.chats.id_by_index(self.model.current_chat)
        if not chat_id:
            return
        duration = get_duration(file_path)
        waveform = get_waveform(file_path)
        self.tg.send_voice(file_path, chat_id, duration, waveform)
        self.present_info(f"Sent voice msg: {file_path}")
Beispiel #4
0
    def show_chat_info(self) -> None:
        """Show chat information"""
        chat = self.model.chats.chats[self.model.current_chat]
        info = self.model.get_chat_info(chat)

        with suspend(self.view) as s:
            s.run_with_input(
                config.VIEW_TEXT_CMD,
                "\n".join(f"{k}: {v}" for k, v in info.items() if v),
            )
Beispiel #5
0
    def _open_msg(self, msg: MsgProxy, cmd: str = None) -> None:
        if msg.is_text:
            with NamedTemporaryFile("w", suffix=".txt") as f:
                f.write(msg.text_content)
                f.flush()
                with suspend(self.view) as s:
                    s.open_file(f.name, cmd)
            return

        path = msg.local_path
        if not path:
            self.present_info("File should be downloaded first")
            return
        chat_id = self.model.chats.id_by_index(self.model.current_chat)
        if not chat_id:
            return
        self.tg.open_message_content(chat_id, msg.msg_id)
        with suspend(self.view) as s:
            s.open_file(path, cmd)
Beispiel #6
0
    def show_user_info(self) -> None:
        """Show user profile"""
        msg = MsgProxy(self.model.current_msg)
        user_id = msg.sender_id
        info = self.model.get_user_info(user_id)

        with suspend(self.view) as s:
            s.run_with_input(
                config.VIEW_TEXT_CMD,
                "\n".join(f"{k}: {v}" for k, v in info.items() if v),
            )
Beispiel #7
0
 def write_long_msg(self):
     if not self.can_send_msg():
         self.present_info("Can't send msg in this chat")
         return
     with NamedTemporaryFile("r+", suffix=".txt") as f, suspend(
         self.view
     ) as s:
         s.call(config.LONG_MSG_CMD.format(file_path=shlex.quote(f.name)))
         with open(f.name) as f:
             if msg := f.read().strip():
                 self.model.send_message(text=msg)
                 self.present_info("Message sent")
Beispiel #8
0
 def write_long_msg(self) -> None:
     chat_id = self.model.chats.id_by_index(self.model.current_chat)
     if not self.can_send_msg() or chat_id is None:
         self.present_info("Can't send msg in this chat")
         return
     with NamedTemporaryFile("r+",
                             suffix=".txt") as f, suspend(self.view) as s:
         self.tg.send_chat_action(chat_id, ChatAction.chatActionTyping)
         s.call(config.LONG_MSG_CMD.format(file_path=shlex.quote(f.name)))
         with open(f.name) as f:
             if msg := f.read().strip():
                 self.model.send_message(text=msg)
                 self.present_info("Message sent")
             else:
Beispiel #9
0
    def _get_user_ids(self, is_multiple: bool = False) -> List[int]:
        users = self.model.users.get_users()
        _, cols = self.view.stdscr.getmaxyx()
        limit = min(
            int(cols / 2),
            max(len(user.name) for user in users),
        )
        users_out = "\n".join(
            f"{user.id}\t{user.name:<{limit}} | {user.status}"
            for user in sorted(users, key=lambda user: user.order))
        cmd = config.FZF + " -n 2"
        if is_multiple:
            cmd += " -m"

        with NamedTemporaryFile("r+") as tmp, suspend(self.view) as s:
            s.run_with_input(f"{cmd} > {tmp.name}", users_out)
            with open(tmp.name) as f:
                return [int(line.split()[0]) for line in f.readlines()]
Beispiel #10
0
 def reply_with_long_message(self):
     if not self.can_send_msg():
         self.present_info("Can't send msg in this chat")
         return
     chat_id = self.model.current_chat_id
     reply_to_msg = self.model.current_msg_id
     msg = MsgProxy(self.model.current_msg)
     with NamedTemporaryFile("w+", suffix=".txt") as f, suspend(
         self.view
     ) as s:
         f.write(insert_replied_msg(msg))
         f.seek(0)
         s.call(config.LONG_MSG_CMD.format(file_path=shlex.quote(f.name)))
         with open(f.name) as f:
             if msg := strip_replied_msg(f.read().strip()):
                 self.tg.reply_message(chat_id, reply_to_msg, msg)
                 self.present_info("Message sent")
             else:
Beispiel #11
0
    def edit_msg(self) -> None:
        msg = MsgProxy(self.model.current_msg)
        log.info("Editing msg: %s", msg.msg)
        if not self.model.is_me(msg.sender_id):
            return self.present_error("You can edit only your messages!")
        if not msg.is_text:
            return self.present_error("You can edit text messages only!")
        if not msg.can_be_edited:
            return self.present_error("Meessage can't be edited!")

        with NamedTemporaryFile("r+",
                                suffix=".txt") as f, suspend(self.view) as s:
            f.write(msg.text_content)
            f.flush()
            s.call(f"{config.EDITOR} {f.name}")
            with open(f.name) as f:
                if text := f.read().strip():
                    self.model.edit_message(text=text)
                    self.present_info("Message edited")
Beispiel #12
0
    def view_contacts(self) -> None:
        contacts = self.model.users.get_contacts()
        if contacts is None:
            return self.present_error("Can't get contacts")

        total = contacts["total_count"]
        users = []
        for user_id in contacts["user_ids"]:
            user_name = get_user_label(self.model.users, user_id)
            status = self.model.users.get_status(user_id)
            order = self.model.users.get_user_status_order(user_id)
            users.append((user_name, status, order))

        _, cols = self.view.stdscr.getmaxyx()
        limit = min(int(cols / 2),
                    max(len(user_name) for user_name, *_ in users))
        users_out = "\n".join(
            f"{user_name:<{limit}} | {status}"
            for user_name, status, _ in sorted(users, key=lambda it: it[2]))
        with suspend(self.view) as s:
            s.run_with_input(config.VIEW_TEXT_CMD,
                             f"{total} users:\n" + users_out)
Beispiel #13
0
 def breakpoint(self) -> None:
     with suspend(self.view):
         breakpoint()
Beispiel #14
0
 def show_msg_help(self) -> None:
     _help = self.format_help(msg_handler)
     with suspend(self.view) as s:
         s.run_with_input(config.VIEW_TEXT_CMD, _help)
Beispiel #15
0
 def breakpoint(self):
     with suspend(self.view):
         breakpoint()
Beispiel #16
0
 def show_msg_help(self):
     _help = self.format_help(msg_handler)
     with suspend(self.view) as s:
         s.run_with_input(config.HELP_CMD, _help)