diff --git a/src/calibre/db/cache.py b/src/calibre/db/cache.py index 82dd762077..46dc5df6d7 100644 --- a/src/calibre/db/cache.py +++ b/src/calibre/db/cache.py @@ -607,6 +607,31 @@ class Cache(object): return False return self.backend.has_format(book_id, fmt, name, path) + @api + def save_original_format(self, book_id, fmt): + fmt = fmt.upper() + if 'ORIGINAL' in fmt: + raise ValueError('Cannot save original of an original fmt') + fmtfile = self.format(book_id, fmt, as_file=True) + if fmtfile is None: + return False + with fmtfile: + nfmt = 'ORIGINAL_'+fmt + return self.add_format(book_id, nfmt, fmtfile, run_hooks=False) + + @api + def restore_original_format(self, book_id, original_fmt): + original_fmt = original_fmt.upper() + fmtfile = self.format(book_id, original_fmt, as_file=True) + if fmtfile is not None: + fmt = original_fmt.partition('_')[2] + with self.write_lock: + with fmtfile: + self._add_format(book_id, fmt, fmtfile, run_hooks=False) + self._remove_formats({book_id:(original_fmt,)}) + return True + return False + @read_api def formats(self, book_id, verify_formats=True): ''' diff --git a/src/calibre/db/legacy.py b/src/calibre/db/legacy.py index f7cab21baf..aeab6e3de0 100644 --- a/src/calibre/db/legacy.py +++ b/src/calibre/db/legacy.py @@ -674,6 +674,28 @@ class LibraryDatabase(object): if notify: self.notify('cover', [book_id]) + def original_fmt(self, book_id, fmt): + nfmt = ('ORIGINAL_%s'%fmt).upper() + return nfmt if self.new_api.has_format(book_id, nfmt) else fmt + + def save_original_format(self, book_id, fmt, notify=True): + ret = self.new_api.save_original_format(book_id, fmt) + if ret and notify: + self.notify('metadata', [book_id]) + return ret + + def restore_original_format(self, book_id, original_fmt, notify=True): + ret = self.new_api.restore_original_format(book_id, original_fmt) + if ret and notify: + self.notify('metadata', [book_id]) + return ret + + def remove_format(self, index, fmt, index_is_id=False, notify=True, commit=True, db_only=False): + book_id = index if index_is_id else self.id(index) + self.new_api.remove_formats({book_id:(fmt,)}, db_only=db_only) + if notify: + self.notify('metadata', [book_id]) + # Private interface {{{ def __iter__(self): for row in self.data.iterall(): diff --git a/src/calibre/db/tests/add_remove.py b/src/calibre/db/tests/add_remove.py index 76349df1c5..0047a0ec4f 100644 --- a/src/calibre/db/tests/add_remove.py +++ b/src/calibre/db/tests/add_remove.py @@ -251,4 +251,21 @@ class AddRemoveTest(BaseTest): # }}} + def test_original_fmt(self): # {{{ + ' Test management of original fmt ' + af, ae, at = self.assertFalse, self.assertEqual, self.assertTrue + db = self.init_cache() + fmts = db.formats(1) + af(db.has_format(1, 'ORIGINAL_FMT1')) + at(db.save_original_format(1, 'FMT1')) + at(db.has_format(1, 'ORIGINAL_FMT1')) + raw = db.format(1, 'FMT1') + ae(raw, db.format(1, 'ORIGINAL_FMT1')) + db.add_format(1, 'FMT1', BytesIO(b'replacedfmt')) + self.assertNotEqual(db.format(1, 'FMT1'), db.format(1, 'ORIGINAL_FMT1')) + at(db.restore_original_format(1, 'ORIGINAL_FMT1')) + ae(raw, db.format(1, 'FMT1')) + af(db.has_format(1, 'ORIGINAL_FMT1')) + ae(set(fmts), set(db.formats(1, verify_formats=False))) + # }}} diff --git a/src/calibre/db/tests/legacy.py b/src/calibre/db/tests/legacy.py index 936eb12e44..e37d954225 100644 --- a/src/calibre/db/tests/legacy.py +++ b/src/calibre/db/tests/legacy.py @@ -49,10 +49,10 @@ def run_funcs(self, db, ndb, funcs): meth(*args) else: fmt = lambda x:x - if meth[0] in {'!', '@', '#', '+', '$', '-'}: + if meth[0] in {'!', '@', '#', '+', '$', '-', '%'}: if meth[0] != '+': fmt = {'!':dict, '@':lambda x:frozenset(x or ()), '#':lambda x:set((x or '').split(',')), - '$':lambda x:set(tuple(y) for y in x), '-':lambda x:None}[meth[0]] + '$':lambda x:set(tuple(y) for y in x), '-':lambda x:None, '%':lambda x: set((x or '').split(','))}[meth[0]] else: fmt = args[-1] args = args[:-1] @@ -357,6 +357,10 @@ class LegacyTest(BaseTest): self.assertEqual(legacy.cover(3, index_is_id=True), origcov) self.assertTrue(legacy.has_cover(3)) + self.assertTrue(legacy.format(1, 'FMT1', index_is_id=True)) + legacy.remove_format(1, 'FMT1', index_is_id=True) + self.assertIsNone(legacy.format(1, 'FMT1', index_is_id=True)) + legacy.delete_book(1) old.delete_book(1) self.assertNotIn(1, legacy.all_ids()) @@ -726,3 +730,16 @@ class LegacyTest(BaseTest): self.assertRaises(KeyError, ndb.custom_field_name, num=num) # }}} + def test_legacy_original_fmt(self): # {{{ + db, ndb = self.init_old(), self.init_legacy() + run_funcs(self, db, ndb, ( + ('original_fmt', 1, 'FMT1'), + ('save_original_format', 1, 'FMT1'), + ('original_fmt', 1, 'FMT1'), + ('restore_original_format', 1, 'ORIGINAL_FMT1'), + ('original_fmt', 1, 'FMT1'), + ('%formats', 1, True), + )) + db.close() + + # }}} diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index b61544f172..4ccba4d9fc 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -1570,6 +1570,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns): with lopen(opath, 'rb') as f: self.add_format(book_id, fmt, f, index_is_id=True, notify=False) self.remove_format(book_id, original_fmt, index_is_id=True, notify=notify) + return True + return False def delete_book(self, id, notify=True, commit=True, permanent=False, do_clean=True):