Files
NubNix/home-manager/20_eww/02_scripts.nix
2025-11-13 14:15:48 +00:00

629 lines
26 KiB
Nix
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{ config, pkgs, ... }:
{
home.file.".config/eww/scripts/ascii/ascii_core_layout.sh".file = ''
#!/usr/bin/env bash
#
# ascii_core_layout.sh
# Gets the current Hyprland workspace ID and writes a small ASCII frame
# to /tmp/core_layout.txt.
# Example output (written to /tmp/core_layout.txt):
#
# [ 2 ]
#
#
ws=$(hyprctl activeworkspace -j | jq -r '.id')
cat <<EOF > /tmp/core_layout.txt
[ $ws ]
EOF
'';
home.file.".config/eww/scripts/audio/audio_cava_status.sh".file = ''
#!/usr/bin/env bash
#
# Checks whether the ASCII visualizer output file (/tmp/visualizer.txt)
# is actively updating by comparing MD5 hashes between loops.
# Outputs simple text.
# Called by ascii_audio_status window
#
VIS_FILE="/tmp/visualizer.txt"
HASH_FILE="/tmp/.last_vis_hash"
# Safety checks
if [ ! -s "$VIS_FILE" ]; then
echo "[ CORE STATUS: ] Standby."
exit 0
fi
# Hash current frame
if command -v md5sum >/dev/null 2>&1; then
CURRENT=$(md5sum "$VIS_FILE" | awk '{print $1}')
elif command -v md5 >/dev/null 2>&1; then # macOS/BSD fallback
CURRENT=$(md5 -q "$VIS_FILE")
else
echo "[ CORE STATUS: ] Unknown (no md5 tool found)"
exit 1
fi
LAST=$(cat "$HASH_FILE" 2>/dev/null || echo "")
# Save current hash for next check
echo "$CURRENT" > "$HASH_FILE"
# Compare
if [ "$CURRENT" = "$LAST" ] && [ -n "$LAST" ]; then
echo "[ CORE STATUS: ] Inactive."
else
echo "[ CORE STATUS: ] Generating visuals."
fi
'';
home.file.".config/eww/scripts/audio/audio_visualizer.py".text = ''
#!/usr/bin/env python3
#
# °˖* ( )🍸 pewdiepie/archdaemon/dionysh shhheersh
# vers. 1.0
#
# Reads /tmp/cava.raw and writes an ASCIIart file that can be shown by eww,
# waybar, or any terminal widget. Can run as exec once in hyprland config.
#
import argparse
import os
import signal
import sys
import time
import numpy as np
# Default visual parameters
DEFAULT_WIDTH = 64
DEFAULT_HEIGHT = 12
DEFAULT_FPS = 30
DEFAULT_DECAY = 0.92 # lower longer trails
CHARS = [" ", ".", ":", "·", "", ""] # ascending intensity
def parse_frame(line: str, width: int) -> list[int]:
"""Turn a semicolonseparated line from CAVA into a list of ints."""
try:
return [int(x) for x in line.strip().split(";") if x][:width]
except ValueError:
return [0] * width
def normalize(vals: list[int]) -> np.ndarray:
"""Scale values to the range [0, 1]."""
arr = np.array(vals, dtype=float)
return (arr - arr.min()) / (arr.max() - arr.min() + 1e-5)
def get_char_index(val: float) -> int:
"""Map a normalized value to the appropriate character index."""
return min(int(val * (len(CHARS) - 1)), len(CHARS) - 1)
def build_frame(_, history: np.ndarray, height: int, width: int) -> list[str]:
"""Create the ASCII rows from the decay buffer."""
frame = [[" " for _ in range(width)] for _ in range(height)]
for x in range(width):
for y in range(height):
strength = history[y, x]
idx = get_char_index(strength)
frame[height - y - 1][x] = CHARS[idx]
# No baseline drawing the remove request is satisfied
return ["".join(row) for row in frame]
def run(
cava_path: str,
out_path: str,
width: int = DEFAULT_WIDTH,
height: int = DEFAULT_HEIGHT,
fps: int = DEFAULT_FPS,
decay: float = DEFAULT_DECAY,
) -> None:
"""Main loop read CAVA output, update the decay buffer, write ASCII."""
os.makedirs(os.path.dirname(out_path), exist_ok=True)
decay_buffer = np.zeros((height, width), dtype=float)
while True:
try:
with open(cava_path, "r") as f:
# read one line at a time from the FIFO
line = f.readline()
if not line:
time.sleep(1.0 / fps)
continue
except Exception:
time.sleep(1.0 / fps)
continue
# 1 Parse & normalise
values = parse_frame(line, width)
values = normalize(values) if values else np.zeros(width)
# 2 Build a binary bars matrix for the current frame
new_frame = np.zeros((height, width), dtype=float)
for i, val in enumerate(values):
bar_h = int(val * height)
new_frame[:bar_h, i] = 1.0
# 3 Apply decay (trails) and blend with the new frame
decay_buffer = np.maximum(decay_buffer * decay, new_frame)
# 4 Render ASCII and write out
ascii_lines = build_frame(values, decay_buffer, height, width)
with open(out_path, "w") as out:
out.write("\n".join(ascii_lines))
time.sleep(1.0 / fps)
def _handle_sigint(signum, frame):
"""Graceful exit on CtrlC."""
print("\n[+] CAVA ASCII visualizer stopped.")
sys.exit(0)
def main() -> None:
parser = argparse.ArgumentParser(
description="CAVA ASCII visualizer (compatible with eww/widgets)",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument("--cava-path", default="/tmp/cava.raw",
help="Path to CAVA raw output file")
parser.add_argument("--out-path", default="/tmp/visualizer.txt",
help="File where ASCII art will be written")
parser.add_argument("--width", type=int, default=DEFAULT_WIDTH,
help="Number of columns (match CAVA `bars` setting)")
parser.add_argument("--height", type=int, default=DEFAULT_HEIGHT,
help="Number of rows in the ASCII canvas")
parser.add_argument("--fps", type=int, default=DEFAULT_FPS,
help="Refresh rate (frames per second)")
parser.add_argument("--decay", type=float, default=DEFAULT_DECAY,
help="Trailfade factor (01, lower = slower fade)")
args = parser.parse_args()
signal.signal(signal.SIGINT, _handle_sigint)
print("[+] Starting CAVA ASCII visualizer ")
run(
cava_path=args.cava_path,
out_path=args.out_path,
width=args.width,
height=args.height,
fps=args.fps,
decay=args.decay,
)
if __name__ == "__main__":
main()
'';
home.file.".config/eww/scripts/bar/bar_render.sh" = ''
#!/usr/bin/env bash
#
# Converts a numeric percentage (0100) into an ASCII block bar.
# Example:
# ./usage_render_bar.sh 73
#
#
usage=$1 # pass percentage as the first argument
full=""
half=""
empty=""
blocks=10
filled=$(( usage * blocks / 100 ))
bar=""
for ((i=0; i<blocks; i++)); do
if [ $i -lt $filled ]; then
bar+="$full"
else
bar+="$empty"
fi
done
echo "$bar"
'';
home.file.".config/eww/scripts/net/net_download.sh".text = ''
#!/usr/bin/env bash
#
# net_download.sh
# Samples network traffic on a given interface and reports download usage
# as a percentage (0100) of a configured max speed.
#
# Usage: ./net_download.sh
# Example: output "42" meaning 42% of max throughput.
#
#
iface="wlp4s0" # Wi-Fi interface
max_speed=12500000 # adjust: this is 100 Mbps (100*1e6 / 8)
# First sample
rx1=$(awk -v iface=$iface '$1 ~ iface {gsub(":", "", $1); print $2}' /proc/net/dev)
sleep 1
# Second sample
rx2=$(awk -v iface=$iface '$1 ~ iface {gsub(":", "", $1); print $2}' /proc/net/dev)
bps=$((rx2 - rx1)) # bytes per second
percent=$((bps * 100 / max_speed))
# Clamp between 0100
if [ "$percent" -gt 100 ]; then percent=100; fi
if [ "$percent" -lt 0 ]; then percent=0; fi
echo $percent
'';
home.file.".config/eww/scripts/net/net_download_bar.sh".text = ''
#!/usr/bin/env bash
#
# upload_bar.sh
# Renders a vertical bar (5 lines) from a given percentage (0100).
#
# Usage: ./upload_bar.sh <percent>
# Example: ./upload_bar.sh 73
# Output (top to bottom):
#
#
#
#
#
#
percent=$1
lines=5
# Cap the percent between 0 and 100
if [ "$percent" -gt 100 ]; then percent=100; fi
if [ "$percent" -lt 0 ]; then percent=0; fi
# Calculate how many rows to fill
filled=$((percent * lines / 100))
# Always show at least one block if >0
if (( percent > 0 && filled == 0 )); then
filled=1
fi
# Draw from top to bottom
for ((i=0; i<lines; i++)); do
row=$((lines - i)) # count from top
if (( row <= filled )); then
if (( row == filled )); then
echo ""
else
echo ""
fi
else
echo ""
fi
done
'';
home.file.".config/eww/scripts/net/net_ping.sh".text = ''
#!/usr/bin/env bash
#
# net_ping.sh
# Measures ICMP ping latency to 139.162.207.118 (natalie) and outputs the result in milliseconds.
# If the host is unreachable, prints "0".
#
# Usage: ./net_ping.sh
# Example: ./net_ping.sh 24 (ms)
#
# Requires: ping (iputils)
#
ping -c 1 -w 2 139.162.207.118 2>/dev/null \
| grep 'time=' \
| awk -F'time=' '{print int($2)}' \
|| echo 0
'';
home.file.".config/eww/scripts/net/ping_latency.sh".text = ''
#!/usr/bin/env bash
#
# net_ping_latency.sh
# Visualizes ping latency as a vertical bar (5 lines).
#
# Usage: ./net_ping_latency.sh <ms>
# Example: ./net_ping_latency.sh 120
# Output (top to bottom):
#
#
#
#
#
#
ms=$1
lines=5
max_ms=200 # adjust scale (200ms = 100%)
# Scale ping ms percentage
percent=$(( ms * 100 / max_ms ))
if [ "$percent" -gt 100 ]; then percent=100; fi
if [ "$percent" -lt 0 ]; then percent=0; fi
# Calculate filled rows
filled=$(( (percent * lines + 99) / 100 ))
if (( ms > 0 && filled == 0 )); then
filled=1
fi
for ((i=0; i<lines; i++)); do
row=$((lines - i))
if (( row <= filled )); then
if (( row == filled )); then
echo ""
else
echo ""
fi
else
echo ""
fi
done
'';
home.file.".config/eww/scripts/net/net_upload.sh".text = ''
#!/usr/bin/env bash
#
# net_upload.sh
# Samples network traffic on a given interface and reports upload usage
# as a percentage (0100) of a configured max speed.
#
iface="wlp4s0" # your active Wi-Fi interface (from `ip -br link`)
max_speed=12500000 # 100 Mbps = 100e6 / 8 (bytes/sec). Adjust if faster.
# First sample
tx1=$(awk -v iface=$iface '$1 ~ iface {gsub(":", "", $1); print $10}' /proc/net/dev)
sleep 1
# Second sample
tx2=$(awk -v iface=$iface '$1 ~ iface {gsub(":", "", $1); print $10}' /proc/net/dev)
bps=$((tx2 - tx1)) # bytes per second
percent=$((bps * 1000 / max_speed)) # scaled ×10 for sensitivity
# Clamp between 0100
if [ "$percent" -gt 100 ]; then percent=100; fi
if [ "$percent" -lt 0 ]; then percent=0; fi
echo $percent
'';
home.file.".config/eww/scripts/net/net_upload_bar.sh".text = ''
#!/usr/bin/env bash
#
# upload_bar.sh
# Renders a vertical bar (5 lines) from a given percentage (0100).
#
# Usage: ./upload_bar.sh <percent>
# Example: ./upload_bar.sh 73
# Output (top to bottom):
#
#
#
#
#
#
percent=$1
lines=5
# Cap 0100
if [ "$percent" -gt 100 ]; then percent=100; fi
if [ "$percent" -lt 0 ]; then percent=0; fi
# Scale percentage into rows (round up)
filled=$(( (percent * lines + 99) / 100 ))
# Always show at least one block if >0
if (( percent > 0 && filled == 0 )); then
filled=1
fi
# Draw from top to bottom
for ((i=0; i<lines; i++)); do
row=$((lines - i)) # count from top
if (( row <= filled )); then
if (( row == filled )); then
echo ""
else
echo ""
fi
else
echo ""
fi
done
'';
home.file.".config/eww/scripts/net/net_vpn.sh".text = ''
#!/usr/bin/env bash
#
# net_vpn.sh
# Checks if VPN (10.6.0.x) is active, outputs 100 (on) or 0 (off).
# Example: VPN connected 100
# VPN disconnected 0
#
if ip a | grep -q "10\.6\."; then
echo 100
else
echo 0
fi
'';
home.file.".config/eww/scripts/net/net_vpn_bar.sh".text = ''
#!/usr/bin/env bash
# ~/.config/eww/scripts/net/net_vpn_bar.sh
# Render a 5-line bar directly based on VPN (ipsec) status.
lines=5
if sudo /usr/bin/ipsec statusall 2>/dev/null | grep -q "ESTABLISHED"; then
# VPN is up full block bar
for ((i=0; i<lines; i++)); do
echo ""
done
else
# VPN is down thin bar
for ((i=0; i<lines; i++)); do
echo ""
done
fi
'';
home.file.".config/eww/scripts/net/net_vpn_status.sh".text = ''
#!/usr/bin/env bash
# ~/.config/eww/scripts/net/net_vpn_status.sh
# Show VPN status + country (for Eww)
if sudo /usr/bin/ipsec statusall 2>/dev/null | grep -q "ESTABLISHED"; then
country=$(curl -s ifconfig.co/country 2>/dev/null)
[[ -z "$country" ]] && country="НЕУСТАНОВЛЕНО"
echo "[УЗЕЛ] $country"
else
echo "[НЕТ СВЯЗИ]"
fi
'';
home.file.".config/eww/scripts/sys/sys_cpu_voltage.sh".text = ''
#!/usr/bin/env bash
#
# sys_dc_voltage.sh
# Reads the VDDNB (SoC / NB voltage) from lm-sensors and prints it in mV.
# Requires: lm-sensors (run `sensors-detect` to configure chip readings).
#
sensors | awk '/vddnb:/ {printf "%s mV\n", $2}' || echo "N/A"
'';
home.file.".config/eww/scripts/sys/sys_dc_voltage.sh".text = ''
#!/bin/bash
#
# sys_cpu_voltage.sh
# Reads CPU voltage (in0) from lm-sensors and prints it in volts.
# Requires: lm-sensors (and sensors-detect configured)
#
sensors | awk '/in0:/ {print $2 " V"}' || echo "N/A"
'';
home.file.".config/eww/scripts/sys/sys_fan_bar.sh".text = ''
#!/usr/bin/env bash
#
# bar_render.sh
# Renders a simple horizontal bar graph from a percentage value.
# Example: ./bar_render.sh 75
#
usage=$1 # percent or normalized value
full=""
empty=""
blocks=10
filled=$(( usage * blocks / 100 ))
bar=""
for ((i=0; i<blocks; i++)); do
if [ $i -lt $filled ]; then
bar+="$full"
else
bar+="$empty"
fi
done
echo "$bar"
'';
home.file.".config/eww/scripts/sys/sys_fan_spin.sh".text = ''
#!/usr/bin/env bash
#
# Script: sys_fan_spin.sh
# Purpose: Displays fan spinner animation (CPU/GPU) based on RPM
# Example:
# ./sys_fan_spin.sh cpu
#
SPIN=('|' '/' '-' '\\')
fan="$1"
# Simple cache file to track frame index across calls
cache="/tmp/${fan}_fan_frame"
if [ -f "$cache" ]; then
index=$(<"$cache")
else
index=0
fi
# Advance frame
index=$(( (index + 1) % ${#SPIN[@]} ))
echo "$index" > "$cache"
# Get RPM
if [ "$fan" = "cpu" ]; then
rpm=$(sensors | grep -i 'cpu_fan' | awk '{print $2}')
elif [ "$fan" = "gpu" ]; then
rpm=$(sensors | grep -i 'gpu_fan' | awk '{print $2}')
else
rpm=0
fi
[ -z "$rpm" ] && rpm=0
if [ "$rpm" -eq 0 ]; then
echo "|"
else
echo "${SPIN[$index]}"
fi
'';
home.file.".config/eww/scripts/sys/sys_gpu_voltage.sh".text = ''
#!/bin/bash
# ─────────────────────────────────────────────────────────────────────────────
# Reads NVIDIA GPU voltage using nvidia-smi and prints it in millivolts.
# ─────────────────────────────────────────────────────────────────────────────
sensors | awk '/vddgfx/ {print $2 " mV"}' || echo "N/A"
'';
home.file.".config/eww/scripts/sys/sys_workspace.sh".text = ''
#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────────────────────
# Prints the status of workspaces 14 in Hyprland, marking the active one.
# Output format: "wsN= [ ACTIVE ]" or "wsN= [INACTIVE]"
# ─────────────────────────────────────────────────────────────────────────────
# Get active workspace ID (requires jq + hyprctl)
CURRENT=$(hyprctl activeworkspace -j 2>/dev/null | jq -r '.id')
# Fallback if query fails
if [[ -z "$CURRENT" || "$CURRENT" == "null" ]]; then
echo "[!] Could not determine active workspace."
exit 1
fi
for i in {1..4}; do
if [[ "$i" -eq "$CURRENT" ]]; then
echo "ws${i}= [ ACTIVE ]"
else
echo "ws${i}= [INACTIVE]"
fi
done
'';
}