Elixir downloading files
Mix.install([
{:bumblebee, "~> 0.5.0"},
{:req, "~> 0.5.0"},
{:kino, "~> 0.13.0"}
])
Image source URL
source_url = "https://elixir-lang.org/images/logo/logo.png"
Destination path
downloads_dir = Path.join(System.tmp_dir!(), "downloads")
File.mkdir_p!(downloads_dir)
extname = Path.extname(source_url)
destination_path = Path.join(downloads_dir, "elixir_logo" <> extname)
Req (binary)
%{status: 200} = response = Req.get!(source_url)
<<_::binary>> = response.body
Req (file)
Req.get!(source_url, into: File.stream!(destination_path))
File.read!(destination_path)
Bumblebee (file)
Bumblebee.Utils.HTTP.download(source_url, destination_path)
File.read!(destination_path)
Req + Finch + ProgressBar
defmodule MNishiguchi.Utils.HTTP do
def download(source_url, req_options \\ []) do
case Req.get(source_url, [finch_request: &finch_request/4] ++ req_options) do
{:ok, response} -> {:ok, response.body}
{:error, exception} -> {:error, exception}
end
end
def download!(source_url, req_options \\ []) do
Req.get!(source_url, [finch_request: &finch_request/4] ++ req_options).body
end
defp finch_request(req_request, finch_request, finch_name, finch_options) do
acc = Req.Response.new()
case Finch.stream(finch_request, finch_name, acc, &handle_finch_stream/2, finch_options) do
{:ok, response} -> {req_request, response}
{:error, exception} -> {req_request, exception}
end
end
defp handle_finch_stream({:status, status}, response), do: %{response | status: status}
defp handle_finch_stream({:headers, headers}, response) do
req_headers = headers |> Enum.map(fn {k, v} -> {k, List.wrap(v)} end) |> Map.new()
total_size = req_headers |> Map.fetch!("content-length") |> List.first() |> String.to_integer
response
|> Map.put(:headers, req_headers)
|> Map.put(:private, %{total_size: total_size, downloaded_size: 0})
end
defp handle_finch_stream({:data, data}, response) do
new_downloaded_size = response.private.downloaded_size + byte_size(data)
ProgressBar.render(new_downloaded_size, response.private.total_size, suffix: :bytes)
response
|> Map.update!(:body, &(&1 <> data))
|> Map.update!(:private, &%{&1 | downloaded_size: new_downloaded_size})
end
end
MNishiguchi.Utils.HTTP.download!(source_url, into: File.stream!(destination_path))
File.read!(destination_path)
<<_::binary>> = data = MNishiguchi.Utils.HTTP.download!(source_url)
data