Skip to content

Instantly share code, notes, and snippets.

@o770
Last active October 19, 2024 01:29
Show Gist options
  • Save o770/98b00f5c54e4e134310834e67838b1fa to your computer and use it in GitHub Desktop.
Save o770/98b00f5c54e4e134310834e67838b1fa to your computer and use it in GitHub Desktop.
Run MPV with optional MPV profiles on a set of files found with GNU Find.

MPVF is a Bash script that runs MPV with optional MPV profiles on a set of files found with GNU Find by including and excluding shell patterns and setting the depth levels in the directory tree. Search patterns and directories are entered on the command line or in the script. File names can also be matched against an optional list of file extensions. With no options entered, the script's defaults are used.

Usage
mpvf {[<mpv profile,...>] [-a <pattern>] [-e <pattern>] [-i <pattern>] [-n <levels>] [-x <levels>] [directory...] | --help | --version}

Options
<mpv profile,...>
Name of the MPV profile to use.

-a, --alt <pattern>
-e, --exc <pattern>
-i, --inc <pattern>
GNU Find -ipath option. Compares the entered shell pattern, to which an asterisk will be appended before and after, with the entire filename starting from the highest directory entered. With the script's -a option, a filename must contain at least one match of the entered patterns. With the -e option, a file match is excluded from the search results, while with the -i option it is included. Case distinctions are ignored. Due to the added special pattern character that matches any string including the null string, matching leading and trailing characters in file names is not always effective with the entered patterns.

-n, --min <levels>
-x, --max <levels>
GNU Find options -maxdepth and -mindepth. The search starts in directories a minimum number of levels away with the script's -n option and descends into directories a maximum number of levels away with the -x option.

--help
Print a summary of the command-line usage of MPVF and exit.

--version
Print the MPVF version number and exit.

Dependencies
GNU Bourne-Again SHell (Bash)
GNU Coreutils
GNU Findutils (find)
GNU Grep
mpv

Changes in the last revision:
- Added search with default patterns.
- Various code improvements.

