-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmplall.sh
executable file
·367 lines (337 loc) · 12.7 KB
/
mplall.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
#!/bin/bash
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
#
# Everyone is permitted to copy and distribute verbatim or modified
# copies of this license document, and changing it is allowed as long
# as the name is changed.
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
# 0. You just DO WHAT THE FUCK YOU WANT TO.
#
# Name: mplall.sh
# Does: loops media players on media files from the command line
# Systems: R Pi using hardware acceleration; GNU/Linux; MacOS
# Author: daid kahl Copyright 2024
# Last updated: 29 Dec 2024 22:44:40
VERSION=1.4
# RPI users: Set the audio device
# See man omxplayer under -o for valid audio output devices
# Here we default to ALSA, but options include: hdmi/local/both/alsa
# Without anything, omxplayer may not respond to standard system volume controls
RPIAUDIO="alsa"
#RPIAUDIO="hdmi"
# Recognized media file types regex for grep (not case sensitive)
# You can add more, but please mimic the grep regex style employed
FILETYPES="(\.avi|\.flac|\.flv|\.mkv|\.mp3|\.mp4|\.m4a|\.mpeg|\.mpg|\.ogg|\.ogv|\.vob|\.wav|\.wmv)"
function Usage () {
cat <<-ENDOFMESSAGE
mplall version $VERSION
Recursively find and play media files starting from the present directory, forever.
Video is full-screened; subtitles enabled by default.
Several media players are supported, including omxplayer for Raspberry Pi.
Usage $0: [-b] [-B] [-c] [-D] [-p int] [-M] [-R] [file]
options:
-b : black background outside video on RPi omxplayer
-B : black background outside video on any system, without flashing the desktop between tracks
Note: The GUI OSD for, e.g., volume control can be seen in -B but not -b mode.
-c : continues playing from previous occasion (presently only on RPi)
-D : play media on Desktop (experimental)
-p [<int>] : profile # environment (presently only on RPi.) To see profiles use -p list
-M : minimize the terminal, black background, without flashing the desktop between tracks
Note: The user needs to refocus to the terminal to control the media!
-R : generate Random playlist
arguments:
file : specific file to play (optional)
ENDOFMESSAGE
exit 1
}
#TODO: produce and employ defaults from file. see getpaper
#TODO: catch PID of find to put on a control_c trap
# If we get a Ctrl+C, kill. Needed for RPi but works in all cases
control_c () {
echo
echo -e "\e[31;1mmplall received kill signal . . . quitting\e[0m\n"
exit
}
# trap keyboard interrupt
trap control_c SIGINT
# if:
# we are using a profile
# a profile file already exists under the number
# we are not in the working directory of said profile
# it's not a continuing playback (which can be called from another location)
# confirm:
# the user wants to erase the old profile?
function CheckCollision(){
file=$HOME/.mplall/mplallp$pval
RESULT=$(grep "${PWD##*/}" "$file")
if [[ -e $file && -z $RESULT && -z $cflag ]] ; then
echo -e "\e[34;1;4mProfile $pval\e[0m"
head -n $(cat $(echo "$file" | sed 's/mplallp/mplall-filenumberp/')) "$file"
echo ""
echo -e "\e[31;1mReally clean this profile?\e[0m\n"
read -p "Yes or no (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Nn]$ ]]; then
echo "No action taken. Quitting. Move to a different directory or choose another profile."
exit
fi
rm -rf $HOME/.mplall/mplallp$pval
rm -rf $HOME/.mplall/mplall-pwdp$pval
rm -rf $HOME/.mplall/mplall-filenumberp$pval
fi
}
#On Screen Display with instructions depending on the player
function OSD(){
clear
echo -e "\e[34;1;4mWelcome to mplall . . . the recursive command line media looper!\e[0m"
if [[ $RPI ]];then
echo -e "\n\e[31;1mPress \e[34;1mCtrl+c \e[31mto kill $0 and \e[34;1mq \e[31mto seek to the next file.\e[0m\n"
else
echo -e "\n\e[31;1mPress \e[34;1mCtrl+c \e[31mor \e[34;1mq \e[31mto kill $0 and the keys \e[34;1m< \e[31mor \e[34;1m> \e[31mto seek files in the playlist.\e[0m\n"
fi
}
# generation of playlist for omxplayer on RPi
function RPIPLAYLIST(){
# Populate playlist from working directory
if [[ -z $cflag && "$pflag" ]];then
echo "$PWD" > $PLAYLIST_PWD
fi
if [[ "$cflag" && "$pflag" ]];then
# echo "$(head -n 1 "$PLAYLIST" | sed -E 's/(.*)\/.*/\1/')"
PWD=$(cat $PLAYLIST_PWD)
#PWD=$(head -n 1 "$PLAYLIST" | sed -E 's/(.*)\/.*/\1/')
cd $PWD
fi
find -L "$PWD" -type f | egrep -i "$FILETYPES" | sort $RANDOMIZE > $PLAYLIST
PLAYLIST_SIZE=$(wc -l < $PLAYLIST)
# If continue, sort it out
if [[ "$cflag" && $FILENUMBER -gt 0 ]];then
PLAYLIST_HEAD="$HOME/.mplall/mplall-head$pflagpval"
PLAYLIST_SORTED="$HOME/.mplall/mplall-sorted$pflagpval"
# Extract the portion to be sorted
tail -n +$((FILENUMBER+1)) $PLAYLIST > $PLAYLIST_SORTED
# Combine the unsorted header with the sorted body
head -n $FILENUMBER $PLAYLIST > $PLAYLIST_HEAD
cat $PLAYLIST_HEAD >> $PLAYLIST_SORTED
# Move the temporary file to replace the original
mv $PLAYLIST_SORTED $PLAYLIST
rm $PLAYLIST_SORTED
fi
}
## Blackout hacking
#function BLACKOUTHAX(){
# # create a 1x1 black pixel on the fly
# CANVAS=/tmp/.mplall_canvas.gif
# convert -size 1x1 canvas:black $CANVAS
#}
# Set appropriate player or die
if ( which omxplayer &>/dev/null );then
MPLAYER="omxplayer"
RPI=true
elif ( which mplayer-x &>/dev/null );then
MPLAYER="mplayer-x"
elif ( which mplayer2 &>/dev/null );then
MPLAYER="mplayer2 --gapless-audio"
elif ( which mplayer &>/dev/null );then
MPLAYER="mplayer"
echo "gapless audio disabled, install mplayer2 to enable: http://www.mplayer2.org/"
else
# TODO more web links or install suggestions
printf "mplall requires omxplayer, mplayer-x, mplayer2 or mplayer, but none are in your PATH or not installed.\n\t(see http://www.mplayerhq.hu or http://www.mplayer2.org/)\nAborting.\n" >&2; exit 1;
fi
if [ ! -d $HOME/.mplall ]; then
printf "$HOME/.mplall does not exist...creating it\n"
mkdir $HOME/.mplall
fi
# Option definition and parsing
Rflag=""
Dflag=""
cflag=""
pflag=""
pval=""
bflag=""
Bflag=""
Mflag=""
while getopts cbgp:BDMR OPTION
do
case $OPTION in
c) cflag=1
#if [[ !$RPI ]];then
# echo "Warning: -c mode only works on RPi's omxplayer. Ignoring -c."
#fi
;;
g) pflag=1
#if [[ !$RPI ]];then
# echo "Warning: -g mode only works on RPi's omxplayer. Ignoring -g."
#fi
;;
p) pflag="p"
#if [[ !$RPI ]];then
# echo "Warning: -p mode only works on RPi's omxplayer. Ignoring -p."
#fi
pval="$OPTARG"
if [[ "$pval" =~ "list" ]];then
for file in $HOME/.mplall/mplallp*; do
if [ -f "$file" ]; then
echo -e "\e[34;1;4mProfile $file\e[0m" | sed 's/\/.*mplall\/mplallp//'
#echo -e "$file"
#echo -e "\e[34;1;4m$file\e[0m"
#echo "$file"
#echo "$file" | sed 's/.mplallp/.mplall-filenumberp/'
head -n $(cat $(echo "$file" | sed 's/mplallp/mplall-filenumberp/')) "$file" | tail -n 3
echo ""
fi
done
exit
fi
if [[ "$pval" =~ "clean" ]];then
for file in $HOME/.mplall/mplallp*; do
if [ -f "$file" ]; then
echo ""
echo -e "\e[34;1;4mProfile $file\e[0m" | sed 's/\/.*mplall\/mplallp//'
#echo -e "$file"
#echo -e "\e[34;1;4m$file\e[0m"
head -n 3 "$file"
fi
done
echo ""
echo -e "\e[31;1mReally clean these profiles?\e[0m\n"
read -p "Yes or no (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
rm -rf $HOME/.mplall/mplallp*
rm -rf $HOME/.mplall/mplall-pwdp*
rm -rf $HOME/.mplall/mplall-filenumberp*
exit
else
echo "No action taken. Quitting."
exit
fi
fi
re='^[0-9]+$'
if ! [[ $pval =~ $re ]] ; then
echo "Error: profile value is not a number" >&2; exit 1
fi
;;
b) bflag=1
BLACKOUT="-b"
if [[ !$RPI ]];then
echo "Warning: -b mode only works on RPi's omxplayer. Ignoring -b. Try -B instead"
fi
;;
B) Bflag=1
which wmctrl &>/dev/null || { printf "mplall requires wmctrl for Blackout hacked mode but it's not in your PATH or not installed.\nAborting.\n" >&2; exit 1; }
which feh &>/dev/null || { printf "mplall requires feh for Blackout hacked mode but it's not in your PATH or not installed.\nAborting.\n" >&2; exit 1; }
which convert &>/dev/null || { printf "mplall requires imagemagick for Blackout hacked mode but it's not in your PATH or not installed.\nAborting.\n" >&2; exit 1; }
;;
M) Mflag=1
MINIMIZE="-M"
which xdotool &>/dev/null || { printf "mplall requires xdotool for Minimize mode but it's not in your PATH or not installed.\nAborting.\n" >&2; exit 1; }
#which feh &>/dev/null || { printf "mplall requires feh for Minimize mode but it's not in your PATH or not installed.\nAborting.\n" >&2; exit 1; }
#which convert &>/dev/null || { printf "mplall requires imagemagick for Minimize mode but it's not in your PATH or not installed.\nAborting.\n" >&2; exit 1; }
;;
R) Rflag=1
RANDOMIZE="-R";;
D) Dflag=1
which xwininfo &>/dev/null || { printf "mplall requires xwininfo for Desktop mode but it's not in your PATH or not installed.\n\t(see http://xorg.freedesktop.org/ )\nAborting.\n" >&2; exit 1; }
DESKTOPID=$(xwininfo -name Desktop | grep Desktop | awk '{printf $4}')
WID="-wid $DESKTOPID"
;;
*) Usage ;;
esac
done
shift $((OPTIND-1))
if [[ ! -z "$2" ]];then
echo "More than one manual input presently unsupported..."
echo "Ignoring inputs after $1 "
fi
# -c flag can come after -p flag so we cannot check it above
if [[ $pflag ]];then
CheckCollision
fi
if [[ ! -z "$1" ]];then
PLAYLIST="$PWD/$1"
#TODO: pass multiple manual inputs
#PLAYLIST="$@"
fi
if [[ "$PWD" = "$HOME" && -z "$PLAYLIST" && -z $pflag ]];then
read -p "Really recursively search all files for media in $HOME? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
continue
else
exit
fi
fi
if [ "$Rflag" ];then
echo "mplall generating random playlist..."
# TODO: Randomize manually inputted playlist.
#PLAYLIST=$(echo "$@"|sed 's/\ /\n/g'|sort $RANDOMIZE)
fi
if [[ $Bflag ]];then
# create a 1x1 black pixel on the fly
CANVAS=/tmp/.mplall_canvas.gif
convert -size 1x1 canvas:black $CANVAS
# full screen the black pixel with feh and return the focus to the terminal
wmctrl -T mplall$$ -r :ACTIVE: ; feh -F $CANVAS & sleep 0.1 ; wmctrl -a mplall$$
fi
if [[ $Mflag ]];then
xdotool windowminimize $(xdotool getactivewindow)
fi
if [[ $RPI ]];then # For omxplayer on Raspberry Pi, we need to pass files one-by-one to emulate a playlist
OPTIONS="$BLACKOUT -o $RPIAUDIO"
if [[ -z "$PLAYLIST" ]]; then
PLAYLIST="$HOME/.mplall/mplall$pflag$pval"
PLAYLIST_PWD="$HOME/.mplall/mplall-pwd$pflag$pval"
FILENUMBER_OUTPUT="$HOME/.mplall/mplall-filenumber$pflag$pval"
if [ "$cflag" ];then
if wc -l $FILENUMBER_OUTPUT > /dev/null 2>&1; then
FILENUMBER=$(< "$FILENUMBER_OUTPUT")
let "FILENUMBER -= 1"
else
FILENUMBER=0
fi
else
FILENUMBER=0
fi
RPIPLGEN=1
RPIPLAYLIST
else
echo "$PLAYLIST" > $HOME/.mplall/mplall_singular
RPIPLGEN=""
PLAYLIST="$HOME/.mplall/mplall_singular"
fi
while true; do
# allow loop body to read stdin so redirect on 10,
# see https://stackoverflow.com/questions/1521462/looping-through-the-content-of-a-file-in-bash
while read -u 10 entry; do
let "FILENUMBER += 1"
if [ $FILENUMBER -gt $PLAYLIST_SIZE ]; then
FILENUMBER=1
fi
OSD
echo -e "\e[34;1mPlaying file $FILENUMBER of $PLAYLIST_SIZE: \e[93;1m$entry \e[34;1m. . .\e[0m\n"
echo $FILENUMBER > $FILENUMBER_OUTPUT
"$MPLAYER" $OPTIONS "$entry"
done 10< "$PLAYLIST"
# regenerate playlist to reflect any new files.
# see https://github.com/goatface/mplall/issues/1
if [ "$RPIPLGEN" ];then
RPIPLAYLIST
fi
done
else # For mplayer and derivatives, direct playlists are supported greatly simplifying the code
OSD
if [[ -z "$PLAYLIST" ]];then
PLAYLIST=$(find -L "$PWD" -type f | egrep -i "$FILETYPES" | sort $RANDOMIZE )
#PLAYLIST=$(find -L "$PWD" -type f | egrep -i '(\.avi|\.flac|\.flv|\.mkv|\.mp3|\.mp4|\.mpeg|\.mpg|\.ogg|\.ogv|\.vob|\.x|\.wav|\.wmv)' | sort $RANDOMIZE )
fi
$MPLAYER $WID -fs -loop 0 -zoom -playlist <(echo "$PLAYLIST")
fi
exit
# old
#$MPLAYER $WID -fs -loop 0 -zoom -playlist <(find -L "$PWD" -type f | egrep -i '(\.avi|\.flac|\.flv|\.mkv|\.mp3|\.mp4|\.m4a|\.mpeg|\.mpg|\.ogg|\.ogv|\.vob|\.wav|\.wmv)' | sort $RANDOMIZE )
#$MPLAYER -wid 0x1000003 -fs -loop 0 -zoom -playlist <(find -L "$PWD" -type f | egrep -i '(\.avi|\.flac|\.flv|\.mkv|\.mp3|\.mp4|\.mpeg|\.mpg|\.ogg|\.ogv|\.vob|\.wav|\.wmv)' | sort $* )