diff --git a/TODO b/TODO index f5b0a1f..8b94b7a 100644 --- a/TODO +++ b/TODO @@ -33,6 +33,8 @@ TODO ✓ Include (action) icons with the applications ✓ Drag and drop support for the library ✓ Tab reordering + Additional Settings: + ✓ Create covers for books without them - VERY SLOW Set focus to newly added file Reading: ✓ Drop down for TOC @@ -101,7 +103,6 @@ TODO Additional Settings: Disable progressbar - 20% book addition speed improvement Disable cover loading when reading - Saves ~2M / book - Create covers for books without them - VERY SLOW Special formatting for each chapter's title Signal end of chapter with some text Graphical themes diff --git a/com.basiomeuspuga.Lector.json b/com.basiomeuspuga.Lector.json index 66d50c9..3c39a5a 100644 --- a/com.basiomeuspuga.Lector.json +++ b/com.basiomeuspuga.Lector.json @@ -1,7 +1,7 @@ { "app-id":"com.basiomeuspuga.Lector", "runtime":"org.kde.Platform", - "runtime-version":"5.10", + "runtime-version":"5.12", "sdk":"org.kde.Sdk", "command":"lector", "rename-icon":"Lector", @@ -21,74 +21,107 @@ }, "modules":[ { - "name": "python", - "sources": [ - { - "type": "archive", - "url": "https://www.python.org/ftp/python/3.6.4/Python-3.6.4.tar.xz", - "sha256": "159b932bf56aeaa76fd66e7420522d8c8853d486b8567c459b84fe2ed13bcaba" - } - ] - }, - { - "name": "pyqt5", + "name": "PyQt5", "buildsystem": "simple", "build-commands": [ - "pip3 install --prefix=/app PyQt5-5.10.1-5.10.1-cp35.cp36.cp37.cp38-abi3-manylinux1_x86_64.whl" + "pip3 install --prefix=/app PyQt5-5.12-5.12.1-cp35.cp36.cp37.cp38-abi3-manylinux1_x86_64.whl" ], "modules":[ { - "name":"sip", + "name":"PyQt5-sip", "sources":[ { "type":"file", - "url":"https://pypi.python.org/packages/8a/ea/d317ce5696dda4df7c156cd60447cda22833b38106c98250eae1451f03ec/sip-4.19.8-cp36-cp36m-manylinux1_x86_64.whl", - "sha256":"cf98150a99e43fda7ae22abe655b6f202e491d6291486548daa56cb15a2fcf85" + "url":"https://files.pythonhosted.org/packages/ae/9c/74fba0b62a0756d214f9aded5b0184130f7866def7532fa68823f34feefa/PyQt5_sip-4.19.14-cp37-cp37m-manylinux1_x86_64.whl", + "sha256":"04bd0bb8b6f8fa03c2dfbdfff0c8c9bfb3f46a21dd4cac73983dae93bf949523" } ], "buildsystem":"simple", "build-commands":[ - "pip3 install --prefix=/app sip-4.19.8-cp36-cp36m-manylinux1_x86_64.whl" + "pip3 install --prefix=/app PyQt5_sip-4.19.14-cp37-cp37m-manylinux1_x86_64.whl" ] } ], "sources": [ { "type": "file", - "url": "https://pypi.python.org/packages/e4/15/4e2e49f64884edbab6f833c6fd3add24d7938f2429aec1f2883e645d4d8f/PyQt5-5.10.1-5.10.1-cp35.cp36.cp37.cp38-abi3-manylinux1_x86_64.whl", - "sha256": "1e652910bd1ffd23a3a48c510ecad23a57a853ed26b782cd54b16658e6f271ac" + "url": "https://files.pythonhosted.org/packages/5e/91/9ac8827d0af428e756f461a3aa7bcbc53d6450edfe026e27569f5ff3689e/PyQt5-5.12-5.12.1-cp35.cp36.cp37.cp38-abi3-manylinux1_x86_64.whl", + "sha256": "fd5946795b39922f971cf92dec799aadc7544b7fa993a79b9f6059f13d817e6e" } ] }, { - "name":"beautifulsoup", + "name":"beautifulsoup4", "buildsystem":"simple", "sources":[ { - "type":"archive", - "url":"https://pypi.python.org/packages/fa/8d/1d14391fdaed5abada4e0f63543fef49b8331a34ca60c88bd521bcf7f782/beautifulsoup4-4.6.0.tar.gz", - "sha256":"808b6ac932dccb0a4126558f7dfdcf41710dd44a4ef497a0bb59a77f9f078e89" + "type":"file", + "url":"https://files.pythonhosted.org/packages/1d/5d/3260694a59df0ec52f8b4883f5d23b130bc237602a1411fa670eae12351e/beautifulsoup4-4.7.1-py3-none-any.whl", + "sha256":"034740f6cb549b4e932ae1ab975581e6103ac8f942200a0e9759065984391858" + } + ], + "modules":[ + { + "name": "soupsieve", + "sources":[ + { + "type":"file", + "url":"https://files.pythonhosted.org/packages/bf/b3/2473abf05c4950c6a829ed5dcbc40d8b56d4351d15d6939c8ffb7c6b1a14/soupsieve-1.7.3-py2.py3-none-any.whl", + "sha256":"466910df7561796a60748826781ebe9a888f7a1668a636ae86783f44d10aae73" + } + ], + "buildsystem":"simple", + "build-commands":[ + "pip3 install --prefix=/app soupsieve-1.7.3-py2.py3-none-any.whl" + ] } ], "build-commands":[ - "python3 setup.py build", - "python3 setup.py install --prefix=/app" + "pip3 install --prefix=/app beautifulsoup4-4.7.1-py3-none-any.whl" ] }, - { - "name": "lxml", - "buildsystem": "simple", + { + "name":"xmltodict", + "buildsystem":"simple", + "sources":[ + { + "type": "file", + "url":"https://files.pythonhosted.org/packages/28/fd/30d5c1d3ac29ce229f6bdc40bbc20b28f716e8b363140c26eff19122d8a5/xmltodict-0.12.0-py2.py3-none-any.whl", + "sha256":"8bbcb45cc982f48b2ca8fe7e7827c5d792f217ecf1792626f808bf41c3b86051" + } + ], + "build-commands":[ + "pip3 install --prefix=/app xmltodict-0.12.0-py2.py3-none-any.whl" + ] + }, + { + "name":"PyMuPDF", + "buildsystem":"simple", "build-commands": [ - "pip3 install --prefix=/app lxml-4.2.1-cp36-cp36m-manylinux1_x86_64.whl" + "pip3 install --prefix=/app PyMuPDF-1.14.8-cp37-cp37m-manylinux1_x86_64.whl" ], - "sources": [ + "sources":[ { "type": "file", - "url": "https://pypi.python.org/packages/a7/b9/ccf46cea0f698b40bca2a9c1a44039c336fe1988b82de4f7353be7a8396a/lxml-4.2.1-cp36-cp36m-manylinux1_x86_64.whl", - "sha256": "0e3cd94c95d30ba9ca3cff40e9b2a14e1a10a4fd8131105b86c6b61648f57e4b" + "url": "https://files.pythonhosted.org/packages/3c/df/4bfaee2631b505d502c2ba64aa437799f0a64125edb1d4c4c38044ad1ecc/PyMuPDF-1.14.8-cp37-cp37m-manylinux1_x86_64.whl", + "sha256": "a49798b58cce00e09b8a4431a5f64a400b11a0959f29507187c471208ce040a5" } ] }, + { + "name":"lxml", + "buildsystem":"simple", + "sources":[ + { + "type":"file", + "url":"https://files.pythonhosted.org/packages/08/f2/04bf04e42c070f65b64dbde02d2c94851251f19f5e9f803cc8f8bc61ac77/lxml-4.3.1-cp37-cp37m-manylinux1_x86_64.whl", + "sha256":"c0a7751ba1a4bfbe7831920d98cee3ce748007eab8dfda74593d44079568219a" + } + ], + "build-commands":[ + "pip3 install --prefix=/app lxml-4.3.1-cp37-cp37m-manylinux1_x86_64.whl" + ] + }, { "name":"lector", "buildsystem":"simple", diff --git a/lector/__main__.py b/lector/__main__.py index 0e735d5..e8d249f 100755 --- a/lector/__main__.py +++ b/lector/__main__.py @@ -165,7 +165,10 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): self.libraryToolBar.reloadLibraryButton.triggered.connect( self.settingsDialog.start_library_scan) self.libraryToolBar.colorButton.triggered.connect(self.get_color) - self.libraryToolBar.settingsButton.triggered.connect(self.show_settings) + self.libraryToolBar.settingsButton.triggered.connect( + lambda: self.show_settings(0)) + self.libraryToolBar.aboutButton.triggered.connect( + lambda: self.show_settings(3)) self.libraryToolBar.searchBar.textChanged.connect(self.lib_ref.update_proxymodels) self.libraryToolBar.sortingBox.activated.connect(self.lib_ref.update_proxymodels) self.libraryToolBar.libraryFilterButton.setPopupMode(QtWidgets.QToolButton.InstantPopup) @@ -369,7 +372,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): file_list, ('addition', 'manual'), self.database_path, - self.settings['auto_tags'], + self.settings, self.temp_dir.path()) parsed_books = books.initiate_threads() @@ -423,7 +426,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): file_paths, ('reading', None), self.database_path, - True, + self.settings, self.temp_dir.path()).initiate_threads() # TODO @@ -739,9 +742,15 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow): else: self.statusBar.setVisible(True) - def show_settings(self): + def show_settings(self, stacked_widget_index): if not self.settingsDialog.isVisible(): self.settingsDialog.show() + self.settingsDialog.okButton.setVisible(False) + index = self.settingsDialog.listModel.index( + stacked_widget_index, 0) + self.settingsDialog.listView.setCurrentIndex(index) + self.settingsDialog.stackedWidget.setCurrentIndex( + stacked_widget_index) else: self.settingsDialog.hide() diff --git a/lector/readers/read_fb2.py b/lector/readers/read_fb2.py index 36c26c2..9c58631 100644 --- a/lector/readers/read_fb2.py +++ b/lector/readers/read_fb2.py @@ -64,6 +64,8 @@ class FB2: 'author').getText(separator=' ').replace('\n', ' ') if author == '' or author is None: author = '' + else: + author = author.strip() # TODO # Account for other date formats diff --git a/lector/resources/raw/settings.ui b/lector/resources/raw/settings.ui index 34fff6e..2500654 100644 --- a/lector/resources/raw/settings.ui +++ b/lector/resources/raw/settings.ui @@ -175,6 +175,20 @@ + + + + + + <html><head/><body><p>Attempt to download missing book covers from Google books - SLOW</p></body></html> + + + Download missing covers + + + + + diff --git a/lector/resources/settingswindow.py b/lector/resources/settingswindow.py index 3a27b3c..b320e3e 100644 --- a/lector/resources/settingswindow.py +++ b/lector/resources/settingswindow.py @@ -106,6 +106,12 @@ class Ui_Dialog(object): self.attenuateTitles.setObjectName("attenuateTitles") self.horizontalLayout_9.addWidget(self.attenuateTitles) self.verticalLayout_2.addLayout(self.horizontalLayout_9) + self.horizontalLayout_16 = QtWidgets.QHBoxLayout() + self.horizontalLayout_16.setObjectName("horizontalLayout_16") + self.autoCover = QtWidgets.QCheckBox(self.groupBox) + self.autoCover.setObjectName("autoCover") + self.horizontalLayout_16.addWidget(self.autoCover) + self.verticalLayout_2.addLayout(self.horizontalLayout_16) self.gridLayout_4.addLayout(self.verticalLayout_2, 0, 0, 1, 1) self.verticalLayout.addWidget(self.groupBox) self.groupBox_2 = QtWidgets.QGroupBox(self.switchPage) @@ -342,6 +348,8 @@ class Ui_Dialog(object): self.performCulling.setText(_translate("Dialog", "Load covers only when needed")) self.autoTags.setText(_translate("Dialog", "Generate tags from files")) self.attenuateTitles.setText(_translate("Dialog", "Shrink long book titles")) + self.autoCover.setToolTip(_translate("Dialog", "

