Skip to content

Commit

Permalink
Merge pull request #4 from r8/fixes
Browse files Browse the repository at this point in the history
Fixes
  • Loading branch information
r8 authored Feb 25, 2017
2 parents 324a522 + 0fc428f commit 173758c
Show file tree
Hide file tree
Showing 13 changed files with 125 additions and 30 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Change Log

## [0.1.0] - 2017-02-25

Initial release.
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@
[![Inline docs](http://inch-ci.org/github/r8/elixir-oembed.svg?branch=master&style=flat)](http://inch-ci.org/github/r8/elixir-oembed)
[![Ebert](https://ebertapp.io/github/r8/elixir-oembed.svg)](https://ebertapp.io/github/r8/elixir-oembed)

Work in progress
oEmbed consumer library for Elixir applications.

oEmbed consumer for Elixir
> oEmbed is a format for allowing an embedded representation of a URL on third party sites. The simple API allows a website to display embedded content (such as photos or videos) when a user posts a link to that resource, without having to parse the resource directly.
> -- See [oembed.com](http://oembed.com) for more info about the protocol.
This library supports any discoverable oEmbed endpoint and some other services via custom adapters.
Among them:

- Instagram
- Pinterest

## Installation

Add `oembed` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[{:oembed, "~> 0.1.0"}]
end
```

## Usage

```elixir
{:ok, result} = OEmbed.for("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
```
25 changes: 21 additions & 4 deletions lib/oembed.ex
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
defmodule OEmbed do
@moduledoc """
oEmbed consumer for Elixir.
oEmbed consumer library for Elixir applications.
## Usage
```elixir
{:ok, result} = OEmbed.for("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
```
"""

@core_providers [OEmbed.InstagramProvider,
OEmbed.PinterestProvider,
OEmbed.DiscoverableProvider]

@doc """
Get oEmbed structure for given URL.
## Example
```elixir
{:ok, result} = OEmbed.for("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
```
"""
def for(url) do
case Enum.find(get_providers(), fn(provider) -> provider.provides?(url) end) do
nil ->
Expand All @@ -13,8 +32,6 @@ defmodule OEmbed do
end

defp get_providers do
[OEmbed.InstagramProvider,
OEmbed.PinterestProvider,
OEmbed.DiscoverProvider]
@core_providers
end
end
44 changes: 26 additions & 18 deletions lib/oembed/provider.ex
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
defmodule OEmbed.Provider do
@moduledoc """
oEmbed provider behaviour.
"""

defmacro __using__(_) do
quote do
import OEmbed.Provider

@behaviour OEmbed.Provider
end
end
alias OEmbed.Link
alias OEmbed.Photo
alias OEmbed.Rich
alias OEmbed.Video

alias OEmbed.{Link, Photo, Rich, Video}
@behaviour OEmbed.Provider

@callback provides?(String.t) :: boolean
defp get_oembed(url) do
with {:ok, %HTTPoison.Response{body: body}} <- HTTPoison.get(url, [], [follow_redirect: true, ssl: [{:versions, [:'tlsv1.2']}]]),
{:ok, struct} <- Poison.decode(body),
resource <- get_resource(struct) do
{:ok, resource}
else
_ -> {:error, "oEmbed url not found"}
end
end

def get_oembed(url) do
with {:ok, %HTTPoison.Response{body: body}} <- HTTPoison.get(url, [], [follow_redirect: true, ssl: [{:versions, [:'tlsv1.2']}]]),
{:ok, struct} <- Poison.decode(body),
resource <- get_resource(struct) do
{:ok, resource}
else
_ -> {:error, "oEmbed url not found"}
defp get_resource(%{"type" => "link"} = struct), do: Link.new(struct)
defp get_resource(%{"type" => "photo"} = struct), do: Photo.new(struct)
defp get_resource(%{"type" => "rich"} = struct), do: Rich.new(struct)
defp get_resource(%{"type" => "video"} = struct), do: Video.new(struct)
defp get_resource(struct), do: struct
end
end

defp get_resource(%{"type" => "link"} = struct), do: Link.new(struct)
defp get_resource(%{"type" => "photo"} = struct), do: Photo.new(struct)
defp get_resource(%{"type" => "rich"} = struct), do: Rich.new(struct)
defp get_resource(%{"type" => "video"} = struct), do: Video.new(struct)
defp get_resource(struct), do: struct
end
@callback provides?(String.t) :: boolean
@callback get(String.t) :: struct
end
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
defmodule OEmbed.DiscoverProvider do
defmodule OEmbed.DiscoverableProvider do
@moduledoc """
oEmbed provider for discoverable endpoints.
"""

use OEmbed.Provider

@doc """
Check if this provider supports given URL.
"""
def provides?(_) do
true
end

@doc """
Get oEmbed result for given URL.
"""
def get(url) do
with {:ok, href} <- discover(url),
{:ok, oembed} <- get_oembed(href) do
Expand All @@ -15,7 +25,7 @@ defmodule OEmbed.DiscoverProvider do
end
end

def discover(url) do
defp discover(url) do
with {:ok, %HTTPoison.Response{body: html}} <- HTTPoison.get(url, [], [follow_redirect: true, ssl: [{:versions, [:'tlsv1.2']}]]),
[_ | _] = tags <- Floki.find(html, "head link[type='application/json+oembed']"),
{"link", attributes, _} <- List.first(tags),
Expand Down
9 changes: 9 additions & 0 deletions lib/oembed/providers/instagram_provider.ex
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
defmodule OEmbed.InstagramProvider do
@moduledoc """
oEmbed provider for Instagram URLs.
"""
use OEmbed.Provider

@oembed_endpoint "https://api.instagram.com/oembed?url="

@doc """
Check if this provider supports given URL.
"""
def provides?(url) do
Regex.match?(~r/^(?:(?:http|https):\/\/)?(?:www.)?(?:instagram.com|instagr.am)\/([A-Za-z0-9-_]+)/im, url)
end

@doc """
Get oEmbed result for given URL.
"""
def get(url) do
get_oembed(@oembed_endpoint <> url)
end
Expand Down
11 changes: 10 additions & 1 deletion lib/oembed/providers/pinterest_provider.ex
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
defmodule OEmbed.PinterestProvider do
@moduledoc """
oEmbed provider for Pinterest URLs.
"""
use OEmbed.Provider

alias OEmbed.Rich

@doc """
Check if this provider supports given URL.
"""
def provides?(url) do
Regex.match?(~r/^(?:(?:http|https):\/\/)?(?:[A-Za-z0-9-_]+\.)*?(?:pinterest.com)\/(?:pin)?\/(?:[0-9-_]+)/im, url)
end

@doc """
Get oEmbed result for given URL.
"""
def get(url) do
oembed = Rich.new(%{
html: get_pin_html(url)
Expand All @@ -15,7 +24,7 @@ defmodule OEmbed.PinterestProvider do
{:ok, oembed}
end

def get_pin_html(url) do
defp get_pin_html(url) do
"""
<a data-pin-do="embedPin" data-pin-width="large" href="#{url}"></a>
<script async defer src="//assets.pinterest.com/js/pinit.js"></script>
Expand Down
2 changes: 1 addition & 1 deletion lib/oembed/resource.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule OEmbed.Resource do
@moduledoc """
oEmbed resource
oEmbed resource.
"""

defmacro __using__(_) do
Expand Down
3 changes: 3 additions & 0 deletions lib/oembed/resources/link.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
defmodule OEmbed.Link do
@moduledoc """
oEmbed Link resource.
"""

@keys [type: "link"]

Expand Down
3 changes: 3 additions & 0 deletions lib/oembed/resources/photo.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
defmodule OEmbed.Photo do
@moduledoc """
oEmbed Photo resource.
"""

@keys [type: "photo", url: nil, width: nil, height: nil]

Expand Down
3 changes: 3 additions & 0 deletions lib/oembed/resources/rich.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
defmodule OEmbed.Rich do
@moduledoc """
oEmbed Rich resource.
"""

@keys [type: "rich", html: nil, width: nil, height: nil]

Expand Down
3 changes: 3 additions & 0 deletions lib/oembed/resources/video.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
defmodule OEmbed.Video do
@moduledoc """
oEmbed Video resource.
"""

@keys [type: "video", html: nil, width: nil, height: nil]

Expand Down
6 changes: 4 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ defmodule OEmbed.Mixfile do
{:exconstructor, ">= 1.0.0"},
{:exvcr, "~> 0.8", only: :test},
{:inch_ex, only: :docs},
{:credo, "~> 0.6.1", only: :dev}]
{:credo, "~> 0.6.1", only: :dev},
{:earmark, ">= 0.0.0", only: :dev},
{:ex_doc, "~> 0.10", only: :dev}]
end

defp docs do
Expand All @@ -50,7 +52,7 @@ defmodule OEmbed.Mixfile do

defp description do
"""
oEmbed consumer for Elixir.
oEmbed consumer library for Elixir applications.
"""
end

Expand Down

0 comments on commit 173758c

Please sign in to comment.