package worker import ( "bufio" "bytes" "context" "fmt" "os/exec" "git.sr.ht/~gabrielgio/midr/db" work "git.sr.ht/~sircmpwn/dowork" ) const ( statusNotQueued = "NOTQUEUED" statusQueued = "QUEUED" statusStarted = "RUNNING" commandStart = "START" commandEnqueue = "ENQUEUE" commandDequeue = "DEQUEUE" ) type command struct { action string index uint } type Worker struct { jobs map[uint]string c chan command } type Job struct { Id uint Status string } func NewWorkder() Worker { return Worker{ c: make(chan command), jobs: make(map[uint]string), } } func RunYtDlpProcess(entry *db.Entry) (error, []byte, []byte) { args := []string{entry.Link} var stdout bytes.Buffer var stderr bytes.Buffer output_template := fmt.Sprintf("%s/%%(title)s.%%(ext)s", entry.OutputFolder) args = append(args, "-o", output_template) downloaded_txt := fmt.Sprintf("%s/downloaded.txt", entry.OutputFolder) args = append(args, "--download-archive", downloaded_txt) if len(entry.DateAfter) > 0 { args = append(args, "--dateafter", entry.DateAfter) } cmd := exec.Command("yt-dlp", args...) cmd.Stdout = bufio.NewWriter(&stdout) cmd.Stderr = bufio.NewWriter(&stderr) err := cmd.Run() return err, stdout.Bytes(), stderr.Bytes() } func (w *Worker) CanEnqueue(index uint) bool { v, found := w.jobs[index] return !found || v == statusNotQueued } func (w *Worker) RemoveJob(id uint) { delete(w.jobs, id) } func (w *Worker) RunYtDlpWorker(entry *db.Entry) <-chan []byte { if !w.CanEnqueue(entry.ID) { return nil } log := make(chan []byte) w.c <- command{action: commandEnqueue, index: entry.ID} task := work.NewTask(func(ctx context.Context) error { w.c <- command{action: commandStart, index: entry.ID} err, stdout, stderr := RunYtDlpProcess(entry) log <- stdout log <- stderr return err }).After(func(ctx context.Context, task *work.Task) { w.c <- command{action: commandDequeue, index: entry.ID} close(log) }) work.Enqueue(task) return log } func (w *Worker) startReader() { for { command := <-w.c if command.action == commandEnqueue { w.jobs[command.index] = statusQueued } else if command.action == commandStart { w.jobs[command.index] = statusStarted } else if command.action == commandDequeue { w.jobs[command.index] = statusNotQueued } else { panic(1) } } } func (w *Worker) StartReader() { go w.startReader() } func (w *Worker) GetJobs() []Job { jobs := make([]Job, len(w.jobs)) count := 0 for k, v := range w.jobs { jobs[count] = Job{Id: k, Status: v} count++ } return jobs }