mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-07-04 15:43:06 +02:00
feat: fix stepmania and organize downloads scripts
This commit is contained in:
parent
684e3a1bdb
commit
626ab92699
143
scripts/fixes/fix_stepmania.sh
Executable file
143
scripts/fixes/fix_stepmania.sh
Executable file
@ -0,0 +1,143 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Fix StepMania AUR build failure due to missing vorbis libraries in linker
|
||||||
|
#
|
||||||
|
# Error addressed:
|
||||||
|
# /usr/bin/ld: /usr/local/lib/libavcodec.a(libvorbisenc.o): undefined reference to symbol 'vorbis_encode_setup_vbr'
|
||||||
|
# /usr/bin/ld: /usr/lib/libvorbisenc.so.2: error adding symbols: DSO missing from command line
|
||||||
|
#
|
||||||
|
# Cause:
|
||||||
|
# Static libavcodec.a depends on libvorbisenc but cmake doesn't add it to linker flags
|
||||||
|
#
|
||||||
|
# Solution:
|
||||||
|
# Add vorbis libraries to LDFLAGS before building
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# ./fix_stepmania.sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
source "$SCRIPT_DIR/../lib/common.sh"
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
|
||||||
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
|
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
|
||||||
|
log_success() { echo -e "${GREEN}[OK]${NC} $*"; }
|
||||||
|
|
||||||
|
check_dependencies() {
|
||||||
|
log_info "Checking dependencies..."
|
||||||
|
|
||||||
|
local missing=()
|
||||||
|
|
||||||
|
# Check for vorbis libraries
|
||||||
|
if ! pacman -Q libvorbis &>/dev/null; then
|
||||||
|
missing+=("libvorbis")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for yay or paru
|
||||||
|
if ! has_cmd yay && ! has_cmd paru; then
|
||||||
|
log_error "Neither yay nor paru found. Please install an AUR helper."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||||
|
log_warn "Missing packages: ${missing[*]}"
|
||||||
|
log_info "Installing missing dependencies..."
|
||||||
|
sudo pacman -S --needed "${missing[@]}"
|
||||||
|
else
|
||||||
|
log_success "All dependencies present"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_aur_helper() {
|
||||||
|
if has_cmd yay; then
|
||||||
|
echo "yay"
|
||||||
|
elif has_cmd paru; then
|
||||||
|
echo "paru"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_stepmania() {
|
||||||
|
local aur_helper
|
||||||
|
aur_helper=$(get_aur_helper)
|
||||||
|
|
||||||
|
log_info "Building StepMania with vorbis libraries in LDFLAGS..."
|
||||||
|
log_info "Using AUR helper: $aur_helper"
|
||||||
|
|
||||||
|
# Export LDFLAGS with vorbis libraries to fix the linking issue
|
||||||
|
# The static libavcodec.a needs these shared libraries
|
||||||
|
export LDFLAGS="${LDFLAGS:-} -lvorbis -lvorbisenc -lvorbisfile -logg"
|
||||||
|
|
||||||
|
log_info "LDFLAGS set to: $LDFLAGS"
|
||||||
|
|
||||||
|
# Clean any previous failed build
|
||||||
|
if [[ -d "$HOME/.cache/$aur_helper/stepmania" ]]; then
|
||||||
|
log_info "Cleaning previous build cache..."
|
||||||
|
rm -rf "$HOME/.cache/$aur_helper/stepmania"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build with the modified LDFLAGS
|
||||||
|
# --noconfirm for non-interactive, --cleanafter to cleanup
|
||||||
|
"$aur_helper" -S --rebuild --noconfirm stepmania
|
||||||
|
|
||||||
|
log_success "StepMania built successfully!"
|
||||||
|
}
|
||||||
|
|
||||||
|
alternative_fix_info() {
|
||||||
|
cat <<'EOF'
|
||||||
|
|
||||||
|
If the automated fix doesn't work, try these alternatives:
|
||||||
|
|
||||||
|
1. Use system ffmpeg instead of static libavcodec:
|
||||||
|
- Edit the PKGBUILD to use shared ffmpeg libraries
|
||||||
|
- Remove any bundled/static ffmpeg references
|
||||||
|
|
||||||
|
2. Manually edit CMakeLists.txt:
|
||||||
|
- Find target_link_libraries for StepMania executable
|
||||||
|
- Add: vorbis vorbisenc vorbisfile ogg
|
||||||
|
|
||||||
|
3. Check if /usr/local/lib/libavcodec.a is from a custom ffmpeg build:
|
||||||
|
- If so, rebuild ffmpeg with --enable-shared or remove the static lib
|
||||||
|
- System ffmpeg in /usr/lib should be preferred
|
||||||
|
|
||||||
|
4. Use the stepmania-git package instead which may have different build config
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
echo "======================================"
|
||||||
|
echo " StepMania Build Fix"
|
||||||
|
echo "======================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
check_dependencies
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
log_info "This fix adds vorbis libraries to LDFLAGS to resolve:"
|
||||||
|
log_info " 'undefined reference to symbol vorbis_encode_setup_vbr'"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
read -rp "Proceed with rebuild? [Y/n] " response
|
||||||
|
case "$response" in
|
||||||
|
[nN][oO] | [nN])
|
||||||
|
log_info "Aborted."
|
||||||
|
alternative_fix_info
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
build_stepmania
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
@ -10,10 +10,12 @@ set -euo pipefail
|
|||||||
# Defaults / flags
|
# Defaults / flags
|
||||||
DRY_RUN=false
|
DRY_RUN=false
|
||||||
SAMPLE_LIMIT=20
|
SAMPLE_LIMIT=20
|
||||||
|
# Size threshold for "too big" files (in bytes) - default 100MB
|
||||||
|
SIZE_THRESHOLD=$((100 * 1024 * 1024))
|
||||||
|
|
||||||
# Simple usage helper
|
# Simple usage helper
|
||||||
usage() {
|
usage() {
|
||||||
cat << EOF
|
cat <<EOF
|
||||||
Usage: $(basename "$0") [--dry-run|-n] [--sample=N]
|
Usage: $(basename "$0") [--dry-run|-n] [--sample=N]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
@ -26,6 +28,7 @@ EOF
|
|||||||
# Define directories to scan
|
# Define directories to scan
|
||||||
DOWNLOADS_DIR="$HOME/Downloads"
|
DOWNLOADS_DIR="$HOME/Downloads"
|
||||||
HOME_DIR="$HOME"
|
HOME_DIR="$HOME"
|
||||||
|
TOO_BIG_DIR="$DOWNLOADS_DIR/too_big"
|
||||||
# Prefer a temp dir outside Downloads to avoid recursive re-inclusion; fall back to /tmp
|
# Prefer a temp dir outside Downloads to avoid recursive re-inclusion; fall back to /tmp
|
||||||
TEMP_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/media_organize_$$"
|
TEMP_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/media_organize_$$"
|
||||||
|
|
||||||
@ -36,372 +39,472 @@ VIDEO_EXTENSIONS=("mp4" "avi" "mkv" "mov" "wmv" "flv" "webm" "m4v" "3gp" "ogv" "
|
|||||||
|
|
||||||
# Function to log messages with timestamp
|
# Function to log messages with timestamp
|
||||||
log() {
|
log() {
|
||||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Parse CLI flags early
|
# Parse CLI flags early
|
||||||
while [[ ${1:-} =~ ^- ]]; do
|
while [[ ${1:-} =~ ^- ]]; do
|
||||||
case "${1}" in
|
case "${1}" in
|
||||||
-n | --dry-run)
|
-n | --dry-run)
|
||||||
DRY_RUN=true
|
DRY_RUN=true
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--sample=*)
|
--sample=*)
|
||||||
SAMPLE_LIMIT="${1#*=}"
|
SAMPLE_LIMIT="${1#*=}"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
-h | --help)
|
-h | --help)
|
||||||
usage
|
usage
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown option: $1" >&2
|
echo "Unknown option: $1" >&2
|
||||||
usage
|
usage
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# Function to check if file has media extension
|
# Function to check if file has media extension
|
||||||
is_media_file() {
|
is_media_file() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local extension="${file##*.}"
|
local extension="${file##*.}"
|
||||||
extension=$(echo "$extension" | tr '[:upper:]' '[:lower:]')
|
extension=$(echo "$extension" | tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
# Check if it's an image
|
# Check if it's an image
|
||||||
for ext in "${IMAGE_EXTENSIONS[@]}"; do
|
for ext in "${IMAGE_EXTENSIONS[@]}"; do
|
||||||
if [[ $extension == "$ext" ]]; then
|
if [[ $extension == "$ext" ]]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Check if it's a video
|
# Check if it's a video
|
||||||
for ext in "${VIDEO_EXTENSIONS[@]}"; do
|
for ext in "${VIDEO_EXTENSIONS[@]}"; do
|
||||||
if [[ $extension == "$ext" ]]; then
|
if [[ $extension == "$ext" ]]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check if file is too big for archiving
|
||||||
|
is_too_big() {
|
||||||
|
local file="$1"
|
||||||
|
local size
|
||||||
|
size=$(stat -c%s "$file" 2>/dev/null || echo "0")
|
||||||
|
[[ $size -gt $SIZE_THRESHOLD ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to move oversized files to too_big directory
|
||||||
|
move_big_files() {
|
||||||
|
local files=("$@")
|
||||||
|
local moved_count=0
|
||||||
|
|
||||||
|
if [[ ${#files[@]} -eq 0 ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create too_big directory if it doesn't exist
|
||||||
|
mkdir -p "$TOO_BIG_DIR"
|
||||||
|
|
||||||
|
log "Moving ${#files[@]} oversized files to $TOO_BIG_DIR..."
|
||||||
|
|
||||||
|
for file in "${files[@]}"; do
|
||||||
|
if [[ -f $file ]]; then
|
||||||
|
local basename
|
||||||
|
basename=$(basename "$file")
|
||||||
|
local dest="$TOO_BIG_DIR/$basename"
|
||||||
|
|
||||||
|
# Handle filename collision
|
||||||
|
if [[ -f $dest ]]; then
|
||||||
|
local timestamp
|
||||||
|
timestamp=$(date '+%Y%m%d_%H%M%S')
|
||||||
|
local name="${basename%.*}"
|
||||||
|
local ext="${basename##*.}"
|
||||||
|
if [[ $name == "$ext" ]]; then
|
||||||
|
dest="$TOO_BIG_DIR/${name}_${timestamp}"
|
||||||
|
else
|
||||||
|
dest="$TOO_BIG_DIR/${name}_${timestamp}.${ext}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if mv "$file" "$dest" 2>/dev/null; then
|
||||||
|
log "Moved (too big): $(basename "$file") -> $dest"
|
||||||
|
moved_count=$((moved_count + 1))
|
||||||
|
else
|
||||||
|
log "ERROR: Failed to move $(basename "$file")"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
log "Successfully moved $moved_count oversized files."
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to find media files in a directory (non-recursive for home, avoid common system dirs)
|
# Function to find media files in a directory (non-recursive for home, avoid common system dirs)
|
||||||
find_media_files() {
|
find_media_files() {
|
||||||
local search_dir="$1"
|
local search_dir="$1"
|
||||||
local files=()
|
local files=()
|
||||||
# Directories to exclude under Downloads
|
# Directories to exclude under Downloads
|
||||||
local -a EXCLUDES=(
|
local -a EXCLUDES=(
|
||||||
".git" ".hg" ".svn" ".cache" "node_modules" "dist" "build" "out" "target" "coverage" "__pycache__" "venv" ".venv"
|
".git" ".hg" ".svn" ".cache" "node_modules" "dist" "build" "out" "target" "coverage" "__pycache__" "venv" ".venv"
|
||||||
# previous staging dirs created by this script
|
# previous staging dirs created by this script
|
||||||
".media_organize_" "media_organize_"
|
".media_organize_" "media_organize_"
|
||||||
)
|
# too_big folder for oversized files
|
||||||
|
"too_big"
|
||||||
|
)
|
||||||
|
|
||||||
if [[ $search_dir == "$HOME_DIR" ]]; then
|
if [[ $search_dir == "$HOME_DIR" ]]; then
|
||||||
# For home directory, only check files directly in ~ (not subdirectories)
|
# For home directory, only check files directly in ~ (not subdirectories)
|
||||||
# Exclude common system/config directories
|
# Exclude common system/config directories
|
||||||
while IFS= read -r -d '' file; do
|
while IFS= read -r -d '' file; do
|
||||||
local basename
|
local basename
|
||||||
basename=$(basename "$file")
|
basename=$(basename "$file")
|
||||||
# Skip hidden files and common system directories
|
# Skip hidden files and common system directories
|
||||||
if [[ ! $basename =~ ^\. ]] && [[ -f $file ]]; then
|
if [[ ! $basename =~ ^\. ]] && [[ -f $file ]]; then
|
||||||
if is_media_file "$file"; then
|
if is_media_file "$file"; then
|
||||||
files+=("$file")
|
files+=("$file")
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done < <(find "$search_dir" -maxdepth 1 -type f -print0 2> /dev/null)
|
done < <(find "$search_dir" -maxdepth 1 -type f -print0 2>/dev/null)
|
||||||
else
|
else
|
||||||
# For Downloads, search recursively, pruning excluded directories
|
# For Downloads, search recursively, pruning excluded directories
|
||||||
# Build prune expression
|
# Build prune expression
|
||||||
local prune_expr=()
|
local prune_expr=()
|
||||||
for ex in "${EXCLUDES[@]}"; do
|
for ex in "${EXCLUDES[@]}"; do
|
||||||
prune_expr+=(-name "$ex*" -o)
|
prune_expr+=(-name "$ex*" -o)
|
||||||
done
|
done
|
||||||
# Remove trailing -o
|
# Remove trailing -o
|
||||||
unset 'prune_expr[${#prune_expr[@]}-1]'
|
unset 'prune_expr[${#prune_expr[@]}-1]'
|
||||||
|
|
||||||
while IFS= read -r -d '' file; do
|
while IFS= read -r -d '' file; do
|
||||||
if is_media_file "$file"; then
|
if is_media_file "$file"; then
|
||||||
files+=("$file")
|
files+=("$file")
|
||||||
fi
|
fi
|
||||||
done < <(find "$search_dir" \( -type d \( "${prune_expr[@]}" \) -prune \) -o -type f -print0 2> /dev/null)
|
done < <(find "$search_dir" \( -type d \( "${prune_expr[@]}" \) -prune \) -o -type f -print0 2>/dev/null)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf '%s\n' "${files[@]}"
|
printf '%s\n' "${files[@]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Function to create timestamped zip archive
|
# Function to create timestamped zip archive
|
||||||
create_media_archive() {
|
create_media_archive() {
|
||||||
local files=("$@")
|
local files=("$@")
|
||||||
|
|
||||||
if [[ ${#files[@]} -eq 0 ]]; then
|
if [[ ${#files[@]} -eq 0 ]]; then
|
||||||
log "No media files found to archive."
|
log "No media files found to archive."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create timestamp for archive name
|
# Create timestamp for archive name
|
||||||
local timestamp
|
local timestamp
|
||||||
timestamp=$(date '+%Y%m%d_%H%M%S')
|
timestamp=$(date '+%Y%m%d_%H%M%S')
|
||||||
local archive_name="media_archive_${timestamp}.zip"
|
local archive_name="media_archive_${timestamp}.zip"
|
||||||
local archive_path="$DOWNLOADS_DIR/$archive_name"
|
local archive_path="$DOWNLOADS_DIR/$archive_name"
|
||||||
|
|
||||||
# Create temporary directory (fallback to /tmp if needed)
|
# Create temporary directory (fallback to /tmp if needed)
|
||||||
if ! mkdir -p "$TEMP_DIR" 2> /dev/null; then
|
if ! mkdir -p "$TEMP_DIR" 2>/dev/null; then
|
||||||
TEMP_DIR="/tmp/media_organize_$$"
|
TEMP_DIR="/tmp/media_organize_$$"
|
||||||
mkdir -p "$TEMP_DIR"
|
mkdir -p "$TEMP_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Ensure temp dir is cleaned up on function return; trap unsets itself after running
|
# Ensure temp dir is cleaned up on function return; trap unsets itself after running
|
||||||
trap 'rm -rf "$TEMP_DIR" 2>/dev/null || true; trap - RETURN' RETURN
|
trap 'rm -rf "$TEMP_DIR" 2>/dev/null || true; trap - RETURN' RETURN
|
||||||
|
|
||||||
log "Found ${#files[@]} media files to archive."
|
log "Found ${#files[@]} media files to archive."
|
||||||
log "Creating archive: $archive_path"
|
log "Creating archive: $archive_path"
|
||||||
|
|
||||||
# Copy files to temp directory maintaining relative structure
|
# Copy files to temp directory maintaining relative structure
|
||||||
local successfully_copied=()
|
local successfully_copied=()
|
||||||
local copy_errors=0
|
local copy_errors=0
|
||||||
|
|
||||||
for file in "${files[@]}"; do
|
for file in "${files[@]}"; do
|
||||||
if [[ -f $file ]]; then
|
if [[ -f $file ]]; then
|
||||||
local relative_path=""
|
local relative_path=""
|
||||||
if [[ $file == "$DOWNLOADS_DIR"* ]]; then
|
if [[ $file == "$DOWNLOADS_DIR"* ]]; then
|
||||||
relative_path="downloads/${file#"$DOWNLOADS_DIR"/}"
|
relative_path="downloads/${file#"$DOWNLOADS_DIR"/}"
|
||||||
else
|
else
|
||||||
relative_path="home/${file#"$HOME_DIR"/}"
|
relative_path="home/${file#"$HOME_DIR"/}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local temp_file="$TEMP_DIR/$relative_path"
|
local temp_file="$TEMP_DIR/$relative_path"
|
||||||
local temp_dir
|
local temp_dir
|
||||||
temp_dir=$(dirname "$temp_file")
|
temp_dir=$(dirname "$temp_file")
|
||||||
|
|
||||||
mkdir -p "$temp_dir"
|
mkdir -p "$temp_dir"
|
||||||
# Check readability first to provide a clearer error
|
# Check readability first to provide a clearer error
|
||||||
if [[ ! -r $file ]]; then
|
if [[ ! -r $file ]]; then
|
||||||
log "WARNING: Cannot read $file (permission denied?)"
|
log "WARNING: Cannot read $file (permission denied?)"
|
||||||
((copy_errors++))
|
((copy_errors++))
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Attempt copy and capture any error for logging
|
# Attempt copy and capture any error for logging
|
||||||
local cp_err
|
local cp_err
|
||||||
if cp_err=$(cp -p "$file" "$temp_file" 2>&1); then
|
if cp_err=$(cp -p "$file" "$temp_file" 2>&1); then
|
||||||
successfully_copied+=("$file")
|
successfully_copied+=("$file")
|
||||||
else
|
else
|
||||||
# Surface the cp error so the user can see the reason
|
# Surface the cp error so the user can see the reason
|
||||||
log "WARNING: Failed to copy $file -> $cp_err"
|
log "WARNING: Failed to copy $file -> $cp_err"
|
||||||
# Special hint for space issues
|
# Special hint for space issues
|
||||||
if echo "$cp_err" | grep -qi "No space left on device"; then
|
if echo "$cp_err" | grep -qi "No space left on device"; then
|
||||||
log "HINT: Not enough free space to stage files. Using $TEMP_DIR. Free up space or change TEMP_DIR."
|
log "HINT: Not enough free space to stage files. Using $TEMP_DIR. Free up space or change TEMP_DIR."
|
||||||
fi
|
fi
|
||||||
((copy_errors++))
|
((copy_errors++))
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ ${#successfully_copied[@]} -eq 0 ]]; then
|
if [[ ${#successfully_copied[@]} -eq 0 ]]; then
|
||||||
log "ERROR: No files were successfully copied to temp directory."
|
log "ERROR: No files were successfully copied to temp directory."
|
||||||
rm -rf "$TEMP_DIR"
|
rm -rf "$TEMP_DIR"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $copy_errors -gt 0 ]]; then
|
if [[ $copy_errors -gt 0 ]]; then
|
||||||
log "WARNING: $copy_errors files failed to copy."
|
log "WARNING: $copy_errors files failed to copy."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create zip archive with maximum compression
|
# Create zip archive with maximum compression
|
||||||
log "Creating zip archive with ${#successfully_copied[@]} files..."
|
log "Creating zip archive with ${#successfully_copied[@]} files..."
|
||||||
cd "$TEMP_DIR"
|
cd "$TEMP_DIR"
|
||||||
if zip -9 -r "$archive_path" . 2>&1; then
|
if zip -9 -r "$archive_path" . 2>&1; then
|
||||||
log "Successfully created archive with ${#successfully_copied[@]} files."
|
log "Successfully created archive with ${#successfully_copied[@]} files."
|
||||||
|
|
||||||
# Verify the zip file was actually created and is not empty
|
# Verify the zip file was actually created and is not empty
|
||||||
if [[ ! -f $archive_path ]]; then
|
if [[ ! -f $archive_path ]]; then
|
||||||
log "ERROR: Archive file was not created at $archive_path"
|
log "ERROR: Archive file was not created at $archive_path"
|
||||||
rm -rf "$TEMP_DIR"
|
rm -rf "$TEMP_DIR"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local archive_size
|
local archive_size
|
||||||
archive_size=$(stat -c%s "$archive_path" 2> /dev/null || echo "0")
|
archive_size=$(stat -c%s "$archive_path" 2>/dev/null || echo "0")
|
||||||
if [[ $archive_size -eq 0 ]]; then
|
if [[ $archive_size -eq 0 ]]; then
|
||||||
log "ERROR: Archive file is empty"
|
log "ERROR: Archive file is empty"
|
||||||
rm -rf "$TEMP_DIR"
|
rm -rf "$TEMP_DIR"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Remove original files only if zip was successful
|
# Remove original files only if zip was successful
|
||||||
local removed_count=0
|
local removed_count=0
|
||||||
local remove_errors=0
|
local remove_errors=0
|
||||||
|
|
||||||
log "Starting to remove ${#successfully_copied[@]} original files..."
|
log "Starting to remove ${#successfully_copied[@]} original files..."
|
||||||
|
|
||||||
# Temporarily disable strict error handling for file removal
|
# Temporarily disable strict error handling for file removal
|
||||||
set +e
|
set +e
|
||||||
|
|
||||||
for file in "${successfully_copied[@]}"; do
|
for file in "${successfully_copied[@]}"; do
|
||||||
if [[ -f $file ]]; then
|
if [[ -f $file ]]; then
|
||||||
if rm "$file" 2> /dev/null; then
|
if rm "$file" 2>/dev/null; then
|
||||||
removed_count=$((removed_count + 1))
|
removed_count=$((removed_count + 1))
|
||||||
log "Removed: $(basename "$file")"
|
log "Removed: $(basename "$file")"
|
||||||
else
|
else
|
||||||
remove_errors=$((remove_errors + 1))
|
remove_errors=$((remove_errors + 1))
|
||||||
log "ERROR: Failed to remove $(basename "$file")"
|
log "ERROR: Failed to remove $(basename "$file")"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
log "WARNING: File no longer exists: $(basename "$file")"
|
log "WARNING: File no longer exists: $(basename "$file")"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Re-enable strict error handling
|
# Re-enable strict error handling
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
log "Successfully removed $removed_count original files."
|
log "Successfully removed $removed_count original files."
|
||||||
if [[ $remove_errors -gt 0 ]]; then
|
if [[ $remove_errors -gt 0 ]]; then
|
||||||
log "WARNING: Failed to remove $remove_errors files."
|
log "WARNING: Failed to remove $remove_errors files."
|
||||||
fi
|
fi
|
||||||
log "Archive size: $(du -h "$archive_path" | cut -f1)"
|
log "Archive size: $(du -h "$archive_path" | cut -f1)"
|
||||||
|
|
||||||
# Cleanup temp directory (trap will also attempt, which is safe)
|
# Cleanup temp directory (trap will also attempt, which is safe)
|
||||||
rm -rf "$TEMP_DIR"
|
rm -rf "$TEMP_DIR"
|
||||||
|
|
||||||
# Return success only if we removed files or there were no files to remove
|
# Return success only if we removed files or there were no files to remove
|
||||||
if [[ $removed_count -gt 0 ]] || [[ ${#successfully_copied[@]} -eq 0 ]]; then
|
if [[ $removed_count -gt 0 ]] || [[ ${#successfully_copied[@]} -eq 0 ]]; then
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
log "ERROR: Failed to remove any files after successful archive creation."
|
log "ERROR: Failed to remove any files after successful archive creation."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
log "ERROR: Failed to create archive. Original files preserved."
|
log "ERROR: Failed to create archive. Original files preserved."
|
||||||
log "Zip command failed."
|
log "Zip command failed."
|
||||||
rm -rf "$TEMP_DIR"
|
rm -rf "$TEMP_DIR"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Main execution
|
# Main execution
|
||||||
main() {
|
main() {
|
||||||
log "Starting media file organization..."
|
log "Starting media file organization..."
|
||||||
|
|
||||||
# Check if required directories exist
|
# Check if required directories exist
|
||||||
if [[ ! -d $DOWNLOADS_DIR ]]; then
|
if [[ ! -d $DOWNLOADS_DIR ]]; then
|
||||||
log "ERROR: Downloads directory not found: $DOWNLOADS_DIR"
|
log "ERROR: Downloads directory not found: $DOWNLOADS_DIR"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -d $HOME_DIR ]]; then
|
if [[ ! -d $HOME_DIR ]]; then
|
||||||
log "ERROR: Home directory not found: $HOME_DIR"
|
log "ERROR: Home directory not found: $HOME_DIR"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if zip command is available
|
# Check if zip command is available
|
||||||
if ! command -v zip > /dev/null 2>&1; then
|
if ! command -v zip >/dev/null 2>&1; then
|
||||||
log "ERROR: zip command not found. Please install zip package."
|
log "ERROR: zip command not found. Please install zip package."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Find all media files
|
# Find all media files
|
||||||
log "Scanning for media files..."
|
log "Scanning for media files..."
|
||||||
local all_files=()
|
local all_files=()
|
||||||
|
|
||||||
# Find files in Downloads directory
|
# Find files in Downloads directory
|
||||||
log "Scanning Downloads directory..."
|
log "Scanning Downloads directory..."
|
||||||
while IFS= read -r file; do
|
while IFS= read -r file; do
|
||||||
[[ -n $file ]] && all_files+=("$file")
|
[[ -n $file ]] && all_files+=("$file")
|
||||||
done < <(find_media_files "$DOWNLOADS_DIR")
|
done < <(find_media_files "$DOWNLOADS_DIR")
|
||||||
|
|
||||||
# Find files in home directory (only direct files, not subdirectories)
|
# Find files in home directory (only direct files, not subdirectories)
|
||||||
log "Scanning home directory (root level only)..."
|
log "Scanning home directory (root level only)..."
|
||||||
while IFS= read -r file; do
|
while IFS= read -r file; do
|
||||||
[[ -n $file ]] && all_files+=("$file")
|
[[ -n $file ]] && all_files+=("$file")
|
||||||
done < <(find_media_files "$HOME_DIR")
|
done < <(find_media_files "$HOME_DIR")
|
||||||
|
|
||||||
if $DRY_RUN; then
|
if $DRY_RUN; then
|
||||||
log "Dry-run mode: summarizing what would be archived."
|
log "Dry-run mode: summarizing what would be archived."
|
||||||
if [[ ${#all_files[@]} -eq 0 ]]; then
|
if [[ ${#all_files[@]} -eq 0 ]]; then
|
||||||
log "No media files found to organize."
|
log "No media files found to organize."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Count by extension
|
# Separate big files for dry-run reporting
|
||||||
declare -A ext_counts=()
|
local dry_regular_files=()
|
||||||
# Count by top-level directory under Downloads
|
local dry_big_files=()
|
||||||
declare -A dir_counts=()
|
for f in "${all_files[@]}"; do
|
||||||
# Sample paths for suspect extensions
|
if is_too_big "$f"; then
|
||||||
declare -A samples_ts=()
|
dry_big_files+=("$f")
|
||||||
declare -A samples_svg=()
|
else
|
||||||
declare -A samples_ico=()
|
dry_regular_files+=("$f")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
for f in "${all_files[@]}"; do
|
# Count by extension
|
||||||
# Extension
|
declare -A ext_counts=()
|
||||||
ext="${f##*.}"
|
# Count by top-level directory under Downloads
|
||||||
ext="${ext,,}"
|
declare -A dir_counts=()
|
||||||
((ext_counts["$ext"]++)) || true
|
# Sample paths for suspect extensions
|
||||||
|
declare -A samples_ts=()
|
||||||
|
declare -A samples_svg=()
|
||||||
|
declare -A samples_ico=()
|
||||||
|
|
||||||
# Top directory under Downloads
|
for f in "${all_files[@]}"; do
|
||||||
if [[ $f == "$DOWNLOADS_DIR"/* ]]; then
|
# Extension
|
||||||
rel="${f#"$DOWNLOADS_DIR"/}"
|
ext="${f##*.}"
|
||||||
topdir="${rel%%/*}"
|
ext="${ext,,}"
|
||||||
[[ $topdir == "$rel" ]] && topdir="."
|
((ext_counts["$ext"]++)) || true
|
||||||
((dir_counts["$topdir"]++)) || true
|
|
||||||
else
|
|
||||||
((dir_counts["~"]++)) || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Samples for suspect extensions
|
# Top directory under Downloads
|
||||||
case "$ext" in
|
if [[ $f == "$DOWNLOADS_DIR"/* ]]; then
|
||||||
ts)
|
rel="${f#"$DOWNLOADS_DIR"/}"
|
||||||
if [[ ${#samples_ts[@]} -lt $SAMPLE_LIMIT ]]; then samples_ts["$f"]=1; fi
|
topdir="${rel%%/*}"
|
||||||
;;
|
[[ $topdir == "$rel" ]] && topdir="."
|
||||||
svg)
|
((dir_counts["$topdir"]++)) || true
|
||||||
if [[ ${#samples_svg[@]} -lt $SAMPLE_LIMIT ]]; then samples_svg["$f"]=1; fi
|
else
|
||||||
;;
|
((dir_counts["~"]++)) || true
|
||||||
ico)
|
fi
|
||||||
if [[ ${#samples_ico[@]} -lt $SAMPLE_LIMIT ]]; then samples_ico["$f"]=1; fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
echo ""
|
# Samples for suspect extensions
|
||||||
echo "Summary by extension (top 20):"
|
case "$ext" in
|
||||||
for k in "${!ext_counts[@]}"; do
|
ts)
|
||||||
printf "%8d %s\n" "${ext_counts[$k]}" "$k"
|
if [[ ${#samples_ts[@]} -lt $SAMPLE_LIMIT ]]; then samples_ts["$f"]=1; fi
|
||||||
done | sort -nr | head -n 20
|
;;
|
||||||
|
svg)
|
||||||
|
if [[ ${#samples_svg[@]} -lt $SAMPLE_LIMIT ]]; then samples_svg["$f"]=1; fi
|
||||||
|
;;
|
||||||
|
ico)
|
||||||
|
if [[ ${#samples_ico[@]} -lt $SAMPLE_LIMIT ]]; then samples_ico["$f"]=1; fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Top contributing directories under Downloads (top 20):"
|
echo "Summary by extension (top 20):"
|
||||||
for k in "${!dir_counts[@]}"; do
|
for k in "${!ext_counts[@]}"; do
|
||||||
printf "%8d %s\n" "${dir_counts[$k]}" "$k"
|
printf "%8d %s\n" "${ext_counts[$k]}" "$k"
|
||||||
done | sort -nr | head -n 20
|
done | sort -nr | head -n 20
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
if [[ ${#samples_ts[@]} -gt 0 ]]; then
|
echo "Top contributing directories under Downloads (top 20):"
|
||||||
echo "Sample .ts files (TypeScript vs Transport Stream) up to $SAMPLE_LIMIT:"
|
for k in "${!dir_counts[@]}"; do
|
||||||
for p in "${!samples_ts[@]}"; do echo " $p"; done | sort
|
printf "%8d %s\n" "${dir_counts[$k]}" "$k"
|
||||||
echo ""
|
done | sort -nr | head -n 20
|
||||||
fi
|
|
||||||
if [[ ${#samples_svg[@]} -gt 0 ]]; then
|
|
||||||
echo "Sample .svg files up to $SAMPLE_LIMIT:"
|
|
||||||
for p in "${!samples_svg[@]}"; do echo " $p"; done | sort
|
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
if [[ ${#samples_ico[@]} -gt 0 ]]; then
|
|
||||||
echo "Sample .ico files up to $SAMPLE_LIMIT:"
|
|
||||||
for p in "${!samples_ico[@]}"; do echo " $p"; done | sort
|
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Total files that would be archived: ${#all_files[@]}"
|
echo ""
|
||||||
echo "(Use: $(basename "$0") --dry-run --sample=50 to see more examples.)"
|
if [[ ${#samples_ts[@]} -gt 0 ]]; then
|
||||||
exit 0
|
echo "Sample .ts files (TypeScript vs Transport Stream) up to $SAMPLE_LIMIT:"
|
||||||
fi
|
for p in "${!samples_ts[@]}"; do echo " $p"; done | sort
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
if [[ ${#samples_svg[@]} -gt 0 ]]; then
|
||||||
|
echo "Sample .svg files up to $SAMPLE_LIMIT:"
|
||||||
|
for p in "${!samples_svg[@]}"; do echo " $p"; done | sort
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
if [[ ${#samples_ico[@]} -gt 0 ]]; then
|
||||||
|
echo "Sample .ico files up to $SAMPLE_LIMIT:"
|
||||||
|
for p in "${!samples_ico[@]}"; do echo " $p"; done | sort
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
# Create archive if files found
|
echo "Files to archive (regular size): ${#dry_regular_files[@]}"
|
||||||
if [[ ${#all_files[@]} -gt 0 ]]; then
|
echo "Files to move to too_big folder: ${#dry_big_files[@]}"
|
||||||
create_media_archive "${all_files[@]}"
|
if [[ ${#dry_big_files[@]} -gt 0 ]]; then
|
||||||
log "Media organization completed successfully."
|
echo ""
|
||||||
else
|
echo "Oversized files (> $((SIZE_THRESHOLD / 1024 / 1024))MB) that would be moved to too_big/:"
|
||||||
log "No media files found to organize."
|
for f in "${dry_big_files[@]}"; do
|
||||||
fi
|
local size
|
||||||
|
size=$(du -h "$f" 2>/dev/null | cut -f1)
|
||||||
|
echo " [$size] $f"
|
||||||
|
done | head -n "$SAMPLE_LIMIT"
|
||||||
|
if [[ ${#dry_big_files[@]} -gt $SAMPLE_LIMIT ]]; then
|
||||||
|
echo " ... and $((${#dry_big_files[@]} - SAMPLE_LIMIT)) more"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
echo "Total files that would be organized: ${#all_files[@]}"
|
||||||
|
echo "(Use: $(basename "$0") --dry-run --sample=50 to see more examples.)"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Separate files into regular and too-big categories
|
||||||
|
local regular_files=()
|
||||||
|
local big_files=()
|
||||||
|
|
||||||
|
for file in "${all_files[@]}"; do
|
||||||
|
if is_too_big "$file"; then
|
||||||
|
big_files+=("$file")
|
||||||
|
else
|
||||||
|
regular_files+=("$file")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
log "Found ${#regular_files[@]} regular files and ${#big_files[@]} oversized files."
|
||||||
|
|
||||||
|
# Move oversized files to too_big directory
|
||||||
|
if [[ ${#big_files[@]} -gt 0 ]]; then
|
||||||
|
move_big_files "${big_files[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create archive for regular-sized files
|
||||||
|
if [[ ${#regular_files[@]} -gt 0 ]]; then
|
||||||
|
create_media_archive "${regular_files[@]}"
|
||||||
|
log "Media organization completed successfully."
|
||||||
|
else
|
||||||
|
log "No regular-sized media files found to archive."
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run main function
|
# Run main function
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user