diff --git a/handlers/api_modifiers_structdef.gen.go b/handlers/api_modifiers_structdef.gen.go
index c0e2699..6a8abc0 100644
--- a/handlers/api_modifiers_structdef.gen.go
+++ b/handlers/api_modifiers_structdef.gen.go
@@ -160,7 +160,7 @@ var AllMods Modifiers = Modifiers{
Description: "DeleteOutGoingCookiesExcept prevents non-whitelisted cookies from being sent from the client to the upstream proxy server. Cookies whose names are in the whitelist are not removed.",
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/requestmodifiers/modify_outgoing_cookies.go",
Params: []Param{
- {Name: "whitelist", Type: "&{Ellipsis:12348 Elt:string}"},
+ {Name: "whitelist", Type: "&{Ellipsis:12476 Elt:string}"},
},
},
{
@@ -485,7 +485,7 @@ var AllMods Modifiers = Modifiers{
Description: "DeleteIncomingCookies prevents ALL cookies from being sent from the proxy server back down to the client.",
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/modify_incoming_cookies.go",
Params: []Param{
- {Name: "_", Type: "&{Ellipsis:16342 Elt:string}"},
+ {Name: "_", Type: "&{Ellipsis:18778 Elt:string}"},
},
},
{
@@ -493,7 +493,7 @@ var AllMods Modifiers = Modifiers{
Description: "DeleteIncomingCookiesExcept prevents non-whitelisted cookies from being sent from the proxy server to the client. Cookies whose names are in the whitelist are not removed.",
CodeEditLink: "https://github.com/everywall/ladder/edit/origin/proxy_v2/proxychain/responsemodifiers/modify_incoming_cookies.go",
Params: []Param{
- {Name: "whitelist", Type: "&{Ellipsis:16887 Elt:string}"},
+ {Name: "whitelist", Type: "&{Ellipsis:19323 Elt:string}"},
},
},
{
diff --git a/proxychain/responsemodifiers/generate_readable_outline.go b/proxychain/responsemodifiers/generate_readable_outline.go
index 1d9e4d9..b5ccc47 100644
--- a/proxychain/responsemodifiers/generate_readable_outline.go
+++ b/proxychain/responsemodifiers/generate_readable_outline.go
@@ -7,16 +7,15 @@ import (
"html/template"
"io"
"log"
+ "math"
"net/url"
"strings"
+ "time"
"github.com/everywall/ladder/proxychain"
-
+ "github.com/markusmobius/go-trafilatura"
"golang.org/x/net/html"
"golang.org/x/net/html/atom"
-
- //"github.com/go-shiori/dom"
- "github.com/markusmobius/go-trafilatura"
)
//go:embed vendor/generate_readable_outline.html
@@ -63,19 +62,24 @@ func GenerateReadableOutline() proxychain.ResponseModification {
html.Render(&b, extract.ContentNode)
distilledHTML := b.String()
+ siteName := strings.Split(extract.Metadata.Sitename, ";")[0]
+ title := strings.Split(extract.Metadata.Title, "|")[0]
+ fmtDate := createWikipediaDateLink(extract.Metadata.Date)
+ readingTime := formatDuration(estimateReadingTime(extract.ContentText))
+
// populate template parameters
data := map[string]interface{}{
"Success": true,
"Image": extract.Metadata.Image,
"Description": extract.Metadata.Description,
- "Sitename": strings.Split(extract.Metadata.Sitename, ";")[0],
+ "Sitename": siteName,
"Hostname": extract.Metadata.Hostname,
"Url": "/" + chain.Request.URL.String(),
- "Title": extract.Metadata.Title, // todo: modify CreateReadableDocument so we don't have
titles duplicated?
- "Date": extract.Metadata.Date.String(),
- "Author": createWikipediaSearchLinks(extract.Metadata.Author),
- //"Author": extract.Metadata.Author,
- "Body": distilledHTML,
+ "Title": title,
+ "Date": fmtDate,
+ "Author": createDDGFeelingLuckyLinks(extract.Metadata.Author, extract.Metadata.Hostname),
+ "Body": distilledHTML,
+ "ReadingTime": readingTime,
}
// ============================================================================
@@ -157,9 +161,20 @@ func rewriteHrefLinks(n *html.Node, baseURL string, apiPath string) {
recurse(n)
}
-// createWikipediaSearchLinks takes in comma or semicolon separated terms,
-// then turns them into links searching for the term.
-func createWikipediaSearchLinks(searchTerms string) string {
+// createWikipediaDateLink takes in a date
+// and returns an link pointing to the current events page for that day
+func createWikipediaDateLink(t time.Time) string {
+ url := fmt.Sprintf("https://en.wikipedia.org/wiki/Portal:Current_events#%s", t.Format("2006_January_2"))
+ date := t.Format("January 2, 2006")
+ return fmt.Sprintf("%s", url, date)
+}
+
+// createDDGFeelingLuckyLinks takes in comma or semicolon separated terms,
+// then turns them into links searching for the term using DuckDuckGo's I'm
+// feeling lucky feature. It will redirect the user immediately to the first search result.
+func createDDGFeelingLuckyLinks(searchTerms string, siteHostname string) string {
+
+ siteHostname = strings.TrimSpace(siteHostname)
semiColonSplit := strings.Split(searchTerms, ";")
var links []string
@@ -171,11 +186,13 @@ func createWikipediaSearchLinks(searchTerms string) string {
continue
}
- encodedTerm := url.QueryEscape(trimmedTerm)
+ ddgQuery := fmt.Sprintf(` site:%s intitle:"%s"`, strings.TrimPrefix(siteHostname, "www."), trimmedTerm)
- wikiURL := fmt.Sprintf("https://en.wikipedia.org/w/index.php?search=%s", encodedTerm)
+ encodedTerm := `\%s:` + url.QueryEscape(ddgQuery)
+ //ddgURL := `https://html.duckduckgo.com/html/?q=` + encodedTerm
+ ddgURL := `https://www.duckduckgo.com/?q=` + encodedTerm
- link := fmt.Sprintf("%s", wikiURL, trimmedTerm)
+ link := fmt.Sprintf("%s", ddgURL, trimmedTerm)
links = append(links, link)
}
@@ -187,3 +204,66 @@ func createWikipediaSearchLinks(searchTerms string) string {
return strings.Join(links, " ")
}
+
+// estimateReadingTime estimates how long the given text will take to read using the given configuration.
+func estimateReadingTime(text string) time.Duration {
+ if len(text) == 0 {
+ return 0
+ }
+
+ // Init options with default values.
+ WordsPerMinute := 200
+ WordBound := func(b byte) bool {
+ return b == ' ' || b == '\n' || b == '\r' || b == '\t'
+ }
+
+ words := 0
+ start := 0
+ end := len(text) - 1
+
+ // Fetch bounds.
+ for WordBound(text[start]) {
+ start++
+ }
+ for WordBound(text[end]) {
+ end--
+ }
+
+ // Calculate the number of words.
+ for i := start; i <= end; {
+ for i <= end && !WordBound(text[i]) {
+ i++
+ }
+
+ words++
+
+ for i <= end && WordBound(text[i]) {
+ i++
+ }
+ }
+
+ // Reading time stats.
+ minutes := math.Ceil(float64(words) / float64(WordsPerMinute))
+ duration := time.Duration(math.Ceil(minutes) * float64(time.Minute))
+
+ return duration
+
+}
+
+func formatDuration(d time.Duration) string {
+ // Check if the duration is less than one minute
+ if d < time.Minute {
+ seconds := int(d.Seconds())
+ return fmt.Sprintf("%d seconds", seconds)
+ }
+
+ // Convert the duration to minutes
+ minutes := int(d.Minutes())
+
+ // Format the string for one or more minutes
+ if minutes == 1 {
+ return "1 minute"
+ } else {
+ return fmt.Sprintf("%d minutes", minutes)
+ }
+}
diff --git a/proxychain/responsemodifiers/vendor/generate_readable_outline.html b/proxychain/responsemodifiers/vendor/generate_readable_outline.html
index 0f0d251..79a9fd6 100644
--- a/proxychain/responsemodifiers/vendor/generate_readable_outline.html
+++ b/proxychain/responsemodifiers/vendor/generate_readable_outline.html
@@ -45,7 +45,7 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 512 512"
- class="h-8 focus:outline-none focus:ring focus:border-[#7AA7D1] ring-offset-2"
+ class="noprint h-8 focus:outline-none focus:ring focus:border-[#7AA7D1] ring-offset-2"
>
-
+
+
+
{{else}}
-
-
- {{if ne .Date ""}}
-
{{.Date}}
- {{end}}
- {{if ne .Author ""}}
-
{{.Author}}
- {{end}}
-
+
+
+
+
+
+
+ {{if ne .Author ""}}
+ {{.Author}} |
+ {{end}}
+
+ {{if ne .Date ""}}
+ {{.Date}}
+ {{end}}
+
+
+
+ Reading Time: {{.ReadingTime}}
+
+
@@ -357,21 +370,22 @@
-