Connoisseur
Posts: 95
Karma: 10
Join Date: Sep 2013
Device: Kindle Paperwhite (2012)
|
Quote:
Originally Posted by siebert
Of course you can! You just need some monkey patch.
Running the following demo recipe with "ebook-convert authorpublisher.recipe authorpublisher.mobi" will create a dummy Mobipocket file which has the author and the publisher set to the values defined in the recipe:
Code:
'''
Demo recipe to demonstrate how to set the author and publisher in an ebook to values defined in the recipe.
'''
__license__ = 'GPL v3'
__copyright__ = '2014, Steffen Siebert <calibre at steffensiebert.de>'
__version__ = '1.0'
import os
import re
import string
import calibre.web.feeds.news
from calibre import fit_image
from calibre.constants import preferred_encoding
from calibre.ebooks.metadata.book.base import Metadata
from calibre.utils.magick import Image
from calibre.web.feeds import templates
from calibre.web.feeds.recipes import BasicNewsRecipe
from lxml.html.builder import HTML, HEAD, DIV, BODY, HR
author = "Recipe author"
publisher = "Recipe publisher"
'''
Replaces calibre.web.feeds.news.MetaInformation via monkey patching.
Creates a LockedMetadata instead of a Metadata object and sets the author and publisher defined in this receipe.
'''
def LockedMetaInformation(title, authors=(_('Unknown'),)):
mi = None
if hasattr(title, 'title') and hasattr(title, 'authors'):
title.authors = (author, )
mi = title
title = mi.title
authors = mi.authors
authors = (author, )
metadata = LockedMetadata(title, authors, other=mi)
metadata.__setattr__("publisher", publisher)
return metadata
'''
Extends calibre.ebooks.metadata.book.base.Metadata.
'''
class LockedMetadata(Metadata):
'''
Set fields author, authors and publishers only once.
'''
def __setattr__(self, field, val, extra=None):
if field in ["author", "publisher"] and self.has_key(field):
return
elif field == "authors" and self.authors[0] != _('Unknown'):
return
Metadata.__setattr__(self, field, val, extra)
class AuthorPublisherRecipe(BasicNewsRecipe):
title = u'Author Publisher Recipe'
def __init__(self, options, log, progress_reporter):
BasicNewsRecipe.__init__(self, options, log, progress_reporter)
# Monkey patch calibre.web.feeds.news to use LockedMetaInformation.
# This prevents calibre to set author and publisher to 'calibre'.
calibre.web.feeds.news.MetaInformation = LockedMetaInformation
def parse_index(self):
feed = []
articles = []
articles.append({'title': 'demo'})
feed.append(('feed', articles))
return feed
return [('demofeed', [{'title': 'demo'}, ])]
If you run the recipe from within the Calibre GUI, the author in the calibre database will still be set to 'calibre'.
A comment in the Calibre code responsible for this "feature" claims that this is needed for the auto delete process to identify the ebooks to delete, but this is a very lame excuse for messing with the author field instead of introducing a dedicated flag in the database.
Anyway, if you also want to see the actual author in the calibre database, you can install the following plugin by saving it as a file named "__init__.py" in an otherwise empty directory and run "calibre-customize -b ." in that directory:
Code:
import os
from calibre.customize import FileTypePlugin
from calibre.ebooks.metadata.meta import get_metadata, string_to_authors
class FixRecipeAuthorPlugin(FileTypePlugin):
name = 'Fix Recipe Author Plugin'
description = 'Replace "calibre" with the true authors in calibre database.'
supported_platforms = ['windows', 'osx', 'linux']
author = 'Steffen Siebert <calibre at steffensiebert.de>'
version = (1, 0, 0)
file_types = set(['epub', 'mobi'])
on_postimport = True
minimum_calibre_version = (0, 7, 53)
def postimport(self, book_id, book_format, db):
if db.field_for("authors", book_id) != ('calibre', ):
# The author isn't set to 'calibre', nothing to do.
return
# Open file and extract metadata to get the real authors.
path = db.format_abspath(book_id, book_format)
file = open(path, 'r+b')
mi = get_metadata(file, book_format)
file.close()
if not mi.authors:
# No authors found in metadata, don't change anything.
return
# Extract authors from metadata and write them to database.
authors = []
for a in mi.authors:
authors += string_to_authors(a)
db.set_field("authors", {book_id: authors})
Have fun hacking Calibre!
|
Thanks, it works as intended. I just wish I could do this with two lines in a recipe instead of twenty:-). (unless that already happened)
|