Skip to content

Instantly share code, notes, and snippets.

@thornbill
Last active February 24, 2024 22:16
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save thornbill/eb97761472cd0285106a98c101eff962 to your computer and use it in GitHub Desktop.
Save thornbill/eb97761472cd0285106a98c101eff962 to your computer and use it in GitHub Desktop.
DVR post processing script for Jellyfin
#!/usr/bin/env bash
set -o errexit
set -o pipefail
set -o nounset
# set -o xtrace
PWD="$(pwd)"
die () {
echo >&2 "$@"
cd "${PWD}"
exit 1
}
# Colors
GREEN='\033[0;32m'
NC='\033[0m' # No Color
__path="${1:-}"
# verify a path was provided
[ -n "$__path" ] || die "path is required"
# verify the path exists
[ -f "$__path" ] || die "path ($__path) is not a file"
__dir="$(dirname "${__path}")"
__file="$(basename "${__path}")"
__base="$(basename "${__path}" ".ts")"
# Debbuging path variables
# printf "${GREEN}path:${NC} ${__path}\ndir: ${__dir}\nbase: ${__base}\n"
# Try to find local version of ffmpeg, defaults to the path used in docker if not found
__ffmpeg="$(which ffmpeg || echo '/usr/lib/jellyfin-ffmpeg/ffmpeg')"
# Change to the directory containing the recording
cd "${__dir}"
# Extract closed captions to external SRT file
printf "[post-process.sh] %bExtracting subtitles...%b\n" "$GREEN" "$NC"
$__ffmpeg -f lavfi -i movie="${__file}[out+subcc]" -map 0:1 "${__base}.srt"
# Transcode to mp4, crf parameter can be adjusted to change output quality
printf "[post-process.sh] %bTranscoding file..%b\n" "$GREEN" "$NC"
$__ffmpeg -i "${__file}" -vcodec libx264 -vf yadif=parity=auto -crf 20 -preset veryslow "${__base}.mp4"
# Remove the original recording file
printf "[post-process.sh] %bRemoving originial file...%b\n" "$GREEN" "$NC"
rm "${__file}"
# Return to the starting directory
cd "${PWD}"
@MapGuy11
Copy link

Any way to get the original file removed after the conversion is done.

@thornbill
Copy link
Author

@MapGuy11 👍 I have updated the script to remove the original file and added some comments about what each step is doing.

@MapGuy11
Copy link

Wow Thank you!

@CFusionMM
Copy link

i got a windows jellyfin server, would this work on that? I cant seem to get it working

@MapGuy11
Copy link

No , this script is linux based. If you are stuck on Windows use Windows Subsystem for Linux to install Jellyfin on Linux with Windows OS Install.

@Alucard316
Copy link

I whipped together a very quick and dirty windows version for myself, figured I'd link it here for people that stumble across this (like I did) but need it in Windows.

Windows DVR PostProcess Batch Script for Jellyfin

@tge101
Copy link

tge101 commented Apr 12, 2021

Any plans to add comskip?

@thornbill
Copy link
Author

It’s something that I have considered, but I haven’t had a chance to try it yet.

@Artiume
Copy link

Artiume commented Aug 30, 2021

Found this, might help debug the character ecaping issue

http://underpop.online.fr/f/ffmpeg/help/quoting-and-escaping.htm.gz

The function av_get_token defined in 'libavutil/avstring.h' can be used to parse a token quoted or escaped according to the rules defined above.

The tool 'tools/ffescape' in the FFmpeg source tree can be used to automatically quote or escape a string in a script.

@bwarden
Copy link

bwarden commented Sep 9, 2021

I found this awkward quoting process (inspiration from ffmpeg#5896) helped with normal escaping, plus the extra touches the filter parameter requires for single ticks (') and colons (:) in filenames for the subtitle extraction command:

$__ffmpeg -f lavfi -i movie="$(printf %q "${__file//\'/\\\'}" | sed "s#\:#\\\\\\\\:#")[out+subcc]" -map 0:1 "${__base}.srt"

I'm also poking at muxing to mkv instead of mp4, and detecting whether the incoming TS needs transcoding at all, or just remuxing:

+# Decide whether we need to transcode video or audio
+VCODEC=$(ffprobe -loglevel error -select_streams v -show_entries stream=codec_name -of default=nw=1:nk=1 "${__file}" | sort -u)
+ACODEC=$(ffprobe -loglevel error -select_streams a -show_entries stream=codec_name -of default=nw=1:nk=1 "${__file}" | sort -u)
+
+ENCODE_ARGS=""
+if [[ "$VCODEC" != "h264" ]]; then
+       ENCODE_ARGS="$ENCODE_ARGS -c:v libx264"
+else
+       ENCODE_ARGS="$ENCODE_ARGS -c:v copy"
+fi
+if [[ "$ACODEC" != "ac3" ]]; then
+       ENCODE_ARGS="$ENCODE_ARGS -c:a aac"
+else
+       ENCODE_ARGS="$ENCODE_ARGS -c:a copy"
+fi
 # Transcode to mp4, crf parameter can be adjusted to change output quality
 printf "[post-process.sh] %bTranscoding file..%b\n" "$GREEN" "$NC"
-$__ffmpeg -i "${__file}" -vcodec libx264 -vf yadif=parity=auto -crf 20 -preset veryslow "${__base}.mp4"
+$__ffmpeg -i "${__file}" -map 0 $ENCODE_ARGS "${__base}.mkv"

@wanghan0501
Copy link

However, ffprobe cannot be found @bwarden

@AndrewBreyen
Copy link

could be totally missing something, but how do you have this set in DVR settings? I keep getting an exit code of 1 in JF logs: set up like

Post-processing application:
/bin/bash
Post-processor command line arguments:
/Scripts/livetv_postprocess.sh {path}

@jwt4000
Copy link

jwt4000 commented Aug 19, 2023

Your script is awesome! Could you help me with the encode syntax to enable intel quick sync? I am unfortunately running Jellyfin on a lower powered CPU and QSV helps a ton. Thanks!!

@coldshouldermedia
Copy link

It’s something that I have considered, but I haven’t had a chance to try it yet.

Had a chance to try it out yet?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment