Adding works (more or less)

This commit is contained in:
Kovid Goyal 2009-05-15 00:02:32 -07:00
parent 92a1d8c4e7
commit 042841b912
10 changed files with 97 additions and 64 deletions

View File

@ -28,6 +28,14 @@ def path_to_ext(path):
return os.path.splitext(path)[1][1:].lower() return os.path.splitext(path)[1][1:].lower()
def metadata_from_formats(formats): def metadata_from_formats(formats):
try:
return _metadata_from_formats(formats)
except:
mi = metadata_from_filename(formats[0])
if not mi.authors:
mi.authors = [_('Unknown')]
def _metadata_from_formats(formats):
mi = MetaInformation(None, None) mi = MetaInformation(None, None)
formats.sort(cmp=lambda x,y: cmp(METADATA_PRIORITIES[path_to_ext(x)], formats.sort(cmp=lambda x,y: cmp(METADATA_PRIORITIES[path_to_ext(x)],
METADATA_PRIORITIES[path_to_ext(y)])) METADATA_PRIORITIES[path_to_ext(y)]))

View File

@ -387,6 +387,8 @@ class MetadataField(object):
ans = self.formatter(ans) ans = self.formatter(ans)
except: except:
return None return None
if hasattr(ans, 'strip'):
ans = ans.strip()
return ans return ans
def __get__(self, obj, type=None): def __get__(self, obj, type=None):

View File

@ -8,13 +8,18 @@ __docformat__ = 'restructuredtext en'
from threading import Thread from threading import Thread
from Queue import Empty from Queue import Empty
import os, time import os, time, sys
from calibre.utils.ipc.job import ParallelJob from calibre.utils.ipc.job import ParallelJob
from calibre.utils.ipc.server import Server from calibre.utils.ipc.server import Server
from calibre.ptempfile import PersistentTemporaryDirectory from calibre.ptempfile import PersistentTemporaryDirectory
from calibre import prints from calibre import prints
def debug(*args):
prints(*args)
sys.stdout.flush()
def read_metadata_(task, tdir, notification=lambda x,y:x): def read_metadata_(task, tdir, notification=lambda x,y:x):
from calibre.ebooks.metadata.meta import metadata_from_formats from calibre.ebooks.metadata.meta import metadata_from_formats
from calibre.ebooks.metadata.opf2 import OPFCreator from calibre.ebooks.metadata.opf2 import OPFCreator
@ -44,7 +49,7 @@ class Progress(object):
def __call__(self, id): def __call__(self, id):
cover = os.path.join(self.tdir, str(id)) cover = os.path.join(self.tdir, str(id))
if not os.path.exists(cover): cover = None if not os.path.exists(cover): cover = None
self.result_queue.put((id, os.path.join(self.tdir, id+'.opf'), cover)) self.result_queue.put((id, os.path.join(self.tdir, '%s.opf'%id), cover))
class ReadMetadata(Thread): class ReadMetadata(Thread):
@ -57,7 +62,10 @@ class ReadMetadata(Thread):
def run(self): def run(self):
jobs, ids = set([]), set([id for id, p in self.tasks]) jobs, ids = set([]), set([])
for t in self.tasks:
for b in t:
ids.add(b[0])
progress = Progress(self.result_queue, self.tdir) progress = Progress(self.result_queue, self.tdir)
server = Server() server = Server()
for i, task in enumerate(self.tasks): for i, task in enumerate(self.tasks):
@ -74,6 +82,7 @@ class ReadMetadata(Thread):
while True: while True:
try: try:
id = job.notifications.get_nowait()[-1] id = job.notifications.get_nowait()[-1]
if id in ids:
progress(id) progress(id)
ids.remove(id) ids.remove(id)
except Empty: except Empty:
@ -81,15 +90,18 @@ class ReadMetadata(Thread):
job.update() job.update()
if not job.is_finished: if not job.is_finished:
running = True running = True
if not running: if not running:
break break
if self.canceled:
server.close() server.close()
time.sleep(1) time.sleep(1)
if self.canceled:
return return
for id in ids: for id in ids:
print 11111111, id
progress(id) progress(id)
for job in jobs: for job in jobs:
@ -99,9 +111,8 @@ class ReadMetadata(Thread):
os.remove(job.log_path) os.remove(job.log_path)
def read_metadata(paths, result_queue): def read_metadata(paths, result_queue, chunk=50):
tasks = [] tasks = []
chunk = 50
pos = 0 pos = 0
while pos < len(paths): while pos < len(paths):
tasks.append(paths[pos:pos+chunk]) tasks.append(paths[pos:pos+chunk])

