1diff --git a/.gitignore b/.gitignore
2index 329aa21294f047bbbe577a5f5fbeba71cbcf00db..579c7ac6e983bae789f2d307a00f5c19a8e476a5 100644
3--- a/.gitignore
4+++ b/.gitignore
5@@ -3,3 +3,4 @@ midr
6 __debug_bin
7
8 .cache/
9+.nenv/
10diff --git a/assets/style.css b/assets/style.css
11new file mode 100644
12index 0000000000000000000000000000000000000000..7f524b9e18950647ef523c4edca09cc03477d870
13--- /dev/null
14+++ b/assets/style.css
15@@ -0,0 +1,100 @@
16+html, body, div, h1, header,section, table, th, td, tr{
17+ margin: 0;
18+ padding: 0;
19+ border: 0;
20+}
21+
22+body {
23+ font-family: sans-serif;
24+ margin: 0 auto;
25+ background-color: #f4f4f4;
26+}
27+
28+header {
29+ background-color: #0062cc;
30+ padding: .5em;
31+ margin: 0 auto;
32+}
33+
34+header h1 {
35+ font-size: large;
36+ text-transform: uppercase;
37+}
38+
39+header > h1 > a {
40+ color: white;
41+ text-decoration: none;
42+}
43+
44+main {
45+ margin: 1em;
46+}
47+
48+table {
49+ display: block;
50+ border-spacing: 0;
51+ width: 100%;
52+ overflow:auto;
53+ margin-top: 1em;
54+}
55+
56+th.fixed, td.fixed {
57+ width: 100px;
58+ overflow: hidden;
59+}
60+
61+th {
62+ padding: 1em;
63+ text-align: left;
64+}
65+
66+td {
67+ padding: 1em;
68+ overflow: hidden;
69+ white-space: nowrap;
70+ border-top: 1px solid #ccc;
71+}
72+
73+form {
74+ width: 70%;
75+ max-width: 500px;
76+}
77+
78+form input {
79+ width: 100%
80+}
81+
82+form label {
83+ display: block;
84+}
85+
86+.container {
87+ display: flex;
88+ flex-direction: column;
89+ justify-content: center;
90+ align-items: center;
91+}
92+
93+.field {
94+ margin-bottom: 1em;
95+}
96+
97+a.button, button {
98+ display: inline-block;
99+ padding: .1rem .75rem;
100+ background: #e9ecef;
101+ border: #343a40 1px solid;
102+ font-size: .9rem;
103+ font-weight: 400;
104+ line-height: 1.5;
105+ cursor: pointer;
106+ color: #000;
107+ border-radius: 0;
108+ text-decoration: none;
109+ transition: 0.5s all;
110+ align-self: flex-start;
111+}
112+
113+a.button:hover {
114+ background-color: #fff;
115+}
116diff --git a/controller/controller.go b/controller/controller.go
117index e381bf81c9f1386fcbdb5ad9f45629b5bd1890d9..c7f41454059c3dfad7a8239ab948eb0779ba3f2e 100644
118--- a/controller/controller.go
119+++ b/controller/controller.go
120@@ -2,6 +2,7 @@ package controller
121
122 import (
123 "net/http"
124+ "strconv"
125 "time"
126
127 "git.sr.ht/~gabrielgio/midr/db"
128@@ -40,7 +41,7 @@ func (e *Env) CreateEntry(c *gin.Context) {
129 var entry db.Entry
130 c.ShouldBind(&entry)
131 e.Entries.Create(&entry)
132- e.Worker.SpawnWorker(entry.ID, entry.Link, entry.OutputFolder)
133+ e.Worker.SpawnWorker(&entry)
134 c.Redirect(http.StatusFound, "/")
135 }
136
137@@ -48,6 +49,8 @@ func (e *Env) DeleteEntry(c *gin.Context) {
138 var entry db.Entry
139 id := c.Param("id")
140 e.Entries.Delete(id)
141+ u64, _ := strconv.ParseUint(id, 10, 32)
142+ e.Worker.RemoveJob(uint(u64))
143 c.HTML(http.StatusOK, "entry", entry)
144 }
145
146@@ -59,13 +62,13 @@
147 func (e *Env) StartScheduler() {
148 e.Worker.StartReader()
149 go func() {
150- for true {
151+ for {
152 entries := e.Entries.All()
153
154 for _, entry := range entries {
155- e.Worker.SpawnWorker(entry.ID, entry.Link, entry.OutputFolder)
156+ e.Worker.SpawnWorker(&entry)
157 }
158- time.Sleep(30 * time.Minute)
159+ time.Sleep(30 * time.Second)
160 }
161 }()
162 }
163diff --git a/db/model.go b/db/model.go
164index 0a5ca98a33c029aa1291ab7bced124f13273c95b..0d5cb47996c2813d2c47e83a088c5fa778553d04 100644
165--- a/db/model.go
166+++ b/db/model.go
167@@ -9,6 +9,7 @@ gorm.Model
168 Title string
169 Link string
170 Format string
171+ DateAfter string
172 OutputFolder string
173 }
174
175diff --git a/templates/_footer.tmpl b/templates/_footer.tmpl
176index 97a5bf86321cb9dfb79e36f15c192f3bb67392ba..b72953bfe205e50078ddbd7e2cf27b23ab0596ab 100644
177--- a/templates/_footer.tmpl
178+++ b/templates/_footer.tmpl
179@@ -1,6 +1,5 @@
180 {{ define "_footer" }}
181 </main>
182- </section>
183 <script>
184 function deleteEntry(id) {
185 fetch("/entries/"+id, { method: 'DELETE' })
186@@ -20,7 +19,7 @@ }
187 });
188 }
189
190-setInterval(getStatus, 1000);
191+setInterval(getStatus, 5000);
192
193 </script>
194 </body>
195diff --git a/templates/_head.tmpl b/templates/_head.tmpl
196index b99510f9b7ebbd4035848c4735481ebd55ee3a5c..11a4aa80c3bfb9eb7394dc8b50c920e476174831 100644
197--- a/templates/_head.tmpl
198+++ b/templates/_head.tmpl
199@@ -3,12 +3,11 @@ <!DOCTYPE html>
200 <html>
201 <head>
202 <meta name="viewport" content="width=device-width, initial-scale=1">
203- <link rel="stylesheet" href="/assets/bulma.min.css">
204+ <link rel="stylesheet" href="/assets/style.css">
205 </head>
206 <body>
207- <section class="section">
208- <div class="container">
209- <h1><a href="/"><strong>Home</strong></a></h1>
210- </div>
211+ <header>
212+ <h1><a href="/">midr</a></h1>
213+ </header>
214 <main class="container">
215 {{ end }}
216diff --git a/templates/entry.tmpl b/templates/entry.tmpl
217index 9f1181fdb5ad5771b731713f7b50b35f3bff9fb7..9edd5cdd0d0ce85251cbec5fc3f64230de0df150 100644
218--- a/templates/entry.tmpl
219+++ b/templates/entry.tmpl
220@@ -1,6 +1,5 @@
221 {{ define "entry" }}
222 {{ template "_head" }}
223-<div class="container">
224 {{ if (eq .ID 0) }}
225 <form action="/entries" method="POST">
226 {{ else }}
227@@ -16,11 +15,14 @@ <label for="link">Link</label>
228 <input class="input" type="text" id="Link" name="Link" value="{{ .Link }}" placeholder="Paste a valid youtube-dl link" required>
229 </div>
230 <div class="field">
231+ <label for="DateAfter">Date after</label>
232+ <input class="input" type="text" id="DateAfter" name="DateAfter" value="{{ .DateAfter }}" placeholder="Select the start date" required>
233+ </div>
234+ <div class="field">
235 <label for="output">Output folder</label>
236 <input class="input" type="text" id="OutputFolder" name="OutputFolder" value="{{ .OutputFolder }}" placeholder="Select a ralative folder" required>
237 </div>
238 <button type="submit">Submit</button>
239 </form>
240- </div>
241 {{ template "_footer" }}
242 {{ end }}
243diff --git a/templates/index.tmpl b/templates/index.tmpl
244index ae7f6747e8f506135ea1732727f54b8ab1886e4c..14cb420741e73d970f6161b700904b603c339c53 100644
245--- a/templates/index.tmpl
246+++ b/templates/index.tmpl
247@@ -1,14 +1,13 @@
248 {{ define "index" }}
249 {{ template "_head" }}
250-<div class="container">
251-<table class="table">
252+<table>
253 <thead>
254 <tr>
255 <th scope="col">ID</th>
256 <th scope="col">Title</th>
257 <th scope="col">Link</th>
258 <th scope="col">Output</th>
259- <th scope="col">Status</th>
260+ <th class="fixed" scope="col">Status</th>
261 <th scope="col"></th>
262 </tr>
263 </thead>
264@@ -19,19 +18,18 @@ <td>{{ .ID }}</td>
265 <td>{{ .Title }}</td>
266 <td>{{ .Link }}</td>
267 <td>{{ .OutputFolder }}</td>
268- <td>
269+ <td class="fixed">
270 <span id="status_{{ .ID }}" class="tag is-primary is-light"></span>
271 </td>
272 <td>
273 <a href="entries/{{ .ID }}" >Edit</a>
274 </span>
275- <a onclick="deleteEntry({{ .ID }})">Delete</a>
276+ <a href="#delete/{{ .ID }}" onclick="deleteEntry({{ .ID }})">Delete</a>
277 </td>
278 </tr>
279 {{ end }}
280 </tbody>
281 </table>
282-</div>
283 <a href="/entries/createEntry" class="button">Create</a>
284 {{ template "_footer" }}
285 {{ end }}
286diff --git a/worker/worker.go b/worker/worker.go
287index a8f15180e1093473163b8eb4ccf274786ea6d380..2444e892278f1547dd820ac6e664107b158acdb0 100644
288--- a/worker/worker.go
289+++ b/worker/worker.go
290@@ -3,6 +3,7 @@
291 import (
292 "context"
293
294+ "git.sr.ht/~gabrielgio/midr/db"
295 "git.sr.ht/~gabrielgio/midr/yt"
296 work "git.sr.ht/~sircmpwn/dowork"
297 )
298@@ -34,7 +35,7 @@ }
299
300 func NewWorkder() Worker {
301 return Worker{
302- c: make(chan command, 10),
303+ c: make(chan command),
304 jobs: make(map[uint]string),
305 }
306 }
307@@ -44,26 +45,31 @@ v, found := w.jobs[index]
308 return !found || v == statusNotQueued
309 }
310
311-func (w *Worker) SpawnWorker(index uint, link string, output string) {
312+func (w *Worker) RemoveJob(id uint) {
313+ delete(w.jobs, id)
314+}
315
316- if !w.CanEnqueue(index) {
317+func (w *Worker) SpawnWorker(entry *db.Entry) {
318+
319+ if !w.CanEnqueue(entry.ID) {
320 return
321 }
322
323- w.c <- command{action: commandEnqueue, index: index}
324+ w.c <- command{action: commandEnqueue, index: entry.ID}
325 task := work.NewTask(func(ctx context.Context) error {
326- w.c <- command{action: commandStart, index: index}
327- yt.RunYtDlpProcess(link, output)
328+
329+ w.c <- command{action: commandStart, index: entry.ID}
330+ yt.RunYtDlpProcess(entry)
331 return nil
332 }).After(func(ctx context.Context, task *work.Task) {
333- w.c <- command{action: commandDequeue, index: index}
334+ w.c <- command{action: commandDequeue, index: entry.ID}
335 })
336
337 work.Enqueue(task)
338 }
339
340 func (w *Worker) startReader() {
341- for true {
342+ for {
343 command := <-w.c
344
345 if command.action == commandEnqueue {
346diff --git a/yt/manager.go b/yt/manager.go
347index c0cf6cb7eef0168a5f79c944625d9862aa76c7c9..b9dc3336f203538ef073730e34f044a3eccdf409 100644
348--- a/yt/manager.go
349+++ b/yt/manager.go
350@@ -3,11 +3,23 @@
351 import (
352 "fmt"
353 "os/exec"
354+
355+ "git.sr.ht/~gabrielgio/midr/db"
356 )
357
358-func RunYtDlpProcess(link string, output string) {
359- output_template := fmt.Sprintf("%s/%%(title)s.%%(ext)s", output)
360- downloaded_txt := fmt.Sprintf("%s/downloaded.txt", output)
361- cmd := exec.Command("yt-dlp", link, "-o", output_template, "--download-archive", downloaded_txt)
362- cmd.Run()
363+func RunYtDlpProcess(entry *db.Entry) error {
364+ args := []string{entry.Link}
365+
366+ output_template := fmt.Sprintf("%s/%%(title)s.%%(ext)s", entry.OutputFolder)
367+ args = append(args, "-o", output_template)
368+
369+ downloaded_txt := fmt.Sprintf("%s/downloaded.txt", entry.OutputFolder)
370+ args = append(args, "--download-archive", downloaded_txt)
371+
372+ if len(entry.DateAfter) > 0 {
373+ args = append(args, "--dateafter", entry.DateAfter)
374+ }
375+
376+ cmd := exec.Command("yt-dlp", args...)
377+ return cmd.Run()
378 }