mirror of
https://github.com/janeczku/calibre-web
synced 2024-11-10 01:13:33 +00:00
Merge branch 'master' into Develop
# Conflicts: # test/Calibre-Web TestSummary_Linux.html
This commit is contained in:
commit
8d9f301aea
@ -19,14 +19,11 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
import ast
|
|
||||||
import hashlib
|
|
||||||
|
|
||||||
from .cw_login import LoginManager
|
from .cw_login import LoginManager
|
||||||
from flask import session
|
from flask import session
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MyLoginManager(LoginManager):
|
class MyLoginManager(LoginManager):
|
||||||
def _session_protection_failed(self):
|
def _session_protection_failed(self):
|
||||||
sess = session._get_current_object()
|
sess = session._get_current_object()
|
||||||
|
@ -397,7 +397,7 @@ class LoginManager:
|
|||||||
|
|
||||||
def _load_user_from_remember_cookie(self, cookie):
|
def _load_user_from_remember_cookie(self, cookie):
|
||||||
signer_kwargs = dict(
|
signer_kwargs = dict(
|
||||||
key_derivation="hmac", digest_method=staticmethod(hashlib.sha1)
|
key_derivation="hmac", digest_method=hashlib.sha1
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
remember_dict = URLSafeSerializer(
|
remember_dict = URLSafeSerializer(
|
||||||
@ -482,7 +482,7 @@ class LoginManager:
|
|||||||
# prepare data
|
# prepare data
|
||||||
max_age = int(current_app.permanent_session_lifetime.total_seconds())
|
max_age = int(current_app.permanent_session_lifetime.total_seconds())
|
||||||
signer_kwargs = dict(
|
signer_kwargs = dict(
|
||||||
key_derivation="hmac", digest_method=staticmethod(hashlib.sha1)
|
key_derivation="hmac", digest_method=hashlib.sha1
|
||||||
)
|
)
|
||||||
# save
|
# save
|
||||||
data = URLSafeSerializer(
|
data = URLSafeSerializer(
|
||||||
|
@ -134,8 +134,9 @@ def edit_book(book_id):
|
|||||||
# handle upload other formats from local disk
|
# handle upload other formats from local disk
|
||||||
meta = upload_single_file(request, book, book_id)
|
meta = upload_single_file(request, book, book_id)
|
||||||
# only merge metadata if file was uploaded and no error occurred (meta equals not false or none)
|
# only merge metadata if file was uploaded and no error occurred (meta equals not false or none)
|
||||||
|
upload_format = False
|
||||||
if meta:
|
if meta:
|
||||||
merge_metadata(to_save, meta)
|
upload_format = merge_metadata(to_save, meta)
|
||||||
# handle upload covers from local disk
|
# handle upload covers from local disk
|
||||||
cover_upload_success = upload_cover(request, book)
|
cover_upload_success = upload_cover(request, book)
|
||||||
if cover_upload_success:
|
if cover_upload_success:
|
||||||
@ -179,7 +180,7 @@ def edit_book(book_id):
|
|||||||
modify_date |= edit_book_publisher(to_save['publisher'], book)
|
modify_date |= edit_book_publisher(to_save['publisher'], book)
|
||||||
# handle book languages
|
# handle book languages
|
||||||
try:
|
try:
|
||||||
modify_date |= edit_book_languages(to_save['languages'], book)
|
modify_date |= edit_book_languages(to_save['languages'], book, upload_format)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
flash(str(e), category="error")
|
flash(str(e), category="error")
|
||||||
edit_error = True
|
edit_error = True
|
||||||
@ -575,6 +576,10 @@ def merge_metadata(to_save, meta):
|
|||||||
to_save['author_name'] = ''
|
to_save['author_name'] = ''
|
||||||
if to_save.get('book_title', "") == _('Unknown'):
|
if to_save.get('book_title', "") == _('Unknown'):
|
||||||
to_save['book_title'] = ''
|
to_save['book_title'] = ''
|
||||||
|
if not to_save["languages"] and meta.languages:
|
||||||
|
upload_language = True
|
||||||
|
else:
|
||||||
|
upload_language = False
|
||||||
for s_field, m_field in [
|
for s_field, m_field in [
|
||||||
('tags', 'tags'), ('author_name', 'author'), ('series', 'series'),
|
('tags', 'tags'), ('author_name', 'author'), ('series', 'series'),
|
||||||
('series_index', 'series_id'), ('languages', 'languages'),
|
('series_index', 'series_id'), ('languages', 'languages'),
|
||||||
@ -582,7 +587,7 @@ def merge_metadata(to_save, meta):
|
|||||||
to_save[s_field] = to_save[s_field] or getattr(meta, m_field, '')
|
to_save[s_field] = to_save[s_field] or getattr(meta, m_field, '')
|
||||||
to_save["description"] = to_save["description"] or Markup(
|
to_save["description"] = to_save["description"] or Markup(
|
||||||
getattr(meta, 'description', '')).unescape()
|
getattr(meta, 'description', '')).unescape()
|
||||||
|
return upload_language
|
||||||
|
|
||||||
def identifier_list(to_save, book):
|
def identifier_list(to_save, book):
|
||||||
"""Generate a list of Identifiers from form information"""
|
"""Generate a list of Identifiers from form information"""
|
||||||
|
@ -28,7 +28,7 @@ log = logger.create()
|
|||||||
|
|
||||||
def do_calibre_export(book_id, book_format):
|
def do_calibre_export(book_id, book_format):
|
||||||
try:
|
try:
|
||||||
quotes = [3, 5, 7, 9]
|
quotes = [4, 6]
|
||||||
tmp_dir = get_temp_dir()
|
tmp_dir = get_temp_dir()
|
||||||
calibredb_binarypath = get_calibre_binarypath("calibredb")
|
calibredb_binarypath = get_calibre_binarypath("calibredb")
|
||||||
temp_file_name = str(uuid4())
|
temp_file_name = str(uuid4())
|
||||||
|
@ -413,36 +413,6 @@ def rename_all_files_on_change(one_book, new_path, old_path, all_new_name, gdriv
|
|||||||
file_format.name = all_new_name
|
file_format.name = all_new_name
|
||||||
|
|
||||||
|
|
||||||
'''def rename_all_authors(first_author, renamed_author, calibre_path="", localbook=None, gdrive=False):
|
|
||||||
# Create new_author_dir from parameter or from database
|
|
||||||
# Create new title_dir from database and add id
|
|
||||||
if first_author:
|
|
||||||
new_authordir = get_valid_filename(first_author, chars=96)
|
|
||||||
for r in renamed_author:
|
|
||||||
new_author = calibre_db.session.query(db.Authors).filter(db.Authors.name == r).first()
|
|
||||||
old_author_dir = get_valid_filename(r, chars=96)
|
|
||||||
new_author_rename_dir = get_valid_filename(new_author.name, chars=96)
|
|
||||||
if gdrive:
|
|
||||||
g_file = gd.getFileFromEbooksFolder(None, old_author_dir)
|
|
||||||
if g_file:
|
|
||||||
gd.moveGdriveFolderRemote(g_file, new_author_rename_dir)
|
|
||||||
gd.updateDatabaseOnEdit(g_file['id'], new_author_rename_dir)
|
|
||||||
else:
|
|
||||||
if os.path.isdir(os.path.join(calibre_path, old_author_dir)):
|
|
||||||
old_author_path = os.path.join(calibre_path, old_author_dir)
|
|
||||||
new_author_path = os.path.join(calibre_path, new_author_rename_dir)
|
|
||||||
try:
|
|
||||||
shutil.move(os.path.normcase(old_author_path), os.path.normcase(new_author_path))
|
|
||||||
except OSError as ex:
|
|
||||||
log.error("Rename author from: %s to %s: %s", old_author_path, new_author_path, ex)
|
|
||||||
log.debug(ex, exc_info=True)
|
|
||||||
return _("Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
|
|
||||||
src=old_author_path, dest=new_author_path, error=str(ex))
|
|
||||||
else:
|
|
||||||
new_authordir = get_valid_filename(localbook.authors[0].name, chars=96)
|
|
||||||
return new_authordir'''
|
|
||||||
|
|
||||||
|
|
||||||
def rename_author_path(first_author, old_author_dir, renamed_author, calibre_path="", gdrive=False):
|
def rename_author_path(first_author, old_author_dir, renamed_author, calibre_path="", gdrive=False):
|
||||||
# Create new_author_dir from parameter or from database
|
# Create new_author_dir from parameter or from database
|
||||||
# Create new title_dir from database and add id
|
# Create new title_dir from database and add id
|
||||||
@ -458,13 +428,16 @@ def rename_author_path(first_author, old_author_dir, renamed_author, calibre_pat
|
|||||||
if os.path.isdir(os.path.join(calibre_path, old_author_dir)):
|
if os.path.isdir(os.path.join(calibre_path, old_author_dir)):
|
||||||
old_author_path = os.path.join(calibre_path, old_author_dir)
|
old_author_path = os.path.join(calibre_path, old_author_dir)
|
||||||
new_author_path = os.path.join(calibre_path, new_author_rename_dir)
|
new_author_path = os.path.join(calibre_path, new_author_rename_dir)
|
||||||
|
try:
|
||||||
|
os.rename(old_author_path, new_author_path)
|
||||||
|
except OSError:
|
||||||
try:
|
try:
|
||||||
shutil.move(old_author_path, new_author_path)
|
shutil.move(old_author_path, new_author_path)
|
||||||
except OSError as ex:
|
except OSError as ex:
|
||||||
log.error("Rename author from: %s to %s: %s", old_author_path, new_author_path, ex)
|
log.error("Rename author from: %s to %s: %s", old_author_path, new_author_path, ex)
|
||||||
log.debug(ex, exc_info=True)
|
log.error_or_exception(ex)
|
||||||
return _("Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
|
raise Exception(_("Rename author from: '%(src)s' to '%(dest)s' failed with error: %(error)s",
|
||||||
src=old_author_path, dest=new_author_path, error=str(ex))
|
src=old_author_path, dest=new_author_path, error=str(ex)))
|
||||||
return new_authordir
|
return new_authordir
|
||||||
|
|
||||||
# Moves files in file storage during author/title rename, or from temp dir to file storage
|
# Moves files in file storage during author/title rename, or from temp dir to file storage
|
||||||
|
@ -20,7 +20,6 @@ import sys
|
|||||||
|
|
||||||
from . import create_app, limiter
|
from . import create_app, limiter
|
||||||
from .jinjia import jinjia
|
from .jinjia import jinjia
|
||||||
from .remotelogin import remotelogin
|
|
||||||
from flask import request
|
from flask import request
|
||||||
|
|
||||||
|
|
||||||
@ -42,6 +41,7 @@ def main():
|
|||||||
from .shelf import shelf
|
from .shelf import shelf
|
||||||
from .tasks_status import tasks
|
from .tasks_status import tasks
|
||||||
from .error_handler import init_errorhandler
|
from .error_handler import init_errorhandler
|
||||||
|
from .remotelogin import remotelogin
|
||||||
try:
|
try:
|
||||||
from .kobo import kobo, get_kobo_activated
|
from .kobo import kobo, get_kobo_activated
|
||||||
from .kobo_auth import kobo_auth
|
from .kobo_auth import kobo_auth
|
||||||
|
@ -79,6 +79,6 @@ var reader;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Default settings load
|
// Default settings load
|
||||||
const theme = localStorage.getItem("calibre.reader.theme") ?? Object.keys(themes)[0];
|
const theme = localStorage.getItem("calibre.reader.theme") ?? "lightTheme";
|
||||||
selectTheme(theme);
|
selectTheme(theme);
|
||||||
})();
|
})();
|
||||||
|
@ -255,7 +255,7 @@ class TaskConvert(CalibreTask):
|
|||||||
try:
|
try:
|
||||||
# path_tmp_opf = self._embed_metadata()
|
# path_tmp_opf = self._embed_metadata()
|
||||||
if config.config_embed_metadata:
|
if config.config_embed_metadata:
|
||||||
quotes = [3, 5]
|
quotes = [5]
|
||||||
tmp_dir = get_temp_dir()
|
tmp_dir = get_temp_dir()
|
||||||
calibredb_binarypath = os.path.join(config.config_binariesdir, SUPPORTED_CALIBRE_BINARIES["calibredb"])
|
calibredb_binarypath = os.path.join(config.config_binariesdir, SUPPORTED_CALIBRE_BINARIES["calibredb"])
|
||||||
my_env = os.environ.copy()
|
my_env = os.environ.copy()
|
||||||
|
@ -16,11 +16,9 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from urllib.request import urlopen
|
|
||||||
|
|
||||||
from flask_babel import lazy_gettext as N_
|
from flask_babel import lazy_gettext as N_
|
||||||
|
|
||||||
from cps import config, logger
|
from cps import config, logger, db, ub
|
||||||
from cps.services.worker import CalibreTask
|
from cps.services.worker import CalibreTask
|
||||||
|
|
||||||
|
|
||||||
@ -28,18 +26,12 @@ class TaskReconnectDatabase(CalibreTask):
|
|||||||
def __init__(self, task_message=N_('Reconnecting Calibre database')):
|
def __init__(self, task_message=N_('Reconnecting Calibre database')):
|
||||||
super(TaskReconnectDatabase, self).__init__(task_message)
|
super(TaskReconnectDatabase, self).__init__(task_message)
|
||||||
self.log = logger.create()
|
self.log = logger.create()
|
||||||
self.listen_address = config.get_config_ipaddress()
|
self.calibre_db = db.CalibreDB(expire_on_commit=False, init=True)
|
||||||
self.listen_port = config.config_port
|
|
||||||
|
|
||||||
def run(self, worker_thread):
|
def run(self, worker_thread):
|
||||||
address = self.listen_address if self.listen_address else 'localhost'
|
self.calibre_db.reconnect_db(config, ub.app_DB_path)
|
||||||
port = self.listen_port if self.listen_port else 8083
|
self.calibre_db.session.close()
|
||||||
|
|
||||||
try:
|
|
||||||
urlopen('http://' + address + ':' + str(port) + '/reconnect')
|
|
||||||
self._handleSuccess()
|
self._handleSuccess()
|
||||||
except Exception as ex:
|
|
||||||
self._handleError('Unable to reconnect Calibre database: ' + str(ex))
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
@ -70,7 +70,6 @@ class TaskGenerateCoverThumbnails(CalibreTask):
|
|||||||
self.log = logger.create()
|
self.log = logger.create()
|
||||||
self.book_id = book_id
|
self.book_id = book_id
|
||||||
self.app_db_session = ub.get_new_session_instance()
|
self.app_db_session = ub.get_new_session_instance()
|
||||||
# self.calibre_db = db.CalibreDB(expire_on_commit=False, init=True)
|
|
||||||
self.cache = fs.FileSystem()
|
self.cache = fs.FileSystem()
|
||||||
self.resolutions = [
|
self.resolutions = [
|
||||||
constants.COVER_THUMBNAIL_SMALL,
|
constants.COVER_THUMBNAIL_SMALL,
|
||||||
|
16
cps/web.py
16
cps/web.py
@ -89,8 +89,10 @@ except ImportError:
|
|||||||
def add_security_headers(resp):
|
def add_security_headers(resp):
|
||||||
default_src = ([host.strip() for host in config.config_trustedhosts.split(',') if host] +
|
default_src = ([host.strip() for host in config.config_trustedhosts.split(',') if host] +
|
||||||
["'self'", "'unsafe-inline'", "'unsafe-eval'"])
|
["'self'", "'unsafe-inline'", "'unsafe-eval'"])
|
||||||
csp = "default-src " + ' '.join(default_src) + "; "
|
csp = "default-src " + ' '.join(default_src)
|
||||||
csp += "font-src 'self' data:"
|
if request.endpoint == "web.read_book" and config.config_use_google_drive:
|
||||||
|
csp +=" blob: "
|
||||||
|
csp += "; font-src 'self' data:"
|
||||||
if request.endpoint == "web.read_book":
|
if request.endpoint == "web.read_book":
|
||||||
csp += " blob: "
|
csp += " blob: "
|
||||||
csp += "; img-src 'self'"
|
csp += "; img-src 'self'"
|
||||||
@ -98,12 +100,10 @@ def add_security_headers(resp):
|
|||||||
csp += " images.gr-assets.com i.gr-assets.com s.gr-assets.com"
|
csp += " images.gr-assets.com i.gr-assets.com s.gr-assets.com"
|
||||||
csp += " data:"
|
csp += " data:"
|
||||||
if request.endpoint == "edit-book.show_edit_book" or config.config_use_google_drive:
|
if request.endpoint == "edit-book.show_edit_book" or config.config_use_google_drive:
|
||||||
csp += " *;"
|
csp += " *"
|
||||||
elif request.endpoint == "web.read_book":
|
if request.endpoint == "web.read_book":
|
||||||
csp += " blob:; style-src-elem 'self' blob: 'unsafe-inline';"
|
csp += " blob: ; style-src-elem 'self' blob: 'unsafe-inline'"
|
||||||
else:
|
csp += "; object-src 'none';"
|
||||||
csp += ";"
|
|
||||||
csp += " object-src 'none';"
|
|
||||||
resp.headers['Content-Security-Policy'] = csp
|
resp.headers['Content-Security-Policy'] = csp
|
||||||
resp.headers['X-Content-Type-Options'] = 'nosniff'
|
resp.headers['X-Content-Type-Options'] = 'nosniff'
|
||||||
resp.headers['X-Frame-Options'] = 'SAMEORIGIN'
|
resp.headers['X-Frame-Options'] = 'SAMEORIGIN'
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
Werkzeug<3.0.0
|
|
||||||
APScheduler>=3.6.3,<3.11.0
|
APScheduler>=3.6.3,<3.11.0
|
||||||
Babel>=1.3,<3.0
|
Babel>=1.3,<3.0
|
||||||
Flask-Babel>=0.11.1,<4.1.0
|
Flask-Babel>=0.11.1,<4.1.0
|
||||||
# Flask-Login>=0.3.2,<0.6.4
|
|
||||||
Flask-Principal>=0.3.2,<0.5.1
|
Flask-Principal>=0.3.2,<0.5.1
|
||||||
Flask>=1.0.2,<3.1.0
|
Flask>=1.0.2,<3.1.0
|
||||||
iso-639>=0.4.5,<0.5.0
|
iso-639>=0.4.5,<0.5.0
|
||||||
@ -17,8 +15,8 @@ lxml>=4.9.1,<5.3.0
|
|||||||
flask-wtf>=0.14.2,<1.3.0
|
flask-wtf>=0.14.2,<1.3.0
|
||||||
chardet>=3.0.0,<4.1.0
|
chardet>=3.0.0,<4.1.0
|
||||||
advocate>=1.0.0,<1.1.0
|
advocate>=1.0.0,<1.1.0
|
||||||
Flask-Limiter>=2.3.0,<3.6.0
|
Flask-Limiter>=2.3.0,<3.9.0
|
||||||
regex>=2022.3.2,<2024.6.25
|
regex>=2022.3.2,<2024.6.25
|
||||||
bleach>=6.0.0,<6.2.0
|
bleach>=6.0.0,<6.2.0
|
||||||
python-magic>=0.4.27,<0.5.0
|
python-magic>=0.4.27,<0.5.0
|
||||||
flask-httpAuth>=4.4.0
|
flask-httpAuth>=4.4.0,<5.0.0
|
||||||
|
Loading…
Reference in New Issue
Block a user