From 65e2c7b6021ab00d80f1306d31155ac05f10af5e Mon Sep 17 00:00:00 2001 From: yazgoo Date: Tue, 17 Oct 2023 22:23:05 +0200 Subject: [PATCH 1/5] support more than 100 channels --- src/wtwitch | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/wtwitch b/src/wtwitch index 204bd5b..71ce0a4 100755 --- a/src/wtwitch +++ b/src/wtwitch @@ -1,5 +1,4 @@ #!/usr/bin/env bash -# # Description: Browse and watch Twitch without being tracked. # Homepage: https://github.com/krathalan/wtwitch # @@ -924,17 +923,22 @@ cache_online_subscription_json() # Make request URL with all streamers followed by &, so the request URL looks something like: # /streams?user_login=streamerone&user_login=streamertwo&user_login=streamerthree local requestURL - requestURL="${TWITCH_API_URL}/streams?user_login=$(jq -r ".subscriptions[].streamer" "${CONFIG_FILE}" | awk 1 ORS="&user_login=")" - # Remove trailing &user_login= - requestURL="${requestURL%&user_login=}" + local allStreamerJson="" + printf "" > "${CACHE_CHECK_JSON_TEXT_FILE}.tmp" + jq -r ".subscriptions[].streamer" "${CONFIG_FILE}" | xargs -n 99 | while read -r page + do + requestURL="${TWITCH_API_URL}/streams?user_login=$(echo "$page"| tr '\n' ' ' | sed 's/ /\&user_login=/g')" - # Get data of all online streamers (sans game names) - local -r allStreamerJson="$(download_file "${requestURL}")" + # Remove trailing &user_login= + requestURL="${requestURL%&user_login=}" - printf "%s" "${allStreamerJson}" > "${CACHE_CHECK_JSON_TEXT_FILE}" + # Get data of all online streamers (sans game names) + printf "%s" "$(download_file "${requestURL}")" >> "${CACHE_CHECK_JSON_TEXT_FILE}.tmp" + done + sed 's/\],"pagination".*{"data":\[/,/g' < "${CACHE_CHECK_JSON_TEXT_FILE}.tmp" > "${CACHE_CHECK_JSON_TEXT_FILE}" # Print usernames to cache file for easy mapfile-ing for tab completion - jq -r ".data[].user_login" <<< "${allStreamerJson}" > "${CACHE_ONLINE_SUBS_TEXT_FILE}" + jq -r ".data[].user_login" < "${CACHE_CHECK_JSON_TEXT_FILE}" > "${CACHE_ONLINE_SUBS_TEXT_FILE}" # Update lastSubscriptionUpdate time write_setting ".lastSubscriptionUpdate" "${CURRENT_TIME_UNIX}" & From b37e71bd382e69529f8af196f66e6dd1ef7be0a8 Mon Sep 17 00:00:00 2001 From: yazgoo Date: Tue, 17 Oct 2023 22:26:19 +0200 Subject: [PATCH 2/5] cleanup --- src/wtwitch | 1 - 1 file changed, 1 deletion(-) diff --git a/src/wtwitch b/src/wtwitch index 71ce0a4..ab86704 100755 --- a/src/wtwitch +++ b/src/wtwitch @@ -923,7 +923,6 @@ cache_online_subscription_json() # Make request URL with all streamers followed by &, so the request URL looks something like: # /streams?user_login=streamerone&user_login=streamertwo&user_login=streamerthree local requestURL - local allStreamerJson="" printf "" > "${CACHE_CHECK_JSON_TEXT_FILE}.tmp" jq -r ".subscriptions[].streamer" "${CONFIG_FILE}" | xargs -n 99 | while read -r page do From 67d4ea3106807136b4cac8145dbddac623bbe700 Mon Sep 17 00:00:00 2001 From: yazgoo Date: Wed, 18 Oct 2023 08:55:31 +0200 Subject: [PATCH 3/5] support empty data arrays --- src/wtwitch | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wtwitch b/src/wtwitch index ab86704..df108f9 100755 --- a/src/wtwitch +++ b/src/wtwitch @@ -935,7 +935,8 @@ cache_online_subscription_json() printf "%s" "$(download_file "${requestURL}")" >> "${CACHE_CHECK_JSON_TEXT_FILE}.tmp" done - sed 's/\],"pagination".*{"data":\[/,/g' < "${CACHE_CHECK_JSON_TEXT_FILE}.tmp" > "${CACHE_CHECK_JSON_TEXT_FILE}" + # merge all data arrays into one + sed 's/\],"pagination".*{"data":\[\]/]/g' < "${CACHE_CHECK_JSON_TEXT_FILE}.tmp" | sed 's/\],"pagination".*{"data":\[/,/g' > "${CACHE_CHECK_JSON_TEXT_FILE}" # Print usernames to cache file for easy mapfile-ing for tab completion jq -r ".data[].user_login" < "${CACHE_CHECK_JSON_TEXT_FILE}" > "${CACHE_ONLINE_SUBS_TEXT_FILE}" From 351b842079d76c31522008b9f9a7043a155c2654 Mon Sep 17 00:00:00 2001 From: yazgoo Date: Tue, 6 Feb 2024 12:22:32 +0100 Subject: [PATCH 4/5] allow open selected stream without fzf --- src/wtwitch | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/src/wtwitch b/src/wtwitch index df108f9..e55538e 100755 --- a/src/wtwitch +++ b/src/wtwitch @@ -463,12 +463,6 @@ TRANSLATIONS="$(cat <&2 + echo "$choices" | grep -i --color=always "$filter" >&2 + echo -en "\n> $filter" >&2 + read -rsn1 key &2 + case "$key" in + ' ') filter="$filter " ;; + '') + echo "$choices" | grep -i "$filter" | tail -1 | head -1 | remove_ansi_escape_codes + break + ;; + $'\x7f') filter="${filter%?}" ;; + *) filter="$filter$key" ;; + esac + done +} + open_selected_stream() { + local selector if ! command -v "fzf" &> /dev/null; then - exit_script_on_failure "$(get_translation install_fzf_first)" + selector=nofzf + else + selector="fzf --ansi" fi - stream="$(check_twitch_streams --online-only | fzf --ansi | cut -d: -f1 | sed 's/ *//')" + stream="$(check_twitch_streams --online-only | $selector | cut -d: -f1 | sed 's/ *//')" + + clear + echo "opening stream: $stream" if [ -n "$stream" ]; then watch_stream "$stream" From 20737b5fd95d3ded0645e1f6f2374dde13ae8df9 Mon Sep 17 00:00:00 2001 From: yazgoo Date: Sun, 11 Feb 2024 23:27:19 +0100 Subject: [PATCH 5/5] use fzh --- src/wtwitch | 187 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 166 insertions(+), 21 deletions(-) diff --git a/src/wtwitch b/src/wtwitch index e55538e..226e42e 100755 --- a/src/wtwitch +++ b/src/wtwitch @@ -951,38 +951,183 @@ remove_ansi_escape_codes() { sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]//g" } -nofzf() { - local choices - choices=$(cat) - local filter="" - while true - do - clear >&2 - echo "$choices" | grep -i --color=always "$filter" >&2 - echo -en "\n> $filter" >&2 - read -rsn1 key &2 + + +fsh() { + # https://github.com/yazgoo/fuzzysh/ + + setup_theme() { + selector_color=${FSH_SELECTOR_COLOR:=40} + grep_colors=${FSH_GREP_COLORS:='ms=01;92'} + frame_color=${FSH_FRAME_COLOR:=30} + prompt_color=${FSH_PROMPT_COLOR:=34} + select_color=${FSH_SELECT_COLOR:=31} + } + + remove_ansi_escape_codes() { + sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]//g" + } + + get_new_choices() { + echo "$choices" | GREP_COLORS="$grep_colors" grep -i --color=always "$filter" + } + + read_key() { + # not POSIX + IFS= read -rsn1 "$1" &2 + } + + handle_key() { + read_key key case "$key" in ' ') filter="$filter " ;; + $'\x1b') + read_key key3 + # arrows + read_key key2 + case "$key2" in + 'A') [ "$item_n" -lt "$((n_choices - 1))" ] && item_n=$((item_n + 1)) ;; + 'B') [ "$item_n" -gt 0 ] && item_n=$((item_n - 1)) ;; + *) ;; + esac + # flush stdin + read -rsn5 -t 0.1 + ;; '') - echo "$choices" | grep -i "$filter" | tail -1 | head -1 | remove_ansi_escape_codes - break - ;; + result=$(echo "$new_choices" | head "-$((item_n + 1))" | tail -1 | remove_ansi_escape_codes) + running=false + ;; + # not POSIX $'\x7f') filter="${filter%?}" ;; - *) filter="$filter$key" ;; + *) filter="${filter}${key}" ;; esac - done + } + + smcup() { + stty -echo + printf "\e[?1049h" + printf "\e[?25l" + } + + rmcup() { + printf "\e[?1049l" + printf "\e[?25h" + stty echo + } + + move_cursor_to() { + printf "\e[%d;%dH" "$1" "$2" + } + + start_color() { + printf "\e[1;%dm" "$1" + } + + end_color() { + printf "\e[0m" + } + + draw_frame() { + move_cursor_to 0 0 + start_color "$frame_color" + printf "┌%s┐" "$(printf '─%.0s' $(seq 1 $((columns - 2))))" + for i in $(seq 2 $((lines - 1))) + do + move_cursor_to "$i" 0 + printf "│" + move_cursor_to "$i" $columns + printf "│" + done + move_cursor_to $lines 0 + printf "└%s┘" "$(printf '─%.0s' $(seq 1 $((columns - 2))))" + end_color + } + + print_text() { + ( + i="$((n_choices - 1))" + echo "$new_choices" | tac | while read -r choice + do + cursor=" "$(end_color) + [ $i -eq $item_n ] && cursor=$(printf "%s>%s%s" "$(start_color "$select_color")" "$(end_color)" "$(start_color "$selector_color")") + printf "\n%s%s %s %s%s" "$(start_color "$selector_color")" "$cursor" "$choice" "$(end_color)" "$(printf " %.0s" $(seq 1 $((columns - 5 - ${#choice}))))" + i=$((i - 1)) + done + display_n_choice="$n_choices" + [ "$new_choices" = "" ] && display_n_choice=0 + choices_quota=$(printf "%d/%d" "$display_n_choice" "$total_n_choices") + printf "\n%s%s%s%s %s%s%s" "$(start_color "$frame_color")" "$choices_quota" "$(end_color)" "$header" $(start_color "$frame_color") "$(printf "─%.0s" $(seq 1 $((columns - 5 - ${#header} - ${#choices_quota}))))" "$(end_color)" + printf "\n%s>%s %s %s" "$(start_color "$prompt_color")" "$(end_color)" "$filter" "$(printf " %.0s" $(seq 1 $((columns - 5 - ${#filter}))))" + ) | sed 's/^/ /' + } + + draw_frame_content() { + new_choices=$(get_new_choices) + n_choices=$(echo "$new_choices" | wc -l) + start_line=$(( lines - n_choices - 4)) + for i in $(seq 1 $((start_line + 1))) + do + move_cursor_to "$i" 0 + printf " %0.s" $(seq 1 $((columns - 5))) + done + s=$(print_text) + printf "%s" "$s" + } + + init() { + setup_theme + header="" + [ "$#" -gt 1 ] && header=" $1" + if read -t 0; then + choices=$(cat) + else + choices=$(find . -not -path '*/.*' | sed 's,^./,,') + fi + total_n_choices=$(echo "$choices" | wc -l) + filter="" + result="" + running=true + item_n=0 + lines=$(tput lines) + columns=$(tput cols) + } + + draw() { + draw_frame_content + draw_frame + } + + run() { + clear >&2 + while $running + do + draw >&2 + handle_key >/dev/null 2>&1 + done + } + + main() { + init "$@" + smcup + run + rmcup + if [ -n "$result" ]; then + echo "$result" + else + false + fi + } + + main "$@" } open_selected_stream() { local selector - if ! command -v "fzf" &> /dev/null; then - selector=nofzf - else - selector="fzf --ansi" - fi + selector=fsh - stream="$(check_twitch_streams --online-only | $selector | cut -d: -f1 | sed 's/ *//')" + streams=$(check_twitch_streams --online-only) + stream="$(echo "$streams" | $selector | cut -d: -f1 | remove_ansi_escape_codes | sed -E "s/.* +//")" clear echo "opening stream: $stream"