diff --git a/NOTES.md b/NOTES.md index da2c060..bd6951a 100644 --- a/NOTES.md +++ b/NOTES.md @@ -1,7 +1,8 @@ # Notes ## Feeds (temp) -- Feed page doesn't update automatically if you add a feed by bottom bar URL while already on the feed page +- Support multiple links in Atom feeds + - Display gemini one if it exist, then HTTP(S), then whatever is first - TODO: remove all logger lines ## Issues diff --git a/feeds/entries.go b/feeds/entries.go new file mode 100644 index 0000000..9e40998 --- /dev/null +++ b/feeds/entries.go @@ -0,0 +1,148 @@ +package feeds + +import ( + "net/url" + "sort" + "strings" + "time" + + "github.com/makeworld-the-better-one/amfora/logger" +) + +// This file contains funcs for creating PageEntries, which +// are consumed by display/feeds.go + +// getURL returns a URL to be used in a PageEntry, from a +// list of URLs for that item. It prefers gemini URLs, then +// HTTP(S), then by order. +func getURL(urls []string) string { + if len(urls) == 0 { + return "" + } + + var firstHTTP string + for _, u := range urls { + if strings.HasPrefix(u, "gemini://") { + return u + } + if (strings.HasPrefix(u, "http://") || strings.HasPrefix(u, "https://")) && firstHTTP == "" { + // First HTTP(S) URL in the list + firstHTTP = u + } + } + if firstHTTP != "" { + return firstHTTP + } + return urls[0] +} + +// GetPageEntries returns the current list of PageEntries +// for use in rendering a page. +// The contents of the returned entries will never change, +// so this function needs to be called again to get updates. +// It always returns sorted entries - by post time, from newest to oldest. +func GetPageEntries() *PageEntries { + logger.Log.Println("feeds.GetPageEntries called") + + var pe PageEntries + + data.RLock() + + for _, feed := range data.Feeds { + for _, item := range feed.Items { + if item.Links == nil || len(item.Links) == 0 { + // Ignore items without links + continue + } + + // Set pub + + var pub time.Time + + // Try to use updated time first, then published + + if !item.UpdatedParsed.IsZero() { + pub = *item.UpdatedParsed + } else if !item.PublishedParsed.IsZero() { + pub = *item.PublishedParsed + } else { + // No time on the post + pub = time.Now() + } + + // Set prefix + + // Prefer using the feed title over anything else. + // Many feeds in Gemini only have this due to gemfeed's default settings. + prefix := feed.Title + + if prefix == "" { + // feed.Title was empty + + if item.Author != nil { + // Prefer using the item author over the feed author + prefix = item.Author.Name + } else { + if feed.Author != nil { + prefix = feed.Author.Name + } else { + prefix = "[author unknown]" + } + } + } else { + // There's already a title, so add the author (if exists) to + // the end of the title in parentheses. + // Don't add the author if it's the same as the title. + + if item.Author != nil && item.Author.Name != prefix { + // Prefer using the item author over the feed author + prefix += " (" + item.Author.Name + ")" + } else if feed.Author != nil && feed.Author.Name != prefix { + prefix += " (" + feed.Author.Name + ")" + } + } + + pe.Entries = append(pe.Entries, &PageEntry{ + Prefix: prefix, + Title: item.Title, + URL: getURL(item.Links), + Published: pub, + }) + } + } + + for u, page := range data.Pages { + parsed, _ := url.Parse(u) + + // Path is title + title := parsed.Path + if strings.HasPrefix(title, "/~") { + // A user dir + title = title[2:] // Remove beginning slash and tilde + // Remove trailing slash if the root of a user dir is being tracked + if strings.Count(title, "/") <= 1 && title[len(title)-1] == '/' { + title = title[:len(title)-1] + } + } else if strings.HasPrefix(title, "/users/") { + // "/users/" is removed for aesthetics when tracking hosted users + title = strings.TrimPrefix(title, "/users/") + title = strings.TrimPrefix(title, "~") // Remove leading tilde + // Remove trailing slash if the root of a user dir is being tracked + if strings.Count(title, "/") <= 1 && title[len(title)-1] == '/' { + title = title[:len(title)-1] + } + } + + pe.Entries = append(pe.Entries, &PageEntry{ + Prefix: parsed.Host, + Title: title, + URL: u, + Published: page.Changed, + }) + } + + data.RUnlock() + + sort.Sort(&pe) + return &pe +} diff --git a/feeds/feeds.go b/feeds/feeds.go index 35c318c..61b532a 100644 --- a/feeds/feeds.go +++ b/feeds/feeds.go @@ -7,11 +7,9 @@ import ( "fmt" "io" "mime" - urlPkg "net/url" "os" "path" "reflect" - "sort" "strings" "sync" "time" @@ -170,6 +168,8 @@ func AddFeed(url string, feed *gofeed.Feed) error { feed.DublinCoreExt = nil feed.ITunesExt = nil feed.Custom = nil + feed.Link = "" + feed.Links = nil for _, item := range feed.Items { item.Description = "" item.Content = "" @@ -180,6 +180,7 @@ func AddFeed(url string, feed *gofeed.Feed) error { item.ITunesExt = nil item.Extensions = nil item.Custom = nil + item.Link = "" // Links is used instead } data.feedMu.Lock() @@ -361,107 +362,3 @@ func updateAll() { wg.Wait() } - -// GetPageEntries returns the current list of PageEntries -// for use in rendering a page. -// The contents of the returned entries will never change, -// so this function needs to be called again to get updates. -// It always returns sorted entries - by post time, from newest to oldest. -func GetPageEntries() *PageEntries { - logger.Log.Println("feeds.GetPageEntries called") - - var pe PageEntries - - data.RLock() - - for _, feed := range data.Feeds { - for _, item := range feed.Items { - - var pub time.Time - - // Try to use updated time first, then published - - if !item.UpdatedParsed.IsZero() { - pub = *item.UpdatedParsed - } else if !item.PublishedParsed.IsZero() { - pub = *item.PublishedParsed - } else { - // No time on the post - pub = time.Now() - } - - // Prefer using the feed title over anything else. - // Many feeds in Gemini only have this due to gemfeed's default settings. - prefix := feed.Title - - if prefix == "" { - // feed.Title was empty - if feed.Author != nil { - // Prefer using the feed author over the item author - prefix = feed.Author.Name - } else { - if item.Author != nil { - prefix = item.Author.Name - } else { - prefix = "[author unknown]" - } - } - } else { - // There's already a title, so add the author (if exists) to - // the end of the title in parentheses. - // Don't add the author if it's the same as the title. - - if feed.Author != nil && feed.Author.Name != prefix { - // Prefer using the feed author over the item author - prefix += " (" + feed.Author.Name + ")" - } else { - if item.Author != nil && item.Author.Name != prefix { - prefix += " (" + item.Author.Name + ")" - } - } - } - - pe.Entries = append(pe.Entries, &PageEntry{ - Prefix: prefix, - Title: item.Title, - URL: item.Link, - Published: pub, - }) - } - } - - for url, page := range data.Pages { - parsed, _ := urlPkg.Parse(url) - - // Path is title - title := parsed.Path - if strings.HasPrefix(title, "/~") { - // A user dir - title = title[2:] // Remove beginning slash and tilde - // Remove trailing slash if the root of a user dir is being tracked - if strings.Count(title, "/") <= 1 && title[len(title)-1] == '/' { - title = title[:len(title)-1] - } - } else if strings.HasPrefix(title, "/users/") { - // "/users/" is removed for aesthetics when tracking hosted users - title = strings.TrimPrefix(title, "/users/") - title = strings.TrimPrefix(title, "~") // Remove leading tilde - // Remove trailing slash if the root of a user dir is being tracked - if strings.Count(title, "/") <= 1 && title[len(title)-1] == '/' { - title = title[:len(title)-1] - } - } - - pe.Entries = append(pe.Entries, &PageEntry{ - Prefix: parsed.Host, - Title: title, - URL: url, - Published: page.Changed, - }) - } - - data.RUnlock() - - sort.Sort(&pe) - return &pe -} diff --git a/feeds/structs.go b/feeds/structs.go index a44b190..6fa2aa9 100644 --- a/feeds/structs.go +++ b/feeds/structs.go @@ -8,7 +8,7 @@ import ( ) /* -Example JSON +Example stored JSON. { "feeds": { diff --git a/go.mod b/go.mod index 63c4281..796274e 100644 --- a/go.mod +++ b/go.mod @@ -27,3 +27,5 @@ require ( gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/ini.v1 v1.57.0 // indirect ) + +replace github.com/mmcdole/gofeed => github.com/makeworld-the-better-one/gofeed v1.1.1-0.20201123002655-c0c6354134fe diff --git a/go.sum b/go.sum index c15d2a0..f26e776 100644 --- a/go.sum +++ b/go.sum @@ -137,6 +137,8 @@ github.com/makeworld-the-better-one/go-gemini v0.9.1 h1:/Vc6Y4Y1aOi4lZIBA1wDe+4N github.com/makeworld-the-better-one/go-gemini v0.9.1/go.mod h1:P7/FbZ+IEIbA/d+A0Y3w2GNgD8SA2AcNv7aDGJbaWG4= github.com/makeworld-the-better-one/go-isemoji v1.1.0 h1:wZBHOKB5zAIgaU2vaWnXFDDhatebB8TySrNVxjVV84g= github.com/makeworld-the-better-one/go-isemoji v1.1.0/go.mod h1:FBjkPl9rr0G4vlZCc+Mr+QcnOfGCTbGWYW8/1sp06I0= +github.com/makeworld-the-better-one/gofeed v1.1.1-0.20201123002655-c0c6354134fe h1:i3b9Qy5z23DcXRnrsMYcM5s9Ng5VIidM1xZd+szuTsY= +github.com/makeworld-the-better-one/gofeed v1.1.1-0.20201123002655-c0c6354134fe/go.mod h1:QQO3maftbOu+hiVOGOZDRLymqGQCos4zxbA4j89gMrE= github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f h1:YEUlTs5gb35UlBLTgqrub9axWTYB3d7/8TxrkJDZpRI= github.com/makeworld-the-better-one/progressbar/v3 v3.3.5-0.20200710151429-125743e22b4f/go.mod h1:X6sxWNi9PBgQybpR4fpXPVD5fm7svLqZTQ5DJuERIoM= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -161,8 +163,6 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA= github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mmcdole/gofeed v1.1.0 h1:T2WrGLVJRV04PY2qwhEJLHCt9JiCtBhb6SmC8ZvJH08= -github.com/mmcdole/gofeed v1.1.0/go.mod h1:PPiVwgDXLlz2N83KB4TrIim2lyYM5Zn7ZWH9Pi4oHUk= github.com/mmcdole/goxpp v0.0.0-20181012175147-0068e33feabf h1:sWGE2v+hO0Nd4yFU/S/mDBM5plIU8v/Qhfz41hkDIAI= github.com/mmcdole/goxpp v0.0.0-20181012175147-0068e33feabf/go.mod h1:pasqhqstspkosTneA62Nc+2p9SOBBYAPbnmRRWPQ0V8= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=