Skip to content

Instantly share code, notes, and snippets.

@101arrowz
Last active July 16, 2025 12:38
Show Gist options
  • Save 101arrowz/88156556326106a6ccd58ecb4526498c to your computer and use it in GitHub Desktop.
Save 101arrowz/88156556326106a6ccd58ecb4526498c to your computer and use it in GitHub Desktop.
Download a McGraw Hill Education eTextbook

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) in a private/incognito window. Use Chrome if possible; this won't work at all in Firefox.
  2. Type javascript: into the address bar (note that you CANNOT copy-paste it in).
  3. Copy-paste the following into the address bar AFTER the javascript: part:
var x=new XMLHttpRequest();x.onload=function(){eval(x.responseText)};x.open('GET','https://gist.githubusercontent.com/101arrowz/88156556326106a6ccd58ecb4526498c/raw/script.js');x.send();
  1. Press ENTER.
  2. Follow the instructions that appear on screen. Be patient! The download takes between 10 and 40 minutes depending on internet speed.
  3. Your textbook will download on its own.

If you found this tutorial useful, please give it a star. Thanks!

~101arrowz

// Optimized code for the downloader.
!function(){var t=function(t){var e=Object.prototype,r=e.hasOwnProperty,n="function"==typeof Symbol?Symbol:{},o=n.iterator||"@@iterator",i=n.asyncIterator||"@@asyncIterator",a=n.toStringTag||"@@toStringTag";function c(t,e,r,n){var o=e&&e.prototype instanceof u?e:u,i=Object.create(o.prototype),a=new L(n||[]);return i._invoke=function(t,e,r){var n="suspendedStart";return function(o,i){if("executing"===n)throw new Error("Generator is already running");if("completed"===n){if("throw"===o)throw i;return k()}for(r.method=o,r.arg=i;;){var a=r.delegate;if(a){var c=w(a,r);if(c){if(c===l)continue;return c}}if("next"===r.method)r.sent=r._sent=r.arg;else if("throw"===r.method){if("suspendedStart"===n)throw n="completed",r.arg;r.dispatchException(r.arg)}else"return"===r.method&&r.abrupt("return",r.arg);n="executing";var u=s(t,e,r);if("normal"===u.type){if(n=r.done?"completed":"suspendedYield",u.arg===l)continue;return{value:u.arg,done:r.done}}"throw"===u.type&&(n="completed",r.method="throw",r.arg=u.arg)}}}(t,r,a),i}function s(t,e,r){try{return{type:"normal",arg:t.call(e,r)}}catch(t){return{type:"throw",arg:t}}}t.wrap=c;var l={};function u(){}function h(){}function d(){}var f={};f[o]=function(){return this};var p=Object.getPrototypeOf,v=p&&p(p(E([])));v&&v!==e&&r.call(v,o)&&(f=v);var y=d.prototype=u.prototype=Object.create(f);function m(t){["next","throw","return"].forEach((function(e){t[e]=function(t){return this._invoke(e,t)}}))}function g(t,e){var n;this._invoke=function(o,i){function a(){return new e((function(n,a){!function n(o,i,a,c){var l=s(t[o],t,i);if("throw"!==l.type){var u=l.arg,h=u.value;return h&&"object"==typeof h&&r.call(h,"__await")?e.resolve(h.__await).then((function(t){n("next",t,a,c)}),(function(t){n("throw",t,a,c)})):e.resolve(h).then((function(t){u.value=t,a(u)}),(function(t){return n("throw",t,a,c)}))}c(l.arg)}(o,i,n,a)}))}return n=n?n.then(a,a):a()}}function w(t,e){var r=t.iterator[e.method];if(void 0===r){if(e.delegate=null,"throw"===e.method){if(t.iterator.return&&(e.method="return",e.arg=void 0,w(t,e),"throw"===e.method))return l;e.method="throw",e.arg=new TypeError("The iterator does not provide a 'throw' method")}return l}var n=s(r,t.iterator,e.arg);if("throw"===n.type)return e.method="throw",e.arg=n.arg,e.delegate=null,l;var o=n.arg;return o?o.done?(e[t.resultName]=o.value,e.next=t.nextLoc,"return"!==e.method&&(e.method="next",e.arg=void 0),e.delegate=null,l):o:(e.method="throw",e.arg=new TypeError("iterator result is not an object"),e.delegate=null,l)}function x(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function b(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function L(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(x,this),this.reset(!0)}function E(t){if(t){var e=t[o];if(e)return e.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var n=-1,i=function e(){for(;++n<t.length;)if(r.call(t,n))return e.value=t[n],e.done=!1,e;return e.value=void 0,e.done=!0,e};return i.next=i}}return{next:k}}function k(){return{value:void 0,done:!0}}return h.prototype=y.constructor=d,d.constructor=h,d[a]=h.displayName="GeneratorFunction",t.isGeneratorFunction=function(t){var e="function"==typeof t&&t.constructor;return!!e&&(e===h||"GeneratorFunction"===(e.displayName||e.name))},t.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,d):(t.__proto__=d,a in t||(t[a]="GeneratorFunction")),t.prototype=Object.create(y),t},t.awrap=function(t){return{__await:t}},m(g.prototype),g.prototype[i]=function(){return this},t.AsyncIterator=g,t.async=function(e,r,n,o,i){void 0===i&&(i=Promise);var a=new g(c(e,r,n,o),i);return t.isGeneratorFunction(r)?a:a.next().then((function(t){return t.done?t.value:a.next()}))},m(y),y[a]="Generator",y[o]=function(){return this},y.toString=function(){return"[object Generator]"},t.keys=function(t){var e=[];for(var r in t)e.push(r);return e.reverse(),function r(){for(;e.length;){var n=e.pop();if(n in t)return r.value=n,r.done=!1,r}return r.done=!0,r}},t.values=E,L.prototype={constructor:L,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=void 0,this.done=!1,this.delegate=null,this.method="next",this.arg=void 0,this.tryEntries.forEach(b),!t)for(var e in this)"t"===e.charAt(0)&&r.call(this,e)&&!isNaN(+e.slice(1))&&(this[e]=void 0)},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var e=this;function n(r,n){return a.type="throw",a.arg=t,e.next=r,n&&(e.method="next",e.arg=void 0),!!n}for(var o=this.tryEntries.length-1;o>=0;--o){var i=this.tryEntries[o],a=i.completion;if("root"===i.tryLoc)return n("end");if(i.tryLoc<=this.prev){var c=r.call(i,"catchLoc"),s=r.call(i,"finallyLoc");if(c&&s){if(this.prev<i.catchLoc)return n(i.catchLoc,!0);if(this.prev<i.finallyLoc)return n(i.finallyLoc)}else if(c){if(this.prev<i.catchLoc)return n(i.catchLoc,!0)}else{if(!s)throw new Error("try statement without catch or finally");if(this.prev<i.finallyLoc)return n(i.finallyLoc)}}}},abrupt:function(t,e){for(var n=this.tryEntries.length-1;n>=0;--n){var o=this.tryEntries[n];if(o.tryLoc<=this.prev&&r.call(o,"finallyLoc")&&this.prev<o.finallyLoc){var i=o;break}}i&&("break"===t||"continue"===t)&&i.tryLoc<=e&&e<=i.finallyLoc&&(i=null);var a=i?i.completion:{};return a.type=t,a.arg=e,i?(this.method="next",this.next=i.finallyLoc,l):this.complete(a)},complete:function(t,e){if("throw"===t.type)throw t.arg;return"break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&e&&(this.next=e),l},finish:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var r=this.tryEntries[e];if(r.finallyLoc===t)return this.complete(r.completion,r.afterLoc),b(r),l}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var r=this.tryEntries[e];if(r.tryLoc===t){var n=r.completion;if("throw"===n.type){var o=n.arg;b(r)}return o}}throw new Error("illegal catch attempt")},delegateYield:function(t,e,r){return this.delegate={iterator:E(t),resultName:e,nextLoc:r},"next"===this.method&&(this.arg=void 0),l}},t}({});try{regeneratorRuntime=t}catch(e){Function("r","regeneratorRuntime = r")(t)}function e(t,e,r,n,o,i,a){try{var c=t[i](a),s=c.value}catch(t){return void r(t)}c.done?e(s):Promise.resolve(s).then(n,o)}self.fetch||(self.fetch=function(t,e){return e=e||{},new Promise((r,n)=>{const o=new XMLHttpRequest,i=[],a=[],c={},s=()=>({ok:2==(o.status/100|0),statusText:o.statusText,status:o.status,url:o.responseURL,text:()=>Promise.resolve(o.responseText),json:()=>Promise.resolve(JSON.parse(o.responseText)),blob:()=>Promise.resolve(new Blob([o.response])),clone:s,headers:{keys:()=>i,entries:()=>a,get:t=>c[t.toLowerCase()],has:t=>t.toLowerCase()in c}});o.open(e.method||"get",t,!0),o.onload=()=>{o.getAllResponseHeaders().replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm,(t,e,r)=>{i.push(e=e.toLowerCase()),a.push([e,r]),c[e]=c[e]?`${c[e]},${r}`:r}),r(s())},o.onerror=n,o.withCredentials="include"==e.credentials;for(const t in e.headers)o.setRequestHeader(t,e.headers[t]);o.send(e.body||null)})});var r=document.createElement("script");r.src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js";var n=document.createElement("div");n.style.background="white",n.style.position="fixed",n.style.width="100vw",n.style.height="100vh",n.style.top=0,n.style.left=0,n.style.zIndex=1e6;var o=document.createTextNode("");n.appendChild(o),document.body.style.marginBottom=0,document.body.appendChild(n);var i=function(){var t;n.removeChild(n.lastChild);for(var e=arguments.length,r=new Array(e),o=0;o<e;o++)r[o]=arguments[o];(t=console).log.apply(t,r);var i=document.createElement("div");i.textContent=r.join(" "),n.appendChild(i)},a=function(){var t;n.removeChild(n.lastChild);for(var e=arguments.length,r=new Array(e),i=0;i<e;i++)r[i]=arguments[i];(t=console).error.apply(t,r);var a=document.createElement("div");a.style.color="red",a.textContent=r.join(" "),n.appendChild(a),n.appendChild(o)},c=function(){var t,r=(t=regeneratorRuntime.mark((function t(){var e,r,c,s,l,u,h,d,f,p,v,y,m,g,w,x,b,L;return regeneratorRuntime.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return i("This is the McGraw-Hill Education Textbook Downloader. Once the download completes, refresh the page to go back to the original site. Starting file download..."),n.appendChild(o),t.next=4,fetch("https://player-api.mheducation.com/lti",{credentials:"include"});case 4:return t.next=6,t.sent.json();case 6:return e=t.sent.custom_epub_url,r=new JSZip,c=r.folder("META-INF"),t.t0=c,t.next=12,fetch(e+"META-INF/container.xml",{credentials:"include"});case 12:return t.next=14,t.sent.text();case 14:return t.t1=t.sent,t.t0.file.call(t.t0,"container.xml",t.t1),s=r.folder("OPS"),t.next=19,fetch(e+"OPS/content.opf",{credentials:"include"});case 19:return t.next=21,t.sent.text();case 21:l=t.sent,s.file("content.opf",l),u=(new DOMParser).parseFromString(l,"application/xml"),h=u.querySelector("manifest").children,d=h.length,f=0;case 27:if(!(f<d)){t.next=46;break}return p=h.item(f),v=p.getAttribute("href"),t.prev=30,t.next=33,fetch("".concat(e,"OPS/").concat(v),{credentials:"include"});case 33:return t.next=35,t.sent.arrayBuffer();case 35:y=t.sent,s.file(v,y),i("Finished downloading",v,"(".concat(f," of ").concat(d,")")),t.next=43;break;case 40:t.prev=40,t.t2=t.catch(30),a("Failed to download ".concat(v,": ").concat(t.t2));case 43:f++,t.next=27;break;case 46:return i("Finished downloading data! Starting compression..."),n.appendChild(o),window.__savedTextbook=r,m=0,t.next=52,r.generateInternalStream({type:"blob",compression:"STORE"}).accumulate((function(t){var e=t.percent,r=Math.floor(e);r>m&&(i(r+"% complete"),m=r)}));case 52:g=t.sent,i("Finished compressing textbook! Starting download..."),n.appendChild(o),window.__savedTextbookEpub=g,w=URL.createObjectURL(g),(x=document.createElement("a")).href=w,b=u.querySelector("metadata title"),L=b?b.innerHTML:"textbook",x.download=L+".epub",x.click(),URL.revokeObjectURL(w);case 64:case"end":return t.stop()}}),t,null,[[30,40]])})),function(){var r=this,n=arguments;return new Promise((function(o,i){var a=t.apply(r,n);function c(t){e(a,o,i,c,s,"next",t)}function s(t){e(a,o,i,c,s,"throw",t)}c(void 0)}))});return function(){return r.apply(this,arguments)}}();document.head.appendChild(r),r.onload=c}();
// Source code for the downloader.
import('https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/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));
@bjia18
Copy link

bjia18 commented Sep 9, 2021

same problem as thatblife

@bjia18
Copy link

bjia18 commented Sep 9, 2021

oh nevermind, figured it out: @thatblife, type "javascript:" AFTER clearing address bar, not behind the address

@michaelroa2
Copy link

michaelroa2 commented Sep 14, 2021

An issue downloading two error codes.
From Program:
Textbook download failed because an error occurred: Failed to download assets/audio/chapter09/dnk7txtaudio-voc_08-009.mp3: TypeError: NetworkError when attempting to fetch resource.

From Console:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://epub-factory-cdn.mheducation.com/publish/sn_89498/35/1080mp4/OPS/assets/audio/chapter09/dnk7txtaudio-voc_08-009.mp3. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)
Also prevents the script for making any outputted files for download. The script was run locally through dev console,

@101arrowz
Copy link
Author

101arrowz commented Sep 14, 2021

I've never seen the epub-factory-cdn subdomain, but if that's not the domain in your browser window there's not much you can do with the current script. You can try editing the script and prepending a CORS proxy to each fetch request, e.g. CORS-Anywhere. After requesting access to the demo server here, add https://cors-anywhere.herokuapp.com/ before each URL in each fetch call. (If you don't know what this means, try running the original instructions without the dev console; it might work better).

