defmodule LSG.IRC.LastFmHandler do require Logger @moduledoc """ # last.fm * **!lastfm `[nick|username]`** * **!lastfmall** * **+lastfm ``, -lastfm** """ defstruct client: nil, dets: nil def irc_doc, do: @moduledoc def start_link(client) do GenServer.start_link(__MODULE__, [client]) end def init([client]) do ExIRC.Client.add_handler(client, self()) dets_filename = (LSG.data_path() <> "/" <> "lastfm.dets") |> String.to_charlist {:ok, dets} = :dets.open_file(dets_filename, []) {:ok, %__MODULE__{client: client, dets: dets}} end def handle_info({:received, "+lastfm " <> username, sender, chan}, state) do username = String.strip(username) :ok = :dets.insert(state.dets, {String.downcase(sender.nick), username}) ExIRC.Client.msg(state.client, :privmsg, chan, "#{sender.nick}: nom d'utilisateur last.fm configuré: \"#{username}\"") {:noreply, state} end def handle_info({:received, "-lastfm", sender, chan}, state) do text = case :dets.lookup(state.dets, sender.nick) do [{_nick, username}] -> :dets.delete(state.dets, String.downcase(sender.nick)) "#{sender.nick}: nom d'utilisateur last.fm enlevé" _ -> "" end ExIRC.Client.msg(state.client, :privmsg, chan, text) {:noreply, state} end def handle_info({:received, "!lastfm", sender, chan}, state) do irc_now_playing(sender.nick, chan, state) {:noreply, state} end def handle_info({:received, "!lastfm " <> nick_or_user, sender, chan}, state) do irc_now_playing(nick_or_user, chan, state) {:noreply, state} end def handle_info({:received, "!lastfmall", sender, chan}, state) do foldfun = fn({_nick, user}, acc) -> [user|acc] end usernames = :dets.foldl(foldfun, [], state.dets) |> Enum.uniq for u <- usernames, do: irc_now_playing(u, chan, state) {:noreply, state} end def handle_info(info, state) do {:noreply, state} end def terminate(_reason, state) do if state.dets do :dets.sync(state.dets) :dets.close(state.dets) end :ok end defp irc_now_playing(nick_or_user, chan, state) do nick_or_user = String.strip(nick_or_user) username = case :dets.lookup(state.dets, String.downcase(nick_or_user)) do [{^nick_or_user, username}] -> username _ -> nick_or_user end case now_playing(username) do {:error, text} when is_binary(text) -> ExIRC.Client.msg(state.client, :privmsg, chan, text) {:ok, map} when is_map(map) -> text = format_now_playing(map) user = lookup_nick(username, state) if user && text, do: ExIRC.Client.msg(state.client, :privmsg, chan, "#{user} #{text}") other -> IO.inspect(other) nil end end defp now_playing(user) do api = Application.get_env(:lsg, __MODULE__)[:api_key] url = "http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&format=json&limit=1" <> "&api_key=" <> api <> "&user="<> user case HTTPoison.get(url) do {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> Jason.decode(body) {:ok, %HTTPoison.Response{status_code: 400}} -> {:error, "last.fm: utilisateur #{user} inexistant"} {:ok, %HTTPoison.Response{status_code: code}} -> {:error, "last.fm: erreur #{to_string(code)}"} error -> Logger.error "Lastfm http error: #{inspect error}" :error end end defp format_now_playing(%{"recenttracks" => %{"track" => [track = %{"@attr" => %{"nowplaying" => "true"}}, _old]}}) do format_track(true, track) end defp format_now_playing(%{"recenttracks" => %{"track" => [track]}}) do format_track(false, track) end defp format_now_playing(%{"error" => err, "message" => message}) do "last.fm error #{err}: #{message}" end defp format_now_playing(miss) do nil end defp format_track(np, track) do album = if track["album"]["#text"] do " (" <> track["album"]["#text"] <> ")" else "" end action = if np, do: "écoute ", else: "a écouté " action <> track["artist"]["#text"] <> " - " <> track["name"] <> album <> " — " <> track["url"] end defp lookup_nick(username, state) do case :dets.match(state.dets, {:'$1', username}) do [[match]] -> match [[match] | _many] -> match _ -> username end end end