View File

@ -122,7 +122,7 @@ def question_dialog(parent, title, msg, det_msg=''):
parent) parent)
d.setDetailedText(det_msg) d.setDetailedText(det_msg)
d.setIconPixmap(QPixmap(':/images/dialog_information.svg')) d.setIconPixmap(QPixmap(':/images/dialog_information.svg'))
return d return d.exec_() == QMessageBox.Yes
def info_dialog(parent, title, msg, det_msg='', show=False): def info_dialog(parent, title, msg, det_msg='', show=False):
d = QMessageBox(QMessageBox.Information, title, msg, QMessageBox.NoButton, d = QMessageBox(QMessageBox.Information, title, msg, QMessageBox.NoButton,

View File

@ -2,12 +2,12 @@
UI for adding books to the database UI for adding books to the database
''' '''
import os import os
from threading import Queue, Empty from Queue import Queue, Empty
from PyQt4.Qt import QThread, SIGNAL, QObject, QTimer from PyQt4.Qt import QThread, SIGNAL, QObject, QTimer, Qt
from calibre.gui2.dialogs.progress import ProgressDialog from calibre.gui2.dialogs.progress import ProgressDialog
from calibre.gui2 import warning_dialog from calibre.gui2 import question_dialog
from calibre.ebooks.metadata.opf2 import OPF from calibre.ebooks.metadata.opf2 import OPF
from calibre.ebooks.metadata import MetaInformation from calibre.ebooks.metadata import MetaInformation
from calibre.constants import preferred_encoding from calibre.constants import preferred_encoding
@ -17,11 +17,13 @@ class RecursiveFind(QThread):
def __init__(self, parent, db, root, single): def __init__(self, parent, db, root, single):
QThread.__init__(self, parent) QThread.__init__(self, parent)
self.db = db self.db = db
self.path = root, self.single_book_per_directory = single self.path = root
self.single_book_per_directory = single
self.canceled = False self.canceled = False
def run(self): def run(self):
root = os.path.abspath(self.path) root = os.path.abspath(self.path)
self.books = []
for dirpath in os.walk(root): for dirpath in os.walk(root):
if self.canceled: if self.canceled:
return return
@ -47,6 +49,7 @@ class Adder(QObject):
self.number_of_books_added = 0 self.number_of_books_added = 0
self.rfind = self.worker = self.timer = None self.rfind = self.worker = self.timer = None
self.callback = callback self.callback = callback
self.callback_called = False
self.infos, self.paths, self.names = [], [], [] self.infos, self.paths, self.names = [], [], []
self.connect(self.pd, SIGNAL('canceled()'), self.canceled) self.connect(self.pd, SIGNAL('canceled()'), self.canceled)
@ -58,9 +61,10 @@ class Adder(QObject):
self.pd.value = 0 self.pd.value = 0
self.rfind = RecursiveFind(self, self.db, root, single) self.rfind = RecursiveFind(self, self.db, root, single)
self.connect(self.rfind, SIGNAL('update(PyQt_PyObject)'), self.connect(self.rfind, SIGNAL('update(PyQt_PyObject)'),
self.pd.set_msg) self.pd.set_msg, Qt.QueuedConnection)
self.connect(self.rfind, SIGNAL('found(PyQt_PyObject)'), self.connect(self.rfind, SIGNAL('found(PyQt_PyObject)'),
self.add) self.add, Qt.QueuedConnection)
self.rfind.start()
def add(self, books): def add(self, books):
books = [[b] if isinstance(b, basestring) else b for b in books] books = [[b] if isinstance(b, basestring) else b for b in books]
@ -71,10 +75,10 @@ class Adder(QObject):
self.ids = {} self.ids = {}
self.nmap = {} self.nmap = {}
self.duplicates = [] self.duplicates = []
for i, b in books: for i, b in enumerate(books):
tasks.append((i, b)) tasks.append((i, b))
self.ids[i] = b self.ids[i] = b
self.nmap = os.path.basename(b[0]) self.nmap[i] = os.path.basename(b[0])
self.worker = read_metadata(tasks, self.rq) self.worker = read_metadata(tasks, self.rq)
self.pd.set_min(0) self.pd.set_min(0)
self.pd.set_max(len(self.ids)) self.pd.set_max(len(self.ids))
@ -97,6 +101,10 @@ class Adder(QObject):
if self.worker is not None: if self.worker is not None:
self.worker.canceled = True self.worker.canceled = True
self.pd.hide() self.pd.hide()
if not self.callback_called:
self.callback(self.paths, self.names, self.infos)
self.callback_called = True
def update(self): def update(self):
@ -104,7 +112,9 @@ class Adder(QObject):
self.timer.stop() self.timer.stop()
self.process_duplicates() self.process_duplicates()
self.pd.hide() self.pd.hide()
if not self.callback_called:
self.callback(self.paths, self.names, self.infos) self.callback(self.paths, self.names, self.infos)
self.callback_called = True
return return
try: try:
@ -139,15 +149,16 @@ class Adder(QObject):
'tags':mi.tags if mi.tags else []}) 'tags':mi.tags if mi.tags else []})
def process_duplicates(self): def process_duplicates(self):
if not self.duplicates:
return
files = [x[0].title for x in self.duplicates] files = [x[0].title for x in self.duplicates]
d = warning_dialog(_('Duplicates found!'), if question_dialog(self._parent, _('Duplicates found!'),
_('Books with the same title as the following already ' _('Books with the same title as the following already '
'exist in the database. Add them anyway?'), 'exist in the database. Add them anyway?'),
'\n'.join(files), parent=self._parent) '\n'.join(files)):
if d.exec_() == d.Accepted:
for mi, cover, formats in self.duplicates: for mi, cover, formats in self.duplicates:
id = self.db.create_book_entry(mi, cover=cover, id = self.db.create_book_entry(mi, cover=cover,
add_duplicates=False) add_duplicates=True)
self.add_formats(id, formats) self.add_formats(id, formats)
self.number_of_books_added += 1 self.number_of_books_added += 1

