/** * For initializing members of the class. * * @param array $args misc. arguments * * @return boolean true */ function prepare($args) { parent::prepare($args); if (!$this->isPost()) { throw new ClientException(_('POST only'), 405); } $this->checkSessionToken(); $this->url = $this->trimmed('url'); if (empty($this->url)) { throw new ClientException(_('URL is required.'), 400); } if (!common_valid_http_url($this->url)) { throw new ClientException(_('Invalid URL.'), 400); } try { // processNew will first try to fetch a locally stored File entry $f = File::processNew($this->url); } catch (ServerException $e) { $f = null; } // How about now? if ($f instanceof File) { // FIXME: Use some File metadata Event instead $this->oembed = File_oembed::getKV('file_id', $f->id); if ($this->oembed instanceof File_oembed) { $this->title = $this->oembed->title; } $this->thumbnail = File_thumbnail::getKV('file_id', $f->id); } return true; }
/** * Add stuff to notices in API responses * * @param Action $action action being executed * * @return boolean hook return */ function onNoticeSimpleStatusArray($notice, &$twitter_status, $scoped) { // groups $notice_groups = $notice->getGroups(); $group_addressees = false; foreach ($notice_groups as $g) { $group_addressees[] = array('nickname' => $g->nickname, 'url' => $g->mainpage); } $twitter_status['statusnet_in_groups'] = $group_addressees; // for older verions of gnu social: include the repeat-id, which we need when unrepeating later if (array_key_exists('repeated', $twitter_status) && $twitter_status['repeated'] === true) { $repeated = Notice::pkeyGet(array('profile_id' => $scoped->id, 'repeat_of' => $notice->id, 'verb' => 'http://activitystrea.ms/schema/1.0/share')); $twitter_status['repeated_id'] = $repeated->id; } // more metadata about attachments // get all attachments first, and put all the extra meta data in an array $attachments = $notice->attachments(); $attachment_url_to_id = array(); if (!empty($attachments)) { foreach ($attachments as $attachment) { if (is_object($attachment)) { try { $enclosure_o = $attachment->getEnclosure(); // Oembed if (array_key_exists('Oembed', StatusNet::getActivePlugins())) { $oembed = File_oembed::getKV('file_id', $attachment->id); if ($oembed instanceof File_oembed) { $oembed_html = str_replace('<!--//-->', '', $oembed->html); // trash left of wordpress' javascript after htmLawed removed the tags if ($oembed->provider == 'Twitter' && strstr($oembed_html, '>— ' . $oembed->author_name)) { $oembed_html = substr($oembed_html, 0, strpos($oembed_html, '>— ' . $oembed->author_name) + 1); // remove user data from twitter oembed html (we have it in ) $twitter_username = substr($oembed->html, strpos($oembed->html, '>— ' . $oembed->author_name) + strlen('>— ' . $oembed->author_name)); $twitter_username = substr($twitter_username, strpos($twitter_username, '(@') + 1); $twitter_username = substr($twitter_username, 0, strpos($twitter_username, ')')); $oembed->title = $twitter_username; } $oembed_html = str_replace('…', '...', $oembed_html); // ellipsis is sometimes stored as html in db, for some reason $oembed_html = mb_substr(trim(strip_tags(html_entity_decode($oembed_html, ENT_QUOTES))), 0, 250); // sometimes we have html charachters that we want to decode and then strip $oembed_title = trim(strip_tags(html_entity_decode($oembed->title, ENT_QUOTES))); $oembed_provider = trim(strip_tags(html_entity_decode($oembed->provider, ENT_QUOTES))); $oembed_author_name = trim(strip_tags(html_entity_decode($oembed->author_name, ENT_QUOTES))); $attachment_url_to_id[$enclosure_o->url]['oembed'] = array('type' => $oembed->type, 'provider' => $oembed_provider, 'provider_url' => $oembed->provider_url, 'oembedHTML' => $oembed_html, 'title' => $oembed_title, 'author_name' => $oembed_author_name, 'author_url' => $oembed->author_url); } else { $attachment_url_to_id[$enclosure_o->url]['oembed'] = false; } } // add id to all attachments $attachment_url_to_id[$enclosure_o->url]['id'] = $attachment->id; // add an attachment version to all attachments // this means we can force all cached attachments to update, if we change this $attachment_url_to_id[$enclosure_o->url]['version'] = '1.2'; // add data about thumbnails $thumb = $attachment->getThumbnail(); $large_thumb = $attachment->getThumbnail(1000, 3000, false); if (method_exists('File_thumbnail', 'url')) { $thumb_url = File_thumbnail::url($thumb->filename); $large_thumb_url = File_thumbnail::url($large_thumb->filename); } else { $thumb_url = $thumb->getUrl(); $large_thumb_url = $large_thumb->getUrl(); } $attachment_url_to_id[$enclosure_o->url]['thumb_url'] = $thumb_url; $attachment_url_to_id[$enclosure_o->url]['large_thumb_url'] = $large_thumb_url; $attachment_url_to_id[$enclosure_o->url]['width'] = $attachment->width; $attachment_url_to_id[$enclosure_o->url]['height'] = $attachment->height; // animated gif? if ($attachment->mimetype == 'image/gif') { $image = ImageFile::fromFileObject($attachment); if ($image->animated == 1) { $attachment_url_to_id[$enclosure_o->url]['animated'] = true; } else { $attachment_url_to_id[$enclosure_o->url]['animated'] = false; } } // this applies to older versions of gnu social, i think } catch (Exception $e) { $thumb = File_thumbnail::getKV('file_id', $attachment->id); if ($thumb instanceof File_thumbnail) { $thumb_url = $thumb->getUrl(); $attachment_url_to_id[$enclosure_o->url]['id'] = $attachment->id; $attachment_url_to_id[$enclosure_o->url]['thumb_url'] = $thumb_url; $attachment_url_to_id[$enclosure_o->url]['large_thumb_url'] = $thumb_url; $attachment_url_to_id[$enclosure_o->url]['width'] = $attachment->width; $attachment_url_to_id[$enclosure_o->url]['height'] = $attachment->height; // animated gif? if ($attachment->mimetype == 'image/gif') { $image = ImageFile::fromFileObject($attachment); if ($image->animated == 1) { $attachment_url_to_id[$enclosure_o->url]['animated'] = true; } else { $attachment_url_to_id[$enclosure_o->url]['animated'] = false; } } } } } } } // add the extra meta data to $twitter_status if (!empty($twitter_status['attachments'])) { foreach ($twitter_status['attachments'] as &$attachment) { if (!empty($attachment_url_to_id[$attachment['url']])) { $attachment = array_merge($attachment, $attachment_url_to_id[$attachment['url']]); } } } // quoted notices if (!empty($twitter_status['attachments'])) { foreach ($twitter_status['attachments'] as &$attachment) { $quoted_notice = false; // if this attachment has an url this might be a notice url if (isset($attachment['url'])) { $noticeurl = common_path('notice/', StatusNet::isHTTPS()); $instanceurl = common_path('', StatusNet::isHTTPS()); // remove protocol for the comparison below $noticeurl_wo_protocol = preg_replace('(^https?://)', '', $noticeurl); $instanceurl_wo_protocol = preg_replace('(^https?://)', '', $instanceurl); $attachment_url_wo_protocol = preg_replace('(^https?://)', '', $attachment['url']); // local notice urls if (strpos($attachment_url_wo_protocol, $noticeurl_wo_protocol) === 0) { $possible_notice_id = str_replace($noticeurl_wo_protocol, '', $attachment_url_wo_protocol); if (ctype_digit($possible_notice_id)) { $quoted_notice = Notice::getKV('id', $possible_notice_id); } } elseif (strpos($attachment_url_wo_protocol, $instanceurl_wo_protocol) !== 0 && stristr($attachment_url_wo_protocol, '/notice/')) { $quoted_notice = Notice::getKV('url', $attachment['url']); // try with http<->https if no match. applies to quitter.se notices mostly if (!$quoted_notice instanceof Notice) { if (strpos($attachment['url'], 'https://') === 0) { $quoted_notice = Notice::getKV('url', str_replace('https://', 'http://', $attachment['url'])); } else { $quoted_notice = Notice::getKV('url', str_replace('http://', 'https://', $attachment['url'])); } } } // include the quoted notice in the attachment if ($quoted_notice instanceof Notice) { $quoted_notice_author = Profile::getKV('id', $quoted_notice->profile_id); if ($quoted_notice_author instanceof Profile) { $attachment['quoted_notice']['id'] = $quoted_notice->id; $attachment['quoted_notice']['content'] = $quoted_notice->content; $attachment['quoted_notice']['nickname'] = $quoted_notice_author->nickname; $attachment['quoted_notice']['fullname'] = $quoted_notice_author->fullname; $attachment['quoted_notice']['is_local'] = $quoted_notice_author->isLocal(); $quoted_notice_attachments = $quoted_notice->attachments(); foreach ($quoted_notice_attachments as $q_attach) { if (is_object($q_attach)) { try { $qthumb = $q_attach->getThumbnail(); if (method_exists('File_thumbnail', 'url')) { $thumb_url = File_thumbnail::url($qthumb->filename); } else { $thumb_url = $qthumb->getUrl(); } $attachment['quoted_notice']['attachments'][] = array('thumb_url' => $thumb_url, 'attachment_id' => $q_attach->id); } catch (Exception $e) { common_debug('Qvitter: could not get thumbnail for attachment id=' . $q_attach->id . ' in quoted notice id=' . $quoted_notice->id); } } } } } } } } try { $twitter_status['external_url'] = $notice->getUrl(true); } catch (InvalidUrlException $e) { common_debug('Qvitter: No URL available for external notice: id=' . $notice->id); } // reply-to profile url try { $reply = $notice->getParent(); $twitter_status['in_reply_to_profileurl'] = $reply->getProfile()->getUrl(); } catch (ServerException $e) { $twitter_status['in_reply_to_profileurl'] = null; } // fave number $faves = Fave::byNotice($notice); $favenum = count($faves); $twitter_status['fave_num'] = $favenum; // repeat number $repeats = $notice->repeatStream(); $repeatnum = 0; while ($repeats->fetch()) { if ($repeats->verb == ActivityVerb::SHARE) { // i.e. not deleted repeats $repeatnum++; } } $twitter_status['repeat_num'] = $repeatnum; // is this a post? (previously is_activity) if (method_exists('ActivityUtils', 'compareVerbs')) { $twitter_status['is_post_verb'] = ActivityUtils::compareVerbs($notice->verb, array(ActivityVerb::POST)); } else { $twitter_status['is_post_verb'] = $notice->verb == ActivityVerb::POST ? true : false; } // some more metadata about notice if ($notice->is_local == '1') { $twitter_status['is_local'] = true; } else { $twitter_status['is_local'] = false; if ($twitter_status['is_post_verb'] === true) { try { $twitter_status['external_url'] = $notice->getUrl(true); } catch (InvalidUrlException $e) { common_debug('Qvitter: No URL available for external notice: id=' . $notice->id); } } } if (ActivityUtils::compareTypes($notice->verb, array('qvitter-delete-notice', 'delete'))) { $twitter_status['qvitter_delete_notice'] = true; } 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) && (GNUsocial::isAjax() || common_config('attachments', 'show_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)); } }
protected function handle() { parent::handle(); $url = $this->trimmed('url'); if (substr(strtolower($url), 0, strlen(common_root_url())) !== strtolower(common_root_url())) { // TRANS: Error message displaying attachments. %s is the site's base URL. $this->clientError(sprintf(_('oEmbed data will only be provided for %s URLs.'), common_root_url()), 400); } $path = substr($url, strlen(common_root_url())); $r = Router::get(); $proxy_args = $r->map($path); if (!$proxy_args) { // TRANS: Client error displayed in oEmbed action when path not found. // TRANS: %s is a path. $this->clientError(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: Client error displayed in oEmbed action when notice not found. // TRANS: %s is a notice. $this->clientError(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: Client error displayed in oEmbed action when attachment not found. // TRANS: %d is an attachment ID. $this->clientError(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); } }
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; }