+7

Adding Currently Reading label to comics

lostndessence 7 months ago updated by ListerD 2 months ago 27

Hello, I'm new to Ubooquity and I've taken to using it primarily for comics. With so many to sort through, it can be hard to keep track of where you are in any given series. So I've been trying to figure out how to mark them as Read or Started Reading. I couldn't find any solutions online or here on the forum so I decided to try doing it myself. (However if this info was already out there, please let me know)

This solution is currently only tested in the plex theme for Ubooquity as that's the theme I use, and only works for comics.

This Theme: https://ubooquity.userecho.com/communities/1/topics/666-plex-based-theme

Through tweaking and digging in the code, I discovered that a GET pathway exists where one can request some data if they have the id of a comic. That path looks like this:

host_name:port/user-api/bookmark?docId=****

where host_name is your ip or domain, port is the port, and **** is the id of the comic.

The returned JSON looks like this:

{

"docId" : 3326,

"isBook" : false,

"mark" : "0",

"isFinished" : false,

"lastUpdate" : 1576387903971

}

It's important to note that "mark" in the above JSON is the current page saved in the bookmark of that particular comic. Therefore, using a GET request we can determine if a comic has been started or not based on that value. Also, if a comic has never been opened, the GET request will return null.

The last bit of information we need is where to get that ID for the comic, and this can be found by looking at the source url of the cover image displayed. It will say /comics/****/comic_filename?params (again where **** is the comic id).

The following JS code will loop through all of the comics (exluding folders) on the current page, make a GET request for each, and (so long as the value of mark is not 0 or null) will add a "reading" label.

///////////////////

//MODS

///////////////////

// Anonymous "self-invoking" function

(function() {

var startingTime = new Date().getTime();

// Load the script

var script = document.createElement("SCRIPT");

script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js';

script.type = 'text/javascript';

document.getElementsByTagName("head")[0].appendChild(script);

// Poll for jQuery to come into existance

var checkReady = function(callback) {

if (window.jQuery) {

callback(jQuery);

}

else {

window.setTimeout(function() { checkReady(callback); }, 20);

}

};

// Start polling...

checkReady(function($) {

//////////////////////////////////

//Add currently reading condition to comic

//////////////////////////////////

$('.thumb a img').each(function(){

raw_src = $(this).attr('src')

page_num = '0';

//sort comics from folders

if (raw_src.search("folder") >= 0){

//console.log("raw_src: "+raw_src);

} else {

//extract Comic ID

thing = $(this);

src = $(this).attr('src');

//console.log("source: "+src);

$(this).closest('.thumb').append('');

var comicid = src.split('/');

//console.log("Comic ID: "+comicid[2]);

//get comic meta from server

json_url = window.location.origin+"/user-api/bookmark?docId="+comicid[2];

console.log("url: "+json_url);

$.getJSON( json_url, function() {

console.log( "success" );

}).done(function( data ) {

current_this = thing;

if (data != null){

var items = [];

var c_id = '';

$.each( data, function( key, val ) {

if (key == 'docId'){c_id = val;}

if (key == 'mark'){

page_num = val;

if (page_num != '0'){

$("img[src*='"+c_id+"']").closest('.thumb').find('.number').html("reading");

$("img[src*='"+c_id+"']").closest('.thumb').find('.numberblock').addClass("reading");

}

//console.log("page_num "+page_num);

}

});

}

}).fail(function(){});

}

//console.log("triggered");

});

});

})();

// end Anonymous "self-invoking" function

Add this script at the bottom of themeScript.js in the plextheme files. Note: This script can only determine if the comic has been started, not when it is completed. So to clear the "reading" label, simply return the comic to page 1 and exit it. I also added some styles to make the label itself look ok. This can be added to comics.css

.reading{ bottom: 0; background-color: #009218 !important; top: initial !important;}

Anyone with knowledge of js and css should be able to modify this for their own favorite theme, or hopefully this can help someone more clever than me develop a universal script that can do the same thing for everyone.

thanks, this is a feature i really miss. Can you share your modified files because I tried but I didn't get it to work.

Another question, if the returned JSON looks like this:

{

"docId" : 3326,

"isBook" : false,

"mark" : "0",

"isFinished" : false,

"lastUpdate" : 1576387903971

}

Cannot be used "isFinished" to flag the comic as finished or whatever instead still showing the "reading" tag?

+1

The isFinished value always seems to be false for comics. I've tried getting all the way to the last page of the comic, closing, refreshing, clearing cache. It remains false. Not sure what it's purpose is, but maybe it's an eBook only variable.
If any Ubooquity devs are reading this, having that work for comics as well would be a blessing. Thanks in advance.
Actually going back into the code, I've learned that the structure of this bookmark object is meant to be used as a cookie. If you have the cookie version of the bookmark enabled in the server settings, the isFinished value tells it if the cookie is expired, or something along those lines, but has nothing to do with your place in the book, unfortunately. 

As for the modified files, I went ahead and added them to git here:
https://github.com/nullredirect/modifiedPlexTheme-Ubooquity.git

Hey thanks for your quick reply. I have it working now with your repo :)

