├── .github
├── dependabot.yml
└── workflows
│ └── build.yml
├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
├── main
└── java
│ └── net
│ └── kodehawa
│ └── lib
│ └── imageboards
│ ├── DefaultImageBoards.java
│ ├── ImageBoard.java
│ ├── ImageBoards.java
│ ├── boards
│ ├── Board.java
│ ├── CustomBoard.java
│ └── DefaultBoards.java
│ ├── entities
│ ├── BoardImage.java
│ ├── Rating.java
│ ├── RatingDeserializer.java
│ ├── exceptions
│ │ ├── QueryFailedException.java
│ │ └── QueryParseException.java
│ └── impl
│ │ ├── DanbooruImage.java
│ │ ├── FurryImage.java
│ │ ├── GelbooruImage.java
│ │ ├── KonachanImage.java
│ │ ├── Rule34Image.java
│ │ ├── SafeFurryImage.java
│ │ ├── SafebooruImage.java
│ │ ├── YandereImage.java
│ │ └── autocomplete
│ │ ├── IAutoComplete.java
│ │ └── pojo
│ │ ├── DanbooruAutoComplete.java
│ │ ├── FurryAutoComplete.java
│ │ ├── GelbooruAutoComplete.java
│ │ ├── Rule34AutoComplete.java
│ │ └── SafebooruAutoComplete.java
│ └── requests
│ ├── RequestAction.java
│ └── RequestFactory.java
└── test
└── java
└── net
└── kodehawa
└── lib
└── imageboards
├── ImageBoardTest.java
├── RandomImages.java
└── TagImages.java
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: gradle
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | time: "09:00"
8 | open-pull-requests-limit: 10
9 | ignore:
10 | - dependency-name: com.squareup.okhttp3:okhttp
11 | versions:
12 | - ">= 4.a, < 5"
13 | - dependency-name: com.fasterxml.jackson.core:jackson-core
14 | versions:
15 | - 2.12.2
16 | - dependency-name: com.fasterxml.jackson.core:jackson-databind
17 | versions:
18 | - 2.12.2
19 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 |
3 | on:
4 | push:
5 | branches: "master"
6 | release:
7 | types: [created]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 | permissions:
13 | contents: read
14 | packages: write
15 | steps:
16 | - uses: actions/checkout@v2
17 | - uses: actions/setup-java@v2
18 | with:
19 | distribution: 'zulu'
20 | java-version: 11
21 | - run: ./gradlew publishGprPublicationToGitHubPackagesRepository
22 | if: github.event_name == 'release' && github.event.action == 'created'
23 | env:
24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25 | - run: ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository
26 | if: github.event_name == 'release' && github.event.action == 'created'
27 | env:
28 | SONATYPE_USER: ${{ secrets.SONATYPE_USER }}
29 | SONATYPE_PASS: ${{ secrets.SONATYPE_PASS }}
30 | SIGN_KEY: ${{ secrets.SIGN_KEY }}
31 | SIGN_PW: ${{ secrets.SIGN_PW }}
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 |
3 | ### Gradle ###
4 | .gradle
5 | build/
6 | !gradle/wrapper/gradle-wrapper.jar
7 | !**/src/main/**/build/
8 | !**/src/test/**/build/
9 |
10 | # Compiled class file
11 | *.class
12 |
13 | # Log file
14 | *.log
15 |
16 | # BlueJ files
17 | *.ctxt
18 |
19 | # Mobile Tools for Java (J2ME)
20 | .mtj.tmp/
21 |
22 | # Package Files #
23 | *.jar
24 | *.war
25 | *.ear
26 | *.zip
27 | *.tar.gz
28 | *.rar
29 |
30 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
31 | hs_err_pid*
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ImageBoard (Booru) API
2 |
3 | [](https://maven-badges.herokuapp.com/maven-central/io.github.kodehawa/imageboard-api)
4 |
5 | ImageBoard API is a simple asynchronous Java API wrapper around the most popular danbooru-compatible booru APIs. Pretty much, it is a Booru library for Java.
6 | The interface also supports other types of custom boards given a little tweaking. Releases are published in [Maven Central](https://central.sonatype.com/artifact/io.github.kodehawa/imageboard-api).
7 |
8 | This helps you craft requests and search/fetch images on the danbooru-compatible imageboards (boorus) that exist out there.
9 |
10 | #### Supported Booru Image Boards
11 | * Rule34
12 | * e621
13 | * Konachan
14 | * Yande.re
15 | * Danbooru
16 | * Safebooru
17 | * Gelbooru
18 | * e926
19 |
20 | Creating your own ImageBoard instance is possible, but would require a little tweaking.
21 | Please refer to the `ImageBoards.java` and `CustomBoard.java` to set up boards that are not included
22 | with this library. The boorus listed above are available by default with no further configuration required by the user.
23 |
24 | ## Adding ImageBoardAPI to your project
25 | imageboard-api is available in Maven Central (Sonatype). Check [the Sonatype respository](https://central.sonatype.com/artifact/io.github.kodehawa/imageboard-api) for more information
26 |
27 | #### Gradle
28 | ```groovy
29 | repositories {
30 | mavenCentral()
31 | }
32 |
33 | dependencies {
34 | implementation 'io.github.kodehawa:imageboard-api:2.6.1.1'
35 | }
36 | ```
37 |
38 | ## Set Up
39 | There is a `ImageBoards` class located under utils, that one contains static, pre-created
40 | ImageBoardAPI objects for you, but you can roll your own.
41 |
42 |
43 | ### Implementation
44 | You can find implementation details and a lot of examples in the [tests for this project](https://github.com/Kodehawa/imageboard-api/blob/master/src/test/java/net/kodehawa/lib/imageboards/ImageBoardTest.java) and in [Mantaro](https://github.com/Mantaro/MantaroBot/blob/master/src/main/java/net/kodehawa/mantarobot/commands/image/ImageboardUtils.java#L54)
45 |
46 | The User-Agent must be initialized to make requests. You can initialize it with `ImageBoard.setUserAgent()`. The default one was blocked by most imageboards, setting your own is the best to avoid UA blocking.
47 |
48 | ## Examples
49 | ### Random Images
50 | ```java
51 | import net.kodehawa.lib.imageboards.entities.BoardImage;
52 | import net.kodehawa.lib.imageboards.DefaultImageBoards;
53 |
54 | public class RandomImages {
55 | public static void main(String[] args) {
56 | // Asynchronous GET
57 | // 60 random images
58 | DefaultImageBoards.KONACHAN.get().async(images -> {
59 | for (BoardImage image : images) System.out.println(image.getURL());
60 | });
61 |
62 | // Asynchronous GET
63 | // 30 random images
64 | ImageBoards.KONACHAN.get(30).async(images -> {
65 | for (BoardImage image : images) System.out.println(image.getURL());
66 | });
67 |
68 | // Blocking GET
69 | // 5 random image
70 | BoardImage image = DefaultImageBoards.KONACHAN.get(5).blocking().get(0);
71 | System.out.println(image.getURL());
72 | System.out.println(image.getRating());
73 | System.out.println(image.getTags());
74 | System.out.println(image.getHeight());
75 | System.out.println(image.getWidth());
76 | }
77 | }
78 | ```
79 |
80 | ### Image Tag Search
81 | ```java
82 | import net.kodehawa.lib.imageboards.entities.BoardImage;
83 | import net.kodehawa.lib.imageboards.DefaultImageBoards;
84 |
85 | public class TagImages {
86 | public static void main(String[] args) {
87 | // Asynchronous GET
88 | // 20 images tagged with animal_ears
89 | DefaultImageBoards.KONACHAN.search(20, "animal_ears").async(images -> {
90 | for (BoardImage image : images) System.out.println(image.getURL());
91 | });
92 |
93 | // Blocking GET
94 | // 60 images tagged with animal_ears
95 | BoardImage image = DefaultImageBoards.KONACHAN.search("animal_ears").blocking().get(0);
96 | System.out.println(image.getURL());
97 | System.out.println(image.getRating());
98 | System.out.println(image.getTags());
99 | System.out.println(image.getHeight());
100 | System.out.println(image.getWidth());
101 | }
102 | }
103 | ```
104 |
105 | ### Filter bad results
106 |
107 | You might want to filter BoardImage#isPending, as the tags/rating of those is almost guaranteed to never be correct.
108 |
109 | For filtering other results, you can filter tags from BoardImage#getTags and use a .contains call on the list.
110 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | id 'maven-publish'
4 | id 'io.github.gradle-nexus.publish-plugin' version "1.3.0"
5 | id 'com.github.johnrengelman.shadow' version '7.0.0'
6 | id 'signing'
7 | }
8 |
9 | import org.apache.tools.ant.filters.ReplaceTokens
10 | def versionObj = new Version(major: 2, minor: 7, revision: 0)
11 |
12 | group 'io.github.kodehawa'
13 | version "$versionObj"
14 | apply plugin: 'java'
15 |
16 | sourceCompatibility = 1.8
17 |
18 | repositories {
19 | mavenCentral()
20 | }
21 |
22 | dependencies {
23 | implementation 'com.fasterxml.jackson.core:jackson-core:2.16.0'
24 | implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.0'
25 | implementation 'com.squareup.okhttp3:okhttp:4.10.0'
26 | implementation 'org.slf4j:slf4j-api:2.0.9'
27 |
28 | testImplementation 'ch.qos.logback:logback-classic:1.4.14'
29 | testImplementation 'junit:junit:4.13.2'
30 | }
31 |
32 | task sourcesForRelease(type: Copy) {
33 | from 'src/main/java'
34 | into 'build/filteredSrc'
35 | }
36 |
37 | //Task for the versioning system
38 | task prepareSource(type: Copy) {
39 | from 'src/main/java'
40 | into 'build/prepared-src'
41 | filter(ReplaceTokens, tokens: [
42 | version: versionObj.toString()
43 | ])
44 | dependsOn clean
45 | }
46 | prepareSource.dependsOn clean
47 |
48 | // Maven Central requirement
49 | java {
50 | withJavadocJar()
51 | withSourcesJar()
52 | }
53 |
54 | tasks.withType(JavaCompile).configureEach {
55 | options.encoding = 'UTF-8'
56 | }
57 |
58 | javadoc {
59 | failOnError = true
60 | options.memberLevel = JavadocMemberLevel.PUBLIC
61 | options.author()
62 | options.encoding = 'UTF-8'
63 | }
64 |
65 | compileJava {
66 | source = sourcesForRelease.destinationDir
67 | classpath = sourceSets.main.compileClasspath
68 |
69 | options.encoding = 'UTF-8'
70 |
71 | dependsOn sourcesForRelease
72 | }
73 |
74 | jar {
75 | archiveBaseName = project.name
76 | manifest {
77 | attributes 'Implementation-Version': archiveVersion
78 | }
79 | }
80 |
81 | shadowJar {
82 | classifier("withDependencies")
83 | }
84 |
85 | nexusPublishing {
86 | repositories {
87 | sonatype {
88 | nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
89 | snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
90 | username = System.getenv("SONATYPE_USER")
91 | password = System.getenv("SONATYPE_PASS")
92 | }
93 | }
94 | }
95 |
96 | publishing {
97 | repositories {
98 | maven {
99 | name = "GitHubPackages"
100 | url = uri("https://maven.pkg.github.com/kodehawa/imageboard-api")
101 | credentials {
102 | username = project.findProperty("gpr.user") ?: System.getenv("GITHUB_ACTOR")
103 | password = project.findProperty("gpr.key") ?: System.getenv("GITHUB_TOKEN")
104 | }
105 | }
106 | }
107 |
108 | publications {
109 | gpr(MavenPublication) {
110 | from(components.java)
111 | }
112 |
113 | mavenJava(MavenPublication) {
114 | from(components.java)
115 |
116 | pom {
117 | name.set("imageboard-api")
118 | description.set(" Simple asynchronous Java API wrapper around the most popular danbooru-compatible (Konachan, Yande.re, Danbooru, Gelbooru, etc) booru APIs. ")
119 | url.set("https://github.com/Kodehawa/imageboard-api")
120 | licenses {
121 | license {
122 | name.set("Apache-2.0")
123 | url.set("https://www.apache.org/licenses/LICENSE-2.0")
124 | }
125 | }
126 | developers {
127 | developer {
128 | id.set("1")
129 | name.set("Kodehawa")
130 | email.set("contact@mantaro.site")
131 | }
132 | }
133 | scm {
134 | connection.set("scm:git:git://github.com/Kodehawa/imageboard-api.git")
135 | developerConnection.set("scm:git:ssh://github.com/Kodehawa/imageboard-api.git")
136 | url.set("https://github.com/Kodehawa/imageboard-api")
137 | }
138 | }
139 | }
140 | }
141 | }
142 |
143 | signing {
144 | def signingKey = base64Decode(System.getenv("SIGN_KEY"))
145 | def signingPassword = System.getenv("SIGN_PW")
146 | useInMemoryPgpKeys(signingKey, signingPassword)
147 | sign publishing.publications.mavenJava
148 | }
149 |
150 | static def base64Decode(encodedString){
151 | if(encodedString != null) {
152 | byte[] decoded = encodedString.decodeBase64()
153 | String decode = new String(decoded)
154 | return decode
155 | }
156 | return null;
157 | }
158 |
159 | build {
160 | dependsOn clean
161 | dependsOn jar
162 | dependsOn javadocJar
163 | dependsOn sourcesJar
164 | dependsOn shadowJar
165 |
166 | dependsOn test
167 |
168 | jar.mustRunAfter clean
169 | javadocJar.mustRunAfter jar
170 | sourcesJar.mustRunAfter javadocJar
171 | shadowJar.mustRunAfter sourcesJar
172 | }
173 |
174 | class Version {
175 | String major, minor, revision
176 |
177 | String toString() {
178 | "${major}.${minor}" + (revision == "0" ? "" : ".${revision}")
179 | }
180 | }
181 |
182 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kodehawa/imageboard-api/57fa6ab4fa2a26cbf1ad3d7dd9e3469c851d6933/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'imageboard-api'
2 |
3 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/DefaultImageBoards.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards;
18 |
19 | import net.kodehawa.lib.imageboards.entities.impl.*;
20 |
21 | /**
22 | * Utility class representing already-created objects around the most used image boards.
23 | * As of now, this contains the following boorus / imageboards:
24 | *
25 | * - e621 - Furry pictures, both NSFW and safe.
26 | * - Konachan (owned by booru.org) - Anime pictures, both NSFW and safe.
27 | * - Rule34 (owned by booru.org) - Anime pictures, only NSFW
28 | * - Yande.re - Anime pictures, both NSFW and safe (though tagging is sloppy, would recommend setting this to only NSFW)
29 | * - Danbooru (the original one) - Anime pictures, both NSFW and safe.
30 | * - Safebooru (owned by booru.org) - Anime pictures, only safe.
31 | * - e926 (a safe version of e621) - Furry pictures, only safe.
32 | *
33 | *
34 | * It's recommended to lock the usage of the boorus to only NSFW channels unless the image is safe. If you're not
35 | * using this for a discord bot, then just use as your own discretion :P
36 | *
37 | * @author Kodehawa
38 | */
39 | public class DefaultImageBoards {
40 | public static final ImageBoard E621 = ImageBoards.Default.E621;
41 | public static final ImageBoard KONACHAN = ImageBoards.Default.KONACHAN;
42 | public static final ImageBoard RULE34 = ImageBoards.Default.RULE34;
43 | public static final ImageBoard YANDERE = ImageBoards.Default.YANDERE;
44 | public static final ImageBoard DANBOORU = ImageBoards.Default.DANBOORU;
45 | public static final ImageBoard SAFEBOORU = ImageBoards.Default.SAFEBOORU;
46 | public static final ImageBoard E926 = ImageBoards.Default.E926;
47 | public static final ImageBoard GELBOORU = ImageBoards.Default.GELBOORU;
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/ImageBoard.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards;
18 |
19 | import com.fasterxml.jackson.databind.DeserializationFeature;
20 | import com.fasterxml.jackson.databind.ObjectMapper;
21 | import com.fasterxml.jackson.databind.exc.MismatchedInputException;
22 | import net.kodehawa.lib.imageboards.boards.Board;
23 | import net.kodehawa.lib.imageboards.boards.DefaultBoards;
24 | import net.kodehawa.lib.imageboards.entities.BoardImage;
25 | import net.kodehawa.lib.imageboards.entities.Rating;
26 | import net.kodehawa.lib.imageboards.entities.exceptions.QueryFailedException;
27 | import net.kodehawa.lib.imageboards.entities.exceptions.QueryParseException;
28 | import net.kodehawa.lib.imageboards.entities.impl.DanbooruImage;
29 | import net.kodehawa.lib.imageboards.entities.impl.FurryImage;
30 | import net.kodehawa.lib.imageboards.entities.impl.GelbooruImage;
31 | import net.kodehawa.lib.imageboards.entities.impl.SafeFurryImage;
32 | import net.kodehawa.lib.imageboards.entities.impl.autocomplete.IAutoComplete;
33 | import net.kodehawa.lib.imageboards.requests.RequestAction;
34 | import net.kodehawa.lib.imageboards.requests.RequestFactory;
35 | import okhttp3.HttpUrl;
36 | import okhttp3.OkHttpClient;
37 | import okhttp3.ResponseBody;
38 | import org.slf4j.Logger;
39 | import org.slf4j.LoggerFactory;
40 |
41 | import java.io.IOException;
42 | import java.io.InputStream;
43 | import java.nio.channels.NonReadableChannelException;
44 | import java.util.Collections;
45 | import java.util.List;
46 | import java.util.concurrent.TimeUnit;
47 |
48 | /**
49 | * Image board API instance.
50 | * @param Board image return type.
51 | *
52 | * @author Avarel
53 | * @author Kodehawa
54 | */
55 | public class ImageBoard {
56 | private static final Logger log = LoggerFactory.getLogger(ImageBoard.class);
57 |
58 | /**
59 | * Current version of the image board library.
60 | */
61 | public static final String VERSION = "@version@";
62 |
63 | /**
64 | * User agent to send to the services we request data from.
65 | */
66 | private static String userAgent;
67 |
68 | /**
69 | * Requester client.
70 | */
71 | private final RequestFactory requestFactory;
72 |
73 | /**
74 | * Image board's endpoint.
75 | */
76 | private final Board board;
77 |
78 | /**
79 | * Deserialization target.
80 | */
81 | private final Class cls;
82 |
83 | /**
84 | * GET return format of the board.
85 | */
86 | private final ResponseFormat responseFormat;
87 |
88 | /**
89 | * Create a new image board instance.
90 | *
91 | * @param landing Board {@link Board API landing}.
92 | * @param cls The class this refers to.
93 | */
94 | public ImageBoard(Board landing, Class cls) {
95 | this(landing, ResponseFormat.JSON, cls);
96 | }
97 |
98 | /**
99 | * Create a new image board instance.
100 | *
101 | * @param landing Board {@link Board API landing}.
102 | * @param responseFormat Response format of the board.
103 | * @param cls The class this refers to.
104 | */
105 | public ImageBoard(Board landing, ResponseFormat responseFormat, Class cls) {
106 | this(new OkHttpClient.Builder()
107 | .readTimeout(2, TimeUnit.SECONDS)
108 | .build(),
109 | landing,
110 | responseFormat,
111 | cls);
112 | }
113 |
114 | /**
115 | * Create a new image board instance.
116 | *
117 | * @param client {@link RequestFactory}'s request client.
118 | * @param landing Board {@link Board API landing}.
119 | * @param cls The class this refers to.
120 | */
121 | public ImageBoard(OkHttpClient client,
122 | Board landing,
123 | Class cls) {
124 | this(client, landing, ResponseFormat.JSON, cls);
125 | }
126 |
127 | /**
128 | * Create a new image board instance.
129 | *
130 | * @param client {@link RequestFactory}'s request client.
131 | * @param landing Board {@link Board API landing}.
132 | * @param responseFormat Response format of the board.
133 | * @param cls The class this refers to.
134 | */
135 | public ImageBoard(OkHttpClient client,
136 | Board landing,
137 | ResponseFormat responseFormat,
138 | Class cls) {
139 | this.requestFactory = new RequestFactory(client);
140 | this.board = landing;
141 | this.responseFormat = responseFormat;
142 | this.cls = cls;
143 | }
144 |
145 | /**
146 | * Set a custom user agent to use in the requests to image boards (boorus).
147 | * The default one is ImageBoardAPI/https://github.com/Kodehawa/imageboard-api
148 | * This can be changed to basically anything, even a browser agent. Please don't abuse, though.
149 | * @param agent The new user agent to make HTTP requests with.
150 | */
151 | public static void setUserAgent(String agent) {
152 | userAgent = agent;
153 | }
154 |
155 | /**
156 | * Get the current user agent used by ImageBoard. This can be changed with {@link #setUserAgent(String)}
157 | * @return the current user agent used to make HTTP requests with.
158 | */
159 | public static String getUserAgent() {
160 | return userAgent;
161 | }
162 |
163 | /**
164 | * Get the board landing of this instance.
165 | * @return Board type.
166 | */
167 | public Board getBoardType() {
168 | return board;
169 | }
170 |
171 | /**
172 | * Get the image return type of this board.
173 | * @return A java class of the image return type.
174 | */
175 | public Class getImageType() {
176 | return cls;
177 | }
178 |
179 | /**
180 | * Get first page results of the image board, limited at 60 images.
181 | * @return A {@link RequestAction request action} that returns a list of images.
182 | */
183 | public RequestAction> get() {
184 | return get(60);
185 | }
186 |
187 | /**
188 | * Get first page results of the image board.
189 | *
190 | * @param limit Maximum number of images.
191 | * @return A {@link RequestAction request action} that returns a list of images.
192 | */
193 | public RequestAction> get(int limit) {
194 | return get(0, limit);
195 | }
196 |
197 | /**
198 | * Get the provided page's results of the image board.
199 | *
200 | * @param page Page number.
201 | * @param limit Maximum number of images.
202 | * @return A {@link RequestAction request action} that returns a list of images.
203 | */
204 | public RequestAction> get(int page, int limit) {
205 | return get(page, limit, null);
206 | }
207 |
208 | /**
209 | * Get the provided page's results of the image board.
210 | *
211 | * @param page Page number.
212 | * @param limit Maximum number of images.
213 | * @param rating The rating to look for.
214 | * @return A {@link RequestAction request action} that returns a list of images.
215 | */
216 | public RequestAction> get(int page, int limit, Rating rating) {
217 | return makeGetRequest(page, limit, "", rating);
218 | }
219 |
220 | /**
221 | * Get the provided page's results of the image board.
222 | *
223 | * @param limit Maximum number of images.
224 | * @param rating The rating to look for.
225 | * @return A {@link RequestAction request action} that returns a list of images.
226 | */
227 | public RequestAction> get(int limit, Rating rating) {
228 | return get(0, limit, rating);
229 | }
230 |
231 | public RequestAction> search(List search, Rating rating) {
232 | return search(0, 60, String.join(" ", search), rating);
233 | }
234 |
235 | public RequestAction> search(String[] search, Rating rating) {
236 | return search(0, 60, String.join(" ", search), rating);
237 | }
238 |
239 | public RequestAction> search(Rating rating, String... search) {
240 | return search(0, 60, String.join(" ", search), rating);
241 | }
242 |
243 | /**
244 | * Get the first page's results from the image board search, limited at 60 images.
245 | *
246 | * @param search Image tags.
247 | * @return A {@link RequestAction request action} that returns a list of images.
248 | */
249 | public RequestAction> search(String search) {
250 | return search(60, search);
251 | }
252 |
253 | /**
254 | * Get the first page's results from the image board search, limited at 60 images.
255 | *
256 | * @param limit Maximum number of images.
257 | * @param search Image tags.
258 | * @return A {@link RequestAction request action} that returns a list of images.
259 | */
260 | public RequestAction> search(int limit, String search) {
261 | return search(0, limit, search);
262 | }
263 |
264 | /**
265 | * Get the first page's results from the image board search, limited at 60 images.
266 | *
267 | * @param limit Maximum number of images.
268 | * @param search Image tags.
269 | * @param rating The rating to look for
270 | * @return A {@link RequestAction request action} that returns a list of images.
271 | */
272 | public RequestAction> search(int limit, String search, Rating rating) {
273 | return search(0, limit, search, rating);
274 | }
275 |
276 | /**
277 | * Get the first page's results from the image board search, limited at 60 images.
278 | *
279 | * @param page Page number.
280 | * @param limit Maximum number of images.
281 | * @param search Image tags.
282 | * @return A {@link RequestAction request action} that returns a list of images.
283 | */
284 | public RequestAction> search(int page, int limit, String search) {
285 | return makeGetRequest(page, limit, search, null);
286 | }
287 |
288 | /**
289 | * Get the first page's results from the image board search, limited at 60 images.
290 | *
291 | * @param page Page number.
292 | * @param limit Maximum number of images.
293 | * @param search Image tags.
294 | * @param rating The rating to look for.
295 | * @return A {@link RequestAction request action} that returns a list of images.
296 | */
297 | public RequestAction> search(int page, int limit, String search, Rating rating) {
298 | return makeGetRequest(page, limit, search, rating);
299 | }
300 |
301 | /**
302 | * Get the first page's results from the image board search, limited at 60 images.
303 | *
304 | * @param search Image tags.
305 | * @param rating The rating to look for.
306 | * @return A {@link RequestAction request action} that returns a list of images.
307 | */
308 | public RequestAction> search(String search, Rating rating) {
309 | return search(0, 60, search, rating);
310 | }
311 |
312 | public RequestAction> autocomplete(String query) {
313 | return makeAutoCompleteRequest(query, 10);
314 | }
315 |
316 | public RequestAction> autocomplete(String query, int limit) {
317 | return makeAutoCompleteRequest(query, limit);
318 | }
319 |
320 | private RequestAction> makeAutoCompleteRequest(String query, int limit) {
321 | Class extends IAutoComplete> pojo = board.getAutoCompletePOJO();
322 | if (pojo == null) {
323 | throw new IllegalArgumentException("[Autocomplete] This Booru does not support autocomplete.");
324 | }
325 |
326 | HttpUrl.Builder urlBuilder = new HttpUrl.Builder()
327 | .scheme(board.getScheme())
328 | .host(board.getHost())
329 | .addPathSegment(board.getAutoCompletePath());
330 |
331 | // Why
332 | if (getImageType() == GelbooruImage.class) {
333 | urlBuilder.addEncodedQueryParameter("page", "autocomplete2");
334 | }
335 |
336 | urlBuilder.addEncodedQueryParameter(board.getAutoCompleteParameter(), query)
337 | .addQueryParameter("limit", String.valueOf(limit));
338 |
339 | // Why are you alone in this?
340 | if (getImageType() == DanbooruImage.class) {
341 | urlBuilder.addEncodedQueryParameter("search[type]", "tag_query");
342 | }
343 |
344 | HttpUrl url = urlBuilder.build();
345 | return requestFactory.makeRequest(url, response -> {
346 | log.debug("[Autocomplete] Making request to {} (Response format: {}, Booru: {}, Target: {})", url.toString(), responseFormat, board, pojo);
347 | try (ResponseBody body = response.body()) {
348 | if (body == null) {
349 | log.debug("[Autocomplete] Received empty body from a Booru ({})! Returning empty list.", getImageType());
350 | return Collections.emptyList();
351 | }
352 |
353 | ObjectMapper mapper = responseFormat.mapper;
354 | List images;
355 | InputStream json = body.byteStream();
356 |
357 | images = mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, pojo));
358 | body.close();
359 |
360 | return images;
361 | } catch (MismatchedInputException eof) {
362 | log.debug("[Autocomplete] Received MismatchedInputException from a Booru ({})! Returning empty list.", getImageType(), eof);
363 | return Collections.emptyList();
364 | } catch (IOException e) {
365 | throw new QueryParseException(e);
366 | }
367 | });
368 | }
369 |
370 | private RequestAction> makeGetRequest(int page, int limit, String search, Rating rating) throws QueryParseException, QueryFailedException {
371 | HttpUrl.Builder urlBuilder = new HttpUrl.Builder()
372 | .scheme(board.getScheme())
373 | .host(board.getHost())
374 | .addEncodedPathSegment(board.getPath())
375 | .query(board.getQuery())
376 | .addQueryParameter("limit", String.valueOf(limit));
377 |
378 | // Adjust for old Gelbooru searches.
379 | if (rating == Rating.SAFE && getImageType() == GelbooruImage.class)
380 | rating = Rating.GENERAL;
381 | // Adjust in case someone uses GENERAL or SENSITIVE outside of Gelbooru.
382 | // This is very much an adjustment due to Gelbooru being a outliar on the Rating system.
383 | if (rating == Rating.GENERAL && getImageType() != GelbooruImage.class)
384 | rating = Rating.SAFE;
385 | // Adjust for SENSITIVE not existing outside of Gelbooru: adjust to questionable.
386 | if (rating == Rating.SENSITIVE && getImageType() != GelbooruImage.class)
387 | rating = Rating.QUESTIONABLE;
388 |
389 | if (page != 0)
390 | urlBuilder.addQueryParameter(board.getPageMarker(), String.valueOf(page));
391 | if (search != null) {
392 | StringBuilder tags = new StringBuilder(search.toLowerCase().trim());
393 | if(rating != null) {
394 | // I call cursed.
395 | boolean appendLongTag = (board == DefaultBoards.GELBOORU || board == DefaultBoards.R34 || board == DefaultBoards.SAFEBOORU);
396 | tags.append(" rating:").append(appendLongTag ? rating.getLongName() : rating.getShortName());
397 | }
398 |
399 | // Why, just, why, why would you return anything but?
400 | // Other imageboards do this aswell, but we can't filter on all
401 | // Use BoardImage#isPending to check yourself
402 | if (getImageType() == FurryImage.class || getImageType() == SafeFurryImage.class || getImageType() == DanbooruImage.class) {
403 | tags.append(" status:active");
404 | }
405 |
406 | urlBuilder.addEncodedQueryParameter("tags", tags.toString());
407 | }
408 |
409 | HttpUrl url = urlBuilder.build();
410 | return requestFactory.makeRequest(url, response -> {
411 | log.debug("[Get] Making request to {} (Response format: {}, Booru: {}, Target: {})", url.toString(), responseFormat, board, cls);
412 | try (ResponseBody body = response.body()) {
413 | if (body == null) {
414 | log.debug("[Get] Received empty body from a Booru ({})! Returning empty list.", getImageType());
415 | return Collections.emptyList();
416 | }
417 |
418 | ObjectMapper mapper = responseFormat.mapper;
419 | List images;
420 | InputStream json = body.byteStream();
421 |
422 | if(board.getOuterObject() != null) {
423 | String posts = mapper.writeValueAsString(mapper.readTree(json).get(board.getOuterObject()));
424 | images = mapper.readValue(posts, mapper.getTypeFactory().constructCollectionType(List.class, cls));
425 | } else {
426 | images = mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, cls));
427 | }
428 |
429 | body.close();
430 |
431 | return images;
432 | } catch (MismatchedInputException eof) {
433 | log.debug("[Get] Received MismatchedInputException from a Booru ({})! Returning empty list.", getImageType(), eof);
434 | return Collections.emptyList();
435 | } catch (IOException e) {
436 | throw new QueryParseException(e);
437 | }
438 | });
439 | }
440 |
441 | /**
442 | * The type of the specified ImageBoard.
443 | * This is important because if you specify the wrong type, it'll be impossible to deserialize it properly.
444 | * For now we only have JSON, as all imageboards now support a JSON response.
445 | * If your imageboard doesn't by default, make sure it's an option.
446 | */
447 | public enum ResponseFormat {
448 | /** JSON response type. */
449 | JSON(new ObjectMapper());
450 |
451 | private final ObjectMapper mapper;
452 |
453 | ResponseFormat(ObjectMapper mapper) {
454 | this.mapper = mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
455 | }
456 | }
457 | }
458 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/ImageBoards.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards;
18 |
19 | import net.kodehawa.lib.imageboards.boards.DefaultBoards;
20 | import net.kodehawa.lib.imageboards.entities.impl.*;
21 | import okhttp3.OkHttpClient;
22 | import org.jetbrains.annotations.NotNull;
23 | import org.jetbrains.annotations.Nullable;
24 |
25 | import java.util.concurrent.TimeUnit;
26 |
27 | /**
28 | * Utility class representing already-created objects around the most used image boards.
29 | * As of now, this contains the following boorus / imageboards:
30 | *
31 | * - e621 - Furry pictures, both NSFW and safe.
32 | * - Konachan (owned by booru.org) - Anime pictures, both NSFW and safe.
33 | * - Rule34 (owned by booru.org) - Anime pictures, only NSFW
34 | * - Yande.re - Anime pictures, both NSFW and safe (though tagging is sloppy, would recommend setting this to only NSFW)
35 | * - Danbooru (the original one) - Anime pictures, both NSFW and safe.
36 | * - Safebooru (owned by booru.org) - Anime pictures, only safe.
37 | * - e926 (a safe version of e621) - Furry pictures, only safe.
38 | *
39 | *
40 | * It's recommended to lock the usage of the boorus to only NSFW channels unless the image is safe. If you're not
41 | * using this for a discord bot, then just use as your own discretion :P
42 | *
43 | * In difference with {@link DefaultImageBoards} this class allow you to configure {@link OkHttpClient} via passing
44 | * your own client into constructor.
45 | *
46 | * @author Kodehawa
47 | * @author InsanusMokrassar
48 | */
49 | public class ImageBoards {
50 | @NotNull
51 | public final ImageBoard E621;
52 | @NotNull
53 | public final ImageBoard KONACHAN;
54 | @NotNull
55 | public final ImageBoard RULE34;
56 | @NotNull
57 | public final ImageBoard YANDERE;
58 | @NotNull
59 | public final ImageBoard DANBOORU;
60 | @NotNull
61 | public final ImageBoard SAFEBOORU;
62 | @NotNull
63 | public final ImageBoard E926;
64 | @NotNull
65 | public final ImageBoard GELBOORU;
66 |
67 | public ImageBoards(@Nullable OkHttpClient client) {
68 | OkHttpClient localClient = client;
69 | if (localClient == null) {
70 | localClient = new OkHttpClient.Builder()
71 | .connectTimeout(3, TimeUnit.SECONDS)
72 | .readTimeout(3, TimeUnit.SECONDS)
73 | .build();
74 | }
75 |
76 | E621 = new ImageBoard<>(localClient, DefaultBoards.E621, FurryImage.class);
77 | KONACHAN = new ImageBoard<>(localClient, DefaultBoards.KONACHAN, KonachanImage.class);
78 | RULE34 = new ImageBoard<>(localClient, DefaultBoards.R34, Rule34Image.class);
79 | YANDERE = new ImageBoard<>(localClient, DefaultBoards.YANDERE, YandereImage.class);
80 | DANBOORU = new ImageBoard<>(localClient, DefaultBoards.DANBOORU, DanbooruImage.class);
81 | SAFEBOORU = new ImageBoard<>(localClient, DefaultBoards.SAFEBOORU, SafebooruImage.class);
82 | E926 = new ImageBoard<>(localClient, DefaultBoards.E926, SafeFurryImage.class);
83 | GELBOORU = new ImageBoard<>(localClient, DefaultBoards.GELBOORU, GelbooruImage.class);
84 | }
85 |
86 | public static final ImageBoards Default = new ImageBoards(null);
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/boards/Board.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.boards;
18 |
19 | import net.kodehawa.lib.imageboards.entities.impl.autocomplete.IAutoComplete;
20 |
21 | /**
22 | * Information about the board.
23 | *
24 | * @author Avarel
25 | * @author Kodehawa
26 | */
27 | public interface Board {
28 | /**
29 | * @return Scheme of the board. ie. http/https
30 | */
31 | String getScheme();
32 |
33 | /**
34 | * @return Base url of the board.
35 | */
36 | String getHost();
37 |
38 | /**
39 | * @return Path segment.
40 | */
41 | String getPath();
42 |
43 | /**
44 | * @return The string that separates the base url from the queries.
45 | */
46 | String getQuery();
47 |
48 | /**
49 | * @return Page marker.
50 | */
51 | String getPageMarker();
52 |
53 | String getOuterObject();
54 |
55 | String getAutoCompletePath();
56 |
57 | String getAutoCompleteParameter();
58 |
59 | Class extends IAutoComplete> getAutoCompletePOJO();
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/boards/CustomBoard.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.boards;
18 |
19 | import net.kodehawa.lib.imageboards.entities.impl.autocomplete.IAutoComplete;
20 |
21 | /**
22 | * Custom board information.
23 | *
24 | * @author Avarel
25 | * @author Kodehawa
26 | */
27 | public class CustomBoard implements Board {
28 | private final String host;
29 | private final String scheme;
30 | private final String pathSegment;
31 | private final String separator;
32 | private final String pageMarker;
33 | private final String outerObject;
34 | private final String autoCompletePath;
35 | private final String autoCompleteParameter;
36 | private final Class extends IAutoComplete> autoCompletePOJO;
37 |
38 | public CustomBoard(String scheme, String host, String pathSegment, String separator, String pageMarker, String outerObject) {
39 | this.scheme = scheme;
40 | this.pathSegment = pathSegment;
41 | this.separator = separator;
42 | this.host = host;
43 | this.pageMarker = pageMarker;
44 | this.outerObject = outerObject;
45 | this.autoCompleteParameter = null;
46 | this.autoCompletePath = null;
47 | this.autoCompletePOJO = null;
48 | }
49 |
50 | public CustomBoard(String scheme, String host, String pathSegment, String separator, String pageMarker, String outerObject, String autoCompleteParameter,
51 | String autoCompletePath, Class extends IAutoComplete> autoCompletePOJO) {
52 | this.scheme = scheme;
53 | this.pathSegment = pathSegment;
54 | this.separator = separator;
55 | this.host = host;
56 | this.pageMarker = pageMarker;
57 | this.outerObject = outerObject;
58 | this.autoCompleteParameter = autoCompleteParameter;
59 | this.autoCompletePath = autoCompletePath;
60 | this.autoCompletePOJO = autoCompletePOJO;
61 | }
62 |
63 | @Override
64 | public String getScheme() {
65 | return scheme;
66 | }
67 |
68 | @Override
69 | public String getHost() {
70 | return host;
71 | }
72 |
73 | @Override
74 | public String getPath() {
75 | return pathSegment;
76 | }
77 |
78 | @Override
79 | public String getQuery() {
80 | return separator;
81 | }
82 |
83 | @Override
84 | public String getPageMarker() {
85 | return pageMarker;
86 | }
87 |
88 | @Override
89 | public String getOuterObject() {
90 | return outerObject;
91 | }
92 |
93 | @Override
94 | public String getAutoCompletePath() {
95 | return autoCompletePath;
96 | }
97 |
98 | @Override
99 | public String getAutoCompleteParameter() {
100 | return autoCompleteParameter;
101 | }
102 |
103 | @Override
104 | public Class extends IAutoComplete> getAutoCompletePOJO() {
105 | return autoCompletePOJO;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/boards/DefaultBoards.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.boards;
18 |
19 | import net.kodehawa.lib.imageboards.entities.impl.autocomplete.IAutoComplete;
20 | import net.kodehawa.lib.imageboards.entities.impl.autocomplete.pojo.*;
21 |
22 | /**
23 | * The included ImageBoards implementations in this API.
24 | *
25 | * - Rule 34
26 | * - E621
27 | * - Konachan
28 | * - Yande.re
29 | * - Danbooru
30 | * - Safebooru
31 | *
32 | *
33 | * @author Kodehawa
34 | */
35 | public enum DefaultBoards implements Board {
36 | R34("https", "api.rule34.xxx", "index.php", "page=dapi&s=post&q=index&json=1", "pid",
37 | "autocomplete.php", "q", Rule34AutoComplete.class
38 | ),
39 |
40 | E621("https", "e621.net", "posts.json", null, "page", "posts",
41 | "tags/autocomplete.json", "search[name_matches]", FurryAutoComplete.class
42 | ),
43 |
44 | E926("https", "e926.net", "posts.json", null, "page", "posts",
45 | "tags/autocomplete.json", "search[name_matches]", FurryAutoComplete.class
46 | ),
47 |
48 | DANBOORU("https", "danbooru.donmai.us", "posts.json", null, "page",
49 | "autocomplete.json", "search[query]", DanbooruAutoComplete.class
50 | ),
51 |
52 | SAFEBOORU("https", "safebooru.org", "index.php", "page=dapi&s=post&q=index&json=1", "pid",
53 | "autocomplete.php", "q", SafebooruAutoComplete.class
54 | ),
55 |
56 | GELBOORU("https", "gelbooru.com", "index.php", "page=dapi&s=post&q=index&json=1", "pid",
57 | "post", "index.php", "term", GelbooruAutoComplete.class
58 | ),
59 |
60 | KONACHAN("http", "konachan.com", "post.json", null, "page"),
61 | YANDERE("https", "yande.re", "post.json", null, "page");
62 |
63 | private final String scheme;
64 | private final String pathSegment;
65 | private final String host;
66 | private final String query;
67 | private final String pageMarker;
68 | private final String outerObject;
69 | private final String autoCompletePath;
70 | private final String autoCompleteParameter;
71 | private final Class extends IAutoComplete> autoCompletePOJO;
72 |
73 | DefaultBoards(String scheme, String host, String pathSegment, String query, String pageMarker) {
74 | this.scheme = scheme;
75 | this.host = host;
76 | this.query = query;
77 | this.pathSegment = pathSegment;
78 | this.pageMarker = pageMarker;
79 | this.autoCompletePath = null;
80 | this.autoCompleteParameter = null;
81 | this.autoCompletePOJO = null;
82 | this.outerObject = null;
83 | }
84 |
85 | DefaultBoards(String scheme, String host, String pathSegment, String query, String pageMarker, String autoCompletePath,
86 | String autoCompleteParameter, Class extends IAutoComplete> autoCompletePOJO) {
87 | this.scheme = scheme;
88 | this.host = host;
89 | this.query = query;
90 | this.pathSegment = pathSegment;
91 | this.pageMarker = pageMarker;
92 | this.autoCompletePath = autoCompletePath;
93 | this.autoCompleteParameter = autoCompleteParameter;
94 | this.autoCompletePOJO = autoCompletePOJO;
95 | this.outerObject = null;
96 | }
97 |
98 | DefaultBoards(String scheme, String host, String pathSegment, String query, String pageMarker, String outerObject) {
99 | this.scheme = scheme;
100 | this.host = host;
101 | this.query = query;
102 | this.pathSegment = pathSegment;
103 | this.pageMarker = pageMarker;
104 | this.outerObject = outerObject;
105 | this.autoCompleteParameter = null;
106 | this.autoCompletePath = null;
107 | this.autoCompletePOJO = null;
108 | }
109 |
110 | DefaultBoards(String scheme, String host, String pathSegment, String query, String pageMarker, String outerObject, String autoCompletePath,
111 | String autoCompleteParameter, Class extends IAutoComplete> autoCompletePOJO) {
112 | this.scheme = scheme;
113 | this.host = host;
114 | this.query = query;
115 | this.pathSegment = pathSegment;
116 | this.pageMarker = pageMarker;
117 | this.outerObject = outerObject;
118 | this.autoCompleteParameter = autoCompleteParameter;
119 | this.autoCompletePath = autoCompletePath;
120 | this.autoCompletePOJO = autoCompletePOJO;
121 | }
122 |
123 | @Override
124 | public String getScheme() {
125 | return scheme;
126 | }
127 |
128 | @Override
129 | public String getPath() {
130 | return pathSegment;
131 | }
132 |
133 | @Override
134 | public String getQuery() {
135 | return query;
136 | }
137 |
138 | @Override
139 | public String getHost() {
140 | return host;
141 | }
142 |
143 | @Override
144 | public String getPageMarker() {
145 | return pageMarker;
146 | }
147 |
148 | @Override
149 | public String getOuterObject() {
150 | return outerObject;
151 | }
152 |
153 | @Override
154 | public String getAutoCompletePath() {
155 | return autoCompletePath;
156 | }
157 |
158 | @Override
159 | public String getAutoCompleteParameter() {
160 | return autoCompleteParameter;
161 | }
162 |
163 | @Override
164 | public Class extends IAutoComplete> getAutoCompletePOJO() {
165 | return autoCompletePOJO;
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/BoardImage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.entities;
18 |
19 | import com.fasterxml.jackson.annotation.JsonIgnore;
20 | import okhttp3.HttpUrl;
21 |
22 | import java.util.List;
23 |
24 | /**
25 | * Common board image interface.
26 | * @author NatchRaben
27 | */
28 | public interface BoardImage {
29 | /**
30 | * @return Width of the image.
31 | */
32 | int getWidth();
33 |
34 | /**
35 | * @return Height of the image.
36 | */
37 | int getHeight();
38 |
39 | /**
40 | * @return Score of the image.
41 | */
42 | int getScore();
43 |
44 | /**
45 | * @return Rating of the image.
46 | */
47 | Rating getRating();
48 |
49 | /**
50 | * @return Tags of the image.
51 | */
52 | List getTags();
53 |
54 | /**
55 | * @return Image url.
56 | */
57 | String getURL();
58 |
59 | /**
60 | * @return Whether the image has a children attached.
61 | */
62 | boolean hasChildren();
63 |
64 | /**
65 | * @return Whether the image is pending, held or deleted.
66 | */
67 | boolean isPending();
68 |
69 | /**
70 | * The time when the image was created in milliseconds
71 | * @return millis
72 | */
73 | long getCreationMillis();
74 |
75 | /**
76 | * @return The URL to use to perform an autocomplete search.
77 | */
78 | @JsonIgnore
79 | default HttpUrl getAutoCompleteURL(String query, int limit) {
80 | return null;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/Rating.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.entities;
18 |
19 | import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
20 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
21 |
22 | /**
23 | * Board image ratings. Just remember that God is watching.
24 | *
25 | * @author Avarel
26 | */
27 | @JsonDeserialize(using = RatingDeserializer.class)
28 | public enum Rating {
29 | /**
30 | * Safe for family and friends. I'd imagine.
31 | */
32 | SAFE("s"),
33 |
34 | /**
35 | * Safe for family and friends. I'd imagine.
36 | * DO NOT USE OUTSIDE OF GelbooruImage. This will adjust to SAFE otherwise.
37 | */
38 | GENERAL("g"), // Gelbooru bullshit?
39 |
40 | /**
41 | * Questionable board images. Borderline explicit.
42 | */
43 | QUESTIONABLE("q"),
44 |
45 | /**
46 | * Sensitive board images. Borderline explicit.
47 | * DO NOT USE OUTSIDE OF GelbooruImage. This will adjust to QUESTIONABLE otherwise.
48 | */
49 | SENSITIVE("se"), // gelbooru bullshit, part 2
50 |
51 | /**
52 | * Default rating, assume the worst.
53 | * Board images with explicit/NSFW ratings.
54 | */
55 | @JsonEnumDefaultValue
56 | EXPLICIT("e");
57 |
58 | final String shortName;
59 | final String longName;
60 |
61 | Rating(String shortName) {
62 | this.shortName = shortName;
63 | this.longName = this.name().toLowerCase();
64 | }
65 |
66 | public String getShortName() {
67 | return shortName;
68 | }
69 |
70 | public String getLongName() {
71 | return longName;
72 | }
73 |
74 | /**
75 | * Looks up the rating based on the full name, if nothing is found returns null.
76 | *
77 | * @param name The String value to match
78 | * @return The badge, or null if nothing is found.
79 | */
80 | public static Rating lookupFromString(String name) {
81 | for (Rating b : Rating.values()) {
82 | if (b.name().equalsIgnoreCase(name)) {
83 | return b;
84 | }
85 | }
86 | return null;
87 | }
88 |
89 | /**
90 | * Looks up the rating based on the full name, if nothing is found returns null.
91 | *
92 | * @param shortName The short name to match
93 | * @return The badge, or null if nothing is found.
94 | */
95 | public static Rating lookupFromStringShort(String shortName) {
96 | for (Rating b : Rating.values()) {
97 | if (b.getShortName().equalsIgnoreCase(shortName)) {
98 | return b;
99 | }
100 | }
101 | return null;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/RatingDeserializer.java:
--------------------------------------------------------------------------------
1 | package net.kodehawa.lib.imageboards.entities;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.databind.DeserializationContext;
5 | import com.fasterxml.jackson.databind.JsonDeserializer;
6 |
7 | import java.io.IOException;
8 |
9 | public class RatingDeserializer extends JsonDeserializer {
10 |
11 | @Override
12 | public Rating deserialize(JsonParser parser, DeserializationContext ctx)
13 | throws IOException {
14 | String value = parser.getValueAsString();
15 | Rating rating = Rating.lookupFromStringShort(value);
16 | if (rating != null) {
17 | return rating;
18 | }
19 | rating = Rating.lookupFromString(value);
20 | if (rating != null) {
21 | return rating;
22 | }
23 | throw new IOException("Unable to deserialize rating " + value);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/exceptions/QueryFailedException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.entities.exceptions;
18 |
19 | /**
20 | * Exception thrown when the image board returns a response
21 | * code other than 200.
22 | *
23 | * @author Kodehawa
24 | */
25 | public class QueryFailedException extends RuntimeException {
26 | private final int code;
27 | private final String url;
28 |
29 | public QueryFailedException(int code, String url) {
30 | super("Failed to query " + url);
31 | this.code = code;
32 | this.url = url;
33 | }
34 |
35 | public QueryFailedException(int code, String url, Throwable e) {
36 | super("Failed to query " + url, e);
37 | this.code = code;
38 | this.url = url;
39 | }
40 |
41 | public int getCode() {
42 | return code;
43 | }
44 |
45 | public String getURL() {
46 | return url;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/exceptions/QueryParseException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.entities.exceptions;
18 |
19 | /**
20 | * Exception thrown when the image board return a response
21 | * that causes errors during parsing.
22 | *
23 | * @author Kodehawa
24 | */
25 | public class QueryParseException extends RuntimeException {
26 | public QueryParseException(Throwable e) {
27 | super("Failed to parse response from an ImageBoard.", e);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/DanbooruImage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.entities.impl;
18 |
19 | import com.fasterxml.jackson.annotation.JsonProperty;
20 | import net.kodehawa.lib.imageboards.entities.BoardImage;
21 | import net.kodehawa.lib.imageboards.entities.Rating;
22 |
23 | import java.time.ZonedDateTime;
24 | import java.util.Arrays;
25 | import java.util.Collections;
26 | import java.util.List;
27 | import java.util.regex.Matcher;
28 | import java.util.regex.Pattern;
29 |
30 | /**
31 | * @author Kodehawa
32 | */
33 | public class DanbooruImage implements BoardImage {
34 | private int uploader_id;
35 | @JsonProperty("created_at")
36 | private String created_at;
37 | private int score;
38 | private String source;
39 | private Rating rating;
40 | private int image_width;
41 | private int image_height;
42 | private String tag_string;
43 | private String file_ext;
44 | private int file_size;
45 | private int up_score;
46 | private int down_score;
47 | private int tag_count;
48 | private String uploader_name;
49 | private String tag_string_artist;
50 | private String tag_string_character;
51 | @JsonProperty("file_url")
52 | private String file_url;
53 | @JsonProperty("large_file_url")
54 | private String large_file_url;
55 | @JsonProperty("preview_file_url")
56 | private String preview_file_url;
57 | @JsonProperty("has_children")
58 | private boolean has_children;
59 |
60 | private boolean is_pending;
61 | private boolean is_flagged;
62 | private boolean is_deleted;
63 |
64 | private Pattern urlPattern = Pattern.compile("https(:)?//[\\w\\d.]*donmai.us");
65 |
66 | /**
67 | * Danbooru normally returns the URL as "file_url": "/data/__furude_rika_higurashi_no_naku_koro_ni_drawn_by_kamaboko_red__fc6fb27e9c6ea2a77c849e5483eafc40.png"
68 | * Which isn't reachable. This methods gets around it.
69 | * @return The *reachable* URL to get this image. PNG format, or the extension defined in file_ext.
70 | */
71 | public String getParsedFileUrl() {
72 | return getFixedURL(getFile_url());
73 | }
74 |
75 | /**
76 | * Danbooru normally returns the URL as "large_file_url": "/data/__furude_rika_higurashi_no_naku_koro_ni_drawn_by_kamaboko_red__fc6fb27e9c6ea2a77c849e5483eafc40.jpg"
77 | * Which isn't reachable. This methods gets around it.
78 | * @return The *reachable* URL to get this image. JPG format.
79 | */
80 | public String getParsedLargeFileUrl() {
81 | return getFixedURL(getLarge_file_url());
82 | }
83 |
84 | /**
85 | * Danbooru normally returns the URL as "preview_file_url": "/data/preview/fc6fb27e9c6ea2a77c849e5483eafc40.jpg"
86 | * Which isn't reachable. This methods gets around it.
87 | * @return The *reachable* URL to get this image. JPG format.
88 | */
89 | public String getParsedPreviewFileUrl() {
90 | return getFixedURL(this.getPreview_file_url());
91 | }
92 |
93 | private String getFixedURL(String url) {
94 | if (url == null) {
95 | return null;
96 | }
97 |
98 | Matcher matcher = urlPattern.matcher(url);
99 | if(matcher.find()) {
100 | if(matcher.group(1).isEmpty()) {
101 | // Broken URL (https//)
102 | return url.replace("https//", "https://");
103 | } else {
104 | return url; // Valid URL
105 | }
106 | } else {
107 | // URL without domain (/data/XXX)
108 | return "https://danbooru.donmai.us" + url;
109 | }
110 | }
111 |
112 | public int getUploader_id() {
113 | return uploader_id;
114 | }
115 |
116 | public String getSource() {
117 | return source;
118 | }
119 |
120 | public int getImage_width() {
121 | return image_width;
122 | }
123 |
124 | public int getImage_height() {
125 | return image_height;
126 | }
127 |
128 | public String getTag_string() {
129 | return tag_string;
130 | }
131 |
132 | public String getFile_ext() {
133 | return file_ext;
134 | }
135 |
136 | public int getFile_size() {
137 | return file_size;
138 | }
139 |
140 | public int getUp_score() {
141 | return up_score;
142 | }
143 |
144 | public int getDown_score() {
145 | return down_score;
146 | }
147 |
148 | public int getTag_count() {
149 | return tag_count;
150 | }
151 |
152 | public String getUploader_name() {
153 | return uploader_name;
154 | }
155 |
156 | public String getTag_string_artist() {
157 | return tag_string_artist;
158 | }
159 |
160 | public String getTag_string_character() {
161 | return tag_string_character;
162 | }
163 |
164 | public String getFile_url() {
165 | return file_url;
166 | }
167 |
168 | public String getLarge_file_url() {
169 | return large_file_url;
170 | }
171 |
172 | public String getPreview_file_url() {
173 | return preview_file_url;
174 | }
175 |
176 | public boolean isHas_children() {
177 | return has_children;
178 | }
179 |
180 | public boolean isIs_pending() {
181 | return is_pending;
182 | }
183 |
184 | public boolean isIs_flagged() {
185 | return is_flagged;
186 | }
187 |
188 | public boolean isIs_deleted() {
189 | return is_deleted;
190 | }
191 |
192 | @Override
193 | public int getWidth() {
194 | return image_width;
195 | }
196 |
197 | @Override
198 | public int getHeight() {
199 | return image_height;
200 | }
201 |
202 | @Override
203 | public Rating getRating() {
204 | return rating;
205 | }
206 |
207 | @Override
208 | public int getScore() {
209 | return score;
210 | }
211 |
212 | @Override
213 | public List getTags() {
214 | return Collections.unmodifiableList(Arrays.asList(tag_string.split(" ")));
215 | }
216 |
217 | @Override
218 | public String getURL() {
219 | return getParsedFileUrl();
220 | }
221 |
222 | @Override
223 | public boolean hasChildren() {
224 | return isHas_children();
225 | }
226 |
227 | @Override
228 | public boolean isPending() {
229 | return is_pending || is_deleted || is_flagged;
230 | }
231 |
232 | @Override
233 | public long getCreationMillis() {
234 | return ZonedDateTime.parse(created_at).toInstant().toEpochMilli();
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/FurryImage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.entities.impl;
18 |
19 | import com.fasterxml.jackson.annotation.JsonIgnore;
20 | import com.fasterxml.jackson.annotation.JsonProperty;
21 | import net.kodehawa.lib.imageboards.entities.BoardImage;
22 | import net.kodehawa.lib.imageboards.entities.Rating;
23 |
24 | import java.time.ZonedDateTime;
25 | import java.util.Collection;
26 | import java.util.List;
27 | import java.util.stream.Collectors;
28 | import java.util.stream.Stream;
29 |
30 | /**
31 | * @author Kodehawa
32 | */
33 | public class FurryImage implements BoardImage {
34 | @JsonProperty("created_at")
35 | private String created_at;
36 | private String description;
37 | private Rating rating;
38 | private File file;
39 | private Flags flags;
40 |
41 | @JsonProperty("has_children")
42 | private boolean has_children;
43 |
44 | @JsonProperty("score")
45 | private Score score;
46 | @JsonProperty("tags")
47 | private Tags tags;
48 |
49 | public boolean isHas_children() {
50 | return has_children;
51 | }
52 |
53 | //Image description
54 | public String getDescription() {
55 | return description;
56 | }
57 |
58 | public File getFile() {
59 | return file;
60 | }
61 |
62 | public Tags getAllTags() {
63 | return tags;
64 | }
65 |
66 | public Flags getFlags() {
67 | return flags;
68 | }
69 |
70 | static class Score {
71 | private int up;
72 | private int down;
73 | private int total;
74 |
75 | public int getUp() {
76 | return up;
77 | }
78 |
79 | public int getDown() {
80 | return down;
81 | }
82 |
83 | public int getTotal() {
84 | return total;
85 | }
86 | }
87 |
88 | static class Tags {
89 | private List general;
90 | private List species;
91 | private List character;
92 | private List lore;
93 | private List meta;
94 | private List artist;
95 | private List copyright;
96 |
97 | public List getGeneral() {
98 | return general;
99 | }
100 |
101 | public List getSpecies() {
102 | return species;
103 | }
104 |
105 | public List getCharacter() {
106 | return character;
107 | }
108 |
109 | public List getLore() {
110 | return lore;
111 | }
112 |
113 | public List getMeta() {
114 | return meta;
115 | }
116 |
117 | public List getArtist() {
118 | return artist;
119 | }
120 |
121 | public List getCopyright() {
122 | return copyright;
123 | }
124 |
125 | public List getAll() {
126 | return Stream.of(general, species, character, lore, meta, artist, copyright)
127 | .flatMap(Collection::stream)
128 | .collect(Collectors.toList());
129 | }
130 | }
131 |
132 | static class Flags {
133 | private boolean pending;
134 | private boolean flagged;
135 | private boolean note_locked;
136 | private boolean status_locked;
137 | private boolean rating_locked;
138 | private boolean deleted;
139 |
140 | public boolean isPending() {
141 | return pending;
142 | }
143 |
144 | public boolean isFlagged() {
145 | return flagged;
146 | }
147 |
148 | public boolean isNote_locked() {
149 | return note_locked;
150 | }
151 |
152 | public boolean isStatus_locked() {
153 | return status_locked;
154 | }
155 |
156 | public boolean isRating_locked() {
157 | return rating_locked;
158 | }
159 |
160 | public boolean isDeleted() {
161 | return deleted;
162 | }
163 | }
164 |
165 | static class File {
166 | @JsonProperty("width")
167 | private int width;
168 | @JsonProperty("height")
169 | private int height;
170 | @JsonProperty("size")
171 | private int size;
172 | @JsonProperty("url")
173 | private String url;
174 |
175 | public int getWidth() {
176 | return width;
177 | }
178 |
179 | public int getHeight() {
180 | return height;
181 | }
182 |
183 | public int getSize() {
184 | return size;
185 | }
186 |
187 | public String getUrl() {
188 | return url;
189 | }
190 | }
191 |
192 | @Override
193 | public int getWidth() {
194 | return getFile().getWidth();
195 | }
196 |
197 | @Override
198 | public int getHeight() {
199 | return getFile().getHeight();
200 | }
201 |
202 | @Override
203 | public int getScore() {
204 | return score.getTotal();
205 | }
206 |
207 | @Override
208 | public Rating getRating() {
209 | return rating;
210 | }
211 |
212 | @Override
213 | @JsonIgnore
214 | public List getTags() {
215 | return tags.getAll();
216 | }
217 |
218 | public List getArtist() {
219 | return getAllTags().getArtist();
220 | }
221 |
222 | @Override
223 | public String getURL() {
224 | return getFile().getUrl();
225 | }
226 |
227 | @Override
228 | public boolean hasChildren() {
229 | return isHas_children();
230 | }
231 |
232 | @Override
233 | public boolean isPending() {
234 | return getFlags().isPending() || getFlags().isDeleted() || getFlags().isFlagged();
235 | }
236 |
237 | @Override
238 | public long getCreationMillis() {
239 | return ZonedDateTime.parse(created_at).toInstant().toEpochMilli();
240 | }
241 | }
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/GelbooruImage.java:
--------------------------------------------------------------------------------
1 | package net.kodehawa.lib.imageboards.entities.impl;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import net.kodehawa.lib.imageboards.entities.BoardImage;
5 | import net.kodehawa.lib.imageboards.entities.Rating;
6 |
7 | import java.util.Arrays;
8 | import java.util.Collections;
9 | import java.util.List;
10 |
11 | public class GelbooruImage implements BoardImage {
12 | private String source;
13 | private String hash;
14 | private int height;
15 | private int width;
16 | private int id;
17 | private String image;
18 | private String owner;
19 | private Rating rating;
20 | private String tags;
21 | private String file_url; //Thanks gelbooru for giving a full url I love you
22 | private int score;
23 | @JsonProperty("has_children")
24 | private boolean has_children;
25 | @JsonProperty("change")
26 | private long change; // timestamp in seconds
27 |
28 | public String getSource() {
29 | return source;
30 | }
31 |
32 | public String getHash() {
33 | return hash;
34 | }
35 |
36 | public int getId() {
37 | return id;
38 | }
39 |
40 | public String getImage() {
41 | return image;
42 | }
43 |
44 | public String getOwner() {
45 | return owner;
46 | }
47 |
48 | public String getFile_url() {
49 | return file_url;
50 | }
51 |
52 | public boolean isHas_children() {
53 | return has_children;
54 | }
55 |
56 | @Override
57 | public Rating getRating() {
58 | return rating;
59 | }
60 |
61 | @Override
62 | public List getTags() {
63 | return Collections.unmodifiableList(Arrays.asList(tags.split(" ")));
64 | }
65 |
66 | @Override
67 | public int getScore() {
68 | return score;
69 | }
70 |
71 | @Override
72 | public int getHeight() {
73 | return height;
74 | }
75 |
76 | @Override
77 | public int getWidth() {
78 | return width;
79 | }
80 |
81 | @Override
82 | public String getURL() {
83 | return getFile_url();
84 | }
85 |
86 | @Override
87 | public boolean hasChildren() {
88 | return isHas_children();
89 | }
90 |
91 | // Doesn't implement this
92 | @Override
93 | public boolean isPending() {
94 | return false;
95 | }
96 |
97 | @Override
98 | public long getCreationMillis() {
99 | return change * 1000;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/KonachanImage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.entities.impl;
18 |
19 | import com.fasterxml.jackson.annotation.JsonIgnore;
20 | import com.fasterxml.jackson.annotation.JsonProperty;
21 | import net.kodehawa.lib.imageboards.entities.BoardImage;
22 | import net.kodehawa.lib.imageboards.entities.Rating;
23 |
24 | import java.util.Arrays;
25 | import java.util.Collections;
26 | import java.util.List;
27 |
28 | /**
29 | * @author Kodehawa
30 | */
31 | public class KonachanImage implements BoardImage {
32 | private String author;
33 | @JsonProperty("created_at")
34 | private long created_at;
35 | private long file_size;
36 | private String file_url;
37 | private int height;
38 | private int id;
39 | private long jpeg_file_size;
40 | private int jpeg_height;
41 | private String jpeg_url;
42 | private int jpeg_width;
43 | private int preview_height;
44 | private String preview_url;
45 | private int preview_width;
46 | private Rating rating;
47 | private long sample_file_size;
48 | private int sample_height;
49 | private String sample_url;
50 | private int sample_width;
51 | private int score;
52 | private String source;
53 | private String status;
54 | private String tags;
55 | @JsonProperty("has_children")
56 | private boolean has_children;
57 | @JsonProperty("is_held")
58 | private boolean is_held;
59 |
60 | public long getCreated_at() {
61 | return created_at;
62 | }
63 |
64 | public long getFile_size() {
65 | return file_size;
66 | }
67 |
68 | public String getFile_url() {
69 | return file_url;
70 | }
71 |
72 | public long getJpeg_file_size() {
73 | return jpeg_file_size;
74 | }
75 |
76 | public int getJpeg_height() {
77 | return jpeg_height;
78 | }
79 |
80 | public int getJpeg_width() {
81 | return jpeg_width;
82 | }
83 |
84 | public int getPreview_height() {
85 | return preview_height;
86 | }
87 |
88 | public String getPreview_url() {
89 | return preview_url;
90 | }
91 |
92 | public int getPreview_width() {
93 | return preview_width;
94 | }
95 |
96 | public long getSample_file_size() {
97 | return sample_file_size;
98 | }
99 |
100 | public int getSample_height() {
101 | return sample_height;
102 | }
103 |
104 | public String getSample_url() {
105 | return sample_url;
106 | }
107 |
108 | public int getSample_width() {
109 | return sample_width;
110 | }
111 |
112 | public String getSource() {
113 | return source;
114 | }
115 |
116 | private int width;
117 |
118 | public String getAuthor() {
119 | return author;
120 | }
121 |
122 | public int getId() {
123 | return id;
124 | }
125 |
126 | @JsonIgnore
127 | public String getParsedUrl() {
128 | return jpeg_url;
129 | }
130 |
131 | public String getJpeg_url() {
132 | return jpeg_url;
133 | }
134 |
135 | public String getStatus() {
136 | return status;
137 | }
138 |
139 | public boolean isHas_children() {
140 | return has_children;
141 | }
142 |
143 | @Override
144 | public int getScore() {
145 | return score;
146 | }
147 |
148 | @Override
149 | public int getWidth() {
150 | return width;
151 | }
152 |
153 | @Override
154 | public int getHeight() {
155 | return height;
156 | }
157 |
158 | @Override
159 | public Rating getRating() {
160 | return rating;
161 | }
162 |
163 | @Override
164 | public List getTags() {
165 | return tags == null ? Collections.emptyList() : Collections.unmodifiableList(Arrays.asList(tags.split(" ")));
166 | }
167 |
168 | @Override
169 | public String getURL() {
170 | return getParsedUrl();
171 | }
172 |
173 | @Override
174 | public boolean hasChildren() {
175 | return isHas_children();
176 | }
177 |
178 | @Override
179 | public boolean isPending() {
180 | return is_held;
181 | }
182 |
183 | @Override
184 | public long getCreationMillis() {
185 | return created_at * 1000;
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/Rule34Image.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.entities.impl;
18 |
19 | import com.fasterxml.jackson.annotation.JsonIgnore;
20 | import com.fasterxml.jackson.annotation.JsonProperty;
21 | import net.kodehawa.lib.imageboards.entities.BoardImage;
22 | import net.kodehawa.lib.imageboards.entities.Rating;
23 |
24 | import java.util.Arrays;
25 | import java.util.Collections;
26 | import java.util.List;
27 |
28 | /**
29 | * @author Kodehawa
30 | */
31 | public class Rule34Image implements BoardImage {
32 | private String directory;
33 | private String image;
34 | private int height;
35 | private String tags;
36 | private int width;
37 | private String file_url;
38 | @JsonProperty("change")
39 | private long change; // timestamp in seconds
40 |
41 | //Backwards-compatible.
42 | public String getFile_url() {
43 | return file_url;
44 | }
45 |
46 | public String getDirectory() {
47 | return directory;
48 | }
49 |
50 | public String getImage() {
51 | return image;
52 | }
53 |
54 | @Override
55 | public int getWidth() {
56 | return width;
57 | }
58 |
59 | @Override
60 | public int getHeight() {
61 | return height;
62 | }
63 |
64 | @Override
65 | public int getScore() {
66 | return 0;
67 | }
68 |
69 | @Override
70 | public Rating getRating() {
71 | return Rating.EXPLICIT;
72 | }
73 |
74 | @Override
75 | public List getTags() {
76 | return Collections.unmodifiableList(Arrays.asList(tags.split(" ")));
77 | }
78 |
79 | @Override
80 | @JsonIgnore
81 | public String getURL(){
82 | return getFile_url();
83 | }
84 |
85 | // Doesn't implement it, lol.
86 | @Override
87 | @JsonIgnore
88 | public boolean hasChildren() {
89 | return false;
90 | }
91 |
92 | // Doesn't implement it
93 | @Override
94 | public boolean isPending() {
95 | return false;
96 | }
97 |
98 | @Override
99 | public long getCreationMillis() {
100 | return change * 1000;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/SafeFurryImage.java:
--------------------------------------------------------------------------------
1 | package net.kodehawa.lib.imageboards.entities.impl;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import net.kodehawa.lib.imageboards.entities.BoardImage;
5 | import net.kodehawa.lib.imageboards.entities.Rating;
6 |
7 | import java.time.ZonedDateTime;
8 | import java.util.Collection;
9 | import java.util.Collections;
10 | import java.util.List;
11 | import java.util.stream.Collectors;
12 | import java.util.stream.Stream;
13 |
14 | public class SafeFurryImage implements BoardImage {
15 | @JsonProperty("created_at")
16 | private String created_at;
17 | private String description;
18 | private Rating rating;
19 | private File file;
20 | private Flags flags;
21 |
22 | @JsonProperty("score")
23 | private Score score;
24 | @JsonProperty("tags")
25 | private Tags tags;
26 |
27 | public List getTags() {
28 | return tags.getAll();
29 | }
30 |
31 | public Tags getAllTags() {
32 | return tags;
33 | }
34 |
35 | public String getDescription() {
36 | return description;
37 | }
38 |
39 | public File getFile() {
40 | return file;
41 | }
42 |
43 | public int getScore() {
44 | return score.total;
45 | }
46 |
47 | public String getURL() {
48 | return file.url;
49 | }
50 |
51 | public Rating getRating() {
52 | return rating;
53 | }
54 |
55 | public int getWidth() {
56 | return file.width;
57 | }
58 |
59 | public int getHeight() {
60 | return file.height;
61 | }
62 |
63 | public List getArtist() {
64 | return tags.artist;
65 | }
66 |
67 | public Flags getFlags() {
68 | return flags;
69 | }
70 |
71 | static class Score {
72 | private int up;
73 | private int down;
74 | private int total;
75 |
76 | public int getUp() {
77 | return up;
78 | }
79 |
80 | public int getDown() {
81 | return down;
82 | }
83 |
84 | public int getTotal() {
85 | return total;
86 | }
87 | }
88 |
89 | static class Tags {
90 | private List general;
91 | private List species;
92 | private List character;
93 | private List lore;
94 | private List meta;
95 | private List artist;
96 | private List copyright;
97 |
98 | public List getGeneral() {
99 | return general;
100 | }
101 |
102 | public List getSpecies() {
103 | return species;
104 | }
105 |
106 | public List getCharacter() {
107 | return character;
108 | }
109 |
110 | public List getLore() {
111 | return lore;
112 | }
113 |
114 | public List getMeta() {
115 | return meta;
116 | }
117 |
118 | public List getArtist() {
119 | return artist;
120 | }
121 |
122 | public List getCopyright() {
123 | return copyright;
124 | }
125 |
126 | public List getAll() {
127 | return Stream.of(general, species, character, lore, meta, artist, copyright)
128 | .flatMap(Collection::stream)
129 | .collect(Collectors.toList());
130 | }
131 | }
132 |
133 | static class File {
134 | private int width;
135 | private int height;
136 | private int size;
137 | private String url;
138 |
139 | public int getWidth() {
140 | return width;
141 | }
142 |
143 | public int getHeight() {
144 | return height;
145 | }
146 |
147 | public int getSize() {
148 | return size;
149 | }
150 |
151 | public String getUrl() {
152 | return url;
153 | }
154 | }
155 |
156 | static class Flags {
157 | private boolean pending;
158 | private boolean flagged;
159 | private boolean note_locked;
160 | private boolean status_locked;
161 | private boolean rating_locked;
162 | private boolean deleted;
163 |
164 | public boolean isPending() {
165 | return pending;
166 | }
167 |
168 | public boolean isFlagged() {
169 | return flagged;
170 | }
171 |
172 | public boolean isNote_locked() {
173 | return note_locked;
174 | }
175 |
176 | public boolean isStatus_locked() {
177 | return status_locked;
178 | }
179 |
180 | public boolean isRating_locked() {
181 | return rating_locked;
182 | }
183 |
184 | public boolean isDeleted() {
185 | return deleted;
186 | }
187 | }
188 |
189 | // Doesn't implement it, probably doesn't matter since it's a safe board.
190 | @Override
191 | public boolean hasChildren() {
192 | return false;
193 | }
194 |
195 | @Override
196 | public boolean isPending() {
197 | return getFlags().isPending() || getFlags().isDeleted() || getFlags().isFlagged();
198 | }
199 |
200 | @Override
201 | public long getCreationMillis() {
202 | return ZonedDateTime.parse(created_at).toInstant().toEpochMilli();
203 | }
204 | }
205 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/SafebooruImage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.entities.impl;
18 |
19 | import com.fasterxml.jackson.annotation.JsonProperty;
20 | import net.kodehawa.lib.imageboards.entities.BoardImage;
21 | import net.kodehawa.lib.imageboards.entities.Rating;
22 |
23 | import java.util.Arrays;
24 | import java.util.Collections;
25 | import java.util.List;
26 |
27 | /**
28 | * @author Kodehawa
29 | */
30 | public class SafebooruImage implements BoardImage {
31 | private String directory;
32 | private String image;
33 | private int height;
34 | private int width;
35 | private String tags;
36 | @JsonProperty("id")
37 | private int id;
38 | @JsonProperty("change")
39 | private long change; // timestamp in seconds
40 |
41 | public String getFileUrl() {
42 | return "https://safebooru.org/images/" + directory + "/" + image;
43 | }
44 |
45 | public String getDirectory() {
46 | return directory;
47 | }
48 |
49 | public String getImage() {
50 | return image;
51 | }
52 |
53 | @Override
54 | public int getWidth() {
55 | return width;
56 | }
57 |
58 | @Override
59 | public int getHeight() {
60 | return height;
61 | }
62 |
63 | public int getScore() {
64 | return 0;
65 | }
66 |
67 | @Override
68 | public Rating getRating() {
69 | return Rating.SAFE;
70 | }
71 |
72 | public int getId(){
73 | return id;
74 | }
75 |
76 | @Override
77 | public List getTags() {
78 | return Collections.unmodifiableList(Arrays.asList(tags.split(" ")));
79 | }
80 |
81 | @Override
82 | public String getURL(){
83 | return getFileUrl();
84 | }
85 |
86 | // Doesn't implement it, probably doesn't matter since it's a safe board.
87 | @Override
88 | public boolean hasChildren() {
89 | return false;
90 | }
91 |
92 | // Doesn't implement it, old version of board
93 | @Override
94 | public boolean isPending() {
95 | return false;
96 | }
97 |
98 | @Override
99 | public long getCreationMillis() {
100 | return change * 1000;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/YandereImage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.entities.impl;
18 |
19 | import com.fasterxml.jackson.annotation.JsonProperty;
20 | import net.kodehawa.lib.imageboards.entities.BoardImage;
21 | import net.kodehawa.lib.imageboards.entities.Rating;
22 |
23 | import java.util.Arrays;
24 | import java.util.Collections;
25 | import java.util.List;
26 |
27 | /**
28 | * @author Kodehawa
29 | */
30 | public class YandereImage implements BoardImage {
31 | private int actual_preview_width;
32 | private String author;
33 | private String file_ext;
34 | private int file_size;
35 | private String file_url;
36 | private int height;
37 | private int id;
38 | private int jpeg_file_size;
39 | private int jpeg_height;
40 | private String jpeg_url;
41 | private int jpeg_width;
42 | private int preview_height;
43 | private String preview_url;
44 | private int preview_width;
45 | private Rating rating;
46 | private int sample_file_size;
47 | private int sample_height;
48 | private String sample_url;
49 | private int sample_width;
50 | private int score;
51 | private String status;
52 | private String tags;
53 | private int width;
54 | private int actual_preview_height;
55 | private int approver_id;
56 | private int change;
57 | @JsonProperty("created_at")
58 | private long created_at;
59 | private int creator_id;
60 | private List frames;
61 | private List frames_pending;
62 | private String frames_pending_string;
63 | private String frames_string;
64 | private boolean has_children;
65 | private boolean is_held;
66 | private boolean is_note_locked;
67 | private boolean is_pending;
68 | private boolean is_rating_locked;
69 | private boolean is_shown_in_index;
70 | private int last_commented_at;
71 | private int last_noted_at;
72 | private String md5;
73 | private int parent_id;
74 | private String source;
75 | private int updated_at;
76 |
77 | public int getActual_preview_width() {
78 | return actual_preview_width;
79 | }
80 |
81 | public String getAuthor() {
82 | return author;
83 | }
84 |
85 | public String getFile_ext() {
86 | return file_ext;
87 | }
88 |
89 | public int getFile_size() {
90 | return file_size;
91 | }
92 |
93 | public String getFile_url() {
94 | return file_url;
95 | }
96 |
97 | public int getId() {
98 | return id;
99 | }
100 |
101 | public int getJpeg_file_size() {
102 | return jpeg_file_size;
103 | }
104 |
105 | public int getJpeg_height() {
106 | return jpeg_height;
107 | }
108 |
109 | public String getJpeg_url() {
110 | return jpeg_url;
111 | }
112 |
113 | public int getJpeg_width() {
114 | return jpeg_width;
115 | }
116 |
117 | public int getPreview_height() {
118 | return preview_height;
119 | }
120 |
121 | public String getPreview_url() {
122 | return preview_url;
123 | }
124 |
125 | public int getPreview_width() {
126 | return preview_width;
127 | }
128 |
129 | public int getSample_file_size() {
130 | return sample_file_size;
131 | }
132 |
133 | public int getSample_height() {
134 | return sample_height;
135 | }
136 |
137 | public String getSample_url() {
138 | return sample_url;
139 | }
140 |
141 | public int getSample_width() {
142 | return sample_width;
143 | }
144 |
145 | public String getStatus() {
146 | return status;
147 | }
148 |
149 | public boolean isHas_children() {
150 | return has_children;
151 | }
152 |
153 | @Override
154 | public int getScore() {
155 | return score;
156 | }
157 |
158 | @Override
159 | public int getWidth() {
160 | return width;
161 | }
162 |
163 | @Override
164 | public int getHeight() {
165 | return height;
166 | }
167 |
168 | @Override
169 | public Rating getRating() {
170 | return rating;
171 | }
172 |
173 | @Override
174 | public List getTags() {
175 | return Collections.unmodifiableList(Arrays.asList(tags.split(" ")));
176 | }
177 |
178 | @Override
179 | public String getURL() {
180 | return getFile_url();
181 | }
182 |
183 | @Override
184 | public boolean hasChildren() {
185 | return isHas_children();
186 | }
187 |
188 | @Override
189 | public boolean isPending() {
190 | // ?????????????
191 | return is_pending || status.equalsIgnoreCase("pending");
192 | }
193 |
194 | @Override
195 | public long getCreationMillis() {
196 | return created_at * 1000;
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/autocomplete/IAutoComplete.java:
--------------------------------------------------------------------------------
1 | package net.kodehawa.lib.imageboards.entities.impl.autocomplete;
2 |
3 | public interface IAutoComplete {
4 | String getTagName();
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/autocomplete/pojo/DanbooruAutoComplete.java:
--------------------------------------------------------------------------------
1 | package net.kodehawa.lib.imageboards.entities.impl.autocomplete.pojo;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import net.kodehawa.lib.imageboards.entities.impl.autocomplete.IAutoComplete;
5 |
6 | public class DanbooruAutoComplete implements IAutoComplete {
7 | String type;
8 | String label;
9 | String value;
10 | int category;
11 | int post_count;
12 |
13 | @JsonProperty("post_count")
14 | public void setPostCount(int post_count) {
15 | this.post_count = post_count;
16 | }
17 |
18 | public void setCategory(int category) {
19 | this.category = category;
20 | }
21 |
22 | public void setValue(String value) {
23 | this.value = value;
24 | }
25 |
26 | public void setLabel(String label) {
27 | this.label = label;
28 | }
29 |
30 | public void setType(String type) {
31 | this.type = type;
32 | }
33 |
34 | @JsonProperty("post_count")
35 | public int getPostCount() {
36 | return post_count;
37 | }
38 |
39 | public int getCategory() {
40 | return category;
41 | }
42 |
43 | public String getValue() {
44 | return value;
45 | }
46 |
47 | public String getLabel() {
48 | return label;
49 | }
50 |
51 | public String getType() {
52 | return type;
53 | }
54 |
55 | @Override
56 | public String getTagName() {
57 | return value;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/autocomplete/pojo/FurryAutoComplete.java:
--------------------------------------------------------------------------------
1 | package net.kodehawa.lib.imageboards.entities.impl.autocomplete.pojo;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import net.kodehawa.lib.imageboards.entities.impl.autocomplete.IAutoComplete;
5 |
6 | public class FurryAutoComplete implements IAutoComplete {
7 | int id;
8 | String name;
9 | int post_count;
10 | int category;
11 | String antecedent_name;
12 |
13 | public int getId() {
14 | return id;
15 | }
16 |
17 | public void setId(int id) {
18 | this.id = id;
19 | }
20 |
21 | public String getName() {
22 | return name;
23 | }
24 |
25 | public void setName(String name) {
26 | this.name = name;
27 | }
28 |
29 | @JsonProperty("post_count")
30 | public int getPostCount() {
31 | return post_count;
32 | }
33 |
34 | @JsonProperty("post_count")
35 | public void setPostCount(int post_count) {
36 | this.post_count = post_count;
37 | }
38 |
39 | public int getCategory() {
40 | return category;
41 | }
42 |
43 | public void setCategory(int category) {
44 | this.category = category;
45 | }
46 |
47 | @JsonProperty("antecedent_name")
48 | public String getAntecedentName() {
49 | return antecedent_name;
50 | }
51 |
52 | @JsonProperty("antecedent_name")
53 | public void setAntecedentName(String antecedent_name) {
54 | this.antecedent_name = antecedent_name;
55 | }
56 |
57 | @Override
58 | public String getTagName() {
59 | return name;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/autocomplete/pojo/GelbooruAutoComplete.java:
--------------------------------------------------------------------------------
1 | package net.kodehawa.lib.imageboards.entities.impl.autocomplete.pojo;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import net.kodehawa.lib.imageboards.entities.impl.autocomplete.IAutoComplete;
5 |
6 | public class GelbooruAutoComplete implements IAutoComplete {
7 | String type;
8 | String label;
9 | String value;
10 | String category;
11 | int post_count;
12 |
13 | @JsonProperty("post_count")
14 | public void setPostCount(int post_count) {
15 | this.post_count = post_count;
16 | }
17 |
18 | public void setCategory(String category) {
19 | this.category = category;
20 | }
21 |
22 | public void setValue(String value) {
23 | this.value = value;
24 | }
25 |
26 | public void setLabel(String label) {
27 | this.label = label;
28 | }
29 |
30 | public void setType(String type) {
31 | this.type = type;
32 | }
33 |
34 | @JsonProperty("post_count")
35 | public int getPostCount() {
36 | return post_count;
37 | }
38 |
39 | public String getCategory() {
40 | return category;
41 | }
42 |
43 | public String getValue() {
44 | return value;
45 | }
46 |
47 | public String getLabel() {
48 | return label;
49 | }
50 |
51 | public String getType() {
52 | return type;
53 | }
54 |
55 | @Override
56 | public String getTagName() {
57 | return value;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/autocomplete/pojo/Rule34AutoComplete.java:
--------------------------------------------------------------------------------
1 | package net.kodehawa.lib.imageboards.entities.impl.autocomplete.pojo;
2 |
3 | import net.kodehawa.lib.imageboards.entities.impl.autocomplete.IAutoComplete;
4 |
5 | public class Rule34AutoComplete implements IAutoComplete {
6 | String label;
7 | String value;
8 | String type;
9 |
10 | public void setLabel(String label) {
11 | this.label = label;
12 | }
13 |
14 | public void setValue(String value) {
15 | this.value = value;
16 | }
17 |
18 | public void setType(String type) {
19 | this.type = type;
20 | }
21 |
22 | public String getType() {
23 | return type;
24 | }
25 |
26 | public String getValue() {
27 | return value;
28 | }
29 |
30 | public String getLabel() {
31 | return label;
32 | }
33 |
34 | @Override
35 | public String getTagName() {
36 | return label;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/entities/impl/autocomplete/pojo/SafebooruAutoComplete.java:
--------------------------------------------------------------------------------
1 | package net.kodehawa.lib.imageboards.entities.impl.autocomplete.pojo;
2 |
3 | import net.kodehawa.lib.imageboards.entities.impl.autocomplete.IAutoComplete;
4 |
5 | public class SafebooruAutoComplete implements IAutoComplete {
6 | String label;
7 | String value;
8 |
9 | public void setLabel(String label) {
10 | this.label = label;
11 | }
12 |
13 | public void setValue(String value) {
14 | this.value = value;
15 | }
16 |
17 | public String getValue() {
18 | return value;
19 | }
20 |
21 | public String getLabel() {
22 | return label;
23 | }
24 |
25 | @Override
26 | public String getTagName() {
27 | return value;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/requests/RequestAction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.requests;
18 |
19 | import net.kodehawa.lib.imageboards.entities.exceptions.QueryFailedException;
20 | import okhttp3.Call;
21 | import okhttp3.Callback;
22 | import okhttp3.Response;
23 |
24 | import java.io.IOException;
25 | import java.util.concurrent.CompletableFuture;
26 | import java.util.concurrent.CompletionStage;
27 | import java.util.function.Consumer;
28 | import java.util.function.Function;
29 |
30 | /**
31 | * Utility action instance that can execute a request and obtain the result
32 | * by blocking the calling thread or using callbacks.
33 | *
34 | * @param Return type of the request.
35 | * @author Avarel
36 | */
37 | public class RequestAction {
38 | private final Call call;
39 | private final Function transform;
40 |
41 | RequestAction(Call call, Function successTransformer) {
42 | this.call = call;
43 | this.transform = successTransformer;
44 | }
45 |
46 | /**
47 | * Obtain the request result by blocking the calling thread.
48 | *
49 | * @return Return type of the request.
50 | */
51 | public T blocking() {
52 | try (Response response = call.execute()) {
53 | if (response.code() != 200) {
54 | throw new QueryFailedException(response.code(), call.request().url().toString());
55 | }
56 |
57 | return transform.apply(response);
58 | } catch (IOException e) {
59 | throw new RuntimeException(e);
60 | }
61 | }
62 |
63 | /**
64 | * Obtain the result by submitting the task to an executor and
65 | * returning a {@link CompletionStage promise}.
66 | *
67 | * @return Executor promise.
68 | */
69 | public CompletionStage submit() {
70 | CompletableFuture future = new CompletableFuture<>();
71 | async(future::complete, future::completeExceptionally);
72 | return future;
73 | }
74 |
75 | /**
76 | * Obtain the result by submitting the task to an executor
77 | * and forwarding the result to a success consumer.
78 | *
79 | * @param successConsumer Consumer of the response.
80 | */
81 | public void async(Consumer successConsumer) {
82 | async(successConsumer, null);
83 | }
84 |
85 | /**
86 | * Obtain the result by submitting the task to an executor
87 | * and forwarding the result to a success consumer.
88 | *
89 | * However, if an exception occurs then the exception will forward to the
90 | * failure consumer if set.
91 | *
92 | * @param successConsumer Consumer of the response.
93 | * @param failureConsumer Consumer of the exception (if it occurs).
94 | */
95 | public void async(Consumer successConsumer, Consumer failureConsumer) {
96 | if (successConsumer == null) {
97 | throw new NullPointerException("success consumer == null");
98 | }
99 |
100 | call.enqueue(new Callback() {
101 | @Override
102 | public void onFailure(Call call, IOException e) {
103 | call.cancel();
104 | failureConsumer.accept(e);
105 | }
106 |
107 | @Override
108 | public void onResponse(Call call, Response response) throws IOException {
109 | try {
110 | if (response.code() != 200) {
111 | throw new QueryFailedException(response.code(), RequestAction.this.call.request().url().toString());
112 | }
113 |
114 | successConsumer.accept(transform.apply(response));
115 | } catch (Throwable e) {
116 | if (failureConsumer != null) {
117 | failureConsumer.accept(e);
118 | }
119 | } finally {
120 | response.close();
121 | }
122 | }
123 | });
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/java/net/kodehawa/lib/imageboards/requests/RequestFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards.requests;
18 |
19 | import net.kodehawa.lib.imageboards.ImageBoard;
20 | import okhttp3.HttpUrl;
21 | import okhttp3.OkHttpClient;
22 | import okhttp3.Request;
23 | import okhttp3.Response;
24 |
25 | import java.util.function.Function;
26 |
27 | /**
28 | * A requester that can make request actions.
29 | *
30 | * @author Avarel
31 | * @see RequestAction
32 | */
33 | public class RequestFactory {
34 | /**
35 | * Request client.
36 | */
37 | private final OkHttpClient client;
38 |
39 | /**
40 | * Create a requester that can make request actions.
41 | *
42 | * @param client OKHttp client.
43 | */
44 | public RequestFactory(OkHttpClient client) {
45 | this.client = client;
46 | }
47 |
48 | /**
49 | * Creates a {@link RequestAction request action} on a URL.
50 | *
51 | * @param url Target url.
52 | * @param transform Successful response transformer.
53 | * @param Return type.
54 | * @return Request action.
55 | */
56 | public RequestAction makeRequest(String url, Function transform) {
57 | return makeRequest(HttpUrl.parse(url), transform);
58 | }
59 |
60 | /**
61 | * Creates a {@link RequestAction request action} on a URL.
62 | *
63 | * @param url Target url.
64 | * @param transform Successful response transformer.
65 | * @param Return type.
66 | * @return Request action.
67 | */
68 | public RequestAction makeRequest(HttpUrl url, Function transform) {
69 | if(ImageBoard.getUserAgent() == null) {
70 | throw new IllegalStateException("User-Agent must be initialized to make requests, Initialize with ImageBoard.setUserAgent()");
71 | }
72 | return new RequestAction<>(client.newCall(new Request.Builder().url(url).header("User-Agent", ImageBoard.getUserAgent()).build()), transform);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/test/java/net/kodehawa/lib/imageboards/ImageBoardTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards;
18 |
19 | import net.kodehawa.lib.imageboards.boards.DefaultBoards;
20 | import net.kodehawa.lib.imageboards.entities.BoardImage;
21 | import net.kodehawa.lib.imageboards.entities.Rating;
22 | import net.kodehawa.lib.imageboards.entities.impl.*;
23 | import net.kodehawa.lib.imageboards.entities.impl.autocomplete.IAutoComplete;
24 | import org.junit.Test;
25 |
26 | import java.util.Date;
27 | import java.util.List;
28 | import java.util.concurrent.TimeUnit;
29 |
30 | import static org.junit.Assert.*;
31 |
32 | public class ImageBoardTest {
33 |
34 | static {
35 | ImageBoard.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0");
36 | }
37 |
38 | private static final ImageBoard e621 = DefaultImageBoards.E621;
39 | private static final ImageBoard konachan = DefaultImageBoards.KONACHAN;
40 | private static final ImageBoard rule34 = DefaultImageBoards.RULE34;
41 | private static final ImageBoard yandere = DefaultImageBoards.YANDERE;
42 | private static final ImageBoard danbooru = DefaultImageBoards.DANBOORU;
43 | private static final ImageBoard safebooru = DefaultImageBoards.SAFEBOORU;
44 | private static final ImageBoard e926 = DefaultImageBoards.E926;
45 | private static final ImageBoard gelbooru = DefaultImageBoards.GELBOORU;
46 |
47 | //Run this first to check if everything returns as expected
48 | public static void main(String[] args) {
49 | e621.get(2).async(ImageBoardTest::printImages);
50 | konachan.get(2).async(ImageBoardTest::printImages);
51 | rule34.get(2).async(ImageBoardTest::printImages);
52 | yandere.get(2).async(ImageBoardTest::printImages);
53 | danbooru.get(2).async(ImageBoardTest::printImages);
54 | safebooru.get(2).async(ImageBoardTest::printImages);
55 | gelbooru.get(2).async(ImageBoardTest::printImages);
56 | e926.get(2).async(ImageBoardTest::printImages);
57 | }
58 |
59 | private static void printImages(List extends BoardImage> images) {
60 | for (BoardImage image : images) {
61 | System.out.println(
62 | "ImageBoard: " + image.getClass()
63 | + " " + image.getURL()
64 | + " " + image.getScore()
65 | + " " + image.getRating()
66 | + " " + image.getTags()
67 | + " " + image.getHeight()
68 | + " " + image.getWidth()
69 | + " " + image.hasChildren()
70 | + " " + image.isPending()
71 | + " " + new Date(image.getCreationMillis()).toString()
72 | );
73 | }
74 | }
75 |
76 | private static void printAutoComplete(List extends IAutoComplete> images) {
77 | for (IAutoComplete autocomplete : images) {
78 | System.out.println(
79 | "Autocomplete: " + autocomplete.getClass()
80 | + " " + autocomplete.getTagName()
81 | );
82 | }
83 | }
84 |
85 | @Test
86 | public void returnsNonNullValues() {
87 | e621.get(1).async(ImageBoardTest::assertImages);
88 | konachan.get(1).async(ImageBoardTest::assertImages);
89 | rule34.get(1).async(ImageBoardTest::assertImages);
90 | yandere.get(1).async(ImageBoardTest::assertImages);
91 | danbooru.get(1).async(ImageBoardTest::assertImages);
92 | safebooru.get(1).async(ImageBoardTest::assertImages);
93 | gelbooru.get(1).async(ImageBoardTest::assertImages);
94 | e926.get(1).async(ImageBoardTest::assertImages);
95 | }
96 |
97 | @Test
98 | public void blockingTest() {
99 | printImages(e621.get(2).blocking());
100 | printImages(konachan.get(2).blocking());
101 | printImages(rule34.get(2).blocking());
102 | printImages(yandere.get(2).blocking());
103 | printImages(danbooru.get(2).blocking());
104 | printImages(safebooru.get(2).blocking());
105 | printImages(gelbooru.get(2).blocking());
106 | printImages(e926.get(2).blocking());
107 |
108 | printAutoComplete(e621.autocomplete("animal", 2).blocking());
109 | printAutoComplete(gelbooru.autocomplete("animal", 2).blocking());
110 | printAutoComplete(rule34.autocomplete("animal", 2).blocking());
111 | printAutoComplete(danbooru.autocomplete("animal",2).blocking());
112 | printAutoComplete(safebooru.autocomplete("animal", 2).blocking());
113 | }
114 |
115 | @Test(expected = NullPointerException.class)
116 | public void throwErrorNullConsumer() {
117 | e621.get(1).async(null);
118 | }
119 |
120 | public static void assertImages(List extends BoardImage> images) {
121 | assertNotEquals(images.get(0).getURL(), null);
122 | assertNotEquals(images.get(0).getTags(), null);
123 | }
124 |
125 | @Test
126 | public void tagsReturnRelevantResults() {
127 | String tag = "animal_ears";
128 | String[] knownAliases = {"animal_ear", "animal_humanoid"};
129 |
130 | String tagRemoval = "-animal_ears humanoid";
131 | String tagRemoval1 = "-animal_ears yuri";
132 | String tagRemoval2 = "-animal_humanoid humanoid";
133 |
134 | // This actually used to alias animal_ears to animal_humanoid, but it doesn't anymore (As of 08/12/2021)
135 | // Nothing I can do on my side!
136 | assertTrue(e621.search(1, knownAliases[1]).blocking().get(0).getTags().contains(knownAliases[1]));
137 | assertTrue(konachan.search(1, tag).blocking().get(0).getTags().contains(tag));
138 | assertTrue(rule34.search(1, tag).blocking().get(0).getTags().contains(tag) ||
139 | rule34.search(1, tag).blocking().get(0).getTags().contains(knownAliases[0]));
140 |
141 | assertTrue(yandere.search(1, tag).blocking().get(0).getTags().contains(tag));
142 | assertTrue(danbooru.search(1, tag).blocking().get(0).getTags().contains(tag));
143 | assertTrue(safebooru.search(1, tag).blocking().get(0).getTags().contains(tag));
144 | assertTrue(yandere.search("animal_ears yuri", Rating.EXPLICIT).blocking().get(0).getTags().contains(tag));
145 | assertTrue(gelbooru.search(1, tag).blocking().get(0).getTags().contains(tag));
146 |
147 | // Tag removal
148 | assertFalse(e621.search(100, tagRemoval2).blocking().stream().anyMatch(image -> image.getTags().contains(knownAliases[1])));
149 | assertFalse(konachan.search(100, tagRemoval).blocking().stream().anyMatch(image -> image.getTags().contains(tag)));
150 | assertFalse(rule34.search(100, tagRemoval).blocking().stream().anyMatch(image -> image.getTags().contains(tag)));
151 | assertFalse(yandere.search(100, tagRemoval).blocking().stream().anyMatch(image -> image.getTags().contains(tag)));
152 | assertFalse(danbooru.search(100, tagRemoval1).blocking().stream().anyMatch(image -> image.getTags().contains(tag)));
153 | assertFalse(safebooru.search(100, tagRemoval).blocking().stream().anyMatch(image -> image.getTags().contains(tag)));
154 | assertFalse(yandere.search(tagRemoval1, Rating.EXPLICIT).blocking().stream().anyMatch(image -> image.getTags().contains(tag)));
155 | assertFalse(gelbooru.search(100, tagRemoval).blocking().stream().anyMatch(image -> image.getTags().contains(tag)));
156 |
157 | // Same for e961, no more tag aliases seemingly
158 | assertTrue(e926.search(1, knownAliases[1]).blocking().get(0).getTags().contains(knownAliases[1]));
159 | // This shouldn't fail, even if Yande.re has no GENERAL rating, as we adjust to this.
160 | assertSame(yandere.search(tag, Rating.GENERAL).blocking().get(0).getRating(), Rating.SAFE);
161 | assertSame(yandere.search(tag, Rating.EXPLICIT).blocking().get(0).getRating(), Rating.EXPLICIT);
162 | assertSame(danbooru.search(tag, Rating.EXPLICIT).blocking().get(0).getRating(), Rating.EXPLICIT);
163 | assertSame(danbooru.search(tag, Rating.QUESTIONABLE).blocking().get(0).getRating(), Rating.QUESTIONABLE);
164 | // This shouldn't fail even though Gelbooru has no SAFE rating, as we adjust to this.
165 | assertSame(gelbooru.search(tag, Rating.SAFE).blocking().get(0).getRating(), Rating.GENERAL);
166 | assertSame(gelbooru.search(tag, Rating.SENSITIVE).blocking().get(0).getRating(), Rating.SENSITIVE);
167 | assertSame(gelbooru.search(tag, Rating.QUESTIONABLE).blocking().get(0).getRating(), Rating.QUESTIONABLE);
168 | assertSame(gelbooru.search(tag, Rating.EXPLICIT).blocking().get(0).getRating(), Rating.EXPLICIT);
169 | assertSame(gelbooru.search(tag, Rating.QUESTIONABLE).blocking().get(0).getRating(), Rating.QUESTIONABLE);
170 | assertSame(konachan.search(tag, Rating.EXPLICIT).blocking().get(0).getRating(), Rating.EXPLICIT);
171 | assertSame(konachan.search(tag, Rating.SAFE).blocking().get(0).getRating(), Rating.SAFE);
172 | assertSame(konachan.search("", Rating.SAFE).blocking().get(0).getRating(), Rating.SAFE);
173 | assertSame(konachan.get(7, Rating.SAFE).blocking().get(0).getRating(), Rating.SAFE);
174 | assertSame(danbooru.get(7, Rating.SAFE).blocking().get(0).getRating(), Rating.SAFE);
175 | assertSame(e926.get(7, Rating.SAFE).blocking().get(0).getRating(), Rating.SAFE);
176 | }
177 |
178 | @Test
179 | public void autoCompleteReturnsResults() {
180 | assertFalse(e621.autocomplete("animal").blocking().isEmpty());
181 | assertFalse(gelbooru.autocomplete("animal").blocking().isEmpty());
182 | assertFalse(rule34.autocomplete("animal").blocking().isEmpty());
183 | assertFalse(danbooru.autocomplete("animal").blocking().isEmpty());
184 | assertFalse(safebooru.autocomplete("animal").blocking().isEmpty());
185 | }
186 |
187 | @Test
188 | public void autoCompleteReturnsRelevantResults() {
189 | assertTrue(e621.autocomplete("animal").blocking().get(1).getTagName().contains("an")); // Don't ask me why. e621 searches by "antecedent_name" even if I ask for a name.
190 | assertTrue(gelbooru.autocomplete("animal").blocking().get(1).getTagName().contains("animal"));
191 | assertTrue(rule34.autocomplete("animal").blocking().get(1).getTagName().contains("animal"));
192 | assertTrue(danbooru.autocomplete("animal").blocking().get(1).getTagName().contains("animal"));
193 | assertTrue(safebooru.autocomplete("animal").blocking().get(1).getTagName().contains("animal"));
194 | }
195 |
196 | @Test
197 | public void returnsProperClasses() {
198 | assertEquals(e621.getBoardType(), DefaultBoards.E621);
199 | assertEquals(e621.getImageType(), FurryImage.class);
200 |
201 | assertEquals(konachan.getBoardType(), DefaultBoards.KONACHAN);
202 | assertEquals(konachan.getImageType(), KonachanImage.class);
203 |
204 | assertEquals(rule34.getBoardType(), DefaultBoards.R34);
205 | assertEquals(rule34.getImageType(), Rule34Image.class);
206 |
207 | assertEquals(yandere.getBoardType(), DefaultBoards.YANDERE);
208 | assertEquals(yandere.getImageType(), YandereImage.class);
209 |
210 | assertEquals(danbooru.getBoardType(), DefaultBoards.DANBOORU);
211 | assertEquals(danbooru.getImageType(), DanbooruImage.class);
212 |
213 | assertEquals(safebooru.getBoardType(), DefaultBoards.SAFEBOORU);
214 | assertEquals(safebooru.getImageType(), SafebooruImage.class);
215 |
216 | assertEquals(gelbooru.getBoardType(), DefaultBoards.GELBOORU);
217 | assertEquals(gelbooru.getImageType(), GelbooruImage.class);
218 |
219 | assertEquals(e926.getBoardType(), DefaultBoards.E926);
220 | assertEquals(e926.getImageType(), SafeFurryImage.class);
221 |
222 | }
223 |
224 | @Test
225 | public void recentDate() {
226 | long oneDayAgo = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1);
227 | assertTrue(e621.get(1).blocking().get(0).getCreationMillis() > oneDayAgo);
228 | assertTrue(konachan.get(1).blocking().get(0).getCreationMillis() > oneDayAgo);
229 | assertTrue(rule34.get(1).blocking().get(0).getCreationMillis() > oneDayAgo);
230 | assertTrue(yandere.get(1).blocking().get(0).getCreationMillis() > oneDayAgo);
231 | assertTrue(danbooru.get(1).blocking().get(0).getCreationMillis() > oneDayAgo);
232 | assertTrue(safebooru.get(1).blocking().get(0).getCreationMillis() > oneDayAgo);
233 | assertTrue(gelbooru.get(1).blocking().get(0).getCreationMillis() > oneDayAgo);
234 | assertTrue(e926.get(1).blocking().get(0).getCreationMillis() > oneDayAgo);
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/src/test/java/net/kodehawa/lib/imageboards/RandomImages.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards;
18 |
19 | import net.kodehawa.lib.imageboards.entities.BoardImage;
20 |
21 | public class RandomImages {
22 | public static void main(String[] args) {
23 | // Asynchronous GET
24 | // 60 random images
25 | DefaultImageBoards.KONACHAN.get().async(images -> {
26 | for (BoardImage image : images) System.out.println(image.getURL());
27 | });
28 |
29 | // Blocking GET
30 | // 1 random image
31 | BoardImage image = DefaultImageBoards.KONACHAN.get(1).blocking().get(0);
32 | System.out.println(image.getURL());
33 | System.out.println(image.getRating());
34 | System.out.println(image.getTags());
35 | System.out.println(image.getHeight());
36 | System.out.println(image.getWidth());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/net/kodehawa/lib/imageboards/TagImages.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Kodehawa
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.kodehawa.lib.imageboards;
18 |
19 | import net.kodehawa.lib.imageboards.entities.BoardImage;
20 |
21 | public class TagImages {
22 | public static void main(String[] args) {
23 | // Asynchronous GET
24 | // 20 images tagged with animal_ears
25 | DefaultImageBoards.KONACHAN.search(20, "animal_ears").async(images -> {
26 | for (BoardImage image : images) System.out.println(image.getURL());
27 | });
28 |
29 | // Blocking GET
30 | // 60 images tagged with animal_ears
31 | BoardImage image = DefaultImageBoards.KONACHAN.search("animal_ears").blocking().get(0);
32 | System.out.println(image.getURL());
33 | System.out.println(image.getRating());
34 | System.out.println(image.getTags());
35 | System.out.println(image.getHeight());
36 | System.out.println(image.getWidth());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------