def _build_local_path(): path = remote_db_path.split('/')[-1] if iswindows: from calibre.utils.filenames import shorten_components_to plen = len(self.temp_dir) path = ''.join(shorten_components_to(245-plen, [path])) full_path = os.path.join(self.temp_dir, path) return os.path.normpath(full_path)
def _build_local_path(): path = remote_db_path.split('/')[-1] if iswindows: from calibre.utils.filenames import shorten_components_to plen = len(self.temp_dir) path = ''.join(shorten_components_to(245 - plen, [path])) full_path = os.path.join(self.temp_dir, path) return os.path.normpath(full_path)
def _localize_database_path(self, app_id, remote_db_path): ''' Copy remote_db_path from iOS to local storage as needed ''' self._log_location("app_id: '%s' remote_db_path: '%s'" % (app_id, remote_db_path)) # Mount app_id self.ios.mount_ios_app(app_id=app_id) local_db_path = None db_stats = {} if '*' in remote_db_path: # Find matching file based on wildcard f_els = os.path.basename(remote_db_path).split('*') prefix = f_els[0] suffix = f_els[1] files = self.ios.listdir(os.path.dirname(remote_db_path)) for f in files: if f.startswith(prefix) and f.endswith(suffix): remote_db_path = '/'.join( [os.path.dirname(remote_db_path), f]) break db_stats = self.ios.stat(remote_db_path) if db_stats: path = remote_db_path.split('/')[-1] if iswindows: plen = len(self.temp_dir) path = ''.join(shorten_components_to(245 - plen, [path])) full_path = os.path.join(self.temp_dir, path) if os.path.exists(full_path): lfs = os.stat(full_path) if (int(db_stats['st_mtime']) == lfs.st_mtime and int(db_stats['st_size']) == lfs.st_size): local_db_path = full_path if not local_db_path: with open(full_path, 'wb') as out: self.ios.copy_from_idevice(remote_db_path, out) local_db_path = out.name else: self._log_location("'%s' not found" % remote_db_path) raise DatabaseNotFoundException # Dismount ios self.ios.disconnect_idevice() return {'path': local_db_path, 'stats': db_stats}
def _build_local_path(): ''' GoodReader stores individual dbs for each book, matching the folder and name structure in the Documents folder. Make a local version, renamed to .db ''' path = remote_db_path.split('/')[-1] if iswindows: from calibre.utils.filenames import shorten_components_to plen = len(self.temp_dir) path = ''.join(shorten_components_to(245 - plen, [path])) full_path = os.path.join(self.temp_dir, path) base = os.path.splitext(full_path)[0] full_path = base + ".db" return os.path.normpath(full_path)
def _build_local_path(): ''' GoodReader stores individual dbs for each book, matching the folder and name structure in the Documents folder. Make a local version, renamed to .db ''' path = remote_db_path.split('/')[-1] if iswindows: from calibre.utils.filenames import shorten_components_to plen = len(self.temp_dir) path = ''.join(shorten_components_to(245-plen, [path])) full_path = os.path.join(self.temp_dir, path) base = os.path.splitext(full_path)[0] full_path = base + ".db" return os.path.normpath(full_path)
def _localize_database_path(self, app_id, remote_db_path): ''' Copy remote_db_path from iOS to local storage as needed ''' self._log_location("app_id: '%s' remote_db_path: '%s'" % (app_id, remote_db_path)) # Mount app_id self.ios.mount_ios_app(app_id=app_id) local_db_path = None db_stats = {} if '*' in remote_db_path: # Find matching file based on wildcard f_els = os.path.basename(remote_db_path).split('*') prefix = f_els[0] suffix = f_els[1] files = self.ios.listdir(os.path.dirname(remote_db_path)) for f in files: if f.startswith(prefix) and f.endswith(suffix): remote_db_path = '/'.join([os.path.dirname(remote_db_path),f]) break db_stats = self.ios.stat(remote_db_path) if db_stats: path = remote_db_path.split('/')[-1] if iswindows: plen = len(self.temp_dir) path = ''.join(shorten_components_to(245-plen, [path])) full_path = os.path.join(self.temp_dir, path) if os.path.exists(full_path): lfs = os.stat(full_path) if (int(db_stats['st_mtime']) == lfs.st_mtime and int(db_stats['st_size']) == lfs.st_size): local_db_path = full_path if not local_db_path: with open(full_path, 'wb') as out: self.ios.copy_from_idevice(remote_db_path, out) local_db_path = out.name else: self._log_location("'%s' not found" % remote_db_path) raise DatabaseNotFoundException # Dismount ios self.ios.disconnect_idevice() return {'path': local_db_path, 'stats': db_stats}
def prepare_addable_books(self, paths): """ Given a list of paths, returns another list of paths. These paths point to addable versions of the books. If there is an error preparing a book, then instead of a path, the position in the returned list for that book should be a three tuple: (original_path, the exception instance, traceback) Modeled on calibre.devices.mtp.driver:prepare_addable_books() #304 """ from calibre import sanitize_file_name from calibre.ptempfile import PersistentTemporaryDirectory self._log_location() tdir = PersistentTemporaryDirectory("_prep_gr") ans = [] for path in paths: if not self.ios.exists("/".join([self.documents_folder, path])): ans.append((path, "File not found", "File not found")) continue base = tdir if iswindows: from calibre.utils.filenames import shorten_components_to plen = len(base) bfn = path.split("/")[-1] dest = "".join(shorten_components_to(245 - plen, [bfn])) else: dest = path out_path = os.path.normpath(os.path.join(base, sanitize_file_name(dest))) with open(out_path, "wb") as out: try: self.get_file(path, out) except Exception as e: import traceback ans.append((dest, e, traceback.format_exc())) else: ans.append(out.name) return ans
def prepare_addable_books(self, paths): ''' Given a list of paths, returns another list of paths. These paths point to addable versions of the books. If there is an error preparing a book, then instead of a path, the position in the returned list for that book should be a three tuple: (original_path, the exception instance, traceback) Modeled on calibre.devices.mtp.driver:prepare_addable_books() #304 ''' from calibre import sanitize_file_name from calibre.ptempfile import PersistentTemporaryDirectory self._log_location() tdir = PersistentTemporaryDirectory('_prep_gr') ans = [] for path in paths: if not self.ios.exists('/'.join([self.documents_folder, path])): ans.append((path, 'File not found', 'File not found')) continue base = tdir if iswindows: from calibre.utils.filenames import shorten_components_to plen = len(base) bfn = path.split('/')[-1] dest = ''.join(shorten_components_to(245 - plen, [bfn])) else: dest = path out_path = os.path.normpath( os.path.join(base, sanitize_file_name(dest))) with open(out_path, 'wb') as out: try: self.get_file(path, out) except Exception as e: import traceback ans.append((dest, e, traceback.format_exc())) else: ans.append(out.name) return ans
def _localize_mobi(self, remote_path): ''' Copy remote_path from iOS to local storage as needed ''' self._log_location("remote_path: '%s'" % (remote_path)) local_path = None path = remote_path.split('/')[-1] if iswindows: from calibre.utils.filenames import shorten_components_to plen = len(self.temp_dir) path = ''.join(shorten_components_to(245 - plen, [path])) full_path = os.path.join(self.temp_dir, path) full_path = os.path.normpath(full_path) with open(full_path, 'wb') as out: self.ios.copy_from_idevice(remote_path, out) local_path = out.name return local_path
def _localize_pdf(self, remote_path): ''' Copy remote_path from iOS to local storage as needed ''' self._log_location("remote_path: '%s'" % (remote_path)) local_path = None path = remote_path.split('/')[-1] if iswindows: from calibre.utils.filenames import shorten_components_to plen = len(self.temp_dir) path = ''.join(shorten_components_to(245-plen, [path])) full_path = os.path.join(self.temp_dir, path) full_path = os.path.normpath(full_path) with open(full_path, 'wb') as out: self.ios.copy_from_idevice(remote_path, out) local_path = out.name return local_path
def prepare_addable_books(self, paths): tdir = PersistentTemporaryDirectory('_prepare_mtp') ans = [] for path in paths: try: f = self.filesystem_cache.resolve_mtp_id_path(path) except Exception as e: ans.append((path, e, traceback.format_exc())) continue base = os.path.join(tdir, '%s'%f.object_id) os.mkdir(base) name = f.name if iswindows: plen = len(base) name = ''.join(shorten_components_to(245-plen, [name])) with lopen(os.path.join(base, name), 'wb') as out: try: self.get_mtp_file(f, out) except Exception as e: ans.append((path, e, traceback.format_exc())) else: ans.append(out.name) return ans
def get_components(template, mi, id, timefmt='%b %Y', length=250, sanitize_func=ascii_filename, replace_whitespace=False, to_lowercase=False, safe_format=True, last_has_extension=True, single_dir=False): tsorder = tweaks['save_template_title_series_sorting'] format_args = FORMAT_ARGS.copy() format_args.update(mi.all_non_none_fields()) if mi.title: if tsorder == 'strictly_alphabetic': v = mi.title else: # title_sort might be missing or empty. Check both conditions v = mi.get('title_sort', None) if not v: v = title_sort(mi.title, order=tsorder) format_args['title'] = v if mi.authors: format_args['authors'] = mi.format_authors() format_args['author'] = format_args['authors'] if mi.tags: format_args['tags'] = mi.format_tags() if format_args['tags'].startswith('/'): format_args['tags'] = format_args['tags'][1:] else: format_args['tags'] = '' if mi.series: format_args['series'] = title_sort(mi.series, order=tsorder) if mi.series_index is not None: format_args['series_index'] = mi.format_series_index() else: template = re.sub(r'\{series_index[^}]*?\}', '', template) if mi.rating is not None: format_args['rating'] = mi.format_rating(divide_by=2.0) if mi.identifiers: format_args['identifiers'] = mi.format_field_extended('identifiers')[1] else: format_args['identifiers'] = '' if hasattr(mi.timestamp, 'timetuple'): format_args['timestamp'] = strftime(timefmt, mi.timestamp.timetuple()) if hasattr(mi.pubdate, 'timetuple'): format_args['pubdate'] = strftime(timefmt, mi.pubdate.timetuple()) if hasattr(mi, 'last_modified') and hasattr(mi.last_modified, 'timetuple'): format_args['last_modified'] = strftime(timefmt, mi.last_modified.timetuple()) format_args['id'] = unicode_type(id) # Now format the custom fields custom_metadata = mi.get_all_user_metadata(make_copy=False) for key in custom_metadata: if key in format_args: cm = custom_metadata[key] if cm['datatype'] == 'series': format_args[key] = title_sort(format_args[key], order=tsorder) if key+'_index' in format_args: format_args[key+'_index'] = fmt_sidx(format_args[key+'_index']) elif cm['datatype'] == 'datetime': format_args[key] = strftime(timefmt, as_local_time(format_args[key]).timetuple()) elif cm['datatype'] == 'bool': format_args[key] = _('yes') if format_args[key] else _('no') elif cm['datatype'] == 'rating': format_args[key] = mi.format_rating(format_args[key], divide_by=2.0) elif cm['datatype'] in ['int', 'float']: if format_args[key] != 0: format_args[key] = unicode_type(format_args[key]) else: format_args[key] = '' if safe_format: components = Formatter().safe_format(template, format_args, 'G_C-EXCEPTION!', mi) else: components = Formatter().unsafe_format(template, format_args, mi) components = [x.strip() for x in components.split('/')] components = [sanitize_func(x) for x in components if x] if not components: components = [unicode_type(id)] if to_lowercase: components = [x.lower() for x in components] if replace_whitespace: components = [re.sub(r'\s', '_', x) for x in components] if single_dir: components = components[-1:] return shorten_components_to(length, components, last_has_extension=last_has_extension)
def convert(self, oeb_book, output_path, input_plugin, opts, log): from lxml import etree from calibre.ebooks.oeb.base import OEB_IMAGES, SVG_MIME from calibre.ebooks.metadata.opf2 import OPF, metadata_to_opf from calibre.utils.zipfile import ZipFile from calibre.utils.filenames import ascii_filename # HTML if opts.htmlz_css_type == 'inline': from calibre.ebooks.htmlz.oeb2html import OEB2HTMLInlineCSSizer OEB2HTMLizer = OEB2HTMLInlineCSSizer elif opts.htmlz_css_type == 'tag': from calibre.ebooks.htmlz.oeb2html import OEB2HTMLNoCSSizer OEB2HTMLizer = OEB2HTMLNoCSSizer else: from calibre.ebooks.htmlz.oeb2html import OEB2HTMLClassCSSizer as OEB2HTMLizer with TemporaryDirectory(u'_htmlz_output') as tdir: htmlizer = OEB2HTMLizer(log) html = htmlizer.oeb2html(oeb_book, opts) fname = u'index' if opts.htmlz_title_filename: from calibre.utils.filenames import shorten_components_to fname = shorten_components_to(100, (ascii_filename(unicode_type(oeb_book.metadata.title[0])),))[0] with open(os.path.join(tdir, fname+u'.html'), 'wb') as tf: if isinstance(html, unicode_type): html = html.encode('utf-8') tf.write(html) # CSS if opts.htmlz_css_type == 'class' and opts.htmlz_class_style == 'external': with open(os.path.join(tdir, u'style.css'), 'wb') as tf: tf.write(htmlizer.get_css(oeb_book)) # Images images = htmlizer.images if images: if not os.path.exists(os.path.join(tdir, u'images')): os.makedirs(os.path.join(tdir, u'images')) for item in oeb_book.manifest: if item.media_type in OEB_IMAGES and item.href in images: if item.media_type == SVG_MIME: data = etree.tostring(item.data, encoding='unicode') else: data = item.data fname = os.path.join(tdir, u'images', images[item.href]) with open(fname, 'wb') as img: img.write(data) # Cover cover_path = None try: cover_data = None if oeb_book.metadata.cover: term = oeb_book.metadata.cover[0].term cover_data = oeb_book.guide[term].item.data if cover_data: from calibre.utils.img import save_cover_data_to cover_path = os.path.join(tdir, u'cover.jpg') with lopen(cover_path, 'w') as cf: cf.write('') save_cover_data_to(cover_data, cover_path) except: import traceback traceback.print_exc() # Metadata with open(os.path.join(tdir, u'metadata.opf'), 'wb') as mdataf: opf = OPF(io.BytesIO(etree.tostring(oeb_book.metadata.to_opf1(), encoding='UTF-8'))) mi = opf.to_book_metadata() if cover_path: mi.cover = u'cover.jpg' mdataf.write(metadata_to_opf(mi)) htmlz = ZipFile(output_path, 'w') htmlz.add_dir(tdir)
def convert(self, oeb_book, output_path, input_plugin, opts, log): from lxml import etree from calibre.ebooks.oeb.base import OEB_IMAGES, SVG_MIME from calibre.ebooks.metadata.opf2 import OPF, metadata_to_opf from calibre.utils.zipfile import ZipFile from calibre.utils.filenames import ascii_filename # HTML if opts.htmlz_css_type == 'inline': from calibre.ebooks.htmlz.oeb2html import OEB2HTMLInlineCSSizer OEB2HTMLizer = OEB2HTMLInlineCSSizer elif opts.htmlz_css_type == 'tag': from calibre.ebooks.htmlz.oeb2html import OEB2HTMLNoCSSizer OEB2HTMLizer = OEB2HTMLNoCSSizer else: from calibre.ebooks.htmlz.oeb2html import OEB2HTMLClassCSSizer as OEB2HTMLizer with TemporaryDirectory(u'_htmlz_output') as tdir: htmlizer = OEB2HTMLizer(log) html = htmlizer.oeb2html(oeb_book, opts) fname = u'index' if opts.htmlz_title_filename: from calibre.utils.filenames import shorten_components_to fname = shorten_components_to(100, (ascii_filename( unicode_type(oeb_book.metadata.title[0])), ))[0] with open(os.path.join(tdir, fname + u'.html'), 'wb') as tf: if isinstance(html, unicode_type): html = html.encode('utf-8') tf.write(html) # CSS if opts.htmlz_css_type == 'class' and opts.htmlz_class_style == 'external': with open(os.path.join(tdir, u'style.css'), 'wb') as tf: tf.write(htmlizer.get_css(oeb_book)) # Images images = htmlizer.images if images: if not os.path.exists(os.path.join(tdir, u'images')): os.makedirs(os.path.join(tdir, u'images')) for item in oeb_book.manifest: if item.media_type in OEB_IMAGES and item.href in images: if item.media_type == SVG_MIME: data = unicode_type( etree.tostring(item.data, encoding=unicode_type)) else: data = item.data fname = os.path.join(tdir, u'images', images[item.href]) with open(fname, 'wb') as img: img.write(data) # Cover cover_path = None try: cover_data = None if oeb_book.metadata.cover: term = oeb_book.metadata.cover[0].term cover_data = oeb_book.guide[term].item.data if cover_data: from calibre.utils.img import save_cover_data_to cover_path = os.path.join(tdir, u'cover.jpg') with lopen(cover_path, 'w') as cf: cf.write('') save_cover_data_to(cover_data, cover_path) except: import traceback traceback.print_exc() # Metadata with open(os.path.join(tdir, u'metadata.opf'), 'wb') as mdataf: opf = OPF( io.BytesIO( etree.tostring(oeb_book.metadata.to_opf1(), encoding='UTF-8'))) mi = opf.to_book_metadata() if cover_path: mi.cover = u'cover.jpg' mdataf.write(metadata_to_opf(mi)) htmlz = ZipFile(output_path, 'w') htmlz.add_dir(tdir)
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 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(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 get_components(template, mi, id, timefmt='%b %Y', length=250, sanitize_func=ascii_filename, replace_whitespace=False, to_lowercase=False, safe_format=True): tsorder = tweaks['save_template_title_series_sorting'] format_args = FORMAT_ARGS.copy() format_args.update(mi.all_non_none_fields()) if mi.title: if tsorder == 'strictly_alphabetic': v = mi.title else: # title_sort might be missing or empty. Check both conditions v = mi.get('title_sort', None) if not v: v = title_sort(mi.title, order=tsorder) format_args['title'] = v if mi.authors: format_args['authors'] = mi.format_authors() format_args['author'] = format_args['authors'] if mi.tags: format_args['tags'] = mi.format_tags() if format_args['tags'].startswith('/'): format_args['tags'] = format_args['tags'][1:] else: format_args['tags'] = '' if mi.series: format_args['series'] = title_sort(mi.series, order=tsorder) if mi.series_index is not None: format_args['series_index'] = mi.format_series_index() else: template = re.sub(r'\{series_index[^}]*?\}', '', template) if mi.rating is not None: format_args['rating'] = mi.format_rating(divide_by=2.0) if mi.identifiers: format_args['identifiers'] = mi.format_field_extended('identifiers')[1] else: format_args['identifiers'] = '' if hasattr(mi.timestamp, 'timetuple'): format_args['timestamp'] = strftime(timefmt, mi.timestamp.timetuple()) if hasattr(mi.pubdate, 'timetuple'): format_args['pubdate'] = strftime(timefmt, mi.pubdate.timetuple()) if hasattr(mi, 'last_modified') and hasattr(mi.last_modified, 'timetuple'): format_args['last_modified'] = strftime(timefmt, mi.last_modified.timetuple()) format_args['id'] = str(id) # Now format the custom fields custom_metadata = mi.get_all_user_metadata(make_copy=False) for key in custom_metadata: if key in format_args: cm = custom_metadata[key] if cm['datatype'] == 'series': format_args[key] = title_sort(format_args[key], order=tsorder) if key+'_index' in format_args: format_args[key+'_index'] = fmt_sidx(format_args[key+'_index']) elif cm['datatype'] == 'datetime': format_args[key] = strftime(timefmt, format_args[key].timetuple()) elif cm['datatype'] == 'bool': format_args[key] = _('yes') if format_args[key] else _('no') elif cm['datatype'] == 'rating': format_args[key] = mi.format_rating(format_args[key], divide_by=2.0) elif cm['datatype'] in ['int', 'float']: if format_args[key] != 0: format_args[key] = unicode(format_args[key]) else: format_args[key] = '' if safe_format: components = Formatter().safe_format(template, format_args, 'G_C-EXCEPTION!', mi) else: components = Formatter().unsafe_format(template, format_args, mi) components = [x.strip() for x in components.split('/')] components = [sanitize_func(x) for x in components if x] if not components: components = [str(id)] if to_lowercase: components = [x.lower() for x in components] if replace_whitespace: components = [re.sub(r'\s', '_', x) for x in components] return shorten_components_to(length, components)
def convert(self, oeb_book, output_path, input_plugin, opts, log): from lxml import etree from calibre.ebooks.oeb.base import OEB_IMAGES, SVG_MIME from calibre.ebooks.metadata.opf2 import OPF, metadata_to_opf from calibre.utils.zipfile import ZipFile from calibre.utils.filenames import ascii_filename # HTML if opts.htmlz_css_type == "inline": from calibre.ebooks.htmlz.oeb2html import OEB2HTMLInlineCSSizer OEB2HTMLizer = OEB2HTMLInlineCSSizer elif opts.htmlz_css_type == "tag": from calibre.ebooks.htmlz.oeb2html import OEB2HTMLNoCSSizer OEB2HTMLizer = OEB2HTMLNoCSSizer else: from calibre.ebooks.htmlz.oeb2html import OEB2HTMLClassCSSizer as OEB2HTMLizer with TemporaryDirectory("_htmlz_output") as tdir: htmlizer = OEB2HTMLizer(log) html = htmlizer.oeb2html(oeb_book, opts) fname = "index" if opts.htmlz_title_filename: from calibre.utils.filenames import shorten_components_to fname = shorten_components_to(100, (ascii_filename(unicode(oeb_book.metadata.title[0])),))[0] with open(os.path.join(tdir, fname + ".html"), "wb") as tf: if isinstance(html, unicode): html = html.encode("utf-8") tf.write(html) # CSS if opts.htmlz_css_type == "class" and opts.htmlz_class_style == "external": with open(os.path.join(tdir, "style.css"), "wb") as tf: tf.write(htmlizer.get_css(oeb_book)) # Images images = htmlizer.images if images: if not os.path.exists(os.path.join(tdir, "images")): os.makedirs(os.path.join(tdir, "images")) for item in oeb_book.manifest: if item.media_type in OEB_IMAGES and item.href in images: if item.media_type == SVG_MIME: data = unicode(etree.tostring(item.data, encoding=unicode)) else: data = item.data fname = os.path.join(tdir, "images", images[item.href]) with open(fname, "wb") as img: img.write(data) # Cover cover_path = None try: cover_data = None if oeb_book.metadata.cover: term = oeb_book.metadata.cover[0].term cover_data = oeb_book.guide[term].item.data if cover_data: from calibre.utils.magick.draw import save_cover_data_to cover_path = os.path.join(tdir, "cover.jpg") with open(cover_path, "w") as cf: cf.write("") save_cover_data_to(cover_data, cover_path) except: import traceback traceback.print_exc() # Metadata with open(os.path.join(tdir, "metadata.opf"), "wb") as mdataf: opf = OPF(StringIO(etree.tostring(oeb_book.metadata.to_opf1()))) mi = opf.to_book_metadata() if cover_path: mi.cover = "cover.jpg" mdataf.write(metadata_to_opf(mi)) htmlz = ZipFile(output_path, "w") htmlz.add_dir(tdir)