From 23307b3aa50a2e5ebc68ec2a02e5af4258745a6e Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Thu, 30 Jun 2011 18:09:18 +0100 Subject: [PATCH] Add format_metadata to get_metadata using a cache. Add formatter functions to deal with the information. --- src/calibre/library/database2.py | 17 +++++++++-- src/calibre/utils/formatter_functions.py | 37 ++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 3ebd63afde..530e5d8adf 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -8,6 +8,7 @@ The database used to store ebook metadata ''' import os, sys, shutil, cStringIO, glob, time, functools, traceback, re, \ json, uuid, tempfile, hashlib +from collections import defaultdict import threading, random from itertools import repeat from math import ceil @@ -487,6 +488,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): self.refresh_ondevice = functools.partial(self.data.refresh_ondevice, self) self.refresh() self.last_update_check = self.last_modified() + self.format_metadata_cache = defaultdict(dict) def break_cycles(self): self.data.break_cycles() @@ -914,11 +916,15 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): mi.book_size = row[fm['size']] mi.ondevice_col= row[fm['ondevice']] mi.last_modified = row[fm['last_modified']] + id = idx if index_is_id else self.id(idx) formats = row[fm['formats']] + mi.format_metadata = {} if not formats: formats = None else: formats = formats.split(',') + for f in formats: + mi.format_metadata[f] = self.format_metadata(id, f, allow_cache=True) mi.formats = formats tags = row[fm['tags']] if tags: @@ -927,7 +933,6 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): if mi.series: mi.series_index = row[fm['series_index']] mi.rating = row[fm['rating']] - id = idx if index_is_id else self.id(idx) mi.set_identifiers(self.get_identifiers(id, index_is_id=True)) mi.application_id = id mi.id = id @@ -1126,13 +1131,16 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): if m: return m['mtime'] - def format_metadata(self, id_, fmt): + def format_metadata(self, id_, fmt, allow_cache=True): + if allow_cache and fmt in self.format_metadata_cache.get(id_, {}): + return self.format_metadata_cache[id_][fmt] path = self.format_abspath(id_, fmt, index_is_id=True) ans = {} if path is not None: stat = os.stat(path) ans['size'] = stat.st_size ans['mtime'] = utcfromtimestamp(stat.st_mtime) + self.format_metadata_cache[id_][fmt] = ans return ans def format_hash(self, id_, fmt): @@ -1254,6 +1262,11 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): ret.name = f.name else: ret = f.read() + try: + self.format_metadata(index if index_is_id else self.id(index), + format, allow_cache=False) + except: + traceback.print_exc() return ret def add_format_with_hooks(self, index, format, fpath, index_is_id=False, diff --git a/src/calibre/utils/formatter_functions.py b/src/calibre/utils/formatter_functions.py index 1684b9f85b..f3d8370895 100644 --- a/src/calibre/utils/formatter_functions.py +++ b/src/calibre/utils/formatter_functions.py @@ -519,6 +519,41 @@ class BuiltinSelect(BuiltinFormatterFunction): return v[len(key)+1:] return '' +class BuiltinFormatsModtimes(BuiltinFormatterFunction): + name = 'formats_modtimes' + arg_count = 0 + category = 'Get values from metadata' + __doc__ = doc = _('formats_modtimes() -- return a comma-separated list of ' + 'colon_separated items representing modification times ' + 'for the formats of a book. You can use the select ' + 'function to get the mod time for a specific ' + 'format. Note that format names are always uppercase, ' + 'as in EPUB.' + ) + + def evaluate(self, formatter, kwargs, mi, locals): + fmt_data = mi.get('format_metadata', {}) + print fmt_data + return ','.join(k.upper()+':'+format_date(v['mtime'], 'iso') + for k,v in fmt_data.iteritems()) + +class BuiltinFormatsSizes(BuiltinFormatterFunction): + name = 'formats_sizes' + arg_count = 0 + category = 'Get values from metadata' + __doc__ = doc = _('formats_sizes() -- return a comma-separated list of ' + 'colon_separated items representing sizes ' + 'of the formats of a book. You can use the select ' + 'function to get the size for a specific ' + 'format. Note that format names are always uppercase, ' + 'as in EPUB.' + ) + + def evaluate(self, formatter, kwargs, mi, locals): + fmt_data = mi.get('format_metadata', {}) + print fmt_data + return ','.join(k.upper()+':'+str(v['size']) for k,v in fmt_data.iteritems()) + class BuiltinSublist(BuiltinFormatterFunction): name = 'sublist' arg_count = 4 @@ -814,6 +849,8 @@ builtin_eval = BuiltinEval() builtin_first_non_empty = BuiltinFirstNonEmpty() builtin_field = BuiltinField() builtin_format_date = BuiltinFormatDate() +builtin_formats_modt= BuiltinFormatsModtimes() +builtin_formats_size= BuiltinFormatsSizes() builtin_identifier_in_list = BuiltinIdentifierInList() builtin_ifempty = BuiltinIfempty() builtin_in_list = BuiltinInList()