def CATALOG_ENTRY(item, item_kind, request_context, updated, catalog_name, ignore_count=False, add_kind=False): id_ = 'calibre:category:' + item.name iid = 'N' + item.name if item.id is not None: iid = 'I' + unicode_type(item.id) iid += ':' + item_kind href = request_context.url_for('/opds/category', category=as_hex_unicode(catalog_name), which=as_hex_unicode(iid)) link = NAVLINK(href=href) if ignore_count: count = '' else: count = ngettext('one book', '{} books', item.count).format(item.count) if item.use_sort_as_name: name = item.sort else: name = item.name return E.entry(TITLE(name + ('' if not add_kind else ' (%s)' % item_kind)), ID(id_), UPDATED(updated), E.content(count, type='text'), link)
def launch_worker(self, gui=False, redirect_output=None, job_name=None): start = time.monotonic() id = next(self.launched_worker_counter) fd, rfile = tempfile.mkstemp(prefix='ipc_result_%d_%d_' % (self.id, id), dir=base_dir(), suffix='.pickle') os.close(fd) if redirect_output is None: redirect_output = not gui env = { 'CALIBRE_WORKER_ADDRESS': environ_item(as_hex_unicode(msgpack_dumps(self.address))), 'CALIBRE_WORKER_KEY': environ_item(as_hex_unicode(self.auth_key)), 'CALIBRE_WORKER_RESULT': environ_item(as_hex_unicode(rfile)), } cw = self.do_launch(env, gui, redirect_output, rfile, job_name=job_name) if isinstance(cw, string_or_bytes): raise CriticalError('Failed to launch worker process:\n' + force_unicode(cw)) if DEBUG: print( 'Worker Launch took: {:.2f} seconds'.format(time.monotonic() - start)) return cw
def CATALOG_GROUP_ENTRY(item, category, request_context, updated): id_ = 'calibre:category-group:' + category + ':' + item.text iid = item.text link = NAVLINK( href=request_context.url_for('/opds/categorygroup', category=as_hex_unicode(category), which=as_hex_unicode(iid))) return E.entry( TITLE(item.text), ID(id_), UPDATED(updated), E.content(ngettext('one item', '{} items', item.count).format(item.count), type='text'), link)
def create_worker(env, priority='normal', cwd=None, func='main'): from calibre.utils.ipc.server import create_listener auth_key = os.urandom(32) address, listener = create_listener(auth_key) env = dict(env) env.update({ 'CALIBRE_WORKER_ADDRESS': environ_item(as_hex_unicode(msgpack_dumps(address))), 'CALIBRE_WORKER_KEY': environ_item(as_hex_unicode(auth_key)), 'CALIBRE_SIMPLE_WORKER': environ_item('calibre.utils.ipc.simple_worker:%s' % func), }) w = Worker(env) w(cwd=cwd, priority=priority) return listener, w
def create_worker(env, priority='normal', cwd=None, func='main'): from calibre.utils.ipc.server import create_listener auth_key = os.urandom(32) address, listener = create_listener(auth_key) env = dict(env) env.update({ 'CALIBRE_WORKER_ADDRESS': environ_item(as_hex_unicode(msgpack_dumps(address))), 'CALIBRE_WORKER_KEY': environ_item(as_hex_unicode(auth_key)), 'CALIBRE_SIMPLE_WORKER': environ_item('calibre.utils.ipc.simple_worker:%s' % func), }) w = Worker(env) w(cwd=cwd, priority=priority) return listener, w
def env(self): env = os.environ.copy() env[native_string_type('CALIBRE_WORKER')] = environ_item('1') td = as_hex_unicode(msgpack_dumps(base_dir())) env[native_string_type('CALIBRE_WORKER_TEMP_DIR')] = environ_item(td) env.update(self._env) return env
def set_email_settings(self, to_set): from_ = unicode_type(self.email_from.text()).strip() if to_set and not from_: error_dialog(self, _('Bad configuration'), _('You must set the From email address')).exec_() return False username = unicode_type(self.relay_username.text()).strip() password = unicode_type(self.relay_password.text()).strip() host = unicode_type(self.relay_host.text()).strip() enc_method = ('TLS' if self.relay_tls.isChecked() else 'SSL' if self.relay_ssl.isChecked() else 'NONE') if host: # Validate input if ((username and not password) or (not username and password)): error_dialog(self, _('Bad configuration'), _('You must either set both the username <b>and</b> password for ' 'the mail server or no username and no password at all.')).exec_() return False if not (username and password) and not question_dialog( self, _('Are you sure?'), _('No username and password set for mailserver. Most ' ' mailservers need a username and password. Are you sure?')): return False conf = smtp_prefs() conf.set('from_', from_) conf.set('relay_host', host if host else None) conf.set('relay_port', self.relay_port.value()) conf.set('relay_username', username if username else None) conf.set('relay_password', as_hex_unicode(password)) conf.set('encryption', enc_method) return True
def windows_repair(library_path=None): import subprocess from calibre.utils.serialize import json_dumps, json_loads from polyglot.binary import as_hex_unicode, from_hex_bytes if library_path: library_path = as_hex_unicode(json_dumps(library_path)) winutil.prepare_for_restart() os.environ['CALIBRE_REPAIR_CORRUPTED_DB'] = environ_item(library_path) subprocess.Popen([sys.executable]) else: try: app = Application([]) from calibre.gui2.dialogs.restore_library import repair_library_at library_path = json_loads( from_hex_bytes(os.environ.pop('CALIBRE_REPAIR_CORRUPTED_DB'))) done = repair_library_at(library_path, wait_time=4) except Exception: done = False error_dialog( None, _('Failed to repair library'), _('Could not repair library. Click "Show details" for more information.' ), det_msg=traceback.format_exc(), show=True) if done: subprocess.Popen([sys.executable]) app.quit()
def env(self): if ispy3: env = os.environ.copy() else: # We use this inefficient method of copying the environment variables # because of non ascii env vars on windows. See https://bugs.launchpad.net/bugs/811191 env = {} for key in os.environ: try: val = os.environ[key] if isinstance(val, unicode_type): # On windows subprocess cannot handle unicode env vars try: val = val.encode(filesystem_encoding) except ValueError: val = val.encode('utf-8') if isinstance(key, unicode_type): key = key.encode('ascii') env[key] = val except: pass env[native_string_type('CALIBRE_WORKER')] = environ_item('1') td = as_hex_unicode(msgpack_dumps(base_dir())) env[native_string_type('CALIBRE_WORKER_TEMP_DIR')] = environ_item(td) env.update(self._env) return env
def set_email_settings(self, to_set): from_ = unicode_type(self.email_from.text()).strip() if to_set and not from_: error_dialog(self, _('Bad configuration'), _('You must set the From email address')).exec_() return False username = unicode_type(self.relay_username.text()).strip() password = unicode_type(self.relay_password.text()).strip() host = unicode_type(self.relay_host.text()).strip() enc_method = ('TLS' if self.relay_tls.isChecked() else 'SSL' if self.relay_ssl.isChecked() else 'NONE') if host: # Validate input if ((username and not password) or (not username and password)): error_dialog(self, _('Bad configuration'), _('You must either set both the username <b>and</b> password for ' 'the mail server or no username and no password at all.')).exec_() return False if not (username and password) and not question_dialog( self, _('Are you sure?'), _('No username and password set for mailserver. Most ' ' mailservers need a username and password. Are you sure?')): return False conf = smtp_prefs() conf.set('from_', from_) conf.set('relay_host', host if host else None) conf.set('relay_port', self.relay_port.value()) conf.set('relay_username', username if username else None) conf.set('relay_password', as_hex_unicode(password)) conf.set('encryption', enc_method) return True
def env(self): if ispy3: env = os.environ.copy() else: # We use this inefficient method of copying the environment variables # because of non ascii env vars on windows. See https://bugs.launchpad.net/bugs/811191 env = {} for key in os.environ: try: val = os.environ[key] if isinstance(val, unicode_type): # On windows subprocess cannot handle unicode env vars try: val = val.encode(filesystem_encoding) except ValueError: val = val.encode('utf-8') if isinstance(key, unicode_type): key = key.encode('ascii') env[key] = val except: pass env[native_string_type('CALIBRE_WORKER')] = environ_item('1') td = as_hex_unicode(msgpack_dumps(base_dir())) env[native_string_type('CALIBRE_WORKER_TEMP_DIR')] = environ_item(td) env.update(self._env) return env
def __call__(self, redirect_output=True, cwd=None, priority=None): ''' If redirect_output is True, output from the child is redirected to a file on disk and this method returns the path to that file. ''' exe = self.gui_executable if self.gui else self.executable env = self.env try: origwd = cwd or os.path.abspath(getcwd()) except EnvironmentError: # cwd no longer exists origwd = cwd or os.path.expanduser('~') env[native_string_type('ORIGWD')] = environ_item( as_hex_unicode(msgpack_dumps(origwd))) _cwd = cwd if priority is None: priority = prefs['worker_process_priority'] cmd = [exe] if isinstance(exe, string_or_bytes) else exe args = { 'env': env, 'cwd': _cwd, } if iswindows: priority = { 'high': subprocess.HIGH_PRIORITY_CLASS, 'normal': subprocess.NORMAL_PRIORITY_CLASS, 'low': subprocess.IDLE_PRIORITY_CLASS }[priority] args['creationflags'] = subprocess.CREATE_NO_WINDOW | priority else: niceness = { 'normal': 0, 'low': 10, 'high': 20, }[priority] args['env']['CALIBRE_WORKER_NICENESS'] = str(niceness) ret = None if redirect_output: self._file = PersistentTemporaryFile('_worker_redirect.log') args['stdout'] = self._file._fd args['stderr'] = subprocess.STDOUT if iswindows: args['stdin'] = subprocess.PIPE ret = self._file.name if iswindows and 'stdin' not in args: # On windows when using the pythonw interpreter, # stdout, stderr and stdin may not be valid args['stdin'] = subprocess.PIPE args['stdout'] = windows_null_file args['stderr'] = subprocess.STDOUT self.child = subprocess.Popen(cmd, **args) if 'stdin' in args: self.child.stdin.close() self.log_path = ret return ret
def NAVCATALOG_ENTRY(url_for, updated, title, description, query): href = url_for('/opds/navcatalog', which=as_hex_unicode(query)) id_ = 'calibre-navcatalog:' + hashlib.sha1(as_bytes(href)).hexdigest() return E.entry( TITLE(title), ID(id_), UPDATED(updated), E.content(description, type='text'), NAVLINK(href=href) )
def NAVCATALOG_ENTRY(url_for, updated, title, description, query): href = url_for('/opds/navcatalog', which=as_hex_unicode(query)) id_ = 'calibre-navcatalog:' + hashlib.sha1(as_bytes(href)).hexdigest() return E.entry( TITLE(title), ID(id_), UPDATED(updated), E.content(description, type='text'), NAVLINK(href=href) )
def create_file_copy(ctx, rd, prefix, library_id, book_id, ext, mtime, copy_func, extra_etag_data=''): ''' We cannot copy files directly from the library folder to the output socket, as this can potentially lock the library for an extended period. So instead we copy out the data from the library folder into a temp folder. We make sure to only do this copy once, using the previous copy, if there have been no changes to the data for the file since the last copy. ''' global rename_counter # Avoid too many items in a single directory for performance base = os.path.join(rd.tdir, 'fcache', (('%x' % book_id)[-3:])) if iswindows: base = '\\\\?\\' + os.path.abspath(base) # Ensure fname is not too long for windows' API bname = '%s-%s-%x.%s' % (prefix, library_id, book_id, ext) if '\\' in bname or '/' in bname: raise ValueError('File components must not contain path separators') fname = os.path.join(base, bname) used_cache = 'no' with lock: previous_mtime = mtimes.get(bname) if previous_mtime is None or previous_mtime < mtime: if previous_mtime is not None: # File exists and may be open, so we cannot change its # contents, as that would lead to corrupted downloads in any # clients that are currently downloading the file. if iswindows: # On windows in order to re-use bname, we have to rename it # before deleting it rename_counter += 1 dname = os.path.join(base, '_%x' % rename_counter) atomic_rename(fname, dname) os.remove(dname) else: os.remove(fname) ans = open_for_write(fname) mtimes[bname] = mtime copy_func(ans) ans.seek(0) else: try: ans = share_open(fname, 'rb') used_cache = 'yes' except EnvironmentError as err: if err.errno != errno.ENOENT: raise ans = open_for_write(fname) mtimes[bname] = mtime copy_func(ans) ans.seek(0) if ctx.testing: rd.outheaders['Used-Cache'] = used_cache rd.outheaders['Tempfile'] = as_hex_unicode(fname) return rd.filesystem_file_with_custom_etag(ans, prefix, library_id, book_id, mtime, extra_etag_data)
def CATALOG_GROUP_ENTRY(item, category, request_context, updated): id_ = 'calibre:category-group:'+category+':'+item.text iid = item.text link = NAVLINK(href=request_context.url_for('/opds/categorygroup', category=as_hex_unicode(category), which=as_hex_unicode(iid))) return E.entry( TITLE(item.text), ID(id_), UPDATED(updated), E.content(ngettext('one item', '{} items', item.count).format(item.count), type='text'), link )
def create_file_copy(ctx, rd, prefix, library_id, book_id, ext, mtime, copy_func, extra_etag_data=''): ''' We cannot copy files directly from the library folder to the output socket, as this can potentially lock the library for an extended period. So instead we copy out the data from the library folder into a temp folder. We make sure to only do this copy once, using the previous copy, if there have been no changes to the data for the file since the last copy. ''' global rename_counter # Avoid too many items in a single directory for performance base = os.path.join(rd.tdir, 'fcache', (('%x' % book_id)[-3:])) if iswindows: base = '\\\\?\\' + os.path.abspath(base) # Ensure fname is not too long for windows' API bname = '%s-%s-%x.%s' % (prefix, library_id, book_id, ext) if '\\' in bname or '/' in bname: raise ValueError('File components must not contain path separators') fname = os.path.join(base, bname) used_cache = 'no' with lock: previous_mtime = mtimes.get(bname) if previous_mtime is None or previous_mtime < mtime: if previous_mtime is not None: # File exists and may be open, so we cannot change its # contents, as that would lead to corrupted downloads in any # clients that are currently downloading the file. if iswindows: # On windows in order to re-use bname, we have to rename it # before deleting it rename_counter += 1 dname = os.path.join(base, '_%x' % rename_counter) atomic_rename(fname, dname) os.remove(dname) else: os.remove(fname) ans = open_for_write(fname) mtimes[bname] = mtime copy_func(ans) ans.seek(0) else: try: ans = share_open(fname, 'rb') used_cache = 'yes' except EnvironmentError as err: if err.errno != errno.ENOENT: raise ans = open_for_write(fname) mtimes[bname] = mtime copy_func(ans) ans.seek(0) if ctx.testing: rd.outheaders['Used-Cache'] = used_cache rd.outheaders['Tempfile'] = as_hex_unicode(fname) return rd.filesystem_file_with_custom_etag(ans, prefix, library_id, book_id, mtime, extra_etag_data)
def opds_categorygroup(ctx, rd, category, which): try: offset = int(rd.query.get('offset', 0)) except Exception: raise HTTPNotFound('Not found') if not which or not category: raise HTTPNotFound('Not found') rc = RequestContext(ctx, rd) categories = rc.get_categories() page_url = rc.url_for('/opds/categorygroup', category=category, which=which) category = from_hex_unicode(category) if category not in categories: raise HTTPNotFound('Category %r not found' % which) category_meta = rc.db.field_metadata meta = category_meta.get(category, {}) category_name = meta.get('name', which) which = from_hex_unicode(which) feed_title = default_feed_title + ' :: ' + (_('By {0} :: {1}').format( category_name, which)) owhich = as_hex_unicode('N' + which) up_url = rc.url_for('/opds/navcatalog', which=owhich) items = categories[category] def belongs(x, which): return getattr(x, 'sort', x.name).lower().startswith(which.lower()) items = [x for x in items if belongs(x, which)] if not items: raise HTTPNotFound('No items in group %r:%r' % (category, which)) updated = rc.last_modified() id_ = 'calibre-category-group-feed:' + category + ':' + which max_items = rc.opts.max_opds_items offsets = Offsets(offset, max_items, len(items)) items = list(items)[offsets.offset:offsets.offset + max_items] rc.outheaders['Last-Modified'] = http_date(timestampfromdt(updated)) return CategoryFeed(items, category, id_, updated, rc, offsets, page_url, up_url, title=feed_title).root
def __init__(self, user_credentials=None, prefer_basic_auth=False, realm='calibre', max_age_seconds=MAX_AGE_SECONDS, log=None, ban_time_in_minutes=0, ban_after=5): self.user_credentials, self.prefer_basic_auth = user_credentials, prefer_basic_auth self.ban_list = BanList(ban_time_in_minutes=ban_time_in_minutes, max_failures_before_ban=ban_after) self.log = log self.secret = as_hex_unicode(os.urandom(random.randint(20, 30))) self.max_age_seconds = max_age_seconds self.key_order = '{%d}:{%d}:{%d}' % random.choice(tuple(permutations((0,1,2)))) self.realm = realm if '"' in realm: raise ValueError('Double-quotes are not allowed in the authentication realm')
def launch_worker(self, gui=False, redirect_output=None, job_name=None): start = time.time() with self._worker_launch_lock: self.launched_worker_count += 1 id = self.launched_worker_count fd, rfile = tempfile.mkstemp(prefix=u'ipc_result_%d_%d_'%(self.id, id), dir=base_dir(), suffix=u'.pickle') os.close(fd) if redirect_output is None: redirect_output = not gui env = { 'CALIBRE_WORKER_ADDRESS' : environ_item(as_hex_unicode(msgpack_dumps(self.address))), 'CALIBRE_WORKER_KEY' : environ_item(as_hex_unicode(self.auth_key)), 'CALIBRE_WORKER_RESULT' : environ_item(as_hex_unicode(rfile)), } cw = self.do_launch(env, gui, redirect_output, rfile, job_name=job_name) if isinstance(cw, string_or_bytes): raise CriticalError('Failed to launch worker process:\n'+cw) if DEBUG: print('Worker Launch took:', time.time() - start) return cw
def update_found(self, calibre_version, number_of_plugin_updates, force=False, no_show_popup=False): self.last_newest_calibre_version = calibre_version has_calibre_update = calibre_version != NO_CALIBRE_UPDATE and calibre_version[ 0] > 0 has_plugin_updates = number_of_plugin_updates > 0 self.plugin_update_found(number_of_plugin_updates) version_url = as_hex_unicode( msgpack_dumps((calibre_version, number_of_plugin_updates))) calibre_version = '.'.join(map(str, calibre_version)) if not has_calibre_update and not has_plugin_updates: self.status_bar.update_label.setVisible(False) return if has_calibre_update: plt = '' if has_plugin_updates: plt = ngettext( ' and one plugin update', ' and {} plugin updates', number_of_plugin_updates).format(number_of_plugin_updates) msg = ('<span style="color:green; font-weight: bold">%s: ' '<a href="update:%s">%s%s</a></span>') % ( _('Update found'), version_url, calibre_version, plt) else: plt = ngettext('plugin update available', 'plugin updates available', number_of_plugin_updates) msg = ('<a href="update:%s">%d %s</a>') % ( version_url, number_of_plugin_updates, plt) self.status_bar.update_label.setText(msg) self.status_bar.update_label.setVisible(True) if has_calibre_update: if (force or (config.get('new_version_notification') and not is_version_notified(calibre_version))): if not no_show_popup: self._update_notification__ = UpdateNotification( calibre_version, number_of_plugin_updates, parent=self) self._update_notification__.show() elif has_plugin_updates: if force: from calibre.gui2.dialogs.plugin_updater import ( PluginUpdaterDialog, FILTER_UPDATE_AVAILABLE) d = PluginUpdaterDialog(self, initial_filter=FILTER_UPDATE_AVAILABLE) d.exec() if d.do_restart: self.quit(restart=True)
def synthesize_nonce(key_order, realm, secret, timestamp=None): ''' Create a nonce. Can be used for either digest or cookie based auth. The nonce is of the form timestamp:hash with hash being a hash of the timestamp, server secret and realm. This allows the timestamp to be validated and stale nonce's to be rejected. ''' if timestamp is None: global nonce_counter with nonce_counter_lock: nonce_counter = (nonce_counter + 1) % 65535 # The resolution of monotonic() on windows is very low (10s of # milliseconds) so to ensure nonce values are not re-used, we have a # global counter timestamp = as_hex_unicode(struct.pack(b'!dH', float(monotonic()), nonce_counter)) h = sha256_hex(key_order.format(timestamp, realm, secret)) nonce = ':'.join((timestamp, h)) return nonce
def export_dir(self, path, dir_key): pkey = as_hex_unicode(dir_key) self.metadata[dir_key] = files = [] for dirpath, dirnames, filenames in os.walk(path): for fname in filenames: fpath = os.path.join(dirpath, fname) rpath = os.path.relpath(fpath, path).replace(os.sep, '/') key = '%s:%s' % (pkey, rpath) try: with lopen(fpath, 'rb') as f: self.add_file(f, key) except EnvironmentError: if not iswindows: raise time.sleep(1) with lopen(fpath, 'rb') as f: self.add_file(f, key) files.append((key, rpath))
def export_dir(self, path, dir_key): pkey = as_hex_unicode(dir_key) self.metadata[dir_key] = files = [] for dirpath, dirnames, filenames in os.walk(path): for fname in filenames: fpath = os.path.join(dirpath, fname) rpath = os.path.relpath(fpath, path).replace(os.sep, '/') key = '%s:%s' % (pkey, rpath) try: with lopen(fpath, 'rb') as f: self.add_file(f, key) except EnvironmentError: if not iswindows: raise time.sleep(1) with lopen(fpath, 'rb') as f: self.add_file(f, key) files.append((key, rpath))
def set_display_name(name, item): if tprefs['file_list_shows_full_pathname']: text = name else: if name in processed: # We have an exact duplicate (can happen if there are # duplicates in the spine) item.setText(0, processed[name].text(0)) item.setText(1, processed[name].text(1)) return parts = name.split('/') text = parts.pop() while text in seen and parts: text = parts.pop() + '/' + text seen[text] = item item.setText(0, text) item.setText(1, as_hex_unicode(numeric_sort_key(text)))
def set_display_name(name, item): if tprefs['file_list_shows_full_pathname']: text = name else: if name in processed: # We have an exact duplicate (can happen if there are # duplicates in the spine) item.setText(0, processed[name].text(0)) item.setText(1, processed[name].text(1)) return parts = name.split('/') text = parts.pop() while text in seen and parts: text = parts.pop() + '/' + text seen[text] = item item.setText(0, text) item.setText(1, as_hex_unicode(numeric_sort_key(text)))
def do_launch(self, gui, redirect_output, rfile, job_name=None): a, b = Pipe() with a: env = { 'CALIBRE_WORKER_FD': str(a.fileno()), 'CALIBRE_WORKER_RESULT': environ_item(as_hex_unicode(rfile)) } w = Worker(env, gui=gui, job_name=job_name) try: w(pass_fds=(a.fileno(), ), redirect_output=redirect_output) except BaseException: try: w.kill() except: pass b.close() import traceback return traceback.format_exc() return ConnectedWorker(w, b, rfile)
def opds_categorygroup(ctx, rd, category, which): try: offset = int(rd.query.get('offset', 0)) except Exception: raise HTTPNotFound('Not found') if not which or not category: raise HTTPNotFound('Not found') rc = RequestContext(ctx, rd) categories = rc.get_categories() page_url = rc.url_for('/opds/categorygroup', category=category, which=which) category = from_hex_unicode(category) if category not in categories: raise HTTPNotFound('Category %r not found'%which) category_meta = rc.db.field_metadata meta = category_meta.get(category, {}) category_name = meta.get('name', which) which = from_hex_unicode(which) feed_title = default_feed_title + ' :: ' + (_('By {0} :: {1}').format(category_name, which)) owhich = as_hex_unicode('N'+which) up_url = rc.url_for('/opds/navcatalog', which=owhich) items = categories[category] def belongs(x, which): return getattr(x, 'sort', x.name).lower().startswith(which.lower()) items = [x for x in items if belongs(x, which)] if not items: raise HTTPNotFound('No items in group %r:%r'%(category, which)) updated = rc.last_modified() id_ = 'calibre-category-group-feed:'+category+':'+which max_items = rc.opts.max_opds_items offsets = Offsets(offset, max_items, len(items)) items = list(items)[offsets.offset:offsets.offset+max_items] rc.outheaders['Last-Modified'] = http_date(timestampfromdt(updated)) return CategoryFeed(items, category, id_, updated, rc, offsets, page_url, up_url, title=feed_title).root
def windows_repair(library_path=None): import subprocess from calibre.utils.serialize import json_dumps, json_loads from polyglot.binary import as_hex_unicode, from_hex_bytes if library_path: library_path = as_hex_unicode(json_dumps(library_path)) winutil.prepare_for_restart() os.environ['CALIBRE_REPAIR_CORRUPTED_DB'] = environ_item(library_path) subprocess.Popen([sys.executable]) else: try: app = Application([]) from calibre.gui2.dialogs.restore_library import repair_library_at library_path = json_loads(from_hex_bytes(os.environ.pop('CALIBRE_REPAIR_CORRUPTED_DB'))) done = repair_library_at(library_path, wait_time=4) except Exception: done = False error_dialog(None, _('Failed to repair library'), _( 'Could not repair library. Click "Show details" for more information.'), det_msg=traceback.format_exc(), show=True) if done: subprocess.Popen([sys.executable]) app.quit()
def CATALOG_ENTRY(item, item_kind, request_context, updated, catalog_name, ignore_count=False, add_kind=False): id_ = 'calibre:category:'+item.name iid = 'N' + item.name if item.id is not None: iid = 'I' + str(item.id) iid += ':'+item_kind href = request_context.url_for('/opds/category', category=as_hex_unicode(catalog_name), which=as_hex_unicode(iid)) link = NAVLINK(href=href) if ignore_count: count = '' else: count = ngettext('one book', '{} books', item.count).format(item.count) if item.use_sort_as_name: name = item.sort else: name = item.name return E.entry( TITLE(name + ('' if not add_kind else ' (%s)'%item_kind)), ID(id_), UPDATED(updated), E.content(count, type='text'), link )
def signature(self): args = (self.color, self.conditions) sig = json.dumps(args, ensure_ascii=False) return self.SIGNATURE + as_hex_unicode(sig)
def __call__(self, redirect_output=True, cwd=None, priority=None): ''' If redirect_output is True, output from the child is redirected to a file on disk and this method returns the path to that file. ''' exe = self.gui_executable if self.gui else self.executable env = self.env try: origwd = cwd or os.path.abspath(os.getcwdu()) except EnvironmentError: # cwd no longer exists origwd = cwd or os.path.expanduser(u'~') env[native_string_type('ORIGWD')] = environ_item(as_hex_unicode(msgpack_dumps(origwd))) _cwd = cwd if priority is None: priority = prefs['worker_process_priority'] cmd = [exe] if isinstance(exe, string_or_bytes) else exe args = { 'env' : env, 'cwd' : _cwd, } if iswindows: priority = { 'high' : win32process.HIGH_PRIORITY_CLASS, 'normal' : win32process.NORMAL_PRIORITY_CLASS, 'low' : win32process.IDLE_PRIORITY_CLASS}[priority] args['creationflags'] = win32process.CREATE_NO_WINDOW|priority else: niceness = { 'normal' : 0, 'low' : 10, 'high' : 20, }[priority] args['preexec_fn'] = partial(renice, niceness) ret = None if redirect_output: self._file = PersistentTemporaryFile('_worker_redirect.log') args['stdout'] = self._file._fd args['stderr'] = subprocess.STDOUT if iswindows: args['stdin'] = subprocess.PIPE ret = self._file.name if iswindows and 'stdin' not in args: # On windows when using the pythonw interpreter, # stdout, stderr and stdin may not be valid args['stdin'] = subprocess.PIPE args['stdout'] = windows_null_file args['stderr'] = subprocess.STDOUT if not iswindows: # Close inherited file descriptors in worker # On windows, this is done in the worker process # itself args['close_fds'] = True self.child = subprocess.Popen(cmd, **args) if 'stdin' in args: self.child.stdin.close() self.log_path = ret return ret
def signature(self): args = (self.color, self.conditions) sig = json.dumps(args, ensure_ascii=False) return self.SIGNATURE + as_hex_unicode(sig)
def action(main, **keys): keys['type'] = main return 'action:' + as_hex_unicode(json_dumps(keys))
def item_data(field_name, value, book_id): return as_hex_unicode(json_dumps((field_name, value, book_id)))
def search_href(search_term, value): search = '%s:"=%s"' % (search_term, value.replace('"', '\\"')) return prepare_string_for_xml('search:' + as_hex_unicode(search.encode('utf-8')), True)