mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
Add thread to GUI for distributed metadata backup
This commit is contained in:
parent
1ad0eebd56
commit
f46d919c75
@ -21,7 +21,7 @@ from calibre.utils.date import dt_factory, qt_to_dt, isoformat
|
|||||||
from calibre.ebooks.metadata.meta import set_metadata as _set_metadata
|
from calibre.ebooks.metadata.meta import set_metadata as _set_metadata
|
||||||
from calibre.utils.search_query_parser import SearchQueryParser
|
from calibre.utils.search_query_parser import SearchQueryParser
|
||||||
from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \
|
from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \
|
||||||
REGEXP_MATCH, CoverCache
|
REGEXP_MATCH, CoverCache, MetadataBackup
|
||||||
from calibre.library.cli import parse_series_string
|
from calibre.library.cli import parse_series_string
|
||||||
from calibre import strftime, isbytestring, prepare_string_for_xml
|
from calibre import strftime, isbytestring, prepare_string_for_xml
|
||||||
from calibre.constants import filesystem_encoding
|
from calibre.constants import filesystem_encoding
|
||||||
@ -153,6 +153,9 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
self.cover_cache.stop()
|
self.cover_cache.stop()
|
||||||
self.cover_cache = CoverCache(db, FunctionDispatcher(self.db.cover))
|
self.cover_cache = CoverCache(db, FunctionDispatcher(self.db.cover))
|
||||||
self.cover_cache.start()
|
self.cover_cache.start()
|
||||||
|
self.metadata_backup = MetadataBackup(db,
|
||||||
|
FunctionDispatcher(self.db.dump_metadata))
|
||||||
|
self.metadata_backup.start()
|
||||||
def refresh_cover(event, ids):
|
def refresh_cover(event, ids):
|
||||||
if event == 'cover' and self.cover_cache is not None:
|
if event == 'cover' and self.cover_cache is not None:
|
||||||
self.cover_cache.refresh(ids)
|
self.cover_cache.refresh(ids)
|
||||||
|
@ -551,6 +551,10 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
|
|||||||
cc = self.library_view.model().cover_cache
|
cc = self.library_view.model().cover_cache
|
||||||
if cc is not None:
|
if cc is not None:
|
||||||
cc.stop()
|
cc.stop()
|
||||||
|
mb = self.library_view.model().metadata_backup
|
||||||
|
if mb is not None:
|
||||||
|
mb.stop()
|
||||||
|
|
||||||
self.hide_windows()
|
self.hide_windows()
|
||||||
self.emailer.stop()
|
self.emailer.stop()
|
||||||
try:
|
try:
|
||||||
|
@ -21,7 +21,31 @@ from calibre.utils.pyparsing import ParseException
|
|||||||
from calibre.ebooks.metadata import title_sort
|
from calibre.ebooks.metadata import title_sort
|
||||||
from calibre import fit_image
|
from calibre import fit_image
|
||||||
|
|
||||||
class CoverCache(Thread):
|
class MetadataBackup(Thread): # {{{
|
||||||
|
|
||||||
|
def __init__(self, db, dump_func):
|
||||||
|
Thread.__init__(self)
|
||||||
|
self.daemon = True
|
||||||
|
self.db = db
|
||||||
|
self.dump_func = dump_func
|
||||||
|
self.keep_running = True
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.keep_running = False
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while self.keep_running:
|
||||||
|
try:
|
||||||
|
id_ = self.db.dirtied_queue.get(True, 5)
|
||||||
|
except Empty:
|
||||||
|
continue
|
||||||
|
# If there is an exception is dump_func, we
|
||||||
|
# have no way of knowing
|
||||||
|
self.dump_func([id_])
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
class CoverCache(Thread): # {{{
|
||||||
|
|
||||||
def __init__(self, db, cover_func):
|
def __init__(self, db, cover_func):
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
@ -90,6 +114,7 @@ class CoverCache(Thread):
|
|||||||
for id_ in ids:
|
for id_ in ids:
|
||||||
self.cache.pop(id_, None)
|
self.cache.pop(id_, None)
|
||||||
self.load_queue.put(id_)
|
self.load_queue.put(id_)
|
||||||
|
# }}}
|
||||||
|
|
||||||
### Global utility function for get_match here and in gui2/library.py
|
### Global utility function for get_match here and in gui2/library.py
|
||||||
CONTAINS_MATCH = 0
|
CONTAINS_MATCH = 0
|
||||||
@ -107,7 +132,7 @@ def _match(query, value, matchkind):
|
|||||||
pass
|
pass
|
||||||
return False
|
return False
|
||||||
|
|
||||||
class ResultCache(SearchQueryParser):
|
class ResultCache(SearchQueryParser): # {{{
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Stores sorted and filtered metadata in memory.
|
Stores sorted and filtered metadata in memory.
|
||||||
@ -694,4 +719,5 @@ class SortKeyGenerator(object):
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ The database used to store ebook metadata
|
|||||||
import os, sys, shutil, cStringIO, glob, time, functools, traceback, re
|
import os, sys, shutil, cStringIO, glob, time, functools, traceback, re
|
||||||
from itertools import repeat
|
from itertools import repeat
|
||||||
from math import floor
|
from math import floor
|
||||||
|
from Queue import Queue
|
||||||
|
|
||||||
from PyQt4.QtGui import QImage
|
from PyQt4.QtGui import QImage
|
||||||
|
|
||||||
@ -127,7 +128,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
|
|
||||||
def __init__(self, library_path, row_factory=False):
|
def __init__(self, library_path, row_factory=False):
|
||||||
self.field_metadata = FieldMetadata()
|
self.field_metadata = FieldMetadata()
|
||||||
self.dirtied_cache = set([])
|
self.dirtied_queue = Queue()
|
||||||
if not os.path.exists(library_path):
|
if not os.path.exists(library_path):
|
||||||
os.makedirs(library_path)
|
os.makedirs(library_path)
|
||||||
self.listeners = set([])
|
self.listeners = set([])
|
||||||
@ -340,7 +341,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
loc=self.FIELD_MAP['sort']))
|
loc=self.FIELD_MAP['sort']))
|
||||||
|
|
||||||
d = self.conn.get('SELECT book FROM metadata_dirtied', all=True)
|
d = self.conn.get('SELECT book FROM metadata_dirtied', all=True)
|
||||||
self.dirtied_cache.update(set([x[0] for x in d]))
|
for x in d:
|
||||||
|
self.dirtied_queue.put(x[0])
|
||||||
|
|
||||||
self.refresh_ondevice = functools.partial(self.data.refresh_ondevice, self)
|
self.refresh_ondevice = functools.partial(self.data.refresh_ondevice, self)
|
||||||
self.refresh()
|
self.refresh()
|
||||||
@ -557,6 +559,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
|
|
||||||
def dump_metadata(self, book_ids, remove_from_dirtied=True, commit=True):
|
def dump_metadata(self, book_ids, remove_from_dirtied=True, commit=True):
|
||||||
for book_id in book_ids:
|
for book_id in book_ids:
|
||||||
|
if not self.data.has_id(book_id):
|
||||||
|
continue
|
||||||
mi = self.get_metadata(book_id, index_is_id=True, get_cover=True)
|
mi = self.get_metadata(book_id, index_is_id=True, get_cover=True)
|
||||||
# Always set cover to cover.jpg. Even if cover doesn't exist,
|
# Always set cover to cover.jpg. Even if cover doesn't exist,
|
||||||
# no harm done. This way no need to call dirtied when
|
# no harm done. This way no need to call dirtied when
|
||||||
@ -569,18 +573,17 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
if remove_from_dirtied:
|
if remove_from_dirtied:
|
||||||
self.conn.execute('DELETE FROM metadata_dirtied WHERE book=?',
|
self.conn.execute('DELETE FROM metadata_dirtied WHERE book=?',
|
||||||
(book_id,))
|
(book_id,))
|
||||||
if book_id in self.dirtied_cache:
|
|
||||||
self.dirtied_cache.remove(book_id)
|
|
||||||
if commit:
|
if commit:
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
|
||||||
def dirtied(self, book_ids, commit=True):
|
def dirtied(self, book_ids, commit=True):
|
||||||
self.conn.executemany(
|
self.conn.executemany(
|
||||||
'INSERT OR REPLACE INTO metadata_dirtied VALUES (?)',
|
'INSERT OR REPLACE INTO metadata_dirtied (book) VALUES (?)',
|
||||||
[(x,) for x in book_ids])
|
[(x,) for x in book_ids])
|
||||||
if commit:
|
if commit:
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
self.dirtied.update(set(book_ids))
|
for x in book_ids:
|
||||||
|
self.dirtied_queue.put(x)
|
||||||
|
|
||||||
def get_metadata(self, idx, index_is_id=False, get_cover=False):
|
def get_metadata(self, idx, index_is_id=False, get_cover=False):
|
||||||
'''
|
'''
|
||||||
|
Loading…
x
Reference in New Issue
Block a user