* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('STATUSNET')) {
- exit(1);
-}
+if (!defined('GNUSOCIAL')) { exit(1); }
/**
'revision3.com' => 'https://revision3.com/api/oembed/',
'vimeo.com' => 'https://vimeo.com/api/oembed.json',
);
- protected static $functionMap = array(
- 'twitpic.com' => 'oEmbedHelper::twitPic',
- );
/**
* Perform or fake an oEmbed lookup for the given resource.
*/
public static function getObject($url, $params=array())
{
- $host = parse_url($url, PHP_URL_HOST);
- if (substr($host, 0, 4) == 'www.') {
- $host = substr($host, 4);
- }
-
- common_log(LOG_INFO, 'Checking for oEmbed data for ' . $url);
+ common_log(LOG_INFO, 'Checking for remote URL metadata for ' . $url);
- // You can fiddle with the order of discovery -- either skipping
- // some types or re-ordering them.
+ // TODO: Make this class something like UrlMetadata, or use a dataobject?
+ $metadata = new stdClass();
- $order = common_config('oembed', 'order');
+ if (Event::handle('GetRemoteUrlMetadata', array($url, &$metadata))) {
+ // If that event didn't return anything, try downloading the body and parse it
+ $body = HTTPClient::quickGet($url);
- foreach ($order as $method) {
+ // DOMDocument::loadHTML may throw warnings on unrecognized elements,
+ // and notices on unrecognized namespaces.
+ $old = error_reporting(error_reporting() & ~(E_WARNING | E_NOTICE));
+ $dom = new DOMDocument();
+ $ok = $dom->loadHTML($body);
+ unset($body); // storing the DOM in memory is enough...
+ error_reporting($old);
- switch ($method) {
- case 'built-in':
- common_log(LOG_INFO, 'Considering built-in oEmbed methods...');
- // Blacklist: systems with no oEmbed API of their own, which are
- // either missing from or broken on noembed.com's proxy.
- // we know how to look data up in another way...
- if (array_key_exists($host, self::$functionMap)) {
- common_log(LOG_INFO, 'We have a built-in method for ' . $host);
- $func = self::$functionMap[$host];
- return call_user_func($func, $url, $params);
- }
- break;
- case 'well-known':
- common_log(LOG_INFO, 'Considering well-known oEmbed endpoints...');
- // Whitelist: known API endpoints for sites that don't provide discovery...
- if (array_key_exists($host, self::$apiMap)) {
- $api = self::$apiMap[$host];
- common_log(LOG_INFO, 'Using well-known endpoint "' . $api . '" for "' . $host . '"');
- break 2;
- }
- break;
- case 'discovery':
- try {
- common_log(LOG_INFO, 'Trying to discover an oEmbed endpoint using link headers.');
- $api = self::discover($url);
- common_log(LOG_INFO, 'Found API endpoint ' . $api . ' for URL ' . $url);
- break 2;
- } catch (Exception $e) {
- common_log(LOG_INFO, 'Could not find an oEmbed endpoint using link headers.');
- // Just ignore it!
- }
- break;
- case 'service':
- $api = common_config('oembed', 'endpoint');
- common_log(LOG_INFO, 'Using service API endpoint ' . $api);
- break 2;
- break;
+ if (!$ok) {
+ throw new oEmbedHelper_BadHtmlException();
}
- }
- if (empty($api)) {
- // TRANS: Server exception thrown in oEmbed action if no API endpoint is available.
- throw new ServerException(_('No oEmbed API endpoint available.'));
+ Event::handle('GetRemoteUrlMetadataFromDom', array($url, $dom, &$metadata));
}
- return self::getObjectFrom($api, $url, $params);
- }
-
- /**
- * Perform basic discovery.
- * @return string
- */
- static function discover($url)
- {
- // @fixme ideally skip this for non-HTML stuff!
- $body = self::http($url);
- return self::discoverFromHTML($url, $body);
+ return self::normalize($metadata);
}
/**
* @param string $body HTML body text
* @return mixed string with URL or false if no target found
*/
- static function discoverFromHTML($url, $body)
+ static function oEmbedEndpointFromHTML(DOMDocument $dom)
{
- // DOMDocument::loadHTML may throw warnings on unrecognized elements,
- // and notices on unrecognized namespaces.
- $old = error_reporting(error_reporting() & ~(E_WARNING | E_NOTICE));
- $dom = new DOMDocument();
- $ok = $dom->loadHTML($body);
- error_reporting($old);
-
- if (!$ok) {
- throw new oEmbedHelper_BadHtmlException();
- }
-
// Ok... now on to the links!
$feeds = array(
'application/json+oembed' => false,
* @param array $params
* @return object
*/
- static function getObjectFrom($api, $url, $params=array())
+ 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');
}
- $data = self::json($api, $params);
- return self::normalize($data);
+ return HTTPClient::quickGetJson($api, $params);
}
/**
* @param object $orig
* @return object
*/
- static function normalize($orig)
+ static function normalize(stdClass $data)
{
- $data = clone($orig);
-
if (empty($data->type)) {
throw new Exception('Invalid oEmbed data: no type field.');
}
-
if ($data->type == 'image') {
// YFrog does this.
$data->type = 'photo';
return $data;
}
-
- /**
- * Using a local function for twitpic lookups, as oohembed's adapter
- * doesn't return a valid result:
- * http://code.google.com/p/oohembed/issues/detail?id=19
- *
- * This code fetches metadata from Twitpic's own API, and attempts
- * to guess proper thumbnail size from the original's size.
- *
- * @todo respect maxwidth and maxheight params
- *
- * @param string $url
- * @param array $params
- * @return object
- */
- static function twitPic($url, $params=array())
- {
- $matches = array();
- if (preg_match('!twitpic\.com/(\w+)!', $url, $matches)) {
- $id = $matches[1];
- } else {
- throw new Exception("Invalid twitpic URL");
- }
-
- // Grab metadata from twitpic's API...
- // http://dev.twitpic.com/docs/2/media_show
- $data = self::json('http://api.twitpic.com/2/media/show.json',
- array('id' => $id));
- $oembed = (object)array('type' => 'photo',
- 'url' => 'http://twitpic.com/show/full/' . $data->short_id,
- 'width' => $data->width,
- 'height' => $data->height);
- if (!empty($data->message)) {
- $oembed->title = $data->message;
- }
-
- // Thumbnail is cropped and scaled to 150x150 box:
- // http://dev.twitpic.com/docs/thumbnails/
- $thumbSize = 150;
- $oembed->thumbnail_url = 'http://twitpic.com/show/thumb/' . $data->short_id;
- $oembed->thumbnail_width = $thumbSize;
- $oembed->thumbnail_height = $thumbSize;
-
- return $oembed;
- }
-
- /**
- * Fetch some URL and return JSON data.
- *
- * @param string $url
- * @param array $params query-string params
- * @return object
- */
- static protected function json($url, $params=array())
- {
- $data = self::http($url, $params);
- return json_decode($data);
- }
-
- /**
- * Hit some web API and return data on success.
- * @param string $url
- * @param array $params
- * @return string
- */
- static protected function http($url, $params=array())
- {
- $client = HTTPClient::start();
- if ($params) {
- $query = http_build_query($params, null, '&');
- if (strpos($url, '?') === false) {
- $url .= '?' . $query;
- } else {
- $url .= '&' . $query;
- }
- }
- $response = $client->get($url);
- if ($response->isOk()) {
- return $response->getBody();
- } else {
- throw new Exception('Bad HTTP response code: ' . $response->getStatus());
- }
- }
}
class oEmbedHelper_Exception extends Exception