* on this event to add our action handler for Embed.
*
* @param $m URLMapper the router that was initialized.
- * @return bool true if successful, the exception object if it isn't.
+ * @return void true if successful, the exception object if it isn't.
+ * @throws Exception
*/
public function onRouterInitialized(URLMapper $m)
{
$metadata->thumbnail_width = $info->imageWidth;
} catch (Exception $e) {
common_log(LOG_INFO, "Failed to find Embed data for {$url} with 'oscarotero/Embed'");
- try {
- common_log(LOG_INFO, "Trying to discover an oEmbed endpoint for {$url} using link headers.");
- $api = EmbedHelper::oEmbedEndpointFromHTML($dom);
- common_log(LOG_INFO, 'Found oEmbed API endpoint ' . $api . ' for URL ' . $url);
- $params = array(
- 'maxwidth' => common_config('thumbnail', 'width'),
- 'maxheight' => common_config('thumbnail', 'height'),
- );
- $metadata = EmbedHelper::getOembedFrom($api, $url, $params);
- // Facebook just gives us javascript in its oembed html,
- // so use the content of the title element instead
- if (strpos($url, 'https://www.facebook.com/') === 0) {
- $metadata->html = @$dom->getElementsByTagName('title')->item(0)->nodeValue;
- }
-
- // Wordpress sometimes also just gives us javascript, use og:description if it is available
- $xpath = new DomXpath($dom);
- $generatorNode = @$xpath->query('//meta[@name="generator"][1]')->item(0);
- if ($generatorNode instanceof DomElement) {
- // when wordpress only gives us javascript, the html stripped from tags
- // is the same as the title, so this helps us to identify this (common) case
- if (strpos($generatorNode->getAttribute('content'), 'WordPress') === 0
- && trim(strip_tags($metadata->html)) == trim($metadata->title)) {
- $propertyNode = @$xpath->query('//meta[@property="og:description"][1]')->item(0);
- if ($propertyNode instanceof DomElement) {
- $metadata->html = $propertyNode->getAttribute('content');
- }
- }
- }
- } catch (Exception $e) {
- // FIXME - make sure the error was because we couldn't get metadata, not something else! -mb
- common_log(LOG_INFO, 'Could not find an oEmbed endpoint using link headers, ' .
- 'trying OpenGraph from HTML.');
- // Just ignore it!
- $metadata = OpenGraphHelper::ogFromHtml($dom);
- }
}
if (isset($metadata->thumbnail_url)) {
*/
class EmbedHelper
{
- protected static $apiMap = array(
- 'flickr.com' => 'https://www.flickr.com/services/oembed/',
- 'youtube.com' => 'https://www.youtube.com/oembed',
- 'viddler.com' => 'http://lab.viddler.com/services/oembed/',
- 'revision3.com' => 'https://revision3.com/api/oembed/',
- 'vimeo.com' => 'https://vimeo.com/api/oembed.json',
- );
/**
* Perform or fake an oEmbed lookup for the given resource.
* Throws exceptions on failure.
*
* @param string $url
- * @param array $params
* @return object
+ * @throws EmbedHelper_BadHtmlException
+ * @throws HTTP_Request2_Exception
*/
- public static function getObject($url, $params=array())
+ public static function getObject($url)
{
common_log(LOG_INFO, 'Checking for remote URL metadata for ' . $url);
return self::normalize($metadata);
}
- /**
- * Partially ripped from OStatus' FeedDiscovery class.
- *
- * @param string $url source URL, used to resolve relative links
- * @param string $body HTML body text
- * @return mixed string with URL or false if no target found
- */
- public static function oEmbedEndpointFromHTML(DOMDocument $dom)
- {
- // Ok... now on to the links!
- $feeds = array(
- 'application/json+oembed' => false,
- );
-
- $nodes = $dom->getElementsByTagName('link');
- for ($i = 0; $i < $nodes->length; $i++) {
- $node = $nodes->item($i);
- if ($node->hasAttributes()) {
- $rel = $node->attributes->getNamedItem('rel');
- $type = $node->attributes->getNamedItem('type');
- $href = $node->attributes->getNamedItem('href');
- if ($rel && $type && $href) {
- $rel = array_filter(explode(" ", $rel->value));
- $type = trim($type->value);
- $href = trim($href->value);
-
- if (in_array('alternate', $rel) && array_key_exists($type, $feeds) && empty($feeds[$type])) {
- // Save the first feed found of each type...
- $feeds[$type] = $href;
- }
- }
- }
- }
-
- // Return the highest-priority feed found
- foreach ($feeds as $type => $url) {
- if ($url) {
- return $url;
- }
- }
-
- throw new EmbedHelper_DiscoveryException();
- }
-
- /**
- * Actually do an oEmbed lookup to a particular API endpoint.
- *
- * @param string $api oEmbed API endpoint URL
- * @param string $url target URL to look up info about
- * @param array $params
- * @return object
- */
- public static function getOembedFrom($api, $url, $params=array())
- {
- if (empty($api)) {
- // TRANS: Server exception thrown in oEmbed action if no API endpoint is available.
- throw new ServerException(_('No oEmbed API endpoint available.'));
- }
- $params['url'] = $url;
- $params['format'] = 'json';
- $key=common_config('oembed', 'apikey');
- if (isset($key)) {
- $params['key'] = common_config('oembed', 'apikey');
- }
-
- $oembed_data = HTTPClient::quickGetJson($api, $params);
- if (isset($oembed_data->html)) {
- $oembed_data->html = common_purify($oembed_data->html);
- }
-
- return $oembed_data;
- }
-
/**
* Normalize oEmbed format.
*
- * @param object $orig
+ * @param stdClass $data
* @return object
+ * @throws Exception
*/
public static function normalize(stdClass $data)
{
{
public function __construct($message = "", $code = 0, $previous = null)
{
- parent::__construct($message, $code);
+ parent::__construct($message, $code, $previous);
}
}
+++ /dev/null
-<?php
-// This file is part of GNU social - https://www.gnu.org/software/social
-//
-// GNU social is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// GNU social is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * OembedPlugin implementation for GNU social
- *
- * @package GNUsocial
- * @author Mikael Nordfeldth
- * @author Diogo Cordeiro <diogo@fc.up.pt>
- * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
- * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
- */
-
-defined('GNUSOCIAL') || die();
-
-/**
- * Utility class to get OpenGraph data from HTML DOMs etc.
- *
- * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org
- * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
- */
-class OpenGraphHelper
-{
- const KEY_REGEX = '/^og\:(\w+(?:\:\w+)?)/';
- protected static $property_map = [
- 'site_name' => 'provider_name',
- 'title' => 'title',
- 'description' => 'html',
- 'type' => 'type',
- 'url' => 'url',
- 'image' => 'thumbnail_url',
- 'image:height' => 'thumbnail_height',
- 'image:width' => 'thumbnail_width',
- ];
-
- // This regex map has: /pattern(match)/ => matchindex | string
- protected static $type_regex_map = [
- '/^(video)/' => 1,
- '/^image/' => 'photo',
- ];
-
- public static function ogFromHtml(DOMDocument $dom)
- {
- $obj = new stdClass();
- $obj->version = '1.0'; // fake it til u make it
-
- $nodes = $dom->getElementsByTagName('meta');
- for ($i = 0; $i < $nodes->length; $i++) {
- $node = $nodes->item($i);
- if (!$node->hasAttributes()) {
- continue;
- }
- $property = $node->attributes->getNamedItem('property');
- $matches = array();
- if ($property === null || !preg_match(self::KEY_REGEX, $property->value, $matches)) {
- // not property="og:something"
- continue;
- }
- if (!isset(self::$property_map[$matches[1]])) {
- // unknown metadata property, nothing we would care about anyway
- continue;
- }
-
- $prop = self::$property_map[$matches[1]];
- $obj->{$prop} = $node->attributes->getNamedItem('content')->value;
- // I don't care right now if they're empty
- }
- if (isset($obj->type)) {
- // Loop through each known OpenGraph type where we have a match in oEmbed
- foreach (self::$type_regex_map as $pattern=>$replacement) {
- $matches = array();
- if (preg_match($pattern, $obj->type, $matches)) {
- $obj->type = is_int($replacement)
- ? $matches[$replacement]
- : $replacement;
- break;
- }
- }
- // If it's not known to our type map, we just pass it through in hopes of it getting handled anyway
- } elseif (isset($obj->url)) {
- // If no type is set but we have a URL, let's set type=link
- $obj->type = 'link';
- }
- return $obj;
- }
-}