diff options
author | Jordan Bracco <href@random.sh> | 2022-12-20 02:13:47 +0000 |
---|---|---|
committer | Jordan Bracco <href@random.sh> | 2022-12-20 19:29:41 +0100 |
commit | 70b9bba56f5319361ce5a7df5c489b9c0d6905ce (patch) | |
tree | f9b4438965f4c5e3e1f3a6129904cbb9a37047f2 /lib/nola_plugins/last_fm.ex | |
parent | Update repo URL, refs T77. (diff) |
Rename to Nola
Summary:
Nola rename cont. pt. 2. Refs T77.
`find lib -name "*.ex" -type f | xargs sed -i '' 's/LSG/Nola/g'`
Nola rename, cont. pt. 3. Refs T77.
`s/:lsg/:nola/g`
Nola rename, cont. pt. 4. Refs T77.
Nola rename, cont. pt. 5. Refs T77. Configs.
find config -type f | xargs sed -i '' 's/LSG/Nola/g'
find config -type f | xargs sed -i '' 's/lsg/nola/g'
BREAKING CHANGE: Config keys switch from `:lsg` to `:nola`
Nola rename, the end. pt 6. Refs T77.
Nola rename: The Big Move, Refs T77
Update repo URL, refs T77.
Nola rename: Nola.Plugins, refs T77
Maniphest Tasks: T77
Differential Revision: https://phab.random.sh/D3
Diffstat (limited to 'lib/nola_plugins/last_fm.ex')
-rw-r--r-- | lib/nola_plugins/last_fm.ex | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/lib/nola_plugins/last_fm.ex b/lib/nola_plugins/last_fm.ex new file mode 100644 index 0000000..1a9b7dd --- /dev/null +++ b/lib/nola_plugins/last_fm.ex @@ -0,0 +1,187 @@ +defmodule Nola.Plugins.LastFm do + require Logger + + @moduledoc """ + # last.fm + + * **!lastfm|np `[nick|username]`** + * **.lastfm|np** + * **+lastfm, -lastfm `<username last.fm>; ?lastfm`** Configurer un nom d'utilisateur last.fm + """ + + @single_trigger ~w(lastfm np) + @pubsub_topics ~w(trigger:lastfm trigger:np) + + defstruct dets: nil + + def irc_doc, do: @moduledoc + + def start_link() do + GenServer.start_link(__MODULE__, [], name: __MODULE__) + end + + def init([]) do + regopts = [type: __MODULE__] + for t <- @pubsub_topics, do: {:ok, _} = Registry.register(IRC.PubSub, t, type: __MODULE__) + dets_filename = (Nola.data_path() <> "/" <> "lastfm.dets") |> String.to_charlist + {:ok, dets} = :dets.open_file(dets_filename, []) + {:ok, %__MODULE__{dets: dets}} + end + + def handle_info({:irc, :trigger, "lastfm", message = %{trigger: %{type: :plus, args: [username]}}}, state) do + username = String.strip(username) + :ok = :dets.insert(state.dets, {message.account.id, username}) + message.replyfun.("#{message.sender.nick}: nom d'utilisateur last.fm configuré: \"#{username}\".") + {:noreply, state} + end + + def handle_info({:irc, :trigger, "lastfm", message = %{trigger: %{type: :minus, args: []}}}, state) do + text = case :dets.lookup(state.dets, message.account.id) do + [{_nick, _username}] -> + :dets.delete(state.dets, message.account.id) + message.replyfun.("#{message.sender.nick}: nom d'utilisateur last.fm enlevé.") + _ -> nil + end + {:noreply, state} + end + + def handle_info({:irc, :trigger, "lastfm", message = %{trigger: %{type: :query, args: []}}}, state) do + text = case :dets.lookup(state.dets, message.account.id) do + [{_nick, username}] -> + message.replyfun.("#{message.sender.nick}: #{username}.") + _ -> nil + end + {:noreply, state} + end + + def handle_info({:irc, :trigger, _, message = %{trigger: %{type: :bang, args: []}}}, state) do + irc_now_playing(message.account.id, message, state) + {:noreply, state} + end + + def handle_info({:irc, :trigger, _, message = %{trigger: %{type: :bang, args: [nick_or_user]}}}, state) do + irc_now_playing(nick_or_user, message, state) + {:noreply, state} + end + + def handle_info({:irc, :trigger, _, message = %{trigger: %{type: :dot}}}, state) do + members = IRC.Membership.members(message.network, message.channel) + foldfun = fn({nick, user}, acc) -> [{nick,user}|acc] end + usernames = :dets.foldl(foldfun, [], state.dets) + |> Enum.uniq() + |> Enum.filter(fn({acct,_}) -> Enum.member?(members, acct) end) + |> Enum.map(fn({_, u}) -> u end) + for u <- usernames, do: irc_now_playing(u, message, 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, message, state) do + nick_or_user = String.strip(nick_or_user) + + id_or_user = if account = IRC.Account.get(nick_or_user) || IRC.Account.find_always_by_nick(message.network, message.channel, nick_or_user) do + account.id + else + nick_or_user + end + + username = case :dets.lookup(state.dets, id_or_user) do + [{_, username}] -> username + _ -> id_or_user + end + + case now_playing(username) do + {:error, text} when is_binary(text) -> + message.replyfun.(text) + {:ok, map} when is_map(map) -> + track = fetch_track(username, map) + text = format_now_playing(map, track) + user = if account = IRC.Account.get(id_or_user) do + user = IRC.UserTrack.find_by_account(message.network, account) + if(user, do: user.nick, else: account.name) + else + username + end + if user && text do + message.replyfun.("#{user} #{text}") + else + message.replyfun.("#{username}: pas de résultat") + end + other -> + message.replyfun.("erreur :(") + end + end + + defp now_playing(user) do + api = Application.get_env(:nola, :lastfm)[:api_key] + url = "http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&format=json&limit=1&extended=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: 404}} -> {: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 fetch_track(user, %{"recenttracks" => %{"track" => [ t = %{"name" => name, "artist" => %{"name" => artist}} | _]}}) do + api = Application.get_env(:nola, :lastfm)[:api_key] + url = "http://ws.audioscrobbler.com/2.0/?method=track.getInfo&format=json" <> "&api_key=" <> api <> "&username="<> user <> "&artist="<>URI.encode(artist)<>"&track="<>URI.encode(name) + case HTTPoison.get(url) do + {:ok, %HTTPoison.Response{status_code: 200, body: body}} -> + case Jason.decode(body) do + {:ok, body} -> body["track"] || %{} + _ -> %{} + end + error -> + Logger.error "Lastfm http error: #{inspect error}" + :error + end + end + + defp format_now_playing(%{"recenttracks" => %{"track" => [track = %{"@attr" => %{"nowplaying" => "true"}} | _]}}, et) do + format_track(true, track, et) + end + + defp format_now_playing(%{"recenttracks" => %{"track" => [track | _]}}, et) do + format_track(false, track, et) + 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, extended) do + artist = track["artist"]["name"] + album = if track["album"]["#text"], do: " (" <> track["album"]["#text"] <> ")", else: "" + name = track["name"] <> album + action = if np, do: "écoute ", else: "a écouté" + love = if track["loved"] != "0", do: "❤️" + count = if x = extended["userplaycount"], do: "x#{x} #{love}" + tags = (get_in(extended, ["toptags", "tag"]) || []) + |> Enum.map(fn(tag) -> tag["name"] end) + |> Enum.filter(& &1) + |> Enum.join(", ") + + [action, artist, name, count, tags, track["url"]] + |> Enum.filter(& &1) + |> Enum.map(&String.trim(&1)) + |> Enum.join(" - ") + end + +end |