First cut.
36
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
// {
|
||||||
|
// "name": "Launch index.html",
|
||||||
|
// "type": "firefox",
|
||||||
|
// "request": "launch",
|
||||||
|
// "reAttach": true,
|
||||||
|
// "file": "${workspaceFolder}/index.html"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "Launch localhost",
|
||||||
|
// "type": "firefox",
|
||||||
|
// "request": "launch",
|
||||||
|
// "reAttach": true,
|
||||||
|
// "url": "http://localhost/index.html",
|
||||||
|
// "webRoot": "${workspaceFolder}"
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "name": "Attach",
|
||||||
|
// "type": "firefox",
|
||||||
|
// "request": "attach"
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
"name": "Launch addon",
|
||||||
|
"type": "firefox",
|
||||||
|
"request": "launch",
|
||||||
|
"reAttach": true,
|
||||||
|
"addonType": "webExtension",
|
||||||
|
"addonPath": "${workspaceFolder}/src"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
5619
src/3pty/bluebird.js
Normal file
6
src/3pty/bootstrap-theme.min.css
vendored
Normal file
6
src/3pty/bootstrap.min.css
vendored
Normal file
7
src/3pty/bootstrap.min.js
vendored
Normal file
4
src/3pty/jquery-3.1.1.slim.min.js
vendored
Normal file
11391
src/3pty/jszip.js
Normal file
1
src/3pty/tether.min.js
vendored
Normal file
38
src/epub.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
class EpubWriter{
|
||||||
|
constructor(book_id) {
|
||||||
|
this.zip = new JSZip();
|
||||||
|
|
||||||
|
this.filename = "test";
|
||||||
|
|
||||||
|
this.createEpubStruct();
|
||||||
|
|
||||||
|
// this.image
|
||||||
|
|
||||||
|
// this.book_id = book_id;
|
||||||
|
// this.raw_book = [];
|
||||||
|
// this.chapter_list = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
createEpubStruct(){
|
||||||
|
this.zip.file("mimetype", "application/epub+zip", {compression: "STORE"});
|
||||||
|
this.zip.file("META-INF/container.xml", `
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<container xmlns="urn:oasis:names:tc:opendocument:xmlns:container" version="1.0">
|
||||||
|
<rootfiles>
|
||||||
|
<rootfile media-type="application/oebps-package+xml" full-path="EPUB/content.opf"/>
|
||||||
|
</rootfiles>
|
||||||
|
</container>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
addFile(name, content){
|
||||||
|
console.log(`epub ${name}: ${content}`)
|
||||||
|
this.zip.file("EPUB/"+name, content)
|
||||||
|
}
|
||||||
|
|
||||||
|
generateAsync(){
|
||||||
|
return this.zip.generateAsync({
|
||||||
|
type: 'blob',
|
||||||
|
compression: "DEFLATE"})
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/icon/book-128.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
src/icon/book-16.png
Normal file
|
After Width: | Height: | Size: 688 B |
BIN
src/icon/book-24.png
Normal file
|
After Width: | Height: | Size: 984 B |
BIN
src/icon/book-256.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
src/icon/book-32.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/icon/book-64.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
src/icon/book-download-128.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
src/icon/book-download-16.png
Normal file
|
After Width: | Height: | Size: 516 B |
BIN
src/icon/book-download-24.png
Normal file
|
After Width: | Height: | Size: 563 B |
BIN
src/icon/book-download-256.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
src/icon/book-download-32.png
Normal file
|
After Width: | Height: | Size: 772 B |
BIN
src/icon/book-download-64.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
57
src/icon/book-download.svg
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 539.077 539.077" style="enable-background:new 0 0 539.077 539.077;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path d="M213.385,539.077H78.615c-30.961,0-56.154-25.181-56.154-56.154V67.385c0-1.206,0.186-2.358,0.537-3.444
|
||||||
|
c-0.351-2.544-0.537-5.144-0.537-7.787C22.462,25.192,47.654,0,78.615,0h381.846c6.208,0,11.231,5.023,11.231,11.231
|
||||||
|
s-5.023,11.231-11.231,11.231H78.615c-18.579,0-33.692,15.113-33.692,33.692s15.113,33.692,33.692,33.692h381.846
|
||||||
|
c6.208,0,11.231,5.023,11.231,11.231v101.077c0,6.208-5.023,11.231-11.231,11.231c-6.208,0-11.231-5.023-11.231-11.231v-89.846
|
||||||
|
H78.615c-12.635,0-24.304-4.19-33.692-11.253v381.868c0,18.579,15.113,33.692,33.692,33.692h134.769
|
||||||
|
c6.208,0,11.231,5.023,11.231,11.231C224.615,534.054,219.592,539.077,213.385,539.077z"/>
|
||||||
|
<path d="M370.615,539.077c-80.502,0-146-65.498-146-146s65.498-146,146-146s146,65.498,146,146S451.117,539.077,370.615,539.077z
|
||||||
|
M370.615,269.538c-68.108,0-123.538,55.43-123.538,123.538s55.43,123.538,123.538,123.538s123.538-55.43,123.538-123.538
|
||||||
|
S438.724,269.538,370.615,269.538z"/>
|
||||||
|
<path d="M370.615,460.462c-0.088,0-0.197,0-0.285,0l0,0c-0.022,0-0.022,0-0.022,0c-0.022,0-0.022,0-0.022,0l0,0
|
||||||
|
c-1.404-0.044-2.742-0.351-3.948-0.855c-1.228-0.483-2.369-1.228-3.4-2.172l0,0c0,0,0-0.022-0.022-0.022c0,0,0,0,0-0.022l0,0
|
||||||
|
c-0.088-0.066-0.175-0.154-0.263-0.241l-44.901-44.901c-4.387-4.387-4.387-11.494,0-15.881s11.494-4.387,15.881,0l25.752,25.752
|
||||||
|
v-85.196c0-6.208,5.023-11.231,11.231-11.231s11.231,5.023,11.231,11.231v85.196l25.752-25.752c4.387-4.387,11.494-4.387,15.881,0
|
||||||
|
s4.387,11.494,0,15.881l-44.901,44.901c-0.088,0.088-0.175,0.175-0.263,0.241l0,0c0,0.022,0,0.022,0,0.022
|
||||||
|
c-0.022,0-0.022,0.022-0.022,0.022l0,0c-1.031,0.943-2.172,1.689-3.4,2.172c-1.228,0.504-2.544,0.812-3.948,0.855l0,0
|
||||||
|
c0,0,0,0-0.022,0c0,0,0,0-0.022,0l0,0C370.813,460.462,370.703,460.462,370.615,460.462z M438,67.385H78.615
|
||||||
|
c-6.208,0-11.231-5.023-11.231-11.231s5.023-11.231,11.231-11.231H438c6.208,0,11.231,5.023,11.231,11.231
|
||||||
|
S444.208,67.385,438,67.385z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |
50
src/icon/book.svg
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||||
|
<circle style="fill:#005C83;" cx="256" cy="256" r="256"/>
|
||||||
|
<path style="fill:#00263F;" d="M191.666,437.01l74.761,74.761C402.975,506.298,512,393.891,512,256
|
||||||
|
c0-10.316-0.628-20.484-1.814-30.48L393.667,109L191.666,437.01z"/>
|
||||||
|
<rect x="153.78" y="109" style="fill:#FF6838;" width="194.47" height="270.74"/>
|
||||||
|
<rect x="240.48" y="109" style="fill:#A04630;" width="107.78" height="270.74"/>
|
||||||
|
<rect x="327.87" y="109" style="fill:#AE4E32;" width="65.793" height="270.74"/>
|
||||||
|
<rect x="327.87" y="211.47" style="fill:#FF9451;" width="65.793" height="65.793"/>
|
||||||
|
<rect x="178.24" y="155" style="fill:#FFCF35;" width="121.11" height="22.707"/>
|
||||||
|
<rect x="240.48" y="155" style="fill:#FFB344;" width="58.868" height="22.707"/>
|
||||||
|
<rect x="178.24" y="188.77" style="fill:#FFCF35;" width="121.11" height="22.707"/>
|
||||||
|
<rect x="240.48" y="188.77" style="fill:#FFB344;" width="58.868" height="22.708"/>
|
||||||
|
<polygon style="fill:#FFFFFF;" points="255.526,323.654 209.167,370.013 209.167,259.795 174.167,259.795 174.167,370.014
|
||||||
|
127.808,323.654 103.06,348.402 191.666,437.01 280.274,348.403 "/>
|
||||||
|
<polygon style="fill:#B9EAFF;" points="191.666,437.01 280.274,348.403 255.526,323.654 209.167,370.013 209.167,259.795
|
||||||
|
191.666,259.795 "/>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
BIN
src/icon/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
src/icon/icon.png
Normal file
|
After Width: | Height: | Size: 973 B |
55
src/manifest.json
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 2,
|
||||||
|
"name": "Safari-Hunt",
|
||||||
|
"version": "1.0",
|
||||||
|
|
||||||
|
"description": "Hunt safarionline",
|
||||||
|
|
||||||
|
"icons": {
|
||||||
|
"16": "icon/book-download-16.png",
|
||||||
|
"24": "icon/book-download-24.png",
|
||||||
|
"32": "icon/book-download-32.png",
|
||||||
|
"64": "icon/book-download-64.png"
|
||||||
|
},
|
||||||
|
|
||||||
|
"permissions": [
|
||||||
|
"activeTab",
|
||||||
|
"tabs",
|
||||||
|
"downloads",
|
||||||
|
"*://*.safaribooksonline.com/*"
|
||||||
|
],
|
||||||
|
|
||||||
|
"browser_action": {
|
||||||
|
"default_icon": {
|
||||||
|
"16": "icon/book-download-16.png",
|
||||||
|
"24": "icon/book-download-24.png",
|
||||||
|
"32": "icon/book-download-32.png",
|
||||||
|
"64": "icon/book-download-64.png"
|
||||||
|
},
|
||||||
|
"default_title": "Hunt Safari Online"
|
||||||
|
},
|
||||||
|
|
||||||
|
"background": {
|
||||||
|
"page": "safarihunt.html"
|
||||||
|
},
|
||||||
|
|
||||||
|
"sidebar_action": {
|
||||||
|
"default_icon": {
|
||||||
|
"16": "icon/book-download-16.png",
|
||||||
|
"24": "icon/book-download-24.png",
|
||||||
|
"32": "icon/book-download-32.png",
|
||||||
|
"64": "icon/book-download-64.png"
|
||||||
|
},
|
||||||
|
"default_title": "Hunt Safari Online",
|
||||||
|
"default_panel": "sidebar.html",
|
||||||
|
"open_at_install":true
|
||||||
|
}
|
||||||
|
|
||||||
|
// "content_scripts": [
|
||||||
|
// {
|
||||||
|
// "matches": ["*://*.safaribooksonline.com/*"],
|
||||||
|
// "js": ["safarihunt.js"]
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
|
||||||
|
}
|
||||||
7
src/popup.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<script type="module" src="safarihunt.js"></script>
|
||||||
|
</head>
|
||||||
|
</html>
|
||||||
1
src/popup.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// document.body.style.border = "5px solid red";
|
||||||
7
src/safarihunt.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<script type="module" src="safarihunt.js"></script>
|
||||||
|
</head>
|
||||||
|
</html>
|
||||||
2
src/safarihunt.js
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
console.log("test")
|
||||||
|
// document.body.style.border = "5px solid red";
|
||||||
79
src/sidebar.html
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<script type="module" src="safarihunt.js"></script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: "Segoe UI", "Lucida Grande", Tahoma, sans-serif;
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
#status {
|
||||||
|
/* avoid an excessively wide status text */
|
||||||
|
white-space: pre;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
@keyframes blink {50% { color: transparent }}
|
||||||
|
.loader__dot { animation: 1s blink infinite }
|
||||||
|
.loader__dot:nth-child(2) { animation-delay: 250ms }
|
||||||
|
.loader__dot:nth-child(3) { animation-delay: 500ms }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<button id="download-book-button" type="button" class="btn btn-outline-primary">Download Book</button>
|
||||||
|
|
||||||
|
<div class="status">
|
||||||
|
<p id="error-message" class="bg-warning"></p>
|
||||||
|
<div class="loader" id="loading" style="display:none;">
|
||||||
|
<p class="bg-success">
|
||||||
|
<strong>
|
||||||
|
Loading book info
|
||||||
|
<span class="loader__dot">.</span>
|
||||||
|
<span class="loader__dot">.</span>
|
||||||
|
<span class="loader__dot">.</span>
|
||||||
|
</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="book-info" class="container">
|
||||||
|
<h4 id="book-info-notice"></h4>
|
||||||
|
|
||||||
|
<img id="book-cover" src="" class="img-fluid">
|
||||||
|
<p class="bg-success">
|
||||||
|
<span><strong>Book Name:</strong></span>
|
||||||
|
<span id="book-name"></span>
|
||||||
|
</p>
|
||||||
|
<p class="bg-success">
|
||||||
|
<span ><strong>Chapters: </strong></span>
|
||||||
|
</p>
|
||||||
|
<ul id="book-chapter-list" class="list-group">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div id="download-section">
|
||||||
|
<p id="download-warning" style="display: none;" class="bg-warning"></p>
|
||||||
|
<button id="download-button" type="button" style="display: none;" class="btn btn-primary">Download above chapters as zip package</button>
|
||||||
|
<p id="book-name"><strong></strong></p>
|
||||||
|
<div id="status"></div>
|
||||||
|
<img id="image-result" hidden>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="3pty/bootstrap.min.css">
|
||||||
|
|
||||||
|
<script src="3pty/bluebird.js"></script>
|
||||||
|
<script src="3pty/jszip.js"></script>
|
||||||
|
<script src="epub.js"></script>
|
||||||
|
<script src="sidebar.js"></script>
|
||||||
|
|
||||||
|
<script src="3pty/jquery-3.1.1.slim.min.js"></script>
|
||||||
|
<script src="3pty/tether.min.js"></script>
|
||||||
|
<script src="3pty/bootstrap.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
304
src/sidebar.js
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
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 = $("<li></li>")
|
||||||
|
.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();
|
||||||
|
})
|
||||||