Adding queue for download.

This commit is contained in:
Vahagn Khachatryan
2019-02-09 10:59:51 +00:00
parent 5365385bd5
commit 0654ae807a
2 changed files with 269 additions and 127 deletions

View File

@@ -22,30 +22,19 @@
</style> </style>
</head> </head>
<body> <body>
<button id="download-book-button" type="button" class="btn btn-outline-primary">Download Book</button> <!-- <button id="add-book-button" type="button" class="btn btn-primary">Add Book</button> -->
<button id="download-book-button" type="button" class="btn btn-primary">Download</button>
<div class="status"> <div id="book-list" class="container">
<p id="error-message" class="bg-warning"></p> <ul id="book-queue" class="list-group">
<div class="loader" id="loading" style="display:none;"> </ul>
<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>
<div id="book-info" class="container"> <div id="book-info" class="container">
<h4 id="book-info-notice"></h4>
<img id="book-cover" src="" class="img-fluid">
<p class="bg-success"> <p class="bg-success">
<span><strong>Book Name:</strong></span> <span><strong>Book Name:</strong></span>
<span id="book-name"></span> <span id="book-name"></span>
</p> </p>
<img id="book-cover" src="" class="img-fluid">
<p class="bg-success"> <p class="bg-success">
<span ><strong>Progress: </strong></span> <span ><strong>Progress: </strong></span>
</p> </p>
@@ -54,26 +43,16 @@
</div> </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"> <link rel="stylesheet" href="3pty/bootstrap.min.css">
<script src="3pty/bluebird.js"></script> <script src="3pty/bluebird.js"></script>
<script src="3pty/jszip.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/jquery-3.1.1.slim.min.js"></script>
<script src="3pty/tether.min.js"></script> <script src="3pty/tether.min.js"></script>
<script src="3pty/bootstrap.min.js"></script> <script src="3pty/bootstrap.min.js"></script>
<script src="epub.js"></script>
<script src="sidebar.js"></script>
</body> </body>
</html> </html>

View File

