document.body.style.border = "5px solid red"; function onError(error) { console.error(`Error: ${error}`); $('#error-message').text(`Error: ${error}`); $('#error-message').show(); $('#loading').hide(); $('#book-info').hide(); } function getCurrentTab() { console.debug("Querying active tab."); var queryInfo = { active: true, currentWindow: true }; return browser.tabs.query(queryInfo) .then(function(tabs) { if (tabs.length == 1){ let url = tabs[0].url; console.info(`Active URL: ${url}`); return url; } else { console.error(`Expected 1 active tab, received: ${tabs}`); throw 'Failed to get active tab.'; } }, onError); } function extractBookId(url){ console.debug(`Extracting book id from ${url}`); // match a url like: // https://www.safaribooksonline.com/library/view/startup-opportunities-2nd/9781119378181/ // https://www.safaribooksonline.com/library/view/startup-growth-engines/77961SEM00001/ let match = url.match(/\/library\/view\/[^\/]+\/(\w+)\//); let bookId = match && match[1]; if (bookId) { console.debug(`Extracted book id: ${bookId}`); return bookId; }else{ console.error('Could not extract book id from url, only ' +'domain "www.safaribooksonline.com“ is supported.'); throw 'Failed to extract book id.'; } } // class MiniWebServer{ // constructor() { // this.url = "http://127.0.0.1:8080/test.zip" // } // downloadTestZip(){ // console.info(`Downloading ${this.url}`) // return fetch(this.url, { // credentials: 'include' // }).then((res) => { // console.log(`Getting blob.`) // return res.blob() // }).then(JSZip.loadAsync) // .then((zip) => { // this.zip = zip // }) // } // fetchUrl(url){ // let name = "meta/"+url.replace(/[^a-z0-9]/gi, '_').toLowerCase() // this.zip.file(name) // . // } // } class Book{ constructor(book_id, epub) { this.book_id = book_id; this.raw_book = {}; this.chapter_list = []; this.book_files = {} this.book_info = null this.book_toc = null this.book_flattoc = null } downloadResource(url){ console.info(`Downloading ${url}`) return fetch(url, { credentials: 'include' }).then((res) => { console.log(`Downloaded.`) return res; }, onError) } downloadJson(url){ return this.downloadResource(url) .then((res) => { return res.json(); }, onError); } downloadBookInfo(){ console.info(`Downloading book info for ${this.book_id}`); let url = `https://www.safaribooksonline.com/api/v1/book/${this.book_id}/`; return this.downloadJson(url) .then((book_info)=>{ this.book_info = book_info; }, onError); } downloadChapterList(){ function helper(book, url){ console.info(`Downloading chapter list ${url}`); return book.downloadJson(url) .then((chapter_list)=>{ book.chapter_list = book.chapter_list.concat(chapter_list.results); if (chapter_list.next != null){ return helper(book, chapter_list.next); } }, onError); } return helper(this, this.book_info.chapter_list) .then(() => { console.info(`Chapter List Downloaded.`); }, onError); } downloadMetaContent(){ let downloads = [] this.insertBookFile({ url: this.book_info.cover, file: "cover.img", context: null, mime: null }) downloads.push( this.downloadJson(this.book_info.toc) .then((json)=>{ this.book_toc=json })) downloads.push( this.downloadJson(this.book_info.flat_toc) .then((json)=>{ this.book_flattoc=json })) downloads.push( Promise.map(this.book_info.chapters, (chapter) => { return this.downloadJson(chapter) .then((json) => { return this.extractChapterAssets(json) }) },{concurrency: 1})) return Promise.all(downloads) } downloadMetaContent(){ let downloads = [] // downloads.push(this.downloadResource(this.book_info.cover)) downloads.push( this.downloadJson(this.book_info.toc) .then((json)=>{ this.book_toc=json })) downloads.push( this.downloadJson(this.book_info.flat_toc) .then((json)=>{ this.book_flattoc=json })) downloads.push( Promise.map(this.book_info.chapters, (chapter) => { return this.downloadJson(chapter) .then((json) => { return this.extractChapterAssets(json) }) },{concurrency: 1})) return Promise.all(downloads) } extractChapterAssets(json){ if (!json.asset_base_url || !json.content){ throw "Missing data." } // Html this.insertBookFile({ url: json.content, file: json.full_path, context: null, mime: null }) // List of images. for (let idx in json.images){ this.insertBookFile({ url: json.asset_base_url + json.images[idx], file: json.images[idx], context: null, mime: null }) } // List of stylesheets. for (let idx in json.stylesheets){ this.insertBookFile({ url: json.stylesheets[idx].original_url, file: json.stylesheets[idx].full_path, context: null, mime: null }) } } insertBookFile(obj){ this.book_files[obj.url] = obj } } function renderInfo(book){ $("#book-name").text(book.book_info.title); $("#book-cover").attr("src", book.book_info.cover); $('#book-info').show(); } function renderChapterList(book){ // Add chapters to UI for (let chapter_idx in book.chapter_list) { console.log(book.chapter_list[chapter_idx]) let chapter = book.chapter_list[chapter_idx]; var chapter_dom = $("
") .addClass("list-group-item") .html(chapter.title) .attr("chapterIndex", chapter_idx); $("#book-chapter-list").append(chapter_dom); } $('#loading').hide(); } function createEpub(book, epub){ for (let url in book.raw_book){ let name = "meta/"+book.raw_book[url].url.replace(/[^a-z0-9]/gi, '_').toLowerCase() epub.addFile(name, book.raw_book[url].clone().blob()) } // epub.addFile("book_info.json", JSON.stringify(book.book_info)) // epub.addFile("book_files.json", JSON.stringify(book.book_files)) // epub.addFile("book_toc.json", JSON.stringify(book.book_toc)) // epub.addFile("book_flattoc.json", JSON.stringify(book.book_flattoc)) epub.addFile("book.json", JSON.stringify(book, null, '\t')) } function onDownloadBookClicked(){ console.info("Begin book download."); $('#loading').show(); $('#error-message').hide(); $('#book-info').hide(); getCurrentTab() .then(extractBookId, onError) .then((book_id) => { epub = new EpubWriter(); book = new Book(book_id); book.downloadBookInfo() .then(() => { renderInfo(book); }) .then(() => { return book.downloadChapterList(); }) .then(() => { return renderChapterList(book); }) .then(() => { return book.downloadContent(); }) .then(() => { return createEpub(book, epub); }) .then(() => { return epub.generateAsync(); }) .then((file) => { let filename = "books/" + "test" + ".zip" // book.filename.replace(/[^a-z0-9]/gi, '_').toLowerCase() let url = window.URL.createObjectURL(file) browser.downloads.download({ "filename" : filename, url : url}) }) }, onError); } document.addEventListener('DOMContentLoaded', function() { console.log("Start safari book hunter."); $('#loading').hide(); $('#error-message').hide(); $('#book-info').hide(); $('#download-book-button').click(() => { onDownloadBookClicked(); }); $('#deselect-all-button').show() $('#download-button').show() $('#download-section').hide(); // let bookInfo = new BookInfo(); })