Files
Varaverk/Media/Manual-Media.md
T
Gmer4Lfe 8a2707ee37 Correct and extend folder docs for Docker Essentials, Watchdogs, Media and Arrs Stack
The docs had drifted from the scripts — a script that no longer exists, three wrong variable
names, a reversed run order, and seven scheduled scripts that were never documented at all.
2026-08-01 22:59:07 -04:00

8.2 KiB

━━━━━ MEDIA — Manual ━━━━━

Config reference, procedures, operational workflows for Media/ scripts. For overview see README-Media.md. For per-script detail see script headers.

For arr stack config and procedures (cleanup, release fixer, sync, discovery) see Arrs_Stack/Manual-Arrs_Stack.md.


━━━ PERMISSIONS MODEL ━━━

Directories: 755 nobody:users
  Owner (nobody) — rwx   enter, list, create files
  Group (users)  — r-x   enter and list
  Others         — r-x   Samba guests can browse
  No world-write — prevents accidental deletion by unauthenticated access

Files: 664 nobody:users
  Owner (nobody) — rw    read + write
  Group (users)  — rw    arrs can import, rename, delete
  Others         — r     Samba guests can read
  No execute bit — media files are never executable

Two separate passes — not a single recursive chmod. Directories need the execute bit to enter. Files must never have the execute bit. A single chmod -R 664 would break directory entry. The script runs find -type d and find -type f separately.

If this script corrects many files on every run, a container has wrong PUID/PGID. Correct values on unRAID: PUID=99 (nobody) PGID=100 (users). Add to each container's environment in its Docker template. Common culprits: SABnzbd, qBittorrent, slskd. Once fixed, this script corrects 0 files per run — it becomes a pure daily failsafe.


━━━ CONFIGURATION — master.conf ━━━

Permissions

PERMISSIONS_DIR_MODE="755"
PERMISSIONS_FILE_MODE="664"
PERMISSIONS_OWNER="nobody:users"

Media Cleaner — File Patterns

ANIME_FILE_PATTERNS=(
    "*.sfv"             # checksum verification — useless after download verified
    "*.md5" "*.sha1"    # other checksum formats
    "*.nfo"             # scene info file — not library metadata
    "*.url" "*.lnk"     # website shortcuts
    "*.rar" "*.zip"     # source archives kept by some clients after extraction
    "*.info"            # tool output files
    "*.torrent"         # torrent descriptor left by some clients
    "*.sample*"         # scene preview clip
    "*.proof*"          # screenshot proving encode quality
    "*sync-conflict*"   # Syncthing conflict copies
    "*.scr" "*.exe"     # executables — should never be in a media folder
    "*.srr"             # scene recovery record
    "*.log"             # tool/client logs
    "*.json"            # metadata or tool output
)

MEDIA_FILE_PATTERNS=(
    "${ANIME_FILE_PATTERNS[@]}"   # all anime patterns plus:
    "*.iso"                       # disc images after ripping
    "*.lrc"                       # lyric files in media folders
)

DO NOT add patterns that match media you want to keep: *.mkv *.mp4 *.avi *.m4v — video files *.flac *.mp3 *.m4a — audio files *.srt *.sub *.ass — subtitle files (Bazarr managed) *.jpg *.png — artwork Always use --dry-run when adding new patterns.


Play State Sync

PLAY_SYNC_ENABLED=true                # toggle entire sync
PLAY_SYNC_REMOTE=true                 # sync across hosts via Tailscale
                                      # false = local servers only (this host's Emby + Jellyfin)
PLAY_SYNC_TYPES="Movie,Episode"       # item types to sync — Audio excluded, music library too large
PLAY_SYNC_FAV_TYPES="MusicArtist,MusicAlbum,Movie,Series"   # favourites, union sync, never unmarks

PLAY_SYNC_PROBE=true                  # skip per-item work when nothing changed since last run
PLAY_SYNC_PROBE_MAX_AGE_HOURS=24      # force a full comparison when the fingerprint is older

PLAY_SYNC_HANDBACK_RETRIES=5          # fallback handback: attempts before DNS cutover proceeds
PLAY_SYNC_HANDBACK_RETRY_DELAY=60     # seconds between those attempts

