Share your plugins #12
Replies: 126 comments 396 replies
-
Window TitleDESCRIPTION: This will display the current window's title in your bar. If the window's title is greater than 50 characters it will truncate it, if there it no title available it will fall back to the application name. This was written by @FelixKratz and Modified by me. NOTE: Assuming you are using yabai, you can quickly check window titles and app names of the current window with Updated Configuration: sketchybarrc# E V E N T S
sketchybar -m --add event window_focus \
--add event title_change
# W I N D O W T I T L E
sketchybar -m --add item title left \
--set title script="$HOME/.config/sketchybar/plugins/window_title.sh" \
--subscribe title window_focus front_app_switched space_change title_change window_title.sh#!/bin/bash
# W I N D O W T I T L E
WINDOW_TITLE=$(/opt/homebrew/bin/yabai -m query --windows --window | jq -r '.title')
if [[ $WINDOW_TITLE = "" ]]; then
WINDOW_TITLE=$(/opt/homebrew/bin/yabai -m query --windows --window | jq -r '.app')
fi
if [[ ${#WINDOW_TITLE} -gt 50 ]]; then
WINDOW_TITLE=$(echo "$WINDOW_TITLE" | cut -c 1-50)
sketchybar -m --set title label="│ $WINDOW_TITLE"…
exit 0
fi
sketchybar -m --set title label="│ $WINDOW_TITLE" yabairc # S K E T C H Y B A R E V E N T S
yabai -m signal --add event=window_focused action="sketchybar -m --trigger window_focus &> /dev/null"
yabai -m signal --add event=window_title_changed action="sketchybar -m --trigger title_change &> /dev/null" |
Beta Was this translation helpful? Give feedback.
-
24 Hour Change in Bitcoin PriceDESCRIPTION: This will display the 24hr change in price of bitcoin in your bar. sketchybarrcsketchybar -m --add item btc right \
--set btc icon= \
--set btc update_freq=20 \
--set btc script="~/.config/sketchybar/plugins/btc.sh" btc.sh#!/usr/bin/env python3
import requests
import os
response = requests.get('https://api.gemini.com/v1/pricefeed')
jsonResponse = response.json()
for i in jsonResponse:
if i["pair"] == "BTCUSD":
percentChange = str(round((float(i["percentChange24h"]) * 100), 2))
os.system('sketchybar -m --set btc label='+ percentChange + '%')
break |
Beta Was this translation helpful? Give feedback.
-
24 Hour Change in Ethereum PriceDESCRIPTION: This will display the 24hr change in price of Ethereum in your bar. sketchybarrcsketchybarrcsketchybar -m --add item eth right \
--set eth icon=ﲹ \
--set eth update_freq=20 \
--set eth script="~/.config/sketchybar/plugins/eth.sh" eth.sh#!/usr/bin/env python3
import requests
import os
response = requests.get('https://api.gemini.com/v1/pricefeed')
jsonResponse = response.json()
for i in jsonResponse:
if i["pair"] == "BTCUSD":
percentChange = str(round((float(i["percentChange24h"]) * 100), 2))
os.system('sketchybar -m --set eth label='+ percentChange + '%')
break |
Beta Was this translation helpful? Give feedback.
-
Battery StatusDESCRIPTION: This will display your current battery status. NOTE: This could probably be improved on greatly. I am not sure what an appropriate UPDATED: Updated to implement improvements made by ut0mt8 from this comment. sketchybarrcsketchybar -m --add item battery right \
--set battery update_freq=3 \
--set battery script="~/.config/sketchybar/plugins/power.sh" \
--set battery icon= power.sh#!/bin/bash
. ~/.cache/wal/colors.sh
BATT_PERCENT=$(pmset -g batt | grep -Eo "\d+%" | cut -d% -f1)
CHARGING=$(pmset -g batt | grep 'AC Power')
if [[ $CHARGING != "" ]]; then
sketchybar -m --set battery \
icon.color=0xFF5DFE67 \
icon= \
label=$(printf "${BATT_PERCENT}%%")
exit 0
fi
[[ ${BATT_PERCENT} -gt 10 ]] && COLOR=0xFF${color5:1} || COLOR=0xFFFF0000
case ${BATT_PERCENT} in
100) ICON="" ;;
9[0-9]) ICON="" ;;
8[0-9]) ICON="" ;;
7[0-9]) ICON="" ;;
6[0-9]) ICON="" ;;
5[0-9]) ICON="" ;;
4[0-9]) ICON="" ;;
3[0-9]) ICON="" ;;
2[0-9]) ICON="" ;;
1[0-9]) ICON="" ;;
*) ICON=""
esac
sketchybar -m --set battery\
icon.color=$COLOR \
icon=$ICON \
label=$(printf "${BATT_PERCENT}%%") |
Beta Was this translation helpful? Give feedback.
-
Music InformationUpdate History:
DESCRIPTION: This will display information about the current track in the Music.app. It will update based on the NSDistributedNotificationCenter Events sent by the Music app. sketchybarrc# Add event
sketchybar -m --add event song_update com.apple.iTunes.playerInfo
# Add Music Item
sketchybar -m --add item music right \
--set music script="~/.config/sketchybar/scripts/music" \
click_script="~/.config/sketchybar/scripts/music_click" \
label.padding_right=10 \
drawing=off \
--subscribe music song_update music#!/usr/bin/env bash
# FIXME: Running an osascript on an application target opens that app
# This sleep is needed to try and ensure that theres enough time to
# quit the app before the next osascript command is called. I assume
# com.apple.iTunes.playerInfo fires off an event when the player quits
# so it imediately runs before the process is killed
sleep 1
APP_STATE=$(pgrep -x Music)
if [[ ! $APP_STATE ]]; then
sketchybar -m --set music drawing=off
exit 0
fi
PLAYER_STATE=$(osascript -e "tell application \"Music\" to set playerState to (get player state) as text")
if [[ $PLAYER_STATE == "stopped" ]]; then
sketchybar --set music drawing=off
exit 0
fi
title=$(osascript -e 'tell application "Music" to get name of current track')
artist=$(osascript -e 'tell application "Music" to get artist of current track')
# ALBUM=$(osascript -e 'tell application "Music" to get album of current track')
loved=$(osascript -l JavaScript -e "Application('Music').currentTrack().loved()")
if [[ $loved ]]; then
icon=""
fi
if [[ $PLAYER_STATE == "paused" ]]; then
icon=""
fi
if [[ $PLAYER_STATE == "playing" ]]; then
icon=""
fi
if [[ ${#title} -gt 25 ]]; then
TITLE=$(printf "$(echo $title | cut -c 1-25)…")
fi
if [[ ${#artist} -gt 25 ]]; then
ARTIST=$(printf "$(echo $artist | cut -c 1-25)…")
fi
# if [[ ${#ALBUM} -gt 25 ]]; then
# ALBUM=$(printf "$(echo $ALBUM | cut -c 1-12)…")
# fi
sketchybar -m --set music icon="$icon" \
--set music label="${title} x ${artist}" \
--set music drawing=on
music_click#!/usr/bin/env osascript
tell application "Music"
if loved of current track is true then
set loved of current track to false
do shell script "sketchybar -m --set music icon="
else
set loved of current track to true
do shell script "sketchybar -m --set music icon="
end if
end tell
delay 1
do shell script "sh $HOME/.config/sketchybar/scripts/music" |
Beta Was this translation helpful? Give feedback.
-
VPN StatusDESCRIPTION: Shows the vpn your currently connected to if any in your bar. sketchybarrcsketchybar -m --add item vpn right \
--set vpn icon= \
update_freq=5 \
script="~/.config/sketchybar/plugins/vpn.sh" vpn.sh#!/bin/bash
VPN=$(scutil --nc list | grep Connected | sed -E 's/.*"(.*)".*/\1/')
if [[ $VPN != "" ]]; then
sketchybar -m --set vpn icon= \
label="$VPN" \
drawing=on
else
sketchybar -m --set vpn drawing=off
fi |
Beta Was this translation helpful? Give feedback.
-
Mic StatusDESCRIPTION: Check and Mute/Unmute your mic. sketchybarrcsketchybar -m --add item mic right \
sketchybar -m --set mic update_freq=3 \
--set mic script="~/.config/sketchybar/plugins/mic.sh" \
--set mic click_script="~/.config/sketchybar/plugins/mic_click.sh" mic.sh#!/bin/bash
MIC_VOLUME=$(osascript -e 'input volume of (get volume settings)')
if [[ $MIC_VOLUME -eq 0 ]]; then
sketchybar -m --set mic icon=
elif [[ $MIC_VOLUME -gt 0 ]]; then
sketchybar -m --set mic icon=
fi
mic_click.sh#!/bin/bash
MIC_VOLUME=$(osascript -e 'input volume of (get volume settings)')
if [[ $MIC_VOLUME -eq 0 ]]; then
osascript -e 'set volume input volume 25'
sketchybar -m --set mic icon=
elif [[ $MIC_VOLUME -gt 0 ]]; then
osascript -e 'set volume input volume 0'
sketchybar -m --set mic icon=
fi |
Beta Was this translation helpful? Give feedback.
This comment has been hidden.
This comment has been hidden.
-
RemindersDESCRIPTION: Show your reminders. NOTE: This is just a very basic script, but it could be extended to show the reminder, or use a different app like taskwarrior or taskell instead. sketchybarrcsketchybar -m --add item reminders right \
--set reminders update_freq=20 \
--set reminders script="~/.config/sketchybar/plugins/reminders.sh" \
--set reminders click_script="~/.config/sketchybar/plugins/reminders_click.sh" reminders.sh#!/bin/bash
REMINDERS_COUNT=$(osascript -l JavaScript -e "Application('Reminders').lists.byName('📥 Inbox').reminders.whose({completed: false}).name().length")
if [[ $REMINDERS_COUNT -gt 0 ]]; then
sketchybar -m --set reminders icon="" \
--set reminders label="$REMINDERS_COUNT"
else
sketchybar -m --set reminders icon="" \
--set reminders label=""
fi reminders_click.sh#!/bin/bash
open -a Reminders |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
This comment has been hidden.
This comment has been hidden.
-
Stack IndicatorDESCRIPTION: Show you Window's Stack Position. NOTE: Occasionally querying yabai can be delayed possibly related to this, which can lead to a number or dot being displayed late and overwriting the actual position in the indicator. sketchybarrc# S T A C K I N D I C A T O R
sketchybar -m --add item stack_sep center \
--add item stack center \
--set stack script="$HOME/.dotfiles/sketchybar/plugins/stack.sh" \
--subscribe stack window_focus front_app_switched space_change title_change \
--set stack_sep drawing=off \
--set stack drawing=off \
--set stack update_freq=0 stack.sh#!/bin/bash
# Exit if Not in Stack
CURRENT=$(yabai -m query --windows --window | jq '.["stack-index"]')
if [[ $CURRENT -eq 0 ]]; then
sketchybar -m --set stack label="" \
--set stack_sep drawing=off \
--set stack drawing=off
exit 0
fi
# Use Numbers in place of Dots if the Stack is greater than 10
# Use a larger font for the unicode dots
LAST=$(yabai -m query --windows --window stack.last | jq '.["stack-index"]')
if [[ $LAST -gt 10 ]]; then
sketchybar -m --set stack label.font="Iosevka Nerd Font:Bold:16.0" \
--set stack label=$(printf "[%s/%s]" "$CURRENT" "$LAST") \
--set stack_sep drawing=on \
--set stack drawing=on
exit 0
else
sketchybar -m --set stack label.font="Iosevka Nerd Font:Bold:22.0"
fi
# Create Stack Indicator
declare -a dots=()
for i in $(seq 0 $(expr $LAST - 1))
do
# Theme 1
# if [[ $i -lt $(expr $CURRENT - 1) ]]; then
# dots+="◖"
# elif [[ $i -gt $(expr $CURRENT - 1) ]]; then
# dots+="◗"
# elif [[ $i -eq $(expr $CURRENT - 1) ]]; then
# dots+="●"
# fi
# Theme 2
[[ $( expr $CURRENT - 1) -eq $i ]] && dots+="●" || dots+="○"
done
# Display Indicator
sketchybar -m --set stack label=$(printf "%s" ${dots[@]}) \
--set stack_sep drawing=on \
--set stack drawing=on |
Beta Was this translation helpful? Give feedback.
-
SKHD Modal IndicatorDESCRIPTION: Show the current SKHD Mode NOTES: You can hardcode the sketchybar commands into your skhdrc. I just use a seperate helper script to clean things up. sketchybarrc# M O D A L I N D I C A T O R
sketchybar -m --add item modal left
sketchybar -m --set modal icon=[N]
sketchybar -m --set modal icon_color =0xFF83A1F1 skhdrc# M O D E S
:: default : $HOME/.config/bin/helpers -n
:: window @ : $HOME/.config/bin/helpers -w
:: scripts @ : $HOME/.config/bin/helpers -s
# Mode Shortcuts
default, scripts < lcmd - escape ; window
window, scripts < escape ; default
default, window < lctrl - escape ; scripts helpersfunction normal_mode() {
echo "N O R M A L M O D E";
# C O L O R S
. $HOME/.cache/wal/colors.sh;
# Y A B A I
yabai -m config active_window_border_color 0xff${color5:1};
yabai -m config normal_window_border_color 0xff${color8:1};
yabai -m config insert_feedback_color 0xff${color5:1};
# S K E T C H Y B A R
sketchybar -m --bar color=0xF0${color0:1}
sketchybar -m --default label.color=0xFF${foreground:1}
sketchybar -m --default icon.color=0xFF${color5:1}
sketchybar -m --set modal icon.color=0xFF83A1F1
sketchybar -m --set modal icon="[N]"
}
# W I N D O W M O D E
function window_mode() {
echo "W I N D O W M O D E";
# C O L O R S
. $HOME/.cache/wal/colors.sh;
# Y A B A I
yabai -m config active_window_border_color 0xff${color3:1};
yabai -m config normal_window_border_color 0xff${color3:1};
yabai -m config insert_feedback_color 0xff${color3:1};
# S K E T C H Y B A R
sketchybar -m --bar color=0xF0${color3:1}
sketchybar -m --default label.color=0xFF${foreground:1}
sketchybar -m --default icon.color=0xFF${background:1}
sketchybar -m --set modal icon.color=0xFFA8CD76
sketchybar -m --set modal icon="[W]"
}
# S C R I P T S M O D E
function scripts_mode() {
echo "S C R I P T S M O D E";
# C O L O R S
. $HOME/.cache/wal/colors.sh;
# Y A B A I
yabai -m config active_window_border_color 0xff${color5:1};
yabai -m config normal_window_border_color 0xff${color5:1};
yabai -m config insert_feedback_color 0xff${color5:1};
# S K E T C H Y B A R
sketchybar -m --bar color=0xF0${color5:1}
sketchybar -m --default label.color=0xFF${foreground:1}
sketchybar -m --default icon.color=0xFF${color6:1}
sketchybar -m --set modal icon.color=0xFFF29B9B
sketchybar -m --set modal icon="[S]"
}
|
Beta Was this translation helpful? Give feedback.
-
yabai helperDESCRIPTION: shows the current yabai space, and the mode. Click the menu item to switch between the sketchybarrcsketchybar -m --add item yabai right
sketchybar -m --set yabai update_freq=3
sketchybar -m --set yabai script="~/.config/sketchybar/plugins/yabai.sh"
sketchybar -m --subscribe yabai space_change
sketchybar -m --set yabai click_script="~/.config/sketchybar/plugins/yabai_click.sh" yabai.sh#!/bin/bash
space_number=$(yabai -m query --spaces --display | jq 'map(select(."focused" == 1))[-1].index')
yabai_mode=$(yabai -m query --spaces --display | jq -r 'map(select(."focused" == 1))[-1].type')
sketchybar -m --set yabai label="$space_number:$yabai_mode" yabai_click.sh#!/bin/bash
space_number=$(yabai -m query --spaces --display | jq 'map(select(."focused" == 1))[-1].index')
yabai_mode=$(yabai -m query --spaces --display | jq -r 'map(select(."focused" == 1))[-1].type')
case "$yabai_mode" in
bsp)
yabai -m config layout stack
;;
stack)
yabai -m config layout float
;;
float)
yabai -m config layout bsp
;;
esac
new_yabai_mode=$(yabai -m query --spaces --display | jq -r 'map(select(."focused" == 1))[-1].type')
sketchybar -m --set yabai label="$space_number:$new_yabai_mode" |
Beta Was this translation helpful? Give feedback.
This comment has been hidden.
This comment has been hidden.
-
Beta Was this translation helpful? Give feedback.
-
I’ve been absolutely inspired by the creativity shared in this thread—so much that I took the liberty of compiling all the amazing SketchyBar plugins into a curated list for easier browsing. This way, newcomers (or anyone looking for fresh ideas!) can quickly explore the awesome setups shared here. If you’d like your config added or have updates, feel free to drop a comment, and I’ll happily include it. A huge thanks to everyone who contributed—your setups are pure eye candy! 🎨 |
Beta Was this translation helpful? Give feedback.
-
Long-Running CommandsI hate polling, especially using commands with a "long" startup time, like top. The trick to running the command once on startup and continuously feeding the output to sketchybar is the --line-buffered option for grep. I use pkill to make sure there's only instance of the script running. This example runs vm_stat 5 to update a used/free memory plugin every 5 seconds. The method also works for:
sketchybarrc
# -*- mode: shell-script; sh-shell: /bin/bash -*-
# shellcheck shell=bash disable=2154
NAME=${NAME:-freemem}
POS=${POS:-left}
CONFIG_DIR=${CONFIG_DIR:-.}
sketchybar --add item "${NAME}" "${POS}" \
--set "${NAME}" script="${CONFIG_DIR}/plugins/${NAME}"
freemem
#!/bin/bash
##################################################
# Command to run. Keep INTERVAL separate so we can change it and
# pkill will still work as expected.
COMMAND="vm_stat"
INTERVAL=5
##################################################
# Get total system RAM
#
# vm.pages: 481346
# vm.pagesize: 16384
PAGES=$(sysctl vm.pages | awk '{ print $2 }')
SIZE=$(sysctl vm.pagesize | awk '{ print $2 }')
RAM=$(bc -e "(${PAGES} * ${SIZE}) / 1048576")
##################################################
# vm_stat output
#
# Mach Virtual Memory Statistics: (page size of 16384 bytes)
# free active specul inactive throttle wired prgable faults copy 0fill reactive purged file-backed anonymous cmprssed cmprssor dcomprs comprs pageins pageout swapins swapouts
# 2717 72829 1469 70151 0 152217 0 8032205K 779260K 1694501K 1850172K 137930K 50038 94411 2004734 187100 2371117K 2451197K 279654K 2349486 33349243 35088860
# 4017 72930 1202 70876 0 150882 24 34799 4061 10464 12110 772 49785 95223 2009473 188747 6903 11706 159 21 8 0
# 3532 71804 1039 69971 0 152467 83 68321 1701 11833 20499 2712 49616 93198 2007284 189821 34326 32439 307 1 401 0
# 4001 72888 903 71127 0 150797 2 34417 1086 4982 11033 1441 49532 95386 2007350 188935 20270 20349 27 0 36 0
##################################################
# Main
case "${SENDER}" in
"forced")
# There can be only one
pkill -QUIT -f "${COMMAND}" >/dev/null 2>&1
${COMMAND} "${INTERVAL}" \
| grep --line-buffered '^ *[0-9]' \
| while read -r -a STATS; do
# free + inactive + prgable
FREE=$(bc -e "(${STATS[0]} + ${STATS[3]} + ${STATS[6]}) / 64")
USED=$(bc -e "${RAM} - ${FREE}")
sketchybar --set "${NAME}" label="U: ${USED} MB / F: ${FREE} MB"
done
;;
esac
|
Beta Was this translation helpful? Give feedback.
-
menu bar anywherei didn't really like the way integration of default menu bar items(aka file edit..) because they were always kind of mispositioned and slow. so when i hit a hotkey combination a menubar opens as a menu under the cursor. https://github.com/acsandmann/menuanywhere ![]() |
Beta Was this translation helpful? Give feedback.
-
icalPal popupHere's another popup to show upcoming events on your calendars. This uses icalPal. It can output in JSON format, which is very handy for scripting. And you can use the colors you've assigned in Calendar.app to match the events. ![]() sketchybarrc#!/bin/bash
NAME=${NAME:-icalPal}
POS=${POS:-left}
##################################################
# Set some icalPal options
export ICALPAL='--days 10 --li 10 --ec Birthdays'
UPDATE_FREQ=$((15 * 60)) # Update the events every 15 minutes
##################################################
# Set the environment
# Homebrew Ruby required
export PATH=/opt/homebrew/opt/ruby/bin:${PATH}
# Install icalPal if it's not already
GEM=$(gem info --exact --installed icalPal)
[ "${GEM}" == "false" ] && gem install --no-document --silent icalPal
# Find icalPal
EXE=$(gem contents --norc icalPal | grep -i '/bin/icalpal$')
##################################################
# Add the item
sketchybar --add item "${NAME}" "${POS}" \
--set "${NAME}" label="$(date "+%b %e")" \
--set "${NAME}" popup.align="${POS}" popup.background.drawing=off \
--set "${NAME}" update_freq="${UPDATE_FREQ}" \
--set "${NAME}" script="EXE=\"${EXE}\" ICALPAL=\"${ICALPAL}\" ${CONFIG_DIR}/plugins/icalPal.sh" \
--subscribe "${NAME}" mouse.{clicked,exited} mouse.exited.global icalPal.sh#!/bin/bash
# shellcheck disable=2086
##################################################
# More icalPal options
export ICALPAL="${ICALPAL} --cmd events --nrd --df %a %b %e, %Y %I:%M -o json"
export ICALPAL_CONFIG=
##################################################
# Set the environment
# Set the path to the awk script
SHADE="./plugins/shade.awk"
# Homebrew Ruby required
export PATH=/opt/homebrew/opt/ruby/bin:${PATH}
##################################################
# Style options
# Day header
day_style=(
background.border_color="0xffffffff"
background.border_width=1
background.color="0xff000000"
background.corner_radius=2
icon.drawing=off
label.background.height=30
label.color="0xffffffff"
label.font.size=15.0
label.font.style=Bold
label.padding_left=8
label.width=300
)
# Events
event_style=(
icon.font.style=Bold
icon.padding_left=8
icon.padding_right=8
icon.width=68
label.width=232
)
##################################################
# Add events to the popup
add_event() {
# Extract the properties we want from the event
TITLE=$(jq -r '.title' <<< "${EVENT}")
SD=$(jq -r '.sdate' <<< "${EVENT}")
AD=$(jq -r '.all_day' <<< "${EVENT}")
COLOR=$(jq -r '.color' <<< "${EVENT}" | grep -Eio '[0-9A-F]{6}')
# Split .sdate into date and time
DATE=${SD/%??????/ }
TIME=${SD/#????????????????/}
# Show day header only when it changes
if [ "${DAY}" != "${DATE}" ]; then
DAY="${DATE}"
sketchybar --add item "${NAME}_d${N}" "popup.${NAME}" \
--set "${NAME}_d${N}" label="${DAY}" "${day_style[@]}"
fi
# Compute colors
# The color from icalPal becomes options for awk
# RRGGBB => "-v r=0xRR -v g=0xGG -v b=0xBB"
RGB=$(sed -E 's/(..)(..)(..)/-v r=0x\1 -v g=0x\2 -v b=0x\3/' <<< "${COLOR}")
BG=$(${SHADE} -v m=lighter ${RGB})
FG=$(${SHADE} -v m=darker ${RGB})
# Italicize all-day events
if [ "${AD}" == "1" ]; then
FONT=Italic
TIME=
else
FONT=Regular
fi
# Add the event
sketchybar --add item "${NAME}_p${N}" "popup.${NAME}" \
--set "${NAME}_p${N}" background.color="${BG}" \
--set "${NAME}_p${N}" icon="${TIME}" icon.color="${FG}" \
--set "${NAME}_p${N}" label="${TITLE}" label.color="${FG}" label.font.style=${FONT} \
--set "${NAME}_p${N}" "${event_style[@]}"
}
##################################################
# Make the popup
make_popup() {
"${EXE}" | jq -c '.[]' | while read -r EVENT; do
add_event
((N++))
done
}
##################################################
# Main
case "${SENDER}" in
# Forced
"forced")
make_popup
;;
# Routine
"routine")
# Refresh the popup
sketchybar --set "/${NAME}_/" drawing=off --remove "/${NAME}_/" \
--set "${NAME}" popup.drawing=off
make_popup
;;
# Mouse clicked
"mouse.clicked")
# Toggle visibility of the popup
sketchybar --set "${NAME}" popup.drawing=toggle
;;
# Mouse exited
"mouse.exited.global" | "mouse.exited")
# Hide the popup
sketchybar --set "${NAME}" popup.drawing=off
;;
esac shade.awk#!/usr/bin/awk -f
# shade.awk -v m=(darker|lighter) -v r=0xFF -v g=0xFF -v b=0xFF
##################################################
# Absolute value
function abs(x) { return x < 0 ? -x : x; }
##################################################
# Convert RGB to HSB
function rgb2hsb(red, green, blue) {
red /= 255; green /= 255; blue /= 255;
max = (red > green ? (red > blue ? red : blue) : (green > blue ? green : blue));
min = (red < green ? (red < blue ? red : blue) : (green < blue ? green : blue));
delta = max - min;
# Hue calculation
if (delta == 0) {
hue = 0;
} else if (max == red) {
hue = 60 * (((green - blue) / delta) % 6);
} else if (max == green) {
hue = 60 * (((blue - red) / delta) + 2);
} else {
hue = 60 * (((red - green) / delta) + 4);
}
if (hue < 0) hue += 360;
# Saturation
sat = (max == 0) ? 0 : delta / max;
sat = sat * 100;
# Brightness
br = max * 100;
}
##################################################
# Convert HSB to RGB
function hsb2rgb(h, s, v) {
s /= 100;
v /= 100;
c = v * s;
x = c * (1 - abs((h / 60) % 2 - 1));
m = v - c;
if (h < 60) { r = c; g = x; b = 0; }
else if (h < 120){ r = x; g = c; b = 0; }
else if (h < 180){ r = 0; g = c; b = x; }
else if (h < 240){ r = 0; g = x; b = c; }
else if (h < 300){ r = x; g = 0; b = c; }
else { r = c; g = 0; b = x; }
red = int((r + m) * 255 + 0.5);
green = int((g + m) * 255 + 0.5);
blue = int((b + m) * 255 + 0.5);
}
##################################################
# Make it darker
function darker(h, s, v) {
if (s < mins) { sat = mins } else { sat = s };
if (v > maxv) { br = maxv } else { br = v };
}
##################################################
# Make it lighter
function lighter(h, s, v) {
if (s > mins) { sat = mins } else { sat = s };
if (v < maxv) { br = maxv } else { br = v };
}
##################################################
# Main
BEGIN {
# Convert to HSB
rgb2hsb(r, g, b);
# Adjust
if (m == "darker") {
mins = 70
maxv = 40
darker(hue, sat, br);
} else {
mins = 15
maxv = 100
lighter(hue, sat, br);
}
# Convert to RGB
hsb2rgb(hue, sat, br);
# Print in a format for sketchybar with 100% opacity
printf("0xff%.2x%.2x%.2x\n", red, green, blue);
} |
Beta Was this translation helpful? Give feedback.
-
Aerospace workspace statusBuilt upon the Aerospace+SketchyBar tutorial. And also utilize the
For example: aerospace.sh#!/usr/bin/env bash
ACTIVE_WORKSPACES=$(aerospace list-windows --all --format %{workspace} | sort -u)
if [ "$1" = "$FOCUSED_WORKSPACE" ]; then
sketchybar --set $NAME background.drawing=on
if printf "%s\n" "${ACTIVE_WORKSPACES[@]}" | grep -Fxq -- "$1"; then
# If current focused workspace is shown on the sketchybar
sketchybar --set $NAME label.color=$RED
fi
fi
if [ "$1" = "$PREV_WORKSPACE" ]; then
sketchybar --set $NAME background.drawing=off
if ! printf "%s\n" "${ACTIVE_WORKSPACES[@]}" | grep -Fxq -- "$1"; then
# If the previous workspace doesn't have any windows
sketchybar --set $NAME label.color=$GREEN
fi
fi items.shsketchybar --add event aerospace_workspace_change
for sid in $(aerospace list-workspaces --all); do
sketchybar --add item space.$sid left \
--subscribe space.$sid aerospace_workspace_change \
--set space.$sid \
icon.padding_left=0 \
icon.padding_right=0 \
label.padding_left=4 \
label.padding_right=5 \
label.font="SF Pro:Semibold:9.0" \
label.color=$GREEN \
background.padding_left=0 \
background.padding_right=0 \
background.color=$GRAY \
background.corner_radius=3 \
background.height=15 \
background.drawing=off \
label="$sid" \
click_script="aerospace workspace $sid" \
script="$PLUGIN_DIR/aerospace.sh $sid"
done
for sid in $(aerospace list-windows --all --format %{workspace} | sort -u); do
sketchybar --set space.$sid \
label.color=$RED
done aerospace.toml# Notify Sketchybar about workspace change
exec-on-workspace-change = ['/bin/bash', '-c',
'sketchybar --trigger aerospace_workspace_change PREV_WORKSPACE=$AEROSPACE_PREV_WORKSPACE FOCUSED_WORKSPACE=$AEROSPACE_FOCUSED_WORKSPACE',
] |
Beta Was this translation helpful? Give feedback.
-
Notion CalendarNotion Calendar (formerly Cron) is a Calendar Management App, and has a very useful feature of a Menu Bar item that shows the upcoming meetings at a glance, and you can join the meeting directly from the Menu bar if it's an online meeting. Since it is an Electron app, after some tinkering, I found out that it uses IndexdDB to store the calendar events. I also found this experimental tool by Google dfindexeddb which can be used to parse a IndexdDB database. Using these, I wrote a javascript plugin to display the latest meeting within 3 hours in the Menu Bar, and also open the meeting link (Google Meet only) if it exists. pip install commandsCPPFLAGS="-I/opt/homebrew/include -L/opt/homebrew/lib" python3 -m pip install --user dfindexeddb
CPPFLAGS="-I/opt/homebrew/include -L/opt/homebrew/lib" python3 -m pip install --user 'dfindexeddb[plugins]' items/cron.sh#!/bin/bash
sketchybar --add item cron right \
--set cron icon= \
label="..." \
# I fixed it to show only on one display since my other monitor is in vertical layout
# display=1 \
update_freq=120 \
icon.font="Hack Nerd Font:Bold:17.0" \
background.drawing=on \
icon.padding_left=12 \
label.padding_right=12 \
# Change your colors accordingly
# background.border_color="$ACCENT_COLOR" \
# background.shadow.color="$ACCENT_COLOR" \
background.border_width=0 \
background.shadow.angle=90 \
background.shadow.distance=1 \
background.shadow.drawing=on \
script="$PLUGIN_DIR/cron.js" plugins/cron.js#!/opt/homebrew/bin/node
import { createReadStream, rmSync } from "fs";
import { createInterface } from "readline";
import { execSync } from "child_process";
const ITEM_NAME = process.env.NAME;
const execute = (COMMAND) =>
execSync(COMMAND, (error) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
});
const JSON_FILE = "cron_data.json";
rmSync(JSON_FILE, { force: true });
const INDEXDB_LOCATION =
process.env.HOME + "/Library/Application Support/Notion Calendar/IndexedDB";
const formatDuration = (time) => {
let duration = time;
if (duration > 60 * 60) {
duration = Math.floor(duration / 60 / 60);
duration =
duration + "h " + Math.floor((time - duration * 60 * 60) / 60) + "m";
} else if (duration > 120) {
duration = Math.floor(duration / 60) + "m";
} else {
duration = "now";
}
return duration;
};
const truncateText = (text, length) => {
if (text.length <= length) {
return text;
}
return text.substr(0, length) + "\u2026";
};
// Set Status to Loading
execute(`
sketchybar --set ${ITEM_NAME} \
icon= \
click_script="" \
`);
// Extract data from IndexedDB
const python = execute("python3 -m site --user-base").toString().trim();
execute(`
${python}/bin/dfindexeddb db \
-s "${INDEXDB_LOCATION}/https_calendar.notion.so_0.indexeddb.leveldb" \
--format chrome \
--use_manifest \
-o jsonl \
>> ${JSON_FILE}
`);
var rd = createInterface({
input: createReadStream(JSON_FILE),
console: false,
});
const events = [];
rd.on("line", function (line) {
const data = JSON.parse(line);
if (data.value?.value?.kind === "calendar#event") {
const summary = data.value.value?.summary;
let startTime = data.value.value?.start?.dateTime;
let endTime = data.value.value?.end?.dateTime;
// Don't process full day events
if (!startTime) {
return;
}
const isStaleData = Boolean(data.recovered);
const timeGap = (new Date(startTime) - new Date()) / 1000;
const isToStart = new Date() < new Date(startTime);
const isCurrentlyOnGoing =
new Date() > new Date(startTime) && new Date() < new Date(endTime);
const isCancelled = data.value.value.status === "cancelled";
const isWithin3Hours = timeGap < 60 * 60 * 3;
const attendees = data.value.value.attendees?.values || [];
const iAmAttending = attendees.some((attendee) => {
return attendee.self && attendee.responseStatus !== "declined";
});
if (
// The data is not stale
!isStaleData &&
// It is within 3 hours from now
isWithin3Hours &&
// The meeting is not cancelled
!isCancelled &&
// Meeting is to start or is ongoing
(isToStart || isCurrentlyOnGoing) &&
// I am attending the meeting
iAmAttending
) {
// Duration by difference of START and END
const duration = (new Date(endTime) - new Date(startTime)) / 1000;
events.push({
summary,
startTime,
endTime,
duration,
meet: data.value.value.hangoutLink,
});
}
}
});
rd.on("close", function () {
// Set status to No Meetings if there are no meetings
if (!events.length) {
execute(`
sketchybar --set ${ITEM_NAME} \
label="No upcoming meetings" \
background.drawing=off \
icon.padding_left=0 \
label.padding_right=0 \
icon= \
click_script="" \
`);
return;
}
// Get latest meeting
const meeting = events.sort((a, b) => {
return new Date(a.startTime) - new Date(b.startTime);
})[0];
const timeGap = formatDuration(
(new Date(meeting.startTime) - new Date()) / 1000,
);
const duration = formatDuration(meeting.duration);
// If meeting is too short doesn't show duration
const durationText = duration === "now" ? "" : ` (${duration})`;
const summary = truncateText(meeting.summary, 15);
const remainingTime = timeGap === "now" ? "" : ` in ${timeGap}`;
const label = `${summary}${durationText}${remainingTime}`;
const icon = meeting.meet ? "" : "";
const clickScript = meeting.meet ? `open -n "${meeting.meet}"` : "";
execute(`
sketchybar --set ${ITEM_NAME} \
background.drawing=on \
icon.padding_left=12 \
label.padding_right=12 \
label="${label}" \
click_script="${clickScript}" \
icon="${icon}"
`);
});
ScreenshotsInitial LoadingIn Office EventOnline Event (Google Meet)When there are no meetings in next 3 hours |
Beta Was this translation helpful? Give feedback.
-
Caffeine / Amphetamine / CaffeinateMac OS has a native command to keep the system awake, and we can use that to have an Amphetamine / Caffeine toggle in the SketchyBar. items/caffeinate.sh#!/bin/bash
sketchybar --add item caffeinate right \
--set caffeinate script="$PLUGIN_DIR/caffeinate.sh" \
click_script="$PLUGIN_DIR/caffeinate.sh" \
icon.font="Hack Nerd Font:Bold:17.0" \
padding_left=0 \
padding_right=0 \
icon= plugins/caffeinate.sh#!/bin/bash
CAFFINATE_ID=$(pmset -g assertions | grep "caffeinate" | awk '{print $2}' | cut -d '(' -f1 | head -n 1)
# It was not a button click
if [ -z "$BUTTON" ]; then
if [ -z "$CAFFINATE_ID" ]; then
sketchybar --set "$NAME" icon=
else
sketchybar --set "$NAME" icon=
fi
exit 0
fi
# It is a mouse click
if [ -z "$CAFFINATE_ID" ]; then
caffeinate -id &
sketchybar --set "$NAME" icon=
else
kill -9 "$CAFFINATE_ID"
sketchybar --set "$NAME" icon=
fi Caffeinate OffCaffeinate On |
Beta Was this translation helpful? Give feedback.
-
Aerospace Workspace Status with Multiple Monitors and Hover + Transition EffectsBuilding on top of the multiple Aerospace Tutorials in this thread and some opinionated choices, I customized my aerospace plugin. Features
items/spaces.sh#!/bin/bash
for sid in $(aerospace list-workspaces --all); do
monitor=$(aerospace list-windows --workspace "$sid" --format "%{monitor-appkit-nsscreen-screens-id}")
if [ -z "$monitor" ]; then
monitor="1"
fi
sketchybar --add item space."$sid" left \
--subscribe space."$sid" aerospace_workspace_change display_change system_woke mouse.entered mouse.exited \
--set space."$sid" \
display="$monitor" \
padding_right=0 \
icon="$sid" \
label.padding_right=7 \
icon.padding_left=7 \
icon.padding_right=4 \
background.drawing=on \
label.font="sketchybar-app-font:Regular:16.0" \
background.color="$ACCENT_COLOR" \
icon.color="$BACKGROUND" \
label.color="$BACKGROUND" \
background.corner_radius=5 \
background.height=25 \
label.drawing=on \
click_script="aerospace workspace $sid" \
script="$CONFIG_DIR/plugins/aerospace.sh $sid"
done
plugins/aerospace.sh#!/usr/bin/env bash
# A color config for hover and highlight effects
# Example
# export BAR_COLOR=0x40000000
# export ITEM_BG_COLOR=0xff353c3f
# export ACCENT_COLOR=0xffffffff
# export BACKGROUND=0xff101314
source "$CONFIG_DIR/colors.sh"
FOCUSED_WORKSPACE=$(aerospace list-workspaces --focused --format "%{workspace}")
if [ "$SENDER" == "mouse.entered" ]; then
if [ "$1" = "$FOCUSED_WORKSPACE" ]; then
exit 0
fi
sketchybar --set "$NAME" \
background.drawing=on \
label.color="$BACKGROUND" \
icon.color="$BACKGROUND" \
background.color="$ACCENT_COLOR"
exit 0
fi
if [ "$SENDER" == "mouse.exited" ]; then
if [ "$1" = "$FOCUSED_WORKSPACE" ]; then
exit 0
fi
sketchybar --set "$NAME" \
background.drawing=off \
label.color="$ACCENT_COLOR" \
icon.color="$ACCENT_COLOR" \
background.color="$BAR_COLOR"
exit 0
fi
icons=""
APPS_INFO=$(aerospace list-windows --workspace "$1" --json --format "%{monitor-appkit-nsscreen-screens-id}%{app-name}")
IFS=$'\n'
for sid in $(echo "$APPS_INFO" | jq -r "map ( .\"app-name\" ) | .[]"); do
icons+=$("$CONFIG_DIR/plugins/icon_map_fn.sh" "$sid")
icons+=" "
done
for monitor_id in $(echo "$APPS_INFO" | jq -r "map ( .\"monitor-appkit-nsscreen-screens-id\" ) | .[]"); do
monitor=$monitor_id
done
if [ -z "$monitor" ]; then
monitor="1"
fi
# When icons is empty, set it to " "
if [ -z "$icons" ]; then
if [ "$1" = "$FOCUSED_WORKSPACE" ]; then
sketchybar --animate sin 10 \
--set "$NAME" \
y_offset=10 y_offset=0 \
background.drawing=on
sketchybar --set "$NAME" \
display="$monitor" \
drawing=on \
label="$icons" \
label.color="$BACKGROUND" \
icon.color="$BACKGROUND" \
background.color="$ACCENT_COLOR"
else
sketchybar --set "$NAME" drawing=off
fi
else
if [ "$1" = "$FOCUSED_WORKSPACE" ]; then
sketchybar --animate sin 10 \
--set "$NAME" \
y_offset=10 y_offset=0 \
background.drawing=on
sketchybar --set "$NAME" \
display="$monitor" \
drawing=on \
label="$icons" \
label.color="$BACKGROUND" \
icon.color="$BACKGROUND" \
background.color="$ACCENT_COLOR"
else
sketchybar --set "$NAME" \
display="$monitor" \
drawing=on \
label="$icons" \
background.drawing=off \
label.color="$ACCENT_COLOR" \
icon.color="$ACCENT_COLOR" \
background.color="$BAR_COLOR"
fi
fi Monitor 1Monitor 2When 2 or more apps are in a single workspaceHover and Jump EffectsScreen.Recording.2025-04-28.at.12.55.28.mov |
Beta Was this translation helpful? Give feedback.
-
Youtube MusicPlugin for th-ch/youtube-music. Inspired by the built in plugin in Grsmto/simplebar. Features:
PrerequisitesMake sure the Screen.Recording.2025-04-28.at.13.06.52.movitems/music.sh#!/bin/bash
music=(
script="$PLUGIN_DIR/youtube-music.sh"
click_script="curl -s -X POST 0.0.0.0:26538/api/v1/toggle-play && $PLUGIN_DIR/youtube-music.sh"
label.padding_right=8
label.font="Hack Nerd Font:Bold:17.0"
padding_right=0
icon=
# Pinned it to the primary display since my other monitor is in vertical layout
# display=1
label="Loading…"
background.image.scale=0.9
background.image.corner_radius=8
background.image.border_color="$TRANSPARENT"
background.color="$TRANSPARENT"
icon.padding_left=36
icon.padding_right=8
label.align=left
update_freq=10
label.max_chars=40
scroll_texts=on
)
music_artwork=(
click_script="curl -s -X POST 0.0.0.0:26538/api/v1/toggle-play && $PLUGIN_DIR/youtube-music.sh"
label.padding_right=8
padding_right=16
display=1
label=""
width=40
background.image.scale=0.07
background.image.corner_radius=8
background.image.border_color="$TRANSPARENT"
background.color="$TRANSPARENT"
)
sketchybar \
--add item music center \
--set music "${music[@]}"
sketchybar \
--add item music-artwork center \
--set music-artwork "${music_artwork[@]}" plugins/youtube-music.sh#!/bin/bash
SONG_INFO=$(curl -s 0.0.0.0:26538/api/v1/song-info)
PAUSED="$(echo "$SONG_INFO" | jq -r '.isPaused')"
CURRENT_SONG="$(echo "$SONG_INFO" | jq -r '.title + " - " + .artist')"
ARTWORK="$(echo "$SONG_INFO" | jq -r '.imageSrc')"
ARTWORK_LOCATION="$(curl -O --output-dir "$TMPDIR" -s --remote-name -w "%{filename_effective}" "$ARTWORK")"
if [ "$PAUSED" = true ]; then
ICON=
else
ICON=
fi
sketchybar --set "$NAME" label="$CURRENT_SONG" icon="$ICON" drawing=on
sketchybar --set "$NAME"-artwork background.image="$ARTWORK_LOCATION" Now Playing with Album Art |
Beta Was this translation helpful? Give feedback.
-
Pomodoro TimerA simple, yet customizable Pomodoro timer. To customize the sounds you can play all back with this script ls /System/Library/PrivateFrameworks/ScreenReader.framework/Versions/A/Resources/Sounds/ | awk '{print $1}' | while read sound; do printf "using $sound...\n"; afplay /System/Library/PrivateFrameworks/ScreenReader.framework/Versions/A/Resources/Sounds/$sound; sleep 0.5; done Controls:
SketchyBar item#!/bin/bash
sketchybar --add item timer right \
--set timer label="No Timer" \
icon= \
icon.color=0xFFF9E2AF \
icon.padding_right=6 \
background.drawing=off \
y_offset=1 \
script="PATH/TO/SCRIPT/timer.sh" \
popup.background.corner_radius=10 \
popup.background.color=0xFF1E1E2E \
popup.background.border_width=1 \
popup.background.border_color=0xFF45475A \
--subscribe timer mouse.clicked mouse.entered mouse.exited mouse.exited.global
for timer in "5" "10" "25"; do
sketchybar --add item "timer.${timer}" popup.timer \
--set "timer.${timer}" label="${timer} Minutes" \
padding_left=16 \
padding_right=16 \
click_script="PATH/TO/SCRIPT/timer.sh $((timer * 60)); sketchybar -m --set timer popup.drawing=off"
done Script#!/bin/bash
SOUNDS_PATH="/System/Library/PrivateFrameworks/ScreenReader.framework/Versions/A/Resources/Sounds/"
COUNTDOWN_PID_FILE="/tmp/sketchybar_timer_pid"
DEFAULT_DURATION=1500 # 25 minutes
__start() {
local name="$1"
local duration="$2"
(
local time_left="$duration"
while [ "$time_left" -gt 0 ]; do
local minutes=$((time_left / 60))
local seconds=$((time_left % 60))
sketchybar --set "$name" label="$(printf "%02d:%02d" "$minutes" "$seconds")"
sleep 1
time_left=$((time_left - 1))
done
afplay "$SOUNDS_PATH/GuideSuccess.aiff"
sketchybar --set "$name" label="Done"
) &
printf "%s\n" "$!" > "$COUNTDOWN_PID_FILE"
}
__stop() {
if [ -f "$COUNTDOWN_PID_FILE" ]; then
if IFS= read -r PID < "$COUNTDOWN_PID_FILE"; then
if ps -p "$PID" > /dev/null 2>&1; then
kill -- "$PID"
fi
fi
rm -f "$COUNTDOWN_PID_FILE"
fi
}
start_countdown() {
__stop
__start "$1" "$2"
afplay "$SOUNDS_PATH/TrackingOn.aiff"
}
stop_countdown() {
__stop
afplay "$SOUNDS_PATH/TrackingOff.aiff"
sketchybar --set "$NAME" label="No Timer"
}
# If script is run directly with a duration argument (e.g. ./timer.sh 300)
if [[ "$#" -eq 1 && "$1" =~ ^[0-9]+$ ]]; then
start_countdown "$(echo "$NAME" | awk -F'.' '{print $1}')" "$1"
exit 0
fi
# Handle SketchyBar mouse events
if [ "$SENDER" = "mouse.clicked" ]; then
case "$BUTTON" in
"left")
start_countdown "$NAME" "$DEFAULT_DURATION"
;;
"right")
stop_countdown
;;
esac
fi
case "$SENDER" in
"mouse.entered")
sketchybar --set "$NAME" popup.drawing=on
;;
"mouse.exited"|"mouse.exited.global")
sketchybar --set "$NAME" popup.drawing=off
;;
esac
|
Beta Was this translation helpful? Give feedback.
-
Hi everyone, I’ve been working on the Spotify setup by @FelixKratz and made some tweaks that might be useful:
I hope these improvements help streamline the setup and make it more flexible! IMPORTANT: Big thanks again to Felix for the original template! :)
|
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Audio Output DisplayDisplays a simple icon based on audio output device. Requires that you have SwitchAudio-OSX installed ( sketchybarrc
audio.sh
|
Beta Was this translation helpful? Give feedback.
-
Check for SecureInput being EnabledDisplays a warning alert if SecureInput is Enabled, which disables/overtakes global hotkey use. Main use would be for AeroSpace users, as if this is enabled, many hotkeys won't work (to move windows, spaces, or change focus). The alert displays the PID as well so that you can determine what app is causing it and you can decide if you want to close that app right away or deal with it until you are done with that app. sketchybarrc
secure_input.sh
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
This is a thread to share the plugins you've created with the community.
Beta Was this translation helpful? Give feedback.
All reactions