As for why the download didn't work, no clue. It should function whether or not all files were successfully fetched.

Copy link

ghost commented Sep 21, 2021

how can i convert the .epub to .pdf ?

Copy link

ghost commented Sep 21, 2021

Screenshot 2021-09-21 at 4 48 15 PM

what are these errors ? ------------------- also why i cant convert it to pdf using paid apps and websites ?

@101arrowz
Copy link
Author

Most files that fail to fetch should be OK, since none of them are xhtml files you will have all the textbook content. You can open an ePub with various ebook reading software. As I mentioned earlier:

You won't get a PDF, you get an ePub file. This can be read most easily by Calibre or Adobe Digital Editions. It's possible to use Calibre to convert an ePub to PDF for normal usage.

@GBAGuy007
Copy link

Hi, I was hoping to use your downloader, but where I try to use it, it just gets stuck at the "starting file download..." screen. Linked is an image of the screen and the Dev Console. I'm using the Chrome Web Browser and while I have absolutely no experience with Javascript, it seems to be failing some sort of authentication step. I'm using Classlink, could this be causing the issue?
Mcgraw_Downloader

@101arrowz
Copy link
Author

If your URL does not include connect it's not guaranteed to work. However in this case it looks like the error is arising from a conflict with Grammarly (try disabling that extension for a bit) and/or some issue with the request to /lti (which might be a result of using Classlink).

If disabling Grammarly doesn't work and you'd like to investigate this further, you can try fiddling with the source code and hardcoding IMPORT_URL to the URL of your textbook, which you can try to find by looking in the "Requests" tab while the textbook loads. Even if you have no experience in JS it's not too difficult, you can just change the statement to const IMPORT_URL = 'https://epub-factory-cdn.mheducation.com/publish/sn_647e/5/1080mp4/' (your URL will probably be slightly different).

@jeff38724
Copy link

Hi, I have the connect version of my textbook, but i hate the reader so i wish to download it. I tried your method- first typed "javascript:" and then copy pasted that long link you put. I get nothing. The page stays the same. there is no download being initiated or any change in my screen. Help please.

@101arrowz
Copy link
Author

Make sure you put javascript:var x=new XMLHttpRequest();x.onload=function(){eval(x.responseText)};x.open('GET','https://gist.githubusercontent.com/101arrowz/88156556326106a6ccd58ecb4526498c/raw/script.js');x.send(); into the address bar rather than typing in one and replacing it with the other. The reason you can't just paste this entire thing directly is that most browsers block pasting entire scripts: scripts like this one are often used by hackers to trick people into giving up their account credentials.

If that doesn't work, you should open the developer console and send a screenshot of any errors you see.

@jeff38724
Copy link

Um still didn't work. So i took screenshots of everything I did, step by step. Uploaded on imgur.
Link= https://imgur.com/a/BBHpS8h

@101arrowz
Copy link
Author

I'll look into this. You can also try pasting the script without the javascript: prefix into the console and hitting enter, which should 100% show some kind of error.

@BellRinging
Copy link

I have downloaded and created the ebook with minor error. However, the format is hard to read because css file is missing (error on download css). Is there a way to fix download error under css file ?

@101arrowz
Copy link
Author

101arrowz commented Jan 17, 2022

You can try to redownload, sometimes it's just random chance that a download fails. It's possible to patch your existing download but probably not worth the trouble, you'd need to do quite a lot of work by finding where the resource is referenced and injecting it into the unzipped EPUB, then rezipping.

@mahmoudmmh1
Copy link

thanks a lot, it worked very well as an ebook or a pdf after converting. but I still need one thing which is the videos. I want a script support video to be downloaded not as a picture or at least as a URL separated from mc graw hill as my subscription will end sooner or alter

@Nirvanatin
Copy link

The following error appears every time I try.

This is the McGraw-Hill Education Textbook Downloader. Once the download completes, refresh the page to go back to the original site. Starting file download...
Failed to download assets/js/habitat_platform.js: TypeError: Failed to fetch
Failed to download assets/modules/mhe.mhhe-blk2/css/blk-base-page.css: TypeError: Failed to fetch
Failed to download assets/css/blk-base-patch_106-107.css: TypeError: Failed to fetch
Failed to download assets/css/dpg-custom.css: TypeError: Failed to fetch
Failed to download assets/modules/mhe.mhhe-blk2/img/icon-link-blue.svg: TypeError: Failed to fetch
Finished downloading data! Starting compression...
Finished compressing textbook! Starting download...

