Skip to content

Instantly share code, notes, and snippets.

@The0x539
Created April 27, 2020 02:16
Show Gist options
  • Save The0x539/865479766e81132740deba6c8a10f361 to your computer and use it in GitHub Desktop.
Save The0x539/865479766e81132740deba6c8a10f361 to your computer and use it in GitHub Desktop.
# Sample output of 'mkvmerge -i file.mkv'
#
# File 'file.mkv': container: Matroska
# Track ID 0: video (MPEG-4p10/AVC/h.264)
# Track ID 1: audio (AAC)
# Track ID 2: subtitles (SubStationAlpha)
# Attachment ID 1: type 'application/x-truetype-font', size 53532 bytes, file name 'some_font.ttf'
# Chapters: 7 entries
function __fish_mkvextract_get_mode
set -l cmd (commandline -opc)
set -l skip_next 0
set -l mode
for arg in $cmd[2..-1]
test $skip_next = 1; and set skip_next 0; and continue
switch $arg
case tracks tags attachments chapters cuesheet timecodes_v2 cues
# Docs specify that an invocation can use multiple modes
# With that in mind, find the last one rather than returning now
set mode $arg
case --ui-language --command-line-charset --output-charset -r --redirect-output --ui-language --debug --engage -c --blockadd --simple-language
# Switches that are accompanied by a value
set skip_next 1
case -h --help -V --version --check-for-updates
# Switches that disable normal program behavior
return 1
end
end
if test $mode
echo $mode
return 0
else
return 1
end
end
function __fish_mkvextract_get_file
# According to mkvtoolnix docs, the source file should be argv[1]
# However, at the time of writing, other invocations, most notably `mkvextract tracks file.mkv ...`, are accepted
# In accordance with the robustness principle:
# - suggested completions will fullfil that expectation
# - parsing of the command line will not assume this to necessarily be true
set -l cmd (commandline -opc)
set -l skip_next 0
for arg in $cmd[2..-1]
test $skip_next = 1; and set skip_next 0; and continue
switch $arg
case tracks tags attachments chapters cuesheet timecodes_v2 cues -f --parse-fully --flush-on-close --abort-on-warnings --gui-mode -v --verbose -q --quiet --cuesheet --raw --fullraw -s --simple
# Switches that aren't accompanied by a value, but shouldn't be
continue
case '@*'
# JSON options files, specified to contain an array of string literals
# For maximum correctness, one might open the file and treat its contents as args
# In the context of tab completions, however, that seems almost out of scope
continue
case --ui-language --command-line-charset --output-charset -r --redirect-output --ui-language --debug --engage -c --blockadd --simple-language
# Switches that are accompanied by a value
set skip_next 1
case -h --help -V --version --check-for-updates
# Switches that disable normal program behavior
return 1
case '*'
# If we haven't found a filename yet, anything not matching the above patterns ought to be our input file
echo $arg
return 0
end
end
return 1
end
function __fish_mkvextract_using_mode
set -l mode (__fish_mkvextract_get_mode)
and contains -- $mode $argv
end
function __fish_mkvextract_no_mode
__fish_mkvextract_get_file
and not __fish_mkvextract_get_mode
end
function __fish_mkvextract_print_attachments
if set -l matroska (__fish_mkvextract_get_file)
if set -l info (mkvmerge -i $matroska)
string match 'Attachment ID*' -- $info | string replace -r '.*?(\d+).*? type \'(.*?)\'.*?file name \'(.*?)\'' '$1:\t$3 ($2)'
end
end
end
function __fish_mkvextract_print_tracks
set -l matroska (__fish_mkvextract_get_file)
or return 1 # No file
mkvmerge -q -i $matroska >/dev/null 2>/dev/null
or return 2 # Not a valid Matroska file (either nonexistent or wrong contents)
if type -q jq
# mkvmerge -J gives more information than mkvmerge -i
# mkvinfo also gives the information we'd need
# however, due to its format, the text manipulation necessary for what we're doing here would be... complicated
# introducing jq as an optional dependency makes things much easier
mkvmerge -J $matroska | jq -r ' .tracks[]
| .properties as $p
| (if $p.language == "und" then "" else "/"+$p.language end) as $lang
| (if $p.track_name then ": "+$p.track_name else "" end) as $name
| "\(.id):\t\(.type)\($lang)\($name) (\(.codec))"
'
else
mkvmerge -i $matroska | string match 'Track ID*' | string replace -r '.*?(\d+): (.*)' '$1:\t$2'
end
end
# simple options
complete -c mkvextract -s 'V' -l 'version' -f -d 'Show version information'
complete -c mkvextract -s 'h' -l 'help' -f -d 'Show help'
complete -c mkvextract -l 'check-for-updates' -f -d 'Check online for updates'
# once a file has been specified, no more are needed
complete -c mkvextract -n '__fish_mkvextract_get_file' -f
# extraction modes
complete -c mkvextract -n '__fish_mkvextract_no_mode' -k -a 'tracks'
complete -c mkvextract -n '__fish_mkvextract_no_mode' -k -a 'tags'
complete -c mkvextract -n '__fish_mkvextract_no_mode' -k -a 'attachments'
complete -c mkvextract -n '__fish_mkvextract_no_mode' -k -a 'chapters'
complete -c mkvextract -n '__fish_mkvextract_no_mode' -k -a 'cuesheet'
complete -c mkvextract -n '__fish_mkvextract_no_mode' -k -a 'timecodes_v2'
complete -c mkvextract -n '__fish_mkvextract_no_mode' -k -a 'cues'
# suggest tracks/attachments when appropriate
complete -c mkvextract -n '__fish_mkvextract_using_mode tracks timecodes_v2 cues' -a '(__fish_mkvextract_print_tracks)'
complete -c mkvextract -n '__fish_mkvextract_using_mode attachments' -a '(__fish_mkvextract_print_attachments)'
# these extraction modes have no parameters other than optional flags and the file
complete -c mkvextract -n '__fish_mkvextract_using_mode tags chapters cuesheet'
# general switches
complete -c mkvextract -s 'f' -l 'parse-fully' -d 'Parse the whole file instead of relying on the index'
complete -c mkvextract -s 'v' -l 'verbose' -d 'Increase verbosity'
complete -c mkvextract -s 'q' -l 'quiet' -d 'Suppress status output'
complete -c mkvextract -l 'ui-language' -r -d 'Force a locale'
complete -c mkvextract -l 'command-line-charset' -r -d 'Charset for strings on the command line'
complete -c mkvextract -l 'output-charset' -r -d 'Outputs messages in specified charset'
complete -c mkvextract -s 'r' -l 'redirect-output' -r -d 'Redirect all messages into a file' -F
complete -c mkvextract -l 'debug' -r -d 'Turn on debugging for a specific feature'
complete -c mkvextract -l 'engage' -r -d 'Turn on an experimental feature' -a '(mkvextract --engage list | tail -n+2)'
complete -c mkvextract -l 'gui-mode' -d 'Enable GUI mode'
complete -c mkvextract -l 'flush-on-close' -d 'Flush all cached data from memory when closing opened files'
complete -c mkvextract -l 'abort-on-warnings' -d 'Abort with exit code 1 after the first warning is emitted'
# track extraction switches
complete -c mkvextract -n '__fish_mkvextract_using_mode tracks' -s 'c' -r -d 'Convert text subtitles to a charset'
complete -c mkvextract -n '__fish_mkvextract_using_mode tracks' -l 'cuesheet' -d 'Also try to extract the CUE sheet'
complete -c mkvextract -n '__fish_mkvextract_using_mode tracks' -l 'blockadd' -r -d 'Keep only the BlockAdditions up to the specified level'
complete -c mkvextract -n '__fish_mkvextract_using_mode tracks' -l 'raw' -d 'Extract the data to a raw file'
complete -c mkvextract -n '__fish_mkvextract_using_mode tracks' -l 'fullraw' -d 'Extract the data to a raw file including the CodecPrivate as header'
# chapter extraction switches
complete -c mkvextract -n '__fish_mkvextract_using_mode chapters' -s 's' -l 'simple' -d 'Output chapter information as OGM instead of XML'
complete -c mkvextract -n '__fish_mkvextract_using_mode chapters' -l 'simple-language' -r -d 'Output only a specific language\'s chapter names'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment