package main import ( "encoding/base64" "fmt" "io/ioutil" "log" "net/http" "os" "path" "strings" "willnorris.com/go/webmention" ) func main() { lastArticleDir, lastArticleDirSet := os.LookupEnv("LAST_ARTICLE_DIR") if lastArticleDirSet { http.HandleFunc("/hook", func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Wrong HTTP method", http.StatusMethodNotAllowed) return } blacklist := r.URL.Query()["blacklist"] feeds, feedsPresent := r.URL.Query()["feed"] if feedsPresent { go func() { for _, feed := range feeds { fmt.Println("Check webmentions for feed:", feed) article, err := LatestArticle(feed) if err != nil { fmt.Println(err.Error()) continue } lastArticleUrl, lastArticleDate := lastArticle(lastArticleDir, feed) if lastArticleUrl != article.Url || lastArticleDate != article.Modified { err := sendWebmentions(article.Url, blacklist) if err != nil { fmt.Println(err.Error()) continue } err = updateLastArticle(lastArticleDir, feed, article.Url, article.Modified) if err != nil { fmt.Println(err.Error()) continue } } else { fmt.Println("No new article") continue } } }() } urls, urlsPresent := r.URL.Query()["url"] if urlsPresent { go func() { for _, url := range urls { fmt.Println("Check webmentions for url:", url) err := sendWebmentions(url, blacklist) if err != nil { fmt.Println(err.Error()) continue } } }() } }) log.Fatal(http.ListenAndServe(":8080", nil)) } else { log.Fatal("Not configured") } } func lastArticle(dirname string, feed string) (url string, date string) { fileContent, _ := ioutil.ReadFile(path.Join(dirname, base64.StdEncoding.EncodeToString([]byte(feed)))) if len(string(fileContent)) == 0 { return } urlDate := strings.SplitN(string(fileContent), ";", 2) return urlDate[0], urlDate[1] } func updateLastArticle(dirname string, feed string, url string, date string) error { return ioutil.WriteFile(path.Join(dirname, base64.StdEncoding.EncodeToString([]byte(feed))), []byte(url+";"+date), 0644) } func sendWebmentions(url string, blacklist []string) error { req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return err } req.Header.Add("User-Agent", "WebmentionHelper") resp, err := http.DefaultClient.Do(req) if err != nil { return err } discovered, err := webmention.DiscoverLinksFromReader(resp.Body, url, ".h-entry") _ = resp.Body.Close() if err != nil { return err } var filtered []string allowed := func(link string) bool { for _, black := range blacklist { if strings.Contains(link, black) { return false } } return true } for _, link := range discovered { if allowed(link) { filtered = append(filtered, link) } } client := webmention.New(nil) for _, link := range filtered { endpoint, err := client.DiscoverEndpoint(link) if err != nil || len(endpoint) < 1 { continue } _, err = client.SendWebmention(endpoint, url, link) if err != nil { log.Println("Sending webmention to " + link + " failed") continue } fmt.Println("Sent webmention to " + link) } return nil }