def __init__(self, url, fname, parent): QDialog.__init__(self, parent) self.setWindowTitle(_('Download %s')%fname) self.l = QVBoxLayout(self) self.purl = urlparse(url) self.msg = QLabel(_('Downloading <b>%(fname)s</b> from %(url)s')%dict( fname=fname, url=self.purl.netloc)) self.msg.setWordWrap(True) self.l.addWidget(self.msg) self.pb = QProgressBar(self) self.pb.setMinimum(0) self.pb.setMaximum(0) self.l.addWidget(self.pb) self.bb = QDialogButtonBox(QDialogButtonBox.Cancel, Qt.Horizontal, self) self.l.addWidget(self.bb) self.bb.rejected.connect(self.reject) sz = self.sizeHint() self.resize(max(sz.width(), 400), sz.height()) fpath = PersistentTemporaryFile(os.path.splitext(fname)[1]) fpath.close() self.fpath = fpath.name self.worker = Worker(url, self.fpath, Queue()) self.rejected = False
def save_container(container, path): temp = PersistentTemporaryFile( prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) if hasattr(os, 'fchmod'): # Ensure file permissions and owner information is preserved fno = temp.fileno() try: st = os.stat(path) except EnvironmentError as err: if err.errno != errno.ENOENT: raise # path may not exist if we are saving a copy, in which case we use # the metadata from the original book st = os.stat(container.path_to_ebook) os.fchmod(fno, st.st_mode) os.fchown(fno, st.st_uid, st.st_gid) temp.close() temp = temp.name try: container.commit(temp) atomic_rename(temp, path) finally: if os.path.exists(temp): os.remove(temp)
def _write_new_cover(new_cdata, cpath): from calibre.utils.magick.draw import save_cover_data_to new_cover = PersistentTemporaryFile(suffix=os.path.splitext(cpath)[1]) new_cover.close() save_cover_data_to(new_cdata, new_cover.name) return new_cover
def save_container(container, path): temp = PersistentTemporaryFile( prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) if hasattr(os, 'fchmod'): # Ensure file permissions and owner information is preserved fno = temp.fileno() try: st = os.stat(path) except EnvironmentError as err: if err.errno != errno.ENOENT: raise # path may not exist if we are saving a copy, in which case we use # the metadata from the original book st = os.stat(container.path_to_ebook) os.fchmod(fno, st.st_mode) try: os.fchown(fno, st.st_uid, st.st_gid) except EnvironmentError as err: if err.errno != errno.EPERM: # ignore chown failure as user could be editing file belonging # to a different user, in which case we really cant do anything # about it short of making the file update non-atomic raise temp.close() temp = temp.name try: container.commit(temp) atomic_rename(temp, path) finally: if os.path.exists(temp): os.remove(temp)
def commit(self, save_defaults=False): ''' Settings are stored in two attributes: `opf_file` and `cover_file`. Both may be None. Also returns a recommendation dictionary. ''' recs = self.commit_options(save_defaults) self.user_mi = mi = self.get_metadata() self.cover_file = self.opf_file = None if self.db is not None: if mi.title == self.db.title(self.book_id, index_is_id=True): mi.title_sort = self.db.title_sort(self.book_id, index_is_id=True) else: # Regenerate title sort taking into account book language languages = self.db.languages(self.book_id, index_is_id=True) if languages: lang = languages.split(',')[0] else: lang = None mi.title_sort = title_sort(mi.title, lang=lang) self.db.set_metadata(self.book_id, self.user_mi) self.mi, self.opf_file = create_opf_file(self.db, self.book_id) if self.cover_changed and self.cover_data is not None: self.db.set_cover(self.book_id, self.cover_data) cover = self.db.cover(self.book_id, index_is_id=True) if cover: cf = PersistentTemporaryFile('.jpeg') cf.write(cover) cf.close() self.cover_file = cf return recs
def get_metadata(stream): from calibre.ebooks.metadata.archive import is_comic from calibre.ebooks.metadata.meta import get_metadata path = getattr(stream, 'name', False) if not path: pt = PersistentTemporaryFile('_rar-meta.rar') pt.write(stream.read()) pt.close() path = pt.name path = os.path.abspath(path) file_names = list(names(path)) if is_comic(file_names): return get_metadata(stream, 'cbr') for f in file_names: stream_type = os.path.splitext(f)[1].lower() if stream_type: stream_type = stream_type[1:] if stream_type in ('lit', 'opf', 'prc', 'mobi', 'fb2', 'epub', 'rb', 'imp', 'pdf', 'lrf', 'azw'): with TemporaryDirectory() as tdir: with CurrentDir(tdir): stream = extract_member(path, match=None, name=f, as_file=True)[1] return get_metadata(stream, stream_type) raise ValueError('No ebook found in RAR archive')
def get_metadata(stream, cpath=None): if not podofo: raise Unavailable(podofo_err) pt = PersistentTemporaryFile('_podofo.pdf') pt.write(stream.read()) pt.close() server = Server(pool_size=1) job = ParallelJob('read_pdf_metadata', 'Read pdf metadata', lambda x,y:x, args=[pt.name, cpath]) server.add_job(job) while not job.is_finished: time.sleep(0.1) job.update() job.update() server.close() if job.result is None: raise ValueError('Failed to read metadata: ' + job.details) title, authors, creator, tags, ok = job.result if not ok: print 'Failed to extract cover:' print job.details if title == '_': title = getattr(stream, 'name', _('Unknown')) title = os.path.splitext(title)[0] mi = MetaInformation(title, authors) if creator: mi.book_producer = creator if tags: mi.tags = tags if os.path.exists(pt.name): os.remove(pt.name) if ok: mi.cover = cpath return mi
def rebuild_it(self): from calibre.ebooks.tweak import get_tools, WorkerError src_dir = self._exploded det_msg = None of = PersistentTemporaryFile('_tweak_rebuild.'+self.current_format.lower()) of.close() of = of.name self._cleanup_files.append(of) try: rebuilder = get_tools(self.current_format)[1] rebuilder(src_dir, of) except WorkerError as e: det_msg = e.orig_tb except: import traceback det_msg = traceback.format_exc() finally: self.hide_msg() if det_msg is not None: error_dialog(self, _('Failed to rebuild file'), _('Failed to rebuild %s. For more information, click ' '"Show details".')%self.current_format, det_msg=det_msg, show=True) return None return of
def _download(self, cookie_file, url, filename, save_loc, add_to_lib): dfilename = '' if not url: raise Exception(_('No file specified to download.')) if not save_loc and not add_to_lib: # Nothing to do. return dfilename if not filename: filename = get_download_filename(url, cookie_file) filename, ext = os.path.splitext(filename) filename = filename[:60] + ext filename = ascii_filename(filename) br = browser() if cookie_file: cj = MozillaCookieJar() cj.load(cookie_file) br.set_cookiejar(cj) with closing(br.open(url)) as r: tf = PersistentTemporaryFile(suffix=filename) tf.write(r.read()) dfilename = tf.name return dfilename
def do_download(self, urn): self.lock.lock() try: account_info = self.recipe_model.get_account_info(urn) customize_info = self.recipe_model.get_customize_info(urn) recipe = self.recipe_model.recipe_from_urn(urn) un = pw = None if account_info is not None: un, pw = account_info add_title_tag, custom_tags, keep_issues = customize_info script = self.recipe_model.get_recipe(urn) pt = PersistentTemporaryFile('_builtin.recipe') pt.write(script) pt.close() arg = { 'username': un, 'password': pw, 'add_title_tag':add_title_tag, 'custom_tags':custom_tags, 'recipe':pt.name, 'title':recipe.get('title',''), 'urn':urn, 'keep_issues':keep_issues } self.download_queue.add(urn) self.start_recipe_fetch.emit(arg) finally: self.lock.unlock()
def fetch_scheduled_recipe(arg): # {{{ fmt = prefs['output_format'].lower() pt = PersistentTemporaryFile(suffix='_recipe_out.%s'%fmt.lower()) pt.close() recs = [] ps = load_defaults('page_setup') if 'output_profile' in ps: recs.append(('output_profile', ps['output_profile'], OptionRecommendation.HIGH)) lf = load_defaults('look_and_feel') if lf.get('base_font_size', 0.0) != 0.0: recs.append(('base_font_size', lf['base_font_size'], OptionRecommendation.HIGH)) recs.append(('keep_ligatures', lf.get('keep_ligatures', False), OptionRecommendation.HIGH)) lr = load_defaults('lrf_output') if lr.get('header', False): recs.append(('header', True, OptionRecommendation.HIGH)) recs.append(('header_format', '%t', OptionRecommendation.HIGH)) epub = load_defaults('epub_output') if epub.get('epub_flatten', False): recs.append(('epub_flatten', True, OptionRecommendation.HIGH)) args = [arg['recipe'], pt.name, recs] if arg['username'] is not None: recs.append(('username', arg['username'], OptionRecommendation.HIGH)) if arg['password'] is not None: recs.append(('password', arg['password'], OptionRecommendation.HIGH)) return 'gui_convert', args, _('Fetch news from ')+arg['title'], fmt.upper(), [pt]
def view_device_book(self, path): pt = PersistentTemporaryFile('_view_device_book'+ os.path.splitext(path)[1]) self.persistent_files.append(pt) pt.close() self.gui.device_manager.view_book( Dispatcher(self.book_downloaded_for_viewing), path, pt.name)
def convert(self, stream, options, file_ext, log, accelerators): from calibre.ebooks.txt.processor import convert_basic stdout = StringIO() ppdjvu = True # using djvutxt is MUCH faster, should make it an option if options.use_djvutxt and os.path.exists('/usr/bin/djvutxt'): from calibre.ptempfile import PersistentTemporaryFile try: fp = PersistentTemporaryFile(suffix='.djvu', prefix='djv_input') filename = fp._name fp.write(stream.read()) fp.close() cmd = ['djvutxt', filename] stdout.write(Popen(cmd, stdout=PIPE, close_fds=True).communicate()[0]) os.remove(filename) ppdjvu = False except: stream.seek(0) # retry with the pure python converter if ppdjvu: from calibre.ebooks.djvu.djvu import DJVUFile x = DJVUFile(stream) x.get_text(stdout) html = convert_basic(stdout.getvalue().replace(b"\n", b' ').replace( b'\037', b'\n\n')) # Run the HTMLized text through the html processing plugin. from calibre.customize.ui import plugin_for_input_format html_input = plugin_for_input_format('html') for opt in html_input.options: setattr(options, opt.option.name, opt.recommended_value) options.input_encoding = 'utf-8' base = os.getcwdu() if file_ext != 'txtz' and hasattr(stream, 'name'): base = os.path.dirname(stream.name) fname = os.path.join(base, 'index.html') c = 0 while os.path.exists(fname): c += 1 fname = 'index%d.html'%c htmlfile = open(fname, 'wb') with htmlfile: htmlfile.write(html.encode('utf-8')) odi = options.debug_pipeline options.debug_pipeline = None # Generate oeb from html conversion. with open(htmlfile.name, 'rb') as f: oeb = html_input.convert(f, options, 'html', log, {}) options.debug_pipeline = odi os.remove(htmlfile.name) # Set metadata from file. from calibre.customize.ui import get_file_type_metadata from calibre.ebooks.oeb.transforms.metadata import meta_info_to_oeb_metadata mi = get_file_type_metadata(stream, file_ext) meta_info_to_oeb_metadata(mi, oeb.metadata, log) return oeb
def add_empty(self, *args): ''' Add an empty book item to the library. This does not import any formats from a book file. ''' author = series = title = None index = self.gui.library_view.currentIndex() if index.isValid(): raw = index.model().db.authors(index.row()) if raw: authors = [a.strip().replace('|', ',') for a in raw.split(',')] if authors: author = authors[0] series = index.model().db.series(index.row()) title = index.model().db.title(index.row()) dlg = AddEmptyBookDialog(self.gui, self.gui.library_view.model().db, author, series, dup_title=title) if dlg.exec_() == dlg.Accepted: temp_files = [] num = dlg.qty_to_add series = dlg.selected_series title = dlg.selected_title or _('Unknown') db = self.gui.library_view.model().db ids, orig_fmts = [], [] if dlg.duplicate_current_book: origmi = db.get_metadata(index.row(), get_cover=True, cover_as_data=True) if dlg.copy_formats.isChecked(): book_id = db.id(index.row()) orig_fmts = tuple(db.new_api.format(book_id, fmt, as_path=True) for fmt in db.new_api.formats(book_id)) for x in xrange(num): if dlg.duplicate_current_book: mi = origmi else: mi = MetaInformation(title, dlg.selected_authors) if series: mi.series = series mi.series_index = db.get_next_series_num_for(series) fmts = [] empty_format = gprefs.get('create_empty_format_file', '') if dlg.duplicate_current_book and dlg.copy_formats.isChecked(): fmts = orig_fmts elif empty_format: from calibre.ebooks.oeb.polish.create import create_book pt = PersistentTemporaryFile(suffix='.' + empty_format) pt.close() temp_files.append(pt.name) create_book(mi, pt.name, fmt=empty_format) fmts = [pt.name] ids.append(db.import_book(mi, fmts)) tuple(map(os.remove, orig_fmts)) self.gui.library_view.model().books_added(num) self.gui.refresh_cover_browser() self.gui.tags_view.recount() if ids: ids.reverse() self.gui.library_view.select_rows(ids) for path in temp_files: os.remove(path)
def create_cover_file(db, book_id): cover = db.cover(book_id, index_is_id=True) cf = None if cover: cf = PersistentTemporaryFile('.jpeg') cf.write(cover) cf.close() return cf
def generate_catalog(parent, dbspec, ids, device_manager, db): # {{{ from calibre.gui2.dialogs.catalog import Catalog # Build the Catalog dialog in gui2.dialogs.catalog d = Catalog(parent, dbspec, ids, db) if d.exec_() != d.Accepted: return None # Create the output file out = PersistentTemporaryFile(suffix='_catalog_out.'+d.catalog_format.lower()) # Profile the connected device # Parallel initialization in calibre.library.cli:command_catalog() connected_device = { 'is_device_connected': device_manager.is_device_connected, 'kind': device_manager.connected_device_kind, 'name': None, 'save_template': None, 'serial': None, 'storage': None } if device_manager.is_device_connected: device = device_manager.device connected_device['name'] = device.get_gui_name() try: storage = [] if device._main_prefix: storage.append(os.path.join(device._main_prefix, device.EBOOK_DIR_MAIN)) if device._card_a_prefix: storage.append(os.path.join(device._card_a_prefix, device.EBOOK_DIR_CARD_A)) if device._card_b_prefix: storage.append(os.path.join(device._card_b_prefix, device.EBOOK_DIR_CARD_B)) connected_device['storage'] = storage connected_device['serial'] = device.detected_device.serial if \ hasattr(device.detected_device,'serial') else None connected_device['save_template'] = device.save_template() except: pass # These args are passed inline to gui2.convert.gui_conversion:gui_catalog args = [ d.catalog_format, d.catalog_title, dbspec, ids, out.name, d.catalog_sync, d.fmt_options, connected_device ] out.close() # This returns to gui2.actions.catalog:generate_catalog() # Which then calls gui2.convert.gui_conversion:gui_catalog() with the args inline return 'gui_catalog', args, _('Generate catalog'), out.name, d.catalog_sync, \ d.catalog_title
def dump(self, items, out_stream, pdf_metadata): f = PersistentTemporaryFile('_comic2pdf.pdf') f.close() try: self.render_images(f.name, pdf_metadata, items) with open(f.name, 'rb') as x: shutil.copyfileobj(x, out_stream) finally: os.remove(f.name)
def render_inline_toc(self): self.rendered_inline_toc = True from calibre.ebooks.pdf.render.toc import toc_as_html raw = toc_as_html(self.toc, self.doc, self.opts) pt = PersistentTemporaryFile('_pdf_itoc.htm') pt.write(raw) pt.close() self.render_queue.append(pt.name) self.render_next()
def _download_zip(self, plugin_zip_url): from calibre.ptempfile import PersistentTemporaryFile br = browser() br.set_handle_gzip(True) raw = br.open_novisit(plugin_zip_url).read() pt = PersistentTemporaryFile('.zip') pt.write(raw) pt.close() return pt.name
def prince_convert(self): ''' Call the actual Prince command to convert to PDF ''' from os import makedirs from os.path import dirname, join, exists from calibre.ptempfile import PersistentTemporaryFile from calibre.constants import DEBUG # All files are relative to the OPF location opf_dir = dirname(self.opf) base_dir = dirname(self.pdf_file) base_dir = join(opf_dir, base_dir) try: makedirs(base_dir) except BaseException: if not exists(base_dir): raise # Create a temporary CSS file with the box contents custom_CSS = PersistentTemporaryFile() custom_CSS.write(unicode(self.css1.toPlainText())) custom_CSS.close() # Create a temporary file with the list of input files file_list = PersistentTemporaryFile() for item in self.oeb.spine: file_list.write(item.href + "\n") file_list.close() # Build the command line command = prefs['prince_exe'] args = ['-v'] if self.prince_file: args.append('-s') args.append(self.prince_file) args.append('-s') args.append(custom_CSS.name) args.append('-l') args.append(file_list.name) args.append('-o') args.append(self.pdf_file) # Hide the convert button and show a busy indicator self.convert.setEnabled(False) self.progress_bar = QProgressBar() self.progress_bar.setRange(0,0) self.progress_bar.setValue(0) self.l.addWidget(self.progress_bar) # Run the command and return the path to the PDF file if DEBUG: print(_('Converting book...')) process = QProcess(self) process.setWorkingDirectory(opf_dir) process.setProcessChannelMode(QProcess.MergedChannels); process.error.connect(self.error) process.finished.connect(self.end) self.process = process process.start(command, args)
def render_inline_toc(self): evaljs = self.view.page().mainFrame().evaluateJavaScript self.rendered_inline_toc = True from calibre.ebooks.pdf.render.toc import toc_as_html raw = toc_as_html(self.toc, self.doc, self.opts, evaljs) pt = PersistentTemporaryFile('_pdf_itoc.htm') pt.write(raw) pt.close() self.render_queue.append(pt.name) self.render_next()
def test_roundtrip(): ebook = get_container(sys.argv[-1]) p = PersistentTemporaryFile(suffix='.'+sys.argv[-1].rpartition('.')[-1]) p.close() ebook.commit(outpath=p.name) ebook2 = get_container(p.name) ebook3 = get_container(p.name) diff = ebook3.compare_to(ebook2) if diff is not None: print (diff)
def get_cookies(self): ''' Writes QNetworkCookies to Mozilla cookie .txt file. :return: The file path to the cookie file. ''' cf = PersistentTemporaryFile(suffix='.txt') cf.write('# Netscape HTTP Cookie File\n\n') for c in self.page().networkAccessManager().cookieJar().allCookies(): cookie = [] domain = unicode(c.domain()) cookie.append(domain) cookie.append('TRUE' if domain.startswith('.') else 'FALSE') cookie.append(unicode(c.path())) cookie.append('TRUE' if c.isSecure() else 'FALSE') cookie.append(unicode(c.expirationDate().toTime_t())) cookie.append(unicode(c.name())) cookie.append(unicode(c.value())) cf.write('\t'.join(cookie)) cf.write('\n') cf.close() return cf.name
def run_import_plugins(path_or_stream, fmt): fmt = fmt.lower() if hasattr(path_or_stream, 'seek'): path_or_stream.seek(0) pt = PersistentTemporaryFile('_import_plugin.'+fmt) shutil.copyfileobj(path_or_stream, pt, 1024**2) pt.close() path = pt.name else: path = path_or_stream return run_plugins_on_import(path, fmt)
def save_container(container, path): temp = PersistentTemporaryFile( prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) temp.close() temp = temp.name try: container.commit(temp) atomic_rename(temp, path) finally: if os.path.exists(temp): os.remove(temp)
def create_opf_file(db, book_id): mi = db.get_metadata(book_id, index_is_id=True) mi.application_id = uuid.uuid4() old_cover = mi.cover mi.cover = None raw = metadata_to_opf(mi) mi.cover = old_cover opf_file = PersistentTemporaryFile('.opf') opf_file.write(raw) opf_file.close() return mi, opf_file
def download_cover(self, url): from calibre import browser from PIL import Image from cStringIO import StringIO from calibre.ptempfile import PersistentTemporaryFile self.log('Downloading cover from %r'%url) br = browser() raw = br.open_novisit(url).read() buf = StringIO(raw) pt = PersistentTemporaryFile('.jpg') pt.close() img = Image.open(buf) img.convert('RGB').save(pt.name) return pt.name
def do_save(self, tdir, container): temp = None try: path = container.path_to_ebook temp = PersistentTemporaryFile( prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) temp.close() temp = temp.name container.commit(temp) atomic_rename(temp, path) finally: if temp and os.path.exists(temp): os.remove(temp) shutil.rmtree(tdir, ignore_errors=True)
def __init__(self, text, font_size, bottom_margin=30, font_path=None): self.text, self.font_size, = text, font_size self.bottom_margin = bottom_margin if font_path is None: if not isinstance(text, unicode): text = force_unicode(text) from calibre.utils.fonts.utils import get_font_for_text fd = get_font_for_text(text) if fd is not None: from calibre.ptempfile import PersistentTemporaryFile pt = PersistentTemporaryFile('.ttf') pt.write(fd) pt.close() font_path = pt.name self.font_path = font_path
def build_plugin(path): from calibre import prints from calibre.ptempfile import PersistentTemporaryFile from calibre.utils.zipfile import ZipFile, ZIP_STORED path = type(u'')(path) names = frozenset(os.listdir(path)) if u'__init__.py' not in names: prints(path, ' is not a valid plugin') raise SystemExit(1) t = PersistentTemporaryFile(u'.zip') with ZipFile(t, u'w', ZIP_STORED) as zf: zf.add_dir(path, simple_filter=lambda x:x in {'.git', '.bzr', '.svn', '.hg'}) t.close() plugin = add_plugin(t.name) os.remove(t.name) prints(u'Plugin updated:', plugin.name, plugin.version)
def save_container(container, path): if container.is_dir: return save_dir_container(container, path) temp = PersistentTemporaryFile(prefix=('_' if iswindows else '.'), suffix=os.path.splitext(path)[1], dir=os.path.dirname(path)) if hasattr(os, 'fchmod'): # Ensure file permissions and owner information is preserved fno = temp.fileno() try: st = os.stat(path) except EnvironmentError as err: if err.errno != errno.ENOENT: raise # path may not exist if we are saving a copy, in which case we use # the metadata from the original book st = os.stat(container.path_to_ebook) try: os.fchmod(fno, st.st_mode) except EnvironmentError as err: if err.errno != errno.EPERM: raise raise EnvironmentError( 'Failed to change permissions of %s to %s (%s), with error: %s. Most likely the %s directory has a restrictive umask' % (temp.name, oct(st.st_mode), format_permissions(st.st_mode), errno.errorcode[err.errno], os.path.dirname(temp.name))) try: os.fchown(fno, st.st_uid, st.st_gid) except EnvironmentError as err: if err.errno not in (errno.EPERM, errno.EACCES): # ignore chown failure as user could be editing file belonging # to a different user, in which case we really cant do anything # about it short of making the file update non-atomic raise temp.close() temp = temp.name try: container.commit(temp) atomic_rename(temp, path) finally: if os.path.exists(temp): os.remove(temp)
def temporary_file(self, suffix): ''' Return a file-like object that is a temporary file on the file system. This file will remain available even after being closed and will only be removed on interpreter shutdown. Use the ``name`` member of the returned object to access the full path to the created temporary file. :param suffix: The suffix that the temporary file will have. ''' return PersistentTemporaryFile(suffix)
def start_download(gui, ids, callback, ensure_fields=None): d = ConfirmDialog(ids, gui) ret = d.exec_() d.b.clicked.disconnect() if ret != d.Accepted: return tf = PersistentTemporaryFile('_metadata_bulk.log') tf.close() job = Job('metadata bulk download', ngettext( 'Download metadata for one book', 'Download metadata for {} books', len(ids)).format(len(ids)), download, (ids, tf.name, gui.current_db, d.identify, d.covers, ensure_fields), {}, callback) job.metadata_and_covers = (d.identify, d.covers) job.download_debug_log = tf.name gui.job_manager.run_threaded_job(job) gui.status_bar.show_message(_('Metadata download started'), 3000)
def decryptBook(self, book): ''' Decrypt Kobo book :param book: obok file object ''' result = {} result['success'] = False result['fileobj'] = None zin = zipfile.ZipFile(book.filename, 'r') #print ('Kobo library filename: {0}'.format(book.filename)) for userkey in self.userkeys: print (_('Trying key: '), userkey.encode('hex_codec')) check = True try: fileout = PersistentTemporaryFile('.epub', dir=self.tdir) #print ('Temp file: {0}'.format(fileout.name)) # modify the output file to be compressed by default zout = zipfile.ZipFile(fileout.name, "w", zipfile.ZIP_DEFLATED) # ensure that the mimetype file is the first written to the epub container # and is stored with no compression members = zin.namelist(); try: members.remove('mimetype') except Exception: pass zout.writestr('mimetype', 'application/epub+zip', zipfile.ZIP_STORED) # end of mimetype mod for filename in members: contents = zin.read(filename) if filename in book.encryptedfiles: file = book.encryptedfiles[filename] contents = file.decrypt(userkey, contents) # Parse failures mean the key is probably wrong. if check: check = not file.check(contents) zout.writestr(filename, contents) zout.close() zin.close() result['success'] = True result['fileobj'] = fileout print ('Success!') return result except ValueError: print (_('Decryption failed, trying next key.')) zout.close() continue except Exception: print (_('Unknown Error decrypting, trying next key..')) zout.close() continue result['fileobj'] = book.filename zin.close() return result
def _add_empty_format(self, format_): view = self.gui.library_view rows = view.selectionModel().selectedRows() ids = [view.model().id(r) for r in rows] db = self.gui.library_view.model().db if len(ids) == 1: formats = db.formats(ids[0], index_is_id=True) if formats: formats = {x.lower() for x in formats.split(',')} if format_ in formats: title = db.title(ids[0], index_is_id=True) msg = _( 'The {0} format will be replaced in the book {1}. Are you sure?' ).format(format_, title) if not confirm(msg, 'confirm_format_override_on_add', title=_('Are you sure?'), parent=self.gui): return for id_ in ids: from calibre.ebooks.oeb.polish.create import create_book pt = PersistentTemporaryFile(suffix='.' + format_) pt.close() try: mi = db.new_api.get_metadata(id_, get_cover=False, get_user_categories=False, cover_as_data=False) create_book(mi, pt.name, fmt=format_) db.add_format_with_hooks(id_, format_, pt.name, index_is_id=True, notify=True) finally: os.remove(pt.name) current_idx = self.gui.library_view.currentIndex() if current_idx.isValid(): view.model().current_changed(current_idx, current_idx)
def _view_books(self, rows): if not rows or len(rows) == 0: self._launch_viewer() return if not self._view_check(len(rows)): return if self.gui.current_view() is self.gui.library_view: ids = list(map(self.gui.library_view.model().id, rows)) self._view_calibre_books(ids) else: paths = self.gui.current_view().model().paths(rows) for path in paths: pt = PersistentTemporaryFile('_viewer_'+\ os.path.splitext(path)[1]) self.persistent_files.append(pt) pt.close() self.gui.device_manager.view_book(\ Dispatcher(self.book_downloaded_for_viewing), path, pt.name)
def start_load(self): try: self.conn.close() self.pb.setMaximum(self.count) self.pb.setValue(0) self.msg.setText(_('Loading database from SQL')) self.db.close() self.ndbpath = PersistentTemporaryFile('.db') self.ndbpath.close() self.ndbpath = self.ndbpath.name t = DBThread(self.ndbpath, False) t.connect() self.conn = t.conn self.conn.execute('create temporary table temp_sequence(id INTEGER PRIMARY KEY AUTOINCREMENT)') self.conn.commit() QTimer.singleShot(0, self.do_one_load) except Exception as e: import traceback self.error = (as_unicode(e), traceback.format_exc()) self.reject()
def paste_image(self): c = QApplication.instance().clipboard() img = c.image() if img.isNull(): img = c.image(QClipboard.Mode.Selection) if img.isNull(): return error_dialog(self, _('No image'), _('There is no image on the clipboard'), show=True) d = ChooseName('image.jpg', self) if d.exec_() == QDialog.DialogCode.Accepted and d.filename: fmt = d.filename.rpartition('.')[-1].lower() if fmt not in {'jpg', 'jpeg', 'png'}: return error_dialog( self, _('Invalid file extension'), _('The file name you choose must have a .jpg or .png extension' ), show=True) t = PersistentTemporaryFile(prefix='editor-paste-image-', suffix='.' + fmt) t.write(pixmap_to_data(img, fmt)) t.close() self.chosen_image_is_external = (d.filename, t.name) self.accept()
def convert(self, stream, options, file_ext, log, accelerators): from calibre.ebooks.txt.processor import convert_basic stdout = StringIO() ppdjvu = True # using djvutxt is MUCH faster, should make it an option if options.use_djvutxt and os.path.exists('/usr/bin/djvutxt'): from calibre.ptempfile import PersistentTemporaryFile try: fp = PersistentTemporaryFile(suffix='.djvu', prefix='djv_input') filename = fp._name fp.write(stream.read()) fp.close() cmd = ['djvutxt', filename] stdout.write( Popen(cmd, stdout=PIPE, close_fds=True).communicate()[0]) os.remove(filename) ppdjvu = False except: stream.seek(0) # retry with the pure python converter if ppdjvu: from calibre.ebooks.djvu.djvu import DJVUFile x = DJVUFile(stream) x.get_text(stdout) html = convert_basic(stdout.getvalue().replace(b"\n", b' ').replace( b'\037', b'\n\n')) # Run the HTMLized text through the html processing plugin. from calibre.customize.ui import plugin_for_input_format html_input = plugin_for_input_format('html') for opt in html_input.options: setattr(options, opt.option.name, opt.recommended_value) options.input_encoding = 'utf-8' base = os.getcwdu() if file_ext != 'txtz' and hasattr(stream, 'name'): base = os.path.dirname(stream.name) fname = os.path.join(base, 'index.html') c = 0 while os.path.exists(fname): c += 1 fname = 'index%d.html' % c htmlfile = open(fname, 'wb') with htmlfile: htmlfile.write(html.encode('utf-8')) odi = options.debug_pipeline options.debug_pipeline = None # Generate oeb from html conversion. with open(htmlfile.name, 'rb') as f: oeb = html_input.convert(f, options, 'html', log, {}) options.debug_pipeline = odi os.remove(htmlfile.name) # Set metadata from file. from calibre.customize.ui import get_file_type_metadata from calibre.ebooks.oeb.transforms.metadata import meta_info_to_oeb_metadata mi = get_file_type_metadata(stream, file_ext) meta_info_to_oeb_metadata(mi, oeb.metadata, log) return oeb
def _do_splitnew_loop(self, book, tdir=None, db=None): em = self.get_epubmerge_plugin() es = self.get_epubsplit_plugin() # modifies book. em._populate_book_from_calibre_id(book,db) # logger.debug("gonna split:") # logger.debug(book) tmp = PersistentTemporaryFile(prefix='split-%s-'%book['calibre_id'], suffix='.epub', dir=tdir) epubO = es.get_splitepub(book['epub']) lines = epubO.get_split_lines() book['good']=False count = 0 keep_lines=[] showlist=['toc','guide','anchor','id','href'] for line in lines: new_chap = '(new)' in "".join(line.get('toc',[])) if new_chap: book['good']=True if ( new_chap or 'cover' in line['id'] or 'title_page' in line['id']): # or 'log_page' in line['id']) keep_lines.append(count) ## Also grab the previous chapter if new. # if ( new_chap and # count-1 not in keep_lines and # 'file' in lines[count-1]['id'] ): # keep_lines.append(count-1) # print("\nLine Number: %d"%count) # for s in showlist: # if s in line and line[s]: # print("\t%s: %s"%(s,line[s])) count += 1 epubO.write_split_epub(tmp, keep_lines) # , # authoropts=options.authoropts, # titleopt=options.titleopt, # descopt=options.descopt, # tags=options.tagopts, # languages=options.languageopts, # coverjpgpath=options.coveropt) book['splittmp'] = tmp return book
def __enter__(self): self.temppath = None if isinstance(self.stream, str): return as_unicode(self.stream) name = getattr(self.stream, 'name', None) if name and os.access(name, os.R_OK): return as_unicode(name) pos = self.stream.tell() with PersistentTemporaryFile('for-unar', 'wb') as f: shutil.copyfileobj(self.stream, f) self.stream.seek(pos) self.temppath = f.name return as_unicode(f.name)
def _download(self, url, filename, save_loc): dfilename = '' if not url: raise Exception(_('No file specified to download.')) if not save_loc: # Nothing to do. return dfilename if not filename: filename = get_download_filename(url) filename, ext = os.path.splitext(filename) filename = filename[:60] + ext filename = ascii_filename(filename) br = browser() with closing(br.open(url)) as r: tf = PersistentTemporaryFile(suffix=filename) tf.write(r.read()) dfilename = tf.name return dfilename
def _launch_viewer(self, name=None, viewer='ebook-viewer', internal=True, calibre_book_data=None, open_at=None): self.gui.setCursor(Qt.CursorShape.BusyCursor) try: if internal: args = [viewer] if ismacos and 'ebook' in viewer: args.append('--raise-window') if name is not None: args.append(name) if viewer != 'lrfviewer': if open_at is not None: args.append('--open-at=' + open_at) if calibre_book_data is not None: with PersistentTemporaryFile('.json') as ptf: ptf.write( as_bytes(json.dumps(calibre_book_data))) args.append('--internal-book-data=' + ptf.name) self.gui.job_manager.launch_gui_app(viewer, kwargs=dict(args=args)) else: if iswindows: from calibre_extensions import winutil ext = name.rpartition('.')[-1] if ext: try: prog = winutil.file_association(str('.' + ext)) except Exception: prog = None if prog and prog.lower().endswith('calibre.exe'): name = os.path.basename(name) return error_dialog( self.gui, _('No associated program'), _('Windows will try to open %s with calibre itself' ' resulting in a duplicate in your calibre library. You' ' should install some program capable of viewing this' ' file format and tell Windows to use that program to open' ' files of this type.') % name, show=True) open_local_file(name) time.sleep(2) # User feedback finally: self.gui.unsetCursor()
def test_basic(): stream = BytesIO( # {{{ b"Rar!\x1a\x07\x00\xcf\x90s\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x14\xe7z\x00\x80#\x00\x17\x00\x00\x00\r\x00\x00\x00\x03\xc2\xb3\x96o\x00\x00\x00\x00\x1d3\x03\x00\x00\x00\x00\x00CMT\x0c\x00\x8b\xec\x8e\xef\x14\xf6\xe6h\x04\x17\xff\xcd\x0f\xffk9b\x11]^\x80\xd3dt \x90+\x00\x14\x00\x00\x00\x08\x00\x00\x00\x03\xf1\x84\x93\\\xb9]yA\x1d3\t\x00\xa4\x81\x00\x001\\sub-one\x00\xc0\x0c\x00\x8f\xec\x89\xfe.JM\x86\x82\x0c_\xfd\xfd\xd7\x11\x1a\xef@\x9eHt \x80'\x00\x0e\x00\x00\x00\x04\x00\x00\x00\x03\x9f\xa8\x17\xf8\xaf]yA\x1d3\x07\x00\xa4\x81\x00\x00one.txt\x00\x08\xbf\x08\xae\xf3\xca\x87\xfeo\xfe\xd2n\x80-Ht \x82:\x00\x18\x00\x00\x00\x10\x00\x00\x00\x03\xa86\x81\xdf\xf9fyA\x1d3\x1a\x00\xa4\x81\x00\x00\xe8\xaf\xb6\xe6\xaf\x94\xe5\xb1\x81.txt\x00\x8bh\xf6\xd4kA\\.\x00txt\x0c\x00\x8b\xec\x8e\xef\x14\xf6\xe2l\x91\x189\xff\xdf\xfe\xc2\xd3:g\x9a\x19F=cYt \x928\x00\x11\x00\x00\x00\x08\x00\x00\x00\x03\x7f\xd6\xb6\x7f\xeafyA\x1d3\x16\x00\xa4\x81\x00\x00F\xc3\xbc\xc3\x9fe.txt\x00\x01\x00F\xfc\xdfe\x00.txt\x00\xc0<D\xfe\xc8\xef\xbc\xd1\x04I?\xfd\xff\xdbF)]\xe8\xb9\xe1t \x90/\x00\x13\x00\x00\x00\x08\x00\x00\x00\x03\x1a$\x932\xc2]yA\x1d3\r\x00\xa4\x81\x00\x002\\sub-two.txt\x00\xc0\x10\x00S\xec\xcb\x7f\x8b\xa5(\x0b\x01\xcb\xef\xdf\xf6t\x89\x97z\x0eft \x90)\x00\r\x00\x00\x00\r\x00\x00\x00\x03c\x89K\xd3\xc8fyA\x140\x07\x00\xff\xa1\x00\x00symlink\x00\xc02/sub-two.txt\xeb\x86t\xe0\x90#\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\xb9]yA\x140\x01\x00\xedA\x00\x001\x00\xc0\xe0Dt\xe0\x90#\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\xc2]yA\x140\x01\x00\xedA\x00\x002\x00\xc0u\xa1t \x80,\x00\r\x00\x00\x00\r\x00\x00\x00\x03T\xea\x04\xca\xe6\x84yA\x140\x0c\x00\xa4\x81\x00\x00uncompresseduncompressed\n\xda\x10t \x900\x00\x0e\x00\x00\x00\x04\x00\x00\x00\x035K.\xa6\x18\x85yA\x1d5\x0e\x00\xa4\x81\x00\x00max-compressed\x00\xc0\x00\x08\xbf\x08\xae\xf2\xcc\x01s\xf8\xff\xec\x96\xe8\xc4={\x00@\x07\x00" ) # noqa }}} tdata = { '1': b'', '1/sub-one': b'sub-one\n', '2': b'', '2/sub-two.txt': b'sub-two\n', 'F\xfc\xdfe.txt': b'unicode\n', 'max-compressed': b'max\n', 'one.txt': b'one\n', 'symlink': b'2/sub-two.txt', 'uncompressed': b'uncompressed\n', '\u8bf6\u6bd4\u5c41.txt': b'chinese unicode\n' } def do_test(stream): c = comment(stream) expected = 'some comment\n' if c != expected: raise ValueError('Comment not read: %r != %r' % (c, expected)) if set(names(stream)) != { '1/sub-one', 'one.txt', '2/sub-two.txt', '诶比屁.txt', 'Füße.txt', 'uncompressed', 'max-compressed' }: raise ValueError('Name list does not match') with TemporaryDirectory('test-unrar') as tdir: extract(stream, tdir) for name in tdata: if name not in '1 2 symlink'.split(): with open(os.path.join(tdir, name), 'rb') as s: if s.read() != tdata[name]: raise ValueError('Did not extract %s properly' % name) for name in tdata: if name not in '1 2 symlink'.split(): d = extract_member(stream, name=name) if d is None or d[1] != tdata[name]: raise ValueError('Failed to extract %s %r != %r' % (name, d, tdata[name])) do_test(stream) with PersistentTemporaryFile('test-unrar') as f: shutil.copyfileobj(stream, f) with open(f.name, 'rb') as stream: do_test(stream) os.remove(f.name)
def fetch_scheduled_recipe(arg): # {{{ fmt = prefs['output_format'].lower() # Never use AZW3 for periodicals... if fmt == 'azw3': fmt = 'mobi' pt = PersistentTemporaryFile(suffix='_recipe_out.%s'%fmt.lower()) pt.close() recs = [] ps = load_defaults('page_setup') if 'output_profile' in ps: recs.append(('output_profile', ps['output_profile'], OptionRecommendation.HIGH)) lf = load_defaults('look_and_feel') if lf.get('base_font_size', 0.0) != 0.0: recs.append(('base_font_size', lf['base_font_size'], OptionRecommendation.HIGH)) recs.append(('keep_ligatures', lf.get('keep_ligatures', False), OptionRecommendation.HIGH)) lr = load_defaults('lrf_output') if lr.get('header', False): recs.append(('header', True, OptionRecommendation.HIGH)) recs.append(('header_format', '%t', OptionRecommendation.HIGH)) epub = load_defaults('epub_output') if epub.get('epub_flatten', False): recs.append(('epub_flatten', True, OptionRecommendation.HIGH)) args = [arg['recipe'], pt.name, recs] if arg['username'] is not None: recs.append(('username', arg['username'], OptionRecommendation.HIGH)) if arg['password'] is not None: recs.append(('password', arg['password'], OptionRecommendation.HIGH)) return 'gui_convert', args, _('Fetch news from ')+arg['title'], fmt.upper(), [pt]
def dump(self, items, out_stream, pdf_metadata): from calibre.utils.podofo import get_podofo f = PersistentTemporaryFile('_comic2pdf.pdf') f.close() self.metadata = pdf_metadata try: self.render_images(f.name, pdf_metadata, items) with open(f.name, 'rb') as x: raw = x.read() doc = get_podofo().PDFDoc() doc.load(raw) doc.creator = u'%s %s [http://calibre-ebook.com]' % (__appname__, __version__) doc.title = self.metadata.title doc.author = self.metadata.author if self.metadata.tags: doc.keywords = self.metadata.tags raw = doc.write() out_stream.write(raw) finally: try: os.remove(f.name) except: pass
def run(self): try: with PersistentTemporaryFile('print-to-pdf-log.txt') as f: p = self.worker = start_pipe_worker('from calibre.gui2.viewer.printing import do_print; do_print()', stdout=f, stderr=subprocess.STDOUT) p.stdin.write(msgpack_dumps(self.data)), p.stdin.flush(), p.stdin.close() rc = p.wait() if rc != 0: f.seek(0) self.log = f.read().decode('utf-8', 'replace') try: os.remove(f.name) except EnvironmentError: pass except Exception: import traceback self.tb = traceback.format_exc()
def extract_content(self, output_dir): self.log.info('Extracting PDF...') pdf = PersistentTemporaryFile('.pdf') pdf.close() pdf = open(pdf, 'wb') for x in xrange(self.header.section_count()): pdf.write(self.header.section_data(x)) pdf.close() from calibre.customize.ui import plugin_for_input_format pdf_plugin = plugin_for_input_format('pdf') for opt in pdf_plugin.options: if not hasattr(self.options, opt.option.name): setattr(self.options, opt.option.name, opt.recommended_value) return pdf_plugin.convert(open(pdf, 'rb'), self.options, 'pdf', self.log, {})
def process_image(self, data): if not self.process_images: return data try: return mobify_image(data) except Exception: if 'png' != what(None, data): raise with PersistentTemporaryFile(suffix='.png') as pt: pt.write(data) try: from calibre.utils.img import optimize_png optimize_png(pt.name) data = lopen(pt.name, 'rb').read() finally: os.remove(pt.name) return mobify_image(data)
def process_image(self, data): if not self.process_images: return data func = mobify_image if self.opts.mobi_keep_original_images else rescale_image try: return ensure_jpeg_has_jfif(func(data)) except Exception: if 'png' != what(None, data): raise with PersistentTemporaryFile(suffix='.png') as pt: pt.write(data) try: from calibre.utils.img import optimize_png optimize_png(pt.name) data = lopen(pt.name, 'rb').read() finally: os.remove(pt.name) return func(data)
def calibre_cover(title, author_string, series_string=None, output_format='jpg', title_size=46, author_size=36, logo_path=None): title = normalize(title) author_string = normalize(author_string) series_string = normalize(series_string) from calibre.utils.magick.draw import create_cover_page, TextLine import regex pat = regex.compile( ur'\p{Cf}+', flags=regex.VERSION1) # remove non-printing chars like the soft hyphen text = pat.sub(u'', title + author_string + (series_string or u'')) font_path = P('fonts/liberation/LiberationSerif-Bold.ttf') from calibre.utils.fonts.utils import get_font_for_text font = open(font_path, 'rb').read() c = get_font_for_text(text, font) cleanup = False if c is not None and c != font: from calibre.ptempfile import PersistentTemporaryFile pt = PersistentTemporaryFile('.ttf') pt.write(c) pt.close() font_path = pt.name cleanup = True lines = [ TextLine(pat.sub(u'', title), title_size, font_path=font_path), TextLine(pat.sub(u'', author_string), author_size, font_path=font_path) ] if series_string: lines.append( TextLine(pat.sub(u'', series_string), author_size, font_path=font_path)) if logo_path is None: logo_path = I('library.png') try: return create_cover_page(lines, logo_path, output_format='jpg', texture_opacity=0.3, texture_data=I('cover_texture.png', data=True)) finally: if cleanup: os.remove(font_path)
def handle_event(self, event): if isinstance(event, Job): job = event if not self.available_workers: if len(self.busy_workers) >= self.max_workers: self.pending_jobs.append(job) return if self.start_worker() is False: return False return self.run_job(job) elif isinstance(event, WorkerResult): worker_result = event self.busy_workers.pop(worker_result.worker, None) self.available_workers.append(worker_result.worker) self.tracker.task_done() if worker_result.is_terminal_failure: self.terminal_failure = TerminalFailure( 'Worker process crashed while executing job', worker_result.result.traceback, worker_result.id) self.terminal_error() return False self.results.put(worker_result) else: self.common_data = cPickle.dumps(event, -1) if len(self.common_data) > MAX_SIZE: self.cd_file = PersistentTemporaryFile('pool_common_data') with self.cd_file as f: f.write(self.common_data) self.common_data = cPickle.dumps(File(f.name), -1) for worker in self.available_workers: try: worker.set_common_data(self.common_data) except Exception: import traceback self.terminal_failure = TerminalFailure( 'Worker process crashed while sending common data', traceback.format_exc(), None) self.terminal_error() return False while self.pending_jobs and self.available_workers: if self.run_job(self.pending_jobs.pop()) is False: return False