zotero-link.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Show hidden characters
#!/usr/bin/env bash
export LC_ALL=en_US.UTF-8
#
mode="${1:-link}" library="$HOME/Base/Obsidian/.library.json"
fail() {
printf 'zotero-link: %s\n' "$*" >&2
exit 1
} #βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if command -v pbpaste >/dev/null 2>&1; then
text=$(pbpaste)
elif command -v xsel >/dev/null 2>&1; then
text=$(xsel --clipboard --output)
else
fail "could not find pbpaste or xsel"
fi
command -v jq >/dev/null 2>&1 || fail "jq is not installed"
[[ -r "$library" ]] || fail "library file is not readable: $library"
#βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
id=$(printf '%s\n' "$text" |
grep -Eo 'zotero://select/library/items/[a-zA-Z0-9]+' |
sed 's|zotero://select/library/items/||' |
head -n 1)
if [[ -z "$id" ]]; then
id=$(printf '%s\n' "$text" |
grep -Eo 'zotero://open-pdf/library/items/[a-zA-Z0-9]+' |
sed 's|zotero://open-pdf/library/items/||' |
head -n 1)
fi
if [[ -z "$id" ]]; then fail "could not find Zotero item ID in the clipboard text"
fi
#βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
item=$(jq --arg key "$id" '
.items[]
| select(
.key == $key
or any(.attachments[]?; (.select == ("zotero://select/library/items/" + $key)) or (.uri | endswith("/items/" + $key)))
)
' "$library")
title=$(jq -r 'if .shortTitle then .shortTitle else .title end' <<<"$item")
if [[ -z "$title" ]]; then
fail "could not find exported Zotero item or parent attachment for ID: $id"
fi
#βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
if [[ "$mode" == "citekey" ]]; then
citekey=$(jq -r '.citationKey' <<<"$item")
echo "[@${citekey#@}]"
exit 0
fi
#βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
link_patterns=(
"pdf:zotero:\/\/open-pdf\/library\/items\/([a-zA-Z0-9]+)\?page=([0-9]+)&annotation=([a-zA-Z0-9])+"
"snap:zotero:\/\/open-pdf\/library\/items\/([a-zA-Z0-9]+)\?sel=([^&]+)&annotation=([a-zA-Z0-9]+)"
"epub:zotero:\/\/open-pdf\/library\/items\/([a-zA-Z0-9]+)\?cfi=([^&]+)&annotation=([a-zA-Z0-9]+)"
)
#βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
for pattern in "${link_patterns[@]}"; do
IFS=':' read -r link_type regex <<<"$pattern"
if [[ "$text" =~ $regex ]]; then
link="${BASH_REMATCH[0]}"
page_number="${BASH_REMATCH[2]}"
case "$mode" in
quote)
quote_text=$(printf '%s' "$text" | sed 's/ *(\[.*//')
author_full=$(jq -r 'if .creators[0] then "\(.creators[0].firstName) \(.creators[0].lastName)" else empty end' <<<"$item")
echo "> [!quote]"
echo "> ${quote_text//$'\n'/$'\n> '}"
echo ">"
case "$link_type" in
pdf) echo "> - ${title}, [p. ${page_number}](${link})" ;;
*) echo "> - [${title}](${link})" ;;
esac
[[ -n "$author_full" ]] && echo "> - ${author_full}"
;;
*)
author=$(jq -r '.creators[0].lastName // empty' <<<"$item")
year=$(jq -r '.date // empty' <<<"$item" | grep -Eo '[0-9]{4}')
result=""
[[ -n "$author" ]] && result="${author}, "
case "$link_type" in
pdf)
result="${result}${title}"
[[ -n "$year" ]] && result="${result} (${year})"
result="${result}, [p. ${page_number}](${link})"
;;
*)
result="${result}[${title}](${link})"
[[ -n "$year" ]] && result="${result} (${year})"
;;
esac
echo "$result"
;;
esac
exit 0
fi
done
fail "no suitable Zotero PDF/snapshot/EPUB link found in the clipboard text"