torrent/usr/local/lib/torrent-mover/archive_handler.sh
2025-03-04 08:53:02 +00:00

134 lines
4.8 KiB
Bash

#!/bin/bash
# Archive extraction handler for torrent-mover
# extract_single_archive: Extract a single archive with proper error handling
extract_single_archive() {
local archive="$1"
local target_dir="$2"
local archive_type="${archive##*.}"
local extract_success=1
local tmp_marker="${target_dir}/.extraction_in_progress"
# Create extraction marker to indicate incomplete extraction
touch "${tmp_marker}"
# Ensure proper permissions for extraction directory
chmod 775 "${target_dir}"
chown ${TORRENT_USER:-debian-transmission}:${TORRENT_GROUP:-debian-transmission} "${target_dir}"
# Extract based on archive type
case "${archive_type,,}" in # Use lowercase comparison
rar)
log_debug "Extracting RAR archive: ${archive}"
# Check which unrar variant is available
if command -v unrar-free &>/dev/null; then
# unrar-free has different syntax
retry_command "unrar-free x \"${archive}\" \"${target_dir}\"" 3 10
else
retry_command "unrar x -o- \"${archive}\" \"${target_dir}\"" 3 10
fi
extract_success=$?
;;
zip)
log_debug "Extracting ZIP archive: ${archive}"
retry_command "unzip -o \"${archive}\" -d \"${target_dir}\"" 3 10
extract_success=$?
;;
7z|7zip)
log_debug "Extracting 7Z archive: ${archive}"
retry_command "7z x \"${archive}\" -o\"${target_dir}\"" 3 10
extract_success=$?
;;
*)
log_error "Unknown archive type: ${archive_type}"
extract_success=1
;;
esac
# Apply consistent permissions to all extracted files and directories
if [[ ${extract_success} -eq 0 ]]; then
log_debug "Setting permissions for extracted files in ${target_dir}"
find "${target_dir}" -type d -exec chmod 775 {} \;
find "${target_dir}" -type f -exec chmod 664 {} \;
find "${target_dir}" -exec chown ${TORRENT_USER:-debian-transmission}:${TORRENT_GROUP:-debian-transmission} {} \;
# Remove the extraction marker to indicate successful completion
rm -f "${tmp_marker}"
return 0
else
log_error "Extraction failed for ${archive}"
# Keep marker to indicate failed extraction
return 1
fi
}
# handle_archives: Process all archives in a source directory
# Returns: 0 if all archives extracted successfully or no archives found, 1 if any failed
handle_archives() {
local src="$1" dst="$2"
local overall_success=0
local archive_found=0
local extraction_errors=0
# Check if source and destination are valid
if [[ ! -d "${src}" ]]; then
log_error "Source directory missing: ${src}"
return 1
fi
if [[ ! -d "${dst}" ]]; then
log_error "Destination directory missing: ${dst}"
return 1
fi
# Find all archives and extract them
find "${src}" -type f \( -iname "*.rar" -o -iname "*.zip" -o -iname "*.7z" \) | while read -r arch; do
archive_found=1
log_info "Processing archive: ${arch}"
# Create extraction subdirectory
local base
base=$(basename "${arch}")
local subdir="${dst}/${base%.*}"
if ! mkdir -p "${subdir}"; then
log_error "Failed to create subdirectory ${subdir} for archive extraction"
extraction_errors=$((extraction_errors + 1))
continue
fi
# Extract the archive
if ! extract_single_archive "${arch}" "${subdir}"; then
log_error "Extraction failed for ${arch}"
extraction_errors=$((extraction_errors + 1))
else
log_info "Archive ${arch} extracted successfully to ${subdir}"
log_info "Archive ${arch} retained in source until ratio limits are reached."
fi
done
# Check for cleanup of any incomplete extractions from previous runs
find "${dst}" -name ".extraction_in_progress" | while read -r marker; do
local problem_dir=$(dirname "${marker}")
log_warn "Found incomplete extraction in ${problem_dir} from previous run"
# Option 1: Remove incomplete directory
# rm -rf "${problem_dir}"
# Option 2: Mark as incomplete but leave content
touch "${problem_dir}/.incomplete_extraction"
rm -f "${marker}"
done
# Return success if no archives found or all extracted successfully
if [[ ${archive_found} -eq 0 ]]; then
log_debug "No archives found in ${src}"
return 0
elif [[ ${extraction_errors} -eq 0 ]]; then
log_info "All archives extracted successfully"
return 0
else
log_warn "${extraction_errors} archives failed to extract properly"
return 1
fi
}