mirror of
https://github.com/zhenyan121/dotfiles.git
synced 2026-04-10 14:34:09 +08:00
195 lines
6.7 KiB
Bash
Executable File
195 lines
6.7 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# ==============================================================================
|
||
# 1. 本地化与文案配置
|
||
# ==============================================================================
|
||
# 默认英文
|
||
STR_PROMPT="Longshot> "
|
||
STR_START="⛶ Start Selection (Width as baseline)"
|
||
STR_CANCEL="❌ Cancel"
|
||
STR_NEXT="📸 Capture Next (Height only)"
|
||
STR_SAVE="💾 Save & Finish"
|
||
STR_EDIT="🎨 Edit & Finish"
|
||
STR_ABORT="❌ Abort"
|
||
STR_NOTIFY_TITLE="Longshot"
|
||
STR_NOTIFY_SAVED="Saved to"
|
||
STR_NOTIFY_COPIED="Copied to clipboard"
|
||
STR_ERR_DEP="Missing dependency"
|
||
STR_ERR_MENU="Menu tool not found"
|
||
STR_ERR_TITLE="Error"
|
||
|
||
# 中文检测
|
||
if env | grep -q "zh_CN"; then
|
||
STR_PROMPT="长截图> "
|
||
STR_START="⛶ 开始框选(该图宽视为基准)"
|
||
STR_CANCEL="❌ 取消"
|
||
STR_NEXT="📸 截取下一张(只需确定高度)"
|
||
STR_SAVE="💾 完成并保存"
|
||
STR_EDIT="🎨 完成并编辑"
|
||
STR_ABORT="❌ 放弃并退出"
|
||
STR_NOTIFY_TITLE="长截图完成"
|
||
STR_NOTIFY_SAVED="已保存至"
|
||
STR_NOTIFY_COPIED="并已复制到剪贴板"
|
||
STR_ERR_DEP="缺少核心依赖"
|
||
STR_ERR_MENU="未找到菜单工具 (fuzzel/rofi/wofi)"
|
||
STR_ERR_TITLE="错误"
|
||
fi
|
||
|
||
# ==============================================================================
|
||
# 2. 用户配置与安全初始化
|
||
# ==============================================================================
|
||
SAVE_DIR="$HOME/Pictures/Screenshots/longshots"
|
||
TMP_BASE_NAME="niri_longshot"
|
||
TMP_DIR="/tmp/${TMP_BASE_NAME}_$(date +%s)"
|
||
FILENAME="longshot_$(date +%Y%m%d_%H%M%S).png"
|
||
RESULT_PATH="$SAVE_DIR/$FILENAME"
|
||
TMP_STITCHED="$TMP_DIR/stitched_temp.png"
|
||
|
||
# --- [保险措施 1] 启动时清理陈旧垃圾 ---
|
||
# 查找 /tmp 下名字包含 niri_longshot 且修改时间超过 10 分钟的目录并删除
|
||
# 这可以防止因断电或 kill -9 导致的垃圾堆积,同时不影响刚启动的其他实例
|
||
find /tmp -maxdepth 1 -type d -name "${TMP_BASE_NAME}_*" -mmin +10 -exec rm -rf {} + 2>/dev/null
|
||
|
||
# 创建目录
|
||
mkdir -p "$SAVE_DIR"
|
||
mkdir -p "$TMP_DIR"
|
||
|
||
# --- [保险措施 2] 增强型 Trap ---
|
||
# 无论脚本是正常退出 (EXIT)、被 Ctrl+C (SIGINT)、还是被 kill (SIGTERM),都执行清理
|
||
# 这里的逻辑是:只要脚本进程结束,就删掉本次生成的 TMP_DIR
|
||
cleanup() {
|
||
rm -rf "$TMP_DIR"
|
||
}
|
||
trap cleanup EXIT SIGINT SIGTERM SIGHUP
|
||
|
||
# ==============================================================================
|
||
# 3. 依赖与工具探测
|
||
# ==============================================================================
|
||
CMD_FUZZEL="fuzzel -d --anchor=top --y-margin=10 --lines=5 --width=45 --prompt=$STR_PROMPT"
|
||
CMD_ROFI="rofi -dmenu -i -p $STR_PROMPT -l 5"
|
||
CMD_WOFI="wofi --dmenu --lines 5 --prompt $STR_PROMPT"
|
||
|
||
REQUIRED_CMDS=("grim" "slurp" "magick" "notify-send")
|
||
for cmd in "${REQUIRED_CMDS[@]}"; do
|
||
if ! command -v "$cmd" &> /dev/null; then
|
||
PKG_NAME="$cmd"
|
||
[[ "$cmd" == "magick" ]] && PKG_NAME="imagemagick"
|
||
notify-send -u critical "$STR_ERR_TITLE" "$STR_ERR_DEP: $cmd\nInstall: sudo pacman -S $PKG_NAME"
|
||
exit 1
|
||
fi
|
||
done
|
||
|
||
EDITOR_CMD=""
|
||
if command -v satty &> /dev/null; then EDITOR_CMD="satty --filename";
|
||
elif command -v swappy &> /dev/null; then EDITOR_CMD="swappy -f"; fi
|
||
|
||
MENU_CMD=""
|
||
if command -v fuzzel &> /dev/null; then MENU_CMD="$CMD_FUZZEL"
|
||
elif command -v rofi &> /dev/null; then MENU_CMD="$CMD_ROFI"
|
||
elif command -v wofi &> /dev/null; then MENU_CMD="$CMD_WOFI"
|
||
else
|
||
notify-send -u critical "$STR_ERR_TITLE" "$STR_ERR_MENU"
|
||
exit 1
|
||
fi
|
||
|
||
function show_menu() { echo -e "$1" | $MENU_CMD; }
|
||
|
||
# ==============================================================================
|
||
# 步骤 1: 第一张截图 (基准)
|
||
# ==============================================================================
|
||
|
||
SELECTION=$(show_menu "$STR_START\n$STR_CANCEL")
|
||
if [[ "$SELECTION" != "$STR_START" ]]; then exit 0; fi
|
||
|
||
sleep 0.2
|
||
GEO_1=$(slurp)
|
||
# 如果第一步被 Super+Q 杀掉 slurp,GEO_1 为空,脚本会在此退出并触发 cleanup
|
||
if [ -z "$GEO_1" ]; then exit 0; fi
|
||
|
||
IFS=', x' read -r FIX_X FIX_Y FIX_W FIX_H <<< "$GEO_1"
|
||
grim -g "$GEO_1" "$TMP_DIR/001.png"
|
||
|
||
# ==============================================================================
|
||
# 步骤 2: 循环截图
|
||
# ==============================================================================
|
||
INDEX=2
|
||
SAVE_MODE=""
|
||
|
||
while true; do
|
||
MENU_OPTIONS="$STR_NEXT\n$STR_SAVE"
|
||
if [[ -n "$EDITOR_CMD" ]]; then MENU_OPTIONS="$MENU_OPTIONS\n$STR_EDIT"; fi
|
||
MENU_OPTIONS="$MENU_OPTIONS\n$STR_ABORT"
|
||
|
||
# 如果此时 Super+Q 杀掉了 Fuzzel,ACTION 为空
|
||
ACTION=$(show_menu "$MENU_OPTIONS")
|
||
|
||
case "$ACTION" in
|
||
*"📸"*)
|
||
sleep 0.2
|
||
GEO_NEXT=$(slurp)
|
||
|
||
# 如果此时 Super+Q 杀掉 Slurp,GEO_NEXT 为空,回到菜单
|
||
if [ -z "$GEO_NEXT" ]; then
|
||
continue
|
||
fi
|
||
|
||
IFS=', x' read -r _TEMP_X NEW_Y _TEMP_W NEW_H <<< "$GEO_NEXT"
|
||
FINAL_GEO="${FIX_X},${NEW_Y} ${FIX_W}x${NEW_H}"
|
||
|
||
IMG_NAME="$(printf "%03d" $INDEX).png"
|
||
grim -g "$FINAL_GEO" "$TMP_DIR/$IMG_NAME"
|
||
((INDEX++))
|
||
;;
|
||
|
||
*"💾"*)
|
||
SAVE_MODE="save"
|
||
break
|
||
;;
|
||
|
||
*"🎨"*)
|
||
SAVE_MODE="edit"
|
||
break
|
||
;;
|
||
|
||
*"❌"*)
|
||
exit 0
|
||
;;
|
||
|
||
*)
|
||
# Fuzzel 被 Super+Q 关闭,ACTION 为空,进入这里
|
||
# 直接 Break 跳出循环,进入保存/拼接流程 (防止误操作导致丢失)
|
||
# 或者如果你想放弃,这里改成 exit 0
|
||
break
|
||
;;
|
||
esac
|
||
done
|
||
|
||
# ==============================================================================
|
||
# 步骤 3: 拼接与后续处理
|
||
# ==============================================================================
|
||
COUNT=$(ls "$TMP_DIR"/*.png 2>/dev/null | wc -l)
|
||
|
||
if [ "$COUNT" -gt 0 ]; then
|
||
magick "$TMP_DIR"/*.png -append "$TMP_STITCHED"
|
||
|
||
if [[ "$SAVE_MODE" == "edit" ]]; then
|
||
$EDITOR_CMD "$TMP_STITCHED"
|
||
fi
|
||
|
||
# 只要有保存意向 (SAVE_MODE不为空),或者是因为意外退出且至少有图
|
||
# 如果你是"意外退出菜单",默认是不保存的 (SAVE_MODE为空)
|
||
# 这里我们只在显式选择保存/编辑时才保存
|
||
if [[ -n "$SAVE_MODE" ]]; then
|
||
mv "$TMP_STITCHED" "$RESULT_PATH"
|
||
|
||
COPY_MSG=""
|
||
if command -v wl-copy &> /dev/null; then
|
||
wl-copy < "$RESULT_PATH"
|
||
COPY_MSG="$STR_NOTIFY_COPIED"
|
||
fi
|
||
|
||
notify-send -i "$RESULT_PATH" "$STR_NOTIFY_TITLE" "$STR_NOTIFY_SAVED $FILENAME\n$COPY_MSG"
|
||
fi
|
||
fi
|
||
|
||
# 脚本结束,触发 Trap 清理 TMP_DIR |