100 lines
2.2 KiB
Elixir
100 lines
2.2 KiB
Elixir
defmodule FeedParser.Parser.JSONFeed do
|
|
@moduledoc """
|
|
A `FeedParser.Parser` that handles [JSON Feeds](https://jsonfeed.org/version/1).
|
|
"""
|
|
|
|
@behaviour FeedParser.Parser
|
|
|
|
@mime_types [
|
|
"application/json",
|
|
"application/feed+json"
|
|
]
|
|
|
|
@versions [
|
|
"https://jsonfeed.org/version/1",
|
|
"https://jsonfeed.org/version/1.1"
|
|
]
|
|
|
|
@impl FeedParser.Parser
|
|
def accepts(data, content_type) do
|
|
with true <- content_type in @mime_types,
|
|
{:ok, json} <- Poison.decode(data),
|
|
%{"version" => v} when v in @versions <- json do
|
|
{true, json}
|
|
else
|
|
_ ->
|
|
false
|
|
end
|
|
end
|
|
|
|
@impl FeedParser.Parser
|
|
def parse_feed(json) do
|
|
title = json["title"]
|
|
home_page_url = Map.get(json, "home_page_url")
|
|
icon = Map.get(json, "icon") || Map.get(json, "favicon")
|
|
|
|
feed_author = authors_string(json)
|
|
|
|
items =
|
|
Map.get(json, "items", [])
|
|
|> Enum.map(fn item ->
|
|
id = item["id"]
|
|
|
|
url =
|
|
Map.get(item, "url") ||
|
|
if String.starts_with?(id, ["http://", "https://"]), do: id, else: nil
|
|
|
|
title = Map.get(item, "title")
|
|
|
|
content =
|
|
Map.get(item, "content_html") || Map.get(item, "content_text") ||
|
|
Map.get(item, "summary")
|
|
|
|
date =
|
|
(Map.get(item, "date_published") || Map.get(item, "date_updated"))
|
|
|> Timex.parse("{RFC3339}")
|
|
|> case do
|
|
{:ok, date} -> date
|
|
_ -> nil
|
|
end
|
|
|
|
author = authors_string(item) || feed_author
|
|
|
|
%FeedParser.Item{
|
|
guid: id,
|
|
url: url,
|
|
links: [{url, nil}],
|
|
title: title,
|
|
content: content,
|
|
date: date,
|
|
creator: author
|
|
}
|
|
end)
|
|
|
|
{:ok,
|
|
%FeedParser.Feed{
|
|
site_url: home_page_url,
|
|
title: title,
|
|
image_url: icon,
|
|
last_updated: nil,
|
|
items: items
|
|
}}
|
|
end
|
|
|
|
defp authors_string(%{"author" => author}) do
|
|
author_name(author)
|
|
end
|
|
|
|
defp authors_string(%{"authors" => authors}) do
|
|
authors
|
|
|> Enum.map(&author_name/1)
|
|
|> Enum.reject(&is_nil/1)
|
|
|> Enum.join(", ")
|
|
end
|
|
|
|
defp authors_string(_), do: nil
|
|
|
|
defp author_name(%{"name" => name}), do: name
|
|
defp author_name(_), do: nil
|
|
end
|