diff --git a/config/oembed.php b/config/oembed.php index 6929b9774..7819da95c 100644 --- a/config/oembed.php +++ b/config/oembed.php @@ -1,25 +1,50 @@ [ 'providers' => [ - - 'soundcloud.com' => 'https://soundcloud.com/oembed', - - '*.spotify.com' => 'https://embed.spotify.com/oembed/', - - 'vimeo.com' => 'https://vimeo.com/api/oembed.json', - '*.vimeo.com' => 'https://vimeo.com/api/oembed.json', - - 'youtube.com' => 'https://www.youtube.com/oembed', - 'www.youtube.com' => 'https://www.youtube.com/oembed', - 'youtu.be' => 'https://www.youtube.com/oembed', + 'soundcloud' => [ + 'name' => 'SoundCloud', + 'match' => ['soundcloud.com'], + 'url' => 'https://soundcloud.com/oembed', + ], + 'spotify' => [ + 'name' => 'Spotify', + 'match' => ['*.spotify.com'], + 'url' => 'https://embed.spotify.com/oembed', + ], + 'vimeo' => [ + 'name' => 'Vimeo', + 'match' => [ + 'vimeo.com', + '*.vimeo.com', + ], + 'url' => 'https://vimeo.com/api/oembed.json', + 'options' => [ + 'headers' => [ + 'Referer' => env('VIMEO_REFERER_HEADER', Router::url('/', true)), + ], + ], + ], + 'youtube' => [ + 'name' => 'YouTube', + 'match' => [ + 'youtube.com', + 'www.youtube.com', + 'youtu.be', + ], + 'url' => 'https://www.youtube.com/oembed', + ], ], ], ]; diff --git a/src/Utility/OEmbed.php b/src/Utility/OEmbed.php index 875ba3c2e..5d939a389 100644 --- a/src/Utility/OEmbed.php +++ b/src/Utility/OEmbed.php @@ -33,17 +33,18 @@ public function readMetadata($url): array { $parsed = parse_url($url); $host = Hash::get($parsed, 'host', ''); - $oemBedurl = $this->findProvider($host); - if (empty($oemBedurl)) { + $provider = $this->findProvider($host); + $oEmbedUrl = Hash::get($provider, 'url'); + if (empty($oEmbedUrl)) { return ['provider_url' => $url]; } - $oemBedurl = sprintf('%s?url=%s&format=json', $oemBedurl, $url); + $oEmbedUrl = sprintf('%s?url=%s&format=json', $oEmbedUrl, rawurlencode($url)); // custom UID if not found via oEmbed => query or path $providerUID = Hash::get($parsed, 'query', Hash::get($parsed, 'path')); - $meta = $this->fetchJson($oemBedurl); + $meta = $this->fetchJson($oEmbedUrl, (array)Hash::get($provider, 'options')); if (empty($meta)) { return ['provider_url' => $url]; } @@ -62,13 +63,14 @@ public function readMetadata($url): array /** * Fetch oEmbed JSON response from oEmbed provider URL * - * @param string $oemBedurl oEmbed URL + * @param string $oEmbedUrl oEmbed URL + * @param array $options The options to apply to the request * @return array JSON decoded response or empty array on failure * @codeCoverageIgnore */ - protected function fetchJson(string $oemBedurl): array + protected function fetchJson(string $oEmbedUrl, array $options = []): array { - $o = (new Client())->get($oemBedurl, [], ['type' => 'json']); + $o = (new Client())->get($oEmbedUrl, [], ['type' => 'json'] + $options); return $o->getJson() ?? []; } @@ -77,23 +79,27 @@ protected function fetchJson(string $oemBedurl): array * Find oEmbed provider URL for a given hostname * * @param string $host Host name - * @return string|null OEmbed provider or null if no match + * @return array OEmbed provider configuration or null if no match */ - protected function findProvider(string $host): ?string + protected function findProvider(string $host): array { Configure::load('oembed'); - // exact match + $providers = (array)Configure::read('OEmbed.providers'); - if (!empty($providers[$host])) { - return $providers[$host]; - } - // wildcard match - foreach ($providers as $h => $url) { - if (fnmatch($h, $host)) { - return $url; + $providerConf = array_filter($providers, function ($conf) use ($host) { + foreach ((array)Hash::get($conf, 'match') as $pattern) { + if (fnmatch($pattern, $host)) { + return true; + } } + + return false; + }); + + if (empty($providerConf)) { + return []; } - return null; + return current($providerConf); } } diff --git a/templates/Element/Form/media.twig b/templates/Element/Form/media.twig index 9dd21aa62..daa7bb731 100644 --- a/templates/Element/Form/media.twig +++ b/templates/Element/Form/media.twig @@ -9,8 +9,12 @@
{# Display embedded video if available #} {% if object.attributes.provider_extra.html %} + {% set height = object.attributes.provider_extra.height|default(1) %} + {% set width = object.attributes.provider_extra.width|default(1) %}
+ {% if height matches '/^\\d+$/' and width matches '/^\\d+$/' %} + style="padding-bottom: {{ 100 * height / width|default(1) }}%;" + {% endif %}> {{ object.attributes.provider_extra.html|raw }}
{% else %} diff --git a/tests/TestCase/Utility/OEmbedTest.php b/tests/TestCase/Utility/OEmbedTest.php index d5b44f85d..180f79a80 100644 --- a/tests/TestCase/Utility/OEmbedTest.php +++ b/tests/TestCase/Utility/OEmbedTest.php @@ -83,7 +83,7 @@ public function testReadMetadata(array $expected, string $url, array $oembedResp $oembed = new class () extends OEmbed { public $json = []; - protected function fetchJson(string $oembedUrl): array + protected function fetchJson(string $oembedUrl, array $options = []): array { return $this->json; }