is there any way to get the total pages of a comic? because i'm thinking if we could get that it can be used to match it with the mark value and if the mark is equal to total pages tag it as Completed or something like that.

+2

I think I found a way to get that value. I'll try to get this setup on my system and if it works I'll update the git and then come back here and leave an explanation. 

Also someone was asking for a progress bar a while ago in the forum. With both those values, it's possible. 

This is such a good starting point. Thank you so much.

I cannot get my head around how JS works. I've only taught myself enough Python to accomplish what little projects I come up with and have time for.

How would importing this to another theme work? I don't understand where themescript.js is called.

The existence of the "page_num = val;" pointer also opens up changing the default "total number" when browsing comics and being able to do an unread value, if that pointer is exposed when the server cycles through the series view.  I'm about to spent 4 sleepless days in the hospital, maybe I'll take my laptop and give it a go.

I don't know anything about Python so I totally understand that feeling of disconnect between one language and another. 

So the Ubooquity server seems to be built in JAVA as an applet, but really it's just an html server, meaning it's job is to give out some html when a user goes to a specific url on the server.

Quick note JAVA and Javascript are two completely different things.  

Now to understand JS, you have to think in terms of things that happen on the serverside of an html request (what we sometimes call a site visit or page visit), and what happens on the browser side. On the server side, html is compiled from separate files and consolidated into a response that your browser then interprets and displays. Once the browser gets hold of the code, then we're talking about the browser side of things. Here, the original server no longer has control of the content it sent over, leaving us room to make all sorts of modifications. One of the ways we can do that is using Javascript, a browser-side scripting language. So I think the best way to view JS is as an after the fact patch tool. 

Take photography for instance. You start by taking a photo with the camera, then you might tidy it up in photoshop. Well the act of taking the picture with the camera is the serverside part, and the tidying it up in photoshop is the browserside part. In this analogy, JS would be a sick suite of tools in photoshop that lets you go beyond the normal limitations of photoshop. 

Of course JS can also be used in a host of other projects that aren't web based. I'm not familiar with these applications so I wont talk about them here, but at least now I think you'll have the most basic idea of how you would use JS. 
-----

Now lets talk about the themescript.js file. Ubooquity is designed with a theme system in place, giving us the ability to change the appearance of the server. The way these theme customizations work: within the theme files are files with names identical to the default theme files, and the system lets us use our version of that file instead of the originals. 
This is still pretty limited in some respects since we have a limited pool of files to override, but the file themescript.js is one of those files, and as long as it is in our theme, Ubooquity will automatically load up that code. So if you're looking through the theme code hoping to see where that file is being called, you wont. That part is somewhere in the server code. 

Using another theme, it may have it's own themescript.js file setup, in which case you would NOT want to just delete all the content in there and replace it with the code in my themescript.js file. You would lose some of the code uniquely added to let your own theme function. That's why I was saying to paste the above code at the bottom of said file, as this should allow the original code to still work, and ALSO add on this functionality. 
-----

Also yes, the script can be modified to say unread instead by changing some of the code. 
Currently the code is ignoring comics with null bookmarks, but you would want to target those first. 
Then after that check through the comics with bookmarks and target the unread ones like this:
if (page_num < 1)

and lastly change this:
$("img[src*='"+c_id+"']").closest('.thumb').find('.number').html("reading");

to this:
$("img[src*='"+c_id+"']").closest('.thumb').find('.number').html("unread");

Hi !

Splendid idea !

I'm quite new to Ubooquity(a week ?) and I love it.

Beeing able to know what your are reading is so great ! When the comics are hidden deeply in subfolders on the other hand,  it is still difficult to remember what you are reading.

Do you think of a way to list first all the comics you are reading atthe moment first (like in Plex where you see first all the movies you are watching) ? I know that it is not so easy on the client side... I could be helpfull because I know js/html/css. 

Thanks !

Hi lostndessence !

