Register Guidelines E-Books Today's Posts Search

Go Back   MobileRead Forums > E-Book Readers > Kobo Reader > Kobo Developer's Corner

Notices

Reply
 
Thread Tools Search this Thread
Old 03-26-2024, 10:20 PM   #16
elinkser
Addict
elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.
 
Posts: 222
Karma: 146236
Join Date: Oct 2022
Device: Kobo Clara HD
FBPDF - A PDF/EPUB VIEWER FOR ELINKS

***


FBPDF - A PDF/EPUB VIEWER FOR ELINKS


Fbpdf is a mupdf-based pdf viewer from the same author as fbpad.


$ source ~/koxtoolchain/refs/x-compile.sh kobo env bare
(Prepare build system as was done in Post #4 above.)

mupdf
$ wget https://mupdf.com/downloads/archive/...-source.tar.gz

$ tar zxvf mupdf-1.24.0-source.tar.gz

$ cd mupdf-1.24.0-source/

$ make shared-clean

$ make CC=arm-kobo-linux-gnueabihf-gcc CXX=arm-kobo-linux-gnueabihf-g++ OBJCOPY=arm-kobo-linux-gnueabihf-objcopy LINK=arm-kobo-linux-gnueabihf-gcc LD=arm-kobo-linux-gnueabihf-ld AR=arm-kobo-linux-gnueabihf-ar RANLIB=arm-kobo-linux-gnueabihf-ranlib XCFLAGS=" -fPIC -DTOFU_CJK -DTOFU_NOTO " HAVE_X11=no HAVE_GLUT=no shared-release

$ ls -l build/shared-release/libmupdf.so.24.0
-rwxr-xr-x 1 6514576 build/shared-release/libmupdf.so.24.0

$ file build/shared-release/mutool
build/shared-release/mutool: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.33, stripped


$ cd ..



*The next section was already done in Post #4 above:

************************************************** **

NiLuJe/FBInk

https://github.com/NiLuJe/FBInk/releases

$ wget https://github.com/NiLuJe/FBInk/rele...v1.25.0.tar.xz

$ tar xJf FBInk-v1.25.0.tar.xz

$ cd FBInk-v1.25.0/

$ make static stripped

$ cd ..



ddvk / fbpad-eink
forked from kisonecat/fbpad-eink
https://github.com/ddvk/fbpad-eink

$ wget https://github.com/ddvk/fbpad-eink/a...ads/master.zip

$ unzip fbpad-eink-master.zip

$ cd ..


************************************************** **





aligrudi/fbpdf
https://github.com/aligrudi/fbpdf

$ wget https://github.com/aligrudi/fbpdf/ar...ads/master.zip

$ mv master.zip fbpdf-master.zip

$ unzip fbpdf-master.zip

$ cd fbpdf-master/

$ cp -r ../mupdf-1.24.0-source/include .

$ mkdir lib

$ cp -r ../mupdf-1.24.0-source/build/shared-release/libmupdf* lib/


$ mkdir FBInk

$ cp -r ../FBInk-v1.25.0/Release FBInk/

$ cp ../FBInk-v1.25.0/fbink.h FBInk/

$ cp ../fbpad-eink-master/draw.c .

$ cp ../fbpad-eink-master/draw.h .


$ nano -l draw.h
Code:
...
 19 void  fbpdf_refresh(int fd, int invalid_top, int invalid_left, int invalid_right, int invalid_bottom);
$ nano -l draw.c
Code:
...
160
161 void fbpdf_refresh(int fd, int invalid_top, int invalid_left, int invalid_right, int invalid_bottom) {
162   fbink_refresh( fb_fd(),
163                  invalid_top,
164                  invalid_left,
165                  invalid_right - invalid_left,
166                  invalid_bottom - invalid_top,
167                  cfg() );
168 }


*** UPDATE ***
Modified space,b,r,s, and R defs.
**************

$ nano -l fbpdf.c
Code:
...
 27 #define FBDEV           "/dev/fb0"
...
 43 static int percentDisplay;      /* percent of display used */
 44 static int startDisplay;        /* start percent of display used */
 45 static int firstRow;            /* first row of display used */
 46 static int numRows;             /* number of rows of display used */
...
 74                 memcpy(fb_mem(i - srow + firstRow), rbuf, scols * bpp);
 75         }
 76         free(rbuf);
 77         fbpdf_refresh(fb_fd(), firstRow, 0, scols, firstRow + srows);
 78 }
...
255                 switch (c) {    /* commands that require redrawing */
256                 case ' ':
257                                                 if (srow < -(int)(srows / 11)) {
258                                                         srow += (int)(9 * srows / 10);
259                                                 } else {
260                                                         if (!loadpage(num + getcount(1)))
261                                                                 srow = prow;
262                                                 }
263                                                 break;
264                 case 'b':
265                                                 srow -= (int)(srows / 2);
266                                                 if (srow < -prows / 2) {
267                                                         srow = -prows / 2;
268                                                         if (!loadpage(num - getcount(1)))
269                                                                 srow = -(int)(srows / 2);
270                                                 }
271                                                 break;
272                 case CTRLKEY('b'):
273                 case CTRLKEY('f'):
274                 case 'J':
275                         if (!loadpage(num + getcount(1)))
276                                 srow = prow;
277                         break;
278                 case 'K':
279                         if (!loadpage(num - getcount(1)))
280                                 srow = prow;
281                         break;
282                 case 'r':
283                                 setmark('\'');
284                                 if (!loadpage(num - count))
285                                         srow = prow;
286                                 break;
287                 case 's':
288                                 setmark('\'');
289                                 if (!loadpage(num + count))
290                                         srow = prow;
291                                 break;
292                 case 'g':
293                 case 'G':
...
319                 case 'R':
320                         rotate = getcount(0);
321                         if (!loadpage(num))
322                                 srow = prow;
323                         break;
...
352 /*              case ' ': */
...
418         if (fb_init(FBDEV))
419                 return 1;
420         srows = fb_rows();
421         scols = fb_cols();
422
423         if (getenv("FBPDF_START") != NULL) {
424                 printf("FBPDF_START = %s\n", getenv("FBPDF_START"));
425                 startDisplay = atoi(getenv("FBPDF_START"));
426                 if (startDisplay < 1 || startDisplay > 99) {
427                         startDisplay = 0;
428                 }
429         } else {
430                 startDisplay = 0;
431         }
432         firstRow = srows * startDisplay / 100;
433         
434         if (getenv("FBPDF_PERCENT") != NULL) {
435                 printf("FBPDF_PERCENT = %s\n", getenv("FBPDF_PERCENT"));
436                 percentDisplay = atoi(getenv("FBPDF_PERCENT"));
437                 if (percentDisplay < 1 || percentDisplay > 99) {
438                         percentDisplay = 100;
439                 }
440         } else {
441                 percentDisplay = 100;
442         }
443         if ((startDisplay + percentDisplay) > 100) {
444                 percentDisplay = 100 - startDisplay;
445         }
446         numRows = srows * percentDisplay / 100;
447
448         if ((firstRow + numRows) > srows) {
449                 numRows = numRows - 1;
450         }
451         srows = numRows;
...

$ nano -l Makefile
Code:
...
  2 CC = arm-kobo-linux-gnueabihf-gcc
...
 14         $(CC) -o $@ $^ $(LDFLAGS) -lmupdf -lmupdf-pkcs7 -lmupdf-threads -lm FBInk/Release/libfbink.a
...

$ make fbpdf

$ file fbpdf
fbpdf: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.33, with debug_info, not stripped

$ ls -l fbpdf
-rwxr-xr-x 1 23832 fbpdf

$ cd ..

$ cp fbpdf-master/lib/libmupdf.so.24.0 .

$ ls -l libmupdf.so.24.0
-rwxr-xr-x 1 6514576 libmupdf.so.24.0

I compressed the libmupdf.so.24.0 file:
$ xz -z libmupdf.so.24.0

$ ls -l libmupdf.so.24.0.xz
-rwxr-xr-x 1 3353772 libmupdf.so.24.0.xz

I split up the libmupdf.so.24.0.xz file, so that it meets mobileread.com 1MB upload limit:
* UPDATE - I guess upload limits were increased, or did I imagine the whole thing? Hmmm...
Anyway, just unzip the one file now

$ split -d -b 1000000 libmupdf.so.24.0.xz mx

$ ls -l mx*
-rw-r--r-- 1 1000000 mx00
-rw-r--r-- 1 1000000 mx01
-rw-r--r-- 1 1000000 mx02
-rw-r--r-- 1 353772 mx03

I added .zip extension to the split files to meet mobileread.com naming convention - didn't actually zip them) :

$ mv mx00 mx00.zip
$ mv mx01 mx01.zip
$ mv mx02 mx02.zip
$ mv mx03 mx03.zip

$ ls -l mx*
-rw-r--r-- 1 1000000 mx00.zip
-rw-r--r-- 1 1000000 mx01.zip
-rw-r--r-- 1 1000000 mx02.zip
-rw-r--r-- 1 353772 mx03.zip


Now to recreate the original libmupdf.so.24.0 file, you just have to reverse the process.
Copy the mx*.zip files to the Kobo's /mnt/onboard/.adds/kordir/libs/ folder.

On your kobo, reassemble the libmupdf.so.24.0.xz compressed file:

# cd /mnt/onboard/.adds/kordir/libs/

# cat mx*.zip > libmupdf.so.24.0.xz

# xz -d libmupdf.so.24.0.xz

# ls -l libmupdf.so.24.0
-rwxr-xr-x 1 6514576 libmupdf.so.24.0

With libmupdf.so.24.0 installed in /mnt/onboard/.adds/kordir/libs/ folder:

Copy the fbpdf binary to the Kobo's /mnt/onboard/.adds/kordir/scripts/ folder.

Copy sample files fbpdf.pdf and sfm.epub, and self.png to the /mnt/onboard/.adds/kordir/ folder.

# . /korenv.sh

# FBPDF_PERCENT=58 fbpdf -z 20 fbpdf.pdf

# FBPDF_START=29 FBPDF_PERCENT=29 fbpdf -z 20 sfm.epub

# FBPDF_PERCENT=58 fbpdf -z 5 self.png

space to PageDown
b to PageUp
j,k to scroll each page
q to quit


Now you can set up fbpdf as the pdf handler for elinks:

Edit /mnt/onboard/.adds/kordir/.elinks/elinks.conf
Code:
...
set mime.extension.pdf="application/pdf"

set mime.handler.pdf_viewer.unix.ask = 1
set mime.handler.pdf_viewer.unix-xwin.ask = 0

set mime.handler.pdf_viewer.unix.block = 1
set mime.handler.pdf_viewer.unix-xwin.block = 0

set mime.handler.pdf_viewer.unix.program = "/mnt/onboard/.adds/kordir/scripts/fbpdf %"
set mime.handler.pdf_viewer.unix-xwin.program = "/mnt/onboard/.adds/kordir/scripts/fbpdf %"

set mime.type.application.pdf = "pdf_viewer"
...
So if you run elinks like this:
# FBPDF_PERCENT=58 elinks
(Hit . <RET> to browse the current folder)

Navigate to a pdf file and it will open with fbpdf.
e.g. 25z to zoom 2.5x
h,l to scroll left,right

Similarly edit /mnt/onboard/.adds/kordir/.elinks/elinks.conf to set fbpdf as an epub handler:
Code:
...
set mime.extension.epub="application/epub"

set mime.handler.epub_viewer.unix.ask = 1
set mime.handler.epub_viewer.unix-xwin.ask = 0

set mime.handler.epub_viewer.unix.block = 1
set mime.handler.epub_viewer.unix-xwin.block = 0

set mime.handler.epub_viewer.unix.program = "/mnt/onboard/.adds/kordir/scripts/fbpdf %"
set mime.handler.epub_viewer.unix-xwin.program = "/mnt/onboard/.adds/kordir/scripts/fbpdf %"

set mime.type.application.epub = "epub_viewer"
...
What the heck - edit the image viewer to fbpdf too, it's all fbink under the hood anyway

Code:
# set mime.handler.image_viewer.unix.program = "/mnt/onboard/.adds/kordir/scripts/fbink -G -y 30 -g file=% ;sleep 2"
# set mime.handler.image_viewer.unix-xwin.program = "/mnt/onboard/.adds/kordir/scripts/fbink -G -y 30 -g file=% ;sleep 2"
set mime.handler.image_viewer.unix.program = "/mnt/onboard/.adds/kordir/scripts/fbpdf %"
set mime.handler.image_viewer.unix-xwin.program = "/mnt/onboard/.adds/kordir/scripts/fbpdf %"

*** UPDATE ***
Modified space,b,r,s, and R defs.
**************

space now scrolls down, then next page when reaches bottom
b now scrolls up, then previous page when reaches top
r for rotate has been reassigned to R
ESC followed by integer to reset 'count'. Then:
g to goto page 'count'
s to skim forward 'count' pages
r to skim backward 'count' pages
i to get info
q to quit

Included mutool and muraster utility binaries.

***


******* UPDATE2 *****
Width and css support.
***********************
UPDATE2a : support ignore doc css when user css provided

$ nano -l mupdf.c
Code:
...
  7 #define MIN_(a, b)      ((a) < (b) ? (a) : (b))
  8
  9 static float layout_w = FZ_DEFAULT_LAYOUT_W;
 10 static float layout_h = FZ_DEFAULT_LAYOUT_H;
 11 static float layout_em = FZ_DEFAULT_LAYOUT_EM;
 12 static char *layout_css = NULL;
 13 static int layout_use_doc_css = 1;
 14
 15 struct doc {
...
 64         }
 65         if (getenv("FBPDF_CSS") != NULL) {
 66                 printf("FBPDF_CSS = %s\n", getenv("FBPDF_CSS"));
 67                 layout_css = getenv("FBPDF_CSS");
 68                 if (getenv("FBPDF_DOCCSS") != NULL) {
 69                         printf("FBPDF_DOCCSS = %s\n", getenv("FBPDF_DOCCSS"));
 70                         layout_use_doc_css = fz_atoi(getenv("FBPDF_DOCCSS"));
 71                         if (layout_use_doc_css != 0)
 72                                 layout_use_doc_css = 1;
 73                 }
 74                 fz_buffer *buf = fz_read_file(doc->ctx, layout_css);
 75                 fz_set_user_css(doc->ctx, fz_string_from_buffer(doc->ctx, buf));
 76                 fz_drop_buffer(doc->ctx, buf);
 77                 fz_set_use_document_css(doc->ctx, layout_use_doc_css);
 78         }
 79         if (getenv("FBPDF_WIDTH") != NULL) {
 80                 printf("FBPDF_WIDTH = %s\n", getenv("FBPDF_WIDTH"));
 81                 layout_w = fz_atof(getenv("FBPDF_WIDTH"));
 82                 if (layout_w < 50 || layout_w > 5000) {
 83                         layout_w = FZ_DEFAULT_LAYOUT_W;
 84                 }
 85         } else {
 86                 layout_w = FZ_DEFAULT_LAYOUT_W;
 87         }
 88         fz_layout_document(doc->ctx, doc->pdf, layout_w, layout_h, layout_em);
 89         return doc;
 90 }
