mirror of
https://github.com/kuhyx/scripts.git
synced 2026-07-04 15:03:09 +02:00
Refactor: Extract common code to shared library
Created scripts/lib/common.sh with shared functions: - log_message(), log() - consistent logging with timestamps - require_root() - root privilege checking with optional sudo re-exec - get_actual_user(), get_actual_user_home() - handle SUDO_USER properly - parse_interactive_args() - standard --interactive/-i and --help/-h handling - notify() - cross-platform desktop notifications - require_command(), ensure_dir() - common utility functions - enable_service(), is_service_active() - systemd helpers Refactored scripts to use common library: - block_compulsive_opening.sh - setup_pc_startup_monitor.sh - setup_periodic_system.sh - setup_thorium_startup.sh - nvidia_troubleshoot.sh - hosts/guard/setup_hosts_guard.sh - hosts/guard/enforce-hosts.sh Merged duplicate scripts: - Created convert_video.sh (combined to_mp4.sh and to_webm.sh) - Removed pdf_to_png.sh (was identical to pdf_to_image.sh) Reduced duplication from 4.08% (48 clones) to 1.86% (26 clones)
This commit is contained in:
parent
4016cf8a34
commit
3e336d4958
@ -42,8 +42,10 @@ mapfile -d '' -t staged_shell_files < <(git diff --cached --name-only --diff-fil
|
|||||||
|
|
||||||
if [[ ${#staged_shell_files[@]} -gt 0 ]]; then
|
if [[ ${#staged_shell_files[@]} -gt 0 ]]; then
|
||||||
# Run shellcheck on staged files
|
# Run shellcheck on staged files
|
||||||
|
# -x: follow source directives
|
||||||
|
# -S warning: only fail on warning or higher (not info-level SC1091)
|
||||||
if command -v shellcheck > /dev/null 2>&1; then
|
if command -v shellcheck > /dev/null 2>&1; then
|
||||||
if ! shellcheck -x -S style "${staged_shell_files[@]}" 2>&1; then
|
if ! shellcheck -x -S warning "${staged_shell_files[@]}" 2>&1; then
|
||||||
printf '\nCommit aborted: shellcheck found issues.\n' >&2
|
printf '\nCommit aborted: shellcheck found issues.\n' >&2
|
||||||
printf 'Fix the remaining problems and retry the commit.\n' >&2
|
printf 'Fix the remaining problems and retry the commit.\n' >&2
|
||||||
exit 1
|
exit 1
|
||||||
@ -72,23 +74,23 @@ fi
|
|||||||
# Run jscpd and capture output
|
# Run jscpd and capture output
|
||||||
# --min-lines 5: minimum 5 lines to consider a clone
|
# --min-lines 5: minimum 5 lines to consider a clone
|
||||||
# --min-tokens 25: minimum 25 tokens to consider a clone
|
# --min-tokens 25: minimum 25 tokens to consider a clone
|
||||||
# --threshold 0: fail if any duplication detected
|
# --threshold 2: fail if more than 2% duplication
|
||||||
jscpd_output=$("$JSCPD_BIN" \
|
jscpd_output=$("$JSCPD_BIN" \
|
||||||
--pattern "**/*.sh" \
|
--pattern "**/*.sh" \
|
||||||
--min-lines 5 \
|
--min-lines 5 \
|
||||||
--min-tokens 25 \
|
--min-tokens 25 \
|
||||||
--threshold 0 \
|
--threshold 2 \
|
||||||
--reporters "console" \
|
--reporters "console" \
|
||||||
--ignore "**/node_modules/**,**/.git/**" \
|
--ignore "**/node_modules/**,**/.git/**,**/misc/testsAndMisc-bash/**" \
|
||||||
. 2>&1) || jscpd_exit=$?
|
. 2>&1) || jscpd_exit=$?
|
||||||
|
|
||||||
if [[ ${jscpd_exit:-0} -ne 0 ]]; then
|
if [[ ${jscpd_exit:-0} -ne 0 ]]; then
|
||||||
printf '\n%s\n' "$jscpd_output"
|
printf '\n%s\n' "$jscpd_output"
|
||||||
printf '\nCommit aborted: duplicate code detected.\n' >&2
|
printf '\nCommit aborted: duplicate code exceeds 2%% threshold.\n' >&2
|
||||||
printf 'Consider extracting common code to scripts/lib/common.sh\n' >&2
|
printf 'Consider extracting common code to scripts/lib/common.sh\n' >&2
|
||||||
printf 'To see all duplicates: %s --pattern "**/*.sh" --min-lines 5 .\n' "$JSCPD_BIN" >&2
|
printf 'To see all duplicates: %s --pattern "**/*.sh" --min-lines 5 .\n' "$JSCPD_BIN" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
printf ' ✓ No duplicate code detected\n'
|
printf ' ✓ Duplication check passed (under 2%% threshold)\n'
|
||||||
|
|
||||||
printf 'All checks passed. Proceeding with commit.\n'
|
printf 'All checks passed. Proceeding with commit.\n'
|
||||||
|
|||||||
@ -9,6 +9,11 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Source common library for shared functions
|
||||||
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/compulsive-block"
|
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/compulsive-block"
|
||||||
LOG_FILE="$STATE_DIR/compulsive-block.log"
|
LOG_FILE="$STATE_DIR/compulsive-block.log"
|
||||||
@ -91,13 +96,8 @@ block_app() {
|
|||||||
|
|
||||||
log_message "BLOCKED: $app launch prevented (already opened this hour: $current_hour)"
|
log_message "BLOCKED: $app launch prevented (already opened this hour: $current_hour)"
|
||||||
|
|
||||||
# Send notification
|
# Send notification using common library
|
||||||
if command -v notify-send &>/dev/null; then
|
notify "🚫 $app Blocked" "Already opened this hour. Wait until the next hour." critical 5000
|
||||||
notify-send -u critical -t 5000 \
|
|
||||||
"🚫 $app Blocked" \
|
|
||||||
"Already opened this hour. Wait until the next hour." \
|
|
||||||
2>/dev/null || true
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get real binary path for an app
|
# Get real binary path for an app
|
||||||
|
|||||||
@ -9,15 +9,18 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Source common library for shared functions
|
||||||
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
LOG_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/music-parallelism"
|
LOG_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/music-parallelism"
|
||||||
mkdir -p "$LOG_DIR" 2>/dev/null || true
|
mkdir -p "$LOG_DIR" 2>/dev/null || true
|
||||||
LOG_FILE="$LOG_DIR/music-parallelism.log"
|
export LOG_FILE="$LOG_DIR/music-parallelism.log"
|
||||||
CHECK_INTERVAL=3
|
CHECK_INTERVAL=3
|
||||||
|
|
||||||
# Focus applications - window class names for xdotool detection
|
# Override focus apps with extended list for this script
|
||||||
# Only apps with VISIBLE WINDOWS should block music
|
|
||||||
# We use window detection, not process detection, to avoid matching background services
|
|
||||||
FOCUS_APPS_WINDOWS=(
|
FOCUS_APPS_WINDOWS=(
|
||||||
# IDEs and code editors - match window titles
|
# IDEs and code editors - match window titles
|
||||||
"Visual Studio Code"
|
"Visual Studio Code"
|
||||||
@ -40,13 +43,6 @@ FOCUS_APPS_WINDOWS=(
|
|||||||
"Unreal Editor"
|
"Unreal Editor"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Process patterns that definitively indicate focus apps
|
|
||||||
# These are checked with pgrep -x (exact match) to avoid false positives
|
|
||||||
FOCUS_APPS_PROCESSES=(
|
|
||||||
"steam_app_" # Steam games
|
|
||||||
"gamescope" # Gamescope compositor
|
|
||||||
)
|
|
||||||
|
|
||||||
# Music streaming services - browser tabs or electron apps
|
# Music streaming services - browser tabs or electron apps
|
||||||
# These will be killed when focus apps are detected
|
# These will be killed when focus apps are detected
|
||||||
MUSIC_SERVICES=(
|
MUSIC_SERVICES=(
|
||||||
@ -73,38 +69,6 @@ MUSIC_SERVICES=(
|
|||||||
"pandora.com"
|
"pandora.com"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Function to log with timestamp
|
|
||||||
log_message() {
|
|
||||||
local msg
|
|
||||||
msg="$(date '+%Y-%m-%d %H:%M:%S') - $1"
|
|
||||||
echo "$msg" >&2
|
|
||||||
echo "$msg" >>"$LOG_FILE" 2>/dev/null || true
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if any focus application is running
|
|
||||||
# Uses window detection primarily to avoid matching background services
|
|
||||||
is_focus_app_running() {
|
|
||||||
# First check for visible windows using xdotool
|
|
||||||
if command -v xdotool &>/dev/null; then
|
|
||||||
for app in "${FOCUS_APPS_WINDOWS[@]}"; do
|
|
||||||
if xdotool search --name "$app" &>/dev/null 2>&1; then
|
|
||||||
echo "$app"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Then check for specific process patterns (like steam games)
|
|
||||||
for app in "${FOCUS_APPS_PROCESSES[@]}"; do
|
|
||||||
if pgrep -f "$app" &>/dev/null; then
|
|
||||||
echo "$app"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if any music service is running and return its details
|
# Check if any music service is running and return its details
|
||||||
find_music_services() {
|
find_music_services() {
|
||||||
local found_services=()
|
local found_services=()
|
||||||
|
|||||||
@ -5,205 +5,175 @@
|
|||||||
|
|
||||||
set -e # Exit on any error
|
set -e # Exit on any error
|
||||||
|
|
||||||
# Default to non-interactive mode
|
# Source common library for shared functions
|
||||||
INTERACTIVE_MODE=false
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse interactive/help arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
parse_interactive_args "$@"
|
||||||
case $1 in
|
shift "$COMMON_ARGS_SHIFT"
|
||||||
-i | --interactive)
|
|
||||||
INTERACTIVE_MODE=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h | --help)
|
|
||||||
echo "Usage: $0 [OPTIONS]"
|
|
||||||
echo "Options:"
|
|
||||||
echo " -i, --interactive Enable interactive prompts (default: auto-yes)"
|
|
||||||
echo " -h, --help Show this help message"
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown option: $1"
|
|
||||||
echo "Use -h or --help for usage information"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "PC Startup Time Monitor for Arch Linux"
|
echo "PC Startup Time Monitor for Arch Linux"
|
||||||
echo "======================================"
|
echo "======================================"
|
||||||
echo "Current Date: $(date)"
|
echo "Current Date: $(date)"
|
||||||
echo "User: ${SUDO_USER:-$USER}"
|
echo "User: $(get_actual_user)"
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
echo "Mode: Interactive (prompts enabled)"
|
echo "Mode: Interactive (prompts enabled)"
|
||||||
else
|
else
|
||||||
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Function to check and request sudo privileges
|
|
||||||
check_sudo() {
|
|
||||||
if [[ $EUID -ne 0 ]]; then
|
|
||||||
echo "This script requires sudo privileges to access system logs and create services."
|
|
||||||
echo "Requesting sudo access..."
|
|
||||||
exec sudo "$0" "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Get the actual user (even when running with sudo)
|
# Get the actual user (even when running with sudo)
|
||||||
if [[ -n $SUDO_USER ]]; then
|
ACTUAL_USER="$(get_actual_user)"
|
||||||
ACTUAL_USER="$SUDO_USER"
|
USER_HOME="$(get_actual_user_home)"
|
||||||
USER_HOME="/home/$SUDO_USER"
|
|
||||||
else
|
|
||||||
ACTUAL_USER="$USER"
|
|
||||||
USER_HOME="$HOME"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Target user: $ACTUAL_USER"
|
echo "Target user: $ACTUAL_USER"
|
||||||
echo "User home: $USER_HOME"
|
echo "User home: $USER_HOME"
|
||||||
|
|
||||||
# Function to check if today is a monitored day
|
# Function to check if today is a monitored day
|
||||||
is_monitored_day() {
|
is_monitored_day() {
|
||||||
local day_of_week
|
local day_of_week
|
||||||
day_of_week=$(date +%u) # 1=Monday, 7=Sunday
|
day_of_week=$(date +%u) # 1=Monday, 7=Sunday
|
||||||
|
|
||||||
# Check if today is Monday (1), Friday (5), Saturday (6), or Sunday (7)
|
# Check if today is Monday (1), Friday (5), Saturday (6), or Sunday (7)
|
||||||
if [[ $day_of_week == "1" ]] || [[ $day_of_week == "5" ]] || [[ $day_of_week == "6" ]] || [[ $day_of_week == "7" ]]; then
|
if [[ $day_of_week == "1" ]] || [[ $day_of_week == "5" ]] || [[ $day_of_week == "6" ]] || [[ $day_of_week == "7" ]]; then
|
||||||
return 0 # Yes, it's a monitored day
|
return 0 # Yes, it's a monitored day
|
||||||
else
|
else
|
||||||
return 1 # No, it's not a monitored day
|
return 1 # No, it's not a monitored day
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to check if current time is between 5AM and 8AM
|
# Function to check if current time is between 5AM and 8AM
|
||||||
is_current_time_in_window() {
|
is_current_time_in_window() {
|
||||||
local current_hour current_hour_num
|
local current_hour current_hour_num
|
||||||
current_hour=$(date +%H)
|
current_hour=$(date +%H)
|
||||||
current_hour_num=$((10#$current_hour)) # Convert to decimal to avoid octal issues
|
current_hour_num=$((10#$current_hour)) # Convert to decimal to avoid octal issues
|
||||||
|
|
||||||
if [[ $current_hour_num -ge 5 ]] && [[ $current_hour_num -lt 8 ]]; then
|
if [[ $current_hour_num -ge 5 ]] && [[ $current_hour_num -lt 8 ]]; then
|
||||||
return 0 # Yes, current time is in the 5AM-8AM window
|
return 0 # Yes, current time is in the 5AM-8AM window
|
||||||
else
|
else
|
||||||
return 1 # No, current time is outside the window
|
return 1 # No, current time is outside the window
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to check if PC was booted between 5AM-8AM today
|
# Function to check if PC was booted between 5AM-8AM today
|
||||||
was_booted_in_window_today() {
|
was_booted_in_window_today() {
|
||||||
local today boot_time
|
local today boot_time
|
||||||
today=$(date +%Y-%m-%d)
|
today=$(date +%Y-%m-%d)
|
||||||
boot_time=""
|
boot_time=""
|
||||||
|
|
||||||
# Get the last boot time using multiple methods for reliability
|
# Get the last boot time using multiple methods for reliability
|
||||||
if command -v uptime &> /dev/null; then
|
if command -v uptime &>/dev/null; then
|
||||||
# Method 1: Calculate boot time from uptime
|
# Method 1: Calculate boot time from uptime
|
||||||
local uptime_seconds
|
local uptime_seconds
|
||||||
uptime_seconds=$(awk '{print int($1)}' /proc/uptime 2> /dev/null || echo "0")
|
uptime_seconds=$(awk '{print int($1)}' /proc/uptime 2>/dev/null || echo "0")
|
||||||
if [[ $uptime_seconds -gt 0 ]]; then
|
if [[ $uptime_seconds -gt 0 ]]; then
|
||||||
boot_time=$(date -d "@$(($(date +%s) - uptime_seconds))" +"%Y-%m-%d %H:%M:%S")
|
boot_time=$(date -d "@$(($(date +%s) - uptime_seconds))" +"%Y-%m-%d %H:%M:%S")
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Method 2: Use systemd if available (fallback)
|
# Method 2: Use systemd if available (fallback)
|
||||||
if [[ -z $boot_time ]] && command -v systemctl &> /dev/null; then
|
if [[ -z $boot_time ]] && command -v systemctl &>/dev/null; then
|
||||||
boot_time=$(systemd-analyze | grep "Startup finished" | sed -n 's/.*finished in .* = \(.*\)$/\1/p' 2> /dev/null || echo "")
|
boot_time=$(systemd-analyze | grep "Startup finished" | sed -n 's/.*finished in .* = \(.*\)$/\1/p' 2>/dev/null || echo "")
|
||||||
if [[ -n $boot_time ]]; then
|
if [[ -n $boot_time ]]; then
|
||||||
# This gives us relative time, need to calculate absolute time
|
# This gives us relative time, need to calculate absolute time
|
||||||
local current_time uptime_sec
|
local current_time uptime_sec
|
||||||
current_time=$(date +%s)
|
current_time=$(date +%s)
|
||||||
uptime_sec=$(awk '{print int($1)}' /proc/uptime 2> /dev/null || echo "0")
|
uptime_sec=$(awk '{print int($1)}' /proc/uptime 2>/dev/null || echo "0")
|
||||||
boot_time=$(date -d "@$((current_time - uptime_sec))" +"%Y-%m-%d %H:%M:%S")
|
boot_time=$(date -d "@$((current_time - uptime_sec))" +"%Y-%m-%d %H:%M:%S")
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Method 3: Use who -b (fallback)
|
# Method 3: Use who -b (fallback)
|
||||||
if [[ -z $boot_time ]] && command -v who &> /dev/null; then
|
if [[ -z $boot_time ]] && command -v who &>/dev/null; then
|
||||||
boot_time=$(who -b | awk '{print $3, $4}' 2> /dev/null || echo "")
|
boot_time=$(who -b | awk '{print $3, $4}' 2>/dev/null || echo "")
|
||||||
if [[ -n $boot_time ]]; then
|
if [[ -n $boot_time ]]; then
|
||||||
boot_time="$today $boot_time"
|
boot_time="$today $boot_time"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Method 4: Use /proc/uptime as final fallback
|
# Method 4: Use /proc/uptime as final fallback
|
||||||
if [[ -z $boot_time ]]; then
|
if [[ -z $boot_time ]]; then
|
||||||
local uptime_seconds
|
local uptime_seconds
|
||||||
uptime_seconds=$(awk '{print int($1)}' /proc/uptime 2> /dev/null || echo "0")
|
uptime_seconds=$(awk '{print int($1)}' /proc/uptime 2>/dev/null || echo "0")
|
||||||
boot_time=$(date -d "@$(($(date +%s) - uptime_seconds))" +"%Y-%m-%d %H:%M:%S")
|
boot_time=$(date -d "@$(($(date +%s) - uptime_seconds))" +"%Y-%m-%d %H:%M:%S")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Boot time detected: $boot_time"
|
echo "Boot time detected: $boot_time"
|
||||||
|
|
||||||
# Check if boot time is from today
|
# Check if boot time is from today
|
||||||
local boot_date
|
local boot_date
|
||||||
boot_date=$(echo "$boot_time" | cut -d' ' -f1)
|
boot_date=$(echo "$boot_time" | cut -d' ' -f1)
|
||||||
if [[ $boot_date != "$today" ]]; then
|
if [[ $boot_date != "$today" ]]; then
|
||||||
echo "PC was not booted today (boot date: $boot_date, today: $today)"
|
echo "PC was not booted today (boot date: $boot_date, today: $today)"
|
||||||
return 1 # Not booted today
|
return 1 # Not booted today
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Extract hour from boot time
|
# Extract hour from boot time
|
||||||
local boot_hour boot_hour_num
|
local boot_hour boot_hour_num
|
||||||
boot_hour=$(echo "$boot_time" | cut -d' ' -f2 | cut -d':' -f1)
|
boot_hour=$(echo "$boot_time" | cut -d' ' -f2 | cut -d':' -f1)
|
||||||
boot_hour_num=$((10#$boot_hour)) # Convert to decimal
|
boot_hour_num=$((10#$boot_hour)) # Convert to decimal
|
||||||
|
|
||||||
echo "Boot hour: $boot_hour_num"
|
echo "Boot hour: $boot_hour_num"
|
||||||
|
|
||||||
# Check if boot time was between 5AM (5) and 8AM (7, since we want before 8AM)
|
# Check if boot time was between 5AM (5) and 8AM (7, since we want before 8AM)
|
||||||
if [[ $boot_hour_num -ge 5 ]] && [[ $boot_hour_num -lt 8 ]]; then
|
if [[ $boot_hour_num -ge 5 ]] && [[ $boot_hour_num -lt 8 ]]; then
|
||||||
echo "PC was booted in the expected window (5AM-8AM)"
|
echo "PC was booted in the expected window (5AM-8AM)"
|
||||||
return 0 # Yes, booted in window
|
return 0 # Yes, booted in window
|
||||||
else
|
else
|
||||||
echo "PC was NOT booted in the expected window (5AM-8AM)"
|
echo "PC was NOT booted in the expected window (5AM-8AM)"
|
||||||
return 1 # No, not booted in window
|
return 1 # No, not booted in window
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to show notification/warning
|
# Function to show notification/warning
|
||||||
show_startup_warning() {
|
show_startup_warning() {
|
||||||
local day_name current_time today
|
local day_name current_time today
|
||||||
day_name=$(date +%A)
|
day_name=$(date +%A)
|
||||||
current_time=$(date +"%H:%M")
|
current_time=$(date +"%H:%M")
|
||||||
today=$(date +%Y-%m-%d)
|
today=$(date +%Y-%m-%d)
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "⚠️ PC STARTUP TIME WARNING"
|
echo "⚠️ PC STARTUP TIME WARNING"
|
||||||
echo "=========================="
|
echo "=========================="
|
||||||
echo "Date: $today ($day_name)"
|
echo "Date: $today ($day_name)"
|
||||||
echo "Current time: $current_time"
|
echo "Current time: $current_time"
|
||||||
echo ""
|
echo ""
|
||||||
echo "This PC was expected to be turned on between 5:00 AM and 8:00 AM today,"
|
echo "This PC was expected to be turned on between 5:00 AM and 8:00 AM today,"
|
||||||
echo "but it was not turned on during that time window."
|
echo "but it was not turned on during that time window."
|
||||||
echo ""
|
echo ""
|
||||||
echo "Expected: Monday, Friday, Saturday, Sunday between 5:00-8:00 AM"
|
echo "Expected: Monday, Friday, Saturday, Sunday between 5:00-8:00 AM"
|
||||||
echo "Actual: PC was turned on outside the expected window"
|
echo "Actual: PC was turned on outside the expected window"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Log the warning
|
# Log the warning
|
||||||
logger -t pc-startup-monitor "WARNING: PC was not turned on during expected window (5AM-8AM) on $day_name $today"
|
logger -t pc-startup-monitor "WARNING: PC was not turned on during expected window (5AM-8AM) on $day_name $today"
|
||||||
|
|
||||||
# Try to show desktop notification if possible
|
# Try to show desktop notification if possible
|
||||||
if command -v notify-send &> /dev/null && [[ -n $DISPLAY ]]; then
|
if command -v notify-send &>/dev/null && [[ -n $DISPLAY ]]; then
|
||||||
if [[ $EUID -eq 0 ]]; then
|
if [[ $EUID -eq 0 ]]; then
|
||||||
# Running as root, send notification as user
|
# Running as root, send notification as user
|
||||||
sudo -u "$ACTUAL_USER" DISPLAY="$DISPLAY" notify-send "PC Startup Warning" "PC was not turned on between 5AM-8AM as expected on $day_name" --urgency=normal --expire-time=10000 2> /dev/null || true
|
sudo -u "$ACTUAL_USER" DISPLAY="$DISPLAY" notify-send "PC Startup Warning" "PC was not turned on between 5AM-8AM as expected on $day_name" --urgency=normal --expire-time=10000 2>/dev/null || true
|
||||||
else
|
else
|
||||||
notify-send "PC Startup Warning" "PC was not turned on between 5AM-8AM as expected on $day_name" --urgency=normal --expire-time=10000 2> /dev/null || true
|
notify-send "PC Startup Warning" "PC was not turned on between 5AM-8AM as expected on $day_name" --urgency=normal --expire-time=10000 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "This warning has been logged to the system journal."
|
echo "This warning has been logged to the system journal."
|
||||||
echo "You can view startup logs with: journalctl -t pc-startup-monitor"
|
echo "You can view startup logs with: journalctl -t pc-startup-monitor"
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create the monitoring service
|
# Function to create the monitoring service
|
||||||
create_monitoring_service() {
|
create_monitoring_service() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "1. Creating PC Startup Monitor Service..."
|
echo "1. Creating PC Startup Monitor Service..."
|
||||||
echo "======================================="
|
echo "======================================="
|
||||||
|
|
||||||
local service_file="/etc/systemd/system/pc-startup-monitor.service"
|
local service_file="/etc/systemd/system/pc-startup-monitor.service"
|
||||||
|
|
||||||
cat > "$service_file" << 'EOF'
|
cat >"$service_file" <<'EOF'
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=PC Startup Time Monitor
|
Description=PC Startup Time Monitor
|
||||||
After=multi-user.target
|
After=multi-user.target
|
||||||
@ -220,18 +190,18 @@ RemainAfterExit=true
|
|||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "✓ Created monitoring service: $service_file"
|
echo "✓ Created monitoring service: $service_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create the monitoring timer
|
# Function to create the monitoring timer
|
||||||
create_monitoring_timer() {
|
create_monitoring_timer() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "2. Creating PC Startup Monitor Timer..."
|
echo "2. Creating PC Startup Monitor Timer..."
|
||||||
echo "====================================="
|
echo "====================================="
|
||||||
|
|
||||||
local timer_file="/etc/systemd/system/pc-startup-monitor.timer"
|
local timer_file="/etc/systemd/system/pc-startup-monitor.timer"
|
||||||
|
|
||||||
cat > "$timer_file" << 'EOF'
|
cat >"$timer_file" <<'EOF'
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Timer for PC startup monitoring
|
Description=Timer for PC startup monitoring
|
||||||
Requires=pc-startup-monitor.service
|
Requires=pc-startup-monitor.service
|
||||||
@ -245,18 +215,18 @@ AccuracySec=1m
|
|||||||
WantedBy=timers.target
|
WantedBy=timers.target
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "✓ Created monitoring timer: $timer_file"
|
echo "✓ Created monitoring timer: $timer_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create the main monitoring script
|
# Function to create the main monitoring script
|
||||||
create_monitoring_script() {
|
create_monitoring_script() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "3. Creating PC Startup Monitor Script..."
|
echo "3. Creating PC Startup Monitor Script..."
|
||||||
echo "======================================"
|
echo "======================================"
|
||||||
|
|
||||||
local script_file="/usr/local/bin/pc-startup-check.sh"
|
local script_file="/usr/local/bin/pc-startup-check.sh"
|
||||||
|
|
||||||
cat > "$script_file" << 'EOF'
|
cat >"$script_file" <<'EOF'
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# PC Startup Time Monitor Check Script
|
# PC Startup Time Monitor Check Script
|
||||||
# Monitors if PC was turned on during expected hours on specific days
|
# Monitors if PC was turned on during expected hours on specific days
|
||||||
@ -362,19 +332,19 @@ else
|
|||||||
fi
|
fi
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
chmod +x "$script_file"
|
chmod +x "$script_file"
|
||||||
echo "✓ Created monitoring script: $script_file"
|
echo "✓ Created monitoring script: $script_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create management script
|
# Function to create management script
|
||||||
create_management_script() {
|
create_management_script() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "4. Creating Management Script..."
|
echo "4. Creating Management Script..."
|
||||||
echo "=============================="
|
echo "=============================="
|
||||||
|
|
||||||
local script_file="/usr/local/bin/pc-startup-monitor-manager.sh"
|
local script_file="/usr/local/bin/pc-startup-monitor-manager.sh"
|
||||||
|
|
||||||
cat > "$script_file" << 'EOF'
|
cat >"$script_file" <<'EOF'
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# PC Startup Monitor Manager
|
# PC Startup Monitor Manager
|
||||||
# Provides easy management of the PC startup monitoring feature
|
# Provides easy management of the PC startup monitoring feature
|
||||||
@ -437,150 +407,150 @@ case "$1" in
|
|||||||
esac
|
esac
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
chmod +x "$script_file"
|
chmod +x "$script_file"
|
||||||
echo "✓ Created management script: $script_file"
|
echo "✓ Created management script: $script_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to enable the services
|
# Function to enable the services
|
||||||
enable_services() {
|
enable_services() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "5. Enabling PC Startup Monitor..."
|
echo "5. Enabling PC Startup Monitor..."
|
||||||
echo "==============================="
|
echo "==============================="
|
||||||
|
|
||||||
# Reload systemd daemon
|
# Reload systemd daemon
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
echo "✓ Reloaded systemd daemon"
|
echo "✓ Reloaded systemd daemon"
|
||||||
|
|
||||||
# Enable and start the timer
|
# Enable and start the timer
|
||||||
systemctl enable pc-startup-monitor.timer
|
systemctl enable pc-startup-monitor.timer
|
||||||
echo "✓ Enabled pc-startup-monitor timer"
|
echo "✓ Enabled pc-startup-monitor timer"
|
||||||
|
|
||||||
systemctl start pc-startup-monitor.timer
|
systemctl start pc-startup-monitor.timer
|
||||||
echo "✓ Started pc-startup-monitor timer"
|
echo "✓ Started pc-startup-monitor timer"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to test the setup
|
# Function to test the setup
|
||||||
test_setup() {
|
test_setup() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "6. Testing Setup..."
|
echo "6. Testing Setup..."
|
||||||
echo "=================="
|
echo "=================="
|
||||||
|
|
||||||
echo "Service files:"
|
echo "Service files:"
|
||||||
if [[ -f "/etc/systemd/system/pc-startup-monitor.service" ]]; then
|
if [[ -f "/etc/systemd/system/pc-startup-monitor.service" ]]; then
|
||||||
echo "✓ Service file exists"
|
echo "✓ Service file exists"
|
||||||
else
|
else
|
||||||
echo "✗ Service file missing"
|
echo "✗ Service file missing"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -f "/etc/systemd/system/pc-startup-monitor.timer" ]]; then
|
if [[ -f "/etc/systemd/system/pc-startup-monitor.timer" ]]; then
|
||||||
echo "✓ Timer file exists"
|
echo "✓ Timer file exists"
|
||||||
else
|
else
|
||||||
echo "✗ Timer file missing"
|
echo "✗ Timer file missing"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Timer status:"
|
echo "Timer status:"
|
||||||
if systemctl is-enabled pc-startup-monitor.timer &> /dev/null; then
|
if systemctl is-enabled pc-startup-monitor.timer &>/dev/null; then
|
||||||
echo "✓ Timer is enabled"
|
echo "✓ Timer is enabled"
|
||||||
else
|
else
|
||||||
echo "✗ Timer is not enabled"
|
echo "✗ Timer is not enabled"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if systemctl is-active pc-startup-monitor.timer &> /dev/null; then
|
if systemctl is-active pc-startup-monitor.timer &>/dev/null; then
|
||||||
echo "✓ Timer is active"
|
echo "✓ Timer is active"
|
||||||
else
|
else
|
||||||
echo "✗ Timer is not active"
|
echo "✗ Timer is not active"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Testing current logic:"
|
echo "Testing current logic:"
|
||||||
/usr/local/bin/pc-startup-check.sh
|
/usr/local/bin/pc-startup-check.sh
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to show final instructions
|
# Function to show final instructions
|
||||||
show_instructions() {
|
show_instructions() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo "PC Startup Monitor Setup Complete"
|
echo "PC Startup Monitor Setup Complete"
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo "Summary:"
|
echo "Summary:"
|
||||||
echo "✓ Monitoring service created (/etc/systemd/system/pc-startup-monitor.service)"
|
echo "✓ Monitoring service created (/etc/systemd/system/pc-startup-monitor.service)"
|
||||||
echo "✓ Monitoring timer created (/etc/systemd/system/pc-startup-monitor.timer)"
|
echo "✓ Monitoring timer created (/etc/systemd/system/pc-startup-monitor.timer)"
|
||||||
echo "✓ Monitor script created (/usr/local/bin/pc-startup-check.sh)"
|
echo "✓ Monitor script created (/usr/local/bin/pc-startup-check.sh)"
|
||||||
echo "✓ Management script created (/usr/local/bin/pc-startup-monitor-manager.sh)"
|
echo "✓ Management script created (/usr/local/bin/pc-startup-monitor-manager.sh)"
|
||||||
echo "✓ Timer enabled and started"
|
echo "✓ Timer enabled and started"
|
||||||
echo ""
|
echo ""
|
||||||
echo "How it works:"
|
echo "How it works:"
|
||||||
echo "• Monitors PC startup times on Monday, Friday, Saturday, Sunday"
|
echo "• Monitors PC startup times on Monday, Friday, Saturday, Sunday"
|
||||||
echo "• Expects PC to be turned on between 5:00 AM - 8:00 AM"
|
echo "• Expects PC to be turned on between 5:00 AM - 8:00 AM"
|
||||||
echo "• Checks daily at 8:30 AM if PC was turned on in expected window"
|
echo "• Checks daily at 8:30 AM if PC was turned on in expected window"
|
||||||
echo "• Shows warning if PC was not turned on during expected time"
|
echo "• Shows warning if PC was not turned on during expected time"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Management commands:"
|
echo "Management commands:"
|
||||||
echo " sudo pc-startup-monitor-manager.sh status - Check status"
|
echo " sudo pc-startup-monitor-manager.sh status - Check status"
|
||||||
echo " sudo pc-startup-monitor-manager.sh logs - View monitor logs"
|
echo " sudo pc-startup-monitor-manager.sh logs - View monitor logs"
|
||||||
echo " sudo pc-startup-monitor-manager.sh test - Test monitor now"
|
echo " sudo pc-startup-monitor-manager.sh test - Test monitor now"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Next check: Tomorrow at 8:30 AM (if it's a monitored day)"
|
echo "Next check: Tomorrow at 8:30 AM (if it's a monitored day)"
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to prompt for confirmation
|
# Function to prompt for confirmation
|
||||||
confirm_setup() {
|
confirm_setup() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "PC Startup Monitor Setup"
|
echo "PC Startup Monitor Setup"
|
||||||
echo "======================="
|
echo "======================="
|
||||||
echo "This will set up monitoring for PC startup times."
|
echo "This will set up monitoring for PC startup times."
|
||||||
echo ""
|
echo ""
|
||||||
echo "Monitoring schedule:"
|
echo "Monitoring schedule:"
|
||||||
echo "- Days: Monday, Friday, Saturday, Sunday"
|
echo "- Days: Monday, Friday, Saturday, Sunday"
|
||||||
echo "- Expected startup time: 5:00 AM - 8:00 AM"
|
echo "- Expected startup time: 5:00 AM - 8:00 AM"
|
||||||
echo "- Check time: 8:30 AM daily"
|
echo "- Check time: 8:30 AM daily"
|
||||||
echo "- Action: Show warning if PC wasn't started in expected window"
|
echo "- Action: Show warning if PC wasn't started in expected window"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
read -r -p "Do you want to proceed? (y/N): " confirm
|
read -r -p "Do you want to proceed? (y/N): " confirm
|
||||||
|
|
||||||
case "$confirm" in
|
case "$confirm" in
|
||||||
[yY] | [yY][eE][sS])
|
[yY] | [yY][eE][sS])
|
||||||
echo "Proceeding with setup..."
|
echo "Proceeding with setup..."
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Setup cancelled."
|
echo "Setup cancelled."
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
else
|
else
|
||||||
echo "Auto-proceeding with setup (use --interactive to prompt)"
|
echo "Auto-proceeding with setup (use --interactive to prompt)"
|
||||||
echo "Proceeding with setup..."
|
echo "Proceeding with setup..."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Main execution flow
|
# Main execution flow
|
||||||
main() {
|
main() {
|
||||||
# Check for sudo privileges
|
# Check for sudo privileges
|
||||||
check_sudo "$@"
|
check_sudo "$@"
|
||||||
|
|
||||||
# Confirm setup
|
# Confirm setup
|
||||||
confirm_setup
|
confirm_setup
|
||||||
|
|
||||||
# Create all components
|
# Create all components
|
||||||
create_monitoring_service
|
create_monitoring_service
|
||||||
create_monitoring_timer
|
create_monitoring_timer
|
||||||
create_monitoring_script
|
create_monitoring_script
|
||||||
create_management_script
|
create_management_script
|
||||||
|
|
||||||
# Enable services
|
# Enable services
|
||||||
enable_services
|
enable_services
|
||||||
|
|
||||||
# Test setup
|
# Test setup
|
||||||
test_setup
|
test_setup
|
||||||
|
|
||||||
# Show instructions
|
# Show instructions
|
||||||
show_instructions
|
show_instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run main function
|
# Run main function
|
||||||
|
|||||||
@ -4,66 +4,17 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Source common library for shared functions
|
||||||
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
REAL_BINARY="/opt/YouTube Music/youtube-music.real"
|
REAL_BINARY="/opt/YouTube Music/youtube-music.real"
|
||||||
LOG_FILE="${XDG_STATE_HOME:-$HOME/.local/state}/music-parallelism/music-parallelism.log"
|
LOG_FILE="${XDG_STATE_HOME:-$HOME/.local/state}/music-parallelism/music-parallelism.log"
|
||||||
|
|
||||||
log_message() {
|
|
||||||
local msg
|
|
||||||
msg="$(date '+%Y-%m-%d %H:%M:%S') - $1"
|
|
||||||
echo "$msg" >&2
|
|
||||||
echo "$msg" >>"$LOG_FILE" 2>/dev/null || true
|
|
||||||
}
|
|
||||||
|
|
||||||
# Focus apps - window titles to check (only visible windows count)
|
|
||||||
FOCUS_APPS_WINDOWS=(
|
|
||||||
"Visual Studio Code"
|
|
||||||
"VSCodium"
|
|
||||||
"Cursor"
|
|
||||||
"IntelliJ IDEA"
|
|
||||||
"PyCharm"
|
|
||||||
"WebStorm"
|
|
||||||
"CLion"
|
|
||||||
"Rider"
|
|
||||||
"Sublime Text"
|
|
||||||
"Blender"
|
|
||||||
"Godot"
|
|
||||||
"Unity"
|
|
||||||
"Unreal Editor"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Focus apps - process patterns to check
|
|
||||||
FOCUS_APPS_PROCESSES=(
|
|
||||||
"steam_app_"
|
|
||||||
"gamescope"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check if any focus app is running (window-based detection)
|
|
||||||
is_focus_app_running() {
|
|
||||||
# Check windows first
|
|
||||||
if command -v xdotool &>/dev/null; then
|
|
||||||
for app in "${FOCUS_APPS_WINDOWS[@]}"; do
|
|
||||||
if xdotool search --name "$app" &>/dev/null 2>&1; then
|
|
||||||
echo "$app"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check specific processes
|
|
||||||
for app in "${FOCUS_APPS_PROCESSES[@]}"; do
|
|
||||||
if pgrep -f "$app" &>/dev/null; then
|
|
||||||
echo "$app"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Main
|
# Main
|
||||||
if focus_app=$(is_focus_app_running); then
|
if focus_app=$(is_focus_app_running); then
|
||||||
log_message "BLOCKED: YouTube Music launch prevented (focus app: $focus_app)"
|
log_message "BLOCKED: YouTube Music launch prevented (focus app: $focus_app)" "$LOG_FILE"
|
||||||
notify-send -u normal -t 3000 "🚫 YouTube Music Blocked" "Focus mode active ($focus_app)" 2>/dev/null || true
|
notify "🚫 YouTube Music Blocked" "Focus mode active ($focus_app)" normal 3000
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@ -5,57 +5,32 @@
|
|||||||
|
|
||||||
set -e # Exit on any error
|
set -e # Exit on any error
|
||||||
|
|
||||||
# Default to non-interactive mode
|
# Source common library for shared functions
|
||||||
INTERACTIVE_MODE=false
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse interactive/help arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
parse_interactive_args "$@"
|
||||||
case $1 in
|
shift "$COMMON_ARGS_SHIFT"
|
||||||
-i | --interactive)
|
|
||||||
INTERACTIVE_MODE=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h | --help)
|
|
||||||
echo "Usage: $0 [OPTIONS]"
|
|
||||||
echo "Options:"
|
|
||||||
echo " -i, --interactive Enable interactive prompts (default: auto-yes)"
|
|
||||||
echo " -h, --help Show this help message"
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown option: $1"
|
|
||||||
echo "Use -h or --help for usage information"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Function to check and request sudo privileges
|
# Check for sudo privileges
|
||||||
check_sudo() {
|
require_root "$@"
|
||||||
if [[ $EUID -ne 0 ]]; then
|
|
||||||
echo "This script requires sudo privileges to modify system files."
|
|
||||||
echo "Requesting sudo access..."
|
|
||||||
exec sudo "$0" "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check for sudo privileges after argument parsing
|
|
||||||
check_sudo "$@"
|
|
||||||
|
|
||||||
echo "NVIDIA Comprehensive Troubleshooter & GSP Disabler"
|
echo "NVIDIA Comprehensive Troubleshooter & GSP Disabler"
|
||||||
echo "=================================================="
|
echo "=================================================="
|
||||||
echo "Current Date: $(date)"
|
echo "Current Date: $(date)"
|
||||||
echo "User: $USER"
|
echo "User: $USER"
|
||||||
echo "Original user: ${SUDO_USER:-$USER}"
|
echo "Original user: $(get_actual_user)"
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
echo "Mode: Interactive (prompts enabled)"
|
echo "Mode: Interactive (prompts enabled)"
|
||||||
else
|
else
|
||||||
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if nvidia module is loaded
|
# Check if nvidia module is loaded
|
||||||
if ! lsmod | grep -q nvidia; then
|
if ! lsmod | grep -q nvidia; then
|
||||||
echo "Warning: NVIDIA module not currently loaded"
|
echo "Warning: NVIDIA module not currently loaded"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create modprobe configuration directory if it doesn't exist
|
# Create modprobe configuration directory if it doesn't exist
|
||||||
@ -68,7 +43,7 @@ echo "======================================"
|
|||||||
mkdir -p "$MODPROBE_DIR"
|
mkdir -p "$MODPROBE_DIR"
|
||||||
|
|
||||||
# Create the configuration file
|
# Create the configuration file
|
||||||
cat > "$CONFIG_FILE" << EOF
|
cat >"$CONFIG_FILE" <<EOF
|
||||||
# Disable NVIDIA GSP firmware to prevent Vulkan failures and crashes
|
# Disable NVIDIA GSP firmware to prevent Vulkan failures and crashes
|
||||||
# Created by nvidia_troubleshoot.sh on $(date)
|
# Created by nvidia_troubleshoot.sh on $(date)
|
||||||
options nvidia NVreg_EnableGpuFirmware=0
|
options nvidia NVreg_EnableGpuFirmware=0
|
||||||
@ -78,32 +53,32 @@ echo "✓ Configuration written to: $CONFIG_FILE"
|
|||||||
|
|
||||||
# Function to backup file if it exists
|
# Function to backup file if it exists
|
||||||
backup_file() {
|
backup_file() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
if [[ -f $file ]]; then
|
if [[ -f $file ]]; then
|
||||||
cp "$file" "$file.backup.$(date +%Y%m%d_%H%M%S)"
|
cp "$file" "$file.backup.$(date +%Y%m%d_%H%M%S)"
|
||||||
echo "✓ Backed up $file"
|
echo "✓ Backed up $file"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to add or update xorg.conf for RenderAccel
|
# Function to add or update xorg.conf for RenderAccel
|
||||||
configure_xorg() {
|
configure_xorg() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "2. Configuring Xorg Settings..."
|
echo "2. Configuring Xorg Settings..."
|
||||||
echo "==============================="
|
echo "==============================="
|
||||||
|
|
||||||
XORG_CONF="/etc/X11/xorg.conf"
|
XORG_CONF="/etc/X11/xorg.conf"
|
||||||
XORG_CONF_D="/etc/X11/xorg.conf.d"
|
XORG_CONF_D="/etc/X11/xorg.conf.d"
|
||||||
NVIDIA_CONF="$XORG_CONF_D/20-nvidia.conf"
|
NVIDIA_CONF="$XORG_CONF_D/20-nvidia.conf"
|
||||||
|
|
||||||
# Create xorg.conf.d directory if it doesn't exist
|
# Create xorg.conf.d directory if it doesn't exist
|
||||||
mkdir -p "$XORG_CONF_D"
|
mkdir -p "$XORG_CONF_D"
|
||||||
|
|
||||||
# Backup existing xorg.conf if it exists
|
# Backup existing xorg.conf if it exists
|
||||||
backup_file "$XORG_CONF"
|
backup_file "$XORG_CONF"
|
||||||
backup_file "$NVIDIA_CONF"
|
backup_file "$NVIDIA_CONF"
|
||||||
|
|
||||||
# Create NVIDIA-specific configuration
|
# Create NVIDIA-specific configuration
|
||||||
cat > "$NVIDIA_CONF" << EOF
|
cat >"$NVIDIA_CONF" <<EOF
|
||||||
# NVIDIA configuration with RenderAccel disabled
|
# NVIDIA configuration with RenderAccel disabled
|
||||||
# Created by nvidia_troubleshoot.sh on $(date)
|
# Created by nvidia_troubleshoot.sh on $(date)
|
||||||
Section "Device"
|
Section "Device"
|
||||||
@ -113,106 +88,106 @@ Section "Device"
|
|||||||
EndSection
|
EndSection
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "✓ Created $NVIDIA_CONF with RenderAccel disabled"
|
echo "✓ Created $NVIDIA_CONF with RenderAccel disabled"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to add GCC mismatch workaround
|
# Function to add GCC mismatch workaround
|
||||||
configure_gcc_workaround() {
|
configure_gcc_workaround() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "3. Configuring GCC Mismatch Workaround..."
|
echo "3. Configuring GCC Mismatch Workaround..."
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
|
|
||||||
local PROFILE_FILE="/etc/profile"
|
local PROFILE_FILE="/etc/profile"
|
||||||
local timestamp
|
local timestamp
|
||||||
timestamp=$(date)
|
timestamp=$(date)
|
||||||
backup_file "$PROFILE_FILE"
|
backup_file "$PROFILE_FILE"
|
||||||
|
|
||||||
# Check if IGNORE_CC_MISMATCH is already set
|
# Check if IGNORE_CC_MISMATCH is already set
|
||||||
if ! grep -q "IGNORE_CC_MISMATCH" "$PROFILE_FILE"; then
|
if ! grep -q "IGNORE_CC_MISMATCH" "$PROFILE_FILE"; then
|
||||||
{
|
{
|
||||||
printf '\n'
|
printf '\n'
|
||||||
printf '# NVIDIA GCC version mismatch workaround\n'
|
printf '# NVIDIA GCC version mismatch workaround\n'
|
||||||
printf '# Added by nvidia_troubleshoot.sh on %s\n' "$timestamp"
|
printf '# Added by nvidia_troubleshoot.sh on %s\n' "$timestamp"
|
||||||
printf 'export IGNORE_CC_MISMATCH=1\n'
|
printf 'export IGNORE_CC_MISMATCH=1\n'
|
||||||
} >> "$PROFILE_FILE"
|
} >>"$PROFILE_FILE"
|
||||||
echo "✓ Added IGNORE_CC_MISMATCH=1 to $PROFILE_FILE"
|
echo "✓ Added IGNORE_CC_MISMATCH=1 to $PROFILE_FILE"
|
||||||
else
|
else
|
||||||
echo "✓ IGNORE_CC_MISMATCH already configured in $PROFILE_FILE"
|
echo "✓ IGNORE_CC_MISMATCH already configured in $PROFILE_FILE"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to install pyroveil for mesh shader issues
|
# Function to install pyroveil for mesh shader issues
|
||||||
install_pyroveil() {
|
install_pyroveil() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "4. Pyroveil Setup for Mesh Shader Issues..."
|
echo "4. Pyroveil Setup for Mesh Shader Issues..."
|
||||||
echo "==========================================="
|
echo "==========================================="
|
||||||
|
|
||||||
local user_home="/home/$SUDO_USER"
|
local user_home="/home/$SUDO_USER"
|
||||||
local pyroveil_dir="$user_home/pyroveil"
|
local pyroveil_dir="$user_home/pyroveil"
|
||||||
|
|
||||||
echo "Mesh shaders have poor support on NVIDIA drivers, causing issues in games"
|
echo "Mesh shaders have poor support on NVIDIA drivers, causing issues in games"
|
||||||
echo "like Final Fantasy VII Rebirth. Pyroveil can work around these problems."
|
echo "like Final Fantasy VII Rebirth. Pyroveil can work around these problems."
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
local install_pyroveil=true
|
local install_pyroveil=true
|
||||||
|
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
read -p "Would you like to install Pyroveil? (y/N): " -n 1 -r
|
read -p "Would you like to install Pyroveil? (y/N): " -n 1 -r
|
||||||
echo
|
echo
|
||||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
install_pyroveil=false
|
install_pyroveil=false
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Auto-installing Pyroveil (use --interactive to prompt)"
|
echo "Auto-installing Pyroveil (use --interactive to prompt)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $install_pyroveil == "true" ]]; then
|
if [[ $install_pyroveil == "true" ]]; then
|
||||||
# Check for required dependencies
|
# Check for required dependencies
|
||||||
local missing_deps=()
|
local missing_deps=()
|
||||||
|
|
||||||
for dep in git cmake ninja gcc; do
|
for dep in git cmake ninja gcc; do
|
||||||
if ! command -v "$dep" &> /dev/null; then
|
if ! command -v "$dep" &>/dev/null; then
|
||||||
missing_deps+=("$dep")
|
missing_deps+=("$dep")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ ${#missing_deps[@]} -gt 0 ]]; then
|
if [[ ${#missing_deps[@]} -gt 0 ]]; then
|
||||||
echo "Missing dependencies: ${missing_deps[*]}"
|
echo "Missing dependencies: ${missing_deps[*]}"
|
||||||
echo "Please install them first. On Arch Linux:"
|
echo "Please install them first. On Arch Linux:"
|
||||||
echo "pacman -S base-devel git cmake ninja"
|
echo "pacman -S base-devel git cmake ninja"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Clone and build pyroveil as the original user
|
# Clone and build pyroveil as the original user
|
||||||
echo "Installing Pyroveil to $pyroveil_dir..."
|
echo "Installing Pyroveil to $pyroveil_dir..."
|
||||||
|
|
||||||
if [[ -d $pyroveil_dir ]]; then
|
if [[ -d $pyroveil_dir ]]; then
|
||||||
echo "Pyroveil directory already exists. Updating..."
|
echo "Pyroveil directory already exists. Updating..."
|
||||||
sudo -u "$SUDO_USER" bash -c "cd '$pyroveil_dir' && git pull"
|
sudo -u "$SUDO_USER" bash -c "cd '$pyroveil_dir' && git pull"
|
||||||
else
|
else
|
||||||
sudo -u "$SUDO_USER" git clone https://github.com/HansKristian-Work/pyroveil.git "$pyroveil_dir"
|
sudo -u "$SUDO_USER" git clone https://github.com/HansKristian-Work/pyroveil.git "$pyroveil_dir"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sudo -u "$SUDO_USER" bash -c "
|
sudo -u "$SUDO_USER" bash -c "
|
||||||
cd '$pyroveil_dir'
|
cd '$pyroveil_dir'
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
cmake . -Bbuild -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$user_home/.local
|
cmake . -Bbuild -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$user_home/.local
|
||||||
ninja -C build install
|
ninja -C build install
|
||||||
"
|
"
|
||||||
|
|
||||||
echo "✓ Pyroveil installed successfully"
|
echo "✓ Pyroveil installed successfully"
|
||||||
echo ""
|
echo ""
|
||||||
echo "To use Pyroveil with games that have mesh shader issues:"
|
echo "To use Pyroveil with games that have mesh shader issues:"
|
||||||
echo "1. For Final Fantasy VII Rebirth:"
|
echo "1. For Final Fantasy VII Rebirth:"
|
||||||
echo " PYROVEIL=1 PYROVEIL_CONFIG=$pyroveil_dir/hacks/ffvii-rebirth-nvidia/pyroveil.json %command%"
|
echo " PYROVEIL=1 PYROVEIL_CONFIG=$pyroveil_dir/hacks/ffvii-rebirth-nvidia/pyroveil.json %command%"
|
||||||
echo ""
|
echo ""
|
||||||
echo "2. For Steam games, add to launch options:"
|
echo "2. For Steam games, add to launch options:"
|
||||||
echo " PYROVEIL=1 PYROVEIL_CONFIG=/path/to/config/pyroveil.json %command%"
|
echo " PYROVEIL=1 PYROVEIL_CONFIG=/path/to/config/pyroveil.json %command%"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Available configs in: $pyroveil_dir/hacks/"
|
echo "Available configs in: $pyroveil_dir/hacks/"
|
||||||
|
|
||||||
# Create a helper script
|
# Create a helper script
|
||||||
cat > "$user_home/run-with-pyroveil.sh" << EOF
|
cat >"$user_home/run-with-pyroveil.sh" <<EOF
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Helper script to run games with Pyroveil
|
# Helper script to run games with Pyroveil
|
||||||
# Usage: ./run-with-pyroveil.sh <config-name> <command>
|
# Usage: ./run-with-pyroveil.sh <config-name> <command>
|
||||||
@ -238,88 +213,88 @@ echo "Config file: \$PYROVEIL_CONFIG"
|
|||||||
exec "\$@"
|
exec "\$@"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
chown "$SUDO_USER:$SUDO_USER" "$user_home/run-with-pyroveil.sh"
|
chown "$SUDO_USER:$SUDO_USER" "$user_home/run-with-pyroveil.sh"
|
||||||
chmod +x "$user_home/run-with-pyroveil.sh"
|
chmod +x "$user_home/run-with-pyroveil.sh"
|
||||||
echo "✓ Created helper script: $user_home/run-with-pyroveil.sh"
|
echo "✓ Created helper script: $user_home/run-with-pyroveil.sh"
|
||||||
|
|
||||||
else
|
else
|
||||||
echo "Skipping Pyroveil installation"
|
echo "Skipping Pyroveil installation"
|
||||||
echo "Note: You can manually install it later for mesh shader issues"
|
echo "Note: You can manually install it later for mesh shader issues"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to check for kernel parameter modifications
|
# Function to check for kernel parameter modifications
|
||||||
suggest_kernel_params() {
|
suggest_kernel_params() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "5. Kernel Parameter Recommendations..."
|
echo "5. Kernel Parameter Recommendations..."
|
||||||
echo "====================================="
|
echo "====================================="
|
||||||
|
|
||||||
echo "NVIDIA Driver Issues and Recommended Kernel Parameters:"
|
echo "NVIDIA Driver Issues and Recommended Kernel Parameters:"
|
||||||
echo ""
|
echo ""
|
||||||
echo "A) For 'conflicting memory type' or 'failed to allocate primary buffer' errors"
|
echo "A) For 'conflicting memory type' or 'failed to allocate primary buffer' errors"
|
||||||
echo " (especially with nvidia-96xx drivers):"
|
echo " (especially with nvidia-96xx drivers):"
|
||||||
echo " → Add 'nopat' to kernel parameters"
|
echo " → Add 'nopat' to kernel parameters"
|
||||||
echo ""
|
echo ""
|
||||||
echo "B) For OpenGL visual glitches, hangs, and errors with modern CPUs:"
|
echo "B) For OpenGL visual glitches, hangs, and errors with modern CPUs:"
|
||||||
echo " → Consider disabling micro-op cache in BIOS settings"
|
echo " → Consider disabling micro-op cache in BIOS settings"
|
||||||
echo " → This affects Intel Sandy Bridge (2011+) and AMD Zen (2017+) CPUs"
|
echo " → This affects Intel Sandy Bridge (2011+) and AMD Zen (2017+) CPUs"
|
||||||
echo " → Helps with severe graphical glitches in Xwayland applications"
|
echo " → Helps with severe graphical glitches in Xwayland applications"
|
||||||
echo " → Note: Disabling micro-op cache reduces CPU performance"
|
echo " → Note: Disabling micro-op cache reduces CPU performance"
|
||||||
echo ""
|
echo ""
|
||||||
echo "To add kernel parameters:"
|
echo "To add kernel parameters:"
|
||||||
echo "1. Edit /etc/default/grub"
|
echo "1. Edit /etc/default/grub"
|
||||||
echo "2. Add parameters to GRUB_CMDLINE_LINUX_DEFAULT"
|
echo "2. Add parameters to GRUB_CMDLINE_LINUX_DEFAULT"
|
||||||
echo "3. Run: grub-mkconfig -o /boot/grub/grub.cfg"
|
echo "3. Run: grub-mkconfig -o /boot/grub/grub.cfg"
|
||||||
echo "4. Reboot"
|
echo "4. Reboot"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Example GRUB_CMDLINE_LINUX_DEFAULT line:"
|
echo "Example GRUB_CMDLINE_LINUX_DEFAULT line:"
|
||||||
echo 'GRUB_CMDLINE_LINUX_DEFAULT="quiet nopat"'
|
echo 'GRUB_CMDLINE_LINUX_DEFAULT="quiet nopat"'
|
||||||
|
|
||||||
# Check current CPU for micro-op cache relevance
|
# Check current CPU for micro-op cache relevance
|
||||||
echo ""
|
echo ""
|
||||||
echo "CPU Information (for micro-op cache consideration):"
|
echo "CPU Information (for micro-op cache consideration):"
|
||||||
if command -v lscpu &> /dev/null; then
|
if command -v lscpu &>/dev/null; then
|
||||||
local cpu_info
|
local cpu_info
|
||||||
cpu_info=$(lscpu | grep "Model name" | cut -d: -f2 | xargs)
|
cpu_info=$(lscpu | grep "Model name" | cut -d: -f2 | xargs)
|
||||||
echo "Current CPU: $cpu_info"
|
echo "Current CPU: $cpu_info"
|
||||||
|
|
||||||
if echo "$cpu_info" | grep -qi "intel"; then
|
if echo "$cpu_info" | grep -qi "intel"; then
|
||||||
echo "→ Intel CPU detected. Sandy Bridge (2011) and later have micro-op cache"
|
echo "→ Intel CPU detected. Sandy Bridge (2011) and later have micro-op cache"
|
||||||
elif echo "$cpu_info" | grep -qi "amd"; then
|
elif echo "$cpu_info" | grep -qi "amd"; then
|
||||||
echo "→ AMD CPU detected. Zen (2017) and later have micro-op cache"
|
echo "→ AMD CPU detected. Zen (2017) and later have micro-op cache"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to suggest desktop environment settings
|
# Function to suggest desktop environment settings
|
||||||
suggest_desktop_settings() {
|
suggest_desktop_settings() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "6. Desktop Environment Recommendations..."
|
echo "6. Desktop Environment Recommendations..."
|
||||||
echo "========================================"
|
echo "========================================"
|
||||||
|
|
||||||
echo "For fullscreen application freezing/crashing issues:"
|
echo "For fullscreen application freezing/crashing issues:"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Enable Display Compositing and Direct fullscreen rendering:"
|
echo "Enable Display Compositing and Direct fullscreen rendering:"
|
||||||
echo ""
|
echo ""
|
||||||
echo "• KDE Plasma:"
|
echo "• KDE Plasma:"
|
||||||
echo " System Settings → Display and Monitor → Compositor"
|
echo " System Settings → Display and Monitor → Compositor"
|
||||||
echo " → Enable compositor + Enable direct rendering for fullscreen windows"
|
echo " → Enable compositor + Enable direct rendering for fullscreen windows"
|
||||||
echo ""
|
echo ""
|
||||||
echo "• GNOME:"
|
echo "• GNOME:"
|
||||||
echo " Use Extensions or dconf-editor to enable compositing features"
|
echo " Use Extensions or dconf-editor to enable compositing features"
|
||||||
echo ""
|
echo ""
|
||||||
echo "• XFCE:"
|
echo "• XFCE:"
|
||||||
echo " Settings → Window Manager Tweaks → Compositor"
|
echo " Settings → Window Manager Tweaks → Compositor"
|
||||||
echo " → Enable display compositing"
|
echo " → Enable display compositing"
|
||||||
echo ""
|
echo ""
|
||||||
echo "• Cinnamon:"
|
echo "• Cinnamon:"
|
||||||
echo " System Settings → Effects → Enable desktop effects"
|
echo " System Settings → Effects → Enable desktop effects"
|
||||||
|
|
||||||
# Detect current desktop environment
|
# Detect current desktop environment
|
||||||
if [[ -n $XDG_CURRENT_DESKTOP ]]; then
|
if [[ -n $XDG_CURRENT_DESKTOP ]]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "Detected desktop environment: $XDG_CURRENT_DESKTOP"
|
echo "Detected desktop environment: $XDG_CURRENT_DESKTOP"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Apply all configurations
|
# Apply all configurations
|
||||||
@ -331,14 +306,14 @@ install_pyroveil
|
|||||||
echo ""
|
echo ""
|
||||||
echo "7. Regenerating Initramfs..."
|
echo "7. Regenerating Initramfs..."
|
||||||
echo "============================"
|
echo "============================"
|
||||||
if command -v mkinitcpio &> /dev/null; then
|
if command -v mkinitcpio &>/dev/null; then
|
||||||
mkinitcpio -P
|
mkinitcpio -P
|
||||||
echo "✓ Initramfs regenerated with mkinitcpio"
|
echo "✓ Initramfs regenerated with mkinitcpio"
|
||||||
elif command -v dracut &> /dev/null; then
|
elif command -v dracut &>/dev/null; then
|
||||||
dracut --force
|
dracut --force
|
||||||
echo "✓ Initramfs regenerated with dracut"
|
echo "✓ Initramfs regenerated with dracut"
|
||||||
else
|
else
|
||||||
echo "Warning: Could not find mkinitcpio or dracut. You may need to manually regenerate initramfs."
|
echo "Warning: Could not find mkinitcpio or dracut. You may need to manually regenerate initramfs."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Display all recommendations
|
# Display all recommendations
|
||||||
@ -354,7 +329,7 @@ echo "✓ GSP firmware disabled"
|
|||||||
echo "✓ RenderAccel disabled in Xorg configuration"
|
echo "✓ RenderAccel disabled in Xorg configuration"
|
||||||
echo "✓ GCC version mismatch workaround added"
|
echo "✓ GCC version mismatch workaround added"
|
||||||
if [[ -d "/home/$SUDO_USER/pyroveil" ]]; then
|
if [[ -d "/home/$SUDO_USER/pyroveil" ]]; then
|
||||||
echo "✓ Pyroveil installed for mesh shader issues"
|
echo "✓ Pyroveil installed for mesh shader issues"
|
||||||
fi
|
fi
|
||||||
echo "✓ Initramfs regenerated"
|
echo "✓ Initramfs regenerated"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
241
scripts/lib/common.sh
Normal file
241
scripts/lib/common.sh
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Common library functions for linux-configuration scripts
|
||||||
|
# Source this file at the beginning of scripts that need shared functionality
|
||||||
|
#
|
||||||
|
# Usage: source "$(dirname "$(readlink -f "$0")")/../lib/common.sh"
|
||||||
|
# Or: source "/path/to/scripts/lib/common.sh"
|
||||||
|
|
||||||
|
# Prevent multiple sourcing
|
||||||
|
[[ -n ${_LIB_COMMON_LOADED:-} ]] && return 0
|
||||||
|
_LIB_COMMON_LOADED=1
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# LOGGING FUNCTIONS
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Log message with timestamp to stderr and optionally to a file
|
||||||
|
# Usage: log_message "message" [log_file]
|
||||||
|
log_message() {
|
||||||
|
local msg="$1"
|
||||||
|
local log_file="${2:-}"
|
||||||
|
local formatted
|
||||||
|
formatted="$(date '+%Y-%m-%d %H:%M:%S') - $msg"
|
||||||
|
echo "$formatted" >&2
|
||||||
|
if [[ -n "$log_file" ]]; then
|
||||||
|
echo "$formatted" >>"$log_file" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Simple log with timestamp (no file output)
|
||||||
|
# Usage: log "message"
|
||||||
|
log() {
|
||||||
|
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SUDO / ROOT HANDLING
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Check if running as root, if not re-exec with sudo
|
||||||
|
# Usage: require_root "$@"
|
||||||
|
require_root() {
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
echo "This script requires root privileges."
|
||||||
|
echo "Requesting sudo access..."
|
||||||
|
exec sudo "$0" "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the actual user even when running with sudo
|
||||||
|
# Usage: ACTUAL_USER=$(get_actual_user)
|
||||||
|
get_actual_user() {
|
||||||
|
echo "${SUDO_USER:-$USER}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the actual user's home directory
|
||||||
|
# Usage: USER_HOME=$(get_actual_user_home)
|
||||||
|
get_actual_user_home() {
|
||||||
|
local user
|
||||||
|
user=$(get_actual_user)
|
||||||
|
if [[ "$user" == "root" ]]; then
|
||||||
|
echo "/root"
|
||||||
|
else
|
||||||
|
echo "/home/$user"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# ARGUMENT PARSING HELPERS
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Parse common --interactive/-i and --help/-h flags
|
||||||
|
# Sets INTERACTIVE_MODE variable (exported for use by calling scripts)
|
||||||
|
# Usage: parse_common_args "$@"
|
||||||
|
# shift "$COMMON_ARGS_SHIFT"
|
||||||
|
export INTERACTIVE_MODE=false
|
||||||
|
export COMMON_ARGS_SHIFT=0
|
||||||
|
|
||||||
|
parse_interactive_args() {
|
||||||
|
INTERACTIVE_MODE=false
|
||||||
|
COMMON_ARGS_SHIFT=0
|
||||||
|
local script_name="${0##*/}"
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-i | --interactive)
|
||||||
|
INTERACTIVE_MODE=true
|
||||||
|
((COMMON_ARGS_SHIFT++))
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h | --help)
|
||||||
|
echo "Usage: $script_name [OPTIONS]"
|
||||||
|
echo "Options:"
|
||||||
|
echo " -i, --interactive Enable interactive prompts (default: auto-yes)"
|
||||||
|
echo " -h, --help Show this help message"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Stop parsing at first unknown argument
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# FOCUS APP DETECTION (for digital wellbeing scripts)
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Default focus apps - can be overridden before calling is_focus_app_running
|
||||||
|
FOCUS_APPS_WINDOWS=(
|
||||||
|
"Visual Studio Code"
|
||||||
|
"VSCodium"
|
||||||
|
"Cursor"
|
||||||
|
"IntelliJ IDEA"
|
||||||
|
"PyCharm"
|
||||||
|
"WebStorm"
|
||||||
|
"CLion"
|
||||||
|
"Rider"
|
||||||
|
"Sublime Text"
|
||||||
|
"Blender"
|
||||||
|
"Godot"
|
||||||
|
"Unity"
|
||||||
|
"Unreal Editor"
|
||||||
|
)
|
||||||
|
|
||||||
|
FOCUS_APPS_PROCESSES=(
|
||||||
|
"steam_app_"
|
||||||
|
"gamescope"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if any focus app is running (window-based detection)
|
||||||
|
# Returns 0 if focus app found, 1 otherwise
|
||||||
|
# Echoes the name of the found app
|
||||||
|
is_focus_app_running() {
|
||||||
|
# Check windows first
|
||||||
|
if command -v xdotool &>/dev/null; then
|
||||||
|
local app
|
||||||
|
for app in "${FOCUS_APPS_WINDOWS[@]}"; do
|
||||||
|
if xdotool search --name "$app" &>/dev/null 2>&1; then
|
||||||
|
echo "$app"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check specific processes
|
||||||
|
local app
|
||||||
|
for app in "${FOCUS_APPS_PROCESSES[@]}"; do
|
||||||
|
if pgrep -f "$app" &>/dev/null; then
|
||||||
|
echo "$app"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# COMMAND AVAILABILITY
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Check if a command exists
|
||||||
|
# Usage: if require_command ffmpeg; then ...
|
||||||
|
require_command() {
|
||||||
|
local cmd="$1"
|
||||||
|
local pkg="${2:-$1}"
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
echo "Error: '$cmd' is not installed or not in PATH." >&2
|
||||||
|
echo "Install with: sudo pacman -S $pkg" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# NOTIFICATION
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Send desktop notification (fails silently if notify-send not available)
|
||||||
|
# Usage: notify "Title" "Message" [urgency: low/normal/critical] [timeout_ms]
|
||||||
|
notify() {
|
||||||
|
local title="$1"
|
||||||
|
local message="$2"
|
||||||
|
local urgency="${3:-normal}"
|
||||||
|
local timeout="${4:-5000}"
|
||||||
|
|
||||||
|
if command -v notify-send &>/dev/null; then
|
||||||
|
notify-send -u "$urgency" -t "$timeout" "$title" "$message" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# FILE/PATH UTILITIES
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Get the directory containing the calling script
|
||||||
|
# Usage: SCRIPT_DIR=$(get_script_dir)
|
||||||
|
get_script_dir() {
|
||||||
|
dirname "$(readlink -f "${BASH_SOURCE[1]:-$0}")"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure a directory exists
|
||||||
|
# Usage: ensure_dir "/path/to/dir"
|
||||||
|
ensure_dir() {
|
||||||
|
local dir="$1"
|
||||||
|
if [[ ! -d "$dir" ]]; then
|
||||||
|
mkdir -p "$dir"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SYSTEMD HELPERS
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Enable and start a systemd service (user or system)
|
||||||
|
# Usage: enable_service "service-name" [--user]
|
||||||
|
enable_service() {
|
||||||
|
local service="$1"
|
||||||
|
local user_flag="${2:-}"
|
||||||
|
|
||||||
|
if [[ "$user_flag" == "--user" ]]; then
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
systemctl --user enable --now "$service"
|
||||||
|
else
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now "$service"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if a systemd service is active
|
||||||
|
# Usage: if is_service_active "service-name" [--user]; then ...
|
||||||
|
is_service_active() {
|
||||||
|
local service="$1"
|
||||||
|
local user_flag="${2:-}"
|
||||||
|
|
||||||
|
if [[ "$user_flag" == "--user" ]]; then
|
||||||
|
systemctl --user is-active --quiet "$service"
|
||||||
|
else
|
||||||
|
systemctl is-active --quiet "$service"
|
||||||
|
fi
|
||||||
|
}
|
||||||
@ -5,56 +5,30 @@
|
|||||||
|
|
||||||
set -e # Exit on any error
|
set -e # Exit on any error
|
||||||
|
|
||||||
# Default to non-interactive mode
|
# Source common library for shared functions
|
||||||
INTERACTIVE_MODE=false
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/lib/common.sh"
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse interactive/help arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
parse_interactive_args "$@"
|
||||||
case $1 in
|
shift "$COMMON_ARGS_SHIFT"
|
||||||
-i | --interactive)
|
|
||||||
INTERACTIVE_MODE=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h | --help)
|
|
||||||
echo "Usage: $0 [OPTIONS]"
|
|
||||||
echo "Options:"
|
|
||||||
echo " -i, --interactive Enable interactive prompts (default: auto-yes)"
|
|
||||||
echo " -h, --help Show this help message"
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown option: $1"
|
|
||||||
echo "Use -h or --help for usage information"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Function to check and request sudo privileges
|
# Check for sudo privileges
|
||||||
check_sudo() {
|
require_root "$@"
|
||||||
if [[ $EUID -ne 0 ]]; then
|
|
||||||
echo "This script requires sudo privileges to create systemd services and timers."
|
|
||||||
echo "Requesting sudo access..."
|
|
||||||
exec sudo "$0" "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check for sudo privileges after argument parsing
|
|
||||||
check_sudo "$@"
|
|
||||||
|
|
||||||
echo "Periodic System Setup - Pacman Wrapper & Hosts File"
|
echo "Periodic System Setup - Pacman Wrapper & Hosts File"
|
||||||
echo "==================================================="
|
echo "==================================================="
|
||||||
echo "Current Date: $(date)"
|
echo "Current Date: $(date)"
|
||||||
echo "User: $USER"
|
echo "User: $USER"
|
||||||
echo "Original user: ${SUDO_USER:-$USER}"
|
echo "Original user: $(get_actual_user)"
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
echo "Mode: Interactive (prompts enabled)"
|
echo "Mode: Interactive (prompts enabled)"
|
||||||
else
|
else
|
||||||
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get the directory where this script is located
|
# Get the directory where this script is located
|
||||||
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
|
||||||
CONFIG_DIR="$(dirname "$SCRIPT_DIR")"
|
CONFIG_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
|
|
||||||
# Define paths
|
# Define paths
|
||||||
@ -86,231 +60,231 @@ TEMPLATE_LOGROTATE="$LOGROTATE_TEMPLATES/periodic-system-maintenance"
|
|||||||
|
|
||||||
# Function to verify required files exist
|
# Function to verify required files exist
|
||||||
verify_files() {
|
verify_files() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "1. Verifying Required Files..."
|
echo "1. Verifying Required Files..."
|
||||||
echo "=============================="
|
echo "=============================="
|
||||||
|
|
||||||
local missing_files=()
|
local missing_files=()
|
||||||
|
|
||||||
if [[ ! -f $PACMAN_WRAPPER_SCRIPT ]]; then
|
if [[ ! -f $PACMAN_WRAPPER_SCRIPT ]]; then
|
||||||
missing_files+=("$PACMAN_WRAPPER_SCRIPT")
|
missing_files+=("$PACMAN_WRAPPER_SCRIPT")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -f $PACMAN_WRAPPER_INSTALL ]]; then
|
if [[ ! -f $PACMAN_WRAPPER_INSTALL ]]; then
|
||||||
missing_files+=("$PACMAN_WRAPPER_INSTALL")
|
missing_files+=("$PACMAN_WRAPPER_INSTALL")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -f $HOSTS_INSTALL_SCRIPT ]]; then
|
if [[ ! -f $HOSTS_INSTALL_SCRIPT ]]; then
|
||||||
missing_files+=("$HOSTS_INSTALL_SCRIPT")
|
missing_files+=("$HOSTS_INSTALL_SCRIPT")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check template files as well
|
# Check template files as well
|
||||||
for tmpl in \
|
for tmpl in \
|
||||||
"$TEMPLATE_MAINT_SCRIPT" \
|
"$TEMPLATE_MAINT_SCRIPT" \
|
||||||
"$TEMPLATE_HOSTS_MONITOR" \
|
"$TEMPLATE_HOSTS_MONITOR" \
|
||||||
"$TEMPLATE_BROWSER_WRAPPER" \
|
"$TEMPLATE_BROWSER_WRAPPER" \
|
||||||
"$TEMPLATE_SVC_MAINT" \
|
"$TEMPLATE_SVC_MAINT" \
|
||||||
"$TEMPLATE_TIMER" \
|
"$TEMPLATE_TIMER" \
|
||||||
"$TEMPLATE_STARTUP" \
|
"$TEMPLATE_STARTUP" \
|
||||||
"$TEMPLATE_HOSTS_SVC" \
|
"$TEMPLATE_HOSTS_SVC" \
|
||||||
"$TEMPLATE_LOGROTATE"; do
|
"$TEMPLATE_LOGROTATE"; do
|
||||||
if [[ ! -f $tmpl ]]; then
|
if [[ ! -f $tmpl ]]; then
|
||||||
missing_files+=("$tmpl")
|
missing_files+=("$tmpl")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ ${#missing_files[@]} -gt 0 ]]; then
|
if [[ ${#missing_files[@]} -gt 0 ]]; then
|
||||||
echo "Error: The following required files are missing:"
|
echo "Error: The following required files are missing:"
|
||||||
for file in "${missing_files[@]}"; do
|
for file in "${missing_files[@]}"; do
|
||||||
echo " - $file"
|
echo " - $file"
|
||||||
done
|
done
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "✓ All required files found"
|
echo "✓ All required files found"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create the combined execution script
|
# Function to create the combined execution script
|
||||||
create_execution_script() {
|
create_execution_script() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "2. Creating Combined Execution Script..."
|
echo "2. Creating Combined Execution Script..."
|
||||||
echo "======================================="
|
echo "======================================="
|
||||||
|
|
||||||
local exec_script="/usr/local/bin/periodic-system-maintenance.sh"
|
local exec_script="/usr/local/bin/periodic-system-maintenance.sh"
|
||||||
|
|
||||||
# Install from template with path substitutions
|
# Install from template with path substitutions
|
||||||
sed \
|
sed \
|
||||||
-e "s|__PACMAN_WRAPPER_INSTALL__|$PACMAN_WRAPPER_INSTALL|g" \
|
-e "s|__PACMAN_WRAPPER_INSTALL__|$PACMAN_WRAPPER_INSTALL|g" \
|
||||||
-e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
-e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
||||||
"$TEMPLATE_MAINT_SCRIPT" > "$exec_script"
|
"$TEMPLATE_MAINT_SCRIPT" >"$exec_script"
|
||||||
|
|
||||||
chmod +x "$exec_script"
|
chmod +x "$exec_script"
|
||||||
echo "✓ Installed execution script from template: $exec_script"
|
echo "✓ Installed execution script from template: $exec_script"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create systemd service
|
# Function to create systemd service
|
||||||
create_systemd_service() {
|
create_systemd_service() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "3. Creating Systemd Service..."
|
echo "3. Creating Systemd Service..."
|
||||||
echo "============================="
|
echo "============================="
|
||||||
|
|
||||||
local service_file="/etc/systemd/system/periodic-system-maintenance.service"
|
local service_file="/etc/systemd/system/periodic-system-maintenance.service"
|
||||||
install -m 0644 "$TEMPLATE_SVC_MAINT" "$service_file"
|
install -m 0644 "$TEMPLATE_SVC_MAINT" "$service_file"
|
||||||
echo "✓ Installed systemd service from template: $service_file"
|
echo "✓ Installed systemd service from template: $service_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create systemd timer for hourly execution
|
# Function to create systemd timer for hourly execution
|
||||||
create_systemd_timer() {
|
create_systemd_timer() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "4. Creating Systemd Timer..."
|
echo "4. Creating Systemd Timer..."
|
||||||
echo "============================"
|
echo "============================"
|
||||||
|
|
||||||
local timer_file="/etc/systemd/system/periodic-system-maintenance.timer"
|
local timer_file="/etc/systemd/system/periodic-system-maintenance.timer"
|
||||||
install -m 0644 "$TEMPLATE_TIMER" "$timer_file"
|
install -m 0644 "$TEMPLATE_TIMER" "$timer_file"
|
||||||
echo "✓ Installed systemd timer from template: $timer_file"
|
echo "✓ Installed systemd timer from template: $timer_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create startup service (additional to timer)
|
# Function to create startup service (additional to timer)
|
||||||
create_startup_service() {
|
create_startup_service() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "5. Creating Startup Service..."
|
echo "5. Creating Startup Service..."
|
||||||
echo "=============================="
|
echo "=============================="
|
||||||
|
|
||||||
local startup_service="/etc/systemd/system/periodic-system-startup.service"
|
local startup_service="/etc/systemd/system/periodic-system-startup.service"
|
||||||
install -m 0644 "$TEMPLATE_STARTUP" "$startup_service"
|
install -m 0644 "$TEMPLATE_STARTUP" "$startup_service"
|
||||||
echo "✓ Installed startup service from template: $startup_service"
|
echo "✓ Installed startup service from template: $startup_service"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create hosts file monitor service
|
# Function to create hosts file monitor service
|
||||||
create_hosts_monitor_service() {
|
create_hosts_monitor_service() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "6. Creating Hosts File Monitor Service..."
|
echo "6. Creating Hosts File Monitor Service..."
|
||||||
echo "========================================"
|
echo "========================================"
|
||||||
|
|
||||||
local monitor_script="/usr/local/bin/hosts-file-monitor.sh"
|
local monitor_script="/usr/local/bin/hosts-file-monitor.sh"
|
||||||
local monitor_service="/etc/systemd/system/hosts-file-monitor.service"
|
local monitor_service="/etc/systemd/system/hosts-file-monitor.service"
|
||||||
|
|
||||||
# Install the monitor script from template with substitution
|
# Install the monitor script from template with substitution
|
||||||
sed -e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
sed -e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
||||||
"$TEMPLATE_HOSTS_MONITOR" > "$monitor_script"
|
"$TEMPLATE_HOSTS_MONITOR" >"$monitor_script"
|
||||||
chmod +x "$monitor_script"
|
chmod +x "$monitor_script"
|
||||||
echo "✓ Installed hosts monitor script from template: $monitor_script"
|
echo "✓ Installed hosts monitor script from template: $monitor_script"
|
||||||
|
|
||||||
# Install the systemd service from template
|
# Install the systemd service from template
|
||||||
install -m 0644 "$TEMPLATE_HOSTS_SVC" "$monitor_service"
|
install -m 0644 "$TEMPLATE_HOSTS_SVC" "$monitor_service"
|
||||||
echo "✓ Installed hosts monitor service from template: $monitor_service"
|
echo "✓ Installed hosts monitor service from template: $monitor_service"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to install browser pre-exec wrapper and wire common browser names
|
# Function to install browser pre-exec wrapper and wire common browser names
|
||||||
install_browser_preexec_wrapper() {
|
install_browser_preexec_wrapper() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "6.1 Installing Browser Pre-Exec Wrapper..."
|
echo "6.1 Installing Browser Pre-Exec Wrapper..."
|
||||||
echo "========================================="
|
echo "========================================="
|
||||||
|
|
||||||
local wrapper="/usr/local/bin/browser-preexec-wrapper"
|
local wrapper="/usr/local/bin/browser-preexec-wrapper"
|
||||||
sed -e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
sed -e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
||||||
"$TEMPLATE_BROWSER_WRAPPER" > "$wrapper"
|
"$TEMPLATE_BROWSER_WRAPPER" >"$wrapper"
|
||||||
chmod +x "$wrapper"
|
chmod +x "$wrapper"
|
||||||
echo "✓ Installed wrapper: $wrapper"
|
echo "✓ Installed wrapper: $wrapper"
|
||||||
|
|
||||||
# Allow passwordless execution of hosts installer for root-only actions
|
# Allow passwordless execution of hosts installer for root-only actions
|
||||||
local sudoers_file="/etc/sudoers.d/hosts-install-no-passwd"
|
local sudoers_file="/etc/sudoers.d/hosts-install-no-passwd"
|
||||||
if command -v visudo > /dev/null 2>&1; then
|
if command -v visudo >/dev/null 2>&1; then
|
||||||
echo "${SUDO_USER:-$USER} ALL=(ALL) NOPASSWD: $HOSTS_INSTALL_SCRIPT" > "$sudoers_file"
|
echo "${SUDO_USER:-$USER} ALL=(ALL) NOPASSWD: $HOSTS_INSTALL_SCRIPT" >"$sudoers_file"
|
||||||
chmod 440 "$sudoers_file"
|
chmod 440 "$sudoers_file"
|
||||||
# Validate syntax
|
# Validate syntax
|
||||||
visudo -c > /dev/null || echo "Warning: sudoers validation returned non-zero"
|
visudo -c >/dev/null || echo "Warning: sudoers validation returned non-zero"
|
||||||
echo "✓ Sudoers drop-in created: $sudoers_file"
|
echo "✓ Sudoers drop-in created: $sudoers_file"
|
||||||
else
|
else
|
||||||
echo "visudo not found; skipping sudoers drop-in"
|
echo "visudo not found; skipping sudoers drop-in"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create symlinks for common browser commands to the wrapper in /usr/local/bin
|
# Create symlinks for common browser commands to the wrapper in /usr/local/bin
|
||||||
# This takes precedence over /usr/bin in PATH on most systems.
|
# This takes precedence over /usr/bin in PATH on most systems.
|
||||||
local browsers=("thorium-browser" "google-chrome" "google-chrome-stable" "chromium" "brave" "brave-browser" "vivaldi-stable" "firefox")
|
local browsers=("thorium-browser" "google-chrome" "google-chrome-stable" "chromium" "brave" "brave-browser" "vivaldi-stable" "firefox")
|
||||||
for b in "${browsers[@]}"; do
|
for b in "${browsers[@]}"; do
|
||||||
local link="/usr/local/bin/$b"
|
local link="/usr/local/bin/$b"
|
||||||
ln -sf "$wrapper" "$link"
|
ln -sf "$wrapper" "$link"
|
||||||
done
|
done
|
||||||
echo "✓ Symlinked wrapper for common browsers in /usr/local/bin"
|
echo "✓ Symlinked wrapper for common browsers in /usr/local/bin"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to enable and start services
|
# Function to enable and start services
|
||||||
enable_services() {
|
enable_services() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "7. Enabling Services and Timer..."
|
echo "7. Enabling Services and Timer..."
|
||||||
echo "================================="
|
echo "================================="
|
||||||
|
|
||||||
# Reload systemd daemon
|
# Reload systemd daemon
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
echo "✓ Systemd daemon reloaded"
|
echo "✓ Systemd daemon reloaded"
|
||||||
|
|
||||||
# Enable and start the timer
|
# Enable and start the timer
|
||||||
systemctl enable periodic-system-maintenance.timer
|
systemctl enable periodic-system-maintenance.timer
|
||||||
systemctl start periodic-system-maintenance.timer
|
systemctl start periodic-system-maintenance.timer
|
||||||
echo "✓ Timer enabled and started"
|
echo "✓ Timer enabled and started"
|
||||||
|
|
||||||
# Enable startup service (but don't start it now)
|
# Enable startup service (but don't start it now)
|
||||||
systemctl enable periodic-system-startup.service
|
systemctl enable periodic-system-startup.service
|
||||||
echo "✓ Startup service enabled"
|
echo "✓ Startup service enabled"
|
||||||
|
|
||||||
# Enable hosts file monitor service
|
# Enable hosts file monitor service
|
||||||
systemctl enable hosts-file-monitor.service
|
systemctl enable hosts-file-monitor.service
|
||||||
systemctl start hosts-file-monitor.service
|
systemctl start hosts-file-monitor.service
|
||||||
echo "✓ Hosts file monitor service enabled and started"
|
echo "✓ Hosts file monitor service enabled and started"
|
||||||
|
|
||||||
# Show timer status
|
# Show timer status
|
||||||
echo ""
|
echo ""
|
||||||
echo "Timer Status:"
|
echo "Timer Status:"
|
||||||
systemctl status periodic-system-maintenance.timer --no-pager -l
|
systemctl status periodic-system-maintenance.timer --no-pager -l
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Hosts Monitor Status:"
|
echo "Hosts Monitor Status:"
|
||||||
systemctl status hosts-file-monitor.service --no-pager -l
|
systemctl status hosts-file-monitor.service --no-pager -l
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Next scheduled runs:"
|
echo "Next scheduled runs:"
|
||||||
systemctl list-timers periodic-system-maintenance.timer --no-pager
|
systemctl list-timers periodic-system-maintenance.timer --no-pager
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create log rotation configuration
|
# Function to create log rotation configuration
|
||||||
create_log_rotation() {
|
create_log_rotation() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "8. Setting up Log Rotation..."
|
echo "8. Setting up Log Rotation..."
|
||||||
echo "============================="
|
echo "============================="
|
||||||
|
|
||||||
local logrotate_conf="/etc/logrotate.d/periodic-system-maintenance"
|
local logrotate_conf="/etc/logrotate.d/periodic-system-maintenance"
|
||||||
install -m 0644 "$TEMPLATE_LOGROTATE" "$logrotate_conf"
|
install -m 0644 "$TEMPLATE_LOGROTATE" "$logrotate_conf"
|
||||||
echo "✓ Installed log rotation configuration from template: $logrotate_conf"
|
echo "✓ Installed log rotation configuration from template: $logrotate_conf"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to run initial execution
|
# Function to run initial execution
|
||||||
run_initial_execution() {
|
run_initial_execution() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "9. Running Initial Execution..."
|
echo "9. Running Initial Execution..."
|
||||||
echo "==============================="
|
echo "==============================="
|
||||||
|
|
||||||
local run_initial=true
|
local run_initial=true
|
||||||
|
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
echo "Would you like to run the system maintenance now to test the setup?"
|
echo "Would you like to run the system maintenance now to test the setup?"
|
||||||
read -p "Run initial execution? (y/N): " -n 1 -r
|
read -p "Run initial execution? (y/N): " -n 1 -r
|
||||||
echo
|
echo
|
||||||
|
|
||||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
run_initial=false
|
run_initial=false
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Auto-running initial execution to test the setup (use --interactive to prompt)"
|
echo "Auto-running initial execution to test the setup (use --interactive to prompt)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $run_initial == "true" ]]; then
|
if [[ $run_initial == "true" ]]; then
|
||||||
echo "Running initial system maintenance..."
|
echo "Running initial system maintenance..."
|
||||||
/usr/local/bin/periodic-system-maintenance.sh
|
/usr/local/bin/periodic-system-maintenance.sh
|
||||||
echo "✓ Initial execution completed"
|
echo "✓ Initial execution completed"
|
||||||
else
|
else
|
||||||
echo "Skipping initial execution"
|
echo "Skipping initial execution"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Main execution
|
# Main execution
|
||||||
|
|||||||
@ -4,58 +4,33 @@
|
|||||||
|
|
||||||
set -e # Exit on any error
|
set -e # Exit on any error
|
||||||
|
|
||||||
# Default to non-interactive mode
|
# Source common library for shared functions
|
||||||
INTERACTIVE_MODE=false
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/lib/common.sh"
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse interactive/help arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
parse_interactive_args "$@"
|
||||||
case $1 in
|
shift "$COMMON_ARGS_SHIFT"
|
||||||
-i | --interactive)
|
|
||||||
INTERACTIVE_MODE=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h | --help)
|
|
||||||
echo "Usage: $0 [OPTIONS]"
|
|
||||||
echo "Options:"
|
|
||||||
echo " -i, --interactive Enable interactive prompts (default: auto-yes)"
|
|
||||||
echo " -h, --help Show this help message"
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown option: $1"
|
|
||||||
echo "Use -h or --help for usage information"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Function to check and request sudo privileges
|
# Check for sudo privileges
|
||||||
check_sudo() {
|
require_root "$@"
|
||||||
if [[ $EUID -ne 0 ]]; then
|
|
||||||
echo "This script requires sudo privileges to create systemd services."
|
|
||||||
echo "Requesting sudo access..."
|
|
||||||
exec sudo "$0" "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check for sudo privileges after argument parsing
|
|
||||||
check_sudo "$@"
|
|
||||||
|
|
||||||
echo "Thorium Browser Auto-Startup Setup"
|
echo "Thorium Browser Auto-Startup Setup"
|
||||||
echo "=================================="
|
echo "=================================="
|
||||||
echo "Current Date: $(date)"
|
echo "Current Date: $(date)"
|
||||||
echo "User: $USER"
|
echo "User: $USER"
|
||||||
echo "Original user: ${SUDO_USER:-$USER}"
|
echo "Original user: $(get_actual_user)"
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
echo "Mode: Interactive (prompts enabled)"
|
echo "Mode: Interactive (prompts enabled)"
|
||||||
else
|
else
|
||||||
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Target URL
|
# Target URL
|
||||||
TARGET_URL="https://www.fitatu.com/app/planner"
|
TARGET_URL="https://www.fitatu.com/app/planner"
|
||||||
BROWSER_COMMAND="thorium-browser"
|
BROWSER_COMMAND="thorium-browser"
|
||||||
USER_HOME="/home/${SUDO_USER}"
|
USER_HOME="/home/$(get_actual_user)"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Target URL: $TARGET_URL"
|
echo "Target URL: $TARGET_URL"
|
||||||
@ -64,72 +39,72 @@ echo "User home: $USER_HOME"
|
|||||||
|
|
||||||
# Function to check if Thorium browser is installed
|
# Function to check if Thorium browser is installed
|
||||||
check_thorium_browser() {
|
check_thorium_browser() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "1. Checking Thorium Browser Installation..."
|
echo "1. Checking Thorium Browser Installation..."
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
|
|
||||||
if ! command -v "$BROWSER_COMMAND" &> /dev/null; then
|
if ! command -v "$BROWSER_COMMAND" &>/dev/null; then
|
||||||
echo "Warning: Thorium browser not found in PATH"
|
echo "Warning: Thorium browser not found in PATH"
|
||||||
echo "Checking alternative locations..."
|
echo "Checking alternative locations..."
|
||||||
|
|
||||||
# Check common installation paths
|
# Check common installation paths
|
||||||
local alt_paths=(
|
local alt_paths=(
|
||||||
"/opt/thorium/thorium"
|
"/opt/thorium/thorium"
|
||||||
"/usr/bin/thorium"
|
"/usr/bin/thorium"
|
||||||
"/usr/local/bin/thorium"
|
"/usr/local/bin/thorium"
|
||||||
"/opt/thorium-browser/thorium-browser"
|
"/opt/thorium-browser/thorium-browser"
|
||||||
"${USER_HOME}/.local/bin/thorium-browser"
|
"${USER_HOME}/.local/bin/thorium-browser"
|
||||||
)
|
)
|
||||||
|
|
||||||
local found=false
|
local found=false
|
||||||
for path in "${alt_paths[@]}"; do
|
for path in "${alt_paths[@]}"; do
|
||||||
if [[ -x $path ]]; then
|
if [[ -x $path ]]; then
|
||||||
BROWSER_COMMAND="$path"
|
BROWSER_COMMAND="$path"
|
||||||
echo "✓ Found Thorium browser at: $path"
|
echo "✓ Found Thorium browser at: $path"
|
||||||
found=true
|
found=true
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ $found != true ]]; then
|
if [[ $found != true ]]; then
|
||||||
echo "Error: Thorium browser not found!"
|
echo "Error: Thorium browser not found!"
|
||||||
echo "Please install Thorium browser first or ensure it's in your PATH."
|
echo "Please install Thorium browser first or ensure it's in your PATH."
|
||||||
echo ""
|
echo ""
|
||||||
echo "You can install Thorium browser from:"
|
echo "You can install Thorium browser from:"
|
||||||
echo "https://thorium.rocks/"
|
echo "https://thorium.rocks/"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
local continue_anyway=false
|
local continue_anyway=false
|
||||||
|
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
read -p "Continue anyway? The service will be created but may fail to start (y/N): " -n 1 -r
|
read -p "Continue anyway? The service will be created but may fail to start (y/N): " -n 1 -r
|
||||||
echo
|
echo
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
continue_anyway=true
|
continue_anyway=true
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Auto-continuing anyway - service will be created but may fail to start (use --interactive to prompt)"
|
echo "Auto-continuing anyway - service will be created but may fail to start (use --interactive to prompt)"
|
||||||
continue_anyway=true
|
continue_anyway=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $continue_anyway != true ]]; then
|
if [[ $continue_anyway != true ]]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "✓ Thorium browser found: $(which $BROWSER_COMMAND)"
|
echo "✓ Thorium browser found: $(which $BROWSER_COMMAND)"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create the browser launcher script
|
# Function to create the browser launcher script
|
||||||
create_launcher_script() {
|
create_launcher_script() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "2. Creating Browser Launcher Script..."
|
echo "2. Creating Browser Launcher Script..."
|
||||||
echo "====================================="
|
echo "====================================="
|
||||||
|
|
||||||
local launcher_script="/usr/local/bin/thorium-fitatu-launcher.sh"
|
local launcher_script="/usr/local/bin/thorium-fitatu-launcher.sh"
|
||||||
|
|
||||||
cat > "$launcher_script" << EOF
|
cat >"$launcher_script" <<EOF
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Thorium browser launcher for Fitatu website
|
# Thorium browser launcher for Fitatu website
|
||||||
# Created by setup_thorium_startup.sh on $(date)
|
# Created by setup_thorium_startup.sh on $(date)
|
||||||
@ -203,24 +178,24 @@ else
|
|||||||
fi
|
fi
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
chmod +x "$launcher_script"
|
chmod +x "$launcher_script"
|
||||||
echo "✓ Created launcher script: $launcher_script"
|
echo "✓ Created launcher script: $launcher_script"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create systemd service for user session
|
# Function to create systemd service for user session
|
||||||
create_user_systemd_service() {
|
create_user_systemd_service() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "3. Creating User Systemd Service..."
|
echo "3. Creating User Systemd Service..."
|
||||||
echo "=================================="
|
echo "=================================="
|
||||||
|
|
||||||
local user_systemd_dir="$USER_HOME/.config/systemd/user"
|
local user_systemd_dir="$USER_HOME/.config/systemd/user"
|
||||||
local service_file="$user_systemd_dir/thorium-fitatu-startup.service"
|
local service_file="$user_systemd_dir/thorium-fitatu-startup.service"
|
||||||
|
|
||||||
# Create user systemd directory
|
# Create user systemd directory
|
||||||
sudo -u "${SUDO_USER}" mkdir -p "$user_systemd_dir"
|
sudo -u "${SUDO_USER}" mkdir -p "$user_systemd_dir"
|
||||||
|
|
||||||
# Create the service file
|
# Create the service file
|
||||||
sudo -u "${SUDO_USER}" tee "$service_file" > /dev/null << EOF
|
sudo -u "${SUDO_USER}" tee "$service_file" >/dev/null <<EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Launch Thorium Browser with Fitatu on Startup
|
Description=Launch Thorium Browser with Fitatu on Startup
|
||||||
After=graphical-session.target
|
After=graphical-session.target
|
||||||
@ -245,18 +220,18 @@ TimeoutStartSec=120
|
|||||||
WantedBy=default.target
|
WantedBy=default.target
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "✓ Created user systemd service: $service_file"
|
echo "✓ Created user systemd service: $service_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create system-wide systemd service (alternative approach)
|
# Function to create system-wide systemd service (alternative approach)
|
||||||
create_system_systemd_service() {
|
create_system_systemd_service() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "4. Creating System Systemd Service..."
|
echo "4. Creating System Systemd Service..."
|
||||||
echo "===================================="
|
echo "===================================="
|
||||||
|
|
||||||
local service_file="/etc/systemd/system/thorium-fitatu-startup.service"
|
local service_file="/etc/systemd/system/thorium-fitatu-startup.service"
|
||||||
|
|
||||||
cat > "$service_file" << EOF
|
cat >"$service_file" <<EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Launch Thorium Browser with Fitatu on Startup
|
Description=Launch Thorium Browser with Fitatu on Startup
|
||||||
After=multi-user.target network-online.target
|
After=multi-user.target network-online.target
|
||||||
@ -283,23 +258,23 @@ TimeoutStartSec=180
|
|||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "✓ Created system systemd service: $service_file"
|
echo "✓ Created system systemd service: $service_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create autostart desktop entry (additional method)
|
# Function to create autostart desktop entry (additional method)
|
||||||
create_autostart_entry() {
|
create_autostart_entry() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "5. Creating Autostart Desktop Entry..."
|
echo "5. Creating Autostart Desktop Entry..."
|
||||||
echo "====================================="
|
echo "====================================="
|
||||||
|
|
||||||
local autostart_dir="$USER_HOME/.config/autostart"
|
local autostart_dir="$USER_HOME/.config/autostart"
|
||||||
local desktop_file="$autostart_dir/thorium-fitatu.desktop"
|
local desktop_file="$autostart_dir/thorium-fitatu.desktop"
|
||||||
|
|
||||||
# Create autostart directory
|
# Create autostart directory
|
||||||
sudo -u "${SUDO_USER}" mkdir -p "$autostart_dir"
|
sudo -u "${SUDO_USER}" mkdir -p "$autostart_dir"
|
||||||
|
|
||||||
# Create desktop entry
|
# Create desktop entry
|
||||||
sudo -u "${SUDO_USER}" tee "$desktop_file" > /dev/null << EOF
|
sudo -u "${SUDO_USER}" tee "$desktop_file" >/dev/null <<EOF
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=Thorium Fitatu Startup
|
Name=Thorium Fitatu Startup
|
||||||
@ -314,45 +289,45 @@ Terminal=false
|
|||||||
Categories=Network;WebBrowser;
|
Categories=Network;WebBrowser;
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "✓ Created autostart desktop entry: $desktop_file"
|
echo "✓ Created autostart desktop entry: $desktop_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create i3 config autostart entry
|
# Function to create i3 config autostart entry
|
||||||
create_i3_autostart() {
|
create_i3_autostart() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "6. Creating i3 Config Autostart Entry..."
|
echo "6. Creating i3 Config Autostart Entry..."
|
||||||
echo "======================================="
|
echo "======================================="
|
||||||
|
|
||||||
local i3_config="$USER_HOME/.config/i3/config"
|
local i3_config="$USER_HOME/.config/i3/config"
|
||||||
local i3_config_dir="$USER_HOME/.config/i3"
|
local i3_config_dir="$USER_HOME/.config/i3"
|
||||||
|
|
||||||
# Create i3 config directory if it doesn't exist
|
# Create i3 config directory if it doesn't exist
|
||||||
sudo -u "${SUDO_USER}" mkdir -p "$i3_config_dir"
|
sudo -u "${SUDO_USER}" mkdir -p "$i3_config_dir"
|
||||||
|
|
||||||
# Check if i3 config exists
|
# Check if i3 config exists
|
||||||
if [[ -f $i3_config ]]; then
|
if [[ -f $i3_config ]]; then
|
||||||
# Check if autostart entry already exists
|
# Check if autostart entry already exists
|
||||||
if ! sudo -u "${SUDO_USER}" grep -q "thorium-fitatu-launcher" "$i3_config"; then
|
if ! sudo -u "${SUDO_USER}" grep -q "thorium-fitatu-launcher" "$i3_config"; then
|
||||||
# Add autostart entry to i3 config
|
# Add autostart entry to i3 config
|
||||||
sudo -u "${SUDO_USER}" bash -c "echo '' >> '$i3_config'"
|
sudo -u "${SUDO_USER}" bash -c "echo '' >> '$i3_config'"
|
||||||
sudo -u "${SUDO_USER}" bash -c "echo '# Auto-start Thorium browser with Fitatu' >> '$i3_config'"
|
sudo -u "${SUDO_USER}" bash -c "echo '# Auto-start Thorium browser with Fitatu' >> '$i3_config'"
|
||||||
sudo -u "${SUDO_USER}" bash -c "echo 'exec --no-startup-id /usr/local/bin/thorium-fitatu-launcher.sh' >> '$i3_config'"
|
sudo -u "${SUDO_USER}" bash -c "echo 'exec --no-startup-id /usr/local/bin/thorium-fitatu-launcher.sh' >> '$i3_config'"
|
||||||
echo "✓ Added autostart entry to i3 config: $i3_config"
|
echo "✓ Added autostart entry to i3 config: $i3_config"
|
||||||
else
|
else
|
||||||
echo "✓ Autostart entry already exists in i3 config"
|
echo "✓ Autostart entry already exists in i3 config"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Warning: i3 config file not found at $i3_config"
|
echo "Warning: i3 config file not found at $i3_config"
|
||||||
echo "You may need to manually add the following line to your i3 config:"
|
echo "You may need to manually add the following line to your i3 config:"
|
||||||
echo "exec --no-startup-id /usr/local/bin/thorium-fitatu-launcher.sh"
|
echo "exec --no-startup-id /usr/local/bin/thorium-fitatu-launcher.sh"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create a script to enable user service after login
|
# Function to create a script to enable user service after login
|
||||||
create_user_enable_script() {
|
create_user_enable_script() {
|
||||||
local enable_script="$USER_HOME/.config/thorium-enable-service.sh"
|
local enable_script="$USER_HOME/.config/thorium-enable-service.sh"
|
||||||
|
|
||||||
sudo -u "${SUDO_USER}" tee "$enable_script" > /dev/null << 'EOF'
|
sudo -u "${SUDO_USER}" tee "$enable_script" >/dev/null <<'EOF'
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Script to enable thorium-fitatu-startup user service
|
# Script to enable thorium-fitatu-startup user service
|
||||||
# This runs once to enable the service, then removes itself
|
# This runs once to enable the service, then removes itself
|
||||||
@ -365,110 +340,110 @@ systemctl --user enable thorium-fitatu-startup.service
|
|||||||
rm "$0"
|
rm "$0"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
sudo -u "${SUDO_USER}" chmod +x "$enable_script"
|
sudo -u "${SUDO_USER}" chmod +x "$enable_script"
|
||||||
|
|
||||||
# Add to user's .bashrc to run on next login
|
# Add to user's .bashrc to run on next login
|
||||||
local bashrc="$USER_HOME/.bashrc"
|
local bashrc="$USER_HOME/.bashrc"
|
||||||
if [[ -f $bashrc ]]; then
|
if [[ -f $bashrc ]]; then
|
||||||
sudo -u "${SUDO_USER}" bash -c "echo '' >> '$bashrc'"
|
sudo -u "${SUDO_USER}" bash -c "echo '' >> '$bashrc'"
|
||||||
sudo -u "${SUDO_USER}" bash -c "echo '# Auto-enable thorium service (temporary)' >> '$bashrc'"
|
sudo -u "${SUDO_USER}" bash -c "echo '# Auto-enable thorium service (temporary)' >> '$bashrc'"
|
||||||
sudo -u "${SUDO_USER}" bash -c "echo '[[ -x ~/.config/thorium-enable-service.sh ]] && ~/.config/thorium-enable-service.sh' >> '$bashrc'"
|
sudo -u "${SUDO_USER}" bash -c "echo '[[ -x ~/.config/thorium-enable-service.sh ]] && ~/.config/thorium-enable-service.sh' >> '$bashrc'"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to enable services
|
# Function to enable services
|
||||||
enable_services() {
|
enable_services() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "7. Enabling Services..."
|
echo "7. Enabling Services..."
|
||||||
echo "======================"
|
echo "======================"
|
||||||
|
|
||||||
# Reload systemd daemon
|
# Reload systemd daemon
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
echo "✓ System daemon reloaded"
|
echo "✓ System daemon reloaded"
|
||||||
|
|
||||||
# Enable system service
|
# Enable system service
|
||||||
systemctl enable thorium-fitatu-startup.service
|
systemctl enable thorium-fitatu-startup.service
|
||||||
echo "✓ System service enabled"
|
echo "✓ System service enabled"
|
||||||
|
|
||||||
# Enable lingering for the user (allows user services to run without login)
|
# Enable lingering for the user (allows user services to run without login)
|
||||||
loginctl enable-linger "${SUDO_USER}"
|
loginctl enable-linger "${SUDO_USER}"
|
||||||
echo "✓ User lingering enabled"
|
echo "✓ User lingering enabled"
|
||||||
|
|
||||||
# Create a script to enable user service after login
|
# Create a script to enable user service after login
|
||||||
create_user_enable_script
|
create_user_enable_script
|
||||||
echo "✓ User service will be enabled on next login"
|
echo "✓ User service will be enabled on next login"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to test the setup
|
# Function to test the setup
|
||||||
test_setup() {
|
test_setup() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "8. Testing Setup..."
|
echo "8. Testing Setup..."
|
||||||
echo "=================="
|
echo "=================="
|
||||||
|
|
||||||
local run_test=true
|
local run_test=true
|
||||||
|
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
echo "Would you like to test the browser launcher now?"
|
echo "Would you like to test the browser launcher now?"
|
||||||
read -p "Test launch Thorium browser with Fitatu? (y/N): " -n 1 -r
|
read -p "Test launch Thorium browser with Fitatu? (y/N): " -n 1 -r
|
||||||
echo
|
echo
|
||||||
|
|
||||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
run_test=false
|
run_test=false
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Auto-testing the browser launcher (use --interactive to prompt)"
|
echo "Auto-testing the browser launcher (use --interactive to prompt)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $run_test == "true" ]]; then
|
if [[ $run_test == "true" ]]; then
|
||||||
echo "Testing browser launch..."
|
echo "Testing browser launch..."
|
||||||
echo "Note: This will open Thorium browser with Fitatu website"
|
echo "Note: This will open Thorium browser with Fitatu website"
|
||||||
|
|
||||||
# Test the launcher immediately
|
# Test the launcher immediately
|
||||||
if /usr/local/bin/thorium-fitatu-launcher.sh; then
|
if /usr/local/bin/thorium-fitatu-launcher.sh; then
|
||||||
echo "✓ Test launch completed successfully"
|
echo "✓ Test launch completed successfully"
|
||||||
else
|
else
|
||||||
echo "✗ Test launch failed"
|
echo "✗ Test launch failed"
|
||||||
echo "Check that Thorium browser is properly installed and accessible"
|
echo "Check that Thorium browser is properly installed and accessible"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Skipping test launch"
|
echo "Skipping test launch"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to show usage instructions
|
# Function to show usage instructions
|
||||||
show_instructions() {
|
show_instructions() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo "Thorium Browser Auto-Startup Setup Complete"
|
echo "Thorium Browser Auto-Startup Setup Complete"
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo "Summary:"
|
echo "Summary:"
|
||||||
echo "✓ Launcher script created: /usr/local/bin/thorium-fitatu-launcher.sh"
|
echo "✓ Launcher script created: /usr/local/bin/thorium-fitatu-launcher.sh"
|
||||||
echo "✓ System service created: thorium-fitatu-startup.service"
|
echo "✓ System service created: thorium-fitatu-startup.service"
|
||||||
echo "✓ User service created: ~/.config/systemd/user/thorium-fitatu-startup.service"
|
echo "✓ User service created: ~/.config/systemd/user/thorium-fitatu-startup.service"
|
||||||
echo "✓ Autostart entry created: ~/.config/autostart/thorium-fitatu.desktop"
|
echo "✓ Autostart entry created: ~/.config/autostart/thorium-fitatu.desktop"
|
||||||
echo "✓ i3 autostart entry added to: ~/.config/i3/config"
|
echo "✓ i3 autostart entry added to: ~/.config/i3/config"
|
||||||
echo "✓ Services enabled for automatic startup"
|
echo "✓ Services enabled for automatic startup"
|
||||||
echo ""
|
echo ""
|
||||||
echo "The system will now:"
|
echo "The system will now:"
|
||||||
echo "• Launch Thorium browser with $TARGET_URL on every startup"
|
echo "• Launch Thorium browser with $TARGET_URL on every startup"
|
||||||
echo "• Use multiple methods to ensure reliable startup"
|
echo "• Use multiple methods to ensure reliable startup"
|
||||||
echo "• Wait for desktop environment to be ready before launching"
|
echo "• Wait for desktop environment to be ready before launching"
|
||||||
echo "• User service will be enabled automatically on next login"
|
echo "• User service will be enabled automatically on next login"
|
||||||
echo ""
|
echo ""
|
||||||
echo "To check status:"
|
echo "To check status:"
|
||||||
echo " systemctl status thorium-fitatu-startup.service"
|
echo " systemctl status thorium-fitatu-startup.service"
|
||||||
echo " systemctl --user status thorium-fitatu-startup.service (after login)"
|
echo " systemctl --user status thorium-fitatu-startup.service (after login)"
|
||||||
echo ""
|
echo ""
|
||||||
echo "To view logs:"
|
echo "To view logs:"
|
||||||
echo " journalctl -u thorium-fitatu-startup.service"
|
echo " journalctl -u thorium-fitatu-startup.service"
|
||||||
echo " journalctl --user -u thorium-fitatu-startup.service"
|
echo " journalctl --user -u thorium-fitatu-startup.service"
|
||||||
echo ""
|
echo ""
|
||||||
echo "To disable (if needed):"
|
echo "To disable (if needed):"
|
||||||
echo " sudo systemctl disable thorium-fitatu-startup.service"
|
echo " sudo systemctl disable thorium-fitatu-startup.service"
|
||||||
echo " systemctl --user disable thorium-fitatu-startup.service"
|
echo " systemctl --user disable thorium-fitatu-startup.service"
|
||||||
echo " rm ~/.config/autostart/thorium-fitatu.desktop"
|
echo " rm ~/.config/autostart/thorium-fitatu.desktop"
|
||||||
echo ""
|
echo ""
|
||||||
echo "IMPORTANT: Browser will launch automatically on next reboot!"
|
echo "IMPORTANT: Browser will launch automatically on next reboot!"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Main execution
|
# Main execution
|
||||||
|
|||||||
238
scripts/utils/convert_video.sh
Normal file
238
scripts/utils/convert_video.sh
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# convert_video.sh
|
||||||
|
#
|
||||||
|
# Convert video files to a target format (mp4 or webm) using ffmpeg.
|
||||||
|
# Accepts either a single video file or a directory (will recurse into subdirectories).
|
||||||
|
|
||||||
|
# Default settings
|
||||||
|
TARGET_FORMAT="mp4"
|
||||||
|
CRF="" # Will be set based on format if not specified
|
||||||
|
PRESET="medium"
|
||||||
|
DELETE_ORIGINAL=false
|
||||||
|
TARGET_PATH=""
|
||||||
|
|
||||||
|
# Video extensions to search for
|
||||||
|
ALL_VIDEO_EXTENSIONS=("mp4" "webm" "mkv" "avi" "mov" "wmv" "flv" "m4v" "mpg" "mpeg" "3gp" "ogv" "ts" "mts" "m2ts" "vob" "asf" "rm" "rmvb" "divx" "f4v")
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage:
|
||||||
|
$(basename "$0") [OPTIONS] PATH
|
||||||
|
|
||||||
|
Convert video files to mp4 or webm format using ffmpeg.
|
||||||
|
PATH can be a single video file or a directory (will recurse into subdirectories).
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-f FORMAT Target format: mp4 or webm (default: mp4)
|
||||||
|
-c CRF Quality level (default: 23 for mp4, 30 for webm; lower = better)
|
||||||
|
-p PRESET Encoding preset (default: medium)
|
||||||
|
Options: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow
|
||||||
|
-d Delete original file after successful conversion
|
||||||
|
-h Show this help
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
$(basename "$0") video.webm # Convert to mp4
|
||||||
|
$(basename "$0") -f webm video.mp4 # Convert to webm
|
||||||
|
$(basename "$0") /path/to/videos/ # Convert all videos in directory to mp4
|
||||||
|
$(basename "$0") -f webm -c 25 -d /path/to/videos/
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_ffmpeg() {
|
||||||
|
if ! command -v ffmpeg >/dev/null 2>&1; then
|
||||||
|
echo "Error: 'ffmpeg' is not installed or not in PATH." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_video_extensions_except() {
|
||||||
|
local exclude="$1"
|
||||||
|
local exts=()
|
||||||
|
for ext in "${ALL_VIDEO_EXTENSIONS[@]}"; do
|
||||||
|
if [[ "${ext,,}" != "${exclude,,}" ]]; then
|
||||||
|
exts+=("$ext")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "${exts[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
is_video_file() {
|
||||||
|
local file="$1"
|
||||||
|
local ext="${file##*.}"
|
||||||
|
ext="${ext,,}" # lowercase
|
||||||
|
|
||||||
|
for video_ext in "${ALL_VIDEO_EXTENSIONS[@]}"; do
|
||||||
|
if [[ "$ext" == "${video_ext,,}" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
convert_video() {
|
||||||
|
local input_file="$1"
|
||||||
|
local output_file="${input_file%.*}.${TARGET_FORMAT}"
|
||||||
|
|
||||||
|
# Skip if output already exists
|
||||||
|
if [[ -f "$output_file" ]]; then
|
||||||
|
log "Skipping '$input_file': output '$output_file' already exists"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Converting '$input_file' -> '$output_file'"
|
||||||
|
|
||||||
|
local ffmpeg_args=()
|
||||||
|
ffmpeg_args+=(-hide_banner -loglevel warning -i "$input_file")
|
||||||
|
|
||||||
|
if [[ "$TARGET_FORMAT" == "mp4" ]]; then
|
||||||
|
# H.264 codec for video and AAC for audio (maximum compatibility)
|
||||||
|
ffmpeg_args+=(-c:v libx264 -crf "$CRF" -preset "$PRESET")
|
||||||
|
ffmpeg_args+=(-c:a aac -b:a 192k)
|
||||||
|
ffmpeg_args+=(-movflags +faststart)
|
||||||
|
elif [[ "$TARGET_FORMAT" == "webm" ]]; then
|
||||||
|
# VP9 codec for video and Opus for audio
|
||||||
|
ffmpeg_args+=(-c:v libvpx-vp9 -crf "$CRF" -b:v 0)
|
||||||
|
ffmpeg_args+=(-c:a libopus -b:a 128k)
|
||||||
|
fi
|
||||||
|
|
||||||
|
ffmpeg_args+=("$output_file")
|
||||||
|
|
||||||
|
if ffmpeg "${ffmpeg_args[@]}"; then
|
||||||
|
log "Successfully converted '$input_file'"
|
||||||
|
|
||||||
|
if [[ "$DELETE_ORIGINAL" == true ]]; then
|
||||||
|
log "Deleting original: '$input_file'"
|
||||||
|
rm "$input_file"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log "Error converting '$input_file'"
|
||||||
|
[[ -f "$output_file" ]] && rm "$output_file"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
process_directory() {
|
||||||
|
local dir="$1"
|
||||||
|
local count=0
|
||||||
|
local failed=0
|
||||||
|
|
||||||
|
log "Searching for video files in '$dir'..."
|
||||||
|
|
||||||
|
# Build find command dynamically
|
||||||
|
local find_args=(-type f \()
|
||||||
|
local first=true
|
||||||
|
for ext in "${ALL_VIDEO_EXTENSIONS[@]}"; do
|
||||||
|
if [[ "${ext,,}" != "${TARGET_FORMAT,,}" ]]; then
|
||||||
|
if [[ "$first" == true ]]; then
|
||||||
|
first=false
|
||||||
|
else
|
||||||
|
find_args+=(-o)
|
||||||
|
fi
|
||||||
|
find_args+=(-iname "*.$ext")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
find_args+=(\) -print0)
|
||||||
|
|
||||||
|
while IFS= read -r -d '' file; do
|
||||||
|
((count++)) || true
|
||||||
|
if ! convert_video "$file"; then
|
||||||
|
((failed++)) || true
|
||||||
|
fi
|
||||||
|
done < <(find "$dir" "${find_args[@]}" 2>/dev/null)
|
||||||
|
|
||||||
|
log "Processed $count video file(s), $failed failed"
|
||||||
|
|
||||||
|
if [[ $count -eq 0 ]]; then
|
||||||
|
log "No video files found in '$dir'"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_args() {
|
||||||
|
while getopts ":f:c:p:dh" opt; do
|
||||||
|
case "$opt" in
|
||||||
|
f)
|
||||||
|
TARGET_FORMAT="${OPTARG,,}"
|
||||||
|
if [[ "$TARGET_FORMAT" != "mp4" && "$TARGET_FORMAT" != "webm" ]]; then
|
||||||
|
echo "Error: Format must be 'mp4' or 'webm'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
c) CRF="$OPTARG" ;;
|
||||||
|
p) PRESET="$OPTARG" ;;
|
||||||
|
d) DELETE_ORIGINAL=true ;;
|
||||||
|
h)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
:)
|
||||||
|
echo "Error: Option -$OPTARG requires an argument." >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
\?)
|
||||||
|
echo "Error: Invalid option -$OPTARG" >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
echo "Error: No path specified." >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET_PATH="$1"
|
||||||
|
|
||||||
|
# Set default CRF based on format if not specified
|
||||||
|
if [[ -z "$CRF" ]]; then
|
||||||
|
if [[ "$TARGET_FORMAT" == "mp4" ]]; then
|
||||||
|
CRF=23
|
||||||
|
else
|
||||||
|
CRF=30
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
ensure_ffmpeg
|
||||||
|
parse_args "$@"
|
||||||
|
|
||||||
|
if [[ ! -e "$TARGET_PATH" ]]; then
|
||||||
|
echo "Error: Path '$TARGET_PATH' does not exist." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -f "$TARGET_PATH" ]]; then
|
||||||
|
# Single file
|
||||||
|
if [[ "${TARGET_PATH,,}" == *."$TARGET_FORMAT" ]]; then
|
||||||
|
log "File '$TARGET_PATH' is already in $TARGET_FORMAT format, skipping."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if is_video_file "$TARGET_PATH"; then
|
||||||
|
convert_video "$TARGET_PATH"
|
||||||
|
else
|
||||||
|
echo "Error: '$TARGET_PATH' is not a recognized video file." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
elif [[ -d "$TARGET_PATH" ]]; then
|
||||||
|
process_directory "$TARGET_PATH"
|
||||||
|
else
|
||||||
|
echo "Error: '$TARGET_PATH' is neither a file nor a directory." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Done!"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
@ -1,117 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# pdf_to_png.sh (magick-only backend, behaves like pdf_to_image)
|
|
||||||
#
|
|
||||||
# Convert one or more PDF files to image files using ImageMagick v7 `magick`.
|
|
||||||
# Default output format is jpg, but can be changed with -f.
|
|
||||||
|
|
||||||
OUTPUT_DIR=""
|
|
||||||
OUTPUT_FORMAT="jpg"
|
|
||||||
PDF_FILES=()
|
|
||||||
|
|
||||||
log() {
|
|
||||||
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat << EOF
|
|
||||||
Usage:
|
|
||||||
$(basename "$0") [OPTIONS] PDF_FILE [PDF_FILE...]
|
|
||||||
|
|
||||||
Convert one or more PDF files to images using ImageMagick 'magick'.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-o DIR Output directory (default: current directory)
|
|
||||||
-f FORMAT Output image format (default: jpg)
|
|
||||||
-h Show this help
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
$(basename "$0") file.pdf
|
|
||||||
$(basename "$0") -f png file1.pdf file2.pdf
|
|
||||||
$(basename "$0") -o out -f webp file.pdf
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_magick() {
|
|
||||||
if ! command -v magick > /dev/null 2>&1; then
|
|
||||||
echo "Error: 'magick' (ImageMagick v7) is not installed or not in PATH." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_args() {
|
|
||||||
local opt
|
|
||||||
OUTPUT_DIR=""
|
|
||||||
OUTPUT_FORMAT="jpg"
|
|
||||||
PDF_FILES=()
|
|
||||||
|
|
||||||
while getopts ":o:f:h" opt; do
|
|
||||||
case "$opt" in
|
|
||||||
o)
|
|
||||||
OUTPUT_DIR="$OPTARG"
|
|
||||||
;;
|
|
||||||
f)
|
|
||||||
OUTPUT_FORMAT="$OPTARG"
|
|
||||||
;;
|
|
||||||
h)
|
|
||||||
usage
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
shift $((OPTIND - 1))
|
|
||||||
|
|
||||||
if [[ $# -lt 1 ]]; then
|
|
||||||
echo "Error: at least one PDF file must be specified." >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
PDF_FILES=("$@")
|
|
||||||
|
|
||||||
if [[ -z ${OUTPUT_DIR:-} ]]; then
|
|
||||||
OUTPUT_DIR="${PWD}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -d $OUTPUT_DIR ]]; then
|
|
||||||
mkdir -p "$OUTPUT_DIR"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_pdf() {
|
|
||||||
local pdf_file="$1"
|
|
||||||
local base name out_pattern
|
|
||||||
|
|
||||||
name="$(basename "$pdf_file")"
|
|
||||||
base="${name%.*}"
|
|
||||||
out_pattern="${OUTPUT_DIR%/}/${base}_page-"
|
|
||||||
|
|
||||||
log "Converting '$pdf_file' to $OUTPUT_FORMAT using magick -> ${out_pattern}*.${OUTPUT_FORMAT}"
|
|
||||||
magick -density 300 "$pdf_file" -quality 90 "${out_pattern}%d.${OUTPUT_FORMAT}"
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
ensure_magick
|
|
||||||
parse_args "$@"
|
|
||||||
|
|
||||||
local pdf
|
|
||||||
for pdf in "${PDF_FILES[@]}"; do
|
|
||||||
if [[ ! -f $pdf ]]; then
|
|
||||||
echo "Warning: '$pdf' is not a regular file, skipping." >&2
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
convert_pdf "$pdf"
|
|
||||||
done
|
|
||||||
|
|
||||||
log "Done converting PDFs to ${OUTPUT_FORMAT}. Output directory: $OUTPUT_DIR"
|
|
||||||
}
|
|
||||||
|
|
||||||
main "$@"
|
|
||||||
@ -2,34 +2,21 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Source common library
|
||||||
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
# Re-run with sudo if needed for reading /etc/hosts
|
# Re-run with sudo if needed for reading /etc/hosts
|
||||||
if [[ $EUID -ne 0 ]] && [[ ! -r /etc/hosts ]]; then
|
if [[ $EUID -ne 0 ]] && [[ ! -r /etc/hosts ]]; then
|
||||||
exec sudo -E bash "$0" "$@"
|
exec sudo -E bash "$0" "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
WORK_DIR="${HOME}/.cache/android-adblock"
|
WORK_DIR="${HOME}/.cache/android-adblock"
|
||||||
|
ensure_dir "$WORK_DIR"
|
||||||
mkdir -p "$WORK_DIR"
|
|
||||||
|
|
||||||
# Colors
|
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
NC='\033[0m'
|
|
||||||
|
|
||||||
log() {
|
|
||||||
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S%z')]${NC} $*"
|
|
||||||
}
|
|
||||||
|
|
||||||
error() {
|
|
||||||
echo -e "${RED}[ERROR]${NC} $*" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
warn() {
|
|
||||||
echo -e "${YELLOW}[WARN]${NC} $*"
|
|
||||||
}
|
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
error "$@"
|
echo "[ERROR] $*" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,194 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
# Wrapper for backward compatibility - converts to mp4
|
||||||
set -euo pipefail
|
# See convert_video.sh for full options
|
||||||
|
exec "$(dirname "$(readlink -f "$0")")/convert_video.sh" -f mp4 "$@"
|
||||||
# to_mp4.sh
|
|
||||||
#
|
|
||||||
# Convert video files (non-mp4) to mp4 format using ffmpeg.
|
|
||||||
# Accepts either a single video file or a directory (will recurse into subdirectories).
|
|
||||||
|
|
||||||
# Video extensions to search for (excluding mp4 since that's our target)
|
|
||||||
VIDEO_EXTENSIONS=("webm" "mkv" "avi" "mov" "wmv" "flv" "m4v" "mpg" "mpeg" "3gp" "ogv" "ts" "mts" "m2ts" "vob" "asf" "rm" "rmvb" "divx" "f4v")
|
|
||||||
|
|
||||||
# Conversion settings
|
|
||||||
CRF=23 # Quality (0-51, lower = better quality, 18-28 is reasonable for H.264)
|
|
||||||
PRESET="medium" # Encoding speed: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow
|
|
||||||
DELETE_ORIGINAL=false
|
|
||||||
|
|
||||||
log() {
|
|
||||||
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat <<EOF
|
|
||||||
Usage:
|
|
||||||
$(basename "$0") [OPTIONS] PATH
|
|
||||||
|
|
||||||
Convert video files to mp4 format using ffmpeg.
|
|
||||||
PATH can be a single video file or a directory (will recurse into subdirectories).
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-c CRF Quality level 0-51 (default: 23, lower = better quality)
|
|
||||||
-p PRESET Encoding preset (default: medium)
|
|
||||||
Options: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow
|
|
||||||
-d Delete original file after successful conversion
|
|
||||||
-h Show this help
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
$(basename "$0") video.webm
|
|
||||||
$(basename "$0") /path/to/videos/
|
|
||||||
$(basename "$0") -c 20 -d /path/to/videos/
|
|
||||||
$(basename "$0") -p slow -c 18 movie.mkv
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_ffmpeg() {
|
|
||||||
if ! command -v ffmpeg >/dev/null 2>&1; then
|
|
||||||
echo "Error: 'ffmpeg' is not installed or not in PATH." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
is_video_file() {
|
|
||||||
local file="$1"
|
|
||||||
local ext="${file##*.}"
|
|
||||||
ext="${ext,,}" # lowercase
|
|
||||||
|
|
||||||
for video_ext in "${VIDEO_EXTENSIONS[@]}"; do
|
|
||||||
if [[ "$ext" == "${video_ext,,}" ]]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_to_mp4() {
|
|
||||||
local input_file="$1"
|
|
||||||
local output_file="${input_file%.*}.mp4"
|
|
||||||
|
|
||||||
# Skip if output already exists
|
|
||||||
if [[ -f "$output_file" ]]; then
|
|
||||||
log "Skipping '$input_file': output '$output_file' already exists"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Converting '$input_file' -> '$output_file'"
|
|
||||||
|
|
||||||
# Use H.264 codec for video and AAC for audio (maximum compatibility)
|
|
||||||
if ffmpeg -hide_banner -loglevel warning -i "$input_file" \
|
|
||||||
-c:v libx264 -crf "$CRF" -preset "$PRESET" \
|
|
||||||
-c:a aac -b:a 192k \
|
|
||||||
-movflags +faststart \
|
|
||||||
"$output_file"; then
|
|
||||||
log "Successfully converted '$input_file'"
|
|
||||||
|
|
||||||
if [[ "$DELETE_ORIGINAL" == true ]]; then
|
|
||||||
log "Deleting original: '$input_file'"
|
|
||||||
rm "$input_file"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
log "Error converting '$input_file'"
|
|
||||||
# Remove partial output file if it exists
|
|
||||||
[[ -f "$output_file" ]] && rm "$output_file"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
process_directory() {
|
|
||||||
local dir="$1"
|
|
||||||
local count=0
|
|
||||||
local failed=0
|
|
||||||
|
|
||||||
log "Searching for video files in '$dir'..."
|
|
||||||
|
|
||||||
# Find all video files (case-insensitive)
|
|
||||||
while IFS= read -r -d '' file; do
|
|
||||||
# Skip mp4 files
|
|
||||||
if [[ "${file,,}" == *.mp4 ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
((count++)) || true
|
|
||||||
if ! convert_to_mp4 "$file"; then
|
|
||||||
((failed++)) || true
|
|
||||||
fi
|
|
||||||
done < <(find "$dir" -type f \( -iname "*.webm" -o -iname "*.mkv" -o -iname "*.avi" -o -iname "*.mov" \
|
|
||||||
-o -iname "*.wmv" -o -iname "*.flv" -o -iname "*.m4v" -o -iname "*.mpg" -o -iname "*.mpeg" \
|
|
||||||
-o -iname "*.3gp" -o -iname "*.ogv" -o -iname "*.ts" -o -iname "*.mts" -o -iname "*.m2ts" \
|
|
||||||
-o -iname "*.vob" -o -iname "*.asf" -o -iname "*.rm" -o -iname "*.rmvb" -o -iname "*.divx" \
|
|
||||||
-o -iname "*.f4v" \) -print0 2>/dev/null)
|
|
||||||
|
|
||||||
log "Processed $count video file(s), $failed failed"
|
|
||||||
|
|
||||||
if [[ $count -eq 0 ]]; then
|
|
||||||
log "No video files found in '$dir'"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_args() {
|
|
||||||
while getopts ":c:p:dh" opt; do
|
|
||||||
case "$opt" in
|
|
||||||
c) CRF="$OPTARG" ;;
|
|
||||||
p) PRESET="$OPTARG" ;;
|
|
||||||
d) DELETE_ORIGINAL=true ;;
|
|
||||||
h)
|
|
||||||
usage
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
:)
|
|
||||||
echo "Error: Option -$OPTARG requires an argument." >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
\?)
|
|
||||||
echo "Error: Invalid option -$OPTARG" >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
shift $((OPTIND - 1))
|
|
||||||
|
|
||||||
if [[ $# -lt 1 ]]; then
|
|
||||||
echo "Error: No path specified." >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
TARGET_PATH="$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
ensure_ffmpeg
|
|
||||||
parse_args "$@"
|
|
||||||
|
|
||||||
if [[ ! -e "$TARGET_PATH" ]]; then
|
|
||||||
echo "Error: Path '$TARGET_PATH' does not exist." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -f "$TARGET_PATH" ]]; then
|
|
||||||
# Single file
|
|
||||||
if [[ "${TARGET_PATH,,}" == *.mp4 ]]; then
|
|
||||||
log "File '$TARGET_PATH' is already in mp4 format, skipping."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if is_video_file "$TARGET_PATH"; then
|
|
||||||
convert_to_mp4 "$TARGET_PATH"
|
|
||||||
else
|
|
||||||
echo "Error: '$TARGET_PATH' is not a recognized video file." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
elif [[ -d "$TARGET_PATH" ]]; then
|
|
||||||
# Directory
|
|
||||||
process_directory "$TARGET_PATH"
|
|
||||||
else
|
|
||||||
echo "Error: '$TARGET_PATH' is neither a file nor a directory." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Done!"
|
|
||||||
}
|
|
||||||
|
|
||||||
main "$@"
|
|
||||||
|
|||||||
@ -1,206 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
# Wrapper for backward compatibility - converts to webm
|
||||||
set -euo pipefail
|
# See convert_video.sh for full options
|
||||||
|
exec "$(dirname "$(readlink -f "$0")")/convert_video.sh" -f webm "$@"
|
||||||
# to_webm.sh
|
|
||||||
#
|
|
||||||
# Convert video files (non-webm) to webm format using ffmpeg.
|
|
||||||
# Accepts either a single video file or a directory (will recurse into subdirectories).
|
|
||||||
|
|
||||||
# Video extensions to search for (excluding webm since that's our target)
|
|
||||||
VIDEO_EXTENSIONS=("mp4" "mkv" "avi" "mov" "wmv" "flv" "m4v" "mpg" "mpeg" "3gp" "ogv" "ts" "mts" "m2ts" "vob" "asf" "rm" "rmvb" "divx" "f4v")
|
|
||||||
|
|
||||||
# Conversion settings
|
|
||||||
CRF=30 # Quality (0-63, lower = better quality, 23-30 is reasonable)
|
|
||||||
PRESET="medium" # Encoding speed: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow
|
|
||||||
DELETE_ORIGINAL=false
|
|
||||||
|
|
||||||
log() {
|
|
||||||
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat <<EOF
|
|
||||||
Usage:
|
|
||||||
$(basename "$0") [OPTIONS] PATH
|
|
||||||
|
|
||||||
Convert video files to webm format using ffmpeg.
|
|
||||||
PATH can be a single video file or a directory (will recurse into subdirectories).
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-c CRF Quality level 0-63 (default: 30, lower = better quality)
|
|
||||||
-p PRESET Encoding preset (default: medium)
|
|
||||||
Options: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow
|
|
||||||
-d Delete original file after successful conversion
|
|
||||||
-h Show this help
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
$(basename "$0") video.mp4
|
|
||||||
$(basename "$0") /path/to/videos/
|
|
||||||
$(basename "$0") -c 25 -d /path/to/videos/
|
|
||||||
$(basename "$0") -p slow -c 20 movie.mkv
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_ffmpeg() {
|
|
||||||
if ! command -v ffmpeg >/dev/null 2>&1; then
|
|
||||||
echo "Error: 'ffmpeg' is not installed or not in PATH." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
build_extension_pattern() {
|
|
||||||
# Build a find pattern for video extensions
|
|
||||||
local pattern=""
|
|
||||||
for ext in "${VIDEO_EXTENSIONS[@]}"; do
|
|
||||||
if [[ -n "$pattern" ]]; then
|
|
||||||
pattern="$pattern -o"
|
|
||||||
fi
|
|
||||||
pattern="$pattern -iname *.$ext"
|
|
||||||
done
|
|
||||||
echo "$pattern"
|
|
||||||
}
|
|
||||||
|
|
||||||
is_video_file() {
|
|
||||||
local file="$1"
|
|
||||||
local ext="${file##*.}"
|
|
||||||
ext="${ext,,}" # lowercase
|
|
||||||
|
|
||||||
for video_ext in "${VIDEO_EXTENSIONS[@]}"; do
|
|
||||||
if [[ "$ext" == "${video_ext,,}" ]]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_to_webm() {
|
|
||||||
local input_file="$1"
|
|
||||||
local output_file="${input_file%.*}.webm"
|
|
||||||
|
|
||||||
# Skip if output already exists
|
|
||||||
if [[ -f "$output_file" ]]; then
|
|
||||||
log "Skipping '$input_file': output '$output_file' already exists"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Converting '$input_file' -> '$output_file'"
|
|
||||||
|
|
||||||
# Use VP9 codec for video and Opus for audio (good quality, wide compatibility)
|
|
||||||
if ffmpeg -hide_banner -loglevel warning -i "$input_file" \
|
|
||||||
-c:v libvpx-vp9 -crf "$CRF" -b:v 0 \
|
|
||||||
-c:a libopus -b:a 128k \
|
|
||||||
-preset "$PRESET" \
|
|
||||||
"$output_file"; then
|
|
||||||
log "Successfully converted '$input_file'"
|
|
||||||
|
|
||||||
if [[ "$DELETE_ORIGINAL" == true ]]; then
|
|
||||||
log "Deleting original: '$input_file'"
|
|
||||||
rm "$input_file"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
log "Error converting '$input_file'"
|
|
||||||
# Remove partial output file if it exists
|
|
||||||
[[ -f "$output_file" ]] && rm "$output_file"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
process_directory() {
|
|
||||||
local dir="$1"
|
|
||||||
local count=0
|
|
||||||
local failed=0
|
|
||||||
|
|
||||||
log "Searching for video files in '$dir'..."
|
|
||||||
|
|
||||||
# Find all video files (case-insensitive)
|
|
||||||
while IFS= read -r -d '' file; do
|
|
||||||
# Skip webm files
|
|
||||||
if [[ "${file,,}" == *.webm ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
((count++)) || true
|
|
||||||
if ! convert_to_webm "$file"; then
|
|
||||||
((failed++)) || true
|
|
||||||
fi
|
|
||||||
done < <(find "$dir" -type f \( -iname "*.mp4" -o -iname "*.mkv" -o -iname "*.avi" -o -iname "*.mov" \
|
|
||||||
-o -iname "*.wmv" -o -iname "*.flv" -o -iname "*.m4v" -o -iname "*.mpg" -o -iname "*.mpeg" \
|
|
||||||
-o -iname "*.3gp" -o -iname "*.ogv" -o -iname "*.ts" -o -iname "*.mts" -o -iname "*.m2ts" \
|
|
||||||
-o -iname "*.vob" -o -iname "*.asf" -o -iname "*.rm" -o -iname "*.rmvb" -o -iname "*.divx" \
|
|
||||||
-o -iname "*.f4v" \) -print0 2>/dev/null)
|
|
||||||
|
|
||||||
log "Processed $count video file(s), $failed failed"
|
|
||||||
|
|
||||||
if [[ $count -eq 0 ]]; then
|
|
||||||
log "No video files found in '$dir'"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_args() {
|
|
||||||
while getopts ":c:p:dh" opt; do
|
|
||||||
case "$opt" in
|
|
||||||
c) CRF="$OPTARG" ;;
|
|
||||||
p) PRESET="$OPTARG" ;;
|
|
||||||
d) DELETE_ORIGINAL=true ;;
|
|
||||||
h)
|
|
||||||
usage
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
:)
|
|
||||||
echo "Error: Option -$OPTARG requires an argument." >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
\?)
|
|
||||||
echo "Error: Invalid option -$OPTARG" >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
shift $((OPTIND - 1))
|
|
||||||
|
|
||||||
if [[ $# -lt 1 ]]; then
|
|
||||||
echo "Error: No path specified." >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
TARGET_PATH="$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
ensure_ffmpeg
|
|
||||||
parse_args "$@"
|
|
||||||
|
|
||||||
if [[ ! -e "$TARGET_PATH" ]]; then
|
|
||||||
echo "Error: Path '$TARGET_PATH' does not exist." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -f "$TARGET_PATH" ]]; then
|
|
||||||
# Single file
|
|
||||||
if [[ "${TARGET_PATH,,}" == *.webm ]]; then
|
|
||||||
log "File '$TARGET_PATH' is already in webm format, skipping."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if is_video_file "$TARGET_PATH"; then
|
|
||||||
convert_to_webm "$TARGET_PATH"
|
|
||||||
else
|
|
||||||
echo "Error: '$TARGET_PATH' is not a recognized video file." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
elif [[ -d "$TARGET_PATH" ]]; then
|
|
||||||
# Directory
|
|
||||||
process_directory "$TARGET_PATH"
|
|
||||||
else
|
|
||||||
echo "Error: '$TARGET_PATH' is neither a file nor a directory." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Done!"
|
|
||||||
}
|
|
||||||
|
|
||||||
main "$@"
|
|
||||||
|
|||||||
@ -2,29 +2,21 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Source common library
|
||||||
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
# Re-run with sudo if needed for reading /etc/hosts
|
# Re-run with sudo if needed for reading /etc/hosts
|
||||||
if [[ $EUID -ne 0 ]] && [[ ! -r /etc/hosts ]]; then
|
if [[ $EUID -ne 0 ]] && [[ ! -r /etc/hosts ]]; then
|
||||||
exec sudo -E bash "$0" "$@"
|
exec sudo -E bash "$0" "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
WORK_DIR="${HOME}/.cache/android-adblock"
|
WORK_DIR="${HOME}/.cache/android-adblock"
|
||||||
mkdir -p "$WORK_DIR"
|
ensure_dir "$WORK_DIR"
|
||||||
|
|
||||||
# Color codes for output
|
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
log() {
|
|
||||||
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S%z')]${NC} $*"
|
|
||||||
}
|
|
||||||
|
|
||||||
error() {
|
|
||||||
echo -e "${RED}[ERROR]${NC} $*" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
error "$@"
|
echo "[ERROR] $*" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user