settings.go
⎇
Raw
1package handler
2
3import (
4 "fmt"
5 "log"
6 "net/http"
7 "strconv"
8 "strings"
9
10 "vidarchive/internal/models"
11)
12
13func (h *Handler) Settings(w http.ResponseWriter, r *http.Request) {
14 presets, err := h.presetSvc.GetAll()
15 if err != nil {
16 h.serverError(w, r, "list presets", err)
17 return
18 }
19
20 settings, err := h.settingsSvc.GetAll()
21 if err != nil {
22 h.serverError(w, r, "load settings", err)
23 return
24 }
25
26 h.renderWithRequest(w, r, "settings", PageData{
27 Title: "Settings",
28 ActiveTab: "settings",
29 Data: struct {
30 Presets []*models.Preset
31 Settings *models.Settings
32 }{
33 Presets: presets,
34 Settings: settings,
35 },
36 })
37}
38
39func (h *Handler) CreatePreset(w http.ResponseWriter, r *http.Request) {
40 if err := r.ParseForm(); err != nil {
41 http.Error(w, err.Error(), http.StatusBadRequest)
42 return
43 }
44
45 preset := &models.Preset{}
46 if err := applyPresetForm(preset, r); err != nil {
47 redirectWithError(w, r, "/settings", err.Error(), nil)
48 return
49 }
50
51 if err := h.presetSvc.Create(preset); err != nil {
52 redirectWithError(w, r, "/settings", "Couldn't create this preset.", err)
53 return
54 }
55
56 redirectWithSuccess(w, r, "/settings", "Preset created.")
57}
58
59// applyPresetForm copies the preset form fields onto p and validates them. It is
60// shared by create and update so the two can't drift apart as fields are added.
61func applyPresetForm(p *models.Preset, r *http.Request) error {
62 name := strings.TrimSpace(r.FormValue("name"))
63 if name == "" {
64 return fmt.Errorf("A preset needs a name.")
65 }
66
67 // Mirrors the radio options on the settings form; empty means "unspecified"
68 // and BuildArgs applies its own default.
69 formatMode := r.FormValue("format_mode")
70 switch formatMode {
71 case "", "default", "preset", "custom":
72 default:
73 return fmt.Errorf("Unknown format mode %q.", formatMode)
74 }
75
76 p.Name = name
77 p.Description = r.FormValue("description")
78 p.FormatMode = formatMode
79 p.Format = r.FormValue("format")
80 p.Quality = r.FormValue("quality")
81 p.CustomFormat = r.FormValue("custom_format")
82 p.AudioFormat = r.FormValue("audio_format")
83 p.SubLangs = r.FormValue("sub_langs")
84 p.CustomFlags = r.FormValue("custom_flags")
85 p.IsDefault = r.FormValue("is_default") == "1"
86 p.ExtractAudio = r.FormValue("extract_audio") == "1"
87 p.EmbedSubs = r.FormValue("embed_subs") == "1"
88 p.EmbedThumbnail = r.FormValue("embed_thumbnail") == "1"
89 p.EmbedMetadata = r.FormValue("embed_metadata") == "1"
90 p.WriteInfoJSON = r.FormValue("write_info_json") == "1"
91 p.WriteComments = r.FormValue("write_comments") == "1"
92 p.CommentSort = strings.TrimSpace(r.FormValue("comment_sort"))
93 p.CommentExtractorArgs = strings.TrimSpace(r.FormValue("comment_extractor_args"))
94 p.MaxComments = 0
95 if raw := strings.TrimSpace(r.FormValue("max_comments")); raw != "" {
96 maxComments, err := strconv.Atoi(raw)
97 if err != nil || maxComments < 0 {
98 return fmt.Errorf("Max comments must be a non-negative number.")
99 }
100 p.MaxComments = maxComments
101 }
102 // Comments are stored in the info JSON sidecar. Keep the dependent options
103 // consistent even when a client submits the form without JavaScript.
104 if !p.WriteInfoJSON || !p.WriteComments {
105 p.WriteComments = false
106 p.CommentSort = ""
107 p.MaxComments = 0
108 p.CommentExtractorArgs = ""
109 }
110
111 return nil
112}
113
114func (h *Handler) UpdatePreset(w http.ResponseWriter, r *http.Request) {
115 id, ok := parseID(w, r)
116 if !ok {
117 return
118 }
119
120 if err := r.ParseForm(); err != nil {
121 http.Error(w, err.Error(), http.StatusBadRequest)
122 return
123 }
124
125 preset, err := h.presetSvc.GetByID(id)
126 if err != nil {
127 http.Error(w, "Not found", http.StatusNotFound)
128 return
129 }
130
131 if err := applyPresetForm(preset, r); err != nil {
132 redirectWithError(w, r, "/settings", err.Error(), nil)
133 return
134 }
135
136 if err := h.presetSvc.Update(preset); err != nil {
137 redirectWithError(w, r, "/settings", "Couldn't update this preset.", err)
138 return
139 }
140
141 redirectWithSuccess(w, r, "/settings", "Preset updated.")
142}
143
144func (h *Handler) DeletePreset(w http.ResponseWriter, r *http.Request) {
145 id, ok := parseID(w, r)
146 if !ok {
147 return
148 }
149
150 if err := h.presetSvc.Delete(id); err != nil {
151 redirectWithError(w, r, "/settings", "Couldn't delete this preset.", err)
152 return
153 }
154
155 redirectWithSuccess(w, r, "/settings", "Preset deleted.")
156}
157
158func (h *Handler) UpdateSettings(w http.ResponseWriter, r *http.Request) {
159 if err := r.ParseForm(); err != nil {
160 http.Error(w, err.Error(), http.StatusBadRequest)
161 return
162 }
163
164 var firstErr error
165 record := func(err error) {
166 if err != nil && firstErr == nil {
167 firstErr = err
168 }
169 }
170
171 if interval := r.FormValue("refresh_interval"); interval != "" {
172 record(h.settingsSvc.SetRefreshInterval(interval))
173 }
174 record(h.settingsSvc.SetAutoRefreshLibrary(r.FormValue("auto_refresh_library") == "1"))
175 record(h.settingsSvc.SetAutoRefreshDownloads(r.FormValue("auto_refresh_downloads") == "1"))
176 record(h.settingsSvc.SetCookies(r.FormValue("cookies")))
177
178 if firstErr != nil {
179 log.Printf("UpdateSettings: %v", firstErr)
180 flashError(w, "Some settings couldn't be saved: "+firstErr.Error())
181 } else {
182 flashSuccess(w, "Settings saved.")
183 }
184 http.Redirect(w, r, "/settings", http.StatusSeeOther)
185}
186
187func (h *Handler) Theme(w http.ResponseWriter, r *http.Request) {
188 if err := r.ParseForm(); err != nil {
189 http.Error(w, err.Error(), http.StatusBadRequest)
190 return
191 }
192
193 theme := r.FormValue("theme")
194 if theme == "" {
195 theme = "auto"
196 }
197
198 setCookie(w, "theme", theme)
199
200 referer := r.Header.Get("Referer")
201 if referer == "" {
202 referer = "/"
203 }
204 http.Redirect(w, r, referer, http.StatusSeeOther)
205}
206