subscriptions.html
⎇
Raw
1{{define "subscriptions"}}
2<div class="page-header">
3 <h2>Subscriptions</h2>
4</div>
5
6<div class="settings-layout">
7 <article>
8 <h3>Your Subscriptions</h3>
9 <div class="subscriptions-list">
10 {{range .Data.Subscriptions}}
11 <article>
12 <div class="preset-header">
13 <h4>
14 {{.Name}}
15 {{if .Enabled}}<span class="badge">active</span>{{else}}<span class="badge">paused</span>{{end}}
16 </h4>
17 <details class="delete-overlay">
18 <summary role="button" class="small danger">Delete</summary>
19 <div class="overlay-panel">
20 <p>Delete subscription <strong>{{.Name}}</strong>? (Downloaded files are kept.)</p>
21 <form method="post" action="/subscriptions/{{.ID}}/delete" class="form-actions">
22 <button type="submit" class="danger">Yes, Delete</button>
23 </form>
24 </div>
25 </details>
26 </div>
27
28 <p class="preset-description">
29 <code>{{.URL}}</code><br>
30 Folder: <code>{{.OutputDir}}</code> &middot;
31 Mode: <strong>{{.RefreshMode}}</strong> &middot;
32 Schedule: <strong>{{.ScheduleKind}}</strong> (<code>{{.CronExpr}}</code>)
33 {{if .PruneRemoved}} &middot; prunes removed{{end}}
34 </p>
35 <p class="preset-description">
36 Next run: {{if .NextRunAt.Valid}}{{.NextRunAt.Time.Format "2006-01-02 15:04"}}{{else}}&mdash;{{end}}
37 &middot; Last run: {{if .LastRunAt.Valid}}{{.LastRunAt.Time.Format "2006-01-02 15:04"}}{{else}}never{{end}}
38 {{if .LastStatus.Valid}} ({{.LastStatus.String}}){{end}}
39 </p>
40
41 <div class="preset-actions">
42 <form method="post" action="/subscriptions/{{.ID}}/run" class="inline">
43 <button type="submit" class="small">Run now</button>
44 </form>
45 <form method="post" action="/subscriptions/{{.ID}}/toggle" class="inline">
46 <button type="submit" class="small secondary">{{if .Enabled}}Pause{{else}}Resume{{end}}</button>
47 </form>
48 <details>
49 <summary role="button" class="small"><span class="edit-text">Edit</span><span class="cancel-text">Cancel</span></summary>
50 <form method="post" action="/subscriptions/{{.ID}}" class="edit-form">
51 {{template "subscription_form" (dict "Sub" . "Presets" $.Data.Presets)}}
52 <div class="form-actions">
53 <button type="submit" class="primary">Update Subscription</button>
54 </div>
55 </form>
56 </details>
57 </div>
58 </article>
59 {{else}}
60 <p>No subscriptions yet. Create one below.</p>
61 {{end}}
62 </div>
63 </article>
64
65 <article>
66 <h3>Create Subscription</h3>
67 <form method="post" action="/subscriptions">
68 {{template "subscription_form" (dict "Sub" newSubscription "Presets" .Data.Presets)}}
69 <div class="form-actions">
70 <button type="submit" class="primary">Create Subscription</button>
71 </div>
72 </form>
73 </article>
74</div>
75{{end}}
76
77{{/* subscription_form renders the create/edit fields. Data: {Sub *Subscription, Presets []*Preset}.
78 Sub is always non-nil — newSubscription supplies create-time defaults. */}}
79{{define "subscription_form"}}
80 {{$sub := .Sub}}
81 <div class="form-group">
82 <label>Name *</label>
83 <input type="text" name="name" required value="{{$sub.Name}}" placeholder="A name for this subscription">
84 </div>
85 <div class="form-group">
86 <label>URL *</label>
87 <input type="text" name="url" required value="{{$sub.URL}}" placeholder="https://youtube.com/watch?v=...">
88 </div>
89 <div class="form-group">
90 <label>Library folder *</label>
91 <input type="text" name="output_dir" required value="{{$sub.OutputDir}}" placeholder="e.g., videos/music (relative to library folder)">
92 <small>This subscription owns this folder &mdash; don't download into it manually. May be nested, e.g. <code>subscriptions/news</code>.</small>
93 </div>
94
95 <div class="form-group">
96 <label>Refresh mode</label>
97 <div class="radio-group">
98 <label><input type="radio" name="refresh_mode" value="overwrite" {{if eq $sub.RefreshMode "overwrite"}}checked{{end}}> Overwrite (re-download &amp; replace)</label>
99 <label><input type="radio" name="refresh_mode" value="skip" {{if eq $sub.RefreshMode "skip"}}checked{{end}}> Skip existing (add new only)</label>
100 <label><input type="radio" name="refresh_mode" value="metadata" {{if eq $sub.RefreshMode "metadata"}}checked{{end}}> Metadata refresh (update existing, add new)</label>
101 </div>
102 </div>
103
104 <div class="form-row">
105 <div class="form-group">
106 <label>Schedule</label>
107 <select name="schedule_kind">
108 <option value="hourly" {{if eq $sub.ScheduleKind "hourly"}}selected{{end}}>Hourly</option>
109 <option value="daily" {{if eq $sub.ScheduleKind "daily"}}selected{{end}}>Daily</option>
110 <option value="weekly" {{if eq $sub.ScheduleKind "weekly"}}selected{{end}}>Weekly</option>
111 <option value="monthly" {{if eq $sub.ScheduleKind "monthly"}}selected{{end}}>Monthly</option>
112 <option value="cron" {{if eq $sub.ScheduleKind "cron"}}selected{{end}}>Custom (cron)</option>
113 </select>
114 </div>
115 <div class="form-group">
116 <label>Cron expression</label>
117 <input type="text" name="cron_expr" value="{{$sub.CronExpr}}" placeholder="0 3 * * *">
118 <small>Used when schedule is "Custom". Standard 5-field cron.</small>
119 </div>
120 </div>
121
122 <div class="form-group">
123 <label>Preset</label>
124 <select name="preset_id">
125 <option value="">Default preset</option>
126 {{range .Presets}}
127 <option value="{{.ID}}" {{if and $sub.PresetID.Valid (eq $sub.PresetID.Int64 .ID)}}selected{{end}}>{{.Name}}</option>
128 {{end}}
129 </select>
130 </div>
131
132 <div class="form-group">
133 <label>Format override</label>
134 <input type="text" name="format_override" value="{{$sub.FormatOverride}}" placeholder="e.g., bestvideo+bestaudio/best or format ID like 22">
135 </div>
136 <div class="form-group">
137 <label>Custom flags</label>
138 <textarea name="custom_flags" rows="2" placeholder="Any additional yt-dlp flags...">{{$sub.CustomFlags}}</textarea>
139 {{template "ytdlp_notes" true}}
140 </div>
141 <div class="form-group">
142 <label>
143 <input type="checkbox" name="prune_removed" value="1" {{if $sub.PruneRemoved}}checked{{end}}>
144 Delete items removed from the source (prune)
145 </label>
146 </div>
147{{end}}
148