mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-07-04 15:03:01 +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
e3e5002d35
commit
51fb0d6064
@ -42,8 +42,10 @@ mapfile -d '' -t staged_shell_files < <(git diff --cached --name-only --diff-fil
|
||||
|
||||
if [[ ${#staged_shell_files[@]} -gt 0 ]]; then
|
||||
# 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 ! 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 'Fix the remaining problems and retry the commit.\n' >&2
|
||||
exit 1
|
||||
@ -72,23 +74,23 @@ fi
|
||||
# Run jscpd and capture output
|
||||
# --min-lines 5: minimum 5 lines 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" \
|
||||
--pattern "**/*.sh" \
|
||||
--min-lines 5 \
|
||||
--min-tokens 25 \
|
||||
--threshold 0 \
|
||||
--threshold 2 \
|
||||
--reporters "console" \
|
||||
--ignore "**/node_modules/**,**/.git/**" \
|
||||
--ignore "**/node_modules/**,**/.git/**,**/misc/testsAndMisc-bash/**" \
|
||||
. 2>&1) || jscpd_exit=$?
|
||||
|
||||
if [[ ${jscpd_exit:-0} -ne 0 ]]; then
|
||||
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 'To see all duplicates: %s --pattern "**/*.sh" --min-lines 5 .\n' "$JSCPD_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
printf ' ✓ No duplicate code detected\n'
|
||||
printf ' ✓ Duplication check passed (under 2%% threshold)\n'
|
||||
|
||||
printf 'All checks passed. Proceeding with commit.\n'
|
||||
|
||||
@ -9,6 +9,11 @@
|
||||
|
||||
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
|
||||
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/compulsive-block"
|
||||
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)"
|
||||
|
||||
# Send notification
|
||||
if command -v notify-send &>/dev/null; then
|
||||
notify-send -u critical -t 5000 \
|
||||
"🚫 $app Blocked" \
|
||||
"Already opened this hour. Wait until the next hour." \
|
||||
2>/dev/null || true
|
||||
fi
|
||||
# Send notification using common library
|
||||
notify "🚫 $app Blocked" "Already opened this hour. Wait until the next hour." critical 5000
|
||||
}
|
||||
|
||||
# Get real binary path for an app
|
||||
|
||||
@ -9,15 +9,18 @@
|
||||
|
||||
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
|
||||
LOG_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/music-parallelism"
|
||||
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
|
||||
|
||||
# Focus applications - window class names for xdotool detection
|
||||
# Only apps with VISIBLE WINDOWS should block music
|
||||
# We use window detection, not process detection, to avoid matching background services
|
||||
# Override focus apps with extended list for this script
|
||||
FOCUS_APPS_WINDOWS=(
|
||||
# IDEs and code editors - match window titles
|
||||
"Visual Studio Code"
|
||||
@ -40,13 +43,6 @@ FOCUS_APPS_WINDOWS=(
|
||||
"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
|
||||
# These will be killed when focus apps are detected
|
||||
MUSIC_SERVICES=(
|
||||
@ -73,38 +69,6 @@ MUSIC_SERVICES=(
|
||||
"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
|
||||
find_music_services() {
|
||||
local found_services=()
|
||||
|
||||
@ -5,205 +5,175 @@
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
# Default to non-interactive mode
|
||||
INTERACTIVE_MODE=false
|
||||
# Source common library for shared functions
|
||||
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
# shellcheck source=../lib/common.sh
|
||||
source "$SCRIPT_DIR/../lib/common.sh"
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-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
|
||||
# Parse interactive/help arguments
|
||||
parse_interactive_args "$@"
|
||||
shift "$COMMON_ARGS_SHIFT"
|
||||
|
||||
echo "PC Startup Time Monitor for Arch Linux"
|
||||
echo "======================================"
|
||||
echo "Current Date: $(date)"
|
||||
echo "User: ${SUDO_USER:-$USER}"
|
||||
echo "User: $(get_actual_user)"
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
echo "Mode: Interactive (prompts enabled)"
|
||||
echo "Mode: Interactive (prompts enabled)"
|
||||
else
|
||||
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
||||
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
||||
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)
|
||||
if [[ -n $SUDO_USER ]]; then
|
||||
ACTUAL_USER="$SUDO_USER"
|
||||
USER_HOME="/home/$SUDO_USER"
|
||||
else
|
||||
ACTUAL_USER="$USER"
|
||||
USER_HOME="$HOME"
|
||||
fi
|
||||
ACTUAL_USER="$(get_actual_user)"
|
||||
USER_HOME="$(get_actual_user_home)"
|
||||
|
||||
echo "Target user: $ACTUAL_USER"
|
||||
echo "User home: $USER_HOME"
|
||||
|
||||
# Function to check if today is a monitored day
|
||||
is_monitored_day() {
|
||||
local day_of_week
|
||||
day_of_week=$(date +%u) # 1=Monday, 7=Sunday
|
||||
local day_of_week
|
||||
day_of_week=$(date +%u) # 1=Monday, 7=Sunday
|
||||
|
||||
# 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
|
||||
return 0 # Yes, it's a monitored day
|
||||
else
|
||||
return 1 # No, it's not a monitored day
|
||||
fi
|
||||
# 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
|
||||
return 0 # Yes, it's a monitored day
|
||||
else
|
||||
return 1 # No, it's not a monitored day
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check if current time is between 5AM and 8AM
|
||||
is_current_time_in_window() {
|
||||
local current_hour current_hour_num
|
||||
current_hour=$(date +%H)
|
||||
current_hour_num=$((10#$current_hour)) # Convert to decimal to avoid octal issues
|
||||
local current_hour current_hour_num
|
||||
current_hour=$(date +%H)
|
||||
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
|
||||
return 0 # Yes, current time is in the 5AM-8AM window
|
||||
else
|
||||
return 1 # No, current time is outside the window
|
||||
fi
|
||||
if [[ $current_hour_num -ge 5 ]] && [[ $current_hour_num -lt 8 ]]; then
|
||||
return 0 # Yes, current time is in the 5AM-8AM window
|
||||
else
|
||||
return 1 # No, current time is outside the window
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check if PC was booted between 5AM-8AM today
|
||||
was_booted_in_window_today() {
|
||||
local today boot_time
|
||||
today=$(date +%Y-%m-%d)
|
||||
boot_time=""
|
||||
local today boot_time
|
||||
today=$(date +%Y-%m-%d)
|
||||
boot_time=""
|
||||
|
||||
# Get the last boot time using multiple methods for reliability
|
||||
if command -v uptime &> /dev/null; then
|
||||
# Method 1: Calculate boot time from uptime
|
||||
local uptime_seconds
|
||||
uptime_seconds=$(awk '{print int($1)}' /proc/uptime 2> /dev/null || echo "0")
|
||||
if [[ $uptime_seconds -gt 0 ]]; then
|
||||
boot_time=$(date -d "@$(($(date +%s) - uptime_seconds))" +"%Y-%m-%d %H:%M:%S")
|
||||
fi
|
||||
fi
|
||||
# Get the last boot time using multiple methods for reliability
|
||||
if command -v uptime &>/dev/null; then
|
||||
# Method 1: Calculate boot time from uptime
|
||||
local uptime_seconds
|
||||
uptime_seconds=$(awk '{print int($1)}' /proc/uptime 2>/dev/null || echo "0")
|
||||
if [[ $uptime_seconds -gt 0 ]]; then
|
||||
boot_time=$(date -d "@$(($(date +%s) - uptime_seconds))" +"%Y-%m-%d %H:%M:%S")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Method 2: Use systemd if available (fallback)
|
||||
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 "")
|
||||
if [[ -n $boot_time ]]; then
|
||||
# This gives us relative time, need to calculate absolute time
|
||||
local current_time uptime_sec
|
||||
current_time=$(date +%s)
|
||||
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")
|
||||
fi
|
||||
fi
|
||||
# Method 2: Use systemd if available (fallback)
|
||||
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 "")
|
||||
if [[ -n $boot_time ]]; then
|
||||
# This gives us relative time, need to calculate absolute time
|
||||
local current_time uptime_sec
|
||||
current_time=$(date +%s)
|
||||
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")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Method 3: Use who -b (fallback)
|
||||
if [[ -z $boot_time ]] && command -v who &> /dev/null; then
|
||||
boot_time=$(who -b | awk '{print $3, $4}' 2> /dev/null || echo "")
|
||||
if [[ -n $boot_time ]]; then
|
||||
boot_time="$today $boot_time"
|
||||
fi
|
||||
fi
|
||||
# Method 3: Use who -b (fallback)
|
||||
if [[ -z $boot_time ]] && command -v who &>/dev/null; then
|
||||
boot_time=$(who -b | awk '{print $3, $4}' 2>/dev/null || echo "")
|
||||
if [[ -n $boot_time ]]; then
|
||||
boot_time="$today $boot_time"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Method 4: Use /proc/uptime as final fallback
|
||||
if [[ -z $boot_time ]]; then
|
||||
local uptime_seconds
|
||||
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")
|
||||
fi
|
||||
# Method 4: Use /proc/uptime as final fallback
|
||||
if [[ -z $boot_time ]]; then
|
||||
local uptime_seconds
|
||||
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")
|
||||
fi
|
||||
|
||||
echo "Boot time detected: $boot_time"
|
||||
echo "Boot time detected: $boot_time"
|
||||
|
||||
# Check if boot time is from today
|
||||
local boot_date
|
||||
boot_date=$(echo "$boot_time" | cut -d' ' -f1)
|
||||
if [[ $boot_date != "$today" ]]; then
|
||||
echo "PC was not booted today (boot date: $boot_date, today: $today)"
|
||||
return 1 # Not booted today
|
||||
fi
|
||||
# Check if boot time is from today
|
||||
local boot_date
|
||||
boot_date=$(echo "$boot_time" | cut -d' ' -f1)
|
||||
if [[ $boot_date != "$today" ]]; then
|
||||
echo "PC was not booted today (boot date: $boot_date, today: $today)"
|
||||
return 1 # Not booted today
|
||||
fi
|
||||
|
||||
# Extract hour from boot time
|
||||
local boot_hour boot_hour_num
|
||||
boot_hour=$(echo "$boot_time" | cut -d' ' -f2 | cut -d':' -f1)
|
||||
boot_hour_num=$((10#$boot_hour)) # Convert to decimal
|
||||
# Extract hour from boot time
|
||||
local boot_hour boot_hour_num
|
||||
boot_hour=$(echo "$boot_time" | cut -d' ' -f2 | cut -d':' -f1)
|
||||
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)
|
||||
if [[ $boot_hour_num -ge 5 ]] && [[ $boot_hour_num -lt 8 ]]; then
|
||||
echo "PC was booted in the expected window (5AM-8AM)"
|
||||
return 0 # Yes, booted in window
|
||||
else
|
||||
echo "PC was NOT booted in the expected window (5AM-8AM)"
|
||||
return 1 # No, not booted in window
|
||||
fi
|
||||
# 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
|
||||
echo "PC was booted in the expected window (5AM-8AM)"
|
||||
return 0 # Yes, booted in window
|
||||
else
|
||||
echo "PC was NOT booted in the expected window (5AM-8AM)"
|
||||
return 1 # No, not booted in window
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to show notification/warning
|
||||
show_startup_warning() {
|
||||
local day_name current_time today
|
||||
day_name=$(date +%A)
|
||||
current_time=$(date +"%H:%M")
|
||||
today=$(date +%Y-%m-%d)
|
||||
local day_name current_time today
|
||||
day_name=$(date +%A)
|
||||
current_time=$(date +"%H:%M")
|
||||
today=$(date +%Y-%m-%d)
|
||||
|
||||
echo ""
|
||||
echo "⚠️ PC STARTUP TIME WARNING"
|
||||
echo "=========================="
|
||||
echo "Date: $today ($day_name)"
|
||||
echo "Current time: $current_time"
|
||||
echo ""
|
||||
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 ""
|
||||
echo "Expected: Monday, Friday, Saturday, Sunday between 5:00-8:00 AM"
|
||||
echo "Actual: PC was turned on outside the expected window"
|
||||
echo ""
|
||||
echo ""
|
||||
echo "⚠️ PC STARTUP TIME WARNING"
|
||||
echo "=========================="
|
||||
echo "Date: $today ($day_name)"
|
||||
echo "Current time: $current_time"
|
||||
echo ""
|
||||
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 ""
|
||||
echo "Expected: Monday, Friday, Saturday, Sunday between 5:00-8:00 AM"
|
||||
echo "Actual: PC was turned on outside the expected window"
|
||||
echo ""
|
||||
|
||||
# Log the warning
|
||||
logger -t pc-startup-monitor "WARNING: PC was not turned on during expected window (5AM-8AM) on $day_name $today"
|
||||
# Log the warning
|
||||
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
|
||||
if command -v notify-send &> /dev/null && [[ -n $DISPLAY ]]; then
|
||||
if [[ $EUID -eq 0 ]]; then
|
||||
# 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
|
||||
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
|
||||
fi
|
||||
fi
|
||||
# Try to show desktop notification if possible
|
||||
if command -v notify-send &>/dev/null && [[ -n $DISPLAY ]]; then
|
||||
if [[ $EUID -eq 0 ]]; then
|
||||
# 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
|
||||
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
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "This warning has been logged to the system journal."
|
||||
echo "You can view startup logs with: journalctl -t pc-startup-monitor"
|
||||
echo ""
|
||||
echo "This warning has been logged to the system journal."
|
||||
echo "You can view startup logs with: journalctl -t pc-startup-monitor"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Function to create the monitoring service
|
||||
create_monitoring_service() {
|
||||
echo ""
|
||||
echo "1. Creating PC Startup Monitor Service..."
|
||||
echo "======================================="
|
||||
echo ""
|
||||
echo "1. Creating PC Startup Monitor Service..."
|
||||
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]
|
||||
Description=PC Startup Time Monitor
|
||||
After=multi-user.target
|
||||
@ -220,18 +190,18 @@ RemainAfterExit=true
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
echo "✓ Created monitoring service: $service_file"
|
||||
echo "✓ Created monitoring service: $service_file"
|
||||
}
|
||||
|
||||
# Function to create the monitoring timer
|
||||
create_monitoring_timer() {
|
||||
echo ""
|
||||
echo "2. Creating PC Startup Monitor Timer..."
|
||||
echo "====================================="
|
||||
echo ""
|
||||
echo "2. Creating PC Startup Monitor Timer..."
|
||||
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]
|
||||
Description=Timer for PC startup monitoring
|
||||
Requires=pc-startup-monitor.service
|
||||
@ -245,18 +215,18 @@ AccuracySec=1m
|
||||
WantedBy=timers.target
|
||||
EOF
|
||||
|
||||
echo "✓ Created monitoring timer: $timer_file"
|
||||
echo "✓ Created monitoring timer: $timer_file"
|
||||
}
|
||||
|
||||
# Function to create the main monitoring script
|
||||
create_monitoring_script() {
|
||||
echo ""
|
||||
echo "3. Creating PC Startup Monitor Script..."
|
||||
echo "======================================"
|
||||
echo ""
|
||||
echo "3. Creating PC Startup Monitor Script..."
|
||||
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
|
||||
# PC Startup Time Monitor Check Script
|
||||
# Monitors if PC was turned on during expected hours on specific days
|
||||
@ -362,19 +332,19 @@ else
|
||||
fi
|
||||
EOF
|
||||
|
||||
chmod +x "$script_file"
|
||||
echo "✓ Created monitoring script: $script_file"
|
||||
chmod +x "$script_file"
|
||||
echo "✓ Created monitoring script: $script_file"
|
||||
}
|
||||
|
||||
# Function to create management script
|
||||
create_management_script() {
|
||||
echo ""
|
||||
echo "4. Creating Management Script..."
|
||||
echo "=============================="
|
||||
echo ""
|
||||
echo "4. Creating Management Script..."
|
||||
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
|
||||
# PC Startup Monitor Manager
|
||||
# Provides easy management of the PC startup monitoring feature
|
||||
@ -437,150 +407,150 @@ case "$1" in
|
||||
esac
|
||||
EOF
|
||||
|
||||
chmod +x "$script_file"
|
||||
echo "✓ Created management script: $script_file"
|
||||
chmod +x "$script_file"
|
||||
echo "✓ Created management script: $script_file"
|
||||
}
|
||||
|
||||
# Function to enable the services
|
||||
enable_services() {
|
||||
echo ""
|
||||
echo "5. Enabling PC Startup Monitor..."
|
||||
echo "==============================="
|
||||
echo ""
|
||||
echo "5. Enabling PC Startup Monitor..."
|
||||
echo "==============================="
|
||||
|
||||
# Reload systemd daemon
|
||||
systemctl daemon-reload
|
||||
echo "✓ Reloaded systemd daemon"
|
||||
# Reload systemd daemon
|
||||
systemctl daemon-reload
|
||||
echo "✓ Reloaded systemd daemon"
|
||||
|
||||
# Enable and start the timer
|
||||
systemctl enable pc-startup-monitor.timer
|
||||
echo "✓ Enabled pc-startup-monitor timer"
|
||||
# Enable and start the timer
|
||||
systemctl enable pc-startup-monitor.timer
|
||||
echo "✓ Enabled pc-startup-monitor timer"
|
||||
|
||||
systemctl start pc-startup-monitor.timer
|
||||
echo "✓ Started pc-startup-monitor timer"
|
||||
systemctl start pc-startup-monitor.timer
|
||||
echo "✓ Started pc-startup-monitor timer"
|
||||
}
|
||||
|
||||
# Function to test the setup
|
||||
test_setup() {
|
||||
echo ""
|
||||
echo "6. Testing Setup..."
|
||||
echo "=================="
|
||||
echo ""
|
||||
echo "6. Testing Setup..."
|
||||
echo "=================="
|
||||
|
||||
echo "Service files:"
|
||||
if [[ -f "/etc/systemd/system/pc-startup-monitor.service" ]]; then
|
||||
echo "✓ Service file exists"
|
||||
else
|
||||
echo "✗ Service file missing"
|
||||
fi
|
||||
echo "Service files:"
|
||||
if [[ -f "/etc/systemd/system/pc-startup-monitor.service" ]]; then
|
||||
echo "✓ Service file exists"
|
||||
else
|
||||
echo "✗ Service file missing"
|
||||
fi
|
||||
|
||||
if [[ -f "/etc/systemd/system/pc-startup-monitor.timer" ]]; then
|
||||
echo "✓ Timer file exists"
|
||||
else
|
||||
echo "✗ Timer file missing"
|
||||
fi
|
||||
if [[ -f "/etc/systemd/system/pc-startup-monitor.timer" ]]; then
|
||||
echo "✓ Timer file exists"
|
||||
else
|
||||
echo "✗ Timer file missing"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Timer status:"
|
||||
if systemctl is-enabled pc-startup-monitor.timer &> /dev/null; then
|
||||
echo "✓ Timer is enabled"
|
||||
else
|
||||
echo "✗ Timer is not enabled"
|
||||
fi
|
||||
echo ""
|
||||
echo "Timer status:"
|
||||
if systemctl is-enabled pc-startup-monitor.timer &>/dev/null; then
|
||||
echo "✓ Timer is enabled"
|
||||
else
|
||||
echo "✗ Timer is not enabled"
|
||||
fi
|
||||
|
||||
if systemctl is-active pc-startup-monitor.timer &> /dev/null; then
|
||||
echo "✓ Timer is active"
|
||||
else
|
||||
echo "✗ Timer is not active"
|
||||
fi
|
||||
if systemctl is-active pc-startup-monitor.timer &>/dev/null; then
|
||||
echo "✓ Timer is active"
|
||||
else
|
||||
echo "✗ Timer is not active"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Testing current logic:"
|
||||
/usr/local/bin/pc-startup-check.sh
|
||||
echo ""
|
||||
echo "Testing current logic:"
|
||||
/usr/local/bin/pc-startup-check.sh
|
||||
}
|
||||
|
||||
# Function to show final instructions
|
||||
show_instructions() {
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "PC Startup Monitor Setup Complete"
|
||||
echo "=========================================="
|
||||
echo "Summary:"
|
||||
echo "✓ Monitoring service created (/etc/systemd/system/pc-startup-monitor.service)"
|
||||
echo "✓ Monitoring timer created (/etc/systemd/system/pc-startup-monitor.timer)"
|
||||
echo "✓ Monitor script created (/usr/local/bin/pc-startup-check.sh)"
|
||||
echo "✓ Management script created (/usr/local/bin/pc-startup-monitor-manager.sh)"
|
||||
echo "✓ Timer enabled and started"
|
||||
echo ""
|
||||
echo "How it works:"
|
||||
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 "• 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 ""
|
||||
echo "Management commands:"
|
||||
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 test - Test monitor now"
|
||||
echo ""
|
||||
echo "Next check: Tomorrow at 8:30 AM (if it's a monitored day)"
|
||||
echo ""
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "PC Startup Monitor Setup Complete"
|
||||
echo "=========================================="
|
||||
echo "Summary:"
|
||||
echo "✓ Monitoring service created (/etc/systemd/system/pc-startup-monitor.service)"
|
||||
echo "✓ Monitoring timer created (/etc/systemd/system/pc-startup-monitor.timer)"
|
||||
echo "✓ Monitor script created (/usr/local/bin/pc-startup-check.sh)"
|
||||
echo "✓ Management script created (/usr/local/bin/pc-startup-monitor-manager.sh)"
|
||||
echo "✓ Timer enabled and started"
|
||||
echo ""
|
||||
echo "How it works:"
|
||||
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 "• 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 ""
|
||||
echo "Management commands:"
|
||||
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 test - Test monitor now"
|
||||
echo ""
|
||||
echo "Next check: Tomorrow at 8:30 AM (if it's a monitored day)"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Function to prompt for confirmation
|
||||
confirm_setup() {
|
||||
echo ""
|
||||
echo "PC Startup Monitor Setup"
|
||||
echo "======================="
|
||||
echo "This will set up monitoring for PC startup times."
|
||||
echo ""
|
||||
echo "Monitoring schedule:"
|
||||
echo "- Days: Monday, Friday, Saturday, Sunday"
|
||||
echo "- Expected startup time: 5:00 AM - 8:00 AM"
|
||||
echo "- Check time: 8:30 AM daily"
|
||||
echo "- Action: Show warning if PC wasn't started in expected window"
|
||||
echo ""
|
||||
echo ""
|
||||
echo "PC Startup Monitor Setup"
|
||||
echo "======================="
|
||||
echo "This will set up monitoring for PC startup times."
|
||||
echo ""
|
||||
echo "Monitoring schedule:"
|
||||
echo "- Days: Monday, Friday, Saturday, Sunday"
|
||||
echo "- Expected startup time: 5:00 AM - 8:00 AM"
|
||||
echo "- Check time: 8:30 AM daily"
|
||||
echo "- Action: Show warning if PC wasn't started in expected window"
|
||||
echo ""
|
||||
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
read -r -p "Do you want to proceed? (y/N): " confirm
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
read -r -p "Do you want to proceed? (y/N): " confirm
|
||||
|
||||
case "$confirm" in
|
||||
[yY] | [yY][eE][sS])
|
||||
echo "Proceeding with setup..."
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
echo "Setup cancelled."
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "Auto-proceeding with setup (use --interactive to prompt)"
|
||||
echo "Proceeding with setup..."
|
||||
return 0
|
||||
fi
|
||||
case "$confirm" in
|
||||
[yY] | [yY][eE][sS])
|
||||
echo "Proceeding with setup..."
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
echo "Setup cancelled."
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "Auto-proceeding with setup (use --interactive to prompt)"
|
||||
echo "Proceeding with setup..."
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution flow
|
||||
main() {
|
||||
# Check for sudo privileges
|
||||
check_sudo "$@"
|
||||
# Check for sudo privileges
|
||||
check_sudo "$@"
|
||||
|
||||
# Confirm setup
|
||||
confirm_setup
|
||||
# Confirm setup
|
||||
confirm_setup
|
||||
|
||||
# Create all components
|
||||
create_monitoring_service
|
||||
create_monitoring_timer
|
||||
create_monitoring_script
|
||||
create_management_script
|
||||
# Create all components
|
||||
create_monitoring_service
|
||||
create_monitoring_timer
|
||||
create_monitoring_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
|
||||
|
||||
@ -4,66 +4,17 @@
|
||||
|
||||
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"
|
||||
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
|
||||
if focus_app=$(is_focus_app_running); then
|
||||
log_message "BLOCKED: YouTube Music launch prevented (focus app: $focus_app)"
|
||||
notify-send -u normal -t 3000 "🚫 YouTube Music Blocked" "Focus mode active ($focus_app)" 2>/dev/null || true
|
||||
log_message "BLOCKED: YouTube Music launch prevented (focus app: $focus_app)" "$LOG_FILE"
|
||||
notify "🚫 YouTube Music Blocked" "Focus mode active ($focus_app)" normal 3000
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@ -5,57 +5,32 @@
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
# Default to non-interactive mode
|
||||
INTERACTIVE_MODE=false
|
||||
# Source common library for shared functions
|
||||
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
# shellcheck source=../lib/common.sh
|
||||
source "$SCRIPT_DIR/../lib/common.sh"
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-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
|
||||
# Parse interactive/help arguments
|
||||
parse_interactive_args "$@"
|
||||
shift "$COMMON_ARGS_SHIFT"
|
||||
|
||||
# Function to check and request sudo privileges
|
||||
check_sudo() {
|
||||
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 "$@"
|
||||
# Check for sudo privileges
|
||||
require_root "$@"
|
||||
|
||||
echo "NVIDIA Comprehensive Troubleshooter & GSP Disabler"
|
||||
echo "=================================================="
|
||||
echo "Current Date: $(date)"
|
||||
echo "User: $USER"
|
||||
echo "Original user: ${SUDO_USER:-$USER}"
|
||||
echo "Original user: $(get_actual_user)"
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
echo "Mode: Interactive (prompts enabled)"
|
||||
echo "Mode: Interactive (prompts enabled)"
|
||||
else
|
||||
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
||||
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
||||
fi
|
||||
|
||||
# Check if nvidia module is loaded
|
||||
if ! lsmod | grep -q nvidia; then
|
||||
echo "Warning: NVIDIA module not currently loaded"
|
||||
echo "Warning: NVIDIA module not currently loaded"
|
||||
fi
|
||||
|
||||
# Create modprobe configuration directory if it doesn't exist
|
||||
@ -68,7 +43,7 @@ echo "======================================"
|
||||
mkdir -p "$MODPROBE_DIR"
|
||||
|
||||
# Create the configuration file
|
||||
cat > "$CONFIG_FILE" << EOF
|
||||
cat >"$CONFIG_FILE" <<EOF
|
||||
# Disable NVIDIA GSP firmware to prevent Vulkan failures and crashes
|
||||
# Created by nvidia_troubleshoot.sh on $(date)
|
||||
options nvidia NVreg_EnableGpuFirmware=0
|
||||
@ -78,32 +53,32 @@ echo "✓ Configuration written to: $CONFIG_FILE"
|
||||
|
||||
# Function to backup file if it exists
|
||||
backup_file() {
|
||||
local file="$1"
|
||||
if [[ -f $file ]]; then
|
||||
cp "$file" "$file.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
echo "✓ Backed up $file"
|
||||
fi
|
||||
local file="$1"
|
||||
if [[ -f $file ]]; then
|
||||
cp "$file" "$file.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
echo "✓ Backed up $file"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to add or update xorg.conf for RenderAccel
|
||||
configure_xorg() {
|
||||
echo ""
|
||||
echo "2. Configuring Xorg Settings..."
|
||||
echo "==============================="
|
||||
echo ""
|
||||
echo "2. Configuring Xorg Settings..."
|
||||
echo "==============================="
|
||||
|
||||
XORG_CONF="/etc/X11/xorg.conf"
|
||||
XORG_CONF_D="/etc/X11/xorg.conf.d"
|
||||
NVIDIA_CONF="$XORG_CONF_D/20-nvidia.conf"
|
||||
XORG_CONF="/etc/X11/xorg.conf"
|
||||
XORG_CONF_D="/etc/X11/xorg.conf.d"
|
||||
NVIDIA_CONF="$XORG_CONF_D/20-nvidia.conf"
|
||||
|
||||
# Create xorg.conf.d directory if it doesn't exist
|
||||
mkdir -p "$XORG_CONF_D"
|
||||
# Create xorg.conf.d directory if it doesn't exist
|
||||
mkdir -p "$XORG_CONF_D"
|
||||
|
||||
# Backup existing xorg.conf if it exists
|
||||
backup_file "$XORG_CONF"
|
||||
backup_file "$NVIDIA_CONF"
|
||||
# Backup existing xorg.conf if it exists
|
||||
backup_file "$XORG_CONF"
|
||||
backup_file "$NVIDIA_CONF"
|
||||
|
||||
# Create NVIDIA-specific configuration
|
||||
cat > "$NVIDIA_CONF" << EOF
|
||||
# Create NVIDIA-specific configuration
|
||||
cat >"$NVIDIA_CONF" <<EOF
|
||||
# NVIDIA configuration with RenderAccel disabled
|
||||
# Created by nvidia_troubleshoot.sh on $(date)
|
||||
Section "Device"
|
||||
@ -113,106 +88,106 @@ Section "Device"
|
||||
EndSection
|
||||
EOF
|
||||
|
||||
echo "✓ Created $NVIDIA_CONF with RenderAccel disabled"
|
||||
echo "✓ Created $NVIDIA_CONF with RenderAccel disabled"
|
||||
}
|
||||
|
||||
# Function to add GCC mismatch workaround
|
||||
configure_gcc_workaround() {
|
||||
echo ""
|
||||
echo "3. Configuring GCC Mismatch Workaround..."
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "3. Configuring GCC Mismatch Workaround..."
|
||||
echo "=========================================="
|
||||
|
||||
local PROFILE_FILE="/etc/profile"
|
||||
local timestamp
|
||||
timestamp=$(date)
|
||||
backup_file "$PROFILE_FILE"
|
||||
local PROFILE_FILE="/etc/profile"
|
||||
local timestamp
|
||||
timestamp=$(date)
|
||||
backup_file "$PROFILE_FILE"
|
||||
|
||||
# Check if IGNORE_CC_MISMATCH is already set
|
||||
if ! grep -q "IGNORE_CC_MISMATCH" "$PROFILE_FILE"; then
|
||||
{
|
||||
printf '\n'
|
||||
printf '# NVIDIA GCC version mismatch workaround\n'
|
||||
printf '# Added by nvidia_troubleshoot.sh on %s\n' "$timestamp"
|
||||
printf 'export IGNORE_CC_MISMATCH=1\n'
|
||||
} >> "$PROFILE_FILE"
|
||||
echo "✓ Added IGNORE_CC_MISMATCH=1 to $PROFILE_FILE"
|
||||
else
|
||||
echo "✓ IGNORE_CC_MISMATCH already configured in $PROFILE_FILE"
|
||||
fi
|
||||
# Check if IGNORE_CC_MISMATCH is already set
|
||||
if ! grep -q "IGNORE_CC_MISMATCH" "$PROFILE_FILE"; then
|
||||
{
|
||||
printf '\n'
|
||||
printf '# NVIDIA GCC version mismatch workaround\n'
|
||||
printf '# Added by nvidia_troubleshoot.sh on %s\n' "$timestamp"
|
||||
printf 'export IGNORE_CC_MISMATCH=1\n'
|
||||
} >>"$PROFILE_FILE"
|
||||
echo "✓ Added IGNORE_CC_MISMATCH=1 to $PROFILE_FILE"
|
||||
else
|
||||
echo "✓ IGNORE_CC_MISMATCH already configured in $PROFILE_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to install pyroveil for mesh shader issues
|
||||
install_pyroveil() {
|
||||
echo ""
|
||||
echo "4. Pyroveil Setup for Mesh Shader Issues..."
|
||||
echo "==========================================="
|
||||
echo ""
|
||||
echo "4. Pyroveil Setup for Mesh Shader Issues..."
|
||||
echo "==========================================="
|
||||
|
||||
local user_home="/home/$SUDO_USER"
|
||||
local pyroveil_dir="$user_home/pyroveil"
|
||||
local user_home="/home/$SUDO_USER"
|
||||
local pyroveil_dir="$user_home/pyroveil"
|
||||
|
||||
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 ""
|
||||
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 ""
|
||||
|
||||
local install_pyroveil=true
|
||||
local install_pyroveil=true
|
||||
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
read -p "Would you like to install Pyroveil? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
install_pyroveil=false
|
||||
fi
|
||||
else
|
||||
echo "Auto-installing Pyroveil (use --interactive to prompt)"
|
||||
fi
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
read -p "Would you like to install Pyroveil? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
install_pyroveil=false
|
||||
fi
|
||||
else
|
||||
echo "Auto-installing Pyroveil (use --interactive to prompt)"
|
||||
fi
|
||||
|
||||
if [[ $install_pyroveil == "true" ]]; then
|
||||
# Check for required dependencies
|
||||
local missing_deps=()
|
||||
if [[ $install_pyroveil == "true" ]]; then
|
||||
# Check for required dependencies
|
||||
local missing_deps=()
|
||||
|
||||
for dep in git cmake ninja gcc; do
|
||||
if ! command -v "$dep" &> /dev/null; then
|
||||
missing_deps+=("$dep")
|
||||
fi
|
||||
done
|
||||
for dep in git cmake ninja gcc; do
|
||||
if ! command -v "$dep" &>/dev/null; then
|
||||
missing_deps+=("$dep")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#missing_deps[@]} -gt 0 ]]; then
|
||||
echo "Missing dependencies: ${missing_deps[*]}"
|
||||
echo "Please install them first. On Arch Linux:"
|
||||
echo "pacman -S base-devel git cmake ninja"
|
||||
return 1
|
||||
fi
|
||||
if [[ ${#missing_deps[@]} -gt 0 ]]; then
|
||||
echo "Missing dependencies: ${missing_deps[*]}"
|
||||
echo "Please install them first. On Arch Linux:"
|
||||
echo "pacman -S base-devel git cmake ninja"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Clone and build pyroveil as the original user
|
||||
echo "Installing Pyroveil to $pyroveil_dir..."
|
||||
# Clone and build pyroveil as the original user
|
||||
echo "Installing Pyroveil to $pyroveil_dir..."
|
||||
|
||||
if [[ -d $pyroveil_dir ]]; then
|
||||
echo "Pyroveil directory already exists. Updating..."
|
||||
sudo -u "$SUDO_USER" bash -c "cd '$pyroveil_dir' && git pull"
|
||||
else
|
||||
sudo -u "$SUDO_USER" git clone https://github.com/HansKristian-Work/pyroveil.git "$pyroveil_dir"
|
||||
fi
|
||||
if [[ -d $pyroveil_dir ]]; then
|
||||
echo "Pyroveil directory already exists. Updating..."
|
||||
sudo -u "$SUDO_USER" bash -c "cd '$pyroveil_dir' && git pull"
|
||||
else
|
||||
sudo -u "$SUDO_USER" git clone https://github.com/HansKristian-Work/pyroveil.git "$pyroveil_dir"
|
||||
fi
|
||||
|
||||
sudo -u "$SUDO_USER" bash -c "
|
||||
sudo -u "$SUDO_USER" bash -c "
|
||||
cd '$pyroveil_dir'
|
||||
git submodule update --init
|
||||
cmake . -Bbuild -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$user_home/.local
|
||||
ninja -C build install
|
||||
"
|
||||
|
||||
echo "✓ Pyroveil installed successfully"
|
||||
echo ""
|
||||
echo "To use Pyroveil with games that have mesh shader issues:"
|
||||
echo "1. For Final Fantasy VII Rebirth:"
|
||||
echo " PYROVEIL=1 PYROVEIL_CONFIG=$pyroveil_dir/hacks/ffvii-rebirth-nvidia/pyroveil.json %command%"
|
||||
echo ""
|
||||
echo "2. For Steam games, add to launch options:"
|
||||
echo " PYROVEIL=1 PYROVEIL_CONFIG=/path/to/config/pyroveil.json %command%"
|
||||
echo ""
|
||||
echo "Available configs in: $pyroveil_dir/hacks/"
|
||||
echo "✓ Pyroveil installed successfully"
|
||||
echo ""
|
||||
echo "To use Pyroveil with games that have mesh shader issues:"
|
||||
echo "1. For Final Fantasy VII Rebirth:"
|
||||
echo " PYROVEIL=1 PYROVEIL_CONFIG=$pyroveil_dir/hacks/ffvii-rebirth-nvidia/pyroveil.json %command%"
|
||||
echo ""
|
||||
echo "2. For Steam games, add to launch options:"
|
||||
echo " PYROVEIL=1 PYROVEIL_CONFIG=/path/to/config/pyroveil.json %command%"
|
||||
echo ""
|
||||
echo "Available configs in: $pyroveil_dir/hacks/"
|
||||
|
||||
# Create a helper script
|
||||
cat > "$user_home/run-with-pyroveil.sh" << EOF
|
||||
# Create a helper script
|
||||
cat >"$user_home/run-with-pyroveil.sh" <<EOF
|
||||
#!/bin/bash
|
||||
# Helper script to run games with Pyroveil
|
||||
# Usage: ./run-with-pyroveil.sh <config-name> <command>
|
||||
@ -238,88 +213,88 @@ echo "Config file: \$PYROVEIL_CONFIG"
|
||||
exec "\$@"
|
||||
EOF
|
||||
|
||||
chown "$SUDO_USER:$SUDO_USER" "$user_home/run-with-pyroveil.sh"
|
||||
chmod +x "$user_home/run-with-pyroveil.sh"
|
||||
echo "✓ Created helper script: $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"
|
||||
echo "✓ Created helper script: $user_home/run-with-pyroveil.sh"
|
||||
|
||||
else
|
||||
echo "Skipping Pyroveil installation"
|
||||
echo "Note: You can manually install it later for mesh shader issues"
|
||||
fi
|
||||
else
|
||||
echo "Skipping Pyroveil installation"
|
||||
echo "Note: You can manually install it later for mesh shader issues"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check for kernel parameter modifications
|
||||
suggest_kernel_params() {
|
||||
echo ""
|
||||
echo "5. Kernel Parameter Recommendations..."
|
||||
echo "====================================="
|
||||
echo ""
|
||||
echo "5. Kernel Parameter Recommendations..."
|
||||
echo "====================================="
|
||||
|
||||
echo "NVIDIA Driver Issues and Recommended Kernel Parameters:"
|
||||
echo ""
|
||||
echo "A) For 'conflicting memory type' or 'failed to allocate primary buffer' errors"
|
||||
echo " (especially with nvidia-96xx drivers):"
|
||||
echo " → Add 'nopat' to kernel parameters"
|
||||
echo ""
|
||||
echo "B) For OpenGL visual glitches, hangs, and errors with modern CPUs:"
|
||||
echo " → Consider disabling micro-op cache in BIOS settings"
|
||||
echo " → This affects Intel Sandy Bridge (2011+) and AMD Zen (2017+) CPUs"
|
||||
echo " → Helps with severe graphical glitches in Xwayland applications"
|
||||
echo " → Note: Disabling micro-op cache reduces CPU performance"
|
||||
echo ""
|
||||
echo "To add kernel parameters:"
|
||||
echo "1. Edit /etc/default/grub"
|
||||
echo "2. Add parameters to GRUB_CMDLINE_LINUX_DEFAULT"
|
||||
echo "3. Run: grub-mkconfig -o /boot/grub/grub.cfg"
|
||||
echo "4. Reboot"
|
||||
echo ""
|
||||
echo "Example GRUB_CMDLINE_LINUX_DEFAULT line:"
|
||||
echo 'GRUB_CMDLINE_LINUX_DEFAULT="quiet nopat"'
|
||||
echo "NVIDIA Driver Issues and Recommended Kernel Parameters:"
|
||||
echo ""
|
||||
echo "A) For 'conflicting memory type' or 'failed to allocate primary buffer' errors"
|
||||
echo " (especially with nvidia-96xx drivers):"
|
||||
echo " → Add 'nopat' to kernel parameters"
|
||||
echo ""
|
||||
echo "B) For OpenGL visual glitches, hangs, and errors with modern CPUs:"
|
||||
echo " → Consider disabling micro-op cache in BIOS settings"
|
||||
echo " → This affects Intel Sandy Bridge (2011+) and AMD Zen (2017+) CPUs"
|
||||
echo " → Helps with severe graphical glitches in Xwayland applications"
|
||||
echo " → Note: Disabling micro-op cache reduces CPU performance"
|
||||
echo ""
|
||||
echo "To add kernel parameters:"
|
||||
echo "1. Edit /etc/default/grub"
|
||||
echo "2. Add parameters to GRUB_CMDLINE_LINUX_DEFAULT"
|
||||
echo "3. Run: grub-mkconfig -o /boot/grub/grub.cfg"
|
||||
echo "4. Reboot"
|
||||
echo ""
|
||||
echo "Example GRUB_CMDLINE_LINUX_DEFAULT line:"
|
||||
echo 'GRUB_CMDLINE_LINUX_DEFAULT="quiet nopat"'
|
||||
|
||||
# Check current CPU for micro-op cache relevance
|
||||
echo ""
|
||||
echo "CPU Information (for micro-op cache consideration):"
|
||||
if command -v lscpu &> /dev/null; then
|
||||
local cpu_info
|
||||
cpu_info=$(lscpu | grep "Model name" | cut -d: -f2 | xargs)
|
||||
echo "Current CPU: $cpu_info"
|
||||
# Check current CPU for micro-op cache relevance
|
||||
echo ""
|
||||
echo "CPU Information (for micro-op cache consideration):"
|
||||
if command -v lscpu &>/dev/null; then
|
||||
local cpu_info
|
||||
cpu_info=$(lscpu | grep "Model name" | cut -d: -f2 | xargs)
|
||||
echo "Current CPU: $cpu_info"
|
||||
|
||||
if echo "$cpu_info" | grep -qi "intel"; then
|
||||
echo "→ Intel CPU detected. Sandy Bridge (2011) and later have micro-op cache"
|
||||
elif echo "$cpu_info" | grep -qi "amd"; then
|
||||
echo "→ AMD CPU detected. Zen (2017) and later have micro-op cache"
|
||||
fi
|
||||
fi
|
||||
if echo "$cpu_info" | grep -qi "intel"; then
|
||||
echo "→ Intel CPU detected. Sandy Bridge (2011) and later have micro-op cache"
|
||||
elif echo "$cpu_info" | grep -qi "amd"; then
|
||||
echo "→ AMD CPU detected. Zen (2017) and later have micro-op cache"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to suggest desktop environment settings
|
||||
suggest_desktop_settings() {
|
||||
echo ""
|
||||
echo "6. Desktop Environment Recommendations..."
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "6. Desktop Environment Recommendations..."
|
||||
echo "========================================"
|
||||
|
||||
echo "For fullscreen application freezing/crashing issues:"
|
||||
echo ""
|
||||
echo "Enable Display Compositing and Direct fullscreen rendering:"
|
||||
echo ""
|
||||
echo "• KDE Plasma:"
|
||||
echo " System Settings → Display and Monitor → Compositor"
|
||||
echo " → Enable compositor + Enable direct rendering for fullscreen windows"
|
||||
echo ""
|
||||
echo "• GNOME:"
|
||||
echo " Use Extensions or dconf-editor to enable compositing features"
|
||||
echo ""
|
||||
echo "• XFCE:"
|
||||
echo " Settings → Window Manager Tweaks → Compositor"
|
||||
echo " → Enable display compositing"
|
||||
echo ""
|
||||
echo "• Cinnamon:"
|
||||
echo " System Settings → Effects → Enable desktop effects"
|
||||
echo "For fullscreen application freezing/crashing issues:"
|
||||
echo ""
|
||||
echo "Enable Display Compositing and Direct fullscreen rendering:"
|
||||
echo ""
|
||||
echo "• KDE Plasma:"
|
||||
echo " System Settings → Display and Monitor → Compositor"
|
||||
echo " → Enable compositor + Enable direct rendering for fullscreen windows"
|
||||
echo ""
|
||||
echo "• GNOME:"
|
||||
echo " Use Extensions or dconf-editor to enable compositing features"
|
||||
echo ""
|
||||
echo "• XFCE:"
|
||||
echo " Settings → Window Manager Tweaks → Compositor"
|
||||
echo " → Enable display compositing"
|
||||
echo ""
|
||||
echo "• Cinnamon:"
|
||||
echo " System Settings → Effects → Enable desktop effects"
|
||||
|
||||
# Detect current desktop environment
|
||||
if [[ -n $XDG_CURRENT_DESKTOP ]]; then
|
||||
echo ""
|
||||
echo "Detected desktop environment: $XDG_CURRENT_DESKTOP"
|
||||
fi
|
||||
# Detect current desktop environment
|
||||
if [[ -n $XDG_CURRENT_DESKTOP ]]; then
|
||||
echo ""
|
||||
echo "Detected desktop environment: $XDG_CURRENT_DESKTOP"
|
||||
fi
|
||||
}
|
||||
|
||||
# Apply all configurations
|
||||
@ -331,14 +306,14 @@ install_pyroveil
|
||||
echo ""
|
||||
echo "7. Regenerating Initramfs..."
|
||||
echo "============================"
|
||||
if command -v mkinitcpio &> /dev/null; then
|
||||
mkinitcpio -P
|
||||
echo "✓ Initramfs regenerated with mkinitcpio"
|
||||
elif command -v dracut &> /dev/null; then
|
||||
dracut --force
|
||||
echo "✓ Initramfs regenerated with dracut"
|
||||
if command -v mkinitcpio &>/dev/null; then
|
||||
mkinitcpio -P
|
||||
echo "✓ Initramfs regenerated with mkinitcpio"
|
||||
elif command -v dracut &>/dev/null; then
|
||||
dracut --force
|
||||
echo "✓ Initramfs regenerated with dracut"
|
||||
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
|
||||
|
||||
# Display all recommendations
|
||||
@ -354,7 +329,7 @@ echo "✓ GSP firmware disabled"
|
||||
echo "✓ RenderAccel disabled in Xorg configuration"
|
||||
echo "✓ GCC version mismatch workaround added"
|
||||
if [[ -d "/home/$SUDO_USER/pyroveil" ]]; then
|
||||
echo "✓ Pyroveil installed for mesh shader issues"
|
||||
echo "✓ Pyroveil installed for mesh shader issues"
|
||||
fi
|
||||
echo "✓ Initramfs regenerated"
|
||||
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
|
||||
|
||||
# Default to non-interactive mode
|
||||
INTERACTIVE_MODE=false
|
||||
# Source common library for shared functions
|
||||
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
# shellcheck source=lib/common.sh
|
||||
source "$SCRIPT_DIR/lib/common.sh"
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-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
|
||||
# Parse interactive/help arguments
|
||||
parse_interactive_args "$@"
|
||||
shift "$COMMON_ARGS_SHIFT"
|
||||
|
||||
# Function to check and request sudo privileges
|
||||
check_sudo() {
|
||||
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 "$@"
|
||||
# Check for sudo privileges
|
||||
require_root "$@"
|
||||
|
||||
echo "Periodic System Setup - Pacman Wrapper & Hosts File"
|
||||
echo "==================================================="
|
||||
echo "Current Date: $(date)"
|
||||
echo "User: $USER"
|
||||
echo "Original user: ${SUDO_USER:-$USER}"
|
||||
echo "Original user: $(get_actual_user)"
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
echo "Mode: Interactive (prompts enabled)"
|
||||
echo "Mode: Interactive (prompts enabled)"
|
||||
else
|
||||
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
||||
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
||||
fi
|
||||
|
||||
# Get the directory where this script is located
|
||||
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
CONFIG_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# Define paths
|
||||
@ -86,231 +60,231 @@ TEMPLATE_LOGROTATE="$LOGROTATE_TEMPLATES/periodic-system-maintenance"
|
||||
|
||||
# Function to verify required files exist
|
||||
verify_files() {
|
||||
echo ""
|
||||
echo "1. Verifying Required Files..."
|
||||
echo "=============================="
|
||||
echo ""
|
||||
echo "1. Verifying Required Files..."
|
||||
echo "=============================="
|
||||
|
||||
local missing_files=()
|
||||
local missing_files=()
|
||||
|
||||
if [[ ! -f $PACMAN_WRAPPER_SCRIPT ]]; then
|
||||
missing_files+=("$PACMAN_WRAPPER_SCRIPT")
|
||||
fi
|
||||
if [[ ! -f $PACMAN_WRAPPER_SCRIPT ]]; then
|
||||
missing_files+=("$PACMAN_WRAPPER_SCRIPT")
|
||||
fi
|
||||
|
||||
if [[ ! -f $PACMAN_WRAPPER_INSTALL ]]; then
|
||||
missing_files+=("$PACMAN_WRAPPER_INSTALL")
|
||||
fi
|
||||
if [[ ! -f $PACMAN_WRAPPER_INSTALL ]]; then
|
||||
missing_files+=("$PACMAN_WRAPPER_INSTALL")
|
||||
fi
|
||||
|
||||
if [[ ! -f $HOSTS_INSTALL_SCRIPT ]]; then
|
||||
missing_files+=("$HOSTS_INSTALL_SCRIPT")
|
||||
fi
|
||||
if [[ ! -f $HOSTS_INSTALL_SCRIPT ]]; then
|
||||
missing_files+=("$HOSTS_INSTALL_SCRIPT")
|
||||
fi
|
||||
|
||||
# Check template files as well
|
||||
for tmpl in \
|
||||
"$TEMPLATE_MAINT_SCRIPT" \
|
||||
"$TEMPLATE_HOSTS_MONITOR" \
|
||||
"$TEMPLATE_BROWSER_WRAPPER" \
|
||||
"$TEMPLATE_SVC_MAINT" \
|
||||
"$TEMPLATE_TIMER" \
|
||||
"$TEMPLATE_STARTUP" \
|
||||
"$TEMPLATE_HOSTS_SVC" \
|
||||
"$TEMPLATE_LOGROTATE"; do
|
||||
if [[ ! -f $tmpl ]]; then
|
||||
missing_files+=("$tmpl")
|
||||
fi
|
||||
done
|
||||
# Check template files as well
|
||||
for tmpl in \
|
||||
"$TEMPLATE_MAINT_SCRIPT" \
|
||||
"$TEMPLATE_HOSTS_MONITOR" \
|
||||
"$TEMPLATE_BROWSER_WRAPPER" \
|
||||
"$TEMPLATE_SVC_MAINT" \
|
||||
"$TEMPLATE_TIMER" \
|
||||
"$TEMPLATE_STARTUP" \
|
||||
"$TEMPLATE_HOSTS_SVC" \
|
||||
"$TEMPLATE_LOGROTATE"; do
|
||||
if [[ ! -f $tmpl ]]; then
|
||||
missing_files+=("$tmpl")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#missing_files[@]} -gt 0 ]]; then
|
||||
echo "Error: The following required files are missing:"
|
||||
for file in "${missing_files[@]}"; do
|
||||
echo " - $file"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
if [[ ${#missing_files[@]} -gt 0 ]]; then
|
||||
echo "Error: The following required files are missing:"
|
||||
for file in "${missing_files[@]}"; do
|
||||
echo " - $file"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ All required files found"
|
||||
echo "✓ All required files found"
|
||||
}
|
||||
|
||||
# Function to create the combined execution script
|
||||
create_execution_script() {
|
||||
echo ""
|
||||
echo "2. Creating Combined Execution Script..."
|
||||
echo "======================================="
|
||||
echo ""
|
||||
echo "2. Creating Combined Execution Script..."
|
||||
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
|
||||
sed \
|
||||
-e "s|__PACMAN_WRAPPER_INSTALL__|$PACMAN_WRAPPER_INSTALL|g" \
|
||||
-e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
||||
"$TEMPLATE_MAINT_SCRIPT" > "$exec_script"
|
||||
# Install from template with path substitutions
|
||||
sed \
|
||||
-e "s|__PACMAN_WRAPPER_INSTALL__|$PACMAN_WRAPPER_INSTALL|g" \
|
||||
-e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
||||
"$TEMPLATE_MAINT_SCRIPT" >"$exec_script"
|
||||
|
||||
chmod +x "$exec_script"
|
||||
echo "✓ Installed execution script from template: $exec_script"
|
||||
chmod +x "$exec_script"
|
||||
echo "✓ Installed execution script from template: $exec_script"
|
||||
}
|
||||
|
||||
# Function to create systemd service
|
||||
create_systemd_service() {
|
||||
echo ""
|
||||
echo "3. Creating Systemd Service..."
|
||||
echo "============================="
|
||||
echo ""
|
||||
echo "3. Creating Systemd Service..."
|
||||
echo "============================="
|
||||
|
||||
local service_file="/etc/systemd/system/periodic-system-maintenance.service"
|
||||
install -m 0644 "$TEMPLATE_SVC_MAINT" "$service_file"
|
||||
echo "✓ Installed systemd service from template: $service_file"
|
||||
local service_file="/etc/systemd/system/periodic-system-maintenance.service"
|
||||
install -m 0644 "$TEMPLATE_SVC_MAINT" "$service_file"
|
||||
echo "✓ Installed systemd service from template: $service_file"
|
||||
}
|
||||
|
||||
# Function to create systemd timer for hourly execution
|
||||
create_systemd_timer() {
|
||||
echo ""
|
||||
echo "4. Creating Systemd Timer..."
|
||||
echo "============================"
|
||||
echo ""
|
||||
echo "4. Creating Systemd Timer..."
|
||||
echo "============================"
|
||||
|
||||
local timer_file="/etc/systemd/system/periodic-system-maintenance.timer"
|
||||
install -m 0644 "$TEMPLATE_TIMER" "$timer_file"
|
||||
echo "✓ Installed systemd timer from template: $timer_file"
|
||||
local timer_file="/etc/systemd/system/periodic-system-maintenance.timer"
|
||||
install -m 0644 "$TEMPLATE_TIMER" "$timer_file"
|
||||
echo "✓ Installed systemd timer from template: $timer_file"
|
||||
}
|
||||
|
||||
# Function to create startup service (additional to timer)
|
||||
create_startup_service() {
|
||||
echo ""
|
||||
echo "5. Creating Startup Service..."
|
||||
echo "=============================="
|
||||
echo ""
|
||||
echo "5. Creating Startup Service..."
|
||||
echo "=============================="
|
||||
|
||||
local startup_service="/etc/systemd/system/periodic-system-startup.service"
|
||||
install -m 0644 "$TEMPLATE_STARTUP" "$startup_service"
|
||||
echo "✓ Installed startup service from template: $startup_service"
|
||||
local startup_service="/etc/systemd/system/periodic-system-startup.service"
|
||||
install -m 0644 "$TEMPLATE_STARTUP" "$startup_service"
|
||||
echo "✓ Installed startup service from template: $startup_service"
|
||||
}
|
||||
|
||||
# Function to create hosts file monitor service
|
||||
create_hosts_monitor_service() {
|
||||
echo ""
|
||||
echo "6. Creating Hosts File Monitor Service..."
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "6. Creating Hosts File Monitor Service..."
|
||||
echo "========================================"
|
||||
|
||||
local monitor_script="/usr/local/bin/hosts-file-monitor.sh"
|
||||
local monitor_service="/etc/systemd/system/hosts-file-monitor.service"
|
||||
local monitor_script="/usr/local/bin/hosts-file-monitor.sh"
|
||||
local monitor_service="/etc/systemd/system/hosts-file-monitor.service"
|
||||
|
||||
# Install the monitor script from template with substitution
|
||||
sed -e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
||||
"$TEMPLATE_HOSTS_MONITOR" > "$monitor_script"
|
||||
chmod +x "$monitor_script"
|
||||
echo "✓ Installed hosts monitor script from template: $monitor_script"
|
||||
# Install the monitor script from template with substitution
|
||||
sed -e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
||||
"$TEMPLATE_HOSTS_MONITOR" >"$monitor_script"
|
||||
chmod +x "$monitor_script"
|
||||
echo "✓ Installed hosts monitor script from template: $monitor_script"
|
||||
|
||||
# Install the systemd service from template
|
||||
install -m 0644 "$TEMPLATE_HOSTS_SVC" "$monitor_service"
|
||||
echo "✓ Installed hosts monitor service from template: $monitor_service"
|
||||
# Install the systemd service from template
|
||||
install -m 0644 "$TEMPLATE_HOSTS_SVC" "$monitor_service"
|
||||
echo "✓ Installed hosts monitor service from template: $monitor_service"
|
||||
}
|
||||
|
||||
# Function to install browser pre-exec wrapper and wire common browser names
|
||||
install_browser_preexec_wrapper() {
|
||||
echo ""
|
||||
echo "6.1 Installing Browser Pre-Exec Wrapper..."
|
||||
echo "========================================="
|
||||
echo ""
|
||||
echo "6.1 Installing Browser Pre-Exec Wrapper..."
|
||||
echo "========================================="
|
||||
|
||||
local wrapper="/usr/local/bin/browser-preexec-wrapper"
|
||||
sed -e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
||||
"$TEMPLATE_BROWSER_WRAPPER" > "$wrapper"
|
||||
chmod +x "$wrapper"
|
||||
echo "✓ Installed wrapper: $wrapper"
|
||||
local wrapper="/usr/local/bin/browser-preexec-wrapper"
|
||||
sed -e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
||||
"$TEMPLATE_BROWSER_WRAPPER" >"$wrapper"
|
||||
chmod +x "$wrapper"
|
||||
echo "✓ Installed wrapper: $wrapper"
|
||||
|
||||
# Allow passwordless execution of hosts installer for root-only actions
|
||||
local sudoers_file="/etc/sudoers.d/hosts-install-no-passwd"
|
||||
if command -v visudo > /dev/null 2>&1; then
|
||||
echo "${SUDO_USER:-$USER} ALL=(ALL) NOPASSWD: $HOSTS_INSTALL_SCRIPT" > "$sudoers_file"
|
||||
chmod 440 "$sudoers_file"
|
||||
# Validate syntax
|
||||
visudo -c > /dev/null || echo "Warning: sudoers validation returned non-zero"
|
||||
echo "✓ Sudoers drop-in created: $sudoers_file"
|
||||
else
|
||||
echo "visudo not found; skipping sudoers drop-in"
|
||||
fi
|
||||
# Allow passwordless execution of hosts installer for root-only actions
|
||||
local sudoers_file="/etc/sudoers.d/hosts-install-no-passwd"
|
||||
if command -v visudo >/dev/null 2>&1; then
|
||||
echo "${SUDO_USER:-$USER} ALL=(ALL) NOPASSWD: $HOSTS_INSTALL_SCRIPT" >"$sudoers_file"
|
||||
chmod 440 "$sudoers_file"
|
||||
# Validate syntax
|
||||
visudo -c >/dev/null || echo "Warning: sudoers validation returned non-zero"
|
||||
echo "✓ Sudoers drop-in created: $sudoers_file"
|
||||
else
|
||||
echo "visudo not found; skipping sudoers drop-in"
|
||||
fi
|
||||
|
||||
# Create symlinks for common browser commands to the wrapper in /usr/local/bin
|
||||
# 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")
|
||||
for b in "${browsers[@]}"; do
|
||||
local link="/usr/local/bin/$b"
|
||||
ln -sf "$wrapper" "$link"
|
||||
done
|
||||
echo "✓ Symlinked wrapper for common browsers 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.
|
||||
local browsers=("thorium-browser" "google-chrome" "google-chrome-stable" "chromium" "brave" "brave-browser" "vivaldi-stable" "firefox")
|
||||
for b in "${browsers[@]}"; do
|
||||
local link="/usr/local/bin/$b"
|
||||
ln -sf "$wrapper" "$link"
|
||||
done
|
||||
echo "✓ Symlinked wrapper for common browsers in /usr/local/bin"
|
||||
}
|
||||
|
||||
# Function to enable and start services
|
||||
enable_services() {
|
||||
echo ""
|
||||
echo "7. Enabling Services and Timer..."
|
||||
echo "================================="
|
||||
echo ""
|
||||
echo "7. Enabling Services and Timer..."
|
||||
echo "================================="
|
||||
|
||||
# Reload systemd daemon
|
||||
systemctl daemon-reload
|
||||
echo "✓ Systemd daemon reloaded"
|
||||
# Reload systemd daemon
|
||||
systemctl daemon-reload
|
||||
echo "✓ Systemd daemon reloaded"
|
||||
|
||||
# Enable and start the timer
|
||||
systemctl enable periodic-system-maintenance.timer
|
||||
systemctl start periodic-system-maintenance.timer
|
||||
echo "✓ Timer enabled and started"
|
||||
# Enable and start the timer
|
||||
systemctl enable periodic-system-maintenance.timer
|
||||
systemctl start periodic-system-maintenance.timer
|
||||
echo "✓ Timer enabled and started"
|
||||
|
||||
# Enable startup service (but don't start it now)
|
||||
systemctl enable periodic-system-startup.service
|
||||
echo "✓ Startup service enabled"
|
||||
# Enable startup service (but don't start it now)
|
||||
systemctl enable periodic-system-startup.service
|
||||
echo "✓ Startup service enabled"
|
||||
|
||||
# Enable hosts file monitor service
|
||||
systemctl enable hosts-file-monitor.service
|
||||
systemctl start hosts-file-monitor.service
|
||||
echo "✓ Hosts file monitor service enabled and started"
|
||||
# Enable hosts file monitor service
|
||||
systemctl enable hosts-file-monitor.service
|
||||
systemctl start hosts-file-monitor.service
|
||||
echo "✓ Hosts file monitor service enabled and started"
|
||||
|
||||
# Show timer status
|
||||
echo ""
|
||||
echo "Timer Status:"
|
||||
systemctl status periodic-system-maintenance.timer --no-pager -l
|
||||
# Show timer status
|
||||
echo ""
|
||||
echo "Timer Status:"
|
||||
systemctl status periodic-system-maintenance.timer --no-pager -l
|
||||
|
||||
echo ""
|
||||
echo "Hosts Monitor Status:"
|
||||
systemctl status hosts-file-monitor.service --no-pager -l
|
||||
echo ""
|
||||
echo "Hosts Monitor Status:"
|
||||
systemctl status hosts-file-monitor.service --no-pager -l
|
||||
|
||||
echo ""
|
||||
echo "Next scheduled runs:"
|
||||
systemctl list-timers periodic-system-maintenance.timer --no-pager
|
||||
echo ""
|
||||
echo "Next scheduled runs:"
|
||||
systemctl list-timers periodic-system-maintenance.timer --no-pager
|
||||
}
|
||||
|
||||
# Function to create log rotation configuration
|
||||
create_log_rotation() {
|
||||
echo ""
|
||||
echo "8. Setting up Log Rotation..."
|
||||
echo "============================="
|
||||
echo ""
|
||||
echo "8. Setting up Log Rotation..."
|
||||
echo "============================="
|
||||
|
||||
local logrotate_conf="/etc/logrotate.d/periodic-system-maintenance"
|
||||
install -m 0644 "$TEMPLATE_LOGROTATE" "$logrotate_conf"
|
||||
echo "✓ Installed log rotation configuration from template: $logrotate_conf"
|
||||
local logrotate_conf="/etc/logrotate.d/periodic-system-maintenance"
|
||||
install -m 0644 "$TEMPLATE_LOGROTATE" "$logrotate_conf"
|
||||
echo "✓ Installed log rotation configuration from template: $logrotate_conf"
|
||||
}
|
||||
|
||||
# Function to run initial execution
|
||||
run_initial_execution() {
|
||||
echo ""
|
||||
echo "9. Running Initial Execution..."
|
||||
echo "==============================="
|
||||
echo ""
|
||||
echo "9. Running Initial Execution..."
|
||||
echo "==============================="
|
||||
|
||||
local run_initial=true
|
||||
local run_initial=true
|
||||
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
echo "Would you like to run the system maintenance now to test the setup?"
|
||||
read -p "Run initial execution? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
echo "Would you like to run the system maintenance now to test the setup?"
|
||||
read -p "Run initial execution? (y/N): " -n 1 -r
|
||||
echo
|
||||
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
run_initial=false
|
||||
fi
|
||||
else
|
||||
echo "Auto-running initial execution to test the setup (use --interactive to prompt)"
|
||||
fi
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
run_initial=false
|
||||
fi
|
||||
else
|
||||
echo "Auto-running initial execution to test the setup (use --interactive to prompt)"
|
||||
fi
|
||||
|
||||
if [[ $run_initial == "true" ]]; then
|
||||
echo "Running initial system maintenance..."
|
||||
/usr/local/bin/periodic-system-maintenance.sh
|
||||
echo "✓ Initial execution completed"
|
||||
else
|
||||
echo "Skipping initial execution"
|
||||
fi
|
||||
if [[ $run_initial == "true" ]]; then
|
||||
echo "Running initial system maintenance..."
|
||||
/usr/local/bin/periodic-system-maintenance.sh
|
||||
echo "✓ Initial execution completed"
|
||||
else
|
||||
echo "Skipping initial execution"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
|
||||
@ -4,58 +4,33 @@
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
# Default to non-interactive mode
|
||||
INTERACTIVE_MODE=false
|
||||
# Source common library for shared functions
|
||||
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
# shellcheck source=lib/common.sh
|
||||
source "$SCRIPT_DIR/lib/common.sh"
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-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
|
||||
# Parse interactive/help arguments
|
||||
parse_interactive_args "$@"
|
||||
shift "$COMMON_ARGS_SHIFT"
|
||||
|
||||
# Function to check and request sudo privileges
|
||||
check_sudo() {
|
||||
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 "$@"
|
||||
# Check for sudo privileges
|
||||
require_root "$@"
|
||||
|
||||
echo "Thorium Browser Auto-Startup Setup"
|
||||
echo "=================================="
|
||||
echo "Current Date: $(date)"
|
||||
echo "User: $USER"
|
||||
echo "Original user: ${SUDO_USER:-$USER}"
|
||||
echo "Original user: $(get_actual_user)"
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
echo "Mode: Interactive (prompts enabled)"
|
||||
echo "Mode: Interactive (prompts enabled)"
|
||||
else
|
||||
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
||||
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
||||
fi
|
||||
|
||||
# Target URL
|
||||
TARGET_URL="https://www.fitatu.com/app/planner"
|
||||
BROWSER_COMMAND="thorium-browser"
|
||||
USER_HOME="/home/${SUDO_USER}"
|
||||
USER_HOME="/home/$(get_actual_user)"
|
||||
|
||||
echo ""
|
||||
echo "Target URL: $TARGET_URL"
|
||||
@ -64,72 +39,72 @@ echo "User home: $USER_HOME"
|
||||
|
||||
# Function to check if Thorium browser is installed
|
||||
check_thorium_browser() {
|
||||
echo ""
|
||||
echo "1. Checking Thorium Browser Installation..."
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
echo "1. Checking Thorium Browser Installation..."
|
||||
echo "=========================================="
|
||||
|
||||
if ! command -v "$BROWSER_COMMAND" &> /dev/null; then
|
||||
echo "Warning: Thorium browser not found in PATH"
|
||||
echo "Checking alternative locations..."
|
||||
if ! command -v "$BROWSER_COMMAND" &>/dev/null; then
|
||||
echo "Warning: Thorium browser not found in PATH"
|
||||
echo "Checking alternative locations..."
|
||||
|
||||
# Check common installation paths
|
||||
local alt_paths=(
|
||||
"/opt/thorium/thorium"
|
||||
"/usr/bin/thorium"
|
||||
"/usr/local/bin/thorium"
|
||||
"/opt/thorium-browser/thorium-browser"
|
||||
"${USER_HOME}/.local/bin/thorium-browser"
|
||||
)
|
||||
# Check common installation paths
|
||||
local alt_paths=(
|
||||
"/opt/thorium/thorium"
|
||||
"/usr/bin/thorium"
|
||||
"/usr/local/bin/thorium"
|
||||
"/opt/thorium-browser/thorium-browser"
|
||||
"${USER_HOME}/.local/bin/thorium-browser"
|
||||
)
|
||||
|
||||
local found=false
|
||||
for path in "${alt_paths[@]}"; do
|
||||
if [[ -x $path ]]; then
|
||||
BROWSER_COMMAND="$path"
|
||||
echo "✓ Found Thorium browser at: $path"
|
||||
found=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
local found=false
|
||||
for path in "${alt_paths[@]}"; do
|
||||
if [[ -x $path ]]; then
|
||||
BROWSER_COMMAND="$path"
|
||||
echo "✓ Found Thorium browser at: $path"
|
||||
found=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $found != true ]]; then
|
||||
echo "Error: Thorium browser not found!"
|
||||
echo "Please install Thorium browser first or ensure it's in your PATH."
|
||||
echo ""
|
||||
echo "You can install Thorium browser from:"
|
||||
echo "https://thorium.rocks/"
|
||||
echo ""
|
||||
if [[ $found != true ]]; then
|
||||
echo "Error: Thorium browser not found!"
|
||||
echo "Please install Thorium browser first or ensure it's in your PATH."
|
||||
echo ""
|
||||
echo "You can install Thorium browser from:"
|
||||
echo "https://thorium.rocks/"
|
||||
echo ""
|
||||
|
||||
local continue_anyway=false
|
||||
local continue_anyway=false
|
||||
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
read -p "Continue anyway? The service will be created but may fail to start (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
continue_anyway=true
|
||||
fi
|
||||
else
|
||||
echo "Auto-continuing anyway - service will be created but may fail to start (use --interactive to prompt)"
|
||||
continue_anyway=true
|
||||
fi
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
read -p "Continue anyway? The service will be created but may fail to start (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
continue_anyway=true
|
||||
fi
|
||||
else
|
||||
echo "Auto-continuing anyway - service will be created but may fail to start (use --interactive to prompt)"
|
||||
continue_anyway=true
|
||||
fi
|
||||
|
||||
if [[ $continue_anyway != true ]]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "✓ Thorium browser found: $(which $BROWSER_COMMAND)"
|
||||
fi
|
||||
if [[ $continue_anyway != true ]]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "✓ Thorium browser found: $(which $BROWSER_COMMAND)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to create the browser launcher script
|
||||
create_launcher_script() {
|
||||
echo ""
|
||||
echo "2. Creating Browser Launcher Script..."
|
||||
echo "====================================="
|
||||
echo ""
|
||||
echo "2. Creating Browser Launcher Script..."
|
||||
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
|
||||
# Thorium browser launcher for Fitatu website
|
||||
# Created by setup_thorium_startup.sh on $(date)
|
||||
@ -203,24 +178,24 @@ else
|
||||
fi
|
||||
EOF
|
||||
|
||||
chmod +x "$launcher_script"
|
||||
echo "✓ Created launcher script: $launcher_script"
|
||||
chmod +x "$launcher_script"
|
||||
echo "✓ Created launcher script: $launcher_script"
|
||||
}
|
||||
|
||||
# Function to create systemd service for user session
|
||||
create_user_systemd_service() {
|
||||
echo ""
|
||||
echo "3. Creating User Systemd Service..."
|
||||
echo "=================================="
|
||||
echo ""
|
||||
echo "3. Creating User Systemd Service..."
|
||||
echo "=================================="
|
||||
|
||||
local user_systemd_dir="$USER_HOME/.config/systemd/user"
|
||||
local service_file="$user_systemd_dir/thorium-fitatu-startup.service"
|
||||
local user_systemd_dir="$USER_HOME/.config/systemd/user"
|
||||
local service_file="$user_systemd_dir/thorium-fitatu-startup.service"
|
||||
|
||||
# Create user systemd directory
|
||||
sudo -u "${SUDO_USER}" mkdir -p "$user_systemd_dir"
|
||||
# Create user systemd directory
|
||||
sudo -u "${SUDO_USER}" mkdir -p "$user_systemd_dir"
|
||||
|
||||
# Create the service file
|
||||
sudo -u "${SUDO_USER}" tee "$service_file" > /dev/null << EOF
|
||||
# Create the service file
|
||||
sudo -u "${SUDO_USER}" tee "$service_file" >/dev/null <<EOF
|
||||
[Unit]
|
||||
Description=Launch Thorium Browser with Fitatu on Startup
|
||||
After=graphical-session.target
|
||||
@ -245,18 +220,18 @@ TimeoutStartSec=120
|
||||
WantedBy=default.target
|
||||
EOF
|
||||
|
||||
echo "✓ Created user systemd service: $service_file"
|
||||
echo "✓ Created user systemd service: $service_file"
|
||||
}
|
||||
|
||||
# Function to create system-wide systemd service (alternative approach)
|
||||
create_system_systemd_service() {
|
||||
echo ""
|
||||
echo "4. Creating System Systemd Service..."
|
||||
echo "===================================="
|
||||
echo ""
|
||||
echo "4. Creating System Systemd Service..."
|
||||
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]
|
||||
Description=Launch Thorium Browser with Fitatu on Startup
|
||||
After=multi-user.target network-online.target
|
||||
@ -283,23 +258,23 @@ TimeoutStartSec=180
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
echo "✓ Created system systemd service: $service_file"
|
||||
echo "✓ Created system systemd service: $service_file"
|
||||
}
|
||||
|
||||
# Function to create autostart desktop entry (additional method)
|
||||
create_autostart_entry() {
|
||||
echo ""
|
||||
echo "5. Creating Autostart Desktop Entry..."
|
||||
echo "====================================="
|
||||
echo ""
|
||||
echo "5. Creating Autostart Desktop Entry..."
|
||||
echo "====================================="
|
||||
|
||||
local autostart_dir="$USER_HOME/.config/autostart"
|
||||
local desktop_file="$autostart_dir/thorium-fitatu.desktop"
|
||||
local autostart_dir="$USER_HOME/.config/autostart"
|
||||
local desktop_file="$autostart_dir/thorium-fitatu.desktop"
|
||||
|
||||
# Create autostart directory
|
||||
sudo -u "${SUDO_USER}" mkdir -p "$autostart_dir"
|
||||
# Create autostart directory
|
||||
sudo -u "${SUDO_USER}" mkdir -p "$autostart_dir"
|
||||
|
||||
# Create desktop entry
|
||||
sudo -u "${SUDO_USER}" tee "$desktop_file" > /dev/null << EOF
|
||||
# Create desktop entry
|
||||
sudo -u "${SUDO_USER}" tee "$desktop_file" >/dev/null <<EOF
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Thorium Fitatu Startup
|
||||
@ -314,45 +289,45 @@ Terminal=false
|
||||
Categories=Network;WebBrowser;
|
||||
EOF
|
||||
|
||||
echo "✓ Created autostart desktop entry: $desktop_file"
|
||||
echo "✓ Created autostart desktop entry: $desktop_file"
|
||||
}
|
||||
|
||||
# Function to create i3 config autostart entry
|
||||
create_i3_autostart() {
|
||||
echo ""
|
||||
echo "6. Creating i3 Config Autostart Entry..."
|
||||
echo "======================================="
|
||||
echo ""
|
||||
echo "6. Creating i3 Config Autostart Entry..."
|
||||
echo "======================================="
|
||||
|
||||
local i3_config="$USER_HOME/.config/i3/config"
|
||||
local i3_config_dir="$USER_HOME/.config/i3"
|
||||
local i3_config="$USER_HOME/.config/i3/config"
|
||||
local i3_config_dir="$USER_HOME/.config/i3"
|
||||
|
||||
# Create i3 config directory if it doesn't exist
|
||||
sudo -u "${SUDO_USER}" mkdir -p "$i3_config_dir"
|
||||
# Create i3 config directory if it doesn't exist
|
||||
sudo -u "${SUDO_USER}" mkdir -p "$i3_config_dir"
|
||||
|
||||
# Check if i3 config exists
|
||||
if [[ -f $i3_config ]]; then
|
||||
# Check if autostart entry already exists
|
||||
if ! sudo -u "${SUDO_USER}" grep -q "thorium-fitatu-launcher" "$i3_config"; then
|
||||
# Add autostart entry to 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 'exec --no-startup-id /usr/local/bin/thorium-fitatu-launcher.sh' >> '$i3_config'"
|
||||
echo "✓ Added autostart entry to i3 config: $i3_config"
|
||||
else
|
||||
echo "✓ Autostart entry already exists in i3 config"
|
||||
fi
|
||||
else
|
||||
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 "exec --no-startup-id /usr/local/bin/thorium-fitatu-launcher.sh"
|
||||
fi
|
||||
# Check if i3 config exists
|
||||
if [[ -f $i3_config ]]; then
|
||||
# Check if autostart entry already exists
|
||||
if ! sudo -u "${SUDO_USER}" grep -q "thorium-fitatu-launcher" "$i3_config"; then
|
||||
# Add autostart entry to 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 'exec --no-startup-id /usr/local/bin/thorium-fitatu-launcher.sh' >> '$i3_config'"
|
||||
echo "✓ Added autostart entry to i3 config: $i3_config"
|
||||
else
|
||||
echo "✓ Autostart entry already exists in i3 config"
|
||||
fi
|
||||
else
|
||||
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 "exec --no-startup-id /usr/local/bin/thorium-fitatu-launcher.sh"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to create a script to enable user service after login
|
||||
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
|
||||
# Script to enable thorium-fitatu-startup user service
|
||||
# This runs once to enable the service, then removes itself
|
||||
@ -365,110 +340,110 @@ systemctl --user enable thorium-fitatu-startup.service
|
||||
rm "$0"
|
||||
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
|
||||
local bashrc="$USER_HOME/.bashrc"
|
||||
if [[ -f $bashrc ]]; then
|
||||
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 '[[ -x ~/.config/thorium-enable-service.sh ]] && ~/.config/thorium-enable-service.sh' >> '$bashrc'"
|
||||
fi
|
||||
# Add to user's .bashrc to run on next login
|
||||
local bashrc="$USER_HOME/.bashrc"
|
||||
if [[ -f $bashrc ]]; then
|
||||
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 '[[ -x ~/.config/thorium-enable-service.sh ]] && ~/.config/thorium-enable-service.sh' >> '$bashrc'"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to enable services
|
||||
enable_services() {
|
||||
echo ""
|
||||
echo "7. Enabling Services..."
|
||||
echo "======================"
|
||||
echo ""
|
||||
echo "7. Enabling Services..."
|
||||
echo "======================"
|
||||
|
||||
# Reload systemd daemon
|
||||
systemctl daemon-reload
|
||||
echo "✓ System daemon reloaded"
|
||||
# Reload systemd daemon
|
||||
systemctl daemon-reload
|
||||
echo "✓ System daemon reloaded"
|
||||
|
||||
# Enable system service
|
||||
systemctl enable thorium-fitatu-startup.service
|
||||
echo "✓ System service enabled"
|
||||
# Enable system service
|
||||
systemctl enable thorium-fitatu-startup.service
|
||||
echo "✓ System service enabled"
|
||||
|
||||
# Enable lingering for the user (allows user services to run without login)
|
||||
loginctl enable-linger "${SUDO_USER}"
|
||||
echo "✓ User lingering enabled"
|
||||
# Enable lingering for the user (allows user services to run without login)
|
||||
loginctl enable-linger "${SUDO_USER}"
|
||||
echo "✓ User lingering enabled"
|
||||
|
||||
# Create a script to enable user service after login
|
||||
create_user_enable_script
|
||||
echo "✓ User service will be enabled on next login"
|
||||
# Create a script to enable user service after login
|
||||
create_user_enable_script
|
||||
echo "✓ User service will be enabled on next login"
|
||||
}
|
||||
|
||||
# Function to test the setup
|
||||
test_setup() {
|
||||
echo ""
|
||||
echo "8. Testing Setup..."
|
||||
echo "=================="
|
||||
echo ""
|
||||
echo "8. Testing Setup..."
|
||||
echo "=================="
|
||||
|
||||
local run_test=true
|
||||
local run_test=true
|
||||
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
echo "Would you like to test the browser launcher now?"
|
||||
read -p "Test launch Thorium browser with Fitatu? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||
echo "Would you like to test the browser launcher now?"
|
||||
read -p "Test launch Thorium browser with Fitatu? (y/N): " -n 1 -r
|
||||
echo
|
||||
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
run_test=false
|
||||
fi
|
||||
else
|
||||
echo "Auto-testing the browser launcher (use --interactive to prompt)"
|
||||
fi
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
run_test=false
|
||||
fi
|
||||
else
|
||||
echo "Auto-testing the browser launcher (use --interactive to prompt)"
|
||||
fi
|
||||
|
||||
if [[ $run_test == "true" ]]; then
|
||||
echo "Testing browser launch..."
|
||||
echo "Note: This will open Thorium browser with Fitatu website"
|
||||
if [[ $run_test == "true" ]]; then
|
||||
echo "Testing browser launch..."
|
||||
echo "Note: This will open Thorium browser with Fitatu website"
|
||||
|
||||
# Test the launcher immediately
|
||||
if /usr/local/bin/thorium-fitatu-launcher.sh; then
|
||||
echo "✓ Test launch completed successfully"
|
||||
else
|
||||
echo "✗ Test launch failed"
|
||||
echo "Check that Thorium browser is properly installed and accessible"
|
||||
fi
|
||||
else
|
||||
echo "Skipping test launch"
|
||||
fi
|
||||
# Test the launcher immediately
|
||||
if /usr/local/bin/thorium-fitatu-launcher.sh; then
|
||||
echo "✓ Test launch completed successfully"
|
||||
else
|
||||
echo "✗ Test launch failed"
|
||||
echo "Check that Thorium browser is properly installed and accessible"
|
||||
fi
|
||||
else
|
||||
echo "Skipping test launch"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to show usage instructions
|
||||
show_instructions() {
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "Thorium Browser Auto-Startup Setup Complete"
|
||||
echo "=========================================="
|
||||
echo "Summary:"
|
||||
echo "✓ Launcher script created: /usr/local/bin/thorium-fitatu-launcher.sh"
|
||||
echo "✓ System service created: 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 "✓ i3 autostart entry added to: ~/.config/i3/config"
|
||||
echo "✓ Services enabled for automatic startup"
|
||||
echo ""
|
||||
echo "The system will now:"
|
||||
echo "• Launch Thorium browser with $TARGET_URL on every startup"
|
||||
echo "• Use multiple methods to ensure reliable startup"
|
||||
echo "• Wait for desktop environment to be ready before launching"
|
||||
echo "• User service will be enabled automatically on next login"
|
||||
echo ""
|
||||
echo "To check status:"
|
||||
echo " systemctl status thorium-fitatu-startup.service"
|
||||
echo " systemctl --user status thorium-fitatu-startup.service (after login)"
|
||||
echo ""
|
||||
echo "To view logs:"
|
||||
echo " journalctl -u thorium-fitatu-startup.service"
|
||||
echo " journalctl --user -u thorium-fitatu-startup.service"
|
||||
echo ""
|
||||
echo "To disable (if needed):"
|
||||
echo " sudo systemctl disable thorium-fitatu-startup.service"
|
||||
echo " systemctl --user disable thorium-fitatu-startup.service"
|
||||
echo " rm ~/.config/autostart/thorium-fitatu.desktop"
|
||||
echo ""
|
||||
echo "IMPORTANT: Browser will launch automatically on next reboot!"
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "Thorium Browser Auto-Startup Setup Complete"
|
||||
echo "=========================================="
|
||||
echo "Summary:"
|
||||
echo "✓ Launcher script created: /usr/local/bin/thorium-fitatu-launcher.sh"
|
||||
echo "✓ System service created: 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 "✓ i3 autostart entry added to: ~/.config/i3/config"
|
||||
echo "✓ Services enabled for automatic startup"
|
||||
echo ""
|
||||
echo "The system will now:"
|
||||
echo "• Launch Thorium browser with $TARGET_URL on every startup"
|
||||
echo "• Use multiple methods to ensure reliable startup"
|
||||
echo "• Wait for desktop environment to be ready before launching"
|
||||
echo "• User service will be enabled automatically on next login"
|
||||
echo ""
|
||||
echo "To check status:"
|
||||
echo " systemctl status thorium-fitatu-startup.service"
|
||||
echo " systemctl --user status thorium-fitatu-startup.service (after login)"
|
||||
echo ""
|
||||
echo "To view logs:"
|
||||
echo " journalctl -u thorium-fitatu-startup.service"
|
||||
echo " journalctl --user -u thorium-fitatu-startup.service"
|
||||
echo ""
|
||||
echo "To disable (if needed):"
|
||||
echo " sudo systemctl disable thorium-fitatu-startup.service"
|
||||
echo " systemctl --user disable thorium-fitatu-startup.service"
|
||||
echo " rm ~/.config/autostart/thorium-fitatu.desktop"
|
||||
echo ""
|
||||
echo "IMPORTANT: Browser will launch automatically on next reboot!"
|
||||
}
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
if [[ $EUID -ne 0 ]] && [[ ! -r /etc/hosts ]]; then
|
||||
exec sudo -E bash "$0" "$@"
|
||||
fi
|
||||
|
||||
WORK_DIR="${HOME}/.cache/android-adblock"
|
||||
|
||||
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} $*"
|
||||
}
|
||||
ensure_dir "$WORK_DIR"
|
||||
|
||||
die() {
|
||||
error "$@"
|
||||
echo "[ERROR] $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
@ -1,194 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# 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 "$@"
|
||||
# Wrapper for backward compatibility - converts to mp4
|
||||
# See convert_video.sh for full options
|
||||
exec "$(dirname "$(readlink -f "$0")")/convert_video.sh" -f mp4 "$@"
|
||||
|
||||
@ -1,206 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# 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 "$@"
|
||||
# Wrapper for backward compatibility - converts to webm
|
||||
# See convert_video.sh for full options
|
||||
exec "$(dirname "$(readlink -f "$0")")/convert_video.sh" -f webm "$@"
|
||||
|
||||
@ -2,29 +2,21 @@
|
||||
|
||||
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
|
||||
if [[ $EUID -ne 0 ]] && [[ ! -r /etc/hosts ]]; then
|
||||
exec sudo -E bash "$0" "$@"
|
||||
fi
|
||||
|
||||
WORK_DIR="${HOME}/.cache/android-adblock"
|
||||
mkdir -p "$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
|
||||
}
|
||||
ensure_dir "$WORK_DIR"
|
||||
|
||||
die() {
|
||||
error "$@"
|
||||
echo "[ERROR] $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user