Created
April 7, 2025 17:35
-
-
Save SkeLLLa/f0b14531c011788969bae6d44f0c5438 to your computer and use it in GitHub Desktop.
Import script for *arr apps to utilize hardlinking with mergerfs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Universal import script for *arr applications with MergerFS | |
# Works with Sonarr, Radarr, Lidarr, and Readarr | |
# Ensures hardlinking between downloads and destination directories | |
set -e # Exit on any error | |
# Get parameters from the *arr application | |
SOURCE_PATH="$1" | |
TARGET_PATH="$2" | |
# Determine which application is calling the script based on environment variables | |
if [[ -n "$sonarr_eventtype" ]]; then | |
APP_NAME="Sonarr" | |
elif [[ -n "$radarr_eventtype" ]]; then | |
APP_NAME="Radarr" | |
elif [[ -n "$lidarr_eventtype" ]]; then | |
APP_NAME="Lidarr" | |
elif [[ -n "$readarr_eventtype" ]]; then | |
APP_NAME="Readarr" | |
else | |
# Try to guess based on the path | |
if [[ "$TARGET_PATH" == */series/* ]]; then | |
APP_NAME="Sonarr" | |
elif [[ "$TARGET_PATH" == */movies/* ]]; then | |
APP_NAME="Radarr" | |
elif [[ "$TARGET_PATH" == */music/* ]]; then | |
APP_NAME="Lidarr" | |
elif [[ "$TARGET_PATH" == */books/* ]]; then | |
APP_NAME="Readarr" | |
else | |
APP_NAME="Unknown" | |
fi | |
fi | |
# Log file for debugging | |
LOG_FILE="/tmp/${APP_NAME,,}_import.log" | |
# Function to log messages | |
log() { | |
echo "$(date '+%Y-%m-%d %H:%M:%S') - $APP_NAME - $1" | tee -a "$LOG_FILE" | |
} | |
# Check if parameters are provided | |
if [ -z "$SOURCE_PATH" ] || [ -z "$TARGET_PATH" ]; then | |
log "Error: Source or target path not provided" | |
log "Usage: $0 <source_path> <target_path>" | |
exit 1 | |
fi | |
log "Starting import from $SOURCE_PATH to $TARGET_PATH" | |
# Find the actual physical location of the source file using getfattr | |
SOURCE_BASE_PATH=$(getfattr -n user.mergerfs.basepath --only-values "$SOURCE_PATH" 2>/dev/null || echo "") | |
if [ -z "$SOURCE_BASE_PATH" ]; then | |
log "Error: Could not determine the physical location of the source file" | |
log "Make sure the getfattr utility is installed and the file has the mergerfs attribute" | |
exit 1 | |
fi | |
log "Physical base path: $SOURCE_BASE_PATH" | |
# Get the relative path from the mergerfs mount point | |
RELATIVE_PATH=${SOURCE_PATH#/media/storage/} | |
log "Relative path: $RELATIVE_PATH" | |
# Construct the full physical source path | |
PHYSICAL_SOURCE_PATH="${SOURCE_BASE_PATH}/${RELATIVE_PATH}" | |
log "Full physical source path: $PHYSICAL_SOURCE_PATH" | |
# Modify the target path to be on the same physical drive | |
RELATIVE_TARGET_PATH=${TARGET_PATH#/media/storage/} | |
PHYSICAL_TARGET_PATH="${SOURCE_BASE_PATH}/${RELATIVE_TARGET_PATH}" | |
log "Physical target path: $PHYSICAL_TARGET_PATH" | |
# Create the directory structure for the physical target | |
PHYSICAL_TARGET_DIR=$(dirname "$PHYSICAL_TARGET_PATH") | |
mkdir -p "$PHYSICAL_TARGET_DIR" | |
# Create a hardlink from physical source to the physical target | |
log "Creating hardlink from $PHYSICAL_SOURCE_PATH to $PHYSICAL_TARGET_PATH" | |
if ln "$PHYSICAL_SOURCE_PATH" "$PHYSICAL_TARGET_PATH"; then | |
log "Hardlink created successfully" | |
# Handle associated files based on the application type | |
SOURCE_DIR=$(dirname "$PHYSICAL_SOURCE_PATH") | |
SOURCE_FILENAME=$(basename "$PHYSICAL_SOURCE_PATH") | |
SOURCE_NAME="${SOURCE_FILENAME%.*}" | |
# Define file extensions to look for based on application | |
case "$APP_NAME" in | |
"Sonarr") | |
# Video and subtitle files | |
EXTENSIONS=(".srt" ".sub" ".idx" ".ass" ".ssa" ".vtt" ".nfo") | |
;; | |
"Radarr") | |
# Video and subtitle files | |
EXTENSIONS=(".srt" ".sub" ".idx" ".ass" ".ssa" ".vtt" ".nfo") | |
;; | |
"Lidarr") | |
# Audio and metadata files | |
EXTENSIONS=(".cue" ".log" ".jpg" ".jpeg" ".png" ".pdf" ".nfo") | |
;; | |
"Readarr") | |
# E-book related files | |
EXTENSIONS=(".opf" ".jpg" ".jpeg" ".png" ".pdf") | |
;; | |
*) | |
# Default - try common extensions | |
EXTENSIONS=(".srt" ".sub" ".idx" ".jpg" ".jpeg" ".png" ".nfo") | |
;; | |
esac | |
# Look for associated files with the same base name | |
for EXT in "${EXTENSIONS[@]}"; do | |
for ASSOC_FILE in "$SOURCE_DIR/$SOURCE_NAME"*"$EXT"; do | |
if [ -f "$ASSOC_FILE" ]; then | |
ASSOC_FILENAME=$(basename "$ASSOC_FILE") | |
PHYSICAL_TARGET_ASSOC="${PHYSICAL_TARGET_DIR}/${ASSOC_FILENAME}" | |
log "Found associated file: $ASSOC_FILE" | |
log "Creating hardlink for associated file to $PHYSICAL_TARGET_ASSOC" | |
ln "$ASSOC_FILE" "$PHYSICAL_TARGET_ASSOC" || log "Warning: Failed to hardlink associated file $ASSOC_FILE" | |
fi | |
done | |
done | |
# Special case for multi-file media (like music albums or book series) | |
if [[ "$APP_NAME" == "Lidarr" || "$APP_NAME" == "Readarr" ]]; then | |
# If the source is a directory, hardlink all files inside it | |
if [ -d "$PHYSICAL_SOURCE_PATH" ]; then | |
log "Source is a directory, hardlinking all files inside" | |
find "$PHYSICAL_SOURCE_PATH" -type f -print0 | while IFS= read -r -d '' FILE; do | |
REL_PATH="${FILE#$PHYSICAL_SOURCE_PATH/}" | |
TARGET_FILE="$PHYSICAL_TARGET_PATH/$REL_PATH" | |
TARGET_DIR=$(dirname "$TARGET_FILE") | |
mkdir -p "$TARGET_DIR" | |
ln "$FILE" "$TARGET_FILE" || log "Warning: Failed to hardlink $FILE" | |
done | |
fi | |
fi | |
log "Import completed successfully" | |
exit 0 | |
else | |
log "Error: Failed to create hardlink" | |
exit 1 | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment