

My ebook reader app just passed 6000 users. - rdwallis
http://magicscroll.net

======
rdwallis
This is my first post to HN. Since this is a Hacker Community I thought you
all might be interested in some stats and info about the project:

\---

I think MagicScroll's doing pretty well in terms of uptake but I don't have
any kind of tracking implemented yet so I'm a bit blind.

I've got just over 6000 users from the Chrome Web Store.

[https://chrome.google.com/webstore/detail/ghgnmgfdoiplfmhggh...](https://chrome.google.com/webstore/detail/ghgnmgfdoiplfmhgghbmlphanpfmjble)

On my server logs I get between 700 and 900 hits to my cache manifest file
every 24 hours with more over the weekend. As near as I can tell users turn a
books page an average of just less than 400 times an hour. (Each page turn
involves a round trip to the server for syncing purposes). More than 95% of
the hits are coming from Chrome so I think there's a lot of room to expand.

\---

I didn't build MagicScroll as a commercial venture but based on its limited
popularity I do think it has the potential to create revenue, and I now hope
to build a business around it. In the next month or so I plan to create a paid
extension similar to Readability that will allow websites to be read using
MagicScroll. I also intend to build an API for booksellers to allow
MagicScroll to be integrated into their stores. If MagicScroll does gain a
significant number of users I hope to integrate my own ebook store into it but
I think that will be in a year or twos time at the earliest.

\---

For those of you interested in the programming side. It is built in GWT and
runs on the Google App Engine. I'm embarrassed to say that I don't have any
real knowledge of javascript though I'm trying to rectify that. There are
about 30 lines of native javascript in the project most of which facilates
communication between the frame that holds the book and the UI.

The entire project is heavily cached and apart from unzipping the ePUB and
some security logic everything happens clientside. There are obviously a lot
of advantages to this and it was quite easy to do because I was working in
GWT. In fact I found that the same logic on the client often runs
significantly faster than it does on the App Engine server.

To do page rendering I'm using a very simple binary search. I draw a page with
a certain number of characters and if it overflows I draw it half the size and
then half between that and so on. It's quick but I have no idea how Google has
managed to get their pages in Google Books to render so fast, or to change the
font size without redrawing.

One thing I've perhaps overrelyed on is AsyncCallbacks here's part of the code
that draws the book:

    
    
            LoadDialog.get().show("Loading Book. Stage 2 of 3");
            init(eacKey, new DelayedCallback<Void>(new SimpleCallback<Void>(){
    
                @Override
                public void onSuccess(Void result) {
                    resize();
                    LoadDialog.get().show("Loading Book.  Stage 3 of 3");
                    PageRendererFrame.addEPubStyleSheets(new DelayedCallback<Void>(new SimpleCallback<Void>(){
    
                        @Override
                        public void onSuccess(Void result) {
                            SettingsWidget.get(new SimpleCallback<SettingsWidget>() {
    
                                @Override
                                public void onSuccess(final SettingsWidget settingsWidget) {
                                    PageRendererFrame.addStyleSheet(settingsWidget.getCurrentValueStore().getCurrentColors().getLocation(), new DelayedCallback<Void>(new SimpleCallback<Void>() {
    
                                        @Override
                                        public void onSuccess(Void result) {
                                            PageRendererFrame.addStyleSheet(settingsWidget.getCurrentValueStore().getCurrentFont().getLocation(), new DelayedCallback<Void>(new SimpleCallback<Void>() {
    
                                            	@Override
                                                public void onSuccess(Void result) {
                                                    PageRendererFrame.showPage(new DelayedCallback<Void>(new SimpleCallback<Void>() {
    
                                                        @Override
                                                        public void onSuccess(Void result) {
                                                        	hider.removeFromParent();
                                                        	preventDraw = false;
                                                            callback.onSuccess(null);       
                                                        }
    
                                                    }));
    
                                                }
    
                                            }));
    
    
                                        }
    
                                    }));
    
                                }
    
                            });
    
    
                        }
    
                    }));
    
                }
    
            }));
    

The DelayedCallback works like a normal callback but introduces a 1
millisecond delay to avoid the browser from thinking the code has frozen.
SimpleCallback is just like AsyncCallback but without the onFailure method. If
an exception occurs the program halts instead of recovering. I made it so that
whenever an uncaught exception occurs I get emailed about it. This has
massively increased my stress levels but I think its contributed to the
stability of the code so I'll probably do the same in the future. I now get
less than 20 errors a day. Mostly if someone tries to use MagicScroll with IE7
or if they try to read an encrypted book.

Anyway thanks for letting me ramble, I'm interested to know what HN thinks.

~~~
revorad
Congrats! I also get a lot of traffic from the Chrome store. Just one quick
suggestion - Make the example book prominent in your app, so that a new user
can quickly see what your app's all about. I'd say put it on top before the
upload option.

Also, can you preload the example book somehow so that there's no waiting time
at all? Right now, it took about 5 seconds before the book opened. From what
I've seen, Chrome visitors are quite impatient and bounce very easily.

~~~
rdwallis
Thanks for the input.

I think the most significant problem with the example books is not their
position on the page but the couple of second delay before they appear. I'll
definitely fix this in the next few days.

As for caching the example books in the background. It would be nice to do and
I'll think about the problem for the next few days but I think it may be be
extremely difficult based on the current design.

Edit: Thought on it a bit more. It may be possible to cache the contents of
the example book but not the processing of the book. I suspect that the major
part of the load delay comes from processing rather than downloading but it'll
probably be worth it anyway.

