126 lines
2.6 KiB
Go
126 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/k3a/html2text"
|
|
)
|
|
|
|
func fetchWebpage(url string) (string, error) {
|
|
res, err := http.Get(url)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
body, err := io.ReadAll(res.Body)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return string(body), nil
|
|
}
|
|
|
|
const HN_SEARCH_URL = "https://hn.algolia.com/api/v1/"
|
|
|
|
type Comment struct {
|
|
Author string `json:"author"`
|
|
Text string `json:"text"`
|
|
Children []Comment `json:"children"`
|
|
}
|
|
|
|
func sanitize(input string) string {
|
|
return html2text.HTML2Text(input)
|
|
}
|
|
|
|
func safeRequest(url string) *http.Response {
|
|
resp, err := http.Get(url)
|
|
if err != nil {
|
|
fmt.Printf("Failed to fetch URL: %s\n", url)
|
|
return nil
|
|
}
|
|
return resp
|
|
}
|
|
|
|
func fetchComments(storyID string) []string {
|
|
resp := safeRequest(HN_SEARCH_URL + "items/" + storyID)
|
|
if resp == nil {
|
|
return nil
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var comments map[string]interface{}
|
|
if err := json.NewDecoder(resp.Body).Decode(&comments); err != nil {
|
|
fmt.Printf("Failed to decode JSON response\n")
|
|
return nil
|
|
}
|
|
|
|
var lines []string
|
|
lines = append(lines, " ")
|
|
|
|
if children, ok := comments["children"].([]interface{}); ok {
|
|
for _, child := range children {
|
|
childComment := child.(map[string]interface{})
|
|
appendComment(childComment, &lines, 0)
|
|
}
|
|
}
|
|
|
|
return lines
|
|
}
|
|
|
|
func appendComment(comment map[string]interface{}, lines *[]string, level int) {
|
|
indent := "" + strings.Repeat(" ", min(level, 4)*2) + "| "
|
|
|
|
if author, ok := comment["author"].(string); ok {
|
|
*lines = append(*lines, indent+sanitize(author)+" wrote:")
|
|
|
|
text := sanitize(comment["text"].(string))
|
|
|
|
paragraphs := strings.Split(text, "\n\n")
|
|
for _, paragraph := range paragraphs {
|
|
textLines := wrapText(paragraph, indent)
|
|
*lines = append(*lines, textLines...)
|
|
*lines = append(*lines, indent)
|
|
}
|
|
*lines = (*lines)[:len(*lines)-1] // Drop the blank line after the last paragraph
|
|
} else {
|
|
*lines = append(*lines, indent+"[deleted]")
|
|
}
|
|
|
|
*lines = append(*lines, " ")
|
|
|
|
if children, ok := comment["children"].([]interface{}); ok {
|
|
for _, child := range children {
|
|
appendComment(child.(map[string]interface{}), lines, level+1)
|
|
}
|
|
}
|
|
}
|
|
|
|
func wrapText(text, indent string) []string {
|
|
words := strings.Fields(text)
|
|
var lines []string
|
|
var sb strings.Builder
|
|
|
|
maxWidth := 80
|
|
|
|
for _, word := range words {
|
|
if sb.Len()+len(word)+1 > maxWidth {
|
|
lines = append(lines, indent+sb.String())
|
|
sb.Reset()
|
|
}
|
|
if sb.Len() > 0 {
|
|
sb.WriteString(" ")
|
|
}
|
|
sb.WriteString(word)
|
|
}
|
|
if sb.Len() > 0 {
|
|
lines = append(lines, indent+sb.String())
|
|
}
|
|
|
|
return lines
|
|
}
|