summaryrefslogtreecommitdiff
path: root/plugins/LinkPreview
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/LinkPreview')
-rw-r--r--plugins/LinkPreview/LinkPreviewPlugin.php101
-rw-r--r--plugins/LinkPreview/linkpreview.js194
-rw-r--r--plugins/LinkPreview/locale/LinkPreview.pot21
-rw-r--r--plugins/LinkPreview/locale/fr/LC_MESSAGES/LinkPreview.po28
-rw-r--r--plugins/LinkPreview/locale/mk/LC_MESSAGES/LinkPreview.po27
-rw-r--r--plugins/LinkPreview/locale/nl/LC_MESSAGES/LinkPreview.po28
-rw-r--r--plugins/LinkPreview/oembedproxyaction.php84
7 files changed, 483 insertions, 0 deletions
diff --git a/plugins/LinkPreview/LinkPreviewPlugin.php b/plugins/LinkPreview/LinkPreviewPlugin.php
new file mode 100644
index 000000000..39d2c9bf3
--- /dev/null
+++ b/plugins/LinkPreview/LinkPreviewPlugin.php
@@ -0,0 +1,101 @@
+<?php
+/*
+ * StatusNet - the 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Some UI extras for now...
+ *
+ * @package LinkPreviewPlugin
+ * @maintainer Brion Vibber <brion@status.net>
+ */
+class LinkPreviewPlugin extends Plugin
+{
+ function onPluginVersion(&$versions)
+ {
+ $versions[] = array('name' => 'LinkPreview',
+ 'version' => STATUSNET_VERSION,
+ 'author' => 'Brion Vibber',
+ 'homepage' => 'http://status.net/wiki/Plugin:LinkPreview',
+ 'rawdescription' =>
+ _m('UI extensions previewing thumbnails from links.'));
+
+ return true;
+ }
+
+ /**
+ * Load JS at runtime if we're logged in.
+ *
+ * @param Action $action
+ * @return boolean hook result
+ */
+ function onEndShowScripts($action)
+ {
+ $user = common_current_user();
+ if ($user && common_config('attachments', 'process_links')) {
+ $action->script('plugins/LinkPreview/linkpreview.js');
+ $data = json_encode(array(
+ 'api' => common_local_url('oembedproxy'),
+ 'width' => common_config('attachments', 'thumbwidth'),
+ 'height' => common_config('attachments', 'thumbheight'),
+ ));
+ $action->inlineScript('$(function() {SN.Init.LinkPreview && SN.Init.LinkPreview('.$data.');})');
+ }
+ return true;
+ }
+
+ /**
+ * Autoloader
+ *
+ * Loads our classes if they're requested.
+ *
+ * @param string $cls Class requested
+ *
+ * @return boolean hook return
+ */
+ function onAutoload($cls)
+ {
+ $lower = strtolower($cls);
+ switch ($lower)
+ {
+ case 'oembedproxyaction':
+ require_once dirname(__FILE__) . '/' . $lower . '.php';
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Hook for RouterInitialized event.
+ *
+ * @param Net_URL_Mapper $m URL mapper
+ *
+ * @return boolean hook return
+ */
+ function onStartInitializeRouter($m)
+ {
+ $m->connect('main/oembed/proxy',
+ array('action' => 'oembedproxy'));
+
+ return true;
+ }
+}
diff --git a/plugins/LinkPreview/linkpreview.js b/plugins/LinkPreview/linkpreview.js
new file mode 100644
index 000000000..0c0eb734e
--- /dev/null
+++ b/plugins/LinkPreview/linkpreview.js
@@ -0,0 +1,194 @@
+/**
+ * (c) 2010 StatusNet, Inc.
+ */
+
+(function() {
+ var oEmbed = {
+ api: 'http://oohembed.com/oohembed',
+ width: 100,
+ height: 75,
+ cache: {},
+ callbacks: {},
+
+ /**
+ * Do a cached oEmbed lookup for the given URL.
+ *
+ * @param {String} url
+ * @param {function} callback
+ */
+ lookup: function(url, callback)
+ {
+ if (typeof oEmbed.cache[url] == "object") {
+ // We already have a successful lookup.
+ callback(oEmbed.cache[url]);
+ } else if (typeof oEmbed.callbacks[url] == "undefined") {
+ // No lookup yet... Start it!
+ oEmbed.callbacks[url] = [callback];
+
+ oEmbed.rawLookup(url, function(data) {
+ oEmbed.cache[url] = data;
+ var callbacks = oEmbed.callbacks[url];
+ oEmbed.callbacks[url] = undefined;
+ for (var i = 0; i < callbacks.length; i++) {
+ callbacks[i](data);
+ }
+ });
+ } else {
+ // A lookup is in progress.
+ oEmbed.callbacks[url].push(callback);
+ }
+ },
+
+ /**
+ * Do an oEmbed lookup for the given URL.
+ *
+ * @fixme proxy through ourselves if possible?
+ * @fixme use the global thumbnail size settings
+ *
+ * @param {String} url
+ * @param {function} callback
+ */
+ rawLookup: function(url, callback)
+ {
+ var params = {
+ url: url,
+ format: 'json',
+ maxwidth: oEmbed.width,
+ maxheight: oEmbed.height,
+ token: $('#token').val()
+ };
+ $.get(oEmbed.api, params, function(data, xhr) {
+ callback(data);
+ }, 'json');
+ }
+ };
+
+ var LinkPreview = {
+ links: [],
+
+ /**
+ * Find URL links from the source text that may be interesting.
+ *
+ * @param {String} text
+ * @return {Array} list of URLs
+ */
+ findLinks: function (text)
+ {
+ // @fixme match this to core code
+ var re = /(?:^| )(https?:\/\/.+?\/.+?)(?= |$)/mg;
+ var links = [];
+ var matches;
+ while ((matches = re.exec(text)) !== null) {
+ links.push(matches[1]);
+ }
+ return links;
+ },
+
+ /**
+ * Start looking up info for a link preview...
+ * May start async data loads.
+ *
+ * @param {String} id
+ * @param {String} url
+ */
+ prepLinkPreview: function(id, url)
+ {
+ oEmbed.lookup(url, function(data) {
+ var thumb = null;
+ var width = 100;
+ if (typeof data.thumbnail_url == "string") {
+ thumb = data.thumbnail_url;
+ if (typeof data.thumbnail_width !== "undefined") {
+ if (data.thumbnail_width < width) {
+ width = data.thumbnail_width;
+ }
+ }
+ } else if (data.type == 'photo' && typeof data.url == "string") {
+ thumb = data.url;
+ if (typeof data.width !== "undefined") {
+ if (data.width < width) {
+ width = data.width;
+ }
+ }
+ }
+ if (thumb) {
+ var link = $('<span class="inline-attachment"><a><img/></a></span>');
+ link.find('a')
+ .attr('href', url)
+ .attr('target', '_blank')
+ .last()
+ .find('img')
+ .attr('src', thumb)
+ .attr('width', width)
+ .attr('title', data.title || data.url || url);
+ $('#' + id).append(link);
+ }
+ });
+ },
+
+ /**
+ * Update the live preview section with links found in the given text.
+ * May start async data loads.
+ *
+ * @param {String} text: free-form input text
+ */
+ previewLinks: function(text)
+ {
+ var old = LinkPreview.links;
+ var links = LinkPreview.findLinks(text);
+
+ // Check for existing common elements...
+ for (var i = 0; i < old.length && i < links.length; i++) {
+ if (links[i] != old[i]) {
+ // Change an existing entry!
+ var id = 'link-preview-' + i;
+ $('#' + id).html('');
+ LinkPreview.prepLinkPreview(id, links[i]);
+ }
+ }
+ if (links.length > old.length) {
+ // Adding new entries, whee!
+ for (var i = old.length; i < links.length; i++) {
+ var id = 'link-preview-' + i;
+ $('#link-preview').append('<span id="' + id + '"></span>');
+ LinkPreview.prepLinkPreview(id, links[i]);
+ }
+ } else if (old.length > links.length) {
+ // Remove preview entries for links that have been removed.
+ for (var i = links.length; i < old.length; i++) {
+ var id = 'link-preview-' + i;
+ $('#' + id).remove();
+ }
+ }
+
+ LinkPreview.links = links;
+ },
+
+ /**
+ * Clear out any link preview data.
+ */
+ clear: function() {
+ LinkPreview.links = [];
+ $('#link-preview').empty();
+ }
+ };
+
+ SN.Init.LinkPreview = function(params) {
+ if (params.api) oEmbed.api = params.api;
+ if (params.width) oEmbed.width = params.width;
+ if (params.height) oEmbed.height = params.height;
+
+ $('#form_notice')
+ .append('<div id="link-preview" class="thumbnails"></div>')
+ .bind('reset', function() {
+ LinkPreview.clear();
+ });
+
+ // Piggyback on the counter update...
+ var origCounter = SN.U.Counter;
+ SN.U.Counter = function(form) {
+ LinkPreview.previewLinks($('#notice_data-text').val());
+ return origCounter(form);
+ }
+ }
+})();
diff --git a/plugins/LinkPreview/locale/LinkPreview.pot b/plugins/LinkPreview/locale/LinkPreview.pot
new file mode 100644
index 000000000..202060391
--- /dev/null
+++ b/plugins/LinkPreview/locale/LinkPreview.pot
@@ -0,0 +1,21 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-11-29 15:37+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: LinkPreviewPlugin.php:39
+msgid "UI extensions previewing thumbnails from links."
+msgstr ""
diff --git a/plugins/LinkPreview/locale/fr/LC_MESSAGES/LinkPreview.po b/plugins/LinkPreview/locale/fr/LC_MESSAGES/LinkPreview.po
new file mode 100644
index 000000000..30ad1b676
--- /dev/null
+++ b/plugins/LinkPreview/locale/fr/LC_MESSAGES/LinkPreview.po
@@ -0,0 +1,28 @@
+# Translation of StatusNet - LinkPreview to French (Français)
+# Expored from translatewiki.net
+#
+# Author: Peter17
+# --
+# This file is distributed under the same license as the StatusNet package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: StatusNet - LinkPreview\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-11-30 16:54+0000\n"
+"PO-Revision-Date: 2010-11-30 16:57:34+0000\n"
+"Language-Team: French <http://translatewiki.net/wiki/Portal:fr>\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-POT-Import-Date: 2010-11-29 20:20:26+0000\n"
+"X-Generator: MediaWiki 1.17alpha (r77474); Translate extension (2010-09-17)\n"
+"X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
+"X-Language-Code: fr\n"
+"X-Message-Group: #out-statusnet-plugin-linkpreview\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: LinkPreviewPlugin.php:39
+msgid "UI extensions previewing thumbnails from links."
+msgstr ""
+"Extensions d’interface utilisateur pour prévisualiser des vignettes depuis "
+"les liens."
diff --git a/plugins/LinkPreview/locale/mk/LC_MESSAGES/LinkPreview.po b/plugins/LinkPreview/locale/mk/LC_MESSAGES/LinkPreview.po
new file mode 100644
index 000000000..72de65a42
--- /dev/null
+++ b/plugins/LinkPreview/locale/mk/LC_MESSAGES/LinkPreview.po
@@ -0,0 +1,27 @@
+# Translation of StatusNet - LinkPreview to Macedonian (Македонски)
+# Expored from translatewiki.net
+#
+# Author: Bjankuloski06
+# --
+# This file is distributed under the same license as the StatusNet package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: StatusNet - LinkPreview\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-11-30 16:54+0000\n"
+"PO-Revision-Date: 2010-11-30 16:57:34+0000\n"
+"Language-Team: Macedonian <http://translatewiki.net/wiki/Portal:mk>\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-POT-Import-Date: 2010-11-29 20:20:26+0000\n"
+"X-Generator: MediaWiki 1.17alpha (r77474); Translate extension (2010-09-17)\n"
+"X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
+"X-Language-Code: mk\n"
+"X-Message-Group: #out-statusnet-plugin-linkpreview\n"
+"Plural-Forms: nplurals=2; plural=(n == 1 || n%10 == 1) ? 0 : 1;\n"
+
+#: LinkPreviewPlugin.php:39
+msgid "UI extensions previewing thumbnails from links."
+msgstr ""
+"Додатоци за корисничкиот посредник што даваат преглед на минијатури од врски."
diff --git a/plugins/LinkPreview/locale/nl/LC_MESSAGES/LinkPreview.po b/plugins/LinkPreview/locale/nl/LC_MESSAGES/LinkPreview.po
new file mode 100644
index 000000000..371d63614
--- /dev/null
+++ b/plugins/LinkPreview/locale/nl/LC_MESSAGES/LinkPreview.po
@@ -0,0 +1,28 @@
+# Translation of StatusNet - LinkPreview to Dutch (Nederlands)
+# Expored from translatewiki.net
+#
+# Author: Siebrand
+# --
+# This file is distributed under the same license as the StatusNet package.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: StatusNet - LinkPreview\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-11-30 16:54+0000\n"
+"PO-Revision-Date: 2010-11-30 16:57:34+0000\n"
+"Language-Team: Dutch <http://translatewiki.net/wiki/Portal:nl>\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-POT-Import-Date: 2010-11-29 20:20:26+0000\n"
+"X-Generator: MediaWiki 1.17alpha (r77474); Translate extension (2010-09-17)\n"
+"X-Translation-Project: translatewiki.net at http://translatewiki.net\n"
+"X-Language-Code: nl\n"
+"X-Message-Group: #out-statusnet-plugin-linkpreview\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: LinkPreviewPlugin.php:39
+msgid "UI extensions previewing thumbnails from links."
+msgstr ""
+"Gebruikersinterfaceuitbreiding voor het weergeven van miniaturen voor "
+"verwijzingen."
diff --git a/plugins/LinkPreview/oembedproxyaction.php b/plugins/LinkPreview/oembedproxyaction.php
new file mode 100644
index 000000000..470f78073
--- /dev/null
+++ b/plugins/LinkPreview/oembedproxyaction.php
@@ -0,0 +1,84 @@
+<?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/>.
+ *
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2010 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/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Oembed proxy implementation
+ *
+ * This class provides an interface for our JS-side code to pull info on
+ * links from other sites, using either native oEmbed, our own custom
+ * handlers, or the oohEmbed.com offsite proxy service as configured.
+ *
+ * @category oEmbed
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2010 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 OembedproxyAction extends OembedAction
+{
+
+ function handle($args)
+ {
+ // We're not a general oEmbed proxy service; limit to valid sessions.
+ $token = $this->trimmed('token');
+ if (!$token || $token != common_session_token()) {
+ $this->clientError(_('There was a problem with your session token. '.
+ 'Try again, please.'));
+ }
+
+ $format = $this->arg('format');
+ if ($format && $format != 'json') {
+ throw new ClientException('Invalid format; only JSON supported.');
+ }
+
+ $url = $this->arg('url');
+ if (!common_valid_http_url($url)) {
+ throw new ClientException('Invalid URL.');
+ }
+
+ $params = array();
+ if ($this->arg('maxwidth')) {
+ $params['maxwidth'] = $this->arg('maxwidth');
+ }
+ if ($this->arg('maxheight')) {
+ $params['maxheight'] = $this->arg('maxheight');
+ }
+
+ $data = oEmbedHelper::getObject($url, $params);
+
+ $this->init_document('json');
+ print json_encode($data);
+ }
+
+}