Files
I-DeskPet/ideskpet
T
2026-03-23 13:21:31 +01:00

380 lines
9.1 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
# =============================================================================
# ideskpet - CLI tool for I-DeskPet Quickshell application
# =============================================================================
VERSION="1.0.0"
REPO_URL="https://github.com/InoriShio/I-DeskPet"
INSTALL_DIR="/etc/xdg/quickshell/I-DeskPet"
LOG_DIR="$HOME/.local/state/ideskpet"
LOG_FILE="$LOG_DIR/ideskpet.log"
APP_ID="I-DeskPet"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
BOLD='\033[1m'
NC='\033[0m'
# =============================================================================
# Helper Functions
# =============================================================================
print_help() {
cat << EOF
${BOLD}ideskpet${NC} - CLI tool for I-DeskPet desktop pet application (v${VERSION})
${BOLD}USAGE:${NC}
ideskpet <COMMAND> [OPTIONS]
${BOLD}COMMANDS:${NC}
${GREEN}start${NC} Start the I-DeskPet application
${GREEN}stop${NC} Stop the running I-DeskPet instance
${GREEN}restart${NC} Restart the I-DeskPet application
${GREEN}log${NC} Show application logs
${GREEN}update${NC} Update I-DeskPet from GitHub
${BOLD}HYPRLAND SHORTCUTS:${NC}
${BLUE}toggle-layer${NC} Toggle pet between overlay/bottom layer
${BLUE}toggle-region${NC} Toggle click-through mode
${BLUE}cycle-zindex${NC} Cycle z-index of hovered gif
${BOLD}LOG OPTIONS:${NC}
ideskpet log Show last 50 lines of logs
ideskpet log -f Follow logs in real-time (Ctrl+C to exit)
ideskpet log -n <N> Show last N lines of logs
${BOLD}OTHER:${NC}
-h, --help Show this help message
-v, --version Show version
${BOLD}CONFIGURATION:${NC}
User config: ~/.config/I-DeskPet/config.json
Example config.json:
{
"gifFolder": "/home/user/Pictures/Pets",
"maxScaling": 1
}
${BOLD}HYPRLAND KEYBIND EXAMPLES:${NC}
bind = CTRL, mouse:274, global, I-DeskPet:toggle-Region
bind = SHIFT, mouse:274, global, I-DeskPet:toggle-Layer
bind = \$mainMod, Z, global, I-DeskPet:cycle-zIndex
${BOLD}INSTALLATION:${NC}
sudo cp ideskpet /usr/bin/ideskpet
sudo chmod +x /usr/bin/ideskpet
EOF
}
print_version() {
echo "ideskpet v${VERSION}"
}
info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
}
is_running() {
pgrep -f "quickshell.*${APP_ID}" > /dev/null 2>&1
}
get_pid() {
pgrep -f "quickshell.*${APP_ID}" 2>/dev/null || true
}
ensure_log_dir() {
if [[ ! -d "$LOG_DIR" ]]; then
mkdir -p "$LOG_DIR"
fi
}
ensure_installed() {
if [[ ! -d "$INSTALL_DIR" ]]; then
warn "I-DeskPet is not installed at ${INSTALL_DIR}"
info "Cloning from ${REPO_URL}..."
# Check if /etc/xdg/quickshell exists
if [[ ! -d "/etc/xdg/quickshell" ]]; then
info "Creating /etc/xdg/quickshell directory (requires sudo)..."
sudo mkdir -p /etc/xdg/quickshell
fi
info "Cloning repository (requires sudo)..."
sudo git clone "$REPO_URL" "$INSTALL_DIR"
if [[ $? -eq 0 ]]; then
info "Successfully installed I-DeskPet to ${INSTALL_DIR}"
else
error "Failed to clone repository"
exit 1
fi
fi
}
check_dependencies() {
local missing=()
if ! command -v quickshell &> /dev/null; then
missing+=("quickshell")
fi
if ! command -v hyprctl &> /dev/null; then
missing+=("hyprctl (hyprland)")
fi
if ! command -v git &> /dev/null; then
missing+=("git")
fi
if [[ ${#missing[@]} -gt 0 ]]; then
error "Missing dependencies: ${missing[*]}"
echo "Please install the missing packages and try again."
exit 1
fi
}
# =============================================================================
# Command Implementations
# =============================================================================
cmd_start() {
check_dependencies
ensure_installed
ensure_log_dir
if is_running; then
warn "I-DeskPet is already running (PID: $(get_pid))"
echo "Use 'ideskpet restart' to restart, or 'ideskpet stop' to stop."
exit 1
fi
info "Starting I-DeskPet..."
# Start quickshell in background, redirect output to log file
nohup quickshell -p "$INSTALL_DIR" >> "$LOG_FILE" 2>&1 &
disown
# Wait a moment and check if it started successfully
sleep 1
if is_running; then
info "I-DeskPet started successfully (PID: $(get_pid))"
echo "Use 'ideskpet log -f' to view logs"
else
error "Failed to start I-DeskPet"
echo "Check logs with 'ideskpet log' for details"
exit 1
fi
}
cmd_stop() {
if ! is_running; then
warn "I-DeskPet is not running"
exit 0
fi
local pid
pid=$(get_pid)
info "Stopping I-DeskPet (PID: ${pid})..."
# Try graceful shutdown first
kill "$pid" 2>/dev/null || true
# Wait up to 5 seconds for graceful shutdown
local count=0
while is_running && [[ $count -lt 10 ]]; do
sleep 0.5
((count++))
done
# Force kill if still running
if is_running; then
warn "Graceful shutdown failed, force killing..."
kill -9 "$pid" 2>/dev/null || true
sleep 0.5
fi
if is_running; then
error "Failed to stop I-DeskPet"
exit 1
else
info "I-DeskPet stopped successfully"
fi
}
cmd_restart() {
info "Restarting I-DeskPet..."
if is_running; then
cmd_stop
fi
sleep 0.5
cmd_start
}
cmd_log() {
ensure_log_dir
if [[ ! -f "$LOG_FILE" ]]; then
warn "No log file found at ${LOG_FILE}"
echo "Start I-DeskPet first with 'ideskpet start'"
exit 1
fi
local follow=false
local lines=50
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-f|--follow)
follow=true
shift
;;
-n|--lines)
if [[ -n "${2:-}" ]] && [[ "$2" =~ ^[0-9]+$ ]]; then
lines="$2"
shift 2
else
error "Option -n requires a numeric argument"
exit 1
fi
;;
*)
error "Unknown log option: $1"
echo "Usage: ideskpet log [-f] [-n <lines>]"
exit 1
;;
esac
done
if [[ "$follow" == true ]]; then
info "Following logs (Ctrl+C to exit)..."
echo "---"
tail -n "$lines" -f "$LOG_FILE"
else
tail -n "$lines" "$LOG_FILE"
fi
}
cmd_update() {
check_dependencies
if [[ ! -d "$INSTALL_DIR" ]]; then
error "I-DeskPet is not installed at ${INSTALL_DIR}"
echo "Run 'ideskpet start' to install it first."
exit 1
fi
info "Updating I-DeskPet from GitHub..."
cd "$INSTALL_DIR"
# Check for local changes
if ! sudo git diff --quiet 2>/dev/null; then
warn "Local changes detected. They may be overwritten."
fi
sudo git pull
if [[ $? -eq 0 ]]; then
info "Update completed successfully"
if is_running; then
echo ""
warn "I-DeskPet is currently running."
echo "Run 'ideskpet restart' to apply changes."
fi
else
error "Update failed"
exit 1
fi
}
cmd_shortcut() {
local shortcut="$1"
if ! command -v hyprctl &> /dev/null; then
error "hyprctl not found. Are you running Hyprland?"
exit 1
fi
if ! is_running; then
warn "I-DeskPet is not running"
echo "Start it first with 'ideskpet start'"
exit 1
fi
info "Triggering shortcut: ${APP_ID}:${shortcut}"
hyprctl dispatch global "${APP_ID}:${shortcut}"
}
# =============================================================================
# Main Entry Point
# =============================================================================
main() {
local cmd="${1:-}"
case "$cmd" in
start)
cmd_start
;;
stop)
cmd_stop
;;
restart)
cmd_restart
;;
log)
shift
cmd_log "$@"
;;
update)
cmd_update
;;
toggle-layer)
cmd_shortcut "toggle-Layer"
;;
toggle-region)
cmd_shortcut "toggle-Region"
;;
cycle-zindex)
cmd_shortcut "cycle-zIndex"
;;
-h|--help|help)
print_help
;;
-v|--version|version)
print_version
;;
"")
print_help
;;
*)
error "Unknown command: ${cmd}"
echo "Run 'ideskpet --help' for usage information."
exit 1
;;
esac
}
main "$@"