// Copyright (C) 2021 nytpu // SPDX-License-Identifier: AGPL-3.0-or-later // For more license details, see LICENSE or . // This file incorporates code from makeworld's amfora: // https://github.com/makeworld-the-better-one/amfora/blob/master/subscriptions/structs.go // Original source is Copyright 2020 makeworld and is licensed under the // terms of the GNU General Public License Version 3.0. // https://www.gnu.org/licenses/gpl-3.0-standalone.html package core import ( "fmt" "io/ioutil" "os" "path/filepath" "sort" "time" ) // getPageEntries returns a full list of page entries from a FullData. It will // always be sorted from newest to oldest. func (d *FullData) getPageEntries() *PageEntries { var pe PageEntries d.RLock() for _, feed := range d.Feeds { for _, item := range feed.Items { // Ignore items without links if item.Link == "" { continue } var prefix string if feed.Title != "" { prefix = feed.Title } else { prefix = feed.Link } pe.Entries = append(pe.Entries, &PageEntry{ Prefix: prefix, Title: item.Title, Published: item.Published, URL: item.Link, }) } } for _, page := range d.Pages { var prefix string if page.Title != "" { prefix = page.Title } else { prefix = page.Link } pe.Entries = append(pe.Entries, &PageEntry{ Prefix: prefix, Published: page.Updated, URL: page.Link, }) } d.RUnlock() sort.Sort(&pe) return &pe } // toLocalDay truncates the provided time to a date only, but converts to the // local time first. func toLocalDay(t time.Time) time.Time { t = t.Local() return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location()) } func (d *FullData) WriteSubs(dataPath string) error { path := filepath.Join(dataPath, "subscriptions.gmi.new") rawPage := `# subscribed feeds ## Feeds Gemini, Atom, RSS, and JSON feeds from all over. ` d.FeedsMu.RLock() for _, v := range d.Feeds { var link string if v.FeedLink != "" { link = v.FeedLink } else { link = v.Link } rawPage += fmt.Sprintf("=> %v %v\n", link, v.Title) } d.FeedsMu.RUnlock() rawPage += ` ## Pages Watching these pages for any changes that occur. ` d.PagesMu.RLock() for _, v := range d.Pages { rawPage += fmt.Sprintf("=> %v", v.Link) if v.Title != "" { rawPage += fmt.Sprintf(" %v", v.Title) } rawPage += "\n" } d.PagesMu.RUnlock() rawPage += ` --- => https://git.nytpu.com/comitium/about/ aggregated using comitium ` err := ioutil.WriteFile(path, []byte(rawPage), 0666) if err != nil { return err } // if full write was successful then overwrite original err = os.Rename(path, filepath.Join(dataPath, "subscriptions.gmi")) return err } func (d *FullData) WriteFeed(dataPath string) error { path := filepath.Join(dataPath, "feed.gmi.new") rawPage := Header d.RLock() pe := d.getPageEntries() rawPage += fmt.Sprintf("\n=> subscriptions.gmi Currently aggregating %d capsules, gopherholes, and websites.\n\n", len(d.Feeds)+len(d.Pages)) d.RUnlock() rawPage += fmt.Sprintf("Generated on %s\n", time.Now().Format("2006-01-02 at 15:04")) if len(pe.Entries) > 0 { curDay := toLocalDay(pe.Entries[0].Published) rawPage += fmt.Sprintf("\n\n## %s\n\n", curDay.Format("2006-01-02")) for _, entry := range pe.Entries { // get just the date it was published pub := toLocalDay(entry.Published) if pub.Before(curDay) { curDay = pub rawPage += fmt.Sprintf("\n\n## %s\n\n", curDay.Format("2006-01-02")) } if entry.Title == "" { rawPage += fmt.Sprintf("=> %s %s\n", entry.URL, entry.Prefix) } else { rawPage += fmt.Sprintf("=> %s %s — %s\n", entry.URL, entry.Prefix, entry.Title) } } } rawPage += ` --- => https://git.nytpu.com/comitium/about/ aggregated using comitium ` err := ioutil.WriteFile(path, []byte(rawPage), 0666) if err != nil { return err } // if full write was successful then overwrite original err = os.Rename(path, filepath.Join(dataPath, "feed.gmi")) return err }