mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Have book_on_device() return the type of match and also the matched paths. Also clean it up and improve performance by no recompiling the regex for every book.
This commit is contained in:
parent
bc6e622d25
commit
8769c07451
@ -1308,35 +1308,43 @@ class DeviceMixin(object): # {{{
|
|||||||
def book_on_device(self, id, format=None, reset=False):
|
def book_on_device(self, id, format=None, reset=False):
|
||||||
'''
|
'''
|
||||||
Return an indication of whether the given book represented by its db id
|
Return an indication of whether the given book represented by its db id
|
||||||
is on the currently connected device. It returns a 4 element list. The
|
is on the currently connected device. It returns a 6 element list. The
|
||||||
first three elements represent memory locations main, carda, and cardb,
|
first three elements represent memory locations main, carda, and cardb,
|
||||||
and are true if the book is identifiably in that memory. The fourth
|
and are true if the book is identifiably in that memory. The fourth
|
||||||
is the a count of how many instances of the book were found across all
|
is a count of how many instances of the book were found across all
|
||||||
the memory locations.
|
the memory locations. The fifth is the type of match. The type can be
|
||||||
|
one of: None, 'uuid', 'db_id', 'metadata'. The sixth is a set of paths to the
|
||||||
|
matching books on the device.
|
||||||
'''
|
'''
|
||||||
loc = [None, None, None, 0]
|
loc = [None, None, None, 0, None, set([])]
|
||||||
|
|
||||||
if reset:
|
if reset:
|
||||||
self.book_db_title_cache = None
|
self.book_db_title_cache = None
|
||||||
self.book_db_uuid_cache = None
|
self.book_db_uuid_cache = None
|
||||||
self.book_db_id_counts = None
|
self.book_db_id_counts = None
|
||||||
|
self.book_db_uuid_path_map = None
|
||||||
return
|
return
|
||||||
|
|
||||||
|
string_pat = re.compile('(?u)\W|[_]')
|
||||||
|
def clean_string(x):
|
||||||
|
x = x.lower() if x else ''
|
||||||
|
return string_pat.sub('', x)
|
||||||
|
|
||||||
if self.book_db_title_cache is None:
|
if self.book_db_title_cache is None:
|
||||||
self.book_db_title_cache = []
|
self.book_db_title_cache = []
|
||||||
self.book_db_uuid_cache = []
|
self.book_db_uuid_cache = []
|
||||||
|
self.book_db_uuid_path_map = {}
|
||||||
self.book_db_id_counts = {}
|
self.book_db_id_counts = {}
|
||||||
for i, l in enumerate(self.booklists()):
|
for i, l in enumerate(self.booklists()):
|
||||||
self.book_db_title_cache.append({})
|
self.book_db_title_cache.append({})
|
||||||
self.book_db_uuid_cache.append(set())
|
self.book_db_uuid_cache.append(set())
|
||||||
for book in l:
|
for book in l:
|
||||||
book_title = book.title.lower() if book.title else ''
|
book_title = clean_string(book.title)
|
||||||
book_title = re.sub('(?u)\W|[_]', '', book_title)
|
|
||||||
if book_title not in self.book_db_title_cache[i]:
|
if book_title not in self.book_db_title_cache[i]:
|
||||||
self.book_db_title_cache[i][book_title] = \
|
self.book_db_title_cache[i][book_title] = \
|
||||||
{'authors':set(), 'db_ids':set(), 'uuids':set()}
|
{'authors':set(), 'db_ids':set(),
|
||||||
book_authors = authors_to_string(book.authors).lower()
|
'uuids':set(), 'paths':set()}
|
||||||
book_authors = re.sub('(?u)\W|[_]', '', book_authors)
|
book_authors = clean_string(authors_to_string(book.authors))
|
||||||
self.book_db_title_cache[i][book_title]['authors'].add(book_authors)
|
self.book_db_title_cache[i][book_title]['authors'].add(book_authors)
|
||||||
db_id = getattr(book, 'application_id', None)
|
db_id = getattr(book, 'application_id', None)
|
||||||
if db_id is None:
|
if db_id is None:
|
||||||
@ -1350,35 +1358,36 @@ class DeviceMixin(object): # {{{
|
|||||||
uuid = getattr(book, 'uuid', None)
|
uuid = getattr(book, 'uuid', None)
|
||||||
if uuid is not None:
|
if uuid is not None:
|
||||||
self.book_db_uuid_cache[i].add(uuid)
|
self.book_db_uuid_cache[i].add(uuid)
|
||||||
|
self.book_db_uuid_path_map[uuid] = book.path
|
||||||
|
self.book_db_title_cache[i][book_title]['paths'].add(book.path)
|
||||||
|
|
||||||
mi = self.library_view.model().db.get_metadata(id, index_is_id=True)
|
mi = self.library_view.model().db.get_metadata(id, index_is_id=True)
|
||||||
for i, l in enumerate(self.booklists()):
|
for i, l in enumerate(self.booklists()):
|
||||||
if mi.uuid in self.book_db_uuid_cache[i]:
|
if mi.uuid in self.book_db_uuid_cache[i]:
|
||||||
loc[i] = True
|
loc[i] = True
|
||||||
|
loc[4] = 'uuid'
|
||||||
|
loc[5].add(self.book_db_uuid_path_map[mi.uuid])
|
||||||
continue
|
continue
|
||||||
db_title = re.sub('(?u)\W|[_]', '', mi.title.lower())
|
db_title = clean_string(mi.title)
|
||||||
cache = self.book_db_title_cache[i].get(db_title, None)
|
cache = self.book_db_title_cache[i].get(db_title, None)
|
||||||
if cache:
|
if cache:
|
||||||
if id in cache['db_ids']:
|
if id in cache['db_ids']:
|
||||||
loc[i] = True
|
loc[i] = True
|
||||||
|
loc[4] = 'db_id'
|
||||||
|
loc[5] = cache['paths']
|
||||||
continue
|
continue
|
||||||
if mi.authors and \
|
# Also check author sort, because it can be used as author in
|
||||||
re.sub('(?u)\W|[_]', '', authors_to_string(mi.authors).lower()) \
|
# some formats
|
||||||
in cache['authors']:
|
if (mi.authors and clean_string(authors_to_string(mi.authors))
|
||||||
|
in cache['authors']) or (mi.author_sort and
|
||||||
|
clean_string(mi.author_sort) in cache['authors']):
|
||||||
# We really shouldn't get here, because set_books_in_library
|
# We really shouldn't get here, because set_books_in_library
|
||||||
# should have set the db_ids for the books, and therefore
|
# should have set the db_ids for the books, and therefore
|
||||||
# the if just above should have found them. Mark the book
|
# the if just above should have found them. Mark the book
|
||||||
# anyway, and print a message about the situation
|
# anyway, and print a message about the situation
|
||||||
loc[i] = True
|
loc[i] = True
|
||||||
prints('book_on_device: matched title/author but not db_id!',
|
loc[4] = 'metadata'
|
||||||
mi.title, authors_to_string(mi.authors))
|
loc[5] = cache['paths']
|
||||||
continue
|
|
||||||
# Also check author sort, because it can be used as author in
|
|
||||||
# some formats
|
|
||||||
if mi.author_sort and \
|
|
||||||
re.sub('(?u)\W|[_]', '', mi.author_sort.lower()) \
|
|
||||||
in cache['authors']:
|
|
||||||
loc[i] = True
|
|
||||||
continue
|
continue
|
||||||
loc[3] = self.book_db_id_counts.get(id, 0)
|
loc[3] = self.book_db_id_counts.get(id, 0)
|
||||||
return loc
|
return loc
|
||||||
@ -1394,10 +1403,9 @@ class DeviceMixin(object): # {{{
|
|||||||
if reset or not hasattr(self, 'db_book_title_cache'):
|
if reset or not hasattr(self, 'db_book_title_cache'):
|
||||||
# It might be possible to get here without having initialized the
|
# It might be possible to get here without having initialized the
|
||||||
# library view. In this case, simply give up
|
# library view. In this case, simply give up
|
||||||
if not hasattr(self, 'library_view') or self.library_view is None:
|
try:
|
||||||
return
|
db = self.library_view.model().db
|
||||||
db = getattr(self.library_view.model(), 'db', None)
|
except:
|
||||||
if db is None:
|
|
||||||
return
|
return
|
||||||
# Build a cache (map) of the library, so the search isn't On**2
|
# Build a cache (map) of the library, so the search isn't On**2
|
||||||
self.db_book_title_cache = {}
|
self.db_book_title_cache = {}
|
||||||
|
@ -641,7 +641,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
count = 0
|
count = 0
|
||||||
on = self.book_on_device(id)
|
on = self.book_on_device(id)
|
||||||
if on is not None:
|
if on is not None:
|
||||||
m, a, b, count = on
|
m, a, b, count = on[:4]
|
||||||
if m is not None:
|
if m is not None:
|
||||||
loc.append(_('Main'))
|
loc.append(_('Main'))
|
||||||
if a is not None:
|
if a is not None:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user