■ 🕑 1. PLAY NU MPV
│ https://x0.at/30jh.png
│ #!/bin/bash
│ # ┏━┓╻ ┏━┓╻ ╻┏┓╻╻ ╻┏┳┓┏━┓╻ ╻ USAGE: playnumpv <days>
│ # ┣━┛┃ ┣━┫┗┳┛┃┗┫┃ ┃┃┃┃┣━┛┃┏┛ (where days = number of days to
│ # ╹ ┗━╸╹ ╹ ╹ ╹ ╹┗━┛╹ ╹╹ ┗┛ search back for newer media files)
│
│ # Check if argument is provided
│ if [ -z "$1" ] || [[ ! "$1" =~ ^[0-9]+$ ]]; then
│ echo "Usage: $0 <days>"
│ exit 1
│ fi
│
│ # Create a temporary playlist file in a safe location
│ playlist=$(mktemp) || { echo "Failed to create temporary file"; exit 1; }
│
│ # Set trap to clean up temporary file on exit
│ trap 'rm -f "$playlist"' EXIT
│
│ # Get absolute path of the playlist to exclude it from search
│ abs_playlist=$(realpath "$playlist")
│
│ # Find all media files modified in the last $1 days and add them to the playlist
│ # Using absolute paths to avoid issues with relative paths
│ find "$PWD" -type f -regextype posix-extended -regex '.*\.(mp3|flac|opus|ogg|m4a|wav|nsf|mod|xm)' \
│ -mtime -"${1}" ! -path "$abs_playlist" -print0 | \
│ sort -z | \
│ tr '\0' '\n' > "$playlist"
│
│ # Check if any files were found
│ if [ ! -s "$playlist" ]; then
│ echo "No files found newer than ${1} days."; exit 0
│ fi
│
│ # Count the number of files in the playlist
│ file_count=$(wc -l < "$playlist")
│ echo "Found $file_count files to play."
│
│ # Play playlist with mpv using unbuffer to maintain terminal connection
│ # and process substitution to capture output without breaking stdin
│ unbuffer -p mpv --shuffle --term-osd=auto --osd-level=2 --no-audio-display \
│ --playlist="$playlist" 2>&1 > >(grep -E "Playing") < /dev/tty
│
│
└─■ 🕑 2. explanation console stdin, stdout, redirection
#!/bin/bash
# ┏━┓╻ ┏━┓╻ ╻┏┓╻╻ ╻┏┳┓┏━┓╻ ╻ USAGE: playnumpv <days>
# ┣━┛┃ ┣━┫┗┳┛┃┗┫┃ ┃┃┃┃┣━┛┃┏┛ (where days = number of days to
# ╹ ┗━╸╹ ╹ ╹ ╹ ╹┗━┛╹ ╹╹ ┗┛ search back for newer media files)
# Check if argument is provided
if [ -z "$1" ] || [[ ! "$1" =~ ^[0-9]+$ ]]; then
echo "Usage: $0 <days>"
exit 1
fi
# Create a temporary playlist file in a safe location
playlist=$(mktemp) || { echo "Failed to create temporary file"; exit 1; }
# Set trap to clean up temporary file on exit
trap 'rm -f "$playlist"' EXIT
# Get absolute path of the playlist to exclude it from search
abs_playlist=$(realpath "$playlist")
# Find all media files modified in the last $1 days and add them to the playlist
# Using absolute paths to avoid issues with relative paths
find "$PWD" -type f -regextype posix-extended -regex '.*\.(mp3|flac|opus|ogg|m4a|wav|nsf|mod|xm)' \
-mtime -"${1}" ! -path "$abs_playlist" -print0 | \
sort -z | \
tr '\0' '\n' > "$playlist"
# Check if any files were found
if [ ! -s "$playlist" ]; then
echo "No files found newer than ${1} days."
exit 0
fi
# Count the number of files in the playlist
file_count=$(wc -l < "$playlist")
echo "Found $file_count files to play."
# Play the playlist with mpv, using unbuffer to maintain terminal connection
# and process substitution to capture output without breaking stdin
unbuffer -p mpv --shuffle --term-osd=auto --osd-level=2 --no-audio-display \
--playlist="$playlist" 2>&1 > >(grep -E "Playing") < /dev/tty
# Multi-line comment explaining the redirection technique:
: <<'EOF'
EXPLANATION OF THE REDIRECTION TECHNIQUE:
The command uses several advanced shell features to maintain keyboard control while filtering output:
1. `unbuffer -p`:
- Creates a pseudo-terminal for mpv
- Ensures mpv maintains interactive behavior including keyboard input handling
2. `2>&1`:
- Redirects stderr to stdout
- Combines both output streams
3. `> >(grep -E "Playing")`:
- Uses process substitution (the `>(...)` syntax)
- Creates a temporary file descriptor connected to grep
- Sends mpv's output to grep without breaking terminal connection
- Unlike a regular pipe, this doesn't disrupt keyboard input
4. `< /dev/tty`:
- Explicitly redirects stdin to the terminal device
- Ensures mpv gets keyboard input directly from the terminal
- This is critical for maintaining keyboard control
WHY THIS WORKS WHEN REGULAR PIPES FAIL:
Regular pipes (mpv | grep) break keyboard input because:
- The shell puts commands in separate process groups
- mpv detects its output is going to a pipe and may change behavior
- Terminal control gets disrupted
Our solution works because:
- unbuffer maintains the terminal connection
- Process substitution doesn't break the terminal connection like a pipe
- Explicit terminal input redirection ensures keyboard control
- The combination preserves mpv's interactive capabilities
DATA FLOW:
Keyboard Input → /dev/tty → mpv (via unbuffer) → Process Substitution → grep → Terminal
EOF