summaryrefslogtreecommitdiff
path: root/lib/plugins/alcoolog.ex
diff options
context:
space:
mode:
Diffstat (limited to 'lib/plugins/alcoolog.ex')
-rw-r--r--lib/plugins/alcoolog.ex1689
1 files changed, 1078 insertions, 611 deletions
diff --git a/lib/plugins/alcoolog.ex b/lib/plugins/alcoolog.ex
index 69bd60c..de69b13 100644
--- a/lib/plugins/alcoolog.ex
+++ b/lib/plugins/alcoolog.ex
@@ -49,27 +49,40 @@ defmodule Nola.Plugins.Alcoolog do
@default_user_meta %{weight: 77.4, sex: true, loss_factor: 15}
def data_state() do
- dets_filename = (Nola.data_path() <> "/" <> "alcoolisme.dets") |> String.to_charlist
- dets_meta_filename = (Nola.data_path() <> "/" <> "alcoolisme_meta.dets") |> String.to_charlist
+ dets_filename = (Nola.data_path() <> "/" <> "alcoolisme.dets") |> String.to_charlist()
+
+ dets_meta_filename =
+ (Nola.data_path() <> "/" <> "alcoolisme_meta.dets") |> String.to_charlist()
+
%{dets: dets_filename, meta: dets_meta_filename, ets: __MODULE__.ETS}
end
def init(_) do
- triggers = for(t <- @pubsub_triggers, do: "trigger:"<>t)
+ triggers = for(t <- @pubsub_triggers, do: "trigger:" <> t)
+
for sub <- @pubsub ++ triggers do
{:ok, _} = Registry.register(Nola.PubSub, sub, plugin: __MODULE__)
end
- dets_filename = (Nola.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}])
- dets_meta_filename = (Nola.data_path() <> "/" <> "alcoolisme_meta.dets") |> String.to_charlist
- {:ok, meta} = :dets.open_file(dets_meta_filename, [{:type,:set}])
- traverse_fun = fn(obj, dets) ->
+
+ dets_filename = (Nola.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}])
+
+ dets_meta_filename =
+ (Nola.data_path() <> "/" <> "alcoolisme_meta.dets") |> String.to_charlist()
+
+ {:ok, meta} = :dets.open_file(dets_meta_filename, [{:type, :set}])
+
+ traverse_fun = fn obj, dets ->
case obj do
object = {nick, naive = %NaiveDateTime{}, volumes, active, cl, deg, name, comment} ->
- date = naive
- |> DateTime.from_naive!("Etc/UTC")
- |> DateTime.to_unix()
+ date =
+ naive
+ |> DateTime.from_naive!("Etc/UTC")
+ |> DateTime.to_unix()
+
new = {nick, date, volumes, active, cl, deg, name, comment, Map.new()}
:dets.delete_object(dets, object)
:dets.insert(dets, new)
@@ -77,9 +90,11 @@ defmodule Nola.Plugins.Alcoolog do
dets
object = {nick, naive = %NaiveDateTime{}, volumes, active, cl, deg, name, comment, meta} ->
- date = naive
- |> DateTime.from_naive!("Etc/UTC")
- |> DateTime.to_unix()
+ date =
+ naive
+ |> DateTime.from_naive!("Etc/UTC")
+ |> DateTime.to_unix()
+
new = {nick, date, volumes, active, cl, deg, name, comment, Map.new()}
:dets.delete_object(dets, object)
:dets.insert(dets, new)
@@ -94,6 +109,7 @@ defmodule Nola.Plugins.Alcoolog do
dets
end
end
+
:dets.foldl(traverse_fun, dets, dets)
:dets.sync(dets)
state = %{dets: dets, meta: meta, ets: ets}
@@ -101,59 +117,82 @@ defmodule Nola.Plugins.Alcoolog do
end
@eau ["santo", "santeau"]
- def handle_info({:irc, :trigger, santeau, m = %Nola.Message{trigger: %Nola.Trigger{args: _, type: :bang}}}, state) when santeau in @eau do
+ def handle_info(
+ {:irc, :trigger, santeau,
+ m = %Nola.Message{trigger: %Nola.Trigger{args: _, type: :bang}}},
+ state
+ )
+ when santeau in @eau do
Nola.Plugins.Txt.reply_random(m, "alcoolog.santo")
{:noreply, state}
end
- def handle_info({:irc, :trigger, "soif", m = %Nola.Message{trigger: %Nola.Trigger{args: _, type: :bang}}}, state) do
- now = DateTime.utc_now()
- |> Timex.Timezone.convert("Europe/Paris")
+ def handle_info(
+ {:irc, :trigger, "soif", m = %Nola.Message{trigger: %Nola.Trigger{args: _, type: :bang}}},
+ state
+ ) do
+ now =
+ DateTime.utc_now()
+ |> 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, apero?} = cond do
- now.hour >= 0 && now.hour < 6 ->
- {["apéro tardif ? Je dis OUI ! SANTAI !"], true}
- now.hour >= 6 && now.hour < 12 ->
- if day_of_week >= 6 do
- {["de l'alcool pour le petit dej ? le week-end, pas de problème !"], true}
- else
- {["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})",
- "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}",
- "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
- |> Enum.shuffle()
- |> Enum.random()
+ {txt, apero?} =
+ cond do
+ now.hour >= 0 && now.hour < 6 ->
+ {["apéro tardif ? Je dis OUI ! SANTAI !"], true}
+
+ now.hour >= 6 && now.hour < 12 ->
+ if day_of_week >= 6 do
+ {["de l'alcool pour le petit dej ? le week-end, pas de problème !"], true}
+ else
+ {["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})",
+ "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}",
+ "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
+ |> Enum.shuffle()
+ |> Enum.random()
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
@@ -161,99 +200,151 @@ defmodule Nola.Plugins.Alcoolog do
{:noreply, state}
end
- def handle_info({:irc, :trigger, "sobrepour", m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :bang}}}, state) do
+ def handle_info(
+ {:irc, :trigger, "sobrepour",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :bang}}},
+ state
+ ) do
args = Enum.join(args, " ")
{:ok, now} = DateTime.now("Europe/Paris", Tzdata.TimeZoneDatabase)
- time = case args do
- "demain " <> time ->
- {h, m} = case String.split(time, [":", "h"]) do
- [hour, ""] ->
- IO.puts ("h #{inspect hour}")
- {h, _} = Integer.parse(hour)
- {h, 0}
- [hour, min] when min != "" ->
- {h, _} = Integer.parse(hour)
- {m, _} = Integer.parse(min)
- {h, m}
- [hour] ->
- IO.puts ("h #{inspect hour}")
- {h, _} = Integer.parse(hour)
- {h, 0}
- _ -> {0, 0}
- end
- secs = ((60*60)*24)
- day = DateTime.add(now, secs, :second, Tzdata.TimeZoneDatabase)
- %DateTime{day | hour: h, minute: m, second: 0}
- "après demain " <> time ->
- secs = 2*((60*60)*24)
- DateTime.add(now, secs, :second, Tzdata.TimeZoneDatabase)
- datetime ->
- case Timex.Parse.DateTime.Parser.parse(datetime, "{}") do
- {:ok, dt} -> dt
- _ -> nil
- end
- end
+
+ time =
+ case args do
+ "demain " <> time ->
+ {h, m} =
+ case String.split(time, [":", "h"]) do
+ [hour, ""] ->
+ IO.puts("h #{inspect(hour)}")
+ {h, _} = Integer.parse(hour)
+ {h, 0}
+
+ [hour, min] when min != "" ->
+ {h, _} = Integer.parse(hour)
+ {m, _} = Integer.parse(min)
+ {h, m}
+
+ [hour] ->
+ IO.puts("h #{inspect(hour)}")
+ {h, _} = Integer.parse(hour)
+ {h, 0}
+
+ _ ->
+ {0, 0}
+ end
+
+ secs = 60 * 60 * 24
+ day = DateTime.add(now, secs, :second, Tzdata.TimeZoneDatabase)
+ %DateTime{day | hour: h, minute: m, second: 0}
+
+ "après demain " <> time ->
+ secs = 2 * (60 * 60 * 24)
+ DateTime.add(now, secs, :second, Tzdata.TimeZoneDatabase)
+
+ datetime ->
+ case Timex.Parse.DateTime.Parser.parse(datetime, "{}") do
+ {:ok, dt} -> dt
+ _ -> nil
+ end
+ end
if time do
meta = get_user_meta(state, m.account.id)
stats = get_full_statistics(state, m.account.id)
- duration = round(DateTime.diff(time, now)/60.0)
+ duration = round(DateTime.diff(time, now) / 60.0)
- IO.puts "diff #{inspect duration} sober in #{inspect stats.sober_in}"
+ IO.puts("diff #{inspect(duration)} sober in #{inspect(stats.sober_in)}")
if duration < stats.sober_in do
int = stats.sober_in - duration
m.replyfun.("désolé, aucune chance! tu seras sobre #{format_minute_duration(int)} après!")
else
remaining = duration - stats.sober_in
+
if remaining < 30 do
m.replyfun.("moins de 30 minutes de sobriété, c'est impossible de boire plus")
else
- loss_per_minute = ((meta.loss_factor/100)/60)
- remaining_gl = (remaining-30)*loss_per_minute
- m.replyfun.("marge de boisson: #{inspect remaining} minutes, #{remaining_gl} g/l")
+ loss_per_minute = meta.loss_factor / 100 / 60
+ remaining_gl = (remaining - 30) * loss_per_minute
+ m.replyfun.("marge de boisson: #{inspect(remaining)} minutes, #{remaining_gl} g/l")
end
end
-
end
+
{:noreply, state}
end
- def handle_info({:irc, :trigger, "alcoolog", m = %Nola.Message{trigger: %Nola.Trigger{args: [], type: :plus}}}, state) do
+ def handle_info(
+ {:irc, :trigger, "alcoolog",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: [], type: :plus}}},
+ state
+ ) do
{:ok, token} = Nola.Token.new({:alcoolog, :index, m.sender.network, m.channel})
- url = NolaWeb.Router.Helpers.alcoolog_url(NolaWeb.Endpoint, :index, m.network, NolaWeb.format_chan(m.channel), token)
+
+ url =
+ NolaWeb.Router.Helpers.alcoolog_url(
+ NolaWeb.Endpoint,
+ :index,
+ m.network,
+ NolaWeb.format_chan(m.channel),
+ token
+ )
+
m.replyfun.("-> #{url}")
{:noreply, state}
end
- def handle_info({:irc, :trigger, "alcoolog", m = %Nola.Message{trigger: %Nola.Trigger{args: [], type: :bang}}}, state) do
- url = NolaWeb.Router.Helpers.alcoolog_url(NolaWeb.Endpoint, :index, m.network, NolaWeb.format_chan(m.channel))
+ def handle_info(
+ {:irc, :trigger, "alcoolog",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: [], type: :bang}}},
+ state
+ ) do
+ url =
+ NolaWeb.Router.Helpers.alcoolog_url(
+ NolaWeb.Endpoint,
+ :index,
+ m.network,
+ NolaWeb.format_chan(m.channel)
+ )
+
m.replyfun.("-> #{url}")
{:noreply, state}
end
- def handle_info({:irc, :trigger, "alcool", m = %Nola.Message{trigger: %Nola.Trigger{args: args = [cl, deg], type: :bang}}}, state) do
+ def handle_info(
+ {:irc, :trigger, "alcool",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: args = [cl, deg], type: :bang}}},
+ state
+ ) do
{cl, _} = Util.float_paparse(cl)
{deg, _} = Util.float_paparse(deg)
points = Alcool.units(cl, deg)
meta = get_user_meta(state, m.account.id)
k = if meta.sex, do: 0.7, else: 0.6
weight = meta.weight
- gl = (10*points)/(k*weight)
- duration = round(gl/((meta.loss_factor/100)/60))+30
- sober_in_s = if duration > 0 do
+ gl = 10 * points / (k * weight)
+ duration = round(gl / (meta.loss_factor / 100 / 60)) + 30
+
+ sober_in_s =
+ if duration > 0 do
duration = Timex.Duration.from_minutes(duration)
- Timex.Format.Duration.Formatter.lformat(duration, "fr", :humanized)
- else
- ""
- end
+ Timex.Format.Duration.Formatter.lformat(duration, "fr", :humanized)
+ else
+ ""
+ end
+
+ m.replyfun.(
+ "Il y a #{Float.round(points + 0.0, 4)} unités d'alcool dans #{cl}cl à #{deg}° (#{Float.round(gl + 0.0, 4)} g/l, #{sober_in_s})"
+ )
- m.replyfun.("Il y a #{Float.round(points+0.0, 4)} unités d'alcool dans #{cl}cl à #{deg}° (#{Float.round(gl + 0.0, 4)} g/l, #{sober_in_s})")
{:noreply, state}
end
- def handle_info({:irc, :trigger, "santai", m = %Nola.Message{trigger: %Nola.Trigger{args: [cl, deg | comment], type: :bang}}}, state) do
+ def handle_info(
+ {:irc, :trigger, "santai",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: [cl, deg | comment], type: :bang}}},
+ state
+ ) do
santai(m, state, cl, deg, comment)
{:noreply, state}
end
@@ -263,80 +354,138 @@ defmodule Nola.Plugins.Alcoolog do
"{{message.sender.nick}}: et voilà la petite sœur !"
]
- def handle_info({:irc, :trigger, "bis", m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :bang}}}, state) do
+ def handle_info(
+ {:irc, :trigger, "bis",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :bang}}},
+ state
+ ) do
handle_info({:irc, :trigger, "moar", m}, state)
end
- def handle_info({:irc, :trigger, "again", m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :bang}}}, state) do
+
+ def handle_info(
+ {:irc, :trigger, "again",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :bang}}},
+ state
+ ) do
handle_info({:irc, :trigger, "moar", m}, state)
end
- def handle_info({:irc, :trigger, "moar", m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :bang}}}, state) do
+ def handle_info(
+ {:irc, :trigger, "moar",
+ m = %Nola.Message{trigger: %Nola.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
+ 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")
+ 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
+
+ _ ->
+ 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
+ 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, "("<>_} ->
- try do
- {:ok, result} = Abacus.eval(cl)
- {result, nil}
- rescue
- _ -> {nil, "cl: invalid calc expression"}
- end
- {:error, _} -> {nil, "cl: invalid value"}
- end
+ {cl, cl_extra} =
+ case {Util.float_paparse(cl), cl} do
+ {{cl, extra}, _} ->
+ {cl, extra}
+
+ {:error, "(" <> _} ->
+ try do
+ {:ok, result} = Abacus.eval(cl)
+ {result, nil}
+ rescue
+ _ -> {nil, "cl: invalid calc expression"}
+ end
- {deg, comment, auto_set, beer_id} = case Util.float_paparse(deg) do
- {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
- {:ok, %{"response" => %{"beers" => %{"count" => count, "items" => [%{"beer" => beer, "brewery" => brewery} | _]}}}} ->
- {Map.get(beer, "beer_abv"), "#{Map.get(brewery, "brewery_name")}: #{Map.get(beer, "beer_name")}", true, Map.get(beer, "bid")}
- _ ->
+ {:error, _} ->
+ {nil, "cl: invalid value"}
+ end
+
+ {deg, comment, auto_set, beer_id} =
+ case Util.float_paparse(deg) do
+ {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
+ {:ok,
+ %{
+ "response" => %{
+ "beers" => %{
+ "count" => count,
+ "items" => [%{"beer" => beer, "brewery" => brewery} | _]
+ }
+ }
+ }} ->
+ {Map.get(beer, "beer_abv"),
+ "#{Map.get(brewery, "brewery_name")}: #{Map.get(beer, "beer_name")}", true,
+ Map.get(beer, "bid")}
+
+ _ ->
{deg, "could not find beer", false, nil}
- end
- end
+ end
+ end
cond do
- cl == nil -> m.replyfun.(cl_extra)
- deg == nil -> m.replyfun.(comment)
- cl >= 500 || deg >= 100 -> Nola.Plugins.Txt.reply_random(m, "alcoolog.drink_toohuge")
- cl == 0 || deg == 0 -> Nola.Plugins.Txt.reply_random(m, "alcoolog.drink_zero")
- cl < 0 || deg < 0 -> Nola.Plugins.Txt.reply_random(m, "alcoolog.drink_negative")
+ cl == nil ->
+ m.replyfun.(cl_extra)
+
+ deg == nil ->
+ m.replyfun.(comment)
+
+ cl >= 500 || deg >= 100 ->
+ Nola.Plugins.Txt.reply_random(m, "alcoolog.drink_toohuge")
+
+ cl == 0 || deg == 0 ->
+ Nola.Plugins.Txt.reply_random(m, "alcoolog.drink_zero")
+
+ cl < 0 || deg < 0 ->
+ Nola.Plugins.Txt.reply_random(m, "alcoolog.drink_negative")
+
true ->
points = Alcool.units(cl, deg)
- now = m.at || DateTime.utc_now()
- |> DateTime.to_unix(: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)
@@ -344,87 +493,132 @@ defmodule Nola.Plugins.Alcoolog do
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()
+
+ :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()
sante = Nola.Plugins.Txt.random("alcoolog.santai")
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)
+ 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
- mins = round(stats.sober_in - old_stats.sober_in)
- " [+#{mins}m]"
- else
- ""
- end
+
+ sober_add =
+ if old_stats && Map.get(old_stats || %{}, :sober_in) do
+ mins = round(stats.sober_in - old_stats.sober_in)
+ " [+#{mins}m]"
+ else
+ ""
+ end
+
nonow = DateTime.utc_now()
- sober = nonow |> DateTime.add(round(stats.sober_in*60), :second)
- |> Timex.Timezone.convert("Europe/Paris")
- at = if nonow.day == sober.day do
- {:ok, detail} = Timex.Format.DateTime.Formatters.Default.lformat(sober, "aujourd'hui {h24}:{m}", "fr")
- detail
- else
- {:ok, detail} = Timex.Format.DateTime.Formatters.Default.lformat(sober, "{WDfull} {h24}:{m}", "fr")
- detail
- end
- up = if stats.active_drinks > 1 do
- " " <> Enum.join(for(_ <- 1..stats.active_drinks, do: "▲")) <> ""
- else
- ""
- end
+ sober =
+ nonow
+ |> DateTime.add(round(stats.sober_in * 60), :second)
+ |> Timex.Timezone.convert("Europe/Paris")
- since_str = if stats.since && stats.since_min > 180 do
- "(depuis: #{stats.since_s}) "
- else
- ""
- end
+ at =
+ if nonow.day == sober.day do
+ {:ok, detail} =
+ Timex.Format.DateTime.Formatters.Default.lformat(
+ sober,
+ "aujourd'hui {h24}:{m}",
+ "fr"
+ )
- 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}) #{since_str}(sobriété #{at} (dans #{stats.sober_in_s})#{sober_add}) !"
- <> " (aujourd'hui #{stats.daily_volumes} points - #{stats.daily_gl} g/l)"
- end
+ detail
+ else
+ {:ok, detail} =
+ Timex.Format.DateTime.Formatters.Default.lformat(sober, "{WDfull} {h24}:{m}", "fr")
- meta = if beer_id do
- Map.put(meta, "untappd:beer_id", beer_id)
- else
- meta
+ detail
+ end
+
+ up =
+ if stats.active_drinks > 1 do
+ " " <> Enum.join(for(_ <- 1..stats.active_drinks, do: "▲")) <> ""
+ else
+ ""
+ 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}) #{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() ->
+ spawn(fn ->
case Untappd.maybe_checkin(m.account, beer_id) do
{:ok, body} ->
badges = get_in(body, ["badges", "items"])
+
if badges != [] do
- badges_s = Enum.map(badges, fn(badge) -> Map.get(badge, "badge_name") end)
- |> Enum.filter(fn(b) -> b end)
- |> Enum.intersperse(", ")
- |> Enum.join("")
- badge = if(length(badges) > 1, do: "badges", else: "badge")
- m.replyfun.("\\O/ Unlocked untappd #{badge}: #{badges_s}")
+ badges_s =
+ Enum.map(badges, fn badge -> Map.get(badge, "badge_name") end)
+ |> Enum.filter(fn b -> b end)
+ |> Enum.intersperse(", ")
+ |> Enum.join("")
+
+ badge = if(length(badges) > 1, do: "badges", else: "badge")
+ m.replyfun.("\\O/ Unlocked untappd #{badge}: #{badges_s}")
end
+
:ok
- {:error, {:http_error, error}} when is_integer(error) -> m.replyfun.("Checkin to Untappd failed: #{to_string(error)}")
- {:error, {:http_error, error}} -> m.replyfun.("Checkin to Untappd failed: #{inspect error}")
- _ -> :error
+
+ {:error, {:http_error, error}} when is_integer(error) ->
+ m.replyfun.("Checkin to Untappd failed: #{to_string(error)}")
+
+ {:error, {:http_error, error}} ->
+ m.replyfun.("Checkin to Untappd failed: #{inspect(error)}")
+
+ _ ->
+ :error
end
end)
end
- local_extra = if auto_set do
- if comment do
- " #{comment} (#{cl}cl @ #{deg}°)"
+ local_extra =
+ if auto_set do
+ if comment do
+ " #{comment} (#{cl}cl @ #{deg}°)"
+ else
+ "#{cl}cl @ #{deg}°"
+ end
else
- "#{cl}cl @ #{deg}°"
+ ""
end
- else
- ""
- end
+
m.replyfun.(msg.(m.sender.nick, local_extra))
- notify = Nola.Membership.notify_channels(m.account) -- [{m.network,m.channel}]
+ notify = Nola.Membership.notify_channels(m.account) -- [{m.network, m.channel}]
+
for {net, chan} <- notify do
user = Nola.UserTrack.find_by_account(net, m.account)
nick = if(user, do: user.nick, else: m.account.name)
@@ -432,24 +626,26 @@ defmodule Nola.Plugins.Alcoolog do
Nola.Irc.Connection.broadcast_message(net, chan, msg.(nick, extra))
end
- miss = cond do
- points <= 0.6 -> :small
- stats.active30m >= 2.9 && stats.active30m < 3 -> :miss3
- stats.active30m >= 1.9 && stats.active30m < 2 -> :miss2
- stats.active30m >= 0.9 && stats.active30m < 1 -> :miss1
- stats.active30m >= 0.45 && stats.active30m < 0.5 -> :miss05
- stats.active30m >= 0.20 && stats.active30m < 0.20 -> :miss025
- stats.active30m >= 3 && stats.active1h < 3.15 -> :small3
- stats.active30m >= 2 && stats.active1h < 2.15 -> :small2
- stats.active30m >= 1.5 && stats.active1h < 1.5 -> :small15
- stats.active30m >= 1 && stats.active1h < 1.15 -> :small1
- stats.active30m >= 0.5 && stats.active1h <= 0.51 -> :small05
- stats.active30m >= 0.25 && stats.active30m <= 0.255 -> :small025
- true -> nil
- end
+ miss =
+ cond do
+ points <= 0.6 -> :small
+ stats.active30m >= 2.9 && stats.active30m < 3 -> :miss3
+ stats.active30m >= 1.9 && stats.active30m < 2 -> :miss2
+ stats.active30m >= 0.9 && stats.active30m < 1 -> :miss1
+ stats.active30m >= 0.45 && stats.active30m < 0.5 -> :miss05
+ stats.active30m >= 0.20 && stats.active30m < 0.20 -> :miss025
+ stats.active30m >= 3 && stats.active1h < 3.15 -> :small3
+ stats.active30m >= 2 && stats.active1h < 2.15 -> :small2
+ stats.active30m >= 1.5 && stats.active1h < 1.5 -> :small15
+ stats.active30m >= 1 && stats.active1h < 1.15 -> :small1
+ stats.active30m >= 0.5 && stats.active1h <= 0.51 -> :small05
+ stats.active30m >= 0.25 && stats.active30m <= 0.255 -> :small025
+ true -> nil
+ end
if miss do
miss = Nola.Plugins.Txt.random("alcoolog.#{to_string(miss)}")
+
if miss do
for {net, chan} <- Nola.Membership.notify_channels(m.account) do
user = Nola.UserTrack.find_by_account(net, m.account)
@@ -461,45 +657,59 @@ defmodule Nola.Plugins.Alcoolog do
end
end
- def handle_info({:irc, :trigger, "santai", m = %Nola.Message{trigger: %Nola.Trigger{args: _, type: :bang}}}, state) do
+ def handle_info(
+ {:irc, :trigger, "santai",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: _, type: :bang}}},
+ state
+ ) do
m.replyfun.("!santai <cl> <degrés> [commentaire]")
{:noreply, state}
end
def get_all_stats() do
Nola.Account.all_accounts()
- |> Enum.map(fn(account) -> {account.id, get_full_statistics(account.id)} end)
- |> Enum.filter(fn({_nick, status}) -> status && (status.active > 0 || status.active30m > 0) end)
- |> Enum.sort_by(fn({_, status}) -> status.active end, &>/2)
+ |> Enum.map(fn account -> {account.id, get_full_statistics(account.id)} end)
+ |> Enum.filter(fn {_nick, status} ->
+ status && (status.active > 0 || status.active30m > 0)
+ end)
+ |> Enum.sort_by(fn {_, status} -> status.active end, &>/2)
end
def get_channel_statistics(account, network, nil) do
Nola.Membership.expanded_members_or_friends(account, network, nil)
- |> Enum.map(fn({account, _, nick}) -> {nick, get_full_statistics(account.id)} end)
- |> Enum.filter(fn({_nick, status}) -> status && (status.active > 0 || status.active30m > 0) end)
- |> Enum.sort_by(fn({_, status}) -> status.active end, &>/2)
+ |> Enum.map(fn {account, _, nick} -> {nick, get_full_statistics(account.id)} end)
+ |> Enum.filter(fn {_nick, status} ->
+ status && (status.active > 0 || status.active30m > 0)
+ end)
+ |> Enum.sort_by(fn {_, status} -> status.active end, &>/2)
end
def get_channel_statistics(_, network, channel), do: get_channel_statistics(network, channel)
def get_channel_statistics(network, channel) do
Nola.Membership.expanded_members(network, channel)
- |> Enum.map(fn({account, _, nick}) -> {nick, get_full_statistics(account.id)} end)
- |> Enum.filter(fn({_nick, status}) -> status && (status.active > 0 || status.active30m > 0) end)
- |> Enum.sort_by(fn({_, status}) -> status.active end, &>/2)
+ |> Enum.map(fn {account, _, nick} -> {nick, get_full_statistics(account.id)} end)
+ |> Enum.filter(fn {_nick, status} ->
+ status && (status.active > 0 || status.active30m > 0)
+ end)
+ |> Enum.sort_by(fn {_, status} -> status.active end, &>/2)
end
@spec since() :: %{Nola.Account.id() => DateTime.t()}
@doc "Returns the last time the user was at 0 g/l"
def since() do
- :ets.foldr(fn({{acct, timestamp_or_date}, _vol, current, _cl, _deg, _name, _comment, _m}, acc) ->
- if !Map.get(acc, acct) && current == 0 do
- date = Util.to_date_time(timestamp_or_date)
- Map.put(acc, acct, date)
- else
- acc
- end
- end, %{}, __MODULE__.ETS)
+ :ets.foldr(
+ fn {{acct, timestamp_or_date}, _vol, current, _cl, _deg, _name, _comment, _m}, acc ->
+ if !Map.get(acc, acct) && current == 0 do
+ date = Util.to_date_time(timestamp_or_date)
+ Map.put(acc, acct, date)
+ else
+ acc
+ end
+ end,
+ %{},
+ __MODULE__.ETS
+ )
end
def get_full_statistics(nick) do
@@ -508,129 +718,204 @@ defmodule Nola.Plugins.Alcoolog do
defp get_full_statistics(state, nick) do
case get_statistics_for_nick(state, nick) do
- {count, {_, last_at, last_points, last_active, last_cl, last_deg, last_type, last_descr, _meta}} ->
+ {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)
{_, m5} = alcohol_level_rising(state, nick, 5)
{_, h1} = alcohol_level_rising(state, nick, 60)
- trend = if rising do
- "▲"
- else
- "▼"
- end
- user_state = cond do
- active <= 0.0 -> :sober
- active <= 0.25 -> :low
- active <= 0.50 -> :legal
- active <= 1.0 -> :legalhigh
- active <= 2.5 -> :high
- active < 3 -> :toohigh
- true -> :sick
- end
+ trend =
+ if rising do
+ "▲"
+ else
+ "▼"
+ end
- rising_file_key = if rising, do: "_rising", else: ""
- txt_file = "alcoolog." <> "user_" <> to_string(user_state) <> rising_file_key
- user_status = Nola.Plugins.Txt.random(txt_file)
-
- meta = get_user_meta(state, nick)
- minutes_til_sober = h1/((meta.loss_factor/100)/60)
- minutes_til_sober = cond do
- active < 0 -> 0
- m15 < 0 -> 15
- m30 < 0 -> 30
- h1 < 0 -> 60
- minutes_til_sober > 0 ->
- Float.round(minutes_til_sober+60)
- true -> 0
- end
+ user_state =
+ cond do
+ active <= 0.0 -> :sober
+ active <= 0.25 -> :low
+ active <= 0.50 -> :legal
+ active <= 1.0 -> :legalhigh
+ active <= 2.5 -> :high
+ active < 3 -> :toohigh
+ true -> :sick
+ end
+
+ rising_file_key = if rising, do: "_rising", else: ""
+ txt_file = "alcoolog." <> "user_" <> to_string(user_state) <> rising_file_key
+ user_status = Nola.Plugins.Txt.random(txt_file)
+
+ meta = get_user_meta(state, nick)
+ minutes_til_sober = h1 / (meta.loss_factor / 100 / 60)
+
+ minutes_til_sober =
+ cond do
+ active < 0 ->
+ 0
+
+ m15 < 0 ->
+ 15
+
+ m30 < 0 ->
+ 30
+
+ h1 < 0 ->
+ 60
+
+ minutes_til_sober > 0 ->
+ Float.round(minutes_til_sober + 60)
+
+ true ->
+ 0
+ end
duration = Timex.Duration.from_minutes(minutes_til_sober)
- sober_in_s = if minutes_til_sober > 0 do
- Timex.Format.Duration.Formatter.lformat(duration, "fr", :humanized)
- else
- nil
- end
- since = if active > 0 do
- since()
- |> Map.get(nick)
- end
+ sober_in_s =
+ if minutes_til_sober > 0 do
+ Timex.Format.Duration.Formatter.lformat(duration, "fr", :humanized)
+ else
+ 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)
- {total_volumes, total_gl} = user_stats(state, nick)
+ since_s =
+ if since, do: Timex.Format.Duration.Formatter.lformat(since_duration, "fr", :humanized)
+ {total_volumes, total_gl} = user_stats(state, nick)
- %{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,
+ %{
+ 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,
+ 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,
- since: since, since_min: since_diff, since_s: since_s,
+ daily_gl: total_gl,
+ daily_volumes: total_volumes,
+ sober_in: minutes_til_sober,
+ sober_in_s: sober_in_s,
+ since: since,
+ since_min: since_diff,
+ since_s: since_s
}
- _ ->
- nil
+
+ _ ->
+ nil
end
end
- def handle_info({:irc, :trigger, "sobre", m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :dot}}}, state) do
- nicks = Nola.Membership.expanded_members_or_friends(m.account, m.network, m.channel)
- |> Enum.map(fn({account, _, nick}) -> {nick, get_full_statistics(state, account.id)} end)
- |> Enum.filter(fn({_nick, status}) -> status && status.sober_in && status.sober_in > 0 end)
- |> Enum.sort_by(fn({_, status}) -> status.sober_in end, &</2)
- |> Enum.map(fn({nick, stats}) ->
- now = DateTime.utc_now()
- sober = now |> DateTime.add(round(stats.sober_in*60), :second)
- |> Timex.Timezone.convert("Europe/Paris")
- at = if now.day == sober.day do
- {:ok, detail} = Timex.Format.DateTime.Formatters.Default.lformat(sober, "aujourd'hui {h24}:{m}", "fr")
- detail
- else
- {:ok, detail} = Timex.Format.DateTime.Formatters.Default.lformat(sober, "{WDfull} {h24}:{m}", "fr")
- detail
- end
- "#{nick} sobre #{at} (dans #{stats.sober_in_s})"
- end)
- |> Enum.intersperse(", ")
- |> Enum.join("")
- |> (fn(line) ->
- case line do
- "" -> "tout le monde est sobre......."
- line -> line
- end
- end).()
- |> m.replyfun.()
+ def handle_info(
+ {:irc, :trigger, "sobre",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :dot}}},
+ state
+ ) do
+ nicks =
+ Nola.Membership.expanded_members_or_friends(m.account, m.network, m.channel)
+ |> Enum.map(fn {account, _, nick} -> {nick, get_full_statistics(state, account.id)} end)
+ |> Enum.filter(fn {_nick, status} -> status && status.sober_in && status.sober_in > 0 end)
+ |> Enum.sort_by(fn {_, status} -> status.sober_in end, &</2)
+ |> Enum.map(fn {nick, stats} ->
+ now = DateTime.utc_now()
+
+ sober =
+ now
+ |> DateTime.add(round(stats.sober_in * 60), :second)
+ |> Timex.Timezone.convert("Europe/Paris")
+
+ at =
+ if now.day == sober.day do
+ {:ok, detail} =
+ Timex.Format.DateTime.Formatters.Default.lformat(
+ sober,
+ "aujourd'hui {h24}:{m}",
+ "fr"
+ )
+
+ detail
+ else
+ {:ok, detail} =
+ Timex.Format.DateTime.Formatters.Default.lformat(sober, "{WDfull} {h24}:{m}", "fr")
+
+ detail
+ end
+
+ "#{nick} sobre #{at} (dans #{stats.sober_in_s})"
+ end)
+ |> Enum.intersperse(", ")
+ |> Enum.join("")
+ |> (fn line ->
+ case line do
+ "" -> "tout le monde est sobre......."
+ line -> line
+ end
+ end).()
+ |> m.replyfun.()
+
{:noreply, state}
end
- def handle_info({:irc, :trigger, "sobre", m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :bang}}}, state) do
- account = case args do
- [nick] -> Nola.Account.find_always_by_nick(m.network, m.channel, nick)
- [] -> m.account
- end
+ def handle_info(
+ {:irc, :trigger, "sobre",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :bang}}},
+ state
+ ) do
+ account =
+ case args do
+ [nick] -> Nola.Account.find_always_by_nick(m.network, m.channel, nick)
+ [] -> m.account
+ end
if account do
user = Nola.UserTrack.find_by_account(m.network, account)
nick = if(user, do: user.nick, else: account.name)
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)
- |> Timex.Timezone.convert("Europe/Paris")
- at = if now.day == sober.day do
- {:ok, detail} = Timex.Format.DateTime.Formatters.Default.lformat(sober, "aujourd'hui {h24}:{m}", "fr")
+
+ sober =
+ now
+ |> DateTime.add(round(stats.sober_in * 60), :second)
+ |> Timex.Timezone.convert("Europe/Paris")
+
+ at =
+ if now.day == sober.day do
+ {:ok, detail} =
+ Timex.Format.DateTime.Formatters.Default.lformat(
+ sober,
+ "aujourd'hui {h24}:{m}",
+ "fr"
+ )
+
detail
else
- {:ok, detail} = Timex.Format.DateTime.Formatters.Default.lformat(sober, "{WDfull} {h24}:{m}", "fr")
+ {:ok, detail} =
+ Timex.Format.DateTime.Formatters.Default.lformat(sober, "{WDfull} {h24}:{m}", "fr")
+
detail
end
+
m.replyfun.("#{nick} sera sobre #{at} (dans #{stats.sober_in_s})!")
else
m.replyfun.("#{nick} est déjà sobre. aidez le !")
@@ -638,61 +923,85 @@ defmodule Nola.Plugins.Alcoolog do
else
m.replyfun.("inconnu")
end
+
{:noreply, state}
end
- def handle_info({:irc, :trigger, "alcoolisme", m = %Nola.Message{trigger: %Nola.Trigger{args: [], type: :dot}}}, state) do
- nicks = Nola.Membership.expanded_members_or_friends(m.account, m.network, m.channel)
- |> Enum.map(fn({account, _, nick}) -> {nick, get_full_statistics(state, account.id)} end)
- |> Enum.filter(fn({_nick, status}) -> status && (status.active > 0 || status.active30m > 0) end)
- |> Enum.sort_by(fn({_, status}) -> status.active end, &>/2)
- |> Enum.map(fn({nick, status}) ->
- trend_symbol = if status.active_drinks > 1 do
- Enum.join(for(_ <- 1..status.active_drinks, do: status.trend_symbol))
- else
- status.trend_symbol
- end
- since_str = if status.since_min > 180 do
- "depuis: #{status.since_s} | "
+ def handle_info(
+ {:irc, :trigger, "alcoolisme",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: [], type: :dot}}},
+ state
+ ) do
+ nicks =
+ Nola.Membership.expanded_members_or_friends(m.account, m.network, m.channel)
+ |> Enum.map(fn {account, _, nick} -> {nick, get_full_statistics(state, account.id)} end)
+ |> Enum.filter(fn {_nick, status} ->
+ status && (status.active > 0 || status.active30m > 0)
+ end)
+ |> Enum.sort_by(fn {_, status} -> status.active end, &>/2)
+ |> Enum.map(fn {nick, status} ->
+ trend_symbol =
+ if status.active_drinks > 1 do
+ Enum.join(for(_ <- 1..status.active_drinks, do: status.trend_symbol))
+ else
+ status.trend_symbol
+ end
+
+ 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("")
+
+ msg =
+ if nicks == "" do
+ "wtf?!?! personne n'a bu!"
else
- ""
+ nicks
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("")
-
- msg = if nicks == "" do
- "wtf?!?! personne n'a bu!"
- else
- nicks
- end
m.replyfun.(msg)
{:noreply, state}
end
- def handle_info({:irc, :trigger, "alcoolisme", m = %Nola.Message{trigger: %Nola.Trigger{args: [time], type: :dot}}}, state) do
- time = case time do
- "semaine" -> 7
- string ->
- case Integer.parse(string) do
- {time, "j"} -> time
- {time, "J"} -> time
- _ -> nil
- end
- end
+ def handle_info(
+ {:irc, :trigger, "alcoolisme",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: [time], type: :dot}}},
+ state
+ ) do
+ time =
+ case time do
+ "semaine" ->
+ 7
+
+ string ->
+ case Integer.parse(string) do
+ {time, "j"} -> time
+ {time, "J"} -> time
+ _ -> nil
+ end
+ end
if time do
- aday = time*((24 * 60)*60)
+ aday = time * (24 * 60 * 60)
now = DateTime.utc_now()
- before = now
- |> DateTime.add(-aday, :second)
- |> DateTime.to_unix(:millisecond)
+
+ before =
+ now
+ |> DateTime.add(-aday, :second)
+ |> DateTime.to_unix(:millisecond)
+
over_time_stats(before, time, m, state)
else
m.replyfun.(".alcooolisme semaine|Xj")
end
+
{:noreply, state}
end
@@ -701,30 +1010,37 @@ defmodule Nola.Plugins.Alcoolog do
end
def user_over_time(state, account, count) do
- delay = count*((24 * 60)*60)
+ delay = count * (24 * 60 * 60)
now = DateTime.utc_now()
- before = DateTime.utc_now()
- |> DateTime.shift_zone!("Europe/Paris", Tzdata.TimeZoneDatabase)
- |> DateTime.add(-delay, :second, Tzdata.TimeZoneDatabase)
- |> DateTime.to_unix(:millisecond)
- #[
-# {{{:"$1", :"$2"}, :_, :_, :_, :_, :_, :_, :_},
-# [{:andalso, {:==, :"$1", :"$1"}, {:<, :"$2", {:const, 3000}}}], [:lol]}
- #]
- match = [{{{:"$1", :"$2"}, :_, :_, :_, :_, :_, :_, :_},
+
+ before =
+ DateTime.utc_now()
+ |> DateTime.shift_zone!("Europe/Paris", Tzdata.TimeZoneDatabase)
+ |> DateTime.add(-delay, :second, Tzdata.TimeZoneDatabase)
+ |> DateTime.to_unix(:millisecond)
+
+ # [
+ # {{{:"$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()
+ :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()
Map.put(acc, date, Map.get(acc, date, 0) + vol)
end)
@@ -733,164 +1049,219 @@ defmodule Nola.Plugins.Alcoolog do
def user_over_time_gl(account, count) do
state = data_state()
meta = get_user_meta(state, account.id)
- delay = count*((24 * 60)*60)
+ delay = count * (24 * 60 * 60)
now = DateTime.utc_now()
- before = DateTime.utc_now()
- |> DateTime.shift_zone!("Europe/Paris", Tzdata.TimeZoneDatabase)
- |> DateTime.add(-delay, :second, Tzdata.TimeZoneDatabase)
- |> DateTime.to_unix(:millisecond)
- #[
-# {{{:"$1", :"$2"}, :_, :_, :_, :_, :_, :_, :_},
-# [{:andalso, {:==, :"$1", :"$1"}, {:<, :"$2", {:const, 3000}}}], [:lol]}
- #]
- match = [{{{:"$1", :"$2"}, :_, :_, :_, :_, :_, :_, :_},
+
+ before =
+ DateTime.utc_now()
+ |> DateTime.shift_zone!("Europe/Paris", Tzdata.TimeZoneDatabase)
+ |> DateTime.add(-delay, :second, Tzdata.TimeZoneDatabase)
+ |> DateTime.to_unix(:millisecond)
+
+ # [
+ # {{{:"$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)
+ |> 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()
- date = if date.hour <= 8 do
- DateTime.add(date, -(60*(60*(date.hour+1))), :second, Tzdata.TimeZoneDatabase)
- else
- date
- end
- |> DateTime.to_date()
weight = meta.weight
k = if meta.sex, do: 0.7, else: 0.6
- gl = (10*vol)/(k*weight)
+ gl = 10 * vol / (k * weight)
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"}, :_, :_, :_, :_, :_, :_, :_},
- [{:>, :"$1", {:const, before}}], [:"$_"]}
+ # 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}
+
+ # tuple ets: {{nick, date}, volumes, current, nom, commentaire}
members = Nola.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)
- top = Enum.reduce(drinks, %{}, fn({{nick, _}, vol, _, _, _, _, _, _}, acc) ->
- all = Map.get(acc, nick, 0)
- Map.put(acc, nick, all + vol)
- end)
- |> Enum.sort_by(fn({_nick, count}) -> count end, &>/2)
- |> Enum.map(fn({nick, count}) ->
- account = Nola.Account.get(nick)
- user = Nola.UserTrack.find_by_account(m.network, account)
- nick = if(user, do: user.nick, else: account.name)
- "#{nick}: #{Float.round(count, 4)}"
- end)
- |> Enum.intersperse(", ")
+ drinks =
+ :ets.select(state.ets, match)
+ |> 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 ->
+ all = Map.get(acc, nick, 0)
+ Map.put(acc, nick, all + vol)
+ end)
+ |> Enum.sort_by(fn {_nick, count} -> count end, &>/2)
+ |> Enum.map(fn {nick, count} ->
+ account = Nola.Account.get(nick)
+ user = Nola.UserTrack.find_by_account(m.network, account)
+ nick = if(user, do: user.nick, else: account.name)
+ "#{nick}: #{Float.round(count, 4)}"
+ end)
+ |> Enum.intersperse(", ")
m.replyfun.("sur #{j} jours: #{top}")
{:noreply, state}
end
- def handle_info({:irc, :trigger, "alcoolisme", m = %Nola.Message{trigger: %Nola.Trigger{args: [], type: :plus}}}, state) do
+ def handle_info(
+ {:irc, :trigger, "alcoolisme",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: [], type: :plus}}},
+ state
+ ) do
meta = get_user_meta(state, m.account.id)
hf = if meta.sex, do: "h", else: "f"
- m.replyfun.("+alcoolisme sexe: #{hf} poids: #{meta.weight} facteur de perte: #{meta.loss_factor}")
+
+ m.replyfun.(
+ "+alcoolisme sexe: #{hf} poids: #{meta.weight} facteur de perte: #{meta.loss_factor}"
+ )
+
{:noreply, state}
end
- def handle_info({:irc, :trigger, "alcoolisme", m = %Nola.Message{trigger: %Nola.Trigger{args: [h, weight | rest], type: :plus}}}, state) do
- h = case h do
- "h" -> true
- "f" -> false
- _ -> nil
- end
+ def handle_info(
+ {:irc, :trigger, "alcoolisme",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: [h, weight | rest], type: :plus}}},
+ state
+ ) do
+ h =
+ case h do
+ "h" -> true
+ "f" -> false
+ _ -> nil
+ end
- weight = case Util.float_paparse(weight) do
+ weight =
+ case Util.float_paparse(weight) do
{weight, _} -> weight
_ -> nil
end
- {factor} = case rest do
+ {factor} =
+ case rest do
[factor] ->
case Util.float_paparse(factor) do
{float, _} -> {float}
_ -> {@default_user_meta.loss_factor}
end
- _ -> {@default_user_meta.loss_factor}
+
+ _ ->
+ {@default_user_meta.loss_factor}
end
- if h == nil || weight == nil do
- m.replyfun.("paramètres invalides")
- else
- old_meta = get_user_meta(state, m.account.id)
- meta = Map.merge(@default_user_meta, %{sex: h, weight: weight, loss_factor: factor})
- put_user_meta(state, m.account.id, meta)
- cond do
- old_meta.weight < meta.weight ->
- Nola.Plugins.Txt.reply_random(m, "alcoolog.fatter")
- old_meta.weight == meta.weight ->
- m.replyfun.("aucun changement!")
- true ->
- Nola.Plugins.Txt.reply_random(m, "alcoolog.thinner")
- end
+ if h == nil || weight == nil do
+ m.replyfun.("paramètres invalides")
+ else
+ old_meta = get_user_meta(state, m.account.id)
+ meta = Map.merge(@default_user_meta, %{sex: h, weight: weight, loss_factor: factor})
+ put_user_meta(state, m.account.id, meta)
+
+ cond do
+ old_meta.weight < meta.weight ->
+ Nola.Plugins.Txt.reply_random(m, "alcoolog.fatter")
+
+ old_meta.weight == meta.weight ->
+ m.replyfun.("aucun changement!")
+
+ true ->
+ Nola.Plugins.Txt.reply_random(m, "alcoolog.thinner")
end
+ end
{:noreply, state}
end
- def handle_info({:irc, :trigger, "santai", m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :minus}}}, state) do
+ def handle_info(
+ {:irc, :trigger, "santai",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :minus}}},
+ state
+ ) do
case get_statistics_for_nick(state, m.account.id) do
{_, 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}")
Nola.Plugins.Txt.reply_random(m, "alcoolog.delete")
- notify = Nola.Membership.notify_channels(m.account) -- [{m.network,m.channel}]
+ notify = Nola.Membership.notify_channels(m.account) -- [{m.network, m.channel}]
+
for {net, chan} <- notify do
user = Nola.UserTrack.find_by_account(net, m.account)
nick = if(user, do: user.nick, else: m.account.name)
- Nola.Irc.Connection.broadcast_message(net, chan, "#{nick} -santai #{points} #{type} #{descr}")
+
+ Nola.Irc.Connection.broadcast_message(
+ net,
+ chan,
+ "#{nick} -santai #{points} #{type} #{descr}"
+ )
end
+
{:noreply, state}
+
_ ->
{:noreply, state}
end
end
+ def handle_info(
+ {:irc, :trigger, "alcoolisme",
+ m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :bang}}},
+ state
+ ) do
+ {account, duration} =
+ case args do
+ [nick | rest] -> {Nola.Account.find_always_by_nick(m.network, m.channel, nick), rest}
+ [] -> {m.account, []}
+ end
- def handle_info({:irc, :trigger, "alcoolisme", m = %Nola.Message{trigger: %Nola.Trigger{args: args, type: :bang}}}, state) do
- {account, duration} = case args do
- [nick | rest] -> {Nola.Account.find_always_by_nick(m.network, m.channel, nick), rest}
- [] -> {m.account, []}
- end
if account do
- duration = case duration do
- ["semaine"] -> 7
- [j] ->
- case Integer.parse(j) do
- {j, "j"} -> j
- _ -> nil
- end
- _ -> nil
- end
+ duration =
+ case duration do
+ ["semaine"] ->
+ 7
+
+ [j] ->
+ case Integer.parse(j) do
+ {j, "j"} -> j
+ _ -> nil
+ end
+
+ _ ->
+ nil
+ end
+
user = Nola.UserTrack.find_by_account(m.network, account)
nick = if(user, do: user.nick, else: account.name)
+
if duration do
if duration > 90 do
m.replyfun.("trop gros, ça rentrera pas")
else
# duration stats
- stats = user_over_time(state, account, duration)
- |> Enum.sort_by(fn({k,_v}) -> k end, {:asc, Date})
- |> Enum.map(fn({date, count}) ->
- "#{date.day}: #{Float.round(count, 2)}"
- end)
- |> Enum.intersperse(", ")
- |> Enum.join("")
+ stats =
+ user_over_time(state, account, duration)
+ |> Enum.sort_by(fn {k, _v} -> k end, {:asc, Date})
+ |> Enum.map(fn {date, count} ->
+ "#{date.day}: #{Float.round(count, 2)}"
+ end)
+ |> Enum.intersperse(", ")
+ |> Enum.join("")
if stats == "" do
m.replyfun.("alcoolisme a zéro sur #{duration}j :/")
@@ -900,47 +1271,67 @@ defmodule Nola.Plugins.Alcoolog do
end
else
if stats = get_full_statistics(state, account.id) do
- trend_symbol = if stats.active_drinks > 1 do
- Enum.join(for(_ <- 1..stats.active_drinks, do: stats.trend_symbol))
- else
- stats.trend_symbol
- end
- # TODO: Lookup nick for account_id
- msg = "#{nick} #{stats.user_status} "
- <> (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: "")
+ trend_symbol =
+ if stats.active_drinks > 1 do
+ Enum.join(for(_ <- 1..stats.active_drinks, do: stats.trend_symbol))
+ else
+ stats.trend_symbol
+ end
+
+ # TODO: Lookup nick for account_id
+ msg =
+ "#{nick} #{stats.user_status} " <>
+ 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: ""
m.replyfun.(msg)
else
m.replyfun.("honteux mais #{nick} n'a pas l'air alcoolique du tout. /kick")
end
end
- else
+ else
m.replyfun.("je ne connais pas cet utilisateur")
end
+
{:noreply, state}
end
-
# Account merge
def handle_info({:account_change, old_id, new_id}, state) do
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}")
+
+ 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)
end)
+
case :dets.lookup(state.meta, {:meta, old_id}) do
[{_, meta}] ->
:dets.delete(state.meta, {:meta, old_id})
:dets.insert(state.meta, {{:meta, new_id}, meta})
+
_ ->
:ok
end
+
{:noreply, state}
end
@@ -951,7 +1342,13 @@ defmodule Nola.Plugins.Alcoolog do
end
end
- defp rename_object_owner(table, ets, object = {old_id, date, volume, current, cl, deg, name, comment, meta}, 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, cl, deg, name, comment, meta})
@@ -960,58 +1357,75 @@ defmodule Nola.Plugins.Alcoolog do
# Account: move from nick to account id
def handle_info({:accounts, accounts}, state) do
- #for x={:account, _, _, _, _} <- accounts, do: handle_info(x, state)
- #{:noreply, state}
- mapping = Enum.reduce(accounts, Map.new, fn({:account, _net, _chan, nick, account_id}, acc) ->
- Map.put(acc, String.downcase(nick), account_id)
- end)
+ # for x={:account, _, _, _, _} <- accounts, do: handle_info(x, state)
+ # {:noreply, state}
+ 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", :_, :_, :_, :_, :_, :_, :_, :_}, [], [:"$_"]}]
- Logger.debug("accounts:: mappings #{inspect mapping}")
- 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)}")
+ Logger.debug("accounts:: mappings #{inspect(mapping)}")
+
+ 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}")
rename_object_owner(table, state.ets, obj, nick, new_id)
end
end)
+
{:noreply, state}
end
def handle_info({:account, _net, _chan, nick, account_id}, state) do
nick = String.downcase(nick)
spec = [{{:"$1", :_, :_, :_, :_, :_, :_, :_, :_}, [{:==, :"$1", {:const, nick}}], [:"$_"]}]
- Util.ets_mutate_select_each(:dets, state.dets, spec, fn(table, obj) ->
+
+ 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)
end)
+
case :dets.lookup(state.meta, {:meta, nick}) do
[{_, meta}] ->
:dets.delete(state.meta, {:meta, nick})
:dets.insert(state.meta, {{:meta, account_id}, meta})
+
_ ->
:ok
end
+
{:noreply, state}
end
def handle_info(t, state) do
- Logger.debug("#{__MODULE__}: unhandled info #{inspect t}")
+ Logger.debug("#{__MODULE__}: unhandled info #{inspect(t)}")
{:noreply, state}
end
def nick_history(account) do
spec = [
- {{{:"$1", :_}, :_, :_, :_, :_, :_, :_, :_},
- [{:==, :"$1", {:const, account.id}}],
- [:"$_"]}
+ {{{:"$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, _cl, _deg, _type, _descr, _meta}, acc) -> acc + (points||0) end)
+ 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, _cl, _deg, _type, _descr, _meta},
+ acc ->
+ acc + (points || 0)
+ end)
+
last = List.last(qvc) || nil
{count, last}
end
@@ -1022,26 +1436,34 @@ defmodule Nola.Plugins.Alcoolog do
def format_points(int) when is_integer(int) and int > 0 do
"+#{Integer.to_string(int)}"
end
+
def format_points(int) when is_integer(int) and int < 0 do
Integer.to_string(int)
end
+
def format_points(int) when is_float(int) and int > 0 do
- "+#{Float.to_string(Float.round(int,4))}"
+ "+#{Float.to_string(Float.round(int, 4))}"
end
+
def format_points(int) when is_float(int) and int < 0 do
- Float.to_string(Float.round(int,4))
+ Float.to_string(Float.round(int, 4))
end
+
def format_points(0), do: "0"
def format_points(0.0), do: "0"
defp format_relative_timestamp(timestamp) do
alias Timex.Format.DateTime.Formatters
alias Timex.Timezone
- date = timestamp
- |> DateTime.from_unix!(:millisecond)
- |> Timezone.convert("Europe/Paris")
- {:ok, relative} = Formatters.Relative.relative_to(date, Timex.now("Europe/Paris"), "{relative}", "fr")
+ date =
+ timestamp
+ |> DateTime.from_unix!(:millisecond)
+ |> Timezone.convert("Europe/Paris")
+
+ {:ok, relative} =
+ Formatters.Relative.relative_to(date, Timex.now("Europe/Paris"), "{relative}", "fr")
+
{:ok, detail} = Formatters.Default.lformat(date, " ({h24}:{m})", "fr")
relative <> detail
@@ -1056,10 +1478,12 @@ defmodule Nola.Plugins.Alcoolog do
case :dets.lookup(meta, {:meta, account_id}) do
[{{:meta, _}, meta}] ->
Map.merge(@default_user_meta, meta)
+
_ ->
@default_user_meta
end
end
+
# Calcul g/l actuel:
# 1. load user meta
# 2. foldr ets
@@ -1077,12 +1501,15 @@ defmodule Nola.Plugins.Alcoolog do
defp user_stats(state = %{ets: ets}, account_id) do
meta = get_user_meta(state, account_id)
- aday = (10 * 60)*60
+ aday = 10 * 60 * 60
now = DateTime.utc_now()
- before = now
- |> DateTime.add(-aday, :second)
- |> DateTime.to_unix(:millisecond)
- #match = :ets.fun2ms(fn(obj = {{^nick, date}, _, _, _, _}) when date > before -> obj end)
+
+ before =
+ now
+ |> DateTime.add(-aday, :second)
+ |> DateTime.to_unix(:millisecond)
+
+ # match = :ets.fun2ms(fn(obj = {{^nick, date}, _, _, _, _}) when date > before -> obj end)
match = [
{{{:"$1", :"$2"}, :_, :_, :_, :_, :_, :_, :_},
[
@@ -1090,43 +1517,57 @@ defmodule Nola.Plugins.Alcoolog do
{:"=:=", {:const, account_id}, :"$1"}
], [:"$_"]}
]
- # tuple ets: {{nick, date}, volumes, current, nom, commentaire}
+
+ # 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) ->
- acc + volume
- end)
+ total_volume =
+ Enum.reduce(drinks, 0.0, fn {{_, date}, volume, _, _, _, _, _, _}, acc ->
+ acc + volume
+ end)
+
k = if meta.sex, do: 0.7, else: 0.6
weight = meta.weight
- gl = (10*total_volume)/(k*weight)
+ gl = 10 * total_volume / (k * weight)
{Float.round(total_volume + 0.0, 4), Float.round(gl + 0.0, 4)}
end
defp alcohol_level_rising(state, account_id, minutes \\ 30) do
{now, _} = current_alcohol_level(state, account_id)
- soon_date = DateTime.utc_now
- |> DateTime.add(minutes*60, :second)
+
+ soon_date =
+ DateTime.utc_now()
+ |> DateTime.add(minutes * 60, :second)
+
{soon, _} = current_alcohol_level(state, account_id, soon_date)
- soon = cond do
- soon < 0 -> 0.0
- true -> soon
- end
- #IO.puts "soon #{soon_date} - #{inspect soon} #{inspect now}"
- {soon > now, Float.round(soon+0.0, 4)}
+
+ soon =
+ cond do
+ soon < 0 -> 0.0
+ true -> soon
+ end
+
+ # IO.puts "soon #{soon_date} - #{inspect soon} #{inspect now}"
+ {soon > now, Float.round(soon + 0.0, 4)}
end
defp current_alcohol_level(state = %{ets: ets}, account_id, now \\ nil) do
meta = get_user_meta(state, account_id)
- aday = ((24*7) * 60)*60
- now = if now do
+ aday = 24 * 7 * 60 * 60
+
+ now =
+ if now do
+ now
+ else
+ DateTime.utc_now()
+ end
+
+ before =
now
- else
- DateTime.utc_now()
- end
- before = now
- |> DateTime.add(-aday, :second)
- |> DateTime.to_unix(:millisecond)
- #match = :ets.fun2ms(fn(obj = {{^nick, date}, _, _, _, _}) when date > before -> obj end)
+ |> DateTime.add(-aday, :second)
+ |> DateTime.to_unix(:millisecond)
+
+ # match = :ets.fun2ms(fn(obj = {{^nick, date}, _, _, _, _}) when date > before -> obj end)
match = [
{{{:"$1", :"$2"}, :_, :_, :_, :_, :_, :_, :_},
[
@@ -1134,59 +1575,77 @@ defmodule Nola.Plugins.Alcoolog do
{:"=:=", {:const, account_id}, :"$1"}
], [:"$_"]}
]
- # tuple ets: {{nick, date}, volumes, current, nom, commentaire}
- drinks = :ets.select(ets, match)
- |> Enum.sort_by(fn({{_, date}, _, _, _, _, _, _, _}) -> date end, &</2)
+
+ # tuple ets: {{nick, date}, volumes, current, nom, commentaire}
+ drinks =
+ :ets.select(ets, match)
+ |> 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}) ->
- k = if meta.sex, do: 0.7, else: 0.6
- weight = meta.weight
- peak = (10*volume)/(k*weight)
- date = case date do
- ts when is_integer(ts) -> DateTime.from_unix!(ts, :millisecond)
- date = %NaiveDateTime{} -> DateTime.from_naive!(date, "Etc/UTC")
- date = %DateTime{} -> date
- end
- last_at = last_at || date
- mins_since = round(DateTime.diff(now, date)/60.0)
- #IO.puts "Drink: #{inspect({date, volume})} - mins since: #{inspect mins_since} - last drink at #{inspect last_at}"
- # Apply loss since `last_at` on `all`
- #
- all = if last_at do
- mins_since_last = round(DateTime.diff(date, last_at)/60.0)
- loss = ((meta.loss_factor/100)/60)*(mins_since_last)
- #IO.puts "Applying last drink loss: from #{all}, loss of #{inspect loss} (mins since #{inspect mins_since_first})"
- cond do
- (all-loss) > 0 -> all - loss
- true -> 0.0
+ {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)
+
+ date =
+ case date do
+ ts when is_integer(ts) -> DateTime.from_unix!(ts, :millisecond)
+ date = %NaiveDateTime{} -> DateTime.from_naive!(date, "Etc/UTC")
+ date = %DateTime{} -> date
+ end
+
+ last_at = last_at || date
+ mins_since = round(DateTime.diff(now, date) / 60.0)
+
+ # IO.puts "Drink: #{inspect({date, volume})} - mins since: #{inspect mins_since} - last drink at #{inspect last_at}"
+ # Apply loss since `last_at` on `all`
+ #
+ all =
+ if last_at do
+ mins_since_last = round(DateTime.diff(date, last_at) / 60.0)
+ loss = meta.loss_factor / 100 / 60 * mins_since_last
+
+ # IO.puts "Applying last drink loss: from #{all}, loss of #{inspect loss} (mins since #{inspect mins_since_first})"
+ cond do
+ all - loss > 0 -> all - loss
+ true -> 0.0
+ end
+ else
+ all
+ end
+
+ # IO.puts "Applying last drink current before drink: #{inspect all}"
+ if mins_since < 30 do
+ per_min = peak / 30.0
+ current = per_min * mins_since
+
+ # IO.puts "Applying current drink 30m: from #{peak}, loss of #{inspect per_min}/min (mins since #{inspect mins_since})"
+ {all + current, date, [{date, current} | acc], active_drinks + 1}
+ else
+ {all + peak, date, [{date, peak} | acc], active_drinks}
end
+ end)
+
+ # IO.puts "last drink #{inspect last_drink_at}"
+ mins_since_last =
+ if last_drink_at do
+ round(DateTime.diff(now, last_drink_at) / 60.0)
else
- all
+ 0
end
- #IO.puts "Applying last drink current before drink: #{inspect all}"
- if mins_since < 30 do
- per_min = (peak)/30.0
- current = (per_min*mins_since)
- #IO.puts "Applying current drink 30m: from #{peak}, loss of #{inspect per_min}/min (mins since #{inspect mins_since})"
- {all + current, date, [{date, current} | acc], active_drinks + 1}
+
+ # Si on a déjà bu y'a déjà moins 15 minutes (big up le binge drinking), on applique plus de perte
+ level =
+ if mins_since_last > 15 do
+ loss = meta.loss_factor / 100 / 60 * mins_since_last
+ Float.round(all - loss, 4)
else
- {all + peak, date, [{date, peak} | acc], active_drinks}
+ all
end
- end)
- #IO.puts "last drink #{inspect last_drink_at}"
- mins_since_last = if last_drink_at do
- round(DateTime.diff(now, last_drink_at)/60.0)
- else
- 0
- end
- # Si on a déjà bu y'a déjà moins 15 minutes (big up le binge drinking), on applique plus de perte
- level = if mins_since_last > 15 do
- loss = ((meta.loss_factor/100)/60)*(mins_since_last)
- Float.round(all - loss, 4)
- else
- all
- end
- #IO.puts "\n LEVEL #{inspect level}\n\n\n\n"
+
+ # IO.puts "\n LEVEL #{inspect level}\n\n\n\n"
cond do
level < 0 -> {0.0, 0}
true -> {level, active_drinks}
@@ -1194,23 +1653,31 @@ defmodule Nola.Plugins.Alcoolog do
end
defp format_duration_from_now(date, with_detail \\ true) do
- date = if is_integer(date) do
- date = DateTime.from_unix!(date, :millisecond)
+ date =
+ if is_integer(date) do
+ date =
+ DateTime.from_unix!(date, :millisecond)
+ |> Timex.Timezone.convert("Europe/Paris")
+ else
+ Util.to_naive_date_time(date)
+ end
+
+ now =
+ DateTime.utc_now()
|> Timex.Timezone.convert("Europe/Paris")
- else
- Util.to_naive_date_time(date)
- end
- now = DateTime.utc_now()
- |> Timex.Timezone.convert("Europe/Paris")
+
{:ok, detail} = Timex.Format.DateTime.Formatters.Default.lformat(date, "({h24}:{m})", "fr")
- mins_since = round(DateTime.diff(now, date)/60.0)
+ mins_since = round(DateTime.diff(now, date) / 60.0)
+
if ago = format_minute_duration(mins_since) do
- word = if mins_since > 0 do
- "il y a "
- else
- "dans "
- end
+ word =
+ if mins_since > 0 do
+ "il y a "
+ else
+ "dans "
+ end
+
word <> ago <> if(with_detail, do: " #{detail}", else: "")
else
"maintenant #{detail}"
@@ -1218,12 +1685,12 @@ defmodule Nola.Plugins.Alcoolog do
end
defp format_minute_duration(minutes) do
- sober_in_s = if (minutes != 0) do
- duration = Timex.Duration.from_minutes(minutes)
- Timex.Format.Duration.Formatter.lformat(duration, "fr", :humanized)
- else
- nil
- end
+ sober_in_s =
+ if minutes != 0 do
+ duration = Timex.Duration.from_minutes(minutes)
+ Timex.Format.Duration.Formatter.lformat(duration, "fr", :humanized)
+ else
+ nil
+ end
end
-
end