Merge pull request #352 from Diftraku/master
Adding basic Ouroboros API
This commit is contained in:
		
						commit
						9cdc529c13
					
				
							
								
								
									
										391
									
								
								ext/ouroboros_api/main.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										391
									
								
								ext/ouroboros_api/main.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,391 @@ | |||||||
|  | <?php | ||||||
|  | /* | ||||||
|  |  * Name: Ouroboros API | ||||||
|  |  * Author: Diftraku <diftraku[at]derpy.me> | ||||||
|  |  * Description: Ouroboros-like API for Shimmie | ||||||
|  |  * Documentation: | ||||||
|  |  *   Currently working features | ||||||
|  |  *   <ul> | ||||||
|  |  *     <li>Post: | ||||||
|  |  *       <ul> | ||||||
|  |  *         <li>Index/List</li> | ||||||
|  |  *         <li>Show</li> | ||||||
|  |  *       </ul> | ||||||
|  |  *     </li> | ||||||
|  |  *     <li>Tag: | ||||||
|  |  *       <ul> | ||||||
|  |  *         <li>Index/List</li> | ||||||
|  |  *       </ul> | ||||||
|  |  *     </li> | ||||||
|  |  *   </ul> | ||||||
|  |  *   Tested to work with CartonBox using "Danbooru 1.18.x" as site type. | ||||||
|  |  *   Does not work with Andbooru or Danbooru Gallery for reasons beyond me, took me a while to figure rating "u" is bad... | ||||||
|  |  *   Lots of Ouroboros/Danbooru specific values use their defaults (or what I gathered them to be default) | ||||||
|  |  *   and tons of stuff not supported directly in Shimmie is botched to work | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class _SafeOuroborosImage | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * Author | ||||||
|  |      */ | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Post author | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public $author = ''; | ||||||
|  |     /** | ||||||
|  |      * Post author user ID | ||||||
|  |      * @var integer | ||||||
|  |      */ | ||||||
|  |     public $creator_id = null; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Image | ||||||
|  |      */ | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Image height | ||||||
|  |      * @var integer | ||||||
|  |      */ | ||||||
|  |     public $height = null; | ||||||
|  |     /** | ||||||
|  |      * Image width | ||||||
|  |      * @var integer | ||||||
|  |      */ | ||||||
|  |     public $width = null; | ||||||
|  |     /** | ||||||
|  |      * File Size in bytes | ||||||
|  |      * @var integer | ||||||
|  |      */ | ||||||
|  |     public $file_size = null; | ||||||
|  |     /** | ||||||
|  |      * URL to the static file | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public $file_url = ''; | ||||||
|  |     /** | ||||||
|  |      * File MD5 hash | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public $md5 = ''; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Post Meta | ||||||
|  |      */ | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * (Unknown) Change | ||||||
|  |      * @var integer | ||||||
|  |      */ | ||||||
|  |     public $change = null; | ||||||
|  |     /** | ||||||
|  |      * Timestamp for post creation | ||||||
|  |      * @var integer | ||||||
|  |      */ | ||||||
|  |     public $created_at = null; | ||||||
|  |     /** | ||||||
|  |      * Post ID | ||||||
|  |      * @var integer | ||||||
|  |      */ | ||||||
|  |     public $id = null; | ||||||
|  |     /** | ||||||
|  |      * Parent post ID | ||||||
|  |      * @var integer | ||||||
|  |      */ | ||||||
|  |     public $parent_id = null; | ||||||
|  |     /** | ||||||
|  |      * Post content rating | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public $rating = 'q'; | ||||||
|  |     /** | ||||||
|  |      * Post score | ||||||
|  |      * @var integer | ||||||
|  |      */ | ||||||
|  |     public $score = 1; | ||||||
|  |     /** | ||||||
|  |      * Post source | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public $source = ''; | ||||||
|  |     /** | ||||||
|  |      * Post status | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public $status = ''; | ||||||
|  |     /** | ||||||
|  |      * Post tags | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public $tags = ''; | ||||||
|  |     /** | ||||||
|  |      * Flag if the post has child posts | ||||||
|  |      * @var bool | ||||||
|  |      */ | ||||||
|  |     public $has_children = false; | ||||||
|  |     /** | ||||||
|  |      * Flag if the post has comments | ||||||
|  |      * @var bool | ||||||
|  |      */ | ||||||
|  |     public $has_comments = false; | ||||||
|  |     /** | ||||||
|  |      * Flag if the post has notes | ||||||
|  |      * @var bool | ||||||
|  |      */ | ||||||
|  |     public $has_notes = false; | ||||||
|  |     /** | ||||||
|  |      * Post description | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public $description = ''; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Thumbnail | ||||||
|  |      */ | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Thumbnail Height | ||||||
|  |      * @var integer | ||||||
|  |      */ | ||||||
|  |     public $preview_height = null; | ||||||
|  |     /** | ||||||
|  |      * Thumbnail URL | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public $preview_url = ''; | ||||||
|  |     /** | ||||||
|  |      * Thumbnail Width | ||||||
|  |      * @var integer | ||||||
|  |      */ | ||||||
|  |     public $preview_width = null; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Downscaled Image | ||||||
|  |      */ | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Downscaled image height | ||||||
|  |      * @var integer | ||||||
|  |      */ | ||||||
|  |     public $sample_height = null; | ||||||
|  |     /** | ||||||
|  |      * Downscaled image | ||||||
|  |      * @var string | ||||||
|  |      */ | ||||||
|  |     public $sample_url = ''; | ||||||
|  |     /** | ||||||
|  |      * Downscaled image | ||||||
|  |      * @var integer | ||||||
|  |      */ | ||||||
|  |     public $sample_width = null; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Constructor | ||||||
|  |      * @param Image $img | ||||||
|  |      */ | ||||||
|  |     function __construct(Image $img) | ||||||
|  |     { | ||||||
|  |         global $config; | ||||||
|  |         // author
 | ||||||
|  |         $author = $img->get_owner(); | ||||||
|  |         $this->author = $author->name; | ||||||
|  |         $this->creator_id = intval($author->id); | ||||||
|  | 
 | ||||||
|  |         // file
 | ||||||
|  |         $this->height = intval($img->height); | ||||||
|  |         $this->width = intval($img->width); | ||||||
|  |         $this->file_ext = $img->ext; | ||||||
|  |         $this->file_size = intval($img->filesize); | ||||||
|  |         $this->file_url = make_http($img->get_image_link()); | ||||||
|  |         $this->md5 = $img->hash; | ||||||
|  | 
 | ||||||
|  |         // meta
 | ||||||
|  |         $this->change = intval($img->id); //DaFug is this even supposed to do? ChangeID?
 | ||||||
|  |         // Should be JSON specific, just strip this when converting to XML
 | ||||||
|  |         $this->created_at = array('n' => 123456789, 's' => $img->posted_timestamp, 'json_class' => 'Time'); | ||||||
|  |         $this->id = intval($img->id); | ||||||
|  |         $this->parent_id = null; | ||||||
|  |         if (defined('ENABLED_EXTS')) { | ||||||
|  |             if (strstr(ENABLED_EXTS, 'rating') !== false) { | ||||||
|  |                 //$this->rating = $img->rating;
 | ||||||
|  |             } | ||||||
|  |             if (strstr(ENABLED_EXTS, 'numeric_score') !== false) { | ||||||
|  |                 $this->score = $img->numeric_score; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         $this->source = $img->source; | ||||||
|  |         $this->status = 'active'; //not supported in Shimmie... yet
 | ||||||
|  |         $this->tags = $img->get_tag_list(); | ||||||
|  |         $this->has_children = false; | ||||||
|  |         $this->has_comments = false; | ||||||
|  |         $this->has_notes = false; | ||||||
|  | 
 | ||||||
|  |         // thumb
 | ||||||
|  |         $this->preview_height = $config->get_int('thumb_height'); | ||||||
|  |         $this->preview_width = $config->get_int('thumb_width'); | ||||||
|  |         $this->preview_url = make_http($img->get_thumb_link()); | ||||||
|  | 
 | ||||||
|  |         // sample (use the full image here)
 | ||||||
|  |         $this->sample_height = intval($img->height); | ||||||
|  |         $this->sample_width = intval($img->width); | ||||||
|  |         $this->sample_url = make_http($img->get_image_link()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | class _SafeOuroborosTag | ||||||
|  | { | ||||||
|  |     public $ambiguous = false; | ||||||
|  |     public $count = 0; | ||||||
|  |     public $id = 0; | ||||||
|  |     public $name = ''; | ||||||
|  |     public $type = 0; | ||||||
|  | 
 | ||||||
|  |     function __construct(array $tag) | ||||||
|  |     { | ||||||
|  |         $this->count = $tag['count']; | ||||||
|  |         $this->id = $tag['id']; | ||||||
|  |         $this->name = $tag['tag']; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | class OuroborosAPI extends Extension | ||||||
|  | { | ||||||
|  |     private $event; | ||||||
|  |     const ERROR_HTTP_200 = 'Request was successful'; | ||||||
|  |     const ERROR_HTTP_403 = 'Access denied'; | ||||||
|  |     const ERROR_HTTP_404 = 'Not found'; | ||||||
|  |     const ERROR_HTTP_420 = 'Record could not be saved'; | ||||||
|  |     const ERROR_HTTP_421 = 'User is throttled, try again later'; | ||||||
|  |     const ERROR_HTTP_422 = 'The resource is locked and cannot be modified'; | ||||||
|  |     const ERROR_HTTP_423 = 'Resource already exists'; | ||||||
|  |     const ERROR_HTTP_424 = 'The given parameters were invalid'; | ||||||
|  |     const ERROR_HTTP_500 = 'Some unknown error occurred on the server'; | ||||||
|  |     const ERROR_HTTP_503 = 'Server cannot currently handle the request, try again later'; | ||||||
|  | 
 | ||||||
|  |     const ERROR_POST_CREATE_MD5 = 'MD5 mismatch'; | ||||||
|  |     const ERROR_POST_CREATE_DUPE = 'Duplicate'; | ||||||
|  | 
 | ||||||
|  |     public function onPageRequest(PageRequestEvent $event) | ||||||
|  |     { | ||||||
|  |         global $database, $page, $config, $user; | ||||||
|  | 
 | ||||||
|  |         if (preg_match("%\.(xml|json)$%", implode('/', $event->args), $matches) === 1) { | ||||||
|  |             $this->event = $event; | ||||||
|  |             $type = $matches[1]; | ||||||
|  |             if ($type == 'json') { | ||||||
|  |                 $page->set_type('application/json; charset=utf-8'); | ||||||
|  |             } | ||||||
|  |             elseif ($type == 'xml') { | ||||||
|  |                 $page->set_type('text/xml'); | ||||||
|  |             } | ||||||
|  |             $page->set_mode('data'); | ||||||
|  | 
 | ||||||
|  |             if ($event->page_matches('post')) { | ||||||
|  |                 if ($this->match('create')) { | ||||||
|  |                     // Create
 | ||||||
|  |                     $post = array( | ||||||
|  |                         'tags' => !empty($_REQUEST['post']['tags']) ? filter_var($_REQUEST['post']['tags'], FILTER_SANITIZE_STRING) : 'tagme', | ||||||
|  |                         'file' => !empty($_REQUEST['post']['file']) ? filter_var($_REQUEST['post']['file'], FILTER_UNSAFE_RAW) : null, | ||||||
|  |                         'rating' => !empty($_REQUEST['post']['rating']) ? filter_var($_REQUEST['post']['rating'], FILTER_SANITIZE_NUMBER_INT) : null, | ||||||
|  |                         'source' => !empty($_REQUEST['post']['source']) ? filter_var($_REQUEST['post']['source'], FILTER_SANITIZE_URL) : null, | ||||||
|  |                         'sourceurl' => !empty($_REQUEST['post']['sourceurl']) ? filter_var($_REQUEST['post']['sourceurl'], FILTER_SANITIZE_URL) : '', | ||||||
|  |                         'description' => !empty($_REQUEST['post']['description']) ? filter_var($_REQUEST['post']['description'], FILTER_SANITIZE_STRING) : '', | ||||||
|  |                         'is_rating_locked' => !empty($_REQUEST['post']['is_rating_locked']) ? filter_var($_REQUEST['post']['is_rating_locked'], FILTER_SANITIZE_NUMBER_INT) : false, | ||||||
|  |                         'is_note_locked' => !empty($_REQUEST['post']['is_note_locked']) ? filter_var($_REQUEST['post']['is_note_locked'], FILTER_SANITIZE_NUMBER_INT) : false, | ||||||
|  |                         'parent_id' => !empty($_REQUEST['post']['parent_id']) ? filter_var($_REQUEST['post']['parent_id'], FILTER_SANITIZE_NUMBER_INT) : null, | ||||||
|  |                     ); | ||||||
|  |                     $md5 = !empty($_REQUEST['md5']) ? filter_var($_REQUEST['md5'], FILTER_SANITIZE_STRING) : null; | ||||||
|  | 
 | ||||||
|  |                 } | ||||||
|  |                 elseif ($this->match('update')) { | ||||||
|  |                     // Update
 | ||||||
|  |                 } | ||||||
|  |                 elseif ($this->match('show')) { | ||||||
|  |                     // Show
 | ||||||
|  |                     if (isset($_REQUEST['id'])) { | ||||||
|  |                         $id = $_REQUEST['id']; | ||||||
|  |                         $posts = array(); | ||||||
|  |                         $posts[] = new _SafeOuroborosImage(Image::by_id($id)); | ||||||
|  |                         $page->set_data(json_encode($posts)); | ||||||
|  |                     } | ||||||
|  |                     else { | ||||||
|  |                         $page->set_data(json_encode(array())); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 elseif ($this->match('index') || $this->match('list')) { | ||||||
|  |                     // List
 | ||||||
|  |                     $limit = !empty($_REQUEST['limit']) ? intval(filter_var($_REQUEST['limit'], FILTER_SANITIZE_NUMBER_INT)) : 45; | ||||||
|  |                     $p = !empty($_REQUEST['page']) ? intval(filter_var($_REQUEST['page'], FILTER_SANITIZE_NUMBER_INT)) : 1; | ||||||
|  |                     $tags = !empty($_REQUEST['tags']) ? filter_var($_REQUEST['tags'], FILTER_SANITIZE_STRING) : array(); | ||||||
|  |                     if (!empty($tags)) { | ||||||
|  |                         $tags = Tag::explode($tags); | ||||||
|  |                     } | ||||||
|  |                     $start = ( $p - 1 ) * $limit; | ||||||
|  |                     //var_dump($limit, $p, $tags, $start);die();
 | ||||||
|  |                     $results = Image::find_images(max($start, 0), min($limit, 100), $tags); | ||||||
|  |                     $posts = array(); | ||||||
|  |                     foreach ($results as $img) { | ||||||
|  |                         if (!is_object($img)) { | ||||||
|  |                             continue; | ||||||
|  |                         } | ||||||
|  |                         $posts[] = new _SafeOuroborosImage($img); | ||||||
|  |                     } | ||||||
|  |                     $page->set_data(json_encode($posts)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             elseif ($event->page_matches('tag')) { | ||||||
|  |                 if ($this->match('index') || $this->match('list')) { | ||||||
|  |                     $limit = !empty($_REQUEST['limit']) ? intval(filter_var($_REQUEST['limit'], FILTER_SANITIZE_NUMBER_INT)) : 50; | ||||||
|  |                     $p = !empty($_REQUEST['page']) ? intval(filter_var($_REQUEST['page'], FILTER_SANITIZE_NUMBER_INT)) : 1; | ||||||
|  |                     $order = (!empty($_REQUEST['order']) && ($_REQUEST['order'] == 'date' || $_REQUEST['order'] == 'count' || $_REQUEST['order'] == 'name')) ? filter_var($_REQUEST['order'], FILTER_SANITIZE_STRING) : 'date'; | ||||||
|  |                     $id = !empty($_REQUEST['id']) ? intval(filter_var($_REQUEST['id'], FILTER_SANITIZE_NUMBER_INT)) : null; | ||||||
|  |                     $after_id = !empty($_REQUEST['after_id']) ? intval(filter_var($_REQUEST['after_id'], FILTER_SANITIZE_NUMBER_INT)) : null; | ||||||
|  |                     $name = !empty($_REQUEST['name']) ? filter_var($_REQUEST['name'], FILTER_SANITIZE_STRING) : ''; | ||||||
|  |                     $name_pattern = !empty($_REQUEST['name_pattern']) ? filter_var($_REQUEST['name_pattern'], FILTER_SANITIZE_STRING) : ''; | ||||||
|  |                     $start = ( $p - 1 ) * $limit; | ||||||
|  |                     $tag_data = array(); | ||||||
|  |                     switch ($order) { | ||||||
|  |                         case 'name': | ||||||
|  |                             $tag_data = $database->get_col($database->scoreql_to_sql(" | ||||||
|  |                                 SELECT DISTINCT | ||||||
|  |                                     id, SCORE_STRNORM(substr(tag, 1, 1)), count | ||||||
|  |                                 FROM tags | ||||||
|  |                                 WHERE count >= :tags_min | ||||||
|  |                                 ORDER BY SCORE_STRNORM(substr(tag, 1, 1)) LIMIT :start, :max_items | ||||||
|  |                             "), array("tags_min" => $config->get_int('tags_min'), 'start' => $start, 'max_items' => $limit));
 | ||||||
|  |                             break; | ||||||
|  |                         case 'count': | ||||||
|  |                             $tag_data = $database->get_all(" | ||||||
|  |                                 SELECT id, tag, count | ||||||
|  |                                 FROM tags | ||||||
|  |                                 WHERE count >= :tags_min | ||||||
|  |                                 ORDER BY count DESC, tag ASC LIMIT :start, :max_items | ||||||
|  |                                 ", array("tags_min" => $config->get_int('tags_min'), 'start' => $start, 'max_items' => $limit));
 | ||||||
|  |                             break; | ||||||
|  |                         case 'date': | ||||||
|  |                             $tag_data = $database->get_all(" | ||||||
|  |                                 SELECT id, tag, count | ||||||
|  |                                 FROM tags | ||||||
|  |                                 WHERE count >= :tags_min | ||||||
|  |                                 ORDER BY count DESC, tag ASC LIMIT :start, :max_items | ||||||
|  |                                 ", array("tags_min" => $config->get_int('tags_min'), 'start' => $start, 'max_items' => $limit));
 | ||||||
|  |                             break; | ||||||
|  |                     } | ||||||
|  |                     $tags = array(); | ||||||
|  |                     foreach ($tag_data as $tag) { | ||||||
|  |                         if (!is_array($tag)) { | ||||||
|  |                             continue; | ||||||
|  |                         } | ||||||
|  |                         $tags[] = new _SafeOuroborosTag($tag); | ||||||
|  |                     } | ||||||
|  |                     $page->set_data(json_encode($tags)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private function match($page) { | ||||||
|  |         return (preg_match("%{$page}\.(xml|json)$%", implode('/', $this->event->args), $matches) === 1); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user