def save_book(ids, dpath, plugboards, template_functions, path, recs, notification=lambda x, y: x): from calibre.library.save_to_disk import config, save_serialized_to_disk from calibre.customize.ui import apply_null_metadata from calibre.utils.formatter_functions import load_user_template_functions load_user_template_functions('', template_functions) opts = config().parse() for name in recs: setattr(opts, name, recs[name]) results = [] def callback(id, title, failed, tb): results.append((id, title, not failed, tb)) notification((id, title, not failed, tb)) return True data_ = json.loads(open(dpath, 'rb').read().decode('utf-8')) data = {} for k, v in data_.iteritems(): data[int(k)] = v with apply_null_metadata: save_serialized_to_disk(ids, data, plugboards, path, opts, callback) return results
def save_book(ids, dpath, plugboards, template_functions, path, recs, notification=lambda x,y:x): from calibre.library.save_to_disk import config, save_serialized_to_disk from calibre.customize.ui import apply_null_metadata from calibre.utils.formatter_functions import load_user_template_functions load_user_template_functions('', template_functions) opts = config().parse() for name in recs: setattr(opts, name, recs[name]) results = [] def callback(id, title, failed, tb): results.append((id, title, not failed, tb)) notification((id, title, not failed, tb)) return True data_ = json.loads(open(dpath, 'rb').read().decode('utf-8')) data = {} for k, v in data_.iteritems(): data[int(k)] = v with apply_null_metadata: save_serialized_to_disk(ids, data, plugboards, path, opts, callback) return results
def save_to_disk(self, checked, single_dir=False, single_format=None, rows=None, write_opf=None, save_cover=None): if rows is None: rows = self.gui.current_view().selectionModel().selectedRows() if not rows or len(rows) == 0: return error_dialog(self.gui, _('Cannot save to disk'), _('No books selected'), show=True) path = choose_dir(self.gui, 'save to disk dialog', _('Choose destination directory')) if not path: return dpath = os.path.abspath(path).replace('/', os.sep) + os.sep lpath = self.gui.library_view.model().db.library_path.replace( '/', os.sep) + os.sep if dpath.startswith(lpath): return error_dialog( self.gui, _('Not allowed'), _('You are trying to save files into the calibre ' 'library. This can cause corruption of your ' 'library. Save to disk is meant to export ' 'files from your calibre library elsewhere.'), show=True) if self.gui.current_view() is self.gui.library_view: from calibre.gui2.save import Saver from calibre.library.save_to_disk import config opts = config().parse() if single_format is not None: opts.formats = single_format # Special case for Kindle annotation files if single_format.lower() in ['mbp', 'pdr', 'tan']: opts.to_lowercase = False opts.save_cover = False opts.write_opf = False opts.template = opts.send_template opts.single_dir = single_dir if write_opf is not None: opts.write_opf = write_opf if save_cover is not None: opts.save_cover = save_cover book_ids = set(map(self.gui.library_view.model().id, rows)) Saver(book_ids, self.gui.current_db, opts, path, parent=self.gui, pool=self.gui.spare_pool()) else: paths = self.gui.current_view().model().paths(rows) self.gui.device_manager.save_books(Dispatcher(self.books_saved), paths, path)
def option_parser(get_parser, args): parser = get_parser( _( '''\ %prog export [options] ids Export the books specified by ids (a comma separated list) to the filesystem. The export operation saves all formats of the book, its cover and metadata (in an opf file). You can get id numbers from the search command. ''' ) ) parser.add_option( '--all', default=False, action='store_true', help=_('Export all books in database, ignoring the list of ids.') ) parser.add_option( '--to-dir', default='.', help=( _('Export books to the specified directory. Default is') + ' %default' ) ) parser.add_option( '--single-dir', default=False, action='store_true', help=_('Export all books into a single directory') ) c = config() for pref in ['asciiize', 'update_metadata', 'write_opf', 'save_cover']: opt = c.get_option(pref) switch = '--dont-' + pref.replace('_', '-') parser.add_option( switch, default=True, action='store_false', help=opt.help + ' ' + _('Specifying this switch will turn ' 'this behavior off.'), dest=pref ) for pref in ['timefmt', 'template', 'formats']: opt = c.get_option(pref) switch = '--' + pref parser.add_option(switch, default=opt.default, help=opt.help, dest=pref) for pref in ('replace_whitespace', 'to_lowercase'): opt = c.get_option(pref) switch = '--' + pref.replace('_', '-') parser.add_option(switch, default=False, action='store_true', help=opt.help) return parser
def option_parser(get_parser, args): parser = get_parser( _('''\ %prog export [options] ids Export the books specified by ids (a comma separated list) to the filesystem. The export operation saves all formats of the book, its cover and metadata (in an opf file). You can get id numbers from the search command. ''')) parser.add_option( '--all', default=False, action='store_true', help=_('Export all books in database, ignoring the list of ids.')) parser.add_option( '--to-dir', default='.', help=(_('Export books to the specified folder. Default is') + ' %default')) parser.add_option('--single-dir', default=False, action='store_true', help=_('Export all books into a single folder')) parser.add_option('--progress', default=False, action='store_true', help=_('Report progress')) c = config() for pref in ['asciiize', 'update_metadata', 'write_opf', 'save_cover']: opt = c.get_option(pref) switch = '--dont-' + pref.replace('_', '-') parser.add_option(switch, default=True, action='store_false', help=opt.help + ' ' + _('Specifying this switch will turn ' 'this behavior off.'), dest=pref) for pref in ['timefmt', 'template', 'formats']: opt = c.get_option(pref) switch = '--' + pref parser.add_option(switch, default=opt.default, help=opt.help, dest=pref) for pref in ('replace_whitespace', 'to_lowercase'): opt = c.get_option(pref) switch = '--' + pref.replace('_', '-') parser.add_option(switch, default=False, action='store_true', help=opt.help) return parser
def genesis(self, gui): self.gui = gui self.proxy = ConfigProxy(config()) r = self.register for x in ('asciiize', 'update_metadata', 'save_cover', 'write_opf', 'replace_whitespace', 'to_lowercase', 'formats', 'timefmt'): r(x, self.proxy) r('show_files_after_save', gprefs) self.save_template.changed_signal.connect(self.changed_signal.emit)
def get_filename(self, book_id, mi): ''' Obtain a filename from the save_to_disk template :param book_id: The book identifier :param mi: The book metadata ''' from os.path import join from calibre.library.save_to_disk import get_components, config from calibre import sanitize_file_name_unicode from calibre.utils.filenames import ascii_filename opts = config().parse() components = get_components(opts.template, mi, book_id, opts.timefmt, sanitize_func=(ascii_filename if opts.asciiize else sanitize_file_name_unicode), to_lowercase=opts.to_lowercase, replace_whitespace=opts.replace_whitespace) base_path = join(*components) return '%s.pdf' % base_path
def save_to_disk(self, checked, single_dir=False, single_format=None, rows=None, write_opf=None, save_cover=None): if rows is None: rows = self.gui.current_view().selectionModel().selectedRows() if not rows or len(rows) == 0: return error_dialog(self.gui, _('Cannot save to disk'), _('No books selected'), show=True) path = choose_dir(self.gui, 'save to disk dialog', _('Choose destination directory')) if not path: return dpath = os.path.abspath(path).replace('/', os.sep)+os.sep lpath = self.gui.library_view.model().db.library_path.replace('/', os.sep)+os.sep if dpath.startswith(lpath): return error_dialog(self.gui, _('Not allowed'), _('You are trying to save files into the calibre ' 'library. This can cause corruption of your ' 'library. Save to disk is meant to export ' 'files from your calibre library elsewhere.'), show=True) if self.gui.current_view() is self.gui.library_view: from calibre.gui2.add import Saver from calibre.library.save_to_disk import config opts = config().parse() if single_format is not None: opts.formats = single_format # Special case for Kindle annotation files if single_format.lower() in ['mbp','pdr','tan']: opts.to_lowercase = False opts.save_cover = False opts.write_opf = False opts.template = opts.send_template opts.single_dir = single_dir if write_opf is not None: opts.write_opf = write_opf if save_cover is not None: opts.save_cover = save_cover self._saver = Saver(self.gui, self.gui.library_view.model().db, Dispatcher(self._books_saved), rows, path, opts, spare_server=self.gui.spare_server) else: paths = self.gui.current_view().model().paths(rows) self.gui.device_manager.save_books( Dispatcher(self.books_saved), paths, path)
def genesis(self, gui): self.gui = gui self.proxy = ConfigProxy(config()) r = self.register for x in ('send_timefmt',): r(x, self.proxy) choices = [(_('Manual management'), 'manual'), (_('Only on send'), 'on_send'), (_('Automatic management'), 'on_connect')] r('manage_device_metadata', prefs, choices=choices) if gui.device_manager.is_device_connected: self.opt_manage_device_metadata.setEnabled(False) self.opt_manage_device_metadata.setToolTip( _('Cannot change metadata management while a device is connected')) self.mm_label.setText(_('Metadata management (disabled while ' 'device connected)')) self.send_template.changed_signal.connect(self.changed_signal.emit)
def genesis(self, gui): self.gui = gui self.proxy = ConfigProxy(config()) r = self.register for x in ('send_timefmt',): r(x, self.proxy) choices = [(_('Manual management'), 'manual'), (_('Only on send'), 'on_send'), (_('Automatic management'), 'on_connect')] r('manage_device_metadata', prefs, choices=choices) if gui.device_manager.is_device_connected: self.opt_manage_device_metadata.setEnabled(False) self.opt_manage_device_metadata.setToolTip( _('Cannot change metadata management while a device is connected')) self.mm_label.setText('Metadata management (disabled while ' 'device connected)') self.send_template.changed_signal.connect(self.changed_signal.emit)
def get_filename(self, book_id, mi): ''' Obtain a filename from the save_to_disk template :param book_id: The book identifier :param mi: The book metadata ''' from os.path import join from calibre.library.save_to_disk import get_components, config from calibre import sanitize_file_name_unicode from calibre.utils.filenames import ascii_filename opts = config().parse() components = get_components( opts.template, mi, book_id, opts.timefmt, sanitize_func=(ascii_filename if opts.asciiize else sanitize_file_name_unicode), to_lowercase=opts.to_lowercase, replace_whitespace=opts.replace_whitespace) base_path = join(*components) return '%s.pdf' % base_path
def create_upload_path(self, path, mdata, fname, create_dirs=True): path = os.path.abspath(path) maxlen = self.MAX_PATH_LEN special_tag = None if mdata.tags: for t in mdata.tags: if t.startswith(_('News')) or t.startswith('/'): special_tag = t break settings = self.settings() template = self.save_template() if mdata.tags and _('News') in mdata.tags: try: p = mdata.pubdate date = (p.year, p.month, p.day) except: today = time.localtime() date = (today[0], today[1], today[2]) template = "{title}_%d-%d-%d" % date use_subdirs = self.SUPPORTS_SUB_DIRS and settings.use_subdirs fname = sanitize(fname) ext = os.path.splitext(fname)[1] from calibre.library.save_to_disk import get_components from calibre.library.save_to_disk import config opts = config().parse() if not isinstance(template, unicode): template = template.decode('utf-8') app_id = str(getattr(mdata, 'application_id', '')) id_ = mdata.get('id', fname) extra_components = get_components(template, mdata, id_, timefmt=opts.send_timefmt, length=maxlen - len(app_id) - 1) if not extra_components: extra_components.append( sanitize(self.filename_callback(fname, mdata))) else: extra_components[-1] = sanitize( self.filename_callback(extra_components[-1] + ext, mdata)) if extra_components[-1] and extra_components[-1][0] in ('.', '_'): extra_components[-1] = 'x' + extra_components[-1][1:] if special_tag is not None: name = extra_components[-1] extra_components = [] tag = special_tag if tag.startswith(_('News')): if self.NEWS_IN_FOLDER: extra_components.append('News') else: for c in tag.split('/'): c = sanitize(c) if not c: continue extra_components.append(c) extra_components.append(name) if not use_subdirs: extra_components = extra_components[-1:] def remove_trailing_periods(x): ans = x while ans.endswith('.'): ans = ans[:-1].strip() if not ans: ans = 'x' return ans extra_components = list(map(remove_trailing_periods, extra_components)) components = shorten_components_to(maxlen - len(path), extra_components) components = self.sanitize_path_components(components) filepath = os.path.join(path, *components) filedir = os.path.dirname(filepath) if create_dirs and not os.path.exists(filedir): os.makedirs(filedir) return filepath
def create_upload_path(mdata, fname, template, sanitize, prefix_path='', path_type=os.path, maxlen=250, use_subdirs=True, news_in_folder=True, filename_callback=lambda x, y:x, sanitize_path_components=lambda x: x ): from calibre.library.save_to_disk import get_components, config from calibre.utils.filenames import shorten_components_to special_tag = None if mdata.tags: for t in mdata.tags: if t.startswith(_('News')) or t.startswith('/'): special_tag = t break if mdata.tags and _('News') in mdata.tags: try: p = mdata.pubdate date = (p.year, p.month, p.day) except: today = time.localtime() date = (today[0], today[1], today[2]) template = u"{title}_%d-%d-%d" % date fname = sanitize(fname) ext = path_type.splitext(fname)[1] opts = config().parse() if not isinstance(template, unicode): template = template.decode('utf-8') app_id = str(getattr(mdata, 'application_id', '')) id_ = mdata.get('id', fname) extra_components = get_components(template, mdata, id_, timefmt=opts.send_timefmt, length=maxlen-len(app_id)-1, sanitize_func=sanitize, last_has_extension=False) if not extra_components: extra_components.append(sanitize(filename_callback(fname, mdata))) else: extra_components[-1] = sanitize(filename_callback(extra_components[-1]+ext, mdata)) if extra_components[-1] and extra_components[-1][0] in ('.', '_'): extra_components[-1] = 'x' + extra_components[-1][1:] if special_tag is not None: name = extra_components[-1] extra_components = [] tag = special_tag if tag.startswith(_('News')): if news_in_folder: extra_components.append('News') else: for c in tag.split('/'): c = sanitize(c) if not c: continue extra_components.append(c) extra_components.append(name) if not use_subdirs: extra_components = extra_components[-1:] def remove_trailing_periods(x): ans = x while ans.endswith('.'): ans = ans[:-1].strip() if not ans: ans = 'x' return ans extra_components = list(map(remove_trailing_periods, extra_components)) components = shorten_components_to(maxlen - len(prefix_path), extra_components) components = sanitize_path_components(components) if prefix_path: filepath = path_type.join(prefix_path, *components) else: filepath = path_type.join(*components) return filepath
def create_upload_path(self, path, mdata, fname, create_dirs=True): path = os.path.abspath(path) maxlen = self.MAX_PATH_LEN special_tag = None if mdata.tags: for t in mdata.tags: if t.startswith(_('News')) or t.startswith('/'): special_tag = t break settings = self.settings() template = self.save_template() if mdata.tags and _('News') in mdata.tags: try: p = mdata.pubdate date = (p.year, p.month, p.day) except: today = time.localtime() date = (today[0], today[1], today[2]) template = "{title}_%d-%d-%d" % date use_subdirs = self.SUPPORTS_SUB_DIRS and settings.use_subdirs fname = sanitize(fname) ext = os.path.splitext(fname)[1] from calibre.library.save_to_disk import get_components from calibre.library.save_to_disk import config opts = config().parse() if not isinstance(template, unicode): template = template.decode('utf-8') app_id = str(getattr(mdata, 'application_id', '')) id_ = mdata.get('id', fname) extra_components = get_components(template, mdata, id_, timefmt=opts.send_timefmt, length=maxlen-len(app_id)-1) if not extra_components: extra_components.append(sanitize(self.filename_callback(fname, mdata))) else: extra_components[-1] = sanitize(self.filename_callback(extra_components[-1]+ext, mdata)) if extra_components[-1] and extra_components[-1][0] in ('.', '_'): extra_components[-1] = 'x' + extra_components[-1][1:] if special_tag is not None: name = extra_components[-1] extra_components = [] tag = special_tag if tag.startswith(_('News')): if self.NEWS_IN_FOLDER: extra_components.append('News') else: for c in tag.split('/'): c = sanitize(c) if not c: continue extra_components.append(c) extra_components.append(name) if not use_subdirs: extra_components = extra_components[-1:] def remove_trailing_periods(x): ans = x while ans.endswith('.'): ans = ans[:-1].strip() if not ans: ans = 'x' return ans extra_components = list(map(remove_trailing_periods, extra_components)) components = shorten_components_to(maxlen - len(path), extra_components) components = self.sanitize_path_components(components) filepath = os.path.join(path, *components) filedir = os.path.dirname(filepath) if create_dirs and not os.path.exists(filedir): os.makedirs(filedir) return filepath
def create_upload_path(mdata, fname, template, sanitize, prefix_path='', path_type=os.path, maxlen=250, use_subdirs=True, news_in_folder=True, filename_callback=lambda x, y: x, sanitize_path_components=lambda x: x): from calibre.library.save_to_disk import get_components, config from calibre.utils.filenames import shorten_components_to special_tag = None if mdata.tags: for t in mdata.tags: if t.startswith(_('News')) or t.startswith('/'): special_tag = t break if mdata.tags and _('News') in mdata.tags: try: p = mdata.pubdate date = (p.year, p.month, p.day) except: today = time.localtime() date = (today[0], today[1], today[2]) template = "{title}_%d-%d-%d" % date fname = sanitize(fname) ext = path_type.splitext(fname)[1] opts = config().parse() if not isinstance(template, str): template = template.decode('utf-8') app_id = str(getattr(mdata, 'application_id', '')) id_ = mdata.get('id', fname) extra_components = get_components(template, mdata, id_, timefmt=opts.send_timefmt, length=maxlen - len(app_id) - 1, sanitize_func=sanitize, last_has_extension=False) if not extra_components: extra_components.append(sanitize(filename_callback(fname, mdata))) else: extra_components[-1] = sanitize( filename_callback(extra_components[-1] + ext, mdata)) if extra_components[-1] and extra_components[-1][0] in ('.', '_'): extra_components[-1] = 'x' + extra_components[-1][1:] if special_tag is not None: name = extra_components[-1] extra_components = [] tag = special_tag if tag.startswith(_('News')): if news_in_folder: extra_components.append('News') else: for c in tag.split('/'): c = sanitize(c) if not c: continue extra_components.append(c) extra_components.append(name) if not use_subdirs: extra_components = extra_components[-1:] def remove_trailing_periods(x): ans = x while ans.endswith('.'): ans = ans[:-1].strip() if not ans: ans = 'x' return ans extra_components = list(map(remove_trailing_periods, extra_components)) components = shorten_components_to(maxlen - len(prefix_path), extra_components) components = sanitize_path_components(components) if prefix_path: filepath = path_type.join(prefix_path, *components) else: filepath = path_type.join(*components) return filepath
def _run(self, tdir): from calibre.library.save_to_disk import config server = Server() if self.spare_server is None else self.spare_server ids = set(self.ids) tasks = server.split(list(ids)) jobs = set([]) c = config() recs = {} for pref in c.preferences: recs[pref.name] = getattr(self.opts, pref.name) plugboards = self.db.prefs.get('plugboards', {}) template_functions = self.db.prefs.get('user_template_functions', []) for i, task in enumerate(tasks): tids = [x[-1] for x in task] data = self.collect_data(tids, tdir) dpath = os.path.join(tdir, '%d.json' % i) with open(dpath, 'wb') as f: f.write(json.dumps(data, ensure_ascii=False).encode('utf-8')) job = ParallelJob('save_book', 'Save books (%d of %d)' % (i, len(tasks)), lambda x, y: x, args=[ tids, dpath, plugboards, template_functions, self.path, recs ]) jobs.add(job) server.add_job(job) while not self.canceled: time.sleep(0.2) running = False for job in jobs: self.get_notifications(job, ids) if not job.is_finished: running = True if not running: break for job in jobs: if not job.result: continue for id_, title, ok, tb in job.result: if id_ in ids: self.result_queue.put((id_, title, ok, tb)) ids.remove(id_) server.close() time.sleep(1) if self.canceled: return for job in jobs: if job.failed: prints(job.details) self.error = job.details if os.path.exists(job.log_path): try: os.remove(job.log_path) except: pass
def _default_save_template(cls): from calibre.library.save_to_disk import config return cls.SAVE_TEMPLATE if cls.SAVE_TEMPLATE else \ config().parse().send_template
def _run(self, tdir): from calibre.library.save_to_disk import config server = Server() if self.spare_server is None else self.spare_server ids = set(self.ids) tasks = server.split(list(ids)) jobs = set([]) c = config() recs = {} for pref in c.preferences: recs[pref.name] = getattr(self.opts, pref.name) plugboards = self.db.prefs.get('plugboards', {}) template_functions = self.db.prefs.get('user_template_functions', []) for i, task in enumerate(tasks): tids = [x[-1] for x in task] data = self.collect_data(tids, tdir) dpath = os.path.join(tdir, '%d.json'%i) with open(dpath, 'wb') as f: f.write(json.dumps(data, ensure_ascii=False).encode('utf-8')) job = ParallelJob('save_book', 'Save books (%d of %d)'%(i, len(tasks)), lambda x,y:x, args=[tids, dpath, plugboards, template_functions, self.path, recs]) jobs.add(job) server.add_job(job) while not self.canceled: time.sleep(0.2) running = False for job in jobs: self.get_notifications(job, ids) if not job.is_finished: running = True if not running: break for job in jobs: if not job.result: continue for id_, title, ok, tb in job.result: if id_ in ids: self.result_queue.put((id_, title, ok, tb)) ids.remove(id_) server.close() time.sleep(1) if self.canceled: return for job in jobs: if job.failed: prints(job.details) self.error = job.details if os.path.exists(job.log_path): try: os.remove(job.log_path) except: pass