Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@peterbartha
Last active April 22, 2024 17:57
Show Gist options
  • Star 28 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save peterbartha/54708ae739478a45b52612311d49717c to your computer and use it in GitHub Desktop.
Save peterbartha/54708ae739478a45b52612311d49717c to your computer and use it in GitHub Desktop.
Convert Rust books to EPUB (incl. The Rust Programming Language)

Convert Rust books to EPUB (incl. The Rust Programming Language)

The following steps work for all the HTML learning materials on the Learn Rust page:

  1. Click on the "Print this book" icon in the top right corner.
  2. "Cancel" print popup.
  3. Press F12.
  4. Copy, paste, and run the contents of ebookFormatPreparation.js into your browser's console.
  5. Save the modified HTML file.
  6. Install pandoc: https://pandoc.org/installing.html.
  7. From CLI, execute the following: pandoc <inputFileName>.html --to=epub --output=<outputFileName>.epub
    You can use other output formats as well (e.g. mobi, docbook, or fb2).
  8. (Optional) Open the generated EPUB file in Calibre and add the two custom stylesheets (epub.css and then custom.css) to the ebook using the integrated editor.
  9. Upload the generated EPUB file to your e-reader, enjoy! 📜🤓
.ferris, .ferris-explain {
width: 70px;
}
// Remove unnecessary (singular) page elements by id
const idsToRemove = [
'sidebar',
'menu-bar-hover-placeholder',
'menu-bar',
'search-wrapper',
];
idsToRemove.forEach((selector) => {
const elem = document.getElementById(selector);
if (elem) {
elem.remove();
}
});
// Remove unnecessary anchors from header tag elements
Array.from(document.querySelectorAll(':is(h1,h2,h3,h4,h5,h6) a')).forEach(
(a) => {
const span = document.createElement('span');
span.innerText = a.innerText;
a.parentNode.replaceChild(span, a);
}
);
// Fix anchor ids on headings
Array.from(document.querySelectorAll('a :is(h1,h2,h3,h4,h5,h6)')).forEach(
(heading) => {
const a = heading.parentNode;
heading.id = a.id;
a.parentNode.replaceChild(heading, a);
}
);
// Create 'Table of Contents' section
const secondSection = document.getElementsByTagName('h1')[1];
const tableOfContents = document.createElement('ol');
secondSection.parentNode.insertBefore(tableOfContents, secondSection);
let lastParent = tableOfContents;
const headings = Array.from(document.querySelectorAll('h1, h2'));
headings.forEach((heading, index) => {
const link = document.createElement('a');
link.setAttribute('href', `#${heading.id}`);
link.textContent = heading.textContent;
const li = document.createElement('li');
li.setAttribute('class', heading.tagName.toLowerCase());
li.appendChild(link);
if (
heading.tagName.toLowerCase() === 'h1' &&
headings[index + 1] &&
headings[index + 1].tagName.toLowerCase() === 'h1'
) {
tableOfContents.appendChild(li);
} else if (heading.tagName.toLowerCase() === 'h1') {
tableOfContents.appendChild(li);
const subParent = document.createElement('ol');
tableOfContents.appendChild(subParent);
lastParent = subParent;
} else {
lastParent.appendChild(li);
}
});
const tocHeader = document.createElement('h1');
tocHeader.innerText = 'Table of Contents';
tableOfContents.parentNode.insertBefore(tocHeader, tableOfContents);
// Remove buttons (i.e. `copy`, `run` on rust playground)
Array.from(document.getElementsByClassName('buttons')).forEach((el) =>
el.remove()
);
// Use absolute URLs instead of relative
Array.from(document.getElementsByTagName('img')).forEach((img) => {
if (img.src.includes('https://rustwasm.github.io/docs/images/')) {
img.src = `https://rustwasm.github.io/docs/book/images/game-of-life/${img.src
.split(/[/ ]+/)
.pop()}`;
return;
}
if (!img.getAttribute('src').startsWith('http')) {
img.src = img.src;
}
});
// Move out Ferris from syntax highlighter
Array.from(
document.querySelectorAll('pre .ferris-container img.ferris')
).forEach((ferris) => {
const parentCodeBlock = ferris.closest('pre');
parentCodeBlock.parentNode.insertBefore(ferris, parentCodeBlock);
});
// Flatten code block elements
Array.from(document.querySelectorAll('pre pre')).forEach((pre) => {
pre.parentNode.replaceWith(pre);
});
// Remove syntax highlighter
Array.from(document.querySelectorAll('pre code')).forEach((code) => {
const match = /language-([^ ]*)/gi.exec(code.className);
if (match && match[1]) {
code.removeAttribute('class');
code.parentNode.className = `${match[1] === 'console' ? 'bash' : match[1]}`;
}
code.innerText = code.textContent; // replace elements by text
});
// Remove scripts
Array.from(document.getElementsByTagName('script')).forEach((scripts) =>
scripts.remove()
);
// Unfold details HTML element
Array.from(document.querySelectorAll('details summary')).forEach((summary) => {
summary.remove();
});
Array.from(document.getElementsByTagName('details')).forEach((details) => {
details.replaceWith(...details.childNodes);
});
// Reset the wrapper
document.getElementById('page-wrapper').classList.remove('page-wrapper');
document
.getElementsByTagName('main')[0]
.setAttribute('style', 'max-width:none;');
document
.getElementsByClassName('page')[0]
.setAttribute('style', 'margin-top: 0;');
/* from http://bbebooksthailand.com/bb-CSS-boilerplate.html */
/* This adds margins around every page to stop ADE's line numbers from being superimposed over content */
@page {
margin: 10px;
}
/*===Reset code to prevent cross-reader strangeness===*/
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
vertical-align: baseline;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
ol,
ul,
li,
dl,
dt,
dd {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
vertical-align: baseline;
}
/*===GENERAL PRESENTATION===*/
/*===Body Presentation and Margins===*/
/* Text alignment is still a matter of debate. Feel free to change to text-align: left; */
body {
text-align: justify;
line-height: 120%;
}
/*===Headings===*/
/* After page breaks, eReaders sometimes do not render margins above the content. Adjusting padding-top can help */
h1 {
text-indent: 0;
text-align: center;
margin: 100px 0 0 0;
font-size: 2em;
font-weight: bold;
page-break-before: always;
line-height: 150%; /*gets squished otherwise on ADE */
}
h2 {
text-indent: 0;
text-align: center;
margin: 50px 0 0 0;
font-size: 1.5em;
font-weight: bold;
page-break-before: always;
line-height: 135%; /*get squished otherwise on ADE */
}
h3 {
text-indent: 0;
text-align: left;
font-size: 1.4em;
font-weight: bold;
margin-top: 1.4em;
}
h4 {
text-indent: 0;
text-align: left;
font-size: 1.2em;
font-weight: bold;
margin-top: 1.2em;
}
h5 {
text-indent: 0;
text-align: left;
font-size: 1.1em;
font-weight: bold;
margin-top: 1.1em;
}
h6 {
text-indent: 0;
text-align: left;
font-size: 1em;
font-weight: bold;
margin-top: 1em;
}
/* Hyphen and pagination Fixer */
/* Note: Do not try on the Kindle, it does not recognize the hyphens property */
h1,
h2,
h3,
h4,
h5,
h6 {
-webkit-hyphens: none !important;
hyphens: none;
page-break-after: avoid;
page-break-inside: avoid;
}
/*===Paragraph Elements===*/
/* Margins are usually added on the top, left, and right, but not on the bottom to prevent certain eReaders not collapsing white space properly */
/*first-line indent paragraph for fiction*/
p {
/* text-indent: 1.25em; */
margin: 0;
widows: 2;
orphans: 2;
}
/* block type paragraph for non-fiction* /
/*
p
{
text-indent: 0;
margin: 1.0em 0 0 0;
widows: 2;
orphans: 2;
}
*/
/* for centered text and wrappers on images */
p.centered {
text-indent: 0;
margin: 1em 0 0 0;
text-align: center;
}
/* section Breaks (can use centered-style for non-fiction) */
p.centeredbreak {
text-indent: 0;
margin: 1em 0 1em 0;
text-align: center;
}
/* First sentence in chapters following heading */
p.texttop {
margin: 1.5em 0 0 0;
text-indent: 0;
}
/* Use for second sentence to clear drop cap's float */
p.clearit {
clear: both;
}
/* 1st level TOC */
p.toctext {
margin: 0 0 0 1.5em;
text-indent: 0;
}
/* 2nd level TOC */
p.toctext2 {
margin: 0 0 0 2.5em;
text-indent: 0;
}
/*==LISTS==*/
ul {
margin: 1em 0 0 2em;
text-align: left;
}
ol {
margin: 1em 0 0 2em;
text-align: left;
}
/*===IN-LINE STYLES===*/
/* Recommend avoiding use of <b>, <i>, and <u>. Use span tags instead */
span.i {
font-style: italic;
}
span.b {
font-weight: bold;
}
span.u {
text-decoration: underline;
}
span.st {
text-decoration: line-through;
}
/*==in-line combinations==*/
/* Using something like <span class="i b">... may seem okay, but it causes problems on some eReaders */
span.ib {
font-style: italic;
font-weight: bold;
}
span.iu {
font-style: italic;
text-decoration: underline;
}
span.bu {
font-weight: bold;
text-decoration: underline;
}
span.ibu {
font-style: italic;
font-weight: bold;
text-decoration: underline;
}
/* This fixes the bug where the text-align property of block-level elements is not recognized on iBooks
example: html markup would look like <p class="centered"><span class="ipadcenterfix">Centered Content</span></p> */
span.ipadcenterfix {
text-align: center;
}
/*==IMAGES==*/
img {
max-width: 100%;
}
/*==TABLES==*/
table {
margin: 1em auto;
}
tr,
th,
td {
margin: 0;
padding: 2px;
border: 1px solid black;
font-size: 100%;
vertical-align: baseline;
}
/* Superscripted Footnote Text */
.footnote {
vertical-align: super;
font-size: 0.75em;
text-decoration: none;
}
/*==DROP CAPS==*/
span.dropcap {
font-size: 300%;
font-weight: bold;
height: 1em;
float: left;
margin: 0.3em 0.125em -0.4em 0.1em;
}
/*==PULL QUOTE==*/
div.pullquote {
margin: 2em 2em 0 2em;
text-align: left;
}
div.pullquote p {
font-weight: bold;
font-style: italic;
}
div.pullquote hr {
width: 100%;
margin: 0;
height: 3px;
color: #2e8de0;
background-color: #2e8de0;
border: 0;
}
/*==BLOCK QUOTE==*/
div.blockquote {
margin: 1em 1.5em 0 1.5em;
text-align: left;
font-size: 0.9em;
}
/*==eBook Specific Formatting Below Here==*/
body {
padding: 1em;
}
pre,
code {
font-size: 90%;
line-height: 100%;
}
pre {
border-left: 1px #000 solid;
padding-left: 10px;
}
blockquote {
color: #666666;
margin: 1em 0;
padding-left: 1.5em;
border-left: 0.5em #eee solid;
}
p {
margin: 1em 0;
}
/* used for strings in code when using HTML */
span.st {
text-decoration: initial;
}
@hedefalk
Copy link

hedefalk commented May 9, 2023

Nice, thanks!

@hedefalk
Copy link

Nice, thanks!

Too early :) Code fragments seem not to work - full referenced listing is shown. Did i miss a step?

@Lolozendev
Copy link

when you add the css sheets to you need to add the link in the editors ? with a new ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment