From b7aca97d3e5c371dbaddf87456f4537bf3c11c14 Mon Sep 17 00:00:00 2001 From: Ian Denhardt Date: Tue, 15 Mar 2011 23:51:07 -0400 Subject: [PATCH] Video plugin. still rough, but federation works. --- .../GNUsocialVideo/GNUsocialVideoPlugin.php | 96 ++++++++++++++- plugins/GNUsocialVideo/Video.php | 112 ++++++++++++++++++ plugins/GNUsocialVideo/actions/postvideo.php | 53 +++++---- plugins/GNUsocialVideo/showvideo.php | 67 +++++++++++ plugins/GNUsocialVideo/videoform.php | 61 ++++++++++ 5 files changed, 363 insertions(+), 26 deletions(-) create mode 100644 plugins/GNUsocialVideo/Video.php create mode 100644 plugins/GNUsocialVideo/showvideo.php create mode 100644 plugins/GNUsocialVideo/videoform.php diff --git a/plugins/GNUsocialVideo/GNUsocialVideoPlugin.php b/plugins/GNUsocialVideo/GNUsocialVideoPlugin.php index 5e9a6f85e9..79f79c50d2 100644 --- a/plugins/GNUsocialVideo/GNUsocialVideoPlugin.php +++ b/plugins/GNUsocialVideo/GNUsocialVideoPlugin.php @@ -30,8 +30,18 @@ if (!defined('STATUSNET')) { exit(1); } -class GNUsocialVideoPlugin extends Plugin +class GNUsocialVideoPlugin extends MicroAppPlugin { + + function onCheckSchema() + { + $schema = Schema::get(); + + $schema->ensureTable('video', Video::schemaDef()); + + return true; + } + function onAutoload($cls) { $dir = dirname(__FILE__); @@ -40,6 +50,15 @@ class GNUsocialVideoPlugin extends Plugin case 'PostvideoAction': include_once $dir . '/actions/postvideo.php'; break; + case 'Video': + include_once $dir . '/Video.php'; + break; + case 'VideoForm': + include_once $dir . '/videoform.php'; + break; + case 'ShowvideoAction': + include_once $dir . '/showvideo.php'; + break; default: break; } @@ -49,6 +68,81 @@ class GNUsocialVideoPlugin extends Plugin function onRouterInitialized($m) { $m->connect('main/postvideo', array('action' => 'postvideo')); + $m->connect('showvideo/:id', array('action' => 'showvideo')); return true; } + + function entryForm($out) + { + return new VideoForm($out); + } + + function appTitle() + { + return _('video'); + } + + function tag() + { + return 'GNUsocialVideo'; + } + + function types() + { + return array(Video::OBJECT_TYPE); + } + + function saveNoticeFromActivity($activity, $actor, $options=array()) + { + if(count($activity->objects) != 1) { + throw new Exception('Too many activity objects.'); + } + + $videoObj = $activity->objects[0]; + + if ($videoObj->type != Video::OBJECT_TYPE) { + throw new Exception('Wrong type for object.'); + } + + // For now we read straight from the xml tree, no other way to get this information. + // When there's a better API for this, we should change to it. + $uri = ActivityUtils::getLink($activity->entry, 'enclosure'); + + $options['object_type'] = Video::OBJECT_TYPE; + + Video::saveNew($actor, $uri, $options); + + } + + function activityObjectFromNotice($notice) + { + $object = new ActivityObject(); + $object->id = $notice->uri; + $object->type = Video::OBJECT_TYPE; + $object->title = $notice->content; + $object->summary = $notice->content; + $object->link = $notice->bestUrl(); + + $vid = Video::getByNotice($notice); + + if ($vid) { + $object->extra[] = array('link', array('rel' => 'enclosure', 'href' => $vid->url), array()); + } + + return $object; + + } + + function showNotice($notice, $out) + { + $vid = Video::getByNotice($notice); + if ($vid) { + $out->element('video', array('src' => $vid->url)); + } + } + + function deleteRelated($notice) + { + exit(1); // TODO: implement + } } diff --git a/plugins/GNUsocialVideo/Video.php b/plugins/GNUsocialVideo/Video.php new file mode 100644 index 0000000000..40c74e08c8 --- /dev/null +++ b/plugins/GNUsocialVideo/Video.php @@ -0,0 +1,112 @@ +. + * + * @package GNU Social + * @author Ian Denhardt + * @copyright 2011 Free Software Foundation, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + */ + +if(!defined('STATUSNET')){ + exit(1); +} + +/** + * Data class for videos. + */ + +class Video extends Managed_DataObject +{ + const OBJECT_TYPE = 'http://activitystrea.ms/schema/1.0/video'; + + public $__table = 'video'; // table name + public $id; // char (36) // UUID + public $uri; // varchar (255) // This is the corresponding notice's uri. + public $url; // varchar (255) + public $profile_id; // int + + public function staticGet($k, $v=null) + { + return Memcached_DataObject::staticGet('Video', $k, $v); + } + + public function getByNotice($notice) + { + return self::staticGet('uri', $notice->uri); + } + + public function getNotice() + { + return Notice::staticGet('uri', $this->uri); + } + + public static function schemaDef() + { + return array( + 'description' => 'A video clip', + 'fields' => array( + 'id' => array('type' => 'char', + 'length' => 36, + 'not null' => true, + 'description' => 'UUID'), + 'uri' => array('type' => 'varchar', + 'length' => 255, + 'not null' => true), + 'url' => array('type' => 'varchar', + 'length' => 255, + 'not null' => true), + 'profile_id' => array('type' => 'int', 'not null' => true), + ), + 'primary key' => array('id'), + 'foreign keys' => array('video_profile_id__key' => array('profile' => array('profile_id' => 'id'))), + ); + } + + function saveNew($profile, $url, $options=array()) + { + $vid = new Video(); + + $vid->id = UUID::gen(); + $vid->profile_id = $profile->id; + $vid->url = $url; + + + $options['object_type'] = Video::OBJECT_TYPE; + + if (!array_key_exists('uri', $options)) { + $options['uri'] = common_local_url('showvideo', array('id' => $vid->id)); + } + + if (!array_key_exists('rendered', $options)) { + $options['rendered'] = sprintf("", $url); + } + + $vid->uri = $options['uri']; + + $vid->insert(); + + return Notice::saveNew($profile->id, + '', + 'web', + $options); + + } +} diff --git a/plugins/GNUsocialVideo/actions/postvideo.php b/plugins/GNUsocialVideo/actions/postvideo.php index 4af34af7ab..db27ecd8e4 100644 --- a/plugins/GNUsocialVideo/actions/postvideo.php +++ b/plugins/GNUsocialVideo/actions/postvideo.php @@ -32,52 +32,55 @@ if (!defined('STATUSNET')) { class PostvideoAction extends Action { var $user = null; + var $url = null; function prepare($args) { parent::prepare($args); $this->user = common_current_user(); + + if(empty($this->user)){ + throw new ClientException(_('Must be logged in to post a video'), + 403); + } + + if($this->isPost()){ + $this->checkSessionToken(); + } + + $this->url = filter_var($this->trimmed('url'), FILTER_SANITIZE_URL); + $this->url = filter_var($this->url, FILTER_VALIDATE_URL); + return true; } function handle($args) { parent::handle($args); - if ($_SERVER['REQUEST_METHOD'] == 'POST') { + + if ($this->isPost()) { $this->handlePost($args); + } else { + $this->showPage(); } - $this->showPage(); } function handlePost($args) { - if (!$this->arg('post')) { - return; - } - if (empty($_POST['video_uri'])) { - return; - } - $uri = $_POST['video_uri']; - $uri = filter_var($uri, FILTER_SANITIZE_URL); - $uri = filter_var($uri, FILTER_VALIDATE_URL); - if($uri) { - $rend = sprintf('', $uri); - Notice::saveNew($this->user->id, 'video : ' . $uri, 'web', array('rendered' => $rend)); + if (empty($this->url)) { + throw new ClientException(_('Bad URL.')); } + + $profile = $this->user->getProfile(); + + $vid = Video::saveNew($profile, $this->url, array()); + + common_redirect($vid->uri, 303); } function showContent() { - if(empty($this->user)) { - $this->element('p', array(), 'You are not logged in.'); - } else { - $this->elementStart('form', array('method' => 'post', - 'action' => common_local_url('postvideo'))); - $this->element('input', array('name' => 'video_uri', - 'type' => 'text', - 'id' => 'video_uri')); - $this->submit('post', _('Post')); - $this->elementEnd('form'); - } + $form = new VideoForm(); + $form->show(); } } diff --git a/plugins/GNUsocialVideo/showvideo.php b/plugins/GNUsocialVideo/showvideo.php new file mode 100644 index 0000000000..be4f18d10b --- /dev/null +++ b/plugins/GNUsocialVideo/showvideo.php @@ -0,0 +1,67 @@ +. + * + * @package GNU Social + * @author Ian Denhardt + * @copyright 2011 Free Software Foundation, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + */ + +if(!defined('STATUSNET')){ + exit(1); +} + +class ShowvideoAction extends ShownoticeAction +{ + protected $id = null; + protected $vid = null; + + function prepare($args) + { + OwnerDesignAction::prepare($args); + $this->id = $this->trimmed('id'); + $this->vid = Video::staticGet('id', $this->id); + + if (empty($this->vid)) { + throw new ClientException(_('No such video.'), 404); + } + + $this->notice = $this->vid->getNotice(); + + if (empty($this->notice)) { + throw new ClientException(_('No such video'), 404); + } + + $this->user = User::staticGet('id', $this->vid->profile_id); + + if (empty($this->user)) { + throw new ClientException(_('No such user.'), 404); + } + + $this->profile = $this->user->getProfile(); + + if (empty($this->profile)) { + throw new ServerException(_('User without a profile.')); + } + + return true; + } +} diff --git a/plugins/GNUsocialVideo/videoform.php b/plugins/GNUsocialVideo/videoform.php new file mode 100644 index 0000000000..d47605a947 --- /dev/null +++ b/plugins/GNUsocialVideo/videoform.php @@ -0,0 +1,61 @@ +. + * + * @package GNU Social + * @author Ian Denhardt + * @copyright 2011 Free Software Foundation, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + */ + +if(!defined('STATUSNET')){ + exit(1); +} + +class VideoForm extends Form +{ + function id() + { + return "form_new_video"; + } + + function action() + { + return common_local_url('postvideo'); + } + + function formData() + { + $this->out->elementStart('fieldset', array('id' => 'new_video_data')); + $this->out->elementStart('ul', 'form_data'); + + $this->li(); + $this->out->input('url', _('URL'), null, _('URL of the video')); + $this->unli(); + + $this->out->elementEnd('ul'); + $this->out->elementEnd('fieldset'); + } + + function formActions() + { + $this->out->submit('submit', _m('BUTTON', 'Save')); + } +}