package nomad import ( "bytes" "errors" "fmt" "net/url" "path/filepath" "git.sr.ht/~thrrgilag/woodstock" "git.wntrmute.dev/kyle/goutils/log" "github.com/anaskhan96/soup" ) func nomadLink(item Item) string { if item.Title != "" { return fmt.Sprintf("[%s](%s)", item.Title, item.URL.ID()) } u, err := url.Parse(item.URL.ID()) if err != nil { log.Errf("nomadLink: %s", err) return fmt.Sprintf("[%s](%s)", item.URL.ID(), item.URL.ID()) } return fmt.Sprintf("[%s](%s)", u.Host, item.URL.ID()) } type sel struct { selectors []string } func selector(selectors ...string) sel { return sel{selectors: selectors} } type imageFinder func(soup.Root) (string, bool) var imageFinders = []imageFinder{ func(root soup.Root) (string, bool) { return find( root, "src", selector("div", "class", "entry-image"), selector("img")) }, func(root soup.Root) (string, bool) { return find( root, "src", selector("div", "class", "gh-inner"), selector("img")) }, } func find(root soup.Root, attr string, selectors ...sel) (string, bool) { result := root for _, selector := range selectors { result = result.Find(selector.selectors...) if result.Pointer == nil { return "", false } } if attr == "" { text := result.Text() return text, text != "" } value, hasAttr := result.Attrs()[attr] return value, hasAttr } type Post struct { Title string Image Source Body string URL Source } func NewPost(item Item) Post { post := Post{ Body: nomadLink(item), URL: item.URL, } return post } func (p *Post) Fetch() error { pageSource, err := p.URL.Fetch() if err != nil { return err } root := soup.HTMLParse(pageSource) body, hasBody := find(root, "", selector("p", "class", "entry-body")) if hasBody { p.Body = body + " " + p.Body } var imageURL string var hasImageURL bool for _, finder := range imageFinders { imageURL, hasImageURL = finder(root) if hasImageURL { break } } if hasImageURL { p.Image = NewURLSource(imageURL) } return nil } func (p Post) Post(client *woodstock.Client) error { pnutPost := woodstock.NewPost{ Text: p.Body, } if p.Image != nil { imageData, err := p.Image.FetchBytes() if err != nil { return err } params := map[string]string{ "name": filepath.Base(p.Image.ID()), "is_public": "1", "type": "photo", } r := bytes.NewBuffer(imageData) file, err := client.CreateFile(params, r) if err != nil { panic(err.Error()) return err } pnutPost.Raw = []woodstock.Raw{pnutOembedRaw(file)} } result, err := client.Post(pnutPost) if err != nil { return err } if result.Meta.ErrorMessage != "" { return errors.New("woodstock: " + result.Meta.ErrorMessage) } return nil } func pnutOembedRaw(file woodstock.FileResult) woodstock.Raw { fval := map[string]string{ "file_id": file.Data.ID, "file_token": file.Data.FileToken, "format": "oembed", } value := map[string]map[string]string{"+io.pnut.core.file": fval} return woodstock.Raw{Type: "io.pnut.core.oembed", Value: value} }