diff --git a/inc/anti-bot.php b/inc/anti-bot.php index fde97096..41e0a1d6 100644 --- a/inc/anti-bot.php +++ b/inc/anti-bot.php @@ -178,11 +178,14 @@ class AntiBot { } function _create_antibot($board, $thread) { - global $config; + global $config, $purged_old_antispam; $antibot = new AntiBot(array($board, $thread)); - query('DELETE FROM ``antispam`` WHERE `expires` < UNIX_TIMESTAMP()') or error(db_error()); + if (!isset($purged_old_antispam)) { + $purged_old_antispam = true; + query('DELETE FROM ``antispam`` WHERE `expires` < UNIX_TIMESTAMP()') or error(db_error()); + } if ($thread) $query = prepare('UPDATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` = :thread AND `expires` IS NULL'); diff --git a/inc/config.php b/inc/config.php index 888cbeb8..ccefe1e8 100644 --- a/inc/config.php +++ b/inc/config.php @@ -77,16 +77,18 @@ // Database driver (http://www.php.net/manual/en/pdo.drivers.php) // Only MySQL is supported by Tinyboard at the moment, sorry. $config['db']['type'] = 'mysql'; - // Hostname or IP address + // Hostname, IP address or Unix socket (prefixed with ":") $config['db']['server'] = 'localhost'; + // Example: Unix socket + // $config['db']['server'] = ':/tmp/mysql.sock'; // Login $config['db']['user'] = ''; $config['db']['password'] = ''; // Tinyboard database $config['db']['database'] = ''; - // Table prefix + // Table prefix (optional) $config['db']['prefix'] = ''; - // Use a persistent connection (experimental) + // Use a persistent connection (experimental; benefits unknown) $config['db']['persistent'] = false; // Anything more to add to the DSN string (eg. port=xxx;foo=bar) $config['db']['dsn'] = ''; @@ -1350,14 +1352,14 @@ * ============= */ - // Whether or not to use the API, disabled by default. + // Whether or not to enable the 4chan-compatible API, disabled by default. See + // https://github.com/4chan/4chan-API for API specification. $config['api']['enabled'] = false; - // Extra fields in to be shown in the array that are not 4chan API compatible. - // You canget these by taking a look at the schema for posts_ tables. The array should be formatted as $db_name => $translated_name. - // For example: - - // $config['api']['extra_fields'] = array('body_nomarkup'=>'com_nomarkup'); + // Extra fields in to be shown in the array that are not in the 4chan-API. You can get these by taking a + // look at the schema for posts_ tables. The array should be formatted as $db_column => $translated_name. + // Example: Adding the pre-markup post body to the API as "com_nomarkup". + // $config['api']['extra_fields'] = array('body_nomarkup' => 'com_nomarkup'); /* * ==================== diff --git a/inc/database.php b/inc/database.php index 24959d0c..8daa20b4 100644 --- a/inc/database.php +++ b/inc/database.php @@ -43,9 +43,17 @@ class PreparedQueryDebug { function sql_open() { global $pdo, $config; - if ($pdo) return true; + if ($pdo) + return true; - $dsn = $config['db']['type'] . ':host=' . $config['db']['server'] . ';dbname=' . $config['db']['database']; + if (isset($config['db']['server'][0]) && $config['db']['server'][0] == ':') + $unix_socket = substr($config['db']['server'], 1); + else + $unix_socket = false; + + $dsn = $config['db']['type'] . ':' . + ($unix_socket ? 'unix_socket=' . $unix_socket : 'host=' . $config['db']['server']) . + ';dbname=' . $config['db']['database']; if (!empty($config['db']['dsn'])) $dsn .= ';' . $config['db']['dsn']; try { diff --git a/inc/functions.php b/inc/functions.php index 94c64c75..b5daa3a6 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -35,6 +35,7 @@ function loadConfig() { $arrays = array( 'db', + 'api', 'cache', 'cookies', 'error', @@ -1001,9 +1002,8 @@ function deletePost($id, $error_if_doesnt_exist=true, $rebuild_after=true) { if (isset($tmp_board)) openBoard($tmp_board); - $query = prepare("DELETE FROM ``cites`` WHERE (`target_board` = :board AND `target` = :id) OR (`board` = :board AND `post` = :id)"); + $query = prepare("DELETE FROM ``cites`` WHERE (`target_board` = :board AND `target` = (" . implode(' OR `target` = ', $ids) . ")) OR (`board` = :board AND (`post` = " . implode(' OR `post` = ', $ids) . "))"); $query->bindValue(':board', $board['uri']); - $query->bindValue(':id', $id, PDO::PARAM_INT); $query->execute() or error(db_error($query)); if (isset($rebuild) && $rebuild_after) { @@ -1056,7 +1056,7 @@ function index($page, $mod=false) { return false; $threads = array(); - + while ($th = $query->fetch(PDO::FETCH_ASSOC)) { $thread = new Thread($th, $mod ? '?/' : $config['root'], $mod); @@ -1097,7 +1097,7 @@ function index($page, $mod=false) { $thread->omitted = $omitted['post_count'] - ($th['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview']); $thread->omitted_images = $omitted['image_count'] - $num_images; } - + $threads[] = $thread; $body .= $thread->build(true); } @@ -1309,7 +1309,8 @@ function buildIndex() { for ($page = 1; $page <= $config['max_pages']; $page++) { $filename = $board['dir'] . ($page == 1 ? $config['file_index'] : sprintf($config['file_page'], $page)); - if ($config['try_smarter'] && isset($build_pages) && count($build_pages) && !in_array($page, $build_pages) && is_file($filename)) + if ($config['try_smarter'] && isset($build_pages) && count($build_pages) + && !in_array($page, $build_pages) && is_file($filename)) continue; $content = index($page); if (!$content) @@ -1326,24 +1327,25 @@ function buildIndex() { $content['antibot'] = $antibot; file_write($filename, Element('index.html', $content)); - + // json api if ($config['api']['enabled']) { $threads = $content['threads']; $json = json_encode($api->translatePage($threads)); - $jsonFilename = $board['dir'] . ($page-1) . ".json"; // pages should start from 0 + $jsonFilename = $board['dir'] . ($page - 1) . '.json'; // pages should start from 0 file_write($jsonFilename, $json); - $catalog[$page-1] = $threads; + $catalog[$page-1] = $threads; } } + if ($page < $config['max_pages']) { for (;$page<=$config['max_pages'];$page++) { $filename = $board['dir'] . ($page==1 ? $config['file_index'] : sprintf($config['file_page'], $page)); file_unlink($filename); - + if ($config['api']['enabled']) { - $jsonFilename = $board['dir'] . ($page-1) . ".json"; + $jsonFilename = $board['dir'] . ($page - 1) . '.json'; file_unlink($jsonFilename); } } @@ -1352,7 +1354,7 @@ function buildIndex() { // json api catalog if ($config['api']['enabled']) { $json = json_encode($api->translateCatalog($catalog)); - $jsonFilename = $board['dir'] . "catalog.json"; + $jsonFilename = $board['dir'] . 'catalog.json'; file_write($jsonFilename, $json); } } @@ -1779,7 +1781,7 @@ function buildThread($id, $return = false, $mod = false) { if ($config['api']['enabled']) { $api = new Api(); $json = json_encode($api->translateThread($thread)); - $jsonFilename = $board['dir'] . $config['dir']['res'] . $id . ".json"; + $jsonFilename = $board['dir'] . $config['dir']['res'] . $id . '.json'; file_write($jsonFilename, $json); } @@ -1874,7 +1876,7 @@ function buildThread50($id, $return = false, $mod = false, $thread = null, $anti } } - function rrmdir($dir) { +function rrmdir($dir) { if (is_dir($dir)) { $objects = scandir($dir); foreach ($objects as $object) { @@ -2029,7 +2031,7 @@ function DNS($host) { global $config; if ($config['cache']['enabled'] && ($ip_addr = cache::get('dns_' . $host))) { - return $ip_addr; + return $ip_addr != '?' ? $ip_addr : false; } if (!$config['dns_system']) { @@ -2045,7 +2047,7 @@ function DNS($host) { } if ($config['cache']['enabled']) - cache::set('dns_' . $host, $ip_addr, 3600); + cache::set('dns_' . $host, $ip_addr !== false ? $ip_addr : '?', 3600); return $ip_addr; } diff --git a/inc/image.php b/inc/image.php index 8088999d..d3692a39 100644 --- a/inc/image.php +++ b/inc/image.php @@ -314,16 +314,18 @@ class ImageConvert extends ImageBase { $this->destroy(); } - $this->temp = tempnam($config['tmp'], 'imagick'); + $this->temp = tempnam($config['tmp'], 'convert'); $config['thumb_keep_animation_frames'] = (int)$config['thumb_keep_animation_frames']; if ($this->format == 'gif' && ($config['thumb_ext'] == 'gif' || $config['thumb_ext'] == '') && $config['thumb_keep_animation_frames'] > 1) { if ($this->gifsicle) { if (($error = shell_exec("gifsicle -w --unoptimize -O2 --resize {$this->width}x{$this->height} < " . - escapeshellarg($this->src . '') . " \"#0-{$config['thumb_keep_animation_frames']}\" -o " . - escapeshellarg($this->temp))) || !file_exists($this->temp)) + escapeshellarg($this->src . '') . " \"#0-{$config['thumb_keep_animation_frames']}\" -o " . + escapeshellarg($this->temp))) || !file_exists($this->temp)) { + $this->destroy(); error('Failed to resize image!', null, $error); + } } else { if ($config['convert_manual_orient'] && ($this->format == 'jpg' || $this->format == 'jpeg')) $convert_args = str_replace('-auto-orient', ImageConvert::jpeg_exif_orientation($this->src), $config['convert_args']); @@ -338,8 +340,10 @@ class ImageConvert extends ImageBase { escapeshellarg($this->src), $this->width, $this->height, - escapeshellarg($this->temp)))) || !file_exists($this->temp)) + escapeshellarg($this->temp)))) || !file_exists($this->temp)) { + $this->destroy(); error('Failed to resize image!', null, $error); + } if ($size = $this->get_size($this->temp)) { $this->width = $size[0]; $this->height = $size[1]; @@ -359,8 +363,10 @@ class ImageConvert extends ImageBase { escapeshellarg($this->src . '[0]'), $this->width, $this->height, - escapeshellarg($this->temp)))) || !file_exists($this->temp)) + escapeshellarg($this->temp)))) || !file_exists($this->temp)) { + $this->destroy(); error('Failed to resize image!', null, $error); + } if ($size = $this->get_size($this->temp)) { $this->width = $size[0]; $this->height = $size[1]; diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 2ca7eb55..8940f684 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -379,7 +379,7 @@ function mod_edit_board($boardName) { $query->bindValue(':uri', $board['uri'], PDO::PARAM_INT); $query->execute() or error(db_error($query)); - $query = prepare("SELECT `board`, `post` FROM ``cites`` WHERE `target_board` = :board"); + $query = prepare("SELECT `board`, `post` FROM ``cites`` WHERE `target_board` = :board ORDER BY `board`"); $query->bindValue(':board', $board['uri']); $query->execute() or error(db_error($query)); while ($cite = $query->fetch(PDO::FETCH_ASSOC)) { @@ -391,6 +391,9 @@ function mod_edit_board($boardName) { } } + if (isset($tmp_board)) + $board = $tmp_board; + $query = prepare('DELETE FROM ``cites`` WHERE `board` = :board OR `target_board` = :board'); $query->bindValue(':board', $board['uri']); $query->execute() or error(db_error($query)); @@ -1156,7 +1159,7 @@ function mod_move($originBoard, $postID) { if ($post['has_file']) { // copy image $clone($file_src, sprintf($config['board_path'], $board['uri']) . $config['dir']['img'] . $post['file']); - if (!in_array($post['thumb'], array('spoiler', 'deleted'))) + if (!in_array($post['thumb'], array('spoiler', 'deleted', 'file'))) $clone($file_thumb, sprintf($config['board_path'], $board['uri']) . $config['dir']['thumb'] . $post['thumb']); } @@ -1346,6 +1349,8 @@ function mod_ban_post($board, $delete, $post, $token = false) { modLog("Deleted post #{$post}"); // Rebuild board buildIndex(); + // Rebuild themes + rebuildThemes('post-delete', $board['uri']); } header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); @@ -1409,6 +1414,8 @@ function mod_edit_post($board, $edit_raw_html, $postID) { } buildIndex(); + + rebuildThemes('post', $board); header('Location: ?/' . sprintf($config['board_path'], $board) . $config['dir']['res'] . sprintf($config['file_page'], $post['thread'] ? $post['thread'] : $postID) . '#' . $postID, true, $config['redirect_http']); } else { @@ -1438,7 +1445,8 @@ function mod_delete($board, $post) { modLog("Deleted post #{$post}"); // Rebuild board buildIndex(); - + // Rebuild themes + rebuildThemes('post-delete', $board['uri']); // Redirect header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); } @@ -1459,6 +1467,8 @@ function mod_deletefile($board, $post) { // Rebuild board buildIndex(); + // Rebuild themes + rebuildThemes('post-delete', $board['uri']); // Redirect header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); @@ -1497,6 +1507,9 @@ function mod_spoiler_image($board, $post) { // Rebuild board buildIndex(); + + // Rebuild themes + rebuildThemes('post-delete', $board['uri']); // Redirect header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); @@ -1547,6 +1560,8 @@ function mod_deletebyip($boardName, $post, $global = false) { deletePost($post['id'], false, false); + rebuildThemes('post-delete', $board['uri']); + if ($post['thread']) $threads_to_rebuild[$post['board']][$post['thread']] = true; else diff --git a/inc/template.php b/inc/template.php index 09e27c26..ef688944 100644 --- a/inc/template.php +++ b/inc/template.php @@ -26,7 +26,8 @@ function load_twig() { $loader->setPaths($config['dir']['template']); $twig = new Twig_Environment($loader, array( 'autoescape' => false, - 'cache' => "{$config['dir']['template']}/cache", + 'cache' => is_writable('templates') && (!is_dir('templates/cache') || is_writable('templates/cache')) ? + "{$config['dir']['template']}/cache" : false, 'debug' => $config['debug'] )); $twig->addExtension(new Twig_Extensions_Extension_Tinyboard()); diff --git a/install.php b/install.php index 8453d2ae..a029659e 100644 --- a/install.php +++ b/install.php @@ -1,7 +1,7 @@ vichan-devel-4.0.11-gold'); +define('VERSION', 'v0.9.6-dev-14 + vichan-devel-4.0.12'); require 'inc/functions.php'; @@ -377,6 +377,12 @@ if (file_exists($config['has_installed'])) { } case 'v0.9.6-dev-12': case 'v0.9.6-dev-12 + vichan-devel-4.0.10': + case 'v0.9.6-dev-12 + vichan-devel-4.0.11-gold': + foreach ($boards as &$board) { + query(sprintf("ALTER TABLE ``posts_%s`` ADD INDEX `ip` (`ip`)", $board['uri'])) or error(db_error()); + } + case 'v0.9.6-dev-13': + query("ALTER TABLE ``antispam`` ADD INDEX `expires` (`expires`)") or error(db_error()); case false: // Update version number file_write($config['has_installed'], VERSION); @@ -525,6 +531,13 @@ if ($step == 0) { 'required' => false, 'message' => '(Optional) `identify` was not found or executable; command-line ImageMagick image processing cannot be enabled.', ), + array( + 'category' => 'Image processing', + 'name' => '`gm` (command-line GraphicsMagick)', + 'result' => $can_exec && shell_exec('which gm'), + 'required' => false, + 'message' => '(Optional) `gm` was not found or executable; command-line GraphicsMagick (faster than ImageMagick) cannot be enabled.', + ), array( 'category' => 'Image processing', 'name' => '`gifsicle` (command-line animted GIF thumbnailing)', @@ -539,12 +552,27 @@ if ($step == 0) { 'required' => true, 'message' => 'Tinyboard does not have permission to create directories (boards) here. You will need to chmod (or operating system equivalent) appropriately.' ), + array( + 'category' => 'File permissions', + 'name' => getcwd() . '/templates/cache', + 'result' => is_writable('templates') && (!is_dir('templates/cache') || is_writable('templates/cache')), + 'required' => true, + 'message' => 'You must give Tinyboard permission to create (and write to) the templates/cache directory or performance will be drastically reduced.' + ), array( 'category' => 'File permissions', 'name' => getcwd() . '/inc/instance-config.php', 'result' => is_writable('inc/instance-config.php'), 'required' => false, - 'message' => 'Tinyboard does not have permission to make changes to inc/instance-config.php. To complete the installation, you will be asked to manually copy and paste code into the file instead.' + 'message' => 'Tinyboard does not have permission to make changes to inc/instance-config.php. To complete the installation, you will be asked to manually copy and paste code into the file instead.' + ), + array( + 'category' => 'Misc', + 'name' => 'Caching available (APC, XCache, Memcached or Redis)', + 'result' => extension_loaded('apc') || extension_loaded('xcache') + || extension_loaded('memcached') || extension_loaded('redis'), + 'required' => false, + 'message' => 'You will not be able to enable the additional caching system, designed to minimize SQL queries and significantly improve performance. APC is the recommended method of caching, but XCache, Memcached and Redis are also supported.' ), array( 'category' => 'Misc', diff --git a/install.sql b/install.sql index 84090999..02787984 100644 --- a/install.sql +++ b/install.sql @@ -29,7 +29,8 @@ CREATE TABLE IF NOT EXISTS `antispam` ( `expires` int(11) DEFAULT NULL, `passed` smallint(6) NOT NULL, PRIMARY KEY (`hash`), - KEY `board` (`board`,`thread`) + KEY `board` (`board`,`thread`), + KEY `expires` (`expires`) ) ENGINE=MyISAM DEFAULT CHARSET=ascii COLLATE=ascii_bin; -- -------------------------------------------------------- diff --git a/post.php b/post.php index 60a078ea..867e3595 100644 --- a/post.php +++ b/post.php @@ -75,6 +75,9 @@ if (isset($_POST['delete'])) { } buildIndex(); + + + rebuildThemes('post-delete', $board['uri']); $is_mod = isset($_POST['mod']) && $_POST['mod']; $root = $is_mod ? $config['root'] . $config['file_mod'] . '?/' : $config['root']; @@ -275,14 +278,19 @@ if (isset($_POST['delete'])) { if (!preg_match($config['url_regex'], $post['file_url'])) error($config['error']['invalidimg']); - - $post['extension'] = strtolower(mb_substr($post['file_url'], mb_strrpos($post['file_url'], '.') + 1)); + if (mb_strpos($post['file_url'], '?') !== false) + $url_without_params = mb_substr($post['file_url'], 0, mb_strpos($post['file_url'], '?')); + else + $url_without_params = $post['file_url']; + + $post['extension'] = strtolower(mb_substr($url_without_params, mb_strrpos($url_without_params, '.') + 1)); if (!in_array($post['extension'], $config['allowed_ext']) && !in_array($post['extension'], $config['allowed_ext_files'])) error($config['error']['unknownext']); $post['file_tmp'] = tempnam($config['tmp'], 'url'); function unlink_tmp_file($file) { @unlink($file); + fatal_error_handler(); } register_shutdown_function('unlink_tmp_file', $post['file_tmp']); @@ -307,7 +315,7 @@ if (isset($_POST['delete'])) { fclose($fp); $_FILES['file'] = array( - 'name' => basename($post['file_url']), + 'name' => basename($url_without_params), 'tmp_name' => $post['file_tmp'], 'error' => 0, 'size' => filesize($post['file_tmp']) @@ -520,7 +528,8 @@ if (isset($_POST['delete'])) { escapeshellarg($upload)); if ($config['use_exiftool'] && !$config['strip_exif']) { if ($exiftool_error = shell_exec_error( - 'exiftool -q -orientation=1 -n ' . escapeshellarg($upload))) + 'exiftool -overwrite_original -q -q -orientation=1 -n ' . + escapeshellarg($upload))) error('exiftool failed!', null, $exiftool_error); } else { // TODO: Find another way to remove the Orientation tag from the EXIF profile @@ -583,7 +592,8 @@ if (isset($_POST['delete'])) { if ($config['redraw_image'] || (!@$post['exif_stripped'] && $config['strip_exif'] && ($post['extension'] == 'jpg' || $post['extension'] == 'jpeg'))) { if (!$config['redraw_image'] && $config['use_exiftool']) { - if($error = shell_exec_error('exiftool -ignoreMinorErrors -q -q -all= ' . escapeshellarg($upload))) + if($error = shell_exec_error('exiftool -overwrite_original -ignoreMinorErrors -q -q -all= ' . + escapeshellarg($upload))) error('Could not strip EXIF metadata!', null, $error); } else { $image->to($post['file']); diff --git a/stylesheets/dark_roach.css b/stylesheets/dark_roach.css index 271d6856..f05a89ae 100644 --- a/stylesheets/dark_roach.css +++ b/stylesheets/dark_roach.css @@ -6,7 +6,7 @@ } body { background: #000112; - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAADICAIAAACmkByiAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAGYktHRAD/AP8A/6C9p5MAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfaBgYGLxNHdTqUAAAAeElEQVQoz5WSyw3AMAhDLXboEh2k+2/0eqiKyMdpeuAQgp8BoeO8QlJIClBI5LsNQph8attcxoQLbHgQpL4wOt5Tw4L1zRkZbS90vD96TN9vPWZ2Uf56PWUu481iZ6Jod/SzvS/2Nd4Fxmt2C7XnDZ65MX9nzmNg38Oyc6KXq154AAAAAElFTkSuQmCC), url(data:image/png;base64,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); + background-image: url('img/dark_roach_top.png'), url('img/dark_roach_bg.png'); background-repeat: repeat-x, no-repeat; background-attachment: fixed, fixed; background-position: top, right bottom; diff --git a/stylesheets/img/dark_roach_bg.png b/stylesheets/img/dark_roach_bg.png new file mode 100644 index 00000000..5cc59dff Binary files /dev/null and b/stylesheets/img/dark_roach_bg.png differ diff --git a/stylesheets/img/dark_roach_top.png b/stylesheets/img/dark_roach_top.png new file mode 100644 index 00000000..bdfc1ff9 Binary files /dev/null and b/stylesheets/img/dark_roach_top.png differ diff --git a/stylesheets/img/rect820.png b/stylesheets/img/rect820.png old mode 100755 new mode 100644 diff --git a/stylesheets/img/rect821.png b/stylesheets/img/rect821.png old mode 100755 new mode 100644 diff --git a/stylesheets/notsuba.css b/stylesheets/notsuba.css new file mode 100644 index 00000000..ef9e1057 --- /dev/null +++ b/stylesheets/notsuba.css @@ -0,0 +1,88 @@ +/** +* notsuba.css +* Tagechan is the best +* you are forbidden by law from making any unauthorized edits to this file. I-I'll sue! ;_; +*/ +body { +background: #f2edd0 +} + +a:link, a:visited { +text-decoration: none; +color: #608673; +} + +a:link:hover, a:visited:hover { +color: #DD0000; +} + +a.post_no { +color: #000033; +} + +p.intro a.email span.name { +color: #608673; +} + +p.intro a.email:hover span.name { +color: #DD0000; +} + +h2, div.title, h1 { +color: #800000; +} + +form table tr th { +background: #ded8b7; +} + +div.banner { +background-color: #E04000; +} + +div.post.op hr { +border-color: #608673; +} + +p.intro span.subject { +color: #8a2e2e; +font-weight: 800; +} + +p.intro span.name { +color: #117743; +font-weight: 800; +} + +div.post.reply.highlighted { +background: #dcae9b; +} + +div.post.reply { +background: #e9d1be; +border-color: #dcae9b; +} + +div.ban { +border: 1px solid #B0C2B9; +} + +div.ban h2 { +background: #e9d1be; +color: #608673; +} + +div.pages { +color: #8899AA; +background: #e9d1be; +border-right: 1px solid #8FCCCD; +border-bottom: 1px solid #8FCCCD; +} + +hr { +border-color: #B0C2B9; +} + +div.boardlist { +color: #608673; +} \ No newline at end of file diff --git a/templates/posts.sql b/templates/posts.sql index 4eef3a0d..1e092985 100644 --- a/templates/posts.sql +++ b/templates/posts.sql @@ -28,6 +28,7 @@ CREATE TABLE IF NOT EXISTS ``posts_{{ board }}`` ( UNIQUE KEY `id` (`id`), KEY `thread_id` (`thread`,`id`), KEY `time` (`time`), - FULLTEXT KEY `body` (`body`) + FULLTEXT KEY `body` (`body`), + KEY `ip` (`ip`), ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ; \ No newline at end of file diff --git a/templates/themes/catalog/theme.php b/templates/themes/catalog/theme.php index 96550683..424a813b 100644 --- a/templates/themes/catalog/theme.php +++ b/templates/themes/catalog/theme.php @@ -20,7 +20,7 @@ $b = new Catalog(); $b->build($settings, $board); } - } elseif ($action == 'post-thread' || ($settings['update_on_posts'] && $action == 'post') && in_array($board, $boards)) { + } elseif ($action == 'post-thread' || ($settings['update_on_posts'] && $action == 'post') || ($settings['update_on_posts'] && $action == 'post-delete') && in_array($board, $boards)) { $b = new Catalog(); $b->build($settings, $board); } diff --git a/templates/themes/recent/theme.php b/templates/themes/recent/theme.php index 08d910f8..4bbf1469 100644 --- a/templates/themes/recent/theme.php +++ b/templates/themes/recent/theme.php @@ -24,7 +24,7 @@ $this->excluded = explode(' ', $settings['exclude']); - if ($action == 'all' || $action == 'post' || $action == 'post-thread') + if ($action == 'all' || $action == 'post' || $action == 'post-thread' || $action == 'post-delete') file_write($config['dir']['home'] . $settings['html'], $this->homepage($settings)); } diff --git a/templates/themes/sitemap/info.php b/templates/themes/sitemap/info.php index 43b529fa..0ea2ba9d 100644 --- a/templates/themes/sitemap/info.php +++ b/templates/themes/sitemap/info.php @@ -35,6 +35,15 @@ 'default' => 'hourly', 'size' => '20' ); + + $theme['config'][] = Array( + 'title' => 'Minimum time between regenerating', + 'name' => 'regen_time', + 'type' => 'text', + 'comment' => '(in seconds)', + 'default' => '0', + 'size' => '8' + ); $__boards = listBoards(); $__default_boards = Array(); diff --git a/templates/themes/sitemap/theme.php b/templates/themes/sitemap/theme.php index 226f8357..1e36422d 100644 --- a/templates/themes/sitemap/theme.php +++ b/templates/themes/sitemap/theme.php @@ -11,9 +11,16 @@ // - post (a post has been made) // - thread (a thread has been made) - if ($action != 'post' && $action != 'post-thread') + if ($action != 'post-thread' && $action != 'post-delete') return; + if ($settings['regen_time'] > 0) { + if ($last_gen = @filemtime($settings['path'])) { + if (time() - $last_gen < (int)$settings['regen_time']) + return; // Too soon + } + } + $boards = explode(' ', $settings['boards']); $threads = array();