Files
Server-scripts/torrent/torrent_copy_from_server.sh
T
Lucas Vivohost da2981a5be refactor: improve torrent transfer workflow
refactor: improve torrent transfer workflow

- replace unsafe word splitting with Bash arrays
- improve command-line argument parsing
- centralize remote and local configuration
- replace remote ls parsing with find
- simplify confirmation handling
- improve SSH and SCP error handling
- safely quote local paths and filenames
- separate copy, rename, and delete operations
- add comprehensive usage documentation
2026-09-14 12:46:09 +02:00

377 lines
8.2 KiB
Bash
Executable File

```bash
#!/bin/bash
# Torrent Copy / Rename / Delete Utility
#
# Description:
# Selects completed torrents from a remote Deluge server, copies them
# locally, optionally renames the downloaded files, and finally removes
# the remote torrents.
#
# Workflow:
# 1. List files from the configured remote torrent directory.
# 2. Optionally select individual files.
# 3. Confirm and copy selected files locally.
# 4. Confirm and rename copied files.
# 5. Confirm and remove the remote files.
#
# Usage:
# ./torrent_copy.sh [options]
#
# Options:
# -y Automatically answer "yes" to all confirmations.
# -m Use the remote Mega torrent directory.
# -yt Use the remote YouTube torrent directory.
# -l Select individual files interactively.
# -f Copy files to the configured torrent destination.
# -d Copy files to the current directory.
# -help Display this help.
#
# Examples:
# ./torrent_copy.sh
# ./torrent_copy.sh -y
# ./torrent_copy.sh -l
# ./torrent_copy.sh -m -l
# ./torrent_copy.sh -yt -f
# ./torrent_copy.sh -d
#
# Requirements:
# - bash
# - ssh
# - scp
# - Remote SSH access to "serverhost"
# - /home/lucas/scripts/rename_episodes.sh
#
set -o pipefail
# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
readonly REMOTE_HOST="serverhost"
readonly REMOTE_USER="deluge-user"
readonly DEFAULT_DEST="/data/Nextcloud/Filme/New/"
readonly TORRENT_DEST="/data/Torrents"
readonly RENAME_SCRIPT="/home/lucas/scripts/rename_episodes.sh"
REMOTE_PATH="/torrent/complete/"
DESTINATION="$DEFAULT_DEST"
ASSUME_YES=false
LIST_MODE=false
# ---------------------------------------------------------------------------
# Help
# ---------------------------------------------------------------------------
usage() {
cat <<EOF
Usage:
$(basename "$0") [options]
Options:
-y Automatically answer yes to all confirmations
-m Use Mega torrent directory
-yt Use YouTube torrent directory
-l Select files individually
-f Copy to $TORRENT_DEST
-d Copy to the current directory
-help Display this help
Examples:
$(basename "$0") -y
$(basename "$0") -l
$(basename "$0") -m -l
$(basename "$0") -yt -f
$(basename "$0") -d
EOF
}
# ---------------------------------------------------------------------------
# Argument parsing
# ---------------------------------------------------------------------------
parse_args() {
while (($#)); do
case "$1" in
-help|--help)
usage
exit 0
;;
-y)
ASSUME_YES=true
;;
-yt)
REMOTE_PATH="/torrent/youtube/"
;;
-m)
REMOTE_PATH="/torrent/mega/"
;;
-l)
LIST_MODE=true
;;
-d)
DESTINATION="$(pwd)"
;;
-f)
DESTINATION="$TORRENT_DEST"
;;
*)
echo "Error: unknown option '$1'" >&2
usage >&2
exit 1
;;
esac
shift
done
}
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
confirm() {
local message=$1
if [[ "$ASSUME_YES" == true ]]; then
return 0
fi
printf '%s (y/*) ' "$message"
read -r -n 1 answer
printf '\n'
[[ "$answer" == "y" ]]
}
die() {
echo "Error: $*" >&2
exit 1
}
# ---------------------------------------------------------------------------
# Get remote file list
# ---------------------------------------------------------------------------
get_file_list() {
local remote_listing
echo "Remote directory: $REMOTE_PATH"
echo "Destination: $DESTINATION"
echo
if ! remote_listing=$(
ssh "$REMOTE_USER@$REMOTE_HOST" \
"find '$REMOTE_PATH' -mindepth 1 -maxdepth 1 -printf '%f\n'"
); then
die "Unable to retrieve remote file list."
fi
if [[ -z "$remote_listing" ]]; then
echo "Nothing to copy/delete."
exit 0
fi
mapfile -t FILES <<< "$remote_listing"
}
# ---------------------------------------------------------------------------
# Select individual files
# ---------------------------------------------------------------------------
select_files() {
local file
local selected=()
echo "Select files:"
echo
for file in "${FILES[@]}"; do
if confirm "Copy '$file'?"; then
selected+=("$file")
else
echo "Skipping '$file'"
fi
done
FILES=("${selected[@]}")
}
# ---------------------------------------------------------------------------
# Copy files
# ---------------------------------------------------------------------------
copy_files() {
local file
local remote_file
[[ ${#FILES[@]} -gt 0 ]] || {
echo "Nothing to copy."
return
}
echo
printf 'Files to copy:\n'
printf ' %s\n' "${FILES[@]}"
echo
if ! confirm "Copy files?"; then
echo "Nothing copied."
return 1
fi
for file in "${FILES[@]}"; do
echo "Copying: $file"
# Pass the remote path as a single SSH/SCP argument.
remote_file="${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_PATH}${file}"
if ! scp -r "$remote_file" "$DESTINATION/"; then
die "Copy failed: $file"
fi
done
echo "Torrents copied."
}
# ---------------------------------------------------------------------------
# Rename files
# ---------------------------------------------------------------------------
rename_files() {
local file
local filepath
[[ ${#FILES[@]} -gt 0 ]] || {
echo "Nothing to rename."
return
}
echo
printf 'Files to rename:\n'
printf ' %s\n' "${FILES[@]}"
echo
if ! confirm "Rename files?"; then
echo "Nothing renamed."
return
fi
if [[ ! -x "$RENAME_SCRIPT" && ! -f "$RENAME_SCRIPT" ]]; then
die "Rename script not found: $RENAME_SCRIPT"
fi
for file in "${FILES[@]}"; do
filepath="${DESTINATION%/}/$file"
echo "Renaming: $filepath"
if [[ -d "$filepath" ]]; then
echo "$filepath is a directory."
bash "$RENAME_SCRIPT" \
-del \
-files \
-dir \
-repair \
-path "$filepath"
elif [[ -f "$filepath" ]]; then
echo "$filepath is a file."
bash "$RENAME_SCRIPT" \
-files \
-file "$filepath"
else
echo "Warning: $filepath is neither a directory nor a regular file."
fi
done
echo "Rename complete."
}
# ---------------------------------------------------------------------------
# Delete remote files
# ---------------------------------------------------------------------------
delete_files() {
local file
local remote_file
[[ ${#FILES[@]} -gt 0 ]] || {
echo "Nothing to remove."
return
}
echo
printf 'Remote files to remove:\n'
printf ' %s\n' "${FILES[@]}"
echo
if ! confirm "Delete remote files?"; then
echo "Nothing removed."
return
fi
for file in "${FILES[@]}"; do
echo "Removing: $file"
remote_file="${REMOTE_PATH}${file}"
if ! ssh "$REMOTE_USER@$REMOTE_HOST" \
"rm -rf -- '$remote_file'"; then
echo "Warning: failed to remove '$file'." >&2
fi
done
echo "Torrents removed."
}
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
main() {
parse_args "$@"
get_file_list
if [[ "$LIST_MODE" == true ]]; then
select_files
fi
[[ ${#FILES[@]} -gt 0 ]] || {
echo "No files selected."
exit 0
}
copy_files || exit 1
rename_files
delete_files
}
main "$@"
```