Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Humble bundle book bundles - download all books at once
/*
After purchasing a humble book bundle, go to your download page for that bundle.
Open a console window for the page and paste in the below javascript
*/
$('a').each(function(i){
if ($.trim($(this).text()) == 'MOBI') {
$('body').append('<iframe id="dl_iframe_'+i+'" style="display:none;">');
document.getElementById('dl_iframe_'+i).src = $(this).data('web');
}
});
@BryanWall

This comment has been minimized.

Copy link

@BryanWall BryanWall commented Aug 20, 2016

This is a very useful script. Do you know how to modify it to download the PDF versions?

I am a Javascript novice and was able to get it to download the EPUB. I tried making changes that would download the PDFs, and got very close, but I think it's beyond my Javascript knowledge.

@barrywoolgar

This comment has been minimized.

Copy link

@barrywoolgar barrywoolgar commented Sep 2, 2016

@BryanWall you can modify the string 'MOBI'to match the type you would rather have. In your case 'PDF'.

@barrywoolgar

This comment has been minimized.

Copy link

@barrywoolgar barrywoolgar commented Sep 2, 2016

If you would like a version that downloads all the books in all the formats, see my fork of this gist.

Thanks very much for the script @graymouser!

@graymouser

This comment has been minimized.

Copy link
Owner Author

@graymouser graymouser commented Nov 14, 2016

@BryanWall sorry just saw these messages now, happy this gist helped, @barrywoolgar thanks for helping out with a great fork!

@kfatehi

This comment has been minimized.

Copy link

@kfatehi kfatehi commented Nov 23, 2016

thanks! didnt work for me so i made a fork here that does not use jquery and also grabs all formats. https://gist.github.com/kfatehi/e7642697dcda5f948854bfdebe934cd3

@kellerkindt

This comment has been minimized.

Copy link

@kellerkindt kellerkindt commented Nov 23, 2016

Or if you are on a *nix system and want to use wget instead of clicking save a dozen times:

(Modified version of @kfatehi ones):

var pattern = /(MOBI|EPUB|PDF)$/i;
var nodes = document.getElementsByTagName('a');
for (i in nodes) {
    var a = nodes[i];
    if (a && a.text && pattern.test(a.text.trim())) {
        download(a.attributes['data-web'].value, i);
    }
}
function download(url, i) {
    console.log('wget --content-disposition', url)
}

Just copy and paste the console output to the terminal. Tested with firefox

@tjoels

This comment has been minimized.

Copy link

@tjoels tjoels commented Dec 6, 2016

@barrywoolgar like @BryanWall, I can't get it to download the PDF's by replacing 'MOBI' with 'PDF'. It works fine with 'EPUB', though.

@JShorthouse

This comment has been minimized.

Copy link

@JShorthouse JShorthouse commented Dec 6, 2016

@kellerkindt Thanks a lot, this script worked perfectly, saving it for future use!

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Dec 23, 2016

@kellerkindt, works well but sometimes humble bundle has "PDF (HQ)" instead of "PDF".

@kellerkindt

This comment has been minimized.

Copy link

@kellerkindt kellerkindt commented Dec 26, 2016

@whitephoenix0 Never seen that, but the following should include those as well? (not tested)

var pattern = /(MOBI|EPUB|PDF|PDF \(HQ\))$/i;
var nodes = document.getElementsByTagName('a');
for (i in nodes) {
    var a = nodes[i];
    if (a && a.text && pattern.test(a.text.trim())) {
        download(a.attributes['data-web'].value, i);
    }
}
function download(url, i) {
    console.log('wget --content-disposition', url)
}
@robingrindrod

This comment has been minimized.

Copy link

@robingrindrod robingrindrod commented Jan 10, 2017

@Trules @BryanWall because of the way this script starts the automatic downloads, at least in Chrome, PDFs just get added as a hidden element on the page and don't get processed as a "download". I presume this is because most modern browsers know how to display a PDF where as the other formats are just "files".

@chazzam

This comment has been minimized.

Copy link

