From e05325ceb8b812fc40b7c3475c59602dde9efdae Mon Sep 17 00:00:00 2001 From: Roman Bazalevsky Date: Wed, 28 Sep 2016 19:50:21 +0300 Subject: [PATCH] =?utf8?q?=D0=92=D0=B5=D0=B1-=D0=B8=D0=BD=D1=82=D0=B5?= =?utf8?q?=D1=80=D1=84=D0=B5=D0=B9=D1=81=20=D0=BA=20MPD.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Серверная часть - PHP + libmpc. Клиентская часть - AJAX без библиотек. --- ajax/command.php | 8 + ajax/editplaylist.php | 72 +++ ajax/mpd.js | 198 ++++++ ajax/mpd.php | 14 + ajax/playerstate.php | 7 + ajax/playlist-command.php | 9 + ajax/playlist.php | 50 ++ ajax/repeatstate.php | 7 + ajax/trackinfo.php | 17 + ajax/volume.php | 7 + config/config.php | 7 + css/general.css | 192 ++++++ images/addall.png | Bin 0 -> 1267 bytes images/addselected.png | Bin 0 -> 1699 bytes images/bg.png | Bin 0 -> 22211 bytes images/control_bg.png | Bin 0 -> 414 bytes images/down.png | Bin 0 -> 1344 bytes images/highlight.png | Bin 0 -> 430 bytes images/left.png | Bin 0 -> 1306 bytes images/minus.png | Bin 0 -> 981 bytes images/next.png | Bin 0 -> 1267 bytes images/pause.png | Bin 0 -> 1058 bytes images/play.png | Bin 0 -> 1281 bytes images/playing_bg.png | Bin 0 -> 19970 bytes images/playlist.png | Bin 0 -> 1445 bytes images/plus.png | Bin 0 -> 1055 bytes images/prev.png | Bin 0 -> 1390 bytes images/previous.png | Bin 0 -> 1268 bytes images/remall.png | Bin 0 -> 1459 bytes images/remove.png | Bin 0 -> 1256 bytes images/removeall.png | Bin 0 -> 1280 bytes images/removeselected.png | Bin 0 -> 1664 bytes images/remselected.png | Bin 0 -> 1613 bytes images/repeatoff.png | Bin 0 -> 1671 bytes images/repeaton.png | Bin 0 -> 1709 bytes images/right.png | Bin 0 -> 1352 bytes images/songs.png | Bin 0 -> 1353 bytes images/stop.png | Bin 0 -> 938 bytes images/up.png | Bin 0 -> 1317 bytes images/update.png | Bin 0 -> 1732 bytes index.php | 17 + model/player.php | 44 ++ model/tracklist.php | 100 +++ system/helper.php | 35 ++ system/mpd_class.php | 976 +++++++++++++++++++++++++++++ view/default/tmpl/default.php | 29 + view/default/tmpl/playlistmenu.php | 9 + view/default/view.php | 4 + view/player/tmpl/default.php | 38 ++ view/player/view.php | 6 + 50 files changed, 1846 insertions(+) create mode 100644 ajax/command.php create mode 100644 ajax/editplaylist.php create mode 100644 ajax/mpd.js create mode 100644 ajax/mpd.php create mode 100644 ajax/playerstate.php create mode 100644 ajax/playlist-command.php create mode 100644 ajax/playlist.php create mode 100644 ajax/repeatstate.php create mode 100644 ajax/trackinfo.php create mode 100644 ajax/volume.php create mode 100644 config/config.php create mode 100644 css/general.css create mode 100755 images/addall.png create mode 100755 images/addselected.png create mode 100755 images/bg.png create mode 100755 images/control_bg.png create mode 100755 images/down.png create mode 100755 images/highlight.png create mode 100755 images/left.png create mode 100755 images/minus.png create mode 100755 images/next.png create mode 100755 images/pause.png create mode 100755 images/play.png create mode 100755 images/playing_bg.png create mode 100755 images/playlist.png create mode 100755 images/plus.png create mode 100755 images/prev.png create mode 100755 images/previous.png create mode 100755 images/remall.png create mode 100755 images/remove.png create mode 100755 images/removeall.png create mode 100755 images/removeselected.png create mode 100755 images/remselected.png create mode 100755 images/repeatoff.png create mode 100755 images/repeaton.png create mode 100755 images/right.png create mode 100755 images/songs.png create mode 100755 images/stop.png create mode 100755 images/up.png create mode 100755 images/update.png create mode 100644 index.php create mode 100644 model/player.php create mode 100644 model/tracklist.php create mode 100644 system/helper.php create mode 100644 system/mpd_class.php create mode 100644 view/default/tmpl/default.php create mode 100644 view/default/tmpl/playlistmenu.php create mode 100644 view/default/view.php create mode 100644 view/player/tmpl/default.php create mode 100644 view/player/view.php diff --git a/ajax/command.php b/ajax/command.php new file mode 100644 index 0000000..25567a4 --- /dev/null +++ b/ajax/command.php @@ -0,0 +1,8 @@ + diff --git a/ajax/editplaylist.php b/ajax/editplaylist.php new file mode 100644 index 0000000..b7e8bf4 --- /dev/null +++ b/ajax/editplaylist.php @@ -0,0 +1,72 @@ + '\\\'', + "\\" => '\\\\', + "\r\n" => "\\r\\n", + "\n" => "\\n" + ); + return strtr($target, $replacements); +} + +include('mpd.php'); +$dir = $_REQUEST['dir']; + +?> +
+ + + +
+ + +
+
+
+ + + + + GetDir($dir); + ?> + + + + "> + + + + + + + + + +
TitleControl
+
+ +
+ + + +
+ + +
+
diff --git a/ajax/mpd.js b/ajax/mpd.js new file mode 100644 index 0000000..5d64a92 --- /dev/null +++ b/ajax/mpd.js @@ -0,0 +1,198 @@ + +function RefreshNowPlaying() { + +var req = new XMLHttpRequest(); + +req.onreadystatechange = function () { + if (this.readyState != 4 || this.status != 200) return; + document.getElementById('nowplaying_content').innerHTML=this.responseText; + document.title='MPD Player: '+this.responseText; +}; + +req.open("GET", "ajax/trackinfo.php", true); +req.send(); + +} + +function RefreshPlayerState() { + +var req = new XMLHttpRequest(); + +req.onreadystatechange = function () { + if (this.readyState != 4 || this.status != 200) return; + if (this.responseText=="play") { + document.getElementById('playpausebutton').innerHTML=""; + } else { + document.getElementById('playpausebutton').innerHTML=""; + } +}; + +req.open("GET", "ajax/playerstate.php", true); +req.send(); + +} + +function RefreshRepeatState() { + +var req = new XMLHttpRequest(); + +req.onreadystatechange = function () { + if (this.readyState != 4 || this.status != 200) return; + if (this.responseText=="1") { + document.getElementById('repeatstate').innerHTML=""; + } else { + document.getElementById('repeatstate').innerHTML=""; + } +}; + +req.open("GET", "ajax/repeatstate.php", true); +req.send(); + +} + +function RefreshVolume() { + +var req = new XMLHttpRequest(); + +req.onreadystatechange = function () { + if (this.readyState != 4 || this.status != 200) return; + document.getElementById('volume_total').innerHTML="
"; +}; + +req.open("GET", "ajax/volume.php", true); +req.send(); + +} + +function RefreshPageStatus() { + + RefreshNowPlaying(); + RefreshPlayerState(); + RefreshRepeatState(); + RefreshVolume(); + +} + +function RefreshPlaylist() { + +var req = new XMLHttpRequest(); + +req.onreadystatechange = function () { + if (this.readyState != 4 || this.status != 200) return; + document.getElementById('playlist').innerHTML=this.responseText; +}; + +req.open("GET", "ajax/playlist.php", true); +req.send(); + +} + +function EditPlayList(dir) { + +var req = new XMLHttpRequest(); + +req.onreadystatechange = function () { + if (this.readyState != 4 || this.status != 200) return; + document.getElementById('playlist').innerHTML=this.responseText; +}; + +if (!dir) { dir = ''; }; + +req.open("GET", "ajax/editplaylist.php?dir="+dir, true); +req.send(); + +} + +function RefreshPageContent() { + + RefreshPageStatus(); + RefreshPlaylist(); + +} + +function Command(cmd) { + +var req = new XMLHttpRequest(); + +req.onreadystatechange = function () { + if (this.readyState != 4 || this.status != 200) return; + RefreshPageStatus(); +}; + +req.open("GET", "ajax/command.php?task="+cmd, true); +req.send(); + +} + +function PlaylistCommand(cmd,item) { + +var req = new XMLHttpRequest(); + +req.onreadystatechange = function () { + if (this.readyState != 4 || this.status != 200) return; + RefreshPageContent(); +}; + +req.open("GET", "ajax/playlist-command.php?item="+item+"&task="+cmd, true); +req.send(); + +} + +function PlaylistEditCommand(cmd,item) { + +var req = new XMLHttpRequest(); + +req.open("GET", "ajax/playlist-command.php?item="+item+"&task="+cmd, true); +req.send(); + +} + + +function PlaylistItemsCommand(cmd) { + +var req = new XMLHttpRequest(); + +var selected = [].filter.call(document.getElementsByName('itemlist[]'), function(c) { + return c.checked; +}).map(function(c) { + return c.value; +}); + +req.onreadystatechange = function () { + if (this.readyState != 4 || this.status != 200) return; + RefreshPageContent(); +}; + +params=selected.map(function(el) { + //Map each field into a name=value string, make sure to properly escape! + return 'itemlist[]=' + encodeURIComponent(el); + }).join('&'); + +req.open("POST", "ajax/playlist-command.php?task="+cmd, true); +req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); +req.send(params); + +} + +function PlaylistEditItemsCommand(cmd,dir) { + +var req = new XMLHttpRequest(); + +var selected = [].filter.call(document.getElementsByName('itemlist[]'), function(c) { + return c.checked; +}).map(function(c) { + return c.value; +}); + +params=selected.map(function(el) { + //Map each field into a name=value string, make sure to properly escape! + return 'itemlist[]=' + encodeURIComponent(el); + }).join('&'); + +req.open("POST", "ajax/playlist-command.php?dir="+dir+"&task="+cmd, true); +req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); +req.send(params); + +} + +// setInterval(RefreshPageStatus, 5000); diff --git a/ajax/mpd.php b/ajax/mpd.php new file mode 100644 index 0000000..9f435e2 --- /dev/null +++ b/ajax/mpd.php @@ -0,0 +1,14 @@ +connected != 1){ + echo "Not Connected to Server"; + exit(1); +} + +?> diff --git a/ajax/playerstate.php b/ajax/playerstate.php new file mode 100644 index 0000000..c4735a3 --- /dev/null +++ b/ajax/playerstate.php @@ -0,0 +1,7 @@ +state; + +?> diff --git a/ajax/playlist-command.php b/ajax/playlist-command.php new file mode 100644 index 0000000..19344da --- /dev/null +++ b/ajax/playlist-command.php @@ -0,0 +1,9 @@ + diff --git a/ajax/playlist.php b/ajax/playlist.php new file mode 100644 index 0000000..78fe8ad --- /dev/null +++ b/ajax/playlist.php @@ -0,0 +1,50 @@ +current_track_id; +$playlist= $mpd->playlist; +?> +
+ +
+ + + + + + "> + + + + + + + + + +
TitleControls
+ + + + + + + + + + +
+
+ +
diff --git a/ajax/repeatstate.php b/ajax/repeatstate.php new file mode 100644 index 0000000..c983152 --- /dev/null +++ b/ajax/repeatstate.php @@ -0,0 +1,7 @@ +repeat; + +?> diff --git a/ajax/trackinfo.php b/ajax/trackinfo.php new file mode 100644 index 0000000..e5cc464 --- /dev/null +++ b/ajax/trackinfo.php @@ -0,0 +1,17 @@ +current_track_id; +$playlist= $mpd->playlist; +if($cur_track !=-1) + + if ($playlist[$cur_track]['name']==$playlist[$cur_track]['title']) { + echo htmlentities(cut_file($playlist[$cur_track]['name'])); + } else { + echo htmlentities($playlist[$cur_track]['title']); + } +else + echo "No Track selected"; + +?> diff --git a/ajax/volume.php b/ajax/volume.php new file mode 100644 index 0000000..bd3caf0 --- /dev/null +++ b/ajax/volume.php @@ -0,0 +1,7 @@ +volume; + +?> diff --git a/config/config.php b/config/config.php new file mode 100644 index 0000000..fecc1f6 --- /dev/null +++ b/config/config.php @@ -0,0 +1,7 @@ + diff --git a/css/general.css b/css/general.css new file mode 100644 index 0000000..19078d4 --- /dev/null +++ b/css/general.css @@ -0,0 +1,192 @@ +/* +#525356 +*/ + + + +* { + margin:0; +} + +body { + text-align: center; + font-family:arial,sans-serif; + margin-top: 15px; + margin-bottom: 15px; + color:#AEAEAE; +} + +a { + text-decoration:none; + color: #AEAEAE; +} + +table +{ + border-style:none; + padding:0px; + border-collapse: collapse; + border-spacing: 0; + +} + +img{ + border:0px; + margin: 2px 2px 2px 2px; +} + +button +{ +background : none; +cursor : pointer; +border: 0px; +margin : 0px; +padding : 0px; +} + +.button +{ +cursor : pointer; +} + +#heading_tbl { + width: 400px +} + +#frame { + text-align: left; + border: 1px solid #000; + width: 400px; + background:url(../images/bg.png) no-repeat #251616; + margin: 0 auto; +} + + +#nowplaying_heading { + font-size: 1.3em; + font-wieght: bold; + height: 30px; + background: url(../images/control_bg.png) repeat-x; + border-bottom: 1px solid #525356; +} + +#nowplaying_content { + margin: 10px 5px 10px 5px; + text-align: center; + border: 1px solid #525356; + width: 380px; + padding: 30px 0px 30px 0px; + background:url(../images/playing_bg.png); + font-weight: bold; + color: #fff; +} + +#control_buttons { + text-align:center; + width: 390px; + margin: 10px 5px 10px 5px; +} + +#control_buttons table { + margin-left:auto; + margin-right:auto; +} + + +#control_volume { + text-align:center; + width: 390px; + margin: 10px 5px 10px 5px; +} + +#control_volume table { + margin-left:auto; + margin-right:auto; +} + +#playlist_menu { + font-wieght: bold; + height: 24px; + background: url(../images/control_bg.png) repeat-x; + border-top: 2px solid #525356; + margin-top:5px; + margin-bottom:5px; +} + +#items_heading { + text-align: center; + font-size: 1.0em; + font-weight:bold; + border-bottom: 1px solid #525356; + border-top: 1px solid #525356; + background-color: #333; +} + +#home { + text-align: left; + font-size: 1.0em; + font-weight:bold; + border-bottom: 3px solid #525356; + background-color: #251616; +} + +#items { + font-size: 0.9em; + text-align: center; + min-height: 400px; + background:url(../images/playing_bg.png); +} + +#items table { + width: 390px; + margin: 0px 5px 0px 5px; + border: 1px solid #525356; +} + +#file { + text-align: left; + width: 100%; + +} + + +#itemEven{ + background-color: #251616; + +} + +#itemOdd{ + background-color: #333; +} + +#itemActive { + background: url(../images/playing_bg.png); + color: #fff; +} + +#itemActive a { + color: #fff; +} + + +#move img { + margin: 1px 1px 1px 1px; +} + +#remove img { + margin: 1px 1px 1px 1px; +} + + +#volume_total { + width: 100px; + border: 1px solid #525356; + height: 5px; +} + + +#volume_actual { + background-color: #d9600c; + height:5px; +} + diff --git a/images/addall.png b/images/addall.png new file mode 100755 index 0000000000000000000000000000000000000000..fa3983ed6d71921d29f1cf179123d0770f41edd0 GIT binary patch literal 1267 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 WE!2iqN4B~E0000 literal 0 HcmV?d00001 diff --git a/images/control_bg.png b/images/control_bg.png new file mode 100755 index 0000000000000000000000000000000000000000..685abbb544e988011461ec299e0b13dd1271501d GIT binary patch literal 414 zcmeAS@N?(olHy`uVBq!ia0vp^AhsL_6Of!GE|CtT7>k44ofy`glX(f`a29w(7Bet# z3xhBt!>lS|xv6<2KrRD=b5UwyNotBh zd1gt5g1e`0K#E=}JJ4`;PZ!4!jq|mW9gA2DIhdoP{}_hueDc3uB7iU9{Ejl=`5Sb( z8++>Z?cX3MfBp5HE=H~v&Tz&Z{Cf+INhp2a%5$i0lWQ7Ra%HTygn`gQpYv;Zgtktd zb>fUKkIBwJ`~EXhhm>D3EHc`7F(vQdWI3hJvo?H8Sg6^%Vs%yeJ02skh>26v{YsQY zr|x{hr5GICayK{g%f_fRvQtz4q)pv8;qj^N#LJN)?{>AWIw^2>pQ@VHYftmAtY2a? zD>a-rcApLli8fNbue4QmcFyObK#78oWwzEcg}h~7)a~_&ICds|)f(N>iPh2)H|xId zJaR3)AtJ)Q?$Z3^59g=M`2M4`-T!2EOkB;peU^V%P4ymjZF{y_1{7AFu6{1-oD!M< DZE2k~ literal 0 HcmV?d00001 diff --git a/images/down.png b/images/down.png new file mode 100755 index 0000000000000000000000000000000000000000..e8f3d6efecabce05623878a5cdad9f9e060370d1 GIT binary patch literal 1344 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 DLEN1v literal 0 HcmV?d00001 diff --git a/images/next.png b/images/next.png new file mode 100755 index 0000000000000000000000000000000000000000..fc2c7911f6ec242288328a7a3baaa625016ad4c1 GIT binary patch literal 1267 zcmVPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipr8 z6DlyPiy;dD0013nR9JLFZ*6U5Zgc_CX>@2HM@dakWG-a~000C^ zNklWQ!2bpc;FF=K63 zR%fe%nc#|X6^tUdm;y6l`k9~H*ucwQ?Xkjfn~kaBP^<_>3vg*Fpm_}8#^-)^*989e z_zPAsN)o$T5EW1wGm9yhQjv%=P4*g-3L>oA^Q&7C_@86XTjj8lbM2!Gjo=3JyKr?C zGGHOSX%!?UDJT`z&;C*3^@`5rqtBX(MD{OQVnCwj!rL2d1h_D=>@>Zn-w1H@sCxRFwzGQky{vigAl9EoV+NCehWv~} zL~_4Iq6ctk;c=5}q%mL`@}#f=a2hic0QxuI!PK9GBz8s6F{U6SdNd3XceSu3pVHaqCuYdh8IoYKoZi z#bQ8JP&Ldz4SJHDND)<$iJBsn*p<~OAI!9~>P>Fi#)hYk;#RFeRS*mT6cEk8DxMg8 z#Wn^s49l#v6{L>Am&w%$zWHu8JpCn1tV1*dX3)eqROuhXFlAy^z+xbFFfLRv)vF#b zQ@3wt!vN}AQCee#R|hg7Lli=^&s7CrvrZwTNlZ2)s=N?)T-Yb7x~ zO)$x;vI4M1k4d~LV~s-wi}Rd2{wgMlkw9IJwJ*V^+FUX&m{hg8ld)xI9Vd-RVCmGy zoISQ59bU#2c9s$hpr4!wYJ!vE6jHQyrjD@D3~F?$vGmJf&U~>S9S+KqsBPMp=s`13 zzFC;X^3b!{N}V&a&RC=8 z(&8abAK6D-9;B_4_pVwkqZPKkiR%Nz=s{8zSGSIp(^bhC+5kPw=_9kq@=~?dR*`MX z-2>Qm;IfOkJgP)gtr2CH)T$s?254C3;^JX`|8$n{-%?qbBrBpdrebi{TPYX&RT+#` zltr56eb*&5!1+^$7!JPx#24YJ`L;wH)0002_L%V+f000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipr8 z6CMKCc7uEX0013nR9JLFZ*6U5Zgc_CX>@2HM@dakWG-a~000Ad zNkl zh)5z55J{_@t%8Usq==%~J2S^(?#JGJd*6HH!sG3GcXrOqnKQF@1xK#=`bB~U&;d8J zYwfP@dErYr#-AJpJSAPjF|C2R12C`#vD`D9IrpvH74U!8PPxvC%WU018l>#IfhfUg z1V+QXFWr=*f&cyH0*m8yHgt!;!4ixYaO)ZHya&U5uly(nf&cmXJX=OVu`GgUK(R+^ z1XCGN2tDjwg9S6(f8l2t0{{Kht85M%ouEN-UFiza^KV;}Kr8k17G$}XZg}w0FR}xC z`|8VN&1fl_024O=;gmGMf?8D2Om_i=1J*=Y1p4sXe+U3f1=w|to2hV%n;$rLb*KKf zK0BLBU=R;x=!S=0`)SAauPcum{Pzkn>JTvY8iw|BY-`1OR2R79AX9^1xZE#+#MQ|rMdN@ zTUWc0Qv2cJpy{?P0c22SiPRR62Ub6=2EV6hJ%!7phyvAsUS8<|&J7p#frG+iF_^@LFRHu{aH4t#0mvx~X

4{WB=9$thihExyD~cgfX6T27R^r?H-$TEeYU7}&mV^K zku6J>Y)n1ze)K?Xgqv?gKxE9*nu+W>TmRS9e9=CT-MuG2SOEjT4{w4?;H4hw1X@g= zE{K(a1wA+bJaq*!JnVh{Mh4%aPF5_iKfTFfE_V(Hoc$1T@OXRUQpe7|jyc%N0Pyrj zIDEV<>$}$%zIe<#$F|usALIA~{c>GD?X&MhRvgGm0|cJ^1b6oevtHLOX4MbGR&?>) cr^osHA7(GhFe|?7h5!Hn07*qoM6N<$f`V|-vj6}9 literal 0 HcmV?d00001 diff --git a/images/play.png b/images/play.png new file mode 100755 index 0000000000000000000000000000000000000000..3591973ab0e556be7483d5cc4bba8d2d080f4a46 GIT binary patch literal 1281 zcmV+c1^)VpP)Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipr8 z5;YWC5TSDb0013nR9JLFZ*6U5Zgc_CX>@2HM@dakWG-a~000D7 zNkl z@0|0-VZ^JR-A7OX8eob%mezQD&sT1g^W6G?)1*l_n3_S&04UgyDCZRYXHK{c0be~n z&8}4}tu+OyaB1EYL?S1F7!{kJJLN_OzVh8(rh~iI&DAk%n6;AmmJN$`RyuHSpctqHvR%}dM&W_N-LM@8?(tr)v$ z8&*z#4re}lAp$1X(=y4lm!`O3|Jeqwmj;8cpQmXJRS(k|CN)fJP<cE@=(;~Ko1*j(Bsy@bV*#)Y{ zm6Pv-=8L$-5TMwT+-*^)rNs+hKF!43#DnHx(E^h?Jd1BOy0LLg-1a#7Q*XmmpwTkZ z8m2xzho6Xt`8vGwE4Xm5&&FcY$hyc^CWdKj0+LxAW8>)Gz8h4*(vJrK^+lTHv`S(m z70{r30I2@?VmE_TWzJ@Cl_Eg_3;?d0z~t5^KoeX(@h(8gE^UMtGa=SOZOM__b7B3a&C2CqzgQ&+Qs+np!8 zTiey?@{8wj?z3Gm5@d{L3I_u^Bos;%g$j0A=O z`^)F?`{A9?!F-5>8{T`nJ1dnMun3e=fYLO5CPHoq=wKed9h!n)x{v|OWgLPW$GyAX zn{%3Kta^ynP#-#qi3dfXV9;A}s9&1LnVIcaS(<|(_J{5-rmYcBhPxSX?+0)d0EpCp zW|yuikI{uJK!5#sC;Z~vP;1Kkb$NTs89e~F@8H0R#15hYGqzbqieEs&JE?;8GNyb|x{-0ip;6w72uHyx^bH){Qxpe@62M@um z`}g*T{Vnf+BYYKHYt2K4;YR*L|NSe)Ssdk?WB9U%kHBr{6J~b0ZT-+z=Q=UMY9p4vKzlPY7E*|@Iv@`z)@_c!O1F`g000000NkvXXu0mjfU07JK literal 0 HcmV?d00001 diff --git a/images/playing_bg.png b/images/playing_bg.png new file mode 100755 index 0000000000000000000000000000000000000000..f2e2337aef06dcee8986d39bc3aaeb257dbbb13f GIT binary patch literal 19970 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 literal 0 HcmV?d00001 diff --git a/images/plus.png b/images/plus.png new file mode 100755 index 0000000000000000000000000000000000000000..b72d57908a97ef7f31df90d88308ced748811ac9 GIT binary patch literal 1055 zcmV+)1mOFLP)Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipr8 z696dJjCFMY0013nR9JLFZ*6U5Zgc_CX>@2HM@dakWG-a~000Aa zNkl}Q3yT0ca12R;qLR_%SOk4U45S2U=Jr~keXMz;`lSy)}r+12MXygppVSaSuC_Ox(&6>4Vu`$tbR5FWs_fL`F0f$JF0T7tD6 zY;atrh?v%h=?Ja+Ohkz=j-4YBH>)2CIxg5P%3k z0)uIR(BKVK6BG@!RL4l578w@+1~G%@@&i|kwgzm7l8M-hJKPQT?SGA19VcG-W8>Nn zmt?JJ3|7V|x134-s0JNi_1v5fZe{ALQy!0a7yuyv0+awTOpU{|3+#VlOaY|Mr%-ps zdgP9s;Y>Jb3-aA-_Y%($PPi#GG zu)crvO4t0F_`iG!B$uzB%n6$-xVA%b!7_oz-iBY Z{{g3S=OS4a(t7{^002ovPDHLkV1mMC(^3Ec literal 0 HcmV?d00001 diff --git a/images/prev.png b/images/prev.png new file mode 100755 index 0000000000000000000000000000000000000000..aedbbdff733b6918e27babffbdb556545b55b8c4 GIT binary patch literal 1390 zcmV-!1(EuRP)Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipr8 z5H=wt3gZ0$0013nR9JLFZ*6U5Zgc_CX>@2HM@dakWG-a~000EV zNklD&R{9?3X$t2~8Za?n1jgPW9QU_U zB%kVnL_N;Tqa;@Ls6_)y?usz=Js=d${EPr92vi16lP3VO)sOCY)}gVOZFFG z@+gJVXFvo&VyRtt&OJHe6W%^`0_v*v z0btFI4hl1u(2i^9i2E!$pv~BSIu`cEH>rPjl2qp#zO83dR_)BZBgUTt;DfsHw}x4GuA=V*E9 zFv_wPY;9tMBb6eKVN#j8Vo7R^uRbl19Xrak11-#4{b6BXps0;{op^ESm@idpuvA00 ze_cGo!psDJf8NVKU+qG4ao!wjG2j()9KD)F0qVQ4RLf4*X3QOqoNV%sBmDVcGt;Br z&6{H#6j|gR7bW0VV08wp=ABsCyD3+l=Bpz`p)fnm_5SC%-v0tlVYZBFFN!#-wSd-P z%Ef`~-4s@1$8M$4?KloNIuL<`S(v!|Ef+s{go%qs$_j|LuTqYK6;7qwY3SIkEP&*O zgFKNjQAg+wZqCm=;OZB<82hvrr!ea})Fr0kavUtdk7vMcKj_wK0K2tUsoHkdXUg;J zi$Z%26!)+E$ocn|GIebPjpaLzrP_SgW!z}()?O9rIpe4MrTW%hem`mMnwtL=)T_NJ z*!QCAf!`fHFuS~;wyk?rSqIGD9FUpQeOwqWiATkBM+xlo8;OdPPE~TSu?K3l43Jvc z=erA)r_{<(7$`9Qye=ua7-Q#+JG!B&^H2!1V$YxZYe2H6`T#gT9H_S{ zh6V|z##`QO-tW`f2dG-rSB4W?kgHbrsod&*th#nKbp@0gWx=Sn7^!@nMo76;{js2n z`U^96`@~ literal 0 HcmV?d00001 diff --git a/images/previous.png b/images/previous.png new file mode 100755 index 0000000000000000000000000000000000000000..9c49139402bce1a85c361308cbeec2beee0fa27c GIT binary patch literal 1268 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 LNkvXXu0mjfBYFFC literal 0 HcmV?d00001 diff --git a/images/repeatoff.png b/images/repeatoff.png new file mode 100755 index 0000000000000000000000000000000000000000..0a1765992ec3b5bf732555cc5b6cc96fbf0e89ab GIT binary patch literal 1671 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 D-FhW7 literal 0 HcmV?d00001 diff --git a/images/right.png b/images/right.png new file mode 100755 index 0000000000000000000000000000000000000000..2ce6d362c8e0db8625512ce8e779182771e437b8 GIT binary patch literal 1352 zcmV-O1-JT%P)Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipr8 z5;g*a=||xJ0013nR9JLFZ*6U5Zgc_CX>@2HM@dakWG-a~000D^ zNklrD#@@Cf(Ux4ULp!YG%>15Bea2q6GCJLB<(B24^&#bM{)RhrRbX``)?cG;O%teec8$3Am&vFEN2xXny`Fl6 zUcgsJwpq7VmV2v$nc&iM6^umA2Vy1+J@vhtGw_vzTPzvw_Qq6kD3-`*0+-GRXncln z!!y6S>jGc?@;R$L3L$nGi5e(8GxLE=6%mg!4eQm1D2T9V%Q1IN;7eaTYqh~ToS5KZ zUQIn_0f^=R6w?)83cYDfGVL`L7H|K{%>thO{Ashwqg*rr%&7pusF{EWu73zObTfMX zSe^d_ih|UlOafiHbKC*660rIrY&MTdmfOsOq~?$U!To)ef!iOU@CADAk02=Z6+!ZF zYZPi64S>l5kDEw|`We)hn3kxNs4oK{jq|do)~GKLUrdmr!22TII`P=$AhEDXp7UGjr-FQ-}B9FC4G;Cf%eu$H1VazNif5jiE8H zgx2B}@qYtiw=%_4fiQ0_SdQy!)97n6aLWc3ZrsD;bT~%+m<{+-G9R$-i#K6jpEZX!clOwzE=T8Q>ylA7oS}Fx5 zq3bx+NWg<@(rho`zm7)#FzwqO!XDVm`GYSa7f*$Nbv2Ealtq=>lxH(R#WUa0=pSb2 zj)##elbrkNC2Zzmh?T3sTPh{BxZ=0QI{Y6)u3qHwiBZa#so02V?>a8y33ZT(!Gq`*${?b{-M_=RIj~S@- zK#udqn%$?Jq#i3JUJ9fvk=W+Udjw0p162?MwJ`5rwg!`evC-F=_-;Qc8qNw0VO7G~ ze9xV4;aULR7a&|t4DE*V^>9&(pEu0G$s5UM5t=aEf6EbBgI(Q@{DR%o*&_r8m}=4J2bjtJhP zF<5T3`^<=h%z9WhxbHpOb+5NyZ|{iQtQzcfRsFX$_wU2a`9gpA`OKEh<(;GVvQ6*f z=Jg75Xj`ZEd8t$eT$ct69{hm$y~1>lk*#&7?j^RQi_QDzX7eAk6JhH3`5$Wl0000< KMNUMnLSTZs5`B#T literal 0 HcmV?d00001 diff --git a/images/songs.png b/images/songs.png new file mode 100755 index 0000000000000000000000000000000000000000..f24c1ef0c2fb12441701751bc13b3960a41bc59b GIT binary patch literal 1353 zcmV-P1-AN$P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipr8 z6B7uH4HPc`0013nR9JLFZ*6U5Zgc_CX>@2HM@dakWG-a~000D_ zNkl3{-#uTt zvjVPf8?pARtjHE{y~CJuI8$u$cTmA7f(tP)69yjm&dnNlX6qw{3TBrZ1DYPD29|9|H*~5Fhs* z-?Y%W0#ALi+B8L|5;v;kO{YF@G9bQ+i-tzr7d+w%0LJVg7m5a(UCD+$Wx3^TamIeHe}kV?@;wRl7V1J|r$VEG1w z8qyL#QHJ;zpmyZ_J1k~Z?OBbjq{4Ya3z@roJ+*n4(sSYEH;i+R#(`ag`U%Veh{Pe2RN)+$f&25Fo6MP@MO1~LOfZSr*9I0a zZ{^$6h8D#P^C{e%L7aqv3rc3p+%g3^%}CCW{pjigJUbHkM99s@o4LW{AInvS)|!qWIL-)8A&s?-6X9M z-{A1}XPDmmb*z7~zrT2jsXbqz#BAEl62(HITMMdvbHIylbkZ2&0FdAjKh1#;S5rUq zBc{rU@5dPb_SKTsZoq1hW~~I5j-&wEEqG5TrcVg?ljH2)d_R*vZQ;PjYY-g>DYMXi^hL3(K6B2uhUhdQ!XR{X+^E) z%8E?IVA;#DD9!J20yN`)0dB8KqoJYsO_4(T`}pKi^HO`SNWJkalWtoo&&&2NtG%Wiy~*&pbu zwtb{E`x3+|4k{^|iv#B7H#obWFzvQ&ZFF5`RRv0cIN;VdXXo=@bMIcqwupUK00000 LNkvXXu0mjfNECkc literal 0 HcmV?d00001 diff --git a/images/stop.png b/images/stop.png new file mode 100755 index 0000000000000000000000000000000000000000..1e1dd0fd767364a149f45df1c568dbc5dff85065 GIT binary patch literal 938 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 != 1){ + echo "Not Connected to Server"; + exit(1); +} + +$task=$_REQUEST['task']; + +include('view/default/view.php'); + +?> diff --git a/model/player.php b/model/player.php new file mode 100644 index 0000000..ff3fc0d --- /dev/null +++ b/model/player.php @@ -0,0 +1,44 @@ +Play(); + break; + + case("prev"): + $mpd->Previous(); + break; + + case("pause"): + $mpd->Pause(); + break; + + case("stop"): + $mpd->Stop(); + break; + + case("next"): + $mpd->Next(); + break; + + case("vold"): + $mpd->AdjustVolume(-3); + break; + case("volu"): + $mpd->AdjustVolume(+3); + break; + + case("update"): + $mpd->DBRefresh(); + break; + + case("repeat"): + $repeat = $mpd->repeat; + if($repeat==1) + $mpd->SetRepeat(0); + else + $mpd->SetRepeat(1); + break; +} +?> diff --git a/model/tracklist.php b/model/tracklist.php new file mode 100644 index 0000000..798ca01 --- /dev/null +++ b/model/tracklist.php @@ -0,0 +1,100 @@ +GetDir($current); + for($i=0;$iPLAdd($files[$i]['name']); + } + + } + } +} + +switch($task) { + + case("remove"): + if($item != null) + $mpd->PLRemove($item); + break; + + + case("clear"): + $mpd->PLClear(); + break; + + case("playitem"): + if($item != null){ + $mpd->SkipTo($item); + } + break; + + case("addfile"): + $mpd->PLAdd($item); + break; + + case("adddir"): + addDir($item,$mpd); + break; + + + case("moveup"): + if($item !=0) { + $mpd->Move($item,$item-1); + } + break; + + case("movedown"): + if($item !=count($mpd->playlist)-1) { + $mpd->Move($item,$item+1); + } + break; + + + case("removeselected"): + $items=$_POST['itemlist']; + for($i=0;$iPLRemove($items[$i]-$i); + } + break; + + + case("addselected"): + $items=$_POST['itemlist']; + $dir=$_REQUEST['dir']; + $files = $mpd->GetDir($dir); + for($i=0;$iPLAdd($files[$items[$i]]['name']); + } + } + break; + + case("addall"): + $dir=$_REQUEST['item']; + $files = $mpd->GetDir($dir); + for($i=0;$iPLAdd($files[$i]['name']); + } + } + break; + + + +} + + +?> diff --git a/system/helper.php b/system/helper.php new file mode 100644 index 0000000..10009e4 --- /dev/null +++ b/system/helper.php @@ -0,0 +1,35 @@ + diff --git a/system/mpd_class.php b/system/mpd_class.php new file mode 100644 index 0000000..8ffddcd --- /dev/null +++ b/system/mpd_class.php @@ -0,0 +1,976 @@ +host = $srv; + $this->port = $port; + $this->password = $pwd; + + $resp = $this->Connect(); + if ( is_null($resp) ) { + $this->errStr = "Could not connect"; + return; + } else { + list ( $this->mpd_version ) = sscanf($resp, MPD_RESPONSE_OK . " MPD %s\n"); + if ( ! is_null($pwd) ) { + if ( is_null($this->SendCommand(MPD_CMD_PASSWORD,$pwd)) ) { + $this->connected = FALSE; + return; // bad password or command + } + if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected! + $this->connected = FALSE; + $this->errStr = "Password supplied does not have read access"; + return; + } + } else { + if ( is_null($this->RefreshInfo()) ) { // no read access -- might as well be disconnected! + $this->connected = FALSE; + $this->errStr = "Password required to access server"; + return; + } + } + } + } + + /* Connect() + * + * Connects to the MPD server. + * + * NOTE: This is called automatically upon object instantiation; you should not need to call this directly. + */ + function Connect() { + if ( $this->debugging ) echo "mpd->Connect() / host: ".$this->host.", port: ".$this->port."\n"; + $this->mpd_sock = fsockopen($this->host,$this->port,$errNo,$errStr,10); + if (!$this->mpd_sock) { + $this->errStr = "Socket Error: $errStr ($errNo)"; + return NULL; + } else { + while(!feof($this->mpd_sock)) { + $response = fgets($this->mpd_sock,1024); + if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) { + $this->connected = TRUE; + return $response; + break; + } + if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) { + $this->errStr = "Server responded with: $response"; + return NULL; + } + } + // Generic response + $this->errStr = "Connection not available"; + return NULL; + } + } + + /* SendCommand() + * + * Sends a generic command to the MPD server. Several command constants are pre-defined for + * use (see MPD_CMD_* constant definitions above). + */ + function SendCommand($cmdStr,$arg1 = "",$arg2 = "") { + if ( $this->debugging ) echo "mpd->SendCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2."\n"; + + if ( ! $this->connected ) { + echo "mpd->SendCommand() / Error: Not connected\n"; + } else { + // Clear out the error String + $this->errStr = ""; + $respStr = ""; + + // Check the command compatibility: + if ( ! $this->_checkCompatibility($cmdStr) ) { + echo "Not compatible command!"; + return NULL; + } + + if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\""; + + if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\""; + if ( $this->debugging ) echo "mpd-> ".$cmdStr."\n"; + fputs($this->mpd_sock,"$cmdStr\n"); + while(!feof($this->mpd_sock)) { + $response = fgets($this->mpd_sock,1024); + if ( $this->debugging ) echo "mpd.response-> ".$response."\n"; + + // An OK signals the end of transmission -- we'll ignore it + if (strncmp(MPD_RESPONSE_OK,$response,strlen(MPD_RESPONSE_OK)) == 0) { + break; + } + + // An ERR signals the end of transmission with an error! Let's grab the single-line message. + if (strncmp(MPD_RESPONSE_ERR,$response,strlen(MPD_RESPONSE_ERR)) == 0) { + list ( $junk, $errTmp ) = explode(MPD_RESPONSE_ERR . " ",$response ); + $this->errStr = strtok($errTmp,"\n"); + } + + if ( strlen($this->errStr) > 0 ) { + return NULL; + } + + // Build the response string + $respStr .= $response; + } + if ( $this->debugging ) echo "mpd->SendCommand() / response: '".$respStr."'\n"; + } + return $respStr; + } + + /* QueueCommand() + * + * Queues a generic command for later sending to the MPD server. The CommandQueue can hold + * as many commands as needed, and are sent all at once, in the order they are queued, using + * the SendCommandQueue() method. The syntax for queueing commands is identical to SendCommand(). + */ + function QueueCommand($cmdStr,$arg1 = "",$arg2 = "") { + if ( $this->debugging ) echo "mpd->QueueCommand() / cmd: ".$cmdStr.", args: ".$arg1." ".$arg2."\n"; + if ( ! $this->connected ) { + echo "mpd->QueueCommand() / Error: Not connected\n"; + return NULL; + } else { + if ( strlen($this->command_queue) == 0 ) { + $this->command_queue = MPD_CMD_START_BULK . "\n"; + } + if (strlen($arg1) > 0) $cmdStr .= " \"$arg1\""; + if (strlen($arg2) > 0) $cmdStr .= " \"$arg2\""; + + $this->command_queue .= $cmdStr ."\n"; + + if ( $this->debugging ) echo "mpd->QueueCommand() / return\n"; + } + return TRUE; + } + + /* SendCommandQueue() + * + * Sends all commands in the Command Queue to the MPD server. See also QueueCommand(). + */ + function SendCommandQueue() { + if ( $this->debugging ) echo "mpd->SendCommandQueue()\n"; + if ( ! $this->connected ) { + echo "mpd->SendCommandQueue() / Error: Not connected\n"; + return NULL; + } else { + $this->command_queue .= MPD_CMD_END_BULK . "\n"; + if ( is_null($respStr = $this->SendCommand($this->command_queue)) ) { + return NULL; + } else { + $this->command_queue = NULL; + if ( $this->debugging ) echo "mpd->SendCommandQueue() / response: '".$respStr."'\n"; + } + } + return $respStr; + } + + /* AdjustVolume() + * + * Adjusts the mixer volume on the MPD by , which can be a positive (volume increase), + * or negative (volume decrease) value. + */ + function AdjustVolume($modifier) { + if ( $this->debugging ) echo "mpd->AdjustVolume()\n"; + if ( ! is_numeric($modifier) ) { + $this->errStr = "AdjustVolume() : argument 1 must be a numeric value"; + return NULL; + } + + $this->RefreshInfo(); + $newVol = $this->volume + $modifier; + $ret = $this->SetVolume($newVol); + + if ( $this->debugging ) echo "mpd->AdjustVolume() / return\n"; + return $ret; + } + + /* SetVolume() + * + * Sets the mixer volume to , which should be between 1 - 100. + */ + function SetVolume($newVol) { + if ( $this->debugging ) echo "mpd->SetVolume()\n"; + if ( ! is_numeric($newVol) ) { + $this->errStr = "SetVolume() : argument 1 must be a numeric value"; + return NULL; + } + + // Forcibly prevent out of range errors + if ( $newVol < 0 ) $newVol = 0; + if ( $newVol > 100 ) $newVol = 100; + + // If we're not compatible with SETVOL, we'll try adjusting using VOLUME + if ( $this->_checkCompatibility(MPD_CMD_SETVOL) ) { + if ( ! is_null($ret = $this->SendCommand(MPD_CMD_SETVOL,$newVol))) $this->volume = $newVol; + } else { + $this->RefreshInfo(); // Get the latest volume + if ( is_null($this->volume) ) { + return NULL; + } else { + $modifier = ( $newVol - $this->volume ); + if ( ! is_null($ret = $this->SendCommand(MPD_CMD_VOLUME,$modifier))) $this->volume = $newVol; + } + } + + if ( $this->debugging ) echo "mpd->SetVolume() / return\n"; + return $ret; + } + + /* GetDir() + * + * Retrieves a database directory listing of the

directory and places the results into + * a multidimensional array. If no directory is specified, the directory listing is at the + * base of the MPD music path. + */ + function GetDir($dir = "") { + if ( $this->debugging ) echo "mpd->GetDir()\n"; + $resp = $this->SendCommand(MPD_CMD_LSDIR,$dir); + $dirlist = $this->_parseFileListResponse($resp); + if ( $this->debugging ) echo "mpd->GetDir() / return ".print_r($dirlist)."\n"; + return $dirlist; + } + + /* PLAdd() + * + * Adds each track listed in a single-dimensional , which contains filenames + * of tracks to add, to the end of the playlist. This is used to add many, many tracks to + * the playlist in one swoop. + */ + function PLAddBulk($trackArray) { + if ( $this->debugging ) echo "mpd->PLAddBulk()\n"; + $num_files = count($trackArray); + for ( $i = 0; $i < $num_files; $i++ ) { + $this->QueueCommand(MPD_CMD_PLADD,$trackArray[$i]); + } + $resp = $this->SendCommandQueue(); + $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->PLAddBulk() / return\n"; + return $resp; + } + + /* PLAdd() + * + * Adds the file to the end of the playlist. must be a track in the MPD database. + */ + function PLAdd($fileName) { + if ( $this->debugging ) echo "mpd->PLAdd()\n"; + if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLADD,$fileName))) $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->PLAdd() / return\n"; + return $resp; + } + + /* PLMoveTrack() + * + * Moves track number to position in the playlist. This is used to reorder + * the songs in the playlist. + */ + function PLMoveTrack($origPos, $newPos) { + if ( $this->debugging ) echo "mpd->PLMoveTrack()\n"; + if ( ! is_numeric($origPos) ) { + $this->errStr = "PLMoveTrack(): argument 1 must be numeric"; + return NULL; + } + if ( $origPos < 0 or $origPos > $this->playlist_count ) { + $this->errStr = "PLMoveTrack(): argument 1 out of range"; + return NULL; + } + if ( $newPos < 0 ) $newPos = 0; + if ( $newPos > $this->playlist_count ) $newPos = $this->playlist_count; + + if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLMOVETRACK,$origPos,$newPos))) $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->PLMoveTrack() / return\n"; + return $resp; + } + + /* PLShuffle() + * + * Randomly reorders the songs in the playlist. + */ + function PLShuffle() { + if ( $this->debugging ) echo "mpd->PLShuffle()\n"; + if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLSHUFFLE))) $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->PLShuffle() / return\n"; + return $resp; + } + + /* PLLoad() + * + * Retrieves the playlist from .m3u and loads it into the current playlist. + */ + function PLLoad($file) { + if ( $this->debugging ) echo "mpd->PLLoad()\n"; + if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLLOAD,$file))) $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->PLLoad() / return\n"; + return $resp; + } + + /* PLSave() + * + * Saves the playlist to .m3u for later retrieval. The file is saved in the MPD playlist + * directory. + */ + function PLSave($file) { + if ( $this->debugging ) echo "mpd->PLSave()\n"; + $resp = $this->SendCommand(MPD_CMD_PLSAVE,$file); + if ( $this->debugging ) echo "mpd->PLSave() / return\n"; + return $resp; + } + + /* PLClear() + * + * Empties the playlist. + */ + function PLClear() { + if ( $this->debugging ) echo "mpd->PLClear()\n"; + if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLCLEAR))) $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->PLClear() / return\n"; + return $resp; + } + + + /* PLMove() + * + * Move song from pos to the other + */ + function Move ($from,$to) { + if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLMOVETRACK,$from,$to))) $this->RefreshInfo(); + //die(print_r($resp)); + + } + + + /* PLRemove() + * + * Removes track from the playlist. + */ + function PLRemove($id) { + if ( $this->debugging ) echo "mpd->PLRemove()\n"; + if ( ! is_numeric($id) ) { + $this->errStr = "PLRemove() : argument 1 must be a numeric value"; + return NULL; + } + if ( ! is_null($resp = $this->SendCommand(MPD_CMD_PLREMOVE,$id))) $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->PLRemove() / return\n"; + return $resp; + } + + /* SetRepeat() + * + * Enables 'loop' mode -- tells MPD continually loop the playlist. The parameter + * is either 1 (on) or 0 (off). + */ + function SetRepeat($repVal) { + if ( $this->debugging ) echo "mpd->SetRepeat()\n"; + $rpt = $this->SendCommand(MPD_CMD_REPEAT,$repVal); + $this->repeat = $repVal; + if ( $this->debugging ) echo "mpd->SetRepeat() / return\n"; + return $rpt; + } + + /* SetRandom() + * + * Enables 'randomize' mode -- tells MPD to play songs in the playlist in random order. The + * parameter is either 1 (on) or 0 (off). + */ + function SetRandom($rndVal) { + if ( $this->debugging ) echo "mpd->SetRandom()\n"; + $resp = $this->SendCommand(MPD_CMD_RANDOM,$rndVal); + $this->random = $rndVal; + if ( $this->debugging ) echo "mpd->SetRandom() / return\n"; + return $resp; + } + + /* Shutdown() + * + * Shuts down the MPD server (aka sends the KILL command). This closes the current connection, + * and prevents future communication with the server. + */ + function Shutdown() { + if ( $this->debugging ) echo "mpd->Shutdown()\n"; + $resp = $this->SendCommand(MPD_CMD_SHUTDOWN); + + $this->connected = FALSE; + unset($this->mpd_version); + unset($this->errStr); + unset($this->mpd_sock); + + if ( $this->debugging ) echo "mpd->Shutdown() / return\n"; + return $resp; + } + + /* DBRefresh() + * + * Tells MPD to rescan the music directory for new tracks, and to refresh the Database. Tracks + * cannot be played unless they are in the MPD database. + */ + function DBRefresh() { + if ( $this->debugging ) echo "mpd->DBRefresh()\n"; + $resp = $this->SendCommand(MPD_CMD_REFRESH); + + // Update local variables + $this->RefreshInfo(); + + if ( $this->debugging ) echo "mpd->DBRefresh() / return\n"; + return $resp; + } + + /* Play() + * + * Begins playing the songs in the MPD playlist. + */ + function Play() { + if ( $this->debugging ) echo "mpd->Play()\n"; + if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY) )) $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->Play() / return\n"; + return $rpt; + } + + /* Stop() + * + * Stops playing the MPD. + */ + function Stop() { + if ( $this->debugging ) echo "mpd->Stop()\n"; + if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_STOP) )) $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->Stop() / return\n"; + return $rpt; + } + + /* Pause() + * + * Toggles pausing on the MPD. Calling it once will pause the player, calling it again + * will unpause. + */ + function Pause() { + if ( $this->debugging ) echo "mpd->Pause()\n"; + if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PAUSE) )) $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->Pause() / return\n"; + return $rpt; + } + + /* SeekTo() + * + * Skips directly to the song in the MPD playlist. + */ + function SkipTo($idx) { + if ( $this->debugging ) echo "mpd->SkipTo()\n"; + if ( ! is_numeric($idx) ) { + $this->errStr = "SkipTo() : argument 1 must be a numeric value"; + return NULL; + } + if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PLAY,$idx))) $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->SkipTo() / return\n"; + return $idx; + } + + /* SeekTo() + * + * Skips directly to a given position within a track in the MPD playlist. The argument, + * given in seconds, is the track position to locate. The argument, if supplied is + * the track number in the playlist. If is not specified, the current track is assumed. + */ + function SeekTo($pos, $track = -1) { + if ( $this->debugging ) echo "mpd->SeekTo()\n"; + if ( ! is_numeric($pos) ) { + $this->errStr = "SeekTo() : argument 1 must be a numeric value"; + return NULL; + } + if ( ! is_numeric($track) ) { + $this->errStr = "SeekTo() : argument 2 must be a numeric value"; + return NULL; + } + if ( $track == -1 ) { + $track = $this->current_track_id; + } + + if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_SEEK,$track,$pos))) $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->SeekTo() / return\n"; + return $pos; + } + + /* Next() + * + * Skips to the next song in the MPD playlist. If not playing, returns an error. + */ + function Next() { + if ( $this->debugging ) echo "mpd->Next()\n"; + if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_NEXT))) $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->Next() / return\n"; + return $rpt; + } + + /* Previous() + * + * Skips to the previous song in the MPD playlist. If not playing, returns an error. + */ + function Previous() { + if ( $this->debugging ) echo "mpd->Previous()\n"; + if ( ! is_null($rpt = $this->SendCommand(MPD_CMD_PREV))) $this->RefreshInfo(); + if ( $this->debugging ) echo "mpd->Previous() / return\n"; + return $rpt; + } + + /* Search() + * + * Searches the MPD database. The search should be one of the following: + * MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM + * The search is a case-insensitive locator string. Anything that contains + * will be returned in the results. + */ + function Search($type,$string) { + if ( $this->debugging ) echo "mpd->Search()\n"; + if ( $type != MPD_SEARCH_ARTIST and + $type != MPD_SEARCH_ALBUM and + $type != MPD_SEARCH_TITLE ) { + $this->errStr = "mpd->Search(): invalid search type"; + return NULL; + } else { + if ( is_null($resp = $this->SendCommand(MPD_CMD_SEARCH,$type,$string))) return NULL; + $searchlist = $this->_parseFileListResponse($resp); + } + if ( $this->debugging ) echo "mpd->Search() / return ".print_r($searchlist)."\n"; + return $searchlist; + } + + /* Find() + * + * Find() looks for exact matches in the MPD database. The find should be one of + * the following: + * MPD_SEARCH_ARTIST, MPD_SEARCH_TITLE, MPD_SEARCH_ALBUM + * The find is a case-insensitive locator string. Anything that exactly matches + * will be returned in the results. + */ + function Find($type,$string) { + if ( $this->debugging ) echo "mpd->Find()\n"; + if ( $type != MPD_SEARCH_ARTIST and + $type != MPD_SEARCH_ALBUM and + $type != MPD_SEARCH_TITLE ) { + $this->errStr = "mpd->Find(): invalid find type"; + return NULL; + } else { + if ( is_null($resp = $this->SendCommand(MPD_CMD_FIND,$type,$string))) return NULL; + $searchlist = $this->_parseFileListResponse($resp); + } + if ( $this->debugging ) echo "mpd->Find() / return ".print_r($searchlist)."\n"; + return $searchlist; + } + + /* Disconnect() + * + * Closes the connection to the MPD server. + */ + function Disconnect() { + if ( $this->debugging ) echo "mpd->Disconnect()\n"; + fclose($this->mpd_sock); + + $this->connected = FALSE; + unset($this->mpd_version); + unset($this->errStr); + unset($this->mpd_sock); + } + + /* GetArtists() + * + * Returns the list of artists in the database in an associative array. + */ + function GetArtists() { + if ( $this->debugging ) echo "mpd->GetArtists()\n"; + if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ARTIST))) return NULL; + $arArray = array(); + + $arLine = strtok($resp,"\n"); + $arName = ""; + $arCounter = -1; + while ( $arLine ) { + list ( $element, $value ) = explode(": ",$arLine); + if ( $element == "Artist" ) { + $arCounter++; + $arName = $value; + $arArray[$arCounter] = $arName; + } + + $arLine = strtok("\n"); + } + if ( $this->debugging ) echo "mpd->GetArtists()\n"; + return $arArray; + } + + /* GetAlbums() + * + * Returns the list of albums in the database in an associative array. Optional parameter + * is an artist Name which will list all albums by a particular artist. + */ + function GetAlbums( $ar = NULL) { + if ( $this->debugging ) echo "mpd->GetAlbums()\n"; + if ( is_null($resp = $this->SendCommand(MPD_CMD_TABLE, MPD_TBL_ALBUM, $ar ))) return NULL; + $alArray = array(); + + $alLine = strtok($resp,"\n"); + $alName = ""; + $alCounter = -1; + while ( $alLine ) { + list ( $element, $value ) = explode(": ",$alLine); + if ( $element == "Album" ) { + $alCounter++; + $alName = $value; + $alArray[$alCounter] = $alName; + } + + $alLine = strtok("\n"); + } + if ( $this->debugging ) echo "mpd->GetAlbums()\n"; + return $alArray; + } + + //*******************************************************************************// + //***************************** INTERNAL FUNCTIONS ******************************// + //*******************************************************************************// + + /* _computeVersionValue() + * + * Computes a compatibility value from a version string + * + */ + function _computeVersionValue($verStr) { + list ($ver_maj, $ver_min, $ver_rel ) = explode("\.",$verStr); + return ( 100 * $ver_maj ) + ( 10 * $ver_min ) + ( $ver_rel ); + } + + /* _checkCompatibility() + * + * Check MPD command compatibility against our internal table. If there is no version + * listed in the table, allow it by default. + */ + function _checkCompatibility($cmd) { + // Check minimum compatibility + $req_ver_low = $this->COMPATIBILITY_MIN_TBL[$cmd]; + $req_ver_hi = $this->COMPATIBILITY_MAX_TBL[$cmd]; + + $mpd_ver = $this->_computeVersionValue($this->mpd_version); + + if ( $req_ver_low ) { + $req_ver = $this->_computeVersionValue($req_ver_low); + + if ( $mpd_ver < $req_ver ) { + $this->errStr = "Command '$cmd' is not compatible with this version of MPD, version ".$req_ver_low." required"; + return FALSE; + } + } + + // Check maxmum compatibility -- this will check for deprecations + if ( $req_ver_hi ) { + $req_ver = $this->_computeVersionValue($req_ver_hi); + + if ( $mpd_ver > $req_ver ) { + $this->errStr = "Command '$cmd' has been deprecated in this version of MPD."; + return FALSE; + } + } + + return TRUE; + } + + /* _parseFileListResponse() + * + * Builds a multidimensional array with MPD response lists. + * + * NOTE: This function is used internally within the class. It should not be used. + */ + function _parseFileListResponse($resp) { + if ( is_null($resp) ) { + return NULL; + } else { + $plistArray = array(); + $plistLine = strtok($resp,"\n"); + $plistFile = ""; + $plCounter = -1; + while ( $plistLine ) { + list ( $element, $value ) = explode(": ",$plistLine); + if($element == "file" || $element=="directory") { + $plCounter++; + $plistArray[$plCounter]['name']=$value; + $plistArray[$plCounter]['type']=$element; + $plistArray[$plCounter]['title']=$value; + } + if($element == "Name") { + $plistArray[$plCounter]['title']=$value; + } + $plistLine = strtok("\n"); + } + } + return $plistArray; + } + + /* RefreshInfo() + * + * Updates all class properties with the values from the MPD server. + * + * NOTE: This function is automatically called upon Connect() as of v1.1. + */ + function RefreshInfo() { + // Get the Server Statistics + $statStr = $this->SendCommand(MPD_CMD_STATISTICS); + if ( !$statStr ) { + return NULL; + } else { + $stats = array(); + $statLine = strtok($statStr,"\n"); + while ( $statLine ) { + list ( $element, $value ) = explode(": ",$statLine); + $stats[$element] = $value; + $statLine = strtok("\n"); + } + } + + // Get the Server Status + $statusStr = $this->SendCommand(MPD_CMD_STATUS); + if ( ! $statusStr ) { + return NULL; + } else { + $status = array(); + $statusLine = strtok($statusStr,"\n"); + while ( $statusLine ) { + list ( $element, $value ) = explode(": ",$statusLine); + $status[$element] = $value; + $statusLine = strtok("\n"); + } + } + + // Get the Playlist + $plStr = $this->SendCommand(MPD_CMD_PLLIST); + $this->playlist = $this->_parseFileListResponse($plStr); + $this->playlist_count = count($this->playlist); + + // Set Misc Other Variables + $this->state = $status['state']; + if ( ($this->state == MPD_STATE_PLAYING) || ($this->state == MPD_STATE_PAUSED) ) { + $this->current_track_id = $status['song']; + list ($this->current_track_position, $this->current_track_length ) = explode(":",$status['time']); + } else { + $this->current_track_id = -1; + $this->current_track_position = -1; + $this->current_track_length = -1; + } + + $this->repeat = $status['repeat']; + $this->random = $status['random']; + + $this->db_last_refreshed = $stats['db_update']; + + $this->volume = $status['volume']; + $this->uptime = $stats['uptime']; + $this->playtime = $stats['playtime']; + $this->num_songs_played = $stats['songs_played']; + $this->num_artists = $stats['num_artists']; + $this->num_songs = $stats['num_songs']; + $this->num_albums = $stats['num_albums']; + return TRUE; + } + + /* ------------------ DEPRECATED METHODS -------------------*/ + /* GetStatistics() + * + * Retrieves the 'statistics' variables from the server and tosses them into an array. + * + * NOTE: This function really should not be used. Instead, use $this->[variable]. The function + * will most likely be deprecated in future releases. + */ + function GetStatistics() { + if ( $this->debugging ) echo "mpd->GetStatistics()\n"; + $stats = $this->SendCommand(MPD_CMD_STATISTICS); + if ( !$stats ) { + return NULL; + } else { + $statsArray = array(); + $statsLine = strtok($stats,"\n"); + while ( $statsLine ) { + list ( $element, $value ) = explode(": ",$statsLine); + $statsArray[$element] = $value; + $statsLine = strtok("\n"); + } + } + if ( $this->debugging ) echo "mpd->GetStatistics() / return: " . print_r($statsArray) ."\n"; + return $statsArray; + } + + /* GetStatus() + * + * Retrieves the 'status' variables from the server and tosses them into an array. + * + * NOTE: This function really should not be used. Instead, use $this->[variable]. The function + * will most likely be deprecated in future releases. + */ + function GetStatus() { + if ( $this->debugging ) echo "mpd->GetStatus()\n"; + $status = $this->SendCommand(MPD_CMD_STATUS); + if ( ! $status ) { + return NULL; + } else { + $statusArray = array(); + $statusLine = strtok($status,"\n"); + while ( $statusLine ) { + list ( $element, $value ) = explode(": ",$statusLine); + $statusArray[$element] = $value; + $statusLine = strtok("\n"); + } + } + if ( $this->debugging ) echo "mpd->GetStatus() / return: " . print_r($statusArray) ."\n"; + return $statusArray; + } + + /* GetVolume() + * + * Retrieves the mixer volume from the server. + * + * NOTE: This function really should not be used. Instead, use $this->volume. The function + * will most likely be deprecated in future releases. + */ + function GetVolume() { + if ( $this->debugging ) echo "mpd->GetVolume()\n"; + $volLine = $this->SendCommand(MPD_CMD_STATUS); + if ( ! $volLine ) { + return NULL; + } else { + list ($vol) = sscanf($volLine,"volume: %d"); + } + if ( $this->debugging ) echo "mpd->GetVolume() / return: $vol\n"; + return $vol; + } + + /* GetPlaylist() + * + * Retrieves the playlist from the server and tosses it into a multidimensional array. + * + * NOTE: This function really should not be used. Instead, use $this->playlist. The function + * will most likely be deprecated in future releases. + */ + function GetPlaylist() { + if ( $this->debugging ) echo "mpd->GetPlaylist()\n"; + $resp = $this->SendCommand(MPD_CMD_PLLIST); + $playlist = $this->_parseFileListResponse($resp); + if ( $this->debugging ) echo "mpd->GetPlaylist() / return ".print_r($playlist)."\n"; + return $playlist; + } + + /* ----------------- Command compatibility tables --------------------- */ + var $COMPATIBILITY_MIN_TBL = array( + ); + + var $COMPATIBILITY_MAX_TBL = array( + ); + +} // ---------------------------- end of class ------------------------------ +?> diff --git a/view/default/tmpl/default.php b/view/default/tmpl/default.php new file mode 100644 index 0000000..269b508 --- /dev/null +++ b/view/default/tmpl/default.php @@ -0,0 +1,29 @@ + + + + + MPD Player + + + + + +
+ + + +
+ +
+
+ +
+ +
+ + + + + diff --git a/view/default/tmpl/playlistmenu.php b/view/default/tmpl/playlistmenu.php new file mode 100644 index 0000000..bc0f8f0 --- /dev/null +++ b/view/default/tmpl/playlistmenu.php @@ -0,0 +1,9 @@ +
+ + + +
+ + +
+
diff --git a/view/default/view.php b/view/default/view.php new file mode 100644 index 0000000..12276a0 --- /dev/null +++ b/view/default/view.php @@ -0,0 +1,4 @@ + diff --git a/view/player/tmpl/default.php b/view/player/tmpl/default.php new file mode 100644 index 0000000..e3c5315 --- /dev/null +++ b/view/player/tmpl/default.php @@ -0,0 +1,38 @@ +
+
+ + + + +
Now Playing
+
+
+
+
+ + + + + + + + + +
+
+ +
+
+ +
+ +
+ + + + + + +
Volume:
+
+
diff --git a/view/player/view.php b/view/player/view.php new file mode 100644 index 0000000..6cf1b29 --- /dev/null +++ b/view/player/view.php @@ -0,0 +1,6 @@ + -- 2.34.1