defmodule CobblemonUi.TierListScraper do @url "https://rankedboost.com/pokemon/tier-list/" @filename "pokemon_tier_list.json" def output_file do dir = System.get_env("CACHE_DIR", ".") Path.join(dir, @filename) end def run do with {:ok, html} <- fetch_page(), pokemon <- parse(html), :ok <- write_json(pokemon) do {:ok, pokemon} end end def fetch_page do case Req.get(@url) do {:ok, %Req.Response{status: 200, body: body}} -> {:ok, body} {:ok, %Req.Response{status: status}} -> {:error, {:http_error, status}} {:error, err} -> {:error, err} end end def parse(html) do html |> Floki.parse_document!() |> Floki.find(".pokemon-tier") |> Enum.map(&extract_pokemon/1) end defp extract_pokemon(node) do name = node |> Floki.find(".name") |> Floki.text() |> String.trim() tier = node |> Floki.find(".tier") |> Floki.text() |> String.trim() %{name: name, tier: tier} end def write_json(data) do json = Jason.encode!(data, pretty: true) File.write(output_file(), json) end # Returns a map of %{lowercase_name => tier} for fast lookup, or an empty map if unavailable. def load_tier_list do with {:ok, contents} <- File.read(output_file()), {:ok, entries} <- Jason.decode(contents) do Map.new(entries, fn %{"name" => name, "tier" => tier} -> {String.downcase(name), tier} end) else _ -> %{} end end end