more extensions

git-svn-id: file:///home/shish/svn/shimmie2/branches/branch_2.1@649 7f39781d-f577-437e-ae19-be835c7a54ca
This commit is contained in:
shish 2007-12-09 04:18:58 +00:00
parent 91139cb688
commit 0836574070
8 changed files with 1070 additions and 0 deletions

114
contrib/browser_search/main.php Executable file
View File

@ -0,0 +1,114 @@
<?php
/**
* Name: Browser Search
* Author: ATravelingGeek <atg@atravelinggeek.com>
* Some code (and lots of help) by Artanis (Erik Youngren <artanis.00@gmail.com>) from the 'tagger' extention - Used with permission
* Link: http://atravelinggeek.com/
* License: GPLv2
* Description: Allows the user to add a browser 'plugin' to search the site with real-time suggestions
* Version 0.1c
* October 26, 2007
*
*/
class BrowserSearch extends Extension {
public function receive_event($event) {
global $page;
global $config;
if(is_a($event, 'InitExtEvent')) {
$config->set_default_string("search_suggestions_results_order", 'a');
}
// Add in header code to let the browser know that the search plugin exists
if(is_a($event, 'PageRequestEvent')) {
// We need to build the data for the header
global $config;
$search_title = $config->get_string('title');
$search_file_url = make_link('browser_search/please_dont_use_this_tag_as_it_would_break_stuff__search.xml');
$page->add_header("<link rel='search' type='application/opensearchdescription+xml' title='$search_title' href='$search_file_url'>");
}
// The search.xml file that is generated on the fly
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "browser_search") && $event->get_arg(0) == "please_dont_use_this_tag_as_it_would_break_stuff__search.xml") {
// First, we need to build all the variables we'll need
$search_title = $config->get_string('title');
//$search_form_url = $config->get_string('base_href'); //make_link('post/list');
$search_form_url = make_link('post/list/{searchTerms}');
$suggenton_url = make_link('browser_search/')."{searchTerms}";
// Now for the XML
$xml = "
<SearchPlugin xmlns='http://www.mozilla.org/2006/browser/search/' xmlns:os='http://a9.com/-/spec/opensearch/1.1/'>
<os:ShortName>$search_title</os:ShortName>
<os:InputEncoding>UTF-8</os:InputEncoding>
<os:Image width='16'
height='16'>data:image/x-icon;base64,AAABAAEAEBAAAAEACABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWFhYAfX19AH9/fwCAgIAAgYGBAIODgwCEhIQAhoaGAIeHhwCJiYkAioqKAIyMjACPj48AkJCQAJKSkgCTk5MAlZWVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREREREREREREREAAAAAAAAAAAAAABERERERAAEBAQEBAQEBAQAAEREREQABAQEBAQEBAQEAAQAREREAAQEBAQEBAQEBAAEBABERAAEBAQEBAQEBAQABAQAREQAGBgUEAwIBAQEAAgEAEREADAwMCwsKCQkHAAkIABERABAQEBAQEA4ODAANDQAREQAQEBAQEBAQEBAAEBAAEREAEBAQEBAQEBAQABAQABERAAAAAAAAAAAAAAAQEAAREREAEBAPEBAQEBAQABAAEREREQAQEBAQEBAPEBAAABERERERAAAAAAAAAAAAAAAREREREREREREREREREREREf//AACADwAAgAcAAIADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMABAADgAQAA8AEAAP//AAA=</os:Image>
<SearchForm>$search_form_url</SearchForm>
<os:Url type='text/html' method='GET' template='$search_form_url'>
<os:Param name='search' value='{searchTerms}'/>
</os:Url>
<Url type='application/x-suggestions+json' template='$suggenton_url'/>
</SearchPlugin>
";
// And now to send it to the browser
$page->set_mode("data");
$page->set_type("text/xml");
$page->set_data($xml);
} else if(is_a($event, 'PageRequestEvent') && ($event->page_name == "browser_search") && !$config->get_bool("disable_search_suggestions")) { // We need to return results!
global $database;
// We have to build some json stuff
$tag_search = $event->get_arg(0);
// Now to get DB results
if($config->get_string("search_suggestions_results_order") == "a") {
$tags = $database->execute("SELECT tag FROM tags WHERE tag LIKE ? AND count > 0 ORDER BY tag ASC LIMIT 30",array($tag_search."%"));
} else {
$tags = $database->execute("SELECT tag FROM tags WHERE tag LIKE ? AND count > 0 ORDER BY count DESC LIMIT 30",array($tag_search."%"));
}
// And to do stuff with it. We want our output to look like:
// ["shimmie",["shimmies","shimmy","shimmie","21 shimmies","hip shimmies","skea shimmies"],[],[]]
$json_tag_list = "";
$tags_array = array();
foreach($tags as $tag) {
array_push($tags_array,$tag['tag']);
}
$json_tag_list .= implode("\",\"", $tags_array);
// $json_tag_list = implode($tags_array,", ");
// $json_tag_list = "\"".implode($tags_array,"\", \"")."\"";
// And now for the final output
$json_string = "[\"$tag_search\",[\"$json_tag_list\"],[],[]]";
$page->set_mode("data");
$page->set_data($json_string);
}
if(is_a($event, 'SetupBuildingEvent')) {
$sort_by = array();
$sort_by['Alphabetical'] = 'a';
$sort_by['Tag Count'] = 't';
$sb = new SetupBlock("Browser Search");
$sb->add_bool_option("disable_search_suggestions", "Disable search suggestions when using browser-based search: ");
$sb->add_label("<br>");
$sb->add_choice_option("search_suggestions_results_order", $sort_by, "Sort the suggestions by:");
$event->panel->add_block($sb);
}
}
}
add_event_listener(new BrowserSearch());
?>

