PRSAnnotationExtractor For The Sony PRS-350 In Ubuntu 18.04 (And Related) – Ruby Installs, Error Messages, And Simple Tweak

The Sony PRS-350 remains a wonderful eReader after many years (and it's cheap on eBay!) and I am pleased to report that, despite its age, some Ruby exists to extract annotations.

The trusty Sony PRS-350.

After attempts to save annotations using Kovid Goyal's tremendous Calibre with the Calibre-Annotations plug-in, it was eventually discovered that the PRS-350 annotation saving is a bit different from what later Sony readers and other current readers employ. I then stumbled upon Elie Morisse's PRSAnnotationExtractor – now eight years past any updates and written around (it seems) a later Sony Reader (at least the PRS-650, as reported for testing).

Fortunately, with the right installs in place, PRSAnnotationExtractor works just fine to process book annotations provided both the epub and the annot files are in the right place, both of which are accessible from the mounted PRS-350 device on your desktop.

Qualifiers

  1. The process below works just fine under Ubuntu 18.04.5 LTS and should work just fine for others.
  2. The install process and associated errors from a semi-fresh Ubuntu install are included under the assumption that someone searching for how to install PRSAnnotationExtractor is getting the same errors.

Ruby Installs

Working from the requirements listed on the PRSAnnotationExtractor page, you need nokogiri, csspool, and zipruby

Install and failure of nokogiri …

user@machine:~$ sudo gem install nokogiri

Fetching: racc-1.5.2.gem (100%)
Building native extensions. This could take a while...
ERROR:  Error installing nokogiri:
	ERROR: Failed to build gem native extension.

    current directory: /var/lib/gems/2.5.0/gems/racc-1.5.2/ext/racc/cparse
/usr/bin/ruby2.5 -r ./siteconf20210719-2367-hgn9lr.rb extconf.rb
mkmf.rb can't find header files for ruby at /usr/lib/ruby/include/ruby.h

extconf failed, exit code 1

Gem files will remain installed in /var/lib/gems/2.5.0/gems/racc-1.5.2 for inspection.
Results logged to /var/lib/gems/2.5.0/extensions/x86_64-linux/2.5.0/racc-1.5.2/gem_make.out

… because you've not the necessary Ruby files installed by default (ruby2.5-dev or whatever the available version is in that range).

user@machine:~$ sudo apt-get install ruby2.5-dev 
Reading package lists... Done
Building dependency tree       
Reading state information... Done
...
Setting up ruby2.5-dev:amd64 (2.5.1-1ubuntu1.9) ...
Processing triggers for libc-bin (2.27-3ubuntu1.4) ...

With ruby2.5-dev installed …

user@machine:~$ sudo gem install nokogiri
Building native extensions. This could take a while...
Successfully installed racc-1.5.2
Fetching: nokogiri-1.11.7-x86_64-linux.gem (100%)
Successfully installed nokogiri-1.11.7-x86_64-linux
Parsing documentation for racc-1.5.2
Installing ri documentation for racc-1.5.2
Parsing documentation for nokogiri-1.11.7-x86_64-linux
Installing ri documentation for nokogiri-1.11.7-x86_64-linux
Done installing documentation for racc, nokogiri after 2 seconds
2 gems installed

… goes without issue, as does csspool.

user@machine:~$ sudo gem install csspool
Fetching: csspool-4.0.5.gem (100%)
Successfully installed csspool-4.0.5
Parsing documentation for csspool-4.0.5
Installing ri documentation for csspool-4.0.5
Done installing documentation for csspool after 0 seconds
1 gem installed

An initial zipruby install produced the error below …

user@machine:~$ sudo gem install zipruby
Fetching: zipruby-0.3.6.gem (100%)
Building native extensions. This could take a while...
ERROR:  Error installing zipruby:
	ERROR: Failed to build gem native extension.

    current directory: /var/lib/gems/2.5.0/gems/zipruby-0.3.6/ext
/usr/bin/ruby2.5 -r ./siteconf20210719-3294-m0tqur.rb extconf.rb
checking for zlib.h... no
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
	--with-opt-dir
	--without-opt-dir
	--with-opt-include
	--without-opt-include=${opt-dir}/include
	--with-opt-lib
	--without-opt-lib=${opt-dir}/lib
	--with-make-prog
	--without-make-prog
	--srcdir=.
	--curdir
	--ruby=/usr/bin/$(RUBY_BASE_NAME)2.5

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /var/lib/gems/2.5.0/extensions/x86_64-linux/2.5.0/zipruby-0.3.6/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /var/lib/gems/2.5.0/gems/zipruby-0.3.6 for inspection.
Results logged to /var/lib/gems/2.5.0/extensions/x86_64-linux/2.5.0/zipruby-0.3.6/gem_make.out

… which, upon inspection, is due to missing zlib.h.

user@machine:~$ more  /var/lib/gems/2.5.0/extensions/x86_64-linux/2.5.0/zipruby-0.3.6/mkmf.log
have_header: checking for zlib.h... -------------------- no

"gcc -o conftest -I/usr/include/x86_64-linux-gnu/ruby-2.5.0 -I/usr/include/ruby-2.5.0/ruby/backward -I/usr/include/ruby-2.5.0 -I. -Wdate-time -D_FORTIFY_SOURCE=2   -g -O2 -fdebug-prefix-map=/build/r
uby2.5-FWwz7w/ruby2.5-2.5.1=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC conftest.c  -L. -L/usr/lib/x86_64-linux-gnu -L. -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fstack
-protector -rdynamic -Wl,-export-dynamic     -lruby-2.5  -lpthread -lgmp -ldl -lcrypt -lm   -lc"
checked program was:
/* begin */
1: #include "ruby.h"
2: 
3: int main(int argc, char **argv)
4: {
5:   return 0;
6: }
/* end */

"gcc -E -I/usr/include/x86_64-linux-gnu/ruby-2.5.0 -I/usr/include/ruby-2.5.0/ruby/backward -I/usr/include/ruby-2.5.0 -I. -Wdate-time -D_FORTIFY_SOURCE=2   -g -O2 -fdebug-prefix-map=/build/ruby2.5-FW
wz7w/ruby2.5-2.5.1=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC  conftest.c -o conftest.i"
conftest.c:3:10: fatal error: zlib.h: No such file or directory
 #include <zlib.h>
          ^~~~~~~~
compilation terminated.
checked program was:
/* begin */
1: #include "ruby.h"
2: 
3: #include <zlib.h>
/* end */

--------------------

Install of zlib1g-dev solves this issue …

user@machine:~$ sudo apt install zlib1g-dev
Reading package lists... Done
Building dependency tree       
Reading state information... Done
...
Setting up zlib1g-dev:amd64 (1:1.2.11.dfsg-0ubuntu2) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...

… and zipruby now cleanly installs.

user@machine:~$ sudo gem install zipruby
Building native extensions. This could take a while...
Successfully installed zipruby-0.3.6
Parsing documentation for zipruby-0.3.6
Installing ri documentation for zipruby-0.3.6
Done installing documentation for zipruby after 0 seconds
1 gem installed

PRSAnnotationExtractor

Now, with the PRSAnnotationExtractor-master.zip downloaded (click the green "Code" and "Download Zip"), we expand …

user@machine:~$ unzip PRSAnnotationExtractor-master.zip 
Archive:  PRSAnnotationExtractor-master.zip
66f0b284ed662ffd939f4608ac15c375f635b3a1
   creating: PRSAnnotationExtractor-master/
  inflating: PRSAnnotationExtractor-master/.gitignore  
...
  inflating: PRSAnnotationExtractor-master/prsannotextract.rb  
  inflating: PRSAnnotationExtractor-master/screenshot.png

… and confirm contents:

user@machine:~$ cd PRSAnnotationExtractor-master/
user@machine:~/PRSAnnotationExtractor-master$ ls -l
total 116
drwxrwxr-x 7 user user  4096 Oct 22  2013 csspool
-rw-rw-r-- 1 user user   488 Oct 22  2013 csspool.rb
-rw-rw-r-- 1 user user 15292 Oct 22  2013 inlineparser.rb
-rw-rw-r-- 1 user user  4028 Oct 22  2013 inlineparser.y
-rw-rw-r-- 1 user user  7066 Oct 22  2013 inlinetokenizer.rb
-rw-rw-r-- 1 user user  3661 Oct 22  2013 inlinetokenizer.rex
-rw-rw-r-- 1 user user  1079 Oct 22  2013 LICENSE
-rw-rw-r-- 1 user user  1110 Oct 22  2013 LICENSE.csspool
-rwxr-xr-x 1 user user 15905 Oct 22  2013 prsannotextract.rb
-rw-rw-r-- 1 user user  1848 Oct 22  2013 README.md
-rw-rw-r-- 1 user user 47437 Oct 22  2013 screenshot.png

Usage And Tweak

To run, you copy the .epub and .annot files for the epub into the folder containing prsannotextract.rb and:

ruby prsannotextract.rb book.epub.annot book.epub

Upon mounting the PRS-350, your book location and annotation location are:

Reader > database > media > books

Reader > Digital Editions > Annotations > database > media > books

For ease, simply copy the book and annotation files into the PRSAnnotationExtractor-master folder. That said, first execution on my sample book (out of the PRS-350-formatted .annot file) produced the following:

user@machine:~/PRSAnnotationExtractor-master$ ruby prsannotextract.rb book.epub.annot book.epub
Traceback (most recent call last):
	23: from prsannotextract.rb:535:in `<main>'
	22: from prsannotextract.rb:410:in `extract'
	21: from prsannotextract.rb:410:in `new'
	20: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:296:in `initialize'
	19: from prsannotextract.rb:421:in `block in extract'
	18: from prsannotextract.rb:421:in `open'
	17: from prsannotextract.rb:428:in `block (2 levels) in extract'
	16: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:378:in `method_missing'
	15: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:395:in `insert'
	14: from prsannotextract.rb:443:in `block (3 levels) in extract'
	13: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:378:in `method_missing'
	12: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:395:in `insert'
	11: from prsannotextract.rb:446:in `block (4 levels) in extract'
	10: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/node_set.rb:238:in `each'
	 9: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/node_set.rb:238:in `upto'
	 8: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/node_set.rb:239:in `block in each'
	 7: from prsannotextract.rb:449:in `block (5 levels) in extract'
	 6: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:378:in `method_missing'
	 5: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:395:in `insert'
	 4: from prsannotextract.rb:456:in `block (6 levels) in extract'
	 3: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:378:in `method_missing'
	 2: from /var/lib/gems/2.5.0/gems/nokogiri-1.11.7-x86_64-linux/lib/nokogiri/xml/builder.rb:395:in `insert'
	 1: from prsannotextract.rb:489:in `block (7 levels) in extract'
prsannotextract.rb:349:in `wraptext': invalid byte sequence in UTF-8 (ArgumentError

This issue here, which I address without proper workup, is due to lines 349 – 351 in prsannotextract.rb – the UTF-8 error is not an error for the purposes of extracting the annotations from the PRS-350 (again, something must have changed in the PRS-650 and similar devices). Simply commenting out the block of lines (add the #'s) in a text editor …

#    if not /[^\s]/ =~ text
#      return
#    end

… yields a working annotation extraction program – which, initially, writes to the terminal.

user@machine:~/PRSAnnotationExtractor-master$ ruby prsannotextract.rb book.epub.annot book.epub
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8"/>
    <style>
        div#wrapper { margin:0 auto; background-color:#d8d880; }
        div.Annotation { margin:10px 0; border:thin dotted #080808; background-color:#f2f2ff; max-width:750px; }
        div.AnnotationTitle { margin-left:2px; }
        span.AnnotTitle { font-weight:bold; }
        span.AnnotDate { font-size:90%; color:sienna; }
        div.AnnotationBody { margin-left:8px; margin-top:3px; }
</style>
  </head>
  <body>
    <div class="Annotation">
      <div class="AnnotationTitle">
        <span class="AnnotTitle">Elevate</span>
        <span class="AnnotDate">2010-01-02 10:45:34</span>
      </div>
      <div class="AnnotationBody">
        <p>
          <span style="font-size:0.875em;">zeitgeist </span>
        </p>
      </div>
    </div>
    <div class="Annotation">
      <div class="AnnotationTitle">
        <span class="AnnotTitle">Elevate</span>
        <span class="AnnotDate">2010-01-02 11:11:14</span>
      </div>
      <div class="AnnotationBody">
        <p>
          <span style="font-size:0.875em;">Annotation... </span>
        </p>
      </div>
    </div>
  </body>
</html>

Simply redirect to book.html and your annotations are visible and cleanly formatted.

ruby prsannotextract.rb book.epub.annot book.epub > book.html

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.