From 7e5043a2505efa383ae372662fa4849051cd9799 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Sat, 11 Nov 2023 17:51:49 -0500 Subject: Improve basic cmv usage - Make cap more robust - Disable ECHO in the TUI - Improve youtube playback url selection - Some cleanup Signed-off-by: Andrew Opalach --- NOTES | 17 ++++---- flake.nix | 6 +++ meson.build | 2 +- scripts/run.sh | 2 + scripts/run_debug.sh | 2 + src/buffer/audio.c | 14 ++++--- src/fruits/cap/cap.c | 87 ++++++++++++++++++++++++--------------- src/fruits/cap/cap.h | 7 +++- src/fruits/cmv/cmv2.c | 13 ++++-- src/fruits/cmv/tui.c | 14 +++++-- src/fruits/cmv/tui.h | 5 ++- src/libclient/meson.build | 2 +- src/libsink/sink.c | 44 ++++++++++++++++---- src/libsink/sink.h | 1 + src/shoki/py/providers/twitter.py | 3 +- src/shoki/py/providers/youtube.py | 29 ++++++++----- 16 files changed, 171 insertions(+), 77 deletions(-) create mode 100755 scripts/run.sh create mode 100755 scripts/run_debug.sh diff --git a/NOTES b/NOTES index b99ff5b..b3cbdd9 100644 --- a/NOTES +++ b/NOTES @@ -19,16 +19,19 @@ TODO: - [x] Cleanup camu - [x] Fix TODO's in sink.c - [x] Improve cch_handle "wait for any write" - - [ ] Upload everything to git - - [ ] Add timeout to aki_http - - [ ] Proper threaded upload for libsink - - [ ] Solidify scroll - - [ ] Complete as possible UI widget for a twitter post - - [ ] Add desktop code to git + - [x] Upload everything to git + - [ ] Tree server-sink support + - [ ] Networked bimu + - [ ] Remove thread from cch_handler_http (wait_for_range still needs a mutex, BIMU_THREADED_DEMUXING?) - [ ] Adapt all shoki backends to new post structure - [ ] Finally move archived twitter/pixiv files into a proper "camu_db" - - [ ] Windows file backend in libakiyo + - [ ] Native windows file backend in libakiyo - [ ] Add idle animation to cmv - https://www.shadertoy.com/view/wtsXRX - [ ] Add node paradigm to the server-client stuff - [ ] Allow cmv to act as a node + +PLANNED: + - [ ] Add timeout to aki_http + - [ ] Proper threaded upload for libsink + - [ ] Add GUI diff --git a/flake.nix b/flake.nix index 8c5c704..1c8abea 100644 --- a/flake.nix +++ b/flake.nix @@ -26,6 +26,8 @@ python3 python3.pkgs.requests python3.pkgs.pip + gsettings-desktop-schemas + multimarkdown ]; buildInputs = [ curl @@ -51,6 +53,10 @@ lz4 glm nlohmann_json + fftw + gst_all_1.gstreamer + gst_all_1.gst-plugins-base + gst_all_1.gst-plugins-good ]; shellHook = '' export NIX_SHELL=true diff --git a/meson.build b/meson.build index 6a0218d..50b778f 100644 --- a/meson.build +++ b/meson.build @@ -45,6 +45,6 @@ else subdir('src/libclient') subdir('src/libsink') subdir('src/tree') - #subdir('src/desktop') + #subdir('src/fruits/desktop') subdir('src/fruits/cmv') endif diff --git a/scripts/run.sh b/scripts/run.sh new file mode 100755 index 0000000..61acd73 --- /dev/null +++ b/scripts/run.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env sh +rm -f /tmp/cmv_sock && ./src/fruits/cmv/cmv2 $@ diff --git a/scripts/run_debug.sh b/scripts/run_debug.sh new file mode 100755 index 0000000..73c336f --- /dev/null +++ b/scripts/run_debug.sh @@ -0,0 +1,2 @@ +#! /usr/bin/env sh +rm -f /tmp/cmv_sock && gdb -ex run --args ./src/fruits/cmv/cmv2 $@ diff --git a/src/buffer/audio.c b/src/buffer/audio.c index 34d3c65..939b98a 100644 --- a/src/buffer/audio.c +++ b/src/buffer/audio.c @@ -73,8 +73,8 @@ bool camu_audio_buffer_init(struct camu_audio_buffer *buf, struct camu_clock *cl buf->clock = clock; buf->pts = camu_mixer_get_latency(buf->mixer); buf->buffered = false; - buf->pause = PAUSE_PRE; - //buf->pause = PAUSE_IGNORE_DESYNC; + //buf->pause = PAUSE_PRE; + buf->pause = PAUSE_IGNORE_DESYNC; #ifdef CAMU_AUDIO_BUFFER_FADE buf->fade_period = 0; buf->fade_offset = 0; @@ -248,6 +248,8 @@ static void handle_fade(struct camu_audio_buffer *buf, u8 *data, size_t size, bo } #endif +#define NOT_UNPAUSED(pause) (pause != PAUSE_UNPAUSED && pause != PAUSE_PRE && pause != PAUSE_IGNORE_DESYNC) + size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t req) { f64 pts = camu_clock_get_pts(buf->clock); @@ -260,7 +262,7 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re buf->pause = PAUSE_FADING; } else if (buf->fade_period == 0) { al_memset(data, 0, req); - if (buf->pause != PAUSE_UNPAUSED && buf->pause != PAUSE_PRE) { + if (NOT_UNPAUSED(buf->pause)) { buf->pause = PAUSE_UNPAUSED; buf->callback(buf->userdata, CAMU_BUFFER_PAUSED); } @@ -273,7 +275,7 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re buf->pause = PAUSE_PLAYING; #else al_memset(data, 0, req); - if (buf->pause != PAUSE_UNPAUSED && buf->pause != PAUSE_PRE) { + if (NOT_UNPAUSED(buf->pause)) { buf->pause = PAUSE_UNPAUSED; buf->callback(buf->userdata, CAMU_BUFFER_PAUSED); } @@ -315,12 +317,12 @@ size_t camu_audio_buffer_read(struct camu_audio_buffer *buf, u8 *data, size_t re if (flow == FLUSHED) { signal = size; al_atomic_u8_store(&buf->flow, SIGNALED, AL_ATOMIC_RELAXED); - al_log_debug("audio_buffer", "Flushed (signal: %li).", signal); + al_log_debug("audio_buffer", "Flushed (signal: %zu).", signal); buf->callback(buf->userdata, CAMU_BUFFER_EOF); } else { al_memset(data + size, 0, req - size); if (flow == FLOWING) { - al_log_warn("audio_buffer", "Underrun (req: %i, have: %i).", req, size); + al_log_warn("audio_buffer", "Underrun (req: %zu, have: %zu).", req, size); } } req = size; diff --git a/src/fruits/cap/cap.c b/src/fruits/cap/cap.c index 2f60cb4..e1d9e13 100644 --- a/src/fruits/cap/cap.c +++ b/src/fruits/cap/cap.c @@ -36,28 +36,25 @@ static struct cch_entry *entry_for_unique_id(str *unique_id) #if CAP_USE_PYTHON struct sho_search s; sho_search_init(&s); + str query; + al_str_from(&query, ""); 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, al_str_c("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, al_str_c("link:")); al_str_cat(&query, unique_id); } if (!sho_search_more_results(&s, al_str_c("youtube"), &query)) { } } + al_str_free(&query); entry = NULL; struct sho_result_page *page; al_array_foreach_ptr(s.result.pages, k, page) { @@ -77,7 +74,7 @@ static struct cch_entry *entry_for_unique_id(str *unique_id) #else if (!is_search) entry = cch_handler_http_create(unique_id); #endif - entry->handler->maybe_spawn_worker(entry->handler, 0); + if (entry) entry->handler->maybe_spawn_worker(entry->handler, 0); } else // { #endif entry = cch_handler_file_create(unique_id); @@ -87,10 +84,11 @@ static struct cch_entry *entry_for_unique_id(str *unique_id) static bool buffer_entry(struct cap_runner *cap, struct cap_list *list, struct cap_list_entry *entry) { + if (entry->errored) return false; 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->entry = entry_for_unique_id(&entry->unique_id); + if (!entry->entry) return false; + if (!cap->callback(cap->userdata, CAP_BUFFER, &list->name, &entry->unique_id, entry->entry)) { entry->errored = true; return false; } @@ -102,7 +100,7 @@ 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) { + if (entry->buffer_requested && abs(list->current - (s32)i) >= 3) { cap->callback(cap->userdata, CAP_UNLOAD, &list->name, &entry->unique_id, NULL); entry->buffer_requested = false; } @@ -111,28 +109,34 @@ static void maybe_cleanup_entries(struct cap_runner *cap, struct cap_list *list) 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) +static void list_pump_internal(struct cap_runner *cap, struct cap_list *list, bool buffer) { s32 size = (s32)list->entries.size; if (size <= list->current) return; + if (buffer) list->buffer = true; if (list->set != list->current) { struct cap_list_entry *entry = &al_array_at(list->entries, list->current); + if (list->swap && !entry->buffer_requested) { + list->swap = false; + return; + } if (!buffer_entry(cap, list, entry)) { - list_skip_internal(cap, list, 1); + list_skip_internal(cap, list, list->forward ? 1 : -1); return; } + cap->callback(cap->userdata, list->swap ? CAP_SWAP : CAP_SET, &list->name, &entry->unique_id, NULL); 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)); + if (list->buffer) { + for (s32 i = 1; i <= 2; i++) { + if (list->current + i < size) { + buffer_entry(cap, list, &al_array_at(list->entries, list->current + i)); + list->buffer = false; + } + if (list->current - i >= 0) { + buffer_entry(cap, list, &al_array_at(list->entries, list->current - i)); + } + } } maybe_cleanup_entries(cap, list); } @@ -144,7 +148,8 @@ bool list_skip_internal(struct cap_runner *cap, struct cap_list *list, s32 n) return false; } list->current += n; - list_pump_internal(cap, list); + list->forward = n >= 0; + list_pump_internal(cap, list, false); return true; } @@ -153,9 +158,12 @@ void cap_make_list(struct cap_runner *cap, str *name) struct cap_list list; al_str_clone(&list.name, name); list.current = 0; + list.forward = true; list.set = -1; list.idle = false; + list.buffer = false; list.swap = false; + aki_mutex_init(&list.mutex); al_array_init(list.entries); al_array_push(cap->lists, list); } @@ -164,39 +172,51 @@ 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; + aki_mutex_lock(&list->mutex); struct cap_list_entry entry; al_str_clone(&entry.unique_id, unique_id); - entry.buffer_requested = false; + entry.entry = NULL; entry.errored = false; + entry.buffer_requested = false; al_array_push(list->entries, entry); if (list->idle && list_skip_internal(cap, list, 1)) { list->idle = false; - return; + } else { + list_pump_internal(cap, list, false); } - list_pump_internal(cap, list); + aki_mutex_unlock(&list->mutex); } 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); + aki_mutex_lock(&list->mutex); + bool ret = list_skip_internal(cap, list, n); + aki_mutex_unlock(&list->mutex); + return ret; } -void cap_list_pump(struct cap_runner *cap, str *name) +void cap_list_pump(struct cap_runner *cap, str *name, bool buffer) { struct cap_list *list = list_from_name(cap, name); - if (list) list_pump_internal(cap, list); + if (!list) return; + aki_mutex_lock(&list->mutex); + list_pump_internal(cap, list, buffer); + aki_mutex_unlock(&list->mutex); } bool cap_list_set_completed(struct cap_runner *cap, str *name) { struct cap_list *list = list_from_name(cap, name); if (!list) return false; + aki_mutex_lock(&list->mutex); list->swap = true; list->idle = !list_skip_internal(cap, list, 1); + bool ret = !list->idle && list->swap; list->swap = false; - return !list->idle; + aki_mutex_unlock(&list->mutex); + return ret; } static void list_close_internal(struct cap_list *list) @@ -206,6 +226,7 @@ static void list_close_internal(struct cap_list *list) al_str_free(&entry->unique_id); } al_array_free(list->entries); + aki_mutex_destroy(&list->mutex); al_str_free(&list->name); } diff --git a/src/fruits/cap/cap.h b/src/fruits/cap/cap.h index d522a82..07aa63b 100644 --- a/src/fruits/cap/cap.h +++ b/src/fruits/cap/cap.h @@ -4,9 +4,11 @@ #include #include +#include struct cap_list_entry { str unique_id; + struct cch_entry *entry; bool buffer_requested; bool errored; }; @@ -14,9 +16,12 @@ struct cap_list_entry { struct cap_list { str name; s32 current; + bool forward; s32 set; bool idle; + bool buffer; bool swap; + struct aki_mutex mutex; array(struct cap_list_entry) entries; }; @@ -37,6 +42,6 @@ void cap_init(struct cap_runner *cap, bool (*callback)(void *, u8, str *, str *, 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); +void cap_list_pump(struct cap_runner *cap, str *name, bool buffer); bool cap_list_set_completed(struct cap_runner *cap, str *name); void cap_close(struct cap_runner *cap); diff --git a/src/fruits/cmv/cmv2.c b/src/fruits/cmv/cmv2.c index d8f4fc2..3c70317 100644 --- a/src/fruits/cmv/cmv2.c +++ b/src/fruits/cmv/cmv2.c @@ -42,8 +42,6 @@ struct cmv { #endif }; -static struct cmv c; - static str *default_list = al_str_c("default"); static u8 sink_callback(void *userdata, u8 op, u8 type, void *opaque) @@ -97,6 +95,10 @@ static u8 sink_callback(void *userdata, u8 op, u8 type, void *opaque) } } break; + case CAMU_SINK_SET_BUFFERED: { + cap_list_pump(&c->cap, default_list, true); + break; + } case CAMU_SINK_START: switch (type) { case CAMU_SINK_AUDIO: { @@ -177,6 +179,7 @@ static bool cap_callback(void *userdata, u8 op, str *name, str *unique_id, void return camu_sink_local_buffer(&c->sink, unique_id, (struct cch_entry *)opaque); case CAP_SET: camu_sink_local_set(&c->sink, unique_id); + al_log_info("cmv", "Now playing: %.*s.", AL_STR_PRINTF(unique_id)); break; case CAP_SWAP: camu_sink_local_swap(&c->sink, unique_id); @@ -237,12 +240,14 @@ s32 main(s32 argc, char *argv[]) { aki_common_init(); + struct cmv c = { }; + #if CMV_USE_TUI if (!tui_init(&c.tui)) { aki_common_close(); return EXIT_FAILURE; } - al_set_print(&c, log_callback); + al_set_print(log_callback, &c); #ifdef HAVE_FFMPEG camu_lav_set_log_callback(lav_log_callback); #endif @@ -297,7 +302,7 @@ s32 main(s32 argc, char *argv[]) #if CMV_USE_TUI aki_timer_init(&c.timer, &c.loop, timer_callback, &c); - aki_timer_set_repeat(&c.timer, 0.15); + aki_timer_set_repeat(&c.timer, 0.10); aki_timer_again(&c.timer); #endif diff --git a/src/fruits/cmv/tui.c b/src/fruits/cmv/tui.c index 84a1846..21aeac8 100644 --- a/src/fruits/cmv/tui.c +++ b/src/fruits/cmv/tui.c @@ -1,7 +1,6 @@ #include #include #include -#include #include "tui.h" @@ -31,15 +30,22 @@ bool tui_init(struct cmv_tui *tui) tui->height = 0; //tui->prev_lines = 0; - tui->fd = STDIN_FILENO; + tui->fd = fileno(stdin); tui->out = fdopen(tui->fd, "w"); if (!tui->out) return false; - setbuf(tui->out, NULL); tui_global = tui; aki_mutex_init(&tui->mutex); signal(SIGWINCH, handle_winch); + // Disable buffer. + setbuf(tui->out, NULL); + + // Disable echo. + tcgetattr(tui->fd, &tui->term); + tui->term.c_lflag &= ~ECHO; + tcsetattr(tui->fd, 0, &tui->term); + al_array_init(tui->log_buffer); tui->last_pts = 0.0; @@ -114,5 +120,7 @@ void tui_close(struct cmv_tui *tui) aki_mutex_destroy(&tui->mutex); fprintf(tui->out, "\n"); fflush(tui->out); + tui->term.c_lflag |= ECHO; + tcsetattr(tui->fd, 0, &tui->term); fclose(tui->out); } diff --git a/src/fruits/cmv/tui.h b/src/fruits/cmv/tui.h index 8cf58c0..fb4215e 100644 --- a/src/fruits/cmv/tui.h +++ b/src/fruits/cmv/tui.h @@ -1,18 +1,21 @@ #pragma once +#include + #include "../../bimu/local.h" #include "../../buffer/clock.h" struct cmv_tui { s32 fd; FILE *out; + struct aki_mutex mutex; + struct termios term; bool update_size; u32 width; u32 height; //u32 prev_lines; array(char *) log_buffer; f64 last_pts; - struct aki_mutex mutex; }; bool tui_init(struct cmv_tui *tui); diff --git a/src/libclient/meson.build b/src/libclient/meson.build index a2f23b0..99eabb2 100644 --- a/src/libclient/meson.build +++ b/src/libclient/meson.build @@ -1,3 +1,3 @@ -libclient_src = ['client.c', 'resource_client.c'] +libclient_src = ['client.c', 'search.c', 'resource_client.c'] libclient_deps = [shoki] libclient = declare_dependency(sources: libclient_src, dependencies: libclient_deps) diff --git a/src/libsink/sink.c b/src/libsink/sink.c index 50adb40..bae6c77 100644 --- a/src/libsink/sink.c +++ b/src/libsink/sink.c @@ -23,6 +23,7 @@ enum { enum { ADD_BUFFER = 0, REMOVE_BUFFER, + SET_BUFFERED, START, STOP, TOGGLE_PAUSE, @@ -73,6 +74,21 @@ static void handle_sink_cmd(struct camu_sink *sink, struct camu_sink_cmd *cmd) sink->callback(sink->userdata, CAMU_SINK_REMOVE_BUFFER, CAMU_SINK_VIDEO, &entry->video.buf); break; } +#endif + } + break; + } + case SET_BUFFERED: { + switch (cmd->value.i) { + case CAMU_SINK_AUDIO: { + sink->callback(sink->userdata, CAMU_SINK_SET_BUFFERED, CAMU_SINK_AUDIO, NULL); + break; + } +#ifndef CAMU_SINK_NO_VIDEO + case CAMU_SINK_VIDEO: { + sink->callback(sink->userdata, CAMU_SINK_SET_BUFFERED, CAMU_SINK_VIDEO, NULL); + break; + } #endif } break; @@ -178,6 +194,10 @@ static void add_audio_if_set_and_buffered(struct camu_sink_entry *entry) u8 state = entry->audio.state; if (state == BUFFER_SET_OR_BUFFERED) { entry->sink->callback(entry->sink->userdata, CAMU_SINK_ADD_BUFFER, CAMU_SINK_AUDIO, &entry->audio.buf); + queue_cmd(entry->sink, (struct camu_sink_cmd){ + .op = SET_BUFFERED, + .value.i = CAMU_SINK_AUDIO + }); queue_cmd(entry->sink, (struct camu_sink_cmd){ .op = START, .value.i = CAMU_SINK_AUDIO, @@ -230,6 +250,10 @@ static void audio_buffer_callback(void *userdata, u8 op) .value.i = CAMU_SINK_AUDIO, .opaque = entry->sink }); + queue_cmd(entry->sink, (struct camu_sink_cmd){ + .op = SET_BUFFERED, + .value.i = CAMU_SINK_VIDEO + }); } break; } @@ -242,6 +266,10 @@ static void add_video_if_set_and_buffered(struct camu_sink_entry *entry) u8 state = entry->video.state; if (state == BUFFER_SET_OR_BUFFERED) { entry->sink->callback(entry->sink->userdata, CAMU_SINK_ADD_BUFFER, CAMU_SINK_VIDEO, &entry->video.buf); + queue_cmd(entry->sink, (struct camu_sink_cmd){ + .op = SET_BUFFERED, + .value.i = CAMU_SINK_VIDEO + }); queue_cmd(entry->sink, (struct camu_sink_cmd){ .op = START, .value.i = CAMU_SINK_VIDEO, @@ -543,6 +571,7 @@ bool camu_sink_local_buffer(struct camu_sink *sink, str *unique_id, struct cch_e .value.f = 0, .opaque = entry }); + aki_mutex_unlock(&sink->mutex); return true; } @@ -599,17 +628,18 @@ void camu_sink_local_set(struct camu_sink *sink, str *unique_id) { aki_mutex_lock(&sink->mutex); struct camu_sink_entry *entry = entry_from_unique_id(sink, unique_id); - if (sink->current) { - if (!camu_clock_is_paused(&sink->current->clock)) { - camu_clock_pause(&sink->current->clock); - } - remove_entry_buffers(sink, sink->current); - } + struct camu_sink_entry *previous = sink->current; sink->current = entry; add_audio_if_set_and_buffered(entry); #ifndef CAMU_SINK_NO_VIDEO add_video_if_set_and_buffered(entry); #endif + if (previous) { + if (!camu_clock_is_paused(&previous->clock)) { + camu_clock_pause(&previous->clock); + } + remove_entry_buffers(sink, previous); + } maybe_cleanup_entries(sink); aki_mutex_unlock(&sink->mutex); } @@ -628,6 +658,6 @@ void camu_sink_local_unload(struct camu_sink *sink, str *unique_id) { aki_mutex_lock(&sink->mutex); struct camu_sink_entry *entry = entry_from_unique_id(sink, unique_id); - if (entry->state == ENTRY_LOADED) entry->state = ENTRY_DISREGUARDED; + if (entry && entry->state == ENTRY_LOADED) entry->state = ENTRY_DISREGUARDED; aki_mutex_unlock(&sink->mutex); } diff --git a/src/libsink/sink.h b/src/libsink/sink.h index e105245..92c18d9 100644 --- a/src/libsink/sink.h +++ b/src/libsink/sink.h @@ -30,6 +30,7 @@ enum { CAMU_SINK_ADD_BUFFER = 0, CAMU_SINK_REMOVE_BUFFER, CAMU_SINK_SWAP_BUFFER, + CAMU_SINK_SET_BUFFERED, CAMU_SINK_START, CAMU_SINK_STOP, CAMU_SINK_EXIT diff --git a/src/shoki/py/providers/twitter.py b/src/shoki/py/providers/twitter.py index 2fc0faf..4770dda 100644 --- a/src/shoki/py/providers/twitter.py +++ b/src/shoki/py/providers/twitter.py @@ -2,7 +2,6 @@ import json import config import http.cookiejar from datetime import timezone -from socketserver import UDPServer import log from provider import Provider @@ -13,7 +12,7 @@ from query_parser import QueryParser # Official Twitter API #from twitter import Twitter2, TwitterError, OAuth -# GraphQL Scrape API +# GraphQL API import snscrape.modules.twitter from snscrape.base import ScraperException from snscrape.modules.twitter import (TwitterSearchScraper, TwitterProfileScraper, diff --git a/src/shoki/py/providers/youtube.py b/src/shoki/py/providers/youtube.py index f17211e..3cbf0c8 100644 --- a/src/shoki/py/providers/youtube.py +++ b/src/shoki/py/providers/youtube.py @@ -1,9 +1,9 @@ import log -import yt_dlp from provider import Provider from search import Search from post import Post, PostType, Image, Video from query_parser import QueryParser +from yt_dlp import YoutubeDL class YDLLogger(): def debug(self, msg): @@ -28,24 +28,28 @@ ydl_opts = { # 'cookiefile': '', } -ydl = yt_dlp.YoutubeDL(ydl_opts) +ydl = YoutubeDL(ydl_opts) def get_playback_url(data, video=True): if 'entries' in data: + if len(data['entries']) == 0: + return None data = data['entries'][0] - url = data['formats'][0]['url'] + if 'formats' not in data: + if 'url' in data: + return data['url'] + return None - ''' - data['formats'] = list(filter(lambda f: 'container' not in f, data['formats'])) + # Filter out hls temporarily. + data['formats'] = list(filter(lambda f: not f['protocol'].startswith('m3u8'), data['formats'])) - data['formats'] = list(filter( - lambda f: not ('container' in f and (f['container'] in ['mp4_dash', 'webm_dash'])), data['formats'] - )) - ''' + if len(data['formats']) == 0: + return None - data['formats'] = list(filter(lambda f: 'manifest_url' not in f, data['formats'])) + url = data['formats'][0]['url'] + # audio_ext? has_audio = list(filter(lambda f: 'acodec' not in f or f['acodec'] != 'none', data['formats'])) if video: @@ -86,7 +90,10 @@ class YoutubeBase(Search): self.pages[index] = { 'posts': [], 'list': [] } res = self.get_info() if res: - media = [Video(url=get_playback_url(res))] + url = get_playback_url(res) + if not url: + return False + media = [Video(url=url)] self.pages[index]['posts'].append(Post(type=PostType.POST, unique_id='', url='', title='', text='', media=media)) return True -- cgit v1.2.3-101-g0448