User:Ilmari Karonen/FacebookMetadata

From NetHackWiki
Jump to navigation Jump to search

Facebook metadata is a MediaWiki extension for generating enhanced page metadata for Facebook and other sites supporting it. (See e.g. [1] and [2].) In particular, it generates rel="image_src" links to images used on the page and to the site logo.

Note that this extension does not (so far) provide any direct Facebook integration such as "Like" or "Share" buttons. You'll need another extension for those.

Planned future features include:

  • Image links for category pages (currently missing).
  • Better description text for file pages. (FB seems to extract page text from normal pages just fine.)
  • Try to find a way to get audio/video sharing to work better with FB. We're already providing sensible metadata for those, but FB doesn't seem to like the Ogg format commonly used on wikis.
  • Hook into the parser so that we can see how each image is used on the page.
  • Switch to Open Graph metadata instead of the old style currently used?
  • Like/Share buttons?

Source

<?php
/*
 * Copyright (c) 2011 Ilmari Karonen <nospam@vyznev.net>.
 * 
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

if ( !defined( 'MEDIAWIKI' ) ) {
	die( 'This file is a MediaWiki extension, it is not a valid entry point.' );
}

// Credits:
$wgExtensionCredits['other'][] = array(
       'name'		=> 'Facebook metadata',
       'version'	=> '0.1',
       'author'		=> 'Ilmari Karonen', 
       'url'		=> 'http://nethackwiki.com/wiki/User:Ilmari_Karonen/FacebookMetadata', 
       'description'	=> 'Adds metadata to help link sharing on Facebook and other sites',
);

// Config variables:
$wgFacebookMetadataImageMinSize = 50;  // ignore images less than 50x50 px

// Hook definitions:
$wgHooks['OutputPageParserOutput'][] = 'facebookMetadataFromParserOutput';
$wgHooks['ImageOpenShowImageInlineBefore'][] = 'facebookMetadataFromImagePage';
$wgHooks['BeforePageDisplay'][] = 'facebookMetadataSiteLogo';

// Hook functions:

/**
 * Add metadata links to all images on the page.  TODO: Skip images
 * with empty link/alt attrs and images that are small on the page
 * even if the original is large (needs tighter parser integration).
 */
function facebookMetadataFromParserOutput( &$out, &$parserOutput ) {
	global $wfFacebookMetadataImageMinSize, $wgTitle;
	$min = $wfFacebookMetadataImageMinSize;

	// XXX: File pages are handled below, don't add duplicate links for them
	if ( $wgTitle->getNamespace() == NS_FILE ) {
		return true;
	}
	$images = &$parserOutput->getImages();
	foreach ( $images as $dbkey => $dummy ) {
		$file = wfFindFile( Title::makeTitle( NS_FILE, $dbkey ) );
		if ( $file && $file->canRender() && $file->getWidth() >= $min && $file->getHeight() >= $min ) {
			$out->addLink( array( 'rel' => 'image_src', 'href' => $file->getViewUrl() ) );
		}
	}
	return true;
}

/**
 * On file pages, add metadata for the file.  Ignore the minimum size.
 * TODO: Provide a better title and description.
 */
function facebookMetadataFromImagePage( &$imagePage, &$out ) {
	$file = $imagePage->getDisplayedFile();
	if ( $file ) {
		$fileUrl = $file->getUrl();
		$fileType = $file->getMimeType();
		$mediaType = $file->getMediaType();
		$canRender = $file->canRender();

		// XXX: work around what seems to be a bug in ForeignAPIRepo
		if ( $mediaType == MEDIATYPE_MULTIMEDIA && $fileType == 'application/ogg' && !$file->getWidth() ) {
			$mediaType = MEDIATYPE_AUDIO;
		}

		switch ( $mediaType ) {
		case MEDIATYPE_AUDIO:
			$out->addMeta( 'medium', 'audio' );
			$out->addMeta( 'audio_type', $fileType );
			$out->addLink( array( 'rel' => 'audio_src', 'href' => $fileUrl, 'type' => $fileType ) );
			break;
		case MEDIATYPE_VIDEO:
		case MEDIATYPE_MULTIMEDIA:
			$out->addMeta( 'medium', 'video' );
			$out->addMeta( 'video_type', $fileType );
			$out->addMeta( 'video_width', $file->getWidth() );
			$out->addMeta( 'video_height', $file->getHeight() );
			$out->addLink( array( 'rel' => 'video_src', 'href' => $fileUrl, 'type' => $fileType ) );
			break;
		default:
			if ( $canRender ) {
				$out->addMeta( 'medium', 'image' );
			}
			break;
		}

		if ( $canRender ) {
			if ( !$file->isMultipage() ) {
				$out->addLink( array( 'rel' => 'image_src', 'href' => $file->getViewUrl() ) );
			} else {
				// For multipage images, link to current page or all if not specified
				// XXX: Does this make sense, or should we treat both cases the same?
				global $wgRequest;
				$page = $wgRequest->getIntOrNull( 'page' );  // eww... this should be a param to the hook
				if ( is_null( $page ) ) {
					$minPage = 1; $maxPage = $file->pageCount();
				} else {
					$minPage = $maxPage = $page;
				}
				for ( $page = $minPage; $page <= $maxPage; $page++ ) {
					$thumb = $file->getUnscaledThumb( array( 'page' => $page ) );
					if ( $thumb && !$thumb->isError() ) {
						$out->addLink( array( 'rel' => 'image_src', 'href' => $thumb->getUrl() ) );
					}
				}
			}
		} else {
			// Can't render, fall back to site logo
			global $wgLogo;
			$out->addLink( array( 'rel' => 'image_src', 'href' => $wgLogo ) );
		}
	}
	return true;
}

/**
 * Add a link to the site logo as a fallback.
 */
function facebookMetadataSiteLogo ( &$out, &$skin ) {
        global $wgTitle, $wgLogo;
	// XXX: File pages are handled above, don't add duplicate links for them
	if ( $wgTitle->getNamespace() != NS_FILE ) {
		$out->addLink( array( 'rel' => 'image_src', 'href' => $wgLogo ) );
	}
        return true;
}