summaryrefslogtreecommitdiff
path: root/lib/plugins/coronavirus.ex
diff options
context:
space:
mode:
authorJordan Bracco <href@random.sh>2025-06-25 19:22:59 +0200
committerJordan Bracco <href@random.sh>2025-06-25 19:22:59 +0200
commitc934e79e5852e05f714b2d542cc2678e287c49b8 (patch)
tree55779a0168260fce03e4775eacdd613ffc945588 /lib/plugins/coronavirus.ex
parentupdates (diff)
format.
Diffstat (limited to 'lib/plugins/coronavirus.ex')
-rw-r--r--lib/plugins/coronavirus.ex266
1 files changed, 173 insertions, 93 deletions
diff --git a/lib/plugins/coronavirus.ex b/lib/plugins/coronavirus.ex
index afd8a33..db9f646 100644
--- a/lib/plugins/coronavirus.ex
+++ b/lib/plugins/coronavirus.ex
@@ -1,6 +1,7 @@
defmodule Nola.Plugins.Coronavirus do
require Logger
NimbleCSV.define(CovidCsv, separator: ",", escape: "\"")
+
@moduledoc """
# Corona Virus
@@ -19,7 +20,7 @@ defmodule Nola.Plugins.Coronavirus do
end
def init(_) do
- {:ok, _} = Registry.register(Nola.PubSub, "trigger:coronavirus", [plugin: __MODULE__])
+ {:ok, _} = Registry.register(Nola.PubSub, "trigger:coronavirus", plugin: __MODULE__)
{:ok, nil, {:continue, :init}}
:ignore
end
@@ -38,53 +39,87 @@ defmodule Nola.Plugins.Coronavirus do
{:noreply, %{data: data}}
end
- def handle_info({:irc, :trigger, "coronavirus", m = %Nola.Message{trigger: %{type: :bang, args: args}}}, state) when args in [
- [], ["morts"], ["confirmés"], ["soignés"], ["malades"], ["n"], ["nmorts"], ["nsoignés"], ["nconfirmés"]] do
- {field, name} = case args do
- ["confirmés"] -> {:confirmed, "confirmés"}
- ["morts"] -> {:deaths, "morts"}
- ["soignés"] -> {:recovered, "soignés"}
- ["nmorts"] -> {:new_deaths, "nouveaux morts"}
- ["nconfirmés"] -> {:new_confirmed, "nouveaux confirmés"}
- ["n"] -> {:new_current, "nouveaux malades"}
- ["nsoignés"] -> {:new_recovered, "nouveaux soignés"}
- _ -> {:current, "malades"}
- end
- IO.puts("FIELD #{inspect field}")
+ def handle_info(
+ {:irc, :trigger, "coronavirus", m = %Nola.Message{trigger: %{type: :bang, args: args}}},
+ state
+ )
+ when args in [
+ [],
+ ["morts"],
+ ["confirmés"],
+ ["soignés"],
+ ["malades"],
+ ["n"],
+ ["nmorts"],
+ ["nsoignés"],
+ ["nconfirmés"]
+ ] do
+ {field, name} =
+ case args do
+ ["confirmés"] -> {:confirmed, "confirmés"}
+ ["morts"] -> {:deaths, "morts"}
+ ["soignés"] -> {:recovered, "soignés"}
+ ["nmorts"] -> {:new_deaths, "nouveaux morts"}
+ ["nconfirmés"] -> {:new_confirmed, "nouveaux confirmés"}
+ ["n"] -> {:new_current, "nouveaux malades"}
+ ["nsoignés"] -> {:new_recovered, "nouveaux soignés"}
+ _ -> {:current, "malades"}
+ end
+
+ IO.puts("FIELD #{inspect(field)}")
field_evol = String.to_atom("new_#{field}")
- sorted = state.data
- |> Enum.filter(fn({_, %{region: region}}) -> region == true end)
- |> Enum.map(fn({location, data}) -> {location, Map.get(data, field, 0), Map.get(data, field_evol, 0)} end)
- |> Enum.sort_by(fn({_,count,_}) -> count end, &>=/2)
- |> Enum.take(10)
- |> Enum.with_index()
- |> Enum.map(fn({{location, count, evol}, index}) ->
- ev = if String.starts_with?(name, "nouveaux") do
- ""
- else
- " (#{Util.plusminus(evol)})"
- end
- "##{index+1}: #{location} #{count}#{ev}"
- end)
- |> Enum.intersperse(" - ")
- |> Enum.join()
+
+ sorted =
+ state.data
+ |> Enum.filter(fn {_, %{region: region}} -> region == true end)
+ |> Enum.map(fn {location, data} ->
+ {location, Map.get(data, field, 0), Map.get(data, field_evol, 0)}
+ end)
+ |> Enum.sort_by(fn {_, count, _} -> count end, &>=/2)
+ |> Enum.take(10)
+ |> Enum.with_index()
+ |> Enum.map(fn {{location, count, evol}, index} ->
+ ev =
+ if String.starts_with?(name, "nouveaux") do
+ ""
+ else
+ " (#{Util.plusminus(evol)})"
+ end
+
+ "##{index + 1}: #{location} #{count}#{ev}"
+ end)
+ |> Enum.intersperse(" - ")
+ |> Enum.join()
+
m.replyfun.("CORONAVIRUS TOP10 #{name}: " <> sorted)
{:noreply, state}
end
- def handle_info({:irc, :trigger, "coronavirus", m = %Nola.Message{trigger: %{type: :bang, args: location}}}, state) do
+ def handle_info(
+ {:irc, :trigger, "coronavirus",
+ m = %Nola.Message{trigger: %{type: :bang, args: location}}},
+ state
+ ) do
location = Enum.join(location, " ") |> String.downcase()
+
if data = Map.get(state.data, location) do
- m.replyfun.("coronavirus: #{location}: "
- <> "#{data.current} malades (#{Util.plusminus(data.new_current)}), "
- <> "#{data.confirmed} confirmés (#{Util.plusminus(data.new_confirmed)}), "
- <> "#{data.deaths} morts (#{Util.plusminus(data.new_deaths)}), "
- <> "#{data.recovered} soignés (#{Util.plusminus(data.new_recovered)}) (@ #{data.update})")
+ m.replyfun.(
+ "coronavirus: #{location}: " <>
+ "#{data.current} malades (#{Util.plusminus(data.new_current)}), " <>
+ "#{data.confirmed} confirmés (#{Util.plusminus(data.new_confirmed)}), " <>
+ "#{data.deaths} morts (#{Util.plusminus(data.new_deaths)}), " <>
+ "#{data.recovered} soignés (#{Util.plusminus(data.new_recovered)}) (@ #{data.update})"
+ )
end
+
{:noreply, state}
end
- def handle_info({:irc, :trigger, "coronavirus", m = %Nola.Message{trigger: %{type: :query, args: location}}}, state) do
+ def handle_info(
+ {:irc, :trigger, "coronavirus",
+ m = %Nola.Message{trigger: %{type: :query, args: location}}},
+ state
+ ) do
m.replyfun.("https://github.com/CSSEGISandData/COVID-19")
{:noreply, state}
end
@@ -93,80 +128,125 @@ defmodule Nola.Plugins.Coronavirus do
# 2. Fetch yesterday if no results
defp fetch_data(current_data, date \\ nil) do
now = Date.utc_today()
- url = fn(date) ->
+
+ url = fn date ->
"https://github.com/CSSEGISandData/COVID-19/raw/master/csse_covid_19_data/csse_covid_19_daily_reports/#{date}.csv"
end
+
request_date = date || now
- Logger.debug("Coronavirus check date: #{inspect request_date}")
- {:ok, date_s} = Timex.format({request_date.year, request_date.month, request_date.day}, "%m-%d-%Y", :strftime)
+ Logger.debug("Coronavirus check date: #{inspect(request_date)}")
+
+ {:ok, date_s} =
+ Timex.format(
+ {request_date.year, request_date.month, request_date.day},
+ "%m-%d-%Y",
+ :strftime
+ )
+
cur_url = url.(date_s)
- Logger.debug "Fetching URL #{cur_url}"
+ Logger.debug("Fetching URL #{cur_url}")
+
case HTTPoison.get(cur_url, [], follow_redirect: true) do
{:ok, %HTTPoison.Response{status_code: 200, body: csv}} ->
# Parse CSV update data
- data = csv
- |> CovidCsv.parse_string()
- |> Enum.reduce(%{}, fn(line, acc) ->
- case line do
- # FIPS,Admin2,Province_State,Country_Region,Last_Update,Lat,Long_,Confirmed,Deaths,Recovered,Active,Combined_Key
- #0FIPS,Admin2,Province_State,Country_Region,Last_Update,Lat,Long_,Confirmed,Deaths,Recovered,Active,Combined_Key,Incidence_Rate,Case-Fatality_Ratio
- [_, _, state, region, update, _lat, _lng, confirmed, deaths, recovered, _active, _combined_key, _incidence_rate, _fatality_ratio] ->
- state = String.downcase(state)
- region = String.downcase(region)
- confirmed = String.to_integer(confirmed)
- deaths = String.to_integer(deaths)
- recovered = String.to_integer(recovered)
-
- current = (confirmed - recovered) - deaths
-
- entry = %{update: update, confirmed: confirmed, deaths: deaths, recovered: recovered, current: current, region: region}
-
- region_entry = Map.get(acc, region, %{update: nil, confirmed: 0, deaths: 0, recovered: 0, current: 0})
- region_entry = %{
- update: region_entry.update || update,
- confirmed: region_entry.confirmed + confirmed,
- deaths: region_entry.deaths + deaths,
- current: region_entry.current + current,
- recovered: region_entry.recovered + recovered,
- region: true
- }
-
- changes = if old = Map.get(current_data, region) do
- %{
- new_confirmed: region_entry.confirmed - old.confirmed,
- new_current: region_entry.current - old.current,
- new_deaths: region_entry.deaths - old.deaths,
- new_recovered: region_entry.recovered - old.recovered,
+ data =
+ csv
+ |> CovidCsv.parse_string()
+ |> Enum.reduce(%{}, fn line, acc ->
+ case line do
+ # FIPS,Admin2,Province_State,Country_Region,Last_Update,Lat,Long_,Confirmed,Deaths,Recovered,Active,Combined_Key
+ # 0FIPS,Admin2,Province_State,Country_Region,Last_Update,Lat,Long_,Confirmed,Deaths,Recovered,Active,Combined_Key,Incidence_Rate,Case-Fatality_Ratio
+ [
+ _,
+ _,
+ state,
+ region,
+ update,
+ _lat,
+ _lng,
+ confirmed,
+ deaths,
+ recovered,
+ _active,
+ _combined_key,
+ _incidence_rate,
+ _fatality_ratio
+ ] ->
+ state = String.downcase(state)
+ region = String.downcase(region)
+ confirmed = String.to_integer(confirmed)
+ deaths = String.to_integer(deaths)
+ recovered = String.to_integer(recovered)
+
+ current = confirmed - recovered - deaths
+
+ entry = %{
+ update: update,
+ confirmed: confirmed,
+ deaths: deaths,
+ recovered: recovered,
+ current: current,
+ region: region
}
- else
- %{new_confirmed: 0, new_current: 0, new_deaths: 0, new_recovered: 0}
- end
- region_entry = Map.merge(region_entry, changes)
-
- acc = Map.put(acc, region, region_entry)
+ region_entry =
+ Map.get(acc, region, %{
+ update: nil,
+ confirmed: 0,
+ deaths: 0,
+ recovered: 0,
+ current: 0
+ })
+
+ region_entry = %{
+ update: region_entry.update || update,
+ confirmed: region_entry.confirmed + confirmed,
+ deaths: region_entry.deaths + deaths,
+ current: region_entry.current + current,
+ recovered: region_entry.recovered + recovered,
+ region: true
+ }
- acc = if state && state != "" do
- Map.put(acc, state, entry)
- else
+ changes =
+ if old = Map.get(current_data, region) do
+ %{
+ new_confirmed: region_entry.confirmed - old.confirmed,
+ new_current: region_entry.current - old.current,
+ new_deaths: region_entry.deaths - old.deaths,
+ new_recovered: region_entry.recovered - old.recovered
+ }
+ else
+ %{new_confirmed: 0, new_current: 0, new_deaths: 0, new_recovered: 0}
+ end
+
+ region_entry = Map.merge(region_entry, changes)
+
+ acc = Map.put(acc, region, region_entry)
+
+ acc =
+ if state && state != "" do
+ Map.put(acc, state, entry)
+ else
+ acc
+ end
+
+ other ->
+ Logger.info("Coronavirus line failed: #{inspect(line)}")
acc
- end
+ end
+ end)
- other ->
- Logger.info("Coronavirus line failed: #{inspect line}")
- acc
- end
- end)
- Logger.info "Updated coronavirus database"
+ Logger.info("Updated coronavirus database")
{data, :timer.minutes(60)}
+
{:ok, %HTTPoison.Response{status_code: 404}} ->
- Logger.debug "Corona 404 #{cur_url}"
+ Logger.debug("Corona 404 #{cur_url}")
date = Date.add(date || now, -1)
fetch_data(current_data, date)
+
other ->
- Logger.error "Coronavirus: Update failed #{inspect other}"
+ Logger.error("Coronavirus: Update failed #{inspect(other)}")
{current_data, :timer.minutes(5)}
end
end
-
end