Home

Dmenu script for bookmarks

Screenshot of the dmenu bookmarks script in action

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 result
  • xclip (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.

  1. Download writeBookmarks.py.
  2. Export your bookmarks from a browser into a file called bookmarks.html.
  3. Run python3 writeBookmarks.py bookmarks.html >> bookmarks.yaml, assuming you are in the directory containing both files. This will create file called bookmarks.yaml with all your bookmarks. If you wish to edit/add bookmarks in the future, edit this file.
  4. Download bookmarks.py and bookmarks.sh, ensuring that they are in the same directory. Run chmod +x bookmarks.sh to make it executable.
  5. 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.