The version of vichan running on lainchan.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

192 line
5.0KB

  1. <?php
  2. /*
  3. * Copyright (c) 2010-2013 Tinyboard Development Group
  4. */
  5. defined('TINYBOARD') or exit;
  6. /**
  7. * Class for generating json API compatible with 4chan API
  8. */
  9. class Api {
  10. function __construct(){
  11. global $config;
  12. /**
  13. * Translation from local fields to fields in 4chan-style API
  14. */
  15. $this->config = $config;
  16. $this->postFields = array(
  17. 'id' => 'no',
  18. 'thread' => 'resto',
  19. 'subject' => 'sub',
  20. 'body' => 'com',
  21. 'email' => 'email',
  22. 'name' => 'name',
  23. 'trip' => 'trip',
  24. 'capcode' => 'capcode',
  25. 'time' => 'time',
  26. 'omitted' => 'omitted_posts',
  27. 'omitted_images' => 'omitted_images',
  28. 'replies' => 'replies',
  29. 'images' => 'images',
  30. 'sticky' => 'sticky',
  31. 'locked' => 'locked',
  32. 'cycle' => 'cyclical',
  33. 'bump' => 'last_modified',
  34. 'embed' => 'embed',
  35. );
  36. $this->threadsPageFields = array(
  37. 'id' => 'no',
  38. 'bump' => 'last_modified'
  39. );
  40. $this->fileFields = array(
  41. 'thumbheight' => 'tn_h',
  42. 'thumbwidth' => 'tn_w',
  43. 'height' => 'h',
  44. 'width' => 'w',
  45. 'size' => 'fsize',
  46. );
  47. if (isset($config['api']['extra_fields']) && gettype($config['api']['extra_fields']) == 'array'){
  48. $this->postFields = array_merge($this->postFields, $config['api']['extra_fields']);
  49. }
  50. }
  51. private static $ints = array(
  52. 'no' => 1,
  53. 'resto' => 1,
  54. 'time' => 1,
  55. 'tn_w' => 1,
  56. 'tn_h' => 1,
  57. 'w' => 1,
  58. 'h' => 1,
  59. 'fsize' => 1,
  60. 'omitted_posts' => 1,
  61. 'omitted_images' => 1,
  62. 'replies' => 1,
  63. 'images' => 1,
  64. 'sticky' => 1,
  65. 'locked' => 1,
  66. 'last_modified' => 1
  67. );
  68. private function translateFields($fields, $object, &$apiPost) {
  69. foreach ($fields as $local => $translated) {
  70. if (!isset($object->$local))
  71. continue;
  72. $toInt = isset(self::$ints[$translated]);
  73. $val = $object->$local;
  74. if ($val !== null && $val !== '') {
  75. $apiPost[$translated] = $toInt ? (int) $val : $val;
  76. }
  77. }
  78. }
  79. private function translateFile($file, $post, &$apiPost) {
  80. $this->translateFields($this->fileFields, $file, $apiPost);
  81. $apiPost['filename'] = @substr($file->name, 0, strrpos($file->name, '.'));
  82. $dotPos = strrpos($file->file, '.');
  83. $apiPost['ext'] = substr($file->file, $dotPos);
  84. $apiPost['tim'] = substr($file->file, 0, $dotPos);
  85. if (isset ($file->hash) && $file->hash) {
  86. $apiPost['md5'] = base64_encode(hex2bin($file->hash));
  87. }
  88. else if (isset ($post->filehash) && $post->filehash) {
  89. $apiPost['md5'] = base64_encode(hex2bin($post->filehash));
  90. }
  91. }
  92. private function translatePost($post, $threadsPage = false) {
  93. global $config, $board;
  94. $apiPost = array();
  95. $fields = $threadsPage ? $this->threadsPageFields : $this->postFields;
  96. $this->translateFields($fields, $post, $apiPost);
  97. if (isset($config['poster_ids']) && $config['poster_ids']) $apiPost['id'] = poster_id($post->ip, $post->thread, $board['uri']);
  98. if ($threadsPage) return $apiPost;
  99. // Handle country field
  100. if (isset($post->body_nomarkup) && $this->config['country_flags']) {
  101. $modifiers = extract_modifiers($post->body_nomarkup);
  102. if (isset($modifiers['flag']) && isset($modifiers['flag alt']) && preg_match('/^[a-z]{2}$/', $modifiers['flag'])) {
  103. $country = strtoupper($modifiers['flag']);
  104. if ($country) {
  105. $apiPost['country'] = $country;
  106. $apiPost['country_name'] = $modifiers['flag alt'];
  107. }
  108. }
  109. }
  110. if ($config['slugify'] && !$post->thread) {
  111. $apiPost['semantic_url'] = $post->slug;
  112. }
  113. // Handle files
  114. // Note: 4chan only supports one file, so only the first file is taken into account for 4chan-compatible API.
  115. if (isset($post->files) && $post->files && !$threadsPage) {
  116. $file = $post->files[0];
  117. $this->translateFile($file, $post, $apiPost);
  118. if (sizeof($post->files) > 1) {
  119. $extra_files = array();
  120. foreach ($post->files as $i => $f) {
  121. if ($i == 0) continue;
  122. $extra_file = array();
  123. $this->translateFile($f, $post, $extra_file);
  124. $extra_files[] = $extra_file;
  125. }
  126. $apiPost['extra_files'] = $extra_files;
  127. }
  128. }
  129. return $apiPost;
  130. }
  131. function translateThread(Thread $thread, $threadsPage = false) {
  132. $apiPosts = array();
  133. $op = $this->translatePost($thread, $threadsPage);
  134. if (!$threadsPage) $op['resto'] = 0;
  135. $apiPosts['posts'][] = $op;
  136. foreach ($thread->posts as $p) {
  137. $apiPosts['posts'][] = $this->translatePost($p, $threadsPage);
  138. }
  139. return $apiPosts;
  140. }
  141. function translatePage(array $threads) {
  142. $apiPage = array();
  143. foreach ($threads as $thread) {
  144. $apiPage['threads'][] = $this->translateThread($thread);
  145. }
  146. return $apiPage;
  147. }
  148. function translateCatalogPage(array $threads, $threadsPage = false) {
  149. $apiPage = array();
  150. foreach ($threads as $thread) {
  151. $ts = $this->translateThread($thread, $threadsPage);
  152. $apiPage['threads'][] = current($ts['posts']);
  153. }
  154. return $apiPage;
  155. }
  156. function translateCatalog($catalog, $threadsPage = false) {
  157. $apiCatalog = array();
  158. foreach ($catalog as $page => $threads) {
  159. $apiPage = $this->translateCatalogPage($threads, $threadsPage);
  160. $apiPage['page'] = $page;
  161. $apiCatalog[] = $apiPage;
  162. }
  163. return $apiCatalog;
  164. }
  165. }