diff --git a/Transcodes/transcode_cleanup.sh b/Transcodes/transcode_cleanup.sh index 659cfc9..4f52dd4 100755 --- a/Transcodes/transcode_cleanup.sh +++ b/Transcodes/transcode_cleanup.sh @@ -172,20 +172,24 @@ fi cleanup_location() { local location="$1" label="$2" max_age="$3" - local files_removed=0 bytes_freed=0 files_skipped=0 files_active=0 files_streaming=0 + local files_removed=0 bytes_freed=0 files_skipped=0 files_active=0 files_streaming=0 files_too_young=0 if [[ ! -d "$location" ]]; then log "$label does not exist — skipping" - LOCATION_REMOVED=0 LOCATION_FREED="0B" LOCATION_SKIPPED=0 LOCATION_ACTIVE=0 LOCATION_STREAMING=0 + LOCATION_REMOVED=0 LOCATION_FREED="0B" LOCATION_SKIPPED=0 LOCATION_ACTIVE=0 LOCATION_STREAMING=0 LOCATION_TOO_YOUNG=0 return fi - local file_count + local file_count eligible_count file_count=$(find "$location" -type f 2>/dev/null | wc -l) - log "$label: $file_count files to scan (age threshold: ${max_age}min)" + eligible_count=$(find "$location" -type f -mmin +"$max_age" 2>/dev/null | wc -l) + files_too_young=$(( file_count - eligible_count )) + log "$label: $file_count files ($eligible_count eligible, $files_too_young < ${max_age}min)" # Build in-memory open file map — O(1) lookup per file # One lsof call per location — never per file + # Note: HLS/remux segments (Live TV, Direct Stream) are written atomically and immediately + # closed — lsof will not detect them. The age check is the effective guard for those files. declare -A OPEN_FILES_MAP if [[ "$LSOF_AVAILABLE" == true ]]; then log "Building open file map for $label..." @@ -245,20 +249,21 @@ cleanup_location() { freed_human="0B" fi - log "$label — removed $files_removed files ($freed_human freed) | streaming: $files_streaming | aged+open: $files_active | skipped: $files_skipped" + log "$label — removed $files_removed ($freed_human) | active(fresh): $files_too_young | streaming(lsof): $files_streaming | protected(old+open): $files_active | skipped: $files_skipped" LOCATION_REMOVED=$files_removed LOCATION_FREED=$freed_human LOCATION_SKIPPED=$files_skipped LOCATION_ACTIVE=$files_active LOCATION_STREAMING=$files_streaming + LOCATION_TOO_YOUNG=$files_too_young } # ============================================================================================== # ━━━ Transcode Cleanup ━━━ # ============================================================================================== START=$(date +%s) -TOTAL_REMOVED=0 TOTAL_SKIPPED=0 TOTAL_ACTIVE=0 TOTAL_STREAMING=0 +TOTAL_REMOVED=0 TOTAL_SKIPPED=0 TOTAL_ACTIVE=0 TOTAL_STREAMING=0 TOTAL_TOO_YOUNG=0 RAMDISK_FREED="0B" SSD_FREED="0B" # Cleanup ramdisk @@ -268,6 +273,7 @@ if mountpoint -q "$RAMDISK_PATH" 2>/dev/null; then TOTAL_SKIPPED=$(( TOTAL_SKIPPED + LOCATION_SKIPPED )) TOTAL_ACTIVE=$(( TOTAL_ACTIVE + LOCATION_ACTIVE )) TOTAL_STREAMING=$(( TOTAL_STREAMING + LOCATION_STREAMING )) + TOTAL_TOO_YOUNG=$(( TOTAL_TOO_YOUNG + LOCATION_TOO_YOUNG )) RAMDISK_FREED=$LOCATION_FREED else log "Ramdisk not mounted — skipping ramdisk cleanup" @@ -280,6 +286,7 @@ if [[ -d "$TRANSCODE_SSD" ]]; then TOTAL_SKIPPED=$(( TOTAL_SKIPPED + LOCATION_SKIPPED )) TOTAL_ACTIVE=$(( TOTAL_ACTIVE + LOCATION_ACTIVE )) TOTAL_STREAMING=$(( TOTAL_STREAMING + LOCATION_STREAMING )) + TOTAL_TOO_YOUNG=$(( TOTAL_TOO_YOUNG + LOCATION_TOO_YOUNG )) SSD_FREED=$LOCATION_FREED else log "SSD fallback not found — skipping SSD cleanup" @@ -308,7 +315,8 @@ echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)" echo "$ICON_RAM Ramdisk freed: $RAMDISK_FREED" echo "$ICON_DISK SSD freed: $SSD_FREED" echo "$ICON_TRASH Removed: $TOTAL_REMOVED files" -echo "$ICON_RUNNING Streaming: $TOTAL_STREAMING files (open by Emby — untouched)" +echo "$ICON_RUNNING Active: $TOTAL_TOO_YOUNG files (< ${TRANSCODE_MAX_AGE}min old — Live TV / Direct Stream segments)" +echo "$ICON_RUNNING Streaming: $TOTAL_STREAMING files (open file handle — long-running transcode)" echo "$ICON_SHIELD Protected: $TOTAL_ACTIVE aged files saved by open-file check" echo "$ICON_TRASH Skipped: $TOTAL_SKIPPED files" echo "$ICON_TIME Duration: $(format_duration $(( END - START )))" diff --git a/Transcodes/transcode_manager.sh b/Transcodes/transcode_manager.sh index 2b067de..c58550e 100755 --- a/Transcodes/transcode_manager.sh +++ b/Transcodes/transcode_manager.sh @@ -501,22 +501,31 @@ for server_entry in "${TRANSCODE_SERVERS[@]}"; do done # Storage state -RAM_SESSION_COUNT=$(find "$RAMDISK_PATH/transcoding-temp" \ - -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l) -SSD_SESSION_COUNT=$(find "$TRANSCODE_SSD/transcoding-temp" \ - -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l) +# Sessions may use subdirectories (legacy transcode) or flat files (Live TV / Direct Stream HLS). +# Count both: subdirs per-session, and unique hex session ID prefixes for flat files. +_count_sessions() { + local base="$1/transcoding-temp" + local _dirs _flat + _dirs=$(find "$base" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l) + _flat=$(find "$base" -maxdepth 1 -type f -printf '%f\n' 2>/dev/null | \ + grep -oE '^[0-9a-f]{16,}' | sort -u | wc -l) + echo $(( _dirs + _flat )) +} +RAM_SESSION_COUNT=$(_count_sessions "$RAMDISK_PATH") +SSD_SESSION_COUNT=$(_count_sessions "$TRANSCODE_SSD") +unset -f _count_sessions if [[ "$TOTAL_SESSIONS" -gt 0 ]]; then echo "" echo " $ICON_EMBY Total: $TOTAL_SESSIONS | Live TV: $LIVE_TV | Transcoding: $TRANSCODING | Direct: $DIRECT" if [[ "$RAM_SESSION_COUNT" -gt 0 && "$SSD_SESSION_COUNT" -gt 0 ]]; then - warn "Split state — $RAM_SESSION_COUNT folder(s) ramdisk / $SSD_SESSION_COUNT SSD" + warn "Split state — $RAM_SESSION_COUNT session(s) ramdisk / $SSD_SESSION_COUNT SSD" warn "Older sessions remain on original location until they end naturally" elif [[ "$RAM_SESSION_COUNT" -gt 0 ]]; then - log "Storage: ramdisk ($RAM_SESSION_COUNT sessions)" + log "Storage: ramdisk ($RAM_SESSION_COUNT session(s))" elif [[ "$SSD_SESSION_COUNT" -gt 0 ]]; then - log "Storage: SSD ($SSD_SESSION_COUNT sessions)" + log "Storage: SSD ($SSD_SESSION_COUNT session(s))" fi fi