[Tutorial] Set download location on macOS

Prerequisites

  • macOS operating system
  • Infuse installed
  • Basic familiarity with Terminal

Steps to Use the Script

Step 1: Download the Script

Download and save the script to your computer.

#!/bin/bash

DEBUG_MODE=false # Set to true for debug mode, false for normal operation
SANDBOX_DIR="$(pwd)/sandbox"

CURRENT_USER=$(whoami)
SPARSE_IMAGE_NAME="Infuse.sparseimage"
MOUNT_POINT="/Users/$CURRENT_USER/Movies/Infuse"
BACKUP_FOLDER="/Users/$CURRENT_USER/Movies/Infuse_"

# Function to create empty copies of files/folders in sandbox directory
create_sandbox_copy() {
  local original_path="$1"
  local sandbox_mount_path="${original_path//$MOUNT_POINT/$SANDBOX_DIR/Mount_Point}"
  local sandbox_backup_path="${original_path//$BACKUP_FOLDER/$SANDBOX_DIR/Backup_Folder}"
  local sandbox_path="$sandbox_mount_path"
  if [ "$sandbox_mount_path" = "$original_path" ]; then
    sandbox_path="$sandbox_backup_path"
  fi

  if [ -d "$original_path" ]; then
    mkdir -p "$sandbox_path"
  elif [ -f "$original_path" ]; then
    mkdir -p "$(dirname "$sandbox_path")"
    touch "$sandbox_path"
  fi
}

# Function to execute a command or print it if in debug mode
execute_or_debug() {
  if [ "$DEBUG_MODE" = true ]; then
    echo "DEBUG: Would execute: $@"
  else
    eval "$@"
  fi
}

# Wait for all drives to be mounted
echo "Waiting for all drives to be mounted..."
while [ $(ls /Volumes | wc -l) -lt 2 ]; do
  sleep 5
done
echo "All drives are mounted."

# Get the name of the OS drive
OS_DRIVE=$(df / | tail -1 | awk '{print $1}' | xargs -I {} basename {})

# Search for the sparse image file across all available volumes
SPARSE_IMAGE=$(find /Volumes -name "$SPARSE_IMAGE_NAME" -type f -maxdepth 3 2>/dev/null | head -n 1)

# Check if the sparse image file was found
if [ -z "$SPARSE_IMAGE" ]; then
  echo "Sparse image file not found. Would you like to create one? (y/n)"
  read -r answer
  if [ "$answer" = "y" ]; then
    echo "Select the external storage to use:"
    select vol in $(ls /Volumes | grep -v "$OS_DRIVE"); do  # Ignoring the OS drive
      SPARSE_IMAGE="/Volumes/$vol/$SPARSE_IMAGE_NAME"
      echo "Enter the size of the sparse image (e.g., 100g for 100GB):"
      read -r size
      echo "Do you want an expanding volume? (y/n)"
      read -r expand
      if [ "$expand" = "y" ]; then
        execute_or_debug "hdiutil create -size $size -type SPARSE -fs HFS+J -volname Infuse \"$SPARSE_IMAGE\""
      else
        execute_or_debug "hdiutil create -size $size -type SPARSEBUNDLE -fs HFS+J -volname Infuse \"$SPARSE_IMAGE\""
      fi
      break
    done
  else
    echo "Exiting."
    exit 1
  fi
fi

echo "Sparse image file found at $SPARSE_IMAGE."

# Check if the sparse image is already mounted at the correct location
MOUNTED_VOLUME=$(hdiutil info | grep "$SPARSE_IMAGE" | awk '{ print $1 }' | xargs -I {} hdiutil info -plist -imagekey {} | grep -A1 '<key>mount-point</key>' | tail -1 | sed 's/<[^>]*>//g' | xargs)

if [ "$MOUNTED_VOLUME" = "$MOUNT_POINT" ]; then
  echo "Sparse image is already mounted at $MOUNT_POINT. Exiting."
  exit 0
elif [ ! -z "$MOUNTED_VOLUME" ]; then
  echo "Sparse image is mounted at a different location $MOUNTED_VOLUME. Unmounting..."
  execute_or_debug "hdiutil detach \"$MOUNTED_VOLUME\""
fi

# Check if the mount point directory exists
execute_or_debug "mkdir -p \"$MOUNT_POINT\""
if [ ! -d "$MOUNT_POINT" ] && [ "$DEBUG_MODE" = false ]; then
  echo "Failed to create or access mount point directory. Exiting."
  exit 1
fi

echo "Mount point directory found."

