def main(args=sys.argv): parser = option_parser() opts, args = parser.parse_args(args) if len(args) < 2: parser.print_help() prints(_('No file specified'), file=sys.stderr) return 1 path = args[1] stream_type = os.path.splitext(path)[1].replace('.', '').lower() trying_to_set = False for pref in config().option_set.preferences: if pref.name in ('to_opf', 'get_cover'): continue if getattr(opts, pref.name) is not None: trying_to_set = True break with open(path, 'rb') as stream: mi = get_metadata(stream, stream_type, force_read_metadata=True) if trying_to_set: prints(_('Original metadata')+'::') metadata = unicode_type(mi) if trying_to_set: metadata = '\t'+'\n\t'.join(metadata.split('\n')) prints(metadata, safe_encode=True) if trying_to_set: with open(path, 'r+b') as stream: do_set_metadata(opts, mi, stream, stream_type) stream.seek(0) stream.flush() lrf = None if stream_type == 'lrf': if opts.lrf_bookid is not None: lrf = LRFMetaFile(stream) lrf.book_id = opts.lrf_bookid mi = get_metadata(stream, stream_type, force_read_metadata=True) prints('\n' + _('Changed metadata') + '::') metadata = unicode_type(mi) metadata = '\t'+'\n\t'.join(metadata.split('\n')) prints(metadata, safe_encode=True) if lrf is not None: prints('\tBookID:', lrf.book_id) if opts.to_opf is not None: from calibre.ebooks.metadata.opf2 import OPFCreator opf = OPFCreator(getcwd(), mi) with open(opts.to_opf, 'wb') as f: opf.render(f) prints(_('OPF created in'), opts.to_opf) if opts.get_cover is not None: if mi.cover_data and mi.cover_data[1]: with open(opts.get_cover, 'wb') as f: f.write(mi.cover_data[1]) prints(_('Cover saved to'), f.name) else: prints(_('No cover found'), file=sys.stderr) return 0
def main(args=sys.argv): parser = option_parser() opts, args = parser.parse_args(args) if len(args) < 2: parser.print_help() prints(_('No file specified'), file=sys.stderr) return 1 path = args[1] stream = open(path, 'r+b') stream_type = os.path.splitext(path)[1].replace('.', '').lower() trying_to_set = False for pref in config().option_set.preferences: if pref.name in ('to_opf', 'get_cover'): continue if getattr(opts, pref.name) is not None: trying_to_set = True break mi = get_metadata(stream, stream_type, force_read_metadata=True) if trying_to_set: prints(_('Original metadata') + '::') metadata = unicode(mi) if trying_to_set: metadata = '\t' + '\n\t'.join(metadata.split('\n')) prints(metadata, safe_encode=True) if trying_to_set: stream.seek(0) do_set_metadata(opts, mi, stream, stream_type) stream.seek(0) stream.flush() lrf = None if stream_type == 'lrf': if opts.lrf_bookid is not None: lrf = LRFMetaFile(stream) lrf.book_id = opts.lrf_bookid mi = get_metadata(stream, stream_type, force_read_metadata=True) prints('\n' + _('Changed metadata') + '::') metadata = unicode(mi) metadata = '\t' + '\n\t'.join(metadata.split('\n')) prints(metadata, safe_encode=True) if lrf is not None: prints('\tBookID:', lrf.book_id) if opts.to_opf is not None: from calibre.ebooks.metadata.opf2 import OPFCreator opf = OPFCreator(os.getcwdu(), mi) with open(opts.to_opf, 'wb') as f: opf.render(f) prints(_('OPF created in'), opts.to_opf) if opts.get_cover is not None: if mi.cover_data and mi.cover_data[1]: with open(opts.get_cover, 'wb') as f: f.write(mi.cover_data[1]) prints(_('Cover saved to'), f.name) else: prints(_('No cover found'), file=sys.stderr) return 0
def get_metadata(stream): from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks.metadata.archive import is_comic stream_type = None zf = ZipFile(stream, 'r') names = zf.namelist() if is_comic(names): # Is probably a comic return get_metadata(stream, 'cbz') for f in names: stream_type = os.path.splitext(f)[1].lower() if stream_type: stream_type = stream_type[1:] if stream_type in ('lit', 'opf', 'prc', 'mobi', 'fb2', 'epub', 'rb', 'imp', 'pdf', 'lrf', 'azw', 'azw1', 'azw3'): with TemporaryDirectory() as tdir: with CurrentDir(tdir): path = zf.extract(f) mi = get_metadata(open(path,'rb'), stream_type) if stream_type == 'opf' and mi.application_id is None: try: # zip archive opf files without an application_id were assumed not to have a cover # reparse the opf and if cover exists read its data from zip archive for the metadata nmi = zip_opf_metadata(path, zf) nmi.timestamp = None return nmi except: pass mi.timestamp = None return mi raise ValueError('No ebook found in ZIP archive (%s)' % os.path.basename(getattr(stream, 'name', '') or '<stream>'))
def get_metadata(stream): from calibre.ebooks.metadata.archive import is_comic from calibre.ebooks.metadata.meta import get_metadata path = getattr(stream, 'name', False) if not path: pt = PersistentTemporaryFile('_rar-meta.rar') pt.write(stream.read()) pt.close() path = pt.name path = os.path.abspath(path) file_names = list(names(path)) if is_comic(file_names): return get_metadata(stream, 'cbr') for f in file_names: stream_type = os.path.splitext(f)[1].lower() if stream_type: stream_type = stream_type[1:] if stream_type in ('lit', 'opf', 'prc', 'mobi', 'fb2', 'epub', 'rb', 'imp', 'pdf', 'lrf', 'azw'): with TemporaryDirectory() as tdir: with CurrentDir(tdir): stream = extract_member(path, match=None, name=f, as_file=True)[1] return get_metadata(stream, stream_type) raise ValueError('No ebook found in RAR archive')
def get_metadata(stream): from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks.metadata.archive import is_comic stream_type = None zf = ZipFile(stream, 'r') names = zf.namelist() if is_comic(names): # Is probably a comic return get_metadata(stream, 'cbz') for f in names: stream_type = os.path.splitext(f)[1].lower() if stream_type: stream_type = stream_type[1:] if stream_type in ('lit', 'opf', 'prc', 'mobi', 'fb2', 'epub', 'rb', 'imp', 'pdf', 'lrf', 'azw', 'azw1', 'azw3'): with TemporaryDirectory() as tdir: with CurrentDir(tdir): path = zf.extract(f) mi = get_metadata(open(path,'rb'), stream_type) if stream_type == 'opf' and mi.application_id is None: try: # zip archive opf files without an application_id were assumed not to have a cover # reparse the opf and if cover exists read its data from zip archive for the metadata nmi = zip_opf_metadata(path, zf) nmi.timestamp = None return nmi except: pass mi.timestamp = None return mi raise ValueError('No ebook found in ZIP archive (%s)' % os.path.basename(getattr(stream, 'name', '') or '<stream>'))
def get_metadata(stream): from calibre.ebooks.metadata.archive import is_comic from calibre.ebooks.metadata.meta import get_metadata path = getattr(stream, 'name', False) if not path: pt = PersistentTemporaryFile('_rar-meta.rar') pt.write(stream.read()) pt.close() path = pt.name path = os.path.abspath(path) file_names = list(names(path)) if is_comic(file_names): return get_metadata(stream, 'cbr') for f in file_names: stream_type = os.path.splitext(f)[1].lower() if stream_type: stream_type = stream_type[1:] if stream_type in ('lit', 'opf', 'prc', 'mobi', 'fb2', 'epub', 'rb', 'imp', 'pdf', 'lrf', 'azw'): with TemporaryDirectory() as tdir: with CurrentDir(tdir): stream = extract_member(path, match=None, name=f, as_file=True)[1] return get_metadata(stream, stream_type) raise ValueError('No ebook found in RAR archive')
def convert_to_html_add_to_library(self, vtt_dir, main_lang, sub_lang, cover_file_path): ''' return book_id when the html is added to library ''' html_file = PersistentTemporaryFile('.html', dir=self.temp_dir) convert.convert_webvtt_to_html(vtt_dir, main_lang, sub_lang, html_file.name) # add to library new_api = self.db.new_api from calibre.ebooks.metadata.meta import get_metadata with lopen(html_file.name, 'rb') as stream: mi = get_metadata(stream, stream_type='html', use_libprs_metadata=True) mi.tags = ['subtitles'] if cover_file_path != None: ext = cover_file_path.rpartition('.')[-1].lower().strip() if ext not in ('png', 'jpg', 'jpeg'): ext = 'jpg' with lopen(cover_file_path, 'rb') as stream: mi.cover_data = (ext, stream.read()) # add book in html format book_ids, duplicates = new_api.add_books([(mi, { 'HTML': html_file.name })], run_hooks=False) self.db.data.books_added(book_ids) self.gui.library_view.model().books_added(1) # remove temp directory #shutil.rmtree(self.temp_dir) return book_ids[0]
def add_catalog(cache, path, title): from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.meta import get_metadata from calibre.utils.date import utcnow fmt = os.path.splitext(path)[1][1:].lower() with lopen(path, 'rb') as stream, cache.write_lock: matches = cache._search('title:="%s" and tags:="%s"' % (title.replace('"', '\\"'), _('Catalog')), None) db_id = None if matches: db_id = list(matches)[0] try: mi = get_metadata(stream, fmt) mi.authors = ['calibre'] except: mi = Metadata(title, ['calibre']) mi.title, mi.authors = title, ['calibre'] mi.tags = [_('Catalog')] mi.pubdate = mi.timestamp = utcnow() if fmt == 'mobi': mi.cover, mi.cover_data = None, (None, None) if db_id is None: db_id = cache._create_book_entry(mi, apply_import_tags=False) else: cache._set_metadata(db_id, mi) cache._add_format(db_id, fmt, stream) return db_id
def cdb_add_book(ctx, rd, job_id, add_duplicates, filename, library_id): ''' Add a file as a new book. The file contents must be in the body of the request. The response will also have the title/authors/languages read from the metadata of the file/filename. It will contain a `book_id` field specifying the id of the newly added book, or if add_duplicates is not specified and a duplicate was found, no book_id will be present. It will also return the value of `job_id` as the `id` field and `filename` as the `filename` field. ''' db = get_db(ctx, rd, library_id) if ctx.restriction_for(rd, db): raise HTTPForbidden('Cannot use the add book interface with a user who has per library restrictions') if not filename: raise HTTPBadRequest('An empty filename is not allowed') sfilename = sanitize_file_name_unicode(filename) fmt = os.path.splitext(sfilename)[1] fmt = fmt[1:] if fmt else None if not fmt: raise HTTPBadRequest('An filename with no extension is not allowed') if isinstance(rd.request_body_file, BytesIO): raise HTTPBadRequest('A request body containing the file data must be specified') add_duplicates = add_duplicates in ('y', '1') path = os.path.join(rd.tdir, sfilename) rd.request_body_file.name = path rd.request_body_file.seek(0) mi = get_metadata(rd.request_body_file, stream_type=fmt, use_libprs_metadata=True) rd.request_body_file.seek(0) ids, duplicates = db.add_books([(mi, {fmt: rd.request_body_file})], add_duplicates=add_duplicates) ans = {'title': mi.title, 'authors': mi.authors, 'languages': mi.languages, 'filename': filename, 'id': job_id} if ids: ans['book_id'] = ids[0] books_added(ids) return ans
def convert(self, stream, options, file_ext, log, accelerators): from calibre.ebooks.metadata.opf2 import OPFCreator from calibre.ebooks.pdf.pdftohtml import pdftohtml log.debug('Converting file to html...') # The main html file will be named index.html self.opts, self.log = options, log if options.new_pdf_engine: return self.convert_new(stream, accelerators) pdftohtml(os.getcwdu(), stream.name, options.no_images) from calibre.ebooks.metadata.meta import get_metadata log.debug('Retrieving document metadata...') mi = get_metadata(stream, 'pdf') opf = OPFCreator(os.getcwdu(), mi) manifest = [(u'index.html', None)] images = os.listdir(os.getcwdu()) images.remove('index.html') for i in images: manifest.append((i, None)) log.debug('Generating manifest...') opf.create_manifest(manifest) opf.create_spine([u'index.html']) log.debug('Rendering manifest...') with open(u'metadata.opf', 'wb') as opffile: opf.render(opffile) return os.path.join(os.getcwdu(), u'metadata.opf')
def add_news(cache, path, arg, dbapi=None): from calibre.ebooks.metadata.meta import get_metadata from calibre.utils.date import utcnow fmt = os.path.splitext(getattr(path, 'name', path))[1][1:].lower() stream = path if hasattr(path, 'read') else lopen(path, 'rb') stream.seek(0) mi = get_metadata(stream, fmt, use_libprs_metadata=False, force_read_metadata=True) # Force the author to calibre as the auto delete of old news checks for # both the author==calibre and the tag News mi.authors = ['calibre'] stream.seek(0) with cache.write_lock: if mi.series_index is None: mi.series_index = cache._get_next_series_num_for(mi.series) mi.tags = [_('News')] if arg['add_title_tag']: mi.tags += [arg['title']] if arg['custom_tags']: mi.tags += arg['custom_tags'] if mi.pubdate is None: mi.pubdate = utcnow() if mi.timestamp is None: mi.timestamp = utcnow() db_id = cache._create_book_entry(mi, apply_import_tags=False) cache.add_format(db_id, fmt, stream, dbapi=dbapi) # Cant keep write lock since post-import hooks might run if not hasattr(path, 'read'): stream.close() return db_id
def get_selected_format_metadata(self, db, id_): old = prefs['read_file_metadata'] if not old: prefs['read_file_metadata'] = True try: row = self.formats.currentRow() fmt = self.formats.item(row) if fmt is None: if self.formats.count() == 1: fmt = self.formats.item(0) if fmt is None: error_dialog(self, _('No format selected'), _('No format selected')).exec_() return None, None ext = fmt.ext.lower() if fmt.path is None: stream = db.format(id_, ext, as_file=True, index_is_id=True) else: stream = open(fmt.path, 'r+b') try: with stream: mi = get_metadata(stream, ext) return mi, ext except: error_dialog(self, _('Could not read metadata'), _('Could not read metadata from %s format') % ext).exec_() return None, None finally: if old != prefs['read_file_metadata']: prefs['read_file_metadata'] = old
def add_news(cache, path, arg): from calibre.ebooks.metadata.meta import get_metadata from calibre.utils.date import utcnow fmt = os.path.splitext(getattr(path, 'name', path))[1][1:].lower() stream = path if hasattr(path, 'read') else lopen(path, 'rb') stream.seek(0) mi = get_metadata(stream, fmt, use_libprs_metadata=False, force_read_metadata=True) # Force the author to calibre as the auto delete of old news checks for # both the author==calibre and the tag News mi.authors = ['calibre'] stream.seek(0) with cache.write_lock: if mi.series_index is None: mi.series_index = cache._get_next_series_num_for(mi.series) mi.tags = [_('News')] if arg['add_title_tag']: mi.tags += [arg['title']] if arg['custom_tags']: mi.tags += arg['custom_tags'] if mi.pubdate is None: mi.pubdate = utcnow() if mi.timestamp is None: mi.timestamp = utcnow() db_id = cache._create_book_entry(mi, apply_import_tags=False) cache.add_format(db_id, fmt, stream) # Cant keep write lock since post-import hooks might run if not hasattr(path, 'read'): stream.close() return db_id
def _get_metadata(self, id, args, kwargs): from calibre.ebooks.metadata.meta import get_metadata try: mi = get_metadata(*args, **kwargs) except: mi = MetaInformation('', [_('Unknown')]) self.metadata.emit(id, mi)
def test_srv_add_book(self): # {{{ with self.create_server(auth=True, auth_mode='basic') as server: server.handler.ctx.user_manager.add_user('12', 'test') server.handler.ctx.user_manager.add_user('ro', 'test', readonly=True) conn = server.connect() ae = self.assertEqual def a(filename, data=None, status=OK, method='POST', username='******', add_duplicates='n', job_id=1): r, data = make_request(conn, '/cdb/add-book/{}/{}/{}'.format(job_id, add_duplicates, quote(filename.encode('utf-8')).decode('ascii')), username=username, password='******', prefix='', method=method, data=data) ae(status, r.status) return data def d(book_ids, username='******', status=OK): book_ids = ','.join(map(str, book_ids)) r, data = make_request(conn, '/cdb/delete-books/{}'.format(book_ids), username=username, password='******', prefix='', method='POST') ae(status, r.status) return data a('test.epub', None, username='******', status=FORBIDDEN) content = b'content' filename = 'test add - XXX.txt' data = a(filename, content) s = BytesIO(content) s.name = filename mi = get_metadata(s, stream_type='txt') ae(data, {'title': mi.title, 'book_id': data['book_id'], 'authors': mi.authors, 'languages': mi.languages, 'id': '1', 'filename': filename}) r, q = make_request(conn, '/get/txt/{}'.format(data['book_id']), username='******', password='******', prefix='') ae(r.status, OK) ae(q, content) d((1,), username='******', status=FORBIDDEN) d((1, data['book_id']))
def add_quick_start_guide(library_view, db_images): from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks import calibre_cover from calibre.utils.zipfile import safe_replace from calibre.utils.localization import get_lang, canonicalize_lang from calibre.ptempfile import PersistentTemporaryFile l = canonicalize_lang(get_lang()) or "eng" gprefs["quick_start_guide_added"] = True imgbuf = BytesIO(calibre_cover(_("Quick Start Guide"), "", author_size=8)) try: with open(P("quick_start/%s.epub" % l), "rb") as src: buf = BytesIO(src.read()) except EnvironmentError as err: if err.errno != errno.ENOENT: raise with open(P("quick_start/eng.epub"), "rb") as src: buf = BytesIO(src.read()) safe_replace(buf, "images/cover.jpg", imgbuf) buf.seek(0) mi = get_metadata(buf, "epub") with PersistentTemporaryFile(".epub") as tmp: tmp.write(buf.getvalue()) library_view.model().add_books([tmp.name], ["epub"], [mi]) os.remove(tmp.name) library_view.model().books_added(1) if hasattr(db_images, "reset"): db_images.reset() if library_view.model().rowCount(None) < 3: library_view.resizeColumnsToContents()
def _get_metadata(self, id, args, kwargs): from calibre.ebooks.metadata.meta import get_metadata try: mi = get_metadata(*args, **kwargs) except: mi = MetaInformation('', [_('Unknown')]) self.emit(SIGNAL('metadata(PyQt_PyObject, PyQt_PyObject)'), id, mi)
def render(pathtoebook, output_dir, book_hash=None, serialize_metadata=False, extract_annotations=False): mi = None if serialize_metadata: from calibre.ebooks.metadata.meta import get_metadata from calibre.customize.ui import quick_metadata with lopen(pathtoebook, 'rb') as f, quick_metadata: mi = get_metadata(f, os.path.splitext(pathtoebook)[1][1:].lower()) container = Container(pathtoebook, output_dir, book_hash=book_hash, save_bookmark_data=extract_annotations, book_metadata=mi) if serialize_metadata: from calibre.utils.serialize import json_dumps from calibre.ebooks.metadata.book.serialize import metadata_as_dict d = metadata_as_dict(mi) d.pop('cover_data', None) serialize_datetimes(d), serialize_datetimes(d.get('user_metadata', {})) with lopen(os.path.join(output_dir, 'calibre-book-metadata.json'), 'wb') as f: f.write(json_dumps(d)) if extract_annotations: annotations = None if container.bookmark_data: annotations = json_dumps(tuple(get_stored_annotations(container))) if annotations: with lopen( os.path.join(output_dir, 'calibre-book-annotations.json'), 'wb') as f: f.write(annotations)
def convert(self, stream, options, file_ext, log, accelerators): from calibre.ebooks.metadata.opf2 import OPFCreator from calibre.ebooks.pdf.pdftohtml import pdftohtml log.debug('Converting file to html...') # The main html file will be named index.html self.opts, self.log = options, log if options.new_pdf_engine: return self.convert_new(stream, accelerators) pdftohtml(os.getcwdu(), stream.name, options.no_images) from calibre.ebooks.metadata.meta import get_metadata log.debug('Retrieving document metadata...') mi = get_metadata(stream, 'pdf') opf = OPFCreator(os.getcwdu(), mi) manifest = [(u'index.html', None)] images = os.listdir(os.getcwdu()) images.remove('index.html') for i in images: manifest.append((i, None)) log.debug('Generating manifest...') opf.create_manifest(manifest) opf.create_spine([u'index.html']) log.debug('Rendering manifest...') with open(u'metadata.opf', 'wb') as opffile: opf.render(opffile) return os.path.join(os.getcwdu(), u'metadata.opf')
def add_catalog(cache, path, title): from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.meta import get_metadata from calibre.utils.date import utcnow fmt = os.path.splitext(path)[1][1:].lower() with lopen(path, 'rb') as stream: with cache.write_lock: matches = cache._search( 'title:="%s" and tags:="%s"' % (title.replace('"', '\\"'), _('Catalog')), None) db_id = None if matches: db_id = list(matches)[0] try: mi = get_metadata(stream, fmt) mi.authors = ['calibre'] except: mi = Metadata(title, ['calibre']) mi.title, mi.authors = title, ['calibre'] mi.tags = [_('Catalog')] mi.pubdate = mi.timestamp = utcnow() if fmt == 'mobi': mi.cover, mi.cover_data = None, (None, None) if db_id is None: db_id = cache._create_book_entry(mi, apply_import_tags=False) else: cache._set_metadata(db_id, mi) cache.add_format( db_id, fmt, stream) # Cant keep write lock since post-import hooks might run return db_id
def render(pathtoebook, output_dir, book_hash=None, serialize_metadata=False, extract_annotations=False, virtualize_resources=True, max_workers=1): pathtoebook = os.path.abspath(pathtoebook) with RenderManager(max_workers) as render_manager: mi = None if serialize_metadata: from calibre.customize.ui import quick_metadata from calibre.ebooks.metadata.meta import get_metadata with lopen(pathtoebook, 'rb') as f, quick_metadata: mi = get_metadata(f, os.path.splitext(pathtoebook)[1][1:].lower()) book_fmt, opfpath, input_fmt = extract_book(pathtoebook, output_dir, log=default_log) container, bookmark_data = process_exploded_book( book_fmt, opfpath, input_fmt, output_dir, render_manager, book_hash=book_hash, save_bookmark_data=extract_annotations, book_metadata=mi, virtualize_resources=virtualize_resources ) if serialize_metadata: from calibre.ebooks.metadata.book.serialize import metadata_as_dict d = metadata_as_dict(mi) d.pop('cover_data', None) serialize_datetimes(d), serialize_datetimes(d.get('user_metadata', {})) with lopen(os.path.join(output_dir, 'calibre-book-metadata.json'), 'wb') as f: f.write(json_dumps(d)) if extract_annotations: annotations = None if bookmark_data: annotations = json_dumps(tuple(get_stored_annotations(container, bookmark_data))) if annotations: with lopen(os.path.join(output_dir, 'calibre-book-annotations.json'), 'wb') as f: f.write(annotations)
def add_quick_start_guide(library_view, refresh_cover_browser=None): from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks import calibre_cover from calibre.utils.zipfile import safe_replace from calibre.utils.localization import get_lang, canonicalize_lang from calibre.ptempfile import PersistentTemporaryFile l = canonicalize_lang(get_lang()) or 'eng' gprefs['quick_start_guide_added'] = True imgbuf = BytesIO(calibre_cover(_('Quick Start Guide'), '', author_size=8)) try: with open(P('quick_start/%s.epub' % l), 'rb') as src: buf = BytesIO(src.read()) except EnvironmentError as err: if err.errno != errno.ENOENT: raise with open(P('quick_start/eng.epub'), 'rb') as src: buf = BytesIO(src.read()) safe_replace(buf, 'images/cover.jpg', imgbuf) buf.seek(0) mi = get_metadata(buf, 'epub') with PersistentTemporaryFile('.epub') as tmp: tmp.write(buf.getvalue()) library_view.model().add_books([tmp.name], ['epub'], [mi]) os.remove(tmp.name) library_view.model().books_added(1) if refresh_cover_browser is not None: refresh_cover_browser() if library_view.model().rowCount(None) < 3: library_view.resizeColumnsToContents()
def get_selected_format_metadata(self, db, id_): old = prefs['read_file_metadata'] if not old: prefs['read_file_metadata'] = True try: row = self.formats.currentRow() fmt = self.formats.item(row) if fmt is None: if self.formats.count() == 1: fmt = self.formats.item(0) if fmt is None: error_dialog(self, _('No format selected'), _('No format selected')).exec_() return None, None ext = fmt.ext.lower() if fmt.path is None: stream = db.format(id_, ext, as_file=True, index_is_id=True) else: stream = open(fmt.path, 'r+b') try: with stream: mi = get_metadata(stream, ext) return mi, ext except: error_dialog(self, _('Could not read metadata'), _('Could not read metadata from %s format')%ext).exec_() return None, None finally: if old != prefs['read_file_metadata']: prefs['read_file_metadata'] = old
def add_catalog(cache, path, title, dbapi=None): from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.meta import get_metadata from calibre.utils.date import utcnow fmt = os.path.splitext(path)[1][1:].lower() new_book_added = False with lopen(path, 'rb') as stream: with cache.write_lock: matches = cache._search('title:="%s" and tags:="%s"' % (title.replace('"', '\\"'), _('Catalog')), None) db_id = None if matches: db_id = list(matches)[0] try: mi = get_metadata(stream, fmt) mi.authors = ['calibre'] except: mi = Metadata(title, ['calibre']) mi.title, mi.authors = title, ['calibre'] mi.author_sort = 'calibre' # The MOBI/AZW3 format sets author sort to date mi.tags = [_('Catalog')] mi.pubdate = mi.timestamp = utcnow() if fmt == 'mobi': mi.cover, mi.cover_data = None, (None, None) if db_id is None: db_id = cache._create_book_entry(mi, apply_import_tags=False) new_book_added = True else: cache._set_metadata(db_id, mi) cache.add_format(db_id, fmt, stream, dbapi=dbapi) # Cant keep write lock since post-import hooks might run return db_id, new_book_added
def add_quick_start_guide(library_view, refresh_cover_browser=None): from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks.covers import calibre_cover2 from calibre.utils.zipfile import safe_replace from calibre.utils.localization import get_lang, canonicalize_lang from calibre.ptempfile import PersistentTemporaryFile l = canonicalize_lang(get_lang()) or 'eng' gprefs['quick_start_guide_added'] = True imgbuf = BytesIO(calibre_cover2(_('Quick Start Guide'), '')) try: with lopen(P('quick_start/%s.epub' % l), 'rb') as src: buf = BytesIO(src.read()) except EnvironmentError as err: if err.errno != errno.ENOENT: raise with lopen(P('quick_start/eng.epub'), 'rb') as src: buf = BytesIO(src.read()) safe_replace(buf, 'images/cover.jpg', imgbuf) buf.seek(0) mi = get_metadata(buf, 'epub') with PersistentTemporaryFile('.epub') as tmp: tmp.write(buf.getvalue()) library_view.model().add_books([tmp.name], ['epub'], [mi]) os.remove(tmp.name) library_view.model().books_added(1) if refresh_cover_browser is not None: refresh_cover_browser() if library_view.model().rowCount(None) < 3: library_view.resizeColumnsToContents()
def test_srv_add_book(self): # {{{ with self.create_server(auth=True, auth_mode='basic') as server: server.handler.ctx.user_manager.add_user('12', 'test') server.handler.ctx.user_manager.add_user('ro', 'test', readonly=True) conn = server.connect() ae = self.assertEqual def a(filename, data=None, status=OK, method='POST', username='******', add_duplicates='n', job_id=1): r, data = make_request(conn, '/cdb/add-book/{}/{}/{}'.format(job_id, add_duplicates, quote(filename.encode('utf-8'))), username=username, password='******', prefix='', method=method, data=data) ae(status, r.status) return data def d(book_ids, username='******', status=OK): book_ids = ','.join(map(str, book_ids)) r, data = make_request(conn, '/cdb/delete-books/{}'.format(book_ids), username=username, password='******', prefix='', method='POST') ae(status, r.status) return data a('test.epub', None, username='******', status=FORBIDDEN) content = b'content' filename = 'test add - XXX.txt' data = a(filename, content) s = BytesIO(content) s.name = filename mi = get_metadata(s, stream_type='txt') ae(data, {'title': mi.title, 'book_id': data['book_id'], 'authors': mi.authors, 'languages': mi.languages, 'id': '1', 'filename': filename}) r, q = make_request(conn, '/get/txt/{}'.format(data['book_id']), username='******', password='******', prefix='') ae(r.status, OK) ae(q, content) d((1,), username='******', status=FORBIDDEN) d((1, data['book_id']))
def _get_metadata(self, id, args, kwargs): from calibre.ebooks.metadata.meta import get_metadata try: mi = get_metadata(*args, **kwargs) except: mi = MetaInformation('', [_('Unknown')]) self.emit(SIGNAL('metadata(PyQt_PyObject, PyQt_PyObject)'), id, mi)
def _get_metadata(self, id, args, kwargs): from calibre.ebooks.metadata.meta import get_metadata try: mi = get_metadata(*args, **kwargs) except: mi = MetaInformation('', [_('Unknown')]) self.metadata.emit(id, mi)
def run(self, path_to_ebook): from calibre.ebooks.metadata.meta import get_metadata, set_metadata with open(path_to_ebook, 'r+b') as file: ext = os.path.splitext(path_to_ebook)[-1][1:].lower() mi = get_metadata(file, ext) mi.publisher = 'Hello World' set_metadata(file, mi, ext) return path_to_ebook
def run(self, path_to_ebook): from calibre.ebooks.metadata.meta import get_metadata, set_metadata file = open(path_to_ebook, 'r+b') ext = os.path.splitext(path_to_ebook)[-1][1:].lower() mi = get_metadata(file, ext) mi.publisher = 'Hello World' set_metadata(file, mi, ext) return path_to_ebook
def run(self, path_to_ebook): # print("run FanficAuthorsNetCSSFix") # logger.warn("logger") book_format = 'epub' ## Really crude brute force check to see if it's a ## fanficauthors.net epub: epub = ZipFile( path_to_ebook, 'r') # works equally well with inputio as a path or a blob tocfile = "content/toc.ncx" if not (tocfile in epub.namelist() and "fanficauthors.net" in epub.read(tocfile)): # bail without doing anything return path_to_ebook print("It's a fanficauthors.net epub!") tmpfile = self.temporary_file('.' + book_format) outputepub = ZipFile(tmpfile, "w", compression=ZIP_STORED) outputepub.debug = 3 outputepub.writestr("mimetype", "application/epub+zip") outputepub.close() ## Re-open file for content. outputepub = ZipFile(tmpfile, "a", compression=ZIP_DEFLATED) outputepub.debug = 3 for fname in epub.namelist(): if fname.endswith('.html'): outputepub.writestr( fname, epub.read(fname).replace( """body { margin-top: 0px; padding-top: 0px; }""", """body { background-color: #FFFFFF; text-align: justify; margin: 2%; adobe-hyphenate: none; }""")) elif fname != "mimetype": outputepub.writestr(fname, epub.read(fname)) for zf in outputepub.filelist: zf.create_system = 0 outputepub.close() # file = open(path_to_ebook, 'r+b') ext = os.path.splitext(path_to_ebook)[-1][1:].lower() mi = get_metadata(tmpfile, ext) mi.publisher = "fanficauthors.net" set_metadata(tmpfile, mi, ext) # return path_to_ebook return tmpfile.name
def read_file_metadata(self, mtp_file): from calibre.ebooks.metadata.meta import get_metadata from calibre.customize.ui import quick_metadata ext = mtp_file.name.rpartition('.')[-1].lower() stream = self.get_mtp_file(mtp_file) with quick_metadata: return get_metadata(stream, stream_type=ext, force_read_metadata=True, pattern=self.build_template_regexp())
def convert(self, stream, options, file_ext, log, accelerators): from calibre.ebooks.metadata.toc import TOC from calibre.ebooks.metadata.opf2 import OPFCreator from calibre.utils.zipfile import ZipFile self.options = options self.log = log pages, images = [], [] toc = TOC() if file_ext == 'pmlz': log.debug('De-compressing content to temporary directory...') with TemporaryDirectory('_unpmlz') as tdir: zf = ZipFile(stream) zf.extractall(tdir) pmls = glob.glob(os.path.join(tdir, '*.pml')) for pml in pmls: html_name = os.path.splitext( os.path.basename(pml))[0] + '.html' html_path = os.path.join(os.getcwd(), html_name) pages.append(html_name) log.debug('Processing PML item %s...' % pml) ttoc = self.process_pml(pml, html_path) toc += ttoc images = self.get_images(stream, tdir, True) else: toc = self.process_pml(stream, 'index.html') pages.append('index.html') if hasattr(stream, 'name'): images = self.get_images( stream, os.path.abspath(os.path.dirname(stream.name))) # We want pages to be ordered alphabetically. pages.sort() manifest_items = [] for item in pages + images: manifest_items.append((item, None)) from calibre.ebooks.metadata.meta import get_metadata log.debug('Reading metadata from input file...') mi = get_metadata(stream, 'pml') if 'images/cover.png' in images: mi.cover = 'images/cover.png' opf = OPFCreator(os.getcwd(), mi) log.debug('Generating manifest...') opf.create_manifest(manifest_items) opf.create_spine(pages) opf.set_toc(toc) with lopen('metadata.opf', 'wb') as opffile: with lopen('toc.ncx', 'wb') as tocfile: opf.render(opffile, tocfile, 'toc.ncx') return os.path.join(os.getcwd(), 'metadata.opf')
def convert(self, stream, options, file_ext, log, accelerators): from calibre.ebooks.metadata.toc import TOC from calibre.ebooks.metadata.opf2 import OPFCreator from calibre.utils.zipfile import ZipFile self.options = options self.log = log pages, images = [], [] toc = TOC() if file_ext == 'pmlz': log.debug('De-compressing content to temporary directory...') with TemporaryDirectory('_unpmlz') as tdir: zf = ZipFile(stream) zf.extractall(tdir) pmls = glob.glob(os.path.join(tdir, '*.pml')) for pml in pmls: html_name = os.path.splitext(os.path.basename(pml))[0]+'.html' html_path = os.path.join(getcwd(), html_name) pages.append(html_name) log.debug('Processing PML item %s...' % pml) ttoc = self.process_pml(pml, html_path) toc += ttoc images = self.get_images(stream, tdir, True) else: toc = self.process_pml(stream, 'index.html') pages.append('index.html') if hasattr(stream, 'name'): images = self.get_images(stream, os.path.abspath(os.path.dirname(stream.name))) # We want pages to be orded alphabetically. pages.sort() manifest_items = [] for item in pages+images: manifest_items.append((item, None)) from calibre.ebooks.metadata.meta import get_metadata log.debug('Reading metadata from input file...') mi = get_metadata(stream, 'pml') if 'images/cover.png' in images: mi.cover = 'images/cover.png' opf = OPFCreator(getcwd(), mi) log.debug('Generating manifest...') opf.create_manifest(manifest_items) opf.create_spine(pages) opf.set_toc(toc) with lopen('metadata.opf', 'wb') as opffile: with lopen('toc.ncx', 'wb') as tocfile: opf.render(opffile, tocfile, 'toc.ncx') return os.path.join(getcwd(), 'metadata.opf')
def run(self, path_to_ebook): from calibre.ebooks.metadata.meta import get_metadata, set_metadata file = open(path_to_ebook, 'r+b') ext = os.path.splitext(path_to_ebook)[-1][1:].lower() mi = get_metadata(file, ext) outfile = run_on_file(path_to_ebook) set_metadata(outfile, mi, 'mp3') return path_to_ebook
def get_metadata(stream): from calibre.ebooks.metadata.archive import is_comic from calibre.ebooks.metadata.meta import get_metadata file_names = list(names(stream)) if is_comic(file_names): return get_metadata(stream, 'cbr') for f in file_names: stream_type = os.path.splitext(f)[1].lower() if stream_type: stream_type = stream_type[1:] if stream_type in {'lit', 'opf', 'prc', 'mobi', 'fb2', 'epub', 'rb', 'imp', 'pdf', 'lrf', 'azw', 'azw1', 'azw3'}: name, data = extract_member(stream, match=None, name=f) stream = BytesIO(data) stream.name = os.path.basename(name) return get_metadata(stream, stream_type) raise ValueError('No ebook found in RAR archive')
def set_cover_from_format(self, book_id, fmt): from calibre.ebooks.metadata.meta import get_metadata from calibre.utils.config import prefs fmt = fmt.lower() cdata = None db = self.gui.current_db.new_api if fmt == 'pdf': pdfpath = db.format_abspath(book_id, fmt) if pdfpath is None: return error_dialog(self.gui, _('Format file missing'), _( 'Cannot read cover as the %s file is missing from this book') % 'PDF', show=True) from calibre.gui2.metadata.pdf_covers import PDFCovers d = PDFCovers(pdfpath, parent=self.gui) ret = d.exec_() if ret == QDialog.DialogCode.Accepted: cpath = d.cover_path if cpath: with open(cpath, 'rb') as f: cdata = f.read() d.cleanup() if ret != QDialog.DialogCode.Accepted: return else: stream = BytesIO() try: db.copy_format_to(book_id, fmt, stream) except NoSuchFormat: return error_dialog(self.gui, _('Format file missing'), _( 'Cannot read cover as the %s file is missing from this book') % fmt.upper(), show=True) old = prefs['read_file_metadata'] if not old: prefs['read_file_metadata'] = True try: stream.seek(0) mi = get_metadata(stream, fmt) except Exception: import traceback return error_dialog(self.gui, _('Could not read metadata'), _('Could not read metadata from %s format')%fmt.upper(), det_msg=traceback.format_exc(), show=True) finally: if old != prefs['read_file_metadata']: prefs['read_file_metadata'] = old if mi.cover and os.access(mi.cover, os.R_OK): with open(mi.cover, 'rb') as f: cdata = f.read() elif mi.cover_data[1] is not None: cdata = mi.cover_data[1] if cdata is None: return error_dialog(self.gui, _('Could not read cover'), _('Could not read cover from %s format')%fmt.upper(), show=True) db.set_cover({book_id:cdata}) current_idx = self.gui.library_view.currentIndex() self.gui.library_view.model().current_changed(current_idx, current_idx) self.gui.refresh_cover_browser()
def set_cover_from_format(self, book_id, fmt): from calibre.utils.config import prefs from calibre.ebooks.metadata.meta import get_metadata fmt = fmt.lower() cdata = None db = self.gui.current_db.new_api if fmt == 'pdf': pdfpath = db.format_abspath(book_id, fmt) if pdfpath is None: return error_dialog(self.gui, _('Format file missing'), _( 'Cannot read cover as the %s file is missing from this book') % 'PDF', show=True) from calibre.gui2.metadata.pdf_covers import PDFCovers d = PDFCovers(pdfpath, parent=self.gui) ret = d.exec_() if ret == d.Accepted: cpath = d.cover_path if cpath: with open(cpath, 'rb') as f: cdata = f.read() d.cleanup() if ret != d.Accepted: return else: stream = BytesIO() try: db.copy_format_to(book_id, fmt, stream) except NoSuchFormat: return error_dialog(self.gui, _('Format file missing'), _( 'Cannot read cover as the %s file is missing from this book') % fmt.upper(), show=True) old = prefs['read_file_metadata'] if not old: prefs['read_file_metadata'] = True try: stream.seek(0) mi = get_metadata(stream, fmt) except Exception: import traceback return error_dialog(self.gui, _('Could not read metadata'), _('Could not read metadata from %s format')%fmt.upper(), det_msg=traceback.format_exc(), show=True) finally: if old != prefs['read_file_metadata']: prefs['read_file_metadata'] = old if mi.cover and os.access(mi.cover, os.R_OK): cdata = open(mi.cover).read() elif mi.cover_data[1] is not None: cdata = mi.cover_data[1] if cdata is None: return error_dialog(self.gui, _('Could not read cover'), _('Could not read cover from %s format')%fmt.upper(), show=True) db.set_cover({book_id:cdata}) current_idx = self.gui.library_view.currentIndex() self.gui.library_view.model().current_changed(current_idx, current_idx) self.gui.refresh_cover_browser()
def get_metadata(stream): from calibre.ebooks.metadata.archive import is_comic from calibre.ebooks.metadata.meta import get_metadata path = getattr(stream, "name", False) if not path: pt = PersistentTemporaryFile("_rar-meta.rar") pt.write(stream.read()) pt.close() path = pt.name path = os.path.abspath(path) file_names = list(names(path)) if is_comic(file_names): return get_metadata(stream, "cbr") for f in file_names: stream_type = os.path.splitext(f)[1].lower() if stream_type: stream_type = stream_type[1:] if stream_type in ( "lit", "opf", "prc", "mobi", "fb2", "epub", "rb", "imp", "pdf", "lrf", "azw", "azw1", "azw3", ): with TemporaryDirectory() as tdir: with CurrentDir(tdir): stream = extract_member(path, match=None, name=f, as_file=True)[1] return get_metadata(stream, stream_type) raise ValueError("No ebook found in RAR archive")
def run(self, path_to_ebook): from calibre.ebooks.metadata.meta import get_metadata, set_metadata file = open(path_to_ebook, 'r+b') ext = os.path.splitext(path_to_ebook)[-1][1:].lower() mi = get_metadata(file, ext) genresonbook = [element.lower() for element in mi.tags] mi.tags = self.new_genre_list(genresonbook) set_metadata(file, mi, ext) print(mi) print(genresonbook) return path_to_ebook
def run(self, path_to_ebook): from calibre.ebooks.metadata.meta import get_metadata, set_metadata file = open(path_to_ebook, 'r+b') ext = os.path.splitext(path_to_ebook)[-1][1:].lower() mi = get_metadata(file, ext) genresonbook = [element.lower() for element in mi.tags] mi.tags = self.new_genre_list(genresonbook) set_metadata(file, mi, ext) print(mi) print(genresonbook) return path_to_ebook
def _add(self, filename, gui, add_to_lib, tags): if not add_to_lib or not filename: return ext = os.path.splitext(filename)[1][1:].lower() if ext not in BOOK_EXTENSIONS: raise Exception(_('Not a support e-book format.')) from calibre.ebooks.metadata.meta import get_metadata with open(filename, 'rb') as f: mi = get_metadata(f, ext, force_read_metadata=True) mi.tags.extend(tags) id = gui.library_view.model().db.create_book_entry(mi) gui.library_view.model().db.add_format_with_hooks(id, ext.upper(), filename, index_is_id=True) gui.library_view.model().books_added(1) gui.library_view.model().count_changed()
def _add(self, filename, gui, add_to_lib, tags): if not add_to_lib or not filename: return ext = os.path.splitext(filename)[1][1:].lower() if ext not in BOOK_EXTENSIONS: raise Exception(_('Not a support ebook format.')) from calibre.ebooks.metadata.meta import get_metadata with open(filename, 'rb') as f: mi = get_metadata(f, ext, force_read_metadata=True) mi.tags.extend(tags) id = gui.library_view.model().db.create_book_entry(mi) gui.library_view.model().db.add_format_with_hooks(id, ext.upper(), filename, index_is_id=True) gui.library_view.model().books_added(1) gui.library_view.model().count_changed()
def book(db, notify_changes, is_remote, args): data, fname, fmt, add_duplicates, otitle, oauthors, oisbn, otags, oseries, oseries_index, ocover, oidentifiers, olanguages = args with add_ctx(), TemporaryDirectory( 'add-single') as tdir, run_import_plugins_before_metadata(tdir): if is_remote: with lopen(os.path.join(tdir, fname), 'wb') as f: f.write(data[1]) path = f.name else: path = data path = run_import_plugins([path])[0] fmt = os.path.splitext(path)[1] fmt = (fmt[1:] if fmt else None) or 'unknown' with lopen(path, 'rb') as stream: mi = get_metadata(stream, stream_type=fmt, use_libprs_metadata=True) if not mi.title: mi.title = os.path.splitext(os.path.basename(path))[0] if not mi.authors: mi.authors = [_('Unknown')] if oidentifiers: ids = mi.get_identifiers() ids.update(oidentifiers) mi.set_identifiers(ids) for x in ('title', 'authors', 'isbn', 'tags', 'series', 'languages'): val = locals()['o' + x] if val: setattr(mi, x, val) if oseries: mi.series_index = oseries_index if ocover: mi.cover = None mi.cover_data = ocover ids, duplicates = db.add_books([(mi, { fmt: path })], add_duplicates=add_duplicates, run_hooks=False) if is_remote: notify_changes(books_added(ids)) db.dump_metadata() return ids, bool(duplicates), mi.title
def run(self, path_to_ebook): from calibre.ebooks.metadata.meta import get_metadata from calibre.library import db import time file = open(path_to_ebook, 'r+b') ext = os.path.splitext(path_to_ebook)[-1][1:].lower() mi = get_metadata(file, ext) db = db('C:/Users/jmoor/Docs/eBooks/Calibre').new_api title = mi.title author = mi.authors[0] ids = list(db.search('title:' + title + ' author:' + author)) db.remove_formats({ids[0]: ['ORIGINAL_MOBI', 'epub', 'azw3']}) searchResults = db.search('formats:"=ORIGINAL_MOBI"') for bookId in searchResults: try: db.remove_formats({bookId: ['original_mobi']}) except: pass
def get_decrypted_kobo_books(self, book): ''' This method is a call-back function used by DecryptAddProgressDialog in dialogs.py to decrypt Kobo books :param book: A KoboBook object that is to be decrypted. ''' print (_('{0} - Decrypting {1}').format(PLUGIN_NAME + ' v' + PLUGIN_VERSION, book.title)) decrypted = self.decryptBook(book) if decrypted['success']: # Build a list of calibre "book maps" for calibre's add_book function. mi = get_metadata(decrypted['fileobj'], 'epub') bookmap = {'EPUB':decrypted['fileobj'].name} self.books_to_add.append((mi, bookmap)) else: # Book is probably still encrypted. print (_('{0} - Couldn\'t decrypt {1}').format(PLUGIN_NAME + ' v' + PLUGIN_VERSION, book.title)) self.decryption_errors.append((book.title, _('decryption errors'))) return False return True
def get_decrypted_kobo_books(self, book): ''' This method is a call-back function used by DecryptAddProgressDialog in dialogs.py to decrypt Kobo books :param book: A KoboBook object that is to be decrypted. ''' print (_('{0} - Decrypting {1}').format(PLUGIN_NAME + ' v' + PLUGIN_VERSION, book.title)) decrypted = self.decryptBook(book) if decrypted['success']: # Build a list of calibre "book maps" for calibre's add_book function. mi = get_metadata(decrypted['fileobj'], 'epub') bookmap = {'EPUB':decrypted['fileobj'].name} self.books_to_add.append((mi, bookmap)) else: # Book is probably still encrypted. print (_('{0} - Couldn\'t decrypt {1}').format(PLUGIN_NAME + ' v' + PLUGIN_VERSION, book.title)) self.decryption_errors.append((book.title, _('decryption errors'))) return False return True
def book(db, notify_changes, is_remote, args): data, fname, fmt, add_duplicates, otitle, oauthors, oisbn, otags, oseries, oseries_index, ocover, oidentifiers, olanguages = args with add_ctx(), TemporaryDirectory('add-single') as tdir, run_import_plugins_before_metadata(tdir): if is_remote: with lopen(os.path.join(tdir, fname), 'wb') as f: f.write(data[1]) path = f.name else: path = data path = run_import_plugins([path])[0] fmt = os.path.splitext(path)[1] fmt = (fmt[1:] if fmt else None) or 'unknown' with lopen(path, 'rb') as stream: mi = get_metadata(stream, stream_type=fmt, use_libprs_metadata=True) if not mi.title: mi.title = os.path.splitext(os.path.basename(path))[0] if not mi.authors: mi.authors = [_('Unknown')] if oidentifiers: ids = mi.get_identifiers() ids.update(oidentifiers) mi.set_identifiers(ids) for x in ('title', 'authors', 'isbn', 'tags', 'series', 'languages'): val = locals()['o' + x] if val: setattr(mi, x, val) if oseries: mi.series_index = oseries_index if ocover: mi.cover = None mi.cover_data = ocover ids, duplicates = db.add_books( [(mi, {fmt: path})], add_duplicates=add_duplicates, run_hooks=False) if is_remote: notify_changes(books_added(ids)) db.dump_metadata() return ids, bool(duplicates), mi.title
def convert(self, stream, options, file_ext, log, accelerators): from calibre.ebooks.metadata.opf2 import OPFCreator from calibre.ebooks.pdf.pdftohtml import pdftohtml log.debug('Converting file to html...') # The main html file will be named index.html self.opts, self.log = options, log if options.new_pdf_engine: return self.convert_new(stream, accelerators) pdftohtml(os.getcwd(), stream.name, options.no_images) from calibre.ebooks.metadata.meta import get_metadata log.debug('Retrieving document metadata...') mi = get_metadata(stream, 'pdf') opf = OPFCreator(os.getcwd(), mi) manifest = [('index.html', None)] images = os.listdir(os.getcwd()) images.remove('index.html') for i in images: manifest.append((i, None)) log.debug('Generating manifest...') opf.create_manifest(manifest) opf.create_spine(['index.html']) log.debug('Rendering manifest...') with lopen('metadata.opf', 'wb') as opffile: opf.render(opffile) if os.path.exists('toc.ncx'): ncxid = opf.manifest.id_for_path('toc.ncx') if ncxid: with lopen('metadata.opf', 'r+b') as f: raw = f.read().replace( b'<spine', b'<spine toc="%s"' % as_bytes(ncxid)) f.seek(0) f.write(raw) return os.path.join(os.getcwd(), 'metadata.opf')
def convert(self, stream, options, file_ext, log, accelerators): from calibre.ebooks.metadata.opf2 import OPFCreator from calibre.ebooks.pdf.pdftohtml import pdftohtml log.debug('Converting file to html...') # The main html file will be named index.html self.opts, self.log = options, log if options.new_pdf_engine: return self.convert_new(stream, accelerators) pdftohtml(getcwd(), stream.name, options.no_images) from calibre.ebooks.metadata.meta import get_metadata log.debug('Retrieving document metadata...') mi = get_metadata(stream, 'pdf') opf = OPFCreator(getcwd(), mi) manifest = [('index.html', None)] images = os.listdir(getcwd()) images.remove('index.html') for i in images: manifest.append((i, None)) log.debug('Generating manifest...') opf.create_manifest(manifest) opf.create_spine(['index.html']) log.debug('Rendering manifest...') with lopen('metadata.opf', 'wb') as opffile: opf.render(opffile) if os.path.exists('toc.ncx'): ncxid = opf.manifest.id_for_path('toc.ncx') if ncxid: with lopen('metadata.opf', 'r+b') as f: raw = f.read().replace(b'<spine', b'<spine toc="%s"' % as_bytes(ncxid)) f.seek(0) f.write(raw) return os.path.join(getcwd(), 'metadata.opf')
def __call__(self, stream, odir, log): from calibre.utils.zipfile import ZipFile from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks.metadata.opf2 import OPFCreator if not os.path.exists(odir): os.makedirs(odir) with CurrentDir(odir): log('Extracting ODT file...') html = self.odf2xhtml(stream) # A blanket img specification like this causes problems # with EPUB output as the containing element often has # an absolute height and width set that is larger than # the available screen real estate html = html.replace('img { width: 100%; height: 100%; }', '') try: html = self.fix_markup(html, log) except: log.exception('Failed to filter CSS, conversion may be slow') with open('index.xhtml', 'wb') as f: f.write(html.encode('utf-8')) zf = ZipFile(stream, 'r') self.extract_pictures(zf) stream.seek(0) mi = get_metadata(stream, 'odt') if not mi.title: mi.title = _('Unknown') if not mi.authors: mi.authors = [_('Unknown')] opf = OPFCreator(os.path.abspath(os.getcwdu()), mi) opf.create_manifest([(os.path.abspath(f), None) for f in walk(os.getcwdu())]) opf.create_spine([os.path.abspath('index.xhtml')]) with open('metadata.opf', 'wb') as f: opf.render(f) return os.path.abspath('metadata.opf')
def book_upload(self, ebook_file=None, generate_fmt=False): from calibre.ebooks.metadata import MetaInformation cherrypy.response.timeout = 3600 name = ebook_file.filename fmt = os.path.splitext(name)[1] fmt = fmt[1:] if fmt else None if not fmt: return "bad file name: %s" % name fmt = fmt.lower() # save file data = '' while True: d = ebook_file.file.read(8192) data += d if not d: break fpath = "/tmp/" + name open(fpath, "wb").write(data) # read ebook meta stream = open(fpath, 'rb') mi = get_metadata(stream, stream_type=fmt, use_libprs_metadata=True) books = self.db.books_with_same_title(mi) if books: book_id = books.pop() raise cherrypy.HTTPRedirect('/book/%d' % book_id) fpaths = [fpath] self.generate_books(mi, fpath, fmt) book_id = self.db.import_book(mi, fpaths) messages.append({ 'status': 'success', 'msg': _("import books success") }) raise cherrypy.HTTPRedirect('/book/%d' % book_id)
def get_cover_data(stream, ext): # {{{ from calibre.ebooks.metadata.meta import get_metadata old = prefs['read_file_metadata'] if not old: prefs['read_file_metadata'] = True cdata = area = None try: with stream: mi = get_metadata(stream, ext) if mi.cover and os.access(mi.cover, os.R_OK): cdata = open(mi.cover).read() elif mi.cover_data[1] is not None: cdata = mi.cover_data[1] if cdata: width, height, fmt = identify_data(cdata) area = width*height except: cdata = area = None if old != prefs['read_file_metadata']: prefs['read_file_metadata'] = old return cdata, area
def __call__(self, stream, odir, log): from calibre.utils.zipfile import ZipFile from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks.metadata.opf2 import OPFCreator if not os.path.exists(odir): os.makedirs(odir) with CurrentDir(odir): log('Extracting ODT file...') html = self.odf2xhtml(stream) # A blanket img specification like this causes problems # with EPUB output as the containing element often has # an absolute height and width set that is larger than # the available screen real estate html = html.replace('img { width: 100%; height: 100%; }', '') try: html = self.fix_markup(html, log) except: log.exception('Failed to filter CSS, conversion may be slow') with open('index.xhtml', 'wb') as f: f.write(html.encode('utf-8')) zf = ZipFile(stream, 'r') self.extract_pictures(zf) stream.seek(0) mi = get_metadata(stream, 'odt') if not mi.title: mi.title = _('Unknown') if not mi.authors: mi.authors = [_('Unknown')] opf = OPFCreator(os.path.abspath(os.getcwdu()), mi) opf.create_manifest([(os.path.abspath(f), None) for f in walk(os.getcwdu())]) opf.create_spine([os.path.abspath('index.xhtml')]) with open('metadata.opf', 'wb') as f: opf.render(f) return os.path.abspath('metadata.opf')
def do_add( dbctx, paths, one_book_per_directory, recurse, add_duplicates, otitle, oauthors, oisbn, otags, oseries, oseries_index, ocover, oidentifiers, olanguages, compiled_rules ): with add_ctx(): files, dirs = [], [] for path in paths: path = os.path.abspath(path) if os.path.isdir(path): dirs.append(path) else: if os.path.exists(path): files.append(path) else: prints(path, 'not found') file_duplicates, added_ids = [], set() for book in files: fmt = os.path.splitext(book)[1] fmt = fmt[1:] if fmt else None if not fmt: continue ids, dups, book_title = dbctx.run( 'add', 'book', dbctx.path(book), os.path.basename(book), fmt, add_duplicates, otitle, oauthors, oisbn, otags, oseries, oseries_index, serialize_cover(ocover) if ocover else None, oidentifiers, olanguages ) added_ids |= set(ids) if dups: file_duplicates.append((book_title, book)) dir_dups = [] scanner = cdb_recursive_find if recurse else cdb_find_in_dir for dpath in dirs: for formats in scanner(dpath, one_book_per_directory, compiled_rules): cover_data = None for fmt in formats: if fmt.lower().endswith('.opf'): with lopen(fmt, 'rb') as f: mi = get_metadata(f, stream_type='opf') if mi.cover_data and mi.cover_data[1]: cover_data = mi.cover_data[1] elif mi.cover: try: with lopen(mi.cover, 'rb') as f: cover_data = f.read() except EnvironmentError: pass book_title, ids, dups = dbctx.run( 'add', 'format_group', tuple(map(dbctx.path, formats)), add_duplicates, cover_data) if book_title is not None: added_ids |= set(ids) if dups: dir_dups.append((book_title, formats)) sys.stdout = sys.__stdout__ if dir_dups or file_duplicates: prints( _( 'The following books were not added as ' 'they already exist in the database ' '(see --duplicates option):' ), file=sys.stderr ) for title, formats in dir_dups: prints(' ', title, file=sys.stderr) for path in formats: prints(' ', path) if file_duplicates: for title, path in file_duplicates: prints(' ', title, file=sys.stderr) prints(' ', path) if added_ids: prints(_('Added book ids: %s') % (', '.join(map(unicode_type, added_ids))))
def convert(self, stream, options, file_ext, log, accelerators): from lxml import etree from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks.metadata.opf2 import OPFCreator from calibre.ebooks.rtf2xml.ParseRtf import RtfInvalidCodeException from calibre.ebooks.rtf.input import InlineClass self.opts = options self.log = log self.log('Converting RTF to XML...') try: xml = self.generate_xml(stream.name) except RtfInvalidCodeException as e: raise ValueError(_('This RTF file has a feature calibre does not ' 'support. Convert it to HTML first and then try it.\n%s')%e) d = glob.glob(os.path.join('*_rtf_pict_dir', 'picts.rtf')) if d: imap = {} try: imap = self.extract_images(d[0]) except: self.log.exception('Failed to extract images...') self.log('Parsing XML...') parser = etree.XMLParser(recover=True, no_network=True) doc = etree.fromstring(xml, parser=parser) border_styles = self.convert_borders(doc) for pict in doc.xpath('//rtf:pict[@num]', namespaces={'rtf':'http://rtf2xml.sourceforge.net/'}): num = int(pict.get('num')) name = imap.get(num, None) if name is not None: pict.set('num', name) self.log('Converting XML to HTML...') inline_class = InlineClass(self.log) styledoc = etree.fromstring(P('templates/rtf.xsl', data=True)) extensions = { ('calibre', 'inline-class') : inline_class } transform = etree.XSLT(styledoc, extensions=extensions) result = transform(doc) html = u'index.xhtml' with open(html, 'wb') as f: res = transform.tostring(result) # res = res[:100].replace('xmlns:html', 'xmlns') + res[100:] #clean multiple \n res = re.sub('\n+', '\n', res) # Replace newlines inserted by the 'empty_paragraphs' option in rtf2xml with html blank lines # res = re.sub('\s*<body>', '<body>', res) # res = re.sub('(?<=\n)\n{2}', # u'<p>\u00a0</p>\n'.encode('utf-8'), res) f.write(res) self.write_inline_css(inline_class, border_styles) stream.seek(0) mi = get_metadata(stream, 'rtf') if not mi.title: mi.title = _('Unknown') if not mi.authors: mi.authors = [_('Unknown')] opf = OPFCreator(os.getcwdu(), mi) opf.create_manifest([(u'index.xhtml', None)]) opf.create_spine([u'index.xhtml']) opf.render(open(u'metadata.opf', 'wb')) return os.path.abspath(u'metadata.opf')
def initialize(self, library_path, db, listener, actions, show_gui=True): opts = self.opts self.preferences_action, self.quit_action = actions self.library_path = library_path self.content_server = None self.spare_servers = [] self.must_restart_before_config = False self.listener = Listener(listener) self.check_messages_timer = QTimer() self.connect(self.check_messages_timer, SIGNAL('timeout()'), self.another_instance_wants_to_talk) self.check_messages_timer.start(1000) for ac in self.iactions.values(): ac.do_genesis() self.donate_action = QAction(QIcon(I('donate.png')), _('&Donate to support calibre'), self) for st in self.istores.values(): st.do_genesis() MainWindowMixin.__init__(self, db) # Jobs Button {{{ self.job_manager = JobManager() self.jobs_dialog = JobsDialog(self, self.job_manager) self.jobs_button = JobsButton(horizontal=True, parent=self) self.jobs_button.initialize(self.jobs_dialog, self.job_manager) # }}} LayoutMixin.__init__(self) EmailMixin.__init__(self) EbookDownloadMixin.__init__(self) DeviceMixin.__init__(self) self.progress_indicator = ProgressIndicator(self) self.progress_indicator.pos = (0, 20) self.verbose = opts.verbose self.get_metadata = GetMetadata() self.upload_memory = {} self.metadata_dialogs = [] self.default_thumbnail = None self.tb_wrapper = textwrap.TextWrapper(width=40) self.viewers = collections.deque() self.system_tray_icon = SystemTrayIcon(QIcon(I('lt.png')), self) self.system_tray_icon.setToolTip('calibre') self.system_tray_icon.tooltip_requested.connect( self.job_manager.show_tooltip) if not config['systray_icon']: self.system_tray_icon.hide() else: self.system_tray_icon.show() self.system_tray_menu = QMenu(self) self.restore_action = self.system_tray_menu.addAction( QIcon(I('page.png')), _('&Restore')) self.system_tray_menu.addAction(self.donate_action) self.donate_button.setDefaultAction(self.donate_action) self.donate_button.setStatusTip(self.donate_button.toolTip()) self.eject_action = self.system_tray_menu.addAction( QIcon(I('eject.png')), _('&Eject connected device')) self.eject_action.setEnabled(False) self.addAction(self.quit_action) self.system_tray_menu.addAction(self.quit_action) self.keyboard.register_shortcut('quit calibre', _('Quit calibre'), default_keys=('Ctrl+Q',), action=self.quit_action) self.system_tray_icon.setContextMenu(self.system_tray_menu) self.connect(self.quit_action, SIGNAL('triggered(bool)'), self.quit) self.connect(self.donate_action, SIGNAL('triggered(bool)'), self.donate) self.connect(self.restore_action, SIGNAL('triggered()'), self.show_windows) self.system_tray_icon.activated.connect( self.system_tray_icon_activated) self.esc_action = QAction(self) self.addAction(self.esc_action) self.keyboard.register_shortcut('clear current search', _('Clear the current search'), default_keys=('Esc',), action=self.esc_action) self.esc_action.triggered.connect(self.esc) ####################### Start spare job server ######################## QTimer.singleShot(1000, self.add_spare_server) ####################### Location Manager ######################## self.location_manager.location_selected.connect(self.location_selected) self.location_manager.unmount_device.connect(self.device_manager.umount_device) self.location_manager.configure_device.connect(self.configure_connected_device) self.eject_action.triggered.connect(self.device_manager.umount_device) #################### Update notification ################### UpdateMixin.__init__(self, opts) ####################### Search boxes ######################## SavedSearchBoxMixin.__init__(self) SearchBoxMixin.__init__(self) ####################### Library view ######################## LibraryViewMixin.__init__(self, db) if show_gui: self.show() if self.system_tray_icon.isVisible() and opts.start_in_tray: self.hide_windows() self.library_view.model().count_changed_signal.connect( self.iactions['Choose Library'].count_changed) if not gprefs.get('quick_start_guide_added', False): from calibre.ebooks.metadata.meta import get_metadata mi = get_metadata(open(P('quick_start.epub'), 'rb'), 'epub') self.library_view.model().add_books([P('quick_start.epub')], ['epub'], [mi]) gprefs['quick_start_guide_added'] = True self.library_view.model().books_added(1) if hasattr(self, 'db_images'): self.db_images.reset() if self.library_view.model().rowCount(None) < 3: self.library_view.resizeColumnsToContents() self.library_view.model().count_changed() self.bars_manager.database_changed(self.library_view.model().db) self.library_view.model().database_changed.connect(self.bars_manager.database_changed, type=Qt.QueuedConnection) ########################### Tags Browser ############################## TagBrowserMixin.__init__(self, db) ######################### Search Restriction ########################## SearchRestrictionMixin.__init__(self) if db.prefs['gui_restriction']: self.apply_named_search_restriction(db.prefs['gui_restriction']) ########################### Cover Flow ################################ CoverFlowMixin.__init__(self) self._calculated_available_height = min(max_available_height()-15, self.height()) self.resize(self.width(), self._calculated_available_height) self.build_context_menus() for ac in self.iactions.values(): try: ac.gui_layout_complete() except: import traceback traceback.print_exc() if ac.plugin_path is None: raise if config['autolaunch_server']: self.start_content_server() self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection) self.read_settings() self.finalize_layout() if self.bars_manager.showing_donate: self.donate_button.start_animation() self.set_window_title() for ac in self.iactions.values(): try: ac.initialization_complete() except: import traceback traceback.print_exc() if ac.plugin_path is None: raise self.device_manager.set_current_library_uuid(db.library_id) self.keyboard.finalize() self.auto_adder = AutoAdder(gprefs['auto_add_path'], self) self.save_layout_state() # Collect cycles now gc.collect() if show_gui and self.gui_debug is not None: info_dialog(self, _('Debug mode'), '<p>' + _('You have started calibre in debug mode. After you ' 'quit calibre, the debug log will be available in ' 'the file: %s<p>The ' 'log will be displayed automatically.')%self.gui_debug, show=True) self.iactions['Connect Share'].check_smartdevice_menus() QTimer.singleShot(1, self.start_smartdevice)