diff --git a/src/wtwitch b/src/wtwitch index 204bd5b..226e42e 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 # @@ -464,12 +463,6 @@ TRANSLATIONS="$(cat < "${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 + # 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" <<< "${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}" & @@ -942,19 +940,197 @@ cache_online_subscription_json() } ####################################### -# Select and open online streams with FZF. +# Select and open online streams (uses FZF if available) # Arguments: # none # Returns: # none ####################################### + +remove_ansi_escape_codes() { + sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2};?)?)?[mGK]//g" +} + + + +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 + ;; + '') + result=$(echo "$new_choices" | head "-$((item_n + 1))" | tail -1 | remove_ansi_escape_codes) + running=false + ;; + # not POSIX + $'\x7f') filter="${filter%?}" ;; + *) filter="${filter}${key}" ;; + esac + } + + 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() { - if ! command -v "fzf" &> /dev/null; then - exit_script_on_failure "$(get_translation install_fzf_first)" - fi + local selector + selector=fsh + + streams=$(check_twitch_streams --online-only) + stream="$(echo "$streams" | $selector | cut -d: -f1 | remove_ansi_escape_codes | sed -E "s/.* +//")" - stream="$(check_twitch_streams --online-only | fzf --ansi | cut -d: -f1 | sed 's/ *//')" + clear + echo "opening stream: $stream" if [ -n "$stream" ]; then watch_stream "$stream"