mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-10-31 02:27:01 -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