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()
|
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)]))
|
||||||
|
@ -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):
|
||||||
|
@ -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,22 +82,26 @@ class ReadMetadata(Thread):
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
id = job.notifications.get_nowait()[-1]
|
id = job.notifications.get_nowait()[-1]
|
||||||
progress(id)
|
if id in ids:
|
||||||
ids.remove(id)
|
progress(id)
|
||||||
|
ids.remove(id)
|
||||||
except Empty:
|
except Empty:
|
||||||
break
|
break
|
||||||
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
|
||||||
|
|
||||||
|
server.close()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
if self.canceled:
|
if self.canceled:
|
||||||
server.close()
|
|
||||||
time.sleep(1)
|
|
||||||
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])
|
||||||
|
@ -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,
|
||||||
|
@ -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()
|
||||||
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
|
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
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
|
@ -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()
|
||||||
|
@ -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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user