Refactored helper.py and db.py

pull/1429/head
Ozzieisaacs 5 years ago
parent ec3a3a73ef
commit 5f0660a4e5

@ -37,8 +37,6 @@ from . import config_sql, logger, cache_buster, cli, ub, db
from .reverseproxy import ReverseProxied from .reverseproxy import ReverseProxied
from .server import WebServer from .server import WebServer
# import queue
# queue = queue.Queue()
mimetypes.init() mimetypes.init()
mimetypes.add_type('application/xhtml+xml', '.xhtml') mimetypes.add_type('application/xhtml+xml', '.xhtml')

@ -39,7 +39,7 @@ from sqlalchemy.sql.expression import func
from . import constants, logger, helper, services from . import constants, logger, helper, services
from . import db, calibre_db, ub, web_server, get_locale, config, updater_thread, babel, gdriveutils from . import db, calibre_db, ub, web_server, get_locale, config, updater_thread, babel, gdriveutils
from .helper import speaking_language, check_valid_domain, send_test_mail, reset_password, generate_password_hash from .helper import check_valid_domain, send_test_mail, reset_password, generate_password_hash
from .gdriveutils import is_gdrive_ready, gdrive_support from .gdriveutils import is_gdrive_ready, gdrive_support
from .web import admin_required, render_title_template, before_request, unconfigured, login_required_if_no_ano from .web import admin_required, render_title_template, before_request, unconfigured, login_required_if_no_ano
@ -878,7 +878,7 @@ def _handle_edit_user(to_save, content,languages, translations, kobo_support, do
@admin_required @admin_required
def new_user(): def new_user():
content = ub.User() content = ub.User()
languages = speaking_language() languages = calibre_db.speaking_language()
translations = [LC('en')] + babel.list_translations() translations = [LC('en')] + babel.list_translations()
kobo_support = feature_support['kobo'] and config.config_kobo_sync kobo_support = feature_support['kobo'] and config.config_kobo_sync
if request.method == "POST": if request.method == "POST":
@ -942,11 +942,11 @@ def edit_user(user_id):
flash(_(u"User not found"), category="error") flash(_(u"User not found"), category="error")
return redirect(url_for('admin.admin')) return redirect(url_for('admin.admin'))
downloads = list() downloads = list()
languages = speaking_language() languages = calibre_db.speaking_language()
translations = babel.list_translations() + [LC('en')] translations = babel.list_translations() + [LC('en')]
kobo_support = feature_support['kobo'] and config.config_kobo_sync kobo_support = feature_support['kobo'] and config.config_kobo_sync
for book in content.downloads: for book in content.downloads:
downloadbook = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).first() downloadbook = calibre_db.get_book(book.book_id)
if downloadbook: if downloadbook:
downloads.append(downloadbook) downloads.append(downloadbook)
else: else:

@ -22,10 +22,9 @@ import sys
import os import os
import re import re
import ast import ast
import json
from datetime import datetime from datetime import datetime
import threading import threading
import time
import queue
from sqlalchemy import create_engine from sqlalchemy import create_engine
from sqlalchemy import Table, Column, ForeignKey, CheckConstraint from sqlalchemy import Table, Column, ForeignKey, CheckConstraint
@ -33,12 +32,24 @@ from sqlalchemy import String, Integer, Boolean, TIMESTAMP, Float
from sqlalchemy.orm import relationship, sessionmaker, scoped_session from sqlalchemy.orm import relationship, sessionmaker, scoped_session
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.exc import OperationalError from sqlalchemy.exc import OperationalError
from flask_login import current_user
from sqlalchemy.sql.expression import and_, true, false, text, func, or_
from babel import Locale as LC
from babel.core import UnknownLocaleError
from flask_babel import gettext as _
from . import logger, ub, isoLanguages
from .pagination import Pagination
try:
import unidecode
use_unidecode = True
except ImportError:
use_unidecode = False
from . import logger
# session = None
cc_exceptions = ['datetime', 'comments', 'composite', 'series'] cc_exceptions = ['datetime', 'comments', 'composite', 'series']
cc_classes = {} cc_classes = {}
# engine = None
Base = declarative_base() Base = declarative_base()
@ -327,6 +338,7 @@ class CalibreDB(threading.Thread):
self.session = None self.session = None
self.queue = None self.queue = None
self.log = None self.log = None
self.config = None
def add_queue(self,queue): def add_queue(self,queue):
self.queue = queue self.queue = queue
@ -356,6 +368,7 @@ class CalibreDB(threading.Thread):
self.queue.put('dummy') self.queue.put('dummy')
def setup_db(self, config, app_db_path): def setup_db(self, config, app_db_path):
self.config = config
self.dispose() self.dispose()
# global engine # global engine
@ -441,6 +454,149 @@ class CalibreDB(threading.Thread):
self.session = Session() self.session = Session()
return True return True
def get_book(self, book_id):
return self.session.query(Books).filter(Books.id == book_id).first()
def get_filtered_book(self, book_id, allow_show_archived=False):
return self.session.query(Books).filter(Books.id == book_id).\
filter(self.common_filters(allow_show_archived)).first()
def get_book_by_uuid(self, book_uuid):
return self.session.query(Books).filter(Books.uuid == book_uuid).first()
def get_book_format(self, book_id, format):
return self.session.query(Data).filter(Data.book == book_id).filter(Data.format == format).first()
# Language and content filters for displaying in the UI
def common_filters(self, allow_show_archived=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_book_ids = [archived_book.book_id for archived_book in archived_books]
archived_filter = Books.id.notin_(archived_book_ids)
else:
archived_filter = true()
if current_user.filter_language() != "all":
lang_filter = Books.languages.any(Languages.lang_code == current_user.filter_language())
else:
lang_filter = true()
negtags_list = current_user.list_denied_tags()
postags_list = current_user.list_allowed_tags()
neg_content_tags_filter = false() if negtags_list == [''] else Books.tags.any(Tags.name.in_(negtags_list))
pos_content_tags_filter = true() if postags_list == [''] else Books.tags.any(Tags.name.in_(postags_list))
if self.config.config_restricted_column:
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))
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))
else:
pos_content_cc_filter = true()
neg_content_cc_filter = false()
return and_(lang_filter, pos_content_tags_filter, ~neg_content_tags_filter,
pos_content_cc_filter, ~neg_content_cc_filter, archived_filter)
# Fill indexpage with all requested data from database
def fill_indexpage(self, page, database, db_filter, order, *join):
return self.fill_indexpage_with_archived_books(page, database, db_filter, order, False, *join)
def fill_indexpage_with_archived_books(self, page, database, db_filter, order, allow_show_archived, *join):
if current_user.show_detail_random():
randm = self.session.query(Books) \
.filter(self.common_filters(allow_show_archived)) \
.order_by(func.random()) \
.limit(self.config.config_random_books)
else:
randm = false()
off = int(int(self.config.config_books_per_page) * (page - 1))
query = self.session.query(database) \
.join(*join, isouter=True) \
.filter(db_filter) \
.filter(self.common_filters(allow_show_archived))
pagination = Pagination(page, self.config.config_books_per_page,
len(query.all()))
entries = query.order_by(*order).offset(off).limit(self.config.config_books_per_page).all()
for book in entries:
book = self.order_authors(book)
return entries, randm, pagination
# Orders all Authors in the list according to authors sort
def order_authors(self, entry):
sort_authors = entry.author_sort.split('&')
authors_ordered = list()
error = False
for auth in sort_authors:
# ToDo: How to handle not found authorname
result = self.session.query(Authors).filter(Authors.sort == auth.lstrip().strip()).first()
if not result:
error = True
break
authors_ordered.append(result)
if not error:
entry.authors = authors_ordered
return entry
def get_typeahead(self, database, query, replace=('', ''), tag_filter=true()):
query = query or ''
self.session.connection().connection.connection.create_function("lower", 1, self.lcase)
entries = self.session.query(database).filter(tag_filter). \
filter(func.lower(database.name).ilike("%" + query + "%")).all()
json_dumps = json.dumps([dict(name=r.name.replace(*replace)) for r in entries])
return json_dumps
def check_exists_book(self, authr, title):
self.session.connection().connection.connection.create_function("lower", 1, self.lcase)
q = list()
authorterms = re.split(r'\s*&\s*', authr)
for authorterm in authorterms:
q.append(Books.authors.any(func.lower(Authors.name).ilike("%" + authorterm + "%")))
return self.session.query(Books)\
.filter(and_(Books.authors.any(and_(*q)), func.lower(Books.title).ilike("%" + title + "%"))).first()
# read search results from calibre-database and return it (function is used for feed and simple search
def get_search_results(self, term):
term.strip().lower()
self.session.connection().connection.connection.create_function("lower", 1, self.lcase)
q = list()
authorterms = re.split("[, ]+", term)
for authorterm in authorterms:
q.append(Books.authors.any(func.lower(Authors.name).ilike("%" + authorterm + "%")))
return self.session.query(Books).filter(self.common_filters()).filter(
or_(Books.tags.any(func.lower(Tags.name).ilike("%" + term + "%")),
Books.series.any(func.lower(Series.name).ilike("%" + term + "%")),
Books.authors.any(and_(*q)),
Books.publishers.any(func.lower(Publishers.name).ilike("%" + term + "%")),
func.lower(Books.title).ilike("%" + term + "%")
)).order_by(Books.sort).all()
# Creates for all stored languages a translated speaking name in the array for the UI
def speaking_language(self, languages=None):
from . import get_locale
if not languages:
languages = self.session.query(Languages) \
.join(books_languages_link) \
.join(Books) \
.filter(self.common_filters()) \
.group_by(text('books_languages_link.lang_code')).all()
for lang in languages:
try:
cur_l = LC.parse(lang.lang_code)
lang.name = cur_l.get_language_name(get_locale())
except UnknownLocaleError:
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
return languages
def update_title_sort(self, config, conn=None): def update_title_sort(self, config, conn=None):
# user defined sort function for calibre databases (Series, etc.) # user defined sort function for calibre databases (Series, etc.)
def _title_sort(title): def _title_sort(title):
@ -481,8 +637,13 @@ class CalibreDB(threading.Thread):
if table is not None: if table is not None:
Base.metadata.remove(table) Base.metadata.remove(table)
def reconnect_db(self, config, app_db_path): def reconnect_db(self, config, app_db_path):
self.session.close() self.session.close()
self.engine.dispose() self.engine.dispose()
self.setup_db(config, app_db_path) self.setup_db(config, app_db_path)
def lcase(self, s):
try:
return unidecode.unidecode(s.lower())
except Exception as e:
self.log.exception(e)

