Skip to content

Instantly share code, notes, and snippets.

@adamscybot
Last active April 25, 2025 23:06
Show Gist options
  • Save adamscybot/11160665643e41f362894222a5e9fec6 to your computer and use it in GitHub Desktop.
Save adamscybot/11160665643e41f362894222a5e9fec6 to your computer and use it in GitHub Desktop.
"LG+Sonos" optimized pipeline. Conditionally does non, either or both of: 1) Transcodes audio codecs that are incompatible with Sonos. 2) If input contains DV profile 8, but container is not mp4, changes container to mp4 such that DV will work on LG for this file -- ONLY if it comes at no cost to anything else (e.g. subs, audio)
#!/bin/bash
set -euo pipefail
INPUT_FILE="$1"
DEST_DIR="$2"
DRY_RUN="${3:-false}"
LOG_FILE="$DEST_DIR/convert.log"
mkdir -p "$DEST_DIR"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
run_cmd() {
log "$1"
if [[ "$DRY_RUN" != "true" ]]; then
eval "$1"
fi
}
if [[ ! -f "$INPUT_FILE" ]]; then
log "ERROR: Input file does not exist: $INPUT_FILE"
exit 1
fi
log "LG+Sonos Optimize: $INPUT_FILE"
# Get container format
CONTAINER=$(ffprobe -v error -select_streams v:0 -show_entries format=format_name -of default=noprint_wrappers=1:nokey=1 "$INPUT_FILE")
# Get video codec
VIDEO_CODEC=$(ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$INPUT_FILE")
# Get Dolby Vision profile
DV_PROFILE=$(dovi_tool info "$INPUT_FILE" 2>/dev/null | grep -oP 'profile: \K\d+(\.\d+)?' || echo "none")
# Get audio codec
AUDIO_CODEC=$(ffprobe -v error -select_streams a:0 -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 "$INPUT_FILE")
# Get subtitle codecs
SUBTITLE_CODECS=$(ffprobe -v error -select_streams s -show_entries stream=codec_name -of csv=p=0 "$INPUT_FILE" | sort -u)
log "Container: $CONTAINER"
log "Video codec: $VIDEO_CODEC"
log "Audio codec: $AUDIO_CODEC"
log "Subtitle codecs: $SUBTITLE_CODECS"
log "Dolby Vision profile: $DV_PROFILE"
# Analyze subtitles
SUBS_OK=true
if echo "$SUBTITLE_CODECS" | grep -qvE '^(subrip|srt)$'; then
SUBS_OK=false
fi
# Analyze video and DV profile
VIDEO_HAS_LG_COMPAT_DV=true
if [[ "$VIDEO_CODEC" != "hevc" ]] || [[ "$DV_PROFILE" != "8.1" ]]; then
VIDEO_HAS_LG_COMPAT_DV=false
fi
# Analyze audio compatibility
AUDIO_TARGET="$AUDIO_CODEC"
NEEDS_AUDIO_TRANSCODE=false
if echo "$AUDIO_CODEC" | grep -qE '^(dts|dts_hd_ma|flac|opus)$'; then
AUDIO_TARGET="eac3"
NEEDS_AUDIO_TRANSCODE=true
fi
# Check if planned audio codec is MP4 compatible
AUDIO_MP4_COMPATIBLE=false
if echo "$AUDIO_TARGET" | grep -qE '^(aac|ac3|eac3)$'; then
AUDIO_MP4_COMPATIBLE=true
fi
BASENAME=$(basename "$INPUT_FILE")
EXTENSION="${BASENAME##*.}"
BASENAME_NOEXT="${BASENAME%.*}"
FFMPEG_CMD="ffmpeg -hide_banner -y -i \"$INPUT_FILE\" -map 0 -c:v copy"
# Logging audio plan
log "❓Plan operations to make audio compatible with Sonos?"
[[ "$NEEDS_AUDIO_TRANSCODE" == "true" ]] && log " ❌ Audio codec $AUDIO_CODEC incompatible with Sonos Arc" || log " ✅ Audio codec $AUDIO_CODEC is compatible with Sonos Arc"
[[ "$NEEDS_AUDIO_TRANSCODE" == "true" ]] && log "➡️ Audio will be converted to $AUDIO_TARGET" || log "➡️ $AUDIO_CODEC will be retained"
# Setup audio stream
if [[ "$NEEDS_AUDIO_TRANSCODE" == "true" ]]; then
FFMPEG_CMD+=" -c:a $AUDIO_TARGET -b:a 1024k"
else
FFMPEG_CMD+=" -c:a copy"
fi
# Logging decisions
log "❓Plan operations to make video Dolby Vision compatible with LG TVs?"
[[ "$CONTAINER" != "mp4" ]] && log " ✅ Not already MP4" || log " ❌ Already MP4. No need to swap."
[[ "$SUBS_OK" == "true" ]] && log " ✅ Subtitles OK (only SRT)" || log " ❌ Subtitles $SUBTITLE_CODECS not compatible inside MP4. Priorising retaining subs."
[[ "$VIDEO_HAS_LG_COMPAT_DV" == "true" ]] && log " ✅ Video codec HEVC and DV profile 8.1" || log " ❌ Video codec and/or DV profile incompatible (regardless of if we change to mp4)"
[[ "$AUDIO_MP4_COMPATIBLE" == "true" ]] && log " ✅ Audio codec $AUDIO_TARGET compatible with MP4" || log " ❌ Audio codec $AUDIO_TARGET not compatible with MP4, but is compatible with Sonos. Audio quality prioritised."
# Decide output container
if [[ "$CONTAINER" != "mp4" ]] && [[ "$SUBS_OK" == "true" ]] && [[ "$VIDEO_HAS_LG_COMPAT_DV" == "true" ]] && [[ "$AUDIO_MP4_COMPATIBLE" == "true" ]]; then
log "➡️ Container will be converted to MP4 for Dolby Vision LG Compat"
OUTPUT_FILE="$DEST_DIR/${BASENAME_NOEXT}.mp4"
FFMPEG_CMD+=" -c:s mov_text"
log "Planned output container: MP4"
else
[[ "$VIDEO_HAS_LG_COMPAT_DV" == "true" ]] && log " ➡️ Container will stay as MKV even though video track has DV that could be made to be LG compat via MP4. Prioritising other factors." || log " ➡️ Container will stay as MKV as no value in changing it (no DV compat gains)"
OUTPUT_FILE="$DEST_DIR/${BASENAME_NOEXT}.mkv"
log "Planned output container: MKV"
FFMPEG_CMD+=" -c:s copy"
fi
# Handle no-transcode, MKV direct copy
if [[ "$OUTPUT_FILE" == *".mkv" ]] && [[ "$NEEDS_AUDIO_TRANSCODE" == "false" ]]; then
log "✨ No actions needed. Copying file directly."
run_cmd "cp \"$INPUT_FILE\" \"$OUTPUT_FILE\""
exit 0
fi
FFMPEG_CMD+=" \"$OUTPUT_FILE\""
log "✨ Performing actions, starting ffmpeg..."
run_cmd "$FFMPEG_CMD"
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment