diff options
author | href <href@random.sh> | 2021-09-01 10:30:18 +0200 |
---|---|---|
committer | href <href@random.sh> | 2021-09-01 10:30:18 +0200 |
commit | 75687711f35355bc30e4829439384aab28fcac6d (patch) | |
tree | 8f3256f472893c39720a684d390e890a152f7303 /lib/lsg_irc/alcolog_plugin.ex | |
parent | link: post_* callbacks; html & pdftitle. (diff) |
Commit all the changes that hasn't been committed + updates.
Diffstat (limited to 'lib/lsg_irc/alcolog_plugin.ex')
-rw-r--r-- | lib/lsg_irc/alcolog_plugin.ex | 358 |
1 files changed, 245 insertions, 113 deletions
diff --git a/lib/lsg_irc/alcolog_plugin.ex b/lib/lsg_irc/alcolog_plugin.ex index 600dc1a..c758117 100644 --- a/lib/lsg_irc/alcolog_plugin.ex +++ b/lib/lsg_irc/alcolog_plugin.ex @@ -6,6 +6,7 @@ defmodule LSG.IRC.AlcoologPlugin do * **!santai `<cl | (calc)>` `<degrés d'alcool> [annotation]`**: enregistre un nouveau verre de `montant` d'une boisson à `degrés d'alcool`. * **!santai `<cl | (calc)>` `<beer name>`**: enregistre un nouveau verre de `cl` de la bière `beer name`, et checkin sur Untappd.com. + * **!moar `[cl]` : enregistre un verre équivalent au dernier !santai. * **-santai**: annule la dernière entrée d'alcoolisme. * **.alcoolisme**: état du channel en temps réel. * **.alcoolisme `<semaine | Xj>`**: points par jour, sur X j. @@ -139,7 +140,7 @@ defmodule LSG.IRC.AlcoologPlugin do "attention... l'alcool permet de rendre l'eau potable", "{{'QUOI ?' | bold}}", "QUO{{'I' | rrepeat}}?", - "{{'COMMENT ÇA DE L'EAU ?' | red}}", + "{{\"COMMENT ÇA DE L'EAU ?\" | red}}", "resaisis toi et va ouvrir une bonne teille de rouge...", "bwais tu veux pas un \"petit\" rhum plutôt ?" ] @@ -163,16 +164,20 @@ defmodule LSG.IRC.AlcoologPlugin do end def init(_) do - {:ok, _} = Registry.register(IRC.PubSub, "account", []) - {:ok, _} = Registry.register(IRC.PubSub, "trigger:santai", []) - {:ok, _} = Registry.register(IRC.PubSub, "trigger:santo", []) - {:ok, _} = Registry.register(IRC.PubSub, "trigger:santeau", []) - {:ok, _} = Registry.register(IRC.PubSub, "trigger:alcoolog", []) - {:ok, _} = Registry.register(IRC.PubSub, "trigger:sobre", []) - {:ok, _} = Registry.register(IRC.PubSub, "trigger:sobrepour", []) - {:ok, _} = Registry.register(IRC.PubSub, "trigger:soif", []) - {:ok, _} = Registry.register(IRC.PubSub, "trigger:alcoolisme", []) - {:ok, _} = Registry.register(IRC.PubSub, "trigger:alcool", []) + regopts = [plugin: __MODULE__] + {:ok, _} = Registry.register(IRC.PubSub, "account", regopts) + {:ok, _} = Registry.register(IRC.PubSub, "trigger:santai", regopts) + {:ok, _} = Registry.register(IRC.PubSub, "trigger:moar", regopts) + {:ok, _} = Registry.register(IRC.PubSub, "trigger:again", regopts) + {:ok, _} = Registry.register(IRC.PubSub, "trigger:bis", regopts) + {:ok, _} = Registry.register(IRC.PubSub, "trigger:santo", regopts) + {:ok, _} = Registry.register(IRC.PubSub, "trigger:santeau", regopts) + {:ok, _} = Registry.register(IRC.PubSub, "trigger:alcoolog", regopts) + {:ok, _} = Registry.register(IRC.PubSub, "trigger:sobre", regopts) + {:ok, _} = Registry.register(IRC.PubSub, "trigger:sobrepour", regopts) + {:ok, _} = Registry.register(IRC.PubSub, "trigger:soif", regopts) + {:ok, _} = Registry.register(IRC.PubSub, "trigger:alcoolisme", regopts) + {:ok, _} = Registry.register(IRC.PubSub, "trigger:alcool", regopts) dets_filename = (LSG.data_path() <> "/" <> "alcoolisme.dets") |> String.to_charlist {:ok, dets} = :dets.open_file(dets_filename, [{:type,:bag}]) ets = :ets.new(__MODULE__.ETS, [:ordered_set, :named_table, :protected, {:read_concurrency, true}]) @@ -182,8 +187,25 @@ defmodule LSG.IRC.AlcoologPlugin do traverse_fun = fn(obj, dets) -> case obj do + object = {nick, date, volumes, active, cl, deg, name, comment, meta} -> + :ets.insert(ets, {{nick, date}, volumes, active, cl, deg, name, comment, meta}) + dets object = {nick, date, volumes, active, name, comment} -> - :ets.insert(ets, {{nick, date}, volumes, active, name, comment}) + IO.puts("Migrating object #{inspect object}") + {cl, deg} = with \ + %{"cl" => cl, "deg" => deg} <- Regex.named_captures(~r/^(?<cl>\d+[.]\d+)cl\s+(?<deg>\d+[.]\d+)°$/, name), + {cl, _} <- Util.float_paparse(cl), + {deg, _} <- Util.float_paparse(deg) + do + {cl, deg} + else + _ -> {nil, nil} + end + new = {nick, date, volumes, active, cl, deg, name, comment, Map.new()} + :dets.delete_object(dets, obj) + :dets.insert(dets, new) + + :ets.insert(ets, {{nick, date}, volumes, active, cl, deg, name, comment, Map.new()}) dets _ -> dets @@ -206,40 +228,40 @@ defmodule LSG.IRC.AlcoologPlugin do |> Timex.Timezone.convert("Europe/Paris") apero = format_duration_from_now(%DateTime{now | hour: 18, minute: 0, second: 0}, false) day_of_week = Date.day_of_week(now) - txt = cond do + {txt, apero?} = cond do now.hour >= 0 && now.hour < 6 -> - ["apéro tardif ? Je dis OUI ! SANTAI !"] + {["apéro tardif ? Je dis OUI ! SANTAI !"], true} now.hour >= 6 && now.hour < 12 -> if day_of_week >= 6 do - ["C'est quand même un peu tôt non ? Prochain apéro #{apero}"] + {["de l'alcool pour le petit dej ? le week-end, pas de problème !"], true} else - ["de l'alcool pour le petit dej ? le week-end, pas de problème !"] + {["C'est quand même un peu tôt non ? Prochain apéro #{apero}"], false} end now.hour >= 12 && (now.hour < 14) -> - ["oui! c'est l'apéro de midi! (et apéro #{apero})", + {["oui! c'est l'apéro de midi! (et apéro #{apero})", "tu peux attendre #{apero} ou y aller, il est midi !" - ] + ], true} now.hour == 17 -> - [ + {[ "ÇA APPROCHE !!! Apéro #{apero}", "BIENTÔT !!! Apéro #{apero}", "achetez vite les teilles, apéro dans #{apero}!", "préparez les teilles, apéro dans #{apero}!" - ] + ], false} now.hour >= 14 && now.hour < 18 -> weekend = if day_of_week >= 6 do " ... ou maintenant en fait, c'est le week-end!" else "" end - ["tiens bon! apéro #{apero}#{weekend}", + {["tiens bon! apéro #{apero}#{weekend}", "courage... apéro dans #{apero}#{weekend}", "pas encore :'( apéro dans #{apero}#{weekend}" - ] + ], false} true -> - [ + {[ "C'EST L'HEURE DE L'APÉRO !!! SANTAIIIIIIIIIIII !!!!" - ] + ], true} end txt = txt @@ -248,6 +270,11 @@ defmodule LSG.IRC.AlcoologPlugin do m.replyfun.(txt) + stats = get_full_statistics(state, m.account.id) + if !apero? && stats.active > 0.1 do + m.replyfun.("(... ou continue en fait, je suis pas ta mère !)") + end + {:noreply, state} end @@ -344,15 +371,58 @@ defmodule LSG.IRC.AlcoologPlugin do end def handle_info({:irc, :trigger, "santai", m = %IRC.Message{trigger: %IRC.Trigger{args: [cl, deg | comment], type: :bang}}}, state) do - comment = if comment == [] do - nil - else - Enum.join(comment, " ") + santai(m, state, cl, deg, comment) + {:noreply, state} + end + + @moar [ + "{{message.sender.nick}}: la même donc ?", + "{{message.sender.nick}}: et voilà la petite sœur !" + ] + + def handle_info({:irc, :trigger, "bis", m = %IRC.Message{trigger: %IRC.Trigger{args: args, type: :bang}}}, state) do + handle_info({:irc, :trigger, "moar", m}, state) + end + def handle_info({:irc, :trigger, "again", m = %IRC.Message{trigger: %IRC.Trigger{args: args, type: :bang}}}, state) do + handle_info({:irc, :trigger, "moar", m}, state) + end + + def handle_info({:irc, :trigger, "moar", m = %IRC.Message{trigger: %IRC.Trigger{args: args, type: :bang}}}, state) do + case get_statistics_for_nick(state, m.account.id) do + {_, obj = {_, _date, _points, _active, cl, deg, _name, comment, _meta}} -> + cl = case args do + [cls] -> + case Util.float_paparse(cls) do + {cl, _} -> cl + _ -> cl + end + _ -> cl + end + moar = @moar |> Enum.shuffle() |> Enum.random() |> Tmpl.render(m) |> m.replyfun.() + santai(m, state, cl, deg, comment, auto_set: true) + {_, obj = {_, date, points, _last_active, type, descr}} -> + case Regex.named_captures(~r/^(?<cl>\d+[.]\d+)cl\s+(?<deg>\d+[.]\d+)°$/, type) do + nil -> m.replyfun.("suce") + u -> + moar = @moar |> Enum.shuffle() |> Enum.random() |> Tmpl.render(m) |> m.replyfun.() + santai(m, state, u["cl"], u["deg"], descr, auto_set: true) + end + _ -> nil + end + {:noreply, state} + end + + defp santai(m, state, cl, deg, comment, options \\ []) do + comment = cond do + comment == [] -> nil + is_binary(comment) -> comment + comment == nil -> nil + true -> Enum.join(comment, " ") end {cl, cl_extra} = case {Util.float_paparse(cl), cl} do {{cl, extra}, _} -> {cl, extra} - {:error, "("<>_} -> + {:error, "("<>_} -> try do {:ok, result} = Abacus.eval(cl) {result, nil} @@ -363,7 +433,7 @@ defmodule LSG.IRC.AlcoologPlugin do end {deg, comment, auto_set, beer_id} = case Util.float_paparse(deg) do - {deg, _} -> {deg, comment, false, nil} + {deg, _} -> {deg, comment, Keyword.get(options, :auto_set, false), nil} :error -> beername = if(comment, do: "#{deg} #{comment}", else: deg) case Untappd.search_beer(beername, limit: 1) do @@ -374,7 +444,6 @@ defmodule LSG.IRC.AlcoologPlugin do end end - cond do cl == nil -> m.replyfun.(cl_extra) deg == nil -> m.replyfun.(comment) @@ -383,16 +452,20 @@ defmodule LSG.IRC.AlcoologPlugin do cl < 0 || deg < 0 -> m.replyfun.(Tmpl.render(Enum.random(Enum.shuffle(Map.get(@bad_drinks, :negative))), m)) true -> points = Alcool.units(cl, deg) - now = DateTime.to_unix(DateTime.utc_now(), :millisecond) + now = m.at || DateTime.utc_now() + |> DateTime.to_unix(:millisecond) user_meta = get_user_meta(state, m.account.id) name = "#{cl}cl #{deg}°" old_stats = get_full_statistics(state, m.account.id) - :ok = :dets.insert(state.dets, {m.account.id, now, points, if(old_stats, do: old_stats.active, else: 0), name, comment}) - true = :ets.insert(state.ets, {{m.account.id, now}, points, if(old_stats, do: old_stats.active, else: 0),name, comment}) + meta = %{} + meta = Map.put(meta, "timestamp", now) + meta = Map.put(meta, "weight", user_meta.weight) + meta = Map.put(meta, "sex", user_meta.sex) + :ok = :dets.insert(state.dets, {m.account.id, now, points, if(old_stats, do: old_stats.active, else: 0), cl, deg, name, comment, meta}) + true = :ets.insert(state.ets, {{m.account.id, now}, points, if(old_stats, do: old_stats.active, else: 0),cl, deg, name, comment, meta}) sante = @santai |> Enum.map(fn(s) -> String.trim(String.upcase(s)) end) |> Enum.shuffle() |> Enum.random() - meta = get_user_meta(state, m.account.id) - k = if meta.sex, do: 0.7, else: 0.6 - weight = meta.weight + k = if user_meta.sex, do: 0.7, else: 0.6 + weight = user_meta.weight peak = Float.round((10*points||0.0)/(k*weight), 4) stats = get_full_statistics(state, m.account.id) sober_add = if old_stats && Map.get(old_stats || %{}, :sober_in) do @@ -418,12 +491,24 @@ defmodule LSG.IRC.AlcoologPlugin do "" end + since_str = if stats.since && stats.since_min > 180 do + "(depuis: #{stats.since_s}) " + else + "" + end + msg = fn(nick, extra) -> - "#{sante} #{nick}#{extra}#{up} #{format_points(points)} @#{stats.active}g/l [+#{peak} g/l]" - <> " (15m: #{stats.active15m}, 30m: #{stats.active30m}, 1h: #{stats.active1h}) (sobriété #{at} (dans #{stats.sober_in_s})#{sober_add}) !" + "#{sante} #{nick} #{extra}#{up} #{format_points(points)} @#{stats.active}g/l [+#{peak} g/l]" + <> " (15m: #{stats.active15m}, 30m: #{stats.active30m}, 1h: #{stats.active1h}) #{since_str}(sobriété #{at} (dans #{stats.sober_in_s})#{sober_add}) !" <> " (aujourd'hui #{stats.daily_volumes} points - #{stats.daily_gl} g/l)" end + meta = if beer_id do + Map.put(meta, "untappd:beer_id", beer_id) + else + meta + end + if beer_id do spawn(fn() -> case Untappd.maybe_checkin(m.account, beer_id) do @@ -434,7 +519,7 @@ defmodule LSG.IRC.AlcoologPlugin do |> Enum.filter(fn(b) -> b end) |> Enum.intersperse(", ") |> Enum.join("") - badge = if(badges > 1, do: "badges", else: "badge") + badge = if(length(badges) > 1, do: "badges", else: "badge") m.replyfun.("\\O/ Unlocked untappd #{badge}: #{badges_s}") end :ok @@ -445,7 +530,15 @@ defmodule LSG.IRC.AlcoologPlugin do end) end - local_extra = if auto_set, do: " #{comment} (#{deg}°)", else: "" + local_extra = if auto_set do + if comment do + " #{comment} (#{cl}cl @ #{deg}°)" + else + "#{cl}cl @ #{deg}°" + end + else + "" + end m.replyfun.(msg.(m.sender.nick, local_extra)) notify = IRC.Membership.notify_channels(m.account) -- [{m.network,m.channel}] for {net, chan} <- notify do @@ -456,6 +549,7 @@ defmodule LSG.IRC.AlcoologPlugin do end miss = cond do + points <= 0.6 -> :blague stats.active30m >= 2.9 && stats.active30m < 3 -> :miss3 stats.active30m >= 1.9 && stats.active30m < 2 -> :miss2 stats.active30m >= 0.9 && stats.active30m < 1 -> :miss1 @@ -471,6 +565,9 @@ defmodule LSG.IRC.AlcoologPlugin do end miss = case miss do + :blague -> [ + "c'est une blague ?!" + ] :miss025 -> [ "si peu ?" ] @@ -518,7 +615,6 @@ defmodule LSG.IRC.AlcoologPlugin do end end - {:noreply, state} end def handle_info({:irc, :trigger, "santai", m = %IRC.Message{trigger: %IRC.Trigger{args: _, type: :bang}}}, state) do @@ -549,13 +645,26 @@ defmodule LSG.IRC.AlcoologPlugin do |> Enum.sort_by(fn({_, status}) -> status.active end, &>/2) end + @spec since() :: %{IRC.Account.id() => DateTime.t()} + @doc "Returns the last time the user was at 0 g/l" + def since() do + :ets.foldr(fn({{acct, timestamp}, _vol, current, _cl, _deg, _name, _comment, _m}, acc) -> + if !Map.get(acc, acct) && current == 0 do + date = DateTime.from_unix!(timestamp, :millisecond) + Map.put(acc, acct, date) + else + acc + end + end, %{}, __MODULE__.ETS) + end + def get_full_statistics(nick) do get_full_statistics(data_state(), nick) end defp get_full_statistics(state, nick) do case get_statistics_for_nick(state, nick) do - {count, {_, last_at, last_points, last_active, last_type, last_descr}} -> + {count, {_, last_at, last_points, last_active, last_cl, last_deg, last_type, last_descr, _meta}} -> {active, active_drinks} = current_alcohol_level(state, nick) {_, m30} = alcohol_level_rising(state, nick) {rising, m15} = alcohol_level_rising(state, nick, 15) @@ -601,20 +710,30 @@ defmodule LSG.IRC.AlcoologPlugin do nil end + since = if active > 0 do + since() + |> Map.get(nick) + end + + since_diff = if since, do: Timex.diff(DateTime.utc_now(), since, :minutes) + since_duration = if since, do: Timex.Duration.from_minutes(since_diff) + since_s = if since, do: Timex.Format.Duration.Formatter.lformat(since_duration, "fr", :humanized) + user_status = list |> Enum.shuffle() |> Enum.random() {total_volumes, total_gl} = user_stats(state, nick) - %{active: active, last_at: last_at, last_points: last_points, last_type: last_type, last_descr: last_descr, + %{active: active, last_at: last_at, last_cl: last_cl, last_deg: last_deg, last_points: last_points, last_type: last_type, last_descr: last_descr, trend_symbol: trend, active5m: m5, active15m: m15, active30m: m30, active1h: h1, rising: rising, active_drinks: active_drinks, user_status: user_status, daily_gl: total_gl, daily_volumes: total_volumes, - sober_in: minutes_til_sober, sober_in_s: sober_in_s + sober_in: minutes_til_sober, sober_in_s: sober_in_s, + since: since, since_min: since_diff, since_s: since_s, } _ -> nil @@ -660,7 +779,7 @@ defmodule LSG.IRC.AlcoologPlugin do if account do user = IRC.UserTrack.find_by_account(m.network, account) nick = if(user, do: user.nick, else: account.name) - stats = get_full_statistics(state, nick) + stats = get_full_statistics(state, account.id) if stats && stats.sober_in > 0 do now = DateTime.utc_now() sober = now |> DateTime.add(round(stats.sober_in*60), :second) @@ -693,7 +812,12 @@ defmodule LSG.IRC.AlcoologPlugin do else status.trend_symbol end - "#{nick} #{status.user_status} #{trend_symbol} #{Float.round(status.active, 4)} g/l" + since_str = if status.since_min > 180 do + "depuis: #{status.since_s} | " + else + "" + end + "#{nick} #{status.user_status} #{trend_symbol} #{Float.round(status.active, 4)} g/l [#{since_str}sobre dans: #{status.sober_in_s}]" end) |> Enum.intersperse(", ") |> Enum.join("") @@ -732,54 +856,43 @@ defmodule LSG.IRC.AlcoologPlugin do {:noreply, state} end - # TODO Fix with user/channel membership - def handle_info({:irc, :trigger, "alcoolisme", m = %IRC.Message{trigger: %IRC.Trigger{args: ["semaine"], type: :bang}}}, state) do - aday = 7*((24 * 60)*60) - now = DateTime.utc_now() - before = now - |> DateTime.add(-aday, :second) - |> DateTime.to_unix(:millisecond) - over_time_stats(before, 7, m, state) - end - - def handle_info({:irc, :trigger, "alcoolisme", m = %IRC.Message{trigger: %IRC.Trigger{args: ["30j"], type: :bang}}}, state) do - aday = 31*((24 * 60)*60) - now = DateTime.utc_now() - before = now - |> DateTime.add(-aday, :second) - |> DateTime.to_unix(:millisecond) - over_time_stats(before, 30, m, state) + def user_over_time(account, count) do + user_over_time(data_state(), account, count) end - def handle_info({:irc, :trigger, "alcoolisme", m = %IRC.Message{trigger: %IRC.Trigger{args: ["90j"], type: :bang}}}, state) do - aday = 91*((24 * 60)*60) - now = DateTime.utc_now() - before = now - |> DateTime.add(-aday, :second) - |> DateTime.to_unix(:millisecond) - over_time_stats(before, 90, m, state) - end - - def handle_info({:irc, :trigger, "alcoolisme", m = %IRC.Message{trigger: %IRC.Trigger{args: ["180j"], type: :bang}}}, state) do - aday = 180*((24 * 60)*60) + def user_over_time(state, account, count) do + delay = count*((24 * 60)*60) now = DateTime.utc_now() - before = now - |> DateTime.add(-aday, :second) + before = DateTime.utc_now() + |> DateTime.shift_zone!("Europe/Paris", Tzdata.TimeZoneDatabase) + |> DateTime.add(-delay, :second, Tzdata.TimeZoneDatabase) |> DateTime.to_unix(:millisecond) - over_time_stats(before, 180, m, state) - end + #[ +# {{{:"$1", :"$2"}, :_, :_, :_, :_, :_, :_, :_}, +# [{:andalso, {:==, :"$1", :"$1"}, {:<, :"$2", {:const, 3000}}}], [:lol]} + #] + match = [{{{:"$1", :"$2"}, :_, :_, :_, :_, :_, :_, :_}, + [{:andalso, {:>, :"$2", {:const, before}}, {:==, :"$1", {:const, account.id}}}], [:"$_"]} + ] + :ets.select(state.ets, match) + |> Enum.reduce(Map.new, fn({{_, ts}, vol, _, _, _, _, _, _}, acc) -> + date = DateTime.from_unix!(ts, :millisecond) + |> DateTime.shift_zone!("Europe/Paris", Tzdata.TimeZoneDatabase) + date = if date.hour <= 8 do + DateTime.add(date, -(60*(60*(date.hour+1))), :second, Tzdata.TimeZoneDatabase) + else + date + end + |> DateTime.to_date() - def handle_info({:irc, :trigger, "alcoolisme", m = %IRC.Message{trigger: %IRC.Trigger{args: ["365j"], type: :bang}}}, state) do - aday = 365*((24 * 60)*60) - now = DateTime.utc_now() - before = now - |> DateTime.add(-aday, :second) - |> DateTime.to_unix(:millisecond) - over_time_stats(before, 365, m, state) + Map.put(acc, date, Map.get(acc, date, 0) + vol) + end) end - defp user_over_time(state, account, count) do + def user_over_time_gl(account, count) do + state = data_state() + meta = get_user_meta(state, account.id) delay = count*((24 * 60)*60) now = DateTime.utc_now() before = DateTime.utc_now() @@ -787,14 +900,14 @@ defmodule LSG.IRC.AlcoologPlugin do |> DateTime.add(-delay, :second, Tzdata.TimeZoneDatabase) |> DateTime.to_unix(:millisecond) #[ -# {{{:"$1", :"$2"}, :_, :_, :_, :_}, +# {{{:"$1", :"$2"}, :_, :_, :_, :_, :_, :_, :_}, # [{:andalso, {:==, :"$1", :"$1"}, {:<, :"$2", {:const, 3000}}}], [:lol]} #] - match = [{{{:"$1", :"$2"}, :_, :_, :_, :_}, + match = [{{{:"$1", :"$2"}, :_, :_, :_, :_, :_, :_, :_}, [{:andalso, {:>, :"$2", {:const, before}}, {:==, :"$1", {:const, account.id}}}], [:"$_"]} ] :ets.select(state.ets, match) - |> Enum.reduce(Map.new, fn({{_, ts}, vol, _, _, _}, acc) -> + |> Enum.reduce(Map.new, fn({{_, ts}, vol, _, _, _, _, _, _}, acc) -> date = DateTime.from_unix!(ts, :millisecond) |> DateTime.shift_zone!("Europe/Paris", Tzdata.TimeZoneDatabase) @@ -804,23 +917,28 @@ defmodule LSG.IRC.AlcoologPlugin do date end |> DateTime.to_date() + weight = meta.weight + k = if meta.sex, do: 0.7, else: 0.6 + gl = (10*vol)/(k*weight) - Map.put(acc, date, Map.get(acc, date, 0) + vol) + Map.put(acc, date, Map.get(acc, date, 0) + gl) end) end + + defp over_time_stats(before, j, m, state) do - #match = :ets.fun2ms(fn(obj = {{^nick, date}, _, _, _, _}) when date > before -> obj end) - match = [{{{:_, :"$1"}, :_, :_, :_, :_}, + #match = :ets.fun2ms(fn(obj = {{^nick, date}, _, _, _, _, _, _, _}) when date > before -> obj end) + match = [{{{:_, :"$1"}, :_, :_, :_, :_, :_, :_, :_}, [{:>, :"$1", {:const, before}}], [:"$_"]} ] # tuple ets: {{nick, date}, volumes, current, nom, commentaire} members = IRC.Membership.members_or_friends(m.account, m.network, m.channel) drinks = :ets.select(state.ets, match) - |> Enum.filter(fn({{account, _}, _, _, _, _}) -> Enum.member?(members, account) end) - |> Enum.sort_by(fn({{_, ts}, _, _, _, _}) -> ts end, &>/2) + |> Enum.filter(fn({{account, _}, _, _, _, _, _, _, _}) -> Enum.member?(members, account) end) + |> Enum.sort_by(fn({{_, ts}, _, _, _, _, _, _, _}) -> ts end, &>/2) - top = Enum.reduce(drinks, %{}, fn({{nick, _}, vol, _, _, _}, acc) -> + top = Enum.reduce(drinks, %{}, fn({{nick, _}, vol, _, _, _, _, _, _}, acc) -> all = Map.get(acc, nick, 0) Map.put(acc, nick, all + vol) end) @@ -872,7 +990,7 @@ defmodule LSG.IRC.AlcoologPlugin do meta = Map.merge(@default_user_meta, %{sex: h, weight: weight, loss_factor: factor}) put_user_meta(state, m.account.id, meta) fat = ["t'as grossi...", "bientôt la tonne ?", "t'as encore abusé du fromage ?"] - thin = ["en route vers l'anorexie ?", "t'as grossi...", "faut manger plus de fromage!"] + thin = ["en route vers l'anorexie ?", "t'as vomi...", "t'as grossi...", "faut manger plus de fromage!"] msg = cond do old_meta.weight < meta.weight -> Enum.random(Enum.shuffle(fat)) old_meta.weight == meta.weight -> "ok" @@ -886,7 +1004,7 @@ defmodule LSG.IRC.AlcoologPlugin do def handle_info({:irc, :trigger, "santai", m = %IRC.Message{trigger: %IRC.Trigger{args: args, type: :minus}}}, state) do case get_statistics_for_nick(state, m.account.id) do - {_, obj = {_, date, points, _last_active, type, descr}} -> + {_, obj = {_, date, points, _last_active, _cl, _deg, type, descr, _meta}} -> :dets.delete_object(state.dets, obj) :ets.delete(state.ets, {m.account.id, date}) m.replyfun.("supprimé: #{m.sender.nick} #{points} #{type} #{descr}") @@ -903,6 +1021,7 @@ defmodule LSG.IRC.AlcoologPlugin do end end + def handle_info({:irc, :trigger, "alcoolisme", m = %IRC.Message{trigger: %IRC.Trigger{args: args, type: :bang}}}, state) do {account, duration} = case args do [nick | rest] -> {IRC.Account.find_always_by_nick(m.network, m.channel, nick), rest} @@ -951,6 +1070,7 @@ defmodule LSG.IRC.AlcoologPlugin do <> (if stats.active > 0 || stats.active15m > 0 || stats.active30m > 0 || stats.active1h > 0, do: ": #{trend_symbol} #{Float.round(stats.active, 4)}g/l ", else: "") <> (if stats.active30m > 0 || stats.active1h > 0, do: "(15m: #{stats.active15m}, 30m: #{stats.active30m}, 1h: #{stats.active1h}) ", else: "") <> (if stats.sober_in > 0, do: "— Sobre dans #{stats.sober_in_s} ", else: "") + <> (if stats.since && stats.since_min > 180, do: "— Paitai depuis #{stats.since_s} ", else: "") <> "— Dernier verre: #{present_type(stats.last_type, stats.last_descr)} [#{Float.round(stats.last_points+0.0, 4)}] " <> "#{format_duration_from_now(stats.last_at)} " <> (if stats.daily_volumes > 0, do: "— Aujourd'hui: #{stats.daily_volumes} #{stats.daily_gl}g/l", else: "") @@ -969,7 +1089,7 @@ defmodule LSG.IRC.AlcoologPlugin do # Account merge def handle_info({:account_change, old_id, new_id}, state) do - spec = [{{:"$1", :_, :_, :_, :_, :_}, [{:==, :"$1", {:const, old_id}}], [:"$_"]}] + spec = [{{:"$1", :_, :_, :_, :_, :_, :_, :_, :_}, [{:==, :"$1", {:const, old_id}}], [:"$_"]}] Util.ets_mutate_select_each(:dets, state.dets, spec, fn(table, obj) -> Logger.debug("alcolog/account_change:: merging #{old_id} -> #{new_id}") rename_object_owner(table, state.ets, obj, old_id, new_id) @@ -991,11 +1111,11 @@ defmodule LSG.IRC.AlcoologPlugin do end end - defp rename_object_owner(table, ets, object = {old_id, date, volume, current, name, comment}, old_id, new_id) do + defp rename_object_owner(table, ets, object = {old_id, date, volume, current, cl, deg, name, comment, meta}, old_id, new_id) do :dets.delete_object(table, object) :ets.delete(ets, {old_id, date}) - :dets.insert(table, {new_id, date, volume, current, name, comment}) - :ets.insert(ets, {{new_id, date}, volume, current, name, comment}) + :dets.insert(table, {new_id, date, volume, current, cl, deg, name, comment, meta}) + :ets.insert(ets, {{new_id, date}, volume, current, cl, deg, name, comment, meta}) end # Account: move from nick to account id @@ -1005,9 +1125,9 @@ defmodule LSG.IRC.AlcoologPlugin do mapping = Enum.reduce(accounts, Map.new, fn({:account, _net, _chan, nick, account_id}, acc) -> Map.put(acc, String.downcase(nick), account_id) end) - spec = [{{:"$1", :_, :_, :_, :_, :_}, [], [:"$_"]}] + spec = [{{:"$1", :_, :_, :_, :_, :_, :_, :_, :_}, [], [:"$_"]}] Logger.debug("accounts:: mappings #{inspect mapping}") - Util.ets_mutate_select_each(:dets, state.dets, spec, fn(table, obj = {nick, _date, _vol, _cur, _name, _comment}) -> + Util.ets_mutate_select_each(:dets, state.dets, spec, fn(table, obj = {nick, _date, _vol, _cur, _cl, _deg, _name, _comment, _meta}) -> #Logger.debug("accounts:: item #{inspect(obj)}") if new_id = Map.get(mapping, nick) do Logger.debug("alcolog/accounts:: merging #{nick} -> #{new_id}") @@ -1019,7 +1139,7 @@ defmodule LSG.IRC.AlcoologPlugin do def handle_info({:account, _net, _chan, nick, account_id}, state) do nick = String.downcase(nick) - spec = [{{:"$1", :_, :_, :_, :_, :_}, [{:==, :"$1", {:const, nick}}], [:"$_"]}] + spec = [{{:"$1", :_, :_, :_, :_, :_, :_, :_, :_}, [{:==, :"$1", {:const, nick}}], [:"$_"]}] Util.ets_mutate_select_each(:dets, state.dets, spec, fn(table, obj) -> Logger.debug("alcoolog/account:: merging #{nick} -> #{account_id}") rename_object_owner(table, state.ets, obj, nick, account_id) @@ -1039,10 +1159,19 @@ defmodule LSG.IRC.AlcoologPlugin do {:noreply, state} end + def nick_history(account) do + spec = [ + {{{:"$1", :_}, :_, :_, :_, :_, :_, :_, :_}, + [{:==, :"$1", {:const, account.id}}], + [:"$_"]} + ] + :ets.select(data_state().ets, spec) + end + defp get_statistics_for_nick(state, account_id) do qvc = :dets.lookup(state.dets, account_id) - |> Enum.sort_by(fn({_, ts, _, _, _, _}) -> ts end, &</2) - count = Enum.reduce(qvc, 0, fn({_nick, _ts, points, _active, _type, _descr}, acc) -> acc + (points||0) end) + |> Enum.sort_by(fn({_, ts, _, _, _, _, _, _, _}) -> ts end, &</2) + count = Enum.reduce(qvc, 0, fn({_nick, _ts, points, _active, _cl, _deg, _type, _descr, _meta}, acc) -> acc + (points||0) end) last = List.last(qvc) || nil {count, last} end @@ -1102,6 +1231,10 @@ defmodule LSG.IRC.AlcoologPlugin do # stop folding when ? # + def user_stats(account) do + user_stats(data_state(), account.id) + end + defp user_stats(state = %{ets: ets}, account_id) do meta = get_user_meta(state, account_id) aday = (10 * 60)*60 @@ -1111,7 +1244,7 @@ defmodule LSG.IRC.AlcoologPlugin do |> DateTime.to_unix(:millisecond) #match = :ets.fun2ms(fn(obj = {{^nick, date}, _, _, _, _}) when date > before -> obj end) match = [ - {{{:"$1", :"$2"}, :_, :_, :_, :_}, + {{{:"$1", :"$2"}, :_, :_, :_, :_, :_, :_, :_}, [ {:>, :"$2", {:const, before}}, {:"=:=", {:const, account_id}, :"$1"} @@ -1120,7 +1253,7 @@ defmodule LSG.IRC.AlcoologPlugin do # tuple ets: {{nick, date}, volumes, current, nom, commentaire} drinks = :ets.select(ets, match) # {date, single_peak} - total_volume = Enum.reduce(drinks, 0.0, fn({{_, date}, volume, _, _, _}, acc) -> + total_volume = Enum.reduce(drinks, 0.0, fn({{_, date}, volume, _, _, _, _, _, _}, acc) -> acc + volume end) k = if meta.sex, do: 0.7, else: 0.6 @@ -1155,7 +1288,7 @@ defmodule LSG.IRC.AlcoologPlugin do |> DateTime.to_unix(:millisecond) #match = :ets.fun2ms(fn(obj = {{^nick, date}, _, _, _, _}) when date > before -> obj end) match = [ - {{{:"$1", :"$2"}, :_, :_, :_, :_}, + {{{:"$1", :"$2"}, :_, :_, :_, :_, :_, :_, :_}, [ {:>, :"$2", {:const, before}}, {:"=:=", {:const, account_id}, :"$1"} @@ -1163,9 +1296,9 @@ defmodule LSG.IRC.AlcoologPlugin do ] # tuple ets: {{nick, date}, volumes, current, nom, commentaire} drinks = :ets.select(ets, match) - |> Enum.sort_by(fn({{_, date}, _, _, _, _}) -> date end, &</2) + |> Enum.sort_by(fn({{_, date}, _, _, _, _, _, _, _}) -> date end, &</2) # {date, single_peak} - {all, last_drink_at, gl, active_drinks} = Enum.reduce(drinks, {0.0, nil, [], 0}, fn({{_, date}, volume, _, _, _}, {all, last_at, acc, active_drinks}) -> + {all, last_drink_at, gl, active_drinks} = Enum.reduce(drinks, {0.0, nil, [], 0}, fn({{_, date}, volume, _, _, _, _, _, _}, {all, last_at, acc, active_drinks}) -> k = if meta.sex, do: 0.7, else: 0.6 weight = meta.weight peak = (10*volume)/(k*weight) @@ -1249,4 +1382,3 @@ defmodule LSG.IRC.AlcoologPlugin do end end - |