View File

@ -0,0 +1,427 @@
<?php
/*
Name: Danbooru Client API for Shimmie2
Description: Provides simple interfaces for third party software to interact with Shimmie via
simple HTTP GET/POST requests.
Author: JJS <jsutinen@gmail.com>
Notes:
danbooru API based on documentation from danbooru 1.0 - http://attachr.com/7569
I've only been able to test add_post and find_tags because I use the old danbooru firefox extension for firefox 1.5
Functions currently implemented:
add_comment - NOT DONE YET, waiting on some backend shimmie code :)
add_post - title and rating are currently ignored because shimmie does not support them
find_posts - sort of works, filename is returned as the original filename and probably won't help when it comes to actually downloading it
find_tags - id, name, and after_id all work but the tags parameter is ignored just like danbooru 1.0 ignores it
CHANGELOG
21-OCT-07 9:07PM CST - JJS
Turns out I actually did need to implement the new parameter names
for danbooru api v1.8.1. Now danbooruup should work when used with /api/danbooru/post/create.xml
Also correctly redirects the url provided by danbooruup in the event
of a duplicate image.
19-OCT-07 4:46PM CST - JJS
Add compatibility with danbooru api v1.8.1 style urls
for find_posts and add_post. NOTE: This does not implement
the changes to the parameter names, it is simply a
workaround for the latest danbooruup firefox extension.
Completely compatibility will probably involve a rewrite with a different URL
*/
class DanbooruApi extends Extension
{
// Receive the event
public function receive_event($event)
{
// Check if someone is accessing /api/danbooru (us)
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "api") && ($event->get_arg(0) == 'danbooru'))
{
// execute the danbooru processing code
$this->api_danbooru($event);
}
}
// Danbooru API
private function api_danbooru($event)
{
global $page;
global $config;
global $database;
global $user;
$page->set_mode("data");
$page->set_type("application/xml");
//debug
//$page->set_type("text/plain");
$results = array();
/*
add_comment()
Adds a comment to a post.
Parameters
* body: the body of the comment
* post_id: the post id
* login: your login
* password: your password Response
* 200: success
* 500: error. response body will the the error message.
*/
if($event->get_arg(1) == 'add_comment')
{
// On error the response body is the error message so plain text is fine
$page->set_type("text/plain");
// We do wish to auth the user if possible, if it fails treat as anonymous
$this->authenticate_user();
// Check if anonymous commenting is allowed before proceeding
if($config->get_bool("comment_anon") || !$user->is_anonymous())
{
// Did the user supply a post_id and a comment body?
if(isset($_REQUEST['post_id']) && isset($_REQUEST['body']) && trim($_REQUEST['body']) != "")
{
// waiting for someone to write an event handler for the comments extension :)
} else
{
// User didn't supply necessary parameters, tell them that
header("HTTP/1.0 500 Internal Server Error");
$page->set_data("You forgot to supply either a post id or the body of your comment");
}
} else
{
header("HTTP/1.0 500 Internal Server Error");
$page->set_data("You supplied an invalid login or password or anonymous commenting is currently disabled");
}
}
/*
add_post()
Adds a post to the database.
Parameters
* login: login
* password: password
* file: file as a multipart form
* source: source url
* title: title **IGNORED**
* tags: list of tags as a string, delimited by whitespace
* md5: MD5 hash of upload in hexadecimal format
* rating: rating of the post. can be explicit, questionable, or safe. **IGNORED**
Notes
* The only necessary parameter is tags and either file or source.
* If you want to sign your post, you need a way to authenticate your account, either by supplying login and password, or by supplying a cookie.
* If an account is not supplied or if it doesnt authenticate, he post will be added anonymously.
* If the md5 parameter is supplied and does not match the hash of whats on the server, the post is rejected.
Response
The response depends on the method used:
Post
* X-Danbooru-Location set to the URL for newly uploaded post.
Get
* Redirected to the newly uploaded post.
*/
if(($event->get_arg(1) == 'add_post') || (($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'create.xml')))
{
// No XML data is returned from this function
$page->set_type("text/plain");
// Check first if a login was supplied, if it wasn't check if the user is logged in via cookie
// If all that fails, it's an anonymous upload
$this->authenticate_user();
// Now we check if a file was uploaded or a url was provided to transload
// Much of this code is borrowed from /ext/upload
if($config->get_bool("upload_anon") || !$user->is_anonymous())
{
$file = null;
$filename = "";
$source = "";
if(isset($_FILES['file']))
{ // A file was POST'd in
$file = $_FILES['file']['tmp_name'];
$filename = $_FILES['file']['name'];
// If both a file is posted and a source provided, I'm assuming source is the source of the file
if(isset($_REQUEST['source']) && !empty($_REQUEST['source']))
{
$source = $_REQUEST['source'];
} else
{
$source = null;
}
} elseif(isset($_FILES['post']))
{
$file = $_FILES['post']['tmp_name']['file'];
$filename = $_FILES['post']['name']['file'];
if(isset($_REQUEST['post']['source']) && !empty($_REQUEST['post']['source']))
{
$source = $_REQUEST['post']['source'];
} else
{
$source = null;
}
} elseif(isset($_REQUEST['source']) || isset($_REQUEST['post']['source']))
{ // A url was provided
$url = isset($_REQUEST['source']) ? $_REQUEST['source'] : $_REQUEST['post']['source'];
$source = $url;
$tmp_filename = tempnam("/tmp", "shimmie_transload");
// Are we using fopen wrappers or curl?
if($config->get_string("transload_engine") == "fopen")
{
$fp = fopen($url, "r");
if(!$fp) {
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: fopen read error");
}
$data = "";
$length = 0;
while(!feof($fp) && $length <= $config->get_int('upload_size'))
{
$data .= fread($fp, 8192);
$length = strlen($data);
}
fclose($fp);
$fp = fopen($tmp_filename, "w");
fwrite($fp, $data);
fclose($fp);
}
if($config->get_string("transload_engine") == "curl")
{
$ch = curl_init($url);
$fp = fopen($tmp_filename, "w");
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
}
$file = $tmp_filename;
$filename = basename($url);
} else
{ // Nothing was specified at all
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: no input files");
return;
}
// Get tags out of url
$posttags = isset($_REQUEST['tags']) ? $_REQUEST['tags'] : $_REQUEST['post']['tags'];
// Now that we have some sort of physical file, process it
$image = new Image($file, $filename, $posttags, $source);
// This occurs if the uploaded file is not an image
if(!$image->is_ok())
{
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: unknown");
return;
}
// Was an md5 supplied? Does it match the image hash?
if(isset($_REQUEST['md5']))
{
if($_REQUEST['md5'] != $image->hash)
{
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: md5 mismatch");
return;
}
}
// Is the image too large?
if(filesize($file['tmp_name']) > $config->get_int('upload_size'))
{
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: too large");
return;
}
// Does it exist already?
$existing = $database->get_image_by_hash($image->hash);
if(!is_null($existing)) {
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: duplicate");
$existinglink = make_link("post/view/" . $existing->id);
header("X-Danbooru-Location: $existinglink");
}
// Fire off an event which should process the new image and add it to the db
$nevent = new UploadingImageEvent($user, $image);
send_event($nevent);
// Did something screw up?
if($event->vetoed) {
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: $event->veto_reason");
return;
} else
{ // If it went ok, grab the id for the newly uploaded image and pass it in the header
$newimg = $database->get_image_by_hash($image->hash);
$newid = make_link("post/view/" . $newimg->id);
// Did we POST or GET this call?
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
header("X-Danbooru-Location: $newid");
}
else
header("Location: $newid");
}
} else
{
header("HTTP/1.0 409 Conflict");
header("X-Danbooru-Errors: authentication error");
return;
}
}
/*
find_posts()
Find all posts that match the search criteria. Posts will be ordered by id descending.
Parameters
* md5: md5 hash to search for (comma delimited)
* id: id to search for (comma delimited)
* tags: what tags to search for
* limit: limit
* offset: offset
* after_id: limit results to posts added after this id
*/
if(($event->get_arg(1) == 'find_posts') || (($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'index.xml')))
{
if(isset($_GET['md5']))
{
$md5list = explode(",",$_GET['md5']);
foreach($md5list as $md5)
{
$results[] = $database->get_image_by_hash($md5);
}
} elseif(isset($_GET['id']))
{
$idlist = explode(",",$_GET['id']);
foreach($idlist as $id)
{
$results[] = $database->get_image($id);
}
} else
{
$limit = isset($_GET['limit']) ? int_escape($_GET['limit']) : 100;
$start = isset($_GET['offset']) ? int_escape($_GET['offset']) : 0;
$tags = isset($_GET['tags']) ? tag_explode($_GET['tags']) : array();
$results = $database->get_images($start,$limit,$tags);
}
// Now we have the array $results filled with Image objects
// Let's display them
$xml = "<posts>\n";
foreach($results as $img)
{
// Sanity check to see if $img is really an image object
// If it isn't (e.g. someone requested an invalid md5 or id), break out of the this
if(!is_object($img))
continue;
$taglist = $img->get_tag_list();
$owner = $img->get_owner();
$xml .= "<post md5=\"$img->hash\" rating=\"Questionable\" date=\"$img->posted\" is_warehoused=\"false\" file_name=\"$img->filename\" tags=\"$taglist\" source=\"$img->source\" score=\"0\" id=\"$img->id\" author=\"$owner->name\"/>\n";
}
$xml .= "</posts>";
$page->set_data($xml);
}
/*
find_tags() Find all tags that match the search criteria.
Parameters
* id: A comma delimited list of tag id numbers.
* name: A comma delimited list of tag names.
* tags: any typical tag query. See Tag#parse_query for details.
* after_id: limit results to tags with an id number after after_id. Useful if you only want to refresh
*/
if($event->get_arg(1) == 'find_tags')
{
if(isset($_GET['id']))
{
$idlist = explode(",",$_GET['id']);
foreach($idlist as $id)
{
$sqlresult = $database->execute("SELECT id,tag,count FROM tags WHERE id = ?", array($id));
if(!$sqlresult->EOF)
{
$results[] = array($sqlresult->fields['count'], $sqlresult->fields['tag'], $sqlresult->fields['id']);
}
}
} elseif(isset($_GET['name']))
{
$namelist = explode(",",$_GET['name']);
foreach($namelist as $name)
{
$sqlresult = $database->execute("SELECT id,tag,count FROM tags WHERE tag = ?", array($name));
if(!$sqlresult->EOF)
{
$results[] = array($sqlresult->fields['count'], $sqlresult->fields['tag'], $sqlresult->fields['id']);
}
}
}
/* Currently disabled to maintain identical functionality to danbooru 1.0's own "broken" find_tags
elseif(isset($_GET['tags']))
{
$start = isset($_GET['after_id']) ? int_escape($_GET['offset']) : 0;
$tags = tag_explode($_GET['tags']);
}
*/
else
{
$start = isset($_GET['after_id']) ? int_escape($_GET['offset']) : 0;
$sqlresult = $database->execute("SELECT id,tag,count FROM tags WHERE count > 0 AND id >= ? ORDER BY id DESC",array($start));
while(!$sqlresult->EOF)
{
$results[] = array($sqlresult->fields['count'], $sqlresult->fields['tag'], $sqlresult->fields['id']);
$sqlresult->MoveNext();
}
}
// Tag results collected, build XML output
$xml = "<tags>\n";
foreach($results as $tag)
{
$xml .= "<tag type=\"0\" count=\"$tag[0]\" name=\"$tag[1]\" id=\"$tag[2]\"/>\n";
}
$xml .= "</tags>";
$page->set_data($xml);
}
// Hackery for danbooruup 0.3.2 providing the wrong view url. This simply redirects to the proper
// Shimmie view page
// Example: danbooruup says the url is http://shimmie/api/danbooru/post/show/123
// This redirects that to http://shimmie/post/view/123
if(($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'show'))
{
$fixedlocation = make_link("post/view/" . $event->get_arg(3));
header("Location: $fixedlocation");
}
}
// Turns out I use this a couple times so let's make it a utility function
// Authenticates a user based on the contents of the login and password parameters
// or makes them anonymous. Does not set any cookies or anything permanent.
private function authenticate_user()
{
global $database;
global $user;
if(isset($_REQUEST['login']) && isset($_REQUEST['password']))
{
// Get this user from the db, if it fails the user becomes anonymous
// Code borrowed from /ext/user
$name = $_REQUEST['login'];
$pass = $_REQUEST['password'];
$hash = md5( strtolower($name) . $pass );
$duser = $database->get_user_by_name_and_hash($name, $hash);
if(!is_null($duser)) {
$user = $duser;
} else
{
$user = $database->get_user_by_id($config->get_int("anon_id", 0));
}
}
}
}
add_event_listener(new DanbooruApi());
?>

View File

@ -0,0 +1,41 @@
/*
* This file may not be distributed without its readme.txt
**/
/* * * Link to Image * * */
#Link_to_Image {
/* allows borders to encompass the content; */
overflow:hidden;
}
#Link_to_Image fieldset {
width: 32%;
float:left;
min-width:25em;
}
#Link_to_Image input, #Link_to_Image label {
display:block;
width:66%;
float:left;
margin-bottom:2.5px;
}
#Link_to_Image label {
width:30%;
text-align:left;
padding-right:2%;
cursor:pointer;
}
#Link_to_Image input {
font-size:0.7em;
font-family:courier, fixed, monospace;
}
#Link_to_Image br {
clear:both;
}
#Link_to_Image label:hover {
border-bottom:1px dashed;
}

View File

@ -0,0 +1,45 @@
<?php
/**
* Name: Link to Image
* Author: Artanis <artanis.00@gmail.com>
* Description: Show various forms of link to each image, for copy & paste
*/
class LinkImage extends Extension {
var $theme;
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("link_image", "LinkImageTheme");
if(is_a($event, 'DisplayingImageEvent')) {
global $config;
$data_href = get_base_href();
$event->page->add_header("<link rel='stylesheet' href='$data_href/ext/link_image/_style.css' type='text/css'>",0);
$this->theme->links_block($event->page,$this->data($event->image));
}
if(is_a($event, 'SetupBuildingEvent')) {
$sb = new SetupBlock("Link to Image");
$sb->add_text_option("ext_link-img_text-link_format", "Text Link Format: ");
$event->panel->add_block($sb);
}
if(is_a($event, 'InitExtEvent')) {
global $config;
//just set default if empty.
$config->set_default_string("ext_link-img_text-link_format",
'$title - $id ($ext $size $filesize)');
}
}
private function data($image) {
global $config;
$text_link = $image->parse_link_template($config->get_string("ext_link-img_text-link_format"));
$text_link = $text_link==" "? null : $text_link; // null blank setting so the url gets filled in on the text links.
return array(
'thumb_src' => $image->get_thumb_link(),
'image_src' => $image->get_image_link(),
'post_link' => $image->get_short_link(),
'text_link' => $text_link);
}
}
add_event_listener(new LinkImage());
?>

View File

@ -0,0 +1,82 @@
Link to Image adds BBCode and HTML link codes to the image view. Offers code for a customizable text link, thumbnail links, and full image inline.
Author: Erik Youngren <artanis.00@gmail.com>
License: GPLv2
Submit a Bug Report or Suggestion for Link to Image:
* http://trac.shishnet.org/shimmie2/newticket?owner=artanis.00@gmail.com&component=third%20party%20extensions&keywords=link_to_image
= Use =
There is one option in Board Config: Text Link Format.
It takes the following arguments as well as plain text.
|| arguments || replacement ||
|| $id || The image ID. ||
|| $hash || The MD5 hash of the image. ||
|| $tags || The image's tag list. ||
|| $base || The base HREF as set in Config. ||
|| $ext || The image's extension. ||
|| $size || The image's display size. ||
|| $filesize || The image's size in KB. ||
|| $filename || The image's original filename. ||
|| $title || The site title as set in Config. ||
Link to Image will default this option to '$title - $id ($ext $size $filesize)'.
To reset to the default, simply clear the current setting. Link to Image will then fill in the default value after the save.
To leave the setting blank for any reason, leave a space (' ') in it.
= Install =
1. Copy the folder {{{contrib/link_image/}}} to {{{ext/}}}.
2. In the Config panel, make sure Base URL is set (you may as well set Data URL while you're there, if you haven't already.)
3. Make sure Image Link, Thumb Link, and Short Link all contain the full path ("http://" and onward,) either by using $base or plain text. Link to Image will not be able to retrieve the correct paths without these variables.
= Change Log =
== Version 0.3.0 ==
* Moved Link to Image over to the official theme engine. This functions basically the same as what the prototype was, but it's more thought out and nicer.
* Cleaned up the insides a bit.
== Version 0.2.0 ==
* Changed the HTML generation to use a prototype theme engine. All HTML generation is now contained within {{{link_image.html.php}}}, which may be copied to the current theme folder and edited from there.
== Version 0.1.4 - 20070510 ==
* Style changes.
* Added output containing only the locations of the thumb, image and post.
* Added a link to wikipedia's HTML page, just as BBCode has a wikipedia link.
== Version 0.1.3b - 20070509 ==
* Renamed style.css to _style.css to avoid the auto loader.
== Version 0.1.3 - 20070508 ==
* Created Readme.txt
* Merged 0.1.2 into 0.1.2b
* Removed uneeded documentation from main.php
* Rewrote the css to be unique. Previously used CSS I wrote for elsewhere. Styled to reduce space consumption.
* Added code to insert the CSS import.
* Updated Nice URLs to allow access to the /ext/ folder. (Why is my stylesheet returning HTML instead of CSS?)
* First SVN update.
== Version 0.1.2b - 20070507 ==
(fairly simultaneous with 0.1.2)
* shish:
* Updated to new extension format
* Created folder link_image in trunk/contrib
* Renamed link_image.ext.php to main.php and moved to /link_image/
* Created style.css {{{ /* 404'd :|*/ }}}.
* Documentation (different from mine.)
* Changed add_text_option() and added add_label() in SetupBuildingEvent because I was using an edited version of the function that shish didn't know about. It was a wonder that didn't throw massive errors.
* Published on SVN.
== Version 0.1.2 - 20070506 ==
* Textboxes now select-all when they gain focus.
* Commenting and documentation.
== Version 0.1.1 - 20070506 ==
* Fixed HTML thumbnail link code. (image tag was being html_escaped twice, resulting in "$gt;" and "&lt;" from the first escape becoming "&amp;gt;" and "&amp;lt;") It turns out that html_escape was completely unnecessary, all I had to do was replace the single-quotes around the attributes with escaped double-quotes ('\"'.)
== Version 0.1.0 - 20070506 ==
* Release.
= Links =
* http://trac.shishnet.org/shimmie2/wiki/Contrib/Extensions/LinkToImage - Home
* http://forum.shishnet.org/viewtopic.php?p=153 - Discussion
* http://trac.shishnet.org/shimmie2/browser/trunk/contrib/link_image - Shimmie2 Trac SVN

View File

@ -0,0 +1,71 @@
<?php
class LinkImageTheme extends Themelet {
public function links_block($page,$data) {
$thumb_src = $data['thumb_src'];
$image_src = $data['image_src'];
$post_link = $data['post_link'];
$text_link = $data['text_link'];
$page->add_block( new Block(
"Link to Image",
"<fieldset>".
"<legend><a href='http://en.wikipedia.org/wiki/Bbcode' target='_blank'>BBCode</a></legend>".
$this->link_code("Text Link",$this->url($post_link, $text_link,"ubb"),"ubb_text-link").
$this->link_code("Thumbnail Link",$this->url($post_link, $this->img($thumb_src,"ubb"),"ubb"),"ubb_thumb-link").
$this->link_code("Inline Image", $this->img($image_src,"ubb"), "ubb_full-img").
"</fieldset>".
"<fieldset>".
"<legend><a href='http://en.wikipedia.org/wiki/Html' target='_blank'>HTML</a></legend>".
$this->link_code("Text Link", $this->url($post_link, $text_link,"html"), "html_text-link").
$this->link_code("Thumbnail Link", $this->url($post_link,$this->img($thumb_src,"html"),"html"), "html_thumb-link").
$this->link_code("Inline Image", $this->img($image_src,"html"), "html_full-image").
"</fieldset>".
"<fieldset>".
"<legend>Plain Text</legend>".
$this->link_code("Post URL",$post_link,"text_post-link").
$this->link_code("Thumbnail URL",$thumb_src,"text_thumb-url").
$this->link_code("Image URL",$image_src,"text_image-src").
"</fieldset>",
"main",
50));
}
protected function url ($url,$content,$type) {
if ($content == NULL) {$content=$url;}
switch ($type) {
case "html":
$text = "<a href=\"".$url."\">".$content."</a>";
break;
case "ubb":
$text = "[url=".$url."]".$content."[/url]";
break;
default:
$text = $link." - ".$content;
}
return $text;
}
protected function img ($src,$type) {
switch ($type) {
case "html":
$text = "<img src=\"$src\" />";
break;
case "ubb":
$text = "[img]".$src."[/img]";
break;
default:
$text = $src;
}
return $text;
}
protected function link_code($label,$content,$id=NULL) {
return "<label for='".$id."' title='Click to select the textbox'>$label</label>\n".
"<input type='text' readonly='readonly' id='".$id."' name='".$id."' value='".html_escape($content)."' onfocus='this.select();'></input>\n<br/>\n";
}
}
?>

