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
This commit is contained in:
1 parent
081210d3ae
commit
da2981a5be
2 files changed
+376
-145
No files matched your search
@@ -1,145 +0,0 @@
|
||||
#!/bin/bash
|
||||
IFS=$'\n'; set -f
|
||||
STUFF="/data/Nextcloud/Filme/New/"
|
||||
STUFF_ALT="/data/Torrents"
|
||||
ASSUMEYES=false
|
||||
FILE_PATH="/torrent/complete/"
|
||||
usage() {
|
||||
printf "Usage:
|
||||
-y\ty Mode
|
||||
-m\tmega Mode
|
||||
-f\tCopy to ~/data
|
||||
-d\tCopy to .
|
||||
-l\tSelect List
|
||||
-yt\tYoutube Folder
|
||||
-help\tDisplay this\n"
|
||||
}
|
||||
get_config() {
|
||||
while [[ ${1:0:1} == - ]]; do
|
||||
echo "Param: $1"
|
||||
[[ $1 == -help ]] && {
|
||||
echo "Help"
|
||||
usage;
|
||||
exit;
|
||||
};
|
||||
[[ $1 == -y ]] && {
|
||||
echo "y Mode"
|
||||
ASSUMEYES=true
|
||||
shift 1
|
||||
continue
|
||||
};
|
||||
[[ $1 == -yt ]] && {
|
||||
echo "Youtube Mode"
|
||||
FILE_PATH="/torrent/youtube/"
|
||||
shift 1
|
||||
continue
|
||||
};
|
||||
[[ $1 == -m ]] && {
|
||||
echo "mega Mode"
|
||||
FILE_PATH="/torrent/mega/"
|
||||
shift 1
|
||||
continue
|
||||
};
|
||||
[[ $1 == -l ]] && {
|
||||
echo "List Mode"
|
||||
LIST_MODE=true
|
||||
shift 1
|
||||
continue
|
||||
};
|
||||
[[ $1 == -d ]] && {
|
||||
STUFF="$(pwd)"
|
||||
echo "Change Folder: $STUFF"
|
||||
shift 1
|
||||
continue
|
||||
};
|
||||
[[ $1 == -f ]] && {
|
||||
echo "Change Folder"
|
||||
STUFF=${STUFF_ALT}
|
||||
shift 1
|
||||
continue
|
||||
};
|
||||
echo "Parameter $1 discarded"
|
||||
usage
|
||||
exit
|
||||
done
|
||||
}
|
||||
get_config "$@"
|
||||
|
||||
LIST=($(ssh serverhost ls ${FILE_PATH}))
|
||||
if [ ${#LIST[@]} -eq 0 ]; then
|
||||
echo "Nothing to Copy/Delete"
|
||||
exit
|
||||
fi
|
||||
if [ "${LIST_MODE}" == "true" ]; then
|
||||
for i in "${!LIST[@]}"; do
|
||||
files=${LIST[$i]}
|
||||
echo "Copy? ${files} (y/*)"
|
||||
read -n 10 ans
|
||||
if [ "$ans" != "y" ]; then
|
||||
echo "Dont copy $files"
|
||||
unset 'LIST[i]'
|
||||
fi
|
||||
done
|
||||
echo "NEW LIST:"
|
||||
echo "${LIST[*]}"
|
||||
fi
|
||||
if [ "${ASSUMEYES}" == "false" ]; then
|
||||
echo "Copy? (y/*)"
|
||||
echo "${LIST[*]}"
|
||||
read -n 10 ans
|
||||
else
|
||||
ans="y"
|
||||
fi
|
||||
if [ "$ans" == "y" ]; then
|
||||
for files in ${LIST[@]}; do
|
||||
scp -r deluge-user@serverhost:${FILE_PATH}$(printf "%q" "$files") "${STUFF}"
|
||||
if [ $? -ne 0 ]; then fail=true; echo "Copy Failure"; exit; fi
|
||||
done
|
||||
printf "Torrents Copied\n"
|
||||
else
|
||||
printf "Nothing Copied\n"
|
||||
fi
|
||||
if [ "${ASSUMEYES}" == "false" ]; then
|
||||
echo "Rename? (y/*)"
|
||||
echo "${LIST[*]}"
|
||||
read -n 10 ans
|
||||
else
|
||||
ans="y"
|
||||
fi
|
||||
|
||||
if [ "$ans" == "y" ]; then
|
||||
for files in ${LIST[@]}; do
|
||||
echo "Rename $files"
|
||||
filepath="${STUFF}${files}"
|
||||
if [ -d "${filepath}" ]; then
|
||||
echo "${filepath} is a Directory"
|
||||
bash /home/lucas/scripts/rename_episodes.sh -del -files -dir -repair -path "${filepath}"
|
||||
elif [ -f "${filepath}" ]; then
|
||||
echo "${filepath} is a File"
|
||||
bash /home/lucas/scripts/rename_episodes.sh -files -file "${filepath}"
|
||||
else
|
||||
echo "${filepath} neither Directory nor regular file"
|
||||
fi
|
||||
done
|
||||
printf "Rename Complete\n"
|
||||
else
|
||||
printf "Nothing Renamed\n"
|
||||
fi
|
||||
if [ "${ASSUMEYES}" == "false" ]; then
|
||||
echo "Delete? (y/*)"
|
||||
echo "${LIST[*]}"
|
||||
read -n 10 ans
|
||||
else
|
||||
ans="y"
|
||||
fi
|
||||
if [ "$ans" == "y" ]; then
|
||||
for files in ${LIST[@]}; do
|
||||
echo "Delete $files"
|
||||
ssh deluge-user@serverhost rm -dr ${FILE_PATH}$(printf "%q" "$files")
|
||||
done
|
||||
printf "Torrents Removed\n"
|
||||
else
|
||||
printf "Nothing Removed\n"
|
||||
fi
|
||||
unset IFS; set +f
|
||||
|
||||
Executable
+376
@@ -0,0 +1,376 @@
|
||||
```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 "$@"
|
||||
```
|
||||
Reference in new issue
Block a user