def create_from_query_string(qs): ans = MultiDict() if ispy3: qs = as_unicode(qs) for k, v in iteritems(parse_qs(qs, keep_blank_values=True)): dict.__setitem__(ans, as_unicode(k), [as_unicode(x) for x in v]) return ans
def prints(*a, **kw): ' Print either unicode or bytes to either binary or text mode streams ' stream = kw.get('file', sys.stdout) if stream is None: return sep, end = kw.get('sep'), kw.get('end') if sep is None: sep = ' ' if end is None: end = '\n' if is_binary(stream): encoding = getattr(stream, 'encoding', None) or 'utf-8' a = (as_bytes(x, encoding=encoding) for x in a) sep = as_bytes(sep) end = as_bytes(end) else: a = (as_unicode(x, errors='replace') for x in a) sep = as_unicode(sep) end = as_unicode(end) for i, x in enumerate(a): if sep and i != 0: stream.write(sep) stream.write(x) if end: stream.write(end) if kw.get('flush'): try: stream.flush() except Exception: pass
def setData(self, index, value, role): if not index.isValid(): return False row, col = index.row(), index.column() account = self.account_order[row] if col == 3: self.accounts[account][1] ^= True elif col == 2: self.subjects[account] = as_unicode(value or '') elif col == 4: self.aliases.pop(account, None) aval = as_unicode(value or '').strip() if aval: self.aliases[account] = aval elif col == 5: self.tags.pop(account, None) aval = as_unicode(value or '').strip() if aval: self.tags[account] = aval elif col == 1: self.accounts[account][0] = re.sub(',+', ',', re.sub(r'\s+', ',', as_unicode(value or '').upper())) elif col == 0: na = as_unicode(value or '') from email.utils import parseaddr addr = parseaddr(na)[-1] if not addr: return False self.accounts[na] = self.accounts.pop(account) self.account_order[row] = na if '@kindle.com' in addr: self.accounts[na][0] = 'AZW, MOBI, TPZ, PRC, AZW1' self.dataChanged.emit( self.index(index.row(), 0), self.index(index.row(), 3)) return True
def href(self, basedir=None): ''' Return a URL pointing to this resource. If it is a file on the filesystem the URL is relative to `basedir`. `basedir`: If None, the basedir of this resource is used (see :method:`set_basedir`). If this resource has no basedir, then the current working directory is used as the basedir. ''' if basedir is None: if self._basedir: basedir = self._basedir else: basedir = os.getcwd() if self.path is None: return self._href f = self.fragment.encode('utf-8') if isinstance(self.fragment, str) else self.fragment frag = '#' + as_unicode(quote(f)) if self.fragment else '' if self.path == basedir: return '' + frag try: rpath = relpath(self.path, basedir) except OSError: # On windows path and basedir could be on different drives rpath = self.path if isinstance(rpath, str): rpath = rpath.encode('utf-8') return as_unicode(quote(rpath.replace(os.sep, '/'))) + frag
def __init__(self, input, log, input_encoding=None): CHMFile.__init__(self) if isinstance(input, unicode_type): input = input.encode(filesystem_encoding) if not self.LoadCHM(input): raise CHMError("Unable to open CHM file '%s'"%(input,)) self.log = log self.input_encoding = input_encoding self.chm_encoding = self.get_encoding() or 'cp1252' self._sourcechm = input self._contents = None self._playorder = 0 self._metadata = False self._extracted = False self.re_encoded_files = set() if self.home: self.home = as_unicode(self.home, self.chm_encoding) if self.topics: self.topics = as_unicode(self.topics, self.chm_encoding) # location of '.hhc' file, which is the CHM TOC. if self.topics is None: self.root, ext = os.path.splitext(self.home.lstrip('/')) self.hhc_path = self.root + ".hhc" else: self.root, ext = os.path.splitext(self.topics.lstrip('/')) self.hhc_path = self.root + ".hhc"
def __init__(self, input, log, input_encoding=None): CHMFile.__init__(self) if isinstance(input, unicode_type): enc = 'mbcs' if iswindows else filesystem_encoding try: input = input.encode(enc) except UnicodeEncodeError: from calibre.ptempfile import PersistentTemporaryFile with PersistentTemporaryFile(suffix='.chm') as t: t.write(open(input, 'rb').read()) input = t.name if not self.LoadCHM(input): raise CHMError("Unable to open CHM file '%s'" % (input, )) self.log = log self.input_encoding = input_encoding self.chm_encoding = self.get_encoding() or 'cp1252' self._sourcechm = input self._contents = None self._playorder = 0 self._metadata = False self._extracted = False self.re_encoded_files = set() if self.home: self.home = as_unicode(self.home, self.chm_encoding) if self.topics: self.topics = as_unicode(self.topics, self.chm_encoding) # location of '.hhc' file, which is the CHM TOC. if self.topics is None: self.root, ext = os.path.splitext(self.home.lstrip('/')) self.hhc_path = self.root + ".hhc" else: self.root, ext = os.path.splitext(self.topics.lstrip('/')) self.hhc_path = self.root + ".hhc"
def get_paths(chm, ui, ctx): try: path = as_unicode(ui.path, self.chm_encoding) except UnicodeDecodeError: path = as_unicode(ui.path, 'utf-8') # skip directories # note this path refers to the internal CHM structure if path[-1] != '/': # and make paths relative paths.append(path.lstrip('/'))
def create_ncx(self): index_entries = read_ncx(self.kf8_sections, self.header.ncxidx, self.header.codec) remove = [] # Add href and anchor info to the index entries for entry in index_entries: pos_fid = entry['pos_fid'] if pos_fid is None: pos = entry['pos'] fi = self.get_file_info(pos) if fi.filename is None: raise ValueError('Index entry has invalid pos: %d' % pos) idtag = self.get_id_tag(pos) href = '%s/%s' % (fi.type, fi.filename) else: try: href, idtag = self.get_id_tag_by_pos_fid(*pos_fid) except ValueError: self.log.warn( 'Invalid entry in NCX (title: %s), ignoring' % entry['text']) remove.append(entry) continue entry['href'] = href entry['idtag'] = as_unicode(idtag, self.header.codec or 'utf-8') for e in remove: index_entries.remove(e) # Build the TOC object return build_toc(index_entries)
def metadata_from_path(cls, path): if path.endswith('.kfx'): from calibre.ebooks.metadata.kfx import read_metadata_kfx try: kfx_path = path with lopen(kfx_path, 'rb') as f: if f.read(8) != b'\xeaDRMION\xee': f.seek(0) mi = read_metadata_kfx(f) else: kfx_path = os.path.join( path.rpartition('.')[0] + '.sdr', 'assets', 'metadata.kfx') with lopen(kfx_path, 'rb') as mf: mi = read_metadata_kfx(mf) except Exception: import traceback traceback.print_exc() if DEBUG: prints('failed kfx path:', kfx_path) mi = cls.metadata_from_formats([path]) else: mi = cls.metadata_from_formats([path]) if mi.title == _('Unknown') or ('-asin' in mi.title and '-type' in mi.title): path = as_unicode(path, filesystem_encoding, 'replace') match = cls.WIRELESS_FILE_NAME_PATTERN.match( os.path.basename(path)) if match is not None: mi.title = match.group('title') return mi
def resource_adder(self, link_, base=None): from polyglot.urllib import quote link, frag = self.link_to_local_path(link_, base=base) if link is None: return link_ try: if base and not os.path.isabs(link): link = os.path.join(base, link) link = os.path.abspath(link) except: return link_ if not os.access(link, os.R_OK): return link_ if os.path.isdir(link): self.log.warn(link_, 'is a link to a directory. Ignoring.') return link_ if not self.is_case_sensitive(tempfile.gettempdir()): link = link.lower() if link not in self.added_resources: bhref = os.path.basename(link) id, href = self.oeb.manifest.generate( id='added', href=sanitize_file_name(bhref)) guessed = self.guess_type(href)[0] media_type = guessed or self.BINARY_MIME if media_type == 'text/plain': self.log.warn('Ignoring link to text file %r' % link_) return None if media_type == self.BINARY_MIME: # Check for the common case, images try: img = what(link) except EnvironmentError: pass else: if img: media_type = self.guess_type( 'dummy.' + img)[0] or self.BINARY_MIME self.oeb.log.debug('Added', link) self.oeb.container = self.DirContainer(os.path.dirname(link), self.oeb.log, ignore_opf=True) # Load into memory item = self.oeb.manifest.add(id, href, media_type) # bhref refers to an already existing file. The read() method of # DirContainer will call unquote on it before trying to read the # file, therefore we quote it here. if isinstance(bhref, unicode_type): bhref = bhref.encode('utf-8') item.html_input_href = as_unicode(quote(bhref)) if guessed in self.OEB_STYLES: item.override_css_fetch = partial(self.css_import_handler, os.path.dirname(link)) item.data self.added_resources[link] = href nlink = self.added_resources[link] if frag: nlink = '#'.join((nlink, frag)) return nlink
def safe_localhost(): # RFC 2821 says we should use the fqdn in the EHLO/HELO verb, and # if that can't be calculated, that we should use a domain literal # instead (essentially an encoded IP address like [A.B.C.D]). try: fqdn = decode_fqdn(socket.getfqdn()) except UnicodeDecodeError: if not iswindows: raise from calibre_extensions.winutil import get_computer_name fqdn = get_computer_name() if '.' in fqdn and fqdn != '.': # Some mail servers have problems with non-ascii local hostnames, see # https://bugs.launchpad.net/bugs/1256549 try: local_hostname = as_unicode(idna.ToASCII(fqdn)) except Exception: local_hostname = 'localhost.localdomain' else: # We can't find an fqdn hostname, so use a domain literal addr = '127.0.0.1' try: addr = socket.gethostbyname(socket.gethostname()) except socket.gaierror: pass local_hostname = '[%s]' % addr return local_hostname
def create_new_lc_custom_columns(self, execution_param_list): if len(self.cli_param_list) == 0: return True, False # successful since the labels already exist; no restart is required. dbpath = self.lib_path was_successful = True restart_required = True for param in execution_param_list: try: lc_cli_add_custom_column(self.guidb, param, dbpath) except Exception as e: if DEBUG: print("Exception: ", as_unicode(e)) was_successful = False break #END FOR return was_successful, restart_required #----------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------- #END of library_codes_dialog.py
def parse_bookmarks(raw): raw = as_unicode(raw) for line in raw.splitlines(): if '^' in line: tokens = line.rpartition('^') title, ref = tokens[0], tokens[2] try: spine, _, pos = ref.partition('#') spine = int(spine.strip()) except Exception: continue yield { 'type': 'legacy', 'title': title, 'spine': spine, 'pos': pos } elif BM_FIELD_SEP in line: try: title, spine, pos = line.strip().split(BM_FIELD_SEP) spine = int(spine) except Exception: continue # Unescape from serialization pos = pos.replace(BM_LEGACY_ESC, u'^') # Check for pos being a scroll fraction try: pos = float(pos) except Exception: pass yield {'type': 'cfi', 'title': title, 'pos': pos, 'spine': spine}
def compile_pyj(data, filename='<stdin>', beautify=True, private_scope=True, libdir=None, omit_baselib=False, js_version=5, add_call_site_to_functions=''): if isinstance(data, bytes): data = data.decode('utf-8') options = { 'beautify': beautify, 'private_scope': private_scope, 'keep_baselib': not omit_baselib, 'filename': filename, 'js_version': js_version, 'add_call_site_to_functions': '', } if not ok_to_import_webengine(): from calibre.debug import run_calibre_debug p = run_calibre_debug( '-c', 'from calibre.utils.rapydscript import *; forked_compile()', json.dumps(options), stdin=subprocess.PIPE, stdout=subprocess.PIPE) stdout = p.communicate(as_bytes(data))[0] if p.wait() != 0: raise SystemExit(p.returncode) idx = stdout.find(OUTPUT_SENTINEL) result = as_unicode(stdout[idx + len(OUTPUT_SENTINEL):]) else: c = compiler() result = c(data, options) return result
def get_paths(chm, ui, ctx): # these are supposed to be UTF-8 in CHM as best as I can determine # see https://tika.apache.org/1.11/api/org/apache/tika/parser/chm/accessor/ChmPmgiHeader.html path = as_unicode(ui.path, 'utf-8') # skip directories # note this path refers to the internal CHM structure if path[-1] != '/': # and make paths relative paths.append(path.lstrip('/'))
def load_finished(self, ok, data): cbd = self.calibre_book_data_for_first_book self.calibre_book_data_for_first_book = None if self.shutting_down: return open_at, self.pending_open_at = self.pending_open_at, None self.web_view.clear_caches() if not ok: self.actions_toolbar.update_action_state(False) self.setWindowTitle(self.base_window_title) tb = as_unicode(data['tb'].strip(), errors='replace') tb = re.split(r'^calibre\.gui2\.viewer\.convert_book\.ConversionFailure:\s*', tb, maxsplit=1, flags=re.M)[-1] last_line = tuple(tb.strip().splitlines())[-1] if last_line.startswith('calibre.ebooks.DRMError'): DRMErrorMessage(self).exec_() else: error_dialog(self, _('Loading book failed'), _( 'Failed to open the book at {0}. Click "Show details" for more info.').format(data['pathtoebook']), det_msg=tb, show=True) self.loading_overlay.hide() self.web_view.show_home_page() return try: set_book_path(data['base'], data['pathtoebook']) except Exception: if data['reloaded']: raise self.load_ebook(data['pathtoebook'], open_at=data['open_at'], reload_book=True) return self.current_book_data = data get_current_book_data(self.current_book_data) self.current_book_data['annotations_map'] = defaultdict(list) self.current_book_data['annotations_path_key'] = path_key(data['pathtoebook']) + '.json' self.load_book_data(cbd) self.update_window_title() initial_cfi = self.initial_cfi_for_current_book() initial_position = {'type': 'cfi', 'data': initial_cfi} if initial_cfi else None if open_at: if open_at.startswith('toc:'): initial_toc_node = self.toc_model.node_id_for_text(open_at[len('toc:'):]) initial_position = {'type': 'toc', 'data': initial_toc_node} elif open_at.startswith('toc-href:'): initial_toc_node = self.toc_model.node_id_for_href(open_at[len('toc-href:'):], exact=True) initial_position = {'type': 'toc', 'data': initial_toc_node} elif open_at.startswith('toc-href-contains:'): initial_toc_node = self.toc_model.node_id_for_href(open_at[len('toc-href-contains:'):], exact=False) initial_position = {'type': 'toc', 'data': initial_toc_node} elif open_at.startswith('epubcfi(/'): initial_position = {'type': 'cfi', 'data': open_at} elif open_at.startswith('ref:'): initial_position = {'type': 'ref', 'data': open_at[len('ref:'):]} elif is_float(open_at): initial_position = {'type': 'bookpos', 'data': float(open_at)} highlights = self.current_book_data['annotations_map']['highlight'] self.highlights_widget.load(highlights) self.web_view.start_book_load(initial_position=initial_position, highlights=highlights, current_book_data=self.current_book_data) performance_monitor('webview loading requested')
def customize_recipe(self): d = ChooseBuiltinRecipe(self.recipe_model, self) if d.exec_() != d.Accepted: return id_ = d.selected_recipe if not id_: return src = get_builtin_recipe_by_id(id_, download_recipe=True) if src is None: raise Exception('Something weird happened') src = as_unicode(src) self.edit_recipe(None, src)
def convert(images, output_path, opts, metadata, report_progress): with open(output_path, 'wb') as buf: page_layout = get_page_layout(opts, for_comic=True) page_size = page_layout.fullRectPoints().size() writer = PDFStream(buf, (page_size.width(), page_size.height()), compress=True) writer.apply_fill(color=(1, 1, 1)) pdf_metadata = PDFMetadata(metadata) writer.set_metadata(pdf_metadata.title, pdf_metadata.author, pdf_metadata.tags, pdf_metadata.mi) for i, path in enumerate(images): img = Image(as_unicode(path, filesystem_encoding)) draw_image_page(writer, img) writer.end_page() report_progress((i + 1) / len(images), _('Rendered {0} of {1} pages').format(i + 1, len(images))) writer.end()
def lc_cli_add_custom_column(guidb, param, dbpath): #~ param = --is-multiple + '|||' + label + '|||' + name + '|||' + datatype #~ param = label + '|||' + name + '|||' + datatype if "is-multiple" in param: is_multiple = True param = param.replace("--is-multiple|||", "") else: is_multiple = False if DEBUG: print("final param:", param) param = param.strip() args = param.split("|||") args_list = [] for row in args: s = row.strip() if s > " ": s = s.replace('"', '') args_list.append(s) if DEBUG: print("arg: ", as_unicode(s)) #END FOR label = args_list[0] name = args_list[1] datatype = args_list[2] display = {} db = LibraryDatabase(dbpath) db.create_custom_column(label, name, datatype, is_multiple, display=display) if DEBUG: print("Custom column created: ", label, " ", name, " ", datatype) # Re-open the DB so that field_metadata reflects the column changes guidb.prefs['field_metadata'] = db.field_metadata.all_metadata() #~ if DEBUG: #~ s = guidb.prefs['field_metadata'] #~ print("new guidb field_metadata: ", as_unicode(s)) send_rc_message('')
def mount(self, device_node_path): d = self.device(device_node_path) try: return as_unicode(d.Mount( { 'auth.no_user_interaction':True, 'options':','.join(basic_mount_options()) }, dbus_interface=self.FILESYSTEM)) except Exception: # May be already mounted, check mp = node_mountpoint(unicode_type(device_node_path)) if mp is None: raise return mp
def end(self): if self.current_page.getvalue(): self.end_page() self.font_manager.embed_fonts(self.debug) inforef = self.objects.add(self.info) self.links.add_links() self.objects.pdf_serialize(self.stream) self.write_line() startxref = self.objects.write_xref(self.stream) file_id = String(as_unicode(self.stream.hashobj.hexdigest())) self.write_line('trailer') trailer = Dictionary({'Root':self.catalog, 'Size':len(self.objects)+1, 'ID':Array([file_id, file_id]), 'Info':inforef}) serialize(trailer, self.stream) self.write_line('startxref') self.write_line('%d'%startxref) self.stream.write('%%EOF')
def prints(self, level, *args, **kwargs): col = self.color[level] if col != self.last_col: if self.data: self.data.append(self.normal) self.data.append(col) self.last_col = col sep = kwargs.get('sep', ' ') end = kwargs.get('end', '\n') for arg in args: arg = as_unicode(arg) self.data.append(arg + sep) self.plain_text.append(arg + sep) self.data.append(end) self.plain_text.append(end)
def customize_recipe(self): d = QDialog(self) d.l = QVBoxLayout() d.setLayout(d.l) d.list = QListWidget(d) connect_lambda(d.list.doubleClicked, d, lambda d: d.accept()) d.l.addWidget(d.list) d.bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, d) d.bb.accepted.connect(d.accept) d.bb.rejected.connect(d.reject) d.l.addWidget(d.bb) d.setWindowTitle(_('Choose builtin recipe')) items = [] for r in get_builtin_recipe_collection(): id_ = r.get('id', '') title = r.get('title', '') lang = r.get('language', '') if id_ and title: items.append((title + ' [%s]' % lang, id_)) items.sort(key=lambda x: sort_key(x[0])) for title, id_ in items: item = QListWidgetItem(title) item.setData(Qt.UserRole, id_) d.list.addItem(item) d.resize(QSize(450, 400)) ret = d.exec_() d.list.doubleClicked.disconnect() if ret != d.Accepted: return items = list(d.list.selectedItems()) if not items: return item = items[-1] id_ = unicode_type(item.data(Qt.UserRole) or '') title = unicode_type(item.data(Qt.DisplayRole) or '').rpartition(' [')[0] src = get_builtin_recipe_by_id(id_, download_recipe=True) if src is None: raise Exception('Something weird happened') src = as_unicode(src) self.edit_recipe(None, src)
def mount(self, device_node_path): d = self.device(device_node_path) mount_options = ['rw', 'noexec', 'nosuid', 'nodev', 'uid=%d'%os.geteuid(), 'gid=%d'%os.getegid()] try: return as_unicode(d.Mount( { 'auth.no_user_interaction':True, 'options':','.join(mount_options) }, dbus_interface=self.FILESYSTEM)) except Exception: # May be already mounted, check mp = node_mountpoint(unicode_type(device_node_path)) if mp is None: raise return mp
def download_ebook(self, url='', cookie_file=None, filename='', save_loc='', add_to_lib=True, tags=[], create_browser=None): if tags: if isinstance(tags, string_or_bytes): tags = tags.split(',') start_ebook_download(Dispatcher(self.downloaded_ebook), self.job_manager, self, cookie_file, url, filename, save_loc, add_to_lib, tags, create_browser) self.status_bar.show_message( _('Downloading') + ' ' + as_unicode(filename or url, errors='replace'), 3000)
def get_droppable_files(self, md): def is_mt_ok(mt): return self.syntax == 'html' and ( mt in OEB_DOCS or mt in OEB_STYLES or mt.startswith('image/') ) if md.hasFormat(CONTAINER_DND_MIMETYPE): for line in as_unicode(bytes(md.data(CONTAINER_DND_MIMETYPE))).splitlines(): mt = current_container().mime_map.get(line, 'application/octet-stream') if is_mt_ok(mt): yield line, mt, True return for qurl in md.urls(): if qurl.isLocalFile() and os.access(qurl.toLocalFile(), os.R_OK): path = qurl.toLocalFile() mt = guess_type(path) if is_mt_ok(mt): yield path, mt, False
def extract_content(self, output_dir): self.log.debug('Extracting content from file...') html = [] images = [] for item in self.toc: iname = as_unicode(item.name) if iname.lower().endswith('html'): self.log.debug('HTML item %s found...' % iname) html.append(iname) self.get_text(item, output_dir) if iname.lower().endswith('png'): self.log.debug('PNG item %s found...' % iname) images.append(iname) self.get_image(item, output_dir) opf_path = self.create_opf(output_dir, html, images) return opf_path
def load_plugin(self, name): if name in self._plugins: return sys.path.insert(0, plugins_loc) try: del sys.modules[name] except KeyError: pass plugin_err = '' try: p = importlib.import_module(name) except Exception as err: p = None try: plugin_err = unicode_type(err) except Exception: plugin_err = as_unicode(native_string_type(err), encoding=preferred_encoding, errors='replace') self._plugins[name] = p, plugin_err sys.path.remove(plugins_loc)
def extract_content(self, output_dir): from calibre.ebooks.pml.pmlconverter import pml_to_html output_dir = os.path.abspath(output_dir) if not os.path.exists(output_dir): os.makedirs(output_dir) pml = '' for i in range(1, self.header_record.num_text_pages + 1): self.log.debug('Extracting text page %i' % i) pml += self.get_text_page(i) title = self.mi.title if not isinstance(title, unicode_type): title = title.decode('utf-8', 'replace') html = '<html><head><title>%s</title></head><body>%s</body></html>' % \ (title, pml_to_html(pml)) with CurrentDir(output_dir): with open('index.html', 'wb') as index: self.log.debug('Writing text to index.html') index.write(html.encode('utf-8')) if not os.path.exists(os.path.join(output_dir, 'images/')): os.makedirs(os.path.join(output_dir, 'images/')) images = [] with CurrentDir(os.path.join(output_dir, 'images/')): for i in range(self.header_record.non_text_offset, len(self.sections)): name, img = self.get_image(i) if name: name = as_unicode(name) images.append(name) with open(name, 'wb') as imgf: self.log.debug('Writing image %s to images/' % name) imgf.write(img) opf_path = self.create_opf(output_dir, images) return opf_path
def mount(self, device_node_path): d = self.device(device_node_path) mount_options = [ 'rw', 'noexec', 'nosuid', 'nodev', 'uid=%d' % os.geteuid(), 'gid=%d' % os.getegid() ] try: return as_unicode( d.Mount( { 'auth.no_user_interaction': True, 'options': ','.join(mount_options) }, dbus_interface=self.FILESYSTEM)) except Exception: # May be already mounted, check mp = node_mountpoint(unicode_type(device_node_path)) if mp is None: raise return mp
def start_ebook_download(callback, job_manager, gui, cookie_file=None, url='', filename='', save_loc='', add_to_lib=True, tags=[], create_browser=None): description = _('Downloading %s') % as_unicode(filename or url, errors='replace') job = ThreadedJob('ebook_download', description, gui_ebook_download, (gui, cookie_file, url, filename, save_loc, add_to_lib, tags, create_browser), {}, callback, max_concurrent_count=2, killable=False) job_manager.run_threaded_job(job)
def key(account_key): return numeric_sort_key(as_unicode(self.accounts[account_key][0]) or '')
def write_apnx(self, mobi_file_path, apnx_path, method=None, page_count=0): ''' If you want a fixed number of pages (such as from a custom column) then pass in a value to page_count, otherwise a count will be estimated using either the fast or accurate algorithm. ''' import uuid apnx_meta = {'guid': str(uuid.uuid4()).replace('-', '')[:8], 'asin': '', 'cdetype': 'EBOK', 'format': 'MOBI_7', 'acr': ''} with lopen(mobi_file_path, 'rb') as mf: ident = PdbHeaderReader(mf).identity() if ident != b'BOOKMOBI': # Check that this is really a MOBI file. raise Exception(_('Not a valid MOBI file. Reports identity of %s') % ident) apnx_meta['acr'] = as_unicode(PdbHeaderReader(mf).name(), errors='replace') # We'll need the PDB name, the MOBI version, and some metadata to make FW 3.4 happy with KF8 files... with lopen(mobi_file_path, 'rb') as mf: mh = MetadataHeader(mf, default_log) if mh.mobi_version == 8: apnx_meta['format'] = 'MOBI_8' else: apnx_meta['format'] = 'MOBI_7' if mh.exth is None or not mh.exth.cdetype: apnx_meta['cdetype'] = 'EBOK' else: apnx_meta['cdetype'] = str(mh.exth.cdetype) if mh.exth is None or not mh.exth.uuid: apnx_meta['asin'] = '' else: apnx_meta['asin'] = str(mh.exth.uuid) # Get the pages depending on the chosen parser pages = [] if page_count: pages = self.get_pages_exact(mobi_file_path, page_count) else: try: if method == 'accurate': pages = self.get_pages_accurate(mobi_file_path) elif method == 'pagebreak': pages = self.get_pages_pagebreak_tag(mobi_file_path) if not pages: pages = self.get_pages_accurate(mobi_file_path) else: raise Exception('%r is not a valid apnx generation method' % method) except: # Fall back to the fast parser if we can't # use the accurate one. Typically this is # due to the file having DRM. pages = self.get_pages_fast(mobi_file_path) if not pages: pages = self.get_pages_fast(mobi_file_path) if not pages: raise Exception(_('Could not generate page mapping.')) # Generate the APNX file from the page mapping. apnx = self.generate_apnx(pages, apnx_meta) # Write the APNX. with lopen(apnx_path, 'wb') as apnxf: apnxf.write(apnx) fsync(apnxf)
def fast_now_strftime(fmt): return as_unicode(time.strftime(fmt), errors='replace')
def book_hash(library_uuid, book_id, fmt, size, mtime): raw = json_dumps((library_uuid, book_id, fmt.upper(), size, mtime, RENDER_VERSION)) return as_unicode(sha1(raw).hexdigest())