1 // linksexp -- Texinfo/XBEL/OPML/urls autogeneration from recfile bookmark
2 // Copyright (C) 2021-2024 Sergey Matveev <stargrave@stargrave.org>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, version 3 of the License.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program. If not, see <http://www.gnu.org/licenses/>.
27 "go.cypherpunks.ru/recfile"
30 type ByTitle []map[string][]string
32 func (a ByTitle) Len() int { return len(a) }
33 func (a ByTitle) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
34 func (a ByTitle) Less(i, j int) bool {
35 return strings.Compare(a[i]["Title"][0], a[j]["Title"][0]) < 0
39 doXBEL := flag.Bool("xbel", false, "Make XBEL")
40 doOPML := flag.Bool("opml", false, "Make OPML")
41 doURLS := flag.Bool("urls", false, "Make newsboat urls")
44 r := recfile.NewReader(os.Stdin)
48 m, err := r.NextMapWithSlice()
58 sort.Strings(m["Category"])
59 cats := strings.Join(m["Category"], " ")
60 for _, f := range m["Feed"] {
61 if strings.HasPrefix(f, "gemini://") {
62 f = "https://gemini/" + f
71 data := make([]map[string][]string, 0)
73 m, err := r.NextMapWithSlice()
83 sort.Strings(m["Category"])
84 data = append(data, m)
86 sort.Sort(ByTitle(data))
91 data := make(map[string][]map[string][]string)
93 m, err := r.NextMapWithSlice()
100 if m["%rec"] != nil {
103 sort.Strings(m["Category"])
104 if cs := m["Category"]; len(cs) == 0 {
105 data["Uncategorized"] = append(data["Uncategorized"], m)
107 for _, cat := range cs {
108 data[cat] = append(data[cat], m)
112 cats := make([]string, 0, len(data))
113 for c := range data {
114 cats = append(cats, c)
115 sort.Sort(ByTitle(data[c]))
124 fmt.Println("Updated:", time.Now().Format(time.RFC3339))
127 fmt.Println("Categories:")
128 for _, cat := range cats {
129 fmt.Printf("* %s (%d items): LinksCat%s\n", cat, len(data[cat]), cat)
131 fmt.Println("@end menu")
133 for _, cat := range cats {
134 fmt.Println("@node", "LinksCat"+cat)
135 fmt.Println("@section Links category:", cat)
136 fmt.Println("@multitable @columnfractions .05 .8 .1 .05")
137 fmt.Println("@headitem @tab @tab Other categories @tab Feed URLs")
139 for n, ent := range ents {
140 catsOther := make([]string, 0)
141 for _, c := range ent["Category"] {
143 catsOther = append(catsOther, c)
147 if len(ent["Note"]) > 0 {
148 note = "(" + strings.Trim(ent["Note"][0], " \n") + ")"
151 " @item %d @tab @url{%s,, %s} %s @tab %s @tab\n",
153 strings.ReplaceAll(ent["URL"][0], "@", "@@"),
154 strings.ReplaceAll(ent["Title"][0], "@", "@@"),
156 strings.Join(catsOther, ", "),
158 switch feeds := ent["Feed"]; len(feeds) {
160 fmt.Printf(" @emph{STATIC}\n")
164 strings.ReplaceAll(feeds[0], "@", "@@"),
167 for i, feed := range feeds {
169 " @url{%s, feed%d}\n",
170 strings.ReplaceAll(feed, "@", "@@"), i,
175 fmt.Println("@end multitable")