@@ -7,16 +7,15 @@ import (
7
7
"html/template"
8
8
"io"
9
9
"log"
10
+ "math"
10
11
"net/url"
11
12
"strings"
13
+ "time"
12
14
13
15
"github.com/everywall/ladder/proxychain"
14
-
16
+ "github.com/markusmobius/go-trafilatura"
15
17
"golang.org/x/net/html"
16
18
"golang.org/x/net/html/atom"
17
-
18
- //"github.com/go-shiori/dom"
19
- "github.com/markusmobius/go-trafilatura"
20
19
)
21
20
22
21
//go:embed vendor/generate_readable_outline.html
@@ -63,19 +62,24 @@ func GenerateReadableOutline() proxychain.ResponseModification {
63
62
html .Render (& b , extract .ContentNode )
64
63
distilledHTML := b .String ()
65
64
65
+ siteName := strings .Split (extract .Metadata .Sitename , ";" )[0 ]
66
+ title := strings .Split (extract .Metadata .Title , "|" )[0 ]
67
+ fmtDate := createWikipediaDateLink (extract .Metadata .Date )
68
+ readingTime := formatDuration (estimateReadingTime (extract .ContentText ))
69
+
66
70
// populate template parameters
67
71
data := map [string ]interface {}{
68
72
"Success" : true ,
69
73
"Image" : extract .Metadata .Image ,
70
74
"Description" : extract .Metadata .Description ,
71
- "Sitename" : strings . Split ( extract . Metadata . Sitename , ";" )[ 0 ] ,
75
+ "Sitename" : siteName ,
72
76
"Hostname" : extract .Metadata .Hostname ,
73
77
"Url" : "/" + chain .Request .URL .String (),
74
- "Title" : extract . Metadata . Title , // todo: modify CreateReadableDocument so we don't have <h1> titles duplicated?
75
- "Date" : extract . Metadata . Date . String () ,
76
- "Author" : createWikipediaSearchLinks (extract .Metadata .Author ),
77
- //"Author ": extract.Metadata.Author ,
78
- "Body " : distilledHTML ,
78
+ "Title" : title ,
79
+ "Date" : fmtDate ,
80
+ "Author" : createDDGFeelingLuckyLinks (extract .Metadata .Author , extract . Metadata . Hostname ),
81
+ "Body " : distilledHTML ,
82
+ "ReadingTime " : readingTime ,
79
83
}
80
84
81
85
// ============================================================================
@@ -157,9 +161,20 @@ func rewriteHrefLinks(n *html.Node, baseURL string, apiPath string) {
157
161
recurse (n )
158
162
}
159
163
160
- // createWikipediaSearchLinks takes in comma or semicolon separated terms,
161
- // then turns them into <a> links searching for the term.
162
- func createWikipediaSearchLinks (searchTerms string ) string {
164
+ // createWikipediaDateLink takes in a date
165
+ // and returns an <a> link pointing to the current events page for that day
166
+ func createWikipediaDateLink (t time.Time ) string {
167
+ url := fmt .Sprintf ("https://en.wikipedia.org/wiki/Portal:Current_events#%s" , t .Format ("2006_January_2" ))
168
+ date := t .Format ("January 2, 2006" )
169
+ return fmt .Sprintf ("<a rel=\" noreferrer\" href=\" %s\" >%s</a>" , url , date )
170
+ }
171
+
172
+ // createDDGFeelingLuckyLinks takes in comma or semicolon separated terms,
173
+ // then turns them into <a> links searching for the term using DuckDuckGo's I'm
174
+ // feeling lucky feature. It will redirect the user immediately to the first search result.
175
+ func createDDGFeelingLuckyLinks (searchTerms string , siteHostname string ) string {
176
+
177
+ siteHostname = strings .TrimSpace (siteHostname )
163
178
semiColonSplit := strings .Split (searchTerms , ";" )
164
179
165
180
var links []string
@@ -171,11 +186,13 @@ func createWikipediaSearchLinks(searchTerms string) string {
171
186
continue
172
187
}
173
188
174
- encodedTerm := url . QueryEscape ( trimmedTerm )
189
+ ddgQuery := fmt . Sprintf ( ` site:%s intitle:"%s"` , strings . TrimPrefix ( siteHostname , "www." ), trimmedTerm )
175
190
176
- wikiURL := fmt .Sprintf ("https://en.wikipedia.org/w/index.php?search=%s" , encodedTerm )
191
+ encodedTerm := `\%s:` + url .QueryEscape (ddgQuery )
192
+ //ddgURL := `https://html.duckduckgo.com/html/?q=` + encodedTerm
193
+ ddgURL := `https://www.duckduckgo.com/?q=` + encodedTerm
177
194
178
- link := fmt .Sprintf ("<a href=\" %s\" >%s</a>" , wikiURL , trimmedTerm )
195
+ link := fmt .Sprintf ("<a rel= \" noreferrer \" href=\" %s\" >%s</a>" , ddgURL , trimmedTerm )
179
196
links = append (links , link )
180
197
}
181
198
@@ -187,3 +204,66 @@ func createWikipediaSearchLinks(searchTerms string) string {
187
204
188
205
return strings .Join (links , " " )
189
206
}
207
+
208
+ // estimateReadingTime estimates how long the given text will take to read using the given configuration.
209
+ func estimateReadingTime (text string ) time.Duration {
210
+ if len (text ) == 0 {
211
+ return 0
212
+ }
213
+
214
+ // Init options with default values.
215
+ WordsPerMinute := 200
216
+ WordBound := func (b byte ) bool {
217
+ return b == ' ' || b == '\n' || b == '\r' || b == '\t'
218
+ }
219
+
220
+ words := 0
221
+ start := 0
222
+ end := len (text ) - 1
223
+
224
+ // Fetch bounds.
225
+ for WordBound (text [start ]) {
226
+ start ++
227
+ }
228
+ for WordBound (text [end ]) {
229
+ end --
230
+ }
231
+
232
+ // Calculate the number of words.
233
+ for i := start ; i <= end ; {
234
+ for i <= end && ! WordBound (text [i ]) {
235
+ i ++
236
+ }
237
+
238
+ words ++
239
+
240
+ for i <= end && WordBound (text [i ]) {
241
+ i ++
242
+ }
243
+ }
244
+
245
+ // Reading time stats.
246
+ minutes := math .Ceil (float64 (words ) / float64 (WordsPerMinute ))
247
+ duration := time .Duration (math .Ceil (minutes ) * float64 (time .Minute ))
248
+
249
+ return duration
250
+
251
+ }
252
+
253
+ func formatDuration (d time.Duration ) string {
254
+ // Check if the duration is less than one minute
255
+ if d < time .Minute {
256
+ seconds := int (d .Seconds ())
257
+ return fmt .Sprintf ("%d seconds" , seconds )
258
+ }
259
+
260
+ // Convert the duration to minutes
261
+ minutes := int (d .Minutes ())
262
+
263
+ // Format the string for one or more minutes
264
+ if minutes == 1 {
265
+ return "1 minute"
266
+ } else {
267
+ return fmt .Sprintf ("%d minutes" , minutes )
268
+ }
269
+ }
0 commit comments