Added .local/bin

This commit is contained in:
HeCodes2Much 2024-08-20 18:25:13 +01:00
parent 9d396c7796
commit 1e75df1729
No known key found for this signature in database
GPG Key ID: 772B2F0F09B01DBE
20 changed files with 3746 additions and 0 deletions

27
.local/bin/fzf/fzf_menu_run Executable file
View File

@ -0,0 +1,27 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# fzf_menu_run
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Wed 10 March 2021, 12:34:47 PM [GMT+1]
#Modified:
# Thu 20 October 2022, 05:48:00 AM [GMT+1]
#
#Description:
# <Todo>
#
#Dependencies:
# devour, fzf
#
# shellcheck disable=all
programs=$(compgen -c | sort -u | tail -n +9)
cmd=$(echo -e "$programs" | fzf --prompt="Run Program: " --border=rounded --margin=1% --color=dark --height 100% --reverse --header=" PROGRAM MENU " --info=hidden --header-first)
exec gobble $cmd

78
.local/bin/fzf/fzf_music Executable file
View File

@ -0,0 +1,78 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# fzf_music
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Wed 10 March 2021, 12:34:47 PM [GMT]
#Modified:
# Mon 21 November 2022, 07:44:23 AM [GMT]
#
#Description:
# fzf music player
#
#Dependencies:
# fzf
#
REPOMENU_MUSICPLAYER="ffplay -nodisp -loglevel quiet"
asksetting() {
playlist=$*
if [[ -z ${playlist} ]]; then
for Song in "$HOME"/Music/*; do
if [ -f "$Song" ]; then
Name=${Song##*/}
case $Name in
*.mp3 | *.flac | *.wav | .ogg)
options+=${Song##*/}$'\n'
;;
esac
fi
done
else
for Song in "$playlist"/*; do
if [ -f "$Song" ]; then
Name=${Song##*/}
case $Name in
*.mp3 | *.flac | *.wav | *.ogg)
options+=${Song##*/}$'\n'
;;
esac
fi
done
fi
echo -e "${options::-1}
Close music player" | fzf --prompt="Song Search: " --border=rounded --margin=1% --color=dark --height 100% --reverse --header=" MUSIC MENU " --info=hidden --header-first
}
LOOPSETTING="true"
while [ -n "$LOOPSETTING" ]; do
CHOICE="$(asksetting "$1")"
[ -n "$CHOICE" ] || exit
unset LOOPSETTING
case $CHOICE in
*.mp3 | *.flac | *.wav | *.ogg)
playlist=$*
if [[ -z ${playlist} ]]; then
folder=$HOME/Music
else
folder=$playlist
fi
$REPOMENU_MUSICPLAYER "$folder/$CHOICE" &
;;
*Close*)
pkill "${REPOMENU_MUSICPLAYER%% *}" &
;;
*)
echo "Program terminated." && exit
;;
esac
done

115
.local/bin/fzf/fzf_pass Executable file
View File

@ -0,0 +1,115 @@
#!/usr/bin/env bash
# -*-coding:utf-8 -*-
# Auto updated?
# Yes
#File :
# fzf_pass
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
# Created:
# Wed 10 March 2021, 12:34:47 PM [GMT]
# Modified:
# Thu 20 October 2022, 06:02:31 AM [GMT+1]
#
# Description:
# fzf
#
# shellcheck disable=all
shopt -s nullglob globstar
typeit=0
if [[ $1 == "--type" ]]; then
typeit=1
shift
fi
xdotool="xsel -b"
STARTDIR=${PASSWORD_STORE_DIR-~/.password-store}
BASEDIR=$STARTDIR
DONE=0
LEVEL=0
PREVSELECTION=""
SELECTION=""
URL_FIELD='url'
LOGIN_FIELD='login'
while [ "$DONE" -eq 0 ] ; do
password_files=( "$STARTDIR"/* )
password_files=( "${password_files[@]#"$STARTDIR"/}" )
password_files=( "${password_files[@]%.gpg}" )
if [ "$LEVEL" -ne 0 ] ; then
password_files=(".." "${password_files[@]}")
fi
entry=$(printf ' %s\n' "${password_files[@]}" | fzf --prompt="Password Search: " --border=rounded --margin=1% --color=dark --height 100% --reverse --header=" PASSWORD MENU " --info=hidden --header-first)
entry=$(echo $entry | sed "s/ //")
if [ -z "$entry" ] ; then
DONE=1
exit
fi
if [ "$entry" != ".." ] ; then
PREVSELECTION=$SELECTION
SELECTION="$SELECTION/$entry"
# check if another dir
if [ -d "$STARTDIR/$entry" ] ; then
STARTDIR="$STARTDIR/$entry"
LEVEL=$((LEVEL+1))
else
# not a directory so it must be a real password entry
if [[ $typeit -eq 0 ]]; then
FIELDS=()
PASSWORD=$(pass show "$SELECTION" | head -1 | sed '/^$/d')
OTHER=$(pass show "$SELECTION" | awk -F: '(NR>1){ st = index($0,":");print $1 substr($0,st+1)}')
FIELDS+=" Password\n"
if [ ! -z "${OTHER}" ]; then
while read -r line; do
FIELD=$(echo -e "$line" | awk '{print $1}')
if [ "$FIELD" = "login" ]; then
FIELDS+=" ${FIELD^}\n"
elif [ "$FIELD" = "url" ]; then
FIELDS+="爵 ${FIELD^^}\n"
else
FIELDS+=" ${FIELD^}\n"
fi
done <<< "$OTHER"
fi
ENTRY_FIELD=$(echo -e "$FIELDS" | sed '/^$/d' | fzf --prompt="Password Settings: " --border=rounded --margin=1% --color=dark --height 100% --reverse --header=" PASSWORD MENU " --info=hidden --header-first)
if [[ $ENTRY_FIELD = *'Password' ]]; then
PASSWORD=$(pass show "$SELECTION" | sed "s/^[ \t]*//" | head -1 | sed '/^$/d')
echo -n "$PASSWORD" | $xdotool
elif [[ $ENTRY_FIELD = *'URL' ]]; then
URL=$(pass show "$SELECTION" | grep "${URL_FIELD}" | awk '{sub(/:/,"")}{print $2}1' | sed "s/^[ \t]*//" | head -1 | sed '/^$/d')
echo -n "$URL" | $xdotool
elif [[ $ENTRY_FIELD = *'Login' ]]; then
LOGIN=$(pass show "$SELECTION" | grep "${LOGIN_FIELD}" | awk '{sub(/:/,"")}{print $2}1' | sed "s/^[ \t]*//" | head -1 | sed '/^$/d')
echo -n "$LOGIN" | $xdotool
else
CUSTOM_FIELD=$(echo -e "$ENTRY_FIELD" | awk 'NF>1 {sub("^[^A-Z]*","")} {print}')
CUSTOM_FIELD=$(pass show "$SELECTION" | grep "${CUSTOM_FIELD,,}" | awk '{sub(/:/,"")}{first = $1; $1=""; print $0;}1' | sed "s/^[ \t]*//" | head -1 | sed '/^$/d')
echo -n "$CUSTOM_FIELD" | $xdotool
fi
else
xdotool - <<<"type --clearmodifiers -- $(pass show "$SELECTION" | head -n 1 | sed '/^$/d')"
fi
DONE=1
fi
else
LEVEL=$((LEVEL-1))
SELECTION=$PREVSELECTION
STARTDIR="$BASEDIR/$SELECTION"
fi
done

101
.local/bin/fzf/fzf_powermenu Executable file
View File

@ -0,0 +1,101 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# fzf_powermenu
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Wed 10 March 2021, 12:34:47 PM [GMT+1]
#Modified:
# Tue 01 November 2022, 06:45:08 AM [GMT]
#
#Description:
# <Todo>
#
#Dependencies:
# fzf
#
# shellcheck disable=all
getuptime() {
uptime -p >/dev/null 2>&1
if [ "$?" -eq 0 ]; then
# Supports most Linux distro
# when the machine is up for less than '0' minutes then
# 'uptime -p' returns ONLY 'up', so we need to set a default value
UP_SET_OR_EMPTY=$(uptime -p | awk -F 'up ' '{print $2}')
UP=${UP_SET_OR_EMPTY:-'less than a minute'}
else
# Supports Mac OS X, Debian 7, etc
UP=$(uptime | sed -E 's/^[^,]*up *//; s/mins/minutes/; s/hrs?/hours/;
s/([[:digit:]]+):0?([[:digit:]]+)/\1 hours, \2 minutes/;
s/^1 hours/1 hour/; s/ 1 hours/ 1 hour/;
s/min,/minutes,/; s/ 0 minutes,/ less than a minute,/; s/ 1 minutes/ 1 minute/;
s/ / /; s/, *[[:digit:]]* users?.*//')
fi
echo "$UP"
}
asksetting() {
options=" Lock
望 Sleep
 Logout
 Restart
襤 Shutdown"
echo -e "Uptime: $(getuptime)
$options" | fzf --prompt="Power Settings: " --border=rounded --margin=1% --color=dark --height 100% --reverse --header=" POWER MENU " --info=hidden --header-first
}
triggerFunction() {
init_system="$(cat /proc/1/comm)"
if [[ $init_system = "systemd" ]]; then
systemctl "$1"
elif [[ $init_system = "init" ]]; then
loginctl "$1"
elif [[ $init_system = "runit" ]]; then
loginctl "$1"
else
systemctl "$1"
fi
}
LOOPSETTING="true"
while [ -n "$LOOPSETTING" ]; do
CHOICE="$(asksetting "$@")"
[ -n "$CHOICE" ] || exit
unset LOOPSETTING
case "$CHOICE" in
*Logout)
if [[ "$DESKTOP_SESSION" == "i3" ]]; then
i3-msg exit
elif [[ "$DESKTOP_SESSION" == "herbstluftwm" ]]; then
herbstclient quit
else
pkill -KILL -u "$USER"
fi
;;
*Lock)
multimonitorlock -l -- --time-str="%I:%M:%S %p"
;;
*Shutdown)
triggerFunction poweroff
;;
*Restart)
triggerFunction reboot
;;
*Sleep)
triggerFunction suspend
;;
*)
echo "Program terminated." && exit 1
;;
esac
done

138
.local/bin/fzf/fzf_run Executable file
View File

@ -0,0 +1,138 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# fzf_run
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Wed 10 March 2021, 12:34:47 PM [GMT+1]
#Modified:
# Sat 05 November 2022, 04:25:20 PM [GMT]
#
#Description:
# <Todo>
#
#Dependencies:
# bash
#
# shellcheck disable=all
## Script metadata
SCRIPTNAME=${0##*/}
DESCRIPTION="A bash and fzf run script for terminal."
AUTHOR="The-Repo-Club <wayne6324@gmail.com>"
command=''
width=''
height=''
instance=''
term=''
#=== COLORS ===================================================================
## Set Colors (copied from makepkg)
b_blk="\e[0;90m"
b_red="\e[0;91m"
b_grn="\e[0;92m"
b_yel="\e[0;93m"
b_blu="\e[0;94m"
b_mag="\e[0;95m"
b_cyn="\e[0;96m"
b_wht="\e[0;97m"
blk="\e[0;30m"
red="\e[0;31m"
grn="\e[0;32m"
yel="\e[0;33m"
blu="\e[0;34m"
mag="\e[0;35m"
cyn="\e[0;36m"
wht="\e[0;37m"
bld="\e[1;1m"
del="\e[0;0m"
readonly b_blk b_red b_grn b_yel b_blu b_mag b_cyn b_wht blk red grn yel blu mag cyn wht bld del
#=== FUNCTION =================================================================
# Name: error
# Description: Print message with a red pretag an ERROR
# Parameter 1: Message to print
#==============================================================================
# copied from makepkg
error() {
local mesg=$1
printf "${red}${bld}==> ERROR:${wht} %b${del}\n" "$mesg"
}
run_program() {
if command -v $command &>/dev/null; then
cmd="xterm"
if [[ -n $term ]]; then
cmd="$term"
fi
if [[ -n $instance ]]; then
cmd+=" --class=$instance"
fi
if [[ -n $command ]]; then
cmd+=" -e $command"
fi
exec $cmd >&/dev/null
exit 0
fi
}
show_help() {
printf "
%b
Usage:
%b...
%b [options]...
Options:
-h, --help Display help.
-c, --command Set the command to be ran..
-i, --instance Set the WM_CLASS for the program thats ran.
-t, --term Override the terminal you would like to use.
\n" "$DESCRIPTION" "$SCRIPTNAME" "$SCRIPTNAME"
exit 0
}
while [[ "$1" ]]; do
case $1 in
--command | -c)
shift
command=$1
;;
--instance | -i)
shift
instance=$1
;;
--term | -t)
shift
term=$1
;;
--help | -h)
show_help
exit
;;
-*)
error 'Incorrect option(s) specified.'
show_help
;;
*)
error 'Incorrect option(s) specified.'
show_help
;;
esac
shift
done
run_program
error 'Incorrect option(s) specified.'
show_help

269
.local/bin/fzf/fzf_youtube_subs Executable file
View File

