https://blog.owulveryck.info/2021/10/07/reading-from-the-web-offline-and-distraction-free.html
owulveryck's blog
* This is Home
* Archives
* Tags
* Categories
* About
owulveryck's blog
* This is Home
* Archives
* Tags
* Categories
* About
Reading from the web offline and distraction-free
2021-10-07
Table of Contents
* The Why
+ This article
* Existent solutions
* First part: extracting the content
+ Readability / Arc90
+ The problem with reactive content and Medium articles
* Second part: generating the ePub
+ First step: crafting the ePub
+ Second step: creating the ePub
* Third part: adding fancy features
+ Grabbing meta information
+ Generating a cover
+ GetPocket integration
+ Dealing with MathJax
* Conclusion and future work
TL;DR: This article describes the wiring of a tool to turn a webpage
into a self-sufficient epub (for reading offline). If you want to try
the tool, you can grab a binary version from GitHub
The Why
To oversimplify my need, I will quote this from the Readability
Project
Reading anything on the Internet has become a full-on nightmare.
As media outlets attempt to eke out as much advertising revenue
as possible, we're left trying to put blinders on to mask away
all the insanity that surrounds the content we're trying to read.
It's almost like listening to talk radio, except the commercials
play during the program in the background. It's a pretty awful
experience. Our friend to date has been the trusty "Print View"
button. Click it and all the junk goes away. I click it all the
time and rarely print. It's really become the "Peace & Quiet"
button for many.
This article
In a recent post, I blogged about a tool I am building for my
reMarkable. In this post, I will describe a new tool that converts
any webpage into an ePub file.
The goals of this tool are:
* to keep track of the articles I like without fearing any broken
links
* to extract the content, and read the articles without distraction
* to be able to read the articles offline on devices such as ebook
readers or my reMarkable
Existent solutions
This feature already exists if you are using a Kobo and the getPocket
service. The problem is that it is that the offline experience is
tidily linked with my Kobo device. On top of that, getPocket does not
offer any way to download the cleaned version of the articles.
We, as developers, have superpowers: we can build the tools we want.
Let's explain the features I am building step by step.
Disclaimer at the time this post is written, the tool results from
various experiments, but not the architecture or the code is clean
and maintainable. Take this post as a validation of a proof of
concept.
First part: extracting the content
The most important part of this journey is the tool's ability to
extract the content of a webpage. The first idea would be to query
the getPocket service that does this, but the documentation of their
API mentions that:
Pocket's Article View API will return article content and
relevant meta data on any provided URL.
The Pocket Article View API is currently only open to partners
that are integrating Pocket specific features or full-fledged
Pocket clients. For example, building a Pocket client for X
platform.
If you are looking for a general text parser or to provide "read
now" functionality in your app - we do not currently support
that. There are other companies/products that provide that type
of API, for example: Diffbot.
They mention Diffbot, but it is a web service that requires a
subscription; I'd like to build a simple tool, free of charge, for my
usage, and therefore this is not an option.
Readability / Arc90
I looked into open source initiatives that empower the reading modes
of the browsers (I am/was a fan of the safari reading mode), and I
found that some of them were based on an experiment made by Arc90.
This experiment led to the (discontinued) service readability.
We can now find various implementations of the Arc90 algorithm. I am
using this implementation in Go for my tool.
Code
Feel free to skip this part if you are not interested in the code
The API of the readability library is straightforward. First, there
is a need to create a Readability object with an HTML parser that
reads and extracts relevant content.
Then, calling the Parse method on this object, feeding it with an
io.Reader that contains the page to analyze.
The result is an object of type Article that contains some metadata
and the cleaned content. This content is an HTML tree and is
accessible via a top-level html.Node.
1 package main
2
3 import (
4 "log"
5 "net/http"
6 "os"
7
8 "github.com/cixtor/readability"
9 "golang.org/x/net/html"
10 )
11
12 func main() {
13 // create a parser
14 htmlParser := readability.New()
15 // Fetch a webpage
16 resp, err := http.Get("https://example.com/")
17 passOrDie(err)
18 // Deal with errors etc...
19 defer resp.Body.Close()
20 // Parse the content
21 article, err := htmlParser.Parse(resp.Body, "https://example.com")
22 passOrDie(err)
23 // Write the readable result on stdout
24 html.Render(os.Stdout, article.Node)
25 }
The problem with reactive content and Medium articles
When the Arc90 project made this experiment, there were not many
reactive contents.
On top of that, it does not handle the javascript. This leads to
images that are not correctly displayed. Let's take the first chapter
of Simon Wardley's book about maps to illustrate the problem.
The picture below is a screenshot of a reader view of the page with
Safari:
[medium]
The medium issue with Arc90
The code below is the code extracter by a curl request:
1
3
5
6
7
9
11
17
18
31
32
33
34
35
Within the element, we can see that the first image (https:/
/miro.medium.com/max/60/1*RSH2vh_xgQtjB68Zb7oBaA.jpeg?q=20) is a
thumbnail and it acts as a placeholder.
A couple of JavaScript routines replaces the image at rendering time
in the browser. Luckily a