massive update. Master conf split, now modular with a load sceriprt to drive all configs to scripts. with unraid scpecific safeguard tests , and improved standardized ux. including dynamic host detect, who am i who else it there. EVERY SINGLE SCRIPT UPDATED. DEBATING THAT THIS IS ACUALLY V2

This commit is contained in:
2026-05-03 17:16:49 -04:00
parent 2691a35e80
commit ec7de648dc
72 changed files with 25640 additions and 14629 deletions
+120 -58
View File
@@ -1,42 +1,81 @@
#!/bin/bash
# -----------------------------------------------------------------------------------------------
# --------------------------------- Media Cleaner Script ---------------------------------------
# -----------------------------------------------------------------------------------------------
# Removes unwanted files from media share folders using configurable file patterns.
# Supports two profiles: anime and media — each with their own folder list and file patterns.
# Profiles and patterns are configured in Master.conf.
# Supports --dry-run to preview what would be deleted without making changes.
# ==============================================================================================
# ================================= Media Cleaner ==============================================
# ==============================================================================================
# Removes unwanted junk files from media share folders using configurable file patterns.
# Two profiles anime and media — each with their own folder list and file patterns.
# Runs daily via DAILY_MAINTENANCE_SCRIPTS after media_shares_permissions.sh.
#
# Usage:
# media_cleaner.sh anime — clean anime shares
# media_cleaner.sh media — clean media shares
# media_cleaner.sh anime --dry-run — preview anime clean
# -----------------------------------------------------------------------------------------------
# ── PROFILES ──────────────────────────────────────────────────────────────────────────────────
# anime — cleans ANIME_CLEAN_FOLDERS using ANIME_FILE_PATTERNS
# typical targets: *.sfv *.nfo *.url *.rar *.zip *.sample* etc.
#
# media — cleans MEDIA_CLEAN_FOLDERS using MEDIA_FILE_PATTERNS
# same patterns plus *.iso *.lrc (media-specific extras)
#
# ── WHAT IT REMOVES ───────────────────────────────────────────────────────────────────────────
# Junk files left behind by download clients, scene releases, and various tools:
# *.sfv *.md5 *.sha1 — checksum verification files — useless post-download
# *.nfo *.url *.lnk — scene info files — not needed in media library
# *.rar *.zip — archives — source files not needed after extraction
# *.sample* *.proof* — scene samples — never needed
# *sync-conflict* — Syncthing conflict files
# *.scr *.exe — executables — should never be in a media folder
# *.torrent — torrent files left by download clients
# *.log *.json — tool output files
#
# ── HOST AWARENESS ────────────────────────────────────────────────────────────────────────────
# detect_hosts() sets MY_ID and aliases HOST*_ANIME_CLEAN_FOLDERS → ANIME_CLEAN_FOLDERS
# and HOST*_MEDIA_CLEAN_FOLDERS → MEDIA_CLEAN_FOLDERS.
# Each server only cleans the shares it owns — correct folders per host automatically.
#
# ── SAFEGUARDS ────────────────────────────────────────────────────────────────────────────────
# acquire_lock "wait" — wait if previous run still active
# detect_hosts() — correct folder lists per host via MY_ID aliases
# Empty array guards — warns and exits cleanly if no folders or patterns configured
# Folder existence — skips missing folders with warning, continues others
# validate_unraid_cmd — notify script validated before use
# Silent by default — only problems and removals produce output
#
# ── CONFIGURATION (master_host*.conf) ─────────────────────────────────────────────────────────
# HOST*_ANIME_CLEAN_FOLDERS — folders cleaned by the anime profile on this host
# HOST*_MEDIA_CLEAN_FOLDERS — folders cleaned by the media profile on this host
# Aliased by detect_hosts() — script uses ANIME_CLEAN_FOLDERS / MEDIA_CLEAN_FOLDERS
#
# ── CONFIGURATION (master.conf) ───────────────────────────────────────────────────────────────
# ANIME_FILE_PATTERNS — file patterns removed by the anime profile
# MEDIA_FILE_PATTERNS — file patterns removed by the media profile
#
# ── USAGE ─────────────────────────────────────────────────────────────────────────────────────
# media_cleaner.sh anime — clean anime shares
# media_cleaner.sh media — clean media shares
# media_cleaner.sh anime --dry-run — preview anime clean, no deletions
# media_cleaner.sh media --dry-run — preview media clean, no deletions
# media_cleaner.sh anime --log — verbose output
# media_cleaner.sh anime --status — show config and exit
# ==============================================================================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../Master.conf"
source "$SCRIPT_DIR/../common.sh"
source "$SCRIPT_DIR/../load_config.sh"
# -----------------------------------------------------------------------------------------------
# Separate profile argument from flags
# -----------------------------------------------------------------------------------------------
# ── Separate profile argument from flags ──────────────────────────────────────────────────────
# Profile (anime|media) is a positional arg — separate before parse_args sees flags
PROFILE=""
RAW_ARGS=()
for ARG in "$@"; do
case "$ARG" in
--*|*=*) RAW_ARGS+=("$ARG") ;;
anime|media) PROFILE="$ARG" ;;
*) RAW_ARGS+=("$ARG") ;;
*) RAW_ARGS+=("$ARG") ;;
esac
done
parse_args "${RAW_ARGS[@]}"
# -----------------------------------------------------------------------------------------------
# ━━━ $ICON_GEAR Setup ━━━
# -----------------------------------------------------------------------------------------------
# ==============================================================================================
# ━━━ Setup ━━━
# ==============================================================================================
echo ""
echo "━━━ $ICON_GEAR Setup ━━━"
@@ -45,19 +84,21 @@ if [[ "$EUID" -ne 0 ]]; then
exit 1
fi
success "Running as root"
if [[ -z "$PROFILE" ]]; then
error "No profile specified"
error "Usage: media_cleaner.sh <anime|media> [--dry-run] [--log] [--status]"
exit 1
fi
acquire_lock "wait"
if ! command -v find >/dev/null 2>&1; then
error "find command not found — check findutils installation"
exit 1
fi
# detect_hosts() sets MY_ID and aliases HOST*_ANIME/MEDIA_CLEAN_FOLDERS
detect_hosts
if [[ -z "$PROFILE" ]]; then
error "No profile specified. Usage: media_cleaner.sh <anime|media> [--dry-run]"
exit 1
fi
validate_unraid_cmd \
"/usr/local/emhttp/plugins/dynamix/scripts/notify" \
"" "" \
"unRAID notify script" || warn "unRAID notify script not found — native notifications disabled"
# Resolve profile folders and patterns
case "$PROFILE" in
@@ -75,18 +116,35 @@ case "$PROFILE" in
;;
esac
info "$ICON_GEAR Profile: $PROFILE"
info "$ICON_CLEAN Folders: ${#CLEAN_FOLDERS[@]}"
info "$ICON_TRASH Patterns: ${#FILE_PATTERNS[@]}"
# Empty array guards
if [[ ${#CLEAN_FOLDERS[@]} -eq 0 ]]; then
warn "No folders configured for profile '$PROFILE' on $MY_ID"
warn "Check HOST*_${PROFILE^^}_CLEAN_FOLDERS in master_host*.conf"
exit 0
fi
# -----------------------------------------------------------------------------------------------
# ━━━ $ICON_SUMMARY Status ━━━
# -----------------------------------------------------------------------------------------------
if [[ ${#FILE_PATTERNS[@]} -eq 0 ]]; then
warn "No file patterns configured for profile '$PROFILE'"
warn "Check ${PROFILE^^}_FILE_PATTERNS in master.conf"
exit 0
fi
log "Profile: $PROFILE"
log "Folders: ${#CLEAN_FOLDERS[@]}"
log "Patterns: ${#FILE_PATTERNS[@]}"
# ==============================================================================================
# ━━━ Status ━━━
# ==============================================================================================
if [[ "$SHOW_STATUS" == true ]]; then
echo ""
echo "━━━━━ $ICON_SUMMARY STATUS ━━━━━"
echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)"
echo "$ICON_GEAR Profile: $PROFILE"
echo "$ICON_CLEAN Folders: ${CLEAN_FOLDERS[*]}"
echo "$ICON_CLEAN Folders:"
for f in "${CLEAN_FOLDERS[@]}"; do
echo " $f"
done
echo "$ICON_TRASH Patterns: ${FILE_PATTERNS[*]}"
echo "$ICON_GEAR Dry Run: $DRY_RUN"
echo "━━━━━━━━━━━━━━━━━━━━━━━"
@@ -95,11 +153,11 @@ fi
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no files will be deleted"
# -----------------------------------------------------------------------------------------------
# ━━━ $ICON_CLEAN Media Cleaner ━━━
# -----------------------------------------------------------------------------------------------
# ==============================================================================================
# ━━━ Media Cleaner ━━━
# ==============================================================================================
echo ""
echo "━━━ $ICON_CLEAN Media Cleaner — $PROFILE ━━━"
echo "━━━ $ICON_CLEAN Media Cleaner — $PROFILE$MY_ID ━━━"
echo ""
START=$(date +%s)
@@ -120,7 +178,7 @@ for FOLDER in "${CLEAN_FOLDERS[@]}"; do
# Build find command dynamically from FILE_PATTERNS array
CMD=(find "$FOLDER" -type f \()
for ((i = 0; i < ${#FILE_PATTERNS[@]}; i++)); do
for (( i = 0; i < ${#FILE_PATTERNS[@]}; i++ )); do
CMD+=(-iname "${FILE_PATTERNS[i]}")
if [[ $i -lt $(( ${#FILE_PATTERNS[@]} - 1 )) ]]; then
CMD+=(-o)
@@ -132,12 +190,12 @@ for FOLDER in "${CLEAN_FOLDERS[@]}"; do
FILE_COUNT=$("${CMD[@]}" 2>/dev/null | wc -l)
if [[ "$FILE_COUNT" -eq 0 ]]; then
success "$FOLDER_NAMEno matching files found"
log "$FOLDER_NAMEclean ✅"
echo ""
continue
fi
info "$ICON_TRASH $FILE_COUNT file(s) found in $FOLDER_NAME"
warn "$ICON_TRASH $FILE_COUNT file(s) to remove from $FOLDER_NAME"
if [[ "$DRY_RUN" == true ]]; then
warn "DRY RUN — files that would be deleted:"
@@ -147,8 +205,8 @@ for FOLDER in "${CLEAN_FOLDERS[@]}"; do
else
CLEAN_CMD=("${CMD[@]}" -exec rm -f {} +)
if "${CLEAN_CMD[@]}" 2>/dev/null; then
success "$FOLDER_NAME$FILE_COUNT file(s) removed"
TOTAL_REMOVED=$((TOTAL_REMOVED + FILE_COUNT))
log "$FOLDER_NAME$FILE_COUNT file(s) removed"
TOTAL_REMOVED=$(( TOTAL_REMOVED + FILE_COUNT ))
else
error "$FOLDER_NAME — cleanup failed"
FAILED+=("$FOLDER_NAME")
@@ -160,24 +218,28 @@ done
END=$(date +%s)
# -----------------------------------------------------------------------------------------------
# ━━━ $ICON_SUMMARY Summary ━━━
# -----------------------------------------------------------------------------------------------
# ==============================================================================================
# ━━━ Summary ━━━
# ==============================================================================================
echo "━━━━━ $ICON_SUMMARY MEDIA CLEANER SUMMARY ━━━━━"
echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)"
echo "$ICON_GEAR Profile: $PROFILE"
echo "$ICON_TIME Duration: $(format_duration $((END - START)))"
[[ ${#SKIPPED[@]} -gt 0 ]] && echo "$ICON_WARN Skipped: ${SKIPPED[*]}"
echo "$ICON_TIME Duration: $(format_duration $(( END - START )))"
[[ ${#SKIPPED[@]} -gt 0 ]] && warn "Skipped: ${SKIPPED[*]} (folders not found)"
[[ ${#FAILED[@]} -gt 0 ]] && echo "$ICON_ERROR Failed: ${FAILED[*]}"
if [[ "$DRY_RUN" == true ]]; then
echo "$ICON_WARN Status: DRY RUN — no files deleted"
warn "DRY RUN — no files deleted"
elif [[ ${#FAILED[@]} -gt 0 ]]; then
echo "$ICON_ERROR Status: $ICON_ERROR SOME FOLDERS FAILED"
notify "Media cleaner ($PROFILE) failed on $(hostname)${FAILED[*]}" "Media Cleaner" "warning"
echo "$ICON_ERROR Status: SOME FOLDERS FAILED"
notify "Media cleaner ($PROFILE) failed on $(hostname)${FAILED[*]}" \
"Media Cleaner" "warning"
elif [[ "$TOTAL_REMOVED" -eq 0 ]]; then
log "$ICON_DONE Status: clean — nothing to remove"
else
echo "$ICON_TRASH Removed: $TOTAL_REMOVED file(s)"
echo "$ICON_DONE Status: $ICON_SUCCESS DONE"
notify "Media cleaner ($PROFILE) complete on $(hostname)$TOTAL_REMOVED file(s) removed" "Media Cleaner" "normal"
warn "$ICON_TRASH Removed: $TOTAL_REMOVED file(s)"
notify "Media cleaner ($PROFILE) on $(hostname)$TOTAL_REMOVED file(s) removed" \
"Media Cleaner" "warning"
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"