@ -0,0 +1,269 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# fzf_youtube_subs
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Sun 03 January 2021, 05:09:33 PM [GMT]
#Modified:
# Thu 20 October 2022, 03:27:18 PM [GMT+1]
#
#Description:
# Watch your youtube subscriptions without a youtube account
# via curl, fzf, browser and basic unix commands.
#
# The $SUBS_FILE is a text file containing usernames or channel IDs
# comments and blank lines are ignored.
#
#
#Dependencies:
# fzf
#
fzf_menu() {
fzf --prompt="Select a video: " --border=rounded --margin=1% --color=dark --height 100% --reverse --header=" YOUTUBE SUBS MENU " --info=hidden --header-first
}
# -/-/-/-/- Settings -/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
: "${SUBS_FILE:=${HOME}/.config/fzf/subs.ini}"
: "${SUBS_MENU_PROG:=fzf_menu}"
: "${SUBS:=${HOME}/.cache/subs}"
: "${SUBS_LINKS:=$SUBS/links}"
: "${SUBS_OPEN:=$(gobble videoplayer)}"
: "${SUBS_CACHE:=$SUBS/cache}"
: "${SUBS_SLEEP_VALUE:=0.05}" # raise this if you experience problems
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SEP=^^^^^ # shouldn't need to change this
# -/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
die() {
printf >&2 '%s\n' "$*"
exit 1
}
usage() {
die 'Usage: fzf_youtube_subs [-c cat_subs] [-g gen_links] [-u update_subs] [-d daemonize]'
}
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
# Synopsis: $SUBS_FILE [txt] -> $SUBS_LINKS [xml links]
#
# Updates local cache of xml subscription links from the
# subscription file containing either usernames or channel ids.
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
gen_links() {
: >"$SUBS_LINKS"
count=0
total=$(sed -e '/^$/d' -e '/^#/d' <"$SUBS_FILE" | wc -l)
while read -r line; do
# ignore comments and blank lines
case $line in '' | ' ' | '#'*) continue ;; esac
# strip off in-line comments and any trailing whitespace
line=${line%%#*}
line=${line%% *}
count=$((count + 1))
case $line in
UC*)
# YT channel IDs always begin with 'UC' and are 24 chars long
printf "[%s/%s] using channel ID '%s' for xml link\n" "$count" "$total" "$line"
[ ${#line} -eq 24 ] &&
printf 'https://youtube.com/feeds/videos.xml?%s\n' \
"channel_id=$line" >>"$SUBS_LINKS"
;;
*)
# otherwise we are given a username, we must find out its channel ID
printf "fetching channel ID for %s...\n" "$line"
curl -sfL --retry 10 "https://youtube.com/user/$line/about" |
while read -r line; do
case $line in
*channel/UC??????????????????????*)
line=${line##*channel/}
line=${line%%\"*}
printf "[%s/%s] using channel ID '%s' for xml link\n" "$count" "$total" "$line"
printf 'https://youtube.com/feeds/videos.xml?channel_id=%s\n' \
"$line" >>"$SUBS_LINKS"
break
;;
esac
done &
sleep "${SUBS_SLEEP_VALUE:-0}"
;;
esac
done <"$SUBS_FILE"
count=0
while [ "$count" -ne "$total" ]; do
count=$(wc -l <"$SUBS_LINKS")
printf "[%s/%s] waiting for jobs to complete...\n" "$count" "$total"
sleep 0.5
done
}
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
# Synopsis: $1 [LINK] -> $SUBS_CACHE/$chan_name/concat [CHANNEL INFO]
#
# Takes a channel rss feed link and creates a file
# with a line of its videos dates, titles, and urls.
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
get_vids() {
data=$(curl -sfL --retry 15 "$1")
# hide the first <published> tag which is the channel
# creation date
data=${data#*\<\/published\>}
# trim off outer <name> tags
chan=${data%%</name*}
chan=${chan##*name>}
printf "%s\n" "$data" |
while read -r line; do
case $line in
*'link rel='*)
line=${line#*href=\"}
line=${line%\"/\>}
line=https://${line#*www.}
url=$line
;;
*'<published>'*)
line=${line%+00:*}
line=${line#*<published>}
date=$line
;;
*'<media:title>'*)
line=${line%</*}
line=${line#*:title>}
title=$line
printf '%s\n' \
"${date}${SEP}${chan}${SEP}${title}${SEP}${url}" \
>>"$SUBS_CACHE/$chan"
;;
esac
done
}
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
# Updates the local cache of subscriptions. ([-u] flag)
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
update_subs() {
[ -f "$SUBS_LINKS" ] || die 'Subs links have not been generated.'
rm -r "${SUBS_CACHE:-?}" 2>/dev/null || :
mkdir -p "$SUBS_CACHE"
total=$(wc -l <"$SUBS_LINKS")
count=0
while read -r link; do
count=$((count + 1))
printf 'starting job [%s/%s] for %s\n' "$count" "$total" "$link"
get_vids "$link" &
sleep "${SUBS_SLEEP_VALUE:-0}"
done <"$SUBS_LINKS"
count=0
while [ "$count" -ne "$total" ]; do
count=$(printf '%s\n' "$SUBS_CACHE"/* | wc -l)
printf "[%s/%s] waiting for fetch jobs to complete...\n" "$count" "$total"
sleep 0.5
done
printf '%s\n\n' 'done!'
}
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
# Grab current cache of subscriptions, sort by date uploaded
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
cat_subs() {
sort -r "$SUBS_CACHE"/* |
while read -r line; do
chan=${line#*$SEP}
chan=${chan%%$SEP*}
title=${line#*$chan$SEP}
title=${title%%$SEP*}
date=${line%%$SEP*}
date=${date#*-}
date=${date%T*}
printf '[%s %s] %s\n' "$date" "$chan" "$title"
done
}
# Split the concatenated lines into entities, send to menu program.
# Finally, play the result with mpv.
get_sel() {
if [ -d "$SUBS_CACHE" ]; then
sel=$(cat_subs | $SUBS_MENU_PROG)
else
die 'Subs cache has not been retrieved.'
fi
[ "$sel" ] || die Interrupted
chan="${sel#* }"
chan="${chan%%] *}"
title=${sel#*"$chan"\] }
while read -r line; do
case $line in
*"$SEP$title$SEP"*)
url=${line##*$SEP}
if [ "$url" ]; then
printf 'playing: %s\n' "$url"
# Play the selection.
# shellcheck disable=2086
exec devour $SUBS_OPEN "$url"
fi
break
;;
esac
done <"$SUBS_CACHE/$chan"
}
daemonize() {
# create a cached copy of the subs file to check for changes
# if changes occur, re-generate links automatically
daemon_file=${HOME}/.cache/subs_daemon.cache
if [ ! -f "$daemon_file" ]; then
cp -f "${SUBS_FILE:=${HOME}/.config/fzf/subs.ini}" "$daemon_file"
fi
while true; do
if ! cmp "${SUBS_FILE:=${HOME}/.config/fzf/subs.ini}" "$daemon_file"; then
cp -f "${SUBS_FILE:=${HOME}/.config/fzf/subs.ini}" "$daemon_file"
fi
gen_links
update_subs
interval=${SUBS_DAEMON_INTERVAL:-$((10 * 60))}
printf 'Sleeping for %s seconds...\n' "$interval"
sleep "$interval"
done
}
main() {
mkdir -p "$SUBS"
case ${1#-} in
h) usage ;;
g) gen_links ;;
u) update_subs ;;
c) cat_subs ;;
d) daemonize ;;
*) get_sel ;;
esac
}
main "$@"

125
.local/bin/rofi/README.md Normal file
View File

@ -0,0 +1,125 @@
# Bookmark Manager
## Usage
```help
Usage: ./bm [modifier(s)] command [option(s)]
Commands :
==========
-h Print this help
-H Print help for legacy usage
-v/-V Print the version
-a 'URL' Add the URL to bookmark file
Options for -a
-t "TagList" Tags are sparated by a comma ,
-T "Title" Title for this URL (if empty and allowed Title
downloaded)
-A "accel" Accelerator when search for URLs (start with Accel)
Default is FQDN without gTld (and www, and sheme)
-F Force the bookmark to be created (even if duplicate
or invalid)
-p Force the screenshot to be taken
-l List all URLs (default action, same thing as calling bm without args)
Options for -l
-z Use the alternate print list
-n Sort the results by date
-N Sort the results by date (reverse)
-s 'object' Search for bookmarks
Options for -s
-i Incensitive case search
-z Use the alternate print list
-n Sort the results by date
-N Sort the results by date (reverse)
-o 'object' Search for bookmarks and open it (use the same argument as for -s)
Options for -o
-i Incensitive case search
-O If more than one answer force the first bookmark to be open
-Y If more than one answer force ALL bookmarks to be open
-x 'object' Search for bookmarks and copy it to clipboard (use the same argument as for -s)
Options for -x
-i Incensitive case search
-X If more than one answer force the first bookmark to be copied
-Y If more than one answer force ALL bookmarks to be copied
-r 'object' Search for bookmarks and Print the recorded associated picture (use the same argument as for -s)
Options for -r
-i Incensitive case search
-O If more than one answer force the first bookmark to have its picture printed
-Y If more than one answer force ALL bookmarks to have their picture printed
-d 'URL' or Delete the URL from bookmark file md5sum or 'URL part'
Options for -d
-D Delete first occurence only
-F Force the bookmark to be deleted (even if duplicate)
-p Delete the associated picture (no trash available)
-g Generate a HTML page with all bookmarks
If used more than once, generate a page per tag
Options for -g
-G "filename" If g==1 then generate then use this filename to generate page
-O Open the file when generated
-P 'object' Generate all Non existant picture (check done for all URL in bm), if none argument.
If an argument is given (use the same argument as for -s) only the results will have a picture.
Options for -P
-F Force the picture to be taken again (even if already exists).
-L List all tags
-C Print the color table (usefull for configuration)
-S Show statistics about bookmarks/tags (and also configuration)
Options for -S
-p Print the list of orphaned Pictures
Modifiers :
===========
-c 'file' Use this configuration file instead of the default one
-b 'file' Use this bookmark file instead of the default one
Objects:
========
:string Search in accelerator list
+string Search in tags list
=string Search in MD5 list
/string Search in URL list
string Search in full test
How to use:
===========
# add a bookmark with the given url, description, and optional tags
$ bm add <url> [desc] [tag...] [accelerator]
# open the first bookmark matching <query>
$ bm open <query>
$ bm <query>
# search the bookmarks via full-text <query>
$ bm search <query>
# list tags
$ bm tags
# list bookmarks available
$ bm list
$ bm ls
$ bm
# display statistics about the bookmarks
$ bm statistics
$ bm stats
# view bookmark screenshots in your default browser
$ bm view design
$ bm view
# clear all bookmarks
$ bm clear
```

925
.local/bin/rofi/bm Executable file
View File

@ -0,0 +1,925 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# bm
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Fri 09 December 2022, 07:19:23 AM [GMT]
#Modified:
# Fri 14 July 2023, 11:47:25 PM [GMT+1]
#
#Description:
# <Todo>
#
#Dependencies:
# <None>
#
# shellcheck disable=all
# default filename for Baker config file (just the filename no path)
readonly _BM_DEFAULT_CONFIG_FILENAME="${_BM_DEFAULT_CONFIG_FILENAME:=bm.conf}"
config() {
echo "Reading Configuration..."
[[ "${__w:=$HOME}" != "${HOME}" ]] && echo "Working dir changed to ${__w}"
[[ "${__w: -1}" != '/' ]] && __w="${__w//\/\//\/}/"
if [ ${__B:=0} -eq 0 ]; then
# If a config file is given, we take it first, or look for a default config file
export _BM_CONFIG_FILE="${__w}${_BM_DEFAULT_CONFIG_FILENAME}"
if [ "$(uname -s)" = 'Linux' -a -f "$(readlink -m "${1:-}" 2>/dev/null)" ]; then
export _BM_CONFIG_FILE="${1}"
. "${1}"
elif [ -e "${1}" ]; then
export _BM_CONFIG_FILE="${1}"
. "${1}"
elif [ ${__n:=0} -eq 0 -a -f "${__w}${_BM_DEFAULT_CONFIG_FILENAME}" ]; then
. "${__w}${_BM_DEFAULT_CONFIG_FILENAME}"
echo "Default config file loaded ${__w}${_BM_DEFAULT_CONFIG_FILENAME}"
fi
else
export _BM_CONFIG_FILE='none'
fi
# _BM_BOOKMARK_FILE : Where is stored the bookmark file
export _BM_BOOKMARK_FILE="${_BM_BOOKMARK_FILE:=${__w}bm.bm}"
# _BM_BOOKMARK_BACKUP_FILE : Where is stored the backup of bookmark file
export _BM_BOOKMARK_BACKUP_FILE="${_BM_BOOKMARK_BACKUP_FILE:=${__w}.bm.bm.bck}"
# _BM_HTML_FILE : Location of generated HTML file
export _BM_HTML_FILE="${_BM_HTML_FILE:=${__w}bm.html}"
# _BM_DELETE_FILE : Where to find the deleted URLs
export _BM_DELETE_FILE="${_BM_DELETE_FILE:=${__w}.bm.trash}"
# _BM_BOOKMARK_BACKUP : Copy the bookmark file before each modification
export _BM_BOOKMARK_BACKUP=${_BM_BOOKMARK_BACKUP:=false}
# _BM_BOOKMARK_BACKUP_VERSION : How many copy to keep (0 for 1, 1 for 2, ...)
export _BM_BOOKMARK_BACKUP_VERSION=${_BM_BOOKMARK_BACKUP_VERSION:=0}
# _BM_DELETE_ALLOWED : Even with the force flag the delete function will not be allowed (true or false)
export _BM_DELETE_ALLOWED=${_BM_DELETE_ALLOWED:=true}
# _BM_DELETE_TO_FILE : Allow or disallow the deleted URLs to be copied in the Trash (true or false)
export _BM_DELETE_TO_FILE=${_BM_DELETE_TO_FILE:=false}
# _BM_DELETE_PICTURE : Allow or disallow the picture associated to a URL to be deleted (true or false)
export _BM_DELETE_PICTURE=${_BM_DELETE_PICTURE:=true}
# _BM_DUPS_DETECT : Look for duplicates URL before insert in bookmark file (ovverided by -F)
export _BM_DUPS_DETECT=${_BM_DUPS_DETECT:=true}
# _BM_ASK_BEFORE_OPEN : When using bm with a URL (or search term) ask before opening the browser if more than one answer
export _BM_ASK_BEFORE_OPEN=${_BM_ASK_BEFORE_OPEN:=true}
# _BM_GET_PAGE_TITLE : When adding a URL execute a curl command to get the <title> if none given
export _BM_GET_PAGE_TITLE=${_BM_GET_PAGE_TITLE:=true}
# _BM_SCREENSHOT_DIRECTORY : Where to store the screenshot taken
export _BM_SCREENSHOT_DIRECTORY="${_BM_SCREENSHOT_DIRECTORY:=${__w}.bm.shots}"
# _BM_SCREENSHOT_GET : When adding a URL try to take a screenshot in background
export _BM_SCREENSHOT_GET=${_BM_SCREENSHOT_GET:=true}
# _BM_SCREENSHOT_WAIT : When taking a screenshot wait for the action to finish
export _BM_SCREENSHOT_WAIT=${_BM_SCREENSHOT_WAIT:=false}
# _BM_OPEN_FIRST : When using open, the first link found is open
# Also work with the copy to clipboard function
export _BM_OPEN_FIRST=${_BM_OPEN_FIRST:=false}
# _BM_OPEN_ALL : When using open, if more than one result, all are open (with the same function)
# Also work with the copy to clipboard function (overrided by -Y)
export _BM_OPEN_ALL=${_BM_OPEN_ALL:=false}
# _BM_NO_ARGS_FORCE_HELP : If no args given to script sends to help instead of list all link
export _BM_NO_ARGS_FORCE_HELP=${_BM_NO_ARGS_FORCE_HELP:=false}
# _BM_CREATE_BOOKMARK_FILE : If bm is called to list and no file exists. bm will create a default one.
export _BM_CREATE_BOOKMARK_FILE=${_BM_CREATE_BOOKMARK_FILE:=true}
# _BM_CMD_CAPTURE_CHECK : If you don't have tool installed to take screenshot, just put to false.
# It will disable the _BM_GET_SCREENSHOT.
export _BM_CMD_CAPTURE_CHECK=${_BM_CMD_CAPTURE_CHECK:=true}
# I suppose the uname command is available
# Please note, the PRE & POST capture command will not be analyzes nor verified.
if [ "$(uname -s)" = 'Linux' ]; then
export _BM_CMD_IMAGE_OPEN='feh'
export _BM_CMD_OPEN='xdg-open'
export _BM_CMD_PRE_CAPTURE=''
export _BM_CMD_CAPTURE='cutycapt'
export _BM_CMD_CAPTURE_ARGS='--insecure --url={URL} --out={FILE}'
export _BM_CMD_POST_CAPTURE=''
export _BM_CMD_MD5='md5sum'
export _BM_CMD_COPY='xsel'
else
# To keep commpatibility with the Mac (even i don't have any)
export _BM_CMD_IMAGE_OPEN='open'
export _BM_CMD_OPEN='open'
export _BM_CMD_PRE_CAPTURE=''
export _BM_CMD_CAPTURE='webkit2png'
export _BM_CMD_CAPTURE_ARGS='-C -o {FILE}.png {URL}'
export _BM_CMD_POST_CAPTURE='cp -- "{FILE}-clipped.png" "{FILE}" ; rm -f -- {FILE}-{clipped,full,thumb}.png'
export _BM_CMD_MD5='md5'
export _BM_CMD_COPY='xsel'
fi
# _BM_PRINT_LINE : This line is used to print datas
export _BM_PRINT_LINE="${_BM_PRINT_LINE:=${BOLD}${GRAY}BM_ACCEL ${RESET}${DIM}-->${RESET} ${GRAY_LIGHT}BM_TITLE ${GRAY_DARK}${BOLD}[BM_TAGS]${RESET}\n${UNDERLINE}${DIM}BM_URL${RESET} - ${GRAY_DARK}Added: BM_DATE${RESET}}"
# _BM_PRINT_LINE_ALTERNATIVE : This line is used to print datas
export _BM_PRINT_LINE_ALTERNATIVE="${_BM_PRINT_LINE_ALTERNATIVE:=${BOLD}${GRAY}BM_ACCEL ${RESET}${DIM}-->${RESET} ${GRAY_LIGHT}BM_TITLE ${GRAY_DARK}${BOLD}[BM_TAGS]${RESET}\n${UNDERLINE}${DIM}BM_URL${RESET} ${GRAY_DARK}(BM_MD5)${RESET} - ${GRAY_DARK}Added: BM_DATE${RESET} - ${GRAY_DARK}Picture: BM_PICTURE${RESET}}"
# _BM_PRINT_SCHEME : If set to no, bm will remove scheme from URL printing
export _BM_PRINT_SCHEME=${_BM_PRINT_SCHEME:=true}
# _BM_SEARCH_IGNORECASE : Ignore case if set when searching (overrided by -i)
export _BM_SEARCH_IGNORECASE=${_BM_SEARCH_IGNORECASE:=false}
}
# slug creates a friendly URL like 'hello-world'
slug() {
iconv -f utf8 -t ascii//TRANSLIT | tr -cs '[:alnum:]\n' - | tr '[:upper:]' '[:lower:]' | sed 's|^-*||;s|-*$||'
}
# version
RELEASE='$Format:%h$'
VERSION='2021.04.05'
#
# Output usage info
#
usage() {
cat <<EOF
Usage: ${0} [modifier(s)] command [option(s)]
Commands :
==========
-h Print this help
-v/-V Print the version/And the short commit name
-a 'URL' Add the URL to bookmark file
Options for -a
-t "TagList" Tags are sparated by a comma ,
-T "Title" Title for this URL (if empty and allowed Title
downloaded)
-A "accel" Accelerator when search for URLs (start with Accel)
Default is an autoincrement index
-F Force the bookmark to be created (even if duplicate
or invalid)
-p Force the screenshot to be taken (config dependant)
-l List all URLs (default action, same thing as calling bm without args)
Options for -l
-z Use the alternate print list
-n Sort the results by date
-N Sort the results by date (reverse)
-s 'object' Search for bookmarks
Options for -s
-i Incensitive case search
-z Use the alternate print list
-n Sort the results by date
-N Sort the results by date (reverse)
Objects are
:string Search in accelerator list
+string Search in tags list
=string Search in MD5 list
/string Search in URL list
string Search in full test
-o 'object' Search for bookmarks and open it (use the same argument as for -s)
Options for -o
-i Incensitive case search
-O If more than one answer force the first bookmark to be open
-Y If more than one answer force ALL bookmarks to be open
-x 'object' Search for bookmarks and copy it to clipboard (use the same argument as for -s)
Options for -x
-i Incensitive case search
-X If more than one answer force the first bookmark to be copied
-Y If more than one answer force ALL bookmarks to be copied
-r 'object' Search for bookmarks and Print the recorded associated picture (use the same argument as for -s)
Options for -r
-i Incensitive case search
-O If more than one answer force the first bookmark to have its picture printed
-Y If more than one answer force ALL bookmarks to have their picture printed
-d 'URL' Delete the URL from bookmark file
md5sum or
'URL part' Options for -d
-D Delete first occurence only
-F Force the bookmark to be deleted (even if duplicate)
-p Delete the associated picture (no trash available)
-g Generate a HTML page with all bookmarks
If used more than once, generate a page per tag
Options for -g
-G "filename" If g==1 then generate and use this filename to generate page
-O Open the file when generated
-P 'object' Generate all Non existant picture (check done for all URL in bm), if none argument.
If an argument is given (use the same argument as for -s) only the results will have a picture.
Options for -P
-F Force the picture to be taken again (even if already exists).
-q 'object' Connect to the URL to replace the existing Title by the downloaded one.
Options for -q
-i Incensitive case search
-O If more than one answer force the first bookmark to have its title downloaded
-Y If more than one answer force ALL bookmarks to have their title downloaded
-L List all tags
-C Print the color table (usefull for configuration)
-E Open the bm.bm with your \$EDITOR
-S Show statistics about bookmarks/tags (and also configuration)
Options for -S
-p Print the list of orphaned Pictures
Modifiers :
===========
-c 'file' Use this configuration file instead of the default one
-b 'file' Use this bookmark file instead of the default one
-w 'directory' Use this directory to find default configuration file and bookmark file instead of the default one
EOF
}
getAccelMax() {
while read a; do
(( ${a:=0} >= ${_max:=0} )) && (( _max=${a}+1 ))
done <<< "$( awk -F'|' '$0 !~ /^[ ]*#/ && $3 ~ /^[:space:]*:[:space:]*[0-9]+[:space:]*$/ { sub(/:+/, "", $3); print $3; }' "${_BM_BOOKMARK_FILE}")"
echo -n "${_max}"
}
backupBm() {
if [ "${_BM_BOOKMARK_BACKUP,,}" = 'true' ]; then
while [ ${count:=${_BM_BOOKMARK_BACKUP_VERSION}} -gt 0 ]; do
cp -- "${_BM_BOOKMARK_BACKUP_FILE}.$(( count-1 ))" "${_BM_BOOKMARK_BACKUP_FILE}.$(( count-- ))" 2>&1 >/dev/null
done
cp -- "${_BM_BOOKMARK_FILE}" "${_BM_BOOKMARK_BACKUP_FILE}.0"
fi
}
titleDl() {
if command -v hxselect &>/dev/null ; then
curl -Lks "${1:-}" 2>&1 | hxselect -ic title 2>/dev/null
else
curl -Lks "${1:-}" 2>&1 | sed '/<title>/I!d;/<\/title>/I!d;s;^[[:space:]]*<title>\([^<]*\)<.*;\1;i'
fi
}
saveUrl() {
[[ "${__url}" =~ ^[[:space:]]*(f|ht)tps*://.*$ ]] || {
if [ ${__F:=0} -eq 0 ]; then
die "Your URL seems invalid '${__url}'. Use -F to force."
else
echo "Force adding invalid URL" >&2
fi
}
local _sum="$(${_BM_CMD_MD5} <<< "${__url}")"
if [ "${_BM_DUPS_DETECT,,}" = 'true' ]; then
if [ ! -z "$(awk -F '|' '$0 !~ /^[ ]*#/ && $1 ~ /'"${_sum%% *}"'/' "${_BM_BOOKMARK_FILE}")" ]; then
if [ ${__F:=0} -eq 0 ]; then
die "URL is already in the Bookmark file"
else
echo "Force adding duplicate URL" >&2
fi
fi
fi
if [ "${_BM_GET_PAGE_TITLE,,}" = 'true' -a -z "${__T:=}" ]; then
# if [ $( command -v hxselect &>/dev/null ) ]; then
# __T="$( curl -Lks "${__url}" 2>&1 | hxselect -ic title )"
# else
# __T="$( curl -Lks "${__url}" 2>&1 | sed '/<title>/I!d;/<\/title>/I!d;s;^[[:space:]]*<title>\([^<]*\)<.*;\1;i' )"
# fi
__T="$( titleDl "${__url}" )"
fi
[[ ! -z "${__T:=}" ]] && __T="${__T//\|/\\|}"
backupBm
[[ -z "${__T:=}" ]] && __T="$(slug <<< "${__url}")" # If no title => slug the url
[[ -z "${__t:=}" ]] && __t='default' # Default tag is default
[[ -z "${__A:=}" ]] && __A="$(getAccelMax)"
[[ "${__A:0:1}" != ':' ]] && __A=":${__A}" # If no accel => Add a number
echo "${_sum%% *}|$(date '+%FT%TZ')|${__A}|${__url}|${__T}|${__t}" >> "${_BM_BOOKMARK_FILE}" || die "Insert aborted into '${_BM_BOOKMARK_FILE}' !"
echo "${__url} inserted into '${_BM_BOOKMARK_FILE}'"
[[ ! -f "${_BM_SCREENSHOT_DIRECTORY}/${_sum%% *}.png" || ${__F:=0} -eq 1 ]] && { screenshot_take "${_BM_SCREENSHOT_DIRECTORY}/${_sum%% *}.png" "${__url}" & }
[[ "${_BM_SCREENSHOT_WAIT,,}" = 'true' ]] && wait
search_bookmarks "${__A}"
}
#
# manage each line to print it
#
readLines() {
IFS='|'
while read m d a u T t; do
_line="${_BM_PRINT_LINE}"
[[ ${__z:=0} -eq 1 ]] && _line="${_BM_PRINT_LINE_ALTERNATIVE}"
_line="${_line//BM_MD5/$m}"
if [ "${_BM_PRINT_SCHEME,,}" = 'false' ]; then
u="$(sed 's/^[[:space:]]*\(f\|ht\)tps*:\/\///' <<< "${u}")"
fi
_line="${_line//BM_URL/$u}"
_line="${_line//BM_TITLE/$T}"
_line="${_line//BM_TAGS/$t}"
_line="${_line//BM_ACCEL/${a:=No-Accelerator}}"
_line="${_line//BM_DATE/${d}}"
local _pict="$(stat -c '%y' "${_BM_SCREENSHOT_DIRECTORY}/${m}.png" 2>/dev/null)"
[[ ! -z "${_pict}" ]] && _pict="$(date '+%FT%TZ' --date "${_pict}")"
_line="${_line//BM_PICTURE/${_pict:=None}}"
echo -e "${_line}\n"
done
}
#
# List all bookmarks
#
list_bookmarks() {
[[ ${__n:=0} -eq 1 ]] && { awk '$0 !~ /^[ ]*#/' "${_BM_BOOKMARK_FILE}" | sort -t'|' -k2 | readLines; return; }
[[ ${__N:=0} -eq 1 ]] && { awk '$0 !~ /^[ ]*#/' "${_BM_BOOKMARK_FILE}" | sort -t'|' -k2 -r | readLines; return; }
awk '$0 !~ /^[ ]*#/' "${_BM_BOOKMARK_FILE}" | readLines
}
#
# Search all bookmarks with <query>
#
search() {
local _s=''
[[ -z "${1:-}" ]] && list_bookmarks && return
case "${1:0:1}" in
:) _s=3; _ss=0 ;; # Accelerator
+) _s="NF"; _ss=1 ;; # Tags
=) _s=1; _ss=1 ;; # MD5 part
/) _s=4; _ss=1 ;; # URL part
*) _s=0; _ss=0 ;; # full text search
esac
[[ "${_BM_SEARCH_IGNORECASE,,}" = 'true' || ${__i:=0} -eq 1 ]] && local _ign=1
awk -F'|' -vIgn=${_ign:=0} '
BEGIN {
if (Ign == 1) { s=tolower("'"${1:${_ss}}"'"); } else { s="'"${1:${_ss}}"'"; }
}
$0 !~ /^[ ]*#/ && (Ign == 0 && $'"${_s}"' ~ s) || (Ign ==1 && tolower($'"${_s}"') ~ s) {print $0;}
' "${_BM_BOOKMARK_FILE}"
}
search_bookmarks() {
[[ ${__n:=0} -eq 1 ]] && { search "${@}" | sort -t'|' -k2 | readLines; return; }
[[ ${__N:=0} -eq 1 ]] && { search "${@}" | sort -t'|' -k2 -r | readLines; return; }
search "${@}" | readLines
}
#
# Open first bookmark matching <query>
#
recorded_picture() {
local _lines="$(search "${@}")"
if [ "${_BM_ASK_BEFORE_OPEN,,}" = 'true' -a ${__O:=0} -eq 0 -a ${__Y:=0} -eq 0 ]; then
if [ $(wc -l <<< "${_lines}") -gt 1 ]; then
read -p"More than one URL found. Open all Pictures ? [Y/N] : " -n1 _answer
[[ "${_answer,,}" != 'y' ]] && die "\nUse -O to force the first URL or refine your search"
fi
fi
local _all=''
echo ''
while read _nl; do
readLines <<< "${_nl}"
if [ "${_BM_OPEN_ALL,,}" = 'true' -o ${__Y:=0} -eq 1 ]; then
_all="${_BM_SCREENSHOT_DIRECTORY}/$(awk -F'|' '{print $1}' <<< "${_nl}").png ${_all}"
else
"${_BM_CMD_IMAGE_OPEN}" "${_BM_SCREENSHOT_DIRECTORY}/$(awk -F'|' '{print $1}' <<< "${_nl}").png"
[[ "${_BM_OPEN_FIRST,,}" = 'true' || ${__O:=0} -eq 1 ]] && exit 0
fi
done <<< "$(echo -e "${_lines}")"
[[ "${_BM_OPEN_ALL,,}" = 'true' || ${__Y:=0} -eq 1 ]] && "${_BM_CMD_IMAGE_OPEN}" "${_all}"
}
download_title() {
local _lines="$(search "${@}")"
if [ "${_BM_ASK_BEFORE_OPEN,,}" = 'true' -a ${__O:=0} -eq 0 -a ${__Y:=0} -eq 0 ]; then
if [ $(wc -l <<< "${_lines}") -gt 1 ]; then
read -p"More than one URL found. Download Title for all URLs ? [Y/N] : " -n1 _answer
[[ "${_answer,,}" != 'y' ]] && die "\nUse -O to force the first URL or refine your search"
fi
fi
local _all=''
echo ''
while read _nl; do
readLines <<< "${_nl}"
local u="$(awk -F'|' '{print $4}' <<< "${_nl}")"
if [ "${_BM_OPEN_ALL,,}" = 'true' -o ${__Y:=0} -eq 1 ]; then
echo "${u} --> $( titleDl "${u}" )"
else
echo "${u} --> $( titleDl "${u}" )"
[[ "${_BM_OPEN_FIRST,,}" = 'true' || ${__O:=0} -eq 1 ]] && exit 0
fi
done <<< "$(echo -e "${_lines}")"
}
open_bookmark() {
local _lines="$(search "${@}")"
if [ "${_BM_ASK_BEFORE_OPEN,,}" = 'true' -a ${__O:=0} -eq 0 -a ${__Y:=0} -eq 0 ]; then
if [ $(wc -l <<< "${_lines}") -gt 1 ]; then
read -p"More than one URL found. Open all ? [Y/N] : " -n1 _answer
[[ "${_answer,,}" != 'y' ]] && die "\nUse -O to force the first URL or refine your search"
fi
fi
local _all=''
while read _nl; do
readLines <<< "${_nl}"
if [ "${_BM_OPEN_ALL,,}" = 'true' -o ${__Y:=0} -eq 1 ]; then
_all="$(awk -F'|' '{print $4}' <<< "${_nl}") ${_all}"
else
"${_BM_CMD_OPEN}" "$(awk -F'|' '{print $4}' <<< "${_nl}")"
[[ "${_BM_OPEN_FIRST,,}" = 'true' || ${__O:=0} -eq 1 ]] && exit 0
fi
done <<< "$(echo -e "${_lines}")"
[[ "${_BM_OPEN_ALL,,}" = 'true' || ${__Y:=0} -eq 1 ]] && "${_BM_CMD_OPEN}" "${_all}"
}
copy_bookmark() {
local _lines="$(search "${@}")"
if [ "${_BM_ASK_BEFORE_OPEN,,}" = 'true' -a ${__X:=0} -eq 0 -a ${__Y:=0} -eq 0 ]; then
if [ $(wc -l <<< "${_lines}") -gt 1 ]; then
read -p"More than one URL found. Copy all ? [Y/N] : " -n1 _answer
[[ "${_answer,,}" != 'y' ]] && die "\nUse -X to force the first URL or refine your search"
fi
fi
local _all=''
while read _nl; do
readLines <<< "${_nl}"
if [ "${_BM_OPEN_ALL,,}" = 'true' -o ${__Y:=0} -eq 1 ]; then
_all="$(awk -F'|' '{print $4}' <<< "${_nl}") ${_all}"
else
awk -F'|' '{print $4}' <<< "${_nl}" | "${_BM_CMD_COPY}"
awk -F'|' '{print $4}' <<< "${_nl}" | "${_BM_CMD_COPY}" -b
[[ "${_BM_OPEN_FIRST,,}" = 'true' || ${__X:=0} -eq 1 ]] && exit 0
fi
done <<< "$(echo -e "${_lines}")"
[[ "${_BM_OPEN_ALL,,}" = 'true' || ${__Y:=0} -eq 1 ]] && "${_BM_CMD_COPY}" <<< "${_all}"
[[ "${_BM_OPEN_ALL,,}" = 'true' || ${__Y:=0} -eq 1 ]] && "${_BM_CMD_COPY}" -b <<< "${_all}"
}
delete_bookmark() {
[[ -z "${@//[ ]/}" ]] && die "You MUST give an argument !"
local _lines="$(search "${@}")"
if [ "${_BM_DELETE_ALLOWED,,}" = 'true' ]; then
while read _nl; do readLines <<< "${_nl}"; done <<< "$(echo -e "${_lines}")"
if [ "${_BM_ASK_BEFORE_OPEN,,}" = 'true' -a ${__D:=0} -eq 0 -a ${__Y:=0} -eq 0 ]; then
if [ $(wc -l <<< "${_lines}") -ge 1 ]; then
read -p"You're about to delete entry(ies). Ready ? [Y/N] : " -n1 _answer
[[ "${_answer,,}" != 'y' ]] && die "\nUse -D to force the backup if not configured."
echo ''
fi
fi
backupBm
local _all=''
while read _nl; do
if [ "${_BM_DELETE_TO_FILE,,}" = 'true' -o ${__D:=0} -eq 1 ]; then
echo "${_nl}" >> "${_BM_DELETE_FILE}"
fi
[[ "${_BM_DELETE_PICTURE,,}" = 'true' || ${__p:=0} -eq 1 ]] && rm -f -- "${_BM_SCREENSHOT_DIRECTORY}/${_nl%%|*}.png"
IFS='|' read m d a u T t <<< "${_nl}"
sed -i -e '/^'"${m}.*${u//\//\\/}.*${t//\//\\/}"'$/d' "${_BM_BOOKMARK_FILE}"
done <<< "$(echo -e "${_lines}")"
else
die "You're not allowed to delete entries. Change the _BM_DELETE_ALLOWED to true !"
fi
}
edit_bookmark() {
echo -e "You're about to open your '${_BM_BOOKMARK_FILE}' file with your \$EDITOR.\n\n/!\ Press any key to continue, or CTRL+C to abort. /!\ "
read -n1 toto
${EDITOR:=vi} "${_BM_BOOKMARK_FILE}"
}
#
# Diplay some statistics about the bookmarks
#
stats() {
echo "===== Configuration ====="
echo "Bookmark file : ${_BM_BOOKMARK_FILE}"
echo "Trash file : ${_BM_DELETE_FILE}$([[ ! -e "${_BM_DELETE_FILE}" ]] && echo " (but doesn't exist)")"
echo "Config file : ${_BM_CONFIG_FILE}$([[ ! -e "${_BM_CONFIG_FILE}" ]] && echo " (but doesn't exist)")"
echo "Screenshot directory : ${_BM_SCREENSHOT_DIRECTORY}"
echo "Backup file(s) : ${_BM_BOOKMARK_BACKUP_FILE}*"
for i in "${_BM_BOOKMARK_BACKUP_FILE}"*; do
echo " ${i}"
done
echo -e "\n===== Statistics ====="
readarray -t lines < "${_BM_BOOKMARK_FILE}"
echo "# of Bookmarks : ${#lines[@]}"
echo "# of Duplicate : $(awk -F'|' '$0 !~ /^[ ]*#/ {print $1}' "${_BM_BOOKMARK_FILE}" |sort |uniq -d |wc -l)"
local tags="$(awk -F'|' '$0 !~ /^[ ]*#/ {print $NF}' "${_BM_BOOKMARK_FILE}" | sed -e 's/\([[:space:]]*,[[:space:]]*\)/\n/g')"
echo "# of tags : $( sort -u <<< "${tags,,}" |wc -l)"
echo "Top 14 tags used :"
local nli=0;local pa=0
(
sort <<< "${tags,,}" | uniq -c | sort -nr | while read n t; do
(( nli++ ));[[ ${nli} -gt 7 ]] && nli=1 && echo ''
(( pa++ ));[[ ${pa} -gt 14 ]] && break
echo -n "${t// / }:${n} "
done
echo ''
) | column -t -c 17
echo "# of Pictures : $(ls -1 "${_BM_SCREENSHOT_DIRECTORY}"/*.png |wc -l) [# of files in ${_BM_SCREENSHOT_DIRECTORY}:$(ls -1 "${_BM_SCREENSHOT_DIRECTORY}"/* |wc -l)]"
echo "All Pictures size : $(du -sh "${_BM_SCREENSHOT_DIRECTORY}" | awk '{print $1}')"
local orphaned="$( cd "${_BM_SCREENSHOT_DIRECTORY}" && for i in *; do [[ -z "$(sed -e '/'"${i%%.*}"'/!d' "${_BM_BOOKMARK_FILE}")" ]] && ((orph++)); done; echo "${orph:=0}" )"
local nopics="$( while read i; do [[ ! -f "${_BM_SCREENSHOT_DIRECTORY}/${i%%|*}.png" ]] && ((nopics++)); done <<< ${lines[@]}; echo "${nopics:=0}" )"
echo "Bookmark Without Pic : ${nopics}"
echo "Orphaned pictures : ${orphaned}"
[[ ${__p:=0} -eq 1 ]] && { echo -e "\n===== Orphaned ====="; echo "List of orphaned pictures :"; cd "${_BM_SCREENSHOT_DIRECTORY}" && for i in *; do [[ -z "$(sed -e '/'"${i%%.*}"'/!d' "${_BM_BOOKMARK_FILE}")" ]] && echo " - ${_BM_SCREENSHOT_DIRECTORY}/${i} [Trashed URL should be: $(awk -F'|' 'BEGIN{l="Unknown"} ($1 ~ /'"${i%%.*}"'/) {l=$4;} END {print l}' "${_BM_DELETE_FILE}")]"; done; };
}
#
# Output tags.
#
list_tags() {
local tags="$(awk -F'|' '$0 !~ /^[ ]*#/ {print $NF}' "${_BM_BOOKMARK_FILE}" | sed -e 's/\([[:space:]]*,[[:space:]]*\)/\n/g')"
local nli=0
(
sort <<< "${tags,,}" | uniq -c | sort -nr | while read n t; do
(( nli++ ));[[ ${nli} -gt 7 ]] && nli=1 && echo ''
echo -n "${t// / }:${n} "
done
echo ''
) | column -t -c 17
}
#
# Stylesheet
#
style() {
cat <<EOF
<style type="text/css">
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body {
padding: 50px 0 5px 50px;
background: #1f1f1f url(${_BM_SCREENSHOT_DIRECTORY}/black-Linen.png);
font: 12px "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.bm {
position: relative;
float: left;
margin: 15px;
padding: 1px;
opacity: 1;
border: 15px solid black;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-webkit-transition: -webkit-box-shadow 600ms;
-moz-transition: -webkit-box-shadow 600ms;
-webkit-box-shadow: 0 0 1px 0 #555, 0 0 10px rgba(0,0,0,.5);
-moz-box-shadow: 0 0 1px 0 #555, 0 0 10px rgba(0,0,0,.5);
overflow: hidden;
}
.bm:hover {
-webkit-box-shadow: 0 0 40px #1ab0ff
, 0 0 3px #06bdff
, 0 1px 1px #4ee2ff
, 0 1px 0 #fff;
-moz-box-shadow: 0 0 40px #1ab0ff
, 0 0 3px #06bdff
, 0 1px 1px #4ee2ff
, 0 1px 0 #fff;
}
.bm:hover img {
opacity: 1;
}
.bm img {
width: 200px;
height: 150px;
opacity: .5;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-webkit-transition: opacity 200ms;
-moz-transition: opacity 200ms;
}
.bm p {
margin: 0;
padding: 10px;
width: 100%;
background: rgba(0,0,0,.75);
position: absolute;
left: 0;
color: white;
letter-spacing: 1px;
bottom: -50px;
-webkit-font-smoothing: antialiased;
-webkit-transition: bottom 200ms ease-in;
}
.bm:hover p {
bottom: 0;
}
</style>
EOF
}
#
# Generate bookmark screenshots
#
screenshot_take() {
if [ "${_BM_SCREENSHOT_GET,,}" = 'true' -o ${__p:=0} -eq 1 ]; then
[[ ! -d "${_BM_SCREENSHOT_DIRECTORY}" ]] && { mkdir -p "${_BM_SCREENSHOT_DIRECTORY}" || die "Can't create thumbnail directory." ; }
[[ ! -z "${_BM_CMD_PRE_CAPTURE}" ]] && { local _pre="${_BM_CMD_PRE_CAPTURE//\{FILE\}/${1}}"; _pre="${_pre//\{URL\}/${2}}"; ${_pre} ; }
local _cmd="${_BM_CMD_CAPTURE//\{FILE\}/${1}}"; _cmd="${_cmd//\{URL\}/${2}}";
local _args="${_BM_CMD_CAPTURE_ARGS//\{FILE\}/${1}}"; _args="${_args//\{URL\}/${2}}";
eval ${_cmd} ${_args}
[[ ! -z "${_BM_CMD_POST_CAPTURE}" ]] && { local _post="${_BM_CMD_POST_CAPTURE//\{FILE\}/${1}}"; _post="${_post//\{URL\}/${2}}"; ${_post} ; }
fi
}
picturize() {
if [ -z "${1:-}" ]; then
awk -F'|' '$0 !~ /^[ ]*#/ {print $1,$4;}' "${_BM_BOOKMARK_FILE}" | while read m u; do
[[ ! -f "${_BM_SCREENSHOT_DIRECTORY}/${m}.png" || ${__F:=0} -eq 1 ]] && { screenshot_take "${_BM_SCREENSHOT_DIRECTORY}/${m}.png" "${u}" & }
[[ "${_BM_SCREENSHOT_WAIT,,}" = 'true' ]] && wait
done
else
local _lines="$(search "${@}")"
if [ "${_BM_ASK_BEFORE_OPEN,,}" = 'true' -a ${__O:=0} -eq 0 -a ${__Y:=0} -eq 0 ]; then
if [ $(wc -l <<< "${_lines}") -gt 1 ]; then
read -p"More than one URL found. Open all ? [Y/N] : " -n1 _answer
[[ "${_answer,,}" != 'y' ]] && die "\nUse -O to force the first URL or refine your search"
fi
fi
local _all=''
while read _nl; do
readLines <<< "${_nl}"
if [ "${_BM_OPEN_ALL,,}" = 'true' -o ${__Y:=0} -eq 1 ]; then
IFS='|' read m d a u b <<< "${_nl}"
screenshot_take "${_BM_SCREENSHOT_DIRECTORY}/${m}.png" "${u}" &
else
IFS='|' read m d a u b <<< "${_nl}"
screenshot_take "${_BM_SCREENSHOT_DIRECTORY}/${m}.png" "${u}" &
[[ "${_BM_OPEN_FIRST,,}" = 'true' || ${__O:=0} -eq 1 ]] && exit 0
fi
done <<< "$(echo -e "${_lines}")"
fi
}
bookmark_generator() {
[[ ! -f "${_BM_SCREENSHOT_DIRECTORY}/black-Linen.png" && -f "/usr/share/bm/black-Linen.png" ]] && cp "/usr/share/bm/black-Linen.png" "${_BM_SCREENSHOT_DIRECTORY}/black-Linen.png"
echo "<!DOCTYPE html><html><head><meta charset="UTF-8"><title>bm v${VERSION} : all your bookmarks</title>" > "${1:-${_BM_HTML_FILE}}"
style >> "${1:-${_BM_HTML_FILE}}"
echo "</head><body>" >> "${1:-${_BM_HTML_FILE}}"
# search "${2:-}" | while IFS='|' read m a u T t d; do
awk '$0 !~ /^[ ]*#/' "${_BM_BOOKMARK_FILE}" | while IFS='|' read m d a u T t; do
echo " <div class=bm>
<a href='${u}'><img src='${_BM_SCREENSHOT_DIRECTORY}/${m}.png' alt='${u}' /></a>
<p>${T}<br/><a href='${_BM_SCREENSHOT_DIRECTORY}/${m}.png'>View image</a></p>
</div>" >> "${1:-${_BM_HTML_FILE}}"
done
echo "</body></html>" >> "${1:-${_BM_HTML_FILE}}"
[[ ${__O:=0} -eq 1 ]] && "${_BM_CMD_OPEN}" "${1:-${_BM_HTML_FILE}}"
}
#
# die print message to stderr and exit
#
die() {
echo -e "${@}" >&2
exit 1
}
#
# checkBinaries check the script is able to run and give hints
#
checkBinaries() {
if [ ${#} -ne 0 ]; then
local cmdErr="${@}"
else
local cmdErr="sed awk date iconv cat curl ${_BM_CMD_OPEN} ${_BM_CMD_MD5} column"
fi
set ${cmdErr}
while [ ${#} -ne 0 ]; do
if ! command -v "${1:-}" &>/dev/null; then
echo "command not found: ${1}" >&2
local rc=1
fi
shift
done
[[ ${rc:=0} -ne 0 ]] && die "At least one command is missing. Please install it before using bm."
# Checking sed
local rc=1
[[ ! -f "/tmp/sedtest.$$" ]] && \
echo -n 'toto' > "/tmp/sedtest.$$" && \
sed -i.bak -e 's;^toto$;tata;' "/tmp/sedtest.$$" && \
[[ -f "/tmp/sedtest.$$.bak" ]] && \
grep -q "tata" "/tmp/sedtest.$$" && \
rc=0 && \
rm -f "/tmp/sedtest.$$" "/tmp/sedtest.$$.bak"
[[ ${rc} -ne 0 ]] && die "sed seems to not handle -i argument properly, please check"
}
#
# defineColors generate the variables to use to colorize the output
#
defineColors() {
export BLACK="\e[30m"; export BLACK_LIGHT="\e[90m"; export GRAY_DARK="${BLACK_LIGHT}"
export RED="\e[31m"; export RED_LIGHT="\e[91m"
export GREEN="\e[32m"; export GREEN_LIGHT="\e[92m"
export YELLOW="\e[33m"; export YELLOW_LIGHT="\e[93m"
export BLUE="\e[34m"; export BLUE_LIGHT="\e[94m"
export MAGENTA="\e[35m"; export MAGENTA_LIGHT="\e[95m"
export CYAN="\e[36m"; export CYAN_LIGHT="\e[96m"
export GRAY="\e[37m"; export GRAY_LIGHT="\e[97m"; export WHITE="${GRAY_LIGHT}"
export RESET="\e[0m"
export BOLD="\e[1m"; export BOLD_RESET="\e[21m"
export DIM="\e[2m"; export DIM_RESET="\e[22m"
export UNDERLINE="\e[4m"; export UNDERLINE_RESET="\e[24m"
export INVERT="\e[7m"; export INVERT_RESET="\e[27m"
if [ ! -z "${1:-}" ]; then
echo "Use the following colors to fit your needs :"
(
echo -e "${RESET}${BLACK}BLACK${RESET} - ${BLACK_LIGHT}BLACK_LIGHT${RESET} - ${BOLD}${BLACK}BOLD BLACK${RESET} - ${DIM}${BLACK}DIM BLACK${RESET}"
echo -e "${RESET}${RED}RED${RESET} - ${RED_LIGHT}RED_LIGHT${RESET} - ${BOLD}${RED}BOLD RED${RESET} - ${DIM}${RED}DIM RED${RESET}"
echo -e "${RESET}${GREEN}GREEN${RESET} - ${GREEN_LIGHT}GREEN_LIGHT${RESET} - ${BOLD}${GREEN}BOLD GREEN${RESET} - ${DIM}${GREEN}DIM GREEN${RESET}"
echo -e "${RESET}${YELLOW}YELLOW${RESET} - ${YELLOW_LIGHT}YELLOW_LIGHT${RESET} - ${BOLD}${YELLOW}BOLD YELLOW${RESET} - ${DIM}${YELLOW}DIM YELLOW${RESET}"
echo -e "${RESET}${BLUE}BLUE${RESET} - ${BLUE_LIGHT}BLUE_LIGHT${RESET} - ${BOLD}${BLUE}BOLD BLUE${RESET} - ${DIM}${BLUE}DIM BLUE${RESET}"
echo -e "${RESET}${MAGENTA}MAGENTA${RESET} - ${MAGENTA_LIGHT}MAGENTA_LIGHT${RESET} - ${BOLD}${MAGENTA}BOLD MAGENTA${RESET} - ${DIM}${MAGENTA}DIM MAGENTA${RESET}"
echo -e "${RESET}${CYAN}CYAN${RESET} - ${CYAN_LIGHT}CYAN_LIGHT${RESET} - ${BOLD}${CYAN}BOLD CYAN${RESET} - ${DIM}${CYAN}DIM CYAN${RESET}"
echo -e "${RESET}${GRAY}GRAY${RESET} - ${GRAY_LIGHT}GRAY_LIGHT${RESET} - ${BOLD}${GRAY}BOLD GRAY${RESET} - ${DIM}${GRAY}DIM GRAY${RESET}"
echo -e "${RESET}${GRAY_DARK}GRAY_DARK${RESET} - ${WHITE}WHITE${RESET}"
) | column -t
echo -e "You could also use the ${UNDERLINE}UNDERLINE, the ${INVERT}INVERT and the ${RESET}RESET variable. INVERT_RESET and UNDERLINE_RESET also available"
exit 0
fi
}
##############################################################################
# MAIN
##############################################################################
##################### TRANSITIONNAL ############################
_regex='^(help|version|tags|ls|list|search|open|add|view|stats|statistics|clear|colors)$'
if [[ ${1:-} =~ ${_regex} ]]; then
case "$1" in
tags) __L=1 ;;
ls|list) __l=1 ;;
search) __s=1; __search="${@:2}" ;;
open) __o=1; __open="${@:2}";;
add) __a=1; __url="${2:-}"; __T="${3:-}"; __t="${4:-}"; __A="${5:-}";;
view) __r=1; __search="${@:2}" ;;
stats|statistics) __S=1 ;;
clear) die "This now a deprecated feature. Use -d instead." ;;
colors) __C=1;;
help) usage 1;exit 0;;
version) echo -n "${0} v${VERSION}";exit 0;;
esac
else
# -c config file
# -C colors print ==> exit
# -b bookmark file
# -d delete
# -D deletefile if set override _BM_DELETE_TO_FILE to true
# -w working dir
# -a add url =/= -l, -s, -S, -O, -o, -x, -X, -g, -C
# -A Accelerator
# -T title
# -t tags
# -s search
# -S stats
# -l list all url
# -o open
# -O open first
# -x copy to clipboard
# -X copy first URL
# -h help
# -H more help
# -v version
# -V more version ?
# -g generate html file
# -G use this file
# -g -g generate 1 file per tags
# used : AaBbCcDdE-F-GgHh-i----Ll--NnOoPp-q-rSsTt--Vv-wXxY--z----------
# available : ---------e-f----I-JjKk--Mm------Q-R-----Uu--W----yZ-0123456789
while getopts ":a:A:b:c:d:G:o:P:q:r:s:t:T:w:x:BCDEFghHilLnNOpPSvVXYz" option; do
case ${option} in
a) __a=1; __url="${OPTARG}";; # Add url to bookmark
A) __A="${OPTARG}";; # AcceleratoR
b) __b="${OPTARG}";; # Bookmark file
B) __B=1;; # Don't load the default config file
c) __c="${OPTARG}";; # Config file
C) __C=1;; # Print color table
d) __d=1; __del="${OPTARG}";; # Config file
D) __D=1;; # Print color table
E) __E=1;; # Open the bm.bm file with the $EDITOR
F) __F=1;; # Force the add or delete or picture
g) (( __g++ ));; # generate html file(s)
G) __G=1; __file="${OPTARG}";; # Generate this file (only for g=1)
h|H) usage; exit 0;; # Help
i) __i=1;; # Ignore case when searching
l) __l=1;; # List all bookmarks
L) __L=1;; # List all tags
n) __n=1;; # sort by date
N) __N=1;; # sort by date (reverse)
o) __o=1; __open="${OPTARG}";; # Open
O) __O=1;; # Open First
p) __p=1;; # Take a screenshot
P) __P=1; __search="${OPTARG}";; # Take all screenshot
q) __q=1; __search="${OPTARG}";; # Search
r) __r=1; __search="${OPTARG}";; # Search
s) __s=1; __search="${OPTARG}";; # Search
S) __S=1;; # Print Statistics
t) __t="${OPTARG}";; # tags for a URL
T) __T="${OPTARG}";; # Title for a URL
v|V) echo -n "${0} v${VERSION}"; [[ "${option}" = 'V' ]] && echo -n " [commit: ${RELEASE}]"; echo ''; exit 0;;
w) __w="${OPTARG}";; # Working directory
x) __x=1; __copy="${OPTARG}";; # Copy
X) __X=1;; # Copy First
Y) __Y=1;; # Open/copy All
z) __z=1;; # Alternative print listing
:) echo "Missing argument for '-${OPTARG}'" >&2 ; exit 1 ;;
?) echo "Argument unknown '-${OPTARG}'" >&2 ; exit 1 ;; # usage;;
*) echo "Argument unknown '-${option}'" >&2 ; exit 1 ;; # usage;;
esac
done
fi
# Parsing args is done, Starting to work, so check if binaries are here
checkBinaries
# defineColors MUST be called before the config() or _BM_PRINT_LINE will be in trouble.
defineColors
# Before loading config, checking if working dir exist...
if [ ! -z "${__w:=}" -a ! -d "${__w}" ]; then
die "Working directory '${__w}' doesn't exist !" >&2
fi
# Loading config
config "${__c}"
[[ ! -z "${__b:=}" ]] && export _BM_BOOKMARK_FILE="${__b}"
# Following config, we maybe not have to check the capture tool
[[ ${_BM_CMD_CAPTURE_CHECK} ]] && checkBinaries "${_BM_CMD_CAPTURE}"
# If no bookmark file exist, create one if allowed
if [ ! -f "${_BM_BOOKMARK_FILE}" -a "${_BM_CREATE_BOOKMARK_FILE,,}" = 'true' ]; then
# Remember fields : 1=md5, 2=date, 2=accel, 3=url, 4=title, 5=tags
echo "eef521de8df447ad392dbace16cf2edc|$(date '+%FT%TZ')|:bm|https://github.com/The-Repo-Club/repomenu-extra/|Download link for repomenu-extra|default,shell,scripts" >> "${_BM_BOOKMARK_FILE}"
fi
# Starting to work with args. If none probably list...
[[ ${#} -eq 0 && "${_BM_NO_ARGS_FORCE_HELP,,}" = 'true' ]] && { usage ; exit; }
# Only one action at a time
if [ $(( ${__a:=0} + ${__C:=0} + ${__d:=0} + ${__E:=0} + ${__g:=0} + ${__l:=0} + ${__L:=0} + ${__o:=0} + ${__P:=0} + ${__q:=0} + ${__r:=0} + ${__s:=0} + ${__S:=0} + ${__x:=0} )) -gt 1 ]; then
echo "You have to choose between -a, -C, -d, -E, -g, -l, -L, -o, -P, -q, -r, -s, -S, -x" >&2
echo "Use -h for help" >&2
exit 0
fi
if [ $(( ${__O:=0} + ${__Y:=0} + ${__X:=0} )) -gt 1 ]; then
echo "You have to choose between -O, -X, -Y" >&2
echo "Use -h for help" >&2
exit 0
fi
# Executing actions
[[ ${__a} -eq 1 ]] && { saveUrl ; exit ; }
[[ ${__C} -eq 1 ]] && { defineColors 1 ; exit ; }
[[ ${__d} -eq 1 ]] && { delete_bookmark "${__del}"; exit ; }
[[ ${__g} -ge 1 ]] && { bookmark_generator "${__file:=}" ''; exit ; }
[[ ${__l} -eq 1 ]] && { search ; exit; }
[[ ${__L} -eq 1 ]] && { list_tags ; exit; }
[[ ${__o} -eq 1 ]] && { open_bookmark "${__open}" ; exit; }
[[ ${__P} -eq 1 ]] && { picturize "${__search}" ; exit; }
[[ ${__r} -eq 1 ]] && { recorded_picture "${__search}" ; exit; }
[[ ${__q} -eq 1 ]] && { download_title "${__search}" ; exit; }
[[ ${__s} -eq 1 ]] && { search_bookmarks "${__search}" ; exit; }
[[ ${__S} -eq 1 ]] && { stats ; exit; }
[[ ${__x} -eq 1 ]] && { copy_bookmark "${__copy}" ; exit; }
[[ ${__E} -eq 1 ]] && { edit_bookmark ; exit; }
search
# $Format:%cn @ %cD$ : $Id$

37
.local/bin/rofi/bm_add Executable file
View File

@ -0,0 +1,37 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# bm_add
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Fri 09 December 2022, 06:43:52 AM [GMT]
#Modified:
# Fri 09 December 2022, 08:03:21 AM [GMT]
#
#Description:
# <Todo>
#
#Dependencies:
# bm
#
result() {
echo -n | rofi -dmenu -p "${1:-Add a bookmark:...}" -mesg "+ Add a Bookmark"
}
url="$(result "URL:")"
if [ -z "$url" ]; then
exit
fi
title="$(result "Title:")"
tags="$(result "Tags (comma delimited):")"
bm -w "$HOME/.config/rofi/bookmarks/" -a "$url" -T "$title" -t "$tags"

58
.local/bin/rofi/bm_remove Executable file
View File

@ -0,0 +1,58 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# bm_remove
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Fri 09 December 2022, 06:43:41 AM [GMT]
#Modified:
# Fri 14 July 2023, 11:04:29 PM [GMT+1]
#
#Description:
# <Todo>
#
#Dependencies:
# bm
#
# shellcheck disable=all
bmFile="$HOME/.config/rofi/bookmarks/bm.bm"
if [[ ! -f $bmFile ]]; then
printf "%s\n" "No current bookmark file found.";
exit
fi
declare -A bmarray;
while IFS=\| read -r md5 date accel url title tags;
do
bookmark="$title-$url-$tags";
bmarray["$bookmark"]="$url";
done < "$bmFile"
function load() {
while IFS=\| read -r md5 date accel url title tags;
do
bookmark="$title-$url-$tags";
printf "%s\n" "$bookmark";
done < "$bmFile"
}
choice=$(load | rofi -dmenu i -p "${1:-Remove a bookmark:...}" -mesg "- Remove a Bookmark")
LOOPSETTING="true"
while [ -n "$LOOPSETTING" ]; do
[ -n "$choice" ] || exit
unset LOOPSETTING
case "$choice" in
*) bm -w "$HOME/.config/rofi/bookmarks/" -d "${bmarray[$choice]}" -D;;
esac
done

54
.local/bin/rofi/bm_viewer Executable file
View File

@ -0,0 +1,54 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# bm_viewer
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Fri 09 December 2022, 06:43:30 AM [GMT]
#Modified:
# Fri 14 July 2023, 11:04:22 PM [GMT+1]
#
#Description:
# <Todo>
#
#Dependencies:
# bm
#
# shellcheck disable=all
bmFile="$HOME/.config/rofi/bookmarks/bm.bm"
if [[ ! -f $bmFile ]]; then
printf "%s\n" "No current bookmark file found.";
exit
fi
declare -A bmarray;
function load() {
printf "Add Bookmark\nRemove Bookmark\n"
while IFS=\| read -r md5 date accel url title tags;
do
bookmark="$title-$url-$tags";
printf "%s\n" "$title";
done < "$bmFile"
}
choice=$(load | rofi -dmenu -p "${1:-Select a bookmark:...}" -mesg "+ Add Bookmark - Remove Bookmark Select Bookmarks")
LOOPSETTING="true"
while [ -n "$LOOPSETTING" ]; do
[ -n "$choice" ] || exit
unset LOOPSETTING
case "$choice" in
Add*) bm_add ;;
Remove*) bm_remove ;;
*) bm -w "$HOME/.config/rofi/bookmarks/" -o "${bmarray[$choice]}";;
esac
done

25
.local/bin/rofi/clipmenu_run Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# clipmenu_run
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Wed 07 December 2022, 11:01:52 PM [GMT]
#Modified:
# Sun 06 August 2023, 11:39:26 AM [GMT+1]
#
#Description:
# <Todo>
#
#Dependencies:
# <None>
#
# shellcheck disable=all
clipmenu -p ClipMenu -mesg "Copy from clipboard."

27
.local/bin/rofi/menu Executable file
View File

@ -0,0 +1,27 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# menu
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Wed 10 March 2021, 12:34:47 PM [GMT+1]
#Modified:
# Thu 08 December 2022, 07:37:35 AM [GMT]
#
#Description:
# <Todo>
#
#Dependencies:
# rofi
#
# shellcheck disable=all
programs=$(compgen -c | sort -u | tail -n +9)
cmd=$(echo -e "$programs" | rofi -dmenu -p "Programs" -mesg "Select a program.")
exec $cmd

64
.local/bin/rofi/music Executable file
View File

@ -0,0 +1,64 @@
#!/usr/bin/env bash
# -*-coding:utf-8 -*-
# Auto updated?
# Yes
#File :
# music
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
# Created:
# Wed 10 March 2021, 12:34:47 PM [GMT]
# Modified:
# Sat 05 August 2023, 11:57:57 PM [GMT+1]
#
# Description:
# <Todo>
#
# shellcheck disable=all
MUSICPLAYER="mplayer"
CURRENT_SONG=$(lsof -c "$MUSICPLAYER" | grep -F ".mp3" | awk -F"/" '{ print $NF; }' | cut -d'.' -f1)
PLAYING_MSG="Currently Playing :: ${CURRENT_SONG}"
MUSICDIR=$HOME/Music
for Song in "$MUSICDIR/"*; do
if [ -f "$Song" ]; then
Name=${Song##*/}
case $Name in
*.mp3 | *.flac | *.wav | .ogg)
options+=${Song##*/}$'\n'
;;
esac
fi
done
CHOICE=$(rofi -dmenu -no-custom -p "Muisc Player" -kb-custom-1 "Alt+Return" -mesg "${PLAYING_MSG}" "$@" <<ENDOPTS
${options::-1}
ENDOPTS
)
ret=$?
if [[ $ret -eq 0 ]]; then
case $CHOICE in
*.mp3 | *.flac | *.wav | *.ogg)
if pgrep -f "$MUSICPLAYER" >/dev/null; then
killall -9 "$MUSICPLAYER"
fi
if [[ $MUSICPLAYER == "mplayer" ]]; then
$MUSICPLAYER -ao alsa "$MUSICDIR/$CHOICE" >> /dev/null &
else
$MUSICPLAYER "$MUSICDIR/$CHOICE" &
fi
;;
*)
echo "Program terminated." && exit
;;
esac
elif [[ $ret -gt 1 ]]; then
if [[ $ret -eq 10 ]]; then
killall -9 "$MUSICPLAYER"
fi
fi

897
.local/bin/rofi/passmenu Executable file
View File

@ -0,0 +1,897 @@
#!/usr/bin/env bash
# passmenu
# (c) 2022 Wayne Wesley <wayne6324@gmail.com>
basecommand="$0"
# set default settings
_rofi () {
rofi -no-auto-select -i "$@"
}
_pwgen () {
pwgen -y "$@"
}
_image_viewer () {
feh -
}
_clip_in_primary() {
xclip
}
_clip_in_clipboard() {
xclip -selection clipboard
}
_clip_out_primary() {
xclip -o
}
_clip_out_clipboard() {
xclip --selection clipboard -o
}
config_dir=${XDG_CONFIG_HOME:-$HOME/.config}
cache_dir=${XDG_CACHE_HOME:-$HOME/.cache}
# We expect to find these fields in pass(1)'s output
URL_field='url'
USERNAME_field='user'
AUTOTYPE_field='autotype'
OTPmethod_field='otp_method'
default_autotype="user :tab pass"
delay=2
wait=0.2
xdotool_delay=12
default_do='menu' # menu, copyPass, typeUser, typePass, copyUser, copyUrl, viewEntry, typeMenu, actionMenu, copyMenu, openUrl
auto_enter='false'
notify='false'
help_color=""
clip=primary
clip_clear=45
default_user="${ROFI_PASS_DEFAULT_USER-$(whoami)}"
default_user2=john_doe
password_length=12
fix_layout=false
# default shortcuts
autotype="Alt+1"
type_user="Alt+2"
type_pass="Alt+3"
open_url="Alt+4"
copy_name="Alt+u"
copy_url="Alt+l"
copy_pass="Alt+p"
show="Alt+o"
copy_menu="Alt+c"
action_menu="Alt+a"
type_menu="Alt+t"
help="Alt+h"
switch="Alt+x"
insert_pass="Alt+n"
qrcode="Alt+q"
previous_root="Shift+Left"
next_root="Shift+Right"
# Safe permissions
umask 077
has_qrencode() {
command -v qrencode >/dev/null 2>&1
}
listgpg () {
mapfile -d '' pw_list < <(find -L . -name '*.gpg' -print0)
pw_list=("${pw_list[@]#./}")
printf '%s\n' "${pw_list[@]}" | sort -n
}
# get all password files and output as newline-delimited text
list_passwords() {
cd "${root}" || exit
mapfile -t pw_list < <(listgpg)
printf '%s\n' "${pw_list[@]%.gpg}" | sort -n
}
doClip () {
case "$clip" in
"primary") _clip_in_primary ;;
"clipboard") _clip_in_clipboard ;;
"both") _clip_in_primary; _clip_out_primary | _clip_in_clipboard;;
esac
}
checkIfPass () {
printf '%s\n' "${root}: $selected_password" >| "$cache_dir/passmenu/last_used"
}
autopass () {
x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
xset r off
rm -f "$cache_dir/passmenu/last_used"
printf '%s\n' "${root}: $selected_password" > "$cache_dir/passmenu/last_used"
for word in ${stuff["$AUTOTYPE_field"]}; do
case "$word" in
":tab") xdotool key Tab;;
":space") xdotool key space;;
":delay") sleep "${delay}";;
":enter") xdotool key Return;;
":otp") printf '%s' "$(generateOTP)" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -;;
"pass") printf '%s' "${password}" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -;;
"path") printf '%s' "${selected_password}" | rev | cut -d'/' -f1 | rev | xdotool type --clearmodifiers --file -;;
*) printf '%s' "${stuff[${word}]}" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -;;
esac
done
if [[ ${auto_enter} == "true" ]]; then
xdotool key Return
fi
xset r "$x_repeat_enabled"
unset x_repeat_enabled
clearUp
}
generateQrCode() {
has_qrencode
if [[ $? -eq "1" ]]; then
printf '%s\n' "qrencode not found" | _rofi -dmenu
exit_code=$?
if [[ $exit_code -eq "1" ]]; then
exit
else
"${basecommand}"
fi
fi
checkIfPass
pass "$selected_password" | head -n 1 | qrencode -d 300 -v 8 -l H -o - | _image_viewer
if [[ $? -eq "1" ]]; then
printf '%s\n' "" | _rofi -dmenu -mesg "Image viewer not defined or cannot read from pipe"
exit_value=$?
if [[ $exit_value -eq "1" ]]; then
exit
else
"${basecommand}"
fi
fi
clearUp
}
openURL () {
checkIfPass
$BROWSER "$(PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep "${URL_field}: " | gawk '{sub(/:/,"")}{print $2}1' | head -1)"; exit;
clearUp
}
typeUser () {
checkIfPass
x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
xset r off
printf '%s' "${stuff[${USERNAME_field}]}" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -
xset r "$x_repeat_enabled"
unset x_repeat_enabled
clearUp
}
typePass () {
checkIfPass
x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
xset r off
printf '%s' "${password}" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -
if [[ $notify == "true" ]]; then
if [[ "${stuff[notify]}" == "false" ]]; then
:
else
notify-send "passmenu" "finished typing password";
fi
elif [[ $notify == "false" ]]; then
if [[ "${stuff[notify]}" == "true" ]]; then
notify-send "passmenu" "finished typing password";
else
:
fi
fi
xset r "$x_repeat_enabled"
unset x_repeat_enabled
clearUp
}
typeField () {
checkIfPass
local to_type
x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
xset r off
case $typefield in
"OTP") to_type="$(generateOTP)" ;;
*) to_type="${stuff[${typefield}]}" ;;
esac
printf '%s' "$to_type" | xdotool type --delay ${xdotool_delay} --clearmodifiers --file -
xset r "$x_repeat_enabled"
unset x_repeat_enabled
unset to_type
clearUp
}
generateOTP () {
checkIfPass
# First, we check if there is a non-conventional OTP command in the pass file
if PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep -q "${OTPmethod_field}: "; then
# We execute the commands after otp_method: AS-IS
bash -c "$(PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep "${OTPmethod_field}: " | cut -d' ' -f2-)"
else
# If there is no method defined, fallback to pass-otp
PASSWORD_STORE_DIR="${root}" pass otp "$selected_password"
fi
clearUp
}
copyUser () {
checkIfPass
printf '%s' "${stuff[${USERNAME_field}]}" | doClip
clearUp
}
copyField () {
checkIfPass
printf '%s' "${stuff[${copyfield}]}" | doClip
clearUp
}
copyURL () {
checkIfPass
printf '%s' "${stuff[${URL_field}]}" | doClip
clearUp
}
copyPass () {
checkIfPass
printf '%s' "$password" | doClip
if [[ $notify == "true" ]]; then
notify-send "passmenu" "Copied Password\\nClearing in $clip_clear seconds"
fi
if [[ $notify == "true" ]]; then
(sleep $clip_clear; printf '%s' "" | _clip_in_primary; printf '%s' "" | _clip_in_clipboard | notify-send "passmenu" "Clipboard cleared") &
elif [[ $notify == "false" ]]; then
(sleep $clip_clear; printf '%s' "" | _clip_in_primary; printf '%s' "" | _clip_in_clipboard) &
fi
}
viewEntry () {
checkIfPass
showEntry "${selected_password}"
}
generatePass () {
askmenu_content=(
"Yes"
"No"
)
askGenMenu=$(printf '%s\n' "${askmenu_content[@]}" | _rofi -dmenu -p "Generate new Password for ${selected_password}? > ")
askgen_exit=$?
if [[ $askgen_exit -eq 1 ]]; then
exit
fi
if [[ $askGenMenu == "Yes" ]]; then
true
elif [[ $askGenMenu == "No" ]]; then
actionMenu
fi
checkIfPass
symbols_content=(
"0 Cancel"
"1 Yes"
"2 No"
)
symbols=$(printf '%s\n' "${symbols_content[@]}" | _rofi -dmenu -p "Use Symbols? > ")
symbols_val=$?
if [[ $symbols_val -eq 1 ]]; then
exit
fi
if [[ $symbols == "0 Cancel" ]]; then
mainMenu;
elif [[ $symbols == "1 Yes" ]]; then
symbols="";
elif [[ $symbols == "2 No" ]]; then
symbols="-n";
fi
HELP="<span color='$help_color'>Enter Number or hit Enter to use default length</span>"
length=$(printf '%s' "" | _rofi -dmenu -mesg "${HELP}" -p "Password length? (Default: ${password_length}) > ")
length_exit=$?
if [[ $length_exit -eq 1 ]]; then
exit
fi
if [[ $length == "" ]]; then
PASSWORD_STORE_DIR="${root}" pass generate ${symbols} -i "$selected_password" "${password_length}" > /dev/null;
else
PASSWORD_STORE_DIR="${root}" pass generate ${symbols} -i "$selected_password" "${length}" > /dev/null;
fi
}
# main Menu
mainMenu () {
if [[ $1 == "--bmarks" ]]; then
selected_password="$(list_passwords 2>/dev/null \
| _rofi -mesg "Bookmarks Mode. ${switch} to switch" \
-dmenu \
-kb-custom-10 "${switch}" \
-select "$entry" \
-p "passmenu > ")"
rofi_exit=$?
if [[ $rofi_exit -eq 1 ]]; then
exit
elif [[ $rofi_exit -eq 19 ]]; then
${basecommand}
elif [[ $rofi_exit -eq 0 ]]; then
openURL
fi
else
unset selected_password
args=( -dmenu
-kb-custom-1 "${autotype}"
-kb-custom-2 "${type_user}"
-kb-custom-3 "${type_pass}"
-kb-custom-4 "${open_url}"
-kb-custom-5 "${copy_name}"
-kb-custom-6 "${copy_pass}"
-kb-custom-7 "${show}"
-kb-custom-8 "${copy_url}"
-kb-custom-9 "${type_menu}"
-kb-custom-10 "${previous_root}"
-kb-custom-11 "${next_root}"
-kb-custom-14 "${action_menu}"
-kb-custom-15 "${copy_menu}"
-kb-custom-16 "${help}"
-kb-custom-17 "${switch}"
-kb-custom-18 "${insert_pass}"
-kb-custom-19 "${qrcode}"
)
args+=( -kb-mode-previous "" # These keyboard shortcut options are needed, because
-kb-mode-next "" # Shift+<Left|Right> are otherwise taken by rofi.
-select "$entry"
-mesg "PW Store: ${root}"
-p "passmenu > " )
selected_password="$(list_passwords 2>/dev/null | _rofi "${args[@]}")"
rofi_exit=$?
if [[ $rofi_exit -eq 1 ]]; then
exit
fi
# Actions based on exit code, which do not need the entry.
# The exit code for -kb-custom-X is X+9.
case "${rofi_exit}" in
19) roots_index=$(( (roots_index-1+roots_length) % roots_length)); root=${roots[$roots_index]}; mainMenu; return;;
20) roots_index=$(( (roots_index+1) % roots_length)); root=${roots[$roots_index]}; mainMenu; return;;
25) helpMenu; return;;
26) ${basecommand} --bmarks; return;;
esac
mapfile -t password_temp < <(PASSWORD_STORE_DIR="${root}" pass show "$selected_password")
password=${password_temp[0]}
if [[ ${password} == "#FILE="* ]]; then
pass_file="${password#*=}"
mapfile -t password_temp2 < <(PASSWORD_STORE_DIR="${root}" pass show "${pass_file}")
password=${password_temp2[0]}
fi
fields=$(printf '%s\n' "${password_temp[@]:1}" | awk '$1 ~ /:$/ || /otpauth:\/\// {$1=$1;print}')
declare -A stuff
stuff["pass"]=${password}
if [[ -n $fields ]]; then
while read -r LINE; do
unset _id _val
case "$LINE" in
"otpauth://"*|"${OTPmethod_field}"*)
_id="OTP"
_val=""
;;
*)
_id="${LINE%%: *}"
_val="${LINE#* }"
;;
esac
if [[ -n "$_id" ]]; then
stuff["${_id}"]=${_val}
fi
done < <(printf '%s\n' "${fields}")
if test "${stuff['autotype']+autotype}"; then
:
else
stuff["autotype"]="${USERNAME_field} :tab pass"
fi
fi
fi
if [[ -z "${stuff["${AUTOTYPE_field}"]}" ]]; then
if [[ -n $default_autotype ]]; then
stuff["${AUTOTYPE_field}"]="${default_autotype}"
fi
fi
if [[ -z "${stuff["${USERNAME_field}"]}" ]]; then
if [[ -n $default_user ]]; then
if [[ "$default_user" == ":filename" ]]; then
stuff["${USERNAME_field}"]="$(basename "$selected_password")"
else
stuff["${USERNAME_field}"]="${default_user}"
fi
fi
fi
pass_content="$(for key in "${!stuff[@]}"; do printf '%s\n' "${key}: ${stuff[$key]}"; done)"
# actions based on keypresses
# The exit code for -kb-custom-X is X+9.
case "${rofi_exit}" in
0) typeMenu;;
10) sleep $wait; autopass;;
11) sleep $wait; typeUser;;
12) sleep $wait; typePass;;
13) openURL;;
14) copyUser;;
15) copyPass;;
16) viewEntry;;
17) copyURL;;
18) default_do="menu" typeMenu;;
23) actionMenu;;
24) copyMenu;;
27) insertPass;;
28) generateQrCode;;
esac
clearUp
}
clearUp () {
password=''
selected_password=''
unset stuff
unset password
unset selected_password
unset password_temp
unset stuff
}
helpMenu () {
_rofi -dmenu -mesg "Hint: All hotkeys are configurable in config file" -p "Help > " <<- EOM
${autotype}: Autotype
${type_user}: Type Username
${type_pass}: Type Password
${qrcode}: Generate and display qrcode
---
${copy_name}: Copy Username
${copy_pass}: Copy Password
${copy_url}: Copy URL
${open_url}: Open URL
${copy_menu}: Copy Custom Field
---
${action_menu}: Edit, Move, Delete, Re-generate Submenu
${show}: Show Password File
${insert_pass}: Insert new Pass Entry
${switch}: Switch Pass/Bookmark Mode
---
${previous_root}: Switch to previous password store (--root)
${next_root}: Switch to next password store (--root)
EOM
help_val=$?
if [[ $help_val -eq 1 ]]; then
exit;
else
unset helptext; mainMenu;
fi
}
typeMenu () {
if [[ -n $default_do ]]; then
if [[ $default_do == "menu" ]]; then
checkIfPass
local -a keys=("${!stuff[@]}")
keys=("${keys[@]/$AUTOTYPE_field}")
typefield=$({ printf '%s' "${AUTOTYPE_field}" ; printf '%s\n' "${keys[@]}" | sort; } | _rofi -dmenu -p "Choose Field to type > ")
typefield_exit=$?
if [[ $typefield_exit -eq 1 ]]; then
exit
fi
case "$typefield" in
'') exit;;
'pass') sleep $wait; typePass;;
"${AUTOTYPE_field}") sleep $wait; autopass;;
*) sleep $wait; typeField
esac
clearUp
elif [[ $default_do == "${AUTOTYPE_field}" ]]; then
sleep $wait; autopass
else
${default_do}
fi
fi
}
copyMenu () {
checkIfPass
copyfield=$(printf '%s\n' "${!stuff[@]}" | sort | _rofi -dmenu -p "Choose Field to copy > ")
val=$?
if [[ $val -eq 1 ]]; then
exit;
fi
if [[ $copyfield == "pass" ]]; then
copyPass;
else
copyField
fi
clearUp
}
actionMenu () {
checkIfPass
action_content=("< Return"
"---"
"1 Move Password File"
"2 Copy Password File"
"3 Delete Password File"
"4 Edit Password File"
"5 Generate New Password"
)
action=$(printf '%s\n' "${action_content[@]}" | _rofi -dmenu -p "Choose Action > ")
if [[ ${action} == "1 Move Password File" ]]; then
manageEntry move;
elif [[ ${action} == "3 Delete Password File" ]]; then
manageEntry delete;
elif [[ ${action} == "2 Copy Password File" ]]; then
manageEntry copy;
elif [[ ${action} == "4 Edit Password File" ]]; then
manageEntry edit;
elif [[ ${action} == "5 Generate New Password" ]]; then
generatePass;
elif [[ ${action} == "< Return" ]]; then
mainMenu;
elif [[ ${action} == "" ]]; then
exit
fi
}
showEntry () {
if [[ -z $pass_content ]]; then
pass_temp=$(PASSWORD_STORE_DIR="${root}" pass show "$selected_password")
password="${pass_temp%%$'\n'*}"
pass_key_value=$(printf '%s\n' "${pass_temp}" | tail -n+2 | grep ': ')
declare -A stuff
while read -r LINE; do
_id="${LINE%%: *}"
_val="${LINE#* }"
stuff["${_id}"]=${_val}
done < <(printf '%s\n' "${pass_key_value}")
stuff["pass"]=${password}
if test "${stuff['autotype']+autotype}"; then
:
else
stuff["autotype"]="${USERNAME_field} :tab pass"
fi
pass_content="$(for key in "${!stuff[@]}"; do printf '%s\n' "${key}: ${stuff[$key]}"; done)"
fi
bla_content=("< Return"
"${pass_content}"
)
bla=$(printf '%s\n' "${bla_content[@]}" | _rofi -dmenu -mesg "Enter: Copy entry to clipboard" -p "> ")
rofi_exit=$?
word=$(printf '%s' "$bla" | gawk -F': ' '{print $1}')
if [[ ${rofi_exit} -eq 1 ]]; then
exit
elif [[ ${rofi_exit} -eq 0 ]]; then
if [[ ${bla} == "< Return" ]]; then
mainMenu
else
if [[ -z $(printf '%s' "${stuff[${word}]}") ]]; then
printf '%s' "$word" | doClip
else
printf '%s' "${stuff[${word}]}" | doClip
fi
if [[ $notify == "true" ]]; then
notify-send "passmenu" "Copied Password\\nClearing in $clip_clear seconds"
fi
if [[ $notify == "true" ]]; then
(sleep $clip_clear; printf '%s' "" | _clip_in_primary; printf '%s' "" | _clip_in_clipboard | notify-send "passmenu" "Clipboard cleared") &
elif [[ $notify == "false" ]]; then
(sleep $clip_clear; printf '%s' "" | _clip_in_primary; printf '%s' "" | _clip_in_clipboard) &
fi
exit
fi
fi
exit
unset stuff
unset password
unset selected_password
unset password_temp
unset stuff
exit
}
manageEntry () {
if [[ "$1" == "edit" ]]; then
EDITOR=$EDITOR PASSWORD_STORE_DIR="${root}" pass edit "${selected_password}"
mainMenu
elif [[ $1 == "move" ]]; then
cd "${root}" || exit
group_array=(*/)
group=$(printf '%s\n' "${group_array[@]%/}" | _rofi -dmenu -p "Choose Group > ")
if [[ $group == "" ]]; then
exit
fi
PASSWORD_STORE_DIR="${root}" pass mv "$selected_password" "${group}"
mainMenu
elif [[ $1 == "copy" ]]; then
cd "${root}" || exit
group_array=(*/)
group=$(printf '%s\n' "${group_array[@]%/}" | _rofi -dmenu -p "Choose Group > ")
if [[ $group == "" ]]; then
exit
else
new_name="$(listgpg | _rofi -dmenu -format 'f' -mesg "Copying to same Group. Please enter a name for the new entry" -p "> ")"
fi
PASSWORD_STORE_DIR="${root}" pass cp "$selected_password" "${group}/${new_name}"
mainMenu
elif [[ "$1" == "delete" ]]; then
HELP="<span color='$help_color'>Selected entry: ${selected_password}</span>"
ask_content=("Yes"
"No"
)
ask=$(printf '%s\n' "${ask_content[@]}" | _rofi -mesg "${HELP}" -dmenu -p "Are You Sure? > ")
if [[ "$ask" == "Yes" ]]; then
PASSWORD_STORE_DIR="${root}" pass rm --force "${selected_password}"
elif [[ "$ask" == "No" ]]; then
mainMenu
elif [[ -z "$ask" ]]; then
exit
fi
else
mainMenu
fi
}
edit_pass() {
if [[ $edit_new_pass == "true" ]]; then
PASSWORD_STORE_DIR="${root}" pass edit "${1}"
fi
}
insertPass () {
url=$(_clip_out_clipboard)
if [[ "${url:0:4}" == "http" ]]; then
domain_name="$(printf '%s\n' "${url}" | awk -F / '{l=split($3,a,"."); print (a[l-1]=="com"?a[l-2] OFS:X) a[l-1] OFS a[l]}' OFS=".")"
help_content="Domain: ${domain_name}
Type name, make sure it is unique"
else
help_content="Hint: Copy URL to clipboard before calling this menu.
Type name, make sure it is unique"
fi
cd "${root}" || exit
group_array=(*/)
grouplist=$(printf '%s\n' "${group_array[@]%/}")
name="$(listgpg | _rofi -dmenu -format 'f' -filter "${domain_name}" -mesg "${help_content}" -p "> ")"
val=$?
if [[ $val -eq 1 ]]; then
exit
fi
user_content=("${default_user2}"
"${USER}"
"${default_user}"
)
user=$(printf '%s\n' "${user_content[@]}" | _rofi -dmenu -mesg "Chose Username or type" -p "> ")
val=$?
if [[ $val -eq 1 ]]; then
exit
fi
group_content=("No Group"
"---"
"${grouplist}"
)
group=$(printf '%s\n' "${group_content[@]}" | _rofi -dmenu -p "Choose Group > ")
val=$?
if [[ $val -eq 1 ]]; then
exit
fi
pw=$(printf '%s' "Generate" | _rofi -dmenu -password -p "Password > " -mesg "Type Password or hit Enter to generate one")
if [[ $pw == "Generate" ]]; then
pw=$(_pwgen "${password_length}")
fi
clear
if [[ "$group" == "No Group" ]]; then
if [[ $url == http* ]]; then
pass_content=("${pw}"
"---"
"${USERNAME_field}: ${user}"
"${URL_field}: ${url}"
)
printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${name}" > /dev/null && edit_pass "${name}"
else
pass_content=("${pw}"
"---"
"${USERNAME_field}: ${user}"
)
printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${name}" > /dev/null && edit_pass "${name}"
fi
else
if [[ $url == http* ]]; then
pass_content=("${pw}"
"---"
"${USERNAME_field}: ${user}"
"${URL_field}: ${url}"
)
printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${group}/${name}" > /dev/null && edit_pass "${group}/${name}"
else
pass_content=("${pw}"
"---"
"${USERNAME_field}: ${user}"
)
printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${group}/${name}" > /dev/null && edit_pass "${group}/${name}"
fi
fi
}
help_msg () {
cat <<'EOF'
Usage:
passmenu [command]
Commands:
--insert insert new entry to password store
--root set custom root directories (colon separated)
--last-used highlight last used item
--show-last show details of last used Entry
--bmarks start in bookmarks mode
passmenu version 1.0.0
EOF
}
get_config_file () {
configs=("$ROFI_PASS_CONFIG"
"$config_dir/rofi/passmenu/config"
"/etc/passmenu.conf")
# return the first config file with a valid path
for config in "${configs[@]}"; do
# '-n' is needed in case ROFI_PASS_CONFIG is not set
if [[ -n "${config}" && -f "${config}" ]]; then
printf "%s" "$config"
return
fi
done
}
main () {
# load config file
config_file="$(get_config_file)"
[[ -n "$config_file" ]] && source "$config_file"
# create tmp dir
if [[ ! -d "$cache_dir/passmenu" ]]; then
mkdir -p "$cache_dir/passmenu"
fi
# fix keyboard layout if enabled in config
if [[ $fix_layout == "true" ]]; then
layout_cmd
fi
# set help color
if [[ $help_color == "" ]]; then
help_color=$(rofi -dump-xresources | grep 'rofi.color.normal' | gawk -F ',' '/,/{gsub(/ /, "", $2); print $2}')
fi
# check for BROWSER variable, use xdg-open as fallback
if [[ -z $BROWSER ]]; then
export BROWSER=xdg-open
fi
# check if alternative root directory was given on commandline
if [[ -r "$cache_dir/passmenu/last_used" ]] && [[ $1 == "--last-used" || $1 == "--show-last" ]]; then
roots=("$(awk -F ': ' '{ print $1 }' "$cache_dir/passmenu/last_used")")
elif [[ -n "$2" && "$1" == "--root" ]]; then
custom_root=true; IFS=: read -r -a roots <<< "$2"
elif [[ -n $root ]]; then
custom_root=true; IFS=: read -r -a roots <<< "${root}"
elif [[ -n ${PASSWORD_STORE_DIR} ]]; then
roots=("${PASSWORD_STORE_DIR}")
else
roots=("$HOME/.password-store")
fi
roots_index=0
roots_length=${#roots[@]}
export root=${roots[$roots_index]}
export PASSWORD_STORE_DIR="${root}"
case $1 in
--insert)
insertPass
;;
--root)
mainMenu
;;
--help)
help_msg
;;
--last-used)
if [[ -r "$cache_dir/passmenu/last_used" ]]; then
entry="$(awk -F ': ' '{ print $2 }' "$cache_dir/passmenu/last_used")"
fi
mainMenu
;;
--show-last)
if [[ -r "$cache_dir/passmenu/last_used" ]]; then
selected_password="$(awk -F ': ' '{ print $2 }' "$cache_dir/passmenu/last_used")" viewEntry
else
mainMenu
fi
;;
--bmarks)
mainMenu --bmarks;
;;
*)
mainMenu
;;
esac
}
main "$@"

263
.local/bin/rofi/powermenu Executable file
View File

@ -0,0 +1,263 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# powermenu
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Wed 07 December 2022, 11:01:52 PM [GMT]
#Modified:
# Sat 02 September 2023, 12:11:51 AM [GMT+1]
#
#Description:
# This script defines just a mode for rofi instead of being a self-contained
# executable that launches rofi by itself. This makes it more flexible than
# running rofi inside this script as now the user can call rofi as one pleases.
# For instance:
#
# rofi -show powermenu -config ~/.config/rofi/powermenu.rasi
#
#Dependencies:
# <None>
#
# shellcheck disable=all
if [ -z "${ROFI_OUTSIDE}" ]; then
echo "run this script in rofi".
exit
fi
set -e
set -u
# All supported choices
all=(shutdown reboot suspend hibernate logout lockscreen)
# By default, show all (i.e., just copy the array)
show=("${all[@]}")
declare -A texts
texts[lockscreen]="lock screen"
texts[logout]="log out"
texts[suspend]="suspend"
texts[hibernate]="hibernate"
texts[reboot]="reboot"
texts[shutdown]="shut down"
declare -A icons
icons[lockscreen]=""
icons[logout]="󰍃"
icons[suspend]="󰒲"
icons[hibernate]="󰋊"
icons[reboot]="󰜉"
icons[shutdown]="󰐥"
icons[cancel]=""
declare -A actions
actions[lockscreen]="loginctl lock-session"
actions[logout]="pkill -KILL -u ${USER}"
actions[suspend]="systemctl suspend"
actions[hibernate]="systemctl hibernate"
actions[reboot]="systemctl reboot"
actions[shutdown]="systemctl poweroff"
# By default, ask for confirmation for actions that are irreversible
confirmations=(reboot shutdown logout)
# By default, no dry run
dryrun=false
showsymbols=true
getuptime() {
state=$(uptime | sed -E 's/^[^,]*up *//; s/mins/minutes/; s/hrs?/hours/;
s/([[:digit:]]+):0?([[:digit:]]+)/\1 hours, \2 minutes/;
s/^1 hours/1 hour/; s/ 1 hours/ 1 hour/;
s/min,/minutes,/; s/ 0 minutes,/ less than a minute,/; s/ 1 minutes/ 1 minute/;
s/ / /; s/, *[[:digit:]]* users?.*//')
}
function check_valid {
option="$1"
shift 1
for entry in "${@}"; do
if [ -z "${actions[$entry]+x}" ]; then
echo "Invalid choice in $option: $entry" >&2
exit 1
fi
done
}
# Parse command-line options
parsed=$(getopt --options=h --longoptions=help,dry-run,confirm:,choices:,choose:,symbols,no-symbols --name "$0" -- "$@")
if [ $? -ne 0 ]; then
echo 'Terminating...' >&2
exit 1
fi
eval set -- "$parsed"
unset parsed
while true; do
case "$1" in
"-h" | "--help")
echo "rofi-power-menu - a power menu mode for Rofi"
echo
echo "Usage: rofi-power-menu [--choices CHOICES] [--confirm CHOICES]"
echo " [--choose CHOICE] [--dry-run] [--symbols|--no-symbols]"
echo
echo "Use with Rofi in script mode. For instance, to ask for shutdown or reboot:"
echo
echo " rofi -show menu -modi \"menu:rofi-power-menu --choices=shutdown/reboot\""
echo
echo "Available options:"
echo " --dry-run Don't perform the selected action but print it to stderr."
echo " --choices CHOICES Show only the selected choices in the given order. Use / "
echo " as the separator. Available choices are lockscreen, logout,"
echo " suspend, hibernate, reboot and shutdown. By default, all"
echo " available choices are shown."
echo " --confirm CHOICES Require confirmation for the gives choices only. Use / as"
echo " the separator. Available choices are lockscreen, logout,"
echo " suspend, hibernate, reboot and shutdown. By default, only"
echo " irreversible actions logout, reboot and shutdown require"
echo " confirmation."
echo " --choose CHOICE Preselect the given choice and only ask for a confirmation"
echo " (if confirmation is set to be requested). It is strongly"
echo " recommended to combine this option with --confirm=CHOICE"
echo " if the choice wouldn't require confirmation by default."
echo " Available choices are lockscreen, logout, suspend,"
echo " hibernate, reboot and shutdown."
echo " --[no-]symbols Show Unicode symbols or not. Requires a font with support"
echo " for the symbols. Use, for instance, fonts from the"
echo " Nerdfonts collection. By default, they are shown"
echo " -h,--help Show this help text."
exit 0
;;
"--dry-run")
dryrun=true
shift 1
;;
"--confirm")
IFS='/' read -ra confirmations <<<"$2"
check_valid "$1" "${confirmations[@]}"
shift 2
;;
"--choices")
IFS='/' read -ra show <<<"$2"
check_valid "$1" "${show[@]}"
shift 2
;;
"--choose")
# Check that the choice is valid
check_valid "$1" "$2"
selectionID="$2"
shift 2
;;
"--symbols")
showsymbols=true
shift 1
;;
"--no-symbols")
showsymbols=false
shift 1
;;
"--")
shift
break
;;
*)
echo "Internal error" >&2
exit 1
;;
esac
done
# Define the messages after parsing the CLI options so that it is possible to
# configure them in the future.
function write_message {
icon="<span font_size=\"medium\">$1</span>"
text="<span font_size=\"medium\">$2</span>"
if [ "$showsymbols" = "true" ]; then
echo -n "\u200e$icon \u2068$text\u2069"
else
echo -n "$text"
fi
}
function print_selection {
echo -e "$1" | $(
read -r -d '' entry
echo "echo $entry"
)
}
declare -A messages
declare -A confirmationMessages
for entry in "${all[@]}"; do
messages[$entry]=$(write_message "${icons[$entry]}" "${texts[$entry]^}")
done
for entry in "${all[@]}"; do
confirmationMessages[$entry]=$(write_message "${icons[$entry]}" "Yes, ${texts[$entry]}")
done
confirmationMessages[cancel]=$(write_message "${icons[cancel]}" "No, cancel")
if [ $# -gt 0 ]; then
# If arguments given, use those as the selection
selection="${*}"
else
# Otherwise, use the CLI passed choice if given
if [ -n "${selectionID+x}" ]; then
selection="${messages[$selectionID]}"
fi
fi
# Don't allow custom entries
echo -e "\0no-custom\x1ftrue"
echo -e "\0markup-rows\x1ftrue"
if [ -z "${selection+x}" ]; then
getuptime
echo -e "\0prompt\x1fPower Menu"
echo -en "\0message\x1fUptime :: ${state^}\n"
for entry in "${show[@]}"; do
echo -e "${messages[$entry]}\0icon\x1f${icons[$entry]}"
done
else
for entry in "${show[@]}"; do
if [ "$selection" = "$(print_selection "${messages[$entry]}")" ]; then
# Check if the selected entry is listed in confirmation requirements
for confirmation in "${confirmations[@]}"; do
if [ "$entry" = "$confirmation" ]; then
# Ask for confirmation
echo -e "\0prompt\x1fAre you sure"
echo -e "${confirmationMessages[$entry]}\0icon\x1f${icons[$entry]}"
echo -e "${confirmationMessages[cancel]}\0icon\x1f${icons[cancel]}"
exit 0
fi
done
# If not, then no confirmation is required, so mark confirmed
selection=$(print_selection "${confirmationMessages[$entry]}")
fi
if [ "$selection" = "$(print_selection "${confirmationMessages[$entry]}")" ]; then
if [ $dryrun = true ]; then
# Tell what would have been done
echo "Selected: $entry" >&2
else
# Perform the action
${actions[$entry]}
fi
exit 0
fi
if [ "$selection" = "$(print_selection "${confirmationMessages[cancel]}")" ]; then
# Do nothing
exit 0
fi
done
# The selection didn't match anything, so raise an error
echo "Invalid selection: $selection" >&2
exit 1
fi

25
.local/bin/rofi/powermenu_run Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# powermenu_run
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Wed 07 December 2022, 11:01:52 PM [GMT]
#Modified:
# Sun 06 August 2023, 11:40:51 AM [GMT+1]
#
#Description:
# <Todo>
#
#Dependencies:
# <None>
#
# shellcheck disable=all
rofi -show powermenu -config ~/.config/rofi/powermenu.rasi

224
.local/bin/rofi/wifimanager Executable file
View File

@ -0,0 +1,224 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# wifimanager
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Wed 07 December 2022, 11:01:26 PM [GMT]
#Modified:
# Mon 16 January 2023, 05:33:28 PM [GMT]
#
#Description:
# <Todo>
#
#Dependencies:
# rofi nmcli(Network Manager) dunst
#
# shellcheck disable=all
if [ -z "${ROFI_OUTSIDE}" ]
then
echo "run this script in rofi".
exit
fi
CACHE_DIR="$HOME/.cache/rofi/network"
[ ! -d $CACHE_DIR ] && mkdir -p "$CACHE_DIR"
station=$(nmcli device | grep "wifi " | awk '{ printf $1 }') # Device Station name
function network_status () {
state=$(nmcli -fields WIFI g | sed -n 2p | xargs) # Wifi enbaled or disabled
connection=$(nmcli connection show --active | grep "wifi" | awk -F "wifi" '{ print $1 }' | sed -e '1{s/[^ ]\+\s*$//}')
}
# Don't allow custom entries
echo -e "\0no-custom\x1ftrue"
function network_options() {
if [[ "$state" == "enabled" ]]; then
if [ -z "$connection" ]; then
echo "-=|> Connect to a Network"
echo "-=|> Connect to a Hidden Network"
connection="N/A"
elif [ ! -z "$connection" ]; then
echo "-=|> Connect to a Network"
echo "-=|> Connect to a Hidden Network"
echo "-=|> Disconnect Current Network"
fi
echo "-=|> Disable Wifi"
elif [[ "$state" =~ "disabled" ]]; then
echo "-=|> Enable Wifi"
fi
}
function main_scrn() { # Main window to be displayed on start
rm $CACHE_DIR/* >/dev/null 2>&1
network_status
network_options
echo -en "\x00prompt\x1fWifi\n"
echo -en "\0message\x1fWIFI Status :: ${state^}\t\tConnected to :: ${connection}\n"
echo -en "-=|> Delete existing connections\n"
echo -en "-=|> Refresh\n"
}
function show_available_networks(){ # Output the list of available Wifi networks
nmcli -f BSSID,SSID device wifi list > "$CACHE_DIR/available_networks"
echo -en "\0message\x1f $(cat "$CACHE_DIR/available_networks" | sed '1!d')\n"
echo "$(cat "$CACHE_DIR/available_networks" | sed '1d')"
echo "-=|> Rescan available networks"
echo "<|=- To Previous Menu"
}
function saved_connections() {
echo "delete_network" > "$CACHE_DIR/delete_connection"
echo -en "\0message\x1f\t\t\t\t\t\t[Enter] - Delete selected connection\n"
echo -en "UUID\t\t\t\t TYPE\tNAME\0nonselectable\x1ftrue\n"
echo -en "\0active\x1f0\n"
nmcli --fields UUID,TYPE,NAME con show | grep wifi
echo "<|=- To Previous Menu"
}
function error_status() {
if [[ "$status" =~ "Connection successfully activated " ]]; then # If connected successfully, then notify and exit
notify-send "Connected to " "$SSID"
exit 0
elif [[ "$status" =~ "Device '$station' successfully activated with " ]]; then # If connected successfully, then notify and exit
notify-send "Network " "$(echo $status | cut -c 6-)"
rm $CACHE_DIR/*
exit 0
else
if [ -f $CACHE_DIR/network_ssid ]; then
echo -en "\0message\x1f! Connection Failed. This is normal if connecting to a hidden network, Try again.\n"
elif [ -f $CACHE_DIR/network_bssid ]; then
echo -en "\0message\x1f! Connection Failed! Check your password.\n"
fi
echo "$status" # If failed to connect, shows the error code and asks for password
echo "<|=- To Previous Menu"
fi
}
function get_ssid() {
echo "hidden" > "$CACHE_DIR/get_ssid"
echo -en "\00prompt\x1fEnter SSID\n"
echo -en "\0message\x1f# Type your network SSID (Network Name).\n"
echo "<|=- To Previous Menu"
}
function get_password() {
echo -en "\00prompt\x1fPassword\n"
echo -en "\0message\x1f# Type your network security passphrase here.\n"
echo "<|=- To Previous Menu"
}
function restore_view() {
if [ -f $CACHE_DIR/delete_connection ]; then
saved_connections
elif [ -f $CACHE_DIR/available_networks ]; then
show_available_networks
elif [ -f $CACHE_DIR/network_selected ]; then
show_available_networks
elif [ -f $CACHE_DIR/get_ssid ]; then
get_ssid
elif [ -f $CACHE_DIR/network_bssid ] || [ -f $CACHE_DIR/network_ssid ]; then
get_password
else
main_scrn
fi
}
function show_previous_menu() {
if [ -f $CACHE_DIR/network_bssid ]; then
rm $CACHE_DIR/network_bssid
show_available_networks
elif [ -f $CACHE_DIR/network_ssid ]; then
rm $CACHE_DIR/network_ssid
get_ssid
else
main_scrn
fi
}
if [[ "${ROFI_RETV}" == "0" ]]; then
main_scrn
elif [[ "${ROFI_RETV}" == "1" ]]; then
if [[ "$@" == "<|=- To Previous Menu" ]]; then
show_previous_menu
elif [[ "$@" == "-=|> Refresh" ]]; then
main_scrn
elif [[ "$@" == "-=|> Disable Wifi" ]]; then
nmcli radio wifi off
restore_view
elif [[ "$@" == "-=|> Enable Wifi" ]]; then
nmcli radio wifi on
restore_view
elif [[ "$@" == "-=|> Connect to a Network" ]]; then
show_available_networks
elif [[ "$@" == "-=|> Connect to a Hidden Network" ]]; then
get_ssid
elif [[ "$@" == "-=|> Disconnect Current Network" ]]; then # Disconnect any connected network
con_uuid=$(nmcli connection show --active | grep "wifi" | awk -F "wifi" '{print $1}' | awk '{print $NF}' | xargs)
nmcli connection down "$con_uuid" > /dev/null 2>&1
restore_view
elif [[ "$@" == "-=|> Delete existing connections" ]]; then # Opens the saved networks list window
saved_connections
elif [ -f $CACHE_DIR/delete_connection ]; then
connection_uuid=$(echo "$@" | awk '{print $1}')
nmcli con delete uuid "$connection_uuid" >/dev/null 2>&1
restore_view
elif [ -f $CACHE_DIR/available_networks ]; then
if [[ "$@" == "-=|> Rescan available networks" ]]; then
nmcli device wifi rescan >/dev/null 2>&1
restore_view
else
rm $CACHE_DIR/available_networks
echo "$@" > "$CACHE_DIR/network_selected"
BSSID=$(echo "$@" | awk '{print $1}')
SSID=$(echo "$@" | cut -c 20- | xargs)
SECURITY=$(nmcli -f BSSID,SECURITY device wifi | grep "$BSSID" | awk -F " " '{print $2}' | xargs)
if [[ $(nmcli -f NAME con show | grep -o -m 1 "$SSID") == "$SSID" ]]; then
status=$(nmcli connection up "$SSID")
error_status
exit 0
elif [[ "$SECURITY" =~ "--" ]] || [ -z "$SECURITY" ]; then
nmcli device wifi connect "$BSSID" >/dev/null 2>&1
notify-send "Successfully connected to " "$SSID"
elif [[ "$SECURITY" =~ "WPA" ]] || [ "$SECURITY" =~ "WEP" ]; then
rm $CACHE_DIR/network_selected
echo "$BSSID" > "$CACHE_DIR/network_bssid"
get_password
fi
fi
fi
elif [[ "${ROFI_RETV}" == "2" ]]; then
if [ -f $CACHE_DIR/get_ssid ]; then
rm $CACHE_DIR/get_ssid
echo "$@" > "$CACHE_DIR/network_ssid"
get_password
elif [ -f $CACHE_DIR/network_bssid ]; then
PASSWORD="$@"
BSSID=$(cat "$CACHE_DIR/network_bssid")
status=$(nmcli device wifi connect "$BSSID" password "$PASSWORD")
error_status
elif [ -f $CACHE_DIR/network_ssid ]; then
PASSWORD="$@"
SSID=$(cat "$CACHE_DIR/network_ssid")
status=$(nmcli device wifi connect "$SSID" password "$PASSWORD" hidden true)
error_status
else
restore_view
fi
else
restore_view
echo -en "\0message\x1f# Custom key events are not valid in this mode.\n"
fi

25
.local/bin/rofi/wifimanager_run Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# wifimanager_run
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Wed 07 December 2022, 11:01:52 PM [GMT]
#Modified:
# Sat 16 September 2023, 07:42:10 PM [UTC]
#
#Description:
# <Todo>
#
#Dependencies:
# <None>
#
# shellcheck disable=all
rofi -show wifimanager -config ~/.config/rofi/wifimanager.rasi

269
.local/bin/rofi/youtube_subs Executable file
View File

@ -0,0 +1,269 @@
#!/usr/bin/env bash
#-*-coding:utf-8 -*-
#Auto updated?
# Yes
#File:
# youtube_subs
#Author:
# The-Repo-Club [wayne6324@gmail.com]
#Github:
# https://github.com/The-Repo-Club/
#
#Created:
# Sun 03 January 2021, 05:09:33 PM [GMT]
#Modified:
# Fri 25 August 2023, 05:45:05 PM [GMT+1]
#
#Description:
# Watch your youtube subscriptions without a youtube account
# via curl, repomenu, browser and basic unix commands.
#
# The $SUBS_FILE is a text file containing usernames or channel IDs
# comments and blank lines are ignored.
#
#
#Dependencies:
# rofi
#
rofis() {
rofi -dmenu -p "Youtube Subs:" -mesg "Select a video."
}
# -/-/-/-/- Settings -/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
: "${SUBS_FILE:=${HOME}/.config/rofi/configs/subs.ini}"
: "${SUBS_MENU_PROG:=rofis}"
: "${SUBS:=${HOME}/.cache/subs}"
: "${SUBS_LINKS:=$SUBS/links}"
: "${SUBS_CACHE:=$SUBS/cache}"
: "${SUBS_SLEEP_VALUE:=0.05}" # raise this if you experience problems
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SEP=^^^^^ # shouldn't need to change this
SUBS_OPEN="mpv --volume=50"
# -/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
die() {
printf >&2 '%s\n' "$*"
exit 1
}
usage() {
die 'Usage: youtube_subs [-c cat_subs] [-g gen_links] [-u update_subs] [-d daemonize]'
}
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
# Synopsis: $SUBS_FILE [txt] -> $SUBS_LINKS [xml links]
#
# Updates local cache of xml subscription links from the
# subscription file containing either usernames or channel ids.
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
gen_links() {
: >"$SUBS_LINKS"
count=0
total=$(sed -e '/^$/d' -e '/^#/d' <"$SUBS_FILE" | wc -l)
while read -r line; do
# ignore comments and blank lines
case $line in '' | ' ' | '#'*) continue ;; esac
# strip off in-line comments and any trailing whitespace
line=${line%%#*}
line=${line%% *}
count=$((count + 1))
case $line in
UC*)
# YT channel IDs always begin with 'UC' and are 24 chars long
printf "[%s/%s] using channel ID '%s' for xml link\n" "$count" "$total" "$line"
[ ${#line} -eq 24 ] &&
printf 'https://youtube.com/feeds/videos.xml?%s\n' \
"channel_id=$line" >>"$SUBS_LINKS"
;;
*)
# otherwise we are given a username, we must find out its channel ID
printf "fetching channel ID for %s...\n" "$line"
curl -sfL --retry 10 "https://youtube.com/user/$line/about" |
while read -r line; do
case $line in
*channel/UC??????????????????????*)
line=${line##*channel/}
line=${line%%\"*}
printf "[%s/%s] using channel ID '%s' for xml link\n" "$count" "$total" "$line"
printf 'https://youtube.com/feeds/videos.xml?channel_id=%s\n' \
"$line" >>"$SUBS_LINKS"
break
;;
esac
done &
sleep "${SUBS_SLEEP_VALUE:-0}"
;;
esac
done <"$SUBS_FILE"
count=0
while [ "$count" -ne "$total" ]; do
count=$(wc -l <"$SUBS_LINKS")
printf "[%s/%s] waiting for jobs to complete...\n" "$count" "$total"
sleep 0.5
done
}
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
# Synopsis: $1 [LINK] -> $SUBS_CACHE/$chan_name/concat [CHANNEL INFO]
#
# Takes a channel rss feed link and creates a file
# with a line of its videos dates, titles, and urls.
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
get_vids() {
data=$(curl -sfL --retry 15 "$1")
# hide the first <published> tag which is the channel
# creation date
data=${data#*\<\/published\>}
# trim off outer <name> tags
chan=${data%%</name*}
chan=${chan##*name>}
printf "%s\n" "$data" |
while read -r line; do
case $line in
*'link rel='*)
line=${line#*href=\"}
line=${line%\"/\>}
line=https://${line#*www.}
url=$line
;;
*'<published>'*)
line=${line%+00:*}
line=${line#*<published>}
date=$line
;;
*'<media:title>'*)
line=${line%</*}
line=${line#*:title>}
title=$line
printf '%s\n' \
"${date}${SEP}${chan}${SEP}${title}${SEP}${url}" \
>>"$SUBS_CACHE/$chan"
;;
esac
done
}
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
# Updates the local cache of subscriptions. ([-u] flag)
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
update_subs() {
[ -f "$SUBS_LINKS" ] || die 'Subs links have not been generated.'
rm -r "${SUBS_CACHE:-?}" 2>/dev/null || :
mkdir -p "$SUBS_CACHE"
total=$(wc -l <"$SUBS_LINKS")
count=0
while read -r link; do
count=$((count + 1))
printf 'starting job [%s/%s] for %s\n' "$count" "$total" "$link"
get_vids "$link" &
sleep "${SUBS_SLEEP_VALUE:-0}"
done <"$SUBS_LINKS"
count=0
while [ "$count" -ne "$total" ]; do
count=$(printf '%s\n' "$SUBS_CACHE"/* | wc -l)
printf "[%s/%s] waiting for fetch jobs to complete...\n" "$count" "$total"
sleep 0.5
done
printf '%s\n\n' 'done!'
}
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
# Grab current cache of subscriptions, sort by date uploaded
# -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
cat_subs() {
sort -r "$SUBS_CACHE"/* |
while read -r line; do
chan=${line#*$SEP}
chan=${chan%%$SEP*}
title=${line#*$chan$SEP}
title=${title%%$SEP*}
date=${line%%$SEP*}
date=${date#*-}
date=${date%T*}
printf '[%s %s] %s\n' "$date" "$chan" "$title"
done
}
# Split the concatenated lines into entities, send to menu program.
# Finally, play the result with mpv.
get_sel() {
if [ -d "$SUBS_CACHE" ]; then
sel=$(cat_subs | $SUBS_MENU_PROG)
else
die 'Subs cache has not been retrieved.'
fi
[ "$sel" ] || die Interrupted
chan="${sel#* }"
chan="${chan%%] *}"
title=${sel#*"$chan"\] }
while read -r line; do
case $line in
*"$SEP$title$SEP"*)
url=${line##*$SEP}
if [ "$url" ]; then
printf 'playing: %s\n' "$url"
# Play the selection.
# shellcheck disable=2086
exec $SUBS_OPEN "$url"
fi
break
;;
esac
done <"$SUBS_CACHE/$chan"
}
daemonize() {
# create a cached copy of the subs file to check for changes
# if changes occur, re-generate links automatically
daemon_file=${HOME}/.cache/subs_daemon.cache
if [ ! -f "$daemon_file" ]; then
cp -f "${SUBS_FILE:=${HOME}/.config/repomenu/subs.ini}" "$daemon_file"
fi
while true; do
if ! cmp "${SUBS_FILE:=${HOME}/.config/repomenu/subs.ini}" "$daemon_file"; then
cp -f "${SUBS_FILE:=${HOME}/.config/repomenu/subs.ini}" "$daemon_file"
fi
gen_links
update_subs
interval=${SUBS_DAEMON_INTERVAL:-$((10 * 60))}
printf 'Sleeping for %s seconds...\n' "$interval"
sleep "$interval"
done
}
main() {
mkdir -p "$SUBS"
case ${1#-} in
h) usage ;;
g) gen_links ;;
u) update_subs ;;
c) cat_subs ;;
d) daemonize ;;
*) get_sel ;;
esac
}
main "$@"