{"type":"mode","mode":"normal","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac"} {"type":"permission-mode","permissionMode":"default","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac"} {"type":"file-history-snapshot","messageId":"761c25f9-7ee8-46e5-b2d0-cea0531bf3ca","snapshot":{"messageId":"761c25f9-7ee8-46e5-b2d0-cea0531bf3ca","trackedFileBackups":{},"timestamp":"2026-06-11T22:00:00.634Z"},"isSnapshotUpdate":false} {"parentUuid":null,"isSidechain":false,"promptId":"1523688a-a842-492d-bb41-f7ece7e3b28c","type":"user","message":{"role":"user","content":"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n━━━ 🔄 Play State Sync — 2026-06-11 17:37:58 ━━━\n⚠️ [WARN] Emby-Jayred365 (unRAID-Jayred365) — unreachable, skipping\n⚠️ [WARN] Jellyfin (unRAID-Jayred365) — unreachable, skipping\n\n── User: gmer4lfe (2 server(s)) ──\n⚠️ [WARN] ✗ tvdb:ep:5618559:s7e2 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n🏁 [OK] ✓ tvdb:ep:167594:s5e4 → Jellyfin (unRAID-Gmer4Lfe) marked played\n⚠️ [WARN] ✗ tvdb:ep:11818886:s18e1 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n⚠️ [WARN] ✗ tvdb:ep:11759792:s9e2 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n⚠️ [WARN] ✗ tvdb:ep:11766619:s10e12 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n⚠️ [WARN] ✗ imdb:tt8750122 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n🏁 [OK] ✓ tvdb:ep:3279811:s1e2 → Emby (unRAID-Gmer4Lfe) resume synced (370s)\n⚠️ [WARN] ✗ tvdb:ep:11493564:s8e11 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n⚠️ [WARN] ✗ tvdb:ep:11426444:s1e3 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n⚠️ [WARN] ✗ tvdb:ep:10355686:s9e6 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n⚠️ [WARN] ✗ tvdb:ep:10355684:s9e7 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n⚠️ [WARN] ✗ imdb:tt0437863 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n🏁 [OK] ✓ tvdb:ep:7547570:s1e1 → Jellyfin (unRAID-Gmer4Lfe) marked played\n⚠️ [WARN] ✗ tvdb:ep:1555111:s1e1 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n⚠️ [WARN] ✗ tvdb:ep:5553405:s4e13 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n⚠️ [WARN] ✗ tvdb:ep:893201:s1e5 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n⚠️ [WARN] ✗ tvdb:ep:2861921:s1e1 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n⚠️ [WARN] ✗ tvdb:ep:11759791:s9e1 → Emby (unRAID-Gmer4Lfe) failed (HTTP 500)\n"},"uuid":"761c25f9-7ee8-46e5-b2d0-cea0531bf3ca","timestamp":"2026-06-11T22:00:00.634Z","permissionMode":"default","promptSource":"typed","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"761c25f9-7ee8-46e5-b2d0-cea0531bf3ca","isSidechain":false,"attachment":{"type":"deferred_tools_delta","addedNames":["CronCreate","CronDelete","CronList","DesignSync","EnterPlanMode","EnterWorktree","ExitPlanMode","ExitWorktree","Monitor","NotebookEdit","PushNotification","RemoteTrigger","TaskCreate","TaskGet","TaskList","TaskOutput","TaskStop","TaskUpdate","WebFetch","WebSearch","mcp__claude_ai_Google_Drive__authenticate","mcp__claude_ai_Google_Drive__complete_authentication"],"addedLines":["CronCreate","CronDelete","CronList","DesignSync","EnterPlanMode","EnterWorktree","ExitPlanMode","ExitWorktree","Monitor","NotebookEdit","PushNotification","RemoteTrigger","TaskCreate","TaskGet","TaskList","TaskOutput","TaskStop","TaskUpdate","WebFetch","WebSearch","mcp__claude_ai_Google_Drive__authenticate","mcp__claude_ai_Google_Drive__complete_authentication"],"removedNames":[],"readdedNames":[],"pendingMcpServers":[]},"type":"attachment","uuid":"44821a2a-af8a-426d-a767-ff8a64758940","timestamp":"2026-06-11T22:00:00.633Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"44821a2a-af8a-426d-a767-ff8a64758940","isSidechain":false,"attachment":{"type":"skill_listing","content":"- update-config: Use this skill to configure the Claude Code harness via settings.json. Automated behaviors (\"from now on when X\", \"each time X\", \"whenever X\", \"before/after X\") require hooks configured in settings.json - the harness executes these, not Claude, so memory/preferences cannot fulfill them. Also use for: permissions (\"allow X\", \"add permission\", \"move permission to\"), env vars (\"set X=Y\"), hook troubleshooting, or any changes to settings.json/settings.local.json files. Examples: \"allow npm commands\", \"add bq permission to global settings\", \"move permission to user settings\", \"set DEBUG=true\", \"when claude stops show X\". For simple settings like theme/model, suggest the /config command.\n- keybindings-help: Use when the user wants to customize keyboard shortcuts, rebind keys, add chord bindings, or modify ~/.claude/keybindings.json. Examples: \"rebind ctrl+s\", \"add a chord shortcut\", \"change the submit key\", \"customize keybindings\".\n- verify: Verify that a code change actually does what it's supposed to by running the app and observing behavior. Use when asked to verify a PR, confirm a fix works, test a change manually, check that a feature works, or validate local changes before pushing.\n- code-review: Review the current diff for correctness bugs and reuse/simplification/efficiency cleanups at the given effort level (low/medium: fewer, high-confidence findings; high→max: broader coverage, may include uncertain findings; ultra: deep multi-agent review in the cloud). Pass --comment to post findings as inline PR comments, or --fix to apply the findings to the working tree after the review.\n- simplify: Review the changed code for reuse, simplification, efficiency, and altitude cleanups, then apply the fixes. Quality only — it does not hunt for bugs; use /code-review for that.\n- fewer-permission-prompts: Scan your transcripts for common read-only Bash and MCP tool calls, then add a prioritized allowlist to project .claude/settings.json to reduce permission prompts.\n- loop: Run a prompt or slash command on a recurring interval (e.g. /loop 5m /foo). Omit the interval to let the model self-pace. - When the user wants to set up a recurring task, poll for status, or run something repeatedly on an interval (e.g. \"check the deploy every 5 minutes\", \"keep running /babysit-prs\"). Do NOT invoke for one-off tasks.\n- schedule: Create, update, list, or run scheduled cloud agents (routines) that execute on a cron schedule. - When the user wants to schedule a recurring cloud agent, set up automated tasks, create a cron job for Claude Code, or manage their scheduled agents/routines. Also use when the user wants a one-time scheduled run (\"run this once at 3pm\", \"remind me to check X tomorrow\").\n- claude-api: Reference for the Claude API / Anthropic SDK — model ids, pricing, params, streaming, tool use, MCP, agents, caching, token counting, model migration.\nTRIGGER — read BEFORE opening the target file; don't skip because it \"looks like a one-liner\" — whenever: the prompt names Claude/Anthropic in any form (Claude, Anthropic, Fable, Opus, Sonnet, Haiku, `anthropic`, `@anthropic-ai`, `claude-*`, `us.anthropic.*`, `[1m]`); the user asks about an LLM (pricing/model choice/limits/caching) — never answer from memory; OR the task is LLM-shaped with provider unstated (agent/MCP/tool-definition/multi-agent/RAG/LLM-judge/computer-use; generate/summarize/extract/classify/rewrite/converse over NL; debugging refusals/cutoffs/streaming/tool-calls/tokens).\nSKIP only when another provider is being worked on (overrides all triggers): OpenAI/GPT/Gemini/Llama/Mistral/Cohere/Ollama named in the query; OR `grep -rE 'openai|langchain_openai|google.generativeai|genai|mistralai|cohere|ollama'` over the project hits (run this grep FIRST if no provider named — don't Read the file).\n- run: Launch and drive this project's app to see a change working. Use when asked to run, start, or screenshot the app, or to confirm a change works in the real app (not just tests). First looks for a project skill that already covers launching the app; otherwise falls back to built-in patterns per project type (CLI, server, TUI, Electron, browser-driven, library).\n- init: Initialize a new CLAUDE.md file with codebase documentation\n- review: Review a pull request\n- security-review: Complete a security review of the pending changes on the current branch","skillCount":13,"isInitial":true,"names":["update-config","keybindings-help","verify","code-review","simplify","fewer-permission-prompts","loop","schedule","claude-api","run","init","review","security-review"]},"type":"attachment","uuid":"d517ed15-7de2-44bb-98f8-d236a166ea97","timestamp":"2026-06-11T22:00:00.633Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"type":"ai-title","aiTitle":"Debug Emby play state sync HTTP 500 errors","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac"} {"parentUuid":"d517ed15-7de2-44bb-98f8-d236a166ea97","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_01WFaPjkhJaqYevUyXUWVxBz","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"","signature":"EuUDCmUIDhgCKkD+eA+CbzeWWzZIHE4Dr5ElxXrRd9rnj4537r3R9lAqQG8HxDjscxdF3Jd6NE81w39QN0hEsFlq0Ehb45qTBPHsMhFjbGF1ZGUtc29ubmV0LTQtNjgAQgh0aGlua2luZxIMEavgMdzKfGf52RGOGgwIewmnk2V9a+iwoAYiMAawTqqOMjhrD+5jwvUA0KDR90bLB/CoXl2NPlB5Uyt0VNMAPkDBd6fBup4vXIGDIiqtAp3FNf8vscqLmHOClr2uEUWAAHYj0J+Ltg3HjSbbwQqkFKKEOoIxl2vdoKs3o7CnV9+1DxU2X/GxB+XdahWOY50T11bmCAQ1eyI5Dg19wQla7N6ok8695H0r0u7jiWZgulK11xXHBsADqka5zArRxLI2U79gwInzl3DVb5HpXT/CZ5mS5r1TUe/a2/WpfgjHuqD1RynzfB4PKOy/OtceTHJStZC7SRtAzaKge2VpRKcyTuG946PM0NYfbqqieCJ3ATD4zkLEmX+J/+8V384Ijg5JsI7E6zmOifz313lHUvMfldFo87rgIlS3boSWi7rAa9Z3CmOVHixLc+iNGmKaduimEz4Qav2mKKgKjfcb0mXGJZsrT4v9WDoR5jBB+fa/Y0SbAhp5AWvEafnp8cUYAQ=="}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":2,"cache_creation_input_tokens":9271,"cache_read_input_tokens":12038,"output_tokens":227,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":9271,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":2,"output_tokens":227,"cache_read_input_tokens":12038,"cache_creation_input_tokens":9271,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":9271},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxDwoLA7a1XK3qn2EUD9","type":"assistant","uuid":"236c77a0-4a77-4874-ab20-20052e63bd24","timestamp":"2026-06-11T22:00:04.921Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"236c77a0-4a77-4874-ab20-20052e63bd24","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_01WFaPjkhJaqYevUyXUWVxBz","type":"message","role":"assistant","content":[{"type":"text","text":"Let me look at the play state sync script to understand what's causing these HTTP 500s from Emby."}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":2,"cache_creation_input_tokens":9271,"cache_read_input_tokens":12038,"output_tokens":227,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":9271,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":2,"output_tokens":227,"cache_read_input_tokens":12038,"cache_creation_input_tokens":9271,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":9271},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxDwoLA7a1XK3qn2EUD9","type":"assistant","uuid":"6c7b3fbe-4894-4723-979e-3e3b10775e02","timestamp":"2026-06-11T22:00:05.374Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"6c7b3fbe-4894-4723-979e-3e3b10775e02","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_01WFaPjkhJaqYevUyXUWVxBz","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01UJp7nLBjVkywwzgFjCq9Kp","name":"Bash","input":{"command":"find /boot/config/plugins/varaverk -name \"*play_state*\" -o -name \"*playstate*\" 2>/dev/null","description":"Find play state sync scripts"},"caller":{"type":"direct"}}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":2,"cache_creation_input_tokens":9271,"cache_read_input_tokens":12038,"output_tokens":227,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":9271,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":2,"output_tokens":227,"cache_read_input_tokens":12038,"cache_creation_input_tokens":9271,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":9271},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxDwoLA7a1XK3qn2EUD9","type":"assistant","uuid":"8b725732-1e32-4d9f-9e52-f9e929f41a80","timestamp":"2026-06-11T22:00:05.882Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"8b725732-1e32-4d9f-9e52-f9e929f41a80","isSidechain":false,"promptId":"1523688a-a842-492d-bb41-f7ece7e3b28c","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01UJp7nLBjVkywwzgFjCq9Kp","type":"tool_result","content":"/boot/config/plugins/varaverk/Media/play_state_sync.sh","is_error":false}]},"uuid":"dc7dbd3e-829b-4816-bcd4-116bfe859208","timestamp":"2026-06-11T22:00:09.344Z","toolUseResult":{"stdout":"/boot/config/plugins/varaverk/Media/play_state_sync.sh","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"8b725732-1e32-4d9f-9e52-f9e929f41a80","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"dc7dbd3e-829b-4816-bcd4-116bfe859208","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_01L9TCKEpS4Q95ZJV38WGkct","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_016djfknFAvTbLpjjAG2JtQH","name":"Read","input":{"file_path":"/boot/config/plugins/varaverk/Media/play_state_sync.sh"},"caller":{"type":"direct"}}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":1,"cache_creation_input_tokens":259,"cache_read_input_tokens":21309,"output_tokens":72,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":259,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":1,"output_tokens":72,"cache_read_input_tokens":21309,"cache_creation_input_tokens":259,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":259},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxDxSEvM3tXpHGRY7mnz","type":"assistant","uuid":"78a251b3-e0d8-4a20-b645-a47e80fd773e","timestamp":"2026-06-11T22:00:11.098Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"78a251b3-e0d8-4a20-b645-a47e80fd773e","isSidechain":false,"promptId":"1523688a-a842-492d-bb41-f7ece7e3b28c","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_016djfknFAvTbLpjjAG2JtQH","type":"tool_result","content":"1\t#!/bin/bash\n2\t# ==============================================================================================\n3\t# ================================= Play State Sync ============================================\n4\t# ==============================================================================================\n5\t#\n6\t# PURPOSE\n7\t# ─────────────────────────────────────────────────────────────────────────────\n8\t# Syncs watched/played state and resume positions across all configured Emby\n9\t# and Jellyfin servers. Newest timestamp wins — no data is ever lost.\n10\t#\n11\t# Users are matched by name (case-insensitive). If a user exists on some servers\n12\t# but not others, those servers are skipped for that user — no errors, no partial\n13\t# syncs from unrelated accounts.\n14\t#\n15\t# Items are matched by external provider IDs:\n16\t# Movies → IMDb ID, then TMDB ID\n17\t# Episodes → TVDB ID + season + episode number\n18\t# Audio → MusicBrainz Track ID\n19\t#\n20\t# ==============================================================================================\n21\t# SYNC LOGIC\n22\t# ==============================================================================================\n23\t#\n24\t# For each matched item across ≥2 servers:\n25\t# 1. Compare LastPlayedDate across all servers that have a play record.\n26\t# 2. The server with the newest LastPlayedDate is authoritative.\n27\t# 3. Push that server's state (Played, PlayCount, LastPlayedDate,\n28\t# PlaybackPositionTicks) to every other server.\n29\t# 4. Servers with no record for that item also receive the state.\n30\t#\n31\t# Resume positions (partial plays, not marked Played):\n32\t# Synced by comparing PlaybackPositionTicks when LastPlayedDate is absent.\n33\t# The higher tick count wins.\n34\t#\n35\t# ==============================================================================================\n36\t# CONFIGURATION (host*.conf, aliased by detect_hosts)\n37\t# ==============================================================================================\n38\t#\n39\t# HOST*_TRANSCODE_SERVERS \"Name|URL|APIKey|type\" entries per host (emby/jellyfin)\n40\t# All hosts are discovered automatically — no extra config needed.\n41\t# Remote host URLs have localhost rewritten to their Tailscale IP.\n42\t#\n43\t# master.conf\n44\t#\n45\t# PLAY_SYNC_ENABLED Master toggle (default: true)\n46\t# PLAY_SYNC_REMOTE Sync across all hosts via Tailscale (default: true)\n47\t# false = local servers only (this host's Emby + Jellyfin)\n48\t# PLAY_SYNC_DAYS How many days back to check for played items (default: 90)\n49\t# Use 0 to sync all played items (slow on large libraries).\n50\t# PLAY_SYNC_TYPES Comma-separated item types to sync (default: Movie,Episode,Audio)\n51\t#\n52\t# ==============================================================================================\n53\t# RUNTIME MODES\n54\t# ==============================================================================================\n55\t#\n56\t# play_state_sync.sh\n57\t# Sync all matched users across all configured servers.\n58\t#\n59\t# play_state_sync.sh --dry-run\n60\t# Show what would be synced without writing any state.\n61\t#\n62\t# play_state_sync.sh --status\n63\t# Show configured servers, reachability, and user counts.\n64\t#\n65\t# play_state_sync.sh --full\n66\t# Ignore PLAY_SYNC_DAYS — sync all played items (may be slow).\n67\t#\n68\t# play_state_sync.sh --log\n69\t# Verbose output — show each item comparison.\n70\t#\n71\t# ==============================================================================================\n72\t\n73\tSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\n74\tsource \"$SCRIPT_DIR/../load_config.sh\"\n75\t\n76\t# ── Handle --full before parse_args ───────────────────────────────────────────\n77\tFULL_SYNC=false\n78\t_FILTERED=()\n79\tfor _a in \"$@\"; do\n80\t [[ \"$_a\" == \"--full\" ]] && FULL_SYNC=true || _FILTERED+=(\"$_a\")\n81\tdone\n82\tparse_args \"${_FILTERED[@]}\"\n83\t\n84\t# ==============================================================================================\n85\t# ━━━ Setup ━━━\n86\t# ==============================================================================================\n87\t[[ \"${PLAY_SYNC_ENABLED:-true}\" != \"true\" ]] && echo \"Play state sync disabled\" && exit 0\n88\t\n89\tSYNC_DAYS=\"${PLAY_SYNC_DAYS:-90}\"\n90\tSYNC_TYPES=\"${PLAY_SYNC_TYPES:-Movie,Episode,Audio}\"\n91\t[[ \"$FULL_SYNC\" == true ]] && SYNC_DAYS=0\n92\tlog \"$ICON_GEAR Config: days=${SYNC_DAYS} types=${SYNC_TYPES} remote=${PLAY_SYNC_REMOTE:-true}\"\n93\t\n94\tcommand -v jq >/dev/null 2>&1 || { error \"jq is required but not installed\"; exit 1; }\n95\t\n96\tacquire_lock\n97\t\n98\t# ── Build server list across ALL hosts ────────────────────────────────────────\n99\t# All HOST*_TRANSCODE_SERVERS arrays are loaded into env by load_config.sh.\n100\t# For remote hosts, localhost in the URL is rewritten to their Tailscale IP.\n101\tdeclare -a SRV_NAME SRV_URL SRV_KEY SRV_TYPE\n102\t_srv_count=0\n103\t_my_hostname=$(hostname -s)\n104\t\n105\t_add_server() {\n106\t local name=\"$1\" url=\"$2\" key=\"$3\" type=\"$4\"\n107\t [[ -z \"$url\" || -z \"$key\" ]] && return\n108\t [[ \"$key\" == \"YOUR_API_KEY\"* || \"$key\" == \"placeholder\"* ]] && return\n109\t SRV_NAME[$_srv_count]=\"$name\"\n110\t SRV_URL[$_srv_count]=\"$url\"\n111\t SRV_KEY[$_srv_count]=\"$key\"\n112\t SRV_TYPE[$_srv_count]=\"$type\"\n113\t (( _srv_count++ ))\n114\t}\n115\t\n116\tfor _varname in $(compgen -v | grep -E '^HOST[0-9]+$' | sort); do\n117\t _num=\"${_varname//[^0-9]/}\"\n118\t _host_hostname=\"${!_varname}\"\n119\t [[ -z \"$_host_hostname\" ]] && continue\n120\t\n121\t _is_me=false\n122\t [[ \"${_host_hostname,,}\" == \"${_my_hostname,,}\" ]] && _is_me=true\n123\t\n124\t # Skip remote hosts when PLAY_SYNC_REMOTE=false\n125\t if [[ \"$_is_me\" == false && \"${PLAY_SYNC_REMOTE:-true}\" != \"true\" ]]; then\n126\t log \"$_host_hostname — remote sync disabled (PLAY_SYNC_REMOTE=false), skipping\"\n127\t continue\n128\t fi\n129\t\n130\t # Resolve Tailscale IP for remote hosts\n131\t _ts_ip=\"\"\n132\t if [[ \"$_is_me\" == false ]]; then\n133\t _ts_ip=$(resolve_tailscale_ip \"$_host_hostname\")\n134\t if [[ -z \"$_ts_ip\" ]]; then\n135\t log \"$_host_hostname — Tailscale IP not found, skipping\"\n136\t continue\n137\t fi\n138\t fi\n139\t\n140\t # Load this host's TRANSCODE_SERVERS array\n141\t _srv_arr_name=\"HOST${_num}_TRANSCODE_SERVERS\"\n142\t eval \"_host_entries=(\\\"\\${${_srv_arr_name}[@]}\\\")\"\n143\t [[ \"${#_host_entries[@]}\" -eq 0 ]] && continue\n144\t\n145\t for _entry in \"${_host_entries[@]}\"; do\n146\t IFS='|' read -r _name _url _key _type <<< \"$_entry\"\n147\t [[ \"$_type\" == \"emby\" || \"$_type\" == \"jellyfin\" ]] || continue\n148\t # For remote hosts rewrite localhost/127.0.0.1 → Tailscale IP\n149\t if [[ \"$_is_me\" == false ]]; then\n150\t _url=\"${_url//localhost/$_ts_ip}\"\n151\t _url=\"${_url//127.0.0.1/$_ts_ip}\"\n152\t fi\n153\t _add_server \"${_name} (${_host_hostname})\" \"$_url\" \"$_key\" \"$_type\"\n154\t done\n155\tdone\n156\t\n157\tif [[ \"$_srv_count\" -lt 2 ]]; then\n158\t error \"Need at least 2 media servers configured — found $_srv_count\"\n159\t exit 1\n160\tfi\n161\t\n162\t# ==============================================================================================\n163\t# ━━━ API Helpers ━━━\n164\t# ==============================================================================================\n165\t_api_get() {\n166\t local url=\"$1\" key=\"$2\" endpoint=\"$3\"\n167\t curl -sf --max-time 30 \\\n168\t -H \"X-Emby-Token: $key\" \\\n169\t \"${url%/}/${endpoint}\" 2>/dev/null\n170\t}\n171\t\n172\t_api_post() {\n173\t local url=\"$1\" key=\"$2\" endpoint=\"$3\" data=\"${4:-}\"\n174\t if [[ -n \"$data\" ]]; then\n175\t curl -sf --max-time 30 -s -o /dev/null -w \"%{http_code}\" -X POST \\\n176\t -H \"X-Emby-Token: $key\" \\\n177\t -H \"Content-Type: application/json\" \\\n178\t -d \"$data\" \\\n179\t \"${url%/}/${endpoint}\" 2>/dev/null\n180\t else\n181\t curl -sf --max-time 30 -s -o /dev/null -w \"%{http_code}\" -X POST \\\n182\t -H \"X-Emby-Token: $key\" \\\n183\t \"${url%/}/${endpoint}\" 2>/dev/null\n184\t fi\n185\t}\n186\t\n187\t# ISO 8601 date → unix seconds (portable, no date -d on BusyBox)\n188\t_iso_to_epoch() {\n189\t local dt=\"$1\"\n190\t [[ -z \"$dt\" || \"$dt\" == \"null\" ]] && echo 0 && return\n191\t # Strip fractional seconds and Z, convert to seconds\n192\t dt=\"${dt%.*}\" # remove .NNNNNNN\n193\t dt=\"${dt%Z}\" # remove trailing Z\n194\t dt=\"${dt/T/ }\" # T → space\n195\t date -u -d \"$dt UTC\" +%s 2>/dev/null || echo 0\n196\t}\n197\t\n198\t# Ticks → seconds (1 tick = 100ns, 10_000_000 ticks = 1s)\n199\t_ticks_to_sec() {\n200\t echo $(( ${1:-0} / 10000000 ))\n201\t}\n202\t\n203\t# ==============================================================================================\n204\t# ━━━ Status ━━━\n205\t# ==============================================================================================\n206\tif [[ \"$SHOW_STATUS\" == true ]]; then\n207\t echo \"\"\n208\t echo \"━━━━━ $ICON_SUMMARY PLAY STATE SYNC STATUS ━━━━━\"\n209\t echo \"$ICON_GEAR Remote sync: ${PLAY_SYNC_REMOTE:-true}\"\n210\t echo \"$ICON_GEAR Sync days: ${SYNC_DAYS:-all}\"\n211\t echo \"$ICON_GEAR Item types: $SYNC_TYPES\"\n212\t echo \"\"\n213\t for i in $(seq 0 $(( _srv_count - 1 ))); do\n214\t echo \"$ICON_HOST [${SRV_TYPE[$i]}] ${SRV_NAME[$i]} (${SRV_URL[$i]})\"\n215\t _users=$(_api_get \"${SRV_URL[$i]}\" \"${SRV_KEY[$i]}\" \"Users\" 2>/dev/null | jq -r '.[].Name' 2>/dev/null | wc -l)\n216\t if [[ \"$_users\" -gt 0 ]]; then\n217\t echo \" $ICON_DONE Reachable — $_users user(s)\"\n218\t _api_get \"${SRV_URL[$i]}\" \"${SRV_KEY[$i]}\" \"Users\" 2>/dev/null \\\n219\t | jq -r '.[].Name' 2>/dev/null | while read -r n; do echo \" · $n\"; done\n220\t else\n221\t echo \" $ICON_ERROR Unreachable or no users\"\n222\t fi\n223\t done\n224\t echo \"━━━━━━━━━━━━━━━━━━━━━━━\"\n225\t exit 0\n226\tfi\n227\t\n228\t# ==============================================================================================\n229\t# ━━━ Main Sync ━━━\n230\t# ==============================================================================================\n231\techo \"━━━ $ICON_SYNC Play State Sync — $(date '+%Y-%m-%d %H:%M:%S') ━━━\"\n232\t[[ \"$DRY_RUN\" == true ]] && warn \"DRY RUN — no state will be written\"\n233\t[[ \"$FULL_SYNC\" == true ]] && log \"Full sync mode — ignoring PLAY_SYNC_DAYS\"\n234\t\n235\tSTART=$(date +%s)\n236\tTOTAL_SYNCED=0\n237\tTOTAL_SKIPPED=0\n238\tTOTAL_ERRORS=0\n239\t\n240\t# ── Step 1: Fetch users from each server ─────────────────────────────────────\n241\tdeclare -A SRV_USERS # idx → JSON array string of users\n242\t\n243\tlog \"Fetching users...\"\n244\tfor i in $(seq 0 $(( _srv_count - 1 ))); do\n245\t _resp=$(_api_get \"${SRV_URL[$i]}\" \"${SRV_KEY[$i]}\" \"Users\")\n246\t if [[ -z \"$_resp\" ]]; then\n247\t warn \"${SRV_NAME[$i]} — unreachable, skipping\"\n248\t SRV_USERS[$i]=\"\"\n249\t continue\n250\t fi\n251\t SRV_USERS[$i]=\"$_resp\"\n252\t _count=$(echo \"$_resp\" | jq 'length' 2>/dev/null || echo 0)\n253\t log \"${SRV_NAME[$i]} — $_count user(s)\"\n254\tdone\n255\t\n256\t# ── Step 2: Build cross-server user map ──────────────────────────────────────\n257\t# lowercase_name → \"server_idx:user_id server_idx:user_id ...\"\n258\tdeclare -A USER_MAP\n259\t\n260\tfor i in $(seq 0 $(( _srv_count - 1 ))); do\n261\t [[ -z \"${SRV_USERS[$i]}\" ]] && continue\n262\t while IFS=$'\\t' read -r uid uname; do\n263\t [[ -z \"$uid\" || -z \"$uname\" ]] && continue\n264\t lname=\"${uname,,}\"\n265\t if [[ -n \"${USER_MAP[$lname]}\" ]]; then\n266\t USER_MAP[$lname]+=\" ${i}:${uid}\"\n267\t else\n268\t USER_MAP[$lname]=\"${i}:${uid}\"\n269\t fi\n270\t done < <(echo \"${SRV_USERS[$i]}\" | jq -r '.[] | [.Id, .Name] | @tsv' 2>/dev/null)\n271\tdone\n272\t\n273\t# ── Step 3: Sync per matched user ────────────────────────────────────────────\n274\t_date_filter=\"\"\n275\tif [[ \"$SYNC_DAYS\" -gt 0 ]]; then\n276\t _cutoff=$(date -u -d \"$SYNC_DAYS days ago\" '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || \\\n277\t date -u -v \"-${SYNC_DAYS}d\" '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null)\n278\t [[ -n \"$_cutoff\" ]] && _date_filter=\"&MinDateLastSaved=$_cutoff\"\n279\tfi\n280\t\n281\tfor lname in \"${!USER_MAP[@]}\"; do\n282\t read -ra _pairs <<< \"${USER_MAP[$lname]}\"\n283\t\n284\t # Skip users only on one server\n285\t [[ \"${#_pairs[@]}\" -lt 2 ]] && log \" $lname — only on 1 server, skipping\" && continue\n286\t\n287\t echo \"\"\n288\t echo \"── User: $lname (${#_pairs[@]} server(s)) ──\"\n289\t\n290\t # Build per-server user context\n291\t declare -A U_IDX U_UID\n292\t for _pair in \"${_pairs[@]}\"; do\n293\t IFS=':' read -r _si _ui <<< \"$_pair\"\n294\t U_IDX[\"$_si\"]=\"$_si\"\n295\t U_UID[\"$_si\"]=\"$_ui\"\n296\t done\n297\t\n298\t # ── Fetch played items from each server for this user ────────────────────\n299\t # Key: provider_id_string → sorted list of (epoch, srv_idx, item_id, play_count, ticks, played)\n300\t declare -A ITEM_MAP # provider_key → JSON per-server data\n301\t\n302\t for _si in \"${!U_IDX[@]}\"; do\n303\t _uid=\"${U_UID[$_si]}\"\n304\t _endpoint=\"Users/${_uid}/Items?Recursive=true&Fields=ProviderIds,UserData,Type,ParentIndexNumber,IndexNumber,SeriesName&IncludeItemTypes=${SYNC_TYPES}&Filters=IsPlayed${_date_filter}&Limit=5000\"\n305\t _resp=$(_api_get \"${SRV_URL[$_si]}\" \"${SRV_KEY[$_si]}\" \"$_endpoint\")\n306\t if [[ -z \"$_resp\" ]]; then\n307\t warn \" ${SRV_NAME[$_si]} — failed to fetch items for $lname\"\n308\t continue\n309\t fi\n310\t\n311\t # Also fetch items with resume position (not yet marked played)\n312\t _endpoint2=\"Users/${_uid}/Items?Recursive=true&Fields=ProviderIds,UserData,Type,ParentIndexNumber,IndexNumber,SeriesName&IncludeItemTypes=${SYNC_TYPES}&SortBy=DatePlayed&SortOrder=Descending&Filters=IsResumable${_date_filter}&Limit=500\"\n313\t _resp2=$(_api_get \"${SRV_URL[$_si]}\" \"${SRV_KEY[$_si]}\" \"$_endpoint2\")\n314\t\n315\t # Combine and deduplicate by Id\n316\t if [[ -n \"$_resp2\" ]]; then\n317\t _combined=$(printf '%s\\n%s' \"$_resp\" \"$_resp2\" | jq -s \\\n318\t '[.[0].Items // [], .[1].Items // []] | add // [] | unique_by(.Id)' 2>/dev/null)\n319\t else\n320\t _combined=$(echo \"$_resp\" | jq '.Items // []' 2>/dev/null)\n321\t fi\n322\t\n323\t _count=$(echo \"$_combined\" | jq 'length' 2>/dev/null || echo 0)\n324\t log \" ${SRV_NAME[$_si]} — $_count item(s) with state for $lname\"\n325\t\n326\t # Build item lookup by provider key\n327\t while IFS=$'\\t' read -r iid itype season ep imdb tmdb tvdb mbtrack played ticks lplayed pcount; do\n328\t # Build canonical provider key\n329\t _pkey=\"\"\n330\t case \"$itype\" in\n331\t Movie)\n332\t [[ \"$imdb\" != \"null\" && -n \"$imdb\" ]] && _pkey=\"imdb:${imdb}\"\n333\t [[ -z \"$_pkey\" && \"$tmdb\" != \"null\" && -n \"$tmdb\" ]] && _pkey=\"tmdb:movie:${tmdb}\"\n334\t ;;\n335\t Episode)\n336\t [[ \"$tvdb\" != \"null\" && -n \"$tvdb\" && \"$season\" != \"null\" && \"$ep\" != \"null\" ]] && \\\n337\t _pkey=\"tvdb:ep:${tvdb}:s${season}e${ep}\"\n338\t ;;\n339\t Audio)\n340\t [[ \"$mbtrack\" != \"null\" && -n \"$mbtrack\" ]] && _pkey=\"mb:track:${mbtrack}\"\n341\t ;;\n342\t esac\n343\t [[ -z \"$_pkey\" ]] && continue\n344\t\n345\t _epoch=$(_iso_to_epoch \"$lplayed\")\n346\t _entry=\"${_si}|${iid}|${played}|${pcount}|${ticks}|${_epoch}|${lplayed}\"\n347\t\n348\t if [[ -n \"${ITEM_MAP[$_pkey]}\" ]]; then\n349\t ITEM_MAP[$_pkey]+=$'\\n'\"$_entry\"\n350\t else\n351\t ITEM_MAP[$_pkey]=\"$_entry\"\n352\t fi\n353\t\n354\t done < <(echo \"$_combined\" | jq -r '.[] | [\n355\t .Id,\n356\t .Type,\n357\t (.ParentIndexNumber // \"null\" | tostring),\n358\t (.IndexNumber // \"null\" | tostring),\n359\t (.ProviderIds.Imdb // \"null\"),\n360\t (.ProviderIds.Tmdb // \"null\"),\n361\t (.ProviderIds.Tvdb // \"null\"),\n362\t (.ProviderIds.MusicBrainzTrackId // \"null\"),\n363\t (.UserData.Played // false | tostring),\n364\t (.UserData.PlaybackPositionTicks // 0 | tostring),\n365\t (.UserData.LastPlayedDate // \"null\"),\n366\t (.UserData.PlayCount // 0 | tostring)\n367\t ] | @tsv' 2>/dev/null)\n368\t done\n369\t\n370\t # ── Compare and sync ─────────────────────────────────────────────────────\n371\t for _pkey in \"${!ITEM_MAP[@]}\"; do\n372\t # Collect all server entries for this item\n373\t declare -A E_EPOCH E_PLAYED E_PCOUNT E_TICKS E_IID E_LPLAYED E_SIDX\n374\t _has_entries=false\n375\t\n376\t while IFS='|' read -r _si _iid _played _pcount _ticks _epoch _lplayed; do\n377\t [[ -z \"$_si\" ]] && continue\n378\t E_SIDX[$_si]=\"$_si\"\n379\t E_IID[$_si]=\"$_iid\"\n380\t E_PLAYED[$_si]=\"$_played\"\n381\t E_PCOUNT[$_si]=\"$_pcount\"\n382\t E_TICKS[$_si]=\"$_ticks\"\n383\t E_EPOCH[$_si]=\"$_epoch\"\n384\t E_LPLAYED[$_si]=\"$_lplayed\"\n385\t _has_entries=true\n386\t done <<< \"${ITEM_MAP[$_pkey]}\"\n387\t\n388\t [[ \"$_has_entries\" == false ]] && continue\n389\t\n390\t # Find the authoritative server: newest LastPlayedDate epoch\n391\t # Tie-break: higher PlayCount, then higher Ticks\n392\t _auth_si=\"\"\n393\t _auth_epoch=0\n394\t _auth_pcount=0\n395\t _auth_ticks=0\n396\t\n397\t for _si in \"${!E_SIDX[@]}\"; do\n398\t _e=\"${E_EPOCH[$_si]:-0}\"\n399\t _pc=\"${E_PCOUNT[$_si]:-0}\"\n400\t _tk=\"${E_TICKS[$_si]:-0}\"\n401\t if [[ \"$_e\" -gt \"$_auth_epoch\" ]] || \\\n402\t [[ \"$_e\" -eq \"$_auth_epoch\" && \"$_pc\" -gt \"$_auth_pcount\" ]] || \\\n403\t [[ \"$_e\" -eq \"$_auth_epoch\" && \"$_pc\" -eq \"$_auth_pcount\" && \"$_tk\" -gt \"$_auth_ticks\" ]]; then\n404\t _auth_si=\"$_si\"\n405\t _auth_epoch=\"$_e\"\n406\t _auth_pcount=\"$_pc\"\n407\t _auth_ticks=\"$_tk\"\n408\t fi\n409\t done\n410\t\n411\t [[ -z \"$_auth_si\" ]] && continue\n412\t\n413\t _auth_played=\"${E_PLAYED[$_auth_si]}\"\n414\t _auth_lplayed=\"${E_LPLAYED[$_auth_si]}\"\n415\t _auth_pcount=\"${E_PCOUNT[$_auth_si]}\"\n416\t _auth_ticks=\"${E_TICKS[$_auth_si]}\"\n417\t\n418\t # Push to servers with older state OR no state at all\n419\t for _si in \"${!U_IDX[@]}\"; do\n420\t [[ \"$_si\" == \"$_auth_si\" ]] && continue\n421\t _their_epoch=\"${E_EPOCH[$_si]:-0}\"\n422\t _their_played=\"${E_PLAYED[$_si]:-false}\"\n423\t\n424\t # Skip if they already have the same/newer state\n425\t if [[ \"$_their_epoch\" -ge \"$_auth_epoch\" ]] && \\\n426\t [[ \"$_their_played\" == \"$_auth_played\" ]]; then\n427\t log \" SKIP $_pkey → ${SRV_NAME[$_si]} already up to date\"\n428\t (( TOTAL_SKIPPED++ ))\n429\t continue\n430\t fi\n431\t\n432\t _uid=\"${U_UID[$_si]}\"\n433\t _iid=\"${E_IID[$_si]:-}\" # might not exist on this server yet\n434\t\n435\t # Find item ID on target server by provider key if not in our map\n436\t if [[ -z \"$_iid\" ]]; then\n437\t _ptype=\"${_pkey%%:*}\"\n438\t _pval=\"${_pkey##*:}\"\n439\t case \"$_ptype\" in\n440\t imdb) _search_field=\"imdb.${_pval}\" ;;\n441\t tmdb) _search_field=\"tmdb.${_pval##movie:}\" ;;\n442\t tvdb)\n443\t # _pkey format: tvdb:ep:{tvdb_id}:s{season}e{ep}\n444\t # ##*: gives \"s7e2\" (wrong); strip prefix then first :\n445\t _tvdb_num=\"${_pkey#tvdb:ep:}\"; _tvdb_num=\"${_tvdb_num%%:*}\"\n446\t _search_field=\"tvdb.${_tvdb_num}\"\n447\t ;;\n448\t mb) _search_field=\"\" ;; # skip music if not found\n449\t esac\n450\t\n451\t if [[ -n \"$_search_field\" ]]; then\n452\t _iid=$(_api_get \"${SRV_URL[$_si]}\" \"${SRV_KEY[$_si]}\" \\\n453\t \"Items?AnyProviderIdEquals=${_search_field}&Recursive=true&Fields=ProviderIds&ExcludeLocationTypes=Virtual&Limit=1\" 2>/dev/null \\\n454\t | jq -r '.Items[0].Id // empty' 2>/dev/null)\n455\t fi\n456\t [[ -z \"$_iid\" ]] && log \" SKIP $_pkey → ${SRV_NAME[$_si]} item not found on server\" && continue\n457\t fi\n458\t\n459\t log \" SYNC $_pkey → ${SRV_NAME[$_si]} (auth: ${SRV_NAME[$_auth_si]}, epoch: $_auth_epoch)\"\n460\t\n461\t if [[ \"$DRY_RUN\" == true ]]; then\n462\t echo \" DRY RUN: would sync $_pkey → ${SRV_NAME[$_si]} user=$lname played=$_auth_played date=$_auth_lplayed\"\n463\t (( TOTAL_SYNCED++ ))\n464\t continue\n465\t fi\n466\t\n467\t # Write state to target server\n468\t if [[ \"$_auth_played\" == \"true\" ]]; then\n469\t # Mark as played with date\n470\t _date_param=\"\"\n471\t if [[ \"$_auth_lplayed\" != \"null\" && -n \"$_auth_lplayed\" ]]; then\n472\t # Emby's PlayedItems endpoint rejects 7-digit fractional seconds (.0000000)\n473\t # with HTTP 500; strip to whole seconds before encoding\n474\t if [[ \"$_auth_lplayed\" == *.* ]]; then\n475\t _lp=\"${_auth_lplayed%.*}\"\n476\t [[ \"$_auth_lplayed\" == *Z ]] && _lp+=\"Z\"\n477\t else\n478\t _lp=\"$_auth_lplayed\"\n479\t fi\n480\t _date_param=\"?DatePlayed=${_lp//[: ]/%3A}\"\n481\t fi\n482\t _http=$(_api_post \"${SRV_URL[$_si]}\" \"${SRV_KEY[$_si]}\" \\\n483\t \"Users/${_uid}/PlayedItems/${_iid}${_date_param}\")\n484\t if [[ \"$_http\" == \"200\" || \"$_http\" == \"201\" ]]; then\n485\t success \" ✓ $_pkey → ${SRV_NAME[$_si]} marked played\"\n486\t (( TOTAL_SYNCED++ ))\n487\t else\n488\t warn \" ✗ $_pkey → ${SRV_NAME[$_si]} failed (HTTP ${_http:-err})\"\n489\t (( TOTAL_ERRORS++ ))\n490\t fi\n491\t else\n492\t # Sync resume position only\n493\t _ticks_int=$(( ${_auth_ticks:-0} ))\n494\t if [[ \"$_ticks_int\" -gt 0 ]]; then\n495\t _payload=\"{\\\"PlaybackPositionTicks\\\":${_ticks_int}}\"\n496\t _http=$(_api_post \"${SRV_URL[$_si]}\" \"${SRV_KEY[$_si]}\" \\\n497\t \"Users/${_uid}/Items/${_iid}/UserData\" \"$_payload\")\n498\t if [[ \"$_http\" == \"200\" || \"$_http\" == \"204\" ]]; then\n499\t success \" ✓ $_pkey → ${SRV_NAME[$_si]} resume synced ($(_ticks_to_sec \"$_ticks_int\")s)\"\n500\t (( TOTAL_SYNCED++ ))\n501\t else\n502\t warn \" ✗ $_pkey → ${SRV_NAME[$_si]} resume sync failed (HTTP ${_http:-err})\"\n503\t (( TOTAL_ERRORS++ ))\n504\t fi\n505\t fi\n506\t fi\n507\t done\n508\t\n509\t unset E_EPOCH E_PLAYED E_PCOUNT E_TICKS E_IID E_LPLAYED E_SIDX\n510\t done\n511\t\n512\t unset ITEM_MAP U_IDX U_UID\n513\tdone\n514\t\n515\t# ==============================================================================================\n516\t# ━━━ Summary ━━━\n517\t# ==============================================================================================\n518\tEND=$(date +%s)\n519\techo \"\"\n520\techo \"━━━━━ $ICON_SUMMARY PLAY STATE SYNC SUMMARY ━━━━━\"\n521\techo \"$ICON_TIME Duration: $(format_duration $(( END - START )))\"\n522\techo \"$ICON_DONE Synced: $TOTAL_SYNCED\"\n523\t[[ \"$TOTAL_SKIPPED\" -gt 0 ]] && echo \"$ICON_RUNNING Skipped: $TOTAL_SKIPPED (already current)\"\n524\t[[ \"$TOTAL_ERRORS\" -gt 0 ]] && echo \"$ICON_ERROR Errors: $TOTAL_ERRORS\"\n525\t\n526\tif [[ \"$DRY_RUN\" == true ]]; then\n527\t warn \"DRY RUN — no changes written\"\n528\telif [[ \"$TOTAL_ERRORS\" -eq 0 ]]; then\n529\t success \"Done ✅\"\n530\telse\n531\t warn \"Done with $TOTAL_ERRORS error(s)\"\n532\tfi\n533\t"}]},"uuid":"a3205a15-a640-434b-b42f-875260168336","timestamp":"2026-06-11T22:00:11.115Z","toolUseResult":{"type":"text","file":{"filePath":"/boot/config/plugins/varaverk/Media/play_state_sync.sh","content":"#!/bin/bash\n# ==============================================================================================\n# ================================= Play State Sync ============================================\n# ==============================================================================================\n#\n# PURPOSE\n# ─────────────────────────────────────────────────────────────────────────────\n# Syncs watched/played state and resume positions across all configured Emby\n# and Jellyfin servers. Newest timestamp wins — no data is ever lost.\n#\n# Users are matched by name (case-insensitive). If a user exists on some servers\n# but not others, those servers are skipped for that user — no errors, no partial\n# syncs from unrelated accounts.\n#\n# Items are matched by external provider IDs:\n# Movies → IMDb ID, then TMDB ID\n# Episodes → TVDB ID + season + episode number\n# Audio → MusicBrainz Track ID\n#\n# ==============================================================================================\n# SYNC LOGIC\n# ==============================================================================================\n#\n# For each matched item across ≥2 servers:\n# 1. Compare LastPlayedDate across all servers that have a play record.\n# 2. The server with the newest LastPlayedDate is authoritative.\n# 3. Push that server's state (Played, PlayCount, LastPlayedDate,\n# PlaybackPositionTicks) to every other server.\n# 4. Servers with no record for that item also receive the state.\n#\n# Resume positions (partial plays, not marked Played):\n# Synced by comparing PlaybackPositionTicks when LastPlayedDate is absent.\n# The higher tick count wins.\n#\n# ==============================================================================================\n# CONFIGURATION (host*.conf, aliased by detect_hosts)\n# ==============================================================================================\n#\n# HOST*_TRANSCODE_SERVERS \"Name|URL|APIKey|type\" entries per host (emby/jellyfin)\n# All hosts are discovered automatically — no extra config needed.\n# Remote host URLs have localhost rewritten to their Tailscale IP.\n#\n# master.conf\n#\n# PLAY_SYNC_ENABLED Master toggle (default: true)\n# PLAY_SYNC_REMOTE Sync across all hosts via Tailscale (default: true)\n# false = local servers only (this host's Emby + Jellyfin)\n# PLAY_SYNC_DAYS How many days back to check for played items (default: 90)\n# Use 0 to sync all played items (slow on large libraries).\n# PLAY_SYNC_TYPES Comma-separated item types to sync (default: Movie,Episode,Audio)\n#\n# ==============================================================================================\n# RUNTIME MODES\n# ==============================================================================================\n#\n# play_state_sync.sh\n# Sync all matched users across all configured servers.\n#\n# play_state_sync.sh --dry-run\n# Show what would be synced without writing any state.\n#\n# play_state_sync.sh --status\n# Show configured servers, reachability, and user counts.\n#\n# play_state_sync.sh --full\n# Ignore PLAY_SYNC_DAYS — sync all played items (may be slow).\n#\n# play_state_sync.sh --log\n# Verbose output — show each item comparison.\n#\n# ==============================================================================================\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nsource \"$SCRIPT_DIR/../load_config.sh\"\n\n# ── Handle --full before parse_args ───────────────────────────────────────────\nFULL_SYNC=false\n_FILTERED=()\nfor _a in \"$@\"; do\n [[ \"$_a\" == \"--full\" ]] && FULL_SYNC=true || _FILTERED+=(\"$_a\")\ndone\nparse_args \"${_FILTERED[@]}\"\n\n# ==============================================================================================\n# ━━━ Setup ━━━\n# ==============================================================================================\n[[ \"${PLAY_SYNC_ENABLED:-true}\" != \"true\" ]] && echo \"Play state sync disabled\" && exit 0\n\nSYNC_DAYS=\"${PLAY_SYNC_DAYS:-90}\"\nSYNC_TYPES=\"${PLAY_SYNC_TYPES:-Movie,Episode,Audio}\"\n[[ \"$FULL_SYNC\" == true ]] && SYNC_DAYS=0\nlog \"$ICON_GEAR Config: days=${SYNC_DAYS} types=${SYNC_TYPES} remote=${PLAY_SYNC_REMOTE:-true}\"\n\ncommand -v jq >/dev/null 2>&1 || { error \"jq is required but not installed\"; exit 1; }\n\nacquire_lock\n\n# ── Build server list across ALL hosts ────────────────────────────────────────\n# All HOST*_TRANSCODE_SERVERS arrays are loaded into env by load_config.sh.\n# For remote hosts, localhost in the URL is rewritten to their Tailscale IP.\ndeclare -a SRV_NAME SRV_URL SRV_KEY SRV_TYPE\n_srv_count=0\n_my_hostname=$(hostname -s)\n\n_add_server() {\n local name=\"$1\" url=\"$2\" key=\"$3\" type=\"$4\"\n [[ -z \"$url\" || -z \"$key\" ]] && return\n [[ \"$key\" == \"YOUR_API_KEY\"* || \"$key\" == \"placeholder\"* ]] && return\n SRV_NAME[$_srv_count]=\"$name\"\n SRV_URL[$_srv_count]=\"$url\"\n SRV_KEY[$_srv_count]=\"$key\"\n SRV_TYPE[$_srv_count]=\"$type\"\n (( _srv_count++ ))\n}\n\nfor _varname in $(compgen -v | grep -E '^HOST[0-9]+$' | sort); do\n _num=\"${_varname//[^0-9]/}\"\n _host_hostname=\"${!_varname}\"\n [[ -z \"$_host_hostname\" ]] && continue\n\n _is_me=false\n [[ \"${_host_hostname,,}\" == \"${_my_hostname,,}\" ]] && _is_me=true\n\n # Skip remote hosts when PLAY_SYNC_REMOTE=false\n if [[ \"$_is_me\" == false && \"${PLAY_SYNC_REMOTE:-true}\" != \"true\" ]]; then\n log \"$_host_hostname — remote sync disabled (PLAY_SYNC_REMOTE=false), skipping\"\n continue\n fi\n\n # Resolve Tailscale IP for remote hosts\n _ts_ip=\"\"\n if [[ \"$_is_me\" == false ]]; then\n _ts_ip=$(resolve_tailscale_ip \"$_host_hostname\")\n if [[ -z \"$_ts_ip\" ]]; then\n log \"$_host_hostname — Tailscale IP not found, skipping\"\n continue\n fi\n fi\n\n # Load this host's TRANSCODE_SERVERS array\n _srv_arr_name=\"HOST${_num}_TRANSCODE_SERVERS\"\n eval \"_host_entries=(\\\"\\${${_srv_arr_name}[@]}\\\")\"\n [[ \"${#_host_entries[@]}\" -eq 0 ]] && continue\n\n for _entry in \"${_host_entries[@]}\"; do\n IFS='|' read -r _name _url _key _type <<< \"$_entry\"\n [[ \"$_type\" == \"emby\" || \"$_type\" == \"jellyfin\" ]] || continue\n # For remote hosts rewrite localhost/127.0.0.1 → Tailscale IP\n if [[ \"$_is_me\" == false ]]; then\n _url=\"${_url//localhost/$_ts_ip}\"\n _url=\"${_url//127.0.0.1/$_ts_ip}\"\n fi\n _add_server \"${_name} (${_host_hostname})\" \"$_url\" \"$_key\" \"$_type\"\n done\ndone\n\nif [[ \"$_srv_count\" -lt 2 ]]; then\n error \"Need at least 2 media servers configured — found $_srv_count\"\n exit 1\nfi\n\n# ==============================================================================================\n# ━━━ API Helpers ━━━\n# ==============================================================================================\n_api_get() {\n local url=\"$1\" key=\"$2\" endpoint=\"$3\"\n curl -sf --max-time 30 \\\n -H \"X-Emby-Token: $key\" \\\n \"${url%/}/${endpoint}\" 2>/dev/null\n}\n\n_api_post() {\n local url=\"$1\" key=\"$2\" endpoint=\"$3\" data=\"${4:-}\"\n if [[ -n \"$data\" ]]; then\n curl -sf --max-time 30 -s -o /dev/null -w \"%{http_code}\" -X POST \\\n -H \"X-Emby-Token: $key\" \\\n -H \"Content-Type: application/json\" \\\n -d \"$data\" \\\n \"${url%/}/${endpoint}\" 2>/dev/null\n else\n curl -sf --max-time 30 -s -o /dev/null -w \"%{http_code}\" -X POST \\\n -H \"X-Emby-Token: $key\" \\\n \"${url%/}/${endpoint}\" 2>/dev/null\n fi\n}\n\n# ISO 8601 date → unix seconds (portable, no date -d on BusyBox)\n_iso_to_epoch() {\n local dt=\"$1\"\n [[ -z \"$dt\" || \"$dt\" == \"null\" ]] && echo 0 && return\n # Strip fractional seconds and Z, convert to seconds\n dt=\"${dt%.*}\" # remove .NNNNNNN\n dt=\"${dt%Z}\" # remove trailing Z\n dt=\"${dt/T/ }\" # T → space\n date -u -d \"$dt UTC\" +%s 2>/dev/null || echo 0\n}\n\n# Ticks → seconds (1 tick = 100ns, 10_000_000 ticks = 1s)\n_ticks_to_sec() {\n echo $(( ${1:-0} / 10000000 ))\n}\n\n# ==============================================================================================\n# ━━━ Status ━━━\n# ==============================================================================================\nif [[ \"$SHOW_STATUS\" == true ]]; then\n echo \"\"\n echo \"━━━━━ $ICON_SUMMARY PLAY STATE SYNC STATUS ━━━━━\"\n echo \"$ICON_GEAR Remote sync: ${PLAY_SYNC_REMOTE:-true}\"\n echo \"$ICON_GEAR Sync days: ${SYNC_DAYS:-all}\"\n echo \"$ICON_GEAR Item types: $SYNC_TYPES\"\n echo \"\"\n for i in $(seq 0 $(( _srv_count - 1 ))); do\n echo \"$ICON_HOST [${SRV_TYPE[$i]}] ${SRV_NAME[$i]} (${SRV_URL[$i]})\"\n _users=$(_api_get \"${SRV_URL[$i]}\" \"${SRV_KEY[$i]}\" \"Users\" 2>/dev/null | jq -r '.[].Name' 2>/dev/null | wc -l)\n if [[ \"$_users\" -gt 0 ]]; then\n echo \" $ICON_DONE Reachable — $_users user(s)\"\n _api_get \"${SRV_URL[$i]}\" \"${SRV_KEY[$i]}\" \"Users\" 2>/dev/null \\\n | jq -r '.[].Name' 2>/dev/null | while read -r n; do echo \" · $n\"; done\n else\n echo \" $ICON_ERROR Unreachable or no users\"\n fi\n done\n echo \"━━━━━━━━━━━━━━━━━━━━━━━\"\n exit 0\nfi\n\n# ==============================================================================================\n# ━━━ Main Sync ━━━\n# ==============================================================================================\necho \"━━━ $ICON_SYNC Play State Sync — $(date '+%Y-%m-%d %H:%M:%S') ━━━\"\n[[ \"$DRY_RUN\" == true ]] && warn \"DRY RUN — no state will be written\"\n[[ \"$FULL_SYNC\" == true ]] && log \"Full sync mode — ignoring PLAY_SYNC_DAYS\"\n\nSTART=$(date +%s)\nTOTAL_SYNCED=0\nTOTAL_SKIPPED=0\nTOTAL_ERRORS=0\n\n# ── Step 1: Fetch users from each server ─────────────────────────────────────\ndeclare -A SRV_USERS # idx → JSON array string of users\n\nlog \"Fetching users...\"\nfor i in $(seq 0 $(( _srv_count - 1 ))); do\n _resp=$(_api_get \"${SRV_URL[$i]}\" \"${SRV_KEY[$i]}\" \"Users\")\n if [[ -z \"$_resp\" ]]; then\n warn \"${SRV_NAME[$i]} — unreachable, skipping\"\n SRV_USERS[$i]=\"\"\n continue\n fi\n SRV_USERS[$i]=\"$_resp\"\n _count=$(echo \"$_resp\" | jq 'length' 2>/dev/null || echo 0)\n log \"${SRV_NAME[$i]} — $_count user(s)\"\ndone\n\n# ── Step 2: Build cross-server user map ──────────────────────────────────────\n# lowercase_name → \"server_idx:user_id server_idx:user_id ...\"\ndeclare -A USER_MAP\n\nfor i in $(seq 0 $(( _srv_count - 1 ))); do\n [[ -z \"${SRV_USERS[$i]}\" ]] && continue\n while IFS=$'\\t' read -r uid uname; do\n [[ -z \"$uid\" || -z \"$uname\" ]] && continue\n lname=\"${uname,,}\"\n if [[ -n \"${USER_MAP[$lname]}\" ]]; then\n USER_MAP[$lname]+=\" ${i}:${uid}\"\n else\n USER_MAP[$lname]=\"${i}:${uid}\"\n fi\n done < <(echo \"${SRV_USERS[$i]}\" | jq -r '.[] | [.Id, .Name] | @tsv' 2>/dev/null)\ndone\n\n# ── Step 3: Sync per matched user ────────────────────────────────────────────\n_date_filter=\"\"\nif [[ \"$SYNC_DAYS\" -gt 0 ]]; then\n _cutoff=$(date -u -d \"$SYNC_DAYS days ago\" '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || \\\n date -u -v \"-${SYNC_DAYS}d\" '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null)\n [[ -n \"$_cutoff\" ]] && _date_filter=\"&MinDateLastSaved=$_cutoff\"\nfi\n\nfor lname in \"${!USER_MAP[@]}\"; do\n read -ra _pairs <<< \"${USER_MAP[$lname]}\"\n\n # Skip users only on one server\n [[ \"${#_pairs[@]}\" -lt 2 ]] && log \" $lname — only on 1 server, skipping\" && continue\n\n echo \"\"\n echo \"── User: $lname (${#_pairs[@]} server(s)) ──\"\n\n # Build per-server user context\n declare -A U_IDX U_UID\n for _pair in \"${_pairs[@]}\"; do\n IFS=':' read -r _si _ui <<< \"$_pair\"\n U_IDX[\"$_si\"]=\"$_si\"\n U_UID[\"$_si\"]=\"$_ui\"\n done\n\n # ── Fetch played items from each server for this user ────────────────────\n # Key: provider_id_string → sorted list of (epoch, srv_idx, item_id, play_count, ticks, played)\n declare -A ITEM_MAP # provider_key → JSON per-server data\n\n for _si in \"${!U_IDX[@]}\"; do\n _uid=\"${U_UID[$_si]}\"\n _endpoint=\"Users/${_uid}/Items?Recursive=true&Fields=ProviderIds,UserData,Type,ParentIndexNumber,IndexNumber,SeriesName&IncludeItemTypes=${SYNC_TYPES}&Filters=IsPlayed${_date_filter}&Limit=5000\"\n _resp=$(_api_get \"${SRV_URL[$_si]}\" \"${SRV_KEY[$_si]}\" \"$_endpoint\")\n if [[ -z \"$_resp\" ]]; then\n warn \" ${SRV_NAME[$_si]} — failed to fetch items for $lname\"\n continue\n fi\n\n # Also fetch items with resume position (not yet marked played)\n _endpoint2=\"Users/${_uid}/Items?Recursive=true&Fields=ProviderIds,UserData,Type,ParentIndexNumber,IndexNumber,SeriesName&IncludeItemTypes=${SYNC_TYPES}&SortBy=DatePlayed&SortOrder=Descending&Filters=IsResumable${_date_filter}&Limit=500\"\n _resp2=$(_api_get \"${SRV_URL[$_si]}\" \"${SRV_KEY[$_si]}\" \"$_endpoint2\")\n\n # Combine and deduplicate by Id\n if [[ -n \"$_resp2\" ]]; then\n _combined=$(printf '%s\\n%s' \"$_resp\" \"$_resp2\" | jq -s \\\n '[.[0].Items // [], .[1].Items // []] | add // [] | unique_by(.Id)' 2>/dev/null)\n else\n _combined=$(echo \"$_resp\" | jq '.Items // []' 2>/dev/null)\n fi\n\n _count=$(echo \"$_combined\" | jq 'length' 2>/dev/null || echo 0)\n log \" ${SRV_NAME[$_si]} — $_count item(s) with state for $lname\"\n\n # Build item lookup by provider key\n while IFS=$'\\t' read -r iid itype season ep imdb tmdb tvdb mbtrack played ticks lplayed pcount; do\n # Build canonical provider key\n _pkey=\"\"\n case \"$itype\" in\n Movie)\n [[ \"$imdb\" != \"null\" && -n \"$imdb\" ]] && _pkey=\"imdb:${imdb}\"\n [[ -z \"$_pkey\" && \"$tmdb\" != \"null\" && -n \"$tmdb\" ]] && _pkey=\"tmdb:movie:${tmdb}\"\n ;;\n Episode)\n [[ \"$tvdb\" != \"null\" && -n \"$tvdb\" && \"$season\" != \"null\" && \"$ep\" != \"null\" ]] && \\\n _pkey=\"tvdb:ep:${tvdb}:s${season}e${ep}\"\n ;;\n Audio)\n [[ \"$mbtrack\" != \"null\" && -n \"$mbtrack\" ]] && _pkey=\"mb:track:${mbtrack}\"\n ;;\n esac\n [[ -z \"$_pkey\" ]] && continue\n\n _epoch=$(_iso_to_epoch \"$lplayed\")\n _entry=\"${_si}|${iid}|${played}|${pcount}|${ticks}|${_epoch}|${lplayed}\"\n\n if [[ -n \"${ITEM_MAP[$_pkey]}\" ]]; then\n ITEM_MAP[$_pkey]+=$'\\n'\"$_entry\"\n else\n ITEM_MAP[$_pkey]=\"$_entry\"\n fi\n\n done < <(echo \"$_combined\" | jq -r '.[] | [\n .Id,\n .Type,\n (.ParentIndexNumber // \"null\" | tostring),\n (.IndexNumber // \"null\" | tostring),\n (.ProviderIds.Imdb // \"null\"),\n (.ProviderIds.Tmdb // \"null\"),\n (.ProviderIds.Tvdb // \"null\"),\n (.ProviderIds.MusicBrainzTrackId // \"null\"),\n (.UserData.Played // false | tostring),\n (.UserData.PlaybackPositionTicks // 0 | tostring),\n (.UserData.LastPlayedDate // \"null\"),\n (.UserData.PlayCount // 0 | tostring)\n ] | @tsv' 2>/dev/null)\n done\n\n # ── Compare and sync ─────────────────────────────────────────────────────\n for _pkey in \"${!ITEM_MAP[@]}\"; do\n # Collect all server entries for this item\n declare -A E_EPOCH E_PLAYED E_PCOUNT E_TICKS E_IID E_LPLAYED E_SIDX\n _has_entries=false\n\n while IFS='|' read -r _si _iid _played _pcount _ticks _epoch _lplayed; do\n [[ -z \"$_si\" ]] && continue\n E_SIDX[$_si]=\"$_si\"\n E_IID[$_si]=\"$_iid\"\n E_PLAYED[$_si]=\"$_played\"\n E_PCOUNT[$_si]=\"$_pcount\"\n E_TICKS[$_si]=\"$_ticks\"\n E_EPOCH[$_si]=\"$_epoch\"\n E_LPLAYED[$_si]=\"$_lplayed\"\n _has_entries=true\n done <<< \"${ITEM_MAP[$_pkey]}\"\n\n [[ \"$_has_entries\" == false ]] && continue\n\n # Find the authoritative server: newest LastPlayedDate epoch\n # Tie-break: higher PlayCount, then higher Ticks\n _auth_si=\"\"\n _auth_epoch=0\n _auth_pcount=0\n _auth_ticks=0\n\n for _si in \"${!E_SIDX[@]}\"; do\n _e=\"${E_EPOCH[$_si]:-0}\"\n _pc=\"${E_PCOUNT[$_si]:-0}\"\n _tk=\"${E_TICKS[$_si]:-0}\"\n if [[ \"$_e\" -gt \"$_auth_epoch\" ]] || \\\n [[ \"$_e\" -eq \"$_auth_epoch\" && \"$_pc\" -gt \"$_auth_pcount\" ]] || \\\n [[ \"$_e\" -eq \"$_auth_epoch\" && \"$_pc\" -eq \"$_auth_pcount\" && \"$_tk\" -gt \"$_auth_ticks\" ]]; then\n _auth_si=\"$_si\"\n _auth_epoch=\"$_e\"\n _auth_pcount=\"$_pc\"\n _auth_ticks=\"$_tk\"\n fi\n done\n\n [[ -z \"$_auth_si\" ]] && continue\n\n _auth_played=\"${E_PLAYED[$_auth_si]}\"\n _auth_lplayed=\"${E_LPLAYED[$_auth_si]}\"\n _auth_pcount=\"${E_PCOUNT[$_auth_si]}\"\n _auth_ticks=\"${E_TICKS[$_auth_si]}\"\n\n # Push to servers with older state OR no state at all\n for _si in \"${!U_IDX[@]}\"; do\n [[ \"$_si\" == \"$_auth_si\" ]] && continue\n _their_epoch=\"${E_EPOCH[$_si]:-0}\"\n _their_played=\"${E_PLAYED[$_si]:-false}\"\n\n # Skip if they already have the same/newer state\n if [[ \"$_their_epoch\" -ge \"$_auth_epoch\" ]] && \\\n [[ \"$_their_played\" == \"$_auth_played\" ]]; then\n log \" SKIP $_pkey → ${SRV_NAME[$_si]} already up to date\"\n (( TOTAL_SKIPPED++ ))\n continue\n fi\n\n _uid=\"${U_UID[$_si]}\"\n _iid=\"${E_IID[$_si]:-}\" # might not exist on this server yet\n\n # Find item ID on target server by provider key if not in our map\n if [[ -z \"$_iid\" ]]; then\n _ptype=\"${_pkey%%:*}\"\n _pval=\"${_pkey##*:}\"\n case \"$_ptype\" in\n imdb) _search_field=\"imdb.${_pval}\" ;;\n tmdb) _search_field=\"tmdb.${_pval##movie:}\" ;;\n tvdb)\n # _pkey format: tvdb:ep:{tvdb_id}:s{season}e{ep}\n # ##*: gives \"s7e2\" (wrong); strip prefix then first :\n _tvdb_num=\"${_pkey#tvdb:ep:}\"; _tvdb_num=\"${_tvdb_num%%:*}\"\n _search_field=\"tvdb.${_tvdb_num}\"\n ;;\n mb) _search_field=\"\" ;; # skip music if not found\n esac\n\n if [[ -n \"$_search_field\" ]]; then\n _iid=$(_api_get \"${SRV_URL[$_si]}\" \"${SRV_KEY[$_si]}\" \\\n \"Items?AnyProviderIdEquals=${_search_field}&Recursive=true&Fields=ProviderIds&ExcludeLocationTypes=Virtual&Limit=1\" 2>/dev/null \\\n | jq -r '.Items[0].Id // empty' 2>/dev/null)\n fi\n [[ -z \"$_iid\" ]] && log \" SKIP $_pkey → ${SRV_NAME[$_si]} item not found on server\" && continue\n fi\n\n log \" SYNC $_pkey → ${SRV_NAME[$_si]} (auth: ${SRV_NAME[$_auth_si]}, epoch: $_auth_epoch)\"\n\n if [[ \"$DRY_RUN\" == true ]]; then\n echo \" DRY RUN: would sync $_pkey → ${SRV_NAME[$_si]} user=$lname played=$_auth_played date=$_auth_lplayed\"\n (( TOTAL_SYNCED++ ))\n continue\n fi\n\n # Write state to target server\n if [[ \"$_auth_played\" == \"true\" ]]; then\n # Mark as played with date\n _date_param=\"\"\n if [[ \"$_auth_lplayed\" != \"null\" && -n \"$_auth_lplayed\" ]]; then\n # Emby's PlayedItems endpoint rejects 7-digit fractional seconds (.0000000)\n # with HTTP 500; strip to whole seconds before encoding\n if [[ \"$_auth_lplayed\" == *.* ]]; then\n _lp=\"${_auth_lplayed%.*}\"\n [[ \"$_auth_lplayed\" == *Z ]] && _lp+=\"Z\"\n else\n _lp=\"$_auth_lplayed\"\n fi\n _date_param=\"?DatePlayed=${_lp//[: ]/%3A}\"\n fi\n _http=$(_api_post \"${SRV_URL[$_si]}\" \"${SRV_KEY[$_si]}\" \\\n \"Users/${_uid}/PlayedItems/${_iid}${_date_param}\")\n if [[ \"$_http\" == \"200\" || \"$_http\" == \"201\" ]]; then\n success \" ✓ $_pkey → ${SRV_NAME[$_si]} marked played\"\n (( TOTAL_SYNCED++ ))\n else\n warn \" ✗ $_pkey → ${SRV_NAME[$_si]} failed (HTTP ${_http:-err})\"\n (( TOTAL_ERRORS++ ))\n fi\n else\n # Sync resume position only\n _ticks_int=$(( ${_auth_ticks:-0} ))\n if [[ \"$_ticks_int\" -gt 0 ]]; then\n _payload=\"{\\\"PlaybackPositionTicks\\\":${_ticks_int}}\"\n _http=$(_api_post \"${SRV_URL[$_si]}\" \"${SRV_KEY[$_si]}\" \\\n \"Users/${_uid}/Items/${_iid}/UserData\" \"$_payload\")\n if [[ \"$_http\" == \"200\" || \"$_http\" == \"204\" ]]; then\n success \" ✓ $_pkey → ${SRV_NAME[$_si]} resume synced ($(_ticks_to_sec \"$_ticks_int\")s)\"\n (( TOTAL_SYNCED++ ))\n else\n warn \" ✗ $_pkey → ${SRV_NAME[$_si]} resume sync failed (HTTP ${_http:-err})\"\n (( TOTAL_ERRORS++ ))\n fi\n fi\n fi\n done\n\n unset E_EPOCH E_PLAYED E_PCOUNT E_TICKS E_IID E_LPLAYED E_SIDX\n done\n\n unset ITEM_MAP U_IDX U_UID\ndone\n\n# ==============================================================================================\n# ━━━ Summary ━━━\n# ==============================================================================================\nEND=$(date +%s)\necho \"\"\necho \"━━━━━ $ICON_SUMMARY PLAY STATE SYNC SUMMARY ━━━━━\"\necho \"$ICON_TIME Duration: $(format_duration $(( END - START )))\"\necho \"$ICON_DONE Synced: $TOTAL_SYNCED\"\n[[ \"$TOTAL_SKIPPED\" -gt 0 ]] && echo \"$ICON_RUNNING Skipped: $TOTAL_SKIPPED (already current)\"\n[[ \"$TOTAL_ERRORS\" -gt 0 ]] && echo \"$ICON_ERROR Errors: $TOTAL_ERRORS\"\n\nif [[ \"$DRY_RUN\" == true ]]; then\n warn \"DRY RUN — no changes written\"\nelif [[ \"$TOTAL_ERRORS\" -eq 0 ]]; then\n success \"Done ✅\"\nelse\n warn \"Done with $TOTAL_ERRORS error(s)\"\nfi\n","numLines":533,"startLine":1,"totalLines":533}},"sourceToolAssistantUUID":"78a251b3-e0d8-4a20-b645-a47e80fd773e","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"type":"last-prompt","lastPrompt":"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━ 🔄 Play State Sync — 2026-06-11 17:37:58 ━━━ ⚠️ [WARN] Emby-Jayred365 (unRAID-Jayred365) — unreachable, skipping ⚠️ [WARN] Jellyfin (unRAID-Jayred365…","leafUuid":"a3205a15-a640-434b-b42f-875260168336","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac"} {"type":"ai-title","aiTitle":"Debug Emby play state sync HTTP 500 errors","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac"} {"type":"mode","mode":"normal","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac"} {"type":"permission-mode","permissionMode":"default","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac"} {"type":"file-history-snapshot","messageId":"91d74879-2ab9-40e4-9b72-a48a9c412fdf","snapshot":{"messageId":"761c25f9-7ee8-46e5-b2d0-cea0531bf3ca","trackedFileBackups":{"/boot/config/plugins/varaverk/Media/play_state_sync.sh":{"backupFileName":"9c50ba6f918d705a@v1","version":1,"backupTime":"2026-06-11T22:03:35.039Z"}},"timestamp":"2026-06-11T22:00:00.634Z"},"isSnapshotUpdate":true} {"parentUuid":"a3205a15-a640-434b-b42f-875260168336","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_01Usw3vRT51bLToCCCH9W7gC","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"","signature":"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"}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":1,"cache_creation_input_tokens":8790,"cache_read_input_tokens":21568,"output_tokens":10825,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":8790,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":1,"output_tokens":10825,"cache_read_input_tokens":21568,"cache_creation_input_tokens":8790,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":8790},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxDxa2jmHXWR5GdYmFBu","type":"assistant","uuid":"ca265a96-b3cb-4d81-ad16-32f222724409","timestamp":"2026-06-11T22:02:52.903Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"ca265a96-b3cb-4d81-ad16-32f222724409","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_01Usw3vRT51bLToCCCH9W7gC","type":"message","role":"assistant","content":[{"type":"text","text":"The issue is in the date format being sent to Emby's `PlayedItems` endpoint. The code already has a comment about Emby rejecting fractional seconds, but it's still sending ISO 8601 (`2026-01-15T10:30:45Z` → `2026-01-15T10%3A30%3A45Z`). Emby's API spec requires `yyyyMMddHHmmss` format (`20260115103045`). Jellyfin marks-played are succeeding likely because those items don't have a date (null `_date_param`).\n\nThe fix is at lines 473-480 — convert the date format rather than just URL-encoding ISO 8601:"}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":1,"cache_creation_input_tokens":8790,"cache_read_input_tokens":21568,"output_tokens":10825,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":8790,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":1,"output_tokens":10825,"cache_read_input_tokens":21568,"cache_creation_input_tokens":8790,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":8790},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxDxa2jmHXWR5GdYmFBu","type":"assistant","uuid":"d28bdf6b-4c88-4187-909e-f14bcbf57d1d","timestamp":"2026-06-11T22:02:55.646Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"d28bdf6b-4c88-4187-909e-f14bcbf57d1d","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_01Usw3vRT51bLToCCCH9W7gC","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01DRu4Qx8pcNiZvBE6NnLrw8","name":"Edit","input":{"replace_all":false,"file_path":"/boot/config/plugins/varaverk/Media/play_state_sync.sh","old_string":" # Emby's PlayedItems endpoint rejects 7-digit fractional seconds (.0000000)\n # with HTTP 500; strip to whole seconds before encoding\n if [[ \"$_auth_lplayed\" == *.* ]]; then\n _lp=\"${_auth_lplayed%.*}\"\n [[ \"$_auth_lplayed\" == *Z ]] && _lp+=\"Z\"\n else\n _lp=\"$_auth_lplayed\"\n fi\n _date_param=\"?DatePlayed=${_lp//[: ]/%3A}\"","new_string":" # PlayedItems expects DatePlayed in yyyyMMddHHmmss (no separators, no timezone)\n _lp=\"${_auth_lplayed%.*}\"\n _lp=\"${_lp%Z}\"\n _date_param=\"?DatePlayed=${_lp//[-T:]/}\""},"caller":{"type":"direct"}}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":1,"cache_creation_input_tokens":8790,"cache_read_input_tokens":21568,"output_tokens":10825,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":8790,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":1,"output_tokens":10825,"cache_read_input_tokens":21568,"cache_creation_input_tokens":8790,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":8790},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxDxa2jmHXWR5GdYmFBu","type":"assistant","uuid":"91d74879-2ab9-40e4-9b72-a48a9c412fdf","timestamp":"2026-06-11T22:02:58.836Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"91d74879-2ab9-40e4-9b72-a48a9c412fdf","isSidechain":false,"promptId":"1523688a-a842-492d-bb41-f7ece7e3b28c","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01DRu4Qx8pcNiZvBE6NnLrw8","type":"tool_result","content":"The file /boot/config/plugins/varaverk/Media/play_state_sync.sh has been updated successfully. (file state is current in your context — no need to Read it back)"}]},"uuid":"80868393-4e6d-462a-8b96-347c310cf570","timestamp":"2026-06-11T22:03:35.082Z","toolUseResult":{"filePath":"/boot/config/plugins/varaverk/Media/play_state_sync.sh","oldString":" # Emby's PlayedItems endpoint rejects 7-digit fractional seconds (.0000000)\n # with HTTP 500; strip to whole seconds before encoding\n if [[ \"$_auth_lplayed\" == *.* ]]; then\n _lp=\"${_auth_lplayed%.*}\"\n [[ \"$_auth_lplayed\" == *Z ]] && _lp+=\"Z\"\n else\n _lp=\"$_auth_lplayed\"\n fi\n _date_param=\"?DatePlayed=${_lp//[: ]/%3A}\"","newString":" # PlayedItems expects DatePlayed in yyyyMMddHHmmss (no separators, no timezone)\n _lp=\"${_auth_lplayed%.*}\"\n _lp=\"${_lp%Z}\"\n _date_param=\"?DatePlayed=${_lp//[-T:]/}\"","originalFile":null,"structuredPatch":[{"oldStart":469,"oldLines":15,"newStart":469,"newLines":10,"lines":[" # Mark as played with date"," _date_param=\"\""," if [[ \"$_auth_lplayed\" != \"null\" && -n \"$_auth_lplayed\" ]]; then","- # Emby's PlayedItems endpoint rejects 7-digit fractional seconds (.0000000)","- # with HTTP 500; strip to whole seconds before encoding","- if [[ \"$_auth_lplayed\" == *.* ]]; then","- _lp=\"${_auth_lplayed%.*}\"","- [[ \"$_auth_lplayed\" == *Z ]] && _lp+=\"Z\"","- else","- _lp=\"$_auth_lplayed\"","- fi","- _date_param=\"?DatePlayed=${_lp//[: ]/%3A}\"","+ # PlayedItems expects DatePlayed in yyyyMMddHHmmss (no separators, no timezone)","+ _lp=\"${_auth_lplayed%.*}\"","+ _lp=\"${_lp%Z}\"","+ _date_param=\"?DatePlayed=${_lp//[-T:]/}\""," fi"," _http=$(_api_post \"${SRV_URL[$_si]}\" \"${SRV_KEY[$_si]}\" \\"," \"Users/${_uid}/PlayedItems/${_iid}${_date_param}\")"]}],"userModified":false,"replaceAll":false},"sourceToolAssistantUUID":"91d74879-2ab9-40e4-9b72-a48a9c412fdf","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"type":"last-prompt","lastPrompt":"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━ 🔄 Play State Sync — 2026-06-11 17:37:58 ━━━ ⚠️ [WARN] Emby-Jayred365 (unRAID-Jayred365) — unreachable, skipping ⚠️ [WARN] Jellyfin (unRAID-Jayred365…","leafUuid":"80868393-4e6d-462a-8b96-347c310cf570","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac"} {"type":"ai-title","aiTitle":"Debug Emby play state sync HTTP 500 errors","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac"} {"type":"mode","mode":"normal","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac"} {"type":"permission-mode","permissionMode":"acceptEdits","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac"} {"parentUuid":"80868393-4e6d-462a-8b96-347c310cf570","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_01FYgs2dZk1i9RCA2dYtuhEZ","type":"message","role":"assistant","content":[{"type":"text","text":"The root cause: `%.*` strips the fractional part but the previous code then re-appended `Z` and URL-encoded the colons, resulting in `2026-01-15T10%3A30%3A45Z` — which Emby's API rejects. The fix strips fractional seconds and the `Z`, then removes all separators to produce `20260115103045`, which is what the API actually expects.\n\nNext run of play_state_sync should clear those 500s."}],"stop_reason":"end_turn","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":1,"cache_creation_input_tokens":10898,"cache_read_input_tokens":30358,"output_tokens":116,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":10898,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":1,"output_tokens":116,"cache_read_input_tokens":30358,"cache_creation_input_tokens":10898,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":10898},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxEDbtXQ5yeAL1niWrs4","type":"assistant","uuid":"49dc15aa-b263-4ed3-98fc-cc53730116c2","timestamp":"2026-06-11T22:03:39.720Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"49dc15aa-b263-4ed3-98fc-cc53730116c2","isSidechain":false,"type":"system","subtype":"turn_duration","durationMs":180889,"messageCount":14,"timestamp":"2026-06-11T22:03:39.802Z","uuid":"ff421d88-c379-4deb-8682-88ed0aa606dd","isMeta":false,"userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"type":"file-history-snapshot","messageId":"f78c9355-ffdd-4902-9cf7-f34bd29869a0","snapshot":{"messageId":"f78c9355-ffdd-4902-9cf7-f34bd29869a0","trackedFileBackups":{"/boot/config/plugins/varaverk/Media/play_state_sync.sh":{"backupFileName":"9c50ba6f918d705a@v2","version":2,"backupTime":"2026-06-11T22:04:13.181Z"}},"timestamp":"2026-06-11T22:04:13.181Z"},"isSnapshotUpdate":false} {"parentUuid":"ff421d88-c379-4deb-8682-88ed0aa606dd","isSidechain":false,"promptId":"7a5d2b09-53d4-4b1c-99c7-6b518385f06c","type":"user","message":{"role":"user","content":"lets run it"},"uuid":"f78c9355-ffdd-4902-9cf7-f34bd29869a0","timestamp":"2026-06-11T22:04:13.160Z","permissionMode":"acceptEdits","promptSource":"typed","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"f78c9355-ffdd-4902-9cf7-f34bd29869a0","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_0178dNDsgKfgfPTKFwdkdC7n","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"","signature":"EocCCmUIDhgCKkDjFmy+WywAiC9U+7iPRFF560qYG7UOPtHu8QOb+uB0csQJT9klEQL00AEtMybALFO4g6bbm2LdxZe7op3r5XUyMhFjbGF1ZGUtc29ubmV0LTQtNjgAQgh0aGlua2luZxIMyWSz7srLT2+51kBBGgyaNqx4Cd9kVPFDUTAiMIiDGSWmnGYBfKgJNHMFpqWxwPTCNoxlr7iL9kY7xjeKQVKxi7KsNp1qjq8PWPvOWypQUhn+KerSNWBCUgGaXCvOVfNOOB/CG3ZYm5Z95WULAowd5uOX5h57IJK91Xu/5UY4GcvcVqEYrrZqdsyGXbelmcXjQjihUTo1e9mA6e4ztu0YAQ=="}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":120,"cache_read_input_tokens":41256,"output_tokens":146,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":120,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":3,"output_tokens":146,"cache_read_input_tokens":41256,"cache_creation_input_tokens":120,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":120},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxEGQkdK2thvffQXT6UF","type":"assistant","uuid":"95e04e85-ae28-4227-975b-c4a4a423a1ac","timestamp":"2026-06-11T22:04:14.964Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"95e04e85-ae28-4227-975b-c4a4a423a1ac","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_0178dNDsgKfgfPTKFwdkdC7n","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01XmXbnvDCM4wwoqpwnWm1Z1","name":"Bash","input":{"command":"/boot/config/plugins/varaverk/Media/play_state_sync.sh 2>&1","description":"Run play state sync","timeout":120000},"caller":{"type":"direct"}}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":3,"cache_creation_input_tokens":120,"cache_read_input_tokens":41256,"output_tokens":146,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":120,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":3,"output_tokens":146,"cache_read_input_tokens":41256,"cache_creation_input_tokens":120,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":120},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxEGQkdK2thvffQXT6UF","type":"assistant","uuid":"ff56b8ca-8a15-4723-b6c3-a6020836501a","timestamp":"2026-06-11T22:04:15.615Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"ff56b8ca-8a15-4723-b6c3-a6020836501a","isSidechain":false,"promptId":"7a5d2b09-53d4-4b1c-99c7-6b518385f06c","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01XmXbnvDCM4wwoqpwnWm1Z1","type":"tool_result","content":"━━━ 🔄 Play State Sync — 2026-06-11 18:04:23 ━━━\n⚠️ [WARN] Emby-Jayred365 (unRAID-Jayred365) — unreachable, skipping\n⚠️ [WARN] Jellyfin (unRAID-Jayred365) — unreachable, skipping\n\n── User: gmer4lfe (2 server(s)) ──\n🏁 [OK] ✓ tvdb:ep:5618559:s7e2 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:167594:s5e4 → Jellyfin (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:11818886:s18e1 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:11759792:s9e2 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:11766619:s10e12 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ imdb:tt8750122 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:3279811:s1e2 → Emby (unRAID-Gmer4Lfe) resume synced (370s)\n🏁 [OK] ✓ tvdb:ep:11493564:s8e11 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:11426444:s1e3 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:10355686:s9e6 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:10355684:s9e7 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ imdb:tt0437863 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:7547570:s1e1 → Jellyfin (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:1555111:s1e1 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:5553405:s4e13 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:893201:s1e5 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:2861921:s1e1 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:11759791:s9e1 → Emby (unRAID-Gmer4Lfe) marked played\n\n── User: failedproxy (2 server(s)) ──\n\n━━━━━ 📋 PLAY STATE SYNC SUMMARY ━━━━━\n⏱️ Duration: 43s\n🏁 Synced: 18\n🟢 Skipped: 35 (already current)\n🏁 [OK] Done ✅","is_error":false}]},"uuid":"086cb69a-7f9c-469c-96ca-963ee1b636ce","timestamp":"2026-06-11T22:05:06.762Z","toolUseResult":{"stdout":"━━━ 🔄 Play State Sync — 2026-06-11 18:04:23 ━━━\n⚠️ [WARN] Emby-Jayred365 (unRAID-Jayred365) — unreachable, skipping\n⚠️ [WARN] Jellyfin (unRAID-Jayred365) — unreachable, skipping\n\n── User: gmer4lfe (2 server(s)) ──\n🏁 [OK] ✓ tvdb:ep:5618559:s7e2 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:167594:s5e4 → Jellyfin (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:11818886:s18e1 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:11759792:s9e2 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:11766619:s10e12 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ imdb:tt8750122 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:3279811:s1e2 → Emby (unRAID-Gmer4Lfe) resume synced (370s)\n🏁 [OK] ✓ tvdb:ep:11493564:s8e11 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:11426444:s1e3 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:10355686:s9e6 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:10355684:s9e7 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ imdb:tt0437863 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:7547570:s1e1 → Jellyfin (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:1555111:s1e1 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:5553405:s4e13 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:893201:s1e5 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:2861921:s1e1 → Emby (unRAID-Gmer4Lfe) marked played\n🏁 [OK] ✓ tvdb:ep:11759791:s9e1 → Emby (unRAID-Gmer4Lfe) marked played\n\n── User: failedproxy (2 server(s)) ──\n\n━━━━━ 📋 PLAY STATE SYNC SUMMARY ━━━━━\n⏱️ Duration: 43s\n🏁 Synced: 18\n🟢 Skipped: 35 (already current)\n🏁 [OK] Done ✅","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"ff56b8ca-8a15-4723-b6c3-a6020836501a","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"086cb69a-7f9c-469c-96ca-963ee1b636ce","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_01DJLGVawukAaVoQWGSNBdqM","type":"message","role":"assistant","content":[{"type":"text","text":"All 18 previously-failing items synced clean — zero errors. The `yyyyMMddHHmmss` format is what Emby needed."}],"stop_reason":"end_turn","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":1,"cache_creation_input_tokens":1192,"cache_read_input_tokens":41376,"output_tokens":37,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":1192,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":1,"output_tokens":37,"cache_read_input_tokens":41376,"cache_creation_input_tokens":1192,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":1192},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxELMsbu9xApb75SXmSj","type":"assistant","uuid":"3b2f818f-dc09-43fa-a3e3-6503aaa5ca55","timestamp":"2026-06-11T22:05:09.019Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"3b2f818f-dc09-43fa-a3e3-6503aaa5ca55","isSidechain":false,"type":"system","subtype":"turn_duration","durationMs":53361,"messageCount":20,"timestamp":"2026-06-11T22:05:09.093Z","uuid":"0ff31fd6-2c3c-4db7-818f-048487510c3f","isMeta":false,"userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"type":"file-history-snapshot","messageId":"e97fb388-2538-4dfd-861a-c8a765aefb0f","snapshot":{"messageId":"e97fb388-2538-4dfd-861a-c8a765aefb0f","trackedFileBackups":{"/boot/config/plugins/varaverk/Media/play_state_sync.sh":{"backupFileName":"9c50ba6f918d705a@v2","version":2,"backupTime":"2026-06-11T22:04:13.181Z"}},"timestamp":"2026-06-11T22:06:03.626Z"},"isSnapshotUpdate":false} {"parentUuid":"0ff31fd6-2c3c-4db7-818f-048487510c3f","isSidechain":false,"promptId":"8c57c845-2fc6-4731-92d4-b8ef5a0b7fb3","type":"user","message":{"role":"user","content":"🔄 Shares (14):\n ❌ Books — 0s\n ❌ Intros — 0s\n ❌ Kids_Movies — 0s\n ❌ Kids_Tv_Shows — 0s\n ❌ Movies — 0s\n ❌ Music — 0s\n ❌ Music_Videos — 0s\n ❌ Nextcloud — 0s\n ❌ stand-up_comedy — 0s\n ❌ Sports — 0s\n ❌ Anime_Shows-Old — 0s\n ❌ Anime_Movies-Old — 0s\n ❌ Anime_Movies — 0s\n ❌ Anime_Shows — 0s\n Passed: 0/14 Failed: 14/14\n"},"uuid":"e97fb388-2538-4dfd-861a-c8a765aefb0f","timestamp":"2026-06-11T22:06:03.615Z","permissionMode":"acceptEdits","promptSource":"typed","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"e97fb388-2538-4dfd-861a-c8a765aefb0f","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_015HtE4iovriqpHB7mwD3y7p","type":"message","role":"assistant","content":[{"type":"thinking","thinking":"","signature":"EtMCCmUIDhgCKkCn55hFsd665SIcEcjX6sUugX6/bG7ayMyJi9BSKM1AsU5ExdapH/I8w6Wgd75E5UVjCk8Ue1gBhCVFr98dQhMcMhFjbGF1ZGUtc29ubmV0LTQtNjgAQgh0aGlua2luZxIM96NaBV7GrrMOoJwxGgzuhnFdIZjz6Ltauu8iMFi4vtM7wCqW9YAd1jDXsenf/Sj3N4xw0jW7o5AJ/Ck4H2aYDrIQsVNtwlV2OizsCCqbAZxzNKqoVoDMRC+RBKWsYVEvn/YYHprQEDweBm+rN8l4VxOkW+xuOVdiG8YIviVkQlEjmfW7n9l7nv4GcDe3fM+/N1zE0QTQLZdCKjz3bentbazJDC+TqVTueYmJYBVHgHKeY6dstwxM7+UUrOnXlFisiLjxQIgxFEceWYlZQJWA41tPLgqsvRnhqZxMNp0dnbywcFKcEZgGMPQjGAE="}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":2,"cache_creation_input_tokens":252,"cache_read_input_tokens":42568,"output_tokens":247,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":252,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":2,"output_tokens":247,"cache_read_input_tokens":42568,"cache_creation_input_tokens":252,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":252},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxEQYtkPWVGb4figzzTt","type":"assistant","uuid":"2912d42f-27f7-4956-b29c-31d0492f6d8a","timestamp":"2026-06-11T22:06:06.285Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"2912d42f-27f7-4956-b29c-31d0492f6d8a","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_015HtE4iovriqpHB7mwD3y7p","type":"message","role":"assistant","content":[{"type":"text","text":"Let me find what's generating this output and check the rsync script."}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":2,"cache_creation_input_tokens":252,"cache_read_input_tokens":42568,"output_tokens":247,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":252,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":2,"output_tokens":247,"cache_read_input_tokens":42568,"cache_creation_input_tokens":252,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":252},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxEQYtkPWVGb4figzzTt","type":"assistant","uuid":"9479dfb1-0e1f-42e5-8085-9be8ce120a1e","timestamp":"2026-06-11T22:06:06.777Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"9479dfb1-0e1f-42e5-8085-9be8ce120a1e","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_015HtE4iovriqpHB7mwD3y7p","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01VVYGXn37iSNhxCUbw5ooUt","name":"Bash","input":{"command":"grep -r \"Passed:.*Failed:\" /boot/config/plugins/varaverk --include=\"*.sh\" -l","description":"Find script producing Passed/Failed output"},"caller":{"type":"direct"}}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":2,"cache_creation_input_tokens":252,"cache_read_input_tokens":42568,"output_tokens":247,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":252,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":2,"output_tokens":247,"cache_read_input_tokens":42568,"cache_creation_input_tokens":252,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":252},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxEQYtkPWVGb4figzzTt","type":"assistant","uuid":"24c1b169-562a-4f8b-bd99-06e91573d336","timestamp":"2026-06-11T22:06:07.785Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"24c1b169-562a-4f8b-bd99-06e91573d336","isSidechain":false,"promptId":"8c57c845-2fc6-4731-92d4-b8ef5a0b7fb3","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01VVYGXn37iSNhxCUbw5ooUt","type":"tool_result","content":"/boot/config/plugins/varaverk/Orchestrators/intermediate_sync_maintenance.sh\n/boot/config/plugins/varaverk/Orchestrators/weekly_sync_maintenance.sh\n/boot/config/plugins/varaverk/Orchestrators/daily_sync_maintenance.sh","is_error":false}]},"uuid":"decf9331-67dd-4be5-b003-5d57ee538984","timestamp":"2026-06-11T22:06:08.364Z","toolUseResult":{"stdout":"/boot/config/plugins/varaverk/Orchestrators/intermediate_sync_maintenance.sh\n/boot/config/plugins/varaverk/Orchestrators/weekly_sync_maintenance.sh\n/boot/config/plugins/varaverk/Orchestrators/daily_sync_maintenance.sh","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"24c1b169-562a-4f8b-bd99-06e91573d336","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"decf9331-67dd-4be5-b003-5d57ee538984","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_015HtE4iovriqpHB7mwD3y7p","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_01HJfYY6Q1cmfXBgxcf1HNSP","name":"Bash","input":{"command":"grep -r \"Shares (\" /boot/config/plugins/varaverk --include=\"*.sh\" -l","description":"Find script producing Shares output"},"caller":{"type":"direct"}}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":2,"cache_creation_input_tokens":252,"cache_read_input_tokens":42568,"output_tokens":247,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":252,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":2,"output_tokens":247,"cache_read_input_tokens":42568,"cache_creation_input_tokens":252,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":252},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxEQYtkPWVGb4figzzTt","type":"assistant","uuid":"6dc8566a-07ef-47f6-94a0-cd32d5dd6782","timestamp":"2026-06-11T22:06:08.485Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"6dc8566a-07ef-47f6-94a0-cd32d5dd6782","isSidechain":false,"promptId":"8c57c845-2fc6-4731-92d4-b8ef5a0b7fb3","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_01HJfYY6Q1cmfXBgxcf1HNSP","type":"tool_result","content":"/boot/config/plugins/varaverk/Orchestrators/daily_sync_maintenance.sh\n/boot/config/plugins/varaverk/Orchestrators/intermediate_sync_maintenance.sh","is_error":false}]},"uuid":"8317b715-7330-4a02-8a4e-26e1ddb4db1e","timestamp":"2026-06-11T22:06:09.059Z","toolUseResult":{"stdout":"/boot/config/plugins/varaverk/Orchestrators/daily_sync_maintenance.sh\n/boot/config/plugins/varaverk/Orchestrators/intermediate_sync_maintenance.sh","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"6dc8566a-07ef-47f6-94a0-cd32d5dd6782","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"8317b715-7330-4a02-8a4e-26e1ddb4db1e","isSidechain":false,"attachment":{"type":"task_reminder","content":[],"itemCount":0},"type":"attachment","uuid":"97b026b2-66cd-4fc4-9f83-cdb4d8f89087","timestamp":"2026-06-11T22:06:09.061Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"97b026b2-66cd-4fc4-9f83-cdb4d8f89087","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_01F9C2FE4QNemiLyMEimtCCb","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_011nxFUx5QGrVawkfqMEfoQc","name":"Bash","input":{"command":"find /boot/config/plugins/varaverk/Rsync -name \"*.sh\" | sort","description":"List rsync scripts"},"caller":{"type":"direct"}}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":1,"cache_creation_input_tokens":518,"cache_read_input_tokens":42820,"output_tokens":94,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":518,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":1,"output_tokens":94,"cache_read_input_tokens":42820,"cache_creation_input_tokens":518,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":518},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxEQxCTkjGGBoKZcQoKC","type":"assistant","uuid":"f9d4db23-bcd2-4c40-b289-9fae4518f9d4","timestamp":"2026-06-11T22:06:11.460Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"f9d4db23-bcd2-4c40-b289-9fae4518f9d4","isSidechain":false,"promptId":"8c57c845-2fc6-4731-92d4-b8ef5a0b7fb3","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_011nxFUx5QGrVawkfqMEfoQc","type":"tool_result","content":"/boot/config/plugins/varaverk/Rsync/rsync.sh","is_error":false}]},"uuid":"fcb8cb52-9eaf-4719-8397-e1231b89d32b","timestamp":"2026-06-11T22:06:12.009Z","toolUseResult":{"stdout":"/boot/config/plugins/varaverk/Rsync/rsync.sh","stderr":"","interrupted":false,"isImage":false,"noOutputExpected":false},"sourceToolAssistantUUID":"f9d4db23-bcd2-4c40-b289-9fae4518f9d4","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"fcb8cb52-9eaf-4719-8397-e1231b89d32b","isSidechain":false,"message":{"model":"claude-sonnet-4-6","id":"msg_01UMTUYjwmjgsJreV4qMKBov","type":"message","role":"assistant","content":[{"type":"tool_use","id":"toolu_019gVN1b9MbS3VbR5sxG4Rmf","name":"Read","input":{"file_path":"/boot/config/plugins/varaverk/Rsync/rsync.sh"},"caller":{"type":"direct"}}],"stop_reason":"tool_use","stop_sequence":null,"stop_details":null,"usage":{"input_tokens":1,"cache_creation_input_tokens":124,"cache_read_input_tokens":43338,"output_tokens":71,"server_tool_use":{"web_search_requests":0,"web_fetch_requests":0},"service_tier":"standard","cache_creation":{"ephemeral_1h_input_tokens":124,"ephemeral_5m_input_tokens":0},"inference_geo":"not_available","iterations":[{"input_tokens":1,"output_tokens":71,"cache_read_input_tokens":43338,"cache_creation_input_tokens":124,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":124},"type":"message"}],"speed":"standard"},"diagnostics":null},"requestId":"req_011CbxERAnkBTD5Vs2HVL1u9","type":"assistant","uuid":"08c81a80-23bd-4cc1-8682-f2ae61d336b9","timestamp":"2026-06-11T22:06:13.828Z","userType":"external","entrypoint":"cli","cwd":"/root","sessionId":"e3c50283-9cfd-4062-a4e7-213e0884cdac","version":"2.1.170","gitBranch":"HEAD"} {"parentUuid":"08c81a80-23bd-4cc1-8682-f2ae61d336b9","isSidechain":false,"promptId":"8c57c845-2fc6-4731-92d4-b8ef5a0b7fb3","type":"user","message":{"role":"user","content":[{"tool_use_id":"toolu_019gVN1b9MbS3VbR5sxG4Rmf","type":"tool_result","content":"1\t#!/bin/bash\n2\t# ==============================================================================================\n3\t# ============================= Rsync Core Script ==============================================\n4\t# ==============================================================================================\n5\t#\n6\t# PURPOSE\n7\t# ─────────────────────────────────────────────────────────────────────────────\n8\t# Core rsync engine for the two-server ecosystem. Called per share or per\n9\t# appdata profile by orchestrators (daily_sync_maintenance, weekly_sync_maintenance,\n10\t# critical_sync_maintenance) and directly for manual or scheduled dirty syncs.\n11\t#\n12\t# Profile is inferred from the directory basename (lowercased). Override with\n13\t# --profile=name for explicit selection. If no profile matches, global defaults\n14\t# from master.conf apply and no containers are stopped.\n15\t#\n16\t# After each sync, logs transfer data to bandwidth_monitor.sh for the weekly\n17\t# bandwidth report. Silent on success — only failures produce visible output.\n18\t#\n19\t# ==============================================================================================\n20\t# OPERATIONAL MODEL\n21\t# ==============================================================================================\n22\t#\n23\t# Profiles define per-share behavior:\n24\t# PROFILE_CRITICAL_CONTAINER_NAMES — containers stopped on both servers before sync\n25\t# PROFILE_DELAYED_CONTAINERS — containers with a delay before restart after sync\n26\t# PROFILE_CONTAINER_DELAY — seconds before delayed containers start\n27\t# PROFILE_RSYNC_OPTS — rsync flags (does not inherit DEFAULT_RSYNC_OPTS)\n28\t# PROFILE_BW_LIMIT — bandwidth limit in KB/s\n29\t# PROFILE_RETRY_COUNT — retry attempts on failure\n30\t# PROFILE_SLEEP — seconds between retry attempts\n31\t# PROFILE_EXCLUDE_DIRS — paths excluded from transfer\n32\t# PROFILE_REMOTE_RESTART_CONTAINERS — containers restarted on remote after dirty sync\n33\t# Was running → restart. Was stopped → leave stopped.\n34\t#\n35\t# Two-tier rsync enable/disable:\n36\t# Tier 1: RSYNC_ENABLED=false → all rsync stops immediately (checked by this script)\n37\t# Tier 2: per-orchestrator flag (DAILY_RSYNC_ENABLED etc.) → checked by caller\n38\t#\n39\t# Bandwidth logging: after each sync, logs profile/duration/status/bytes to\n40\t# bandwidth_monitor.sh --log-transfer. Bytes captured from rsync --stats via awk\n41\t# using version-stable field names.\n42\t#\n43\t# ==============================================================================================\n44\t# OPERATIONAL SAFEGUARDS\n45\t# ==============================================================================================\n46\t#\n47\t# Global Rsync Gate\n48\t# check_rsync_enabled() — RSYNC_ENABLED=false exits cleanly before any operation.\n49\t#\n50\t# Partnership Blocklist\n51\t# Refuses to sync if REMOTE_SERVER_NAME appears in the partnership blocklist.\n52\t# Written at offboard — prevents stale access after a partnership ends.\n53\t#\n54\t# Version Parity\n55\t# check_unraid_version_parity — refuses sync if servers on incompatible unRAID versions.\n56\t#\n57\t# Remote Health Pre-flights\n58\t# check_connectivity() — Tailscale IP reachable before any SSH\n59\t# check_remote_rootfs() — aborts if remote rootfs exceeds ROOTFS_WARN_PCT\n60\t# check_remote_share() — aborts if target directory missing or empty on remote\n61\t# check_remote_disks() — verifies all backing disks online on remote\n62\t#\n63\t# Drive Temperature Check\n64\t# check_local_disk_temps() — runs before any transfer. Exit 1 = skip this profile,\n65\t# exit 2 = abort all remaining syncs (CRITICAL temperature).\n66\t#\n67\t# Remote Docker Daemon Check\n68\t# check_remote_docker_daemon — verified before any container stop/start operations.\n69\t# If daemon unresponsive: container operations skipped, rsync proceeds without stopping.\n70\t#\n71\t# Per-Profile Concurrency Lock\n72\t# acquire_rsync_lock() — per-profile lock prevents parallel runs of the same profile.\n73\t# Global concurrent limit prevents too many simultaneous rsync processes.\n74\t#\n75\t# Notification Validated\n76\t# platform_require_cmd confirms the notify script is present before use.\n77\t#\n78\t# ==============================================================================================\n79\t# CONFIGURATION\n80\t# ==============================================================================================\n81\t#\n82\t# master.conf\n83\t#\n84\t# RSYNC_ENABLED\n85\t# Global on/off toggle for all rsync operations. (default: true)\n86\t#\n87\t# DEFAULT_RSYNC_OPTS\n88\t# Base rsync flags for unproiled shares. Note: --delete is intentionally absent —\n89\t# media shares spread files only, arr cleanup scripts own deletions. Profile-specific\n90\t# opts set --delete explicitly where needed.\n91\t#\n92\t# BW_LIMIT\n93\t# Default bandwidth cap in KB/s when no PROFILE_BW_LIMIT is set. (default: 0 = unlimited)\n94\t#\n95\t# RETRY_COUNT\n96\t# Default retry attempts on rsync failure. (default: 3)\n97\t#\n98\t# SLEEP\n99\t# Default seconds between retry attempts. (default: 60)\n100\t#\n101\t# ROOTFS_WARN_PCT\n102\t# Abort threshold for remote rootfs percentage full. (default: 75)\n103\t#\n104\t# PROFILES[\"profile_KEY\"]\n105\t# Profile definitions — one entry per PROFILE_* key per profile name.\n106\t# See OPERATIONAL MODEL above for all supported keys.\n107\t#\n108\t# BANDWIDTH_LOG / BANDWIDTH_WARN_GB\n109\t# Shared with bandwidth_monitor.sh — set once, used by both.\n110\t#\n111\t# ==============================================================================================\n112\t# RUNTIME MODES\n113\t# ==============================================================================================\n114\t#\n115\t# rsync.sh /path/to/share\n116\t# Sync the given path to the remote. Profile inferred from directory basename.\n117\t#\n118\t# rsync.sh /path/to/share --profile=name\n119\t# Sync with explicit profile override — bypasses basename inference.\n120\t#\n121\t# rsync.sh /path/to/share --dry-run\n122\t# Run all pre-flight checks and show what rsync would transfer. No transfer,\n123\t# no container stops.\n124\t#\n125\t# rsync.sh /path/to/share --status\n126\t# Show resolved profile, remote identity, and configuration. Then exit.\n127\t#\n128\t# rsync.sh /path/to/share --log\n129\t# Verbose output throughout — every decision logged.\n130\t#\n131\t# ==============================================================================================\n132\t\n133\tSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\n134\t\n135\tsource \"$SCRIPT_DIR/../load_config.sh\"\n136\t\n137\t# ── Separate positional directory arg from flags ───────────────────────────────────────────────\n138\tDIRECTORY=\"\"\n139\tPROFILE_OVERRIDE=\"\"\n140\tRAW_ARGS=()\n141\t\n142\tfor ARG in \"$@\"; do\n143\t case \"$ARG\" in\n144\t --profile=*) PROFILE_OVERRIDE=\"${ARG#--profile=}\" ;;\n145\t --*|*=*) RAW_ARGS+=(\"$ARG\") ;;\n146\t *) [[ -z \"$DIRECTORY\" ]] && DIRECTORY=\"$ARG\" || RAW_ARGS+=(\"$ARG\") ;;\n147\t esac\n148\tdone\n149\t\n150\tparse_args \"${RAW_ARGS[@]}\"\n151\t\n152\t[[ -z \"$DIRECTORY\" ]] && {\n153\t error \"No directory specified\"\n154\t error \"Usage: rsync.sh