Speedup bulk metadata editing of remaining standard fields

This commit is contained in:
Kovid Goyal 2010-08-18 14:28:21 -06:00
commit 0e19ed4543
3 changed files with 63 additions and 35 deletions

View File

@ -31,6 +31,10 @@ class Worker(Thread):
do_autonumber, do_remove_format, remove_format, do_swap_ta, \ do_autonumber, do_remove_format, remove_format, do_swap_ta, \
do_remove_conv, do_auto_author, series = self.args do_remove_conv, do_auto_author, series = self.args
# first loop: do author and title. These will commit at the end of each
# operation, because each operation modifies the file system. We want to
# try hard to keep the DB and the file system in sync, even in the face
# of exceptions or forced exits.
for id in self.ids: for id in self.ids:
if do_swap_ta: if do_swap_ta:
title = self.db.title(id, index_is_id=True) title = self.db.title(id, index_is_id=True)
@ -46,31 +50,34 @@ class Worker(Thread):
if au: if au:
self.db.set_authors(id, string_to_authors(au), notify=False) self.db.set_authors(id, string_to_authors(au), notify=False)
# All of these just affect the DB, so we can tolerate a total rollback
for id in self.ids:
if do_auto_author: if do_auto_author:
x = self.db.author_sort_from_book(id, index_is_id=True) x = self.db.author_sort_from_book(id, index_is_id=True)
if x: if x:
self.db.set_author_sort(id, x, notify=False) self.db.set_author_sort(id, x, notify=False, commit=False)
if aus and do_aus: if aus and do_aus:
self.db.set_author_sort(id, aus, notify=False) self.db.set_author_sort(id, aus, notify=False, commit=False)
if rating != -1: if rating != -1:
self.db.set_rating(id, 2*rating, notify=False) self.db.set_rating(id, 2*rating, notify=False, commit=False)
if pub: if pub:
self.db.set_publisher(id, pub, notify=False) self.db.set_publisher(id, pub, notify=False, commit=False)
if do_series: if do_series:
next = self.db.get_next_series_num_for(series) next = self.db.get_next_series_num_for(series)
self.db.set_series(id, series, notify=False) self.db.set_series(id, series, notify=False, commit=False)
num = next if do_autonumber and series else 1.0 num = next if do_autonumber and series else 1.0
self.db.set_series_index(id, num, notify=False) self.db.set_series_index(id, num, notify=False, commit=False)
if do_remove_format: if do_remove_format:
self.db.remove_format(id, remove_format, index_is_id=True, notify=False) self.db.remove_format(id, remove_format, index_is_id=True, notify=False, commit=False)
if do_remove_conv: if do_remove_conv:
self.db.delete_conversion_options(id, 'PIPE') self.db.delete_conversion_options(id, 'PIPE', commit=False)
self.db.commit()
for w in self.cc_widgets: for w in self.cc_widgets:
w.commit(self.ids) w.commit(self.ids)
@ -224,6 +231,11 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
return error_dialog(self, _('Failed'), return error_dialog(self, _('Failed'),
self.worker.error[0], det_msg=self.worker.error[1], self.worker.error[0], det_msg=self.worker.error[1],
show=True) show=True)
for w in getattr(self, 'custom_column_widgets', []):
w.commit(self.ids)
self.db.clean()
return QDialog.accept(self) return QDialog.accept(self)

View File

@ -1080,9 +1080,11 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
return cPickle.loads(str(data)) return cPickle.loads(str(data))
return None return None
def delete_conversion_options(self, id, format): def delete_conversion_options(self, id, format, commit=True):
self.conn.execute('DELETE FROM conversion_options WHERE book=? AND format=?', self.conn.execute('DELETE FROM conversion_options WHERE book=? AND format=?',
(id, format.upper())) (id, format.upper()))
if commit:
self.conn.commit()
def add_format(self, index, ext, stream, index_is_id=False): def add_format(self, index, ext, stream, index_is_id=False):

View File

