diff --git a/README.md b/README.md index 8e3f3bf..44ef051 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Bitcoin: 17jaxj26vFJNqQ2hEVerbBV5fpTusfqFro | PyQt5 | 5.10.1 | | python-lxml | 4.3.0 | | python-beautifulsoup4 | 4.6.0 | +| python-xmltodict | 0.11.0 | ### Optional | Package | Version tested | diff --git a/TODO b/TODO index 08ebecc..f5b0a1f 100644 --- a/TODO +++ b/TODO @@ -92,15 +92,9 @@ TODO Bugs: Deselecting all directories in the settings dialog also filters out manually added books Last line in QTextBrowser should never be cut off - Does image alignment need to be centered? Bookmark name for a page that's not on the TOC and has nothing before Screen position still keeps jumping when inside a paragraph Better recursion needed for fb2 toc - Initial sort by author in tableview - Last column not filling up tableview - Comic view mode changing does not work for newly added books - Ctrl + A reports 10 times the number of books selected for deletion - Ordering for non TOC chapters is beyond borked Secondary: Tab tooltip diff --git a/lector/__main__.py b/lector/__main__.py index e62590e..0e735d5 100755 --- a/lector/__main__.py +++ b/lector/__main__.py @@ -302,9 +302,10 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): for count, i in enumerate(self.settings['main_window_headers']): self.tableView.horizontalHeader().resizeSection(count, int(i)) self.tableView.horizontalHeader().resizeSection(5, 30) - self.tableView.horizontalHeader().setStretchLastSection(False) + self.tableView.horizontalHeader().setStretchLastSection(True) self.tableView.horizontalHeader().sectionClicked.connect( self.lib_ref.tableProxyModel.sort_table_columns) + self.lib_ref.tableProxyModel.sort_table_columns(2) self.tableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.tableView.customContextMenuRequested.connect( self.generate_library_context_menu) @@ -360,7 +361,6 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): def process_post_hoc_files(self, file_list, open_files_after_processing): # Takes care of both dragged and dropped files # As well as files sent as command line arguments - file_list = [i for i in file_list if os.path.exists(i)] if not file_list: return @@ -390,7 +390,6 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): # This allows for threading file opening # Which should speed up multiple file opening # especially @ application start - file_paths = [i for i in path_hash_dictionary] for filename in path_hash_dictionary.items(): @@ -520,15 +519,15 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): self.thread.finished.connect(self.move_on) self.thread.start() - def get_selection(self, library_widget): + def get_selection(self): selected_indexes = None - if library_widget == self.listView: + if self.listView.isVisible(): selected_books = self.lib_ref.itemProxyModel.mapSelectionToSource( self.listView.selectionModel().selection()) selected_indexes = [i.indexes()[0] for i in selected_books] - elif library_widget == self.tableView: + elif self.tableView.isVisible(): selected_books = self.tableView.selectionModel().selectedRows() selected_indexes = [ self.lib_ref.tableProxyModel.mapToSource(i) for i in selected_books] @@ -536,16 +535,10 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): return selected_indexes def delete_books(self, selected_indexes=None): - if not selected_indexes: - # Get a list of QItemSelection objects - # What we're interested in is the indexes()[0] in each of them - # That gives a list of indexes from the view model - if self.listView.isVisible(): - selected_indexes = self.get_selection(self.listView) - - elif self.tableView.isVisible(): - selected_indexes = self.get_selection(self.tableView) - + # Get a list of QItemSelection objects + # What we're interested in is the indexes()[0] in each of them + # That gives a list of indexes from the view model + selected_indexes = self.get_selection() if not selected_indexes: return @@ -572,10 +565,9 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): self.thread.start() # Generate a message box to confirm deletion - selected_number = len(selected_indexes) confirm_deletion = QtWidgets.QMessageBox() deletion_prompt = self._translate( - 'Main_UI', f'Delete {selected_number} book(s)?') + 'Main_UI', f'Delete book(s)?') confirm_deletion.setText(deletion_prompt) confirm_deletion.setIcon(QtWidgets.QMessageBox.Question) confirm_deletion.setWindowTitle(self._translate('Main_UI', 'Confirm deletion')) @@ -770,6 +762,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): signal_sender = None else: signal_sender = self.sender().objectName() + self.profile_functions.modify_comic_view( signal_sender, key_pressed) @@ -805,7 +798,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): # It's worth remembering that these are indexes of the libraryModel # and NOT of the proxy models - selected_indexes = self.get_selection(self.sender()) + selected_indexes = self.get_selection() context_menu = QtWidgets.QMenu() diff --git a/lector/guifunctions.py b/lector/guifunctions.py index 9f73beb..d2f6016 100644 --- a/lector/guifunctions.py +++ b/lector/guifunctions.py @@ -241,6 +241,7 @@ class ViewProfileModification: self.format_contentView() def modify_comic_view(self, signal_sender, key_pressed): + comic_profile = self.main_window.comic_profile current_tab = self.tabWidget.widget(self.tabWidget.currentIndex()) self.bookToolBar.fitWidth.setChecked(False) @@ -248,34 +249,35 @@ class ViewProfileModification: self.bookToolBar.originalSize.setChecked(False) if signal_sender == 'zoomOut' or key_pressed == QtCore.Qt.Key_Minus: - self.comic_profile['zoom_mode'] = 'manualZoom' - self.comic_profile['padding'] += 50 + comic_profile['zoom_mode'] = 'manualZoom' + comic_profile['padding'] += 50 # This prevents infinite zoom out - if self.comic_profile['padding'] * 2 > current_tab.contentView.viewport().width(): - self.comic_profile['padding'] -= 50 + if comic_profile['padding'] * 2 > current_tab.contentView.viewport().width(): + comic_profile['padding'] -= 50 - if signal_sender == 'zoomIn' or key_pressed in (QtCore.Qt.Key_Plus, QtCore.Qt.Key_Equal): - self.comic_profile['zoom_mode'] = 'manualZoom' - self.comic_profile['padding'] -= 50 + if signal_sender == 'zoomIn' or key_pressed in ( + QtCore.Qt.Key_Plus, QtCore.Qt.Key_Equal): + comic_profile['zoom_mode'] = 'manualZoom' + comic_profile['padding'] -= 50 # This prevents infinite zoom in - if self.comic_profile['padding'] < 0: - self.comic_profile['padding'] = 0 + if comic_profile['padding'] < 0: + comic_profile['padding'] = 0 if signal_sender == 'fitWidth' or key_pressed == QtCore.Qt.Key_W: - self.comic_profile['zoom_mode'] = 'fitWidth' - self.comic_profile['padding'] = 0 + comic_profile['zoom_mode'] = 'fitWidth' + comic_profile['padding'] = 0 self.bookToolBar.fitWidth.setChecked(True) # Padding in the following cases is decided by # the image pixmap loaded by the widget if signal_sender == 'bestFit' or key_pressed == QtCore.Qt.Key_B: - self.comic_profile['zoom_mode'] = 'bestFit' + comic_profile['zoom_mode'] = 'bestFit' self.bookToolBar.bestFit.setChecked(True) if signal_sender == 'originalSize' or key_pressed == QtCore.Qt.Key_O: - self.comic_profile['zoom_mode'] = 'originalSize' + comic_profile['zoom_mode'] = 'originalSize' self.bookToolBar.originalSize.setChecked(True) self.format_contentView() @@ -290,7 +292,6 @@ class ViewProfileModification: if current_metadata['images_only']: background = self.comic_profile['background'] - padding = self.comic_profile['padding'] zoom_mode = self.comic_profile['zoom_mode'] if zoom_mode == 'fitWidth': @@ -304,7 +305,7 @@ class ViewProfileModification: 'background-color: %s' % background.name()) current_tab.format_view( - None, None, None, background, padding, None, None) + None, None, None, background, None, None, None) else: profile_index = self.bookToolBar.profileBox.currentIndex() diff --git a/lector/parsers/pdf.py b/lector/parsers/pdf.py index 6929798..6997038 100644 --- a/lector/parsers/pdf.py +++ b/lector/parsers/pdf.py @@ -27,11 +27,7 @@ class ParsePDF: self.book = None def read_book(self): - try: - self.book = fitz.open(self.filename) - return True - except RuntimeError: - return False + self.book = fitz.open(self.filename) def generate_metadata(self): title = self.book.metadata['title'] diff --git a/lector/readers/read_epub.py b/lector/readers/read_epub.py index 0dddf45..f39366c 100644 --- a/lector/readers/read_epub.py +++ b/lector/readers/read_epub.py @@ -17,7 +17,6 @@ # TODO # See if inserting chapters not in the toc.ncx can be avoided # Account for stylesheets... eventually -# Everything needs logging import os import zipfile @@ -40,6 +39,7 @@ class EPUB: self.zip_file = None self.file_list = None self.opf_dict = None + self.cover_image_name = None self.split_chapters = {} self.metadata = None @@ -89,7 +89,7 @@ class EPUB: return i # If the file isn't found - logging.error(filename + ' not found in ' + self.book_filename) + logger.error(filename + ' not found in ' + self.book_filename) return False def generate_toc(self): @@ -247,25 +247,19 @@ class EPUB: toc_chapters = [ unquote(i[2].split('#')[0]) for i in self.content] - # TODO - # This totally borks the order - - last_valid_index = -2 # Yes, but why? for i in spine_final: if not i in toc_chapters: - previous_chapter = spine_final[spine_final.index(i) - 1] - try: + spine_index = spine_final.index(i) + if spine_index == 0: # Or chapter insertion circles back to the end + previous_chapter_toc_index = -1 + else: + previous_chapter = spine_final[spine_final.index(i) - 1] previous_chapter_toc_index = toc_chapters.index(previous_chapter) - # In case of 2+ consecutive missing chapters - last_valid_index = previous_chapter_toc_index - except ValueError: - last_valid_index += 1 - # Chapters are currently named None - # Blank chapters will later be removed - # and the None will be replaced by a number + toc_chapters.insert( + previous_chapter_toc_index + 1, i) self.content.insert( - last_valid_index + 1, [1, None, i]) + previous_chapter_toc_index + 1, [1, None, i]) # Parse split chapters as below # They can be picked up during the iteration through the toc @@ -334,28 +328,42 @@ class EPUB: chapter_title = i[1] if not chapter_title: chapter_title = unnamed_chapter_title - unnamed_chapter_title += 1 content_copy.append(( i[0], str(chapter_title), i[2])) + unnamed_chapter_title += 1 self.content = content_copy - # TODO - # This can probably be circumvented by shifting the extraction - # to this module and simply getting the path to the cover - # Get cover image and put it in its place # I imagine this involves saying nasty things to it + # There's no point shifting this to the parser + # The performance increase is negligible cover_image = self.generate_book_cover() + if cover_image: cover_path = os.path.join( self.temp_dir, os.path.basename(self.book_filename)) + ' - cover' with open(cover_path, 'wb') as cover_temp: cover_temp.write(cover_image) - # There's probably some rationale to doing an insert here - # But a replacement seems... neater - self.content.insert( - 0, (1, 'Cover', f'