def reply_text_or_edit_with_keyboard( message: Message, query: Optional[CallbackQuery], text: str, reply_markup: Union[InlineKeyboardMarkup, str], quote: bool = False, **kwargs, ): # Для запросов CallbackQuery нужно менять текущее сообщение if query: # Fix error: "telegram.error.BadRequest: Message is not modified" if text == query.message.text and is_equal_inline_keyboards( reply_markup, query.message.reply_markup): return try: message.edit_text( text, reply_markup=reply_markup, **kwargs, ) except telegram.error.BadRequest as e: if 'Message is not modified' in str(e): return raise e else: message.reply_text( text, reply_markup=reply_markup, quote=quote, **kwargs, )
def update_text(self, message: telegram.Message, text: str): """ Update text function. Arguments: message : Message to update text : New text to send """ if message.text != text: try: message.edit_text(text) except Exception as e: pass
def edit_mdv2(tg_msg: TelegramMessage, msg_text, keyboard=None, need_cancel=True): cancel_button = InlineKeyboardButton( text=GlobalTxt.CANCEL_BUTTON_TEXT, callback_data=GlobalTxt.CANCEL_BUTTON_CB_DATA) if need_cancel: if keyboard: keyboard.append([cancel_button]) else: keyboard = [[cancel_button]] tg_msg.edit_text( text=msg_text, parse_mode=ParseMode.MARKDOWN_V2, reply_markup=InlineKeyboardMarkup(keyboard) if keyboard else None, disable_web_page_preview=True)
def __iteratively_edit_message(self, message: Message, texts: list, current_item: int, time_per_message: timedelta): if self.iterating_chats[ message.chat_id] != message.message_id or current_item > 50: return message = message.edit_text(texts[current_item % len(texts)]) current_item += 1 self.updater.dispatcher.job_queue.run_once( lambda job: self.__iteratively_edit_message( message, texts, current_item, time_per_message), time_per_message)
def __delayed_type_message_part(self, message: Message, text: str, current_char: int, time_per_char: timedelta, callback: callable): while text[0:current_char].strip() == message.text: current_char += 1 partial_text = text[0:current_char] message = message.edit_text(partial_text) if current_char == len(text): callback() return self.updater.dispatcher.job_queue.run_once( lambda job: self.__delayed_type_message_part( message, text, current_char + 1, time_per_char, callback), time_per_char)
def edit_message(original: Message, message: any, add_dismiss: bool = True): """ :param original: :param message: :param add_dismiss: :return: """ text, callbacks, sizes = MessageManager.__split_message(message) # Get Reply Markup reply_markup = MessageManager.__make_reply_markup( callbacks, sizes, add_dismiss) return original.edit_text(text=text, parse_mode='HTML', disable_web_page_preview=True, reply_markup=reply_markup)
def auto_next_frame(message: Message): finish = datetime.datetime.now() + datetime.timedelta(days=1) time.sleep(5) while finish > datetime.datetime.now(): try: for frame in frames[1:5]: try: message.edit_text( text=f"<code>{html.escape(frame)}</code>", parse_mode="HTML", ) except BadRequest: pass time.sleep(1) time.sleep(3) for frame in frames[5:9]: try: message.edit_text( text=f"<code>{html.escape(frame)}</code>", parse_mode="HTML", ) except: pass time.sleep(1) time.sleep(7) except TimedOut: time.sleep(2) continue except RetryAfter as err: print("/norooz: retry after", err.retry_after) time.sleep(err.retry_after) while 1: try: message.edit_text( text=f"<code>{html.escape(frames[9])}</code>", parse_mode="HTML", ) break except TimedOut: time.sleep(2) except RetryAfter: print("/norooz: retry after", err.retry_after) time.sleep(err.retry_after)
def _create_timelapse( self, printing_filename: str, gcode_name: str, info_mess: Message) -> Tuple[BytesIO, BytesIO, int, int, str, str]: if not printing_filename: raise ValueError("Gcode file name is empty") while self.light_need_off: time.sleep(1) lapse_dir = f"{self._base_dir}/{printing_filename}" lock_file = Path(f"{lapse_dir}/lapse.lock") if not lock_file.is_file(): lock_file.touch() # Todo: check for nonempty photos! photos = glob.glob(f"{glob.escape(lapse_dir)}/*.{self._img_extension}") photos.sort(key=os.path.getmtime) photo_count = len(photos) if photo_count == 0: raise ValueError( f"Empty photos list for {printing_filename} in lapse path {lapse_dir}" ) info_mess.edit_text(text="Creating thumbnail") last_photo = photos[-1] img = cv2.imread(last_photo) height, width, layers = img.shape thumb_bio = self._create_thumb(img) video_filename = Path(printing_filename).name video_filepath = f"{lapse_dir}/{video_filename}.mp4" if Path(video_filepath).is_file(): os.remove(video_filepath) lapse_fps = self._calculate_fps(photo_count) with self._camera_lock: cv2.setNumThreads( self._threads) # TOdo: check self set and remove! out = cv2.VideoWriter( video_filepath, fourcc=cv2.VideoWriter_fourcc(*self._fourcc), fps=lapse_fps, frameSize=(width, height), ) info_mess.edit_text(text="Images recoding") last_update_time = time.time() for fnum, filename in enumerate(photos): if time.time() >= last_update_time + 3: info_mess.edit_text( text=f"Images recoded {fnum}/{photo_count}") last_update_time = time.time() out.write(cv2.imread(filename)) info_mess.edit_text( text= f"Repeating last image for {self._last_frame_duration} seconds" ) for _ in range(lapse_fps * self._last_frame_duration): out.write(img) out.release() cv2.destroyAllWindows() del out del photos, img, layers # Todo: some error handling? video_bio = BytesIO() video_bio.name = f"{video_filename}.mp4" target_video_file = f"{self._ready_dir}/{printing_filename}.mp4" with open(video_filepath, "rb") as fh: video_bio.write(fh.read()) if self._ready_dir and os.path.isdir(self._ready_dir): info_mess.edit_text(text="Copy lapse to target ditectory") Path(target_video_file).parent.mkdir(parents=True, exist_ok=True) with open(target_video_file, "wb") as cpf: cpf.write(video_bio.getvalue()) video_bio.seek(0) os.remove(f"{lapse_dir}/lapse.lock") return video_bio, thumb_bio, width, height, video_filepath, gcode_name
def send_plan(userid: str, chat: Chat, new_plan=True, message: Message = None, date=None, custom_name=None): if not date: date = datetime.today() logging.debug("/send_plan") if date.weekday() == 5: date += timedelta(days=2) elif date.weekday() == 6: date += timedelta(days=1) def date_to_name(_date): return ("Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag")[date.weekday()] def construct_message(day, _substitution, _date, _infos): week = "B" if _date.isocalendar()[1] % 2 == 0: # even = A week = "A" msg = "```" msg += f' {week} {date_to_name(_date).ljust(7)} {_date.strftime("%d-%m-%y")}' # plan for row in range(len(day)): # for every lesson if day[row] != "---": # if day not empty msg += f'\n{row + 1} ' msg += f"{day[row].split(' ')[1].rjust(7)} " msg += f"{day[row].split(' ')[2].ljust(4)} " if len(day[row].split(' ')) > 3: msg += f"{day[row].split(' ')[3]} " # add substitution plan infos # possible types: Vertr. | Verlegung | Raum | Vtr. | enfälllt | EVA | Betreuung | Unterricht geändert | Trotz Absenz for entry in _substitution: if entry["subject"] == day[row].split(" ")[1]: # if substitution matches a subject subst_msg = "-> " if entry["type"] == "entfälllt": subst_msg += f"Entfall" else: something_changed = False # append type of entry to message (to prevent empty arrows -> ) if entry["teacher"] != day[row].split(" ")[2]: subst_msg += f"{entry['teacher']} " something_changed = True if entry["room"] != day[row].split(" ")[3]: subst_msg += f"{entry['room']} " something_changed = True if not something_changed: subst_msg += f"{entry['type']} " if len(subst_msg) > 10: subst_msg = "\n " + subst_msg msg += subst_msg break else: msg += f'\n{row + 1}' # info msg += "\n" for info in _infos: if info[0] not in ["Abwesende Lehrer", "Blockierte Räume", "Betroffene Klassen"]: msg += "\n" + " - ".join(info) msg += "```" return msg if custom_name: name = custom_name else: userdata = load_userdata() if userid not in userdata or userdata[userid][0] == "": userdata[userid] = ["", chat.id] save_userdata(userdata) chat.send_message("Bitte gib mir die Login-Daten für deinen Stundenplan (Nachname).", reply_markup=ForceReply()) return name = userdata[userid][0] splan = Stundenplan(name) vplan_obj = Vertretungsplan() vplan = vplan_obj.get_filtered(splan) if date.strftime("%d-%m-%y") in vplan: # get only substitution info for that date substitution = vplan[date.strftime("%d-%m-%y")] else: # empty list if none substitution = [] if date.strftime("%d-%m-%y") in vplan_obj.infos: # get only substitution info for that date infos = vplan_obj.infos[date.strftime("%d-%m-%y")] else: # empty list if none infos = [] new_message = construct_message(splan.get_day(date), substitution, date, infos) # inline keyboard date already contains date for previous and next plans next_date = (date + timedelta(days=1)) prev_date = (date - timedelta(days=1)) if next_date.weekday() == 5: next_date += timedelta(days=2) if prev_date.weekday() == 6: prev_date -= timedelta(days=2) reply_markup = InlineKeyboardMarkup([[ InlineKeyboardButton(ARROW_LEFT, callback_data=f'plan {prev_date.strftime("%d-%m-%y")}'), InlineKeyboardButton(ARROW_RIGHT, callback_data=f'plan {next_date.strftime("%d-%m-%y")}') ]]) if new_plan: chat.send_message(new_message, reply_markup=reply_markup, parse_mode=ParseMode.MARKDOWN_V2) add_admin_log(f"Sent plan to {userid}, date={date.strftime('%d-%m-%y')}.") else: message.edit_text(new_message, reply_markup=reply_markup, parse_mode=ParseMode.MARKDOWN_V2) add_admin_log(f"Sent plan to {userid}, date={date.strftime('%d-%m-%y')}.")