]> Sergey Matveev's repositories - linksexp.git/blob - main.go
Unify copyright comment format
[linksexp.git] / main.go
1 // linksexp -- Texinfo/XBEL/OPML/urls autogeneration from recfile bookmark
2 // Copyright (C) 2021-2024 Sergey Matveev <stargrave@stargrave.org>
3 //
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.
7 //
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.
12 //
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/>.
15
16 package main
17
18 import (
19         "flag"
20         "fmt"
21         "io"
22         "os"
23         "sort"
24         "strings"
25         "time"
26
27         "go.cypherpunks.ru/recfile"
28 )
29
30 type ByTitle []map[string][]string
31
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
36 }
37
38 func main() {
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")
42         flag.Parse()
43
44         r := recfile.NewReader(os.Stdin)
45
46         if *doURLS {
47                 for {
48                         m, err := r.NextMapWithSlice()
49                         if err == io.EOF {
50                                 break
51                         }
52                         if err != nil {
53                                 panic(err)
54                         }
55                         if m["%rec"] != nil {
56                                 continue
57                         }
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
63                                 }
64                                 fmt.Println(f, cats)
65                         }
66                 }
67                 os.Exit(0)
68         }
69
70         if *doOPML {
71                 data := make([]map[string][]string, 0)
72                 for {
73                         m, err := r.NextMapWithSlice()
74                         if err == io.EOF {
75                                 break
76                         }
77                         if err != nil {
78                                 panic(err)
79                         }
80                         if m["%rec"] != nil {
81                                 continue
82                         }
83                         sort.Strings(m["Category"])
84                         data = append(data, m)
85                 }
86                 sort.Sort(ByTitle(data))
87                 opml(data)
88                 os.Exit(0)
89         }
90
91         data := make(map[string][]map[string][]string)
92         for {
93                 m, err := r.NextMapWithSlice()
94                 if err == io.EOF {
95                         break
96                 }
97                 if err != nil {
98                         panic(err)
99                 }
100                 if m["%rec"] != nil {
101                         continue
102                 }
103                 sort.Strings(m["Category"])
104                 if cs := m["Category"]; len(cs) == 0 {
105                         data["Uncategorized"] = append(data["Uncategorized"], m)
106                 } else {
107                         for _, cat := range cs {
108                                 data[cat] = append(data[cat], m)
109                         }
110                 }
111         }
112         cats := make([]string, 0, len(data))
113         for c := range data {
114                 cats = append(cats, c)
115                 sort.Sort(ByTitle(data[c]))
116         }
117         sort.Strings(cats)
118
119         if *doXBEL {
120                 xbel(cats, data)
121                 os.Exit(0)
122         }
123
124         fmt.Println("Updated:", time.Now().Format(time.RFC3339))
125
126         fmt.Println("@menu")
127         fmt.Println("Categories:")
128         for _, cat := range cats {
129                 fmt.Printf("* %s (%d items): LinksCat%s\n", cat, len(data[cat]), cat)
130         }
131         fmt.Println("@end menu")
132
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")
138                 ents := data[cat]
139                 for n, ent := range ents {
140                         catsOther := make([]string, 0)
141                         for _, c := range ent["Category"] {
142                                 if c != cat {
143                                         catsOther = append(catsOther, c)
144                                 }
145                         }
146                         var note string
147                         if len(ent["Note"]) > 0 {
148                                 note = "(" + strings.Trim(ent["Note"][0], " \n") + ")"
149                         }
150                         fmt.Printf(
151                                 "  @item %d @tab @url{%s,, %s} %s @tab %s @tab\n",
152                                 n,
153                                 strings.ReplaceAll(ent["URL"][0], "@", "@@"),
154                                 strings.ReplaceAll(ent["Title"][0], "@", "@@"),
155                                 note,
156                                 strings.Join(catsOther, ", "),
157                         )
158                         switch feeds := ent["Feed"]; len(feeds) {
159                         case 0:
160                                 fmt.Printf("    @emph{STATIC}\n")
161                         case 1:
162                                 fmt.Printf(
163                                         "    @url{%s, feed}\n",
164                                         strings.ReplaceAll(feeds[0], "@", "@@"),
165                                 )
166                         default:
167                                 for i, feed := range feeds {
168                                         fmt.Printf(
169                                                 "    @url{%s, feed%d}\n",
170                                                 strings.ReplaceAll(feed, "@", "@@"), i,
171                                         )
172                                 }
173                         }
174                 }
175                 fmt.Println("@end multitable")
176         }
177 }