diff options
Diffstat (limited to 'src/fruits/cap')
| -rw-r--r-- | src/fruits/cap/cap.c | 219 | ||||
| -rw-r--r-- | src/fruits/cap/cap.h | 42 | ||||
| -rw-r--r-- | src/fruits/cap/meson.build | 4 |
3 files changed, 265 insertions, 0 deletions
diff --git a/src/fruits/cap/cap.c b/src/fruits/cap/cap.c new file mode 100644 index 0000000..2f60cb4 --- /dev/null +++ b/src/fruits/cap/cap.c @@ -0,0 +1,219 @@ +#include "cap.h" + +#if CAP_USE_PYTHON +#include "../../shoki/src/search.h" +#endif +#include "../../cache/handlers/file.h" +#ifdef AKIYO_HAS_CURL +#include "../../cache/handlers/http.h" +#endif + +void cap_init(struct cap_runner *cap, bool (*callback)(void *, u8, str *, str *, void *), void *userdata) +{ + cap->callback = callback; + cap->userdata = userdata; + al_array_init(cap->lists); +} + +static struct cap_list *list_from_name(struct cap_runner *cap, str *name) +{ + struct cap_list *list; + al_array_foreach_ptr(cap->lists, i, list) { + if (al_str_eq(&list->name, name)) { + return list; + } + } + return NULL; +} + +static struct cch_entry *entry_for_unique_id(str *unique_id) +{ + struct cch_entry *entry = NULL; +#ifdef AKIYO_HAS_CURL + bool is_search = al_str_at(unique_id, 0) == ';'; + if (is_search || al_str_cmp(unique_id, al_str_c("https://"), 0, 8) == 0 || + al_str_cmp(unique_id, al_str_c("http://"), 0, 7) == 0) { +#if CAP_USE_PYTHON + struct sho_search s; + sho_search_init(&s); + if (al_str_cmp(unique_id, al_str_c("https://twitter.com"), 0, 19) == 0 || + al_str_cmp(unique_id, al_str_c("https://x.com"), 0, 13) == 0) { + str query; + al_str_from(&query, "tweet:"); + al_str_cat(&query, unique_id); + if (!sho_search_more_results(&s, al_str_c("twitter"), &query)) { + } + al_str_free(&query); + } else { + str query; + if (is_search) { + //al_str_from(&query, "\""); + al_str_from(&query, ""); + al_str_cat(&query, al_str_substr(unique_id, 1, unique_id->len)); + //al_str_cat(&query, al_str_c("\"")); + } else { + al_str_from(&query, "link:"); + al_str_cat(&query, unique_id); + } + if (!sho_search_more_results(&s, al_str_c("youtube"), &query)) { + } + } + entry = NULL; + struct sho_result_page *page; + al_array_foreach_ptr(s.result.pages, k, page) { + struct sho_post *post; + al_array_foreach_ptr(page->posts, i, post) { + struct sho_post_media *media; + al_array_foreach_ptr(post->media, j, media) { + if (media->url.len > 0) { + entry = cch_handler_http_create(&media->url); + break; + } + } + if (entry) break; + } + } + sho_search_free(&s); +#else + if (!is_search) entry = cch_handler_http_create(unique_id); +#endif + entry->handler->maybe_spawn_worker(entry->handler, 0); + } else // { +#endif + entry = cch_handler_file_create(unique_id); + // } + return entry; +} + +static bool buffer_entry(struct cap_runner *cap, struct cap_list *list, struct cap_list_entry *entry) +{ + if (entry->buffer_requested) return true; + struct cch_entry *centry = entry_for_unique_id(&entry->unique_id); + if (!centry) return false; + if (!cap->callback(cap->userdata, CAP_BUFFER, &list->name, &entry->unique_id, centry)) { + entry->errored = true; + return false; + } + entry->buffer_requested = true; + return true; +} + +static void maybe_cleanup_entries(struct cap_runner *cap, struct cap_list *list) +{ + struct cap_list_entry *entry; + al_array_foreach_ptr(list->entries, i, entry) { + if (entry->buffer_requested && abs((s32)i - list->current) >= 3) { + cap->callback(cap->userdata, CAP_UNLOAD, &list->name, &entry->unique_id, NULL); + entry->buffer_requested = false; + } + } +} + +static bool list_skip_internal(struct cap_runner *cap, struct cap_list *list, s32 n); + +static void list_pump_internal(struct cap_runner *cap, struct cap_list *list) +{ + s32 size = (s32)list->entries.size; + if (size <= list->current) return; + if (list->set != list->current) { + struct cap_list_entry *entry = &al_array_at(list->entries, list->current); + if (!buffer_entry(cap, list, entry)) { + list_skip_internal(cap, list, 1); + return; + } + list->set = list->current; + if (list->swap && entry->buffer_requested) { + cap->callback(cap->userdata, CAP_SWAP, &list->name, &entry->unique_id, NULL); + } else { + cap->callback(cap->userdata, CAP_SET, &list->name, &entry->unique_id, NULL); + } + } + if (list->current + 1 < size) { + buffer_entry(cap, list, &al_array_at(list->entries, list->current + 1)); + } + if (list->current - 1 >= 0) { + buffer_entry(cap, list, &al_array_at(list->entries, list->current - 1)); + } + maybe_cleanup_entries(cap, list); +} + +bool list_skip_internal(struct cap_runner *cap, struct cap_list *list, s32 n) +{ + s32 size = (s32)list->entries.size; + if (list->current + n < 0 || list->current + n >= size) { + return false; + } + list->current += n; + list_pump_internal(cap, list); + return true; +} + +void cap_make_list(struct cap_runner *cap, str *name) +{ + struct cap_list list; + al_str_clone(&list.name, name); + list.current = 0; + list.set = -1; + list.idle = false; + list.swap = false; + al_array_init(list.entries); + al_array_push(cap->lists, list); +} + +void cap_list_add(struct cap_runner *cap, str *name, str *unique_id) +{ + struct cap_list *list = list_from_name(cap, name); + if (!list) return; + struct cap_list_entry entry; + al_str_clone(&entry.unique_id, unique_id); + entry.buffer_requested = false; + entry.errored = false; + al_array_push(list->entries, entry); + if (list->idle && list_skip_internal(cap, list, 1)) { + list->idle = false; + return; + } + list_pump_internal(cap, list); +} + +bool cap_list_skip(struct cap_runner *cap, str *name, s32 n) +{ + struct cap_list *list = list_from_name(cap, name); + if (!list) return false; + return list_skip_internal(cap, list, n); +} + +void cap_list_pump(struct cap_runner *cap, str *name) +{ + struct cap_list *list = list_from_name(cap, name); + if (list) list_pump_internal(cap, list); +} + +bool cap_list_set_completed(struct cap_runner *cap, str *name) +{ + struct cap_list *list = list_from_name(cap, name); + if (!list) return false; + list->swap = true; + list->idle = !list_skip_internal(cap, list, 1); + list->swap = false; + return !list->idle; +} + +static void list_close_internal(struct cap_list *list) +{ + struct cap_list_entry *entry; + al_array_foreach_ptr(list->entries, i, entry) { + al_str_free(&entry->unique_id); + } + al_array_free(list->entries); + al_str_free(&list->name); +} + +void cap_close(struct cap_runner *cap) +{ + struct cap_list *list; + al_array_foreach_ptr(cap->lists, i, list) { + list_close_internal(list); + } + al_array_free(cap->lists); +} diff --git a/src/fruits/cap/cap.h b/src/fruits/cap/cap.h new file mode 100644 index 0000000..d522a82 --- /dev/null +++ b/src/fruits/cap/cap.h @@ -0,0 +1,42 @@ +#pragma once + +#define CAP_USE_PYTHON 1 + +#include <al/array.h> +#include <al/str.h> + +struct cap_list_entry { + str unique_id; + bool buffer_requested; + bool errored; +}; + +struct cap_list { + str name; + s32 current; + s32 set; + bool idle; + bool swap; + array(struct cap_list_entry) entries; +}; + +enum { + CAP_BUFFER = 0, + CAP_SET, + CAP_SWAP, + CAP_UNLOAD +}; + +struct cap_runner { + array(struct cap_list) lists; + bool (*callback)(void *, u8, str *, str *, void *); + void *userdata; +}; + +void cap_init(struct cap_runner *cap, bool (*callback)(void *, u8, str *, str *, void *), void *userdata); +void cap_make_list(struct cap_runner *cap, str *name); +void cap_list_add(struct cap_runner *cap, str *name, str *unique_id); +bool cap_list_skip(struct cap_runner *cap, str *name, s32 n); +void cap_list_pump(struct cap_runner *cap, str *name); +bool cap_list_set_completed(struct cap_runner *cap, str *name); +void cap_close(struct cap_runner *cap); diff --git a/src/fruits/cap/meson.build b/src/fruits/cap/meson.build new file mode 100644 index 0000000..b5930ac --- /dev/null +++ b/src/fruits/cap/meson.build @@ -0,0 +1,4 @@ +cap_src = ['cap.c'] +cap_deps = [common_deps, shoki] +cap = declare_dependency(sources: cap_src, + dependencies: cap_deps) |