@chazzam chazzam commented Jan 12, 2017

Doesn't solve the chrome issue, but solves the PDF (HQ) and PDF (HD) issue at least.
Also adds CBZ and Download for .zip files

var pattern = /(MOBI|EPUB|PDF( ?\(H.\))?|CBZ|Download)$/i;
var nodes = document.getElementsByTagName('a');
for (i in nodes) {
    var a = nodes[i];
    if (a && a.text && pattern.test(a.text.trim())) {
        download(a.attributes['data-web'].value, i);
    }
}
function download(url, i) {
    console.log('wget --content-disposition', url)
}
@gbirke

This comment has been minimized.

Copy link

@gbirke gbirke commented Jan 13, 2017

I've tried the wget solution, but the generated wget commands are not ready to be pasted into a console as-is. It contains line number prefixes, unescaped ampersands and will fail because there is no download cookie.

So, before issuing the wget commands, save your Humble Bundle cookies with the "cookies.txt" Chrome extension or the "Export cookies" Firefox extension into the file cookies.txt. Now run the following code:

var pattern = /(MOBI|EPUB|PDF( ?\(H.\))?|CBZ|Download)$/i;
var nodes = document.getElementsByTagName('a');
var downloadCmd = '';
function download(url, i) {
    return 'wget --load-cookies=cookies.txt --content-disposition "' + url + "\"\n";
}
for (i in nodes) {
    var a = nodes[i];
    if (a && a.text && pattern.test(a.text.trim()) && a.attributes['data-web']) {
        downloadCmd += download(a.attributes['data-web'].value, i);
    }
}
console.log(downloadCmd);
@sebtomasi

This comment has been minimized.

Copy link

@sebtomasi sebtomasi commented Feb 23, 2017

Thanks for that work, it's brilliant

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Mar 13, 2017

Any chance you could make it work here too ?
Since all items are possibly on same page after selecting "Platform: Ebook"
https://www.humblebundle.com/home/library

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Apr 15, 2017

What programs do I need to run this. I'm new to programming and I'm trying to see how this works.

@mberry

This comment has been minimized.

Copy link

@mberry mberry commented May 6, 2017

@Blackxican1995
You only need a web browser

For Chrome: press F12, and choose console tab
For Mozilla: Ctrl + Shift + K

@DMarby

This comment has been minimized.

Copy link

@DMarby DMarby commented May 11, 2017

I've written a tool that lets you easily download all the ebooks from the bundles you've bought, in whatever format you wish:
https://github.com/DMarby/humblebundle-ebook-downloader

It supports accounts that has 2FA enabled as well.

@Freak613

This comment has been minimized.

Copy link

@Freak613 Freak613 commented Jun 2, 2017

While all your implementations looks overcomplicated, what I'm doing is temporary set browser's default download folder to target folder, disable "Ask where to save" and run following snippet to click all download links for all books in all formats:

$("a[data-web]").click()
@kfarnung

This comment has been minimized.

Copy link

@kfarnung kfarnung commented Jun 5, 2017

@Freak613 Thanks! This one works great in Chrome.

@oxguy3

This comment has been minimized.

Copy link

@oxguy3 oxguy3 commented Jul 17, 2017

@gbirke's solution was no good for me -- the URLs were long enough that Chrome was partially replacing them with ellipses, so I couldn't copy them from the console. Also, it doesn't seem that cookies are actually necessary -- all the authentication bits are in the URLs. Here's my modified version of his command -- it creates a <pre> box at the top of the page and puts the commands there. Also simplified the code a little bit.

var pattern = /(MOBI|EPUB|PDF( ?\(H.\))?|CBZ|Download)$/i;
var nodes = document.getElementsByTagName('a');
var downloadCmd = '';
for (i in nodes) {
    var a = nodes[i];
    if (a && a.text && pattern.test(a.text.trim()) && a.attributes['data-web']) {
        downloadCmd += 'wget --content-disposition "' + a.attributes['data-web'].value + "\"\n";
    }
}
var output = document.createElement("pre");
output.textContent = downloadCmd;
document.getElementById("papers-content").prepend(output);
@fsacer

