Skip to content

Instantly share code, notes, and snippets.

@konfou
Last active May 10, 2024 02:33
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save konfou/05db32e11ee84efde0adba2ac34331f4 to your computer and use it in GitHub Desktop.
Save konfou/05db32e11ee84efde0adba2ac34331f4 to your computer and use it in GitHub Desktop.
extract all tracks/attachments/chapters from an mkv file
#!/usr/bin/env bash
#
# Extract all tracks/attachments/chapters from an mkv file.
# depends
type -p mkvmerge &>/dev/null || exit 3
type -p mkvextract &>/dev/null || exit 3
# trap SIGINT
trap 'trap - INT; kill -s INT "$$"' INT
get_ext() {
# get_ext <mime>
# TODO: actually make it useful
case $1 in
MPEG-4p10/AVC/h.264) echo mp4;;
FLAC) echo flac;;
SubStationAlpha) echo ass;;
esac
}
tracks() {
# tracks <src-file> <track>
grep "$2" ${info} | while read line; do
id=$(echo ${line} | egrep -o '[0-9]*' | head -1)
ext=$(get_ext "$(echo ${line} | egrep -o '\((.*?)\)' | tr -d '()')")
mkvextract tracks "$1" ${id}:"${dest}/track_${id}.${ext}"
done
}
attachments() {
# attachments <src-file>
grep Attachment ${info} | while read line; do
id=$(echo ${line} | egrep -o '[0-9]*' | head -1)
name=$(echo ${line} | awk -F, '{ print $NF }' | egrep -o "'.*?'" | tr -d \')
mkvextract attachments "$1" ${id}:"${dest}/${name}"
done
}
chapters() {
# chapters <src-file>
mkvextract chapters "$1" > "${dest}/chapters.xml"
}
file() {
dest="${1/.mkv/}"
mkdir -p "${dest}"
mkvmerge -i "$1" > ${info}
while getopts ":adstc" opt ${@:2}; do
case ${opt} in
a) tracks "$1" "audio" ;;
d) tracks "$1" "video" ;;
s) tracks "$1" "subtitles" ;;
t) attachments "$1" ;;
c) chapters "$1" ;;
esac
done
}
usage() {
cat <<EOF
$(basename $0) <mode> <source> [options]
Usage:
$(basename $0) --file/-f <inname> extract from <inname> file
$(basename $0) --dir/-d <inname> extract from all files in <inname>
$(basename $0) --all same thing as doing --dir .
Extract options:
-a audio
-v video
-s subtitles
-t attachments
-c chapters
Example:
# extract all subs/attachments/chapters in ./file/ for all files in folder
$(basename $0) --all -stc
EOF
}
main() {
info=$(mktemp)
case $1 in
--file|-f) file "$2" "${@:3}" ;;
--dir|-d)
find "$2" -type f -name '*.mkv' | while read f; do
file "$f" "${@:3}"
done ;;
--all) main --dir . "${@:2}" ;;
*) usage ;;
esac
rm ${info}
}
main "$@"
@vicokoby
Copy link

vicokoby commented Aug 8, 2019

Chapter ( -t ) option doesn't work with mkvextract v35.0.0
$(basename $0) --all -stc doesn't work either

@pcroland
Copy link

It's very inefficient. If I want to demux a 40GB file for 5 subtitles it will read the file 5 times.

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