200 lines
4.4 KiB
Bash
200 lines
4.4 KiB
Bash
#!/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 "========================================" |