From 063d630bc1acbaaf1b9743a33bef559601b117d3 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sun, 27 Oct 2024 10:53:32 +0200 Subject: can share an article with preview text of the title --- go.mod | 3 ++- go.sum | 4 +++ internal/platforms/linkedin/escapes.go | 48 +++++++++++++++++++++++++++++++++ internal/platforms/linkedin/linkedin.go | 15 +++++++++-- 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 563eb4f..1b14607 100644 --- a/go.mod +++ b/go.mod @@ -11,5 +11,6 @@ require ( github.com/fatih/color v1.17.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - golang.org/x/sys v0.18.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/sys v0.26.0 // indirect ) diff --git a/go.sum b/go.sum index 9f05b15..5f0b1c1 100644 --- a/go.sum +++ b/go.sum @@ -11,9 +11,13 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/internal/platforms/linkedin/escapes.go b/internal/platforms/linkedin/escapes.go index 5f803a5..6c18a76 100644 --- a/internal/platforms/linkedin/escapes.go +++ b/internal/platforms/linkedin/escapes.go @@ -1,7 +1,11 @@ package linkedin import ( + "fmt" + "net/http" "strings" + + "golang.org/x/net/html" ) // https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/little-text-format?view=li-lms-2024-01#language-grammar @@ -37,3 +41,47 @@ func escapeLinkedInText(input string) string { return builder.String() } + +// fetchTitle fetches the HTML page at the given URL and returns the content of the tag. +func fetchTitle(url string) (string, error) { + // Send a GET request to the URL + resp, err := http.Get(url) + if err != nil { + return "", fmt.Errorf("failed to get URL: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("failed to get a successful response: %v", resp.StatusCode) + } + + // Parse the HTML document + doc, err := html.Parse(resp.Body) + if err != nil { + return "", fmt.Errorf("failed to parse HTML: %v", err) + } + + // Traverse the document and find the <title> tag + var title string + var f func(*html.Node) + f = func(n *html.Node) { + if n.Type == html.ElementNode && n.Data == "title" { + if n.FirstChild != nil { + title = n.FirstChild.Data + } + return + } + for c := n.FirstChild; c != nil; c = c.NextSibling { + f(c) + } + } + + // Call the function to search for the title + f(doc) + + if title == "" { + return "", fmt.Errorf("no title element found") + } + + return title, nil +} diff --git a/internal/platforms/linkedin/linkedin.go b/internal/platforms/linkedin/linkedin.go index ebd92b0..54752b9 100644 --- a/internal/platforms/linkedin/linkedin.go +++ b/internal/platforms/linkedin/linkedin.go @@ -57,7 +57,7 @@ func post(ctx context.Context, args config.Args, sizeLimit int, ent entry.Entry) } func callLinkedInAPI(ctx context.Context, personID, accessToken, content string, urls []string) error { - const url = "https://api.linkedin.com/v2/posts" + const url = "https://api.linkedin.com/rest/posts" post := map[string]interface{}{ "author": fmt.Sprintf("urn:li:person:%s", personID), @@ -73,10 +73,20 @@ func callLinkedInAPI(ctx context.Context, personID, accessToken, content string, } if len(urls) > 0 { - // TODO: Add media links to post structure + title, err := fetchTitle(urls[0]) + if err != nil { + return err + } + post["content"] = map[string]interface{}{ + "article": map[string]interface{}{ + "title": title, + "source": urls[0], + }, + } } payload, err := json.Marshal(post) + fmt.Println(string(payload)) if err != nil { return fmt.Errorf("Error encoding JSON:%w", err) } @@ -88,6 +98,7 @@ func callLinkedInAPI(ctx context.Context, personID, accessToken, content string, req.Header.Add("Authorization", "Bearer "+accessToken) req.Header.Set("Content-Type", "application/json") req.Header.Add("X-RestLi-Protocol-Version", "2.0.0") + req.Header.Add("LinkedIn-Version", "202409") client := &http.Client{} resp, err := client.Do(req) -- cgit v1.2.3