Advertisement
Guest User

Untitled

a guest
Feb 7th, 2017
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 11.59 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3. # v 1.0 (after some previous unnumbered versions) [12-09-2009]
  4. #
  5. # v 2.0 [19-09-2009]
  6. #       (fixed bug with IFS/ORIGIFS)
  7. #       (use XMLStarlet)
  8. #
  9. # v 2.1 [29-11-2014]
  10. #       (option for reading epub in lynx. SBT) [09-12-2011]
  11. #       (correctly detect authors without opf:role)
  12. #       (escape HTML contents)
  13. #       (delete temporary directory when aborted)
  14. #   (fix quotes around variables)
  15. #       (fix prev/next links)
  16. #       (open with xdg-open)
  17.  
  18. # Needs:
  19. #   unzip      (http://www.info-zip.org/)
  20. #   XMLStarlet (http://xmlstar.sourceforge.net/)
  21. #===============================================================================
  22.  
  23. get_data() {
  24.   # Get name and path of the OPF file
  25.   NS=$($XML sel -B -T -t \
  26.     -m "//*[local-name()='rootfile'][1]" -v "namespace-uri()" META-INF/container.xml)
  27.   OPF=$($XML sel -B -T -N x="$NS" -t \
  28.     -m "//x:rootfile" -v "@full-path" META-INF/container.xml)
  29.   BASEDIR=$(dirname $OPF)
  30.   # Get the title of the EPUB
  31.   NS=$($XML sel -B -T -t \
  32.     -m "//*[local-name()='metadata'][1]" -v "namespace-uri()" "$OPF")
  33.   DC=$($XML sel -B -T -t \
  34.     -m "//*[local-name()='title'][1]" -v "namespace-uri()" "$OPF")
  35.   TITLE=$($XML sel -B -T -N x="$NS" -N dc="$DC" -t \
  36.     -m "//x:metadata/dc:title[1]" -v "text()" "$OPF")
  37.   AUTHOR=$($XML sel -B -T -N x="$NS" -N dc="$DC" -t \
  38.     -m "//x:metadata/dc:creator[@x:role='aut' or not(@x:role)]" -v "text()" -i "position()!=last()" -o "; " "$OPF")
  39.   echo "Title: $TITLE"
  40.   echo "Author(s): $AUTHOR"
  41.   # Get name of the NCX file
  42.   NCX=$($XML sel -B -T -N x="$NS" -t \
  43.     -m "//x:spine" -v "@toc" "$OPF")
  44.   NCX=$($XML sel -B -T -N x="$NS" -t \
  45.     -m "//x:manifest/x:item[@id='$NCX']" -v "@href" "$OPF")
  46.   NCX=$BASEDIR/$NCX
  47.  
  48.   # Handle lynx' inability to deal with xml:base and meta charset:
  49.   lynx_base=
  50.   if (( $LYNX )); then
  51.      lynx_base="${BASEDIR}/"
  52.      find ${BASEDIR} -name "*html" -exec sed -i s/'<[^>]*charset=[^>]*>'//I {} \;
  53.      lynx -show_cfg > lynx.config
  54.      cat >> lynx.config << EOF
  55.      SUFFIX_ORDER:PRECEDENCE_HERE
  56.      SUFFIX:.xhtml:text/html
  57. EOF
  58.   fi
  59. }
  60.  
  61. read_spine() {
  62.   ORIGIFS=$IFS
  63.   IFS=$(echo -en "\n\b")
  64.   # Get the filenames for all the items in the spine
  65.   for id in $($XML sel -B -T -N x="$NS" -t \
  66.     -m "//x:spine/*" -v "@idref" -n "$OPF"); do
  67.     ids[${#ids[*]}]=$id
  68.     files[${#files[*]}]=$($XML sel -B -T -N x="$NS" -t \
  69.     -m "//x:manifest/x:item[@id='$id']" -v "@href" "$OPF")
  70.     linears[${#linears[*]}]=$($XML sel -B -T -N x="$NS" -t \
  71.     -m "//x:spine/x:itemref[@idref='$id']" -v "number(not(@linear='no'))" "$OPF")
  72.   done
  73.   IFS=$ORIGIFS
  74. }
  75.  
  76. read_toc() {
  77.   NC=$($XML sel -B -T -t \
  78.     -m "//*[local-name()='navMap'][1]" -v "namespace-uri()" "$NCX")
  79.   # Get the depth of the navMap element
  80.   navmap=$($XML sel -B -T -N x="$NC" -t \
  81.     -m "//x:navMap[1]" -v "count(ancestor::*)" "$NCX")
  82.   ORIGIFS=$IFS
  83.   IFS=$(echo -en "\n\b")
  84.   # Get the name, source and depth of every navPoint element
  85.   for line in $($XML sel -B -T -N x="$NC" -t \
  86.     -m "//x:navMap[1]//x:navPoint" \
  87.         -m "x:navLabel/x:text" -v "text()" -o "|" -b \
  88.         -m "x:content" -v "@src" -o "|" -b \
  89.         -v "count(ancestor::*)" -n "$NCX"); do
  90.     IFS="|"
  91.     words=($line)
  92.     items[${#items[*]}]=$($XML esc ${words[0]})
  93.     srcs[${#srcs[*]}]=${words[1]}
  94.     levels[${#levels[*]}]=$((${words[2]}-navmap))
  95.   done
  96.   IFS=$ORIGIFS
  97. }
  98.  
  99. write_css() {
  100.   CSSFILE="epub-read.css"
  101.   cp $DEF_STYLE $CSSFILE
  102. }
  103.  
  104. write_xhtml() {
  105.   XHTMLFILE="epub-read.xhtml"
  106.   cat > $XHTMLFILE << EOF
  107. <?xml version="1.0" encoding="UTF-8"?>
  108. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
  109. <html xmlns="http://www.w3.org/1999/xhtml" xml:base="$BASEDIR/">
  110. <head>
  111.   <style>
  112. body {
  113.   margin-top: 4em;
  114.   background-color: white;
  115. }
  116. div.top {
  117.   position: fixed;
  118.   top: 0;
  119.   margin: 0 auto 0 auto;
  120.   background-color: white;
  121.   color: black;
  122.   width: 100%;
  123. }
  124. div.top a {
  125.   color: inherit;
  126.   text-decoration: none;
  127.   font-weight: bold;
  128. }
  129. div.top a.deact {
  130.   opacity: 0.3;
  131. }
  132. div.top table {
  133.   width: 100%;
  134. }
  135. div.top td {
  136.   width: 25%;
  137.   text-align: center;
  138. }
  139. p {
  140.   text-indent: -1em;
  141.   margin: 0;
  142. }
  143. .level1 {
  144.   margin: 1em 0 0 1em;
  145. }
  146. .level2 {
  147.   margin: 0.5em 0 0 1.5em;
  148. }
  149. .level3 {
  150.   margin: 0 0 0 2em;
  151. }
  152. .big {
  153.   font-size: 150%;
  154.   font-weight: bold;
  155. }
  156. .small {
  157.   font-size: 80%;
  158.   color: red;
  159. }
  160. .show {
  161.   display: block;
  162. }
  163. .hide {
  164.   display: none;
  165. }
  166.   </style>
  167.   <script lang="javascript" type="text/javascript">
  168. <![CDATA[
  169. var num = 0;
  170. var html = document.getElementsByTagName("html");
  171. var basedir = html[0].getAttribute("xml:base");
  172. EOF
  173.  
  174.   echo -n 'var files = [' >> $XHTMLFILE
  175.   echo -n "'${files[0]}'" >> $XHTMLFILE
  176.   for (( i=1; i<${#files[*]}; i++ )); do
  177.     if [[ ${linears[$i]} -eq 1 ]]; then echo -n ", '${files[$i]}'" >> $XHTMLFILE; fi
  178.   done
  179.   echo '];' >> $XHTMLFILE
  180.  
  181.   cat >> $XHTMLFILE << EOF
  182. function nextFile() {
  183.   if (num < files.length-1) {
  184.     num = Math.floor(num);
  185.     num++;
  186.     parent.book.location.href=basedir + files[num];
  187.     setLinks(num);
  188.   }
  189. }
  190. function prevFile() {
  191.   if (num > 0) {
  192.     num = Math.ceil(num);
  193.     num--;
  194.     parent.book.location.href=basedir + files[num];
  195.     setLinks(num);
  196.   }
  197. }
  198. function setLinks(number) {
  199.   num = number;
  200.   if (Math.floor(num) == Math.ceil(num)) {
  201.     if (num <= 0) {
  202.       document.getElementById('prev').setAttribute('class','deact');
  203.       document.getElementById('prev').href=files[0];
  204.     } else {
  205.       document.getElementById('prev').setAttribute('class','act');
  206.       document.getElementById('prev').href=files[num-1];
  207.     }
  208.     if (num >= files.length-1) {
  209.       document.getElementById('next').setAttribute('class','deact');
  210.       document.getElementById('next').href=files[files.length-1];
  211.     } else {
  212.       document.getElementById('next').setAttribute('class','act');
  213.       document.getElementById('next').href=files[num+1];
  214.     }
  215.   } else {
  216.     document.getElementById('prev').setAttribute('class','act');
  217.     document.getElementById('prev').href=files[Math.floor(num)];
  218.     if (Math.ceil(num) >= files.length-1) {
  219.       document.getElementById('next').setAttribute('class','deact');
  220.       document.getElementById('next').href=window.event.srcElement.href;
  221.     } else {
  222.       document.getElementById('next').setAttribute('class','act');
  223.       document.getElementById('next').href=files[Math.ceil(num)+1];
  224.     }
  225.   }
  226. }
  227. function setSpine() {
  228.   document.getElementById('current').innerHTML='SPINE';
  229.   document.getElementById('change').innerHTML='TOC';
  230.   document.getElementById('change').setAttribute('onclick','setToc()');
  231.   document.getElementById('spine').setAttribute('class','show');
  232.   document.getElementById('toc').setAttribute('class','hide');
  233. }
  234. function setToc() {
  235.   document.getElementById('current').innerHTML='TOC';
  236.   document.getElementById('change').innerHTML='SPINE';
  237.   document.getElementById('change').setAttribute('onclick','setSpine()');
  238.   document.getElementById('toc').setAttribute('class','show');
  239.   document.getElementById('spine').setAttribute('class','hide');
  240. }
  241. ]]>
  242.   </script>
  243. </head>
  244. <body>
  245.  
  246. <div class="top">
  247. <table><tr>
  248. <td><a href="${files[0]}" target="book" onclick="setLinks(0);">&lt;&lt;&lt;</a></td>
  249. <td><a class="deact" id="prev" href="${files[0]}" target="book" onclick="prevFile(); return false;">&lt;</a></td>
  250. <td><a id="next" href="${files[1]}" target="book" onclick="nextFile(); return false;">&gt;</a></td>
  251. <td><a href="${files[${#files[*]}-1]}" target="book" onclick="setLinks(files.length-1);">&gt;&gt;&gt;</a></td>
  252. </tr><tr>
  253. <td id="current" class="big" colspan="2">TOC</td>
  254. <td id="change" class="small" onclick="setSpine();">SPINE</td>
  255. </tr></table>
  256. </div>
  257.  
  258. <div id="spine" class="hide">
  259. EOF
  260.  
  261.   j=-1
  262.   for (( i=0; i<${#ids[*]}; i++ )); do
  263.     if [[ ${linears[$i]} -eq 0 ]]; then
  264.       j=$(echo "scale=0; k=($j+1)/1-($j); scale=10; if ($j >= 0) $j+k/2 else 0" | bc)
  265.       echo -n "* " >> $XHTMLFILE
  266.      else
  267.       j=$(echo "scale=0; ($j+1)/1" | bc);
  268.     fi
  269.     echo "<a href=\"${lynx_base}${files[$i]}\" target=\"book\" onclick=\"setLinks($j);\">${ids[$i]}</a><br/>" >> $XHTMLFILE
  270.     index[${#index[*]}]=$j
  271.   done
  272.  
  273.   cat >> $XHTMLFILE << EOF
  274. </div>
  275.  
  276. <div id="toc" class="show">
  277. EOF
  278.  
  279.   for (( i=0; i<${#items[*]}; i++ )); do
  280.     k=-1
  281.     check=$(expr ${srcs[$i]} : '\([^#]*\)#\?.*$')
  282.     for (( j=0; j<${#files[*]}; j++ )); do
  283.       if [[ "$check" == "${files[$j]}" ]]; then k=$j; fi
  284.     done
  285.     echo "<p class=\"level${levels[$i]}\">&bull; <a href=\"${lynx_base}${srcs[$i]}\" target=\"book\" onclick=\"setLinks(${index[$k]});\">${items[$i]}</a></p>" >> $XHTMLFILE
  286.   done
  287.  
  288.   cat >> $XHTMLFILE << EOF
  289. </div>
  290.  
  291. </body>
  292. </html>
  293. EOF
  294. }
  295.  
  296. write_html() {
  297.   HTMLFILE="epub-read.html"
  298.   cat > $HTMLFILE << EOF
  299. <html>
  300. <head>
  301.   <title>$($XML esc "$TITLE")</title>
  302.   <script lang="javascript" type="text/javascript">
  303.   function AddCSS() {
  304.     var NewStyle=book.document.createElement("link");
  305.     NewStyle.setAttribute("rel","stylesheet");
  306.     NewStyle.setAttribute("type","text/css");
  307.     NewStyle.setAttribute("href","$(readlink -f "$CSSFILE")");
  308.     book.document.getElementsByTagName("head")[0].appendChild(NewStyle);
  309.   }
  310.   function ChangeTitle() {
  311.     document.title=book.document.title;
  312.   }
  313.   </script>
  314. </head>
  315. <frameset cols="25%,75%">
  316.   <frame src="$XHTMLFILE"/>
  317.   <frame src="$BASEDIR/${files[0]}" name="book" onload="AddCSS(); ChangeTitle()"/>
  318. </frameset>
  319. </html>
  320. EOF
  321. }
  322.  
  323. #===============================================================================
  324.  
  325. VERBOSE=0
  326. HELP=0
  327. EXIT=0
  328. DEF_STYLE="epub-read.css"
  329. XML="xml"
  330.  
  331. while getopts "volsh:" OPTION; do
  332.   case "$OPTION" in
  333.     v ) VERBOSE=1 ;;
  334.     o ) OPEN=1 ;;
  335.     l ) LYNX=1 ;;
  336.     s ) DEF_STYLE="$OPTARG" ;;
  337.     h|*) HELP=1 ;;
  338.   esac
  339. done
  340. shift $(($OPTIND-1))
  341.  
  342. if [[ $# < 1 ]]; then
  343.   HELP=1
  344. fi
  345. if (( $HELP )); then
  346.   echo
  347.   cat << EOF
  348. USAGE:
  349.  
  350. $(basename $0) [options] input.epub
  351.  
  352. Where the options are:
  353.   -s "style.css"  Use "style.css" as stylesheet (default is "epub-read.css")
  354.          The stylesheet will be searched in the current directory first, and then in ~/.epub2pdf
  355.   -o              Open the generated page with the default program (with xdg-open)
  356.   -l              Open the generated page with lynx
  357.   -v              Verbose output
  358.   -h              Show this help
  359. EOF
  360.   echo
  361.   EXIT=1
  362. fi
  363.  
  364. # Check the needed programs exist
  365. unzip >& /dev/null
  366. if (( $? == 127 )); then
  367.   echo "Error: unzip does not exist (http://www.info-zip.org/)"
  368.   EXIT=1
  369. fi
  370. $XML >& /dev/null
  371. if (( $? == 127 )); then
  372.   XML="xmlstarlet"
  373.   $XML >& /dev/null
  374.   if (( $? == 127 )); then
  375.     echo "Error: xml and xmlstarlet do not exist (http://xmlstar.sourceforge.net/)"
  376.     EXIT=1
  377.   fi
  378. fi
  379.  
  380. if (( $EXIT )); then exit 1; fi
  381.  
  382. if [[ ! -r "$DEF_STYLE" ]]; then
  383.   if [[ -r "$HOME/.epub2pdf/$DEF_STYLE" ]]; then
  384.     DEF_STYLE="$HOME/.epub2pdf/$DEF_STYLE"
  385.   fi
  386. fi
  387. if [[ -r "$DEF_STYLE" ]]; then
  388.   if (( $VERBOSE )); then
  389.     echo "Using stylesheet $DEF_STYLE"
  390.   fi
  391.  else
  392.   echo "Cannot read file $DEF_STYLE"
  393.   exit 1
  394. fi
  395. DEF_STYLE=$(readlink -f "$DEF_STYLE")
  396.  
  397. DIR=$PWD
  398. EPUB=$(readlink -f "$1")
  399.  
  400. if [[ ! -r "$EPUB" ]]; then
  401.   echo "Cannot read file $1"
  402.   exit 1
  403. fi
  404.  
  405. TEMPDIR=$(mktemp -td epub-read.XXX) || exit 1
  406. [ -d $TEMPDIR ] || mkdir $TEMPDIR
  407. trap "rm -rf $TEMPDIR" INT TERM
  408.  
  409. cd $TEMPDIR
  410. unzip -qo "$EPUB"
  411.  
  412. get_data
  413. read_spine
  414. read_toc
  415. write_css
  416. write_xhtml
  417. write_html
  418.  
  419. echo -e "\n$(readlink -f $HTMLFILE)\n"
  420.  
  421. if (( $OPEN )); then
  422.   xdg-open $(readlink -f $HTMLFILE)
  423. elif (( $LYNX )); then
  424.   lynx -cfg=lynx.config $(readlink -f $HTMLFILE)
  425. fi
  426.  
  427. read -p "Press <ENTER> to delete the temporary files" END
  428.  
  429. cd "$DIR"
  430. rm -rf $TEMPDIR
  431. exit 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement