#!/usr/bin/env bash # Subtitle fetch helper — recipe v1 Step 4. # # Single-episode loop body. Runs against a Jellyfin instance reachable from # nullstone via `docker exec jellyfin curl ...`. Driver loops should source or # call this per episode. # # Picker: highest DownloadCount among results that are NOT # (HearingImpaired|MachineTranslated|AiTranslated|Forced); 23.976fps preferred. # Falls back to all results if every candidate is HI/MT/AI/Forced. # # Side effects: # - POSTs RemoteSearch download (consumes 1 of 20 daily free-tier slots) # - docker cp's the resulting metadata-cache srt to MEDIA_DIR # # Caller env: # TOK Jellyfin admin X-Emby-Token # EP Jellyfin episode item id # MEDIA_DIR destination dir on nullstone, e.g. # '/home/user/media/tv/American Dad! (2005)/Season 01' # MEDIA_BASE filename without extension, must match the .mkv basename # # Exits non-zero on no-subs (1) or download HTTP != 204 (2). # Output to stdout: "OK -> ". # Output to stderr: chosen sub release name + fps + DownloadCount, or error. set -euo pipefail : "${TOK:?TOK required}" : "${EP:?EP required}" : "${MEDIA_DIR:?MEDIA_DIR required}" : "${MEDIA_BASE:?MEDIA_BASE required}" NULLSTONE="${NULLSTONE:-user@192.168.0.100}" RAW=$(ssh "$NULLSTONE" "docker exec jellyfin curl -s -H 'X-Emby-Token: $TOK' \ 'http://localhost:8096/Items/$EP/RemoteSearch/Subtitles/eng'") SUBID=$(printf '%s' "$RAW" | python3 -c " import json, sys subs = json.load(sys.stdin) clean = [s for s in subs if not (s.get('HearingImpaired') or s.get('MachineTranslated') or s.get('AiTranslated') or s.get('Forced'))] if not clean: clean = subs fps2398 = [s for s in clean if abs(s.get('FrameRate', 0) - 23.976) < 0.01] pool = fps2398 if fps2398 else clean pool.sort(key=lambda s: -s.get('DownloadCount', 0)) if pool: print(pool[0]['Id']) print(pool[0]['Name'], pool[0].get('FrameRate'), pool[0].get('DownloadCount'), file=sys.stderr) ") if [[ -z "$SUBID" ]]; then echo "NO-SUBS for $EP" >&2 exit 1 fi HTTP=$(ssh "$NULLSTONE" "docker exec jellyfin curl -s -o /dev/null -X POST \ -H 'X-Emby-Token: $TOK' \ 'http://localhost:8096/Items/$EP/RemoteSearch/Subtitles/$SUBID' \ -w '%{http_code}'") if [[ "$HTTP" != "204" ]]; then echo "DL-FAIL HTTP=$HTTP for $EP $SUBID" >&2 exit 2 fi SHARD="${EP:0:2}" SRC_IN_CONTAINER="/config/metadata/library/$SHARD/$EP/$MEDIA_BASE.eng.srt" DEST="$MEDIA_DIR/$MEDIA_BASE.eng.srt" ssh "$NULLSTONE" "docker cp \"jellyfin:$SRC_IN_CONTAINER\" \"$DEST\"" >/dev/null echo "OK $EP -> $DEST"