updated scripts
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
# Automatically learn email addresses from sent/received mail
|
||||
|
||||
ABOOK_FILE="$HOME/.abook/addressbook"
|
||||
mkdir -p "$HOME/.abook"
|
||||
touch "$ABOOK_FILE"
|
||||
|
||||
# Extract all email addresses from notmuch database
|
||||
notmuch address --output=sender --output=recipients '*' |
|
||||
sort -u |
|
||||
while read -r email; do
|
||||
# Check if email is already in abook
|
||||
if ! grep -q "$email" "$ABOOK_FILE" 2>/dev/null; then
|
||||
# Extract name and email
|
||||
if [[ $email =~ ^(.+)\<(.+)\>$ ]]; then
|
||||
NAME="${BASH_REMATCH[1]}"
|
||||
EMAIL="${BASH_REMATCH[2]}"
|
||||
else
|
||||
NAME=""
|
||||
EMAIL="$email"
|
||||
fi
|
||||
|
||||
# Add to abook (skip if already exists)
|
||||
echo "[format]
|
||||
program=abook
|
||||
version=0.6.1
|
||||
|
||||
[0]
|
||||
name=$NAME
|
||||
email=$EMAIL
|
||||
" >>"$ABOOK_FILE"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Address book updated: $(grep -c '^\[' "$ABOOK_FILE") entries"
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Fast Aria2 Download Script
|
||||
# Usage: ./aria2-download.sh <URL> [output-filename]
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Check if aria2c is installed
|
||||
if ! command -v aria2c &> /dev/null; then
|
||||
echo -e "${RED}aria2c is not installed!${NC}"
|
||||
echo "Installing aria2..."
|
||||
|
||||
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
if command -v apt-get &> /dev/null; then
|
||||
sudo apt-get update && sudo apt-get install -y aria2
|
||||
elif command -v yum &> /dev/null; then
|
||||
sudo yum install -y aria2
|
||||
elif command -v pacman &> /dev/null; then
|
||||
sudo pacman -S aria2
|
||||
else
|
||||
echo -e "${RED}Please install aria2 manually${NC}"
|
||||
exit 1
|
||||
fi
|
||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
if command -v brew &> /dev/null; then
|
||||
brew install aria2
|
||||
else
|
||||
echo -e "${RED}Please install Homebrew or aria2 manually${NC}"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}Unsupported OS. Please install aria2 manually${NC}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if URL is provided
|
||||
if [ -z "$1" ]; then
|
||||
echo -e "${RED}Error: No URL provided${NC}"
|
||||
echo "Usage: $0 <URL> [output-filename]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
URL="$1"
|
||||
OUTPUT_FILE="$2"
|
||||
|
||||
# Build aria2c command with optimized settings
|
||||
ARIA2_CMD="aria2c \
|
||||
--max-connection-per-server=16 \
|
||||
--split=16 \
|
||||
--min-split-size=1M \
|
||||
--max-concurrent-downloads=16 \
|
||||
--continue=true \
|
||||
--max-tries=5 \
|
||||
--retry-wait=3 \
|
||||
--timeout=60 \
|
||||
--connect-timeout=30 \
|
||||
--file-allocation=none \
|
||||
--summary-interval=0 \
|
||||
--console-log-level=notice"
|
||||
|
||||
# Add output filename if provided
|
||||
if [ -n "$OUTPUT_FILE" ]; then
|
||||
ARIA2_CMD="$ARIA2_CMD --out=\"$OUTPUT_FILE\""
|
||||
fi
|
||||
|
||||
# Add URL
|
||||
ARIA2_CMD="$ARIA2_CMD \"$URL\""
|
||||
|
||||
echo -e "${GREEN}Starting download...${NC}"
|
||||
echo -e "${YELLOW}URL: $URL${NC}"
|
||||
if [ -n "$OUTPUT_FILE" ]; then
|
||||
echo -e "${YELLOW}Output: $OUTPUT_FILE${NC}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Execute download
|
||||
eval $ARIA2_CMD
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "\n${GREEN}✓ Download completed successfully!${NC}"
|
||||
else
|
||||
echo -e "\n${RED}✗ Download failed!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
Executable
+87
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
|
||||
SHADER_DIR="$HOME/.config/hypr/shaders"
|
||||
SHADER_FILE="$SHADER_DIR/brightness.frag"
|
||||
|
||||
# Ensure shader directory exists
|
||||
mkdir -p "$SHADER_DIR"
|
||||
|
||||
# Get screen brightness level
|
||||
echo "Enter screen brightness level (0-10, where 10 = 100%):"
|
||||
read -r LEVEL
|
||||
|
||||
# Validate input
|
||||
if ! [[ "$LEVEL" =~ ^[0-9]+$ ]] || [ "$LEVEL" -lt 0 ] || [ "$LEVEL" -gt 10 ]; then
|
||||
echo "Invalid input. Please enter a number between 0 and 10."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Convert to decimal (0-10 -> 0.0-1.0)
|
||||
BRIGHTNESS=$(echo "scale=2; $LEVEL / 10" | bc)
|
||||
|
||||
# Ask about keyboard backlight
|
||||
echo "Adjust keyboard backlight? (y/n):"
|
||||
read -r KBD_ADJUST
|
||||
|
||||
if [[ "$KBD_ADJUST" == "y" || "$KBD_ADJUST" == "Y" ]]; then
|
||||
echo "Enter keyboard backlight level (0-10, where 10 = 100%):"
|
||||
read -r KBD_LEVEL
|
||||
|
||||
# Validate keyboard input
|
||||
if ! [[ "$KBD_LEVEL" =~ ^[0-9]+$ ]] || [ "$KBD_LEVEL" -lt 0 ] || [ "$KBD_LEVEL" -gt 10 ]; then
|
||||
echo "Invalid input. Please enter a number between 0 and 10."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Convert to percentage (0-10 -> 0-100)
|
||||
KBD_PERCENT=$((KBD_LEVEL * 10))
|
||||
|
||||
# Set keyboard backlight
|
||||
kbdlight set $KBD_PERCENT
|
||||
echo "Keyboard backlight set to ${KBD_PERCENT}%"
|
||||
fi
|
||||
|
||||
# Ask about blue light filter
|
||||
echo "Apply blue light filter? (y/n):"
|
||||
read -r BLUELIGHT
|
||||
|
||||
# Create shader based on choice
|
||||
cat > "$SHADER_FILE" << EOF
|
||||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
|
||||
in vec2 v_texcoord;
|
||||
out vec4 fragColor;
|
||||
uniform sampler2D tex;
|
||||
|
||||
void main() {
|
||||
vec4 pixColor = texture(tex, v_texcoord);
|
||||
|
||||
EOF
|
||||
|
||||
if [[ "$BLUELIGHT" == "y" || "$BLUELIGHT" == "Y" ]]; then
|
||||
cat >> "$SHADER_FILE" << EOF
|
||||
// Reduce blue light
|
||||
pixColor.r *= 1.0;
|
||||
pixColor.g *= 0.85;
|
||||
pixColor.b *= 0.65;
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
cat >> "$SHADER_FILE" << EOF
|
||||
// Adjust brightness
|
||||
pixColor.rgb *= $BRIGHTNESS;
|
||||
|
||||
fragColor = pixColor;
|
||||
}
|
||||
EOF
|
||||
|
||||
# Apply shader
|
||||
if [ -z "$HYPRLAND_INSTANCE_SIGNATURE" ]; then
|
||||
export HYPRLAND_INSTANCE_SIGNATURE=$(ls -t /tmp/hypr/ 2>/dev/null | head -n1)
|
||||
fi
|
||||
/usr/bin/hyprctl keyword decoration:screen_shader "$SHADER_FILE"
|
||||
|
||||
echo "Screen brightness set to ${LEVEL}0% $([ "$BLUELIGHT" == "y" ] || [ "$BLUELIGHT" == "Y" ] && echo "with blue light filter")"
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
SOURCE_DIRS=("/home/liph/Documents" "/home/liph/Pictures" "/home/liph/Downloads")
|
||||
REPO_DIR="/home/liph/borg-repo"
|
||||
BORG_PASSPHRASE="1ChagearC"
|
||||
|
||||
export BORG_PASSPHRASE
|
||||
|
||||
for SOURCE_DIR in "${SOURCE_DIRS[@]}"; do
|
||||
ARCHIVE_NAME="{hostname}-{user}-{now}"
|
||||
|
||||
echo "Starting backup of ${SOURCE_DIR}..."
|
||||
borg create --stats --progress \
|
||||
"${REPO_DIR}::${ARCHIVE_NAME}" \
|
||||
"${SOURCE_DIR}"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Backup of ${SOURCE_DIR} completed successfully!"
|
||||
else
|
||||
echo "Backup of ${SOURCE_DIR} failed!"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Pruning old backups..."
|
||||
borg prune --stats --progress \
|
||||
--keep-daily=7 \
|
||||
--keep-weekly=4 \
|
||||
--keep-monthly=6 \
|
||||
"${REPO_DIR}"
|
||||
|
||||
echo "Backup and pruning completed!"
|
||||
|
||||
Executable
+95
@@ -0,0 +1,95 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Setting this, so the repo does not need to be given on the commandline:
|
||||
# export BORG_REPO=ssh://username@example.com:2022/~/backup/main
|
||||
#export BORG_REPO=~/backup/
|
||||
|
||||
# See the section "Passphrase notes" for more infos.
|
||||
#export BORG_PASSPHRASE='1ChagearC'
|
||||
|
||||
export BORG_REPO="ssh://100.121.203.110:2222/./repo/borg-repo"
|
||||
export BORG_PASSPHRASE="1ChagearC" # Encryption key
|
||||
BACKUP_SOURCES=(
|
||||
"/home/liph/Downloads/"
|
||||
"/home/liph/dotfiles/"
|
||||
"/home/liph/scripts"
|
||||
) # What to back up
|
||||
BACKUP_NAME="laptop-$(date +%Y-%m-%d)" # Dynamic backup name
|
||||
|
||||
# some helpers and error handling:
|
||||
info() { printf "\n%s %s\n\n" "$( date )" "$*" >&2; }
|
||||
trap 'echo $( date ) Backup interrupted >&2; exit 2' INT TERM
|
||||
|
||||
info "Starting backup"
|
||||
|
||||
# Initialize Borg repo (if not exists)
|
||||
borg init --encryption=repokey "$BORG_REPO" 2>/dev/null || true
|
||||
|
||||
# Backup the most important directories into an archive named after
|
||||
# the machine this script is currently running on:
|
||||
|
||||
borg create \
|
||||
--verbose \
|
||||
--filter AME \
|
||||
--list \
|
||||
--stats \
|
||||
--show-rc \
|
||||
--progress \
|
||||
--compression lz4 \
|
||||
--exclude-caches \
|
||||
--exclude 'home/*/.cache/*' \
|
||||
--exclude 'var/tmp/*' \
|
||||
"$BORG_REPO::$BACKUP_NAME" \
|
||||
"${BACKUP_SOURCES[@]}" \
|
||||
# ::'{hostname}-{user}-{now}' \
|
||||
# /home/liph/Documents/ \
|
||||
# /home/liph/Pictures/ \
|
||||
# /home/liph/Downloads/
|
||||
# /etc \
|
||||
# /home \
|
||||
# /root \
|
||||
# /var
|
||||
backup_exit=$?
|
||||
|
||||
info "Pruning repository"
|
||||
|
||||
# Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly
|
||||
# archives of THIS machine. The '{hostname}-*' matching is very important to
|
||||
# limit prune's operation to this machine's archives and not apply to
|
||||
# other machines' archives also:
|
||||
|
||||
borg prune \
|
||||
--list \
|
||||
--glob-archives '{hostname}-*' \
|
||||
--show-rc \
|
||||
--keep-daily 7 \
|
||||
--keep-weekly 4 \
|
||||
--keep-monthly 6
|
||||
"$BORG_REPO"
|
||||
|
||||
prune_exit=$?
|
||||
|
||||
# actually free repo disk space by compacting segments
|
||||
|
||||
info "Compacting repository"
|
||||
|
||||
borg compact
|
||||
|
||||
compact_exit=$?
|
||||
|
||||
# use highest exit code as global exit code
|
||||
global_exit=$(( backup_exit > prune_exit ? backup_exit : prune_exit ))
|
||||
global_exit=$(( compact_exit > global_exit ? compact_exit : global_exit ))
|
||||
|
||||
if [ ${global_exit} -eq 0 ]; then
|
||||
info "Backup, Prune, and Compact finished successfully"
|
||||
elif [ ${global_exit} -eq 1 ]; then
|
||||
info "Backup, Prune, and/or Compact finished with warnings"
|
||||
else
|
||||
info "Backup, Prune, and/or Compact finished with errors"
|
||||
fi
|
||||
|
||||
exit ${global_exit}
|
||||
|
||||
# Check backup integrity
|
||||
borg check "$BORG_REPO"
|
||||
Executable
+95
@@ -0,0 +1,95 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Setting this, so the repo does not need to be given on the commandline:
|
||||
# export BORG_REPO=ssh://username@example.com:2022/~/backup/main
|
||||
#export BORG_REPO=~/backup/
|
||||
|
||||
# See the section "Passphrase notes" for more infos.
|
||||
#export BORG_PASSPHRASE='1ChagearC'
|
||||
|
||||
export BORG_REPO="ssh://100.121.203.110:2222/./repo/borg-repo"
|
||||
export BORG_PASSPHRASE="1ChagearC" # Encryption key
|
||||
BACKUP_SOURCES=(
|
||||
"/home/liph/Documents"
|
||||
"/home/liph/Pictures"
|
||||
"/home/liph/scripts"
|
||||
) # What to back up
|
||||
BACKUP_NAME="server-$(date +%Y-%m-%d)" # Dynamic backup name
|
||||
|
||||
# some helpers and error handling:
|
||||
info() { printf "\n%s %s\n\n" "$( date )" "$*" >&2; }
|
||||
trap 'echo $( date ) Backup interrupted >&2; exit 2' INT TERM
|
||||
|
||||
info "Starting backup"
|
||||
|
||||
# Initialize Borg repo (if not exists)
|
||||
borg init --encryption=repokey "$BORG_REPO" 2>/dev/null || true
|
||||
|
||||
# Backup the most important directories into an archive named after
|
||||
# the machine this script is currently running on:
|
||||
|
||||
borg create \
|
||||
--verbose \
|
||||
--filter AME \
|
||||
--list \
|
||||
--stats \
|
||||
--show-rc \
|
||||
--progress \
|
||||
--compression lz4 \
|
||||
--exclude-caches \
|
||||
--exclude 'home/*/.cache/*' \
|
||||
--exclude 'var/tmp/*' \
|
||||
"$BORG_REPO::$BACKUP_NAME" \
|
||||
"${BACKUP_SOURCES[@]}" \
|
||||
# ::'{hostname}-{user}-{now}' \
|
||||
# /home/liph/Documents/ \
|
||||
# /home/liph/Pictures/ \
|
||||
# /home/liph/Downloads/
|
||||
# /etc \
|
||||
# /home \
|
||||
# /root \
|
||||
# /var
|
||||
backup_exit=$?
|
||||
|
||||
info "Pruning repository"
|
||||
|
||||
# Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly
|
||||
# archives of THIS machine. The '{hostname}-*' matching is very important to
|
||||
# limit prune's operation to this machine's archives and not apply to
|
||||
# other machines' archives also:
|
||||
|
||||
borg prune \
|
||||
--list \
|
||||
--glob-archives '{hostname}-*' \
|
||||
--show-rc \
|
||||
--keep-daily 7 \
|
||||
--keep-weekly 4 \
|
||||
--keep-monthly 6
|
||||
"$BORG_REPO"
|
||||
|
||||
prune_exit=$?
|
||||
|
||||
# actually free repo disk space by compacting segments
|
||||
|
||||
info "Compacting repository"
|
||||
|
||||
borg compact
|
||||
|
||||
compact_exit=$?
|
||||
|
||||
# use highest exit code as global exit code
|
||||
global_exit=$(( backup_exit > prune_exit ? backup_exit : prune_exit ))
|
||||
global_exit=$(( compact_exit > global_exit ? compact_exit : global_exit ))
|
||||
|
||||
if [ ${global_exit} -eq 0 ]; then
|
||||
info "Backup, Prune, and Compact finished successfully"
|
||||
elif [ ${global_exit} -eq 1 ]; then
|
||||
info "Backup, Prune, and/or Compact finished with warnings"
|
||||
else
|
||||
info "Backup, Prune, and/or Compact finished with errors"
|
||||
fi
|
||||
|
||||
exit ${global_exit}
|
||||
|
||||
# Check backup integrity
|
||||
borg check "$BORG_REPO"
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Setting this, so the repo does not need to be given on the commandline:
|
||||
# export BORG_REPO=ssh://username@example.com:2022/~/backup/main
|
||||
#export BORG_REPO=~/backup/
|
||||
|
||||
# See the section "Passphrase notes" for more infos.
|
||||
#export BORG_PASSPHRASE='1ChagearC'
|
||||
|
||||
export BORG_REPO="ssh://100.121.203.110:2222/./repo/borg-repo"
|
||||
export BORG_PASSPHRASE="1ChagearC" # Encryption key
|
||||
BACKUP_SOURCES=(
|
||||
"/home/liph/Documents"
|
||||
"/home/liph/Pictures"
|
||||
"/home/liph/scripts"
|
||||
) # What to back up
|
||||
BACKUP_NAME="laptop-$(date +%Y-%m-%d)" # Dynamic backup name
|
||||
|
||||
# some helpers and error handling:
|
||||
info() { printf "\n%s %s\n\n" "$( date )" "$*" >&2; }
|
||||
trap 'echo $( date ) Backup interrupted >&2; exit 2' INT TERM
|
||||
|
||||
info "Starting backup"
|
||||
|
||||
# Initialize Borg repo (if not exists)
|
||||
borg init --encryption=repokey "$BORG_REPO" 2>/dev/null || true
|
||||
|
||||
# Backup the most important directories into an archive named after
|
||||
# the machine this script is currently running on:
|
||||
|
||||
borg create \
|
||||
--verbose \
|
||||
--filter AME \
|
||||
--list \
|
||||
--stats \
|
||||
--show-rc \
|
||||
--progress \
|
||||
--compression lz4 \
|
||||
--exclude-caches \
|
||||
--exclude 'home/*/.cache/*' \
|
||||
--exclude 'var/tmp/*' \
|
||||
"$BORG_REPO::$BACKUP_NAME" \
|
||||
"${BACKUP_SOURCES[@]}" \
|
||||
# ::'{hostname}-{user}-{now}' \
|
||||
# /home/liph/Documents/ \
|
||||
# /home/liph/Pictures/ \
|
||||
# /home/liph/Downloads/
|
||||
# /etc \
|
||||
# /home \
|
||||
# /root \
|
||||
# /var
|
||||
backup_exit=$?
|
||||
|
||||
info "Pruning repository"
|
||||
|
||||
# Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly
|
||||
# archives of THIS machine. The '{hostname}-*' matching is very important to
|
||||
# limit prune's operation to this machine's archives and not apply to
|
||||
# other machines' archives also:
|
||||
|
||||
borg prune \
|
||||
--list \
|
||||
--glob-archives '{hostname}-*' \
|
||||
--show-rc \
|
||||
--keep-daily 7 \
|
||||
--keep-weekly 4 \
|
||||
--keep-monthly 6
|
||||
"$BORG_REPO"
|
||||
|
||||
prune_exit=$?
|
||||
|
||||
# actually free repo disk space by compacting segments
|
||||
|
||||
info "Compacting repository"
|
||||
|
||||
borg compact
|
||||
|
||||
compact_exit=$?
|
||||
|
||||
# use highest exit code as global exit code
|
||||
global_exit=$(( backup_exit > prune_exit ? backup_exit : prune_exit ))
|
||||
global_exit=$(( compact_exit > global_exit ? compact_exit : global_exit ))
|
||||
|
||||
if [ ${global_exit} -eq 0 ]; then
|
||||
info "Backup, Prune, and Compact finished successfully"
|
||||
elif [ ${global_exit} -eq 1 ]; then
|
||||
info "Backup, Prune, and/or Compact finished with warnings"
|
||||
else
|
||||
info "Backup, Prune, and/or Compact finished with errors"
|
||||
fi
|
||||
|
||||
exit ${global_exit}
|
||||
|
||||
# Check backup integrity
|
||||
borg check "$BORG_REPO"
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Path to the brightness shader file
|
||||
SHADER_DIR="$HOME/.config/hypr/shaders"
|
||||
SHADER_FILE="$SHADER_DIR/brightness.frag"
|
||||
|
||||
# Ensure shader directory exists
|
||||
mkdir -p "$SHADER_DIR"
|
||||
|
||||
# Check if shader file exists, if not create with default values
|
||||
if [ ! -f "$SHADER_FILE" ]; then
|
||||
CURRENT_BRIGHTNESS=1.0
|
||||
BLUELIGHT_ENABLED=false
|
||||
else
|
||||
# Get current brightness multiplier
|
||||
CURRENT_BRIGHTNESS=$(grep -oP 'pixColor.rgb \*= \K[0-9.]+' "$SHADER_FILE" | tail -1)
|
||||
|
||||
# Check current state by looking at the blue channel multiplier
|
||||
if grep -q "pixColor.b \*= 0.6" "$SHADER_FILE"; then
|
||||
BLUELIGHT_ENABLED=true
|
||||
else
|
||||
BLUELIGHT_ENABLED=false
|
||||
fi
|
||||
fi
|
||||
|
||||
# Toggle the blue light filter state
|
||||
if [ "$BLUELIGHT_ENABLED" = true ]; then
|
||||
# Filter is ON, turn it OFF
|
||||
NEW_STATE=false
|
||||
echo "Blue light filter: OFF"
|
||||
else
|
||||
# Filter is OFF, turn it ON
|
||||
NEW_STATE=true
|
||||
echo "Blue light filter: ON"
|
||||
fi
|
||||
|
||||
# Recreate the shader file
|
||||
cat > "$SHADER_FILE" << EOF
|
||||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
|
||||
in vec2 v_texcoord;
|
||||
out vec4 fragColor;
|
||||
uniform sampler2D tex;
|
||||
|
||||
void main() {
|
||||
vec4 pixColor = texture(tex, v_texcoord);
|
||||
|
||||
EOF
|
||||
|
||||
if [ "$NEW_STATE" = true ]; then
|
||||
cat >> "$SHADER_FILE" << EOF
|
||||
// Reduce blue light
|
||||
pixColor.r *= 1.0;
|
||||
pixColor.g *= 0.85;
|
||||
pixColor.b *= 0.6;
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
cat >> "$SHADER_FILE" << EOF
|
||||
// Adjust brightness
|
||||
pixColor.rgb *= $CURRENT_BRIGHTNESS;
|
||||
|
||||
fragColor = pixColor;
|
||||
}
|
||||
EOF
|
||||
|
||||
# Apply shader
|
||||
if [ -z "$HYPRLAND_INSTANCE_SIGNATURE" ]; then
|
||||
export HYPRLAND_INSTANCE_SIGNATURE=$(ls -t /tmp/hypr/ 2>/dev/null | head -n1)
|
||||
fi
|
||||
/usr/bin/hyprctl keyword decoration:screen_shader "$SHADER_FILE"
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Path to the brightness shader file
|
||||
SHADER_DIR="$HOME/.config/hypr/shaders"
|
||||
SHADER_FILE="$SHADER_DIR/brightness.frag"
|
||||
|
||||
# Ensure shader directory exists
|
||||
mkdir -p "$SHADER_DIR"
|
||||
|
||||
# Check if shader file exists, if not create with default brightness
|
||||
if [ ! -f "$SHADER_FILE" ]; then
|
||||
CURRENT=1.0
|
||||
else
|
||||
# Get current brightness multiplier
|
||||
CURRENT=$(grep -oP 'pixColor.rgb \*= \K[0-9.]+' "$SHADER_FILE" | tail -1)
|
||||
fi
|
||||
|
||||
# Calculate new brightness (decrease by 10%)
|
||||
NEW=$(echo "$CURRENT * 0.90" | bc -l)
|
||||
|
||||
# Cap at 0.1 to prevent complete darkness
|
||||
if (( $(echo "$NEW < 0.1" | bc -l) )); then
|
||||
NEW=0.1
|
||||
fi
|
||||
|
||||
# Format to 2 decimal places
|
||||
NEW=$(printf "%.2f" "$NEW")
|
||||
|
||||
# Check if blue light filter is currently enabled
|
||||
BLUELIGHT_ENABLED=false
|
||||
if [ -f "$SHADER_FILE" ] && grep -q "pixColor.b \*= 0.6" "$SHADER_FILE"; then
|
||||
BLUELIGHT_ENABLED=true
|
||||
fi
|
||||
|
||||
# Recreate the shader file
|
||||
cat > "$SHADER_FILE" << EOF
|
||||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
|
||||
in vec2 v_texcoord;
|
||||
out vec4 fragColor;
|
||||
uniform sampler2D tex;
|
||||
|
||||
void main() {
|
||||
vec4 pixColor = texture(tex, v_texcoord);
|
||||
|
||||
EOF
|
||||
|
||||
if [ "$BLUELIGHT_ENABLED" = true ]; then
|
||||
cat >> "$SHADER_FILE" << EOF
|
||||
// Reduce blue light
|
||||
pixColor.r *= 1.0;
|
||||
pixColor.g *= 0.85;
|
||||
pixColor.b *= 0.6;
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
cat >> "$SHADER_FILE" << EOF
|
||||
// Adjust brightness
|
||||
pixColor.rgb *= $NEW;
|
||||
|
||||
fragColor = pixColor;
|
||||
}
|
||||
EOF
|
||||
|
||||
# Apply shader
|
||||
if [ -z "$HYPRLAND_INSTANCE_SIGNATURE" ]; then
|
||||
export HYPRLAND_INSTANCE_SIGNATURE=$(ls -t /tmp/hypr/ 2>/dev/null | head -n1)
|
||||
fi
|
||||
/usr/bin/hyprctl keyword decoration:screen_shader "$SHADER_FILE"
|
||||
|
||||
echo "Brightness decreased from $CURRENT to $NEW"
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Path to the brightness shader file
|
||||
SHADER_DIR="$HOME/.config/hypr/shaders"
|
||||
SHADER_FILE="$SHADER_DIR/brightness.frag"
|
||||
|
||||
# Ensure shader directory exists
|
||||
mkdir -p "$SHADER_DIR"
|
||||
|
||||
# Create shader file with 100% brightness and no blue light filter
|
||||
cat > "$SHADER_FILE" << EOF
|
||||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
|
||||
in vec2 v_texcoord;
|
||||
out vec4 fragColor;
|
||||
uniform sampler2D tex;
|
||||
|
||||
void main() {
|
||||
vec4 pixColor = texture(tex, v_texcoord);
|
||||
|
||||
// Adjust brightness
|
||||
pixColor.rgb *= 1.00;
|
||||
|
||||
fragColor = pixColor;
|
||||
}
|
||||
EOF
|
||||
|
||||
# Apply shader
|
||||
if [ -z "$HYPRLAND_INSTANCE_SIGNATURE" ]; then
|
||||
export HYPRLAND_INSTANCE_SIGNATURE=$(ls -t /tmp/hypr/ 2>/dev/null | head -n1)
|
||||
fi
|
||||
/usr/bin/hyprctl keyword decoration:screen_shader "$SHADER_FILE"
|
||||
|
||||
echo "Screen reset: Brightness 100%, Blue light filter OFF"
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Path to the brightness shader file
|
||||
SHADER_DIR="$HOME/.config/hypr/shaders"
|
||||
SHADER_FILE="$SHADER_DIR/brightness.frag"
|
||||
|
||||
# Ensure shader directory exists
|
||||
mkdir -p "$SHADER_DIR"
|
||||
|
||||
# Check if shader file exists, if not create with default brightness
|
||||
if [ ! -f "$SHADER_FILE" ]; then
|
||||
CURRENT=1.0
|
||||
else
|
||||
# Get current brightness multiplier
|
||||
CURRENT=$(grep -oP 'pixColor.rgb \*= \K[0-9.]+' "$SHADER_FILE" | tail -1)
|
||||
fi
|
||||
|
||||
# Calculate new brightness (increase by 10%)
|
||||
NEW=$(echo "$CURRENT * 1.10" | bc -l)
|
||||
|
||||
# Cap at 2.0 to prevent excessive brightness
|
||||
if (( $(echo "$NEW > 2.0" | bc -l) )); then
|
||||
NEW=2.0
|
||||
fi
|
||||
|
||||
# Format to 2 decimal places
|
||||
NEW=$(printf "%.2f" "$NEW")
|
||||
|
||||
# Check if blue light filter is currently enabled
|
||||
BLUELIGHT_ENABLED=false
|
||||
if [ -f "$SHADER_FILE" ] && grep -q "pixColor.b \*= 0.6" "$SHADER_FILE"; then
|
||||
BLUELIGHT_ENABLED=true
|
||||
fi
|
||||
|
||||
# Recreate the shader file
|
||||
cat > "$SHADER_FILE" << EOF
|
||||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
|
||||
in vec2 v_texcoord;
|
||||
out vec4 fragColor;
|
||||
uniform sampler2D tex;
|
||||
|
||||
void main() {
|
||||
vec4 pixColor = texture(tex, v_texcoord);
|
||||
|
||||
EOF
|
||||
|
||||
if [ "$BLUELIGHT_ENABLED" = true ]; then
|
||||
cat >> "$SHADER_FILE" << EOF
|
||||
// Reduce blue light
|
||||
pixColor.r *= 1.0;
|
||||
pixColor.g *= 0.85;
|
||||
pixColor.b *= 0.6;
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
cat >> "$SHADER_FILE" << EOF
|
||||
// Adjust brightness
|
||||
pixColor.rgb *= $NEW;
|
||||
|
||||
fragColor = pixColor;
|
||||
}
|
||||
EOF
|
||||
|
||||
# Apply shader
|
||||
if [ -z "$HYPRLAND_INSTANCE_SIGNATURE" ]; then
|
||||
export HYPRLAND_INSTANCE_SIGNATURE=$(ls -t /tmp/hypr/ 2>/dev/null | head -n1)
|
||||
fi
|
||||
/usr/bin/hyprctl keyword decoration:screen_shader "$SHADER_FILE"
|
||||
|
||||
echo "Brightness increased from $CURRENT to $NEW"
|
||||
@@ -0,0 +1,109 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -z "$BW_SESSION" ]; then
|
||||
export BW_SESSION=$(bw unlock --raw)
|
||||
fi
|
||||
|
||||
items=$(bw list items)
|
||||
|
||||
# Select item with preview showing full details
|
||||
selected=$(echo "$items" | jq -r '.[] | "\(.name)\t\(.login.username // "no username")"' | \
|
||||
column -t -s $'\t' | \
|
||||
fzf --preview 'name=$(echo {} | awk "{print \$1}"); bw get item "$name" 2>/dev/null | jq -r "
|
||||
\"Name: \" + .name,
|
||||
\"Type: \" + (.type | tostring),
|
||||
\"---\",
|
||||
(if .login then
|
||||
\"Username: \" + (.login.username // \"none\"),
|
||||
\"Password: \" + (if .login.password then \"********\" else \"none\" end),
|
||||
(if .login.uris then \"URIs:\", (.login.uris[] | \" - \" + .uri) else empty end),
|
||||
(if .login.totp then \"TOTP: configured\" else empty end)
|
||||
else empty end),
|
||||
(if .notes then \"---\", \"Notes:\", .notes else empty end),
|
||||
(if .fields then \"---\", \"Custom Fields:\", (.fields[] | \" \" + .name + \": \" + (if .type == 1 then \"********\" else (.value // \"empty\") end)) else empty end)
|
||||
" | cat' --preview-window=right:60%:wrap)
|
||||
|
||||
if [ -n "$selected" ]; then
|
||||
name=$(echo "$selected" | awk '{print $1}')
|
||||
|
||||
# Get full item details
|
||||
item=$(bw get item "$name" 2>/dev/null)
|
||||
|
||||
if [ -z "$item" ]; then
|
||||
notify-send "Bitwarden" "Failed to get item for $name"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build a list of available fields
|
||||
fields=()
|
||||
|
||||
if echo "$item" | jq -e '.login.password' &>/dev/null; then
|
||||
fields+=("Password")
|
||||
fi
|
||||
|
||||
if echo "$item" | jq -e '.login.username' &>/dev/null; then
|
||||
fields+=("Username")
|
||||
fi
|
||||
|
||||
if echo "$item" | jq -e '.login.uris[]' &>/dev/null; then
|
||||
fields+=("URI")
|
||||
fi
|
||||
|
||||
if echo "$item" | jq -e '.login.totp' &>/dev/null; then
|
||||
fields+=("TOTP Code")
|
||||
fi
|
||||
|
||||
if echo "$item" | jq -e '.notes' &>/dev/null; then
|
||||
notes=$(echo "$item" | jq -r '.notes')
|
||||
if [ -n "$notes" ] && [ "$notes" != "null" ]; then
|
||||
fields+=("Notes")
|
||||
fi
|
||||
fi
|
||||
|
||||
if echo "$item" | jq -e '.fields[]' &>/dev/null; then
|
||||
while IFS= read -r field_name; do
|
||||
fields+=("Custom: $field_name")
|
||||
done < <(echo "$item" | jq -r '.fields[] | .name')
|
||||
fi
|
||||
|
||||
fields+=("View All (JSON)")
|
||||
|
||||
# Let user choose what to copy
|
||||
choice=$(printf '%s\n' "${fields[@]}" | fzf --prompt="What to copy? ")
|
||||
|
||||
if [ -n "$choice" ]; then
|
||||
case "$choice" in
|
||||
"Password")
|
||||
echo "$item" | jq -r '.login.password' | wl-copy
|
||||
notify-send "Bitwarden" "Password copied for $name"
|
||||
;;
|
||||
"Username")
|
||||
echo "$item" | jq -r '.login.username' | wl-copy
|
||||
notify-send "Bitwarden" "Username copied for $name"
|
||||
;;
|
||||
"URI")
|
||||
echo "$item" | jq -r '.login.uris[0].uri' | wl-copy
|
||||
notify-send "Bitwarden" "URI copied for $name"
|
||||
;;
|
||||
"TOTP Code")
|
||||
totp=$(bw get totp "$name" 2>/dev/null)
|
||||
echo -n "$totp" | wl-copy
|
||||
notify-send "Bitwarden" "TOTP code copied for $name"
|
||||
;;
|
||||
"Notes")
|
||||
echo "$item" | jq -r '.notes' | wl-copy
|
||||
notify-send "Bitwarden" "Notes copied for $name"
|
||||
;;
|
||||
Custom:*)
|
||||
field_name="${choice#Custom: }"
|
||||
value=$(echo "$item" | jq -r --arg name "$field_name" '.fields[] | select(.name == $name) | .value')
|
||||
echo -n "$value" | wl-copy
|
||||
notify-send "Bitwarden" "Custom field '$field_name' copied"
|
||||
;;
|
||||
"View All (JSON)")
|
||||
echo "$item" | jq '.' | wl-copy
|
||||
notify-send "Bitwarden" "Full item JSON copied for $name"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Ensure script is run as root on the Proxmox host
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "Please run as root"
|
||||
exit
|
||||
fi
|
||||
|
||||
# Get all LXC IDs
|
||||
CONTAINERS=$(pct list | awk 'NR>1 {print $1}')
|
||||
|
||||
for VMID in $CONTAINERS; do
|
||||
# Check if container is running
|
||||
STATUS=$(pct status $VMID)
|
||||
|
||||
if [[ $STATUS == *"status: running"* ]]; then
|
||||
echo "========================================================"
|
||||
echo " CLEANING ARCH LXC: $VMID"
|
||||
echo "========================================================"
|
||||
|
||||
# 1. Clean Arch Linux Packages
|
||||
pct exec $VMID -- bash -c '
|
||||
echo "--- Removing orphaned packages ---"
|
||||
ORPHANS=$(pacman -Qtdq)
|
||||
if [ -n "$ORPHANS" ]; then
|
||||
pacman -Rns $ORPHANS --noconfirm
|
||||
else
|
||||
echo "No orphaned packages found."
|
||||
fi
|
||||
|
||||
echo "--- Fixing and cleaning pacman cache ---"
|
||||
# Remove those broken "download-" temporary files manually to stop the FD errors
|
||||
rm -f /var/cache/pacman/pkg/download-* 2>/dev/null
|
||||
|
||||
# Use paccache if installed (cleans all but latest 3 versions),
|
||||
# otherwise wipe the cache directory manually.
|
||||
if command -v paccache >/dev/null 2>&1; then
|
||||
paccache -r -k 0 --noconfirm
|
||||
else
|
||||
echo "paccache not found, performing manual cache wipe..."
|
||||
# Keeping the directory but removing all files
|
||||
find /var/cache/pacman/pkg/ -type f -delete
|
||||
fi
|
||||
'
|
||||
|
||||
# 2. Clean Podman
|
||||
pct exec $VMID -- bash -c '
|
||||
if command -v podman >/dev/null 2>&1; then
|
||||
echo "--- Podman found. Pruning all unused images ---"
|
||||
podman image prune -af
|
||||
else
|
||||
echo "--- Podman not installed. Skipping ---"
|
||||
fi
|
||||
'
|
||||
|
||||
echo "Finished cleaning $VMID"
|
||||
echo ""
|
||||
else
|
||||
echo "Skipping $VMID (Container is powered off)"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "All Arch containers processed."
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
# Convert your aerc/maildir to vCards
|
||||
em2vcf /mnt/flash1/mail-server/mail/maildir/ \
|
||||
--output-folder ~/.contacts_mail/ \
|
||||
--no-duplicates \
|
||||
--overwrite
|
||||
Executable
+107
@@ -0,0 +1,107 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Ask where to place the MP3 files
|
||||
read -p "Place MP3s in same folder as MP4s? (y/n) [y]: " same_folder
|
||||
same_folder=${same_folder:-y}
|
||||
|
||||
if [[ "$same_folder" =~ ^[Nn]$ ]]; then
|
||||
read -p "Enter output folder path: " output_folder
|
||||
mkdir -p "$output_folder"
|
||||
else
|
||||
output_folder=""
|
||||
fi
|
||||
|
||||
# Get default values from folder structure
|
||||
# Current directory is "The Energies of Love"
|
||||
default_album=$(basename "$PWD")
|
||||
# Parent directory is "Donna Eden & David Feinstein"
|
||||
default_album_artist=$(basename "$(dirname "$PWD")")
|
||||
|
||||
# Prompt for metadata with defaults
|
||||
read -p "Enter Album Artist [$default_album_artist]: " album_artist
|
||||
album_artist=${album_artist:-$default_album_artist}
|
||||
|
||||
read -p "Enter Release Date (YYYY): " release_date
|
||||
|
||||
echo ""
|
||||
echo "Processing MP4 files..."
|
||||
echo "Album Artist: $album_artist"
|
||||
echo ""
|
||||
|
||||
counter=0
|
||||
|
||||
# Process all mp4 files in subdirectories
|
||||
for file in */*.mp4 *.mp4; do
|
||||
# Skip if file doesn't exist
|
||||
[ -e "$file" ] || continue
|
||||
|
||||
dir=$(dirname "$file")
|
||||
filename=$(basename "$file" .mp4)
|
||||
|
||||
# Determine album based on folder structure
|
||||
if [ "$dir" != "." ]; then
|
||||
# File is in subfolder (Intro, week1, week2, etc.)
|
||||
album=$(basename "$dir")
|
||||
else
|
||||
# File is in current directory
|
||||
album="$default_album"
|
||||
fi
|
||||
|
||||
# Set output location
|
||||
if [ -n "$output_folder" ]; then
|
||||
# Create matching folder structure in output folder
|
||||
if [ "$dir" != "." ]; then
|
||||
mkdir -p "$output_folder/$dir"
|
||||
output="$output_folder/$dir/${filename}.mp3"
|
||||
else
|
||||
output="$output_folder/${filename}.mp3"
|
||||
fi
|
||||
else
|
||||
output="$dir/${filename}.mp3"
|
||||
fi
|
||||
|
||||
# Skip if already exists
|
||||
if [ -f "$output" ]; then
|
||||
echo "Skip: $filename (exists)"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Get track number
|
||||
track_num=$(echo "$filename" | grep -oP '^\d+')
|
||||
|
||||
echo "Converting: $filename"
|
||||
echo " Album: $album"
|
||||
|
||||
# Convert using temp file
|
||||
temp_file="/tmp/convert_$$.mp3"
|
||||
|
||||
if [ -n "$track_num" ]; then
|
||||
ffmpeg -i "$file" -vn -acodec libmp3lame -q:a 0 \
|
||||
-metadata title="$filename" \
|
||||
-metadata track="$track_num" \
|
||||
-metadata album_artist="$album_artist" \
|
||||
-metadata artist="$album_artist" \
|
||||
-metadata album="$album" \
|
||||
-metadata date="$release_date" \
|
||||
"$temp_file" -y >/dev/null 2>&1
|
||||
else
|
||||
ffmpeg -i "$file" -vn -acodec libmp3lame -q:a 0 \
|
||||
-metadata title="$filename" \
|
||||
-metadata album_artist="$album_artist" \
|
||||
-metadata artist="$album_artist" \
|
||||
-metadata album="$album" \
|
||||
-metadata date="$release_date" \
|
||||
"$temp_file" -y >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
if [ -f "$temp_file" ]; then
|
||||
mv "$temp_file" "$output"
|
||||
echo " ✓ Done"
|
||||
((counter++))
|
||||
else
|
||||
echo " ✗ Failed"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Converted $counter files"
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
# Save as ~/.config/niri/scripts/fix-bitwarden.sh
|
||||
# Make executable: chmod +x ~/.config/niri/scripts/fix-bitwarden.sh
|
||||
|
||||
niri msg -j event-stream | jq --unbuffered -r '
|
||||
select(.WindowOpenedOrChanged) |
|
||||
.WindowOpenedOrChanged.window |
|
||||
select(
|
||||
(.title? | match("Extension:.*LibreWolf")) and
|
||||
.is_floating == false
|
||||
) |
|
||||
.id
|
||||
' | while read id; do
|
||||
niri msg action toggle-window-floating --id="$id"
|
||||
niri msg action set-window-height 50%
|
||||
niri msg action set-window-width 20%
|
||||
done
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
# Save as ~/.config/niri/scripts/fix-bitwarden.sh
|
||||
# Make executable: chmod +x ~/.config/niri/scripts/fix-bitwarden.sh
|
||||
|
||||
niri msg -j event-stream | jq --unbuffered -r '
|
||||
select(.WindowOpenedOrChanged) |
|
||||
.WindowOpenedOrChanged.window |
|
||||
select(
|
||||
(.title? | match("Extension:.*LibreWolf")) and
|
||||
.is_floating == false
|
||||
) |
|
||||
.id
|
||||
' | while read id; do
|
||||
niri msg action toggle-window-floating --id="$id"
|
||||
niri msg action set-window-height 50%
|
||||
niri msg action set-window-width 20%
|
||||
done
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
# Fuzzy find email addresses with fzf
|
||||
|
||||
QUERY="$1"
|
||||
|
||||
# Get all addresses from notmuch
|
||||
ADDRESSES=$(notmuch address --output=sender --output=recipients \
|
||||
--deduplicate=address '*' | sort -u)
|
||||
|
||||
# If query is provided, pre-filter
|
||||
if [ -n "$QUERY" ]; then
|
||||
ADDRESSES=$(echo "$ADDRESSES" | grep -i "$QUERY")
|
||||
fi
|
||||
|
||||
# Use fzf for selection
|
||||
SELECTED=$(echo "$ADDRESSES" | fzf \
|
||||
--height=40% \
|
||||
--layout=reverse \
|
||||
--border \
|
||||
--prompt="Select recipient: " \
|
||||
--preview="" \
|
||||
--query="$QUERY")
|
||||
|
||||
# Output selected address
|
||||
echo "$SELECTED"
|
||||
Executable
+310
@@ -0,0 +1,310 @@
|
||||
# Fzf with Git in the shell
|
||||
# You can find this whole script from Junegunn Github repo below
|
||||
# https://github.com/junegunn/fzf-git.sh
|
||||
|
||||
# Script is used in .zshrc
|
||||
|
||||
# shellcheck disable=SC2039
|
||||
[[ $0 = - ]] && return
|
||||
|
||||
__fzf_git_color() {
|
||||
if [[ -n $NO_COLOR ]]; then
|
||||
echo never
|
||||
elif [[ $# -gt 0 ]] && [[ -n $FZF_GIT_PREVIEW_COLOR ]]; then
|
||||
echo "$FZF_GIT_PREVIEW_COLOR"
|
||||
else
|
||||
echo "${FZF_GIT_COLOR:-always}"
|
||||
fi
|
||||
}
|
||||
|
||||
__fzf_git_cat() {
|
||||
if [[ -n $FZF_GIT_CAT ]]; then
|
||||
echo "$FZF_GIT_CAT"
|
||||
return
|
||||
fi
|
||||
|
||||
# Sometimes bat is installed as batcat
|
||||
_fzf_git_bat_options="--style='${BAT_STYLE:-full}' --color=$(__fzf_git_color .) --pager=never"
|
||||
if command -v batcat > /dev/null; then
|
||||
echo "batcat $_fzf_git_bat_options"
|
||||
elif command -v bat > /dev/null; then
|
||||
echo "bat $_fzf_git_bat_options"
|
||||
else
|
||||
echo cat
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ $# -eq 1 ]]; then
|
||||
branches() {
|
||||
git branch "$@" --sort=-committerdate --sort=-HEAD --format=$'%(HEAD) %(color:yellow)%(refname:short) %(color:green)(%(committerdate:relative))\t%(color:blue)%(subject)%(color:reset)' --color=$(__fzf_git_color) | column -ts$'\t'
|
||||
}
|
||||
refs() {
|
||||
git for-each-ref --sort=-creatordate --sort=-HEAD --color=$(__fzf_git_color) --format=$'%(refname) %(color:green)(%(creatordate:relative))\t%(color:blue)%(subject)%(color:reset)' |
|
||||
eval "$1" |
|
||||
sed 's#^refs/remotes/#\x1b[95mremote-branch\t\x1b[33m#; s#^refs/heads/#\x1b[92mbranch\t\x1b[33m#; s#^refs/tags/#\x1b[96mtag\t\x1b[33m#; s#refs/stash#\x1b[91mstash\t\x1b[33mrefs/stash#' |
|
||||
column -ts$'\t'
|
||||
}
|
||||
hashes() {
|
||||
git log --date=short --format="%C(green)%C(bold)%cd %C(auto)%h%d %s (%an)" --graph --color=$(__fzf_git_color) "$@"
|
||||
}
|
||||
case "$1" in
|
||||
branches)
|
||||
echo $'CTRL-O (open in browser) ╱ ALT-A (show all branches)\n'
|
||||
branches
|
||||
;;
|
||||
all-branches)
|
||||
echo $'CTRL-O (open in browser)\n'
|
||||
branches -a
|
||||
;;
|
||||
hashes)
|
||||
echo $'CTRL-O (open in browser) ╱ CTRL-D (diff)\nCTRL-S (toggle sort) ╱ ALT-A (show all hashes)\n'
|
||||
hashes
|
||||
;;
|
||||
all-hashes)
|
||||
echo $'CTRL-O (open in browser) ╱ CTRL-D (diff)\nCTRL-S (toggle sort)\n'
|
||||
hashes --all
|
||||
;;
|
||||
refs)
|
||||
echo $'CTRL-O (open in browser) ╱ ALT-E (examine in editor) ╱ ALT-A (show all refs)\n'
|
||||
refs 'grep -v ^refs/remotes'
|
||||
;;
|
||||
all-refs)
|
||||
echo $'CTRL-O (open in browser) ╱ ALT-E (examine in editor)\n'
|
||||
refs 'cat'
|
||||
;;
|
||||
nobeep) ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
elif [[ $# -gt 1 ]]; then
|
||||
set -e
|
||||
|
||||
branch=$(git rev-parse --abbrev-ref HEAD 2> /dev/null)
|
||||
if [[ $branch = HEAD ]]; then
|
||||
branch=$(git describe --exact-match --tags 2> /dev/null || git rev-parse --short HEAD)
|
||||
fi
|
||||
|
||||
# Only supports GitHub for now
|
||||
case "$1" in
|
||||
commit)
|
||||
hash=$(grep -o "[a-f0-9]\{7,\}" <<< "$2")
|
||||
path=/commit/$hash
|
||||
;;
|
||||
branch|remote-branch)
|
||||
branch=$(sed 's/^[* ]*//' <<< "$2" | cut -d' ' -f1)
|
||||
remote=$(git config branch."${branch}".remote || echo 'origin')
|
||||
branch=${branch#$remote/}
|
||||
path=/tree/$branch
|
||||
;;
|
||||
remote)
|
||||
remote=$2
|
||||
path=/tree/$branch
|
||||
;;
|
||||
file) path=/blob/$branch/$(git rev-parse --show-prefix)$2 ;;
|
||||
tag) path=/releases/tag/$2 ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
|
||||
remote=${remote:-$(git config branch."${branch}".remote || echo 'origin')}
|
||||
remote_url=$(git remote get-url "$remote" 2> /dev/null || echo "$remote")
|
||||
|
||||
if [[ $remote_url =~ ^git@ ]]; then
|
||||
url=${remote_url%.git}
|
||||
url=${url#git@}
|
||||
url=https://${url/://}
|
||||
elif [[ $remote_url =~ ^http ]]; then
|
||||
url=${remote_url%.git}
|
||||
fi
|
||||
|
||||
case "$(uname -s)" in
|
||||
Darwin) open "$url$path" ;;
|
||||
*) xdg-open "$url$path" ;;
|
||||
esac
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ $- =~ i ]]; then
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Redefine this function to change the options
|
||||
_fzf_git_fzf() {
|
||||
fzf-tmux -p80%,60% -- \
|
||||
--layout=reverse --multi --height=50% --min-height=20 --border \
|
||||
--border-label-pos=2 \
|
||||
--color='header:italic:underline,label:blue' \
|
||||
--preview-window='right,50%,border-left' \
|
||||
--bind='ctrl-/:change-preview-window(down,50%,border-top|hidden|)' "$@"
|
||||
}
|
||||
|
||||
_fzf_git_check() {
|
||||
git rev-parse HEAD > /dev/null 2>&1 && return
|
||||
|
||||
[[ -n $TMUX ]] && tmux display-message "Not in a git repository"
|
||||
return 1
|
||||
}
|
||||
|
||||
__fzf_git=${BASH_SOURCE[0]:-${(%):-%x}}
|
||||
__fzf_git=$(readlink -f "$__fzf_git" 2> /dev/null || /usr/bin/ruby --disable-gems -e 'puts File.expand_path(ARGV.first)' "$__fzf_git" 2> /dev/null)
|
||||
|
||||
_fzf_git_files() {
|
||||
_fzf_git_check || return
|
||||
local root query
|
||||
root=$(git rev-parse --show-toplevel)
|
||||
[[ $root != "$PWD" ]] && query='!../ '
|
||||
|
||||
(git -c color.status=$(__fzf_git_color) status --short --no-branch
|
||||
git ls-files "$root" | grep -vxFf <(git status -s | grep '^[^?]' | cut -c4-; echo :) | sed 's/^/ /') |
|
||||
_fzf_git_fzf -m --ansi --nth 2..,.. \
|
||||
--border-label '📁 Files' \
|
||||
--header $'CTRL-O (open in browser) ╱ ALT-E (open in editor)\n\n' \
|
||||
--bind "ctrl-o:execute-silent:bash $__fzf_git file {-1}" \
|
||||
--bind "alt-e:execute:${EDITOR:-vim} {-1} > /dev/tty" \
|
||||
--query "$query" \
|
||||
--preview "git diff --no-ext-diff --color=$(__fzf_git_color .) -- {-1} | sed 1,4d; $(__fzf_git_cat) {-1}" "$@" |
|
||||
cut -c4- | sed 's/.* -> //'
|
||||
}
|
||||
|
||||
_fzf_git_branches() {
|
||||
_fzf_git_check || return
|
||||
bash "$__fzf_git" branches |
|
||||
_fzf_git_fzf --ansi \
|
||||
--border-label '🌲 Branches' \
|
||||
--header-lines 2 \
|
||||
--tiebreak begin \
|
||||
--preview-window down,border-top,40% \
|
||||
--color hl:underline,hl+:underline \
|
||||
--no-hscroll \
|
||||
--bind 'ctrl-/:change-preview-window(down,70%|hidden|)' \
|
||||
--bind "ctrl-o:execute-silent:bash $__fzf_git branch {}" \
|
||||
--bind "alt-a:change-border-label(🌳 All branches)+reload:bash \"$__fzf_git\" all-branches" \
|
||||
--preview "git log --oneline --graph --date=short --color=$(__fzf_git_color .) --pretty='format:%C(auto)%cd %h%d %s' \$(sed s/^..// <<< {} | cut -d' ' -f1) --" "$@" |
|
||||
sed 's/^..//' | cut -d' ' -f1
|
||||
}
|
||||
|
||||
_fzf_git_tags() {
|
||||
_fzf_git_check || return
|
||||
git tag --sort -version:refname |
|
||||
_fzf_git_fzf --preview-window right,70% \
|
||||
--border-label '📛 Tags' \
|
||||
--header $'CTRL-O (open in browser)\n\n' \
|
||||
--bind "ctrl-o:execute-silent:bash $__fzf_git tag {}" \
|
||||
--preview "git show --color=$(__fzf_git_color .) {}" "$@"
|
||||
}
|
||||
|
||||
_fzf_git_hashes() {
|
||||
_fzf_git_check || return
|
||||
bash "$__fzf_git" hashes |
|
||||
_fzf_git_fzf --ansi --no-sort --bind 'ctrl-s:toggle-sort' \
|
||||
--border-label '🍡 Hashes' \
|
||||
--header-lines 3 \
|
||||
--bind "ctrl-o:execute-silent:bash $__fzf_git commit {}" \
|
||||
--bind "ctrl-d:execute:grep -o '[a-f0-9]\{7,\}' <<< {} | head -n 1 | xargs git diff --color=$(__fzf_git_color) > /dev/tty" \
|
||||
--bind "alt-a:change-border-label(🍇 All hashes)+reload:bash \"$__fzf_git\" all-hashes" \
|
||||
--color hl:underline,hl+:underline \
|
||||
--preview "grep -o '[a-f0-9]\{7,\}' <<< {} | head -n 1 | xargs git show --color=$(__fzf_git_color .)" "$@" |
|
||||
awk 'match($0, /[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]*/) { print substr($0, RSTART, RLENGTH) }'
|
||||
}
|
||||
|
||||
_fzf_git_remotes() {
|
||||
_fzf_git_check || return
|
||||
git remote -v | awk '{print $1 "\t" $2}' | uniq |
|
||||
_fzf_git_fzf --tac \
|
||||
--border-label '📡 Remotes' \
|
||||
--header $'CTRL-O (open in browser)\n\n' \
|
||||
--bind "ctrl-o:execute-silent:bash $__fzf_git remote {1}" \
|
||||
--preview-window right,70% \
|
||||
--preview "git log --oneline --graph --date=short --color=$(__fzf_git_color .) --pretty='format:%C(auto)%cd %h%d %s' '{1}/$(git rev-parse --abbrev-ref HEAD)' --" "$@" |
|
||||
cut -d$'\t' -f1
|
||||
}
|
||||
|
||||
_fzf_git_stashes() {
|
||||
_fzf_git_check || return
|
||||
git stash list | _fzf_git_fzf \
|
||||
--border-label '🥡 Stashes' \
|
||||
--header $'CTRL-X (drop stash)\n\n' \
|
||||
--bind 'ctrl-x:reload(git stash drop -q {1}; git stash list)' \
|
||||
-d: --preview "git show --color=$(__fzf_git_color .) {1}" "$@" |
|
||||
cut -d: -f1
|
||||
}
|
||||
|
||||
_fzf_git_lreflogs() {
|
||||
_fzf_git_check || return
|
||||
git reflog --color=$(__fzf_git_color) --format="%C(blue)%gD %C(yellow)%h%C(auto)%d %gs" | _fzf_git_fzf --ansi \
|
||||
--border-label '📒 Reflogs' \
|
||||
--preview "git show --color=$(__fzf_git_color .) {1}" "$@" |
|
||||
awk '{print $1}'
|
||||
}
|
||||
|
||||
_fzf_git_each_ref() {
|
||||
_fzf_git_check || return
|
||||
bash "$__fzf_git" refs | _fzf_git_fzf --ansi \
|
||||
--nth 2,2.. \
|
||||
--tiebreak begin \
|
||||
--border-label '☘️ Each ref' \
|
||||
--header-lines 2 \
|
||||
--preview-window down,border-top,40% \
|
||||
--color hl:underline,hl+:underline \
|
||||
--no-hscroll \
|
||||
--bind 'ctrl-/:change-preview-window(down,70%|hidden|)' \
|
||||
--bind "ctrl-o:execute-silent:bash $__fzf_git {1} {2}" \
|
||||
--bind "alt-e:execute:${EDITOR:-vim} <(git show {2}) > /dev/tty" \
|
||||
--bind "alt-a:change-border-label(🍀 Every ref)+reload:bash \"$__fzf_git\" all-refs" \
|
||||
--preview "git log --oneline --graph --date=short --color=$(__fzf_git_color .) --pretty='format:%C(auto)%cd %h%d %s' {2} --" "$@" |
|
||||
awk '{print $2}'
|
||||
}
|
||||
|
||||
_fzf_git_worktrees() {
|
||||
_fzf_git_check || return
|
||||
git worktree list | _fzf_git_fzf \
|
||||
--border-label '🌴 Worktrees' \
|
||||
--header $'CTRL-X (remove worktree)\n\n' \
|
||||
--bind 'ctrl-x:reload(git worktree remove {1} > /dev/null; git worktree list)' \
|
||||
--preview "
|
||||
git -c color.status=$(__fzf_git_color .) -C {1} status --short --branch
|
||||
echo
|
||||
git log --oneline --graph --date=short --color=$(__fzf_git_color .) --pretty='format:%C(auto)%cd %h%d %s' {2} --
|
||||
" "$@" |
|
||||
awk '{print $1}'
|
||||
}
|
||||
|
||||
if [[ -n "${BASH_VERSION:-}" ]]; then
|
||||
__fzf_git_init() {
|
||||
bind -m emacs-standard '"\er": redraw-current-line'
|
||||
bind -m emacs-standard '"\C-z": vi-editing-mode'
|
||||
bind -m vi-command '"\C-z": emacs-editing-mode'
|
||||
bind -m vi-insert '"\C-z": emacs-editing-mode'
|
||||
|
||||
local o c
|
||||
for o in "$@"; do
|
||||
c=${o:0:1}
|
||||
bind -m emacs-standard '"\C-g\C-'$c'": " \C-u \C-a\C-k`_fzf_git_'$o'`\e\C-e\C-y\C-a\C-y\ey\C-h\C-e\er \C-h"'
|
||||
bind -m vi-command '"\C-g\C-'$c'": "\C-z\C-g\C-'$c'\C-z"'
|
||||
bind -m vi-insert '"\C-g\C-'$c'": "\C-z\C-g\C-'$c'\C-z"'
|
||||
bind -m emacs-standard '"\C-g'$c'": " \C-u \C-a\C-k`_fzf_git_'$o'`\e\C-e\C-y\C-a\C-y\ey\C-h\C-e\er \C-h"'
|
||||
bind -m vi-command '"\C-g'$c'": "\C-z\C-g'$c'\C-z"'
|
||||
bind -m vi-insert '"\C-g'$c'": "\C-z\C-g'$c'\C-z"'
|
||||
done
|
||||
}
|
||||
elif [[ -n "${ZSH_VERSION:-}" ]]; then
|
||||
__fzf_git_join() {
|
||||
local item
|
||||
while read item; do
|
||||
echo -n "${(q)item} "
|
||||
done
|
||||
}
|
||||
|
||||
__fzf_git_init() {
|
||||
local m o
|
||||
for o in "$@"; do
|
||||
eval "fzf-git-$o-widget() { local result=\$(_fzf_git_$o | __fzf_git_join); zle reset-prompt; LBUFFER+=\$result }"
|
||||
eval "zle -N fzf-git-$o-widget"
|
||||
for m in emacs vicmd viins; do
|
||||
eval "bindkey -M $m '^g^${o[1]}' fzf-git-$o-widget"
|
||||
eval "bindkey -M $m '^g${o[1]}' fzf-git-$o-widget"
|
||||
done
|
||||
done
|
||||
}
|
||||
fi
|
||||
__fzf_git_init files branches tags remotes hashes stashes lreflogs each_ref worktrees
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
fi
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script to list recent files and open nvim using fzf
|
||||
# set to an alias nlof in .zshrc
|
||||
|
||||
list_oldfiles() {
|
||||
# Get the oldfiles list from Neovim
|
||||
local oldfiles=($(nvim -u NONE --headless +'lua io.write(table.concat(vim.v.oldfiles, "\n") .. "\n")' +qa))
|
||||
# Filter invalid paths or files not found
|
||||
local valid_files=()
|
||||
for file in "${oldfiles[@]}"; do
|
||||
if [[ -f "$file" ]]; then
|
||||
valid_files+=("$file")
|
||||
fi
|
||||
done
|
||||
# Use fzf to select from valid files
|
||||
local files=($(printf "%s\n" "${valid_files[@]}" | \
|
||||
grep -v '\[.*' | \
|
||||
fzf --multi \
|
||||
--preview 'bat -n --color=always --line-range=:500 {} 2>/dev/null || echo "Error previewing file"' \
|
||||
--height=70% \
|
||||
--layout=default))
|
||||
|
||||
# Open selected files in Neovim
|
||||
[[ ${#files[@]} -gt 0 ]] && nvim "${files[@]}"
|
||||
}
|
||||
|
||||
# Call the function
|
||||
list_oldfiles "$@"
|
||||
@@ -0,0 +1,3 @@
|
||||
kanata --cfg ~/.config/kanata/config.kbd &
|
||||
|
||||
sudo mount -a
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
# ~/.config/hypr/scripts/keyboard-layer.sh
|
||||
|
||||
# This checks which modifiers are active as a proxy for layers
|
||||
# Adjust based on your actual layer keys
|
||||
|
||||
while true; do
|
||||
# You might need to adjust this based on your keyboard
|
||||
# This is a simplified example
|
||||
echo '{"text": "Layer ?", "class": "layer"}'
|
||||
sleep 0.5
|
||||
done
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
case $1 in
|
||||
0) notify-send -t 1500 "Layer 0" "Base/QWERTY" ;;
|
||||
1) notify-send -t 1500 "Layer 1" "Navigation/Numbers" ;;
|
||||
2) notify-send -t 1500 "Layer 2" "Symbols" ;;
|
||||
3) notify-send -t 1500 "Layer 3" "Function Keys" ;;
|
||||
*) notify-send -t 1500 "Unknown Layer" ;;
|
||||
esac
|
||||
Executable
+131
@@ -0,0 +1,131 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# --- CONFIGURATION ---
|
||||
# The user that runs paru inside the Arch LXCs
|
||||
AUR_USER="liph"
|
||||
|
||||
EXCLUDE_LIST=(120 121 150 151 152)
|
||||
|
||||
declare -A CONTAINER_MAP
|
||||
CONTAINER_MAP[100]="/mnt/flash1/podman/lxc_servarr/"
|
||||
CONTAINER_MAP[101]="/mnt/flash1/podman/lxc_second/"
|
||||
CONTAINER_MAP[108]="/mnt/flash1/podman/lxc_dns/" # Multiple paths allowed
|
||||
CONTAINER_MAP[109]="/mnt/flash1/podman/lxc_immich/"
|
||||
CONTAINER_MAP[111]="/mnt/flash1/podman/lxc_ollama/"
|
||||
|
||||
# --- UTILS ---
|
||||
log() {
|
||||
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
|
||||
}
|
||||
|
||||
# Wrapper for commands that modify state
|
||||
run_pct() {
|
||||
if [[ "${DRY_RUN:-0}" == "1" ]]; then
|
||||
log "[DRY-RUN] pct $*"
|
||||
else
|
||||
pct "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
ALL_CTIDS=$(pct list | awk 'NR>1 {print $1}')
|
||||
|
||||
for CTID in $ALL_CTIDS; do
|
||||
# Check if CTID is in EXCLUDE_LIST
|
||||
IS_EXCLUDED=false
|
||||
for EXCLUDE in "${EXCLUDE_LIST[@]}"; do
|
||||
if [[ "$CTID" == "$EXCLUDE" ]]; then
|
||||
IS_EXCLUDED=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ "$IS_EXCLUDED" = true ]; then continue; fi
|
||||
|
||||
if pct config "$CTID" | grep -q "template: 1"; then continue; fi
|
||||
|
||||
NAME=$(pct config "$CTID" | grep "hostname:" | awk '{print $2}')
|
||||
STATUS=$(pct status "$CTID" | awk '{print $2}')
|
||||
|
||||
echo "======================================================="
|
||||
log "PROCESSING LXC: $NAME (ID: $CTID)"
|
||||
echo "======================================================="
|
||||
|
||||
WAS_STOPPED=false
|
||||
if [ "$STATUS" == "stopped" ]; then
|
||||
run_pct start "$CTID"
|
||||
[[ "${DRY_RUN:-0}" == "0" ]] && sleep 10
|
||||
WAS_STOPPED=true
|
||||
fi
|
||||
|
||||
# --- 1. SETUP PASSWORDLESS FOR PARU ---
|
||||
# Paru MUST run as a user, so we keep this sudoers rule for pacman.
|
||||
log "[+] Configuring temporary sudoers for $AUR_USER..."
|
||||
run_pct exec "$CTID" -- bash -c "echo '$AUR_USER ALL=(ALL) NOPASSWD: /usr/bin/pacman' > /etc/sudoers.d/99-paru-nopass"
|
||||
run_pct exec "$CTID" -- chmod 440 /etc/sudoers.d/99-paru-nopass
|
||||
|
||||
# --- 2. OS UPDATER (User Context) ---
|
||||
log "[+] Updating Arch packages (as $AUR_USER)..."
|
||||
run_pct exec "$CTID" -- sudo -u "$AUR_USER" paru -Syu --noconfirm --cleanafter
|
||||
|
||||
# --- 3. PODMAN SCAN (Root Context) ---
|
||||
if [[ -n "${CONTAINER_MAP[$CTID]:-}" ]]; then
|
||||
# Check Storage Driver (Diagnostic)
|
||||
DRIVER=$(pct exec "$CTID" -- podman info --format '{{.Store.GraphDriverName}}' 2>/dev/null || echo "unknown")
|
||||
if [[ "$DRIVER" == "vfs" ]]; then
|
||||
log "[WARN] Storage driver is 'vfs'. Image operations will be slow."
|
||||
fi
|
||||
|
||||
# Support multiple paths
|
||||
ROOT_DIRS=${CONTAINER_MAP[$CTID]}
|
||||
for ROOT_DIR in $ROOT_DIRS; do
|
||||
log "[+] Scanning for compose files in: $ROOT_DIR"
|
||||
|
||||
# Determine Command
|
||||
if pct exec "$CTID" -- podman compose version >/dev/null 2>&1; then
|
||||
FINAL_CMD="podman compose"
|
||||
elif pct exec "$CTID" -- podman-compose version >/dev/null 2>&1; then
|
||||
FINAL_CMD="podman-compose"
|
||||
elif pct exec "$CTID" -- docker-compose version >/dev/null 2>&1; then
|
||||
FINAL_CMD="docker-compose"
|
||||
else FINAL_CMD=""; fi
|
||||
|
||||
if [ -n "$FINAL_CMD" ]; then
|
||||
# Scan for files
|
||||
if pct exec "$CTID" -- [ -d "$ROOT_DIR" ]; then
|
||||
pct exec "$CTID" -- find "$ROOT_DIR" -maxdepth 2 -name "docker-compose.y*ml" | while read -r FILE; do
|
||||
[ -z "$FILE" ] && continue
|
||||
DIR=$(dirname "$FILE")
|
||||
log " -> Updating Project: $DIR"
|
||||
|
||||
log " -> Pulling new images (this may take a while)..."
|
||||
run_pct exec "$CTID" -- bash -c "cd \"$DIR\" && $FINAL_CMD pull"
|
||||
|
||||
if [ "$WAS_STOPPED" = true ]; then
|
||||
log " -> Recreating stopped container (up --no-start)..."
|
||||
run_pct exec "$CTID" -- bash -c "cd \"$DIR\" && $FINAL_CMD up --no-start" ||
|
||||
log " [WARN] Failed to recreate stopped container. Old images may not be pruned."
|
||||
else
|
||||
log " -> Applying updates (up -d --force-recreate)..."
|
||||
run_pct exec "$CTID" -- bash -c "cd \"$DIR\" && $FINAL_CMD up -d --force-recreate"
|
||||
fi
|
||||
done
|
||||
else
|
||||
log " [WARN] Root directory not found: $ROOT_DIR"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
log "[+] Pruning all unused images to save space..."
|
||||
run_pct exec "$CTID" -- podman image prune -a -f
|
||||
fi
|
||||
|
||||
# --- 4. MAINTENANCE ---
|
||||
log "[+] Running maintenance tasks (journal, orphans)..."
|
||||
run_pct exec "$CTID" -- journalctl --rotate
|
||||
run_pct exec "$CTID" -- journalctl --vacuum-time=7d
|
||||
run_pct exec "$CTID" -- bash -c "orphans=\$(pacman -Qtdq); if [ -n \"\$orphans\" ]; then echo \" -> Removing orphans: \$orphans\"; pacman -Rns \$orphans --noconfirm; fi"
|
||||
|
||||
if [ "$WAS_STOPPED" = true ]; then
|
||||
log "[+] Shutting down container (was previously stopped)..."
|
||||
run_pct shutdown "$CTID"
|
||||
fi
|
||||
done
|
||||
Executable
+92
@@ -0,0 +1,92 @@
|
||||
#!/bin/bash
|
||||
|
||||
# --- CONFIGURATION ---
|
||||
# The user that runs paru inside the Arch LXCs
|
||||
AUR_USER="liph"
|
||||
|
||||
# 1. EXCLUDE LIST: Put CTIDs here that you want the script to TOTALLY ignore
|
||||
# Example: EXCLUDE_LIST=( 105 110 )
|
||||
EXCLUDE_LIST=(106 113 114 115 116)
|
||||
|
||||
declare -A CONTAINER_MAP
|
||||
CONTAINER_MAP[100]="/mnt/flash1/podman/lxc_servarr/"
|
||||
CONTAINER_MAP[101]="/mnt/flash1/podman/lxc_second/"
|
||||
CONTAINER_MAP[108]="/mnt/flash1/podman/lxc_dns/" # Multiple paths allowed
|
||||
CONTAINER_MAP[109]="/mnt/flash1/podman/lxc_immich/"
|
||||
CONTAINER_MAP[111]="/mnt/flash1/podman/lxc_ollama/"
|
||||
|
||||
ALL_CTIDS=$(pct list | awk 'NR>1 {print $1}')
|
||||
|
||||
for CTID in $ALL_CTIDS; do
|
||||
if [[ " ${EXCLUDE_LIST[@]} " =~ " ${CTID} " ]]; then continue; fi
|
||||
if pct config $CTID | grep -q "template: 1"; then continue; fi
|
||||
|
||||
NAME=$(pct config $CTID | grep "hostname:" | awk '{print $2}')
|
||||
STATUS=$(pct status $CTID | awk '{print $2}')
|
||||
|
||||
echo "======================================================="
|
||||
echo " PROCESSING LXC: $NAME (ID: $CTID)"
|
||||
echo "======================================================="
|
||||
|
||||
WAS_STOPPED=false
|
||||
if [ "$STATUS" == "stopped" ]; then
|
||||
pct start $CTID
|
||||
sleep 10
|
||||
WAS_STOPPED=true
|
||||
fi
|
||||
|
||||
# 1. OS UPDATER (Handling Paru correctly)
|
||||
echo "[+] Updating Arch packages..."
|
||||
# We use -Syu. We run it via 'sudo -u user' but because pct exec is root,
|
||||
# it won't ask for a password.
|
||||
pct exec $CTID -- sudo -u $AUR_USER paru -Syu --noconfirm --cleanafter
|
||||
|
||||
# 2. PODMAN SCAN & AUTO-DETECT COMMAND
|
||||
if [[ -n "${CONTAINER_MAP[$CTID]}" ]]; then
|
||||
ROOT_DIR=${CONTAINER_MAP[$CTID]}
|
||||
|
||||
# Detect which command works: 'podman compose' (V2) or 'podman-compose' (Python)
|
||||
# We test this inside the LXC
|
||||
if pct exec $CTID -- podman compose version >/dev/null 2>&1; then
|
||||
FINAL_CMD="podman compose"
|
||||
elif pct exec $CTID -- podman-compose version >/dev/null 2>&1; then
|
||||
FINAL_CMD="podman-compose"
|
||||
elif pct exec $CTID -- docker-compose version >/dev/null 2>&1; then
|
||||
FINAL_CMD="docker-compose"
|
||||
else
|
||||
FINAL_CMD=""
|
||||
fi
|
||||
|
||||
if [ -z "$FINAL_CMD" ]; then
|
||||
echo "[ERROR] No compose command found in LXC $CTID!"
|
||||
else
|
||||
echo "[#] Using command: $FINAL_CMD"
|
||||
COMPOSE_FILES=$(pct exec $CTID -- find "$ROOT_DIR" -maxdepth 2 -name "docker-compose.y*ml")
|
||||
|
||||
for FILE in $COMPOSE_FILES; do
|
||||
DIR=$(dirname "$FILE")
|
||||
echo " -> Updating: $DIR"
|
||||
|
||||
# Run the pull and up
|
||||
# Note: No 'sudo' here because pct exec is already root full
|
||||
pct exec $CTID -- bash -c "cd $DIR && $FINAL_CMD pull"
|
||||
|
||||
if [ "$WAS_STOPPED" = false ]; then
|
||||
pct exec $CTID -- bash -c "cd $DIR && $FINAL_CMD up -d"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "[+] Pruning images..."
|
||||
pct exec $CTID -- podman image prune -f
|
||||
fi
|
||||
|
||||
# 3. MAINTENANCE
|
||||
pct exec $CTID -- journalctl --rotate
|
||||
pct exec $CTID -- journalctl --vacuum-time=7d
|
||||
pct exec $CTID -- bash -c 'orphans=$(pacman -Qtdq); if [ -n "$orphans" ]; then pacman -Rns $orphans --noconfirm; fi'
|
||||
|
||||
if [ "$WAS_STOPPED" = true ]; then
|
||||
pct shutdown $CTID
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Ask for the final filename first
|
||||
echo "=== Video Downloader (yt-dlp + aria2c) ==="
|
||||
read -p "Enter the final filename (without extension): " filename
|
||||
|
||||
# Then ask for the m3u8 URL
|
||||
read -p "Enter the m3u8 URL: " url
|
||||
|
||||
# Download using yt-dlp with aria2c
|
||||
echo "Starting download..."
|
||||
yt-dlp --external-downloader aria2c \
|
||||
--external-downloader-args "aria2c:-x 16 -s 16" \
|
||||
-o "${filename}.%(ext)s" \
|
||||
"$url"
|
||||
|
||||
echo "Download complete: ${filename}.mp4"
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python3
|
||||
# ~/.local/bin/maildir2vcf
|
||||
import email, os, sys, pathlib, fileinput
|
||||
|
||||
MAILDIR = pathlib.Path.home()/ "Mail" # ← change if your mail sits elsewhere
|
||||
OUTDIR = pathlib.Path.home()/ ".contacts_mail"
|
||||
OUTDIR.mkdir(exist_ok=True)
|
||||
|
||||
seen = set() # de-duplicate on lower-case e-mail
|
||||
|
||||
def vcard(name, mail):
|
||||
safe_name = name.replace(";", " ").strip() or "No Name"
|
||||
safe_mail = mail.strip().lower()
|
||||
if safe_mail in seen: # already exported
|
||||
return
|
||||
seen.add(safe_mail)
|
||||
fn = OUTDIR/f"{safe_mail}.vcf"
|
||||
fn.write_text(f"""\
|
||||
BEGIN:VCARD
|
||||
VERSION:3.0
|
||||
FN:{safe_name}
|
||||
EMAIL:{safe_mail}
|
||||
END:VCARD
|
||||
""")
|
||||
|
||||
def addresses_from_msg(path):
|
||||
with open(path, "rb") as f:
|
||||
msg = email.message_from_binary_file(f)
|
||||
for hdr in ("From", "To", "Cc", "Bcc"):
|
||||
for addr in email.utils.getaddresses(msg.get_all(hdr, [])):
|
||||
name, mail = addr
|
||||
if "@" in mail:
|
||||
vcard(name, mail)
|
||||
|
||||
# walk cur/ + new/ (typical Maildir layout)
|
||||
for sub in ("cur", "new"):
|
||||
for root, _, files in os.walk(MAILDIR/sub):
|
||||
for file in files:
|
||||
if file.startswith("."):
|
||||
continue
|
||||
addresses_from_msg(pathlib.Path(root)/file)
|
||||
|
||||
print("Exported", len(seen), "unique addresses →", OUTDIR)
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Get the current message's notmuch ID from aerc's environment
|
||||
# We'll use notmuch to find and move the file
|
||||
|
||||
maildir="$HOME/.local/share/mail"
|
||||
|
||||
# Find files for messages in current thread that aren't already in Trash
|
||||
notmuch search --output=files thread:{} 2>/dev/null | while read filepath; do
|
||||
# Skip if already in Trash
|
||||
if [[ "$filepath" == *"/Trash/"* ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ -f "$filepath" ]]; then
|
||||
filename=$(basename "$filepath")
|
||||
mkdir -p "$maildir/Trash/cur"
|
||||
mv "$filepath" "$maildir/Trash/cur/$filename"
|
||||
fi
|
||||
done
|
||||
|
||||
# Re-index
|
||||
notmuch new >/dev/null 2>&1
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Read the message file path from aerc
|
||||
while read -r filepath; do
|
||||
# Get the base mail directory
|
||||
maildir="$HOME/.local/share/mail"
|
||||
|
||||
# Extract the filename
|
||||
filename=$(basename "$filepath")
|
||||
|
||||
# Create Trash/cur if it doesn't exist
|
||||
mkdir -p "$maildir/Trash/cur"
|
||||
|
||||
# Move the file to Trash
|
||||
if [[ -f "$filepath" ]]; then
|
||||
mv "$filepath" "$maildir/Trash/cur/$filename"
|
||||
echo "Moved to Trash: $filename" >&2
|
||||
fi
|
||||
done
|
||||
|
||||
# Re-index with notmuch
|
||||
notmuch new >/dev/null 2>&1
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
MBSYNC=$(pgrep mbsync)
|
||||
NOTMUCH=$(pgrep notmuch)
|
||||
if [ -n "$MBSYNC" -o -n "$NOTMUCH" ]; then
|
||||
echo "Already running one instance of mbsync or notmuch. Exiting..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
maildir="$HOME/.local/share/mail"
|
||||
|
||||
echo "Moving messages tagged as *deleted* to Trash"
|
||||
notmuch search --format=text0 --output=files tag:deleted | while IFS= read -r -d '' filepath; do
|
||||
# Skip if already in Trash
|
||||
case "$filepath" in
|
||||
*/Trash/*)
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
# Move to Trash if file exists
|
||||
if [ -f "$filepath" ]; then
|
||||
filename=$(basename "$filepath")
|
||||
mkdir -p "$maildir/Trash/cur"
|
||||
mv -v "$filepath" "$maildir/Trash/cur/$filename"
|
||||
fi
|
||||
done
|
||||
|
||||
mbsync -Va
|
||||
notmuch new
|
||||
PYTHONWARNINGS="ignore::UserWarning" afew --tag --new
|
||||
|
||||
# Auto-tag and cleanup
|
||||
notmuch tag +sent -- folder:Sent and not tag:sent
|
||||
notmuch tag +trash -- folder:Trash and not tag:trash
|
||||
notmuch tag -deleted -- folder:Trash
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
MBSYNC=$(pgrep mbsync)
|
||||
NOTMUCH=$(pgrep notmuch)
|
||||
|
||||
if [ -n "$MBSYNC" -o -n "$NOTMUCH" ]; then
|
||||
echo "Already running one instance of mbsync or notmuch. Exiting..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Deleting messages tagged as *deleted*"
|
||||
notmuch search --format=text0 --output=files tag:deleted | xargs -0 --no-run-if-empty rm -v
|
||||
|
||||
mbsync -Va
|
||||
notmuch new
|
||||
Executable
Executable
+45
@@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
STATE_FILE="$HOME/.cache/brightness_state"
|
||||
TEMP_FILE="$HOME/.cache/bluelight_state"
|
||||
|
||||
# Get screen brightness level
|
||||
echo "Enter screen brightness level (0-10, where 10 = 100%):"
|
||||
read -r LEVEL
|
||||
|
||||
# Validate input
|
||||
if ! [[ "$LEVEL" =~ ^[0-9]+$ ]] || [ "$LEVEL" -lt 0 ] || [ "$LEVEL" -gt 10 ]; then
|
||||
echo "Invalid input. Please enter a number between 0 and 10."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Convert to decimal (0-10 -> 0.0-1.0)
|
||||
BRIGHTNESS=$(echo "scale=2; $LEVEL / 10" | bc)
|
||||
|
||||
# Ensure at least 0.1 to avoid complete darkness
|
||||
if (($(echo "$BRIGHTNESS < 0.1" | bc -l))); then
|
||||
BRIGHTNESS=0.1
|
||||
fi
|
||||
|
||||
# Ask about blue light filter
|
||||
echo "Apply blue light filter? (y/n):"
|
||||
read -r BLUELIGHT
|
||||
|
||||
if [[ "$BLUELIGHT" == "y" || "$BLUELIGHT" == "Y" ]]; then
|
||||
TEMP=3400
|
||||
FILTER_MSG="with blue light filter"
|
||||
else
|
||||
TEMP=6500
|
||||
FILTER_MSG=""
|
||||
fi
|
||||
|
||||
# Apply settings
|
||||
pkill -9 gammastep
|
||||
gammastep -O $TEMP -b "$BRIGHTNESS" &>/dev/null &
|
||||
|
||||
# Save state
|
||||
echo "$BRIGHTNESS" >"$STATE_FILE"
|
||||
echo "$TEMP" >"$TEMP_FILE"
|
||||
|
||||
echo "Screen brightness set to ${LEVEL}0% $FILTER_MSG"
|
||||
notify-send "Brightness" "${LEVEL}0% $FILTER_MSG" -t 2000
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
STATE_FILE="$HOME/.cache/brightness_state"
|
||||
TEMP_FILE="$HOME/.cache/bluelight_state"
|
||||
|
||||
CURRENT=$(cat "$TEMP_FILE" 2>/dev/null || echo "6500")
|
||||
BRIGHTNESS=$(cat "$STATE_FILE" 2>/dev/null || echo "1.0")
|
||||
|
||||
if [ "$CURRENT" = "6500" ]; then
|
||||
NEW=3400
|
||||
MSG="ON"
|
||||
else
|
||||
NEW=6500
|
||||
MSG="OFF"
|
||||
fi
|
||||
|
||||
pkill -9 gammastep
|
||||
gammastep -O $NEW -b "$BRIGHTNESS" &>/dev/null &
|
||||
|
||||
echo "$NEW" >"$TEMP_FILE"
|
||||
notify-send "Blue Light" "$MSG" -t 1000
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
STATE_FILE="$HOME/.cache/brightness_state"
|
||||
TEMP_FILE="$HOME/.cache/bluelight_state"
|
||||
|
||||
CURRENT=$(cat "$STATE_FILE" 2>/dev/null || echo "1.0")
|
||||
NEW=$(echo "$CURRENT - 0.1" | bc -l)
|
||||
if (($(echo "$NEW < 0.3" | bc -l))); then NEW=0.3; fi
|
||||
|
||||
TEMP=$(cat "$TEMP_FILE" 2>/dev/null || echo "6500")
|
||||
|
||||
pkill -9 gammastep
|
||||
gammastep -O $TEMP -b "$NEW" &>/dev/null &
|
||||
|
||||
echo "$NEW" >"$STATE_FILE"
|
||||
notify-send "Brightness" "$(printf '%.0f%%' $(echo "$NEW * 100" | bc))" -t 1000
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
STATE_FILE="$HOME/.cache/brightness_state"
|
||||
TEMP_FILE="$HOME/.cache/bluelight_state"
|
||||
|
||||
TEMP=$(cat "$TEMP_FILE" 2>/dev/null || echo "6500")
|
||||
|
||||
pkill -9 gammastep
|
||||
gammastep -O $TEMP -b 1.0 &>/dev/null &
|
||||
|
||||
echo "1.0" >"$STATE_FILE"
|
||||
notify-send "Brightness" "100%" -t 1000
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
STATE_FILE="$HOME/.cache/brightness_state"
|
||||
TEMP_FILE="$HOME/.cache/bluelight_state"
|
||||
|
||||
CURRENT=$(cat "$STATE_FILE" 2>/dev/null || echo "1.0")
|
||||
NEW=$(echo "$CURRENT + 0.1" | bc -l)
|
||||
if (($(echo "$NEW > 1.0" | bc -l))); then
|
||||
NEW=1.0
|
||||
notify-send "Brightness" "Maximum (100%)" -t 1000
|
||||
exit 0
|
||||
fi
|
||||
|
||||
TEMP=$(cat "$TEMP_FILE" 2>/dev/null || echo "6500")
|
||||
|
||||
pkill -9 gammastep
|
||||
gammastep -O $TEMP -b "$NEW" &>/dev/null &
|
||||
|
||||
echo "$NEW" >"$STATE_FILE"
|
||||
notify-send "Brightness" "$(printf '%.0f%%' $(echo "$NEW * 100" | bc))" -t 1000
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Removing numbers from filenames and titles (keeping track numbers)..."
|
||||
echo ""
|
||||
|
||||
for file in *.mp3; do
|
||||
filename="${file%.*}"
|
||||
|
||||
# Extract track number before removing it from filename
|
||||
track_num=$(echo "$filename" | grep -oP '^\d+')
|
||||
|
||||
# Remove leading numbers and dot/space from filename
|
||||
new_filename=$(echo "$filename" | sed 's/^[0-9]\+[. ]\+//')
|
||||
new_file="${new_filename}.mp3"
|
||||
|
||||
if [ "$file" != "$new_file" ]; then
|
||||
echo "Processing: $file"
|
||||
echo " New filename: $new_file"
|
||||
echo " New title: $new_filename"
|
||||
echo " Track number: $track_num (kept)"
|
||||
|
||||
# Retag with new title (without number) but keep track number
|
||||
ffmpeg -i "$file" -c copy \
|
||||
-metadata title="$new_filename" \
|
||||
-metadata track="$track_num" \
|
||||
"${new_filename}_temp.mp3" 2>/dev/null
|
||||
|
||||
# Remove original and rename temp file
|
||||
rm "$file"
|
||||
mv "${new_filename}_temp.mp3" "$new_file"
|
||||
|
||||
echo " ✓ Done"
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Complete! All files processed."
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Removing thumbnails and associated CDs from MP3 files..."
|
||||
echo ""
|
||||
|
||||
counter=0
|
||||
|
||||
# Process all mp3 files
|
||||
for file in *.mp3 */*.mp3 */*/*.mp3; do
|
||||
# Skip if file doesn't exist
|
||||
[ -e "$file" ] || continue
|
||||
|
||||
filename=$(basename "$file")
|
||||
|
||||
echo "Processing: $file"
|
||||
|
||||
# Create temp file
|
||||
temp_file="/tmp/strip_${counter}_$$.mp3"
|
||||
|
||||
# Remove all images/artwork and strip video streams
|
||||
ffmpeg -i "$file" \
|
||||
-map 0:a \
|
||||
-c copy \
|
||||
-map_metadata 0 \
|
||||
-id3v2_version 3 \
|
||||
-vn \
|
||||
"$temp_file" -y >/dev/null 2>&1
|
||||
|
||||
if [ -f "$temp_file" ] && [ -s "$temp_file" ]; then
|
||||
# Remove disc number metadata using eyeD3 if available
|
||||
if command -v eyeD3 &> /dev/null; then
|
||||
eyeD3 --remove-images \
|
||||
--disc-num "" \
|
||||
"$temp_file" >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
mv "$temp_file" "$file"
|
||||
echo " ✓ Done"
|
||||
((counter++))
|
||||
else
|
||||
echo " ✗ Failed"
|
||||
[ -f "$temp_file" ] && rm "$temp_file"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Processed $counter files"
|
||||
Executable
+95
@@ -0,0 +1,95 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 1. CONFIGURATION
|
||||
# List folders to exclude (separated by spaces, NOT commas)
|
||||
EXCLUDED_FOLDERS=("ai" "dns-adguard" "dns-pihole" "immich")
|
||||
|
||||
# 2. VALIDATION
|
||||
# Ensure the script is running as root (Sudo) to avoid permission issues
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "=========================================="
|
||||
echo "ERROR: Please run this script as root"
|
||||
echo "Usage: sudo $0"
|
||||
echo "=========================================="
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 3. SETUP ABSOLUTE PATHS
|
||||
# Get the absolute path of the directory where this script is located
|
||||
# This ensures that even if we 'cd' into folders, we don't lose track of where we are.
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
echo "=========================================="
|
||||
echo "Starting Podman Maintenance Script"
|
||||
echo "Target Directory: $SCRIPT_DIR"
|
||||
echo "Excluded Folders: ${EXCLUDED_FOLDERS[*]}"
|
||||
echo "=========================================="
|
||||
|
||||
# 4. MAIN LOOP (Using Globbing instead of 'find' to prevent Subshell issues)
|
||||
# "$SCRIPT_DIR"/*/ iterates through all immediate subdirectories
|
||||
for dir in "$SCRIPT_DIR"/*/; do
|
||||
# Extract just the folder name (e.g., /podman/essential/ -> "essential")
|
||||
folder_name=$(basename "$dir")
|
||||
|
||||
# --- EXCLUSION CHECK ---
|
||||
skip_folder=0
|
||||
for excluded in "${EXCLUDED_FOLDERS[@]}"; do
|
||||
if [[ "$folder_name" == "$excluded" ]]; then
|
||||
# Debug: echo "Skipping $folder_name (Excluded)"
|
||||
skip_folder=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ "$skip_folder" -eq 1 ]; then
|
||||
continue
|
||||
fi
|
||||
# ---------------------
|
||||
|
||||
# Check for compose file (handles both .yml and .yaml)
|
||||
COMPOSE_FILE=""
|
||||
if [ -f "$dir/docker-compose.yml" ]; then
|
||||
COMPOSE_FILE="$dir/docker-compose.yml"
|
||||
elif [ -f "$dir/docker-compose.yaml" ]; then
|
||||
COMPOSE_FILE="$dir/docker-compose.yaml"
|
||||
fi
|
||||
|
||||
# If file exists, proceed with updates
|
||||
if [ -n "$COMPOSE_FILE" ]; then
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "[PROCESSING] Folder: $folder_name"
|
||||
|
||||
# Change directory to the stack
|
||||
# We trap errors in cd to prevent the script from running commands in the wrong place
|
||||
cd "$dir" || {
|
||||
echo "[ERROR] Could not enter $dir"
|
||||
continue
|
||||
}
|
||||
|
||||
echo " -> Step 1: Stopping containers..."
|
||||
podman-compose stop
|
||||
|
||||
echo " -> Step 2: Removing containers and networks (Down)..."
|
||||
podman-compose down
|
||||
|
||||
echo " -> Step 3: Pulling latest images..."
|
||||
podman-compose pull
|
||||
|
||||
echo " -> Step 4: Starting services (Up -d)..."
|
||||
podman-compose up -d
|
||||
|
||||
echo " -> [COMPLETED] $folder_name is updated."
|
||||
|
||||
# Return to the base directory (Safety measure)
|
||||
cd "$SCRIPT_DIR" || exit
|
||||
else
|
||||
# Debug: Uncomment the line below to see which folders are being ignored
|
||||
# echo "[IGNORE] No compose file in: $folder_name"
|
||||
:
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "All tasks successfully completed."
|
||||
echo "=========================================="
|
||||
@@ -9,3 +9,9 @@ sudo chmod -R 777 /mnt/tank/audio
|
||||
|
||||
sudo chown -R 101000:101000 /mnt/flash1/downloads/music
|
||||
sudo chmod -R 755 /mnt/flash1/downloads/music
|
||||
|
||||
sudo chown -R 100033:101000 /mnt/ssd2/cloud_phil /mnt/flash1/podman/lxc_servarr/browser/data/.consume
|
||||
sudo chmod -R 775 /mnt/ssd2/cloud_phil /mnt/flash1/podman/lxc_servarr/browser/data/.consume
|
||||
|
||||
sudo chown -R 101000:101000 /mnt/flash1/podman/lxc_servarr/nextcloud/config/obsidian/vaults
|
||||
sudo chmod -R 755 /mnt/flash1/podman/lxc_servarr/nextcloud/config/obsidian/vaults
|
||||
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
sudo chown -R 101000:100033 /mnt/{hdd1,hdd2,hdd3,hdd4,hdd5,ssd1,ssd2}
|
||||
|
||||
sudo chmod -R 775 /mnt/{hdd1,hdd2,hdd3,hdd4,hdd5,ssd1,ssd2}
|
||||
|
||||
sudo chown -R 101000:101000 /mnt/tank/audio
|
||||
sudo chmod -R 777 /mnt/tank/audio
|
||||
|
||||
sudo chown -R 101000:101000 /mnt/flash1/downloads/music
|
||||
sudo chmod -R 755 /mnt/flash1/downloads/music
|
||||
|
||||
sudo chown -R 101000:100033 /mnt/ssd2/cloud_phil /mnt/flash1/podman/browser/data/.consume
|
||||
sudo chmod -R 775 /mnt/ssd2/cloud_phil /mnt/flash1/podman/browser/data/.consume
|
||||
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Get metadata from first mp3 file if it exists
|
||||
first_file=$(ls *.mp3 2>/dev/null | head -n 1)
|
||||
|
||||
if [ -n "$first_file" ]; then
|
||||
default_artist=$(ffprobe -v quiet -show_entries format_tags=artist -of default=noprint_wrappers=1:nokey=1 "$first_file")
|
||||
default_album=$(ffprobe -v quiet -show_entries format_tags=album -of default=noprint_wrappers=1:nokey=1 "$first_file")
|
||||
default_date=$(ffprobe -v quiet -show_entries format_tags=date -of default=noprint_wrappers=1:nokey=1 "$first_file")
|
||||
default_composer=$(ffprobe -v quiet -show_entries format_tags=composer -of default=noprint_wrappers=1:nokey=1 "$first_file")
|
||||
fi
|
||||
|
||||
# Prompt with defaults
|
||||
read -p "Enter Album Artist [$default_artist]: " album_artist
|
||||
album_artist=${album_artist:-$default_artist}
|
||||
|
||||
read -p "Enter Album [$default_album]: " album
|
||||
album=${album:-$default_album}
|
||||
|
||||
read -p "Enter Release Date (YYYY or YYYY-MM-DD) [$default_date]: " release_date
|
||||
release_date=${release_date:-$default_date}
|
||||
|
||||
read -p "Enter Composer [$default_composer]: " composer
|
||||
composer=${composer:-$default_composer}
|
||||
|
||||
echo ""
|
||||
echo "Retagging files..."
|
||||
echo "Album Artist: $album_artist"
|
||||
echo "Album: $album"
|
||||
echo "Release Date: $release_date"
|
||||
echo "Composer: $composer"
|
||||
echo ""
|
||||
|
||||
for file in *.mp3; do
|
||||
filename="${file%.*}"
|
||||
track_num=$(echo "$filename" | grep -oP '^\d+')
|
||||
|
||||
echo "Retagging: $file (Track $track_num)"
|
||||
|
||||
if [ -n "$composer" ]; then
|
||||
ffmpeg -i "$file" -c copy \
|
||||
-metadata title="$filename" \
|
||||
-metadata track="$track_num" \
|
||||
-metadata album_artist="$album_artist" \
|
||||
-metadata artist="$album_artist" \
|
||||
-metadata album="$album" \
|
||||
-metadata date="$release_date" \
|
||||
-metadata composer="$composer" \
|
||||
-metadata disc="" \
|
||||
-metadata discnumber="" \
|
||||
-metadata totaldiscs="" \
|
||||
-metadata disk="" \
|
||||
-metadata disknumber="" \
|
||||
"${filename}_temp.mp3" 2>/dev/null
|
||||
else
|
||||
ffmpeg -i "$file" -c copy \
|
||||
-metadata title="$filename" \
|
||||
-metadata track="$track_num" \
|
||||
-metadata album_artist="$album_artist" \
|
||||
-metadata artist="$album_artist" \
|
||||
-metadata album="$album" \
|
||||
-metadata date="$release_date" \
|
||||
-metadata composer="" \
|
||||
-metadata disc="" \
|
||||
-metadata discnumber="" \
|
||||
-metadata totaldiscs="" \
|
||||
-metadata disk="" \
|
||||
-metadata disknumber="" \
|
||||
"${filename}_temp.mp3" 2>/dev/null
|
||||
fi
|
||||
|
||||
mv "${filename}_temp.mp3" "$file"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Done! All files retagged."
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
read input
|
||||
|
||||
case "$input" in
|
||||
"liiph@proton.me")
|
||||
cat ~/.config/aerc/sigs/liph.txt
|
||||
;;
|
||||
"liiph@protonmail.com")
|
||||
cat ~/.config/aerc/sigs/liph.txt
|
||||
;;
|
||||
"liiph@pm.me")
|
||||
cat ~/.config/aerc/sigs/liph.txt
|
||||
;;
|
||||
"ph.waibel@proton.me")
|
||||
cat ~/.config/aerc/sigs/formal.txt
|
||||
;;
|
||||
"ph.waibel@pm.me")
|
||||
cat ~/.config/aerc/sigs/phil.txt
|
||||
;;
|
||||
*)
|
||||
# Default signature if no match
|
||||
cat ~/.config/aerc/sigs/default.txt
|
||||
;;
|
||||
esac
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
/usr/bin/python3 /opt/snapraid-runner/snapraid-runner.py -c /opt/snapraid-runner/snapraid-runner.conf
|
||||
STATE=$?
|
||||
|
||||
if [ $STATE -le 2 ]; then
|
||||
# Success or Warning (still successful sync)
|
||||
/usr/bin/curl -fsS "https://uptime.liphlink.xyz/api/push/a73pMB3WnL?status=up&msg=ExitCode_$STATE"
|
||||
else
|
||||
# Hard Failure
|
||||
/usr/bin/curl -fsS "https://uptime.liphlink.xyz/api/push/a73pMB3WnL?status=down&msg=Failed_Code_$STATE"
|
||||
fi
|
||||
Executable
+105
@@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Handle Ctrl+C gracefully
|
||||
trap ctrl_c INT
|
||||
|
||||
function ctrl_c() {
|
||||
echo ""
|
||||
echo "Cancelled by user."
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Function to read input with tab completion for paths
|
||||
read_path() {
|
||||
local prompt="$1"
|
||||
local input
|
||||
|
||||
# Use read with -e flag for readline editing (enables tab completion)
|
||||
read -e -p "$prompt" input
|
||||
echo "$input"
|
||||
}
|
||||
|
||||
# Get source folder
|
||||
SOURCE=$(read_path "Enter source folder path: ")
|
||||
|
||||
# Validate source exists
|
||||
if [ ! -d "$SOURCE" ]; then
|
||||
echo "Error: Source folder '$SOURCE' does not exist!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get destination folders
|
||||
echo "Enter destination folders (one per line, empty line to finish):"
|
||||
echo "(Tip: Use TAB for folder completion, Ctrl+C to cancel)"
|
||||
DESTINATIONS=()
|
||||
while true; do
|
||||
dest=$(read_path "Destination $((${#DESTINATIONS[@]} + 1)): ")
|
||||
if [ -z "$dest" ]; then
|
||||
break
|
||||
fi
|
||||
# Create destination if it doesn't exist
|
||||
if [ ! -d "$dest" ]; then
|
||||
read -p "Destination '$dest' doesn't exist. Create it? (y/n): " create
|
||||
if [ "$create" = "y" ]; then
|
||||
mkdir -p "$dest"
|
||||
else
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
DESTINATIONS+=("$dest")
|
||||
done
|
||||
|
||||
# Validate we have destinations
|
||||
if [ ${#DESTINATIONS[@]} -eq 0 ]; then
|
||||
echo "Error: No destination folders provided!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Display summary
|
||||
echo ""
|
||||
echo "=== Summary ==="
|
||||
echo "Source: $SOURCE"
|
||||
echo "Destinations:"
|
||||
for i in "${!DESTINATIONS[@]}"; do
|
||||
echo " $((i + 1)). ${DESTINATIONS[$i]}"
|
||||
done
|
||||
|
||||
# Get list of items in source
|
||||
items=("$SOURCE"/*)
|
||||
total=${#items[@]}
|
||||
items_per_dest=$((total / ${#DESTINATIONS[@]}))
|
||||
|
||||
echo ""
|
||||
echo "Total items to split: $total"
|
||||
echo "Items per destination: ~$items_per_dest"
|
||||
echo ""
|
||||
|
||||
read -p "Proceed with copy? (y/n): " confirm
|
||||
if [ "$confirm" != "y" ]; then
|
||||
echo "Cancelled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Distribute items
|
||||
echo ""
|
||||
echo "Starting distribution..."
|
||||
for i in "${!DESTINATIONS[@]}"; do
|
||||
start=$((i * items_per_dest))
|
||||
if [ $i -eq $((${#DESTINATIONS[@]} - 1)) ]; then
|
||||
# Last destination gets remainder
|
||||
end=$total
|
||||
else
|
||||
end=$(((i + 1) * items_per_dest))
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Copying to ${DESTINATIONS[$i]} (items $((start + 1)) to $end)..."
|
||||
for ((j=start; j<end; j++)); do
|
||||
item_name=$(basename "${items[$j]}")
|
||||
echo " -> $item_name"
|
||||
rsync -a "${items[$j]}" "${DESTINATIONS[$i]}/"
|
||||
done
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Distribution complete!"
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "=== Syncing all mailboxes ==="
|
||||
|
||||
# 1. Sync emails bidirectionally (includes deletions)
|
||||
mbsync -a
|
||||
|
||||
# 2. Index each account separately (runs post-new hook)
|
||||
for account in phil spam; do
|
||||
echo "Indexing $account..."
|
||||
NOTMUCH_CONFIG=~/Mail/$account/.notmuch-config notmuch new
|
||||
done
|
||||
|
||||
# 3. Optional: Sync back any tag changes to IMAP flags
|
||||
for account in phil spam; do
|
||||
NOTMUCH_CONFIG=~/Mail/$account/.notmuch-config notmuch tag --batch < /dev/null
|
||||
done
|
||||
|
||||
echo "=== Sync complete ==="
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Sync mail from ProtonMail Bridge (suppress CLOSE error)
|
||||
echo "Syncing mail from ProtonMail..."
|
||||
mbsync -a 2>&1 | grep -v "CLOSE"
|
||||
|
||||
# Index new mail (this automatically runs post-new hook)
|
||||
echo "Indexing new messages..."
|
||||
notmuch new
|
||||
|
||||
# Move all deleted messages to Trash folder
|
||||
echo "Cleaning up deleted messages..."
|
||||
DELETED_COUNT=0
|
||||
notmuch search --output=files tag:deleted 2>/dev/null | while read filepath; do
|
||||
if [ -f "$filepath" ]; then
|
||||
TRASH_DIR="$HOME/.local/share/mail/Trash/cur"
|
||||
mkdir -p "$TRASH_DIR"
|
||||
|
||||
FILENAME=$(basename "$filepath")
|
||||
mv "$filepath" "$TRASH_DIR/$FILENAME"
|
||||
((DELETED_COUNT++))
|
||||
fi
|
||||
done
|
||||
|
||||
# Update notmuch after moving files
|
||||
if [ $DELETED_COUNT -gt 0 ]; then
|
||||
echo "Moved $DELETED_COUNT message(s) to Trash"
|
||||
notmuch new --no-hooks >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
# Sync moved messages back to ProtonMail
|
||||
echo "Syncing changes to ProtonMail..."
|
||||
mbsync -a 2>&1 | grep -v "CLOSE" >/dev/null
|
||||
|
||||
# Notify if new mail
|
||||
NEW=$(notmuch count tag:unread)
|
||||
if [ $NEW -gt 0 ]; then
|
||||
notify-send "📬 Mail" "$NEW unread message(s)"
|
||||
fi
|
||||
|
||||
echo "Sync complete: $(date)"
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Sync with server (this pushes local changes including deletions)
|
||||
mbsync -a
|
||||
|
||||
# Re-index
|
||||
notmuch new
|
||||
|
||||
# Auto-tag folders
|
||||
notmuch tag +sent -- folder:Sent and not tag:sent
|
||||
notmuch tag +draft -- folder:Drafts and not tag:draft
|
||||
notmuch tag +trash -- folder:Trash and not tag:trash
|
||||
notmuch tag +spam -- folder:Spam and not tag:spam
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
THEME="${1:-catppuccin-mocha}"
|
||||
CONFIG_DIR="$HOME/.config"
|
||||
# WAYBAR_DIR="$CONFIG_DIR/niri/waybar-niri"
|
||||
|
||||
declare -A THEMES=(
|
||||
["cat"]="catppuccin-mocha"
|
||||
["rose"]="rose-pine-moon"
|
||||
["dracula"]="dracula"
|
||||
)
|
||||
|
||||
if [[ ! -v "THEMES[$THEME]" ]]; then
|
||||
echo "Unknown theme: $THEME"
|
||||
echo "Available themes: ${!THEMES[@]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Switching to theme: $THEME"
|
||||
|
||||
# Neovim
|
||||
echo "vim.cmd.colorscheme('${THEMES[$THEME]}')" >"$CONFIG_DIR/nvim/lua/current_theme.lua"
|
||||
echo " ✓ Neovim"
|
||||
|
||||
# Kitty
|
||||
if command -v kitty &>/dev/null && [[ -f "$CONFIG_DIR/kitty/themes/${THEME}.conf" ]]; then
|
||||
ln -sf "$CONFIG_DIR/kitty/themes/${THEME}.conf" "$CONFIG_DIR/kitty/current-theme.conf"
|
||||
kill -SIGUSR1 $(pgrep kitty) 2>/dev/null || true
|
||||
echo " ✓ Kitty"
|
||||
fi
|
||||
|
||||
# Btop
|
||||
if [[ -f "$CONFIG_DIR/btop/themes/${THEME}.theme" ]]; then
|
||||
sed -i "s|^color_theme = .*|color_theme = \"$CONFIG_DIR/btop/themes/${THEME}.theme\"|" "$CONFIG_DIR/btop/btop.conf"
|
||||
echo " ✓ Btop"
|
||||
fi
|
||||
|
||||
# Yazi
|
||||
if [[ -f "$CONFIG_DIR/yazi/themes/${THEME}.toml" ]]; then
|
||||
ln -sf "$CONFIG_DIR/yazi/themes/${THEME}.toml" "$CONFIG_DIR/yazi/theme.toml"
|
||||
echo " ✓ Yazi"
|
||||
fi
|
||||
|
||||
# # Waybar - simply copy the theme file to theme.css
|
||||
# if [[ -f "$WAYBAR_DIR/themes/${THEME}.css" ]]; then
|
||||
# cp "$WAYBAR_DIR/themes/${THEME}.css" "$WAYBAR_DIR/theme.css"
|
||||
#
|
||||
# pkill waybar 2>/dev/null || true
|
||||
# sleep 0.5
|
||||
# waybar -c "$WAYBAR_DIR/config.jsonc" -s "$WAYBAR_DIR/style.css" &
|
||||
# echo " ✓ Waybar"
|
||||
# else
|
||||
# echo " ✗ Waybar: theme file not found at $WAYBAR_DIR/themes/${THEME}.css"
|
||||
# fi
|
||||
|
||||
# Bat
|
||||
if command -v bat &>/dev/null; then
|
||||
case $THEME in
|
||||
catppuccin-mocha) BAT_THEME="Catppuccin Mocha" ;;
|
||||
rose-pine-moon) BAT_THEME="TwoDark" ;;
|
||||
*) BAT_THEME="Monokai Extended" ;;
|
||||
esac
|
||||
|
||||
if [[ -f "$CONFIG_DIR/bat/config" ]]; then
|
||||
sed -i "s/^--theme=.*/--theme=\"${BAT_THEME}\"/" "$CONFIG_DIR/bat/config"
|
||||
else
|
||||
mkdir -p "$CONFIG_DIR/bat"
|
||||
echo "--theme=\"${BAT_THEME}\"" >"$CONFIG_DIR/bat/config"
|
||||
fi
|
||||
echo " ✓ Bat"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✓ Theme switched to: $THEME"
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Ask for the thumbnail filename
|
||||
echo "=== Album Art Embedder (Recursive) ==="
|
||||
echo "Current directory: $(pwd)"
|
||||
read -p "Enter thumbnail filename in this directory (e.g., cover.jpg): " thumbnail
|
||||
|
||||
# Full path to thumbnail
|
||||
thumbnail_path="$(pwd)/$thumbnail"
|
||||
|
||||
# Check if thumbnail exists
|
||||
if [ ! -f "$thumbnail_path" ]; then
|
||||
echo "Error: Thumbnail not found at $thumbnail_path"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ask for album artist
|
||||
read -p "Enter album artist name: " album_artist
|
||||
|
||||
# Get album name from current directory
|
||||
album_name="$(basename "$(pwd)")"
|
||||
|
||||
echo ""
|
||||
echo "Found thumbnail: $thumbnail_path"
|
||||
echo "Album: $album_name"
|
||||
echo "Album Artist: $album_artist"
|
||||
echo "Processing all mp3/mp4 files in subdirectories..."
|
||||
echo ""
|
||||
|
||||
# Counter for processed files
|
||||
count=0
|
||||
|
||||
# Find all mp3 and mp4 files in subdirectories (not current dir)
|
||||
find . -mindepth 2 -type f \( -name "*.mp3" -o -name "*.mp4" \) | while read -r file; do
|
||||
echo "Processing: $file"
|
||||
|
||||
# Get file extension
|
||||
ext="${file##*.}"
|
||||
|
||||
# Create temporary filename
|
||||
temp_file="${file}.tmp.${ext}"
|
||||
|
||||
# Add thumbnail and metadata using ffmpeg
|
||||
if [ "$ext" = "mp3" ]; then
|
||||
ffmpeg -i "$file" -i "$thumbnail_path" \
|
||||
-map 0 -map 1 \
|
||||
-c copy \
|
||||
-metadata album_artist="$album_artist" \
|
||||
-metadata album="$album_name" \
|
||||
-disposition:v:0 attached_pic \
|
||||
"$temp_file" 2>/dev/null
|
||||
else
|
||||
# For mp4 files
|
||||
ffmpeg -i "$file" -i "$thumbnail_path" \
|
||||
-map 0 -map 1 \
|
||||
-c copy \
|
||||
-metadata artist="$album_artist" \
|
||||
-metadata album="$album_name" \
|
||||
-disposition:v:0 attached_pic \
|
||||
"$temp_file" 2>/dev/null
|
||||
fi
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
mv "$temp_file" "$file"
|
||||
((count++))
|
||||
echo "✓ Done"
|
||||
else
|
||||
echo "✗ Failed"
|
||||
[ -f "$temp_file" ] && rm "$temp_file"
|
||||
fi
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "Finished! Processed $count files."
|
||||
echo "Album Artist set to: $album_artist"
|
||||
echo "Album set to: $album_name"
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
cd ~/mcp/tidal-mcp/
|
||||
|
||||
uv venv --clear
|
||||
source .venv/bin/activate
|
||||
|
||||
uv pip install --editable .
|
||||
|
||||
cd ~/mcp/tidal-mcp/tidal_api/
|
||||
uv pip install flask tidalapi
|
||||
|
||||
nohup python app.py > tidal.log 2>&1 &
|
||||
@@ -0,0 +1,2 @@
|
||||
nohup: ignoring input
|
||||
/usr/bin/python: can't open file '/home/liph/dotfiles/scripts/scripts/app.py': [Errno 2] No such file or directory
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Save this file as ~/scripts/tmux-sessionizer
|
||||
# Make it executable with: chmod +x ~/.local/bin/tmux-sessionizer
|
||||
|
||||
if [[ $# -eq 1 ]]; then
|
||||
selected=$1
|
||||
else
|
||||
selected=$(fd -H . ~/dotfiles ~/Desktop/main-cs ~/Desktop/main-cs/Projects ~/ ~/Desktop/work ~/Desktop/work/youtube -t d -d 1 | fzf)
|
||||
fi
|
||||
|
||||
if [[ -z $selected ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
selected_name=$(basename "$selected" | tr . _)
|
||||
tmux_running=$(pgrep tmux)
|
||||
|
||||
if [[ -z $TMUX ]] && [[ -z $tmux_running ]]; then
|
||||
tmux new-session -s $selected_name -c $selected
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! tmux has-session -t=$selected_name 2> /dev/null; then
|
||||
tmux new-session -ds $selected_name -c $selected
|
||||
fi
|
||||
|
||||
tmux switch-client -t $selected_name
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Save the piped message to temp file
|
||||
TEMP_MSG=$(mktemp)
|
||||
cat > "$TEMP_MSG"
|
||||
|
||||
# Extract Message-ID more robustly
|
||||
MESSAGE_ID=$(grep -i "^Message-ID:" "$TEMP_MSG" | head -1 | sed 's/^[Mm]essage-[Ii][Dd]: *//; s/^<//; s/>$//' | tr -d '\r\n ')
|
||||
|
||||
# Cleanup temp file
|
||||
rm "$TEMP_MSG"
|
||||
|
||||
if [ -z "$MESSAGE_ID" ]; then
|
||||
notify-send "Error" "Could not find Message-ID"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get file path from notmuch
|
||||
FILEPATH=$(notmuch search --output=files "id:$MESSAGE_ID" 2>/dev/null | head -1)
|
||||
|
||||
if [ -z "$FILEPATH" ] || [ ! -f "$FILEPATH" ]; then
|
||||
# Try alternative search
|
||||
FILEPATH=$(notmuch search --output=files --exclude=false "*" 2>/dev/null | xargs grep -l "Message-ID.*$MESSAGE_ID" 2>/dev/null | head -1)
|
||||
fi
|
||||
|
||||
if [ -z "$FILEPATH" ] || [ ! -f "$FILEPATH" ]; then
|
||||
notify-send "Error" "File not found for Message-ID: $MESSAGE_ID"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Move to Trash folder
|
||||
TRASH_DIR="$HOME/.local/share/mail/Trash/cur"
|
||||
mkdir -p "$TRASH_DIR"
|
||||
|
||||
FILENAME=$(basename "$FILEPATH")
|
||||
mv "$FILEPATH" "$TRASH_DIR/$FILENAME"
|
||||
|
||||
# Update notmuch database
|
||||
notmuch new --no-hooks >/dev/null 2>&1
|
||||
|
||||
# Tag as deleted
|
||||
notmuch tag +deleted +trash -inbox -unread -- "id:$MESSAGE_ID" >/dev/null 2>&1
|
||||
|
||||
# Trigger sync in background
|
||||
(sleep 2 && mbsync -a 2>&1 | grep -v CLOSE >/dev/null) &
|
||||
|
||||
notify-send "📧 Aerc" "Moved to Trash"
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
# ~/scripts/yazi-picker.sh
|
||||
|
||||
# Launch Yazi and capture the selected file
|
||||
selected_file=$(yazi --chooser-file)
|
||||
|
||||
# If a file was selected, print it (or pass it to another application)
|
||||
if [ -n "$selected_file" ]; then
|
||||
echo "$selected_file" | xclip -selection clipboard # Copy to clipboard (optional)
|
||||
echo "Selected file: $selected_file"
|
||||
fi
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
# ~/scripts/yazi-picker.sh
|
||||
|
||||
# Launch Yazi and capture the selected file
|
||||
selected_file=$(yazi --chooser-file)
|
||||
|
||||
# If a file was selected, print it (or pass it to another application)
|
||||
if [ -n "$selected_file" ]; then
|
||||
echo "$selected_file" | xclip -selection clipboard # Copy to clipboard (optional)
|
||||
echo "Selected file: $selected_file"
|
||||
fi
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script to find every single file and opens in neovim
|
||||
# alias set as nzo in .zshrc
|
||||
search_with_zoxdie() {
|
||||
if [ -z "$1" ]; then
|
||||
# use fd with fzf to select & open a file when no arg are provided
|
||||
file="$(fd --type f -I -H -E .git -E .git-crypt -E .cache -E .backup | fzf --height=70% --preview='bat -n --color=always --line-range :500 {}')"
|
||||
if [ -n "$file" ]; then
|
||||
nvim "$file"
|
||||
fi
|
||||
else
|
||||
# Handle when an arg is provided
|
||||
lines=$(zoxide query -l | xargs -I {} fd --type f -I -H -E .git -E .git-crypt -E .cache -E .backup -E .vscode "$1" {} | fzf --no-sort) # Initial filter attempt with fzf
|
||||
line_count="$(echo "$lines" | wc -l | xargs)" # Trim any leading spaces
|
||||
|
||||
if [ -n "$lines" ] && [ "$line_count" -eq 1 ]; then
|
||||
# looks for the exact ones and opens it
|
||||
file="$lines"
|
||||
nvim "$file"
|
||||
elif [ -n "$lines" ]; then
|
||||
# If multiple files are found, allow further selection using fzf and bat for preview
|
||||
file=$(echo "$lines" | fzf --query="$1" --height=70% --preview='bat -n --color=always --line-range :500 {}')
|
||||
if [ -n "$file" ]; then
|
||||
nvim "$file"
|
||||
fi
|
||||
else
|
||||
echo "No matches found." >&2
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
search_with_zoxdie "$@"
|
||||
Reference in New Issue
Block a user