defmodule OEmbedProviders do @moduledoc """ Build OEmbed URLs with a list of providers. """ alias OEmbedProviders.Provider @providers_file Application.app_dir(:oembed_providers) |> Path.join("priv/providers.json") @providers Application.get_env(:oembed_providers, :providers_file, @providers_file) |> File.read!() |> Jason.decode!() |> Enum.map(&Provider.from_map/1) @doc """ Get a list of available providers. ```elixir iex(1)> OEmbedProviders.list_providers() [ %OEmbedProviders.Provider{ endpoints: [ %OEmbedProviders.Provider.Endpoint{ discovery: nil, formats: [], schemes: ["http://www.23hq.com/*/photo/*"], url: "http://www.23hq.com/23/oembed" } ], provider_name: "23HQ", provider_url: "http://www.23hq.com" }, %OEmbedProviders.Provider{...}, %OEmbedProviders.Provider{...}, %OEmbedProviders.Provider{...}, ... ] ``` """ @spec list_providers() :: [Provider.t()] def list_providers(), do: @providers @doc """ Get the `OEmbedProviders.Provider` for a URL. ```elixir iex(2)> OEmbedProviders.find_provider("https://www.youtube.com/watch?v=dQw4w9WgXcQ") %OEmbedProviders.Provider{ endpoints: [ %OEmbedProviders.Provider.Endpoint{ discovery: true, formats: [], schemes: ["https://*.youtube.com/watch*", "https://*.youtube.com/v/*", "https://youtu.be/*"], url: "https://www.youtube.com/oembed" } ], provider_name: "YouTube", provider_url: "https://www.youtube.com/" } ``` """ @spec find_provider(url :: String.t()) :: Provider.t() def find_provider(url) do Enum.find(list_providers(), &Provider.matches?(&1, url)) end @doc """ Construct the OEmbed endpoint URL for the given URL. ```elixir iex(1)> OEmbedProviders.oembed_url("https://www.youtube.com/watch?v=dQw4w9WgXcQ") {:ok, "https://www.youtube.com/oembed?format=json&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdQw4w9WgXcQ"} iex(2)> OEmbedProviders.oembed_url("https://gleasonator.com/@alex") {:error, :no_provider} ``` """ @spec oembed_url(url :: String.t()) :: {:ok, String.t()} | {:error, any()} def oembed_url(url) do with %Provider{} = provider <- find_provider(url), {:ok, oembed_url} <- Provider.oembed_url(provider, url) do {:ok, oembed_url} else {:error, error} -> {:error, error} nil -> {:error, :no_provider} error -> {:error, error} end end end