Piano notes book, powered by Astro and React.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

epubify.ts 3.6 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // import { readFile } from 'fs/promises';
  2. import archiver from 'archiver';
  3. import {createWriteStream} from 'fs';
  4. import {readdir} from 'fs/promises';
  5. import assert from 'assert';
  6. // const act = <T extends (...args: any[]) => any>(fn: T) => {
  7. // return async (...args: Parameters<T>) => {
  8. // let r;
  9. // try {
  10. // r = await fn(...args);
  11. // } catch {
  12. // // noop
  13. // }
  14. // return r;
  15. // }
  16. // };
  17. const main = async () => {
  18. // await act(cp)('dist', 'book', {recursive: true});
  19. // await act(rm)('dist', {recursive: true, force: true});
  20. // await act(mkdir)('dist');
  21. // await act(cp)('book', 'dist/book', {recursive: true});
  22. const { default: astroConfig } = await import('../astro.config.mjs');
  23. const { outDir = 'dist/', output = 'static', build, compressHTML = false } = astroConfig;
  24. assert(output === 'static');
  25. assert(build?.format === 'file');
  26. assert(!compressHTML)
  27. const distFiles = await readdir(outDir);
  28. // TODO get all assets and declare to manifest
  29. console.log(distFiles);
  30. return new Promise<number>((resolve, reject) => {
  31. const output = createWriteStream('book.epub');
  32. const archive = archiver('zip', {
  33. zlib: {
  34. level: 9,
  35. },
  36. });
  37. output.on('close', () => {
  38. resolve(archive.pointer());
  39. });
  40. archive.on('error', (err) => {
  41. reject(err);
  42. });
  43. archive.pipe(output);
  44. archive.append('application/epub+zip', { name: 'mimetype' });
  45. archive.append(`<?xml version="1.0"?>
  46. <container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
  47. <rootfiles>
  48. <rootfile full-path="content.opf" media-type="application/oebps-package+xml"/>
  49. </rootfiles>
  50. </container>
  51. `, { name: 'META-INF/container.xml' });
  52. archive.append(`<?xml version="1.0"?>
  53. <package xmlns="http://www.idpf.org/2007/opf" xmlns:opf="http://www.idpf.org/2007/opf" version="3.0" unique-identifier="BookID">
  54. <metadata xmlns:dc="http://purl.org/dc/elements/1.1/">
  55. <dc:identifier id="BookID" opf:scheme="isbn">978-3-86680-192-9</dc:identifier>
  56. <dc:identifier>3b622266-b838-4003-bcb8-b126ee6ae1a2</dc:identifier>
  57. <dc:title>The title</dc:title>
  58. <dc:language>fr</dc:language>
  59. <dc:publisher>The publisher</dc:publisher>
  60. <dc:creator>The author</dc:creator>
  61. <dc:contributor>A contributor</dc:contributor>
  62. <dc:description>A description</dc:description>
  63. <dc:subject>A subject of the publication</dc:subject>
  64. <dc:subject>Another subject of the publication</dc:subject>
  65. <dc:rights>© copyright notice</dc:rights>
  66. <meta property="dcterms:modified">2020-01-01T01:01:01Z</meta>
  67. </metadata>
  68. <manifest>
  69. <item id="coverimage" href="OEBPS/cover.jpg" media-type="image/jpeg" properties="cover-image"/>
  70. <item id="cover" href="OEBPS/index.xhtml" media-type="application/xhtml+xml"/>
  71. <item id="toc" href="toc.html" media-type="application/xhtml+xml" properties="nav"/>
  72. <item id="chapter-1" href="Text/chapter-1.xhtml" media-type="application/xhtml+xml"/>
  73. <item id="chapter-2" href="Text/chapter-2.xhtml" media-type="application/xhtml+xml"/>
  74. <item id="css" href="Styles/publication.css" media-type="text/css"/>
  75. <item id="font1" href="Fonts/Andada-Italic.otf" media-type="application/vnd.ms-opentype"/>
  76. <item id="font2" href="Fonts/Andada-Regular.otf" media-type="application/vnd.ms-opentype"/>
  77. <item id="glyph" href="Images/glyph.png" media-type="image/png"/>
  78. </manifest>
  79. <spine>
  80. <itemref idref="cover"/>
  81. <itemref idref="toc"/>
  82. <itemref idref="chapter-1"/>
  83. <itemref idref="chapter-2"/>
  84. </spine>
  85. </package>
  86. `, { name: 'content.opf' });
  87. archive.directory(outDir, 'OEBPS');
  88. });
  89. };
  90. main().then((bytes) => {
  91. console.log(`${bytes} written.`);
  92. });