This comment has been minimized.

Copy link

@fsacer fsacer commented Jul 19, 2017

@Freak613 KISS, works great ;)

@fsacer

This comment has been minimized.

Copy link

@fsacer fsacer commented Jul 19, 2017

Also slight adjustment from @Freak613 just for PDFs:
$("a[data-web*='pdf']").click()

@nvilagos

This comment has been minimized.

Copy link

@nvilagos nvilagos commented Aug 25, 2017

For Chrome users:

The location of the plugins have changed, you can set the required field here:
Settings (chrome://settings) --> Advanced --> Privacy and security --> Content settings --> PDF documents --> Download PDF files instead of automatically opening them in Chrome --> Turn ON

Moreover, I recommend turning off for asking download location:
Settings (chrome://settings) --> Advanced --> Downloads --> Ask where to save each file before downloading --> Turn OFF

@freizeit-pirat

This comment has been minimized.

Copy link

@freizeit-pirat freizeit-pirat commented Sep 6, 2017

but for my understanding, this just works for the direct download of the files. is it also possible to get the bt-torrent versions?

@TsoliasPN

This comment has been minimized.

Copy link

@TsoliasPN TsoliasPN commented Sep 14, 2017

Does anyone have a suggestion on how we can download all the audiobooks? I tried the below but did not work.

$('a').each(function(i){
if (['MP3', 'MD5', 'ZIP'].indexOf($.trim($(this).text())) >= 0) {
$('body').append('<iframe id="dl_iframe_'+i+'" style="display:none;">');
document.getElementById('dl_iframe_'+i).src = $(this).data('web');
}
});

@Woody2143

This comment has been minimized.

Copy link

@Woody2143 Woody2143 commented Sep 14, 2017

@oxguy3 Very nice. The only other thing I'd love to be able to get is the correctly formatted book titles to save the books under.... Anyone take a swing at that?

@Woody2143

This comment has been minimized.

Copy link

@Woody2143 Woody2143 commented Sep 14, 2017

Ok, so building off what @oxguy3 wrote I came up with the following code to save the file as the actual title of the book or whatever. Likely it could be improved upon, so corrections are very much welcome.

Edit: Moved the below code to my own gist for saving/editing, see the updated versions there: https://gist.github.com/Woody2143/830d5eae396f5ddcae4f6b7668690659

var pattern = /(MOBI|EPUB|PDF( ?\(H.\))?|CBZ|Download)$/i;
var nodes = document.getElementsByTagName('a');
var downloadCmd = '';
for (i in nodes) {
    var a = nodes[i];
    if (a && a.text && pattern.test(a.text.trim()) && a.attributes['data-web']) {
        var name = a.parentNode.parentNode.parentNode.parentNode.parentNode.getAttribute("data-human-name");
        name = name.replace(/\s+/g, '_'); /* change spaces to underscores */
        name = name.replace(/'/g, ''); /* don't want single quotes */
        name = name.replace(/:/g, '_-'); /* change : to _- for looks */
        name = name.replace(/,/g, ''); /* don't need commas */
        name = name.replace(/&/g, 'and'); /* taking out the pesky & */
        /* likely the below regex will need corrected at some point */
        var extension = /https:\/\/dl\.humble\.com\/.*\.(.*)\?gamekey.*/.exec(a.attributes['data-web'].value);
        name += '.' + extension[1];
        downloadCmd += 'wget --output-document="' + name + '" --content-disposition "' + a.attributes['data-web'].value + "\"\n";
    }
}
downloadCmd += "\n";
var output = document.createElement("pre");
output.textContent = downloadCmd;
document.getElementById("papers-content").prepend(output);
@Woody2143

This comment has been minimized.

Copy link

@Woody2143 Woody2143 commented Sep 27, 2017

None of the above methods will work as Humble Bundle appears to have changed how their page renders, it hides the download URLs now.
That being said there is a single request to their API that returns a JSON response with a list of the files and download links that can be parsed to not only download the files but check their hashes as well. If I get around to writing this up I'll post a link to the gist here... Please stand by.

@jimmckeeth

This comment has been minimized.

Copy link

@jimmckeeth jimmckeeth commented Sep 28, 2017

Hey @Woody2143, can you share those API request details?

@moldypeach

This comment has been minimized.

Copy link

@moldypeach moldypeach commented Sep 29, 2017

@nvilagos <3
tyty

@jimmckeeth

This comment has been minimized.

@achidlow

This comment has been minimized.

Copy link

@achidlow achidlow commented Oct 15, 2017

Couldn't get any of the JavaScript versions to work for me, so I wrote a quick python script (using the API that @jimmckeeth linked) that will download all the books to a directory in parallel, with the correct names, with the ability to select formats or just download all available.

@jmonsted

This comment has been minimized.

Copy link

@jmonsted jmonsted commented Nov 19, 2017

No luck with any of the javascript ones or @achidlow's python script. The API seems to need to login before pulling the inventory :(

@tkan

This comment has been minimized.

Copy link

@tkan tkan commented Nov 29, 2017

Small python script on my behalf - https://gist.github.com/tkan/9ed02fc0338b8d2562ae5af752384f7c
Note: it will only work for individual orders. So, rather than the whole inventory, you can download seperate orders at once with your order key.

@justathoughtor2

This comment has been minimized.

Copy link

@justathoughtor2 justathoughtor2 commented Dec 29, 2017

My own personal browser-based solution. This is designed to be run from the Humble Library page.

$('div.text-holder').children('h2').each(function() {
	$(this).click();
	$('h4:contains(EPUB)').click();
});

It should download every EPUB file on the page. You could replace EPUB with another format and receive similar results for that format.

Or to download a single bundle off of its gamekey page:

$('span.label:contains(EPUB)').click()

Note that either of these solutions should be run from the browser console. Only verified to work in Chrome.

@nicjansma

This comment has been minimized.

Copy link

@nicjansma nicjansma commented Jan 27, 2018

This worked for me to download all books, all versions:

$('div.download-buttons div.js-start-download a').each(function() {
  $(this).click();
});
@azdle

This comment has been minimized.

Copy link

@azdle azdle commented Jan 27, 2018

Here's my version that just creates wget commands to paste into a terminal for every link on the page that points to humble's file domain, worked great on the books page that I tired.

cmds = "";
for (a of document.getElementsByTagName("a")) {
  if (a.href.startsWith("https://dl.humble.com")) cmds += "wget --content-disposition \"" + a.href + "\"\n";
};
console.log(cmds);

https://gist.github.com/azdle/7317289a6f0401b6a95e2b568bc1a806

@helb

This comment has been minimized.

Copy link

@helb helb commented Jan 31, 2018

Chrome seems to truncate long URLs logged with console.log. If you see URLs ending with "" using @azdle's script, replace console.log with console.dir.

Before finding this gist, I came up with this – it's almost the same thing, it just uses -O filename instead of --content-disposition:

var str=""; document.querySelectorAll("a[href*='dl.humble.com']").forEach(link => str += (`wget "${link.href}" -O "${link.href.replace('https://dl.humble.com/', '').replace(/\?.*/, '')}"; `)); console.dir(str)

https://gist.github.com/helb/fc326be114a225a2c408471bef890ee8

@Woody2143

This comment has been minimized.

Copy link

@Woody2143 Woody2143 commented Feb 2, 2018

I've been working on a Perl script to do the downloads. You will need to login via the website first and grab the session cookie.
If you go to run it you'll need to manually tweak it some first: HumbleBundleDL

@liesnikov

This comment has been minimized.

Copy link

@liesnikov liesnikov commented Feb 14, 2018

There is a working one (at least as I write this) from @tlc
https://gist.github.com/tlc/96292166c7253f86565f0d18e5f8ec41

@scheras

This comment has been minimized.

Copy link

@scheras scheras commented Feb 26, 2018

I used

$('div.js-start-download a').each(function(){ $(this).trigger('click') });

for downloading all formats of all books just now.

@KurtBurgess

This comment has been minimized.

Copy link

@KurtBurgess KurtBurgess commented May 4, 2018

Building on what @azdle wrote I have modified the script to only select PDF files and changed the syntax for Windows PowerShell's wget command:

cmds = "";

function removeExtra(a2){
	a2 = a2.replace('https://dl.humble.com/','');
	a2 = a2.substring(0, a2.indexOf('.'));
	return a2;
	
}
for (a of document.getElementsByTagName("a")) {
  if (a.href.startsWith("https://dl.humble.com") && a.href.includes("pdf")) cmds += "wget \"" + a.href + "\" -Outfile " + removeExtra(a.href) + ".pdf \n";
};
console.log(cmds);

It's ugly but it works,

  1. Iterates over each anchor tag
  2. Only selects if the URL starts with 'https://dl.humble.com' and contains 'pdf' (change for EPUB or other file type).
  3. Then names the Outfile the same as URL without 'https://dl.humble.com' or anything after the first '.' then appends .pdf at the end (again replace with any extension you prefer). Thus naming the file as it's title name without caps or spaces.
  4. Finally paste all console logs in a PowerShell window in the directory to save and they will automatically download.

Thanks @azdle, couldn't of done it without your code to start

@Drizzt321

This comment has been minimized.

Copy link

@Drizzt321 Drizzt321 commented May 10, 2018

FYI, for regular wget (e.g. Unix, Linux, Mac), it's just -O, not -Outfile (WHY does powershell have to be different?). So you need to modify the above to change -Outfile to -O

Although Mac doesn't have wget installed by default, in that case using curl, modify the IF statement to be:

if (a.href.startsWith("https://dl.humble.com") && a.href.includes("pdf")) cmds += "curl \"" + a.href + "\" -o " + removeExtra(a.href) + ".pdf \n";

@schemacs

This comment has been minimized.

Copy link

@schemacs schemacs commented May 17, 2018

This code works if you set firefox to save pdf instead of preview it(Firefox > Preferences > Applications > Adobe PDF document : Save File):

function Book(title, author, formats) {
  this.title = title;
  this.author = author;
  this.formats = formats;
};

// Change this to non-zero to download
var seconds_between_switch_book = 0; // 10;
var seconds_between_download = 0; // 3;
var books = [];
var rows = document.querySelectorAll('.subproduct-selector');
rows.forEach(function(item, item_index) {
    setTimeout(function() {
        item.click();
        var title = item.querySelectorAll('h2')[0].title;
        var author = item.querySelectorAll('p')[0].innerText;
        var formats = [...document.querySelectorAll('div.js-download-button')].map(
            download_item => download_item.querySelectorAll('h4')[0].innerText
        )
        books.push(new Book(title, author, formats));

        document.querySelectorAll('div.js-download-button').forEach(function(download_item, download_index){
            setTimeout(function() {
                var format = download_item.querySelectorAll('h4')[0].childNodes[1].data;
                console.log(item_index, download_index, title, format);
                // uncomment this to download
                //download_item.click();
            }, seconds_between_download * 1000 * download_index);
        });
    }, seconds_between_switch_book * 1000 * item_index);
});

setTimeout(function(){
    console.table(books);
    copy(books);
}, (rows.length + 1) * 1000 * seconds_between_switch_book);
@jbhelfrich

This comment has been minimized.

Copy link

@jbhelfrich jbhelfrich commented May 29, 2018

So I'm currently downloading just about everything to put in a Calibre library. Since some of the bundles have some repeat content (looking at you , Make) I updated the @KurtBurgess script to test the working directory for a copy of the current file and skip it if present:

cmds = "";

function buildCommand(a, ext) {
  let filename = removeExtra(a.href);
  ext = '.' + ext;
  cmds += "If(Test-Path -Path \"" + filename + ext + "\") {Write-Warning \"" + filename + ext + " exists, skipping \"} Else { wget \"" + a.href + "\" -Outfile " + filename + ext + "}\n";
  }
  
function removeExtra(a2){
	a2 = a2.replace('https://dl.humble.com/','');
	a2 = a2.substring(0, a2.indexOf('.'));
	return a2;
}

for (a of document.getElementsByTagName("a")) {
  if (a.href.startsWith("https://dl.humble.com") && a.href.includes("pdf")) buildCommand(a, 'pdf');
  if (a.href.startsWith("https://dl.humble.com") && a.href.includes("epub")) buildCommand (a, 'epub');
  if (a.href.startsWith("https://dl.humble.com") && a.href.includes("cbz")) buildCommand(a, 'cbz');
};

console.log(cmds);

Next steps, adding a bash variant, and seeing if I can remove the repeated if statements for a some

@calexandrepcjr

This comment has been minimized.

Copy link

@calexandrepcjr calexandrepcjr commented Jul 17, 2018

var pattern = /(MOBI|EPUB|PDF( ?\(H.\))?|CBZ|Download)$/i; var nodes = document.getElementsByTagName('a'); var downloadCmd = ''; for (i in nodes) { var a = nodes[i]; if (a && a.text && pattern.test(a.text.trim()) && a.attributes['href']) { downloadCmd += a.attributes['href'].value + "\"\n"; } } var output = document.createElement("pre"); output.textContent = downloadCmd; document.getElementById("papers-content").prepend(output);

Copy/Paste the links in one txt and run wget:

wget --no-check-certificate --content-disposition -r -H -np -nH -N --cut-dirs=1 -e robots=off -l1 -i ./linksfilename.txt -B 'https://dl.humble.com/'

@bl4ckb1rd

This comment has been minimized.

Copy link

@bl4ckb1rd bl4ckb1rd commented Jul 19, 2018

A modified version of @kellerkindt

var nodes_a = document.querySelectorAll('.downloads a:not(.dlmd5)');

for (node of nodes_a) {
    console.log('wget --content-disposition', node.href);
};
@m-d-johnson

This comment has been minimized.

Copy link

@m-d-johnson m-d-johnson commented Jul 22, 2018

If you're using the above, you may need to place the generated link in double quotes so your shell interprets the ampersand literally. I tried to tweak this but I hit an issue with whitespace which would be easy for someone who actually knows Javascript to fix. Sadly this person is not me.

@m-d-johnson

This comment has been minimized.

Copy link

@m-d-johnson m-d-johnson commented Jul 22, 2018

var nodes_a = document.querySelectorAll('.downloads a:not(.dlmd5)');
for (node of nodes_a) {
    var tmp = node.href;
    tmp = tmp.replace(/ /g,'')
    console.log('wget --content-disposition \"'+tmp+"\"");
};

Maybe this works. Apologies for hackyness. I'm sure a better alteration is possible but like I say, I don't know javascript

@jmerle

This comment has been minimized.

Copy link

@jmerle jmerle commented Aug 3, 2018

I like my files to be organized, so here's my take on it.

const commands = [];

document.querySelectorAll('.row').forEach(row => {
  const bookTitle = row.dataset.humanName;

  [...row.querySelectorAll('.downloads .flexbtn a')].forEach(el => {
    const downloadLink = el.href;
    const fileName = /\.com\/([^?]+)/.exec(downloadLink)[1];

    commands.push(`curl --create-dirs -o "${bookTitle}/${fileName}" "${downloadLink}"`);
  });
});

console.log(commands.join('; '));

Instead of wget this uses curl, because wget's -O does not create directories automatically (and while -P does, -O and -P cannot be used together).

The resulting directory tree is like this:

.
├── Advanced Penetration Testing
│   ├── advancedpenetrationtesting.epub
│   └── advancedpenetrationtesting.pdf
├── Applied Cryptography: Protocols, Algorithms and Source Code in C, 20th Anniversary Edition
│   ├── applied_cryptography_protocols_algorithms_and_source_code_in_c.epub
│   └── applied_cryptography_protocols_algorithms_and_source_code_in_c.pdf
└── Cryptography Engineering: Design Principles and Practical Applications
    ├── cryptography_engineering_design_principles_and_practical_applications.epub
    ├── cryptography_engineering_design_principles_and_practical_applications.pdf
    └── cryptography_engineering_design_principles_and_practical_applications.prc
@fsteffek

This comment has been minimized.

Copy link

@fsteffek fsteffek commented Aug 28, 2018

I took @jmerle's code and changed the last line:

console.log(commands.join('; ');

to:

console.log(commands.join(' && ');

That way, it didn't try to download everything at once.

@fsteffek

This comment has been minimized.

Copy link

@fsteffek fsteffek commented Aug 29, 2018

If you want to verify your downloads, here's the code to make the md5 hashes visible:

var md5_links = document.querySelectorAll(".dlmd5");
for (i in md5_links) {
  md5_links[i].click();
}

OR...

If you are like me and have way too many book bundles, you might be interested in something like the following code.

function getTitle() {
  var re = /^Humble\ Book\ Bundle\:\ (.*)\ \(/g;
  return re.exec(document.title)[1];
}
function showHashes() {
  document.querySelectorAll('.dlmd5').forEach(md5 => {
    if (md5.innerText.trim() == 'md5') {
      md5.click();
    }
  });
}
function gatherInfo() {
  const data = [];
  const bundleTitle = getTitle();
  showHashes();
  document.querySelectorAll('.row').forEach(row => {
    const bookTitle = row.dataset.humanName;
    [...row.querySelectorAll('.downloads .download')].forEach(dl => {
      const downloadLink = dl.querySelector('.flexbtn a').href;
      const filename = /\.com\/([^?]+)/.exec(downloadLink)[1];
      const md5 = dl.querySelector('a.dlmd5').innerText.trim();
      data.push({
        "bundleTitle": bundleTitle,
        "bookTitle": bookTitle,
        "filename": filename,
        "downloadLink": downloadLink,
        "md5": md5
      });
    });
  });
  return data;
}
function downloadBookBundle() {
  const commands = []
  const md5Sums = [];
  const info = gatherInfo();
  for (var i in info) {
    bundleTitle = info[i]["bundleTitle"];
    bookTitle = info[i]["bookTitle"];
    filename = info[i]["filename"];
    downloadLink = info[i]["downloadLink"];
    md5 = info[i]["md5"];
    commands.push(`curl --create-dirs -o "${bundleTitle}/${bookTitle}/${filename}" "${downloadLink}"`);
    md5Sums.push(`${md5}  ${bundleTitle}/${bookTitle}/${filename}`);
  };
  console.log(commands.join(' && '));
  console.log(md5Sums.join('\n'));
}
downloadBookBundle();

It is based upon's @jmerle's approach and is also forked here: https://gist.github.com/fsteffek/bf4ac1e3d2601629a6c9cca94b5649f6.

What does it do?

  1. It prints the command line command for curl to download your Humble Book Bundle. I modified it, so each bundle is saved into a separate folder:
.
├── Bundle Name
│   └── Book Name
│       └── Files
└── More Bundles
  1. It prints the content of an md5 file, which md5sum can read/check. Paste it into a file like hb_all_books.md5 ...
5b3e6de1fc4c45be45b1299ea50a6a7d  Essential Knowledge by MIT Press/Cloud Computing/cloudcomputing.epub
a14391f6971da830d064c2c0fd132019  Essential Knowledge by MIT Press/Cloud Computing/cloudcomputing.mobi
...

... and check it with md5sum -c hb_all_books.md5.

Essential Knowledge by MIT Press/Cloud Computing/cloudcomputing.epub: OK
Essential Knowledge by MIT Press/Cloud Computing/cloudcomputing.mobi: OK
...

Feel free to tell me how to make this script more readable, convenient and generally just better.

@zuazo

This comment has been minimized.

Copy link

@zuazo zuazo commented Oct 2, 2018

My JavaScript fork of this script is still working today: https://gist.github.com/zuazo/a91ecbb97b90ef3ef9ce8caf361199a2

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