-
-
Save tyrelsouza/9c6681850fc00bf5d9f35568faf611d4 to your computer and use it in GitHub Desktop.
Epub Reader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re | |
from typing import TypeVar, Dict, Any, List, Optional | |
import dearpygui.dearpygui as dpg | |
import ebooklib | |
from bs4 import BeautifulSoup | |
from ebooklib import epub | |
WIDTH: int = 700 | |
class BookBase: | |
pass | |
Book = TypeVar('Book', bound=BookBase) | |
class Epub(BookBase): | |
def __init__(self, book_path: str) -> None: | |
self.contents: ebooklib.epub.EpubBook = epub.read_epub(book_path) | |
self.title: str = self.contents.title | |
self.toc: List[ebooklib.epub.Link] = self.contents.toc | |
self.current_index = 0 | |
self.current_text: Optional[str] = None | |
self.chapters: List[Dict[str, Any]] = [] | |
self.parse_chapters() | |
def parse_chapters(self) -> None: | |
idx = 0 | |
for _item in self.toc: | |
if isinstance(_item, tuple): # In case is section tuple(section, [link, ...]) | |
for link in _item[1]: | |
self._parse_link(idx, link) | |
idx += 1 | |
else: | |
self._parse_link(idx, _item) | |
idx += 1 | |
def _parse_link(self, idx, link): | |
title = link.title | |
self.chapters.append(dict( | |
index=idx, | |
title=title, | |
item=self.contents.get_item_with_href(link.href) | |
)) | |
def load_view(self) -> None: | |
item = self.chapters[self.current_index]['item'] | |
soup = BeautifulSoup(item.get_body_content(), "html.parser") | |
text = [para.get_text() for para in soup.find_all("p")] | |
self.current_text = "\n".join(text) | |
self.fix_quotes() | |
def fix_quotes(self): | |
self.current_text = re.sub(u"[\u201c\u201d]", '"', self.current_text) | |
self.current_text = re.sub(u"’", "'", self.current_text) | |
self.current_text = re.sub(u"—", "--", self.current_text) | |
def show_chapter(self, index) -> None: | |
self.current_index = index | |
self.load_view() | |
class Readz: | |
file_name: str = None | |
book: Optional[Book] = None | |
# Elements | |
lbl_title: int = None | |
btn_open_close: int = None | |
list_btn_chapter: List[int] = [] | |
w_window: int = None | |
txt_body: int = None | |
tbl_main_table: int = None | |
def __init__(self): | |
pass | |
def cb_open_file(self, sender, app_data): | |
self.file_name = app_data['file_path_name'] | |
self.book = Epub(book_path=self.file_name) | |
dpg.set_value(self.lbl_title, self.book.title) | |
self.load_chapter_table() | |
# dpg.set_item_callback(self.btn_open_close, self.cb_close_file) | |
# dpg.set_item_label(self.btn_open_close, "Close File") | |
dpg.hide_item(sender) | |
self.book.load_view() | |
dpg.set_value(self.txt_body, self.book.current_text) | |
def cb_close_file(self): | |
self.book = None | |
dpg.set_value(self.lbl_title, "No Book") | |
dpg.configure_item("chapter_titles", resizable=False) | |
dpg.set_item_callback(self.btn_open_close, lambda: dpg.show_item("file_dialog_id")) | |
dpg.set_item_label(self.btn_open_close, "Open File") | |
dpg.delete_item(item="chapter_titles", children_only=False) | |
# self.tbl_chapter_titles = dpg.table(tag="chapter_titles", resizable=False) | |
with dpg.table(tag="chapter_titles", resizable=False): | |
dpg.add_table_column(label="-Chapter Titles-") | |
def cb_change_chapter(self, sender, app_data, user_data) -> None: | |
# print(user_data, self.list_btn_chapter) | |
self.book.show_chapter(user_data['chapter']) | |
dpg.set_value(self.txt_body, self.book.current_text) | |
for chapter in self.list_btn_chapter: | |
dpg.enable_item(chapter) | |
dpg.disable_item(sender) | |
def load_chapter_table(self): | |
dpg.configure_item("chapter_titles", resizable=False) | |
for chapter in self.book.chapters: | |
with dpg.table_row(parent="chapter_titles"): | |
title = chapter['title'] | |
if title.lower().startswith("chapter "): | |
title = f"Chp. {title[len('chapter '):]}" | |
self.list_btn_chapter.append( | |
dpg.add_button( | |
label=title, | |
callback=self.cb_change_chapter, | |
user_data={"chapter": chapter['index']})) | |
def dpg_set_themes(self) -> None: | |
with dpg.theme() as disabled_theme: | |
with dpg.theme_component(dpg.mvButton, enabled_state=False): | |
dpg.add_theme_color(dpg.mvThemeCol_Text, [255, 255, 255]) | |
dpg.add_theme_color(dpg.mvThemeCol_Button, [0, 0, 100]) | |
dpg.bind_theme(disabled_theme) | |
def start(self): | |
dpg.create_context() | |
self.dpg_set_themes() | |
# Configure File Dialog | |
with dpg.file_dialog(directory_selector=False, show=False, callback=self.cb_open_file, id="file_dialog_id"): | |
dpg.add_file_extension(".epub", color=(0, 255, 0, 255), custom_text="[Epub]") | |
# Setup initial window. | |
self.dpg_main_window() | |
dpg.create_viewport(title='Readz', width=WIDTH, height=768) | |
dpg.setup_dearpygui() | |
dpg.show_viewport() | |
dpg.set_primary_window("MAIN_WINDOW", True) | |
dpg.start_dearpygui() | |
dpg.destroy_context() | |
def dpg_main_window(self): | |
# Setup initial window. | |
self.w_window = dpg.window(label="Readz", tag="MAIN_WINDOW", width=WIDTH, height=768) | |
with self.w_window: | |
self.tbl_main_table = dpg.table(tag="main_layout", header_row=False) | |
with self.tbl_main_table: | |
dpg.add_table_column(width=120, width_fixed=True) | |
dpg.add_table_column() | |
with dpg.table_row(): | |
self.lbl_title = dpg.add_text(label="<Title>") | |
self.btn_open_close = dpg.add_button( | |
label="Open File", | |
callback=lambda: dpg.show_item("file_dialog_id")) | |
with dpg.table_row(): | |
with dpg.table(tag="chapter_titles", resizable=False): | |
dpg.add_table_column(label="Chapter Titles") | |
self.txt_body = dpg.add_text("...", tracked=True, wrap=WIDTH-120) | |
if __name__ == '__main__': | |
r = Readz() | |
r.start() | |
# TODO: Reset the chapter list | |
# TODO: Make chapter list load a view | |
# TODO: Switch away from DPG |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ebooklib | |
beautifulsoup4 | |
dearpygui |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment