yay/pkg/news/news.go

175 lines
3.1 KiB
Go
Raw Normal View History

package news
import (
"bytes"
2021-05-16 22:41:33 +02:00
"context"
"encoding/xml"
"fmt"
"html"
"io"
"net/http"
"os"
"strings"
"time"
2021-09-08 22:28:08 +02:00
"github.com/Jguer/yay/v11/pkg/text"
)
type item struct {
Title string `xml:"title"`
Link string `xml:"link"`
Description string `xml:"description"`
PubDate string `xml:"pubDate"`
Creator string `xml:"dc:creator"`
}
2020-07-27 00:11:24 +02:00
func (item *item) print(buildTime time.Time, all, quiet bool) {
var fd string
2021-08-11 20:13:28 +02:00
date, err := time.Parse(time.RFC1123Z, item.PubDate)
if err != nil {
fmt.Fprintln(os.Stderr, err)
} else {
fd = text.FormatTime(int(date.Unix()))
2020-07-27 00:11:24 +02:00
if !all && !buildTime.IsZero() {
if buildTime.After(date) {
return
}
}
}
fmt.Println(text.Bold(text.Magenta(fd)), text.Bold(strings.TrimSpace(item.Title)))
if !quiet {
desc := strings.TrimSpace(parseNews(item.Description))
fmt.Println(desc)
}
}
type channel struct {
Title string `xml:"title"`
Link string `xml:"link"`
Description string `xml:"description"`
Language string `xml:"language"`
Lastbuilddate string `xml:"lastbuilddate"`
Items []item `xml:"item"`
}
type rss struct {
Channel channel `xml:"channel"`
}
func PrintNewsFeed(ctx context.Context, client *http.Client, cutOffDate time.Time, bottomUp, all, quiet bool) error {
2022-08-14 19:41:54 +02:00
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://archlinux.org/feeds/news", http.NoBody)
2021-05-16 22:41:33 +02:00
if err != nil {
return err
}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
2021-08-11 20:13:28 +02:00
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
rssGot := rss{}
d := xml.NewDecoder(bytes.NewReader(body))
2021-08-11 20:13:28 +02:00
if err := d.Decode(&rssGot); err != nil {
return err
}
if bottomUp {
for i := len(rssGot.Channel.Items) - 1; i >= 0; i-- {
2020-07-27 00:44:31 +02:00
rssGot.Channel.Items[i].print(cutOffDate, all, quiet)
}
} else {
for i := 0; i < len(rssGot.Channel.Items); i++ {
2020-07-27 00:44:31 +02:00
rssGot.Channel.Items[i].print(cutOffDate, all, quiet)
}
}
return nil
}
// Crude html parsing, good enough for the arch news
// This is only displayed in the terminal so there should be no security
2021-08-11 20:13:28 +02:00
// concerns.
func parseNews(str string) string {
2021-08-11 20:13:28 +02:00
var (
buffer bytes.Buffer
tagBuffer bytes.Buffer
escapeBuffer bytes.Buffer
inTag = false
inEscape = false
)
for _, char := range str {
if inTag {
if char == '>' {
inTag = false
2021-08-11 20:13:28 +02:00
switch tagBuffer.String() {
case "code":
buffer.WriteString(text.CyanCode)
case "/code":
buffer.WriteString(text.ResetCode)
case "/p":
buffer.WriteRune('\n')
}
continue
}
tagBuffer.WriteRune(char)
2021-08-11 20:13:28 +02:00
continue
}
if inEscape {
if char == ';' {
inEscape = false
2021-08-11 20:13:28 +02:00
escapeBuffer.WriteRune(char)
s := html.UnescapeString(escapeBuffer.String())
buffer.WriteString(s)
2021-08-11 20:13:28 +02:00
continue
}
escapeBuffer.WriteRune(char)
2021-08-11 20:13:28 +02:00
continue
}
if char == '<' {
inTag = true
2021-08-11 20:13:28 +02:00
tagBuffer.Reset()
2021-08-11 20:13:28 +02:00
continue
}
if char == '&' {
inEscape = true
2021-08-11 20:13:28 +02:00
escapeBuffer.Reset()
escapeBuffer.WriteRune(char)
2021-08-11 20:13:28 +02:00
continue
}
buffer.WriteRune(char)
}
buffer.WriteString(text.ResetCode)
2021-08-11 20:13:28 +02:00
return buffer.String()
}