View File

@ -1,7 +1,7 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
from PyQt4.QtCore import SIGNAL, Qt from PyQt4.QtCore import SIGNAL, Qt
from PyQt4.QtGui import QDialog, QMessageBox from PyQt4.QtGui import QDialog
from calibre.gui2.dialogs.tag_editor_ui import Ui_TagEditor from calibre.gui2.dialogs.tag_editor_ui import Ui_TagEditor
from calibre.gui2 import qstring_to_unicode from calibre.gui2 import qstring_to_unicode
@ -59,9 +59,9 @@ class TagEditor(QDialog, Ui_TagEditor):
deletes.append(item) deletes.append(item)
if confirms: if confirms:
ct = ', '.join([qstring_to_unicode(item.text()) for item in confirms]) ct = ', '.join([qstring_to_unicode(item.text()) for item in confirms])
d = question_dialog(self, 'Are your sure?', if question_dialog(self, _('Are your sure?'),
'<p>The following tags are used by one or more books. Are you certain you want to delete them?<br>'+ct) '<p>'+_('The following tags are used by one or more books. '
if d.exec_() == QMessageBox.Yes: 'Are you certain you want to delete them?')+'<br>'+ct):
deletes += confirms deletes += confirms
for item in deletes: for item in deletes:

View File

@ -3,7 +3,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import time, os import time, os
from PyQt4.QtCore import SIGNAL, QUrl from PyQt4.QtCore import SIGNAL, QUrl
from PyQt4.QtGui import QMessageBox, QDesktopServices from PyQt4.QtGui import QDesktopServices
from calibre.web.feeds.recipes import compile_recipe from calibre.web.feeds.recipes import compile_recipe
from calibre.web.feeds.news import AutomaticNewsRecipe from calibre.web.feeds.news import AutomaticNewsRecipe
@ -175,9 +175,9 @@ class %(classname)s(%(base_class)s):
try: try:
self.available_profiles.add_item(title, (title, profile), replace=False) self.available_profiles.add_item(title, (title, profile), replace=False)
except ValueError: except ValueError:
d = question_dialog(self, _('Replace recipe?'), if question_dialog(self, _('Replace recipe?'),
_('A custom recipe named %s already exists. Do you want to replace it?')%title) _('A custom recipe named %s already exists. Do you want to '
if d.exec_() == QMessageBox.Yes: 'replace it?')%title):
self.available_profiles.add_item(title, (title, profile), replace=True) self.available_profiles.add_item(title, (title, profile), replace=True)
else: else:
return return
@ -207,9 +207,9 @@ class %(classname)s(%(base_class)s):
try: try:
self.available_profiles.add_item(title, (title, r.text), replace=False) self.available_profiles.add_item(title, (title, r.text), replace=False)
except ValueError: except ValueError:
d = question_dialog(self, _('Replace recipe?'), if question_dialog(self, _('Replace recipe?'),
_('A custom recipe named %s already exists. Do you want to replace it?')%title) _('A custom recipe named %s already exists. Do you '
if d.exec_() == QMessageBox.Yes: 'want to replace it?')%title):
self.available_profiles.add_item(title, (title, r.text), replace=True) self.available_profiles.add_item(title, (title, r.text), replace=True)
else: else:
return return
@ -231,9 +231,9 @@ class %(classname)s(%(base_class)s):
try: try:
self.available_profiles.add_item(title, (title, src), replace=False) self.available_profiles.add_item(title, (title, src), replace=False)
except ValueError: except ValueError:
d = question_dialog(self, _('Replace recipe?'), if question_dialog(self, _('Replace recipe?'),
_('A custom recipe named %s already exists. Do you want to replace it?')%title) _('A custom recipe named %s already exists. Do you want to '
if d.exec_() == QMessageBox.Yes: 'replace it?')%title):
self.available_profiles.add_item(title, (title, src), replace=True) self.available_profiles.add_item(title, (title, src), replace=True)
else: else:
return return

