shell腳本製作《落網》音樂播放器(完)
在急於寫代碼之前,我們先明確一下交互功能,我的設計如下,w/s鍵為上下選擇歌曲,p鍵為播放暫停,-/+鍵為音量控制!
shell腳本的讀入鍵盤大家應該知道就是read,但是read通常需要額外按一次回車來確認。有沒有一次只讀取一個位元組且免回車的方式呢?有的那就是帶上參數的讀——"read -n 1"。當然你直接在終端嘗試應該看不出效果。可以寫一個test.sh腳本來測試。
#!/bin/bashfunction keymap { #-s參數silent,免回顯,否則會在終端上顯示輸入 read -sn 1 key echo "you just push $key"}while true; do keymapdone
效果如下
於是改造luoo.sh,添加如下函數
declare CONTROL_FILE=/tmp/contorl. ./control.sh #載入播放庫function choose { if [ $1 = next ] ;then let cursor=($cursor+1)%$size elif [ $1 = prev ]; then let move=$cursor-1 let cursor=$move==-1?$size-1:$move fi}function enjoy { #cursor由於是0開始的,但是樂曲是從01開始的,所以是cursor+1 local url=`printf http://mp3-cdn.luoo.net/low/luoo/radio%s/%02d.mp3 $vol $[cursor+1]` > /dev/null if [ ! $playing -eq $cursor ] ;then #play是一個阻塞調用,末尾加上&,變成非阻塞 play $url & else pause fi}function keymap { read -sn 1 key case $key in w) choose prev ;; s) choose next ;; p) enjoy ;; esac}#最後改造一下main函數,變成死循環tput inittput smcupecho -e $NORMALloadsongs $1if [ -p $CONTROL_FILE ] ;then rm $CONTROL_FILEfimkfifo $CONTROL_FILEwhile true ;do draw keymapdonetput rmcup
好了,再執行的時候,我相信已經可以自由上下選擇了並播放、暫停音樂了。很簡單吧?
好如果你只做到這一步,基本上達到了我最開始寫文章時候的完成度,80%吧。
首先是播放函數除了play函數其他函數都沒有考慮到mplayer進程不存在的情況,如果消費者不存在,一上來就往管道寫內容,比如我一進來誰都沒有選定,直接按了p鍵,就會阻塞。整個軟體也就卡住了。為了健壯,cursor不要默認為-1應為0
然後如果你能注意到我的播放器在播放的選項之前是有一個playing的狀態的。這個狀態就是一個數字變數,但是,這個變數luoo.sh和control.sh同時都要用到,shell的特殊就在於變數只能由調用者向被調用者傳遞,而不能反過來,這個傳遞呢,其實是複製了一份拷貝進被調用者,也就是說control.sh即便對playing變數修改是不會對luoo.sh造成影響,要解決這個問題呢,得考慮使用文件。control.sh和luoo.sh同時讀寫/tmp/playing這個文件,就可以實現共享。
於是先改造control.sh
#!/bin/bashdeclare -x CONTROL_FILE #-x為導出變數,全局變數declare -x PLAYING_FILE #playing共享變數文件function mplayerpause { local playerpid=`ps -ef|grep mplayer |grep -v grep |awk {print $2} |head -n1` if [ -n "$playerpid" ] ;then echo pause > $CONTROL_FILE fi}function mplayerquit { local playerpid=`ps -ef|grep mplayer |grep -v grep |awk {print $2} |head -n1` if [ -n "$playerpid" ] ;then echo quit > $CONTROL_FILE fi}function mplayerplay { #接受參數$1為音樂地址 local playerpid=`ps -ef|grep mplayer |grep -v grep |awk {print $2} |head -n1` if [ -z "$playerpid" ] ;then #檢查mplayer進程是否存在,如果不存在則啟動mplayer echo $CONTROL_FILE >> luoo.log mplayer -input file=$CONTROL_FILE $1 > /dev/null 2>&1 echo -1 > $PLAYING_FILE #播放結束需修改「當前播放」 else #如果存在,則寫入操作指令到控制文件 echo "load $1" > $CONTROL_FILE fi}
接下來,luoo.sh的最終形態!
#!/bin/bashdeclare -a songs #-a定義songs為Array結構declare -i size=0 #-i定義size為數字類型 songs的長度declare -i cursor=0 #定義選中游標declare vol #什麼參數都不加,默認為字元串declare titledeclare CONTROL_FILE=/tmp/contorldeclare PLAYING_FILE=/tmp/playing. ./control.shSELECTED=" 33[31;44m" #選中的時候前景色為紅,背景色青藍NORMAL=" 33[37;44m" #非選中請景色為白,背景色仍是青藍function debug { #日誌功能,帶上時間點列印到luoo.log文件中去,方便調試 echo `date +%T:` $@ >> luoo.log}#loadsongs(vol),載入某一期的歌曲專輯function loadsongs { debug "loadsongs $1" vol=$1 local html=$(curl -s http://www.luoo.net/music/$1) title=$(echo $html |grep -oP "vol-title">[^<]+<" |grep -oP ">[^<]+<") title=${title:1:-1} local body=$(echo $html |grep -oP "trackname btn-play">[^<]+<" |grep -oP ">[^<]+<") #read -r 意思是每次讀一行!否則每次讀一個字元串,讀到line變數中! while read -r line; do songs[$size]=${line:1:-1} $((size++)) done<<EOF $bodyEOF}function draw { read playing < $PLAYING_FILE clear cat <<EOF <vol.$vol>$titleEOF for index in ${!songs[@]} ;do printf " " if [ $playing -eq $index ] ;then printf "["$BOLD"playing"$NORMAL"]" else printf "[-------]" fi if [ $cursor -eq $index ] ;then echo -e $SELECTED${songs[$index]}$NORMAL else echo -e $NORMAL${songs[$index]}$NORMAL fi done}function keymap { read -sn 1 key case $key in s) choose next ;; w) choose prev ;; p) enjoy ;; esac}function choose { if [ $1 = next ] ;then let cursor=($cursor+1)%$size elif [ $1 = prev ]; then let move=$cursor-1 let cursor=$move==-1?$size-1:$move fi}function enjoy { read playing < $PLAYING_FILE local url=`printf http://mp3-cdn.luoo.net/low/luoo/radio%s/%02d.mp3 $vol $[cursor+1]` > /dev/null if [ ! $playing -eq $cursor ] ;then #播放結束後需要觸發一次重繪所以在play之後緊接著draw (mplayerplay $url && draw) & echo $cursor > $PLAYING_FILE else mplayerpause fi}function initialize { #初始化函數 if [ -p $CONTROL_FILE ] ;then #如果存在mplayer控制管道,則刪掉先 rm $CONTROL_FILE fi #創建mplayer控制管道 mkfifo $CONTROL_FILE #初始化「正在播放」變數為-1 echo -1 > $PLAYING_FILE}function quitluoo { mplayerquit sleep 1 #給予mplayer進程退出一點時間 tput rmcup clear exit}#maintput inittput smcupinitializeecho -e $NORMALtrap quitluoo INT #捕獲ctrl+c信號,調用quitluoo函數loadsongs $1while true; do draw keymapdone
接下來,好好享受音樂吧!
是不是很強勢?
本期代碼已經更新到我的github上去了:nikoloss/linuxstuff
推薦閱讀:
※2017 年成為 Linux 專家的 4 個熱門技能
※應用層協議那些事
※非 NTFS 的日誌式文件系統上,比如Ext4,能實現類似 Everything 這個軟體的利用日誌進行快速搜索的功能么?
※如何輕鬆記住 Linux 命令
※2.5 寸的 SSD(固態硬碟)怎麼塞進 3.5 寸的 SATA 硬碟櫃?