#!/bin/bash
# MPVF - run MPV with optional MPV profiles on a set of files found with GNU Find
# Version 0.7
# Values in parentheses that exist as a directory will be displayed and searched
# if no directory is entered on the command line. A pathname must be enclosed in
# quotes if it contains whitespace.
#default_directories+=(/home/user/Videos/Dir1 "/home/user/Videos/Dir 2")
# Values in parentheses will be displayed and used as search patterns in the -a
# option if none are entered on the command line. With whitespace, the pattern
# must be enclosed in quotes.
#default_patterns+=(Earth "Infinite Blue")
# Pipe-separated filename extensions. Uncomment to have the file search only match
# names ending with these extensions, ignoring case distinctions.
#file_extensions=".3g2|.3gp|.asf|.avi|.flv|.f4v|.gif|.m4v|.mkv|.mov|.mp4|.m4v|.mpg|.mpeg|.MTS|.M2TS|.TS|.ogv|.ogg|.rm|.rmvb|.vob|.webm|.wmv"
# SORT command line for file sorting. If not set, defaults are used.
#file_sorting=(sort -R)
scp="$(basename "$0")"
hver() {
cat << '_EOF_'
mpvf 0.7
Unlicense <http://unlicense.org/>
This is free and unencumbered software released into the public domain and
provided without warranty of any kind.
_EOF_
}
hman() {
cat << '_EOF_'
MPVF - run MPV with optional MPV profiles on a set of files found with GNU Find
SYNOPSIS
mpvf {[<mpv profile,...>] [-a <pattern>] [-e <pattern>] [-i <pattern>]
[-n <levels>] [-x <levels>] [directory...] | --help | --version}
DESCRIPTION
MPVF is a Bash script that runs MPV with optional MPV profiles on a set of files
found with GNU Find by including and excluding shell patterns and setting the
depth levels in the directory tree. Search patterns and directories are entered
on the command line or in the script. File names can also be matched against an
optional list of file extensions. With no options entered, the script's defaults
are used.
OPTIONS
<mpv profile,...>
Name of the MPV profile to use.
-a, --alt <pattern>
-e, --exc <pattern>
-i, --inc <pattern>
GNU Find -ipath option. Compares the entered shell pattern, to which an asterisk
will be appended before and after, with the entire filename starting from the
highest directory entered. With the script's -a option, a filename must contain
at least one match of the entered patterns. With the -e option, a file match is
excluded from the search results, while with the -i option it is included. Case
distinctions are ignored. Due to the added special pattern character that matches
any string including the null string, matching leading and trailing characters in
file names is not always effective with the entered patterns.
-n, --min <levels>
-x, --max <levels>
GNU Find options -maxdepth and -mindepth. The search starts in directories a
minimum number of levels away with the script's -n option and descends into
directories a maximum number of levels away with the -x option.
--help
Print a summary of the command-line usage of MPVF and exit.
--version
Print the MPVF version number and exit.
DEPENDENCIES
GNU Bourne-Again SHell (Bash)
GNU Coreutils
GNU Findutils (find)
GNU Grep
mpv
_EOF_
}
swdep() {
type grep >/dev/null 2>&1 || { echo >&2 "${scp}: GREP not found - aborting." ; exit ; }
type mpv >/dev/null 2>&1 || { echo >&2 "${scp}: MPV not found - aborting." ; exit ; }
type find >/dev/null 2>&1 || { echo >&2 "${scp}: GNU Find not found - aborting." ; exit ; }
}
addressing() {
if [ -v ifile ] ; then
for i in "${ifile[@]}" ; do
if [ -d "$i" ] ; then
idir+=("$i")
fi
done
else
if [ -v default_directories ] ; then
for i in "${default_directories[@]}" ; do
if [ -d "$i" ] ; then
idir+=("$i")
fi
done
if [ -v idir ] ; then
echo "${scp}: Search directories: ${idir[*]@Q}"
fi
fi
fi
}
searching() {
if [ -v file_extensions ] ; then
if [ -v depth ] ; then
readarray -t isch < <(find "${idir[@]}" "${depth[@]}" "${apat[@]}" -type f | grep -iE '.*('"${file_extensions}"')$' | "${file_sorting[@]:-sort}")
else
readarray -t isch < <(find "${idir[@]}" "${apat[@]}" -type f | grep -iE '.*('"${file_extensions}"')$' | "${file_sorting[@]:-sort}")
fi
else
if [ -v depth ] ; then
readarray -t isch < <(find "${idir[@]}" "${depth[@]}" "${apat[@]}" -type f | "${file_sorting[@]:-sort}")
else
readarray -t isch < <(find "${idir[@]}" "${apat[@]}" -type f | "${file_sorting[@]:-sort}")
fi
fi
}
playing() {
if [ -n "${isch[0]}" ] ; then
echo "${scp}: Starting mpv..."
if [ -v prf ] ; then
mpv --profile="$prf" "${isch[@]}"
else
mpv "${isch[@]}"
fi
else
echo "${scp}: No files found matching pattern criteria - exiting..."
fi
}
swdep
iall+=("$@")
for arg in "${iall[@]}" ; do
iter=$((iter + 1))
if [ "${itersk:-0}" -ne "$iter" ] ; then
if [ '--help' = "$arg" ] ; then
eop+=(help)
elif [ '--version' = "$arg" ] ; then
eop+=(version)
elif [ '-e' = "$arg" ] || [ '--exc' = "$arg" ] ; then
itersk=$((iter + 1))
wpat+=('!' -ipath '*'"${iall[$iter]}"'*')
elif [ '-i' = "$arg" ] || [ '--inc' = "$arg" ] ; then
itersk=$((iter + 1))
wpat+=(-ipath '*'"${iall[$iter]}"'*')
elif [ '-a' = "$arg" ] || [ '--alt' = "$arg" ] ; then
itersk=$((iter + 1))
itera=$((itera + 1))
if [ "$itera" -eq 1 ] ; then
opat+=(-ipath '*'"${iall[$iter]}"'*')
else
opat+=(-o -ipath '*'"${iall[$iter]}"'*')
fi
elif [ '--min' = "$arg" ] || [ '-n' = "$arg" ] ; then
itersk=$((iter + 1))
if [ ! -v min ] ; then
if grep -qE '^(0|[1-9]\d*)$' <<< "${iall[$iter]}" ; then
depth+=(-mindepth "${iall[$iter]}")
min=yes
else
eop+=(min)
fi
else
iop+=(min)
iopmin="${iall[$iter]}"
fi
elif [ '--max' = "$arg" ] || [ '-x' = "$arg" ] ; then
itersk=$((iter + 1))
if [ ! -v max ] ; then
if grep -qE '^(0|[1-9]\d*)$' <<< "${iall[$iter]}" ; then
depth+=(-maxdepth "${iall[$iter]}")
max=yes
else
eop+=(max)
fi
else
iop+=(max)
iopmax="${iall[$iter]}"
fi
elif [ -e "$arg" ] ; then
shift $((iter - 1))
ifile+=("$@")
break
else
if [ ! -v prf ] ; then
prf="$arg"
else
iop+=(prf)
iopprf="$arg"
fi
fi
fi
done
unset iter
if [ ! -v eop ] ; then
if [ -v iop ] ; then
for i in "${iop[@]}" ; do
if [ 'max' = "$i" ] ; then
echo >&2 "${scp}: Maximum depth is already defined - ignoring: $iopmax"
elif [ 'min' = "$i" ] ; then
echo >&2 "${scp}: Minimum depth is already defined - ignoring: $iopmin"
elif [ 'prf' = "$i" ] ; then
echo >&2 "${scp}: MPV profile is already defined - ignoring: $iopprf"
fi
done
fi
if [ -v wpat ] || [ -v opat ] ; then
if [ ! -v opat ] ; then
apat+=(\( "${wpat[@]}" \))
elif [ ! -v wpat ] ; then
apat+=(\( "${opat[@]}" \))
else
apat+=(\( "${wpat[@]}" \) \( "${opat[@]}" \))
fi
addressing
if [ -v idir ] ; then
echo "${scp}: Searching..."
searching
playing
else
echo "${scp}: No search directories - aborting."
fi
else
if [ -v default_patterns ] ; then
echo "${scp}: Search patterns: ${default_patterns[*]@Q}"
for i in "${default_patterns[@]}" ; do
iterdp=$((iterdp + 1))
if [ "$iterdp" -ne 1 ] ; then
opat+=(-o -ipath '*'"$i"'*')
else
opat+=(-ipath '*'"$i"'*')
fi
done
unset iterdp
apat+=(\( "${opat[@]}" \))
addressing
if [ -v idir ] ; then
echo "${scp}: Searching..."
searching
playing
else
echo "${scp}: No search directories - aborting."
fi
else
echo "${scp}: Usage: $scp {[<mpv profile,...>] [-a <pattern>] [-e <pattern>] [-i <pattern>] [-n <levels>] [-x <levels>] [directory...] | --help | --version}"
echo "${scp}: No search pattern - aborting."
fi
fi
else
for i in "${eop[@]}" ; do
if [ 'help' = "$i" ] ; then
hman
exit
elif [ 'version' = "$i" ] ; then
hver
exit
fi
done
if [ 'max' = "${eop[0]}" ] ; then
echo >&2 "${scp}: Non-fractional positive number expected in depth options - aborting."
elif [ 'min' = "${eop[0]}" ] ; then
echo >&2 "${scp}: Non-fractional positive number expected in depth options - aborting."
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment