diff options
author | Jordan Bracco <href@random.sh> | 2025-06-25 19:22:59 +0200 |
---|---|---|
committer | Jordan Bracco <href@random.sh> | 2025-06-25 19:22:59 +0200 |
commit | c934e79e5852e05f714b2d542cc2678e287c49b8 (patch) | |
tree | 55779a0168260fce03e4775eacdd613ffc945588 /lib/plugins/coronavirus.ex | |
parent | updates (diff) |
format.
Diffstat (limited to 'lib/plugins/coronavirus.ex')
-rw-r--r-- | lib/plugins/coronavirus.ex | 266 |
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 |