@@ -1,48 +1,12 @@
var concurrency = 5 var concurrency = 5
var retry_delay = 15/* seconds */ var retry_delay = 15/* seconds */
var book_delay = 300/* seconds */
var download_list = []
function sleep(delay) { function sleep(delay) {
return new Promise((resolve) => setTimeout(resolve, delay*1000)); return new Promise((resolve) => setTimeout(resolve, delay*1000));
} }
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.';
}
});
}
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 Book{ class Book{
constructor(book_id, page) { constructor(book_id, page) {
@@ -57,6 +21,25 @@ class Book{
this.page = page this.page = page
} }
addToLocalPlaylist(){
let method = "https://learning.oreilly.com/api/v2/collections/92f0712e-eb58-4c6e-939e-d5c57a7e6d90/add-content/"
let request = {
content: [`/api/v1/book/${this.book_id}/`]
}
return fetch(method, {
method: "post",
body: JSON.stringify(request),
headers: new Headers({
"Accept" : "application/json; version=v2",
"Content-Type": "application/json"
}),
credentials: 'include'
})
.then((res)=>{
console.warn(`Post ${method} - ${res.status} - ${res.statusText}`)
})
}
downloadResource(url, retry=false){ downloadResource(url, retry=false){
if (retry){ if (retry){
console.warn(`Retry ${url}`) console.warn(`Retry ${url}`)
@@ -212,50 +195,120 @@ class Book{
} }
} }
/*************************************************************************/
class SidebarPage{ class SidebarPage{
constructor() { constructor() {
$('#loading').show(); $('#book-info').hide()
$('#error-message').hide();
$('#book-info').hide();
$("#book-file-list").empty();
this.id = 1 this.id = 1
} }
renderInfo(book){ getUniqueueId(){
$("#book-name").text(book.book_info.title); let id = `item_${this.id}`
this.id++
return id
}
loading_animatedDot(){
return $('<snap/>')
.addClass('loader__dot')
.text('.')
}
loading_animation(){
return $('<snap/>')
.attr('id', 'dot_animation')
.append(this.loading_animatedDot())
.append(this.loading_animatedDot())
.append(this.loading_animatedDot())
}
remove_loading_animation(){
$('#dot_animation').remove()
}
/****************************************************/
renderBookItemId(book_id){
let id = this.getUniqueueId()
let link = $('<a/>')
.attr('href', `https://learning.oreilly.com/search/?query=${book_id}`)
.attr('id', `a_${id}`)
.text(`${book_id}`)
var book_item =
$("<li></li>")
.addClass("list-group-item")
.attr('id', id)
.append(link)
$("#book-queue").prepend(book_item);
return id
}
renderBookItemNameAndURL(id, name, url){
$('#a_'+id)
.attr('href', url)
.text(name)
}
renderBookItemAnimatedLoading(id){
$('#'+id)
.append(this.loading_animation())
}
renderBookItemSuccess(id){
this.remove_loading_animation()
$('#'+id)
.css( "color", "green" )
.append(' - OK');
}
renderBookItemFail(id, err){
this.remove_loading_animation()
$('#'+id)
.css( "color", "red" )
.append(' - Fail: ')
.append(err)
}
/****************************************************/
renderBookBeginLoading(id){
$('#book-info').hide();
$("#book-file-list").empty();
this.renderBookItemAnimatedLoading(id)
}
renderBookInfo(book, id){
$("#book-cover").attr("src", book.book_info.cover); $("#book-cover").attr("src", book.book_info.cover);
let link = $('<a/>')
.attr('href', book.book_info.web_url)
.text(book.book_info.title)
$("#book-name").empty()
.append(link);
this.renderBookItemNameAndURL(id,
book.book_info.title,
book.book_info.web_url)
$('#book-info').show(); $('#book-info').show();
} }
renderDoneWithBook(){ renderBookSuccess(id){
$('#loading').hide(); this.renderBookItemSuccess(id)
} }
renderFailedTheBook(error) { renderBookFail(id, err){
console.error(`Error: ${error}`); this.renderBookItemFail(id, err)
$('#loading').hide();
$('#error-message').text(`Error: ${error}`);
$('#error-message').show();
// $('#book-info').hide();
} }
renderChapterList(book){ /****************************************************/
// Add chapters to UI
for (let chapter_idx in book.chapter_list) {
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();
}
renderProgress(txt){ renderProgress(txt){
let id = `item_${this.id}` let id = this.getUniqueueId()
this.id++
// Add chapters to UI // Add chapters to UI
var progress_dom = $("<li></li>") var progress_dom = $("<li></li>")
.addClass("list-group-item") .addClass("list-group-item")
@@ -278,7 +331,9 @@ class SidebarPage{
.attr('title',reason.message); .attr('title',reason.message);
} }
} }
var page = new SidebarPage()
/*********************************************************/
function fillMetadata(epub, book) function fillMetadata(epub, book)
{ {
@@ -390,42 +445,152 @@ function createEpub(book, epub){
} }
} }
/*********************************************************************/
function downloadBook(book_id, item_id){
let epub = new EpubWriter();
let book = new Book(book_id, page);
return book.downloadBookInfo()
.then(() => { page.renderBookInfo(book, item_id); })
.then(() => { return book.downloadMetaContent(); })
.then(() => { return book.downloadContent(); })
.then(() => { return createEpubStructure(book, epub); })
.then(() => { return createEpub(book, epub); })
.then(() => { return epub.generateAsync(); })
.then((file) => {
let title = book.book_info.title
let filename = "books/"
+ title.replace(/[^a-z0-9]/gi, '_').toLowerCase()
+ ".epub"
console.log(`Zip file name ${filename}`)
page.renderProgress(`Saved to ${filename}`)
let url = window.URL.createObjectURL(file)
return browser.downloads.download({ "filename" : filename, url : url})
})
.then(()=>{
// Add to playlist "local" to indicate that this book
// is already downloaded.
return book.addToLocalPlaylist()
})
}
/*********************************************************************/
var progress = false
function downloadNextBook(){
progress = true
let download = download_list.pop()
item_id = download.page_id
book_id = download.book_id
page.renderBookBeginLoading(item_id)
downloadBook(book_id, item_id)
.then(() =>{
page.renderBookSuccess(item_id);
})
.catch((error)=>{
page.renderBookFail(item_id, error);
})
.then(()=>{
if (download_list.length){
return sleep(book_delay)
.then(()=>{
return downloadNextBook()
})
}
else{
progress = false
}
});
}
/*********************************************************************/
function getCurrentTabUrl() {
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.';
}
});
}
function closeCurrentTab() {
console.debug("Querying active tab.");
var queryInfo = {
active: true,
currentWindow: true
};
return browser.tabs.query(queryInfo)
.then(function(tabs) {
if (tabs.length == 1){
let tabId = tabs[0].id;
console.info(`Closing tab: ${tabId}`);
return browser.tabs.remove(tabId);
} else {
console.error(`Expected 1 active tab, received: ${tabs}`);
throw 'Failed to get active tab.';
}
});
}
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.';
}
}
function onDownloadBookClicked(){ function onDownloadBookClicked(){
console.info("Begin book download."); console.info("Begin book download.");
page = new SidebarPage()
getCurrentTab() getCurrentTabUrl()
.then(extractBookId) .then((url)=>{
.then((book_id) => { return extractBookId(url)
epub = new EpubWriter(); })
book = new Book(book_id, page); .then((book_id)=>{
return book.downloadBookInfo() closeCurrentTab()
.then(() => { page.renderInfo(book); }) return book_id
// .then(() => { return book.downloadChapterList(); }) })
// .then(() => { return page.renderChapterList(book); }) .then((book_id)=>{
.then(() => { return book.downloadMetaContent(); }) page_id = page.renderBookItemId(book_id)
.then(() => { return book.downloadContent(); }) download_list.push({
.then(() => { return createEpubStructure(book, epub); }) book_id : book_id,
.then(() => { return createEpub(book, epub); }) page_id : page_id
.then(() => { return epub.generateAsync(); })
.then((file) => {
let title = book.book_info.title
let filename = "books/"
+ title.replace(/[^a-z0-9]/gi, '_').toLowerCase()
+ ".epub"
console.log(`Zip file name ${filename}`)
page.renderProgress(`Saved to ${filename}`)
let url = window.URL.createObjectURL(file)
return browser.downloads.download({ "filename" : filename, url : url})
}) })
}) })
.then(() =>{ .then(()=>{
page.renderDoneWithBook(); if (download_list.length && !progress){
downloadNextBook()
}
}) })
.catch((error)=>{
page.renderFailedTheBook(error);
});
} }
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
@@ -438,8 +603,6 @@ document.addEventListener('DOMContentLoaded', function() {
onDownloadBookClicked(); onDownloadBookClicked();
}); });
$('#deselect-all-button').show() $('#deselect-all-button').show()
$('#download-button').show() $('#download-button').show()
$('#download-section').hide(); $('#download-section').hide();