Skip to content

Instantly share code, notes, and snippets.

@miguno
Forked from peterbartha/README.md
Last active January 10, 2023 16:43
Show Gist options
  • Save miguno/1ceb2bf97abfa528c3b6114477e63fa0 to your computer and use it in GitHub Desktop.
Save miguno/1ceb2bf97abfa528c3b6114477e63fa0 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 (on Firefox) to open the browser console. Or: Tools > Browser Tools > Web Developer Tools, then switch to Console tab.
  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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment