![]() |
#1 |
frumious Bandersnatch
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 7,542
Karma: 19001583
Join Date: Jan 2008
Location: Spaniard in Sweden
Device: Cybook Orizon, Kobo Aura
|
Reading ePUBs in a browser
Those who have seen my ePUB uploads probably know that I like to supply a set of files (index.html, index.xhtml, index.css) that allow to view the uncompressed ePUB in a web browser, with a frames layout. I create these files by hand (with extensive copy&paste) for every project, but I thought that I could also try to write a script or something that would create them automatically, and be useful for reading any ePUB.
There already exist something similar (epubjs), but I wanted it simpler. So, this is my try. It is a bash script (so it works on Linux, maybe on OS X, and you'd need a Cygwin environment for Windows, I guess) that uncompresses an ePUB file to a temporary directory, creates the index.* files, outputs the path of the index.html (so you can paste it in your browser) and waits; when you press <Enter>, it deletes the temporary directory, and everything is as it was before. Some features: The left frame has a list of all files in the <spine> in order (with their "id" as names), files with "linear=no" are marked with an asterisk. At the top there are four arrow links, clicking on "<" or ">" moves to the previous or next file in the book (skipping entries with asterisks), "<<<" and ">>>" are the first and last files. You can click on any file in the list, and the "<" and ">" links work as expected (but they don't if you follow links in the main book frame). If you click on the red "TOC", the left frame view should change to the TOC instead of the <spine>, but it's not implemented yet ![]() After any change in the main book frame, the index.css file (which is defined inside the script) is applied on top of the normal CSS files of the ePUB, that means text size and layout can change, and anchors may not be as expected (this probably depends on the browser). For the future I'd like to implement the TOC properly, and I'd also like to make it work directly from the browser, as a sort of CGI script, but I'm afraid it's not possible without installing a local web server, and that's not what I want. Disclaimer: I tried to make the script safe and clean, but I'm no expert programmer, I basically learn along as I try new things. The script was only tried in Linux, with the Opera browser, and with the ePUB files I have created... I hope it will work in other cases, but there's no guarantee. By the way, just run the script as: Code:
./epub-read.sh Some_book.epub For the latest version, see post #12 Last edited by Jellby; 11-29-2014 at 04:22 AM. |
![]() |
![]() |
![]() |
#2 |
frumious Bandersnatch
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 7,542
Karma: 19001583
Join Date: Jan 2008
Location: Spaniard in Sweden
Device: Cybook Orizon, Kobo Aura
|
I think the TOC is working now
![]() It also worked fine with a couple arbitrary Calibre-generated ePUBs I downloaded from MR, I'm happy ![]() |
![]() |
![]() |
Advert | |
|
![]() |
#3 |
frumious Bandersnatch
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 7,542
Karma: 19001583
Join Date: Jan 2008
Location: Spaniard in Sweden
Device: Cybook Orizon, Kobo Aura
|
Some additional fixes.
|
![]() |
![]() |
![]() |
#4 |
frumious Bandersnatch
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 7,542
Karma: 19001583
Join Date: Jan 2008
Location: Spaniard in Sweden
Device: Cybook Orizon, Kobo Aura
|
Another version. Now it accepts an optional flag -o, that will call kfmclient to open the HTML with the default KDE application (sorry, no Gnome alternative yet, but I'm open to suggestions).
I'll call this version 1.0 ![]() |
![]() |
![]() |
![]() |
#5 |
Fanatic
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 580
Karma: 810184
Join Date: Sep 2010
Location: Norway
Device: prs-t1, tablet, Nook Simple, assorted kindles, iPad
|
Here's a rather quick&dirty patch which includes a -v option, which lets you view the epub-file in lynx. Haven't had a chance to test many epub-files on it, but it seems to work with xhtml UTF-8 files.
I rip out any lines in xhtml files than contain meta.. charset= info, as otherwise lynx just displays blobs instead of any character that's not strictly ascii. A more robust method would be to use html tidy, I suppose, and convert from xhtml to html. |
![]() |
![]() |
Advert | |
|
![]() |
#6 |
Enthusiast
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 25
Karma: 1028
Join Date: Mar 2010
Location: Chandler, AZ
Device: Samsung Stratosphere (coolreader), BeBook Neo,EBookman
|
SBT:
Thanks. Just to be clear for others. I had to Code:
patch epub-read.sh epub-read_lynxviewer.patch epub-read.sh -v Oz_Omnibus.epub Code:
XLOADIMAGE_COMMAND:xv %s & MAKE_LINKS_FOR_ALL_IMAGES:TRUE |
![]() |
![]() |
![]() |
#7 |
Member
![]() Posts: 13
Karma: 10
Join Date: Dec 2010
Device: htc dream, htc desire, cybook odyssey
|
Thank you for this useful script (and the patch). I've uploaded the patched version on my repository:
https://code.google.com/p/textallion...s/epub-read.sh |
![]() |
![]() |
![]() |
#8 |
Fanatic
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 580
Karma: 810184
Join Date: Sep 2010
Location: Norway
Device: prs-t1, tablet, Nook Simple, assorted kindles, iPad
|
Thought I'd have a stab at making a dynamic web page capable of reading the content.xml/.opf/.ncx files, and then creating a toc and displaying the chapters. I've sort of succeeded; this page works in firefox, just save it at the same level as META-INF in a blown-up epub.
The akward issue is loading files dynamically into an iframe; security-conscious browsers are typically not fond of doing this for local files. Chrome should be able to do it if you use the --allow-file-access-from-files, but I can't get it to work. Firefox also behaves rather strangely; it reports an error for line 233, because the basis variable is undeclared, but if I declare it, it no longer reads loaded files properly. I ran a bit amuck with css3, I'm afraid. Couldn't resist playing with all the nice new shiny bells and whistles. ![]() Code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF8" /> <style type="text/css"> div#innh p:hover { opacity:1; background:yellow; background: -moz-linear-gradient( left ,#ffff55, #995522); } div#spine { position:relative; left:2px; top:-4px; width:60px; } div#innh { opacity:0.95; border-style:solid double solid none; border-color:#300808; border-width:4px 8px 4px; position:absolute; z-index:1; width:400px; height:823px; background:lightgreen; background: -moz-linear-gradient( left ,#9f6a46, #490d0d); color: -moz-linear-gradient( right ,#11aa55, #dfaa66); -moz-transform: scaleX(0.05); -moz-transition:-moz-transform 0.5s; -moz-transform-origin:left center; top:-384px; left:80px; overflow:hidden; border-radius:0 20px 20px 0; } div#innh p { margin:0 0 0 20px; font-family:sans-serif; white-space:nowrap; overflow:hidden; } div#innh:hover{ -moz-transform: scaleX(1); min-height:823px; height:auto; } div#chaps p{ margin:0 0 0 0px; font-family:sans-serif; white-space:nowrap; overflow:hidden; } div#chaps { opacity:0; -moz-transition:opacity 1s; } body { background:#dfaa66; min-height:600px; background: -moz-radial-gradient(300px 400px 65deg, ellipse cover, green 50%,blue 100%); } div#help{ background:cyan; background: -moz-linear-gradient( top,#088 , cyan, cyan, cyan,white); border-color:darkblue ; border-style:none solid ridge solid; border-width: 8px 1px 8px 1px; position:absolute; height:0px; width:595px; top:18px; left:118px; overflow-y:auto; z-index:3; -moz-transition:height 0.6s; -moz-transform-origin:center top; border-radius:0 0 29px 29px ; font-family:sans-serif; visibility:hidden; } div#help hr{ margin:0 15% ;} div#help h2 { text-align:center; margin:1em 0 0.5em 0 ; text-shadow:2px 2px 2px #044; } div#help p{margin:1em;} .knapp{ display:block; text-align:center; text-shadow:2px 2px 4px blue; line-height:24px; font-size:24px; color:darkblue; width:24px; height:24px; background:red; border-style:outset; border-width:3px; border-color:darkblue; background: -moz-radial-gradient(10px 12px 65deg, circle cover, #99f 5%,blue 80%); border-radius:6px; } div.knapp:hover { color:green; } div.knapp:active { border-style:inset; background: -moz-radial-gradient(10px 12px 65deg, circle cover, #448 5%,#00a 60%); } div.hjelp { width:70px; border-color:; color:#442; font-size:19px; margin:20px; text-shadow:1px 1px 3px maroon; background: -moz-radial-gradient(10px 12px 65deg, circle cover, #ff8 5%,#aa0 80%); } div.hjelp:active { background: -moz-radial-gradient(10px 12px 65deg, circle cover, #884 5%,#550 80%); } iframe#ramme { background:white; position:absolute; top:10px; left:108px; height:800px; width:615px; z-index:0; border-style:ridge double outset none; border-width:11px; border-color:brown; border-radius:0 9px 9px 0; } p#tittel { font-size:36px; font-style:italic; font-weight:bold; text-shadow:2px 2px 5px maroon; text-align:center; padding-bottom:14px; color:#a68120; border-color:#300808; margin-left:-358px; margin-top:393px; background:cyan; border-style:double solid none solid; border-width:5px 4px 2px 3px; -moz-transform: rotate(-90deg); -webkit-transform: rotate(-90deg); -o-transform: rotate(-90deg); -ms-transform: rotate(-90deg); background: -moz-linear-gradient( bottom,#9f6a46, #490d0d); width:824px; border-radius:20px 20px 0 0; } p.nav { letter-spacing:0.36em; text-shadow:1px 1px 3px #842; margin-top:2px; float:left; width:308px; text-align:center; font-family:sans-serif; font-weight:bold; font-style:italic; border-style:solid; color:maroon; background:yellow; position:absolute; top:828px; } p#next:active { background: -moz-linear-gradient( left ,#ff9f55, #300502); } p#next:hover { color:#311; } p#next { background: -moz-linear-gradient( left ,#ff9f55, #793522); border-bottom-right-radius:20px; border-top-right-radius:20px; left:420px; } p#prev:active { background: -moz-linear-gradient( right ,#ff9f55, #300502); } p#prev:hover { color:#311; } p#prev { background: -moz-linear-gradient( right ,#ff9f55, #793522); border-top-left-radius:20px; border-bottom-left-radius:20px; left:110px; } div#controls { position:absolute; top:30px; left:750px; width:110px; height:180px; border:ridge; border-color:green; border-radius:25px; margin-left:auto; margin-right:auto; background: -moz-radial-gradient(55px 90px 65deg, ellipse cover, #084 80%,lightgreen 100%); } </style> <script type="text/javascript"> var fs=25 var opfFile="" var ncxFile="" var author="" var title="" var titlepage="" var indx=0 var toggle=new Boolean() var urlArr=new Array() var titleArr=new Array() var spineArr=new Array() var tocTxtArr=new Array() var tocUrlArr=new Array() var toggleHelp=new Boolean() function readFile(func, file) { document.getElementById("ramme").src=file var t=setTimeout(func+'();', 100) } function readContentXml() { opfFile=document.getElementById("ramme").contentDocument.getElementsByTagName("container")[0].getElementsByTagName("rootfiles")[0].getElementsByTagName("rootfile")[0].getAttribute("full-path") basis=opfFile.replace(/\/[^/]*$/,"/") readFile("readOpf", opfFile) } function readOpf() { var d=document.getElementById("ramme").contentDocument.getElementsByTagName("package")[0] var spineNodes=d.getElementsByTagName("spine")[0].getElementsByTagName("itemref") var manifestNodes=d.getElementsByTagName("manifest")[0].getElementsByTagName("item") var i=0 var j=0 for (j=0;j<spineNodes.length;j++) { for (i=0;i<manifestNodes.length;i++) { if (manifestNodes[i].getAttribute("id")==spineNodes[j].getAttribute("idref")) { spineArr[j]=manifestNodes[i].getAttribute("href") } } } for (i=0;i<manifestNodes.length;i++) { if (manifestNodes[i].getAttribute("id")==d.getElementsByTagName("spine")[0].getAttribute("toc")) { ncxFile=manifestNodes[i].getAttribute("href") } } titlepage=d.getElementsByTagName("guide")[0].getElementsByTagName("reference")[0].getAttribute("href") author=d.getElementsByTagName("metadata")[0].getElementsByTagName("dc:creator")[0].childNodes[0].nodeValue title=d.getElementsByTagName("metadata")[0].getElementsByTagName("dc:title")[0].childNodes[0].nodeValue readFile("readNcx", basis+ncxFile) } function readNcx() { var d=document.getElementById("ramme").contentDocument.getElementsByTagName("ncx")[0] var navPoints=d.getElementsByTagName("navMap")[0].getElementsByTagName("navPoint") for (i=0;i<navPoints.length;i++) { tocUrlArr[i]=navPoints[i].getElementsByTagName("content")[0].getAttribute("src") tocTxtArr[i]= navPoints[i].getElementsByTagName("text")[0].childNodes[0].nodeValue; } toggleToc() document.getElementById("ramme").src=basis+titlepage document.getElementById("ramme").style.visibility="visible" document.getElementById("tittel").innerHTML=author+": "+title } function fillToc() { var i=0 var d=document.getElementById("chaps"); d.innerHTML="" for (i=0; i<titleArr.length;i++) { d.innerHTML+="<p onClick=\"showChap("+i+")\" id=\""+i+"\">"+titleArr[i]+"</p>" } } function toggleToc() { var tmp="" toggle=document.getElementById("toggler").checked if (urlArr.length>0) tmp=urlArr[indx] if (toggle) { titleArr=spineArr urlArr=spineArr } else { titleArr=tocTxtArr urlArr=tocUrlArr } fillToc() if (tmp.length>0) { var i=0 for (i=0;i<urlArr.length;i++) { if (tmp==urlArr[i]) indx=i } } document.getElementById(indx).style.fontWeight="bold" } function hideToc() { document.getElementById('innh').style.MozTransform='scaleX(0.05)' document.getElementById('chaps').style.opacity=0 document.getElementById('innh').style.height='823px' } function showToc() { if (toggleHelp) { document.getElementById('innh').style.MozTransform='scaleX(1)' document.getElementById('innh').style.height='auto' document.getElementById('innh').style.minHeight='823px' document.getElementById('chaps').style.opacity=1 } } function nextPrev(t) { indx+=t if (indx<0) {indx=0} if (indx>=urlArr.length) {indx=(urlArr.length-1)} showChap(indx) } function showHelp() { if (toggleHelp) { document.getElementById('help').style.visibility="visible" document.getElementById('help').style.height='600px' var t=setTimeout("document.getElementById('help').style.overflowY='auto'",1000) } else { document.getElementById('help').style.overflowY='hidden' document.getElementById('help').style.height='0px' var t=setTimeout("document.getElementById('help').style.visibility='hidden'",1000) } toggleHelp=!toggleHelp } function scaleFont(t) { fs+=t document.getElementById("ramme").contentDocument.getElementsByTagName("body")[0].style.fontSize=fs+"px" } function showChap(n) { document.getElementById("ramme").src=basis+urlArr[n] var t=setTimeout('document.getElementById("ramme").contentDocument.getElementsByTagName("body")[0].style.fontSize=fs+"px"',50) var i=0 for (i=0;i<urlArr.length;i++) { document.getElementById(i).style.fontWeight="normal" } document.getElementById(n).style.fontWeight="bold" indx=n } function init() { var msg="Only works with Firefox, I'm afraid..." document.getElementById("ramme").src="META-INF/container.xml" if (navigator.appVersion.indexOf("Chrome")>-1) {alert(msg+"\nYou could try starting chrome with --allow-file-access-from-local-files")} if (navigator.appName.indexOf("Opera")>-1) {alert(msg)} document.getElementById("ramme").style.visibility="hidden" readFile("readContentXml", "META-INF/container.xml") document.getElementById("ramme").src=basis+titlepage } </script> </head> <body onLoad="init()"> <p onClick="nextPrev(-1)" class="nav" id="prev">Previous Chapter</p> <p onClick="nextPrev(1)" class="nav" id="next">Next Chapter</p> <iframe name="ramme" id="ramme" src="META-INF/container.xml" ></iframe> <div id="help" onClick="showHelp()"> <h2>SBT's Attempt at a Viewer for Epub</h2> <hr> <ul> <li> Only works with Firefox when reading from files. If it is accessed through a web server, it should in theory work in all major browsers. Chrome shoul also work if started wit <tt>--allow-file-access-from-files</tt>, but I've not been successful. <li> Unzip your epub-file, and save this web page on the top level of the unzipped directory structure, i.e. on the same level as META-INF (not <em>in</em> META-INF) <li>Move the pointer over the book spine to see and select from list of contents. <li> Use buttons to increase/decrease font size. <li> If 'Spine' box is checked, the table of contents lists the xhtml files listed in the <tt><spine></tt> section of the OPF-manifest file. <li>Viewing window is 600x800, so this viewer can be handy when crafting an epub book to see how it looks on a standard e-reader screen. <li> Click inside the help window or on the help button to make this info go away. </ul> <p> No copyright claimed, but an acknowledgement is always appreciated if you use this web page to create a derived work.</p> <div style="margin:2em 2em 1em 60%"> <p> <em> SBT 9. March 2012</em></p> </div> </div> <div id="spine" onMouseOut="hideToc()" onMouseOver="showToc()"><div> <p id="tittel">(Author:Title)</p> </div> <div id="innh"> <div id="chaps"> </div> </div> </div> <div id="controls"> <div class="knapp hjelp" onClick="showHelp()" id="helpbt">Help</div> <div style="height:30px;margin-bottom:20px;"> <div class="knapp" onClick="scaleFont(-1)" style="margin-left:22px;;float:left"><span style="font-size:10px;">A</span></div> <div class="knapp" onClick="scaleFont(1)"style="margin-right:22px;float:right"><span style="font-size:20px;">A</span> </div> </div> <form> <input type="checkbox" id="toggler" onClick="toggleToc()" value="true" ><span style="font-size:21px;color:lightgreen;text-shadow:2px 2px 2px #f44;}">Spine</span></input> </form> </body> </html> |
![]() |
![]() |
![]() |
#9 |
Enthusiast
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 25
Karma: 1028
Join Date: Mar 2010
Location: Chandler, AZ
Device: Samsung Stratosphere (coolreader), BeBook Neo,EBookman
|
@SBT:
Why not just use the firefox add-on EPUBreader? But it is so much fun to do it yourself. AZdave |
![]() |
![]() |
![]() |
#10 |
Fanatic
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 580
Karma: 810184
Join Date: Sep 2010
Location: Norway
Device: prs-t1, tablet, Nook Simple, assorted kindles, iPad
|
What?? Has somebody already done it? Darn...
![]() My feeble claim to usefulness for this is that you can stick it in your epub file, and not require any modifications to your browser, and it can be nice to have for visually inspecting an epub during development. And it's rather fun messing about with CSS3 and javascript. I'm still fiddling about with it, and have got it working in Chrome and Opera too. Trying to get javascript unzipping and html5 file reading to work as well. |
![]() |
![]() |
![]() |
#11 |
Junior Member
![]() Posts: 1
Karma: 10
Join Date: Nov 2014
Device: kobo
|
Tiny bugfix for epub_read.sh
Hi - I was looking for a quick way to view epub files at the command line, and found this - does just what I wanted. However, I got a load of syntax errors, from bc. I tracked it down to line 237:
j=$(echo "scale=0; k=($j+1)/1-$j; scale=10; if ($j >= 0) $j+k/2 else 0" | bc) j starts at -1, which leads to a divide by 1--1 in the expression for k. It seems bc doesn't like '--'; adding brackets around the variable j solves the problem: j=$(echo "scale=0; k=($j+1)/1-($j); scale=10; if ($j >= 0) $j+k/2 else 0" | bc) Thanks |
![]() |
![]() |
![]() |
#12 |
frumious Bandersnatch
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 7,542
Karma: 19001583
Join Date: Jan 2008
Location: Spaniard in Sweden
Device: Cybook Orizon, Kobo Aura
|
Thanks for reminding me. I had actually fixed this some time ago. Here is an updated version, with some other fixes too, including SBT's patch for lynx (but the option is -l instead of -v).
This is version 2.1 |
![]() |
![]() |
![]() |
|
![]() |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
converting epubs | alansplace | ePub | 8 | 09-19-2010 10:30 PM |
Deregistering epubs: How? | Dr. Drib | Ectaco jetBook | 2 | 09-12-2010 03:50 PM |
Do you finish reading every book you start reading? | JSWolf | General Discussions | 56 | 08-12-2010 05:52 PM |
Free ePUBS anyone? | ondabeach | ePub | 7 | 06-16-2009 06:26 PM |
Environmental study: 30 min of e-paper reading = 30 mins of print reading | Steven Lyle Jordan | News | 36 | 12-14-2007 03:29 PM |