Skip to content

Instantly share code, notes, and snippets.

@martinpickett
Created September 19, 2022 14:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinpickett/82236d7fcf96b32bea9ce9d13fe2ff64 to your computer and use it in GitHub Desktop.
Save martinpickett/82236d7fcf96b32bea9ce9d13fe2ff64 to your computer and use it in GitHub Desktop.
Displays track information for an MKV file. Requires FFprobe and jq.
#!/usr/bin/env bash
# Function which does almost everything. It needs to be a function as it is recursively
# called if the input is a directory.
main () {
for i in "$@"; do
# Check to see if input is valid
checkInput "$i"
# If input is not valid then skip to next iteration of for loop
if [ "$?" -ne 0 ]; then
continue
fi
# Print header
printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' -
printf '%s\n' "$i"
printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' -
# Generate and format information
json=$(ffprobe -v error -show_entries stream -print_format json=compact=1 "$i")
codex_type=$(echo "$json" | jq '(.streams[] | select(.codec_type=="video" or .codec_type=="audio" or .codec_type=="subtitle") | .codec_type) | @text' | sed 's/\"//g' | tr '\n' ' ')
index=$(echo "$json" | jq '(.streams[] | select(.codec_type=="video" or .codec_type=="audio" or .codec_type=="subtitle") | .index) | @text' | sed 's/\"//g' | tr '\n' ' ')
language=$(echo "$json" | jq '(.streams[] | select(.codec_type=="video" or .codec_type=="audio" or .codec_type=="subtitle") | .tags.language) | @text' | sed 's/\"//g' | tr '\n' ' ')
codec_name=$(echo "$json" | jq '(.streams[] | select(.codec_type=="video" or .codec_type=="audio" or .codec_type=="subtitle") | if .codec_type=="audio" and .profile then .profile else .codec_name end) | @text' | sed 's/\"//g' | tr '\n' ',')
channel_layout=$(echo "$json" | jq '(.streams[] | select(.codec_type=="video" or .codec_type=="audio" or .codec_type=="subtitle") | .channel_layout) | @text' | sed 's/\"//g' | sed 's/null/-/g' | tr '\n' ',')
bitrate=$(echo "$json" | jq '.streams[].tags | to_entries | .[] | if .key|test("BPS*") then .value else empty end | @text' | sed 's/\"//g' | tr '\n' ' ')
no_of_elements=$(echo "$json" | jq '.streams[].tags | to_entries | .[] | if .key|test("NUMBER_OF_FRAMES*") then .value else empty end | @text' | sed 's/\"//g' | tr '\n' ' ')
default_flag=$(echo "$json" | jq '(.streams[] | select(.codec_type=="video" or .codec_type=="audio" or .codec_type=="subtitle") | .disposition.default) | @text' | sed 's/\"//g' | tr '\n' ' ')
forced_flag=$(echo "$json" | jq '(.streams[] | select(.codec_type=="video" or .codec_type=="audio" or .codec_type=="subtitle") | .disposition.forced) | @text' | sed 's/\"//g' | tr '\n' ' ')
track_title=$(echo "$json" | jq '(.streams[] | select(.codec_type=="video" or .codec_type=="audio" or .codec_type=="subtitle") | .tags.title) | @text' | sed 's/\"//g' | sed 's/null/-/g' | tr '\n' ',')
# Store information in arrays
read -ra codex_type_a <<< "$codex_type"
read -ra index_a <<< "$index"
read -ra language_a <<< "$language"
IFS=',' read -ra codec_name_a <<< "$codec_name"
IFS=',' read -ra channel_layout_a <<< "$channel_layout"
read -ra bitrate_a <<< "$bitrate"
read -ra no_of_elements_a <<< "$no_of_elements"
read -ra default_flag_a <<< "$default_flag"
read -ra forced_flag_a <<< "$forced_flag"
IFS=',' read -ra track_title_a <<< "$track_title"
# Print information
table="TYPE,INDEX,LANGUAGE,CODEC,CHANNEL LAYOUT,BITRATE,NO OF ELEMENTS,DEFAULT,FORCED FLAG,TITLE \n"
num_tracks=${#codex_type_a[@]}
num_tracks_offset=$(($num_tracks-1))
for i in $( eval echo {0.."$num_tracks_offset"} )
do
table+="${codex_type_a[$i]},${index_a[$i]},${language_a[$i]},${codec_name_a[$i]},${channel_layout_a[$i]},${bitrate_a[$i]},${no_of_elements_a[$i]},${default_flag_a[$i]},${forced_flag_a[$i]},${track_title_a[$i]} \n"
done
echo -e "$table" | column -t -s ','
# Newline for formatting reasons
echo ""
done
}
# Function to check input validity. Returns 0 if valid, non-zero if not.
checkInput() {
# Check if input is a directory
# If it is look for mkv files in directory
if [ -d "$1" ]; then
for j in "$1"/*.mkv; do
if [ ! -f "$j" ]; then
echo "There are no mkv files in directory $1"
return 1
else
main "$j"
fi
done
continue
fi
# Check if input file exists
if [ ! -f "$1" ]; then
echo "Input file $1 does not exist."
return 1
fi
# Check input file is an mkv file
if [[ $1 != *.mkv ]]; then
echo "Input file $1 is not an mkv file. This script only supports mkv files."
return 1
fi
return 0
}
# Run main function
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment