Dmenu script for bookmarks
A dmenu
script for handling bookmarks, as well as other commonly typed one-liners.
Contains a script for converting a bookmarks.html
file exported from a browser
into a .yaml
file. Using yaml
allows folders by indentation, which is the feature
that prompted me to write this.
Requisites
dmenu
available from https://tools.suckless.org/dmenu/python3
xdotool
for typing the selected resultxclip
(optional) for pasting the result, instead of typing it (can be a lot quicker)
Instructions
Steps 1-3 are optional, since they are just converting an exported bookmarks
file to a file the script can use. If you wish to use the xclip
version,
simply download bookmarks-xclip.sh
and name it
bookmarks.sh
instead of downloading bookmarks.sh
.
- Download
writeBookmarks.py
. - Export your bookmarks from a browser into a file called
bookmarks.html
. - Run
python3 writeBookmarks.py bookmarks.html >> bookmarks.yaml
, assuming you are in the directory containing both files. This will create file calledbookmarks.yaml
with all your bookmarks. If you wish to edit/add bookmarks in the future, edit this file. - Download
bookmarks.py
andbookmarks.sh
, ensuring that they are in the same directory. Runchmod +x bookmarks.sh
to make it executable. - Run
./bookmarks.sh ./bookmarks.yaml
, where./bookmarks.yaml
is replaced with the suitable path.
Scripts
writeBookmarks.py
import sys
with open(sys.argv[1], 'r', encoding="utf-8") as bookmarks:
for line in bookmarks:
if "HREF" in line or "H3" in line:
spaces = (line.find("<")-8)*' '
reversed = line[::-1]
reversed = reversed[reversed.find("<")+1:]
title = reversed[:reversed.find(">")][::-1]
title = title.replace(" :", " -").replace(":", " -").replace("[", "").replace("]", " ").replace("#", "no. ")
url = ""
if "HREF" in line:
url = line[line.find("HREF=")+6:]
url = url[:url.find('"')]
print(f'{spaces}{title}: "{url}"')
else:
print(f'{spaces}{title}:')
bookmarks.py
import sys
bookmarksFilePath = sys.argv[1]
sys.argv.pop(1)
with open(bookmarksFilePath, 'r') as bookmarksFile:
if len(sys.argv) == 1:
print(bookmarksFile.read())
quit()
if '"' in sys.argv[1]:
for line in bookmarksFile:
if sys.argv[1][sys.argv[1].find('"'):-1] in line:
print(sys.argv[1][sys.argv[1].find('"')+1:-1])
quit()
else:
printing = False
level = -1
for line in bookmarksFile:
if sys.argv[1].strip() == line.strip():
printing = True
level = len(line) - len(line.lstrip())
elif len(line) - len(line.lstrip()) <= level:
quit()
if printing and len(line) - len(line.lstrip()) > level:
print(line, end="")
bookmarks.sh
#!/bin/bash
[ $# -eq 0 ] && { echo "Usage: $0 file.yaml"; exit 1; }
DIR=$(dirname "$0")
var=$(python3 "$DIR"/bookmarks.py "$1" | dmenu -i -l 20)
if [ -z "$var" ]
then
exit
fi
if [[ "$var" == *"\""* ]]; then
xdotool type "$(python3 "$DIR"/bookmarks.py "$1" "$var")"
exit
fi
while true
do
var=$(python3 "$DIR"/bookmarks.py "$1" "$var" | dmenu -i -l 20)
if [ -z "$var" ]
then
exit
fi
if [[ "$var" == *"\""* ]]; then
xdotool type "$(python3 "$DIR"/bookmarks.py "$1" "$var")"
exit
fi
done
bookmarks-xclip.sh
#!/bin/bash
[ $# -eq 0 ] && { echo "Usage: $0 file.yaml"; exit 1; }
DIR=$(dirname "$0")
var=$(python3 "$DIR"/bookmarks.py "$1" | dmenu -i -l 20)
if [ -z "$var" ]
then
exit
fi
if [[ "$var" == *"\""* ]]; then
python3 "$DIR"/bookmarks.py "$1" "$var" | xclip -i -sel clip
xdotool key Ctrl+Shift+v
exit
fi
while true
do
var=$(python3 "$DIR"/bookmarks.py "$1" "$var" | dmenu -i -l 20)
if [ -z "$var" ]
then
exit
fi
if [[ "$var" == *"\""* ]]; then
python3 "$DIR"/bookmarks.py "$1" "$var" | xclip -i -sel clip
xdotool key Ctrl+Shift+v
exit
fi
done
Alternative Using Markdown
It is possible using a text editor (e.g. Neovim) and a few regexes to convert
the yaml
to a Markdown file. So, if you have a file using Markdown, where you
use titles (lines beginning with “#”) and dot points (lines beginning with “- "
and links in the form of “Example website” so that your
bookmarks look like this:
# Catholic
## Bibles
- [Douay-Rheims Catholic Bible](http://www.drbo.org/)
- [Vulgate, Douay-Rheims and Knox Bible side by side](http://catholicbible.online/side_by_side/OT/Gen/ch_1?act_indx=0&act=1)
- [Vulgate Latin Bible With English Translation](https://vulgate.org/)
## Books
- [DigiVatLib](https://digi.vatlib.it/)
- [The Holy See Archive](https://www.vatican.va/archive/index.htm)
- [The Holy Father – The Holy See](https://www.vatican.va/holy_father/index.htm)
- [Catholic eBooks Project](https://catholicebooks.wordpress.com/)
- [Catholic texts](https://archive.org/details/catholictexts)
- [patristica.net](http://patristica.net/)
- [St. Dominic Biographical Documents](http://www.domcentral.org/trad/domdocs/default.htm)
- [Saints' Books](http://www.saintsbooks.net/BooksList.html)
- [Saints' Books (scripture)](http://www.saintsbooks.net/BooksList.html#Scripture)
- [Saints' Prayers](http://www.saintsprayers.net/)
Then you can use this script, which functions similarly. The usage is described in the help message.
#!/bin/sh
if [ $# -ne 3 ]; then
echo "Usage: $0 filepath selector-command paste-command"
echo "Example:"
echo "$0 bookmarks.md \"dmenu -b -i -l 20\" \"xclip -i -sel clip && xdotool key Ctrl+v\""
exit
fi
filepath=$1
selector=$2
paste=$3
strip_and_send_to_selector() {
sed '/^[[:space:]]*$/d' |
sed 's/^\- \[//' |
sed 's/\](/: "/' |
sed 's/)$/"/' |
tail -n +1 |
eval "$1"
}
get_item_from_dmenu() {
# If has folder passed to it (assuming second parameter is valid folder)
if [ -n "$3" ]; then
level=$(printf "%s" "$3" | sed 's/# .*/#/' | wc --chars)
sed -n "/^$3$/,\$p" "$1" |
sed -n "1d; /^#\{1,$level\} /q; p" |
strip_and_send_to_selector "$2"
else
strip_and_send_to_selector "$2" < "$1"
fi
}
var=$(get_item_from_dmenu "$filepath" "$selector")
if [ -z "${var}" ]; then exit; fi
while [ "$(printf "%s" "$var" | sed 's/^#.*//' | wc --chars)" -eq 0 ]; do
var=$(get_item_from_dmenu "$filepath" "$selector" "$var")
if [ -z "${var}" ]; then exit; fi
done
echo "$var" | sed 's/.*:\s*"\(.*\)".*/\1/' | eval "$paste"
Tags
Categories
If you have questions, you can email me at jeremy.w.cains at gmail.com. View page source here.