예제 #1
0
 public function recent_comments()
 {
     $recent = new Rails\ActiveRecord\Collection();
     # reverse_order to fetch last 6 comments
     # reversed in the last to return from lowest id
     if ($this->comments) {
         $recent->merge(array_slice($this->comments->members(), -6));
     }
     return $recent;
 }
예제 #2
0
파일: Artist.php 프로젝트: JCQS04/myimouto
 public static function find_all_by_url($url)
 {
     $url = ArtistUrl::normalize($url);
     $artists = new Rails\ActiveRecord\Collection();
     while ($artists->blank() && strlen($url) > 10) {
         $u = str_replace('*', '%', $url) . '%';
         $artists->merge(Artist::where("artists.alias_id IS NULL AND artists_urls.normalized_url LIKE ?", $u)->joins("JOIN artists_urls ON artists_urls.artist_id = artists.id")->order("artists.name")->take());
         # Remove duplicates based on name
         $artists->unique('name');
         $url = dirname($url);
     }
     return $artists->slice(0, 20);
 }
예제 #3
0
 public function index()
 {
     $this->set_title('Notes');
     if ($this->params()->post_id) {
         $this->posts = Post::where("id = ?", $this->params()->post_id)->order("last_noted_at DESC")->paginate($this->page_number(), 100);
     } else {
         $this->posts = Post::where("last_noted_at IS NOT NULL")->order("last_noted_at DESC")->paginate($this->page_number(), 16);
     }
     # iTODO:
     $this->respondTo(['html', 'xml' => function () {
         $notes = new Rails\ActiveRecord\Collection();
         foreach ($this->posts as $post) {
             $notes->merge($post->notes);
         }
         $this->render(['xml' => $notes, 'root' => "notes"]);
     }, 'json' => function () {
         // {render :json => @posts.map {|x| x.notes}.flatten.to_json}
     }]);
 }
예제 #4
0
 public function index()
 {
     $this->set_title('Comments');
     if ($this->request()->format() == "json" || $this->request()->format() == "xml") {
         $this->comments = Comment::generate_sql($this->params()->all())->order("id DESC")->paginate($this->page_number(), 25);
         $this->respond_to_list("comments");
     } else {
         $this->posts = Post::where("last_commented_at IS NOT NULL")->order("last_commented_at DESC")->paginate($this->page_number(), 10);
         $comments = new Rails\ActiveRecord\Collection();
         $this->posts->each(function ($post) use($comments) {
             $comments->merge($post->recent_comments());
         });
         $newest_comment = $comments->max(function ($a, $b) {
             return $a->created_at > $b->created_at ? $a : $b;
         });
         if (!current_user()->is_anonymous() && $newest_comment && current_user()->last_comment_read_at < $newest_comment->created_at) {
             current_user()->updateAttribute('last_comment_read_at', $newest_comment->created_at);
         }
         $this->posts->deleteIf(function ($x) {
             return !$x->can_be_seen_by(current_user(), array('show_deleted' => true));
         });
     }
 }
