diff options
Diffstat (limited to 'server/szurubooru/api/post_api.py')
| -rw-r--r-- | server/szurubooru/api/post_api.py | 82 |
1 files changed, 81 insertions, 1 deletions
diff --git a/server/szurubooru/api/post_api.py b/server/szurubooru/api/post_api.py index 7883f5e..4e89f54 100644 --- a/server/szurubooru/api/post_api.py +++ b/server/szurubooru/api/post_api.py @@ -1,3 +1,4 @@ +from math import ceil from datetime import datetime from typing import Dict, List, Optional @@ -5,13 +6,15 @@ from szurubooru import db, errors, model, rest, search from szurubooru.func import ( auth, favorites, + metrics, mime, posts, scores, serialization, + similar, snapshots, tags, - versions, + versions, image_hash, ) _search_executor_config = search.configs.PostSearchConfig() @@ -167,6 +170,14 @@ def update_post(ctx: rest.Context, params: Dict[str, str]) -> rest.Response: if ctx.has_file("thumbnail"): auth.verify_privilege(ctx.user, "posts:edit:thumbnail") posts.update_post_thumbnail(post, ctx.get_file("thumbnail")) + if ctx.has_param("metrics"): + auth.verify_privilege(ctx.user, "metrics:edit:posts") + metrics.update_or_create_post_metrics( + post, ctx.get_param_as_list("metrics")) + if ctx.has_param("metricRanges"): + auth.verify_privilege(ctx.user, "metrics:edit:posts") + metrics.update_or_create_post_metric_ranges( + post, ctx.get_param_as_list("metricRanges")) post.last_edit_time = datetime.utcnow() ctx.session.flush() snapshots.modify(post, ctx.user) @@ -310,3 +321,72 @@ def get_posts_by_image( for distance, post in lookalikes ], } + + +@rest.routes.get("/post/(?P<post_id>[^/]+)/reverse-search/?") +def get_posts_lookalikes( + ctx: rest.Context, params: Dict[str, str] = {} +) -> rest.Response: + auth.verify_privilege(ctx.user, "posts:reverse_search") + limit = ctx.get_param_as_int("limit", default=10, min=1, max=100) + threshold = ctx.get_param_as_float("threshold", default=1, min=0, max=100) + query_text = ctx.get_param_as_string("query", default="") + post_id = _get_post_id(params) + post = posts.get_post_by_id(post_id) + if post.signature is None: + return {"similarPosts": []} + + sig = image_hash.unpack_signature(post.signature.signature) + # limit + 1 because the original post will be excluded + lookalikes = posts.search_by_signature(sig, limit + 1, threshold, query_text) + # exclude the original post: + lookalikes = filter(lambda la: la[1].post_id != post_id, lookalikes) + lookalikes = sorted(lookalikes, key=lambda la: la[0]) + return { + "similarPosts": [ + { + "distance": distance, + "post": _serialize_post(ctx, post), + } + for distance, post in lookalikes + ], + } + + +@rest.routes.get("/posts/median/?") +def get_posts_median( + ctx: rest.Context, _params: Dict[str, str] = {} +) -> rest.Response: + auth.verify_privilege(ctx.user, "posts:list") + _search_executor_config.user = ctx.user + query_text = ctx.get_param_as_string("query", default="") + total_count = _search_executor.count(query_text) + offset = ceil(total_count / 2) - 1 + _, results = _search_executor.execute(query_text, offset, 1) + return { + "query": query_text, + "offset": offset, + "limit": 1, + "total": len(results), + "results": list([_serialize_post(ctx, post) for post in results]) + } + + +@rest.routes.get("/post/(?P<post_id>[^/]+)/similar-by-tags/?") +def get_posts_similar_by_tags( + ctx: rest.Context, params: Dict[str, str] +) -> rest.Response: + auth.verify_privilege(ctx.user, "posts:view:similar") + _search_executor_config.user = ctx.user + query_text = ctx.get_param_as_string("query", default="") + post_id = _get_post_id(params) + post = posts.get_post_by_id(post_id) + limit = ctx.get_param_as_int("limit", default=10, min=1, max=100) + results = similar.find_similar_posts(post, limit, query_text) + return { + "query": query_text, + "limit": limit, + "results": list([ + posts.serialize_micro_post(result, ctx.user) for result in results + ]) + } |