foxygit / ytmdl Log in
commits tags

/c/src/queue.c · 3.36 KB

raw
#include "queue.h"

#include <string.h>

#include "util.h"

void queue_init(Queue *q) {
    memset(q, 0, sizeof(*q));
    q->count = 0;
    q->next_id = 1;
    pthread_mutex_init(&q->lock, NULL);
}

static int find_index_locked(Queue *q, int id) {
    for (int i = 0; i < q->count; i++) {
        if (q->items[i].id == id) return i;
    }
    return -1;
}

int queue_add(Queue *q, const char *url, const char *title, const char *subdir) {
    pthread_mutex_lock(&q->lock);
    if (q->count >= MAX_QUEUE_ITEMS) {
        pthread_mutex_unlock(&q->lock);
        return -1;
    }
    QueueItem *item = &q->items[q->count++];
    memset(item, 0, sizeof(*item));
    item->id = q->next_id++;
    safe_strcpy(item->url, sizeof(item->url), url);
    safe_strcpy(item->title, sizeof(item->title), title);
    safe_strcpy(item->subdir, sizeof(item->subdir), subdir);
    item->status = STATUS_PENDING;
    int id = item->id;
    pthread_mutex_unlock(&q->lock);
    return id;
}

int queue_get(Queue *q, int id, QueueItem *out) {
    pthread_mutex_lock(&q->lock);
    int idx = find_index_locked(q, id);
    int found = 0;
    if (idx >= 0) {
        *out = q->items[idx];
        found = 1;
    }
    pthread_mutex_unlock(&q->lock);
    return found;
}

void queue_set_status(Queue *q, int id, ItemStatus status, const char *error) {
    pthread_mutex_lock(&q->lock);
    int idx = find_index_locked(q, id);
    if (idx >= 0) {
        q->items[idx].status = status;
        if (error) safe_strcpy(q->items[idx].error, sizeof(q->items[idx].error), error);
        if (status == STATUS_DONE) q->items[idx].percent = 100.0f;
    }
    pthread_mutex_unlock(&q->lock);
}

void queue_set_progress(Queue *q, int id, float percent, const char *speed, const char *eta) {
    pthread_mutex_lock(&q->lock);
    int idx = find_index_locked(q, id);
    if (idx >= 0) {
        q->items[idx].percent = percent;
        safe_strcpy(q->items[idx].speed, sizeof(q->items[idx].speed), speed);
        safe_strcpy(q->items[idx].eta, sizeof(q->items[idx].eta), eta);
    }
    pthread_mutex_unlock(&q->lock);
}

void queue_reset_for_retry(Queue *q, int id) {
    pthread_mutex_lock(&q->lock);
    int idx = find_index_locked(q, id);
    if (idx >= 0) {
        q->items[idx].status = STATUS_PENDING;
        q->items[idx].percent = 0.0f;
        q->items[idx].error[0] = '\0';
        q->items[idx].speed[0] = '\0';
        q->items[idx].eta[0] = '\0';
    }
    pthread_mutex_unlock(&q->lock);
}

static void remove_index_locked(Queue *q, int idx) {
    for (int i = idx; i < q->count - 1; i++) {
        q->items[i] = q->items[i + 1];
    }
    q->count--;
}

void queue_remove(Queue *q, int id) {
    pthread_mutex_lock(&q->lock);
    int idx = find_index_locked(q, id);
    if (idx >= 0 && q->items[idx].status != STATUS_DOWNLOADING) {
        remove_index_locked(q, idx);
    }
    pthread_mutex_unlock(&q->lock);
}

int queue_clear_finished(Queue *q) {
    pthread_mutex_lock(&q->lock);
    int removed = 0;
    for (int i = 0; i < q->count; /* no increment here */) {
        /* Only successfully finished items are cleared automatically;
         * errored ones stay visible so they can be inspected/retried. */
        ItemStatus s = q->items[i].status;
        if (s == STATUS_DONE) {
            remove_index_locked(q, i);
            removed++;
        } else {
            i++;
        }
    }
    pthread_mutex_unlock(&q->lock);
    return removed;
}