aboutsummaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/feed/cache.go2
-rw-r--r--internal/feed/cache_v1.go23
-rw-r--r--internal/feed/feed.go43
-rw-r--r--internal/feed/item.go59
-rw-r--r--internal/feed/mail.go55
-rw-r--r--internal/feed/parse.go10
6 files changed, 104 insertions, 88 deletions
diff --git a/internal/feed/cache.go b/internal/feed/cache.go
index 731eab1..5674de4 100644
--- a/internal/feed/cache.go
+++ b/internal/feed/cache.go
@@ -28,7 +28,7 @@ type CachedFeed interface {
Failures() int
Last() time.Time
ID() string
- filterItems(items []feeditem, ignoreHash bool, alwaysNew bool) []feeditem
+ filterItems(items []item, ignoreHash bool, alwaysNew bool) []item
Commit()
}
diff --git a/internal/feed/cache_v1.go b/internal/feed/cache_v1.go
index b2813ce..9a6de50 100644
--- a/internal/feed/cache_v1.go
+++ b/internal/feed/cache_v1.go
@@ -6,8 +6,6 @@ import (
"strconv"
"time"
- "github.com/lithammer/shortuuid"
-
"github.com/Necoro/feed2imap-go/pkg/log"
"github.com/Necoro/feed2imap-go/pkg/util"
)
@@ -153,11 +151,10 @@ func (cache *v1Cache) findItem(feed *Feed) CachedFeed {
return item
}
-func newCachedItem(item feeditem) cachedItem {
+func (item *item) newCachedItem() cachedItem {
var ci cachedItem
- ci.ID = shortuuid.New()
-
+ ci.ID = item.itemId
ci.Title = item.Item.Title
ci.Link = item.Item.Link
if item.Item.PublishedParsed != nil {
@@ -187,28 +184,30 @@ func (cf *cachedFeed) deleteItem(index int) {
cf.Items = cf.Items[:len(cf.Items)-1]
}
-func (cf *cachedFeed) filterItems(items []feeditem, ignoreHash, alwaysNew bool) []feeditem {
+func (cf *cachedFeed) filterItems(items []item, ignoreHash, alwaysNew bool) []item {
if len(items) == 0 {
return items
}
- cacheItems := make(map[cachedItem]*feeditem, len(items))
+ cacheItems := make(map[cachedItem]*item, len(items))
for idx := range items {
// remove complete duplicates on the go
- cacheItems[newCachedItem(items[idx])] = &items[idx]
+ cacheItems[items[idx].newCachedItem()] = &items[idx]
}
log.Debugf("%d items after deduplication", len(cacheItems))
- filtered := make([]feeditem, 0, len(items))
+ filtered := make([]item, 0, len(items))
cacheadd := make([]cachedItem, 0, len(items))
- app := func(item *feeditem, ci cachedItem, oldIdx *int) {
+ app := func(item *item, ci cachedItem, oldIdx *int) {
if oldIdx != nil {
item.updateOnly = true
+ prevId := cf.Items[*oldIdx].ID
+ ci.ID = prevId
+ item.itemId = prevId
cf.deleteItem(*oldIdx)
}
filtered = append(filtered, *item)
cacheadd = append(cacheadd, ci)
- item.itemId = ci.ID
}
CACHE_ITEMS:
@@ -228,7 +227,6 @@ CACHE_ITEMS:
log.Debugf("Guid matches with: %s", oldItem)
if !oldItem.similarTo(&ci, ignoreHash) {
item.addReason("guid (upd)")
- ci.ID = oldItem.ID
app(item, ci, &idx)
} else {
log.Debugf("Similar, ignoring")
@@ -258,7 +256,6 @@ CACHE_ITEMS:
}
log.Debugf("Link matches, updating: %s", oldItem)
item.addReason("link (upd)")
- ci.ID = oldItem.ID
app(item, ci, &idx)
continue CACHE_ITEMS
diff --git a/internal/feed/feed.go b/internal/feed/feed.go
index 9ed44df..4a0e724 100644
--- a/internal/feed/feed.go
+++ b/internal/feed/feed.go
@@ -7,13 +7,12 @@ import (
"github.com/Necoro/feed2imap-go/pkg/config"
"github.com/Necoro/feed2imap-go/pkg/log"
- "github.com/Necoro/feed2imap-go/pkg/util"
)
type Feed struct {
*config.Feed
feed *gofeed.Feed
- items []feeditem
+ items []item
cached CachedFeed
Global config.GlobalOptions
}
@@ -23,46 +22,6 @@ type feedDescriptor struct {
Url string
}
-type feedImage struct {
- image []byte
- mime string
-}
-
-type feeditem struct {
- *gofeed.Feed
- *gofeed.Item
- Body string
- updateOnly bool
- reasons []string
- images []feedImage
- itemId string
-}
-
-// Creator returns the name of the creating author.
-// MUST NOT have `*feeditem` has the receiver, because the template breaks then.
-func (item feeditem) Creator() string {
- if item.Item.Author != nil {
- return item.Item.Author.Name
- }
- return ""
-}
-
-func (item *feeditem) addReason(reason string) {
- if !util.StrContains(item.reasons, reason) {
- item.reasons = append(item.reasons, reason)
- }
-}
-
-func (item *feeditem) addImage(img []byte, mime string) int {
- i := feedImage{img, mime}
- item.images = append(item.images, i)
- return len(item.images)
-}
-
-func (item *feeditem) clearImages() {
- item.images = []feedImage{}
-}
-
func (feed *Feed) descriptor() feedDescriptor {
return feedDescriptor{
Name: feed.Name,
diff --git a/internal/feed/item.go b/internal/feed/item.go
new file mode 100644
index 0000000..5c67784
--- /dev/null
+++ b/internal/feed/item.go
@@ -0,0 +1,59 @@
+package feed
+
+import (
+ "fmt"
+
+ "github.com/mmcdole/gofeed"
+
+ "github.com/Necoro/feed2imap-go/pkg/config"
+ "github.com/Necoro/feed2imap-go/pkg/util"
+)
+
+type feedImage struct {
+ image []byte
+ mime string
+}
+
+type item struct {
+ *gofeed.Feed
+ *gofeed.Item
+ feed *Feed
+ Body string
+ updateOnly bool
+ reasons []string
+ images []feedImage
+ itemId string
+}
+
+// Creator returns the name of the creating author.
+// MUST NOT have `*item` has the receiver, because the template breaks then.
+func (item *item) Creator() string {
+ if item.Item.Author != nil {
+ return item.Item.Author.Name
+ }
+ return ""
+}
+
+func (item *item) addReason(reason string) {
+ if !util.StrContains(item.reasons, reason) {
+ item.reasons = append(item.reasons, reason)
+ }
+}
+
+func (item *item) addImage(img []byte, mime string) int {
+ i := feedImage{img, mime}
+ item.images = append(item.images, i)
+ return len(item.images)
+}
+
+func (item *item) clearImages() {
+ item.images = []feedImage{}
+}
+
+func (item *item) defaultEmail() string {
+ return item.feed.Global.DefaultEmail
+}
+
+func (item *item) messageId() string {
+ return fmt.Sprintf("<feed#%s#%s@%s>", item.feed.cached.ID(), item.itemId, config.Hostname())
+}
diff --git a/internal/feed/mail.go b/internal/feed/mail.go
index ebf032a..41a4cbd 100644
--- a/internal/feed/mail.go
+++ b/internal/feed/mail.go
@@ -25,33 +25,37 @@ func address(name, address string) []*mail.Address {
return []*mail.Address{{Name: name, Address: address}}
}
-func fromAdress(feed *Feed, item feeditem, cfg *config.Config) []*mail.Address {
+func (item *item) fromAdress() []*mail.Address {
switch {
case item.Item.Author != nil && item.Item.Author.Email != "":
return address(item.Item.Author.Name, item.Item.Author.Email)
case item.Item.Author != nil && item.Item.Author.Name != "":
- return address(item.Item.Author.Name, cfg.DefaultEmail)
+ return address(item.Item.Author.Name, item.defaultEmail())
case item.Feed.Author != nil && item.Feed.Author.Email != "":
return address(item.Feed.Author.Name, item.Feed.Author.Email)
case item.Feed.Author != nil && item.Feed.Author.Name != "":
- return address(item.Feed.Author.Name, cfg.DefaultEmail)
+ return address(item.Feed.Author.Name, item.defaultEmail())
default:
- return address(feed.Name, cfg.DefaultEmail)
+ return address(item.feed.Name, item.defaultEmail())
}
}
-func writeHtml(writer io.Writer, item feeditem) error {
+func (item *item) toAddress() []*mail.Address {
+ return address(item.feed.Name, item.defaultEmail())
+}
+
+func (item *item) writeHtml(writer io.Writer) error {
return template.Feed.Execute(writer, item)
}
-func buildHeader(feed *Feed, item feeditem, cfg *config.Config) message.Header {
+func (item *item) buildHeader() message.Header {
var h mail.Header
h.SetContentType("multipart/alternative", nil)
- h.SetAddressList("From", fromAdress(feed, item, cfg))
- h.SetAddressList("To", address(feed.Name, cfg.DefaultEmail))
+ h.SetAddressList("From", item.fromAdress())
+ h.SetAddressList("To", item.toAddress())
h.Set("X-Feed2Imap-Version", config.Version())
h.Set("X-Feed2Imap-Reason", strings.Join(item.reasons, ","))
- h.Set("Message-Id", feed.messageId(item))
+ h.Set("Message-Id", item.messageId())
{ // date
date := item.Item.PublishedParsed
@@ -75,7 +79,7 @@ func buildHeader(feed *Feed, item feeditem, cfg *config.Config) message.Header {
return h.Header
}
-func writeHtmlPart(w *message.Writer, item feeditem) error {
+func (item *item) writeHtmlPart(w *message.Writer) error {
var ih message.Header
ih.SetContentType("text/html", map[string]string{"charset": "utf-8"})
ih.SetContentDisposition("inline", nil)
@@ -87,14 +91,14 @@ func writeHtmlPart(w *message.Writer, item feeditem) error {
}
defer partW.Close()
- if err = writeHtml(w, item); err != nil {
+ if err = item.writeHtml(w); err != nil {
return fmt.Errorf("writing html part: %w", err)
}
return nil
}
-func writeImagePart(w *message.Writer, img feedImage, cid string) error {
+func (img *feedImage) writeImagePart(w *message.Writer, cid string) error {
var ih message.Header
ih.SetContentType(img.mime, nil)
ih.SetContentDisposition("inline", nil)
@@ -114,8 +118,8 @@ func writeImagePart(w *message.Writer, img feedImage, cid string) error {
return nil
}
-func writeToBuffer(b *bytes.Buffer, feed *Feed, item feeditem, cfg *config.Config) error {
- h := buildHeader(feed, item, cfg)
+func (item *item) writeToBuffer(b *bytes.Buffer) error {
+ h := item.buildHeader()
writer, err := message.CreateWriter(b, h)
if err != nil {
@@ -123,8 +127,8 @@ func writeToBuffer(b *bytes.Buffer, feed *Feed, item feeditem, cfg *config.Confi
}
defer writer.Close()
- if cfg.WithPartHtml() {
- feed.buildBody(&item)
+ if item.feed.Global.WithPartHtml() {
+ item.buildBody()
var relWriter *message.Writer
if len(item.images) > 0 {
@@ -138,13 +142,13 @@ func writeToBuffer(b *bytes.Buffer, feed *Feed, item feeditem, cfg *config.Confi
relWriter = writer
}
- if err = writeHtmlPart(relWriter, item); err != nil {
+ if err = item.writeHtmlPart(relWriter); err != nil {
return err
}
for idx, img := range item.images {
cid := cidNr(idx + 1)
- if err = writeImagePart(relWriter, img, cid); err != nil {
+ if err = img.writeImagePart(relWriter, cid); err != nil {
return err
}
}
@@ -155,23 +159,23 @@ func writeToBuffer(b *bytes.Buffer, feed *Feed, item feeditem, cfg *config.Confi
return nil
}
-func asMail(feed *Feed, item feeditem, cfg *config.Config) (string, error) {
+func (item *item) asMail() (string, error) {
var b bytes.Buffer
- if err := writeToBuffer(&b, feed, item, cfg); err != nil {
+ if err := item.writeToBuffer(&b); err != nil {
return "", err
}
return b.String(), nil
}
-func (feed *Feed) ToMails(cfg *config.Config) ([]string, error) {
+func (feed *Feed) ToMails() ([]string, error) {
var (
err error
mails = make([]string, len(feed.items))
)
for idx := range feed.items {
- if mails[idx], err = asMail(feed, feed.items[idx], cfg); err != nil {
+ if mails[idx], err = feed.items[idx].asMail(); err != nil {
return nil, fmt.Errorf("creating mails for %s: %w", feed.Name, err)
}
}
@@ -228,11 +232,8 @@ func getBody(content, description string, bodyCfg config.Body) string {
}
}
-func (feed *Feed) messageId(item feeditem) string {
- return fmt.Sprintf("<feed#%s#%s@%s>", feed.cached.ID(), item.itemId, config.Hostname())
-}
-
-func (feed *Feed) buildBody(item *feeditem) {
+func (item *item) buildBody() {
+ feed := item.feed
body := getBody(item.Item.Content, item.Item.Description, feed.Body)
if !feed.InclImages {
diff --git a/internal/feed/parse.go b/internal/feed/parse.go
index 435c0ed..dfb447a 100644
--- a/internal/feed/parse.go
+++ b/internal/feed/parse.go
@@ -41,7 +41,7 @@ func httpClient(disableTLS bool) *http.Client {
return stdHTTPClient
}
-func parseFeed(feed *Feed) error {
+func (feed *Feed) parse() error {
ctx, cancel := context(feed.Global.Timeout)
defer cancel()
@@ -54,9 +54,9 @@ func parseFeed(feed *Feed) error {
}
feed.feed = parsedFeed
- feed.items = make([]feeditem, len(parsedFeed.Items))
- for idx, item := range parsedFeed.Items {
- feed.items[idx] = feeditem{Feed: parsedFeed, Item: item, itemId: shortuuid.New()}
+ feed.items = make([]item, len(parsedFeed.Items))
+ for idx, feedItem := range parsedFeed.Items {
+ feed.items[idx] = item{Feed: parsedFeed, Item: feedItem, itemId: shortuuid.New(), feed: feed}
}
return nil
}
@@ -64,7 +64,7 @@ func parseFeed(feed *Feed) error {
func handleFeed(feed *Feed) {
log.Printf("Fetching %s from %s", feed.Name, feed.Url)
- err := parseFeed(feed)
+ err := feed.parse()
if err != nil {
if feed.cached.Failures() >= feed.Global.MaxFailures {
log.Error(err)