1
0
mirror of https://github.com/janeczku/calibre-web synced 2024-11-17 23:34:53 +00:00

backup metadata second step

This commit is contained in:
Ozzieisaacs 2022-09-14 17:03:48 +02:00
parent ca0ee5d391
commit 241aa77d41
3 changed files with 91 additions and 38 deletions

View File

@ -399,8 +399,29 @@ class CustomColumns(Base):
display_dict = json.loads(self.display) display_dict = json.loads(self.display)
return display_dict return display_dict
def to_json(self): def to_json(self, value, extra):
pass content = dict()
content['table'] = "custom_column_" + str(self.id)
content['column'] = "value"
content['datatype'] = self.datatype
content['is_multiple'] = None if not self.is_multiple else self.is_multiple
content['kind'] = "field"
content['name'] = self.name
content['search_terms'] = ['#' + self.label]
content['label'] = self.label
content['colnum'] = self.id
content['display'] = self.get_display_dict()
content['is_custom'] = True
content['is_category'] = self.datatype in ['text', 'rating', 'enumeration', 'series']
content['link_column'] = "value"
content['category_sort'] = "value"
content['is_csp'] = False
content['is_editable'] = self.editable
content['rec_index'] = self.id + 22 # toDo why ??
content['#value#'] = value
content['#extra#'] = extra
content['is_multiple2'] = {}
return json.dumps(content, ensure_ascii=False)
class AlchemyEncoder(json.JSONEncoder): class AlchemyEncoder(json.JSONEncoder):

View File

@ -34,7 +34,7 @@ def get_scheduled_tasks(reconnect=True):
# ToDo make configurable. Generate metadata.opf file for each changed book # ToDo make configurable. Generate metadata.opf file for each changed book
if True: if True:
tasks.append([lambda: TaskBackupMetadata(), 'backup metadata', False]) tasks.append([lambda: TaskBackupMetadata(), "en", 'backup metadata', False])
# Generate all missing book cover thumbnails # Generate all missing book cover thumbnails
if config.schedule_generate_book_covers: if config.schedule_generate_book_covers:

View File

@ -15,9 +15,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/>.
import datetime
import os import os
import json from lxml import objectify
from urllib.request import urlopen from urllib.request import urlopen
from lxml import etree from lxml import etree
from html import escape from html import escape
@ -41,33 +41,35 @@ NSMAP = {'dc': PURL_NAMESPACE, 'opf': OPF_NAMESPACE}
class TaskBackupMetadata(CalibreTask): class TaskBackupMetadata(CalibreTask):
def __init__(self, task_message=N_('Backing up Metadata')): def __init__(self, export_language="en", translated_title="cover", task_message=N_('Backing up Metadata')):
super(TaskBackupMetadata, self).__init__(task_message) super(TaskBackupMetadata, self).__init__(task_message)
self.log = logger.create() self.log = logger.create()
self.db_session = db.CalibreDB(expire_on_commit=False, init=True).session self.calibre_db = db.CalibreDB(expire_on_commit=False, init=True)
self.export_language = export_language
self.translated_title = translated_title
def run(self, worker_thread): def run(self, worker_thread):
try: try:
metadata_backup = self.db_session.query(db.Metadata_Dirtied).all() metadata_backup = self.calibre_db.session.query(db.Metadata_Dirtied).all()
custom_columns = self.db_session.query(db.CustomColumns).all() custom_columns = self.calibre_db.session.query(db.CustomColumns).order_by(db.CustomColumns.label).all()
for backup in metadata_backup: for backup in metadata_backup:
book = self.db_session.query(db.Books).filter(db.Books.id == backup.book).one_or_none() book = self.calibre_db.session.query(db.Books).filter(db.Books.id == backup.book).one_or_none()
# self.db_session.query(db.Metadata_Dirtied).filter(db.Metadata_Dirtied == backup.id).delete() # self.calibre_db.session.query(db.Metadata_Dirtied).filter(db.Metadata_Dirtied == backup.id).delete()
# self.db_session.commit() # self.calibre_db.session.commit()
if book: if book:
metadata_file = self.open_metadata(book, custom_columns) self.open_metadata(book, custom_columns)
self._handleSuccess() self._handleSuccess()
self.db_session.remove() self.calibre_db.session.close()
else: else:
self.log.error("Book {} not found in database".format(backup.book)) self.log.error("Book {} not found in database".format(backup.book))
self._handleError("Book {} not found in database".format(backup.book)) self._handleError("Book {} not found in database".format(backup.book))
self.db_session.remove() self.calibre_db.session.close()
except Exception as ex: except Exception as ex:
self.log.debug('Error creating metadata backup: ' + str(ex)) self.log.debug('Error creating metadata backup: ' + str(ex))
self._handleError('Error creating metadata backup: ' + str(ex)) self._handleError('Error creating metadata backup: ' + str(ex))
self.db_session.rollback() self.calibre_db.session.rollback()
self.db_session.remove() self.calibre_db.session.close()
def open_metadata(self, book, custom_columns): def open_metadata(self, book, custom_columns):
if config.config_use_google_drive: if config.config_use_google_drive:
@ -89,13 +91,27 @@ class TaskBackupMetadata(CalibreTask):
if stream is not None: if stream is not None:
stream.close() stream.close()
else: else:
# ToDo: Handle book folder not found or not readable
book_metadata_filepath = os.path.join(config.config_calibre_dir, book.path, 'metadata.opf') book_metadata_filepath = os.path.join(config.config_calibre_dir, book.path, 'metadata.opf')
if not os.path.isfile(book_metadata_filepath): #if not os.path.isfile(book_metadata_filepath):
self.create_new_metadata_backup(book, custom_columns, book_metadata_filepath) self.create_new_metadata_backup(book, custom_columns, book_metadata_filepath)
# ToDo What to do # else:
return open(book_metadata_filepath, "w") '''namespaces = {'dc': PURL_NAMESPACE, 'opf': OPF_NAMESPACE}
else: test = etree.parse(book_metadata_filepath)
etree.parse(book_metadata_filepath) root = test.getroot()
for i in root.iter():
self.log.info(i)
title = root.find("dc:metadata", namespaces)
pass'''
with open(book_metadata_filepath, "rb") as f:
xml = f.read()
root = objectify.fromstring(xml)
# root.metadata['{http://purl.org/dc/elements/1.1/}title']
# root.metadata[PURL + 'title']
# getattr(root.metadata, PURL +'title')
# test = objectify.parse()
pass
# backup not found has to be created # backup not found has to be created
#raise Exception('Book cover file not found') #raise Exception('Book cover file not found')
@ -124,16 +140,23 @@ class TaskBackupMetadata(CalibreTask):
contributor.text = "calibre (5.7.2) [https://calibre-ebook.com]" contributor.text = "calibre (5.7.2) [https://calibre-ebook.com]"
contributor.set(OPF + "file-as", "calibre") # ToDo Check contributor.set(OPF + "file-as", "calibre") # ToDo Check
contributor.set(OPF + "role", "bpk") contributor.set(OPF + "role", "bpk")
date = etree.SubElement(metadata, PURL + "date", nsmap=NSMAP) date = etree.SubElement(metadata, PURL + "date", nsmap=NSMAP)
date.text = datetime.datetime.strftime(book.pubdate, "%Y-%m-%dT%H:%M:%S+00:00") date.text = '{d.year:04}-{d.month:02}-{d.day:02}T{d.hour:02}:{d.minute:02}:{d.second:02}'.format(d=book.pubdate)
if not book.languages:
language = etree.SubElement(metadata, PURL + "language", nsmap=NSMAP) language = etree.SubElement(metadata, PURL + "language", nsmap=NSMAP)
if book.languages: language.text = self.export_language
language.text = str(book.languages)
else: else:
language.text = "" # ToDo: insert locale (2 letter code) for b in book.languages:
if book.tags: language = etree.SubElement(metadata, PURL + "language", nsmap=NSMAP)
language.text = str(b.languages)
for b in book.tags:
subject = etree.SubElement(metadata, PURL + "subject", nsmap=NSMAP) subject = etree.SubElement(metadata, PURL + "subject", nsmap=NSMAP)
subject.text = str(book.tags) subject.text = str(b.tags)
if book.comments:
description = etree.SubElement(metadata, PURL + "description", nsmap=NSMAP)
description.text = escape(str(book.comments))
etree.SubElement(metadata, "meta", name="calibre:author_link_map", etree.SubElement(metadata, "meta", name="calibre:author_link_map",
content="{" + escape(",".join(['"' + str(a) + '":""' for a in book.authors])) + "}", content="{" + escape(",".join(['"' + str(a) + '":""' for a in book.authors])) + "}",
nsmap=NSMAP) nsmap=NSMAP)
@ -144,27 +167,36 @@ class TaskBackupMetadata(CalibreTask):
content=str(book.series_index), content=str(book.series_index),
nsmap=NSMAP) nsmap=NSMAP)
etree.SubElement(metadata, "meta", name="calibre:timestamp", etree.SubElement(metadata, "meta", name="calibre:timestamp",
content=datetime.datetime.strftime(book.timestamp, "%Y-%m-%dT%H:%M:%S+00:00"), content='{d.year:04}-{d.month:02}-{d.day:02}T{d.hour:02}:{d.minute:02}:{d.second:02}'.format(
d=book.timestamp),
nsmap=NSMAP) nsmap=NSMAP)
etree.SubElement(metadata, "meta", name="calibre:title_sort", etree.SubElement(metadata, "meta", name="calibre:title_sort",
content=book.sort, content=book.sort,
nsmap=NSMAP) nsmap=NSMAP)
for cc in custom_columns: for cc in custom_columns:
value = None
extra = None
cc_entry = getattr(book, "custom_column_" + str(cc.id))
if cc_entry.__len__():
value = cc_entry[0].get("value")
extra = cc_entry[0].get("extra")
etree.SubElement(metadata, "meta", name="calibre:user_metadata:#{}".format(cc.label), etree.SubElement(metadata, "meta", name="calibre:user_metadata:#{}".format(cc.label),
content=escape(cc.get_display_dict()), content=escape(cc.to_json(value, extra)),
nsmap=NSMAP) nsmap=NSMAP)
pass
# generate guide element and all sub elements of it # generate guide element and all sub elements of it
# Title is translated from default export language
guide = etree.SubElement(package, "guide") guide = etree.SubElement(package, "guide")
etree.SubElement(guide, "reference", type="cover", title="Titelbild", href="cover.jpg") etree.SubElement(guide, "reference", type="cover", title=self.translated_title, href="cover.jpg")
# prepare finalize everything and output # prepare finalize everything and output
doc = etree.ElementTree(package) doc = etree.ElementTree(package)
try:
with open(book_metadata_filepath, 'wb') as f: with open(book_metadata_filepath, 'wb') as f:
doc.write(f, xml_declaration=True, encoding='utf-8', pretty_print=True) doc.write(f, xml_declaration=True, encoding='utf-8', pretty_print=True)
except Exception:
# ToDo: Folder not writeable errror
pass
@property @property
def name(self): def name(self):
return "Backing up Metadata" return "Backing up Metadata"