mirror of
https://github.com/janeczku/calibre-web
synced 2024-11-28 04:19:59 +00:00
Implemented embed metadata on send to ereader
This commit is contained in:
parent
8e5bee5352
commit
ff9e1ed7c8
@ -47,7 +47,8 @@ from . import constants, logger, helper, services, cli_param
|
|||||||
from . import db, calibre_db, ub, web_server, config, updater_thread, gdriveutils, \
|
from . import db, calibre_db, ub, web_server, config, updater_thread, gdriveutils, \
|
||||||
kobo_sync_status, schedule
|
kobo_sync_status, schedule
|
||||||
from .helper import check_valid_domain, send_test_mail, reset_password, generate_password_hash, check_email, \
|
from .helper import check_valid_domain, send_test_mail, reset_password, generate_password_hash, check_email, \
|
||||||
valid_email, check_username, get_calibre_binarypath
|
valid_email, check_username
|
||||||
|
from .embed_helper import get_calibre_binarypath
|
||||||
from .gdriveutils import is_gdrive_ready, gdrive_support
|
from .gdriveutils import is_gdrive_ready, gdrive_support
|
||||||
from .render_template import render_title_template, get_sidebar_config
|
from .render_template import render_title_template, get_sidebar_config
|
||||||
from .services.worker import WorkerThread
|
from .services.worker import WorkerThread
|
||||||
|
55
cps/embed_helper.py
Normal file
55
cps/embed_helper.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# This file is part of the Calibre-Web (https://github.com/janeczku/calibre-web)
|
||||||
|
# Copyright (C) 2024 OzzieIsaacs
|
||||||
|
#
|
||||||
|
# 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 uuid import uuid4
|
||||||
|
import os
|
||||||
|
|
||||||
|
from .file_helper import get_temp_dir
|
||||||
|
from .subproc_wrapper import process_open
|
||||||
|
from . import logger, config
|
||||||
|
from .constants import SUPPORTED_CALIBRE_BINARIES
|
||||||
|
|
||||||
|
log = logger.create()
|
||||||
|
|
||||||
|
def do_calibre_export(book_id, book_format):
|
||||||
|
try:
|
||||||
|
quotes = [3, 5, 7, 9]
|
||||||
|
tmp_dir = get_temp_dir()
|
||||||
|
calibredb_binarypath = get_calibre_binarypath("calibredb")
|
||||||
|
temp_file_name = str(uuid4())
|
||||||
|
opf_command = [calibredb_binarypath, 'export', '--dont-write-opf', '--with-library', config.config_calibre_dir,
|
||||||
|
'--to-dir', tmp_dir, '--formats', book_format, "--template", "{}".format(temp_file_name),
|
||||||
|
str(book_id)]
|
||||||
|
p = process_open(opf_command, quotes)
|
||||||
|
_, err = p.communicate()
|
||||||
|
if err:
|
||||||
|
log.error('Metadata embedder encountered an error: %s', err)
|
||||||
|
return tmp_dir, temp_file_name
|
||||||
|
except OSError as ex:
|
||||||
|
# ToDo real error handling
|
||||||
|
log.error_or_exception(ex)
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
def get_calibre_binarypath(binary):
|
||||||
|
binariesdir = config.config_binariesdir
|
||||||
|
if binariesdir:
|
||||||
|
try:
|
||||||
|
return os.path.join(binariesdir, SUPPORTED_CALIBRE_BINARIES[binary])
|
||||||
|
except KeyError as ex:
|
||||||
|
log.error("Binary not supported by Calibre-Web: %s", SUPPORTED_CALIBRE_BINARIES[binary])
|
||||||
|
pass
|
||||||
|
return ""
|
@ -28,7 +28,6 @@ from datetime import datetime, timedelta
|
|||||||
import requests
|
import requests
|
||||||
import unidecode
|
import unidecode
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from lxml import etree
|
|
||||||
|
|
||||||
from flask import send_from_directory, make_response, redirect, abort, url_for
|
from flask import send_from_directory, make_response, redirect, abort, url_for
|
||||||
from flask_babel import gettext as _
|
from flask_babel import gettext as _
|
||||||
@ -56,13 +55,14 @@ from .tasks.convert import TaskConvert
|
|||||||
from . import logger, config, db, ub, fs
|
from . import logger, config, db, ub, fs
|
||||||
from . import gdriveutils as gd
|
from . import gdriveutils as gd
|
||||||
from .constants import STATIC_DIR as _STATIC_DIR, CACHE_TYPE_THUMBNAILS, THUMBNAIL_TYPE_COVER, THUMBNAIL_TYPE_SERIES, SUPPORTED_CALIBRE_BINARIES
|
from .constants import STATIC_DIR as _STATIC_DIR, CACHE_TYPE_THUMBNAILS, THUMBNAIL_TYPE_COVER, THUMBNAIL_TYPE_SERIES, SUPPORTED_CALIBRE_BINARIES
|
||||||
from .subproc_wrapper import process_wait, process_open
|
from .subproc_wrapper import process_wait
|
||||||
from .services.worker import WorkerThread
|
from .services.worker import WorkerThread
|
||||||
from .tasks.mail import TaskEmail
|
from .tasks.mail import TaskEmail
|
||||||
from .tasks.thumbnail import TaskClearCoverThumbnailCache, TaskGenerateCoverThumbnails
|
from .tasks.thumbnail import TaskClearCoverThumbnailCache, TaskGenerateCoverThumbnails
|
||||||
from .tasks.metadata_backup import TaskBackupMetadata
|
from .tasks.metadata_backup import TaskBackupMetadata
|
||||||
from .file_helper import get_temp_dir
|
from .file_helper import get_temp_dir
|
||||||
from .epub_helper import get_content_opf, create_new_metadata_backup, updateEpub, replace_metadata
|
from .epub_helper import get_content_opf, create_new_metadata_backup, updateEpub, replace_metadata
|
||||||
|
from .embed_helper import do_calibre_export
|
||||||
|
|
||||||
log = logger.create()
|
log = logger.create()
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ def send_mail(book_id, book_format, convert, ereader_mail, calibrepath, user_id)
|
|||||||
email_text = N_("%(book)s send to eReader", book=link)
|
email_text = N_("%(book)s send to eReader", book=link)
|
||||||
WorkerThread.add(user_id, TaskEmail(_("Send to eReader"), book.path, converted_file_name,
|
WorkerThread.add(user_id, TaskEmail(_("Send to eReader"), book.path, converted_file_name,
|
||||||
config.get_mail_settings(), ereader_mail,
|
config.get_mail_settings(), ereader_mail,
|
||||||
email_text, _('This Email has been sent via Calibre-Web.')))
|
email_text, _('This Email has been sent via Calibre-Web.'),book.id))
|
||||||
return
|
return
|
||||||
return _("The requested file could not be read. Maybe wrong permissions?")
|
return _("The requested file could not be read. Maybe wrong permissions?")
|
||||||
|
|
||||||
@ -1001,26 +1001,6 @@ def do_kepubify_metadata_replace(book, file_path):
|
|||||||
return tmp_dir, temp_file_name
|
return tmp_dir, temp_file_name
|
||||||
|
|
||||||
|
|
||||||
def do_calibre_export(book_id, book_format, ):
|
|
||||||
try:
|
|
||||||
quotes = [3, 5, 7, 9]
|
|
||||||
tmp_dir = get_temp_dir()
|
|
||||||
calibredb_binarypath = get_calibre_binarypath("calibredb")
|
|
||||||
temp_file_name = str(uuid4())
|
|
||||||
opf_command = [calibredb_binarypath, 'export', '--dont-write-opf', '--with-library', config.config_calibre_dir,
|
|
||||||
'--to-dir', tmp_dir, '--formats', book_format, "--template", "{}".format(temp_file_name),
|
|
||||||
str(book_id)]
|
|
||||||
p = process_open(opf_command, quotes)
|
|
||||||
_, err = p.communicate()
|
|
||||||
if err:
|
|
||||||
log.error('Metadata embedder encountered an error: %s', err)
|
|
||||||
return tmp_dir, temp_file_name
|
|
||||||
except OSError as ex:
|
|
||||||
# ToDo real error handling
|
|
||||||
log.error_or_exception(ex)
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
|
|
||||||
##################################
|
##################################
|
||||||
|
|
||||||
|
|
||||||
@ -1142,17 +1122,6 @@ def get_download_link(book_id, book_format, client):
|
|||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
|
|
||||||
def get_calibre_binarypath(binary):
|
|
||||||
binariesdir = config.config_binariesdir
|
|
||||||
if binariesdir:
|
|
||||||
try:
|
|
||||||
return os.path.join(binariesdir, SUPPORTED_CALIBRE_BINARIES[binary])
|
|
||||||
except KeyError as ex:
|
|
||||||
log.error("Binary not supported by Calibre-Web: %s", SUPPORTED_CALIBRE_BINARIES[binary])
|
|
||||||
pass
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
def clear_cover_thumbnail_cache(book_id):
|
def clear_cover_thumbnail_cache(book_id):
|
||||||
if config.schedule_generate_book_covers:
|
if config.schedule_generate_book_covers:
|
||||||
WorkerThread.add(None, TaskClearCoverThumbnailCache(book_id), hidden=True)
|
WorkerThread.add(None, TaskClearCoverThumbnailCache(book_id), hidden=True)
|
||||||
|
@ -110,6 +110,7 @@ class TaskConvert(CalibreTask):
|
|||||||
self.ereader_mail,
|
self.ereader_mail,
|
||||||
EmailText,
|
EmailText,
|
||||||
self.settings['body'],
|
self.settings['body'],
|
||||||
|
id=self.book_id,
|
||||||
internal=True)
|
internal=True)
|
||||||
)
|
)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
|
@ -21,7 +21,6 @@ import smtplib
|
|||||||
import ssl
|
import ssl
|
||||||
import threading
|
import threading
|
||||||
import socket
|
import socket
|
||||||
from shutil import copy
|
|
||||||
import mimetypes
|
import mimetypes
|
||||||
|
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
@ -29,14 +28,11 @@ from email.message import EmailMessage
|
|||||||
from email.utils import formatdate, parseaddr
|
from email.utils import formatdate, parseaddr
|
||||||
from email.generator import Generator
|
from email.generator import Generator
|
||||||
from flask_babel import lazy_gettext as N_
|
from flask_babel import lazy_gettext as N_
|
||||||
from email.utils import formatdate
|
|
||||||
|
|
||||||
from cps.services.worker import CalibreTask
|
from cps.services.worker import CalibreTask
|
||||||
from cps.services import gmail
|
from cps.services import gmail
|
||||||
|
from cps.embed_helper import do_calibre_export
|
||||||
from cps import logger, config
|
from cps import logger, config
|
||||||
from cps.subproc_wrapper import process_open
|
|
||||||
from cps.constants import SUPPORTED_CALIBRE_BINARIES
|
|
||||||
|
|
||||||
from cps import gdriveutils
|
from cps import gdriveutils
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
@ -113,7 +109,7 @@ class EmailSSL(EmailBase, smtplib.SMTP_SSL):
|
|||||||
|
|
||||||
|
|
||||||
class TaskEmail(CalibreTask):
|
class TaskEmail(CalibreTask):
|
||||||
def __init__(self, subject, filepath, attachment, settings, recipient, task_message, text, internal=False):
|
def __init__(self, subject, filepath, attachment, settings, recipient, task_message, text, id=0, internal=False):
|
||||||
super(TaskEmail, self).__init__(task_message)
|
super(TaskEmail, self).__init__(task_message)
|
||||||
self.subject = subject
|
self.subject = subject
|
||||||
self.attachment = attachment
|
self.attachment = attachment
|
||||||
@ -122,6 +118,7 @@ class TaskEmail(CalibreTask):
|
|||||||
self.recipient = recipient
|
self.recipient = recipient
|
||||||
self.text = text
|
self.text = text
|
||||||
self.asyncSMTP = None
|
self.asyncSMTP = None
|
||||||
|
self.book_id = id
|
||||||
self.results = dict()
|
self.results = dict()
|
||||||
|
|
||||||
# from calibre code:
|
# from calibre code:
|
||||||
@ -144,7 +141,7 @@ class TaskEmail(CalibreTask):
|
|||||||
message['To'] = self.recipient
|
message['To'] = self.recipient
|
||||||
message['Subject'] = self.subject
|
message['Subject'] = self.subject
|
||||||
message['Date'] = formatdate(localtime=True)
|
message['Date'] = formatdate(localtime=True)
|
||||||
message['Message-Id'] = "{}@{}".format(uuid.uuid4(), self.get_msgid_domain()) # f"<{uuid.uuid4()}@{get_msgid_domain(from_)}>" # make_msgid('calibre-web')
|
message['Message-Id'] = "{}@{}".format(uuid.uuid4(), self.get_msgid_domain())
|
||||||
message.set_content(self.text.encode('UTF-8'), "text", "plain")
|
message.set_content(self.text.encode('UTF-8'), "text", "plain")
|
||||||
if self.attachment:
|
if self.attachment:
|
||||||
data = self._get_attachment(self.filepath, self.attachment)
|
data = self._get_attachment(self.filepath, self.attachment)
|
||||||
@ -164,6 +161,8 @@ class TaskEmail(CalibreTask):
|
|||||||
try:
|
try:
|
||||||
# create MIME message
|
# create MIME message
|
||||||
msg = self.prepare_message()
|
msg = self.prepare_message()
|
||||||
|
if not msg:
|
||||||
|
return
|
||||||
if self.settings['mail_server_type'] == 0:
|
if self.settings['mail_server_type'] == 0:
|
||||||
self.send_standard_email(msg)
|
self.send_standard_email(msg)
|
||||||
else:
|
else:
|
||||||
@ -239,10 +238,10 @@ class TaskEmail(CalibreTask):
|
|||||||
self.asyncSMTP = None
|
self.asyncSMTP = None
|
||||||
self._progress = x
|
self._progress = x
|
||||||
|
|
||||||
@classmethod
|
def _get_attachment(self, book_path, filename):
|
||||||
def _get_attachment(cls, book_path, filename):
|
|
||||||
"""Get file as MIMEBase message"""
|
"""Get file as MIMEBase message"""
|
||||||
calibre_path = config.get_book_path()
|
calibre_path = config.get_book_path()
|
||||||
|
extension = os.path.splitext(filename)[1][1:]
|
||||||
if config.config_use_google_drive:
|
if config.config_use_google_drive:
|
||||||
df = gdriveutils.getFileFromEbooksFolder(book_path, filename)
|
df = gdriveutils.getFileFromEbooksFolder(book_path, filename)
|
||||||
if df:
|
if df:
|
||||||
@ -252,22 +251,21 @@ class TaskEmail(CalibreTask):
|
|||||||
df.GetContentFile(datafile)
|
df.GetContentFile(datafile)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
if config.config_binariesdir:
|
if config.config_binariesdir and config.config_embed_metadata:
|
||||||
datafile = cls._embed_metadata(calibre_path, book_path, filename, datafile)
|
data_path, data_file = do_calibre_export(self.book_id, extension)
|
||||||
os.remove(os.path.join(calibre_path, book_path, filename))
|
datafile = os.path.join(data_path, data_file + "." + extension)
|
||||||
file_ = open(datafile, 'rb')
|
with open(datafile, 'rb') as file_:
|
||||||
data = file_.read()
|
data = file_.read()
|
||||||
file_.close()
|
|
||||||
os.remove(datafile)
|
os.remove(datafile)
|
||||||
else:
|
else:
|
||||||
datafile = os.path.join(calibre_path, book_path, filename)
|
datafile = os.path.join(calibre_path, book_path, filename)
|
||||||
try:
|
try:
|
||||||
if config.config_binariesdir:
|
if config.config_binariesdir and config.config_embed_metadata:
|
||||||
datafile = cls._embed_metadata(calibre_path, book_path, filename, datafile)
|
data_path, data_file = do_calibre_export(self.book_id, extension)
|
||||||
file_ = open(datafile, 'rb')
|
datafile = os.path.join(data_path, data_file + "." + extension)
|
||||||
|
with open(datafile, 'rb') as file_:
|
||||||
data = file_.read()
|
data = file_.read()
|
||||||
file_.close()
|
if config.config_binariesdir and config.config_embed_metadata:
|
||||||
if config.config_binariesdir:
|
|
||||||
os.remove(datafile)
|
os.remove(datafile)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
log.error_or_exception(e, stacklevel=3)
|
log.error_or_exception(e, stacklevel=3)
|
||||||
@ -285,17 +283,3 @@ class TaskEmail(CalibreTask):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "E-mail {}, {}".format(self.name, self.subject)
|
return "E-mail {}, {}".format(self.name, self.subject)
|
||||||
|
|
||||||
def _embed_metadata(self, calibre_path, book_path, filename, datafile):
|
|
||||||
datafile_tmp = os.path.join(calibre_path, book_path, "tmp_" + filename)
|
|
||||||
path_opf = os.path.join(calibre_path, book_path, "metadata.opf")
|
|
||||||
copy(datafile, datafile_tmp)
|
|
||||||
|
|
||||||
calibredb_binarypath = os.path.join(config.config_binariesdir, SUPPORTED_CALIBRE_BINARIES["ebook-meta"])
|
|
||||||
opf_command = [calibredb_binarypath, datafile_tmp, "--from-opf", path_opf]
|
|
||||||
p = process_open(opf_command)
|
|
||||||
_, err = p.communicate()
|
|
||||||
if err:
|
|
||||||
# ToDo: Improve error handling
|
|
||||||
log.error('Metadata embedder encountered an error: %s', err)
|
|
||||||
return datafile_tmp
|
|
||||||
|
Loading…
Reference in New Issue
Block a user