def process_dir(self, dirpath, filenames, book_id): book_id = int(book_id) formats = list(filter(self.is_ebook_file, filenames)) fmts = [os.path.splitext(x)[1][1:].upper() for x in formats] sizes = [os.path.getsize(os.path.join(dirpath, x)) for x in formats] names = [os.path.splitext(x)[0] for x in formats] opf = os.path.join(dirpath, 'metadata.opf') parsed_opf = OPF(opf, basedir=dirpath) mi = parsed_opf.to_book_metadata() annotations = tuple(parsed_opf.read_annotations()) timestamp = os.path.getmtime(opf) path = os.path.relpath(dirpath, self.src_library_path).replace(os.sep, '/') if int(mi.application_id) == book_id: self.books.append({ 'mi': mi, 'timestamp': timestamp, 'formats': list(zip(fmts, sizes, names)), 'id': book_id, 'dirpath': dirpath, 'path': path, 'annotations': annotations }) else: self.mismatched_dirs.append(dirpath) alm = mi.get('author_link_map', {}) for author, link in iteritems(alm): existing_link, timestamp = self.authors_links.get(author, (None, None)) if existing_link is None or existing_link != link and timestamp < mi.timestamp: self.authors_links[author] = (link, mi.timestamp)
def test_annotations(self): # {{{ 'Test handling of annotations' from calibre.utils.date import utcnow, EPOCH cl = self.cloned_library cache = self.init_cache(cl) # First empty dirtied cache.dump_metadata() self.assertFalse(cache.dirtied_cache) def a(**kw): ts = utcnow() kw['timestamp'] = utcnow().isoformat() return kw, (ts - EPOCH).total_seconds() annot_list = [ a(type='bookmark', title='bookmark1 changed', seq=1), a(type='highlight', highlighted_text='text1', uuid='1', seq=2), a(type='highlight', highlighted_text='text2', uuid='2', seq=3, notes='notes2 some word changed again'), ] def map_as_list(amap): ans = [] for items in amap.values(): ans.extend(items) ans.sort(key=lambda x:x['seq']) return ans cache.set_annotations_for_book(1, 'moo', annot_list) amap = cache.annotations_map_for_book(1, 'moo') self.assertEqual(3, len(cache.all_annotations_for_book(1))) self.assertEqual([x[0] for x in annot_list], map_as_list(amap)) self.assertFalse(cache.dirtied_cache) cache.check_dirtied_annotations() self.assertEqual(set(cache.dirtied_cache), {1}) cache.dump_metadata() cache.check_dirtied_annotations() self.assertFalse(cache.dirtied_cache) # Test searching results = cache.search_annotations('"changed"') self.assertEqual([1, 3], [x['id'] for x in results]) results = cache.search_annotations('"changed"', annotation_type='bookmark') self.assertEqual([1], [x['id'] for x in results]) results = cache.search_annotations('"Changed"') # changed and change stem differently in english and other euro languages self.assertEqual([1, 3], [x['id'] for x in results]) results = cache.search_annotations('"SOMe"') self.assertEqual([3], [x['id'] for x in results]) results = cache.search_annotations('"change"', use_stemming=False) self.assertFalse(results) results = cache.search_annotations('"bookmark1"', highlight_start='[', highlight_end=']') self.assertEqual(results[0]['text'], '[bookmark1] changed') results = cache.search_annotations('"word"', highlight_start='[', highlight_end=']', snippet_size=3) self.assertEqual(results[0]['text'], '…some [word] changed…') self.assertRaises(FTSQueryError, cache.search_annotations, 'AND OR') fts_l = [a(type='bookmark', title='路坎坷走来', seq=1),] cache.set_annotations_for_book(1, 'moo', fts_l) results = cache.search_annotations('路', highlight_start='[', highlight_end=']') self.assertEqual(results[0]['text'], '[路]坎坷走来') annot_list[0][0]['title'] = 'changed title' cache.set_annotations_for_book(1, 'moo', annot_list) amap = cache.annotations_map_for_book(1, 'moo') self.assertEqual([x[0] for x in annot_list], map_as_list(amap)) del annot_list[1] cache.set_annotations_for_book(1, 'moo', annot_list) amap = cache.annotations_map_for_book(1, 'moo') self.assertEqual([x[0] for x in annot_list], map_as_list(amap)) cache.check_dirtied_annotations() cache.dump_metadata() from calibre.ebooks.metadata.opf2 import OPF raw = cache.read_backup(1) opf = OPF(BytesIO(raw)) cache.restore_annotations(1, list(opf.read_annotations())) amap = cache.annotations_map_for_book(1, 'moo') self.assertEqual([x[0] for x in annot_list], map_as_list(amap))