@ -35,7 +35,6 @@ from sqlalchemy.exc import OperationalError
from . import constants, logger, isoLanguages, gdriveutils, uploader, helper from . import constants, logger, isoLanguages, gdriveutils, uploader, helper
from . import config, get_locale, ub, worker, db from . import config, get_locale, ub, worker, db
from . import calibre_db from . import calibre_db
from .helper import order_authors, common_filters
from .web import login_required_if_no_ano, render_title_template, edit_required, upload_required from .web import login_required_if_no_ano, render_title_template, edit_required, upload_required
@ -176,7 +175,7 @@ def modify_identifiers(input_identifiers, db_identifiers, db_session):
@login_required @login_required
def delete_book(book_id, book_format): def delete_book(book_id, book_format):
if current_user.role_delete_books(): if current_user.role_delete_books():
book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first() book = calibre_db.get_book(book_id)
if book: if book:
try: try:
result, error = helper.delete_book(book, config.config_calibre_dir, book_format=book_format.upper()) result, error = helper.delete_book(book, config.config_calibre_dir, book_format=book_format.upper())
@ -250,9 +249,7 @@ def delete_book(book_id, book_format):
def render_edit_book(book_id): def render_edit_book(book_id):
calibre_db.update_title_sort(config) calibre_db.update_title_sort(config)
cc = calibre_db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() cc = calibre_db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
book = calibre_db.session.query(db.Books)\ book = calibre_db.get_filtered_book(book_id)
.filter(db.Books.id == book_id).filter(common_filters()).first()
if not book: if not book:
flash(_(u"Error opening eBook. File does not exist or file is not accessible"), category="error") flash(_(u"Error opening eBook. File does not exist or file is not accessible"), category="error")
return redirect(url_for("web.index")) return redirect(url_for("web.index"))
@ -260,7 +257,7 @@ def render_edit_book(book_id):
for lang in book.languages: for lang in book.languages:
lang.language_name = isoLanguages.get_language_name(get_locale(), lang.lang_code) lang.language_name = isoLanguages.get_language_name(get_locale(), lang.lang_code)
book = order_authors(book) book = calibre_db.order_authors(book)
author_names = [] author_names = []
for authr in book.authors: for authr in book.authors:
@ -447,8 +444,7 @@ def upload_single_file(request, book, book_id):
return redirect(url_for('web.show_book', book_id=book.id)) return redirect(url_for('web.show_book', book_id=book.id))
file_size = os.path.getsize(saved_filename) file_size = os.path.getsize(saved_filename)
is_format = calibre_db.session.query(db.Data).filter(db.Data.book == book_id).\ is_format = calibre_db.get_book_format(book_id, file_ext.upper())
filter(db.Data.format == file_ext.upper()).first()
# Format entry already exists, no need to update the database # Format entry already exists, no need to update the database
if is_format: if is_format:
@ -500,8 +496,7 @@ def edit_book(book_id):
# create the function for sorting... # create the function for sorting...
calibre_db.update_title_sort(config) calibre_db.update_title_sort(config)
book = calibre_db.session.query(db.Books)\ book = calibre_db.get_filtered_book(book_id)
.filter(db.Books.id == book_id).filter(common_filters()).first()
# Book not found # Book not found
if not book: if not book:
@ -702,7 +697,7 @@ def upload():
series_index = meta.series_id series_index = meta.series_id
if title != _(u'Unknown') and authr != _(u'Unknown'): if title != _(u'Unknown') and authr != _(u'Unknown'):
entry = helper.check_exists_book(authr, title) entry = calibre_db.check_exists_book(authr, title)
if entry: if entry:
log.info("Uploaded book probably exists in library") log.info("Uploaded book probably exists in library")
flash(_(u"Uploaded book probably exists in the library, consider to change before upload new: ") flash(_(u"Uploaded book probably exists in the library, consider to change before upload new: ")
@ -807,7 +802,7 @@ def upload():
calibre_db.update_title_sort(config) calibre_db.update_title_sort(config)
# Reread book. It's important not to filter the result, as it could have language which hide it from # Reread book. It's important not to filter the result, as it could have language which hide it from
# current users view (tags are not stored/extracted from metadata and could also be limited) # current users view (tags are not stored/extracted from metadata and could also be limited)
book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first() book = calibre_db.get_book(book_id)
# upload book to gdrive if nesseccary and add "(bookid)" to folder name # upload book to gdrive if nesseccary and add "(bookid)" to folder name
if config.config_use_google_drive: if config.config_use_google_drive:
gdriveutils.updateGdriveCalibreFromLocal() gdriveutils.updateGdriveCalibreFromLocal()

@ -74,8 +74,8 @@ log = logger.create()
# Convert existing book entry to new format # Convert existing book entry to new format
def convert_book_format(book_id, calibrepath, old_book_format, new_book_format, user_id, kindle_mail=None): def convert_book_format(book_id, calibrepath, old_book_format, new_book_format, user_id, kindle_mail=None):
book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first() book = calibre_db.get_book(book_id)
data = calibre_db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == old_book_format).first() data = calibre_db.get_book_format(book.id, old_book_format)
if not data: if not data:
error_message = _(u"%(format)s format not found for book id: %(book)d", format=old_book_format, book=book_id) error_message = _(u"%(format)s format not found for book id: %(book)d", format=old_book_format, book=book_id)
log.error("convert_book_format: %s", error_message) log.error("convert_book_format: %s", error_message)
@ -212,7 +212,7 @@ def check_read_formats(entry):
# 3: If Pdf file is existing, it's directly send to kindle email # 3: If Pdf file is existing, it's directly send to kindle email
def send_mail(book_id, book_format, convert, kindle_mail, calibrepath, user_id): def send_mail(book_id, book_format, convert, kindle_mail, calibrepath, user_id):
"""Send email with attachments""" """Send email with attachments"""
book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first() book = calibre_db.get_book(book_id)
if convert == 1: if convert == 1:
# returns None if success, otherwise errormessage # returns None if success, otherwise errormessage
@ -324,7 +324,7 @@ def delete_book_file(book, calibrepath, book_format=None):
def update_dir_structure_file(book_id, calibrepath, first_author): def update_dir_structure_file(book_id, calibrepath, first_author):
localbook = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first() localbook = calibre_db.get_book(book_id)
path = os.path.join(calibrepath, localbook.path) path = os.path.join(calibrepath, localbook.path)
authordir = localbook.path.split('/')[0] authordir = localbook.path.split('/')[0]
@ -383,7 +383,7 @@ def update_dir_structure_file(book_id, calibrepath, first_author):
def update_dir_structure_gdrive(book_id, first_author): def update_dir_structure_gdrive(book_id, first_author):
error = False error = False
book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first() book = calibre_db.get_book(book_id)
path = book.path path = book.path
authordir = book.path.split('/')[0] authordir = book.path.split('/')[0]
@ -494,18 +494,17 @@ def get_cover_on_failure(use_generic_cover):
def get_book_cover(book_id): def get_book_cover(book_id):
book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters(allow_show_archived=True)).first() book = calibre_db.get_filtered_book(book_id, allow_show_archived=True)
return get_book_cover_internal(book, use_generic_cover_on_failure=True) return get_book_cover_internal(book, use_generic_cover_on_failure=True)
def get_book_cover_with_uuid(book_uuid, def get_book_cover_with_uuid(book_uuid,
use_generic_cover_on_failure=True): use_generic_cover_on_failure=True):
book = calibre_db.session.query(db.Books).filter(db.Books.uuid == book_uuid).first() book = calibre_db.get_book_by_uuid(book_uuid)
return get_book_cover_internal(book, use_generic_cover_on_failure) return get_book_cover_internal(book, use_generic_cover_on_failure)
def get_book_cover_internal(book, def get_book_cover_internal(book, use_generic_cover_on_failure):
use_generic_cover_on_failure):
if book and book.has_cover: if book and book.has_cover:
if config.config_use_google_drive: if config.config_use_google_drive:
try: try:
@ -725,66 +724,12 @@ def render_task_status(tasklist):
return renderedtasklist return renderedtasklist
# Language and content filters for displaying in the UI
def common_filters(allow_show_archived=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_book_ids = [archived_book.book_id for archived_book in archived_books]
archived_filter = db.Books.id.notin_(archived_book_ids)
else:
archived_filter = true()
if current_user.filter_language() != "all":
lang_filter = db.Books.languages.any(db.Languages.lang_code == current_user.filter_language())
else:
lang_filter = true()
negtags_list = current_user.list_denied_tags()
postags_list = current_user.list_allowed_tags()
neg_content_tags_filter = false() if negtags_list == [''] else db.Books.tags.any(db.Tags.name.in_(negtags_list))
pos_content_tags_filter = true() if postags_list == [''] else db.Books.tags.any(db.Tags.name.in_(postags_list))
if config.config_restricted_column:
pos_cc_list = current_user.allowed_column_value.split(',')
pos_content_cc_filter = true() if pos_cc_list == [''] else \
getattr(db.Books, 'custom_column_' + str(config.config_restricted_column)).\
any(db.cc_classes[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(db.Books, 'custom_column_' + str(config.config_restricted_column)).\
any(db.cc_classes[config.config_restricted_column].value.in_(neg_cc_list))
else:
pos_content_cc_filter = true()
neg_content_cc_filter = false()
return and_(lang_filter, pos_content_tags_filter, ~neg_content_tags_filter,
pos_content_cc_filter, ~neg_content_cc_filter, archived_filter)
def tags_filters(): def tags_filters():
negtags_list = current_user.list_denied_tags() negtags_list = current_user.list_denied_tags()
postags_list = current_user.list_allowed_tags() postags_list = current_user.list_allowed_tags()
neg_content_tags_filter = false() if negtags_list == [''] else db.Tags.name.in_(negtags_list) neg_content_tags_filter = false() if negtags_list == [''] else db.Tags.name.in_(negtags_list)
pos_content_tags_filter = true() if postags_list == [''] else db.Tags.name.in_(postags_list) pos_content_tags_filter = true() if postags_list == [''] else db.Tags.name.in_(postags_list)
return and_(pos_content_tags_filter, ~neg_content_tags_filter) return and_(pos_content_tags_filter, ~neg_content_tags_filter)
# return ~(false()) if postags_list == [''] else db.Tags.in_(postags_list)
# Creates for all stored languages a translated speaking name in the array for the UI
def speaking_language(languages=None):
if not languages:
languages = calibre_db.session.query(db.Languages).join(db.books_languages_link).join(db.Books)\
.filter(common_filters())\
.group_by(text('books_languages_link.lang_code')).all()
for lang in languages:
try:
cur_l = LC.parse(lang.lang_code)
lang.name = cur_l.get_language_name(get_locale())
except UnknownLocaleError:
lang.name = _(isoLanguages.get(part3=lang.lang_code).name)
return languages
# checks if domain is in database (including wildcards) # checks if domain is in database (including wildcards)
@ -801,76 +746,9 @@ def check_valid_domain(domain_text):
return not len(result) return not len(result)
# Orders all Authors in the list according to authors sort
def order_authors(entry):
sort_authors = entry.author_sort.split('&')
authors_ordered = list()
error = False
for auth in sort_authors:
# ToDo: How to handle not found authorname
result = calibre_db.session.query(db.Authors).filter(db.Authors.sort == auth.lstrip().strip()).first()
if not result:
error = True
break
authors_ordered.append(result)
if not error:
entry.authors = authors_ordered
return entry
# Fill indexpage with all requested data from database
def fill_indexpage(page, database, db_filter, order, *join):
return fill_indexpage_with_archived_books(page, database, db_filter, order, False, *join)
def fill_indexpage_with_archived_books(page, database, db_filter, order, allow_show_archived, *join):
if current_user.show_detail_random():
randm = calibre_db.session.query(db.Books).filter(common_filters(allow_show_archived))\
.order_by(func.random()).limit(config.config_random_books)
else:
randm = false()
off = int(int(config.config_books_per_page) * (page - 1))
query = calibre_db.session.query(database).join(*join, isouter=True).\
filter(db_filter).\
filter(common_filters(allow_show_archived))
pagination = Pagination(page, config.config_books_per_page,
len(query.all()))
entries = query.order_by(*order).offset(off).limit(config.config_books_per_page).all()
for book in entries:
book = order_authors(book)
return entries, randm, pagination
def get_typeahead(database, query, replace=('', ''), tag_filter=true()):
query = query or ''
calibre_db.session.connection().connection.connection.create_function("lower", 1, lcase)
entries = calibre_db.session.query(database).filter(tag_filter).\
filter(func.lower(database.name).ilike("%" + query + "%")).all()
json_dumps = json.dumps([dict(name=r.name.replace(*replace)) for r in entries])
return json_dumps
# read search results from calibre-database and return it (function is used for feed and simple search
def get_search_results(term):
calibre_db.session.connection().connection.connection.create_function("lower", 1, lcase)
q = list()
authorterms = re.split("[, ]+", term)
for authorterm in authorterms:
q.append(db.Books.authors.any(func.lower(db.Authors.name).ilike("%" + authorterm + "%")))
db.Books.authors.any(func.lower(db.Authors.name).ilike("%" + term + "%"))
return calibre_db.session.query(db.Books).filter(common_filters()).filter(
or_(db.Books.tags.any(func.lower(db.Tags.name).ilike("%" + term + "%")),
db.Books.series.any(func.lower(db.Series.name).ilike("%" + term + "%")),
db.Books.authors.any(and_(*q)),
db.Books.publishers.any(func.lower(db.Publishers.name).ilike("%" + term + "%")),
func.lower(db.Books.title).ilike("%" + term + "%")
)).order_by(db.Books.sort).all()
def get_cc_columns(filter_config_custom_read=False): def get_cc_columns(filter_config_custom_read=False):
tmpcc = calibre_db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all() tmpcc = calibre_db.session.query(db.Custom_Columns)\
.filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
cc = [] cc = []
r = None r = None
if config.config_columns_to_ignore: if config.config_columns_to_ignore:
@ -887,10 +765,9 @@ def get_cc_columns(filter_config_custom_read=False):
def get_download_link(book_id, book_format, client): def get_download_link(book_id, book_format, client):
book_format = book_format.split(".")[0] book_format = book_format.split(".")[0]
book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first() book = calibre_db.get_filtered_book(book_id)
if book: if book:
data1 = calibre_db.session.query(db.Data).filter(db.Data.book == book.id)\ data1 = data = calibre_db.get_book_format(book.id, book_format.upper())
.filter(db.Data.format == book_format.upper()).first()
else: else:
abort(404) abort(404)
if data1: if data1:
@ -908,25 +785,3 @@ def get_download_link(book_id, book_format, client):
return do_download_file(book, book_format, client, data1, headers) return do_download_file(book, book_format, client, data1, headers)
else: else:
abort(404) abort(404)
def check_exists_book(authr, title):
calibre_db.session.connection().connection.connection.create_function("lower", 1, lcase)
q = list()
authorterms = re.split(r'\s*&\s*', authr)
for authorterm in authorterms:
q.append(db.Books.authors.any(func.lower(db.Authors.name).ilike("%" + authorterm + "%")))
return calibre_db.session.query(db.Books).filter(
and_(db.Books.authors.any(and_(*q)),
func.lower(db.Books.title).ilike("%" + title + "%")
)).first()
############### Database Helper functions
def lcase(s):
try:
return unidecode.unidecode(s.lower())
except Exception as e:
log.exception(e)

@ -111,10 +111,3 @@ def timestamptodate(date, fmt=None):
@jinjia.app_template_filter('yesno') @jinjia.app_template_filter('yesno')
def yesno(value, yes, no): def yesno(value, yes, no):
return yes if value else no return yes if value else no
'''@jinjia.app_template_filter('canread')
def canread(ext):
if isinstance(ext, db.Data):
ext = ext.format
return ext.lower() in EXTENSIONS_READER'''

@ -256,7 +256,7 @@ def HandleMetadataRequest(book_uuid):
if not current_app.wsgi_app.is_proxied: if not current_app.wsgi_app.is_proxied:
log.debug('Kobo: Received unproxied request, changed request port to server port') log.debug('Kobo: Received unproxied request, changed request port to server port')
log.info("Kobo library metadata request received for book %s" % book_uuid) log.info("Kobo library metadata request received for book %s" % book_uuid)
book = calibre_db.session.query(db.Books).filter(db.Books.uuid == book_uuid).first() book = calibre_db.get_book_by_uuid(book_uuid)
if not book or not book.data: if not book or not book.data:
log.info(u"Book %s not found in database", book_uuid) log.info(u"Book %s not found in database", book_uuid)
return redirect_or_proxy_request() return redirect_or_proxy_request()
@ -474,7 +474,7 @@ def add_items_to_shelf(items, shelf):
items_unknown_to_calibre.append(item) items_unknown_to_calibre.append(item)
continue continue
book = calibre_db.session.query(db.Books).filter(db.Books.uuid == item["RevisionId"]).one_or_none() book = calibre_db.get_book_by_uuid(item["RevisionId"])
if not book: if not book:
items_unknown_to_calibre.append(item) items_unknown_to_calibre.append(item)
continue continue
@ -545,7 +545,7 @@ def HandleTagRemoveItem(tag_id):
items_unknown_to_calibre.append(item) items_unknown_to_calibre.append(item)
continue continue
book = calibre_db.session.query(db.Books).filter(db.Books.uuid == item["RevisionId"]).one_or_none() book = calibre_db.get_book_by_uuid(item["RevisionId"])
if not book: if not book:
items_unknown_to_calibre.append(item) items_unknown_to_calibre.append(item)
continue continue
@ -613,7 +613,7 @@ def create_kobo_tag(shelf):
"Type": "UserTag" "Type": "UserTag"
} }
for book_shelf in shelf.books: for book_shelf in shelf.books:
book = calibre_db.session.query(db.Books).filter(db.Books.id == book_shelf.book_id).one_or_none() book = calibre_db.get_book_by_uuid(book_shelf.book_id)
if not book: if not book:
log.info(u"Book (id: %s) in BookShelf (id: %s) not found in book database", book_shelf.book_id, shelf.id) log.info(u"Book (id: %s) in BookShelf (id: %s) not found in book database", book_shelf.book_id, shelf.id)
continue continue
@ -629,7 +629,7 @@ def create_kobo_tag(shelf):
@kobo.route("/v1/library/<book_uuid>/state", methods=["GET", "PUT"]) @kobo.route("/v1/library/<book_uuid>/state", methods=["GET", "PUT"])
@login_required @login_required
def HandleStateRequest(book_uuid): def HandleStateRequest(book_uuid):
book = calibre_db.session.query(db.Books).filter(db.Books.uuid == book_uuid).first() book = calibre_db.get_book_by_uuid(book_uuid)
if not book or not book.data: if not book or not book.data:
log.info(u"Book %s not found in database", book_uuid) log.info(u"Book %s not found in database", book_uuid)
return redirect_or_proxy_request() return redirect_or_proxy_request()
@ -804,7 +804,7 @@ def TopLevelEndpoint():
@login_required @login_required
def HandleBookDeletionRequest(book_uuid): def HandleBookDeletionRequest(book_uuid):
log.info("Kobo book deletion request received for book %s" % book_uuid) log.info("Kobo book deletion request received for book %s" % book_uuid)
book = calibre_db.session.query(db.Books).filter(db.Books.uuid == book_uuid).first() book = calibre_db.get_book_by_uuid(book_uuid)
if not book: if not book:
log.info(u"Book %s not found in database", book_uuid) log.info(u"Book %s not found in database", book_uuid)
return redirect_or_proxy_request() return redirect_or_proxy_request()

@ -31,9 +31,9 @@ from sqlalchemy.sql.expression import func, text, or_, and_
from werkzeug.security import check_password_hash from werkzeug.security import check_password_hash
from . import constants, logger, config, db, calibre_db, ub, services, get_locale, isoLanguages from . import constants, logger, config, db, calibre_db, ub, services, get_locale, isoLanguages
from .helper import fill_indexpage, get_download_link, get_book_cover, speaking_language from .helper import get_download_link, get_book_cover
from .pagination import Pagination from .pagination import Pagination
from .web import common_filters, get_search_results, render_read_books, download_required from .web import render_read_books, download_required
from flask_babel import gettext as _ from flask_babel import gettext as _
from babel import Locale as LC from babel import Locale as LC
from babel.core import UnknownLocaleError from babel.core import UnknownLocaleError
@ -100,7 +100,7 @@ def feed_normal_search():
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_new(): def feed_new():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
db.Books, True, [db.Books.timestamp.desc()]) db.Books, True, [db.Books.timestamp.desc()])
return render_xml_template('feed.xml', entries=entries, pagination=pagination) return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@ -108,7 +108,7 @@ def feed_new():
@opds.route("/opds/discover") @opds.route("/opds/discover")
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_discover(): def feed_discover():
entries = calibre_db.session.query(db.Books).filter(common_filters()).order_by(func.random())\ entries = calibre_db.session.query(db.Books).filter(calibre_db.common_filters()).order_by(func.random())\
.limit(config.config_books_per_page) .limit(config.config_books_per_page)
pagination = Pagination(1, config.config_books_per_page, int(config.config_books_per_page)) pagination = Pagination(1, config.config_books_per_page, int(config.config_books_per_page))
return render_xml_template('feed.xml', entries=entries, pagination=pagination) return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@ -118,7 +118,7 @@ def feed_discover():
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_best_rated(): def feed_best_rated():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
db.Books, db.Books.ratings.any(db.Ratings.rating > 9), db.Books, db.Books.ratings.any(db.Ratings.rating > 9),
[db.Books.timestamp.desc()]) [db.Books.timestamp.desc()])
return render_xml_template('feed.xml', entries=entries, pagination=pagination) return render_xml_template('feed.xml', entries=entries, pagination=pagination)
@ -133,16 +133,13 @@ def feed_hot():
hot_books = all_books.offset(off).limit(config.config_books_per_page) hot_books = all_books.offset(off).limit(config.config_books_per_page)
entries = list() entries = list()
for book in hot_books: for book in hot_books:
downloadBook = calibre_db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first() downloadBook = calibre_db.get_book(book.Downloads.book_id)
if downloadBook: if downloadBook:
entries.append( entries.append(
calibre_db.session.query(db.Books).filter(common_filters()) calibre_db.get_filtered_book(book.Downloads.book_id)
.filter(db.Books.id == book.Downloads.book_id).first()
) )
else: else:
ub.delete_download(book.Downloads.book_id) ub.delete_download(book.Downloads.book_id)
# ub.session.query(ub.Downloads).filter(book.Downloads.book_id == ub.Downloads.book_id).delete()
# ub.session.commit()
numBooks = entries.__len__() numBooks = entries.__len__()
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1),
config.config_books_per_page, numBooks) config.config_books_per_page, numBooks)
@ -153,8 +150,10 @@ def feed_hot():
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_authorindex(): def feed_authorindex():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries = calibre_db.session.query(db.Authors).join(db.books_authors_link).join(db.Books).filter(common_filters())\ entries = calibre_db.session.query(db.Authors).join(db.books_authors_link).join(db.Books)\
.group_by(text('books_authors_link.author')).order_by(db.Authors.sort).limit(config.config_books_per_page)\ .filter(calibre_db.common_filters())\
.group_by(text('books_authors_link.author'))\
.order_by(db.Authors.sort).limit(config.config_books_per_page)\
.offset(off) .offset(off)
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(calibre_db.session.query(db.Authors).all())) len(calibre_db.session.query(db.Authors).all()))
@ -165,7 +164,7 @@ def feed_authorindex():
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_author(book_id): def feed_author(book_id):
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
db.Books, db.Books,
db.Books.authors.any(db.Authors.id == book_id), db.Books.authors.any(db.Authors.id == book_id),
[db.Books.timestamp.desc()]) [db.Books.timestamp.desc()])
@ -176,8 +175,11 @@ def feed_author(book_id):
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_publisherindex(): def feed_publisherindex():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries = calibre_db.session.query(db.Publishers).join(db.books_publishers_link).join(db.Books).filter(common_filters())\ entries = calibre_db.session.query(db.Publishers)\
.group_by(text('books_publishers_link.publisher')).order_by(db.Publishers.sort)\ .join(db.books_publishers_link)\
.join(db.Books).filter(calibre_db.common_filters())\
.group_by(text('books_publishers_link.publisher'))\
.order_by(db.Publishers.sort)\
.limit(config.config_books_per_page).offset(off) .limit(config.config_books_per_page).offset(off)
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(calibre_db.session.query(db.Publishers).all())) len(calibre_db.session.query(db.Publishers).all()))
@ -188,7 +190,7 @@ def feed_publisherindex():
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_publisher(book_id): def feed_publisher(book_id):
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
db.Books, db.Books,
db.Books.publishers.any(db.Publishers.id == book_id), db.Books.publishers.any(db.Publishers.id == book_id),
[db.Books.timestamp.desc()]) [db.Books.timestamp.desc()])
@ -199,8 +201,14 @@ def feed_publisher(book_id):
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_categoryindex(): def feed_categoryindex():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries = calibre_db.session.query(db.Tags).join(db.books_tags_link).join(db.Books).filter(common_filters())\ entries = calibre_db.session.query(db.Tags)\
.group_by(text('books_tags_link.tag')).order_by(db.Tags.name).offset(off).limit(config.config_books_per_page) .join(db.books_tags_link)\
.join(db.Books)\
.filter(calibre_db.common_filters())\
.group_by(text('books_tags_link.tag'))\
.order_by(db.Tags.name)\
.offset(off)\
.limit(config.config_books_per_page)
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(calibre_db.session.query(db.Tags).all())) len(calibre_db.session.query(db.Tags).all()))
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_category', pagination=pagination) return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_category', pagination=pagination)
@ -210,7 +218,7 @@ def feed_categoryindex():
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_category(book_id): def feed_category(book_id):
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
db.Books, db.Books,
db.Books.tags.any(db.Tags.id == book_id), db.Books.tags.any(db.Tags.id == book_id),
[db.Books.timestamp.desc()]) [db.Books.timestamp.desc()])
@ -221,8 +229,13 @@ def feed_category(book_id):
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_seriesindex(): def feed_seriesindex():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries = calibre_db.session.query(db.Series).join(db.books_series_link).join(db.Books).filter(common_filters())\ entries = calibre_db.session.query(db.Series)\
.group_by(text('books_series_link.series')).order_by(db.Series.sort).offset(off).all() .join(db.books_series_link)\
.join(db.Books)\
.filter(calibre_db.common_filters())\
.group_by(text('books_series_link.series'))\
.order_by(db.Series.sort)\
.offset(off).all()
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(calibre_db.session.query(db.Series).all())) len(calibre_db.session.query(db.Series).all()))
return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_series', pagination=pagination) return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_series', pagination=pagination)
@ -232,7 +245,7 @@ def feed_seriesindex():
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_series(book_id): def feed_series(book_id):
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
db.Books, db.Books,
db.Books.series.any(db.Series.id == book_id), db.Books.series.any(db.Series.id == book_id),
[db.Books.series_index]) [db.Books.series_index])
@ -245,8 +258,11 @@ def feed_ratingindex():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries = calibre_db.session.query(db.Ratings, func.count('books_ratings_link.book').label('count'), entries = calibre_db.session.query(db.Ratings, func.count('books_ratings_link.book').label('count'),
(db.Ratings.rating / 2).label('name')) \ (db.Ratings.rating / 2).label('name')) \
.join(db.books_ratings_link).join(db.Books).filter(common_filters()) \ .join(db.books_ratings_link)\
.group_by(text('books_ratings_link.rating')).order_by(db.Ratings.rating).all() .join(db.Books)\
.filter(calibre_db.common_filters()) \
.group_by(text('books_ratings_link.rating'))\
.order_by(db.Ratings.rating).all()
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(entries)) len(entries))
@ -260,7 +276,7 @@ def feed_ratingindex():
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_ratings(book_id): def feed_ratings(book_id):
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
db.Books, db.Books,
db.Books.ratings.any(db.Ratings.id == book_id), db.Books.ratings.any(db.Ratings.id == book_id),
[db.Books.timestamp.desc()]) [db.Books.timestamp.desc()])
@ -271,8 +287,10 @@ def feed_ratings(book_id):
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_formatindex(): def feed_formatindex():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries = calibre_db.session.query(db.Data).join(db.Books).filter(common_filters()) \ entries = calibre_db.session.query(db.Data).join(db.Books)\
.group_by(db.Data.format).order_by(db.Data.format).all() .filter(calibre_db.common_filters()) \
.group_by(db.Data.format)\
.order_by(db.Data.format).all()
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(entries)) len(entries))
@ -286,7 +304,7 @@ def feed_formatindex():
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_format(book_id): def feed_format(book_id):
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
db.Books, db.Books,
db.Books.data.any(db.Data.format == book_id.upper()), db.Books.data.any(db.Data.format == book_id.upper()),
[db.Books.timestamp.desc()]) [db.Books.timestamp.desc()])
@ -299,7 +317,7 @@ def feed_format(book_id):
def feed_languagesindex(): def feed_languagesindex():
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
if current_user.filter_language() == u"all": if current_user.filter_language() == u"all":
languages = speaking_language() languages = calibre_db.speaking_language()
else: else:
try: try:
cur_l = LC.parse(current_user.filter_language()) cur_l = LC.parse(current_user.filter_language())
@ -320,7 +338,7 @@ def feed_languagesindex():
@requires_basic_auth_if_no_ano @requires_basic_auth_if_no_ano
def feed_languages(book_id): def feed_languages(book_id):
off = request.args.get("offset") or 0 off = request.args.get("offset") or 0
entries, __, pagination = fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1), entries, __, pagination = calibre_db.fill_indexpage((int(off) / (int(config.config_books_per_page)) + 1),
db.Books, db.Books,
db.Books.languages.any(db.Languages.id == book_id), db.Books.languages.any(db.Languages.id == book_id),
[db.Books.timestamp.desc()]) [db.Books.timestamp.desc()])
@ -356,7 +374,7 @@ def feed_shelf(book_id):
books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == book_id).order_by( books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == book_id).order_by(
ub.BookShelf.order.asc()).all() ub.BookShelf.order.asc()).all()
for book in books_in_shelf: for book in books_in_shelf:
cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).first() cur_book = calibre_db.get_book(book.book_id)
result.append(cur_book) result.append(cur_book)
pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page, pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
len(result)) len(result))
@ -390,8 +408,7 @@ def get_metadata_calibre_companion(uuid, library):
def feed_search(term): def feed_search(term):
if term: if term:
term = term.strip().lower() entries = calibre_db.get_search_results(term)
entries = get_search_results(term)
entriescount = len(entries) if len(entries) > 0 else 1 entriescount = len(entries) if len(entries) > 0 else 1
pagination = Pagination(1, entriescount, entriescount) pagination = Pagination(1, entriescount, entriescount)
return render_xml_template('feed.xml', searchterm=term, entries=entries, pagination=pagination) return render_xml_template('feed.xml', searchterm=term, entries=entries, pagination=pagination)

@ -30,7 +30,6 @@ from sqlalchemy.sql.expression import func
from . import logger, ub, searched_ids, db, calibre_db from . import logger, ub, searched_ids, db, calibre_db
from .web import render_title_template from .web import render_title_template
from .helper import common_filters
shelf = Blueprint('shelf', __name__) shelf = Blueprint('shelf', __name__)
@ -320,11 +319,11 @@ def show_shelf(shelf_type, shelf_id):
books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id)\ books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id)\
.order_by(ub.BookShelf.order.asc()).all() .order_by(ub.BookShelf.order.asc()).all()
for book in books_in_shelf: for book in books_in_shelf:
cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).filter(common_filters()).first() cur_book = calibre_db.get_filtered_book(book.book_id)
if cur_book: if cur_book:
result.append(cur_book) result.append(cur_book)
else: else:
cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).first() cur_book = calibre_db.get_book(book.book_id)
if not cur_book: if not cur_book:
log.info('Not existing book %s in %s deleted', book.book_id, shelf) log.info('Not existing book %s in %s deleted', book.book_id, shelf)
ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book.book_id).delete() ub.session.query(ub.BookShelf).filter(ub.BookShelf.book_id == book.book_id).delete()
@ -356,7 +355,7 @@ def order_shelf(shelf_id):
books_in_shelf2 = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id) \ books_in_shelf2 = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id) \
.order_by(ub.BookShelf.order.asc()).all() .order_by(ub.BookShelf.order.asc()).all()
for book in books_in_shelf2: for book in books_in_shelf2:
cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).filter(common_filters()).first() cur_book = calibre_db.get_filtered_book(book.book_id)
if cur_book: if cur_book:
result.append({'title': cur_book.title, result.append({'title': cur_book.title,
'id': cur_book.id, 'id': cur_book.id,
@ -364,7 +363,7 @@ def order_shelf(shelf_id):
'series': cur_book.series, 'series': cur_book.series,
'series_index': cur_book.series_index}) 'series_index': cur_book.series_index})
else: else:
cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).first() cur_book = calibre_db.get_book(book.book_id)
result.append({'title': _('Hidden Book'), result.append({'title': _('Hidden Book'),
'id': cur_book.id, 'id': cur_book.id,
'author': [], 'author': [],

@ -52,10 +52,9 @@ from . import constants, logger, isoLanguages, services, worker
from . import searched_ids, lm, babel, db, ub, config, get_locale, app from . import searched_ids, lm, babel, db, ub, config, get_locale, app
from . import calibre_db from . import calibre_db
from .gdriveutils import getFileFromEbooksFolder, do_gdrive_download from .gdriveutils import getFileFromEbooksFolder, do_gdrive_download
from .helper import common_filters, get_search_results, fill_indexpage, fill_indexpage_with_archived_books, \ from .helper import check_valid_domain, render_task_status, json_serial, \
speaking_language, check_valid_domain, order_authors, get_typeahead, render_task_status, json_serial, \
get_cc_columns, get_book_cover, get_download_link, send_mail, generate_random_password, \ get_cc_columns, get_book_cover, get_download_link, send_mail, generate_random_password, \
send_registration_mail, check_send_to_kindle, check_read_formats, lcase, tags_filters, reset_password send_registration_mail, check_send_to_kindle, check_read_formats, tags_filters, reset_password
from .pagination import Pagination from .pagination import Pagination
from .redirect import redirect_back from .redirect import redirect_back
@ -440,7 +439,7 @@ def toggle_read(book_id):
else: else:
try: try:
calibre_db.update_title_sort(config) calibre_db.update_title_sort(config)
book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first() book = calibre_db.get_filtered_book(book_id)
read_status = getattr(book, 'custom_column_' + str(config.config_read_column)) read_status = getattr(book, 'custom_column_' + str(config.config_read_column))
if len(read_status): if len(read_status):
read_status[0].value = not read_status[0].value read_status[0].value = not read_status[0].value
@ -497,7 +496,7 @@ def update_view():
@web.route("/ajax/getcomic/<int:book_id>/<book_format>/<int:page>") @web.route("/ajax/getcomic/<int:book_id>/<book_format>/<int:page>")
@login_required @login_required
def get_comic_book(book_id, book_format, page): def get_comic_book(book_id, book_format, page):
book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first() book = calibre_db.get_book(book_id)
if not book: if not book:
return "", 204 return "", 204
else: else:
@ -551,25 +550,25 @@ def get_comic_book(book_id, book_format, page):
@web.route("/get_authors_json", methods=['GET']) @web.route("/get_authors_json", methods=['GET'])
@login_required_if_no_ano @login_required_if_no_ano
def get_authors_json(): def get_authors_json():
return get_typeahead(db.Authors, request.args.get('q'), ('|', ',')) return calibre_db.get_typeahead(db.Authors, request.args.get('q'), ('|', ','))
@web.route("/get_publishers_json", methods=['GET']) @web.route("/get_publishers_json", methods=['GET'])
@login_required_if_no_ano @login_required_if_no_ano
def get_publishers_json(): def get_publishers_json():
return get_typeahead(db.Publishers, request.args.get('q'), ('|', ',')) return calibre_db.get_typeahead(db.Publishers, request.args.get('q'), ('|', ','))
@web.route("/get_tags_json", methods=['GET']) @web.route("/get_tags_json", methods=['GET'])
@login_required_if_no_ano @login_required_if_no_ano
def get_tags_json(): def get_tags_json():
return get_typeahead(db.Tags, request.args.get('q'), tag_filter=tags_filters()) return calibre_db.get_typeahead(db.Tags, request.args.get('q'), tag_filter=tags_filters())
@web.route("/get_series_json", methods=['GET']) @web.route("/get_series_json", methods=['GET'])
@login_required_if_no_ano @login_required_if_no_ano
def get_series_json(): def get_series_json():
return get_typeahead(db.Series, request.args.get('q')) return calibre_db.get_typeahead(db.Series, request.args.get('q'))
@web.route("/get_languages_json", methods=['GET']) @web.route("/get_languages_json", methods=['GET'])
@ -591,7 +590,7 @@ def get_languages_json():
def get_matching_tags(): def get_matching_tags():
tag_dict = {'tags': []} tag_dict = {'tags': []}
q = calibre_db.session.query(db.Books) q = calibre_db.session.query(db.Books)
calibre_db.session.connection().connection.connection.create_function("lower", 1, lcase) calibre_db.session.connection().connection.connection.create_function("lower", 1, calibre_db.lcase)
author_input = request.args.get('author_name') or '' author_input = request.args.get('author_name') or ''
title_input = request.args.get('book_title') or '' title_input = request.args.get('book_title') or ''
include_tag_inputs = request.args.getlist('include_tag') or '' include_tag_inputs = request.args.getlist('include_tag') or ''
@ -621,7 +620,7 @@ def get_matching_tags():
@web.route('/page/<int:page>') @web.route('/page/<int:page>')
@login_required_if_no_ano @login_required_if_no_ano
def index(page): def index(page):
entries, random, pagination = fill_indexpage(page, db.Books, True, [db.Books.timestamp.desc()]) entries, random, pagination = calibre_db.fill_indexpage(page, db.Books, True, [db.Books.timestamp.desc()])
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
title=_(u"Recently Added Books"), page="root") title=_(u"Recently Added Books"), page="root")
@ -648,7 +647,9 @@ def books_list(data, sort, book_id, page):
if data == "rated": if data == "rated":
if current_user.check_visibility(constants.SIDEBAR_BEST_RATED): if current_user.check_visibility(constants.SIDEBAR_BEST_RATED):
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.ratings.any(db.Ratings.rating > 9), entries, random, pagination = calibre_db.fill_indexpage(page,
db.Books,
db.Books.ratings.any(db.Ratings.rating > 9),
order) order)
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
id=book_id, title=_(u"Top Rated Books"), page="rated") id=book_id, title=_(u"Top Rated Books"), page="rated")
@ -656,7 +657,7 @@ def books_list(data, sort, book_id, page):
abort(404) abort(404)
elif data == "discover": elif data == "discover":
if current_user.check_visibility(constants.SIDEBAR_RANDOM): if current_user.check_visibility(constants.SIDEBAR_RANDOM):
entries, __, pagination = fill_indexpage(page, db.Books, True, [func.randomblob(2)]) entries, __, pagination = calibre_db.calibre_db.fill_indexpage(page, db.Books, True, [func.randomblob(2)])
pagination = Pagination(1, config.config_books_per_page, config.config_books_per_page) pagination = Pagination(1, config.config_books_per_page, config.config_books_per_page)
return render_title_template('discover.html', entries=entries, pagination=pagination, id=book_id, return render_title_template('discover.html', entries=entries, pagination=pagination, id=book_id,
title=_(u"Discover (Random Books)"), page="discover") title=_(u"Discover (Random Books)"), page="discover")
@ -685,7 +686,7 @@ def books_list(data, sort, book_id, page):
elif data == "archived": elif data == "archived":
return render_archived_books(page, order) return render_archived_books(page, order)
else: else:
entries, random, pagination = fill_indexpage(page, db.Books, True, order) entries, random, pagination = calibre_db.fill_indexpage(page, db.Books, True, order)
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, return render_title_template('index.html', random=random, entries=entries, pagination=pagination,
title=_(u"Books"), page="newest") title=_(u"Books"), page="newest")
@ -693,7 +694,7 @@ def books_list(data, sort, book_id, page):
def render_hot_books(page): def render_hot_books(page):
if current_user.check_visibility(constants.SIDEBAR_HOT): if current_user.check_visibility(constants.SIDEBAR_HOT):
if current_user.show_detail_random(): if current_user.show_detail_random():
random = calibre_db.session.query(db.Books).filter(common_filters()) \ random = calibre_db.session.query(db.Books).filter(calibre_db.common_filters()) \
.order_by(func.random()).limit(config.config_random_books) .order_by(func.random()).limit(config.config_random_books)
else: else:
random = false() random = false()
@ -703,7 +704,7 @@ def render_hot_books(page):
hot_books = all_books.offset(off).limit(config.config_books_per_page) hot_books = all_books.offset(off).limit(config.config_books_per_page)
entries = list() entries = list()
for book in hot_books: for book in hot_books:
downloadBook = calibre_db.session.query(db.Books).filter(common_filters()).filter( downloadBook = calibre_db.session.query(db.Books).filter(calibre_db.common_filters()).filter(
db.Books.id == book.Downloads.book_id).first() db.Books.id == book.Downloads.book_id).first()
if downloadBook: if downloadBook:
entries.append(downloadBook) entries.append(downloadBook)
@ -720,9 +721,12 @@ def render_hot_books(page):
def render_author_books(page, author_id, order): def render_author_books(page, author_id, order):
entries, __, pagination = fill_indexpage(page, db.Books, db.Books.authors.any(db.Authors.id == author_id), entries, __, pagination = calibre_db.fill_indexpage(page,
db.Books,
db.Books.authors.any(db.Authors.id == author_id),
[order[0], db.Series.name, db.Books.series_index], [order[0], db.Series.name, db.Books.series_index],
db.books_series_link, db.Series) db.books_series_link,
db.Series)
if entries is None or not len(entries): if entries is None or not len(entries):
flash(_(u"Oops! Selected book title is unavailable. File does not exist or is not accessible"), flash(_(u"Oops! Selected book title is unavailable. File does not exist or is not accessible"),
category="error") category="error")
@ -745,10 +749,12 @@ def render_author_books(page, author_id, order):
def render_publisher_books(page, book_id, order): def render_publisher_books(page, book_id, order):
publisher = calibre_db.session.query(db.Publishers).filter(db.Publishers.id == book_id).first() publisher = calibre_db.session.query(db.Publishers).filter(db.Publishers.id == book_id).first()
if publisher: if publisher:
entries, random, pagination = fill_indexpage(page, db.Books, entries, random, pagination = calibre_db.fill_indexpage(page,
db.Books,
db.Books.publishers.any(db.Publishers.id == book_id), db.Books.publishers.any(db.Publishers.id == book_id),
[db.Series.name, order[0], db.Books.series_index], [db.Series.name, order[0], db.Books.series_index],
db.books_series_link, db.Series) db.books_series_link,
db.Series)
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=book_id, return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=book_id,
title=_(u"Publisher: %(name)s", name=publisher.name), page="publisher") title=_(u"Publisher: %(name)s", name=publisher.name), page="publisher")
else: else:
@ -758,7 +764,9 @@ def render_publisher_books(page, book_id, order):
def render_series_books(page, book_id, order): def render_series_books(page, book_id, order):
name = calibre_db.session.query(db.Series).filter(db.Series.id == book_id).first() name = calibre_db.session.query(db.Series).filter(db.Series.id == book_id).first()
if name: if name:
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.series.any(db.Series.id == book_id), entries, random, pagination = calibre_db.fill_indexpage(page,
db.Books,
db.Books.series.any(db.Series.id == book_id),
[db.Books.series_index, order[0]]) [db.Books.series_index, order[0]])
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id, return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
title=_(u"Series: %(serie)s", serie=name.name), page="series") title=_(u"Series: %(serie)s", serie=name.name), page="series")
@ -768,7 +776,9 @@ def render_series_books(page, book_id, order):
def render_ratings_books(page, book_id, order): def render_ratings_books(page, book_id, order):
name = calibre_db.session.query(db.Ratings).filter(db.Ratings.id == book_id).first() name = calibre_db.session.query(db.Ratings).filter(db.Ratings.id == book_id).first()
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.ratings.any(db.Ratings.id == book_id), entries, random, pagination = calibre_db.fill_indexpage(page,
db.Books,
db.Books.ratings.any(db.Ratings.id == book_id),
[db.Books.timestamp.desc(), order[0]]) [db.Books.timestamp.desc(), order[0]])
if name and name.rating <= 10: if name and name.rating <= 10:
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id, return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
@ -780,7 +790,8 @@ def render_ratings_books(page, book_id, order):
def render_formats_books(page, book_id, order): def render_formats_books(page, book_id, order):
name = calibre_db.session.query(db.Data).filter(db.Data.format == book_id.upper()).first() name = calibre_db.session.query(db.Data).filter(db.Data.format == book_id.upper()).first()
if name: if name:
entries, random, pagination = fill_indexpage(page, db.Books, entries, random, pagination = calibre_db.fill_indexpage(page,
db.Books,
db.Books.data.any(db.Data.format == book_id.upper()), db.Books.data.any(db.Data.format == book_id.upper()),
[db.Books.timestamp.desc(), order[0]]) [db.Books.timestamp.desc(), order[0]])
return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id, return render_title_template('index.html', random=random, pagination=pagination, entries=entries, id=book_id,
@ -792,7 +803,9 @@ def render_formats_books(page, book_id, order):
def render_category_books(page, book_id, order): def render_category_books(page, book_id, order):
name = calibre_db.session.query(db.Tags).filter(db.Tags.id == book_id).first() name = calibre_db.session.query(db.Tags).filter(db.Tags.id == book_id).first()
if name: if name:
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.tags.any(db.Tags.id == book_id), entries, random, pagination = calibre_db.fill_indexpage(page,
db.Books,
db.Books.tags.any(db.Tags.id == book_id),
[order[0], db.Series.name, db.Books.series_index], [order[0], db.Series.name, db.Books.series_index],
db.books_series_link, db.Series) db.books_series_link, db.Series)
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=book_id, return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=book_id,
@ -810,7 +823,9 @@ def render_language_books(page, name, order):
lang_name = _(isoLanguages.get(part3=name).name) lang_name = _(isoLanguages.get(part3=name).name)
except KeyError: except KeyError:
abort(404) abort(404)
entries, random, pagination = fill_indexpage(page, db.Books, db.Books.languages.any(db.Languages.lang_code == name), entries, random, pagination = calibre_db.fill_indexpage(page,
db.Books,
db.Books.languages.any(db.Languages.lang_code == name),
[db.Books.timestamp.desc(), order[0]]) [db.Books.timestamp.desc(), order[0]])
return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=name, return render_title_template('index.html', random=random, entries=entries, pagination=pagination, id=name,
title=_(u"Language: %(name)s", name=lang_name), page="language") title=_(u"Language: %(name)s", name=lang_name), page="language")
@ -827,10 +842,10 @@ def books_table():
def author_list(): def author_list():
if current_user.check_visibility(constants.SIDEBAR_AUTHOR): if current_user.check_visibility(constants.SIDEBAR_AUTHOR):
entries = calibre_db.session.query(db.Authors, func.count('books_authors_link.book').label('count')) \ entries = calibre_db.session.query(db.Authors, func.count('books_authors_link.book').label('count')) \
.join(db.books_authors_link).join(db.Books).filter(common_filters()) \ .join(db.books_authors_link).join(db.Books).filter(calibre_db.common_filters()) \
.group_by(text('books_authors_link.author')).order_by(db.Authors.sort).all() .group_by(text('books_authors_link.author')).order_by(db.Authors.sort).all()
charlist = calibre_db.session.query(func.upper(func.substr(db.Authors.sort, 1, 1)).label('char')) \ charlist = calibre_db.session.query(func.upper(func.substr(db.Authors.sort, 1, 1)).label('char')) \
.join(db.books_authors_link).join(db.Books).filter(common_filters()) \ .join(db.books_authors_link).join(db.Books).filter(calibre_db.common_filters()) \
.group_by(func.upper(func.substr(db.Authors.sort, 1, 1))).all() .group_by(func.upper(func.substr(db.Authors.sort, 1, 1))).all()
for entry in entries: for entry in entries:
entry.Authors.name = entry.Authors.name.replace('|', ',') entry.Authors.name = entry.Authors.name.replace('|', ',')
@ -845,10 +860,10 @@ def author_list():
def publisher_list(): def publisher_list():
if current_user.check_visibility(constants.SIDEBAR_PUBLISHER): if current_user.check_visibility(constants.SIDEBAR_PUBLISHER):
entries = calibre_db.session.query(db.Publishers, func.count('books_publishers_link.book').label('count')) \ entries = calibre_db.session.query(db.Publishers, func.count('books_publishers_link.book').label('count')) \
.join(db.books_publishers_link).join(db.Books).filter(common_filters()) \ .join(db.books_publishers_link).join(db.Books).filter(calibre_db.common_filters()) \
.group_by(text('books_publishers_link.publisher')).order_by(db.Publishers.name).all() .group_by(text('books_publishers_link.publisher')).order_by(db.Publishers.name).all()
charlist = calibre_db.session.query(func.upper(func.substr(db.Publishers.name, 1, 1)).label('char')) \ charlist = calibre_db.session.query(func.upper(func.substr(db.Publishers.name, 1, 1)).label('char')) \
.join(db.books_publishers_link).join(db.Books).filter(common_filters()) \ .join(db.books_publishers_link).join(db.Books).filter(calibre_db.common_filters()) \
.group_by(func.upper(func.substr(db.Publishers.name, 1, 1))).all() .group_by(func.upper(func.substr(db.Publishers.name, 1, 1))).all()
return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=charlist, return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=charlist,
title=_(u"Publishers"), page="publisherlist", data="publisher") title=_(u"Publishers"), page="publisherlist", data="publisher")
@ -862,19 +877,19 @@ def series_list():
if current_user.check_visibility(constants.SIDEBAR_SERIES): if current_user.check_visibility(constants.SIDEBAR_SERIES):
if current_user.series_view == 'list': if current_user.series_view == 'list':
entries = calibre_db.session.query(db.Series, func.count('books_series_link.book').label('count')) \ entries = calibre_db.session.query(db.Series, func.count('books_series_link.book').label('count')) \
.join(db.books_series_link).join(db.Books).filter(common_filters()) \ .join(db.books_series_link).join(db.Books).filter(calibre_db.common_filters()) \
.group_by(text('books_series_link.series')).order_by(db.Series.sort).all() .group_by(text('books_series_link.series')).order_by(db.Series.sort).all()
charlist = calibre_db.session.query(func.upper(func.substr(db.Series.sort, 1, 1)).label('char')) \ charlist = calibre_db.session.query(func.upper(func.substr(db.Series.sort, 1, 1)).label('char')) \
.join(db.books_series_link).join(db.Books).filter(common_filters()) \ .join(db.books_series_link).join(db.Books).filter(calibre_db.common_filters()) \
.group_by(func.upper(func.substr(db.Series.sort, 1, 1))).all() .group_by(func.upper(func.substr(db.Series.sort, 1, 1))).all()
return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=charlist, return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=charlist,
title=_(u"Series"), page="serieslist", data="series") title=_(u"Series"), page="serieslist", data="series")
else: else:
entries = calibre_db.session.query(db.Books, func.count('books_series_link').label('count')) \ entries = calibre_db.session.query(db.Books, func.count('books_series_link').label('count')) \
.join(db.books_series_link).join(db.Series).filter(common_filters()) \ .join(db.books_series_link).join(db.Series).filter(calibre_db.common_filters()) \
.group_by(text('books_series_link.series')).order_by(db.Series.sort).all() .group_by(text('books_series_link.series')).order_by(db.Series.sort).all()
charlist = calibre_db.session.query(func.upper(func.substr(db.Series.sort, 1, 1)).label('char')) \ charlist = calibre_db.session.query(func.upper(func.substr(db.Series.sort, 1, 1)).label('char')) \
.join(db.books_series_link).join(db.Books).filter(common_filters()) \ .join(db.books_series_link).join(db.Books).filter(calibre_db.common_filters()) \
.group_by(func.upper(func.substr(db.Series.sort, 1, 1))).all() .group_by(func.upper(func.substr(db.Series.sort, 1, 1))).all()
return render_title_template('grid.html', entries=entries, folder='web.books_list', charlist=charlist, return render_title_template('grid.html', entries=entries, folder='web.books_list', charlist=charlist,
@ -889,7 +904,7 @@ def ratings_list():
if current_user.check_visibility(constants.SIDEBAR_RATING): if current_user.check_visibility(constants.SIDEBAR_RATING):
entries = calibre_db.session.query(db.Ratings, func.count('books_ratings_link.book').label('count'), entries = calibre_db.session.query(db.Ratings, func.count('books_ratings_link.book').label('count'),
(db.Ratings.rating / 2).label('name')) \ (db.Ratings.rating / 2).label('name')) \
.join(db.books_ratings_link).join(db.Books).filter(common_filters()) \ .join(db.books_ratings_link).join(db.Books).filter(calibre_db.common_filters()) \
.group_by(text('books_ratings_link.rating')).order_by(db.Ratings.rating).all() .group_by(text('books_ratings_link.rating')).order_by(db.Ratings.rating).all()
return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=list(), return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=list(),
title=_(u"Ratings list"), page="ratingslist", data="ratings") title=_(u"Ratings list"), page="ratingslist", data="ratings")
@ -901,8 +916,10 @@ def ratings_list():
@login_required_if_no_ano @login_required_if_no_ano
def formats_list(): def formats_list():
if current_user.check_visibility(constants.SIDEBAR_FORMAT): if current_user.check_visibility(constants.SIDEBAR_FORMAT):
entries = calibre_db.session.query(db.Data, func.count('data.book').label('count'), db.Data.format.label('format')) \ entries = calibre_db.session.query(db.Data,
.join(db.Books).filter(common_filters()) \ func.count('data.book').label('count'),
db.Data.format.label('format')) \
.join(db.Books).filter(calibre_db.common_filters()) \
.group_by(db.Data.format).order_by(db.Data.format).all() .group_by(db.Data.format).order_by(db.Data.format).all()
return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=list(), return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=list(),
title=_(u"File formats list"), page="formatslist", data="formats") title=_(u"File formats list"), page="formatslist", data="formats")
@ -916,7 +933,7 @@ def language_overview():
if current_user.check_visibility(constants.SIDEBAR_LANGUAGE): if current_user.check_visibility(constants.SIDEBAR_LANGUAGE):
charlist = list() charlist = list()
if current_user.filter_language() == u"all": if current_user.filter_language() == u"all":
languages = speaking_language() languages = calibre_db.speaking_language()
# ToDo: generate first character list for languages # ToDo: generate first character list for languages
else: else:
try: try:
@ -944,10 +961,10 @@ def language_overview():
def category_list(): def category_list():
if current_user.check_visibility(constants.SIDEBAR_CATEGORY): if current_user.check_visibility(constants.SIDEBAR_CATEGORY):
entries = calibre_db.session.query(db.Tags, func.count('books_tags_link.book').label('count')) \ entries = calibre_db.session.query(db.Tags, func.count('books_tags_link.book').label('count')) \
.join(db.books_tags_link).join(db.Books).order_by(db.Tags.name).filter(common_filters()) \ .join(db.books_tags_link).join(db.Books).order_by(db.Tags.name).filter(calibre_db.common_filters()) \
.group_by(text('books_tags_link.tag')).all() .group_by(text('books_tags_link.tag')).all()
charlist = calibre_db.session.query(func.upper(func.substr(db.Tags.name, 1, 1)).label('char')) \ charlist = calibre_db.session.query(func.upper(func.substr(db.Tags.name, 1, 1)).label('char')) \
.join(db.books_tags_link).join(db.Books).filter(common_filters()) \ .join(db.books_tags_link).join(db.Books).filter(calibre_db.common_filters()) \
.group_by(func.upper(func.substr(db.Tags.name, 1, 1))).all() .group_by(func.upper(func.substr(db.Tags.name, 1, 1))).all()
return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=charlist, return render_title_template('list.html', entries=entries, folder='web.books_list', charlist=charlist,
title=_(u"Categories"), page="catlist", data="category") title=_(u"Categories"), page="catlist", data="category")
@ -980,8 +997,7 @@ def reconnect():
def search(): def search():
term = request.args.get("query") term = request.args.get("query")
if term: if term:
term.strip().lower() entries = calibre_db.get_search_results(term)
entries = get_search_results(term)
ids = list() ids = list()
for element in entries: for element in entries:
ids.append(element.id) ids.append(element.id)
@ -1004,8 +1020,8 @@ def search():
def advanced_search(): def advanced_search():
# Build custom columns names # Build custom columns names
cc = get_cc_columns() cc = get_cc_columns()
calibre_db.session.connection().connection.connection.create_function("lower", 1, lcase) calibre_db.session.connection().connection.connection.create_function("lower", 1, calibre_db.lcase)
q = calibre_db.session.query(db.Books).filter(common_filters()).order_by(db.Books.sort) q = calibre_db.session.query(db.Books).filter(calibre_db.common_filters()).order_by(db.Books.sort)
include_tag_inputs = request.args.getlist('include_tag') include_tag_inputs = request.args.getlist('include_tag')
exclude_tag_inputs = request.args.getlist('exclude_tag') exclude_tag_inputs = request.args.getlist('exclude_tag')
@ -1064,7 +1080,7 @@ def advanced_search():
searchterm.extend(serie.name for serie in serie_names) searchterm.extend(serie.name for serie in serie_names)
language_names = calibre_db.session.query(db.Languages).filter(db.Languages.id.in_(include_languages_inputs)).all() language_names = calibre_db.session.query(db.Languages).filter(db.Languages.id.in_(include_languages_inputs)).all()
if language_names: if language_names:
language_names = speaking_language(language_names) language_names = calibre_db.speaking_language(language_names)
searchterm.extend(language.name for language in language_names) searchterm.extend(language.name for language in language_names)
if rating_high: if rating_high:
searchterm.extend([_(u"Rating <= %(rating)s", rating=rating_high)]) searchterm.extend([_(u"Rating <= %(rating)s", rating=rating_high)])
@ -1137,15 +1153,15 @@ def advanced_search():
return render_title_template('search.html', adv_searchterm=searchterm, return render_title_template('search.html', adv_searchterm=searchterm,
entries=q, title=_(u"search"), page="search") entries=q, title=_(u"search"), page="search")
# prepare data for search-form # prepare data for search-form
tags = calibre_db.session.query(db.Tags).join(db.books_tags_link).join(db.Books).filter(common_filters()) \ tags = calibre_db.session.query(db.Tags).join(db.books_tags_link).join(db.Books).filter(calibre_db.common_filters()) \
.group_by(text('books_tags_link.tag')).order_by(db.Tags.name).all() .group_by(text('books_tags_link.tag')).order_by(db.Tags.name).all()
series = calibre_db.session.query(db.Series).join(db.books_series_link).join(db.Books).filter(common_filters()) \ series = calibre_db.session.query(db.Series).join(db.books_series_link).join(db.Books).filter(calibre_db.common_filters()) \
.group_by(text('books_series_link.series')).order_by(db.Series.name).filter(common_filters()).all() .group_by(text('books_series_link.series')).order_by(db.Series.name).filter(calibre_db.common_filters()).all()
extensions = calibre_db.session.query(db.Data).join(db.Books).filter(common_filters()) \ extensions = calibre_db.session.query(db.Data).join(db.Books).filter(calibre_db.common_filters()) \
.group_by(db.Data.format).order_by(db.Data.format).all() .group_by(db.Data.format).order_by(db.Data.format).all()
if current_user.filter_language() == u"all": if current_user.filter_language() == u"all":
languages = speaking_language() languages = calibre_db.speaking_language()
else: else:
languages = None languages = None
return render_title_template('search_form.html', tags=tags, languages=languages, extensions=extensions, return render_title_template('search_form.html', tags=tags, languages=languages, extensions=extensions,
@ -1160,7 +1176,8 @@ def render_read_books(page, are_read, as_xml=False, order=None, *args, **kwargs)
ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED) ub.ReadBook.read_status == ub.ReadBook.STATUS_FINISHED)
else: else:
db_filter = coalesce(ub.ReadBook.read_status, 0) != ub.ReadBook.STATUS_FINISHED db_filter = coalesce(ub.ReadBook.read_status, 0) != ub.ReadBook.STATUS_FINISHED
entries, random, pagination = fill_indexpage(page, db.Books, entries, random, pagination = calibre_db.fill_indexpage(page,
db.Books,
db_filter, db_filter,
order, order,
ub.ReadBook, db.Books.id==ub.ReadBook.book_id) ub.ReadBook, db.Books.id==ub.ReadBook.book_id)
@ -1170,7 +1187,8 @@ def render_read_books(page, are_read, as_xml=False, order=None, *args, **kwargs)
db_filter = db.cc_classes[config.config_read_column].value == True db_filter = db.cc_classes[config.config_read_column].value == True
else: else:
db_filter = coalesce(db.cc_classes[config.config_read_column].value, False) != True db_filter = coalesce(db.cc_classes[config.config_read_column].value, False) != True
entries, random, pagination = fill_indexpage(page, db.Books, entries, random, pagination = calibre_db.fill_indexpage(page,
db.Books,
db_filter, db_filter,
order, order,
db.cc_classes[config.config_read_column]) db.cc_classes[config.config_read_column])
@ -1207,7 +1225,10 @@ def render_archived_books(page, order):
archived_filter = db.Books.id.in_(archived_book_ids) archived_filter = db.Books.id.in_(archived_book_ids)
entries, random, pagination = fill_indexpage_with_archived_books(page, db.Books, archived_filter, order, entries, random, pagination = calibre_db.fill_indexpage_with_archived_books(page,
db.Books,
archived_filter,
order,
allow_show_archived=True) allow_show_archived=True)
name = _(u'Archived Books') + ' (' + str(len(archived_book_ids)) + ')' name = _(u'Archived Books') + ' (' + str(len(archived_book_ids)) + ')'
@ -1230,9 +1251,8 @@ def get_cover(book_id):
@viewer_required @viewer_required
def serve_book(book_id, book_format, anyname): def serve_book(book_id, book_format, anyname):
book_format = book_format.split(".")[0] book_format = book_format.split(".")[0]
book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first() book = calibre_db.get_book(book_id)
data = calibre_db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper()) \ data = calibre_db.get_book_format(book.id, book_format.upper())
.first()
log.info('Serving book: %s', data.name) log.info('Serving book: %s', data.name)
if config.config_use_google_drive: if config.config_use_google_drive:
headers = Headers() headers = Headers()
@ -1514,7 +1534,7 @@ def token_verified():
@login_required @login_required
def profile(): def profile():
downloads = list() downloads = list()
languages = speaking_language() languages = calibre_db.speaking_language()
translations = babel.list_translations() + [LC('en')] translations = babel.list_translations() + [LC('en')]
kobo_support = feature_support['kobo'] and config.config_kobo_sync kobo_support = feature_support['kobo'] and config.config_kobo_sync
if feature_support['oauth']: if feature_support['oauth']:
@ -1523,9 +1543,9 @@ def profile():
oauth_status = None oauth_status = None
for book in current_user.downloads: for book in current_user.downloads:
downloadBook = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).first() downloadBook = calibre_db.get_book(book.book_id)
if downloadBook: if downloadBook:
downloads.append(calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).first()) downloads.append(downloadBook)
else: else:
ub.delete_download(book.book_id) ub.delete_download(book.book_id)
if request.method == "POST": if request.method == "POST":
@ -1604,7 +1624,7 @@ def profile():
@login_required_if_no_ano @login_required_if_no_ano
@viewer_required @viewer_required
def read_book(book_id, book_format): def read_book(book_id, book_format):
book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first() book = calibre_db.get_filtered_book(book_id)
if not book: if not book:
flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error") flash(_(u"Error opening eBook. File does not exist or file is not accessible:"), category="error")
log.debug(u"Error opening eBook. File does not exist or file is not accessible:") log.debug(u"Error opening eBook. File does not exist or file is not accessible:")
@ -1628,7 +1648,7 @@ def read_book(book_id, book_format):
else: else:
for fileExt in constants.EXTENSIONS_AUDIO: for fileExt in constants.EXTENSIONS_AUDIO:
if book_format.lower() == fileExt: if book_format.lower() == fileExt:
entries = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first() entries = calibre_db.get_filtered_book(book_id)
log.debug(u"Start mp3 listening for %d", book_id) log.debug(u"Start mp3 listening for %d", book_id)
return render_title_template('listenmp3.html', mp3file=book_id, audioformat=book_format.lower(), return render_title_template('listenmp3.html', mp3file=book_id, audioformat=book_format.lower(),
title=_(u"Read a Book"), entry=entries, bookmark=bookmark) title=_(u"Read a Book"), entry=entries, bookmark=bookmark)
@ -1654,8 +1674,7 @@ def read_book(book_id, book_format):
@web.route("/book/<int:book_id>") @web.route("/book/<int:book_id>")
@login_required_if_no_ano @login_required_if_no_ano
def show_book(book_id): def show_book(book_id):
entries = calibre_db.session.query(db.Books).filter(and_(db.Books.id == book_id, entries = calibre_db.get_filtered_book(book_id, allow_show_archived=True)
common_filters(allow_show_archived=True))).first()
if entries: if entries:
for index in range(0, len(entries.languages)): for index in range(0, len(entries.languages)):
try: try:

