Hello everyone - I've enjoyed getting my head around plugin architecture, zipping my files, stopping and starting the code on each comma change, etc. etc. and suspect I will die of a frustration-induced stroke before I get much further.
Is there a simple way of accessing the database from within an external Python program? An interface, if you like ? How else can I retrieve and set book metadata from python outside the plugin metaphor?
Use "calibre-debug -e foo.py". This lets you run standalone python that uses calibre's interface to the database (the stuff in library.database2).
Here is an example of a program that reads & writes metadata in the database for an arbitrary book with ID=1283. Note that I wrote this program quite some time ago and don't know if it still works properly.
Spoiler:
Code:
from calibre.ebooks.metadata.book import ALL_METADATA_FIELDS
from calibre.ebooks.metadata.book.base import Metadata
from calibre.library.database2 import LibraryDatabase2
from calibre.utils.config import prefs
from calibre.utils.date import now
src = prefs['library_path']
db = LibraryDatabase2(src)
def check_equal(mi, nmi):
for k in ALL_METADATA_FIELDS:
if k == 'user_categories':
continue
v1 = mi.get(k)
v2 = nmi.get(k)
if k == 'tags':
v1 = set(v1)
v2 = set(v2)
if v1 != v2:
print 'not a match', k, v1, v2
id=1283
orig_mi = db.get_metadata(id, index_is_id=True)
print 'Set metadata to itself w/o force'
db.set_metadata(id, orig_mi)
nmi = db.get_metadata(id, index_is_id=True)
check_equal(orig_mi, nmi)
print 'Set metadata to itself w/force'
db.set_metadata(id, orig_mi, force_changes=True)
nmi = db.get_metadata(id, index_is_id=True)
check_equal(orig_mi, nmi)
print 'Null set. Should change nothing'
mi = db.get_metadata(id, index_is_id=True)
db.set_metadata(id, Metadata(None), set_title=False, set_authors=False)
nmi = db.get_metadata(id, index_is_id=True)
check_equal(mi, nmi)
print 'None tags. Should not change tags.'
old_tags = mi.tags
mi.tags = None
db.set_metadata(id, mi)
nmi = db.get_metadata(id, index_is_id=True)
if set(nmi.tags) != set(orig_mi.tags):
print 'failed'
print 'Empty tags w/o force. Should not change tags'
mi.tags = []
db.set_metadata(id, mi)
nmi = db.get_metadata(id, index_is_id=True)
if set(nmi.tags) != set(orig_mi.tags):
print 'failed', nmi.tags
print 'Empty tags w/force. Should change tags'
mi.tags = []
db.set_metadata(id, mi, force_changes=True)
nmi = db.get_metadata(id, index_is_id=True)
if nmi.tags:
print 'failed', nmi.tags
print 'Reset tags'
mi.tags = old_tags
db.set_metadata(id, mi)
nmi = db.get_metadata(id, index_is_id=True)
if set(nmi.tags) != set(mi.tags):
print 'failed'
for attr in ('publisher', 'series', 'comments', 'author_sort'):
print 'set %s w/o force'%attr
setattr(mi, attr, '')
db.set_metadata(id, mi)
nmi = db.get_metadata(id, index_is_id=True)
if getattr(nmi, attr, None) == '':
print 'failed'
print 'set %s w/force'%attr
setattr(mi, attr, '')
db.set_metadata(id, mi, force_changes=True)
nmi = db.get_metadata(id, index_is_id=True)
if getattr(nmi, attr, None) != '':
print 'failed'
print 'restore metadata to original'
db.set_metadata(id, orig_mi, force_changes=True)
nmi = db.get_metadata(id, index_is_id=True)
check_equal(orig_mi, nmi)
mi = db.get_metadata(id, index_is_id=True)
print 'set pubdate to None w/o force. Should not change'
orig_pubdate = mi.pubdate
mi.pubdate = None
db.set_metadata(id, mi)
nmi = db.get_metadata(id, index_is_id=True)
if nmi.pubdate != orig_pubdate:
print 'failed'
print 'set pubdate to None w/force. Should not change'
mi.pubdate = None
db.set_metadata(id, mi, force_changes=True)
nmi = db.get_metadata(id, index_is_id=True)
if nmi.pubdate != orig_pubdate:
print 'failed'
print 'set pubdate to now w/o force. Should change'
pd = mi.pubdate = now()
db.set_metadata(id, mi, force_changes=True)
nmi = db.get_metadata(id, index_is_id=True)
if nmi.pubdate != pd:
print 'failed'
print 'set rating to 5 w/o force. Should change'
mi.rating = 5
db.set_metadata(id, mi)
nmi = db.get_metadata(id, index_is_id=True)
if nmi.rating != 5:
print 'failed'
print 'set rating to zero w/o force. Should change to zero'
mi.rating = 0
db.set_metadata(id, mi)
nmi = db.get_metadata(id, index_is_id=True)
if nmi.rating != 0:
print 'failed'
print 'set series_index to 5 w/o force'
mi.series_index = 5.0
db.set_metadata(id, mi)
nmi = db.get_metadata(id, index_is_id=True)
if nmi.series_index != 5.0:
print 'failed', nmi
print 'set series_index to 0 w/o force'
mi.series_index = 0.0
db.set_metadata(id, mi)
nmi = db.get_metadata(id, index_is_id=True)
if nmi.series_index != 0.0:
print 'failed'
print 'set identifiers to None w/o force. Should not change'
orig_idents = mi.identifiers
mi.identifiers = None
db.set_metadata(id, mi)
nmi = db.get_metadata(id, index_is_id=True)
if set(orig_idents) != set(nmi.identifiers):
print 'failed', orig_idents, nmi.identifiers
print 'set identifiers to None w/force. Should change'
mi.identifiers = None
db.set_metadata(id, mi, force_changes=True)
nmi = db.get_metadata(id, index_is_id=True)
if nmi.identifiers != {}:
print 'failed', nmi.identifiers
print 'set custom column to None w/o force. Should not change'
orig_cc = mi.get('#text')
mi.set('#text', None)
db.set_metadata(id, mi)
nmi = db.get_metadata(id, index_is_id=True)
if nmi.get('#text') != orig_cc:
print 'failed'
print 'set custom column to None w/force. Should change'
mi.set('#text', None)
db.set_metadata(id, mi, force_changes=True)
nmi = db.get_metadata(id, index_is_id=True)
if nmi.get('#text')is not None:
print 'failed', nmi.get('#text')
print 'set custom column to "A" w/o force. Should change'
mi.set('#text', 'A')
db.set_metadata(id, mi)
nmi = db.get_metadata(id, index_is_id=True)
if nmi.get('#text') != 'A':
print 'failed'
print 'set custom column to "" w/o force. Should change to None'
mi.set('#text', '')
db.set_metadata(id, mi)
nmi = db.get_metadata(id, index_is_id=True)
if nmi.get('#text') is not None:
print 'failed', nmi.get('#text')
print 'Restore metadata to original'
db.set_metadata(id, orig_mi, force_changes=True)
nmi = db.get_metadata(id, index_is_id=True)
check_equal(orig_mi, nmi)
Last edited by chaley; 12-13-2011 at 10:14 AM.
Reason: Added correctness disclaimer