Merge branch 'master' into cover_thumbnail
# Conflicts: # cps/editbooks.py # cps/helper.py # cps/web.py # test/Calibre-Web TestSummary_Linux.html
This commit is contained in:
@@ -17,13 +17,13 @@
|
||||
# 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 sys
|
||||
import os
|
||||
import re
|
||||
import ast
|
||||
import json
|
||||
from datetime import datetime
|
||||
from urllib.parse import quote
|
||||
import unidecode
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy import Table, Column, ForeignKey, CheckConstraint
|
||||
@@ -49,11 +49,6 @@ from .pagination import Pagination
|
||||
|
||||
from weakref import WeakSet
|
||||
|
||||
try:
|
||||
import unidecode
|
||||
use_unidecode = True
|
||||
except ImportError:
|
||||
use_unidecode = False
|
||||
|
||||
log = logger.create()
|
||||
|
||||
@@ -93,7 +88,7 @@ books_publishers_link = Table('books_publishers_link', Base.metadata,
|
||||
)
|
||||
|
||||
|
||||
class Library_Id(Base):
|
||||
class LibraryId(Base):
|
||||
__tablename__ = 'library_id'
|
||||
id = Column(Integer, primary_key=True)
|
||||
uuid = Column(String, nullable=False)
|
||||
@@ -112,7 +107,7 @@ class Identifiers(Base):
|
||||
self.type = id_type
|
||||
self.book = book
|
||||
|
||||
def formatType(self):
|
||||
def format_type(self):
|
||||
format_type = self.type.lower()
|
||||
if format_type == 'amazon':
|
||||
return u"Amazon"
|
||||
@@ -184,8 +179,8 @@ class Comments(Base):
|
||||
book = Column(Integer, ForeignKey('books.id'), nullable=False, unique=True)
|
||||
text = Column(String(collation='NOCASE'), nullable=False)
|
||||
|
||||
def __init__(self, text, book):
|
||||
self.text = text
|
||||
def __init__(self, comment, book):
|
||||
self.text = comment
|
||||
self.book = book
|
||||
|
||||
def get(self):
|
||||
@@ -367,7 +362,6 @@ class Books(Base):
|
||||
self.path = path
|
||||
self.has_cover = (has_cover != None)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return u"<Books('{0},{1}{2}{3}{4}{5}{6}{7}{8}')>".format(self.title, self.sort, self.author_sort,
|
||||
self.timestamp, self.pubdate, self.series_index,
|
||||
@@ -375,10 +369,10 @@ class Books(Base):
|
||||
|
||||
@property
|
||||
def atom_timestamp(self):
|
||||
return (self.timestamp.strftime('%Y-%m-%dT%H:%M:%S+00:00') or '')
|
||||
return self.timestamp.strftime('%Y-%m-%dT%H:%M:%S+00:00') or ''
|
||||
|
||||
|
||||
class Custom_Columns(Base):
|
||||
class CustomColumns(Base):
|
||||
__tablename__ = 'custom_columns'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
@@ -436,7 +430,7 @@ class AlchemyEncoder(json.JSONEncoder):
|
||||
return json.JSONEncoder.default(self, o)
|
||||
|
||||
|
||||
class CalibreDB():
|
||||
class CalibreDB:
|
||||
_init = False
|
||||
engine = None
|
||||
config = None
|
||||
@@ -460,7 +454,7 @@ class CalibreDB():
|
||||
self.update_title_sort(self.config)
|
||||
|
||||
@classmethod
|
||||
def setup_db_cc_classes(self, cc):
|
||||
def setup_db_cc_classes(cls, cc):
|
||||
cc_ids = []
|
||||
books_custom_column_links = {}
|
||||
for row in cc:
|
||||
@@ -539,16 +533,16 @@ class CalibreDB():
|
||||
return False, False
|
||||
try:
|
||||
check_engine = create_engine('sqlite://',
|
||||
echo=False,
|
||||
isolation_level="SERIALIZABLE",
|
||||
connect_args={'check_same_thread': False},
|
||||
poolclass=StaticPool)
|
||||
echo=False,
|
||||
isolation_level="SERIALIZABLE",
|
||||
connect_args={'check_same_thread': False},
|
||||
poolclass=StaticPool)
|
||||
with check_engine.begin() as connection:
|
||||
connection.execute(text("attach database '{}' as calibre;".format(dbpath)))
|
||||
connection.execute(text("attach database '{}' as app_settings;".format(app_db_path)))
|
||||
local_session = scoped_session(sessionmaker())
|
||||
local_session.configure(bind=connection)
|
||||
database_uuid = local_session().query(Library_Id).one_or_none()
|
||||
database_uuid = local_session().query(LibraryId).one_or_none()
|
||||
# local_session.dispose()
|
||||
|
||||
check_engine.connect()
|
||||
@@ -597,7 +591,7 @@ class CalibreDB():
|
||||
cc = conn.execute(text("SELECT id, datatype FROM custom_columns"))
|
||||
cls.setup_db_cc_classes(cc)
|
||||
except OperationalError as e:
|
||||
log.debug_or_exception(e)
|
||||
log.error_or_exception(e)
|
||||
|
||||
cls.session_factory = scoped_session(sessionmaker(autocommit=False,
|
||||
autoflush=True,
|
||||
@@ -644,12 +638,10 @@ class CalibreDB():
|
||||
# Language and content filters for displaying in the UI
|
||||
def common_filters(self, allow_show_archived=False, return_all_languages=False):
|
||||
if not allow_show_archived:
|
||||
archived_books = (
|
||||
ub.session.query(ub.ArchivedBook)
|
||||
.filter(ub.ArchivedBook.user_id == int(current_user.id))
|
||||
.filter(ub.ArchivedBook.is_archived == True)
|
||||
.all()
|
||||
)
|
||||
archived_books = (ub.session.query(ub.ArchivedBook)
|
||||
.filter(ub.ArchivedBook.user_id == int(current_user.id))
|
||||
.filter(ub.ArchivedBook.is_archived == True)
|
||||
.all())
|
||||
archived_book_ids = [archived_book.book_id for archived_book in archived_books]
|
||||
archived_filter = Books.id.notin_(archived_book_ids)
|
||||
else:
|
||||
@@ -668,11 +660,11 @@ class CalibreDB():
|
||||
pos_cc_list = current_user.allowed_column_value.split(',')
|
||||
pos_content_cc_filter = true() if pos_cc_list == [''] else \
|
||||
getattr(Books, 'custom_column_' + str(self.config.config_restricted_column)). \
|
||||
any(cc_classes[self.config.config_restricted_column].value.in_(pos_cc_list))
|
||||
any(cc_classes[self.config.config_restricted_column].value.in_(pos_cc_list))
|
||||
neg_cc_list = current_user.denied_column_value.split(',')
|
||||
neg_content_cc_filter = false() if neg_cc_list == [''] else \
|
||||
getattr(Books, 'custom_column_' + str(self.config.config_restricted_column)). \
|
||||
any(cc_classes[self.config.config_restricted_column].value.in_(neg_cc_list))
|
||||
any(cc_classes[self.config.config_restricted_column].value.in_(neg_cc_list))
|
||||
except (KeyError, AttributeError):
|
||||
pos_content_cc_filter = false()
|
||||
neg_content_cc_filter = true()
|
||||
@@ -729,7 +721,7 @@ class CalibreDB():
|
||||
query = (self.session.query(database, ub.ReadBook.read_status, ub.ArchivedBook.is_archived)
|
||||
.select_from(Books)
|
||||
.outerjoin(ub.ReadBook,
|
||||
and_(ub.ReadBook.user_id == int(current_user.id), ub.ReadBook.book_id == Books.id)))
|
||||
and_(ub.ReadBook.user_id == int(current_user.id), ub.ReadBook.book_id == Books.id)))
|
||||
else:
|
||||
try:
|
||||
read_column = cc_classes[config_read_column]
|
||||
@@ -739,7 +731,7 @@ class CalibreDB():
|
||||
except (KeyError, AttributeError):
|
||||
log.error("Custom Column No.%d is not existing in calibre database", read_column)
|
||||
# Skip linking read column and return None instead of read status
|
||||
query =self.session.query(database, None, ub.ArchivedBook.is_archived)
|
||||
query = self.session.query(database, None, ub.ArchivedBook.is_archived)
|
||||
query = query.outerjoin(ub.ArchivedBook, and_(Books.id == ub.ArchivedBook.book_id,
|
||||
int(current_user.id) == ub.ArchivedBook.user_id))
|
||||
else:
|
||||
@@ -770,13 +762,15 @@ class CalibreDB():
|
||||
len(query.all()))
|
||||
entries = query.order_by(*order).offset(off).limit(pagesize).all()
|
||||
except Exception as ex:
|
||||
log.debug_or_exception(ex)
|
||||
log.error_or_exception(ex)
|
||||
# display authors in right order
|
||||
entries = self.order_authors(entries, True, join_archive_read)
|
||||
return entries, randm, pagination
|
||||
|
||||
# Orders all Authors in the list according to authors sort
|
||||
def order_authors(self, entries, list_return=False, combined=False):
|
||||
# entries_copy = copy.deepcopy(entries)
|
||||
# entries_copy =[]
|
||||
for entry in entries:
|
||||
if combined:
|
||||
sort_authors = entry.Books.author_sort.split('&')
|
||||
@@ -786,25 +780,30 @@ class CalibreDB():
|
||||
sort_authors = entry.author_sort.split('&')
|
||||
ids = [a.id for a in entry.authors]
|
||||
authors_ordered = list()
|
||||
error = False
|
||||
# error = False
|
||||
for auth in sort_authors:
|
||||
results = self.session.query(Authors).filter(Authors.sort == auth.lstrip().strip()).all()
|
||||
# ToDo: How to handle not found authorname
|
||||
# ToDo: How to handle not found author name
|
||||
if not len(results):
|
||||
error = True
|
||||
log.error("Author {} not found to display name in right order".format(auth.strip()))
|
||||
# error = True
|
||||
break
|
||||
for r in results:
|
||||
if r.id in ids:
|
||||
authors_ordered.append(r)
|
||||
if not error:
|
||||
ids.remove(r.id)
|
||||
for author_id in ids:
|
||||
result = self.session.query(Authors).filter(Authors.id == author_id).first()
|
||||
authors_ordered.append(result)
|
||||
|
||||
if list_return:
|
||||
if combined:
|
||||
entry.Books.authors = authors_ordered
|
||||
else:
|
||||
entry.authors = authors_ordered
|
||||
if list_return:
|
||||
return entries
|
||||
else:
|
||||
return authors_ordered
|
||||
entry.ordered_authors = authors_ordered
|
||||
else:
|
||||
return authors_ordered
|
||||
return entries
|
||||
|
||||
def get_typeahead(self, database, query, replace=('', ''), tag_filter=true()):
|
||||
query = query or ''
|
||||
@@ -865,7 +864,7 @@ class CalibreDB():
|
||||
))
|
||||
|
||||
# read search results from calibre-database and return it (function is used for feed and simple search
|
||||
def get_search_results(self, term, offset=None, order=None, limit=None, allow_show_archived=False,
|
||||
def get_search_results(self, term, offset=None, order=None, limit=None,
|
||||
config_read_column=False, *join):
|
||||
order = order[0] if order else [Books.sort]
|
||||
pagination = None
|
||||
@@ -908,7 +907,6 @@ class CalibreDB():
|
||||
lang.name = isoLanguages.get_language_name(get_locale(), lang.lang_code)
|
||||
return sorted(languages, key=lambda x: x.name, reverse=reverse_order)
|
||||
|
||||
|
||||
def update_title_sort(self, config, conn=None):
|
||||
# user defined sort function for calibre databases (Series, etc.)
|
||||
def _title_sort(title):
|
||||
@@ -966,6 +964,6 @@ def lcase(s):
|
||||
try:
|
||||
return unidecode.unidecode(s.lower())
|
||||
except Exception as ex:
|
||||
log = logger.create()
|
||||
log.debug_or_exception(ex)
|
||||
_log = logger.create()
|
||||
_log.error_or_exception(ex)
|
||||
return s.lower()
|
||||
|
||||
Reference in New Issue
Block a user