Skip to content

Instantly share code, notes, and snippets.

@michd
Last active December 13, 2019 10:23
Show Gist options
  • Save michd/253e8e4635aa645bdd386b2ab3df009b to your computer and use it in GitHub Desktop.
Save michd/253e8e4635aa645bdd386b2ab3df009b to your computer and use it in GitHub Desktop.
A user-friendly bash script for playing content on a TV through Raspberry Pi
#!/bin/bash
# This script collects files in a media folder and presents them in a dialog,
# where you can select one with arrow keys and enter. It is then played with
# omxplayer.
# The script allows navigating into subdirectories, and back up as well. Spaces
# in file names should also work properly.
# Assumptions:
# - `whiplash` is installed. `dialog` is an alternative, but it didn't work well
# for me.
# Directory containing TV. You will need read access.
# Won't allow navigating up beyond this point.
mainTvDir="/mnt/TV/"
# Current directory we're listing files in
tvDir=${mainTvDir}
# Directory we're in at launch, so we can return to it at exit
initialPwd=$(pwd)
# Dialog dimensions based on terminal size
dHeight=$(($(tput lines)-4))
dWidth=$(($(tput cols)-4))
choiceHeight=$((dHeight-11))
# Where to direct terminal output
terminal=$(tty)
# Array of entries in current directory
fileList=("")
# Start in the tv directory
cd $tvDir
# At bottom of file, after all functions are implemented, we invoke main.
# Gets called at the beginning, and every time we need to refresh / return
# or navigate to a different folder
main() {
# Load the list of files into fileList
getFiles
# Show navigation dialog and await user choice
local choice=$(getChoice)
if [[ -z $choice ]]; then
# If no choice was given, this indicates "exit" (cancel) was picked.
# Ask whether to indeed exit
askExit
elif [[ $choice = "reload" ]]; then
# If refresh was picked, just run main again which will get a new list of
# files. Do this if you've added files to the directory after starting the
# script.
main
elif [[ $choice = ".." ]]; then
# Navigate up a directory, then reload file list
cd ..
tvDir="$(pwd)/"
main
else
# Any other option is either a directory or a file to try and play.
# Let navigate deal with it by index in fileList.
local index=$((choice-1))
navigate $index
fi
}
# Collects files and stores them into the fileList array
getFiles() {
# Clear previous array of files
unset fileList
cd $tvDir
# Populate file list anew with all files found.
# Note: this previous used `ls`, but that's a bad idea in bash scripts,
# due to issues with spaces and quotes and such. ls isn't meant for script
# parsing.
for f in *; do
fileList+=("$f")
done
}
# Present a dialog with directory entries and a couple of options to the user
getChoice() {
# tag counter for whiptail dialog - each entry gets a tag. Our file/directory
# entries get a numeric tag.
local cnt=1
# Array index for menu options. Every menu entry takes two array entries:
# One tag, one item.
local i=2
# Array to contain menu options
local menuOpts=(reload "[Refresh]")
if [[ "$tvDir" != "$mainTvDir" ]]; then
# If we're not in the top level TV directory, add an entry to go to the
# parent directory
menuOpts+=(.. "../")
# Increase array index by two, for the entries we've just added
((i+=2))
fi
# Add menu entries for each entry in fileList
for file in "${fileList[@]}"; do
# Assign numeric tag
menuOpts[i]=$cnt
if [[ -d $file ]]; then
# If the entry is a directory, add the "/" suffix as a visual indicator
menuOpts[i+1]="$file/"
else
# Otherwise just use the filename as-is
menuOpts[i+1]="$file"
fi
# Increment menuOpts array index by the two entries just added
((i+=2))
# Increment tag counter by one
((cnt++))
done
# Render menu and output choice to terminal
# Line by line comments:
# Print the current directory in the back
# Set title on the dialog
# Don't display tags as they're useless here
# Chunky buttons
# Use "Exit" as the text for the cancel button
# Start menu options + text above menu
# Pass dialog dimensions (height, width, choice area height)
# Pass all the menu options
# Redirect all output to the tty
whiptail --backtitle "$tvDir" \
--title "Select file" \
--notags \
--fullbuttons \
--cancel-button "Exit" \
--menu "Select a file to watch" \
$dHeight $dWidth $choiceHeight \
"${menuOpts[@]}" \
2>&1 > $terminal
}
# Navigate to an item by index (in $1), corresponding to an item in $fileList
# If this is a directory, navigates to that directory and renders the menu again
# If it's a file, attempt to play it with omxplayer, then render menu again
navigate() {
local fullFilePath="${tvDir}${fileList[$1]}"
if [[ -d $fullFilePath ]]; then
# If it's a directory, set that as our working directory and go back to menu
tvDir=$fullFilePath
main
else
echo "Trying to play ${fileList[$1]} with omxplayer..."
mediaFile=("${fileList[$1]}")
omxplayer "$mediaFile"
main
fi
}
# Prompt user whether to exit, with optionally a custom message.
# If Yes is picked, the script returns to the original directory, and exits.
# Otherwise, it returns to the main menu.
askExit() {
msg=$1
if [[ -z $msg ]]; then
msg="Are you sure you wish to exit?"
fi
if (whiptail --yesno "$msg" \
7 34 \
2>&1 > $terminal); then
echo "Bye."
cd $initialPwd
else
main
fi
}
# Launch main menu
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment