main
1package lobsters
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "net/url"
8
9 "mill/internal/content"
10
11 "github.com/mmcdole/gofeed"
12)
13
14var (
15 ErrMissingLink = errors.New("link fileld unset")
16)
17
18type Source struct {
19 name string
20 url *url.URL
21 feed *gofeed.Feed
22}
23
24func New(name, feedURL string) (*Source, error) {
25 u, err := url.Parse(feedURL)
26 if err != nil {
27 return nil, err
28 }
29
30 return &Source{
31 name: name,
32 url: u,
33 }, nil
34}
35
36func (s *Source) Name() string {
37 return s.name
38}
39
40func (s *Source) Fetch(ctx context.Context) ([]*content.Observation, error) {
41 fp := gofeed.NewParser()
42 feed, err := fp.ParseURLWithContext(s.url.String(), ctx)
43 if err != nil {
44 err = fmt.Errorf("rss feed parsing: %w", err)
45 return nil, err
46 }
47 s.feed = feed
48
49 observations := make([]*content.Observation, len(s.feed.Items))
50 for i, item := range s.feed.Items {
51
52 if item.Link == "" {
53 return nil, ErrMissingLink
54 }
55
56 targetURL, err := url.Parse(item.Link)
57 if err != nil {
58 return nil, err
59 }
60
61 discussionURL, err := url.Parse(item.GUID)
62 if err != nil {
63 return nil, err
64 }
65
66 obs, err := content.NewObservation(
67 s.url, // observation url
68 targetURL, // target url
69 discussionURL, // discussion url
70 s.Name(), // source name
71 item.Title, // item title
72 )
73 if err != nil {
74 err = fmt.Errorf("creating new observation: %w", err)
75 return nil, err
76 }
77 observations[i] = obs
78 }
79 return observations, nil
80}