@ -291,7 +291,7 @@ class WorkerThread(threading.Thread):
w_session = Session() w_session = Session()
engine.execute("attach database '{}' as calibre;".format(dbpath))''' engine.execute("attach database '{}' as calibre;".format(dbpath))'''
file_path = self.queue[index]['file_path'] file_path = self.queue[index]['file_path']
bookid = self.queue[index]['bookid'] book_id = self.queue[index]['bookid']
format_old_ext = u'.' + self.queue[index]['settings']['old_book_format'].lower() format_old_ext = u'.' + self.queue[index]['settings']['old_book_format'].lower()
format_new_ext = u'.' + self.queue[index]['settings']['new_book_format'].lower() format_new_ext = u'.' + self.queue[index]['settings']['new_book_format'].lower()
@ -299,15 +299,15 @@ class WorkerThread(threading.Thread):
# if it does - mark the conversion task as complete and return a success # if it does - mark the conversion task as complete and return a success
# this will allow send to kindle workflow to continue to work # this will allow send to kindle workflow to continue to work
if os.path.isfile(file_path + format_new_ext): if os.path.isfile(file_path + format_new_ext):
log.info("Book id %d already converted to %s", bookid, format_new_ext) log.info("Book id %d already converted to %s", book_id, format_new_ext)
cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == bookid).first() cur_book = calibre_db.get_book(book_id)
self.queue[index]['path'] = file_path self.queue[index]['path'] = file_path
self.queue[index]['title'] = cur_book.title self.queue[index]['title'] = cur_book.title
self._handleSuccess() self._handleSuccess()
return file_path + format_new_ext return file_path + format_new_ext
else: else:
log.info("Book id %d - target format of %s does not exist. Moving forward with convert.", log.info("Book id %d - target format of %s does not exist. Moving forward with convert.",
bookid, book_id,
format_new_ext) format_new_ext)
if config.config_kepubifypath and format_old_ext == '.epub' and format_new_ext == '.kepub': if config.config_kepubifypath and format_old_ext == '.epub' and format_new_ext == '.kepub':
@ -324,13 +324,13 @@ class WorkerThread(threading.Thread):
check, error_message = self._convert_calibre(file_path, format_old_ext, format_new_ext, index) check, error_message = self._convert_calibre(file_path, format_old_ext, format_new_ext, index)
if check == 0: if check == 0:
cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == bookid).first() cur_book = calibre_db.get_book(book_id)
if os.path.isfile(file_path + format_new_ext): if os.path.isfile(file_path + format_new_ext):
# self.db_queue.join() # self.db_queue.join()
new_format = db.Data(name=cur_book.data[0].name, new_format = db.Data(name=cur_book.data[0].name,
book_format=self.queue[index]['settings']['new_book_format'].upper(), book_format=self.queue[index]['settings']['new_book_format'].upper(),
book=bookid, uncompressed_size=os.path.getsize(file_path + format_new_ext)) book=book_id, uncompressed_size=os.path.getsize(file_path + format_new_ext))
task = {'task':'add_format','id': bookid, 'format': new_format} task = {'task':'add_format','id': book_id, 'format': new_format}
self.db_queue.put(task) self.db_queue.put(task)
# To Do how to handle error? # To Do how to handle error?

Loading…
Cancel
Save