.
This commit is contained in:
200
unRAID Userscript/music_sync.sh
Normal file
200
unRAID Userscript/music_sync.sh
Normal file
@@ -0,0 +1,200 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ----------------------------------------
|
||||
# CONFIG
|
||||
# ----------------------------------------
|
||||
INCOMING="/mnt/user/Cache/Picard/incoming"
|
||||
READY="/mnt/user/Cache/Picard/ready"
|
||||
|
||||
DEST1="/mnt/user/Cache/Syncthing/Julian/Musik/Thorsten -> Julian"
|
||||
DEST2="/mnt/user/Media/Musik/[0] Navidrome"
|
||||
|
||||
LOG="/mnt/user/Cache/Picard/sync.log"
|
||||
LOCKFILE="/mnt/user/Cache/Picard/sync.lock"
|
||||
|
||||
LOG_LINES=5000
|
||||
|
||||
DRY_RUN=false
|
||||
|
||||
CHOWN_USER="thorsten"
|
||||
CHOWN_GROUP="users"
|
||||
|
||||
# ----------------------------------------
|
||||
# NORMALIZE PATHS
|
||||
# ----------------------------------------
|
||||
normalize_path() {
|
||||
local p="$1"
|
||||
[[ "$p" != "/" ]] && p="${p%/}"
|
||||
echo "$p"
|
||||
}
|
||||
|
||||
INCOMING="$(normalize_path "$INCOMING")"
|
||||
READY="$(normalize_path "$READY")"
|
||||
DEST1="$(normalize_path "$DEST1")"
|
||||
DEST2="$(normalize_path "$DEST2")"
|
||||
|
||||
# ----------------------------------------
|
||||
# FUNCTIONS
|
||||
# ----------------------------------------
|
||||
log() {
|
||||
MSG="$(date '+%Y-%m-%d %H:%M:%S') | $1"
|
||||
echo "$MSG"
|
||||
echo "$MSG" >> "$LOG"
|
||||
}
|
||||
|
||||
rotate_log() {
|
||||
if [ -f "$LOG" ]; then
|
||||
tail -n "$LOG_LINES" "$LOG" > "${LOG}.tmp" && mv "${LOG}.tmp" "$LOG"
|
||||
fi
|
||||
}
|
||||
|
||||
run_cmd() {
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
log "[DRY-RUN] $*"
|
||||
else
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
|
||||
rsync_cmd() {
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
rsync -a --dry-run "$@"
|
||||
return 0
|
||||
else
|
||||
rsync -a "$@"
|
||||
return $?
|
||||
fi
|
||||
}
|
||||
|
||||
# ----------------------------------------
|
||||
# VERIFY DESTINATIONS
|
||||
# ----------------------------------------
|
||||
for DEST in "$DEST1" "$DEST2"; do
|
||||
if [ ! -d "$DEST" ]; then
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') | ERROR: Destination not found -> $DEST"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# ----------------------------------------
|
||||
# LOCKFILE
|
||||
# ----------------------------------------
|
||||
if [ -f "$LOCKFILE" ]; then
|
||||
echo "Lockfile exists -> $LOCKFILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
trap "rm -f '$LOCKFILE'" EXIT
|
||||
touch "$LOCKFILE"
|
||||
|
||||
# ----------------------------------------
|
||||
# QUICK EXIT
|
||||
# ----------------------------------------
|
||||
if ! find "$INCOMING" -type f -mmin +1 -print -quit | grep -q .; then
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') | No files to process -> exit"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ----------------------------------------
|
||||
# START
|
||||
# ----------------------------------------
|
||||
rotate_log
|
||||
log "========================================"
|
||||
log "START RUN (DRY_RUN=$DRY_RUN)"
|
||||
log "========================================"
|
||||
|
||||
# ----------------------------------------
|
||||
# TRACK CHOWNED DIRECTORIES
|
||||
# ----------------------------------------
|
||||
declare -A CHOWN_DONE_DIRS
|
||||
|
||||
# ----------------------------------------
|
||||
# 1. INCOMING → READY
|
||||
# ----------------------------------------
|
||||
log "---- MOVE: INCOMING → READY ----"
|
||||
|
||||
find "$INCOMING" -type f -mmin +1 | while read -r FILE; do
|
||||
|
||||
[ -f "$FILE" ] || continue
|
||||
|
||||
REL="${FILE#"$INCOMING"/}"
|
||||
TARGET="$READY/$REL"
|
||||
|
||||
mkdir -p "$READY/$(dirname "$REL")"
|
||||
|
||||
log "MOVE -> $REL"
|
||||
run_cmd mv "$FILE" "$TARGET"
|
||||
|
||||
done
|
||||
|
||||
# ----------------------------------------
|
||||
# 2. READY → DESTS
|
||||
# ----------------------------------------
|
||||
log "---- SYNC: READY → DESTINATIONS ----"
|
||||
log "DEST1: $DEST1"
|
||||
log "DEST2: $DEST2"
|
||||
|
||||
find "$READY" -type f 2>/dev/null | while read -r FILE; do
|
||||
|
||||
[ -f "$FILE" ] || continue
|
||||
|
||||
REL="${FILE#"$READY"/}"
|
||||
|
||||
DEST1_FILE="$DEST1/$REL"
|
||||
DEST2_FILE="$DEST2/$REL"
|
||||
|
||||
mkdir -p "$(dirname "$DEST1_FILE")"
|
||||
mkdir -p "$(dirname "$DEST2_FILE")"
|
||||
|
||||
log "SYNC -> $REL"
|
||||
|
||||
rsync_cmd "$FILE" "$DEST1_FILE"
|
||||
STATUS1=$?
|
||||
|
||||
rsync_cmd "$FILE" "$DEST2_FILE"
|
||||
STATUS2=$?
|
||||
|
||||
if [[ $STATUS1 -eq 0 && $STATUS2 -eq 0 ]]; then
|
||||
|
||||
log "SET OWNER -> $REL"
|
||||
|
||||
# Datei
|
||||
run_cmd chown "$CHOWN_USER:$CHOWN_GROUP" "$DEST1_FILE"
|
||||
run_cmd chown "$CHOWN_USER:$CHOWN_GROUP" "$DEST2_FILE"
|
||||
|
||||
# Ordner nur einmal behandeln
|
||||
DIR1="$(dirname "$DEST1_FILE")"
|
||||
DIR2="$(dirname "$DEST2_FILE")"
|
||||
|
||||
if [[ -z "${CHOWN_DONE_DIRS[$DIR1]}" ]]; then
|
||||
run_cmd chown "$CHOWN_USER:$CHOWN_GROUP" "$DIR1"
|
||||
CHOWN_DONE_DIRS[$DIR1]=1
|
||||
fi
|
||||
|
||||
if [[ -z "${CHOWN_DONE_DIRS[$DIR2]}" ]]; then
|
||||
run_cmd chown "$CHOWN_USER:$CHOWN_GROUP" "$DIR2"
|
||||
CHOWN_DONE_DIRS[$DIR2]=1
|
||||
fi
|
||||
|
||||
log "OK -> delete $REL"
|
||||
run_cmd rm "$FILE"
|
||||
|
||||
else
|
||||
log "ERROR -> $REL (dest1=$STATUS1 dest2=$STATUS2)"
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
# ----------------------------------------
|
||||
# CLEANUP
|
||||
# ----------------------------------------
|
||||
if [ "$DRY_RUN" != true ]; then
|
||||
find "$INCOMING" -mindepth 1 -type d -empty -delete
|
||||
find "$READY" -mindepth 1 -type d -empty -delete 2>/dev/null
|
||||
else
|
||||
log "[DRY-RUN] Skipping cleanup"
|
||||
fi
|
||||
|
||||
log "========================================"
|
||||
log "END RUN"
|
||||
log "========================================"
|
||||
Reference in New Issue
Block a user