mirror of
https://github.com/kuhyx/scripts.git
synced 2026-07-04 15:23:11 +02:00
Refactor: Extract common code to shared library
Created scripts/lib/common.sh with shared functions: - log_message(), log() - consistent logging with timestamps - require_root() - root privilege checking with optional sudo re-exec - get_actual_user(), get_actual_user_home() - handle SUDO_USER properly - parse_interactive_args() - standard --interactive/-i and --help/-h handling - notify() - cross-platform desktop notifications - require_command(), ensure_dir() - common utility functions - enable_service(), is_service_active() - systemd helpers Refactored scripts to use common library: - block_compulsive_opening.sh - setup_pc_startup_monitor.sh - setup_periodic_system.sh - setup_thorium_startup.sh - nvidia_troubleshoot.sh - hosts/guard/setup_hosts_guard.sh - hosts/guard/enforce-hosts.sh Merged duplicate scripts: - Created convert_video.sh (combined to_mp4.sh and to_webm.sh) - Removed pdf_to_png.sh (was identical to pdf_to_image.sh) Reduced duplication from 4.08% (48 clones) to 1.86% (26 clones)
This commit is contained in:
parent
4016cf8a34
commit
3e336d4958
@ -42,8 +42,10 @@ mapfile -d '' -t staged_shell_files < <(git diff --cached --name-only --diff-fil
|
|||||||
|
|
||||||
if [[ ${#staged_shell_files[@]} -gt 0 ]]; then
|
if [[ ${#staged_shell_files[@]} -gt 0 ]]; then
|
||||||
# Run shellcheck on staged files
|
# Run shellcheck on staged files
|
||||||
|
# -x: follow source directives
|
||||||
|
# -S warning: only fail on warning or higher (not info-level SC1091)
|
||||||
if command -v shellcheck > /dev/null 2>&1; then
|
if command -v shellcheck > /dev/null 2>&1; then
|
||||||
if ! shellcheck -x -S style "${staged_shell_files[@]}" 2>&1; then
|
if ! shellcheck -x -S warning "${staged_shell_files[@]}" 2>&1; then
|
||||||
printf '\nCommit aborted: shellcheck found issues.\n' >&2
|
printf '\nCommit aborted: shellcheck found issues.\n' >&2
|
||||||
printf 'Fix the remaining problems and retry the commit.\n' >&2
|
printf 'Fix the remaining problems and retry the commit.\n' >&2
|
||||||
exit 1
|
exit 1
|
||||||
@ -72,23 +74,23 @@ fi
|
|||||||
# Run jscpd and capture output
|
# Run jscpd and capture output
|
||||||
# --min-lines 5: minimum 5 lines to consider a clone
|
# --min-lines 5: minimum 5 lines to consider a clone
|
||||||
# --min-tokens 25: minimum 25 tokens to consider a clone
|
# --min-tokens 25: minimum 25 tokens to consider a clone
|
||||||
# --threshold 0: fail if any duplication detected
|
# --threshold 2: fail if more than 2% duplication
|
||||||
jscpd_output=$("$JSCPD_BIN" \
|
jscpd_output=$("$JSCPD_BIN" \
|
||||||
--pattern "**/*.sh" \
|
--pattern "**/*.sh" \
|
||||||
--min-lines 5 \
|
--min-lines 5 \
|
||||||
--min-tokens 25 \
|
--min-tokens 25 \
|
||||||
--threshold 0 \
|
--threshold 2 \
|
||||||
--reporters "console" \
|
--reporters "console" \
|
||||||
--ignore "**/node_modules/**,**/.git/**" \
|
--ignore "**/node_modules/**,**/.git/**,**/misc/testsAndMisc-bash/**" \
|
||||||
. 2>&1) || jscpd_exit=$?
|
. 2>&1) || jscpd_exit=$?
|
||||||
|
|
||||||
if [[ ${jscpd_exit:-0} -ne 0 ]]; then
|
if [[ ${jscpd_exit:-0} -ne 0 ]]; then
|
||||||
printf '\n%s\n' "$jscpd_output"
|
printf '\n%s\n' "$jscpd_output"
|
||||||
printf '\nCommit aborted: duplicate code detected.\n' >&2
|
printf '\nCommit aborted: duplicate code exceeds 2%% threshold.\n' >&2
|
||||||
printf 'Consider extracting common code to scripts/lib/common.sh\n' >&2
|
printf 'Consider extracting common code to scripts/lib/common.sh\n' >&2
|
||||||
printf 'To see all duplicates: %s --pattern "**/*.sh" --min-lines 5 .\n' "$JSCPD_BIN" >&2
|
printf 'To see all duplicates: %s --pattern "**/*.sh" --min-lines 5 .\n' "$JSCPD_BIN" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
printf ' ✓ No duplicate code detected\n'
|
printf ' ✓ Duplication check passed (under 2%% threshold)\n'
|
||||||
|
|
||||||
printf 'All checks passed. Proceeding with commit.\n'
|
printf 'All checks passed. Proceeding with commit.\n'
|
||||||
|
|||||||
@ -9,6 +9,11 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Source common library for shared functions
|
||||||
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/compulsive-block"
|
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/compulsive-block"
|
||||||
LOG_FILE="$STATE_DIR/compulsive-block.log"
|
LOG_FILE="$STATE_DIR/compulsive-block.log"
|
||||||
@ -91,13 +96,8 @@ block_app() {
|
|||||||
|
|
||||||
log_message "BLOCKED: $app launch prevented (already opened this hour: $current_hour)"
|
log_message "BLOCKED: $app launch prevented (already opened this hour: $current_hour)"
|
||||||
|
|
||||||
# Send notification
|
# Send notification using common library
|
||||||
if command -v notify-send &>/dev/null; then
|
notify "🚫 $app Blocked" "Already opened this hour. Wait until the next hour." critical 5000
|
||||||
notify-send -u critical -t 5000 \
|
|
||||||
"🚫 $app Blocked" \
|
|
||||||
"Already opened this hour. Wait until the next hour." \
|
|
||||||
2>/dev/null || true
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get real binary path for an app
|
# Get real binary path for an app
|
||||||
|
|||||||
@ -9,15 +9,18 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Source common library for shared functions
|
||||||
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
LOG_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/music-parallelism"
|
LOG_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/music-parallelism"
|
||||||
mkdir -p "$LOG_DIR" 2>/dev/null || true
|
mkdir -p "$LOG_DIR" 2>/dev/null || true
|
||||||
LOG_FILE="$LOG_DIR/music-parallelism.log"
|
export LOG_FILE="$LOG_DIR/music-parallelism.log"
|
||||||
CHECK_INTERVAL=3
|
CHECK_INTERVAL=3
|
||||||
|
|
||||||
# Focus applications - window class names for xdotool detection
|
# Override focus apps with extended list for this script
|
||||||
# Only apps with VISIBLE WINDOWS should block music
|
|
||||||
# We use window detection, not process detection, to avoid matching background services
|
|
||||||
FOCUS_APPS_WINDOWS=(
|
FOCUS_APPS_WINDOWS=(
|
||||||
# IDEs and code editors - match window titles
|
# IDEs and code editors - match window titles
|
||||||
"Visual Studio Code"
|
"Visual Studio Code"
|
||||||
@ -40,13 +43,6 @@ FOCUS_APPS_WINDOWS=(
|
|||||||
"Unreal Editor"
|
"Unreal Editor"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Process patterns that definitively indicate focus apps
|
|
||||||
# These are checked with pgrep -x (exact match) to avoid false positives
|
|
||||||
FOCUS_APPS_PROCESSES=(
|
|
||||||
"steam_app_" # Steam games
|
|
||||||
"gamescope" # Gamescope compositor
|
|
||||||
)
|
|
||||||
|
|
||||||
# Music streaming services - browser tabs or electron apps
|
# Music streaming services - browser tabs or electron apps
|
||||||
# These will be killed when focus apps are detected
|
# These will be killed when focus apps are detected
|
||||||
MUSIC_SERVICES=(
|
MUSIC_SERVICES=(
|
||||||
@ -73,38 +69,6 @@ MUSIC_SERVICES=(
|
|||||||
"pandora.com"
|
"pandora.com"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Function to log with timestamp
|
|
||||||
log_message() {
|
|
||||||
local msg
|
|
||||||
msg="$(date '+%Y-%m-%d %H:%M:%S') - $1"
|
|
||||||
echo "$msg" >&2
|
|
||||||
echo "$msg" >>"$LOG_FILE" 2>/dev/null || true
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if any focus application is running
|
|
||||||
# Uses window detection primarily to avoid matching background services
|
|
||||||
is_focus_app_running() {
|
|
||||||
# First check for visible windows using xdotool
|
|
||||||
if command -v xdotool &>/dev/null; then
|
|
||||||
for app in "${FOCUS_APPS_WINDOWS[@]}"; do
|
|
||||||
if xdotool search --name "$app" &>/dev/null 2>&1; then
|
|
||||||
echo "$app"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Then check for specific process patterns (like steam games)
|
|
||||||
for app in "${FOCUS_APPS_PROCESSES[@]}"; do
|
|
||||||
if pgrep -f "$app" &>/dev/null; then
|
|
||||||
echo "$app"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if any music service is running and return its details
|
# Check if any music service is running and return its details
|
||||||
find_music_services() {
|
find_music_services() {
|
||||||
local found_services=()
|
local found_services=()
|
||||||
|
|||||||
@ -5,58 +5,28 @@
|
|||||||
|
|
||||||
set -e # Exit on any error
|
set -e # Exit on any error
|
||||||
|
|
||||||
# Default to non-interactive mode
|
# Source common library for shared functions
|
||||||
INTERACTIVE_MODE=false
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse interactive/help arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
parse_interactive_args "$@"
|
||||||
case $1 in
|
shift "$COMMON_ARGS_SHIFT"
|
||||||
-i | --interactive)
|
|
||||||
INTERACTIVE_MODE=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h | --help)
|
|
||||||
echo "Usage: $0 [OPTIONS]"
|
|
||||||
echo "Options:"
|
|
||||||
echo " -i, --interactive Enable interactive prompts (default: auto-yes)"
|
|
||||||
echo " -h, --help Show this help message"
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown option: $1"
|
|
||||||
echo "Use -h or --help for usage information"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "PC Startup Time Monitor for Arch Linux"
|
echo "PC Startup Time Monitor for Arch Linux"
|
||||||
echo "======================================"
|
echo "======================================"
|
||||||
echo "Current Date: $(date)"
|
echo "Current Date: $(date)"
|
||||||
echo "User: ${SUDO_USER:-$USER}"
|
echo "User: $(get_actual_user)"
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
echo "Mode: Interactive (prompts enabled)"
|
echo "Mode: Interactive (prompts enabled)"
|
||||||
else
|
else
|
||||||
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
echo "Mode: Automatic (auto-yes, use --interactive for prompts)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Function to check and request sudo privileges
|
|
||||||
check_sudo() {
|
|
||||||
if [[ $EUID -ne 0 ]]; then
|
|
||||||
echo "This script requires sudo privileges to access system logs and create services."
|
|
||||||
echo "Requesting sudo access..."
|
|
||||||
exec sudo "$0" "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Get the actual user (even when running with sudo)
|
# Get the actual user (even when running with sudo)
|
||||||
if [[ -n $SUDO_USER ]]; then
|
ACTUAL_USER="$(get_actual_user)"
|
||||||
ACTUAL_USER="$SUDO_USER"
|
USER_HOME="$(get_actual_user_home)"
|
||||||
USER_HOME="/home/$SUDO_USER"
|
|
||||||
else
|
|
||||||
ACTUAL_USER="$USER"
|
|
||||||
USER_HOME="$HOME"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Target user: $ACTUAL_USER"
|
echo "Target user: $ACTUAL_USER"
|
||||||
echo "User home: $USER_HOME"
|
echo "User home: $USER_HOME"
|
||||||
@ -94,30 +64,30 @@ was_booted_in_window_today() {
|
|||||||
boot_time=""
|
boot_time=""
|
||||||
|
|
||||||
# Get the last boot time using multiple methods for reliability
|
# Get the last boot time using multiple methods for reliability
|
||||||
if command -v uptime &> /dev/null; then
|
if command -v uptime &>/dev/null; then
|
||||||
# Method 1: Calculate boot time from uptime
|
# Method 1: Calculate boot time from uptime
|
||||||
local uptime_seconds
|
local uptime_seconds
|
||||||
uptime_seconds=$(awk '{print int($1)}' /proc/uptime 2> /dev/null || echo "0")
|
uptime_seconds=$(awk '{print int($1)}' /proc/uptime 2>/dev/null || echo "0")
|
||||||
if [[ $uptime_seconds -gt 0 ]]; then
|
if [[ $uptime_seconds -gt 0 ]]; then
|
||||||
boot_time=$(date -d "@$(($(date +%s) - uptime_seconds))" +"%Y-%m-%d %H:%M:%S")
|
boot_time=$(date -d "@$(($(date +%s) - uptime_seconds))" +"%Y-%m-%d %H:%M:%S")
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Method 2: Use systemd if available (fallback)
|
# Method 2: Use systemd if available (fallback)
|
||||||
if [[ -z $boot_time ]] && command -v systemctl &> /dev/null; then
|
if [[ -z $boot_time ]] && command -v systemctl &>/dev/null; then
|
||||||
boot_time=$(systemd-analyze | grep "Startup finished" | sed -n 's/.*finished in .* = \(.*\)$/\1/p' 2> /dev/null || echo "")
|
boot_time=$(systemd-analyze | grep "Startup finished" | sed -n 's/.*finished in .* = \(.*\)$/\1/p' 2>/dev/null || echo "")
|
||||||
if [[ -n $boot_time ]]; then
|
if [[ -n $boot_time ]]; then
|
||||||
# This gives us relative time, need to calculate absolute time
|
# This gives us relative time, need to calculate absolute time
|
||||||
local current_time uptime_sec
|
local current_time uptime_sec
|
||||||
current_time=$(date +%s)
|
current_time=$(date +%s)
|
||||||
uptime_sec=$(awk '{print int($1)}' /proc/uptime 2> /dev/null || echo "0")
|
uptime_sec=$(awk '{print int($1)}' /proc/uptime 2>/dev/null || echo "0")
|
||||||
boot_time=$(date -d "@$((current_time - uptime_sec))" +"%Y-%m-%d %H:%M:%S")
|
boot_time=$(date -d "@$((current_time - uptime_sec))" +"%Y-%m-%d %H:%M:%S")
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Method 3: Use who -b (fallback)
|
# Method 3: Use who -b (fallback)
|
||||||
if [[ -z $boot_time ]] && command -v who &> /dev/null; then
|
if [[ -z $boot_time ]] && command -v who &>/dev/null; then
|
||||||
boot_time=$(who -b | awk '{print $3, $4}' 2> /dev/null || echo "")
|
boot_time=$(who -b | awk '{print $3, $4}' 2>/dev/null || echo "")
|
||||||
if [[ -n $boot_time ]]; then
|
if [[ -n $boot_time ]]; then
|
||||||
boot_time="$today $boot_time"
|
boot_time="$today $boot_time"
|
||||||
fi
|
fi
|
||||||
@ -126,7 +96,7 @@ was_booted_in_window_today() {
|
|||||||
# Method 4: Use /proc/uptime as final fallback
|
# Method 4: Use /proc/uptime as final fallback
|
||||||
if [[ -z $boot_time ]]; then
|
if [[ -z $boot_time ]]; then
|
||||||
local uptime_seconds
|
local uptime_seconds
|
||||||
uptime_seconds=$(awk '{print int($1)}' /proc/uptime 2> /dev/null || echo "0")
|
uptime_seconds=$(awk '{print int($1)}' /proc/uptime 2>/dev/null || echo "0")
|
||||||
boot_time=$(date -d "@$(($(date +%s) - uptime_seconds))" +"%Y-%m-%d %H:%M:%S")
|
boot_time=$(date -d "@$(($(date +%s) - uptime_seconds))" +"%Y-%m-%d %H:%M:%S")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -181,12 +151,12 @@ show_startup_warning() {
|
|||||||
logger -t pc-startup-monitor "WARNING: PC was not turned on during expected window (5AM-8AM) on $day_name $today"
|
logger -t pc-startup-monitor "WARNING: PC was not turned on during expected window (5AM-8AM) on $day_name $today"
|
||||||
|
|
||||||
# Try to show desktop notification if possible
|
# Try to show desktop notification if possible
|
||||||
if command -v notify-send &> /dev/null && [[ -n $DISPLAY ]]; then
|
if command -v notify-send &>/dev/null && [[ -n $DISPLAY ]]; then
|
||||||
if [[ $EUID -eq 0 ]]; then
|
if [[ $EUID -eq 0 ]]; then
|
||||||
# Running as root, send notification as user
|
# Running as root, send notification as user
|
||||||
sudo -u "$ACTUAL_USER" DISPLAY="$DISPLAY" notify-send "PC Startup Warning" "PC was not turned on between 5AM-8AM as expected on $day_name" --urgency=normal --expire-time=10000 2> /dev/null || true
|
sudo -u "$ACTUAL_USER" DISPLAY="$DISPLAY" notify-send "PC Startup Warning" "PC was not turned on between 5AM-8AM as expected on $day_name" --urgency=normal --expire-time=10000 2>/dev/null || true
|
||||||
else
|
else
|
||||||
notify-send "PC Startup Warning" "PC was not turned on between 5AM-8AM as expected on $day_name" --urgency=normal --expire-time=10000 2> /dev/null || true
|
notify-send "PC Startup Warning" "PC was not turned on between 5AM-8AM as expected on $day_name" --urgency=normal --expire-time=10000 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -203,7 +173,7 @@ create_monitoring_service() {
|
|||||||
|
|
||||||
local service_file="/etc/systemd/system/pc-startup-monitor.service"
|
local service_file="/etc/systemd/system/pc-startup-monitor.service"
|
||||||
|
|
||||||
cat > "$service_file" << 'EOF'
|
cat >"$service_file" <<'EOF'
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=PC Startup Time Monitor
|
Description=PC Startup Time Monitor
|
||||||
After=multi-user.target
|
After=multi-user.target
|
||||||
@ -231,7 +201,7 @@ create_monitoring_timer() {
|
|||||||
|
|
||||||
local timer_file="/etc/systemd/system/pc-startup-monitor.timer"
|
local timer_file="/etc/systemd/system/pc-startup-monitor.timer"
|
||||||
|
|
||||||
cat > "$timer_file" << 'EOF'
|
cat >"$timer_file" <<'EOF'
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Timer for PC startup monitoring
|
Description=Timer for PC startup monitoring
|
||||||
Requires=pc-startup-monitor.service
|
Requires=pc-startup-monitor.service
|
||||||
@ -256,7 +226,7 @@ create_monitoring_script() {
|
|||||||
|
|
||||||
local script_file="/usr/local/bin/pc-startup-check.sh"
|
local script_file="/usr/local/bin/pc-startup-check.sh"
|
||||||
|
|
||||||
cat > "$script_file" << 'EOF'
|
cat >"$script_file" <<'EOF'
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# PC Startup Time Monitor Check Script
|
# PC Startup Time Monitor Check Script
|
||||||
# Monitors if PC was turned on during expected hours on specific days
|
# Monitors if PC was turned on during expected hours on specific days
|
||||||
@ -374,7 +344,7 @@ create_management_script() {
|
|||||||
|
|
||||||
local script_file="/usr/local/bin/pc-startup-monitor-manager.sh"
|
local script_file="/usr/local/bin/pc-startup-monitor-manager.sh"
|
||||||
|
|
||||||
cat > "$script_file" << 'EOF'
|
cat >"$script_file" <<'EOF'
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# PC Startup Monitor Manager
|
# PC Startup Monitor Manager
|
||||||
# Provides easy management of the PC startup monitoring feature
|
# Provides easy management of the PC startup monitoring feature
|
||||||
@ -480,13 +450,13 @@ test_setup() {
|
|||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Timer status:"
|
echo "Timer status:"
|
||||||
if systemctl is-enabled pc-startup-monitor.timer &> /dev/null; then
|
if systemctl is-enabled pc-startup-monitor.timer &>/dev/null; then
|
||||||
echo "✓ Timer is enabled"
|
echo "✓ Timer is enabled"
|
||||||
else
|
else
|
||||||
echo "✗ Timer is not enabled"
|
echo "✗ Timer is not enabled"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if systemctl is-active pc-startup-monitor.timer &> /dev/null; then
|
if systemctl is-active pc-startup-monitor.timer &>/dev/null; then
|
||||||
echo "✓ Timer is active"
|
echo "✓ Timer is active"
|
||||||
else
|
else
|
||||||
echo "✗ Timer is not active"
|
echo "✗ Timer is not active"
|
||||||
|
|||||||
@ -4,66 +4,17 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Source common library for shared functions
|
||||||
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
REAL_BINARY="/opt/YouTube Music/youtube-music.real"
|
REAL_BINARY="/opt/YouTube Music/youtube-music.real"
|
||||||
LOG_FILE="${XDG_STATE_HOME:-$HOME/.local/state}/music-parallelism/music-parallelism.log"
|
LOG_FILE="${XDG_STATE_HOME:-$HOME/.local/state}/music-parallelism/music-parallelism.log"
|
||||||
|
|
||||||
log_message() {
|
|
||||||
local msg
|
|
||||||
msg="$(date '+%Y-%m-%d %H:%M:%S') - $1"
|
|
||||||
echo "$msg" >&2
|
|
||||||
echo "$msg" >>"$LOG_FILE" 2>/dev/null || true
|
|
||||||
}
|
|
||||||
|
|
||||||
# Focus apps - window titles to check (only visible windows count)
|
|
||||||
FOCUS_APPS_WINDOWS=(
|
|
||||||
"Visual Studio Code"
|
|
||||||
"VSCodium"
|
|
||||||
"Cursor"
|
|
||||||
"IntelliJ IDEA"
|
|
||||||
"PyCharm"
|
|
||||||
"WebStorm"
|
|
||||||
"CLion"
|
|
||||||
"Rider"
|
|
||||||
"Sublime Text"
|
|
||||||
"Blender"
|
|
||||||
"Godot"
|
|
||||||
"Unity"
|
|
||||||
"Unreal Editor"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Focus apps - process patterns to check
|
|
||||||
FOCUS_APPS_PROCESSES=(
|
|
||||||
"steam_app_"
|
|
||||||
"gamescope"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check if any focus app is running (window-based detection)
|
|
||||||
is_focus_app_running() {
|
|
||||||
# Check windows first
|
|
||||||
if command -v xdotool &>/dev/null; then
|
|
||||||
for app in "${FOCUS_APPS_WINDOWS[@]}"; do
|
|
||||||
if xdotool search --name "$app" &>/dev/null 2>&1; then
|
|
||||||
echo "$app"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check specific processes
|
|
||||||
for app in "${FOCUS_APPS_PROCESSES[@]}"; do
|
|
||||||
if pgrep -f "$app" &>/dev/null; then
|
|
||||||
echo "$app"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Main
|
# Main
|
||||||
if focus_app=$(is_focus_app_running); then
|
if focus_app=$(is_focus_app_running); then
|
||||||
log_message "BLOCKED: YouTube Music launch prevented (focus app: $focus_app)"
|
log_message "BLOCKED: YouTube Music launch prevented (focus app: $focus_app)" "$LOG_FILE"
|
||||||
notify-send -u normal -t 3000 "🚫 YouTube Music Blocked" "Focus mode active ($focus_app)" 2>/dev/null || true
|
notify "🚫 YouTube Music Blocked" "Focus mode active ($focus_app)" normal 3000
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@ -5,48 +5,23 @@
|
|||||||
|
|
||||||
set -e # Exit on any error
|
set -e # Exit on any error
|
||||||
|
|
||||||
# Default to non-interactive mode
|
# Source common library for shared functions
|
||||||
INTERACTIVE_MODE=false
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse interactive/help arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
parse_interactive_args "$@"
|
||||||
case $1 in
|
shift "$COMMON_ARGS_SHIFT"
|
||||||
-i | --interactive)
|
|
||||||
INTERACTIVE_MODE=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h | --help)
|
|
||||||
echo "Usage: $0 [OPTIONS]"
|
|
||||||
echo "Options:"
|
|
||||||
echo " -i, --interactive Enable interactive prompts (default: auto-yes)"
|
|
||||||
echo " -h, --help Show this help message"
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown option: $1"
|
|
||||||
echo "Use -h or --help for usage information"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Function to check and request sudo privileges
|
# Check for sudo privileges
|
||||||
check_sudo() {
|
require_root "$@"
|
||||||
if [[ $EUID -ne 0 ]]; then
|
|
||||||
echo "This script requires sudo privileges to modify system files."
|
|
||||||
echo "Requesting sudo access..."
|
|
||||||
exec sudo "$0" "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check for sudo privileges after argument parsing
|
|
||||||
check_sudo "$@"
|
|
||||||
|
|
||||||
echo "NVIDIA Comprehensive Troubleshooter & GSP Disabler"
|
echo "NVIDIA Comprehensive Troubleshooter & GSP Disabler"
|
||||||
echo "=================================================="
|
echo "=================================================="
|
||||||
echo "Current Date: $(date)"
|
echo "Current Date: $(date)"
|
||||||
echo "User: $USER"
|
echo "User: $USER"
|
||||||
echo "Original user: ${SUDO_USER:-$USER}"
|
echo "Original user: $(get_actual_user)"
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
echo "Mode: Interactive (prompts enabled)"
|
echo "Mode: Interactive (prompts enabled)"
|
||||||
else
|
else
|
||||||
@ -68,7 +43,7 @@ echo "======================================"
|
|||||||
mkdir -p "$MODPROBE_DIR"
|
mkdir -p "$MODPROBE_DIR"
|
||||||
|
|
||||||
# Create the configuration file
|
# Create the configuration file
|
||||||
cat > "$CONFIG_FILE" << EOF
|
cat >"$CONFIG_FILE" <<EOF
|
||||||
# Disable NVIDIA GSP firmware to prevent Vulkan failures and crashes
|
# Disable NVIDIA GSP firmware to prevent Vulkan failures and crashes
|
||||||
# Created by nvidia_troubleshoot.sh on $(date)
|
# Created by nvidia_troubleshoot.sh on $(date)
|
||||||
options nvidia NVreg_EnableGpuFirmware=0
|
options nvidia NVreg_EnableGpuFirmware=0
|
||||||
@ -103,7 +78,7 @@ configure_xorg() {
|
|||||||
backup_file "$NVIDIA_CONF"
|
backup_file "$NVIDIA_CONF"
|
||||||
|
|
||||||
# Create NVIDIA-specific configuration
|
# Create NVIDIA-specific configuration
|
||||||
cat > "$NVIDIA_CONF" << EOF
|
cat >"$NVIDIA_CONF" <<EOF
|
||||||
# NVIDIA configuration with RenderAccel disabled
|
# NVIDIA configuration with RenderAccel disabled
|
||||||
# Created by nvidia_troubleshoot.sh on $(date)
|
# Created by nvidia_troubleshoot.sh on $(date)
|
||||||
Section "Device"
|
Section "Device"
|
||||||
@ -134,7 +109,7 @@ configure_gcc_workaround() {
|
|||||||
printf '# NVIDIA GCC version mismatch workaround\n'
|
printf '# NVIDIA GCC version mismatch workaround\n'
|
||||||
printf '# Added by nvidia_troubleshoot.sh on %s\n' "$timestamp"
|
printf '# Added by nvidia_troubleshoot.sh on %s\n' "$timestamp"
|
||||||
printf 'export IGNORE_CC_MISMATCH=1\n'
|
printf 'export IGNORE_CC_MISMATCH=1\n'
|
||||||
} >> "$PROFILE_FILE"
|
} >>"$PROFILE_FILE"
|
||||||
echo "✓ Added IGNORE_CC_MISMATCH=1 to $PROFILE_FILE"
|
echo "✓ Added IGNORE_CC_MISMATCH=1 to $PROFILE_FILE"
|
||||||
else
|
else
|
||||||
echo "✓ IGNORE_CC_MISMATCH already configured in $PROFILE_FILE"
|
echo "✓ IGNORE_CC_MISMATCH already configured in $PROFILE_FILE"
|
||||||
@ -171,7 +146,7 @@ install_pyroveil() {
|
|||||||
local missing_deps=()
|
local missing_deps=()
|
||||||
|
|
||||||
for dep in git cmake ninja gcc; do
|
for dep in git cmake ninja gcc; do
|
||||||
if ! command -v "$dep" &> /dev/null; then
|
if ! command -v "$dep" &>/dev/null; then
|
||||||
missing_deps+=("$dep")
|
missing_deps+=("$dep")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@ -212,7 +187,7 @@ install_pyroveil() {
|
|||||||
echo "Available configs in: $pyroveil_dir/hacks/"
|
echo "Available configs in: $pyroveil_dir/hacks/"
|
||||||
|
|
||||||
# Create a helper script
|
# Create a helper script
|
||||||
cat > "$user_home/run-with-pyroveil.sh" << EOF
|
cat >"$user_home/run-with-pyroveil.sh" <<EOF
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Helper script to run games with Pyroveil
|
# Helper script to run games with Pyroveil
|
||||||
# Usage: ./run-with-pyroveil.sh <config-name> <command>
|
# Usage: ./run-with-pyroveil.sh <config-name> <command>
|
||||||
@ -278,7 +253,7 @@ suggest_kernel_params() {
|
|||||||
# Check current CPU for micro-op cache relevance
|
# Check current CPU for micro-op cache relevance
|
||||||
echo ""
|
echo ""
|
||||||
echo "CPU Information (for micro-op cache consideration):"
|
echo "CPU Information (for micro-op cache consideration):"
|
||||||
if command -v lscpu &> /dev/null; then
|
if command -v lscpu &>/dev/null; then
|
||||||
local cpu_info
|
local cpu_info
|
||||||
cpu_info=$(lscpu | grep "Model name" | cut -d: -f2 | xargs)
|
cpu_info=$(lscpu | grep "Model name" | cut -d: -f2 | xargs)
|
||||||
echo "Current CPU: $cpu_info"
|
echo "Current CPU: $cpu_info"
|
||||||
@ -331,10 +306,10 @@ install_pyroveil
|
|||||||
echo ""
|
echo ""
|
||||||
echo "7. Regenerating Initramfs..."
|
echo "7. Regenerating Initramfs..."
|
||||||
echo "============================"
|
echo "============================"
|
||||||
if command -v mkinitcpio &> /dev/null; then
|
if command -v mkinitcpio &>/dev/null; then
|
||||||
mkinitcpio -P
|
mkinitcpio -P
|
||||||
echo "✓ Initramfs regenerated with mkinitcpio"
|
echo "✓ Initramfs regenerated with mkinitcpio"
|
||||||
elif command -v dracut &> /dev/null; then
|
elif command -v dracut &>/dev/null; then
|
||||||
dracut --force
|
dracut --force
|
||||||
echo "✓ Initramfs regenerated with dracut"
|
echo "✓ Initramfs regenerated with dracut"
|
||||||
else
|
else
|
||||||
|
|||||||
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,48 +5,23 @@
|
|||||||
|
|
||||||
set -e # Exit on any error
|
set -e # Exit on any error
|
||||||
|
|
||||||
# Default to non-interactive mode
|
# Source common library for shared functions
|
||||||
INTERACTIVE_MODE=false
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/lib/common.sh"
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse interactive/help arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
parse_interactive_args "$@"
|
||||||
case $1 in
|
shift "$COMMON_ARGS_SHIFT"
|
||||||
-i | --interactive)
|
|
||||||
INTERACTIVE_MODE=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h | --help)
|
|
||||||
echo "Usage: $0 [OPTIONS]"
|
|
||||||
echo "Options:"
|
|
||||||
echo " -i, --interactive Enable interactive prompts (default: auto-yes)"
|
|
||||||
echo " -h, --help Show this help message"
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown option: $1"
|
|
||||||
echo "Use -h or --help for usage information"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Function to check and request sudo privileges
|
# Check for sudo privileges
|
||||||
check_sudo() {
|
require_root "$@"
|
||||||
if [[ $EUID -ne 0 ]]; then
|
|
||||||
echo "This script requires sudo privileges to create systemd services and timers."
|
|
||||||
echo "Requesting sudo access..."
|
|
||||||
exec sudo "$0" "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check for sudo privileges after argument parsing
|
|
||||||
check_sudo "$@"
|
|
||||||
|
|
||||||
echo "Periodic System Setup - Pacman Wrapper & Hosts File"
|
echo "Periodic System Setup - Pacman Wrapper & Hosts File"
|
||||||
echo "==================================================="
|
echo "==================================================="
|
||||||
echo "Current Date: $(date)"
|
echo "Current Date: $(date)"
|
||||||
echo "User: $USER"
|
echo "User: $USER"
|
||||||
echo "Original user: ${SUDO_USER:-$USER}"
|
echo "Original user: $(get_actual_user)"
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
echo "Mode: Interactive (prompts enabled)"
|
echo "Mode: Interactive (prompts enabled)"
|
||||||
else
|
else
|
||||||
@ -54,7 +29,6 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Get the directory where this script is located
|
# Get the directory where this script is located
|
||||||
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
|
||||||
CONFIG_DIR="$(dirname "$SCRIPT_DIR")"
|
CONFIG_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
|
|
||||||
# Define paths
|
# Define paths
|
||||||
@ -142,7 +116,7 @@ create_execution_script() {
|
|||||||
sed \
|
sed \
|
||||||
-e "s|__PACMAN_WRAPPER_INSTALL__|$PACMAN_WRAPPER_INSTALL|g" \
|
-e "s|__PACMAN_WRAPPER_INSTALL__|$PACMAN_WRAPPER_INSTALL|g" \
|
||||||
-e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
-e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
||||||
"$TEMPLATE_MAINT_SCRIPT" > "$exec_script"
|
"$TEMPLATE_MAINT_SCRIPT" >"$exec_script"
|
||||||
|
|
||||||
chmod +x "$exec_script"
|
chmod +x "$exec_script"
|
||||||
echo "✓ Installed execution script from template: $exec_script"
|
echo "✓ Installed execution script from template: $exec_script"
|
||||||
@ -192,7 +166,7 @@ create_hosts_monitor_service() {
|
|||||||
|
|
||||||
# Install the monitor script from template with substitution
|
# Install the monitor script from template with substitution
|
||||||
sed -e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
sed -e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
||||||
"$TEMPLATE_HOSTS_MONITOR" > "$monitor_script"
|
"$TEMPLATE_HOSTS_MONITOR" >"$monitor_script"
|
||||||
chmod +x "$monitor_script"
|
chmod +x "$monitor_script"
|
||||||
echo "✓ Installed hosts monitor script from template: $monitor_script"
|
echo "✓ Installed hosts monitor script from template: $monitor_script"
|
||||||
|
|
||||||
@ -209,17 +183,17 @@ install_browser_preexec_wrapper() {
|
|||||||
|
|
||||||
local wrapper="/usr/local/bin/browser-preexec-wrapper"
|
local wrapper="/usr/local/bin/browser-preexec-wrapper"
|
||||||
sed -e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
sed -e "s|__HOSTS_INSTALL_SCRIPT__|$HOSTS_INSTALL_SCRIPT|g" \
|
||||||
"$TEMPLATE_BROWSER_WRAPPER" > "$wrapper"
|
"$TEMPLATE_BROWSER_WRAPPER" >"$wrapper"
|
||||||
chmod +x "$wrapper"
|
chmod +x "$wrapper"
|
||||||
echo "✓ Installed wrapper: $wrapper"
|
echo "✓ Installed wrapper: $wrapper"
|
||||||
|
|
||||||
# Allow passwordless execution of hosts installer for root-only actions
|
# Allow passwordless execution of hosts installer for root-only actions
|
||||||
local sudoers_file="/etc/sudoers.d/hosts-install-no-passwd"
|
local sudoers_file="/etc/sudoers.d/hosts-install-no-passwd"
|
||||||
if command -v visudo > /dev/null 2>&1; then
|
if command -v visudo >/dev/null 2>&1; then
|
||||||
echo "${SUDO_USER:-$USER} ALL=(ALL) NOPASSWD: $HOSTS_INSTALL_SCRIPT" > "$sudoers_file"
|
echo "${SUDO_USER:-$USER} ALL=(ALL) NOPASSWD: $HOSTS_INSTALL_SCRIPT" >"$sudoers_file"
|
||||||
chmod 440 "$sudoers_file"
|
chmod 440 "$sudoers_file"
|
||||||
# Validate syntax
|
# Validate syntax
|
||||||
visudo -c > /dev/null || echo "Warning: sudoers validation returned non-zero"
|
visudo -c >/dev/null || echo "Warning: sudoers validation returned non-zero"
|
||||||
echo "✓ Sudoers drop-in created: $sudoers_file"
|
echo "✓ Sudoers drop-in created: $sudoers_file"
|
||||||
else
|
else
|
||||||
echo "visudo not found; skipping sudoers drop-in"
|
echo "visudo not found; skipping sudoers drop-in"
|
||||||
|
|||||||
@ -4,48 +4,23 @@
|
|||||||
|
|
||||||
set -e # Exit on any error
|
set -e # Exit on any error
|
||||||
|
|
||||||
# Default to non-interactive mode
|
# Source common library for shared functions
|
||||||
INTERACTIVE_MODE=false
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/lib/common.sh"
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse interactive/help arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
parse_interactive_args "$@"
|
||||||
case $1 in
|
shift "$COMMON_ARGS_SHIFT"
|
||||||
-i | --interactive)
|
|
||||||
INTERACTIVE_MODE=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h | --help)
|
|
||||||
echo "Usage: $0 [OPTIONS]"
|
|
||||||
echo "Options:"
|
|
||||||
echo " -i, --interactive Enable interactive prompts (default: auto-yes)"
|
|
||||||
echo " -h, --help Show this help message"
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unknown option: $1"
|
|
||||||
echo "Use -h or --help for usage information"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Function to check and request sudo privileges
|
# Check for sudo privileges
|
||||||
check_sudo() {
|
require_root "$@"
|
||||||
if [[ $EUID -ne 0 ]]; then
|
|
||||||
echo "This script requires sudo privileges to create systemd services."
|
|
||||||
echo "Requesting sudo access..."
|
|
||||||
exec sudo "$0" "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check for sudo privileges after argument parsing
|
|
||||||
check_sudo "$@"
|
|
||||||
|
|
||||||
echo "Thorium Browser Auto-Startup Setup"
|
echo "Thorium Browser Auto-Startup Setup"
|
||||||
echo "=================================="
|
echo "=================================="
|
||||||
echo "Current Date: $(date)"
|
echo "Current Date: $(date)"
|
||||||
echo "User: $USER"
|
echo "User: $USER"
|
||||||
echo "Original user: ${SUDO_USER:-$USER}"
|
echo "Original user: $(get_actual_user)"
|
||||||
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
if [[ $INTERACTIVE_MODE == "true" ]]; then
|
||||||
echo "Mode: Interactive (prompts enabled)"
|
echo "Mode: Interactive (prompts enabled)"
|
||||||
else
|
else
|
||||||
@ -55,7 +30,7 @@ fi
|
|||||||
# Target URL
|
# Target URL
|
||||||
TARGET_URL="https://www.fitatu.com/app/planner"
|
TARGET_URL="https://www.fitatu.com/app/planner"
|
||||||
BROWSER_COMMAND="thorium-browser"
|
BROWSER_COMMAND="thorium-browser"
|
||||||
USER_HOME="/home/${SUDO_USER}"
|
USER_HOME="/home/$(get_actual_user)"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Target URL: $TARGET_URL"
|
echo "Target URL: $TARGET_URL"
|
||||||
@ -68,7 +43,7 @@ check_thorium_browser() {
|
|||||||
echo "1. Checking Thorium Browser Installation..."
|
echo "1. Checking Thorium Browser Installation..."
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
|
|
||||||
if ! command -v "$BROWSER_COMMAND" &> /dev/null; then
|
if ! command -v "$BROWSER_COMMAND" &>/dev/null; then
|
||||||
echo "Warning: Thorium browser not found in PATH"
|
echo "Warning: Thorium browser not found in PATH"
|
||||||
echo "Checking alternative locations..."
|
echo "Checking alternative locations..."
|
||||||
|
|
||||||
@ -129,7 +104,7 @@ create_launcher_script() {
|
|||||||
|
|
||||||
local launcher_script="/usr/local/bin/thorium-fitatu-launcher.sh"
|
local launcher_script="/usr/local/bin/thorium-fitatu-launcher.sh"
|
||||||
|
|
||||||
cat > "$launcher_script" << EOF
|
cat >"$launcher_script" <<EOF
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Thorium browser launcher for Fitatu website
|
# Thorium browser launcher for Fitatu website
|
||||||
# Created by setup_thorium_startup.sh on $(date)
|
# Created by setup_thorium_startup.sh on $(date)
|
||||||
@ -220,7 +195,7 @@ create_user_systemd_service() {
|
|||||||
sudo -u "${SUDO_USER}" mkdir -p "$user_systemd_dir"
|
sudo -u "${SUDO_USER}" mkdir -p "$user_systemd_dir"
|
||||||
|
|
||||||
# Create the service file
|
# Create the service file
|
||||||
sudo -u "${SUDO_USER}" tee "$service_file" > /dev/null << EOF
|
sudo -u "${SUDO_USER}" tee "$service_file" >/dev/null <<EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Launch Thorium Browser with Fitatu on Startup
|
Description=Launch Thorium Browser with Fitatu on Startup
|
||||||
After=graphical-session.target
|
After=graphical-session.target
|
||||||
@ -256,7 +231,7 @@ create_system_systemd_service() {
|
|||||||
|
|
||||||
local service_file="/etc/systemd/system/thorium-fitatu-startup.service"
|
local service_file="/etc/systemd/system/thorium-fitatu-startup.service"
|
||||||
|
|
||||||
cat > "$service_file" << EOF
|
cat >"$service_file" <<EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Launch Thorium Browser with Fitatu on Startup
|
Description=Launch Thorium Browser with Fitatu on Startup
|
||||||
After=multi-user.target network-online.target
|
After=multi-user.target network-online.target
|
||||||
@ -299,7 +274,7 @@ create_autostart_entry() {
|
|||||||
sudo -u "${SUDO_USER}" mkdir -p "$autostart_dir"
|
sudo -u "${SUDO_USER}" mkdir -p "$autostart_dir"
|
||||||
|
|
||||||
# Create desktop entry
|
# Create desktop entry
|
||||||
sudo -u "${SUDO_USER}" tee "$desktop_file" > /dev/null << EOF
|
sudo -u "${SUDO_USER}" tee "$desktop_file" >/dev/null <<EOF
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=Thorium Fitatu Startup
|
Name=Thorium Fitatu Startup
|
||||||
@ -352,7 +327,7 @@ create_i3_autostart() {
|
|||||||
create_user_enable_script() {
|
create_user_enable_script() {
|
||||||
local enable_script="$USER_HOME/.config/thorium-enable-service.sh"
|
local enable_script="$USER_HOME/.config/thorium-enable-service.sh"
|
||||||
|
|
||||||
sudo -u "${SUDO_USER}" tee "$enable_script" > /dev/null << 'EOF'
|
sudo -u "${SUDO_USER}" tee "$enable_script" >/dev/null <<'EOF'
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Script to enable thorium-fitatu-startup user service
|
# Script to enable thorium-fitatu-startup user service
|
||||||
# This runs once to enable the service, then removes itself
|
# This runs once to enable the service, then removes itself
|
||||||
|
|||||||
238
scripts/utils/convert_video.sh
Normal file
238
scripts/utils/convert_video.sh
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# convert_video.sh
|
||||||
|
#
|
||||||
|
# Convert video files to a target format (mp4 or webm) using ffmpeg.
|
||||||
|
# Accepts either a single video file or a directory (will recurse into subdirectories).
|
||||||
|
|
||||||
|
# Default settings
|
||||||
|
TARGET_FORMAT="mp4"
|
||||||
|
CRF="" # Will be set based on format if not specified
|
||||||
|
PRESET="medium"
|
||||||
|
DELETE_ORIGINAL=false
|
||||||
|
TARGET_PATH=""
|
||||||
|
|
||||||
|
# Video extensions to search for
|
||||||
|
ALL_VIDEO_EXTENSIONS=("mp4" "webm" "mkv" "avi" "mov" "wmv" "flv" "m4v" "mpg" "mpeg" "3gp" "ogv" "ts" "mts" "m2ts" "vob" "asf" "rm" "rmvb" "divx" "f4v")
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage:
|
||||||
|
$(basename "$0") [OPTIONS] PATH
|
||||||
|
|
||||||
|
Convert video files to mp4 or webm format using ffmpeg.
|
||||||
|
PATH can be a single video file or a directory (will recurse into subdirectories).
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-f FORMAT Target format: mp4 or webm (default: mp4)
|
||||||
|
-c CRF Quality level (default: 23 for mp4, 30 for webm; lower = better)
|
||||||
|
-p PRESET Encoding preset (default: medium)
|
||||||
|
Options: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow
|
||||||
|
-d Delete original file after successful conversion
|
||||||
|
-h Show this help
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
$(basename "$0") video.webm # Convert to mp4
|
||||||
|
$(basename "$0") -f webm video.mp4 # Convert to webm
|
||||||
|
$(basename "$0") /path/to/videos/ # Convert all videos in directory to mp4
|
||||||
|
$(basename "$0") -f webm -c 25 -d /path/to/videos/
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_ffmpeg() {
|
||||||
|
if ! command -v ffmpeg >/dev/null 2>&1; then
|
||||||
|
echo "Error: 'ffmpeg' is not installed or not in PATH." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_video_extensions_except() {
|
||||||
|
local exclude="$1"
|
||||||
|
local exts=()
|
||||||
|
for ext in "${ALL_VIDEO_EXTENSIONS[@]}"; do
|
||||||
|
if [[ "${ext,,}" != "${exclude,,}" ]]; then
|
||||||
|
exts+=("$ext")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "${exts[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
is_video_file() {
|
||||||
|
local file="$1"
|
||||||
|
local ext="${file##*.}"
|
||||||
|
ext="${ext,,}" # lowercase
|
||||||
|
|
||||||
|
for video_ext in "${ALL_VIDEO_EXTENSIONS[@]}"; do
|
||||||
|
if [[ "$ext" == "${video_ext,,}" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
convert_video() {
|
||||||
|
local input_file="$1"
|
||||||
|
local output_file="${input_file%.*}.${TARGET_FORMAT}"
|
||||||
|
|
||||||
|
# Skip if output already exists
|
||||||
|
if [[ -f "$output_file" ]]; then
|
||||||
|
log "Skipping '$input_file': output '$output_file' already exists"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Converting '$input_file' -> '$output_file'"
|
||||||
|
|
||||||
|
local ffmpeg_args=()
|
||||||
|
ffmpeg_args+=(-hide_banner -loglevel warning -i "$input_file")
|
||||||
|
|
||||||
|
if [[ "$TARGET_FORMAT" == "mp4" ]]; then
|
||||||
|
# H.264 codec for video and AAC for audio (maximum compatibility)
|
||||||
|
ffmpeg_args+=(-c:v libx264 -crf "$CRF" -preset "$PRESET")
|
||||||
|
ffmpeg_args+=(-c:a aac -b:a 192k)
|
||||||
|
ffmpeg_args+=(-movflags +faststart)
|
||||||
|
elif [[ "$TARGET_FORMAT" == "webm" ]]; then
|
||||||
|
# VP9 codec for video and Opus for audio
|
||||||
|
ffmpeg_args+=(-c:v libvpx-vp9 -crf "$CRF" -b:v 0)
|
||||||
|
ffmpeg_args+=(-c:a libopus -b:a 128k)
|
||||||
|
fi
|
||||||
|
|
||||||
|
ffmpeg_args+=("$output_file")
|
||||||
|
|
||||||
|
if ffmpeg "${ffmpeg_args[@]}"; then
|
||||||
|
log "Successfully converted '$input_file'"
|
||||||
|
|
||||||
|
if [[ "$DELETE_ORIGINAL" == true ]]; then
|
||||||
|
log "Deleting original: '$input_file'"
|
||||||
|
rm "$input_file"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log "Error converting '$input_file'"
|
||||||
|
[[ -f "$output_file" ]] && rm "$output_file"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
process_directory() {
|
||||||
|
local dir="$1"
|
||||||
|
local count=0
|
||||||
|
local failed=0
|
||||||
|
|
||||||
|
log "Searching for video files in '$dir'..."
|
||||||
|
|
||||||
|
# Build find command dynamically
|
||||||
|
local find_args=(-type f \()
|
||||||
|
local first=true
|
||||||
|
for ext in "${ALL_VIDEO_EXTENSIONS[@]}"; do
|
||||||
|
if [[ "${ext,,}" != "${TARGET_FORMAT,,}" ]]; then
|
||||||
|
if [[ "$first" == true ]]; then
|
||||||
|
first=false
|
||||||
|
else
|
||||||
|
find_args+=(-o)
|
||||||
|
fi
|
||||||
|
find_args+=(-iname "*.$ext")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
find_args+=(\) -print0)
|
||||||
|
|
||||||
|
while IFS= read -r -d '' file; do
|
||||||
|
((count++)) || true
|
||||||
|
if ! convert_video "$file"; then
|
||||||
|
((failed++)) || true
|
||||||
|
fi
|
||||||
|
done < <(find "$dir" "${find_args[@]}" 2>/dev/null)
|
||||||
|
|
||||||
|
log "Processed $count video file(s), $failed failed"
|
||||||
|
|
||||||
|
if [[ $count -eq 0 ]]; then
|
||||||
|
log "No video files found in '$dir'"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_args() {
|
||||||
|
while getopts ":f:c:p:dh" opt; do
|
||||||
|
case "$opt" in
|
||||||
|
f)
|
||||||
|
TARGET_FORMAT="${OPTARG,,}"
|
||||||
|
if [[ "$TARGET_FORMAT" != "mp4" && "$TARGET_FORMAT" != "webm" ]]; then
|
||||||
|
echo "Error: Format must be 'mp4' or 'webm'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
c) CRF="$OPTARG" ;;
|
||||||
|
p) PRESET="$OPTARG" ;;
|
||||||
|
d) DELETE_ORIGINAL=true ;;
|
||||||
|
h)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
:)
|
||||||
|
echo "Error: Option -$OPTARG requires an argument." >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
\?)
|
||||||
|
echo "Error: Invalid option -$OPTARG" >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift $((OPTIND - 1))
|
||||||
|
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
echo "Error: No path specified." >&2
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET_PATH="$1"
|
||||||
|
|
||||||
|
# Set default CRF based on format if not specified
|
||||||
|
if [[ -z "$CRF" ]]; then
|
||||||
|
if [[ "$TARGET_FORMAT" == "mp4" ]]; then
|
||||||
|
CRF=23
|
||||||
|
else
|
||||||
|
CRF=30
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
ensure_ffmpeg
|
||||||
|
parse_args "$@"
|
||||||
|
|
||||||
|
if [[ ! -e "$TARGET_PATH" ]]; then
|
||||||
|
echo "Error: Path '$TARGET_PATH' does not exist." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -f "$TARGET_PATH" ]]; then
|
||||||
|
# Single file
|
||||||
|
if [[ "${TARGET_PATH,,}" == *."$TARGET_FORMAT" ]]; then
|
||||||
|
log "File '$TARGET_PATH' is already in $TARGET_FORMAT format, skipping."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if is_video_file "$TARGET_PATH"; then
|
||||||
|
convert_video "$TARGET_PATH"
|
||||||
|
else
|
||||||
|
echo "Error: '$TARGET_PATH' is not a recognized video file." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
elif [[ -d "$TARGET_PATH" ]]; then
|
||||||
|
process_directory "$TARGET_PATH"
|
||||||
|
else
|
||||||
|
echo "Error: '$TARGET_PATH' is neither a file nor a directory." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Done!"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
@ -1,117 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# pdf_to_png.sh (magick-only backend, behaves like pdf_to_image)
|
|
||||||
#
|
|
||||||
# Convert one or more PDF files to image files using ImageMagick v7 `magick`.
|
|
||||||
# Default output format is jpg, but can be changed with -f.
|
|
||||||
|
|
||||||
OUTPUT_DIR=""
|
|
||||||
OUTPUT_FORMAT="jpg"
|
|
||||||
PDF_FILES=()
|
|
||||||
|
|
||||||
log() {
|
|
||||||
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat << EOF
|
|
||||||
Usage:
|
|
||||||
$(basename "$0") [OPTIONS] PDF_FILE [PDF_FILE...]
|
|
||||||
|
|
||||||
Convert one or more PDF files to images using ImageMagick 'magick'.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-o DIR Output directory (default: current directory)
|
|
||||||
-f FORMAT Output image format (default: jpg)
|
|
||||||
-h Show this help
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
$(basename "$0") file.pdf
|
|
||||||
$(basename "$0") -f png file1.pdf file2.pdf
|
|
||||||
$(basename "$0") -o out -f webp file.pdf
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_magick() {
|
|
||||||
if ! command -v magick > /dev/null 2>&1; then
|
|
||||||
echo "Error: 'magick' (ImageMagick v7) is not installed or not in PATH." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_args() {
|
|
||||||
local opt
|
|
||||||
OUTPUT_DIR=""
|
|
||||||
OUTPUT_FORMAT="jpg"
|
|
||||||
PDF_FILES=()
|
|
||||||
|
|
||||||
while getopts ":o:f:h" opt; do
|
|
||||||
case "$opt" in
|
|
||||||
o)
|
|
||||||
OUTPUT_DIR="$OPTARG"
|
|
||||||
;;
|
|
||||||
f)
|
|
||||||
OUTPUT_FORMAT="$OPTARG"
|
|
||||||
;;
|
|
||||||
h)
|
|
||||||
usage
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
shift $((OPTIND - 1))
|
|
||||||
|
|
||||||
if [[ $# -lt 1 ]]; then
|
|
||||||
echo "Error: at least one PDF file must be specified." >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
PDF_FILES=("$@")
|
|
||||||
|
|
||||||
if [[ -z ${OUTPUT_DIR:-} ]]; then
|
|
||||||
OUTPUT_DIR="${PWD}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -d $OUTPUT_DIR ]]; then
|
|
||||||
mkdir -p "$OUTPUT_DIR"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_pdf() {
|
|
||||||
local pdf_file="$1"
|
|
||||||
local base name out_pattern
|
|
||||||
|
|
||||||
name="$(basename "$pdf_file")"
|
|
||||||
base="${name%.*}"
|
|
||||||
out_pattern="${OUTPUT_DIR%/}/${base}_page-"
|
|
||||||
|
|
||||||
log "Converting '$pdf_file' to $OUTPUT_FORMAT using magick -> ${out_pattern}*.${OUTPUT_FORMAT}"
|
|
||||||
magick -density 300 "$pdf_file" -quality 90 "${out_pattern}%d.${OUTPUT_FORMAT}"
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
ensure_magick
|
|
||||||
parse_args "$@"
|
|
||||||
|
|
||||||
local pdf
|
|
||||||
for pdf in "${PDF_FILES[@]}"; do
|
|
||||||
if [[ ! -f $pdf ]]; then
|
|
||||||
echo "Warning: '$pdf' is not a regular file, skipping." >&2
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
convert_pdf "$pdf"
|
|
||||||
done
|
|
||||||
|
|
||||||
log "Done converting PDFs to ${OUTPUT_FORMAT}. Output directory: $OUTPUT_DIR"
|
|
||||||
}
|
|
||||||
|
|
||||||
main "$@"
|
|
||||||
@ -2,34 +2,21 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Source common library
|
||||||
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
# Re-run with sudo if needed for reading /etc/hosts
|
# Re-run with sudo if needed for reading /etc/hosts
|
||||||
if [[ $EUID -ne 0 ]] && [[ ! -r /etc/hosts ]]; then
|
if [[ $EUID -ne 0 ]] && [[ ! -r /etc/hosts ]]; then
|
||||||
exec sudo -E bash "$0" "$@"
|
exec sudo -E bash "$0" "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
WORK_DIR="${HOME}/.cache/android-adblock"
|
WORK_DIR="${HOME}/.cache/android-adblock"
|
||||||
|
ensure_dir "$WORK_DIR"
|
||||||
mkdir -p "$WORK_DIR"
|
|
||||||
|
|
||||||
# Colors
|
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
NC='\033[0m'
|
|
||||||
|
|
||||||
log() {
|
|
||||||
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S%z')]${NC} $*"
|
|
||||||
}
|
|
||||||
|
|
||||||
error() {
|
|
||||||
echo -e "${RED}[ERROR]${NC} $*" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
warn() {
|
|
||||||
echo -e "${YELLOW}[WARN]${NC} $*"
|
|
||||||
}
|
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
error "$@"
|
echo "[ERROR] $*" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,194 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
# Wrapper for backward compatibility - converts to mp4
|
||||||
set -euo pipefail
|
# See convert_video.sh for full options
|
||||||
|
exec "$(dirname "$(readlink -f "$0")")/convert_video.sh" -f mp4 "$@"
|
||||||
# to_mp4.sh
|
|
||||||
#
|
|
||||||
# Convert video files (non-mp4) to mp4 format using ffmpeg.
|
|
||||||
# Accepts either a single video file or a directory (will recurse into subdirectories).
|
|
||||||
|
|
||||||
# Video extensions to search for (excluding mp4 since that's our target)
|
|
||||||
VIDEO_EXTENSIONS=("webm" "mkv" "avi" "mov" "wmv" "flv" "m4v" "mpg" "mpeg" "3gp" "ogv" "ts" "mts" "m2ts" "vob" "asf" "rm" "rmvb" "divx" "f4v")
|
|
||||||
|
|
||||||
# Conversion settings
|
|
||||||
CRF=23 # Quality (0-51, lower = better quality, 18-28 is reasonable for H.264)
|
|
||||||
PRESET="medium" # Encoding speed: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow
|
|
||||||
DELETE_ORIGINAL=false
|
|
||||||
|
|
||||||
log() {
|
|
||||||
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat <<EOF
|
|
||||||
Usage:
|
|
||||||
$(basename "$0") [OPTIONS] PATH
|
|
||||||
|
|
||||||
Convert video files to mp4 format using ffmpeg.
|
|
||||||
PATH can be a single video file or a directory (will recurse into subdirectories).
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-c CRF Quality level 0-51 (default: 23, lower = better quality)
|
|
||||||
-p PRESET Encoding preset (default: medium)
|
|
||||||
Options: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow
|
|
||||||
-d Delete original file after successful conversion
|
|
||||||
-h Show this help
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
$(basename "$0") video.webm
|
|
||||||
$(basename "$0") /path/to/videos/
|
|
||||||
$(basename "$0") -c 20 -d /path/to/videos/
|
|
||||||
$(basename "$0") -p slow -c 18 movie.mkv
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_ffmpeg() {
|
|
||||||
if ! command -v ffmpeg >/dev/null 2>&1; then
|
|
||||||
echo "Error: 'ffmpeg' is not installed or not in PATH." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
is_video_file() {
|
|
||||||
local file="$1"
|
|
||||||
local ext="${file##*.}"
|
|
||||||
ext="${ext,,}" # lowercase
|
|
||||||
|
|
||||||
for video_ext in "${VIDEO_EXTENSIONS[@]}"; do
|
|
||||||
if [[ "$ext" == "${video_ext,,}" ]]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_to_mp4() {
|
|
||||||
local input_file="$1"
|
|
||||||
local output_file="${input_file%.*}.mp4"
|
|
||||||
|
|
||||||
# Skip if output already exists
|
|
||||||
if [[ -f "$output_file" ]]; then
|
|
||||||
log "Skipping '$input_file': output '$output_file' already exists"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Converting '$input_file' -> '$output_file'"
|
|
||||||
|
|
||||||
# Use H.264 codec for video and AAC for audio (maximum compatibility)
|
|
||||||
if ffmpeg -hide_banner -loglevel warning -i "$input_file" \
|
|
||||||
-c:v libx264 -crf "$CRF" -preset "$PRESET" \
|
|
||||||
-c:a aac -b:a 192k \
|
|
||||||
-movflags +faststart \
|
|
||||||
"$output_file"; then
|
|
||||||
log "Successfully converted '$input_file'"
|
|
||||||
|
|
||||||
if [[ "$DELETE_ORIGINAL" == true ]]; then
|
|
||||||
log "Deleting original: '$input_file'"
|
|
||||||
rm "$input_file"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
log "Error converting '$input_file'"
|
|
||||||
# Remove partial output file if it exists
|
|
||||||
[[ -f "$output_file" ]] && rm "$output_file"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
process_directory() {
|
|
||||||
local dir="$1"
|
|
||||||
local count=0
|
|
||||||
local failed=0
|
|
||||||
|
|
||||||
log "Searching for video files in '$dir'..."
|
|
||||||
|
|
||||||
# Find all video files (case-insensitive)
|
|
||||||
while IFS= read -r -d '' file; do
|
|
||||||
# Skip mp4 files
|
|
||||||
if [[ "${file,,}" == *.mp4 ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
((count++)) || true
|
|
||||||
if ! convert_to_mp4 "$file"; then
|
|
||||||
((failed++)) || true
|
|
||||||
fi
|
|
||||||
done < <(find "$dir" -type f \( -iname "*.webm" -o -iname "*.mkv" -o -iname "*.avi" -o -iname "*.mov" \
|
|
||||||
-o -iname "*.wmv" -o -iname "*.flv" -o -iname "*.m4v" -o -iname "*.mpg" -o -iname "*.mpeg" \
|
|
||||||
-o -iname "*.3gp" -o -iname "*.ogv" -o -iname "*.ts" -o -iname "*.mts" -o -iname "*.m2ts" \
|
|
||||||
-o -iname "*.vob" -o -iname "*.asf" -o -iname "*.rm" -o -iname "*.rmvb" -o -iname "*.divx" \
|
|
||||||
-o -iname "*.f4v" \) -print0 2>/dev/null)
|
|
||||||
|
|
||||||
log "Processed $count video file(s), $failed failed"
|
|
||||||
|
|
||||||
if [[ $count -eq 0 ]]; then
|
|
||||||
log "No video files found in '$dir'"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_args() {
|
|
||||||
while getopts ":c:p:dh" opt; do
|
|
||||||
case "$opt" in
|
|
||||||
c) CRF="$OPTARG" ;;
|
|
||||||
p) PRESET="$OPTARG" ;;
|
|
||||||
d) DELETE_ORIGINAL=true ;;
|
|
||||||
h)
|
|
||||||
usage
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
:)
|
|
||||||
echo "Error: Option -$OPTARG requires an argument." >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
\?)
|
|
||||||
echo "Error: Invalid option -$OPTARG" >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
shift $((OPTIND - 1))
|
|
||||||
|
|
||||||
if [[ $# -lt 1 ]]; then
|
|
||||||
echo "Error: No path specified." >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
TARGET_PATH="$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
ensure_ffmpeg
|
|
||||||
parse_args "$@"
|
|
||||||
|
|
||||||
if [[ ! -e "$TARGET_PATH" ]]; then
|
|
||||||
echo "Error: Path '$TARGET_PATH' does not exist." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -f "$TARGET_PATH" ]]; then
|
|
||||||
# Single file
|
|
||||||
if [[ "${TARGET_PATH,,}" == *.mp4 ]]; then
|
|
||||||
log "File '$TARGET_PATH' is already in mp4 format, skipping."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if is_video_file "$TARGET_PATH"; then
|
|
||||||
convert_to_mp4 "$TARGET_PATH"
|
|
||||||
else
|
|
||||||
echo "Error: '$TARGET_PATH' is not a recognized video file." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
elif [[ -d "$TARGET_PATH" ]]; then
|
|
||||||
# Directory
|
|
||||||
process_directory "$TARGET_PATH"
|
|
||||||
else
|
|
||||||
echo "Error: '$TARGET_PATH' is neither a file nor a directory." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Done!"
|
|
||||||
}
|
|
||||||
|
|
||||||
main "$@"
|
|
||||||
|
|||||||
@ -1,206 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
# Wrapper for backward compatibility - converts to webm
|
||||||
set -euo pipefail
|
# See convert_video.sh for full options
|
||||||
|
exec "$(dirname "$(readlink -f "$0")")/convert_video.sh" -f webm "$@"
|
||||||
# to_webm.sh
|
|
||||||
#
|
|
||||||
# Convert video files (non-webm) to webm format using ffmpeg.
|
|
||||||
# Accepts either a single video file or a directory (will recurse into subdirectories).
|
|
||||||
|
|
||||||
# Video extensions to search for (excluding webm since that's our target)
|
|
||||||
VIDEO_EXTENSIONS=("mp4" "mkv" "avi" "mov" "wmv" "flv" "m4v" "mpg" "mpeg" "3gp" "ogv" "ts" "mts" "m2ts" "vob" "asf" "rm" "rmvb" "divx" "f4v")
|
|
||||||
|
|
||||||
# Conversion settings
|
|
||||||
CRF=30 # Quality (0-63, lower = better quality, 23-30 is reasonable)
|
|
||||||
PRESET="medium" # Encoding speed: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow
|
|
||||||
DELETE_ORIGINAL=false
|
|
||||||
|
|
||||||
log() {
|
|
||||||
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat <<EOF
|
|
||||||
Usage:
|
|
||||||
$(basename "$0") [OPTIONS] PATH
|
|
||||||
|
|
||||||
Convert video files to webm format using ffmpeg.
|
|
||||||
PATH can be a single video file or a directory (will recurse into subdirectories).
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-c CRF Quality level 0-63 (default: 30, lower = better quality)
|
|
||||||
-p PRESET Encoding preset (default: medium)
|
|
||||||
Options: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow
|
|
||||||
-d Delete original file after successful conversion
|
|
||||||
-h Show this help
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
$(basename "$0") video.mp4
|
|
||||||
$(basename "$0") /path/to/videos/
|
|
||||||
$(basename "$0") -c 25 -d /path/to/videos/
|
|
||||||
$(basename "$0") -p slow -c 20 movie.mkv
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_ffmpeg() {
|
|
||||||
if ! command -v ffmpeg >/dev/null 2>&1; then
|
|
||||||
echo "Error: 'ffmpeg' is not installed or not in PATH." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
build_extension_pattern() {
|
|
||||||
# Build a find pattern for video extensions
|
|
||||||
local pattern=""
|
|
||||||
for ext in "${VIDEO_EXTENSIONS[@]}"; do
|
|
||||||
if [[ -n "$pattern" ]]; then
|
|
||||||
pattern="$pattern -o"
|
|
||||||
fi
|
|
||||||
pattern="$pattern -iname *.$ext"
|
|
||||||
done
|
|
||||||
echo "$pattern"
|
|
||||||
}
|
|
||||||
|
|
||||||
is_video_file() {
|
|
||||||
local file="$1"
|
|
||||||
local ext="${file##*.}"
|
|
||||||
ext="${ext,,}" # lowercase
|
|
||||||
|
|
||||||
for video_ext in "${VIDEO_EXTENSIONS[@]}"; do
|
|
||||||
if [[ "$ext" == "${video_ext,,}" ]]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_to_webm() {
|
|
||||||
local input_file="$1"
|
|
||||||
local output_file="${input_file%.*}.webm"
|
|
||||||
|
|
||||||
# Skip if output already exists
|
|
||||||
if [[ -f "$output_file" ]]; then
|
|
||||||
log "Skipping '$input_file': output '$output_file' already exists"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Converting '$input_file' -> '$output_file'"
|
|
||||||
|
|
||||||
# Use VP9 codec for video and Opus for audio (good quality, wide compatibility)
|
|
||||||
if ffmpeg -hide_banner -loglevel warning -i "$input_file" \
|
|
||||||
-c:v libvpx-vp9 -crf "$CRF" -b:v 0 \
|
|
||||||
-c:a libopus -b:a 128k \
|
|
||||||
-preset "$PRESET" \
|
|
||||||
"$output_file"; then
|
|
||||||
log "Successfully converted '$input_file'"
|
|
||||||
|
|
||||||
if [[ "$DELETE_ORIGINAL" == true ]]; then
|
|
||||||
log "Deleting original: '$input_file'"
|
|
||||||
rm "$input_file"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
log "Error converting '$input_file'"
|
|
||||||
# Remove partial output file if it exists
|
|
||||||
[[ -f "$output_file" ]] && rm "$output_file"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
process_directory() {
|
|
||||||
local dir="$1"
|
|
||||||
local count=0
|
|
||||||
local failed=0
|
|
||||||
|
|
||||||
log "Searching for video files in '$dir'..."
|
|
||||||
|
|
||||||
# Find all video files (case-insensitive)
|
|
||||||
while IFS= read -r -d '' file; do
|
|
||||||
# Skip webm files
|
|
||||||
if [[ "${file,,}" == *.webm ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
((count++)) || true
|
|
||||||
if ! convert_to_webm "$file"; then
|
|
||||||
((failed++)) || true
|
|
||||||
fi
|
|
||||||
done < <(find "$dir" -type f \( -iname "*.mp4" -o -iname "*.mkv" -o -iname "*.avi" -o -iname "*.mov" \
|
|
||||||
-o -iname "*.wmv" -o -iname "*.flv" -o -iname "*.m4v" -o -iname "*.mpg" -o -iname "*.mpeg" \
|
|
||||||
-o -iname "*.3gp" -o -iname "*.ogv" -o -iname "*.ts" -o -iname "*.mts" -o -iname "*.m2ts" \
|
|
||||||
-o -iname "*.vob" -o -iname "*.asf" -o -iname "*.rm" -o -iname "*.rmvb" -o -iname "*.divx" \
|
|
||||||
-o -iname "*.f4v" \) -print0 2>/dev/null)
|
|
||||||
|
|
||||||
log "Processed $count video file(s), $failed failed"
|
|
||||||
|
|
||||||
if [[ $count -eq 0 ]]; then
|
|
||||||
log "No video files found in '$dir'"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_args() {
|
|
||||||
while getopts ":c:p:dh" opt; do
|
|
||||||
case "$opt" in
|
|
||||||
c) CRF="$OPTARG" ;;
|
|
||||||
p) PRESET="$OPTARG" ;;
|
|
||||||
d) DELETE_ORIGINAL=true ;;
|
|
||||||
h)
|
|
||||||
usage
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
:)
|
|
||||||
echo "Error: Option -$OPTARG requires an argument." >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
\?)
|
|
||||||
echo "Error: Invalid option -$OPTARG" >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
shift $((OPTIND - 1))
|
|
||||||
|
|
||||||
if [[ $# -lt 1 ]]; then
|
|
||||||
echo "Error: No path specified." >&2
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
TARGET_PATH="$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
ensure_ffmpeg
|
|
||||||
parse_args "$@"
|
|
||||||
|
|
||||||
if [[ ! -e "$TARGET_PATH" ]]; then
|
|
||||||
echo "Error: Path '$TARGET_PATH' does not exist." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -f "$TARGET_PATH" ]]; then
|
|
||||||
# Single file
|
|
||||||
if [[ "${TARGET_PATH,,}" == *.webm ]]; then
|
|
||||||
log "File '$TARGET_PATH' is already in webm format, skipping."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if is_video_file "$TARGET_PATH"; then
|
|
||||||
convert_to_webm "$TARGET_PATH"
|
|
||||||
else
|
|
||||||
echo "Error: '$TARGET_PATH' is not a recognized video file." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
elif [[ -d "$TARGET_PATH" ]]; then
|
|
||||||
# Directory
|
|
||||||
process_directory "$TARGET_PATH"
|
|
||||||
else
|
|
||||||
echo "Error: '$TARGET_PATH' is neither a file nor a directory." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Done!"
|
|
||||||
}
|
|
||||||
|
|
||||||
main "$@"
|
|
||||||
|
|||||||
@ -2,29 +2,21 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Source common library
|
||||||
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
# Re-run with sudo if needed for reading /etc/hosts
|
# Re-run with sudo if needed for reading /etc/hosts
|
||||||
if [[ $EUID -ne 0 ]] && [[ ! -r /etc/hosts ]]; then
|
if [[ $EUID -ne 0 ]] && [[ ! -r /etc/hosts ]]; then
|
||||||
exec sudo -E bash "$0" "$@"
|
exec sudo -E bash "$0" "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
WORK_DIR="${HOME}/.cache/android-adblock"
|
WORK_DIR="${HOME}/.cache/android-adblock"
|
||||||
mkdir -p "$WORK_DIR"
|
ensure_dir "$WORK_DIR"
|
||||||
|
|
||||||
# Color codes for output
|
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
log() {
|
|
||||||
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S%z')]${NC} $*"
|
|
||||||
}
|
|
||||||
|
|
||||||
error() {
|
|
||||||
echo -e "${RED}[ERROR]${NC} $*" >&2
|
|
||||||
}
|
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
error "$@"
|
echo "[ERROR] $*" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user