@ -389,7 +389,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
path = path.lower() path = path.lower()
return path return path
def set_path(self, index, index_is_id=False): def set_path(self, index, index_is_id=False, commit=True):
''' '''
Set the path to the directory containing this books files based on its Set the path to the directory containing this books files based on its
current title and author. If there was a previous directory, its contents current title and author. If there was a previous directory, its contents
@ -428,7 +428,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
stream = cStringIO.StringIO(f) stream = cStringIO.StringIO(f)
self.add_format(id, format, stream, index_is_id=True, path=tpath) self.add_format(id, format, stream, index_is_id=True, path=tpath)
self.conn.execute('UPDATE books SET path=? WHERE id=?', (path, id)) self.conn.execute('UPDATE books SET path=? WHERE id=?', (path, id))
self.conn.commit() if commit:
self.conn.commit()
self.data.set(id, self.FIELD_MAP['path'], path, row_is_id=True) self.data.set(id, self.FIELD_MAP['path'], path, row_is_id=True)
# Delete not needed directories # Delete not needed directories
if current_path and os.path.exists(spath): if current_path and os.path.exists(spath):
@ -729,7 +730,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if notify: if notify:
self.notify('delete', [id]) self.notify('delete', [id])
def remove_format(self, index, format, index_is_id=False, notify=True): def remove_format(self, index, format, index_is_id=False, notify=True, commit=True):
id = index if index_is_id else self.id(index) id = index if index_is_id else self.id(index)
name = self.conn.get('SELECT name FROM data WHERE book=? AND format=?', (id, format), all=False) name = self.conn.get('SELECT name FROM data WHERE book=? AND format=?', (id, format), all=False)
if name: if name:
@ -739,7 +740,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
except: except:
traceback.print_exc() traceback.print_exc()
self.conn.execute('DELETE FROM data WHERE book=? AND format=?', (id, format.upper())) self.conn.execute('DELETE FROM data WHERE book=? AND format=?', (id, format.upper()))
self.conn.commit() if commit:
self.conn.commit()
self.refresh_ids([id]) self.refresh_ids([id])
if notify: if notify:
self.notify('metadata', [id]) self.notify('metadata', [id])
@ -1016,7 +1018,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if mi.series: if mi.series:
doit(self.set_series, id, mi.series, notify=False) doit(self.set_series, id, mi.series, notify=False)
if mi.cover_data[1] is not None: if mi.cover_data[1] is not None:
doit(self.set_cover, id, mi.cover_data[1]) doit(self.set_cover, id, mi.cover_data[1]) # doesn't use commit
elif mi.cover is not None and os.access(mi.cover, os.R_OK): elif mi.cover is not None and os.access(mi.cover, os.R_OK):
doit(self.set_cover, id, open(mi.cover, 'rb')) doit(self.set_cover, id, open(mi.cover, 'rb'))
if mi.tags: if mi.tags:
@ -1092,7 +1094,6 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
(id, aid)) (id, aid))
except IntegrityError: # Sometimes books specify the same author twice in their metadata except IntegrityError: # Sometimes books specify the same author twice in their metadata
pass pass
self.conn.commit()
ss = self.author_sort_from_book(id, index_is_id=True) ss = self.author_sort_from_book(id, index_is_id=True)
self.conn.execute('UPDATE books SET author_sort=? WHERE id=?', self.conn.execute('UPDATE books SET author_sort=? WHERE id=?',
(ss, id)) (ss, id))
@ -1121,24 +1122,26 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if notify: if notify:
self.notify('metadata', [id]) self.notify('metadata', [id])
def set_timestamp(self, id, dt, notify=True): def set_timestamp(self, id, dt, notify=True, commit=True):
if dt: if dt:
self.conn.execute('UPDATE books SET timestamp=? WHERE id=?', (dt, id)) self.conn.execute('UPDATE books SET timestamp=? WHERE id=?', (dt, id))
self.data.set(id, self.FIELD_MAP['timestamp'], dt, row_is_id=True) self.data.set(id, self.FIELD_MAP['timestamp'], dt, row_is_id=True)
self.conn.commit() if commit:
self.conn.commit()
if notify: if notify:
self.notify('metadata', [id]) self.notify('metadata', [id])
def set_pubdate(self, id, dt, notify=True): def set_pubdate(self, id, dt, notify=True, commit=True):
if dt: if dt:
self.conn.execute('UPDATE books SET pubdate=? WHERE id=?', (dt, id)) self.conn.execute('UPDATE books SET pubdate=? WHERE id=?', (dt, id))
self.data.set(id, self.FIELD_MAP['pubdate'], dt, row_is_id=True) self.data.set(id, self.FIELD_MAP['pubdate'], dt, row_is_id=True)
self.conn.commit() if commit:
self.conn.commit()
if notify: if notify:
self.notify('metadata', [id]) self.notify('metadata', [id])
def set_publisher(self, id, publisher, notify=True): def set_publisher(self, id, publisher, notify=True, commit=True):
self.conn.execute('DELETE FROM books_publishers_link WHERE book=?',(id,)) self.conn.execute('DELETE FROM books_publishers_link WHERE book=?',(id,))
self.conn.execute('DELETE FROM publishers WHERE (SELECT COUNT(id) FROM books_publishers_link WHERE publisher=publishers.id) < 1') self.conn.execute('DELETE FROM publishers WHERE (SELECT COUNT(id) FROM books_publishers_link WHERE publisher=publishers.id) < 1')
if publisher: if publisher:
@ -1150,7 +1153,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
else: else:
aid = self.conn.execute('INSERT INTO publishers(name) VALUES (?)', (publisher,)).lastrowid aid = self.conn.execute('INSERT INTO publishers(name) VALUES (?)', (publisher,)).lastrowid
self.conn.execute('INSERT INTO books_publishers_link(book, publisher) VALUES (?,?)', (id, aid)) self.conn.execute('INSERT INTO books_publishers_link(book, publisher) VALUES (?,?)', (id, aid))
self.conn.commit() if commit:
self.conn.commit()
self.data.set(id, self.FIELD_MAP['publisher'], publisher, row_is_id=True) self.data.set(id, self.FIELD_MAP['publisher'], publisher, row_is_id=True)
if notify: if notify:
self.notify('metadata', [id]) self.notify('metadata', [id])
@ -1447,7 +1451,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
if notify: if notify:
self.notify('metadata', ids) self.notify('metadata', ids)
def set_tags(self, id, tags, append=False, notify=True): def commit(self):
self.conn.commit()
def set_tags(self, id, tags, append=False, notify=True, commit=True):
''' '''
@param tags: list of strings @param tags: list of strings
@param append: If True existing tags are not removed @param append: If True existing tags are not removed
@ -1481,7 +1488,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
(id, tid), all=False): (id, tid), all=False):
self.conn.execute('INSERT INTO books_tags_link(book, tag) VALUES (?,?)', self.conn.execute('INSERT INTO books_tags_link(book, tag) VALUES (?,?)',
(id, tid)) (id, tid))
self.conn.commit() if commit:
self.conn.commit()
tags = u','.join(self.get_tags(id)) tags = u','.join(self.get_tags(id))
self.data.set(id, self.FIELD_MAP['tags'], tags, row_is_id=True) self.data.set(id, self.FIELD_MAP['tags'], tags, row_is_id=True)
if notify: if notify:
@ -1520,7 +1528,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.conn.execute('DELETE FROM tags WHERE id=?', (id,)) self.conn.execute('DELETE FROM tags WHERE id=?', (id,))
self.conn.commit() self.conn.commit()
def set_series(self, id, series, notify=True): def set_series(self, id, series, notify=True, commit=True):
self.conn.execute('DELETE FROM books_series_link WHERE book=?',(id,)) self.conn.execute('DELETE FROM books_series_link WHERE book=?',(id,))
self.conn.execute('DELETE FROM series WHERE (SELECT COUNT(id) FROM books_series_link WHERE series=series.id) < 1') self.conn.execute('DELETE FROM series WHERE (SELECT COUNT(id) FROM books_series_link WHERE series=series.id) < 1')
if series: if series:
@ -1534,12 +1542,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
else: else:
aid = self.conn.execute('INSERT INTO series(name) VALUES (?)', (series,)).lastrowid aid = self.conn.execute('INSERT INTO series(name) VALUES (?)', (series,)).lastrowid
self.conn.execute('INSERT INTO books_series_link(book, series) VALUES (?,?)', (id, aid)) self.conn.execute('INSERT INTO books_series_link(book, series) VALUES (?,?)', (id, aid))
self.conn.commit() if commit:
self.conn.commit()
self.data.set(id, self.FIELD_MAP['series'], series, row_is_id=True) self.data.set(id, self.FIELD_MAP['series'], series, row_is_id=True)
if notify: if notify:
self.notify('metadata', [id]) self.notify('metadata', [id])
def set_series_index(self, id, idx, notify=True): def set_series_index(self, id, idx, notify=True, commit=True):
if idx is None: if idx is None:
idx = 1.0 idx = 1.0
try: try:
@ -1547,40 +1556,45 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
except: except:
idx = 1.0 idx = 1.0
self.conn.execute('UPDATE books SET series_index=? WHERE id=?', (idx, id)) self.conn.execute('UPDATE books SET series_index=? WHERE id=?', (idx, id))
self.conn.commit() if commit:
self.conn.commit()
self.data.set(id, self.FIELD_MAP['series_index'], idx, row_is_id=True) self.data.set(id, self.FIELD_MAP['series_index'], idx, row_is_id=True)
if notify: if notify:
self.notify('metadata', [id]) self.notify('metadata', [id])
def set_rating(self, id, rating, notify=True): def set_rating(self, id, rating, notify=True, commit=True):
rating = int(rating) rating = int(rating)
self.conn.execute('DELETE FROM books_ratings_link WHERE book=?',(id,)) self.conn.execute('DELETE FROM books_ratings_link WHERE book=?',(id,))
rat = self.conn.get('SELECT id FROM ratings WHERE rating=?', (rating,), all=False) rat = self.conn.get('SELECT id FROM ratings WHERE rating=?', (rating,), all=False)
rat = rat if rat else self.conn.execute('INSERT INTO ratings(rating) VALUES (?)', (rating,)).lastrowid rat = rat if rat else self.conn.execute('INSERT INTO ratings(rating) VALUES (?)', (rating,)).lastrowid
self.conn.execute('INSERT INTO books_ratings_link(book, rating) VALUES (?,?)', (id, rat)) self.conn.execute('INSERT INTO books_ratings_link(book, rating) VALUES (?,?)', (id, rat))
self.conn.commit() if commit:
self.conn.commit()
self.data.set(id, self.FIELD_MAP['rating'], rating, row_is_id=True) self.data.set(id, self.FIELD_MAP['rating'], rating, row_is_id=True)
if notify: if notify:
self.notify('metadata', [id]) self.notify('metadata', [id])
def set_comment(self, id, text, notify=True): def set_comment(self, id, text, notify=True, commit=True):
self.conn.execute('DELETE FROM comments WHERE book=?', (id,)) self.conn.execute('DELETE FROM comments WHERE book=?', (id,))
self.conn.execute('INSERT INTO comments(book,text) VALUES (?,?)', (id, text)) self.conn.execute('INSERT INTO comments(book,text) VALUES (?,?)', (id, text))
self.conn.commit() if commit:
self.conn.commit()
self.data.set(id, self.FIELD_MAP['comments'], text, row_is_id=True) self.data.set(id, self.FIELD_MAP['comments'], text, row_is_id=True)
if notify: if notify:
self.notify('metadata', [id]) self.notify('metadata', [id])
def set_author_sort(self, id, sort, notify=True): def set_author_sort(self, id, sort, notify=True, commit=True):
self.conn.execute('UPDATE books SET author_sort=? WHERE id=?', (sort, id)) self.conn.execute('UPDATE books SET author_sort=? WHERE id=?', (sort, id))
self.conn.commit() if commit:
self.conn.commit()
self.data.set(id, self.FIELD_MAP['author_sort'], sort, row_is_id=True) self.data.set(id, self.FIELD_MAP['author_sort'], sort, row_is_id=True)
if notify: if notify:
self.notify('metadata', [id]) self.notify('metadata', [id])
def set_isbn(self, id, isbn, notify=True): def set_isbn(self, id, isbn, notify=True, commit=True):
self.conn.execute('UPDATE books SET isbn=? WHERE id=?', (isbn, id)) self.conn.execute('UPDATE books SET isbn=? WHERE id=?', (isbn, id))
self.conn.commit() if commit:
self.conn.commit()
self.data.set(id, self.FIELD_MAP['isbn'], isbn, row_is_id=True) self.data.set(id, self.FIELD_MAP['isbn'], isbn, row_is_id=True)
if notify: if notify:
self.notify('metadata', [id]) self.notify('metadata', [id])