diff --git a/README.md b/README.md
index 7f4b40f1..64eebdcd 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,9 @@
+# NOTICE
+
+This project is no longer actively maintained, it should still work for the foreseeable future
+
+---
+
@@ -26,14 +32,14 @@
# Table Of Contents
-* [`Dependencies`](#Dependencies)
-* [`Install`](#Install)
-* [`Features`](#Features)
-* [`Examples`](#Examples)
-* [`Configuration`](#Configuration)
-* [`Bugs`](#Bugs)
-* [`Contributing`](#Contributing)
-* [`Credits`](#Credits)
+- [`Dependencies`](#Dependencies)
+- [`Install`](#Install)
+- [`Features`](#Features)
+- [`Examples`](#Examples)
+- [`Configuration`](#Configuration)
+- [`Bugs`](#Bugs)
+- [`Contributing`](#Contributing)
+- [`Credits`](#Credits)
---
@@ -43,40 +49,40 @@ There are only 2 required dependencies, however the rest require some configurat
## Required dependencies
-* [`jq`](https://github.com/stedolan/jq)
-* [`curl`](https://github.com/curl/curl)
+- [`jq`](https://github.com/stedolan/jq)
+- [`curl`](https://github.com/curl/curl)
## Recommended dependencies
-* [`mpv`](https://github.com/mpv-player/mpv) (the default video and audio player)
-* [`fzf`](https://github.com/junegunn/fzf) (the default menu selection screen)
+- [`mpv`](https://github.com/mpv-player/mpv) (the default video and audio player)
+- [`fzf`](https://github.com/junegunn/fzf) (the default menu selection screen)
## Optional dependencies
-* [`yt-dlp`](https://github.com/yt-dlp/yt-dlp) (for downloading)
-* [`dmenu`](https://tools.suckless.org/dmenu/) (only if using the -D option)
-* [`ueberzugpp`](https://github.com/jstkdng/ueberzugpp)
- * needed for the following thumbnail viewers:
- * `kitty`, `iterm2`, `sixel`, and `ueberzug`
- * the original [`ueberzug`](https://github.com/seebye/ueberzug) or any fork may be used if you only want to use the `ueberzug` viewer.
+- [`yt-dlp`](https://github.com/yt-dlp/yt-dlp) (for downloading)
+- [`dmenu`](https://tools.suckless.org/dmenu/) (only if using the -D option)
+- [`ueberzugpp`](https://github.com/jstkdng/ueberzugpp)
+ - needed for the following thumbnail viewers:
+ - `kitty`, `iterm2`, `sixel`, and `ueberzug`
+ - the original [`ueberzug`](https://github.com/seebye/ueberzug) or any fork may be used if you only want to use the `ueberzug` viewer.
### Thumbnail Viewers
-* **To use a thumbnail viewer include `-T ` in the command when running ytfzf**
-
-| Program | Wayland Support |
-| :-- | :-- |
-| [`kitty`](https://github.com/kovidgoyal/kitty) (requires `ueberzugpp`) | ✅ |
-| `iterm2` (requires `ueberzugpp`) | ✅ |
-| `sixel` (requires `ueberzugpp`) | ✅ |
-| `sway` (requires `ueberzugpp`) | &9989; (only on sway)|
-| `wayland` (requires `ueberzugpp`) | &9989; |
-| [`chafa`](https://github.com/hpjansson/chafa) | ✅ |
-| [`catimg`](https://github.com/posva/catimg) | ✅ |
-| [`imv`](https://git.sr.ht/~exec64/imv) | ✅ |
-| [`mpv`](https://github.com/mpv-player/mpv) | ✅ |
-| [`swayimg`](https://github.com/artemsen/swayimg) | only on `sway` |
-| [`swayimg`](https://github.com/artemsen/swayimg) (-T swayimg-hyprland) | only on `hyprland` |
+- **To use a thumbnail viewer include `-T ` in the command when running ytfzf**
+
+| Program | Wayland Support |
+| :--------------------------------------------------------------------- | :--------------------- |
+| [`kitty`](https://github.com/kovidgoyal/kitty) (requires `ueberzugpp`) | ✅ |
+| `iterm2` (requires `ueberzugpp`) | ✅ |
+| `sixel` (requires `ueberzugpp`) | ✅ |
+| `sway` (requires `ueberzugpp`) | ✅ (only on sway) |
+| `wayland` (requires `ueberzugpp`) | ✅ |
+| [`chafa`](https://github.com/hpjansson/chafa) | ✅ |
+| [`catimg`](https://github.com/posva/catimg) | ✅ |
+| [`imv`](https://git.sr.ht/~exec64/imv) | ✅ |
+| [`mpv`](https://github.com/mpv-player/mpv) | ✅ |
+| [`swayimg`](https://github.com/artemsen/swayimg) | only on `sway` |
+| [`swayimg`](https://github.com/artemsen/swayimg) (-T swayimg-hyprland) | only on `hyprland` |
# Install
@@ -88,19 +94,21 @@ There are only 2 required dependencies, however the rest require some configurat
1. Install the dependencies listed [above](#Dependencies)
2. Run the following commands
+
```sh
git clone https://github.com/pystardust/ytfzf
cd ytfzf
sudo make install doc
```
-* If you wish to not install documentation (highly unrecommended) run `sudo make install` instead.
+- If you wish to not install documentation (highly unrecommended) run `sudo make install` instead.
+
+- If you wish to install addons, run `sudo make addons`
-* If you wish to install addons, run `sudo make addons`
- * `YTFZF_SYSTEM_ADDONS_DIR` will point to `/usr/local/share/ytfzf/addons` even if you set `PREFIX` to something else
- * If you use a different prefix, it would be smart to export `YTFZF_SYSTEM_ADDONS_DIR` to `$PREFIX/share/ytfzf/addons` in a shell startup file.
+ - `YTFZF_SYSTEM_ADDONS_DIR` will point to `/usr/local/share/ytfzf/addons` even if you set `PREFIX` to something else
+ - If you use a different prefix, it would be smart to export `YTFZF_SYSTEM_ADDONS_DIR` to `$PREFIX/share/ytfzf/addons` in a shell startup file.
-* You may also install `ytfzf` through your package manager, as listed on the side.
+- You may also install `ytfzf` through your package manager, as listed on the side.
## Addons
@@ -128,14 +136,14 @@ To use an extension addon run `ytfzf -e ...`
# Features
-* Subscriptions
-* Thumbnails
-* Watch history
-* Search History
-* Downloading
-* Queueing multiple videos
-* Custom menus, and scrapers
-* Addon support
+- Subscriptions
+- Thumbnails
+- Watch history
+- Search History
+- Downloading
+- Queueing multiple videos
+- Custom menus, and scrapers
+- Addon support
---
@@ -165,7 +173,7 @@ ytfzf -L
ytfzf -cO
```
-> Use the chafa thumbnail viewer, pass --vo=sixel, and --quiet to mpv, scrape odysee with the search *odysee search*, youtube with the search: *youtube search*, and also scrape subscriptions
+> Use the chafa thumbnail viewer, pass --vo=sixel, and --quiet to mpv, scrape odysee with the search _odysee search_, youtube with the search: _youtube search_, and also scrape subscriptions
```sh
ytfzf -t -T chafa --url-handler-opts='--vo=sixel --quiet' -cO,Y,SI --multi-search odysee search,youtube search
@@ -187,9 +195,9 @@ For more information, see `ytfzf(5)` which should be installed, if it's not see
# Bugs
-* *dwm with swallow patch: Images don't render with ueberzug when looped (ie, option `-l`)*
-* *if thumbnails are not working `.Xauthority` might be causing it. Try deleting it and relogging into your computer.*
-* When fzf is not set to 100% height, thumbnails may appear in the wrong position
+- _dwm with swallow patch: Images don't render with ueberzug when looped (ie, option `-l`)_
+- _if thumbnails are not working `.Xauthority` might be causing it. Try deleting it and relogging into your computer._
+- When fzf is not set to 100% height, thumbnails may appear in the wrong position
# Contributing
@@ -197,14 +205,13 @@ Feel free to contribute, and add your name to the credits, please use the develo
# Credits
-| User | Contributions | Donate|
-| :--- | :--- | :--- |
-| Pystardust | [contributions](credits/pystardust.md) ||
-| Euro20179 | [contributions](credits/euro20179.md) ||
-| Simonhughxyz | [contributions](credits/simonhughxyz.md) ||
-| Jac-Zac | [contributions](credits/jac-zac.md) ||
-| Mudskipper875 | [contributions](credits/mudskipper875.md) ||
-| Gardockt | [contributions](credits/gardockt.md)||
-| qoheniac | [contributions](credits/qoheniac.md)||
-| mathisto | [contributions](credits/mathisto.md)||
-
+| User | Contributions | Donate |
+| :------------ | :---------------------------------------- | :----- |
+| Pystardust | [contributions](credits/pystardust.md) | |
+| Euro20179 | [contributions](credits/euro20179.md) | |
+| Simonhughxyz | [contributions](credits/simonhughxyz.md) | |
+| Jac-Zac | [contributions](credits/jac-zac.md) | |
+| Mudskipper875 | [contributions](credits/mudskipper875.md) | |
+| Gardockt | [contributions](credits/gardockt.md) | |
+| qoheniac | [contributions](credits/qoheniac.md) | |
+| mathisto | [contributions](credits/mathisto.md) | |
diff --git a/addons/scrapers/yt-music-utils/convert-ascii-escape.pl b/addons/scrapers/yt-music-utils/convert-ascii-escape.pl
index cb334974..a1f54d55 100755
--- a/addons/scrapers/yt-music-utils/convert-ascii-escape.pl
+++ b/addons/scrapers/yt-music-utils/convert-ascii-escape.pl
@@ -3,8 +3,6 @@
use strict;
use warnings;
-binmode(STDOUT, 'utf8');
-
while(<>){
s/\\x([0-9a-fA-F]{2})/chr(hex($1))/eg;
print;
diff --git a/docs/man/ytfzf.5 b/docs/man/ytfzf.5
index c6cc7c32..d760b500 100644
--- a/docs/man/ytfzf.5
+++ b/docs/man/ytfzf.5
@@ -254,6 +254,12 @@ Valid options:
.IR default: " left"
.RE
+.TP
+.RB $ preview_window_width
+The amount of space to use for the fzf preview
+.br
+.IR default: " 50%"
+
.TP
.RB $ thumbnail_viewer
The program to display images for thumbnail previews
@@ -457,67 +463,79 @@ Whether or not to make another search after fzf is closed.
.br
.IR default: " 0"
+.TP
+.RB $ selection_meta_key
+The meta key for shortcuts that select a video.
+.br
+.IR default: " alt"
+
.TP
.RB $ download_shortcut
The shortcut to download the selected videos.
.br
-.IR default: " alt-d"
+.IR default: " $selection_meta_key-d"
.TP
.RB $ video_shortcut
The shortcut to watch the selected videos.
.br
-.IR default: " alt-v"
+.IR default: " $selection_meta_key-v"
.TP
.RB $ audio_shortcut
The shortcut to listen to the selected videos.
.br
-.IR default: " alt-m"
+.IR default: " $selection_meta_key-m"
.TP
.RB $ detach_shortcut
The shortcut to use the detach player.
.br
-.IR default: " alt-e"
+.IR default: " $selection_meta_key-e"
.TP
.RB $ print_link_shortcut
The shortcut to use to print the link.
.br
-.IR default: " alt-l"
+.IR default: " $selection_meta_key-l"
.TP
.RB $ show_formats_shortcut
The shortcut to show formats before playing the video.
.br
-.IR default: " alt-f"
+.IR default: " $selection_meta_key-f"
.TP
.RB $ info_shortcut
The shortcut to get all info about the selected video.
.br
-.IR default: " alt-i"
+.IR default: " $selection_meta_key-i"
.TP
.RB $ search_again_shortcut
The shortcut to make another search.
.br
-.IR default: " alt-s"
+.IR default: " $selection_meta_key-s"
.TP
-.RB $ shortcut_binds
-The keys to listen for in fzf.
+.RB $ action_meta_key
+The meta key for shorcuts that do something
.br
-.IR default: " Enter,double-click,$download_shortcut,
-$video_shortcut,$detach_shortcut,$print_link_shortcut,$show_formats_shortcut,
-$info_shortcut,$search_again_shortcut,$custom_shortcut_binds"
+.IR default: " ctrl"
.TP
.RB next_page_action_shortcut
The shortcut to scrape the next page.
.br
-.IR default: " ctrl-p"
+.IR default: " $action_meta_key-p"
+
+.TP
+.RB $ shortcut_binds
+The keys to listen for in fzf.
+.br
+.IR default: " Enter,double-click,$download_shortcut,
+$video_shortcut,$detach_shortcut,$print_link_shortcut,$show_formats_shortcut,
+$info_shortcut,$search_again_shortcut,$custom_shortcut_binds"
.TP
.RB $ custom_shortcut_binds
@@ -745,6 +763,11 @@ Misc
.RS
+.TP
+.RB $ gap_space
+The amount of space after the title in the thumbnail viewer menu.
+.IR default: "' '"
+
.TP
.RB $ scrape_search_exclude
The scrapers to not ask for a search query.
diff --git a/ytfzf b/ytfzf
index 9b96e8e1..b84a0cb8 100755
--- a/ytfzf
+++ b/ytfzf
@@ -5,7 +5,7 @@
# versioning system:
# major.minor.bugs
-YTFZF_VERSION="2.6.1"
+YTFZF_VERSION="git-2051.a67ba26"
#ENVIRONMENT VARIABLES {{{
: "${YTFZF_CONFIG_DIR:=${XDG_CONFIG_HOME:-$HOME/.config}/ytfzf}"
@@ -26,9 +26,9 @@ YTFZF_VERSION="2.6.1"
: "${YTFZF_LOGFILE:=}"
if [ "$YTFZF_LOGFILE" ] && { [ "$__is_fzf_preview" -eq 1 ] || [ "$__is_submenu" -eq 1 ]; }; then
- printf "[%s]\n==============\nSubmenu: %d\nFzf Preview: %d\n==============\n" "$(date)" "$__is_submenu" "$__is_fzf_preview" >> "${YTFZF_LOGFILE}"
+ printf "[%s]\n==============\nSubmenu: %d\nFzf Preview: %d\n==============\n" "$(date)" "$__is_submenu" "$__is_fzf_preview" >>"${YTFZF_LOGFILE}"
elif [ "${YTFZF_LOGFILE}" ]; then
- : > "${YTFZF_LOGFILE}"
+ : >"${YTFZF_LOGFILE}"
fi
! [ -d "$YTFZF_TEMP_DIR" ] && mkdir -p "${YTFZF_TEMP_DIR}"
@@ -282,7 +282,7 @@ print_help___ytfzf__() {
month
year
- --video-duration= Searches for vidos that are:
+ --video-duration= Searches for videos that are:
short
medium
long
@@ -385,10 +385,10 @@ on_clean_up___ytfzf__() {
done <"$jobs_file"
rm -f "$jobs_file"
#}}}
- if [ "$__is_fzf_preview" -eq 0 ]; then
- [ "$keep_cache" -eq 1 ] && print_debug "[CLEAN UP]: copying cache dir${new_line}" && cp -r "${session_cache_dir}" "${cache_dir}"
- [ -d "$session_cache_dir" ] && rm -rf "$session_cache_dir"
- fi
+ if [ "$__is_fzf_preview" -eq 0 ]; then
+ [ "$keep_cache" -eq 1 ] && print_debug "[CLEAN UP]: copying cache dir" && cp -r "${session_cache_dir}" "${cache_dir}"
+ [ -d "$session_cache_dir" ] && rm -rf "$session_cache_dir"
+ fi
}
on_load_fake_extension___ytfzf__() {
@@ -416,8 +416,8 @@ on_post_set_vars___ytfzf__() {
: "${invidious_instance:=$(get_random_invidious_instance)}"
- #if there is no domain, use the chosen invidious instance
- [ -z "${yt_video_link_domain}" ] && yt_video_link_domain="${invidious_instance}"
+ #if there is no domain, use the chosen invidious instance
+ [ -z "${yt_video_link_domain}" ] && yt_video_link_domain="${invidious_instance}"
export FZF_DEFAULT_OPTS="--margin=0,3,0,0 $FZF_DEFAULT_OPTS"
@@ -427,9 +427,9 @@ on_post_set_vars___ytfzf__() {
source_scrapers
- print_debug "${new_line}=============${new_line}VARIABLE DUMP${new_line}=============${new_line}"
- print_debug "$(set)${new_line}"
- print_debug "${new_line}============${new_line}END VAR DUMP${new_line}============${new_line}"
+ print_debug "${new_line}=============${new_line}VARIABLE DUMP${new_line}============="
+ print_debug "$(set)"
+ print_debug "${new_line}============${new_line}END VAR DUMP${new_line}============"
}
#}}}
@@ -472,16 +472,16 @@ on_load_fake_extension___ytfzf_history_management__() {
case "$1" in
search)
: >"$search_hist_file"
- print_info "Search history cleared${new_line}"
+ print_info "Search history cleared"
;;
watch)
: >"$hist_file"
- print_info "Watch history cleared${new_line}"
+ print_info "Watch history cleared"
;;
*)
: >"$search_hist_file"
: >"$hist_file"
- print_info "History cleared${new_line}"
+ print_info "History cleared"
;;
esac
}
@@ -496,7 +496,7 @@ on_load_fake_extension___ytfzf_history__() {
: "${hist_file:="$cache_dir/watch_hist"}"
on_opt_parse_history() {
if [ "$enable_hist" -eq 0 ]; then
- die 1 "enable_hist must be set to 1 for -H/--history${new_line}"
+ die 1 "enable_hist must be set to 1 for -H/--history"
fi
scrape=history
}
@@ -511,12 +511,12 @@ on_open_url_handler___ytfzf_history__() {
add_to_hist() {
[ "$enable_hist" -eq 1 ] || return
- print_debug "[WATCH HIST]: adding to file $hist_file${new_line}"
+ print_debug "[WATCH HIST]: adding to file $hist_file"
# id of the video to add to hist will be passed through stdin
# if multiple videos are selected, multiple ids will be present on multiple lines
json_file="$1"
- urls="$(printf '"%s",' $(cat))"
- urls="[${urls%,}]"
+ urls="$(printf '"%s",' $(cat))"
+ urls="[${urls%,}]"
jq -r '[ .[]|select(.url as $url | '"$urls"' | index($url) >= 0)]' <"$json_file" | sed "/\[\]/d" | sed "2s/$/\n \"viewed\": \"$(date +'%m\/%d\/%y\ %H\:%M\:%S\ %z')\",/" >>"$hist_file"
unset url urls json_file
}
@@ -554,9 +554,9 @@ on_load_fake_extension___ytfzf_search_history__() {
: "${search_hist_file:="$cache_dir/search_hist"}"
on_opt_parse_q() {
if [ "$enable_search_hist" -eq 0 ]; then
- die 1 'In order to use this search history must be enabled${new_line}'
+ die 1 "In order to use this search history must be enabled"
fi
- [ ! -s "$search_hist_file" ] && die 1 "You have no search history${new_line}"
+ [ ! -s "$search_hist_file" ] && die 1 "You have no search history"
search_source="hist"
}
on_opt_parse_search_hist() {
@@ -565,7 +565,7 @@ on_load_fake_extension___ytfzf_search_history__() {
}
on_post_set_vars___ytfzf_search_history__() {
- [ "${use_search_hist:-0}" -eq 1 ] && print_warning "use_search_hist is deprecated, please use search_source=hist instead${new_line}" && search_source=hist
+ [ "${use_search_hist:-0}" -eq 1 ] && print_warning "use_search_hist is deprecated, please use search_source=hist instead" && search_source=hist
}
on_init_search___ytfzf_history__() {
@@ -606,7 +606,7 @@ def pad_left(n; num):
# Invidious{{{
refresh_inv_instances() {
- print_info "Fetching list of healthy invidious instances ...${new_line}" &&
+ print_info "Fetching list of healthy invidious instances ..." &&
# The pipeline does the following:
# - Fetches the avaiable invidious instances
# - Gets the one where the api is public
@@ -641,7 +641,7 @@ create_sorted_video_data() {
download_thumbnails() {
[ "$skip_thumb_download" -eq 1 ] && {
- print_info "Skipping thumbnail download${new_line}"
+ print_info "Skipping thumbnail download"
return 0
}
[ "$async_thumbnails" -eq 0 ] && print_info "Fetching thumbnails...${new_line}"
@@ -705,10 +705,10 @@ _get_real_channel_link() {
http?://*/@*)
domain=${_input_link#https://}
domain=${domain%%/*}
- url=$(printf "https://www.youtube.com/channel/%s\n" "$(_get_request "$_input_link" | sed -n 's/.*"channelId":"\([^"]\+\).*/\1/p')")
- _get_real_channel_link_handle_empty_real_path () {
- printf "$url"
- }
+ url=$(printf "https://www.youtube.com/channel/%s\n" "$(_get_request "$_input_link" | sed -n 's/.*"channelId":"\([^"]\+\).*/\1/p')")
+ _get_real_channel_link_handle_empty_real_path() {
+ printf "$url"
+ }
;;
http?://*/c/* | http?://*/user/* | *\.*)
domain=${_input_link#https://}
@@ -723,7 +723,7 @@ _get_real_channel_link() {
id="${id%/playlists}"
id="${id%/streams}"
id="${id##*channel/}"
- print_warning "$_input_link appears to be a youtube id, which is hard to detect, please use a full channel url next time${new_line}"
+ print_warning "$_input_link appears to be a youtube id, which is hard to detect, please use a full channel url next time"
domain="youtube.com"
url=$(printf "https://youtube.com/channel/%s/videos" "$id" | sed 's_\(https://\)*\(www\.\)*youtube\.com_'"${invidious_instance}"'_')
_get_real_channel_link_handle_empty_real_path() {
@@ -762,8 +762,11 @@ trim_url() {
done
}
-trim_blank() { _s="${1##[[:blank:]]}"; printf '%s' "${_s%%[[:blank:]]}"; }
-
+trim_blank() {
+ sed -e 's/^[[:blank:]]*//g' -e 's/[[:blank:]]*$//g' </dev/null 2>&1
@@ -891,10 +894,10 @@ generic_wrapper() {
shift
fn_name="$base_name""$(printf "%s" "${interface:+_$interface}" | sed 's/-/_/g')"
if command_exists "$fn_name"; then
- print_debug "[INTERFACE]: Running menu function: $fn_name${new_line}"
+ print_debug "[INTERFACE]: Running menu function: $fn_name"
$fn_name "$@"
else
- print_debug "[INTERFACE]: Menu function $fn_name did not exist, falling back to ${base_name}_ext${new_line}"
+ print_debug "[INTERFACE]: Menu function $fn_name did not exist, falling back to ${base_name}_ext"
"$base_name"_ext "$@"
fi
unset fn_name
@@ -928,7 +931,7 @@ run_interface() {
_interface="interface_${interface:-text}"
- print_debug "[INTERFACE]: Running interface: $_interface${new_line}"
+ print_debug "[INTERFACE]: Running interface: $_interface"
$(printf "%s" "$_interface" | sed 's/-/_/g') "$ytfzf_video_json_file" "$ytfzf_selected_urls"
unset _interface
@@ -937,10 +940,10 @@ run_interface() {
_init_video_info_text() {
TTY_COLS=$1
- command_exists "column" && use_column=1 || {
- use_column=0
- print_warning "command \"column\" not found, the menu may look very bad${new_line}"
- }
+ command_exists "column" && use_column=1 || {
+ use_column=0
+ print_warning "command \"column\" not found, the menu may look very bad"
+ }
title_len=$((TTY_COLS / 2))
channel_len=$((TTY_COLS / 5))
@@ -950,7 +953,7 @@ _init_video_info_text() {
}
_post_video_info_text() {
- if [ "$use_column" = "1" ] ; then
+ if [ "$use_column" = "1" ]; then
column -t -s "$tab_space"
else
cat
@@ -1002,12 +1005,11 @@ thumbnail_video_info_text() {
do_an_event_function() {
event="$1"
shift
- print_debug "[EVENT]: doing event: $event${new_line}"
+ print_debug "[EVENT]: doing event: $event"
command_exists "$event" && $event "$@"
prepare_for_set_args " "
for ext in $loaded_extensions; do
-
- command_exists "${event}_$ext" && print_debug "[EVENT]: $ext running $event${new_line}" && "${event}_$ext" "$@"
+ command_exists "${event}_$ext" && print_debug "[EVENT]: $ext running $event" && "${event}_$ext" "$@"
done
end_of_set_args
}
@@ -1023,7 +1025,7 @@ source_scrapers() {
. "${YTFZF_SYSTEM_ADDON_DIR}/scrapers/$_scr"
fi
[ "$__is_fzf_preview" -eq 0 ] && command_exists "on_startup_$_scr" && "on_startup_$_scr"
- print_debug "[LOADING]: Loaded scraper: $_scr${new_line}"
+ print_debug "[LOADING]: Loaded scraper: $_scr"
done
end_of_set_args
}
@@ -1054,7 +1056,7 @@ load_extension() {
done
end_of_set_args
- print_debug "[LOADING]: loaded extension: ${ext} with exit code: ${rv}${new_line}"
+ print_debug "[LOADING]: loaded extension: ${ext} with exit code: ${rv}"
return $rv
}
@@ -1070,7 +1072,7 @@ load_fake_extension() {
fi
command_exists "on_load_fake_extension_$1" && on_load_fake_extension_"$1"
- print_debug "[LOADING]: fake extension: $1 loaded${new_line}"
+ print_debug "[LOADING]: fake extension: $1 loaded"
}
load_sort_name() {
@@ -1091,7 +1093,7 @@ load_sort_name() {
esac
rv="$?"
unset "$_sort_name"
- print_debug "[LOADING]: loaded sort name: ${_sort_name} with exit code: ${rv}${new_line}"
+ print_debug "[LOADING]: loaded sort name: ${_sort_name} with exit code: ${rv}"
return "$rv"
}
@@ -1103,9 +1105,9 @@ load_url_handler() {
for path in "$YTFZF_URL_HANDLERS_DIR" "$YTFZF_SYSTEM_ADDON_DIR/url-handlers"; do
[ -f "${path}/${requested_url_handler}" ] && url_handler="${path}/${requested_url_handler}" && return
done
- die 2 "$1 is not a url-handler${new_line}"
+ die 2 "$1 is not a url-handler"
fi
- print_debug "[LOADING]: loaded url handler: ${requested_url_handler}${new_line}"
+ print_debug "[LOADING]: loaded url handler: ${requested_url_handler}"
}
load_interface() {
@@ -1134,7 +1136,7 @@ load_interface() {
esac
rv="$?"
unset requested_interface
- print_debug "[LOADING]: loaded interface: ${requested_interface}${new_line}"
+ print_debug "[LOADING]: loaded interface: ${requested_interface}"
return "$rv"
}
@@ -1147,7 +1149,7 @@ load_thumbnail_viewer() {
true
;;
swayimg-hyprland)
- print_warning "swayimg-hyprland thumbnail viewer may mess up any rules you have for swayimg${new_line}"
+ print_warning "swayimg-hyprland thumbnail viewer may mess up any rules you have for swayimg"
thumbnail_viewer="$_thumbnail_viewer"
;;
./* | /* | ../* | ~/*)
@@ -1164,7 +1166,7 @@ load_thumbnail_viewer() {
;;
esac
rv="$?"
- print_debug "[LOADING]: loaded thumbnail viewer: ${_thumbnail_viewer}${new_line}"
+ print_debug "[LOADING]: loaded thumbnail viewer: ${_thumbnail_viewer}"
unset _thumbnail_viewer
return $rv
}
@@ -1172,27 +1174,27 @@ load_thumbnail_viewer() {
# Logging {{{
-_print_to_log_and_stderr () {
- tee -a "${YTFZF_LOGFILE:-/dev/null}" <&2
+_print_to_log_and_stderr() {
+ tee -a "${YTFZF_LOGFILE:-/dev/null}" <&2
$(printf -- "$1")
EOF
}
print_debug() {
- [ "${YTFZF_LOGFILE}" ] && pre_text="[DEBUG]" || pre_text="${c_blue}[DEBUG]${c_reset}"
- [ "$log_level" -ge 3 ] && _print_to_log_and_stderr "${pre_text}: $1"
- return 0
+ [ "${YTFZF_LOGFILE}" ] && pre_text="[DEBUG]" || pre_text="${c_blue}[DEBUG]${c_reset}"
+ [ "$log_level" -ge 3 ] && _print_to_log_and_stderr "${pre_text}: $1"
+ return 0
}
print_info() {
- [ "$log_level" -ge 2 ] && _print_to_log_and_stderr "$1"
+ [ "$log_level" -ge 2 ] && _print_to_log_and_stderr "$1"
}
print_warning() {
- [ "${YTFZF_LOGFILE}" ] && pre_text="[WARNING]" || pre_text="${c_yellow}[WARNING]${c_reset}"
- [ "$log_level" -ge 1 ] && _print_to_log_and_stderr "${pre_text}: $1"
+ [ "${YTFZF_LOGFILE}" ] && pre_text="[WARNING]" || pre_text="${c_yellow}[WARNING]${c_reset}"
+ [ "$log_level" -ge 1 ] && _print_to_log_and_stderr "${pre_text}: $1"
}
print_error() {
- [ "${YTFZF_LOGFILE}" ] && pre_text="[ERROR]" || pre_text="${c_red}[ERROR]${c_reset}"
- [ "$log_level" -ge 0 ] && _print_to_log_and_stderr "${pre_text}: $1"
+ [ "${YTFZF_LOGFILE}" ] && pre_text="[ERROR]" || pre_text="${c_red}[ERROR]${c_reset}"
+ [ "$log_level" -ge 0 ] && _print_to_log_and_stderr "${pre_text}: $1"
}
die() {
@@ -1310,7 +1312,7 @@ set_vars() {
# global vars
- gap_space=" "
+ gap_space=" "
new_line='
' tab_space=$(printf '\t')
#necessary as a seperator for -W
@@ -1326,7 +1328,7 @@ set_vars() {
TTY_LINES="${stty_cols_lines% *}"
TTY_COLS="${stty_cols_lines#* }"
else
- print_warning "Could not determine terminal size, defaulting to 80 COLUMNS x 25 LINES${new_line}"
+ print_warning "Could not determine terminal size, defaulting to 80 COLUMNS x 25 LINES"
TTY_COLS=80
TTY_LINES=25
fi
@@ -1340,6 +1342,8 @@ set_vars() {
# menu options
+ preview_window_width=50%
+
enable_submenus="1" submenu_opts="" submenu_scraping_opts="" enable_back_button="1"
keep_vars=0
@@ -1352,10 +1356,13 @@ set_vars() {
#actions are slow, disable if you want to increase runtime speed by 15ms
enable_actions=1
+ selection_meta_key="alt"
+ action_meta_key="ctrl"
+
# shortcuts
- download_shortcut="alt-d" video_shortcut="alt-v" audio_shortcut="alt-m" detach_shortcut="alt-e" print_link_shortcut="alt-l" show_formats_shortcut="alt-f" info_shortcut="alt-i" search_again_shortcut="alt-s"
+ download_shortcut="${selection_meta_key}-d" video_shortcut="${selection_meta_key}-v" audio_shortcut="${selection_meta_key}-m" detach_shortcut="${selection_meta_key}-e" print_link_shortcut="${selection_meta_key}-l" show_formats_shortcut="${selection_meta_key}-f" info_shortcut="${selection_meta_key}-i" search_again_shortcut="${selection_meta_key}-s"
- next_page_action_shortcut="ctrl-p"
+ next_page_action_shortcut="${action_meta_key}-p"
# interface design
show_thumbnails="0" is_sort="0" skip_thumb_download="0" external_menu_len="210"
@@ -1413,7 +1420,7 @@ set_vars() {
instances_file="$cache_dir/instancesV2.json"
# read from environment to reset any variables to what the user set
-
+
if [ "$check_exists" -eq 1 ]; then
_current_var_name=
_current_var_value=
@@ -1430,9 +1437,14 @@ set_vars() {
_current_var_name="${_current_var_name%%=*}"
_current_var_value="${_var#*=}"
;;
- (*) _current_var_value="${_current_var_value}${new_line}${_var}" ;;
+ *) _current_var_value="${_current_var_value}${new_line}${_var}" ;;
esac
done <"$tmp_env"
+ [ "$_current_var_name" ] && {
+ export "${_current_var_name}"="$(eval echo "$_current_var_value")"
+ _current_var_name=""
+ _current_var_value=""
+ }
rm "$tmp_env"
fi
@@ -1446,7 +1458,7 @@ missing_deps=""
for dep in jq curl; do
command_exists "$dep" || missing_deps="${missing_deps}, ${dep}"
done
-[ "$missing_deps" ] && die 3 "You are missing the following required dependencies${missing_deps}, Please install them.${new_line}"
+[ "$missing_deps" ] && die 3 "You are missing the following required dependencies${missing_deps}, Please install them."
unset missing_deps
#}}}
@@ -1539,7 +1551,7 @@ set_real_channel_url_and_id() {
_id="$(_get_channel_id "$_input_url")"
[ "$_id" = "$_input_url" ] &&
_url="$(_get_real_channel_link "$_input_url")" && _id="$(_get_channel_id "$_url")"
- print_debug "[SCRAPE]: input url: $_input_url, detected url: $_url, detected id: $_id${new_line}"
+ print_debug "[SCRAPE]: input url: $_input_url, detected url: $_url, detected id: $_id"
channel_url="$_url" channel_id="$_id"
unset _url _id _input_url
}
@@ -1605,27 +1617,27 @@ _youtube_channel_json() {
}
#}}}
-scrape_yt () {
- search=$1
- [ "$search" = ":help" ] && print_info "Scrape youtube without invidious\n" && return 100
- output_json_file=$2
- _tmp_html="${session_temp_dir}/yt-search.html"
- _tmp_json="${session_temp_dir}/yt-search.json"
-
- printf "%s\n" "Scraping Youtube (with https://www.youtube.com) ($search)"
-
- _get_request "https://www.youtube.com/results" \
- -G --data-urlencode "search_query=$search" \
- -H "User-Agent: $4" \
- -H 'Accept-Language: en-US,en;q=0.9' \
- --compressed > "$_tmp_html" || exit "$?"
- sed -n '/var *ytInitialData/,$p' < "$_tmp_html" |
- tr -d '\n' |
- sed -E ' s_^.*var ytInitialData ?=__ ; s_;.*__ ;' > "$_tmp_json"
-
- #gets a list of videos
- {
- jq '[ .contents|
+scrape_yt() {
+ search=$1
+ [ "$search" = ":help" ] && print_info "Scrape youtube without invidious" && return 100
+ output_json_file=$2
+ _tmp_html="${session_temp_dir}/yt-search.html"
+ _tmp_json="${session_temp_dir}/yt-search.json"
+
+ printf "%s\n" "Scraping Youtube (with https://www.youtube.com) ($search)"
+
+ _get_request "https://www.youtube.com/results" \
+ -G --data-urlencode "search_query=$search" \
+ -H "User-Agent: $4" \
+ -H 'Accept-Language: en-US,en;q=0.9' \
+ --compressed >"$_tmp_html" || exit "$?"
+ sed -n '/var *ytInitialData/,$p' <"$_tmp_html" |
+ tr -d '\n' |
+ sed -E ' s_^.*var ytInitialData ?=__ ; s_;.*__ ;' >"$_tmp_json"
+
+ #gets a list of videos
+ {
+ jq '[ .contents|
..|.videoRenderer? |
select(. !=null) |
{
@@ -1642,7 +1654,7 @@ scrape_yt () {
}
]'
- jq '[ .contents|
+ jq '[ .contents|
..|.playlistRenderer? |
select(. !=null) |
{
@@ -1658,11 +1670,11 @@ scrape_yt () {
action: "scrape type=invidious-playlist search='"${yt_video_link_domain}"'/playlist?list=\(.playlistId)"
}
]'
- } < "$_tmp_json" >> "$output_json_file"
+ } <"$_tmp_json" >>"$output_json_file"
}
scrape_subscriptions() {
- ! [ -f "$YTFZF_SUBSCRIPTIONS_FILE" ] && die 2 "subscriptions file doesn't exist${new_line}"
+ ! [ -f "$YTFZF_SUBSCRIPTIONS_FILE" ] && die 2 "subscriptions file doesn't exist"
# if _tmp_subfile does not have a unique name, weird things happen
__subfile_line=-1
@@ -1676,16 +1688,16 @@ scrape_subscriptions() {
[ -z "$channel_url" ] && continue
__subfile_line=$((__subfile_line + 1))
{
- print_info "Scraping subscription: ${channel_url} (https://www.youtube.com)"
+ print_info "Scraping subscription: ${channel_url} (https://www.youtube.com)"
_tmp_subfile="${session_temp_dir}/channel-$__subfile_line"
- _tmp_html="${session_temp_dir}/${tmp_filename}${__subfile_line}.html"
- _tmp_json="${session_temp_dir}/${tmp_filename}${__subfile_line}.json"
- set_real_channel_url_and_id "$channel_url"
- _get_request "https://www.youtube.com/channel/${channel_id}/videos" > "$_tmp_html"
- _youtube_get_json <"$_tmp_html" > "$_tmp_json"
-
- channel_name=$(_youtube_channel_name <"$_tmp_html")
- _youtube_channel_json "$channel_name" "youtube_channel_$mod" <"$_tmp_json" >> "$_tmp_subfile"
+ _tmp_html="${session_temp_dir}/${tmp_filename}${__subfile_line}.html"
+ _tmp_json="${session_temp_dir}/${tmp_filename}${__subfile_line}.json"
+ set_real_channel_url_and_id "$channel_url"
+ _get_request "https://www.youtube.com/channel/${channel_id}/videos" >"$_tmp_html"
+ _youtube_get_json <"$_tmp_html" >"$_tmp_json"
+
+ channel_name=$(_youtube_channel_name <"$_tmp_html")
+ _youtube_channel_json "$channel_name" "youtube_channel_$mod" <"$_tmp_json" >>"$_tmp_subfile"
__new_data="$(jq '.[].scraper="subscriptions"' <"$_tmp_subfile")"
printf "%s\n" "$__new_data" >"$_tmp_subfile"
if [ ${fancy_subs} -eq 1 ]; then
@@ -1701,10 +1713,11 @@ scrape_subscriptions() {
}
scrape_youtube_subscriptions() { scrape_subscriptions "$@"; }
scrape_S() { scrape_subscriptions "$@"; }
+scrape_s() { scrape_subscriptions "$@"; }
scrape_SI() {
output_json_file="$2"
- _curl_config_file="${session_temp_dir}/curl_config"
+ _curl_config_file="${session_temp_dir}/curl_channels"
: >"$_curl_config_file"
while read -r url; do
@@ -1724,7 +1737,7 @@ scrape_SI() {
_tmp_json="${session_temp_dir}/SI.json"
- print_info "Scraping subscriptions with instance: $invidious_instance${new_line}"
+ print_info "Scraping subscriptions with instance: $invidious_instance"
curl -fLZ --parallel-max "${max_thread_count}" -K "$_curl_config_file"
[ $? -eq 2 ] && curl -fL -K "$_curl_config_file"
@@ -1750,9 +1763,11 @@ scrape_SI() {
set -f
}
+scrape_si() { scrape_SI "$@"; }
+
scrape_youtube_channel() {
channel_url="$1"
- [ "$channel_url" = ":help" ] && print_info "The search should be a link to a youtube channel${new_line}You can put one or more of the following modifiers followed by a space before the url to specify which type of videos to scrape:${new_line}:videos${new_line}:streams${new_line}:playlists${new_line}:v, :s, and :p may also be used as a shorter version${new_line}You may also use --type=live, --type=video, --type=playlist, or --type=all${new_line}" && return 100
+ [ "$channel_url" = ":help" ] && print_info "The search should be a link to a youtube channel${new_line}You can put one or more of the following modifiers followed by a space before the url to specify which type of videos to scrape:${new_line}:videos${new_line}:streams${new_line}:playlists${new_line}:v, :s, and :p may also be used as a shorter version${new_line}You may also use --type=live, --type=video, --type=playlist, or --type=all" && return 100
output_json_file="$2"
prepare_for_set_args
@@ -1801,7 +1816,7 @@ scrape_youtube_channel() {
set_real_channel_url_and_id "$channel_url"
for mod in $modifiers; do
- print_info "Scraping Youtube channel: https://www.youtube.com/channel/${channel_id}/$mod${new_line}"
+ print_info "Scraping Youtube channel: https://www.youtube.com/channel/${channel_id}/$mod"
tmp_filename="channel-${channel_id}-$mod"
_tmp_html="${session_temp_dir}/${tmp_filename}.html"
_tmp_json="${session_temp_dir}/${tmp_filename}.json"
@@ -1957,7 +1972,7 @@ _concatinate_json_file() {
scrape_invidious_playlist() {
playlist_url=$1
- [ "$playlist_url" = ":help" ] && print_info "The search should be a link to a youtube playlist${new_line}" && return 100
+ [ "$playlist_url" = ":help" ] && print_info "The search should be a link to a youtube playlist" && return 100
output_json_file=$2
playlist_id="${playlist_url##*[?]list=}"
@@ -1975,7 +1990,7 @@ scrape_invidious_playlist() {
_get_request "$invidious_instance/api/v1/playlists/$playlist_id" \
-G --data-urlencode "page=$_cur_page" >"$_tmp_json" || return "$?"
jq -e '.videos==[]' <"$_tmp_json" >/dev/null 2>&1 && break
- print_info "Scraping Youtube playlist (with $invidious_instance) (playlist: $playlist_url, pg: $_cur_page)${new_line}"
+ print_info "Scraping Youtube playlist (with $invidious_instance) (playlist: $playlist_url, pg: $_cur_page)"
_invidious_playlist_json <"$_tmp_json" >>"$output_json_file"
_cur_page=$((_cur_page + 1))
@@ -1985,7 +2000,7 @@ scrape_youtube_playlist() { scrape_invidious_playlist "$@"; }
scrape_invidious_search() {
page_query=$1
- [ "$page_query" = ":help" ] && print_info "Make a youtube search${new_line}" && return 100
+ [ "$page_query" = ":help" ] && print_info "Make a youtube search" && return 100
output_json_file=$2
_ivs_cur_page=${pages_start:-1}
@@ -2003,7 +2018,7 @@ scrape_invidious_search() {
{
_tmp_json="${session_temp_dir}/yt-search-$_ivs_cur_page.json"
- print_info "Scraping YouTube (with $invidious_instance) ($page_query, pg: $_ivs_cur_page)${new_line}"
+ print_info "Scraping YouTube (with $invidious_instance) ($page_query, pg: $_ivs_cur_page)"
_get_request "$invidious_instance/api/v1/search" \
-G --data-urlencode "q=$page_query" \
@@ -2047,7 +2062,7 @@ scrape_next_page_invidious_search() {
scrape_invidious_video_recommended() {
video="$1"
- [ "$video" = ":help" ] && print_info "The search should be a link to a youtube video${new_line}" && return 100
+ [ "$video" = ":help" ] && print_info "The search should be a link to a youtube video" && return 100
output_json_file="$2"
case "$video" in
*/*) video="${video##*=}" ;;
@@ -2062,9 +2077,9 @@ scrape_R() { scrape_invidious_video_recommended "$@"; }
scrape_invidious_trending() {
trending_tab=$(title_str "$1")
- [ "$trending_tab" = ":help" ] && print_info "The search should be one of: Normal, Gaming, Music, News${new_line}" && return 100
+ [ "$trending_tab" = ":help" ] && print_info "The search should be one of: Normal, Gaming, Music, News" && return 100
output_json_file=$2
- print_info "Scraping YouTube (with $invidious_instance) trending (${trending_tab:-Normal})${new_line}"
+ print_info "Scraping YouTube (with $invidious_instance) trending (${trending_tab:-Normal})"
_tmp_json="${session_temp_dir}/yt-trending"
@@ -2083,14 +2098,14 @@ scrape_T() { scrape_invidious_trending "$@"; }
scrape_invidious_channel() {
channel_url=$1
- [ "$channel_url" = ":help" ] && print_info "The search should be a link to a youtube channel${new_line}You can put one or more of the following modifiers followed by a space before the url to specify which type of videos to scrape:${new_line}:videos${new_line}:streams${new_line}:playlists${new_line}:v, :s, and :p may also be used as a shorter version${new_line}You may also use --type=live, --type=video, --type=playlist, or --type=all${new_line}" && return 100
+ [ "$channel_url" = ":help" ] && print_info "The search should be a link to a youtube channel${new_line}You can put one or more of the following modifiers followed by a space before the url to specify which type of videos to scrape:${new_line}:videos${new_line}:streams${new_line}:playlists${new_line}:v, :s, and :p may also be used as a shorter version${new_line}You may also use --type=live, --type=video, --type=playlist, or --type=all" && return 100
output_json_file=$2
tmp_file_name="channel-${channel_id}"
_tmp_html="${session_temp_dir}/${tmp_file_name}.html"
_tmp_json="${session_temp_dir}/${tmp_file_name}.json"
- [ -n "$pages_to_scrape" ] || [ -n "$pages_start" ] && print_warning "If you want to use --pages or --pages-start${new_line}use -c invidious-playlist where the search is https://www.youtube.com/playlist?list=$channel_id${new_line}"
+ [ -n "$pages_to_scrape" ] || [ -n "$pages_start" ] && print_warning "If you want to use --pages or --pages-start${new_line}use -c invidious-playlist where the search is https://www.youtube.com/playlist?list=$channel_id"
prepare_for_set_args
set -- $1
@@ -2140,27 +2155,27 @@ scrape_invidious_channel() {
for modifier in $modifiers; do
channel_url="$invidious_instance/api/v1/channels/$channel_id/$modifier"
- print_info "Scraping Youtube (with $invidious_instance) channel: $channel_url${new_line}"
+ print_info "Scraping Youtube (with $invidious_instance) channel: $channel_url"
case "$modifier" in
- streams)
- __jq_filter='.streams? // []'
- __jq_parser=_invidious_search_json_live
- ;;
- playlists)
- __jq_filter='.playlists? // []'
- __jq_parser=_invidious_search_json_playlist
- ;;
- videos|*)
- __jq_filter='(.videos? // []) + (.latestVideos? // [])'
- __jq_parser=_invidious_search_json_generic
- ;;
+ streams)
+ __jq_filter='.streams? // []'
+ __jq_parser=_invidious_search_json_live
+ ;;
+ playlists)
+ __jq_filter='.playlists? // []'
+ __jq_parser=_invidious_search_json_playlist
+ ;;
+ videos | *)
+ __jq_filter='(.videos? // []) + (.latestVideos? // [])'
+ __jq_parser=_invidious_search_json_generic
+ ;;
esac
_get_invidious_thumb_quality_name
_get_request "${channel_url##* }" \
- -G --data-urlencode "page=$_cur_page" |
+ -G --data-urlencode "page=$_cur_page" |
jq "$__jq_filter" | $__jq_parser "invidious_channel" |
jq 'select(.!=[])' >>"$output_json_file" || return "$?"
done
@@ -2188,7 +2203,7 @@ Eg:
invidious_instance="$PARENT_invidious_instance"
cache_dir="$session_cache_dir"
on_opt_parse_s() {
- print_warning "-s is not supported in multi search${new_line}"
+ print_warning "-s is not supported in multi search"
}
_getopts "$@"
source_scrapers
@@ -2212,9 +2227,9 @@ scrape_M() { scrape_multi "$@"; }
## Peertube {{{
scrape_peertube() {
page_query=$1
- [ "$page_query" = ":help" ] && print_info "Search peertube${new_line}" && return 100
+ [ "$page_query" = ":help" ] && print_info "Search peertube" && return 100
output_json_file=$2
- print_info "Scraping Peertube ($page_query)${new_line}"
+ print_info "Scraping Peertube ($page_query)"
_tmp_json="${session_temp_dir}/peertube.json"
@@ -2248,14 +2263,14 @@ scrape_P() { scrape_peertube "$@"; }
scrape_odysee() {
[ "$odysee_video_search_count" -gt 50 ] && die 1 "--odysee-video-count must be <= 50"
page_query=$1
- [ "$page_query" = ":help" ] && print_info "Search odysee${new_line}" && return 100
- [ "${#page_query}" -le 2 ] && die 4 "Odysee searches must be 3 or more characters${new_line}"
+ [ "$page_query" = ":help" ] && print_info "Search odysee" && return 100
+ [ "${#page_query}" -le 2 ] && die 4 "Odysee searches must be 3 or more characters"
output_json_file=$2
# for scrape_next_page_odysee_search
[ -z "$_initial_odysee_video_search_count" ] && _initial_odysee_video_search_count=$odysee_video_search_count
- print_info "Scraping Odysee ($page_query)${new_line}"
+ print_info "Scraping Odysee ($page_query)"
_tmp_json="${session_temp_dir}/odysee.json"
@@ -2320,36 +2335,38 @@ scrape_O() { scrape_odysee "$@"; }
# ytfzf json format{{{
-scrape_from_cache () {
- search="$1"
- [ "$search" = ":help" ] && print_info "Scrapes from a cached ytfzf search${new_line}the search is the cache # to use, where 1 is the most recent and \$ is the least recent" && return 100
- on_clean_up_scrape_from_cache () {
- rm -r "${cache_dir}/${SEARCH_PREFIX}-${YTFZF_PID}" > /dev/null 2>&1
- }
- load_fake_extension "scrape_from_cache"
-
- set +f
- _locations=$(
- for location in "$cache_dir"/*-[0-9][0-9]*; do
- printf "%s\n" "$(cat "${location}/created-at")-${location}"
- done | sort -nr | cut -d '-' -f2-
- )
-
- if [ -n "$search" ]; then
- _location="$(sed -n "${search}p" </dev/null 2>&1
+ }
+ load_fake_extension "scrape_from_cache"
+
+ set +f
+ _locations=$(
+ for location in "$cache_dir"/*-[0-9][0-9]*; do
+ printf "%s\n" "$(cat "${location}/created-at")-${location}"
+ done | sort -nr | cut -d '-' -f2-
+ )
+
+ if [ -n "$search" ]; then
+ _location="$(
+ sed -n "${search}p" <"$_comment_file"
@@ -2534,7 +2551,7 @@ handle_post_keypress() {
handle_keypress() {
read -r keypress <"$1"
- print_debug "[KEYPRESS]: handling keypress: $keypress${new_line}"
+ print_debug "[KEYPRESS]: handling keypress: $keypress"
command_exists "handle_custom_keypresses" && { handle_custom_keypresses "$keypress" || return "$?"; }
case "$keypress" in
@@ -2606,7 +2623,7 @@ auto_select() {
# Text interface {{{
interface_text() {
- command_exists "fzf" || die 3 "fzf not installed, cannot use the default menu${new_line}"
+ command_exists "fzf" || die 3 "fzf not installed, cannot use the default menu"
# if it doesn't exist, this menu has not opened yet, no need to revert the actions of the last keypress
[ -f "$keypress_file" ] && handle_post_keypress
@@ -2617,6 +2634,8 @@ interface_text() {
_fzf_start_bind="${_fzf_start_bind%"+"}"
fi
+ _init_video_info_text "$TTY_COLS"
+
[ "$show_thumbnails" -eq 1 ] && {
interface_thumbnails "$@"
return
@@ -2625,8 +2644,6 @@ interface_text() {
video_json_file=$1
selected_id_file=$2
- _init_video_info_text "$TTY_COLS"
-
unset IFS
_c_SORTED_VIDEO_DATA="$(create_sorted_video_data)"
@@ -2677,16 +2694,16 @@ preview_start() {
case $thumbnail_viewer in
ueberzug | sixel | kitty | iterm2 | sway | wayland)
command_exists "ueberzug" || {
- [ "$thumbnail_viewer" = "ueberzug" ] && die 3 "ueberzug is not installed${new_line}" || die 3 "ueberzugpp is not installed${new_line}"
+ [ "$thumbnail_viewer" = "ueberzug" ] && die 3 "ueberzug is not installed" || die 3 "ueberzugpp is not installed"
}
export UEBERZUG_FIFO="$session_temp_dir/ytfzf-ueberzug-fifo"
rm -f "$UEBERZUG_FIFO"
mkfifo "$UEBERZUG_FIFO"
- if [ "$thumbnail_viewer" = "ueberzug" ]; then
- o="x11"
- else
- o="${thumbnail_viewer}"
- fi
+ if [ "$thumbnail_viewer" = "ueberzug" ]; then
+ o="x11"
+ else
+ o="${thumbnail_viewer}"
+ fi
if command_exists ueberzugpp; then
ueberzugpp layer -o "${o}" --parser json <"$UEBERZUG_FIFO" 2>>"$thumbnail_debug_log" &
else
@@ -2733,7 +2750,8 @@ preview_stop() {
}
command_exists "on_no_thumbnail" || on_no_thumbnail() {
- die 1 "No image${new_line}"
+ [ "${__did_on_no_thumbnail:-0}" -eq 1 ] || print_error "No image"
+ __did_on_no_thumbnail=1
}
preview_no_img() {
@@ -2864,6 +2882,14 @@ preview_display_image() {
get_ueberzug_positioning "$FZF_PREVIEW_COLUMNS" "$FZF_PREVIEW_LINES" "$fzf_preview_side"
case $thumbnail_viewer in
ueberzug | sixel | kitty | iterm2 | sway | wayland)
+ #not exactly sure why this is necessary
+ [ "$thumbnail_viewer" = "kitty" ] && width=$((width - 11))
+ {
+ printf "{"
+ printf "\"%s\": \"%s\"," "action" "remove" "identifier" "ytfzf"
+ printf '"%s": "%s"' "draw" "True"
+ printf "}\n"
+ } >"$UEBERZUG_FIFO" 2>>"$thumbnail_debug_log"
{
printf "{"
printf '"%s": "%s",' \
@@ -2878,7 +2904,7 @@ preview_display_image() {
} >"$UEBERZUG_FIFO" 2>>"$thumbnail_debug_log"
;;
swayimg-hyprland)
- command_exists "hyprctl" || die 3 "hyprctl is required for this thumbnail viewer${new_line}"
+ command_exists "hyprctl" || die 3 "hyprctl is required for this thumbnail viewer"
_swayimg_pid_file="${session_temp_dir}/_swayimg.pid"
[ -f "$_swayimg_pid_file" ] && kill "$(cat "$_swayimg_pid_file")" 2>/dev/null
@@ -2941,27 +2967,27 @@ preview_display_image() {
;;
chafa)
printf '\n'
- command_exists "chafa" || die 3 "${new_line}chafa is not installed${new_line}"
+ command_exists "chafa" || die 3 "${new_line}chafa is not installed"
chafa --format=symbols -s "$((width - 4))x$height" "$thumb_path" 2>>"$thumbnail_debug_log"
;;
chafa-16)
printf '\n'
- command_exists "chafa" || die 3 "${new_line}chafa is not installed${new_line}"
+ command_exists "chafa" || die 3 "${new_line}chafa is not installed"
chafa --format=symbols -c 240 -s "$((width - 2))x$((height - 10))" "$thumb_path" 2>>"$thumbnail_debug_log"
;;
chafa-tty)
printf '\n'
- command_exists "chafa" || die 3 "${new_line}chafa is not installed${new_line}"
- chafa --format=symbols -c 16 -s "$((width - 2))x$((height - 10))" "$thumb_path" 2>>"$thumbnail_debug_log"
+ command_exists "chafa" || die 3 "${new_line}chafa is not installed"
+ chafa --format=symbols -c 16 -s "$((width - 2))x$((height - 10))" "$thumb_path" 2>>"$thumbnail_debug_log"
;;
catimg)
printf '\n'
- command_exists "catimg" || die 3 "${new_line}catimg is not installed${new_line}"
+ command_exists "catimg" || die 3 "${new_line}catimg is not installed"
catimg -w "$width" "$thumb_path" 2>>"$thumbnail_debug_log"
;;
catimg-256)
printf '\n'
- command_exists "catimg" || die 3 "${new_line}catimg is not installed${new_line}"
+ command_exists "catimg" || die 3 "${new_line}catimg is not installed"
catimg -c -w "$width" "$thumb_path" 2>>"$thumbnail_debug_log"
;;
imv)
@@ -3035,12 +3061,14 @@ interface_thumbnails() {
printf "%s\n" "$_c_SORTED_VIDEO_DATA" |
jq -r '"\(.title)'"$gap_space"'\t|\(.channel)\t|\(.duration)\t|\(.views)\t|\(.date)\t|\(.viewed)\t|\(.url)"' |
- SHELL="$(command -v sh)" fzf -m --sync \
+ _post_video_info_text |
+ fzf -m --sync \
--expect="$shortcut_binds" \
--preview "__is_fzf_preview=1 YTFZF_CHECK_VARS_EXISTS=1 session_cache_dir='$session_cache_dir' session_temp_dir='$session_temp_dir' fzf_preview_side='$fzf_preview_side' scrape='$scrape' thumbnail_viewer='$thumbnail_viewer' ytfzf_video_json_file='$ytfzf_video_json_file' $0 -W \"preview_img"$EOT"{f}\"" \
$_fzf_start_bind \
--bind "${next_page_action_shortcut}:reload(__is_fzf_preview=1 TTY_COLS=${TTY_COLS} TTY_LINES=${TTY_LINES} YTFZF_CHECK_VARS_EXISTS=1 session_cache_dir='$session_cache_dir' ytfzf_video_json_file='$ytfzf_video_json_file' invidious_instance='$invidious_instance' yt_video_link_domain='$yt_video_link_domain' pages_to_scrape='$pages_to_scrape' session_temp_dir='$session_temp_dir' $0 -W \"next_page"$EOT"{f}\")" \
- --preview-window "$fzf_preview_side:50%:wrap" --layout=reverse | set_keypress |
+ --preview-window "$fzf_preview_side:$preview_window_width:wrap" --layout=reverse |
+ set_keypress |
trim_url >"$selected_id_file"
preview_stop "$thumbnail_viewer"
@@ -3090,12 +3118,12 @@ handle_info() {
[ "$info_wait" -eq 1 ] && info_wait_prompt_wrapper
case "$info_wait_action" in
- # simulates old behavior of when alt-l or alt-i is pressed and -l is enabled
- q) [ "$is_loop" -eq 1 ] && return 3 || return 2 ;;
- Q) return 2 ;;
- [MmCc]) return 3 ;;
- '') return 0 ;;
- *) if command_exists "custom_info_wait_action_$info_wait_action"; then custom_info_wait_action_"$info_wait_action"; else print_error "info_wait_action is set to $info_wait_action but custom_info_wait_action_$info_wait_action does not exist${new_line}"; fi ;;
+ # simulates old behavior of when alt-l or alt-i is pressed and -l is enabled
+ q) [ "$is_loop" -eq 1 ] && return 3 || return 2 ;;
+ Q) return 2 ;;
+ [MmCc]) return 3 ;;
+ '') return 0 ;;
+ *) if command_exists "custom_info_wait_action_$info_wait_action"; then custom_info_wait_action_"$info_wait_action"; else print_error "info_wait_action is set to $info_wait_action but custom_info_wait_action_$info_wait_action does not exist"; fi ;;
esac
return 0
@@ -3137,7 +3165,7 @@ submenu_handler() {
end_of_set_args
on_opt_parse_s() {
- print_warning "-s is not supported in submenus${new_line}"
+ print_warning "-s is not supported in submenus"
}
_getopts "$@"
@@ -3171,7 +3199,7 @@ close_url_handler_submenu_handler() {
close_url_handler() {
fn_name="$(printf "%s" "$1" | tr '-' '_')"
command_exists "close_url_handler_$fn_name" && close_url_handler_"$fn_name"
- print_debug "[URL HANDLER]: Closing url handler: ${c_blue}${1}${c_reset} with function: ${c_bold}close_url_handler_${fn_name}${c_reset}${new_line}"
+ print_debug "[URL HANDLER]: Closing url handler: ${c_blue}${1}${c_reset} with function: ${c_bold}close_url_handler_${fn_name}${c_reset}"
do_an_event_function "after_close_url_handler" "$1"
}
@@ -3182,12 +3210,12 @@ open_url_handler() {
prepare_for_set_args ' '
# shellcheck disable=SC2086
set -- $urls
- [ -z "$*" ] && print_info "No urls selected${new_line}" && return 0
+ [ -z "$*" ] && print_info "No urls selected" && return 0
end_of_set_args
do_an_event_function "on_open_url_handler" "$@"
- print_debug "[URL HANDLER]: Opening links: ${c_bold}${urls}${c_reset} with ${c_blue}${url_handler}${c_reset}${new_line}"
+ print_debug "[URL HANDLER]: Opening links: ${c_bold}${urls}${c_reset} with ${c_blue}${url_handler}${c_reset}"
# if we provide video_pref etc as arguments, we wouldn't be able to add more as it would break every url handler function
# shellcheck disable=2031
@@ -3214,14 +3242,14 @@ get_video_format_simple() {
}
get_video_format() {
- case "${ytdl_path##*/}" in
- (youtube-dl) _format_options=$("${ytdl_path}" -F "$1" | sed 1,3d) ;;
- (*) _format_options=$("${ytdl_path}" -q -F "$1" --format-sort "$format_selection_sort" | sed 1,3d) ;;
- esac
- _audio_choices="$(echo "$_format_options" | grep "audio only")"
+ case "${ytdl_path##*/}" in
+ youtube-dl) _format_options=$("${ytdl_path}" -F "$1" | sed 1,3d) ;;
+ *) _format_options=$("${ytdl_path}" -q -F "$1" --format-sort "$format_selection_sort" | sed 1,3d) ;;
+ esac
+ _audio_choices="$(echo "$_format_options" | grep "audio only")"
[ "$_audio_choices" ] && audio_pref="$(echo "$_audio_choices" | quick_menu_wrapper "Audio format: " | awk '{print $1}')"
if [ "$is_audio_only" -eq 0 ]; then
- video_pref=$(echo "$_format_options" | sed 's/\\033\[[[:digit:]]*m//g' | grep -v 'audio only' | quick_menu_wrapper "Video Format: " | awk '{print $1}')
+ video_pref=$(echo "$_format_options" | sed 's/\\033\[[[:digit:]]*m//g' | grep -v 'audio only' | quick_menu_wrapper "Video Format: " | awk '{print $1}')
fi
ytdl_pref="${video_pref}+${audio_pref}/${video_pref}/${audio_pref}"
}
@@ -3234,7 +3262,7 @@ open_format_selection_if_requested() {
set -- $(tr '\n' ' ' <"$1")
end_of_set_args
- print_debug "[INTERFACE]: [FORMAT SELECTION]: open format screen: ${c_blue}${format_selection_screen}${c_reset}${new_line}"
+ print_debug "[INTERFACE]: [FORMAT SELECTION]: open format screen: ${c_blue}${format_selection_screen}${c_reset}"
case "$format_selection_screen" in
normal)
get_video_format "$1"
@@ -3274,6 +3302,8 @@ internal_action_next_page() {
video_json_file="$ytfzf_video_json_file"
+ thumb_dir="${session_cache_dir}/thumbnails"
+
hovered_scraper="$(jq -r '.[]|select(.url=="'"$url"'").scraper' <"$ytfzf_video_json_file")"
if command_exists "scrape_next_page_$hovered_scraper"; then
@@ -3286,6 +3316,15 @@ internal_action_next_page() {
scrape_next_page_"$hovered_scraper"
fi
+ if [ "$show_thumbnails" -eq 1 ]; then
+ prepare_for_set_args
+ case "$async_thumbnails" in
+ 0) download_thumbnails $(get_missing_thumbnails) ;;
+ 1) download_thumbnails $(get_missing_thumbnails) >/dev/null 2>&1 & ;;
+ esac
+ end_of_set_args
+ fi
+
_init_video_info_text "$TTY_COLS"
create_sorted_video_data |
@@ -3315,7 +3354,7 @@ parse_opt() {
# for some reason optarg may equal opt intentionally,
# this checks the unmodified optarg, which will only be equal if there is no = sign
[ "$opt" = "$OPTARG" ] && optarg=""
- print_debug "[OPTIONS]: Parsing opt: $opt=$optarg${new_line}"
+ print_debug "[OPTIONS]: Parsing opt: $opt=$optarg"
# shellcheck disable=SC2031
command_exists "on_opt_parse" && { on_opt_parse "$opt" "$optarg" "$OPT" "$OPTARG" || return 0; }
fn_name="on_opt_parse_$(printf "%s" "$opt" | tr '-' '_')"
@@ -3330,10 +3369,10 @@ parse_opt() {
m | audio-only) is_audio_only=${optarg:-1} ;;
d | download) url_handler=downloader ;;
f | formats) show_formats=${optarg:-1} ;;
- S | select) interface="scripting" && is_specific_select="1" && scripting_video_count="$optarg";;
- a | auto-select) [ -z "$optarg" ] || [ "$optarg" -eq 1 ] && is_auto_select=${optarg:-1};;
- A | select-all) [ -z "$optarg" ] || [ "$optarg" -eq 1 ] && is_auto_select=${optarg:-1} && scripting_video_count='$';;
- r | random-select) [ -z "$optarg" ] || [ "$optarg" -eq 1 ] && is_random_select=${optarg:-1};;
+ S | select) interface="scripting" && is_specific_select="1" && scripting_video_count="$optarg" ;;
+ a | auto-select) [ -z "$optarg" ] || [ "$optarg" -eq 1 ] && is_auto_select=${optarg:-1} ;;
+ A | select-all) [ -z "$optarg" ] || [ "$optarg" -eq 1 ] && is_auto_select=${optarg:-1} && scripting_video_count='$' ;;
+ r | random-select) [ -z "$optarg" ] || [ "$optarg" -eq 1 ] && is_random_select=${optarg:-1} ;;
n | link-count) scripting_video_count=$optarg ;;
l | loop) is_loop=${optarg:-1} ;;
s | search-again) search_again=${optarg:-1} ;;
@@ -3353,7 +3392,7 @@ parse_opt() {
odysee-video-count) odysee_video_search_count="$optarg" ;;
ii | inv-instance) invidious_instance="$optarg" ;;
rii | refresh-inv-instances) refresh_inv_instances ;;
- i | interface) load_interface "$optarg" || die 2 "$optarg is not an interface${new_line}" ;;
+ i | interface) load_interface "$optarg" || die 2 "$optarg is not an interface" ;;
c | scrape) scrape=$optarg ;;
scrape+) scrape="$scrape,$optarg" ;;
scrape-) scrape="$(printf '%s' "$scrape" | sed 's/'"$optarg"'//; s/,,/,/g')" ;;
@@ -3364,14 +3403,14 @@ parse_opt() {
: "${optarg:=1}"
if [ "$optarg" != 1 ] && [ "$optarg" != 0 ]; then
is_sort="1"
- load_sort_name "$optarg" || die 2 "$optarg is not a sort-name${new_line}"
+ load_sort_name "$optarg" || die 2 "$optarg is not a sort-name"
else
is_sort=${optarg}
fi
;;
sort-name)
# shellcheck disable=SC2015
- load_sort_name "$optarg" && is_sort=1 || die 2 "$optarg is not a sort-name${new_line}"
+ load_sort_name "$optarg" && is_sort=1 || die 2 "$optarg is not a sort-name"
;;
video-pref) video_pref=$optarg ;;
ytdl-pref) ytdl_pref=$optarg ;;
@@ -3381,11 +3420,15 @@ parse_opt() {
ytdl-path) ytdl_path="$optarg" ;;
preview-side)
fzf_preview_side="${optarg}"
- [ -z "$fzf_preview_side" ] && die 2 "no preview side given${new_line}"
+ [ -z "$fzf_preview_side" ] && die 2 "no preview side given"
+ case "$fzf_preview_side" in
+ left | right | up | down) : ;;
+ *) die 2 "$fzf_preview_side is not a valid preview side, must be one of: left, right, up, down" ;;
+ esac
;;
- T | thumb-viewer) load_thumbnail_viewer "$optarg" || [ -f "$thumbnail_viewer" ] || die 2 "$optarg is not a thumb-viewer${new_line}" ;;
+ T | thumb-viewer) load_thumbnail_viewer "$optarg" || [ -f "$thumbnail_viewer" ] || die 2 "$optarg is not a thumb-viewer" ;;
force-youtube) yt_video_link_domain="https://www.youtube.com" ;;
- force-invidious) yt_video_link_domain="" ;;
+ force-invidious) yt_video_link_domain="" ;;
info-print-exit | info-exit) [ "${optarg:-1}" -eq 1 ] && info_wait_action=q ;;
info-action) info_wait_action="$optarg" ;;
info-wait) info_wait="${optarg:-1}" ;;
@@ -3457,16 +3500,16 @@ parse_opt() {
;;
*)
# shellcheck disable=SC2031
- [ "$OPT" = "$long_opt_char" ] && print_info "$0: illegal long option -- $opt${new_line}"
+ [ "$OPT" = "$long_opt_char" ] && print_info "$0: illegal long option -- $opt"
;;
esac
}
_getopts() {
case "$long_opt_char" in
- [a-uw-zA-UW-Z0-9]) die 2 "long_opt_char must be v or non alphanumeric${new_line}" ;;
+ [a-uw-zA-UW-Z0-9]) die 2 "long_opt_char must be v or non alphanumeric" ;;
#? = 1 char, * = 1+ chars; ?* = 2+ chars
- ??*) die 2 "long_opt_char must be 1 char${new_line}" ;;
+ ??*) die 2 "long_opt_char must be 1 char" ;;
esac
OPTIND=0
@@ -3511,10 +3554,10 @@ init_files() {
SEARCH_PREFIX="${SEARCH_PREFIX:-SCRAPE-$scrape}"
[ "${#SEARCH_PREFIX}" -gt 200 ] && SEARCH_PREFIX="SCRAPE-$scrape"
- #if we are in a submenu, cache_dir will be the previous session_cache_dir
+ #if we are in a submenu, cache_dir will be the previous session_cache_dir
- [ "$__is_submenu" -eq 1 ] && _session_cache_dir_prefix="${cache_dir}" || _session_cache_dir_prefix="${YTFZF_TEMP_DIR}"
- session_cache_dir="${_session_cache_dir_prefix}/${SEARCH_PREFIX}-${YTFZF_PID}"
+ [ "$__is_submenu" -eq 1 ] && _session_cache_dir_prefix="${cache_dir}" || _session_cache_dir_prefix="${YTFZF_TEMP_DIR}"
+ session_cache_dir="${_session_cache_dir_prefix}/${SEARCH_PREFIX}-${YTFZF_PID}"
session_temp_dir="${session_cache_dir}/tmp"
@@ -3531,9 +3574,9 @@ init_files() {
[ "$1" ] && printf "%s\n" "$1" >"${session_cache_dir}/searches.list"
- awk 'BEGIN{print srand(srand())}' > "${session_cache_dir}/created-at"
+ awk 'BEGIN{print srand(srand())}' >"${session_cache_dir}/created-at"
- unset _session_cache_dir_prefix
+ unset _session_cache_dir_prefix
}
# }}}
@@ -3558,7 +3601,7 @@ handle_actions() {
[ "$enable_actions" -eq 0 ] && return 0
actions=$(jq -r --arg urls "$(cat "$1")" '.[] | [.url, .action] as $data | if ( ($urls | split("\n" )) | index($data[0]) and $data[1] != null ) == true then $data[1] else "" end' <"$ytfzf_video_json_file" | sed '/^[[:space:]]*$/d')
while read -r action; do
- print_debug "[ACTION]: handling action: $action${new_line}"
+ print_debug "[ACTION]: handling action: $action"
# this wil only be empty after all urls with actions have happened
# shellcheck disable=SC2031
@@ -3604,22 +3647,22 @@ set_scrape_count() {
handle_scrape_error() {
_scr="$2"
case "$1" in
- 1) print_info "$_scr failed to load website${new_line}" ;;
- 6) print_error "Website ($_scr) unresponsive (do you have internet?)${new_line}" ;;
- 9) print_info "$_scr does not have a configuration file${new_line}" ;;
+ 1) print_info "$_scr failed to load website" ;;
+ 6) print_error "Website ($_scr) unresponsive (do you have internet?)" ;;
+ 9) print_info "$_scr does not have a configuration file" ;;
22)
case "$_scr" in
youtube | Y | youtube-trending | T)
- print_error "There was an error scraping $_scr ($invidious_instance)${new_line}Try changing invidious instances${new_line}"
+ print_error "There was an error scraping $_scr ($invidious_instance)${new_line}Try changing invidious instances"
;;
- *) print_error "There was an error scraping $_scr${new_line}" ;;
+ *) print_error "There was an error scraping $_scr" ;;
esac
;;
- #:help search operator
- 100) print_info "---------${new_line}" && return 100 ;;
- 126) print_info "$_scr does not have execute permissions${new_line}" ;;
- 127) die 2 "invalid scraper: $_scr${new_line}" ;;
- *) print_error "An error occured while scraping: $_scr (scraper returned error: $1)${new_line}" ;;
+ #:help search operator
+ 100) print_info "---------" && return 100 ;;
+ 126) print_info "$_scr does not have execute permissions" ;;
+ 127) die 2 "invalid scraper: $_scr" ;;
+ *) print_error "An error occured while scraping: $_scr (scraper returned error: $1)" ;;
esac
}
@@ -3647,7 +3690,7 @@ handle_scraping() {
something_was_scraped() {
#this MUST be `! grep -q -v -e '\[\]` because it's possible that [] exists in the file IN ADDITION to a list of actual results, we want to see if those actual results exists.
if ! [ -s "${ytfzf_video_json_file}" ] || ! grep -q -v -e '\[\]' "$ytfzf_video_json_file"; then
- print_error "Nothing was scraped${new_line}"
+ print_error "Nothing was scraped"
return 1
fi
return 0
@@ -3667,10 +3710,10 @@ init_search() {
_search="$1"
_search_source="$2"
- print_debug "[SEARCH]: initializing search with search: $_search, and sources: $_search_source${new_line}"
+ print_debug "[SEARCH]: initializing search with search: $_search, and sources: $_search_source"
# only ask for search if scrape isn't something like S or T
- is_asking_for_search_necessary && { get_search_from_source "$_search_source" "$_search" || die 5 "No search query${new_line}"; }
+ is_asking_for_search_necessary && { get_search_from_source "$_search_source" "$_search" || die 5 "No search query"; }
init_files "$_search"
set_scrape_count
@@ -3741,5 +3784,4 @@ while [ "$search_again" -eq 1 ]; do
main
done
#}}}
-
# vim: foldmethod=marker:shiftwidth=4:tabstop=4