def cli_main(self,argv): with self: # so the sys.path was modified appropriately # I believe there's no performance hit loading these here when # CLI--it would load everytime anyway. from StringIO import StringIO from calibre.library import db from calibre_plugins.fanficfare_plugin.fanficfare.cli import main as fff_main from calibre_plugins.fanficfare_plugin.prefs import PrefsFacade from calibre.utils.config import prefs as calibre_prefs from optparse import OptionParser parser = OptionParser('%prog --run-plugin '+self.name+' -- [options] <storyurl>') parser.add_option('--library-path', '--with-library', default=None, help=_('Path to the calibre library. Default is to use the path stored in the settings.')) # parser.add_option('--dont-notify-gui', default=False, action='store_true', # help=_('Do not notify the running calibre GUI (if any) that the database has' # ' changed. Use with care, as it can lead to database corruption!')) pargs = [x for x in argv if x.startswith('--with-library') or x.startswith('--library-path') or not x.startswith('-')] opts, args = parser.parse_args(pargs) fff_prefs = PrefsFacade(db(path=opts.library_path, read_only=True)) fff_main(argv[1:], parser=parser, passed_defaultsini=StringIO(get_resources("fanficfare/defaults.ini")), passed_personalini=StringIO(fff_prefs["personal.ini"]))
def cli_main(self,argv): with self: # so the sys.path was modified appropriately # I believe there's no performance hit loading these here when # CLI--it would load everytime anyway. from StringIO import StringIO from calibre.library import db from calibre_plugins.fanficfare_plugin.fanficfare.cli import main as fff_main from calibre_plugins.fanficfare_plugin.prefs import PrefsFacade from calibre.utils.config import prefs as calibre_prefs from optparse import OptionParser parser = OptionParser('%prog --run-plugin '+self.name+' -- [options] <storyurl>') parser.add_option('--library-path', '--with-library', default=None, help=_('Path to the calibre library. Default is to use the path stored in the settings.')) # parser.add_option('--dont-notify-gui', default=False, action='store_true', # help=_('Do not notify the running calibre GUI (if any) that the database has' # ' changed. Use with care, as it can lead to database corruption!')) pargs = [x for x in argv if x.startswith('--with-library') or x.startswith('--library-path') or not x.startswith('-')] opts, args = parser.parse_args(pargs) fff_prefs = PrefsFacade(db(path=opts.library_path, read_only=True)) fff_main(argv[1:], parser=parser, passed_defaultsini=StringIO(get_resources("fanficfare/defaults.ini")), passed_personalini=StringIO(fff_prefs["personal.ini"]), )
def test_tag_browser(library_path=None): ' Compare output of server and GUI tag browsers ' from calibre.library import db olddb = db(library_path) db = olddb.new_api opts = categories_settings({}, db) # opts = opts._replace(hidden_categories={'publisher'}) opts = opts._replace(hide_empty_categories=True) category_data = db.get_categories(sort=opts.sort_by, first_letter_sort=opts.collapse_model == 'first letter') data = render_categories(opts, db, category_data) srv_data = dump_categories_tree(data) from calibre.gui2 import Application, gprefs from calibre.gui2.tag_browser.model import TagsModel prefs = { 'tags_browser_category_icons':gprefs['tags_browser_category_icons'], 'tags_browser_collapse_at':opts.collapse_at, 'tags_browser_partition_method': opts.collapse_model, 'tag_browser_dont_collapse': opts.dont_collapse, 'tag_browser_hide_empty_categories': opts.hide_empty_categories, } app = Application([]) m = TagsModel(None, prefs) m.set_database(olddb, opts.hidden_categories) m_data = dump_tags_model(m) if m_data == srv_data: print('No differences found in the two Tag Browser implementations') raise SystemExit(0) from calibre.gui2.tweak_book.diff.main import Diff d = Diff(show_as_window=True) d.string_diff(m_data, srv_data, left_name='GUI', right_name='server') d.exec_() del app
def run_variation_algorithm(match_type, item_type): from calibre.library import db alg = VariationAlgorithm(db()) dm, cm, im = alg.run_variation_check(match_type, item_type) print('---') print('%s %s Duplicate Results:'%(match_type, item_type)) for k, matches in im.iteritems(): texts = ['%s (%d)'%(dm[i],cm[i]) for i in matches] print(' %s (%d) => {%s}'%(dm[k], cm[k], ', '.join(texts)))
def create_wsgi_app(path_to_library=None, prefix=''): 'WSGI entry point' from calibre.library import db cherrypy.config.update({'environment': 'embedded'}) db = db(path_to_library) parser = option_parser() opts, args = parser.parse_args(['calibre-server']) opts.url_prefix = prefix server = LibraryServer(db, opts, wsgi=True, show_tracebacks=True) return cherrypy.Application(server, script_name=None, config=server.config)
def do_obtain_new_books(cpus, account, notification=lambda x, y:x): print "do_obtain_new_books in jobs.py" print "Account is: %s" % (account) # This server is an arbitrary_n job, so there is a notifier available. # Set the % complete to a small number to avoid the 'unavailable' indicator notification(0.01, "Starting up...") from calibre.library import db from calibre.utils.config import prefs prefs.refresh() db = db(read_only=False) print "DB is: %s" % (db) prefs = PrefsFacade(db) print "Prefs are: %s" % (prefs) print "Library id is (%s)" % (prefs.get_library_uuid()) reporter = ConsoleReporter() downloader = BeamEbooksDownloader(prefs, caller = reporter) print "-- LALA -- Downloader is: %s" % (downloader) if account[prefs.ENABLED]: downloader.login(account) if downloader.successful_login == False: notification(1.00, "Failed to log in...") else: notification(0.05, "Parsing document tree now...") downloadable_ebooks = downloader.recursive_descent(norms(prefs[prefs.URLBASE])) notification(0.50, "Loaded OPDS pages") reporter.notify(downloadable_ebooks) # # Now, download the obtained ebooks... notification(1.00, "Done...") adder = EBookAdder(prefs, "beam-ebooks") adder.load_books() new_ebooks = [] for entry in downloadable_ebooks: beamebooks_id = entry['id'] book = adder.books_of_this_shop.get(beamebooks_id) if book is None: new_ebooks.append(entry) result = (new_ebooks) return result
def cli_convert(self, args): #NODOC printsd(args) if args.all: # `calibre-debug -r djvumaker -- convert --all` printsd('in cli convert_all') # TODO: make work `djvumaker -- convert --all` # raise NotImplementedError('Convert all is not implemented.') user_input = ask_yesno_input( 'Do you wany to copy-convert all PDFs to DJVU?') if not user_input: return None from calibre.library import db from calibre.customize.ui import run_plugins_on_postimport db = db() # initialize calibre library database for book_id in list(db.all_ids()): if db.has_format(book_id, 'DJVU', index_is_id=True): continue # TODO: shouldn't work with this code, db has not atributte run_plugins_on_postimport # https://github.com/kovidgoyal/calibre/blob/master/src/calibre/customize/ui.py if db.has_format(book_id, 'PDF', index_is_id=True): run_plugins_on_postimport(db, book_id, 'pdf') continue elif args.path is not None: # `calibre-debug -r djvumaker -- convert -p test.pdf` -> tempfile(test.djvu) printsd('in path') if is_rasterbook(args.path): djvu = self.run_backend(args.path, log=self.prints.func) if djvu: input_filename, _ = os.path.splitext(args.path) shutil.copy2(djvu, input_filename + '.djvu') prints("Finished DJVU outputed to: {}.".format( input_filename + '.djvu')) user_input = ask_yesno_input( 'Do you want to open djvused in subshell?' ' (may not work on not macOS)') if not user_input: return None # de-munge the tty sys.stdin = sys.__stdin__ sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ os.system("stat '%s'" % djvu) # TODO: doesn't work on Windows, why is it here? os.system("djvused -e dump '%s'" % djvu) os.system("djvused -v '%s'" % djvu) elif args.id is not None: # `calibre-debug -r djvumaker -- convert -i 123 #id(123).pdf` -> tempfile(id(123).djvu) printsd('in convert by id') self._postimport(args.id)
def init_gui(): from calibre.gui2.ui import Main from calibre.gui2.main import option_parser from calibre.library import db parser = option_parser() opts, args = parser.parse_args([]) actions = tuple(Main.create_application_menubar()) db = db() gui = Main(opts) gui.initialize(db.library_path, db, None, actions, show_gui=False) return gui
def init_gui(): from calibre.gui2.ui import Main from calibre.gui2.main import option_parser from calibre.library import db parser = option_parser() opts, args = parser.parse_args([]) actions = tuple(Main.create_application_menubar()) db = db() gui = Main(opts) gui.initialize(db.library_path, db, actions, show_gui=False) return gui
def get_current_db(): ''' This method will try to return the current database in use by the user as efficiently as possible, i.e. without constructing duplicate LibraryDatabase objects. ''' from calibre.gui2.ui import get_gui gui = get_gui() if gui is not None and gui.current_db is not None: return gui.current_db from calibre.library import db return db()
def setUpClass(cls): lib_db = db('~/Calibre Library').new_api book_1984_id = 0 for book_id in lib_db.all_book_ids(): mi = lib_db.get_metadata(book_id) if mi.get('title') == '1984': book_1984_id = book_id break data = check_metadata(lib_db, book_1984_id) (_, cls.fmt, cls.asin, cls.book_path, _, _) = data create_x = False if platform.system() == 'Darwin' else True do_job(data, create_x=create_x)
def cli_convert(self, args): #NODOC printsd(args) if args.all: # `calibre-debug -r djvumaker -- convert --all` printsd('in cli convert_all') # TODO: make work `djvumaker -- convert --all` # raise NotImplementedError('Convert all is not implemented.') user_input = ask_yesno_input('Do you wany to copy-convert all PDFs to DJVU?') if not user_input: return None from calibre.library import db from calibre.customize.ui import run_plugins_on_postimport db = db() # initialize calibre library database for book_id in list(db.all_ids()): if db.has_format(book_id, 'DJVU', index_is_id=True): continue # TODO: shouldn't work with this code, db has not atributte run_plugins_on_postimport # https://github.com/kovidgoyal/calibre/blob/master/src/calibre/customize/ui.py if db.has_format(book_id, 'PDF', index_is_id=True): run_plugins_on_postimport(db, book_id, 'pdf') continue elif args.path is not None: # `calibre-debug -r djvumaker -- convert -p test.pdf` -> tempfile(test.djvu) printsd('in path') if is_rasterbook(args.path): djvu = self.run_backend(args.path, log=self.prints.func) if djvu: input_filename, _ = os.path.splitext(args.path) shutil.copy2(djvu, input_filename + '.djvu') prints("Finished DJVU outputed to: {}.".format(input_filename + '.djvu')) user_input = ask_yesno_input('Do you want to open djvused in subshell?' ' (may not work on not macOS)') if not user_input: return None # de-munge the tty sys.stdin = sys.__stdin__ sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ os.system("stat '%s'" % djvu) # TODO: doesn't work on Windows, why is it here? os.system("djvused -e dump '%s'" % djvu) os.system("djvused -v '%s'" % djvu) elif args.id is not None: # `calibre-debug -r djvumaker -- convert -i 123 #id(123).pdf` -> tempfile(id(123).djvu) printsd('in convert by id') self._postimport(args.id, fork_job=False)
def setUpClass(cls): lib_db = db('~/Calibre Library').new_api book_1984_id = 0 for book_id in lib_db.all_book_ids(): mi = lib_db.get_metadata(book_id) if mi.get('title') == '1984': book_1984_id = book_id break data = check_metadata(lib_db, book_1984_id) (_, cls.fmt, cls.asin, cls.book_path, _) = data install_libs() start_time = time.time() do_job(data, load_json('data/lemmas.json')) print(f'{time.time() - start_time} seconds')
def gui_catalog(fmt, title, dbspec, ids, out_file_name, sync, fmt_options, connected_device, notification=DummyReporter(), log=None): if log is None: log = Log() from calibre.library import db from calibre.utils.config import prefs prefs.refresh() db = db(read_only=True) db.catalog_plugin_on_device_temp_mapping = dbspec # Create a minimal OptionParser that we can append to parser = OptionParser() args = [] parser.add_option("--verbose", action="store_true", dest="verbose", default=True) opts, args = parser.parse_args() # Populate opts # opts.gui_search_text = something opts.catalog_title = title opts.connected_device = connected_device opts.ids = ids opts.search_text = None opts.sort_by = None opts.sync = sync # Extract the option dictionary to comma-separated lists for option in fmt_options: if isinstance(fmt_options[option], list): setattr(opts, option, ','.join(fmt_options[option])) else: setattr(opts, option, fmt_options[option]) # Fetch and run the plugin for fmt # Returns 0 if successful, 1 if no catalog built plugin = plugin_for_catalog_format(fmt) return plugin.run(out_file_name, opts, db, notification=notification)
def config_widget(self): ''' Implement this method and :meth:`save_settings` in your plugin to use a custom configuration dialog. This method, if implemented, must return a QWidget. The widget can have an optional method validate() that takes no arguments and is called immediately after the user clicks OK. Changes are applied if and only if the method returns True. ''' if self.actual_plugin_: from calibre_plugins.beam_ebooks_downloader.config import ConfigWidget from calibre_plugins.beam_ebooks_downloader.prefs import PrefsFacade my_db = db(path=None, read_only=True) prefs = PrefsFacade(my_db) return ConfigWidget(self.actual_plugin_, prefs)
def run(self, path_to_ebook): from calibre.ebooks.metadata.meta import get_metadata from calibre.library import db import time file = open(path_to_ebook, 'r+b') ext = os.path.splitext(path_to_ebook)[-1][1:].lower() mi = get_metadata(file, ext) db = db('C:/Users/jmoor/Docs/eBooks/Calibre').new_api title = mi.title author = mi.authors[0] ids = list(db.search('title:' + title + ' author:' + author)) db.remove_formats({ids[0]: ['ORIGINAL_MOBI', 'epub', 'azw3']}) searchResults = db.search('formats:"=ORIGINAL_MOBI"') for bookId in searchResults: try: db.remove_formats({bookId: ['original_mobi']}) except: pass
def cli_main(self, argv): from calibre.utils.config import prefs as calibre_prefs from optparse import OptionParser from calibre_plugins.beam_ebooks_downloader.prefs import PrefsFacade my_db = db(path=None, read_only=False) # print 'Database is (%s)' % (prefs._get_db()) print 'Database is (%s)' % (my_db) prefs = PrefsFacade(my_db) print 'My Prefs are (%s)' % (prefs) print ' methods are (%s)' % (dir(prefs)) print ' library id is (%s)' % (prefs.get_library_uuid()) print 'Calibre Prefs are (%s)' % (calibre_prefs) print ' methods are (%s)' % (dir(calibre_prefs)) downloader = BeamEbooksDownloader(prefs, self.version, caller=self) # Loop over all accounts until we have support for selection for account_id in prefs[prefs.ACCOUNTS]: account = prefs[prefs.ACCOUNTS][account_id] account[prefs.ACCOUNT_ID] = account_id print "Account: '%s'" % account if account[prefs.ENABLED]: downloader.login(account) if downloader.successful_login == False: print "Failed to log in..." else: print "Parsing document tree now..." # Temporarily... # downloader.recursive_descent(prefs[prefs.URLBASE] + "/aldiko/bibuebersicht.php5?user="******"/aldiko/pakete.php5?user="******"/kunden/abos.php5") downloader.download_ebooks() pass
def remove_books_from_metadata(self, paths, booklists): # log.debug("{}".format((paths, booklists))) # if self.can_set_as_read: # calibre_db = db(prefs['library_path']).new_api changed = set() for i, path in enumerate(paths): self.report_progress((i+1) / float(len(paths)), _('Updating fields for deleted books...')) for bl in booklists: for book in bl: # log.debug("Compare {} and {}".format(path, book.path)) if path.endswith(book.path): log.debug("We'll try to update {}".format(book)) log.debug("Here are the original values for {}: {}".format(book.application_id, db().new_api.get_metadata(book.application_id))) try: log.debug("Unset, field {}: {}".format(self.set_as_read_fields[0], (book.application_id, str(book)))) changed |= db().new_api.set_field(self.set_as_read_fields[0], {book.application_id: None}) except Exception, e: log.error(e) log.debug("Here are the values for {} after settings: {}".format(book.application_id, db().new_api.get_metadata(book.application_id)))
def gui_catalog(fmt, title, dbspec, ids, out_file_name, sync, fmt_options, connected_device, notification=DummyReporter(), log=None): if log is None: log = Log() from calibre.library import db from calibre.utils.config import prefs prefs.refresh() db = db(read_only=True) db.catalog_plugin_on_device_temp_mapping = dbspec # Create a minimal OptionParser that we can append to parser = OptionParser() args = [] parser.add_option("--verbose", action="store_true", dest="verbose", default=True) opts, args = parser.parse_args() # Populate opts # opts.gui_search_text = something opts.catalog_title = title opts.connected_device = connected_device opts.ids = ids opts.search_text = None opts.sort_by = None opts.sync = sync # Extract the option dictionary to comma-separated lists for option in fmt_options: if isinstance(fmt_options[option],list): setattr(opts,option, ','.join(fmt_options[option])) else: setattr(opts,option, fmt_options[option]) # Fetch and run the plugin for fmt # Returns 0 if successful, 1 if no catalog built plugin = plugin_for_catalog_format(fmt) return plugin.run(out_file_name, opts, db, notification=notification)
self.current_row = row self.setWindowTitle(mi.title) self.cover_pixmap = QPixmap.fromImage(mi.cover_data[1]) try: dpr = self.devicePixelRatioF() except AttributeError: dpr = self.devicePixelRatio() self.cover_pixmap.setDevicePixelRatio(dpr) self.resize_cover() html = render_html(mi, True, self, pref_name='popup_book_display_fields') set_html(mi, html, self.details) self.marked = mi.marked self.cover.setBackgroundBrush( self.marked_brush if mi.marked else self.normal_brush) self.update_cover_tooltip() if __name__ == '__main__': from calibre.gui2 import Application from calibre.library import db app = Application([]) app.current_db = db() get_gui.ans = app d = Configure(app.current_db) d.exec_() del d del app
annot['notes'] = notes.strip() else: annot.pop('notes', None) db = current_db() db.update_annotations({annot_id: annot}) self.details_panel.update_notes(annot) def show_dialog(self): if self.parent() is None: self.browse_panel.effective_query_changed() self.exec_() else: self.reinitialize() self.show() self.raise_() QTimer.singleShot(80, self.browse_panel.effective_query_changed) def reinitialize(self): self.browse_panel.re_initialize() if __name__ == '__main__': from calibre.library import db app = Application([]) current_db.ans = db(os.path.expanduser('~/test library')) br = AnnotationsBrowser() br.reinitialize() br.show_dialog() del br del app
for book_id in matching_books: aut = [a.replace('|', ',') for a in (db.authors(book_id, index_is_id=True) or '').split(',')] add_child(ta%dict( title=db.title(book_id, index_is_id=True), author=authors_to_string(aut), formats=db.formats(book_id, index_is_id=True, verify_formats=False))) add_child('') yield item @property def duplicates(self): for i in xrange(self.dup_list.topLevelItemCount()): x = self.dup_list.topLevelItem(i) if x.checkState(0) == Qt.Checked: yield x.data(0, Qt.UserRole).toPyObject() if __name__ == '__main__': from PyQt4.Qt import QApplication from calibre.ebooks.metadata.book.base import Metadata as M from calibre.library import db app = QApplication([]) db = db() d = DuplicatesQuestion(db, [(M('Life of Pi', ['Yann Martel']), None, None), (M('Heirs of the blade', ['Adrian Tchaikovsky']), None, None)]) print (tuple(d.duplicates))
def fix_extra_covers(self): tl = self.top_level_items['extra_covers'] child_count = tl.childCount() for i in range(0, child_count): item = tl.child(i) id = int(item.data(0, Qt.UserRole)) self.db.set_has_cover(id, True) def fix_items(self): for check in CHECKS: attr = check[0] fixable = check[3] tl = self.top_level_items[attr] if fixable and tl.checkState(1): func = getattr(self, 'fix_' + attr, None) if func is not None and callable(func): func() self.run_the_check() def copy_to_clipboard(self): QApplication.clipboard().setText(self.text_results) if __name__ == '__main__': app = QApplication([]) from calibre.library import db d = CheckLibraryDialog(None, db()) d.exec_()
def iteritems(self): cl = self.column_list return (cl.item(i) for i in range(cl.count())) def apply_spec(self, spec): self.clear() cl = self.column_list imap = { item.data(Qt.ItemDataRole.UserRole): item for item in self.iteritems() } for key, ascending in reversed(spec): item = imap.get(key) if item is not None: item = cl.takeItem(cl.row(item)) cl.insertItem(0, item) self.sort_order_map[key] = ascending item.setCheckState(Qt.CheckState.Checked) if __name__ == '__main__': from calibre.gui2 import Application app = Application([]) from calibre.library import db d = ChooseMultiSort(db()) d.exec_() print(d.current_sort_spec) del d del app
def _postimport(self, book_id, book_format=None, db=None, log=None, fork_job=True, abort=None, notifications=None): #NODOC IMPORTANT # TODO: make general overhaul of starting conversion logic if log: # divert our printing to the caller's logger prints = log # Log object has __call__ dunder method with INFO level prints = partial(prints, '{}:'.format(PLUGINNAME)) else: log = self.prints.func try: prints except NameError: prints = self.prints if sys.__stdin__.isatty(): # if run by cli, i.e.: # calibredb add # calibredebug -r djvumaker -- convert -i #id # runs also for GUI if run trough `calibredebug -g` fork_job = False # DEBUG UNCOMMENT rpc_refresh = True # use the calibre RPC to signal a GUI refresh if db is None: from calibre.library import db # TODO: probably legacy db import, change for new_api db = db() # initialize calibre library database if book_format == None: if not db.has_format(book_id, 'PDF', index_is_id=True): raise Exception( 'Book with id #{} has not a PDF format.'.format(book_id)) else: book_format = 'pdf' if db.has_format(book_id, 'DJVU', index_is_id=True): prints( "already have 'DJVU' format document for book ID #{}".format( book_id)) return None # don't auto convert, we already have a DJVU for this document path_to_ebook = db.format_abspath(book_id, book_format, index_is_id=True) if book_format == 'pdf': is_rasterbook_val, pages, images = is_rasterbook( path_to_ebook, basic_return=False) if is_rasterbook_val: pass # TODO: should add a 'scanned' or 'djvumaker' tag else: # this is a marked-up/vector-based pdf, # no advantages to having another copy in DJVU format prints(( "{} document from book ID #{} determined to be a markup-based ebook," " not converting to DJVU").format(book_format, book_id)) return None #no-error in job panel # TODO: test the DPI to determine if a document is from a broad-sheeted book. # if so, queue up k2pdfopt to try and chunk the content appropriately to letter size prints(( "scheduling new {} document from book ID #{} for post-import DJVU" " conversion: {}").format(book_format, book_id, path_to_ebook)) if fork_job: #useful for not blocking calibre GUI when large PDFs # are dropped into the automatic-import-folder try: # https://github.com/kovidgoyal/calibre/blob/master/src/calibre/utils/ipc/simple_worker.py # dispatch API for Worker() # src/calibre/utils/ipc/launch.py # Worker() uses sbp.Popen to # run a second Python to a logfile # note that Calibre bungs the python loader to check the plugin directory when # modules with calibre_plugin. prefixed are passed # https://github.com/kovidgoyal/calibre/blob/master/src/calibre/customize/zipplugin.py#L192 func_name = self.plugin_prefs['use_backend'] args = [ path_to_ebook, log, abort, notifications, pages, images ] jobret = worker_fork_job( 'calibre_plugins.{}'.format(PLUGINNAME), func_name, args=args, kwargs={'preferences': self.plugin_prefs}, env={'PATH': os.environ['PATH'] + ':/usr/local/bin'}, # djvu and poppler-utils on osx timeout=600) # TODO: determine a resonable timeout= based on filesize or # make a heartbeat= check # TODO: doesn't work for pdf2djvu, why? except WorkerError as e: prints('djvudigital background conversion failed: \n{}'.format( force_unicode(e.orig_tb))) raise # ConversionError except: prints(traceback.format_exc()) raise # dump djvudigital output logged in file by the Worker to # calibre proc's (gui or console) log/stdout with open(jobret['stdout_stderr'], 'rb') as f: raw = f.read().strip() prints(raw) if jobret['result']: djvu = jobret['result'] else: WorkerError("djvu conversion error: %s" % jobret['result']) # elif hasattr(self, gui): #if we have the calibre gui running, # we can give it a threadedjob and not use fork_job else: #!fork_job & !gui prints("Starts backend") djvu = self.run_backend(path_to_ebook, log, abort, notifications, pages, images) if djvu: db.new_api.add_format(book_id, 'DJVU', djvu, run_hooks=True) prints("added new 'DJVU' document to book ID #{}".format(book_id)) if sys.__stdin__.isatty(): # update calibre gui Out-Of-Band. Like if we were run as a command-line scripted import # this resets current gui views/selections, no cleaner way to do it :-( from calibre.utils.ipc import RC t = RC(print_error=False) t.start() t.join(3) if t.done: # GUI is running t.conn.send('refreshdb:') t.conn.close() prints("signalled Calibre GUI refresh") else: # TODO: normal Exception propagation instead of passing errors as return values raise Exception('ConversionError, djvu: {}'.format(djvu))
def clean_story_link(link): # works for FFNet and AO3 strings = link.split("/") for i, s in enumerate(strings): if s.isnumeric(): return "/".join(strings[:i + 1]) log.warn( f"{link} is not a parsable or valid story link, this may cause issues." ) return link # perform work in temporary directory tempdir = tempfile.gettempdir() log.debug(f"Using temporary directory: {tempdir}") db = db(calibre_path).new_api # import retry links story_urls = [] if os.path.isfile(RETRY_FILE): log.info("Searching for previously failed updates...") with open(RETRY_FILE) as file: story_urls += file.read().splitlines() os.remove(RETRY_FILE) log.info("Searching email for updated stories...") try: story_urls += list( map( clean_story_link, geturls.get_urls_from_imap(imap_server, imap_email, imap_password,
changed = set() for i, path in enumerate(paths): self.report_progress((i+1) / float(len(paths)), _('Updating fields for deleted books...')) for bl in booklists: for book in bl: # log.debug("Compare {} and {}".format(path, book.path)) if path.endswith(book.path): log.debug("We'll try to update {}".format(book)) log.debug("Here are the original values for {}: {}".format(book.application_id, db().new_api.get_metadata(book.application_id))) try: log.debug("Unset, field {}: {}".format(self.set_as_read_fields[0], (book.application_id, str(book)))) changed |= db().new_api.set_field(self.set_as_read_fields[0], {book.application_id: None}) except Exception, e: log.error(e) log.debug("Here are the values for {} after settings: {}".format(book.application_id, db().new_api.get_metadata(book.application_id))) log.debug(changed) log.debug('Finished updating fields for %d books'%(len(paths))) db().new_api.commit_dirty_cache() from calibre.gui2.ui import get_gui if get_gui(): log.debug("Got GUI! Refreshing view for {} ({})".format(changed, db().new_api.all_field_for(self.set_as_read_fields[0], changed))) get_gui().library_view.model().db.refresh() get_gui().library_view.model().refresh_ids(changed) super(MUSE, self).remove_books_from_metadata(paths, booklists)
fmts = set() for path in files: fmt = path.rpartition('.')[-1].upper() if tweaks['save_original_format_when_polishing'] and not is_orig[fmt]: fmts.add(fmt) db.save_original_format(book_id, fmt, notify=False) with open(path, 'rb') as f: db.add_format(book_id, fmt, f, index_is_id=True) self.gui.status_bar.show_message(job.description + _(' completed'), 2000) try: shutil.rmtree(base) parent = os.path.dirname(base) os.rmdir(parent) except: pass self.gui.tags_view.recount() if self.gui.current_view() is self.gui.library_view: current = self.gui.library_view.currentIndex() if current.isValid(): self.gui.library_view.model().current_changed(current, QModelIndex()) if show_reports: self.report(db.title(book_id, index_is_id=True), book_id, fmts, job, job.result) if __name__ == '__main__': app = QApplication([]) app from calibre.library import db d = Polish(db(), {1:{'EPUB'}, 2:{'AZW3'}}) d.exec_()
QWizard.__init__(self, parent) self.setModal(True) self.setWindowTitle(_('Add books to calibre')) self.setWindowIcon(QIcon(I('add_book.png'))) self.setPixmap( self.LogoPixmap, QPixmap(P('content_server/calibre.png')).scaledToHeight( 80, Qt.SmoothTransformation)) self.setPixmap(self.WatermarkPixmap, QPixmap(I('welcome_wizard.png'))) self.register = {} for attr, cls in [ ('welcome_page', WelcomePage), ('scan_page', ScanPage), ]: setattr(self, attr, cls(db, self)) self.setPage(getattr(cls, 'ID'), getattr(self, attr)) # }}} # Test Wizard {{{ if __name__ == '__main__': from PyQt4.Qt import QApplication from calibre.library import db app = QApplication([]) w = Wizard(db()) w.exec_() # }}}
def __init__(self): from calibre.library import current_library_name QWidget.__init__(self) actual_plugin = 'calibre_plugins.getfilename.action:GetFileNameAction' self.plugin_action = actual_plugin # get the prefs self.prefs = prefs_a.GetFileName_Prefs(current_library_name()) if (self.prefs['configured'] == False): try: from calibre.gui2.ui import get_gui db = get_gui().current_db self.prefs = get_library_config(db) except: try: from calibre.library import db self.prefs = get_library_config(db()) except: self.prefs = prefs_a.GetFileName_Prefs( current_library_name()) for key, col in six.iteritems(DEFAULT_MIGRATION): self.prefs.set(col, DEFAULT_LIBRARY_VALUES[key]) self.prefs.set('OPC_PREF', 'name') self.prefs.set('configured', True) self.prefs.set(KEY_SCHEMA_VERSION, DEFAULT_SCHEMA_VERSION) self.prefs.writeprefs() self.filename_col = self.prefs[NAME_PREF] self.extension_col = self.prefs[EXT_PREF] self.path_col = self.prefs[PATH_PREF] self.date_col = self.prefs[DATE_PREF] self.option_name = self.prefs[OPC_PREF] # Start Qt Gui dialog layout layout = QVBoxLayout(self) self.setLayout(layout) # -- Options -- # # --- File --- avail_columns_text = self.get_custom_columns_text() avail_columns_date = self.get_custom_columns_date() filename_group_box = QGroupBox(_('File name options:'), self) layout.addWidget(filename_group_box) filename_group_box_layout = QGridLayout() filename_group_box.setLayout(filename_group_box_layout) pos = 0 self.path_checkbox = QCheckBox(_("Include folder"), self) self.path_checkbox.setTristate(False) self.path_checkbox.setToolTip( _("It indicates it stores the folder with the filename.")) self.path_checkbox.stateChanged.connect(self.path_checkbox_clicked) filename_group_box_layout.addWidget(self.path_checkbox, pos, 0, 1, 1) pos = pos + 1 fname_column_label = QLabel(_('&File name:'), self) fname_column_label.setToolTip( _('Custom text column for storing the filename and folder if included' )) fname_col = self.filename_col self.fname_column_combo = CustomColumnComboBox(self, avail_columns_text, fname_col) fname_column_label.setBuddy(self.fname_column_combo) filename_group_box_layout.addWidget(fname_column_label, pos, 0, 1, 1) filename_group_box_layout.addWidget(self.fname_column_combo, pos, 1, 1, 2) self.fname_column_combo.currentIndexChanged.connect( self.filename_changed) pos = pos + 1 fexten_column_label = QLabel(_('File &Extension:'), self) fexten_column_label.setToolTip( _('Custom text column for storing the extension (if empty the filename is not splited). Not used if file name column is empty' )) fexten_col = self.extension_col self.fexten_column_combo = CustomColumnComboBox( self, avail_columns_text, fexten_col) fexten_column_label.setBuddy(self.fexten_column_combo) filename_group_box_layout.addWidget(fexten_column_label, pos, 0, 1, 1) filename_group_box_layout.addWidget(self.fexten_column_combo, pos, 1, 1, 2) if (self.filename_col == ""): self.fexten_column_combo.setEnabled(False) else: self.fexten_column_combo.setEnabled(True) pos = pos + 1 fpath_column_label = QLabel(_('File &Folder:'), self) fpath_column_label.setToolTip( _('Custom text column for storing the folder (if empty the filename is not splited). Not used if file name column is empty' )) fpath_col = self.path_col self.fpath_column_combo = CustomColumnComboBox(self, avail_columns_text, fpath_col) fpath_column_label.setBuddy(self.fpath_column_combo) filename_group_box_layout.addWidget(fpath_column_label, pos, 0, 1, 1) filename_group_box_layout.addWidget(self.fpath_column_combo, pos, 1, 1, 2) date_column_group = QGroupBox(self) layout.addWidget(date_column_group) date_layout = QGridLayout() date_column_group.setLayout(date_layout) fdate_column_label = QLabel(_('File &Date:'), self) fdate_column_label.setToolTip( _('Custom date column for storing the last modified date (if empty the date is not stored)' )) fdate_col = self.date_col self.fdate_column_combo = CustomColumnComboBox(self, avail_columns_date, fdate_col) fdate_column_label.setBuddy(self.fdate_column_combo) date_layout.addWidget(fdate_column_label, 2, 0, 1, 1) date_layout.addWidget(self.fdate_column_combo, 2, 1, 1, 2) if (self.option_name == 'path'): self.path_checkbox.setChecked(True) if (self.fname_column_combo.currentIndex() == 0): self.fpath_column_combo.setEnabled(False) else: self.fpath_column_combo.setEnabled(True) else: self.path_checkbox.setChecked(False) self.fpath_column_combo.setEnabled(False) layout.addStretch(1)
def _postimport(self, book_id, book_format=None, db=None, log=None, fork_job=True, abort=None, notifications=None): #NODOC IMPORTANT # TODO: make general overhaul of starting conversion logic if log: # divert our printing to the caller's logger prints = log # Log object has __call__ dunder method with INFO level prints = partial(prints, '{}:'.format(PLUGINNAME)) else: log = self.prints.func try: prints except NameError: prints = self.prints if sys.__stdin__.isatty(): # if run by cli, i.e.: # calibredb add # calibredebug -r djvumaker -- convert -i #id # runs also for GUI if run trough `calibredebug -g` fork_job = False # DEBUG UNCOMMENT rpc_refresh = True # use the calibre RPC to signal a GUI refresh if db is None: from calibre.library import db # TODO: probably legacy db import, change for new_api db = db() # initialize calibre library database if book_format == None: if not db.has_format(book_id, 'PDF', index_is_id=True): raise Exception('Book with id #{} has not a PDF format.'.format(book_id)) else: book_format='pdf' if db.has_format(book_id, 'DJVU', index_is_id=True): prints("already have 'DJVU' format document for book ID #{}".format(book_id)) return None # don't auto convert, we already have a DJVU for this document path_to_ebook = db.format_abspath(book_id, book_format, index_is_id=True) if book_format == 'pdf': is_rasterbook_val, pages, images = is_rasterbook(path_to_ebook, basic_return=False) if is_rasterbook_val: pass # TODO: should add a 'scanned' or 'djvumaker' tag else: # this is a marked-up/vector-based pdf, # no advantages to having another copy in DJVU format prints(("{} document from book ID #{} determined to be a markup-based ebook," " not converting to DJVU").format(book_format, book_id)) return None #no-error in job panel # TODO: test the DPI to determine if a document is from a broad-sheeted book. # if so, queue up k2pdfopt to try and chunk the content appropriately to letter size prints(("scheduling new {} document from book ID #{} for post-import DJVU" " conversion: {}").format(book_format, book_id, path_to_ebook)) if fork_job: #useful for not blocking calibre GUI when large PDFs # are dropped into the automatic-import-folder try: # https://github.com/kovidgoyal/calibre/blob/master/src/calibre/utils/ipc/simple_worker.py # dispatch API for Worker() # src/calibre/utils/ipc/launch.py # Worker() uses sbp.Popen to # run a second Python to a logfile # note that Calibre bungs the python loader to check the plugin directory when # modules with calibre_plugin. prefixed are passed # https://github.com/kovidgoyal/calibre/blob/master/src/calibre/customize/zipplugin.py#L192 func_name = self.plugin_prefs['use_backend'] args = [path_to_ebook, log, abort, notifications, pages, images] jobret = worker_fork_job('calibre_plugins.{}'.format(PLUGINNAME), func_name, args= args, kwargs={'preferences' : self.plugin_prefs}, env={'PATH': os.environ['PATH'] + ':/usr/local/bin'}, # djvu and poppler-utils on osx timeout=600) # TODO: determine a resonable timeout= based on filesize or # make a heartbeat= check # TODO: doesn't work for pdf2djvu, why? except WorkerError as e: prints('djvudigital background conversion failed: \n{}'.format(force_unicode(e.orig_tb))) raise # ConversionError except: prints(traceback.format_exc()) raise # dump djvudigital output logged in file by the Worker to # calibre proc's (gui or console) log/stdout with open(jobret['stdout_stderr'], 'rb') as f: raw = f.read().strip() prints(raw) if jobret['result']: djvu = jobret['result'] else: WorkerError("djvu conversion error: %s" % jobret['result']) # elif hasattr(self, gui): #if we have the calibre gui running, # we can give it a threadedjob and not use fork_job else: #!fork_job & !gui prints("Starts backend") djvu = self.run_backend(path_to_ebook, log, abort, notifications, pages, images) if djvu: db.new_api.add_format(book_id, 'DJVU', djvu, run_hooks=True) prints("added new 'DJVU' document to book ID #{}".format(book_id)) if sys.__stdin__.isatty(): # update calibre gui Out-Of-Band. Like if we were run as a command-line scripted import # this resets current gui views/selections, no cleaner way to do it :-( from calibre.utils.ipc import RC t = RC(print_error=False) t.start() t.join(3) if t.done: # GUI is running t.conn.send('refreshdb:') t.conn.close() prints("signalled Calibre GUI refresh") else: # TODO: normal Exception propagation instead of passing errors as return values raise Exception(('ConversionError, djvu: {}. Did you install any backend according to the' ' documentation?').format(djvu))
collection = getattr(self, which) q = icu_lower(unicode(filter_value)) for i in xrange(collection.count()): # on every available tag item = collection.item(i) item.setHidden( bool(q and not primary_contains(q, unicode(item.text())))) def accept(self): self.tags = self._get_applied_tags_box_contents() self.save_state() return QDialog.accept(self) def reject(self): self.save_state() return QDialog.reject(self) def save_state(self): gprefs['tag_editor_geometry'] = bytearray(self.saveGeometry()) if __name__ == '__main__': from calibre.gui2 import Application from calibre.library import db db = db() app = Application([]) d = TagEditor(None, db, key='#authors', id_=tuple(db.new_api.all_book_ids())[0]) d.exec_()
from calibre.library import db from calibre.utils.logging import Log import json log = Log() mydb = db('~/Archive/CalTest/').new_api from calibre_plugins.crossref_doi_download import DoiMeta from calibre.ebooks.metadata.book.base import Metadata from calibre_plugins.crossref_doi_download.doi_reader import DoiReader dm = DoiMeta('./plugin/') # url = 'https://api.crossref.org/works/10.1002/bmc.835' url = 'https://api.crossref.org/works/10.1109/tpami.2013.50' # output = urlopen(url).read() qurl = 'https://api.crossref.org/works?query.author=Bogus%C5%82aw+Buszewski&query.bibliographic=Human+exhaled+air+analytics%3A+biomarkers+of+diseases' br = dm.browser # cdata = br.open_novisit(qurl).read() # d2 = json.loads(cdata) # message = d2['message'] # results = message['items'] reader = DoiReader(log) from calibre import ipython ipython(locals())
def __init__(self, db, parent=None): QWizard.__init__(self, parent) self.setModal(True) self.setWindowTitle(_('Add books to calibre')) self.setWindowIcon(QIcon(I('add_book.png'))) self.setPixmap(self.LogoPixmap, QPixmap(P('content_server/calibre.png')).scaledToHeight(80, Qt.SmoothTransformation)) self.setPixmap(self.WatermarkPixmap, QPixmap(I('welcome_wizard.png'))) self.register = {} for attr, cls in [ ('welcome_page', WelcomePage), ('scan_page', ScanPage), ]: setattr(self, attr, cls(db, self)) self.setPage(getattr(cls, 'ID'), getattr(self, attr)) # }}} # Test Wizard {{{ if __name__ == '__main__': from PyQt4.Qt import QApplication from calibre.library import db app = QApplication([]) w = Wizard(db()) w.exec_() # }}}
return self.previous_button.setEnabled(False if row == 0 else True) self.next_button.setEnabled(False if row == self.view.model().rowCount(QModelIndex())-1 else True) self.current_row = row self.setWindowTitle(mi.title) self.cover_pixmap = QPixmap.fromImage(mi.cover_data[1]) try: dpr = self.devicePixelRatioF() except AttributeError: dpr = self.devicePixelRatio() self.cover_pixmap.setDevicePixelRatio(dpr) self.resize_cover() html = render_html(mi, self.css, True, self, pref_name='popup_book_display_fields') set_html(mi, html, self.details) self.marked = mi.marked self.cover.setBackgroundBrush(self.marked_brush if mi.marked else self.normal_brush) self.update_cover_tooltip() if __name__ == '__main__': from calibre.gui2 import Application from calibre.library import db app = Application([]) app.current_db = db() get_gui.ans = app d = Configure(app.current_db) d.exec_() del d del app