I made another mod on yours (I forked your Gitub repo) to avoid comic duplicates : The deduplicator.

I'm planning to try to make a special page with all the currently reading comics to put on your great mod too. It would be like Plex for movies. I miss too much this on Ubooquity.

We can talk about that when you want if you like.

C U soon !

Love the reading tag, nice work!  Any updates on whether completed or a progress bar will be possible?

Thx!  

I was looking a bit into this.  It seems that isFinished in /user-api/bookmark? is set by some things.  Kuboo sets it to true, but the web viewer doesn't.

As for getting the total pages, OP had mentioned thinking they had somewhere to do that.  Were you just going to try to scrape it out of the /comicdetails/%id% html?

So, I modified this.  I don't use that theme, but it should be similar enough to work anywhere, I think.  

The only known 'issue' is that if you open a comic, read some, and close, this tag isn't updated.  This is because the reading window is an overlay, so when you close it, the comic list isn't refreshed.  I'm not going to bother with that. 

Anyway, I just put the following JS in my themeScript.js file.

// Anonymous "self-invoking" function
(function() {
    var startingTime = new Date().getTime();
    // Load the script
    var script = document.createElement("SCRIPT");
    script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js';
    script.type = 'text/javascript';
    document.getElementsByTagName("head")[0].appendChild(script);

    // Poll for jQuery to come into existance
    var checkReady = function(callback) {
        if (window.jQuery) {
            callback(jQuery);
        } else {
            window.setTimeout(function() { checkReady(callback); }, 20);
        }
    };

    // Start polling...
    checkReady(function($) {
        //////////////////////////////////
        //Add currently reading condition to comic
        //////////////////////////////////
        $('.thumb a img').each(function(){
            raw_src = $(this).attr('src')
            page_num = '0';
            //sort comics from folders
            if (raw_src.search("folder") >= 0){
                //console.log("raw_src: "+raw_src);
            } else {
                //extract Comic ID
                thing = $(this);
                src = $(this).attr('src');                //console.log("source: "+src);
                $(this).closest('.thumb').append('');
                var comicid = src.split('/');            //console.log("Comic ID: "+comicid[2]);
                //get comic meta from server
                json_url = window.location.origin+"/user-api/bookmark?docId="+comicid[2];        //console.log("url: "+json_url);
                $.getJSON( json_url, function() {
                    //console.log( "json_url success" );
                }).done(function( data ) {
                    current_this = thing;
                    if (data != null){
                        var items = [];
                        var c_id = '';
                        var c_pages = '';
                        var page_num = '';
                        $.each( data, function( key, val ) {
                            if (key == 'docId'){ c_id = val;}
                            if (key == 'mark'){    page_num = val;}
                        });
                        if (page_num != '0'){
                            // get total pages from server
                            content_url = window.location.origin+"/comicdetails/"+c_id;    //console.log("url: "+content_url);
                            $.get( content_url, function() {
                                //console.log( "content_url success" );
                            }).done(function( data ) {
                                details = $('<details>').append($.parseHTML(data));
                                size_div = $('#details_size', details).html();
                                c_pages = size_div.match(/\d+/)[0];

                                thumb = $("img[src*='"+c_id+"']").closest('.thumb');
                                thumb.css({ 'display' : 'flex',
                                            'justify-content' : 'flex-end',
                                            'flex-direction' : 'column'});
                                base_thumb_content = thumb.html();
                                // set reading if page_num < total_pages
                                if (page_num >= (c_pages - 1)) {
                                    progress_percent = 100;
                                    progress_string = "Completed";
                                } else {
                                    progress_percent = ((page_num/c_pages) * 100);
                                    page_int = Number(page_num);
                                    progress_string = (page_int++) + " of " + c_pages;
                                }
                                modified_thumb_content = "<div class="progress-container" style="position: absolute; width: -webkit-fill-available; background: rgba(00, 00, 00, 0.6)">" +
                                                            "<div class="progress_percent" style="bottom: 0px; left: 0px; background: rgba(50, 200, 50, 0.7); width: " + progress_percent + "%;"> </div>" +
                                                            "<div class="progress_string" style="bottom: 0px; left: 0px; position: absolute; color: #FFF; width: 100%; height: 100%;">" + progress_string + "</div>" +
                                                         "</div>" + base_thumb_content;
                                thumb.html(modified_thumb_content);
                            });
                        }
                        //console.log("page_num "+page_num);
                    }
                }).fail(function(){});
            }
        //console.log("triggered");
        });
    });
})();
// end Anonymous "self-invoking" function

Hey Jace,

Nice work on the count feature.  I couldn't get the info to render properly though based on the above code snippet.  Kept getting parsing errors around the modified_thumb_content code, and my javascript skills aren't very good (ok, my javascript is crap, I'm a data warehouse developer).  I wasn't able to get it to work properly on my system.  

However, I was able to hack together your counting code with the original to provide a less fancy version that gives a little more info than lostndessence's original.  No progress bar, but a page x of y and completed status text.  

Here's the hacked together code if anyone's interested:


// Anonymous "self-invoking" function
(function() {
    var startingTime = new Date().getTime();
    // Load the script
    var script = document.createElement("SCRIPT");
    script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js';
    script.type = 'text/javascript';
    document.getElementsByTagName("head")[0].appendChild(script);

    // Poll for jQuery to come into existance
    var checkReady = function(callback) {
        if (window.jQuery) {
            callback(jQuery);
        } else {
            window.setTimeout(function() { checkReady(callback); }, 20);
        }
    };

    // Start polling...
    checkReady(function($) {
        //////////////////////////////////
        //Add currently reading condition to comic
        //////////////////////////////////
        $('.thumb a img').each(function(){
            raw_src = $(this).attr('src')
            page_num = '0';
            //sort comics from folders
            if (raw_src.search("folder") >= 0){
                //console.log("raw_src: "+raw_src);
            } else {
                //extract Comic ID
                thing = $(this);
                src = $(this).attr('src');                //console.log("source: "+src);
                $(this).closest('.thumb').append('<div class="numberblock"><div class="number"><span></span></div></div>');
                var comicid = src.split('/');            //console.log("Comic ID: "+comicid[2]);
                //get comic meta from server
                json_url = window.location.origin+"/user-api/bookmark?docId="+comicid[2];        //console.log("url: "+json_url);
                $.getJSON( json_url, function() {
                    console.log( "json_url success" );
                }).done(function( data ) {
                    current_this = thing;
                    if (data != null){
                        var items = [];
                        var c_id = '';
                        var c_pages = '';
                        var page_num = '';
                        $.each( data, function( key, val ) {
                            if (key == 'docId'){c_id = val;}
                            if (key == 'mark'){page_num = val;}
                        });
                        if (page_num != '0'){
                            // get total pages from server
                            content_url = window.location.origin+"/comicdetails/"+c_id;    //console.log("url: "+content_url);
                            $.get( content_url, function() {
                                //console.log( "content_url success" );
                            }).done(function( data ) {
                                details = $('<details>').append($.parseHTML(data));
                                size_div = $('#details_size', details).html();
                                c_pages = size_div.match(/\d+/)[0];

                                if (page_num >= (c_pages-1)) {
                                    progress_percent = 100;
                                    progress_string = "Completed";
                                } else {
                                    progress_percent = ((page_num/c_pages) * 100);
                                    page_int = Number(page_num)+1;
                                    progress_string = (page_int++) + " of " + c_pages;
                                }

                                    $("img[src*='"+c_id+"']").closest('.thumb').find('.number').html(progress_string);
                                    $("img[src*='"+c_id+"']").closest('.thumb').find('.numberblock').addClass("reading");

                            });
                        }
                        console.log("page_num "+page_num);
                    }
                }).fail(function(){});
            }
        console.log("triggered");
        });
    });
})();
// end Anonymous "self-invoking" function</details>

It looks like the forum took single quotes and turned them double. 

I also had to change the z-index to force it on top of the image.  I'd edit my post, but apparently we can't! 

https://gist.github.com/j4c3/fa5b983cd36afce56e35c1dd52059334

Cool, thanks for info.  I'll give it a shot based on the github code.  

Sweet Mod.  I hope you don't mind, but I adjusted it slightly and added colors (red, green, blue) for Completed, In Progress and Unread.  I also added total pages for New books as sometimes I want an idea of what I'm getting into before starting a book.

Screenshot:

Adjusted Code:  

// Anonymous "self-invoking" function
(function() {
    var startingTime = new Date().getTime();
    // Load the script
    var script = document.createElement("SCRIPT");
    script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js';
    script.type = 'text/javascript';
    document.getElementsByTagName("head")[0].appendChild(script);

    // Poll for jQuery to come into existance
    var checkReady = function(callback) {
        if (window.jQuery) {
            callback(jQuery);
        } else {
            window.setTimeout(function() { checkReady(callback); }, 20);
        }
    };

    // Start polling...
    checkReady(function($) {
        //////////////////////////////////
        //Add currently reading condition to comic
        //////////////////////////////////
        $('.thumb a img').each(function(){
            raw_src = $(this).attr('src')
            page_num = '0';
            //sort comics from folders
            if (raw_src.search("folder") >= 0){
                //console.log("raw_src: "+raw_src);
            } else {
                //extract Comic ID
                thing = $(this);
                src = $(this).attr('src');                //console.log("source: "+src);
                $(this).closest('.thumb').append('');
                var comicid = src.split('/');            //console.log("Comic ID: "+comicid[2]);
                //get comic meta from server
                json_url = window.location.origin+"/user-api/bookmark?docId="+comicid[2];        //console.log("url: "+json_url);
                $.getJSON( json_url, function() {
                    //console.log( "json_url success" );
                }).done(function( data ) {
                    current_this = thing;
                    if (data != null){
                        var items = [];
                        var c_id = '';
                        var c_pages = '';
                        var page_num = '';
                        $.each( data, function( key, val ) {
                            if (key == 'docId'){ c_id = val;}
                            if (key == 'mark'){    page_num = val;}
                        });
                        if (page_num != '0'){
                            // get total pages from server
                            content_url = window.location.origin+"/comicdetails/"+c_id;    //console.log("url: "+content_url);
                            $.get( content_url, function() {
                                //console.log( "content_url success" );
                            }).done(function( data ) {
                                details = $('<details>').append($.parseHTML(data));
                                size_div = $('#details_size', details).html();
                                c_pages = size_div.match(/\d+/)[0];

                                thumb = $("img[src*='"+c_id+"']").closest('.thumb');
                                thumb.css({ 'display' : 'flex',
                                            'justify-content' : 'flex-end',
                                            'flex-direction' : 'column'});
                                base_thumb_content = thumb.html();
                                // set reading if page_num < total_pages
                                if (page_num >= (c_pages - 1)) {
                                    progress_percent = 100;
                                    progress_string = "Completed";
                                    progress_color = "rgba(213, 92, 92,0.7)";
                                } else {
                                    progress_percent = ((page_num/c_pages) * 100);
                                    page_int = Number(page_num);
                                    progress_string = (page_int++) + " of " + c_pages;
                                    progress_color = "rgba(50, 200, 50, 0.7)"
                                }
                                modified_thumb_content = "<div class='progress-container' style='position: absolute; z-index: 9; width: -webkit-fill-available; background: rgba(00, 00, 00, 0.6)'>" +
                                                            "<div class='progress_percent' style='bottom: 0px; left: 0px; background: "+ progress_color +"; width: " + progress_percent + "%;'> </div>" +
                                                            "<div class='progress_string' style='bottom: 0px; left: 0px; position: absolute; color: #FFF; width: 100%; height: 100%;'>" + progress_string + "</div>" +
                                                         "</div>" + base_thumb_content;
                                console.log(modified_thumb_content);
                                thumb.html(modified_thumb_content);
                            });
                        }
                        //console.log("page_num "+page_num);
                    } else {
                        content_url = window.location.origin+"/comicdetails/"+comicid[2];    //console.log("url: "+content_url);
                        $.get( content_url, function() {
                            //console.log( "content_url success" );
                        }).done(function( data ) {
                        
                            details = $('<details>').append($.parseHTML(data));
                            size_div = $('#details_size', details).html();
                            c_pages = size_div.match(/\d+/)[0];

                            thumb = $("img[src*='"+comicid[2]+"']").closest('.thumb');
                            thumb.css({ 'display' : 'flex',
                                        'justify-content' : 'flex-end',
                                        'flex-direction' : 'column'});
                            base_thumb_content = thumb.html();
                            // set reading if page_num < total_pages

                            progress_percent = 100;
                            progress_string = "Unread 0 of " + c_pages;
                            progress_color = "rgba(92, 92, 213, 0.7)"

                            modified_thumb_content = "<div class='progress-container' style="position: absolute; z-index: 9; width: -webkit-fill-available; background: rgba(00, 00, 00, 0.6)'>" +
                                                        "<div class='progress_percent' style="bottom: 0px; left: 0px; background: "+ progress_color +"; width: " + progress_percent + "%;'> </div>" +
                                                        "<div class='progress_string' style="bottom: 0px; left: 0px; position: absolute; color: #FFF; width: 100%; height: 100%;'>" + progress_string + "</div>" +
                                                     "</div>" + base_thumb_content;
                            console.log(modified_thumb_content);
                            thumb.html(modified_thumb_content);
                        });
                    }
                }).fail(function(){});
            }
        //console.log("triggered");
        });
    });
})();
// end Anonymous "self-invoking" function

+1

So I got bored and couldn't leave it alone.  I've also added  filter buttons at the top to filter the current page to All, In Progress, Completed and New as well as a counter indicating how many books are visible.  I started with the concept by Starcrouz, but switched over to using basic jQuery hide and show functions so that the buttons work without reloads.  The page does not refresh after closing the reader overlay, I might look at that later.  I've also integrated the DeDup added by Starcrouz, and the progress bars by Jace.  You will need to update two files for this to work themeScript.js and comic.css.

Screenshots:

Showing All:

Showing Completed:

Showing In Progress books:

Code for themeScript.js

// Anonymous "self-invoking" function
(function() {
    var startingTime = new Date().getTime();
    // Load the script
    var script = document.createElement("SCRIPT");
    script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js';
    script.type = 'text/javascript';
    document.getElementsByTagName("head")[0].appendChild(script);

    // Poll for jQuery to come into existance
    var checkReady = function(callback) {
        if (window.jQuery) {
            callback(jQuery);
        } else {
            window.setTimeout(function() { checkReady(callback); }, 20);
        }
    };

    // Start polling...
    checkReady(function($) {
        //////////////////////////////////
        //Add currently reading condition to comic
        //////////////////////////////////
        
        var last_book_name = ""; // Used by the de-duplicator
        var last_book_file_format = "";
        
        $('.thumb a img').each(function(){
            raw_src = $(this).attr('src')
            page_num = '0';
            //sort comics from folders
            if (raw_src.search("folder") >= 0){
                //console.log("raw_src: "+raw_src);
            } else {
                //extract Comic ID
                thing = $(this);
                src = $(this).attr('src');                //console.log("source: "+src);
                $(this).closest('.thumb').append('');
                var comicid = src.split('/');            //console.log("Comic ID: "+comicid[2]);
                // START of the de-duplicator (excepted line "last_book_name..." above)
                var book_file_format = src.slice(src.lastIndexOf(".")+1, src.lastIndexOf("?")); // CBZ, CBR and PDF or of the book : EPUB, MOBI, AZW, PDF and DJVU
                var book_name = src.slice(src.lastIndexOf("/")+1,src.lastIndexOf("."));
                // console.log(book_file_format + " / " + book_name)
                if(book_name == last_book_name) { // 2 books have the same name (but not the same format...)
                    if(book_file_format == "pdf") { // PDF format is not welcome if a CBR or CBZ file exists for the same comic
                        thing.parents('.cellcontainer').hide(); // hide the duplicate book if it is in pdf
                        console.log('duplicate book file hidden : ' + decodeURI(book_name) + '.pdf');
                    }
                    if(last_book_file_format == "pdf") { // usefull when user watch the "latest comics" page
                        thing.parents('.cellcontainer').prev().hide(); // hide the duplicate book if it is in pdf
                        console.log('duplicate book file hidden : ' + decodeURI(book_name) + '.pdf');
                    }
                }
                last_book_name = book_name // memorize the book name
                last_book_file_format = book_file_format // memorize the book format
                // END of the de-duplicator
                            
                //get comic meta from server
                json_url = window.location.origin+"/user-api/bookmark?docId="+comicid[2];        //console.log("url: "+json_url);
                $.getJSON( json_url, function() {
                    //console.log( "json_url success" );
                }).done(function( data ) {
                    current_this = thing;
                    if (data != null){
                        var items = [];
                        var c_id = '';
                        var c_pages = '';
                        var page_num = '';
                        $.each( data, function( key, val ) {
                            if (key == 'docId'){ c_id = val;}
                            if (key == 'mark'){    page_num = val;}
                        });
                        if (page_num != '0'){
                            // get total pages from server
                            content_url = window.location.origin+"/comicdetails/"+c_id;    //console.log("url: "+content_url);
                            $.get( content_url, function() {
                                //console.log( "content_url success" );
                            }).done(function( data ) {
                                details = $('<details>').append($.parseHTML(data));
                                size_div = $('#details_size', details).html();
                                c_pages = size_div.match(/\d+/)[0];

                                thumb = $("img[src*='"+c_id+"']").closest('.thumb');
                                thumb.css({ 'display' : 'flex',
                                            'justify-content' : 'flex-end',
                                            'flex-direction' : 'column'});
                                base_thumb_content = thumb.html();
                                // set reading if page_num < total_pages
                                if (page_num >= (c_pages - 1)) {
                                    progress_percent = 100;
                                    progress_string = "Completed";
                                    progress_color = "rgba(213, 92, 92,0.7)";
                                    thumb.parent().parent().addClass("Completed") // Add Completed Class To cellcontainer for Book
                                } else {
                                    progress_percent = ((page_num/c_pages) * 100);
                                    page_int = Number(page_num);
                                    progress_string = (page_int++) + " of " + c_pages;
                                    progress_color = "rgba(50, 200, 50, 0.7)"
                                    thumb.parent().parent().addClass("InProgress") // Add InProgress Class To cellcontainer for Book
                                }
                                //Add Progressbar / page count to book Thumb
                                modified_thumb_content = "<div class="progress-container" style="position: absolute; z-index: 9; width: -webkit-fill-available; background: rgba(00, 00, 00, 0.6)">" +
                                                            "<div class="progress_percent" style="bottom: 0px; left: 0px; background: "+ progress_color +"; width: " + progress_percent + "%;"> </div>" +
                                                            "<div class="progress_string" style="bottom: 0px; left: 0px; position: absolute; color: #FFF; width: 100%; height: 100%;">" + progress_string + "</div>" +
                                                         "</div>" + base_thumb_content;
                            //    console.log(modified_thumb_content);
                                thumb.html(modified_thumb_content);
                            });
                        }
                        //console.log("page_num "+page_num);
                    } else {  //If we don't have bookmark data it is an unread book, lets mark those too!
                        content_url = window.location.origin+"/comicdetails/"+comicid[2];    //console.log("url: "+content_url);
                        $.get( content_url, function() {
                            //console.log( "content_url success" );
                        }).done(function( data ) {
                        
                            details = $('<details>').append($.parseHTML(data));
                            size_div = $('#details_size', details).html();
                            c_pages = size_div.match(/\d+/)[0];

                            thumb = $("img[src*='"+comicid[2]+"']").closest('.thumb');
                            thumb.css({ 'display' : 'flex',
                                        'justify-content' : 'flex-end',
                                        'flex-direction' : 'column'});
                            base_thumb_content = thumb.html();
                            // set reading if page_num < total_pages

                            progress_percent = 100;
                            progress_string = "Unread 0 of " + c_pages;
                            progress_color = "rgba(92, 92, 213, 0.7)"
                            thumb.parent().parent().addClass("New") // Add New Class To cellcontainer for Book
                            
                            //Add Progressbar to book Thumbnail
                            modified_thumb_content = "<div class="progress-container" style="position: absolute; z-index: 9; width: -webkit-fill-available; background: rgba(00, 00, 00, 0.6)">" +
                                                        "<div class="progress_percent" style="bottom: 0px; left: 0px; background: "+ progress_color +"; width: " + progress_percent + "%;"> </div>" +
                                                        "<div class="progress_string" style="bottom: 0px; left: 0px; position: absolute; color: #FFF; width: 100%; height: 100%;">" + progress_string + "</div>" +
                                                     "</div>" + base_thumb_content;
                        //    console.log(modified_thumb_content);
                            thumb.html(modified_thumb_content);
                        });
                    }
                }).fail(function(){});
            }
        //console.log("triggered");
        });
        //Add View Filter Buttons
        $('<li><a title="All" href="#" onclick="$(\'.InProgress\').show();$(\'.New\').show();$(\'.Completed\').show();$(\'#VisCount\').text($(\'.cellcontainer:visible\').length);return false;"><i class="glyphicon all"></i></a></li><li><a title="In Progress" href="#" onclick="$(\'.InProgress\').show();$(\'.New\').hide();$(\'.Completed\').hide();$(\'#VisCount\').text($(\'.cellcontainer:visible\').length);return false;"><i class="glyphicon eye"></i></a></li><li><a title="Unread" href="#" onclick="$(\'.InProgress\').hide();$(\'.New\').show();$(\'.Completed\').hide();$(\'#VisCount\').text($(\'.cellcontainer:visible\').length);return false;"><i class="glyphicon unread"></i></a></li><li><a title="Completed" href="#" onclick="$(\'.InProgress\').hide();$(\'.New\').hide();$(\'.Completed\').show();$(\'#VisCount\').text($(\'.cellcontainer:visible\').length);return false;"><i class="glyphicon book-read"></i></a></li>').insertAfter('.navigation li:eq(2)');
        
        $('<li style="padding-top: 5%;"><span><div style="float:left">  Showing  </div><div id="VisCount" style="float:left"></div><div style="float:left">  of  </div><div id="TotalCount" style="float:left"></div></span></li>').insertBefore('.navigation li:eq(2)');
        
        $("#VisCount").text($(".cellcontainer:visible").length); //Set Visible books on page.
        $("#TotalCount").text($(".cellcontainer:visible").length); //Set total books on page.
    
        
    });
})();
// end Anonymous "self-invoking" function</details></details>

Code for comic.css (styles for Glyphicons font)

@font-face {
    font-family: "Glyphicons Regular";
    src: url(./static/glyphicons.woff) format("woff");
    font-weight: 400;
    font-style: normal
}

.glyphicon {
    position: relative;
    top: 1px;
    display: inline-block;
    font-family: Glyphicons Regular;
    font-style: normal;
    font-weight: 400;
    line-height: 1;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale
}

.glyphicon.home:before {
    content: "\E021"
}
.glyphicon.heart:before {
    content: "\E020"
}
.glyphicon.unread:before {
    content: "\E072"
}
.glyphicon.eye:before {
    content: "\E052"
}
.glyphicon.book-read:before {
    content: "\E088"
}
.glyphicon.all:before {
    content: "\E464"
}
.glyphicon.chevron-left:before {
    content: "\E225"
}

.glyphicon.settings:before {
    content: "\E281"
}

.glyphicon.random:before {
    content: "\E084"
}

.glyphicon.log-out:before {
    content: "\E388"
}

Hopefully this helps someone, if this doesn't work it is probably due to the cut and paste into the forum.  I'll look into uploading to GitHub if need be.

Hi Justin,

I just saw you got my code and modifyed it deeply. Why not. But you removed the best part :-) which is the possibility to display all the comics you are reading from your whole collection. Instead, you put a filter on the page you display to show only the comics you are reading in that particular page. It is a completly other concept. No problem with that. But because you use the same icons as me, in my point of view, it adds confusion between your theme "plextheme-progress" and mine "plextheme-reading". I mean : they both look the same but are not behaving the same way at all. What do you think about trying to explain that more clearly on both sides ? And trying to change icons and/or something on the user interface to avoid confusion ? Thx !

Looks great Justin! i hope you can put the full theme in github. I couldn't get it to work. the bar never shown to me. Also tried to refresh page to clean cache but changes in the themeScript.js weren't reflected when browsing and couldn't fix the "SyntaxError: unexpected token: identifier" in this variable "modified_thumb_content". Probably caused by single quote turn to double when posting here, but when tried to change them, the file loaded was the original, never with the changes.

Here you go, let me know if this works for you:

https://github.com/Justin27482/plextheme-progress

I'm also thinking about trying to add similar to Comixology V2 Theme as well.  Thoughts?

thanks Justin, now it is working in Chromium but in Firefox im getting some issue. Tried to disable all addons but still it is not load properly. But as it is working in Chromium, i guess is something with my Firefox.

Firefox:

Chromium:

Regarding Comixology theme, sure people will appreciate it. It is a the most popular theme i think.

I've updated the code to fix the width issue for Firefox.

Thanks!

I'd love to see this in Comixology V2 as well!  Not having a working page count is the main reason I haven't switched over, and it seems like most of the enhancement work is going into that theme.  


Working great for me in Chrome and on a kiosk browser app I use for Android (works well as a full-screen web based reader).  Can confirm the issue with Firefox.  

At first glance I wasn't too sure about the unread on each book as it made it a bit busy.  But having the page count for trades and collections is really helpful.  Appreciate the work!

I'll take a look and see where the Firefox incompatibility is.  Thanks for pointing that out!

Hi Justing, yes it is fixed now the issue in Firefox.


Not sure if this is related with the theme or it is from Ubooquity, but previous completed comics are not marked in any way.

I did something between the read of 22 and 23. I changed the Spawn folder to another directory. I know that for Ubooquty that means new comics, and you will loose the status from previously read (i had marked until 22 as completed).

So after the change the Spawn folder, comics 1-22 have no mark, 23 completed, 24 in reading status and from 25 to the last as unread.


btw, since you said you might work on Comixology V2, i tried it again that theme and now you have my +1 to mod that theme too :)

Sorry I haven't been back on here in a while. 

It's absolutely amazing to see what you guys have done with this. 
Thanks to everyone that's contributed so far. I'll definitely be using your modifications in my own personal theme. 

lostndessence, Thanks for kickstarting this whole process!  Your initial reading enhancement is what, for me, took Ubooquity from a cataloging app to my go-to reader.  Really appreciate your work on this.