There is no date/lookback filter, and one must not be re-added. An earlier version gated on played-date; it was removed once the real cost was measured — the 30-minute runtime was fork overhead per item, not API volume or item count. The fix was jq epoch parsing plus the response-hash probe below. Re-introducing a date window would reduce correctness (older items silently stop syncing) without meaningfully reducing runtime.

Emby and Jellyfin servers configured per-host:

# host*.conf
HOST1_EMBY_URL="http://192.168.50.2:8096"
HOST1_EMBY_API_KEY="..."
HOST1_JELLYFIN_URL=""   # empty = skip Jellyfin on this host
HOST1_JELLYFIN_API_KEY=""

━━━ CONFIGURATION — host*.conf ━━━

# Shares this server applies permissions to
HOST1_MEDIA_PERMISSION_SHARES=(
    "/mnt/user/Movies"
    "/mnt/user/Tv_Shows"
    "/mnt/user/Music"
    "/mnt/user/Kids_Movies"
    "/mnt/user/Kids_Tv_Shows"
    "/mnt/user/Sports"
    "/mnt/user/stand-up_comedy"
)

# Folders cleaned by each profile
HOST1_ANIME_CLEAN_FOLDERS=(
    "/mnt/user/Anime_Movies"
    "/mnt/user/Anime_Movies-Old"
    "/mnt/user/Anime_Shows"
    "/mnt/user/Anime_Shows-Old"
)
HOST1_MEDIA_CLEAN_FOLDERS=(
    "/mnt/user/Kids_Movies"
    "/mnt/user/Kids_Tv_Shows"
    "/mnt/user/Movies"
    "/mnt/user/Music"
    "/mnt/user/Sports"
    "/mnt/user/stand-up_comedy"
    "/mnt/user/Tv_Shows"
)

━━━ OUTPUT TIERS ━━━

All scripts have two output levels controlled by --log.

Without --log, each script processes silently and concludes with a summary block. Warnings and errors are always visible.

With --log, per-item detail appears — individual shares being processed, file counts, per-server sync results.


━━━ FLAG REFERENCE ━━━

media_shares_permissions.sh

media_shares_permissions.sh Apply correct ownership and permissions to all configured media shares. Safe to run manually at any time — idempotent, only changes what's wrong.

media_shares_permissions.sh --dry-run Show how many files and directories would be corrected per share. If unexpectedly large, check container PUID/PGID settings first (PUID=99 PGID=100).

media_shares_permissions.sh --status Show configured share list and ownership of the share roots.

media_shares_permissions.sh --log Show ownership correction count per share and per file (verbose).

On large libraries this runs 20-30 minutes. This is expected — millions of files with recursive walk takes time. Designed to run overnight in the maintenance window.


media_cleaner.sh

media_cleaner.sh anime Remove junk files from anime share folders using ANIME_FILE_PATTERNS.

media_cleaner.sh media Remove junk files from media share folders using MEDIA_FILE_PATTERNS.

media_cleaner.sh [profile] --dry-run Show what would be deleted without removing anything. Always run first when adding new patterns or folders.

media_cleaner.sh [profile] --status Show folder list and file patterns for the profile.

media_cleaner.sh [profile] --log Show every file examined, not just those removed.


play_state_sync.sh

play_state_sync.sh Sync played/unplayed state, resume positions and favourites across every configured Emby and Jellyfin server — not just local→remote. Servers are discovered from every HOST*_TRANSCODE_SERVERS entry, with remote hosts' localhost URLs rewritten to their Tailscale IP. Newest LastPlayedDate wins; state only ever moves forward, never clears.

No age filter — every matched item is considered on every run. The change probe is what keeps that cheap: the raw API responses are hashed and compared against the fingerprint from the last successful run, and per-item processing is skipped entirely when nothing moved. Fetches still happen every run, so nothing can be missed by the probe.

play_state_sync.sh --full Bypass the change probe and force the full per-item comparison even when the fingerprint matches. Use after a new Emby install or database restore, or when debugging a sync that appears to be skipping work it should be doing.

play_state_sync.sh --wait Wait for an in-progress run instead of exiting. For manual runs that would otherwise be skipped by the scheduled every-30-minute pass. Used by fallback.sh during handback.

play_state_sync.sh --dry-run Show what would be synced without writing any state.

play_state_sync.sh --status Show configured servers, reachability, and user counts.

play_state_sync.sh --log Verbose output — show each item comparison.