239 lines
7.9 KiB
Bash
Executable File
239 lines
7.9 KiB
Bash
Executable File
#!/usr/bin/env sh
|
|
|
|
# Dmenu plain text URL bookmark manager.
|
|
|
|
# MIT License
|
|
#
|
|
# Copyright (c) 2020 Alexander Chaplin Braz
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in all
|
|
# copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
# SOFTWARE.
|
|
|
|
ScriptName=${0##*/}
|
|
Version=1.0.0
|
|
|
|
# Compose the help message:
|
|
HelpMessage="$ScriptName - Version: $Version
|
|
Creator: Alexander Chaplin Braz (https://alexchaplinbraz.com)
|
|
License: MIT
|
|
|
|
Usage: $ScriptName {bookmark}
|
|
|
|
This script is a simple plain text URL bookmark manager that lets the user
|
|
copy, add, edit and delete bookmark entries. It requires one argument,
|
|
the path to the bookmark file. The URLs are opened with \$BROWSER.
|
|
|
|
The format of the bookmark file is:
|
|
One bookmark per line with three tab separated fields: URL, title and tags.
|
|
The tags are comma separated and can have spaces.
|
|
"
|
|
|
|
case $1 in
|
|
'') printf '%s' "$HelpMessage"; exit 1;;
|
|
-h|--help) printf '%s' "$HelpMessage"; exit 0;;
|
|
-v|--version) printf '%s' "$Version"; exit 0;;
|
|
esac
|
|
|
|
# Temporary file location
|
|
TempFile="/tmp/$ScriptName"
|
|
|
|
# Load and format the bookmarks:
|
|
Bookmarks=$(cat "$1" | nl -n ln)
|
|
FormattedBookmarks=$(printf '%s' "$Bookmarks" \
|
|
| sed 's/\t\t/\tBLANK\t/' \
|
|
| awk -F '\t' '{print $1, $3, "("$4")", $5, "["$2"]"}')
|
|
### For some reason setting OFS='\t' makes dmenu lag.
|
|
|
|
# Set menu options:
|
|
MenuOpen='1. Open a bookmark.'
|
|
MenuCreate='2. Create new bookmark.'
|
|
MenuEdit='3. Edit a bookmark.'
|
|
MenuDelete='4. Delete a bookmark.'
|
|
|
|
# Prompt user to choose action:
|
|
ChosenMenu=$(printf '%s\n%s\n%s\n%s' \
|
|
"$MenuOpen" "$MenuCreate" "$MenuEdit" "$MenuDelete" \
|
|
| dmenu -i -l 10 -p "$ScriptName:")
|
|
|
|
# Open bookmark:
|
|
if [ "$ChosenMenu" = "$MenuOpen" ]; then
|
|
# Prompt user for bookmark:
|
|
Chosen=$(printf '%s' "$FormattedBookmarks" \
|
|
| dmenu -i -l 30 -p 'Open:' \
|
|
| awk '{printf $1}')
|
|
Chosen=$(printf '%s' "$Bookmarks" \
|
|
| grep -w ^$Chosen \
|
|
| awk '{printf $2}')
|
|
[ -z "$Chosen" ] && exit 1
|
|
|
|
# Open browser with selected URL.
|
|
$BROWSER "$Chosen"
|
|
|
|
# Create bookmark:
|
|
elif [ "$ChosenMenu" = "$MenuCreate" ]; then
|
|
# Get the name of the active window:
|
|
ActiveWindow=$(ps -p "$(xdotool getwindowfocus getwindowpid)" -o comm=)
|
|
|
|
# Set the name if the active window is a chromium based browser:
|
|
printf '%s' "$ActiveWindow" | grep -Eq 'chromium|chrome|brave' \
|
|
&& ActiveWindow='chromium-based'
|
|
### Haven't actually checked whether Chromium's window name is chromium.
|
|
|
|
# Get URL/title based on browser:
|
|
if [ "$ActiveWindow" = 'qutebrowser' ]; then
|
|
xdotool search --name qutebrowser key --clearmodifiers y P
|
|
sleep 0.1
|
|
URL=$(xclip -o)
|
|
sleep 0.1
|
|
xdotool search --name qutebrowser key --clearmodifiers y T
|
|
sleep 0.1
|
|
Title=$(xclip -o)
|
|
elif [ "$ActiveWindow" = 'chromium-based' ]; then
|
|
xdotool key --clearmodifiers ctrl+l
|
|
sleep 0.1
|
|
xdotool key --clearmodifiers ctrl+c
|
|
sleep 0.1
|
|
URL=$(xclip -o)
|
|
sleep 0.1
|
|
### Maybe write it to a file in the background to speed it up.
|
|
### Doesn't work for some generated sites.
|
|
Title=$(curl -s "$URL" \
|
|
| awk -F '<title>|</title>' '{for(i=2;i<=NF;i+=2){print $i}}' \
|
|
RS='' \
|
|
| recode html)
|
|
fi
|
|
|
|
# Check if URL already exists.
|
|
if [ "$URL" ] && grep -q "$URL" "$1" ;then
|
|
printf '' | dmenu -p 'ERROR: URL already bookmarked.'
|
|
exit 1
|
|
fi
|
|
|
|
# Prompt user to edit the URL:
|
|
EditedURL=$(printf '%s' "$URL" | dmenu -l 1 -p 'Edit URL:')
|
|
[ "$EditedURL" ] && URL=$EditedURL
|
|
|
|
# Prompt user to edit the title:
|
|
EditedTitle=$(printf '%s' "$Title" | dmenu -l 1 -p 'Edit title:')
|
|
[ "$EditedTitle" ] && Title=$EditedTitle
|
|
|
|
# Prompt the user to pick tags for the bookmark:
|
|
AllTags=$(printf '%s' "$Bookmarks" \
|
|
| awk -F '\t' '{print $4}' \
|
|
| tr ',' '\n' \
|
|
| sort \
|
|
| uniq)
|
|
while true; do
|
|
SelectedTag=$(printf '%s' "$AllTags" \
|
|
| dmenu -i -l 30 \
|
|
-p "Add tags. SHIFT+ENTER to create a new tag. $Tags")
|
|
[ -z "$SelectedTag" ] && break
|
|
Tags="$Tags$SelectedTag,"
|
|
done
|
|
Tags=${Tags%?}
|
|
|
|
# Create a preview for the user to see their input:
|
|
Confirmation=$(printf '%s\nURL: %s\nTitle: %s\nTags: %s' \
|
|
'This is a preview. Press ENTER to confirm or ESCAPE to cancel.' \
|
|
"$URL" "$Title" "$Tags" \
|
|
| dmenu -i -l 10)
|
|
|
|
# If the user pressed ENTER, create the bookmark:
|
|
[ "$Confirmation" ] && \
|
|
printf '%s\t%s\t%s' \
|
|
"$URL" "$Title" "$Tags" >> "$1"
|
|
|
|
# Edit bookmark:
|
|
elif [ "$ChosenMenu" = "$MenuEdit" ]; then
|
|
# Prompt user for bookmark:
|
|
Chosen=$(printf '%s' "$FormattedBookmarks" \
|
|
| dmenu -i -l 30 -p "Edit:" \
|
|
| awk '{printf $1}')
|
|
Chosen=$(printf '%s' "$Bookmarks" \
|
|
| grep -w ^$Chosen \
|
|
| awk '{printf $2}')
|
|
[ -z "$Chosen" ] && exit 1
|
|
|
|
# Get the bookmark information:
|
|
Mark=$(grep "$Chosen" "$1")
|
|
OldURL=$(printf '%s' "$Mark" | awk -F '\t' '{printf $1}')
|
|
OldTitle=$(printf '%s' "$Mark" | awk -F '\t' '{printf $2}')
|
|
OldTags=$(printf '%s' "$Mark" | awk -F '\t' '{printf $3}')
|
|
|
|
# Prompt user to edit the URL:
|
|
EditedURL=$(printf '%s' "$OldURL" | dmenu -l 1 -p 'Edit URL:')
|
|
[ "$EditedURL" ] && URL=$EditedURL
|
|
|
|
# Prompt user to edit the title:
|
|
EditedTitle=$(printf '%s' "$OldTitle" | dmenu -l 1 -p 'Edit title:')
|
|
[ "$EditedTitle" ] && Title=$EditedTitle
|
|
|
|
# Prompt the user to pick tags for the bookmark:
|
|
AllTags=$(printf '%s' "$Bookmarks" \
|
|
| awk -F '\t' '{print $4}' \
|
|
| tr ',' '\n' \
|
|
| sort \
|
|
| uniq)
|
|
while true; do
|
|
SelectedTag=$(printf '%s' "$AllTags" \
|
|
| dmenu -i -l 30 \
|
|
-p "Old: $OldTags | New: $Tags")
|
|
[ -z "$SelectedTag" ] && break
|
|
Tags="$Tags$SelectedTag,"
|
|
done
|
|
Tags=${Tags%,}
|
|
|
|
# Create a preview for the user to see their input:
|
|
Confirmation=$(printf \
|
|
'%s\nNew URL: %s\nOld URL: %s\nNew title: %s\nOld title: %s\
|
|
\nNew tags: %s\nOld tags: %s' \
|
|
'This is a preview. Press ENTER to confirm or ESCAPE to cancel.' \
|
|
"$URL" "$OldURL" "$Title" "$OldTitle" "$Tags" "$OldTags" \
|
|
| dmenu -i -l 10)
|
|
|
|
# If the user pressed ENTER, edit the bookmark:
|
|
if [ "$Confirmation" ]; then
|
|
sed "\|$Chosen|d" "$1" > "$TempFile"
|
|
mv "$TempFile" "$1"
|
|
printf '%s\t%s\t%s' "$URL" "$Title" "$Tags" >> "$1"
|
|
else
|
|
exit 1
|
|
fi
|
|
|
|
# Delete bookmark:
|
|
elif [ "$ChosenMenu" = "$MenuDelete" ]; then
|
|
# Prompt user for bookmark:
|
|
Chosen=$(printf '%s' "$FormattedBookmarks" \
|
|
| dmenu -i -l 30 -p 'Delete:' \
|
|
| awk '{printf $1}')
|
|
Chosen=$(printf '%s' "$Bookmarks" \
|
|
| grep -w ^$Chosen \
|
|
| awk '{printf $2}')
|
|
[ -z "$Chosen" ] && exit 1
|
|
|
|
# Delete selected bookmark from file:
|
|
sed "\|$Chosen|d" "$1" > "$TempFile"
|
|
mv "$TempFile" "$1"
|
|
|
|
elif [ -z "$ChosenMenu" ]; then
|
|
exit 1
|
|
else
|
|
printf 'ERROR: invalid selection.\n'
|
|
exit 1
|
|
fi
|