├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src └── main ├── java └── site │ └── purrbot │ └── api │ ├── ImageAPI.java │ ├── ImageUtil.java │ ├── TextOWOifier.java │ ├── mapper │ └── GsonMapper.java │ └── objects │ ├── ErrorResponse.java │ ├── ImgLinkListResponse.java │ ├── ImgLinkResponse.java │ ├── OWOifiedTextResponse.java │ ├── OWOifyRequest.java │ ├── RequestDetails.java │ ├── RequestResponse.java │ └── openapi │ ├── APIParameter.java │ ├── APIPath.java │ └── APIPathsResponse.java └── resources ├── info.json └── logback.xml /.gitignore: -------------------------------------------------------------------------------- 1 | ### Intellij+all ### 2 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 3 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 4 | 5 | # User-specific stuff: 6 | .idea/**/workspace.xml 7 | .idea/**/tasks.xml 8 | .idea/dictionaries 9 | 10 | # Sensitive or high-churn files: 11 | .idea/**/dataSources/ 12 | .idea/**/dataSources.ids 13 | .idea/**/dataSources.xml 14 | .idea/**/dataSources.local.xml 15 | .idea/**/sqlDataSources.xml 16 | .idea/**/dynamic.xml 17 | .idea/**/uiDesigner.xml 18 | 19 | # Gradle: 20 | .idea/**/gradle.xml 21 | .idea/**/libraries 22 | 23 | # CMake 24 | cmake-build-debug/ 25 | 26 | # Mongo Explorer plugin: 27 | .idea/**/mongoSettings.xml 28 | 29 | ## File-based project format: 30 | *.iws 31 | 32 | ## Plugin-specific files: 33 | 34 | # IntelliJ 35 | /out/ 36 | 37 | # mpeltonen/sbt-idea plugin 38 | .idea_modules/ 39 | 40 | # JIRA plugin 41 | atlassian-ide-plugin.xml 42 | 43 | # Cursive Clojure plugin 44 | .idea/replstate.xml 45 | 46 | # Ruby plugin and RubyMine 47 | /.rakeTasks 48 | 49 | # Crashlytics plugin (for Android Studio and IntelliJ) 50 | com_crashlytics_export_strings.xml 51 | crashlytics.properties 52 | crashlytics-build.properties 53 | fabric.properties 54 | 55 | ### Intellij+all Patch ### 56 | # Ignores the whole idea folder 57 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 58 | 59 | .idea/ 60 | 61 | ### Maven ### 62 | target/ 63 | pom.xml.tag 64 | pom.xml.releaseBackup 65 | pom.xml.versionsBackup 66 | pom.xml.next 67 | release.properties 68 | dependency-reduced-pom.xml 69 | buildNumber.properties 70 | .mvn/timing.properties 71 | 72 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 73 | !/.mvn/wrapper/maven-wrapper.jar 74 | 75 | .gradle/ 76 | build/ 77 | /img/icon/ 78 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Andre_601 (support@purrbot.site) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [docs]: https://docs.purrbot.site/api 2 | [purr]: https://purrbot.site 3 | 4 | # PurrBot Image API 5 | This API was created to provide random images. 6 | The reason behind this and not to just use any existing api (e.g. nekos.life) was to have more controll over the shown images. 7 | 8 | With version 1.2.0 was this API now merged with the original PurrBotAPI to have one central API to use. 9 | 10 | You can see the API being used by the bot [\*Purr*][purr]. 11 | 12 | ## Endpoints 13 | For a complete list of all API endpoints (URLs) available, refer to the [online docs][docs] 14 | 15 | ## Report images 16 | Please report any images that may be seen as illegal (i.e. against a company ToS) on [our Discord](https://purrbot.site/discord) or through mail at support@purrbot.site 17 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 23 | 4.0.0 24 | 25 | site.purrbot.api 26 | ImageAPI 27 | 2.3.0 28 | 29 | Purrbot API 30 | A public API made for the Discord Bot *Purr* that contains random image and text features. 31 | 32 | 33 | 8 34 | 8 35 | UTF-8 36 | 37 | 38 | 39 | 40 | io.javalin 41 | javalin 42 | 6.4.0 43 | compile 44 | 45 | 46 | ch.qos.logback 47 | logback-classic 48 | 1.5.16 49 | compile 50 | 51 | 52 | com.google.code.gson 53 | gson 54 | 2.12.1 55 | compile 56 | 57 | 58 | io.swagger.parser.v3 59 | swagger-parser 60 | 2.1.29 61 | compile 62 | 63 | 64 | 65 | 66 | ImageAPI 67 | 68 | 69 | src/main/resources 70 | true 71 | 72 | 73 | 74 | 75 | org.apache.maven.plugins 76 | maven-shade-plugin 77 | 3.6.0 78 | 79 | 80 | package 81 | 82 | shade 83 | 84 | 85 | 86 | 87 | site.purrbot.api.ImageAPI 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/ImageAPI.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Andre601 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or substantial 10 | * portions of the Software. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 13 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 15 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 16 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | package site.purrbot.api; 20 | 21 | import com.google.gson.Gson; 22 | import com.google.gson.GsonBuilder; 23 | import com.google.gson.JsonObject; 24 | import com.google.gson.JsonSyntaxException; 25 | import io.javalin.Javalin; 26 | import io.javalin.http.Context; 27 | import io.swagger.v3.oas.models.OpenAPI; 28 | import io.swagger.v3.oas.models.Operation; 29 | import io.swagger.v3.oas.models.PathItem; 30 | import io.swagger.v3.oas.models.media.Content; 31 | import io.swagger.v3.oas.models.media.MediaType; 32 | import io.swagger.v3.oas.models.parameters.Parameter; 33 | import io.swagger.v3.parser.OpenAPIV3Parser; 34 | import io.swagger.v3.parser.core.models.SwaggerParseResult; 35 | import org.slf4j.Logger; 36 | import org.slf4j.LoggerFactory; 37 | import site.purrbot.api.mapper.GsonMapper; 38 | import site.purrbot.api.objects.ErrorResponse; 39 | import site.purrbot.api.objects.OWOifyRequest; 40 | import site.purrbot.api.objects.RequestDetails; 41 | import site.purrbot.api.objects.openapi.APIPath; 42 | import site.purrbot.api.objects.openapi.APIPathsResponse; 43 | import site.purrbot.api.objects.openapi.APIParameter; 44 | 45 | import java.io.*; 46 | import java.util.*; 47 | 48 | public class ImageAPI{ 49 | 50 | private final Logger logger = LoggerFactory.getLogger(ImageAPI.class); 51 | private final File base = new File("img/"); 52 | private final Gson gson = new GsonBuilder() 53 | .setPrettyPrinting() 54 | .create(); 55 | 56 | private JsonObject infoJson = null; 57 | private OpenAPI openAPI = null; 58 | 59 | private TextOWOifier owoifier; 60 | 61 | public static void main(String[] args){ 62 | new ImageAPI().start(); 63 | } 64 | 65 | private void start(){ 66 | logger.info("Starting ImageAPI..."); 67 | if(!base.exists()){ 68 | logger.info("Couldn't find base folder. Generating it..."); 69 | if(base.mkdirs()){ 70 | logger.info("Successfully created base folder!"); 71 | }else{ 72 | logger.warn("Couldn't create base folder!"); 73 | } 74 | } 75 | 76 | ImageUtil util = new ImageUtil(this); 77 | this.owoifier = new TextOWOifier(); 78 | 79 | // Setup Javalin and make it handle all Exceptions 80 | Javalin app = Javalin.create(config -> { 81 | config.jsonMapper(new GsonMapper(gson)); 82 | config.requestLogger.http((ctx, ms) -> logger.info("Processed request {} in {}ms", ctx.path(), ms)); 83 | }).start(2000); 84 | app.exception(Exception.class, (ex, ctx) -> { 85 | logger.error("Exception caught", ex); 86 | 87 | sendErrorJSON(500, "Encountered an Exception while handling request. Exception: " + ex.getMessage(), ctx, System.currentTimeMillis()); 88 | }); 89 | 90 | app.get("/v2/", ctx -> { 91 | fetchOpenAPIJson(ctx, System.currentTimeMillis()); 92 | }); 93 | 94 | // New v2 API endpoints. 95 | app.get("/v2/list/", ctx -> { 96 | long time = System.currentTimeMillis(); 97 | 98 | String path = ctx.pathParam("path"); 99 | util.listContent(path, ctx, time, false); 100 | }); 101 | app.get("/v2/img/", ctx -> { 102 | long time = System.currentTimeMillis(); 103 | 104 | String path = ctx.pathParam("path"); 105 | util.getFile(path, ctx, time, false); 106 | }); 107 | 108 | app.post("/v2/owoify", ctx -> processOWOifyJSON(ctx, false)) 109 | .get("/v2/owoify", ctx -> { 110 | long time = System.currentTimeMillis(); 111 | 112 | String text = ctx.queryParam("text"); 113 | boolean stutter = Boolean.parseBoolean(ctx.queryParam("stutter")); 114 | boolean emoticons = Boolean.parseBoolean(ctx.queryParam("emoticons")); 115 | boolean wordSubstitution = Boolean.parseBoolean(ctx.queryParam("replace-words")); 116 | 117 | if(text == null || text.isEmpty()){ 118 | sendErrorJSON(400, "Received request does not contain a 'text' query parameter, or it was empty.", ctx, time); 119 | return; 120 | } 121 | 122 | owoifier.owoify(new OWOifyRequest(text, stutter, emoticons, wordSubstitution), ctx, time, false); 123 | }); 124 | 125 | app.get("/", ctx -> { 126 | long time = System.currentTimeMillis(); 127 | fetchInfoJson(ctx, time); 128 | }); 129 | 130 | // Old /api/list/img/* Endpoints 131 | app.get("/api/list/", ctx -> { 132 | logger.info("Handle GET request for {}", ctx.path()); 133 | long time = System.currentTimeMillis(); 134 | 135 | String path = ctx.pathParam("path"); 136 | util.listContent(path, ctx, time, true); 137 | }); 138 | 139 | // Old /api/img/* Endpoints 140 | app.get("/api/img/", ctx -> { 141 | logger.info("Handle GET request for {}", ctx.path()); 142 | long time = System.currentTimeMillis(); 143 | 144 | String path = ctx.pathParam("path"); 145 | util.getFile(path, ctx, time, true); 146 | }); 147 | 148 | // Old /api/owoify Endpoints 149 | app.post("/api/owoify", ctx -> processOWOifyJSON(ctx, true)).get("/api/owoify", ctx -> { 150 | logger.info("Handle GET request for {}", ctx.path()); 151 | long time = System.currentTimeMillis(); 152 | 153 | String text = ctx.queryParam("text"); 154 | boolean stutter = Boolean.getBoolean(ctx.queryParam("stutter")); 155 | boolean emoticons = Boolean.getBoolean(ctx.queryParam("emoticons")); 156 | boolean wordSubstitution = Boolean.getBoolean(ctx.queryParam("replace-words")); 157 | 158 | if(text == null || text.isEmpty()){ 159 | sendErrorJSON(400, "Received request does not contain a 'text' query parameter, or it was empty.", ctx, time); 160 | return; 161 | } 162 | 163 | owoifier.owoify(new OWOifyRequest(text, stutter, emoticons, wordSubstitution), ctx, time, true); 164 | }); 165 | 166 | // Old /api/info Endpoint 167 | app.get("/api/info", ctx -> { 168 | logger.info("Handle GET request for {}", ctx.path()); 169 | long time = System.currentTimeMillis(); 170 | 171 | fetchInfoJson(ctx, time); 172 | }); 173 | 174 | // Handle unsupported requests. 175 | app.post("/api/quote", ctx -> { 176 | logger.info("Unsupported POST request on /api/quote"); 177 | sendErrorJSON(410, "/api/quote has been removed from the API.", ctx, System.currentTimeMillis()); 178 | }).post("/api/status", ctx -> { 179 | logger.info("Unsupported POST request on /api/status"); 180 | sendErrorJSON(410, "/api/status has been removed from the API.", ctx, System.currentTimeMillis()); 181 | }).post("/api/img/*", ctx -> { 182 | logger.info("Not allowed POST request towards {}", ctx.path()); 183 | ctx.header("Allow", "GET"); 184 | sendErrorJSON(405, "POST requests towards " + ctx.path() + " are not allowed.", ctx, System.currentTimeMillis()); 185 | }).post("/api/list/*", ctx -> { 186 | logger.info("Not allowed POST request towards {}", ctx.path()); 187 | ctx.header("Allow", "GET"); 188 | sendErrorJSON(405, "POST requests towards " + ctx.path() + " are not allowed.", ctx, System.currentTimeMillis()); 189 | }); 190 | } 191 | 192 | void sendErrorJSON(int code, String msg, Context ctx, long time){ 193 | ErrorResponse response = new ErrorResponse(getDetails(ctx), msg, code, time); 194 | 195 | ctx.json(response); 196 | ctx.status(code); 197 | } 198 | 199 | private RequestDetails getDetails(Context ctx){ 200 | return new RequestDetails( 201 | ctx.path(), 202 | ctx.contentType() == null ? "NONE" : ctx.contentType(), 203 | ctx.userAgent() == null ? "NONE" : ctx.userAgent() 204 | ); 205 | } 206 | 207 | private void fetchInfoJson(Context ctx, long time){ 208 | if(infoJson != null){ 209 | ctx.json(infoJson); 210 | ctx.status(200); 211 | return; 212 | } 213 | 214 | try(InputStream stream = getClass().getResourceAsStream("/info.json")){ 215 | if(stream == null){ 216 | sendErrorJSON(500, "Cannot retrieve API information. Reason: Received input stream was null.", ctx, time); 217 | return; 218 | } 219 | 220 | BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); 221 | 222 | infoJson = gson.fromJson(reader, JsonObject.class); 223 | if(infoJson == null){ 224 | sendErrorJSON(500, "Cannot retrieve API information. Reason: Retrieved JSON was null.", ctx, time); 225 | reader.close(); 226 | return; 227 | } 228 | 229 | ctx.json(infoJson); 230 | ctx.status(200); 231 | 232 | reader.close(); 233 | }catch(IOException ex){ 234 | sendErrorJSON(500, "Encountered an IOException: " + ex.getMessage(), ctx, time); 235 | } 236 | } 237 | 238 | private void fetchOpenAPIJson(Context ctx, long time){ 239 | if(openAPI != null){ 240 | displayAPIPaths(ctx, time); 241 | return; 242 | } 243 | 244 | SwaggerParseResult result = new OpenAPIV3Parser().readLocation("https://raw.githubusercontent.com/purrbot-site/Docs/master/docs/assets/imageapi.json", null, null); 245 | 246 | if(result.getMessages() != null && !result.getMessages().isEmpty()){ 247 | sendErrorJSON( 248 | 500, 249 | String.format( 250 | "Encountered an error while parsing OpenAPI JSON: %s", 251 | String.join(";", result.getMessages()) 252 | ), 253 | ctx, 254 | time 255 | ); 256 | return; 257 | } 258 | 259 | OpenAPI openAPI = result.getOpenAPI(); 260 | if(openAPI == null){ 261 | sendErrorJSON( 262 | 500, 263 | "Received OpenAPI instance was null.", 264 | ctx, 265 | time 266 | ); 267 | return; 268 | } 269 | 270 | this.openAPI = openAPI; 271 | 272 | displayAPIPaths(ctx, time); 273 | } 274 | 275 | private void processOWOifyJSON(Context ctx, boolean deprecated){ 276 | long time = System.currentTimeMillis(); 277 | 278 | try{ 279 | OWOifyRequest request = gson.fromJson(ctx.body(), OWOifyRequest.class); 280 | if(request == null){ 281 | sendErrorJSON(400, "The received JSON was invalid or didn't exist.", ctx, time); 282 | return; 283 | } 284 | 285 | if(request.getText() == null || request.getText().isEmpty()){ 286 | sendErrorJSON(400, "The received JSON does not contain a 'text' field or it was empty.", ctx, time); 287 | return; 288 | } 289 | 290 | if(owoifier == null){ 291 | sendErrorJSON(500, "The TextOWOIfier is not available. If this issue persists, report it to the developer!", ctx, time); 292 | return; 293 | } 294 | 295 | owoifier.owoify(request, ctx, time, deprecated); 296 | }catch(JsonSyntaxException ex){ 297 | sendErrorJSON(400, "Received invalid JSON Body: " + ex.getMessage(), ctx, time); 298 | } 299 | } 300 | 301 | private void displayAPIPaths(Context ctx, long time){ 302 | List paths = new ArrayList<>(); 303 | for(Map.Entry path : openAPI.getPaths().entrySet()){ 304 | if(path.getValue().getGet() != null){ 305 | paths.add(processAPIPath(path.getKey(), "GET", path.getValue().getGet())); 306 | } 307 | if(path.getValue().getPost() != null){ 308 | paths.add(processAPIPath(path.getKey(), "POST", path.getValue().getPost())); 309 | } 310 | } 311 | 312 | APIPathsResponse response = new APIPathsResponse(time, paths); 313 | 314 | ctx.status(200); 315 | ctx.json(response); 316 | } 317 | 318 | private APIPath processAPIPath(String name, String method, Operation operation){ 319 | String pathName = "https://api.purrbot.site/v2" + name; 320 | String description = operation.getDescription(); 321 | Map requestBodies = null; 322 | 323 | 324 | if(operation.getRequestBody() != null && operation.getRequestBody().getContent() != null){ 325 | Content content = operation.getRequestBody().getContent(); 326 | requestBodies = new HashMap<>(); 327 | for(Map.Entry schema : content.entrySet()){ 328 | if(schema.getValue().getSchema() == null || schema.getValue().getSchema().get$ref() == null) 329 | continue; 330 | 331 | String ref = schema.getValue().getSchema().get$ref().toLowerCase(Locale.ROOT); 332 | if(ref.startsWith("#/components/schemas/")){ 333 | requestBodies.put( 334 | schema.getKey(), 335 | "https://docs.purrbot.site/api/#" + ref.substring("#/components/schemas/".length())); 336 | }else{ 337 | requestBodies.put(schema.getKey(), ref); 338 | } 339 | } 340 | } 341 | 342 | Boolean deprecated = operation.getDeprecated(); 343 | 344 | List parameters = null; 345 | if(operation.getParameters() != null){ 346 | parameters = new ArrayList<>(); 347 | for(Parameter parameter : operation.getParameters()) 348 | parameters.add(new APIParameter(parameter.getName(), parameter.getIn(), parameter.getDescription(), parameter.getRequired())); 349 | } 350 | 351 | return new APIPath(pathName, method, description, requestBodies, deprecated, parameters); 352 | } 353 | } 354 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/ImageUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Andre601 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or substantial 10 | * portions of the Software. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 13 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 15 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 16 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | package site.purrbot.api; 20 | 21 | import ch.qos.logback.classic.Logger; 22 | import io.javalin.http.Context; 23 | import org.slf4j.LoggerFactory; 24 | import site.purrbot.api.objects.ImgLinkListResponse; 25 | import site.purrbot.api.objects.ImgLinkResponse; 26 | 27 | import java.io.*; 28 | import java.util.*; 29 | import java.util.List; 30 | import java.util.stream.Collectors; 31 | 32 | public class ImageUtil{ 33 | 34 | private final ImageAPI api; 35 | 36 | private final Random random = new Random(); 37 | private final Logger logger = (Logger)LoggerFactory.getLogger(ImageUtil.class); 38 | private final List extensions = Arrays.asList(".png", ".jpg", ".jpeg", ".gif", ".svg"); 39 | private final File base = new File("img/"); 40 | private final FilenameFilter filter = (dir, name) -> { 41 | for(String ext : extensions){ 42 | if(name.endsWith(ext)) 43 | return true; 44 | } 45 | 46 | return false; 47 | }; 48 | 49 | public ImageUtil(ImageAPI api){ 50 | this.api = api; 51 | } 52 | 53 | void listContent(String path, Context ctx, long time, boolean deprecated){ 54 | File[] files = getFiles(path, ctx, time); 55 | if(files.length == 0) 56 | return; 57 | 58 | List links = Arrays.stream(files).map(this::getPath).collect(Collectors.toList()); 59 | 60 | ctx.status(200); 61 | if(deprecated){ 62 | ctx.json(new ImgLinkListResponse(links, time, String.format( 63 | "This endpoint was deprecated and will be removed in the future. " + 64 | "Please forward any future requests towards https://api.purrbot.site/v2/list/%s", 65 | path 66 | ))); 67 | }else{ 68 | ctx.json(new ImgLinkListResponse(links, time)); 69 | } 70 | } 71 | 72 | void getFile(String path, Context ctx, long time, boolean deprecated){ 73 | File[] files = getFiles(path, ctx, time); 74 | if(files.length == 0) 75 | return; 76 | 77 | File selected = files[random.nextInt(files.length)]; 78 | 79 | ctx.status(200); 80 | if(deprecated){ 81 | ctx.json(new ImgLinkResponse(getPath(selected), time, String.format( 82 | "This endpoint was deprecated. Please forward future requests towards https://api.purrbot.site/v2/img/%s", 83 | path 84 | ))); 85 | }else{ 86 | ctx.json(new ImgLinkResponse(getPath(selected), time)); 87 | } 88 | } 89 | 90 | private File[] getFiles(String path, Context ctx, long time){ 91 | File folder = new File(base, path + "/"); 92 | 93 | if(!folder.exists() || folder.isAbsolute()){ 94 | logger.info("Received invalid path {} for Image GET request.", path); 95 | 96 | api.sendErrorJSON(403, "The provided path is not valid.", ctx, time); 97 | return new File[0]; 98 | }else{ 99 | File[] files = folder.listFiles(filter); 100 | if(files == null || files.length == 0){ 101 | logger.info("Received path {} for Image GET request does not contain any images.", path); 102 | 103 | api.sendErrorJSON(403, "The provided path does not contain any images.", ctx, time); 104 | return new File[0]; 105 | } 106 | 107 | return files; 108 | } 109 | } 110 | 111 | private String getPath(File file){ 112 | return ("https://cdn.purrbot.site/" + file.getPath().substring("img/".length())).replace("\\", "/"); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/TextOWOifier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Andre601 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or substantial 10 | * portions of the Software. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 13 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 15 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 16 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | package site.purrbot.api; 20 | 21 | import io.javalin.http.Context; 22 | import site.purrbot.api.objects.OWOifiedTextResponse; 23 | import site.purrbot.api.objects.OWOifyRequest; 24 | 25 | import java.util.*; 26 | 27 | public class TextOWOifier{ 28 | 29 | private final List emotes = Arrays.asList("(・`ω´・)", ";;w;;", ">w<", "^w^", "UwU", "owo", "^^", "x3"); 30 | private final Map wordMap = new HashMap(){{ 31 | put("hello", "hewwo"); 32 | put("hi", "hai"); 33 | put("hey", "haiii"); 34 | put("love", "wuv"); 35 | put("friend", "fwend"); 36 | put("stop", "stahp"); 37 | put("no", "nu"); 38 | put("you're", "ur"); 39 | put("you", "uu"); 40 | put("has", "haz"); 41 | }}; 42 | 43 | private final Random random = new Random(); 44 | 45 | public void owoify(OWOifyRequest request, Context ctx, long time, boolean deprecated){ 46 | String[] words = request.getText().split("\\s+"); 47 | StringBuilder builder = new StringBuilder(); 48 | 49 | for(String word : words){ 50 | String key = word.toLowerCase(Locale.ROOT); 51 | 52 | if(request.isWordSubstitutions() && wordMap.containsKey(key)){ 53 | word = matchCase(word, wordMap.get(key)); 54 | } 55 | 56 | word = word.replaceAll("[rl]", "w").replaceAll("[RL]", "W"); 57 | 58 | double d; 59 | synchronized(random){ 60 | d = random.nextDouble(); 61 | } 62 | if(request.isStutter() && word.length() > 2 && Character.isLetter(word.charAt(0)) && d < 0.2){ 63 | word = word.charAt(0) + "-" + word; 64 | } 65 | 66 | builder.append(word).append(' '); 67 | } 68 | 69 | String owoified = builder.toString().trim(); 70 | 71 | if(request.isEmoticons()){ 72 | owoified = owoified.replaceAll("[.!?]", " " + getRandomEmoticon()); 73 | } 74 | 75 | ctx.status(200); 76 | if(deprecated){ 77 | ctx.json(new OWOifiedTextResponse( 78 | owoified, 79 | time, 80 | "This endpoint was deprecated and will be removed in the future. " + 81 | "Please forward any future requests towards https://api.purrbot.site/v2/owoify" 82 | )); 83 | }else{ 84 | ctx.json(new OWOifiedTextResponse(owoified, time)); 85 | } 86 | } 87 | 88 | private String matchCase(String original, String replacement){ 89 | if(original.equals(original.toLowerCase(Locale.ROOT))) 90 | return replacement.toLowerCase(Locale.ROOT); 91 | 92 | if(original.equals(original.toUpperCase(Locale.ROOT))) 93 | return replacement.toUpperCase(Locale.ROOT); 94 | 95 | if(Character.isUpperCase(original.charAt(0))) 96 | return Character.toUpperCase(replacement.charAt(0)) + replacement.substring(1); 97 | 98 | return replacement; 99 | } 100 | 101 | private String getRandomEmoticon(){ 102 | synchronized(random){ 103 | return emotes.get(random.nextInt(emotes.size())); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/mapper/GsonMapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Andre601 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or substantial 10 | * portions of the Software. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 13 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 15 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 16 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | package site.purrbot.api.mapper; 20 | 21 | import com.google.gson.Gson; 22 | import io.javalin.json.JsonMapper; 23 | import org.jetbrains.annotations.NotNull; 24 | 25 | import java.lang.reflect.Type; 26 | 27 | public class GsonMapper implements JsonMapper{ 28 | private final Gson gson; 29 | 30 | public GsonMapper(Gson gson){ 31 | this.gson = gson; 32 | } 33 | 34 | @NotNull 35 | @Override 36 | public String toJsonString(@NotNull Object obj, @NotNull Type type){ 37 | return gson.toJson(obj, type); 38 | } 39 | 40 | @NotNull 41 | @Override 42 | public T fromJsonString(@NotNull String json, @NotNull Type targetType){ 43 | return gson.fromJson(json, targetType); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/objects/ErrorResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Andre601 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or substantial 10 | * portions of the Software. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 13 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 15 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 16 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | package site.purrbot.api.objects; 20 | 21 | public class ErrorResponse extends RequestResponse{ 22 | 23 | private final RequestDetails details; 24 | private final String message; 25 | 26 | public ErrorResponse(RequestDetails details, String message, int responseCode, long time){ 27 | super(true, responseCode, time); 28 | 29 | this.details = details; 30 | this.message = message; 31 | } 32 | public ErrorResponse(RequestDetails details, String message, int responseCode, long time, String deprecationWarning){ 33 | super(true, responseCode, time, deprecationWarning); 34 | 35 | this.details = details; 36 | this.message = message; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/objects/ImgLinkListResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Andre601 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or substantial 10 | * portions of the Software. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 13 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 15 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 16 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | package site.purrbot.api.objects; 20 | 21 | import java.util.List; 22 | 23 | public class ImgLinkListResponse extends RequestResponse{ 24 | 25 | private final List links; 26 | 27 | public ImgLinkListResponse(List links, long time){ 28 | super(false, 200, time); 29 | 30 | this.links = links; 31 | } 32 | 33 | public ImgLinkListResponse(List links, long time, String deprecationWarning){ 34 | super(false, 200, time, deprecationWarning); 35 | 36 | this.links = links; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/objects/ImgLinkResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Andre601 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or substantial 10 | * portions of the Software. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 13 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 15 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 16 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | package site.purrbot.api.objects; 20 | 21 | public class ImgLinkResponse extends RequestResponse{ 22 | 23 | private final String link; 24 | 25 | public ImgLinkResponse(String link, long time){ 26 | super(false, 200, time); 27 | 28 | this.link = link; 29 | } 30 | 31 | public ImgLinkResponse(String link, long time, String deprecationWarning){ 32 | super(false, 200, time, deprecationWarning); 33 | 34 | this.link = link; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/objects/OWOifiedTextResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Andre601 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or substantial 10 | * portions of the Software. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 13 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 15 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 16 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | package site.purrbot.api.objects; 20 | 21 | public class OWOifiedTextResponse extends RequestResponse{ 22 | 23 | private final String text; 24 | 25 | public OWOifiedTextResponse(String text, long time){ 26 | super(false, 200, time); 27 | 28 | this.text = text; 29 | } 30 | 31 | public OWOifiedTextResponse(String text, long time, String deprecationWarning){ 32 | super(false, 200, time, deprecationWarning); 33 | 34 | this.text = text; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/objects/OWOifyRequest.java: -------------------------------------------------------------------------------- 1 | package site.purrbot.api.objects; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | public class OWOifyRequest{ 6 | private final String text; 7 | private final boolean stutter; 8 | private final boolean emoticons; 9 | @SerializedName("replace-words") 10 | private final boolean wordSubstitutions; 11 | 12 | public OWOifyRequest(String text, boolean stutter, boolean emoticons, boolean wordSubstitutions){ 13 | this.text = text; 14 | this.stutter = stutter; 15 | this.emoticons = emoticons; 16 | this.wordSubstitutions = wordSubstitutions; 17 | } 18 | 19 | public String getText(){ 20 | return text; 21 | } 22 | 23 | public boolean isStutter(){ 24 | return stutter; 25 | } 26 | 27 | public boolean isEmoticons(){ 28 | return emoticons; 29 | } 30 | 31 | public boolean isWordSubstitutions(){ 32 | return wordSubstitutions; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/objects/RequestDetails.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Andre601 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or substantial 10 | * portions of the Software. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 13 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 15 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 16 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | package site.purrbot.api.objects; 20 | 21 | import com.google.gson.annotations.SerializedName; 22 | 23 | public class RequestDetails{ 24 | 25 | private final String path; 26 | @SerializedName("content-type") 27 | private final String contentType; 28 | @SerializedName("user-agent") 29 | private final String userAgent; 30 | 31 | public RequestDetails(String path, String contentType, String userAgent){ 32 | this.path = path; 33 | this.contentType = contentType; 34 | this.userAgent = userAgent; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/objects/RequestResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Andre601 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 5 | * documentation files (the "Software"), to deal in the Software without restriction, including without limitation 6 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 7 | * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 8 | * 9 | * The above copyright notice and this permission notice shall be included in all copies or substantial 10 | * portions of the Software. 11 | * 12 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 13 | * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 15 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 16 | * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | */ 18 | 19 | package site.purrbot.api.objects; 20 | 21 | import com.google.gson.annotations.SerializedName; 22 | 23 | public class RequestResponse{ 24 | 25 | private final boolean error; 26 | @SerializedName("response-code") 27 | private final int responseCode; 28 | private final long time; 29 | @SerializedName("deprecation-warning") 30 | private final String deprecationWarning; 31 | 32 | public RequestResponse(boolean error, int responseCode, long time){ 33 | this(error, responseCode, time, null); 34 | } 35 | 36 | public RequestResponse(boolean error, int responseCode, long time, String deprecationWarning){ 37 | this.error = error; 38 | this.responseCode = responseCode; 39 | this.time = System.currentTimeMillis() - time; 40 | this.deprecationWarning = deprecationWarning; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/objects/openapi/APIParameter.java: -------------------------------------------------------------------------------- 1 | package site.purrbot.api.objects.openapi; 2 | 3 | public class APIParameter{ 4 | private final String name; 5 | private final String location; 6 | private final String description; 7 | private final Boolean required; 8 | 9 | public APIParameter(String name, String location, String description, Boolean required){ 10 | this.name = name; 11 | this.location = location; 12 | this.description = description; 13 | this.required = required; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/objects/openapi/APIPath.java: -------------------------------------------------------------------------------- 1 | package site.purrbot.api.objects.openapi; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | public class APIPath{ 9 | 10 | private final String path; 11 | private final String method; 12 | private final String description; 13 | @SerializedName("request-bodies") 14 | private final Map requestBodies; 15 | private final Boolean deprecated; 16 | private final List parameters; 17 | 18 | public APIPath(String path, String method, String description, Map requestBodies, Boolean deprecated, List parameters){ 19 | this.path = path; 20 | this.method = method; 21 | this.description = description; 22 | this.requestBodies = requestBodies; 23 | this.deprecated = deprecated; 24 | this.parameters = parameters; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/site/purrbot/api/objects/openapi/APIPathsResponse.java: -------------------------------------------------------------------------------- 1 | package site.purrbot.api.objects.openapi; 2 | 3 | import site.purrbot.api.objects.RequestResponse; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class APIPathsResponse extends RequestResponse{ 9 | 10 | private final List paths; 11 | 12 | public APIPathsResponse(long time, List paths){ 13 | super(false, 200, time); 14 | this.paths = paths; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/resources/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "${project.name}", 3 | "version": "${project.version}", 4 | "description": "${project.description}", 5 | "links": { 6 | "documentation": "https://docs.purrbot.site/api", 7 | "source": "https://github.com/purrbot-site/ImageAPI", 8 | "api": "https://api.purrbot.site/v2", 9 | "legal": "https://docs.purrbot.site/legal/api" 10 | }, 11 | "license": { 12 | "type": "MIT", 13 | "link": "https://github.com/purrbot-site/ImageAPI/blob/master/LICENSE" 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | %highlight([) %boldWhite(%d{dd.MM.yyyy HH:mm:ss}) %highlight(%-5level) %highlight(]) %cyan([%t]) %boldWhite([%logger{0}]) %boldRed(-) %white(%msg) %n 27 | 28 | 29 | 30 | 31 | 32 | 33 | INFO 34 | 35 | ${DEV_HOME}/Purr.log 36 | 37 | %d{dd.MM.yyyy HH:mm:ss} [%thread] [ %-5level] [%logger{0}] %msg%n 38 | 39 | 40 | 41 | ${DEV_HOME}/archived/purr-%d{dd.MM.yyyy}.%i.log 42 | 100MB 43 | 60 44 | 20GB 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | --------------------------------------------------------------------------------