Improve logging
requirements.txt Small UI fixes
This commit is contained in:
@@ -19,7 +19,6 @@
|
|||||||
import os
|
import os
|
||||||
import gc
|
import gc
|
||||||
import sys
|
import sys
|
||||||
import logging
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
||||||
@@ -30,6 +29,13 @@ install_dir = os.path.realpath(__file__)
|
|||||||
install_dir = pathlib.Path(install_dir).parents[1]
|
install_dir = pathlib.Path(install_dir).parents[1]
|
||||||
sys.path.append(str(install_dir))
|
sys.path.append(str(install_dir))
|
||||||
|
|
||||||
|
# Init logging
|
||||||
|
# Must be done first and at the module level
|
||||||
|
# or it won't work properly in case of the imports below
|
||||||
|
from lector.logger import init_logging
|
||||||
|
logger = init_logging(sys.argv)
|
||||||
|
logger.log(60, 'Application started')
|
||||||
|
|
||||||
from PyQt5 import QtWidgets, QtGui, QtCore
|
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||||
|
|
||||||
from lector import database
|
from lector import database
|
||||||
@@ -85,10 +91,6 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
Settings(self).read_settings() # This should populate all variables that need
|
Settings(self).read_settings() # This should populate all variables that need
|
||||||
# to be remembered across sessions
|
# to be remembered across sessions
|
||||||
|
|
||||||
# Initialize logging
|
|
||||||
self.logger = init_logging(self.settings['log_level'])
|
|
||||||
self.logger.log(60, 'Application started')
|
|
||||||
|
|
||||||
# Initialize icon factory
|
# Initialize icon factory
|
||||||
self.QImageFactory = QImageFactory(self)
|
self.QImageFactory = QImageFactory(self)
|
||||||
|
|
||||||
@@ -245,7 +247,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
|
|
||||||
# Get list of available parsers
|
# Get list of available parsers
|
||||||
self.available_parsers = '*.' + ' *.'.join(sorter.available_parsers)
|
self.available_parsers = '*.' + ' *.'.join(sorter.available_parsers)
|
||||||
self.logger.info('Available parsers: ' + self.available_parsers)
|
logger.info('Available parsers: ' + self.available_parsers)
|
||||||
|
|
||||||
# The Library tab gets no button
|
# The Library tab gets no button
|
||||||
self.tabWidget.tabBar().setTabButton(
|
self.tabWidget.tabBar().setTabButton(
|
||||||
@@ -412,7 +414,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
if not file_paths:
|
if not file_paths:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.logger.info(
|
logger.info(
|
||||||
'Attempting to open: ' + ', '.join(file_paths))
|
'Attempting to open: ' + ', '.join(file_paths))
|
||||||
|
|
||||||
contents = sorter.BookSorter(
|
contents = sorter.BookSorter(
|
||||||
@@ -426,7 +428,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
# Notification feedback in case all books return nothing
|
# Notification feedback in case all books return nothing
|
||||||
|
|
||||||
if not contents:
|
if not contents:
|
||||||
self.logger.error('No parseable files found')
|
logger.error('No parseable files found')
|
||||||
return
|
return
|
||||||
|
|
||||||
successfully_opened = []
|
successfully_opened = []
|
||||||
@@ -436,7 +438,7 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
file_data = contents[i]
|
file_data = contents[i]
|
||||||
Tab(file_data, self)
|
Tab(file_data, self)
|
||||||
successfully_opened.append(file_data['path'])
|
successfully_opened.append(file_data['path'])
|
||||||
self.logger.info(
|
logger.info(
|
||||||
'Successfully opened: ' + ', '.join(file_paths))
|
'Successfully opened: ' + ', '.join(file_paths))
|
||||||
|
|
||||||
if self.settings['last_open_tab'] == 'library':
|
if self.settings['last_open_tab'] == 'library':
|
||||||
@@ -1038,21 +1040,6 @@ class MainUI(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
QtWidgets.qApp.exit()
|
QtWidgets.qApp.exit()
|
||||||
|
|
||||||
|
|
||||||
def init_logging(log_level):
|
|
||||||
location_prefix = QtCore.QStandardPaths.writableLocation(
|
|
||||||
QtCore.QStandardPaths.AppDataLocation)
|
|
||||||
os.makedirs(location_prefix, exist_ok=True)
|
|
||||||
logger_filename = os.path.join(location_prefix, 'Lector.log')
|
|
||||||
logging.basicConfig(
|
|
||||||
filename=logger_filename,
|
|
||||||
filemode='a',
|
|
||||||
format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
|
|
||||||
datefmt='%Y/%M/%d %H:%M:%S',
|
|
||||||
level=log_level)
|
|
||||||
logging.addLevelName(60, 'HammerTime') ## Messages that MUST be logged
|
|
||||||
return logging.getLogger('lector.main')
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
app = QtWidgets.QApplication(sys.argv)
|
app = QtWidgets.QApplication(sys.argv)
|
||||||
app.setApplicationName('Lector') # This is needed for QStandardPaths
|
app.setApplicationName('Lector') # This is needed for QStandardPaths
|
||||||
|
54
lector/logger.py
Normal file
54
lector/logger.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# This file is a part of Lector, a Qt based ebook reader
|
||||||
|
# Copyright (C) 2017-2019 BasioMeusPuga
|
||||||
|
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from PyQt5 import QtCore
|
||||||
|
|
||||||
|
|
||||||
|
def init_logging(cli_arguments):
|
||||||
|
# This needs a separate 'Lector' in the os.path.join because
|
||||||
|
# application name isn't explicitly set in this module
|
||||||
|
location_prefix = os.path.join(
|
||||||
|
QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.AppDataLocation),
|
||||||
|
'Lector')
|
||||||
|
os.makedirs(location_prefix, exist_ok=True)
|
||||||
|
logger_filename = os.path.join(location_prefix, 'Lector.log')
|
||||||
|
|
||||||
|
log_level = 30 # Warning and above
|
||||||
|
# Set log level according to command line arguments
|
||||||
|
try:
|
||||||
|
if cli_arguments[1] == 'debug':
|
||||||
|
log_level = 10 # Debug and above
|
||||||
|
print('Debug logging enabled')
|
||||||
|
try:
|
||||||
|
os.remove(logger_filename) # Remove old log for clarity
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Create logging object
|
||||||
|
logging.basicConfig(
|
||||||
|
filename=logger_filename,
|
||||||
|
filemode='a',
|
||||||
|
format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
|
||||||
|
datefmt='%Y/%m/%d %H:%M:%S',
|
||||||
|
level=log_level)
|
||||||
|
logging.addLevelName(60, 'HAMMERTIME') ## Messages that MUST be logged
|
||||||
|
|
||||||
|
return logging.getLogger('lector.main')
|
@@ -88,11 +88,6 @@ class Settings:
|
|||||||
'currentProfileIndex', 0))
|
'currentProfileIndex', 0))
|
||||||
self.parent.comic_profile = self.settings.value(
|
self.parent.comic_profile = self.settings.value(
|
||||||
'comicProfile', self.default_comic_profile)
|
'comicProfile', self.default_comic_profile)
|
||||||
try:
|
|
||||||
log_level = int(self.settings.value('logLevel', logging.WARNING))
|
|
||||||
except ValueError:
|
|
||||||
log_level = 30
|
|
||||||
self.parent.settings['log_level'] = log_level
|
|
||||||
self.settings.endGroup()
|
self.settings.endGroup()
|
||||||
|
|
||||||
self.settings.beginGroup('lastOpen')
|
self.settings.beginGroup('lastOpen')
|
||||||
@@ -153,6 +148,8 @@ class Settings:
|
|||||||
self.parent.settings['annotations'] = list()
|
self.parent.settings['annotations'] = list()
|
||||||
self.settings.endGroup()
|
self.settings.endGroup()
|
||||||
|
|
||||||
|
logger.info('Settings loaded')
|
||||||
|
|
||||||
def save_settings(self):
|
def save_settings(self):
|
||||||
current_settings = self.parent.settings
|
current_settings = self.parent.settings
|
||||||
|
|
||||||
@@ -187,7 +184,6 @@ class Settings:
|
|||||||
current_profile3])
|
current_profile3])
|
||||||
self.settings.setValue('currentProfileIndex', current_profile_index)
|
self.settings.setValue('currentProfileIndex', current_profile_index)
|
||||||
self.settings.setValue('comicProfile', self.parent.comic_profile)
|
self.settings.setValue('comicProfile', self.parent.comic_profile)
|
||||||
self.settings.setValue('logLevel', self.parent.settings['log_level'])
|
|
||||||
self.settings.endGroup()
|
self.settings.endGroup()
|
||||||
|
|
||||||
current_tab_index = self.parent.tabWidget.currentIndex()
|
current_tab_index = self.parent.tabWidget.currentIndex()
|
||||||
|
@@ -192,7 +192,7 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
|
|||||||
self.main_window.generate_library_filter_menu(paths)
|
self.main_window.generate_library_filter_menu(paths)
|
||||||
directory_data = {}
|
directory_data = {}
|
||||||
if not paths:
|
if not paths:
|
||||||
logger.warning('No paths saved for books')
|
logger.warning('No book paths saved')
|
||||||
else:
|
else:
|
||||||
# Convert to the dictionary format that is
|
# Convert to the dictionary format that is
|
||||||
# to be fed into the QFileSystemModel
|
# to be fed into the QFileSystemModel
|
||||||
@@ -264,9 +264,14 @@ class SettingsUI(QtWidgets.QDialog, settingswindow.Ui_Dialog):
|
|||||||
self.database_path).set_library_paths(data_pairs)
|
self.database_path).set_library_paths(data_pairs)
|
||||||
|
|
||||||
if not data_pairs:
|
if not data_pairs:
|
||||||
|
logger.error('Can\'t scan - No book paths saved')
|
||||||
try:
|
try:
|
||||||
if self.sender().objectName() == 'reloadLibrary':
|
if self.sender().objectName() == 'reloadLibrary':
|
||||||
self.show()
|
self.show()
|
||||||
|
treeViewIndex = self.listModel.index(0, 0)
|
||||||
|
self.listView.setCurrentIndex(treeViewIndex)
|
||||||
|
self.page_switch(treeViewIndex)
|
||||||
|
return
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@@ -39,6 +39,7 @@ import pickle
|
|||||||
import logging
|
import logging
|
||||||
import hashlib
|
import hashlib
|
||||||
import threading
|
import threading
|
||||||
|
import importlib
|
||||||
|
|
||||||
# The multiprocessing module does not work correctly on Windows
|
# The multiprocessing module does not work correctly on Windows
|
||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
@@ -57,26 +58,38 @@ from lector.parsers.comicbooks import ParseCOMIC
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
sorter = {
|
sorter = {
|
||||||
'epub': ParseEPUB,
|
|
||||||
'mobi': ParseMOBI,
|
|
||||||
'azw': ParseMOBI,
|
|
||||||
'azw3': ParseMOBI,
|
|
||||||
'azw4': ParseMOBI,
|
|
||||||
'prc': ParseMOBI,
|
|
||||||
'fb2': ParseFB2,
|
|
||||||
'fb2.zip': ParseFB2,
|
|
||||||
'cbz': ParseCOMIC,
|
'cbz': ParseCOMIC,
|
||||||
'cbr': ParseCOMIC}
|
'cbr': ParseCOMIC}
|
||||||
|
|
||||||
# The following imports are for optional dependencies
|
# Check what dependencies are installed
|
||||||
try:
|
# python-poppler-qt5 - Optional
|
||||||
|
poppler_check = importlib.util.find_spec('popplerqt5')
|
||||||
|
if poppler_check:
|
||||||
from lector.parsers.pdf import ParsePDF
|
from lector.parsers.pdf import ParsePDF
|
||||||
sorter['pdf'] = ParsePDF
|
sorter['pdf'] = ParsePDF
|
||||||
except ImportError:
|
else:
|
||||||
error_string = 'python-poppler-qt5 is not installed. Pdf files will not work.'
|
error_string = 'python-poppler-qt5 is not installed. Will be unable to load PDFs.'
|
||||||
print(error_string)
|
print(error_string)
|
||||||
logger.error(error_string)
|
logger.error(error_string)
|
||||||
|
|
||||||
|
# python-lxml - Required for everything except comics
|
||||||
|
lxml_check = importlib.util.find_spec('lxml')
|
||||||
|
if lxml_check:
|
||||||
|
lxml_dependent = {
|
||||||
|
'epub': ParseEPUB,
|
||||||
|
'mobi': ParseMOBI,
|
||||||
|
'azw': ParseMOBI,
|
||||||
|
'azw3': ParseMOBI,
|
||||||
|
'azw4': ParseMOBI,
|
||||||
|
'prc': ParseMOBI,
|
||||||
|
'fb2': ParseFB2,
|
||||||
|
'fb2.zip': ParseFB2}
|
||||||
|
sorter.update(lxml_dependent)
|
||||||
|
else:
|
||||||
|
critical_sting = 'python-lxml is not installed. Only comics will load.'
|
||||||
|
print(critical_sting)
|
||||||
|
logger.critical(critical_sting)
|
||||||
|
|
||||||
available_parsers = [i for i in sorter]
|
available_parsers = [i for i in sorter]
|
||||||
progressbar = None # This is populated by __main__
|
progressbar = None # This is populated by __main__
|
||||||
progress_emitter = None # This is to be made into a global variable
|
progress_emitter = None # This is to be made into a global variable
|
||||||
|
@@ -124,8 +124,11 @@ class BackGroundBookSearch(QtCore.QThread):
|
|||||||
|
|
||||||
if self.valid_directories:
|
if self.valid_directories:
|
||||||
initiate_threads()
|
initiate_threads()
|
||||||
info_string = str(len(self.valid_files)) + ' books found'
|
if self.valid_files:
|
||||||
logger.info(info_string)
|
info_string = str(len(self.valid_files)) + ' books found'
|
||||||
|
logger.info(info_string)
|
||||||
|
else:
|
||||||
|
logger.error('No books found on scan')
|
||||||
else:
|
else:
|
||||||
logger.error('No valid directories')
|
logger.error('No valid directories')
|
||||||
|
|
||||||
|
@@ -407,6 +407,7 @@ class LibraryToolBar(QtWidgets.QToolBar):
|
|||||||
image_factory.get_image('reload'),
|
image_factory.get_image('reload'),
|
||||||
self._translate('LibraryToolBar', 'Scan Library'),
|
self._translate('LibraryToolBar', 'Scan Library'),
|
||||||
self)
|
self)
|
||||||
|
self.reloadLibraryButton.setObjectName('reloadLibrary')
|
||||||
|
|
||||||
self.libraryFilterButton = QtWidgets.QToolButton(self)
|
self.libraryFilterButton = QtWidgets.QToolButton(self)
|
||||||
self.libraryFilterButton.setIcon(image_factory.get_image('view-readermode'))
|
self.libraryFilterButton.setIcon(image_factory.get_image('view-readermode'))
|
||||||
|
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
beautifulsoup4==4.7.1
|
||||||
|
lxml==4.3.0
|
||||||
|
PyQt5==5.11.3
|
||||||
|
PyQt5-sip==4.19.13
|
||||||
|
soupsieve==1.7.2
|
Reference in New Issue
Block a user