View File

@ -1576,12 +1576,11 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.vanity.update() self.vanity.update()
if config.get('new_version_notification') and \ if config.get('new_version_notification') and \
dynamic.get('update to version %s'%version, True): dynamic.get('update to version %s'%version, True):
d = question_dialog(self, _('Update available'), if question_dialog(self, _('Update available'),
_('%s has been updated to version %s. ' _('%s has been updated to version %s. '
'See the <a href="http://calibre.kovidgoyal.net/wiki/' 'See the <a href="http://calibre.kovidgoyal.net/wiki/'
'Changelog">new features</a>. Visit the download pa' 'Changelog">new features</a>. Visit the download pa'
'ge?')%(__appname__, version)) 'ge?')%(__appname__, version)):
if d.exec_() == QMessageBox.Yes:
url = 'http://calibre.kovidgoyal.net/download_'+\ url = 'http://calibre.kovidgoyal.net/download_'+\
('windows' if iswindows else 'osx' if isosx else 'linux') ('windows' if iswindows else 'osx' if isosx else 'linux')
QDesktopServices.openUrl(QUrl(url)) QDesktopServices.openUrl(QUrl(url))

View File

@ -166,8 +166,8 @@ class Server(Thread):
if len(self.pool) + len(self.workers) < self.pool_size: if len(self.pool) + len(self.workers) < self.pool_size:
try: try:
self.pool.append(self.launch_worker()) self.pool.append(self.launch_worker())
except: except Exception, err:
break pass
if len(self.pool) > 0 and len(self.waiting_jobs) > 0: if len(self.pool) > 0 and len(self.waiting_jobs) > 0:
job = self.waiting_jobs.pop() job = self.waiting_jobs.pop()

View File

@ -65,6 +65,8 @@ def main():
resultf = unhexlify(os.environ['CALIBRE_WORKER_RESULT']) resultf = unhexlify(os.environ['CALIBRE_WORKER_RESULT'])
with closing(Client(address, authkey=key)) as conn: with closing(Client(address, authkey=key)) as conn:
name, args, kwargs = conn.recv() name, args, kwargs = conn.recv()
#print (name, args, kwargs)
#sys.stdout.flush()
func, notification = get_func(name) func, notification = get_func(name)
notifier = Progress(conn) notifier = Progress(conn)
if notification: if notification: