Browse Source

Added new rewrite rules `add_hn_links_using_hack` and `add_hn_links_using_opener` to open HN comments with iOS apps

Adriano Di Luzio 2 years ago
parent
commit
54cb8fa028

+ 50 - 0
internal/reader/rewrite/rewrite_functions.go

@@ -12,6 +12,7 @@ import (
 	"strings"
 
 	"miniflux.app/v2/internal/config"
+	"miniflux.app/v2/internal/logger"
 
 	"github.com/PuerkitoBio/goquery"
 	"github.com/yuin/goldmark"
@@ -321,6 +322,55 @@ func decodeBase64Content(entryContent string) string {
 	}
 }
 
+func addHackerNewsLinksUsing(entryContent, app string) string {
+	doc, err := goquery.NewDocumentFromReader(strings.NewReader(entryContent))
+	if err != nil {
+		return entryContent
+	}
+
+	hn_prefix := "https://news.ycombinator.com/"
+	matches := doc.Find(`a[href^="` + hn_prefix + `"]`)
+
+	if matches.Length() > 0 {
+		matches.Each(func(i int, a *goquery.Selection) {
+			hrefAttr, _ := a.Attr("href")
+
+			hn_uri, err := url.Parse(hrefAttr)
+			if err != nil {
+				return
+			}
+
+			if app == "opener" {
+				params := url.Values{}
+				params.Add("url", hn_uri.String())
+
+				url := url.URL{
+					Scheme:   "opener",
+					Host:     "x-callback-url",
+					Path:     "show-options",
+					RawQuery: params.Encode(),
+				}
+
+				open_with_opener := `<a href="` + url.String() + `">Open with Opener</a>`
+				a.Parent().AppendHtml(" " + open_with_opener)
+			} else if app == "hack" {
+				url := strings.Replace(hn_uri.String(), hn_prefix, "hack://", 1)
+
+				open_with_hack := `<a href="` + url + `">Open with HACK</a>`
+				a.Parent().AppendHtml(" " + open_with_hack)
+			} else {
+				logger.Error("[openHackerNewsLinksWith] unknown app provided: %q", app)
+				return
+			}
+		})
+
+		output, _ := doc.Find("body").First().Html()
+		return output
+	}
+
+	return entryContent
+}
+
 func parseMarkdown(entryContent string) string {
 	var sb strings.Builder
 	md := goldmark.New(

+ 4 - 0
internal/reader/rewrite/rewriter.go

@@ -113,6 +113,10 @@ func applyRule(entryURL string, entry *model.Entry, rule rule) {
 		} else {
 			entry.Content = applyFuncOnTextContent(entry.Content, "body", decodeBase64Content)
 		}
+	case "add_hn_links_using_hack":
+		entry.Content = addHackerNewsLinksUsing(entry.Content, "hack")
+	case "add_hn_links_using_opener":
+		entry.Content = addHackerNewsLinksUsing(entry.Content, "opener")
 	case "parse_markdown":
 		entry.Content = parseMarkdown(entry.Content)
 	case "remove_tables":

+ 46 - 0
internal/reader/rewrite/rewriter_test.go

@@ -577,3 +577,49 @@ func TestRemoveClickbait(t *testing.T) {
 		t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
 	}
 }
+
+func TestAddHackerNewsLinksUsingHack(t *testing.T) {
+	testEntry := &model.Entry{
+		Title: `A title`,
+		Content: `<p>Article URL: <a href="https://example.org/url">https://example.org/article</a></p>
+		<p>Comments URL: <a href="https://news.ycombinator.com/item?id=37620043">https://news.ycombinator.com/item?id=37620043</a></p>
+		<p>Points: 23</p>
+		<p># Comments: 38</p>`,
+	}
+
+	controlEntry := &model.Entry{
+		Title: `A title`,
+		Content: `<p>Article URL: <a href="https://example.org/url">https://example.org/article</a></p>
+		<p>Comments URL: <a href="https://news.ycombinator.com/item?id=37620043">https://news.ycombinator.com/item?id=37620043</a> <a href="hack://item?id=37620043">Open with HACK</a></p>
+		<p>Points: 23</p>
+		<p># Comments: 38</p>`,
+	}
+	Rewriter("https://example.org/article", testEntry, `add_hn_links_using_hack`)
+
+	if !reflect.DeepEqual(testEntry, controlEntry) {
+		t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
+	}
+}
+
+func TestAddHackerNewsLinksUsingOpener(t *testing.T) {
+	testEntry := &model.Entry{
+		Title: `A title`,
+		Content: `<p>Article URL: <a href="https://example.org/url">https://example.org/article</a></p>
+		<p>Comments URL: <a href="https://news.ycombinator.com/item?id=37620043">https://news.ycombinator.com/item?id=37620043</a></p>
+		<p>Points: 23</p>
+		<p># Comments: 38</p>`,
+	}
+
+	controlEntry := &model.Entry{
+		Title: `A title`,
+		Content: `<p>Article URL: <a href="https://example.org/url">https://example.org/article</a></p>
+		<p>Comments URL: <a href="https://news.ycombinator.com/item?id=37620043">https://news.ycombinator.com/item?id=37620043</a> <a href="opener://x-callback-url/show-options?url=https%3A%2F%2Fnews.ycombinator.com%2Fitem%3Fid%3D37620043">Open with Opener</a></p>
+		<p>Points: 23</p>
+		<p># Comments: 38</p>`,
+	}
+	Rewriter("https://example.org/article", testEntry, `add_hn_links_using_opener`)
+
+	if !reflect.DeepEqual(testEntry, controlEntry) {
+		t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
+	}
+}

+ 4 - 0
internal/reader/sanitizer/sanitizer.go

@@ -297,6 +297,10 @@ func hasValidURIScheme(src string) bool {
 		"tel:",
 		"webcal://",
 		"xmpp:",
+
+		// iOS Apps
+		"opener://", // https://www.opener.link
+		"hack://",   // https://apps.apple.com/it/app/hack-for-hacker-news-reader/id1464477788?l=en-GB
 	}
 
 	for _, prefix := range whitelist {