From f6341b0c37703d02776945d70db7273e99ffdbe6 Mon Sep 17 00:00:00 2001 From: sinanmohd Date: Thu, 16 Mar 2023 18:46:59 +0530 Subject: dbook: initial commit: a bookmark manager --- README.md | 8 ++ dbook | 309 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 317 insertions(+) create mode 100755 dbook diff --git a/README.md b/README.md index f68e089..661ba04 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,14 @@ they work on both xorg and wayland using dmenu and wmenu respectively. these scripts might use [nerd fonts](https://www.nerdfonts.com/), make sure you've installed them for the best experience. you can find more info about them below. +## dbook +dbook is a bookmark manager, it can bookmark directories, files, text, links, +anything, by default dbook will try to represent the data best way possoble +ie open links using the browser, coppy text to clipboard, if it's a video +open using a video player, etc. use -i or -s to add an entry or directly +modify the config file located at ~/.config/dbook/dbook.conf. dbook can +also copy bookmarks and type them. + ## dpass dpass is the dmenu wrapper for the standard unix password manager, run dpass -h from a terminal to see what it's capable of. diff --git a/dbook b/dbook new file mode 100755 index 0000000..3f7b693 --- /dev/null +++ b/dbook @@ -0,0 +1,309 @@ +#!/bin/sh + +book_conf="${XDG_CONFIG_HOME:-$HOME/.config}/dbook/dbook.conf" +book_data="${XDG_DATA_HOME:-$HOME/.local/share}/dbook" +menu="wmenu" + +note() +{ + : "${1:?}" + + command -v notify-send > /dev/null && + notify-send " dbook" "$1" +} + +die() +{ + : "${1:?}" + + note "$1" + printf "\033[31;1merr: %b\033[0m\n" "$1" 1>&2 + exit "${2:-1}" +} + +dep_check() +{ + : "${1:?}" + + for dep; do + command -v "$dep" 1>/dev/null || + die "$dep not found, please install it" 127 + done + + unset dep +} + +parse_name() +{ + while read -r line + do + line=${line%%|*} + + # trim leading and trailing white spaces + line=${line#"${line%%[![:space:]]*}"} + line=${line%"${line##*[![:space:]]}"} + + [ -z "${line##\#*}" ] && + continue + + echo "$line" + done < "$book_conf" +} + +parse_data() +{ + read -r book_name + read_name= + + [ -z "$book_name" ] || [ ! -f "$book_conf" ] && + return 1 + + while read -r line + do + # trim leading and trailing white spaces + line=${line#"${line%%[![:space:]]*}"} + line=${line%"${line##*[![:space:]]}"} + + # skip trailing lines till match + case "$line" in + "$book_name"*) + # make sure read_name fully matches book_name + read_name=${line%%|*} + read_name=${read_name%"${read_name##*[![:space:]]}"} + [ "$book_name" != "$read_name" ] && + continue + ;; + *) + continue + ;; + esac + + # extract date from string + line="${line##*|}" + line=${line#"${line%%[![:space:]]*}"} + + echo "$line" + return 0 + + done < "$book_conf" + + unset read_name + return 1 +} + +rm_data() +{ + # usage rm_data [data_name] + : "${1:?}" + read_name= + data= + cl= + file= + + while read -r line + do + cl="$line\n" + + # trim leading and trailing white spaces + line=${line#"${line%%[![:space:]]*}"} + line=${line%"${line##*[![:space:]]}"} + + # catch match + case "$line" in + "$book_name"*) + read_name=${line%%|*} + read_name=${read_name%"${read_name##*[![:space:]]}"} + + # make sure read_name fully matches + if [ "$1" = "$read_name" ] + then + # remove saved data + data="$(echo "$read_name" | parse_data)" + [ -e "$data" ] && [ -z "${data##"${book_data}"/*}" ] && + rm "$data" + + continue + fi + ;; + esac + + file="${file}${cl}" + + done < "$book_conf" + + # shellcheck disable=SC2059 + printf "$file" > "$book_conf" + unset read_name data file cl +} + +entry() +{ + printf "" | "$menu" -p " ${1:?} " || + die "input empty" +} + +sh_realpath() +{ + # usage: sh_realpath [path] + : "${1:?}" + + if [ -z "${1##/*}" ] + then + echo "$1" + else + echo "${PWD:-$(pwd)}/$1" + fi +} + +clip() +{ + # usage: clip [data] + : "${1:?}" + + if [ -z "$WAYLAND_DISPLAY" ] + then + dep_check "xclip" + echo "$1" | xclip -selection clipboard + else + dep_check "wl-copy" + echo "$1" | wl-copy + fi && + note "data coppied to clipboard" +} + +clip_file() +{ + # usage: clip [data] + : "${1:?}" + + if [ -z "$WAYLAND_DISPLAY" ] + then + dep_check "xclip" + echo "$1" | xclip -selection clipboard "$1" -t text/uri-list + else + dep_check "wl-copy" + echo "$1" | wl-copy -t text/uri-list + fi && + note "data coppied to clipboard" +} + +main() +{ + name= + data= + + [ -z "$WAYLAND_DISPLAY" ] && + menu="dmenu" + + [ -d "$book_data" ] || + mkdir -p "$book_data" + [ -d "$book_conf" ] || + mkdir -p "${book_conf%/*}" + + case "$1" in + -h|--help) + cat <<- EOF + Usage: dbook command + a bookmark manager using dmenu + Commands: + -h show this help cruft + -i [bookmark string] [bookmark name], inset a new entry + -s [bookmark string] [bookmark name], inset a new entry and make a copy + -d [bookmark name], delete an entry + -t [bookmark name], type the data + -c [bookmark name], copy the date to clipboard + EOF + ;; + -i) + data="${2:-$(entry name)}" + shift > /dev/null 2>&1 + shift > /dev/null 2>&1 + name="${*:-$(entry name)}" + + echo "$name" | parse_data > /dev/null && + die "name already in use" + + [ -e "$data" ] && + data="$(sh_realpath "$data")" + + printf "%s\t|\t%s\n" "$name" "$data" >> "$book_conf" + ;; + -s) + data="${2:-$(entry name)}" + shift > /dev/null 2>&1 + shift > /dev/null 2>&1 + name="${*:-$(entry name)}" + + echo "$name" | parse_data > /dev/null && + die "name already in use" + + [ -d "$data" ] && + die "$data is a directory, use -i instead" + + if [ -e "$data" ] + then + cp "$data" "$book_data" + data="${book_data}/${data##*/}" + fi + + printf "%s\t|\t%s\n" "$name" "$data" >> "$book_conf" + ;; + -d) + rm_data "${2:-"$(parse_name | "$menu" -p " " -l 25)"}" + ;; + -t) + shift > /dev/null 2>&1 + data="${*:-"$(parse_name | "$menu" -p " " -l 25 | parse_data)"}" + [ -z "$data" ] && + die "empty, use -i to add an entry" + + if [ -z "$WAYLAND_DISPLAY" ] + then + dep_check "xdotool" + xdotool type --delay 20 "$data" + else + dep_check "wtype" + wtype -d 20 "$data" + fi + ;; + -c) + shift > /dev/null 2>&1 + data="${*:-"$(parse_name | "$menu" -p " " -l 25 | parse_data)"}" + [ -z "$data" ] && + die "empty, use -i to add an entry" + + case "$(file --brief "$data")" in + *ASCII\ text*) + clip "$(cat "$data")" + ;; + *No\ such\ file\ or\ directory\)) + clip "$data" + ;; + *) + clip_file "$(printf "file://%s" "$data")" + ;; + esac + ;; + "") + dep_check "xdg-open" + + data="$(parse_name | "$menu" -p " " -l 25 | parse_data)" + [ -z "$data" ] && + die "empty, use -i to add an entry" + + xdg-open "$data" 2> /dev/null || + case "$(file --brief "$data")" in + *ASCII\ text*) + clip "$(cat "$data")" + ;; + *) + clip "$data" + ;; + esac + ;; + *) + die "$1, invalid usage" + esac +} + +main "$@" -- cgit v1.2.3