The version of vichan running on lainchan.org
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

268 рядки
8.0KB

  1. <?php
  2. require 'info.php';
  3. function catalog_build($action, $settings, $board) {
  4. global $config;
  5. $b = new Catalog($settings);
  6. $boards = explode(' ', $settings['boards']);
  7. // Possible values for $action:
  8. // - all (rebuild everything, initialization)
  9. // - news (news has been updated)
  10. // - boards (board list changed)
  11. // - post (a reply has been made)
  12. // - post-thread (a thread has been made)
  13. if ($action === 'all') {
  14. foreach ($boards as $board) {
  15. $b = new Catalog();
  16. $action = generation_strategy("sb_catalog", array($board));
  17. if ($action == 'delete') {
  18. file_unlink($config['dir']['home'] . $board . '/catalog.html');
  19. file_unlink($config['dir']['home'] . $board . '/index.rss');
  20. }
  21. elseif ($action == 'rebuild') {
  22. $b->build($settings, $board);
  23. }
  24. }
  25. } elseif ($action == 'post-thread' || ($settings['update_on_posts'] && $action == 'post') || ($settings['update_on_posts'] && $action == 'post-delete') && in_array($board, $boards)) {
  26. $b = new Catalog();
  27. $action = generation_strategy("sb_catalog", array($board));
  28. if ($action == 'delete') {
  29. file_unlink($config['dir']['home'] . $board . '/catalog.html');
  30. file_unlink($config['dir']['home'] . $board . '/index.rss');
  31. }
  32. elseif ($action == 'rebuild') {
  33. $b->build($settings, $board);
  34. }
  35. }
  36. // FIXME: Check that Ukko is actually enabled
  37. if ($settings['enable_ukko'] && (
  38. $action === 'all' || $action === 'post' ||
  39. $action === 'post-thread' || $action === 'post-delete'))
  40. {
  41. $b->buildUkko();
  42. }
  43. // FIXME: Check that Rand is actually enabled
  44. if ($settings['enable_rand'] && (
  45. $action === 'all' || $action === 'post' ||
  46. $action === 'post-thread' || $action === 'post-delete'))
  47. {
  48. $b->buildRand();
  49. }
  50. }
  51. // Wrap functions in a class so they don't interfere with normal Tinyboard operations
  52. class Catalog {
  53. private $settings;
  54. // Cache for threads from boards that have already been processed
  55. private $threadsCache = array();
  56. public function __construct($settings) {
  57. $this->settings = $settings;
  58. }
  59. /**
  60. * Build and save the HTML of the catalog for the Ukko theme
  61. */
  62. public function buildUkko() {
  63. global $config;
  64. $ukkoSettings = themeSettings('ukko');
  65. $queries = array();
  66. $threads = array();
  67. $exclusions = explode(' ', $ukkoSettings['exclude']);
  68. $boards = array_diff(listBoards(true), $exclusions);
  69. foreach ($boards as $b) {
  70. if (array_key_exists($b, $this->threadsCache)) {
  71. $threads = array_merge($threads, $this->threadsCache[$b]);
  72. } else {
  73. $queries[] = $this->buildThreadsQuery($b);
  74. }
  75. }
  76. // Fetch threads from boards that haven't beenp processed yet
  77. if (!empty($queries)) {
  78. $sql = implode(' UNION ALL ', $queries);
  79. $res = query($sql) or error(db_error());
  80. $threads = array_merge($threads, $res->fetchAll(PDO::FETCH_ASSOC));
  81. }
  82. // Sort in bump order
  83. usort($threads, function($a, $b) {
  84. return strcmp($b['bump'], $a['bump']);
  85. });
  86. // Generate data for the template
  87. $recent_posts = $this->generateRecentPosts($threads);
  88. $this->saveForBoard($ukkoSettings['uri'], $recent_posts,
  89. $config['root'] . $ukkoSettings['uri']);
  90. }
  91. /**
  92. * Build and save the HTML of the catalog for the Rand theme
  93. */
  94. public function buildRand() {
  95. global $config;
  96. $randSettings = themeSettings('rand');
  97. $queries = array();
  98. $threads = array();
  99. $exclusions = explode(' ', $randSettings['exclude']);
  100. $boards = array_diff(listBoards(true), $exclusions);
  101. foreach ($boards as $b) {
  102. if (array_key_exists($b, $this->threadsCache)) {
  103. $threads = array_merge($threads, $this->threadsCache[$b]);
  104. } else {
  105. $queries[] = $this->buildThreadsQuery($b);
  106. }
  107. }
  108. // Fetch threads from boards that haven't beenp processed yet
  109. if (!empty($queries)) {
  110. $sql = implode(' UNION ALL ', $queries);
  111. $res = query($sql) or error(db_error());
  112. $threads = array_merge($threads, $res->fetchAll(PDO::FETCH_ASSOC));
  113. }
  114. // Sort in bump order
  115. usort($threads, function($a, $b) {
  116. return strcmp($b['bump'], $a['bump']);
  117. });
  118. // Generate data for the template
  119. $recent_posts = $this->generateRecentPosts($threads);
  120. $this->saveForBoard($randSettings['uri'], $recent_posts,
  121. $config['root'] . $randSettings['uri']);
  122. }
  123. /**
  124. * Build and save the HTML of the catalog for the given board
  125. */
  126. public function build($board_name) {
  127. if (!openBoard($board_name)) {
  128. error(sprintf(_("Board %s doesn't exist"), $post['board']));
  129. }
  130. if (array_key_exists($board_name, $this->threadsCache)) {
  131. $threads = $this->threadsCache[$board_name];
  132. } else {
  133. $sql = $this->buildThreadsQuery($board_name);
  134. $query = query($sql . ' ORDER BY `bump` DESC') or error(db_error());
  135. $threads = $query->fetchAll(PDO::FETCH_ASSOC);
  136. // Save for posterity
  137. $this->threadsCache[$board_name] = $threads;
  138. }
  139. // Generate data for the template
  140. $recent_posts = $this->generateRecentPosts($threads);
  141. $this->saveForBoard($board_name, $recent_posts);
  142. }
  143. private function buildThreadsQuery($board) {
  144. $sql = "SELECT *, `id` AS `thread_id`, " .
  145. "(SELECT COUNT(`id`) FROM ``posts_$board`` WHERE `thread` = `thread_id`) AS `reply_count`, " .
  146. "(SELECT SUM(`num_files`) FROM ``posts_$board`` WHERE `thread` = `thread_id` AND `num_files` IS NOT NULL) AS `image_count`, " .
  147. "'$board' AS `board` FROM ``posts_$board`` WHERE `thread` IS NULL";
  148. return $sql;
  149. }
  150. private function generateRecentPosts($threads) {
  151. global $config, $board;
  152. $posts = array();
  153. foreach ($threads as $post) {
  154. if ($board['uri'] !== $post['board']) {
  155. openBoard($post['board']);
  156. }
  157. $post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . link_for($post);
  158. $post['board_name'] = $board['name'];
  159. if ($post['embed'] && preg_match('/^https?:\/\/(\w+\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([a-zA-Z0-9\-_]{10,11})(&.+)?$/i', $post['embed'], $matches)) {
  160. $post['youtube'] = $matches[2];
  161. }
  162. if (isset($post['files']) && $post['files']) {
  163. $files = json_decode($post['files']);
  164. if ($files[0]) {
  165. if ($files[0]->file == 'deleted') {
  166. if (count($files) > 1) {
  167. foreach ($files as $file) {
  168. if (($file == $files[0]) || ($file->file == 'deleted'))
  169. continue;
  170. $post['file'] = $config['uri_thumb'] . $file->thumb;
  171. }
  172. if (empty($post['file']))
  173. $post['file'] = $config['image_deleted'];
  174. } else {
  175. $post['file'] = $config['image_deleted'];
  176. }
  177. } else if($files[0]->thumb == 'spoiler') {
  178. $post['file'] = '/' . $config['spoiler_image'];
  179. } else {
  180. $post['file'] = $config['uri_thumb'] . $files[0]->thumb;
  181. }
  182. }
  183. } else {
  184. $post['file'] = $config['root'] . $config['image_deleted'];
  185. }
  186. if (empty($post['image_count']))
  187. $post['image_count'] = 0;
  188. $post['pubdate'] = date('r', $post['time']);
  189. $posts[] = $post;
  190. }
  191. return $posts;
  192. }
  193. private function saveForBoard($board_name, $recent_posts, $board_link = null) {
  194. global $board, $config;
  195. if ($board_link === null) {
  196. $board_link = $config['root'] . $board['dir'];
  197. }
  198. $required_scripts = array('js/jquery.min.js', 'js/jquery.mixitup.min.js',
  199. 'js/catalog.js');
  200. // Include scripts that haven't been yet included
  201. foreach($required_scripts as $i => $s) {
  202. if (!in_array($s, $config['additional_javascript']))
  203. $config['additional_javascript'][] = $s;
  204. }
  205. file_write($config['dir']['home'] . $board_name . '/catalog.html', Element('themes/catalog/catalog.html', Array(
  206. 'settings' => $this->settings,
  207. 'config' => $config,
  208. 'boardlist' => createBoardlist(),
  209. 'recent_images' => array(),
  210. 'recent_posts' => $recent_posts,
  211. 'stats' => array(),
  212. 'board' => $board_name,
  213. 'link' => $board_link
  214. )));
  215. file_write($config['dir']['home'] . $board_name . '/index.rss', Element('themes/catalog/index.rss', Array(
  216. 'config' => $config,
  217. 'recent_posts' => $recent_posts,
  218. 'board' => $board
  219. )));
  220. }
  221. }