1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.RichMedia.Parser do
8 @config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
11 Pleroma.Config.get([:rich_media, :parsers])
14 def parse(nil), do: nil
16 @spec parse(String.t()) :: {:ok, map()} | {:error, any()}
18 with :ok <- validate_page_url(url),
19 {:ok, data} <- parse_url(url) do
20 data = Map.put(data, "url", url)
25 defp parse_url(url) do
26 with {:ok, %Tesla.Env{body: html}} <- Pleroma.Web.RichMedia.Helpers.rich_media_get(url),
27 {:ok, html} <- Floki.parse_document(html) do
30 |> clean_parsed_data()
31 |> check_parsed_data()
35 defp maybe_parse(html) do
36 Enum.reduce_while(parsers(), %{}, fn parser, acc ->
37 case parser.parse(html, acc) do
38 data when data != %{} -> {:halt, data}
44 defp check_parsed_data(%{"title" => title} = data)
45 when is_binary(title) and title != "" do
49 defp check_parsed_data(data) do
50 {:error, {:invalid_metadata, data}}
53 defp clean_parsed_data(data) do
55 |> Enum.reject(fn {key, val} ->
56 not match?({:ok, _}, Jason.encode(%{key => val}))
61 @spec validate_page_url(URI.t() | binary()) :: :ok | :error
62 defp validate_page_url(page_url) when is_binary(page_url) do
63 validate_tld = @config_impl.get([Pleroma.Formatter, :validate_tld])
66 |> Linkify.Parser.url?(validate_tld: validate_tld)
67 |> parse_uri(page_url)
70 defp validate_page_url(%URI{host: host, scheme: "https"}) do
72 Linkify.Parser.ip?(host) ->
75 host in @config_impl.get([:rich_media, :ignore_hosts], []) ->
78 get_tld(host) in @config_impl.get([:rich_media, :ignore_tld], []) ->
86 defp validate_page_url(_), do: :error
88 defp parse_uri(true, url) do
94 defp parse_uri(_, _), do: :error