mirror of
				https://github.com/janeczku/calibre-web
				synced 2025-11-04 09:13:02 +00:00 
			
		
		
		
	Fix for #1407 converting books should now be possible again
This commit is contained in:
		@@ -37,6 +37,9 @@ from . import config_sql, logger, cache_buster, cli, ub, db
 | 
			
		||||
from .reverseproxy import ReverseProxied
 | 
			
		||||
from .server import WebServer
 | 
			
		||||
 | 
			
		||||
# import queue
 | 
			
		||||
# queue = queue.Queue()
 | 
			
		||||
 | 
			
		||||
mimetypes.init()
 | 
			
		||||
mimetypes.add_type('application/xhtml+xml', '.xhtml')
 | 
			
		||||
mimetypes.add_type('application/epub+zip', '.epub')
 | 
			
		||||
@@ -82,6 +85,8 @@ log = logger.create()
 | 
			
		||||
 | 
			
		||||
from . import services
 | 
			
		||||
 | 
			
		||||
calibre_db = db.CalibreDB()
 | 
			
		||||
 | 
			
		||||
def create_app():
 | 
			
		||||
    app.wsgi_app = ReverseProxied(app.wsgi_app)
 | 
			
		||||
    # For python2 convert path to unicode
 | 
			
		||||
@@ -98,7 +103,8 @@ def create_app():
 | 
			
		||||
    app.secret_key = os.getenv('SECRET_KEY', config_sql.get_flask_session_key(ub.session))
 | 
			
		||||
 | 
			
		||||
    web_server.init_app(app, config)
 | 
			
		||||
    db.setup_db(config, cli.settingspath)
 | 
			
		||||
    calibre_db.setup_db(config, cli.settingspath)
 | 
			
		||||
    calibre_db.start()
 | 
			
		||||
 | 
			
		||||
    babel.init_app(app)
 | 
			
		||||
    _BABEL_TRANSLATIONS.update(str(item) for item in babel.list_translations())
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								cps/about.py
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								cps/about.py
									
									
									
									
									
								
							@@ -30,7 +30,7 @@ import babel, pytz, requests, sqlalchemy
 | 
			
		||||
import werkzeug, flask, flask_login, flask_principal, jinja2
 | 
			
		||||
from flask_babel import gettext as _
 | 
			
		||||
 | 
			
		||||
from . import db, converter, uploader, server, isoLanguages, constants
 | 
			
		||||
from . import db, calibre_db, converter, uploader, server, isoLanguages, constants
 | 
			
		||||
from .web import render_title_template
 | 
			
		||||
try:
 | 
			
		||||
    from flask_login import __version__ as flask_loginVersion
 | 
			
		||||
@@ -85,10 +85,10 @@ _VERSIONS.update(uploader.get_versions())
 | 
			
		||||
@about.route("/stats")
 | 
			
		||||
@flask_login.login_required
 | 
			
		||||
def stats():
 | 
			
		||||
    counter = db.session.query(db.Books).count()
 | 
			
		||||
    authors = db.session.query(db.Authors).count()
 | 
			
		||||
    categorys = db.session.query(db.Tags).count()
 | 
			
		||||
    series = db.session.query(db.Series).count()
 | 
			
		||||
    counter = calibre_db.session.query(db.Books).count()
 | 
			
		||||
    authors = calibre_db.session.query(db.Authors).count()
 | 
			
		||||
    categorys = calibre_db.session.query(db.Tags).count()
 | 
			
		||||
    series = calibre_db.session.query(db.Series).count()
 | 
			
		||||
    _VERSIONS['ebook converter'] = _(converter.get_calibre_version())
 | 
			
		||||
    _VERSIONS['unrar'] = _(converter.get_unrar_version())
 | 
			
		||||
    _VERSIONS['kepubify'] = _(converter.get_kepubify_version())
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								cps/admin.py
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								cps/admin.py
									
									
									
									
									
								
							@@ -38,7 +38,7 @@ from sqlalchemy.exc import IntegrityError
 | 
			
		||||
from sqlalchemy.sql.expression import func
 | 
			
		||||
 | 
			
		||||
from . import constants, logger, helper, services
 | 
			
		||||
from . import 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 .gdriveutils import is_gdrive_ready, gdrive_support
 | 
			
		||||
from .web import admin_required, render_title_template, before_request, unconfigured, login_required_if_no_ano
 | 
			
		||||
@@ -86,7 +86,7 @@ def shutdown():
 | 
			
		||||
    showtext = {}
 | 
			
		||||
    if task in (0, 1):  # valid commandos received
 | 
			
		||||
        # close all database connections
 | 
			
		||||
        db.dispose()
 | 
			
		||||
        calibre_db.dispose()
 | 
			
		||||
        ub.dispose()
 | 
			
		||||
 | 
			
		||||
        if task == 0:
 | 
			
		||||
@@ -99,7 +99,7 @@ def shutdown():
 | 
			
		||||
 | 
			
		||||
    if task == 2:
 | 
			
		||||
        log.warning("reconnecting to calibre database")
 | 
			
		||||
        db.setup_db(config, ub.app_DB_path)
 | 
			
		||||
        calibre_db.setup_db(config, ub.app_DB_path)
 | 
			
		||||
        showtext['text'] = _(u'Reconnect successful')
 | 
			
		||||
        return json.dumps(showtext)
 | 
			
		||||
 | 
			
		||||
@@ -148,9 +148,9 @@ def configuration():
 | 
			
		||||
@login_required
 | 
			
		||||
@admin_required
 | 
			
		||||
def view_configuration():
 | 
			
		||||
    readColumn = db.session.query(db.Custom_Columns)\
 | 
			
		||||
    readColumn = calibre_db.session.query(db.Custom_Columns)\
 | 
			
		||||
            .filter(and_(db.Custom_Columns.datatype == 'bool',db.Custom_Columns.mark_for_delete == 0)).all()
 | 
			
		||||
    restrictColumns= db.session.query(db.Custom_Columns)\
 | 
			
		||||
    restrictColumns= calibre_db.session.query(db.Custom_Columns)\
 | 
			
		||||
            .filter(and_(db.Custom_Columns.datatype == 'text',db.Custom_Columns.mark_for_delete == 0)).all()
 | 
			
		||||
    return render_title_template("config_view_edit.html", conf=config, readColumns=readColumn,
 | 
			
		||||
                                 restrictColumns=restrictColumns,
 | 
			
		||||
@@ -944,7 +944,7 @@ def edit_user(user_id):
 | 
			
		||||
    translations = babel.list_translations() + [LC('en')]
 | 
			
		||||
    kobo_support = feature_support['kobo'] and config.config_kobo_sync
 | 
			
		||||
    for book in content.downloads:
 | 
			
		||||
        downloadbook = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
 | 
			
		||||
        downloadbook = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
 | 
			
		||||
        if downloadbook:
 | 
			
		||||
            downloads.append(downloadbook)
 | 
			
		||||
        else:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										283
									
								
								cps/db.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										283
									
								
								cps/db.py
									
									
									
									
									
										
										
										Executable file → Normal file
									
								
							@@ -23,18 +23,22 @@ import os
 | 
			
		||||
import re
 | 
			
		||||
import ast
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
import threading
 | 
			
		||||
import time
 | 
			
		||||
import queue
 | 
			
		||||
 | 
			
		||||
from sqlalchemy import create_engine, event
 | 
			
		||||
from sqlalchemy import create_engine
 | 
			
		||||
from sqlalchemy import Table, Column, ForeignKey, CheckConstraint
 | 
			
		||||
from sqlalchemy import String, Integer, Boolean, TIMESTAMP, Float
 | 
			
		||||
from sqlalchemy.orm import relationship, sessionmaker, scoped_session
 | 
			
		||||
from sqlalchemy.ext.declarative import declarative_base
 | 
			
		||||
from sqlalchemy.exc import OperationalError
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
session = None
 | 
			
		||||
from . import logger
 | 
			
		||||
# session = None
 | 
			
		||||
cc_exceptions = ['datetime', 'comments', 'composite', 'series']
 | 
			
		||||
cc_classes = {}
 | 
			
		||||
engine = None
 | 
			
		||||
# engine = None
 | 
			
		||||
 | 
			
		||||
Base = declarative_base()
 | 
			
		||||
 | 
			
		||||
@@ -226,6 +230,7 @@ class Publishers(Base):
 | 
			
		||||
 | 
			
		||||
class Data(Base):
 | 
			
		||||
    __tablename__ = 'data'
 | 
			
		||||
    __table_args__ = {'schema':'calibre'}
 | 
			
		||||
 | 
			
		||||
    id = Column(Integer, primary_key=True)
 | 
			
		||||
    book = Column(Integer, ForeignKey('books.id'), nullable=False)
 | 
			
		||||
@@ -314,136 +319,170 @@ class Custom_Columns(Base):
 | 
			
		||||
        return display_dict
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def update_title_sort(config, conn=None):
 | 
			
		||||
    # user defined sort function for calibre databases (Series, etc.)
 | 
			
		||||
    def _title_sort(title):
 | 
			
		||||
        # calibre sort stuff
 | 
			
		||||
        title_pat = re.compile(config.config_title_regex, re.IGNORECASE)
 | 
			
		||||
        match = title_pat.search(title)
 | 
			
		||||
        if match:
 | 
			
		||||
            prep = match.group(1)
 | 
			
		||||
            title = title.replace(prep, '') + ', ' + prep
 | 
			
		||||
        return title.strip()
 | 
			
		||||
class CalibreDB(threading.Thread):
 | 
			
		||||
 | 
			
		||||
    conn = conn or session.connection().connection.connection
 | 
			
		||||
    conn.create_function("title_sort", 1, _title_sort)
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        threading.Thread.__init__(self)
 | 
			
		||||
        self.engine = None
 | 
			
		||||
        self.session = None
 | 
			
		||||
        self.queue = None
 | 
			
		||||
        self.log = None
 | 
			
		||||
 | 
			
		||||
    def add_queue(self,queue):
 | 
			
		||||
        self.queue = queue
 | 
			
		||||
        self.log = logger.create()
 | 
			
		||||
 | 
			
		||||
    def run(self):
 | 
			
		||||
        while True:
 | 
			
		||||
            i = self.queue.get()
 | 
			
		||||
            if i == 'dummy':
 | 
			
		||||
                self.queue.task_done()
 | 
			
		||||
                break
 | 
			
		||||
            if i['task'] == 'add_format':
 | 
			
		||||
                cur_book = self.session.query(Books).filter(Books.id == i['id']).first()
 | 
			
		||||
                cur_book.data.append(i['format'])
 | 
			
		||||
                try:
 | 
			
		||||
                    # db.session.merge(cur_book)
 | 
			
		||||
                    self.session.commit()
 | 
			
		||||
                except OperationalError as e:
 | 
			
		||||
                    self.session.rollback()
 | 
			
		||||
                    self.log.error("Database error: %s", e)
 | 
			
		||||
                    # self._handleError(_(u"Database error: %(error)s.", error=e))
 | 
			
		||||
                    # return
 | 
			
		||||
            self.queue.task_done()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def setup_db(config, app_db_path):
 | 
			
		||||
    dispose()
 | 
			
		||||
    global engine
 | 
			
		||||
    def stop(self):
 | 
			
		||||
        self.queue.put('dummy')
 | 
			
		||||
 | 
			
		||||
    if not config.config_calibre_dir:
 | 
			
		||||
        config.invalidate()
 | 
			
		||||
        return False
 | 
			
		||||
    def setup_db(self, config, app_db_path):
 | 
			
		||||
        self.dispose()
 | 
			
		||||
        # global engine
 | 
			
		||||
 | 
			
		||||
    dbpath = os.path.join(config.config_calibre_dir, "metadata.db")
 | 
			
		||||
    if not os.path.exists(dbpath):
 | 
			
		||||
        config.invalidate()
 | 
			
		||||
        return False
 | 
			
		||||
        if not config.config_calibre_dir:
 | 
			
		||||
            config.invalidate()
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        #engine = create_engine('sqlite:///{0}'.format(dbpath),
 | 
			
		||||
        engine = create_engine('sqlite://',
 | 
			
		||||
                               echo=False,
 | 
			
		||||
                               isolation_level="SERIALIZABLE",
 | 
			
		||||
                               connect_args={'check_same_thread': False})
 | 
			
		||||
        engine.execute("attach database '{}' as calibre;".format(dbpath))
 | 
			
		||||
        engine.execute("attach database '{}' as app_settings;".format(app_db_path))
 | 
			
		||||
        dbpath = os.path.join(config.config_calibre_dir, "metadata.db")
 | 
			
		||||
        if not os.path.exists(dbpath):
 | 
			
		||||
            config.invalidate()
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
        conn = engine.connect()
 | 
			
		||||
        # conn.text_factory = lambda b: b.decode(errors = 'ignore') possible fix for #1302
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        config.invalidate(e)
 | 
			
		||||
        return False
 | 
			
		||||
        try:
 | 
			
		||||
            #engine = create_engine('sqlite:///{0}'.format(dbpath),
 | 
			
		||||
            self.engine = create_engine('sqlite://',
 | 
			
		||||
                                   echo=False,
 | 
			
		||||
                                   isolation_level="SERIALIZABLE",
 | 
			
		||||
                                   connect_args={'check_same_thread': False})
 | 
			
		||||
            self.engine.execute("attach database '{}' as calibre;".format(dbpath))
 | 
			
		||||
            self.engine.execute("attach database '{}' as app_settings;".format(app_db_path))
 | 
			
		||||
 | 
			
		||||
    config.db_configured = True
 | 
			
		||||
    update_title_sort(config, conn.connection)
 | 
			
		||||
            conn = self.engine.connect()
 | 
			
		||||
            # conn.text_factory = lambda b: b.decode(errors = 'ignore') possible fix for #1302
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            config.invalidate(e)
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    if not cc_classes:
 | 
			
		||||
        cc = conn.execute("SELECT id, datatype FROM custom_columns")
 | 
			
		||||
        config.db_configured = True
 | 
			
		||||
        self.update_title_sort(config, conn.connection)
 | 
			
		||||
 | 
			
		||||
        cc_ids = []
 | 
			
		||||
        books_custom_column_links = {}
 | 
			
		||||
        for row in cc:
 | 
			
		||||
            if row.datatype not in cc_exceptions:
 | 
			
		||||
                books_custom_column_links[row.id] = Table('books_custom_column_' + str(row.id) + '_link', Base.metadata,
 | 
			
		||||
                                                          Column('book', Integer, ForeignKey('books.id'),
 | 
			
		||||
                                                                 primary_key=True),
 | 
			
		||||
                                                          Column('value', Integer,
 | 
			
		||||
                                                                 ForeignKey('custom_column_' + str(row.id) + '.id'),
 | 
			
		||||
                                                                 primary_key=True)
 | 
			
		||||
                                                          )
 | 
			
		||||
                cc_ids.append([row.id, row.datatype])
 | 
			
		||||
                if row.datatype == 'bool':
 | 
			
		||||
                    ccdict = {'__tablename__': 'custom_column_' + str(row.id),
 | 
			
		||||
                              'id': Column(Integer, primary_key=True),
 | 
			
		||||
                              'book': Column(Integer, ForeignKey('books.id')),
 | 
			
		||||
                              'value': Column(Boolean)}
 | 
			
		||||
                elif row.datatype == 'int':
 | 
			
		||||
                    ccdict = {'__tablename__': 'custom_column_' + str(row.id),
 | 
			
		||||
                              'id': Column(Integer, primary_key=True),
 | 
			
		||||
                              'book': Column(Integer, ForeignKey('books.id')),
 | 
			
		||||
                              'value': Column(Integer)}
 | 
			
		||||
                elif row.datatype == 'float':
 | 
			
		||||
                    ccdict = {'__tablename__': 'custom_column_' + str(row.id),
 | 
			
		||||
                              'id': Column(Integer, primary_key=True),
 | 
			
		||||
                              'book': Column(Integer, ForeignKey('books.id')),
 | 
			
		||||
                              'value': Column(Float)}
 | 
			
		||||
        if not cc_classes:
 | 
			
		||||
            cc = conn.execute("SELECT id, datatype FROM custom_columns")
 | 
			
		||||
 | 
			
		||||
            cc_ids = []
 | 
			
		||||
            books_custom_column_links = {}
 | 
			
		||||
            for row in cc:
 | 
			
		||||
                if row.datatype not in cc_exceptions:
 | 
			
		||||
                    books_custom_column_links[row.id] = Table('books_custom_column_' + str(row.id) + '_link', Base.metadata,
 | 
			
		||||
                                                              Column('book', Integer, ForeignKey('books.id'),
 | 
			
		||||
                                                                     primary_key=True),
 | 
			
		||||
                                                              Column('value', Integer,
 | 
			
		||||
                                                                     ForeignKey('custom_column_' + str(row.id) + '.id'),
 | 
			
		||||
                                                                     primary_key=True)
 | 
			
		||||
                                                              )
 | 
			
		||||
                    cc_ids.append([row.id, row.datatype])
 | 
			
		||||
                    if row.datatype == 'bool':
 | 
			
		||||
                        ccdict = {'__tablename__': 'custom_column_' + str(row.id),
 | 
			
		||||
                                  'id': Column(Integer, primary_key=True),
 | 
			
		||||
                                  'book': Column(Integer, ForeignKey('books.id')),
 | 
			
		||||
                                  'value': Column(Boolean)}
 | 
			
		||||
                    elif row.datatype == 'int':
 | 
			
		||||
                        ccdict = {'__tablename__': 'custom_column_' + str(row.id),
 | 
			
		||||
                                  'id': Column(Integer, primary_key=True),
 | 
			
		||||
                                  'book': Column(Integer, ForeignKey('books.id')),
 | 
			
		||||
                                  'value': Column(Integer)}
 | 
			
		||||
                    elif row.datatype == 'float':
 | 
			
		||||
                        ccdict = {'__tablename__': 'custom_column_' + str(row.id),
 | 
			
		||||
                                  'id': Column(Integer, primary_key=True),
 | 
			
		||||
                                  'book': Column(Integer, ForeignKey('books.id')),
 | 
			
		||||
                                  'value': Column(Float)}
 | 
			
		||||
                    else:
 | 
			
		||||
                        ccdict = {'__tablename__': 'custom_column_' + str(row.id),
 | 
			
		||||
                                  'id': Column(Integer, primary_key=True),
 | 
			
		||||
                                  'value': Column(String)}
 | 
			
		||||
                    cc_classes[row.id] = type(str('Custom_Column_' + str(row.id)), (Base,), ccdict)
 | 
			
		||||
 | 
			
		||||
            for cc_id in cc_ids:
 | 
			
		||||
                if (cc_id[1] == 'bool') or (cc_id[1] == 'int') or (cc_id[1] == 'float'):
 | 
			
		||||
                    setattr(Books, 'custom_column_' + str(cc_id[0]), relationship(cc_classes[cc_id[0]],
 | 
			
		||||
                                                                               primaryjoin=(
 | 
			
		||||
                                                                               Books.id == cc_classes[cc_id[0]].book),
 | 
			
		||||
                                                                               backref='books'))
 | 
			
		||||
                else:
 | 
			
		||||
                    ccdict = {'__tablename__': 'custom_column_' + str(row.id),
 | 
			
		||||
                              'id': Column(Integer, primary_key=True),
 | 
			
		||||
                              'value': Column(String)}
 | 
			
		||||
                cc_classes[row.id] = type(str('Custom_Column_' + str(row.id)), (Base,), ccdict)
 | 
			
		||||
 | 
			
		||||
        for cc_id in cc_ids:
 | 
			
		||||
            if (cc_id[1] == 'bool') or (cc_id[1] == 'int') or (cc_id[1] == 'float'):
 | 
			
		||||
                setattr(Books, 'custom_column_' + str(cc_id[0]), relationship(cc_classes[cc_id[0]],
 | 
			
		||||
                                                                           primaryjoin=(
 | 
			
		||||
                                                                           Books.id == cc_classes[cc_id[0]].book),
 | 
			
		||||
                                                                           backref='books'))
 | 
			
		||||
            else:
 | 
			
		||||
                setattr(Books, 'custom_column_' + str(cc_id[0]), relationship(cc_classes[cc_id[0]],
 | 
			
		||||
                                                                           secondary=books_custom_column_links[cc_id[0]],
 | 
			
		||||
                                                                           backref='books'))
 | 
			
		||||
                    setattr(Books, 'custom_column_' + str(cc_id[0]), relationship(cc_classes[cc_id[0]],
 | 
			
		||||
                                                                               secondary=books_custom_column_links[cc_id[0]],
 | 
			
		||||
                                                                               backref='books'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    global session
 | 
			
		||||
    Session = scoped_session(sessionmaker(autocommit=False,
 | 
			
		||||
                                             autoflush=False,
 | 
			
		||||
                                             bind=engine))
 | 
			
		||||
    session = Session()
 | 
			
		||||
    return True
 | 
			
		||||
        # global session
 | 
			
		||||
        Session = scoped_session(sessionmaker(autocommit=False,
 | 
			
		||||
                                                 autoflush=False,
 | 
			
		||||
                                                 bind=self.engine))
 | 
			
		||||
        self.session = Session()
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def update_title_sort(self, config, conn=None):
 | 
			
		||||
        # user defined sort function for calibre databases (Series, etc.)
 | 
			
		||||
        def _title_sort(title):
 | 
			
		||||
            # calibre sort stuff
 | 
			
		||||
            title_pat = re.compile(config.config_title_regex, re.IGNORECASE)
 | 
			
		||||
            match = title_pat.search(title)
 | 
			
		||||
            if match:
 | 
			
		||||
                prep = match.group(1)
 | 
			
		||||
                title = title.replace(prep, '') + ', ' + prep
 | 
			
		||||
            return title.strip()
 | 
			
		||||
 | 
			
		||||
        conn = conn or self.session.connection().connection.connection
 | 
			
		||||
        conn.create_function("title_sort", 1, _title_sort)
 | 
			
		||||
 | 
			
		||||
    def dispose(self):
 | 
			
		||||
        # global session
 | 
			
		||||
 | 
			
		||||
        old_session = self.session
 | 
			
		||||
        self.session = None
 | 
			
		||||
        if old_session:
 | 
			
		||||
            try: old_session.close()
 | 
			
		||||
            except: pass
 | 
			
		||||
            if old_session.bind:
 | 
			
		||||
                try: old_session.bind.dispose()
 | 
			
		||||
                except Exception: pass
 | 
			
		||||
 | 
			
		||||
        for attr in list(Books.__dict__.keys()):
 | 
			
		||||
            if attr.startswith("custom_column_"):
 | 
			
		||||
                setattr(Books, attr, None)
 | 
			
		||||
 | 
			
		||||
        for db_class in cc_classes.values():
 | 
			
		||||
            Base.metadata.remove(db_class.__table__)
 | 
			
		||||
        cc_classes.clear()
 | 
			
		||||
 | 
			
		||||
        for table in reversed(Base.metadata.sorted_tables):
 | 
			
		||||
            name = table.key
 | 
			
		||||
            if name.startswith("custom_column_") or name.startswith("books_custom_column_"):
 | 
			
		||||
                if table is not None:
 | 
			
		||||
                    Base.metadata.remove(table)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def dispose():
 | 
			
		||||
    global session
 | 
			
		||||
 | 
			
		||||
    old_session = session
 | 
			
		||||
    session = None
 | 
			
		||||
    if old_session:
 | 
			
		||||
        try: old_session.close()
 | 
			
		||||
        except: pass
 | 
			
		||||
        if old_session.bind:
 | 
			
		||||
            try: old_session.bind.dispose()
 | 
			
		||||
            except Exception: pass
 | 
			
		||||
 | 
			
		||||
    for attr in list(Books.__dict__.keys()):
 | 
			
		||||
        if attr.startswith("custom_column_"):
 | 
			
		||||
            setattr(Books, attr, None)
 | 
			
		||||
 | 
			
		||||
    for db_class in cc_classes.values():
 | 
			
		||||
        Base.metadata.remove(db_class.__table__)
 | 
			
		||||
    cc_classes.clear()
 | 
			
		||||
 | 
			
		||||
    for table in reversed(Base.metadata.sorted_tables):
 | 
			
		||||
        name = table.key
 | 
			
		||||
        if name.startswith("custom_column_") or name.startswith("books_custom_column_"):
 | 
			
		||||
            if table is not None:
 | 
			
		||||
                Base.metadata.remove(table)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def reconnect_db(config, app_db_path):
 | 
			
		||||
    session.close()
 | 
			
		||||
    engine.dispose()
 | 
			
		||||
    setup_db(config, app_db_path)
 | 
			
		||||
    def reconnect_db(self, config, app_db_path):
 | 
			
		||||
        self.session.close()
 | 
			
		||||
        self.engine.dispose()
 | 
			
		||||
        self.setup_db(config, app_db_path)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										139
									
								
								cps/editbooks.py
									
									
									
									
									
								
							
							
						
						
									
										139
									
								
								cps/editbooks.py
									
									
									
									
									
								
							@@ -33,7 +33,8 @@ from flask_login import current_user, login_required
 | 
			
		||||
from sqlalchemy.exc import OperationalError
 | 
			
		||||
 | 
			
		||||
from . import constants, logger, isoLanguages, gdriveutils, uploader, helper
 | 
			
		||||
from . import config, get_locale, db, ub, worker
 | 
			
		||||
from . import config, get_locale, ub, worker, 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
 | 
			
		||||
 | 
			
		||||
@@ -175,7 +176,7 @@ def modify_identifiers(input_identifiers, db_identifiers, db_session):
 | 
			
		||||
@login_required
 | 
			
		||||
def delete_book(book_id, book_format):
 | 
			
		||||
    if current_user.role_delete_books():
 | 
			
		||||
        book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
        book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
        if book:
 | 
			
		||||
            try:
 | 
			
		||||
                result, error = helper.delete_book(book, config.config_calibre_dir, book_format=book_format.upper())
 | 
			
		||||
@@ -193,13 +194,13 @@ def delete_book(book_id, book_format):
 | 
			
		||||
 | 
			
		||||
                    # check if only this book links to:
 | 
			
		||||
                    # author, language, series, tags, custom columns
 | 
			
		||||
                    modify_database_object([u''], book.authors, db.Authors, db.session, 'author')
 | 
			
		||||
                    modify_database_object([u''], book.tags, db.Tags, db.session, 'tags')
 | 
			
		||||
                    modify_database_object([u''], book.series, db.Series, db.session, 'series')
 | 
			
		||||
                    modify_database_object([u''], book.languages, db.Languages, db.session, 'languages')
 | 
			
		||||
                    modify_database_object([u''], book.publishers, db.Publishers, db.session, 'publishers')
 | 
			
		||||
                    modify_database_object([u''], book.authors, db.Authors, calibre_db.session, 'author')
 | 
			
		||||
                    modify_database_object([u''], book.tags, db.Tags, calibre_db.session, 'tags')
 | 
			
		||||
                    modify_database_object([u''], book.series, db.Series, calibre_db.session, 'series')
 | 
			
		||||
                    modify_database_object([u''], book.languages, db.Languages, calibre_db.session, 'languages')
 | 
			
		||||
                    modify_database_object([u''], book.publishers, db.Publishers, calibre_db.session, 'publishers')
 | 
			
		||||
 | 
			
		||||
                    cc = db.session.query(db.Custom_Columns).\
 | 
			
		||||
                    cc = calibre_db.session.query(db.Custom_Columns).\
 | 
			
		||||
                        filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
 | 
			
		||||
                    for c in cc:
 | 
			
		||||
                        cc_string = "custom_column_" + str(c.id)
 | 
			
		||||
@@ -209,32 +210,32 @@ def delete_book(book_id, book_format):
 | 
			
		||||
                                    del_cc = getattr(book, cc_string)[0]
 | 
			
		||||
                                    getattr(book, cc_string).remove(del_cc)
 | 
			
		||||
                                    log.debug('remove ' + str(c.id))
 | 
			
		||||
                                    db.session.delete(del_cc)
 | 
			
		||||
                                    db.session.commit()
 | 
			
		||||
                                    calibre_db.session.delete(del_cc)
 | 
			
		||||
                                    calibre_db.session.commit()
 | 
			
		||||
                                elif c.datatype == 'rating':
 | 
			
		||||
                                    del_cc = getattr(book, cc_string)[0]
 | 
			
		||||
                                    getattr(book, cc_string).remove(del_cc)
 | 
			
		||||
                                    if len(del_cc.books) == 0:
 | 
			
		||||
                                        log.debug('remove ' + str(c.id))
 | 
			
		||||
                                        db.session.delete(del_cc)
 | 
			
		||||
                                        db.session.commit()
 | 
			
		||||
                                        calibre_db.session.delete(del_cc)
 | 
			
		||||
                                        calibre_db.session.commit()
 | 
			
		||||
                                else:
 | 
			
		||||
                                    del_cc = getattr(book, cc_string)[0]
 | 
			
		||||
                                    getattr(book, cc_string).remove(del_cc)
 | 
			
		||||
                                    log.debug('remove ' + str(c.id))
 | 
			
		||||
                                    db.session.delete(del_cc)
 | 
			
		||||
                                    db.session.commit()
 | 
			
		||||
                                    calibre_db.session.delete(del_cc)
 | 
			
		||||
                                    calibre_db.session.commit()
 | 
			
		||||
                        else:
 | 
			
		||||
                            modify_database_object([u''], getattr(book, cc_string), db.cc_classes[c.id],
 | 
			
		||||
                                                   db.session, 'custom')
 | 
			
		||||
                    db.session.query(db.Books).filter(db.Books.id == book_id).delete()
 | 
			
		||||
                                                   calibre_db.session, 'custom')
 | 
			
		||||
                    calibre_db.session.query(db.Books).filter(db.Books.id == book_id).delete()
 | 
			
		||||
                else:
 | 
			
		||||
                    db.session.query(db.Data).filter(db.Data.book == book.id).\
 | 
			
		||||
                    calibre_db.session.query(db.Data).filter(db.Data.book == book.id).\
 | 
			
		||||
                        filter(db.Data.format == book_format).delete()
 | 
			
		||||
                db.session.commit()
 | 
			
		||||
                calibre_db.session.commit()
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                log.debug(e)
 | 
			
		||||
                db.session.rollback()
 | 
			
		||||
                calibre_db.session.rollback()
 | 
			
		||||
        else:
 | 
			
		||||
            # book not found
 | 
			
		||||
            log.error('Book with id "%s" could not be deleted: not found', book_id)
 | 
			
		||||
@@ -247,9 +248,9 @@ def delete_book(book_id, book_format):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def render_edit_book(book_id):
 | 
			
		||||
    db.update_title_sort(config)
 | 
			
		||||
    cc = db.session.query(db.Custom_Columns).filter(db.Custom_Columns.datatype.notin_(db.cc_exceptions)).all()
 | 
			
		||||
    book = db.session.query(db.Books)\
 | 
			
		||||
    calibre_db.update_title_sort(config)
 | 
			
		||||
    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)\
 | 
			
		||||
        .filter(db.Books.id == book_id).filter(common_filters()).first()
 | 
			
		||||
 | 
			
		||||
    if not book:
 | 
			
		||||
@@ -304,7 +305,7 @@ def edit_book_ratings(to_save, book):
 | 
			
		||||
        ratingx2 = int(float(to_save["rating"]) * 2)
 | 
			
		||||
        if ratingx2 != old_rating:
 | 
			
		||||
            changed = True
 | 
			
		||||
            is_rating = db.session.query(db.Ratings).filter(db.Ratings.rating == ratingx2).first()
 | 
			
		||||
            is_rating = calibre_db.session.query(db.Ratings).filter(db.Ratings.rating == ratingx2).first()
 | 
			
		||||
            if is_rating:
 | 
			
		||||
                book.ratings.append(is_rating)
 | 
			
		||||
            else:
 | 
			
		||||
@@ -326,7 +327,7 @@ def edit_book_languages(to_save, book):
 | 
			
		||||
    for l in unknown_languages:
 | 
			
		||||
        log.error('%s is not a valid language', l)
 | 
			
		||||
        flash(_(u"%(langname)s is not a valid language", langname=l), category="error")
 | 
			
		||||
    return modify_database_object(list(input_l), book.languages, db.Languages, db.session, 'languages')
 | 
			
		||||
    return modify_database_object(list(input_l), book.languages, db.Languages, calibre_db.session, 'languages')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def edit_book_publisher(to_save, book):
 | 
			
		||||
@@ -334,15 +335,15 @@ def edit_book_publisher(to_save, book):
 | 
			
		||||
    if to_save["publisher"]:
 | 
			
		||||
        publisher = to_save["publisher"].rstrip().strip()
 | 
			
		||||
        if len(book.publishers) == 0 or (len(book.publishers) > 0 and publisher != book.publishers[0].name):
 | 
			
		||||
            changed |= modify_database_object([publisher], book.publishers, db.Publishers, db.session, 'publisher')
 | 
			
		||||
            changed |= modify_database_object([publisher], book.publishers, db.Publishers, calibre_db.session, 'publisher')
 | 
			
		||||
    elif len(book.publishers):
 | 
			
		||||
        changed |= modify_database_object([], book.publishers, db.Publishers, db.session, 'publisher')
 | 
			
		||||
        changed |= modify_database_object([], book.publishers, db.Publishers, calibre_db.session, 'publisher')
 | 
			
		||||
    return changed
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def edit_cc_data(book_id, book, to_save):
 | 
			
		||||
    changed = False
 | 
			
		||||
    cc = 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()
 | 
			
		||||
    for c in cc:
 | 
			
		||||
        cc_string = "custom_column_" + str(c.id)
 | 
			
		||||
        if not c.is_multiple:
 | 
			
		||||
@@ -365,12 +366,12 @@ def edit_cc_data(book_id, book, to_save):
 | 
			
		||||
                            else:
 | 
			
		||||
                                del_cc = getattr(book, cc_string)[0]
 | 
			
		||||
                                getattr(book, cc_string).remove(del_cc)
 | 
			
		||||
                                db.session.delete(del_cc)
 | 
			
		||||
                                calibre_db.session.delete(del_cc)
 | 
			
		||||
                                changed = True
 | 
			
		||||
                        else:
 | 
			
		||||
                            cc_class = db.cc_classes[c.id]
 | 
			
		||||
                            new_cc = cc_class(value=to_save[cc_string], book=book_id)
 | 
			
		||||
                            db.session.add(new_cc)
 | 
			
		||||
                            calibre_db.session.add(new_cc)
 | 
			
		||||
                            changed = True
 | 
			
		||||
 | 
			
		||||
                else:
 | 
			
		||||
@@ -382,18 +383,18 @@ def edit_cc_data(book_id, book, to_save):
 | 
			
		||||
                            del_cc = getattr(book, cc_string)[0]
 | 
			
		||||
                            getattr(book, cc_string).remove(del_cc)
 | 
			
		||||
                            if len(del_cc.books) == 0:
 | 
			
		||||
                                db.session.delete(del_cc)
 | 
			
		||||
                                calibre_db.session.delete(del_cc)
 | 
			
		||||
                                changed = True
 | 
			
		||||
                        cc_class = db.cc_classes[c.id]
 | 
			
		||||
                        new_cc = db.session.query(cc_class).filter(
 | 
			
		||||
                        new_cc = calibre_db.session.query(cc_class).filter(
 | 
			
		||||
                            cc_class.value == to_save[cc_string].strip()).first()
 | 
			
		||||
                        # if no cc val is found add it
 | 
			
		||||
                        if new_cc is None:
 | 
			
		||||
                            new_cc = cc_class(value=to_save[cc_string].strip())
 | 
			
		||||
                            db.session.add(new_cc)
 | 
			
		||||
                            calibre_db.session.add(new_cc)
 | 
			
		||||
                            changed = True
 | 
			
		||||
                            db.session.flush()
 | 
			
		||||
                            new_cc = db.session.query(cc_class).filter(
 | 
			
		||||
                            calibre_db.session.flush()
 | 
			
		||||
                            new_cc = calibre_db.session.query(cc_class).filter(
 | 
			
		||||
                                cc_class.value == to_save[cc_string].strip()).first()
 | 
			
		||||
                        # add cc value to book
 | 
			
		||||
                        getattr(book, cc_string).append(new_cc)
 | 
			
		||||
@@ -403,12 +404,12 @@ def edit_cc_data(book_id, book, to_save):
 | 
			
		||||
                    del_cc = getattr(book, cc_string)[0]
 | 
			
		||||
                    getattr(book, cc_string).remove(del_cc)
 | 
			
		||||
                    if not del_cc.books or len(del_cc.books) == 0:
 | 
			
		||||
                        db.session.delete(del_cc)
 | 
			
		||||
                        calibre_db.session.delete(del_cc)
 | 
			
		||||
                        changed = True
 | 
			
		||||
        else:
 | 
			
		||||
            input_tags = to_save[cc_string].split(',')
 | 
			
		||||
            input_tags = list(map(lambda it: it.strip(), input_tags))
 | 
			
		||||
            changed |= modify_database_object(input_tags, getattr(book, cc_string), db.cc_classes[c.id], db.session,
 | 
			
		||||
            changed |= modify_database_object(input_tags, getattr(book, cc_string), db.cc_classes[c.id], calibre_db.session,
 | 
			
		||||
                                   'custom')
 | 
			
		||||
    return changed
 | 
			
		||||
 | 
			
		||||
@@ -446,7 +447,7 @@ def upload_single_file(request, book, book_id):
 | 
			
		||||
                return redirect(url_for('web.show_book', book_id=book.id))
 | 
			
		||||
 | 
			
		||||
            file_size = os.path.getsize(saved_filename)
 | 
			
		||||
            is_format = db.session.query(db.Data).filter(db.Data.book == book_id).\
 | 
			
		||||
            is_format = calibre_db.session.query(db.Data).filter(db.Data.book == book_id).\
 | 
			
		||||
                filter(db.Data.format == file_ext.upper()).first()
 | 
			
		||||
 | 
			
		||||
            # Format entry already exists, no need to update the database
 | 
			
		||||
@@ -455,11 +456,11 @@ def upload_single_file(request, book, book_id):
 | 
			
		||||
            else:
 | 
			
		||||
                try:
 | 
			
		||||
                    db_format = db.Data(book_id, file_ext.upper(), file_size, file_name)
 | 
			
		||||
                    db.session.add(db_format)
 | 
			
		||||
                    db.session.commit()
 | 
			
		||||
                    db.update_title_sort(config)
 | 
			
		||||
                    calibre_db.session.add(db_format)
 | 
			
		||||
                    calibre_db.session.commit()
 | 
			
		||||
                    calibre_db.update_title_sort(config)
 | 
			
		||||
                except OperationalError as e:
 | 
			
		||||
                    db.session.rollback()
 | 
			
		||||
                    calibre_db.session.rollback()
 | 
			
		||||
                    log.error('Database error: %s', e)
 | 
			
		||||
                    flash(_(u"Database error: %(error)s.", error=e), category="error")
 | 
			
		||||
                    return redirect(url_for('web.show_book', book_id=book.id))
 | 
			
		||||
@@ -498,8 +499,8 @@ def edit_book(book_id):
 | 
			
		||||
        return render_edit_book(book_id)
 | 
			
		||||
 | 
			
		||||
    # create the function for sorting...
 | 
			
		||||
    db.update_title_sort(config)
 | 
			
		||||
    book = db.session.query(db.Books)\
 | 
			
		||||
    calibre_db.update_title_sort(config)
 | 
			
		||||
    book = calibre_db.session.query(db.Books)\
 | 
			
		||||
        .filter(db.Books.id == book_id).filter(common_filters()).first()
 | 
			
		||||
 | 
			
		||||
    # Book not found
 | 
			
		||||
@@ -531,13 +532,13 @@ def edit_book(book_id):
 | 
			
		||||
        if input_authors == ['']:
 | 
			
		||||
            input_authors = [_(u'Unknown')]  # prevent empty Author
 | 
			
		||||
 | 
			
		||||
        modif_date |= modify_database_object(input_authors, book.authors, db.Authors, db.session, 'author')
 | 
			
		||||
        modif_date |= modify_database_object(input_authors, book.authors, db.Authors, calibre_db.session, 'author')
 | 
			
		||||
 | 
			
		||||
        # Search for each author if author is in database, if not, authorname and sorted authorname is generated new
 | 
			
		||||
        # everything then is assembled for sorted author field in database
 | 
			
		||||
        sort_authors_list = list()
 | 
			
		||||
        for inp in input_authors:
 | 
			
		||||
            stored_author = db.session.query(db.Authors).filter(db.Authors.name == inp).first()
 | 
			
		||||
            stored_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == inp).first()
 | 
			
		||||
            if not stored_author:
 | 
			
		||||
                stored_author = helper.get_sorted_author(inp)
 | 
			
		||||
            else:
 | 
			
		||||
@@ -581,17 +582,17 @@ def edit_book(book_id):
 | 
			
		||||
 | 
			
		||||
                    # Handle identifiers
 | 
			
		||||
            input_identifiers = identifier_list(to_save, book)
 | 
			
		||||
            modif_date |= modify_identifiers(input_identifiers, book.identifiers, db.session)
 | 
			
		||||
            modif_date |= modify_identifiers(input_identifiers, book.identifiers, calibre_db.session)
 | 
			
		||||
 | 
			
		||||
            # Handle book tags
 | 
			
		||||
            input_tags = to_save["tags"].split(',')
 | 
			
		||||
            input_tags = list(map(lambda it: it.strip(), input_tags))
 | 
			
		||||
            modif_date |= modify_database_object(input_tags, book.tags, db.Tags, db.session, 'tags')
 | 
			
		||||
            modif_date |= modify_database_object(input_tags, book.tags, db.Tags, calibre_db.session, 'tags')
 | 
			
		||||
 | 
			
		||||
            # Handle book series
 | 
			
		||||
            input_series = [to_save["series"].strip()]
 | 
			
		||||
            input_series = [x for x in input_series if x != '']
 | 
			
		||||
            modif_date |= modify_database_object(input_series, book.series, db.Series, db.session, 'series')
 | 
			
		||||
            modif_date |= modify_database_object(input_series, book.series, db.Series, calibre_db.session, 'series')
 | 
			
		||||
 | 
			
		||||
            if to_save["pubdate"]:
 | 
			
		||||
                try:
 | 
			
		||||
@@ -615,7 +616,7 @@ def edit_book(book_id):
 | 
			
		||||
 | 
			
		||||
            if modif_date:
 | 
			
		||||
                book.last_modified = datetime.utcnow()
 | 
			
		||||
            db.session.commit()
 | 
			
		||||
            calibre_db.session.commit()
 | 
			
		||||
            if config.config_use_google_drive:
 | 
			
		||||
                gdriveutils.updateGdriveCalibreFromLocal()
 | 
			
		||||
            if "detail_view" in to_save:
 | 
			
		||||
@@ -624,12 +625,12 @@ def edit_book(book_id):
 | 
			
		||||
                flash(_("Metadata successfully updated"), category="success")
 | 
			
		||||
                return render_edit_book(book_id)
 | 
			
		||||
        else:
 | 
			
		||||
            db.session.rollback()
 | 
			
		||||
            calibre_db.session.rollback()
 | 
			
		||||
            flash(error, category="error")
 | 
			
		||||
            return render_edit_book(book_id)
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        log.exception(e)
 | 
			
		||||
        db.session.rollback()
 | 
			
		||||
        calibre_db.session.rollback()
 | 
			
		||||
        flash(_("Error editing book, please check logfile for details"), category="error")
 | 
			
		||||
        return redirect(url_for('web.show_book', book_id=book.id))
 | 
			
		||||
 | 
			
		||||
@@ -671,8 +672,8 @@ def upload():
 | 
			
		||||
        for requested_file in request.files.getlist("btn-upload"):
 | 
			
		||||
            try:
 | 
			
		||||
                # create the function for sorting...
 | 
			
		||||
                db.update_title_sort(config)
 | 
			
		||||
                db.session.connection().connection.connection.create_function('uuid4', 0, lambda: str(uuid4()))
 | 
			
		||||
                calibre_db.update_title_sort(config)
 | 
			
		||||
                calibre_db.session.connection().connection.connection.create_function('uuid4', 0, lambda: str(uuid4()))
 | 
			
		||||
 | 
			
		||||
                # check if file extension is correct
 | 
			
		||||
                if '.' in requested_file.filename:
 | 
			
		||||
@@ -708,13 +709,13 @@ def upload():
 | 
			
		||||
                            + Markup(render_title_template('book_exists_flash.html', entry=entry)), category="warning")
 | 
			
		||||
 | 
			
		||||
                # handle authors
 | 
			
		||||
                is_author = db.session.query(db.Authors).filter(db.Authors.name == authr).first()
 | 
			
		||||
                is_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == authr).first()
 | 
			
		||||
                if is_author:
 | 
			
		||||
                    db_author = is_author
 | 
			
		||||
                    authr= is_author.name
 | 
			
		||||
                else:
 | 
			
		||||
                    db_author = db.Authors(authr, helper.get_sorted_author(authr), "")
 | 
			
		||||
                    db.session.add(db_author)
 | 
			
		||||
                    calibre_db.session.add(db_author)
 | 
			
		||||
 | 
			
		||||
                title_dir = helper.get_valid_filename(title)
 | 
			
		||||
                author_dir = helper.get_valid_filename(authr)
 | 
			
		||||
@@ -746,29 +747,29 @@ def upload():
 | 
			
		||||
 | 
			
		||||
                # handle series
 | 
			
		||||
                db_series = None
 | 
			
		||||
                is_series = db.session.query(db.Series).filter(db.Series.name == series).first()
 | 
			
		||||
                is_series = calibre_db.session.query(db.Series).filter(db.Series.name == series).first()
 | 
			
		||||
                if is_series:
 | 
			
		||||
                    db_series = is_series
 | 
			
		||||
                elif series != '':
 | 
			
		||||
                    db_series = db.Series(series, "")
 | 
			
		||||
                    db.session.add(db_series)
 | 
			
		||||
                    calibre_db.session.add(db_series)
 | 
			
		||||
 | 
			
		||||
                # add language actually one value in list
 | 
			
		||||
                input_language = meta.languages
 | 
			
		||||
                db_language = None
 | 
			
		||||
                if input_language != "":
 | 
			
		||||
                    input_language = isoLanguages.get(name=input_language).part3
 | 
			
		||||
                    hasLanguage = db.session.query(db.Languages).filter(db.Languages.lang_code == input_language).first()
 | 
			
		||||
                    hasLanguage = calibre_db.session.query(db.Languages).filter(db.Languages.lang_code == input_language).first()
 | 
			
		||||
                    if hasLanguage:
 | 
			
		||||
                        db_language = hasLanguage
 | 
			
		||||
                    else:
 | 
			
		||||
                        db_language = db.Languages(input_language)
 | 
			
		||||
                        db.session.add(db_language)
 | 
			
		||||
                        calibre_db.session.add(db_language)
 | 
			
		||||
 | 
			
		||||
                # If the language of the file is excluded from the users view, it's not imported, to allow the user to view
 | 
			
		||||
                # the book it's language is set to the filter language
 | 
			
		||||
                if db_language != current_user.filter_language() and current_user.filter_language() != "all":
 | 
			
		||||
                    db_language = db.session.query(db.Languages).\
 | 
			
		||||
                    db_language = calibre_db.session.query(db.Languages).\
 | 
			
		||||
                        filter(db.Languages.lang_code == current_user.filter_language()).first()
 | 
			
		||||
 | 
			
		||||
                # combine path and normalize path from windows systems
 | 
			
		||||
@@ -788,25 +789,25 @@ def upload():
 | 
			
		||||
                input_tags = tags.split(',')
 | 
			
		||||
                input_tags = list(map(lambda it: it.strip(), input_tags))
 | 
			
		||||
                if input_tags[0] !="":
 | 
			
		||||
                    modify_database_object(input_tags, db_book.tags, db.Tags, db.session, 'tags')
 | 
			
		||||
                    modify_database_object(input_tags, db_book.tags, db.Tags, calibre_db.session, 'tags')
 | 
			
		||||
 | 
			
		||||
                # flush content, get db_book.id available
 | 
			
		||||
                db_book.data.append(db_data)
 | 
			
		||||
                db.session.add(db_book)
 | 
			
		||||
                db.session.flush()
 | 
			
		||||
                calibre_db.session.add(db_book)
 | 
			
		||||
                calibre_db.session.flush()
 | 
			
		||||
 | 
			
		||||
                # add comment
 | 
			
		||||
                book_id = db_book.id
 | 
			
		||||
                upload_comment = Markup(meta.description).unescape()
 | 
			
		||||
                if upload_comment != "":
 | 
			
		||||
                    db.session.add(db.Comments(upload_comment, book_id))
 | 
			
		||||
                    calibre_db.session.add(db.Comments(upload_comment, book_id))
 | 
			
		||||
 | 
			
		||||
                # save data to database, reread data
 | 
			
		||||
                db.session.commit()
 | 
			
		||||
                db.update_title_sort(config)
 | 
			
		||||
                calibre_db.session.commit()
 | 
			
		||||
                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
 | 
			
		||||
                # current users view (tags are not stored/extracted from metadata and could also be limited)
 | 
			
		||||
                book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
                book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
                # upload book to gdrive if nesseccary and add "(bookid)" to folder name
 | 
			
		||||
                if config.config_use_google_drive:
 | 
			
		||||
                    gdriveutils.updateGdriveCalibreFromLocal()
 | 
			
		||||
@@ -823,7 +824,7 @@ def upload():
 | 
			
		||||
                        flash(_(u"Failed to Move Cover File %(file)s: %(error)s", file=new_coverpath,
 | 
			
		||||
                                error=e),
 | 
			
		||||
                              category="error")
 | 
			
		||||
                db.session.commit()
 | 
			
		||||
                calibre_db.session.commit()
 | 
			
		||||
                if config.config_use_google_drive:
 | 
			
		||||
                    gdriveutils.updateGdriveCalibreFromLocal()
 | 
			
		||||
                if error:
 | 
			
		||||
@@ -846,7 +847,7 @@ def upload():
 | 
			
		||||
                        resp = {"location": url_for('web.show_book', book_id=db_book.id)}
 | 
			
		||||
                        return Response(json.dumps(resp), mimetype='application/json')
 | 
			
		||||
            except OperationalError as e:
 | 
			
		||||
                db.session.rollback()
 | 
			
		||||
                calibre_db.session.rollback()
 | 
			
		||||
                log.error("Database error: %s", e)
 | 
			
		||||
                flash(_(u"Database error: %(error)s.", error=e), category="error")
 | 
			
		||||
        return Response(json.dumps({"location": url_for("web.index")}), mimetype='application/json')
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,6 @@ import os
 | 
			
		||||
import io
 | 
			
		||||
import json
 | 
			
		||||
import mimetypes
 | 
			
		||||
import random
 | 
			
		||||
import re
 | 
			
		||||
import shutil
 | 
			
		||||
import time
 | 
			
		||||
@@ -42,6 +41,7 @@ from flask_login import current_user
 | 
			
		||||
from sqlalchemy.sql.expression import true, false, and_, or_, text, func
 | 
			
		||||
from werkzeug.datastructures import Headers
 | 
			
		||||
from werkzeug.security import generate_password_hash
 | 
			
		||||
from . import calibre_db
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    from urllib.parse import quote
 | 
			
		||||
@@ -74,8 +74,8 @@ log = logger.create()
 | 
			
		||||
 | 
			
		||||
# 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):
 | 
			
		||||
    book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
    data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == old_book_format).first()
 | 
			
		||||
    book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
    data = calibre_db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == old_book_format).first()
 | 
			
		||||
    if not data:
 | 
			
		||||
        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)
 | 
			
		||||
@@ -212,7 +212,7 @@ def check_read_formats(entry):
 | 
			
		||||
# 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):
 | 
			
		||||
    """Send email with attachments"""
 | 
			
		||||
    book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
    book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
 | 
			
		||||
    if convert == 1:
 | 
			
		||||
        # 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):
 | 
			
		||||
    localbook = db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
    localbook = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
    path = os.path.join(calibrepath, localbook.path)
 | 
			
		||||
 | 
			
		||||
    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):
 | 
			
		||||
    error = False
 | 
			
		||||
    book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
    book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
    path = book.path
 | 
			
		||||
 | 
			
		||||
    authordir = book.path.split('/')[0]
 | 
			
		||||
@@ -494,13 +494,13 @@ def get_cover_on_failure(use_generic_cover):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_book_cover(book_id):
 | 
			
		||||
    book = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters(allow_show_archived=True)).first()
 | 
			
		||||
    book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters(allow_show_archived=True)).first()
 | 
			
		||||
    return get_book_cover_internal(book, use_generic_cover_on_failure=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_book_cover_with_uuid(book_uuid,
 | 
			
		||||
                             use_generic_cover_on_failure=True):
 | 
			
		||||
    book = db.session.query(db.Books).filter(db.Books.uuid == book_uuid).first()
 | 
			
		||||
    book = calibre_db.session.query(db.Books).filter(db.Books.uuid == book_uuid).first()
 | 
			
		||||
    return get_book_cover_internal(book, use_generic_cover_on_failure)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -775,7 +775,7 @@ def tags_filters():
 | 
			
		||||
# Creates for all stored languages a translated speaking name in the array for the UI
 | 
			
		||||
def speaking_language(languages=None):
 | 
			
		||||
    if not languages:
 | 
			
		||||
        languages = db.session.query(db.Languages).join(db.books_languages_link).join(db.Books)\
 | 
			
		||||
        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:
 | 
			
		||||
@@ -808,7 +808,7 @@ def order_authors(entry):
 | 
			
		||||
    error = False
 | 
			
		||||
    for auth in sort_authors:
 | 
			
		||||
        # ToDo: How to handle not found authorname
 | 
			
		||||
        result = db.session.query(db.Authors).filter(db.Authors.sort == auth.lstrip().strip()).first()
 | 
			
		||||
        result = calibre_db.session.query(db.Authors).filter(db.Authors.sort == auth.lstrip().strip()).first()
 | 
			
		||||
        if not result:
 | 
			
		||||
            error = True
 | 
			
		||||
            break
 | 
			
		||||
@@ -825,12 +825,12 @@ def fill_indexpage(page, database, db_filter, order, *join):
 | 
			
		||||
 | 
			
		||||
def fill_indexpage_with_archived_books(page, database, db_filter, order, allow_show_archived, *join):
 | 
			
		||||
    if current_user.show_detail_random():
 | 
			
		||||
        randm = db.session.query(db.Books).filter(common_filters(allow_show_archived))\
 | 
			
		||||
        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 = db.session.query(database).join(*join, isouter=True).\
 | 
			
		||||
    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,
 | 
			
		||||
@@ -843,8 +843,8 @@ def fill_indexpage_with_archived_books(page, database, db_filter, order, allow_s
 | 
			
		||||
 | 
			
		||||
def get_typeahead(database, query, replace=('', ''), tag_filter=true()):
 | 
			
		||||
    query = query or ''
 | 
			
		||||
    db.session.connection().connection.connection.create_function("lower", 1, lcase)
 | 
			
		||||
    entries = db.session.query(database).filter(tag_filter).\
 | 
			
		||||
    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
 | 
			
		||||
@@ -852,7 +852,7 @@ def get_typeahead(database, query, replace=('', ''), tag_filter=true()):
 | 
			
		||||
 | 
			
		||||
# read search results from calibre-database and return it (function is used for feed and simple search
 | 
			
		||||
def get_search_results(term):
 | 
			
		||||
    db.session.connection().connection.connection.create_function("lower", 1, lcase)
 | 
			
		||||
    calibre_db.session.connection().connection.connection.create_function("lower", 1, lcase)
 | 
			
		||||
    q = list()
 | 
			
		||||
    authorterms = re.split("[, ]+", term)
 | 
			
		||||
    for authorterm in authorterms:
 | 
			
		||||
@@ -860,7 +860,7 @@ def get_search_results(term):
 | 
			
		||||
 | 
			
		||||
    db.Books.authors.any(func.lower(db.Authors.name).ilike("%" + term + "%"))
 | 
			
		||||
 | 
			
		||||
    return db.session.query(db.Books).filter(common_filters()).filter(
 | 
			
		||||
    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)),
 | 
			
		||||
@@ -870,7 +870,7 @@ def get_search_results(term):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_cc_columns(filter_config_custom_read=False):
 | 
			
		||||
    tmpcc = 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 = []
 | 
			
		||||
    r = None
 | 
			
		||||
    if config.config_columns_to_ignore:
 | 
			
		||||
@@ -887,9 +887,9 @@ def get_cc_columns(filter_config_custom_read=False):
 | 
			
		||||
 | 
			
		||||
def get_download_link(book_id, book_format, client):
 | 
			
		||||
    book_format = book_format.split(".")[0]
 | 
			
		||||
    book = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
 | 
			
		||||
    book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
 | 
			
		||||
    if book:
 | 
			
		||||
        data1 = db.session.query(db.Data).filter(db.Data.book == book.id)\
 | 
			
		||||
        data1 = calibre_db.session.query(db.Data).filter(db.Data.book == book.id)\
 | 
			
		||||
            .filter(db.Data.format == book_format.upper()).first()
 | 
			
		||||
    else:
 | 
			
		||||
        abort(404)
 | 
			
		||||
@@ -911,13 +911,13 @@ def get_download_link(book_id, book_format, client):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def check_exists_book(authr, title):
 | 
			
		||||
    db.session.connection().connection.connection.create_function("lower", 1, lcase)
 | 
			
		||||
    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 db.session.query(db.Books).filter(
 | 
			
		||||
    return calibre_db.session.query(db.Books).filter(
 | 
			
		||||
        and_(db.Books.authors.any(and_(*q)),
 | 
			
		||||
             func.lower(db.Books.title).ilike("%" + title + "%")
 | 
			
		||||
             )).first()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								cps/kobo.py
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								cps/kobo.py
									
									
									
									
									
								
							@@ -48,7 +48,7 @@ from sqlalchemy.sql.expression import and_, or_
 | 
			
		||||
from sqlalchemy.exc import StatementError
 | 
			
		||||
import requests
 | 
			
		||||
 | 
			
		||||
from . import config, logger, kobo_auth, db, helper, shelf as shelf_lib, ub
 | 
			
		||||
from . import config, logger, kobo_auth, db, calibre_db, helper, shelf as shelf_lib, ub
 | 
			
		||||
from .services import SyncToken as SyncToken
 | 
			
		||||
from .web import download_required
 | 
			
		||||
from .kobo_auth import requires_kobo_auth
 | 
			
		||||
@@ -170,7 +170,7 @@ def HandleSyncRequest():
 | 
			
		||||
    # It looks like it's treating the db.Books.last_modified field as a string and may fail
 | 
			
		||||
    # the comparison because of the +00:00 suffix.
 | 
			
		||||
    changed_entries = (
 | 
			
		||||
        db.session.query(db.Books)
 | 
			
		||||
        calibre_db.session.query(db.Books)
 | 
			
		||||
        .join(db.Data)
 | 
			
		||||
        .filter(or_(func.datetime(db.Books.last_modified) > sync_token.books_last_modified,
 | 
			
		||||
                    db.Books.id.in_(recently_restored_or_archived_books)))
 | 
			
		||||
@@ -207,7 +207,7 @@ def HandleSyncRequest():
 | 
			
		||||
                     ub.KoboReadingState.user_id == current_user.id,
 | 
			
		||||
                     ub.KoboReadingState.book_id.notin_(reading_states_in_new_entitlements))))
 | 
			
		||||
    for kobo_reading_state in changed_reading_states.all():
 | 
			
		||||
        book = db.session.query(db.Books).filter(db.Books.id == kobo_reading_state.book_id).one_or_none()
 | 
			
		||||
        book = calibre_db.session.query(db.Books).filter(db.Books.id == kobo_reading_state.book_id).one_or_none()
 | 
			
		||||
        if book:
 | 
			
		||||
            sync_results.append({
 | 
			
		||||
                "ChangedReadingState": {
 | 
			
		||||
@@ -256,7 +256,7 @@ def HandleMetadataRequest(book_uuid):
 | 
			
		||||
    if not current_app.wsgi_app.is_proxied:
 | 
			
		||||
        log.debug('Kobo: Received unproxied request, changed request port to server port')
 | 
			
		||||
    log.info("Kobo library metadata request received for book %s" % book_uuid)
 | 
			
		||||
    book = db.session.query(db.Books).filter(db.Books.uuid == book_uuid).first()
 | 
			
		||||
    book = calibre_db.session.query(db.Books).filter(db.Books.uuid == book_uuid).first()
 | 
			
		||||
    if not book or not book.data:
 | 
			
		||||
        log.info(u"Book %s not found in database", book_uuid)
 | 
			
		||||
        return redirect_or_proxy_request()
 | 
			
		||||
@@ -474,7 +474,7 @@ def add_items_to_shelf(items, shelf):
 | 
			
		||||
                items_unknown_to_calibre.append(item)
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            book = db.session.query(db.Books).filter(db.Books.uuid == item["RevisionId"]).one_or_none()
 | 
			
		||||
            book = calibre_db.session.query(db.Books).filter(db.Books.uuid == item["RevisionId"]).one_or_none()
 | 
			
		||||
            if not book:
 | 
			
		||||
                items_unknown_to_calibre.append(item)
 | 
			
		||||
                continue
 | 
			
		||||
@@ -545,7 +545,7 @@ def HandleTagRemoveItem(tag_id):
 | 
			
		||||
                items_unknown_to_calibre.append(item)
 | 
			
		||||
                continue
 | 
			
		||||
 | 
			
		||||
            book = db.session.query(db.Books).filter(db.Books.uuid == item["RevisionId"]).one_or_none()
 | 
			
		||||
            book = calibre_db.session.query(db.Books).filter(db.Books.uuid == item["RevisionId"]).one_or_none()
 | 
			
		||||
            if not book:
 | 
			
		||||
                items_unknown_to_calibre.append(item)
 | 
			
		||||
                continue
 | 
			
		||||
@@ -613,7 +613,7 @@ def create_kobo_tag(shelf):
 | 
			
		||||
        "Type": "UserTag"
 | 
			
		||||
    }
 | 
			
		||||
    for book_shelf in shelf.books:
 | 
			
		||||
        book = db.session.query(db.Books).filter(db.Books.id == book_shelf.book_id).one_or_none()
 | 
			
		||||
        book = calibre_db.session.query(db.Books).filter(db.Books.id == book_shelf.book_id).one_or_none()
 | 
			
		||||
        if not book:
 | 
			
		||||
            log.info(u"Book (id: %s) in BookShelf (id: %s) not found in book database",  book_shelf.book_id, shelf.id)
 | 
			
		||||
            continue
 | 
			
		||||
@@ -629,7 +629,7 @@ def create_kobo_tag(shelf):
 | 
			
		||||
@kobo.route("/v1/library/<book_uuid>/state", methods=["GET", "PUT"])
 | 
			
		||||
@login_required
 | 
			
		||||
def HandleStateRequest(book_uuid):
 | 
			
		||||
    book = db.session.query(db.Books).filter(db.Books.uuid == book_uuid).first()
 | 
			
		||||
    book = calibre_db.session.query(db.Books).filter(db.Books.uuid == book_uuid).first()
 | 
			
		||||
    if not book or not book.data:
 | 
			
		||||
        log.info(u"Book %s not found in database", book_uuid)
 | 
			
		||||
        return redirect_or_proxy_request()
 | 
			
		||||
@@ -804,7 +804,7 @@ def TopLevelEndpoint():
 | 
			
		||||
@login_required
 | 
			
		||||
def HandleBookDeletionRequest(book_uuid):
 | 
			
		||||
    log.info("Kobo book deletion request received for book %s" % book_uuid)
 | 
			
		||||
    book = db.session.query(db.Books).filter(db.Books.uuid == book_uuid).first()
 | 
			
		||||
    book = calibre_db.session.query(db.Books).filter(db.Books.uuid == book_uuid).first()
 | 
			
		||||
    if not book:
 | 
			
		||||
        log.info(u"Book %s not found in database", book_uuid)
 | 
			
		||||
        return redirect_or_proxy_request()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										34
									
								
								cps/opds.py
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								cps/opds.py
									
									
									
									
									
								
							@@ -30,7 +30,7 @@ from flask_login import current_user
 | 
			
		||||
from sqlalchemy.sql.expression import func, text, or_, and_
 | 
			
		||||
from werkzeug.security import check_password_hash
 | 
			
		||||
 | 
			
		||||
from . import constants, logger, config, 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 .pagination import Pagination
 | 
			
		||||
from .web import common_filters, get_search_results, render_read_books, download_required
 | 
			
		||||
@@ -108,7 +108,7 @@ def feed_new():
 | 
			
		||||
@opds.route("/opds/discover")
 | 
			
		||||
@requires_basic_auth_if_no_ano
 | 
			
		||||
def feed_discover():
 | 
			
		||||
    entries = db.session.query(db.Books).filter(common_filters()).order_by(func.random())\
 | 
			
		||||
    entries = calibre_db.session.query(db.Books).filter(common_filters()).order_by(func.random())\
 | 
			
		||||
        .limit(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)
 | 
			
		||||
@@ -133,10 +133,10 @@ def feed_hot():
 | 
			
		||||
    hot_books = all_books.offset(off).limit(config.config_books_per_page)
 | 
			
		||||
    entries = list()
 | 
			
		||||
    for book in hot_books:
 | 
			
		||||
        downloadBook = db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first()
 | 
			
		||||
        downloadBook = calibre_db.session.query(db.Books).filter(db.Books.id == book.Downloads.book_id).first()
 | 
			
		||||
        if downloadBook:
 | 
			
		||||
            entries.append(
 | 
			
		||||
                db.session.query(db.Books).filter(common_filters())
 | 
			
		||||
                calibre_db.session.query(db.Books).filter(common_filters())
 | 
			
		||||
                .filter(db.Books.id == book.Downloads.book_id).first()
 | 
			
		||||
            )
 | 
			
		||||
        else:
 | 
			
		||||
@@ -153,11 +153,11 @@ def feed_hot():
 | 
			
		||||
@requires_basic_auth_if_no_ano
 | 
			
		||||
def feed_authorindex():
 | 
			
		||||
    off = request.args.get("offset") or 0
 | 
			
		||||
    entries = 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).filter(common_filters())\
 | 
			
		||||
        .group_by(text('books_authors_link.author')).order_by(db.Authors.sort).limit(config.config_books_per_page)\
 | 
			
		||||
        .offset(off)
 | 
			
		||||
    pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
 | 
			
		||||
                            len(db.session.query(db.Authors).all()))
 | 
			
		||||
                            len(calibre_db.session.query(db.Authors).all()))
 | 
			
		||||
    return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_author', pagination=pagination)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -176,11 +176,11 @@ def feed_author(book_id):
 | 
			
		||||
@requires_basic_auth_if_no_ano
 | 
			
		||||
def feed_publisherindex():
 | 
			
		||||
    off = request.args.get("offset") or 0
 | 
			
		||||
    entries = db.session.query(db.Publishers).join(db.books_publishers_link).join(db.Books).filter(common_filters())\
 | 
			
		||||
    entries = calibre_db.session.query(db.Publishers).join(db.books_publishers_link).join(db.Books).filter(common_filters())\
 | 
			
		||||
        .group_by(text('books_publishers_link.publisher')).order_by(db.Publishers.sort)\
 | 
			
		||||
        .limit(config.config_books_per_page).offset(off)
 | 
			
		||||
    pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
 | 
			
		||||
                            len(db.session.query(db.Publishers).all()))
 | 
			
		||||
                            len(calibre_db.session.query(db.Publishers).all()))
 | 
			
		||||
    return render_xml_template('feed.xml', listelements=entries, folder='opds.feed_publisher', pagination=pagination)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -199,10 +199,10 @@ def feed_publisher(book_id):
 | 
			
		||||
@requires_basic_auth_if_no_ano
 | 
			
		||||
def feed_categoryindex():
 | 
			
		||||
    off = request.args.get("offset") or 0
 | 
			
		||||
    entries = db.session.query(db.Tags).join(db.books_tags_link).join(db.Books).filter(common_filters())\
 | 
			
		||||
    entries = calibre_db.session.query(db.Tags).join(db.books_tags_link).join(db.Books).filter(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,
 | 
			
		||||
                            len(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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -221,10 +221,10 @@ def feed_category(book_id):
 | 
			
		||||
@requires_basic_auth_if_no_ano
 | 
			
		||||
def feed_seriesindex():
 | 
			
		||||
    off = request.args.get("offset") or 0
 | 
			
		||||
    entries = db.session.query(db.Series).join(db.books_series_link).join(db.Books).filter(common_filters())\
 | 
			
		||||
    entries = calibre_db.session.query(db.Series).join(db.books_series_link).join(db.Books).filter(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,
 | 
			
		||||
                            len(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)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -243,7 +243,7 @@ def feed_series(book_id):
 | 
			
		||||
@requires_basic_auth_if_no_ano
 | 
			
		||||
def feed_ratingindex():
 | 
			
		||||
    off = request.args.get("offset") or 0
 | 
			
		||||
    entries = 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')) \
 | 
			
		||||
        .join(db.books_ratings_link).join(db.Books).filter(common_filters()) \
 | 
			
		||||
        .group_by(text('books_ratings_link.rating')).order_by(db.Ratings.rating).all()
 | 
			
		||||
@@ -271,7 +271,7 @@ def feed_ratings(book_id):
 | 
			
		||||
@requires_basic_auth_if_no_ano
 | 
			
		||||
def feed_formatindex():
 | 
			
		||||
    off = request.args.get("offset") or 0
 | 
			
		||||
    entries = db.session.query(db.Data).join(db.Books).filter(common_filters()) \
 | 
			
		||||
    entries = calibre_db.session.query(db.Data).join(db.Books).filter(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,
 | 
			
		||||
                            len(entries))
 | 
			
		||||
@@ -305,7 +305,7 @@ def feed_languagesindex():
 | 
			
		||||
            cur_l = LC.parse(current_user.filter_language())
 | 
			
		||||
        except UnknownLocaleError:
 | 
			
		||||
            cur_l = None
 | 
			
		||||
        languages = db.session.query(db.Languages).filter(
 | 
			
		||||
        languages = calibre_db.session.query(db.Languages).filter(
 | 
			
		||||
            db.Languages.lang_code == current_user.filter_language()).all()
 | 
			
		||||
        if cur_l:
 | 
			
		||||
            languages[0].name = cur_l.get_language_name(get_locale())
 | 
			
		||||
@@ -356,7 +356,7 @@ def feed_shelf(book_id):
 | 
			
		||||
        books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == book_id).order_by(
 | 
			
		||||
            ub.BookShelf.order.asc()).all()
 | 
			
		||||
        for book in books_in_shelf:
 | 
			
		||||
            cur_book = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
 | 
			
		||||
            cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
 | 
			
		||||
            result.append(cur_book)
 | 
			
		||||
    pagination = Pagination((int(off) / (int(config.config_books_per_page)) + 1), config.config_books_per_page,
 | 
			
		||||
                            len(result))
 | 
			
		||||
@@ -378,7 +378,7 @@ def opds_download_link(book_id, book_format):
 | 
			
		||||
@opds.route("/ajax/book/<string:uuid>", defaults={'library': ""})
 | 
			
		||||
@requires_basic_auth_if_no_ano
 | 
			
		||||
def get_metadata_calibre_companion(uuid, library):
 | 
			
		||||
    entry = db.session.query(db.Books).filter(db.Books.uuid.like("%" + uuid + "%")).first()
 | 
			
		||||
    entry = calibre_db.session.query(db.Books).filter(db.Books.uuid.like("%" + uuid + "%")).first()
 | 
			
		||||
    if entry is not None:
 | 
			
		||||
        js = render_template('json.txt', entry=entry)
 | 
			
		||||
        response = make_response(js)
 | 
			
		||||
 
 | 
			
		||||
@@ -196,6 +196,9 @@ class WebServer(object):
 | 
			
		||||
    def stop(self, restart=False):
 | 
			
		||||
        from . import updater_thread
 | 
			
		||||
        updater_thread.stop()
 | 
			
		||||
        from . import calibre_db
 | 
			
		||||
        calibre_db.stop()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        log.info("webserver stop (restart=%s)", restart)
 | 
			
		||||
        self.restart = restart
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								cps/shelf.py
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								cps/shelf.py
									
									
									
									
									
								
							@@ -28,7 +28,7 @@ from flask_babel import gettext as _
 | 
			
		||||
from flask_login import login_required, current_user
 | 
			
		||||
from sqlalchemy.sql.expression import func
 | 
			
		||||
 | 
			
		||||
from . import logger, ub, searched_ids, db
 | 
			
		||||
from . import logger, ub, searched_ids, db, calibre_db
 | 
			
		||||
from .web import render_title_template
 | 
			
		||||
from .helper import common_filters
 | 
			
		||||
 | 
			
		||||
@@ -320,11 +320,11 @@ def show_shelf(shelf_type, shelf_id):
 | 
			
		||||
        books_in_shelf = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id)\
 | 
			
		||||
            .order_by(ub.BookShelf.order.asc()).all()
 | 
			
		||||
        for book in books_in_shelf:
 | 
			
		||||
            cur_book = db.session.query(db.Books).filter(db.Books.id == book.book_id).filter(common_filters()).first()
 | 
			
		||||
            cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).filter(common_filters()).first()
 | 
			
		||||
            if cur_book:
 | 
			
		||||
                result.append(cur_book)
 | 
			
		||||
            else:
 | 
			
		||||
                cur_book = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
 | 
			
		||||
                cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
 | 
			
		||||
                if not cur_book:
 | 
			
		||||
                    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()
 | 
			
		||||
@@ -356,7 +356,7 @@ def order_shelf(shelf_id):
 | 
			
		||||
        books_in_shelf2 = ub.session.query(ub.BookShelf).filter(ub.BookShelf.shelf == shelf_id) \
 | 
			
		||||
            .order_by(ub.BookShelf.order.asc()).all()
 | 
			
		||||
        for book in books_in_shelf2:
 | 
			
		||||
            cur_book = db.session.query(db.Books).filter(db.Books.id == book.book_id).filter(common_filters()).first()
 | 
			
		||||
            cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).filter(common_filters()).first()
 | 
			
		||||
            if cur_book:
 | 
			
		||||
                result.append({'title': cur_book.title,
 | 
			
		||||
                               'id': cur_book.id,
 | 
			
		||||
@@ -364,7 +364,7 @@ def order_shelf(shelf_id):
 | 
			
		||||
                               'series': cur_book.series,
 | 
			
		||||
                               'series_index': cur_book.series_index})
 | 
			
		||||
            else:
 | 
			
		||||
                cur_book = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
 | 
			
		||||
                cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
 | 
			
		||||
                result.append({'title': _('Hidden Book'),
 | 
			
		||||
                               'id': cur_book.id,
 | 
			
		||||
                               'author': [],
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										95
									
								
								cps/web.py
									
									
									
									
									
								
							
							
						
						
									
										95
									
								
								cps/web.py
									
									
									
									
									
								
							@@ -50,6 +50,7 @@ from werkzeug.security import generate_password_hash, check_password_hash
 | 
			
		||||
 | 
			
		||||
from . import constants, logger, isoLanguages, services, worker
 | 
			
		||||
from . import searched_ids, lm, babel, db, ub, config, get_locale, app
 | 
			
		||||
from . import calibre_db
 | 
			
		||||
from .gdriveutils import getFileFromEbooksFolder, do_gdrive_download
 | 
			
		||||
from .helper import common_filters, get_search_results, fill_indexpage, fill_indexpage_with_archived_books, \
 | 
			
		||||
    speaking_language, check_valid_domain, order_authors, get_typeahead, render_task_status, json_serial, \
 | 
			
		||||
@@ -438,21 +439,21 @@ def toggle_read(book_id):
 | 
			
		||||
        ub.session.commit()
 | 
			
		||||
    else:
 | 
			
		||||
        try:
 | 
			
		||||
            db.update_title_sort(config)
 | 
			
		||||
            book = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
 | 
			
		||||
            calibre_db.update_title_sort(config)
 | 
			
		||||
            book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
 | 
			
		||||
            read_status = getattr(book, 'custom_column_' + str(config.config_read_column))
 | 
			
		||||
            if len(read_status):
 | 
			
		||||
                read_status[0].value = not read_status[0].value
 | 
			
		||||
                db.session.commit()
 | 
			
		||||
                calibre_db.session.commit()
 | 
			
		||||
            else:
 | 
			
		||||
                cc_class = db.cc_classes[config.config_read_column]
 | 
			
		||||
                new_cc = cc_class(value=1, book=book_id)
 | 
			
		||||
                db.session.add(new_cc)
 | 
			
		||||
                db.session.commit()
 | 
			
		||||
                calibre_db.session.add(new_cc)
 | 
			
		||||
                calibre_db.session.commit()
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            log.error(u"Custom Column No.%d is not exisiting in calibre database", config.config_read_column)
 | 
			
		||||
        except OperationalError as e:
 | 
			
		||||
            db.session.rollback()
 | 
			
		||||
            calibre_db.session.rollback()
 | 
			
		||||
            log.error(u"Read status could not set: %e", e)
 | 
			
		||||
 | 
			
		||||
    return ""
 | 
			
		||||
@@ -496,7 +497,7 @@ def update_view():
 | 
			
		||||
@web.route("/ajax/getcomic/<int:book_id>/<book_format>/<int:page>")
 | 
			
		||||
@login_required
 | 
			
		||||
def get_comic_book(book_id, book_format, page):
 | 
			
		||||
    book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
    book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
    if not book:
 | 
			
		||||
        return "", 204
 | 
			
		||||
    else:
 | 
			
		||||
@@ -589,8 +590,8 @@ def get_languages_json():
 | 
			
		||||
@login_required_if_no_ano
 | 
			
		||||
def get_matching_tags():
 | 
			
		||||
    tag_dict = {'tags': []}
 | 
			
		||||
    q = db.session.query(db.Books)
 | 
			
		||||
    db.session.connection().connection.connection.create_function("lower", 1, lcase)
 | 
			
		||||
    q = calibre_db.session.query(db.Books)
 | 
			
		||||
    calibre_db.session.connection().connection.connection.create_function("lower", 1, lcase)
 | 
			
		||||
    author_input = request.args.get('author_name') or ''
 | 
			
		||||
    title_input = request.args.get('book_title') or ''
 | 
			
		||||
    include_tag_inputs = request.args.getlist('include_tag') or ''
 | 
			
		||||
@@ -692,7 +693,7 @@ def books_list(data, sort, book_id, page):
 | 
			
		||||
def render_hot_books(page):
 | 
			
		||||
    if current_user.check_visibility(constants.SIDEBAR_HOT):
 | 
			
		||||
        if current_user.show_detail_random():
 | 
			
		||||
            random = db.session.query(db.Books).filter(common_filters()) \
 | 
			
		||||
            random = calibre_db.session.query(db.Books).filter(common_filters()) \
 | 
			
		||||
                .order_by(func.random()).limit(config.config_random_books)
 | 
			
		||||
        else:
 | 
			
		||||
            random = false()
 | 
			
		||||
@@ -702,7 +703,7 @@ def render_hot_books(page):
 | 
			
		||||
        hot_books = all_books.offset(off).limit(config.config_books_per_page)
 | 
			
		||||
        entries = list()
 | 
			
		||||
        for book in hot_books:
 | 
			
		||||
            downloadBook = db.session.query(db.Books).filter(common_filters()).filter(
 | 
			
		||||
            downloadBook = calibre_db.session.query(db.Books).filter(common_filters()).filter(
 | 
			
		||||
                db.Books.id == book.Downloads.book_id).first()
 | 
			
		||||
            if downloadBook:
 | 
			
		||||
                entries.append(downloadBook)
 | 
			
		||||
@@ -727,7 +728,7 @@ def render_author_books(page, author_id, order):
 | 
			
		||||
              category="error")
 | 
			
		||||
        return redirect(url_for("web.index"))
 | 
			
		||||
 | 
			
		||||
    author = db.session.query(db.Authors).get(author_id)
 | 
			
		||||
    author = calibre_db.session.query(db.Authors).get(author_id)
 | 
			
		||||
    author_name = author.name.replace('|', ',')
 | 
			
		||||
 | 
			
		||||
    author_info = None
 | 
			
		||||
@@ -742,7 +743,7 @@ def render_author_books(page, author_id, order):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def render_publisher_books(page, book_id, order):
 | 
			
		||||
    publisher = 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:
 | 
			
		||||
        entries, random, pagination = fill_indexpage(page, db.Books,
 | 
			
		||||
                                                     db.Books.publishers.any(db.Publishers.id == book_id),
 | 
			
		||||
@@ -755,7 +756,7 @@ def render_publisher_books(page, book_id, order):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def render_series_books(page, book_id, order):
 | 
			
		||||
    name = 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:
 | 
			
		||||
        entries, random, pagination = fill_indexpage(page, db.Books, db.Books.series.any(db.Series.id == book_id),
 | 
			
		||||
                                                     [db.Books.series_index, order[0]])
 | 
			
		||||
@@ -766,7 +767,7 @@ def render_series_books(page, book_id, order):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def render_ratings_books(page, book_id, order):
 | 
			
		||||
    name = 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),
 | 
			
		||||
                                                 [db.Books.timestamp.desc(), order[0]])
 | 
			
		||||
    if name and name.rating <= 10:
 | 
			
		||||
@@ -777,7 +778,7 @@ def render_ratings_books(page, book_id, order):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def render_formats_books(page, book_id, order):
 | 
			
		||||
    name = 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:
 | 
			
		||||
        entries, random, pagination = fill_indexpage(page, db.Books,
 | 
			
		||||
                                                     db.Books.data.any(db.Data.format == book_id.upper()),
 | 
			
		||||
@@ -789,7 +790,7 @@ def render_formats_books(page, book_id, order):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def render_category_books(page, book_id, order):
 | 
			
		||||
    name = 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:
 | 
			
		||||
        entries, random, pagination = fill_indexpage(page, db.Books, db.Books.tags.any(db.Tags.id == book_id),
 | 
			
		||||
                                                     [order[0], db.Series.name, db.Books.series_index],
 | 
			
		||||
@@ -825,10 +826,10 @@ def books_table():
 | 
			
		||||
@login_required_if_no_ano
 | 
			
		||||
def author_list():
 | 
			
		||||
    if current_user.check_visibility(constants.SIDEBAR_AUTHOR):
 | 
			
		||||
        entries = 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()) \
 | 
			
		||||
            .group_by(text('books_authors_link.author')).order_by(db.Authors.sort).all()
 | 
			
		||||
        charlist = 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()) \
 | 
			
		||||
            .group_by(func.upper(func.substr(db.Authors.sort, 1, 1))).all()
 | 
			
		||||
        for entry in entries:
 | 
			
		||||
@@ -843,10 +844,10 @@ def author_list():
 | 
			
		||||
@login_required_if_no_ano
 | 
			
		||||
def publisher_list():
 | 
			
		||||
    if current_user.check_visibility(constants.SIDEBAR_PUBLISHER):
 | 
			
		||||
        entries = 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()) \
 | 
			
		||||
            .group_by(text('books_publishers_link.publisher')).order_by(db.Publishers.name).all()
 | 
			
		||||
        charlist = 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()) \
 | 
			
		||||
            .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,
 | 
			
		||||
@@ -860,19 +861,19 @@ def publisher_list():
 | 
			
		||||
def series_list():
 | 
			
		||||
    if current_user.check_visibility(constants.SIDEBAR_SERIES):
 | 
			
		||||
        if current_user.series_view == 'list':
 | 
			
		||||
            entries = 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()) \
 | 
			
		||||
                .group_by(text('books_series_link.series')).order_by(db.Series.sort).all()
 | 
			
		||||
            charlist = 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()) \
 | 
			
		||||
                .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,
 | 
			
		||||
                                         title=_(u"Series"), page="serieslist", data="series")
 | 
			
		||||
        else:
 | 
			
		||||
            entries = 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()) \
 | 
			
		||||
                .group_by(text('books_series_link.series')).order_by(db.Series.sort).all()
 | 
			
		||||
            charlist = 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()) \
 | 
			
		||||
                .group_by(func.upper(func.substr(db.Series.sort, 1, 1))).all()
 | 
			
		||||
 | 
			
		||||
@@ -886,9 +887,9 @@ def series_list():
 | 
			
		||||
@login_required_if_no_ano
 | 
			
		||||
def ratings_list():
 | 
			
		||||
    if current_user.check_visibility(constants.SIDEBAR_RATING):
 | 
			
		||||
        entries = 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')) \
 | 
			
		||||
            .join(db.books_ratings_link).join(db.Books).filter(common_filters()) \
 | 
			
		||||
            .join(calibre_db.books_ratings_link).join(db.Books).filter(common_filters()) \
 | 
			
		||||
            .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(),
 | 
			
		||||
                                     title=_(u"Ratings list"), page="ratingslist", data="ratings")
 | 
			
		||||
@@ -900,7 +901,7 @@ def ratings_list():
 | 
			
		||||
@login_required_if_no_ano
 | 
			
		||||
def formats_list():
 | 
			
		||||
    if current_user.check_visibility(constants.SIDEBAR_FORMAT):
 | 
			
		||||
        entries = db.session.query(db.Data, func.count('data.book').label('count'), db.Data.format.label('format')) \
 | 
			
		||||
        entries = calibre_db.session.query(db.Data, func.count('data.book').label('count'), db.Data.format.label('format')) \
 | 
			
		||||
            .join(db.Books).filter(common_filters()) \
 | 
			
		||||
            .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(),
 | 
			
		||||
@@ -922,13 +923,13 @@ def language_overview():
 | 
			
		||||
                cur_l = LC.parse(current_user.filter_language())
 | 
			
		||||
            except UnknownLocaleError:
 | 
			
		||||
                cur_l = None
 | 
			
		||||
            languages = db.session.query(db.Languages).filter(
 | 
			
		||||
            languages = calibre_db.session.query(db.Languages).filter(
 | 
			
		||||
                db.Languages.lang_code == current_user.filter_language()).all()
 | 
			
		||||
            if cur_l:
 | 
			
		||||
                languages[0].name = cur_l.get_language_name(get_locale())
 | 
			
		||||
            else:
 | 
			
		||||
                languages[0].name = _(isoLanguages.get(part3=languages[0].lang_code).name)
 | 
			
		||||
        lang_counter = db.session.query(db.books_languages_link,
 | 
			
		||||
        lang_counter = calibre_db.session.query(db.books_languages_link,
 | 
			
		||||
                                        func.count('books_languages_link.book').label('bookcount')).group_by(
 | 
			
		||||
            text('books_languages_link.lang_code')).all()
 | 
			
		||||
        return render_title_template('languages.html', languages=languages, lang_counter=lang_counter,
 | 
			
		||||
@@ -942,10 +943,10 @@ def language_overview():
 | 
			
		||||
@login_required_if_no_ano
 | 
			
		||||
def category_list():
 | 
			
		||||
    if current_user.check_visibility(constants.SIDEBAR_CATEGORY):
 | 
			
		||||
        entries = 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()) \
 | 
			
		||||
            .group_by(text('books_tags_link.tag')).all()
 | 
			
		||||
        charlist = 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()) \
 | 
			
		||||
            .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,
 | 
			
		||||
@@ -1003,8 +1004,8 @@ def search():
 | 
			
		||||
def advanced_search():
 | 
			
		||||
    # Build custom columns names
 | 
			
		||||
    cc = get_cc_columns()
 | 
			
		||||
    db.session.connection().connection.connection.create_function("lower", 1, lcase)
 | 
			
		||||
    q = db.session.query(db.Books).filter(common_filters()).order_by(db.Books.sort)
 | 
			
		||||
    calibre_db.session.connection().connection.connection.create_function("lower", 1, lcase)
 | 
			
		||||
    q = calibre_db.session.query(db.Books).filter(common_filters()).order_by(db.Books.sort)
 | 
			
		||||
 | 
			
		||||
    include_tag_inputs = request.args.getlist('include_tag')
 | 
			
		||||
    exclude_tag_inputs = request.args.getlist('exclude_tag')
 | 
			
		||||
@@ -1057,11 +1058,11 @@ def advanced_search():
 | 
			
		||||
                                               format='medium', locale=get_locale())])
 | 
			
		||||
            except ValueError:
 | 
			
		||||
                pub_start = u""
 | 
			
		||||
        tag_names = db.session.query(db.Tags).filter(db.Tags.id.in_(include_tag_inputs)).all()
 | 
			
		||||
        tag_names = calibre_db.session.query(db.Tags).filter(db.Tags.id.in_(include_tag_inputs)).all()
 | 
			
		||||
        searchterm.extend(tag.name for tag in tag_names)
 | 
			
		||||
        serie_names = db.session.query(db.Series).filter(db.Series.id.in_(include_series_inputs)).all()
 | 
			
		||||
        serie_names = calibre_db.session.query(db.Series).filter(db.Series.id.in_(include_series_inputs)).all()
 | 
			
		||||
        searchterm.extend(serie.name for serie in serie_names)
 | 
			
		||||
        language_names = 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:
 | 
			
		||||
            language_names = speaking_language(language_names)
 | 
			
		||||
        searchterm.extend(language.name for language in language_names)
 | 
			
		||||
@@ -1136,11 +1137,11 @@ def advanced_search():
 | 
			
		||||
        return render_title_template('search.html', adv_searchterm=searchterm,
 | 
			
		||||
                                     entries=q, title=_(u"search"), page="search")
 | 
			
		||||
    # prepare data for search-form
 | 
			
		||||
    tags = 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(common_filters()) \
 | 
			
		||||
        .group_by(text('books_tags_link.tag')).order_by(db.Tags.name).all()
 | 
			
		||||
    series = 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(common_filters()) \
 | 
			
		||||
        .group_by(text('books_series_link.series')).order_by(db.Series.name).filter(common_filters()).all()
 | 
			
		||||
    extensions = db.session.query(db.Data).join(db.Books).filter(common_filters()) \
 | 
			
		||||
    extensions = calibre_db.session.query(db.Data).join(db.Books).filter(common_filters()) \
 | 
			
		||||
        .group_by(db.Data.format).order_by(db.Data.format).all()
 | 
			
		||||
 | 
			
		||||
    if current_user.filter_language() == u"all":
 | 
			
		||||
@@ -1229,8 +1230,8 @@ def get_cover(book_id):
 | 
			
		||||
@viewer_required
 | 
			
		||||
def serve_book(book_id, book_format, anyname):
 | 
			
		||||
    book_format = book_format.split(".")[0]
 | 
			
		||||
    book = db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
    data = db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper()) \
 | 
			
		||||
    book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).first()
 | 
			
		||||
    data = calibre_db.session.query(db.Data).filter(db.Data.book == book.id).filter(db.Data.format == book_format.upper()) \
 | 
			
		||||
        .first()
 | 
			
		||||
    log.info('Serving book: %s', data.name)
 | 
			
		||||
    if config.config_use_google_drive:
 | 
			
		||||
@@ -1522,9 +1523,9 @@ def profile():
 | 
			
		||||
        oauth_status = None
 | 
			
		||||
 | 
			
		||||
    for book in current_user.downloads:
 | 
			
		||||
        downloadBook = db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
 | 
			
		||||
        downloadBook = calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).first()
 | 
			
		||||
        if downloadBook:
 | 
			
		||||
            downloads.append(db.session.query(db.Books).filter(db.Books.id == book.book_id).first())
 | 
			
		||||
            downloads.append(calibre_db.session.query(db.Books).filter(db.Books.id == book.book_id).first())
 | 
			
		||||
        else:
 | 
			
		||||
            ub.delete_download(book.book_id)
 | 
			
		||||
    if request.method == "POST":
 | 
			
		||||
@@ -1603,7 +1604,7 @@ def profile():
 | 
			
		||||
@login_required_if_no_ano
 | 
			
		||||
@viewer_required
 | 
			
		||||
def read_book(book_id, book_format):
 | 
			
		||||
    book = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
 | 
			
		||||
    book = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
 | 
			
		||||
    if not book:
 | 
			
		||||
        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:")
 | 
			
		||||
@@ -1627,7 +1628,7 @@ def read_book(book_id, book_format):
 | 
			
		||||
    else:
 | 
			
		||||
        for fileExt in constants.EXTENSIONS_AUDIO:
 | 
			
		||||
            if book_format.lower() == fileExt:
 | 
			
		||||
                entries = db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
 | 
			
		||||
                entries = calibre_db.session.query(db.Books).filter(db.Books.id == book_id).filter(common_filters()).first()
 | 
			
		||||
                log.debug(u"Start mp3 listening for %d", book_id)
 | 
			
		||||
                return render_title_template('listenmp3.html', mp3file=book_id, audioformat=book_format.lower(),
 | 
			
		||||
                                             title=_(u"Read a Book"), entry=entries, bookmark=bookmark)
 | 
			
		||||
@@ -1653,7 +1654,7 @@ def read_book(book_id, book_format):
 | 
			
		||||
@web.route("/book/<int:book_id>")
 | 
			
		||||
@login_required_if_no_ano
 | 
			
		||||
def show_book(book_id):
 | 
			
		||||
    entries = db.session.query(db.Books).filter(and_(db.Books.id == book_id,
 | 
			
		||||
    entries = calibre_db.session.query(db.Books).filter(and_(db.Books.id == book_id,
 | 
			
		||||
                                                     common_filters(allow_show_archived=True))).first()
 | 
			
		||||
    if entries:
 | 
			
		||||
        for index in range(0, len(entries.languages)):
 | 
			
		||||
 
 | 
			
		||||
@@ -24,10 +24,10 @@ import smtplib
 | 
			
		||||
import socket
 | 
			
		||||
import time
 | 
			
		||||
import threading
 | 
			
		||||
import queue
 | 
			
		||||
from glob import glob
 | 
			
		||||
from shutil import copyfile
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from sqlalchemy.exc import OperationalError
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    from StringIO import StringIO
 | 
			
		||||
@@ -46,7 +46,8 @@ from email.utils import make_msgid
 | 
			
		||||
from email.generator import Generator
 | 
			
		||||
from flask_babel import gettext as _
 | 
			
		||||
 | 
			
		||||
from . import db, logger, config
 | 
			
		||||
from . import calibre_db, db
 | 
			
		||||
from . import logger, config
 | 
			
		||||
from .subproc_wrapper import process_open
 | 
			
		||||
from . import gdriveutils
 | 
			
		||||
 | 
			
		||||
@@ -190,6 +191,8 @@ class WorkerThread(threading.Thread):
 | 
			
		||||
        self.UIqueue = list()
 | 
			
		||||
        self.asyncSMTP = None
 | 
			
		||||
        self.id = 0
 | 
			
		||||
        self.db_queue = queue.Queue()
 | 
			
		||||
        calibre_db.add_queue(self.db_queue)
 | 
			
		||||
        self.doLock = threading.Lock()
 | 
			
		||||
 | 
			
		||||
    # Main thread loop starting the different tasks
 | 
			
		||||
@@ -275,6 +278,18 @@ class WorkerThread(threading.Thread):
 | 
			
		||||
        self.doLock.acquire()
 | 
			
		||||
        index = self.current
 | 
			
		||||
        self.doLock.release()
 | 
			
		||||
        '''dbpath = os.path.join(config.config_calibre_dir, "metadata.db")
 | 
			
		||||
        engine = create_engine('sqlite://',
 | 
			
		||||
                               echo=False,
 | 
			
		||||
                               isolation_level="SERIALIZABLE",
 | 
			
		||||
                               connect_args={'check_same_thread': True})
 | 
			
		||||
        engine.execute("attach database '{}' as calibre;".format(dbpath))
 | 
			
		||||
        conn = engine.connect()
 | 
			
		||||
        Session = scoped_session(sessionmaker(autocommit=False,
 | 
			
		||||
                                              autoflush=False,
 | 
			
		||||
                                              bind=engine))
 | 
			
		||||
        w_session = Session()
 | 
			
		||||
        engine.execute("attach database '{}' as calibre;".format(dbpath))'''
 | 
			
		||||
        file_path = self.queue[index]['file_path']
 | 
			
		||||
        bookid = self.queue[index]['bookid']
 | 
			
		||||
        format_old_ext = u'.' + self.queue[index]['settings']['old_book_format'].lower()
 | 
			
		||||
@@ -285,7 +300,7 @@ class WorkerThread(threading.Thread):
 | 
			
		||||
        # this will allow send to kindle workflow to continue to work
 | 
			
		||||
        if os.path.isfile(file_path + format_new_ext):
 | 
			
		||||
            log.info("Book id %d already converted to %s", bookid, format_new_ext)
 | 
			
		||||
            cur_book = db.session.query(db.Books).filter(db.Books.id == bookid).first()
 | 
			
		||||
            cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == bookid).first()
 | 
			
		||||
            self.queue[index]['path'] = file_path
 | 
			
		||||
            self.queue[index]['title'] = cur_book.title
 | 
			
		||||
            self._handleSuccess()
 | 
			
		||||
@@ -309,19 +324,26 @@ class WorkerThread(threading.Thread):
 | 
			
		||||
            check, error_message = self._convert_calibre(file_path, format_old_ext, format_new_ext, index)
 | 
			
		||||
 | 
			
		||||
        if check == 0:
 | 
			
		||||
            cur_book = db.session.query(db.Books).filter(db.Books.id == bookid).first()
 | 
			
		||||
            cur_book = calibre_db.session.query(db.Books).filter(db.Books.id == bookid).first()
 | 
			
		||||
            if os.path.isfile(file_path + format_new_ext):
 | 
			
		||||
                # self.db_queue.join()
 | 
			
		||||
                new_format = db.Data(name=cur_book.data[0].name,
 | 
			
		||||
                                         book_format=self.queue[index]['settings']['new_book_format'].upper(),
 | 
			
		||||
                                         book=bookid, uncompressed_size=os.path.getsize(file_path + format_new_ext))
 | 
			
		||||
                cur_book.data.append(new_format)
 | 
			
		||||
                task = {'task':'add_format','id': bookid, 'format': new_format}
 | 
			
		||||
                self.db_queue.put(task)
 | 
			
		||||
                # To Do how to handle error?
 | 
			
		||||
                print('finished')
 | 
			
		||||
 | 
			
		||||
                '''cur_book.data.append(new_format)
 | 
			
		||||
                try:
 | 
			
		||||
                    db.session.commit()
 | 
			
		||||
                    # db.session.merge(cur_book)
 | 
			
		||||
                    calibre_db.session.commit()
 | 
			
		||||
                except OperationalError as e:
 | 
			
		||||
                    db.session.rollback()
 | 
			
		||||
                    calibre_db.session.rollback()
 | 
			
		||||
                    log.error("Database error: %s", e)
 | 
			
		||||
                    self._handleError(_(u"Database error: %(error)s.", error=e))
 | 
			
		||||
                    return
 | 
			
		||||
                    return'''
 | 
			
		||||
 | 
			
		||||
                self.queue[index]['path'] = cur_book.path
 | 
			
		||||
                self.queue[index]['title'] = cur_book.title
 | 
			
		||||
@@ -375,6 +397,7 @@ class WorkerThread(threading.Thread):
 | 
			
		||||
        # process returncode
 | 
			
		||||
        check = p.returncode
 | 
			
		||||
        calibre_traceback = p.stderr.readlines()
 | 
			
		||||
        error_message = ""
 | 
			
		||||
        for ele in calibre_traceback:
 | 
			
		||||
            if sys.version_info < (3, 0):
 | 
			
		||||
                ele = ele.decode('utf-8')
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user