mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Framework for GUI catalog generation
This commit is contained in:
parent
392b1bf2d1
commit
e010921c55
@ -20,3 +20,20 @@ def gui_convert(input, output, recommendations, notification=DummyReporter(),
|
|||||||
|
|
||||||
plumber.run()
|
plumber.run()
|
||||||
|
|
||||||
|
def gui_catalog(fmt, title, dbspec, ids, out_file_name,
|
||||||
|
notification=DummyReporter(), log=None):
|
||||||
|
if log is None:
|
||||||
|
log = Log()
|
||||||
|
if dbspec is None:
|
||||||
|
from calibre.utils.config import prefs
|
||||||
|
from calibre.library.database2 import LibraryDatabase2
|
||||||
|
dbpath = prefs['library_path']
|
||||||
|
db = LibraryDatabase2(dbpath)
|
||||||
|
else: # To be implemented in the future
|
||||||
|
pass
|
||||||
|
# Implement the interface to the catalog generating code here
|
||||||
|
db
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -676,6 +676,65 @@ class DeviceGUI(object):
|
|||||||
self.status_bar.showMessage(_('Sent news to')+' '+\
|
self.status_bar.showMessage(_('Sent news to')+' '+\
|
||||||
', '.join(sent_mails), 3000)
|
', '.join(sent_mails), 3000)
|
||||||
|
|
||||||
|
def sync_catalogs(self, send_ids=None, do_auto_convert=True):
|
||||||
|
if self.device_connected:
|
||||||
|
settings = self.device_manager.device.settings()
|
||||||
|
ids = list(dynamic.get('catalogs_to_be_synced', set([]))) if send_ids is None else send_ids
|
||||||
|
ids = [id for id in ids if self.library_view.model().db.has_id(id)]
|
||||||
|
files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(
|
||||||
|
ids, settings.format_map,
|
||||||
|
exclude_auto=do_auto_convert)
|
||||||
|
auto = []
|
||||||
|
if do_auto_convert and _auto_ids:
|
||||||
|
for id in _auto_ids:
|
||||||
|
dbfmts = self.library_view.model().db.formats(id, index_is_id=True)
|
||||||
|
formats = [] if dbfmts is None else \
|
||||||
|
[f.lower() for f in dbfmts.split(',')]
|
||||||
|
if set(formats).intersection(available_input_formats()) \
|
||||||
|
and set(settings.format_map).intersection(available_output_formats()):
|
||||||
|
auto.append(id)
|
||||||
|
if auto:
|
||||||
|
format = None
|
||||||
|
for fmt in settings.format_map:
|
||||||
|
if fmt in list(set(settings.format_map).intersection(set(available_output_formats()))):
|
||||||
|
format = fmt
|
||||||
|
break
|
||||||
|
if format is not None:
|
||||||
|
autos = [self.library_view.model().db.title(id, index_is_id=True) for id in auto]
|
||||||
|
autos = '\n'.join('%s'%i for i in autos)
|
||||||
|
if question_dialog(self, _('No suitable formats'),
|
||||||
|
_('Auto convert the following books before uploading to '
|
||||||
|
'the device?'), det_msg=autos):
|
||||||
|
self.auto_convert_catalogs(auto, format)
|
||||||
|
files = [f for f in files if f is not None]
|
||||||
|
if not files:
|
||||||
|
dynamic.set('catalogs_to_be_synced', set([]))
|
||||||
|
return
|
||||||
|
metadata = self.library_view.model().metadata_for(ids)
|
||||||
|
names = []
|
||||||
|
for mi in metadata:
|
||||||
|
prefix = ascii_filename(mi.title)
|
||||||
|
if not isinstance(prefix, unicode):
|
||||||
|
prefix = prefix.decode(preferred_encoding, 'replace')
|
||||||
|
prefix = ascii_filename(prefix)
|
||||||
|
names.append('%s_%d%s'%(prefix, id,
|
||||||
|
os.path.splitext(f.name)[1]))
|
||||||
|
if mi.cover and os.access(mi.cover, os.R_OK):
|
||||||
|
mi.thumbnail = self.cover_to_thumbnail(open(mi.cover,
|
||||||
|
'rb').read())
|
||||||
|
dynamic.set('catalogs_to_be_synced', set([]))
|
||||||
|
if files:
|
||||||
|
remove = []
|
||||||
|
space = { self.location_view.model().free[0] : None,
|
||||||
|
self.location_view.model().free[1] : 'carda',
|
||||||
|
self.location_view.model().free[2] : 'cardb' }
|
||||||
|
on_card = space.get(sorted(space.keys(), reverse=True)[0], None)
|
||||||
|
self.upload_books(files, names, metadata,
|
||||||
|
on_card=on_card,
|
||||||
|
memory=[[f.name for f in files], remove])
|
||||||
|
self.status_bar.showMessage(_('Sending catalogs to device.'), 5000)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def sync_news(self, send_ids=None, do_auto_convert=True):
|
def sync_news(self, send_ids=None, do_auto_convert=True):
|
||||||
if self.device_connected:
|
if self.device_connected:
|
||||||
|
54
src/calibre/gui2/dialogs/catalog.py
Normal file
54
src/calibre/gui2/dialogs/catalog.py
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
from __future__ import with_statement
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
from PyQt4.Qt import QDialog
|
||||||
|
|
||||||
|
from calibre.gui2.dialogs.catalog_ui import Ui_Dialog
|
||||||
|
from calibre.gui2 import dynamic
|
||||||
|
from calibre.customize.ui import available_catalog_formats
|
||||||
|
|
||||||
|
class Catalog(QDialog, Ui_Dialog):
|
||||||
|
|
||||||
|
def __init__(self, parent, dbspec, ids):
|
||||||
|
QDialog.__init__(self, parent)
|
||||||
|
self.setupUi(self)
|
||||||
|
self.dbspec, self.ids = dbspec, ids
|
||||||
|
|
||||||
|
self.count.setText(unicode(self.count.text()).format(len(ids)))
|
||||||
|
self.title.setText(dynamic.get('catalog_last_used_title',
|
||||||
|
_('My Books')))
|
||||||
|
fmts = sorted([x.upper() for x in available_catalog_formats()])
|
||||||
|
|
||||||
|
self.format.currentIndexChanged.connect(self.format_changed)
|
||||||
|
|
||||||
|
self.format.addItems(fmts)
|
||||||
|
|
||||||
|
pref = dynamic.get('catalog_preferred_format', 'EPUB')
|
||||||
|
idx = self.format.findText(pref)
|
||||||
|
if idx > -1:
|
||||||
|
self.format.setCurrentIndex(idx)
|
||||||
|
|
||||||
|
if self.sync.isEnabled():
|
||||||
|
self.sync.setChecked(dynamic.get('catalog_sync_to_device', True))
|
||||||
|
|
||||||
|
def format_changed(self, idx):
|
||||||
|
cf = unicode(self.format.currentText())
|
||||||
|
if cf in ('EPUB', 'MOBI'):
|
||||||
|
self.sync.setEnabled(True)
|
||||||
|
else:
|
||||||
|
self.sync.setDisabled(True)
|
||||||
|
self.sync.setChecked(False)
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
self.catalog_format = unicode(self.format.currentText())
|
||||||
|
dynamic.set('catalog_preferred_format', self.catalog_format)
|
||||||
|
self.catalog_title = unicode(self.title.text())
|
||||||
|
dynamic.set('catalog_last_used_title', self.catalog_title)
|
||||||
|
self.catalog_sync = bool(self.sync.isChecked())
|
||||||
|
dynamic.set('catalog_sync_to_device', self.catalog_sync)
|
||||||
|
QDialog.accept(self)
|
146
src/calibre/gui2/dialogs/catalog.ui
Normal file
146
src/calibre/gui2/dialogs/catalog.ui
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Dialog</class>
|
||||||
|
<widget class="QDialog" name="Dialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>628</width>
|
||||||
|
<height>503</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Generate catalog</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset resource="../../../work/calibre/resources/images.qrc">
|
||||||
|
<normaloff>:/images/library.png</normaloff>:/images/library.png</iconset>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QTabWidget" name="tabs">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Catalog options</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Catalog &format:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>format</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QComboBox" name="format"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Catalog &title (existing catalog with the same title will be replaced):</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>title</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>299</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QCheckBox" name="sync">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Send catalog to device automatically</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QLineEdit" name="title"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="count">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Generate catalog for {0} books</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../../../work/calibre/resources/images.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@ -232,6 +232,11 @@ class BooksModel(QAbstractTableModel):
|
|||||||
self.count_changed()
|
self.count_changed()
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def add_catalog(self, path, title):
|
||||||
|
ret = self.db.add_catalog(path, title)
|
||||||
|
self.count_changed()
|
||||||
|
return ret
|
||||||
|
|
||||||
def count_changed(self, *args):
|
def count_changed(self, *args):
|
||||||
self.emit(SIGNAL('count_changed(int)'), self.db.count())
|
self.emit(SIGNAL('count_changed(int)'), self.db.count())
|
||||||
|
|
||||||
|
@ -236,6 +236,24 @@ def fetch_scheduled_recipe(arg):
|
|||||||
|
|
||||||
return 'gui_convert', args, _('Fetch news from ')+arg['title'], fmt.upper(), [pt]
|
return 'gui_convert', args, _('Fetch news from ')+arg['title'], fmt.upper(), [pt]
|
||||||
|
|
||||||
|
def generate_catalog(parent, dbspec, ids):
|
||||||
|
from calibre.gui2.dialogs.catalog import Catalog
|
||||||
|
d = Catalog(parent, dbspec, ids)
|
||||||
|
if d.exec_() != d.Accepted:
|
||||||
|
return None
|
||||||
|
out = PersistentTemporaryFile(suffix='_catalog_out.'+d.catalog_format.lower())
|
||||||
|
args = [
|
||||||
|
d.catalog_format,
|
||||||
|
d.catalog_title,
|
||||||
|
dbspec,
|
||||||
|
ids,
|
||||||
|
out.name,
|
||||||
|
]
|
||||||
|
out.close()
|
||||||
|
|
||||||
|
return 'gui_catalog', args, _('Generate catalog'), out.name, d.catalog_sync, \
|
||||||
|
d.catalog_title
|
||||||
|
|
||||||
def convert_existing(parent, db, book_ids, output_format):
|
def convert_existing(parent, db, book_ids, output_format):
|
||||||
already_converted_ids = []
|
already_converted_ids = []
|
||||||
already_converted_titles = []
|
already_converted_titles = []
|
||||||
|
@ -48,7 +48,7 @@ from calibre.gui2.jobs import JobManager, JobsDialog
|
|||||||
from calibre.gui2.dialogs.metadata_single import MetadataSingleDialog
|
from calibre.gui2.dialogs.metadata_single import MetadataSingleDialog
|
||||||
from calibre.gui2.dialogs.metadata_bulk import MetadataBulkDialog
|
from calibre.gui2.dialogs.metadata_bulk import MetadataBulkDialog
|
||||||
from calibre.gui2.tools import convert_single_ebook, convert_bulk_ebook, \
|
from calibre.gui2.tools import convert_single_ebook, convert_bulk_ebook, \
|
||||||
fetch_scheduled_recipe
|
fetch_scheduled_recipe, generate_catalog
|
||||||
from calibre.gui2.dialogs.config import ConfigDialog
|
from calibre.gui2.dialogs.config import ConfigDialog
|
||||||
from calibre.gui2.dialogs.search import SearchDialog
|
from calibre.gui2.dialogs.search import SearchDialog
|
||||||
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
|
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
|
||||||
@ -355,6 +355,10 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
cm = QMenu()
|
cm = QMenu()
|
||||||
cm.addAction(_('Convert individually'))
|
cm.addAction(_('Convert individually'))
|
||||||
cm.addAction(_('Bulk convert'))
|
cm.addAction(_('Bulk convert'))
|
||||||
|
cm.addSeparator()
|
||||||
|
ac = cm.addAction(
|
||||||
|
_('Create catalog of the books in your calibre library'))
|
||||||
|
ac.triggered.connect(self.generate_catalog)
|
||||||
self.action_convert.setMenu(cm)
|
self.action_convert.setMenu(cm)
|
||||||
self._convert_single_hook = partial(self.convert_ebook, bulk=False)
|
self._convert_single_hook = partial(self.convert_ebook, bulk=False)
|
||||||
QObject.connect(cm.actions()[0],
|
QObject.connect(cm.actions()[0],
|
||||||
@ -894,6 +898,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
view.resizeRowsToContents()
|
view.resizeRowsToContents()
|
||||||
view.resize_on_select = not view.isVisible()
|
view.resize_on_select = not view.isVisible()
|
||||||
self.sync_news()
|
self.sync_news()
|
||||||
|
self.sync_catalogs()
|
||||||
############################################################################
|
############################################################################
|
||||||
|
|
||||||
|
|
||||||
@ -1339,6 +1344,43 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
|
|
||||||
############################################################################
|
############################################################################
|
||||||
|
|
||||||
|
############################### Generate catalog ###########################
|
||||||
|
|
||||||
|
def generate_catalog(self):
|
||||||
|
rows = self.library_view.selectionModel().selectedRows()
|
||||||
|
if not rows:
|
||||||
|
rows = xrange(self.library_view.model().rowCount(QModelIndex()))
|
||||||
|
ids = map(self.library_view.model().id, rows)
|
||||||
|
dbspec = None
|
||||||
|
if not ids:
|
||||||
|
return error_dialog(self, _('No books selected'),
|
||||||
|
_('No books selected to generate catalog for'),
|
||||||
|
show=True)
|
||||||
|
ret = generate_catalog(self, dbspec, ids)
|
||||||
|
if ret is None:
|
||||||
|
return
|
||||||
|
func, args, desc, out, sync, title = ret
|
||||||
|
fmt = os.path.splitext(out)[1][1:].upper()
|
||||||
|
job = self.job_manager.run_job(
|
||||||
|
Dispatcher(self.catalog_generated), func, args=args,
|
||||||
|
description=desc)
|
||||||
|
job.catalog_file_path = out
|
||||||
|
job.catalog_sync, job.catalog_title = sync, title
|
||||||
|
self.status_bar.showMessage(_('Generating %s catalog...')%fmt)
|
||||||
|
|
||||||
|
def catalog_generated(self, job):
|
||||||
|
if job.failed:
|
||||||
|
return self.job_exception(job)
|
||||||
|
id = self.library_view.model().add_catalog(job.catalog_file_path, job.catalog_title)
|
||||||
|
self.library_view.model().reset()
|
||||||
|
if job.catalog_sync:
|
||||||
|
sync = dynamic.get('catalogs_to_be_synced', set([]))
|
||||||
|
sync.add(id)
|
||||||
|
dynamic.set('catalogs_to_be_synced', sync)
|
||||||
|
self.status_bar.showMessage(_('Catalog generated.'), 3000)
|
||||||
|
self.sync_catalogs()
|
||||||
|
|
||||||
|
|
||||||
############################### Fetch news #################################
|
############################### Fetch news #################################
|
||||||
|
|
||||||
def download_scheduled_recipe(self, arg):
|
def download_scheduled_recipe(self, arg):
|
||||||
@ -1398,6 +1440,17 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
self.queue_convert_jobs(jobs, changed, bad, rows, previous,
|
self.queue_convert_jobs(jobs, changed, bad, rows, previous,
|
||||||
self.book_auto_converted_news)
|
self.book_auto_converted_news)
|
||||||
|
|
||||||
|
def auto_convert_catalogs(self, book_ids, format):
|
||||||
|
previous = self.library_view.currentIndex()
|
||||||
|
rows = [x.row() for x in \
|
||||||
|
self.library_view.selectionModel().selectedRows()]
|
||||||
|
jobs, changed, bad = convert_single_ebook(self, self.library_view.model().db, book_ids, True, format)
|
||||||
|
if jobs == []: return
|
||||||
|
self.queue_convert_jobs(jobs, changed, bad, rows, previous,
|
||||||
|
self.book_auto_converted_catalogs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_books_for_conversion(self):
|
def get_books_for_conversion(self):
|
||||||
rows = [r.row() for r in \
|
rows = [r.row() for r in \
|
||||||
self.library_view.selectionModel().selectedRows()]
|
self.library_view.selectionModel().selectedRows()]
|
||||||
@ -1463,6 +1516,11 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
self.book_converted(job)
|
self.book_converted(job)
|
||||||
self.sync_news(send_ids=[book_id], do_auto_convert=False)
|
self.sync_news(send_ids=[book_id], do_auto_convert=False)
|
||||||
|
|
||||||
|
def book_auto_converted_catalogs(self, job):
|
||||||
|
temp_files, fmt, book_id = self.conversion_jobs[job]
|
||||||
|
self.book_converted(job)
|
||||||
|
self.sync_catalogs(send_ids=[book_id], do_auto_convert=False)
|
||||||
|
|
||||||
def book_converted(self, job):
|
def book_converted(self, job):
|
||||||
temp_files, fmt, book_id = self.conversion_jobs.pop(job)[:3]
|
temp_files, fmt, book_id = self.conversion_jobs.pop(job)[:3]
|
||||||
try:
|
try:
|
||||||
|
@ -1407,6 +1407,36 @@ class LibraryDatabase2(LibraryDatabase):
|
|||||||
if notify:
|
if notify:
|
||||||
self.notify('metadata', [id])
|
self.notify('metadata', [id])
|
||||||
|
|
||||||
|
def add_catalog(self, path, title):
|
||||||
|
format = os.path.splitext(path)[1][1:].lower()
|
||||||
|
stream = path if hasattr(path, 'read') else open(path, 'rb')
|
||||||
|
stream.seek(0)
|
||||||
|
matches = self.data.get_matches('title', title)
|
||||||
|
if matches:
|
||||||
|
tag_matches = self.data.get_matches('tags', _('Catalog'))
|
||||||
|
matches = matches.intersection(tag_matches)
|
||||||
|
db_id = None
|
||||||
|
if matches:
|
||||||
|
db_id = list(matches)[0]
|
||||||
|
if db_id is None:
|
||||||
|
obj = self.conn.execute('INSERT INTO books(title, author_sort) VALUES (?, ?)',
|
||||||
|
(title, 'calibre'))
|
||||||
|
db_id = obj.lastrowid
|
||||||
|
self.data.books_added([db_id], self)
|
||||||
|
self.set_path(db_id, index_is_id=True)
|
||||||
|
self.conn.commit()
|
||||||
|
mi = MetaInformation(title, ['calibre'])
|
||||||
|
mi.tags = [_('Catalog')]
|
||||||
|
self.set_metadata(db_id, mi)
|
||||||
|
|
||||||
|
self.add_format(db_id, format, stream, index_is_id=True)
|
||||||
|
if not hasattr(path, 'read'):
|
||||||
|
stream.close()
|
||||||
|
self.conn.commit()
|
||||||
|
self.data.refresh_ids(self, [db_id]) # Needed to update format list and size
|
||||||
|
return db_id
|
||||||
|
|
||||||
|
|
||||||
def add_news(self, path, arg):
|
def add_news(self, path, arg):
|
||||||
format = os.path.splitext(path)[1][1:].lower()
|
format = os.path.splitext(path)[1][1:].lower()
|
||||||
stream = path if hasattr(path, 'read') else open(path, 'rb')
|
stream = path if hasattr(path, 'read') else open(path, 'rb')
|
||||||
|
@ -27,6 +27,9 @@ PARALLEL_FUNCS = {
|
|||||||
'gui_convert' :
|
'gui_convert' :
|
||||||
('calibre.gui2.convert.gui_conversion', 'gui_convert', 'notification'),
|
('calibre.gui2.convert.gui_conversion', 'gui_convert', 'notification'),
|
||||||
|
|
||||||
|
'gui_catalog' :
|
||||||
|
('calibre.gui2.convert.gui_conversion', 'gui_catalog', 'notification'),
|
||||||
|
|
||||||
'move_library' :
|
'move_library' :
|
||||||
('calibre.library.move', 'move_library', 'notification'),
|
('calibre.library.move', 'move_library', 'notification'),
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user