mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
Improved PDF handling
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
- Ignore chapter markers and single newlines when calculating text length, improving the accuracy of the text length calculation.
|
- Ignore chapter markers and single newlines when calculating text length, improving the accuracy of the text length calculation.
|
||||||
- Prevent cancellation if process is at 99%, ensuring the process is not interrupted at the last moment.
|
- Prevent cancellation if process is at 99%, ensuring the process is not interrupted at the last moment.
|
||||||
- Improved process handling for subpprocess calls, ensuring better management of subprocesses.
|
- Improved process handling for subpprocess calls, ensuring better management of subprocesses.
|
||||||
|
- Improved PDF handling, ignoring empty pages/chapters and better chapter handling.
|
||||||
- Added `.opus` as output format for generated audio files.
|
- Added `.opus` as output format for generated audio files.
|
||||||
- Added "Playing..." indicator for "Preview" button in the voice mixer.
|
- Added "Playing..." indicator for "Preview" button in the voice mixer.
|
||||||
|
|
||||||
|
|||||||
+49
-58
@@ -934,6 +934,7 @@ class HandlerDialog(QDialog):
|
|||||||
def _build_pdf_tree(self):
|
def _build_pdf_tree(self):
|
||||||
outline = self.pdf_doc.get_toc()
|
outline = self.pdf_doc.get_toc()
|
||||||
self.has_pdf_bookmarks = bool(outline)
|
self.has_pdf_bookmarks = bool(outline)
|
||||||
|
self.bookmark_items_map = {}
|
||||||
|
|
||||||
if not outline:
|
if not outline:
|
||||||
self._build_pdf_pages_tree()
|
self._build_pdf_pages_tree()
|
||||||
@@ -976,20 +977,23 @@ class HandlerDialog(QDialog):
|
|||||||
else self.pdf_doc.resolve_link(page)[0]
|
else self.pdf_doc.resolve_link(page)[0]
|
||||||
)
|
)
|
||||||
page_id = f"page_{page_num+1}"
|
page_id = f"page_{page_num+1}"
|
||||||
|
# attach chapters on same page under original
|
||||||
|
if page_num in self.bookmark_items_map:
|
||||||
|
orig = self.bookmark_items_map[page_num]
|
||||||
|
child = QTreeWidgetItem(orig, [f"{title} (Same page)"])
|
||||||
|
child.setData(0, Qt.UserRole, page_id)
|
||||||
|
child.setFlags(child.flags() & ~Qt.ItemIsUserCheckable)
|
||||||
|
continue
|
||||||
bookmark_item = QTreeWidgetItem(parent_item, [title])
|
bookmark_item = QTreeWidgetItem(parent_item, [title])
|
||||||
bookmark_item.setData(0, Qt.UserRole, page_id)
|
bookmark_item.setData(0, Qt.UserRole, page_id)
|
||||||
bookmark_item.setFlags(
|
# only allow checking if this chapter has content
|
||||||
bookmark_item.flags() | Qt.ItemIsUserCheckable
|
if self.content_lengths.get(page_id, 0) > 0:
|
||||||
)
|
bookmark_item.setFlags(bookmark_item.flags() | Qt.ItemIsUserCheckable)
|
||||||
bookmark_item.setCheckState(
|
bookmark_item.setCheckState(0, Qt.Checked if page_id in self.checked_chapters else Qt.Unchecked)
|
||||||
0,
|
else:
|
||||||
(
|
bookmark_item.setFlags(bookmark_item.flags() & ~Qt.ItemIsUserCheckable)
|
||||||
Qt.Checked
|
# map for uncategorized pages
|
||||||
if page_id in self.checked_chapters
|
self.bookmark_items_map[page_num] = bookmark_item
|
||||||
else Qt.Unchecked
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
added_pages.add(page_num)
|
added_pages.add(page_num)
|
||||||
|
|
||||||
@@ -1012,30 +1016,39 @@ class HandlerDialog(QDialog):
|
|||||||
|
|
||||||
page_item = QTreeWidgetItem(bookmark_item, [page_title])
|
page_item = QTreeWidgetItem(bookmark_item, [page_title])
|
||||||
page_item.setData(0, Qt.UserRole, page_id)
|
page_item.setData(0, Qt.UserRole, page_id)
|
||||||
page_item.setFlags(page_item.flags() | Qt.ItemIsUserCheckable)
|
# only allow checking if this sub-page has content
|
||||||
page_item.setCheckState(
|
if self.content_lengths.get(page_id, 0) > 0:
|
||||||
0,
|
page_item.setFlags(page_item.flags() | Qt.ItemIsUserCheckable)
|
||||||
(
|
page_item.setCheckState(0, Qt.Checked if page_id in self.checked_chapters else Qt.Unchecked)
|
||||||
Qt.Checked
|
else:
|
||||||
if page_id in self.checked_chapters
|
page_item.setFlags(page_item.flags() & ~Qt.ItemIsUserCheckable)
|
||||||
else Qt.Unchecked
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
added_pages.add(sub_page_num)
|
added_pages.add(sub_page_num)
|
||||||
|
|
||||||
if len(entry) > 3 and isinstance(entry[3], list):
|
|
||||||
build_outline_tree(entry[3], bookmark_item)
|
|
||||||
|
|
||||||
build_outline_tree(outline, self.treeWidget)
|
build_outline_tree(outline, self.treeWidget)
|
||||||
|
|
||||||
covered_pages = set(added_pages)
|
covered_pages = set(added_pages)
|
||||||
|
# attach any pages without direct bookmarks under nearest preceding chapter
|
||||||
uncategorized_pages = [
|
uncategorized_pages = [i for i in range(len(self.pdf_doc)) if i not in covered_pages]
|
||||||
i for i in range(len(self.pdf_doc)) if i not in covered_pages
|
for page_num in uncategorized_pages:
|
||||||
]
|
# find nearest previous bookmark
|
||||||
if uncategorized_pages:
|
prev_nums = [n for n in sorted(self.bookmark_items_map) if n < page_num]
|
||||||
self._add_other_pages(uncategorized_pages)
|
parent_item = self.bookmark_items_map[prev_nums[-1]] if prev_nums else self.treeWidget
|
||||||
|
page_id = f"page_{page_num+1}"
|
||||||
|
title = f"Page {page_num+1}"
|
||||||
|
text = self.content_texts.get(page_id, "").strip()
|
||||||
|
if text:
|
||||||
|
first = text.split("\n", 1)[0].strip()
|
||||||
|
if first and len(first) < 100:
|
||||||
|
title += f" - {first}"
|
||||||
|
page_item = QTreeWidgetItem(parent_item, [title])
|
||||||
|
page_item.setData(0, Qt.UserRole, page_id)
|
||||||
|
# only allow checking if uncategorized page has content
|
||||||
|
if self.content_lengths.get(page_id, 0) > 0:
|
||||||
|
page_item.setFlags(page_item.flags() | Qt.ItemIsUserCheckable)
|
||||||
|
page_item.setCheckState(0, Qt.Checked if page_id in self.checked_chapters else Qt.Unchecked)
|
||||||
|
else:
|
||||||
|
page_item.setFlags(page_item.flags() & ~Qt.ItemIsUserCheckable)
|
||||||
|
|
||||||
def _build_pdf_pages_tree(self):
|
def _build_pdf_pages_tree(self):
|
||||||
pages_item = QTreeWidgetItem(self.treeWidget, ["Pages"])
|
pages_item = QTreeWidgetItem(self.treeWidget, ["Pages"])
|
||||||
@@ -1056,34 +1069,12 @@ class HandlerDialog(QDialog):
|
|||||||
|
|
||||||
page_item = QTreeWidgetItem(pages_item, [page_title])
|
page_item = QTreeWidgetItem(pages_item, [page_title])
|
||||||
page_item.setData(0, Qt.UserRole, page_id)
|
page_item.setData(0, Qt.UserRole, page_id)
|
||||||
page_item.setFlags(page_item.flags() | Qt.ItemIsUserCheckable)
|
# only allow checking if standalone page has content
|
||||||
page_item.setCheckState(
|
if self.content_lengths.get(page_id, 0) > 0:
|
||||||
0, Qt.Checked if page_id in self.checked_chapters else Qt.Unchecked
|
page_item.setFlags(page_item.flags() | Qt.ItemIsUserCheckable)
|
||||||
)
|
page_item.setCheckState(0, Qt.Checked if page_id in self.checked_chapters else Qt.Unchecked)
|
||||||
|
else:
|
||||||
def _add_other_pages(self, uncategorized_pages):
|
page_item.setFlags(page_item.flags() & ~Qt.ItemIsUserCheckable)
|
||||||
other_pages = QTreeWidgetItem(self.treeWidget, ["Other Pages"])
|
|
||||||
other_pages.setFlags(other_pages.flags() & ~Qt.ItemIsUserCheckable)
|
|
||||||
font = other_pages.font(0)
|
|
||||||
font.setBold(True)
|
|
||||||
other_pages.setFont(0, font)
|
|
||||||
|
|
||||||
for page_num in uncategorized_pages:
|
|
||||||
page_id = f"page_{page_num+1}"
|
|
||||||
page_title = f"Page {page_num+1}"
|
|
||||||
|
|
||||||
page_text = self.content_texts.get(page_id, "").strip()
|
|
||||||
if page_text:
|
|
||||||
first_line = page_text.split("\n", 1)[0].strip()
|
|
||||||
if first_line and len(first_line) < 100:
|
|
||||||
page_title += f" - {first_line}"
|
|
||||||
|
|
||||||
page_item = QTreeWidgetItem(other_pages, [page_title])
|
|
||||||
page_item.setData(0, Qt.UserRole, page_id)
|
|
||||||
page_item.setFlags(page_item.flags() | Qt.ItemIsUserCheckable)
|
|
||||||
page_item.setCheckState(
|
|
||||||
0, Qt.Checked if page_id in self.checked_chapters else Qt.Unchecked
|
|
||||||
)
|
|
||||||
|
|
||||||
def _are_provided_checks_relevant(self):
|
def _are_provided_checks_relevant(self):
|
||||||
if not self.checked_chapters:
|
if not self.checked_chapters:
|
||||||
|
|||||||
Reference in New Issue
Block a user