changemaker.lite/media-manager/scripts/organize_by_studio.sh

611 lines
26 KiB
Bash
Executable File

#!/bin/bash
# Script to organize MP4 files by studio name with video metadata
# Format: Studio - Performer(s) - Title [DD-MM-YYYY] [H:MM] [Quality] [H/V].mp4
# Enable strict error handling
set -o pipefail # Catch failures in piped commands
# Use environment variable if set (for Docker), otherwise use default path
ROOT_DIR="${SOURCE_LIBRARY:-/media/bunker-admin/Internal/plex/xxx/media/local/studios}"
GIFS_DIR="${GIFS_PATH:-/media/bunker-admin/Internal/plex/xxx/media/local/gifs}"
INBOX_DIR="${INBOX_PATH:-/media/bunker-admin/Internal/plex/xxx/media/local/inbox}"
COMPILATIONS_DIR="${COMPILATIONS_PATH:-/media/bunker-admin/Internal/plex/xxx/media/public/compilations}"
cd "$ROOT_DIR" || exit 1
# Check if ffprobe is available
if ! command -v ffprobe &> /dev/null; then
echo "Error: ffprobe is not installed. Please install ffmpeg."
exit 1
fi
# Function to get video duration in h:mm format
get_duration() {
local file="$1"
local seconds=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)
if [[ -n "$seconds" ]]; then
local hours=$((${seconds%.*} / 3600))
local minutes=$(((${seconds%.*} % 3600) / 60))
printf "%d:%02d" "$hours" "$minutes"
else
echo "0:00"
fi
}
# Function to detect orientation
get_orientation() {
local file="$1"
local width=$(ffprobe -v error -select_streams v:0 -show_entries stream=width -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)
local height=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)
if [[ -n "$width" ]] && [[ -n "$height" ]]; then
if [[ $height -gt $width ]]; then
echo "V"
else
echo "H"
fi
else
echo "H"
fi
}
# Function to detect video quality
get_quality() {
local file="$1"
local height=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)
if [[ -n "$height" ]]; then
if [[ $height -ge 2160 ]]; then
echo "4K"
elif [[ $height -ge 1440 ]]; then
echo "1440p"
elif [[ $height -ge 1080 ]]; then
echo "1080p"
elif [[ $height -ge 720 ]]; then
echo "720p"
elif [[ $height -ge 480 ]]; then
echo "480p"
else
echo "SD"
fi
else
echo "720p"
fi
}
# Function to check if file is already H.265/HEVC encoded
is_hevc() {
local file="$1"
local codec=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)
[[ "$codec" == "hevc" ]] || [[ "$codec" == "h265" ]]
}
# Function to check if filename has [E] encoded flag
has_encoded_flag() {
local filename="$1"
[[ "$filename" =~ \[E\] ]]
}
# Function to extract and format date from filename
extract_date() {
local filename="$1"
local date=""
# Try YY.MM.DD format (e.g., 25.11.19)
if [[ "$filename" =~ ([0-9]{2})\.([0-9]{2})\.([0-9]{2}) ]]; then
date="${BASH_REMATCH[3]}-${BASH_REMATCH[2]}-20${BASH_REMATCH[1]}"
# Try YYYY.MM.DD format
elif [[ "$filename" =~ (20[0-9]{2})\.([0-9]{2})\.([0-9]{2}) ]]; then
date="${BASH_REMATCH[3]}-${BASH_REMATCH[2]}-${BASH_REMATCH[1]}"
# Try YYYYMMDD format
elif [[ "$filename" =~ (20[0-9]{2})([0-9]{2})([0-9]{2}) ]]; then
date="${BASH_REMATCH[3]}-${BASH_REMATCH[2]}-${BASH_REMATCH[1]}"
# Try DD-MM-YYYY format
elif [[ "$filename" =~ ([0-9]{2})-([0-9]{2})-(20[0-9]{2}) ]]; then
date="${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-${BASH_REMATCH[3]}"
# Try (DD.MM.YYYY) format
elif [[ "$filename" =~ \(([0-9]{2})\.([0-9]{2})\.([0-9]{4})\) ]]; then
date="${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-${BASH_REMATCH[3]}"
fi
echo "$date"
}
# Function to clean and standardize filename
clean_filename() {
local name="$1"
local studio="$2"
# Remove common release group tags and patterns (case insensitive) but preserve quality info
name=$(echo "$name" | sed -E 's/\.(XXX|[XC]|MP4|WEB|HD)\..*//gi')
name=$(echo "$name" | sed -E 's/ (XXX|WEB|HD).*//gi')
# Remove existing metadata tags
name=$(echo "$name" | sed -E 's/ \[[0-9]+:[0-9]+\]//g')
name=$(echo "$name" | sed -E 's/ \[[HV]\]//g')
name=$(echo "$name" | sed -E 's/ \[[0-9]{2}-[0-9]{2}-[0-9]{4}\]//g')
name=$(echo "$name" | sed -E 's/ \[(4K|1440p|1080p|720p|480p|SD)\]//g')
name=$(echo "$name" | sed -E 's/ \[E\]//g')
# Remove " rq" suffix (release quality tag)
name=$(echo "$name" | sed -E 's/ rq$//gi')
# Remove quality tags from title but preserve them for later
name=$(echo "$name" | sed -E 's/\.(4K|2160p|1440p|1080p|720p|480p)//gi')
name=$(echo "$name" | sed -E 's/ (4K|2160p|1440p|1080p|720p|480p)//gi')
name=$(echo "$name" | sed -E 's/_720p$//gi')
# Remove dates from the main title
name=$(echo "$name" | sed -E 's/\.?[0-9]{2}\.[0-9]{2}\.[0-9]{2}\.?//g')
name=$(echo "$name" | sed -E 's/\.?(20[0-9]{2})\.[0-9]{2}\.[0-9]{2}\.?//g')
name=$(echo "$name" | sed -E 's/(20[0-9]{2})[0-9]{6}//g')
name=$(echo "$name" | sed -E 's/[0-9]{2}-[0-9]{2}-(20[0-9]{2})//g')
name=$(echo "$name" | sed -E 's/\([0-9]{2}\.[0-9]{2}\.[0-9]{4}\)//g')
# Special handling for OnlyFans
if [[ "$studio" == "OnlyFans" ]]; then
# Remove "onlyfans" prefix (case insensitive)
name=$(echo "$name" | sed -E 's/^[Oo]nly[Ff]ans\.?//g')
name=$(echo "$name" | sed -E 's/^[Oo]nly[Ff]ans //g')
# Remove year prefix/suffix like "2025" or " 2025 "
name=$(echo "$name" | sed -E 's/^20[0-9]{2}\.?//g')
name=$(echo "$name" | sed -E 's/^20[0-9]{2} //g')
name=$(echo "$name" | sed -E 's/ 20[0-9]{2} / /g')
# Remove "xxx" suffix
name=$(echo "$name" | sed -E 's/ xxx$//gi')
# Don't extract if already has the pattern - just return it
# This prevents adding extra dashes when re-processing
fi
# Remove studio name prefix (case insensitive)
name=$(echo "$name" | sed -E "s/^${studio}\.//gi")
name=$(echo "$name" | sed -E "s/^${studio} //gi")
# Replace dots and underscores with spaces
name=$(echo "$name" | tr '._' ' ')
# Remove multiple spaces
name=$(echo "$name" | sed -E 's/ +/ /g')
# Trim leading/trailing spaces and dashes
name=$(echo "$name" | sed -E 's/^[\ -]+| +$//g')
# Capitalize first letter of each word for better readability
name=$(echo "$name" | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1')
echo "$name"
}
# ===========================================
# INBOX PROCESSING - Sort files to correct directories
# ===========================================
echo "=== Processing Inbox Directory ==="
if [[ -d "$INBOX_DIR" ]]; then
# Search recursively for mp4 files (handles release group folders)
inbox_count=$(find "$INBOX_DIR" -type f -name "*.mp4" 2>/dev/null | wc -l)
if [[ $inbox_count -gt 0 ]]; then
echo "Found $inbox_count file(s) in inbox"
find "$INBOX_DIR" -type f -name "*.mp4" | while read -r file; do
filename=$(basename "$file")
echo "Processing: $filename"
# Determine destination based on filename patterns
destination=""
# Check if file is inside a digest output folder (Clips - * or Scenes - *)
parent_dir=$(basename "$(dirname "$file")")
if [[ "$parent_dir" == Clips\ -\ * ]] || [[ "$parent_dir" == Scenes\ -\ * ]]; then
destination="$GIFS_DIR/$parent_dir"
echo " -> GIFs/$parent_dir (digest output)"
# Check for OnlyFans content (treated as a regular studio)
elif [[ "$filename" =~ ^[Oo]nly[Ff]ans ]] || [[ "$filename" =~ [Oo]nly[Ff]ans\.? ]]; then
destination="$ROOT_DIR/OnlyFans"
echo " -> Studios/OnlyFans (detected OnlyFans pattern)"
# Check for known GIF/clip patterns (short duration indicator or known creators)
# Files with [Xs] duration tag are likely GIFs
elif [[ "$filename" =~ \[[0-9]+s\] ]]; then
# Extract creator name (first part before any separator)
if [[ "$filename" =~ ^([A-Za-z0-9_-]+) ]]; then
creator="${BASH_REMATCH[1]}"
# Check if creator directory exists in gifs
if [[ -d "$GIFS_DIR/$creator" ]]; then
destination="$GIFS_DIR/$creator"
echo " -> GIFs/$creator (detected short clip for existing creator)"
else
destination="$GIFS_DIR"
echo " -> GIFs (detected short clip)"
fi
else
destination="$GIFS_DIR"
echo " -> GIFs (detected short clip)"
fi
# Check file duration for potential GIF content (under 2 minutes)
else
duration_sec=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null | cut -d. -f1)
if [[ -n "$duration_sec" ]] && [[ "$duration_sec" -lt 120 ]]; then
# Short file - likely a GIF/clip
# Try to match to existing creator
if [[ "$filename" =~ ^([A-Za-z0-9_-]+) ]]; then
creator="${BASH_REMATCH[1]}"
if [[ -d "$GIFS_DIR/$creator" ]]; then
destination="$GIFS_DIR/$creator"
echo " -> GIFs/$creator (short file, matched creator)"
else
destination="$GIFS_DIR"
echo " -> GIFs (short file < 2min)"
fi
else
destination="$GIFS_DIR"
echo " -> GIFs (short file < 2min)"
fi
else
# Regular video - goes to studios
# Try to extract studio from filename
if [[ "$filename" =~ ^([A-Za-z0-9]+)[\.\-\ ] ]]; then
studio="${BASH_REMATCH[1]}"
destination="$ROOT_DIR/$studio"
mkdir -p "$destination"
echo " -> Studios/$studio"
else
destination="$ROOT_DIR"
echo " -> Studios (root)"
fi
fi
fi
# Copy file to destination (non-destructive - keeps original in inbox)
if [[ -n "$destination" ]]; then
mkdir -p "$destination"
cp "$file" "$destination/"
echo " Copied to: $destination/"
fi
done
# Note: We intentionally do NOT clean up the inbox directory
# Files remain in inbox until manually deleted by user
echo "Inbox files copied (originals retained in inbox)"
else
echo "Inbox is empty"
fi
else
echo "Inbox directory not found, skipping"
fi
echo ""
# Find all MP4 files (including root level)
find . -mindepth 1 -type f -name "*.mp4" | while read -r file; do
# Skip files in excluded directories
if [[ "$file" =~ /scripts/ ]] || [[ "$file" =~ /spankbang/ ]] || [[ "$file" =~ /gifs/ ]]; then
continue
fi
# Skip compilation files (files with " - Compilation [H]" or " - Compilation [V]" in name)
filename=$(basename "$file")
if [[ "$filename" =~ " - Compilation [HV]].mp4"$ ]]; then
continue
fi
dir=$(dirname "$file")
depth=$(echo "$dir" | tr -cd '/' | wc -c)
dirname=$(basename "$dir")
filename=$(basename "$file")
# SKIP if file already has proper [H:MM] [quality] [H/V] format and is in correct directory
# This check happens BEFORE any ffprobe calls for efficiency
# [E] flag is optional - files may or may not have been re-encoded yet
if [[ "$filename" =~ \[[0-9]+:[0-9]+\].*\[(4K|1440p|1080p|720p|480p|SD)\].*(\[E\].*)?(\[[HV]\])\.mp4$ ]]; then
# File has all metadata tags - check if it's in correct studio folder
if [[ $depth -eq 1 ]]; then
# Already in a studio folder with proper tags, skip
continue
fi
# Check if in OnlyFans performer subdirectory
parent_dir=$(dirname "$dir")
parent_name=$(basename "$parent_dir")
if [[ "$parent_name" == "OnlyFans" ]] && [[ $depth -eq 2 ]]; then
# In OnlyFans performer subdirectory with proper tags, skip
continue
fi
fi
# Check if file needs metadata update
needs_update=false
needs_rename=false
# Check if filename already has metadata tags (excluding [E] which is optional)
if [[ ! "$filename" =~ \[[0-9]+:[0-9]+\] ]] || [[ ! "$filename" =~ \[[HV]\] ]] || [[ ! "$filename" =~ \[(4K|1440p|1080p|720p|480p|SD)\] ]]; then
needs_rename=true
fi
# Check if filename needs cleaning (has periods, underscores, or dates in title)
# Note: We exclude ".mp4" from period check
name_without_ext="${filename%.mp4}"
if [[ "$name_without_ext" =~ \. ]] || [[ "$name_without_ext" =~ _ ]] || [[ "$filename" =~ [0-9]{2}\.[0-9]{2}\.[0-9]{2} ]] || [[ "$filename" =~ (20[0-9]{2})[0-9]{6} ]] || [[ "$filename" =~ (^|[^0-9])(20[0-9]{2})([^0-9]) ]] || [[ "$filename" =~ XXX ]] || [[ "$filename" =~ 1080p ]] || [[ "$filename" =~ 2160p ]]; then
needs_rename=true
fi
# Extract studio name
studio=""
# If file is in root, try to extract studio from filename
if [[ "$dir" == "." ]]; then
if [[ "$filename" =~ ^([A-Za-z0-9]+)\. ]] || [[ "$filename" =~ ^([A-Za-z0-9]+)\ -\ ]]; then
studio="${BASH_REMATCH[1]}"
else
studio="Unknown"
fi
needs_update=true # Files in root always need to be moved
else
# Check if already in a performer subdirectory under OnlyFans
parent_dir=$(dirname "$dir")
parent_name=$(basename "$parent_dir")
# If parent is OnlyFans and current dir is a performer folder, skip
if [[ "$parent_name" == "OnlyFans" ]] && [[ $depth -eq 2 ]]; then
continue
fi
# Extract from directory name
if [[ "$dirname" =~ ^([A-Za-z0-9]+)\. ]]; then
studio="${BASH_REMATCH[1]}"
elif [[ "$dirname" =~ ^([A-Za-z0-9]+)\ -\ ]]; then
studio="${BASH_REMATCH[1]}"
else
studio="$dirname"
fi
# Check if file is in wrong directory
if [[ $depth -eq 1 ]] && [[ "$dirname" == "$studio" ]]; then
# File is already in correct studio folder, check if it needs renaming
if [[ "$needs_rename" == true ]]; then
needs_update=true
fi
else
# File needs to be moved
needs_update=true
fi
fi
# Process file if it needs update or rename
if [[ "$needs_update" == true ]] || [[ "$needs_rename" == true ]]; then
echo "Analyzing: $file"
duration=$(get_duration "$file")
orientation=$(get_orientation "$file")
quality=$(get_quality "$file")
date=$(extract_date "$filename")
# Create studio directory if it doesn't exist
if [[ -n "$studio" ]]; then
mkdir -p "$ROOT_DIR/$studio"
# Clean and standardize filename
clean_name=$(clean_filename "${filename%.*}" "$studio")
ext="${filename##*.}"
# For OnlyFans, ensure proper format: OnlyFans - Name - Description
if [[ "$studio" == "OnlyFans" ]]; then
# Check if clean_name already has " - Name - Description" pattern
if [[ "$clean_name" =~ ^([A-Z][a-z]+([\ ][A-Z][a-z]+){0,3})[\ ]-[\ ](.+)$ ]]; then
# Already has the proper format, just add OnlyFans prefix
performer="${BASH_REMATCH[1]}"
description="${BASH_REMATCH[3]}"
new_filename="OnlyFans - ${performer} - ${description}"
# Try to extract performer name (typically first 1-3 capitalized words)
elif [[ "$clean_name" =~ ^([A-Z][a-z]+([\ ][A-Z][a-z]+){0,2})([\ ].+)$ ]]; then
# Has "Name Description" pattern - add separator
performer="${BASH_REMATCH[1]}"
description="${BASH_REMATCH[3]}"
description=$(echo "$description" | sed -E 's/^ +//g')
new_filename="OnlyFans - ${performer} - ${description}"
else
# Can't extract name, just add OnlyFans prefix
# Clean up any leading dashes or spaces
clean_name=$(echo "$clean_name" | sed -E 's/^[\ -]+//g')
if [[ -n "$clean_name" ]]; then
new_filename="OnlyFans - ${clean_name}"
else
new_filename="OnlyFans"
fi
fi
# For other studios with performer names in title
elif [[ "$studio" =~ ^(IntimatePOV|LegalPorno|AccidentalGangbang|18Lust|BlackedRaw|PublicBang|OnlyTarts|Wifey)$ ]]; then
# Try to intelligently separate performer from title
# Look for common title indicator words
if [[ "$clean_name" =~ ^([A-Z][a-z]+([\ ][A-Z][a-z]+){0,3})([\ ](Is|A|The|With|For|On|Of|To|In|Her|Your|My|Lets|Pretend|Seducing|Doubling|Naked|Morning|Sub|Likes|Over).+)$ ]]; then
performer="${BASH_REMATCH[1]}"
title="${BASH_REMATCH[3]}"
title=$(echo "$title" | sed -E 's/^ +//g')
new_filename="${studio} - ${performer} - ${title}"
else
# No clear separator, just use studio and clean name
# Clean up any leading dashes or spaces
clean_name=$(echo "$clean_name" | sed -E 's/^[\ -]+//g')
if [[ -n "$clean_name" ]]; then
new_filename="${studio} - ${clean_name}"
else
new_filename="${studio}"
fi
fi
else
# For unknown studios, clean up leading dashes/spaces
clean_name=$(echo "$clean_name" | sed -E 's/^[\ -]+//g')
if [[ -n "$clean_name" ]]; then
new_filename="${clean_name}"
else
new_filename="${studio}"
fi
fi
# Determine if file should have [E] encoded flag
# Preserve existing [E] flag or add if video is HEVC encoded
encoded_flag=""
if has_encoded_flag "$filename"; then
encoded_flag=" [E]"
elif is_hevc "$file"; then
encoded_flag=" [E]"
echo " Adding [E] flag: Already HEVC encoded"
fi
# Add metadata tags
# Format: [date] [duration] [quality] [E] [orientation]
if [[ -n "$date" ]]; then
new_filename="${new_filename} [${date}] [${duration}] [${quality}]${encoded_flag} [${orientation}].${ext}"
else
new_filename="${new_filename} [${duration}] [${quality}]${encoded_flag} [${orientation}].${ext}"
fi
# Clean up any multiple dashes that may have been created
new_filename=$(echo "$new_filename" | sed -E 's/ - - - / - /g' | sed -E 's/ - - / - /g')
# Set target path (all studios use ROOT_DIR)
target_path="$ROOT_DIR/$studio/$new_filename"
# Only move/rename if target is different from source
if [[ "$file" != "./$studio/$new_filename" ]]; then
echo "Processing: $file -> $studio/$new_filename"
mv "$file" "$target_path"
fi
fi
fi
done
echo ""
echo "Done organizing studio files!"
echo ""
echo "=== Organizing GIFs folder ==="
# Function to get duration in seconds for gifs
get_duration_seconds() {
local file="$1"
local seconds=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file" 2>/dev/null)
if [[ -n "$seconds" ]]; then
printf "%.0f" "$seconds"
else
echo "0"
fi
}
if [[ -d "$GIFS_DIR" ]]; then
cd "$GIFS_DIR" || exit 1
# Process each creator directory
for creator_dir in */; do
if [[ -d "$creator_dir" ]]; then
creator_name="${creator_dir%/}"
echo "Processing: $creator_name"
# Create horizontal/vertical subdirs if they don't exist
mkdir -p "$creator_name/horizontal"
mkdir -p "$creator_name/vertical"
# Process ALL mp4 files in creator directory (root and subdirs)
find "$creator_name" -type f -name "*.mp4" | while read -r file; do
filename=$(basename "$file")
file_dir=$(dirname "$file")
# SKIP compilation files - they should stay in the creator root directory
# Match ANY file with " - Compilation " in the name (whether freshly created or already tagged)
if [[ "$filename" == *" - Compilation "* ]]; then
# This is a generated compilation file
# Move it to creator root if it's in a subdirectory
if [[ "$file_dir" != "$creator_name" ]]; then
echo " Moving compilation to root: $filename"
mv "$file" "$creator_name/$filename"
fi
continue
fi
# SKIP if file already has proper [Xs] [quality] [H/V] format
# This check happens BEFORE any ffprobe calls for efficiency
# [E] flag is optional - files may or may not have been re-encoded yet
if [[ "$filename" =~ \[[0-9]+s\].*\[(4K|1440p|1080p|720p|480p|SD)\].*(\[E\].*)?(\[[HV]\])\.mp4$ ]]; then
# File is already fully processed
# Just check if it's in the correct H/V subdirectory
if [[ "$filename" =~ \[H\]\.mp4$ ]] && [[ "$file_dir" == *"/horizontal" ]]; then
continue # Already in correct place
elif [[ "$filename" =~ \[V\]\.mp4$ ]] && [[ "$file_dir" == *"/vertical" ]]; then
continue # Already in correct place
fi
# Move to correct subdirectory without re-analyzing
if [[ "$filename" =~ \[H\]\.mp4$ ]]; then
target_dir="$creator_name/horizontal"
else
target_dir="$creator_name/vertical"
fi
if [[ "$file" != "$target_dir/$filename" ]]; then
echo " Moving: $filename -> $target_dir/"
mv "$file" "$target_dir/$filename"
fi
continue
fi
# File needs processing - now run ffprobe
echo " Analyzing: $filename"
orientation=$(get_orientation "$file")
quality=$(get_quality "$file")
duration_sec=$(get_duration_seconds "$file")
# Clean filename - remove existing tags and extension
clean_name="${filename%.*}"
clean_name=$(echo "$clean_name" | sed -E 's/ \[[0-9]+:[0-9]+\]//g')
clean_name=$(echo "$clean_name" | sed -E 's/ \[[0-9]+s\]//g')
clean_name=$(echo "$clean_name" | sed -E 's/ \[[HV]\]//g')
clean_name=$(echo "$clean_name" | sed -E 's/ \[(4K|1440p|1080p|720p|480p|SD)\]//g')
clean_name=$(echo "$clean_name" | sed -E 's/ \[E\]//g')
# Determine if file should have [E] encoded flag
encoded_flag=""
if has_encoded_flag "$filename"; then
encoded_flag=" [E]"
elif is_hevc "$file"; then
encoded_flag=" [E]"
echo " Adding [E] flag: Already HEVC encoded"
fi
# Build new filename with metadata
# Format: [Xs] [quality] [E] [orientation]
new_filename="${clean_name} [${duration_sec}s] [${quality}]${encoded_flag} [${orientation}].mp4"
# Determine target directory based on orientation
if [[ "$orientation" == "H" ]]; then
target_dir="$creator_name/horizontal"
else
target_dir="$creator_name/vertical"
fi
# Only move/rename if needed
if [[ "$file" != "$target_dir/$new_filename" ]]; then
echo " -> $target_dir/$(basename "$new_filename")"
mv "$file" "$target_dir/$new_filename"
fi
done
# Clean up empty subdirectories (like old square folders if emptied)
find "$creator_name" -mindepth 1 -type d -empty -delete 2>/dev/null
fi
done
cd "$ROOT_DIR" || exit 1
fi
echo ""
echo "Cleaning up old directories..."
# Remove the now-empty source directories that match typical release naming patterns
find . -mindepth 1 -maxdepth 1 -type d \( -name "*XXX*" -o -name "*[XC]" -o -name "*.MP4-*" \) -exec rm -rf {} + 2>/dev/null
# Remove any remaining empty directories
find . -mindepth 1 -type d -empty -delete 2>/dev/null
echo ""
echo "Complete!"