@cd-z/epub-constructor
Version:
This is a react library that creates an epub structure. This library only provides the file structure. To get a valid epub file it is needed to to create files from the provided data and compress them to a epub file.
100 lines (99 loc) • 5.27 kB
JavaScript
import { createFile, sleep, getImageType, removeFileExtension, setChapterFileNames, sanitizeFileName, } from './methods/helper';
import { createStyle } from './methods/createStyle';
import { createMetadata } from './constructors/metadataConstructor';
import { createChapter } from './methods/createChapter';
import { manifestChapter, manifestCover, manifestImage, manifestNav, manifestStyle, manifestToc, } from './constructors/manifestConstructor';
import { defaultContainer, defaultEpub, defaultHtmlToc, defaultNcxToc, } from './constructors/defaultsConstructor';
export default class EpubFile {
constructor(epubSettings) {
const fileName = epubSettings.fileName?.trim();
this.epubSettings = {
...epubSettings,
fileName: sanitizeFileName(fileName && fileName !== '' ? fileName : epubSettings.title),
};
}
/**
* Constructs the EPUB file based on the provided settings.
* @param localOnProgress Optional callback function to track the progress of EPUB construction.
* @returns An array of File objects representing the files in the EPUB.
* @throws Error if the EPUB file needs at least one chapter.
*/
async constructEpub(localOnProgress) {
var _a;
const files = [];
const manifest = [];
const spine = [];
let dProgress = 0;
if (!this.epubSettings.chapters ||
this.epubSettings.chapters.length === 0) {
throw new Error('Epub file needs at least one chapter');
}
if (!this.epubSettings.title ||
this.epubSettings.title.trim() === '' ||
!this.epubSettings.fileName) {
throw new Error('Epub file needs a title');
}
const len = this.epubSettings.chapters.length;
(_a = this.epubSettings).bookId ?? (_a.bookId = new Date().getUTCMilliseconds().toString());
this.epubSettings.fileName = removeFileExtension(this.epubSettings.fileName);
if (this.epubSettings.cover) {
const fileType = getImageType(this.epubSettings.cover);
const coverFilePath = `OEBPS/images/cover.${fileType}`;
files.push(createFile(coverFilePath, this.epubSettings.cover, true));
manifest.push(manifestCover(fileType));
}
files.push(createFile('META-INF/container.xml', defaultContainer(this.epubSettings.fileName)), createFile('EPUB/styles.css', createStyle(this.epubSettings.stylesheet)), createFile('EPUB/script.js', `function fnEpub(){${this.epubSettings.js ?? ''}}`));
let epub = defaultEpub();
let ncxToc = defaultNcxToc(this.epubSettings.chapters.length, this.epubSettings.title, this.epubSettings.bookId, this.epubSettings.author);
let htmlToc = defaultHtmlToc(this.epubSettings.title);
let metadata = createMetadata(this.epubSettings);
const navMap = [];
const ol = [];
this.epubSettings.chapters = setChapterFileNames(this.epubSettings.chapters);
for (let index = 0; index < len; index++) {
const chapter = this.epubSettings.chapters[index];
dProgress = (index / len) * 100;
let imageIndex = 0;
const idRef = `${sanitizeFileName(chapter.title)}_image_${imageIndex}`;
chapter.htmlBody = chapter.htmlBody
.replace(/(?<=<img[^>]+src=(?:"|')).+?(?="|')/gi, (uri) => {
imageIndex++;
const fileType = getImageType(uri);
const path = `OEBPS/images/${idRef}.${fileType}`;
files.push(createFile(path, uri, true));
manifest.push(manifestImage('../' + path, fileType));
return `../../${path}`;
})
.replace(/ /g, '')
.replace(/(<img[^>]+>)(?!\s*<\/img>)/g, '$1</img>')
.replace(/<\/?(?:html|head|body|input)[^>]*>/g, '');
manifest.push(manifestChapter(idRef, chapter.fileName));
files.push(createChapter(chapter));
spine.push(`<itemref idref="${idRef}" ></itemref>`);
ol.push(`<li><a href="${chapter.fileName}">${chapter.title}</a></li>`);
navMap.push(`<navPoint id="${idRef}" playOrder="${index + 1}">
<navLabel>
<text>${chapter.title}</text>
</navLabel> <content src="${chapter.fileName}" />
</navPoint>`);
if (localOnProgress && index % 300 === 0) {
await sleep(0);
}
if (localOnProgress) {
await localOnProgress(dProgress);
}
}
manifest.push(manifestNav(), manifestStyle(), manifestToc());
epub = epub
.replace('#manifest', manifest.join('\n'))
.replace('#spine', spine.join('\n'))
.replace('#metadata', metadata);
ncxToc = ncxToc.replace('#navMap', navMap.join('\n'));
htmlToc = htmlToc.replace('#ol', ol.join('\n'));
files.push(createFile(`EPUB/${this.epubSettings.fileName}.opf`, epub), createFile('EPUB/toc.xhtml', htmlToc), createFile('EPUB/toc.ncx', ncxToc), createFile('mimetype', 'application/epub+zip'));
if (localOnProgress) {
await localOnProgress(len);
}
return files;
}
}