Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Percentage of loading #319

Open
mQckingbird opened this issue Nov 18, 2015 · 18 comments
Open

Percentage of loading #319

mQckingbird opened this issue Nov 18, 2015 · 18 comments

Comments

@mQckingbird
Copy link

Hi everyone,

Some ebooks with many images take forever to download. And that's ok.

But I really need to show a percentage of the download when the user click the eBook for the first time, because it really looks like an error, «wow, something happen to this. well, I better go» said the user.

Something like: %53 Loading

So.. ¿how can I do it?

Thanks in advance!

@matewilk
Copy link
Contributor

What do you exactly mean by downloading? You can download to your computer, but I suppose you are talking about uploading a book from a sever/client to ePub ?

@mQckingbird
Copy link
Author

No. When you load an ebook for the first time with epub.js, it can take awhile. It shows the gif of loading, but in some books it takes forever to finally load for first time, and then put the book in storage.

What I want is an percentage indicator, like %1 Loading.. %2 Loading.. %60 Loading.. ...
so the user don't get lost.

@mQckingbird
Copy link
Author

Thanks for the quick answer, I am really in a hurry :(

@mQckingbird mQckingbird changed the title Percentage of download Percentage of loading Nov 18, 2015
@fchasen
Copy link
Contributor

fchasen commented Nov 18, 2015

Is this with a zipped ePub file?

@matewilk
Copy link
Contributor

Sorry for the late reply, I don't know this part of code but I imagine there is a hook for it. So if you could take a look at hooks directory, maybe you can find something useful.

Another option is to implement it in your javascript code, but I don't know what technology/library you are using and how your code looks like, so I would need more input and ideally the code itself.

Another option would be to implement custom javascript events and respond to them with starting/stopping a loading spinner.

@mQckingbird
Copy link
Author

@fchasen yes, it is. all of them are zipped .epub files.

@matewilk well, the spinner is already showing up. i had checked out the hooks directory, but all I came up was a lazy solution.
Start at 0% when the epubReader(); function is called, and goes on 'till 99% and when the book is ready, shows 100%.
But, It won't be precise, and the user will realize. ¿How can I hook the precise percentage?

@matewilk
Copy link
Contributor

I'm NOT one of the authors of ePub library, I'm just an ordinary user of ePub class but can you please tell me where do you keep your books and how you upload them?

I personally keep my books in the app (my own app on top of ePub) directory as zipped files, and I'm uploading the books using node.js by providing ePub constructor with a url to my node.js api url.
I'm doing it on localhost, so I haven't gone trough this problem as upload takes couple of millisecond, but if I had the same problem, I would create a spinner with an ajax request listener on it.

It would look something like this:

var ajaxRequest = new XMLHttpRequest();
ajaxRequest.upload.addEventListener('progress', function(event){
   //progress is a variable usually used to change styling of an element on the page
    var progress = Math.ceil(event.loaded / event.total) * 100 + '%';
    //so here you would change the width of the element on the page (progressbar)
}, false);

So basically what I'm saying here, that I don't really know where the problem is, is it your app architecture problem, or ePub library itself ? What are your findings ?

Do you have a github repo so I could take a look at it ?

@mQckingbird
Copy link
Author

In localhost doesn't take any time, is fast. The problem (as always) is when people access. Sartre was right, hell is other people.
That's a nice approach, but ¿what's the deal with xmlhttprequest()? ¿Are you loading the ePubs from a different server? (that would blow my head off, lol)

Adding a eventlistener is a good idea, but ¿where the .loaded and .total event are defined?

The only thing I have to support me on, is the function ePubReader() (when everything starts), and the book.ready.all.then() (when everything is loaded)

So.. ¿the total would be the size of the file?
I'm still very confused, sorry for the inconvenience

@fchasen
Copy link
Contributor

fchasen commented Nov 20, 2015

So the first thing I would recommend is trying an unzipped epub. It will be much faster as it doesn't need to wait for the entire epub to load and doesn't need to decode the images.

The progress listener seems like a great approach if the issue is downloading the epub, though there will be some processing time after that won't be accounted for.

I'd add progress to the request function here https://github.com/futurepress/epub.js/blob/master/src/core.js#L18
but I'm not sure how you'd listen for just the progress events from loading the initial files though. Will need to look into that a bit.

xhr.addEventListener("progress", updateProgress);

// progress on transfers from the server to the client (downloads)
function updateProgress (oEvent) {
  if (oEvent.lengthComputable) {
    var percentComplete = oEvent.loaded / oEvent.total;
    // ...
  } else {
    // Unable to compute progress information since the total size is unknown
  }
}

from: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest

@matewilk
Copy link
Contributor

Well, I'm just keeping my books on the server, and I send ajax request to fetch a book from it and pass to the client (front-end) app where ePub constructor is invoked.

Based on what you said, I assume, the problem is with ePubReader. You have some events that you can listen to, so that's great.
Now my question is, why do you want a user, to see progress ? Wouldn't it be easier to display a loading spinner without percentage? (as progress functionality is not provided by ePubReader)

If it takes ages to load, than I would add some funny text underneath the spinner to hold the user a bit longer before eventually dropping the page. But I suppose it doesn't take so long to finally display the book.

P.S. load and total event properties are part of XMLHttpRequest (ajax) and @fchasen provided you with the url to get to know a bit more about it. Basically you don't have to worry about these properties, they just work and are part of the ajax implementation.

@mQckingbird
Copy link
Author

Take Netflix for example. I know that the size of books and movies are a hugh difference, but if they didn't show a percentage, we would never know when the movie is about to start.

With eBooks is almost the same things. Locally, everything always will work fast. Online, it's a whole other thing. Believe me, in some books you will want to show the percentage of loading.

@fchasen @matewilk I tried both codes, none of them work :'(
I'm not using core.js nor epub.js, but epub.min.js and reader.js
So, I add your piece of code after the EPUBJS.Reader call:

EPUBJS.Reader = function(bookPath, _options) {
var reader = this;
var book;
var plugin;
var $viewer = $("#viewer");
var parameters;
var xhr = new XMLHttpRequest();
xhr.addEventListener("progress", updateProgress);
function updateProgress (oEvent) {
if (oEvent.lengthComputable) {
var percentComplete = oEvent.loaded / oEvent.total;
$('div#percentage').html(percentComplete+"%");
} else {
// Unable to compute progress information since the total size is unknown
}
}

I also tried after and before the epubReader() function, and in the epub.min.js, but it throws: xhr is not defined.
Thank you guys and sorry for bothering

@matewilk
Copy link
Contributor

Did you use dev tools to see what the problem is, did it return any errors ?

Are you sure you're not using core ?
Take a look here, it's just one line below the code you are trying to modify.

@mQckingbird
Copy link
Author

This is the line in my reader.js:
this.settings = _.defaults(_options || {}, {

But this is for setting up, that leaves me with the first question.. ¿how can I do it?
Meaning... ¿where it goes that piece of code in the epub.min.js /or reader.js?

    <script> 
      ePubReader("whatever.epub");
    </script> 

@matewilk
Copy link
Contributor

First of all, you shouldn't modify any of the epub library files (what if some day you decide that you need to update the library to the latest version?). The best practice is to - for example - extend the prototype of the object you are planning to modify. (I'd suggest you go through a tutorial about it)

I'm not sure what @fchasen has on his mind when suggesting modifying this function:
https://github.com/futurepress/epub.js/blob/master/src/core.js#L18

but I would completely override EPUBJS.core.request function with additional changes, and move it to your own project files. It requires you to know how prototype in javascript workins.

Again, it is very difficult to give advices, having very limited knowledge what is wrong in your codebase.

@mQckingbird
Copy link
Author

Perhaps @fchasen understood me, it is just a progress bar with percentage while the book is loading.

I'm still trying, but nothing.. :(

@paulocheque
Copy link

paulocheque commented Nov 24, 2016

Any news about this?

My solution is working, but it was a internal hack in the library. I changed the EPUBJS.Unarchiver.prototype.open and the EPUBJS.core.request functions.

EPUBJS.Unarchiver.prototype.open = function(zipUrl, callback, book){
	if (zipUrl instanceof ArrayBuffer) {
		this.zip = new JSZip(zipUrl);
		var deferred = new RSVP.defer();
		deferred.resolve();
		return deferred.promise;
	} else {
    // FIXME - CUSTOM CHANGE
		return EPUBJS.core.request(zipUrl, "binary", null, true, book).then(function(data){
			this.zip = new JSZip(data);
		}.bind(this));
	}
};

EPUBJS.core.request = function(url, type, withCredentials, trackProgress, book) {
	var supportsURL = window.URL;
	var BLOB_RESPONSE = supportsURL ? "blob" : "arraybuffer";
	var deferred = new RSVP.defer();
	var xhr = new XMLHttpRequest();
	var uri;

  if (trackProgress && book) {
    function updateProgress (oEvent) {
      if (oEvent.lengthComputable) {
        var percentComplete = oEvent.loaded / oEvent.total;
        book.trigger("book:downloadProgress", percentComplete);
      } else {
      }
    }
    xhr.addEventListener("progress", updateProgress);

    function transferComplete (oEvent) {
      book.trigger("book:downloadProgress", 100);
    }
    function transferFailed (oEvent) {
      book.trigger("book:downloadProgressError", true);
    }
    function transferCanceled (oEvent) {
      book.trigger("book:downloadProgressError", true);
    }
    xhr.addEventListener("load", transferComplete);
    xhr.addEventListener("error", transferFailed);
    xhr.addEventListener("abort", transferCanceled);
  }

.... Continue the request function

Then in my code:

      this.book.on('book:downloadProgress', (percentage) => {
        this.updateDownloadProgressBar(percentage)
        console.warn(percentage)
      })

@alifrio75
Copy link

Any news about this?

My solution is working, but it was a internal hack in the library. I changed the EPUBJS.Unarchiver.prototype.open and the EPUBJS.core.request functions.

EPUBJS.Unarchiver.prototype.open = function(zipUrl, callback, book){
	if (zipUrl instanceof ArrayBuffer) {
		this.zip = new JSZip(zipUrl);
		var deferred = new RSVP.defer();
		deferred.resolve();
		return deferred.promise;
	} else {
    // FIXME - CUSTOM CHANGE
		return EPUBJS.core.request(zipUrl, "binary", null, true, book).then(function(data){
			this.zip = new JSZip(data);
		}.bind(this));
	}
};

EPUBJS.core.request = function(url, type, withCredentials, trackProgress, book) {
	var supportsURL = window.URL;
	var BLOB_RESPONSE = supportsURL ? "blob" : "arraybuffer";
	var deferred = new RSVP.defer();
	var xhr = new XMLHttpRequest();
	var uri;

  if (trackProgress && book) {
    function updateProgress (oEvent) {
      if (oEvent.lengthComputable) {
        var percentComplete = oEvent.loaded / oEvent.total;
        book.trigger("book:downloadProgress", percentComplete);
      } else {
      }
    }
    xhr.addEventListener("progress", updateProgress);

    function transferComplete (oEvent) {
      book.trigger("book:downloadProgress", 100);
    }
    function transferFailed (oEvent) {
      book.trigger("book:downloadProgressError", true);
    }
    function transferCanceled (oEvent) {
      book.trigger("book:downloadProgressError", true);
    }
    xhr.addEventListener("load", transferComplete);
    xhr.addEventListener("error", transferFailed);
    xhr.addEventListener("abort", transferCanceled);
  }

.... Continue the request function

Then in my code:

      this.book.on('book:downloadProgress', (percentage) => {
        this.updateDownloadProgressBar(percentage)
        console.warn(percentage)
      })

hi.. novice question here.. can you explain more how you trigger 2nd part of your code? where did you place it, and how did you actually manage to get the load progress?

thankyou so much

@stuartmscott
Copy link

+1

It would be great if there was hook to get updates about the download when using var book = ePub("/path/to.epub"); so a percentage can be shown to the reader.

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

No branches or pull requests

6 participants