From 6c4cba13d034c0c7675e8f2aa3ee04ad24c911e1 Mon Sep 17 00:00:00 2001 From: Roman Bazalevskiy Date: Thu, 28 Dec 2017 20:41:17 +0300 Subject: [PATCH 1/1] =?utf8?q?=D0=91=D0=B0=D0=B3=D1=84=D0=B8=D0=BA=D1=81?= =?utf8?q?=D1=8B.=20=D0=9E=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0?= =?utf8?q?=20=D0=BE=D1=81=D0=BE=D0=B1=D0=B5=D0=BD=D0=BD=D0=BE=D1=81=D1=82?= =?utf8?q?=D0=B5=D0=B9=20=D0=BF=D0=BE=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD=D0=B8?= =?utf8?q?=D1=8F=20mopidy=20=D0=B8=20mpd.=20=D0=9E=D0=B1=D1=80=D0=B0=D0=B1?= =?utf8?q?=D0=BE=D1=82=D0=BA=D0=B0=20=D0=BF=D1=83=D1=81=D1=82=D1=8B=D1=85?= =?utf8?q?=20=D0=B8=20=D0=BC=D0=B0=D0=BB=D0=BE=D0=B7=D0=BD=D0=B0=D1=87?= =?utf8?q?=D0=B0=D1=89=D0=B8=D1=85=20=D0=B8=D0=BC=D0=B5=D0=BD=20=D1=82?= =?utf8?q?=D1=80=D0=B5=D0=BA=D0=BE=D0=B2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- LICENSE | 13 -- mpd.js | 41 +++-- mpd.js~ | 473 ------------------------------------------------------- mpd.lua | 146 +++++++++++------ mpd.lua~ | 417 ------------------------------------------------ 5 files changed, 134 insertions(+), 956 deletions(-) delete mode 100644 LICENSE delete mode 100644 mpd.js~ delete mode 100755 mpd.lua~ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 456c488..0000000 --- a/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 - - Copyright (C) 2004 Sam Hocevar - - 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. diff --git a/mpd.js b/mpd.js index 78d9c8b..b5ff513 100644 --- a/mpd.js +++ b/mpd.js @@ -1,4 +1,4 @@ -urlbase="mpd.lua?" +urlbase="/cgi-bin/mpd.cgi?" minScrollHeight=200 currentState="" @@ -48,8 +48,12 @@ function toHHMMSS(seconds) { function RefreshTime() { if (currentSeconds) { currentTime = toHHMMSS(currentSeconds) - trackTime = toHHMMSS(trackSeconds) - nowPlayingTime = currentTime+"/"+trackTime + if (trackSeconds) { + trackTime = toHHMMSS(trackSeconds) + nowPlayingTime = currentTime+"/"+trackTime + } else { + nowPlayingTime = currentTime + } } else { nowPlayingTime = "-:--/-:--" } @@ -61,7 +65,7 @@ function PeriodicRefreshTime() { nowTime = Date.now() delta = (nowTime - updateTime)/1000 currentSeconds = updateSeconds + Math.round(delta) - if (currentSeconds > trackSeconds) { + if (trackSeconds && (currentSeconds > trackSeconds)) { currentSeconds = trackSeconds } RefreshTime() @@ -76,7 +80,14 @@ function RefreshPageStatus() { if (this.readyState != 4 || this.status != 200) return; var returnedData = JSON.parse(this.responseText); trackName = GetFilename(returnedData['current_playing']); + try { + var trackName=decodeURI(trackName).replace(/%2C/g,",") + } + catch(e) { + console.log(trackName) + } trackNo = returnedData['song']; + trackId = returnedData['songid'] currentState = returnedData['state']; document.title='MPD Player: '+trackName; if (trackNo) { @@ -121,7 +132,7 @@ function RefreshPageStatus() { var items = document.getElementById('items'); var table = items.getElementsByClassName('track'); - var current_track="track_"+trackNo; + var current_track="track_"+trackId; for (var i = 0; i < table.length; i++) { if (table[i].id==current_track) { table[i].classList.add("itemActive"); @@ -162,7 +173,13 @@ req.onreadystatechange = function () { var even = 0; for (var key in returnedData) { var rec=returnedData[key]; - var name=GetFilename(rec["name"]); + var name=GetFilename(rec["title"]); + try { + var name=decodeURI(name).replace(/%2C/g,",") + } + catch(e) { + console.log(name) + } var id=rec["id"]; if (even) { @@ -175,7 +192,7 @@ req.onreadystatechange = function () { itemsText = itemsText + "\ \ - "+(Number(id)+1)+"\ + "+(Number(key)+1)+"\ \ \ "+name+"\ @@ -214,7 +231,7 @@ req.onreadystatechange = function () { var playlistMenuText = "\ \ - \
\ + \ \
"; @@ -250,6 +267,12 @@ req.onreadystatechange = function () { } else { var tailName=name }; + try { + var tailName=decodeURI(tailName).replace(/%2C/g,",") + } + catch(e) { + console.log(tailName) + } if (type == "directory" || type == "file") { if (even) { @@ -306,7 +329,7 @@ req.onreadystatechange = function () { var returnedData = JSON.parse(this.responseText); playlistMenuText="\ \ - \
\ + \ \
"; diff --git a/mpd.js~ b/mpd.js~ deleted file mode 100644 index 3412633..0000000 --- a/mpd.js~ +++ /dev/null @@ -1,473 +0,0 @@ -urlbase="mpd.lua?" -minScrollHeight=200 - -currentState="" - -function GetFilename(url) -{ - if (url) - return url.split('/').pop().split('#')[0].split('?')[0]; -} - -function EscapeStr(str) { - res = str.replace(/'/g,"\\'"); - return res; -} - -function SetSize() { - var w = window, - d = document, - e = d.documentElement, - g = d.getElementsByTagName('body')[0], - body_h = g.clientHeight, - window_h = w.innerHeight|| e.clientHeight|| g.clientHeight, - items = d.getElementById('items'), - current_h = items.clientHeight, - new_h=(window_h-body_h)+current_h; - if (new_h>minScrollHeight) { - items.style.height=new_h+"px"; - } -} - -function toHHMMSS(seconds) { - var hours = Math.floor(seconds / 3600); - seconds -= hours*3600; - var minutes = Math.floor(seconds / 60); - seconds -= minutes*60; - - if (hours < 10) {hours = "0"+hours;} - if (minutes < 10) {minutes = "0"+minutes;} - if (seconds < 10) {seconds = "0"+seconds;} - if (hours == 0) { - return minutes+':'+seconds; - } else { - return hours+':'+minutes+':'+seconds; - } -} - -function RefreshTime() { - if (currentSeconds) { - currentTime = toHHMMSS(currentSeconds) - trackTime = toHHMMSS(trackSeconds) - nowPlayingTime = currentTime+"/"+trackTime - } else { - nowPlayingTime = "-:--/-:--" - } - document.getElementById('nowplaying_tracklen').innerHTML=nowPlayingTime; -} - -function PeriodicRefreshTime() { - if (currentState == "play") { - nowTime = Date.now() - delta = (nowTime - updateTime)/1000 - currentSeconds = updateSeconds + Math.round(delta) - if (currentSeconds > trackSeconds) { - currentSeconds = trackSeconds - } - RefreshTime() - } -} - -function RefreshPageStatus() { - - var req = new XMLHttpRequest(); - - req.onreadystatechange = function () { - if (this.readyState != 4 || this.status != 200) return; - var returnedData = JSON.parse(this.responseText); - trackName = GetFilename(returnedData['current_playing']); - trackNo = returnedData['song']; - currentState = returnedData['state']; - document.title='MPD Player: '+trackName; - if (trackNo) { - var nowPlayingTrackNo=String(1+Number(trackNo)) - } else { - var nowPlayingTrackNo="-" - } - nowPlayingTrack = nowPlayingTrackNo + '/' + returnedData['playlistlength']; - nowPlayingName = trackName; - playingTime = returnedData['time'] - if (playingTime) { - var splits = playingTime.split(":") - updateTime = Date.now() - currentSeconds = Number(splits[0]) - updateSeconds = currentSeconds - trackSeconds = Number(splits[1]) - } else { - currentSeconds = null - } - if (currentState=='stop') { - nowPlayingName = '' + nowPlayingName+ '' - } - document.getElementById('nowplaying_trackno').innerHTML=nowPlayingTrack; - document.getElementById('nowplaying_trackname').innerHTML=nowPlayingName; - RefreshTime() - if (currentState=="play") { - document.getElementById('playpausebutton').innerHTML=""; - } else { - document.getElementById('playpausebutton').innerHTML=""; - } - if (currentState=="stop") { - document.getElementById('stopbutton').innerHTML=""; - } else { - document.getElementById('stopbutton').innerHTML=""; - } - if (returnedData["repeat"]=="1") { - document.getElementById('repeatstate').innerHTML=""; - } else { - document.getElementById('repeatstate').innerHTML=""; - } - document.getElementById('volume_total').innerHTML="
"; - - var items = document.getElementById('items'); - var table = items.getElementsByClassName('track'); - var current_track="track_"+trackNo; - for (var i = 0; i < table.length; i++) { - if (table[i].id==current_track) { - table[i].classList.add("itemActive"); - } else { - table[i].classList.remove("itemActive") - } - } - - }; - - req.open("GET", urlbase+"status", true); - req.send(); - -} - -function RefreshPlaylist() { - -var req = new XMLHttpRequest(); - -req.onreadystatechange = function () { - if (this.readyState != 4 || this.status != 200) return; - var returnedData = JSON.parse(this.responseText); - - var playlistMenuText = "\ - \ - \ -
\ - \ - \ - \ -
"; - - var itemsText="\ - \ - \ - "; - - var even = 0; - for (var key in returnedData) { - var rec=returnedData[key]; - var name=GetFilename(rec["name"]); - var id=rec["id"]; - - if (even) { - evText="itemEven"; - } else { - evText="itemOdd"; - }; - - even = ! even; - - itemsText = itemsText + "\ - \ - \ - \ - \ - \ - \ - "; - } - - itemsText = itemsText + "
TitleControls
\ - "+(Number(id)+1)+"\ - "+name+"\ - \ - \ - \ - \ - \ - \ -
"; - - document.getElementById('items').innerHTML=itemsText; - document.getElementById('playlist_menu_top').innerHTML=playlistMenuText; - document.getElementById('playlist_menu_bottom').innerHTML=playlistMenuText; -}; - -req.open("GET", urlbase+"playlist", true); -req.send(); - -} - -function EditPlayList(dir) { - -var req = new XMLHttpRequest(); - -req.onreadystatechange = function () { - if (this.readyState != 4 || this.status != 200) return; - var returnedData = JSON.parse(this.responseText); - - var playlistMenuText = "\ - \ - \ -
\ - \ -
"; - - var itemsText= "\ - \ - \ - "; - - var even = 0; - if (dir) { - var lastSlash=dir.lastIndexOf("/"); - if (lastSlash>0) { - var upperLevel=dir.slice(0,lastSlash); - } else { - var upperLevel=""; - } - even = ! even; - var itemsText = itemsText + "\ - \ - \ - "; - } - - var i = 0; - for (var key in returnedData) { - var rec=returnedData[key]; - var type=rec["type"]; - var name=rec["name"]; - var lastSlash=name.lastIndexOf("/"); - if (lastSlash>0) { - var tailName=name.slice(lastSlash+1); - } else { - var tailName=name - }; - - if (type == "directory" || type == "file") { - if (even) { - evText="itemEven"; - } else { - evText="itemOdd"; - }; - - i = i + 1; - even = ! even; - - itemsText = itemsText + "\ - \ - "; - - if (type == "directory") { - itemsText = itemsText + ""; - }; - - if (type == "file") { - itemsText = itemsText + ""; - }; - - itemsText = itemsText + ""; - - } - - } - - var itemsText = itemsText+"
TitleControls
..
\ - \ - "+tailName+"\ - \ - "+tailName+"\ -
"; - document.getElementById('items').innerHTML=itemsText; - document.getElementById('playlist_menu_top').innerHTML=playlistMenuText; - document.getElementById('playlist_menu_bottom').innerHTML=playlistMenuText; -}; - -if (!dir) { dir = ''; }; - -req.open("GET", urlbase+"lists|edit|"+dir, true); -req.send(); - -} - -function LoadPlayList() { - -var req = new XMLHttpRequest(); - -req.onreadystatechange = function () { - if (this.readyState != 4 || this.status != 200) return; - var returnedData = JSON.parse(this.responseText); - playlistMenuText="\ - \ - \ -
\ - \ -
"; - itemsText="\ - \ - \ - "; - - var even = 0; - for (var key in returnedData) { - var name=returnedData[key]; - - if (even) { - evText="itemEven"; - } else { - evText="itemOdd"; - }; - - even = ! even; - - itemsText = itemsText + "\ - \ - \ - \ - "; - } - - itemsText=itemsText+"
NameControls
"+name+"
"; - document.getElementById('items').innerHTML=itemsText; - document.getElementById('playlist_menu_top').innerHTML=playlistMenuText; - document.getElementById('playlist_menu_bottom').innerHTML=playlistMenuText; -}; - -req.open("GET", urlbase+"lists|load", true); -req.send(); - -} - -function SavePlayList() { - -var name=window.prompt('List name',''); - -var req = new XMLHttpRequest(); - -req.onreadystatechange = function () { - if (this.readyState != 4 || this.status != 200) return; - if (this.responseText != 'OK') { - window.alert(this.responseText); - } -}; - -req.open("GET", urlbase+"lists|save|"+name, true); -req.send(); - -} - -function DelPlayList(item) { - -var req = new XMLHttpRequest(); - -req.onreadystatechange = function () { - if (this.readyState != 4 || this.status != 200) return; - LoadPlayList(); - RefreshPageStatus(); -}; - -req.open("GET", urlbase+"lists|delete|"+item, true); -req.send(); - -} - -function RefreshPageContent() { - RefreshPlaylist(); - RefreshPageStatus(); -} - -function Command(cmd) { - -var req = new XMLHttpRequest(); - -req.onreadystatechange = function () { - if (this.readyState != 4 || this.status != 200) return; - RefreshPageStatus(); -}; - -req.open("GET", urlbase+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", urlbase+"cpl|"+cmd+"|"+item, true); -req.send(); - -} - -function PlaylistCommandRefStatus(cmd,item) { - -var req = new XMLHttpRequest(); - -req.onreadystatechange = function () { - if (this.readyState != 4 || this.status != 200) return; - RefreshPageStatus(); -}; - -req.open("GET", urlbase+"cpl|"+cmd+"|"+item, true); -req.send(); - -} - -function PlaylistEditCommand(cmd,item) { - -var req = new XMLHttpRequest(); - -req.onreadystatechange = function () { - if (this.readyState != 4 || this.status != 200) return; - RefreshPageStatus(); -}; - -req.open("GET", urlbase+"lists|"+cmd+"|"+item, true); -req.send(); - -} - -function PlaylistEditCommandRefFull(cmd,item) { - -var req = new XMLHttpRequest(); - -req.onreadystatechange = function () { - if (this.readyState != 4 || this.status != 200) return; - RefreshPageContent(); -}; - -req.open("GET", urlbase+"lists|"+cmd+"|"+item, true); -req.send(); - -} - -function subscribe_status() { - var xhr = new XMLHttpRequest(); - - xhr.onreadystatechange = function() { - if (this.readyState != 4) return; - if (this.status == 200) { - RefreshPageStatus() - setTimeout(subscribe_status,1000) - } else { - setTimeout(subscribe_status,15000) - } - } - xhr.open("GET", urlbase+"idle", true); - xhr.send(); -} - -setTimeout(subscribe_status,5000) -setInterval(PeriodicRefreshTime, 1000); diff --git a/mpd.lua b/mpd.lua index 8935c9a..f421b75 100755 --- a/mpd.lua +++ b/mpd.lua @@ -14,6 +14,23 @@ function url_decode(str) return str end +function url_encode(str) + + --Ensure all newlines are in CRLF form + str = string.gsub (str, "\r?\n", "\r\n") + + --Percent-encode all non-unreserved characters + --as per RFC 3986, Section 2.3 + --(except for space, which gets plus-encoded) + str = string.gsub (str, "([^%w%-%.%_%~:/])", + function (c) return string.format ("%%%02X", string.byte(c)) end) + + --Convert spaces to plus signs + str = string.gsub (str, " ", "+") + + return str +end + function split(s, delimiter) local result = {}; for match in (s..delimiter):gmatch("(.-)"..delimiter) do @@ -26,25 +43,53 @@ function string.starts(String,Start) return string.sub(String,1,string.len(Start))==Start end +function filename(path) + local path_elems=split(path,'/') + return path_elems[#path_elems] +end + function process_playlist(playlist) local res={} + local rec={} for _,record in pairs(playlist) do + if record=="OK" then + break + end local splitted = split(record,": ") - local name = splitted[2] - local splitted = split(splitted[1],":") - local id = splitted[1] - local rectype = splitted[2] - local rec = {} - if not (id == "OK") then - rec["id"] = id - rec["type"] = rectype - rec["name"] = name - res[id] = rec + local fieldname = string.lower(splitted[1]) + local fieldvalue = splitted[2] + rec[fieldname] = fieldvalue + if fieldname=="id" then + local title = rec['title'] + if title then + local filtered_title=string.gsub(string.lower(title),'track','') + local filtered_title=string.gsub(filtered_title,'[ _.-]','') + else + filtered_title="" + end + if not filtered_title or string.len(filtered_title)<4 then + if title then + rec['title']=title..' - '..filename(rec['file']) + else + rec['title']=filename(rec['file']) + end + end + res[#res+1] = rec + rec={} end end return res end +function find_by_id(playlist,id) + for key,record in pairs(playlist) do + if record['id']==id then + return key + end + end + return nil +end + function process_playlists(playlists) local res={} for _,record in pairs(playlists) do @@ -72,6 +117,7 @@ end function mpd_new(settings) local client = {} + if settings == nil then settings = {} end client.hostname = settings.hostname or "localhost" @@ -161,6 +207,8 @@ function mpd_send(mpd,action,raw) return values end +hasuci = false + if hasuci then x = uci.cursor() @@ -176,16 +224,13 @@ if hasuci then else - config = arg[1] - if not config then - config="/etc/mpd-lua.json" - end + config="/etc/mpd-lua.json" settings={} local open = io.open - local file = open(config, "r") + file = open(config, "r") if file then - local content = file:read "*a" + content = file:read "*a" file:close() settings=json.decode(content) end @@ -198,7 +243,6 @@ else end - if password then settings["password"] = password end @@ -247,7 +291,7 @@ elseif string.starts(command,"fastfwd") then status=mpd_send(m,"status") rec_time=status["time"] - song=status["song"] + song=status["songid"] if song then @@ -256,12 +300,13 @@ elseif string.starts(command,"fastfwd") then cur_time=tonumber(rec_time[1]) track_time=tonumber(rec_time[2]) - cur_time=cur_time+skip - if cur_time>track_time then - cur_time=track_time - end - - mpd_send(m,"seek "..song.." "..cur_time) + if track_time then + cur_time=cur_time+skip + if cur_time>track_time then + cur_time=track_time + end + end + mpd_send(m,"seekid "..song.." "..cur_time) else @@ -283,22 +328,22 @@ elseif string.starts(command,"rewind") then status=mpd_send(m,"status") rec_time=status["time"] - song=status["song"] + song=status["songid"] if song then if rec_time then rec_time=split(rec_time,":") cur_time=tonumber(rec_time[1]) - - track_time=tonumber(rec_time[2]) cur_time=cur_time-skip if cur_time<0 then cur_time=0 end - mpd_send(m,"seek "..song.." "..cur_time) - + print(song) + print(cur_time) + mpd_send(m,"seekid "..song.." "..cur_time) + else mpd_send(m,"play") @@ -313,19 +358,18 @@ elseif string.starts(command,"rewind") then elseif command=="status" then res=mpd_send(m,"status") - song=res["song"] - playlist=mpd_send(m,"playlist",1) - pl=process_playlist(playlist) - + song=tonumber(res["songid"]) if song then - res['current_playing']=pl[song]['name'] + playlist=mpd_send(m,"playlistid "..song,1) + pl=process_playlist(playlist) + res['current_playing']=pl[1]['title'] else res['current_playing']="---" end elseif command=="playlist" then - playlist=mpd_send(m,"playlist",1) + playlist=mpd_send(m,"playlistinfo",1) res=process_playlist(playlist) elseif command=="repeat" then @@ -341,7 +385,7 @@ elseif string.starts(command,"cpl") then command=cmd[2] if command=="playitem" then - command="play "..id + command="playid "..id res=mpd_send(m,command) end @@ -350,17 +394,27 @@ elseif string.starts(command,"cpl") then end if command=="remove" then - command="delete "..id + command="deleteid "..id res=mpd_send(m,command) end if command=="moveup" then - command="swap "..id.." "..(id-1) + playlist=mpd_send(m,"playlistinfo ",1) + pl=process_playlist(playlist) + idx=find_by_id(pl,id) + if idx>1 then + command="swap "..(idx-1).." "..(idx-2) + end res=mpd_send(m,command) end if command=="movedown" then - command="swap "..id.." "..(id+1) + playlist=mpd_send(m,"playlistinfo ",1) + pl=process_playlist(playlist) + idx=find_by_id(pl,id) + if idx<#pl then + command="swap "..(idx-1).." "..(idx) + end res=mpd_send(m,command) end @@ -374,16 +428,16 @@ elseif string.starts(command,"lists") then lists=mpd_send(m,"listplaylists",1) res=process_playlists(lists) else - res=mpd_send(m,"load "..cmd[3],1) + res=mpd_send(m,"load \""..cmd[3].."\"",1) end end if command=="save" and cmd[3] then - res=mpd_send(m,"save "..cmd[3],1) + res=mpd_send(m,"save \""..cmd[3].."\"",1) end if command=="delete" and cmd[3] then - res=mpd_send(m,"rm "..cmd[3],1) + res=mpd_send(m,"rm \""..cmd[3].."\"",1) end if command=="edit" then @@ -399,6 +453,10 @@ elseif string.starts(command,"lists") then res={} if cmd[3] then res=mpd_send(m,"add \""..cmd[3].."\"") + if (res['errormsg']) then + path=url_encode(cmd[3]) + res=mpd_send(m,"add \""..path.."\"") + end end end @@ -407,9 +465,9 @@ end if not res then print("Content-Type: text/plain\r\n") print("MPD server - unknown command "..command) -elseif (res['error_msg']) then +elseif (res['errormsg']) then print("Content-Type: text/plain\r\n") - print("MPD server connection error: "..res['error_msg']) + print("MPD server connection error: "..res['errormsg']) else print "Content-Type: text/plain\r\n" print(json.encode(res)) diff --git a/mpd.lua~ b/mpd.lua~ deleted file mode 100755 index 97ac4f4..0000000 --- a/mpd.lua~ +++ /dev/null @@ -1,417 +0,0 @@ -#!/usr/bin/lua - -local hasuci,uci = pcall(require,"uci") - -require("socket") -json=require("json") - -function url_decode(str) - if not str then return nil end - str = string.gsub (str, "+", " ") - str = string.gsub (str, "%%(%x%x)", function(h) return - string.char(tonumber(h,16)) end) - str = string.gsub (str, "\r\n", "\n") - return str -end - -function split(s, delimiter) - local result = {}; - for match in (s..delimiter):gmatch("(.-)"..delimiter) do - result[#result+1] = match; - end - return result; -end - -function string.starts(String,Start) - return string.sub(String,1,string.len(Start))==Start -end - -function process_playlist(playlist) - local res={} - for _,record in pairs(playlist) do - local splitted = split(record,": ") - local name = splitted[2] - local splitted = split(splitted[1],":") - local id = splitted[1] - local rectype = splitted[2] - local rec = {} - if not (id == "OK") then - rec["id"] = id - rec["type"] = rectype - rec["name"] = name - res[id] = rec - end - end - return res -end - -function process_playlists(playlists) - local res={} - for _,record in pairs(playlists) do - local splitted = split(record,": ") - if splitted[1]=="playlist" then - res[#res+1] = splitted[2] - end - end - return res -end - -function process_directory(directory) - local res={} - for _,record in pairs(directory) do - local splitted = split(record,": ") - if splitted[1]=="directory" or splitted[1]=="file" then - local rec={} - rec["type"] = splitted[1] - rec["name"] = splitted[2] - res[#res+1] = rec - end - end - return res -end - -function mpd_new(settings) - local client = {} - if settings == nil then settings = {} end - - client.hostname = settings.hostname or "localhost" - client.port = settings.port or 6600 - client.desc = settings.desc or client.hostname - client.password = settings.password - client.timeout = settings.timeout or 1 - client.retry = settings.retry or 60 - - return client -end - -function mpd_send(mpd,action,raw) - - local command = string.format("%s\n", action) - local values = {} - - -- connect to MPD server if not already done. - if not mpd.connected then - local now = os.time(); - if not mpd.last_try or (now - mpd.last_try) > mpd.retry then - mpd.socket = socket.tcp() - mpd.socket:settimeout(mpd.timeout, 't') - mpd.last_try = os.time() - mpd.connected = mpd.socket:connect(mpd.hostname, mpd.port) - if not mpd.connected then - return { errormsg = "could not connect" } - end - mpd.last_error = nil - - -- Read the server's hello message - local line = mpd.socket:receive("*l") - if not line:match("^OK MPD") then -- Invalid hello message? - mpd.connected = false - return { errormsg = string.format("invalid hello message: %s", line) } - else - _, _, mpd.version = string.find(line, "^OK MPD ([0-9.]+)") - end - - -- send the password if needed - if mpd.password then - local rsp = mpd_send(mpd,string.format("password %s", mpd.password)) - if rsp.errormsg then - return rsp - end - end - else - local retry_sec = mpd.retry - (now - mpd.last_try) - return { errormsg = string.format("%s (retrying in %d sec)", mpd.last_error, retry_sec) } - end - end - - mpd.socket:send(command) - - local line = ""; err=0 - while not line:match("^OK$") do - line, err = mpd.socket:receive("*l") - if not line then -- closed,timeout (mpd killed?) - mpd.last_error = err - mpd.connected = false - mpd.socket:close() - return mpd_send(mpd,action) - end - - if line:match("^ACK") then - return { errormsg = line } - end - - if not raw then - - local pattern = string.format("(%s)", ": ") - local i = string.find (line, pattern, 0) - - if i ~= nil then - local key=string.sub(line,1,i-1) - local value=string.sub(line,i+2,-1) - values[string.lower(key)] = value - end - - else - - values[#values+1]=line - - end - end - - return values -end - -if hasuci then - - x = uci.cursor() - - settings = {} - settings['host'] = x.get("mpd","server","host") or "localhost" - settings['port'] = x.get("mpd","server","port") or 6600 - settings['timeout'] = x.get("mpd","server","timeout") or 1 - - volstep = x.get("mpd","control","volume_step") or 3 - - password = x.get("mpd","server","password") - -else - - config = arg[1] - if not config then - config="/etc/mpd-lua.json" - end - - settings={} - local open = io.open - local file = open(config, "r") - if file then - local content = file:read "*a" - file:close() - settings=json.decode(content) - end - - settings['host'] = settings['host'] or "localhost" - settings['port'] = settings["port"] or 6600 - settings['timeout'] = settings["timeout"] or 1 - - volstep = settings["volstep"] or 3 - -end - - -if password then - settings["password"] = password -end - -m = mpd_new(settings) - -command = url_decode(os.getenv('QUERY_STRING')) - -if not command or command=="" then - command="idle" -end - -if command=="play" or command=="pause" or command=="stop" then - - res=mpd_send(m,command) - -elseif command=="previous" or command=="next" then - - res=mpd_send(m,"play") - res=mpd_send(m,command) - -elseif command=="idle" then - - m.timeout=30 - res=mpd_send(m,command) - -elseif command=="vold" then - - status=mpd_send(m,"status") - volume=tonumber(status["volume"]) - res=mpd_send(m,"setvol "..(volume-volstep)) - -elseif command=="volu" then - - status=mpd_send(m,"status") - volume=tonumber(status["volume"]) - res=mpd_send(m,"setvol "..(volume+volstep)) - -elseif string.starts(command,"fastfwd") then - - cmd=split(command,"|") - skip=tonumber(cmd[2]) - if not skip then - skip=15 - end - - status=mpd_send(m,"status") - rec_time=status["time"] - song=status["song"] - - if song then - - if rec_time then - rec_time=split(rec_time,":") - cur_time=tonumber(rec_time[1]) - - track_time=tonumber(rec_time[2]) - cur_time=cur_time+skip - if cur_time>track_time then - cur_time=track_time - end - - mpd_send(m,"seek "..song.." "..cur_time) - - else - - mpd_send(m,"play") - - end - - end - - res={} - -elseif string.starts(command,"rewind") then - - cmd=split(command,"|") - skip=tonumber(cmd[2]) - if not skip then - skip=15 - end - - status=mpd_send(m,"status") - rec_time=status["time"] - song=status["song"] - - if song then - - if rec_time then - rec_time=split(rec_time,":") - cur_time=tonumber(rec_time[1]) - - track_time=tonumber(rec_time[2]) - cur_time=cur_time-skip - if cur_time<0 then - cur_time=0 - end - - mpd_send(m,"seek "..song.." "..cur_time) - - else - - mpd_send(m,"play") - mpd_send(m,"previous") - - end - - end - - res={} - -elseif command=="status" then - - res=mpd_send(m,"status") - song=res["song"] - playlist=mpd_send(m,"playlist",1) - pl=process_playlist(playlist) - - if song then - res['current_playing']=pl[song]['name'] - else - res['song']="--" - res['current_playing']="---" - end - -elseif command=="playlist" then - - playlist=mpd_send(m,"playlist",1) - res=process_playlist(playlist) - -elseif command=="repeat" then - - status=mpd_send(m,"status") - rep=1-status["repeat"] - res=mpd_send(m,"repeat "..rep) - -elseif string.starts(command,"cpl") then - - cmd=split(command,"|") - id=cmd[3] - command=cmd[2] - - if command=="playitem" then - command="play "..id - res=mpd_send(m,command) - end - - if command=="clear" then - res=mpd_send(m,"clear") - end - - if command=="remove" then - command="delete "..id - res=mpd_send(m,command) - end - - if command=="moveup" then - command="swap "..id.." "..(id-1) - res=mpd_send(m,command) - end - - if command=="movedown" then - command="swap "..id.." "..(id+1) - res=mpd_send(m,command) - end - -elseif string.starts(command,"lists") then - - cmd=split(command,"|") - command=cmd[2] - - if command=="load" then - if not cmd[3] then - lists=mpd_send(m,"listplaylists",1) - res=process_playlists(lists) - else - res=mpd_send(m,"load "..cmd[3],1) - end - end - - if command=="save" and cmd[3] then - res=mpd_send(m,"save "..cmd[3],1) - end - - if command=="delete" and cmd[3] then - res=mpd_send(m,"rm "..cmd[3],1) - end - - if command=="edit" then - if cmd[3] then - dir=mpd_send(m,"lsinfo \""..cmd[3].."\"",1) - else - dir=mpd_send(m,"lsinfo",1) - end - res=process_directory(dir) - end - - if command=="add" then - res={} - if cmd[3] then - res=mpd_send(m,"add \""..cmd[3].."\"") - end - end - -end - -if not res then - print("Content-Type: text/plain\r\n") - print("MPD server - unknown command "..command) -elseif (res['error_msg']) then - print("Content-Type: text/plain\r\n") - print("MPD server connection error: "..res['error_msg']) -else - print "Content-Type: text/plain\r\n" - print(json.encode(res)) -end -- 2.34.1