scripts/qb

457 lines
13 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
# Vars {{{
readonly PROGNAME=$(basename "${0}")
readonly NBARGS="${#}"
## Test if DEBUG is already defined (by parent script,…)
[ -z "${DEBUG}" ] && DEBUG=1
## Colors
readonly PURPLE='\033[1;35m'
readonly RED='\033[0;31m'
readonly RESET='\033[0m'
readonly COLOR_DEBUG="${PURPLE}"
# }}}
usage() { # {{{
cat <<- EOF
usage: $PROGNAME [--debug,--help]
Try to open Qutebrowser content (bookmarks, buffers,…).
EXAMPLES:
- Display content if Qutebrowser is already opened
${PROGNAME}
OPTIONS:
-d,--debug
Enable debug messages.
-h,--help
Print this help message.
EOF
}
# }}}
define_vars() { # {{{
## Test if BROWSER is already defined (by parent script,…)
[ -z "${BROWSER}" ] && BROWSER="qutebrowser"
## List of process pattern to monitor
qutebrowser_proc_pattern="(qutebrowser)"
## Use Qutebrowser from Python Virtual Environment by default
QB_VENV_MODE="0"
## Qutebrowser possibles paths
QB_VENV_PYTHON_PATH="${HOME}/src/qutebrowser-venv/bin/python3"
QB_GIT_REPOSITORY="${HOME}/repos/qutebrowser"
## Store selected content to a temp file
choice_temp_file="$(mktemp -t ${PROGNAME}-XXXXXX.tmp)"
## Variables to get Qutebrowser currents buffers
QUTEBROWSER_SESSION_FILE="/tmp/qutebrowser_buffers_zsbd"
QUTEBROWSER_SOCKET_FILE="${XDG_RUNTIME_DIR}/qutebrowser/ipc-$(echo -n "$USER" | md5sum | cut -d' ' -f1)"
QUTEBROWSER_GLOBAL_CONTENT="/tmp/qutebrowser_global_content"
rm -f -- "${QUTEBROWSER_GLOBAL_CONTENT}" ; touch "${QUTEBROWSER_GLOBAL_CONTENT}"
## Variables to get Qutebrowser *marks from current user
QUTEBROWSER_QUICKMARK_FILE="${HOME}/.config/qutebrowser/quickmarks"
QUTEBROWSER_BOOKMARK_FILE="${HOME}/.config/qutebrowser/bookmarks/urls"
## Qutebrowser search engines from current user configuration
QUTEBROWSER_SEARCHENGINE_FILE="${HOME}/.config/qutebrowser/config.py"
QUTEBROWSER_SEARCHENGINE_LIST="/tmp/qutebrowser_searchengine.list"
rm -f -- "${QUTEBROWSER_SEARCHENGINE_LIST}" ; touch "${QUTEBROWSER_SEARCHENGINE_LIST}"
## Default window pattern to search
QUTEBROWSER_WINDOW_TITLE="qutebrowser"
}
# }}}
debug_message() { # {{{
local_debug_message="${1}"
## Print message if DEBUG is enable (=0)
[ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6b\e[m\n' "DEBUG ${PROGNAME}: ${local_debug_message}"
return 0
}
# }}}
error_message() { # {{{
local_error_message="${1}"
local_error_code="${2}"
## Print message if DEBUG is enable (=0)
[ "${DEBUG}" -eq "0" ] && printf '%b\n' "ERROR ${PROGNAME}: ${RED}${local_error_message}${RESET}"
exit "${local_error_code:=66}"
}
# }}}
is_proc_running() { # {{{
local_proc_pattern="${1}"
local_count_proc_pattern="$(pgrep -f -- "${local_proc_pattern}" | wc -l)"
case "${local_count_proc_pattern}" in
0 ) ## No procs related to this pattern are running
return_proc_running="1"
;;
* ) ## At least one proc seems running
return_proc_running="0"
;;
esac
## Simple debug message to valid current variables
debug_message "is_proc_running \
procs running (with the pattern: ${RED}${local_proc_pattern}${COLOR_DEBUG}) on the current host: ${RED}${local_count_proc_pattern}${COLOR_DEBUG}."
return "${return_proc_running}"
}
# }}}
start_qutebrowser() { # {{{
return_start_qutebrowser="1"
if is_proc_running "${qutebrowser_proc_pattern}"; then
debug_message "start_qutebrowser \
Qutebrowser is already started."
else
debug_message "start_qutebrowser \
No existing instance of Qutebrowser. Starting…" >> /tmp/qb.log
sh -c "${BROWSER}"
return_start_qutebrowser="0"
fi
return "${return_start_qutebrowser}"
}
# }}}
focus_to_qutebrowser() { # {{{
## Get desktop and window ID of the first "qutebrowser" window
qutebrowser_desktop_id=$(command wmctrl -l | grep --max-count=1 -E -- "${QUTEBROWSER_WINDOW_TITLE}" | cut -d" " -f3)
qutebrowser_window_id=$(command wmctrl -l | grep --max-count=1 -E -- "${QUTEBROWSER_WINDOW_TITLE}" | cut -d" " -f1)
debug_message "focus_to_qutebrowser \
Qutebrowser window ID: ${RED}${qutebrowser_window_id}${COLOR_DEBUG} on desktop ID: ${RED}${qutebrowser_desktop_id}${COLOR_DEBUG}."
### Switch to Qutebrowser desktop
command wmctrl -s "${qutebrowser_desktop_id}"
## If HerstluftWM is available
if [ "$(command -v herbstclient)" ]; then
debug_message "focus_to_qutebrowser \
Focus with herbstclient."
### Focus to the window id
herbstclient jumpto "${qutebrowser_window_id}"
else
debug_message "focus_to_qutebrowser \
Focus with wmctrl."
### Switch expected window
command wmctrl -i -R "${qutebrowser_window_id}"
fi
}
# }}}
get_qutebrowser_buffers() { # {{{
## Clear previous buffers list
[ -f "${QUTEBROWSER_SESSION_FILE}" ] && rm -f -- "${QUTEBROWSER_SESSION_FILE}"
## Run save_buffers.py in Qutebrowser
echo '{"args":[":save-window-and-buffers"], "target_arg":"", "protocol_version":1}' |\
socat - UNIX-CONNECT:"$QUTEBROWSER_SOCKET_FILE"
## Wait to get the buffers list
i="0"
while [ "${i}" -lt "5" ]; do
if [ -f "${QUTEBROWSER_SESSION_FILE}" ]; then
break
else
sleep 0.01
fi
i=$((i+1))
done
sed "s/^/ff /g" "${QUTEBROWSER_SESSION_FILE}" >> "${QUTEBROWSER_GLOBAL_CONTENT}"
}
# }}}
get_qutebrowser_content() { # {{{
[ -S "${QUTEBROWSER_SOCKET_FILE}" ] && get_qutebrowser_buffers
get_qutebrowser_searchengine
[ -f "${QUTEBROWSER_QUICKMARK_FILE}" ] && sed "s/^/qq /g" "${QUTEBROWSER_QUICKMARK_FILE}" >> "${QUTEBROWSER_GLOBAL_CONTENT}"
[ -f "${QUTEBROWSER_BOOKMARK_FILE}" ] && sed "s/^/bb /g" "${QUTEBROWSER_BOOKMARK_FILE}" >> "${QUTEBROWSER_GLOBAL_CONTENT}"
}
# }}}
get_qutebrowser_searchengine() { # {{{
if [ -f "${QUTEBROWSER_SEARCHENGINE_FILE}" ]; then
### Store search engine in global list (for display)
sed -n "s/c.url.searchengines\['\(.*\)'\] = '\(.*\)'$/\1 \2/p" "${QUTEBROWSER_SEARCHENGINE_FILE}" >> "${QUTEBROWSER_GLOBAL_CONTENT}"
### And in specific list to verify is an engine was used
sed -n "s/c.url.searchengines\['\(.*\)'\] = '\(.*\)'$/\1 \2/p" "${QUTEBROWSER_SEARCHENGINE_FILE}" >> "${QUTEBROWSER_SEARCHENGINE_LIST}"
fi
if [ -s "${QUTEBROWSER_SEARCHENGINE_LIST}" ]; then
return_get_qutebrowser_searchengine="0"
debug_message "get_qutebrowser_searchengine \
successfully add search engines from ${QUTEBROWSER_SEARCHENGINE_FILE} file to temp list."
else
return_get_qutebrowser_searchengine="1"
debug_message "get_qutebrowser_searchengine \
Can't get search engines list.\
${RED}${QUTEBROWSER_SEARCHENGINE_FILE}${COLOR_DEBUG} file doesn't exist or impossible to parse."
fi
return "${return_get_qutebrowser_searchengine}"
}
# }}}
goto_qutebrowser_content() { # {{{
get_qutebrowser_content
debug_message "goto_qutebrowser_content \
Search in Qutebrowser's content ${QUTEBROWSER_GLOBAL_CONTENT} file."
st -g 90x30+0+540 -n QuteBrowserSearch -t QuteBrowserQuteBrowserSearch -e sh -c "cat ${QUTEBROWSER_GLOBAL_CONTENT} | dmenu -l 15 -i -p 'Search with Engine' > ${choice_temp_file}"
if [ -s "${choice_temp_file}" ]; then
debug_message "goto_qutebrowser_content \
Store results in ${choice_temp_file}."
return_goto_qutebrowser_content="0"
else
debug_message "goto_qutebrowser_content \
Search aborded or can't find matching bookmark."
return_goto_qutebrowser_content="1"
fi
return "${return_goto_qutebrowser_content}"
}
# }}}
open_in_qutebrowser() { # {{{
url=$(printf "%s" "${url}" | sed 's/ /%20/g')
debug_message "open_in_qutebrowser \
Try to open ${RED}${url}${COLOR_DEBUG}"
sh -c "${BROWSER} ${url}"
}
# }}}
is_url_in_buffer() { # {{{
if grep -q -E -- "${url}" "${QUTEBROWSER_SESSION_FILE}"; then
debug_message "is_url_in_buffer \
A buffer is already opened with this URL."
return_is_url_in_buffer="0"
buffer_id=$(grep -E -- "${url}" "${QUTEBROWSER_SESSION_FILE}" | cut -d" " -f1)
buffer_title=$(grep -E -- "${url}" "${QUTEBROWSER_SESSION_FILE}" | sed "s;${buffer_id} \(.*\) PyQt5.QtCore.QUrl.*;\1;")
switch_qutebrowser_buffer
else
debug_message "is_url_in_buffer \
No existent buffer with this URL."
return_is_url_in_buffer="1"
fi
return "${return_is_url_in_buffer}"
}
# }}}
goto_url() { # {{{
debug_message "goto_url \
Manage ${RED}${url}${COLOR_DEBUG} URL"
## Go to an existent buffer with the expected URL
### Or open the URL in a new buffer
is_url_in_buffer \
|| open_in_qutebrowser
}
# }}}
switch_qutebrowser_buffer() { # {{{
debug_message "switch_qutebrowser_buffer \
Try to switch to buffer id: ${buffer_id}."
echo "{\"args\":[\":buffer ${buffer_id}\"], \"target_arg\":\"\", \"protocol_version\":1}" |\
socat - UNIX-CONNECT:"${QUTEBROWSER_SOCKET_FILE}"
## Ensure to focus on expected buffer
QUTEBROWSER_WINDOW_TITLE="${buffer_title}"
}
# }}}
use_searchengine() { # {{{
return_use_searchengine="0"
## If the search engine can't be found
if ! grep --quiet -E "^${search_engine}" -- "${QUTEBROWSER_SEARCHENGINE_LIST}"; then
### Set search engine to DEFAULT
search_engine="DEFAULT"
### Be sure to take the complete request
search_request=$(cat "${choice_temp_file}")
fi
debug_message "use_searchengine \
Use ${RED}${search_engine}${COLOR_DEBUG} search engine."
search_url=$(grep -E "^${search_engine}" -- ${QUTEBROWSER_SEARCHENGINE_LIST} | cut --delimiter=" " --field=3)
debug_message "use_searchengine \
Use URL ${RED}${search_url}${COLOR_DEBUG}"
url=$(printf "%s" "${search_url}" | sed "s/{}/${search_request}/")
goto_url
return "${return_use_searchengine}"
}
# }}}
get_url() { # {{{
local_content=$(cat "${choice_temp_file}")
return_get_url="1"
debug_message "get_url \
Try to manage ${RED}$(cat "${choice_temp_file}")${COLOR_DEBUG}."
case "${local_content}" in
bb*http* ) ## Classic bookmark
url=$(printf "%s" "${local_content}" | cut -d" " -f2)
return_get_url="0"
debug_message "get_url \
URL from classic bookmark ${RED}${url}${COLOR_DEBUG}."
goto_url
;;
qq*http* ) ## Quickmark
url=$(printf "%s" "${local_content}" | cut -d" " -f3)
return_get_url="0"
debug_message "get_url \
URL from quickmark ${RED}${url}${COLOR_DEBUG}."
goto_url
;;
ff* ) ## Buffer
buffer_id=$(printf "%s" "${local_content}" | cut -d" " -f2)
buffer_title=$(printf "%s" "${local_content}" | sed "s;ff ${buffer_id} \(.*\) PyQt5.QtCore.QUrl.*;\1;")
return_get_url="0"
debug_message "get_url \
Buffer title from Qutebrowser: ${RED}${buffer_title}${COLOR_DEBUG}."
switch_qutebrowser_buffer
;;
* )
search_engine=$(printf "%s" "${local_content}" | cut -d" " -f1)
search_request=$(printf "%s" "${local_content}" | cut --complement --delimiter=" " --field=1)
debug_message "get_url \
Try to search the content."
use_searchengine
;;
esac
return "${return_get_url}"
}
# }}}
goto_existing_qutebrowser() { # {{{
debug_message "goto_existing_qutebrowser \
Try to open content in existing instance."
## Try to open Qutebrowser content (buffer, bookmark, quickmark,…)
goto_qutebrowser_content \
&& get_url
## Be sure to focus to the expected buffer
focus_to_qutebrowser
return 0
}
# }}}
main() { # {{{
## Define all vars
define_vars
## Start Qutebrowser if needed
### And exit
start_qutebrowser \
&& exit 0
## Manage existing instance
goto_existing_qutebrowser \
&& exit 0
}
# }}}
# Manage arguments # {{{
## If there is argument(s)
if [ ! "${NBARGS}" -eq "0" ]; then
manage_arg="0"
# Parse all options (start with a "-") one by one
while printf -- '%s' "${1}" | grep -q -E -- "^-+"; do
case "${1}" in
-d|--debug ) ## Enable debug mode
## Enable DEBUG
DEBUG="0"
;;
-h|--help ) ## help
usage
## Exit after help informations
exit 0
;;
* ) ## unknow option
printf '%b\n' "${RED}Invalid option: ${1}${RESET}"
printf '%b\n' "---"
usage
exit 1
;;
esac
debug_message "Arguments management \
${RED}${1}${COLOR_DEBUG} option managed."
## Move to the next argument
shift
manage_arg=$((manage_arg+1))
done
debug_message "Arguments management \
${RED}${manage_arg}${COLOR_DEBUG} argument(s) successfully managed."
else
debug_message "Arguments management \
No arguments/options to manage."
fi
# }}}
main
exit 255