Attempt to download missing book covers from Google books - SLOW

")) + self.autoCover.setText(_translate("Dialog", "Download missing covers")) self.groupBox_2.setTitle(_translate("Dialog", "Reading")) self.hideScrollBars.setToolTip(_translate("Dialog", "Horizontal scrolling with Alt + Scroll\n" "Reopen book to see changes")) diff --git a/lector/settings.py b/lector/settings.py index c415204..b31e1ff 100644 --- a/lector/settings.py +++ b/lector/settings.py @@ -122,6 +122,8 @@ class Settings: 'cachingEnabled', 'True').capitalize()) self.parent.settings['hide_scrollbars'] = literal_eval(self.settings.value( 'hideScrollBars', 'False').capitalize()) + self.parent.settings['auto_cover'] = literal_eval(self.settings.value( + 'autoCover', 'False').capitalize()) self.parent.settings['scroll_speed'] = int(self.settings.value('scrollSpeed', 7)) self.parent.settings['consider_read_at'] = int(self.settings.value('considerReadAt', 95)) self.parent.settings['small_increment'] = int(self.settings.value('smallIncrement', 4)) @@ -211,6 +213,7 @@ class Settings: self.settings.setValue('cachingEnabled', str(current_settings['caching_enabled'])) self.settings.setValue('hideScrollBars', str(current_settings['hide_scrollbars'])) self.settings.setValue('attenuateTitles', str(current_settings['attenuate_titles'])) + self.settings.setValue('autoCover', str(current_settings['auto_cover'])) self.settings.setValue('scrollSpeed', current_settings['scroll_speed']) self.settings.setValue('considerReadAt', current_settings['consider_read_at']) self.settings.setValue('mangaMode', str(current_settings['manga_mode'])) diff --git a/lector/settingsdialog.py b/lector/settingsdialog.py index cfd1110..0f7eb83 100644 --- a/lector/settingsdialog.py +++ b/lector/settingsdialog.py @@ -99,6 +99,7 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog): self.cachingEnabled.setChecked(self.main_window.settings['caching_enabled']) self.hideScrollBars.setChecked(self.main_window.settings['hide_scrollbars']) self.attenuateTitles.setChecked(self.main_window.settings['attenuate_titles']) + self.autoCover.setChecked(self.main_window.settings['auto_cover']) self.scrollSpeedSlider.setValue(self.main_window.settings['scroll_speed']) self.readAtPercent.setValue(self.main_window.settings['consider_read_at']) self.smallIncrementBox.setValue(self.main_window.settings['small_increment']) @@ -112,6 +113,7 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog): self.cachingEnabled.clicked.connect(self.manage_checkboxes) self.hideScrollBars.clicked.connect(self.manage_checkboxes) self.attenuateTitles.clicked.connect(self.manage_checkboxes) + self.autoCover.clicked.connect(self.manage_checkboxes) self.scrollSpeedSlider.valueChanged.connect(self.change_scroll_speed) self.readAtPercent.valueChanged.connect(self.change_read_at) self.smallIncrementBox.valueChanged.connect(self.change_increment) @@ -390,7 +392,8 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog): 'performCulling': 'perform_culling', 'cachingEnabled': 'caching_enabled', 'hideScrollBars': 'hide_scrollbars', - 'attenuateTitles': 'attenuate_titles'} + 'attenuateTitles': 'attenuate_titles', + 'autoCover': 'auto_cover'} self.main_window.settings[ sender_dict[sender]] = not self.main_window.settings[sender_dict[sender]] diff --git a/lector/sorter.py b/lector/sorter.py index 8a9df1a..aa71f95 100644 --- a/lector/sorter.py +++ b/lector/sorter.py @@ -102,7 +102,7 @@ class UpdateProgress(QtCore.QObject): class BookSorter: - def __init__(self, file_list, mode, database_path, auto_tags=True, temp_dir=None): + def __init__(self, file_list, mode, database_path, settings, temp_dir=None): # Have the GUI pass a list of files straight to here # Then, on the basis of what is needed, pass the # filenames to the requisite functions @@ -115,7 +115,8 @@ class BookSorter: self.work_mode = mode[0] self.addition_mode = mode[1] self.database_path = database_path - self.auto_tags = auto_tags + self.auto_tags = settings['auto_tags'] + self.auto_cover = settings['auto_cover'] self.temp_dir = temp_dir if database_path: self.database_hashes() @@ -245,10 +246,9 @@ class BookSorter: if cover_image_raw: cover_image = resize_image(cover_image_raw) else: - # TODO - # Needs an option - # cover_image = fetch_cover(title, author) cover_image = None + if self.auto_cover: + cover_image = fetch_cover(title, author) this_book[file_md5]['cover_image'] = cover_image this_book[file_md5]['addition_mode'] = self.addition_mode diff --git a/lector/threaded.py b/lector/threaded.py index 7a7559d..e9eae91 100644 --- a/lector/threaded.py +++ b/lector/threaded.py @@ -65,7 +65,7 @@ class BackGroundBookAddition(QtCore.QThread): self.file_list, ('addition', self.addition_mode), self.database_path, - self.main_window.settings['auto_tags'], + self.main_window.settings, self.main_window.temp_dir.path()) parsed_books = books.initiate_threads() diff --git a/lector/toolbars.py b/lector/toolbars.py index 5aa59a2..e235e73 100644 --- a/lector/toolbars.py +++ b/lector/toolbars.py @@ -383,16 +383,6 @@ class LibraryToolBar(QtWidgets.QToolBar): image_factory.get_image('remove'), self._translate('LibraryToolBar', 'Delete book'), self) - self.colorButton = QtWidgets.QAction( - image_factory.get_image('color-picker'), - self._translate('LibraryToolBar', 'Library background color'), - self) - self.colorButton.setObjectName('libraryBackground') - self.settingsButton = QtWidgets.QAction( - image_factory.get_image('settings'), - self._translate('LibraryToolBar', 'Settings'), - self) - self.settingsButton.setCheckable(True) self.coverViewButton = QtWidgets.QAction( image_factory.get_image('view-grid'), @@ -416,6 +406,22 @@ class LibraryToolBar(QtWidgets.QToolBar): self.libraryFilterButton.setToolTip( self._translate('LibraryToolBar', 'Filter library')) + self.colorButton = QtWidgets.QAction( + image_factory.get_image('color-picker'), + self._translate('LibraryToolBar', 'Library background color'), + self) + self.colorButton.setObjectName('libraryBackground') + self.settingsButton = QtWidgets.QAction( + image_factory.get_image('settings'), + self._translate('LibraryToolBar', 'Settings'), + self) + self.settingsButton.setCheckable(True) + + self.aboutButton = QtWidgets.QAction( + image_factory.get_image('about'), + self._translate('LibraryToolBar', 'About'), + self) + # Auto unchecks the other QToolButton in case of clicking self.viewButtons = QtWidgets.QActionGroup(self) self.viewButtons.setExclusive(True) @@ -434,6 +440,7 @@ class LibraryToolBar(QtWidgets.QToolBar): self.addSeparator() self.addAction(self.colorButton) self.addAction(self.settingsButton) + self.addAction(self.aboutButton) # Filter sizePolicy = QtWidgets.QSizePolicy(