View File

@ -0,0 +1,205 @@
<?php
/**
* Name: Tag History
* Author: Bzchan <bzchan@animemahou.com>
* Description: Keep a record of tag changes
*/
class Tag_History extends Extension {
var $theme;
public function receive_event($event) {
if(is_null($this->theme)) $this->theme = get_theme_object("tag_history", "Tag_HistoryTheme");
if(is_a($event, 'InitExtEvent')) {
// shimmie is being installed so call install to create the table.
global $config;
if($config->get_int("ext_tag_history_version") < 3) {
$this->install();
}
}
if(is_a($event, 'PageRequestEvent') && ($event->page_name == "tag_history"))
{
if($event->get_arg(0) == "revert")
{
// this is a request to revert to a previous version of the tags
$this->process_revert_request($_POST['revert']);
}
else if($event->count_args() == 1)
{
// must be an attempt to view a tag history
$image_id = int_escape($event->get_arg(0));
$this->theme->display_history_page($event->page, $image_id, $this->get_tag_history_from_id($image_id));
}
else {
$this->theme->display_global_page($event->page, $this->get_global_tag_history());
}
}
if(is_a($event, 'DisplayingImageEvent'))
{
// handle displaying a link on the view page
$this->theme->display_history_link($event->page, $event->image->id);
}
if(is_a($event, 'ImageDeletionEvent'))
{
// handle removing of history when an image is deleted
$this->delete_all_tag_history($event->image->id);
}
if(is_a($event, 'SetupBuildingEvent')) {
$sb = new SetupBlock("Tag History");
$sb->add_label("Limit to ");
$sb->add_int_option("history_limit");
$sb->add_label(" entires per image");
$event->panel->add_block($sb);
}
if(is_a($event, 'TagSetEvent')) {
$this->add_tag_history($event->image_id, $event->tags);
}
}
protected function install()
{
global $database;
global $config;
if($config->get_int("ext_tag_history_version") < 1) {
$database->Execute("CREATE TABLE tag_histories
(
id integer NOT NULL auto_increment PRIMARY KEY,
image_id integer NOT NULL,
tags text NOT NULL
)");
$config->set_int("ext_tag_history_version", 1);
}
if($config->get_int("ext_tag_history_version") == 1) {
$database->Execute("ALTER TABLE tag_histories ADD COLUMN user_id INTEGER NOT NULL");
$database->Execute("ALTER TABLE tag_histories ADD COLUMN date_set DATETIME NOT NULL");
$config->set_int("ext_tag_history_version", 2);
}
if($config->get_int("ext_tag_history_version") == 2) {
$database->Execute("ALTER TABLE tag_histories ADD COLUMN user_ip CHAR(15) NOT NULL");
$config->set_int("ext_tag_history_version", 3);
}
}
/*
* this function is called when a revert request is received
*/
private function process_revert_request($revert_id)
{
global $page;
// check for the nothing case
if($revert_id=="nothing")
{
// tried to set it too the same thing so ignore it (might be a bot)
// go back to the index page with you
$page->set_mode("redirect");
$page->set_redirect(make_link());
return;
}
$revert_id = int_escape($revert_id);
// lets get this revert id assuming it exists
$result = $this->get_tag_history_from_revert($revert_id);
if($result==null)
{
// there is no history entry with that id so either the image was deleted
// while the user was viewing the history, someone is playing with form
// variables or we have messed up in code somewhere.
die("Error: No tag history with specified id was found.");
}
// lets get the values out of the result
$stored_result_id = $result->fields['id'];
$stored_image_id = $result->fields['image_id'];
$stored_tags = $result->fields['tags'];
// all should be ok so we can revert by firing the SetUserTags event.
send_event(new TagSetEvent($stored_image_id, $stored_tags));
// all should be done now so redirect the user back to the image
$page->set_mode("redirect");
$page->set_redirect(make_link("post/view/$stored_image_id"));
}
public function get_tag_history_from_revert($revert_id)
{
global $database;
$row = $database->execute("
SELECT tag_histories.*, users.name
FROM tag_histories
JOIN users ON tag_histories.user_id = users.id
WHERE tag_histories.id = ?", array($revert_id));
return ($row ? $row : null);
}
public function get_tag_history_from_id($image_id)
{
global $database;
$row = $database->db->GetAll("
SELECT tag_histories.*, users.name
FROM tag_histories
JOIN users ON tag_histories.user_id = users.id
WHERE image_id = ?
ORDER BY tag_histories.id DESC",
array($image_id));
return ($row ? $row : array());
}
public function get_global_tag_history()
{
global $database;
$row = $database->db->GetAll("
SELECT tag_histories.*, users.name
FROM tag_histories
JOIN users ON tag_histories.user_id = users.id
ORDER BY tag_histories.id DESC
LIMIT 100");
return ($row ? $row : array());
}
/*
* this function is called when an image has been deleted
*/
private function delete_all_tag_history($image_id)
{
global $database;
$database->execute("DELETE FROM tag_histories WHERE image_id = ?", array($image_id));
}
/*
* this function is called just before an images tag are changed
*/
private function add_tag_history($image_id, $tags)
{
global $database;
global $config;
global $user;
if(is_array($tags)) $tags = implode(' ', $tags);
// add a history entry
$allowed = $config->get_int("history_limit",10);
if($allowed<=0) return;
$row = $database->execute("
INSERT INTO tag_histories(image_id, tags, user_id, user_ip, date_set)
VALUES (?, ?, ?, ?, now())",
array($image_id, $tags, $user->id, $_SERVER['REMOTE_ADDR']));
$entries = $database->db->GetOne("SELECT COUNT(*) FROM `tag_histories` WHERE image_id = ?", array($image_id));
// if needed remove oldest one
if($entries > $allowed)
{
// TODO: Make these queries better
$min_id = $database->db->GetOne("SELECT MIN(id) FROM tag_histories WHERE image_id = ?", array($image_id));
$database->execute("DELETE FROM tag_histories WHERE id = ?", array($min_id));
}
}
}
add_event_listener(new Tag_History());
?>

View File

@ -0,0 +1,85 @@
<?php
class Tag_HistoryTheme extends Themelet {
public function display_history_page($page, $image_id, $history) {
$start_string = "
<div style='text-align: left'>
<form enctype='multipart/form-data' action='".make_link("tag_history/revert")."' method='POST'>
<ul style='list-style-type:none;'>
";
global $user;
$history_list = "";
foreach($history as $fields)
{
$current_id = $fields['id'];
$current_tags = html_escape($fields['tags']);
$name = $fields['name'];
$setter = "<a href='".make_link("user/".url_escape($name))."'>".html_escape($name)."</a>";
if($user->is_admin()) {
$setter .= " / " . $fields['user_ip'];
}
$history_list .= "<li><input type='radio' name='revert' value='$current_id'>$current_tags (Set by $setter)</li>\n";
}
$end_string = "
</ul>
<input type='submit' value='Revert'>
</form>
</div>
";
$history_html = $start_string . $history_list . $end_string;
$page->set_title("Image $image_id Tag History");
$page->set_heading("Tag History: $image_id");
$page->add_block(new NavBlock());
$page->add_block(new Block("Tag History", $history_html, "main", 10));
}
public function display_global_page($page, $history) {
$start_string = "
<div style='text-align: left'>
<form enctype='multipart/form-data' action='".make_link("tag_history/revert")."' method='POST'>
<ul style='list-style-type:none;'>
";
$end_string = "
</ul>
<input type='submit' value='Revert'>
</form>
</div>
";
global $user;
$history_list = "";
foreach($history as $fields)
{
$current_id = $fields['id'];
$image_id = $fields['image_id'];
$current_tags = html_escape($fields['tags']);
$name = $fields['name'];
$setter = "<a href='".make_link("user/".url_escape($name))."'>".html_escape($name)."</a>";
if($user->is_admin()) {
$setter .= " / " . $fields['user_ip'];
}
$history_list .= "
<li>
<input type='radio' name='revert' value='$current_id'>
<a href='".make_link("post/view/$image_id")."'>$image_id</a>:
$current_tags (Set by $setter)
</li>
";
}
$history_html = $start_string . $history_list . $end_string;
$page->set_title("Global Tag History");
$page->set_heading("Global Tag History");
$page->add_block(new NavBlock());
$page->add_block(new Block("Tag History", $history_html, "main", 10));
}
public function display_history_link($page, $image_id) {
$link = "<a href='".make_link("tag_history/$image_id")."'>Tag History</a>\n";
$page->add_block(new Block(null, $link, "main", 5));
}
}
?>