diff --git a/.editorconfig b/.editorconfig
index fb360832..d612cf15 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -18,3 +18,7 @@ indent_size = 2
[*.md]
trim_trailing_whitespace = false
+
+[*.{kt,kts}]
+ktlint_code_style = intellij_idea
+ktlint_standard_import-ordering = disabled
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f9a9f88b..edfd28c7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -8,18 +8,19 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v2.3.4
+ uses: actions/checkout@v4
- name: Check Gradle wrapper
- uses: gradle/wrapper-validation-action@v1.0.3
+ uses: gradle/actions/wrapper-validation@v4
- - name: Set up JDK 1.8
- uses: actions/setup-java@v1.4.3
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
with:
- java-version: 1.8
+ distribution: temurin
+ java-version: 17
- name: Set up Gradle Cache
- uses: actions/cache@v2.1.3
+ uses: actions/cache@v4
with:
path: ~/.gradle
key: ${{ runner.OS }}-gradle-
@@ -28,7 +29,7 @@ jobs:
run: ./gradlew ktlintCheck detekt build
- name: Store reports
- uses: actions/upload-artifact@v2.2.1
+ uses: actions/upload-artifact@v4
if: always()
with:
name: Reports
diff --git a/build.gradle b/build.gradle
index 16fcbafc..3adf18c6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,11 +3,8 @@ buildscript {
}
plugins {
- id "org.jetbrains.kotlin.jvm"
- id "org.jetbrains.kotlin.kapt"
- id "org.jetbrains.dokka"
-
- id "com.github.ben-manes.versions"
+ id "org.jetbrains.kotlin.jvm" apply false
+ id "com.google.devtools.ksp" apply false
}
allprojects {
@@ -15,13 +12,7 @@ allprojects {
group = rootProject.ext.group
repositories {
- jcenter()
- }
-}
-
-tasks.named("dependencyUpdates").configure {
- rejectVersionIf {
- !(it.candidate.version ==~ /^[0-9,.v-]+(-r)?$/)
+ mavenCentral()
}
}
diff --git a/gradle.properties b/gradle.properties
index aa9bdc89..1731fb2c 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,9 +1,5 @@
-org.gradle.jvmargs=-Xmx2048M -XX:MaxPermSize=512m -XX:MaxHeapSize=1024M -Dfile.encoding=UTF-8
+org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8
org.gradle.parallel=true
org.gradle.caching=true
kotlin.code.style=official
-
-kapt.use.worker.api=true
-kapt.incremental.apt=true
-kapt.include.compile.classpath=false
diff --git a/gradle/dependencies.gradle b/gradle/dependencies.gradle
index 4af86bf2..3eba8f57 100644
--- a/gradle/dependencies.gradle
+++ b/gradle/dependencies.gradle
@@ -1,5 +1,5 @@
dependencies {
- api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
+ api "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
api "com.squareup.retrofit2:retrofit:$retrofitVersion"
api "com.squareup.retrofit2:converter-moshi:$retrofitVersion"
@@ -12,13 +12,14 @@ dependencies {
runtimeOnly "com.squareup.okio:okio:$okioVersion"
- kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshiVersion"
- kaptTest "com.squareup.moshi:moshi-kotlin-codegen:$moshiVersion"
+ ksp "com.squareup.moshi:moshi-kotlin-codegen:$moshiVersion"
+ kspTest "com.squareup.moshi:moshi-kotlin-codegen:$moshiVersion"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion"
testImplementation "org.junit.jupiter:junit-jupiter:$junitVersion"
testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion"
+ testRuntimeOnly "org.junit.platform:junit-platform-launcher"
testImplementation "net.jodah:concurrentunit:$concurrentUnitVersion"
testImplementation "org.amshove.kluent:kluent:$kluentVersion"
diff --git a/gradle/versions.gradle b/gradle/versions.gradle
index 7a3c42bb..c0f07419 100644
--- a/gradle/versions.gradle
+++ b/gradle/versions.gradle
@@ -1,29 +1,26 @@
ext {
- version = "5.4.0"
+ version = "5.5.0"
group = "com.github.proxer"
- gradleVersion = "6.7.1"
+ gradleVersion = "9.8.1"
- kotlinVersion = "1.4.21"
- kotlinCoroutinesVersion = "1.4.2"
- dokkaVersion = "1.4.20"
+ kotlinVersion = "2.3.21"
+ kspVersion = "2.3.12"
+ kotlinCoroutinesVersion = "1.10.2"
- jacocoVersion = "0.8.6"
- ktlintPluginVersion = "9.4.1"
- ktlintVersion = "0.40.0"
- detektVersion = "1.15.0"
+ jacocoVersion = "0.8.12"
+ ktlintPluginVersion = "14.2.0"
+ ktlintVersion = "1.5.0"
+ detektVersion = "1.23.8"
- gradleVersionsPluginVersion = "0.36.0"
- buildConfigPluginVersion = "1.1.8"
-
- retrofitVersion = "2.9.0"
- okHttpVersion = "4.9.0"
- okioVersion = "2.9.0"
- moshiVersion = "1.11.0"
+ retrofitVersion = "2.11.0"
+ okHttpVersion = "4.12.0"
+ okioVersion = "3.9.1"
+ moshiVersion = "1.15.2"
moshiLazyAdaptersVersion = "2.2"
- junitVersion = "5.7.0"
+ junitVersion = "5.11.4"
concurrentUnitVersion = "0.4.6"
- kluentVersion = "1.64"
- mockkVersion = "1.10.3-jdk8"
+ kluentVersion = "1.73"
+ mockkVersion = "1.13.16"
}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index e708b1c0..1b33c55b 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 4d9ca164..1a31fd1b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.1-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 4f906e0c..23d15a93 100755
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
#
-# Copyright 2015 the original author or authors.
+# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,81 +15,115 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# Attempt to set APP_HOME
+
# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,88 +132,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
fi
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
# Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
fi
- i=`expr $i + 1`
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
done
- case $i in
- 0) set -- ;;
- 1) set -- "$args0" ;;
- 2) set -- "$args0" "$args1" ;;
- 3) set -- "$args0" "$args1" "$args2" ;;
- 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
fi
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=`save "$@"`
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 107acd32..5eed7ee8 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,89 +1,94 @@
-@rem
-@rem Copyright 2015 the original author or authors.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem https://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-
-@if "%DEBUG%" == "" @echo off
-@rem ##########################################################################
-@rem
-@rem Gradle startup script for Windows
-@rem
-@rem ##########################################################################
-
-@rem Set local scope for the variables with windows NT shell
-if "%OS%"=="Windows_NT" setlocal
-
-set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
-set APP_BASE_NAME=%~n0
-set APP_HOME=%DIRNAME%
-
-@rem Resolve any "." and ".." in APP_HOME to make it shorter.
-for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
-
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
-
-@rem Find java.exe
-if defined JAVA_HOME goto findJavaFromJavaHome
-
-set JAVA_EXE=java.exe
-%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:findJavaFromJavaHome
-set JAVA_HOME=%JAVA_HOME:"=%
-set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-
-if exist "%JAVA_EXE%" goto execute
-
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
-
-goto fail
-
-:execute
-@rem Setup the command line
-
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
-
-
-@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
-
-:end
-@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
-
-:fail
-rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
-rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
-
-:mainEnd
-if "%OS%"=="Windows_NT" endlocal
-
-:omega
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/jitpack.yml b/jitpack.yml
new file mode 100644
index 00000000..efde7bf2
--- /dev/null
+++ b/jitpack.yml
@@ -0,0 +1,2 @@
+jdk:
+ - openjdk17
diff --git a/library/build.gradle b/library/build.gradle
index fa500730..283ea5f9 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -1,7 +1,8 @@
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
plugins {
id "org.jetbrains.kotlin.jvm"
- id "org.jetbrains.kotlin.kapt"
- id "org.jetbrains.dokka"
+ id "com.google.devtools.ksp"
id "java-library"
id "maven-publish"
@@ -9,91 +10,91 @@ plugins {
id "jacoco"
id "io.gitlab.arturbosch.detekt"
id "org.jlleitschuh.gradle.ktlint"
-
- id "de.fuerstenau.buildconfig"
}
apply from: "${rootDir}/gradle/dependencies.gradle"
-tasks.withType(org.jetbrains.dokka.gradle.DokkaTask).configureEach {
- dokkaSourceSets {
- configureEach {
- sourceLink {
- localDirectory.set(file("src/main/kotlin"))
- remoteUrl.set(uri("https://github.com/proxer/ProxerLibJava/tree/master/library/src/main/kotlin").toURL())
- }
+java {
+ withSourcesJar()
+ withJavadocJar()
+}
- externalDocumentationLink { url.set(new URL("https://square.github.io/retrofit/2.x/retrofit/")) }
- externalDocumentationLink { url.set(new URL("https://square.github.io/okhttp/3.x/okhttp/")) }
- externalDocumentationLink { url.set(new URL("https://square.github.io/moshi/1.x/moshi/")) }
- }
+kotlin {
+ jvmToolchain(17)
+
+ compilerOptions {
+ jvmTarget = JvmTarget.JVM_1_8
+ freeCompilerArgs.addAll("-Xjsr305=strict", "-Xannotation-default-target=param-property")
}
}
-tasks.dokkaJavadoc.configure {
- outputDirectory.set(javadoc.destinationDir)
+tasks.withType(JavaCompile).configureEach {
+ options.release = 8
}
-task sourceJar(type: Jar) {
- archiveClassifier = "sources"
+// Generates the BuildConfig with the library version, which is used for the default user agent.
+def generatedBuildConfigDir = layout.buildDirectory.dir("generated/buildconfig")
- from sourceSets.main.allSource
-}
+def generateBuildConfig = tasks.register("generateBuildConfig") {
+ def version = project.version.toString()
+ def outputDir = generatedBuildConfigDir
-task javadocJar(type: Jar, dependsOn: dokkaJavadoc) {
- archiveClassifier = "javadoc"
+ inputs.property("version", version)
+ outputs.dir(outputDir)
- from javadoc.destinationDir
-}
+ doLast {
+ def file = outputDir.get().file("me/proxer/library/BuildConfig.kt").asFile
+
+ file.parentFile.mkdirs()
+ file.text = """package me.proxer.library
-tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
- kotlinOptions {
- jvmTarget = "1.8"
- allWarningsAsErrors = true
- freeCompilerArgs = ["-Xjsr305=strict", "-progressive"]
+internal object BuildConfig {
+ const val VERSION = "$version"
+}
+"""
}
}
-kapt {
- useBuildCache = true
-}
+sourceSets.main.kotlin.srcDir(generateBuildConfig)
-test {
- finalizedBy jacocoTestReport
+tasks.named("test") {
+ finalizedBy "jacocoTestReport"
useJUnitPlatform()
}
-buildConfig {
- packageName = "me.proxer.library"
- version = project.version
-}
-
jacoco {
- setToolVersion(jacocoVersion)
+ toolVersion = jacocoVersion
}
jacocoTestReport {
reports {
- xml.enabled = true
- html.enabled = false
+ xml.required = true
+ html.required = false
}
}
ktlint {
- disabledRules = ["import-ordering"]
version = ktlintVersion
+ // The code base predates the current ktlint rule set, so findings are reported but don't fail the build.
+ ignoreFailures = true
+
+ filter {
+ exclude { it.file.path.contains("/build/") }
+ }
+
reporters {
reporter "checkstyle"
}
}
detekt {
- version = detektVersion
+ toolVersion = detektVersion
buildUponDefaultConfig = true
- config = files("$rootDir/config/detekt.yml")
+ config.setFrom(files("$rootDir/config/detekt.yml"))
+ baseline = file("$projectDir/detekt-baseline.xml")
}
publishing {
@@ -103,24 +104,21 @@ publishing {
from components.java
- artifact sourceJar
- artifact javadocJar
-
pom {
name = "ProxerLibJava"
description = "A JVM and Android library, implementing the API of the Proxer.Me website"
- url = "https://github.com/proxer/ProxerLibJava"
+ url = "https://github.com/MrP1ck/ProxerLibJava"
scm {
- url = "https://github.com/proxer/ProxerLibJava"
- connection = "scm:git:https://github.com/proxer/ProxerLibJava"
- developerConnection = "scm:git:git@github.com/proxer/ProxerLibJava"
+ url = "https://github.com/MrP1ck/ProxerLibJava"
+ connection = "scm:git:https://github.com/MrP1ck/ProxerLibJava"
+ developerConnection = "scm:git:git@github.com/MrP1ck/ProxerLibJava"
tag = "HEAD"
}
issueManagement {
system = "GitHub Issues"
- url = "https://github.com/proxer/ProxerLibJava/issues"
+ url = "https://github.com/MrP1ck/ProxerLibJava/issues"
}
licenses {
diff --git a/library/detekt-baseline.xml b/library/detekt-baseline.xml
new file mode 100644
index 00000000..e13e6568
--- /dev/null
+++ b/library/detekt-baseline.xml
@@ -0,0 +1,11 @@
+
+
+
+
+ SwallowedException:TestUtils.kt$error: Throwable
+ ThrowingExceptionsWithoutMessageOrCause:KotlinExtensions.kt$NullPointerException()
+ UseRequire:HttpsEnforcingInterceptor.kt$HttpsEnforcingInterceptor$throw IllegalArgumentException("Only use ProxerLib's OkHttp instance with Proxer.Me URLs!")
+ UseRequire:OneShotInterceptor.kt$OneShotInterceptor$throw IllegalArgumentException("Only use ProxerLib's OkHttp instance with Proxer.Me URLs!")
+ UseRequire:ProxerResponseCallAdapterFactory.kt$ProxerResponseCallAdapterFactory$throw IllegalArgumentException( "ProxerCall return type must be parameterized as ProxerCall<Foo> or ProxerCall<? extends Foo>" )
+
+
diff --git a/library/src/main/kotlin/me/proxer/library/api/info/CharacterEndpoint.kt b/library/src/main/kotlin/me/proxer/library/api/info/CharacterEndpoint.kt
new file mode 100644
index 00000000..c5a2f302
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/api/info/CharacterEndpoint.kt
@@ -0,0 +1,18 @@
+package me.proxer.library.api.info
+
+import me.proxer.library.ProxerCall
+import me.proxer.library.api.Endpoint
+import me.proxer.library.entity.info.Character
+
+/**
+ * Endpoint for retrieving all information of a [Character].
+ */
+class CharacterEndpoint internal constructor(
+ private val internalApi: InternalApi,
+ private val id: String
+) : Endpoint {
+
+ override fun build(): ProxerCall {
+ return internalApi.character(id)
+ }
+}
diff --git a/library/src/main/kotlin/me/proxer/library/api/info/EntryCharactersEndpoint.kt b/library/src/main/kotlin/me/proxer/library/api/info/EntryCharactersEndpoint.kt
new file mode 100644
index 00000000..a3cc85e6
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/api/info/EntryCharactersEndpoint.kt
@@ -0,0 +1,18 @@
+package me.proxer.library.api.info
+
+import me.proxer.library.ProxerCall
+import me.proxer.library.api.Endpoint
+import me.proxer.library.entity.info.EntryCharacter
+
+/**
+ * Endpoint for retrieving the characters of an entry.
+ */
+class EntryCharactersEndpoint internal constructor(
+ private val internalApi: InternalApi,
+ private val id: String
+) : Endpoint> {
+
+ override fun build(): ProxerCall> {
+ return internalApi.entryCharacters(id)
+ }
+}
diff --git a/library/src/main/kotlin/me/proxer/library/api/info/EntryPersonsEndpoint.kt b/library/src/main/kotlin/me/proxer/library/api/info/EntryPersonsEndpoint.kt
new file mode 100644
index 00000000..500210bf
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/api/info/EntryPersonsEndpoint.kt
@@ -0,0 +1,18 @@
+package me.proxer.library.api.info
+
+import me.proxer.library.ProxerCall
+import me.proxer.library.api.Endpoint
+import me.proxer.library.entity.info.EntryPerson
+
+/**
+ * Endpoint for retrieving the persons involved in an entry.
+ */
+class EntryPersonsEndpoint internal constructor(
+ private val internalApi: InternalApi,
+ private val id: String
+) : Endpoint> {
+
+ override fun build(): ProxerCall> {
+ return internalApi.entryPersons(id)
+ }
+}
diff --git a/library/src/main/kotlin/me/proxer/library/api/info/InfoApi.kt b/library/src/main/kotlin/me/proxer/library/api/info/InfoApi.kt
index 76af4299..288e5641 100644
--- a/library/src/main/kotlin/me/proxer/library/api/info/InfoApi.kt
+++ b/library/src/main/kotlin/me/proxer/library/api/info/InfoApi.kt
@@ -108,4 +108,32 @@ class InfoApi internal constructor(retrofit: Retrofit) {
fun forumDiscussions(entryId: String): ForumDiscussionsEndpoint {
return ForumDiscussionsEndpoint(internalApi, entryId)
}
+
+ /**
+ * Returns the respective endpoint.
+ */
+ fun entryCharacters(entryId: String): EntryCharactersEndpoint {
+ return EntryCharactersEndpoint(internalApi, entryId)
+ }
+
+ /**
+ * Returns the respective endpoint.
+ */
+ fun entryPersons(entryId: String): EntryPersonsEndpoint {
+ return EntryPersonsEndpoint(internalApi, entryId)
+ }
+
+ /**
+ * Returns the respective endpoint.
+ */
+ fun character(characterId: String): CharacterEndpoint {
+ return CharacterEndpoint(internalApi, characterId)
+ }
+
+ /**
+ * Returns the respective endpoint.
+ */
+ fun person(personId: String): PersonEndpoint {
+ return PersonEndpoint(internalApi, personId)
+ }
}
diff --git a/library/src/main/kotlin/me/proxer/library/api/info/InternalApi.kt b/library/src/main/kotlin/me/proxer/library/api/info/InternalApi.kt
index 245677a4..51a2965b 100644
--- a/library/src/main/kotlin/me/proxer/library/api/info/InternalApi.kt
+++ b/library/src/main/kotlin/me/proxer/library/api/info/InternalApi.kt
@@ -1,13 +1,17 @@
package me.proxer.library.api.info
import me.proxer.library.ProxerCall
+import me.proxer.library.entity.info.Character
import me.proxer.library.entity.info.Comment
import me.proxer.library.entity.info.Entry
+import me.proxer.library.entity.info.EntryCharacter
import me.proxer.library.entity.info.EntryCore
+import me.proxer.library.entity.info.EntryPerson
import me.proxer.library.entity.info.EpisodeInfo
import me.proxer.library.entity.info.ForumDiscussion
import me.proxer.library.entity.info.Industry
import me.proxer.library.entity.info.MediaUserInfo
+import me.proxer.library.entity.info.Person
import me.proxer.library.entity.info.Recommendation
import me.proxer.library.entity.info.Relation
import me.proxer.library.entity.info.TranslatorGroup
@@ -72,4 +76,16 @@ internal interface InternalApi {
@GET("info/forum")
fun forumDiscussions(@Query("id") id: String?): ProxerCall>
+
+ @GET("info/characters")
+ fun entryCharacters(@Query("id") id: String?): ProxerCall>
+
+ @GET("info/persons")
+ fun entryPersons(@Query("id") id: String?): ProxerCall>
+
+ @GET("info/character")
+ fun character(@Query("id") id: String?): ProxerCall
+
+ @GET("info/person")
+ fun person(@Query("id") id: String?): ProxerCall
}
diff --git a/library/src/main/kotlin/me/proxer/library/api/info/PersonEndpoint.kt b/library/src/main/kotlin/me/proxer/library/api/info/PersonEndpoint.kt
new file mode 100644
index 00000000..6dad8882
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/api/info/PersonEndpoint.kt
@@ -0,0 +1,18 @@
+package me.proxer.library.api.info
+
+import me.proxer.library.ProxerCall
+import me.proxer.library.api.Endpoint
+import me.proxer.library.entity.info.Person
+
+/**
+ * Endpoint for retrieving all information of a [Person].
+ */
+class PersonEndpoint internal constructor(
+ private val internalApi: InternalApi,
+ private val id: String
+) : Endpoint {
+
+ override fun build(): ProxerCall {
+ return internalApi.person(id)
+ }
+}
diff --git a/library/src/main/kotlin/me/proxer/library/api/list/CharacterListEndpoint.kt b/library/src/main/kotlin/me/proxer/library/api/list/CharacterListEndpoint.kt
new file mode 100644
index 00000000..a7d9a58d
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/api/list/CharacterListEndpoint.kt
@@ -0,0 +1,36 @@
+package me.proxer.library.api.list
+
+import me.proxer.library.ProxerCall
+import me.proxer.library.api.PagingLimitEndpoint
+import me.proxer.library.entity.list.CharacterCore
+
+/**
+ * Endpoint for retrieving a list of characters.
+ */
+class CharacterListEndpoint internal constructor(
+ private val internalApi: InternalApi
+) : PagingLimitEndpoint> {
+
+ private var page: Int? = null
+ private var limit: Int? = null
+
+ private var searchStart: String? = null
+ private var search: String? = null
+
+ override fun page(page: Int?) = this.apply { this.page = page }
+ override fun limit(limit: Int?) = this.apply { this.limit = limit }
+
+ /**
+ * Sets the query to search for only from the start.
+ */
+ fun searchStart(searchStart: String?) = this.apply { this.searchStart = searchStart }
+
+ /**
+ * Sets the query to search for.
+ */
+ fun search(search: String?) = this.apply { this.search = search }
+
+ override fun build(): ProxerCall> {
+ return internalApi.characterList(searchStart, search, page, limit)
+ }
+}
diff --git a/library/src/main/kotlin/me/proxer/library/api/list/InternalApi.kt b/library/src/main/kotlin/me/proxer/library/api/list/InternalApi.kt
index f7279463..5e27bfb2 100644
--- a/library/src/main/kotlin/me/proxer/library/api/list/InternalApi.kt
+++ b/library/src/main/kotlin/me/proxer/library/api/list/InternalApi.kt
@@ -1,9 +1,11 @@
package me.proxer.library.api.list
import me.proxer.library.ProxerCall
+import me.proxer.library.entity.list.CharacterCore
import me.proxer.library.entity.list.IndustryCore
import me.proxer.library.entity.list.IndustryProject
import me.proxer.library.entity.list.MediaListEntry
+import me.proxer.library.entity.list.PersonCore
import me.proxer.library.entity.list.Tag
import me.proxer.library.entity.list.TranslatorGroupCore
import me.proxer.library.entity.list.TranslatorGroupProject
@@ -107,4 +109,20 @@ internal interface InternalApi {
@Query("sort_type") sortType: TagSortType?,
@Query("subtype") subType: TagSubType?
): ProxerCall>
+
+ @GET("list/characters")
+ fun characterList(
+ @Query("start") searchStart: String?,
+ @Query("contains") search: String?,
+ @Query("p") page: Int?,
+ @Query("limit") limit: Int?
+ ): ProxerCall>
+
+ @GET("list/persons")
+ fun personList(
+ @Query("start") searchStart: String?,
+ @Query("contains") search: String?,
+ @Query("p") page: Int?,
+ @Query("limit") limit: Int?
+ ): ProxerCall>
}
diff --git a/library/src/main/kotlin/me/proxer/library/api/list/ListApi.kt b/library/src/main/kotlin/me/proxer/library/api/list/ListApi.kt
index d007cc82..8a934fad 100644
--- a/library/src/main/kotlin/me/proxer/library/api/list/ListApi.kt
+++ b/library/src/main/kotlin/me/proxer/library/api/list/ListApi.kt
@@ -59,4 +59,18 @@ class ListApi internal constructor(retrofit: Retrofit) {
fun tagList(): TagListEndpoint {
return TagListEndpoint(internalApi)
}
+
+ /**
+ * Returns the respective endpoint.
+ */
+ fun characterList(): CharacterListEndpoint {
+ return CharacterListEndpoint(internalApi)
+ }
+
+ /**
+ * Returns the respective endpoint.
+ */
+ fun personList(): PersonListEndpoint {
+ return PersonListEndpoint(internalApi)
+ }
}
diff --git a/library/src/main/kotlin/me/proxer/library/api/list/PersonListEndpoint.kt b/library/src/main/kotlin/me/proxer/library/api/list/PersonListEndpoint.kt
new file mode 100644
index 00000000..5b9b0f70
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/api/list/PersonListEndpoint.kt
@@ -0,0 +1,36 @@
+package me.proxer.library.api.list
+
+import me.proxer.library.ProxerCall
+import me.proxer.library.api.PagingLimitEndpoint
+import me.proxer.library.entity.list.PersonCore
+
+/**
+ * Endpoint for retrieving a list of persons.
+ */
+class PersonListEndpoint internal constructor(
+ private val internalApi: InternalApi
+) : PagingLimitEndpoint> {
+
+ private var page: Int? = null
+ private var limit: Int? = null
+
+ private var searchStart: String? = null
+ private var search: String? = null
+
+ override fun page(page: Int?) = this.apply { this.page = page }
+ override fun limit(limit: Int?) = this.apply { this.limit = limit }
+
+ /**
+ * Sets the query to search for only from the start.
+ */
+ fun searchStart(searchStart: String?) = this.apply { this.searchStart = searchStart }
+
+ /**
+ * Sets the query to search for.
+ */
+ fun search(search: String?) = this.apply { this.search = search }
+
+ override fun build(): ProxerCall> {
+ return internalApi.personList(searchStart, search, page, limit)
+ }
+}
diff --git a/library/src/main/kotlin/me/proxer/library/entity/info/Character.kt b/library/src/main/kotlin/me/proxer/library/entity/info/Character.kt
new file mode 100644
index 00000000..25d19092
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/entity/info/Character.kt
@@ -0,0 +1,53 @@
+package me.proxer.library.entity.info
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+import me.proxer.library.entity.ProxerIdItem
+
+/**
+ * Entity with detailed information concerning a character.
+ *
+ * @property name The name.
+ * @property gender The gender. For example "m" or "f".
+ * @property hairColor The hair color as hex string.
+ * @property eyeColor The eye color as hex string.
+ * @property bloodType The blood type.
+ * @property birthday The birthday in the format "yyyy-MM-dd". The year is "0000" if unknown.
+ * @property height The height in centimeters.
+ * @property weight The weight in kilograms.
+ * @property descriptions The sections of the description.
+ * @property names The names in different languages.
+ * @property persons The persons, who voice this character.
+ * @property entries The entries this character appears in.
+ */
+@JsonClass(generateAdapter = true)
+data class Character(
+ @Json(name = "id") override val id: String,
+ @Json(name = "name") val name: String,
+ @Json(name = "gender") val gender: String?,
+ @Json(name = "hair_color") val hairColor: String?,
+ @Json(name = "eye_color") val eyeColor: String?,
+ @Json(name = "bloodtype") val bloodType: String?,
+ @Json(name = "birthday") val birthday: String?,
+ @Json(name = "height") val height: String?,
+ @Json(name = "weight") val weight: String?,
+ @Json(name = "description") val descriptions: List,
+ @Json(name = "names") val names: List,
+ @Json(name = "persons") val persons: List,
+ @Json(name = "links") val entries: List
+) : ProxerIdItem
+
+/**
+ * Entity holding a person, who voices a [Character].
+ *
+ * @property type The type of involvement. For example "seiyuu".
+ * @property language The language the person voices the character in.
+ * @property name The name of the person.
+ */
+@JsonClass(generateAdapter = true)
+data class CharacterPerson(
+ @Json(name = "pid") override val id: String,
+ @Json(name = "type") val type: String,
+ @Json(name = "language") val language: String?,
+ @Json(name = "name") val name: String
+) : ProxerIdItem
diff --git a/library/src/main/kotlin/me/proxer/library/entity/info/Entry.kt b/library/src/main/kotlin/me/proxer/library/entity/info/Entry.kt
index e0cce7c5..ab1f738d 100644
--- a/library/src/main/kotlin/me/proxer/library/entity/info/Entry.kt
+++ b/library/src/main/kotlin/me/proxer/library/entity/info/Entry.kt
@@ -11,6 +11,7 @@ import me.proxer.library.enums.MediaLanguage
import me.proxer.library.enums.MediaState
import me.proxer.library.enums.Medium
import me.proxer.library.internal.adapter.DelimitedEnumSet
+import me.proxer.library.internal.adapter.NumberBasedBoolean
/**
* Entity holding all info of an entry. This is everything what [EntryCore] contains and some
@@ -36,6 +37,12 @@ import me.proxer.library.internal.adapter.DelimitedEnumSet
* @property industries The industries involved in production and marketing.
* @property tags The tags.
* @property genres The genres.
+ * @property mediaFormat The format of the medium. For example "tv" or "ona".
+ * @property ranking The place in the ranking of all entries.
+ * @property cleanedRating The average of the ratings, with suspicious votes removed.
+ * @property bayesianRating The bayesian average of the ratings, which the ranking is based on.
+ * @property availableEpisodeAmount The amount of episodes, which are actually available.
+ * @property isDeactivatedForApps If this entry is not available in apps.
*
* @author Ruben Gees
*/
@@ -61,7 +68,13 @@ data class Entry(
@Json(name = "groups") val translatorGroups: List,
@Json(name = "publisher") val industries: List,
@Json(name = "tags") val tags: List,
- @Json(name = "genres") val genres: List
+ @Json(name = "genres") val genres: List,
+ @Json(name = "media_format") val mediaFormat: String? = null,
+ @Json(name = "ranking") val ranking: Int? = null,
+ @Json(name = "rating_cleaned_average") val cleanedRating: Float? = null,
+ @Json(name = "rating_bayesian_average") val bayesianRating: Float? = null,
+ @Json(name = "count_available") val availableEpisodeAmount: Int? = null,
+ @field:NumberBasedBoolean @Json(name = "flag_deactivate_apps") val isDeactivatedForApps: Boolean = false
) : ProxerIdItem {
/**
diff --git a/library/src/main/kotlin/me/proxer/library/entity/info/EntryCharacter.kt b/library/src/main/kotlin/me/proxer/library/entity/info/EntryCharacter.kt
new file mode 100644
index 00000000..ac200f85
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/entity/info/EntryCharacter.kt
@@ -0,0 +1,18 @@
+package me.proxer.library.entity.info
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+import me.proxer.library.entity.ProxerIdItem
+
+/**
+ * Entity holding the most important information of a character of an entry.
+ *
+ * @property name The name.
+ * @property type The type of the character. For example "main".
+ */
+@JsonClass(generateAdapter = true)
+data class EntryCharacter(
+ @Json(name = "id") override val id: String,
+ @Json(name = "name") val name: String,
+ @Json(name = "type") val type: String
+) : ProxerIdItem
diff --git a/library/src/main/kotlin/me/proxer/library/entity/info/EntryPerson.kt b/library/src/main/kotlin/me/proxer/library/entity/info/EntryPerson.kt
new file mode 100644
index 00000000..34f76686
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/entity/info/EntryPerson.kt
@@ -0,0 +1,18 @@
+package me.proxer.library.entity.info
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+import me.proxer.library.entity.ProxerIdItem
+
+/**
+ * Entity holding the most important information of a person involved in an entry.
+ *
+ * @property name The name.
+ * @property type The type of involvement. For example "original-creator".
+ */
+@JsonClass(generateAdapter = true)
+data class EntryPerson(
+ @Json(name = "pid") override val id: String,
+ @Json(name = "name") val name: String,
+ @Json(name = "type") val type: String
+) : ProxerIdItem
diff --git a/library/src/main/kotlin/me/proxer/library/entity/info/Person.kt b/library/src/main/kotlin/me/proxer/library/entity/info/Person.kt
new file mode 100644
index 00000000..01bbae66
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/entity/info/Person.kt
@@ -0,0 +1,63 @@
+package me.proxer.library.entity.info
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+import me.proxer.library.entity.ProxerIdItem
+
+/**
+ * Entity with detailed information concerning a person.
+ *
+ * @property name The name.
+ * @property gender The gender. For example "m" or "f".
+ * @property bloodType The blood type.
+ * @property birthday The birthday in the format "yyyy-MM-dd".
+ * @property birthplace The place of birth.
+ * @property nationality The nationality as country code.
+ * @property residence The place of residence.
+ * @property descriptions The sections of the description.
+ * @property names The names in different writings.
+ * @property occupations The occupations. For example "mangaka".
+ * @property entries The entries this person was involved in.
+ * @property characters The characters this person voices.
+ */
+@JsonClass(generateAdapter = true)
+data class Person(
+ @Json(name = "id") override val id: String,
+ @Json(name = "name") val name: String,
+ @Json(name = "gender") val gender: String?,
+ @Json(name = "bloodtype") val bloodType: String?,
+ @Json(name = "birthday") val birthday: String?,
+ @Json(name = "birthplace") val birthplace: String?,
+ @Json(name = "nationality") val nationality: String?,
+ @Json(name = "residence") val residence: String?,
+ @Json(name = "description") val descriptions: List,
+ @Json(name = "names") val names: List,
+ @Json(name = "occupations") val occupations: List,
+ @Json(name = "entrys") val entries: List,
+ @Json(name = "characters") val characters: List
+) : ProxerIdItem
+
+/**
+ * Entity holding an occupation of a [Person].
+ *
+ * @property type The type. For example "mangaka" or "seiuu".
+ */
+@JsonClass(generateAdapter = true)
+data class PersonOccupation(
+ @Json(name = "type") val type: String
+)
+
+/**
+ * Entity holding a character voiced by a [Person].
+ *
+ * @property type The type of involvement. For example "seiyuu".
+ * @property language The language the character is voiced in.
+ * @property name The name of the character.
+ */
+@JsonClass(generateAdapter = true)
+data class PersonCharacter(
+ @Json(name = "cid") override val id: String,
+ @Json(name = "type") val type: String,
+ @Json(name = "language") val language: String?,
+ @Json(name = "name") val name: String
+) : ProxerIdItem
diff --git a/library/src/main/kotlin/me/proxer/library/entity/info/ProfileDescription.kt b/library/src/main/kotlin/me/proxer/library/entity/info/ProfileDescription.kt
new file mode 100644
index 00000000..b7fbfe0c
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/entity/info/ProfileDescription.kt
@@ -0,0 +1,18 @@
+package me.proxer.library.entity.info
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+/**
+ * Entity holding a section of the description of a [Character] or [Person].
+ *
+ * @property subject The subject of the section. For example "intro" or "appearance".
+ * @property text The text of the section, formatted with BBCode.
+ * @property language The language of the text.
+ */
+@JsonClass(generateAdapter = true)
+data class ProfileDescription(
+ @Json(name = "subject") val subject: String,
+ @Json(name = "text") val text: String,
+ @Json(name = "language") val language: String?
+)
diff --git a/library/src/main/kotlin/me/proxer/library/entity/info/ProfileEntry.kt b/library/src/main/kotlin/me/proxer/library/entity/info/ProfileEntry.kt
new file mode 100644
index 00000000..4cc6660a
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/entity/info/ProfileEntry.kt
@@ -0,0 +1,18 @@
+package me.proxer.library.entity.info
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+import me.proxer.library.entity.ProxerIdItem
+
+/**
+ * Entity holding the reference to an entry from a [Character] or [Person].
+ *
+ * @property type The role in the entry. For example "main" for characters or "original-creator" for persons.
+ * @property name The name of the entry.
+ */
+@JsonClass(generateAdapter = true)
+data class ProfileEntry(
+ @Json(name = "eid") override val id: String,
+ @Json(name = "type") val type: String,
+ @Json(name = "name") val name: String
+) : ProxerIdItem
diff --git a/library/src/main/kotlin/me/proxer/library/entity/info/ProfileName.kt b/library/src/main/kotlin/me/proxer/library/entity/info/ProfileName.kt
new file mode 100644
index 00000000..a058faed
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/entity/info/ProfileName.kt
@@ -0,0 +1,20 @@
+package me.proxer.library.entity.info
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+
+/**
+ * Entity holding a name of a [Character] or [Person].
+ *
+ * @property name The name.
+ * @property alternative The name in an alternative writing. For example the Japanese one.
+ * @property type The type of the name.
+ * @property language The language of the name. Only available for characters.
+ */
+@JsonClass(generateAdapter = true)
+data class ProfileName(
+ @Json(name = "name") val name: String,
+ @Json(name = "alternative") val alternative: String?,
+ @Json(name = "type") val type: String?,
+ @Json(name = "language") val language: String? = null
+)
diff --git a/library/src/main/kotlin/me/proxer/library/entity/list/CharacterCore.kt b/library/src/main/kotlin/me/proxer/library/entity/list/CharacterCore.kt
new file mode 100644
index 00000000..29bea831
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/entity/list/CharacterCore.kt
@@ -0,0 +1,18 @@
+package me.proxer.library.entity.list
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+import me.proxer.library.entity.ProxerIdItem
+
+/**
+ * Entity containing the core information of a character.
+ *
+ * @property name The name.
+ * @property text The beginning of the description, formatted with BBCode.
+ */
+@JsonClass(generateAdapter = true)
+data class CharacterCore(
+ @Json(name = "id") override val id: String,
+ @Json(name = "name") val name: String,
+ @Json(name = "text") val text: String?
+) : ProxerIdItem
diff --git a/library/src/main/kotlin/me/proxer/library/entity/list/PersonCore.kt b/library/src/main/kotlin/me/proxer/library/entity/list/PersonCore.kt
new file mode 100644
index 00000000..b252fe30
--- /dev/null
+++ b/library/src/main/kotlin/me/proxer/library/entity/list/PersonCore.kt
@@ -0,0 +1,18 @@
+package me.proxer.library.entity.list
+
+import com.squareup.moshi.Json
+import com.squareup.moshi.JsonClass
+import me.proxer.library.entity.ProxerIdItem
+
+/**
+ * Entity containing the core information of a person.
+ *
+ * @property name The name.
+ * @property text The beginning of the description, formatted with BBCode.
+ */
+@JsonClass(generateAdapter = true)
+data class PersonCore(
+ @Json(name = "id") override val id: String,
+ @Json(name = "name") val name: String,
+ @Json(name = "text") val text: String?
+) : ProxerIdItem
diff --git a/library/src/main/kotlin/me/proxer/library/enums/MediaType.kt b/library/src/main/kotlin/me/proxer/library/enums/MediaType.kt
index 7f607f2d..0689ba19 100644
--- a/library/src/main/kotlin/me/proxer/library/enums/MediaType.kt
+++ b/library/src/main/kotlin/me/proxer/library/enums/MediaType.kt
@@ -35,12 +35,24 @@ enum class MediaType {
@Json(name = "hmanga")
HMANGA,
+ @Json(name = "lightnovel")
+ LIGHTNOVEL,
+
+ @Json(name = "webnovel")
+ WEBNOVEL,
+
+ @Json(name = "visualnovel")
+ VISUALNOVEL,
+
@Json(name = "all-anime")
ALL_ANIME,
@Json(name = "all-manga")
ALL_MANGA,
+ @Json(name = "all-novel")
+ ALL_NOVEL,
+
@Json(name = "all")
ALL,
diff --git a/library/src/main/kotlin/me/proxer/library/internal/adapter/DelimitedEnumSet.kt b/library/src/main/kotlin/me/proxer/library/internal/adapter/DelimitedEnumSet.kt
index c981d672..20d42f9d 100644
--- a/library/src/main/kotlin/me/proxer/library/internal/adapter/DelimitedEnumSet.kt
+++ b/library/src/main/kotlin/me/proxer/library/internal/adapter/DelimitedEnumSet.kt
@@ -6,5 +6,4 @@ import com.squareup.moshi.JsonQualifier
* @author Ruben Gees
*/
@JsonQualifier
-@Retention(AnnotationRetention.RUNTIME)
internal annotation class DelimitedEnumSet(val delimiter: String = " ")
diff --git a/library/src/main/kotlin/me/proxer/library/internal/adapter/DelimitedEnumSetAdapterFactory.kt b/library/src/main/kotlin/me/proxer/library/internal/adapter/DelimitedEnumSetAdapterFactory.kt
index b77cf5e6..a23071a6 100644
--- a/library/src/main/kotlin/me/proxer/library/internal/adapter/DelimitedEnumSetAdapterFactory.kt
+++ b/library/src/main/kotlin/me/proxer/library/internal/adapter/DelimitedEnumSetAdapterFactory.kt
@@ -56,7 +56,7 @@ internal class DelimitedEnumSetAdapterFactory : JsonAdapter.Factory {
val annotation = enumType.getField(constant.name).getAnnotation(Json::class.java)
val name = annotation?.name ?: constant.name
- name.toLowerCase(Locale.US) to constant
+ name.lowercase(Locale.US) to constant
} catch (error: NoSuchFieldException) {
throw AssertionError("Missing field in ${enumType.name}", error)
}
@@ -73,7 +73,7 @@ internal class DelimitedEnumSetAdapterFactory : JsonAdapter.Factory {
emptySet()
} else {
- val rawParts = reader.nextString().trim().toLowerCase(Locale.US)
+ val rawParts = reader.nextString().trim().lowercase(Locale.US)
if (rawParts.isEmpty()) {
emptySet()
diff --git a/library/src/main/kotlin/me/proxer/library/internal/adapter/DelimitedStringSet.kt b/library/src/main/kotlin/me/proxer/library/internal/adapter/DelimitedStringSet.kt
index fe08e2ea..cc7d4a07 100644
--- a/library/src/main/kotlin/me/proxer/library/internal/adapter/DelimitedStringSet.kt
+++ b/library/src/main/kotlin/me/proxer/library/internal/adapter/DelimitedStringSet.kt
@@ -6,7 +6,6 @@ import com.squareup.moshi.JsonQualifier
* @author Ruben Gees
*/
@JsonQualifier
-@Retention(AnnotationRetention.RUNTIME)
internal annotation class DelimitedStringSet(
val delimiter: String = " ",
val valuesToKeep: Array = []
diff --git a/library/src/main/kotlin/me/proxer/library/internal/adapter/NumberBasedBoolean.kt b/library/src/main/kotlin/me/proxer/library/internal/adapter/NumberBasedBoolean.kt
index e9382659..023b21ba 100644
--- a/library/src/main/kotlin/me/proxer/library/internal/adapter/NumberBasedBoolean.kt
+++ b/library/src/main/kotlin/me/proxer/library/internal/adapter/NumberBasedBoolean.kt
@@ -9,5 +9,4 @@ import com.squareup.moshi.JsonQualifier
* @author Ruben Gees
*/
@JsonQualifier
-@Retention(AnnotationRetention.RUNTIME)
internal annotation class NumberBasedBoolean
diff --git a/library/src/main/kotlin/me/proxer/library/util/ProxerUrls.kt b/library/src/main/kotlin/me/proxer/library/util/ProxerUrls.kt
index d6c2d7ea..a6af32c1 100644
--- a/library/src/main/kotlin/me/proxer/library/util/ProxerUrls.kt
+++ b/library/src/main/kotlin/me/proxer/library/util/ProxerUrls.kt
@@ -122,6 +122,26 @@ object ProxerUrls {
.build()
}
+ /**
+ * Returns the image link of the character.
+ */
+ fun characterImage(id: String): HttpUrl {
+ return cdnBase.newBuilder()
+ .addPathSegment("character")
+ .addPathSegment("$id.jpg")
+ .build()
+ }
+
+ /**
+ * Returns the image link of the person.
+ */
+ fun personImage(id: String): HttpUrl {
+ return cdnBase.newBuilder()
+ .addPathSegment("person")
+ .addPathSegment("$id.jpg")
+ .build()
+ }
+
/**
* Returns the image link of the industry.
*/
@@ -238,6 +258,26 @@ object ProxerUrls {
.build()
}
+ /**
+ * Returns the link for the web page of the requested character.
+ */
+ fun characterWeb(id: String): HttpUrl {
+ return webBase.newBuilder()
+ .addPathSegment("character")
+ .addQueryParameter("id", id)
+ .build()
+ }
+
+ /**
+ * Returns the link for the web page of the requested person.
+ */
+ fun personWeb(id: String): HttpUrl {
+ return webBase.newBuilder()
+ .addPathSegment("persons")
+ .addQueryParameter("id", id)
+ .build()
+ }
+
/**
* Returns the link for the web page of the requested translator group.
*/
diff --git a/library/src/test/kotlin/me/proxer/library/api/info/CharacterEndpointTest.kt b/library/src/test/kotlin/me/proxer/library/api/info/CharacterEndpointTest.kt
new file mode 100644
index 00000000..5f719d84
--- /dev/null
+++ b/library/src/test/kotlin/me/proxer/library/api/info/CharacterEndpointTest.kt
@@ -0,0 +1,51 @@
+package me.proxer.library.api.info
+
+import me.proxer.library.ProxerTest
+import me.proxer.library.entity.info.CharacterPerson
+import me.proxer.library.entity.info.ProfileEntry
+import me.proxer.library.runRequest
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.jupiter.api.Test
+
+class CharacterEndpointTest : ProxerTest() {
+
+ @Test
+ fun testDefault() {
+ val (result, _) = server.runRequest("character.json") {
+ api.info
+ .character("4")
+ .build()
+ .safeExecute()
+ }
+
+ result.id shouldBeEqualTo "4"
+ result.name shouldBeEqualTo "Monkey D. Luffy"
+ result.gender shouldBeEqualTo "m"
+ result.hairColor shouldBeEqualTo "#000000"
+ result.bloodType shouldBeEqualTo "B"
+ result.birthday shouldBeEqualTo "0000-05-05"
+ result.height shouldBeEqualTo "172"
+ result.weight shouldBeEqualTo ""
+ result.descriptions.size shouldBeEqualTo 5
+ result.descriptions.first().subject shouldBeEqualTo "intro"
+ result.descriptions.first().language shouldBeEqualTo "de"
+ result.names.map { it.name } shouldBeEqualTo listOf("Strohhut-Ruffy", "Straw Hat Luffy")
+ result.names.first().language shouldBeEqualTo "de"
+ result.persons.first() shouldBeEqualTo CharacterPerson("670", "seiyuu", "de", "Daniel Schlauch")
+ result.entries shouldBeEqualTo listOf(
+ ProfileEntry("2786", "main", "One Piece"),
+ ProfileEntry("53", "main", "One Piece")
+ )
+ }
+
+ @Test
+ fun testPath() {
+ val (_, request) = server.runRequest("character.json") {
+ api.info.character("4")
+ .build()
+ .execute()
+ }
+
+ request.path shouldBeEqualTo "/api/v1/info/character?id=4"
+ }
+}
diff --git a/library/src/test/kotlin/me/proxer/library/api/info/EntryCharactersEndpointTest.kt b/library/src/test/kotlin/me/proxer/library/api/info/EntryCharactersEndpointTest.kt
new file mode 100644
index 00000000..ed2bbcf6
--- /dev/null
+++ b/library/src/test/kotlin/me/proxer/library/api/info/EntryCharactersEndpointTest.kt
@@ -0,0 +1,34 @@
+package me.proxer.library.api.info
+
+import me.proxer.library.ProxerTest
+import me.proxer.library.entity.info.EntryCharacter
+import me.proxer.library.runRequest
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.jupiter.api.Test
+
+class EntryCharactersEndpointTest : ProxerTest() {
+
+ @Test
+ fun testDefault() {
+ val (result, _) = server.runRequest("entry_characters.json") {
+ api.info
+ .entryCharacters("53")
+ .build()
+ .safeExecute()
+ }
+
+ result.size shouldBeEqualTo 3
+ result.first() shouldBeEqualTo EntryCharacter("517", "Brook", "main")
+ }
+
+ @Test
+ fun testPath() {
+ val (_, request) = server.runRequest("entry_characters.json") {
+ api.info.entryCharacters("53")
+ .build()
+ .execute()
+ }
+
+ request.path shouldBeEqualTo "/api/v1/info/characters?id=53"
+ }
+}
diff --git a/library/src/test/kotlin/me/proxer/library/api/info/EntryEndpointTest.kt b/library/src/test/kotlin/me/proxer/library/api/info/EntryEndpointTest.kt
index f2afbd8c..011c636b 100644
--- a/library/src/test/kotlin/me/proxer/library/api/info/EntryEndpointTest.kt
+++ b/library/src/test/kotlin/me/proxer/library/api/info/EntryEndpointTest.kt
@@ -100,7 +100,13 @@ class EntryEndpointTest : ProxerTest() {
| Kurzum ein Abenteuer, das es zu bestehen gilt.
""".trimMargin().replace("\n", "")
)
- )
+ ),
+ mediaFormat = "tv",
+ ranking = 69,
+ cleanedRating = 9.65f,
+ bayesianRating = 9.64f,
+ availableEpisodeAmount = 88,
+ isDeactivatedForApps = true
)
@Test
diff --git a/library/src/test/kotlin/me/proxer/library/api/info/EntryPersonsEndpointTest.kt b/library/src/test/kotlin/me/proxer/library/api/info/EntryPersonsEndpointTest.kt
new file mode 100644
index 00000000..27256584
--- /dev/null
+++ b/library/src/test/kotlin/me/proxer/library/api/info/EntryPersonsEndpointTest.kt
@@ -0,0 +1,34 @@
+package me.proxer.library.api.info
+
+import me.proxer.library.ProxerTest
+import me.proxer.library.entity.info.EntryPerson
+import me.proxer.library.runRequest
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.jupiter.api.Test
+
+class EntryPersonsEndpointTest : ProxerTest() {
+
+ @Test
+ fun testDefault() {
+ val (result, _) = server.runRequest("entry_persons.json") {
+ api.info
+ .entryPersons("53")
+ .build()
+ .safeExecute()
+ }
+
+ result.size shouldBeEqualTo 3
+ result.first() shouldBeEqualTo EntryPerson("701", "Eiichiro Oda", "original-creator")
+ }
+
+ @Test
+ fun testPath() {
+ val (_, request) = server.runRequest("entry_persons.json") {
+ api.info.entryPersons("53")
+ .build()
+ .execute()
+ }
+
+ request.path shouldBeEqualTo "/api/v1/info/persons?id=53"
+ }
+}
diff --git a/library/src/test/kotlin/me/proxer/library/api/info/PersonEndpointTest.kt b/library/src/test/kotlin/me/proxer/library/api/info/PersonEndpointTest.kt
new file mode 100644
index 00000000..1ed8d289
--- /dev/null
+++ b/library/src/test/kotlin/me/proxer/library/api/info/PersonEndpointTest.kt
@@ -0,0 +1,51 @@
+package me.proxer.library.api.info
+
+import me.proxer.library.ProxerTest
+import me.proxer.library.entity.info.PersonCharacter
+import me.proxer.library.entity.info.PersonOccupation
+import me.proxer.library.entity.info.ProfileEntry
+import me.proxer.library.runRequest
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.jupiter.api.Test
+
+class PersonEndpointTest : ProxerTest() {
+
+ @Test
+ fun testDefault() {
+ val (result, _) = server.runRequest("person.json") {
+ api.info
+ .person("701")
+ .build()
+ .safeExecute()
+ }
+
+ result.id shouldBeEqualTo "701"
+ result.name shouldBeEqualTo "Eiichiro Oda"
+ result.gender shouldBeEqualTo "m"
+ result.bloodType shouldBeEqualTo "A"
+ result.birthday shouldBeEqualTo "1975-01-01"
+ result.birthplace shouldBeEqualTo "Kumamoto / Japan"
+ result.nationality shouldBeEqualTo "JP"
+ result.residence shouldBeEqualTo "Tokyo / Japan"
+ result.descriptions.single().subject shouldBeEqualTo "intro"
+ result.names.single().alternative shouldBeEqualTo "尾田 栄一郎"
+ result.names.single().language shouldBeEqualTo null
+ result.occupations shouldBeEqualTo listOf(PersonOccupation("seiuu"), PersonOccupation("mangaka"))
+ result.entries shouldBeEqualTo listOf(
+ ProfileEntry("53", "original-creator", "One Piece"),
+ ProfileEntry("2786", "author-art", "One Piece")
+ )
+ result.characters shouldBeEqualTo listOf(PersonCharacter("3990", "seiyuu", "jp", "Odacchi"))
+ }
+
+ @Test
+ fun testPath() {
+ val (_, request) = server.runRequest("person.json") {
+ api.info.person("701")
+ .build()
+ .execute()
+ }
+
+ request.path shouldBeEqualTo "/api/v1/info/person?id=701"
+ }
+}
diff --git a/library/src/test/kotlin/me/proxer/library/api/list/CharacterListEndpointTest.kt b/library/src/test/kotlin/me/proxer/library/api/list/CharacterListEndpointTest.kt
new file mode 100644
index 00000000..6583923f
--- /dev/null
+++ b/library/src/test/kotlin/me/proxer/library/api/list/CharacterListEndpointTest.kt
@@ -0,0 +1,38 @@
+package me.proxer.library.api.list
+
+import me.proxer.library.ProxerTest
+import me.proxer.library.runRequest
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.jupiter.api.Test
+
+class CharacterListEndpointTest : ProxerTest() {
+
+ @Test
+ fun testDefault() {
+ val (result, _) = server.runRequest("character_list.json") {
+ api.list
+ .characterList()
+ .build()
+ .safeExecute()
+ }
+
+ result.size shouldBeEqualTo 3
+ result.first().id shouldBeEqualTo "5170"
+ result.first().name shouldBeEqualTo "001"
+ }
+
+ @Test
+ fun testPath() {
+ val (_, request) = server.runRequest("character_list.json") {
+ api.list.characterList()
+ .search("ab")
+ .searchStart("cd")
+ .page(1)
+ .limit(100)
+ .build()
+ .execute()
+ }
+
+ request.path shouldBeEqualTo "/api/v1/list/characters?start=cd&contains=ab&p=1&limit=100"
+ }
+}
diff --git a/library/src/test/kotlin/me/proxer/library/api/list/PersonListEndpointTest.kt b/library/src/test/kotlin/me/proxer/library/api/list/PersonListEndpointTest.kt
new file mode 100644
index 00000000..683ee9fe
--- /dev/null
+++ b/library/src/test/kotlin/me/proxer/library/api/list/PersonListEndpointTest.kt
@@ -0,0 +1,38 @@
+package me.proxer.library.api.list
+
+import me.proxer.library.ProxerTest
+import me.proxer.library.runRequest
+import org.amshove.kluent.shouldBeEqualTo
+import org.junit.jupiter.api.Test
+
+class PersonListEndpointTest : ProxerTest() {
+
+ @Test
+ fun testDefault() {
+ val (result, _) = server.runRequest("person_list.json") {
+ api.list
+ .personList()
+ .build()
+ .safeExecute()
+ }
+
+ result.size shouldBeEqualTo 3
+ result.first().id shouldBeEqualTo "4584"
+ result.first().name shouldBeEqualTo "100,000 Won"
+ }
+
+ @Test
+ fun testPath() {
+ val (_, request) = server.runRequest("person_list.json") {
+ api.list.personList()
+ .search("ab")
+ .searchStart("cd")
+ .page(1)
+ .limit(100)
+ .build()
+ .execute()
+ }
+
+ request.path shouldBeEqualTo "/api/v1/list/persons?start=cd&contains=ab&p=1&limit=100"
+ }
+}
diff --git a/library/src/test/kotlin/me/proxer/library/internal/adapter/DelimitedEnumSetAdapterFactoryTest.kt b/library/src/test/kotlin/me/proxer/library/internal/adapter/DelimitedEnumSetAdapterFactoryTest.kt
index b363c51d..9258d21f 100644
--- a/library/src/test/kotlin/me/proxer/library/internal/adapter/DelimitedEnumSetAdapterFactoryTest.kt
+++ b/library/src/test/kotlin/me/proxer/library/internal/adapter/DelimitedEnumSetAdapterFactoryTest.kt
@@ -113,7 +113,7 @@ class DelimitedEnumSetAdapterFactoryTest {
@Test
fun testFromJsonDifferentDelimiter() {
- val result = moshi.adapter(GenderWithDelimiterTestClass::class.java).fromJson("""{"genders":"f, m"}""")
+ val result = moshi.adapter(DelimTestClass::class.java).fromJson("""{"genders":"f, m"}""")
result.shouldNotBeNull()
result.genders shouldBeEqualTo setOf(Gender.MALE, Gender.FEMALE)
@@ -156,8 +156,8 @@ class DelimitedEnumSetAdapterFactoryTest {
@Test
fun testToJsonMultipleDifferentDelimiter() {
- val testSubject = GenderWithDelimiterTestClass(setOf(Gender.FEMALE, Gender.MALE))
- val result = moshi.adapter(GenderWithDelimiterTestClass::class.java).toJson(testSubject)
+ val testSubject = DelimTestClass(setOf(Gender.FEMALE, Gender.MALE))
+ val result = moshi.adapter(DelimTestClass::class.java).toJson(testSubject)
result shouldBeEqualTo """{"genders":"f, m"}"""
}
@@ -168,7 +168,7 @@ class DelimitedEnumSetAdapterFactoryTest {
)
@JsonClass(generateAdapter = true)
- data class GenderWithDelimiterTestClass(
+ data class DelimTestClass(
@field:DelimitedEnumSet(delimiter = ", ") val genders: Set? = null
)
diff --git a/library/src/test/kotlin/me/proxer/library/internal/adapter/DelimitedStringSetAdapterFactoryTest.kt b/library/src/test/kotlin/me/proxer/library/internal/adapter/DelimitedStringSetAdapterFactoryTest.kt
index 9d3c8b77..3a238175 100644
--- a/library/src/test/kotlin/me/proxer/library/internal/adapter/DelimitedStringSetAdapterFactoryTest.kt
+++ b/library/src/test/kotlin/me/proxer/library/internal/adapter/DelimitedStringSetAdapterFactoryTest.kt
@@ -104,7 +104,7 @@ class DelimitedStringSetAdapterFactoryTest {
@Test
fun testFromJsonDifferentDelimiter() {
- val result = moshi.adapter(StringSetWithDelimiterTestClass::class.java).fromJson("""{"value":"a, b,c"}""")
+ val result = moshi.adapter(DelimTestClass::class.java).fromJson("""{"value":"a, b,c"}""")
result.shouldNotBeNull()
result.value shouldBeEqualTo setOf("a", "b,c")
@@ -112,7 +112,7 @@ class DelimitedStringSetAdapterFactoryTest {
@Test
fun testFromJsonValuesToKeep() {
- val result = moshi.adapter(StringSetWithValuesToKeepTestClass::class.java).fromJson("""{"value":"a b c"}""")
+ val result = moshi.adapter(KeepTestClass::class.java).fromJson("""{"value":"a b c"}""")
result.shouldNotBeNull()
result.value shouldBeEqualTo setOf("a b", "c")
@@ -136,8 +136,8 @@ class DelimitedStringSetAdapterFactoryTest {
@Test
fun testToJsonDifferentDelimiter() {
- val subject = StringSetWithDelimiterTestClass(setOf("a", "b", "c"))
- val result = moshi.adapter(StringSetWithDelimiterTestClass::class.java).toJson(subject)
+ val subject = DelimTestClass(setOf("a", "b", "c"))
+ val result = moshi.adapter(DelimTestClass::class.java).toJson(subject)
result shouldBeEqualTo """{"value":"a, b, c"}"""
}
@@ -148,12 +148,12 @@ class DelimitedStringSetAdapterFactoryTest {
)
@JsonClass(generateAdapter = true)
- data class StringSetWithDelimiterTestClass(
+ data class DelimTestClass(
@field:DelimitedStringSet(delimiter = ", ") val value: Set
)
@JsonClass(generateAdapter = true)
- data class StringSetWithValuesToKeepTestClass(
+ data class KeepTestClass(
@field:DelimitedStringSet(valuesToKeep = ["a b"]) val value: Set
)
}
diff --git a/library/src/test/kotlin/me/proxer/library/util/ProxerUrlsTest.kt b/library/src/test/kotlin/me/proxer/library/util/ProxerUrlsTest.kt
index 4b0842e5..61dfc277 100644
--- a/library/src/test/kotlin/me/proxer/library/util/ProxerUrlsTest.kt
+++ b/library/src/test/kotlin/me/proxer/library/util/ProxerUrlsTest.kt
@@ -66,6 +66,16 @@ class ProxerUrlsTest {
ProxerUrls.industryImage("1").toString() shouldBeEqualTo "https://cdn.proxer.me/industry/1.jpg"
}
+ @Test
+ fun testCharacterImage() {
+ ProxerUrls.characterImage("4").toString() shouldBeEqualTo "https://cdn.proxer.me/character/4.jpg"
+ }
+
+ @Test
+ fun testPersonImage() {
+ ProxerUrls.personImage("701").toString() shouldBeEqualTo "https://cdn.proxer.me/person/701.jpg"
+ }
+
@Test
fun testHosterImage() {
ProxerUrls.hosterImage("play.png").toString() shouldBeEqualTo "https://proxer.me/images/hoster/play.png"
@@ -143,6 +153,16 @@ class ProxerUrlsTest {
ProxerUrls.industryWeb("453").toString() shouldBeEqualTo "https://proxer.me/industry/453?device=default"
}
+ @Test
+ fun testCharacterWeb() {
+ ProxerUrls.characterWeb("4").toString() shouldBeEqualTo "https://proxer.me/character?id=4"
+ }
+
+ @Test
+ fun testPersonWeb() {
+ ProxerUrls.personWeb("701").toString() shouldBeEqualTo "https://proxer.me/persons?id=701"
+ }
+
@Test
fun testTranslatorGroupWeb() {
ProxerUrls.translatorGroupWeb("123").toString() shouldBeEqualTo
diff --git a/library/src/test/resources/character.json b/library/src/test/resources/character.json
new file mode 100644
index 00000000..d17d74a2
--- /dev/null
+++ b/library/src/test/resources/character.json
@@ -0,0 +1,84 @@
+{
+ "error": 0,
+ "message": "Abfrage erfolgreich",
+ "data": {
+ "id": "4",
+ "name": "Monkey D. Luffy",
+ "gender": "m",
+ "hair_color": "#000000",
+ "eye_color": "#000000",
+ "bloodtype": "B",
+ "birthday": "0000-05-05",
+ "height": "172",
+ "weight": "",
+ "description": [
+ {
+ "subject": "intro",
+ "text": "[b]Monkey D. Luffys[/b] ist es der nächste [i]Piratenkönig[/i] zu werden, welches er zusammen mit seinen Freunden, der [i]Strohhutbande[/i],...",
+ "language": "de"
+ },
+ {
+ "subject": "appearance",
+ "text": "Ruffy hat schwarze Haare und Augen. Sein wichtigstes Merkmal ist sein Strohhut, den er in seiner Kindheit von [url=https://proxer.me/charact...",
+ "language": "de"
+ },
+ {
+ "subject": "personality",
+ "text": "Ruffy ist ein bisschen naiv. Außerdem neigt er dazu eigentlich komplizierte Dinge zu simplifizieren und sehr locker zu sehen. Generell ist e...",
+ "language": "de"
+ },
+ {
+ "subject": "skills",
+ "text": "Ruffy besitzt die Kraft der [i]Gum-Gum-Frucht[/i], mit welcher er seinen Körper beliebig dehnen kann, worauf alle seine Attacken aufbauen. E...",
+ "language": "de"
+ },
+ {
+ "subject": "past",
+ "text": "Zehn Jahre vor Beginn der Haupthandlung lebt Ruffy im [i]Windmühlendorf[/i] im East Blue. Sein Traum ist es ein Pirat zu sein, weshalb er de...",
+ "language": "de"
+ }
+ ],
+ "names": [
+ {
+ "language": "de",
+ "name": "Strohhut-Ruffy",
+ "alternative": "",
+ "type": "pseudonym",
+ "display_name": "0"
+ },
+ {
+ "language": "en",
+ "name": "Straw Hat Luffy",
+ "alternative": "",
+ "type": "pseudonym",
+ "display_name": "0"
+ }
+ ],
+ "persons": [
+ {
+ "pid": "670",
+ "type": "seiyuu",
+ "language": "de",
+ "name": "Daniel Schlauch"
+ },
+ {
+ "pid": "1400",
+ "type": "seiyuu",
+ "language": "en",
+ "name": "Colleen Clinkenbeard"
+ }
+ ],
+ "links": [
+ {
+ "eid": "2786",
+ "type": "main",
+ "name": "One Piece"
+ },
+ {
+ "eid": "53",
+ "type": "main",
+ "name": "One Piece"
+ }
+ ]
+ }
+}
diff --git a/library/src/test/resources/character_list.json b/library/src/test/resources/character_list.json
new file mode 100644
index 00000000..c7d7329d
--- /dev/null
+++ b/library/src/test/resources/character_list.json
@@ -0,0 +1,21 @@
+{
+ "error": 0,
+ "message": "Abfrage erfolgreich",
+ "data": [
+ {
+ "id": "5170",
+ "name": "001",
+ "text": "[B]001[/B], auch bekannt als die [B]Prinzessin der Klaxosaurier[/B], ist ein [I]..."
+ },
+ {
+ "id": "7113",
+ "name": "753♡",
+ "text": ""
+ },
+ {
+ "id": "2399",
+ "name": "A-Chan",
+ "text": "[b]A-Chan[/b] war die Vorsitzende des Mädchen-Wohnheims, bis sie von [url=https:..."
+ }
+ ]
+}
diff --git a/library/src/test/resources/entry.json b/library/src/test/resources/entry.json
index 3e3ec9dc..01cad227 100644
--- a/library/src/test/resources/entry.json
+++ b/library/src/test/resources/entry.json
@@ -9,6 +9,11 @@
"description": "Humans are a despicable lot, committing sin after sin, filling the endless boundaries of the underworld with tortured souls. Now, it would seem, Hell isn't so endless after all, and it has become dangerously close to filling, and then overflowing into the human realm. Princess Lucuha sees this imminent disaster and has a plan: save Hell by making humans decent again. Of course, the angels can't simply allow demons to roam freely on Earth, and they do their best to stop Lucu and her dastardly plans.",
"medium": "mangaseries",
"media_format": "tv",
+ "ranking": "69",
+ "rating_cleaned_average": "9.65",
+ "rating_bayesian_average": "9.64",
+ "count_available": "88",
+ "flag_deactivate_apps": "1",
"adaption_type": "entry",
"adaption_value": "2793",
"count": "90",
diff --git a/library/src/test/resources/entry_characters.json b/library/src/test/resources/entry_characters.json
new file mode 100644
index 00000000..0c4d9bc8
--- /dev/null
+++ b/library/src/test/resources/entry_characters.json
@@ -0,0 +1,21 @@
+{
+ "error": 0,
+ "message": "Abfrage erfolgreich",
+ "data": [
+ {
+ "id": "517",
+ "name": "Brook",
+ "type": "main"
+ },
+ {
+ "id": "978",
+ "name": "Franky",
+ "type": "main"
+ },
+ {
+ "id": "4",
+ "name": "Monkey D. Luffy",
+ "type": "main"
+ }
+ ]
+}
diff --git a/library/src/test/resources/entry_persons.json b/library/src/test/resources/entry_persons.json
new file mode 100644
index 00000000..0829153b
--- /dev/null
+++ b/library/src/test/resources/entry_persons.json
@@ -0,0 +1,21 @@
+{
+ "error": 0,
+ "message": "Abfrage erfolgreich",
+ "data": [
+ {
+ "name": "Eiichiro Oda",
+ "pid": "701",
+ "type": "original-creator"
+ },
+ {
+ "name": "Justin Cook",
+ "pid": "1272",
+ "type": "misc"
+ },
+ {
+ "name": "Mamoru Hosoda",
+ "pid": "72",
+ "type": "misc"
+ }
+ ]
+}
diff --git a/library/src/test/resources/person.json b/library/src/test/resources/person.json
new file mode 100644
index 00000000..24369aee
--- /dev/null
+++ b/library/src/test/resources/person.json
@@ -0,0 +1,58 @@
+{
+ "error": 0,
+ "message": "Abfrage erfolgreich",
+ "data": {
+ "id": "701",
+ "name": "Eiichiro Oda",
+ "gender": "m",
+ "bloodtype": "A",
+ "birthday": "1975-01-01",
+ "birthplace": "Kumamoto / Japan",
+ "nationality": "JP",
+ "residence": "Tokyo / Japan",
+ "description": [
+ {
+ "subject": "intro",
+ "text": "[b]Eiichiro Oda[/b] ist Autor und Zeichner des weltweit erfolgreichen Piratenmangas [url=https://proxer.me/info/2786#top][b][i]\"One Piece\"[/...",
+ "language": "de"
+ }
+ ],
+ "names": [
+ {
+ "name": "Eiichiro Oda",
+ "alternative": "尾田 栄一郎",
+ "type": "name",
+ "display_name": "1"
+ }
+ ],
+ "occupations": [
+ {
+ "type": "seiuu"
+ },
+ {
+ "type": "mangaka"
+ }
+ ],
+ "sites": [],
+ "entrys": [
+ {
+ "eid": "53",
+ "type": "original-creator",
+ "name": "One Piece"
+ },
+ {
+ "eid": "2786",
+ "type": "author-art",
+ "name": "One Piece"
+ }
+ ],
+ "characters": [
+ {
+ "cid": "3990",
+ "type": "seiyuu",
+ "language": "jp",
+ "name": "Odacchi"
+ }
+ ]
+ }
+}
diff --git a/library/src/test/resources/person_list.json b/library/src/test/resources/person_list.json
new file mode 100644
index 00000000..fdb772ca
--- /dev/null
+++ b/library/src/test/resources/person_list.json
@@ -0,0 +1,21 @@
+{
+ "error": 0,
+ "message": "Abfrage erfolgreich",
+ "data": [
+ {
+ "id": "4584",
+ "name": "100,000 Won",
+ "text": "[B]100,000 Won[/B] kommt aus Südkorea und arbeitet an Webtoons wie [URL=https://..."
+ },
+ {
+ "id": "4081",
+ "name": "138neko",
+ "text": "[B]138neko[/B] kommt aus Japan und ist für die Arbeit an Manga wie [URL=https://..."
+ },
+ {
+ "id": "4326",
+ "name": "1535",
+ "text": "[B]1535[/B] kommt aus Südkorea und arbeitet an Werken wie [URL=https://proxer.me..."
+ }
+ ]
+}
diff --git a/sample/build.gradle b/sample/build.gradle
index 059421b6..26579348 100644
--- a/sample/build.gradle
+++ b/sample/build.gradle
@@ -1,11 +1,15 @@
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
plugins {
id "org.jetbrains.kotlin.jvm"
id "application"
}
-mainClassName = "me.proxer.sample.News"
+application {
+ mainClass = "me.proxer.sample.News"
+}
-run {
+tasks.named("run") {
standardInput = System.in
}
@@ -13,10 +17,15 @@ dependencies {
implementation project(":library")
}
-tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
- kotlinOptions {
- jvmTarget = "1.8"
- allWarningsAsErrors = true
- freeCompilerArgs = ["-Xjsr305=strict", "-progressive"]
+kotlin {
+ jvmToolchain(17)
+
+ compilerOptions {
+ jvmTarget = JvmTarget.JVM_1_8
+ freeCompilerArgs.addAll("-Xjsr305=strict", "-Xannotation-default-target=param-property")
}
}
+
+tasks.withType(JavaCompile).configureEach {
+ options.release = 8
+}
diff --git a/settings.gradle b/settings.gradle
index c560323a..0c6b20fb 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -3,15 +3,13 @@ pluginManagement {
plugins {
id "org.jetbrains.kotlin.jvm" version "${kotlinVersion}"
- id "org.jetbrains.kotlin.kapt" version "${kotlinVersion}"
- id "org.jetbrains.dokka" version "${dokkaVersion}"
+ id "com.google.devtools.ksp" version "${kspVersion}"
id "io.gitlab.arturbosch.detekt" version "${detektVersion}"
id "org.jlleitschuh.gradle.ktlint" version "${ktlintPluginVersion}"
-
- id "com.github.ben-manes.versions" version "${gradleVersionsPluginVersion}"
- id "de.fuerstenau.buildconfig" version "${buildConfigPluginVersion}"
}
}
+rootProject.name = "ProxerLibJava"
+
include ":library", ":sample"