Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@ chmod +x /mnt/user/appdata/qbt-mover/mover-tuning-end.sh

After editing the scripts, make sure they use LF line endings (Unix format). If you edited the files on Windows, they may have CRLF line endings, which can cause errors.

Run the following command to convert all `.sh` files to the correct format:
Run the following command to convert all `.sh` and `.cfg` files to the correct format:

```bash
for file in *.sh; do [ -f "$file" ] && sed -i 's/\r$//' "$file" && echo "Converted $file"; done
for file in *.sh *.cfg; do [ -f "$file" ] && sed -i 's/\r$//' "$file" && echo "Converted $file"; done
```

**How to use this command:**
Expand All @@ -143,7 +143,7 @@ for file in *.sh; do [ -f "$file" ] && sed -i 's/\r$//' "$file" && echo "Convert
3. Paste the command above
4. Press ++enter++

This converts all `.sh` files from CRLF (Windows line endings) to LF (Unix line endings) in the current directory.
This converts all `.sh` and `.cfg` files from CRLF (Windows line endings) to LF (Unix line endings) in the current directory.

---

Expand Down
117 changes: 102 additions & 15 deletions includes/downloaders/mover-tuning-end.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ set -euo pipefail # Exit on error, undefined variables, and pipe failures

# =====================================
# Script: qBittorrent Cache Mover - End
# Version: 1.0.0
# Updated: 20251121
# Version: 1.1.0
# Updated: 20251201
# =====================================

# Script version and update check URLs
readonly SCRIPT_VERSION="1.0.0"
readonly SCRIPT_VERSION="1.1.0"
readonly SCRIPT_RAW_URL="https://raw.githubusercontent.com/TRaSH-Guides/Guides/refs/heads/master/includes/downloaders/mover-tuning-end.sh"

# Get the directory where the script is located
Expand Down Expand Up @@ -44,6 +44,63 @@ notify() {
fi
}

