transcode manager now handles multiple media servers
This commit is contained in:
+52
-7
@@ -444,11 +444,11 @@ HOST2_DDNS_CONTAINERS=(
|
||||
# Own DDNS handled separately above — list additional containers here if needed
|
||||
# These stop when this server loses internet — regardless of remote state
|
||||
FAILOVER_HOST1_STOP_ON_NO_NET=(
|
||||
"Gmer4Lfe.com" # add containers that should stop without internet
|
||||
# "container-name" # add containers that should stop without internet
|
||||
)
|
||||
|
||||
FAILOVER_HOST2_STOP_ON_NO_NET=(
|
||||
"Gmer4Lfe.us"
|
||||
# "container-name"
|
||||
)
|
||||
|
||||
# ━━━ HOST1 runs these for HOST2 when HOST2 goes down ━━━
|
||||
@@ -498,8 +498,7 @@ FAILOVER_HOST2_RUNS_FOR_HOST1_IMMEDIATE=(
|
||||
"Dispatcharr" # Live TV — people are watching, cannot wait
|
||||
"Dispatcharr-Basic" # Live TV basic profile
|
||||
"Dispatcharr-Iptv-Users" # Live TV IPTV users
|
||||
"ErsatzTV-Emby"
|
||||
# "container-placeholder" # Live TV scheduling and channel management
|
||||
"ErsatzTV-Emby" # Live TV scheduling and channel management
|
||||
)
|
||||
|
||||
# Tier 2 — starts after HOST1_TIER2_DELAY minutes
|
||||
@@ -1044,10 +1043,56 @@ RADARR_PROTECTED_PATTERNS=("*.jpg" "*.jpeg" "*.png" "*.nfo" "*.srt" "*.sub" "*.a
|
||||
# switch to this mode to drain ramdisk sessions gracefully
|
||||
TRANSCODE_MANAGER_MODE="smart" # smart | ramdisk | ssd
|
||||
|
||||
# Emby container check — skips threshold checks when Emby is not running
|
||||
# Prevents unnecessary symlink flips when no transcoding is happening
|
||||
# ━━━ Transcode Server Array ━━━
|
||||
# All media servers that share the ramdisk transcode space.
|
||||
# transcode_manager.sh reads this array and queries each server's API for active sessions.
|
||||
# Session display, storage detection, and threshold decisions cover ALL servers combined.
|
||||
#
|
||||
# One entry → works exactly as before — single server behavior
|
||||
# Many entries → aggregates sessions from all servers, one threshold on total ramdisk usage
|
||||
#
|
||||
# Each server writes to its own subfolder inside transcoding-temp:
|
||||
# /mnt/ram-transcode/transcoding-temp/ABC123/ ← Emby session
|
||||
# /mnt/ram-transcode/transcoding-temp/XYZ789/ ← Jellyfin session
|
||||
# They never touch each other's files — the ramdisk is shared scratch space.
|
||||
#
|
||||
# Docker Extra Parameters — each media server container that uses the ramdisk needs:
|
||||
# --mount type=bind,source=/mnt/ram-transcode,target=/ext-ram-transcode,bind-propagation=shared
|
||||
# The target path (/ext-ram-transcode) must match what's configured in each server's
|
||||
# transcoding settings. Use a different target path per container if needed.
|
||||
#
|
||||
# Format: "ContainerName|URL|APIKey|Type"
|
||||
# ContainerName — exact Docker container name (used for running check)
|
||||
# URL — API base URL including port
|
||||
# APIKey — server API key (Emby/Jellyfin token, Plex token etc.)
|
||||
# Type — emby | jellyfin | plex (controls API endpoint format)
|
||||
#
|
||||
# The first entry is the primary server — used for container running check
|
||||
# (TRANSCODE_CHECK_EMBY still applies to first entry).
|
||||
# Additional entries are queried if their container is running.
|
||||
# Entries with placeholder APIKey values are skipped automatically.
|
||||
#
|
||||
# ⚠️ Tdarr does NOT belong here — Tdarr encodes full files, not HLS segments.
|
||||
# Large working files would fill the ramdisk rapidly and cause constant flips.
|
||||
# Keep Tdarr on SSD. Use tdarr_cleanup.sh for Tdarr orphan management.
|
||||
|
||||
TRANSCODE_SERVERS=(
|
||||
"Emby|http://localhost:8096|0c27448d93a7431f9ac63569f7655829|emby"
|
||||
# "Emby-Jayred365|http://HOST2-TAILSCALE-IP:8096|his-api-key|emby" # his Emby temporarily
|
||||
# "Jellyfin|http://localhost:8097|jellyfin-api-key|jellyfin" # test Jellyfin instance
|
||||
# "Plex|http://localhost:32400|plex-token|plex" # Plex if needed
|
||||
)
|
||||
|
||||
# Container running check — still applies — skips threshold checks when no servers active
|
||||
# Checked against the first entry in TRANSCODE_SERVERS automatically
|
||||
TRANSCODE_CHECK_EMBY=true
|
||||
TRANSCODE_EMBY_CONTAINER="Emby" # exact Docker container name — case sensitive
|
||||
|
||||
# Per-host Emby container names for database repair
|
||||
# HOST1 repairs its own personal Emby + the shared production Emby
|
||||
# HOST2 repairs its own personal Emby
|
||||
# detect_hosts() selects the correct container at runtime
|
||||
HOST1_EMBY_REPAIR_CONTAINER="Emby" # shared production Emby lives on HOST1
|
||||
HOST2_EMBY_REPAIR_CONTAINER="Emby-Jayred365" # HOST2's personal Emby instance
|
||||
|
||||
# Daily transcode statistics log — read by weekly_health_digest.sh
|
||||
# Tracks peak usage, flip count, session ratio, files cleaned per day
|
||||
|
||||
@@ -22,7 +22,10 @@
|
||||
# authentication.db — API keys and sessions
|
||||
# activity.db — activity log
|
||||
#
|
||||
# All configuration in Master.conf — uses TRANSCODE_EMBY_CONTAINER and EMBY_URL.
|
||||
# HOST1 repairs the shared production Emby (HOST1_EMBY_REPAIR_CONTAINER).
|
||||
# HOST2 repairs its own personal Emby (HOST2_EMBY_REPAIR_CONTAINER).
|
||||
# detect_hosts() selects the correct container at runtime.
|
||||
# Config path is detected from Docker inspect — no hardcoded paths needed.
|
||||
# Supports --dry-run to show what would be checked without stopping Emby.
|
||||
# -----------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -33,10 +36,6 @@ source "$SCRIPT_DIR/../common.sh"
|
||||
|
||||
parse_args "$@"
|
||||
|
||||
# Emby config path — inside the container it's /config, map to host path
|
||||
# Detected from Docker inspect at runtime
|
||||
EMBY_CONTAINER="$TRANSCODE_EMBY_CONTAINER"
|
||||
|
||||
# -----------------------------------------------------------------------------------------------
|
||||
# ━━━ $ICON_GEAR Setup ━━━
|
||||
# -----------------------------------------------------------------------------------------------
|
||||
@@ -52,6 +51,17 @@ success "Running as root"
|
||||
|
||||
acquire_lock
|
||||
|
||||
# Select correct Emby container based on which server is running this script
|
||||
detect_hosts
|
||||
|
||||
if [[ "$LOCAL_SERVER_NAME" == "$HOST1" ]]; then
|
||||
EMBY_CONTAINER="$HOST1_EMBY_REPAIR_CONTAINER"
|
||||
else
|
||||
EMBY_CONTAINER="$HOST2_EMBY_REPAIR_CONTAINER"
|
||||
fi
|
||||
|
||||
info "Emby container: $LOCAL_SERVER_NAME → $EMBY_CONTAINER"
|
||||
|
||||
if ! command -v sqlite3 >/dev/null 2>&1; then
|
||||
error "sqlite3 not found — install sqlite package"
|
||||
exit 1
|
||||
|
||||
@@ -223,13 +223,58 @@ TRANSCODE_CHMOD="755"
|
||||
|
||||
TRANSCODE_MANAGER_MODE="smart" # smart | ramdisk | ssd
|
||||
|
||||
TRANSCODE_CHECK_EMBY=true
|
||||
TRANSCODE_EMBY_CONTAINER="Emby"
|
||||
TRANSCODE_CHECK_EMBY=true # skips threshold checks when no servers active
|
||||
|
||||
TRANSCODE_DAILY_LOG="/boot/config/transcode_daily.db"
|
||||
TRANSCODE_LOG_RETENTION=90
|
||||
```
|
||||
|
||||
### Multi-Server Configuration — `TRANSCODE_SERVERS`
|
||||
|
||||
The transcode manager supports any number of media servers sharing the same ramdisk scratch space. One server or ten — the same script handles it. The threshold decision is based on total ramdisk usage across all servers combined.
|
||||
|
||||
```bash
|
||||
TRANSCODE_SERVERS=(
|
||||
"Emby|http://localhost:8096|your-api-key|emby"
|
||||
# "Emby-Jayred365|http://HOST2-IP:8096|his-api-key|emby" # temporarily cover his Emby
|
||||
# "Jellyfin|http://localhost:8097|jellyfin-api-key|jellyfin" # test Jellyfin instance
|
||||
# "Plex|http://localhost:32400|plex-token|plex" # Plex if needed
|
||||
)
|
||||
```
|
||||
|
||||
**Format:** `"ContainerName|URL|APIKey|Type"`
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `ContainerName` | Exact Docker container name — used for running check |
|
||||
| `URL` | API base URL including port |
|
||||
| `APIKey` | Server API key or token |
|
||||
| `Type` | `emby` \| `jellyfin` \| `plex` — controls API endpoint format |
|
||||
|
||||
**How it works with multiple servers:**
|
||||
|
||||
Each media server writes its transcode sessions to its own subfolder inside `transcoding-temp`:
|
||||
|
||||
```
|
||||
/mnt/ram-transcode/transcoding-temp/
|
||||
E0D8DC/ ← Emby session (Live TV segment files)
|
||||
abc123/ ← Jellyfin session
|
||||
xyz789/ ← his Emby session
|
||||
```
|
||||
|
||||
They never touch each other's files. The ramdisk is shared scratch space — each server is unaware of the others. The manager aggregates session counts from all servers and makes one threshold decision based on total ramdisk usage.
|
||||
|
||||
**Each server container needs the shared propagation mount in Extra Parameters:**
|
||||
```
|
||||
--mount type=bind,source=/mnt/ram-transcode,target=/ext-ram-transcode,bind-propagation=shared
|
||||
```
|
||||
|
||||
Set the transcode path in each server's settings to `/ext-ram-transcode` (or whatever target path you use).
|
||||
|
||||
**Entries with placeholder API key values are skipped automatically** — comment out entries that aren't in use rather than removing them. The placeholders make it clear what's available to enable.
|
||||
|
||||
**⚠️ Tdarr does NOT belong in this array.** Tdarr encodes full files — large working files would fill the ramdisk rapidly and cause constant flips. Keep Tdarr on SSD. A dedicated `tdarr_cleanup.sh` handles Tdarr orphan management separately.
|
||||
|
||||
### Sizing the Ramdisk
|
||||
|
||||
`tmpfs` only uses RAM actually needed — `RAMDISK_SIZE` is a ceiling, not a reservation.
|
||||
|
||||
+102
-50
@@ -49,15 +49,11 @@ success "Running as root"
|
||||
|
||||
acquire_lock "wait"
|
||||
|
||||
# Select correct Emby instance for session display
|
||||
detect_hosts
|
||||
|
||||
if [[ "$LOCAL_SERVER_NAME" == "$HOST1" ]]; then
|
||||
EMBY_URL="${HOST1_EMBY_URL}"
|
||||
EMBY_API_KEY="${HOST1_EMBY_API_KEY}"
|
||||
else
|
||||
EMBY_URL="${HOST2_EMBY_URL}"
|
||||
EMBY_API_KEY="${HOST2_EMBY_API_KEY}"
|
||||
# Primary server for container running check — first entry in TRANSCODE_SERVERS
|
||||
# Full session display loops over all entries in the array
|
||||
if [[ "${#TRANSCODE_SERVERS[@]}" -gt 0 ]]; then
|
||||
IFS='|' read -r PRIMARY_CONTAINER _ _ _ <<< "${TRANSCODE_SERVERS[0]}"
|
||||
TRANSCODE_EMBY_CONTAINER="${PRIMARY_CONTAINER:-Emby}"
|
||||
fi
|
||||
|
||||
case "$TRANSCODE_MANAGER_MODE" in
|
||||
@@ -335,42 +331,116 @@ FLIP_COUNT=$(get_flip_count)
|
||||
echo ""
|
||||
echo "━━━ $ICON_EMBY Active Emby Sessions ━━━"
|
||||
|
||||
# -----------------------------------------------------------------------------------------------
|
||||
# ━━━ $ICON_EMBY Active Transcode Sessions ━━━
|
||||
# Queries all configured servers in TRANSCODE_SERVERS array
|
||||
# Aggregates sessions, counts, and storage state across all servers
|
||||
# -----------------------------------------------------------------------------------------------
|
||||
echo ""
|
||||
echo "━━━ $ICON_EMBY Active Transcode Sessions ━━━"
|
||||
|
||||
TOTAL_SESSIONS=0
|
||||
LIVE_TV=0
|
||||
TRANSCODING=0
|
||||
DIRECT=0
|
||||
ANY_SERVER_RUNNING=false
|
||||
|
||||
if [[ -z "$EMBY_API_KEY" ]]; then
|
||||
info "EMBY_API_KEY not set in Master.conf — skipping session display"
|
||||
elif [[ "$EMBY_RUNNING" == false ]]; then
|
||||
info "Emby not running — no sessions"
|
||||
else
|
||||
SESSION_DATA=$(emby_api "Sessions" 2>/dev/null)
|
||||
for server_entry in "${TRANSCODE_SERVERS[@]}"; do
|
||||
# Parse entry — ContainerName|URL|APIKey|Type
|
||||
IFS='|' read -r SRV_CONTAINER SRV_URL SRV_KEY SRV_TYPE <<< "$server_entry"
|
||||
|
||||
# Skip placeholder entries
|
||||
if [[ "$SRV_KEY" == *"api-key"* ]] || [[ "$SRV_KEY" == *"token"* && ${#SRV_KEY} -lt 20 ]]; then
|
||||
log "Skipping $SRV_CONTAINER — placeholder API key"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if container is running
|
||||
if ! docker inspect "$SRV_CONTAINER" --format '{{.State.Running}}' 2>/dev/null | grep -q "true"; then
|
||||
info "$ICON_CONTAINERS $SRV_CONTAINER — not running, skipping"
|
||||
continue
|
||||
fi
|
||||
|
||||
ANY_SERVER_RUNNING=true
|
||||
|
||||
# Check API reachability
|
||||
if ! check_api "$SRV_URL" "$SRV_CONTAINER" 5; then
|
||||
warn "$SRV_CONTAINER — API unreachable, skipping (container up but API not responding)"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Query sessions based on server type
|
||||
case "$SRV_TYPE" in
|
||||
emby|jellyfin)
|
||||
SESSION_DATA=$(curl -sf --max-time 10 \
|
||||
-H "X-Emby-Token: $SRV_KEY" \
|
||||
"${SRV_URL}/Sessions" 2>/dev/null)
|
||||
;;
|
||||
plex)
|
||||
SESSION_DATA=$(curl -sf --max-time 10 \
|
||||
-H "X-Plex-Token: $SRV_KEY" \
|
||||
"${SRV_URL}/status/sessions" 2>/dev/null)
|
||||
;;
|
||||
*)
|
||||
warn "Unknown server type '$SRV_TYPE' for $SRV_CONTAINER — skipping"
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ -z "$SESSION_DATA" ]] || ! command -v jq >/dev/null 2>&1; then
|
||||
warn "Could not retrieve session data — check EMBY_URL and EMBY_API_KEY"
|
||||
else
|
||||
# Count sessions
|
||||
TOTAL_SESSIONS=$(echo "$SESSION_DATA" | \
|
||||
warn "Could not retrieve session data from $SRV_CONTAINER"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Count sessions (Emby/Jellyfin format)
|
||||
if [[ "$SRV_TYPE" == "emby" || "$SRV_TYPE" == "jellyfin" ]]; then
|
||||
SRV_TOTAL=$(echo "$SESSION_DATA" | \
|
||||
jq '[.[] | select(.NowPlayingItem != null)] | length' 2>/dev/null || echo 0)
|
||||
LIVE_TV=$(echo "$SESSION_DATA" | \
|
||||
SRV_LIVE=$(echo "$SESSION_DATA" | \
|
||||
jq '[.[] | select(.NowPlayingItem != null) | select(.NowPlayingItem.Type == "LiveTv" or .NowPlayingItem.Type == "TvChannel")] | length' \
|
||||
2>/dev/null || echo 0)
|
||||
TRANSCODING=$(echo "$SESSION_DATA" | \
|
||||
SRV_TRANSCODE=$(echo "$SESSION_DATA" | \
|
||||
jq '[.[] | select(.NowPlayingItem != null) | select(.PlayState.PlayMethod == "Transcode")] | length' \
|
||||
2>/dev/null || echo 0)
|
||||
DIRECT=$(echo "$SESSION_DATA" | \
|
||||
SRV_DIRECT=$(echo "$SESSION_DATA" | \
|
||||
jq '[.[] | select(.NowPlayingItem != null) | select(.PlayState.PlayMethod != "Transcode")] | length' \
|
||||
2>/dev/null || echo 0)
|
||||
|
||||
echo " $ICON_EMBY Total: $TOTAL_SESSIONS | $ICON_RAM Live TV: $LIVE_TV | $ICON_SYNC Transcoding: $TRANSCODING | $ICON_DONE Direct: $DIRECT"
|
||||
TOTAL_SESSIONS=$(( TOTAL_SESSIONS + SRV_TOTAL ))
|
||||
LIVE_TV=$(( LIVE_TV + SRV_LIVE ))
|
||||
TRANSCODING=$(( TRANSCODING + SRV_TRANSCODE ))
|
||||
DIRECT=$(( DIRECT + SRV_DIRECT ))
|
||||
|
||||
# Display server header if more than one server configured and running
|
||||
if [[ "${#TRANSCODE_SERVERS[@]}" -gt 1 ]]; then
|
||||
echo " $ICON_EMBY $SRV_CONTAINER — $SRV_TOTAL streams"
|
||||
fi
|
||||
|
||||
# List each active session
|
||||
if [[ "$SRV_TOTAL" -gt 0 ]]; then
|
||||
while IFS= read -r session; do
|
||||
USER=$(echo "$session" | jq -r '.UserName // "Unknown"' 2>/dev/null)
|
||||
TITLE=$(echo "$session" | jq -r '.NowPlayingItem.Name // "Unknown"' 2>/dev/null)
|
||||
MEDIA_TYPE=$(echo "$session" | jq -r '.NowPlayingItem.Type // "Unknown"' 2>/dev/null)
|
||||
PLAY_METHOD=$(echo "$session" | jq -r '.PlayState.PlayMethod // "Unknown"' 2>/dev/null)
|
||||
|
||||
MEDIA_LABEL=$(get_media_type_label "$MEDIA_TYPE")
|
||||
METHOD_LABEL=$(get_play_method_label "$PLAY_METHOD")
|
||||
|
||||
echo " $ICON_EMBY $(printf '%-12s' "$USER") — $(printf '%-30s' "$TITLE") — $(printf '%-10s' "$MEDIA_LABEL") — $METHOD_LABEL"
|
||||
done < <(echo "$SESSION_DATA" | \
|
||||
jq -c '.[] | select(.NowPlayingItem != null)' 2>/dev/null)
|
||||
fi
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
# Totals header — shown after all servers
|
||||
echo ""
|
||||
echo " $ICON_EMBY Total: $TOTAL_SESSIONS | $ICON_RAM Live TV: $LIVE_TV | $ICON_SYNC Transcoding: $TRANSCODING | $ICON_DONE Direct: $DIRECT"
|
||||
|
||||
# Storage state — based on total ramdisk/SSD session folders
|
||||
if [[ "$TOTAL_SESSIONS" -gt 0 ]]; then
|
||||
|
||||
# Storage state — count session folders on each location
|
||||
# Emby folder names don't match API session IDs — per-session location not possible
|
||||
# Split state shows when symlink has flipped mid-session
|
||||
TRANSCODE_TEMP="transcoding-temp"
|
||||
RAM_SESSION_COUNT=$(find "$RAMDISK_PATH/$TRANSCODE_TEMP" \
|
||||
-mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l)
|
||||
@@ -385,30 +455,12 @@ else
|
||||
echo " $ICON_LINK Storage: $ICON_RAM ramdisk"
|
||||
elif [[ "$SSD_SESSION_COUNT" -gt 0 ]]; then
|
||||
echo " $ICON_LINK Storage: $ICON_DISK SSD"
|
||||
else
|
||||
echo " $ICON_LINK Storage: $ICON_INFO no transcode folders found"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# List each active session
|
||||
while IFS= read -r session; do
|
||||
USER=$(echo "$session" | jq -r '.UserName // "Unknown"' 2>/dev/null)
|
||||
TITLE=$(echo "$session" | jq -r '.NowPlayingItem.Name // "Unknown"' 2>/dev/null)
|
||||
MEDIA_TYPE=$(echo "$session" | jq -r '.NowPlayingItem.Type // "Unknown"' 2>/dev/null)
|
||||
PLAY_METHOD=$(echo "$session" | jq -r '.PlayState.PlayMethod // "Unknown"' 2>/dev/null)
|
||||
|
||||
MEDIA_LABEL=$(get_media_type_label "$MEDIA_TYPE")
|
||||
METHOD_LABEL=$(get_play_method_label "$PLAY_METHOD")
|
||||
|
||||
echo " $ICON_EMBY $(printf '%-12s' "$USER") — $(printf '%-30s' "$TITLE") — $(printf '%-10s' "$MEDIA_LABEL") — $METHOD_LABEL"
|
||||
|
||||
done < <(echo "$SESSION_DATA" | \
|
||||
jq -c '.[] | select(.NowPlayingItem != null)' 2>/dev/null)
|
||||
else
|
||||
info "No active streams"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$ANY_SERVER_RUNNING" == false && "$TRANSCODE_CHECK_EMBY" == true ]]; then
|
||||
info "No configured media servers are running — skipping threshold checks"
|
||||
EMBY_RUNNING=false
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------------------------
|
||||
@@ -455,7 +507,7 @@ case "$TRANSCODE_MANAGER_MODE" in
|
||||
info "$ICON_GEAR Mode: SMART — auto threshold management"
|
||||
|
||||
if [[ "$EMBY_RUNNING" == false ]]; then
|
||||
info "Emby not running — skipping threshold checks"
|
||||
info "No media servers running — skipping threshold checks"
|
||||
|
||||
elif [[ "$RAMDISK_HEALTHY" == false ]]; then
|
||||
info "Ramdisk unavailable — staying on SSD until ramdisk recovers"
|
||||
|
||||
@@ -21,12 +21,45 @@
|
||||
# v1.5 — Full icon set expanded — each operation and state has its own distinct icon
|
||||
# All function output updated to use correct icon per context
|
||||
# Icons grouped and commented by category for clarity
|
||||
# v1.6 — ICON_CONTAINERS added — 📦 anchors all container sections for visual consistency
|
||||
# ICON_NOT_RUNNING changed to ⭕ — distinct from ICON_STOPPED 🔴
|
||||
# Section dividers updated from --- to ━━━ for cleaner log readability
|
||||
# Summary passed/failed lines use ICON_SUCCESS and ICON_ERROR consistently
|
||||
# v1.7 — ICON_MOVER added for mover operations
|
||||
# ICON_CONTAINERS replaces ICON_DOCKER for docker/container operations
|
||||
# validate_int added — reusable integer validation for any script
|
||||
# v1.8 — ICON_PHP added for PHP-FPM operations
|
||||
# v1.9 — ICON_REBOOT added for server reboot operations
|
||||
# v2.0 — ICON_PLUGIN added for User Scripts plugin operations
|
||||
# v2.1 — ICON_ZFS and ICON_MEM added for ZFS and memory diagnostics
|
||||
# Diagnostics icon group added to icon block
|
||||
# v2.2 — ICON_WATCHDOG added for Docker watchdog monitoring operations
|
||||
# v2.3 — ICON_NOTIFY added for notification operations
|
||||
# notify() added — shared notification function supporting unRAID native and Discord
|
||||
# NOTIFY_UNRAID and DISCORD_WEBHOOK configured in Master.conf
|
||||
# v2.4 — ICON_CLEAN, ICON_TRASH added for media cleaner operations
|
||||
# ICON_PERMS, ICON_UNLOCKED added for media permissions operations
|
||||
# ICON_REBOOT_SMART added for smart conditional reboot
|
||||
# v2.5 — ICON_RAM added for ramdisk operations
|
||||
# ICON_LINK added for symlink state and management
|
||||
# Transcode scripts group added to ecosystem
|
||||
# v2.6 — ICON_FAILOVER added for failover operations
|
||||
# check_local_array added — verifies local /mnt/user is mounted and healthy
|
||||
# check_remote_array added — verifies remote /mnt/user is mounted and healthy
|
||||
# check_remote_docker added — verifies remote Docker daemon is responding
|
||||
# ping_remote added — non-fatal ping returning status for failover use
|
||||
# ping_internet added — non-fatal external ping for failover use
|
||||
# v2.7 — ICON_WEBGUI added for WebGUI watchdog operations
|
||||
# ICON_DOCKER_NET added for Docker network connect operations
|
||||
# v2.8 — ICON_CERT added for SSL certificate monitoring operations
|
||||
# v2.9 — ICON_MONITOR added for monitoring section headers
|
||||
# v3.0 — Script locking system added — prevents concurrent execution conflicts
|
||||
# acquire_lock() — create PID lock file, register EXIT trap
|
||||
# release_lock() — remove lock file on exit
|
||||
# acquire_rsync_lock() — per-profile lock + global concurrent limit
|
||||
# release_rsync_lock() — decrement global counter, remove profile lock
|
||||
# check_api() — pre-flight API reachability check
|
||||
# ICON_LOCK added — 🔏 script instance lock acquired/released
|
||||
# ICON_SMART added for drive SMART health operations
|
||||
# ICON_BANDWIDTH added for bandwidth tracking operations
|
||||
# ICON_DIGEST added for health digest operations
|
||||
@@ -89,6 +122,7 @@ ICON_CLEAN="🧹" # media cleaner operations
|
||||
ICON_TRASH="🗑️" # files being deleted
|
||||
ICON_PERMS="🔐" # permissions operation / section header
|
||||
ICON_UNLOCKED="🔓" # permissions successfully applied to a share
|
||||
ICON_LOCK="🔏" # script instance lock — acquired/released
|
||||
|
||||
# Transcode Operations
|
||||
ICON_RAM="💨" # ramdisk operations — fast ephemeral storage
|
||||
@@ -660,7 +694,7 @@ acquire_lock() {
|
||||
# Register EXIT trap to always release lock
|
||||
trap "_release_on_exit '$lockfile'" EXIT
|
||||
|
||||
log "Lock acquired: $script_name (PID $$)"
|
||||
log "$ICON_LOCK Lock acquired: $script_name (PID $$)"
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------------------------
|
||||
@@ -719,7 +753,7 @@ acquire_rsync_lock() {
|
||||
# Register EXIT trap
|
||||
trap "_release_rsync_on_exit '$profile_lock'" EXIT
|
||||
|
||||
log "rsync lock acquired: profile '$profile' (PID $$, active: $(( current_count + 1 ))/$RSYNC_MAX_CONCURRENT)"
|
||||
log "$ICON_LOCK rsync lock acquired: profile '$profile' (PID $$, active: $(( current_count + 1 ))/$RSYNC_MAX_CONCURRENT)"
|
||||
}
|
||||
|
||||
# Internal — release rsync lock on exit
|
||||
|
||||
Reference in New Issue
Block a user