~kris/dots

srice

ref: e9b48d06a8541f3eda5c4db90382ab3c77183afb srice/bin/sdict -rwxr-xr-x 4.2 KiB
e9b48d06 — Kris Yotam xprofile: systemd-aware pipewire start + blueman-applet; sb-internet: tolerate missing /proc/net/wireless 2 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/usr/bin/env bash
# sdict — terminal dictionary lookup
# Inspired by BreadOnPenguins/scripts/define
# Backends: Oxford Dictionaries API (set OD_APP_ID + OD_APP_KEY)
#           sdcv with Oxford StarDict dict (offline, set SDICT_USE_SDCV=1)
#           dictionaryapi.dev (free fallback, no config needed)

set -euo pipefail

BOLD='\033[1m'
DIM='\033[2m'
ITALIC='\033[3m'
BLUE='\033[34m'
CYAN='\033[36m'
GREEN='\033[32m'
YELLOW='\033[33m'
RESET='\033[0m'

usage() {
    echo -e "${BOLD}sdict${RESET} — look up a word in the dictionary"
    echo ""
    echo -e "  ${BOLD}Usage:${RESET} sdict <word>"
    echo ""
    echo -e "  ${BOLD}Backends (checked in order):${RESET}"
    echo "    1. Oxford Dictionaries API  — set OD_APP_ID and OD_APP_KEY"
    echo "    2. sdcv (offline Oxford)    — set SDICT_USE_SDCV=1"
    echo "    3. dictionaryapi.dev        — free, no config needed"
    exit 0
}

die() { echo -e "\033[31merror:\033[0m $1" >&2; exit 1; }

[[ $# -lt 1 || "$1" == "-h" || "$1" == "--help" ]] && usage
word="$1"
[[ "$word" =~ [^a-zA-Z-] ]] && die "invalid word: $word"

# --- Backend 1: Oxford Dictionaries API ---
oxford_lookup() {
    local resp
    resp=$(curl -sf --connect-timeout 5 --max-time 10 \
        -H "app_id: $OD_APP_ID" \
        -H "app_key: $OD_APP_KEY" \
        "https://od-api-v2.oxforddictionaries.com/api/v2/entries/en-us/${word,,}") || return 1

    echo -e "${BOLD}${BLUE}${word}${RESET}"
    echo ""

    # phonetic
    local phonetic
    phonetic=$(echo "$resp" | jq -r '
        [.results[].lexicalEntries[].pronunciations[]? | select(.phoneticSpelling) | .phoneticSpelling] | first // empty
    ' 2>/dev/null)
    [[ -n "$phonetic" ]] && echo -e "  ${DIM}/$phonetic/${RESET}" && echo ""

    # etymology
    local etym
    etym=$(echo "$resp" | jq -r '
        [.results[].lexicalEntries[].entries[].etymologies[]?] | first // empty
    ' 2>/dev/null)
    [[ -n "$etym" ]] && echo -e "  ${DIM}Origin: $etym${RESET}" && echo ""

    # definitions by part of speech
    echo "$resp" | jq -r '
        .results[].lexicalEntries[] |
        .lexicalCategory.id as $pos |
        .entries[].senses[:3][] |
        "\($pos)|\(.definitions[0] // empty)|\(.examples[0].text? // empty)"
    ' 2>/dev/null | while IFS='|' read -r pos def example; do
        [[ -z "$def" ]] && continue
        echo -e "  ${GREEN}${pos}${RESET}"
        echo -e "    ${def}"
        [[ -n "$example" ]] && echo -e "    ${DIM}\"${example}\"${RESET}"
        echo ""
    done
}

# --- Backend 2: sdcv (offline) ---
sdcv_lookup() {
    command -v sdcv >/dev/null 2>&1 || return 1
    local result
    result=$(sdcv -n "$word" 2>/dev/null) || return 1
    [[ "$result" == *"Nothing similar"* ]] && return 1
    echo -e "${BOLD}${BLUE}${word}${RESET}"
    echo ""
    echo "$result" | sed 's/^/  /'
    echo ""
}

# --- Backend 3: Free Dictionary API (fallback) ---
free_lookup() {
    local resp
    resp=$(curl -sf --connect-timeout 5 --max-time 10 \
        "https://api.dictionaryapi.dev/api/v2/entries/en_US/${word}") || return 1
    [[ "$resp" == *"No Definitions Found"* ]] && return 1

    echo -e "${BOLD}${BLUE}${word}${RESET}"
    echo ""

    # phonetic
    local phonetic
    phonetic=$(echo "$resp" | jq -r '[.[].phonetic // empty] | first // empty' 2>/dev/null)
    [[ -n "$phonetic" ]] && echo -e "  ${DIM}${phonetic}${RESET}" && echo ""

    # definitions
    echo "$resp" | jq -r '
        .[].meanings[] |
        .partOfSpeech as $pos |
        .definitions[:3][] |
        "\($pos)|\(.definition)|\(.example // empty)"
    ' 2>/dev/null | while IFS='|' read -r pos def example; do
        [[ -z "$def" ]] && continue
        echo -e "  ${GREEN}${pos}${RESET}"
        echo -e "    ${def}"
        [[ -n "$example" ]] && echo -e "    ${DIM}\"${example}\"${RESET}"
        echo ""
    done

    echo -e "  ${DIM}source: dictionaryapi.dev${RESET}"
}

# --- Dispatch ---
if [[ -n "${OD_APP_ID:-}" && -n "${OD_APP_KEY:-}" ]]; then
    oxford_lookup && exit 0
    echo -e "${DIM}Oxford API failed, trying fallback...${RESET}" >&2
fi

if [[ "${SDICT_USE_SDCV:-0}" == "1" ]]; then
    sdcv_lookup && exit 0
    echo -e "${DIM}sdcv failed, trying fallback...${RESET}" >&2
fi

free_lookup || die "no definition found for '${word}'"