lib/send_video.ex

defmodule Exstream.SendVideo do
  import Plug.Conn

  def get_file_size(path) do
    {:ok, %{size: size}} = File.stat(path)

    size
  end

  def handle_range({"range", "bytes=0-1"}, conn, path) do
    file_size = get_file_size(path)

    conn
    |> put_resp_header("content-type", "video/mp4")
    |> put_resp_header("content-range", "bytes 0-1/#{file_size}")
    |> send_file(206, path, 0, 2)
  end

  def handle_range({"range", "bytes=" <> start_pos}, conn, path) do
    file_size = get_file_size(path)

    offset =
      String.split(start_pos, "-")
      |> hd
      |> String.to_integer()

    conn
    |> put_resp_header("content-type", "video/mp4")
    |> put_resp_header("content-range", "bytes #{offset}-#{file_size - 1}/#{file_size}")
    |> send_file(206, path, offset, file_size - offset)
  end

  def handle_range(nil, conn, path) do
    file_size = get_file_size(path)

    conn
    |> put_resp_header("content-type", "video/mp4")
    |> put_resp_header("content-range", "bytes 0-#{file_size - 1}/#{file_size}")
    |> send_file(206, path, 0, file_size - 0)
  end

  def send_video(conn, headers, path) do
    List.keyfind(headers, "range", 0)
    |> handle_range(conn, path)
  end

  def init(default), do: default

  def call(%Plug.Conn{req_headers: headers} = conn, path) do
    send_video(conn, headers, path)
  end
end