@101arrowz
Copy link
Author

Those errors are minor styles and scripts that failed to download, and they do not matter. The final textbook should still look fine in an ePub viewer. See this comment.

@Nirvanatin
Copy link

@101arrowz There is nothing wrong with the ePub except for some pages that are giving me this error. Is there anything that can be done to ignore this error? https://ibb.co/YhwnWQG

@x0thrmc-exe
Copy link

I don't think anyone mentioned, this seems to only work on Chrome/Chromium. And, this is has a pretty high failure rate, but you will get the books eventually if you keep trying. On huge books, the process takes hours, or more like fractions of a day. I'm on the 3rd day of trying and only successfully grabbed 4 out of the 7 books I need so far.

@101arrowz
Copy link
Author

I've tested this script on Firefox and Edge and it works on both of those browsers as well as Chrome, so it's strange it failed for you. How large are your textbooks? You might be running out of memory, this script can use up to 2x the final ePub's size in memory.

@x0thrmc-exe
Copy link

When I tested on Firefox in two different machines, nothing happened. The books are huge, around 300-500mb epub size, some with 30,000 objects listed when downloading. I have 32GB memory, but the connection seems to be pretty slow. Not really the internet itself, but the MH website specifically. Even at school, they load extremely slow and the site is buggy which is why I needed this. Cannot believe they won't provide easy offline use for paying subscribers.

@emi-exe
Copy link

emi-exe commented Aug 23, 2022

worked in edge 104.0.1293.63, but did not work in firefox 104.0 - nothing happened. perhaps default javascript protection is interfering?

@quadradia
Copy link

Open Chrome in incognito mode, login to your mcgraw hill account, follow instructions above.

script

Download Adobe Digital Editions add the .epub file to your library.

Wonderful! Thank you.

@Zi45p
Copy link

Zi45p commented Oct 9, 2022

You are my hero, many thanks.
thumbsup052812

@giwty
Copy link

giwty commented Oct 30, 2022

Thank you, their site is so bad, so this is super helpful.
I did need to change the script to use "EPUB" in the path instead of "OPT".
For instance -
const data = await (await fetch(`${IMPORT_URL}EPUB/${href}`, { credentials: 'include' })).arrayBuffer();

Also, it didnt work for me on Firefox using the url bar, so ended up just pasting the actual script.js in the developers tools console tab, then it worked like magic :)

@ArshanSS
Copy link

Works just fine.

@CR-S01
Copy link

CR-S01 commented Jan 17, 2023

Couldn't execute the script in firefox url bar, worked fine in chrome.

Only took ~10 minutes to download a 630 page textbook for me, great script!

@iiDaxter
Copy link

iiDaxter commented Feb 4, 2023

Thank you so much! Do you have a Pearson eText solution?

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