settings.html
⎇
Raw
1{{define "settings"}}
2<div class="page-header">
3 <h2>Settings</h2>
4</div>
5
6<div class="settings-layout">
7 <article>
8 <h3>Global Settings</h3>
9 <form method="post" action="/settings">
10 <label for="refresh_interval">Auto-refresh Interval (seconds)</label>
11 <input type="number" id="refresh_interval" name="refresh_interval" min="1" max="300"
12 value="{{.Data.Settings.RefreshInterval}}">
13
14 <label>
15 <input type="checkbox" name="auto_refresh_library" value="1"
16 {{if .Data.Settings.AutoRefreshLibrary}}checked{{end}}>
17 Auto-refresh Library page
18 </label>
19
20 <label>
21 <input type="checkbox" name="auto_refresh_downloads" value="1"
22 {{if .Data.Settings.AutoRefreshDownloads}}checked{{end}}>
23 Auto-refresh Queue page
24 </label>
25
26 <label for="cookies">Cookies (cookies.txt format)</label>
27 <textarea id="cookies" name="cookies" rows="6" placeholder="Paste cookies.txt content here...">{{.Data.Settings.Cookies}}</textarea>
28 <small>Paste the contents of a cookies.txt file. Will be passed to yt-dlp via --cookies.</small>
29
30 <div class="form-actions">
31 <button type="submit" class="primary">Save Settings</button>
32 </div>
33 </form>
34 </article>
35
36 <article>
37 <h3>Tools</h3>
38 <table class="tools-table">
39 <tbody>
40 <tr>
41 <th scope="row">yt-dlp</th>
42 <td>{{.Data.Tools.YTDLPVersion}}</td>
43 <td><code>{{.Data.Tools.YTDLPPath}}</code></td>
44 <td>{{.Data.Tools.YTDLPMode}}</td>
45 </tr>
46 <tr>
47 <th scope="row">JS runtime (deno)</th>
48 <td>{{.Data.Tools.DenoVersion}}</td>
49 <td><code>{{.Data.Tools.DenoPath}}</code></td>
50 <td>{{.Data.Tools.DenoMode}}</td>
51 </tr>
52 </tbody>
53 </table>
54
55 <form method="post" action="/settings/tools">
56 <label>
57 <input type="checkbox" name="tool_auto_update" value="1"
58 {{if .Data.Tools.AutoUpdate}}checked{{end}}>
59 Check for tool updates once a day
60 </label>
61
62 <label>
63 <input type="checkbox" name="js_runtime_enabled" value="1"
64 {{if .Data.Tools.JSRuntime}}checked{{end}}>
65 Install a JS runtime for sites with JavaScript challenges
66 </label>
67 <small>Deno is about 130&nbsp;MB unpacked. yt-dlp picks it up from the
68 managed directory automatically.</small>
69
70 <div class="form-actions">
71 <button type="submit" class="primary">Save Tool Settings</button>
72 </div>
73 </form>
74
75 <form method="post" action="/settings/tools/update">
76 <small>Last automatic check:
77 {{if .Data.Tools.CheckedAt.IsZero}}never{{else}}{{.Data.Tools.CheckedAt.Format "2006-01-02 15:04"}}{{end}}</small>
78 <div class="form-actions">
79 <button type="submit" class="secondary">Update Now</button>
80 </div>
81 <small>Runs each managed tool's own updater. This can take a few minutes.</small>
82 </form>
83 </article>
84
85 <article>
86 <h3>Theme</h3>
87 <div class="theme-selector">
88 <form method="post" action="/theme" class="inline">
89 <input type="hidden" name="theme" value="light">
90 <button type="submit" class="secondary {{if eq .Theme "light"}}active{{end}}">Light</button>
91 </form>
92 <form method="post" action="/theme" class="inline">
93 <input type="hidden" name="theme" value="dark">
94 <button type="submit" class="secondary {{if eq .Theme "dark"}}active{{end}}">Dark</button>
95 </form>
96 <form method="post" action="/theme" class="inline">
97 <input type="hidden" name="theme" value="auto">
98 <button type="submit" class="secondary {{if eq .Theme "auto"}}active{{end}}">Auto</button>
99 </form>
100 </div>
101 </article>
102
103 <article>
104 <h3>Presets</h3>
105
106 <div class="presets-list">
107 {{range .Data.Presets}}
108 <article>
109 <div class="preset-header">
110 <h4>{{.Name}} {{if .IsDefault}}<span class="badge">default</span>{{end}}</h4>
111 <details class="overlay">
112 <summary role="button" class="small danger">Delete</summary>
113 <div class="overlay-panel">
114 <p>Are you sure you want to delete preset <strong>{{.Name}}</strong>?</p>
115 <form method="post" action="/settings/presets/{{.ID}}/delete" class="form-actions">
116 <button type="submit" class="danger">Yes, Delete</button>
117 </form>
118 </div>
119 </details>
120 </div>
121
122 {{if .Description}}
123 <p class="preset-description">{{.Description}}</p>
124 {{end}}
125
126 <div class="preset-flags">
127 <strong>Effective flags:</strong>
128 <pre>{{presetFlags .}}</pre>
129 </div>
130
131 <div class="preset-actions">
132 <details>
133 <summary role="button" class="small"><span class="edit-text">Edit</span><span class="cancel-text">Cancel</span></summary>
134 <form method="post" action="/settings/presets/{{.ID}}" class="edit-form">
135 {{template "preset_form" .}}
136 <div class="form-actions">
137 <button type="submit" class="primary">Update Preset</button>
138 </div>
139 </form>
140 </details>
141 </div>
142 </article>
143 {{else}}
144 <p>No presets yet. Create one below.</p>
145 {{end}}
146 </div>
147
148 <article>
149 <h4>Create Preset</h4>
150 <form method="post" action="/settings/presets">
151 {{template "preset_form" emptyPreset}}
152
153 <div class="form-actions">
154 <button type="submit" class="primary">Create Preset</button>
155 </div>
156 </form>
157 </article>
158 </article>
159</div>
160{{end}}
161
162{{define "preset_form"}}
163 <div class="form-group">
164 <label>Name *</label>
165 <input type="text" name="name" required
166 value="{{if .}}{{.Name}}{{end}}">
167 </div>
168
169 <div class="form-group">
170 <label>Description</label>
171 <input type="text" name="description"
172 value="{{if .}}{{.Description}}{{end}}">
173 </div>
174
175 <div class="form-group">
176 <label>
177 <input type="checkbox" name="is_default" value="1"
178 {{if .}}{{if .IsDefault}}checked{{end}}{{end}}>
179 Set as default preset
180 </label>
181 </div>
182
183 <div class="conditional-section">
184 <label>Format Selection</label>
185 <div class="radio-group format-mode">
186 <label>
187 <input type="radio" name="format_mode" value="default" class="conditional-trigger"
188 {{if .}}{{if or (eq .FormatMode "default") (eq .FormatMode "")}}checked{{end}}{{else}}checked{{end}}>
189 yt-dlp default
190 </label>
191 <label>
192 <input type="radio" name="format_mode" value="preset" class="conditional-trigger"
193 {{if .}}{{if eq .FormatMode "preset"}}checked{{end}}{{end}}>
194 Preset format
195 </label>
196 <label>
197 <input type="radio" name="format_mode" value="custom" class="conditional-trigger"
198 {{if .}}{{if eq .FormatMode "custom"}}checked{{end}}{{end}}>
199 Custom format
200 </label>
201 </div>
202
203 <div class="conditional-content format-preset">
204 <div class="form-row">
205 <div class="form-group">
206 <label>Format</label>
207 <select name="format">
208 <option value="best" {{if .}}{{if eq .Format "best"}}selected{{end}}{{end}}>best</option>
209 <option value="worst" {{if .}}{{if eq .Format "worst"}}selected{{end}}{{end}}>worst</option>
210 <option value="bestvideo+bestaudio" {{if .}}{{if eq .Format "bestvideo+bestaudio"}}selected{{end}}{{end}}>bestvideo+bestaudio</option>
211 <option value="bestvideo" {{if .}}{{if eq .Format "bestvideo"}}selected{{end}}{{end}}>bestvideo</option>
212 <option value="bestaudio" {{if .}}{{if eq .Format "bestaudio"}}selected{{end}}{{end}}>bestaudio</option>
213 </select>
214 </div>
215
216 <div class="form-group">
217 <label>Max Quality</label>
218 <select name="quality">
219 <option value="" {{if .}}{{if eq .Quality ""}}selected{{end}}{{end}}>No limit</option>
220 <option value="720" {{if .}}{{if eq .Quality "720"}}selected{{end}}{{end}}>720p</option>
221 <option value="1080" {{if .}}{{if eq .Quality "1080"}}selected{{end}}{{end}}>1080p</option>
222 <option value="1440" {{if .}}{{if eq .Quality "1440"}}selected{{end}}{{end}}>1440p</option>
223 <option value="2160" {{if .}}{{if eq .Quality "2160"}}selected{{end}}{{end}}>4K (2160p)</option>
224 </select>
225 </div>
226 </div>
227 </div>
228
229 <div class="conditional-content format-custom">
230 <div class="form-group">
231 <label>Custom Format</label>
232 <input type="text" name="custom_format" placeholder="e.g., bestvideo+bestaudio/best or format ID like 22"
233 value="{{if .}}{{.CustomFormat}}{{end}}">
234 <small>Overrides the format selection. Use yt-dlp format syntax.</small>
235 </div>
236 </div>
237 </div>
238
239 <div class="conditional-section">
240 <div class="form-group">
241 <label>
242 <input type="checkbox" name="extract_audio" value="1" class="conditional-trigger"
243 {{if .}}{{if .ExtractAudio}}checked{{end}}{{end}}>
244 Extract audio only
245 </label>
246 </div>
247 <div class="conditional-content">
248 <div class="form-group">
249 <label>Audio Format</label>
250 <div class="radio-group">
251 <label><input type="radio" name="audio_format" value="mp3" {{if .}}{{if eq .AudioFormat "mp3"}}checked{{end}}{{end}}> MP3</label>
252 <label><input type="radio" name="audio_format" value="flac" {{if .}}{{if eq .AudioFormat "flac"}}checked{{end}}{{end}}> FLAC</label>
253 <label><input type="radio" name="audio_format" value="wav" {{if .}}{{if eq .AudioFormat "wav"}}checked{{end}}{{end}}> WAV</label>
254 <label><input type="radio" name="audio_format" value="opus" {{if .}}{{if eq .AudioFormat "opus"}}checked{{end}}{{end}}> Opus</label>
255 <label><input type="radio" name="audio_format" value="aac" {{if .}}{{if eq .AudioFormat "aac"}}checked{{end}}{{end}}> AAC</label>
256 <label><input type="radio" name="audio_format" value="" {{if .}}{{if eq .AudioFormat ""}}checked{{end}}{{else}}checked{{end}}> Default (no conversion)</label>
257 </div>
258 </div>
259 </div>
260 </div>
261
262 <div class="conditional-section">
263 <div class="form-group">
264 <label>
265 <input type="checkbox" name="embed_subs" value="1" class="conditional-trigger"
266 {{if .}}{{if .EmbedSubs}}checked{{end}}{{end}}>
267 Embed subtitles
268 </label>
269 </div>
270 <div class="conditional-content">
271 <div class="form-group">
272 <label>Subtitle Languages</label>
273 <input type="text" name="sub_langs" placeholder="e.g., en,de,fr or all"
274 value="{{if .}}{{.SubLangs}}{{else}}en{{end}}">
275 <small>Comma-separated language codes or "all"</small>
276 </div>
277 </div>
278 </div>
279
280 <div class="form-group">
281 <label>
282 <input type="checkbox" name="embed_thumbnail" value="1"
283 {{if .}}{{if .EmbedThumbnail}}checked{{end}}{{else}}checked{{end}}>
284 Embed thumbnail
285 </label>
286 </div>
287
288 <div class="form-group">
289 <label>
290 <input type="checkbox" name="embed_metadata" value="1"
291 {{if .}}{{if .EmbedMetadata}}checked{{end}}{{else}}checked{{end}}>
292 Embed metadata
293 </label>
294 </div>
295
296 <div class="comment-settings-group">
297 <div class="form-group">
298 <label>
299 <input type="checkbox" name="write_info_json" value="1"
300 {{if .}}{{if .WriteInfoJSON}}checked{{end}}{{else}}checked{{end}}>
301 Write info JSON
302 </label>
303 </div>
304
305 <fieldset class="comment-options">
306 <legend>Comments</legend>
307 <label class="comment-toggle">
308 <input type="checkbox" name="write_comments" value="1"
309 {{if .}}{{if .WriteComments}}checked{{end}}{{end}}>
310 Write comments to info JSON
311 </label>
312 <div class="comment-settings-fields">
313 <label>Comment sort</label>
314 <input type="text" name="comment_sort" placeholder="e.g., top or newest"
315 value="{{if .}}{{.CommentSort}}{{end}}">
316 <small>Extractor-specific value; leave blank for yt-dlp's default.</small>
317
318 <label>Maximum comments</label>
319 <input type="number" name="max_comments" min="0"
320 value="{{if .}}{{.MaxComments}}{{end}}">
321 <small>0 leaves the extractor default.</small>
322
323 <label>Additional extractor arguments</label>
324 <input type="text" name="comment_extractor_args"
325 placeholder="e.g., youtube:player_client=web"
326 value="{{if .}}{{.CommentExtractorArgs}}{{end}}">
327 <small>Raw value passed to <code>--extractor-args</code>.</small>
328 </div>
329 </fieldset>
330 </div>
331
332 <div class="form-group">
333 <label>Custom Flags</label>
334 <textarea name="custom_flags" rows="2" placeholder="Any additional yt-dlp flags...">{{if .}}{{.CustomFlags}}{{end}}</textarea>
335 {{template "ytdlp_notes" false}}
336 </div>
337{{end}}
338