krz/skunky-art
Alternative privacy frontend for DeviantArt.
clone: git clone https://gitbay.org/krz/skunky-art.git
1package app
2
3import (
4 "bufio"
5 "bytes"
6 "encoding/json"
7 "html/template"
8 "os"
9 "time"
10)
11
12// ExecuteCommandLineArguments parses argv, applying the flags that override
13// config and running one-shot commands such as --help and --add-instance. Some
14// of those commands exit the process rather than return.
15func ExecuteCommandLineArguments() {
16 var helpmsg = `SkunkyArt v{{.Version}} [{{.Description}}]
17Usage:
18 - [-c|--config] | path to config
19 - [-a|--add-instance] | generates 'instances.json' and 'INSTANCES.md' files with ur instance
20 - [-h|--help] | returns this message
21Example:
22 ./skunkyart -c config.json
23Copyright lost+skunk and zerolabs, X11. https://github.com/zerolabsco/skunky-art/releases/tag/v{{.Version}}`
24
25 a := os.Args[1:]
26 for n, x := range a {
27 switch x {
28 case "-c", "--config":
29 if len(a) >= 2 {
30 CFG.cfg = a[n+1]
31 } else {
32 exit("Not enought arguments", 1)
33 }
34 case "-h", "--help":
35 var buf bytes.Buffer
36 t := template.New("help")
37 tryWithExitStatus(func() error {
38 if _, err := t.Parse(helpmsg); err != nil {
39 return err
40 }
41 return t.Execute(&buf, &Release)
42 }(), 1)
43 exit(buf.String(), 0)
44 case "-a", "--add-instance":
45 addInstance()
46 }
47 }
48}
49
50type settingsUrls struct {
51 I2P string `json:"i2p,omitempty"`
52 Ygg string `json:"ygg,omitempty"`
53 Tor string `json:"tor,omitempty"`
54 Clearnet string `json:"clearnet,omitempty"`
55}
56
57type settingsParams struct {
58 Nsfw bool `json:"nsfw"`
59 Proxy bool `json:"proxy"`
60}
61
62type settings struct {
63 Title string `json:"title"`
64 Country string `json:"country"`
65 ModifiedSrc string `json:"modified-src,omitempty"`
66 Urls settingsUrls `json:"urls"`
67 Settings settingsParams `json:"settings"`
68}
69
70func addInstance() {
71 prompt := func(txt string, necessary bool) string {
72 input := bufio.NewScanner(os.Stdin)
73 for {
74 print(txt)
75 print(": ")
76 input.Scan()
77
78 if i := input.Text(); necessary && i == "" {
79 println("Please specify the", txt)
80 } else {
81 return i
82 }
83 }
84 }
85
86 var settingsVar struct {
87 Instances []settings `json:"instances"`
88 }
89 // 0644: both files are committed to the repository and are meant to be
90 // world-readable, so gosec's 0600 default does not apply.
91 instancesJSON, err := os.OpenFile("instances.json", os.O_CREATE|os.O_WRONLY, 0644) //nolint:gosec // G302
92 if err != nil {
93 exit(err.Error(), 1)
94 }
95 defer func() { try(instancesJSON.Close()) }()
96
97 instancesFile, err := os.OpenFile("INSTANCES.md", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) //nolint:gosec // G302
98 if err != nil {
99 exit(err.Error(), 1)
100 }
101 defer func() { try(instancesFile.Close()) }()
102
103 for {
104 if string(instances) == "" {
105 print("\rDownloading instance list...")
106 } else {
107 println("\r\033[2KDownloaded!")
108 try(json.Unmarshal(instances, &settingsVar))
109
110 settingsVar.Instances = append(settingsVar.Instances, settings{
111 Title: prompt("Title", true),
112 Country: prompt("Country", true),
113 ModifiedSrc: prompt("Link to modified sources", false),
114 Settings: settingsParams{
115 Nsfw: CFG.Nsfw,
116 Proxy: CFG.Proxy,
117 },
118 Urls: settingsUrls{
119 Clearnet: prompt("Clearnet link", false),
120 Ygg: prompt("Yggdrasil link", false),
121 Tor: prompt("Onion link", false),
122 I2P: prompt("I2P link", false),
123 },
124 })
125
126 j, err := json.MarshalIndent(&settingsVar, "", " ")
127 try(err)
128
129 try(func() error { _, err := instancesJSON.Write(j); return err }())
130
131 settingsVar := &settingsVar.Instances[len(settingsVar.Instances)-1]
132 var mdstr bytes.Buffer
133
134 mdbuilder := func(yes bool, link string, title string) {
135 switch {
136 case yes && (title != "" && link != ""):
137 mdstr.WriteString("[")
138 mdstr.WriteString(title)
139 mdstr.WriteString("](")
140 mdstr.WriteString(link)
141 mdstr.WriteString(")")
142 case yes && link != "":
143 mdstr.WriteString("[Yes](")
144 mdstr.WriteString(link)
145 mdstr.WriteString(")")
146 case yes:
147 mdstr.WriteString("Yes")
148 default:
149 mdstr.WriteString("No")
150 }
151 mdstr.WriteString("|")
152 }
153
154 mdstr.WriteString("\n|")
155 mdbuilder(settingsVar.Urls.Clearnet != "", settingsVar.Urls.Clearnet, settingsVar.Title)
156
157 urls := []string{settingsVar.Urls.Ygg, settingsVar.Urls.I2P, settingsVar.Urls.Tor}
158 for i, l := 0, len(urls); i < l; i++ {
159 url := urls[i]
160 mdbuilder(url != "", url, "")
161 }
162
163 settings := []bool{settingsVar.Settings.Nsfw, settingsVar.Settings.Proxy}
164 for i, l := 0, len(settings); i < l; i++ {
165 mdbuilder(settings[i], "", "")
166 }
167
168 mdbuilder(settingsVar.ModifiedSrc != "", settingsVar.ModifiedSrc, "")
169
170 mdstr.WriteString(settingsVar.Country)
171 mdstr.WriteString("|")
172
173 try(func() error { _, err := instancesFile.Write(mdstr.Bytes()); return err }())
174 break
175 }
176 time.Sleep(500 * time.Millisecond)
177 }
178 exit("Done! Now add the files 'instances.json' and 'INSTANCES.md' to the 'main' branch in the repository https://github.com/zerolabsco/skunky-art", 0)
179}