...

$ make fbpdf

Recopy the fbpdf binary to the Kobo's /mnt/onboard/.adds/kordir/scripts/ folder.

Copy Style.css and sfm.epub to the /mnt/onboard/.adds/kordir/ folder.

# . /korenv.sh

# fbpdf -z 25 sfm.epub

# FBPDF_WIDTH=420 fbpdf -z 25 sfm.epub

# FBPDF_WIDTH=210 fbpdf -z 50 sfm.epub

# fbpdf -z 25 sfm.epub

# FBPDF_CSS=Style.css fbpdf -z 25 sfm.epub

# FBPDF_CSS=Style.css FBPDF_DOCCSS=0 fbpdf -z 25 sfm.epub


* SECURITY NOTE RE XZ *
On desktop:
$ xz -V
xz (XZ Utils) 5.2.4
liblzma 5.2.4
On Kobo:
# xz -v
BusyBox v1.31.1.kobo (2020-04-22 11:41:43 EDT) multi-call binary.


***
Attached Files
File Type: zip fbpdf-build.zip (306.8 KB, 177 views)
File Type: zip libmupdf.zip (4.11 MB, 118 views)

Last edited by elinkser; 05-09-2024 at 08:48 AM. Reason: space,b,r,s+mutool+width/css+doccss+single zip file
elinkser is offline   Reply With Quote
Old 03-27-2024, 05:00 PM   #17
elinkser
Addict
elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.
 
Posts: 222
Karma: 146236
Join Date: Oct 2022
Device: Kobo Clara HD
SFM - A DUAL PANE FILE MANAGER FOR FBPAD

***

SFM - A DUAL PANE FILE MANAGER FOR FBPAD


$ source ~/koxtoolchain/refs/x-compile.sh kobo env bare
(Prepare build system as was done in Post #4 above.)


afify/sfm
https://github.com/afify/sfm

$ wget https://github.com/afify/sfm/archive...gs/v0.4.tar.gz

$ mv v0.4.tar.gz sfm-v0.4.tar.gz

$ tar zxvf sfm-v0.4.tar.gz

$ cd sfm-0.4/

$ nano -l config.mk
Code:
...
14 CC = arm-kobo-linux-gnueabihf-gcc  
...
$ make

$ file sfm
sfm: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.33, stripped

Copy the sfm binary to the /mnt/onboard/.adds/kordir/scripts/ folder on your Kobo.

# . /korenv.sh

# sfm

j/k to go down,up
h/l to traverse directories or open file
:q <RET> to quit viewing a file (vi is default viewer)
space to switch panes
b to open shell (CTRL-d to return to sfm)
. to toggle hidden files
CTRL-u to go up 3
CTRL-d to go down 3
q to quit sfm


***

We can customize the keydefs to make them more consistent with our other apps.
At the same time we can add fbpdf and elinks as default handlers:

* Update: added PageUp/PageDown key support, removed redundant ,/.

$ nano -l config.def.h
Code:
...
 50 /* software */
 51 static const char *mpv[]          = { "mpv", "--fullscreen" };
 52 static const char *elinks[]       = { "elinks" };
 53 static const char *fbpdf[]        = { "fbpdf" };
...
 58 /* extensions*/
 59 static const char *images[]    = { "bmp", "jpg", "jpeg", "png", "gif", "xpm" };
 60 static const char *pdf[]       = { "epub", "pdf" };
 61 static const char *arts[]      = { "xcf" };
 62 static const char *html[]      = { "htm", "html" };
...
 69 static Rule rules[] = {
 70         {videos,    LEN(videos),    mpv,         LEN(mpv)         },
 71         {images,    LEN(images),    fbpdf,       LEN(fbpdf)       },
 72         {pdf,       LEN(pdf),       fbpdf,       LEN(fbpdf)       },
 73         {documents, LEN(documents), libreoffice, LEN(libreoffice) },
 74         {arts,      LEN(arts),      gimp,        LEN(gimp)        },
 75         {html,      LEN(html),      elinks,      LEN(elinks)      },
...
 85         { {.ch = 'b'},                 mv_ver,       {.i = +8}       },
 86         { {.key = TB_KEY_PGUP},        mv_ver,       {.i = +8}       },
 87         { {.key = TB_KEY_SPACE},       mv_ver,       {.i = -8}       },
 88         { {.key = TB_KEY_PGDN},        mv_ver,       {.i = -8}       },
 89         { {.ch = 'l'},                 mvfwd,        {.i = 0}        },
 90         { {.key = TB_KEY_ARROW_RIGHT}, mvfwd,        {.i = 0}        },
 91         { {.key = TB_KEY_ENTER},       mvfwd,        {.i = 0}        },
 92         { {.ch = 'h'},                 mvbk,         {.i = 0}        },
 93         { {.key = TB_KEY_ARROW_LEFT},  mvbk,         {.i = 0}        },
 94         { {.key = TB_KEY_BACKSPACE},   mvbk,         {.i = 0}        },
 95         { {.key = TB_KEY_BACKSPACE2},  mvbk,         {.i = 0}        },
...
110         { {.ch = 'B'},                 opnsh,        {0}             },
111         { {.key = TB_KEY_TAB},         switch_pane,  {0}             },
112         { {.key = TB_KEY_CTRL_R},      refresh,      {0}             },
113         { {.ch = '\\'},                bkmrk,        {.v = root}     },
114         { {.ch = 'H'},                 toggle_df,    {0}             },
...
$ rm config.h

$ make

Copy the new sfm binary to the /mnt/onboard/.adds/kordir/scripts/ folder on your Kobo.

# FBPDF_PERCENT=58 sfm

Our new keydefs are:

j/k to go down,up
(* DON'T PRESS ARROW_DOWN OR YOU WILL ENTER SHELL, CTRL-D TO EXIT)
(* DON'T PRESS ARROW_LEFT OR YOU WILL BE PROMPTED TO RENAME, RET TO KEEP NAME)
h/l to traverse directories or open file
BS/RET to traverse directories or open file
:q <RET> to quit viewing a file (vi is default viewer)
TAB to switch panes
B to open shell (CTRL-d to return to sfm)
H to toggle hidden files
b/PageUp to go up 8
space/PageDown to go down 8
q to quit sfm


Now, entering l/RET on a pdf/epub/image file now invokes fbpdf, while on an html file invokes elinks.


***


The vi editor is the default viewer, but we can override this with an environment variable SFM_VIEWER.

* Update: at the same time we can try to correct the errant left and down arrow behavior:

$ nano -l sfm.c
Code:
...
1861         editor[0] = getenv("SFM_VIEWER");
...
2000         
2001         if (tb_select_input_mode(TB_INPUT_ALT) != TB_INPUT_ALT)
2002                 if (tb_select_input_mode(TB_INPUT_ESC) != TB_INPUT_ESC)
2003                         die("input error");
2004
...
$ make

# SFM_VIEWER=less sfm

Now, entering l/RET on a text file invokes the less pager instead of the vi editor, so you can use space/b for pagedown/pageup, and just q for quit.


We can create scripts to call sfm with the viewer we want:

* Update: Set TERM to linux instead of xterm to correct errant arrow key behavior. Unfortunately, same problem occurs if you press keys too quickly! But at least works if you go slow.

# vi /usr/bin/sfmless
Code:
export TERM=linux
SFM_VIEWER=less /mnt/onboard/.adds/kordir/scripts/sfm
# vi /usr/bin/sfmvi
Code:
export TERM=linux
SFM_VIEWER=vi /mnt/onboard/.adds/kordir/scripts/sfm
# vi /usr/bin/sfmnano
Code:
export TERM=linux
SFM_VIEWER=nano /mnt/onboard/.adds/kordir/scripts/sfm
# chmod 755 /usr/bin/sfmless
# chmod 755 /usr/bin/sfmvi
# chmod 755 /usr/bin/sfmnano

# sfmless
(can quit with q)
# sfmvi
(can quit with ESC then :q!)
# sfmnano
(haha, doesn't work unless you installed nano as in Post #3, and even then you would have to first run . /korenv.sh to set the PATH)

***

Our (revised) sfm keydefs:
obsoleted, see update 2


*** UPDATE ELINKS.CONF KEY BINDINGS ***

Update /mnt/onboard/.adds/kordir/.elinks/elinks.conf to harmonize elinks with new apps fbpdf and sfm:

REMOVE:
bind "main" "," = "history-move-back"
bind "main" "." = "history-move-forward"
bind "main" "#" = "toggle-numbered-links"

ADD:
bind "main" "H" = "history-manager"
bind "main" "h" = "history-move-back"
bind "main" "l" = "history-move-forward"
bind "main" "j" = "move-cursor-down"
bind "main" "k" = "move-cursor-up"

RESULT:
Use H instead of h for history
Use h/l instead of ,/. for move forward/back in history
Use j/k for for move cursor down/up
Use the default . to toggle displaying numbered links on page, so you can go directly to the link by entering the number.

***************************************

*** ALSO UPDATE /KORENV.SH ***

Update /korenv.sh to better work with new apps fbpdf and sfm:

REMOVE:
export TERM=xterm

ADD:
export TERM=linux
export FBPDF_PERCENT=58

***************************************


***

* UPDATE 2 - A KLUDGE/FIX FOR ERRANT DIRECTION KEYS:

A possible kludge/fix is to redefine key sequences to NOT be confused with the escape code sequences we are sending for the direction keys.

ANSI escape code sequences for direction keys:
<esc>[A - Up
<esc>[B - Down
<esc>[D - Left
<esc>[C - Right

Errant sfm direction key responses:
ARROW_DOWN - SHELL
ARROW_LEFT - RENAME

Our latest(after 1st update) sfm keydefs:
A undefined
B spawn a shell in the current directory
D duplicate file | directory recursively
C undefined

So we can try redefining these keys:
A up
B down
D left
C right
, duplicate file | directory recursively
S spawn a shell in the current directory
. toggle dotfiles


$ nano -l config.def.h
Code:
...
 81         { {.ch = 'j'},                 mv_ver,       {.i = -1}       },
 82         { {.ch = 'B'},                 mv_ver,       {.i = -1}       },
 83         { {.key = TB_KEY_ARROW_DOWN},  mv_ver,       {.i = -1}       },
 84         { {.ch = 'k'},                 mv_ver,       {.i = +1}       },
 85         { {.ch = 'A'},                 mv_ver,       {.i = +1}       },
 86         { {.key = TB_KEY_ARROW_UP},    mv_ver,       {.i = +1}       },
...
 91         { {.ch = 'l'},                 mvfwd,        {.i = 0}        },
 92         { {.ch = 'C'},                 mvfwd,        {.i = 0}        },
 93         { {.key = TB_KEY_ARROW_RIGHT}, mvfwd,        {.i = 0}        },
 94         { {.key = TB_KEY_ENTER},       mvfwd,        {.i = 0}        },
 95         { {.ch = 'h'},                 mvbk,         {.i = 0}        },
 96         { {.ch = 'D'},                 mvbk,         {.i = 0}        },
 97         { {.key = TB_KEY_ARROW_LEFT},  mvbk,         {.i = 0}        },
 98         { {.key = TB_KEY_BACKSPACE},   mvbk,         {.i = 0}        },
 99         { {.key = TB_KEY_BACKSPACE2},  mvbk,         {.i = 0}        },
...
105         { {.ch = ','},                 dupl,         {0}             },
...
114         { {.ch = 'S'},                 opnsh,        {0}             },
...
118         { {.ch = '.'},                 toggle_df,    {0}             },
...

$ rm config.h

$ make

Copy the new sfm binary to the /mnt/onboard/.adds/kordir/scripts/ folder on your Kobo.

# sfm

Direction keys now working, but colors in elinks a little off.
Change to export TERM=screen and all good.

So...

# vi /usr/bin/sfmless
Code:
export TERM=screen
SFM_VIEWER=less /mnt/onboard/.adds/kordir/scripts/sfm
# vi /usr/bin/sfmvi
Code:
export TERM=screen
SFM_VIEWER=vi /mnt/onboard/.adds/kordir/scripts/sfm
# vi /usr/bin/sfmnano
Code:
export TERM=screen
SFM_VIEWER=nano /mnt/onboard/.adds/kordir/scripts/sfm
# vi /korenv.sh
Code:
#!/bin/sh

export PATH=/mnt/onboard/.adds/kordir/scripts:/mnt/onboard/.adds/koreader/plugins/terminal.koplugin/:/mnt/onboard/.adds/koreader/scripts:$PATH
export LD_LIBRARY_PATH=/mnt/onboard/.adds/kordir/libs:/mnt/onboard/.adds/koreader/libs:$LD_LIBRARY_PATH
export TERM=screen
export FBPDF_PERCENT=58 
export HOME=/mnt/onboard/.adds/kordir/
cd $HOME

alias ls='ls --color=never'
***

* UPDATE 3 - PUT HIGHLIGHTED FILE'S BASENAME ON STATUS BAR:

Helps identify currently selected file when running sfm in KOReader terminal.

$ nano -l sfm.c
Code:
...
 284 static void
 285 print_info(Pane *pane, char *dirsize)
 286 {
 287         char *sz, *ur, *gr, *dt, *prm, *nm;
 288
 289         dt = ecalloc(MAX_DTF, sizeof(char));
 290         nm = basename(CURSOR(pane).name);
...
 309         print_status(cstatus, "%02d/%02d %s %s:%s %s %s %s", pane->hdir,
 310                 pane->dirc, prm, ur, gr, dt, sz, nm);
...
$ make

Copy the new sfm binary to the /mnt/onboard/.adds/kordir/scripts/ folder on your Kobo.

Run sfm in KOReader terminal:

# . /korenv.sh

# sfm

***
Our (final?) sfm keydefs:
Normal Mode
q quit
h/left/BS back
j/down down
k/up up
l/right/RET open dir | file
g top
G bottom
b/PgUp scroll up
SPACE/PgDn scroll down
n create new file if not exists
N create new directory if not exists
d delete file | directory recursively
, duplicate file | directory recursively
y yank
p paste
P move
S spawn a shell in the current directory
c start change
cw rename
co change owner and group (chown)
cm change mode (chmod)
cf change flags (chflags | chattr)
cc exit change
cq exit change
. toggle dotfiles
v start visual mode
/ start filter
ENTER find filter
ESC exit filter
TAB switch pane
ctrl+r refresh panes

Visual Mode
j select down
k select up
d delete selection
v exit visual mode
q exit visual mode
ESC exit visual mode | change



***





* Edit : actually just leave default input mode - comment out the crap I put there (it interfered with ESC key use.)

$ nano -l sfm.c
Code:
...
2000 /*              
2001         if (tb_select_input_mode(TB_INPUT_ALT) != TB_INPUT_ALT)
2002                 if (tb_select_input_mode(TB_INPUT_ESC) != TB_INPUT_ESC)
2003                         die("input error");
2004 */
...

* Edit : add a couple more bindings to elinks.conf to not interfere with screen utility.

Code:
...
bind "main" "Ctrl-a" = "none"
bind "main" "Ctrl-A" = "none"

set document.colors.use_document_colors = 0
...
Attached Files
File Type: zip sfm.zip (29.6 KB, 115 views)

Last edited by elinkser; 04-05-2024 at 10:18 PM. Reason: revised keydefs,TERM,direction,status basename,default
elinkser is offline   Reply With Quote
Old 06-02-2024, 05:51 PM   #18
elinkser
Addict
elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.
 
Posts: 222
Karma: 146236
Join Date: Oct 2022
Device: Kobo Clara HD
W3M - GRAPHICAL BROWSER FOR FBPAD

W3M - GRAPHICAL BROWSER FOR FBPAD


The w3m terminal browser we installed from Alpine Linux to the /mnt/onboard/.adds/koreader/ here ( https://www.mobileread.com/forums/sh...91&postcount=3 ) and migrated to the /mnt/onboard/.adds/kordir/ folder here ( https://www.mobileread.com/forums/sh...6&postcount=14 ) is capable of showing inline images.


It just needs an external image displayer, w3mimgdisplay, which we will crosscompile for fbink and rename w3mimgfbink.


w3mimgdisplay has the following input parameters:
(Thanks to https://blog.z3bra.org/2014/01/images-in-terminal.html for the heads up.)
Code:
/*
* w3mimg protocol
*  0  1  2 ....
* +--+--+--+--+ ...... +--+--+
* |op|; |args             |\n|
* +--+--+--+--+ .......+--+--+
*
* args is separeted by ';'
* op   args
*  0;  params          draw image
*  1;  params          redraw image
*  2;  -none-          terminate drawing
*  3;  -none-          sync drawing
*  4;  -none-          nop, sync communication
*                      response '\n'
*  5;  path            get size of image,
*                      response "<width> <height>\n"
*  6;  params(6)       clear image
*
* params
*      <n>;<x>;<y>;<w>;<h>;<sx>;<sy>;<sw>;<sh>;<path>
* params(6)
*      <x>;<y>;<w>;<h>
*
*/
	/*
		+_______screen_____+
		|       ^             |
		|       |offset_y|
		|       v              |
		|      +image |
		|<____>|         |    |
		|offset_x|       |    |
		|        |       |    |
		|        +_______+     |
		+___________|_________+
		                     |
		                     v
		+________image_______+
		|            ^             |
		|            | shift_y |
		|            v            |
		|       +- view port + ^  |
		|<___>|          |      |     |
		|shift_x |      | height|
		|         |  |  |      |
		|    +______+    v   |
		|   <-  width ->    |
		+_____________________+

	*/

***
***
***


First build w3m on the desktop.
You will build a binary called mktable that runs on the desktop to help crosscompile the arm binary for kobo (you will see later on.)


tats/w3m
https://github.com/tats/w3m/tree/master

$ wget https://github.com/tats/w3m/archive/...ads/master.zip


Now create a directory to build the arm binary:

$ mkdir websw

$ source ~/koxtoolchain/refs/x-compile.sh kobo env bare
(This is the koreader toolchain as was covered here https://www.mobileread.com/forums/sh...16&postcount=4 .
Note the frequent reference to the $HOME/x-tools/ folder.
That is where the koreader crosscompile libs and headers are installed.)

$ cd websw/


Now we will procede to crosscompile the whole w3m package, but we will only need the w3mimgdisplay binary, since the the main browser app w3m we got from Alpine Linux works fine.

***
***
***



giflib
$ wget https://sourceforge.net/projects/gif...b-5.2.2.tar.gz

$ tar zxvf giflib-5.2.2.tar.gz

$ cd giflib-5.2.2/

$ CC=arm-kobo-linux-gnueabihf-gcc make

$ cd ..

***

imlib2
$ wget https://downloads.sourceforge.net/en...-1.12.2.tar.xz

$ tar Jxvf imlib2-1.12.2.tar.xz

$ cd imlib2-1.12.2/

$ ./configure --without-x --without-tiff --without-webp --host=arm-kobo-linux-gnueabihf CPPFLAGS=" -I$HOME/x-tools/usr/include/ -I$HOME/websw/giflib-5.2.2/ " LDFLAGS=" -L$HOME/x-tools/usr/lib/ -L$HOME/websw/giflib-5.2.2/ -lgif " FREETYPE_CFLAGS=" -I$HOME/x-tools/usr/include/freetype2/ " FREETYPE_LIBS=" -L$HOME/x-tools/usr/lib/ -lfreetype " PNG_CFLAGS=" -I$HOME/x-tools/usr/include/ " PNG_LIBS=" -L$HOME/x-tools/usr/lib/ -lpng " JPEG_CFLAGS=" -I$HOME/x-tools/usr/include/ " JPEG_LIBS=" -L$HOME/x-tools/usr/lib/ -ljpeg " ZLIB_CFLAGS=" -I$HOME/x-tools/usr/include/ " ZLIB_LIBS=" -L$HOME/x-tools/usr/lib/ -lz " LIBS=" -lrt "


$ ls -l $HOME/x-tools/arm-kobo-linux-gnueabihf/arm-kobo-linux-gnueabihf/sysroot/lib/libdl*
-r-xr-xr-x 106036 libdl-2.15.so
lrwxrwxrwx 2023 libdl.so.2 -> libdl-2.15.so

$ export DLDIR=$HOME/x-tools/arm-kobo-linux-gnueabihf/arm-kobo-linux-gnueabihf/sysroot/lib/

(What just happened here is we are making sure we are building for the ARM libdl, and not the desktop one.)


$ nano -l Makefile
Code:
...
275 DLOPEN_LIBS = -L$(DLDIR) -ldl
...

$ make

$ cd ..


***


gc 8.2.2-r2
https://hboehm.info/gc/


$ wget https://hboehm.info/gc/gc_source/lib...s-7.8.0.tar.gz

$ tar zxvf libatomic_ops-7.8.0.tar.gz

$ cd libatomic_ops-7.8.0/

$ ./configure --host=arm-kobo-linux-gnueabihf

$ make

$ cd ..

***

$ wget https://hboehm.info/gc/gc_source/gc-8.2.4.tar.gz

$ tar zxvf gc-8.2.4.tar.gz

$ cd gc-8.2.4/

$ ./configure CPPFLAGS=" -I$HOME/websw/libatomic_ops-7.8.0/src/ " LDFLAGS=" -L$HOME/websw/libatomic_ops-7.8.0/src/.libs/ " --with-libatomic-ops=check --host=arm-kobo-linux-gnueabihf

$ nano -l Makefile
Code:
...
 982 THREADDLLIBS = -lpthread -lrt -L$(DLDIR) -ldl
...
$ make

$ cd ..

***


openssl
libssl3 3.1.4-r6

$ wget https://www.openssl.org/source/openssl-3.1.5.tar.gz

$ tar zxvf openssl-3.1.5.tar.gz

$ cd openssl-3.1.5/

$ ./Configure no-ssl2 no-ssl3 --cross-compile-prefix=arm-kobo-linux-gnueabihf- linux-armv4

$ nano -l Makefile
Code:
...
3198 AR=$(CROSS_COMPILE)ar
3199 ARFLAGS= qc
3200 RANLIB=$(CROSS_COMPILE)gcc-ranlib
3201 RC= $(CROSS_COMPILE)windres
3202 RCFLAGS= 
...
3222 CNF_EX_LIBS= -L$(DLDIR) -ldl -pthread -latomic
...
$ make

$ cd ..


***

ncurses
https://invisible-island.net/ncurses/

$ tar zxvf ncurses-6.3.tar.gz

$ cd ncurses-6.3/

$ ./configure --with-static --with-shared --with-cxx-shared --without-ada --without-gpm --without-sysmouse --enable-widec --disable-big-core --host=arm-kobo-linux-gnueabihf

$ make

$ cd ..



***




tats/w3m
https://github.com/tats/w3m/tree/master

$ wget https://github.com/tats/w3m/archive/...ads/master.zip

$ mv master.zip w3m-master.zip

$ unzip w3m-master.zip

$ cd w3m-master/


$ mkdir FBInk

$ cp -r ../FBInk-v1.25.0/Release FBInk/

$ cp ../FBInk-v1.25.0/fbink.h FBInk/



$ nano -l configure
[CODE]
...
7643 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Imlib2 is not installed. Install Imlib2$
7644 $as_echo "$as_me: WARNING: Imlib2 is not installed. Install Imlib2 (version >= 1.0.5)" >&2;}
7645 have_imlib2="yes"
...
9084 if test x"$gclibdir" = xno; then
9085 /* as_fn_error $? "libgc not found" "$LINENO" 5 */
9086 fi
...
9690 /* as_fn_error $? "cannot check setpgrp when cross compiling" "$LINENO" 5 */
...
/CODE]

(A kludge to get get configure to run. Kids please don't copy - read a proper programming book instead.)


$ ./configure --enable-image=fb --with-imagelib=imlib2 --disable-nls --disable-xface --disable-mouse --with-termlib=ncurses --with-gc=$HOME/websw/gc-8.2.4/.libs SSL_CFLAGS=" -I$HOME/websw/openssl-3.1.5/include/ " SSL_LIBS=" -L$HOME/websw/openssl-3.1.5/ " CFLAGS=" -g " CPPFLAGS=" -I$HOME/websw/imlib2-1.12.2/src/lib/ -I$HOME/websw/gc-8.2.4/include/ -I$HOME/websw/openssl-3.1.5/include/ -I$HOME/websw/ncurses-6.3/include/ -I$HOME/x-tools/usr/include/ -I$HOME/x-tools/usr/include/freetype2/ " LDFLAGS=" -L$HOME/websw/imlib2-1.12.2/src/lib/.libs/ -L$HOME/websw/gc-8.2.4/.libs/ -L$HOME/websw/openssl-3.1.5/ -L$HOME/websw/ncurses-6.3/lib/ -L$HOME/x-tools/usr/lib/ -L$HOME/websw/giflib-5.2.2/ -lgif -LFBInk/Release/ " --host=arm-kobo-linux-gnueabihf


$ nano -l w3mimg/Makefile
Code:
 14 SUBDIRS=fb

$ export DLDIR=$HOME/x-tools/arm-kobo-linux-gnueabihf/arm-kobo-linux-gnueabihf/sysroot/lib/


$ nano -l Makefile
Code:
...
 48 LIBS = -lm  -lncursesw -lz -lfreetype -lfbink -lImlib2 -lgc  -L$(DLDIR) -ldl 
...

$ nano -l config.h
Code:
...
159 #define SETPGRP() setpgrp()
...
(another kludge!)


$ nano -l w3mimg/fb/fb.c
Code:
...
  25 #include "fb.h"
  26
  27 #include "FBInk/fbink.h"
  28
  29 FBInkConfig fbink_cfg = {0};
  30
  31 FBInkConfig* cfg(){
  32     return &fbink_cfg;
  33 }
...
 140 /*    if ((fbfp = open(fbdev, O_RDWR)) == -1) {
 141         fprintf(stderr, "open %s error\n", fbdev);
 142         goto ERR_END;
 143     } */
 144     fbfp = fbink_open();
 145     if (fbfp < 0) {   
 146         fprintf(stderr, "%s error\n", fbdev);
 147         goto ERR_END;
 148     }
 149     FBInkRect cls_rect = { 0 };
 150     
 151 #if defined(__linux__)
 152     if (fb_fscrn_get(fbfp, &fscinfo)) {
...
 409     }
 410     fbink_refresh( fbfp, y, x, width, height,cfg() );
 411     return 0;
 412 }
...
(Porting to fbink)


$ nano -l w3mimg/fb/fb_w3mimg.c
Code:
...
179 /*
180     if (!check_tty_console(getenv("W3M_TTY")) &&
181         strncmp("fbterm", getenv("TERM"), 6) != 0 &&
182         strncmp("jfbterm", getenv("TERM"), 7) != 0) {
183         fprintf(stderr, "w3mimgdisplay/fb: tty is not console\n");
184         goto error;
185     }
186 */
...
187     if (fb_open())
188         goto error;
189
190     int percentDisplay;
191     if (getenv("FBPDF_PERCENT") != NULL) {
192         percentDisplay = atoi(getenv("FBPDF_PERCENT"));
193         if (percentDisplay < 1 || percentDisplay > 99)
194             percentDisplay = 100;
195     } else {
196         percentDisplay = 100;
197     }
198     wop->height = fb_height() * percentDisplay / 100;
199     wop->width = fb_width();
200     
201     wop->init = w3mfb_init;
...
(making sure images only fill up the fbpad part of the display.)



$ nano -l w3mimgdisplay.c
Code:
...
 68         fflush(stdout);
...
(dimension data got buffered so have to flush it to output, or inline imaging not enabled on kobo fbpad.)


$ make
./mktable 100 functable.tab > functable.c
/lib/ld-linux-armhf.so.3: No such file or directory
make: *** [Makefile:178: functable.c] Error 255

This error is because make is attempting to use the arm compiler to generate the mktable binary to use during the build, which won't run because whatever it builds with the arm compiler won't run during the make process since that is on the desktop.
So, copy the mktable binary from a previous desktop (non crosscompiled) build:

$ cp ../w3m-master/mktable .

$ make


$ cp ../giflib-5.2.2/libgif.so .

$ cp ../imlib2-1.12.2/src/lib/.libs/libImlib2.so.1.12.2 libImlib2.so.1

$ mkdir imlib2

$ mkdir imlib2/filters

$ mkdir imlib2/loaders

$ cp ../imlib2-1.12.2/src/modules/filters/.libs/*.so imlib2/filters/

$ cp ../imlib2-1.12.2/src/modules/loaders/.libs/*.so imlib2/loaders/

Copy the libImlib2.so.1 lib to the /mnt/onboard/.adds/kordir/libs/ folder of your kobo.

Copy the imlib2 folder to the /mnt/onboard/.adds/kordir/libs/ folder of your kobo.


$ cp w3mimgdisplay w3mimgfbink

Copy the w3mimgfbink binary to the /mnt/onboard/.adds/kordir/scripts/ folder of your kobo.


ON YOUR KOBO:

Setup the path:

# . /korenv.sh


Create a new user named w3muser so that you can browse as nonroot:

# adduser w3muser
Changing password for w3muser
New password:

# addgroup fbgroup

# adduser w3muser fbgroup

# chgrp fbgroup /dev/fb0

(Looks like you have to redo that last chgrp command as root each session.)


Create a startup script:

# nano -l /w3menv.sh
Code:
 1 #!/bin/sh
 2
 3 export PATH=/mnt/onboard/.adds/kordir/scripts:/mnt/onboard/.adds/koreader/plugins/terminal.koplugin/:/mnt/onboard/.adds/koreader/scripts:$PATH
 4 export LD_LIBRARY_PATH=/mnt/onboard/.adds/kordir/libs:/mnt/onboard/.adds/koreader/libs:$LD_LIBRARY_PATH
 5 export TERM=screen
 6 export FBPDF_PERCENT=58
 7 export IMLIB2_LOADER_PATH=/mnt/onboard/.adds/kordir/libs/imlib2/loaders
 8 export HOME=/home/w3muser/
 9 cd $HOME
10
11 alias ls='ls --color=never'
12 chgrp fbgroup /dev/fb0

Run the startup script as root:

# . /w3menv.sh


Switch to the w3muser user:

# su w3muser


Run the startup script as user:

$ . /w3menv.sh


Check that the library path was set:

$ echo $IMLIB2_LOADER_PATH


Test the w3mimgfbink binary on tux.png in same folder:

$ echo -e '0;1;0;0;200;160;;;;;tux.png\n4;\n3;' | /mnt/onboard/.adds/kordir/scripts/w3mimgfbink 2>/dev/null


You can try placing it at 400,400:

$ echo -e '0;1;400;400;200;160;;;;;tux.png\n4;\n3;' | /mnt/onboard/.adds/kordir/scripts/w3mimgfbink 2>/dev/null


You can try making it double the height:

$ echo -e '0;1;400;400;200;320;;;;;tux.png\n4;\n3;' | /mnt/onboard/.adds/kordir/scripts/w3mimgfbink 2>/dev/null


Now run w3m and set the options:

$ ./w3m -v

Enter 'o' for options.

Set options as follows:

Code:
...
Display inline images                                                  (*)YES  ( )NO
Display pseudo-ALTs for inline images with no ALT or TITLE string      (*)YES  ( )NO
Load inline images automatically                                       (*)YES  ( )NO
Maximum processes for parallel image loading                           [4                   ]
Use external image viewer                                              (*)YES  ( )NO
Scale of image (%)                                                     [150                 ]
Inline image display method                                            [external command   ]
External command to display image                                      [/mnt/onboard/.adds/kordir/scripts/w3mimgfbink]
...
Tab down to [OK] and press return to save.
q to quit.


Now you have to run fbpad/fbpad2 (from either onscreen or remote SSH terminal keyboard) to see the inline images working:


From fbpad, run the startup script as root, switch to the w3muser user and run the startup script as user, as before:

# . /w3menv.sh

# su w3muser

$ . /w3menv.sh
(ignore the chgrp error message)


You can now run the Alpine Linux w3m binary on the downloaded google page to see the inline google image:

$ w3m mywgets/index.html

OR, if WiFi is on, e.g.:

$ w3m mobileread.com

Like elinks, it is space/b to page down/up, tab to traverse the links, q to quit, but U to open a URL.

W3m Shortcuts cheatsheet
https://cheatsheetfactory.geekyhacker.com/linux/w3m
⇧r Reload
⇧h Hotkeys
⇧t Open a tab
⌃q Close a tab
⇧u Go to a url
⇧{} Switch between tabs
⌃h Show history
⇧b Exit history
⇧i View image
Esci Save image
c Show which page you are on
u View a URL of a link
Escb View bookmarks
Esca To bookmark
<> Scroll left and right
o Open options/preferences
[number Go to link number
Escl Show all links in a page in pop up form to select (with going to link)


REMEMBER YOU ONLY HAVE AROUND 50MB STORAGE SPACE ON THE ROOT PARTION, SO DELETE ALL THE CACHE FILES IN /home/w3muser/.w3m AFTER EACH SESSION!!!
* CORRECTION: the w3mxxxx files that fill up the .w3m/ folder are just temp files, not cache files, according to the FAQ ( https://stuff.mit.edu/afs/sipb.mit.e...c/w3m/FAQ.html ).
If you open up a second SSH terminal, you can witness these w3mxxxx files multiply and eat up precious storage space as you browse.
Forunately, they are automatically deleted, unless you run out of space and w3m crashes, for example.


So why are we running it in the root partition then?
There is plenty of space in the user /mnt/onboard/ partition.
It is because inline imaging is not enabled on kobo fbpad if w3m can't do a symlink, and guess what the vfat user partition can't do?
Symlinks!
So either modify w3m source to not need symlinks, or run in the linux filesystem based root partition.
For now that is what we are doing.
And since we are there, we use the fine-grained permissions capability to run as nonroot, for a more secure browse. Yay!
Note: if you want to recompile w3m, it is much easier to do it in a chroot - and that way you keep library compatibility with Alpine as well.

***
***
***


* TIPS *

To get bookmarks working:

# cd /usr/lib

# ln -s /mnt/onboard/.adds/kordir/usr/lib/w3m w3m


To get helpkey 'H' working:

# cp /mnt/onboard/.adds/kordir/usr/lib/w3m/w3mhelp.html /usr/share/w3m/w3mhelp-w3m_en.html


To create a 500MB disk image on /mnt/onboard to act as a larger .w3m/ folder that is also formatted as a Linux filesystem.

# dd if=/dev/zero of=/mnt/onboard/w3m.img bs=1M count=512

# mke2fs -F /mnt/onboard/w3m.img

# cd /home/w3muser

# mount /mnt/onboard/w3m.img .w3m

# ls -l .w3m/

# chown -R w3muser:w3muser .w3m

# su w3muser

$ . /w3menv.sh

$ w3m -v

$ exit

# umount .w3m

* DON'T FORGET TO UNMOUNT THE DISK IMAGE AS ROOT WHEN DONE BROWSING (AS IN THAT LAST COMMAND) *
(Possible data corruption risk if connecting USB cable and clicking 'connect' while loopfile still mounted was mentioned here: https://www.mobileread.com/forums/sh...02&postcount=9 )


***
***
***
Attached Files
File Type: zip w3mbuild.zip (391.9 KB, 148 views)

Last edited by elinkser; 06-09-2024 at 11:46 AM. Reason: scale image 150%, tips,terminology,w3mxxxx files
elinkser is offline   Reply With Quote
Old 07-20-2024, 07:23 PM   #19
elinkser
Addict
elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.
 
Posts: 222
Karma: 146236
Join Date: Oct 2022
Device: Kobo Clara HD
YAFT - Yet Another Framebuffer Terminal - with SIXEL* image support

***

YAFT - Yet Another Framebuffer Terminal - with SIXEL* image support

*SIXEL is one of image formats for printer and terminal imaging introduced by Digital Equipment Corp. (DEC). Its data scheme is represented as a terminal-friendly escape sequence. So if you want to view a SIXEL image file, all you have to do is “cat” it to your terminal.
https://saitoha.github.io/libsixel/

You need to have a terminal that supports SIXEL, e.g. xterm if invoked as:
$ xterm -ti vt340

$ img2sixel logo.gif
$ img2sixel tux.png
$ img2sixel tux.png -o tux.six
$ cat tux.six
$ w3m -sixel mywgets/index.html

***

uobikiemukot/yaft
https://github.com/uobikiemukot/yaft

$ wget https://github.com/uobikiemukot/yaft.../v0.2.9.tar.gz

$ mv v0.2.9.tar.gz yaft-v0.2.9.tar.gz

$ tar zxvf yaft-v0.2.9.tar.gz

$ cd yaft-0.2.9/


$ nano -l conf.h
Code:
...
 4 /* color: index number of color_palette[] (see color.h) */
 5 enum {
 6         DEFAULT_FG           = 0,
 7         DEFAULT_BG           = 255,
 8         ACTIVE_CURSOR_COLOR  = 2,
 9         PASSIVE_CURSOR_COLOR = 1,
10 };
...
41 /* shell: refer SHELL environment variable at first */
42 #if defined(__linux__) || defined(__MACH__)
43         const char *shell_cmd = "/bin/sh";
...

Use a bigger font than the default:

cambus/spleen
https://github.com/fcambus/spleen

$ wget https://github.com/fcambus/spleen/re...n-2.1.0.tar.gz

$ tar zxvf spleen-2.1.0.tar.gz

$ cp ../spleen-2.1.0/spleen-32x64.bdf fonts/
$ cp ../spleen-2.1.0/spleen-16x32.bdf fonts/
$ cp ../spleen-2.1.0/spleen-12x24.bdf fonts/


$ nano -l makefile
Code:
 1 CC1 ?= arm-kobo-linux-gnueabihf-gcc
 2 CC2 ?= gcc
...
25 mkfont_bdf: tools/mkfont_bdf.c tools/mkfont_bdf.h tools/bdf.h tools/util.h
26         $(CC2) -o $@ $< $(CFLAGS) $(LDFLAGS)
...
34         # ./mkfont_bdf table/alias fonts/milkjf_k16.bdf fonts/milkjf_8x16r.bdf fonts/milkjf_8x16.bdf > glyph.h
35         ./mkfont_bdf table/alias fonts/spleen-16x32.bdf > glyph.h
36
37 yaft: yaft.c $(HDR)
38         # If you want to change configuration, please modify conf.h before make (see conf.h for more detail)
39         $(CC1) -o $@ $< $(CFLAGS) $(LDFLAGS)
...
$ make mkfont_bdf
gcc -o mkfont_bdf tools/mkfont_bdf.c -std=c99 -pedantic -Wall -Wextra -O3 -s -pipe

$ rm glyph.h

$ make glyph.h

$ cd ..


***

Resize the bdf font:

ntwk/bdfresize
https://github.com/ntwk/bdfresize

$ wget http://openlab.ring.gr.jp/efont/dist...ize-1.5.tar.gz

$ tar zxvf bdfresize-1.5.tar.gz

$ cd bdfresize-1.5/

$ ./configure

$ nano -l charresize.c
Code:
...
 49   void  *malloc();
...
$ make

$ cp ../spleen-2.1.0/spleen-32x64.bdf .

$ ./bdfresize -f 17/32 spleen-32x64.bdf >spleen-17x34.bdf

$ cd ..

$ cd yaft-0.2.9/

Save copy of yaft made with smaller spleen-16x32.bdf font:
$ mv yaft yaftS

$ cp ../bdfresize-1.5/spleen-17x34.bdf fonts/

$ nano -l makefile
Code:
...
34         # ./mkfont_bdf table/alias fonts/milkjf_k16.bdf fonts/milkjf_8x16r.bdf fonts/milkjf_8x16.bdf > glyph.h
35         ./mkfont_bdf table/alias fonts/spleen-17x34.bdf > glyph.h
...

$ rm glyph.h

$ make glyph.h

$ cd ..



***

Prepare build system as was done in Post #4 above:

$ source ~/koxtoolchain/refs/x-compile.sh kobo env bare

***

Make shared version of FBInk as in Post #4 above:

NiLuJe/FBInk
https://github.com/NiLuJe/FBInk/releases

$ wget https://github.com/NiLuJe/FBInk/rele...v1.25.0.tar.xz

$ tar xJf FBInk-v1.25.0.tar.xz

$ cd FBInk-v1.25.0/

$ make static stripped

$ cd ..

***


$ cd yaft-0.2.9/

$ mkdir fb/FBInk

$ cp -r ../FBInk-v1.25.0/Release fb/FBInk/

$ cp ../FBInk-v1.25.0/fbink.h fb/FBInk/


$ nano -l fb/common.h
Code:
...
 41
 42 #include "FBInk/fbink.h"
 43
 44 FBInkConfig fbink_cfg = {0};
 45
 46 FBInkConfig* cfg(){
 47         return &fbink_cfg;
 48 }
 49
...
303         /* open framebuffer device: check FRAMEBUFFER env at first */
304         path = ((env = getenv("FRAMEBUFFER")) == NULL) ? fb_path: env;
305 /*      if ((fb->fd = eopen(path, O_RDWR)) < 0) */
306         fb->fd = fbink_open();
307         if (fb->fd < 0)
308                 return false;
...
488         fbink_refresh( fb->fd,
489                 0,
490                 0,
491                 fb->info.width,
492                 fb->info.height,
493                 cfg() );
494 }
...

$ nano -l terminal.h
Code:
...
340         term->cols  = term->width / CELL_WIDTH;
341         term->lines = term->height / CELL_HEIGHT;
342         int percentDisplay;     /* percent of display used */
343         if (getenv("YAFT_PERCENT") != NULL) {
344                 printf("YAFT_PERCENT = %s\n", getenv("YAFT_PERCENT"));
345                 percentDisplay = atoi(getenv("YAFT_PERCENT"));
346                 if (percentDisplay < 1 || percentDisplay > 99) {
347                         percentDisplay = 100;
348                 }
349         } else {
350                 percentDisplay = 100;
351         }
352         term->lines = term->lines * percentDisplay / 100;
...

$ rm yaft

$ LDFLAGS=" -Lfb/FBInk/Release/ -lfbink " make yaft


$ cd ..


***


Now, copy the yaft and yaftS binaries to the /mnt/onboard/.adds/kordir/scripts/ folder on the Kobo.

From an SSH session to the Kobo:
# . /korenv.sh
# YAFT_PERCENT=58 yaft
YAFT_PERCENT = 58
>>WARN<< ioctl: VT_SETMODE failed (maybe here is not console)
>>WARN<< ioctl: KDSETMODE failed (maybe here is not console)

# lsof | grep yaft

# . /korenv.sh

# OSK_TTY=/dev/pts/0 oskansi2 &

# pkill yaft


Or, update our NickelMenu and fbmenu scripts (from POST #14 above):


# nano /mnt/onboard/.adds/nm/config.txt
Code:
...
menu_item :main    :YAFT_PERCENT=58    :cmd_spawn          :quiet :export HOME="/mnt/onboard/.adds/kordir/" && cd "$HOME" && export PATH="$PATH:/mnt/onboard/.adds/kordir/scripts" && export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/mnt/onboard/.adds/kordir/libs" && export YAFT_PERCENT=58 && yaft 0</dev/tty1
    chain_success                      :dbg_toast          :Started yaft
    chain_failure                      :dbg_toast          :Error starting yaft
...

# nano -l /mnt/onboard/.adds/kordir/scripts/fbmenu.sh
Code:
...
 18 if [ "$num" == "1" ]; then
 19                 qndb -m mwcToast 500 "You selected 1-Stop agetty+fbpad+yaft"
 20                 fbcmd="/usr/bin/pkill agetty"
 21                 qndb -m mwcToast 200 "$fbcmd"
 22                 fberr=$($fbcmd 2>&1)
 23                 fbcmd="/usr/bin/pkill fbpad"
 24                 qndb -m mwcToast 200 "$fbcmd"
 25                 fberr=$($fbcmd 2>&1)
 26                 fbcmd="/usr/bin/pkill fbkeyboard"
 27                 qndb -m mwcToast 200 "$fbcmd"
 28                 fberr=$($fbcmd 2>&1)
 29                 fbcmd="/usr/bin/pkill oskansi"
 30                 qndb -m mwcToast 200 "$fbcmd"
 31                 fberr=$($fbcmd 2>&1)
 32                 fbcmd="/usr/bin/pkill yaft"
 33                 qndb -m mwcToast 200 "$fbcmd"
 34                 fberr=$($fbcmd 2>&1)
 35 elif [ "$num" == "2" ]; then
 36                 qndb -m mwcToast 1000 "You selected 2-yaft"
 37                 export HOME="/mnt/onboard/.adds/kordir/"
 38                 cd "$HOME"
 39                 export LD_LIBRARY_PATH="/mnt/onboard/.adds/kordir/libs/:$LD_LIBRARY_PATH"
 40                 fbcmd="/mnt/onboard/.adds/kordir/scripts/fbkeyboard2"
 41                 qndb -m mwcToast 1000 "$fbcmd"
 42                 fberr=$($fbcmd 2>&1) &
 43                 fbcmd="eval YAFT_PERCENT=58 /mnt/onboard/.adds/kordir/scripts/yaft 0</dev/tty1"
 44                 qndb -m mwcToast 1000 "$fbcmd"
 45                 fberr=$($fbcmd 2>&1)
...


***
UNFORTUNATELY, YOU MAY NEED TO KILL AGETTY (E.G VIA FBMENU) TO GET YAFT TO WORK WITH FBKEYBOARD/OSKANSI KEYBOARDS, AT LEAST ON MY CLARA HD.
*** EDIT - and maybe even USB networking/dropbox too, to get YAFT to start!
ALSO, AS WITH FBPAD, YOU MAY NEED WIFI ON, THOUGH NO ACCESS POINT CONNECTION NEEDED.)
***




***

YAFT supports sixel images:


saitoha/libsixel
https://github.com/saitoha/libsixel

$ wget https://github.com/saitoha/libsixel/.../v1.8.6.tar.gz

$ mv v1.8.6.tar.gz libsixel-v1.8.6.tar.gz

$ tar zxvf libsixel-v1.8.6.tar.gz

$ cd libsixel-1.8.6/

$ ./configure --help

$ ./configure --host=arm-kobo-linux-gnueabihf --disable-python

$ make


$ cp converters/.libs/img2sixel .

$ cp converters/.libs/sixel2png .

$ cp src/.libs/libsixel.so.1.0.6 libsixel.so.1


***

Copy the img2sixel and sixel2png binaries to the /mnt/onboard/.adds/kordir/scripts/ folder of your kobo.


Copy the libsixel.so.1 lib to the /mnt/onboard/.adds/kordir/libs/ folder of your kobo.


Displaying images in YAFT with sixel:

# . /korenv.sh

# img2sixel tux.png


Unfortunately, the img2sixel gives error with Alpine Linux w3m binary:

w3m -sixel -o display_image=1 mywgets/index.html


We will attempt to mod the w3m source to fix sixel support.

***


Building w3m in chroot* partition to fix sixel image support:

*See POST #8 for chroot reference.


On kobo, switch to chroot:

# chalpine.sh

On kobo chroot:

(as root)
***
# apk add gc-dev
(1/2) Installing libgc++ (8.2.2-r2)
(2/2) Installing gc-dev (8.2.2-r2)
OK: 1029 MiB in 528 packages

# apk add ncurses-dev
(1/4) Installing libformw (6.4_p20230506-r0)
(2/4) Installing libmenuw (6.4_p20230506-r0)
(3/4) Installing libncurses++ (6.4_p20230506-r0)
(4/4) Installing ncurses-dev (6.4_p20230506-r0)
Executing busybox-1.36.0-r9.trigger
OK: 1030 MiB in 536 packages

# apk add libpng-dev
OK: 1030 MiB in 532 packages

# apk add libjpeg-turbo-dev
(1/1) Installing libjpeg-turbo-dev (2.1.5.1-r3)
OK: 1030 MiB in 533 packages

# apk add giflib-dev
(1/2) Upgrading giflib (5.2.1-r4 -> 5.2.2-r0)
(2/2) Installing giflib-dev (5.2.2-r0)
OK: 1030 MiB in 534 packages

# apk add imlib2-dev
(1/4) Installing libice-dev (1.1.1-r2)
(2/4) Installing util-linux-dev (2.38.1-r8)
(3/4) Installing libsm-dev (1.2.4-r1)
(4/4) Installing imlib2-dev (1.11.1-r0)
OK: 1033 MiB in 538 packages

# apk add gdb
(1/1) Installing gdb (13.1-r9)
OK: 1043 MiB in 541 packages


# su myuser

$ cd

$ mv master.zip w3m-master.zip

$ unzip w3m-master.zip

$ cd w3m-master/


$ ./configure CFLAGS=" -g " --enable-image=fb --disable-mouse --with-imagelib=imlib2


* While we are messing with w3m source code to support sixel, we may as well remove symlink requirement to allow images even in vfat /mnt/onboard (user) partition, but of course it is not as secure to run as root.


$ nano -l config.h
Code:
...
139 #undef HAVE_SYMLINK
...

Fix execvp quirk that interfered with img2sixel argument parsing (* updated to use snprintf and restore integer length to 11 as in original w3m code *):

$ nano -l terms.c
Code:
...
 789     if ((pid = fork()) == 0) {
 790         char *env;
 791         int n = 0;
 792         char *argv[20];
 793 /*      char digit[2][11+1]; */
 794         char clip1[15+7+1], clip2[3+11+1], clip3[3+11+1], clip4[3+3+44+1], clip5[12+1];
 795         Str str_url;
 796
 797         close(STDERR_FILENO);   /* Don't output error message. */
...
 821         else {
 822                 argv[n++] = "/mnt/onboard/.adds/kordir/scripts/img2sixel";
 823         }
 824 /*      argv[n++] = "-l";
 825         argv[n++] = do_anim ? "auto" : "disable";
 826         argv[n++] = "-w";
 827         sprintf(digit[0], "%d", w);
 828         argv[n++] = digit[0];
 829         argv[n++] = "-h";
 830         sprintf(digit[1], "%d", h);
 831         argv[n++] = digit[1];
 832         argv[n++] = "-c"; */
 833         snprintf(clip1, sizeof(clip1) - 1, "--loop-control=auto");
 834         argv[n++] = clip1;
 835         snprintf(clip2, sizeof(clip2) - 1, "-w %d", w);
 836         argv[n++] = clip2;
 837         snprintf(clip3, sizeof(clip3) - 1, "-h %d", h);
 838         argv[n++] = clip3;
 839         snprintf(clip4, sizeof(clip4) - 1, "-c %dx%d+%d+%d", sw, sh, sx, sy);
 840         argv[n++] = clip4;
 841         argv[n++] = url;
 842         if (getenv("TERM") && strcmp(getenv("TERM"), "screen") == 0 &&
 843             (!getenv("SCREEN_VARIANT") || strcmp(getenv("SCREEN_VARIANT"), "sixel") != 0)) {
 844 /*          argv[n++] = "-P"; */
 845                 snprintf(clip5, sizeof(clip5) - 1, "--penetrate");
 846                 argv[n++] = clip5;
 847         }
 848         argv[n++] = NULL;
 849         execvp(argv[0],argv);
 850         exit(0);
 851     }
...

$ HAVE_SYMLINK="" make

$ mv w3m w3msxl

Copy the w3msxl binary to the /mnt/onboard/.adds/kordir/scripts/ folder of your kobo.



# YAFT_PERCENT=58 yaft

# . /korenv.sh

# TERM=linux w3msxl -sixel -o display_image=1 mywgets/index.html

... and we have sixel image support in w3m in the /mnt/onboard partition (but pls recall security notice in POST #1).

(note that "w3msxl mywgets/index.html" would still work but default to w3imgfbink framebuffer viewer if you had set that up previously, except now can run as root in /mnt/onboard.)


*TO ACTIVATE BOOKMARKS:

# cd /usr/local/libexec/

# ln -s /mnt/onboard/.adds/kordir/usr/lib/w3m w3m


***
***
***
Attached Files
File Type: zip w3msixel.zip (1.63 MB, 124 views)

Last edited by elinkser; 10-28-2024 at 07:57 PM. Reason: cleaned up terms.c&w3msxl,need USB netorking for YAFT?
elinkser is offline   Reply With Quote
Old 08-04-2024, 06:56 PM   #20
elinkser
Addict
elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.
 
Posts: 222
Karma: 146236
Join Date: Oct 2022
Device: Kobo Clara HD
PONG ON SDL ON SIXEL ON YAFT ON KOBO CLARA

***

PONG ON SDL ON SIXEL ON YAFT ON KOBO CLARA

(You know we had to at least give it a shot.)


saitoha/SDL1.2-SIXEL
https://github.com/saitoha/SDL1.2-SIXEL

$ wget https://github.com/saitoha/SDL1.2-SI...eads/sixel.zip

$ unzip SDL1.2-SIXEL.zip

$ cd SDL1.2-SIXEL-sixel/


Prepare build system as was done in Post #4 above:

$ source ~/koxtoolchain/refs/x-compile.sh kobo env bare


$ ./configure --help

$ ./configure --disable-audio --disable-video-x11 --disable-video-fbcon --enable-video-sixel --host=arm-kobo-linux-gnueabihf

$ cp ../libsixel-1.8.6/include/sixel.h .

$ cp ../libsixel-1.8.6/src/.libs/libsixel.a .

$ cp ../libsixel-1.8.6/src/.libs/libsixel.so.1.0.6 libsixel.so.1

$ nano -l Makefile
Code:
...
 25 EXTRA_CFLAGS = -I. -I./include -D_GNU_SOURCE=1 -fvisibility=hidden -D_REENTRANT -DHAVE_LINUX_VERSION_H -Wall -mword-relocation
...
 27 EXTRA_LDFLAGS =  -lm -ldl -lpthread -L. -lsixel
...
 36 SOURCES =  ./src/*.c ./src/audio/*.c ./src/cdrom/*.c ./src/cpuinfo/*.c ./src/events/*.c ./src/file/*.c ./src/stdlib/*.c ./src/thread/*.c ./src/timer/*.c ./src/video/*.c ./src/joystick/*.c ./src/video/dummy/*.c ./src/loadso/dlopen/*.c ./src/video/sixel/*.c ./src/thread/pthread/SDL_systhread.c ./src/thread/pthread/SDL_syssem.c ./src/thread/pthread/SDL_sysmutex.c ./src/thread/pthread/SDL_syscond.c ./src/joystick/linux/*.c ./src/cdrom/linux/*.c ./src/timer/unix/*.c      
...
 37 OBJECTS = $(objects)/SDL.lo $(objects)/SDL_error.lo $(objects)/SDL_fatal.lo $(objects)/SDL_audio.lo $(objects)/SDL_audiocvt.lo $(objects)/SDL_audiodev.lo $(objects)/SDL_mixer.lo $(objects)/SDL_mixer_MMX.lo $(objects)/SDL_mixer_MMX_VC.lo $(objects)/SDL_mixer_m68k.lo $(objects)/SDL_wave.lo $(objects)/SDL_cdrom.lo $(objects)/SDL_cpuinfo.lo $(objects)/SDL_active.lo $(objects)/SDL_events.lo $(objects)/SDL_expose.lo $(objects)/SDL_keyboard.lo $(objects)/SDL_mouse.lo $(objects)/SDL_quit.lo $(objects)/SDL_resize.lo $(objects)/SDL_rwops.lo $(objects)/SDL_getenv.lo $(objects)/SDL_iconv.lo $(objects)/SDL_malloc.lo $(objects)/SDL_qsort.lo $(objects)/SDL_stdlib.lo $(objects)/SDL_string.lo $(objects)/SDL_thread.lo $(objects)/SDL_timer.lo $(objects)/SDL_RLEaccel.lo $(objects)/SDL_blit.lo $(objects)/SDL_blit_0.lo $(objects)/SDL_blit_1.lo $(objects)/SDL_blit_A.lo $(objects)/SDL_blit_N.lo $(objects)/SDL_bmp.lo $(objects)/SDL_cursor.lo $(objects)/SDL_gamma.lo $(objects)/SDL_pixels.lo $(objects)/SDL_stretch.lo $(objects)/SDL_surface.lo $(objects)/SDL_video.lo $(objects)/SDL_yuv.lo $(objects)/SDL_yuv_mmx.lo $(objects)/SDL_yuv_sw.lo $(objects)/SDL_joystick.lo $(objects)/SDL_nullevents.lo $(objects)/SDL_nullmouse.lo $(objects)/SDL_nullvideo.lo $(objects)/SDL_sysloadso.lo $(objects)/SDL_sixelevents.lo $(objects)/SDL_sixelvideo.lo $(objects)/SDL_systhread.lo $(objects)/SDL_syssem.lo $(objects)/SDL_sysmutex.lo $(objects)/SDL_syscond.lo $(objects)/SDL_sysjoystick.lo $(objects)/SDL_syscdrom.lo $(objects)/SDL_systimer.lo
...

$ nano -l build-deps
Code:
...
 982 $(objects)/SDL_sixelevents.lo: ./src/video/sixel/SDL_sixelevents.c \
 983         ./include/SDL.h \
 984         ./include/SDL_active.h \
 985         ./include/SDL_audio.h \
 986         ./include/SDL_cdrom.h \
 987         ./include/SDL_config.h \
 988         ./include/SDL_cpuinfo.h \
 989         ./include/SDL_endian.h \
 990         ./include/SDL_error.h \
 991         ./include/SDL_events.h \
 992         ./include/SDL_joystick.h \
 993         ./include/SDL_keyboard.h \
 994         ./include/SDL_keysym.h \
 995         ./include/SDL_loadso.h \
 996         ./include/SDL_main.h \
 997         ./include/SDL_mouse.h \
 998         ./include/SDL_mutex.h \
 999         ./include/SDL_opengl.h \
1000         ./include/SDL_platform.h \
1001         ./include/SDL_quit.h \
1002         ./include/SDL_rwops.h \
1003         ./include/SDL_stdinc.h \
1004         ./include/SDL_syswm.h \
1005         ./include/SDL_thread.h \
1006         ./include/SDL_timer.h \
1007         ./include/SDL_version.h \
1008         ./include/SDL_video.h \
1009         ./include/begin_code.h \
1010         ./include/close_code.h \
1011         ./src/events/../video/../video/SDL_sysvideo.h \
1012         ./src/events/SDL_events_c.h \
1013         ./src/video/sixel/SDL_sixelevents_c.h \
1014         ./src/video/sixel/SDL_sixelvideo.h \
1015
1016         $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c ./src/video/sixel/SDL_sixelevents.c  -o $@
1017
1018
1019 $(objects)/SDL_sixelvideo.lo: ./src/video/sixel/SDL_sixelvideo.c \
1020         ./include/SDL.h \
1021         ./include/SDL_active.h \
1022         ./include/SDL_audio.h \
1023         ./include/SDL_cdrom.h \
1024         ./include/SDL_config.h \
1025         ./include/SDL_cpuinfo.h \
1026         ./include/SDL_endian.h \
1027         ./include/SDL_error.h \
1028         ./include/SDL_events.h \
1029         ./include/SDL_joystick.h \
1030         ./include/SDL_keyboard.h \
1031         ./include/SDL_keysym.h \
1032         ./include/SDL_loadso.h \
1033         ./include/SDL_main.h \
1034         ./include/SDL_mouse.h \
1035         ./include/SDL_mutex.h \
1036         ./include/SDL_opengl.h \
1037         ./include/SDL_platform.h \
1038         ./include/SDL_quit.h \
1039         ./include/SDL_rwops.h \
1040         ./include/SDL_stdinc.h \
1041         ./include/SDL_syswm.h \
1042         ./include/SDL_thread.h \
1043         ./include/SDL_timer.h \
1044         ./include/SDL_version.h \
1045         ./include/SDL_video.h \
1046         ./include/begin_code.h \
1047         ./include/close_code.h \
1048         ./src/events/../video/../video/SDL_sysvideo.h \
1049         ./src/events/SDL_events_c.h \
1050         ./src/video/SDL_blit.h \
1051         ./src/video/SDL_pixels_c.h \
1052         ./src/video/sixel/SDL_sixelevents_c.h \
1053         ./src/video/sixel/SDL_sixelvideo.h \
1054
1055         $(LIBTOOL) --mode=compile $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c ./src/video/sixel/SDL_sixelvideo.c  -o $@
1056
...


$ nano -l include/SDL_config.h
Code:
...
260 #define SDL_VIDEO_DRIVER_SIXEL 1
...

...


$ nano -l src/video/SDL_video.c
Code:
...
 171 /* #ifdef DEBUG_VIDEO */
 172   fprintf(stderr,
 173         "SDL_video.c: SDL_VideoInit: Start\n");
 174 /* #endif */
 175
 176         /* Check to make sure we don't overwrite 'current_video' */
...
 198         } else {
 199                 for ( i=0; bootstrap[i]; ++i ) {
 200 /* #ifdef DEBUG_VIDEO */
 201   fprintf(stderr,
 202         "SDL_video.c: SDL_VideoInit: i=%d bootstrap[i]->available()= %d\n", i, bootstrap[i]->a$
 203 /* #endif */
 204                         if ( bootstrap[i]->available() ) {
...

$ make


OK, let's test it:


$ cd test/

$ mkdir include

$ cp ../../libsixel-1.8.6/include/sixel.h include/

$ mkdir include/SDL

$ cp ../include/*.h include/SDL/


$ mkdir lib

$ cp ../../libsixel-1.8.6/src/.libs/libsixel.a lib/

$ cp ../../libsixel-1.8.6/src/.libs/libsixel.so.1.0.6 lib/libsixel.so.1

$ cp ../build/.libs/libSDL.a lib/

$ cp ../build/.libs/libSDL-1.2.so.0.11.4 lib/libSDL.so
$ cp ../build/.libs/libSDL-1.2.so.0.11.4 lib/libSDL-1.2.so.0


$ arm-kobo-linux-gnueabihf-gcc -o testplatform testplatform.c -Iinclude -Iinclude/SDL -Llib -lSDL

$ arm-kobo-linux-gnueabihf-gcc -o testvidinfo testvidinfo.c -Iinclude -Iinclude/SDL -Llib -lSDL

$ arm-kobo-linux-gnueabihf-gcc -o testwm testwm.c -Iinclude -Iinclude/SDL -Llib -lSDL

$ arm-kobo-linux-gnueabihf-gcc -o testsprite testsprite.c -Iinclude -Iinclude/SDL -Llib -lSDL -lm

$ arm-kobo-linux-gnueabihf-gcc -o testfile testfile.c -Iinclude -Iinclude/SDL -Llib -lSDL -lpthread


Now, copy the following binaries and image to the /mnt/onboard/.adds/kordir/ folder on the Kobo:
testplatform
testvidinfo
testwm
testsprite
icon.bmp


Copy the libsixel.a, libsixel.so.1, libSDL.a, and libSDL-1.2.so.0 libs to the /mnt/onboard/.adds/kordir/libs/ folder of your kobo.

# YAFT_PERCENT=58 yaft

# . /korenv.sh

From a YAFT terminal:

# . /korenv.sh

# ./testplatform
This system is running Linux
All data types are the expected size.
Detected a little endian machine.
Value 16 = 0xCDAB, swapped = 0xABCD
Value 32 = 0xEFBEADDE, swapped = 0xDEADBEEF
Value 64 = 0xEFBEADDECDAB3412, swapped = 0x1234ABCDDEADBEEF
RDTSC not detected
MMX not detected
MMX Ext not detected
3DNow not detected
3DNow Ext not detected
SSE not detected
SSE2 not detected
AltiVec not detected

# ./testvidinfo
driver: sixel
Current display: 0x0, 24 bits-per-pixel
Red Mask = 0x00ff0000
Green Mask = 0x0000ff00
Blue Mask = 0x000000ff
Fullscreen video modes:
1024x768x24
800x600x24
640x480x24
320x400x24
320x240x24
320x200x24

# ./testwm
(Try hitting UP, DOWN, RIGHT, LEFT, ESC RET keys to exit.)
Key pressed: 273-up modifiers: (none)
Key released: 273-up modifiers: (none)
Key pressed: 274-down modifiers: (none)
Key released: 274-down modifiers: (none)
Key pressed: 275-right modifiers: (none)
Key released: 275-right modifiers: (none)
Key pressed: 276-left modifiers: (none)
Key released: 276-left modifiers: (none)
Key pressed: 27-escape modifiers: (none)
Posting internal quit request
Key released: 27-escape modifiers: (none)
Key pressed: 13-return modifiers: (none)
Key released: 13-return modifiers: (none)
Handling internal quit request
Bye bye..

# ./testsprite
(See the pretty sprites.)



***


Now, back on the desktop, we add more SDL libraries:

https://www.libsdl.org/projects/

$ wget https://www.libsdl.org/projects/SDL_...-1.2.12.tar.gz

$ wget https://downloads.sourceforge.net/pr...tf-1.4-src.zip

$ wget https://www.libsdl.org/projects/SDL_...f-1.2.2.tar.gz

$ wget https://www.libsdl.org/projects/SDL_...t-1.2.8.tar.gz

$ wget https://www.libsdl.org/projects/SDL_...-1.2.12.tar.gz




Prepare build system as was done in Post #4 above:

$ source ~/koxtoolchain/refs/x-compile.sh kobo env bare


$ tar zxvf SDL_image-1.2.12.tar.gz

$ cd SDL_image-1.2.12/


(Use a similar dependency setup, relying on the koreader crosscompile libs and headers in $HOME/x-tools/ folder, as for imlib2 in POST #18 above.)

$ ./configure --host=arm-kobo-linux-gnueabihf CPPFLAGS=" -I$HOME/x-tools/usr/include/ -I$HOME/websw/giflib-5.2.2/ " LDFLAGS=" -L$HOME/x-tools/usr/lib/ -L$HOME/websw/giflib-5.2.2/ -lgif -ljpeg -lz " LIBPNG_CFLAGS=" -I$HOME/x-tools/usr/include/ " LIBPNG_LIBS=" -L$HOME/x-tools/usr/lib/ -lpng " SDL_CFLAGS=" -I../SDL1.2-SIXEL-sixel/include/ " SDL_LIBS=" -L../SDL1.2-SIXEL-sixel/build/.libs/ -lSDL "

$ make

Copy the showimage binary from the .libs/ folder to the /mnt/onboard/.adds/kordir/scripts/ folder on the Kobo:

$ cd ..


***

$ mkdir libttf

$ cd libttf/

$ unzip libttf-1.4-src.zip

$ cd src/

$ chmod 755 configure

$ nano -l configure
Code:
...
3701 ac_cv_sizeof_int=4
3702 echo $ac_n "checking size of int""... $ac_c" 1>&6
...
3740 ac_cv_sizeof_long=4
3741 echo $ac_n "checking size of long""... $ac_c" 1>&6
...

$ CC=arm-kobo-linux-gnueabihf-gcc ./configure --host=arm-kobo-linux-gnueabihf

$ make

$ cd ..

$ cd ..


***

$ tar zxvf SDL_ttf-1.2.2.tar.gz

$ cd SDL_ttf-1.2.2/

$ CC=arm-kobo-linux-gnueabihf-gcc ./configure --host=arm-kobo-linux-gnueabihf


$ nano -l configure
Code:
...
2139   if test "$SDL_CONFIG" = "no" ; then
2140 #    no_sdl=yes
2141 #  else
2142     SDL_CFLAGS="$SDL_CFLAGS"
2143     SDL_LIBS="$SDL_LIBS"
...

$ CC=arm-kobo-linux-gnueabihf-gcc CFLAGS=" -I$HOME/x-tools/usr/include/ -I../libttf/src/lib/ " LIBS=" -L$HOME/x-tools/usr/lib/ -L../libttf/src/lib/.libs/ -lttf " SDL_CFLAGS=" -I../SDL1.2-SIXEL-sixel/include/ " SDL_LIBS=" -L../SDL1.2-SIXEL-sixel/build/.libs/ -lSDL " ./configure --host=arm-kobo-linux-gnueabihf


$ nano -l SDL_ttf.c
Code:
...
  21 /*static int round(float x)
...
  33 }*/
...
$ make

Copy the showfont binary from the .libs/ folder to the /mnt/onboard/.adds/kordir/scripts/ folder on the Kobo:

$ cd ..


***

$ tar zxvf SDL_net-1.2.8.tar.gz

$ cd SDL_net-1.2.8/

$ ./configure --host=arm-kobo-linux-gnueabihf SDL_CFLAGS=" -I../SDL1.2-SIXEL-sixel/include/ " SDL_LIBS=" -L../SDL1.2-SIXEL-sixel/build/.libs/ -lSDL "

$ make


Copy the showinterfaces binary from the .libs/ folder to the /mnt/onboard/.adds/kordir/scripts/ folder on the Kobo:

$ cd ..

***


$ tar zxvf SDL_mixer-1.2.12.tar.gz

$ cd SDL_mixer-1.2.12/

$ ./configure --host=arm-kobo-linux-gnueabihf SDL_CFLAGS=" -I../SDL1.2-SIXEL-sixel/include/ " SDL_LIBS=" -L../SDL1.2-SIXEL-sixel/build/.libs/ -lSDL "

$ make


$ cd ..


***

Here is a PONG game to try out our SDL:

nathan242/SDL-pong
https://github.com/nathan242/sdl-pong


$ cd ..

$ wget https://github.com/nathan242/SDL-pon...ads/master.zip

$ mv master.zip SDL-pong-master.zip

$ unzip SDL-pong-master.zip

$ cd SDL-pong-master/

$ source ~/koxtoolchain/refs/x-compile.sh kobo env bare


$ mkdir include

(Use headers as for imlib2 in POST #18 above.)

$ cp ~/websw/giflib-5.2.2/gif*.h include/

$ cp ~/x-tools/usr/include/png*.h include/

$ cp ~/x-tools/usr/include/j*.h include/

$ cp ~/x-tools/usr/include/z*.h include/


$ cp ../libsixel-1.8.6/include/sixel.h include/

$ mkdir include/SDL

$ cp ../SDL1.2-SIXEL-sixel/include/*.h include/SDL/

$ cp ../SDL_image-1.2.12/SDL_image.h include/SDL/

$ cp ../SDL_ttf-1.2.2/SDL_ttf.h include/SDL/

$ cp ../SDL_net-1.2.8/*.h include/SDL/

$ cp ../SDL_mixer-1.2.12/*.h include/SDL/


$ mkdir lib

(Use libs as for imlib2 in POST #18 above.)

$ cp ~/websw/giflib-5.2.2/libgif.so lib/

$ cp ~/x-tools/usr/lib/libpng16.so.16 lib/libpng16.so

$ cp ~/x-tools/usr/lib/libjpeg.so.62 lib/libjpeg.so

$ cp ~/x-tools/usr/lib/libz.so.1 lib/libz.so


$ cp ../libsixel-1.8.6/src/.libs/libsixel.a lib/

$ cp ../libsixel-1.8.6/src/.libs/libsixel.so.1.0.6 lib/libsixel.so.1

$ cp ../SDL1.2-SIXEL-sixel/build/.libs/libSDL.a lib/

$ cp ../SDL1.2-SIXEL-sixel/build/.libs/libSDL-1.2.so.0.11.4 lib/libSDL.so
$ cp ../SDL1.2-SIXEL-sixel/build/.libs/libSDL-1.2.so.0.11.4 lib/libSDL-1.2.so.0

$ cp ../SDL_image-1.2.12/.libs/libSDL_image.a lib/

$ cp ../SDL_image-1.2.12/.libs/libSDL_image-1.2.so.0.8.4 lib/libSDL_image.so

$ cp ../SDL_image-1.2.12/.libs/libSDL_image-1.2.so.0.8.4 lib/libSDL_image-1.2.so.0


The following are optional, for possible future use:

$ cp ../libttf/src/lib/.libs/libttf.so.2.3.0 lib/libttf.so

$ cp ../libttf/src/lib/.libs/libttf.so.2.3.0 lib/libttf.so.2

$ cp ../SDL_ttf-1.2.2/.libs/libSDL_ttf.a lib/

$ cp ../SDL_ttf-1.2.2/.libs/libSDL_ttf-1.2.so.0.2.0 lib/libSDL_ttf.so

$ cp ../SDL_ttf-1.2.2/.libs/libSDL_ttf-1.2.so.0.2.0 lib/libSDL_ttf-1.2.so.0

$ cp ../SDL_net-1.2.8/.libs/libSDL_net.a lib/

$ cp ../SDL_net-1.2.8/.libs/libSDL_net-1.2.so.0.8.0 lib/libSDL_net.so

$ cp ../SDL_net-1.2.8/.libs/libSDL_net-1.2.so.0.8.0 lib/libSDL_net-1.2.so.0

$ cp ../SDL_mixer-1.2.12/build/.libs/libSDL_mixer.a lib/

$ cp ../SDL_mixer-1.2.12/build/.libs/libSDL_mixer-1.2.so.0.12.0 lib/libSDL_mixer.so

$ cp ../SDL_mixer-1.2.12/build/.libs/libSDL_mixer-1.2.so.0.12.0 lib/libSDL_mixer-1.2.so.0


Now compile PONG:

$ nano -l makefile
Code:
 1 CXX = arm-kobo-linux-gnueabihf-g++
 2
 3 pong: pong.o physics.o
 4         $(CXX) -o pong -Llib -lgif -ljpeg -lz -lSDL -lSDL_image pong.o physics.o
 5
 6 pong.o: pong.cpp
 7         $(CXX)  -g -Iinclude -c pong.cpp
 8
 9 physics.o: physics.cpp physics.h
10         $(CXX) -g -c physics.cpp

$ nano -l pong.cpp
Code:
...
  5 #define CLARA_UP                273
  6 #define CLARA_DOWN              274     
  7 #define CLARA_RIGHT             275
  8 #define CLARA_LEFT              276     
  9 #define CLARA_XSTEP             30
...
 44             if (obj->step_y > 0) { obj->step_y = 1 * CLARA_XSTEP; } else { obj->step_y = -1 * CLARA_XSTEP; }
 45         } else if (obj->pos_x+obj->size_x >= area_x) {
 46             scoreplayer1++;
 47             obj->pos_x = 300;
 48             obj->pos_y = 100;
 49             if (obj->step_y > 0) { obj->step_y = 1 * CLARA_XSTEP; } else { obj->step_y = -1 * CLARA_XSTEP; }
...
 61                 obj->step_y = -2 * CLARA_XSTEP;
 62             } else if (obj->pos_y <= y2) {
 63                 if (obj->step_y > 0) { obj->step_y = 1 * CLARA_XSTEP; } else { obj->step_y = -1 * CLARA_XSTEP; }
 64             } else if (obj->pos_y <= y3) {
 65                 obj->step_y = 2 * CLARA_XSTEP;
...
 75     // Constant variables
 76     const int resX = 800;
 77     const int resY = 600;
...
188     // Right paddle
189     paddle_right->sprite = SDL_DisplayFormat(IMG_Load("paddle.png"));
190     paddle_right->phys = new phys_obj;
191     paddle_right->phys->pos_x = 730;
192     paddle_right->phys->pos_y = 350;
...
206     // Ball
207     ball->sprite = SDL_DisplayFormat(IMG_Load("ball.png"));
208     ball->phys = new phys_obj;
209     ball->phys->pos_x = 300;
210     ball->phys->pos_y = 100;
211     ball->phys->size_x = 20;
212     ball->phys->size_y = 20;
213     ball->phys->step_x = 1 * CLARA_XSTEP;
214     ball->phys->step_y = 1 * CLARA_XSTEP;
...
245             while (quit==false) {
246                 // SDL_Delay(20);
...
283         // Read inputs
284         while (SDL_PollEvent(&input))
285         {
286             switch (input.type)
287             {
288                 case SDL_KEYDOWN:
289                     switch (input.key.keysym.sym)
290                         {
291                             case CLARA_UP:
292                                 down = false;
293                                 up = true;
294                                 break;
295                             case CLARA_DOWN:
296                                 up = false;
297                                 down = true;
298                                 break;
299                             case SDLK_b:
300                                 down = false;
301                                 up = true;
302                                 break;
303                             case SDLK_SPACE:
304                                 up = false;
305                                 down = true;
306                                 break;
307                             case SDLK_q:
308                                 quit = true;
309                                 break;
310                         }
311                         break;
312                 case SDL_KEYUP:
313                     switch (input.key.keysym.sym)
314                         {
315                             case CLARA_RIGHT:
316                                 up = false;
317                                 down = false;
318                                 break;
319                             case CLARA_LEFT:
320                                 up = false;
321                                 down = false;
322                                 break;
323                             case SDLK_n:
324                                 up = false;
325                                 down = false;
326                                 break;
327                             case SDLK_v:
328                                 up = false;
329                                 down = false;
330                                 break;
331                         }
...
335         // Move left paddle
336         paddle_left->phys->step_y = 0;
337         if (up) { paddle_left->phys->step_y = -1 * CLARA_XSTEP; }
338         if (down) { paddle_left->phys->step_y = 1 * CLARA_XSTEP; }
339
340         // Move right paddle
341         if (ball->phys->pos_y > paddle_right->phys->pos_y+paddle_mid) {
342             paddle_right->phys->step_y = 1 * CLARA_XSTEP;
343         } else {
344             paddle_right->phys->step_y = -1 * CLARA_XSTEP;
345         }
...
359         // Second number
360         offset.x = 550;
361         offset.y = 0;
362         SDL_BlitSurface(numbers, &num[scoreplayer2], screen, &offset );
...
379         // Flip screen
380         SDL_Flip(screen);
381         // SDL_Delay(20);
...
$ rm *.o

$ rm pong

$ make


Copy the libsixel.a, libsixel.so.1, libSDL.a, libSDL-1.2.so.0, libSDL_image.a, and libSDL_image-1.2.so.0 libs to the /mnt/onboard/.adds/kordir/libs/ folder of your kobo.

Also copy the following libs for possible future use:
libSDL_mixer.so
libttf.so.2
libSDL_ttf.a
libSDL_ttf-1.2.so.0
libSDL_net.a
libSDL_net-1.2.so.0
libSDL_mixer.a
libSDL_mixer-1.2.so.0


Copy the pong binary and ball.png, numbers.png, paddle.png, p1win.png, and p2win.png images to the /mnt/onboard/.adds/kordir/ folder on the Kobo:

# . /korenv.sh

# YAFT_PERCENT=58 yaft

# . /korenv.sh

From a YAFT terminal:

# showimage tux.jpg

# ./pong


As you can see, it is kind of slow despite the changes I made to pong.cpp.

Anyway, that is PONG on Kobo Clara HD.


***

RUN PONG ON DESKTOP IN KOBO SSH TERMINAL
(SECURITY WARNING: DO NOT SSH TO CRITICAL DESKTOP FROM INSECURE SSH CLIENT, E.G. KOBO)



Create ssh firewall rule on desktop:

$ sudo ufw allow proto tcp from 192.168.2.2 to 192.168.2.1 port 22
Rule added

$ sudo ufw reload

$ sudo ufw status numbered


Install and run sshd server:

$ sudo apk add openssh-server
$ sudo ssh-keygen -A
$ sudo /usr/sbin/sshd
$ ps ax | grep sshd
3093 ? Ss 0:00 /usr/sbin/sshd
19580 pts/3 S+ 0:00 grep sshd

$ netstat -tulpn



Get an ssh client for kobo:

https://pkgs.alpinelinux.org/package...7/dropbear-ssh
The dropbear-ssh client has only the following dependencies:
Depends (1)
dropbear-dbclient
Depends (2)
musl*
zlib*
*already got these from elinks install.


Download and extract the required packages:

$ wget https://dl-cdn.alpinelinux.org/alpin...2022.83-r1.apk

$ wget https://dl-cdn.alpinelinux.org/alpin...2022.83-r1.apk


$ cd myalpine/

$ tar zxvf dropbear-dbclient-2022.83-r1.apk

$ mv usr/bin/dbclient scripts/ssh



NOW CONNECT YOUR KOBO TO YOUR PC:

Copy your ssh binary from the scripts/ folder on the PC to the /mnt/onboard/.adds/kordir/scripts/ folder on the kobo.


On your kobo, connect to your (now insecure) desktop:

# . /korenv.sh

# ssh kobo@192.168.2.1


$ cat tux.six


$ cd

$ cd SDL1.2-SIXEL-sixel/test/

$ ./testsprite
1010 frames per second on desktop becomes 62 on Kobo over SSH connection(compared to 4.44 natively on Kobo)

$ cd

$ cd SDL-pong-master/

$ ./pong
(have to fix the keydefs)

RUNS AT "DESKTOP SPEED" (4.7 seconds paddle to paddle on original source code over SSH, admittedly with ghosting, compared to 2 seconds on desktop)!

$ exit



***
***
***
Attached Files
File Type: zip SDLpong-build.zip (4.86 MB, 142 views)

Last edited by elinkser; 08-10-2024 at 09:09 AM. Reason: add insecure remote gaming section,framerate
elinkser is offline   Reply With Quote
Old 09-10-2024, 11:44 AM   #21
elinkser
Addict
elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.
 
Posts: 222
Karma: 146236
Join Date: Oct 2022
Device: Kobo Clara HD
A FEW UTILITIES FOR FBPDF ON YOUR KOBO

A FEW UTILITIES FOR FBPDF ON YOUR KOBO

***
***
***


grunfink/html2epub
https://codeberg.org/grunfink/html2epub

$ git clone https://codeberg.org/grunfink/html2epub.git


html2epub is a simple shell script to convert html pages to epub, so it can be used without having to crosscompile for the Kobo.

However, it requires the paste(from the coreutils package) and zip utility programs, which we can acquire from Alpine Linux:


***

coreutils
The basic file, shell and text manipulation utilities
Depends (5)
busybox-binsh**
libacl
libattr
musl*
utmps-libs**


zip
Creates PKZIP-compatible .zip files
Depends (2)
musl*
unzip***

*already got these from elinks and nano installs in Post #3 above.
**already got this from screen install in Post #12 above.
***already got this from base busybox.

* note: Alpine Linux files were migrated from the /mnt/onboard/.adds/koreader/ folder to the /mnt/onboard/.adds/kordir/ folder since Post #14.


DOWNLOAD THE REQUIRED PACKAGES:

$ wget https://dl-cdn.alpinelinux.org/alpin...ils-9.1-r0.apk
$ wget https://dl-cdn.alpinelinux.org/alpin...l-2.3.1-r1.apk
$ wget https://dl-cdn.alpinelinux.org/alpin...r-2.5.1-r2.apk


$ wget https://dl-cdn.alpinelinux.org/alpin...ip-3.0-r10.apk


RUN THESE COMMANDS FROM LINUX DESKTOP:

$ cd myalpine/

$ tar zxvf coreutils-9.1-r0.apk
$ tar zxvf libacl-2.3.1-r1.apk
$ tar zxvf libattr-2.5.1-r2.apk

$ tar zxvf zip-3.0-r10.apk

$ cp usr/bin/coreutils scripts/paste
$ cp lib/libacl.so.1.1.2301 libs/libacl.so.1
$ cp lib/libattr.so.1.1.2501 libs/libattr.so.1

$ mv usr/bin/zip scripts/

NOW CONNECT YOUR KOBO TO YOUR PC:

Copy your paste/zip binaries from the scripts/ folder on the PC to the /mnt/onboard/.adds/kordir/scripts/ folder on the kobo.

Copy your libacl.so.1/libattr.so.1 libs from the libs/ folder on the PC to the /mnt/onboard/.adds/kordir/libs/ folder on the kobo.



Copy your html2epub shell script to the /mnt/onboard/.adds/kordir/scripts/ folder on the kobo.


From kobo terminal or ssh session to kobo:

# . /korenv.sh

# mkdir myhtml2epub

# cd myhtml2epub/

Here we download using the full wget binary we acquired from Alpine Linux (and renamed to 'wgets') in Post #3 above:

# wgets --restrict-file-names=windows -k -nd -D codeberg.org -E -r -A jpg,jpeg,png,gif,svg,htm,html -l1 -Q20M https://codeberg.org/grunfink/html2epub

-np, --no-parent don't ascend to the parent directory
-k, --convert-links make links in downloaded HTML or CSS point to local files
-nd, --no-directories don't create directories
-D, --domains=LIST comma-separated list of accepted domains
--exclude-domains=LIST comma-separated list of rejected domains
-E, --adjust-extension save HTML/CSS documents with proper extensions
-r, --recursive specify recursive download
-A, --accept=LIST comma-separated list of accepted extensions
-R, --reject=LIST comma-separated list of rejected extensions
-l, --level=NUMBER maximum recursion depth (inf or 0 for infinite)
-Q, --quota=NUMBER set retrieval quota to NUMBER

# ls
avatar_default.png favicon.svg index.html
favicon.png html2epub.tmp.html

# html2epub html2epub.epub -ntp html2epub.tmp.html
html2epub recommendation: install 'tidy' or 'tidyp'
Gathering data...
Building .epub file...
adding: mimetype (stored 0%)
adding: META-INF/ (stored 0%)
adding: META-INF/container.xml (deflated 34%)
adding: content.opf (deflated 50%)
adding: part-0001.html (deflated 74%)
adding: toc.ncx (deflated 46%)
Finished.

# fbpdf html2epub.epub
(space to page down, q to quit.)

The epub was created. Now let's try another wget variation:


# wgets --restrict-file-names=windows -nd -E -k -p -Q20M "https://www.google.com"

-nd, --no-directories don't create directories
-E, --adjust-extension save HTML/CSS documents with proper extensions
-k, --convert-links make links in downloaded HTML or CSS point to local files
-p, --page-requisites get all images, etc. needed to display HTML page
-Q, --quota=NUMBER set retrieval quota to NUMBER


# html2epub google.epub -ntp index.html.1.html
html2epub: recommendation: install 'tidy' or 'tidyp'
Gathering data...
Building .epub file...
adding: mimetype (stored 0%)
adding: META-INF/ (stored 0%)
adding: META-INF/container.xml (deflated 34%)
adding: content.opf (deflated 50%)
adding: part-0001.html (deflated 58%)
adding: toc.ncx (deflated 48%)
Finished.


# fbpdf google.epub

The page is there but no images! Let's try again:

# html2epub google.epub -ntp index.html.1.html *.png
html2epub: recommendation: install 'tidy' or 'tidyp'
Gathering data...
Building .epub file...
adding: mimetype (stored 0%)
adding: META-INF/ (stored 0%)
adding: META-INF/container.xml (deflated 34%)
adding: avatar_default.png (stored 0%)
adding: content.opf (deflated 50%)
adding: favicon.png (stored 0%)
adding: googlelogo_white_background_color_272x92dp.png (stored 0%)
adding: nav_logo229.png (deflated 0%)
adding: part-0001.html (deflated 58%)
adding: toc.ncx (deflated 48%)
Finished.

# fbpdf google.epub

Now the image is there.


***
***
***


gonejack/html-to-epub
https://github.com/gonejack/html-to-epub

$ wget https://github.com/gonejack/html-to-...v1.0.26.tar.gz

$ mv v1.0.26.tar.gz html-to-epub-v1.0.26.tar.gz


html-to-epub is a Golang binary to convert html pages to epub, so we have to crosscompile for the Kobo.

However, it is self-contained once statically compiled, and also has another benefit which you will see :


$ tar zxvf html-to-epub-v1.0.26.tar.gz

$ cd html-to-epub-1.0.26/

$ source $HOME/.profile

$ go version
go version go1.20.2 linux/amd64

BUILD FOR DESKTOP:

$ go build
go: downloading github.com/PuerkitoBio/goquery v1.7.1
go: downloading github.com/alecthomas/kong v0.2.17
go: downloading github.com/gabriel-vasile/mimetype v1.3.1
go: downloading github.com/gonejack/get v1.0.9
go: downloading github.com/andybalholm/cascadia v1.2.0
go: downloading golang.org/x/net v0.0.0-20210614182718-04defd469f4e
go: downloading github.com/dustin/go-humanize v1.0.0
go: downloading github.com/go-resty/resty/v2 v2.6.0
go: downloading golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
go: downloading github.com/gofrs/uuid v3.1.0+incompatible


$ mkdir myhtml-to-epub

$ cd myhtml-to-epub/


Here we download just the base html page for the Kobo Developer Forum, using the desktop wget command:

$ wget "https://www.mobileread.com/forums/forumdisplay.php?f=247"
Saving to: ‘forumdisplay.php?f=247’

$ ls
'forumdisplay.php?f=247'

$ ../html-to-epub forumdisplay.php\?f\=247

$ ls
'forumdisplay.php?f=247' images output.epub

With ebook-viewer from calibre, you can see the output.epub:
$ ebook-viewer output.epub

It looks like html-to-epub has gone and downloaded the images linked to by the ‘forumdisplay.php?f=247’ page, even though we did not fetch them with our wgets command.


BUILD FOR KOBO:

$ source ~/koxtoolchain/refs/x-compile.sh kobo env bare
( Prepare build as in https://www.mobileread.com/forums/sh...d.php?t=350054 Post #4, or you could try Linaro build as in Post #1.)

$ env GOOS=linux GOARCH=arm CC=arm-kobo-linux-gnueabihf-gcc CXX=arm-kobo-linux-gnueabihf-g++ go build
go: downloading github.com/PuerkitoBio/goquery v1.7.1
go: downloading github.com/alecthomas/kong v0.2.17
go: downloading github.com/gabriel-vasile/mimetype v1.3.1
go: downloading github.com/gonejack/get v1.0.9
go: downloading github.com/andybalholm/cascadia v1.2.0
go: downloading golang.org/x/net v0.0.0-20210614182718-04defd469f4e
go: downloading github.com/dustin/go-humanize v1.0.0
go: downloading github.com/go-resty/resty/v2 v2.6.0
go: downloading golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
go: downloading github.com/gofrs/uuid v3.1.0+incompatible


$ ls -l html-to-epub
-rwxr-xr-x 1 10881529 html-to-epub

$ file html-to-epub
html-to-epub: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, Go BuildID=_DHZTlkwz4xzPeiVUlaW/Sj0LAzd2dr0VlhzcEumV/nqh8YWiS3s137C5H_5Dy/OB662nwm1KaHmiJTMIeA, with debug_info, not stripped

Copy html-to-epub binary to /mnt/onboard/.adds/kordir/scripts/ folder of kobo.

From kobo terminal or ssh session to kobo:

# . /korenv.sh

# mkdir myhtml-to-epub

# cd myhtml-to-epub/

Here we download just the base html page for the Kobo Developer Forum, using the full wget binary we acquired from Alpine Linux in Post #3 above:

# wgets --restrict-file-names=windows "https://www.mobileread.com/forums/forumdisplay.php?f=247"
Saving to: 'forumdisplay.php@f=247'

# ls
forumdisplay.php@f=247

# html-to-epub -o kobodev.epub forumdisplay.php@f\=247

# ls
forumdisplay.php@f=247 images kobodev.epub


Confirm the images have been added to the epub:

# fbpdf kobodev.epub
(space to page down, q to quit.)

OK let's see if that means we can use the stripped-down busybox version of wget that already comes with the Kobo, removing the need to install the full Alpine Linux version:

# which wget
/usr/bin/wget
# ls -l /usr/bin/wget
lrwxrwxrwx root root /usr/bin/wget -> ../../bin/busybox

# wget "https://www.mobileread.com"
saving to 'index.html'

# html-to-epub -o mobileread.epub index.html

# ls
images index.html mobileread.epub

# fbpdf mobileread.epub

html-to-epub has downloaded the images linked to by the index.html page, even though we could not fetch them with the stripped-down busybox/wget command.

This means we can use the html-to-epub binary without the help of other than built-in commands, BUT the built-in wget still does not work with all sites, unfortunately.

* Oops, actually wget can handle it using the -O option:

# wget "https://www.mobileread.com/forums/forumdisplay.php?f=247"
Connecting to www.mobileread.com (162.55.243.172:443)
wget: can't open 'forumdisplay.php?f=247': Invalid argument

# wget -O index.html "https://www.mobileread.com/forums/forumdisplay.php?f=247"
Connecting to www.mobileread.com (162.55.243.172:443)
saving to 'index.html'
index.html 100% |************************************************* ***| 102k 0:00:00 ETA
'index.html' saved

***
***
***


I have used Koreader to read huge 100MB 1000-page files, but even it couldn't handle a 45MB 576-page pdf file of scanned images. Even the sparse fbpdf reader from Post #16 could barely handle it, but with an intolerable minute delay between page turns.

The mutool utility is included in the attached files fbpdf-build.zip of Post #16 above, and we can use it to split up the pdf file:

# mkdir workdir

# cd workdir/

# mutool draw -L -c gray -o out%d.png big.pdf 1-50

# mutool convert -O compress -o out.pdf out*.png

# ls -l *.pdf
-rwxr-xr-x 47245268 big.pdf
-rwxr-xr-x 8076822 out.pdf

Now we have created a grayscale out.pdf which contains just pages 1-50 of big.pdf.
It took about 15 seconds per page to convert.

Reading in Koreader in reflow mode (with contrast level cranked up a notch) is now acceptable.



***


UPDATE:

So I did the same operation on my (MXLinux-converted) chromebook, except I tried generating half the book at a time (takes about 10 minutes), then tried generating the whole book.
Interestingly, even the whole book is now digestible by Koreader, even though the file size is double.

$ mutool draw -L -c gray -o out%03d.png big.pdf 1-288
$ mutool convert -O compress -o out1-288.pdf out*.png

$ mutool draw -L -c gray -o out%03d.png big.pdf 1-552
$ mutool convert -O compress -o out1-552.pdf out*.png

Remove out002.png to out287.png

$ mutool convert -O compress -o out288-552.pdf out*.png

$ rm *.png

$ ls -l *.pdf
-rwxr-xr-x 47245268 big.pdf
-rwxr-xr-x 8076822 out.pdf
-rwxr-xr-x 49088131 out1-288.pdf
-rwxr-xr-x 95610303 out1-552.pdf
-rwxr-xr-x 47191462 out288-552.pdf


* note: I also changed the %d parameter to %03d to generate sequential file names.

** note: I also tried the qpdf utility as follows:
$ qpdf big.pdf --pages . 1-50 -- out.pdf
and
$ qpdf big.pdf --split-pages=50 -- out.pdf
Result:
conversion was super-quick - only a couple of seconds - but the resulting file was much slower to load and for page turns.


***
***
***




Wget should also be useful for things like sites that require a subscription, although I haven't tried.

This page explains how you might attempt it:
https://stackoverflow.com/questions/...page-with-wget


An example of a useful technique is:
Use "Copy as cURL" in the Network tab of Firefox's browser developer tools and replace curl's flag -H with wget's --header (and also --data with --post-data if needed).

So trying this on the page you get from a login attempt at https://www.mobileread.com/forums/fo...play.php?f=247 yields:

curl 'https://www.mobileread.com/forums/login.php?do=login' -X POST -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) Gecko Firefox' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' -H 'Accept-Language: en-US,en;q=0.5' -H 'Accept-Encoding: gzip, deflate, br' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Origin: https://www.mobileread.com' -H 'Connection: keep-alive' -H 'Referer: https://www.mobileread.com/forums/fo...play.php?f=247' -H 'Cookie: bblastvisit=...' -H 'Upgrade-Insecure-Requests: 1' -H 'Sec-Fetch-Dest: document' -H 'Sec-Fetch-Mode: navigate' -H 'Sec-Fetch-Site: same-origin' -H 'Sec-Fetch-User: ?1' --data-raw 'vb_login_username=myname&vb_login_password=&s=&se curitytoken=guest&do=login&vb_login_md5password=.. .'
(truncated-for illustrative purposes only)


Another example would be getting a token from a "Wallabag-like" server.
You could do this with curl:

$ curl -X POST 'http://127.0.0.1:8081/oauth/v2/token' --data 'client_id=myid&client_secret=mysecret' -H 'Content-Type:application/x-www-form-urlencoded'
{
"access_token": "",
"expires_in": 3600,
"refresh_token": "",
"scope": null,
"token_type": "bearer"
}


Or the same thing with wget:

$ wget 'http://127.0.0.1:8081/oauth/v2/token' --post-data 'client_id=myid&client_secret=mysecret' --header 'Content-Type:application/x-www-form-urlencoded'
Connecting to 127.0.0.1:8081... connected.
HTTP request sent, awaiting response... 200 OK
Length: 122 [application/json]
Saving to: ‘token’
token 100%[==================================>] 122 --.-KB/s in 0s
‘token’ saved [122/122]

$ cat token
{
"access_token": "",
"expires_in": 3600,
"refresh_token": "",
"scope": null,
"token_type": "bearer"
}


These may not work with the stripped-down busybox version of wget that already comes with the Kobo, so you may need to install the full Alpine Linux version, as in Post #3.

***
***
***


USE KOREADER AS "BROWSER":

Although Koreader on Kobo doesn't open external links at present (as it does on Android), we can kludge it to enable it.

In a Kobo terminal or SSH/Telnet to Kobo:

# . /korenv.sh

# cd /mnt/onboard/.adds/koreader/

# cd frontend/apps/reader/modules/

# cp readerlink.lua readerlink.lua.bak

Open the readerlink.lua file in nano or vi:

# nano -l readerlink.lua
Code:
...
 138     -- Set up buttons for alternative external link handling methods
 139     self._external_link_buttons = {}
 140     self._external_link_buttons["10_copy"] = function(this, link_url)
 141         return {
 142             text = _("Copy"),
 143             callback = function()
 144                 UIManager:close(this.external_link_dialog)
 145             end,
 146         }
 147     end
...

Compare that code to that of readerhighlight.lua:

# nano -l readerhighlight.lua
Code:
...
  81         ["03_copy"] = function(this)
  82             return {
  83                 text = C_("Text", "Copy"),
  84                 enabled = Device:hasClipboard(),
  85                 callback = function()
  86                     Device.input.setClipboardText(cleanupSelectedText(this.selected_text.text))
  87                     this:onClose()
  88                     UIManager:show(Notification:new{
  89                         text = _("Selection copied to clipboard."),
  90                     })
  91                 end,
  92             }
  93         end,
...


Try modifying the readerlink.lua copy function to look like the readerhighlight.lua copy function:

*** BACKUP ANY FILES BEFORE MODIFYING. IF YOUR FILES DON'T LOOK LIKE THE ABOVE, THIS KLUDGE IS NOT FOR YOU ***


# nano -l readerlink.lua
Code:
 ...
 138     -- Set up buttons for alternative external link handling methods
 139     self._external_link_buttons = {}
 140     self._external_link_buttons["10_copy"] = function(this, link_url)
 141         return {
 142             text = _("Copy"),
 143                         enabled = Device:hasClipboard(),
 144                         callback = function()
 145                                 Device.input.setClipboardText(link_url)
 146                                 UIManager:close(this.external_link_dialog)
 147                                 UIManager:show(Notification:new{
 148                                         text = _("Url copied to clipboard."),
 149                 })
 150             end,
 151         }
 152     end
...


Now the external links copy function should work:

1) In Koreader, open an epub/html file that has external links in it
2) Tap on the external link. The "External link:" dialog should open as usual.
3) Select "Copy"
4) Turn on WiFi. (e.g. I have set spread/pinch gesture for this in Koreader.)
5) Open a terminal. (e.g. I have set two-finger diagonal swipe gesture for this in Koreader.)
6) Type elinks (or wget or whatever command you want.)
7) Tap and hold. The "Clipboard dialog" should open as usual.
8) Select "Paste".
9) Confirm that the pasted URL doesn't contain "rm *" or other such nasties, then press return.
10) You are now browsing the external link!
"q" to quit elinks, "X" to close terminal, and you are right back in your original document in Koreader.


So basically it's tap link, Select "Copy", swipe for terminal, type "elinks/wget", tap screen, select "Paste", and hit return to browse/fetch.

***
***
***


How about browsing without leaving Koreader?

For this we copy the wget111s binary we crosscompiled in Post #1 to the /mnt/onboard/.adds/ folder.
Unfortunately we cannot use the built-in wget command because it leaves many links as relative, and we would not be able to browse by clicking on links of an epub we create with wget.

We also copy the html-to-epub binary we crosscompiled above to the /mnt/onboard/.adds/ folder.

Try modifying the readerlink.lua menu function to add a "add epub" item:

# nano -l readerlink.lua
Code:
...
 153     self._external_link_buttons["15_add_epub"] = function(this, link_url)
 154         return {
 155             text = _("Add epub"),
 156                         callback = function()
 157                                 if not util.pathExists("/mnt/onboard/.adds/ae/") then
 158                                         os.execute("mkdir /mnt/onboard/.adds/ae")
 159                                 end
 160                                 os.execute("rm -r /mnt/onboard/.adds/ae/images/ ")
 161                                 local datetime = os.date("%Y%m%d-%H%M%S")
 162                                 os.execute("/mnt/onboard/.adds/wget111s --ca-certificate=/mnt/onboard/.adds/koreader/data/ca-bundle.crt -k -O /mnt/onboard/.adds/ae/index.html "..'"'..link_url..'"')
 163                                 os.execute("cd /mnt/onboard/.adds/ae && /mnt/onboard/.adds/html-to-epub -o /mnt/onboard/.adds/ae/"..datetime..".epub /mnt/onboard/.adds/ae/index.html")
 164     --                          os.execute("rm /mnt/onboard/.adds/ae/index.html")
 165                                 UIManager:close(this.external_link_dialog)
 166                                 UIManager:show(Notification:new{
 167                                         text = _("Added epub to /mnt/onboard/.adds/ae/ folder"),
 168                 })
 169             end,
 170         }
 171     end
...

Now create an initial html file, index2.html, that we can open in Koreader:

# mkdir mnt/onboard/.adds/ae

# /mnt/onboard/.adds/wget111s --ca-certificate=/mnt/onboard/.adds/koreader/data/ca-bundle.crt -k -O /mnt/onboard/.adds/ae/index2.html "https://www.mobileread.com/forums/forumdisplay.php?f=247"

In Koreader file browser, open, the index2.html file.

1) Click on an external link and select "Add epub".

2) Go back to filemanager and open the epub.


* Instead of crosscompiling wget, you can use the wget binary you got from Alpine Linux (initially installed to /mnt/onboard/.adds/koreader in Post #3, then migrated to /mnt/onboard/.adds/kordir in Post #14).
Just change line 162 as follows:
# nano -l readerlink.lua
Code:
 162                                 os.execute("LD_LIBRARY_PATH=/mnt/onboard/.adds/kordir/libs /mnt/onboard/.adds/kordir/scripts/wgets --ca-certificate=/mnt/onboard/.adds/koreader/data/ca-bundle.crt -k -O /mnt/onboard/.adds/ae/index.html
Similarly, you have to grab the initial index2.html file with:
# LD_LIBRARY_PATH=/mnt/onboard/.adds/kordir/libs /mnt/onboard/.adds/kordir/scripts/wgets --ca-certificate=/mnt/onboard/.adds/koreader/data/ca-bundle.crt -k -O /mnt/onboard/.adds/ae/index2.html "https://www.mobileread.com/forums/forumdisplay.php?f=247"

** You can rewrite the above code to use the built-in wget, but you won't be able to follow links past the first page.

*** For searches, a searches.html file could be kept in the ae/ folder:
Code:
<html>
<body>
<ul>
<li><a href='http://www.nosysearchengine.com/search?q="mobileread"+forum+kobo+developer'>Edit search terms</a>
</ul>
</body>
</html>

***
***
***
Attached Files
File Type: zip utils.zip (5.79 MB, 48 views)

Last edited by elinkser; 09-17-2024 at 03:21 PM. Reason: notes/update,koreader links,160-164,searches
elinkser is offline   Reply With Quote
Reply


Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
PW4 Terminal or SSH through experimental browser SirMassive Kindle Developer's Corner 7 03-30-2021 09:51 PM
Web Browser and BookWalker web viewer chronoreverse Amazon Kindle 0 02-06-2019 02:44 PM
Cannot access Calibre-Web via Kobo web browser chakattack Server 14 08-19-2018 08:51 PM
Kindle Fire Web Browser will likely allow for web based games. sirmaru Kindle Fire 10 11-15-2011 03:55 PM
merged terminal/launchpad/web server lrizzo Kindle Developer's Corner 46 10-21-2011 06:51 PM


All times are GMT -4. The time now is 02:01 PM.


MobileRead.com is a privately owned, operated and funded community.