From 09a3f440b4a6d2ca1a4638b178d3664480d8e2fb Mon Sep 17 00:00:00 2001 From: 101arrowz Date: Tue, 7 Apr 2020 20:19:03 +0000 Subject: [PATCH] --- README.md | 13 +++++++++++++ source.js | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 README.md create mode 100644 source.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..49cac29 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +Download a McGraw Hill Education eTextbook +--- +If you purchase a textbook from McGraw Hill, the website to view it is clunky and only works on some devices. +You can't go to specific page numbers, the search is super slow, etc. +That's why I wrote this script to download the textbook as an ePub file for your own viewing. +Using this script is 100% legal. McGraw Hill publicly hosts their ebooks online in order for their web client to, +download it. Moreover, to use it, you must already have purchased the book you would like to download, so it is +legally yours to use as you please. **However, it IS illegal to use this for piracy purposes.DO NOT DISTRIBUTE +ANY TEXTBOOKS YOU DOWNLOAD USING THIS SCRIPT.** + +## Instructions +1. Open your textbook in the McGraw-Hill Connect website (how you normally open it) +2. \ No newline at end of file diff --git a/source.js b/source.js new file mode 100644 index 0000000..0d21dbc --- /dev/null +++ b/source.js @@ -0,0 +1,41 @@ +import('https://cdnjs.cloudflare.com/ajax/libs/jszip/3.2.2/jszip.min.js').then(async () => { + alert('This is the McGraw-Hill Education Textbook Downloader. Click OK to start downloading the files.'); + const IMPORT_URL = (await (await fetch('https://player-api.mheducation.com/lti', { credentials: 'include' })).json()).custom_epub_url; + const epub = new JSZip(); + const metaInf = epub.folder('META-INF'); + metaInf.file('container.xml', await (await fetch(IMPORT_URL + 'META-INF/container.xml', { credentials: 'include' })).text()); + const epubData = epub.folder('OPS'); + const opfString = await (await fetch(IMPORT_URL + 'OPS/content.opf', { credentials: 'include' })).text(); + epubData.file('content.opf', opfString); + const opf = new DOMParser().parseFromString(opfString, 'application/xml'); + for (let item of opf.querySelector('manifest').children) { + const href = item.getAttribute('href'); + try { + const data = await (await fetch(`${IMPORT_URL}OPS/${href}`, { credentials: 'include' })).arrayBuffer(); + epubData.file(href, data); + console.log('Finished downloading', href); + } catch(e) { + throw `Failed to download ${href}: ${e}`; + } + } + alert('Finished downloading data! Click OK to start compression.'); + window.__savedTextbook = epub; + let highestPercent = 0; + const data = await epub.generateInternalStream({ type: 'blob' }).accumulate(({ percent }) => { + const intPercent = Math.floor(percent); + if (intPercent > highestPercent) { + console.log(intPercent+'% complete'); + highestPercent = intPercent + } + }); + alert('Finished compressing textbook! Click OK to start download.'); + window.__savedTextbookEpub = data; + const url = URL.createObjectURL(data); + const tmpLink = document.createElement('a'); + tmpLink.href = url; + const possibleTitle = opf.querySelector('metadata title'); + const titleString = possibleTitle ? possibleTitle.innerHTML : 'textbook'; + tmpLink.download = titleString + '.epub'; + tmpLink.click(); + URL.revokeObjectURL(url); +}).catch(err => alert('Textbook download failed because an error occurred: '+err)); \ No newline at end of file