예제 #5
0
 public static function similar_images($options = [])
 {
     $errors = [];
     $local_service = CONFIG()->local_image_service;
     $services = $options['services'];
     $services_by_server = [];
     foreach ($services as $service) {
         if (!isset(CONFIG()->image_service_list[$service]) || !($server = CONFIG()->image_service_list[$service])) {
             $errors[] = ['services' => [$service], 'message' => $service . " is an unknown service"];
             continue;
         }
         if (!isset($services_by_server[$server])) {
             $services_by_server[$server] = [];
         }
         $services_by_server[$server][] = $service;
     }
     if (!$services_by_server) {
         return ['posts' => new Rails\ActiveRecord\Collection(), 'posts_external' => new Rails\ActiveRecord\Collection(), 'similarity' => [], 'services' => [], 'errors' => 'No service selected/no local service'];
     }
     # If the source is a local post, read the preview and send it with the request.
     if ($options['type'] == 'post') {
         $source_file = $options['source']->preview_path();
     } elseif ($options['type'] == 'file') {
         $source_file = $options['source'];
     }
     $server_threads = [];
     $server_responses = [];
     $curl_opts = [CURLOPT_TIMEOUT => 5, CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true];
     $mh = curl_multi_init();
     $chk = -1;
     foreach ($services_by_server as $services_list) {
         $chk++;
         $search_url = null;
         if ($options['type'] == 'url') {
             $search_url = $options['source'];
         }
         if ($options['type'] == 'post' && CONFIG()->image_service_local_searches_use_urls) {
             $search_url = $options['source']['preview_url'];
         }
         $params = [];
         if ($search_url) {
             $params['url'] = $search_url;
         } else {
             if (function_exists('curl_file_create')) {
                 // PHP v5.5.* fix
                 $params['file'] = curl_file_create($source_file);
             } else {
                 $params['file'] = '@' . $source_file;
             }
         }
         foreach ($services_list as $k => $s) {
             $params["service[{$k}]"] = $s;
         }
         $chn = 'ch' . $chk;
         ${$chn} = curl_init($server);
         curl_setopt_array(${$chn}, $curl_opts);
         curl_setopt(${$chn}, CURLOPT_POSTFIELDS, $params);
         curl_setopt(${$chn}, CURLOPT_CONNECTTIMEOUT, 4);
         curl_setopt(${$chn}, CURLOPT_HTTPHEADER, ['Host: ' . parse_url($server)['host']]);
         curl_multi_add_handle($mh, ${$chn});
     }
     $ch_count = $chk;
     $active = null;
     do {
         $ret = curl_multi_exec($mh, $active);
     } while ($ret == CURLM_CALL_MULTI_PERFORM);
     while ($active && $ret == CURLM_OK) {
         if (curl_multi_select($mh) != -1) {
             usleep(100);
         }
         do {
             $mrc = curl_multi_exec($mh, $active);
         } while ($mrc == CURLM_CALL_MULTI_PERFORM);
     }
     $posts = new Rails\ActiveRecord\Collection();
     $posts_external = new Rails\ActiveRecord\Collection();
     $similarity = [];
     $preview_url = "";
     $next_id = 1;
     $server_list = array_keys($services_by_server);
     /**
      * Is there a class for PHP that can nicely handle XML?
      */
     $get_attr = function ($xml, $attr) {
         $obj = $xml->attributes()->{$attr};
         if ($obj) {
             $obj = (array) $obj;
             return $obj[0];
         }
         return null;
     };
     foreach (range(0, $ch_count) as $i) {
         $chn = 'ch' . $i;
         $server = $server_list[$i];
         $resp = curl_multi_getcontent(${$chn});
         if (!$resp) {
             $curl_err = curl_error(${$chn});
             if (preg_match('/^Operation timed out/', $curl_err)) {
                 $err_msg = 'timed out';
                 Rails::log()->notice("[SimilarImages] cURL timed out: " . $curl_err);
             } else {
                 $err_msg = 'empty response';
                 Rails::log()->warning(sprintf("[SimilarImages] cURL error: (%s) %s", curl_errno(${$chn}), $curl_err));
             }
             $errors[$server] = ['message' => $err_msg];
             continue;
         }
         try {
             $doc = new SimpleXMLElement($resp);
         } catch (Exception $e) {
             ob_start();
             var_dump(curl_getinfo(${$chn}));
             $info = ob_get_clean();
             Rails::log()->error("Similar Images Error\ncURL Error: " . curl_error(${$chn}) . "\ncURL Info:\n" . $info);
             Rails::log()->exception($e);
             $errors[$server] = ['message' => 'parse error'];
             continue;
         }
         if ($doc->getName() == 'error') {
             $errors[$server] = ['message' => $doc->message];
             continue;
         } elseif ($doc->getName() != 'matches') {
             $errors[$server] = ['message' => 'invalid response'];
             continue;
         }
         $threshold = !empty($options['threshold']) ? $options['threshold'] : (double) $get_attr($doc, 'threshold');
         foreach ($doc->match as $element) {
             $sim = (double) $get_attr($element, 'sim');
             if ($sim >= $threshold and $sim > 0) {
                 $service = $get_attr($element, 'service');
                 $image = $element->post;
                 $id = $get_attr($image, 'id');
                 $md5 = $get_attr($image, 'md5');
                 if ($service == $local_service) {
                     $post = Post::where('id = ?', $id);
                     if ($post && is_object($options['source']) && $post->id != $options['source']->id) {
                         $posts[] = $post;
                         $similarity[spl_object_hash($post)] = $sim;
                     }
                 } elseif ($service) {
                     $post = new ExternalPost();
                     $post->id = (string) $next_id;
                     $next_id++;
                     $post->md5 = $md5;
                     $post->preview_url = $get_attr($element, 'preview');
                     if ($service == 'gelbooru.com') {
                         # hack
                         $post->url = "http://" . $service . "/index.php?page=post&s=view&id=" . $id;
                     } elseif ($service == "e-shuushuu.net") {
                         # hack
                         $post->url = "http://" . $service . "/image/" . $id . "/";
                     } else {
                         $post->url = "http://" . $service . "/post/show/" . $id;
                     }
                     $post->sample_url = $get_attr($image, 'sample_url') ?: $post->url;
                     $post->service = $service;
                     $post->width = $get_attr($image, 'width');
                     $post->height = $get_attr($image, 'height');
                     $post->tags = $get_attr($image, 'tags') ?: '';
                     if (empty($options['data_search'])) {
                         $post->rating = $get_attr($image, 'rating') ?: 's';
                     } else {
                         $post->rating = $get_attr($image, 'rating') ?: false;
                     }
                     # Extra attributes.
                     if (!empty($options['data_search'])) {
                         $post->original_preview_url = $get_attr($image, 'preview_url');
                         $post->id = $get_attr($image, 'id');
                         $post->author = $get_attr($image, 'author');
                         $post->created_at = $get_attr($image, 'created_at');
                         $post->creator_id = $get_attr($image, 'creator_id');
                         $post->file_size = $get_attr($image, 'file_size');
                         $post->file_url = $get_attr($image, 'file_url');
                         $post->score = $get_attr($image, 'score');
                         $post->source = $get_attr($image, 'source');
                         $post->icon_path = ExternalPost::get_service_icon($service);
                         if (preg_match('/\\.png$/', $post->file_url)) {
                             $post->has_png = true;
                         }
                     }
                     $posts_external[] = $post;
                     $similarity[spl_object_hash($post)] = $sim;
                 }
             }
         }
     }
     $posts->sort(function ($a, $b) {
         $aid = spl_object_hash($a);
         $bid = spl_object_hash($b);
         if ($similarity[$aid] == $similarity[$bid]) {
             return 0;
         } elseif ($similarity[$aid] > $similarity[$bid]) {
             return 1;
         }
         return -1;
     });
     foreach ($errors as $server => $error) {
         if (empty($error['services'])) {
             $error['services'] = !empty($services_by_server[$server]) ? $services_by_server[$server] : $server;
         }
     }
     $ret = ['posts' => $posts, 'posts_external' => $posts_external, 'similarity' => $similarity, 'services' => $services, 'errors' => $errors];
     if ($options['type'] == 'post') {
         $ret['source'] = $options['source'];
         $ret['similarity'][spl_object_hash($options['source'])] = 'Original';
         $ret['search_id'] = $ret['source']->id;
     } else {
         $post = new ExternalPost();
         # $post->md5 = $md5;
         $post->preview_url = $options['source_thumb'];
         if (!empty($options['full_url'])) {
             $post->url = $options['full_url'];
         } elseif (!empty($options['url'])) {
             $post->url = $options['url'];
         } elseif (!empty($options['source_thumb'])) {
             $post->url = $options['source_thumb'];
         }
         $post->id = 'source';
         $post->rating = 'q';
         $ret['search_id'] = 'source';
         # Don't include the source URL if it's a data: url; it can be very large and isn't useful.
         if (substr($post->url, 0, 5) == "data:") {
             $post->url = "";
         }
         list($source_width, $source_height) = getimagesize($source_file);
         # Since we lose access to the original image when we redirect to a saved search,
         # the original dimensions can be passed as parameters so we can still display
         # the original size.    This can also be used by user scripts to include the
         # size of the real image when a thumbnail is passed.
         $post->width = !empty($options['width']) ? $options['width'] : $source_width;
         $post->height = !empty($options['height']) ? $options['height'] : $source_height;
         $ret['external_source'] = $post;
         $ret['similarity'][spl_object_hash($post)] = "Original";
     }
     return $ret;
 }
예제 #6
0
 public function moderate()
 {
     $this->set_title('Moderation Queue');
     if ($this->request()->isPost()) {
         $posts = new Rails\ActiveRecord\Collection();
         if ($this->params()->ids) {
             foreach (array_keys($this->params()->ids) as $post_id) {
                 $post = Post::find($post_id);
                 if ($this->params()->commit == "Approve") {
                     $post->approve(current_user()->id);
                 } elseif ($this->params()->commit == "Delete") {
                     $post->destroy_with_reason($this->params()->reason ? $this->params()->reason : $this->params()->reason2, current_user());
                     # Include post data for the parent: deleted posts aren't counted as children, so
                     # their has_children attribute may change.
                     if ($post->parent_id) {
                         $posts[] = $post->get_parent();
                     }
                 }
                 # Post may have been permanently deleted.
                 if (!CONFIG()->delete_posts_permanently) {
                     $post->reload();
                 }
                 $posts[] = $post;
             }
         }
         $posts->unique();
         if ($this->request()->format() == "json" || $this->request()->format() == "xml") {
             $api_data = Post::batch_api_data($posts->members());
         } else {
             $api_data = array();
         }
         if ($this->params()->commit == "Approve") {
             $this->respond_to_success("Post approved", "#moderate", array('api' => $api_data));
         } elseif ($this->params()->commit == "Delete") {
             $this->respond_to_success("Post deleted", "#moderate", array('api' => $api_data));
         }
     } else {
         if ($this->params()->query) {
             list($sql, $params) = Post::generate_sql($this->params()->query, array('pending' => true, 'order' => "id desc"));
             $this->pending_posts = Post::findBySql($sql, $params);
             list($sql, $params) = Post::generate_sql($this->params()->query, array('flagged' => true, 'order' => "id desc"));
             $this->flagged_posts = Post::findBySql($sql, $params);
         } else {
             $this->pending_posts = Post::where("status = 'pending'")->order("id desc")->take();
             $this->flagged_posts = Post::where("status = 'flagged'")->order("id desc")->take();
         }
     }
 }