diff --git a/abogen/gui.py b/abogen/gui.py index 08f03dc..f742ca3 100644 --- a/abogen/gui.py +++ b/abogen/gui.py @@ -230,6 +230,8 @@ class InputBox(QLabel): size_str = self._human_readable_size(os.path.getsize(file_path)) name = os.path.basename(file_path) char_count = 0 + window = self.window() + cache = getattr(window, "_char_count_cache", None) def parse_size(size_str): # Use regex to extract the numeric part @@ -249,41 +251,49 @@ class InputBox(QLabel): except Exception: return str(n) - if ( - file_path.lower().endswith(".epub") - or file_path.lower().endswith(".pdf") - or file_path.lower().endswith((".md", ".markdown")) - ) and hasattr(self.window(), "selected_chapters"): - # EPUB, PDF, or Markdown: sum character counts for selected chapters - try: + doc_extensions = (".epub", ".pdf", ".md", ".markdown") + char_source_path = file_path + cached_char_count = None - book_path = file_path - # HandlerDialog uses internal caching to avoid reprocessing the same book - dialog = HandlerDialog( - book_path, - checked_chapters=self.window().selected_chapters, - parent=self.window(), - ) - chapters_text, all_checked_hrefs = dialog.get_selected_text() - # Clean text before counting characters - cleaned_text = clean_text(chapters_text) - char_count = calculate_text_length(cleaned_text) - except Exception: - char_count = "N/A" - else: + if file_path.lower().endswith(doc_extensions): + selected_file_path = getattr(window, "selected_file", None) + if selected_file_path and os.path.exists(selected_file_path): + char_source_path = selected_file_path + else: + char_source_path = None + + if cache is not None: + cached_char_count = cache.get(file_path) + if ( + cached_char_count is None + and char_source_path + and char_source_path != file_path + ): + cached_char_count = cache.get(char_source_path) + + if cached_char_count is not None: + char_count = cached_char_count + elif char_source_path: try: - with open(file_path, "r", encoding="utf-8", errors="ignore") as f: + with open(char_source_path, "r", encoding="utf-8", errors="ignore") as f: text = f.read() - # Clean text before counting characters cleaned_text = clean_text(text) char_count = calculate_text_length(cleaned_text) except Exception: char_count = "N/A" + else: + char_count = "N/A" + + if cache is not None and isinstance(char_count, int): + cache[file_path] = char_count + if char_source_path and char_source_path != file_path: + cache[char_source_path] = char_count + # Store numeric char_count on window try: - self.window().char_count = int(char_count) + window.char_count = int(char_count) except Exception: - self.window().char_count = 0 + window.char_count = 0 # embed icon at native size with word-wrap for the filename self.setText( f'
{name}
Size: {size_str}
Characters: {format_num(char_count)}' @@ -294,11 +304,11 @@ class InputBox(QLabel): f"QLabel {{ {self.STYLE_ACTIVE} }} QLabel:hover {{ {self.STYLE_ACTIVE_HOVER} }}" ) self.clear_btn.show() - is_document = self.window().selected_file_type in ["epub", "pdf", "md", "markdown"] + is_document = window.selected_file_type in ["epub", "pdf", "md", "markdown"] self.chapters_btn.setVisible(is_document) if is_document: - chapter_count = len(self.window().selected_chapters) - file_type = self.window().selected_file_type + chapter_count = len(window.selected_chapters) + file_type = window.selected_file_type # Adjust button text based on file type if file_type == "epub" or file_type == "md" or file_type == "markdown": self.chapters_btn.setText(f"Chapters ({chapter_count})") @@ -313,8 +323,8 @@ class InputBox(QLabel): # For epub/pdf files, show edit if we have a selected_file (temp txt) if ( - self.window().selected_file_type in ["epub", "pdf", "md", "markdown", "md", "markdown"] - and self.window().selected_file + window.selected_file_type in ["epub", "pdf", "md", "markdown", "md", "markdown"] + and window.selected_file ): should_show_edit = True @@ -322,13 +332,13 @@ class InputBox(QLabel): self.go_to_folder_btn.show() # Enable add to queue button only when file is accepted (input box is green) self.resizeEvent(None) - if hasattr(self.window(), "btn_add_to_queue"): - self.window().btn_add_to_queue.setEnabled(True) + if hasattr(window, "btn_add_to_queue"): + window.btn_add_to_queue.setEnabled(True) self.chapters_btn.adjustSize() # Reset the input_box_cleared_by_queue flag after setting file info - if hasattr(self.window(), "input_box_cleared_by_queue"): - self.window().input_box_cleared_by_queue = False + if hasattr(window, "input_box_cleared_by_queue"): + window.input_box_cleared_by_queue = False def set_error(self, message): self.setText(message) @@ -721,6 +731,8 @@ class abogen(QWidget): self.selected_chapters = set() self.last_opened_book_path = None # Track the last opened book path self.last_output_path = None + self.char_count = 0 + self._char_count_cache = {} # Only one of selected_profile_name or selected_voice should be set self.selected_profile_name = self.config.get("selected_profile_name") self.selected_voice = None @@ -1294,6 +1306,12 @@ class abogen(QWidget): if book_path.lower().endswith(".pdf"): self.pdf_has_bookmarks = getattr(dialog, "has_pdf_bookmarks", False) + cleaned_text = clean_text(chapters_text) + computed_char_count = calculate_text_length(cleaned_text) + self.char_count = computed_char_count + if isinstance(getattr(self, "_char_count_cache", None), dict): + self._char_count_cache[book_path] = computed_char_count + # Use "abogen" prefix for cache files # Extract base name without extension base_name = os.path.splitext(os.path.basename(book_path))[0] @@ -1378,6 +1396,8 @@ class abogen(QWidget): self.selected_file = tmp self.selected_book_path = book_path self.displayed_file_path = book_path + if isinstance(getattr(self, "_char_count_cache", None), dict): + self._char_count_cache[tmp] = computed_char_count # Only set file info if dialog was accepted self.input_box.set_file_info(book_path) return True