Version 3.1.6
soulsync 3.1.6 — dev → main
video downloads land atomically (the skipping-playback corruption fix), automations get custom webhook payloads + per-step conditions + new triggers under a full page redesign, discography ownership stops being source-locked, and file organization learns the "#" folder.
video files land safely (the big one)
reported: movies and episodes skipping during playback like they're corrupted.
- downloads were copied straight to their final library filename — so for a multi-GB copy over SMB, plex/jellyfin could index a half-written file (playback then skips even after the copy finished), and an interrupted copy left a permanently truncated file that looked complete
- files now land under a hidden temp name, get their byte count verified (a silently-short SMB copy is refused), and appear at their real name in one atomic rename — the media server either sees the whole file or nothing
- moves never delete the source until the destination is proven whole, and a crash mid-copy leaves nothing at the final name, so retried imports actually re-copy instead of blessing a half-file
- same guarantee the music side has had for ages; youtube downloads already did this — the main movie/TV path was the holdout
automations, next level
- custom webhook payload templates: write the exact JSON your service wants (gotify, ntfy, slack, home assistant) with {variable} tags — or raw text. broken templates degrade to the default body instead of dropping the notification
- per-step conditions: "only ping discord when status is error" — every THEN step gets an optional gate
- new condition operators: not equals, ends with, and numeric greater/less-than
- a send-test button on every notification step — fire it with sample data, see ✓ or the error inline
- timezone-aware schedules (daily/weekly/monthly all honor a per-automation tz now), monthly schedules finally configurable on music with real countdowns, THEN cap raised to 5
- new triggers: music maintenance finding raised / scan done (parity with video), video release grabbed (sonarr's on-grab — fires at grab time with the release name), request filed and request approved
- builder bug sweep: proper labels everywhere (no more raw snake_case), the hub deploy prompt gained the webhook channel, cards show a last-run summary
automations page redesign
- one uniform card language on both sides: status rail with a live pulsing orb, color-coded WHEN → DO → THEN pipeline chips, quiet ghost controls, live progress with a terminal-style log
- command strip with stat chips + the master switch, refined section headers, rebuilt builder canvas with glowing drop slots and stage badges
- pure reskin architecture: one stylesheet, zero markup/handler changes, fully revertable
cross-source ownership (#1071, thanks @QT3496)
- an album you own no longer shows missing just because the viewing source dates it differently (your files carry the 2014 remaster year, spotify's card says 1989) — when a card's id matches the enrichment id stored on your local album, that's identity proof and OWNED lights up
- structurally can't re-open the re-releases-as-owned bug: a different edition always has a different id
- "other sources" gap cards get real ownership checks too (each against its own source)
the "#" folder (#1072, thanks @QT3496)
- opt-in file-organization toggle: artists starting with digits, symbols, or non-latin scripts all sort into one "#" folder for $artistletter templates instead of one folder per character
- accented letters fold to their base letter (édith piaf → E/, the itunes/plex convention). off by default — nothing changes unless you flip it
- hardening that fell out of it: m3u entries can never start with "#" (players parse that as a comment and silently skip the track)
m3u portability (thanks wolf39us)
- new "path prefix rewrite" setting: generate playlists inside a container, play them anywhere — /data/media → M:/media hot-swapped on every entry at generation time. both fields empty = byte-identical output
video detail fixes
- episode action buttons (auto search / manual search / wishlist) never disappear behind a "✓ downloaded" badge anymore — status renders beside them, and only the auto-grab goes inert while a grab is actually in flight
- grab season / episode auto-grabs send the show poster along, so the downloads page shows real art instead of placeholder orbs
music video filing
- a music video downloaded from a fan channel files under the real artist parsed from the video title, not the uploader's channel name — the metadata-match fallback now covers the empty-results case that used to skip it
internal
- dropped a 160-line double-pasted block from wishlist-tools.js found by a strict syntax sweep across every static file