addtag: Whether to add a tag for the group nickname for every group post
(pre-1.0.x behaviour). Defaults to false.
-oembed
---------
-
-oEmbed endpoint for multimedia attachments (links in posts). Will also
-work as 'oohembed' for backwards compatibility.
-
-endpoint: oohembed endpoint using http://oohembed.com/ software. Defaults to
- 'http://oohembed.com/oohembed/'.
-order: Array of methods to check for OEmbed data. Methods include 'built-in'
- (use a built-in function to simulate oEmbed for some sites),
- 'well-known' (use well-known public oEmbed endpoints),
- 'discovery' (discover using <link> headers in HTML), 'service' (use
- a third-party service, like oohembed or embed.ly. Default is
- array('built-in', 'well-known', 'service', 'discovery'). Note that very
- few sites implement oEmbed; 'discovery' is going to fail 99% of the
- time.
-
search
------
return $a->title();
}
- function extraHead()
- {
- $this->element('link',array('rel'=>'alternate',
- 'type'=>'application/json+oembed',
- 'href'=>common_local_url(
- 'oembed',
- array(),
- array('format'=>'json', 'url'=>
- common_local_url('attachment',
- array('attachment' => $this->attachment->id)))),
- 'title'=>'oEmbed'),null);
- $this->element('link',array('rel'=>'alternate',
- 'type'=>'text/xml+oembed',
- 'href'=>common_local_url(
- 'oembed',
- array(),
- array('format'=>'xml','url'=>
- common_local_url('attachment',
- array('attachment' => $this->attachment->id)))),
- 'title'=>'oEmbed'),null);
- }
-
/**
* Handle input
*
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * StatusNet-only extensions to the Twitter-like API
- *
- * PHP version 5
- *
- * LICENCE: This program 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.
- *
- * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * @category Twitter
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2008 StatusNet, Inc.
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-/**
- * Oembed provider implementation
- *
- * This class handles all /main/oembed(.xml|.json)/ requests.
- *
- * @category oEmbed
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @copyright 2008 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-class OembedAction extends Action
-{
-
- function handle($args)
- {
- common_debug("in oembed api action");
-
- $url = $args['url'];
- if( substr(strtolower($url),0,strlen(common_root_url())) == strtolower(common_root_url()) ){
- $path = substr($url,strlen(common_root_url()));
-
- $r = Router::get();
-
- $proxy_args = $r->map($path);
-
- if (!$proxy_args) {
- // TRANS: Server error displayed in oEmbed action when path not found.
- // TRANS: %s is a path.
- $this->serverError(sprintf(_('"%s" not found.'),$path), 404);
- }
- $oembed=array();
- $oembed['version']='1.0';
- $oembed['provider_name']=common_config('site', 'name');
- $oembed['provider_url']=common_root_url();
- switch($proxy_args['action']){
- case 'shownotice':
- $oembed['type']='link';
- $id = $proxy_args['notice'];
- $notice = Notice::getKV($id);
- if(empty($notice)){
- // TRANS: Server error displayed in oEmbed action when notice not found.
- // TRANS: %s is a notice.
- $this->serverError(sprintf(_("Notice %s not found."),$id), 404);
- }
- $profile = $notice->getProfile();
- if (empty($profile)) {
- // TRANS: Server error displayed in oEmbed action when notice has not profile.
- $this->serverError(_('Notice has no profile.'), 500);
- }
- $authorname = $profile->getFancyName();
- // TRANS: oEmbed title. %1$s is the author name, %2$s is the creation date.
- $oembed['title'] = sprintf(_('%1$s\'s status on %2$s'),
- $authorname,
- common_exact_date($notice->created));
- $oembed['author_name']=$authorname;
- $oembed['author_url']=$profile->profileurl;
- $oembed['url']=$notice->getUrl();
- $oembed['html']=$notice->rendered;
- break;
- case 'attachment':
- $id = $proxy_args['attachment'];
- $attachment = File::getKV($id);
- if(empty($attachment)){
- // TRANS: Server error displayed in oEmbed action when attachment not found.
- // TRANS: %d is an attachment ID.
- $this->serverError(sprintf(_('Attachment %s not found.'),$id), 404);
- }
- if(empty($attachment->filename) && $file_oembed = File_oembed::getKV('file_id', $attachment->id)){
- // Proxy the existing oembed information
- $oembed['type']=$file_oembed->type;
- $oembed['provider']=$file_oembed->provider;
- $oembed['provider_url']=$file_oembed->provider_url;
- $oembed['width']=$file_oembed->width;
- $oembed['height']=$file_oembed->height;
- $oembed['html']=$file_oembed->html;
- $oembed['title']=$file_oembed->title;
- $oembed['author_name']=$file_oembed->author_name;
- $oembed['author_url']=$file_oembed->author_url;
- $oembed['url']=$file_oembed->getUrl();
- }else if(substr($attachment->mimetype,0,strlen('image/'))=='image/'){
- $oembed['type']='photo';
- if ($attachment->filename) {
- $filepath = File::path($attachment->filename);
- $gis = @getimagesize($filepath);
- if ($gis) {
- $oembed['width'] = $gis[0];
- $oembed['height'] = $gis[1];
- } else {
- // TODO Either throw an error or find a fallback?
- }
- }
- $oembed['url']=$attachment->getUrl();
- try {
- $thumb = $attachment->getThumbnail();
- $oembed['thumbnail_url'] = $thumb->getUrl();
- $oembed['thumbnail_width'] = $thumb->width;
- $oembed['thumbnail_height'] = $thumb->height;
- unset($thumb);
- } catch (UnsupportedMediaException $e) {
- // No thumbnail data available
- }
- }else{
- $oembed['type']='link';
- $oembed['url']=common_local_url('attachment',
- array('attachment' => $attachment->id));
- }
- if($attachment->title) $oembed['title']=$attachment->title;
- break;
- default:
- // TRANS: Server error displayed in oEmbed request when a path is not supported.
- // TRANS: %s is a path.
- $this->serverError(sprintf(_('"%s" not supported for oembed requests.'),$path), 501);
- }
- switch($args['format']){
- case 'xml':
- $this->init_document('xml');
- $this->elementStart('oembed');
- $this->element('version',null,$oembed['version']);
- $this->element('type',null,$oembed['type']);
- if($oembed['provider_name']) $this->element('provider_name',null,$oembed['provider_name']);
- if($oembed['provider_url']) $this->element('provider_url',null,$oembed['provider_url']);
- if($oembed['title']) $this->element('title',null,$oembed['title']);
- if($oembed['author_name']) $this->element('author_name',null,$oembed['author_name']);
- if($oembed['author_url']) $this->element('author_url',null,$oembed['author_url']);
- if($oembed['url']) $this->element('url',null,$oembed['url']);
- if($oembed['html']) $this->element('html',null,$oembed['html']);
- if($oembed['width']) $this->element('width',null,$oembed['width']);
- if($oembed['height']) $this->element('height',null,$oembed['height']);
- if($oembed['cache_age']) $this->element('cache_age',null,$oembed['cache_age']);
- if($oembed['thumbnail_url']) $this->element('thumbnail_url',null,$oembed['thumbnail_url']);
- if($oembed['thumbnail_width']) $this->element('thumbnail_width',null,$oembed['thumbnail_width']);
- if($oembed['thumbnail_height']) $this->element('thumbnail_height',null,$oembed['thumbnail_height']);
-
- $this->elementEnd('oembed');
- $this->end_document('xml');
- break;
- case 'json': case '':
- $this->init_document('json');
- print(json_encode($oembed));
- $this->end_document('json');
- break;
- default:
- // TRANS: Error message displaying attachments. %s is a raw MIME type (eg 'image/png')
- $this->serverError(sprintf(_('Content type %s not supported.'), $apidata['content-type']), 501);
- }
- }else{
- // TRANS: Error message displaying attachments. %s is the site's base URL.
- $this->serverError(sprintf(_('Only %s URLs over plain HTTP please.'), common_root_url()), 404);
- }
- }
-
- function init_document($type)
- {
- switch ($type) {
- case 'xml':
- header('Content-Type: application/xml; charset=utf-8');
- $this->startXML();
- break;
- case 'json':
- header('Content-Type: application/json; charset=utf-8');
-
- // Check for JSONP callback
- $callback = $this->arg('callback');
- if ($callback) {
- print $callback . '(';
- }
- break;
- default:
- // TRANS: Server error displayed in oEmbed action when request specifies an unsupported data format.
- $this->serverError(_('Not a supported data format.'), 501);
- break;
- }
- }
-
- function end_document($type='xml')
- {
- switch ($type) {
- case 'xml':
- $this->endXML();
- break;
- case 'json':
- // Check for JSONP callback
- $callback = $this->arg('callback');
- if ($callback) {
- print ')';
- }
- break;
- default:
- // TRANS: Server error displayed in oEmbed action when request specifies an unsupported data format.
- $this->serverError(_('Not a supported data format.'), 501);
- break;
- }
- return;
- }
-
- /**
- * Is this action read-only?
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- return true;
- }
-}
'content' => $id->toString()));
}
- $this->element('link',array('rel'=>'alternate',
- 'type'=>'application/json+oembed',
- 'href'=>common_local_url(
- 'oembed',
- array(),
- array('format'=>'json','url'=>$this->notice->getUrl())),
- 'title'=>'oEmbed'),null);
- $this->element('link',array('rel'=>'alternate',
- 'type'=>'text/xml+oembed',
- 'href'=>common_local_url(
- 'oembed',
- array(),
- array('format'=>'xml','url'=>$this->notice->getUrl())),
- 'title'=>'oEmbed'),null);
-
// Extras to aid in sharing notices to Facebook
$avatarUrl = $this->profile->avatarUrl(AVATAR_PROFILE_SIZE);
$this->element('meta', array('property' => 'og:image',
// I don't know why we have to keep doing this but I'm adding this last check to avoid
// uniqueness bugs.
- $x = File::getKV('url', $given_url);
+ $file = File::getKV('url', $given_url);
- if (!$x instanceof File) {
- $x = new File;
- $x->url = $given_url;
- if (!empty($redir_data['protected'])) $x->protected = $redir_data['protected'];
- if (!empty($redir_data['title'])) $x->title = $redir_data['title'];
- if (!empty($redir_data['type'])) $x->mimetype = $redir_data['type'];
- if (!empty($redir_data['size'])) $x->size = intval($redir_data['size']);
- if (isset($redir_data['time']) && $redir_data['time'] > 0) $x->date = intval($redir_data['time']);
- $file_id = $x->insert();
+ if (!$file instanceof File) {
+ $file = new File;
+ $file->url = $given_url;
+ if (!empty($redir_data['protected'])) $file->protected = $redir_data['protected'];
+ if (!empty($redir_data['title'])) $file->title = $redir_data['title'];
+ if (!empty($redir_data['type'])) $file->mimetype = $redir_data['type'];
+ if (!empty($redir_data['size'])) $file->size = intval($redir_data['size']);
+ if (isset($redir_data['time']) && $redir_data['time'] > 0) $file->date = intval($redir_data['time']);
+ $file_id = $file->insert();
}
- $x->saveOembed($redir_data, $given_url);
- return $x;
- }
-
- /**
- * Save embedding information for this file, if applicable.
- *
- * Normally this won't need to be called manually, as File::saveNew()
- * takes care of it.
- *
- * @param array $redir_data lookup data eg from File_redirection::where()
- * @param string $given_url
- * @return boolean success
- */
- public function saveOembed(array $redir_data, $given_url)
- {
- if (isset($redir_data['type'])
- && (('text/html' === substr($redir_data['type'], 0, 9)
- || 'application/xhtml+xml' === substr($redir_data['type'], 0, 21)))) {
- try {
- $oembed_data = File_oembed::_getOembed($given_url);
- } catch (Exception $e) {
- return false;
- }
- if ($oembed_data === false) {
- return false;
- }
- $fo = File_oembed::getKV('file_id', $this->id);
-
- if ($fo instanceof File_oembed) {
- common_log(LOG_WARNING, "Strangely, a File_oembed object exists for new file $file_id", __FILE__);
- } else {
- File_oembed::saveNew($oembed_data, $this->id);
- return true;
- }
- }
- return false;
+ Event::handle('EndFileSaveNew', array($file, $redir_data, $given_url));
+ return $file;
}
/**
* Go look at a URL and possibly save data about it if it's new:
* - follow redirect chains and store them in file_redirection
- * - look up oEmbed data and save it in file_oembed
* - if a thumbnail is available, save it in file_thumbnail
* - save file record with basic info
* - optionally save a file_to_post record
$enclosure->size=$this->size;
$enclosure->mimetype=$this->mimetype;
- if(! isset($this->filename)){
+ if (!isset($this->filename)) {
$notEnclosureMimeTypes = array(null,'text/html','application/xhtml+xml');
$mimetype = $this->mimetype;
if($mimetype != null){
if($semicolon){
$mimetype = substr($mimetype,0,$semicolon);
}
- if(in_array($mimetype,$notEnclosureMimeTypes)){
- // Never treat generic HTML links as an enclosure type!
- // But if we have oEmbed info, we'll consider it golden.
- $oembed = File_oembed::getKV('file_id',$this->id);
- if($oembed && in_array($oembed->type, array('photo', 'video'))){
- $mimetype = strtolower($oembed->mimetype);
- $semicolon = strpos($mimetype,';');
- if($semicolon){
- $mimetype = substr($mimetype,0,$semicolon);
- }
- // @fixme uncertain if this is right.
- // we want to expose things like YouTube videos as
- // viewable attachments, but don't expose them as
- // downloadable enclosures.....?
- //if (in_array($mimetype, $notEnclosureMimeTypes)) {
- // return false;
- //} else {
- if($oembed->mimetype) $enclosure->mimetype=$oembed->mimetype;
- if($oembed->url) $enclosure->url=$oembed->url;
- if($oembed->title) $enclosure->title=$oembed->title;
- if($oembed->modified) $enclosure->modified=$oembed->modified;
- unset($oembed->size);
- //}
- } else {
- return false;
- }
+ if (in_array($mimetype, $notEnclosureMimeTypes)) {
+ Event::handle('FileEnclosureMetadata', array($file, &$enclosure));
}
}
return $enclosure;
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program 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.
- *
- * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('GNUSOCIAL')) { exit(1); }
-
-/**
- * Table Definition for file_oembed
- */
-
-class File_oembed extends Managed_DataObject
-{
- public $__table = 'file_oembed'; // table name
- public $file_id; // int(4) primary_key not_null
- public $version; // varchar(20)
- public $type; // varchar(20)
- public $mimetype; // varchar(50)
- public $provider; // varchar(50)
- public $provider_url; // varchar(255)
- public $width; // int(4)
- public $height; // int(4)
- public $html; // text()
- public $title; // varchar(255)
- public $author_name; // varchar(50)
- public $author_url; // varchar(255)
- public $url; // varchar(255)
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'file_id' => array('type' => 'int', 'not null' => true, 'description' => 'oEmbed for that URL/file'),
- 'version' => array('type' => 'varchar', 'length' => 20, 'description' => 'oEmbed spec. version'),
- 'type' => array('type' => 'varchar', 'length' => 20, 'description' => 'oEmbed type: photo, video, link, rich'),
- 'mimetype' => array('type' => 'varchar', 'length' => 50, 'description' => 'mime type of resource'),
- 'provider' => array('type' => 'varchar', 'length' => 50, 'description' => 'name of this oEmbed provider'),
- 'provider_url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of this oEmbed provider'),
- 'width' => array('type' => 'int', 'description' => 'width of oEmbed resource when available'),
- 'height' => array('type' => 'int', 'description' => 'height of oEmbed resource when available'),
- 'html' => array('type' => 'text', 'description' => 'html representation of this oEmbed resource when applicable'),
- 'title' => array('type' => 'varchar', 'length' => 255, 'description' => 'title of oEmbed resource when available'),
- 'author_name' => array('type' => 'varchar', 'length' => 50, 'description' => 'author name for this oEmbed resource'),
- 'author_url' => array('type' => 'varchar', 'length' => 255, 'description' => 'author URL for this oEmbed resource'),
- 'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL for this oEmbed resource when applicable (photo, link)'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('file_id'),
- 'foreign keys' => array(
- 'file_oembed_file_id_fkey' => array('file', array('file_id' => 'id')),
- ),
- );
- }
-
- function _getOembed($url) {
- $parameters = array(
- 'maxwidth' => common_config('thumbnail', 'width'),
- 'maxheight' => common_config('thumbnail', 'height'),
- );
- try {
- return oEmbedHelper::getObject($url, $parameters);
- } catch (Exception $e) {
- common_log(LOG_INFO, "Error during oembed lookup for $url - " . $e->getMessage());
- return false;
- }
- }
-
- public function getUrl()
- {
- return $this->url;
- }
-
- /**
- * Save embedding info for a new file.
- *
- * @param object $data Services_oEmbed_Object_*
- * @param int $file_id
- */
- public static function saveNew($data, $file_id) {
- $file_oembed = new File_oembed;
- $file_oembed->file_id = $file_id;
- if (!isset($data->version)) {
- common_debug('DEBUGGING oEmbed: data->version undefined in variable $data: '.var_export($data, true));
- }
- $file_oembed->version = $data->version;
- $file_oembed->type = $data->type;
- if (!empty($data->provider_name)) $file_oembed->provider = $data->provider_name;
- if (!empty($data->provider)) $file_oembed->provider = $data->provider;
- if (!empty($data->provider_url)) $file_oembed->provider_url = $data->provider_url;
- if (!empty($data->width)) $file_oembed->width = intval($data->width);
- if (!empty($data->height)) $file_oembed->height = intval($data->height);
- if (!empty($data->html)) $file_oembed->html = $data->html;
- if (!empty($data->title)) $file_oembed->title = $data->title;
- if (!empty($data->author_name)) $file_oembed->author_name = $data->author_name;
- if (!empty($data->author_url)) $file_oembed->author_url = $data->author_url;
- if (!empty($data->url)){
- $file_oembed->url = $data->url;
- $given_url = File_redirection::_canonUrl($file_oembed->url);
- if (! empty($given_url)){
- $file = File::getKV('url', $given_url);
- if ($file instanceof File) {
- $file_oembed->mimetype = $file->mimetype;
- } else {
- $file_redir = File_redirection::getKV('url', $given_url);
- if (empty($file_redir)) {
- $redir_data = File_redirection::where($given_url);
- $file_oembed->mimetype = $redir_data['type'];
- } else {
- $file_id = $file_redir->file_id;
- }
- }
- }
- }
- $file_oembed->insert();
- if (!empty($data->thumbnail_url) || ($data->type == 'photo')) {
- $ft = File_thumbnail::getKV('file_id', $file_id);
- if ($ft instanceof File_thumbnail) {
- common_log(LOG_WARNING, "Strangely, a File_thumbnail object exists for new file $file_id",
- __FILE__);
- } else {
- File_thumbnail::saveNew($data, $file_id);
- }
- }
- }
-}
// Save file and embedding data about it!
$file = File::saveNew($redir_data, $long_url);
$file_id = $file->id;
- if (!empty($redir_data['oembed']['json'])) {
- File_oembed::saveNew($redir_data['oembed']['json'], $file_id);
- }
} else if (is_string($redir_data)) {
// The file is a known redirect target.
$file = File::getKV('url', $redir_data);
'Group_inbox',
'Group_member',
'File',
- 'File_oembed',
'File_redirection',
'File_thumbnail',
'File_to_post',
return $this->scoped;
}
+ public function getActionName()
+ {
+ return $this->action;
+ }
+
/**
* Show page, a template method.
*
var $attachment = null;
- var $oembed = null;
-
/**
* @param File $attachment the attachment we will display
*/
{
parent::__construct($out);
$this->attachment = $attachment;
- $this->oembed = File_oembed::getKV('file_id', $this->attachment->id);
}
function title() {
- if (empty($this->attachment->title)) {
- if (empty($this->oembed->title)) {
- $title = $this->attachment->filename;
- } else {
- $title = $this->oembed->title;
- }
- } else {
- $title = $this->attachment->title;
- }
-
- return $title;
+ return $this->attachment->title ?: $this->attachment->filename;
}
function linkTitle() {
class Attachment extends AttachmentListItem
{
function showLink() {
- $this->out->elementStart('div', array('id' => 'attachment_view',
- 'class' => 'hentry'));
- $this->out->elementStart('div', 'entry-title');
- $this->out->element('a', $this->linkAttr(), $this->linkTitle());
- $this->out->elementEnd('div');
+ if (Event::handle('StartShowAttachmentLink', array($this->out, $this->attachment))) {
+ $this->out->elementStart('div', array('id' => 'attachment_view',
+ 'class' => 'hentry'));
+ $this->out->elementStart('div', 'entry-title');
+ $this->out->element('a', $this->linkAttr(), $this->linkTitle());
+ $this->out->elementEnd('div');
- $this->out->elementStart('div', 'entry-content');
- $this->showRepresentation();
- $this->out->elementEnd('div');
-
- if (!empty($this->oembed->author_name) || !empty($this->oembed->provider)) {
- $this->out->elementStart('div', array('id' => 'oembed_info',
- 'class' => 'entry-content'));
- if (!empty($this->oembed->author_name)) {
- $this->out->elementStart('div', 'fn vcard author');
- if (empty($this->oembed->author_url)) {
- $this->out->text($this->oembed->author_name);
- } else {
- $this->out->element('a', array('href' => $this->oembed->author_url,
- 'class' => 'url'), $this->oembed->author_name);
- }
- }
- if (!empty($this->oembed->provider)) {
- $this->out->elementStart('div', 'fn vcard');
- if (empty($this->oembed->provider_url)) {
- $this->out->text($this->oembed->provider);
- } else {
- $this->out->element('a', array('href' => $this->oembed->provider_url,
- 'class' => 'url'), $this->oembed->provider);
- }
- }
+ $this->out->elementStart('div', 'entry-content');
+ $this->showRepresentation();
+ $this->out->elementEnd('div');
+ Event::handle('EndShowAttachmentLink', array($this->out, $this->attachment));
$this->out->elementEnd('div');
}
- $this->out->elementEnd('div');
}
function show() {
function showRepresentation() {
if (Event::handle('StartShowAttachmentRepresentation', array($this->out, $this->attachment))) {
- if (!empty($this->oembed->type)) {
- switch ($this->oembed->type) {
- case 'rich':
- case 'video':
- case 'link':
- if (!empty($this->oembed->html)) {
- require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
- $config = array(
- 'safe'=>1,
- 'elements'=>'*+object+embed');
- $this->out->raw(htmLawed($this->oembed->html,$config));
- }
- break;
-
- case 'photo':
- $this->out->element('img', array('src' => $this->oembed->url, 'width' => $this->oembed->width, 'height' => $this->oembed->height, 'alt' => 'alt'));
- break;
-
- default:
- Event::handle('ShowUnsupportedAttachmentRepresentation', array($this->out, $this->attachment));
- }
- } elseif (!empty($this->attachment->mimetype)) {
+ if (!empty($this->attachment->mimetype)) {
switch ($this->attachment->mimetype) {
case 'image/gif':
case 'image/png':
'ClientSideShorten' => array(),
'EmailAuthentication' => array(),
'Event' => array(),
+ 'Oembed' => array(),
'OpenID' => array(),
'Poll' => array(),
'QnA' => array(),
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008-2010, StatusNet, Inc.
- *
- * This program 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.
- *
- * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-
-/**
- * Utility class to wrap basic oEmbed lookups.
- *
- * Blacklisted hosts will use an alternate lookup method:
- * - Twitpic
- *
- * Whitelisted hosts will use known oEmbed API endpoints:
- * - Flickr, YFrog
- *
- * Sites that provide discovery links will use them directly; a bug
- * in use of discovery links with query strings is worked around.
- *
- * Others will fall back to oohembed (unless disabled).
- * The API endpoint can be configured or disabled through config
- * as 'oohembed'/'endpoint'.
- */
-class oEmbedHelper
-{
- protected static $apiMap = array(
- 'flickr.com' => 'http://www.flickr.com/services/oembed/',
- 'yfrog.com' => 'http://www.yfrog.com/api/oembed',
- 'youtube.com' => 'http://www.youtube.com/oembed',
- 'viddler.com' => 'http://lab.viddler.com/services/oembed/',
- 'qik.com' => 'http://qik.com/api/oembed.json',
- 'revision3.com' => 'http://revision3.com/api/oembed/',
- 'hulu.com' => 'http://www.hulu.com/api/oembed.json',
- 'vimeo.com' => 'http://www.vimeo.com/api/oembed.json',
- 'my.opera.com' => 'http://my.opera.com/service/oembed',
- );
- protected static $functionMap = array(
- 'twitpic.com' => 'oEmbedHelper::twitPic',
- );
-
- /**
- * Perform or fake an oEmbed lookup for the given resource.
- *
- * Some known hosts are whitelisted with API endpoints where we
- * know they exist but autodiscovery data isn't available.
- * If autodiscovery links are missing and we don't recognize the
- * host, we'll pass it to noembed.com's public service which
- * will either proxy or fake info on a lot of sites.
- *
- * A few hosts are blacklisted due to known problems with oohembed,
- * in which case we'll look up the info another way and return
- * equivalent data.
- *
- * Throws exceptions on failure.
- *
- * @param string $url
- * @param array $params
- * @return object
- */
- 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);
-
- // You can fiddle with the order of discovery -- either skipping
- // some types or re-ordering them.
-
- $order = common_config('oembed', 'order');
-
- foreach ($order as $method) {
-
- 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 (empty($api)) {
- // TRANS: Server exception thrown in oEmbed action if no API endpoint is available.
- throw new ServerException(_('No oEmbed API endpoint available.'));
- }
-
- 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);
- }
-
- /**
- * 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
- */
- static function discoverFromHTML($url, $body)
- {
- // 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,
- );
-
- $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 oEmbedHelper_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
- */
- static function getObjectFrom($api, $url, $params=array())
- {
- $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);
- }
-
- /**
- * Normalize oEmbed format.
- *
- * @param object $orig
- * @return object
- */
- static function normalize($orig)
- {
- $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';
- }
-
- if (isset($data->thumbnail_url)) {
- if (!isset($data->thumbnail_width)) {
- // !?!?!
- $data->thumbnail_width = common_config('thumbnail', 'width');
- $data->thumbnail_height = common_config('thumbnail', 'height');
- }
- }
-
- 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
-{
- public function __construct($message = "", $code = 0, $previous = null)
- {
- parent::__construct($message, $code);
- }
-}
-
-class oEmbedHelper_BadHtmlException extends oEmbedHelper_Exception
-{
- function __construct($previous=null)
- {
- return parent::__construct('Bad HTML in discovery data.', 0, $previous);
- }
-}
-
-class oEmbedHelper_DiscoveryException extends oEmbedHelper_Exception
-{
- function __construct($previous=null)
- {
- return parent::__construct('No oEmbed discovery data.', 0, $previous);
- }
-}
$m->connect('main/tagprofile', array('action' => 'tagprofile'));
- $m->connect('main/oembed',
- array('action' => 'oembed'));
-
$m->connect('main/xrds',
array('action' => 'publicxrds'));
--- /dev/null
+Depends on the oEmbed plugin (Oembed).
--- /dev/null
+Depends on the oEmbed plugin (Oembed)
--- /dev/null
+So far this is still in $config['site']['oembed'].
+
+oembed
+--------
+
+oEmbed endpoint for multimedia attachments (links in posts). Will also
+work as 'oohembed' for backwards compatibility.
+
+endpoint: oohembed endpoint using http://oohembed.com/ software. Defaults to
+ 'http://oohembed.com/oohembed/'.
+order: Array of methods to check for OEmbed data. Methods include 'built-in'
+ (use a built-in function to simulate oEmbed for some sites),
+ 'well-known' (use well-known public oEmbed endpoints),
+ 'discovery' (discover using <link> headers in HTML), 'service' (use
+ a third-party service, like oohembed or embed.ly. Default is
+ array('built-in', 'well-known', 'service', 'discovery'). Note that very
+ few sites implement oEmbed; 'discovery' is going to fail 99% of the
+ time.
--- /dev/null
+<?php
+
+class OembedPlugin extends Plugin
+{
+ public function onCheckSchema()
+ {
+ $schema = Schema::get();
+ $schema->ensureTable('file_oembed', File_oembed::schemaDef());
+ return true;
+ }
+
+ public function onRouterInitialized(URLMapper $m)
+ {
+ $m->connect('main/oembed', array('action' => 'oembed'));
+ }
+
+ public function onEndShowHeadElements(Action $action)
+ {
+ switch ($action->getActionName()) {
+ case 'attachment':
+ $action->element('link',array('rel'=>'alternate',
+ 'type'=>'application/json+oembed',
+ 'href'=>common_local_url(
+ 'oembed',
+ array(),
+ array('format'=>'json', 'url'=>
+ common_local_url('attachment',
+ array('attachment' => $action->attachment->id)))),
+ 'title'=>'oEmbed'),null);
+ $action->element('link',array('rel'=>'alternate',
+ 'type'=>'text/xml+oembed',
+ 'href'=>common_local_url(
+ 'oembed',
+ array(),
+ array('format'=>'xml','url'=>
+ common_local_url('attachment',
+ array('attachment' => $action->attachment->id)))),
+ 'title'=>'oEmbed'),null);
+ break;
+ case 'shownotice':
+ $this->element('link',array('rel'=>'alternate',
+ 'type'=>'application/json+oembed',
+ 'href'=>common_local_url(
+ 'oembed',
+ array(),
+ array('format'=>'json','url'=>$this->notice->getUrl())),
+ 'title'=>'oEmbed'),null);
+ $this->element('link',array('rel'=>'alternate',
+ 'type'=>'text/xml+oembed',
+ 'href'=>common_local_url(
+ 'oembed',
+ array(),
+ array('format'=>'xml','url'=>$this->notice->getUrl())),
+ 'title'=>'oEmbed'),null);
+ break;
+ }
+
+ return true;
+ }
+
+ /**
+ * Save embedding information for a File, if applicable.
+ *
+ * Normally this event is called through File::saveNew()
+ *
+ * @param File $file The newly inserted File object.
+ * @param array $redir_data lookup data eg from File_redirection::where()
+ * @param string $given_url
+ *
+ * @return boolean success
+ */
+ public function onEndFileSaveNew(File $file, array $redir_data, $given_url)
+ {
+ $fo = File_oembed::getKV('file_id', $file->id);
+ if ($fo instanceof File_oembed) {
+ common_log(LOG_WARNING, "Strangely, a File_oembed object exists for new file $file_id", __FILE__);
+ return true;
+ }
+
+ if (isset($redir_data['oembed']['json'])
+ && !empty($redir_data['oembed']['json'])) {
+ File_oembed::saveNew($redir_data['oembed']['json'], $file->id);
+ } elseif (isset($redir_data['type'])
+ && (('text/html' === substr($redir_data['type'], 0, 9)
+ || 'application/xhtml+xml' === substr($redir_data['type'], 0, 21)))) {
+
+ try {
+ $oembed_data = File_oembed::_getOembed($given_url);
+ if ($oembed_data === false) {
+ throw new Exception('Did not get oEmbed data from URL');
+ }
+ } catch (Exception $e) {
+ return true;
+ }
+
+ File_oembed::saveNew($oembed_data, $file->id);
+ }
+ return true;
+ }
+
+ public function onEndShowAttachmentLink(HTMLOutputter $out, File $file)
+ {
+ $oembed = File_oembed::getKV('file_id', $file->id);
+ if (empty($oembed->author_name) && empty($oembed->provider)) {
+ return true;
+ }
+ $out->elementStart('div', array('id'=>'oembed_info', 'class'=>'entry-content'));
+ if (!empty($oembed->author_name)) {
+ $out->elementStart('div', 'fn vcard author');
+ if (empty($oembed->author_url)) {
+ $out->text($oembed->author_name);
+ } else {
+ $out->element('a', array('href' => $oembed->author_url,
+ 'class' => 'url'),
+ $oembed->author_name);
+ }
+ }
+ if (!empty($oembed->provider)) {
+ $out->elementStart('div', 'fn vcard');
+ if (empty($oembed->provider_url)) {
+ $out->text($oembed->provider);
+ } else {
+ $out->element('a', array('href' => $oembed->provider_url,
+ 'class' => 'url'),
+ $oembed->provider);
+ }
+ }
+ $out->elementEnd('div');
+ }
+
+ public function onFileEnclosureMetadata(File $file, &$enclosure)
+ {
+ // Never treat generic HTML links as an enclosure type!
+ // But if we have oEmbed info, we'll consider it golden.
+ $oembed = File_oembed::getKV('file_id', $file->id);
+ if (!$oembed instanceof File_oembed || !in_array($oembed->type, array('photo', 'video'))) {
+ return true;
+ }
+
+ foreach (array('mimetype', 'url', 'title', 'modified') as $key) {
+ if (!empty($oembed->{$key})) {
+ $enclosure->{$key} = $oembed->{$key};
+ }
+ }
+ return true;
+ }
+
+ public function onStartShowAttachmentRepresentation(HTMLOutputter $out, File $file)
+ {
+ $oembed = File_oembed::getKV('file_id', $file->id);
+ if (empty($oembed->type)) {
+ return true;
+ }
+ switch ($oembed->type) {
+ case 'rich':
+ case 'video':
+ case 'link':
+ if (!empty($oembed->html)) {
+ require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
+ $config = array(
+ 'safe'=>1,
+ 'elements'=>'*+object+embed');
+ $out->raw(htmLawed($oembed->html,$config));
+ }
+ break;
+
+ case 'photo':
+ $out->element('img', array('src' => $oembed->url, 'width' => $oembed->width, 'height' => $oembed->height, 'alt' => 'alt'));
+ break;
+
+ default:
+ Event::handle('ShowUnsupportedAttachmentRepresentation', array($out, $file));
+ }
+ }
+
+ public function onPluginVersion(array &$versions)
+ {
+ $versions[] = array('name' => 'Oembed',
+ 'version' => GNUSOCIAL_VERSION,
+ 'author' => 'Mikael Nordfeldth',
+ 'homepage' => 'http://gnu.io/',
+ 'description' =>
+ // TRANS: Plugin description.
+ _m('Plugin for using and representing Oembed data.'));
+ return true;
+ }
+}
--- /dev/null
+It's really called oEmbed.
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * oEmbed data action for /main/oembed(.xml|.json) requests
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+if (!defined('GNUSOCIAL')) { exit(1); }
+
+/**
+ * Oembed provider implementation
+ *
+ * This class handles all /main/oembed(.xml|.json)/ requests.
+ *
+ * @category oEmbed
+ * @package GNUsocial
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Mikael Nordfeldth <mmn@hethane.se>
+ * @copyright 2008 StatusNet, Inc.
+ * @copyright 2014 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class OembedAction extends Action
+{
+ protected function handle()
+ {
+ parent::handle();
+
+ $url = $this->trimmed('url');
+ if (substr(strtolower($url),0,strlen(common_root_url())) == strtolower(common_root_url())) {
+ $path = substr($url,strlen(common_root_url()));
+
+ $r = Router::get();
+
+ $proxy_args = $r->map($path);
+ if (!$proxy_args) {
+ // TRANS: Server error displayed in oEmbed action when path not found.
+ // TRANS: %s is a path.
+ $this->serverError(sprintf(_('"%s" not found.'),$path), 404);
+ }
+
+ $oembed=array();
+ $oembed['version']='1.0';
+ $oembed['provider_name']=common_config('site', 'name');
+ $oembed['provider_url']=common_root_url();
+
+ switch ($proxy_args['action']) {
+ case 'shownotice':
+ $oembed['type']='link';
+ $id = $proxy_args['notice'];
+ $notice = Notice::getKV($id);
+ if(empty($notice)){
+ // TRANS: Server error displayed in oEmbed action when notice not found.
+ // TRANS: %s is a notice.
+ $this->serverError(sprintf(_("Notice %s not found."),$id), 404);
+ }
+ $profile = $notice->getProfile();
+ if (empty($profile)) {
+ // TRANS: Server error displayed in oEmbed action when notice has not profile.
+ $this->serverError(_('Notice has no profile.'), 500);
+ }
+ $authorname = $profile->getFancyName();
+ // TRANS: oEmbed title. %1$s is the author name, %2$s is the creation date.
+ $oembed['title'] = sprintf(_('%1$s\'s status on %2$s'),
+ $authorname,
+ common_exact_date($notice->created));
+ $oembed['author_name']=$authorname;
+ $oembed['author_url']=$profile->profileurl;
+ $oembed['url']=$notice->getUrl();
+ $oembed['html']=$notice->rendered;
+ break;
+
+ case 'attachment':
+ $id = $proxy_args['attachment'];
+ $attachment = File::getKV($id);
+ if(empty($attachment)){
+ // TRANS: Server error displayed in oEmbed action when attachment not found.
+ // TRANS: %d is an attachment ID.
+ $this->serverError(sprintf(_('Attachment %s not found.'),$id), 404);
+ }
+ if (empty($attachment->filename) && $file_oembed = File_oembed::getKV('file_id', $attachment->id)) {
+ // Proxy the existing oembed information
+ $oembed['type']=$file_oembed->type;
+ $oembed['provider']=$file_oembed->provider;
+ $oembed['provider_url']=$file_oembed->provider_url;
+ $oembed['width']=$file_oembed->width;
+ $oembed['height']=$file_oembed->height;
+ $oembed['html']=$file_oembed->html;
+ $oembed['title']=$file_oembed->title;
+ $oembed['author_name']=$file_oembed->author_name;
+ $oembed['author_url']=$file_oembed->author_url;
+ $oembed['url']=$file_oembed->getUrl();
+ } elseif (substr($attachment->mimetype,0,strlen('image/'))==='image/') {
+ $oembed['type']='photo';
+ if ($attachment->filename) {
+ $filepath = File::path($attachment->filename);
+ $gis = @getimagesize($filepath);
+ if ($gis) {
+ $oembed['width'] = $gis[0];
+ $oembed['height'] = $gis[1];
+ } else {
+ // TODO Either throw an error or find a fallback?
+ }
+ }
+ $oembed['url']=$attachment->getUrl();
+ try {
+ $thumb = $attachment->getThumbnail();
+ $oembed['thumbnail_url'] = $thumb->getUrl();
+ $oembed['thumbnail_width'] = $thumb->width;
+ $oembed['thumbnail_height'] = $thumb->height;
+ unset($thumb);
+ } catch (UnsupportedMediaException $e) {
+ // No thumbnail data available
+ }
+ } else {
+ $oembed['type']='link';
+ $oembed['url']=common_local_url('attachment',
+ array('attachment' => $attachment->id));
+ }
+ if ($attachment->title) {
+ $oembed['title']=$attachment->title;
+ }
+ break;
+ default:
+ // TRANS: Server error displayed in oEmbed request when a path is not supported.
+ // TRANS: %s is a path.
+ $this->serverError(sprintf(_('"%s" not supported for oembed requests.'),$path), 501);
+ }
+ switch ($this->trimmed('format')) {
+ case 'xml':
+ $this->init_document('xml');
+ $this->elementStart('oembed');
+ foreach(array(
+ 'version', 'type', 'provider_name',
+ 'provider_url', 'title', 'author_name',
+ 'author_url', 'url', 'html', 'width',
+ 'height', 'cache_age', 'thumbnail_url',
+ 'thumbnail_width', 'thumbnail_height',
+ ) as $key) {
+ if (isset($oembed[$key]) && $oembed[$key]!='') {
+ $this->element($key, null, $oembed[$key]);
+ }
+ }
+ $this->elementEnd('oembed');
+ $this->end_document('xml');
+ break;
+
+ case 'json':
+ case null:
+ $this->init_document('json');
+ $this->raw(json_encode($oembed));
+ $this->end_document('json');
+ break;
+ default:
+ // TRANS: Error message displaying attachments. %s is a raw MIME type (eg 'image/png')
+ $this->serverError(sprintf(_('Content type %s not supported.'), $apidata['content-type']), 501);
+ }
+ } else {
+ // TRANS: Error message displaying attachments. %s is the site's base URL.
+ $this->serverError(sprintf(_('Only %s URLs over plain HTTP please.'), common_root_url()), 404);
+ }
+ }
+
+ public function init_document($type)
+ {
+ switch ($type) {
+ case 'xml':
+ header('Content-Type: application/xml; charset=utf-8');
+ $this->startXML();
+ break;
+ case 'json':
+ header('Content-Type: application/json; charset=utf-8');
+
+ // Check for JSONP callback
+ $callback = $this->arg('callback');
+ if ($callback) {
+ print $callback . '(';
+ }
+ break;
+ default:
+ // TRANS: Server error displayed in oEmbed action when request specifies an unsupported data format.
+ $this->serverError(_('Not a supported data format.'), 501);
+ break;
+ }
+ }
+
+ public function end_document($type)
+ {
+ switch ($type) {
+ case 'xml':
+ $this->endXML();
+ break;
+ case 'json':
+ // Check for JSONP callback
+ $callback = $this->arg('callback');
+ if ($callback) {
+ print ')';
+ }
+ break;
+ default:
+ // TRANS: Server error displayed in oEmbed action when request specifies an unsupported data format.
+ $this->serverError(_('Not a supported data format.'), 501);
+ break;
+ }
+ return;
+ }
+
+ /**
+ * Is this action read-only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ return true;
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+if (!defined('GNUSOCIAL')) { exit(1); }
+
+/**
+ * Table Definition for file_oembed
+ */
+
+class File_oembed extends Managed_DataObject
+{
+ public $__table = 'file_oembed'; // table name
+ public $file_id; // int(4) primary_key not_null
+ public $version; // varchar(20)
+ public $type; // varchar(20)
+ public $mimetype; // varchar(50)
+ public $provider; // varchar(50)
+ public $provider_url; // varchar(255)
+ public $width; // int(4)
+ public $height; // int(4)
+ public $html; // text()
+ public $title; // varchar(255)
+ public $author_name; // varchar(50)
+ public $author_url; // varchar(255)
+ public $url; // varchar(255)
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'file_id' => array('type' => 'int', 'not null' => true, 'description' => 'oEmbed for that URL/file'),
+ 'version' => array('type' => 'varchar', 'length' => 20, 'description' => 'oEmbed spec. version'),
+ 'type' => array('type' => 'varchar', 'length' => 20, 'description' => 'oEmbed type: photo, video, link, rich'),
+ 'mimetype' => array('type' => 'varchar', 'length' => 50, 'description' => 'mime type of resource'),
+ 'provider' => array('type' => 'varchar', 'length' => 50, 'description' => 'name of this oEmbed provider'),
+ 'provider_url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of this oEmbed provider'),
+ 'width' => array('type' => 'int', 'description' => 'width of oEmbed resource when available'),
+ 'height' => array('type' => 'int', 'description' => 'height of oEmbed resource when available'),
+ 'html' => array('type' => 'text', 'description' => 'html representation of this oEmbed resource when applicable'),
+ 'title' => array('type' => 'varchar', 'length' => 255, 'description' => 'title of oEmbed resource when available'),
+ 'author_name' => array('type' => 'varchar', 'length' => 50, 'description' => 'author name for this oEmbed resource'),
+ 'author_url' => array('type' => 'varchar', 'length' => 255, 'description' => 'author URL for this oEmbed resource'),
+ 'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL for this oEmbed resource when applicable (photo, link)'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('file_id'),
+ 'foreign keys' => array(
+ 'file_oembed_file_id_fkey' => array('file', array('file_id' => 'id')),
+ ),
+ );
+ }
+
+ function _getOembed($url) {
+ $parameters = array(
+ 'maxwidth' => common_config('thumbnail', 'width'),
+ 'maxheight' => common_config('thumbnail', 'height'),
+ );
+ try {
+ return oEmbedHelper::getObject($url, $parameters);
+ } catch (Exception $e) {
+ common_log(LOG_INFO, "Error during oembed lookup for $url - " . $e->getMessage());
+ return false;
+ }
+ }
+
+ public function getUrl()
+ {
+ return $this->url;
+ }
+
+ /**
+ * Save embedding info for a new file.
+ *
+ * @param object $data Services_oEmbed_Object_*
+ * @param int $file_id
+ */
+ public static function saveNew($data, $file_id) {
+ $file_oembed = new File_oembed;
+ $file_oembed->file_id = $file_id;
+ if (!isset($data->version)) {
+ common_debug('DEBUGGING oEmbed: data->version undefined in variable $data: '.var_export($data, true));
+ }
+ $file_oembed->version = $data->version;
+ $file_oembed->type = $data->type;
+ if (!empty($data->provider_name)) $file_oembed->provider = $data->provider_name;
+ if (!empty($data->provider)) $file_oembed->provider = $data->provider;
+ if (!empty($data->provider_url)) $file_oembed->provider_url = $data->provider_url;
+ if (!empty($data->width)) $file_oembed->width = intval($data->width);
+ if (!empty($data->height)) $file_oembed->height = intval($data->height);
+ if (!empty($data->html)) $file_oembed->html = $data->html;
+ if (!empty($data->title)) $file_oembed->title = $data->title;
+ if (!empty($data->author_name)) $file_oembed->author_name = $data->author_name;
+ if (!empty($data->author_url)) $file_oembed->author_url = $data->author_url;
+ if (!empty($data->url)){
+ $file_oembed->url = $data->url;
+ $given_url = File_redirection::_canonUrl($file_oembed->url);
+ if (! empty($given_url)){
+ $file = File::getKV('url', $given_url);
+ if ($file instanceof File) {
+ $file_oembed->mimetype = $file->mimetype;
+ } else {
+ $file_redir = File_redirection::getKV('url', $given_url);
+ if (empty($file_redir)) {
+ $redir_data = File_redirection::where($given_url);
+ $file_oembed->mimetype = $redir_data['type'];
+ } else {
+ $file_id = $file_redir->file_id;
+ }
+ }
+ }
+ }
+ $file_oembed->insert();
+ if (!empty($data->thumbnail_url) || ($data->type == 'photo')) {
+ $ft = File_thumbnail::getKV('file_id', $file_id);
+ if ($ft instanceof File_thumbnail) {
+ common_log(LOG_WARNING, "Strangely, a File_thumbnail object exists for new file $file_id",
+ __FILE__);
+ } else {
+ File_thumbnail::saveNew($data, $file_id);
+ }
+ }
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008-2010, StatusNet, Inc.
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+
+/**
+ * Utility class to wrap basic oEmbed lookups.
+ *
+ * Blacklisted hosts will use an alternate lookup method:
+ * - Twitpic
+ *
+ * Whitelisted hosts will use known oEmbed API endpoints:
+ * - Flickr, YFrog
+ *
+ * Sites that provide discovery links will use them directly; a bug
+ * in use of discovery links with query strings is worked around.
+ *
+ * Others will fall back to oohembed (unless disabled).
+ * The API endpoint can be configured or disabled through config
+ * as 'oohembed'/'endpoint'.
+ */
+class oEmbedHelper
+{
+ protected static $apiMap = array(
+ 'flickr.com' => 'http://www.flickr.com/services/oembed/',
+ 'yfrog.com' => 'http://www.yfrog.com/api/oembed',
+ 'youtube.com' => 'http://www.youtube.com/oembed',
+ 'viddler.com' => 'http://lab.viddler.com/services/oembed/',
+ 'qik.com' => 'http://qik.com/api/oembed.json',
+ 'revision3.com' => 'http://revision3.com/api/oembed/',
+ 'hulu.com' => 'http://www.hulu.com/api/oembed.json',
+ 'vimeo.com' => 'http://www.vimeo.com/api/oembed.json',
+ 'my.opera.com' => 'http://my.opera.com/service/oembed',
+ );
+ protected static $functionMap = array(
+ 'twitpic.com' => 'oEmbedHelper::twitPic',
+ );
+
+ /**
+ * Perform or fake an oEmbed lookup for the given resource.
+ *
+ * Some known hosts are whitelisted with API endpoints where we
+ * know they exist but autodiscovery data isn't available.
+ * If autodiscovery links are missing and we don't recognize the
+ * host, we'll pass it to noembed.com's public service which
+ * will either proxy or fake info on a lot of sites.
+ *
+ * A few hosts are blacklisted due to known problems with oohembed,
+ * in which case we'll look up the info another way and return
+ * equivalent data.
+ *
+ * Throws exceptions on failure.
+ *
+ * @param string $url
+ * @param array $params
+ * @return object
+ */
+ 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);
+
+ // You can fiddle with the order of discovery -- either skipping
+ // some types or re-ordering them.
+
+ $order = common_config('oembed', 'order');
+
+ foreach ($order as $method) {
+
+ 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 (empty($api)) {
+ // TRANS: Server exception thrown in oEmbed action if no API endpoint is available.
+ throw new ServerException(_('No oEmbed API endpoint available.'));
+ }
+
+ 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);
+ }
+
+ /**
+ * 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
+ */
+ static function discoverFromHTML($url, $body)
+ {
+ // 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,
+ );
+
+ $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 oEmbedHelper_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
+ */
+ static function getObjectFrom($api, $url, $params=array())
+ {
+ $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);
+ }
+
+ /**
+ * Normalize oEmbed format.
+ *
+ * @param object $orig
+ * @return object
+ */
+ static function normalize($orig)
+ {
+ $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';
+ }
+
+ if (isset($data->thumbnail_url)) {
+ if (!isset($data->thumbnail_width)) {
+ // !?!?!
+ $data->thumbnail_width = common_config('thumbnail', 'width');
+ $data->thumbnail_height = common_config('thumbnail', 'height');
+ }
+ }
+
+ 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
+{
+ public function __construct($message = "", $code = 0, $previous = null)
+ {
+ parent::__construct($message, $code);
+ }
+}
+
+class oEmbedHelper_BadHtmlException extends oEmbedHelper_Exception
+{
+ function __construct($previous=null)
+ {
+ return parent::__construct('Bad HTML in discovery data.', 0, $previous);
+ }
+}
+
+class oEmbedHelper_DiscoveryException extends oEmbedHelper_Exception
+{
+ function __construct($previous=null)
+ {
+ return parent::__construct('No oEmbed discovery data.', 0, $previous);
+ }
+}
--- /dev/null
+#!/usr/bin/env php
+<?php
+/*
+ * StatusNet - a distributed open-source microblogging tool
+ * Copyright (C) 2010 StatusNet, Inc.
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..'));
+
+$longoptions = array('dry-run');
+
+$helptext = <<<END_OF_USERROLE_HELP
+fixup_files.php [options]
+Patches up file entries with corrupted types and titles (the "h bug").
+
+ --dry-run look but don't touch
+
+END_OF_USERROLE_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+$dry = have_option('dry-run');
+
+$f = new File();
+$f->title = 'h';
+$f->mimetype = 'h';
+$f->size = 0;
+$f->protected = 0;
+$f->find();
+echo "Found $f->N bad items:\n";
+
+while ($f->fetch()) {
+ echo "$f->id $f->url";
+
+ $data = File_redirection::lookupWhere($f->url);
+ if ($dry) {
+ if (is_array($data)) {
+ echo " (unchanged)\n";
+ } else {
+ echo " (unchanged, but embedding lookup failed)\n";
+ }
+ } else {
+ // NULL out the mime/title/size/protected fields
+ $sql = sprintf("UPDATE file " .
+ "SET mimetype=null,title=null,size=null,protected=null " .
+ "WHERE id=%d",
+ $f->id);
+ $f->query($sql);
+ $f->decache();
+
+ if (is_array($data)) {
+ Event::handle('EndFileSaveNew', array($f, $data, $f->url));
+ echo " (ok)\n";
+ } else {
+ echo " (ok, but embedding lookup failed)\n";
+ }
+ }
+}
+
+echo "done.\n";
+
--- /dev/null
+<?php
+
+if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+ print "This script must be run from the command line\n";
+ exit();
+}
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..'));
+define('GNUSOCIAL', true);
+define('STATUSNET', true); // compatibility
+
+require_once INSTALLDIR . '/lib/common.php';
+
+class oEmbedTest extends PHPUnit_Framework_TestCase
+{
+
+ public function setup()
+ {
+ $this->old_ohembed = common_config('ohembed', 'endpoint');
+ }
+
+ public function tearDown()
+ {
+ $GLOBALS['config']['oembed']['endpoint'] = $this->old_ohembed;
+ }
+
+ /**
+ * Test with ohembed DISABLED.
+ *
+ * @dataProvider discoverableSources
+ */
+ public function testoEmbed($url, $expectedType)
+ {
+ $GLOBALS['config']['oembed']['endpoint'] = false;
+ $this->_doTest($url, $expectedType);
+ }
+
+ /**
+ * Test with oohembed ENABLED.
+ *
+ * @dataProvider fallbackSources
+ */
+ public function testnoEmbed($url, $expectedType)
+ {
+ $GLOBALS['config']['oembed']['endpoint'] = $this->_endpoint();
+ $this->_doTest($url, $expectedType);
+ }
+
+ /**
+ * Get default oembed endpoint.
+ *
+ * @return string
+ */
+ function _endpoint()
+ {
+ $default = array();
+ $_server = 'localhost'; $_path = '';
+ require INSTALLDIR . '/lib/default.php';
+ return $default['oembed']['endpoint'];
+ }
+
+ /**
+ * Actually run an individual test.
+ *
+ * @param string $url
+ * @param string $expectedType
+ */
+ function _doTest($url, $expectedType)
+ {
+ try {
+ $data = oEmbedHelper::getObject($url);
+ $this->assertEquals($expectedType, $data->type);
+ if ($data->type == 'photo') {
+ $this->assertTrue(!empty($data->url), 'Photo must have a URL.');
+ $this->assertTrue(!empty($data->width), 'Photo must have a width.');
+ $this->assertTrue(!empty($data->height), 'Photo must have a height.');
+ } else if ($data->type == 'video') {
+ $this->assertTrue(!empty($data->html), 'Video must have embedding HTML.');
+ $this->assertTrue(!empty($data->thumbnail_url), 'Video should have a thumbnail.');
+ }
+ if (!empty($data->thumbnail_url)) {
+ $this->assertTrue(!empty($data->thumbnail_width), 'Thumbnail must list a width.');
+ $this->assertTrue(!empty($data->thumbnail_height), 'Thumbnail must list a height.');
+ }
+ } catch (Exception $e) {
+ if ($expectedType == 'none') {
+ $this->assertEquals($expectedType, 'none', 'Should not have data for this URL.');
+ } else {
+ throw $e;
+ }
+ }
+ }
+
+ /**
+ * Sample oEmbed targets for sites we know ourselves...
+ * @return array
+ */
+ static public function knownSources()
+ {
+ $sources = array(
+ array('http://www.flickr.com/photos/brionv/5172500179/', 'photo'),
+ array('http://yfrog.com/fy42747177j', 'photo'),
+ array('http://twitpic.com/36adw6', 'photo'),
+ );
+ return $sources;
+ }
+
+ /**
+ * Sample oEmbed targets that can be found via discovery.
+ * Includes also knownSources() output.
+ *
+ * @return array
+ */
+ static public function discoverableSources()
+ {
+ $sources = array(
+
+ array('http://www.youtube.com/watch?v=eUgLR232Cnw', 'video'),
+ array('http://vimeo.com/9283184', 'video'),
+
+ // Will fail discovery:
+ array('http://leuksman.com/log/2010/10/29/statusnet-0-9-6-release/', 'none'),
+ );
+ return array_merge(self::knownSources(), $sources);
+ }
+
+ /**
+ * Sample oEmbed targets that can be found via noembed.com.
+ * Includes also discoverableSources() output.
+ *
+ * @return array
+ */
+ static public function fallbackSources()
+ {
+
+ $sources = array(
+ array('https://github.com/git/git/commit/85e9c7e1d42849c5c3084a9da748608468310c0e', 'Github Commit'), // @fixme in future there may be a native provider -- will change to 'photo'
+ );
+
+ $sources = array();
+
+ return array_merge(self::discoverableSources(), $sources);
+ }
+}
+++ /dev/null
-#!/usr/bin/env php
-<?php
-/*
- * StatusNet - a distributed open-source microblogging tool
- * Copyright (C) 2010 StatusNet, Inc.
- *
- * This program 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.
- *
- * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-
-$longoptions = array('dry-run');
-
-$helptext = <<<END_OF_USERROLE_HELP
-fixup_files.php [options]
-Patches up file entries with corrupted types and titles (the "h bug").
-
- --dry-run look but don't touch
-
-END_OF_USERROLE_HELP;
-
-require_once INSTALLDIR.'/scripts/commandline.inc';
-
-$dry = have_option('dry-run');
-
-$f = new File();
-$f->title = 'h';
-$f->mimetype = 'h';
-$f->size = 0;
-$f->protected = 0;
-$f->find();
-echo "Found $f->N bad items:\n";
-
-while ($f->fetch()) {
- echo "$f->id $f->url";
-
- $data = File_redirection::lookupWhere($f->url);
- if ($dry) {
- if (is_array($data)) {
- echo " (unchanged)\n";
- } else {
- echo " (unchanged, but embedding lookup failed)\n";
- }
- } else {
- // NULL out the mime/title/size/protected fields
- $sql = sprintf("UPDATE file " .
- "SET mimetype=null,title=null,size=null,protected=null " .
- "WHERE id=%d",
- $f->id);
- $f->query($sql);
- $f->decache();
-
- if (is_array($data)) {
- if ($f->saveOembed($data, $f->url)) {
- echo " (ok)\n";
- } else {
- echo " (ok, no embedding data)\n";
- }
- } else {
- echo " (ok, but embedding lookup failed)\n";
- }
- }
-}
-
-echo "done.\n";
-
+++ /dev/null
-<?php
-
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
- print "This script must be run from the command line\n";
- exit();
-}
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('GNUSOCIAL', true);
-define('STATUSNET', true); // compatibility
-
-require_once INSTALLDIR . '/lib/common.php';
-
-class oEmbedTest extends PHPUnit_Framework_TestCase
-{
-
- public function setup()
- {
- $this->old_ohembed = common_config('ohembed', 'endpoint');
- }
-
- public function tearDown()
- {
- $GLOBALS['config']['oembed']['endpoint'] = $this->old_ohembed;
- }
-
- /**
- * Test with ohembed DISABLED.
- *
- * @dataProvider discoverableSources
- */
- public function testoEmbed($url, $expectedType)
- {
- $GLOBALS['config']['oembed']['endpoint'] = false;
- $this->_doTest($url, $expectedType);
- }
-
- /**
- * Test with oohembed ENABLED.
- *
- * @dataProvider fallbackSources
- */
- public function testnoEmbed($url, $expectedType)
- {
- $GLOBALS['config']['oembed']['endpoint'] = $this->_endpoint();
- $this->_doTest($url, $expectedType);
- }
-
- /**
- * Get default oembed endpoint.
- *
- * @return string
- */
- function _endpoint()
- {
- $default = array();
- $_server = 'localhost'; $_path = '';
- require INSTALLDIR . '/lib/default.php';
- return $default['oembed']['endpoint'];
- }
-
- /**
- * Actually run an individual test.
- *
- * @param string $url
- * @param string $expectedType
- */
- function _doTest($url, $expectedType)
- {
- try {
- $data = oEmbedHelper::getObject($url);
- $this->assertEquals($expectedType, $data->type);
- if ($data->type == 'photo') {
- $this->assertTrue(!empty($data->url), 'Photo must have a URL.');
- $this->assertTrue(!empty($data->width), 'Photo must have a width.');
- $this->assertTrue(!empty($data->height), 'Photo must have a height.');
- } else if ($data->type == 'video') {
- $this->assertTrue(!empty($data->html), 'Video must have embedding HTML.');
- $this->assertTrue(!empty($data->thumbnail_url), 'Video should have a thumbnail.');
- }
- if (!empty($data->thumbnail_url)) {
- $this->assertTrue(!empty($data->thumbnail_width), 'Thumbnail must list a width.');
- $this->assertTrue(!empty($data->thumbnail_height), 'Thumbnail must list a height.');
- }
- } catch (Exception $e) {
- if ($expectedType == 'none') {
- $this->assertEquals($expectedType, 'none', 'Should not have data for this URL.');
- } else {
- throw $e;
- }
- }
- }
-
- /**
- * Sample oEmbed targets for sites we know ourselves...
- * @return array
- */
- static public function knownSources()
- {
- $sources = array(
- array('http://www.flickr.com/photos/brionv/5172500179/', 'photo'),
- array('http://yfrog.com/fy42747177j', 'photo'),
- array('http://twitpic.com/36adw6', 'photo'),
- );
- return $sources;
- }
-
- /**
- * Sample oEmbed targets that can be found via discovery.
- * Includes also knownSources() output.
- *
- * @return array
- */
- static public function discoverableSources()
- {
- $sources = array(
-
- array('http://www.youtube.com/watch?v=eUgLR232Cnw', 'video'),
- array('http://vimeo.com/9283184', 'video'),
-
- // Will fail discovery:
- array('http://leuksman.com/log/2010/10/29/statusnet-0-9-6-release/', 'none'),
- );
- return array_merge(self::knownSources(), $sources);
- }
-
- /**
- * Sample oEmbed targets that can be found via noembed.com.
- * Includes also discoverableSources() output.
- *
- * @return array
- */
- static public function fallbackSources()
- {
-
- $sources = array(
- array('https://github.com/git/git/commit/85e9c7e1d42849c5c3084a9da748608468310c0e', 'Github Commit'), // @fixme in future there may be a native provider -- will change to 'photo'
- );
-
- $sources = array();
-
- return array_merge(self::discoverableSources(), $sources);
- }
-}