terminal-dashboard 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/bin/terminal-dashboard +2 -0
  3. data/lib/dashboard.sh +149 -0
  4. metadata +50 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 47ebe7b2e4b00567a4997f84080d28e47dd73802e4ec9662ef4d3167fa5a6c84
4
+ data.tar.gz: 56b2038b444ce6b6c4d4767e7e66f32b22503d43ce705e3510a02a21b2696e7c
5
+ SHA512:
6
+ metadata.gz: d51372a99fc9f9e2316bc5d5e6a28d87d2d32bd98752838e95e3b0103e4ccfa194fc39e635954b3ae09ef28928a736a67865b5c6b6bec11c7184a049355abab7
7
+ data.tar.gz: b353ca0d54b95d9bda8e09ccdfd181b60b4710d7591fe812e6027fdae41e4e05dd2077863e205e1f720e64513cbeedef4085c500e4bb8835fb361de6ba6ba23b
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ exec "$(dirname "$0")/../lib/dashboard.sh" "$@"
data/lib/dashboard.sh ADDED
@@ -0,0 +1,149 @@
1
+ #!/bin/bash
2
+ # shellcheck disable=SC2059
3
+
4
+ PLEX_URL="http://localhost:32400"
5
+ PLEX_TOKEN="${PLEX_TOKEN:-$(defaults read com.plexapp.plexmediaserver PlexOnlineToken 2>/dev/null)}"
6
+ QBIT_URL="http://192.168.1.133:8080"
7
+ QBIT_USER="${QBIT_USER:-admin}"
8
+ QBIT_PASS="${QBIT_PASS:-}"
9
+ QBIT_COOKIE="/tmp/qbt_cookie.txt"
10
+ REFRESH_INTERVAL=60
11
+ ANIM_SPEED=1
12
+ CAT_MAX=14
13
+
14
+ SERVICES=("Plex Media Server" "Sonarr" "Radarr" "Prowlarr" "AdGuardHome" "syncthing")
15
+ SERVICE_NAMES=("Plex" "Sonarr" "Radarr" "Prowlarr" "AdGuard" "Syncthing")
16
+
17
+ GREEN='\033[1;32m'
18
+ RED='\033[1;31m'
19
+ CYAN='\033[1;36m'
20
+ YELLOW='\033[1;33m'
21
+ MAGENTA='\033[1;35m'
22
+ WHITE='\033[1;37m'
23
+ DIM='\033[0;37m'
24
+ NC='\033[0m'
25
+ CL='\033[K'
26
+ RC='\033[34G'
27
+
28
+ cleanup() {
29
+ rm -f "$QBIT_COOKIE"
30
+ tput reset
31
+ }
32
+ trap cleanup EXIT INT TERM
33
+
34
+ check_services() {
35
+ local down=""
36
+ for i in "${!SERVICES[@]}"; do
37
+ pgrep -q "${SERVICES[$i]}" || down="${down}${SERVICE_NAMES[$i]} "
38
+ done
39
+ if [ -z "$down" ]; then
40
+ printf "${YELLOW}║${NC} Services: ${GREEN}ALL OK${NC}${CL}${RC}${YELLOW}║${NC}\n"
41
+ else
42
+ printf "${YELLOW}║${NC} Services: ${RED}DOWN: ${down}${NC}${CL}${RC}${YELLOW}║${NC}\n"
43
+ fi
44
+ }
45
+
46
+ check_disk() {
47
+ if mount | grep -q Saved_Media; then
48
+ local disk_info
49
+ disk_info=$(df -h /Volumes/Saved_Media | awk 'NR==2{gsub(/%/,"%%",$5); print $5}')
50
+ printf "${YELLOW}║${NC} Storage: ${GREEN}${disk_info}${NC}${CL}${RC}${YELLOW}║${NC}\n"
51
+ else
52
+ printf "${YELLOW}║${NC} Storage: ${DIM}NOT CONNECTED${NC}${CL}${RC}${YELLOW}║${NC}\n"
53
+ fi
54
+ }
55
+
56
+ check_streams() {
57
+ local stream_count
58
+ stream_count=$(curl -s "${PLEX_URL}/status/sessions?X-Plex-Token=${PLEX_TOKEN}" -H "Accept: application/json" 2>/dev/null | python3 -c '
59
+ import json,sys
60
+ try:
61
+ d=json.load(sys.stdin)
62
+ print(d["MediaContainer"]["size"])
63
+ except: print("0")' 2>/dev/null)
64
+ if [ "$stream_count" = "0" ]; then
65
+ printf "${YELLOW}║${NC} Streaming: ${DIM}0${NC}${CL}${RC}${YELLOW}║${NC}\n"
66
+ else
67
+ printf "${YELLOW}║${NC} Streaming: ${MAGENTA}${stream_count}${NC}${CL}${RC}${YELLOW}║${NC}\n"
68
+ fi
69
+ }
70
+
71
+ check_downloads() {
72
+ curl -s --max-time 3 "${QBIT_URL}/api/v2/auth/login" -d "username=${QBIT_USER}&password=${QBIT_PASS}" -c "$QBIT_COOKIE" >/dev/null 2>&1
73
+ local qbt
74
+ qbt=$(curl -s --max-time 3 "${QBIT_URL}/api/v2/transfer/info" -b "$QBIT_COOKIE" 2>/dev/null | python3 -c '
75
+ import json,sys
76
+ try:
77
+ d=json.load(sys.stdin)
78
+ dl=d.get("dl_info_speed",0)
79
+ if dl > 0:
80
+ mb=dl/1024/1024
81
+ print("DL: "+str(round(mb,1))+" MB/s")
82
+ else:
83
+ print("Idle")
84
+ except: print("---")' 2>/dev/null)
85
+ if [ "$qbt" = "Idle" ] || [ "$qbt" = "---" ]; then
86
+ printf "${YELLOW}║${NC} Downloads: ${DIM}${qbt}${NC}${CL}${RC}${YELLOW}║${NC}\n"
87
+ else
88
+ printf "${YELLOW}║${NC} Downloads: ${GREEN}${qbt}${NC}${CL}${RC}${YELLOW}║${NC}\n"
89
+ fi
90
+ }
91
+
92
+ draw_header() {
93
+ printf "${YELLOW}╔════════════════════════════════╗${NC}${CL}\n"
94
+ printf "${YELLOW}║${NC} ${YELLOW}★${NC} ${WHITE}MEDIA SERVER${NC} ${YELLOW}★${NC}${CL}${RC}${YELLOW}║${NC}\n"
95
+ printf "${YELLOW}╠════════════════════════════════╣${NC}${CL}\n"
96
+ }
97
+
98
+ draw_links() {
99
+ printf "${YELLOW}┌──────────┬─────────────────────┐${NC}${CL}\n"
100
+ printf "${YELLOW}│${NC} Plex ${YELLOW}│${NC} ${CYAN}http://plex.lan${NC} ${YELLOW}│${NC}${CL}\n"
101
+ printf "${YELLOW}│${NC} Radarr ${YELLOW}│${NC} ${CYAN}http://radarr.lan${NC} ${YELLOW}│${NC}${CL}\n"
102
+ printf "${YELLOW}│${NC} Sonarr ${YELLOW}│${NC} ${CYAN}http://sonarr.lan${NC} ${YELLOW}│${NC}${CL}\n"
103
+ printf "${YELLOW}│${NC} Prowlarr ${YELLOW}│${NC} ${CYAN}http://prowlarr.lan${NC} ${YELLOW}│${NC}${CL}\n"
104
+ printf "${YELLOW}│${NC} AdGuard ${YELLOW}│${NC} ${CYAN}http://adguard.lan${NC} ${YELLOW}│${NC}${CL}\n"
105
+ printf "${YELLOW}│${NC} Sync ${YELLOW}│${NC} ${CYAN}http://sync.lan${NC} ${YELLOW}│${NC}${CL}\n"
106
+ printf "${YELLOW}│${NC} qBit ${YELLOW}│${NC} ${CYAN}http://qbit.lan${NC} ${YELLOW}│${NC}${CL}\n"
107
+ printf "${YELLOW}└──────────┴─────────────────────┘${NC}${CL}\n"
108
+ }
109
+
110
+ animate_cat() {
111
+ local last_line=$(($(tput lines) - 1))
112
+ for _ in $(seq 1 "$REFRESH_INTERVAL"); do
113
+ tput cup "$last_line" 0
114
+ printf "${CL}"
115
+ tput cup "$last_line" "$CAT_POS"
116
+ if [ "$CAT_DIR" -eq 1 ]; then
117
+ printf "${DIM}~(=^..^)${NC}"
118
+ else
119
+ printf "${DIM}(^..^=)~${NC}"
120
+ fi
121
+ CAT_POS=$((CAT_POS + CAT_DIR))
122
+ if [ "$CAT_POS" -ge "$CAT_MAX" ]; then
123
+ CAT_DIR=-1
124
+ elif [ "$CAT_POS" -le 0 ]; then
125
+ CAT_DIR=1
126
+ fi
127
+ sleep "$ANIM_SPEED"
128
+ done
129
+ }
130
+
131
+ CAT_POS=0
132
+ CAT_DIR=1
133
+
134
+ clear
135
+ while true; do
136
+ tput cup 0 0
137
+ draw_header
138
+ check_services
139
+ check_disk
140
+ check_streams
141
+ check_downloads
142
+ printf "${YELLOW}╠════════════════════════════════╣${NC}${CL}\n"
143
+ printf "${YELLOW}║${NC} ${DIM}Up: $(uptime | sed 's/.*up //' | sed 's/,.*//')${NC}${CL}${RC}${YELLOW}║${NC}\n"
144
+ printf "${YELLOW}╚════════════════════════════════╝${NC}${CL}\n"
145
+ printf "${CL}\n"
146
+ draw_links
147
+ tput ed
148
+ animate_cat
149
+ done
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: terminal-dashboard
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - embmeals
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-02-02 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A minimal, self-contained bash dashboard for monitoring a home media
14
+ server. Displays service health, disk usage, active Plex streams, download speed,
15
+ uptime, and quick-access links in a single terminal window.
16
+ email:
17
+ executables:
18
+ - terminal-dashboard
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - bin/terminal-dashboard
23
+ - lib/dashboard.sh
24
+ homepage: https://github.com/embmeals/terminal-dashboard
25
+ licenses:
26
+ - MIT
27
+ metadata:
28
+ homepage_uri: https://github.com/embmeals/terminal-dashboard
29
+ source_code_uri: https://github.com/embmeals/terminal-dashboard
30
+ bug_tracker_uri: https://github.com/embmeals/terminal-dashboard/issues
31
+ post_install_message:
32
+ rdoc_options: []
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '2.0'
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ requirements: []
46
+ rubygems_version: 3.0.3.1
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: Terminal-based media server status dashboard with cat animation
50
+ test_files: []