diff --git a/NOTES.md b/NOTES.md index 0ed9778..57b0ee2 100644 --- a/NOTES.md +++ b/NOTES.md @@ -1,6 +1,6 @@ # Notes -## Feeds (temp) +## Subscriptions (temp) - TODO: remove all logger lines ## Issues diff --git a/README.md b/README.md index 667e750..28a3ad1 100644 --- a/README.md +++ b/README.md @@ -128,9 +128,9 @@ Features in *italics* are in the master branch, but not in the latest release. - Manage and browse them - Similar to [Kristall](https://github.com/MasterQ32/kristall) - https://lists.orbitalfox.eu/archives/gemini/2020/001400.html -- [x] Subscribe to feeds and display them - - Tracking page changes is also supported +- [x] Subscriptions - RSS, Atom, and [JSON Feeds](https://jsonfeed.org/) are all supported + - So is tracking any page to be notified when it changes - [ ] Stream support - [ ] Table of contents for pages - [ ] History browser diff --git a/amfora.go b/amfora.go index 25d9365..e3c5690 100644 --- a/amfora.go +++ b/amfora.go @@ -7,8 +7,8 @@ import ( "github.com/makeworld-the-better-one/amfora/client" "github.com/makeworld-the-better-one/amfora/config" "github.com/makeworld-the-better-one/amfora/display" - "github.com/makeworld-the-better-one/amfora/feeds" "github.com/makeworld-the-better-one/amfora/logger" + "github.com/makeworld-the-better-one/amfora/subscriptions" ) var ( @@ -45,9 +45,9 @@ func main() { fmt.Fprintf(os.Stderr, "Config error: %v\n", err) os.Exit(1) } - err = feeds.Init() + err = subscriptions.Init() if err != nil { - fmt.Fprintf(os.Stderr, "feeds.json error: %v\n", err) + fmt.Fprintf(os.Stderr, "subscriptions.json error: %v\n", err) os.Exit(1) } diff --git a/config/config.go b/config/config.go index 65b2772..e32654b 100644 --- a/config/config.go +++ b/config/config.go @@ -39,9 +39,9 @@ var bkmkPath string var DownloadsDir string -// Feeds -var feedDir string -var FeedPath string +// Subscriptions +var subscriptionDir string +var SubscriptionPath string // Command for opening HTTP(S) URLs in the browser, from "a-general.http" in config. var HTTPCommand []string @@ -103,18 +103,18 @@ func Init() error { // Feeds dir and path if runtime.GOOS == "windows" { // In APPDATA beside other Amfora files - feedDir = amforaAppData + subscriptionDir = amforaAppData } else { // XDG data dir on POSIX systems xdg_data, ok := os.LookupEnv("XDG_DATA_HOME") if ok && strings.TrimSpace(xdg_data) != "" { - feedDir = filepath.Join(xdg_data, "amfora") + subscriptionDir = filepath.Join(xdg_data, "amfora") } else { // Default to ~/.local/share/amfora - feedDir = filepath.Join(home, ".local", "share", "amfora") + subscriptionDir = filepath.Join(home, ".local", "share", "amfora") } } - FeedPath = filepath.Join(feedDir, "feeds.json") + SubscriptionPath = filepath.Join(subscriptionDir, "subscriptions.json") // *** Create necessary files and folders *** @@ -152,7 +152,7 @@ func Init() error { f.Close() } // Feeds - err = os.MkdirAll(feedDir, 0755) + err = os.MkdirAll(subscriptionDir, 0755) if err != nil { return err } @@ -234,9 +234,9 @@ func Init() error { viper.SetDefault("url-handlers.other", "off") viper.SetDefault("cache.max_size", 0) viper.SetDefault("cache.max_pages", 20) - viper.SetDefault("feeds.popup", true) - viper.SetDefault("feeds.update_interval", 1800) - viper.SetDefault("feeds.workers", 3) + viper.SetDefault("subscriptions.popup", true) + viper.SetDefault("subscriptions.update_interval", 1800) + viper.SetDefault("subscriptions.workers", 3) viper.SetConfigFile(configPath) viper.SetConfigType("toml") diff --git a/config/default.go b/config/default.go index b3dca36..705664e 100644 --- a/config/default.go +++ b/config/default.go @@ -135,22 +135,22 @@ max_pages = 30 # The maximum number of pages the cache will store # Note that HTTP and HTTPS are treated as separate protocols here. -[feeds] +[subscriptions] # For tracking feeds and pages # Whether a pop-up appears when viewing a potential feed popup = true -# How often to check for new feeds and pages in the background, in seconds. -# Note Amfora will check for updates on browser start anyway. -# Set it to 0 or below to disable this feature. You can still update individual -# feeds manually, or just restart the browser to update all of them. +# How often to check for updates to subscriptions in the background, in seconds. +# Set it to 0 to disable this feature. You can still update individual feeds +# manually, or restart the browser. +# +# Note Amfora will check for updates on browser start no matter what this setting is. update_interval = 1800 # 30 mins -# How many pages/feeds can be checked at the same time when updating. -# If you are tracking many feeds and pages you may want to increase this for -# faster update times. -# Any value below 1 will be corrected to 1. +# How many subscriptions can be checked at the same time when updating. +# If you have many subscriptions you may want to increase this for faster +# update times. Any value below 1 will be corrected to 1. workers = 3 @@ -212,8 +212,8 @@ workers = 3 # yesno_modal_text # tofu_modal_bg # tofu_modal_text -# feed_modal_bg -# feed_modal_text +# subscription_modal_bg +# subscription_modal_text # input_modal_bg # input_modal_text diff --git a/config/theme.go b/config/theme.go index 71f42dc..9bb05d7 100644 --- a/config/theme.go +++ b/config/theme.go @@ -26,20 +26,20 @@ var theme = map[string]tcell.Color{ "btn_bg": tcell.ColorNavy, // All modal buttons "btn_text": tcell.ColorWhite, - "dl_choice_modal_bg": tcell.ColorPurple, - "dl_choice_modal_text": tcell.ColorWhite, - "dl_modal_bg": tcell.Color130, // xterm:DarkOrange3, #af5f00 - "dl_modal_text": tcell.ColorWhite, - "info_modal_bg": tcell.ColorGray, - "info_modal_text": tcell.ColorWhite, - "error_modal_bg": tcell.ColorMaroon, - "error_modal_text": tcell.ColorWhite, - "yesno_modal_bg": tcell.ColorPurple, - "yesno_modal_text": tcell.ColorWhite, - "tofu_modal_bg": tcell.ColorMaroon, - "tofu_modal_text": tcell.ColorWhite, - "feed_modal_bg": tcell.Color61, // xterm:SlateBlue3, #5f5faf - "feed_modal_text": tcell.ColorWhite, + "dl_choice_modal_bg": tcell.ColorPurple, + "dl_choice_modal_text": tcell.ColorWhite, + "dl_modal_bg": tcell.Color130, // xterm:DarkOrange3, #af5f00 + "dl_modal_text": tcell.ColorWhite, + "info_modal_bg": tcell.ColorGray, + "info_modal_text": tcell.ColorWhite, + "error_modal_bg": tcell.ColorMaroon, + "error_modal_text": tcell.ColorWhite, + "yesno_modal_bg": tcell.ColorPurple, + "yesno_modal_text": tcell.ColorWhite, + "tofu_modal_bg": tcell.ColorMaroon, + "tofu_modal_text": tcell.ColorWhite, + "subscription_modal_bg": tcell.Color61, // xterm:SlateBlue3, #5f5faf + "subscription_modal_text": tcell.ColorWhite, "input_modal_bg": tcell.ColorGreen, "input_modal_text": tcell.ColorWhite, diff --git a/default-config.toml b/default-config.toml index 09a4c61..4ba508d 100644 --- a/default-config.toml +++ b/default-config.toml @@ -132,22 +132,22 @@ max_pages = 30 # The maximum number of pages the cache will store # Note that HTTP and HTTPS are treated as separate protocols here. -[feeds] +[subscriptions] # For tracking feeds and pages # Whether a pop-up appears when viewing a potential feed popup = true -# How often to check for new feeds and pages in the background, in seconds. -# Note Amfora will check for updates on browser start anyway. -# Set it to 0 or below to disable this feature. You can still update individual -# feeds manually, or just restart the browser to update all of them. +# How often to check for updates to subscriptions in the background, in seconds. +# Set it to 0 to disable this feature. You can still update individual feeds +# manually, or restart the browser. +# +# Note Amfora will check for updates on browser start no matter what this setting is. update_interval = 1800 # 30 mins -# How many pages/feeds can be checked at the same time when updating. -# If you are tracking many feeds and pages you may want to increase this for -# faster update times. -# Any value below 1 will be corrected to 1. +# How many subscriptions can be checked at the same time when updating. +# If you have many subscriptions you may want to increase this for faster +# update times. Any value below 1 will be corrected to 1. workers = 3 @@ -209,8 +209,8 @@ workers = 3 # yesno_modal_text # tofu_modal_bg # tofu_modal_text -# feed_modal_bg -# feed_modal_text +# subscription_modal_bg +# subscription_modal_text # input_modal_bg # input_modal_text diff --git a/display/display.go b/display/display.go index eaf48d3..919cfb8 100644 --- a/display/display.go +++ b/display/display.go @@ -294,11 +294,11 @@ func Init() { } return nil case tcell.KeyCtrlA: - Feeds(tabs[curTab]) - tabs[curTab].addToHistory("about:feeds") + Subscriptions(tabs[curTab]) + tabs[curTab].addToHistory("about:subscriptions") return nil case tcell.KeyCtrlX: - go addFeed() + go addSubscription() return nil case tcell.KeyRune: // Regular key was sent @@ -583,9 +583,9 @@ func URL(u string) { tabs[curTab].addToHistory("about:bookmarks") return } - if u == "about:feeds" { //nolint:goconst - Feeds(tabs[curTab]) - tabs[curTab].addToHistory("about:feeds") + if u == "about:subscriptions" { //nolint:goconst + Subscriptions(tabs[curTab]) + tabs[curTab].addToHistory("about:subscriptions") return } if u == "about:newtab" { diff --git a/display/help.go b/display/help.go index 9a4c8de..4128d39 100644 --- a/display/help.go +++ b/display/help.go @@ -42,8 +42,8 @@ Ctrl-R, R|Reload a page, discarding the cached version. Ctrl-B|View bookmarks Ctrl-D|Add, change, or remove a bookmark for the current page. Ctrl-S|Save the current page to your downloads. -Ctrl-A|View tracked feeds and pages. -Ctrl-X|Track or update the current feed/page. +Ctrl-A|View subscriptions +Ctrl-X|Add or update a subscription q, Ctrl-Q|Quit Ctrl-C|Hard quit. This can be used when in the middle of downloading, |for example. diff --git a/display/newtab.go b/display/newtab.go index ff212d0..dde3c2f 100644 --- a/display/newtab.go +++ b/display/newtab.go @@ -18,7 +18,7 @@ You can customize this page by creating a gemtext file called newtab.gmi, in Amf Happy browsing! => about:bookmarks Bookmarks -=> about:feeds Feed and Page Tracking +=> about:subscriptions Feed and Page Tracking => //gemini.circumlunar.space Project Gemini => https://github.com/makeworld-the-better-one/amfora Amfora homepage [HTTPS] diff --git a/display/private.go b/display/private.go index ba7d976..a2248e4 100644 --- a/display/private.go +++ b/display/private.go @@ -16,9 +16,9 @@ import ( "github.com/makeworld-the-better-one/amfora/cache" "github.com/makeworld-the-better-one/amfora/client" "github.com/makeworld-the-better-one/amfora/config" - "github.com/makeworld-the-better-one/amfora/feeds" "github.com/makeworld-the-better-one/amfora/renderer" "github.com/makeworld-the-better-one/amfora/structs" + "github.com/makeworld-the-better-one/amfora/subscriptions" "github.com/makeworld-the-better-one/amfora/webbrowser" "github.com/makeworld-the-better-one/go-gemini" "github.com/makeworld-the-better-one/go-isemoji" @@ -39,9 +39,9 @@ func followLink(t *tab, prev, next string) { t.addToHistory("about:bookmarks") return } - if next == "about:feeds" { - Feeds(t) - t.addToHistory("about:feeds") + if next == "about:subscriptions" { + Subscriptions(t) + t.addToHistory("about:subscriptions") return } if strings.HasPrefix(next, "about:") { @@ -340,7 +340,7 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) { t.mode = tabModeDone go func(p *structs.Page) { - if b && t.hasContent() && !feeds.IsTracked(s) && viper.GetBool("feeds.popup") { + if b && t.hasContent() && !subscriptions.IsSubscribed(s) && viper.GetBool("subscriptions.popup") { // The current page might be an untracked feed, and the user wants // to be notified in such cases. @@ -365,9 +365,9 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) { Bookmarks(t) return ret("about:bookmarks", true) } - if u == "about:feeds" { - Feeds(t) - return ret("about:feeds", true) + if u == "about:subscriptions" { + Subscriptions(t) + return ret("about:subscriptions", true) } u = normalizeURL(u) @@ -613,10 +613,10 @@ func handleURL(t *tab, u string, numRedirects int) (string, bool) { // First see if it's a feed, and ask the user about adding it if it is filename := path.Base(parsed.Path) mediatype, _, _ := mime.ParseMediaType(res.Meta) - feed, ok := feeds.GetFeed(mediatype, filename, res.Body) + feed, ok := subscriptions.GetFeed(mediatype, filename, res.Body) if ok { go func() { - added := addFeedDirect(u, feed, feeds.IsTracked(u)) + added := addFeedDirect(u, feed, subscriptions.IsSubscribed(u)) if !added { // Otherwise offer download choices go dlChoice("That file could not be displayed. What would you like to do?", u, res) diff --git a/display/feeds.go b/display/subscriptions.go similarity index 59% rename from display/feeds.go rename to display/subscriptions.go index aacd1b7..58bdd9a 100644 --- a/display/feeds.go +++ b/display/subscriptions.go @@ -11,15 +11,15 @@ import ( "github.com/gdamore/tcell" "github.com/makeworld-the-better-one/amfora/cache" "github.com/makeworld-the-better-one/amfora/config" - "github.com/makeworld-the-better-one/amfora/feeds" "github.com/makeworld-the-better-one/amfora/logger" "github.com/makeworld-the-better-one/amfora/renderer" "github.com/makeworld-the-better-one/amfora/structs" + "github.com/makeworld-the-better-one/amfora/subscriptions" "github.com/mmcdole/gofeed" "github.com/spf13/viper" ) -var feedPageUpdated time.Time +var subscriptionPageUpdated time.Time // toLocalDay truncates the provided time to a date only, // but converts to the local time first. @@ -29,21 +29,21 @@ func toLocalDay(t time.Time) time.Time { } // Feeds displays the feeds page on the current tab. -func Feeds(t *tab) { - logger.Log.Println("display.Feeds called") +func Subscriptions(t *tab) { + logger.Log.Println("display.Subscriptions called") // Retrieve cached version if there hasn't been any updates - p, ok := cache.GetPage("about:feeds") - if feedPageUpdated.After(feeds.LastUpdated) && ok { - logger.Log.Println("using cached feeds page") + p, ok := cache.GetPage("about:subscriptions") + if subscriptionPageUpdated.After(subscriptions.LastUpdated) && ok { + logger.Log.Println("using cached subscriptions page") setPage(t, p) t.applyBottomBar() return } - logger.Log.Println("started rendering feeds page") + logger.Log.Println("started rendering subscriptions page") - feedPageRaw := "# Feeds & Pages\n\n" + + subscriptionPageRaw := "# Subscriptions\n\n" + "See the help (by pressing ?) for details on how to use this page.\n\n" + "If you just opened Amfora then updates will appear incrementally. Reload the page to see them.\n" @@ -58,7 +58,7 @@ func Feeds(t *tab) { // the UTC timezone is specified. I believe gemfeed does this. curDay := toLocalDay(time.Now()).Add(26 * time.Hour) - pe := feeds.GetPageEntries() + pe := subscriptions.GetPageEntries() for _, entry := range pe.Entries { // From new to old // Convert to local time, remove sub-day info @@ -67,24 +67,24 @@ func Feeds(t *tab) { if pub.Before(curDay) { // This post is on a new day, add a day header curDay = pub - feedPageRaw += fmt.Sprintf("\n## %s\n\n", curDay.Format("Jan 02, 2006")) + subscriptionPageRaw += fmt.Sprintf("\n## %s\n\n", curDay.Format("Jan 02, 2006")) } if entry.Title == "" || entry.Title == "/" { // Just put author/title // Mainly used for when you're tracking the root domain of a site - feedPageRaw += fmt.Sprintf("=>%s %s\n", entry.URL, entry.Prefix) + subscriptionPageRaw += fmt.Sprintf("=>%s %s\n", entry.URL, entry.Prefix) } else { // Include title and dash - feedPageRaw += fmt.Sprintf("=>%s %s - %s\n", entry.URL, entry.Prefix, entry.Title) + subscriptionPageRaw += fmt.Sprintf("=>%s %s - %s\n", entry.URL, entry.Prefix, entry.Title) } } - content, links := renderer.RenderGemini(feedPageRaw, textWidth(), leftMargin(), false) + content, links := renderer.RenderGemini(subscriptionPageRaw, textWidth(), leftMargin(), false) page := structs.Page{ - Raw: feedPageRaw, + Raw: subscriptionPageRaw, Content: content, Links: links, - URL: "about:feeds", + URL: "about:subscriptions", Width: termW, Mediatype: structs.TextGemini, } @@ -92,26 +92,26 @@ func Feeds(t *tab) { setPage(t, &page) t.applyBottomBar() - feedPageUpdated = time.Now() + subscriptionPageUpdated = time.Now() - logger.Log.Println("done rendering feeds page") + logger.Log.Println("done rendering subscriptions page") } -// openFeedModal displays the "Add feed/page" modal -// It returns whether the user wanted to add the feed/page. -// The tracked arg specifies whether this feed/page is already -// being tracked. -func openFeedModal(validFeed, tracked bool) bool { +// openSubscriptionModal displays the "Add subscription" modal +// It returns whether the user wanted to subscribe to feed/page. +// The subscribed arg specifies whether this feed/page is already +// subscribed to. +func openSubscriptionModal(validFeed, subscribed bool) bool { logger.Log.Println("display.openFeedModal called") // Reuses yesNoModal if viper.GetBool("a-general.color") { yesNoModal. - SetBackgroundColor(config.GetColor("feed_modal_bg")). - SetTextColor(config.GetColor("feed_modal_text")) + SetBackgroundColor(config.GetColor("subscription_modal_bg")). + SetTextColor(config.GetColor("subscription_modal_text")) yesNoModal.GetFrame(). - SetBorderColor(config.GetColor("feed_modal_text")). - SetTitleColor(config.GetColor("feed_modal_text")) + SetBorderColor(config.GetColor("subscription_modal_text")). + SetTitleColor(config.GetColor("subscription_modal_text")) } else { yesNoModal. SetBackgroundColor(tcell.ColorBlack). @@ -121,18 +121,18 @@ func openFeedModal(validFeed, tracked bool) bool { SetTitleColor(tcell.ColorWhite) } if validFeed { - yesNoModal.GetFrame().SetTitle("Feed Tracking") - if tracked { - yesNoModal.SetText("This is already being tracked. Would you like to manually update it?") + yesNoModal.GetFrame().SetTitle("Feed Subscription") + if subscribed { + yesNoModal.SetText("You are already subscribed to this feed. Would you like to manually update it?") } else { - yesNoModal.SetText("Would you like to start tracking this feed?") + yesNoModal.SetText("Would you like to subscribe to this feed?") } } else { - yesNoModal.GetFrame().SetTitle("Page Tracking") - if tracked { - yesNoModal.SetText("This is already being tracked. Would you like to manually update it?") + yesNoModal.GetFrame().SetTitle("Page Subscription") + if subscribed { + yesNoModal.SetText("You are already subscribed to this page. Would you like to manually update it?") } else { - yesNoModal.SetText("Would you like to start tracking this page?") + yesNoModal.SetText("Would you like to subscribe to this page?") } } @@ -148,12 +148,12 @@ func openFeedModal(validFeed, tracked bool) bool { return resp } -// getFeedFromPage is like feeds.GetFeed but takes a structs.Page as input. +// getFeedFromPage is like subscriptions.GetFeed but takes a structs.Page as input. func getFeedFromPage(p *structs.Page) (*gofeed.Feed, bool) { parsed, _ := url.Parse(p.URL) filename := path.Base(parsed.Path) r := strings.NewReader(p.Raw) - return feeds.GetFeed(p.RawMediatype, filename, r) + return subscriptions.GetFeed(p.RawMediatype, filename, r) } // addFeedDirect is only for adding feeds, not pages. @@ -166,8 +166,8 @@ func getFeedFromPage(p *structs.Page) (*gofeed.Feed, bool) { func addFeedDirect(u string, feed *gofeed.Feed, tracked bool) bool { logger.Log.Println("display.addFeedDirect called") - if openFeedModal(true, tracked) { - err := feeds.AddFeed(u, feed) + if openSubscriptionModal(true, tracked) { + err := subscriptions.AddFeed(u, feed) if err != nil { Error("Feed Error", err.Error()) } @@ -176,10 +176,10 @@ func addFeedDirect(u string, feed *gofeed.Feed, tracked bool) bool { return false } -// addFeed goes through the process of tracking the current page/feed. +// addFeed goes through the process of subscribing to the current page/feed. // It is the high-level way of doing it. It should be called in a goroutine. -func addFeed() { - logger.Log.Println("display.addFeed called") +func addSubscription() { + logger.Log.Println("display.addSubscription called") t := tabs[curTab] p := t.page @@ -190,15 +190,15 @@ func addFeed() { } feed, isFeed := getFeedFromPage(p) - tracked := feeds.IsTracked(p.URL) + tracked := subscriptions.IsSubscribed(p.URL) - if openFeedModal(isFeed, tracked) { + if openSubscriptionModal(isFeed, tracked) { var err error if isFeed { - err = feeds.AddFeed(p.URL, feed) + err = subscriptions.AddFeed(p.URL, feed) } else { - err = feeds.AddPage(p.URL, strings.NewReader(p.Raw)) + err = subscriptions.AddPage(p.URL, strings.NewReader(p.Raw)) } if err != nil { diff --git a/feeds/entries.go b/subscriptions/entries.go similarity index 96% rename from feeds/entries.go rename to subscriptions/entries.go index 9e40998..8729867 100644 --- a/feeds/entries.go +++ b/subscriptions/entries.go @@ -1,4 +1,4 @@ -package feeds +package subscriptions import ( "net/url" @@ -10,7 +10,7 @@ import ( ) // This file contains funcs for creating PageEntries, which -// are consumed by display/feeds.go +// are consumed by display/subscriptions.go // getURL returns a URL to be used in a PageEntry, from a // list of URLs for that item. It prefers gemini URLs, then @@ -42,7 +42,7 @@ func getURL(urls []string) string { // 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") + logger.Log.Println("subscriptions.GetPageEntries called") var pe PageEntries diff --git a/feeds/structs.go b/subscriptions/structs.go similarity index 91% rename from feeds/structs.go rename to subscriptions/structs.go index 6fa2aa9..ba6fc16 100644 --- a/feeds/structs.go +++ b/subscriptions/structs.go @@ -1,4 +1,4 @@ -package feeds +package subscriptions import ( "sync" @@ -77,8 +77,8 @@ var data = jsonData{ Pages: make(map[string]*pageJSON), } -// PageEntry is a single item on a feed page. -// It is used both for tracked feeds and pages. +// PageEntry is a single item on a subscriptions page. +// It is used for both feeds and pages. type PageEntry struct { Prefix string // Feed/log title, author, etc - something before the post title Title string @@ -86,9 +86,10 @@ type PageEntry struct { Published time.Time } -// PageEntries is new-to-old list of Entry structs, used to create a feed page. -// It should always be assumed to be sorted when used in other packages. -// Sorted by post time, from newest to oldest. +// PageEntries is new-to-old list of Entry structs, used to create a +// subscriptions page. +// It should always be assumed to be sorted when used in other packages, +// by post time, from newest to oldest. type PageEntries struct { Entries []*PageEntry } diff --git a/feeds/feeds.go b/subscriptions/subscriptions.go similarity index 80% rename from feeds/feeds.go rename to subscriptions/subscriptions.go index 61b532a..bdf4f8c 100644 --- a/feeds/feeds.go +++ b/subscriptions/subscriptions.go @@ -1,4 +1,4 @@ -package feeds +package subscriptions import ( "crypto/sha256" @@ -31,15 +31,15 @@ var ( ErrNotFeed = errors.New("not a valid feed") ) -var writeMu = sync.Mutex{} // Prevent concurrent writes to feeds.json file +var writeMu = sync.Mutex{} // Prevent concurrent writes to subscriptions.json file // LastUpdated is the time when the in-memory data was last updated. -// It can be used to know if the feed page should be regenerated. +// It can be used to know if the subscriptions page should be regenerated. var LastUpdated time.Time // Init should be called after config.Init. func Init() error { - f, err := os.Open(config.FeedPath) + f, err := os.Open(config.SubscriptionPath) if err == nil { // File exists and could be opened defer f.Close() @@ -50,26 +50,26 @@ func Init() error { dec := json.NewDecoder(f) err = dec.Decode(&data) if err != nil && err != io.EOF { - return fmt.Errorf("feeds.json is corrupted: %w", err) //nolint:goerr113 + return fmt.Errorf("subscriptions.json is corrupted: %w", err) //nolint:goerr113 } } } else if !os.IsNotExist(err) { // There's an error opening the file, but it's not bc is doesn't exist - return fmt.Errorf("open feeds.json error: %w", err) //nolint:goerr113 + return fmt.Errorf("open subscriptions.json error: %w", err) //nolint:goerr113 } LastUpdated = time.Now() - if viper.GetInt("feeds.update_interval") > 0 { - // Update feeds and pages every so often + if viper.GetInt("subscriptions.update_interval") > 0 { + // Update subscriptions every so often go func() { for { updateAll() - time.Sleep(time.Duration(viper.GetInt("feeds.update_interval")) * time.Second) + time.Sleep(time.Duration(viper.GetInt("subscriptions.update_interval")) * time.Second) } }() } else { - // User disabled automatic feed/page updates + // User disabled automatic updates // So just update once at the beginning go updateAll() } @@ -77,9 +77,10 @@ func Init() error { return nil } -// IsTracked returns true if the feed/page URL is already being tracked. -func IsTracked(url string) bool { - logger.Log.Println("feeds.IsTracked called") +// IsSubscribed returns true if the URL is already subscribed to, +// whether a feed or page. +func IsSubscribed(url string) bool { + logger.Log.Println("subscriptions.IsSubscribed called") data.feedMu.RLock() for u := range data.Feeds { @@ -103,7 +104,7 @@ func IsTracked(url string) bool { // GetFeed returns a Feed object and a bool indicating whether the passed // content was actually recognized as a feed. func GetFeed(mediatype, filename string, r io.Reader) (*gofeed.Feed, bool) { - logger.Log.Println("feeds.GetFeed called") + logger.Log.Println("subscriptions.GetFeed called") if r == nil { return nil, false @@ -124,14 +125,14 @@ func GetFeed(mediatype, filename string, r io.Reader) (*gofeed.Feed, bool) { } func writeJSON() error { - logger.Log.Println("feeds.writeJSON called") + logger.Log.Println("subscriptions.writeJSON called") writeMu.Lock() defer writeMu.Unlock() - f, err := os.OpenFile(config.FeedPath, os.O_WRONLY|os.O_CREATE, 0666) + f, err := os.OpenFile(config.SubscriptionPath, os.O_WRONLY|os.O_CREATE, 0666) if err != nil { - logger.Log.Println("feeds.writeJSON error", err) + logger.Log.Println("subscriptions.writeJSON error", err) return err } defer f.Close() @@ -140,12 +141,12 @@ func writeJSON() error { enc.SetIndent("", " ") data.Lock() - logger.Log.Println("feeds.writeJSON acquired data lock") + logger.Log.Println("subscriptions.writeJSON acquired data lock") err = enc.Encode(&data) data.Unlock() if err != nil { - logger.Log.Println("feeds.writeJSON error", err) + logger.Log.Println("subscriptions.writeJSON error", err) } return err @@ -155,7 +156,7 @@ func writeJSON() error { // It can be used to update a feed for a URL, although the package // will handle that on its own. func AddFeed(url string, feed *gofeed.Feed) error { - logger.Log.Println("feeds.AddFeed called") + logger.Log.Println("subscriptions.AddFeed called") if feed == nil { panic("feed is nil") @@ -205,7 +206,7 @@ func AddFeed(url string, feed *gofeed.Feed) error { // It can be used to update the page as well, although the package // will handle that on its own. func AddPage(url string, r io.Reader) error { - logger.Log.Println("feeds.AddPage called") + logger.Log.Println("subscriptions.AddPage called") if r == nil { return nil @@ -241,7 +242,7 @@ func AddPage(url string, r io.Reader) error { } func updateFeed(url string) error { - logger.Log.Println("feeds.updateFeed called") + logger.Log.Println("subscriptions.updateFeed called") res, err := client.Fetch(url) if err != nil { @@ -268,7 +269,7 @@ func updateFeed(url string) error { } func updatePage(url string) error { - logger.Log.Println("feeds.updatePage called") + logger.Log.Println("subscriptions.updatePage called") res, err := client.Fetch(url) if err != nil { @@ -286,10 +287,10 @@ func updatePage(url string) error { return AddPage(url, res.Body) } -// updateAll updates all feeds and pages using workers. +// updateAll updates all subscriptions using workers. // It only returns once all the workers are done. func updateAll() { - logger.Log.Println("feeds.updateAll called") + logger.Log.Println("subscriptions.updateAll called") // TODO: Is two goroutines the right amount? @@ -318,7 +319,7 @@ func updateAll() { return } - numWorkers := viper.GetInt("feeds.workers") + numWorkers := viper.GetInt("subscriptions.workers") if numWorkers < 1 { numWorkers = 1 }