testsAndMisc/linux_configuration/scripts/single_use/utils/lib/download_media.sh
Krzysztof kuhy Rudnicki 2527fb37e6 Split three large linux_configuration scripts, defer a fourth
organize_downloads.sh 513 -> 72, setup_kcd2_dice_solver.sh 497 -> 112,
fix_ubuntu_performance.sh 494 -> 150. First 490+ line scripts done; all
three needed two or three seams.

Repeated splitting chained the libs - each sourced the next, because the
tool inserts its source line relative to the file it just wrote.
Flattened so the entry sources all three and no lib sources a sibling.

diagnose_pacman_hook_stall.sh is reverted and stays at 493. Its
transaction runner assigns LAST_ELAPSED that the caller reads and reads
PACMAN_BIN that the caller defines, so linted alone it is SC2034 plus
SC2153. The pre-commit hook lints each lib in isolation and fails, while
shellcheck -x on the entry passes - suppressing that would be papering
over a seam that does not exist.

organize_downloads.sh is the ExecStart of media-organizer.service; the
unit still resolves and the script still parses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
2026-08-16 19:06:16 +02:00

204 lines
6.0 KiB
Bash
Executable File

#!/bin/bash
# Media discovery, archiving and the per-category moves.
#
# Sourced by organize_downloads.sh; split out to keep it under the 250-line cap.
# Sourced rather than run, so it inherits the caller's strict mode and
# the helper functions and variables defined above the source line.
# Function to find media files in a directory (non-recursive for home, avoid common system dirs)
find_media_files() {
local search_dir="$1"
local files=()
# Directories to exclude under Downloads
local -a EXCLUDES=(
".git" ".hg" ".svn" ".cache" "node_modules" "dist" "build" "out" "target" "coverage" "__pycache__" "venv" ".venv"
# previous staging dirs created by this script
".media_organize_" "media_organize_"
# too_big folder for oversized files
"too_big"
)
if [[ $search_dir == "$HOME_DIR" ]]; then
# For home directory, only check files directly in ~ (not subdirectories)
# Exclude common system/config directories
while IFS= read -r -d '' file; do
local basename
basename=$(basename "$file")
# Skip hidden files and common system directories
if [[ ! $basename =~ ^\. ]] && [[ -f $file ]]; then
if is_media_file "$file"; then
files+=("$file")
fi
fi
done < <(find "$search_dir" -maxdepth 1 -type f -print0 2>/dev/null)
else
# For Downloads, search recursively, pruning excluded directories
# Build prune expression
local prune_expr=()
for ex in "${EXCLUDES[@]}"; do
prune_expr+=(-name "$ex*" -o)
done
# Remove trailing -o
unset 'prune_expr[${#prune_expr[@]}-1]'
while IFS= read -r -d '' file; do
if is_media_file "$file"; then
files+=("$file")
fi
done < <(find "$search_dir" \( -type d \( "${prune_expr[@]}" \) -prune \) -o -type f -print0 2>/dev/null)
fi
printf '%s\n' "${files[@]}"
}
# Function to create timestamped zip archive
create_media_archive() {
local files=("$@")
if [[ ${#files[@]} -eq 0 ]]; then
log "No media files found to archive."
return 0
fi
# Create timestamp for archive name
local timestamp
timestamp=$(date '+%Y%m%d_%H%M%S')
local archive_name="media_archive_${timestamp}.zip"
local archive_path="$DOWNLOADS_DIR/$archive_name"
# Create temporary directory (fallback to /tmp if needed)
if ! mkdir -p "$TEMP_DIR" 2>/dev/null; then
TEMP_DIR="/tmp/media_organize_$$"
mkdir -p "$TEMP_DIR"
fi
# 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
log "Found ${#files[@]} media files to archive."
log "Creating archive: $archive_path"
# Copy files to temp directory maintaining relative structure
local successfully_copied=()
local copy_errors=0
for file in "${files[@]}"; do
if [[ -f $file ]]; then
local relative_path=""
if [[ $file == "$DOWNLOADS_DIR"* ]]; then
relative_path="downloads/${file#"$DOWNLOADS_DIR"/}"
else
relative_path="home/${file#"$HOME_DIR"/}"
fi
local temp_file="$TEMP_DIR/$relative_path"
local temp_dir
temp_dir=$(dirname "$temp_file")
mkdir -p "$temp_dir"
# Check readability first to provide a clearer error
if [[ ! -r $file ]]; then
log "WARNING: Cannot read $file (permission denied?)"
((copy_errors++)) || true
continue
fi
# Attempt copy and capture any error for logging
local cp_err
if cp_err=$(cp -p "$file" "$temp_file" 2>&1); then
successfully_copied+=("$file")
else
# Surface the cp error so the user can see the reason
log "WARNING: Failed to copy $file -> $cp_err"
# Special hint for space issues
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."
fi
((copy_errors++)) || true
fi
fi
done
if [[ ${#successfully_copied[@]} -eq 0 ]]; then
log "ERROR: No files were successfully copied to temp directory."
rm -rf "$TEMP_DIR"
return 1
fi
if [[ $copy_errors -gt 0 ]]; then
log "WARNING: $copy_errors files failed to copy."
fi
# Create zip archive with maximum compression
log "Creating zip archive with ${#successfully_copied[@]} files..."
cd "$TEMP_DIR"
if zip -9 -r "$archive_path" . 2>&1; then
log "Successfully created archive with ${#successfully_copied[@]} files."
# Verify the zip file was actually created and is not empty
if [[ ! -f $archive_path ]]; then
log "ERROR: Archive file was not created at $archive_path"
rm -rf "$TEMP_DIR"
return 1
fi
local archive_size
archive_size=$(stat -c%s "$archive_path" 2>/dev/null || echo "0")
if [[ $archive_size -eq 0 ]]; then
log "ERROR: Archive file is empty"
rm -rf "$TEMP_DIR"
return 1
fi
# Remove original files only if zip was successful
local removed_count=0
local remove_errors=0
log "Starting to remove ${#successfully_copied[@]} original files..."
# Temporarily disable strict error handling for file removal
set +e
for file in "${successfully_copied[@]}"; do
if [[ -f $file ]]; then
if rm "$file" 2>/dev/null; then
removed_count=$((removed_count + 1))
log "Removed: $(basename "$file")"
else
remove_errors=$((remove_errors + 1))
log "ERROR: Failed to remove $(basename "$file")"
fi
else
log "WARNING: File no longer exists: $(basename "$file")"
fi
done
# Re-enable strict error handling
set -e
log "Successfully removed $removed_count original files."
if [[ $remove_errors -gt 0 ]]; then
log "WARNING: Failed to remove $remove_errors files."
fi
log "Archive size: $(du -h "$archive_path" | cut -f1)"
# Cleanup temp directory (trap will also attempt, which is safe)
rm -rf "$TEMP_DIR"
# Return success only if we removed files or there were no files to remove
if [[ $removed_count -gt 0 ]] || [[ ${#successfully_copied[@]} -eq 0 ]]; then
return 0
else
log "ERROR: Failed to remove any files after successful archive creation."
return 1
fi
else
log "ERROR: Failed to create archive. Original files preserved."
log "Zip command failed."
rm -rf "$TEMP_DIR"
return 1
fi
}
# Main execution