Merge pull request #382 from DakuTree/patch
New metatags, fixes various PostgreSQL errors & misc tweaks.
This commit is contained in:
commit
208e8de7f0
31 changed files with 157 additions and 95 deletions
|
@ -39,19 +39,19 @@ class BaseThemelet {
|
||||||
*/
|
*/
|
||||||
public function build_thumb_html(Image $image) {
|
public function build_thumb_html(Image $image) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
$i_id = (int) $image->id;
|
$i_id = (int) $image->id;
|
||||||
$h_view_link = make_link('post/view/'.$i_id);
|
$h_view_link = make_link('post/view/'.$i_id);
|
||||||
$h_thumb_link = $image->get_thumb_link();
|
$h_thumb_link = $image->get_thumb_link();
|
||||||
$h_tip = html_escape($image->get_tooltip());
|
$h_tip = html_escape($image->get_tooltip());
|
||||||
$h_tags = strtolower($image->get_tag_list());
|
$h_tags = strtolower($image->get_tag_list());
|
||||||
$ext = strtolower($image->ext);
|
|
||||||
|
|
||||||
// If the file doesn't support thumbnail generation, show it at max size.
|
$extArr = array_flip(array('swf', 'svg', 'mp4', 'ogv', 'webm', 'flv')); //List of thumbless filetypes
|
||||||
if($ext === 'swf' || $ext === 'svg' || $ext === 'mp4' || $ext === 'ogv' || $ext === 'webm' || $ext === 'flv'){
|
if(!isset($extArr[$image->ext])){
|
||||||
$tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height'));
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
$tsize = get_thumbnail_size($image->width, $image->height);
|
$tsize = get_thumbnail_size($image->width, $image->height);
|
||||||
|
}else{
|
||||||
|
//Use max thumbnail size if using thumbless filetype
|
||||||
|
$tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$custom_classes = "";
|
$custom_classes = "";
|
||||||
|
|
|
@ -129,7 +129,7 @@ class Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
$querylet = Image::build_search_querylet($tags);
|
$querylet = Image::build_search_querylet($tags);
|
||||||
$querylet->append(new Querylet(" ORDER BY images.".($order_sql ?: $config->get_string("index_order"))));
|
$querylet->append(new Querylet(" ORDER BY ".($order_sql ?: "images.".$config->get_string("index_order"))));
|
||||||
$querylet->append(new Querylet(" LIMIT :limit OFFSET :offset", array("limit"=>$limit, "offset"=>$start)));
|
$querylet->append(new Querylet(" LIMIT :limit OFFSET :offset", array("limit"=>$limit, "offset"=>$start)));
|
||||||
#var_dump($querylet->sql); var_dump($querylet->variables);
|
#var_dump($querylet->sql); var_dump($querylet->variables);
|
||||||
$result = $database->execute($querylet->sql, $querylet->variables);
|
$result = $database->execute($querylet->sql, $querylet->variables);
|
||||||
|
|
|
@ -59,8 +59,8 @@ class Artists extends Extension {
|
||||||
id SCORE_AIPK,
|
id SCORE_AIPK,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
name VARCHAR(255) NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
created DATETIME NOT NULL,
|
created SCORE_DATETIME NOT NULL,
|
||||||
updated DATETIME NOT NULL,
|
updated SCORE_DATETIME NOT NULL,
|
||||||
notes TEXT,
|
notes TEXT,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE
|
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
");
|
");
|
||||||
|
@ -70,8 +70,8 @@ class Artists extends Extension {
|
||||||
artist_id INTEGER NOT NULL,
|
artist_id INTEGER NOT NULL,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
name VARCHAR(255) NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
created DATETIME NOT NULL,
|
created SCORE_DATETIME NOT NULL,
|
||||||
updated DATETIME NOT NULL,
|
updated SCORE_DATETIME NOT NULL,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
FOREIGN KEY (artist_id) REFERENCES artists (id) ON UPDATE CASCADE ON DELETE CASCADE
|
FOREIGN KEY (artist_id) REFERENCES artists (id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
");
|
");
|
||||||
|
@ -79,8 +79,8 @@ class Artists extends Extension {
|
||||||
id SCORE_AIPK,
|
id SCORE_AIPK,
|
||||||
artist_id INTEGER NOT NULL,
|
artist_id INTEGER NOT NULL,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
created DATETIME,
|
created SCORE_DATETIME,
|
||||||
updated DATETIME,
|
updated SCORE_DATETIME,
|
||||||
alias VARCHAR(255),
|
alias VARCHAR(255),
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
FOREIGN KEY (artist_id) REFERENCES artists (id) ON UPDATE CASCADE ON DELETE CASCADE
|
FOREIGN KEY (artist_id) REFERENCES artists (id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
|
@ -89,8 +89,8 @@ class Artists extends Extension {
|
||||||
id SCORE_AIPK,
|
id SCORE_AIPK,
|
||||||
artist_id INTEGER NOT NULL,
|
artist_id INTEGER NOT NULL,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
created DATETIME NOT NULL,
|
created SCORE_DATETIME NOT NULL,
|
||||||
updated DATETIME NOT NULL,
|
updated SCORE_DATETIME NOT NULL,
|
||||||
url VARCHAR(1000) NOT NULL,
|
url VARCHAR(1000) NOT NULL,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
FOREIGN KEY (artist_id) REFERENCES artists (id) ON UPDATE CASCADE ON DELETE CASCADE
|
FOREIGN KEY (artist_id) REFERENCES artists (id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
|
|
|
@ -148,15 +148,13 @@ class Favorites extends Extension {
|
||||||
if($config->get_int("ext_favorites_version") < 1) {
|
if($config->get_int("ext_favorites_version") < 1) {
|
||||||
$database->Execute("ALTER TABLE images ADD COLUMN favorites INTEGER NOT NULL DEFAULT 0");
|
$database->Execute("ALTER TABLE images ADD COLUMN favorites INTEGER NOT NULL DEFAULT 0");
|
||||||
$database->Execute("CREATE INDEX images__favorites ON images(favorites)");
|
$database->Execute("CREATE INDEX images__favorites ON images(favorites)");
|
||||||
$database->Execute("
|
$database->create_table("user_favorites", "
|
||||||
CREATE TABLE user_favorites (
|
|
||||||
image_id INTEGER NOT NULL,
|
image_id INTEGER NOT NULL,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
created_at DATETIME NOT NULL,
|
created_at SCORE_DATETIME NOT NULL,
|
||||||
UNIQUE(image_id, user_id),
|
UNIQUE(image_id, user_id),
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE
|
FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE
|
||||||
)
|
|
||||||
");
|
");
|
||||||
$database->execute("CREATE INDEX user_favorites_image_id_idx ON user_favorites(image_id)", array());
|
$database->execute("CREATE INDEX user_favorites_image_id_idx ON user_favorites(image_id)", array());
|
||||||
$config->set_int("ext_favorites_version", 1);
|
$config->set_int("ext_favorites_version", 1);
|
||||||
|
|
|
@ -27,8 +27,8 @@ class Forum extends Extension {
|
||||||
sticky SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N,
|
sticky SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N,
|
||||||
title VARCHAR(255) NOT NULL,
|
title VARCHAR(255) NOT NULL,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
date DATETIME NOT NULL,
|
date SCORE_DATETIME NOT NULL,
|
||||||
uptodate DATETIME NOT NULL,
|
uptodate SCORE_DATETIME NOT NULL,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE RESTRICT
|
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE RESTRICT
|
||||||
");
|
");
|
||||||
$database->execute("CREATE INDEX forum_threads_date_idx ON forum_threads(date)", array());
|
$database->execute("CREATE INDEX forum_threads_date_idx ON forum_threads(date)", array());
|
||||||
|
@ -37,7 +37,7 @@ class Forum extends Extension {
|
||||||
id SCORE_AIPK,
|
id SCORE_AIPK,
|
||||||
thread_id INTEGER NOT NULL,
|
thread_id INTEGER NOT NULL,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
date DATETIME NOT NULL,
|
date SCORE_DATETIME NOT NULL,
|
||||||
message TEXT,
|
message TEXT,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE RESTRICT,
|
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE RESTRICT,
|
||||||
FOREIGN KEY (thread_id) REFERENCES forum_threads (id) ON UPDATE CASCADE ON DELETE CASCADE
|
FOREIGN KEY (thread_id) REFERENCES forum_threads (id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
|
@ -330,7 +330,7 @@ class Forum extends Extension {
|
||||||
private function save_new_thread($user)
|
private function save_new_thread($user)
|
||||||
{
|
{
|
||||||
$title = html_escape($_POST["title"]);
|
$title = html_escape($_POST["title"]);
|
||||||
$sticky = html_escape($_POST["sticky"]);
|
$sticky = !empty($_POST["sticky"]) ? html_escape($_POST["sticky"]) : "N";
|
||||||
|
|
||||||
if($sticky == ""){
|
if($sticky == ""){
|
||||||
$sticky = "N";
|
$sticky = "N";
|
||||||
|
@ -344,11 +344,11 @@ class Forum extends Extension {
|
||||||
(?, ?, ?, now(), now())",
|
(?, ?, ?, now(), now())",
|
||||||
array($title, $sticky, $user->id));
|
array($title, $sticky, $user->id));
|
||||||
|
|
||||||
$result = $database->get_row("SELECT LAST_INSERT_ID() AS threadID", array());
|
$threadID = $database->get_last_insert_id("forum_threads_id_seq");
|
||||||
|
|
||||||
log_info("forum", "Thread {$result["threadID"]} created by {$user->name}");
|
log_info("forum", "Thread {$threadID} created by {$user->name}");
|
||||||
|
|
||||||
return $result["threadID"];
|
return $threadID;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function save_new_post($threadID, $user)
|
private function save_new_post($threadID, $user)
|
||||||
|
@ -367,9 +367,9 @@ class Forum extends Extension {
|
||||||
(?, ?, now(), ?)"
|
(?, ?, now(), ?)"
|
||||||
, array($threadID, $userID, $message));
|
, array($threadID, $userID, $message));
|
||||||
|
|
||||||
$result = $database->get_row("SELECT LAST_INSERT_ID() AS postID", array());
|
$postID = $database->get_last_insert_id("forum_posts_id_seq");
|
||||||
|
|
||||||
log_info("forum", "Post {$result["postID"]} created by {$user->name}");
|
log_info("forum", "Post {$postID} created by {$user->name}");
|
||||||
|
|
||||||
$database->execute("UPDATE forum_threads SET uptodate=now() WHERE id=?", array ($threadID));
|
$database->execute("UPDATE forum_threads SET uptodate=now() WHERE id=?", array ($threadID));
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,7 +325,7 @@ class ImageIO extends Extension {
|
||||||
)",
|
)",
|
||||||
array(
|
array(
|
||||||
"owner_id"=>$user->id, "owner_ip"=>$_SERVER['REMOTE_ADDR'], "filename"=>substr($image->filename, 0, 60), "filesize"=>$image->filesize,
|
"owner_id"=>$user->id, "owner_ip"=>$_SERVER['REMOTE_ADDR'], "filename"=>substr($image->filename, 0, 60), "filesize"=>$image->filesize,
|
||||||
"hash"=>$image->hash, "ext"=>$image->ext, "width"=>$image->width, "height"=>$image->height, "source"=>$image->source
|
"hash"=>$image->hash, "ext"=>strtolower($image->ext), "width"=>$image->width, "height"=>$image->height, "source"=>$image->source
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$image->id = $database->get_last_insert_id('images_id_seq');
|
$image->id = $database->get_last_insert_id('images_id_seq');
|
||||||
|
@ -435,7 +435,7 @@ class ImageIO extends Extension {
|
||||||
",
|
",
|
||||||
array(
|
array(
|
||||||
"filename"=>$image->filename, "filesize"=>$image->filesize, "hash"=>$image->hash,
|
"filename"=>$image->filename, "filesize"=>$image->filesize, "hash"=>$image->hash,
|
||||||
"ext"=>$image->ext, "width"=>$image->width, "height"=>$image->height, "source"=>$image->source,
|
"ext"=>strtolower($image->ext), "width"=>$image->width, "height"=>$image->height, "source"=>$image->source,
|
||||||
"id"=>$id
|
"id"=>$id
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -36,7 +36,7 @@ class ImageBan extends Extension {
|
||||||
$database->create_table("image_bans", "
|
$database->create_table("image_bans", "
|
||||||
id SCORE_AIPK,
|
id SCORE_AIPK,
|
||||||
hash CHAR(32) NOT NULL,
|
hash CHAR(32) NOT NULL,
|
||||||
date DATETIME DEFAULT SCORE_NOW,
|
date SCORE_DATETIME DEFAULT SCORE_NOW,
|
||||||
reason TEXT NOT NULL
|
reason TEXT NOT NULL
|
||||||
");
|
");
|
||||||
$config->set_int("ext_imageban_version", 1);
|
$config->set_int("ext_imageban_version", 1);
|
||||||
|
|
|
@ -94,6 +94,10 @@
|
||||||
* <li>order=width -- find all images sorted from highest > lowest width
|
* <li>order=width -- find all images sorted from highest > lowest width
|
||||||
* <li>order=filesize_asc -- find all images sorted from lowest > highest filesize
|
* <li>order=filesize_asc -- find all images sorted from lowest > highest filesize
|
||||||
* </ul>
|
* </ul>
|
||||||
|
* <li>order=random_####, eg
|
||||||
|
* <ul>
|
||||||
|
* <li>order=random_8547 -- find all images sorted randomly using 8547 as a seed
|
||||||
|
* </ul>
|
||||||
* </ul>
|
* </ul>
|
||||||
* <p>Search items can be combined to search for images which match both,
|
* <p>Search items can be combined to search for images which match both,
|
||||||
* or you can stick "-" in front of an item to search for things that don't
|
* or you can stick "-" in front of an item to search for things that don't
|
||||||
|
@ -362,7 +366,15 @@ class Index extends Extension {
|
||||||
$ord = strtolower($matches[1]);
|
$ord = strtolower($matches[1]);
|
||||||
$default_order_for_column = preg_match("/^(id|filename)$/", $matches[1]) ? "ASC" : "DESC";
|
$default_order_for_column = preg_match("/^(id|filename)$/", $matches[1]) ? "ASC" : "DESC";
|
||||||
$sort = isset($matches[2]) ? strtoupper($matches[2]) : $default_order_for_column;
|
$sort = isset($matches[2]) ? strtoupper($matches[2]) : $default_order_for_column;
|
||||||
$order_sql = "$ord $sort";
|
$order_sql = "images.$ord $sort";
|
||||||
|
$event->add_querylet(new Querylet("1=1")); //small hack to avoid metatag being treated as normal tag
|
||||||
|
}
|
||||||
|
else if(preg_match("/^order[=|:]random[_]([0-9]{1,4})$/i", $event->term, $matches)){
|
||||||
|
global $order_sql;
|
||||||
|
//order[=|:]random requires a seed to avoid duplicates
|
||||||
|
//since the tag can't be changed during the parseevent, we instead generate the seed during submit using js
|
||||||
|
$seed = $matches[1];
|
||||||
|
$order_sql = "RAND($seed)";
|
||||||
$event->add_querylet(new Querylet("1=1")); //small hack to avoid metatag being treated as normal tag
|
$event->add_querylet(new Querylet("1=1")); //small hack to avoid metatag being treated as normal tag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,18 @@ $(function() {
|
||||||
function() {$('.shm-image-list').show();}
|
function() {$('.shm-image-list').show();}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Generate a random seed when using order:random
|
||||||
|
$('form > input[placeholder="Search"]').parent().submit(function(e){
|
||||||
|
var input = $('form > input[placeholder="Search"]');
|
||||||
|
var tagArr = input.val().split(" ");
|
||||||
|
|
||||||
|
var rand = (($.inArray("order:random", tagArr) + 1) || ($.inArray("order=random", tagArr) + 1)) - 1;
|
||||||
|
if(rand !== -1){
|
||||||
|
tagArr[rand] = "order:random_"+Math.floor((Math.random()*9999)+1);
|
||||||
|
input.val(tagArr.join(" "));
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function select_blocked_tags() {
|
function select_blocked_tags() {
|
||||||
|
|
|
@ -130,8 +130,8 @@ class IPBan extends Extension {
|
||||||
$database->Execute("CREATE TABLE bans (
|
$database->Execute("CREATE TABLE bans (
|
||||||
id int(11) NOT NULL auto_increment,
|
id int(11) NOT NULL auto_increment,
|
||||||
ip char(15) default NULL,
|
ip char(15) default NULL,
|
||||||
date datetime default NULL,
|
date SCORE_DATETIME default NULL,
|
||||||
end datetime default NULL,
|
end SCORE_DATETIME default NULL,
|
||||||
reason varchar(255) default NULL,
|
reason varchar(255) default NULL,
|
||||||
PRIMARY KEY (id)
|
PRIMARY KEY (id)
|
||||||
)");
|
)");
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Notes extends Extension {
|
||||||
image_id INTEGER NOT NULL,
|
image_id INTEGER NOT NULL,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
user_ip CHAR(15) NOT NULL,
|
user_ip CHAR(15) NOT NULL,
|
||||||
date DATETIME NOT NULL,
|
date SCORE_DATETIME NOT NULL,
|
||||||
x1 INTEGER NOT NULL,
|
x1 INTEGER NOT NULL,
|
||||||
y1 INTEGER NOT NULL,
|
y1 INTEGER NOT NULL,
|
||||||
height INTEGER NOT NULL,
|
height INTEGER NOT NULL,
|
||||||
|
@ -35,7 +35,7 @@ class Notes extends Extension {
|
||||||
id SCORE_AIPK,
|
id SCORE_AIPK,
|
||||||
image_id INTEGER NOT NULL,
|
image_id INTEGER NOT NULL,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
date DATETIME NOT NULL,
|
date SCORE_DATETIME NOT NULL,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE
|
FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE
|
||||||
");
|
");
|
||||||
|
@ -49,7 +49,7 @@ class Notes extends Extension {
|
||||||
image_id INTEGER NOT NULL,
|
image_id INTEGER NOT NULL,
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
user_ip CHAR(15) NOT NULL,
|
user_ip CHAR(15) NOT NULL,
|
||||||
date DATETIME NOT NULL,
|
date SCORE_DATETIME NOT NULL,
|
||||||
x1 INTEGER NOT NULL,
|
x1 INTEGER NOT NULL,
|
||||||
y1 INTEGER NOT NULL,
|
y1 INTEGER NOT NULL,
|
||||||
height INTEGER NOT NULL,
|
height INTEGER NOT NULL,
|
||||||
|
|
|
@ -237,7 +237,7 @@ class NumericScore extends Extension {
|
||||||
global $order_sql;
|
global $order_sql;
|
||||||
$default_order_for_column = "DESC";
|
$default_order_for_column = "DESC";
|
||||||
$sort = isset($matches[3]) ? strtoupper($matches[3]) : $default_order_for_column;
|
$sort = isset($matches[3]) ? strtoupper($matches[3]) : $default_order_for_column;
|
||||||
$order_sql = "numeric_score $sort";
|
$order_sql = "images.numeric_score $sort";
|
||||||
$event->add_querylet(new Querylet("1=1")); //small hack to avoid metatag being treated as normal tag
|
$event->add_querylet(new Querylet("1=1")); //small hack to avoid metatag being treated as normal tag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ class PrivMsg extends Extension {
|
||||||
from_id INTEGER NOT NULL,
|
from_id INTEGER NOT NULL,
|
||||||
from_ip SCORE_INET NOT NULL,
|
from_ip SCORE_INET NOT NULL,
|
||||||
to_id INTEGER NOT NULL,
|
to_id INTEGER NOT NULL,
|
||||||
sent_date DATETIME NOT NULL,
|
sent_date SCORE_DATETIME NOT NULL,
|
||||||
subject VARCHAR(64) NOT NULL,
|
subject VARCHAR(64) NOT NULL,
|
||||||
message TEXT NOT NULL,
|
message TEXT NOT NULL,
|
||||||
is_read SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N,
|
is_read SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N,
|
||||||
|
|
|
@ -33,7 +33,7 @@ class Pools extends Extension {
|
||||||
public SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N,
|
public SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N,
|
||||||
title VARCHAR(255) NOT NULL,
|
title VARCHAR(255) NOT NULL,
|
||||||
description TEXT,
|
description TEXT,
|
||||||
date DATETIME NOT NULL,
|
date SCORE_DATETIME NOT NULL,
|
||||||
posts INTEGER NOT NULL DEFAULT 0,
|
posts INTEGER NOT NULL DEFAULT 0,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE
|
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
");
|
");
|
||||||
|
@ -51,7 +51,7 @@ class Pools extends Extension {
|
||||||
action INTEGER NOT NULL,
|
action INTEGER NOT NULL,
|
||||||
images TEXT,
|
images TEXT,
|
||||||
count INTEGER NOT NULL DEFAULT 0,
|
count INTEGER NOT NULL DEFAULT 0,
|
||||||
date DATETIME NOT NULL,
|
date SCORE_DATETIME NOT NULL,
|
||||||
FOREIGN KEY (pool_id) REFERENCES pools(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
FOREIGN KEY (pool_id) REFERENCES pools(id) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE
|
FOREIGN KEY (user_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE
|
||||||
");
|
");
|
||||||
|
|
|
@ -93,7 +93,7 @@ class Source_History extends Extension {
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
user_ip SCORE_INET NOT NULL,
|
user_ip SCORE_INET NOT NULL,
|
||||||
source TEXT NOT NULL,
|
source TEXT NOT NULL,
|
||||||
date_set DATETIME NOT NULL,
|
date_set SCORE_DATETIME NOT NULL,
|
||||||
FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE,
|
FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||||
");
|
");
|
||||||
|
|
|
@ -48,6 +48,30 @@ class TagCategories extends Extension {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onSearchTermParse(SearchTermParseEvent $event) {
|
||||||
|
$matches = array();
|
||||||
|
|
||||||
|
if(preg_match("/^(.+)tags([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])([0-9]+)$/i", $event->term, $matches)) {
|
||||||
|
global $database;
|
||||||
|
$type = $matches[1];
|
||||||
|
$cmp = ltrim($matches[2], ":") ?: "=";
|
||||||
|
$count = $matches[3];
|
||||||
|
|
||||||
|
$types = $database->get_col('SELECT category FROM image_tag_categories');
|
||||||
|
if(in_array($type, $types)) {
|
||||||
|
$event->add_querylet(
|
||||||
|
new Querylet("EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM image_tags it
|
||||||
|
LEFT JOIN tags t ON it.tag_id = t.id
|
||||||
|
WHERE images.id = it.image_id
|
||||||
|
GROUP BY image_id
|
||||||
|
HAVING SUM(CASE WHEN t.tag LIKE '$type:%' THEN 1 ELSE 0 END) $cmp $count
|
||||||
|
)"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getDict() {
|
public function getDict() {
|
||||||
global $database;
|
global $database;
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ class Tag_History extends Extension {
|
||||||
user_id INTEGER NOT NULL,
|
user_id INTEGER NOT NULL,
|
||||||
user_ip SCORE_INET NOT NULL,
|
user_ip SCORE_INET NOT NULL,
|
||||||
tags TEXT NOT NULL,
|
tags TEXT NOT NULL,
|
||||||
date_set DATETIME NOT NULL,
|
date_set SCORE_DATETIME NOT NULL,
|
||||||
FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE,
|
FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||||
");
|
");
|
||||||
|
@ -103,7 +103,7 @@ class Tag_History extends Extension {
|
||||||
|
|
||||||
if($config->get_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 user_id INTEGER NOT NULL");
|
||||||
$database->Execute("ALTER TABLE tag_histories ADD COLUMN date_set DATETIME NOT NULL");
|
$database->Execute($database->scoreql_to_sql("ALTER TABLE tag_histories ADD COLUMN date_set SCORE_DATETIME NOT NULL"));
|
||||||
$config->set_int("ext_tag_history_version", 2);
|
$config->set_int("ext_tag_history_version", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,16 +45,19 @@ class TagList extends Extension {
|
||||||
}
|
}
|
||||||
$this->theme->display_page($page);
|
$this->theme->display_page($page);
|
||||||
}
|
}
|
||||||
|
else if($event->page_matches("api/internal/tag_list/complete")) {
|
||||||
if($event->page_matches("api/internal/tag_list/complete")) {
|
|
||||||
if(!isset($_GET["s"])) return;
|
if(!isset($_GET["s"])) return;
|
||||||
|
|
||||||
$all = $database->get_all(
|
$limit = 0;
|
||||||
"SELECT tag FROM tags WHERE tag LIKE :search AND count > 0 LIMIT 10",
|
$limitSQL = "";
|
||||||
array("search"=>$_GET["s"]."%"));
|
$SQLarr = array("search"=>$_GET["s"]."%");
|
||||||
|
if(isset($_GET["limit"]) && $_GET["limit"] !== 0){
|
||||||
|
$limitSQL = "LIMIT :limit";
|
||||||
|
$SQLarr['limit'] = $_GET["limit"];
|
||||||
|
}
|
||||||
|
|
||||||
$res = array();
|
$res = $database->get_col(
|
||||||
foreach($all as $row) {$res[] = $row["tag"];}
|
"SELECT tag FROM tags WHERE tag LIKE :search AND count > 0 $limitSQL", $SQLarr);
|
||||||
|
|
||||||
$page->set_mode("data");
|
$page->set_mode("data");
|
||||||
$page->set_type("text/plain");
|
$page->set_type("text/plain");
|
||||||
|
|
|
@ -75,6 +75,22 @@ class Upgrade extends Extension {
|
||||||
log_info("upgrade", "Database at version 11");
|
log_info("upgrade", "Database at version 11");
|
||||||
$config->set_bool("in_upgrade", false);
|
$config->set_bool("in_upgrade", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($config->get_int("db_version") < 12) {
|
||||||
|
$config->set_bool("in_upgrade", true);
|
||||||
|
$config->set_int("db_version", 12);
|
||||||
|
|
||||||
|
if($database->get_driver_name() == 'pgsql') {
|
||||||
|
log_info("upgrade", "Changing ext column to VARCHAR");
|
||||||
|
$database->execute("ALTER TABLE images ALTER COLUMN ext SET DATA TYPE VARCHAR(4)");
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("upgrade", "Lowering case of all exts");
|
||||||
|
$database->execute("UPDATE images SET ext = LOWER(ext)");
|
||||||
|
|
||||||
|
log_info("upgrade", "Database at version 12");
|
||||||
|
$config->set_bool("in_upgrade", false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_priority() {return 5;}
|
public function get_priority() {return 5;}
|
||||||
|
|
|
@ -70,11 +70,7 @@ class ViewImage extends Extension {
|
||||||
public function onPageRequest(PageRequestEvent $event) {
|
public function onPageRequest(PageRequestEvent $event) {
|
||||||
global $page, $user;
|
global $page, $user;
|
||||||
|
|
||||||
if(
|
if($event->page_matches("post/prev") || $event->page_matches("post/next")) {
|
||||||
$event->page_matches("post/prev") ||
|
|
||||||
$event->page_matches("post/next")
|
|
||||||
) {
|
|
||||||
|
|
||||||
$image_id = int_escape($event->get_arg(0));
|
$image_id = int_escape($event->get_arg(0));
|
||||||
|
|
||||||
if(isset($_GET['search'])) {
|
if(isset($_GET['search'])) {
|
||||||
|
@ -107,8 +103,7 @@ class ViewImage extends Extension {
|
||||||
$page->set_mode("redirect");
|
$page->set_mode("redirect");
|
||||||
$page->set_redirect(make_link("post/view/{$image->id}", $query));
|
$page->set_redirect(make_link("post/view/{$image->id}", $query));
|
||||||
}
|
}
|
||||||
|
else if($event->page_matches("post/view")) {
|
||||||
if($event->page_matches("post/view")) {
|
|
||||||
$image_id = int_escape($event->get_arg(0));
|
$image_id = int_escape($event->get_arg(0));
|
||||||
|
|
||||||
$image = Image::by_id($image_id);
|
$image = Image::by_id($image_id);
|
||||||
|
@ -124,8 +119,7 @@ class ViewImage extends Extension {
|
||||||
$this->theme->display_error(404, "Image not found", "No image in the database has the ID #$image_id");
|
$this->theme->display_error(404, "Image not found", "No image in the database has the ID #$image_id");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if($event->page_matches("post/set")) {
|
||||||
if($event->page_matches("post/set")) {
|
|
||||||
if(!isset($_POST['image_id'])) return;
|
if(!isset($_POST['image_id'])) return;
|
||||||
|
|
||||||
$image_id = int_escape($_POST['image_id']);
|
$image_id = int_escape($_POST['image_id']);
|
||||||
|
|
|
@ -63,7 +63,7 @@ class Wiki extends Extension {
|
||||||
id SCORE_AIPK,
|
id SCORE_AIPK,
|
||||||
owner_id INTEGER NOT NULL,
|
owner_id INTEGER NOT NULL,
|
||||||
owner_ip SCORE_INET NOT NULL,
|
owner_ip SCORE_INET NOT NULL,
|
||||||
date DATETIME DEFAULT NULL,
|
date SCORE_DATETIME DEFAULT NULL,
|
||||||
title VARCHAR(255) NOT NULL,
|
title VARCHAR(255) NOT NULL,
|
||||||
revision INTEGER NOT NULL DEFAULT 1,
|
revision INTEGER NOT NULL DEFAULT 1,
|
||||||
locked SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N,
|
locked SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N,
|
||||||
|
|
|
@ -8,17 +8,20 @@ $(document).ready(function() {
|
||||||
//TODO: Possibly move to using TextExtJS for autocomplete? - http://textextjs.com/
|
//TODO: Possibly move to using TextExtJS for autocomplete? - http://textextjs.com/
|
||||||
// Also use autocomplete in tag box?
|
// Also use autocomplete in tag box?
|
||||||
$('.autocomplete_tags').autocomplete(base_href + '/api/internal/tag_list/complete', {
|
$('.autocomplete_tags').autocomplete(base_href + '/api/internal/tag_list/complete', {
|
||||||
width: 320,
|
//extraParams: {limit: 10},
|
||||||
max: 15,
|
|
||||||
highlight: false,
|
|
||||||
multiple: true,
|
|
||||||
multipleSeparator: ' ',
|
|
||||||
scroll: true,
|
|
||||||
scrollHeight: 300,
|
|
||||||
selectFirst: false,
|
|
||||||
queryParamName: 's',
|
queryParamName: 's',
|
||||||
delay: 150,
|
minChars: 1,
|
||||||
minChars: 1
|
delay: 0,
|
||||||
|
useCache: true,
|
||||||
|
maxCacheLength: 10,
|
||||||
|
matchInside: false,
|
||||||
|
selectFirst: true,
|
||||||
|
selectOnly: false,
|
||||||
|
preventDefaultReturn: 1,
|
||||||
|
preventDefaultTab: 1,
|
||||||
|
useDelimiter: true,
|
||||||
|
delimiterChar : " ",
|
||||||
|
delimiterKeyCode : 48
|
||||||
});
|
});
|
||||||
|
|
||||||
$("TABLE.sortable").tablesorter();
|
$("TABLE.sortable").tablesorter();
|
||||||
|
|
|
@ -231,8 +231,8 @@ $header_html
|
||||||
Images © their respective owners,
|
Images © their respective owners,
|
||||||
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> ©
|
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> ©
|
||||||
<a href="http://www.shishnet.org/">Shish</a> &
|
<a href="http://www.shishnet.org/">Shish</a> &
|
||||||
<a href="https://github.com/shish/shimmie2/contributors">The Team</a>
|
<a href="https://github.com/shish/shimmie2/graphs/contributors">The Team</a>
|
||||||
2007-2012,
|
2007-2014,
|
||||||
based on the Danbooru concept.
|
based on the Danbooru concept.
|
||||||
$debug
|
$debug
|
||||||
$contact
|
$contact
|
||||||
|
|
|
@ -254,11 +254,11 @@ $header_html
|
||||||
</article>
|
</article>
|
||||||
<footer><div>
|
<footer><div>
|
||||||
Running Shimmie –
|
Running Shimmie –
|
||||||
Images © their respective owners –
|
Images © their respective owners,
|
||||||
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> ©
|
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> ©
|
||||||
<a href="http://www.shishnet.org/">Shish</a> &
|
<a href="http://www.shishnet.org/">Shish</a> &
|
||||||
<a href="https://github.com/shish/shimmie2/contributors">The Team</a>
|
<a href="https://github.com/shish/shimmie2/graphs/contributors">The Team</a>
|
||||||
2007-2012,
|
2007-2014,
|
||||||
based on the Danbooru concept<br />
|
based on the Danbooru concept<br />
|
||||||
$debug
|
$debug
|
||||||
$contact
|
$contact
|
||||||
|
|
|
@ -83,8 +83,8 @@ $header_html
|
||||||
Images © their respective owners,
|
Images © their respective owners,
|
||||||
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> ©
|
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> ©
|
||||||
<a href="http://www.shishnet.org/">Shish</a> &
|
<a href="http://www.shishnet.org/">Shish</a> &
|
||||||
<a href="https://github.com/shish/shimmie2/contributors">The Team</a>
|
<a href="https://github.com/shish/shimmie2/graphs/contributors">The Team</a>
|
||||||
2007-2012,
|
2007-2014,
|
||||||
based on the Danbooru concept.
|
based on the Danbooru concept.
|
||||||
$debug
|
$debug
|
||||||
$contact
|
$contact
|
||||||
|
|
|
@ -56,7 +56,7 @@ class CustomCommentListTheme extends CommentListTheme {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function comment_to_html(Comment $comment, $trim=false) {
|
protected function comment_to_html($comment, $trim=false) {
|
||||||
$inner_id = $this->inner_id; // because custom themes can't add params, because PHP
|
$inner_id = $this->inner_id; // because custom themes can't add params, because PHP
|
||||||
global $user;
|
global $user;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
class Layout {
|
class Layout {
|
||||||
function display_page($page) {
|
function display_page(Page $page) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
$theme_name = $config->get_string('theme', 'default');
|
$theme_name = $config->get_string('theme', 'default');
|
||||||
|
@ -90,8 +90,8 @@ $header_html
|
||||||
Images © their respective owners,
|
Images © their respective owners,
|
||||||
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> ©
|
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> ©
|
||||||
<a href="http://www.shishnet.org/">Shish</a> &
|
<a href="http://www.shishnet.org/">Shish</a> &
|
||||||
<a href="https://github.com/shish/shimmie2/contributors">The Team</a>
|
<a href="https://github.com/shish/shimmie2/graphs/contributors">The Team</a>
|
||||||
2007-2012,
|
2007-2014,
|
||||||
based on the Danbooru concept.
|
based on the Danbooru concept.
|
||||||
<br>Futaba theme based on 4chan's layout and CSS :3
|
<br>Futaba theme based on 4chan's layout and CSS :3
|
||||||
$debug
|
$debug
|
||||||
|
|
|
@ -190,8 +190,8 @@ class Layout {
|
||||||
Images © their respective owners,
|
Images © their respective owners,
|
||||||
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> ©
|
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> ©
|
||||||
<a href="http://www.shishnet.org/">Shish</a> &
|
<a href="http://www.shishnet.org/">Shish</a> &
|
||||||
<a href="https://github.com/shish/shimmie2/contributors">The Team</a>
|
<a href="https://github.com/shish/shimmie2/graphs/contributors">The Team</a>
|
||||||
2007-2012,
|
2007-2014,
|
||||||
based on the Danbooru concept.<br />
|
based on the Danbooru concept.<br />
|
||||||
Lite Theme by <a href="http://seemslegit.com">Zach</a>
|
Lite Theme by <a href="http://seemslegit.com">Zach</a>
|
||||||
$debug
|
$debug
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
class CustomUserPageTheme extends UserPageTheme {
|
class CustomUserPageTheme extends UserPageTheme {
|
||||||
public function display_login_page($page) {
|
public function display_login_page(Page $page) {
|
||||||
global $config;
|
global $config;
|
||||||
$page->set_title("Login");
|
$page->set_title("Login");
|
||||||
$page->set_heading("Login");
|
$page->set_heading("Login");
|
||||||
|
@ -27,14 +27,14 @@ class CustomUserPageTheme extends UserPageTheme {
|
||||||
$page->add_block(new Block("Login", $html, "main", 90));
|
$page->add_block(new Block("Login", $html, "main", 90));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function display_user_links($page, $user, $parts) {
|
public function display_user_links(Page $page, User $user, $parts) {
|
||||||
// no block in this theme
|
// no block in this theme
|
||||||
}
|
}
|
||||||
public function display_login_block(Page $page) {
|
public function display_login_block(Page $page) {
|
||||||
// no block in this theme
|
// no block in this theme
|
||||||
}
|
}
|
||||||
|
|
||||||
public function display_user_block($page, $user, $parts) {
|
public function display_user_block(Page $page, User $user, $parts) {
|
||||||
$h_name = html_escape($user->name);
|
$h_name = html_escape($user->name);
|
||||||
$html = "";
|
$html = "";
|
||||||
$blocked = array("Pools", "Pool Changes", "Alias Editor", "My Profile");
|
$blocked = array("Pools", "Pool Changes", "Alias Editor", "My Profile");
|
||||||
|
@ -45,7 +45,7 @@ class CustomUserPageTheme extends UserPageTheme {
|
||||||
$page->add_block(new Block("User Links", $html, "user", 90));
|
$page->add_block(new Block("User Links", $html, "user", 90));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function display_signup_page($page) {
|
public function display_signup_page(Page $page) {
|
||||||
global $config;
|
global $config;
|
||||||
$tac = $config->get_string("login_tac", "");
|
$tac = $config->get_string("login_tac", "");
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ class CustomUserPageTheme extends UserPageTheme {
|
||||||
$page->add_block(new Block("Signup", $html));
|
$page->add_block(new Block("Signup", $html));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function display_ip_list($page, $uploads, $comments) {
|
public function display_ip_list(Page $page, $uploads, $comments) {
|
||||||
$html = "<table id='ip-history' style='width: 400px;'>";
|
$html = "<table id='ip-history' style='width: 400px;'>";
|
||||||
$html .= "<tr><td>Uploaded from: ";
|
$html .= "<tr><td>Uploaded from: ";
|
||||||
foreach($uploads as $ip => $count) {
|
foreach($uploads as $ip => $count) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
class CustomViewImageTheme extends ViewImageTheme {
|
class CustomViewImageTheme extends ViewImageTheme {
|
||||||
public function display_page($image, $editor_parts) {
|
public function display_page(Image $image, $editor_parts) {
|
||||||
global $page;
|
global $page;
|
||||||
$metatags = str_replace(" ", ", ", html_escape($image->get_tag_list()));
|
$metatags = str_replace(" ", ", ", html_escape($image->get_tag_list()));
|
||||||
$page->set_title("Image {$image->id}: ".html_escape($image->get_tag_list()));
|
$page->set_title("Image {$image->id}: ".html_escape($image->get_tag_list()));
|
||||||
|
@ -17,7 +17,7 @@ class CustomViewImageTheme extends ViewImageTheme {
|
||||||
$page->add_block(new Block(null, $this->build_pin($image), "main", 11));
|
$page->add_block(new Block(null, $this->build_pin($image), "main", 11));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function build_stats($image) {
|
private function build_stats(Image $image) {
|
||||||
$h_owner = html_escape($image->get_owner()->name);
|
$h_owner = html_escape($image->get_owner()->name);
|
||||||
$h_ownerlink = "<a href='".make_link("user/$h_owner")."'>$h_owner</a>";
|
$h_ownerlink = "<a href='".make_link("user/$h_owner")."'>$h_owner</a>";
|
||||||
$h_ip = html_escape($image->owner_ip);
|
$h_ip = html_escape($image->owner_ip);
|
||||||
|
|
|
@ -97,8 +97,8 @@ $header_html
|
||||||
Images © their respective owners,
|
Images © their respective owners,
|
||||||
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> ©
|
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> ©
|
||||||
<a href="http://www.shishnet.org/">Shish</a> &
|
<a href="http://www.shishnet.org/">Shish</a> &
|
||||||
<a href="https://github.com/shish/shimmie2/contributors">The Team</a>
|
<a href="https://github.com/shish/shimmie2/graphs/contributors">The Team</a>
|
||||||
2007-2012,
|
2007-2014,
|
||||||
based on the Danbooru concept.
|
based on the Danbooru concept.
|
||||||
$debug
|
$debug
|
||||||
$contact
|
$contact
|
||||||
|
|
Reference in a new issue