#!/usr/bin/env bash
-# Desc: Wrapper for mpv that accepts directory paths via posargs or stdin lines
+# Desc: Wrapper for mpv that accepts directory or file paths via posargs or stdin lines
# Usage: bkmpv2 [DIR]
-# Version: 0.0.1
+# Version: 0.1.0
# Depends: GNU Parallel, GNU Bash v5.1.16, mpv v0.34.1, bc v1.07.1
# Ref/Attrib: [1] Tange, Ole. GNU Parallel with Bash Array. 2019-03-24. https://unix.stackexchange.com/a/508365/411854
# Example: find $HOME/Music -type d | bkmpv2
# Example: bkmpv2 $HOME/Music/
+# Example: find $HOME -type f -name "*.mp3" | bkmpv2
# Note: Does not follow symlinks
# Find settings
# Input: global assoc. array 'appRollCall'
# Output: adds/updates key(value) to global assoc array 'appRollCall'
# Depends: bash 5.0.3
- local returnState
+ local returnState
#===Process Args===
for arg in "$@"; do
- if command -v "$arg" 1>/dev/null 2>&1; then # Check if arg is a valid command
- appRollCall[$arg]="true";
- if ! [ "$returnState" = "false" ]; then returnState="true"; fi;
- else
- appRollCall[$arg]="false"; returnState="false";
- fi;
+ if command -v "$arg" 1>/dev/null 2>&1; then # Check if arg is a valid command
+ appRollCall[$arg]="true";
+ if ! [ "$returnState" = "false" ]; then returnState="true"; fi;
+ else
+ appRollCall[$arg]="false"; returnState="false";
+ fi;
done;
#===Determine function return code===
if [ "$returnState" = "true" ]; then
- return 0;
+ return 0;
else
- return 1;
+ return 1;
fi;
} # Check that app exists
checkfile() {
#===Process Args===
for arg in "$@"; do
- if [ -f "$arg" ]; then
- fileRollCall["$arg"]="true";
- if ! [ "$returnState" = "false" ]; then returnState="true"; fi;
- else
- fileRollCall["$arg"]="false"; returnState="false";
- fi;
+ if [ -f "$arg" ]; then
+ fileRollCall["$arg"]="true";
+ if ! [ "$returnState" = "false" ]; then returnState="true"; fi;
+ else
+ fileRollCall["$arg"]="false"; returnState="false";
+ fi;
done;
-
+
#===Determine function return code===
if [ "$returnState" = "true" ]; then
- return 0;
+ return 0;
else
- return 1;
+ return 1;
fi;
} # Check that file exists
checkdir() {
#===Process Args===
for arg in "$@"; do
- if [ -d "$arg" ]; then
- dirRollCall["$arg"]="true";
- if ! [ "$returnState" = "false" ]; then returnState="true"; fi
- else
- dirRollCall["$arg"]="false"; returnState="false";
- fi
+ if [ -d "$arg" ]; then
+ dirRollCall["$arg"]="true";
+ if ! [ "$returnState" = "false" ]; then returnState="true"; fi
+ else
+ dirRollCall["$arg"]="false"; returnState="false";
+ fi
done
-
+
#===Determine function return code===
if [ "$returnState" = "true" ]; then
- return 0;
+ return 0;
else
- return 1;
+ return 1;
fi
} # Check that dir exists
displayMissing() {
# Depends: bash 5, checkAppFileDir()
local missingApps value appMissing missingFiles fileMissing
local missingDirs dirMissing
-
+
#==BEGIN Display errors==
#===BEGIN Display Missing Apps===
missingApps="Missing apps :";
#for key in "${!appRollCall[@]}"; do echo "DEBUG:$key => ${appRollCall[$key]}"; done
for key in "${!appRollCall[@]}"; do
- value="${appRollCall[$key]}";
- if [ "$value" = "false" ]; then
- #echo "DEBUG:Missing apps: $key => $value";
- missingApps="$missingApps""$key ";
- appMissing="true";
- fi;
+ value="${appRollCall[$key]}";
+ if [ "$value" = "false" ]; then
+ #echo "DEBUG:Missing apps: $key => $value";
+ missingApps="$missingApps""$key ";
+ appMissing="true";
+ fi;
done;
if [ "$appMissing" = "true" ]; then # Only indicate if an app is missing.
- echo "$missingApps" 1>&2;
+ echo "$missingApps" 1>&2;
fi;
unset value;
#===END Display Missing Apps===
missingFiles="Missing files:";
#for key in "${!fileRollCall[@]}"; do echo "DEBUG:$key => ${fileRollCall[$key]}"; done
for key in "${!fileRollCall[@]}"; do
- value="${fileRollCall[$key]}";
- if [ "$value" = "false" ]; then
- #echo "DEBUG:Missing files: $key => $value";
- missingFiles="$missingFiles""$key ";
- fileMissing="true";
- fi;
+ value="${fileRollCall[$key]}";
+ if [ "$value" = "false" ]; then
+ #echo "DEBUG:Missing files: $key => $value";
+ missingFiles="$missingFiles""$key ";
+ fileMissing="true";
+ fi;
done;
if [ "$fileMissing" = "true" ]; then # Only indicate if an app is missing.
- echo "$missingFiles" 1>&2;
+ echo "$missingFiles" 1>&2;
fi;
unset value;
#===END Display Missing Files===
missingDirs="Missing dirs:";
#for key in "${!dirRollCall[@]}"; do echo "DEBUG:$key => ${dirRollCall[$key]}"; done
for key in "${!dirRollCall[@]}"; do
- value="${dirRollCall[$key]}";
- if [ "$value" = "false" ]; then
- #echo "DEBUG:Missing dirs: $key => $value";
- missingDirs="$missingDirs""$key ";
- dirMissing="true";
- fi;
+ value="${dirRollCall[$key]}";
+ if [ "$value" = "false" ]; then
+ #echo "DEBUG:Missing dirs: $key => $value";
+ missingDirs="$missingDirs""$key ";
+ dirMissing="true";
+ fi;
done;
if [ "$dirMissing" = "true" ]; then # Only indicate if an dir is missing.
- echo "$missingDirs" 1>&2;
+ echo "$missingDirs" 1>&2;
fi;
unset value;
#===END Display Missing Directories===
#===Process Arg===
if [[ $# -ne 1 ]]; then
- die "ERROR:Invalid number of arguments:$#";
+ die "ERROR:Invalid number of arguments:$#";
fi;
-
+
RETEST1='^[0-9]+$'; # Regular Expression to test
if [[ ! $1 =~ $RETEST1 ]] ; then
- returnState="false";
+ returnState="false";
else
- returnState="true";
+ returnState="true";
fi;
#===Determine function return code===
if [ "$returnState" = "true" ]; then
- return 0;
+ return 0;
else
- return 1;
+ return 1;
fi;
} # Checks if arg is integer
read_stdin() {
# Store stdin
if [[ -p /dev/stdin ]]; then
input_stdin="$(cat -)";
- fi;
-
+ fi;
+
# Store as output array elements
## Read in stdin
if [[ -n $input_stdin ]]; then
# Depends: GNU bash (version 5.1.16)
# Version: 0.0.1
local input_psarg output;
-
+
# Store arguments
if [[ $# -gt 0 ]]; then
input_psarg="$*";
fi;
-
+
# Store as output array elements
## Read in positional arguments
if [[ -n $input_psarg ]]; then
# var: fc_redbase logarithm base to reduce output file count
local re_dotfile;
- declare -a dirs_stdin dirs_psarg;
+ declare -a files_stdin dirs_stdin dirs_psarg;
declare -a paths_files;
declare list_paths_files;
declare -a cmd_args;
re_dotfile="^\."; # first char is a dot
while read -r line; do
line="$(readlink -e "$line")";
- # Check if dir
- if [[ ! -d "$line" ]]; then
- echo "ERROR:Not a dir:$line" 1>&2;
+ line_bn="$(basename "$line")";
+ # Check if dir and not dotfile
+ if [[ -d "$line" ]] && [[ ! "$line_bn" =~ $re_dotfile ]]; then
+ dirs_stdin+=("$line");
continue;
fi;
- dir_name="$(basename "$line")";
- # Exclude dotdirs
- if [[ "$dir_name" =~ $re_dotfile ]]; then
- echo "ERROR:Is a dotdir:$line" 1>&2;
- continue
- fi;
- dirs_stdin+=("$line");
- done < <(read_stdin);
- yell "STATUS:$SECONDS:Read stdin.";
- ## Read positional arguments as lines
- re_dotfile="^\."; # first char is a dot
- while read -r line; do
- line="$(readlink -e "$line")";
- # Check if dir
- if [[ ! -d "$line" ]]; then
- echo "ERROR:Not a dir:$line" 1>&2;
+
+ # Check if file
+ if [[ -f "$line" ]]; then
+ files_stdin+=("$line");
continue;
fi;
- dir_name="$(basename "$line")";
- # Exclude dotdirs
- if [[ "$dir_name" =~ $re_dotfile ]]; then
- echo "ERROR:Is a dotdir:$line" 1>&2;
- continue
- fi;
- dirs_psarg+=("$line");
- done < <(read_psarg "$@");
- yell "STATUS:$SECONDS:Read posargs.";
-
+
+ # Throw warning
+ yell "WARNING:Not a valid dir or file:$line";
+ done < <( read_stdin; read_psarg "$@"; );
+ yell "STATUS:$SECONDS:Read stdin and psargs.";
+
# Catch all arrays empty
- if [[ "${#dirs_stdin[@]}" -le 0 ]] && [[ "${#dirs_psarg[@]}" -le 0 ]]; then
- die "FATAL:No valid directories provided.";
+ if [[ "${#dirs_stdin[@]}" -le 0 ]] && \
+ [[ "${#dirs_psarg[@]}" -le 0 ]] && \
+ [[ "${#files_stdin[@]}" -le 0 ]]; then
+ die "FATAL:No valid directories or files provided.";
fi;
# Generate file list
+ ## Add stdin argument input
+ if [[ "${#files_stdin[@]}" -gt 0 ]]; then
+ paths_files+=("${files_stdin[@]}");
+ fi;
+
## Call find_filelist() in parallel for positional argument input
if [[ "${#dirs_psarg[@]}" -gt 0 ]]; then
fdepth="$fdepth_posarg"; export fdepth; # for dirs from positional arguments
bc_exp="$fc_falloff * (1 + l( $fc / $fc_falloff )/l($fc_redbase))";
fc_out="$( echo "$bc_exp" | bc -l )";
else
- fc_out="$fc";
+ fc_out="$fc";
fi;
## Reduce output file count by fixed fraction (bkshuf optimization)
fc_out="$(echo "$fc_out * 0.75" | bc -l)";
### Round file count down
fc_out="$(printf "%.0f" "$fc_out")"; # round float down to int
### Get neighbor-preserving shuffled subset (size $fc_out)
- yell "STATUS:$SECONDS:Selecting $fc_out files via bkshuf...";
+ yell "STATUS:$SECONDS:Selecting $fc_out of $fc files via bkshuf...";
must \
echo -n "$list_paths_files" | \
bkshuf "$fc_out" > "$list_paths_files_tmp";