Working again (basically)
This commit is contained in:
parent
561d40f8ff
commit
a00d93a2d9
15
cps.py
15
cps.py
|
@ -1,21 +1,16 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
|
from cps import create_app
|
||||||
base_path = os.path.dirname(os.path.abspath(__file__))
|
from cps.web import web
|
||||||
# Insert local directories into path
|
from cps import Server
|
||||||
sys.path.append(base_path)
|
|
||||||
sys.path.append(os.path.join(base_path, 'cps'))
|
|
||||||
sys.path.append(os.path.join(base_path, 'vendor'))
|
|
||||||
|
|
||||||
from cps.server import Server
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
app = create_app()
|
||||||
|
app.register_blueprint(web)
|
||||||
Server.startServer()
|
Server.startServer()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,85 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# import logging
|
||||||
|
# from logging.handlers import SMTPHandler, RotatingFileHandler
|
||||||
|
# import os
|
||||||
|
|
||||||
|
from flask import Flask# , request, current_app
|
||||||
|
from flask_login import LoginManager
|
||||||
|
from flask_babel import Babel # , lazy_gettext as _l
|
||||||
|
import cache_buster
|
||||||
|
from reverseproxy import ReverseProxied
|
||||||
|
import logging
|
||||||
|
from logging.handlers import RotatingFileHandler
|
||||||
|
from flask_principal import Principal
|
||||||
|
# from flask_sqlalchemy import SQLAlchemy
|
||||||
|
import os
|
||||||
|
import ub
|
||||||
|
from ub import Config, Settings
|
||||||
|
import cPickle
|
||||||
|
|
||||||
|
|
||||||
|
# Normal
|
||||||
|
babel = Babel()
|
||||||
|
lm = LoginManager()
|
||||||
|
lm.login_view = 'web.login'
|
||||||
|
lm.anonymous_user = ub.Anonymous
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ub_session = ub.session
|
||||||
|
# ub_session.start()
|
||||||
|
config = Config()
|
||||||
|
|
||||||
|
|
||||||
|
import db
|
||||||
|
|
||||||
|
with open(os.path.join(config.get_main_dir, 'cps/translations/iso639.pickle'), 'rb') as f:
|
||||||
|
language_table = cPickle.load(f)
|
||||||
|
|
||||||
|
searched_ids = {}
|
||||||
|
|
||||||
|
|
||||||
|
from worker import WorkerThread
|
||||||
|
|
||||||
|
global_WorkerThread = WorkerThread()
|
||||||
|
|
||||||
|
from server import server
|
||||||
|
Server = server()
|
||||||
|
|
||||||
|
|
||||||
|
def create_app():
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.wsgi_app = ReverseProxied(app.wsgi_app)
|
||||||
|
cache_buster.init_cache_busting(app)
|
||||||
|
|
||||||
|
formatter = logging.Formatter(
|
||||||
|
"[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s")
|
||||||
|
try:
|
||||||
|
file_handler = RotatingFileHandler(config.get_config_logfile(), maxBytes=50000, backupCount=2)
|
||||||
|
except IOError:
|
||||||
|
file_handler = RotatingFileHandler(os.path.join(config.get_main_dir, "calibre-web.log"),
|
||||||
|
maxBytes=50000, backupCount=2)
|
||||||
|
# ToDo: reset logfile value in config class
|
||||||
|
file_handler.setFormatter(formatter)
|
||||||
|
app.logger.addHandler(file_handler)
|
||||||
|
app.logger.setLevel(config.config_log_level)
|
||||||
|
|
||||||
|
app.logger.info('Starting Calibre Web...')
|
||||||
|
logging.getLogger("book_formats").addHandler(file_handler)
|
||||||
|
logging.getLogger("book_formats").setLevel(config.config_log_level)
|
||||||
|
Principal(app)
|
||||||
|
lm.init_app(app)
|
||||||
|
babel.init_app(app)
|
||||||
|
app.secret_key = os.getenv('SECRET_KEY', 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT')
|
||||||
|
Server.init_app(app)
|
||||||
|
db.setup_db()
|
||||||
|
global_WorkerThread.start()
|
||||||
|
|
||||||
|
# app.config.from_object(config_class)
|
||||||
|
# db.init_app(app)
|
||||||
|
# login.init_app(app)
|
||||||
|
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
|
@ -24,7 +24,7 @@ from sqlalchemy.orm import *
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import ast
|
import ast
|
||||||
from ub import config
|
from cps import config
|
||||||
import ub
|
import ub
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ except ImportError:
|
||||||
gdrive_support = False
|
gdrive_support = False
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from ub import config
|
from cps import config
|
||||||
import cli
|
import cli
|
||||||
import shutil
|
import shutil
|
||||||
from flask import Response, stream_with_context
|
from flask import Response, stream_with_context
|
||||||
|
|
|
@ -20,14 +20,13 @@
|
||||||
|
|
||||||
|
|
||||||
import db
|
import db
|
||||||
import ub
|
from cps import config
|
||||||
from flask import current_app as app
|
from flask import current_app as app
|
||||||
from tempfile import gettempdir
|
from tempfile import gettempdir
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import unicodedata
|
import unicodedata
|
||||||
# from io import BytesIO
|
|
||||||
import worker
|
import worker
|
||||||
import time
|
import time
|
||||||
from flask import send_from_directory, make_response, redirect, abort
|
from flask import send_from_directory, make_response, redirect, abort
|
||||||
|
@ -41,9 +40,10 @@ try:
|
||||||
import gdriveutils as gd
|
import gdriveutils as gd
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
import web
|
# import web
|
||||||
import random
|
import random
|
||||||
from subproc_wrapper import process_open
|
from subproc_wrapper import process_open
|
||||||
|
import ub
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import unidecode
|
import unidecode
|
||||||
|
@ -51,11 +51,6 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
use_unidecode = False
|
use_unidecode = False
|
||||||
|
|
||||||
# Global variables
|
|
||||||
# updater_thread = None
|
|
||||||
global_WorkerThread = worker.WorkerThread()
|
|
||||||
global_WorkerThread.start()
|
|
||||||
|
|
||||||
|
|
||||||
def update_download(book_id, user_id):
|
def update_download(book_id, user_id):
|
||||||
check = ub.session.query(ub.Downloads).filter(ub.Downloads.user_id == user_id).filter(ub.Downloads.book_id ==
|
check = ub.session.query(ub.Downloads).filter(ub.Downloads.user_id == user_id).filter(ub.Downloads.book_id ==
|
||||||
|
@ -73,7 +68,7 @@ def convert_book_format(book_id, calibrepath, old_book_format, new_book_format,
|
||||||
error_message = _(u"%(format)s format not found for book id: %(book)d", format=old_book_format, book=book_id)
|
error_message = _(u"%(format)s format not found for book id: %(book)d", format=old_book_format, book=book_id)
|
||||||
app.logger.error("convert_book_format: " + error_message)
|
app.logger.error("convert_book_format: " + error_message)
|
||||||
return error_message
|
return error_message
|
||||||
if ub.config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
df = gd.getFileFromEbooksFolder(book.path, data.name + "." + old_book_format.lower())
|
df = gd.getFileFromEbooksFolder(book.path, data.name + "." + old_book_format.lower())
|
||||||
if df:
|
if df:
|
||||||
datafile = os.path.join(calibrepath, book.path, data.name + u"." + old_book_format.lower())
|
datafile = os.path.join(calibrepath, book.path, data.name + u"." + old_book_format.lower())
|
||||||
|
@ -133,7 +128,7 @@ def check_send_to_kindle(entry):
|
||||||
"""
|
"""
|
||||||
if len(entry.data):
|
if len(entry.data):
|
||||||
bookformats=list()
|
bookformats=list()
|
||||||
if ub.config.config_ebookconverter == 0:
|
if config.config_ebookconverter == 0:
|
||||||
# no converter - only for mobi and pdf formats
|
# no converter - only for mobi and pdf formats
|
||||||
for ele in iter(entry.data):
|
for ele in iter(entry.data):
|
||||||
if 'MOBI' in ele.format:
|
if 'MOBI' in ele.format:
|
||||||
|
@ -156,11 +151,11 @@ def check_send_to_kindle(entry):
|
||||||
bookformats.append({'format': 'Azw3','convert':0,'text':_('Send %(format)s to Kindle',format='Azw3')})
|
bookformats.append({'format': 'Azw3','convert':0,'text':_('Send %(format)s to Kindle',format='Azw3')})
|
||||||
if 'PDF' in formats:
|
if 'PDF' in formats:
|
||||||
bookformats.append({'format': 'Pdf','convert':0,'text':_('Send %(format)s to Kindle',format='Pdf')})
|
bookformats.append({'format': 'Pdf','convert':0,'text':_('Send %(format)s to Kindle',format='Pdf')})
|
||||||
if ub.config.config_ebookconverter >= 1:
|
if config.config_ebookconverter >= 1:
|
||||||
if 'EPUB' in formats and not 'MOBI' in formats:
|
if 'EPUB' in formats and not 'MOBI' in formats:
|
||||||
bookformats.append({'format': 'Mobi','convert':1,
|
bookformats.append({'format': 'Mobi','convert':1,
|
||||||
'text':_('Convert %(orig)s to %(format)s and send to Kindle',orig='Epub',format='Mobi')})
|
'text':_('Convert %(orig)s to %(format)s and send to Kindle',orig='Epub',format='Mobi')})
|
||||||
if ub.config.config_ebookconverter == 2:
|
if config.config_ebookconverter == 2:
|
||||||
if 'EPUB' in formats and not 'AZW3' in formats:
|
if 'EPUB' in formats and not 'AZW3' in formats:
|
||||||
bookformats.append({'format': 'Azw3','convert':1,
|
bookformats.append({'format': 'Azw3','convert':1,
|
||||||
'text':_('Convert %(orig)s to %(format)s and send to Kindle',orig='Epub',format='Azw3')})
|
'text':_('Convert %(orig)s to %(format)s and send to Kindle',orig='Epub',format='Azw3')})
|
||||||
|
@ -407,21 +402,21 @@ def generate_random_password():
|
||||||
################################## External interface
|
################################## External interface
|
||||||
|
|
||||||
def update_dir_stucture(book_id, calibrepath, first_author = None):
|
def update_dir_stucture(book_id, calibrepath, first_author = None):
|
||||||
if ub.config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
return update_dir_structure_gdrive(book_id, first_author)
|
return update_dir_structure_gdrive(book_id, first_author)
|
||||||
else:
|
else:
|
||||||
return update_dir_structure_file(book_id, calibrepath, first_author)
|
return update_dir_structure_file(book_id, calibrepath, first_author)
|
||||||
|
|
||||||
|
|
||||||
def delete_book(book, calibrepath, book_format):
|
def delete_book(book, calibrepath, book_format):
|
||||||
if ub.config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
return delete_book_gdrive(book, book_format)
|
return delete_book_gdrive(book, book_format)
|
||||||
else:
|
else:
|
||||||
return delete_book_file(book, calibrepath, book_format)
|
return delete_book_file(book, calibrepath, book_format)
|
||||||
|
|
||||||
|
|
||||||
def get_book_cover(cover_path):
|
def get_book_cover(cover_path):
|
||||||
if ub.config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
try:
|
try:
|
||||||
if not web.is_gdrive_ready():
|
if not web.is_gdrive_ready():
|
||||||
return send_from_directory(os.path.join(os.path.dirname(__file__), "static"), "generic_cover.jpg")
|
return send_from_directory(os.path.join(os.path.dirname(__file__), "static"), "generic_cover.jpg")
|
||||||
|
@ -437,7 +432,7 @@ def get_book_cover(cover_path):
|
||||||
# traceback.print_exc()
|
# traceback.print_exc()
|
||||||
return send_from_directory(os.path.join(os.path.dirname(__file__), "static"),"generic_cover.jpg")
|
return send_from_directory(os.path.join(os.path.dirname(__file__), "static"),"generic_cover.jpg")
|
||||||
else:
|
else:
|
||||||
return send_from_directory(os.path.join(ub.config.config_calibre_dir, cover_path), "cover.jpg")
|
return send_from_directory(os.path.join(config.config_calibre_dir, cover_path), "cover.jpg")
|
||||||
|
|
||||||
|
|
||||||
# saves book cover to gdrive or locally
|
# saves book cover to gdrive or locally
|
||||||
|
@ -447,7 +442,7 @@ def save_cover(url, book_path):
|
||||||
web.app.logger.error("Cover is no jpg file, can't save")
|
web.app.logger.error("Cover is no jpg file, can't save")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if ub.config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
tmpDir = gettempdir()
|
tmpDir = gettempdir()
|
||||||
f = open(os.path.join(tmpDir, "uploaded_cover.jpg"), "wb")
|
f = open(os.path.join(tmpDir, "uploaded_cover.jpg"), "wb")
|
||||||
f.write(img.content)
|
f.write(img.content)
|
||||||
|
@ -456,7 +451,7 @@ def save_cover(url, book_path):
|
||||||
web.app.logger.info("Cover is saved on Google Drive")
|
web.app.logger.info("Cover is saved on Google Drive")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
f = open(os.path.join(ub.config.config_calibre_dir, book_path, "cover.jpg"), "wb")
|
f = open(os.path.join(config.config_calibre_dir, book_path, "cover.jpg"), "wb")
|
||||||
f.write(img.content)
|
f.write(img.content)
|
||||||
f.close()
|
f.close()
|
||||||
web.app.logger.info("Cover is saved")
|
web.app.logger.info("Cover is saved")
|
||||||
|
@ -464,7 +459,7 @@ def save_cover(url, book_path):
|
||||||
|
|
||||||
|
|
||||||
def do_download_file(book, book_format, data, headers):
|
def do_download_file(book, book_format, data, headers):
|
||||||
if ub.config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
startTime = time.time()
|
startTime = time.time()
|
||||||
df = gd.getFileFromEbooksFolder(book.path, data.name + "." + book_format)
|
df = gd.getFileFromEbooksFolder(book.path, data.name + "." + book_format)
|
||||||
web.app.logger.debug(time.time() - startTime)
|
web.app.logger.debug(time.time() - startTime)
|
||||||
|
@ -473,7 +468,7 @@ def do_download_file(book, book_format, data, headers):
|
||||||
else:
|
else:
|
||||||
abort(404)
|
abort(404)
|
||||||
else:
|
else:
|
||||||
filename = os.path.join(ub.config.config_calibre_dir, book.path)
|
filename = os.path.join(config.config_calibre_dir, book.path)
|
||||||
if not os.path.isfile(os.path.join(filename, data.name + "." + book_format)):
|
if not os.path.isfile(os.path.join(filename, data.name + "." + book_format)):
|
||||||
# ToDo: improve error handling
|
# ToDo: improve error handling
|
||||||
web.app.logger.error('File not found: %s' % os.path.join(filename, data.name + "." + book_format))
|
web.app.logger.error('File not found: %s' % os.path.join(filename, data.name + "." + book_format))
|
||||||
|
|
75
cps/pagination.py
Normal file
75
cps/pagination.py
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
|
||||||
|
# Copyright (C) 2018-2019 OzzieIsaacs, cervinko, jkrehm, bodybybuddha, ok11,
|
||||||
|
# andy29485, idalin, Kyosfonica, wuqi, Kennyl, lemmsh,
|
||||||
|
# falgh1, grunjol, csitko, ytils, xybydy, trasba, vrabe,
|
||||||
|
# ruben-herold, marblepebble, JackED42, SiphonSquirrel,
|
||||||
|
# apetresc, nanu-c, mutschler
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from math import ceil
|
||||||
|
|
||||||
|
# simple pagination for the feed
|
||||||
|
class Pagination(object):
|
||||||
|
def __init__(self, page, per_page, total_count):
|
||||||
|
self.page = int(page)
|
||||||
|
self.per_page = int(per_page)
|
||||||
|
self.total_count = int(total_count)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def next_offset(self):
|
||||||
|
return int(self.page * self.per_page)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def previous_offset(self):
|
||||||
|
return int((self.page - 2) * self.per_page)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def last_offset(self):
|
||||||
|
last = int(self.total_count) - int(self.per_page)
|
||||||
|
if last < 0:
|
||||||
|
last = 0
|
||||||
|
return int(last)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pages(self):
|
||||||
|
return int(ceil(self.total_count / float(self.per_page)))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_prev(self):
|
||||||
|
return self.page > 1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_next(self):
|
||||||
|
return self.page < self.pages
|
||||||
|
|
||||||
|
# right_edge: last right_edges count of all pages are shown as number, means, if 10 pages are paginated -> 9,10 shwn
|
||||||
|
# left_edge: first left_edges count of all pages are shown as number -> 1,2 shwn
|
||||||
|
# left_current: left_current count below current page are shown as number, means if current page 5 -> 3,4 shwn
|
||||||
|
# left_current: right_current count above current page are shown as number, means if current page 5 -> 6,7 shwn
|
||||||
|
def iter_pages(self, left_edge=2, left_current=2,
|
||||||
|
right_current=4, right_edge=2):
|
||||||
|
last = 0
|
||||||
|
left_current = self.page - left_current - 1
|
||||||
|
right_current = self.page + right_current + 1
|
||||||
|
right_edge = self.pages - right_edge
|
||||||
|
for num in range(1, (self.pages + 1)):
|
||||||
|
if num <= left_edge or (left_current < num < right_current) or num > right_edge:
|
||||||
|
if last + 1 != num:
|
||||||
|
yield None
|
||||||
|
yield num
|
||||||
|
last = num
|
|
@ -22,7 +22,7 @@ from socket import error as SocketError
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
import web
|
from cps import config, global_WorkerThread
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from gevent.pywsgi import WSGIServer
|
from gevent.pywsgi import WSGIServer
|
||||||
|
@ -42,82 +42,81 @@ class server:
|
||||||
|
|
||||||
wsgiserver = None
|
wsgiserver = None
|
||||||
restart= False
|
restart= False
|
||||||
|
app = None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
signal.signal(signal.SIGINT, self.killServer)
|
signal.signal(signal.SIGINT, self.killServer)
|
||||||
signal.signal(signal.SIGTERM, self.killServer)
|
signal.signal(signal.SIGTERM, self.killServer)
|
||||||
|
|
||||||
|
def init_app(self,application):
|
||||||
|
self.app = application
|
||||||
|
|
||||||
def start_gevent(self):
|
def start_gevent(self):
|
||||||
try:
|
try:
|
||||||
ssl_args = dict()
|
ssl_args = dict()
|
||||||
certfile_path = web.ub.config.get_config_certfile()
|
certfile_path = config.get_config_certfile()
|
||||||
keyfile_path = web.ub.config.get_config_keyfile()
|
keyfile_path = config.get_config_keyfile()
|
||||||
if certfile_path and keyfile_path:
|
if certfile_path and keyfile_path:
|
||||||
if os.path.isfile(certfile_path) and os.path.isfile(keyfile_path):
|
if os.path.isfile(certfile_path) and os.path.isfile(keyfile_path):
|
||||||
ssl_args = {"certfile": certfile_path,
|
ssl_args = {"certfile": certfile_path,
|
||||||
"keyfile": keyfile_path}
|
"keyfile": keyfile_path}
|
||||||
else:
|
else:
|
||||||
web.app.logger.info('The specified paths for the ssl certificate file and/or key file seem to be broken. Ignoring ssl. Cert path: %s | Key path: %s' % (certfile_path, keyfile_path))
|
self.app.logger.info('The specified paths for the ssl certificate file and/or key file seem to be broken. Ignoring ssl. Cert path: %s | Key path: %s' % (certfile_path, keyfile_path))
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
self.wsgiserver= WSGIServer(('0.0.0.0', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args)
|
self.wsgiserver= WSGIServer(('0.0.0.0', config.config_port), self.app, spawn=Pool(), **ssl_args)
|
||||||
else:
|
else:
|
||||||
self.wsgiserver = WSGIServer(('', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args)
|
self.wsgiserver = WSGIServer(('', config.config_port), self.app, spawn=Pool(), **ssl_args)
|
||||||
web.py3_gevent_link = self.wsgiserver
|
|
||||||
self.wsgiserver.serve_forever()
|
self.wsgiserver.serve_forever()
|
||||||
|
|
||||||
except SocketError:
|
except SocketError:
|
||||||
try:
|
try:
|
||||||
web.app.logger.info('Unable to listen on \'\', trying on IPv4 only...')
|
self.app.logger.info('Unable to listen on \'\', trying on IPv4 only...')
|
||||||
self.wsgiserver = WSGIServer(('0.0.0.0', web.ub.config.config_port), web.app, spawn=Pool(), **ssl_args)
|
self.wsgiserver = WSGIServer(('0.0.0.0', config.config_port), self.app, spawn=Pool(), **ssl_args)
|
||||||
web.py3_gevent_link = self.wsgiserver
|
|
||||||
self.wsgiserver.serve_forever()
|
self.wsgiserver.serve_forever()
|
||||||
except (OSError, SocketError) as e:
|
except (OSError, SocketError) as e:
|
||||||
web.app.logger.info("Error starting server: %s" % e.strerror)
|
self.app.logger.info("Error starting server: %s" % e.strerror)
|
||||||
print("Error starting server: %s" % e.strerror)
|
print("Error starting server: %s" % e.strerror)
|
||||||
web.helper.global_WorkerThread.stop()
|
global_WorkerThread.stop()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except Exception:
|
except Exception:
|
||||||
web.app.logger.info("Unknown error while starting gevent")
|
self.app.logger.info("Unknown error while starting gevent")
|
||||||
|
|
||||||
def startServer(self):
|
def startServer(self):
|
||||||
if gevent_present:
|
if gevent_present:
|
||||||
web.app.logger.info('Starting Gevent server')
|
self.app.logger.info('Starting Gevent server')
|
||||||
# leave subprocess out to allow forking for fetchers and processors
|
# leave subprocess out to allow forking for fetchers and processors
|
||||||
self.start_gevent()
|
self.start_gevent()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
ssl = None
|
ssl = None
|
||||||
web.app.logger.info('Starting Tornado server')
|
self.app.logger.info('Starting Tornado server')
|
||||||
certfile_path = web.ub.config.get_config_certfile()
|
certfile_path = config.get_config_certfile()
|
||||||
keyfile_path = web.ub.config.get_config_keyfile()
|
keyfile_path = config.get_config_keyfile()
|
||||||
if certfile_path and keyfile_path:
|
if certfile_path and keyfile_path:
|
||||||
if os.path.isfile(certfile_path) and os.path.isfile(keyfile_path):
|
if os.path.isfile(certfile_path) and os.path.isfile(keyfile_path):
|
||||||
ssl = {"certfile": certfile_path,
|
ssl = {"certfile": certfile_path,
|
||||||
"keyfile": keyfile_path}
|
"keyfile": keyfile_path}
|
||||||
else:
|
else:
|
||||||
web.app.logger.info('The specified paths for the ssl certificate file and/or key file seem to be broken. Ignoring ssl. Cert path: %s | Key path: %s' % (certfile_path, keyfile_path))
|
self.app.logger.info('The specified paths for the ssl certificate file and/or key file seem to be broken. Ignoring ssl. Cert path: %s | Key path: %s' % (certfile_path, keyfile_path))
|
||||||
|
|
||||||
# Max Buffersize set to 200MB
|
# Max Buffersize set to 200MB
|
||||||
http_server = HTTPServer(WSGIContainer(web.app),
|
http_server = HTTPServer(WSGIContainer(self.app),
|
||||||
max_buffer_size = 209700000,
|
max_buffer_size = 209700000,
|
||||||
ssl_options=ssl)
|
ssl_options=ssl)
|
||||||
http_server.listen(web.ub.config.config_port)
|
http_server.listen(config.config_port)
|
||||||
self.wsgiserver=IOLoop.instance()
|
self.wsgiserver=IOLoop.instance()
|
||||||
self.wsgiserver.start()
|
self.wsgiserver.start()
|
||||||
# wait for stop signal
|
# wait for stop signal
|
||||||
self.wsgiserver.close(True)
|
self.wsgiserver.close(True)
|
||||||
except SocketError as e:
|
except SocketError as e:
|
||||||
web.app.logger.info("Error starting server: %s" % e.strerror)
|
self.app.logger.info("Error starting server: %s" % e.strerror)
|
||||||
print("Error starting server: %s" % e.strerror)
|
print("Error starting server: %s" % e.strerror)
|
||||||
web.helper.global_WorkerThread.stop()
|
global_WorkerThread.stop()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# ToDo: Somehow caused by circular import under python3 refactor
|
|
||||||
if sys.version_info > (3, 0):
|
|
||||||
self.restart = web.py3_restart_Typ
|
|
||||||
if self.restart == True:
|
if self.restart == True:
|
||||||
web.app.logger.info("Performing restart of Calibre-Web")
|
self.app.logger.info("Performing restart of Calibre-Web")
|
||||||
web.helper.global_WorkerThread.stop()
|
global_WorkerThread.stop()
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
arguments = ["\"" + sys.executable + "\""]
|
arguments = ["\"" + sys.executable + "\""]
|
||||||
for e in sys.argv:
|
for e in sys.argv:
|
||||||
|
@ -126,26 +125,17 @@ class server:
|
||||||
else:
|
else:
|
||||||
os.execl(sys.executable, sys.executable, *sys.argv)
|
os.execl(sys.executable, sys.executable, *sys.argv)
|
||||||
else:
|
else:
|
||||||
web.app.logger.info("Performing shutdown of Calibre-Web")
|
self.app.logger.info("Performing shutdown of Calibre-Web")
|
||||||
web.helper.global_WorkerThread.stop()
|
global_WorkerThread.stop()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
def setRestartTyp(self,starttyp):
|
def setRestartTyp(self,starttyp):
|
||||||
self.restart = starttyp
|
self.restart = starttyp
|
||||||
# ToDo: Somehow caused by circular import under python3 refactor
|
|
||||||
web.py3_restart_Typ = starttyp
|
|
||||||
|
|
||||||
def killServer(self, signum, frame):
|
def killServer(self, signum, frame):
|
||||||
self.stopServer()
|
self.stopServer()
|
||||||
|
|
||||||
def stopServer(self):
|
def stopServer(self):
|
||||||
# ToDo: Somehow caused by circular import under python3 refactor
|
|
||||||
if sys.version_info > (3, 0):
|
|
||||||
if not self.wsgiserver:
|
|
||||||
if gevent_present:
|
|
||||||
self.wsgiserver = web.py3_gevent_link
|
|
||||||
else:
|
|
||||||
self.wsgiserver = IOLoop.instance()
|
|
||||||
if self.wsgiserver:
|
if self.wsgiserver:
|
||||||
if gevent_present:
|
if gevent_present:
|
||||||
self.wsgiserver.close()
|
self.wsgiserver.close()
|
||||||
|
@ -155,10 +145,6 @@ class server:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def getNameVersion():
|
def getNameVersion():
|
||||||
if gevent_present:
|
if gevent_present:
|
||||||
return {'Gevent':'v'+geventVersion}
|
return {'Gevent':'v' + geventVersion}
|
||||||
else:
|
else:
|
||||||
return {'Tornado':'v'+tornadoVersion}
|
return {'Tornado':'v'+tornadoVersion}
|
||||||
|
|
||||||
|
|
||||||
# Start Instance of Server
|
|
||||||
Server=server()
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
{% for user in content %}
|
{% for user in content %}
|
||||||
{% if not user.role_anonymous() or config.config_anonbrowse %}
|
{% if not user.role_anonymous() or config.config_anonbrowse %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><a href="{{url_for('edit_user', user_id=user.id)}}">{{user.nickname}}</a></td>
|
<td><a href="{{url_for('web.edit_user', user_id=user.id)}}">{{user.nickname}}</a></td>
|
||||||
<td>{{user.email}}</td>
|
<td>{{user.email}}</td>
|
||||||
<td>{{user.kindle_mail}}</td>
|
<td>{{user.kindle_mail}}</td>
|
||||||
<td>{{user.downloads.count()}}</td>
|
<td>{{user.downloads.count()}}</td>
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
<div class="btn btn-default" id="admin_new_user"><a href="{{url_for('new_user')}}">{{_('Add new user')}}</a></div>
|
<div class="btn btn-default" id="admin_new_user"><a href="{{url_for('web.new_user')}}">{{_('Add new user')}}</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
<td class="hidden-xs">{{email.mail_from}}</td>
|
<td class="hidden-xs">{{email.mail_from}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="btn btn-default" id="admin_edit_email"><a href="{{url_for('edit_mailsettings')}}">{{_('Change SMTP settings')}}</a></div>
|
<div class="btn btn-default" id="admin_edit_email"><a href="{{url_for('web.edit_mailsettings')}}">{{_('Change SMTP settings')}}</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -96,8 +96,8 @@
|
||||||
<div class="col-xs-6 col-sm-5">{% if config.config_remote_login %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</div>
|
<div class="col-xs-6 col-sm-5">{% if config.config_remote_login %}<span class="glyphicon glyphicon-ok"></span>{% else %}<span class="glyphicon glyphicon-remove"></span>{% endif %}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn btn-default"><a id="basic_config" href="{{url_for('configuration')}}">{{_('Basic Configuration')}}</a></div>
|
<div class="btn btn-default"><a id="basic_config" href="{{url_for('web.configuration')}}">{{_('Basic Configuration')}}</a></div>
|
||||||
<div class="btn btn-default"><a id="view_config" href="{{url_for('view_configuration')}}">{{_('UI Configuration')}}</a></div>
|
<div class="btn btn-default"><a id="view_config" href="{{url_for('web.view_configuration')}}">{{_('UI Configuration')}}</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<div class="col-sm-3 col-lg-3 col-xs-12">
|
<div class="col-sm-3 col-lg-3 col-xs-12">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
{% if book.has_cover %}
|
{% if book.has_cover %}
|
||||||
<img src="{{ url_for('get_cover', book_id=book.id) }}" alt="{{ book.title }}"/>
|
<img src="{{ url_for('web.get_cover', book_id=book.id) }}" alt="{{ book.title }}"/>
|
||||||
{% else %}
|
{% else %}
|
||||||
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" alt="{{ book.title }}"/>
|
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" alt="{{ book.title }}"/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
<div class="text-center more-stuff"><h4>{{_('Delete formats:')}}</h4>
|
<div class="text-center more-stuff"><h4>{{_('Delete formats:')}}</h4>
|
||||||
{% for file in book.data %}
|
{% for file in book.data %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<a href="{{ url_for('delete_book', book_id=book.id, book_format=file.format) }}" class="btn btn-danger" type="button">{{_('Delete')}} - {{file.format}}</a>
|
<a href="{{ url_for('web.delete_book', book_id=book.id, book_format=file.format) }}" class="btn btn-danger" type="button">{{_('Delete')}} - {{file.format}}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
{% if source_formats|length > 0 and conversion_formats|length > 0 %}
|
{% if source_formats|length > 0 and conversion_formats|length > 0 %}
|
||||||
<div class="text-center more-stuff"><h4>{{_('Convert book format:')}}</h4>
|
<div class="text-center more-stuff"><h4>{{_('Convert book format:')}}</h4>
|
||||||
<form class="padded-bottom" action="{{ url_for('convert_bookformat', book_id=book.id) }}" method="post" id="book_convert_frm">
|
<form class="padded-bottom" action="{{ url_for('web.convert_bookformat', book_id=book.id) }}" method="post" id="book_convert_frm">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="text-left">
|
<div class="text-left">
|
||||||
<label class="control-label" for="book_format_from">{{_('Convert from:')}}</label>
|
<label class="control-label" for="book_format_from">{{_('Convert from:')}}</label>
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<form role="form" action="{{ url_for('edit_book', book_id=book.id) }}" method="post" enctype="multipart/form-data" id="book_edit_frm">
|
<form role="form" action="{{ url_for('web.edit_book', book_id=book.id) }}" method="post" enctype="multipart/form-data" id="book_edit_frm">
|
||||||
<div class="col-sm-9 col-xs-12">
|
<div class="col-sm-9 col-xs-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="book_title">{{_('Book Title')}}</label>
|
<label for="book_title">{{_('Book Title')}}</label>
|
||||||
|
@ -175,7 +175,7 @@
|
||||||
</div>
|
</div>
|
||||||
<a href="#" id="get_meta" class="btn btn-default" data-toggle="modal" data-target="#metaModal">{{_('Get metadata')}}</a>
|
<a href="#" id="get_meta" class="btn btn-default" data-toggle="modal" data-target="#metaModal">{{_('Get metadata')}}</a>
|
||||||
<button type="submit" id="submit" class="btn btn-default">{{_('Submit')}}</button>
|
<button type="submit" id="submit" class="btn btn-default">{{_('Submit')}}</button>
|
||||||
<a href="{{ url_for('show_book', book_id=book.id) }}" class="btn btn-default">{{_('Back')}}</a>
|
<a href="{{ url_for('web.show_book', book_id=book.id) }}" class="btn btn-default">{{_('Back')}}</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<a href="{{ url_for('delete_book', book_id=book.id) }}" class="btn btn-danger">{{_('Delete')}}</a>
|
<a href="{{ url_for('web.delete_book', book_id=book.id) }}" class="btn btn-danger">{{_('Delete')}}</a>
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Back')}}</button>
|
<button type="button" class="btn btn-default" data-dismiss="modal">{{_('Back')}}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="col-sm-3 col-lg-3 col-xs-5">
|
<div class="col-sm-3 col-lg-3 col-xs-5">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
{% if entry.has_cover %}
|
{% if entry.has_cover %}
|
||||||
<img src="{{ url_for('get_cover', book_id=entry.id) }}" alt="{{ entry.title }}" />
|
<img src="{{ url_for('web.get_cover', book_id=entry.id) }}" alt="{{ entry.title }}" />
|
||||||
{% else %}
|
{% else %}
|
||||||
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" alt="{{ entry.title }}" />
|
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" alt="{{ entry.title }}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
{{_('Download')}} :
|
{{_('Download')}} :
|
||||||
</button>
|
</button>
|
||||||
{% for format in entry.data %}
|
{% for format in entry.data %}
|
||||||
<a href="{{ url_for('get_download_link_ext', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}" id="btnGroupDrop1{{format.format|lower}}" class="btn btn-primary" role="button">
|
<a href="{{ url_for('web.get_download_link_ext', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}" id="btnGroupDrop1{{format.format|lower}}" class="btn btn-primary" role="button">
|
||||||
<span class="glyphicon glyphicon-download"></span>{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
|
<span class="glyphicon glyphicon-download"></span>{{format.format}} ({{ format.uncompressed_size|filesizeformat }})
|
||||||
</a>
|
</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
|
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
|
||||||
{% for format in entry.data %}
|
{% for format in entry.data %}
|
||||||
<li><a href="{{ url_for('get_download_link_ext', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}">{{format.format}} ({{ format.uncompressed_size|filesizeformat }})</a></li>
|
<li><a href="{{ url_for('web.get_download_link_ext', book_id=entry.id, book_format=format.format|lower, anyname=entry.id|string+'.'+format.format|lower) }}">{{format.format}} ({{ format.uncompressed_size|filesizeformat }})</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if g.user.kindle_mail and g.user.is_authenticated and kindle_list %}
|
{% if g.user.kindle_mail and g.user.is_authenticated and kindle_list %}
|
||||||
{% if kindle_list.__len__() == 1 %}
|
{% if kindle_list.__len__() == 1 %}
|
||||||
<a href="{{url_for('send_to_kindle', book_id=entry.id, book_format=kindle_list[0]['format'], convert=kindle_list[0]['convert'])}}" id="sendbtn" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-send"></span> {{kindle_list[0]['text']}}</a>
|
<a href="{{url_for('web.send_to_kindle', book_id=entry.id, book_format=kindle_list[0]['format'], convert=kindle_list[0]['convert'])}}" id="sendbtn" class="btn btn-primary" role="button"><span class="glyphicon glyphicon-send"></span> {{kindle_list[0]['text']}}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<button id="sendbtn2" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button id="sendbtn2" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="send-to-kindle">
|
<ul class="dropdown-menu" aria-labelledby="send-to-kindle">
|
||||||
{% for format in kindle_list %}
|
{% for format in kindle_list %}
|
||||||
<li><a href="{{url_for('send_to_kindle', book_id=entry.id, book_format=format['format'], convert=format['convert'])}}">{{format['text']}}</a></li>
|
<li><a href="{{url_for('web.send_to_kindle', book_id=entry.id, book_format=format['format'], convert=format['convert'])}}">{{format['text']}}</a></li>
|
||||||
{%endfor%}
|
{%endfor%}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -66,14 +66,14 @@
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="read-in-browser">
|
<ul class="dropdown-menu" aria-labelledby="read-in-browser">
|
||||||
{% for format in reader_list %}
|
{% for format in reader_list %}
|
||||||
<li><a target="_blank" href="{{ url_for('read_book', book_id=entry.id, book_format=format) }}">{{format}}</a></li>
|
<li><a target="_blank" href="{{ url_for('web.read_book', book_id=entry.id, book_format=format) }}">{{format}}</a></li>
|
||||||
{%endfor%}
|
{%endfor%}
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="dropdown-menu" aria-labelledby="listen-in-browser">
|
<ul class="dropdown-menu" aria-labelledby="listen-in-browser">
|
||||||
|
|
||||||
{% for format in entry.data %}
|
{% for format in entry.data %}
|
||||||
{% if format.format|lower in audioentries %}
|
{% if format.format|lower in audioentries %}
|
||||||
<li><a target="_blank" href="{{ url_for('read_book', book_id=entry.id, book_format=format.format|lower) }}">{{format.format}}</a></li>
|
<li><a target="_blank" href="{{ url_for('web.read_book', book_id=entry.id, book_format=format.format|lower) }}">{{format.format}}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -86,7 +86,7 @@
|
||||||
<h2 id="title">{{entry.title|shortentitle(40)}}</h2>
|
<h2 id="title">{{entry.title|shortentitle(40)}}</h2>
|
||||||
<p class="author">
|
<p class="author">
|
||||||
{% for author in entry.authors %}
|
{% for author in entry.authors %}
|
||||||
<a href="{{url_for('author', book_id=author.id ) }}">{{author.name.replace('|',',')}}</a>
|
<a href="{{url_for('web.author', book_id=author.id ) }}">{{author.name.replace('|',',')}}</a>
|
||||||
{% if not loop.last %}
|
{% if not loop.last %}
|
||||||
&
|
&
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -108,7 +108,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if entry.series|length > 0 %}
|
{% if entry.series|length > 0 %}
|
||||||
<p>{{_('Book')}} {{entry.series_index}} {{_('of')}} <a href="{{url_for('series', book_id=entry.series[0].id)}}">{{entry.series[0].name}}</a></p>
|
<p>{{_('Book')}} {{entry.series_index}} {{_('of')}} <a href="{{url_for('web.series', book_id=entry.series[0].id)}}">{{entry.series[0].name}}</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if entry.languages.__len__() > 0 %}
|
{% if entry.languages.__len__() > 0 %}
|
||||||
|
@ -137,7 +137,7 @@
|
||||||
<span class="glyphicon glyphicon-tags"></span>
|
<span class="glyphicon glyphicon-tags"></span>
|
||||||
|
|
||||||
{% for tag in entry.tags %}
|
{% for tag in entry.tags %}
|
||||||
<a href="{{ url_for('category', book_id=tag.id) }}" class="btn btn-xs btn-info" role="button">{{tag.name}}</a>
|
<a href="{{ url_for('web.category', book_id=tag.id) }}" class="btn btn-xs btn-info" role="button">{{tag.name}}</a>
|
||||||
{%endfor%}
|
{%endfor%}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@
|
||||||
<div class="publishers">
|
<div class="publishers">
|
||||||
<p>
|
<p>
|
||||||
<span>{{_('Publisher')}}:
|
<span>{{_('Publisher')}}:
|
||||||
<a href="{{url_for('publisher', book_id=entry.publishers[0].id ) }}">{{entry.publishers[0].name}}</a>
|
<a href="{{url_for('web.publisher', book_id=entry.publishers[0].id ) }}">{{entry.publishers[0].name}}</a>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -191,7 +191,7 @@
|
||||||
|
|
||||||
<div class="custom_columns">
|
<div class="custom_columns">
|
||||||
<p>
|
<p>
|
||||||
<form id="have_read_form" action="{{ url_for('toggle_read', book_id=entry.id)}}" method="POST">
|
<form id="have_read_form" action="{{ url_for('web.toggle_read', book_id=entry.id)}}" method="POST">
|
||||||
<label class="block-label">
|
<label class="block-label">
|
||||||
<input id="have_read_cb" type="checkbox" {% if have_read %}checked{% endif %} >
|
<input id="have_read_cb" type="checkbox" {% if have_read %}checked{% endif %} >
|
||||||
<span>{{_('Read')}}</span>
|
<span>{{_('Read')}}</span>
|
||||||
|
@ -224,8 +224,8 @@
|
||||||
{% for shelf in g.user.shelf %}
|
{% for shelf in g.user.shelf %}
|
||||||
{% if not shelf.id in books_shelfs and shelf.is_public != 1 %}
|
{% if not shelf.id in books_shelfs and shelf.is_public != 1 %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url_for('add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
<a href="{{ url_for('web.add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
data-remove-href="{{ url_for('remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
data-remove-href="{{ url_for('web.remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
data-shelf-action="add"
|
data-shelf-action="add"
|
||||||
>
|
>
|
||||||
{{shelf.name}}
|
{{shelf.name}}
|
||||||
|
@ -236,8 +236,8 @@
|
||||||
{% for shelf in g.public_shelfes %}
|
{% for shelf in g.public_shelfes %}
|
||||||
{% if not shelf.id in books_shelfs %}
|
{% if not shelf.id in books_shelfs %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url_for('add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
<a href="{{ url_for('web.add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
data-remove-href="{{ url_for('remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
data-remove-href="{{ url_for('web.remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
data-shelf-action="add"
|
data-shelf-action="add"
|
||||||
>
|
>
|
||||||
{{shelf.name}}
|
{{shelf.name}}
|
||||||
|
@ -251,8 +251,8 @@
|
||||||
{% if books_shelfs %}
|
{% if books_shelfs %}
|
||||||
{% for shelf in g.user.shelf %}
|
{% for shelf in g.user.shelf %}
|
||||||
{% if shelf.id in books_shelfs and shelf.is_public != 1 %}
|
{% if shelf.id in books_shelfs and shelf.is_public != 1 %}
|
||||||
<a href="{{ url_for('remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
<a href="{{ url_for('web.remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
data-add-href="{{ url_for('add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
data-add-href="{{ url_for('web.add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
class="btn btn-sm btn-default" role="button" data-shelf-action="remove"
|
class="btn btn-sm btn-default" role="button" data-shelf-action="remove"
|
||||||
>
|
>
|
||||||
<span class="glyphicon glyphicon-remove"></span> {{shelf.name}}
|
<span class="glyphicon glyphicon-remove"></span> {{shelf.name}}
|
||||||
|
@ -261,8 +261,8 @@
|
||||||
{%endfor%}
|
{%endfor%}
|
||||||
{% for shelf in g.public_shelfes %}
|
{% for shelf in g.public_shelfes %}
|
||||||
{% if shelf.id in books_shelfs %}
|
{% if shelf.id in books_shelfs %}
|
||||||
<a href="{{ url_for('remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
<a href="{{ url_for('web.remove_from_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
data-add-href="{{ url_for('add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
data-add-href="{{ url_for('web.add_to_shelf', book_id=entry.id, shelf_id=shelf.id) }}"
|
||||||
class="btn btn-sm btn-default" role="button" data-shelf-action="remove"
|
class="btn btn-sm btn-default" role="button" data-shelf-action="remove"
|
||||||
>
|
>
|
||||||
<span class="glyphicon glyphicon-remove"></span> {{shelf.name}}
|
<span class="glyphicon glyphicon-remove"></span> {{shelf.name}}
|
||||||
|
@ -279,7 +279,7 @@
|
||||||
{% if g.user.role_edit() %}
|
{% if g.user.role_edit() %}
|
||||||
<div class="btn-toolbar" role="toolbar">
|
<div class="btn-toolbar" role="toolbar">
|
||||||
<div class="btn-group" role="group" aria-label="Edit/Delete book">
|
<div class="btn-group" role="group" aria-label="Edit/Delete book">
|
||||||
<a href="{{ url_for('edit_book', book_id=entry.id) }}" class="btn btn-sm btn-warning" id="edit_book" role="button"><span class="glyphicon glyphicon-edit"></span> {{_('Edit metadata')}}</a>
|
<a href="{{ url_for('web.edit_book', book_id=entry.id) }}" class="btn btn-sm btn-warning" id="edit_book" role="button"><span class="glyphicon glyphicon-edit"></span> {{_('Edit metadata')}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -8,21 +8,21 @@
|
||||||
{% for entry in random %}
|
{% for entry in random %}
|
||||||
<div class="col-sm-3 col-lg-2 col-xs-6 book" id="books_rand">
|
<div class="col-sm-3 col-lg-2 col-xs-6 book" id="books_rand">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ url_for('show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||||
{% if entry.has_cover %}
|
{% if entry.has_cover %}
|
||||||
<img src="{{ url_for('get_cover', book_id=entry.id) }}" alt="{{ entry.title }}" />
|
<img src="{{ url_for('web.get_cover', book_id=entry.id) }}" alt="{{ entry.title }}" />
|
||||||
{% else %}
|
{% else %}
|
||||||
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" alt="{{ entry.title }}" />
|
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" alt="{{ entry.title }}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
<a href="{{ url_for('show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||||
<p class="title">{{entry.title|shortentitle}}</p>
|
<p class="title">{{entry.title|shortentitle}}</p>
|
||||||
</a>
|
</a>
|
||||||
<p class="author">
|
<p class="author">
|
||||||
{% for author in entry.authors %}
|
{% for author in entry.authors %}
|
||||||
<a href="{{url_for('author', book_id=author.id) }}">{{author.name.replace('|',',')|shortentitle(30)}}</a>
|
<a href="{{url_for('web.author', book_id=author.id) }}">{{author.name.replace('|',',')|shortentitle(30)}}</a>
|
||||||
{% if not loop.last %}
|
{% if not loop.last %}
|
||||||
&
|
&
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -53,21 +53,21 @@
|
||||||
{% for entry in entries %}
|
{% for entry in entries %}
|
||||||
<div class="col-sm-3 col-lg-2 col-xs-6 book" id="books">
|
<div class="col-sm-3 col-lg-2 col-xs-6 book" id="books">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ url_for('show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||||
{% if entry.has_cover %}
|
{% if entry.has_cover %}
|
||||||
<img src="{{ url_for('get_cover', book_id=entry.id) }}" alt="{{ entry.title }}"/>
|
<img src="{{ url_for('web.get_cover', book_id=entry.id) }}" alt="{{ entry.title }}"/>
|
||||||
{% else %}
|
{% else %}
|
||||||
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" alt="{{ entry.title }}" />
|
<img src="{{ url_for('static', filename='generic_cover.jpg') }}" alt="{{ entry.title }}" />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
<a href="{{ url_for('show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
<a href="{{ url_for('web.show_book', book_id=entry.id) }}" data-toggle="modal" data-target="#bookDetailsModal" data-remote="false">
|
||||||
<p class="title">{{entry.title|shortentitle}}</p>
|
<p class="title">{{entry.title|shortentitle}}</p>
|
||||||
</a>
|
</a>
|
||||||
<p class="author">
|
<p class="author">
|
||||||
{% for author in entry.authors %}
|
{% for author in entry.authors %}
|
||||||
<a href="{{url_for('author', book_id=author.id) }}">{{author.name.replace('|',',')|shortentitle(30)}}</a>
|
<a href="{{url_for('web.author', book_id=author.id) }}">{{author.name.replace('|',',')|shortentitle(30)}}</a>
|
||||||
{% if not loop.last %}
|
{% if not loop.last %}
|
||||||
&
|
&
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -35,10 +35,10 @@
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
</button>
|
</button>
|
||||||
<a class="navbar-brand" href="{{url_for('index')}}">{{instance}}</a>
|
<a class="navbar-brand" href="{{url_for('web.index')}}">{{instance}}</a>
|
||||||
</div>
|
</div>
|
||||||
{% if g.user.is_authenticated or g.user.is_anonymous %}
|
{% if g.user.is_authenticated or g.user.is_anonymous %}
|
||||||
<form class="navbar-form navbar-left" role="search" action="{{url_for('search')}}" method="GET">
|
<form class="navbar-form navbar-left" role="search" action="{{url_for('web.search')}}" method="GET">
|
||||||
<div class="form-group input-group input-group-sm">
|
<div class="form-group input-group input-group-sm">
|
||||||
<label for="query" class="sr-only">{{_('Search')}}</label>
|
<label for="query" class="sr-only">{{_('Search')}}</label>
|
||||||
<input type="text" class="form-control" id="query" name="query" placeholder="{{_('Search')}}">
|
<input type="text" class="form-control" id="query" name="query" placeholder="{{_('Search')}}">
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
<div class="navbar-collapse collapse">
|
<div class="navbar-collapse collapse">
|
||||||
{% if g.user.is_authenticated or g.user.is_anonymous %}
|
{% if g.user.is_authenticated or g.user.is_anonymous %}
|
||||||
<ul class="nav navbar-nav ">
|
<ul class="nav navbar-nav ">
|
||||||
<li><a href="{{url_for('advanced_search')}}"><span class="glyphicon glyphicon-search"></span><span class="hidden-sm"> {{_('Advanced Search')}}</span></a></li>
|
<li><a href="{{url_for('web.advanced_search')}}"><span class="glyphicon glyphicon-search"></span><span class="hidden-sm"> {{_('Advanced Search')}}</span></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<ul class="nav navbar-nav navbar-right" id="main-nav">
|
<ul class="nav navbar-nav navbar-right" id="main-nav">
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
{% if g.user.role_upload() or g.user.role_admin()%}
|
{% if g.user.role_upload() or g.user.role_admin()%}
|
||||||
{% if g.allow_upload %}
|
{% if g.allow_upload %}
|
||||||
<li>
|
<li>
|
||||||
<form id="form-upload" class="navbar-form" action="{{ url_for('upload') }}" method="post" enctype="multipart/form-data">
|
<form id="form-upload" class="navbar-form" action="{{ url_for('web.upload') }}" method="post" enctype="multipart/form-data">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<span class="btn btn-default btn-file">{{_('Upload')}}<input id="btn-upload" name="btn-upload" type="file" multiple></span>
|
<span class="btn btn-default btn-file">{{_('Upload')}}<input id="btn-upload" name="btn-upload" type="file" multiple></span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -68,19 +68,19 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not g.user.is_anonymous %}
|
{% if not g.user.is_anonymous %}
|
||||||
<li><a id="top_tasks" href="{{url_for('get_tasks_status')}}"><span class="glyphicon glyphicon-tasks"></span><span class="hidden-sm"> {{_('Tasks')}}</span></a></li>
|
<li><a id="top_tasks" href="{{url_for('web.get_tasks_status')}}"><span class="glyphicon glyphicon-tasks"></span><span class="hidden-sm"> {{_('Tasks')}}</span></a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if g.user.role_admin() %}
|
{% if g.user.role_admin() %}
|
||||||
<li><a id="top_admin" href="{{url_for('admin')}}"><span class="glyphicon glyphicon-dashboard"></span><span class="hidden-sm"> {{_('Admin')}}</span></a></li>
|
<li><a id="top_admin" href="{{url_for('web.admin')}}"><span class="glyphicon glyphicon-dashboard"></span><span class="hidden-sm"> {{_('Admin')}}</span></a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li><a id="top_user" href="{{url_for('profile')}}"><span class="glyphicon glyphicon-user"></span><span class="hidden-sm"> {{g.user.nickname}}</span></a></li>
|
<li><a id="top_user" href="{{url_for('web.profile')}}"><span class="glyphicon glyphicon-user"></span><span class="hidden-sm"> {{g.user.nickname}}</span></a></li>
|
||||||
{% if not g.user.is_anonymous %}
|
{% if not g.user.is_anonymous %}
|
||||||
<li><a id="logout" href="{{url_for('logout')}}"><span class="glyphicon glyphicon-log-out"></span><span class="hidden-sm"> {{_('Logout')}}</span></a></li>
|
<li><a id="logout" href="{{url_for('web.logout')}}"><span class="glyphicon glyphicon-log-out"></span><span class="hidden-sm"> {{_('Logout')}}</span></a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if g.allow_registration and not g.user.is_authenticated %}
|
{% if g.allow_registration and not g.user.is_authenticated %}
|
||||||
<li><a id="login" href="{{url_for('login')}}"><span class="glyphicon glyphicon-log-in"></span> {{_('Login')}}</a></li>
|
<li><a id="login" href="{{url_for('web.login')}}"><span class="glyphicon glyphicon-log-in"></span> {{_('Login')}}</a></li>
|
||||||
<li><a id="register" href="{{url_for('register')}}"><span class="glyphicon glyphicon-user"></span> {{_('Register')}}</a></li>
|
<li><a id="register" href="{{url_for('web.register')}}"><span class="glyphicon glyphicon-user"></span> {{_('Register')}}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div><!--/.nav-collapse -->
|
</div><!--/.nav-collapse -->
|
||||||
|
@ -119,7 +119,7 @@
|
||||||
<ul class="list-unstyled" id="scnd-nav" intent in-standard-append="nav.navigation" in-mobile-after="#main-nav" in-mobile-class="nav navbar-nav">
|
<ul class="list-unstyled" id="scnd-nav" intent in-standard-append="nav.navigation" in-mobile-after="#main-nav" in-mobile-class="nav navbar-nav">
|
||||||
<li class="nav-head hidden-xs">{{_('Browse')}}</li>
|
<li class="nav-head hidden-xs">{{_('Browse')}}</li>
|
||||||
{% if g.user.show_recent() %}
|
{% if g.user.show_recent() %}
|
||||||
<li id="nav_new" {% if page == 'root' %}class="active"{% endif %}><a href="{{url_for('index')}}"><span class="glyphicon glyphicon-book"></span> {{_('Recently Added')}}</a></li>
|
<li id="nav_new" {% if page == 'root' %}class="active"{% endif %}><a href="{{url_for('web.index')}}"><span class="glyphicon glyphicon-book"></span> {{_('Recently Added')}}</a></li>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{% if g.user.show_sorted() %}
|
{% if g.user.show_sorted() %}
|
||||||
<li id="nav_sort" class="dropdown">
|
<li id="nav_sort" class="dropdown">
|
||||||
|
@ -128,55 +128,55 @@
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li id="nav_sort_old" {% if page == 'newest' %}class="active"{% endif %}><a href="{{url_for('newest_books')}}">{{_('Sort By')}} {{_('Newest')}}</a></li>
|
<li id="nav_sort_old" {% if page == 'newest' %}class="active"{% endif %}><a href="{{url_for('web.newest_books')}}">{{_('Sort By')}} {{_('Newest')}}</a></li>
|
||||||
<li id="nav_sort_new" {% if page == 'oldest' %}class="active"{% endif %}><a href="{{url_for('oldest_books')}}">{{_('Sort By')}} {{_('Oldest')}}</a></li>
|
<li id="nav_sort_new" {% if page == 'oldest' %}class="active"{% endif %}><a href="{{url_for('web.oldest_books')}}">{{_('Sort By')}} {{_('Oldest')}}</a></li>
|
||||||
<li id="nav_sort_asc" {% if page == 'a-z' %}class="active"{% endif %}><a href="{{url_for('titles_ascending')}}">{{_('Sort By')}} {{_('Title')}} ({{_('Ascending')}})</a></li>
|
<li id="nav_sort_asc" {% if page == 'a-z' %}class="active"{% endif %}><a href="{{url_for('web.titles_ascending')}}">{{_('Sort By')}} {{_('Title')}} ({{_('Ascending')}})</a></li>
|
||||||
<li id="nav_sort_desc" {% if page == 'z-a' %}class="active"{% endif %}><a href="{{url_for('titles_descending')}}">{{_('Sort By')}} {{_('Title')}} ({{_('Descending')}})</a></li>
|
<li id="nav_sort_desc" {% if page == 'z-a' %}class="active"{% endif %}><a href="{{url_for('web.titles_descending')}}">{{_('Sort By')}} {{_('Title')}} ({{_('Descending')}})</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{% if g.user.show_hot_books() %}
|
{% if g.user.show_hot_books() %}
|
||||||
<li id="nav_hot" {% if page == 'hot' %}class="active"{% endif %}><a href="{{url_for('hot_books')}}"><span class="glyphicon glyphicon-fire"></span>{{_('Hot Books')}}</a></li>
|
<li id="nav_hot" {% if page == 'hot' %}class="active"{% endif %}><a href="{{url_for('web.hot_books')}}"><span class="glyphicon glyphicon-fire"></span>{{_('Hot Books')}}</a></li>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{% if g.user.show_best_rated_books() %}
|
{% if g.user.show_best_rated_books() %}
|
||||||
<li id="nav_rated" {% if page == 'rated' %}class="active"{% endif %}><a href="{{url_for('best_rated_books')}}"><span class="glyphicon glyphicon-star"></span>{{_('Best rated Books')}}</a></li>
|
<li id="nav_rated" {% if page == 'rated' %}class="active"{% endif %}><a href="{{url_for('web.best_rated_books')}}"><span class="glyphicon glyphicon-star"></span>{{_('Best rated Books')}}</a></li>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{% if g.user.show_read_and_unread() %}
|
{% if g.user.show_read_and_unread() %}
|
||||||
{% if not g.user.is_anonymous %}
|
{% if not g.user.is_anonymous %}
|
||||||
<li id="nav_read" {% if page == 'read' %}class="active"{% endif %}><a href="{{url_for('read_books')}}"><span class="glyphicon glyphicon-eye-open"></span>{{_('Read Books')}}</a></li>
|
<li id="nav_read" {% if page == 'read' %}class="active"{% endif %}><a href="{{url_for('web.read_books')}}"><span class="glyphicon glyphicon-eye-open"></span>{{_('Read Books')}}</a></li>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
<li id="nav_unread" {% if page == 'read' %}class="active"{% endif %}><a href="{{url_for('unread_books')}}"><span class="glyphicon glyphicon-eye-close"></span>{{_('Unread Books')}}</a></li>
|
<li id="nav_unread" {% if page == 'read' %}class="active"{% endif %}><a href="{{url_for('web.unread_books')}}"><span class="glyphicon glyphicon-eye-close"></span>{{_('Unread Books')}}</a></li>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{% if g.user.show_random_books() %}
|
{% if g.user.show_random_books() %}
|
||||||
<li id="nav_rand" {% if page == 'discover' %}class="active"{% endif %}><a href="{{url_for('discover')}}"><span class="glyphicon glyphicon-random"></span>{{_('Discover')}}</a></li>
|
<li id="nav_rand" {% if page == 'discover' %}class="active"{% endif %}><a href="{{url_for('web.discover')}}"><span class="glyphicon glyphicon-random"></span>{{_('Discover')}}</a></li>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{% if g.user.show_category() %}
|
{% if g.user.show_category() %}
|
||||||
<li id="nav_cat" {% if page == 'discover' %}class="category"{% endif %}><a href="{{url_for('category_list')}}"><span class="glyphicon glyphicon-inbox"></span>{{_('Categories')}}</a></li>
|
<li id="nav_cat" {% if page == 'discover' %}class="category"{% endif %}><a href="{{url_for('web.category_list')}}"><span class="glyphicon glyphicon-inbox"></span>{{_('Categories')}}</a></li>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{% if g.user.show_series() %}
|
{% if g.user.show_series() %}
|
||||||
<li id="nav_serie" {% if page == 'series' %}class="active"{% endif %}><a href="{{url_for('series_list')}}"><span class="glyphicon glyphicon-bookmark"></span>{{_('Series')}}</a></li>
|
<li id="nav_serie" {% if page == 'series' %}class="active"{% endif %}><a href="{{url_for('web.series_list')}}"><span class="glyphicon glyphicon-bookmark"></span>{{_('Series')}}</a></li>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{% if g.user.show_author() %}
|
{% if g.user.show_author() %}
|
||||||
<li id="nav_author" {% if page == 'author' %}class="active"{% endif %}><a href="{{url_for('author_list')}}"><span class="glyphicon glyphicon-user"></span>{{_('Authors')}}</a></li>
|
<li id="nav_author" {% if page == 'author' %}class="active"{% endif %}><a href="{{url_for('web.author_list')}}"><span class="glyphicon glyphicon-user"></span>{{_('Authors')}}</a></li>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{% if g.user.show_publisher() %}
|
{% if g.user.show_publisher() %}
|
||||||
<li id="nav_publisher" {% if page == 'publisher' %}class="active"{% endif %}><a href="{{url_for('publisher_list')}}"><span class="glyphicon glyphicon-text-size"></span>{{_('Publishers')}}</a></li>
|
<li id="nav_publisher" {% if page == 'publisher' %}class="active"{% endif %}><a href="{{url_for('web.publisher_list')}}"><span class="glyphicon glyphicon-text-size"></span>{{_('Publishers')}}</a></li>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{% if g.user.filter_language() == 'all' and g.user.show_language() %}
|
{% if g.user.filter_language() == 'all' and g.user.show_language() %}
|
||||||
<li id="nav_lang" {% if page == 'language' %}class="active"{% endif %}><a href="{{url_for('language_overview')}}"><span class="glyphicon glyphicon-flag"></span>{{_('Languages')}} </a></li>
|
<li id="nav_lang" {% if page == 'language' %}class="active"{% endif %}><a href="{{url_for('web.language_overview')}}"><span class="glyphicon glyphicon-flag"></span>{{_('Languages')}} </a></li>
|
||||||
{%endif%}
|
{%endif%}
|
||||||
{% if g.user.is_authenticated or g.user.is_anonymous %}
|
{% if g.user.is_authenticated or g.user.is_anonymous %}
|
||||||
<li class="nav-head hidden-xs public-shelves">{{_('Public Shelves')}}</li>
|
<li class="nav-head hidden-xs public-shelves">{{_('Public Shelves')}}</li>
|
||||||
{% for shelf in g.public_shelfes %}
|
{% for shelf in g.public_shelfes %}
|
||||||
<li><a href="{{url_for('show_shelf', shelf_id=shelf.id)}}"><span class="glyphicon glyphicon-list public_shelf"></span>{{shelf.name|shortentitle(40)}}</a></li>
|
<li><a href="{{url_for('web.show_shelf', shelf_id=shelf.id)}}"><span class="glyphicon glyphicon-list public_shelf"></span>{{shelf.name|shortentitle(40)}}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<li class="nav-head hidden-xs your-shelves">{{_('Your Shelves')}}</li>
|
<li class="nav-head hidden-xs your-shelves">{{_('Your Shelves')}}</li>
|
||||||
{% for shelf in g.user.shelf %}
|
{% for shelf in g.user.shelf %}
|
||||||
<li><a href="{{url_for('show_shelf', shelf_id=shelf.id)}}"><span class="glyphicon glyphicon-list private_shelf"></span>{{shelf.name|shortentitle(40)}}</a></li>
|
<li><a href="{{url_for('web.show_shelf', shelf_id=shelf.id)}}"><span class="glyphicon glyphicon-list private_shelf"></span>{{shelf.name|shortentitle(40)}}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if not g.user.is_anonymous %}
|
{% if not g.user.is_anonymous %}
|
||||||
<li id="nav_createshelf" class="create-shelf"><a href="{{url_for('create_shelf')}}">{{_('Create a Shelf')}}</a></li>
|
<li id="nav_createshelf" class="create-shelf"><a href="{{url_for('web.create_shelf')}}">{{_('Create a Shelf')}}</a></li>
|
||||||
<li id="nav_about" {% if page == 'stat' %}class="active"{% endif %}><a href="{{url_for('stats')}}"><span class="glyphicon glyphicon-info-sign"></span>{{_('About')}}</a></li>
|
<li id="nav_about" {% if page == 'stat' %}class="active"{% endif %}><a href="{{url_for('web.stats')}}"><span class="glyphicon glyphicon-info-sign"></span>{{_('About')}}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{% extends "layout.html" %}
|
{% extends "layout.html" %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<form role="form" id="search" action="{{ url_for('advanced_search') }}" method="GET">
|
<form role="form" id="search" action="{{ url_for('web.advanced_search') }}" method="GET">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="book_title">{{_('Book Title')}}</label>
|
<label for="book_title">{{_('Book Title')}}</label>
|
||||||
<input type="text" class="form-control" name="book_title" id="book_title" value="">
|
<input type="text" class="form-control" name="book_title" id="book_title" value="">
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="discover">
|
<div class="discover">
|
||||||
<h2>{{_('Tasks list')}}</h2>
|
<h2>{{_('Tasks list')}}</h2>
|
||||||
<table class="table table-no-bordered" id="table" data-url="{{ url_for('get_email_status_json') }}" data-sort-name="starttime" data-sort-order="asc">
|
<table class="table table-no-bordered" id="table" data-url="{{ url_for('web.get_email_status_json') }}" data-sort-name="starttime" data-sort-order="asc">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
{% if g.user.role_admin() %}
|
{% if g.user.role_admin() %}
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
setInterval(function() {
|
setInterval(function() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
method:"get",
|
method:"get",
|
||||||
url: "{{ url_for('get_email_status_json')}}",
|
url: "{{ url_for('web.get_email_status_json')}}",
|
||||||
async: true,
|
async: true,
|
||||||
timeout: 900,
|
timeout: 900,
|
||||||
success:function(data){
|
success:function(data){
|
||||||
|
|
27
cps/ub.py
27
cps/ub.py
|
@ -23,7 +23,6 @@ from sqlalchemy import exc
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
from sqlalchemy.orm import *
|
from sqlalchemy.orm import *
|
||||||
from flask_login import AnonymousUserMixin
|
from flask_login import AnonymousUserMixin
|
||||||
from flask_dance.consumer.backend.sqla import OAuthConsumerMixin
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
@ -69,6 +68,10 @@ AUTO_UPDATE_STABLE = 1
|
||||||
UPDATE_NIGHTLY = 2
|
UPDATE_NIGHTLY = 2
|
||||||
AUTO_UPDATE_NIGHTLY = 4
|
AUTO_UPDATE_NIGHTLY = 4
|
||||||
|
|
||||||
|
engine = create_engine('sqlite:///{0}'.format(cli.settingspath), echo=False)
|
||||||
|
Base = declarative_base()
|
||||||
|
|
||||||
|
|
||||||
class UserBase:
|
class UserBase:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -171,13 +174,13 @@ class UserBase:
|
||||||
return '<User %r>' % self.nickname
|
return '<User %r>' % self.nickname
|
||||||
|
|
||||||
#Login via LDAP method
|
#Login via LDAP method
|
||||||
@staticmethod
|
''''@staticmethod
|
||||||
def try_login(username, password):
|
def try_login(username, password):
|
||||||
conn = get_ldap_connection()
|
conn = get_ldap_connection()
|
||||||
conn.simple_bind_s(
|
conn.simple_bind_s(
|
||||||
config.config_ldap_dn.replace("%s", username),
|
config.config_ldap_dn.replace("%s", username),
|
||||||
password
|
password
|
||||||
)
|
)'''
|
||||||
|
|
||||||
# Baseclass for Users in Calibre-Web, settings which are depending on certain users are stored here. It is derived from
|
# Baseclass for Users in Calibre-Web, settings which are depending on certain users are stored here. It is derived from
|
||||||
# User Base (all access methods are declared there)
|
# User Base (all access methods are declared there)
|
||||||
|
@ -197,11 +200,11 @@ class User(UserBase, Base):
|
||||||
default_language = Column(String(3), default="all")
|
default_language = Column(String(3), default="all")
|
||||||
mature_content = Column(Boolean, default=True)
|
mature_content = Column(Boolean, default=True)
|
||||||
|
|
||||||
|
'''
|
||||||
class OAuth(OAuthConsumerMixin, Base):
|
class OAuth(OAuthConsumerMixin, Base):
|
||||||
provider_user_id = Column(String(256))
|
provider_user_id = Column(String(256))
|
||||||
user_id = Column(Integer, ForeignKey(User.id))
|
user_id = Column(Integer, ForeignKey(User.id))
|
||||||
user = relationship(User)
|
user = relationship(User)'''
|
||||||
|
|
||||||
|
|
||||||
# Class for anonymous user is derived from User base and completly overrides methods and properties for the
|
# Class for anonymous user is derived from User base and completly overrides methods and properties for the
|
||||||
|
@ -815,7 +818,7 @@ def delete_download(book_id):
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
# Generate user Guest (translated text), as anoymous user, no rights
|
# Generate user Guest (translated text), as anoymous user, no rights
|
||||||
def create_anonymous_user():
|
def create_anonymous_user(session):
|
||||||
user = User()
|
user = User()
|
||||||
user.nickname = "Guest"
|
user.nickname = "Guest"
|
||||||
user.email = 'no@email'
|
user.email = 'no@email'
|
||||||
|
@ -852,7 +855,7 @@ Session = sessionmaker()
|
||||||
Session.configure(bind=engine)
|
Session.configure(bind=engine)
|
||||||
session = Session()
|
session = Session()
|
||||||
|
|
||||||
# generate database and admin and guest user, if no database is existing
|
|
||||||
if not os.path.exists(cli.settingspath):
|
if not os.path.exists(cli.settingspath):
|
||||||
try:
|
try:
|
||||||
Base.metadata.create_all(engine)
|
Base.metadata.create_all(engine)
|
||||||
|
@ -865,13 +868,3 @@ else:
|
||||||
Base.metadata.create_all(engine)
|
Base.metadata.create_all(engine)
|
||||||
migrate_Database()
|
migrate_Database()
|
||||||
clean_database()
|
clean_database()
|
||||||
|
|
||||||
#get LDAP connection
|
|
||||||
def get_ldap_connection():
|
|
||||||
import ldap
|
|
||||||
conn = ldap.initialize('ldap://{}'.format(config.config_ldap_provider_url))
|
|
||||||
return conn
|
|
||||||
|
|
||||||
# Generate global Settings Object accessible from every file
|
|
||||||
config = Config()
|
|
||||||
searched_ids = {}
|
|
||||||
|
|
|
@ -28,7 +28,8 @@ from io import BytesIO
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import shutil
|
import shutil
|
||||||
from ub import config, UPDATE_STABLE
|
from cps import config
|
||||||
|
from ub import UPDATE_STABLE
|
||||||
from tempfile import gettempdir
|
from tempfile import gettempdir
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
|
442
cps/web.py
442
cps/web.py
File diff suppressed because it is too large
Load Diff
|
@ -27,11 +27,11 @@ import socket
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
from email.generator import Generator
|
from email.generator import Generator
|
||||||
import web
|
from cps import config, db # , app
|
||||||
|
# import web
|
||||||
from flask_babel import gettext as _
|
from flask_babel import gettext as _
|
||||||
import re
|
import re
|
||||||
import gdriveutils as gd
|
# import gdriveutils as gd
|
||||||
# import subprocess
|
|
||||||
from subproc_wrapper import process_open
|
from subproc_wrapper import process_open
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,8 +70,8 @@ RET_SUCCESS = 1
|
||||||
# it in MIME Base64 encoded to
|
# it in MIME Base64 encoded to
|
||||||
def get_attachment(bookpath, filename):
|
def get_attachment(bookpath, filename):
|
||||||
"""Get file as MIMEBase message"""
|
"""Get file as MIMEBase message"""
|
||||||
calibrepath = web.config.config_calibre_dir
|
calibrepath = config.config_calibre_dir
|
||||||
if web.ub.config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
df = gd.getFileFromEbooksFolder(bookpath, filename)
|
df = gd.getFileFromEbooksFolder(bookpath, filename)
|
||||||
if df:
|
if df:
|
||||||
datafile = os.path.join(calibrepath, bookpath, filename)
|
datafile = os.path.join(calibrepath, bookpath, filename)
|
||||||
|
@ -90,8 +90,8 @@ def get_attachment(bookpath, filename):
|
||||||
data = file_.read()
|
data = file_.read()
|
||||||
file_.close()
|
file_.close()
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
web.app.logger.exception(e) # traceback.print_exc()
|
# web.app.logger.exception(e) # traceback.print_exc()
|
||||||
web.app.logger.error(u'The requested file could not be read. Maybe wrong permissions?')
|
# web.app.logger.error(u'The requested file could not be read. Maybe wrong permissions?')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
attachment = MIMEBase('application', 'octet-stream')
|
attachment = MIMEBase('application', 'octet-stream')
|
||||||
|
@ -235,7 +235,7 @@ class WorkerThread(threading.Thread):
|
||||||
curr_task = self.queue[self.current]['taskType']
|
curr_task = self.queue[self.current]['taskType']
|
||||||
filename = self._convert_ebook_format()
|
filename = self._convert_ebook_format()
|
||||||
if filename:
|
if filename:
|
||||||
if web.ub.config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
gd.updateGdriveCalibreFromLocal()
|
gd.updateGdriveCalibreFromLocal()
|
||||||
if curr_task == TASK_CONVERT:
|
if curr_task == TASK_CONVERT:
|
||||||
self.add_email(self.queue[self.current]['settings']['subject'], self.queue[self.current]['path'],
|
self.add_email(self.queue[self.current]['settings']['subject'], self.queue[self.current]['path'],
|
||||||
|
@ -254,8 +254,8 @@ class WorkerThread(threading.Thread):
|
||||||
# if it does - mark the conversion task as complete and return a success
|
# if it does - mark the conversion task as complete and return a success
|
||||||
# this will allow send to kindle workflow to continue to work
|
# this will allow send to kindle workflow to continue to work
|
||||||
if os.path.isfile(file_path + format_new_ext):
|
if os.path.isfile(file_path + format_new_ext):
|
||||||
web.app.logger.info("Book id %d already converted to %s", bookid, format_new_ext)
|
# web.app.logger.info("Book id %d already converted to %s", bookid, format_new_ext)
|
||||||
cur_book = web.db.session.query(web.db.Books).filter(web.db.Books.id == bookid).first()
|
cur_book = db.session.query(db.Books).filter(db.Books.id == bookid).first()
|
||||||
self.queue[self.current]['path'] = file_path
|
self.queue[self.current]['path'] = file_path
|
||||||
self.queue[self.current]['title'] = cur_book.title
|
self.queue[self.current]['title'] = cur_book.title
|
||||||
self._handleSuccess()
|
self._handleSuccess()
|
||||||
|
@ -264,23 +264,23 @@ class WorkerThread(threading.Thread):
|
||||||
web.app.logger.info("Book id %d - target format of %s does not exist. Moving forward with convert.", bookid, format_new_ext)
|
web.app.logger.info("Book id %d - target format of %s does not exist. Moving forward with convert.", bookid, format_new_ext)
|
||||||
|
|
||||||
# check if converter-executable is existing
|
# check if converter-executable is existing
|
||||||
if not os.path.exists(web.ub.config.config_converterpath):
|
if not os.path.exists(config.config_converterpath):
|
||||||
# ToDo Text is not translated
|
# ToDo Text is not translated
|
||||||
self._handleError(u"Convertertool %s not found" % web.ub.config.config_converterpath)
|
self._handleError(u"Convertertool %s not found" % config.config_converterpath)
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# check which converter to use kindlegen is "1"
|
# check which converter to use kindlegen is "1"
|
||||||
if format_old_ext == '.epub' and format_new_ext == '.mobi':
|
if format_old_ext == '.epub' and format_new_ext == '.mobi':
|
||||||
if web.ub.config.config_ebookconverter == 1:
|
if config.config_ebookconverter == 1:
|
||||||
'''if os.name == 'nt':
|
'''if os.name == 'nt':
|
||||||
command = web.ub.config.config_converterpath + u' "' + file_path + u'.epub"'
|
command = web.ub.config.config_converterpath + u' "' + file_path + u'.epub"'
|
||||||
if sys.version_info < (3, 0):
|
if sys.version_info < (3, 0):
|
||||||
command = command.encode(sys.getfilesystemencoding())
|
command = command.encode(sys.getfilesystemencoding())
|
||||||
else:'''
|
else:'''
|
||||||
command = [web.ub.config.config_converterpath, file_path + u'.epub']
|
command = [config.config_converterpath, file_path + u'.epub']
|
||||||
quotes = (1)
|
quotes = (1)
|
||||||
if web.ub.config.config_ebookconverter == 2:
|
if config.config_ebookconverter == 2:
|
||||||
# Linux py2.7 encode as list without quotes no empty element for parameters
|
# Linux py2.7 encode as list without quotes no empty element for parameters
|
||||||
# linux py3.x no encode and as list without quotes no empty element for parameters
|
# linux py3.x no encode and as list without quotes no empty element for parameters
|
||||||
# windows py2.7 encode as string with quotes empty element for parameters is okay
|
# windows py2.7 encode as string with quotes empty element for parameters is okay
|
||||||
|
@ -293,11 +293,11 @@ class WorkerThread(threading.Thread):
|
||||||
if sys.version_info < (3, 0):
|
if sys.version_info < (3, 0):
|
||||||
command = command.encode(sys.getfilesystemencoding())
|
command = command.encode(sys.getfilesystemencoding())
|
||||||
else:'''
|
else:'''
|
||||||
command = [web.ub.config.config_converterpath, (file_path + format_old_ext),
|
command = [config.config_converterpath, (file_path + format_old_ext),
|
||||||
(file_path + format_new_ext)]
|
(file_path + format_new_ext)]
|
||||||
index = 3
|
index = 3
|
||||||
if web.ub.config.config_calibre:
|
if config.config_calibre:
|
||||||
parameters = web.ub.config.config_calibre.split(" ")
|
parameters = config.config_calibre.split(" ")
|
||||||
for param in parameters:
|
for param in parameters:
|
||||||
command.append(param)
|
command.append(param)
|
||||||
quotes.append(index)
|
quotes.append(index)
|
||||||
|
@ -308,7 +308,7 @@ class WorkerThread(threading.Thread):
|
||||||
self._handleError(_(u"Ebook-converter failed: %(error)s", error=e))
|
self._handleError(_(u"Ebook-converter failed: %(error)s", error=e))
|
||||||
return
|
return
|
||||||
|
|
||||||
if web.ub.config.config_ebookconverter == 1:
|
if config.config_ebookconverter == 1:
|
||||||
nextline = p.communicate()[0]
|
nextline = p.communicate()[0]
|
||||||
# Format of error message (kindlegen translates its output texts):
|
# Format of error message (kindlegen translates its output texts):
|
||||||
# Error(prcgen):E23006: Language not recognized in metadata.The dc:Language field is mandatory.Aborting.
|
# Error(prcgen):E23006: Language not recognized in metadata.The dc:Language field is mandatory.Aborting.
|
||||||
|
@ -336,24 +336,24 @@ class WorkerThread(threading.Thread):
|
||||||
# 0 = Info(prcgen):I1036: Mobi file built successfully
|
# 0 = Info(prcgen):I1036: Mobi file built successfully
|
||||||
# 1 = Info(prcgen):I1037: Mobi file built with WARNINGS!
|
# 1 = Info(prcgen):I1037: Mobi file built with WARNINGS!
|
||||||
# 2 = Info(prcgen):I1038: MOBI file could not be generated because of errors!
|
# 2 = Info(prcgen):I1038: MOBI file could not be generated because of errors!
|
||||||
if (check < 2 and web.ub.config.config_ebookconverter == 1) or \
|
if (check < 2 and config.config_ebookconverter == 1) or \
|
||||||
(check == 0 and web.ub.config.config_ebookconverter == 2):
|
(check == 0 and config.config_ebookconverter == 2):
|
||||||
cur_book = web.db.session.query(web.db.Books).filter(web.db.Books.id == bookid).first()
|
cur_book = db.session.query(db.Books).filter(db.Books.id == bookid).first()
|
||||||
if os.path.isfile(file_path + format_new_ext):
|
if os.path.isfile(file_path + format_new_ext):
|
||||||
new_format = web.db.Data(name=cur_book.data[0].name,
|
new_format = db.Data(name=cur_book.data[0].name,
|
||||||
book_format=self.queue[self.current]['settings']['new_book_format'].upper(),
|
book_format=self.queue[self.current]['settings']['new_book_format'].upper(),
|
||||||
book=bookid, uncompressed_size=os.path.getsize(file_path + format_new_ext))
|
book=bookid, uncompressed_size=os.path.getsize(file_path + format_new_ext))
|
||||||
cur_book.data.append(new_format)
|
cur_book.data.append(new_format)
|
||||||
web.db.session.commit()
|
db.session.commit()
|
||||||
self.queue[self.current]['path'] = cur_book.path
|
self.queue[self.current]['path'] = cur_book.path
|
||||||
self.queue[self.current]['title'] = cur_book.title
|
self.queue[self.current]['title'] = cur_book.title
|
||||||
if web.ub.config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
os.remove(file_path + format_old_ext)
|
os.remove(file_path + format_old_ext)
|
||||||
self._handleSuccess()
|
self._handleSuccess()
|
||||||
return file_path + format_new_ext
|
return file_path + format_new_ext
|
||||||
else:
|
else:
|
||||||
error_message = format_new_ext.upper() + ' format not found on disk'
|
error_message = format_new_ext.upper() + ' format not found on disk'
|
||||||
web.app.logger.info("ebook converter failed with error while converting book")
|
# web.app.logger.info("ebook converter failed with error while converting book")
|
||||||
if not error_message:
|
if not error_message:
|
||||||
error_message = 'Ebook converter failed with unknown error'
|
error_message = 'Ebook converter failed with unknown error'
|
||||||
self._handleError(error_message)
|
self._handleError(error_message)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user