resolve relative item urls with the absolute feed_url

This commit is contained in:
mmacia committed 2026-06-23 20:58:37 +00:00
1 parent 677fc89fbd
commit 1c3b0a8e2b
7 files changed
+94 -23

No files matched your search

+8 -6
View File
@@ -1,7 +1,7 @@
defmodule FeedReader.Formats.Atom do
@moduledoc "Atom feed detection and normalization."
@behaviour FeedReader.Format
alias FeedReader.{Feed, Item, XMLResourceLimits}
alias FeedReader.{Feed, Item, URL, XMLResourceLimits}
@impl true
def matches_prefix?(prefix), do: Regex.match?(~r/<feed\b/is, prefix)
@@ -44,7 +44,13 @@ defmodule FeedReader.Formats.Atom do
title = raw |> Map.get("title") |> text() |> clean()
content = raw |> Map.get("content") |> content()
summary = raw |> Map.get("summary") |> content() || if(is_nil(content), do: title)
canonical = raw |> Map.get("link") |> List.wrap() |> find_link() |> correct_url(feed.html_url)
canonical =
raw
|> Map.get("link")
|> List.wrap()
|> find_link()
|> URL.resolve_root_relative([feed.html_url, feed.feed_url])
author = get_in(raw, ["author", "name"]) |> text()
@@ -88,10 +94,6 @@ defmodule FeedReader.Formats.Atom do
defp valid_url?(url),
do: is_binary(url) and url |> URI.parse() |> then(&(!is_nil(&1.scheme) and !is_nil(&1.host)))
defp correct_url("/" <> _ = url, base) when is_binary(base),
do: URI.merge(base, url) |> URI.to_string()
defp correct_url(url, _base), do: url
defp clean(nil), do: nil
defp clean(value), do: value |> HtmlSanitizeEx.strip_tags() |> blank_to_nil()
defp blank_to_nil(value), do: if(String.trim(value) == "", do: nil, else: String.trim(value))
+7 -7
View File
@@ -2,7 +2,7 @@ defmodule FeedReader.Formats.RDF do
@moduledoc "RDF Site Summary format detection and normalization."
@behaviour FeedReader.Format
alias FeedReader.{Feed, Item, XMLResourceLimits}
alias FeedReader.{Feed, Item, URL, XMLResourceLimits}
@impl true
def matches_prefix?(prefix), do: Regex.match?(~r/<rdf:rdf\b/is, prefix)
@@ -52,7 +52,12 @@ defmodule FeedReader.Formats.RDF do
title = raw |> Map.get("title") |> text() |> clean()
description = text(raw["description"])
content = text(raw["content:encoded"])
canonical = raw |> Map.get("link") |> text() |> correct_url(feed.html_url)
canonical =
raw
|> Map.get("link")
|> text()
|> URL.resolve_root_relative([feed.html_url, feed.feed_url])
{:ok,
%Item{
@@ -76,11 +81,6 @@ defmodule FeedReader.Formats.RDF do
defp clean(nil), do: nil
defp clean(value), do: value |> HtmlSanitizeEx.strip_tags() |> text()
defp correct_url("/" <> _ = url, base) when is_binary(base),
do: URI.merge(base, url) |> URI.to_string()
defp correct_url(url, _base), do: url
defp published_at(nil), do: DateTime.utc_now(:second)
defp published_at(value) do
+2 -9
View File
@@ -3,7 +3,7 @@ defmodule FeedReader.Formats.RSS do
@behaviour FeedReader.Format
alias FeedReader.{Feed, Item, XMLResourceLimits}
alias FeedReader.{Feed, Item, URL, XMLResourceLimits}
@impl true
def matches_prefix?(prefix) do
@@ -58,7 +58,7 @@ defmodule FeedReader.Formats.RSS do
content = value(item, "content:encoded")
link = value(item, "link")
canonical_url = correct_url(link, feed.html_url)
canonical_url = URL.resolve_root_relative(link, [feed.html_url, feed.feed_url])
uuid = value(item, "guid") || canonical_url
summary = description || if(is_nil(content), do: title)
language_text = Enum.join(Enum.reject([title, content, description], &is_nil/1), "\n")
@@ -91,13 +91,6 @@ defmodule FeedReader.Formats.RSS do
defp clean_title(nil), do: nil
defp clean_title(value), do: value |> HtmlSanitizeEx.strip_tags() |> blank_to_nil()
defp correct_url(nil, _base), do: nil
defp correct_url("/" <> _ = url, base) when is_binary(base),
do: URI.merge(base, url) |> URI.to_string()
defp correct_url(url, _base), do: url
defp published_at(nil), do: nil
defp published_at(value) do
+32
View File
@@ -0,0 +1,32 @@
defmodule FeedReader.URL do
@moduledoc false
@doc "Resolves root-relative URLs against the first valid absolute base."
@spec resolve_root_relative(String.t() | nil, [String.t() | nil]) :: String.t() | nil
def resolve_root_relative(nil, _bases), do: nil
def resolve_root_relative("/" <> _ = url, bases) when is_list(bases) do
case Enum.find(bases, &absolute?/1) do
nil -> url
base -> merge(base, url)
end
end
def resolve_root_relative(url, _bases), do: url
defp absolute?(url) when is_binary(url) do
uri = URI.parse(url)
is_binary(uri.scheme) and is_binary(uri.host)
rescue
URI.Error -> false
end
defp absolute?(_url), do: false
defp merge(base, url) do
URI.merge(base, url) |> URI.to_string()
rescue
URI.Error -> url
ArgumentError -> url
end
end