# Check if there are existing files or directories to move (excluding hidden files)
if [ "$(find $MOUNT_POINT -mindepth 1 -not -name '.*' 2>/dev/null | wc -l)" -gt 0 ]; then
  echo "Moving existing files or directories to backup folder..."
  execute_or_debug "mkdir -p \"$BACKUP_FOLDER\""
  if [ ! -d "$BACKUP_FOLDER" ] && [ "$DEBUG_MODE" = false ]; then
    echo "Failed to create or access backup folder. Exiting."
    exit 1
  fi
  execute_or_debug "find \"$MOUNT_POINT\" -mindepth 1 -not -name '.*' -exec mv {} \"$BACKUP_FOLDER\"/ \;"
else
  echo "Infuse folder is empty or contains only default or hidden files. No need to perform a backup."
fi

# Compact the sparse image
echo "Compacting the sparse image..."
execute_or_debug "hdiutil compact \"$SPARSE_IMAGE\" -batteryallowed"

# Attach the sparse image
echo "Attaching the sparse image..."
execute_or_debug "hdiutil attach \"$SPARSE_IMAGE\" -mountpoint \"$MOUNT_POINT\" -nobrowse"
echo "Sparse image attached successfully."

# Move files from backup folder to mount point, if any
if [ -d "$BACKUP_FOLDER" ]; then
  if [ "$(ls -A $BACKUP_FOLDER)" ]; then
    echo "Moving files from backup folder to mount point..."
    execute_or_debug "find \"$BACKUP_FOLDER\" -mindepth 1 -not -name '.*' -exec bash -c '
      file=\"\$1\"
      destination=\"\$2\"
      base=\$(basename \"\$file\")
      destination_file=\"\$destination/\$base\"

      if [ -f \"\$destination_file\" ]; then
        src_size=\$(stat -f%z \"\$file\")
        dest_size=\$(stat -f%z \"\$destination_file\")
        if [ \$src_size -le \$dest_size ]; then
          echo \"Source file is smaller or equal in size, skipping \$file...\"
          rm -f \"\$file\"
        else
          echo \"Moving \$file to \$destination/\$base...\"
          mv \"\$file\" \"\$destination_file\"
        fi
      else
        echo \"Moving \$file to \$destination/\$base...\"
        mv \"\$file\" \"\$destination_file\"
      fi
    ' _ {} \"$MOUNT_POINT\" \;"
    echo "Files moved and backup folder removed."
  fi

  execute_or_debug "rm -r \"$BACKUP_FOLDER\""
fi

# Function to install as a launchd service
install_service() {
  PLIST_PATH="$HOME/Library/LaunchAgents/com.user.infuse.plist"
  SCRIPT_PATH="$(pwd)/$(basename "$0")"

  # Make the script executable
  execute_or_debug "chmod +x \"$SCRIPT_PATH\""

  # Create the PLIST file
  if [ "$DEBUG_MODE" = true ]; then
    echo "DEBUG: Would create PLIST file at $PLIST_PATH"
  else
    cat <<EOL > "$PLIST_PATH"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.user.infuse</string>
  <key>ProgramArguments</key>
  <array>
    <string>$SCRIPT_PATH</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>
EOL
  fi

  execute_or_debug "launchctl load \"$PLIST_PATH\""
}

# Check if already installed as a service
PLIST_PATH="$HOME/Library/LaunchAgents/com.user.infuse.plist"
if [ ! -f "$PLIST_PATH" ]; then
  echo "This script is not installed as a service. Would you like to install it? (y/n)"
  read -r answer
  if [ "$answer" = "y" ]; then
    install_service
    echo "Installed as a service."
  else
    echo "Not installed as a service."
  fi
fi

Step 2: Open Terminal

Navigate to the folder where the script is saved.

Step 3: Make the Script Executable

Run chmod +x your_script_name.sh in Terminal.

Step 4: Run the Script

Execute the script with ./your_script_name.sh.

Step 5: Follow the Prompts

Answer the on-screen prompts to proceed. You’ll be asked questions about creating a sparse image, selecting external storage, specifying its size, and whether you want it to expand. Follow the instructions as they appear.

Step 6: Optional - Install as a Service

You’ll be asked if you want the script to run at startup. Make your selection based on your preference.

Example Output and User Prompts

When you run the script, you’ll see messages like “Waiting for all drives to be mounted” and “Sparse image file found at [Location].” You’ll also be prompted to make choices, such as:

  • Would you like to create a sparse image? (y/n)
  • Select the external storage to use.
  • Enter the size of the sparse image (e.g., 100g for 100GB).
  • Do you want an expanding volume? (y/n)
  • Would you like to install the script as a service? (y/n)

Answer these prompts to complete the process.

Conclusion

Follow these steps to set the download location on macOS.

1 Like

Tutorial

Don’t understand…. What does it do?

Moves the download directory to an external drive, SD card etc to free up space on the internal

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.