aboutsummaryrefslogtreecommitdiff
path: root/plugins/degesch/last-fm.lua
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/degesch/last-fm.lua')
-rw-r--r--plugins/degesch/last-fm.lua178
1 files changed, 0 insertions, 178 deletions
diff --git a/plugins/degesch/last-fm.lua b/plugins/degesch/last-fm.lua
deleted file mode 100644
index 6ade80d..0000000
--- a/plugins/degesch/last-fm.lua
+++ /dev/null
@@ -1,178 +0,0 @@
---
--- last-fm.lua: "now playing" feature using the last.fm API
---
--- Dependencies: lua-cjson (from luarocks e.g.)
---
--- I call this style closure-oriented programming
---
--- Copyright (c) 2016, Přemysl Eric Janouch <p@janouch.name>
---
--- Permission to use, copy, modify, and/or distribute this software for any
--- purpose with or without fee is hereby granted.
---
--- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
--- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
--- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
--- SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
--- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
--- OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
--- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
---
-
-local cjson = require "cjson"
-
--- Setup configuration to load last.fm API credentials from
-local user, api_key
-degesch.setup_config {
- user = {
- type = "string",
- comment = "last.fm username",
- on_change = function (v) user = v end
- },
- api_key = {
- type = "string",
- comment = "last.fm API key",
- on_change = function (v) api_key = v end
- },
-}
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
--- Generic error reporting
-local report_error = function (buffer, error)
- buffer:log ("last-fm error: " .. error)
-end
-
--- Process data return by the server and extract the now playing song
-local process = function (buffer, data, action)
- -- There's no reasonable Lua package to parse HTTP that I could find
- local s, e, v, status, message = string.find (data, "(%S+) (%S+) .+\r\n")
- if not s then return "server returned unexpected data" end
- if status ~= "200" then return status .. " " .. message end
-
- local s, e = string.find (data, "\r\n\r\n")
- if not s then return "server returned unexpected data" end
-
- local parser = cjson.new ()
- data = parser.decode (string.sub (data, e + 1))
- if not data.recenttracks or not data.recenttracks.track then
- return "invalid response" end
-
- -- Need to make some sense of the XML automatically converted to JSON
- local text_of = function (node)
- if type (node) ~= "table" then return node end
- return node["#text"] ~= "" and node["#text"] or nil
- end
-
- local name, artist, album
- for i, track in ipairs (data.recenttracks.track) do
- if track["@attr"] and track["@attr"].nowplaying then
- if track.name then name = text_of (track.name) end
- if track.artist then artist = text_of (track.artist) end
- if track.album then album = text_of (track.album) end
- end
- end
-
- if not name then
- action (false)
- else
- local np = "\"" .. name .. "\""
- if artist then np = np .. " by " .. artist end
- if album then np = np .. " from " .. album end
- action (np)
- end
-end
-
--- Set up the connection and make the request
-local on_connected = function (buffer, c, host, action)
- -- Buffer data in the connection object
- c.data = ""
- c.on_data = function (data)
- c.data = c.data .. data
- end
-
- -- And process it after we receive everything
- c.on_eof = function ()
- error = process (buffer, c.data, action)
- if error then report_error (buffer, error) end
- c:close ()
- end
- c.on_error = function (e)
- report_error (buffer, e)
- end
-
- -- Make the unencrypted HTTP request
- local url = "/2.0/?method=user.getrecenttracks&user=" .. user ..
- "&limit=1&api_key=" .. api_key .. "&format=json"
- c:send ("GET " .. url .. " HTTP/1.1\r\n")
- c:send ("User-agent: last-fm.lua\r\n")
- c:send ("Host: " .. host .. "\r\n")
- c:send ("Connection: close\r\n")
- c:send ("\r\n")
-end
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
--- Avoid establishing more than one connection at a time
-local running
-
--- Initiate a connection to last.fm servers
-async, await = degesch.async, coroutine.yield
-local make_request = function (buffer, action)
- if not user or not api_key then
- report_error (buffer, "configuration is incomplete")
- return
- end
-
- if running then running:cancel () end
- running = async.go (function ()
- local c, host, e = await (async.dial ("ws.audioscrobbler.com", 80))
- if e then
- report_error (buffer, e)
- else
- on_connected (buffer, c, host, action)
- end
- running = nil
- end)
-end
-
--- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-local now_playing
-
-local tell_song = function (buffer)
- if now_playing == nil then
- buffer:log ("last-fm: I don't know what you're listening to")
- elseif not now_playing then
- buffer:log ("last-fm: not playing anything right now")
- else
- buffer:log ("last-fm: now playing: " .. now_playing)
- end
-end
-
-local send_song = function (buffer)
- if not now_playing then
- tell_song (buffer)
- else
- buffer:execute ("/me is listening to " .. now_playing)
- end
-end
-
--- Hook input to simulate new commands
-degesch.hook_input (function (hook, buffer, input)
- if input == "/np" then
- make_request (buffer, function (np)
- now_playing = np
- send_song (buffer)
- end)
- elseif input == "/np?" then
- make_request (buffer, function (np)
- now_playing = np
- tell_song (buffer)
- end)
- elseif input == "/np!" then
- send_song (buffer)
- else
- return input
- end
-end)