mirror of
https://github.com/makew0rld/amfora.git
synced 2025-02-02 15:07:34 -05:00
Switch subscription-based naming
This commit is contained in:
parent
ba28b2b5f9
commit
f6e89fdaa1
2
NOTES.md
2
NOTES.md
@ -1,6 +1,6 @@
|
||||
# Notes
|
||||
|
||||
## Feeds (temp)
|
||||
## Subscriptions (temp)
|
||||
- TODO: remove all logger lines
|
||||
|
||||
## Issues
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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" {
|
||||
|
@ -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.
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
@ -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
|
||||
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user