mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Adding works (more or less)
This commit is contained in:
parent
92a1d8c4e7
commit
042841b912
@ -28,6 +28,14 @@ def path_to_ext(path):
|
||||
return os.path.splitext(path)[1][1:].lower()
|
||||
|
||||
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)
|
||||
formats.sort(cmp=lambda x,y: cmp(METADATA_PRIORITIES[path_to_ext(x)],
|
||||
METADATA_PRIORITIES[path_to_ext(y)]))
|
||||
|
@ -387,6 +387,8 @@ class MetadataField(object):
|
||||
ans = self.formatter(ans)
|
||||
except:
|
||||
return None
|
||||
if hasattr(ans, 'strip'):
|
||||
ans = ans.strip()
|
||||
return ans
|
||||
|
||||
def __get__(self, obj, type=None):
|
||||
|
@ -8,13 +8,18 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
from threading import Thread
|
||||
from Queue import Empty
|
||||
import os, time
|
||||
import os, time, sys
|
||||
|
||||
from calibre.utils.ipc.job import ParallelJob
|
||||
from calibre.utils.ipc.server import Server
|
||||
from calibre.ptempfile import PersistentTemporaryDirectory
|
||||
from calibre import prints
|
||||
|
||||
|
||||
def debug(*args):
|
||||
prints(*args)
|
||||
sys.stdout.flush()
|
||||
|
||||
def read_metadata_(task, tdir, notification=lambda x,y:x):
|
||||
from calibre.ebooks.metadata.meta import metadata_from_formats
|
||||
from calibre.ebooks.metadata.opf2 import OPFCreator
|
||||
@ -44,7 +49,7 @@ class Progress(object):
|
||||
def __call__(self, id):
|
||||
cover = os.path.join(self.tdir, str(id))
|
||||
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):
|
||||
|
||||
@ -57,7 +62,10 @@ class ReadMetadata(Thread):
|
||||
|
||||
|
||||
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)
|
||||
server = Server()
|
||||
for i, task in enumerate(self.tasks):
|
||||
@ -74,22 +82,26 @@ class ReadMetadata(Thread):
|
||||
while True:
|
||||
try:
|
||||
id = job.notifications.get_nowait()[-1]
|
||||
progress(id)
|
||||
ids.remove(id)
|
||||
if id in ids:
|
||||
progress(id)
|
||||
ids.remove(id)
|
||||
except Empty:
|
||||
break
|
||||
job.update()
|
||||
if not job.is_finished:
|
||||
running = True
|
||||
|
||||
if not running:
|
||||
break
|
||||
|
||||
server.close()
|
||||
time.sleep(1)
|
||||
|
||||
if self.canceled:
|
||||
server.close()
|
||||
time.sleep(1)
|
||||
return
|
||||
|
||||
for id in ids:
|
||||
print 11111111, id
|
||||
progress(id)
|
||||
|
||||
for job in jobs:
|
||||
@ -99,9 +111,8 @@ class ReadMetadata(Thread):
|
||||
os.remove(job.log_path)
|
||||
|
||||
|
||||
def read_metadata(paths, result_queue):
|
||||
def read_metadata(paths, result_queue, chunk=50):
|
||||
tasks = []
|
||||
chunk = 50
|
||||
pos = 0
|
||||
while pos < len(paths):
|
||||
tasks.append(paths[pos:pos+chunk])
|
||||
|
@ -122,7 +122,7 @@ def question_dialog(parent, title, msg, det_msg=''):
|
||||
parent)
|
||||
d.setDetailedText(det_msg)
|
||||
d.setIconPixmap(QPixmap(':/images/dialog_information.svg'))
|
||||
return d
|
||||
return d.exec_() == QMessageBox.Yes
|
||||
|
||||
def info_dialog(parent, title, msg, det_msg='', show=False):
|
||||
d = QMessageBox(QMessageBox.Information, title, msg, QMessageBox.NoButton,
|
||||
|
@ -2,12 +2,12 @@
|
||||
UI for adding books to the database
|
||||
'''
|
||||
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 import warning_dialog
|
||||
from calibre.gui2 import question_dialog
|
||||
from calibre.ebooks.metadata.opf2 import OPF
|
||||
from calibre.ebooks.metadata import MetaInformation
|
||||
from calibre.constants import preferred_encoding
|
||||
@ -17,11 +17,13 @@ class RecursiveFind(QThread):
|
||||
def __init__(self, parent, db, root, single):
|
||||
QThread.__init__(self, parent)
|
||||
self.db = db
|
||||
self.path = root, self.single_book_per_directory = single
|
||||
self.path = root
|
||||
self.single_book_per_directory = single
|
||||
self.canceled = False
|
||||
|
||||
def run(self):
|
||||
root = os.path.abspath(self.path)
|
||||
self.books = []
|
||||
for dirpath in os.walk(root):
|
||||
if self.canceled:
|
||||
return
|
||||
@ -47,6 +49,7 @@ class Adder(QObject):
|
||||
self.number_of_books_added = 0
|
||||
self.rfind = self.worker = self.timer = None
|
||||
self.callback = callback
|
||||
self.callback_called = False
|
||||
self.infos, self.paths, self.names = [], [], []
|
||||
self.connect(self.pd, SIGNAL('canceled()'), self.canceled)
|
||||
|
||||
@ -58,9 +61,10 @@ class Adder(QObject):
|
||||
self.pd.value = 0
|
||||
self.rfind = RecursiveFind(self, self.db, root, single)
|
||||
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.add)
|
||||
self.add, Qt.QueuedConnection)
|
||||
self.rfind.start()
|
||||
|
||||
def add(self, books):
|
||||
books = [[b] if isinstance(b, basestring) else b for b in books]
|
||||
@ -71,10 +75,10 @@ class Adder(QObject):
|
||||
self.ids = {}
|
||||
self.nmap = {}
|
||||
self.duplicates = []
|
||||
for i, b in books:
|
||||
for i, b in enumerate(books):
|
||||
tasks.append((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.pd.set_min(0)
|
||||
self.pd.set_max(len(self.ids))
|
||||
@ -97,6 +101,10 @@ class Adder(QObject):
|
||||
if self.worker is not None:
|
||||
self.worker.canceled = True
|
||||
self.pd.hide()
|
||||
if not self.callback_called:
|
||||
self.callback(self.paths, self.names, self.infos)
|
||||
self.callback_called = True
|
||||
|
||||
|
||||
|
||||
def update(self):
|
||||
@ -104,7 +112,9 @@ class Adder(QObject):
|
||||
self.timer.stop()
|
||||
self.process_duplicates()
|
||||
self.pd.hide()
|
||||
self.callback(self.paths, self.names, self.infos)
|
||||
if not self.callback_called:
|
||||
self.callback(self.paths, self.names, self.infos)
|
||||
self.callback_called = True
|
||||
return
|
||||
|
||||
try:
|
||||
@ -139,15 +149,16 @@ class Adder(QObject):
|
||||
'tags':mi.tags if mi.tags else []})
|
||||
|
||||
def process_duplicates(self):
|
||||
if not self.duplicates:
|
||||
return
|
||||
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 '
|
||||
'exist in the database. Add them anyway?'),
|
||||
'\n'.join(files), parent=self._parent)
|
||||
if d.exec_() == d.Accepted:
|
||||
'\n'.join(files)):
|
||||
for mi, cover, formats in self.duplicates:
|
||||
id = self.db.create_book_entry(mi, cover=cover,
|
||||
add_duplicates=False)
|
||||
add_duplicates=True)
|
||||
self.add_formats(id, formats)
|
||||
self.number_of_books_added += 1
|
||||
|
||||
|
@ -1,19 +1,19 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
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 import qstring_to_unicode
|
||||
from calibre.gui2 import question_dialog, error_dialog
|
||||
|
||||
class TagEditor(QDialog, Ui_TagEditor):
|
||||
|
||||
|
||||
def __init__(self, window, db, index=None):
|
||||
QDialog.__init__(self, window)
|
||||
Ui_TagEditor.__init__(self)
|
||||
self.setupUi(self)
|
||||
|
||||
|
||||
self.db = db
|
||||
self.index = index
|
||||
if self.index is not None:
|
||||
@ -27,16 +27,16 @@ class TagEditor(QDialog, Ui_TagEditor):
|
||||
self.applied_tags.addItem(tag)
|
||||
else:
|
||||
tags = []
|
||||
|
||||
|
||||
self.tags = tags
|
||||
|
||||
|
||||
all_tags = [tag for tag in self.db.all_tags()]
|
||||
all_tags = list(set(all_tags))
|
||||
all_tags.sort()
|
||||
for tag in all_tags:
|
||||
if tag not in tags:
|
||||
self.available_tags.addItem(tag)
|
||||
|
||||
|
||||
self.connect(self.apply_button, SIGNAL('clicked()'), self.apply_tags)
|
||||
self.connect(self.unapply_button, SIGNAL('clicked()'), self.unapply_tags)
|
||||
self.connect(self.add_tag_button, SIGNAL('clicked()'), self.add_tag)
|
||||
@ -44,8 +44,8 @@ class TagEditor(QDialog, Ui_TagEditor):
|
||||
self.connect(self.add_tag_input, SIGNAL('returnPressed()'), self.add_tag)
|
||||
self.connect(self.available_tags, SIGNAL('itemActivated(QListWidgetItem*)'), self.apply_tags)
|
||||
self.connect(self.applied_tags, SIGNAL('itemActivated(QListWidgetItem*)'), self.unapply_tags)
|
||||
|
||||
|
||||
|
||||
|
||||
def delete_tags(self, item=None):
|
||||
confirms, deletes = [], []
|
||||
items = self.available_tags.selectedItems() if item is None else [item]
|
||||
@ -56,47 +56,47 @@ class TagEditor(QDialog, Ui_TagEditor):
|
||||
if self.db.is_tag_used(qstring_to_unicode(item.text())):
|
||||
confirms.append(item)
|
||||
else:
|
||||
deletes.append(item)
|
||||
deletes.append(item)
|
||||
if confirms:
|
||||
ct = ', '.join([qstring_to_unicode(item.text()) for item in confirms])
|
||||
d = 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)
|
||||
if d.exec_() == QMessageBox.Yes:
|
||||
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):
|
||||
deletes += confirms
|
||||
|
||||
|
||||
for item in deletes:
|
||||
self.db.delete_tag(qstring_to_unicode(item.text()))
|
||||
self.available_tags.takeItem(self.available_tags.row(item))
|
||||
|
||||
|
||||
|
||||
|
||||
def apply_tags(self, item=None):
|
||||
items = self.available_tags.selectedItems() if item is None else [item]
|
||||
items = self.available_tags.selectedItems() if item is None else [item]
|
||||
for item in items:
|
||||
tag = qstring_to_unicode(item.text())
|
||||
self.tags.append(tag)
|
||||
self.available_tags.takeItem(self.available_tags.row(item))
|
||||
|
||||
|
||||
self.tags.sort()
|
||||
self.applied_tags.clear()
|
||||
for tag in self.tags:
|
||||
self.applied_tags.addItem(tag)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def unapply_tags(self, item=None):
|
||||
items = self.applied_tags.selectedItems() if item is None else [item]
|
||||
items = self.applied_tags.selectedItems() if item is None else [item]
|
||||
for item in items:
|
||||
tag = qstring_to_unicode(item.text())
|
||||
self.tags.remove(tag)
|
||||
self.available_tags.addItem(tag)
|
||||
|
||||
|
||||
self.tags.sort()
|
||||
self.applied_tags.clear()
|
||||
for tag in self.tags:
|
||||
self.applied_tags.addItem(tag)
|
||||
|
||||
|
||||
self.available_tags.sortItems()
|
||||
|
||||
|
||||
def add_tag(self):
|
||||
tags = qstring_to_unicode(self.add_tag_input.text()).split(',')
|
||||
for tag in tags:
|
||||
@ -105,10 +105,10 @@ class TagEditor(QDialog, Ui_TagEditor):
|
||||
self.available_tags.takeItem(self.available_tags.row(item))
|
||||
if tag not in self.tags:
|
||||
self.tags.append(tag)
|
||||
|
||||
|
||||
self.tags.sort()
|
||||
self.applied_tags.clear()
|
||||
for tag in self.tags:
|
||||
self.applied_tags.addItem(tag)
|
||||
|
||||
|
||||
self.add_tag_input.setText('')
|
||||
|
@ -3,7 +3,7 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
import time, os
|
||||
|
||||
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.news import AutomaticNewsRecipe
|
||||
@ -175,9 +175,9 @@ class %(classname)s(%(base_class)s):
|
||||
try:
|
||||
self.available_profiles.add_item(title, (title, profile), replace=False)
|
||||
except ValueError:
|
||||
d = question_dialog(self, _('Replace recipe?'),
|
||||
_('A custom recipe named %s already exists. Do you want to replace it?')%title)
|
||||
if d.exec_() == QMessageBox.Yes:
|
||||
if question_dialog(self, _('Replace recipe?'),
|
||||
_('A custom recipe named %s already exists. Do you want to '
|
||||
'replace it?')%title):
|
||||
self.available_profiles.add_item(title, (title, profile), replace=True)
|
||||
else:
|
||||
return
|
||||
@ -207,9 +207,9 @@ class %(classname)s(%(base_class)s):
|
||||
try:
|
||||
self.available_profiles.add_item(title, (title, r.text), replace=False)
|
||||
except ValueError:
|
||||
d = question_dialog(self, _('Replace recipe?'),
|
||||
_('A custom recipe named %s already exists. Do you want to replace it?')%title)
|
||||
if d.exec_() == QMessageBox.Yes:
|
||||
if question_dialog(self, _('Replace recipe?'),
|
||||
_('A custom recipe named %s already exists. Do you '
|
||||
'want to replace it?')%title):
|
||||
self.available_profiles.add_item(title, (title, r.text), replace=True)
|
||||
else:
|
||||
return
|
||||
@ -231,9 +231,9 @@ class %(classname)s(%(base_class)s):
|
||||
try:
|
||||
self.available_profiles.add_item(title, (title, src), replace=False)
|
||||
except ValueError:
|
||||
d = question_dialog(self, _('Replace recipe?'),
|
||||
_('A custom recipe named %s already exists. Do you want to replace it?')%title)
|
||||
if d.exec_() == QMessageBox.Yes:
|
||||
if question_dialog(self, _('Replace recipe?'),
|
||||
_('A custom recipe named %s already exists. Do you want to '
|
||||
'replace it?')%title):
|
||||
self.available_profiles.add_item(title, (title, src), replace=True)
|
||||
else:
|
||||
return
|
||||
|
@ -1576,12 +1576,11 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
||||
self.vanity.update()
|
||||
if config.get('new_version_notification') and \
|
||||
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. '
|
||||
'See the <a href="http://calibre.kovidgoyal.net/wiki/'
|
||||
'Changelog">new features</a>. Visit the download pa'
|
||||
'ge?')%(__appname__, version))
|
||||
if d.exec_() == QMessageBox.Yes:
|
||||
'ge?')%(__appname__, version)):
|
||||
url = 'http://calibre.kovidgoyal.net/download_'+\
|
||||
('windows' if iswindows else 'osx' if isosx else 'linux')
|
||||
QDesktopServices.openUrl(QUrl(url))
|
||||
|
@ -166,8 +166,8 @@ class Server(Thread):
|
||||
if len(self.pool) + len(self.workers) < self.pool_size:
|
||||
try:
|
||||
self.pool.append(self.launch_worker())
|
||||
except:
|
||||
break
|
||||
except Exception, err:
|
||||
pass
|
||||
|
||||
if len(self.pool) > 0 and len(self.waiting_jobs) > 0:
|
||||
job = self.waiting_jobs.pop()
|
||||
|
@ -65,6 +65,8 @@ def main():
|
||||
resultf = unhexlify(os.environ['CALIBRE_WORKER_RESULT'])
|
||||
with closing(Client(address, authkey=key)) as conn:
|
||||
name, args, kwargs = conn.recv()
|
||||
#print (name, args, kwargs)
|
||||
#sys.stdout.flush()
|
||||
func, notification = get_func(name)
|
||||
notifier = Progress(conn)
|
||||
if notification:
|
||||
|
Loading…
x
Reference in New Issue
Block a user