summaryrefslogblamecommitdiff
path: root/lib/lsg_irc/last_fm_handler.ex
blob: 4eef24e185e70e3b4e56f8a23ebb132407bd0b3e (plain) (tree)
1
2
3
4
5
6
7
8
9





                                  


                                             











                                              
                                                                                   













                                                                                                                           
                                                              




























                                                                                  







                                  

                                                    
                                                                              























































                                                                                                                                      
                                                      






                                
defmodule LSG.IRC.LastFmHandler do
  require Logger

  @moduledoc """
  # last.fm

  * **!lastfm `[nick|username]`**
  * **!lastfmall**
  * **+lastfm `<username last.fm>`, -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