# ================================
# CONFIG FORMAT DETECTION
# ================================
detect_config_format() {
# Check if array-based config is used
if [[ -v HOSTS[@] ]] && [[ ${#HOSTS[@]} -gt 0 ]]; then
echo "array"
else
echo "legacy"
fi
}

get_instance_count() {
local format
format=$(detect_config_format)

if [[ "$format" == "array" ]]; then
echo "${#HOSTS[@]}"
else
# Legacy format: count based on ENABLE_QBIT_2
if [[ "${ENABLE_QBIT_2:-false}" == true ]]; then
echo "2"
else
echo "1"
fi
fi
Comment on lines +63 to +72
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Same array validation gap exists in the end script, leading to similar edge cases.

This mirrors the start script: it only enforces matching lengths for HOSTS/USERS/PASSWORDS, not that individual entries are non-empty. Once you add per-entry validation to the start script, please apply the same checks here so misconfigurations are caught consistently and early.

Suggested implementation:

    if [[ "$format" == "array" ]]; then
        # Validate that HOSTS, USERS, and PASSWORDS arrays are consistent and non-empty
        if (( ${#HOSTS[@]} == 0 )); then
            echo "No HOSTS configured for array-based configuration." >&2
            exit 1
        fi

        if (( ${#HOSTS[@]} != ${#USERS[@]} || ${#HOSTS[@]} != ${#PASSWORDS[@]} )); then
            echo "Configuration error: HOSTS, USERS, and PASSWORDS arrays must have the same length." >&2
            exit 1
        fi

        for i in "${!HOSTS[@]}"; do
            if [[ -z "${HOSTS[$i]}" || -z "${USERS[$i]}" || -z "${PASSWORDS[$i]}" ]]; then
                echo "Configuration error: HOSTS, USERS, and PASSWORDS entries must be non-empty (index $i)." >&2
                exit 1
            fi
        done

        echo "${#HOSTS[@]}"

  1. The snippet you provided shows two get_instance_count definitions and a seemingly incomplete if/fi structure. In the actual file, ensure there is only one get_instance_count function and that its if/else/fi structure is syntactically correct.
  2. If the start script uses specific error message wording or a shared helper for validation, you may want to adjust the error messages here to match that convention for consistency.

}

get_instance_details() {
local index="$1"
local format
format=$(detect_config_format)

if [[ "$format" == "array" ]]; then
# Array format: set global variables
INSTANCE_NAME="${NAMES[$index]:-qBit-Instance-$((index + 1))}"
INSTANCE_HOST="${HOSTS[$index]}"
INSTANCE_USER="${USERS[$index]}"
INSTANCE_PASSWORD="${PASSWORDS[$index]}"
else
# Legacy format: map index to old variables
if [[ $index -eq 0 ]]; then
INSTANCE_NAME="${QBIT_NAME_1}"
INSTANCE_HOST="${QBIT_HOST_1}"
INSTANCE_USER="${QBIT_USER_1}"
INSTANCE_PASSWORD="${QBIT_PASS_1}"
elif [[ $index -eq 1 ]]; then
INSTANCE_NAME="${QBIT_NAME_2}"
INSTANCE_HOST="${QBIT_HOST_2}"
INSTANCE_USER="${QBIT_USER_2}"
INSTANCE_PASSWORD="${QBIT_PASS_2}"
else
error "Invalid instance index: $index"
fi
fi
}

# ================================
# VERSION CHECK FUNCTION
# ================================
Expand Down Expand Up @@ -91,9 +148,17 @@ check_script_version() {
# Compare versions
if [[ "$SCRIPT_VERSION" != "$latest_version" ]]; then
# Simple version comparison (works for semantic versioning)
if printf '%s\n' "$latest_version" "$SCRIPT_VERSION" | sort -V | head -n1 | grep -q "^$SCRIPT_VERSION$" 2>/dev/null || true; then
# Sort both versions and check if SCRIPT_VERSION comes first (is older)
local oldest_version
oldest_version=$(printf '%s\n' "$latest_version" "$SCRIPT_VERSION" | sort -V | head -n1)

if [[ "$oldest_version" == "$SCRIPT_VERSION" ]]; then
# SCRIPT_VERSION is older, so there's a newer version available
log "⚠ New version available: $latest_version"
notify "mover-tuning-end.sh Update" "Version $latest_version available (current: $SCRIPT_VERSION)<br><br>📖 Visit the TRaSH-Guides for the latest version"
else
# latest_version is older, local version is newer
log "✓ Local version ($SCRIPT_VERSION) is newer than remote ($latest_version)"
fi
else
log "✓ Script is up to date"
Expand Down Expand Up @@ -297,6 +362,31 @@ validate_config() {
[[ -d "$CACHE_MOUNT" ]] || error "Cache mount not found: $CACHE_MOUNT"
[[ -f "${QBIT_MOVER_PATH}mover.py" ]] || error "mover.py not found: ${QBIT_MOVER_PATH}mover.py"

# Validate instance configuration
local format
format=$(detect_config_format)

if [[ "$format" == "array" ]]; then
# Validate array-based config
[[ ${#HOSTS[@]} -gt 0 ]] || error "HOSTS array is empty"
[[ ${#USERS[@]} -eq ${#HOSTS[@]} ]] || error "USERS array length doesn't match HOSTS"
[[ ${#PASSWORDS[@]} -eq ${#HOSTS[@]} ]] || error "PASSWORDS array length doesn't match HOSTS"

# NAMES array is optional, but if present should match
if [[ -v NAMES[@] ]] && [[ ${#NAMES[@]} -gt 0 ]]; then
[[ ${#NAMES[@]} -eq ${#HOSTS[@]} ]] || error "NAMES array length doesn't match HOSTS"
fi

log "✓ Using array-based configuration (${#HOSTS[@]} instance(s))"
else
# Validate legacy config
[[ -n "${QBIT_HOST_1:-}" ]] || error "QBIT_HOST_1 is not set"
[[ -n "${QBIT_USER_1:-}" ]] || error "QBIT_USER_1 is not set"
[[ -n "${QBIT_PASS_1:-}" ]] || error "QBIT_PASS_1 is not set"

log "✓ Using legacy configuration"
fi

# Validate duplicate finder if enabled
if [[ "$ENABLE_DUPLICATE_FINDER" == true ]]; then
if [[ "$ENABLE_AUTO_INSTALLER" == true ]]; then
Expand Down Expand Up @@ -372,18 +462,15 @@ main() {
# Validate configuration
validate_config || exit 1

# Process primary instance
process_qbit_instance "$QBIT_NAME_1" "$QBIT_HOST_1" "$QBIT_USER_1" "$QBIT_PASS_1" || \
((failed_instances++))
# Process all instances
local instance_count
instance_count=$(get_instance_count)

# Process secondary instance if enabled
if [[ "$ENABLE_QBIT_2" == true ]]; then
log "Processing secondary instance..."
process_qbit_instance "$QBIT_NAME_2" "$QBIT_HOST_2" "$QBIT_USER_2" "$QBIT_PASS_2" || \
((failed_instances++))
else
log "Secondary instance disabled"
fi
for ((i=0; i<instance_count; i++)); do
get_instance_details "$i"

process_qbit_instance "$INSTANCE_NAME" "$INSTANCE_HOST" "$INSTANCE_USER" "$INSTANCE_PASSWORD" || ((failed_instances++))
done

# Run duplicate finder if enabled
if [[ "$ENABLE_DUPLICATE_FINDER" == true ]]; then
Expand Down
135 changes: 125 additions & 10 deletions includes/downloaders/mover-tuning-start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ set -euo pipefail # Exit on error, undefined variables, and pipe failures

# =======================================
# Script: qBittorrent Cache Mover - Start
# Version: 1.0.0
# Updated: 20251121
# Version: 1.1.0
# Updated: 20251201
# =======================================

# Script version and update check URLs
readonly SCRIPT_VERSION="1.0.0"
readonly SCRIPT_VERSION="1.1.0"
readonly SCRIPT_RAW_URL="https://raw.githubusercontent.com/TRaSH-Guides/Guides/refs/heads/master/includes/downloaders/mover-tuning-start.sh"
readonly CONFIG_RAW_URL="https://raw.githubusercontent.com/TRaSH-Guides/Guides/refs/heads/master/includes/downloaders/mover-tuning.cfg"

Expand Down Expand Up @@ -57,6 +57,63 @@ set_ownership() {
chown -R nobody:users "$1" 2>/dev/null || log "⚠ Warning: Could not set ownership for $1"
}

# ================================
# CONFIG FORMAT DETECTION
# ================================
detect_config_format() {
# Check if array-based config is used
if [[ -v HOSTS[@] ]] && [[ ${#HOSTS[@]} -gt 0 ]]; then
echo "array"
else
echo "legacy"
fi
}

get_instance_count() {
local format
format=$(detect_config_format)

if [[ "$format" == "array" ]]; then
echo "${#HOSTS[@]}"
else
# Legacy format: count based on ENABLE_QBIT_2
if [[ "${ENABLE_QBIT_2:-false}" == true ]]; then
echo "2"
else
echo "1"
fi
fi
}

get_instance_details() {
local index="$1"
local format
format=$(detect_config_format)

if [[ "$format" == "array" ]]; then
# Array format: set global variables
INSTANCE_NAME="${NAMES[$index]:-qBit-Instance-$((index + 1))}"
INSTANCE_HOST="${HOSTS[$index]}"
INSTANCE_USER="${USERS[$index]}"
INSTANCE_PASSWORD="${PASSWORDS[$index]}"
else
# Legacy format: map index to old variables
if [[ $index -eq 0 ]]; then
INSTANCE_NAME="${QBIT_NAME_1}"
INSTANCE_HOST="${QBIT_HOST_1}"
INSTANCE_USER="${QBIT_USER_1}"
INSTANCE_PASSWORD="${QBIT_PASS_1}"
elif [[ $index -eq 1 ]]; then
INSTANCE_NAME="${QBIT_NAME_2}"
INSTANCE_HOST="${QBIT_HOST_2}"
INSTANCE_USER="${QBIT_USER_2}"
INSTANCE_PASSWORD="${QBIT_PASS_2}"
else
error "Invalid instance index: $index"
fi
fi
}

# ================================
# VERSION CHECK FUNCTION
# ================================
Expand Down Expand Up @@ -104,9 +161,17 @@ check_script_version() {
# Compare versions
if [[ "$SCRIPT_VERSION" != "$latest_version" ]]; then
# Simple version comparison (works for semantic versioning)
if printf '%s\n' "$latest_version" "$SCRIPT_VERSION" | sort -V | head -n1 | grep -q "^$SCRIPT_VERSION$" 2>/dev/null || true; then
# Sort both versions and check if SCRIPT_VERSION comes first (is older)
local oldest_version
oldest_version=$(printf '%s\n' "$latest_version" "$SCRIPT_VERSION" | sort -V | head -n1)

if [[ "$oldest_version" == "$SCRIPT_VERSION" ]]; then
# SCRIPT_VERSION is older, so there's a newer version available
log "⚠ New version available: $latest_version"
notify "mover-tuning-start.sh Update" "Version $latest_version available (current: $SCRIPT_VERSION)<br><br>📖 Visit the TRaSH-Guides for the latest version"
else
# latest_version is older, local version is newer
log "✓ Local version ($SCRIPT_VERSION) is newer than remote ($latest_version)"
fi
else
log "✓ Script is up to date"
Expand Down Expand Up @@ -162,9 +227,17 @@ check_config_version() {
# Compare versions
if [[ "$current_config_version" != "$remote_config_version" ]]; then
# Simple version comparison (works for semantic versioning)
if printf '%s\n' "$remote_config_version" "$current_config_version" | sort -V | head -n1 | grep -q "^$current_config_version$" 2>/dev/null || true; then
# Sort both versions and check if current_config_version comes first (is older)
local oldest_version
oldest_version=$(printf '%s\n' "$remote_config_version" "$current_config_version" | sort -V | head -n1)

if [[ "$oldest_version" == "$current_config_version" ]]; then
# current_config_version is older, so there's a newer version available
log "⚠ New config version available: $remote_config_version"
notify "mover-tuning.cfg Update" "Config version <b>$remote_config_version</b> available<br>Current version: <b>$current_config_version</b><br><br>📖 Visit the TRaSH-Guides for the latest version"
else
# remote_config_version is older, local version is newer
log "✓ Local config version ($current_config_version) is newer than remote ($remote_config_version)"
fi
else
log "✓ Config is up to date"
Expand Down Expand Up @@ -272,6 +345,45 @@ validate_config() {
[[ "$DAYS_FROM" -ge 2 ]] || error "DAYS_FROM must be at least 2"
[[ "$DAYS_TO" -ge "$DAYS_FROM" ]] || error "DAYS_TO must be >= DAYS_FROM"
[[ -d "$CACHE_MOUNT" ]] || error "Cache mount does not exist: $CACHE_MOUNT"

# Validate instance configuration
local format
format=$(detect_config_format)

if [[ "$format" == "array" ]]; then
# Validate array-based config
if [[ ${#HOSTS[@]} -eq 0 ]]; then
notify "Configuration Error" "HOSTS array is empty"
error "HOSTS array is empty"
fi

if [[ ${#USERS[@]} -ne ${#HOSTS[@]} ]]; then
notify "Configuration Error" "USERS array length (${#USERS[@]}) doesn't match HOSTS (${#HOSTS[@]})"
error "USERS array length doesn't match HOSTS"
fi

if [[ ${#PASSWORDS[@]} -ne ${#HOSTS[@]} ]]; then
notify "Configuration Error" "PASSWORDS array length (${#PASSWORDS[@]}) doesn't match HOSTS (${#HOSTS[@]})"
error "PASSWORDS array length doesn't match HOSTS"
fi

# NAMES array is optional, but if present should match
if [[ -v NAMES[@] ]] && [[ ${#NAMES[@]} -gt 0 ]]; then
if [[ ${#NAMES[@]} -ne ${#HOSTS[@]} ]]; then
notify "Configuration Error" "NAMES array length (${#NAMES[@]}) doesn't match HOSTS (${#HOSTS[@]})"
error "NAMES array length doesn't match HOSTS"
fi
fi

log "✓ Using array-based configuration (${#HOSTS[@]} instance(s))"
else
# Validate legacy config
[[ -n "${QBIT_HOST_1:-}" ]] || error "QBIT_HOST_1 is not set"
[[ -n "${QBIT_USER_1:-}" ]] || error "QBIT_USER_1 is not set"
[[ -n "${QBIT_PASS_1:-}" ]] || error "QBIT_PASS_1 is not set"

log "✓ Using legacy configuration"
fi
}

# ================================
Expand Down Expand Up @@ -350,12 +462,15 @@ main() {
fi
fi

# Process instances
process_qbit_instance "$QBIT_NAME_1" "$QBIT_HOST_1" "$QBIT_USER_1" "$QBIT_PASS_1" || ((failed_instances++))
# Process all instances
local instance_count
instance_count=$(get_instance_count)

if [[ "$ENABLE_QBIT_2" == true ]]; then
process_qbit_instance "$QBIT_NAME_2" "$QBIT_HOST_2" "$QBIT_USER_2" "$QBIT_PASS_2" || ((failed_instances++))
fi
for ((i=0; i<instance_count; i++)); do
get_instance_details "$i"

process_qbit_instance "$INSTANCE_NAME" "$INSTANCE_HOST" "$INSTANCE_USER" "$INSTANCE_PASSWORD" || ((failed_instances++))
done

# Summary
log "========================================"
Expand Down
Loading
Loading